summaryrefslogtreecommitdiffstats
path: root/storage/mroonga
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:04:16 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 18:04:16 +0000
commita68fb2d8219f6bccc573009600e9f23e89226a5e (patch)
treed742d35d14ae816e99293d2b01face30e9f3a46b /storage/mroonga
parentInitial commit. (diff)
downloadmariadb-10.6-a68fb2d8219f6bccc573009600e9f23e89226a5e.tar.xz
mariadb-10.6-a68fb2d8219f6bccc573009600e9f23e89226a5e.zip
Adding upstream version 1:10.6.11.upstream/1%10.6.11upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'storage/mroonga')
-rw-r--r--storage/mroonga/AUTHORS7
-rw-r--r--storage/mroonga/CMakeLists.txt452
-rw-r--r--storage/mroonga/COPYING504
-rw-r--r--storage/mroonga/ChangeLog3
-rw-r--r--storage/mroonga/Makefile.am175
-rw-r--r--storage/mroonga/NEWS1
-rw-r--r--storage/mroonga/README1
-rw-r--r--storage/mroonga/appveyor.yml61
-rwxr-xr-xstorage/mroonga/autogen.sh11
-rw-r--r--storage/mroonga/build/Makefile.am2
-rw-r--r--storage/mroonga/build/cmake_modules/Makefile.am2
-rw-r--r--storage/mroonga/build/cmake_modules/ReadFileList.cmake27
-rw-r--r--storage/mroonga/build/makefiles/LC_MESSAGES.am5
-rw-r--r--storage/mroonga/build/makefiles/gettext.am86
-rw-r--r--storage/mroonga/build/makefiles/locale.am12
-rw-r--r--storage/mroonga/build/makefiles/sphinx-build.am17
-rw-r--r--storage/mroonga/build/makefiles/sphinx.am179
-rw-r--r--storage/mroonga/config.sh.in20
-rw-r--r--storage/mroonga/configure.ac540
-rw-r--r--storage/mroonga/data/Makefile.am4
-rw-r--r--storage/mroonga/data/install.sql.in35
-rw-r--r--storage/mroonga/data/uninstall.sql12
-rw-r--r--storage/mroonga/gpg_uid1
-rw-r--r--storage/mroonga/ha_mroonga.cpp17086
-rw-r--r--storage/mroonga/ha_mroonga.def18
-rw-r--r--storage/mroonga/ha_mroonga.hpp1309
-rw-r--r--storage/mroonga/lib/Makefile.am23
-rw-r--r--storage/mroonga/lib/libmrn_need_mysql_sources.am50
-rw-r--r--storage/mroonga/lib/libmrn_no_mysql_sources.am9
-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_column_name.cpp69
-rw-r--r--storage/mroonga/lib/mrn_column_name.hpp39
-rw-r--r--storage/mroonga/lib/mrn_condition_converter.cpp637
-rw-r--r--storage/mroonga/lib/mrn_condition_converter.hpp85
-rw-r--r--storage/mroonga/lib/mrn_context_pool.cpp120
-rw-r--r--storage/mroonga/lib/mrn_context_pool.hpp41
-rw-r--r--storage/mroonga/lib/mrn_count_skip_checker.cpp303
-rw-r--r--storage/mroonga/lib/mrn_count_skip_checker.hpp57
-rw-r--r--storage/mroonga/lib/mrn_current_thread.hpp27
-rw-r--r--storage/mroonga/lib/mrn_database.cpp89
-rw-r--r--storage/mroonga/lib/mrn_database.hpp47
-rw-r--r--storage/mroonga/lib/mrn_database_manager.cpp364
-rw-r--r--storage/mroonga/lib/mrn_database_manager.hpp52
-rw-r--r--storage/mroonga/lib/mrn_database_repairer.cpp300
-rw-r--r--storage/mroonga/lib/mrn_database_repairer.hpp67
-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.cpp242
-rw-r--r--storage/mroonga/lib/mrn_encoding.hpp36
-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.cpp145
-rw-r--r--storage/mroonga/lib/mrn_field_normalizer.hpp47
-rw-r--r--storage/mroonga/lib/mrn_grn.hpp39
-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.cpp136
-rw-r--r--storage/mroonga/lib/mrn_index_table_name.hpp55
-rw-r--r--storage/mroonga/lib/mrn_lock.cpp36
-rw-r--r--storage/mroonga/lib/mrn_lock.hpp37
-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.cpp712
-rw-r--r--storage/mroonga/lib/mrn_multiple_column_key_codec.hpp100
-rw-r--r--storage/mroonga/lib/mrn_mysqlservices.cpp28
-rw-r--r--storage/mroonga/lib/mrn_operation.cpp51
-rw-r--r--storage/mroonga/lib/mrn_operation.hpp42
-rw-r--r--storage/mroonga/lib/mrn_operations.cpp401
-rw-r--r--storage/mroonga/lib/mrn_operations.hpp60
-rw-r--r--storage/mroonga/lib/mrn_parameters_parser.cpp177
-rw-r--r--storage/mroonga/lib/mrn_parameters_parser.hpp59
-rw-r--r--storage/mroonga/lib/mrn_path_mapper.cpp229
-rw-r--r--storage/mroonga/lib/mrn_path_mapper.hpp55
-rw-r--r--storage/mroonga/lib/mrn_query_parser.cpp361
-rw-r--r--storage/mroonga/lib/mrn_query_parser.hpp67
-rw-r--r--storage/mroonga/lib/mrn_smart_bitmap.cpp42
-rw-r--r--storage/mroonga/lib/mrn_smart_bitmap.hpp36
-rw-r--r--storage/mroonga/lib/mrn_smart_grn_obj.cpp59
-rw-r--r--storage/mroonga/lib/mrn_smart_grn_obj.hpp40
-rw-r--r--storage/mroonga/lib/mrn_table_fields_offset_mover.cpp47
-rw-r--r--storage/mroonga/lib/mrn_table_fields_offset_mover.hpp33
-rw-r--r--storage/mroonga/lib/mrn_time_converter.cpp295
-rw-r--r--storage/mroonga/lib/mrn_time_converter.hpp51
-rw-r--r--storage/mroonga/lib/mrn_value_decoder.cpp75
-rw-r--r--storage/mroonga/lib/mrn_value_decoder.hpp34
-rw-r--r--storage/mroonga/lib/mrn_windows.hpp31
-rw-r--r--storage/mroonga/mrn_constants.hpp49
-rw-r--r--storage/mroonga/mrn_err.h46
-rw-r--r--storage/mroonga/mrn_macro.hpp30
-rw-r--r--storage/mroonga/mrn_mysql.h74
-rw-r--r--storage/mroonga/mrn_mysql_compat.h422
-rw-r--r--storage/mroonga/mrn_table.cpp1198
-rw-r--r--storage/mroonga/mrn_table.hpp179
-rw-r--r--storage/mroonga/mrn_variables.hpp51
-rw-r--r--storage/mroonga/mrn_version.h.in40
-rw-r--r--storage/mroonga/mysql-test/Makefile.am8
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_64bit.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_freebsd.inc20
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_ha_mroonga_so.inc26
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_embedded.inc19
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_lz4.inc20
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zlib.inc20
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zstd.inc20
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_mariadb.inc19
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_osx.inc31
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_solaris.inc20
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_strict_sql_mode.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_version.inc33
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/check_windows.inc20
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_fractional_seconds.inc32
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_freebsd.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_groonga_plugin_register.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb_10_2_or_later.inc26
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga.inc47
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_deinit.inc42
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_helper.inc17
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql_5_7_or_later.inc26
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_signed_64bit_time_t.inc28
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_solaris.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_strict_sql_mode.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0_or_later.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_5.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6_or_later.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7_or_later.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/load_mroonga_functions.inc28
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/print_groonga_query_log.inc8
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_freebsd.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_0_or_later.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1_or_earlier.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_2_or_later.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_5_5.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_5.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7_or_later.inc24
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_osx.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_signed_64bit_time_t.inc28
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_solaris.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/skip_strict_sql_mode.inc21
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_lz4.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zlib.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zstd.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/unload_mroonga_functions.inc26
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_lz4.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zlib.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zstd.inc22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/disabled.def10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_after.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_first.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_comment.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_parameter.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_comment.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_parameter.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_cp932.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_utf8.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multiple.result44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_plain.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_type_comment.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_token_filters_one_token_filter.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_duplicated.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_multiple_column_duplicated.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_key_multiple_column_with_data.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_primary_key.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_comment_not_for_mroonga.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_have_index.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_after.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_first.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_multiple.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_no_order.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_decimal.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_fulltext_index.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_token_filter.result63
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_create_fulltext.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_table.result41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_ujis.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_utf8.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_multiple_column.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_normal.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_primary.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_truncate.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_updating.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_multiple.result36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_one.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_key_multiple_column_with_data.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_primary_key.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_table.result42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_ujis.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_utf8.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_multiple_column.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_normal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_primary.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_no_primary_key.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_normal.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_table.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_drop_table.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_after.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_first.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_no_order.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_recreate_anonymous_index_at_once.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_rename_table.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/alter_table_spatial.result132
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_TODO_SPLIT_ME.result53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_table_param.result70
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_text.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/binlog_TODO_SPLIT_ME.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/check_table_not_broken.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_general_ci_french.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_french.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_japanese.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_french.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_japanese.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_comment_index_not_for_mroonga.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_comment_normal_not_for_mroonga.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_date_with_index.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_date_without_index.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_date_zero_date.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_2038.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_before_unix_epoch.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_max.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_out_of_range.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_2038.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_before_unix_epoch.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_max.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_strict_sql_mode_out_of_range.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_5_out_of_range.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_6_or_later_out_of_range.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_with_index.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_without_index.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_freebsd_before_unix_epoch.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_date.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_month_day.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_date.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_month_day.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_null.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_with_index.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_without_index.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_date.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_month_day.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_with_index.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_without_index.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_with_index.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_without_index.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_enum_less_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_enum_many_with_index.result287
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_add_column.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_delete.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_drop_column.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_insert.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_reindex.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_update.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_add_column.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_delete.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_drop_column.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_insert.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_add_index.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.result8
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mysql_5_7_or_later_add_index.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_update.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id__id.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id_invalid_id.result8
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_other_table.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_vector_other_table.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_int_other_table.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_reference.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_lz4.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zlib.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zstd.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_lz4.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zlib.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zstd.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_with_not_for_mroonga_comment.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_order_by_with_function.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_reference.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_int_with_index_zero_value.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_json_insert.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_cp932.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_utf8.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_set_16_with_index.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_set_24_with_index.result48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_set_32_with_index.result56
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_set_64_with_index.result88
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_set_8_with_index.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_signed_bigint_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_signed_int_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_signed_mediumint_with_index.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_signed_smallint_with_index.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_signed_tinyint_with_index.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_time_fractional_seconds_with_index.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_time_with_index.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_fractional_seconds_with_index.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_with_index.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_tinyint_without_index.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_without_index.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_int_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_mediumint_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_smallint_with_index.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_tinyint_with_index.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_year_with_index.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/column_year_without_index.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/count_star.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_database_name_slash.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_TODO_SPLIT_ME.result172
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_comment.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_parameter.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_comment.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_nonexistent.result6
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_parameter.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_comment.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_nonexistent.result6
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_comment_normal.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_default_tokenizer.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_comment.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_medium.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_small.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_none.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_parameter.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_none.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_with_position_and_with_weight.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_comment.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_fulltext_index_bin.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_index_bin.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_none.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_parameter.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_comment.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_default.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_off.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_multiple_token_filters.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_one_token_filter.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_parameter.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_comment.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_default.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_off.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_parameter.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_default.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_hash.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_multiple_token_filters.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_one_token_filter.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_stop_word.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/delete_fulltext_column.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/delete_index_btree_many_records.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_no_unique.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_unique.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/delete_normal_column.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/delete_unsigned_bigint.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/drop_database_TODO_SPLIT_ME.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/drop_database_no_table.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/drop_table_TODO_SPLIT_ME.result5
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/flush_logs.result1
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_add.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_drop.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_create.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_existent.result53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_nonexistent.result53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_existent.result51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_nonexistent.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_rename.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_existent.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_nonexistent.result53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_empty_query.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_escape.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_leading_not.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_all.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_operator.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_selector.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_full_spec.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_no_weight.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_omit_section.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_three_or_more_sections.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error_and_log.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore_and_log.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_ascii.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_cp932.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_eucjpms.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_japanese.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_utf8mb4.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_empty_query.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_found_rows.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_groonga_varchar_vector.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_index_recreate.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_select.result46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_values.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_delete.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_insert.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_recreate.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_update.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_index.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_no_primary_key.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_not_match_against.result68
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_or.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_against.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_match.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_no_where.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_same_match_against.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_asc.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_desc.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_against.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_match.result36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_no_where.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_same_match_against.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_two_inner_join.result41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_10_0_no_such_key.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_5_no_such_key.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_6_no_such_key.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_command_auto-escape.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_command_select.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_command_special-database-name.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_missing.result3
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_not_string.result3
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_target_characters_is_not_string.result3
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_all.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_custom.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_join.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_match_against.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_named.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_nested.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_decimal.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_integer.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_real.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_string.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_dynamic_keyword.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_japanese.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_multiple_keywords.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_normalizer.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query_pragma.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_record.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_grn_id.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_reference.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_set.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_default.result3
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_normalizer.result3
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_record.result7
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_multiple.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_no_index.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_one.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_pragma.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_ascii.result120
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_cp932.result91
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_eucjpms.result91
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_dynamic_keyword.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_japanese.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_keywords.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_snippets.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query_pragma.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_record.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_nonexistent_charset.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_unsupported_charset.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_japanese.result95
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/geometry_bulk_insert_null.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/geometry_contains.result167
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_bulk_insert_null.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_contains.result169
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/i_s.result7
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_datetime.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_time.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_timestamp.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_btree_normal_column_insert.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_normal.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_primary.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_unique.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_hash_normal_column_insert.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_hash_strict_sql_mode_id_primary.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_delete.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_smallint.result65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_bigint.result65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_int.result65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_smallint.result65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_varchar.result65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_asc_asc.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_desc_desc.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_delete.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_select_int.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_strict_sql_mode_update.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_update.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than_or_equal.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than_or_equal.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_recreate.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_replace.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_double.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_float.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_int.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_max.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_min.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_string.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_varchar.result41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_32bit_equal.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_64bit_equal.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_index_read.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_asc.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_desc.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_asc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_desc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_reinsert.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_index_read.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_asc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_desc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_reinsert.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_decimal.result36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_index_read.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_asc.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_desc.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_reinsert.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_index_read.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_asc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_desc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_reinsert.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_varchar.resultbin0 -> 1027 bytes
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_32bit_equal.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_64bit_equal.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_index_read.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_asc.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_desc.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_asc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_desc.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_reinsert.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_int.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_string.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_exact_length.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_null_character.resultbin0 -> 387 bytes
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_short.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_date.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_with_fractional_seconds.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_without_fractional_seconds.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_with_fractional_seconds.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_without_fractional_seconds.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_with_fractional_seconds.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_without_fractional_seconds.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_with_fractional_seconds.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_without_fractional_seconds.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_varchar_null_character.resultbin0 -> 390 bytes
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_primary_year.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_asc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_desc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_asc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_desc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_asc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_desc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_asc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_desc.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_asc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_desc.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_asc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_desc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_asc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_desc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_asc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_desc.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint_unsigned.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_double.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_float.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int_unsigned.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint_unsigned.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint_unsigned.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint.result38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint_unsigned.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar_collation.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_int.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_varchar.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_int.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_varchar.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_all.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_by_primary_key.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_unique_insert_after_error.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_unique_search_after_duplicated.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_unique_varchar.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_update_multiple_column.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/index_update_single_column.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/information_schema_plugins.result.in4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_none.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_use.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_data_length.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/insert_TODO_SPLIT_ME.result78
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/insert_delayed.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_primary_key.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_unique_key.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/insert_virtual_column.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/like_unicode_ci.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/lock_tables_read.result7
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_multithread.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_single_thread.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_disabled.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_and.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_between.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_equal.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_boolean_mode.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_natural_language_mode.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater_equal.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less_equal.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_not_equal.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_view.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_multiple_conditions.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_between.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_equal.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater_equal.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less_equal.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_not_equal.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_disabled.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_multiple_match_againsts.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_no_limit.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_cp932.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between_over.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_equal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than_or_equal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than_or_equal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_duplicated_order_by_columns.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_name.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_value.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_have_primary_key.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between_over.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_equal.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than_or_equal.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than_or_equal.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_primary_key.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_where_clause.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_asc.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_desc.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_id.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_match_against.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_select_match_against.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between_over.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_equal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than_or_equal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than_or_equal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_with_index.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_without_index.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between_over.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_equal.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than_or_equal.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than_or_equal.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/partition_insert.result42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/partition_update.result43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/replace_geometry.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/replace_select_varchar.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/replace_text.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/replace_varchar.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/replace_vector.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/replace_without_key.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_all.result198
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_equal.result12
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_not_equal.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_with_index.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_without_index.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_pkey.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/select_secondary_key.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/show_create_table_TODO_SPLIT_ME.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/sub_query_fulltext.result35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/temporary_table.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/truncate.result47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_binlog_row.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_fulltext.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_id_hash_index.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_id_unique_hash_index.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_int.result42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_last_insert_grn_id.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/update_virtual_column.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_column.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_leading_not.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_update.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_query.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_script.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_database_path_prefix.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_new_value.result6
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_same_value.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_new_value.result6
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_same_value.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_delete.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_insert.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_update.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_enable_operations_recording_insert.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_disable.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_invalid.result6
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_no_retry.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_valid.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_new_value.result6
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_nonexistent_path.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_same_value.result4
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_log_level_TODO_SPLIT_ME.result49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_global.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_session.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_global.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_not_found_in_limit.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_session.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_empty_value.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_null_value.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_empty_value.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_null_value.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_new_value.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_same_value.result10
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_vector_column_delimiter.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/r/variable_version.result.in3
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/suite.opt1
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/suite.pm23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_after.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_first.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_comment.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_parameter.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_comment.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_parameter.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_cp932.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_utf8.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multiple.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_plain.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_type_comment.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_token_filters_one_token_filter.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_duplicated.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_multiple_column_duplicated.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_key_multiple_column_with_data.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_primary_key.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_comment_not_for_mroonga.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_have_index.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_after.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_first.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_multiple.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_no_order.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_decimal.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_fulltext_index.test58
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_token_filter.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_create_fulltext.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_table.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_ujis.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_utf8.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_multiple_column.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_normal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_primary.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_truncate.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_updating.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_multiple.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_one.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_key_multiple_column_with_data.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_primary_key.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_table.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_ujis.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_utf8.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_multiple_column.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_normal.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_primary.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_no_primary_key.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_normal.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_table.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_drop_table.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_after.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_first.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_no_order.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_recreate_anonymous_index_at_once.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_rename_table.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/alter_table_spatial.test151
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_TODO_SPLIT_ME.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_table_param.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_text.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/binlog_TODO_SPLIT_ME.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/check_table_not_broken.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_general_ci_french.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_french.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_japanese.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_french.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_japanese.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_comment_index_not_for_mroonga.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_comment_normal_not_for_mroonga.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_date_with_index.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_date_without_index.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_date_zero_date.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_2038.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_before_unix_epoch.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_max.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_out_of_range.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_2038.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_before_unix_epoch.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_max.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_strict_sql_mode_out_of_range.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_5_out_of_range.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_6_or_later_out_of_range.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_with_index.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_without_index.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_freebsd_before_unix_epoch.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_date.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_month_day.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_date.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_month_day.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_null.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_with_index.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_without_index.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_date.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_month_day.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_with_index.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_without_index.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_with_index.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_without_index.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_enum_less_with_index.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_enum_many_with_index.test298
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_add_column.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_delete.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_drop_column.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_insert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_reindex.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_update.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_add_column.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_delete.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_drop_column.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_insert.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_add_index.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.test32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mysql_5_7_or_later_add_index.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_update.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id__id.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id_invalid_id.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_other_table.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_vector_other_table.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_int_other_table.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_reference.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_lz4.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zlib.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zstd.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_lz4.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zlib.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zstd.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_with_not_for_mroonga_comment.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_order_by_with_function.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_reference.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_int_with_index_zero_value.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_json_insert.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_cp932.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_utf8.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_set_16_with_index.test56
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_set_24_with_index.test65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_set_32_with_index.test74
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_set_64_with_index.test110
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_set_8_with_index.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_signed_bigint_with_index.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_signed_int_with_index.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_signed_mediumint_with_index.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_signed_smallint_with_index.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_signed_tinyint_with_index.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_time_fractional_seconds_with_index.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_time_with_index.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_fractional_seconds_with_index.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_with_index.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_tinyint_without_index.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_with_index.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_without_index.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_int_with_index.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_mediumint_with_index.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_smallint_with_index.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_tinyint_with_index.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_year_with_index.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/column_year_without_index.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/count_star.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_database_name_slash.test60
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_TODO_SPLIT_ME.test149
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_comment.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_parameter.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_comment.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_nonexistent.test29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_parameter.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_comment.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_nonexistent.test29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_comment_normal.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_default_tokenizer.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_comment.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_medium.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_small.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_none.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_parameter.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_none.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_with_position_and_with_weight.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_comment.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_fulltext_index_bin.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_index_bin.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_none.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_parameter.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_comment.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_default.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_off.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_multiple_token_filters.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_one_token_filter.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_parameter.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_comment.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_default.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_off.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_parameter.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_default.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_hash.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_multiple_token_filters.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_one_token_filter.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_stop_word.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/delete_fulltext_column.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/delete_index_btree_many_records.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_no_unique.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_unique.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/delete_normal_column.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/delete_unsigned_bigint.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/drop_database_TODO_SPLIT_ME.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/drop_database_no_table.test57
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/drop_table_TODO_SPLIT_ME.test29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/flush_logs.test21
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_add.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_drop.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_create.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_existent.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_nonexistent.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_existent.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_nonexistent.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_rename.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_existent.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_nonexistent.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_empty_query.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_escape.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_leading_not.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_all.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_operator.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_selector.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_full_spec.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_no_weight.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_omit_section.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.test63
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_three_or_more_sections.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error_and_log.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore_and_log.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_ascii.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_cp932.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_eucjpms.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_japanese.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_utf8mb4.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_empty_query.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_found_rows.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_groonga_varchar_vector.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_index_recreate.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_select.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_values.test32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_delete.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_insert.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_recreate.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_update.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_index.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_no_primary_key.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_not_match_against.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_or.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_against.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_match.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_no_where.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_same_match_against.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_asc.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_desc.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_against.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_match.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_no_where.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_same_match_against.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_two_inner_join.test69
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_10_0_no_such_key.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_5_no_such_key.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_6_no_such_key.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_command_auto-escape.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_command_select.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_command_special-database-name.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_missing.test27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_not_string.test27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_target_characters_is_not_string.test27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_all.test26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_custom.test26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_join.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_match_against.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_named.test26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_nested.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_decimal.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_integer.test26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_real.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_string.test26
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_dynamic_keyword.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_japanese.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_multiple_keywords.test25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_normalizer.test25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query_pragma.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_record.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_grn_id.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_reference.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_set.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_default.test24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_normalizer.test24
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_record.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_multiple.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_no_index.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_one.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_pragma.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_ascii.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_cp932.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_eucjpms.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_dynamic_keyword.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_japanese.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_keywords.test25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_snippets.test29
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query_pragma.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_record.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_nonexistent_charset.test28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_unsupported_charset.test28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_japanese.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/geometry_bulk_insert_null.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/geometry_contains.test154
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_bulk_insert_null.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_contains.test152
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/i_s.test23
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_datetime.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_time.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_timestamp.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_btree_normal_column_insert.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_normal.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_primary.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_unique.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_hash_normal_column_insert.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_hash_strict_sql_mode_id_primary.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_delete.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_smallint.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_bigint.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_int.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_smallint.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_varchar.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_asc_asc.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_desc_desc.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_delete.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_select_int.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_strict_sql_mode_update.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_update.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than_or_equal.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than_or_equal.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_recreate.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_replace.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_double.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_float.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_int.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_max.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_min.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_string.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_varchar.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_32bit_equal.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_64bit_equal.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_index_read.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_asc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_desc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_asc.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_desc.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_reinsert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_index_read.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_asc.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_desc.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_reinsert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_decimal.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_index_read.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_asc.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_desc.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_reinsert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_index_read.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_asc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_desc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_reinsert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_varchar.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_32bit_equal.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_64bit_equal.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_index_read.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_asc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_desc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_asc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_desc.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_reinsert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_int.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_string.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_exact_length.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_null_character.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_short.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_date.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_with_fractional_seconds.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_without_fractional_seconds.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_with_fractional_seconds.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_without_fractional_seconds.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_with_fractional_seconds.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_without_fractional_seconds.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_with_fractional_seconds.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_without_fractional_seconds.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_varchar_null_character.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_primary_year.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_asc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_desc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_asc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_desc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_asc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_desc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_asc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_desc.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_asc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_desc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_asc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_desc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_asc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_desc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_asc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_desc.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint_unsigned.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_double.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_float.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int_unsigned.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint_unsigned.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint_unsigned.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint_unsigned.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar_collation.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_int.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_varchar.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_int.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_varchar.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_all.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_by_primary_key.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_unique_insert_after_error.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_unique_search_after_duplicated.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_unique_varchar.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_update_multiple_column.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/index_update_single_column.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/information_schema_plugins.test22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_none.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_use.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_data_length.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/insert_TODO_SPLIT_ME.test89
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/insert_delayed.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_primary_key.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_unique_key.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/insert_virtual_column.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/like_unicode_ci.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/lock_tables_read.test32
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_multithread.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_single_thread.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_disabled.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_and.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_between.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_equal.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_boolean_mode.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_natural_language_mode.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater_equal.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less_equal.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_not_equal.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_view.test56
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_multiple_conditions.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_between.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_equal.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater_equal.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less_equal.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_not_equal.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_disabled.test59
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_multiple_match_againsts.test57
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_no_limit.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_cp932.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between_over.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_equal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than_or_equal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than_or_equal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_duplicated_order_by_columns.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_name.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_value.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_have_primary_key.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between_over.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_equal.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than_or_equal.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than_or_equal.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_primary_key.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_where_clause.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_asc.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_desc.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_id.test56
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_match_against.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_select_match_against.test56
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between_over.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_equal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than_or_equal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than_or_equal.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_with_index.test56
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_without_index.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between_over.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_equal.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than_or_equal.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than_or_equal.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/partition_insert.test52
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/partition_update.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test57
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/replace_geometry.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/replace_select_varchar.test65
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/replace_text.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/replace_varchar.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/replace_vector.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/replace_without_key.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_all.test100
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_equal.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_not_equal.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_with_index.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_without_index.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_pkey.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/select_secondary_key.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/show_create_table_TODO_SPLIT_ME.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/sub_query_fulltext.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/temporary_table.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/truncate.test61
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_binlog_row.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_fulltext.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_id_hash_index.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_id_unique_hash_index.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_int.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_last_insert_grn_id.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/update_virtual_column.test49
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_column.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_leading_not.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_update.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_query.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_script.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_database_path_prefix.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_new_value.test25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_same_value.test22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_new_value.test25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_same_value.test22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_delete.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_insert.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_update.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_enable_operations_recording_insert.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_disable.test28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_invalid.test28
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_no_retry.test27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_valid.test27
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_new_value.test25
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_nonexistent_path.test22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_same_value.test22
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_log_level_TODO_SPLIT_ME.test61
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_global.test61
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_session.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_global.test60
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.test60
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_not_found_in_limit.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_session.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_empty_value.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_null_value.test31
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_empty_value.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_null_value.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_new_value.test33
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_same_value.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_vector_column_delimiter.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/storage/t/variable_version.test22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/disabled.def2
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_cp932.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_utf8.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_column_comment.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_engine.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_comment_change_engine.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_create_fulltext.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_fulltext.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_multiple_column.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_normal.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_primary.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_updating.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_drop_column.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_fulltext.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_lock_tables.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_multiple_column.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_normal.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_primary.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_fulltext.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_rename_table.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_spatial.result123
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/auto_increment_text.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/binlog_TODO_SPLIT_ME.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/check_table_for_upgrade.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_comment_index_not_for_mroonga.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_add_column.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_delete.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_drop_column.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_insert.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_reindex.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_update.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_column.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_fulltext_index.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_index.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_delete.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_drop_column.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_insert.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_update.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_cp932.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_utf8.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/column_normal_comment.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/count_star.result11
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_mysql_5_7_or_later_with_index.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_with_index.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_TODO_SPLIT_ME.result109
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_comment_combined.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_comment.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_none.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_parameter.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_none.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_with_position_and_with_weight.result9
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_comment.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_fulltext_index_bin.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_parameter.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_parser_comment.result25
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_multiple_token_filters.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_one_token_filter.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_parameter.result30
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_comment.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_parameter.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/delete_TODO_SPLIT_ME.result55
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/delete_all.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/drop_table_new_connection.result13
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_leading_not.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_multiple_match_against.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result19
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result16
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_full_spec.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_no_weight.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_omit_section.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_ascii.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_cp932.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_eucjpms.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_japanese.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_index_recreate.result32
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_select.result70
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_values.result17
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_many_records.result4381
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_matched_order.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_no_order.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_no_where_both_order.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_delete.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_insert.result29
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_recreate.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_update.result26
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_index.result23
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_myisam.result194
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_not_match_against.result68
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_TODO_SPLIT_ME.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_transaction.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_reference.result15
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_set.result21
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_contains.result160
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_delete.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_update.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/index_force_index_not_used.result8
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/insert_TODO_SPLIT_ME.result78
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/insert_bulk.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.result36
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.result39
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_disk_sweep.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_mysql_5_7_or_later_disk_sweep.result20
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_TODO_SPLIT_ME.result53
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_direction.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_where_clause.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_order_by_primary_key.result27
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/performance_schema.result22
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/temporary_table.result14
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_query_cache.result28
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_delete.result40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_update.result37
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/truncate.result47
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/update_fulltext.result33
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/update_int.result36
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_delete.result45
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_insert.result34
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_update.result31
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_global.result18
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_session.result24
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/suite.opt1
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/suite.pm23
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_cp932.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_utf8.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_column_comment.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_engine.test59
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_comment_change_engine.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_create_fulltext.test56
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_fulltext.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_multiple_column.test52
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_normal.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_primary.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_updating.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_drop_column.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_fulltext.test52
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_lock_tables.test45
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_multiple_column.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_normal.test52
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_primary.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_fulltext.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_rename_table.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_spatial.test150
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/auto_increment_text.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/binlog_TODO_SPLIT_ME.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/check_table_for_upgrade.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_comment_index_not_for_mroonga.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_add_column.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_delete.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_drop_column.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_insert.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_reindex.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_update.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_column.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_fulltext_index.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_index.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_delete.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_drop_column.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_insert.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_update.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_cp932.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_utf8.test53
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/column_normal_comment.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/count_star.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_mysql_5_7_or_later_with_index.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_with_index.test57
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_TODO_SPLIT_ME.test101
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_comment_combined.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_comment.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_none.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_parameter.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_none.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_with_position_and_with_weight.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_comment.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_fulltext_index_bin.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_parameter.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_parser_comment.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_multiple_token_filters.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_one_token_filter.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_parameter.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_comment.test37
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_parameter.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/delete_TODO_SPLIT_ME.test59
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/delete_all.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/drop_table_new_connection.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_leading_not.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_multiple_match_against.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test40
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_full_spec.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_no_weight.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_omit_section.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_ascii.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_cp932.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_eucjpms.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_japanese.test35
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_index_recreate.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_select.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_values.test34
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_many_records.test4135
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_matched_order.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_no_order.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_no_where_both_order.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_delete.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_insert.test42
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_recreate.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_update.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_index.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_myisam.test101
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_not_match_against.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_TODO_SPLIT_ME.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_transaction.test73
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_reference.test36
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_set.test38
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_contains.test145
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_delete.test48
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_update.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/index_force_index_not_used.test32
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/insert_TODO_SPLIT_ME.test91
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/insert_bulk.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.test51
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_disk_sweep.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_mysql_5_7_or_later_disk_sweep.test44
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_TODO_SPLIT_ME.test60
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_direction.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_where_clause.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_order_by_primary_key.test50
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt1
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_files.test58
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test58
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/temporary_table.test39
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_query_cache.test63
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_delete.test58
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_update.test55
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/truncate.test62
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/update_fulltext.test43
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/update_int.test41
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_delete.test54
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_insert.test46
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_update.test47
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_global.test60
-rw-r--r--storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_session.test52
-rw-r--r--storage/mroonga/packages/Makefile.am7
-rw-r--r--storage/mroonga/packages/apt/Makefile.am91
-rw-r--r--storage/mroonga/packages/apt/Vagrantfile50
-rwxr-xr-xstorage/mroonga/packages/apt/build-deb.sh106
-rw-r--r--storage/mroonga/packages/apt/env.sh.in16
-rwxr-xr-xstorage/mroonga/packages/apt/sign-packages.sh42
-rwxr-xr-xstorage/mroonga/packages/apt/sign-repository.sh46
-rwxr-xr-xstorage/mroonga/packages/apt/update-repository.sh130
-rw-r--r--storage/mroonga/packages/rpm/Makefile.am2
-rw-r--r--storage/mroonga/packages/rpm/centos/Makefile.am19
-rw-r--r--storage/mroonga/packages/rpm/centos/mariadb-mroonga.spec.in486
-rw-r--r--storage/mroonga/packages/rpm/centos/mysql55-mroonga.spec.in311
-rw-r--r--storage/mroonga/packages/rpm/centos/mysql56-community-mroonga.spec.in374
-rw-r--r--storage/mroonga/packages/rpm/centos/percona-server-56-mroonga.spec.in273
-rw-r--r--storage/mroonga/packages/source/Makefile.am125
-rw-r--r--storage/mroonga/packages/source/patches/mariadb-10.0.3-windows-build.diff9
-rw-r--r--storage/mroonga/packages/ubuntu/Makefile.am57
-rwxr-xr-xstorage/mroonga/packages/ubuntu/upload.rb247
-rw-r--r--storage/mroonga/packages/windows/Makefile.am12
-rw-r--r--storage/mroonga/packages/windows/README.md21
-rw-r--r--storage/mroonga/packages/windows/build-vc2015-msi-32.bat8
-rw-r--r--storage/mroonga/packages/windows/build-vc2015-msi-64.bat8
-rw-r--r--storage/mroonga/packages/windows/build-vc2015-zip-32.bat13
-rw-r--r--storage/mroonga/packages/windows/build-vc2015-zip-64.bat13
-rw-r--r--storage/mroonga/packages/windows/build-vc2015.bat4
-rw-r--r--storage/mroonga/packages/yum/Makefile.am77
-rw-r--r--storage/mroonga/packages/yum/Vagrantfile42
-rwxr-xr-xstorage/mroonga/packages/yum/build-in-vm.sh85
-rwxr-xr-xstorage/mroonga/packages/yum/build-rpm.sh182
-rw-r--r--storage/mroonga/packages/yum/env.sh.in32
-rwxr-xr-xstorage/mroonga/packages/yum/sign-rpm.sh52
-rwxr-xr-xstorage/mroonga/packages/yum/update-repository.sh27
-rw-r--r--storage/mroonga/plugin_version1
-rw-r--r--storage/mroonga/required_groonga_normalizer_mysql_version1
-rw-r--r--storage/mroonga/required_groonga_version1
-rw-r--r--storage/mroonga/sources.am12
-rw-r--r--storage/mroonga/test/Makefile.am14
-rwxr-xr-xstorage/mroonga/test/run-sql-test.sh244
-rwxr-xr-xstorage/mroonga/test/run-unit-test.sh49
-rw-r--r--storage/mroonga/test/unit/Makefile.am27
-rw-r--r--storage/mroonga/test/unit/test_mrn_path_mapper.cpp134
-rw-r--r--storage/mroonga/tools/Makefile.am6
-rwxr-xr-xstorage/mroonga/tools/prepare-sphinx-html.rb175
-rwxr-xr-xstorage/mroonga/tools/travis/before_script.sh95
-rwxr-xr-xstorage/mroonga/tools/travis/install.sh157
-rwxr-xr-xstorage/mroonga/tools/travis/script.sh136
-rwxr-xr-xstorage/mroonga/tools/upload-to-github.rb42
-rw-r--r--storage/mroonga/udf/Makefile.am10
-rw-r--r--storage/mroonga/udf/mrn_udf_command.cpp294
-rw-r--r--storage/mroonga/udf/mrn_udf_escape.cpp245
-rw-r--r--storage/mroonga/udf/mrn_udf_highlight_html.cpp494
-rw-r--r--storage/mroonga/udf/mrn_udf_last_insert_grn_id.cpp55
-rw-r--r--storage/mroonga/udf/mrn_udf_normalize.cpp212
-rw-r--r--storage/mroonga/udf/mrn_udf_query_expand.cpp282
-rw-r--r--storage/mroonga/udf/mrn_udf_snippet.cpp340
-rw-r--r--storage/mroonga/udf/mrn_udf_snippet_html.cpp444
-rw-r--r--storage/mroonga/udf/sources.am9
-rw-r--r--storage/mroonga/vendor/groonga/CMakeLists.txt662
-rw-r--r--storage/mroonga/vendor/groonga/COPYING502
-rw-r--r--storage/mroonga/vendor/groonga/Makefile.am141
-rw-r--r--storage/mroonga/vendor/groonga/README.md62
-rw-r--r--storage/mroonga/vendor/groonga/appveyor.yml72
-rwxr-xr-xstorage/mroonga/vendor/groonga/autogen.sh33
-rw-r--r--storage/mroonga/vendor/groonga/base_version1
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/Makefile.am153
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-between-sequential.c276
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-cache.c155
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-ctx-create.c198
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-geo-distance.c506
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-geo-select.c276
-rwxr-xr-xstorage/mroonga/vendor/groonga/benchmark/bench-geo-select.sh38
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-nfkc.c275
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer-ddl.grn16
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer.c214
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-range-select.c280
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-result-set.c151
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/bench-table-factory.c277
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/fixtures/Makefile.am2
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/13_2010.CSV.xzbin0 -> 2355640 bytes
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/Makefile.am4
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/README.txt6
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/format_2010.html111
-rwxr-xr-xstorage/mroonga/vendor/groonga/benchmark/geo-distance-summary.rb140
-rwxr-xr-xstorage/mroonga/vendor/groonga/benchmark/geo-select-generate-grn.rb53
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/Makefile.am24
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.c315
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.h64
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.c83
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.h34
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/benchmark.c35
-rw-r--r--storage/mroonga/vendor/groonga/benchmark/lib/benchmark.h32
-rw-r--r--storage/mroonga/vendor/groonga/bindings/php/config.m466
-rw-r--r--storage/mroonga/vendor/groonga/bindings/php/config.w326
-rw-r--r--storage/mroonga/vendor/groonga/bindings/php/groonga.c221
-rw-r--r--storage/mroonga/vendor/groonga/bindings/php/groonga.dsp112
-rw-r--r--storage/mroonga/vendor/groonga/bindings/php/php_groonga.h125
-rw-r--r--storage/mroonga/vendor/groonga/bindings/php/tests/001.phpt29
-rw-r--r--storage/mroonga/vendor/groonga/bindings/python/ql/groongaql.c364
-rwxr-xr-xstorage/mroonga/vendor/groonga/bindings/python/ql/setup.py22
-rw-r--r--storage/mroonga/vendor/groonga/build/Makefile.am2
-rw-r--r--storage/mroonga/vendor/groonga/build/ac_macros/check_functions.m411
-rw-r--r--storage/mroonga/vendor/groonga/build/ac_macros/check_headers.m419
-rw-r--r--storage/mroonga/vendor/groonga/build/cmake_modules/Makefile.am2
-rw-r--r--storage/mroonga/vendor/groonga/build/cmake_modules/ReadFileList.cmake27
-rw-r--r--storage/mroonga/vendor/groonga/build/makefiles/LC_MESSAGES.am5
-rw-r--r--storage/mroonga/vendor/groonga/build/makefiles/gettext.am84
-rw-r--r--storage/mroonga/vendor/groonga/build/makefiles/locale.am12
-rw-r--r--storage/mroonga/vendor/groonga/build/makefiles/sphinx-build.am14
-rw-r--r--storage/mroonga/vendor/groonga/build/makefiles/sphinx.am80
-rw-r--r--storage/mroonga/vendor/groonga/bundled_lz4_version1
-rw-r--r--storage/mroonga/vendor/groonga/bundled_mecab_naist_jdic_version1
-rw-r--r--storage/mroonga/vendor/groonga/bundled_mecab_version1
-rw-r--r--storage/mroonga/vendor/groonga/bundled_message_pack_version1
-rw-r--r--storage/mroonga/vendor/groonga/config.h.cmake147
-rw-r--r--storage/mroonga/vendor/groonga/config.sh.in7
-rw-r--r--storage/mroonga/vendor/groonga/configure.ac1788
-rw-r--r--storage/mroonga/vendor/groonga/examples/Makefile.am1
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/Makefile.am34
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/edict/Makefile.am4
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/edict/edict-import.sh27
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/edict/edict2grn.rb34
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/eijiro/Makefile.am4
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro-import.sh12
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro2grn.rb61
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/gene95/Makefile.am4
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/gene95/gene-import.sh26
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/gene95/gene2grn.rb33
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/dictionary.css3
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.pngbin0 -> 180 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.pngbin0 -> 178 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.pngbin0 -> 120 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.pngbin0 -> 105 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_dadada_1x400.pngbin0 -> 111 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.pngbin0 -> 110 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.pngbin0 -> 119 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.pngbin0 -> 101 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_222222_256x240.pngbin0 -> 4369 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_2e83ff_256x240.pngbin0 -> 4369 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_454545_256x240.pngbin0 -> 4369 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_888888_256x240.pngbin0 -> 4369 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_cd0a0a_256x240.pngbin0 -> 4369 bytes
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/jquery-ui-1.8.12.custom.css578
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/index.html28
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/js/dictionary.js82
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-1.7.2.js9404
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-ui-1.8.18.custom.js11802
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/init-db.sh10
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/jmdict/Makefile.am3
-rwxr-xr-xstorage/mroonga/vendor/groonga/examples/dictionary/jmdict/jmdict.rb42
-rw-r--r--storage/mroonga/vendor/groonga/examples/dictionary/readme.txt71
-rw-r--r--storage/mroonga/vendor/groonga/gpg_uid1
-rw-r--r--storage/mroonga/vendor/groonga/groonga-arrow.pc.in4
-rw-r--r--storage/mroonga/vendor/groonga/groonga-httpd-conf.sh.in34
-rw-r--r--storage/mroonga/vendor/groonga/groonga.pc.in20
-rw-r--r--storage/mroonga/vendor/groonga/include/CMakeLists.txt18
-rw-r--r--storage/mroonga/vendor/groonga/include/Makefile.am8
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga.h53
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga.hpp21
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/Makefile.am43
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/accessor.h34
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/array.h89
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/arrow.h38
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/arrow.hpp21
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/cache.h49
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/column.h29
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/command.h79
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/config.h65
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/dat.h100
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/db.h68
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/dump.h34
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/error.h29
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/expr.h123
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/file_reader.h37
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/geo.h36
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/groonga.h1700
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/hash.h104
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/id.h31
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/ii.h69
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/nfkc.h31
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/normalizer.h53
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/obj.h81
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/operator.h49
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/output.h124
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/pat.h102
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/plugin.h217
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/portability.h201
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/request_canceler.h37
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/request_timer.h53
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/scorer.h93
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/table.h246
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/thread.h39
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/time.h61
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/token.h135
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/token_filter.h67
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/tokenizer.h260
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/type.h40
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/util.h44
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/window_function.h73
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/windows.h31
-rw-r--r--storage/mroonga/vendor/groonga/include/groonga/windows_event_logger.h30
-rw-r--r--storage/mroonga/vendor/groonga/lib/CMakeLists.txt190
-rw-r--r--storage/mroonga/vendor/groonga/lib/Makefile.am99
-rw-r--r--storage/mroonga/vendor/groonga/lib/alloc.c961
-rw-r--r--storage/mroonga/vendor/groonga/lib/arrow.cpp849
-rw-r--r--storage/mroonga/vendor/groonga/lib/c_sources.am112
-rw-r--r--storage/mroonga/vendor/groonga/lib/cache.c1036
-rw-r--r--storage/mroonga/vendor/groonga/lib/column.c49
-rw-r--r--storage/mroonga/vendor/groonga/lib/com.c1202
-rw-r--r--storage/mroonga/vendor/groonga/lib/command.c201
-rw-r--r--storage/mroonga/vendor/groonga/lib/config.c289
-rw-r--r--storage/mroonga/vendor/groonga/lib/cpp_sources.am3
-rw-r--r--storage/mroonga/vendor/groonga/lib/ctx.c1873
-rw-r--r--storage/mroonga/vendor/groonga/lib/ctx_impl_mrb.c324
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat.cpp1338
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/Makefile.am11
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/array.hpp98
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/base.hpp67
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/block.hpp94
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/check.hpp149
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/cursor-factory.cpp92
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/cursor-factory.hpp44
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/cursor.hpp46
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/dat.hpp248
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/entry.hpp59
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/file-impl.cpp279
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/file-impl.hpp73
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/file.cpp73
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/file.hpp60
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/header.hpp179
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/id-cursor.cpp184
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/id-cursor.hpp83
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/key-cursor.cpp349
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/key-cursor.hpp88
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/key.hpp110
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/node.hpp127
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.cpp206
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.hpp84
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.cpp175
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.hpp78
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/sources.am29
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/string.hpp173
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/trie.cpp1225
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/trie.hpp285
-rw-r--r--storage/mroonga/vendor/groonga/lib/dat/vector.hpp191
-rw-r--r--storage/mroonga/vendor/groonga/lib/db.c14052
-rw-r--r--storage/mroonga/vendor/groonga/lib/dump.c112
-rw-r--r--storage/mroonga/vendor/groonga/lib/error.c454
-rw-r--r--storage/mroonga/vendor/groonga/lib/expr.c9294
-rw-r--r--storage/mroonga/vendor/groonga/lib/expr_code.c55
-rw-r--r--storage/mroonga/vendor/groonga/lib/expr_executor.c945
-rw-r--r--storage/mroonga/vendor/groonga/lib/file_lock.c121
-rw-r--r--storage/mroonga/vendor/groonga/lib/file_reader.c109
-rw-r--r--storage/mroonga/vendor/groonga/lib/geo.c2789
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn.h759
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_alloc.h163
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_cache.h49
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_com.h250
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_config.h37
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ctx.h501
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ctx_impl.h237
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ctx_impl_mrb.h35
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_dat.h95
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_db.h493
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ecmascript.c2542
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ecmascript.h74
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ecmascript.lemon581
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_error.h34
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_expr.h86
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_expr_code.h33
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_expr_executor.h39
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_file_lock.h48
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_geo.h200
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_hash.h378
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ii.h192
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_index_column.h34
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_io.h487
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_load.h47
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_logger.h35
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_mrb.h42
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_msgpack.h46
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_nfkc.h39
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_normalizer.h42
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_obj.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_output.h127
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_pat.h129
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_plugin.h62
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_proc.h152
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_raw_string.h62
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_report.h47
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_request_canceler.h28
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_request_timer.h28
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_rset.h114
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_scanner.h40
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_scorer.h49
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_scorers.h31
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_snip.h125
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_store.h216
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_str.h116
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_string.h51
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_time.h40
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_token_cursor.h81
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_tokenizers.h38
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_ts.h48
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_util.h49
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_window_function.h40
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_window_functions.h26
-rw-r--r--storage/mroonga/vendor/groonga/lib/grn_windows.h33
-rw-r--r--storage/mroonga/vendor/groonga/lib/hash.c3720
-rw-r--r--storage/mroonga/vendor/groonga/lib/icudump.c298
-rw-r--r--storage/mroonga/vendor/groonga/lib/id.c36
-rw-r--r--storage/mroonga/vendor/groonga/lib/ii.c12815
-rw-r--r--storage/mroonga/vendor/groonga/lib/index_column.c195
-rw-r--r--storage/mroonga/vendor/groonga/lib/io.c2201
-rw-r--r--storage/mroonga/vendor/groonga/lib/load.c1230
-rw-r--r--storage/mroonga/vendor/groonga/lib/logger.c810
-rw-r--r--storage/mroonga/vendor/groonga/lib/metadata.rc.in28
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb.c220
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/Makefile.am21
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.c121
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.h33
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_array.c92
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_array.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.c373
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.h41
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.c130
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.h33
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_column.c173
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_column.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_command.c196
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_command.h34
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.c139
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.c41
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_config.c90
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_config.h31
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.c49
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.c350
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.h64
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.c838
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.h33
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_database.c206
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_database.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.c60
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_error.c202
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_error.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.c98
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.c1079
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.h43
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.c59
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.c117
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_id.c79
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_id.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.c199
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.c245
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.c170
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.c99
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_object.c346
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_object.h34
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.c96
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.c155
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.h34
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_options.c39
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_options.h38
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.c59
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.c77
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.h31
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.c108
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.c76
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_record.c162
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_record.h31
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table.c493
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.c208
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.c60
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.c48
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.c254
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.h31
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.c42
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.h31
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.c159
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.c46
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_type.c60
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_type.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.c60
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_void.c59
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_void.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.c164
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.c253
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.h32
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/Makefile.am16
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/accessor.rb5
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/backtrace_entry.rb28
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/command.rb64
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/command_input.rb15
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/grndb.rb452
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line_parser.rb168
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/context.rb85
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/context/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/context/error_level.rb30
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/context/rc.rb205
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/context/sources.am3
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/database.rb65
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/error.rb16
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/eval_context.rb18
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression.rb68
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriter.rb22
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriters.rb41
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb54
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree.rb9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/accessor.rb14
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/binary_operation.rb67
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/constant.rb22
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/function_call.rb66
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/index_column.rb14
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/logical_operation.rb33
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/options.rb14
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/procedure.rb18
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/sources.am10
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/variable.rb18
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree_builder.rb111
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/fixed_size_column.rb5
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/id.rb12
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/index_column.rb39
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/index_cursor.rb18
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/index_info.rb10
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/post.rb28
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/pre.rb3
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/sources.am3
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/logger.rb34
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/level.rb40
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/object.rb18
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/operator.rb22
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/plugin_loader.rb14
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger.rb9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/flag.rb39
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/record.rb38
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/require.rb71
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info.rb38
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_builder.rb577
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data.rb324
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data_size_estimator.rb185
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_search_index.rb9
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/sources.am37
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/table.rb144
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/table_cursor.rb28
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/variable_size_column.rb5
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/scripts/writer.rb21
-rw-r--r--storage/mroonga/vendor/groonga/lib/mrb/sources.am93
-rw-r--r--storage/mroonga/vendor/groonga/lib/nfkc-custom-rules.txt1
-rw-r--r--storage/mroonga/vendor/groonga/lib/nfkc.c45
-rwxr-xr-xstorage/mroonga/vendor/groonga/lib/nfkc.rb897
-rw-r--r--storage/mroonga/vendor/groonga/lib/nfkc50.c77784
-rw-r--r--storage/mroonga/vendor/groonga/lib/normalizer.c1194
-rw-r--r--storage/mroonga/vendor/groonga/lib/obj.c689
-rw-r--r--storage/mroonga/vendor/groonga/lib/operator.c1362
-rw-r--r--storage/mroonga/vendor/groonga/lib/output.c2880
-rw-r--r--storage/mroonga/vendor/groonga/lib/pat.c3674
-rw-r--r--storage/mroonga/vendor/groonga/lib/plugin.c1396
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc.c4211
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/Makefile.am17
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_column.c1025
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_config.c139
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_dump.c1138
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_fuzzy_search.c467
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_highlight.c503
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_in_records.c519
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_lock.c172
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_object.c138
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_object_inspect.c614
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_object_list.c413
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_query.c118
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_query_log_flags.c220
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_schema.c1226
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_select.c3809
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_snippet.c319
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_table.c910
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/proc_tokenize.c433
-rw-r--r--storage/mroonga/vendor/groonga/lib/proc/sources.am18
-rw-r--r--storage/mroonga/vendor/groonga/lib/raw_string.c38
-rw-r--r--storage/mroonga/vendor/groonga/lib/report.c98
-rw-r--r--storage/mroonga/vendor/groonga/lib/request_canceler.c176
-rw-r--r--storage/mroonga/vendor/groonga/lib/request_timer.c88
-rw-r--r--storage/mroonga/vendor/groonga/lib/rset.c324
-rw-r--r--storage/mroonga/vendor/groonga/lib/scanner.c73
-rw-r--r--storage/mroonga/vendor/groonga/lib/scorer.c189
-rw-r--r--storage/mroonga/vendor/groonga/lib/scorers.c96
-rw-r--r--storage/mroonga/vendor/groonga/lib/snip.c841
-rw-r--r--storage/mroonga/vendor/groonga/lib/store.c2864
-rw-r--r--storage/mroonga/vendor/groonga/lib/str.c3276
-rw-r--r--storage/mroonga/vendor/groonga/lib/string.c416
-rw-r--r--storage/mroonga/vendor/groonga/lib/table.c122
-rw-r--r--storage/mroonga/vendor/groonga/lib/thread.c59
-rw-r--r--storage/mroonga/vendor/groonga/lib/time.c245
-rw-r--r--storage/mroonga/vendor/groonga/lib/token_cursor.c386
-rw-r--r--storage/mroonga/vendor/groonga/lib/token_filter.c59
-rw-r--r--storage/mroonga/vendor/groonga/lib/tokenizer.c377
-rw-r--r--storage/mroonga/vendor/groonga/lib/tokenizers.c893
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts.c906
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/Makefile.am20
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/sources.am25
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_buf.c244
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_buf.h111
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_cursor.c163
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_cursor.h59
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr.c219
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr.h87
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.c757
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.h128
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c5325
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.h128
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.c1329
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.h107
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_log.h46
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_op.c131
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_op.h87
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_plan.c21
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_plan.h87
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_sorter.c2174
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_sorter.h98
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_str.c191
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_str.h106
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_types.h168
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_util.c129
-rw-r--r--storage/mroonga/vendor/groonga/lib/ts/ts_util.h61
-rw-r--r--storage/mroonga/vendor/groonga/lib/type.c87
-rw-r--r--storage/mroonga/vendor/groonga/lib/util.c1643
-rw-r--r--storage/mroonga/vendor/groonga/lib/window_function.c464
-rw-r--r--storage/mroonga/vendor/groonga/lib/window_functions.c405
-rw-r--r--storage/mroonga/vendor/groonga/lib/windows.c104
-rw-r--r--storage/mroonga/vendor/groonga/lib/windows_event_logger.c203
-rw-r--r--storage/mroonga/vendor/groonga/nginx_version1
-rw-r--r--storage/mroonga/vendor/groonga/plugins/CMakeLists.txt30
-rw-r--r--storage/mroonga/vendor/groonga/plugins/Makefile.am19
-rw-r--r--storage/mroonga/vendor/groonga/plugins/expression_rewriters/CMakeLists.txt26
-rw-r--r--storage/mroonga/vendor/groonga/plugins/expression_rewriters/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/plugins/expression_rewriters/optimizer.rb147
-rw-r--r--storage/mroonga/vendor/groonga/plugins/expression_rewriters/sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/CMakeLists.txt141
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/Makefile.am33
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/index_column.c266
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/index_column_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/math.c142
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/math_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/number.c187
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/number_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/string.c299
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/string_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/time.c376
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/time_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/vector.c401
-rw-r--r--storage/mroonga/vendor/groonga/plugins/functions/vector_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/query_expanders/CMakeLists.txt38
-rw-r--r--storage/mroonga/vendor/groonga/plugins/query_expanders/Makefile.am20
-rw-r--r--storage/mroonga/vendor/groonga/plugins/query_expanders/tsv.c314
-rw-r--r--storage/mroonga/vendor/groonga/plugins/query_expanders/tsv_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/ruby/CMakeLists.txt24
-rw-r--r--storage/mroonga/vendor/groonga/plugins/ruby/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/plugins/ruby/eval.rb36
-rw-r--r--storage/mroonga/vendor/groonga/plugins/ruby/sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/ruby_scripts.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding.rb11
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/CMakeLists.txt24
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/Makefile.am9
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_count.rb169
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_enumerator.rb317
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_parameters.rb44
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_range_filter.rb642
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_select.rb975
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_shard_list.rb28
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/logical_table_remove.rb345
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/parameters.rb10
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/range_expression_builder.rb88
-rw-r--r--storage/mroonga/vendor/groonga/plugins/sharding/sources.am10
-rw-r--r--storage/mroonga/vendor/groonga/plugins/suggest/CMakeLists.txt36
-rw-r--r--storage/mroonga/vendor/groonga/plugins/suggest/Makefile.am24
-rw-r--r--storage/mroonga/vendor/groonga/plugins/suggest/sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/suggest/suggest.c1035
-rw-r--r--storage/mroonga/vendor/groonga/plugins/token_filters/CMakeLists.txt63
-rw-r--r--storage/mroonga/vendor/groonga/plugins/token_filters/Makefile.am28
-rw-r--r--storage/mroonga/vendor/groonga/plugins/token_filters/stem.c279
-rw-r--r--storage/mroonga/vendor/groonga/plugins/token_filters/stem_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/token_filters/stop_word.c159
-rw-r--r--storage/mroonga/vendor/groonga/plugins/token_filters/stop_word_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/tokenizers/CMakeLists.txt76
-rw-r--r--storage/mroonga/vendor/groonga/plugins/tokenizers/Makefile.am33
-rw-r--r--storage/mroonga/vendor/groonga/plugins/tokenizers/kytea.cpp358
-rw-r--r--storage/mroonga/vendor/groonga/plugins/tokenizers/kytea_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/plugins/tokenizers/mecab.c660
-rw-r--r--storage/mroonga/vendor/groonga/plugins/tokenizers/mecab_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/.gitignore2
-rw-r--r--storage/mroonga/vendor/groonga/src/CMakeLists.txt62
-rw-r--r--storage/mroonga/vendor/groonga/src/Makefile.am67
-rw-r--r--storage/mroonga/vendor/groonga/src/grndb.c197
-rw-r--r--storage/mroonga/vendor/groonga/src/grndb_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/grnslap.c375
-rw-r--r--storage/mroonga/vendor/groonga/src/grnslap_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/groonga.c3763
-rw-r--r--storage/mroonga/vendor/groonga/src/groonga_benchmark.c3176
-rw-r--r--storage/mroonga/vendor/groonga/src/groonga_benchmark_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/groonga_mruby.c86
-rw-r--r--storage/mroonga/vendor/groonga/src/groonga_mruby_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/groonga_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/httpd/Makefile.am32
-rw-r--r--storage/mroonga/vendor/groonga/src/httpd/nginx-module/config56
-rw-r--r--storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c1678
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/CMakeLists.txt87
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/Makefile.am74
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/create_dataset_sources.am2
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_create_dataset.c223
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_ddl.txt62
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_httpd.c860
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_learner.c843
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/httpd_sources.am3
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/learner_sources.am3
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/util.c215
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/util.h40
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/util_sources.am3
-rw-r--r--storage/mroonga/vendor/groonga/src/suggest/zmq_compatible.h33
-rw-r--r--storage/mroonga/vendor/groonga/tools/Makefile.am7
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/check-small-index-limit.rb123
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/groonga-benchmark-indexing.rb129
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/groonga-memory-leak-checker.rb93
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/groonga-memory-usage-analyzer.rb127
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/groonga-object-list-checker.rb104
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/groonga-suggest-httpd-client.rb181
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/install/install-for-debian-jessie.sh17
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/prepare-sphinx-html.rb183
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/travis-before-script.sh53
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/travis-install.sh38
-rwxr-xr-xstorage/mroonga/vendor/groonga/tools/travis-script.sh75
-rw-r--r--storage/mroonga/vendor/groonga/vendor/CMakeLists.txt20
-rw-r--r--storage/mroonga/vendor/groonga/vendor/Makefile.am29
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/download_lz4.rb54
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/download_mecab.rb59
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/download_message_pack.rb54
-rw-r--r--storage/mroonga/vendor/groonga/vendor/lz4/CMakeLists.txt98
-rw-r--r--storage/mroonga/vendor/groonga/vendor/lz4/Makefile.am2
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mecab/CMakeLists.txt219
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mecab/Makefile.am4
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mecab/config.h.cmake1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mecab/mecabrc.cmake3
-rw-r--r--storage/mroonga/vendor/groonga/vendor/message_pack/CMakeLists.txt53
-rw-r--r--storage/mroonga/vendor/groonga/vendor/message_pack/Makefile.am2
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mruby/CMakeLists.txt101
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mruby/Makefile.am79
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mruby/build_config.rb54
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mruby/built_sources.am14
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/mruby/mruby_build.rb65
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mruby/sources.am57
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/mruby/update.rb88
-rw-r--r--storage/mroonga/vendor/groonga/vendor/mruby/version1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/onigmo/CMakeLists.txt147
-rw-r--r--storage/mroonga/vendor/groonga/vendor/onigmo/Makefile.am32
-rw-r--r--storage/mroonga/vendor/groonga/vendor/onigmo/config.h.cmake1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/CMakeLists.txt28
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/CMakeLists.txt81
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/Makefile.am84
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/README.md211
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/autogen.sh20
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/Makefile.am18
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/Makefile.am18
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/ReadFileList.cmake27
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/configure.ac223
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/data/travis/setup.sh34
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/Makefile.am18
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/Makefile.am20
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/lgpl-2.0.txt481
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/news.md41
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/gpg_uid1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/groonga-normalizer-mysql.pc.in5
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/CMakeLists.txt43
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/Makefile.am90
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql.c778
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_general_ci_table.h565
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_sources.am7
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h5028
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_table.h5028
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h1685
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_table.h1685
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/Makefile.am6
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Makefile.am67
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Vagrantfile26
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/build-deb.sh57
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/env.sh.in8
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-packages.sh42
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-repository.sh46
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/update-repository.sh130
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/changelog71
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/compat1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/control31
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/copyright85
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/groonga-normalizer-mysql.install1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/patches/series0
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/rules17
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/source/format1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/watch2
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/Makefile.am1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/Makefile.am1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/groonga-normalizer-mysql.spec.in92
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/Makefile.am2
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/groonga-normalizer-mysql.spec.in91
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/source/Makefile.am25
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/ubuntu/Makefile.am28
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Makefile.am72
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Vagrantfile38
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/build-rpm.sh67
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/env.sh.in11
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/sign-rpm.sh37
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/update-repository.sh33
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/required_groonga_version1
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_uca.rb50
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_utf8.rb50
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_uca_table.rb304
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_utf8_table.rb146
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/parser.rb183
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/before_script.sh23
-rwxr-xr-xstorage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/install.sh27
-rw-r--r--storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/version_full1
-rwxr-xr-xstorage/mroonga/vendor/groonga/version-gen.sh35
-rw-r--r--storage/mroonga/version_full1
-rw-r--r--storage/mroonga/version_in_hex1
-rw-r--r--storage/mroonga/version_major1
-rw-r--r--storage/mroonga/version_micro1
-rw-r--r--storage/mroonga/version_minor1
2365 files changed, 391256 insertions, 0 deletions
diff --git a/storage/mroonga/AUTHORS b/storage/mroonga/AUTHORS
new file mode 100644
index 00000000..c29bd9cc
--- /dev/null
+++ b/storage/mroonga/AUTHORS
@@ -0,0 +1,7 @@
+Active developers:
+* Kentoku SHIBA
+* Kouhei Sutou
+
+Inactive developers:
+* Tetsuro IKEDA: The original author: Active
+* Yoshinori Matsunobu: The original author of information schema
diff --git a/storage/mroonga/CMakeLists.txt b/storage/mroonga/CMakeLists.txt
new file mode 100644
index 00000000..c048b214
--- /dev/null
+++ b/storage/mroonga/CMakeLists.txt
@@ -0,0 +1,452 @@
+# -*- indent-tabs-mode: nil -*-
+#
+# Copyright(C) 2012-2015 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-1335 USA
+
+cmake_minimum_required(VERSION 2.8.12)
+project(mroonga)
+
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(MRN_BUNDLED FALSE)
+else()
+ set(MRN_BUNDLED TRUE)
+endif()
+
+include(TestBigEndian)
+test_big_endian(BIG_ENDIAN)
+if(BIG_ENDIAN)
+ set(MRN_BIG_ENDIAN_NOT_SUPPORTED_MESSAGE
+ "Mroonga doesn't support on big-endian")
+ if(MRN_BUNDLED)
+ message(STATUS ${MRN_BIG_ENDIAN_NOT_SUPPORTED_MESSAGE})
+ return()
+ else()
+ message(FATAL_ERROR ${MRN_BIG_ENDIAN_NOT_SUPPORTED_MESSAGE})
+ endif()
+endif()
+
+if(MSVC)
+ if(MSVC_VERSION LESS 1800)
+ set(MRN_OLD_MSVC_MESSAGE "Mroonga supports only MSVC 2013 or later")
+ if(MRN_BUNDLED)
+ message(STATUS ${MRN_OLD_MSVC_MESSAGE})
+ return()
+ else()
+ message(FATAL_ERROR ${MRN_OLD_MSVC_MESSAGE})
+ endif()
+ endif()
+endif()
+
+if(MRN_BUNDLED)
+ if(WITHOUT_MROONGA OR
+ WITHOUT_MROONGA_STORAGE_ENGINE OR
+ "${PLUGIN_MROONGA}" STREQUAL "NO")
+ return()
+ endif()
+endif()
+
+set(MRN_BUNDLED_GROONGA_RELATIVE_DIR "vendor/groonga")
+set(MRN_BUNDLED_GROONGA_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/${MRN_BUNDLED_GROONGA_RELATIVE_DIR}")
+if(EXISTS "${MRN_BUNDLED_GROONGA_DIR}")
+ set(MRN_GROONGA_BUNDLED TRUE)
+ if(MSVC)
+ # Bundled Mroonga does not support MSVC yet
+ return()
+ endif()
+else()
+ set(MRN_GROONGA_BUNDLED FALSE)
+endif()
+
+set(MRN_PLUGIN_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
+
+if(MRN_BUNDLED)
+ set(MRN_SOURCE_DIR ${CMAKE_SOURCE_DIR}/storage/mroonga)
+else()
+ set(MRN_SOURCE_DIR ${CMAKE_SOURCE_DIR})
+endif()
+
+file(READ ${MRN_SOURCE_DIR}/version_full MRN_VERSION)
+file(READ ${MRN_SOURCE_DIR}/version_major MRN_VERSION_MAJOR)
+file(READ ${MRN_SOURCE_DIR}/version_minor MRN_VERSION_MINOR)
+file(READ ${MRN_SOURCE_DIR}/version_micro MRN_VERSION_MICRO)
+file(READ ${MRN_SOURCE_DIR}/version_in_hex MRN_VERSION_IN_HEX)
+file(READ ${MRN_SOURCE_DIR}/plugin_version MRN_PLUGIN_VERSION)
+
+if(MRN_GROONGA_BUNDLED)
+ option(MRN_GROONGA_EMBED
+ "Embed libgroonga"
+ ON)
+ if(MRN_GROONGA_EMBED)
+ set(GRN_EMBED ON)
+ endif()
+
+ set(MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR
+ "${MRN_BUNDLED_GROONGA_DIR}/vendor/plugins/groonga-normalizer-mysql")
+ option(MRN_GROONGA_NORMALIZER_MYSQL_EMBED
+ "Embed groonga-normalizer-mysql Groonga plugin"
+ ON)
+ if(EXISTS ${MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR})
+ set(GROONGA_NORMALIZER_MYSQL_FOUND ON)
+ else()
+ set(GROONGA_NORMALIZER_MYSQL_FOUND OFF)
+ set(MRN_GROONGA_NORMALIZER_MYSQL_EMBED OFF)
+ endif()
+ if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
+ set(GROONGA_NORMALIZER_MYSQL_EMBED ON)
+ endif()
+
+ file(READ "${MRN_BUNDLED_GROONGA_DIR}/bundled_lz4_version"
+ MRN_BUNDLED_LZ4_VERSION)
+ string(STRIP
+ "${MRN_BUNDLED_LZ4_VERSION}"
+ MRN_BUNDLED_LZ4_VERSION)
+ set(MRN_BUNDLED_LZ4_DIR
+ "${MRN_BUNDLED_GROONGA_DIR}/vendor/lz4-${MRN_BUNDLED_LZ4_VERSION}")
+ if(EXISTS ${MRN_BUNDLED_LZ4_DIR})
+ set(GRN_WITH_BUNDLED_LZ4 ON)
+ set(GRN_WITH_LZ4 "yes")
+ else()
+ set(GRN_WITH_LZ4 "no")
+ endif()
+
+ add_subdirectory("${MRN_BUNDLED_GROONGA_RELATIVE_DIR}")
+else()
+ set(MRN_GROONGA_EMBED OFF)
+
+ file(READ ${MRN_SOURCE_DIR}/required_groonga_version REQUIRED_GROONGA_VERSION)
+ string(STRIP "${REQUIRED_GROONGA_VERSION}" REQUIRED_GROONGA_VERSION)
+
+ file(READ
+ ${MRN_SOURCE_DIR}/required_groonga_normalizer_mysql_version
+ REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION)
+ string(STRIP
+ "${REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION}"
+ REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION)
+endif()
+
+set(MRN_PACKAGE_STRING "${PROJECT_NAME} ${MRN_VERSION}")
+
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(${MRN_SOURCE_DIR}/build/cmake_modules/ReadFileList.cmake)
+
+set(MRN_C_COMPILE_FLAGS "")
+set(MRN_CXX_COMPILE_FLAGS "")
+
+if(MRN_BUNDLED)
+ set(MRN_RELATIVE_DIR_PREFIX "${MRN_SOURCE_DIR}/")
+else()
+ set(MRN_RELATIVE_DIR_PREFIX "")
+endif()
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/sources.am MRN_SOURCES)
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/lib/libmrn_no_mysql_sources.am
+ LIBMRN_NO_MYSQL_SOURCES)
+string(REGEX REPLACE "([^;]+)" "${MRN_RELATIVE_DIR_PREFIX}lib/\\1"
+ LIBMRN_NO_MYSQL_SOURCES "${LIBMRN_NO_MYSQL_SOURCES}")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/lib/libmrn_need_mysql_sources.am
+ LIBMRN_NEED_MYSQL_SOURCES)
+string(REGEX REPLACE "([^;]+)" "${MRN_RELATIVE_DIR_PREFIX}lib/\\1"
+ LIBMRN_NEED_MYSQL_SOURCES "${LIBMRN_NEED_MYSQL_SOURCES}")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/udf/sources.am MRN_UDF_SOURCES)
+string(REGEX REPLACE "([^;]+)" "${MRN_RELATIVE_DIR_PREFIX}udf/\\1"
+ MRN_UDF_SOURCES "${MRN_UDF_SOURCES}")
+
+if(MRN_BUNDLED)
+ set(MYSQL_SOURCE_DIR ${CMAKE_SOURCE_DIR})
+ set(MYSQL_BUILD_DIR ${MYSQL_SOURCE_DIR})
+ set(MYSQL_CONFIG ${CMAKE_SOURCE_DIR}/scripts/mysql_config)
+else()
+ set(MYSQL_SOURCE_DIR "/PATH/TO/MYSQL/SOURCE/DIRECTORY/"
+ CACHE PATH "MySQL source directory")
+ if(NOT EXISTS ${MYSQL_SOURCE_DIR})
+ message(FATAL_ERROR
+ "MySQL source directory (MYSQL_SOURCE_DIR) doesn't exist: <${MYSQL_SOURCE_DIR}>")
+ endif()
+ set(MYSQL_BUILD_DIR ${MYSQL_SOURCE_DIR} CACHE PATH "MySQL build directory")
+ set(MYSQL_CONFIG "mysql_config" CACHE PATH "mysql-config command path")
+endif()
+find_path(MYSQL_CONFIG "${MYSQL_CONFIG}")
+
+if(EXISTS "${MYSQL_SOURCE_DIR}/storage/maria")
+ set(MYSQL_VARIANT "MariaDB")
+else()
+ set(MYSQL_VARIANT "MySQL")
+endif()
+
+set(MYSQL_REGEX_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/regex")
+
+if(EXISTS "${MYSQL_SOURCE_DIR}/extra/rapidjson")
+ set(MYSQL_RAPIDJSON_INCLUDE_DIR "${MYSQL_SOURCE_DIR}/extra/rapidjson/include")
+else()
+ set(MYSQL_RAPIDJSON_INCLUDE_DIR)
+endif()
+
+if(EXISTS "${MYSQL_SOURCE_DIR}/libbinlogevents")
+ set(MYSQL_LIBBINLOGEVENTS_EXPORT_DIR
+ "${MYSQL_SOURCE_DIR}/libbinlogevents/export")
+ set(MYSQL_LIBBINLOGEVENTS_INCLUDE_DIR
+ "${MYSQL_BUILD_DIR}/libbinlogevents/include"
+ "${MYSQL_SOURCE_DIR}/libbinlogevents/include")
+else()
+ set(MYSQL_LIBBINLOGEVENTS_EXPORT_DIR)
+ set(MYSQL_LIBBINLOGEVENTS_INCLUDE_DIR)
+endif()
+
+set(MYSQL_INCLUDE_DIRS
+ "${MYSQL_BUILD_DIR}/include"
+ "${MYSQL_SOURCE_DIR}/sql"
+ "${MYSQL_SOURCE_DIR}/include"
+ "${MYSQL_REGEX_INCLUDE_DIR}"
+ "${MYSQL_RAPIDJSON_INCLUDE_DIR}"
+ "${MYSQL_LIBBINLOGEVENTS_EXPORT_DIR}"
+ "${MYSQL_LIBBINLOGEVENTS_INCLUDE_DIR}")
+
+if(MRN_BUNDLED)
+ set(MYSQL_PLUGIN_DIR "${INSTALL_PLUGINDIR}")
+ set(MYSQL_SERVICES_LIB_DIR "${MYSQL_BUILD_DIR}/libservices")
+ set(MYSQL_CFLAGS "${CMAKE_C_FLAGS}")
+ set(MYSQL_VERSION "${MYSQL_BASE_VERSION}")
+else()
+ macro(SET_MYSQL_CONFIG_VALUE OPTION VARIABLE)
+ if(NOT ${VARIABLE})
+ execute_process(COMMAND "${MYSQL_CONFIG}" ${OPTION}
+ OUTPUT_VARIABLE MYSQL_CONFIG_OUTPUT)
+ string(STRIP ${MYSQL_CONFIG_OUTPUT} ${VARIABLE})
+ endif()
+ endmacro()
+
+ set_mysql_config_value("--plugindir" MYSQL_PLUGIN_DIR)
+ set_mysql_config_value("--variable=pkglibdir" MYSQL_PKG_LIB_DIR)
+ set(MYSQL_BUILD_LIBSERVICES_DIR "${MYSQL_BUILD_DIR}/libservices")
+ if(EXISTS "${MYSQL_BUILD_LIBSERVICES_DIR}/libmysqlservices.a")
+ set(MYSQL_SERVICES_LIB_DIR "${MYSQL_BUILD_LIBSERVICES_DIR}")
+ else()
+ set(MYSQL_SERVICES_LIB_DIR "${MYSQL_PKG_LIB_DIR}")
+ endif()
+ set_mysql_config_value("--cflags" MYSQL_CFLAGS)
+ set_mysql_config_value("--version" MYSQL_VERSION)
+endif()
+
+if(${MYSQL_VERSION} VERSION_LESS "5.5.0")
+ message(FATAL_ERROR
+ "Mroonga doesn't support MySQL < 5.5.0: <${MYSQL_VERSION}>")
+ return()
+endif()
+
+if(${MYSQL_VERSION} VERSION_GREATER "10.0.0" AND
+ ${MYSQL_VERSION} VERSION_LESS "10.0.9")
+ message(FATAL_ERROR
+ "Mroonga doesn't support MariaDB 10.0.0-10.0.8: <${MYSQL_VERSION}>")
+ return()
+endif()
+
+if(MRN_GROONGA_BUNDLED)
+ set(GROONGA_INCLUDE_DIRS "${MRN_BUNDLED_GROONGA_DIR}/include")
+ set(GROONGA_LIBRARY_DIRS "${MRN_BUNDLED_GROONGA_DIR}/lib")
+ set(GROONGA_LIBRARIES "libgroonga")
+
+ set(MRN_LIBRARY_DIRS ${GROONGA_LIBRARY_DIRS})
+ set(MRN_LIBRARIES ${GROONGA_LIBRARIES})
+ if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
+ set(MRN_LIBRARY_DIRS
+ ${MRN_LIBRARY_DIRS}
+ "${MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR}/normalizers")
+ set(MRN_LIBRARIES ${MRN_LIBRARIES} mysql_normalizer)
+ endif()
+else()
+ include(FindPkgConfig)
+ pkg_check_modules(GROONGA REQUIRED "groonga >= ${REQUIRED_GROONGA_VERSION}")
+ pkg_check_modules(GROONGA_NORMALIZER_MYSQL
+ "groonga-normalizer-mysql >= ${REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION}")
+ set(MRN_LIBRARY_DIRS
+ ${MRN_LIBRARY_DIRS}
+ ${GROONGA_LIBRARY_DIRS})
+ set(MRN_LIBRARIES ${GROONGA_LIBRARIES})
+endif()
+
+include_directories(
+ "${PROJECT_BINARY_DIR}"
+ "${PROJECT_SOURCE_DIR}"
+ "${PROJECT_SOURCE_DIR}/lib"
+ ${MYSQL_INCLUDE_DIRS}
+ ${GROONGA_INCLUDE_DIRS})
+
+if(WIN32)
+ set(MYSQL_LIBRARY_DIRS
+ "${MYSQL_BUILD_DIR}/lib"
+ "${MYSQL_BUILD_DIR}/libmysqld")
+else()
+ set(MYSQL_LIBRARY_DIRS
+ "${MYSQL_SERVICES_LIB_DIR}")
+endif()
+link_directories(
+ ${MRN_LIBRARY_DIRS}
+ ${MYSQL_LIBRARY_DIRS})
+
+set(MRN_ALL_SOURCES
+ ${MRN_SOURCES}
+ ${MRN_UDF_SOURCES}
+ ${LIBMRN_NO_MYSQL_SOURCES}
+ ${LIBMRN_NEED_MYSQL_SOURCES})
+
+if(MRN_BUNDLED)
+ mysql_add_plugin(mroonga
+ ${MRN_ALL_SOURCES}
+ STORAGE_ENGINE MODULE_ONLY
+ LINK_LIBRARIES ${MRN_LIBRARIES})
+ if(NOT TARGET mroonga)
+ return()
+ endif()
+else()
+ add_library(mroonga MODULE ${MRN_ALL_SOURCES})
+
+ set(MYSQL_LIBRARIES "mysqlservices")
+ target_link_libraries(mroonga ${GROONGA_LIBRARIES} ${MYSQL_LIBRARIES})
+
+ option(WITH_DEBUG "Enable debug options" OFF)
+ if(WITH_DEBUG)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "SAFE_MUTEX")
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set(MRN_C_COMPILE_FLAGS "${MRN_C_COMPILE_FLAGS} -g3 -O0")
+ set(MRN_CXX_COMPILE_FLAGS "${MRN_CXX_COMPILE_FLAGS} -g3 -O0")
+ endif()
+ else()
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "DBUG_OFF")
+ endif()
+
+ option(WITH_DEBUG_FULL "Enable full debug options" OFF)
+ if(WITH_DEBUG_FULL)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "SAFE_MUTEX" "SAFEMALLOC")
+ endif()
+
+ option(DISABLE_FAST_MUTEXES "Force disabling fast mutex" OFF)
+ if(DISABLE_FAST_MUTEXES)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "FORCE_FAST_MUTEX_DISABLED=1")
+ endif()
+
+ option(WITH_FAST_MUTEXES "Enable fast mutex" OFF)
+ if(WITH_FAST_MUTEXES)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "MY_PTHREAD_FASTMUTEX")
+ endif()
+
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wall")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wextra")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-unused-parameter")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-strict-aliasing")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-deprecated")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fno-exceptions")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-felide-constructors")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-implicit-fallthrough")
+ endif()
+ set_source_files_properties(${MRN_SOURCES} PROPERTIES
+ COMPILE_FLAGS "${MYSQL_CFLAGS} ${MRN_CXX_COMPILE_FLAGS}")
+ set_source_files_properties(${LIBMRN_NEED_MYSQL_SOURCES} PROPERTIES
+ COMPILE_FLAGS "${MYSQL_CFLAGS} ${MRN_CXX_COMPILE_FLAGS}")
+ set_source_files_properties(${MRN_UDF_SOURCES} PROPERTIES
+ COMPILE_FLAGS "${MRN_CXX_COMPILE_FLAGS}")
+ set_source_files_properties(${LIBMRN_NO_MYSQL_SOURCES} PROPERTIES
+ COMPILE_FLAGS "${MRN_CXX_COMPILE_FLAGS}")
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "MYSQL_DYNAMIC_PLUGIN")
+ set_target_properties(mroonga PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "ha_mroonga")
+
+ install(TARGETS mroonga DESTINATION "${MYSQL_PLUGIN_DIR}")
+endif()
+
+option(MRN_BUILD_FOR_EMBEDDED_SERVER
+ "Whether to build Mroonga for embedded server or not. You can't use Mroonga built for embedded server with non embedded server."
+ OFF)
+if(MRN_BUILD_FOR_EMBEDDED_SERVER)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "EMBEDDED_LIBRARY")
+endif()
+
+if(GROONGA_NORMALIZER_MYSQL_FOUND)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "WITH_GROONGA_NORMALIZER_MYSQL=1")
+ if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "MRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED")
+ else()
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME=\"normalizers/mysql\"")
+ endif()
+endif()
+
+if(MRN_GROONGA_EMBED)
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "MRN_GROONGA_EMBEDDED")
+endif()
+
+set(MRN_DEFAULT_PARSER "" CACHE STRING
+ "The default fulltext parser (Deprecated. Use MRN_DEFAULT_TOKENIZER instead.)")
+set(MRN_DEFAULT_TOKENIZER "" CACHE STRING
+ "The default tokenizer for fulltext index")
+if(NOT ${MRN_DEFAULT_TOKENIZER} STREQUAL "")
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "MRN_DEFAULT_TOKENIZER=\"${MRN_DEFAULT_TOKENIZER}\"")
+elseif(NOT ${MRN_DEFAULT_PARSER} STREQUAL "")
+ set_property(TARGET mroonga APPEND PROPERTY
+ COMPILE_DEFINITIONS "MRN_DEFAULT_TOKENIZER=\"${MRN_DEFAULT_PARSER}\"")
+endif()
+
+configure_file(
+ "${PROJECT_SOURCE_DIR}/mrn_version.h.in"
+ "${PROJECT_BINARY_DIR}/mrn_version.h")
+
+configure_file(
+ "${PROJECT_SOURCE_DIR}/config.sh.in"
+ "${PROJECT_BINARY_DIR}/config.sh")
+
+set(MRN_TEST_SUITE_DIR "${CMAKE_SOURCE_DIR}/mysql-test/suite/mroonga")
+if(NOT EXISTS "${MRN_TEST_SUITE_DIR}")
+ set(MRN_TEST_SUITE_DIR "${PROJECT_SOURCE_DIR}/mysql-test/mroonga")
+endif()
+configure_file(
+ "${MRN_TEST_SUITE_DIR}/storage/r/information_schema_plugins.result.in"
+ "${MRN_TEST_SUITE_DIR}/storage/r/information_schema_plugins.result"
+ NEWLINE_STYLE LF)
+configure_file(
+ "${MRN_TEST_SUITE_DIR}/storage/r/variable_version.result.in"
+ "${MRN_TEST_SUITE_DIR}/storage/r/variable_version.result"
+ NEWLINE_STYLE LF)
+
+configure_file(
+ "${PROJECT_SOURCE_DIR}/data/install.sql.in"
+ "${PROJECT_BINARY_DIR}/data/install.sql")
+
+if(MRN_BUNDLED)
+ set(MRN_DATA_DIR "${INSTALL_MYSQLSHAREDIR}/${PROJECT_NAME}")
+else()
+ set(MRN_DATA_DIR "share/${PROJECT_NAME}")
+endif()
+install(FILES
+ "${PROJECT_SOURCE_DIR}/AUTHORS"
+ "${PROJECT_SOURCE_DIR}/COPYING"
+ "${PROJECT_BINARY_DIR}/data/install.sql"
+ "${PROJECT_SOURCE_DIR}/data/uninstall.sql"
+ DESTINATION "${MRN_DATA_DIR}/")
diff --git a/storage/mroonga/COPYING b/storage/mroonga/COPYING
new file mode 100644
index 00000000..21d4c6d6
--- /dev/null
+++ b/storage/mroonga/COPYING
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 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-1335 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/storage/mroonga/ChangeLog b/storage/mroonga/ChangeLog
new file mode 100644
index 00000000..1a63e191
--- /dev/null
+++ b/storage/mroonga/ChangeLog
@@ -0,0 +1,3 @@
+2009-01-27 Tetsuro IKEDA <ikdttr at gmail.com>
+
+ * initial import for development
diff --git a/storage/mroonga/Makefile.am b/storage/mroonga/Makefile.am
new file mode 100644
index 00000000..69349ea6
--- /dev/null
+++ b/storage/mroonga/Makefile.am
@@ -0,0 +1,175 @@
+ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_ARGS}
+AUTOMAKE_OPTIONS = 1.9.7
+
+LOCALES = ja
+
+AM_CPPFLAGS = $(MYSQL_INCLUDES) $(GROONGA_CFLAGS) -I$(top_srcdir)/lib
+
+include sources.am
+
+libraries = \
+ $(top_builddir)/udf/libmrn_udf.la \
+ $(top_builddir)/lib/libmrn_no_mysql.la \
+ $(top_builddir)/lib/libmrn_need_mysql.la
+if WITH_LIBMYSQLSERVICES_COMPAT
+libraries += $(top_builddir)/lib/libmysqlservices.la
+endif
+
+dynamic_plugin_ldflags = -module $(GROONGA_LIBS) $(MYSQL_LIBS)
+dynamic_plugin_cxxflags = $(AM_CXXFLAGS) $(MYSQL_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
+dynamic_plugin_cflags = $(AM_CFLAGS) $(MYSQL_CFLAGS) -DMYSQL_DYNAMIC_PLUGIN
+
+plugin_LTLIBRARIES = ha_mroonga.la
+ha_mroonga_la_LDFLAGS = $(dynamic_plugin_ldflags)
+ha_mroonga_la_CXXFLAGS = $(dynamic_plugin_cxxflags)
+ha_mroonga_la_CFLAGS = $(dynamic_plugin_cflags)
+ha_mroonga_la_SOURCES = $(sources)
+ha_mroonga_la_LIBADD = $(libraries)
+
+SUBDIRS = \
+ build \
+ lib \
+ udf \
+ test \
+ mysql-test \
+ doc \
+ tools \
+ packages \
+ data
+
+EXTRA_DIST = \
+ AUTHORS \
+ gpg_uid \
+ CMakeLists.txt
+
+installcheck-local: install
+ test/run-sql-test.sh
+
+tag:
+ cd $(top_srcdir) && \
+ git tag v$(VERSION) -a -m 'Mroonga $(VERSION)!!!'
+
+ensure-cutter-source-path:
+ @if test -z "$(CUTTER_SOURCE_PATH)"; then \
+ echo "\$$(CUTTER_SOURCE_PATH) is missing"; \
+ exit 1; \
+ fi
+
+update-latest-release: ensure-cutter-source-path
+ @if test -z "$(OLD_RELEASE)"; then \
+ echo "\$$(OLD_RELEASE) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(OLD_RELEASE_DATE)"; then \
+ echo "\$$(OLD_RELEASE_DATE) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(NEW_RELEASE_DATE)"; then \
+ echo "\$$(NEW_RELEASE_DATE) is missing"; \
+ exit 1; \
+ fi
+ cd $(top_srcdir) && \
+ "$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
+ $(PACKAGE) $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/rpm/centos/mariadb-mroonga.spec.in \
+ packages/rpm/centos/mariadb-10.1-mroonga.spec.in \
+ packages/rpm/centos/mariadb-10.2-mroonga.spec.in \
+ packages/rpm/centos/mysql55-mroonga.spec.in \
+ packages/rpm/centos/mysql56-community-mroonga.spec.in \
+ packages/rpm/centos/mysql57-community-mroonga.spec.in \
+ packages/rpm/centos/percona-server-56-mroonga.spec.in \
+ packages/rpm/centos/percona-server-57-mroonga.spec.in \
+ doc/source/install/*.rst \
+ doc/locale/*/LC_MESSAGES/install.po \
+ $(MROONGA_GITHUB_COM_PATH)/_config.yml
+ cd $(top_srcdir) && \
+ "$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
+ $(PACKAGE)-5.5 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/debian-5.5/changelog
+ cd $(top_srcdir) && \
+ "$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
+ $(PACKAGE)-5.6 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/debian-5.6/changelog
+ cd $(top_srcdir) && \
+ "$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
+ $(PACKAGE)-5.7 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/debian-5.7/changelog
+ cd $(top_srcdir) && \
+ "$(CUTTER_SOURCE_PATH)/misc/update-latest-release.rb" \
+ $(PACKAGE)-mariadb-10.0 $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/debian-mariadb-10.0/changelog
+
+update-po:
+ @for lang in $(LOCALES); do \
+ (cd $(top_srcdir)/doc/locale/$$lang/LC_MESSAGES && make update) \
+ done
+
+update-document:
+ @if test -z "$(MROONGA_GITHUB_COM_PATH)"; then \
+ echo "\$$(MROONGA_GITHUB_COM_PATH) is missing"; \
+ echo "add --with-mroonga-github-com-path in configure"; \
+ exit 1; \
+ fi
+ rm -rf tmp-doc
+ mkdir tmp-doc
+ (cd doc && $(MAKE) clean-html)
+ (cd doc && $(MAKE) install docdir=$(abs_srcdir)/tmp-doc/install)
+ ruby $(srcdir)/tools/prepare-sphinx-html.rb tmp-doc/install tmp-doc/dist
+ rm -rf $(MROONGA_GITHUB_COM_PATH)/docs
+ mv tmp-doc/dist/en $(MROONGA_GITHUB_COM_PATH)/docs
+ for locale in `cd tmp-doc/dist; echo *`; do \
+ dest_base_dir=$(MROONGA_GITHUB_COM_PATH)/$${locale}; \
+ mkdir -p $${dest_base_dir}; \
+ dest_dir=$${dest_base_dir}/docs; \
+ rm -rf $${dest_dir}; \
+ mv tmp-doc/dist/$${locale} $${dest_dir}; \
+ done
+
+update-files:
+ cd $(srcdir)/doc && $(MAKE) update-files
+
+update-version:
+ @if test -z "$(NEW_VERSION_MAJOR)"; then \
+ echo "\$$(NEW_VERSION_MAJOR) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(NEW_VERSION_MINOR)"; then \
+ echo "\$$(NEW_VERSION_MINOR) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(NEW_VERSION_MICRO)"; then \
+ echo "\$$(NEW_VERSION_MICRO) is missing"; \
+ exit 1; \
+ fi
+ @echo -n $(NEW_VERSION_MAJOR) > $(srcdir)/version_major
+ @echo -n $(NEW_VERSION_MINOR) > $(srcdir)/version_minor
+ @echo -n $(NEW_VERSION_MICRO) > $(srcdir)/version_micro
+ @echo -n $(NEW_VERSION_MAJOR).$(NEW_VERSION_MINOR)$(NEW_VERSION_MICRO) \
+ > $(srcdir)/version
+ @if test $(NEW_VERSION_MINOR) -eq 0 ; then \
+ printf "0x%02x%02x" \
+ $(NEW_VERSION_MAJOR) $(NEW_VERSION_MICRO) \
+ > $(srcdir)/version_in_hex; \
+ printf "%d.%d" \
+ $(NEW_VERSION_MAJOR) $(NEW_VERSION_MICRO) \
+ > $(srcdir)/plugin_version; \
+ else \
+ printf "0x%02x%02x" \
+ $(NEW_VERSION_MAJOR) $(NEW_VERSION_MINOR)$(NEW_VERSION_MICRO) \
+ > $(srcdir)/version_in_hex; \
+ printf "%d.%d" \
+ $(NEW_VERSION_MAJOR) $(NEW_VERSION_MINOR)$(NEW_VERSION_MICRO) \
+ > $(srcdir)/plugin_version; \
+ fi
+
+upload-to-github:
+ ruby $(srcdir)/tools/upload-to-github.rb \
+ $$USER $(PACKAGE)-$(VERSION).tar.gz
+
+echo-cutter:
+ echo $(CUTTER)
diff --git a/storage/mroonga/NEWS b/storage/mroonga/NEWS
new file mode 100644
index 00000000..9dfa8b8d
--- /dev/null
+++ b/storage/mroonga/NEWS
@@ -0,0 +1 @@
+See doc/source/news.txt or http://mroonga.github.com/docs/news.html.
diff --git a/storage/mroonga/README b/storage/mroonga/README
new file mode 100644
index 00000000..7c431018
--- /dev/null
+++ b/storage/mroonga/README
@@ -0,0 +1 @@
+See doc/locale/en/html/index.html or doc/locale/ja/html/index.html
diff --git a/storage/mroonga/appveyor.yml b/storage/mroonga/appveyor.yml
new file mode 100644
index 00000000..9aad756b
--- /dev/null
+++ b/storage/mroonga/appveyor.yml
@@ -0,0 +1,61 @@
+version: "{build}"
+clone_depth: 10
+environment:
+ global:
+ MARIADB_VERSION: 10.1.26
+ matrix:
+ - CMAKE_GENERATOR_NAME: "Visual Studio 14 2015"
+ - CMAKE_GENERATOR_NAME: "Visual Studio 14 2015 Win64"
+
+install:
+ - cd ..
+ - choco install -y curl 7zip.commandline
+ - curl -O http://mirror.jmu.edu/pub/mariadb/mariadb-%MARIADB_VERSION%/source/mariadb-%MARIADB_VERSION%.tar.gz
+ - 7z x mariadb-%MARIADB_VERSION%.tar.gz
+ - 7z x mariadb-%MARIADB_VERSION%.tar > nul
+ - cd mariadb-%MARIADB_VERSION%
+ - rmdir /S /Q storage\mroonga\
+ - move ..\mroonga storage\mroonga
+ - git clone --quiet --depth 1 --recursive https://github.com/groonga/groonga.git ..\groonga
+ - rmdir /S /Q ..\groonga\test\
+ - cd ..\groonga\vendor
+ - c:\Ruby22-x64\bin\ruby -v download_lz4.rb
+ - c:\Ruby22-x64\bin\ruby -v download_mecab.rb
+ - cd ..\..\mariadb-%MARIADB_VERSION%
+ - mkdir storage\mroonga\vendor
+ - move ..\groonga storage\mroonga\vendor\groonga
+ - git clone --quiet --depth 1 https://github.com/groonga/groonga-normalizer-mysql.git storage\mroonga\vendor\groonga\vendor\plugins\groonga-normalizer-mysql
+build_script:
+ - "echo # > win\\packaging\\CMakeLists.txt"
+ - cmake . -G "%CMAKE_GENERATOR_NAME%"
+ -DCMAKE_BUILD_TYPE=Debug
+ -DPLUGIN_ARCHIVE=NO
+ -DPLUGIN_BLACKHOLE=NO
+ -DPLUGIN_CONNECT=NO
+ -DPLUGIN_CSV=NO
+ -DPLUGIN_EXAMPLE=NO
+ -DPLUGIN_FEDERATED=NO
+ -DPLUGIN_FEDERATEDX=NO
+ -DPLUGIN_HEAP=NO
+ -DPLUGIN_INNOBASE=NO
+ -DPLUGIN_MYISAM=NO
+ -DPLUGIN_MYISAMMRG=NO
+ -DPLUGIN_OQGRAPH=NO
+ -DPLUGIN_PERFSCHEMA=NO
+ -DPLUGIN_SEQUENCE=NO
+ -DPLUGIN_SPHINX=NO
+ -DPLUGIN_SPIDER=NO
+ -DPLUGIN_TEST_SQL_DISCOVERY=NO
+ -DPLUGIN_XTRADB=NO
+ -DWITH_UNIT_TESTS=OFF
+ -DWITH_MARIABACKUP=OFF
+ -DGRN_WITH_BUNDLED_MECAB=ON
+ - cmake --build . --config Debug
+
+notifications:
+ - provider: Email
+ to:
+ - groonga-mysql-commit@lists.sourceforge.jp
+ on_build_status_changed: true
+
+test: off
diff --git a/storage/mroonga/autogen.sh b/storage/mroonga/autogen.sh
new file mode 100755
index 00000000..f795ad00
--- /dev/null
+++ b/storage/mroonga/autogen.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+case $(uname -s) in
+FreeBSD)
+ ACLOCAL_ARGS="$ACLOCAL_ARGS -I /usr/local/share/aclocal/"
+ ;;
+esac
+
+mkdir -p m4
+
+${AUTORECONF:-autoreconf} --force --install "$@"
diff --git a/storage/mroonga/build/Makefile.am b/storage/mroonga/build/Makefile.am
new file mode 100644
index 00000000..506a11dc
--- /dev/null
+++ b/storage/mroonga/build/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = \
+ cmake_modules
diff --git a/storage/mroonga/build/cmake_modules/Makefile.am b/storage/mroonga/build/cmake_modules/Makefile.am
new file mode 100644
index 00000000..83fb0f0c
--- /dev/null
+++ b/storage/mroonga/build/cmake_modules/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+ ReadFileList.cmake
diff --git a/storage/mroonga/build/cmake_modules/ReadFileList.cmake b/storage/mroonga/build/cmake_modules/ReadFileList.cmake
new file mode 100644
index 00000000..204f59f6
--- /dev/null
+++ b/storage/mroonga/build/cmake_modules/ReadFileList.cmake
@@ -0,0 +1,27 @@
+# Copyright(C) 2012 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+macro(read_file_list file_name output_variable)
+ file(READ ${file_name} ${output_variable})
+ # Remove variable declaration at the first line:
+ # "libgroonga_la_SOURCES = \" -> ""
+ string(REGEX REPLACE "^.*=[ \t]*\\\\" ""
+ ${output_variable} "${${output_variable}}")
+ # Remove white spaces: " com.c \\\n com.h \\\n" -> "com.c\\com.h"
+ string(REGEX REPLACE "[ \t\n]" "" ${output_variable} "${${output_variable}}")
+ # Convert string to list: "com.c\\com.h" -> "com.c;com.h"
+ # NOTE: List in CMake is ";" separated string.
+ string(REGEX REPLACE "\\\\" ";" ${output_variable} "${${output_variable}}")
+endmacro()
diff --git a/storage/mroonga/build/makefiles/LC_MESSAGES.am b/storage/mroonga/build/makefiles/LC_MESSAGES.am
new file mode 100644
index 00000000..acfc3da2
--- /dev/null
+++ b/storage/mroonga/build/makefiles/LC_MESSAGES.am
@@ -0,0 +1,5 @@
+BUILT_SOURCES =
+EXTRA_DIST =
+SUFFIXES =
+
+include $(top_srcdir)/build/makefiles/gettext.am
diff --git a/storage/mroonga/build/makefiles/gettext.am b/storage/mroonga/build/makefiles/gettext.am
new file mode 100644
index 00000000..9cea8ce6
--- /dev/null
+++ b/storage/mroonga/build/makefiles/gettext.am
@@ -0,0 +1,86 @@
+include $(top_srcdir)/doc/files.am
+include $(top_srcdir)/build/makefiles/sphinx-build.am
+
+CLEANFILES =
+
+EXTRA_DIST += \
+ $(po_files)
+
+if DOCUMENT_AVAILABLE
+EXTRA_DIST += \
+ $(mo_files)
+endif
+
+if DOCUMENT_BUILDABLE
+BUILT_SOURCES += \
+ mo-build-stamp
+CLEANFILES += \
+ pot-build-stamp \
+ edit-po-build-stamp \
+ mo-build-stamp
+endif
+
+SUFFIXES += .pot .po .mo .edit
+
+.PHONY: gettext update build
+
+.pot.edit:
+ if test -f $*.po; then \
+ msgmerge \
+ --quiet \
+ --sort-by-file \
+ --output-file=$@.tmp \
+ $*.po \
+ $<; \
+ else \
+ msginit \
+ --input=$< \
+ --output-file=$@.tmp \
+ --locale=$(LOCALE) \
+ --no-translator; \
+ fi
+ (echo "# -*- po -*-"; \
+ GREP_OPTIONS= grep -v '^# -\*- po -\*-' $@.tmp | \
+ GREP_OPTIONS= grep -v '^"POT-Creation-Date:') > $@
+ rm $@.tmp
+
+.edit.po:
+ msgcat --no-location --output $@ $<
+
+.po.mo:
+ msgfmt -o $@ $<
+
+if DOCUMENT_BUILDABLE
+update: edit-po-build-stamp
+build: mo-build-stamp
+else
+update:
+build:
+endif
+
+html: build
+man: build
+pdf: build
+
+gettext:
+ rm *.pot || true
+ $(SPHINX_BUILD_COMMAND) -d doctrees -b gettext $(ALLSPHINXOPTS) .
+ xgettext --language Python --output conf.pot \
+ $(top_srcdir)/doc/source/conf.py
+
+pot-build-stamp: $(absolute_source_files)
+ $(MAKE) gettext
+ @touch $@
+
+edit-po-build-stamp: pot-build-stamp
+ $(MAKE) $(edit_po_files)
+ @touch $@
+
+mo_build_stamp_dependencies = edit-po-build-stamp
+if DOCUMENT_BUILDABLE
+mo_build_stamp_dependencies += $(edit_po_files)
+endif
+
+mo-build-stamp: $(mo_build_stamp_dependencies)
+ $(MAKE) $(mo_files)
+ @touch $@
diff --git a/storage/mroonga/build/makefiles/locale.am b/storage/mroonga/build/makefiles/locale.am
new file mode 100644
index 00000000..414c19a7
--- /dev/null
+++ b/storage/mroonga/build/makefiles/locale.am
@@ -0,0 +1,12 @@
+SUBDIRS = LC_MESSAGES
+
+BUILT_SOURCES =
+EXTRA_DIST =
+
+include $(top_srcdir)/build/makefiles/sphinx.am
+
+init:
+ cd LC_MESSAGES && $(MAKE) $@
+
+update-po:
+ cd LC_MESSAGES && $(MAKE) update
diff --git a/storage/mroonga/build/makefiles/sphinx-build.am b/storage/mroonga/build/makefiles/sphinx-build.am
new file mode 100644
index 00000000..57bbcd61
--- /dev/null
+++ b/storage/mroonga/build/makefiles/sphinx-build.am
@@ -0,0 +1,17 @@
+# You can set these variables from the command line.
+DOCTREES_BASE = doctrees
+
+SPHINXOPTS =
+PAPER =
+
+# Internal variables.
+SOURCE_DIR = $(abs_top_srcdir)/doc/source
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = $(PAPEROPT_$(PAPER)) -E $(SPHINXOPTS) $(SOURCE_DIR)
+
+SPHINX_BUILD_COMMAND = \
+ DOCUMENT_VERSION="$(DOCUMENT_VERSION)" \
+ DOCUMENT_VERSION_FULL="$(DOCUMENT_VERSION_FULL)" \
+ LOCALE="$(LOCALE)" \
+ $(SPHINX_BUILD)
diff --git a/storage/mroonga/build/makefiles/sphinx.am b/storage/mroonga/build/makefiles/sphinx.am
new file mode 100644
index 00000000..c68f62e2
--- /dev/null
+++ b/storage/mroonga/build/makefiles/sphinx.am
@@ -0,0 +1,179 @@
+include $(top_srcdir)/doc/files.am
+include $(top_srcdir)/build/makefiles/sphinx-build.am
+
+$(html_files): html-build-stamp
+$(html_files_relative_from_locale_dir): html-build-stamp
+$(man_files): man-build-stamp
+
+am__nobase_dist_doc_locale_DATA_DIST =
+if DOCUMENT_AVAILABLE
+doc_localedir = $(docdir)/$(LOCALE)
+nobase_dist_doc_locale_DATA = \
+ $(html_files_relative_from_locale_dir)
+am__nobase_dist_doc_locale_DATA_DIST += \
+ $(nobase_dist_doc_locale_DATA)
+endif
+
+document_source_files = \
+ $(absolute_source_files) \
+ $(absolute_theme_files) \
+ $(po_files_relative_from_locale_dir) \
+ $(mo_files_relative_from_locale_dir)
+
+required_build_stamps = \
+ html-build-stamp \
+ man-build-stamp \
+ mo-build-stamp
+
+if DOCUMENT_BUILDABLE
+EXTRA_DIST += $(required_build_stamps)
+endif
+
+man_files = \
+ man/$(PACKAGE_NAME).1
+
+generated_files = \
+ $(DOCTREES_BASE) \
+ man \
+ man-build-stamp \
+ html \
+ html-build-stamp \
+ pdf \
+ pdf-build-stamp \
+ dirhtml \
+ dirhtml-build-stamp \
+ pickle \
+ pikcle-build-stamp \
+ json \
+ json-build-stamp \
+ htmlhelp \
+ htmlhelp-build-stamp \
+ qthelp \
+ qthelp-build-stamp \
+ latex \
+ latex-build-stamp \
+ changes \
+ changes-build-stamp \
+ linkcheck \
+ linkcheck-build-stamp \
+ doctest
+
+$(mo_files_relative_from_locale_dir): mo-build-stamp
+
+mo-build-stamp: $(po_files_relative_from_locale_dir)
+ cd LC_MESSAGES && $(MAKE) build
+ @touch $@
+
+if DOCUMENT_BUILDABLE
+clean-local: $(clean_targets) clean-doctrees
+
+clean-doctrees:
+ rm -rf $(DOCTREES_BASE)
+
+maintainer-clean-local:
+ rm -rf -- $(generated_files)
+endif
+
+.PHONY: help
+.PHONY: man clean-man
+.PHONY: html clean-html
+.PHONY: pdf
+.PHONY: dirhtml
+.PHONY: pickle
+.PHONY: json
+.PHONY: htmlhelp
+.PHONY: qthelp
+.PHONY: latex
+.PHONY: changes
+.PHONY: linkcheck
+.PHONY: doctest
+
+if DOCUMENT_BUILDABLE
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " man to make man files"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " rdoc to make RDoc files"
+ @echo " textile to make Textile files"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+man: man-build-stamp
+html: html-recursive html-build-stamp
+dirhtml: dirhtml-build-stamp
+pickle: pickle-build-stamp
+json: json-build-stamp
+htmlhelp: htmlhelp-build-stamp
+qthelp: qthelp-build-stamp
+latex: latex-build-stamp
+rdoc: rdoc-build-stamp
+textile: textile-build-stamp
+changes: changes-build-stamp
+linkcheck: linkcheck-build-stamp
+doctest: doctest-build-stamp
+
+clean_targets = \
+ clean-man \
+ clean-html \
+ clean-dirhtml \
+ clean-pickle \
+ clean-json \
+ clean-htmlhelp \
+ clean-qthelp \
+ clean-latex \
+ clean-rdoc \
+ clean-textile \
+ clean-changes \
+ clean-linkcheck \
+ clean-doctest
+
+$(clean_targets):
+ target=`echo $@ | sed -e 's/^clean-//'`; \
+ rm -rf $${target}-build-stamp $${target}
+
+build_stamps = \
+ man-build-stamp \
+ html-build-stamp \
+ dirhtml-build-stamp \
+ pickle-build-stamp \
+ json-build-stamp \
+ htmlhelp-build-stamp \
+ qthelp-build-stamp \
+ latex-build-stamp \
+ rdoc-build-stamp \
+ textile-build-stamp \
+ changes-build-stamp \
+ linkcheck-build-stamp \
+ doctest-build-stamp
+
+$(build_stamps): $(document_source_files)
+ target=`echo $@ | sed -e 's/-build-stamp$$//'`; \
+ $(SPHINX_BUILD_COMMAND) \
+ -Dlanguage=$(LOCALE) \
+ -d $(DOCTREES_BASE)/$${target} \
+ -b $${target} \
+ $(ALLSPHINXOPTS) \
+ $${target}
+ @touch $@
+
+qthelp: qthelp-message
+qthelp-message: qthelp-build-stamp
+ @echo "Build finished; now you can run 'qcollectiongenerator' with the" \
+ ".qhcp project file in qthelp/*, like this:"
+ @echo "# qcollectiongenerator qthelp/groonga.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile qthelp/groonga.qhc"
+
+latex: latex-message
+latex-message: latex-build-stamp
+ @echo "Build finished; the LaTeX files are in latex/*."
+ @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
+ "run these through (pdf)latex."
+endif
diff --git a/storage/mroonga/config.sh.in b/storage/mroonga/config.sh.in
new file mode 100644
index 00000000..4f02fb94
--- /dev/null
+++ b/storage/mroonga/config.sh.in
@@ -0,0 +1,20 @@
+# 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-1335 USA
+
+MYSQL_SOURCE_DIR="@MYSQL_SOURCE_DIR@"
+MYSQL_BUILD_DIR="@MYSQL_BUILD_DIR@"
+MYSQL_VERSION="@MYSQL_VERSION@"
+MRN_BUNDLED="@MRN_BUNDLED@"
diff --git a/storage/mroonga/configure.ac b/storage/mroonga/configure.ac
new file mode 100644
index 00000000..3ef31bdc
--- /dev/null
+++ b/storage/mroonga/configure.ac
@@ -0,0 +1,540 @@
+AC_PREREQ(2.59)
+
+m4_define([mrn_version_major], m4_include(version_major))
+m4_define([mrn_version_minor], m4_include(version_minor))
+m4_define([mrn_version_micro], m4_include(version_micro))
+m4_define([mrn_version], m4_include(version))
+m4_define([mrn_version_in_hex], m4_include(version_in_hex))
+m4_define([mrn_plugin_version], m4_include(plugin_version))
+
+AC_INIT([mroonga], [mrn_version], [groonga-talk@lists.sourceforge.net])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([config.h])
+
+AM_INIT_AUTOMAKE([tar-pax foreign subdir-objects])
+
+MRN_VERSION=mrn_version
+MRN_VERSION_MAJOR=mrn_version_major
+MRN_VERSION_MINOR=mrn_version_minor
+MRN_VERSION_MICRO=mrn_version_micro
+MRN_VERSION_IN_HEX=mrn_version_in_hex
+MRN_PLUGIN_VERSION=mrn_plugin_version
+AC_SUBST([MRN_VERSION])
+AC_SUBST([MRN_VERSION_MAJOR])
+AC_SUBST([MRN_VERSION_MINOR])
+AC_SUBST([MRN_VERSION_MICRO])
+AC_SUBST([MRN_VERSION_IN_HEX])
+AC_SUBST([MRN_PLUGIN_VERSION])
+
+MRN_PACKAGE_STRING="$PACKAGE_STRING"
+AC_SUBST([MRN_PACKAGE_STRING])
+
+MRN_BUNDLED=FALSE
+AC_SUBST([MRN_BUNDLED])
+
+AC_C_BIGENDIAN
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_CPP
+AC_PROG_LIBTOOL
+m4_ifdef([LT_OUTPUT], [LT_OUTPUT])
+
+AC_DEFUN([CHECK_CFLAG], [
+ AC_MSG_CHECKING([if gcc supports $1])
+ old_CFLAGS=$CFLAGS
+ flag=`echo '$1' | sed -e 's,^-Wno-,-W,'`
+ CFLAGS="$CFLAGS $flag -Werror"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+ [check_cflag=yes],
+ [check_cflag=no])
+ CFLAGS="$old_CFLAGS"
+ if test "x$check_cflag" = "xyes"; then
+ CFLAGS="$CFLAGS $1"
+ fi
+ AC_MSG_RESULT([$check_cflag])
+])
+
+AC_DEFUN([CHECK_CXXFLAG], [
+ AC_MSG_CHECKING([if g++ supports $1])
+ old_CXXFLAGS=$CXXFLAGS
+ flag=`echo '$1' | sed -e 's,^-Wno-,-W,'`
+ CXXFLAGS="$CXXFLAGS $flag -Werror"
+ AC_LANG_PUSH([C++])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+ [check_cxxflag=yes],
+ [check_cxxflag=no])
+ AC_LANG_POP([C++])
+ CXXFLAGS="$old_CXXFLAGS"
+ if test "x$check_cxxflag" = "xyes"; then
+ CXXFLAGS="$CXXFLAGS $1"
+ fi
+ AC_MSG_RESULT([$check_cxxflag])
+])
+
+AC_DEFUN([CHECK_BUILD_FLAG], [
+ CHECK_CFLAG([$1])
+ CHECK_CXXFLAG([$1])
+])
+
+if test "$GCC" = "yes"; then
+ CHECK_BUILD_FLAG([-Wall])
+ CHECK_BUILD_FLAG([-Wextra])
+ CHECK_BUILD_FLAG([-Wno-unused-parameter])
+ CHECK_BUILD_FLAG([-Wno-strict-aliasing])
+ # REMOVEME: workaround for MySQL/MariaDB 5.5.22 :<
+ # They use deprecated MYSQL::generate_name style in class definition.
+ CHECK_BUILD_FLAG([-Wno-deprecated])
+fi
+
+AC_MSG_CHECKING(for the suffix of plugin shared libraries)
+shrext_cmds=$(./libtool --config | grep '^shrext_cmds=')
+eval $shrext_cmds
+module=yes eval MRN_PLUGIN_SUFFIX="$shrext_cmds"
+AC_MSG_RESULT($MRN_PLUGIN_SUFFIX)
+if test -z "$MRN_PLUGIN_SUFFIX"; then
+ AC_MSG_ERROR([can't detect plugin suffix])
+fi
+AC_SUBST(MRN_PLUGIN_SUFFIX)
+
+AC_ARG_WITH(libmysqlservices-compat,
+ [AS_HELP_STRING([--with-libmysqlservices-compat],
+ [Use libmysqlservices compatible library for missing libmysqlservices.a])
+ ],
+ [with_libmysqlservices_compat=$withval],
+ [with_libmysqlservices_compat=no])
+AM_CONDITIONAL([WITH_LIBMYSQLSERVICES_COMPAT], [test "${with_libmysqlservices_compat}" != "no"])
+
+AC_DEFUN([CONFIG_OPTION_MYSQL],[
+ AC_MSG_CHECKING([mysql source])
+
+ ac_mysql_source_dir=
+ AC_ARG_WITH([mysql-source],
+ [AS_HELP_STRING([--with-mysql-source=PATH], [MySQL source directory PATH])],
+ [
+ ac_mysql_source_dir="$withval"
+ if test -f "$ac_mysql_source_dir/sql/handler.h"; then
+ case "$ac_mysql_source_dir" in
+ /*)
+ :
+ ;;
+ *)
+ ac_mysql_source_dir="$ac_pwd/$ac_mysql_source_dir"
+ ;;
+ esac
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_ERROR([invalid MySQL source directory])
+ fi
+ ],
+ [AC_MSG_ERROR([--with-mysql-source=PATH is required])]
+ )
+ MYSQL_SOURCE_DIR="$ac_mysql_source_dir"
+ AC_SUBST(MYSQL_SOURCE_DIR)
+
+ ac_mysql_build_dir=
+ AC_ARG_WITH([mysql-build],
+ [AS_HELP_STRING([--with-mysql-build=PATH], [MySQL build directory PATH])],
+ [ac_mysql_build_dir="$withval"],
+ [ac_mysql_build_dir="$ac_mysql_source_dir"]
+ )
+ case "$ac_mysql_build_dir" in
+ /*)
+ :
+ ;;
+ *)
+ ac_mysql_build_dir="$ac_pwd/$ac_mysql_build_dir"
+ ;;
+ esac
+ MYSQL_BUILD_DIR="$ac_mysql_build_dir"
+ AC_SUBST(MYSQL_BUILD_DIR)
+
+ AC_MSG_CHECKING([mysql_config])
+ AC_ARG_WITH([mysql-config],
+ [AS_HELP_STRING([--with-mysql-config=PATH],
+ [mysql_config PATH])],
+ [ac_mysql_config="$withval"],
+ [ac_mysql_config=])
+ if test -z "$ac_mysql_config"; then
+ AC_PATH_PROG(ac_mysql_config, mysql_config, mysql-config-not-found)
+ fi
+ if test "$ac_mysql_config" = "mysql-config-not-found"; then
+ AC_MSG_ERROR([can't detect mysql_config. Please specify mysql_config path by --with-mysql-config=PATH.])
+ fi
+ AC_MSG_RESULT([$ac_mysql_config])
+
+ plugindir="$($ac_mysql_config --plugindir)"
+ if test $? -ne 0; then
+ AC_MSG_ERROR([failed to run "$ac_mysql_config": $plugindir])
+ fi
+ AC_SUBST(plugindir)
+
+ MYSQL_CFLAGS="$MYSQL_CFLAGS $($ac_mysql_config --cflags)"
+ AC_SUBST(MYSQL_CFLAGS)
+
+ MYSQL_INCLUDES=""
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_build_dir/include"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/sql"
+ if test -d "$ac_mysql_source_dir/sql/auth"; then
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/sql/auth"
+ fi
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/include"
+ if test -d "$ac_mysql_source_dir/extra/rapidjson"; then
+ mysql_rapidjson_include_dir="$ac_mysql_source_dir/extra/rapidjson/include"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_rapidjson_include_dir"
+ fi
+ if test -d "$ac_mysql_source_dir/extra/regex"; then
+ mysql_regex_include_dir="$ac_mysql_source_dir/extra/regex"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_regex_include_dir"
+ else
+ mysql_regex_include_dir="$ac_mysql_source_dir/regex"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$mysql_regex_include_dir"
+ fi
+ if test -d "$ac_mysql_source_dir/libbinlogevents"; then
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_build_dir/libbinlogevents/include"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/libbinlogevents/export"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir/libbinlogevents/include"
+ fi
+ MYSQL_INCLUDES="$MYSQL_INCLUDES -I$ac_mysql_source_dir"
+ MYSQL_INCLUDES="$MYSQL_INCLUDES $($ac_mysql_config --include)"
+ AC_SUBST(MYSQL_INCLUDES)
+
+ MYSQL_VERSION="$($ac_mysql_config --version)"
+ AC_SUBST(MYSQL_VERSION)
+
+ MYSQL_MAJOR_MINOR_VERSION=["$(echo $MYSQL_VERSION | sed -e 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*[a-z]*\)[.0-9a-z-]*$/\1.\2/')"]
+
+ MYSQL_CXXFLAGS="-fno-implicit-templates -felide-constructors"
+ case "$MYSQL_MAJOR_MINOR_VERSION" in
+ 5.7|8.*)
+ :
+ ;;
+ *)
+ MYSQL_CXXFLAGS="$MYSQL_CXXFLAGS -fno-exceptions -fno-rtti"
+ ;;
+ esac
+
+ if test "${with_libmysqlservices_compat}" = "no"; then
+ case "$MYSQL_MAJOR_MINOR_VERSION" in
+ 5.1)
+ MYSQL_LIBS=""
+ ;;
+ *)
+ AC_MSG_CHECKING([for libmysqlservices.a directory])
+ pkglibdir="$($ac_mysql_config --variable=pkglibdir)"
+ mysql_build_libservices_dir="${MYSQL_BUILD_DIR}/libservices"
+ if test -f "${mysql_build_libservices_dir}/libmysqlservices.a"; then
+ mysql_services_lib_dir="${mysql_build_libservices_dir}"
+ else
+ if test -f "${pkglibdir}/libmysqlservices.a"; then
+ mysql_services_lib_dir="${pkglibdir}"
+ elif test -f "${pkglibdir}/mysql/libmysqlservices.a"; then
+ mysql_services_lib_dir="${pkglibdir}/mysql"
+ else
+ AC_MSG_ERROR([libmysqlservices.a is not found in <${pkglibdir}/> and <${pkglibdir}/mysql/>])
+ fi
+ fi
+ AC_MSG_RESULT([$mysql_services_lib_dir])
+ MYSQL_LIBS="$MYSQL_LIBS -L\"$mysql_services_lib_dir\" -lmysqlservices"
+ ;;
+ esac
+ AC_SUBST(MYSQL_LIBS)
+ fi
+])
+
+m4_define([mrn_required_groonga_version], m4_include(required_groonga_version))
+REQUIRED_GROONGA_VERSION=mrn_required_groonga_version
+AC_SUBST(REQUIRED_GROONGA_VERSION)
+AC_DEFUN([CONFIG_OPTION_GROONGA],[
+ PKG_CHECK_MODULES(GROONGA, groonga >= ${REQUIRED_GROONGA_VERSION})
+ _PKG_CONFIG(GROONGA_VERSION, variable=groonga_version, groonga)
+ GROONGA_VERSION=$pkg_cv_GROONGA_VERSION
+ AC_SUBST(GROONGA_VERSION)
+])
+
+m4_define([mrn_required_groonga_normalizer_mysql_version],
+ m4_include(required_groonga_normalizer_mysql_version))
+REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION=mrn_required_groonga_normalizer_mysql_version
+AC_DEFUN([CONFIG_OPTION_GROONGA_NORMALIZER_MYSQL], [
+ AC_MSG_CHECKING([for groonga-normalizer-mysql])
+ PKG_CHECK_EXISTS([groonga-normalizer-mysql >= ${REQUIRED_GROONGA_NORMALIZER_MYSQL_VERSION}],
+ [WITH_GROONGA_NORMALIZER_MYSQL=yes],
+ [WITH_GROONGA_NORMALIZER_MYSQL=no])
+ AC_MSG_RESULT($WITH_GROONGA_NORMALIZER_MYSQL)
+ if test "$WITH_GROONGA_NORMALIZER_MYSQL" = "yes"; then
+ AC_DEFINE([WITH_GROONGA_NORMALIZER_MYSQL],
+ [1],
+ [Use MySQL normalizer plugin for groonga])
+ _PKG_CONFIG(plugin_name, variable=plugin_name, groonga-normalizer-mysql)
+ GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME=$pkg_cv_plugin_name
+ AC_DEFINE_UNQUOTED([GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME],
+ "${GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME}",
+ [Name of MySQL normalizer plugin for groonga])
+ fi
+])
+
+AC_ARG_WITH(debug,
+ [dnl
+AS_HELP_STRING([--with-debug],
+ [Add debug code])
+AS_HELP_STRING([--with-debug=full],
+ [Add debug code (adds memory checker, very slow)])dnl
+ ],
+ [with_debug=$withval],
+ [with_debug=no])
+if test "$with_debug" = "yes"
+then
+ # Medium debug.
+ AC_DEFINE([DBUG_ON], [1], [Use libdbug])
+ CFLAGS="$DEBUG_CFLAGS $DEBUG_OPTIMIZE_CC -DSAFE_MUTEX $CFLAGS -O0 -g3"
+ CXXFLAGS="$DEBUG_CXXFLAGS $DEBUG_OPTIMIZE_CXX -DSAFE_MUTEX $CXXFLAGS -O0 -g3"
+elif test "$with_debug" = "full"
+then
+ # Full debug. Very slow in some cases
+ AC_DEFINE([DBUG_ON], [1], [Use libdbug])
+ CFLAGS="$DEBUG_CFLAGS -DSAFE_MUTEX -DSAFEMALLOC $CFLAGS -O0 -g3"
+ CXXFLAGS="$DEBUG_CXXFLAGS -DSAFE_MUTEX -DSAFEMALLOC $CXXFLAGS -O0 -g3"
+else
+ # Optimized version. No debug
+ AC_DEFINE([DBUG_OFF], [1], [Don't use libdbug])
+ CFLAGS="$OPTIMIZE_CFLAGS $CFLAGS"
+ CXXFLAGS="$OPTIMIZE_CXXFLAGS $CXXFLAGS"
+fi
+
+AC_ARG_WITH(valgrind,
+ [AS_HELP_STRING([--with-valgrind], [Use valgrind. [default=no]])],
+ [with_valgrind="$withval"],
+ [with_valgrind="no"])
+if test "$with_valgrind" != "no"; then
+ CFLAGS="-DHAVE_valgrind $CFLAGS"
+ CXXFLAGS="-DHAVE_valgrind $CXXFLAGS"
+fi
+
+CONFIG_OPTION_MYSQL
+CONFIG_OPTION_GROONGA
+CONFIG_OPTION_GROONGA_NORMALIZER_MYSQL
+
+AC_ARG_WITH(default_parser,
+ [AS_HELP_STRING([--with-default-parser=PARSER],
+ [Deprecated. Use --with-default-tokenizer=TOKENIZER instead.
+ specify the default fulltext parser like
+ --with-default-parser=TokenMecab.
+ (default: TokenBigram)])],
+ [default_parser=$withval],
+ [default_parser=no])
+if test x"$default_parser" != x"no"; then
+ AC_DEFINE_UNQUOTED(MRN_TOKENIZER_DEFAULT,
+ "$default_parser",
+ "specified the default tokenizer for fulltext index")
+fi
+
+AC_ARG_WITH(default_tokenizer,
+ [AS_HELP_STRING([--with-default-tokenizer=TOKENIZER],
+ [specify the default tokenizer for fulltext index like
+ --with-default-tokenizer=TokenMecab.
+ (default: TokenBigram)])],
+ [default_tokenizer=$withval],
+ [default_tokenizer=no])
+if test x"$default_tokenizer" != x"no"; then
+ AC_DEFINE_UNQUOTED(MRN_DEFAULT_TOKENIZER,
+ "$default_tokenizer",
+ "specified the default tokenizer for fulltext index")
+fi
+
+AC_ARG_ENABLE(fast_mutexes,
+ [AS_HELP_STRING([--disable-fast-mutexes],
+ [Force disable fast mutex.
+ [default: use mysql_config output]])],
+ [enable_fast_mutexes=$enableval],
+ [enable_fast_mutexes=auto])
+if test "$enable_fast_mutexes" = "no"; then
+ AC_DEFINE(FORCE_FAST_MUTEX_DISABLED, [1],
+ [Define to 1 if force fast mutexes disabled])
+elif test "$enable_fast_mutexes" = "yes"; then
+ AC_DEFINE(MY_PTHREAD_FASTMUTEX, [1],
+ [Define to 1 if fast mutexes enabled])
+fi
+
+AC_ARG_ENABLE(dtrace,
+ [AS_HELP_STRING([--enable-dtrace],
+ [Enable DTrace. [default: no]])],
+ [enable_dtrace=$enableval],
+ [enable_dtrace=no])
+if test "$enable_dtrace" = "no"; then
+ AC_DEFINE(DISABLE_DTRACE, [1], [Define to 1 if DTrace is disabled])
+fi
+
+# check Cutter with C++ support if available
+REQUIRED_MINIMUM_CUTTER_VERSION=1.1.3
+m4_ifdef([AC_CHECK_CPPCUTTER], [
+AC_CHECK_CPPCUTTER(>= $REQUIRED_MINIMUM_CUTTER_VERSION)
+],
+[ac_cv_use_cutter="no"])
+AM_CONDITIONAL([WITH_CUTTER], [test "$ac_cv_use_cutter" != "no"])
+
+# For mroonga.github.com
+AC_ARG_WITH(mroonga-github-com-path,
+ [AS_HELP_STRING([--with-mroonga-github-com-path=PATH],
+ [specify mroonga.github.com path to update mroonga.github.com.])],
+ [MROONGA_GITHUB_COM_PATH="$withval"],
+ [MROONGA_GITHUB_COM_PATH=""])
+AC_SUBST(MROONGA_GITHUB_COM_PATH)
+
+# For package
+AC_ARG_WITH(rsync-path,
+ [AS_HELP_STRING([--with-rsync-path=PATH],
+ [specify rsync path to upload mroonga packages.])],
+ [RSYNC_PATH="$withval"],
+ [RSYNC_PATH="packages@packages.groonga.org:public"])
+AC_SUBST(RSYNC_PATH)
+
+AC_ARG_WITH(launchpad-ppa,
+ [AS_HELP_STRING([--with-launchpad-ppa=PPA],
+ [specify Launchpad Personal Package Archive. [default=groonga-ppa]])],
+ [LAUNCHPAD_PPA="$withval"],
+ [LAUNCHPAD_PPA="groonga-ppa"])
+AC_SUBST(LAUNCHPAD_PPA)
+
+AC_ARG_WITH(launchpad-uploader-pgp-key,
+ [AS_HELP_STRING([--with-launchpad-uploader-pgp-key=KEY],
+ [specify PGP key UID to upload Groonga packages to Launchpad.])],
+ [LAUNCHPAD_UPLOADER_PGP_KEY="$withval"],
+ [LAUNCHPAD_UPLOADER_PGP_KEY=""])
+AC_SUBST(LAUNCHPAD_UPLOADER_PGP_KEY)
+
+GPG_UID=m4_include(gpg_uid)
+AC_SUBST(GPG_UID)
+
+# For update-version
+AC_ARG_WITH(cutter-source-path,
+ [AS_HELP_STRING([--with-cutter-source-path=PATH],
+ [specify Cutter source path for mroonga's release manager.])],
+ [CUTTER_SOURCE_PATH="$withval"])
+case "$CUTTER_SOURCE_PATH" in
+ ""|/*)
+ : # do nothing
+ ;;
+ *)
+ CUTTER_SOURCE_PATH="\$(top_builddir)/${CUTTER_SOURCE_PATH}"
+ ;;
+esac
+AC_SUBST(CUTTER_SOURCE_PATH)
+
+
+# Document
+AC_MSG_CHECKING([whether enable document])
+AC_ARG_ENABLE(document,
+ [AS_HELP_STRING([--enable-document],
+ [enable document generation by Sphinx. [default=auto]])],
+ [enable_document="$enableval"],
+ [enable_document="auto"])
+AC_MSG_RESULT($enable_document)
+
+document_available=no
+document_buildable=no
+have_built_document=no
+if test x"$enable_document" != x"no"; then
+ if test -f "$srcdir/doc/build-stamp"; then
+ document_available=yes
+ have_built_document=yes
+ fi
+
+ if test x"$enable_document" = x"yes"; then
+ AC_PATH_PROG(SPHINX_BUILD, sphinx-build, [])
+ if test -n "$SPHINX_BUILD"; then
+ sphinx_build_version=`"$SPHINX_BUILD" --version`
+ if ! echo "$sphinx_build_version" | grep -q ' 1\.[[2-6]]'; then
+ AC_MSG_ERROR([
+sphinx-build is old: $sphinx_build_version
+Sphinx 1.2 or later is required.])
+ fi
+ document_available=yes
+ document_buildable=yes
+ else
+ AC_MSG_ERROR([
+No sphinx-build found.
+Install it and try again.
+
+How to install sphinx-build:
+
+For Debian GNU/Linux based system like Ubuntu:
+ % sudo apt-get install -y python-pip
+ % sudo pip install sphinx
+
+For Red Hat based system like CentOS:
+ % sudo yum install -y python-pip
+ % sudo pip install sphinx])
+ fi
+ AC_SUBST(SPHINX_BUILD)
+ fi
+fi
+
+AM_CONDITIONAL([DOCUMENT_AVAILABLE],
+ [test "${document_available}" = "yes"])
+AC_MSG_CHECKING([whether document available])
+AC_MSG_RESULT($document_available)
+
+AM_CONDITIONAL([DOCUMENT_BUILDABLE],
+ [test "${document_buildable}" = "yes"])
+AC_MSG_CHECKING([whether document buildable])
+AC_MSG_RESULT($document_buildable)
+
+AM_CONDITIONAL([HAVE_BUILT_DOCUMENT],
+ [test "${have_built_document}" = "yes"])
+AC_MSG_CHECKING([whether having built document])
+AC_MSG_RESULT($have_built_document)
+
+DOCUMENT_VERSION=mrn_version
+DOCUMENT_VERSION_FULL="$DOCUMENT_VERSION"
+AC_SUBST(DOCUMENT_VERSION)
+AC_SUBST(DOCUMENT_VERSION_FULL)
+
+CFLAGS="$CFLAGS"
+CXXFLAGS="$CXXFLAGS $MYSQL_CXXFLAGS"
+
+AC_CONFIG_FILES([
+ Makefile
+ build/Makefile
+ build/cmake_modules/Makefile
+ lib/Makefile
+ udf/Makefile
+ test/Makefile
+ test/unit/Makefile
+ mysql-test/Makefile
+ packages/Makefile
+ packages/rpm/Makefile
+ packages/rpm/centos/Makefile
+ packages/yum/Makefile
+ packages/apt/Makefile
+ packages/source/Makefile
+ packages/ubuntu/Makefile
+ packages/windows/Makefile
+ tools/Makefile
+ doc/Makefile
+ doc/locale/Makefile
+ doc/locale/en/Makefile
+ doc/locale/en/LC_MESSAGES/Makefile
+ doc/locale/ja/Makefile
+ doc/locale/ja/LC_MESSAGES/Makefile
+ data/Makefile
+])
+AC_OUTPUT([
+ config.sh
+ mrn_version.h
+ mysql-test/mroonga/storage/information_schema/r/plugins.result
+ mysql-test/mroonga/storage/variable/r/version.result
+ packages/debian-5.5/control
+ packages/debian-5.6/control
+ packages/debian-5.7/control
+ packages/debian-mariadb-10.0/control
+ packages/apt/env.sh
+ packages/rpm/centos/mysql55-mroonga.spec
+ packages/rpm/centos/mysql56-community-mroonga.spec
+ packages/rpm/centos/mysql57-community-mroonga.spec
+ packages/rpm/centos/mariadb-mroonga.spec
+ packages/rpm/centos/mariadb-10.1-mroonga.spec
+ packages/rpm/centos/mariadb-10.2-mroonga.spec
+ packages/rpm/centos/percona-server-56-mroonga.spec
+ packages/rpm/centos/percona-server-57-mroonga.spec
+ packages/yum/env.sh
+ data/install.sql
+])
diff --git a/storage/mroonga/data/Makefile.am b/storage/mroonga/data/Makefile.am
new file mode 100644
index 00000000..c088c78c
--- /dev/null
+++ b/storage/mroonga/data/Makefile.am
@@ -0,0 +1,4 @@
+sqldir = $(pkgdatadir)
+dist_sql_DATA = \
+ install.sql \
+ uninstall.sql
diff --git a/storage/mroonga/data/install.sql.in b/storage/mroonga/data/install.sql.in
new file mode 100644
index 00000000..0a2f308a
--- /dev/null
+++ b/storage/mroonga/data/install.sql.in
@@ -0,0 +1,35 @@
+SET @inst=IF(EXISTS(SELECT * FROM mysql.plugin WHERE NAME='mroonga'),'DO 1', "INSTALL PLUGIN mroonga SONAME 'ha_mroonga'");
+PREPARE s FROM @inst;
+EXECUTE s;
+
+DROP FUNCTION IF EXISTS last_insert_grn_id;
+CREATE FUNCTION last_insert_grn_id RETURNS INTEGER
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_snippet;
+CREATE FUNCTION mroonga_snippet RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_command;
+CREATE FUNCTION mroonga_command RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_escape;
+CREATE FUNCTION mroonga_escape RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_snippet_html;
+CREATE FUNCTION mroonga_snippet_html RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_normalize;
+CREATE FUNCTION mroonga_normalize RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_highlight_html;
+CREATE FUNCTION mroonga_highlight_html RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
+
+DROP FUNCTION IF EXISTS mroonga_query_expand;
+CREATE FUNCTION mroonga_query_expand RETURNS STRING
+ SONAME 'ha_mroonga@MRN_PLUGIN_SUFFIX@';
diff --git a/storage/mroonga/data/uninstall.sql b/storage/mroonga/data/uninstall.sql
new file mode 100644
index 00000000..5713e074
--- /dev/null
+++ b/storage/mroonga/data/uninstall.sql
@@ -0,0 +1,12 @@
+DROP FUNCTION IF EXISTS last_insert_grn_id;
+DROP FUNCTION IF EXISTS mroonga_snippet;
+DROP FUNCTION IF EXISTS mroonga_command;
+DROP FUNCTION IF EXISTS mroonga_escape;
+DROP FUNCTION IF EXISTS mroonga_snippet_html;
+DROP FUNCTION IF EXISTS mroonga_normalize;
+DROP FUNCTION IF EXISTS mroonga_highlight_html;
+DROP FUNCTION IF EXISTS mroonga_query_expand;
+
+UNINSTALL PLUGIN Mroonga;
+
+FLUSH TABLES;
diff --git a/storage/mroonga/gpg_uid b/storage/mroonga/gpg_uid
new file mode 100644
index 00000000..7c1a800b
--- /dev/null
+++ b/storage/mroonga/gpg_uid
@@ -0,0 +1 @@
+45499429
diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp
new file mode 100644
index 00000000..baf6de6c
--- /dev/null
+++ b/storage/mroonga/ha_mroonga.cpp
@@ -0,0 +1,17086 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2017 Kouhei Sutou <kou@clear-code.com>
+ Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+*/
+
+#include "mrn_mysql.h"
+#include "mrn_mysql_compat.h"
+
+#ifdef USE_PRAGMA_IMPLEMENTATION
+#pragma implementation
+#endif
+
+#include <sql_plugin.h>
+#include <sql_show.h>
+#include <key.h>
+#include <tztime.h>
+#include <sql_base.h>
+#include <sql_select.h>
+#include <item_sum.h>
+
+#ifdef MRN_HAVE_BINLOG_H
+# include <binlog.h>
+#endif
+
+#ifdef MRN_HAVE_SQL_OPTIMIZER_H
+# include <sql_optimizer.h>
+#endif
+
+#include <ft_global.h>
+#include <spatial.h>
+#include <mysql.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <math.h>
+# include <direct.h>
+# define MRN_TABLE_SHARE_LOCK_SHARE_PROC "?key_TABLE_SHARE_LOCK_share@@3IA"
+# define MRN_TABLE_SHARE_LOCK_HA_DATA_PROC "?key_TABLE_SHARE_LOCK_ha_data@@3IA"
+# ifdef _WIN64
+# define MRN_BINLOG_FILTER_PROC "?binlog_filter@@3PEAVRpl_filter@@EA"
+# define MRN_MY_TZ_UTC_PROC "?my_tz_UTC@@3PEAVTime_zone@@EA"
+# else
+# define MRN_BINLOG_FILTER_PROC "?binlog_filter@@3PAVRpl_filter@@A"
+# define MRN_MY_TZ_UTC_PROC "?my_tz_UTC@@3PAVTime_zone@@A"
+# endif
+#else
+# include <dirent.h>
+# include <unistd.h>
+#endif
+
+#include "mrn_err.h"
+#include "mrn_table.hpp"
+#include <groonga/plugin.h>
+#include "ha_mroonga.hpp"
+#include <mrn_path_mapper.hpp>
+#include <mrn_index_table_name.hpp>
+#include <mrn_index_column_name.hpp>
+#include <mrn_debug_column_access.hpp>
+#include <mrn_auto_increment_value_lock.hpp>
+#include <mrn_external_lock.hpp>
+#include <mrn_match_escalation_threshold_scope.hpp>
+#include <mrn_multiple_column_key_codec.hpp>
+#include <mrn_field_normalizer.hpp>
+#include <mrn_encoding.hpp>
+#include <mrn_parameters_parser.hpp>
+#include <mrn_lock.hpp>
+#include <mrn_condition_converter.hpp>
+#include <mrn_time_converter.hpp>
+#include <mrn_smart_grn_obj.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_grn.hpp>
+#include <mrn_value_decoder.hpp>
+#include <mrn_database_repairer.hpp>
+#include <mrn_operation.hpp>
+#include <mrn_column_name.hpp>
+#include <mrn_count_skip_checker.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_query_parser.hpp>
+#include <mrn_smart_bitmap.hpp>
+#include <mrn_table_fields_offset_mover.hpp>
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+# include <sql_table.h>
+#endif
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+# include <create_options.h>
+#endif
+
+// for debug
+#define MRN_CLASS_NAME "ha_mroonga"
+
+#define MRN_SHORT_TEXT_SIZE (1 << 12) // 4Kbytes
+#define MRN_TEXT_SIZE (1 << 16) // 64Kbytes
+#define MRN_LONG_TEXT_SIZE (1 << 31) // 2Gbytes
+
+#ifdef MRN_HAVE_TDC_LOCK_TABLE_SHARE
+# ifdef MRN_TABLE_SHARE_TDC_IS_POINTER
+# define mrn_open_mutex(share) &((share)->tdc->LOCK_table_share)
+# else
+# define mrn_open_mutex(share) &((share)->tdc.LOCK_table_share)
+# endif
+# define mrn_open_mutex_lock(share) do { \
+ TABLE_SHARE *share_ = share; \
+ if (share_ && share_->tmp_table == NO_TMP_TABLE) { \
+ mysql_mutex_lock(mrn_open_mutex(share_)); \
+ } \
+} while (0)
+# define mrn_open_mutex_unlock(share) do { \
+ TABLE_SHARE *share_ = share; \
+ if (share_ && share_->tmp_table == NO_TMP_TABLE) { \
+ mysql_mutex_unlock(mrn_open_mutex(share_)); \
+ } \
+} while (0)
+#else
+# ifdef DBUG_OFF
+# ifndef _WIN32
+extern mysql_mutex_t LOCK_open;
+# endif
+# endif
+static mysql_mutex_t *mrn_LOCK_open;
+# define mrn_open_mutex_lock(share) mysql_mutex_lock(mrn_LOCK_open)
+# define mrn_open_mutex_unlock(share) mysql_mutex_unlock(mrn_LOCK_open)
+#endif
+
+#if MYSQL_VERSION_ID >= 50600
+# define MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
+#endif
+
+#ifdef MRN_MARIADB_P
+# if MYSQL_VERSION_ID >= 100200
+# define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
+# else
+# define MRN_ORDER_IS_ASC(order) ((order)->asc)
+# endif
+#else
+# if MYSQL_VERSION_ID >= 50603
+# define MRN_ORDER_IS_ASC(order) ((order)->direction == ORDER::ORDER_ASC)
+# else
+# define MRN_ORDER_IS_ASC(order) ((order)->asc)
+# endif
+#endif
+
+#define MRN_STRINGIFY(macro_or_string) MRN_STRINGIFY_ARG(macro_or_string)
+#define MRN_STRINGIFY_ARG(contents) #contents
+
+#define MRN_PLUGIN_NAME mroonga
+#define MRN_PLUGIN_NAME_STRING "Mroonga"
+#define MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "Mroonga"
+
+#ifdef MRN_MARIADB_P
+# define st_mysql_plugin st_maria_plugin
+# define mrn_declare_plugin(NAME) maria_declare_plugin(NAME)
+# define mrn_declare_plugin_end maria_declare_plugin_end
+# define MRN_PLUGIN_LAST_VALUES MRN_VERSION, MariaDB_PLUGIN_MATURITY_STABLE
+#else
+# define mrn_declare_plugin(NAME) mysql_declare_plugin(NAME)
+# define mrn_declare_plugin_end mysql_declare_plugin_end
+# define MRN_PLUGIN_LAST_VALUES NULL, 0
+#endif
+
+#if MYSQL_VERSION_ID >= 100007 && defined(MRN_MARIADB_P)
+# define MRN_THD_GET_AUTOINC(thd, off, inc) thd_get_autoinc(thd, off, inc)
+# define MRN_GET_ERR_MSG(code) my_get_err_msg(code)
+#else
+# define MRN_THD_GET_AUTOINC(thd, off, inc) \
+ { \
+ *(off) = thd->variables.auto_increment_offset; \
+ *(inc) = thd->variables.auto_increment_increment; \
+ }
+# define MRN_GET_ERR_MSG(code) ER(code)
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_LEX_GET_TABLE_LIST(lex) (lex)->select_lex->table_list.first
+#else
+# define MRN_LEX_GET_TABLE_LIST(lex) (lex)->first_select_lex()->table_list.first
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_KEYTYPE_FOREIGN KEYTYPE_FOREIGN
+#else
+# define MRN_KEYTYPE_FOREIGN Key::FOREIGN_KEY
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define mrn_calculate_key_len(table, key_index, buffer, keypart_map) \
+ calculate_key_len(table, key_index, keypart_map)
+#else
+# define mrn_calculate_key_len(table, key_index, buffer, keypart_map) \
+ calculate_key_len(table, key_index, buffer, keypart_map)
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_TABLE_LIST_GET_DERIVED(table_list) NULL
+#else
+# define MRN_TABLE_LIST_GET_DERIVED(table_list) (table_list)->derived
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_GEOMETRY_FREE(geometry)
+#else
+# define MRN_GEOMETRY_FREE(geometry) delete (geometry)
+#endif
+
+Rpl_filter *mrn_binlog_filter;
+Time_zone *mrn_my_tz_UTC;
+#ifdef MRN_HAVE_TABLE_DEF_CACHE
+HASH *mrn_table_def_cache;
+#endif
+
+PSI_memory_key mrn_memory_key;
+
+#ifdef MRN_HAVE_PSI_MEMORY_KEY
+static PSI_memory_info mrn_all_memory_keys[]=
+{
+ {&mrn_memory_key, "Mroonga", 0}
+};
+#endif
+
+static const char *INDEX_COLUMN_NAME = "index";
+static const char *MRN_PLUGIN_AUTHOR = "The Mroonga project";
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_PSI_INTERFACE
+# ifdef WIN32
+# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
+PSI_mutex_key *mrn_table_share_lock_share;
+# endif
+PSI_mutex_key *mrn_table_share_lock_ha_data;
+# endif
+static PSI_mutex_key mrn_open_tables_mutex_key;
+static PSI_mutex_key mrn_long_term_share_mutex_key;
+static PSI_mutex_key mrn_allocated_thds_mutex_key;
+PSI_mutex_key mrn_share_mutex_key;
+PSI_mutex_key mrn_long_term_share_auto_inc_mutex_key;
+static PSI_mutex_key mrn_log_mutex_key;
+static PSI_mutex_key mrn_query_log_mutex_key;
+static PSI_mutex_key mrn_db_manager_mutex_key;
+static PSI_mutex_key mrn_context_pool_mutex_key;
+static PSI_mutex_key mrn_operations_mutex_key;
+
+# if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+# define MRN_MUTEXT_INFO_ENTRY(key, name, flags, volatility) \
+ {key, name, flags, volatility}
+# else
+# define MRN_MUTEXT_INFO_ENTRY(key, name, flags, volatility) \
+ {key, name, flags}
+# endif
+
+static PSI_mutex_info mrn_mutexes[] =
+{
+ MRN_MUTEXT_INFO_ENTRY(&mrn_open_tables_mutex_key,
+ "mrn::open_tables", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_long_term_share_mutex_key,
+ "mrn::long_term_share", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_allocated_thds_mutex_key,
+ "mrn::allocated_thds", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_share_mutex_key,
+ "mrn::share", 0, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_long_term_share_auto_inc_mutex_key,
+ "mrn::long_term_share::auto_inc", 0, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_log_mutex_key,
+ "mrn::log", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_query_log_mutex_key,
+ "mrn::query_log", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_db_manager_mutex_key,
+ "mrn::DatabaseManager", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_context_pool_mutex_key,
+ "mrn::ContextPool", PSI_FLAG_GLOBAL, 0),
+ MRN_MUTEXT_INFO_ENTRY(&mrn_operations_mutex_key,
+ "mrn::Operations", PSI_FLAG_GLOBAL, 0)
+};
+#endif
+
+/* global variables */
+handlerton *mrn_hton_ptr;
+HASH mrn_open_tables;
+mysql_mutex_t mrn_open_tables_mutex;
+HASH mrn_long_term_share;
+mysql_mutex_t mrn_long_term_share_mutex;
+
+HASH mrn_allocated_thds;
+mysql_mutex_t mrn_allocated_thds_mutex;
+
+/* internal variables */
+static grn_ctx mrn_ctx;
+static mysql_mutex_t mrn_log_mutex;
+static mysql_mutex_t mrn_query_log_mutex;
+static grn_obj *mrn_db;
+static grn_ctx mrn_db_manager_ctx;
+static mysql_mutex_t mrn_db_manager_mutex;
+mrn::DatabaseManager *mrn_db_manager = NULL;
+static mysql_mutex_t mrn_context_pool_mutex;
+mrn::ContextPool *mrn_context_pool = NULL;
+static mysql_mutex_t mrn_operations_mutex;
+
+
+#ifdef WIN32
+static inline double round(double x)
+{
+ return (floor(x + 0.5));
+}
+#endif
+
+static void mrn_init_encoding_map()
+{
+ mrn::encoding::init();
+}
+
+static int mrn_change_encoding(grn_ctx *ctx, const CHARSET_INFO *charset)
+{
+ return mrn::encoding::set(ctx, charset);
+}
+
+#if defined DBUG_TRACE && !defined(_lint)
+static const char *mrn_inspect_thr_lock_type(enum thr_lock_type lock_type)
+{
+ const char *inspected = "<unknown>";
+ switch (lock_type) {
+ case TL_IGNORE:
+ inspected = "TL_IGNORE";
+ break;
+ case TL_UNLOCK:
+ inspected = "TL_UNLOCK";
+ break;
+ case TL_READ_DEFAULT:
+ inspected = "TL_READ_DEFAULT";
+ break;
+ case TL_READ:
+ inspected = "TL_READ";
+ break;
+ case TL_READ_WITH_SHARED_LOCKS:
+ inspected = "TL_READ_WITH_SHARED_LOCKS";
+ break;
+ case TL_READ_HIGH_PRIORITY:
+ inspected = "TL_READ_HIGH_PRIORITY";
+ break;
+ case TL_READ_NO_INSERT:
+ inspected = "TL_READ_NO_INSERT";
+ break;
+ case TL_READ_SKIP_LOCKED:
+ inspected = "TL_READ_SKIP_LOCKED";
+ break;
+ case TL_WRITE_ALLOW_WRITE:
+ inspected = "TL_WRITE_ALLOW_WRITE";
+ break;
+#ifdef MRN_HAVE_TL_WRITE_CONCURRENT_DEFAULT
+ case TL_WRITE_CONCURRENT_DEFAULT:
+ inspected = "TL_WRITE_CONCURRENT_DEFAULT";
+ break;
+#endif
+ case TL_WRITE_CONCURRENT_INSERT:
+ inspected = "TL_WRITE_CONCURRENT_INSERT";
+ break;
+#ifdef MRN_HAVE_TL_WRITE_DELAYED
+ case TL_WRITE_DELAYED:
+ inspected = "TL_WRITE_DELAYED";
+ break;
+#endif
+ case TL_WRITE_DEFAULT:
+ inspected = "TL_WRITE_DEFAULT";
+ break;
+ case TL_WRITE_LOW_PRIORITY:
+ inspected = "TL_WRITE_LOW_PRIORITY";
+ break;
+ case TL_WRITE:
+ inspected = "TL_WRITE";
+ break;
+ case TL_WRITE_SKIP_LOCKED:
+ inspected = "TL_WRITE_SKIP_LOCKED";
+ break;
+ case TL_WRITE_ONLY:
+ inspected = "TL_WRITE_ONLY";
+ break;
+ }
+ return inspected;
+}
+
+static const char *mrn_inspect_extra_function(enum ha_extra_function operation)
+{
+ const char *inspected = "<unknown>";
+ switch (operation) {
+ case HA_EXTRA_NORMAL:
+ inspected = "HA_EXTRA_NORMAL";
+ break;
+ case HA_EXTRA_QUICK:
+ inspected = "HA_EXTRA_QUICK";
+ break;
+ case HA_EXTRA_NOT_USED:
+ inspected = "HA_EXTRA_NOT_USED";
+ break;
+ case HA_EXTRA_CACHE:
+ inspected = "HA_EXTRA_CACHE";
+ break;
+ case HA_EXTRA_NO_CACHE:
+ inspected = "HA_EXTRA_NO_CACHE";
+ break;
+ case HA_EXTRA_NO_READCHECK:
+ inspected = "HA_EXTRA_NO_READCHECK";
+ break;
+ case HA_EXTRA_READCHECK:
+ inspected = "HA_EXTRA_READCHECK";
+ break;
+ case HA_EXTRA_KEYREAD:
+ inspected = "HA_EXTRA_KEYREAD";
+ break;
+ case HA_EXTRA_NO_KEYREAD:
+ inspected = "HA_EXTRA_NO_KEYREAD";
+ break;
+ case HA_EXTRA_NO_USER_CHANGE:
+ inspected = "HA_EXTRA_NO_USER_CHANGE";
+ break;
+ case HA_EXTRA_KEY_CACHE:
+ inspected = "HA_EXTRA_KEY_CACHE";
+ break;
+ case HA_EXTRA_NO_KEY_CACHE:
+ inspected = "HA_EXTRA_NO_KEY_CACHE";
+ break;
+ case HA_EXTRA_WAIT_LOCK:
+ inspected = "HA_EXTRA_WAIT_LOCK";
+ break;
+ case HA_EXTRA_NO_WAIT_LOCK:
+ inspected = "HA_EXTRA_NO_WAIT_LOCK";
+ break;
+ case HA_EXTRA_WRITE_CACHE:
+ inspected = "HA_EXTRA_WRITE_CACHE";
+ break;
+ case HA_EXTRA_FLUSH_CACHE:
+ inspected = "HA_EXTRA_FLUSH_CACHE";
+ break;
+ case HA_EXTRA_NO_KEYS:
+ inspected = "HA_EXTRA_NO_KEYS";
+ break;
+ case HA_EXTRA_KEYREAD_CHANGE_POS:
+ inspected = "HA_EXTRA_KEYREAD_CHANGE_POS";
+ break;
+ case HA_EXTRA_REMEMBER_POS:
+ inspected = "HA_EXTRA_REMEMBER_POS";
+ break;
+ case HA_EXTRA_RESTORE_POS:
+ inspected = "HA_EXTRA_RESTORE_POS";
+ break;
+ case HA_EXTRA_REINIT_CACHE:
+ inspected = "HA_EXTRA_REINIT_CACHE";
+ break;
+ case HA_EXTRA_FORCE_REOPEN:
+ inspected = "HA_EXTRA_FORCE_REOPEN";
+ break;
+ case HA_EXTRA_FLUSH:
+ inspected = "HA_EXTRA_FLUSH";
+ break;
+ case HA_EXTRA_NO_ROWS:
+ inspected = "HA_EXTRA_NO_ROWS";
+ break;
+ case HA_EXTRA_RESET_STATE:
+ inspected = "HA_EXTRA_RESET_STATE";
+ break;
+ case HA_EXTRA_IGNORE_DUP_KEY:
+ inspected = "HA_EXTRA_IGNORE_DUP_KEY";
+ break;
+ case HA_EXTRA_NO_IGNORE_DUP_KEY:
+ inspected = "HA_EXTRA_NO_IGNORE_DUP_KEY";
+ break;
+ case HA_EXTRA_PREPARE_FOR_DROP:
+ inspected = "HA_EXTRA_PREPARE_FOR_DROP";
+ break;
+ case HA_EXTRA_PREPARE_FOR_ALTER_TABLE:
+ inspected = "HA_EXTRA_PREPARE_FOR_ALTER_TABLE";
+ break;
+ case HA_EXTRA_PREPARE_FOR_UPDATE:
+ inspected = "HA_EXTRA_PREPARE_FOR_UPDATE";
+ break;
+ case HA_EXTRA_PRELOAD_BUFFER_SIZE:
+ inspected = "HA_EXTRA_PRELOAD_BUFFER_SIZE";
+ break;
+ case HA_EXTRA_CHANGE_KEY_TO_UNIQUE:
+ inspected = "HA_EXTRA_CHANGE_KEY_TO_UNIQUE";
+ break;
+ case HA_EXTRA_CHANGE_KEY_TO_DUP:
+ inspected = "HA_EXTRA_CHANGE_KEY_TO_DUP";
+ break;
+ case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
+ inspected = "HA_EXTRA_KEYREAD_PRESERVE_FIELDS";
+ break;
+ case HA_EXTRA_MMAP:
+ inspected = "HA_EXTRA_MMAP";
+ break;
+ case HA_EXTRA_IGNORE_NO_KEY:
+ inspected = "HA_EXTRA_IGNORE_NO_KEY";
+ break;
+ case HA_EXTRA_NO_IGNORE_NO_KEY:
+ inspected = "HA_EXTRA_NO_IGNORE_NO_KEY";
+ break;
+ case HA_EXTRA_MARK_AS_LOG_TABLE:
+ inspected = "HA_EXTRA_MARK_AS_LOG_TABLE";
+ break;
+ case HA_EXTRA_WRITE_CAN_REPLACE:
+ inspected = "HA_EXTRA_WRITE_CAN_REPLACE";
+ break;
+ case HA_EXTRA_WRITE_CANNOT_REPLACE:
+ inspected = "HA_EXTRA_WRITE_CANNOT_REPLACE";
+ break;
+ case HA_EXTRA_DELETE_CANNOT_BATCH:
+ inspected = "HA_EXTRA_DELETE_CANNOT_BATCH";
+ break;
+ case HA_EXTRA_UPDATE_CANNOT_BATCH:
+ inspected = "HA_EXTRA_UPDATE_CANNOT_BATCH";
+ break;
+ case HA_EXTRA_INSERT_WITH_UPDATE:
+ inspected = "HA_EXTRA_INSERT_WITH_UPDATE";
+ break;
+ case HA_EXTRA_PREPARE_FOR_RENAME:
+ inspected = "HA_EXTRA_PREPARE_FOR_RENAME";
+ break;
+ case HA_EXTRA_ADD_CHILDREN_LIST:
+ inspected = "HA_EXTRA_ADD_CHILDREN_LIST";
+ break;
+ case HA_EXTRA_ATTACH_CHILDREN:
+ inspected = "HA_EXTRA_ATTACH_CHILDREN";
+ break;
+ case HA_EXTRA_IS_ATTACHED_CHILDREN:
+ inspected = "HA_EXTRA_IS_ATTACHED_CHILDREN";
+ break;
+ case HA_EXTRA_DETACH_CHILDREN:
+ inspected = "HA_EXTRA_DETACH_CHILDREN";
+ break;
+ case HA_EXTRA_STARTING_ORDERED_INDEX_SCAN:
+ inspected = "HA_EXTRA_STARTING_ORDERED_INDEX_SCAN";
+ break;
+ case HA_EXTRA_BEGIN_ALTER_COPY:
+ inspected = "HA_EXTRA_BEGIN_ALTER_COPY";
+ break;
+ case HA_EXTRA_END_ALTER_COPY:
+ inspected = "HA_EXTRA_END_ALTER_COPY";
+ break;
+#ifdef MRN_HAVE_HA_EXTRA_EXPORT
+ case HA_EXTRA_EXPORT:
+ inspected = "HA_EXTRA_EXPORT";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_SECONDARY_SORT_ROWID
+ case HA_EXTRA_SECONDARY_SORT_ROWID:
+ inspected = "HA_EXTRA_SECONDARY_SORT_ROWID";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_DETACH_CHILD
+ case HA_EXTRA_DETACH_CHILD:
+ inspected = "HA_EXTRA_DETACH_CHILD";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
+ case HA_EXTRA_PREPARE_FOR_FORCED_CLOSE:
+ inspected = "HA_EXTRA_PREPARE_FOR_FORCED_CLOSE";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW
+ case HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW:
+ inspected = "HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_BEGIN_ALTER_COPY
+ case HA_EXTRA_BEGIN_ALTER_COPY:
+ inspected = "HA_EXTRA_BEGIN_ALTER_COPY";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_END_ALTER_COPY
+ case HA_EXTRA_END_ALTER_COPY:
+ inspected = "HA_EXTRA_END_ALTER_COPY";
+ break;
+#endif
+#ifdef MRN_HAVE_HA_EXTRA_NO_AUTOINC_LOCKING
+ case HA_EXTRA_NO_AUTOINC_LOCKING:
+ inspected = "HA_EXTRA_NO_AUTOINC_LOCKING";
+ break;
+#endif
+ case HA_EXTRA_IGNORE_INSERT:
+ inspected = "HA_EXTRA_IGNORE_INSERT";
+ break;
+ }
+ return inspected;
+}
+#endif
+
+static uchar *mrn_open_tables_get_key(const uchar *record,
+ size_t *length,
+ my_bool not_used __attribute__ ((unused)))
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ MRN_SHARE *share = reinterpret_cast<MRN_SHARE *>(const_cast<uchar *>(record));
+ *length = share->table_name_length;
+ DBUG_RETURN(reinterpret_cast<uchar *>(share->table_name));
+}
+
+static uchar *mrn_long_term_share_get_key(const uchar *record,
+ size_t *length,
+ my_bool not_used __attribute__ ((unused)))
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ MRN_LONG_TERM_SHARE *long_term_share =
+ reinterpret_cast<MRN_LONG_TERM_SHARE *>(const_cast<uchar *>(record));
+ *length = long_term_share->table_name_length;
+ DBUG_RETURN(reinterpret_cast<uchar *>(long_term_share->table_name));
+}
+
+/* status */
+static long mrn_count_skip = 0;
+static long mrn_fast_order_limit = 0;
+
+/* logging */
+static char *mrn_log_file_path = NULL;
+static FILE *mrn_log_file = NULL;
+static bool mrn_log_file_opened = false;
+static grn_log_level mrn_log_level_default = GRN_LOG_DEFAULT_LEVEL;
+static ulong mrn_log_level = mrn_log_level_default;
+static char *mrn_query_log_file_path = NULL;
+
+char *mrn_default_tokenizer = NULL;
+char *mrn_default_wrapper_engine = NULL;
+static int mrn_lock_timeout = grn_get_lock_timeout();
+static char *mrn_libgroonga_version = const_cast<char *>(grn_get_version());
+static char *mrn_version = const_cast<char *>(MRN_VERSION);
+static char *mrn_vector_column_delimiter = NULL;
+static mrn_bool mrn_libgroonga_support_zlib = false;
+static mrn_bool mrn_libgroonga_support_lz4 = false;
+static mrn_bool mrn_libgroonga_support_zstd = false;
+static mrn_bool mrn_enable_operations_recording = true;
+#ifdef MRN_SUPPORT_THDVAR_SET
+static const char *mrn_boolean_mode_sytnax_flag_names[] = {
+ "DEFAULT",
+ "SYNTAX_QUERY",
+ "SYNTAX_SCRIPT",
+ "ALLOW_COLUMN",
+ "ALLOW_UPDATE",
+ "ALLOW_LEADING_NOT",
+ NullS
+};
+static TYPELIB mrn_boolean_mode_syntax_flags_typelib = {
+ array_elements(mrn_boolean_mode_sytnax_flag_names) - 1,
+ "",
+ mrn_boolean_mode_sytnax_flag_names,
+ NULL
+};
+#endif
+#ifdef MRN_GROONGA_EMBEDDED
+static mrn_bool mrn_libgroonga_embedded = true;
+#else
+static mrn_bool mrn_libgroonga_embedded = false;
+#endif
+
+static mrn::variables::ActionOnError mrn_action_on_fulltext_query_error_default =
+ mrn::variables::ACTION_ON_ERROR_ERROR_AND_LOG;
+
+static void mrn_logger_log(grn_ctx *ctx, grn_log_level level,
+ const char *timestamp, const char *title,
+ const char *message, const char *location,
+ void *user_data)
+{
+ const char level_marks[] = " EACewnid-";
+ if (mrn_log_file_opened) {
+ mrn::Lock lock(&mrn_log_mutex);
+ fprintf(mrn_log_file,
+ "%s|%c|%08x|%s\n",
+ timestamp,
+ level_marks[level],
+ static_cast<uint>((ulong)(pthread_self())),
+ message);
+ fflush(mrn_log_file);
+ }
+}
+
+static grn_logger mrn_logger = {
+ mrn_log_level_default,
+ GRN_LOG_TIME|GRN_LOG_MESSAGE,
+ NULL,
+ mrn_logger_log,
+ NULL,
+ NULL
+};
+
+static uchar *mrn_allocated_thds_get_key(const uchar *record,
+ size_t *length,
+ my_bool not_used __attribute__ ((unused)))
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ *length = sizeof(THD *);
+ DBUG_RETURN(const_cast<uchar *>(record));
+}
+
+/* system functions */
+
+static struct st_mysql_storage_engine storage_engine_structure =
+{ MYSQL_HANDLERTON_INTERFACE_VERSION };
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_STATUS_VARIABLE_ENTRY(name, value, type, scope) \
+ {name, value, type, scope}
+#else
+# define MRN_STATUS_VARIABLE_ENTRY(name, value, type, scope) \
+ {name, value, type}
+#endif
+
+static struct st_mysql_show_var mrn_status_variables[] =
+{
+ MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_count_skip",
+ (char *)&mrn_count_skip,
+ SHOW_LONG,
+ SHOW_SCOPE_GLOBAL),
+ MRN_STATUS_VARIABLE_ENTRY(MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_fast_order_limit",
+ (char *)&mrn_fast_order_limit,
+ SHOW_LONG,
+ SHOW_SCOPE_GLOBAL),
+ MRN_STATUS_VARIABLE_ENTRY(NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL)
+};
+
+static const char *mrn_log_level_type_names[] = {
+ "NONE",
+ "EMERG",
+ "ALERT",
+ "CRIT",
+ "ERROR",
+ "WARNING",
+ "NOTICE",
+ "INFO",
+ "DEBUG",
+ "DUMP",
+ NullS
+};
+static TYPELIB mrn_log_level_typelib = {
+ array_elements(mrn_log_level_type_names) - 1,
+ "mrn_log_level_typelib",
+ mrn_log_level_type_names,
+ NULL
+};
+
+static void mrn_log_level_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulong new_value = *static_cast<const ulong *>(save);
+ ulong old_value = mrn_log_level;
+ mrn_log_level = new_value;
+ mrn_logger.max_level = static_cast<grn_log_level>(mrn_log_level);
+ grn_logger_set(&mrn_ctx, &mrn_logger);
+ grn_ctx *ctx = grn_ctx_open(0);
+ mrn_change_encoding(ctx, system_charset_info);
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "log level changed from '%s' to '%s'",
+ mrn_log_level_type_names[old_value],
+ mrn_log_level_type_names[new_value]);
+ grn_ctx_fin(ctx);
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_ENUM(log_level, mrn_log_level,
+ PLUGIN_VAR_RQCMDARG,
+ "logging level",
+ NULL,
+ mrn_log_level_update,
+ static_cast<ulong>(mrn_log_level),
+ &mrn_log_level_typelib);
+
+static void mrn_log_file_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const char *new_value = *((const char **)save);
+ char **old_value_ptr = (char **)var_ptr;
+
+ grn_ctx *ctx = &mrn_ctx;
+ mrn_change_encoding(ctx, system_charset_info);
+
+ const char *new_log_file_name;
+ new_log_file_name = *old_value_ptr;
+
+ if (strcmp(*old_value_ptr, new_value) == 0) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "log file isn't changed "
+ "because the requested path isn't different: <%s>",
+ new_value);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "log file is changed: <%s> -> <%s>",
+ *old_value_ptr, new_value);
+
+ int log_file_open_errno = 0;
+ {
+ mrn::Lock lock(&mrn_log_mutex);
+ FILE *new_log_file;
+ new_log_file = fopen(new_value, "a");
+ if (new_log_file) {
+ if (mrn_log_file_opened) {
+ fclose(mrn_log_file);
+ }
+ mrn_log_file = new_log_file;
+ mrn_log_file_opened = true;
+ } else {
+ log_file_open_errno = errno;
+ }
+ }
+
+ if (log_file_open_errno == 0) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "log file is changed: <%s> -> <%s>",
+ *old_value_ptr, new_value);
+ new_log_file_name = new_value;
+ } else {
+ if (mrn_log_file) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "log file isn't changed "
+ "because the requested path can't be opened: <%s>: <%s>",
+ new_value, strerror(log_file_open_errno));
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "log file can't be opened: <%s>: <%s>",
+ new_value, strerror(log_file_open_errno));
+ }
+ }
+ }
+
+#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+ char *old_log_file_name = *old_value_ptr;
+ *old_value_ptr = mrn_my_strdup(new_log_file_name, MYF(MY_WME));
+ my_free(old_log_file_name);
+#else
+ *old_value_ptr = mrn_my_strdup(new_log_file_name, MYF(MY_WME));
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_STR(log_file, mrn_log_file_path,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "log file for " MRN_PLUGIN_NAME_STRING,
+ NULL,
+ mrn_log_file_update,
+ MRN_LOG_FILE_PATH);
+
+static void mrn_query_log_file_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const char *new_value = *((const char **)save);
+ char **old_value_ptr = (char **)var_ptr;
+ const char *normalized_new_value = NULL;
+
+ grn_ctx *ctx = &mrn_ctx;
+ mrn_change_encoding(ctx, system_charset_info);
+
+ const char *new_query_log_file_name;
+ new_query_log_file_name = *old_value_ptr;
+
+ bool need_update = false;
+ if (!*old_value_ptr) {
+ if (new_value && new_value[0] != '\0') {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "query log is enabled: <%s>",
+ new_value);
+ need_update = true;
+ normalized_new_value = new_value;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "query log file is still disabled");
+ }
+ } else {
+ if (!new_value || new_value[0] == '\0') {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "query log file is disabled: <%s>",
+ *old_value_ptr);
+ need_update = true;
+ normalized_new_value = NULL;
+ } else if (strcmp(*old_value_ptr, new_value) == 0) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "query log file isn't changed "
+ "because the requested path isn't different: <%s>",
+ new_value);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "query log file is changed: <%s> -> <%s>",
+ *old_value_ptr, new_value);
+ need_update = true;
+ normalized_new_value = new_value;
+ }
+ }
+
+ if (need_update) {
+ { // TODO: Remove me when Groonga 7.0.5 is released.
+ mrn::Lock lock(&mrn_query_log_mutex);
+ grn_default_query_logger_set_path(normalized_new_value);
+ }
+ grn_query_logger_reopen(ctx);
+ new_query_log_file_name = normalized_new_value;
+ }
+
+#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+ char *old_query_log_file_name = *old_value_ptr;
+#endif
+ if (new_query_log_file_name) {
+ *old_value_ptr = mrn_my_strdup(new_query_log_file_name, MYF(0));
+ } else {
+ *old_value_ptr = NULL;
+ }
+#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+ my_free(old_query_log_file_name);
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_STR(query_log_file, mrn_query_log_file_path,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "query log file for " MRN_PLUGIN_NAME_STRING,
+ NULL,
+ mrn_query_log_file_update,
+ NULL);
+
+static void mrn_default_tokenizer_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const char *new_value = *((const char **)save);
+ char **old_value_ptr = (char **)var_ptr;
+ grn_ctx *ctx = &mrn_ctx;
+
+ mrn_change_encoding(ctx, system_charset_info);
+ if (strcmp(*old_value_ptr, new_value) == 0) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "default tokenizer for fulltext index isn't changed "
+ "because the requested default tokenizer isn't different: <%s>",
+ new_value);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "default tokenizer for fulltext index is changed: <%s> -> <%s>",
+ *old_value_ptr, new_value);
+ }
+
+#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+ my_free(*old_value_ptr);
+ *old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
+#else
+ *old_value_ptr = (char *)new_value;
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_STR(default_parser, mrn_default_tokenizer,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "default fulltext parser "
+ "(Deprecated. Use mroonga_default_tokenizer instead.)",
+ NULL,
+ mrn_default_tokenizer_update,
+ MRN_DEFAULT_TOKENIZER); // since 10.1.6
+
+static MYSQL_SYSVAR_STR(default_tokenizer, mrn_default_tokenizer,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "default tokenizer for fulltext index",
+ NULL,
+ mrn_default_tokenizer_update,
+ MRN_DEFAULT_TOKENIZER);
+
+static MYSQL_THDVAR_BOOL(
+ dry_write, /* name */
+ PLUGIN_VAR_OPCMDARG, /* options */
+ "If dry_write is true, any write operations are ignored.", /* comment */
+ NULL, /* check */
+ NULL, /* update */
+ false /* default */
+);
+
+static MYSQL_THDVAR_BOOL(
+ enable_optimization, /* name */
+ PLUGIN_VAR_OPCMDARG, /* options */
+ "If enable_optimization is true, some optimizations will be applied.", /* comment */
+ NULL, /* check */
+ NULL, /* update */
+ true /* default */
+);
+
+static MYSQL_THDVAR_LONGLONG(match_escalation_threshold,
+ PLUGIN_VAR_RQCMDARG,
+ "The threshold to determin whether search method is escalated",
+ NULL,
+ NULL,
+ grn_get_default_match_escalation_threshold(),
+ -1,
+ INT_MAX64,
+ 0);
+
+static void mrn_vector_column_delimiter_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const char *new_value = *((const char **)save);
+ char **old_value_ptr = (char **)var_ptr;
+
+#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+ my_free(*old_value_ptr);
+ *old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
+#else
+ *old_value_ptr = (char *)new_value;
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_STR(vector_column_delimiter, mrn_vector_column_delimiter,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "The vector column delimiter",
+ NULL,
+ &mrn_vector_column_delimiter_update,
+ " ");
+
+static void mrn_database_path_prefix_update(THD *thd,
+ struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const char *new_value = *((const char **)save);
+ char **old_value_ptr = (char **)var_ptr;
+#ifdef MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+ if (*old_value_ptr)
+ my_free(*old_value_ptr);
+ if (new_value)
+ *old_value_ptr = mrn_my_strdup(new_value, MYF(MY_WME));
+ else
+ *old_value_ptr = NULL;
+#else
+ *old_value_ptr = (char *)new_value;
+#endif
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_STR(database_path_prefix,
+ mrn::PathMapper::default_path_prefix,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC,
+ "The database path prefix",
+ NULL,
+ &mrn_database_path_prefix_update,
+ NULL);
+
+static MYSQL_SYSVAR_STR(default_wrapper_engine, mrn_default_wrapper_engine,
+ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
+ "The default engine for wrapper mode",
+ NULL,
+ NULL,
+ NULL);
+
+static const char *mrn_action_on_error_names[] = {
+ "ERROR",
+ "ERROR_AND_LOG",
+ "IGNORE",
+ "IGNORE_AND_LOG",
+ NullS,
+};
+
+static TYPELIB mrn_action_on_error_typelib =
+{
+ array_elements(mrn_action_on_error_names) - 1,
+ "mrn_action_on_error_typelib",
+ mrn_action_on_error_names,
+ NULL
+};
+
+static MYSQL_THDVAR_ENUM(action_on_fulltext_query_error,
+ PLUGIN_VAR_RQCMDARG,
+ "action on fulltext query error",
+ NULL,
+ NULL,
+ mrn_action_on_fulltext_query_error_default,
+ &mrn_action_on_error_typelib);
+
+static void mrn_lock_timeout_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const int new_value = *static_cast<const int *>(save);
+ int *old_value_ptr = static_cast<int *>(var_ptr);
+
+ *old_value_ptr = new_value;
+ grn_set_lock_timeout(new_value);
+
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_INT(lock_timeout,
+ mrn_lock_timeout,
+ PLUGIN_VAR_RQCMDARG,
+ "lock timeout used in Groonga",
+ NULL,
+ mrn_lock_timeout_update,
+ grn_get_lock_timeout(),
+ -1,
+ INT_MAX,
+ 1);
+
+static MYSQL_SYSVAR_STR(libgroonga_version, mrn_libgroonga_version,
+ PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
+ "The version of libgroonga",
+ NULL,
+ NULL,
+ grn_get_version());
+
+static MYSQL_SYSVAR_STR(version, mrn_version,
+ PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_READONLY,
+ "The version of mroonga",
+ NULL,
+ NULL,
+ MRN_VERSION);
+
+static mrn_bool grn_check_zlib_support()
+{
+ bool is_zlib_support = false;
+ grn_obj grn_support_p;
+
+ GRN_BOOL_INIT(&grn_support_p, 0);
+ grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_ZLIB, &grn_support_p);
+ is_zlib_support = (GRN_BOOL_VALUE(&grn_support_p));
+ grn_obj_unlink(&mrn_ctx, &grn_support_p);
+
+ return is_zlib_support;
+}
+
+static MYSQL_SYSVAR_BOOL(libgroonga_support_zlib, mrn_libgroonga_support_zlib,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "The status of libgroonga supports zlib",
+ NULL,
+ NULL,
+ grn_check_zlib_support());
+
+static mrn_bool grn_check_lz4_support()
+{
+ bool is_lz4_support = false;
+ grn_obj grn_support_p;
+
+ GRN_BOOL_INIT(&grn_support_p, 0);
+ grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_LZ4, &grn_support_p);
+ is_lz4_support = (GRN_BOOL_VALUE(&grn_support_p));
+ grn_obj_unlink(&mrn_ctx, &grn_support_p);
+
+ return is_lz4_support;
+}
+
+static MYSQL_SYSVAR_BOOL(libgroonga_support_lz4, mrn_libgroonga_support_lz4,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "The status of libgroonga supports LZ4",
+ NULL,
+ NULL,
+ grn_check_lz4_support());
+
+static mrn_bool grn_check_zstd_support()
+{
+ bool is_zstd_support = false;
+ grn_obj grn_support_p;
+
+ GRN_BOOL_INIT(&grn_support_p, 0);
+ grn_obj_get_info(&mrn_ctx, NULL, GRN_INFO_SUPPORT_ZSTD, &grn_support_p);
+ is_zstd_support = (GRN_BOOL_VALUE(&grn_support_p));
+ grn_obj_unlink(&mrn_ctx, &grn_support_p);
+
+ return is_zstd_support;
+}
+
+static MYSQL_SYSVAR_BOOL(libgroonga_support_zstd, mrn_libgroonga_support_zstd,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "The status of libgroonga supports Zstandard",
+ NULL,
+ NULL,
+ grn_check_zstd_support());
+
+static void mrn_enable_operations_recording_update(THD *thd, struct st_mysql_sys_var *var,
+ void *var_ptr, const void *save)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const bool new_value = *static_cast<const bool *>(save);
+ bool *old_value_ptr = static_cast<bool *>(var_ptr);
+
+ *old_value_ptr = new_value;
+
+ DBUG_VOID_RETURN;
+}
+
+static MYSQL_SYSVAR_BOOL(enable_operations_recording, mrn_enable_operations_recording,
+ PLUGIN_VAR_RQCMDARG,
+ "Whether recording operations for recovery is enabled or not",
+ NULL,
+ mrn_enable_operations_recording_update,
+ true);
+
+#ifdef MRN_SUPPORT_THDVAR_SET
+static MYSQL_THDVAR_SET(boolean_mode_syntax_flags,
+ PLUGIN_VAR_RQCMDARG,
+ "The flags to custom syntax in BOOLEAN MODE. "
+ "Available flags: "
+ "DEFAULT(=SYNTAX_QUERY,ALLOW_LEADING_NOT), "
+ "SYNTAX_QUERY, SYNTAX_SCRIPT, "
+ "ALLOW_COLUMN, ALLOW_UPDATE and ALLOW_LEADING_NOT",
+ NULL,
+ NULL,
+ mrn::variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT,
+ &mrn_boolean_mode_syntax_flags_typelib);
+#endif
+
+static const int MRN_MAX_N_RECORDS_FOR_ESTIMATE_DEFAULT = 1000;
+
+static MYSQL_THDVAR_INT(max_n_records_for_estimate,
+ PLUGIN_VAR_RQCMDARG,
+ "The max number of records to "
+ "estimate the number of matched records",
+ NULL,
+ NULL,
+ MRN_MAX_N_RECORDS_FOR_ESTIMATE_DEFAULT,
+ -1,
+ INT_MAX,
+ 0);
+
+static MYSQL_SYSVAR_BOOL(libgroonga_embedded, mrn_libgroonga_embedded,
+ PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
+ "Whether libgroonga is embedded or not",
+ NULL,
+ NULL,
+ mrn_libgroonga_embedded);
+
+static struct st_mysql_sys_var *mrn_system_variables[] =
+{
+ MYSQL_SYSVAR(log_level),
+ MYSQL_SYSVAR(log_file),
+ MYSQL_SYSVAR(default_parser),
+ MYSQL_SYSVAR(default_tokenizer),
+ MYSQL_SYSVAR(dry_write),
+ MYSQL_SYSVAR(enable_optimization),
+ MYSQL_SYSVAR(match_escalation_threshold),
+ MYSQL_SYSVAR(database_path_prefix),
+ MYSQL_SYSVAR(default_wrapper_engine),
+ MYSQL_SYSVAR(action_on_fulltext_query_error),
+ MYSQL_SYSVAR(lock_timeout),
+ MYSQL_SYSVAR(libgroonga_version),
+ MYSQL_SYSVAR(version),
+ MYSQL_SYSVAR(vector_column_delimiter),
+ MYSQL_SYSVAR(libgroonga_support_zlib),
+ MYSQL_SYSVAR(libgroonga_support_lz4),
+ MYSQL_SYSVAR(libgroonga_support_zstd),
+#ifdef MRN_SUPPORT_THDVAR_SET
+ MYSQL_SYSVAR(boolean_mode_syntax_flags),
+#endif
+ MYSQL_SYSVAR(max_n_records_for_estimate),
+ MYSQL_SYSVAR(libgroonga_embedded),
+ MYSQL_SYSVAR(query_log_file),
+ MYSQL_SYSVAR(enable_operations_recording),
+ NULL
+};
+
+/* mroonga information schema */
+static struct st_mysql_information_schema i_s_info =
+{
+ MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION
+};
+
+namespace Show {
+static ST_FIELD_INFO i_s_mrn_stats_fields_info[] =
+{
+ Column("VERSION", Varchar(40), NOT_NULL),
+ Column("rows_written", SLong(), NOT_NULL, "Rows written to Groonga"),
+ Column("rows_read", SLong(), NOT_NULL, "Rows read from Groonga"),
+ CEnd()
+};
+} // namespace Show
+
+static int i_s_mrn_stats_deinit(void* p)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_RETURN(0);
+}
+
+static int i_s_mrn_stats_fill(
+ THD* thd, TABLE_LIST* tables, Item* cond)
+{
+ TABLE* table = (TABLE *) tables->table;
+ int status = 0;
+ MRN_DBUG_ENTER_FUNCTION();
+ table->field[0]->store(grn_get_version(), strlen(grn_get_version()),
+ system_charset_info);
+ table->field[0]->set_notnull();
+ table->field[1]->store(1); /* TODO */
+ table->field[2]->store(2); /* TODO */
+ if (schema_table_store_record(thd, table)) {
+ status = 1;
+ }
+ DBUG_RETURN(status);
+}
+
+static int i_s_mrn_stats_init(void* p)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
+ schema->fields_info = Show::i_s_mrn_stats_fields_info;
+ schema->fill_table = i_s_mrn_stats_fill;
+ DBUG_RETURN(0);
+}
+
+struct st_mysql_plugin i_s_mrn_stats =
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &i_s_info,
+ MRN_STATUS_VARIABLE_NAME_PREFIX_STRING "_stats",
+ MRN_PLUGIN_AUTHOR,
+ "Statistics for " MRN_PLUGIN_NAME_STRING,
+ PLUGIN_LICENSE_GPL,
+ i_s_mrn_stats_init,
+#ifdef MRN_ST_MYSQL_PLUGIN_HAVE_CHECK_UNINSTALL
+ NULL,
+#endif
+ i_s_mrn_stats_deinit,
+ MRN_VERSION_IN_HEX,
+ NULL,
+ NULL,
+ MRN_PLUGIN_LAST_VALUES
+};
+/* End of mroonga information schema implementations */
+
+static handler *mrn_handler_create(handlerton *hton,
+ TABLE_SHARE *share,
+#ifdef MRN_HANDLERTON_CREATE_HAVE_PARTITIONED
+ bool partitioned,
+#endif
+ MEM_ROOT *root)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ handler *new_handler = new (root) ha_mroonga(hton, share);
+ DBUG_RETURN(new_handler);
+}
+
+static void mrn_drop_database(handlerton *hton, char *path)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ mrn_db_manager->drop(path);
+ DBUG_VOID_RETURN;
+}
+
+static int mrn_close_connection(handlerton *hton, THD *thd)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ void *p = thd_get_ha_data(thd, mrn_hton_ptr);
+ if (p) {
+ mrn_clear_slot_data(thd);
+ free(p);
+ {
+ mrn::Lock lock(&mrn_allocated_thds_mutex);
+ my_hash_delete(&mrn_allocated_thds, (uchar*) thd);
+ }
+ }
+ DBUG_RETURN(0);
+}
+
+#ifdef MRN_FLUSH_LOGS_HAVE_BINLOG_GROUP_FLUSH
+static bool mrn_flush_logs(handlerton *hton, bool binlog_group_flush)
+#else
+static bool mrn_flush_logs(handlerton *hton)
+#endif
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ bool result = 0;
+ if (mrn_log_file_opened) {
+ mrn::Lock lock(&mrn_log_mutex);
+ fclose(mrn_log_file);
+ mrn_log_file = fopen(mrn_log_file_path, "a");
+ }
+ DBUG_RETURN(result);
+}
+
+static grn_builtin_type mrn_grn_type_from_field(grn_ctx *ctx, Field *field,
+ bool for_index_key)
+{
+ grn_builtin_type type = GRN_DB_VOID;
+ enum_field_types mysql_field_type = field->real_type();
+ switch (mysql_field_type) {
+ case MYSQL_TYPE_DECIMAL: // DECIMAL; <= 65bytes
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ break;
+ case MYSQL_TYPE_TINY: // TINYINT; 1byte
+ if (static_cast<Field_num *>(field)->unsigned_flag) {
+ type = GRN_DB_UINT8; // 1byte
+ } else {
+ type = GRN_DB_INT8; // 1byte
+ }
+ break;
+ case MYSQL_TYPE_SHORT: // SMALLINT; 2bytes
+ if (static_cast<Field_num *>(field)->unsigned_flag) {
+ type = GRN_DB_UINT16; // 2bytes
+ } else {
+ type = GRN_DB_INT16; // 2bytes
+ }
+ break;
+ case MYSQL_TYPE_LONG: // INT; 4bytes
+ if (static_cast<Field_num *>(field)->unsigned_flag) {
+ type = GRN_DB_UINT32; // 4bytes
+ } else {
+ type = GRN_DB_INT32; // 4bytes
+ }
+ break;
+ case MYSQL_TYPE_FLOAT: // FLOAT; 4 or 8bytes
+ case MYSQL_TYPE_DOUBLE: // DOUBLE; 8bytes
+ type = GRN_DB_FLOAT; // 8bytes
+ break;
+ case MYSQL_TYPE_NULL: // NULL; 1byte
+ type = GRN_DB_INT8; // 1byte
+ break;
+ case MYSQL_TYPE_TIMESTAMP: // TIMESTAMP; 4bytes
+ type = GRN_DB_TIME; // 8bytes
+ break;
+ case MYSQL_TYPE_LONGLONG: // BIGINT; 8bytes
+ if (static_cast<Field_num *>(field)->unsigned_flag) {
+ type = GRN_DB_UINT64; // 8bytes
+ } else {
+ type = GRN_DB_INT64; // 8bytes
+ }
+ break;
+ case MYSQL_TYPE_INT24: // MEDIUMINT; 3bytes
+ if (static_cast<Field_num *>(field)->unsigned_flag) {
+ type = GRN_DB_UINT32; // 4bytes
+ } else {
+ type = GRN_DB_INT32; // 4bytes
+ }
+ break;
+ case MYSQL_TYPE_DATE: // DATE; 4bytes
+ case MYSQL_TYPE_TIME: // TIME; 3bytes
+ case MYSQL_TYPE_DATETIME: // DATETIME; 8bytes
+ case MYSQL_TYPE_YEAR: // YEAR; 1byte
+ case MYSQL_TYPE_NEWDATE: // DATE; 3bytes
+ type = GRN_DB_TIME; // 8bytes
+ break;
+ case MYSQL_TYPE_VARCHAR: // VARCHAR; <= 64KB * 4 + 2bytes
+ if (for_index_key) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else {
+ if (field->field_length <= MRN_SHORT_TEXT_SIZE) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else if (field->field_length <= MRN_TEXT_SIZE) {
+ type = GRN_DB_TEXT; // 64Kbytes
+ } else {
+ type = GRN_DB_LONG_TEXT; // 2Gbytes
+ }
+ }
+ break;
+ case MYSQL_TYPE_BIT: // BIT; <= 8bytes
+ type = GRN_DB_INT64; // 8bytes
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ case MYSQL_TYPE_TIMESTAMP2: // TIMESTAMP; 4bytes
+ type = GRN_DB_TIME; // 8bytes
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case MYSQL_TYPE_DATETIME2: // DATETIME; 8bytes
+ type = GRN_DB_TIME; // 8bytes
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ case MYSQL_TYPE_TIME2: // TIME(FSP); 3 + (FSP + 1) / 2 bytes
+ // 0 <= FSP <= 6; 3-6bytes
+ type = GRN_DB_TIME; // 8bytes
+ break;
+#endif
+ case MYSQL_TYPE_NEWDECIMAL: // DECIMAL; <= 9bytes
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ break;
+ case MYSQL_TYPE_ENUM: // ENUM; <= 2bytes
+ if (field->pack_length() == 1) {
+ type = GRN_DB_UINT8; // 1bytes
+ } else {
+ type = GRN_DB_UINT16; // 2bytes
+ }
+ break;
+ case MYSQL_TYPE_SET: // SET; <= 8bytes
+ switch (field->pack_length()) {
+ case 1:
+ type = GRN_DB_UINT8; // 1byte
+ break;
+ case 2:
+ type = GRN_DB_UINT16; // 2bytes
+ break;
+ case 3:
+ case 4:
+ type = GRN_DB_UINT32; // 3bytes
+ break;
+ case 8:
+ default:
+ type = GRN_DB_UINT64; // 8bytes
+ break;
+ }
+ break;
+ case MYSQL_TYPE_TINY_BLOB: // TINYBLOB; <= 256bytes + 1byte
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ break;
+ case MYSQL_TYPE_MEDIUM_BLOB: // MEDIUMBLOB; <= 16Mbytes + 3bytes
+ if (for_index_key) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else {
+ type = GRN_DB_LONG_TEXT; // 2Gbytes
+ }
+ break;
+ case MYSQL_TYPE_LONG_BLOB: // LONGBLOB; <= 4Gbytes + 4bytes
+ if (for_index_key) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else {
+ type = GRN_DB_LONG_TEXT; // 2Gbytes
+ }
+ break;
+ case MYSQL_TYPE_BLOB: // BLOB; <= 64Kbytes + 2bytes
+ if (for_index_key) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else {
+ type = GRN_DB_LONG_TEXT; // 2Gbytes
+ }
+ break;
+ case MYSQL_TYPE_VAR_STRING: // VARCHAR; <= 255byte * 4 + 1bytes
+ if (for_index_key) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else {
+ if (field->field_length <= MRN_SHORT_TEXT_SIZE) {
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ } else if (field->field_length <= MRN_TEXT_SIZE) {
+ type = GRN_DB_TEXT; // 64Kbytes
+ } else {
+ type = GRN_DB_LONG_TEXT; // 2Gbytes
+ }
+ }
+ break;
+ case MYSQL_TYPE_STRING: // CHAR; < 1Kbytes =~ (255 * 4)bytes
+ // 4 is the maximum size of a character
+ type = GRN_DB_SHORT_TEXT; // 4Kbytes
+ break;
+ case MYSQL_TYPE_GEOMETRY: // case-by-case
+ type = GRN_DB_WGS84_GEO_POINT; // 8bytes
+ break;
+ case MYSQL_TYPE_VARCHAR_COMPRESSED:
+ case MYSQL_TYPE_BLOB_COMPRESSED:
+ DBUG_ASSERT(0);
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ case MYSQL_TYPE_JSON:
+ type = GRN_DB_TEXT;
+ break;
+#endif
+ }
+ return type;
+}
+
+static bool mrn_parse_grn_column_create_flags(THD *thd,
+ grn_ctx *ctx,
+ const char *flag_names,
+ uint flag_names_length,
+ grn_obj_flags *column_flags)
+{
+ const char *flag_names_end = flag_names + flag_names_length;
+ bool found = false;
+
+ while (flag_names < flag_names_end) {
+ uint rest_length = flag_names_end - flag_names;
+
+ if (*flag_names == '|' || *flag_names == ' ') {
+ flag_names += 1;
+ continue;
+ }
+ if (rest_length >= 13 && !memcmp(flag_names, "COLUMN_SCALAR", 13)) {
+ *column_flags |= GRN_OBJ_COLUMN_SCALAR;
+ flag_names += 13;
+ found = true;
+ } else if (rest_length >= 13 && !memcmp(flag_names, "COLUMN_VECTOR", 13)) {
+ *column_flags |= GRN_OBJ_COLUMN_VECTOR;
+ flag_names += 13;
+ found = true;
+ } else if (rest_length >= 13 && !memcmp(flag_names, "COMPRESS_ZLIB", 13)) {
+ if (mrn_libgroonga_support_zlib) {
+ *column_flags |= GRN_OBJ_COMPRESS_ZLIB;
+ found = true;
+ } else {
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
+ ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
+ "COMPRESS_ZLIB");
+ }
+ flag_names += 13;
+ } else if (rest_length >= 12 && !memcmp(flag_names, "COMPRESS_LZ4", 12)) {
+ if (mrn_libgroonga_support_lz4) {
+ *column_flags |= GRN_OBJ_COMPRESS_LZ4;
+ found = true;
+ } else {
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
+ ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
+ "COMPRESS_LZ4");
+ }
+ flag_names += 12;
+ } else if (rest_length >= 13 && !memcmp(flag_names, "COMPRESS_ZSTD", 13)) {
+ if (mrn_libgroonga_support_zstd) {
+ *column_flags |= GRN_OBJ_COMPRESS_ZSTD;
+ found = true;
+ } else {
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM,
+ ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR,
+ "COMPRESS_ZSTD");
+ }
+ flag_names += 13;
+ } else {
+ char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
+ "%.*s",
+ static_cast<int>(rest_length),
+ flag_names);
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ ER_MRN_INVALID_COLUMN_FLAG_NUM,
+ ER_MRN_INVALID_COLUMN_FLAG_STR,
+ invalid_flag_name);
+ break;
+ }
+ }
+ return found;
+}
+
+static bool mrn_parse_grn_index_column_flags(THD *thd,
+ grn_ctx *ctx,
+ const char *flag_names,
+ uint flag_names_length,
+ grn_column_flags *index_column_flags)
+{
+ const char *flag_names_end = flag_names + flag_names_length;
+ bool found = false;
+
+ while (flag_names < flag_names_end) {
+ uint rest_length = flag_names_end - flag_names;
+
+ if (*flag_names == '|' || *flag_names == ' ') {
+ flag_names += 1;
+ continue;
+ }
+ if (rest_length >= 4 && !memcmp(flag_names, "NONE", 4)) {
+ flag_names += 4;
+ found = true;
+ } else if (rest_length >= 13 && !memcmp(flag_names, "WITH_POSITION", 13)) {
+ *index_column_flags |= GRN_OBJ_WITH_POSITION;
+ flag_names += 13;
+ found = true;
+ } else if (rest_length >= 12 && !memcmp(flag_names, "WITH_SECTION", 12)) {
+ *index_column_flags |= GRN_OBJ_WITH_SECTION;
+ flag_names += 12;
+ found = true;
+ } else if (rest_length >= 11 && !memcmp(flag_names, "WITH_WEIGHT", 11)) {
+ *index_column_flags |= GRN_OBJ_WITH_WEIGHT;
+ flag_names += 11;
+ found = true;
+ } else if (rest_length >= 11 && !memcmp(flag_names, "INDEX_SMALL", 11)) {
+ *index_column_flags |= GRN_OBJ_INDEX_SMALL;
+ flag_names += 11;
+ found = true;
+ } else if (rest_length >= 12 && !memcmp(flag_names, "INDEX_MEDIUM", 12)) {
+ *index_column_flags |= GRN_OBJ_INDEX_MEDIUM;
+ flag_names += 12;
+ found = true;
+ } else {
+ char invalid_flag_name[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(invalid_flag_name, MRN_MESSAGE_BUFFER_SIZE,
+ "%.*s",
+ static_cast<int>(rest_length),
+ flag_names);
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ ER_MRN_INVALID_INDEX_FLAG_NUM,
+ ER_MRN_INVALID_INDEX_FLAG_STR,
+ invalid_flag_name);
+ }
+ }
+ return found;
+}
+
+#ifdef MRN_HAVE_SPATIAL
+static int mrn_set_geometry(grn_ctx *ctx, grn_obj *buf,
+ const char *wkb, uint wkb_size)
+{
+ int error = 0;
+ Geometry_buffer buffer;
+ Geometry *geometry;
+
+ geometry = Geometry::construct(&buffer, wkb, wkb_size);
+ if (!geometry) {
+ return ER_CANT_CREATE_GEOMETRY_OBJECT;
+ }
+ switch (geometry->get_class_info()->m_type_id) {
+ case Geometry::wkb_point:
+ {
+ Gis_point *point = (Gis_point *)geometry;
+ double latitude = 0.0, longitude = 0.0;
+#ifdef MRN_HAVE_POINT_XY
+ point_xy xy(0.0, 0.0);
+ point->get_xy(&xy);
+ longitude = xy.x;
+ latitude = xy.y;
+#else
+ point->get_xy(&longitude, &latitude);
+#endif
+ grn_obj_reinit(ctx, buf, GRN_DB_WGS84_GEO_POINT, 0);
+ GRN_GEO_POINT_SET(ctx, buf,
+ GRN_GEO_DEGREE2MSEC(latitude),
+ GRN_GEO_DEGREE2MSEC(longitude));
+ break;
+ }
+ default:
+ my_printf_error(ER_MRN_GEOMETRY_NOT_SUPPORT_NUM,
+ ER_MRN_GEOMETRY_NOT_SUPPORT_STR, MYF(0));
+ error = ER_MRN_GEOMETRY_NOT_SUPPORT_NUM;
+ break;
+ }
+ MRN_GEOMETRY_FREE(geometry);
+
+ return error;
+}
+#endif
+
+#ifdef MRN_HAVE_HTON_ALTER_TABLE_FLAGS
+static alter_table_operations mrn_alter_table_flags(alter_table_operations flags)
+{
+ ulonglong alter_flags = 0;
+#ifdef HA_INPLACE_ADD_INDEX_NO_READ_WRITE
+ bool is_inplace_index_change;
+# ifdef MRN_HAVE_ALTER_INFO
+ is_inplace_index_change = (((flags & ALTER_ADD_INDEX) &&
+ (flags & ALTER_DROP_INDEX)) ||
+ (flags & ALTER_CHANGE_COLUMN));
+# else
+ is_inplace_index_change = (((flags & ALTER_ADD_INDEX) &&
+ (flags & ALTER_DROP_INDEX)) ||
+ (flags & ALTER_CHANGE_COLUMN));
+# endif
+ if (!is_inplace_index_change) {
+ alter_flags |=
+ HA_INPLACE_ADD_INDEX_NO_READ_WRITE |
+ HA_INPLACE_DROP_INDEX_NO_READ_WRITE |
+ HA_INPLACE_ADD_UNIQUE_INDEX_NO_READ_WRITE |
+ HA_INPLACE_DROP_UNIQUE_INDEX_NO_READ_WRITE |
+ HA_INPLACE_ADD_INDEX_NO_WRITE |
+ HA_INPLACE_DROP_INDEX_NO_WRITE |
+ HA_INPLACE_ADD_UNIQUE_INDEX_NO_WRITE |
+ HA_INPLACE_DROP_UNIQUE_INDEX_NO_WRITE;
+ }
+#endif
+ return alter_flags;
+}
+#endif
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+static ha_create_table_option mrn_field_options[] =
+{
+ HA_FOPTION_STRING("GROONGA_TYPE", groonga_type),
+ HA_FOPTION_STRING("FLAGS", flags),
+ HA_FOPTION_END
+};
+
+static ha_create_table_option mrn_index_options[] =
+{
+ HA_IOPTION_STRING("TOKENIZER", tokenizer),
+ HA_IOPTION_STRING("NORMALIZER", normalizer),
+ HA_IOPTION_STRING("TOKEN_FILTERS", token_filters),
+ HA_IOPTION_STRING("FLAGS", flags),
+ HA_IOPTION_END
+};
+#endif
+
+static int mrn_init(void *p)
+{
+ // init handlerton
+ grn_ctx *ctx = NULL;
+ handlerton *hton = static_cast<handlerton *>(p);
+ hton->create = mrn_handler_create;
+ hton->flags = HTON_NO_FLAGS;
+#ifndef MRN_SUPPORT_PARTITION
+ hton->flags |= HTON_NO_PARTITION;
+#endif
+ hton->drop_database = mrn_drop_database;
+ hton->close_connection = mrn_close_connection;
+ hton->flush_logs = mrn_flush_logs;
+#ifdef MRN_HAVE_HTON_ALTER_TABLE_FLAGS
+ hton->alter_table_flags = mrn_alter_table_flags;
+#endif
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ hton->field_options = mrn_field_options;
+ hton->index_options = mrn_index_options;
+#endif
+ mrn_hton_ptr = hton;
+
+#ifdef _WIN32
+ HMODULE current_module = GetModuleHandle(NULL);
+ mrn_binlog_filter =
+ *((Rpl_filter **)GetProcAddress(current_module, MRN_BINLOG_FILTER_PROC));
+ mrn_my_tz_UTC =
+ *((Time_zone **)GetProcAddress(current_module, MRN_MY_TZ_UTC_PROC));
+# ifdef MRN_HAVE_TABLE_DEF_CACHE
+ mrn_table_def_cache = (HASH *)GetProcAddress(current_module,
+ "?table_def_cache@@3Ust_hash@@A");
+# endif
+# ifndef MRN_HAVE_TDC_LOCK_TABLE_SHARE
+ mrn_LOCK_open =
+ (mysql_mutex_t *)GetProcAddress(current_module,
+ "?LOCK_open@@3Ust_mysql_mutex@@A");
+# endif
+# ifdef HAVE_PSI_INTERFACE
+# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
+ mrn_table_share_lock_share =
+ (PSI_mutex_key *)GetProcAddress(current_module,
+ MRN_TABLE_SHARE_LOCK_SHARE_PROC);
+# endif
+ mrn_table_share_lock_ha_data =
+ (PSI_mutex_key *)GetProcAddress(current_module,
+ MRN_TABLE_SHARE_LOCK_HA_DATA_PROC);
+# endif
+#else
+ mrn_binlog_filter = binlog_filter;
+ mrn_my_tz_UTC = my_tz_UTC;
+# ifdef MRN_HAVE_TABLE_DEF_CACHE
+ mrn_table_def_cache = &table_def_cache;
+# endif
+# ifndef MRN_HAVE_TDC_LOCK_TABLE_SHARE
+ mrn_LOCK_open = &LOCK_open;
+# endif
+#endif
+
+#ifdef MRN_HAVE_PSI_SERVER
+ if (PSI_server) {
+ const char *category = "mroonga";
+ int n_mutexes = array_elements(mrn_mutexes);
+ PSI_server->register_mutex(category, mrn_mutexes, n_mutexes);
+ }
+#endif
+
+ grn_default_query_logger_set_path(mrn_query_log_file_path);
+
+ if (grn_init() != GRN_SUCCESS) {
+ goto err_grn_init;
+ }
+
+ grn_set_lock_timeout(mrn_lock_timeout);
+
+ mrn_init_encoding_map();
+
+ grn_ctx_init(&mrn_ctx, 0);
+ ctx = &mrn_ctx;
+ if (mrn_change_encoding(ctx, system_charset_info))
+ goto err_mrn_change_encoding;
+
+#ifdef MRN_HAVE_PSI_MEMORY_KEY
+ {
+ const char *category = "ha_mroonga";
+ int n_keys = array_elements(mrn_all_memory_keys);
+ mysql_memory_register(category, mrn_all_memory_keys, n_keys);
+ }
+#endif
+
+ if (mysql_mutex_init(mrn_log_mutex_key,
+ &mrn_log_mutex,
+ MY_MUTEX_INIT_FAST) != 0) {
+ goto err_log_mutex_init;
+ }
+ if (mysql_mutex_init(mrn_query_log_mutex_key,
+ &mrn_query_log_mutex,
+ MY_MUTEX_INIT_FAST) != 0) {
+ goto err_query_log_mutex_init;
+ }
+
+ mrn_logger.max_level = static_cast<grn_log_level>(mrn_log_level);
+ grn_logger_set(ctx, &mrn_logger);
+ if (!(mrn_log_file = fopen(mrn_log_file_path, "a"))) {
+ goto err_log_file_open;
+ }
+ mrn_log_file_opened = true;
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "%s started.", MRN_PACKAGE_STRING);
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "log level is '%s'",
+ mrn_log_level_type_names[mrn_log_level]);
+
+ // init meta-info database
+ if (!(mrn_db = grn_db_create(ctx, NULL, NULL))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "cannot create system database, exiting");
+ goto err_db_create;
+ }
+ grn_ctx_use(ctx, mrn_db);
+
+ grn_ctx_init(&mrn_db_manager_ctx, 0);
+ grn_logger_set(&mrn_db_manager_ctx, &mrn_logger);
+ if (mysql_mutex_init(mrn_db_manager_mutex_key,
+ &mrn_db_manager_mutex,
+ MY_MUTEX_INIT_FAST) != 0) {
+ GRN_LOG(&mrn_db_manager_ctx, GRN_LOG_ERROR,
+ "failed to initialize mutex for database manager");
+ goto err_db_manager_mutex_init;
+ }
+ mrn_db_manager = new mrn::DatabaseManager(&mrn_db_manager_ctx,
+ &mrn_db_manager_mutex);
+ if (!mrn_db_manager->init()) {
+ goto err_db_manager_init;
+ }
+
+ if (mysql_mutex_init(mrn_context_pool_mutex_key,
+ &mrn_context_pool_mutex,
+ MY_MUTEX_INIT_FAST) != 0) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "failed to initialize mutex for context pool");
+ goto error_context_pool_mutex_init;
+ }
+ mrn_context_pool = new mrn::ContextPool(&mrn_context_pool_mutex);
+
+ if (mysql_mutex_init(mrn_operations_mutex_key,
+ &mrn_operations_mutex,
+ MY_MUTEX_INIT_FAST) != 0) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "failed to initialize mutex for operations");
+ goto error_operations_mutex_init;
+ }
+
+ if ((mysql_mutex_init(mrn_allocated_thds_mutex_key,
+ &mrn_allocated_thds_mutex,
+ MY_MUTEX_INIT_FAST) != 0)) {
+ goto err_allocated_thds_mutex_init;
+ }
+ if (mrn_my_hash_init(&mrn_allocated_thds, system_charset_info, 32, 0, 0,
+ mrn_allocated_thds_get_key, 0, 0)) {
+ goto error_allocated_thds_hash_init;
+ }
+ if ((mysql_mutex_init(mrn_open_tables_mutex_key,
+ &mrn_open_tables_mutex,
+ MY_MUTEX_INIT_FAST) != 0)) {
+ goto err_allocated_open_tables_mutex_init;
+ }
+ if (mrn_my_hash_init(&mrn_open_tables, system_charset_info, 32, 0, 0,
+ mrn_open_tables_get_key, 0, 0)) {
+ goto error_allocated_open_tables_hash_init;
+ }
+ if ((mysql_mutex_init(mrn_long_term_share_mutex_key,
+ &mrn_long_term_share_mutex,
+ MY_MUTEX_INIT_FAST) != 0)) {
+ goto error_allocated_long_term_share_mutex_init;
+ }
+ if (mrn_my_hash_init(&mrn_long_term_share, system_charset_info, 32, 0, 0,
+ mrn_long_term_share_get_key, 0, 0)) {
+ goto error_allocated_long_term_share_hash_init;
+ }
+
+#ifdef MRN_USE_MYSQL_DATA_HOME
+ mrn::PathMapper::default_mysql_data_home_path = mysql_data_home;
+#endif
+
+ return 0;
+
+error_allocated_long_term_share_hash_init:
+ mysql_mutex_destroy(&mrn_long_term_share_mutex);
+error_allocated_long_term_share_mutex_init:
+ my_hash_free(&mrn_open_tables);
+error_allocated_open_tables_hash_init:
+ mysql_mutex_destroy(&mrn_open_tables_mutex);
+err_allocated_open_tables_mutex_init:
+ my_hash_free(&mrn_allocated_thds);
+error_allocated_thds_hash_init:
+ mysql_mutex_destroy(&mrn_allocated_thds_mutex);
+err_allocated_thds_mutex_init:
+ mysql_mutex_destroy(&mrn_operations_mutex);
+error_operations_mutex_init:
+ delete mrn_context_pool;
+ mysql_mutex_destroy(&mrn_context_pool_mutex);
+error_context_pool_mutex_init:
+err_db_manager_init:
+ delete mrn_db_manager;
+ mysql_mutex_destroy(&mrn_db_manager_mutex);
+err_db_manager_mutex_init:
+ grn_ctx_fin(&mrn_db_manager_ctx);
+ grn_obj_unlink(ctx, mrn_db);
+err_db_create:
+ if (mrn_log_file_opened) {
+ fclose(mrn_log_file);
+ mrn_log_file_opened = false;
+ }
+err_log_file_open:
+ mysql_mutex_destroy(&mrn_query_log_mutex);
+err_query_log_mutex_init:
+ mysql_mutex_destroy(&mrn_log_mutex);
+err_log_mutex_init:
+err_mrn_change_encoding:
+ grn_ctx_fin(ctx);
+ grn_fin();
+err_grn_init:
+ return -1;
+}
+
+static int mrn_deinit(void *p)
+{
+ THD *thd = current_thd, *tmp_thd;
+ grn_ctx *ctx = &mrn_ctx;
+ MRN_LONG_TERM_SHARE *long_term_share;
+
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "%s deinit", MRN_PACKAGE_STRING);
+
+ if (thd && thd_sql_command(thd) == SQLCOM_UNINSTALL_PLUGIN) {
+ mrn::Lock lock(&mrn_allocated_thds_mutex);
+ while ((tmp_thd = (THD *) my_hash_element(&mrn_allocated_thds, 0)))
+ {
+ mrn_clear_slot_data(tmp_thd);
+ void *slot_ptr = mrn_get_slot_data(tmp_thd, false);
+ if (slot_ptr) free(slot_ptr);
+ thd_set_ha_data(tmp_thd, mrn_hton_ptr, 0);
+ my_hash_delete(&mrn_allocated_thds, (uchar *) tmp_thd);
+ }
+ }
+
+ {
+ mrn::Lock lock(&mrn_open_tables_mutex);
+ while ((long_term_share = (MRN_LONG_TERM_SHARE *)
+ my_hash_element(&mrn_long_term_share, 0)))
+ {
+ mrn_free_long_term_share(long_term_share);
+ }
+ }
+
+ my_hash_free(&mrn_long_term_share);
+ mysql_mutex_destroy(&mrn_long_term_share_mutex);
+ my_hash_free(&mrn_open_tables);
+ mysql_mutex_destroy(&mrn_open_tables_mutex);
+ my_hash_free(&mrn_allocated_thds);
+ mysql_mutex_destroy(&mrn_allocated_thds_mutex);
+ mysql_mutex_destroy(&mrn_operations_mutex);
+ delete mrn_context_pool;
+ mysql_mutex_destroy(&mrn_context_pool_mutex);
+ delete mrn_db_manager;
+ mysql_mutex_destroy(&mrn_db_manager_mutex);
+ grn_ctx_fin(&mrn_db_manager_ctx);
+
+ grn_obj_unlink(ctx, mrn_db);
+ grn_ctx_fin(ctx);
+ grn_fin();
+
+ if (mrn_log_file_opened) {
+ fclose(mrn_log_file);
+ mrn_log_file_opened = false;
+ }
+ mysql_mutex_destroy(&mrn_query_log_mutex);
+ mysql_mutex_destroy(&mrn_log_mutex);
+
+ return 0;
+}
+
+mrn_declare_plugin(MRN_PLUGIN_NAME)
+{
+ MYSQL_STORAGE_ENGINE_PLUGIN,
+ &storage_engine_structure,
+ MRN_PLUGIN_NAME_STRING,
+ MRN_PLUGIN_AUTHOR,
+ "CJK-ready fulltext search, column store",
+ PLUGIN_LICENSE_GPL,
+ mrn_init,
+ mrn_deinit,
+ MRN_VERSION_IN_HEX,
+ mrn_status_variables,
+ mrn_system_variables,
+ MRN_PLUGIN_LAST_VALUES
+},
+i_s_mrn_stats
+mrn_declare_plugin_end;
+
+static double mrn_get_score_value(grn_obj *score)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ double score_value;
+ if (score->header.domain == GRN_DB_FLOAT) {
+ score_value = GRN_FLOAT_VALUE(score);
+ } else {
+ score_value = (double)GRN_INT32_VALUE(score);
+ }
+ DBUG_RETURN(score_value);
+}
+
+static void mrn_generic_ft_clear(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ if (!info->ctx) {
+ DBUG_VOID_RETURN;
+ }
+
+ if (info->cursor) {
+ grn_obj_unlink(info->ctx, info->cursor);
+ }
+ if (info->id_accessor) {
+ grn_obj_unlink(info->ctx, info->id_accessor);
+ }
+ if (info->key_accessor) {
+ grn_obj_unlink(info->ctx, info->key_accessor);
+ }
+ grn_obj_unlink(info->ctx, info->result);
+ grn_obj_unlink(info->ctx, info->score_column);
+ grn_obj_unlink(info->ctx, &(info->key));
+ grn_obj_unlink(info->ctx, &(info->score));
+
+ info->ctx = NULL;
+
+ DBUG_VOID_RETURN;
+}
+
+static void mrn_generic_ft_close_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ mrn_generic_ft_clear(handler);
+ delete info;
+ DBUG_VOID_RETURN;
+}
+
+static int mrn_wrapper_ft_read_next(FT_INFO *handler, char *record)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+}
+
+static float mrn_wrapper_ft_find_relevance(FT_INFO *handler, uchar *record,
+ uint length)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ float score = 0.0;
+ grn_id record_id;
+
+ mrn_change_encoding(info->ctx, NULL);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&(info->key))), record,
+ info->primary_key_info, info->primary_key_info->key_length);
+ record_id = grn_table_get(info->ctx,
+ info->table,
+ GRN_TEXT_VALUE(&(info->key)),
+ GRN_TEXT_LEN(&(info->key)));
+
+ if (record_id != GRN_ID_NIL) {
+ grn_id result_record_id;
+ result_record_id = grn_table_get(info->ctx, info->result,
+ &record_id, sizeof(grn_id));
+ if (result_record_id != GRN_ID_NIL) {
+ GRN_BULK_REWIND(&(info->score));
+ grn_obj_get_value(info->ctx, info->score_column,
+ result_record_id, &(info->score));
+ score = mrn_get_score_value(&(info->score));
+ }
+ }
+
+ DBUG_PRINT("info",
+ ("mroonga: record_id=%d score=%g", record_id, score));
+
+ DBUG_RETURN(score);
+}
+
+static void mrn_wrapper_ft_close_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ mrn_generic_ft_close_search(handler);
+ DBUG_VOID_RETURN;
+}
+
+static float mrn_wrapper_ft_get_relevance(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ float score = 0.0;
+ grn_id record_id;
+ ha_mroonga *mroonga = info->mroonga;
+ mrn_change_encoding(info->ctx, NULL);
+ record_id = grn_table_get(info->ctx,
+ info->table,
+ GRN_TEXT_VALUE(&(mroonga->key_buffer)),
+ GRN_TEXT_LEN(&(mroonga->key_buffer)));
+
+ if (record_id != GRN_ID_NIL) {
+ grn_id result_record_id;
+ result_record_id = grn_table_get(info->ctx, info->result,
+ &record_id, sizeof(grn_id));
+ if (result_record_id != GRN_ID_NIL) {
+ GRN_BULK_REWIND(&(info->score));
+ grn_obj_get_value(info->ctx, info->score_column,
+ result_record_id, &(info->score));
+ score = mrn_get_score_value(&(info->score));
+ }
+ }
+
+ DBUG_PRINT("info",
+ ("mroonga: record_id=%d score=%g", record_id, score));
+
+ DBUG_RETURN(score);
+}
+
+static void mrn_wrapper_ft_reinit_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_VOID_RETURN;
+}
+
+static _ft_vft mrn_wrapper_ft_vft = {
+ mrn_wrapper_ft_read_next,
+ mrn_wrapper_ft_find_relevance,
+ mrn_wrapper_ft_close_search,
+ mrn_wrapper_ft_get_relevance,
+ mrn_wrapper_ft_reinit_search
+};
+
+static int mrn_storage_ft_read_next(FT_INFO *handler, char *record)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+}
+
+static float mrn_storage_ft_find_relevance(FT_INFO *handler, uchar *record,
+ uint length)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ ha_mroonga *mroonga = info->mroonga;
+ mrn_change_encoding(info->ctx, NULL);
+
+ float score = 0.0;
+ if (mroonga->record_id != GRN_ID_NIL) {
+ grn_id result_record_id;
+ result_record_id = grn_table_get(info->ctx, info->result,
+ &(mroonga->record_id), sizeof(grn_id));
+ if (result_record_id != GRN_ID_NIL) {
+ GRN_BULK_REWIND(&(info->score));
+ grn_obj_get_value(info->ctx, info->score_column,
+ result_record_id, &(info->score));
+ score = mrn_get_score_value(&(info->score));
+ }
+ }
+ DBUG_PRINT("info", ("mroonga: record_id=%d score=%g",
+ mroonga->record_id, score));
+
+ DBUG_RETURN(score);
+}
+
+static void mrn_storage_ft_close_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ mrn_generic_ft_close_search(handler);
+ DBUG_VOID_RETURN;
+}
+
+static float mrn_storage_ft_get_relevance(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ ha_mroonga *mroonga = info->mroonga;
+ mrn_change_encoding(info->ctx, NULL);
+
+ float score = 0.0;
+ if (mroonga->record_id != GRN_ID_NIL) {
+ grn_id result_record_id;
+ result_record_id = grn_table_get(info->ctx, info->result,
+ &(mroonga->record_id), sizeof(grn_id));
+ if (result_record_id != GRN_ID_NIL) {
+ GRN_BULK_REWIND(&(info->score));
+ grn_obj_get_value(info->ctx, info->score_column,
+ result_record_id, &(info->score));
+ score = mrn_get_score_value(&(info->score));
+ }
+ }
+ DBUG_PRINT("info",
+ ("mroonga: record_id=%d score=%g", mroonga->record_id, score));
+
+ DBUG_RETURN(score);
+}
+
+static void mrn_storage_ft_reinit_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_VOID_RETURN;
+}
+
+static _ft_vft mrn_storage_ft_vft = {
+ mrn_storage_ft_read_next,
+ mrn_storage_ft_find_relevance,
+ mrn_storage_ft_close_search,
+ mrn_storage_ft_get_relevance,
+ mrn_storage_ft_reinit_search
+};
+
+static int mrn_no_such_key_ft_read_next(FT_INFO *handler, char *record)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+}
+
+static float mrn_no_such_key_ft_find_relevance(FT_INFO *handler, uchar *record,
+ uint length)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_RETURN(0.0);
+}
+
+static void mrn_no_such_key_ft_close_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = (st_mrn_ft_info *)handler;
+ delete info;
+ DBUG_VOID_RETURN;
+}
+
+static float mrn_no_such_key_ft_get_relevance(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_RETURN(0.0);
+}
+
+static void mrn_no_such_key_ft_reinit_search(FT_INFO *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_VOID_RETURN;
+}
+
+static _ft_vft mrn_no_such_key_ft_vft = {
+ mrn_no_such_key_ft_read_next,
+ mrn_no_such_key_ft_find_relevance,
+ mrn_no_such_key_ft_close_search,
+ mrn_no_such_key_ft_get_relevance,
+ mrn_no_such_key_ft_reinit_search
+};
+
+#ifdef HA_CAN_FULLTEXT_EXT
+static uint mrn_generic_ft_get_version()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ // This value is not used in MySQL 5.6.7-rc. So it is
+ // meaningless. It may be used in the future...
+ uint version = 1;
+ DBUG_RETURN(version);
+}
+
+static ulonglong mrn_generic_ft_ext_get_flags()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ // TODO: Should we support FTS_ORDERED_RESULT?
+ // TODO: Shuold we support FTS_DOCID_IN_RESULT?
+ ulonglong flags = 0;
+ DBUG_RETURN(flags);
+}
+
+// This function is used if we enable FTS_DOCID_IN_RESULT flag and the
+// table has "FTS_DOC_ID" (defined as FTS_DOC_ID_COL_NAME macro)
+// special name column. Should we support "FTS_DOC_ID" special name
+// column?
+// See also sql/sql_optimizer.cc:JOIN::optimize_fts_query().
+static ulonglong mrn_generic_ft_ext_get_docid(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong id = GRN_ID_NIL;
+ DBUG_RETURN(id);
+}
+
+static ulonglong mrn_generic_ft_ext_count_matches(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_ft_info *info = reinterpret_cast<st_mrn_ft_info *>(handler);
+ ulonglong n_records = grn_table_size(info->ctx, info->result);
+ DBUG_RETURN(n_records);
+}
+
+static uint mrn_wrapper_ft_ext_get_version()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ uint version = mrn_generic_ft_get_version();
+ DBUG_RETURN(version);
+}
+
+static ulonglong mrn_wrapper_ft_ext_get_flags()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong flags = mrn_generic_ft_ext_get_flags();
+ DBUG_RETURN(flags);
+}
+
+static ulonglong mrn_wrapper_ft_ext_get_docid(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong id = mrn_generic_ft_ext_get_docid(handler);
+ DBUG_RETURN(id);
+}
+
+static ulonglong mrn_wrapper_ft_ext_count_matches(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong n_records = mrn_generic_ft_ext_count_matches(handler);
+ DBUG_RETURN(n_records);
+}
+
+static _ft_vft_ext mrn_wrapper_ft_vft_ext = {
+ mrn_wrapper_ft_ext_get_version,
+ mrn_wrapper_ft_ext_get_flags,
+ mrn_wrapper_ft_ext_get_docid,
+ mrn_wrapper_ft_ext_count_matches
+};
+
+static uint mrn_storage_ft_ext_get_version()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ uint version = mrn_generic_ft_get_version();
+ DBUG_RETURN(version);
+}
+
+static ulonglong mrn_storage_ft_ext_get_flags()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong flags = mrn_generic_ft_ext_get_flags();
+ DBUG_RETURN(flags);
+}
+
+static ulonglong mrn_storage_ft_ext_get_docid(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong id = mrn_generic_ft_ext_get_docid(handler);
+ DBUG_RETURN(id);
+}
+
+static ulonglong mrn_storage_ft_ext_count_matches(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong n_records = mrn_generic_ft_ext_count_matches(handler);
+ DBUG_RETURN(n_records);
+}
+
+static _ft_vft_ext mrn_storage_ft_vft_ext = {
+ mrn_storage_ft_ext_get_version,
+ mrn_storage_ft_ext_get_flags,
+ mrn_storage_ft_ext_get_docid,
+ mrn_storage_ft_ext_count_matches
+};
+
+static uint mrn_no_such_key_ft_ext_get_version()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ uint version = mrn_generic_ft_get_version();
+ DBUG_RETURN(version);
+}
+
+static ulonglong mrn_no_such_key_ft_ext_get_flags()
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong flags = mrn_generic_ft_ext_get_flags();
+ DBUG_RETURN(flags);
+}
+
+static ulonglong mrn_no_such_key_ft_ext_get_docid(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong id = GRN_ID_NIL;
+ DBUG_RETURN(id);
+}
+
+static ulonglong mrn_no_such_key_ft_ext_count_matches(FT_INFO_EXT *handler)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ ulonglong n_records = 0;
+ DBUG_RETURN(n_records);
+}
+
+static _ft_vft_ext mrn_no_such_key_ft_vft_ext = {
+ mrn_no_such_key_ft_ext_get_version,
+ mrn_no_such_key_ft_ext_get_flags,
+ mrn_no_such_key_ft_ext_get_docid,
+ mrn_no_such_key_ft_ext_count_matches
+};
+#endif
+
+/* handler implementation */
+ha_mroonga::ha_mroonga(handlerton *hton, TABLE_SHARE *share_arg)
+ :handler(hton, share_arg),
+ wrap_handler(NULL),
+ is_clone(false),
+ parent_for_clone(NULL),
+ mem_root_for_clone(NULL),
+ record_id(GRN_ID_NIL),
+ key_id(NULL),
+ del_key_id(NULL),
+
+ wrap_ft_init_count(0),
+ share(NULL),
+ wrap_key_info(NULL),
+ base_key_info(NULL),
+
+ analyzed_for_create(false),
+ wrap_handler_for_create(NULL),
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ hnd_add_index(NULL),
+#endif
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ alter_key_info_buffer(NULL),
+#else
+ wrap_alter_key_info(NULL),
+#endif
+ mrn_lock_type(F_UNLCK),
+
+ ctx_entity_(),
+ ctx(&ctx_entity_),
+ grn_table(NULL),
+ grn_columns(NULL),
+ grn_column_ranges(NULL),
+ grn_index_tables(NULL),
+ grn_index_columns(NULL),
+
+ grn_source_column_geo(NULL),
+ cursor_geo(NULL),
+ cursor(NULL),
+ index_table_cursor(NULL),
+ empty_value_records(NULL),
+ empty_value_records_cursor(NULL),
+
+ sorted_result(NULL),
+ matched_record_keys(NULL),
+ blob_buffers(NULL),
+
+ dup_key(0),
+
+ count_skip(false),
+ fast_order_limit(false),
+ fast_order_limit_with_index(false),
+
+ ignoring_duplicated_key(false),
+ inserting_with_update(false),
+ fulltext_searching(false),
+ ignoring_no_key_columns(false),
+ replacing_(false),
+ written_by_row_based_binlog(0),
+ current_ft_item(NULL),
+ operations_(NULL)
+{
+ MRN_DBUG_ENTER_METHOD();
+ grn_ctx_init(ctx, 0);
+ mrn_change_encoding(ctx, system_charset_info);
+ grn_ctx_use(ctx, mrn_db);
+ GRN_WGS84_GEO_POINT_INIT(&top_left_point, 0);
+ GRN_WGS84_GEO_POINT_INIT(&bottom_right_point, 0);
+ GRN_WGS84_GEO_POINT_INIT(&source_point, 0);
+ GRN_TEXT_INIT(&key_buffer, 0);
+ GRN_TEXT_INIT(&encoded_key_buffer, 0);
+ GRN_VOID_INIT(&old_value_buffer);
+ GRN_VOID_INIT(&new_value_buffer);
+ DBUG_VOID_RETURN;
+}
+
+ha_mroonga::~ha_mroonga()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ delete operations_;
+
+ if (analyzed_for_create) {
+ if (wrap_handler_for_create) {
+ delete wrap_handler_for_create;
+ }
+ if (share_for_create.wrapper_mode) {
+ plugin_unlock(NULL, share_for_create.plugin);
+ }
+ if (share_for_create.table_name) {
+ my_free(share_for_create.table_name);
+ }
+ mrn_free_share_alloc(&share_for_create);
+ free_root(&mem_root_for_create, MYF(0));
+ }
+ if (blob_buffers)
+ {
+ delete [] blob_buffers;
+ }
+ grn_obj_unlink(ctx, &top_left_point);
+ grn_obj_unlink(ctx, &bottom_right_point);
+ grn_obj_unlink(ctx, &source_point);
+ grn_obj_unlink(ctx, &key_buffer);
+ grn_obj_unlink(ctx, &encoded_key_buffer);
+ grn_obj_unlink(ctx, &old_value_buffer);
+ grn_obj_unlink(ctx, &new_value_buffer);
+ grn_ctx_fin(ctx);
+ DBUG_VOID_RETURN;
+}
+
+const char *ha_mroonga::table_type() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(MRN_PLUGIN_NAME_STRING);
+}
+
+const char *ha_mroonga::index_type(uint key_nr)
+{
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->s->key_info[key_nr]);
+ if (key_info->algorithm == HA_KEY_ALG_FULLTEXT) {
+ DBUG_RETURN("FULLTEXT");
+ } else if (key_info->algorithm == HA_KEY_ALG_HASH) {
+ DBUG_RETURN("HASH");
+ } else {
+ DBUG_RETURN("BTREE");
+ }
+}
+
+static const char *ha_mroonga_exts[] = {
+ NullS
+};
+const char **ha_mroonga::bas_ext() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(ha_mroonga_exts);
+}
+
+uint ha_mroonga::wrapper_max_supported_record_length() const
+{
+ uint res;
+ MRN_DBUG_ENTER_METHOD();
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrap_handler_for_create->max_supported_record_length();
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->max_supported_record_length();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::storage_max_supported_record_length() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(HA_MAX_REC_LENGTH);
+}
+
+uint ha_mroonga::max_supported_record_length() const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ uint res;
+ if (!share && !analyzed_for_create &&
+ (
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
+ thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
+ )
+ ) {
+ create_share_for_create();
+ }
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrapper_max_supported_record_length();
+ } else if (wrap_handler && share && share->wrapper_mode) {
+ res = wrapper_max_supported_record_length();
+ } else {
+ res = storage_max_supported_record_length();
+ }
+
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::wrapper_max_supported_keys() const
+{
+ uint res;
+ MRN_DBUG_ENTER_METHOD();
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrap_handler_for_create->max_supported_keys();
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->max_supported_keys();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::storage_max_supported_keys() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(HA_MAX_REC_LENGTH);
+}
+
+uint ha_mroonga::max_supported_keys() const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ uint res;
+ if (!share && !analyzed_for_create &&
+ (
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
+ thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
+ )
+ ) {
+ create_share_for_create();
+ }
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrapper_max_supported_keys();
+ } else if (wrap_handler && share && share->wrapper_mode) {
+ res = wrapper_max_supported_keys();
+ } else {
+ res = storage_max_supported_keys();
+ }
+
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::wrapper_max_supported_key_length() const
+{
+ uint res;
+ MRN_DBUG_ENTER_METHOD();
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrap_handler_for_create->max_supported_key_length();
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->max_supported_key_length();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::storage_max_supported_key_length() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(GRN_TABLE_MAX_KEY_SIZE);
+}
+
+uint ha_mroonga::max_supported_key_length() const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ uint res;
+ if (!share && !analyzed_for_create &&
+ (
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
+ thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
+ )
+ ) {
+ create_share_for_create();
+ }
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrapper_max_supported_key_length();
+ } else if (wrap_handler && share && share->wrapper_mode) {
+ res = wrapper_max_supported_key_length();
+ } else {
+ res = storage_max_supported_key_length();
+ }
+
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::wrapper_max_supported_key_part_length() const
+{
+ uint res;
+ MRN_DBUG_ENTER_METHOD();
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrap_handler_for_create->max_supported_key_part_length();
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->max_supported_key_part_length();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::storage_max_supported_key_part_length() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(GRN_TABLE_MAX_KEY_SIZE);
+}
+
+uint ha_mroonga::max_supported_key_part_length() const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ uint res;
+ if (!share && !analyzed_for_create &&
+ (
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
+ thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
+ )
+ ) {
+ create_share_for_create();
+ }
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ res = wrapper_max_supported_key_part_length();
+ } else if (wrap_handler && share && share->wrapper_mode) {
+ res = wrapper_max_supported_key_part_length();
+ } else {
+ res = storage_max_supported_key_part_length();
+ }
+
+ DBUG_RETURN(res);
+}
+
+ulonglong ha_mroonga::wrapper_table_flags() const
+{
+ ulonglong table_flags;
+ MRN_DBUG_ENTER_METHOD();
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ table_flags = wrap_handler_for_create->ha_table_flags();
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ table_flags = wrap_handler->ha_table_flags();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ table_flags |= HA_CAN_FULLTEXT | HA_PRIMARY_KEY_REQUIRED_FOR_DELETE |
+ HA_CAN_RTREEKEYS | HA_REC_NOT_IN_SEQ;
+#ifdef HA_CAN_REPAIR
+ table_flags |= HA_CAN_REPAIR;
+#endif
+#ifdef HA_CAN_FULLTEXT_EXT
+ table_flags |= HA_CAN_FULLTEXT_EXT;
+#endif
+#ifdef HA_GENERATED_COLUMNS
+ table_flags |= HA_GENERATED_COLUMNS;
+#endif
+#ifdef HA_CAN_VIRTUAL_COLUMNS
+ table_flags |= HA_CAN_VIRTUAL_COLUMNS;
+#endif
+ table_flags |= HA_CAN_HASH_KEYS;
+ DBUG_RETURN(table_flags);
+}
+
+ulonglong ha_mroonga::storage_table_flags() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ ulonglong flags =
+ HA_NO_TRANSACTIONS |
+ HA_PARTIAL_COLUMN_READ |
+ HA_REC_NOT_IN_SEQ |
+ HA_NULL_IN_KEY |
+ HA_CAN_INDEX_BLOBS |
+ HA_STATS_RECORDS_IS_EXACT |
+ HA_CAN_FULLTEXT |
+ HA_BINLOG_FLAGS |
+ HA_CAN_BIT_FIELD |
+ HA_DUPLICATE_POS |
+ HA_CAN_GEOMETRY |
+ HA_CAN_RTREEKEYS;
+ //HA_HAS_RECORDS;
+#ifdef HA_MUST_USE_TABLE_CONDITION_PUSHDOWN
+ flags |= HA_MUST_USE_TABLE_CONDITION_PUSHDOWN;
+#endif
+#ifdef HA_CAN_REPAIR
+ flags |= HA_CAN_REPAIR;
+#endif
+#ifdef HA_CAN_FULLTEXT_EXT
+ flags |= HA_CAN_FULLTEXT_EXT;
+#endif
+#ifdef HA_GENERATED_COLUMNS
+ flags |= HA_GENERATED_COLUMNS;
+#endif
+#ifdef HA_CAN_VIRTUAL_COLUMNS
+ flags |= HA_CAN_VIRTUAL_COLUMNS;
+#endif
+ flags |= HA_CAN_HASH_KEYS;
+ DBUG_RETURN(flags);
+}
+
+ulonglong ha_mroonga::table_flags() const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ ulonglong flags;
+ if (!share && !analyzed_for_create &&
+ (
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
+ thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
+ )
+ ) {
+ create_share_for_create();
+ }
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ flags = wrapper_table_flags();
+ } else if (wrap_handler && share && share->wrapper_mode) {
+ flags = wrapper_table_flags();
+ } else {
+ flags = storage_table_flags();
+ }
+
+ DBUG_RETURN(flags);
+}
+
+ulong ha_mroonga::wrapper_index_flags(uint idx, uint part, bool all_parts) const
+{
+ ulong index_flags;
+ KEY *key = &(table_share->key_info[idx]);
+ MRN_DBUG_ENTER_METHOD();
+ if (key->algorithm == HA_KEY_ALG_BTREE ||
+ key->algorithm == HA_KEY_ALG_UNDEF) {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ index_flags = wrap_handler->index_flags(idx, part, all_parts);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ } else {
+ index_flags = HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR;
+ }
+ DBUG_RETURN(index_flags);
+}
+
+ulong ha_mroonga::storage_index_flags(uint idx, uint part, bool all_parts) const
+{
+ MRN_DBUG_ENTER_METHOD();
+ ulong flags;
+ KEY *key = &(table_share->key_info[idx]);
+ if (key->algorithm == HA_KEY_ALG_BTREE ||
+ key->algorithm == HA_KEY_ALG_UNDEF) {
+ flags = HA_READ_NEXT | HA_READ_PREV | HA_READ_RANGE;
+ bool need_normalize_p = false;
+ // TODO: MariaDB 10.1 passes key->user_defined_key_parts as part
+ // for ORDER BY DESC. We just it fallback to part = 0. We may use
+ // it for optimization in the future.
+ //
+ // See also: test_if_order_by_key() in sql/sql_select.cc.
+ if (KEY_N_KEY_PARTS(key) == part) {
+ part = 0;
+ }
+ Field *field = &(key->key_part[part].field[0]);
+ if (field && (have_custom_normalizer(key) || should_normalize(field))) {
+ need_normalize_p = true;
+ }
+ if (!need_normalize_p) {
+ flags |= HA_KEYREAD_ONLY;
+ }
+ if (KEY_N_KEY_PARTS(key) > 1 || !need_normalize_p) {
+ flags |= HA_READ_ORDER;
+ }
+ } else {
+ flags = HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR;
+ }
+ DBUG_RETURN(flags);
+}
+
+ulong ha_mroonga::index_flags(uint idx, uint part, bool all_parts) const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ KEY *key = &(table_share->key_info[idx]);
+ if (key->algorithm == HA_KEY_ALG_FULLTEXT) {
+ DBUG_RETURN(HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR);
+ }
+ if (mrn_is_geo_key(key)) {
+ DBUG_RETURN(HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR | HA_READ_RANGE);
+ }
+
+ int error = 0;
+ if (wrap_handler && share && share->wrapper_mode)
+ {
+ error = wrapper_index_flags(idx, part, all_parts);
+ } else {
+ error = storage_index_flags(idx, part, all_parts);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::create_share_for_create() const
+{
+ int error;
+ THD *thd = ha_thd();
+ LEX *lex = thd->lex;
+ HA_CREATE_INFO *create_info = &lex->create_info;
+ TABLE_LIST *table_list = MRN_LEX_GET_TABLE_LIST(lex);
+ MRN_DBUG_ENTER_METHOD();
+ wrap_handler_for_create = NULL;
+ table_for_create.reset();
+ table_share_for_create.reset();
+ memset(&share_for_create, 0, sizeof(MRN_SHARE));
+ if (table_share) {
+ table_share_for_create.comment = table_share->comment;
+ table_share_for_create.connect_string = table_share->connect_string;
+ } else {
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ if (thd_sql_command(ha_thd()) != SQLCOM_CREATE_INDEX) {
+#endif
+ table_share_for_create.comment = create_info->comment;
+ table_share_for_create.connect_string = create_info->connect_string;
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ }
+#endif
+ if (thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX) {
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, false);
+ if (slot_data && slot_data->alter_create_info) {
+ create_info = slot_data->alter_create_info;
+ if (slot_data->alter_connect_string) {
+ table_share_for_create.connect_string.str =
+ slot_data->alter_connect_string;
+ table_share_for_create.connect_string.length =
+ strlen(slot_data->alter_connect_string);
+ } else {
+ table_share_for_create.connect_string.str = NULL;
+ table_share_for_create.connect_string.length = 0;
+ }
+ if (slot_data->alter_comment) {
+ table_share_for_create.comment.str =
+ slot_data->alter_comment;
+ table_share_for_create.comment.length =
+ strlen(slot_data->alter_comment);
+ } else {
+ table_share_for_create.comment.str = NULL;
+ table_share_for_create.comment.length = 0;
+ }
+ }
+ }
+ }
+ mrn_init_alloc_root(&mem_root_for_create, 1024, 0, MYF(0));
+ analyzed_for_create = true;
+ if (table_list) {
+ share_for_create.table_name = mrn_my_strndup(table_list->table_name.str,
+ table_list->table_name.length,
+ MYF(MY_WME));
+ share_for_create.table_name_length = table_list->table_name.length;
+ }
+ share_for_create.table_share = &table_share_for_create;
+ table_for_create.s = &table_share_for_create;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ table_for_create.part_info = NULL;
+#endif
+ if ((error = mrn_parse_table_param(&share_for_create, &table_for_create)))
+ goto error;
+
+ if (share_for_create.wrapper_mode)
+ {
+ wrap_handler_for_create =
+ share_for_create.hton->create(share_for_create.hton, NULL,
+ &mem_root_for_create);
+ if (!wrap_handler_for_create) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error;
+ }
+ wrap_handler_for_create->init();
+ }
+ DBUG_RETURN(0);
+
+error:
+ if (share_for_create.wrapper_mode) {
+ plugin_unlock(NULL, share_for_create.plugin);
+ }
+ mrn_free_share_alloc(&share_for_create);
+ free_root(&mem_root_for_create, MYF(0));
+ analyzed_for_create = false;
+ thd->clear_error();
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_create(const char *name, TABLE *table,
+ HA_CREATE_INFO *info, MRN_SHARE *tmp_share)
+{
+ int error = 0;
+ handler *hnd;
+ MRN_DBUG_ENTER_METHOD();
+
+ if (table_share->primary_key == MAX_KEY)
+ {
+ my_message(ER_REQUIRES_PRIMARY_KEY,
+ MRN_GET_ERR_MSG(ER_REQUIRES_PRIMARY_KEY), MYF(0));
+ DBUG_RETURN(ER_REQUIRES_PRIMARY_KEY);
+ }
+
+ error = ensure_database_open(name);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = wrapper_create_index(name, table, tmp_share);
+ if (error)
+ DBUG_RETURN(error);
+
+ wrap_key_info = mrn_create_key_info_for_table(tmp_share, table, &error);
+ if (error)
+ DBUG_RETURN(error);
+ base_key_info = table->key_info;
+
+ share = tmp_share;
+ MRN_SET_WRAP_SHARE_KEY(tmp_share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ if (parse_engine_table_options(ha_thd(), tmp_share->hton, table->s)) {
+ MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ share = NULL;
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ error = MRN_GET_ERROR_NUMBER;
+ DBUG_RETURN(error);
+ }
+#endif
+ hnd = get_new_handler(table->s, current_thd->mem_root, tmp_share->hton);
+ if (!hnd)
+ {
+ MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ share = NULL;
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ error = hnd->ha_create(name, table, info);
+ MRN_SET_BASE_SHARE_KEY(tmp_share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ share = NULL;
+ delete hnd;
+
+ if (error) {
+ mrn::PathMapper mapper(name);
+ generic_delete_table(name, mapper.table_name());
+ }
+
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_create_index_fulltext_validate(KEY *key_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ uint i;
+ for (i = 0; i < KEY_N_KEY_PARTS(key_info); i++) {
+ Field *field = key_info->key_part[i].field;
+
+ grn_builtin_type gtype = mrn_grn_type_from_field(ctx, field, true);
+ if (gtype != GRN_DB_SHORT_TEXT)
+ {
+ error = ER_CANT_CREATE_TABLE;
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "key type must be text: <%d> "
+ "(TODO: We should show type name not type ID.)",
+ field->type());
+ my_message(ER_CANT_CREATE_TABLE,
+ "key type must be text. (TODO: We should show type name.)",
+ MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_create_index_fulltext(const char *grn_table_name,
+ int i,
+ KEY *key_info,
+ grn_obj **index_tables,
+ grn_obj **index_columns,
+ MRN_SHARE *tmp_share)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ error = wrapper_create_index_fulltext_validate(key_info);
+ if (error) {
+ DBUG_RETURN(error);
+ }
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ grn_obj_flags index_table_flags =
+ GRN_OBJ_TABLE_PAT_KEY |
+ GRN_OBJ_PERSISTENT;
+ grn_obj *index_table;
+
+ grn_column_flags index_column_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
+
+ if (!find_index_column_flags(key_info, &index_column_flags)) {
+ index_column_flags |= GRN_OBJ_WITH_POSITION;
+ if (KEY_N_KEY_PARTS(key_info) > 1) {
+ index_column_flags |= GRN_OBJ_WITH_SECTION;
+ }
+ }
+
+ mrn::SmartGrnObj lexicon_key_type(ctx, GRN_DB_SHORT_TEXT);
+ error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
+ if (error) {
+ DBUG_RETURN(error);
+ }
+ mrn::IndexTableName index_table_name(grn_table_name, key_info->name.str);
+ index_table = grn_table_create(ctx,
+ index_table_name.c_str(),
+ index_table_name.length(),
+ NULL,
+ index_table_flags,
+ lexicon_key_type.get(),
+ 0);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ mrn_change_encoding(ctx, system_charset_info);
+ index_tables[i] = index_table;
+
+ grn_obj *tokenizer = find_tokenizer(key_info, tmp_share, i);
+ if (tokenizer) {
+ grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
+ grn_obj_set_info(ctx, index_table, info_type, tokenizer);
+ grn_obj_unlink(ctx, tokenizer);
+ }
+
+ {
+ grn_obj token_filters;
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
+ if (find_token_filters(key_info, &token_filters)) {
+ grn_obj_set_info(ctx, index_table,
+ GRN_INFO_TOKEN_FILTERS, &token_filters);
+ }
+ grn_obj_unlink(ctx, &token_filters);
+ }
+
+ if (have_custom_normalizer(key_info) ||
+ should_normalize(&key_info->key_part->field[0])) {
+ grn_info_type info_type = GRN_INFO_NORMALIZER;
+ grn_obj *normalizer = find_normalizer(key_info);
+ if (normalizer) {
+ grn_obj_set_info(ctx, index_table, info_type, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+ }
+
+ grn_obj *index_column = grn_column_create(ctx, index_table,
+ INDEX_COLUMN_NAME,
+ strlen(INDEX_COLUMN_NAME),
+ NULL,
+ index_column_flags,
+ grn_table);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (index_columns) {
+ index_columns[i] = index_column;
+ } else {
+ grn_obj_unlink(ctx, index_column);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_create_index_geo(const char *grn_table_name,
+ int i,
+ KEY *key_info,
+ grn_obj **index_tables,
+ grn_obj **index_columns,
+ MRN_SHARE *tmp_share)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ mrn::IndexTableName index_table_name(grn_table_name, key_info->name.str);
+
+ grn_obj_flags index_table_flags =
+ GRN_OBJ_TABLE_PAT_KEY |
+ GRN_OBJ_PERSISTENT;
+ grn_obj *index_table;
+
+ grn_obj_flags index_column_flags =
+ GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
+
+ grn_obj *lexicon_key_type = grn_ctx_at(ctx, GRN_DB_WGS84_GEO_POINT);
+ index_table = grn_table_create(ctx,
+ index_table_name.c_str(),
+ index_table_name.length(),
+ NULL,
+ index_table_flags, lexicon_key_type, 0);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
+ grn_obj_unlink(ctx, lexicon_key_type);
+ DBUG_RETURN(error);
+ }
+ grn_obj_unlink(ctx, lexicon_key_type);
+ index_tables[i] = index_table;
+
+ grn_obj *index_column = grn_column_create(ctx, index_table,
+ INDEX_COLUMN_NAME,
+ strlen(INDEX_COLUMN_NAME),
+ NULL,
+ index_column_flags,
+ grn_table);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (index_columns) {
+ index_columns[i] = index_column;
+ } else {
+ grn_obj_unlink(ctx, index_column);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_create_index(const char *name, TABLE *table,
+ MRN_SHARE *tmp_share)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ grn_obj *grn_index_table;
+ mrn::PathMapper mapper(name);
+ const char *grn_table_name = mapper.table_name();
+ char *grn_table_path = NULL; // we don't specify path
+ grn_obj *pkey_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
+ grn_obj *pkey_value_type = NULL; // we don't use this
+ grn_obj_flags grn_table_flags = GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_HASH_KEY;
+
+ grn_index_table = grn_table_create(ctx, grn_table_name, strlen(grn_table_name),
+ grn_table_path, grn_table_flags,
+ pkey_type, pkey_value_type);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (grn_table) {
+ grn_obj_unlink(ctx, grn_table);
+ }
+ grn_table = grn_index_table;
+
+ uint i;
+ uint n_keys = table->s->keys;
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
+ if (!tmp_share->disable_keys) {
+ for (i = 0; i < n_keys; i++) {
+ index_tables[i] = NULL;
+
+ KEY *key_info = &(table->s->key_info[i]);
+ if (key_info->algorithm == HA_KEY_ALG_FULLTEXT) {
+ error = wrapper_create_index_fulltext(grn_table_name,
+ i, key_info,
+ index_tables, NULL, tmp_share);
+ } else if (mrn_is_geo_key(key_info)) {
+ error = wrapper_create_index_geo(grn_table_name,
+ i, key_info,
+ index_tables, NULL, tmp_share);
+ }
+ }
+
+ if (error) {
+ for (uint j = 0; j < i; j++) {
+ if (index_tables[j]) {
+ grn_obj_remove(ctx, index_tables[j]);
+ }
+ }
+ grn_obj_remove(ctx, grn_table);
+ grn_table = NULL;
+ }
+ }
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_create(const char *name, TABLE *table,
+ HA_CREATE_INFO *info, MRN_SHARE *tmp_share)
+{
+ int error;
+ MRN_LONG_TERM_SHARE *long_term_share = tmp_share->long_term_share;
+ MRN_DBUG_ENTER_METHOD();
+
+ if (info->auto_increment_value) {
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ long_term_share->auto_inc_value = info->auto_increment_value;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ long_term_share->auto_inc_inited = true;
+ }
+
+ error = storage_create_validate_pseudo_column(table);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = storage_create_validate_index(table);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = ensure_database_open(name);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ grn_obj_flags table_flags = GRN_OBJ_PERSISTENT;
+
+ /* primary key must be handled before creating table */
+ grn_obj *pkey_type;
+ uint pkey_nr = table->s->primary_key;
+ if (pkey_nr != MAX_INDEXES) {
+ KEY *key_info = &(table->s->key_info[pkey_nr]);
+ bool is_id;
+
+ int key_parts = KEY_N_KEY_PARTS(key_info);
+ if (key_parts == 1) {
+ Field *pkey_field = key_info->key_part[0].field;
+ const char *column_name = pkey_field->field_name.str;
+ is_id = (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0);
+
+ grn_builtin_type gtype = mrn_grn_type_from_field(ctx, pkey_field, false);
+ pkey_type = grn_ctx_at(ctx, gtype);
+ } else {
+ is_id = false;
+ pkey_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
+ }
+
+ // default algorithm is BTREE ==> PAT
+ if (!is_id && key_info->algorithm == HA_KEY_ALG_HASH) {
+ table_flags |= GRN_OBJ_TABLE_HASH_KEY;
+ } else if (!is_id) {
+ table_flags |= GRN_OBJ_TABLE_PAT_KEY;
+ } else {
+ // for _id
+ table_flags |= GRN_OBJ_TABLE_NO_KEY;
+ pkey_type = NULL;
+ }
+
+ } else {
+ // primary key doesn't exists
+ table_flags |= GRN_OBJ_TABLE_NO_KEY;
+ pkey_type = NULL;
+ }
+
+ /* create table */
+ grn_obj *table_obj;
+ mrn::PathMapper mapper(name);
+
+ char *table_path = NULL; // we don't specify path
+ grn_obj *pkey_value_type = NULL; // we don't use this
+
+ table_obj = grn_table_create(ctx,
+ mapper.table_name(), strlen(mapper.table_name()),
+ table_path,
+ table_flags, pkey_type, pkey_value_type);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ if (table_flags == (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_PAT_KEY) ||
+ table_flags == (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_HASH_KEY)) {
+ KEY *key_info = &(table->s->key_info[pkey_nr]);
+ int key_parts = KEY_N_KEY_PARTS(key_info);
+ if (key_parts == 1) {
+ grn_obj *normalizer = NULL;
+ if (tmp_share->normalizer) {
+ normalizer = grn_ctx_get(ctx,
+ tmp_share->normalizer,
+ tmp_share->normalizer_length);
+ } else {
+ Field *field = &(key_info->key_part->field[0]);
+ if (should_normalize(field)) {
+ normalizer = find_normalizer(key_info);
+ }
+ }
+ if (normalizer) {
+ grn_info_type info_type = GRN_INFO_NORMALIZER;
+ grn_obj_set_info(ctx, table_obj, info_type, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+ if (tmp_share->default_tokenizer) {
+ grn_obj *default_tokenizer =
+ grn_ctx_get(ctx,
+ tmp_share->default_tokenizer,
+ tmp_share->default_tokenizer_length);
+ if (default_tokenizer) {
+ grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
+ grn_obj_set_info(ctx, table_obj, info_type, default_tokenizer);
+ grn_obj_unlink(ctx, default_tokenizer);
+ }
+ }
+ if (tmp_share->token_filters) {
+ grn_obj token_filters;
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
+ if (find_token_filters_fill(&token_filters,
+ tmp_share->token_filters,
+ tmp_share->token_filters_length)) {
+ grn_obj_set_info(ctx, table_obj,
+ GRN_INFO_TOKEN_FILTERS, &token_filters);
+ }
+ grn_obj_unlink(ctx, &token_filters);
+ }
+ }
+ }
+
+ /* create columns */
+ uint n_columns = table->s->fields;
+ for (uint i = 0; i < n_columns; i++) {
+ Field *field = table->s->field[i];
+ mrn::ColumnName column_name(field->field_name);
+
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name.mysql_name()) == 0) {
+ continue;
+ }
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+ if (storage_create_foreign_key(table, mapper.table_name(), field, table_obj,
+ error)) {
+ continue;
+ }
+ if (error) {
+ grn_obj_remove(ctx, table_obj);
+ DBUG_RETURN(error);
+ }
+#endif
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+
+ grn_obj_flags col_flags = GRN_OBJ_PERSISTENT;
+ if (!find_column_flags(field, tmp_share, i, &col_flags)) {
+ col_flags |= GRN_OBJ_COLUMN_SCALAR;
+ }
+
+ grn_obj *col_type;
+ {
+ int column_type_error_code = ER_CANT_CREATE_TABLE;
+ col_type = find_column_type(field, tmp_share, i, column_type_error_code);
+ if (!col_type) {
+ grn_obj_remove(ctx, table_obj);
+ DBUG_RETURN(column_type_error_code);
+ }
+ }
+ char *col_path = NULL; // we don't specify path
+
+ grn_column_create(ctx, table_obj,
+ column_name.c_str(), column_name.length(),
+ col_path, col_flags, col_type);
+ if (ctx->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ grn_obj_remove(ctx, table_obj);
+ DBUG_RETURN(error);
+ }
+ }
+
+ error = storage_create_indexes(table, mapper.table_name(), table_obj,
+ tmp_share);
+ if (error) {
+ grn_obj_remove(ctx, table_obj);
+ table_obj = NULL;
+ }
+
+ if (table_obj) {
+ grn_obj_unlink(ctx, table_obj);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_create_validate_pseudo_column(TABLE *table)
+{
+ int error = 0;
+ uint i, n_columns;
+
+ MRN_DBUG_ENTER_METHOD();
+ n_columns = table->s->fields;
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->s->field[i];
+ const char *column_name = field->field_name.str;
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
+ switch (field->type()) {
+ case MYSQL_TYPE_TINY :
+ case MYSQL_TYPE_SHORT :
+ case MYSQL_TYPE_INT24 :
+ case MYSQL_TYPE_LONG :
+ case MYSQL_TYPE_LONGLONG :
+ break;
+ default:
+ GRN_LOG(ctx, GRN_LOG_ERROR, "_id must be numeric data type");
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, "_id must be numeric data type", MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+ }
+
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+bool ha_mroonga::storage_create_foreign_key(TABLE *table,
+ const char *grn_table_name,
+ Field *field,
+ grn_obj *table_obj, int &error)
+{
+ MRN_DBUG_ENTER_METHOD();
+ LEX *lex = ha_thd()->lex;
+ Alter_info *alter_info = &lex->alter_info;
+ List_iterator<Key> key_iterator(alter_info->key_list);
+ Key *key;
+ char ref_db_buff[NAME_LEN + 1], ref_table_buff[NAME_LEN + 1];
+ while ((key = key_iterator++))
+ {
+ if (key->type != MRN_KEYTYPE_FOREIGN)
+ {
+ continue;
+ }
+ if (key->columns.elements > 1)
+ {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, "mroonga can't use FOREIGN_KEY with multiple columns",
+ MYF(0));
+ DBUG_RETURN(false);
+ }
+ List_iterator<Key_part_spec> key_part_col_iterator(key->columns);
+ Key_part_spec *key_part_col = key_part_col_iterator++;
+ LEX_CSTRING field_name = key_part_col->field_name;
+ DBUG_PRINT("info", ("mroonga: field_name=%s", field_name.str));
+ DBUG_PRINT("info", ("mroonga: field->field_name=%s", field->field_name.str));
+ if (strcmp(field->field_name.str, field_name.str))
+ {
+ continue;
+ }
+ Foreign_key *fk = (Foreign_key *) key;
+ List_iterator<Key_part_spec> key_part_ref_col_iterator(fk->ref_columns);
+ Key_part_spec *key_part_ref_col = key_part_ref_col_iterator++;
+ LEX_CSTRING ref_field_name = key_part_ref_col->field_name;
+ DBUG_PRINT("info", ("mroonga: ref_field_name=%s", ref_field_name.str));
+#ifdef MRN_FOREIGN_KEY_USE_CONST_STRING
+ LEX_CSTRING ref_db_name = fk->ref_db;
+#else
+ LEX_STRING ref_db_name = fk->ref_db;
+#endif
+ DBUG_PRINT("info", ("mroonga: ref_db_name=%s", ref_db_name.str));
+ if (ref_db_name.str && lower_case_table_names) {
+ strmake(ref_db_buff, ref_db_name.str, sizeof(ref_db_buff) - 1);
+ my_casedn_str(system_charset_info, ref_db_buff);
+ ref_db_name.str = ref_db_buff;
+ DBUG_PRINT("info", ("mroonga: casedn ref_db_name=%s", ref_db_name.str));
+ }
+#ifdef MRN_FOREIGN_KEY_USE_CONST_STRING
+ LEX_CSTRING ref_table_name = fk->ref_table;
+#else
+ LEX_STRING ref_table_name = fk->ref_table;
+#endif
+ DBUG_PRINT("info", ("mroonga: ref_table_name=%s", ref_table_name.str));
+ if (ref_table_name.str && lower_case_table_names) {
+ strmake(ref_table_buff, ref_table_name.str, sizeof(ref_table_buff) - 1);
+ my_casedn_str(system_charset_info, ref_table_buff);
+ ref_table_name.str = ref_table_buff;
+ DBUG_PRINT("info", ("mroonga: casedn ref_table_name=%s", ref_table_name.str));
+ }
+ if (ref_db_name.str && strcmp(table->s->db.str, ref_db_name.str))
+ {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error,
+ "mroonga can't use FOREIGN_KEY during different database tables",
+ MYF(0));
+ DBUG_RETURN(false);
+ }
+
+ grn_obj *column, *column_ref = NULL, *grn_table_ref = NULL;
+ char ref_path[FN_REFLEN + 1];
+ TABLE_LIST table_list;
+ TABLE_SHARE *tmp_ref_table_share;
+ build_table_filename(ref_path, sizeof(ref_path) - 1,
+ table->s->db.str, ref_table_name.str, "", 0);
+
+ DBUG_PRINT("info", ("mroonga: ref_path=%s", ref_path));
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(false);
+ mrn::PathMapper mapper(ref_path);
+ grn_table_ref = grn_ctx_get(ctx, mapper.table_name(),
+ strlen(mapper.table_name()));
+ if (!grn_table_ref) {
+ error = ER_CANT_CREATE_TABLE;
+ char err_msg[MRN_BUFFER_SIZE];
+ sprintf(err_msg, "reference table [%s.%s] is not mroonga table",
+ table->s->db.str, ref_table_name.str);
+ my_message(error, err_msg, MYF(0));
+ DBUG_RETURN(false);
+ }
+
+ LEX_CSTRING tmp_db_name= { mapper.db_name(), strlen(mapper.db_name()) };
+ LEX_CSTRING tmp_table_name= { mapper.mysql_table_name(), strlen(mapper.mysql_table_name()) };
+ table_list.init_one_table(&tmp_db_name, &tmp_table_name, 0, TL_WRITE);
+ mrn_open_mutex_lock(table->s);
+ tmp_ref_table_share =
+ mrn_create_tmp_table_share(&table_list, ref_path, &error);
+ mrn_open_mutex_unlock(table->s);
+ if (!tmp_ref_table_share) {
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = ER_CANT_CREATE_TABLE;
+ char err_msg[MRN_BUFFER_SIZE];
+ sprintf(err_msg, "reference table [%s.%s] is not found",
+ table->s->db.str, ref_table_name.str);
+ my_message(error, err_msg, MYF(0));
+ DBUG_RETURN(false);
+ }
+ uint ref_pkey_nr = tmp_ref_table_share->primary_key;
+ if (ref_pkey_nr == MAX_KEY) {
+ mrn_open_mutex_lock(table->s);
+ mrn_free_tmp_table_share(tmp_ref_table_share);
+ mrn_open_mutex_unlock(table->s);
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = ER_CANT_CREATE_TABLE;
+ char err_msg[MRN_BUFFER_SIZE];
+ sprintf(err_msg, "reference table [%s.%s] has no primary key",
+ table->s->db.str, ref_table_name.str);
+ my_message(error, err_msg, MYF(0));
+ DBUG_RETURN(false);
+ }
+ KEY *ref_key_info = &tmp_ref_table_share->key_info[ref_pkey_nr];
+ uint ref_key_parts = KEY_N_KEY_PARTS(ref_key_info);
+ if (ref_key_parts > 1) {
+ mrn_open_mutex_lock(table->s);
+ mrn_free_tmp_table_share(tmp_ref_table_share);
+ mrn_open_mutex_unlock(table->s);
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = ER_CANT_CREATE_TABLE;
+ char err_msg[MRN_BUFFER_SIZE];
+ sprintf(err_msg,
+ "reference table [%s.%s] primary key is multiple column",
+ table->s->db.str, ref_table_name.str);
+ my_message(error, err_msg, MYF(0));
+ DBUG_RETURN(false);
+ }
+ Field *ref_field = &ref_key_info->key_part->field[0];
+ if (strcmp(ref_field->field_name.str, ref_field_name.str)) {
+ mrn_open_mutex_lock(table->s);
+ mrn_free_tmp_table_share(tmp_ref_table_share);
+ mrn_open_mutex_unlock(table->s);
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = ER_CANT_CREATE_TABLE;
+ char err_msg[MRN_BUFFER_SIZE];
+ sprintf(err_msg,
+ "reference column [%s.%s.%s] is not used for primary key",
+ table->s->db.str, ref_table_name.str, ref_field_name.str);
+ my_message(error, err_msg, MYF(0));
+ DBUG_RETURN(false);
+ }
+ mrn_open_mutex_lock(table->s);
+ mrn_free_tmp_table_share(tmp_ref_table_share);
+ mrn_open_mutex_unlock(table->s);
+ grn_obj_flags col_flags = GRN_OBJ_PERSISTENT;
+ column = grn_column_create(ctx, table_obj, field->field_name.str,
+ field->field_name.length,
+ NULL, col_flags, grn_table_ref);
+ if (ctx->rc) {
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(false);
+ }
+
+ mrn::IndexColumnName index_column_name(grn_table_name, field->field_name.str);
+ grn_obj_flags ref_col_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
+ column_ref = grn_column_create(ctx, grn_table_ref,
+ index_column_name.c_str(),
+ index_column_name.length(),
+ NULL, ref_col_flags, table_obj);
+ if (ctx->rc) {
+ grn_obj_unlink(ctx, column);
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(false);
+ }
+
+ grn_obj source_ids;
+ grn_id source_id = grn_obj_id(ctx, column);
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+ GRN_UINT32_PUT(ctx, &source_ids, source_id);
+ if (error) {
+ grn_obj_unlink(ctx, &source_ids);
+ grn_obj_unlink(ctx, column_ref);
+ grn_obj_unlink(ctx, column);
+ grn_obj_unlink(ctx, grn_table_ref);
+ DBUG_RETURN(false);
+ }
+ grn_obj_set_info(ctx, column_ref, GRN_INFO_SOURCE, &source_ids);
+ grn_obj_unlink(ctx, &source_ids);
+ grn_obj_unlink(ctx, column_ref);
+ grn_obj_unlink(ctx, column);
+ grn_obj_unlink(ctx, grn_table_ref);
+ error = 0;
+ DBUG_RETURN(true);
+ }
+ error = 0;
+ DBUG_RETURN(false);
+}
+#endif
+
+int ha_mroonga::storage_create_validate_index(TABLE *table)
+{
+ int error = 0;
+ uint i;
+
+ MRN_DBUG_ENTER_METHOD();
+ /* checking if index is used for virtual columns */
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->s->key_info[i]);
+ // must be single column key
+ int key_parts = KEY_N_KEY_PARTS(key_info);
+ if (key_parts != 1) {
+ continue;
+ }
+ Field *field = key_info->key_part[0].field;
+ const char *column_name = field->field_name.str;
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
+ if (key_info->algorithm == HA_KEY_ALG_HASH) {
+ continue; // hash index is ok
+ }
+ GRN_LOG(ctx, GRN_LOG_ERROR, "only hash index can be defined for _id");
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, "only hash index can be defined for _id", MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_create_index_table(TABLE *table,
+ const char *grn_table_name,
+ grn_obj *grn_table,
+ MRN_SHARE *tmp_share,
+ KEY *key_info,
+ grn_obj **index_tables,
+ uint i)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ grn_obj *index_type;
+ grn_obj *index_table;
+ grn_obj_flags index_table_flags = GRN_OBJ_PERSISTENT;
+ bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
+
+ if (tmp_share->index_table && tmp_share->index_table[i]) {
+ index_table = grn_ctx_get(ctx,
+ tmp_share->index_table[i],
+ tmp_share->index_table_length[i]);
+ // TODO: add error check
+ index_tables[i] = index_table;
+ DBUG_RETURN(error);
+ }
+
+ if (is_multiple_column_index) {
+ index_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
+ } else {
+ Field *field = key_info->key_part[0].field;
+ grn_builtin_type groonga_type = mrn_grn_type_from_field(ctx, field, true);
+ index_type = grn_ctx_at(ctx, groonga_type);
+ }
+ // TODO: Add NULL check for index_type
+
+ int key_alg = key_info->algorithm;
+ if (key_info->flags & HA_FULLTEXT) {
+ index_table_flags |= GRN_OBJ_TABLE_PAT_KEY;
+ error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
+ if (error) {
+ grn_obj_remove(ctx, grn_table);
+ DBUG_RETURN(error);
+ }
+ } else if (key_alg == HA_KEY_ALG_HASH) {
+ index_table_flags |= GRN_OBJ_TABLE_HASH_KEY;
+ } else {
+ index_table_flags |= GRN_OBJ_TABLE_PAT_KEY;
+ }
+
+ {
+ mrn::IndexTableName index_table_name(grn_table_name, key_info->name.str);
+ index_table = grn_table_create(ctx,
+ index_table_name.c_str(),
+ index_table_name.length(),
+ NULL,
+ index_table_flags,
+ index_type,
+ NULL);
+ }
+ if (ctx->rc) {
+ grn_obj_unlink(ctx, index_type);
+ grn_obj_remove(ctx, grn_table);
+ error = ER_CANT_CREATE_TABLE;
+ my_message(ER_CANT_CREATE_TABLE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ if (key_info->flags & HA_FULLTEXT) {
+ grn_obj *tokenizer = find_tokenizer(key_info, tmp_share, i);
+ if (tokenizer) {
+ grn_info_type info_type = GRN_INFO_DEFAULT_TOKENIZER;
+ grn_obj_set_info(ctx, index_table, info_type, tokenizer);
+ grn_obj_unlink(ctx, tokenizer);
+ }
+
+ {
+ grn_obj token_filters;
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
+ if (find_token_filters(key_info, &token_filters)) {
+ grn_obj_set_info(ctx, index_table,
+ GRN_INFO_TOKEN_FILTERS, &token_filters);
+ }
+ grn_obj_unlink(ctx, &token_filters);
+ }
+ }
+
+ {
+ grn_obj *normalizer = NULL;
+ Field *field = &(key_info->key_part->field[0]);
+ if (key_info->flags & HA_FULLTEXT) {
+ if (have_custom_normalizer(key_info) ||
+ should_normalize(field)) {
+ normalizer = find_normalizer(key_info);
+ }
+ } else if (key_alg != HA_KEY_ALG_HASH) {
+ if (!is_multiple_column_index &&
+ (have_custom_normalizer(key_info) ||
+ should_normalize(field))) {
+ normalizer = find_normalizer(key_info);
+ }
+ }
+ if (normalizer) {
+ grn_info_type info_type = GRN_INFO_NORMALIZER;
+ grn_obj_set_info(ctx, index_table, info_type, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+ }
+
+ index_tables[i] = index_table;
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_create_index(TABLE *table, const char *grn_table_name,
+ grn_obj *grn_table, MRN_SHARE *tmp_share,
+ KEY *key_info, grn_obj **index_tables,
+ grn_obj **index_columns, uint i)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ grn_obj *index_column;
+
+ bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
+ if (!is_multiple_column_index) {
+ Field *field = key_info->key_part[0].field;
+ if (strcmp(MRN_COLUMN_NAME_ID, field->field_name.str) == 0) {
+ // skipping _id virtual column
+ DBUG_RETURN(0);
+ }
+
+ if (is_foreign_key_field(table->s->table_name.str,
+ field->field_name.str)) {
+ DBUG_RETURN(0);
+ }
+
+#ifdef HA_CAN_VIRTUAL_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: storage: failed to create index: "
+ ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_STR,
+ field->field_name.str);
+ error = ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_NUM;
+ my_message(error, error_message, MYF(0));
+ DBUG_RETURN(error);
+ }
+ } else {
+ int j, n_key_parts = KEY_N_KEY_PARTS(key_info);
+ for (j = 0; j < n_key_parts; j++) {
+ Field *field = key_info->key_part[j].field;
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: storage: failed to create index: "
+ ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_STR,
+ field->field_name.str);
+ error = ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_NUM;
+ my_message(error, error_message, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+#endif
+ }
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = storage_create_index_table(table, grn_table_name,
+ grn_table, tmp_share,
+ key_info, index_tables, i);
+ if (error)
+ DBUG_RETURN(error);
+
+ grn_obj *index_table = index_tables[i];
+
+ grn_column_flags index_column_flags = GRN_OBJ_COLUMN_INDEX | GRN_OBJ_PERSISTENT;
+
+ if (!find_index_column_flags(key_info, &index_column_flags)) {
+ grn_obj *tokenizer = grn_obj_get_info(ctx, index_table,
+ GRN_INFO_DEFAULT_TOKENIZER, NULL);
+ if (tokenizer) {
+ index_column_flags |= GRN_OBJ_WITH_POSITION;
+ }
+ if (is_multiple_column_index && (key_info->flags & HA_FULLTEXT)) {
+ index_column_flags |= GRN_OBJ_WITH_SECTION;
+ }
+ }
+
+ const char *index_column_name;
+ if (tmp_share->index_table && tmp_share->index_table[i]) {
+ index_column_name = key_info->name.str;
+ } else {
+ index_column_name = INDEX_COLUMN_NAME;
+ }
+ index_column = grn_column_create(ctx,
+ index_table,
+ index_column_name,
+ strlen(index_column_name),
+ NULL,
+ index_column_flags,
+ grn_table);
+
+ if (ctx->rc) {
+ grn_obj_remove(ctx, index_table);
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ mrn_change_encoding(ctx, system_charset_info);
+ if (is_multiple_column_index) {
+ if (key_info->flags & HA_FULLTEXT) {
+ grn_obj source_ids;
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+
+ int j, n_key_parts = KEY_N_KEY_PARTS(key_info);
+ for (j = 0; j < n_key_parts; j++) {
+ Field *field = key_info->key_part[j].field;
+ mrn::ColumnName column_name(field->field_name);
+ grn_obj *source_column = grn_obj_column(ctx,
+ grn_table,
+ column_name.c_str(),
+ column_name.length());
+ grn_id source_id = grn_obj_id(ctx, source_column);
+ GRN_UINT32_PUT(ctx, &source_ids, source_id);
+ grn_obj_unlink(ctx, source_column);
+ }
+ mrn_change_encoding(ctx, key_info->key_part->field->charset());
+ grn_obj_set_info(ctx, index_column, GRN_INFO_SOURCE, &source_ids);
+ grn_obj_unlink(ctx, &source_ids);
+ }
+ } else {
+ Field *field = key_info->key_part[0].field;
+ mrn::ColumnName column_name(field->field_name);
+ grn_obj *column;
+ column = grn_obj_column(ctx,
+ grn_table,
+ column_name.c_str(),
+ column_name.length());
+ if (column) {
+ grn_obj source_ids;
+ grn_id source_id = grn_obj_id(ctx, column);
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+ GRN_UINT32_PUT(ctx, &source_ids, source_id);
+ mrn_change_encoding(ctx, key_info->key_part->field->charset());
+ grn_obj_set_info(ctx, index_column, GRN_INFO_SOURCE, &source_ids);
+ grn_obj_unlink(ctx, &source_ids);
+ grn_obj_unlink(ctx, column);
+ }
+ }
+ mrn_change_encoding(ctx, system_charset_info);
+
+ if (index_columns) {
+ index_columns[i] = index_column;
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_create_indexes(TABLE *table, const char *grn_table_name,
+ grn_obj *grn_table, MRN_SHARE *tmp_share)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ uint n_keys = table->s->keys;
+ uint i;
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
+ for (i = 0; i < n_keys; i++) {
+ index_tables[i] = NULL;
+ if (i == table->s->primary_key) {
+ continue; // pkey is already handled
+ }
+ KEY *key_info = &table->s->key_info[i];
+ if (tmp_share->disable_keys && !(key_info->flags & HA_NOSAME)) {
+ continue; // key is disabled
+ }
+ if ((error = storage_create_index(table, grn_table_name, grn_table,
+ tmp_share, key_info,
+ index_tables, NULL, i))) {
+ break;
+ }
+ }
+ if (error) {
+ while (true) {
+ if (index_tables[i] &&
+ !(tmp_share->index_table && tmp_share->index_table[i])) {
+ grn_obj_remove(ctx, index_tables[i]);
+ }
+ if (!i)
+ break;
+ i--;
+ }
+ }
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::ensure_database_open(const char *name, mrn::Database **db)
+{
+ int error;
+
+ MRN_DBUG_ENTER_METHOD();
+
+ if (db)
+ *db = NULL;
+
+ mrn::Database *local_db;
+ error = mrn_db_manager->open(name, &local_db);
+ if (error)
+ DBUG_RETURN(error);
+
+ if (db)
+ *db = local_db;
+ grn_ctx_use(ctx, local_db->get());
+
+ delete operations_;
+ operations_ = new mrn::Operations(ctx);
+ if (mrn_enable_operations_recording) {
+ operations_->enable_recording();
+ } else {
+ operations_->disable_recording();
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::ensure_database_remove(const char *name)
+{
+ int error;
+
+ MRN_DBUG_ENTER_METHOD();
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ delete operations_;
+ operations_ = NULL;
+
+ mrn_db_manager->close(name);
+
+ mrn::PathMapper mapper(name);
+ remove_related_files(mapper.db_path());
+
+ DBUG_RETURN(error);
+}
+
+
+int ha_mroonga::create(const char *name,
+ TABLE *table,
+ HA_CREATE_INFO *info
+#ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
+ ,
+ dd::Table *table_def
+#endif
+ )
+{
+ int error = 0;
+ MRN_SHARE *tmp_share;
+ MRN_DBUG_ENTER_METHOD();
+ /* checking data type of virtual columns */
+
+ if (!(tmp_share = mrn_get_share(name, table, &error)))
+ DBUG_RETURN(error);
+
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(ha_thd(), false);
+ if (slot_data && slot_data->disable_keys_create_info == info) {
+ tmp_share->disable_keys = true;
+ }
+
+ if (tmp_share->wrapper_mode)
+ {
+ error = wrapper_create(name, table, info, tmp_share);
+ } else {
+ error = storage_create(name, table, info, tmp_share);
+ }
+
+ if (error) {
+ mrn_free_long_term_share(tmp_share->long_term_share);
+ tmp_share->long_term_share = NULL;
+ } else {
+ error = add_wrap_hton(tmp_share->table_name, tmp_share->hton);
+ }
+ mrn_free_share(tmp_share);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_open(const char *name, int mode, uint open_options)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ mrn::Database *db = NULL;
+ error = ensure_database_open(name, &db);
+ if (error)
+ DBUG_RETURN(error);
+
+ if (!(open_options & HA_OPEN_FOR_REPAIR)) {
+ error = open_table(name);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = wrapper_open_indexes(name);
+ if (error) {
+ grn_obj_unlink(ctx, grn_table);
+ grn_table = NULL;
+ DBUG_RETURN(error);
+ }
+ }
+
+ mrn_init_alloc_root(&mem_root, 1024, 0, MYF(0));
+ wrap_key_info = mrn_create_key_info_for_table(share, table, &error);
+ if (error)
+ DBUG_RETURN(error);
+ base_key_info = table->key_info;
+
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (!is_clone)
+ {
+ wrap_handler = get_new_handler(table->s, &mem_root, share->hton);
+ if (!wrap_handler)
+ {
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+#ifdef MRN_HANDLER_HAVE_SET_HA_SHARE_REF
+ wrap_handler->set_ha_share_ref(&table->s->ha_share);
+#endif
+ error = wrap_handler->ha_open(table, name, mode, open_options);
+ } else {
+ if (!(wrap_handler = parent_for_clone->wrap_handler->clone(name,
+ mem_root_for_clone)))
+ {
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ }
+ ref_length = wrap_handler->ref_length;
+ key_used_on_scan = wrap_handler->key_used_on_scan;
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ init();
+ wrapper_overwrite_index_bits();
+ wrapper_set_keys_in_use();
+
+ pk_keypart_map = make_prev_keypart_map(
+ KEY_N_KEY_PARTS(&(table->key_info[table_share->primary_key])));
+
+ if (!error) {
+ if (open_options & HA_OPEN_FOR_REPAIR) {
+ // TODO: How to check whether is DISABLE KEYS used or not?
+ error = wrapper_recreate_indexes(ha_thd());
+ } else if (db) {
+ mrn::Lock lock(&mrn_operations_mutex);
+ mrn::PathMapper mapper(name);
+ const char *table_name = mapper.table_name();
+ size_t table_name_size = strlen(table_name);
+ if (db->is_broken_table(table_name, table_name_size)) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "Auto repair is started: <%s>",
+ name);
+ error = operations_->clear(table_name, table_name_size);
+ if (!error) {
+ db->mark_table_repaired(table_name, table_name_size);
+ if (!share->disable_keys) {
+ // TODO: implemented by "reindex" instead of "remove and recreate".
+ // Because "remove and recreate" invalidates opened indexes by
+ // other threads.
+ error = wrapper_disable_indexes_mroonga(HA_KEY_SWITCH_ALL);
+ if (!error) {
+ error = wrapper_enable_indexes_mroonga(HA_KEY_SWITCH_ALL);
+ }
+ }
+ }
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "Auto repair is done: <%s>: %s",
+ name, error == 0 ? "success" : "failure");
+ }
+ }
+ }
+
+ if (error)
+ {
+ grn_obj_unlink(ctx, grn_table);
+ grn_table = NULL;
+ // TODO: free indexes.
+
+ delete wrap_handler;
+ wrap_handler = NULL;
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_open_indexes(const char *name)
+{
+ int error;
+
+ MRN_DBUG_ENTER_METHOD();
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ uint n_keys = table->s->keys;
+ uint n_primary_keys = table->s->primary_key;
+ if (n_keys > 0) {
+ // TODO: reduce allocate memories. We only need just
+ // for HA_KEY_ALG_FULLTEXT keys.
+ grn_index_tables = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
+ grn_index_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
+ } else {
+ grn_index_tables = grn_index_columns = NULL;
+ }
+
+ mrn::PathMapper mapper(name);
+ uint i = 0;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->s->key_info[i]);
+
+ grn_index_tables[i] = NULL;
+ grn_index_columns[i] = NULL;
+
+ if (!(wrapper_is_target_index(key_info))) {
+ continue;
+ }
+
+ if (i == n_primary_keys) {
+ continue;
+ }
+
+ mrn::IndexTableName index_table_name(mapper.table_name(), key_info->name.str);
+ grn_index_tables[i] = grn_ctx_get(ctx,
+ index_table_name.c_str(),
+ index_table_name.length());
+ if (ctx->rc == GRN_SUCCESS && !grn_index_tables[i]) {
+ grn_index_tables[i] = grn_ctx_get(ctx,
+ index_table_name.old_c_str(),
+ index_table_name.old_length());
+ }
+ if (ctx->rc) {
+ DBUG_PRINT("info",
+ ("mroonga: sql_command=%u", thd_sql_command(ha_thd())));
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto error;
+ }
+
+ grn_index_columns[i] = grn_obj_column(ctx, grn_index_tables[i],
+ INDEX_COLUMN_NAME,
+ strlen(INDEX_COLUMN_NAME));
+ if (!grn_index_columns[i]) {
+ /* just for backward compatibility before 1.0. */
+ Field *field = key_info->key_part[0].field;
+ grn_index_columns[i] = grn_obj_column(ctx, grn_index_tables[i],
+ field->field_name.str,
+ field->field_name.length);
+ }
+
+ if (ctx->rc) {
+ DBUG_PRINT("info",
+ ("mroonga: sql_command=%u", thd_sql_command(ha_thd())));
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ grn_obj_unlink(ctx, grn_index_tables[i]);
+ goto error;
+ }
+ }
+
+ grn_bulk_space(ctx, &key_buffer, table->key_info->key_length);
+
+error:
+ if (error) {
+ while (i-- > 0) {
+ grn_obj *index_column = grn_index_columns[i];
+ if (index_column) {
+ grn_obj_unlink(ctx, index_column);
+ }
+ grn_obj *index_table = grn_index_tables[i];
+ if (index_table) {
+ grn_obj_unlink(ctx, index_table);
+ }
+ }
+ free(grn_index_columns);
+ free(grn_index_tables);
+ grn_index_columns = NULL;
+ grn_index_tables = NULL;
+ }
+
+ DBUG_RETURN(error);
+}
+
+void ha_mroonga::wrapper_overwrite_index_bits()
+{
+ uint i, j;
+ longlong table_option = table_flags();
+ MRN_DBUG_ENTER_METHOD();
+ table_share->keys_for_keyread.clear_all();
+ for (i = 0; i < table_share->fields; i++)
+ {
+ Field *field = table_share->field[i];
+ field->part_of_key.clear_all();
+#ifdef MRN_HAVE_MYSQL_FIELD_PART_OF_KEY_NOT_CLUSTERED
+ field->part_of_key_not_clustered.clear_all();
+#endif
+ field->part_of_sortkey.clear_all();
+ /*
+ TODO: We may need to update field->part_of_key_not_extended for
+ MySQL >= 5.7.18. If users report "raw InnoDB can use index for
+ this case but Mroonga wrapper mode for InnoDB can't use index
+ for the same case", we'll reconsider it again.
+ */
+ }
+ for (i = 0; i < table_share->keys; i++) {
+ KEY *key_info = &table->s->key_info[i];
+ KEY_PART_INFO *key_part = key_info->key_part;
+ for (j = 0 ; j < KEY_N_KEY_PARTS(key_info); key_part++, j++)
+ {
+ Field *field = key_part->field;
+ if (field->key_length() == key_part->length &&
+ !(field->flags & BLOB_FLAG))
+ {
+ if (index_flags(i, j, 0) & HA_KEYREAD_ONLY)
+ {
+ table_share->keys_for_keyread.set_bit(i);
+ field->part_of_key.set_bit(i);
+#ifdef MRN_HAVE_MYSQL_FIELD_PART_OF_KEY_NOT_CLUSTERED
+ field->part_of_key_not_clustered.set_bit(i);
+#endif
+ }
+ if (index_flags(i, j, 1) & HA_READ_ORDER)
+ field->part_of_sortkey.set_bit(i);
+ }
+ if (i == table_share->primary_key &&
+ (table_option & HA_PRIMARY_KEY_IN_READ_INDEX))
+ {
+ if (field->key_length() == key_part->length &&
+ !(field->flags & BLOB_FLAG))
+ field->part_of_key = table_share->keys_in_use;
+ if (field->part_of_sortkey.is_set(i))
+ field->part_of_sortkey = table_share->keys_in_use;
+ }
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::storage_reindex()
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ uint n_keys = table_share->keys;
+ KEY *key_info = table->key_info;
+
+ bool have_multiple_column_index = false;
+ bitmap_clear_all(table->read_set);
+ for (uint i = 0; i < n_keys; ++i) {
+ if (!grn_index_columns[i])
+ continue;
+
+ grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY);
+ grn_table_columns(ctx, grn_index_tables[i], NULL, 0,
+ reinterpret_cast<grn_obj *>(columns));
+ unsigned int n_columns =
+ grn_table_size(ctx, reinterpret_cast<grn_obj *>(columns));
+ grn_hash_close(ctx, columns);
+
+ bool is_multiple_column_index =
+ (KEY_N_KEY_PARTS(&(key_info[i])) != 1 &&
+ !(key_info[i].flags & HA_FULLTEXT));
+
+ if (n_columns == 1 || is_multiple_column_index) {
+ grn_table_truncate(ctx, grn_index_tables[i]);
+ if (ctx->rc != GRN_SUCCESS) {
+ error = ER_ERROR_ON_WRITE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ char index_table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_table_name_size;
+ index_table_name_size =
+ grn_obj_name(ctx, grn_index_tables[i],
+ index_table_name, GRN_TABLE_MAX_KEY_SIZE);
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: reindex: failed to truncate index table: "
+ "<%.*s>: <%s>(%d)",
+ index_table_name_size, index_table_name,
+ ctx->errbuf, ctx->rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ }
+
+ if (is_multiple_column_index) {
+ mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
+ have_multiple_column_index = true;
+ } else {
+ grn_obj_reindex(ctx, grn_index_columns[i]);
+ if (ctx->rc != GRN_SUCCESS) {
+ error = ER_ERROR_ON_WRITE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_column_name_size;
+ index_column_name_size =
+ grn_obj_name(ctx, grn_index_columns[i],
+ index_column_name, GRN_TABLE_MAX_KEY_SIZE);
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: reindex: failed to reindex: "
+ "<%.*s>: <%s>(%d)",
+ index_column_name_size, index_column_name,
+ ctx->errbuf, ctx->rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ }
+ }
+
+ if (!error && have_multiple_column_index)
+ error = storage_add_index_multiple_columns(key_info, n_keys,
+ grn_index_tables,
+ grn_index_columns,
+ false);
+ bitmap_set_all(table->read_set);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_open(const char *name, int mode, uint open_options)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ mrn::Database *db;
+ error = ensure_database_open(name, &db);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = open_table(name);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = storage_open_columns();
+ if (error) {
+ grn_obj_unlink(ctx, grn_table);
+ grn_table = NULL;
+ DBUG_RETURN(error);
+ }
+
+ if (!(open_options & HA_OPEN_FOR_REPAIR)) {
+ error = storage_open_indexes(name);
+ if (error) {
+ storage_close_columns();
+ grn_obj_unlink(ctx, grn_table);
+ grn_table = NULL;
+ DBUG_RETURN(error);
+ }
+
+ storage_set_keys_in_use();
+
+ {
+ mrn::Lock lock(&mrn_operations_mutex);
+ mrn::PathMapper mapper(name);
+ const char *table_name = mapper.table_name();
+ size_t table_name_size = strlen(table_name);
+ if (db->is_broken_table(table_name, table_name_size)) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "Auto repair is started: <%s>",
+ name);
+ error = operations_->repair(table_name, table_name_size);
+ if (!error)
+ db->mark_table_repaired(table_name, table_name_size);
+ if (!share->disable_keys) {
+ if (!error)
+ error = storage_reindex();
+ }
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "Auto repair is done: <%s>: %s",
+ name, error == 0 ? "success" : "failure");
+ }
+ }
+ }
+
+ ref_length = sizeof(grn_id);
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::open_table(const char *name)
+{
+ int error;
+ MRN_DBUG_ENTER_METHOD();
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ mrn::PathMapper mapper(name);
+ grn_table = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
+ if (ctx->rc) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (!grn_table) {
+ error = ER_CANT_OPEN_FILE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: failed to open table: <%s>",
+ mapper.table_name());
+ my_message(error, error_message, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::storage_open_columns(void)
+{
+ int error;
+ MRN_DBUG_ENTER_METHOD();
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ int n_columns = table->s->fields;
+ grn_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_columns);
+ grn_column_ranges = (grn_obj **)malloc(sizeof(grn_obj *) * n_columns);
+ for (int i = 0; i < n_columns; i++) {
+ grn_columns[i] = NULL;
+ grn_column_ranges[i] = NULL;
+ }
+
+ if (table_share->blob_fields)
+ {
+ DBUG_ASSERT(!blob_buffers);
+ if (!(blob_buffers = new (&table->mem_root) String[n_columns]))
+ {
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ }
+
+ for (int i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+ mrn::ColumnName column_name(field->field_name);
+ if (table_share->blob_fields)
+ {
+ blob_buffers[i].set_charset(field->charset());
+ }
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name.mysql_name()) == 0) {
+ continue;
+ }
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ grn_columns[i] = NULL;
+ grn_column_ranges[i] = NULL;
+ continue;
+ }
+#endif
+
+ grn_columns[i] = grn_obj_column(ctx,
+ grn_table,
+ column_name.c_str(),
+ column_name.length());
+ if (!grn_columns[i]) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ break;
+ }
+
+ grn_id range_id = grn_obj_get_range(ctx, grn_columns[i]);
+ grn_column_ranges[i] = grn_ctx_at(ctx, range_id);
+ if (!grn_column_ranges[i]) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ break;
+ }
+ }
+
+ if (error != 0) {
+ storage_close_columns();
+ }
+
+ DBUG_RETURN(error);
+}
+
+void ha_mroonga::storage_close_columns(void)
+{
+ int n_columns = table->s->fields;
+ for (int i = 0; i < n_columns; i++) {
+ grn_obj *column = grn_columns[i];
+ if (column) {
+ grn_obj_unlink(ctx, column);
+ }
+
+ grn_obj *range = grn_column_ranges[i];
+ if (range) {
+ grn_obj_unlink(ctx, range);
+ }
+ }
+
+ free(grn_columns);
+ grn_columns = NULL;
+ free(grn_column_ranges);
+ grn_column_ranges = NULL;
+}
+
+int ha_mroonga::storage_open_indexes(const char *name)
+{
+ int error;
+
+ MRN_DBUG_ENTER_METHOD();
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ uint n_keys = table->s->keys;
+ uint pkey_nr = table->s->primary_key;
+ if (n_keys > 0) {
+ grn_index_tables = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
+ grn_index_columns = (grn_obj **)malloc(sizeof(grn_obj *) * n_keys);
+ key_id = (grn_id *)malloc(sizeof(grn_id) * n_keys);
+ del_key_id = (grn_id *)malloc(sizeof(grn_id) * n_keys);
+ } else {
+ grn_index_tables = grn_index_columns = NULL;
+ key_id = NULL;
+ del_key_id = NULL;
+ }
+
+ mrn::PathMapper mapper(name);
+ uint i, j;
+ for (i = 0; i < n_keys; i++) {
+ if (i == pkey_nr) {
+ grn_index_tables[i] = grn_index_columns[i] = NULL;
+ continue;
+ }
+
+ KEY *key_info = &(table->s->key_info[i]);
+ if (KEY_N_KEY_PARTS(key_info) > 1) {
+ KEY_PART_INFO *key_part = key_info->key_part;
+ for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
+ bitmap_set_bit(&multiple_column_key_bitmap,
+ key_part[j].field->field_index);
+ }
+ }
+
+ MRN_SHARE *tmp_share;
+ tmp_share = mrn_get_share(name, table, &error);
+ if (tmp_share->index_table[i]) {
+ grn_index_tables[i] = grn_ctx_get(ctx,
+ tmp_share->index_table[i],
+ tmp_share->index_table_length[i]);
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_index_columns[i] = grn_obj_column(ctx,
+ grn_index_tables[i],
+ key_info->name.str,
+ key_info->name.length);
+ }
+ } else {
+ mrn::IndexTableName index_table_name(mapper.table_name(),
+ key_info->name.str);
+ grn_index_tables[i] = grn_ctx_get(ctx,
+ index_table_name.c_str(),
+ index_table_name.length());
+ if (ctx->rc == GRN_SUCCESS && !grn_index_tables[i]) {
+ grn_index_tables[i] = grn_ctx_get(ctx,
+ index_table_name.old_c_str(),
+ index_table_name.old_length());
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_index_columns[i] = grn_obj_column(ctx,
+ grn_index_tables[i],
+ INDEX_COLUMN_NAME,
+ strlen(INDEX_COLUMN_NAME));
+ if (!grn_index_columns[i] && ctx->rc == GRN_SUCCESS) {
+ /* just for backward compatibility before 1.0. */
+ Field *field = key_info->key_part[0].field;
+ grn_index_columns[i] = grn_obj_column(ctx, grn_index_tables[i],
+ field->field_name.str,
+ field->field_name.length);
+ }
+ }
+ }
+ mrn_free_share(tmp_share);
+ if (ctx->rc) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto error;
+ }
+
+ if (ctx->rc) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto error;
+ }
+ }
+
+error:
+ if (error) {
+ if (i) {
+ while (true) {
+ grn_obj *index_column = grn_index_columns[i];
+ if (index_column) {
+ grn_obj_unlink(ctx, index_column);
+ }
+ grn_obj *index_table = grn_index_tables[i];
+ if (index_table) {
+ grn_obj_unlink(ctx, index_table);
+ }
+ if (!i)
+ break;
+ i--;
+ }
+ }
+ free(key_id);
+ free(del_key_id);
+ free(grn_index_columns);
+ free(grn_index_tables);
+ key_id = NULL;
+ del_key_id = NULL;
+ grn_index_columns = NULL;
+ grn_index_tables = NULL;
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::open(const char *name,
+ int mode,
+ uint open_options
+#ifdef MRN_HANDLER_OPEN_HAVE_TABLE_DEFINITION
+ ,
+ const dd::Table *table_def
+#endif
+ )
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!(share = mrn_get_share(name, table, &error)))
+ DBUG_RETURN(error);
+ thr_lock_data_init(&share->lock,&thr_lock_data,NULL);
+
+ if (bitmap_init(&multiple_column_key_bitmap, NULL, table->s->fields, false))
+ {
+ mrn_free_share(share);
+ share = NULL;
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+
+ if (share->wrapper_mode)
+ {
+ error = wrapper_open(name, mode, open_options);
+ } else {
+ error = storage_open(name, mode, open_options);
+ }
+
+ if (error)
+ {
+ bitmap_free(&multiple_column_key_bitmap);
+ mrn_free_share(share);
+ share = NULL;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_close()
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_HAVE_HA_CLOSE
+ error = wrap_handler->ha_close();
+#else
+ error = wrap_handler->close();
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ delete wrap_handler;
+ wrap_handler = NULL;
+ if (wrap_key_info)
+ {
+ my_free(wrap_key_info);
+ wrap_key_info = NULL;
+ }
+ base_key_info = NULL;
+ free_root(&mem_root, MYF(0));
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_close()
+{
+ MRN_DBUG_ENTER_METHOD();
+ grn_obj_unlink(ctx, grn_table);
+ // TODO: unlink elements
+ free(grn_columns);
+ // TODO: unlink elements
+ free(grn_column_ranges);
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::close()
+{
+ int error = 0;
+ THD *thd = ha_thd();
+ MRN_DBUG_ENTER_METHOD();
+
+ clear_indexes();
+
+ if (share->wrapper_mode)
+ {
+ error = wrapper_close();
+ } else {
+ error = storage_close();
+ }
+
+ if (error != 0)
+ {
+ DBUG_RETURN(error);
+ }
+
+ if (thd)
+ {
+ error = add_wrap_hton(share->table_name, share->hton);
+ }
+ bitmap_free(&multiple_column_key_bitmap);
+ if (share->use_count == 1) {
+ mrn_free_long_term_share(share->long_term_share);
+ }
+ mrn_free_share(share);
+ share = NULL;
+ is_clone = false;
+
+ if (
+ thd &&
+ thd_sql_command(thd) == SQLCOM_FLUSH
+ ) {
+ /* flush tables */
+ mrn::Lock lock(&mrn_open_tables_mutex);
+ if (!mrn_open_tables.records)
+ {
+ int tmp_error = mrn_db_manager->clear();
+ if (tmp_error)
+ error = tmp_error;
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_delete_table(const char *name,
+ handlerton *wrap_handlerton,
+ const char *table_name)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(wrap_handlerton->drop_table(wrap_handlerton, name));
+}
+
+int ha_mroonga::generic_delete_table(const char *name, const char *table_name)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ error = ensure_database_open(name);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = drop_indexes(table_name);
+ grn_obj *table_obj = grn_ctx_get(ctx, table_name, strlen(table_name));
+ if (table_obj) {
+ grn_obj_remove(ctx, table_obj);
+ }
+ if (ctx->rc) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::delete_table(const char *name)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ THD *thd = ha_thd();
+ handlerton *wrap_handlerton = NULL;
+ mrn::PathMapper mapper(name);
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, false);
+ if (slot_data && slot_data->first_wrap_hton)
+ {
+ st_mrn_wrap_hton *wrap_hton, *tmp_wrap_hton;
+ tmp_wrap_hton = NULL;
+ wrap_hton = slot_data->first_wrap_hton;
+ while (wrap_hton)
+ {
+ if (!strcmp(wrap_hton->path, name))
+ {
+ /* found */
+ wrap_handlerton = wrap_hton->hton;
+ if (tmp_wrap_hton)
+ tmp_wrap_hton->next = wrap_hton->next;
+ else
+ slot_data->first_wrap_hton = wrap_hton->next;
+ free(wrap_hton);
+ break;
+ }
+ tmp_wrap_hton = wrap_hton;
+ wrap_hton = wrap_hton->next;
+ }
+ }
+
+ if (!wrap_handlerton) {
+ bool open_table_to_get_wrap_handlerton = true;
+ if (mapper.is_internal_table_name()) {
+ open_table_to_get_wrap_handlerton = false;
+ }
+ if (open_table_to_get_wrap_handlerton) {
+ TABLE_LIST table_list;
+ LEX_CSTRING db_name= { mapper.db_name(), strlen(mapper.db_name()) };
+ LEX_CSTRING table_name= { mapper.mysql_table_name(), strlen(mapper.mysql_table_name()) };
+
+ table_list.init_one_table(&db_name, &table_name, 0, TL_WRITE);
+ mrn_open_mutex_lock(NULL);
+ TABLE_SHARE *tmp_table_share =
+ mrn_create_tmp_table_share(&table_list, name, &error);
+ error = 0;
+ mrn_open_mutex_unlock(NULL);
+ if (tmp_table_share) {
+ TABLE tmp_table;
+ tmp_table.s = tmp_table_share;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ tmp_table.part_info = NULL;
+#endif
+ MRN_SHARE *tmp_share = mrn_get_share(name, &tmp_table, &error);
+ if (tmp_share) {
+ wrap_handlerton = tmp_share->hton;
+ mrn_free_long_term_share(tmp_share->long_term_share);
+ tmp_share->long_term_share = NULL;
+ mrn_free_share(tmp_share);
+ }
+ mrn_open_mutex_lock(NULL);
+ mrn_free_tmp_table_share(tmp_table_share);
+ mrn_open_mutex_unlock(NULL);
+ if (error) {
+ DBUG_RETURN(error);
+ }
+ }
+ }
+ }
+
+ if (wrap_handlerton)
+ {
+ error = wrapper_delete_table(name, wrap_handlerton, mapper.table_name());
+ }
+
+ if (!error)
+ {
+ error = generic_delete_table(name, mapper.table_name());
+ }
+
+ if (!error) {
+ error = operations_->clear(name, strlen(name));
+ }
+
+ DBUG_RETURN(error);
+}
+
+void ha_mroonga::wrapper_set_keys_in_use()
+{
+ uint i, j;
+ MRN_DBUG_ENTER_METHOD();
+ mrn::AutoIncrementValueLock lock_(table_share);
+ table_share->keys_in_use.set_prefix(table_share->keys);
+ share->disable_keys = false;
+ for (i = 0; i < table_share->keys; i++) {
+ j = share->wrap_key_nr[i];
+ if (j < MAX_KEY) {
+ if (!share->wrap_table_share->keys_in_use.is_set(j)) {
+ /* copy bitmap */
+ table_share->keys_in_use.clear_bit(i);
+ share->disable_keys = true;
+ }
+ } else {
+ if (!grn_index_tables || !grn_index_tables[i]) {
+ /* disabled */
+ table_share->keys_in_use.clear_bit(i);
+ share->disable_keys = true;
+ }
+ }
+ }
+ table_share->keys_for_keyread.set_prefix(table_share->keys);
+ table_share->keys_for_keyread.intersect(table_share->keys_in_use);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_set_keys_in_use()
+{
+ uint i;
+ MRN_DBUG_ENTER_METHOD();
+ mrn::AutoIncrementValueLock lock_(table_share);
+ table_share->keys_in_use.set_prefix(table_share->keys);
+ share->disable_keys = false;
+ for (i = 0; i < table_share->keys; i++) {
+ if (i == table_share->primary_key) {
+ continue;
+ }
+ if (!grn_index_tables[i]) {
+ /* disabled */
+ table_share->keys_in_use.clear_bit(i);
+ DBUG_PRINT("info", ("mroonga: key %u disabled", i));
+ share->disable_keys = true;
+ }
+ }
+ table_share->keys_for_keyread.set_prefix(table_share->keys);
+ table_share->keys_for_keyread.intersect(table_share->keys_in_use);
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::wrapper_info(uint flag)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->info(flag);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (flag & HA_STATUS_ERRKEY) {
+ errkey = wrap_handler->errkey;
+ memcpy(dup_ref, wrap_handler->dup_ref, wrap_handler->ref_length);
+ }
+ if (flag & HA_STATUS_TIME) {
+ stats.update_time = wrap_handler->stats.update_time;
+ }
+ if (flag & HA_STATUS_CONST) {
+ stats.max_data_file_length = wrap_handler->stats.max_data_file_length;
+ stats.create_time = wrap_handler->stats.create_time;
+ stats.block_size = wrap_handler->stats.block_size;
+ wrapper_set_keys_in_use();
+ }
+ if (flag & HA_STATUS_VARIABLE) {
+ stats.data_file_length = wrap_handler->stats.data_file_length;
+ stats.index_file_length = wrap_handler->stats.index_file_length;
+ stats.records = wrap_handler->stats.records;
+ stats.mean_rec_length = wrap_handler->stats.mean_rec_length;
+ stats.check_time = wrap_handler->stats.check_time;
+ }
+ if (flag & HA_STATUS_AUTO) {
+ stats.auto_increment_value = wrap_handler->stats.auto_increment_value;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_info(uint flag)
+{
+ MRN_DBUG_ENTER_METHOD();
+ mrn_change_encoding(ctx, NULL);
+
+ if (flag & (HA_STATUS_ERRKEY | HA_STATUS_NO_LOCK)) {
+ errkey = dup_key;
+ }
+
+ if ((flag & HA_STATUS_AUTO) && table->found_next_number_field) {
+ THD *thd = ha_thd();
+ ulonglong nb_reserved_values;
+ bool next_number_field_is_null = !table->next_number_field;
+ mrn::ExternalLock mrn_external_lock(ha_thd(), this,
+ mrn_lock_type == F_UNLCK ?
+ F_RDLCK : F_UNLCK);
+ if (mrn_external_lock.error()) {
+ DBUG_RETURN(mrn_external_lock.error());
+ }
+ if (next_number_field_is_null) {
+ table->next_number_field = table->found_next_number_field;
+ }
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ {
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ unsigned long auto_increment_offset, auto_increment_increment;
+ MRN_THD_GET_AUTOINC(thd, &auto_increment_offset,
+ &auto_increment_increment);
+ storage_get_auto_increment(auto_increment_offset,
+ auto_increment_increment, 1,
+ &stats.auto_increment_value,
+ &nb_reserved_values);
+ }
+ if (next_number_field_is_null) {
+ table->next_number_field = NULL;
+ }
+ }
+
+ if (flag & HA_STATUS_CONST) {
+ storage_set_keys_in_use();
+ }
+
+ if (flag & HA_STATUS_VARIABLE) {
+ storage_info_variable();
+ }
+
+ DBUG_RETURN(0);
+}
+
+void ha_mroonga::storage_info_variable()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ storage_info_variable_records();
+ storage_info_variable_data_file_length();
+
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_info_variable_records()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ stats.records = grn_table_size(ctx, grn_table);
+
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_info_variable_data_file_length()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ stats.data_file_length = 0;
+ stats.data_file_length += file_size(grn_obj_path(ctx, grn_table));
+ grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY);
+ grn_table_columns(ctx, grn_table, NULL, 0, (grn_obj *)columns);
+ /* grn_id id __attribute__((unused)); */
+ grn_id *column_id;
+ GRN_HASH_EACH(ctx, columns, id, &column_id, NULL, NULL, {
+ grn_obj *column = grn_ctx_at(ctx, *column_id);
+ stats.data_file_length += file_size(grn_obj_path(ctx, column));
+ grn_obj_unlink(ctx, column);
+ });
+ grn_hash_close(ctx, columns);
+
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::info(uint flag)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_info(flag);
+ } else {
+ error = storage_info(flag);
+ }
+ DBUG_RETURN(error);
+}
+
+uint ha_mroonga::wrapper_lock_count() const
+{
+ uint lock_count;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ lock_count = wrap_handler->lock_count();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(lock_count);
+}
+
+uint ha_mroonga::storage_lock_count() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(1);
+}
+
+uint ha_mroonga::lock_count() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_lock_count();
+ } else {
+ error = storage_lock_count();
+ }
+ DBUG_RETURN(error);
+}
+
+THR_LOCK_DATA **ha_mroonga::wrapper_store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ to = wrap_handler->store_lock(thd, to, lock_type);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(to);
+}
+
+THR_LOCK_DATA **ha_mroonga::storage_store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (lock_type != TL_IGNORE && thr_lock_data.type == TL_UNLOCK) {
+ if (!thd_in_lock_tables(thd)) {
+ if (lock_type == TL_READ_NO_INSERT) {
+ lock_type = TL_READ;
+ } else if (lock_type >= TL_WRITE_CONCURRENT_INSERT &&
+ lock_type <= TL_WRITE && !thd_tablespace_op(thd)) {
+ lock_type = TL_WRITE_ALLOW_WRITE;
+ }
+ }
+
+ thr_lock_data.type = lock_type;
+ }
+ *to++ = &thr_lock_data;
+ DBUG_RETURN(to);
+}
+
+THR_LOCK_DATA **ha_mroonga::store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info", ("mroonga: lock_type=%s",
+ mrn_inspect_thr_lock_type(lock_type)));
+ if (share->wrapper_mode)
+ to = wrapper_store_lock(thd, to, lock_type);
+ else
+ to = storage_store_lock(thd, to, lock_type);
+ DBUG_RETURN(to);
+}
+
+int ha_mroonga::wrapper_external_lock(THD *thd, int lock_type)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_external_lock(thd, lock_type);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_external_lock(THD *thd, int lock_type)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::external_lock(THD *thd, int lock_type)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ mrn_lock_type = lock_type;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_external_lock(thd, lock_type);
+ } else {
+ error = storage_external_lock(thd, lock_type);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_rnd_init(bool scan)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_rnd_init(scan);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_rnd_init(bool scan)
+{
+ MRN_DBUG_ENTER_METHOD();
+ mrn_change_encoding(ctx, NULL);
+ cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0, 0, -1, 0);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::rnd_init(bool scan)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_rnd_init(scan);
+ } else {
+ error = storage_rnd_init(scan);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_rnd_end()
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_rnd_end();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_rnd_end()
+{
+ MRN_DBUG_ENTER_METHOD();
+ clear_cursor();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::rnd_end()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_rnd_end();
+ } else {
+ error = storage_rnd_end();
+ }
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HANDLER_RECORDS_RETURN_ERROR
+int ha_mroonga::wrapper_records(ha_rows *num_rows)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_records(num_rows);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_records(ha_rows *num_rows)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = handler::records(num_rows);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::records(ha_rows *num_rows)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode) {
+ error = wrapper_records(num_rows);
+ } else {
+ error = storage_records(num_rows);
+ }
+ DBUG_RETURN(error);
+}
+#else
+ha_rows ha_mroonga::wrapper_records()
+{
+ ha_rows num_rows;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ num_rows = wrap_handler->records();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(num_rows);
+}
+
+ha_rows ha_mroonga::storage_records()
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows num_rows = handler::records();
+ DBUG_RETURN(num_rows);
+}
+
+ha_rows ha_mroonga::records()
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows num_rows;
+ if (share->wrapper_mode) {
+ num_rows = wrapper_records();
+ } else {
+ num_rows = storage_records();
+ }
+ DBUG_RETURN(num_rows);
+}
+#endif
+
+int ha_mroonga::wrapper_rnd_next(uchar *buf)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_RND_NEXT
+ error = wrap_handler->ha_rnd_next(buf);
+#else
+ error = wrap_handler->rnd_next(buf);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_rnd_next(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::rnd_next(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_rnd_next(buf);
+ } else {
+ error = storage_rnd_next(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_rnd_pos(uchar *buf, uchar *pos)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_HAVE_HA_RND_POS
+ error = wrap_handler->ha_rnd_pos(buf, pos);
+#else
+ error = wrap_handler->rnd_pos(buf, pos);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_rnd_pos(uchar *buf, uchar *pos)
+{
+ MRN_DBUG_ENTER_METHOD();
+ record_id = *((grn_id*) pos);
+ storage_store_fields(buf, record_id);
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::rnd_pos(uchar *buf, uchar *pos)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_rnd_pos(buf, pos);
+ } else {
+ error = storage_rnd_pos(buf, pos);
+ }
+ DBUG_RETURN(error);
+}
+
+void ha_mroonga::wrapper_position(const uchar *record)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->ref = ref;
+ wrap_handler->position(record);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_position(const uchar *record)
+{
+ MRN_DBUG_ENTER_METHOD();
+ memcpy(ref, &record_id, sizeof(grn_id));
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::position(const uchar *record)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ wrapper_position(record);
+ else
+ storage_position(record);
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::generic_extra(enum ha_extra_function operation)
+{
+ MRN_DBUG_ENTER_METHOD();
+ switch (operation) {
+ case HA_EXTRA_IGNORE_DUP_KEY:
+ ignoring_duplicated_key = true;
+ break;
+ case HA_EXTRA_NO_IGNORE_DUP_KEY:
+ ignoring_duplicated_key = false;
+ break;
+ case HA_EXTRA_WRITE_CAN_REPLACE:
+ replacing_ = true;
+ break;
+ case HA_EXTRA_WRITE_CANNOT_REPLACE:
+ replacing_ = false;
+ break;
+ case HA_EXTRA_INSERT_WITH_UPDATE:
+ inserting_with_update = true;
+ break;
+ case HA_EXTRA_KEYREAD:
+ ignoring_no_key_columns = true;
+ break;
+ case HA_EXTRA_NO_KEYREAD:
+ ignoring_no_key_columns = false;
+ break;
+ default:
+ break;
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::wrapper_extra(enum ha_extra_function operation)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->extra(operation);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_extra(enum ha_extra_function operation)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::extra(enum ha_extra_function operation)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info",
+ ("mroonga: this=%p; extra-operation=%s",
+ this, mrn_inspect_extra_function(operation)));
+ if (share->wrapper_mode) {
+ if ((error = wrapper_extra(operation)))
+ DBUG_RETURN(error);
+ } else {
+ if ((error = storage_extra(operation)))
+ DBUG_RETURN(error);
+ }
+ error = generic_extra(operation);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_extra_opt(enum ha_extra_function operation,
+ ulong cache_size)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->extra_opt(operation, cache_size);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_extra_opt(enum ha_extra_function operation,
+ ulong cache_size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::extra_opt(enum ha_extra_function operation, ulong cache_size)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ if ((error = wrapper_extra_opt(operation, cache_size)))
+ DBUG_RETURN(error);
+ } else {
+ if ((error = storage_extra_opt(operation, cache_size)))
+ DBUG_RETURN(error);
+ }
+ error = generic_extra(operation);
+ DBUG_RETURN(error);
+}
+
+bool ha_mroonga::wrapper_is_target_index(KEY *key_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool target_index =
+ (key_info->algorithm == HA_KEY_ALG_FULLTEXT) || mrn_is_geo_key(key_info);
+ DBUG_PRINT("info", ("mroonga: %s", target_index ? "true" : "false"));
+ DBUG_RETURN(target_index);
+}
+
+bool ha_mroonga::wrapper_have_target_index()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have_target_index = false;
+
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->key_info[i]);
+
+ if (wrapper_is_target_index(key_info)) {
+ have_target_index = true;
+ break;
+ }
+ }
+
+ DBUG_PRINT("info", ("mroonga: %s", have_target_index ? "true" : "false"));
+ DBUG_RETURN(have_target_index);
+}
+
+int ha_mroonga::wrapper_write_row(const uchar *buf)
+{
+ int error = 0;
+ THD *thd = ha_thd();
+
+ MRN_DBUG_ENTER_METHOD();
+
+ mrn::Operation operation(operations_,
+ "write",
+ table->s->table_name.str,
+ table->s->table_name.length);
+
+ operation.record_target(record_id);
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ tmp_disable_binlog(thd);
+ error = wrap_handler->ha_write_row(buf);
+ insert_id_for_cur_row = wrap_handler->insert_id_for_cur_row;
+ reenable_binlog(thd);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+ if (!error && wrapper_have_target_index()) {
+ error = wrapper_write_row_index(buf);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_write_row_index(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ mrn_change_encoding(ctx, NULL);
+ GRN_BULK_REWIND(&key_buffer);
+ grn_bulk_space(ctx, &key_buffer, table->key_info->key_length);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&key_buffer)),
+ buf,
+ &(table->key_info[table_share->primary_key]),
+ table->key_info[table_share->primary_key].key_length);
+
+ int added;
+ grn_id record_id;
+ record_id = grn_table_add(ctx, grn_table,
+ GRN_TEXT_VALUE(&key_buffer),
+ GRN_TEXT_LEN(&key_buffer),
+ &added);
+ if (record_id == GRN_ID_NIL) {
+ DBUG_PRINT("info", ("mroonga: failed to add a new record into groonga"));
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to add a new record into groonga: key=<%.*s>",
+ (int)GRN_TEXT_LEN(&key_buffer),
+ GRN_TEXT_VALUE(&key_buffer));
+ error = ER_ERROR_ON_WRITE;
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING, error,
+ error_message);
+ DBUG_RETURN(0);
+ }
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->key_info[i]);
+
+ if (!(wrapper_is_target_index(key_info))) {
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ continue;
+ }
+
+ uint j;
+ for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
+ Field *field = key_info->key_part[j].field;
+
+ if (field->is_null())
+ continue;
+
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ goto err;
+ error = generic_store_bulk(field, &new_value_buffer);
+ if (error) {
+ my_message(error,
+ "mroonga: wrapper: "
+ "failed to get new value for updating index.",
+ MYF(0));
+ goto err;
+ }
+
+ grn_rc rc;
+ rc = grn_column_index_update(ctx, index_column, record_id, j + 1,
+ NULL, &new_value_buffer);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+ }
+err:
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_write_row(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool unique_indexes_are_processed = false;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ mrn::Operation operation(operations_,
+ "write",
+ table->s->table_name.str,
+ table->s->table_name.length);
+
+ THD *thd = ha_thd();
+ int i;
+ int n_columns = table->s->fields;
+
+ if (table->next_number_field && buf == table->record[0])
+ {
+ if ((error = update_auto_increment()))
+ DBUG_RETURN(error);
+ }
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+
+ if (field->is_null()) continue;
+
+ mrn::ColumnName column_name(field->field_name);
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ WARN_DATA_TRUNCATED,
+ MRN_GET_ERR_MSG(WARN_DATA_TRUNCATED),
+ MRN_COLUMN_NAME_ID,
+ MRN_GET_CURRENT_ROW_FOR_WARNING(thd));
+ if (MRN_ABORT_ON_WARNING(thd)) {
+ DBUG_RETURN(ER_DATA_TOO_LONG);
+ }
+ }
+ }
+
+ uint pkey_nr = table->s->primary_key;
+
+ int added = 0;
+ {
+ mrn::Lock lock(&(share->record_mutex), have_unique_index());
+ if ((error = storage_write_row_unique_indexes(buf)))
+ {
+ DBUG_RETURN(error);
+ }
+ unique_indexes_are_processed = true;
+
+ char *pkey;
+ int pkey_size;
+ GRN_BULK_REWIND(&key_buffer);
+ if (pkey_nr == MAX_INDEXES) {
+ pkey = NULL;
+ pkey_size = 0;
+ } else {
+ KEY *key_info = &(table->key_info[pkey_nr]);
+ if (KEY_N_KEY_PARTS(key_info) == 1) {
+ Field *pkey_field = key_info->key_part[0].field;
+ error = mrn_change_encoding(ctx, pkey_field->charset());
+ if (error) {
+ DBUG_RETURN(error);
+ }
+ generic_store_bulk(pkey_field, &key_buffer);
+ pkey = GRN_TEXT_VALUE(&key_buffer);
+ pkey_size = GRN_TEXT_LEN(&key_buffer);
+ } else {
+ mrn_change_encoding(ctx, NULL);
+ uchar key[MRN_MAX_KEY_SIZE];
+ key_copy(key, buf, key_info, key_info->key_length);
+ grn_bulk_reserve(ctx, &key_buffer, MRN_MAX_KEY_SIZE);
+ pkey = GRN_TEXT_VALUE(&key_buffer);
+ storage_encode_multiple_column_key(key_info,
+ key, key_info->key_length,
+ (uchar *)pkey, (uint *)&pkey_size);
+ }
+ }
+
+ if (grn_table->header.type != GRN_TABLE_NO_KEY && pkey_size == 0) {
+ my_message(ER_ERROR_ON_WRITE, "primary key is empty", MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+
+ record_id = grn_table_add(ctx, grn_table, pkey, pkey_size, &added);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ if (!added) {
+ // duplicated error
+ error = HA_ERR_FOUND_DUPP_KEY;
+ memcpy(dup_ref, &record_id, sizeof(grn_id));
+ dup_key = pkey_nr;
+ if (!ignoring_duplicated_key) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "duplicated id on insert: update primary key: <%.*s>",
+ pkey_size, pkey);
+ }
+ uint j;
+ for (j = 0; j < table->s->keys; j++) {
+ if (j == pkey_nr) {
+ continue;
+ }
+ KEY *key_info = &table->key_info[j];
+ if (key_info->flags & HA_NOSAME) {
+ grn_table_delete_by_id(ctx, grn_index_tables[j], key_id[j]);
+ }
+ }
+ DBUG_RETURN(error);
+ }
+ operation.record_target(record_id);
+ }
+
+ grn_obj colbuf;
+ GRN_VOID_INIT(&colbuf);
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+
+ if (field->is_null())
+ continue;
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+
+ mrn::ColumnName column_name(field->field_name);
+
+#ifdef MRN_HAVE_SPATIAL
+ bool is_null_geometry_value =
+ field->real_type() == MYSQL_TYPE_GEOMETRY &&
+ static_cast<Field_blob *>(field)->get_length() == 0;
+ if (is_null_geometry_value) {
+ continue;
+ }
+#endif
+
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
+ continue;
+ }
+
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error) {
+ GRN_OBJ_FIN(ctx, &colbuf);
+ goto err;
+ }
+ error = generic_store_bulk(field, &colbuf);
+ if (error) {
+ GRN_OBJ_FIN(ctx, &colbuf);
+ goto err;
+ }
+
+ grn_obj *column = grn_columns[i];
+ if (is_foreign_key_field(table->s->table_name.str, field->field_name.str)) {
+ grn_obj value;
+ GRN_RECORD_INIT(&value, 0, grn_obj_get_range(ctx, column));
+ grn_rc cast_rc = grn_obj_cast(ctx, &colbuf, &value, GRN_FALSE);
+ if (cast_rc != GRN_SUCCESS) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, &colbuf);
+ error = HA_ERR_NO_REFERENCED_ROW;
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "foreign record doesn't exist: <%s>:<%.*s>",
+ field->field_name.str,
+ static_cast<int>(GRN_TEXT_LEN(&inspected)),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &value);
+ GRN_OBJ_FIN(ctx, &colbuf);
+ GRN_OBJ_FIN(ctx, &inspected);
+ goto err;
+ }
+ grn_obj_set_value(ctx, column, record_id, &value, GRN_OBJ_SET);
+ } else {
+ if (added && is_grn_zero_column_value(column, &colbuf)) {
+ // WORKAROUND: groonga can't index newly added '0' value for
+ // fix size column. So we add non-'0' value first then add
+ // real '0' value again. It will be removed when groonga
+ // supports 'null' value.
+ char *bytes = GRN_BULK_HEAD(&colbuf);
+ bytes[0] = '\1';
+ grn_obj_set_value(ctx, column, record_id, &colbuf, GRN_OBJ_SET);
+ bytes[0] = '\0';
+ }
+ grn_obj_set_value(ctx, column, record_id, &colbuf, GRN_OBJ_SET);
+ }
+ if (ctx->rc) {
+ GRN_OBJ_FIN(ctx, &colbuf);
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ error = ER_ERROR_ON_WRITE;
+ goto err;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &colbuf);
+
+ error = storage_write_row_multiple_column_indexes(buf, record_id);
+ if (error) {
+ goto err;
+ }
+
+ // for UDF last_insert_grn_id()
+ st_mrn_slot_data *slot_data;
+ slot_data = mrn_get_slot_data(thd, true);
+ if (slot_data == NULL) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto err;
+ }
+ slot_data->last_insert_record_id = record_id;
+
+ grn_db_touch(ctx, grn_ctx_db(ctx));
+
+ if (table->found_next_number_field &&
+ !table->s->next_number_keypart) {
+ Field_num *field = (Field_num *) table->found_next_number_field;
+ if (field->unsigned_flag || field->val_int() > 0) {
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ ulonglong nr = (ulonglong) field->val_int();
+ if (!long_term_share->auto_inc_inited) {
+ storage_info(HA_STATUS_AUTO);
+ }
+ {
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ if (long_term_share->auto_inc_value <= nr) {
+ long_term_share->auto_inc_value = nr + 1;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ }
+ }
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ if (unique_indexes_are_processed) {
+ uint j;
+ for (j = 0; j < table->s->keys; j++) {
+ if (j == pkey_nr) {
+ continue;
+ }
+ KEY *key_info = &table->key_info[j];
+ if (key_info->flags & HA_NOSAME) {
+ grn_table_delete_by_id(ctx, grn_index_tables[j], key_id[j]);
+ }
+ }
+ }
+ grn_table_delete_by_id(ctx, grn_table, record_id);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_write_row_multiple_column_index(const uchar *buf,
+ grn_id record_id,
+ KEY *key_info,
+ grn_obj *index_column)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ mrn_change_encoding(ctx, NULL);
+ GRN_BULK_REWIND(&key_buffer);
+ grn_bulk_space(ctx, &key_buffer, key_info->key_length);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&key_buffer)),
+ buf,
+ key_info,
+ key_info->key_length);
+ GRN_BULK_REWIND(&encoded_key_buffer);
+ grn_bulk_reserve(ctx, &encoded_key_buffer, MRN_MAX_KEY_SIZE);
+ uint encoded_key_length;
+ storage_encode_multiple_column_key(key_info,
+ (uchar *)(GRN_TEXT_VALUE(&key_buffer)),
+ key_info->key_length,
+ (uchar *)(GRN_TEXT_VALUE(&encoded_key_buffer)),
+ &encoded_key_length);
+ grn_bulk_space(ctx, &encoded_key_buffer, encoded_key_length);
+ DBUG_PRINT("info", ("mroonga: key_length=%u", key_info->key_length));
+ DBUG_PRINT("info", ("mroonga: encoded_key_length=%u", encoded_key_length));
+
+ grn_rc rc;
+ rc = grn_column_index_update(ctx, index_column, record_id, 1, NULL,
+ &encoded_key_buffer);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_write_row_multiple_column_indexes(const uchar *buf,
+ grn_id record_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &(table->key_info[i]);
+
+ if (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT)) {
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ continue;
+ }
+
+ if ((error = storage_write_row_multiple_column_index(buf,
+ record_id,
+ key_info,
+ index_column)))
+ {
+ goto err;
+ }
+ }
+
+err:
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_write_row_unique_index(const uchar *buf,
+ KEY *key_info,
+ grn_obj *index_table,
+ grn_obj *index_column,
+ grn_id *key_id)
+{
+ char *ukey = NULL;
+ int error, ukey_size = 0;
+ MRN_DBUG_ENTER_METHOD();
+ GRN_BULK_REWIND(&key_buffer);
+ if (KEY_N_KEY_PARTS(key_info) == 1) {
+ Field *ukey_field = key_info->key_part[0].field;
+ error = mrn_change_encoding(ctx, ukey_field->charset());
+ if (error) {
+ DBUG_RETURN(error);
+ }
+ generic_store_bulk(ukey_field, &key_buffer);
+ ukey = GRN_TEXT_VALUE(&key_buffer);
+ ukey_size = GRN_TEXT_LEN(&key_buffer);
+ } else {
+ mrn_change_encoding(ctx, NULL);
+ uchar key[MRN_MAX_KEY_SIZE];
+ key_copy(key, buf, key_info, key_info->key_length);
+ grn_bulk_reserve(ctx, &key_buffer, MRN_MAX_KEY_SIZE);
+ ukey = GRN_TEXT_VALUE(&key_buffer);
+ storage_encode_multiple_column_key(key_info,
+ key, key_info->key_length,
+ (uchar *)(ukey), (uint *)&ukey_size);
+ }
+
+ int added;
+ *key_id = grn_table_add(ctx, index_table, ukey, ukey_size, &added);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ if (!added) {
+ // duplicated error
+ error = HA_ERR_FOUND_DUPP_KEY;
+ grn_id duplicated_record_id = GRN_ID_NIL;
+ {
+ grn_table_cursor *table_cursor;
+ table_cursor = grn_table_cursor_open(ctx, index_table,
+ ukey, ukey_size,
+ ukey, ukey_size,
+ 0, -1, 0);
+ if (table_cursor) {
+ grn_obj *index_cursor;
+ index_cursor = grn_index_cursor_open(ctx, table_cursor, index_column,
+ GRN_ID_NIL, GRN_ID_MAX, 0);
+ if (index_cursor) {
+ grn_posting *posting;
+ posting = grn_index_cursor_next(ctx, index_cursor, NULL);
+ if (posting) {
+ duplicated_record_id = posting->rid;
+ }
+ }
+ grn_obj_unlink(ctx, index_cursor);
+ }
+ grn_table_cursor_close(ctx, table_cursor);
+ }
+ memcpy(dup_ref, &duplicated_record_id, sizeof(grn_id));
+ if (!ignoring_duplicated_key) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "duplicated id on insert: update unique index: <%.*s>",
+ ukey_size, ukey);
+ }
+ DBUG_RETURN(error);
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::storage_write_row_unique_indexes(const uchar *buf)
+{
+ int error = 0;
+ uint i;
+ uint n_keys = table->s->keys;
+ MRN_DBUG_ENTER_METHOD();
+
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &table->key_info[i];
+
+ if (!(key_info->flags & HA_NOSAME)) {
+ continue;
+ }
+
+ grn_obj *index_table = grn_index_tables[i];
+ if (!index_table) {
+ continue;
+ }
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ continue;
+ }
+
+ if ((error = storage_write_row_unique_index(buf, key_info,
+ index_table, index_column,
+ &key_id[i])))
+ {
+ if (error == HA_ERR_FOUND_DUPP_KEY)
+ {
+ dup_key = i;
+ }
+ goto err;
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ if (i) {
+ mrn_change_encoding(ctx, NULL);
+ do {
+ i--;
+
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &table->key_info[i];
+ if (!(key_info->flags & HA_NOSAME)) {
+ continue;
+ }
+
+ if (key_info->flags & HA_NOSAME) {
+ grn_table_delete_by_id(ctx, grn_index_tables[i], key_id[i]);
+ }
+ } while (i);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::write_row(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_write_row(buf);
+ } else {
+ error = storage_write_row(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_get_record_id(uchar *data, grn_id *record_id,
+ const char *context)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ grn_obj key;
+ GRN_TEXT_INIT(&key, 0);
+
+ mrn_change_encoding(ctx, NULL);
+ grn_bulk_space(ctx, &key, table->key_info->key_length);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&key)),
+ data,
+ &(table->key_info[table_share->primary_key]),
+ table->key_info[table_share->primary_key].key_length);
+
+ *record_id = grn_table_get(ctx, grn_table,
+ GRN_TEXT_VALUE(&key), GRN_TEXT_LEN(&key));
+ if (*record_id == GRN_ID_NIL) {
+ DBUG_PRINT("info", ("mroonga: %s", context));
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "%s: key=<%.*s>",
+ context, (int)GRN_TEXT_LEN(&key), GRN_TEXT_VALUE(&key));
+ error = ER_ERROR_ON_WRITE;
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING, error,
+ error_message);
+ }
+ grn_obj_unlink(ctx, &key);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_update_row(const uchar *old_data,
+ const uchar *new_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ THD *thd = ha_thd();
+
+ mrn::Operation operation(operations_,
+ "update",
+ table->s->table_name.str,
+ table->s->table_name.length);
+
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ tmp_disable_binlog(thd);
+ error = wrap_handler->ha_update_row(old_data, new_data);
+ reenable_binlog(thd);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+ if (!error && wrapper_have_target_index()) {
+ error = wrapper_update_row_index(old_data, new_data);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_update_row_index(const uchar *old_data,
+ const uchar *new_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ mrn_change_encoding(ctx, NULL);
+ KEY *key_info = &(table->key_info[table_share->primary_key]);
+ GRN_BULK_REWIND(&key_buffer);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&key_buffer)),
+ new_data,
+ key_info, key_info->key_length);
+ int added;
+ grn_id new_record_id;
+ new_record_id = grn_table_add(ctx, grn_table,
+ GRN_TEXT_VALUE(&key_buffer),
+ table->key_info->key_length,
+ &added);
+ if (new_record_id == GRN_ID_NIL) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to get new record ID for updating from groonga: key=<%.*s>",
+ (int)GRN_TEXT_LEN(&key_buffer), GRN_TEXT_VALUE(&key_buffer));
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, error_message, MYF(0));
+ DBUG_RETURN(error);
+ }
+
+ grn_id old_record_id;
+ my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(old_data, table->record[0]);
+
+ error = wrapper_get_record_id((uchar *)old_data, &old_record_id,
+ "failed to get old record ID "
+ "for updating from groonga");
+ if (error) {
+ DBUG_RETURN(0);
+ }
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->key_info[i]);
+
+ if (!(wrapper_is_target_index(key_info))) {
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ /* disable keys */
+ continue;
+ }
+
+ uint j;
+ for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
+ Field *field = key_info->key_part[j].field;
+
+ generic_store_bulk(field, &new_value_buffer);
+
+ field->move_field_offset(ptr_diff);
+ generic_store_bulk(field, &old_value_buffer);
+ field->move_field_offset(-ptr_diff);
+
+ grn_rc rc;
+ if (old_record_id == new_record_id) {
+ if (added) {
+ rc = grn_column_index_update(ctx, index_column, old_record_id, j + 1,
+ &old_value_buffer, NULL);
+ if (!rc) {
+ rc = grn_column_index_update(ctx, index_column, new_record_id, j + 1,
+ NULL, &new_value_buffer);
+ }
+ } else {
+ rc = grn_column_index_update(ctx, index_column, old_record_id, j + 1,
+ &old_value_buffer, &new_value_buffer);
+ }
+ } else {
+ rc = grn_column_index_update(ctx, index_column, old_record_id, j + 1,
+ &old_value_buffer, NULL);
+ if (!rc) {
+ rc = grn_column_index_update(ctx, index_column, new_record_id, j + 1,
+ NULL, &new_value_buffer);
+ }
+ if (!rc) {
+ rc = grn_table_delete_by_id(ctx, grn_table, old_record_id);
+ }
+ }
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+ }
+err:
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_update_row(const uchar *old_data,
+ const uchar *new_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ mrn::Operation operation(operations_,
+ "update",
+ table->s->table_name.str,
+ table->s->table_name.length);
+ operation.record_target(record_id);
+
+ grn_obj colbuf;
+ int i;
+ uint j;
+ int n_columns = table->s->fields;
+ THD *thd = ha_thd();
+
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+
+ if (!bitmap_is_set(table->write_set, field->field_index))
+ continue;
+
+ if (field->is_null())
+ continue;
+
+ {
+ mrn::ColumnName column_name(field->field_name);
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ WARN_DATA_TRUNCATED, MRN_GET_ERR_MSG(WARN_DATA_TRUNCATED),
+ MRN_COLUMN_NAME_ID,
+ MRN_GET_CURRENT_ROW_FOR_WARNING(thd));
+ if (MRN_ABORT_ON_WARNING(thd)) {
+ DBUG_RETURN(ER_DATA_TOO_LONG);
+ }
+ }
+ }
+
+ if (!is_foreign_key_field(table->s->table_name.str, field->field_name.str))
+ continue;
+
+ {
+ grn_obj *column = grn_columns[i];
+ grn_obj new_value;
+ GRN_VOID_INIT(&new_value);
+ {
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ generic_store_bulk(field, &new_value);
+ }
+ grn_obj casted_value;
+ GRN_RECORD_INIT(&casted_value, 0, grn_obj_get_range(ctx, column));
+ grn_rc cast_rc = grn_obj_cast(ctx, &new_value, &casted_value, GRN_FALSE);
+ GRN_OBJ_FIN(ctx, &casted_value);
+ if (cast_rc != GRN_SUCCESS) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, &new_value);
+ GRN_OBJ_FIN(ctx, &new_value);
+ error = HA_ERR_NO_REFERENCED_ROW;
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "foreign record doesn't exist: <%s>:<%.*s>",
+ field->field_name.str,
+ static_cast<int>(GRN_TEXT_LEN(&inspected)),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ DBUG_RETURN(error);
+ }
+ GRN_OBJ_FIN(ctx, &new_value);
+ }
+ }
+
+ KEY *pkey_info = NULL;
+ storage_store_fields_for_prep_update(old_data, new_data, record_id);
+ {
+ mrn::Lock lock(&(share->record_mutex), have_unique_index());
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ if ((error = storage_prepare_delete_row_unique_indexes(old_data,
+ record_id))) {
+ DBUG_RETURN(error);
+ }
+ if ((error = storage_update_row_unique_indexes(new_data)))
+ {
+ DBUG_RETURN(error);
+ }
+ }
+
+ if (table->s->primary_key != MAX_INDEXES) {
+ pkey_info = &(table->key_info[table->s->primary_key]);
+ }
+ GRN_VOID_INIT(&colbuf);
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+
+ if (bitmap_is_set(table->write_set, field->field_index)) {
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ DBUG_PRINT("info", ("mroonga: update column %d(%d)",i,field->field_index));
+
+ if (field->is_null()) continue;
+
+ mrn::ColumnName column_name(field->field_name);
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name.c_str()) == 0) {
+ continue;
+ }
+
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ goto err;
+
+ bool is_pkey = false;
+ bool on_duplicate_key_update =
+ (inserting_with_update && ignoring_duplicated_key);
+ if (pkey_info && !on_duplicate_key_update) {
+ for (j = 0; j < KEY_N_KEY_PARTS(pkey_info); j++) {
+ Field *pkey_field = pkey_info->key_part[j].field;
+ if (strcmp(pkey_field->field_name.str, column_name.c_str()) == 0) {
+ is_pkey = true;
+ break;
+ }
+ }
+ }
+
+ generic_store_bulk(field, &colbuf);
+ if (is_pkey) {
+ bool is_multiple_column_index = KEY_N_KEY_PARTS(pkey_info) > 1;
+ bool is_same_value;
+ if (is_multiple_column_index) {
+ is_same_value = false;
+ } else {
+ grn_id found_record_id = grn_table_get(ctx,
+ grn_table,
+ GRN_BULK_HEAD(&colbuf),
+ GRN_BULK_VSIZE(&colbuf));
+ is_same_value = (record_id == found_record_id);
+ }
+ if (!is_same_value && !replacing_) {
+ char message[MRN_BUFFER_SIZE];
+ snprintf(message, MRN_BUFFER_SIZE,
+ "data truncated for primary key column: <%s>",
+ column_name.c_str());
+ push_warning(thd, MRN_SEVERITY_WARNING,
+ WARN_DATA_TRUNCATED, message);
+ }
+ continue;
+ }
+
+ grn_obj_set_value(ctx, grn_columns[i], record_id, &colbuf, GRN_OBJ_SET);
+ if (ctx->rc) {
+ grn_obj_unlink(ctx, &colbuf);
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ error = ER_ERROR_ON_WRITE;
+ goto err;
+ }
+ }
+ }
+ grn_obj_unlink(ctx, &colbuf);
+
+ if ((error = storage_update_row_index(old_data, new_data)))
+ {
+ goto err;
+ }
+
+ if ((error = storage_delete_row_unique_indexes()))
+ {
+ DBUG_RETURN(error);
+ }
+
+ grn_db_touch(ctx, grn_ctx_db(ctx));
+
+ if (table->found_next_number_field &&
+ !table->s->next_number_keypart &&
+ new_data == table->record[0]) {
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ Field_num *field = (Field_num *) table->found_next_number_field;
+ if (field->unsigned_flag || field->val_int() > 0) {
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ ulonglong nr = (ulonglong) field->val_int();
+ if (!long_term_share->auto_inc_inited) {
+ storage_info(HA_STATUS_AUTO);
+ }
+ {
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ if (long_term_share->auto_inc_value <= nr) {
+ long_term_share->auto_inc_value = nr + 1;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ }
+ }
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ for (j = 0; j < table->s->keys; j++) {
+ if (j == table->s->primary_key) {
+ continue;
+ }
+ KEY *key_info = &table->key_info[j];
+ if ((key_info->flags & HA_NOSAME) && key_id[j] != GRN_ID_NIL) {
+ grn_table_delete_by_id(ctx, grn_index_tables[j], key_id[j]);
+ }
+ }
+
+ if (!error && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE) {
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ long_term_share->auto_inc_value = 0;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ long_term_share->auto_inc_inited = false;
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_update_row_index(const uchar *old_data,
+ const uchar *new_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ grn_obj old_key, old_encoded_key, new_key, new_encoded_key;
+ GRN_TEXT_INIT(&old_key, 0);
+ GRN_TEXT_INIT(&old_encoded_key, 0);
+ GRN_TEXT_INIT(&new_key, 0);
+ GRN_TEXT_INIT(&new_encoded_key, 0);
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ uint i;
+ uint n_keys = table->s->keys;
+ mrn_change_encoding(ctx, NULL);
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &(table->key_info[i]);
+
+ if (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT)) {
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ /* disable keys */
+ continue;
+ }
+
+ GRN_BULK_REWIND(&old_key);
+ grn_bulk_space(ctx, &old_key, key_info->key_length);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&old_key)),
+ (uchar *)old_data,
+ key_info,
+ key_info->key_length);
+ GRN_BULK_REWIND(&old_encoded_key);
+ grn_bulk_reserve(ctx, &old_encoded_key, MRN_MAX_KEY_SIZE);
+ uint old_encoded_key_length;
+ storage_encode_multiple_column_key(key_info,
+ (uchar *)(GRN_TEXT_VALUE(&old_key)),
+ key_info->key_length,
+ (uchar *)(GRN_TEXT_VALUE(&old_encoded_key)),
+ &old_encoded_key_length);
+ grn_bulk_space(ctx, &old_encoded_key, old_encoded_key_length);
+
+ GRN_BULK_REWIND(&new_key);
+ grn_bulk_space(ctx, &new_key, key_info->key_length);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&new_key)),
+ (uchar *)new_data,
+ key_info,
+ key_info->key_length);
+ GRN_BULK_REWIND(&new_encoded_key);
+ grn_bulk_reserve(ctx, &new_encoded_key, MRN_MAX_KEY_SIZE);
+ uint new_encoded_key_length;
+ storage_encode_multiple_column_key(key_info,
+ (uchar *)(GRN_TEXT_VALUE(&new_key)),
+ key_info->key_length,
+ (uchar *)(GRN_TEXT_VALUE(&new_encoded_key)),
+ &new_encoded_key_length);
+ grn_bulk_space(ctx, &new_encoded_key, new_encoded_key_length);
+
+ grn_rc rc;
+ rc = grn_column_index_update(ctx, index_column, record_id, 1,
+ &old_encoded_key, &new_encoded_key);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+err:
+ grn_obj_unlink(ctx, &old_key);
+ grn_obj_unlink(ctx, &old_encoded_key);
+ grn_obj_unlink(ctx, &new_key);
+ grn_obj_unlink(ctx, &new_encoded_key);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_update_row_unique_indexes(const uchar *new_data)
+{
+ int error;
+ uint i;
+ uint n_keys = table->s->keys;
+ MRN_DBUG_ENTER_METHOD();
+
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &table->key_info[i];
+ if (!(key_info->flags & HA_NOSAME)) {
+ continue;
+ }
+
+ grn_obj *index_table = grn_index_tables[i];
+ if (!index_table) {
+ key_id[i] = GRN_ID_NIL;
+ del_key_id[i] = GRN_ID_NIL;
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ key_id[i] = GRN_ID_NIL;
+ del_key_id[i] = GRN_ID_NIL;
+ continue;
+ }
+
+ if (
+ KEY_N_KEY_PARTS(key_info) == 1 &&
+ !bitmap_is_set(table->write_set,
+ key_info->key_part[0].field->field_index)
+ ) {
+ /* no change */
+ key_id[i] = GRN_ID_NIL;
+ del_key_id[i] = GRN_ID_NIL;
+ continue;
+ }
+
+ if ((error = storage_write_row_unique_index(new_data, key_info,
+ index_table, index_column,
+ &key_id[i])))
+ {
+ if (error == HA_ERR_FOUND_DUPP_KEY)
+ {
+ if (key_id[i] == del_key_id[i]) {
+ /* no change */
+ key_id[i] = GRN_ID_NIL;
+ del_key_id[i] = GRN_ID_NIL;
+ continue;
+ }
+ dup_key = i;
+ DBUG_PRINT("info", ("mroonga: different key ID: %d record ID: %d,%d",
+ i, key_id[i], del_key_id[i]));
+ }
+ goto err;
+ }
+ }
+ DBUG_RETURN(0);
+
+err:
+ if (i) {
+ mrn_change_encoding(ctx, NULL);
+ do {
+ i--;
+ KEY *key_info = &table->key_info[i];
+ if ((key_info->flags & HA_NOSAME) && key_id[i] != GRN_ID_NIL) {
+ grn_table_delete_by_id(ctx, grn_index_tables[i], key_id[i]);
+ }
+ } while (i);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::update_row(const uchar *old_data, const uchar *new_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_update_row(old_data, new_data);
+ } else {
+ error = storage_update_row(old_data, new_data);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_delete_row(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ THD *thd= ha_thd();
+
+ mrn::Operation operation(operations_,
+ "delete",
+ table->s->table_name.str,
+ table->s->table_name.length);
+
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ tmp_disable_binlog(thd);
+ error = wrap_handler->ha_delete_row(buf);
+ reenable_binlog(thd);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+ if (!error && wrapper_have_target_index()) {
+ error = wrapper_delete_row_index(buf);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_delete_row_index(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ mrn_change_encoding(ctx, NULL);
+ grn_id record_id;
+ error = wrapper_get_record_id((uchar *)buf, &record_id,
+ "failed to get record ID "
+ "for deleting from groonga");
+ if (error) {
+ DBUG_RETURN(0);
+ }
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->key_info[i]);
+
+ if (!(wrapper_is_target_index(key_info))) {
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ /* disable keys */
+ continue;
+ }
+
+ uint j;
+ for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
+ Field *field = key_info->key_part[j].field;
+
+ if (field->is_null())
+ continue;
+
+ generic_store_bulk(field, &old_value_buffer);
+ grn_rc rc;
+ rc = grn_column_index_update(ctx, index_column, record_id, j + 1,
+ &old_value_buffer, NULL);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+ }
+err:
+ grn_table_delete_by_id(ctx, grn_table, record_id);
+ if (ctx->rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_delete_row(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(0);
+ }
+
+ mrn::Operation operation(operations_,
+ "delete",
+ table->s->table_name.str,
+ table->s->table_name.length);
+ operation.record_target(record_id);
+
+ {
+ grn_id referencing_child_table_id = GRN_ID_NIL;
+ grn_hash *columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ grn_table_columns(ctx, grn_table, "", 0,
+ reinterpret_cast<grn_obj *>(columns));
+ GRN_HASH_EACH_BEGIN(ctx, columns, cursor, id) {
+ void *key;
+ grn_hash_cursor_get_key(ctx, cursor, &key);
+ grn_id column_id = *static_cast<grn_id *>(key);
+ grn_obj *column = grn_ctx_at(ctx, column_id);
+ if (!column)
+ continue;
+
+ if (column->header.type != GRN_COLUMN_INDEX)
+ continue;
+
+ grn_ii_cursor *ii_cursor =
+ grn_ii_cursor_open(ctx,
+ reinterpret_cast<grn_ii *>(column),
+ record_id,
+ GRN_ID_NIL,
+ GRN_ID_MAX,
+ 0,
+ 0);
+ if (!ii_cursor)
+ continue;
+
+ if (grn_ii_cursor_next(ctx, ii_cursor)) {
+ referencing_child_table_id = grn_obj_get_range(ctx, column);
+ }
+
+ grn_ii_cursor_close(ctx, ii_cursor);
+
+ if (referencing_child_table_id != GRN_ID_NIL)
+ break;
+ } GRN_HASH_EACH_END(ctx, cursor);
+ grn_hash_close(ctx, columns);
+
+ if (referencing_child_table_id != GRN_ID_NIL) {
+ grn_obj *referencing_child_table =
+ grn_ctx_at(ctx, referencing_child_table_id);
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_obj_name(ctx,
+ referencing_child_table,
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ error = HA_ERR_ROW_IS_REFERENCED;
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "one or more child rows exist in <%.*s>",
+ name_size,
+ name);
+ DBUG_RETURN(error);
+ }
+ }
+
+ storage_store_fields_for_prep_update(buf, NULL, record_id);
+ {
+ mrn::Lock lock(&(share->record_mutex), have_unique_index());
+ if ((error = storage_prepare_delete_row_unique_indexes(buf, record_id))) {
+ DBUG_RETURN(error);
+ }
+ mrn_change_encoding(ctx, NULL);
+ grn_table_delete_by_id(ctx, grn_table, record_id);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ if (
+ (error = storage_delete_row_index(buf)) ||
+ (error = storage_delete_row_unique_indexes())
+ ) {
+ DBUG_RETURN(error);
+ }
+ }
+
+ grn_db_touch(ctx, grn_ctx_db(ctx));
+
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::storage_delete_row_index(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ grn_obj key, encoded_key;
+ GRN_TEXT_INIT(&key, 0);
+ GRN_TEXT_INIT(&encoded_key, 0);
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->read_set);
+ uint i;
+ uint n_keys = table->s->keys;
+ mrn_change_encoding(ctx, NULL);
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &(table->key_info[i]);
+
+ if (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT)) {
+ continue;
+ }
+
+ grn_obj *index_column = grn_index_columns[i];
+ if (!index_column) {
+ /* disable keys */
+ continue;
+ }
+
+ GRN_BULK_REWIND(&key);
+ grn_bulk_space(ctx, &key, key_info->key_length);
+ key_copy((uchar *)(GRN_TEXT_VALUE(&key)),
+ (uchar *)buf,
+ key_info,
+ key_info->key_length);
+ GRN_BULK_REWIND(&encoded_key);
+ grn_bulk_reserve(ctx, &encoded_key, MRN_MAX_KEY_SIZE);
+ uint encoded_key_length;
+ storage_encode_multiple_column_key(key_info,
+ (uchar *)(GRN_TEXT_VALUE(&key)),
+ key_info->key_length,
+ (uchar *)(GRN_TEXT_VALUE(&encoded_key)),
+ &encoded_key_length);
+ grn_bulk_space(ctx, &encoded_key, encoded_key_length);
+
+ grn_rc rc;
+ rc = grn_column_index_update(ctx, index_column, record_id, 1,
+ &encoded_key, NULL);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+err:
+ grn_obj_unlink(ctx, &encoded_key);
+ grn_obj_unlink(ctx, &key);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_delete_row_unique_index(grn_obj *index_table,
+ grn_id del_key_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ grn_rc rc = grn_table_delete_by_id(ctx, index_table, del_key_id);
+ if (rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::storage_delete_row_unique_indexes()
+{
+ int error = 0, tmp_error;
+ uint i;
+ uint n_keys = table->s->keys;
+ MRN_DBUG_ENTER_METHOD();
+
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &table->key_info[i];
+ if ((!(key_info->flags & HA_NOSAME)) || del_key_id[i] == GRN_ID_NIL) {
+ continue;
+ }
+
+ grn_obj *index_table = grn_index_tables[i];
+ if ((tmp_error = storage_delete_row_unique_index(index_table,
+ del_key_id[i])))
+ {
+ error = tmp_error;
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_prepare_delete_row_unique_index(const uchar *buf,
+ grn_id record_id,
+ KEY *key_info,
+ grn_obj *index_table,
+ grn_obj *index_column,
+ grn_id *del_key_id)
+{
+ const void *ukey = NULL;
+ uint32 ukey_size = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (KEY_N_KEY_PARTS(key_info) == 1) {
+ GRN_BULK_REWIND(&key_buffer);
+ grn_obj_get_value(ctx, index_column, record_id, &key_buffer);
+ ukey = GRN_TEXT_VALUE(&key_buffer);
+ ukey_size = GRN_TEXT_LEN(&key_buffer);
+ } else {
+ mrn_change_encoding(ctx, NULL);
+ uchar key[MRN_MAX_KEY_SIZE];
+ key_copy(key, (uchar *) buf, key_info, key_info->key_length);
+ grn_bulk_reserve(ctx, &key_buffer, MRN_MAX_KEY_SIZE);
+ ukey = GRN_TEXT_VALUE(&key_buffer);
+ storage_encode_multiple_column_key(key_info,
+ key, key_info->key_length,
+ (uchar *)ukey, (uint *)&ukey_size);
+ }
+ *del_key_id = grn_table_get(ctx, index_table, ukey, ukey_size);
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::storage_prepare_delete_row_unique_indexes(const uchar *buf,
+ grn_id record_id)
+{
+ int error = 0, tmp_error;
+ uint i;
+ uint n_keys = table->s->keys;
+ MRN_DBUG_ENTER_METHOD();
+
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &table->key_info[i];
+ if (!(key_info->flags & HA_NOSAME)) {
+ continue;
+ }
+
+ grn_obj *index_table = grn_index_tables[i];
+ if (!index_table) {
+ del_key_id[i] = GRN_ID_NIL;
+ continue;
+ }
+
+ grn_obj *index_column;
+ if (KEY_N_KEY_PARTS(key_info) == 1) {
+ Field *field = key_info->key_part[0].field;
+ mrn_change_encoding(ctx, field->charset());
+ index_column = grn_columns[field->field_index];
+ } else {
+ mrn_change_encoding(ctx, NULL);
+ index_column = grn_index_columns[i];
+ }
+ if ((tmp_error = storage_prepare_delete_row_unique_index(buf, record_id,
+ key_info,
+ index_table,
+ index_column,
+ &del_key_id[i])))
+ {
+ error = tmp_error;
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::delete_row(const uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_delete_row(buf);
+ } else {
+ error = storage_delete_row(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+uint ha_mroonga::wrapper_max_supported_key_parts() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(MAX_REF_PARTS);
+}
+
+uint ha_mroonga::storage_max_supported_key_parts() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(MAX_REF_PARTS);
+}
+
+uint ha_mroonga::max_supported_key_parts() const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ uint parts;
+ if (!share && !analyzed_for_create &&
+ (
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_TABLE ||
+ thd_sql_command(ha_thd()) == SQLCOM_CREATE_INDEX ||
+ thd_sql_command(ha_thd()) == SQLCOM_ALTER_TABLE
+ )
+ ) {
+ create_share_for_create();
+ }
+ if (analyzed_for_create && share_for_create.wrapper_mode) {
+ parts = wrapper_max_supported_key_parts();
+ } else if (wrap_handler && share && share->wrapper_mode) {
+ parts = wrapper_max_supported_key_parts();
+ } else {
+ parts = storage_max_supported_key_parts();
+ }
+
+ DBUG_RETURN(parts);
+}
+
+ha_rows ha_mroonga::wrapper_records_in_range(uint key_nr,
+ const key_range *range_min,
+ const key_range *range_max,
+ page_range *pages)
+{
+ ha_rows row_count;
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->s->key_info[key_nr]);
+ if (mrn_is_geo_key(key_info)) {
+ row_count = generic_records_in_range_geo(key_nr, range_min, range_max);
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ row_count = wrap_handler->records_in_range(key_nr, range_min, range_max,
+ pages);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(row_count);
+}
+
+ha_rows ha_mroonga::storage_records_in_range(uint key_nr,
+ const key_range *range_min,
+ const key_range *range_max,
+ page_range *pages)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int flags = 0;
+ uint size_min = 0, size_max = 0;
+ ha_rows row_count = 0;
+ uchar *key_min = NULL, *key_max = NULL;
+ uchar key_min_entity[MRN_MAX_KEY_SIZE];
+ uchar key_max_entity[MRN_MAX_KEY_SIZE];
+ KEY *key_info = &(table->s->key_info[key_nr]);
+ bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
+
+ if (is_multiple_column_index) {
+ mrn_change_encoding(ctx, NULL);
+ if (range_min && range_max &&
+ range_min->length == range_max->length &&
+ memcmp(range_min->key, range_max->key, range_min->length) == 0) {
+ flags |= GRN_CURSOR_PREFIX;
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key(key_info,
+ range_min->key, range_min->length,
+ key_min, &size_min);
+ } else {
+ key_min = key_min_entity;
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ range_min, range_max,
+ key_min, &size_min,
+ key_max, &size_max);
+ }
+ } else if (mrn_is_geo_key(key_info)) {
+ mrn_change_encoding(ctx, key_info->key_part->field->charset());
+ row_count = generic_records_in_range_geo(key_nr, range_min, range_max);
+ DBUG_RETURN(row_count);
+ } else {
+ Field *field = key_info->key_part[0].field;
+ const char *column_name = field->field_name.str;
+ mrn_change_encoding(ctx, field->charset());
+
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
+ DBUG_RETURN((ha_rows)1);
+ }
+
+ if (range_min) {
+ key_min = key_min_entity;
+ storage_encode_key(field, range_min->key, key_min, &size_min);
+ if (size_min == 0) {
+ DBUG_RETURN(HA_POS_ERROR);
+ }
+ }
+ if (range_max) {
+ key_max = key_max_entity;
+ storage_encode_key(field, range_max->key, key_max, &size_max);
+ if (size_max == 0) {
+ DBUG_RETURN(HA_POS_ERROR);
+ }
+ }
+ }
+
+ if (range_min) {
+ DBUG_PRINT("info", ("mroonga: range_min->flag=%u", range_min->flag));
+ if (range_min->flag == HA_READ_AFTER_KEY) {
+ flags |= GRN_CURSOR_GT;
+ }
+ }
+ if (range_max) {
+ DBUG_PRINT("info", ("mroonga: range_min->flag=%u", range_max->flag));
+ if (range_max->flag == HA_READ_BEFORE_KEY) {
+ flags |= GRN_CURSOR_LT;
+ }
+ }
+
+ int cursor_limit = THDVAR(ha_thd(), max_n_records_for_estimate);
+ uint pkey_nr = table->s->primary_key;
+ if (key_nr == pkey_nr) {
+ DBUG_PRINT("info", ("mroonga: use primary key"));
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx, grn_table,
+ key_min, size_min,
+ key_max, size_max,
+ 0, cursor_limit, flags);
+ while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ row_count++;
+ }
+ grn_table_cursor_close(ctx, cursor);
+ } else {
+ if (is_multiple_column_index) {
+ DBUG_PRINT("info", ("mroonga: use multiple column key%u", key_nr));
+ } else {
+ DBUG_PRINT("info", ("mroonga: use key%u", key_nr));
+ }
+
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx, grn_index_tables[key_nr],
+ key_min, size_min,
+ key_max, size_max,
+ 0, cursor_limit, flags);
+ grn_obj *index_column = grn_index_columns[key_nr];
+ grn_ii *ii = reinterpret_cast<grn_ii *>(index_column);
+ row_count = grn_ii_estimate_size_for_lexicon_cursor(ctx, ii, cursor);
+ grn_table_cursor_close(ctx, cursor);
+
+ unsigned int max_n_lexicon_records =
+ grn_table_size(ctx, grn_index_tables[key_nr]);
+ if (cursor_limit >= 0 &&
+ static_cast<unsigned int>(cursor_limit) < max_n_lexicon_records) {
+ row_count++;
+ }
+ }
+ DBUG_RETURN(row_count);
+}
+
+ha_rows ha_mroonga::generic_records_in_range_geo(uint key_nr,
+ const key_range *range_min,
+ const key_range *range_max)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows row_count;
+ int error;
+
+ if (!range_min) {
+ DBUG_PRINT("info",
+ ("mroonga: range min is missing for geometry range search"));
+ DBUG_RETURN(HA_POS_ERROR);
+ }
+ if (range_max) {
+ DBUG_PRINT("info",
+ ("mroonga: range max is specified for geometry range search"));
+ DBUG_RETURN(HA_POS_ERROR);
+ }
+ error = mrn_change_encoding(ctx,
+ table->key_info[key_nr].key_part->field->charset());
+ if (error)
+ DBUG_RETURN(error);
+ if (!(range_min->flag & HA_READ_MBR_CONTAIN)) {
+ push_warning_unsupported_spatial_index_search(range_min->flag);
+ row_count = grn_table_size(ctx, grn_table);
+ DBUG_RETURN(row_count);
+ }
+
+ geo_store_rectangle(range_min->key);
+ row_count = grn_geo_estimate_in_rectangle(ctx,
+ grn_index_columns[key_nr],
+ &top_left_point,
+ &bottom_right_point);
+ DBUG_RETURN(row_count);
+}
+
+ha_rows ha_mroonga::records_in_range(uint key_nr, const key_range *range_min,
+ const key_range *range_max,
+ page_range *pages)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows row_count = 0;
+ if (share->wrapper_mode)
+ {
+ row_count = wrapper_records_in_range(key_nr, range_min, range_max, pages);
+ } else {
+ row_count = storage_records_in_range(key_nr, range_min, range_max, pages);
+ }
+ DBUG_PRINT("info", ("mroonga: row_count=%" MRN_HA_ROWS_FORMAT, row_count));
+ DBUG_RETURN(row_count);
+}
+
+int ha_mroonga::wrapper_index_init(uint idx, bool sorted)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ KEY *key_info = &(table->s->key_info[idx]);
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (!mrn_is_geo_key(key_info) && key_info->algorithm != HA_KEY_ALG_FULLTEXT)
+ {
+ error = wrap_handler->ha_index_init(share->wrap_key_nr[idx], sorted);
+ } else {
+ error = wrap_handler->ha_index_init(share->wrap_primary_key, sorted);
+ }
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_init(uint idx, bool sorted)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::index_init(uint idx, bool sorted)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info", ("mroonga: idx=%u", idx));
+ active_index = idx;
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_init(idx, sorted);
+ } else {
+ error = storage_index_init(idx, sorted);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_index_end()
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_index_or_rnd_end();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_end()
+{
+ MRN_DBUG_ENTER_METHOD();
+ clear_cursor();
+ clear_cursor_geo();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::index_end()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_end();
+ } else {
+ error = storage_index_end();
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ clear_cursor_geo();
+ error = generic_geo_open_cursor(key, find_flag);
+ if (!error) {
+ error = wrapper_get_next_geo_record(buf);
+ }
+ DBUG_RETURN(error);
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_MAP
+ error = wrap_handler->ha_index_read_map(buf, key, keypart_map, find_flag);
+#else
+ error = wrap_handler->index_read_map(buf, key, keypart_map, find_flag);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ MRN_DBUG_ENTER_METHOD();
+ check_count_skip(keypart_map);
+
+ int error = 0;
+
+ uint key_nr = active_index;
+ KEY *key_info = &(table->key_info[key_nr]);
+ int flags = 0;
+ uint size_min = 0, size_max = 0;
+ uchar *key_min = NULL, *key_max = NULL;
+ uchar key_min_entity[MRN_MAX_KEY_SIZE];
+ uchar key_max_entity[MRN_MAX_KEY_SIZE];
+
+ clear_cursor();
+ clear_cursor_geo();
+ clear_empty_value_records();
+
+ switch (find_flag) {
+ case HA_READ_BEFORE_KEY:
+ flags |= GRN_CURSOR_LT | GRN_CURSOR_DESCENDING;
+ break;
+ case HA_READ_PREFIX_LAST:
+ flags |= GRN_CURSOR_PREFIX | GRN_CURSOR_DESCENDING;
+ break;
+ case HA_READ_PREFIX_LAST_OR_PREV:
+ flags |= GRN_CURSOR_LE | GRN_CURSOR_DESCENDING;
+ break;
+ case HA_READ_AFTER_KEY:
+ flags |= GRN_CURSOR_GT | GRN_CURSOR_ASCENDING;
+ break;
+ case HA_READ_KEY_OR_NEXT:
+ flags |= GRN_CURSOR_GE | GRN_CURSOR_ASCENDING;
+ break;
+ case HA_READ_KEY_EXACT:
+ flags |= GRN_CURSOR_LE | GRN_CURSOR_GE;
+ break;
+ default:
+ break;
+ }
+
+ bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
+ if (is_multiple_column_index) {
+ mrn_change_encoding(ctx, NULL);
+ uint key_length =
+ mrn_calculate_key_len(table, active_index, key, keypart_map);
+ DBUG_PRINT("info",
+ ("mroonga: multiple column index: "
+ "search key length=<%u>, "
+ "multiple column index key length=<%u>",
+ key_length, key_info->key_length));
+ if (key_length == key_info->key_length) {
+ switch (find_flag) {
+ case HA_READ_BEFORE_KEY:
+ case HA_READ_PREFIX_LAST_OR_PREV:
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key(key_info,
+ key, key_length,
+ key_max, &size_max);
+ break;
+ case HA_READ_PREFIX_LAST:
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key(key_info,
+ key, key_length,
+ key_min, &size_min);
+ break;
+ default:
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key(key_info,
+ key, key_length,
+ key_min, &size_min);
+ if (find_flag == HA_READ_KEY_EXACT) {
+ key_max = key_min;
+ size_max = size_min;
+ }
+ break;
+ }
+ } else {
+ const uchar *prev_key = NULL;
+ uint prev_key_length = 0;
+ if ((keypart_map >> 1) > 0) {
+ prev_key = key;
+ prev_key_length =
+ mrn_calculate_key_len(table, active_index, key, keypart_map >> 1);
+ }
+ switch (find_flag) {
+ case HA_READ_BEFORE_KEY:
+ if (prev_key) {
+ flags |= GRN_CURSOR_GE;
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ prev_key, prev_key_length,
+ NULL, 0,
+ key_min, &size_min,
+ NULL, NULL);
+ }
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ key, key_length,
+ NULL, 0,
+ key_max, &size_max,
+ NULL, NULL);
+ break;
+ case HA_READ_PREFIX_LAST:
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key(key_info,
+ key, key_length,
+ key_min, &size_min);
+ break;
+ case HA_READ_PREFIX_LAST_OR_PREV:
+ if (prev_key) {
+ flags |= GRN_CURSOR_GE;
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ prev_key, prev_key_length,
+ NULL, 0,
+ key_min, &size_min,
+ NULL, NULL);
+ }
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ NULL, 0,
+ key, key_length,
+ NULL, NULL,
+ key_max, &size_max);
+ break;
+ case HA_READ_AFTER_KEY:
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ NULL, 0,
+ key, key_length,
+ NULL, NULL,
+ key_min, &size_min);
+ if (prev_key) {
+ flags |= GRN_CURSOR_LE;
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ NULL, 0,
+ prev_key, prev_key_length,
+ NULL, NULL,
+ key_max, &size_max);
+ }
+ break;
+ case HA_READ_KEY_OR_NEXT:
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ key, key_length,
+ NULL, 0,
+ key_min, &size_min,
+ NULL, NULL);
+ if (prev_key) {
+ flags |= GRN_CURSOR_LE;
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ NULL, 0,
+ prev_key, prev_key_length,
+ NULL, NULL,
+ key_max, &size_max);
+ }
+ break;
+ case HA_READ_KEY_EXACT:
+ key_min = key_min_entity;
+ key_max = key_max_entity;
+ storage_encode_multiple_column_key_range(key_info,
+ key, key_length,
+ key, key_length,
+ key_min, &size_min,
+ key_max, &size_max);
+ default:
+ break;
+ }
+ }
+ } else if (mrn_is_geo_key(key_info)) {
+ error = mrn_change_encoding(ctx, key_info->key_part->field->charset());
+ if (error)
+ DBUG_RETURN(error);
+ error = generic_geo_open_cursor(key, find_flag);
+ if (!error) {
+ error = storage_get_next_record(buf);
+ }
+ DBUG_RETURN(error);
+ } else {
+ Field *field = key_info->key_part[0].field;
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ DBUG_RETURN(error);
+
+ if (find_flag == HA_READ_KEY_EXACT) {
+ const char *column_name = field->field_name.str;
+
+ key_min = key_min_entity;
+ key_max = key_min_entity;
+ storage_encode_key(field, key, key_min, &size_min);
+ size_max = size_min;
+ // for _id
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
+ grn_id found_record_id = *((grn_id *)key_min);
+ if (grn_table_at(ctx, grn_table, found_record_id) != GRN_ID_NIL) { // found
+ storage_store_fields(buf, found_record_id);
+ table->status = 0;
+ record_id = found_record_id;
+ DBUG_RETURN(0);
+ } else {
+ table->status = STATUS_NOT_FOUND;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ }
+ } else if (find_flag == HA_READ_BEFORE_KEY ||
+ find_flag == HA_READ_PREFIX_LAST_OR_PREV) {
+ key_max = key_max_entity;
+ storage_encode_key(field, key, key_max_entity, &size_max);
+ } else {
+ key_min = key_min_entity;
+ storage_encode_key(field, key, key_min_entity, &size_min);
+ }
+ }
+
+ uint pkey_nr = table->s->primary_key;
+ if (key_nr == pkey_nr) {
+ DBUG_PRINT("info", ("mroonga: use primary key"));
+ cursor = grn_table_cursor_open(ctx, grn_table,
+ key_min, size_min,
+ key_max, size_max,
+ 0, -1, flags);
+ } else {
+ bool is_empty_value_records_search = false;
+ if (is_multiple_column_index) {
+ DBUG_PRINT("info", ("mroonga: use multiple column key%u", key_nr));
+ } else if (flags == 0 && size_min == 0 && size_max == 0) {
+ is_empty_value_records_search = true;
+ DBUG_PRINT("info",
+ ("mroonga: use table scan for searching empty value records"));
+ } else {
+ DBUG_PRINT("info", ("mroonga: use key%u", key_nr));
+ }
+ if (is_empty_value_records_search) {
+ grn_obj *expression, *expression_variable;
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, grn_table,
+ expression, expression_variable);
+ grn_obj *target_column =
+ grn_columns[key_info->key_part->field->field_index];
+ grn_expr_append_const(ctx, expression, target_column, GRN_OP_GET_VALUE, 1);
+ grn_obj empty_value;
+ GRN_TEXT_INIT(&empty_value, 0);
+ grn_expr_append_obj(ctx, expression, &empty_value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, expression, GRN_OP_EQUAL, 2);
+
+ empty_value_records =
+ grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
+ grn_table, 0);
+ grn_table_select(ctx, grn_table, expression, empty_value_records,
+ GRN_OP_OR);
+ grn_obj_unlink(ctx, expression);
+ grn_obj_unlink(ctx, &empty_value);
+
+ empty_value_records_cursor =
+ grn_table_cursor_open(ctx, empty_value_records,
+ NULL, 0, NULL, 0,
+ 0, -1, flags);
+ } else {
+ index_table_cursor = grn_table_cursor_open(ctx, grn_index_tables[key_nr],
+ key_min, size_min,
+ key_max, size_max,
+ 0, -1, flags);
+ cursor = grn_index_cursor_open(ctx, index_table_cursor,
+ grn_index_columns[key_nr],
+ 0, GRN_ID_MAX, 0);
+ }
+ }
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+ error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_read_map(buf, key, keypart_map, find_flag);
+ } else {
+ error = storage_index_read_map(buf, key, keypart_map, find_flag);
+ }
+ DBUG_PRINT("info", ("mroonga: error=%d", error));
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HANDLER_HAVE_INDEX_READ_LAST_MAP
+int ha_mroonga::wrapper_index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+# ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_LAST_MAP
+ error = wrap_handler->ha_index_read_last_map(buf, key, keypart_map);
+# else
+ error = wrap_handler->index_read_last_map(buf, key, keypart_map);
+# endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map)
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint key_nr = active_index;
+ KEY *key_info = &(table->key_info[key_nr]);
+
+ int flags = GRN_CURSOR_DESCENDING, error;
+ uint size_min = 0, size_max = 0;
+ uchar *key_min = NULL, *key_max = NULL;
+ uchar key_min_entity[MRN_MAX_KEY_SIZE];
+
+ clear_cursor();
+
+ bool is_multiple_column_index = KEY_N_KEY_PARTS(key_info) > 1;
+ if (is_multiple_column_index) {
+ mrn_change_encoding(ctx, NULL);
+ flags |= GRN_CURSOR_PREFIX;
+ uint key_length =
+ mrn_calculate_key_len(table, active_index, key, keypart_map);
+ key_min = key_min_entity;
+ storage_encode_multiple_column_key(key_info,
+ key, key_length,
+ key_min, &size_min);
+ } else {
+ Field *field = key_info->key_part[0].field;
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ DBUG_RETURN(error);
+
+ key_min = key_min_entity;
+ key_max = key_min_entity;
+ storage_encode_key(field, key, key_min, &size_min);
+ size_max = size_min;
+ }
+
+ uint pkey_nr = table->s->primary_key;
+ if (key_nr == pkey_nr) {
+ DBUG_PRINT("info", ("mroonga: use primary key"));
+ cursor = grn_table_cursor_open(ctx, grn_table,
+ key_min, size_min, key_max, size_max,
+ 0, -1, flags);
+ } else {
+ if (is_multiple_column_index) {
+ DBUG_PRINT("info", ("mroonga: use multiple column key%u", key_nr));
+ } else {
+ DBUG_PRINT("info", ("mroonga: use key%u", key_nr));
+ }
+ index_table_cursor = grn_table_cursor_open(ctx, grn_index_tables[key_nr],
+ key_min, size_min,
+ key_max, size_max,
+ 0, -1, flags);
+ cursor = grn_index_cursor_open(ctx, index_table_cursor,
+ grn_index_columns[key_nr],
+ 0, GRN_ID_MAX, 0);
+ }
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+ error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_read_last_map(buf, key, keypart_map);
+ } else {
+ error = storage_index_read_last_map(buf, key, keypart_map);
+ }
+ DBUG_RETURN(error);
+}
+#endif
+
+int ha_mroonga::wrapper_index_next(uchar *buf)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = wrapper_get_next_geo_record(buf);
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT
+ error = wrap_handler->ha_index_next(buf);
+#else
+ error = wrap_handler->index_next(buf);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_next(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_next(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_next(buf);
+ } else {
+ error = storage_index_next(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_index_prev(uchar *buf)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = wrapper_get_next_geo_record(buf);
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT
+ error = wrap_handler->ha_index_prev(buf);
+#else
+ error = wrap_handler->index_prev(buf);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_prev(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_prev(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_prev(buf);
+ } else {
+ error = storage_index_prev(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_index_first(uchar *buf)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_FIRST
+ error = wrap_handler->ha_index_first(buf);
+#else
+ error = wrap_handler->index_first(buf);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_first(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ clear_cursor();
+ int flags = GRN_CURSOR_ASCENDING;
+ uint pkey_nr = table->s->primary_key;
+ mrn_change_encoding(ctx, NULL);
+ if (active_index == pkey_nr) {
+ DBUG_PRINT("info", ("mroonga: use primary key"));
+ cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0,
+ 0, -1, flags);
+ } else {
+ if (KEY_N_KEY_PARTS(&(table->key_info[active_index])) > 1) {
+ DBUG_PRINT("info", ("mroonga: use multiple column key%u", active_index));
+ } else {
+ DBUG_PRINT("info", ("mroonga: use key%u", active_index));
+ }
+ index_table_cursor = grn_table_cursor_open(ctx,
+ grn_index_tables[active_index],
+ NULL, 0,
+ NULL, 0,
+ 0, -1, flags);
+ cursor = grn_index_cursor_open(ctx, index_table_cursor,
+ grn_index_columns[active_index],
+ 0, GRN_ID_MAX, 0);
+ }
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+ int error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_first(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_first(buf);
+ } else {
+ error = storage_index_first(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_index_last(uchar *buf)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_LAST
+ error = wrap_handler->ha_index_last(buf);
+#else
+ error = wrap_handler->index_last(buf);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_last(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ clear_cursor();
+ int flags = GRN_CURSOR_DESCENDING;
+ uint pkey_nr = table->s->primary_key;
+ mrn_change_encoding(ctx, NULL);
+ if (active_index == pkey_nr) {
+ DBUG_PRINT("info", ("mroonga: use primary key"));
+ cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0,
+ 0, -1, flags);
+ } else {
+ if (KEY_N_KEY_PARTS(&(table->key_info[active_index])) > 1) {
+ DBUG_PRINT("info", ("mroonga: use multiple column key%u", active_index));
+ } else {
+ DBUG_PRINT("info", ("mroonga: use key%u", active_index));
+ }
+ index_table_cursor = grn_table_cursor_open(ctx,
+ grn_index_tables[active_index],
+ NULL, 0,
+ NULL, 0,
+ 0, -1, flags);
+ cursor = grn_index_cursor_open(ctx, index_table_cursor,
+ grn_index_columns[active_index],
+ 0, GRN_ID_MAX, 0);
+ }
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+ int error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_last(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_last(buf);
+ } else {
+ error = storage_index_last(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_index_next_same(uchar *buf, const uchar *key,
+ uint keylen)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ KEY *key_info = &(table->s->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = wrapper_get_next_geo_record(buf);
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT_SAME
+ error = wrap_handler->ha_index_next_same(buf, key, keylen);
+#else
+ error = wrap_handler->index_next_same(buf, key, keylen);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_index_next_same(uchar *buf, const uchar *key,
+ uint keylen)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = storage_get_next_record(count_skip ? NULL : buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::index_next_same(uchar *buf, const uchar *key, uint keylen)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_index_next_same(buf, key, keylen);
+ } else {
+ error = storage_index_next_same(buf, key, keylen);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_ft_init()
+{
+ MRN_DBUG_ENTER_METHOD();
+ struct st_mrn_ft_info *mrn_ft_info =
+ reinterpret_cast<struct st_mrn_ft_info *>(ft_handler);
+ GRN_CTX_SET_ENCODING(ctx, mrn_ft_info->encoding);
+
+ int error = 0;
+ if (sorted_result) {
+ mrn_ft_info->cursor = grn_table_cursor_open(ctx, sorted_result,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ } else {
+ mrn_ft_info->cursor = grn_table_cursor_open(ctx, mrn_ft_info->result,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ }
+ if (ctx->rc) {
+ error = ER_ERROR_ON_READ;
+ my_message(error, ctx->errbuf, MYF(0));
+ } else {
+ if (sorted_result) {
+ if (grn_table->header.type == GRN_TABLE_NO_KEY) {
+ mrn_ft_info->id_accessor = grn_obj_column(ctx, sorted_result,
+ MRN_COLUMN_NAME_ID,
+ strlen(MRN_COLUMN_NAME_ID));
+ } else {
+ mrn_ft_info->key_accessor = grn_obj_column(ctx, sorted_result,
+ MRN_COLUMN_NAME_KEY,
+ strlen(MRN_COLUMN_NAME_KEY));
+ }
+ } else {
+ mrn_ft_info->key_accessor = grn_obj_column(ctx, mrn_ft_info->result,
+ MRN_COLUMN_NAME_KEY,
+ strlen(MRN_COLUMN_NAME_KEY));
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_ft_init()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = generic_ft_init();
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_ft_init()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = generic_ft_init();
+ record_id = GRN_ID_NIL;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::ft_init()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_ft_init();
+ } else {
+ error = storage_ft_init();
+ }
+ DBUG_RETURN(error);
+}
+
+void ha_mroonga::generic_ft_init_ext_add_conditions_fast_order_limit(
+ struct st_mrn_ft_info *info, grn_obj *expression)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ Item *where =
+ MRN_SELECT_LEX_GET_WHERE_COND(table->pos_in_table_list->select_lex);
+
+ bool is_storage_mode = !(share->wrapper_mode);
+ mrn::ConditionConverter converter(info->ctx, grn_table, is_storage_mode);
+ converter.convert(where, expression);
+
+ DBUG_VOID_RETURN;
+}
+
+grn_rc ha_mroonga::generic_ft_init_ext_prepare_expression_in_boolean_mode(
+ struct st_mrn_ft_info *info,
+ String *key,
+ grn_obj *index_column,
+ grn_obj *match_columns,
+ grn_obj *expression)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ mrn::QueryParser query_parser(info->ctx,
+ ha_thd(),
+ expression,
+ index_column,
+ KEY_N_KEY_PARTS(info->key_info),
+ match_columns);
+ grn_rc rc = query_parser.parse(key->ptr(), key->length());
+
+ DBUG_RETURN(rc);
+}
+
+grn_rc ha_mroonga::generic_ft_init_ext_prepare_expression_in_normal_mode(
+ struct st_mrn_ft_info *info,
+ String *key,
+ grn_obj *index_column,
+ grn_obj *match_columns,
+ grn_obj *expression)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ grn_rc rc = GRN_SUCCESS;
+
+ grn_obj query;
+ GRN_TEXT_INIT(&query, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(info->ctx, &query, key->ptr(), key->length());
+ grn_expr_append_obj(info->ctx, match_columns, index_column, GRN_OP_PUSH, 1);
+ grn_expr_append_obj(info->ctx, expression, match_columns, GRN_OP_PUSH, 1);
+ grn_expr_append_const(info->ctx, expression, &query, GRN_OP_PUSH, 1);
+ grn_expr_append_op(info->ctx, expression, GRN_OP_SIMILAR, 2);
+ grn_obj_unlink(info->ctx, &query);
+
+ DBUG_RETURN(rc);
+}
+
+struct st_mrn_ft_info *ha_mroonga::generic_ft_init_ext_select(uint flags,
+ uint key_nr,
+ String *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ struct st_mrn_ft_info *info = new st_mrn_ft_info();
+ info->mroonga = this;
+ info->ctx = ctx;
+ mrn_change_encoding(info->ctx,
+ table->key_info[key_nr].key_part->field->charset());
+ info->encoding = GRN_CTX_GET_ENCODING(info->ctx);
+ info->table = grn_table;
+ info->result = grn_table_create(info->ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
+ grn_table, 0);
+ if (!info->result) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "[mroonga][ft-init] failed to create a table "
+ "to store matched records for one search: <%s>",
+ ctx->errbuf);
+ my_message(ER_ERROR_ON_READ, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ delete info;
+ DBUG_RETURN(NULL);
+ }
+
+ info->score_column = grn_obj_column(info->ctx, info->result,
+ MRN_COLUMN_NAME_SCORE,
+ strlen(MRN_COLUMN_NAME_SCORE));
+ GRN_TEXT_INIT(&(info->key), 0);
+ grn_bulk_space(info->ctx, &(info->key), table->key_info->key_length);
+ GRN_INT32_INIT(&(info->score), 0);
+ info->active_index = key_nr;
+ info->key_info = &(table->key_info[key_nr]);
+ info->primary_key_info = &(table->key_info[table_share->primary_key]);
+ info->cursor = NULL;
+ info->id_accessor = NULL;
+ info->key_accessor = NULL;
+
+ if (key->length() == 0) {
+ DBUG_RETURN(info);
+ }
+
+ grn_obj *index_column = grn_index_columns[key_nr];
+ grn_obj *match_columns, *match_columns_variable;
+ GRN_EXPR_CREATE_FOR_QUERY(info->ctx, info->table, match_columns,
+ match_columns_variable);
+
+ grn_obj *expression, *expression_variable;
+ GRN_EXPR_CREATE_FOR_QUERY(info->ctx, info->table,
+ expression, expression_variable);
+
+ grn_rc rc = GRN_SUCCESS;
+ if (flags & FT_BOOL) {
+ rc = generic_ft_init_ext_prepare_expression_in_boolean_mode(info,
+ key,
+ index_column,
+ match_columns,
+ expression);
+ } else {
+ rc = generic_ft_init_ext_prepare_expression_in_normal_mode(info,
+ key,
+ index_column,
+ match_columns,
+ expression);
+ }
+
+ if (rc == GRN_SUCCESS) {
+ if (fast_order_limit) {
+ generic_ft_init_ext_add_conditions_fast_order_limit(info, expression);
+ }
+ longlong escalation_threshold = THDVAR(ha_thd(), match_escalation_threshold);
+ mrn::MatchEscalationThresholdScope scope(info->ctx, escalation_threshold);
+ grn_table_select(info->ctx, info->table, expression,
+ info->result, GRN_OP_OR);
+ }
+
+ grn_obj_unlink(info->ctx, expression);
+ grn_obj_unlink(info->ctx, match_columns);
+
+ DBUG_RETURN(info);
+}
+
+FT_INFO *ha_mroonga::generic_ft_init_ext(uint flags, uint key_nr, String *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ check_count_skip(0);
+
+ mrn_change_encoding(ctx, system_charset_info);
+ grn_operator operation = GRN_OP_OR;
+ if (!matched_record_keys) {
+ matched_record_keys = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
+ grn_table, 0);
+ if (!matched_record_keys) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "[mroonga][ft-init] "
+ "failed to create a table to store all matched records: <%s>",
+ ctx->errbuf);
+ my_message(ER_ERROR_ON_READ, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ DBUG_RETURN(NULL);
+ }
+ }
+
+ grn_table_sort_key *sort_keys = NULL;
+ int n_sort_keys = 0;
+ longlong limit = -1;
+ check_fast_order_limit(&sort_keys, &n_sort_keys, &limit);
+
+ struct st_mrn_ft_info *info = generic_ft_init_ext_select(flags, key_nr, key);
+ if (!info) {
+ DBUG_RETURN(NULL);
+ }
+
+ grn_rc rc;
+ rc = grn_table_setoperation(ctx, matched_record_keys, info->result,
+ matched_record_keys, operation);
+ if (rc) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to merge matched record keys: <%s>",
+ ctx->errbuf);
+ my_message(ER_ERROR_ON_READ, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ }
+ if (fast_order_limit) {
+ if (sorted_result) {
+ grn_obj_close(ctx, sorted_result);
+ }
+ sorted_result = grn_table_create(ctx, NULL,
+ 0, NULL,
+ GRN_OBJ_TABLE_NO_KEY, NULL,
+ matched_record_keys);
+ grn_table_sort(ctx, matched_record_keys, 0, static_cast<int>(limit),
+ sorted_result, sort_keys, n_sort_keys);
+ } else if (flags & FT_SORTED) {
+ grn_table_sort_key score_sort_key;
+ score_sort_key.key = grn_obj_column(ctx,
+ matched_record_keys,
+ MRN_COLUMN_NAME_SCORE,
+ strlen(MRN_COLUMN_NAME_SCORE));
+ score_sort_key.offset = 0;
+ score_sort_key.flags = GRN_TABLE_SORT_DESC;
+ if (sorted_result) {
+ grn_obj_unlink(ctx, sorted_result);
+ }
+ sorted_result = grn_table_create(ctx, NULL,
+ 0, NULL,
+ GRN_OBJ_TABLE_NO_KEY, NULL,
+ matched_record_keys);
+ grn_table_sort(ctx, matched_record_keys, 0, -1,
+ sorted_result, &score_sort_key, 1);
+ grn_obj_unlink(ctx, score_sort_key.key);
+ }
+ if (sort_keys) {
+ for (int i = 0; i < n_sort_keys; i++) {
+ grn_obj_unlink(info->ctx, sort_keys[i].key);
+ }
+ my_free(sort_keys);
+ }
+
+ DBUG_RETURN((FT_INFO *)info);
+}
+
+FT_INFO *ha_mroonga::wrapper_ft_init_ext(uint flags, uint key_nr, String *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ FT_INFO *info = generic_ft_init_ext(flags, key_nr, key);
+ if (!info) {
+ DBUG_RETURN(NULL);
+ }
+
+ struct st_mrn_ft_info *mrn_ft_info = (struct st_mrn_ft_info *)info;
+ mrn_ft_info->please = &mrn_wrapper_ft_vft;
+#ifdef HA_CAN_FULLTEXT_EXT
+ mrn_ft_info->could_you = &mrn_wrapper_ft_vft_ext;
+#endif
+ ++wrap_ft_init_count;
+
+ DBUG_RETURN(info);
+}
+
+FT_INFO *ha_mroonga::storage_ft_init_ext(uint flags, uint key_nr, String *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ FT_INFO *info = generic_ft_init_ext(flags, key_nr, key);
+ if (!info) {
+ DBUG_RETURN(NULL);
+ }
+
+ struct st_mrn_ft_info *mrn_ft_info = (struct st_mrn_ft_info *)info;
+ mrn_ft_info->please = &mrn_storage_ft_vft;
+#ifdef HA_CAN_FULLTEXT_EXT
+ mrn_ft_info->could_you = &mrn_storage_ft_vft_ext;
+#endif
+ DBUG_RETURN(info);
+}
+
+FT_INFO *ha_mroonga::ft_init_ext(uint flags, uint key_nr, String *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+ fulltext_searching = true;
+ FT_INFO *info;
+ if (key_nr == NO_SUCH_KEY) {
+ struct st_mrn_ft_info *mrn_ft_info = new st_mrn_ft_info();
+ mrn_ft_info->please = &mrn_no_such_key_ft_vft;
+#ifdef HA_CAN_FULLTEXT_EXT
+ mrn_ft_info->could_you = &mrn_no_such_key_ft_vft_ext;
+#endif
+ info = (FT_INFO *)mrn_ft_info;
+ } else {
+ if (share->wrapper_mode)
+ {
+ info = wrapper_ft_init_ext(flags, key_nr, key);
+ } else {
+ info = storage_ft_init_ext(flags, key_nr, key);
+ }
+ }
+ DBUG_RETURN(info);
+}
+
+int ha_mroonga::wrapper_ft_read(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (wrap_ft_init_count)
+ set_pk_bitmap();
+
+ struct st_mrn_ft_info *mrn_ft_info =
+ reinterpret_cast<struct st_mrn_ft_info *>(ft_handler);
+ GRN_CTX_SET_ENCODING(ctx, mrn_ft_info->encoding);
+
+ int error = 0;
+ do {
+ grn_id found_record_id;
+ found_record_id = grn_table_cursor_next(ctx, mrn_ft_info->cursor);
+ if (found_record_id == GRN_ID_NIL) {
+ error = HA_ERR_END_OF_FILE;
+ break;
+ }
+
+ GRN_BULK_REWIND(&key_buffer);
+ if (mrn_ft_info->key_accessor) {
+ grn_obj_get_value(ctx, mrn_ft_info->key_accessor,
+ found_record_id, &key_buffer);
+ } else {
+ void *key;
+ int key_length;
+ key_length = grn_table_cursor_get_key(ctx, mrn_ft_info->cursor, &key);
+ GRN_TEXT_SET(ctx, &key_buffer, key, key_length);
+ }
+ error = wrapper_get_record(buf, (const uchar *)GRN_TEXT_VALUE(&key_buffer));
+ } while (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_ft_read(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ struct st_mrn_ft_info *mrn_ft_info =
+ reinterpret_cast<struct st_mrn_ft_info *>(ft_handler);
+ GRN_CTX_SET_ENCODING(ctx, mrn_ft_info->encoding);
+
+ grn_id found_record_id;
+ found_record_id = grn_table_cursor_next(ctx, mrn_ft_info->cursor);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+
+ if (found_record_id == GRN_ID_NIL) {
+ table->status = STATUS_NOT_FOUND;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ table->status = 0;
+
+ if (count_skip && record_id != GRN_ID_NIL) {
+ DBUG_RETURN(0);
+ }
+
+ GRN_BULK_REWIND(&key_buffer);
+ if (mrn_ft_info->id_accessor) {
+ grn_obj id_buffer;
+ GRN_RECORD_INIT(&id_buffer, 0, grn_obj_id(ctx, grn_table));
+ grn_obj_get_value(ctx, mrn_ft_info->id_accessor,
+ found_record_id, &id_buffer);
+ record_id = GRN_RECORD_VALUE(&id_buffer);
+ } else if (mrn_ft_info->key_accessor) {
+ grn_obj_get_value(ctx, mrn_ft_info->key_accessor,
+ found_record_id, &key_buffer);
+ record_id = grn_table_get(ctx, grn_table,
+ GRN_TEXT_VALUE(&key_buffer),
+ GRN_TEXT_LEN(&key_buffer));
+ } else {
+ void *key;
+ grn_table_cursor_get_key(ctx, mrn_ft_info->cursor, &key);
+ if (ctx->rc) {
+ record_id = GRN_ID_NIL;
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ } else {
+ record_id = *((grn_id *)key);
+ }
+ }
+ storage_store_fields(buf, record_id);
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::ft_read(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_ft_read(buf);
+ } else {
+ error = storage_ft_read(buf);
+ }
+ DBUG_RETURN(error);
+}
+
+const Item *ha_mroonga::wrapper_cond_push(const Item *cond)
+{
+ const Item *reminder_cond;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ reminder_cond = wrap_handler->cond_push(cond);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(reminder_cond);
+}
+
+const Item *ha_mroonga::storage_cond_push(const Item *cond)
+{
+ MRN_DBUG_ENTER_METHOD();
+ const Item *reminder_cond = cond;
+ if (!pushed_cond) {
+ mrn::ConditionConverter converter(ctx, grn_table, true);
+ if (converter.count_match_against(cond) == 1 &&
+ converter.is_convertable(cond)) {
+ reminder_cond = NULL;
+ }
+ }
+ DBUG_RETURN(reminder_cond);
+}
+
+const Item *ha_mroonga::cond_push(const Item *cond)
+{
+ MRN_DBUG_ENTER_METHOD();
+ const Item *reminder_cond;
+ if (share->wrapper_mode)
+ {
+ reminder_cond = wrapper_cond_push(cond);
+ } else {
+ reminder_cond = storage_cond_push(cond);
+ }
+ DBUG_RETURN(reminder_cond);
+}
+
+void ha_mroonga::wrapper_cond_pop()
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->cond_pop();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_cond_pop()
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::cond_pop()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ wrapper_cond_pop();
+ else
+ storage_cond_pop();
+ DBUG_VOID_RETURN;
+}
+
+bool ha_mroonga::wrapper_get_error_message(int error, String *buf)
+{
+ bool temporary_error;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ temporary_error = wrap_handler->get_error_message(error, buf);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(temporary_error);
+}
+
+bool ha_mroonga::storage_get_error_message(int error, String *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool temporary_error = false;
+ // latest error message
+ buf->copy(ctx->errbuf, (uint) strlen(ctx->errbuf), system_charset_info);
+ DBUG_RETURN(temporary_error);
+}
+
+bool ha_mroonga::get_error_message(int error, String *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool temporary_error;
+ if (share && share->wrapper_mode)
+ {
+ temporary_error = wrapper_get_error_message(error, buf);
+ } else {
+ temporary_error = storage_get_error_message(error, buf);
+ }
+ DBUG_RETURN(temporary_error);
+}
+
+ulonglong ha_mroonga::file_size(const char *path)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ struct stat file_status;
+ if (stat(path, &file_status) == 0) {
+ DBUG_RETURN(file_status.st_size);
+ } else {
+ DBUG_RETURN(0);
+ }
+}
+
+bool ha_mroonga::have_unique_index()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ uint n_keys = table->s->keys;
+
+ for (uint i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &(table->key_info[i]);
+ if (key_info->flags & HA_NOSAME) {
+ DBUG_RETURN(true);
+ }
+ }
+
+ DBUG_RETURN(false);
+}
+
+bool ha_mroonga::is_foreign_key_field(const char *table_name,
+ const char *field_name)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ grn_obj *table = grn_ctx_get(ctx, table_name, -1);
+ if (!table) {
+ DBUG_RETURN(false);
+ }
+
+ mrn::ColumnName column_name(field_name);
+ grn_obj *column = grn_obj_column(ctx,
+ table,
+ column_name.c_str(),
+ column_name.length());
+ if (!column) {
+ DBUG_RETURN(false);
+ }
+
+ grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
+ if (!range) {
+ grn_obj_unlink(ctx, column);
+ DBUG_RETURN(false);
+ }
+
+ if (!mrn::grn::is_table(range)) {
+ grn_obj_unlink(ctx, column);
+ DBUG_RETURN(false);
+ }
+
+ grn_obj *foreign_index_column;
+ mrn::IndexColumnName index_column_name(table_name, field_name);
+ foreign_index_column = grn_obj_column(ctx, range,
+ index_column_name.c_str(),
+ index_column_name.length());
+ if (foreign_index_column) {
+ grn_obj_unlink(ctx, foreign_index_column);
+ DBUG_RETURN(true);
+ }
+
+ grn_obj_unlink(ctx, column);
+ DBUG_RETURN(false);
+}
+
+void ha_mroonga::push_warning_unsupported_spatial_index_search(enum ha_rkey_function flag)
+{
+ char search_name[MRN_BUFFER_SIZE];
+ if (flag == HA_READ_MBR_INTERSECT) {
+ strcpy(search_name, "intersect");
+ } else if (flag == HA_READ_MBR_WITHIN) {
+ strcpy(search_name, "within");
+ } else if (flag & HA_READ_MBR_DISJOINT) {
+ strcpy(search_name, "disjoint");
+ } else if (flag & HA_READ_MBR_EQUAL) {
+ strcpy(search_name, "equal");
+ } else {
+ sprintf(search_name, "unknown: %d", flag);
+ }
+ push_warning_printf(ha_thd(),
+ MRN_SEVERITY_WARNING,
+ ER_UNSUPPORTED_EXTENSION,
+ "spatial index search "
+ "except MBRContains aren't supported: <%s>",
+ search_name);
+}
+
+void ha_mroonga::clear_cursor()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (cursor) {
+ grn_obj_unlink(ctx, cursor);
+ cursor = NULL;
+ }
+ if (index_table_cursor) {
+ grn_table_cursor_close(ctx, index_table_cursor);
+ index_table_cursor = NULL;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::clear_cursor_geo()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (cursor_geo) {
+ grn_obj_unlink(ctx, cursor_geo);
+ cursor_geo = NULL;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::clear_empty_value_records()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (empty_value_records_cursor) {
+ grn_table_cursor_close(ctx, empty_value_records_cursor);
+ empty_value_records_cursor = NULL;
+ }
+ if (empty_value_records) {
+ grn_obj_unlink(ctx, empty_value_records);
+ empty_value_records = NULL;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::clear_search_result()
+{
+ MRN_DBUG_ENTER_METHOD();
+ clear_cursor();
+ if (sorted_result) {
+ grn_obj_unlink(ctx, sorted_result);
+ sorted_result = NULL;
+ }
+ if (matched_record_keys) {
+ grn_obj_unlink(ctx, matched_record_keys);
+ matched_record_keys = NULL;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::clear_search_result_geo()
+{
+ MRN_DBUG_ENTER_METHOD();
+ clear_cursor_geo();
+ if (grn_source_column_geo) {
+ grn_obj_unlink(ctx, grn_source_column_geo);
+ grn_source_column_geo = NULL;
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::clear_indexes()
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint n_keys = table->s->keys;
+ uint pkey_nr = table->s->primary_key;
+
+ for (uint i = 0; i < n_keys; i++) {
+ if (i != pkey_nr) {
+ if (grn_index_tables) {
+ grn_obj_unlink(ctx, grn_index_tables[i]);
+ }
+ if (grn_index_columns) {
+ grn_obj_unlink(ctx, grn_index_columns[i]);
+ }
+ }
+ }
+
+ if (grn_index_tables) {
+ free(grn_index_tables);
+ grn_index_tables = NULL;
+ }
+
+ if (grn_index_columns) {
+ free(grn_index_columns);
+ grn_index_columns = NULL;
+ }
+
+ if (key_id) {
+ free(key_id);
+ key_id = NULL;
+ }
+
+ if (del_key_id) {
+ free(del_key_id);
+ del_key_id = NULL;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::add_wrap_hton(const char *path, handlerton *wrap_handlerton)
+{
+ MRN_DBUG_ENTER_METHOD();
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(ha_thd(), true);
+ if (!slot_data)
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ st_mrn_wrap_hton *wrap_hton =
+ (st_mrn_wrap_hton *)malloc(sizeof(st_mrn_wrap_hton));
+ if (!wrap_hton)
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ wrap_hton->next = NULL;
+ strcpy(wrap_hton->path, path);
+ wrap_hton->hton = wrap_handlerton;
+ if (slot_data->first_wrap_hton)
+ {
+ st_mrn_wrap_hton *tmp_wrap_hton = slot_data->first_wrap_hton;
+ while (tmp_wrap_hton->next)
+ tmp_wrap_hton = tmp_wrap_hton->next;
+ tmp_wrap_hton->next = wrap_hton;
+ } else {
+ slot_data->first_wrap_hton = wrap_hton;
+ }
+ DBUG_RETURN(0);
+}
+
+void ha_mroonga::remove_related_files(const char *base_path)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ const char *base_directory_name = ".";
+ size_t base_path_length = strlen(base_path);
+#ifdef WIN32
+ WIN32_FIND_DATA data;
+ HANDLE finder = FindFirstFile(base_directory_name, &data);
+ if (finder != INVALID_HANDLE_VALUE) {
+ do {
+ if (!(data.dwFileAttributes & FILE_ATTRIBUTE_NORMAL)) {
+ continue;
+ }
+ if (strncmp(data.cFileName, base_path, base_path_length) == 0) {
+ unlink(data.cFileName);
+ }
+ } while (FindNextFile(finder, &data) != 0);
+ FindClose(finder);
+ }
+#else
+ DIR *dir = opendir(base_directory_name);
+ if (dir) {
+ while (struct dirent *entry = readdir(dir)) {
+ struct stat file_status;
+ if (stat(entry->d_name, &file_status) != 0) {
+ continue;
+ }
+ if (!((file_status.st_mode & S_IFMT) == S_IFREG)) {
+ continue;
+ }
+ if (strncmp(entry->d_name, base_path, base_path_length) == 0) {
+ unlink(entry->d_name);
+ }
+ }
+ closedir(dir);
+ }
+#endif
+
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::remove_grn_obj_force(const char *name)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ grn_obj *obj = grn_ctx_get(ctx, name, strlen(name));
+ if (obj) {
+ grn_obj_remove(ctx, obj);
+ } else {
+ grn_obj *db = grn_ctx_db(ctx);
+ grn_id id = grn_table_get(ctx, db, name, strlen(name));
+ if (id) {
+ char path[MRN_MAX_PATH_SIZE];
+ grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (grn_obj_path_by_id(ctx, db, id, path) == GRN_SUCCESS) {
+ remove_related_files(path);
+ }
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::drop_index(MRN_SHARE *target_share, uint key_index)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ grn_rc rc = GRN_SUCCESS;
+ char target_name[GRN_TABLE_MAX_KEY_SIZE];
+ int target_name_length;
+
+ KEY *key_info = target_share->table_share->key_info;
+ if (!target_share->wrapper_mode && target_share->index_table[key_index]) {
+ const char *table_name = target_share->index_table[key_index];
+ snprintf(target_name, GRN_TABLE_MAX_KEY_SIZE,
+ "%s.%s", table_name, key_info[key_index].name.str);
+ target_name_length = strlen(target_name);
+ grn_obj *index_column = grn_ctx_get(ctx, target_name, target_name_length);
+ if (index_column) {
+ rc = grn_obj_remove(ctx, index_column);
+ }
+ } else {
+ mrn::PathMapper mapper(target_share->table_name);
+ mrn::IndexTableName index_table_name(mapper.table_name(),
+ key_info[key_index].name.str);
+ grn_obj *index_table = grn_ctx_get(ctx,
+ index_table_name.c_str(),
+ index_table_name.length());
+ if (!index_table) {
+ index_table = grn_ctx_get(ctx,
+ index_table_name.old_c_str(),
+ index_table_name.old_length());
+ }
+ if (index_table) {
+ target_name_length = grn_obj_name(ctx, index_table,
+ target_name, GRN_TABLE_MAX_KEY_SIZE);
+ rc = grn_obj_remove(ctx, index_table);
+ } else {
+ target_name_length = 0;
+ }
+ }
+
+ if (rc != GRN_SUCCESS) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to drop index: <%.*s>: <%s>",
+ target_name_length, target_name,
+ ctx->errbuf);
+ my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::drop_indexes_normal(const char *table_name, grn_obj *table)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ grn_hash *columns_raw = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY);
+ mrn::SmartGrnObj columns(ctx, reinterpret_cast<grn_obj *>(columns_raw));
+ if (!columns.get()) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to allocate columns buffer: <%s>: <%s>",
+ table_name, ctx->errbuf);
+ error = HA_ERR_OUT_OF_MEM;
+ my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ DBUG_RETURN(error);
+ }
+
+ grn_table_columns(ctx, table, "", 0, columns.get());
+ grn_table_cursor *cursor = grn_table_cursor_open(ctx,
+ columns.get(),
+ NULL, 0,
+ NULL, 0,
+ 0, -1,
+ 0);
+ if (!cursor) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to allocate columns cursor: <%s>: <%s>",
+ table_name, ctx->errbuf);
+ error = HA_ERR_OUT_OF_MEM;
+ my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ DBUG_RETURN(error);
+ }
+
+ while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ void *key;
+ grn_table_cursor_get_key(ctx, cursor, &key);
+ grn_id *id = reinterpret_cast<grn_id *>(key);
+ mrn::SmartGrnObj column(ctx, grn_ctx_at(ctx, *id));
+ if (!column.get()) {
+ continue;
+ }
+
+ grn_operator index_operators[] = {
+ GRN_OP_EQUAL,
+ GRN_OP_MATCH,
+ GRN_OP_LESS,
+ GRN_OP_REGEXP
+ };
+ size_t n_index_operators = sizeof(index_operators) / sizeof(grn_operator);
+ for (size_t i = 0; i < n_index_operators; i++) {
+ grn_index_datum index_datum;
+ while (grn_column_find_index_data(ctx,
+ column.get(),
+ index_operators[i],
+ &index_datum,
+ 1) > 0) {
+ grn_id index_table_id = index_datum.index->header.domain;
+ mrn::SmartGrnObj index_table(ctx, grn_ctx_at(ctx, index_table_id));
+ char index_table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_table_name_length;
+ index_table_name_length = grn_obj_name(ctx, index_table.get(),
+ index_table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ if (mrn::IndexTableName::is_custom_name(table_name,
+ strlen(table_name),
+ index_table_name,
+ index_table_name_length)) {
+ char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_column_name_length;
+ index_column_name_length = grn_obj_name(ctx,
+ index_datum.index,
+ index_column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ grn_rc rc = grn_obj_remove(ctx, index_datum.index);
+ if (rc != GRN_SUCCESS) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to drop index column: <%.*s>: <%s>",
+ index_column_name_length, index_column_name,
+ ctx->errbuf);
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ }
+ } else {
+ grn_rc rc = grn_obj_remove(ctx, index_table.get());
+ if (rc == GRN_SUCCESS) {
+ index_table.release();
+ } else {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to drop index table: <%.*s>: <%s>",
+ index_table_name_length, index_table_name,
+ ctx->errbuf);
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ }
+ }
+
+ if (error != 0) {
+ break;
+ }
+ }
+
+ if (error != 0) {
+ break;
+ }
+ }
+
+ if (error != 0) {
+ break;
+ }
+ }
+
+ grn_table_cursor_close(ctx, cursor);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::drop_indexes_multiple(const char *table_name,
+ grn_obj *table,
+ const char *index_table_name_separator)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ char index_table_name_prefix[GRN_TABLE_MAX_KEY_SIZE];
+ snprintf(index_table_name_prefix, GRN_TABLE_MAX_KEY_SIZE,
+ "%s%s", table_name, index_table_name_separator);
+ grn_table_cursor *cursor =
+ grn_table_cursor_open(ctx,
+ grn_ctx_db(ctx),
+ index_table_name_prefix,
+ strlen(index_table_name_prefix),
+ NULL, 0,
+ 0, -1,
+ GRN_CURSOR_PREFIX);
+ if (!cursor) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to allocate index tables cursor: <%s>: <%s>",
+ table_name, ctx->errbuf);
+ error = HA_ERR_OUT_OF_MEM;
+ my_message(ER_ERROR_ON_WRITE, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ DBUG_RETURN(error);
+ }
+
+ grn_id table_id = grn_obj_id(ctx, table);
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ mrn::SmartGrnObj object(ctx, grn_ctx_at(ctx, id));
+ if (!object.get()) {
+ continue;
+ }
+ if (!grn_obj_is_table(ctx, object.get())) {
+ continue;
+ }
+
+ char multiple_column_index_table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int multiple_column_index_table_name_length;
+ multiple_column_index_table_name_length =
+ grn_obj_name(ctx,
+ object.get(),
+ multiple_column_index_table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+
+ char multiple_column_index_name[GRN_TABLE_MAX_KEY_SIZE];
+ snprintf(multiple_column_index_name, GRN_TABLE_MAX_KEY_SIZE,
+ "%.*s.%s",
+ multiple_column_index_table_name_length,
+ multiple_column_index_table_name,
+ INDEX_COLUMN_NAME);
+ mrn::SmartGrnObj index_column(ctx, multiple_column_index_name);
+ if (!index_column.get()) {
+ continue;
+ }
+
+ if (grn_obj_get_range(ctx, index_column.get()) != table_id) {
+ continue;
+ }
+
+ grn_rc rc = grn_obj_remove(ctx, object.get());
+ if (rc == GRN_SUCCESS) {
+ object.release();
+ index_column.release();
+ } else {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to drop multiple column index table: <%.*s>: <%s>",
+ multiple_column_index_table_name_length,
+ multiple_column_index_table_name,
+ ctx->errbuf);
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, error_message, MYF(0));
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ break;
+ }
+ }
+
+ grn_table_cursor_close(ctx, cursor);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::drop_indexes(const char *table_name)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ mrn::SmartGrnObj table(ctx, table_name);
+ if (!table.get()) {
+ DBUG_RETURN(0);
+ }
+
+ error = drop_indexes_normal(table_name, table.get());
+ if (error == 0) {
+ error = drop_indexes_multiple(table_name, table.get(),
+ mrn::IndexTableName::SEPARATOR);
+ }
+ if (error == 0) {
+ error = drop_indexes_multiple(table_name, table.get(),
+ mrn::IndexTableName::OLD_SEPARATOR);
+ }
+
+ DBUG_RETURN(error);
+}
+
+bool ha_mroonga::find_column_flags(Field *field, MRN_SHARE *mrn_share, int i,
+ grn_obj_flags *column_flags)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool found = false;
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ {
+ const char *names = field->option_struct->flags;
+ if (names) {
+ found = mrn_parse_grn_column_create_flags(ha_thd(),
+ ctx,
+ names,
+ strlen(names),
+ column_flags);
+ DBUG_RETURN(found);
+ }
+ }
+#endif
+
+ if (mrn_share->col_flags[i]) {
+ found = mrn_parse_grn_column_create_flags(ha_thd(),
+ ctx,
+ mrn_share->col_flags[i],
+ mrn_share->col_flags_length[i],
+ column_flags);
+ DBUG_RETURN(found);
+ }
+
+ DBUG_RETURN(found);
+}
+
+grn_obj *ha_mroonga::find_column_type(Field *field, MRN_SHARE *mrn_share, int i,
+ int error_code)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ const char *grn_type_name = NULL;
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ grn_type_name = field->option_struct->groonga_type;
+#endif
+ if (!grn_type_name) {
+ grn_type_name = mrn_share->col_type[i];
+ }
+
+ grn_obj *type = NULL;
+ if (grn_type_name) {
+ type = grn_ctx_get(ctx, grn_type_name, -1);
+ if (!type) {
+ char error_message[MRN_BUFFER_SIZE];
+ snprintf(error_message, MRN_BUFFER_SIZE,
+ "unknown custom Groonga type name for <%s> column: <%s>",
+ field->field_name.str, grn_type_name);
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%s", error_message);
+ my_message(error_code, error_message, MYF(0));
+
+ DBUG_RETURN(NULL);
+ }
+ } else {
+ grn_builtin_type grn_type_id = mrn_grn_type_from_field(ctx, field, false);
+ type = grn_ctx_at(ctx, grn_type_id);
+ }
+
+ DBUG_RETURN(type);
+}
+
+grn_obj *ha_mroonga::find_tokenizer(KEY *key, MRN_SHARE *mrn_share, int i)
+{
+ MRN_DBUG_ENTER_METHOD();
+ grn_obj *tokenizer;
+ const char *tokenizer_name = NULL;
+ uint tokenizer_name_length = 0;
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ if (key->option_struct->tokenizer) {
+ tokenizer_name = key->option_struct->tokenizer;
+ tokenizer_name_length = strlen(tokenizer_name);
+ }
+#endif
+ if (!tokenizer_name) {
+ tokenizer_name = mrn_share->key_tokenizer[i];
+ tokenizer_name_length = mrn_share->key_tokenizer_length[i];
+ }
+ tokenizer = find_tokenizer(tokenizer_name, tokenizer_name_length);
+ DBUG_RETURN(tokenizer);
+}
+
+grn_obj *ha_mroonga::find_tokenizer(const char *name, int name_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (strncasecmp("off", name, name_length) == 0) {
+ DBUG_RETURN(NULL);
+ }
+
+ grn_obj *tokenizer;
+ mrn_change_encoding(ctx, system_charset_info);
+ tokenizer = grn_ctx_get(ctx, name, name_length);
+ if (!tokenizer) {
+ char message[MRN_BUFFER_SIZE];
+ sprintf(message,
+ "specified tokenizer for fulltext index <%.*s> doesn't exist. "
+ "The default tokenizer for fulltext index <%s> is used instead.",
+ name_length, name,
+ MRN_DEFAULT_TOKENIZER);
+ push_warning(ha_thd(),
+ MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
+ message);
+ tokenizer = grn_ctx_get(ctx,
+ MRN_DEFAULT_TOKENIZER,
+ strlen(MRN_DEFAULT_TOKENIZER));
+ }
+ if (!tokenizer) {
+ push_warning(ha_thd(),
+ MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
+ "couldn't find tokenizer for fulltext index. "
+ "Bigram tokenizer is used instead.");
+ tokenizer = grn_ctx_at(ctx, GRN_DB_BIGRAM);
+ }
+ DBUG_RETURN(tokenizer);
+}
+
+bool ha_mroonga::have_custom_normalizer(KEY *key) const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ if (key->option_struct && key->option_struct->normalizer) {
+ DBUG_RETURN(true);
+ }
+#endif
+
+ if (key->comment.length > 0) {
+ mrn::ParametersParser parser(key->comment.str,
+ key->comment.length);
+ parser.parse();
+ DBUG_RETURN(parser["normalizer"] != NULL);
+ }
+
+ DBUG_RETURN(false);
+}
+
+grn_obj *ha_mroonga::find_normalizer(KEY *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ if (key->option_struct->normalizer) {
+ grn_obj *normalizer = find_normalizer(key,
+ key->option_struct->normalizer);
+ DBUG_RETURN(normalizer);
+ }
+#endif
+
+ if (key->comment.length > 0) {
+ mrn::ParametersParser parser(key->comment.str,
+ key->comment.length);
+ parser.parse();
+ grn_obj *normalizer = find_normalizer(key, parser["normalizer"]);
+ DBUG_RETURN(normalizer);
+ }
+
+ grn_obj *normalizer = find_normalizer(key, NULL);
+ DBUG_RETURN(normalizer);
+}
+
+grn_obj *ha_mroonga::find_normalizer(KEY *key, const char *name)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ grn_obj *normalizer = NULL;
+ bool use_normalizer = true;
+ if (name) {
+ if (strcmp(name, "none") == 0) {
+ use_normalizer = false;
+ } else {
+ normalizer = grn_ctx_get(ctx, name, -1);
+ }
+ }
+ if (use_normalizer && !normalizer) {
+ Field *field = key->key_part[0].field;
+ mrn::FieldNormalizer field_normalizer(ctx, ha_thd(), field);
+ normalizer = field_normalizer.find_grn_normalizer();
+ }
+
+ DBUG_RETURN(normalizer);
+}
+
+bool ha_mroonga::find_index_column_flags(KEY *key, grn_column_flags *index_column_flags)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool found = false;
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ {
+ const char *names = key->option_struct->flags;
+ if (names) {
+ found = mrn_parse_grn_index_column_flags(ha_thd(),
+ ctx,
+ names,
+ strlen(names),
+ index_column_flags);
+ DBUG_RETURN(found);
+ }
+ }
+#endif
+
+ if (key->comment.length > 0) {
+ mrn::ParametersParser parser(key->comment.str,
+ key->comment.length);
+ parser.parse();
+ const char *names = parser["flags"];
+ if (!names) {
+ // Deprecated. It's for backward compatibility.
+ names = parser["index_flags"];
+ }
+ if (names) {
+ found = mrn_parse_grn_index_column_flags(ha_thd(),
+ ctx,
+ names,
+ strlen(names),
+ index_column_flags);
+ }
+ }
+
+ DBUG_RETURN(found);
+}
+
+bool ha_mroonga::find_token_filters(KEY *key, grn_obj *token_filters)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool found = false;
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ if (key->option_struct->token_filters) {
+ found = find_token_filters_fill(token_filters,
+ key->option_struct->token_filters,
+ strlen(key->option_struct->token_filters));
+ DBUG_RETURN(found);
+ }
+#endif
+
+ if (key->comment.length > 0) {
+ mrn::ParametersParser parser(key->comment.str,
+ key->comment.length);
+ parser.parse();
+ const char *names = parser["token_filters"];
+ if (names) {
+ found = find_token_filters_fill(token_filters, names, strlen(names));
+ }
+ }
+
+ DBUG_RETURN(found);
+}
+
+bool ha_mroonga::find_token_filters_put(grn_obj *token_filters,
+ const char *token_filter_name,
+ int token_filter_name_length)
+{
+ grn_obj *token_filter;
+
+ token_filter = grn_ctx_get(ctx,
+ token_filter_name,
+ token_filter_name_length);
+ if (token_filter) {
+ GRN_PTR_PUT(ctx, token_filters, token_filter);
+ return true;
+ } else {
+ char message[MRN_BUFFER_SIZE];
+ sprintf(message,
+ "nonexistent token filter: <%.*s>",
+ token_filter_name_length, token_filter_name);
+ push_warning(ha_thd(),
+ MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
+ message);
+ return false;
+ }
+}
+
+bool ha_mroonga::find_token_filters_fill(grn_obj *token_filters,
+ const char *token_filter_names,
+ int token_filter_names_length)
+{
+ const char *start, *current, *end;
+ const char *name_start, *name_end;
+ const char *last_name_end;
+
+ start = token_filter_names;
+ end = start + token_filter_names_length;
+ current = start;
+ name_start = NULL;
+ name_end = NULL;
+ last_name_end = start;
+ while (current < end) {
+ switch (current[0]) {
+ case ' ' :
+ if (name_start && !name_end) {
+ name_end = current;
+ }
+ break;
+ case ',' :
+ if (!name_start) {
+ goto break_loop;
+ }
+ if (!name_end) {
+ name_end = current;
+ }
+ find_token_filters_put(token_filters,
+ name_start,
+ name_end - name_start);
+ last_name_end = name_end + 1;
+ name_start = NULL;
+ name_end = NULL;
+ break;
+ default :
+ if (!name_start) {
+ name_start = current;
+ }
+ break;
+ }
+ current++;
+ }
+
+break_loop:
+ if (!name_start) {
+ char message[MRN_BUFFER_SIZE];
+ sprintf(message,
+ "empty token filter name: "
+ "<%.*s|%.*s|%.*s>",
+ (int)(last_name_end - start), start,
+ (int)(current - last_name_end), last_name_end,
+ (int)(end - current), current);
+ push_warning(ha_thd(),
+ MRN_SEVERITY_WARNING, ER_UNSUPPORTED_EXTENSION,
+ message);
+ return false;
+ }
+
+ if (!name_end) {
+ name_end = current;
+ }
+ find_token_filters_put(token_filters,
+ name_start,
+ name_end - name_start);
+
+ return true;
+}
+
+int ha_mroonga::wrapper_get_record(uchar *buf, const uchar *key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (wrap_handler->inited == NONE) {
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_IDX_MAP
+ error = wrap_handler->ha_index_read_idx_map(buf,
+ share->wrap_primary_key,
+ key,
+ pk_keypart_map,
+ HA_READ_KEY_EXACT);
+#else
+ error = wrap_handler->index_read_idx_map(buf,
+ share->wrap_primary_key,
+ key,
+ pk_keypart_map,
+ HA_READ_KEY_EXACT);
+#endif
+ } else {
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_MAP
+ error = wrap_handler->ha_index_read_map(buf,
+ key,
+ pk_keypart_map,
+ HA_READ_KEY_EXACT);
+#else
+ error = wrap_handler->index_read_map(buf,
+ key,
+ pk_keypart_map,
+ HA_READ_KEY_EXACT);
+#endif
+ }
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_get_next_geo_record(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ mrn_change_encoding(ctx, NULL);
+ do {
+ GRN_BULK_REWIND(&key_buffer);
+ grn_id found_record_id;
+ grn_posting *posting;
+ posting = grn_geo_cursor_next(ctx, cursor_geo);
+ if (!posting) {
+ error = HA_ERR_END_OF_FILE;
+ clear_cursor_geo();
+ break;
+ }
+ found_record_id = posting->rid;
+ grn_table_get_key(ctx, grn_table, found_record_id,
+ GRN_TEXT_VALUE(&key_buffer),
+ table->key_info->key_length);
+ error = wrapper_get_record(buf, (const uchar *)GRN_TEXT_VALUE(&key_buffer));
+ } while (error == HA_ERR_END_OF_FILE || error == HA_ERR_KEY_NOT_FOUND);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_get_next_record(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (cursor_geo) {
+ grn_posting *posting;
+ posting = grn_geo_cursor_next(ctx, cursor_geo);
+ if (posting) {
+ record_id = posting->rid;
+ } else {
+ record_id = GRN_ID_NIL;
+ }
+ } else if (cursor) {
+ record_id = grn_table_cursor_next(ctx, cursor);
+ } else if (empty_value_records_cursor) {
+ grn_id empty_value_record_id;
+ empty_value_record_id =
+ grn_table_cursor_next(ctx, empty_value_records_cursor);
+ if (empty_value_record_id == GRN_ID_NIL) {
+ record_id = GRN_ID_NIL;
+ } else {
+ grn_table_get_key(ctx, empty_value_records, empty_value_record_id,
+ &record_id, sizeof(grn_id));
+ }
+ } else {
+ record_id = GRN_ID_NIL;
+ }
+ if (ctx->rc) {
+ int error = ER_ERROR_ON_READ;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ if (record_id == GRN_ID_NIL) {
+ DBUG_PRINT("info", ("mroonga: storage_get_next_record: end-of-file"));
+ table->status = STATUS_NOT_FOUND;
+ DBUG_RETURN(HA_ERR_END_OF_FILE);
+ }
+ if (buf) {
+ if (ignoring_no_key_columns)
+ storage_store_fields_by_index(buf);
+ else
+ storage_store_fields(buf, record_id);
+ if (cursor_geo && grn_source_column_geo) {
+ int latitude, longitude;
+ GRN_GEO_POINT_VALUE(&source_point, latitude, longitude);
+ double latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
+ double longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
+ if (!((bottom_right_latitude_in_degree <= latitude_in_degree &&
+ latitude_in_degree <= top_left_latitude_in_degree) &&
+ (top_left_longitude_in_degree <= longitude_in_degree &&
+ longitude_in_degree <= bottom_right_longitude_in_degree))) {
+ DBUG_PRINT("info",
+ ("mroonga: remove not contained geo point: "
+ "<%g,%g>(<%d,%d>); key: <%g,%g>(<%d,%d>), <%g,%g>(<%d,%d>)",
+ latitude_in_degree, longitude_in_degree,
+ latitude, longitude,
+ top_left_latitude_in_degree, top_left_longitude_in_degree,
+ GRN_GEO_DEGREE2MSEC(top_left_latitude_in_degree),
+ GRN_GEO_DEGREE2MSEC(top_left_longitude_in_degree),
+ bottom_right_latitude_in_degree,
+ bottom_right_longitude_in_degree,
+ GRN_GEO_DEGREE2MSEC(bottom_right_latitude_in_degree),
+ GRN_GEO_DEGREE2MSEC(bottom_right_longitude_in_degree)));
+ int error = storage_get_next_record(buf);
+ DBUG_RETURN(error);
+ }
+ }
+ }
+ table->status = 0;
+ DBUG_RETURN(0);
+}
+
+void ha_mroonga::geo_store_rectangle(const uchar *rectangle)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ double locations[4];
+ for (int i = 0; i < 4; i++) {
+ uchar reversed_value[8];
+ for (int j = 0; j < 8; j++) {
+ reversed_value[j] = (rectangle + (8 * i))[7 - j];
+ }
+ mi_float8get(locations[i], reversed_value);
+ }
+ top_left_longitude_in_degree = locations[0];
+ bottom_right_longitude_in_degree = locations[1];
+ bottom_right_latitude_in_degree = locations[2];
+ top_left_latitude_in_degree = locations[3];
+ int top_left_latitude = GRN_GEO_DEGREE2MSEC(top_left_latitude_in_degree);
+ int top_left_longitude = GRN_GEO_DEGREE2MSEC(top_left_longitude_in_degree);
+ int bottom_right_latitude = GRN_GEO_DEGREE2MSEC(bottom_right_latitude_in_degree);
+ int bottom_right_longitude = GRN_GEO_DEGREE2MSEC(bottom_right_longitude_in_degree);
+ GRN_GEO_POINT_SET(ctx, &top_left_point,
+ top_left_latitude, top_left_longitude);
+ GRN_GEO_POINT_SET(ctx, &bottom_right_point,
+ bottom_right_latitude, bottom_right_longitude);
+
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::generic_geo_open_cursor(const uchar *key,
+ enum ha_rkey_function find_flag)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ int flags = 0;
+ if (find_flag & HA_READ_MBR_CONTAIN) {
+ grn_obj *index = grn_index_columns[active_index];
+ geo_store_rectangle(key);
+ cursor_geo = grn_geo_cursor_open_in_rectangle(ctx,
+ index,
+ &top_left_point,
+ &bottom_right_point,
+ 0, -1);
+ if (cursor_geo) {
+ if (grn_source_column_geo) {
+ grn_obj_unlink(ctx, grn_source_column_geo);
+ }
+ grn_obj sources;
+ GRN_OBJ_INIT(&sources, GRN_BULK, 0, GRN_ID_NIL);
+ grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &sources);
+ grn_source_column_geo = grn_ctx_at(ctx, GRN_RECORD_VALUE(&sources));
+ grn_obj_unlink(ctx, &sources);
+ }
+ } else {
+ push_warning_unsupported_spatial_index_search(find_flag);
+ cursor = grn_table_cursor_open(ctx, grn_table, NULL, 0, NULL, 0,
+ 0, -1, flags);
+ }
+ if (ctx->rc) {
+ error = ER_ERROR_ON_READ;
+ my_message(error, ctx->errbuf, MYF(0));
+ }
+ DBUG_RETURN(error);
+}
+
+bool ha_mroonga::is_dry_write()
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool dry_write_p = THDVAR(ha_thd(), dry_write);
+ DBUG_RETURN(dry_write_p);
+}
+
+bool ha_mroonga::is_enable_optimization()
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool enable_optimization_p = THDVAR(ha_thd(), enable_optimization);
+ DBUG_RETURN(enable_optimization_p);
+}
+
+bool ha_mroonga::should_normalize(Field *field) const
+{
+ MRN_DBUG_ENTER_METHOD();
+ mrn::FieldNormalizer field_normalizer(ctx, ha_thd(), field);
+ bool need_normalize_p = field_normalizer.should_normalize();
+ DBUG_RETURN(need_normalize_p);
+}
+
+void ha_mroonga::check_count_skip(key_part_map target_key_part_map)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!is_enable_optimization()) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] optimization is disabled");
+ count_skip = false;
+ DBUG_VOID_RETURN;
+ }
+
+ if (thd_sql_command(ha_thd()) != SQLCOM_SELECT) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] not SELECT");
+ count_skip = false;
+ DBUG_VOID_RETURN;
+ }
+
+ if (share->wrapper_mode &&
+ !(wrap_handler->ha_table_flags() & HA_NO_TRANSACTIONS)) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] wrapped engine is transactional");
+ count_skip = false;
+ DBUG_VOID_RETURN;
+ }
+
+ st_select_lex *select_lex = table->pos_in_table_list->select_lex;
+ KEY *key_info = NULL;
+ if (active_index != MAX_KEY) {
+ key_info = &(table->key_info[active_index]);
+ }
+ mrn::CountSkipChecker checker(ctx,
+ table,
+ select_lex,
+ key_info,
+ target_key_part_map,
+ !share->wrapper_mode);
+ if (checker.check()) {
+ count_skip = true;
+ mrn_count_skip++;
+ DBUG_VOID_RETURN;
+ } else {
+ count_skip = false;
+ DBUG_VOID_RETURN;
+ }
+}
+
+bool ha_mroonga::is_grn_zero_column_value(grn_obj *column, grn_obj *value)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (column->header.type != GRN_COLUMN_FIX_SIZE) {
+ DBUG_RETURN(false);
+ }
+
+ char *bytes = GRN_BULK_HEAD(value);
+ unsigned int size = GRN_BULK_VSIZE(value);
+ for (unsigned int i = 0; i < size; ++i) {
+ if (bytes[i] != '\0') {
+ DBUG_RETURN(false);
+ }
+ }
+
+ DBUG_RETURN(true);
+}
+
+bool ha_mroonga::is_primary_key_field(Field *field) const
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (table->s->primary_key == MAX_INDEXES) {
+ DBUG_RETURN(false);
+ }
+
+ KEY *key_info = &(table->s->key_info[table->s->primary_key]);
+ if (KEY_N_KEY_PARTS(key_info) != 1) {
+ DBUG_RETURN(false);
+ }
+
+ if (strcmp(field->field_name.str,
+ key_info->key_part[0].field->field_name.str) == 0) {
+ DBUG_RETURN(true);
+ } else {
+ DBUG_RETURN(false);
+ }
+}
+
+void ha_mroonga::check_fast_order_limit(grn_table_sort_key **sort_keys,
+ int *n_sort_keys,
+ longlong *limit)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!is_enable_optimization()) {
+ DBUG_PRINT("info", ("mroonga: fast order limit: optimization is disabled"));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+ }
+
+ TABLE_LIST *table_list = table->pos_in_table_list;
+ st_select_lex *select_lex = table_list->select_lex;
+ SELECT_LEX_UNIT *unit = MRN_TABLE_LIST_GET_DERIVED(table_list);
+ st_select_lex *first_select_lex;
+ if (unit)
+ {
+ first_select_lex = unit->first_select();
+ } else {
+ first_select_lex = select_lex;
+ }
+ DBUG_PRINT("info",
+ ("mroonga: first_select_lex->options=%llu",
+ first_select_lex ? MRN_SELECT_LEX_GET_ACTIVE_OPTIONS(first_select_lex) : 0));
+
+ if (
+ thd_sql_command(ha_thd()) == SQLCOM_SELECT &&
+ !select_lex->with_sum_func &&
+ !select_lex->group_list.elements &&
+ !MRN_SELECT_LEX_GET_HAVING_COND(select_lex) &&
+ select_lex->table_list.elements == 1 &&
+ select_lex->order_list.elements &&
+ select_lex->limit_params.explicit_limit &&
+ select_lex->limit_params.select_limit &&
+ select_lex->limit_params.select_limit->val_int() > 0
+ ) {
+ if (select_lex->limit_params.offset_limit) {
+ *limit = select_lex->limit_params.offset_limit->val_int();
+ } else {
+ *limit = 0;
+ }
+ *limit += select_lex->limit_params.select_limit->val_int();
+ if (*limit > (longlong)INT_MAX) {
+ DBUG_PRINT("info",
+ ("mroonga: fast_order_limit = false: "
+ "too long limit: %lld <= %d is required",
+ *limit, INT_MAX));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+ }
+ if (first_select_lex &&
+ (MRN_SELECT_LEX_GET_ACTIVE_OPTIONS(first_select_lex) & OPTION_FOUND_ROWS)) {
+ DBUG_PRINT("info",
+ ("mroonga: fast_order_limit = false: "
+ "SQL_CALC_FOUND_ROWS is specified"));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+ }
+ bool is_storage_mode = !(share->wrapper_mode);
+ Item *where = MRN_SELECT_LEX_GET_WHERE_COND(select_lex);
+ const Item_func *match_against = NULL;
+ if (where) {
+ mrn::ConditionConverter converter(ctx, grn_table, is_storage_mode);
+ if (!converter.is_convertable(where)) {
+ DBUG_PRINT("info",
+ ("mroonga: fast_order_limit = false: "
+ "not Groonga layer condition search"));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+ }
+ unsigned int n_match_againsts = converter.count_match_against(where);
+ if (n_match_againsts == 0) {
+ DBUG_PRINT("info",
+ ("mroonga: fast_order_limit = false: "
+ "Groonga layer condition but not fulltext search"));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+ }
+ if (n_match_againsts > 1) {
+ DBUG_PRINT("info",
+ ("mroonga: fast_order_limit = false: "
+ "MATCH AGAINST must be only one"));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+ }
+ }
+ int n_max_sort_keys = select_lex->order_list.elements;
+ *n_sort_keys = 0;
+ size_t sort_keys_size = sizeof(grn_table_sort_key) * n_max_sort_keys;
+ *sort_keys = (grn_table_sort_key *)mrn_my_malloc(sort_keys_size,
+ MYF(MY_WME));
+ memset(*sort_keys, 0, sort_keys_size);
+ ORDER *order;
+ int i;
+ mrn_change_encoding(ctx, system_charset_info);
+ for (order = (ORDER *) select_lex->order_list.first, i = 0;
+ order;
+ order = order->next, i++) {
+ Item *item = *order->item;
+ if (item->type() == Item::FIELD_ITEM)
+ {
+ Field *field = static_cast<Item_field *>(item)->field;
+ mrn::ColumnName column_name(field->field_name);
+
+ if (should_normalize(field))
+ {
+ DBUG_PRINT("info", ("mroonga: fast_order_limit = false: "
+ "sort by collated value isn't supported yet."));
+ fast_order_limit = false;
+ my_free(*sort_keys);
+ *sort_keys = NULL;
+ *n_sort_keys = 0;
+ DBUG_VOID_RETURN;
+ }
+
+ if (is_storage_mode) {
+ (*sort_keys)[i].key = grn_obj_column(ctx, matched_record_keys,
+ column_name.c_str(),
+ column_name.length());
+ } else {
+ if (is_primary_key_field(field)) {
+ (*sort_keys)[i].key = grn_obj_column(ctx, matched_record_keys,
+ MRN_COLUMN_NAME_KEY,
+ strlen(MRN_COLUMN_NAME_KEY));
+ } else {
+ DBUG_PRINT("info", ("mroonga: fast_order_limit = false: "
+ "sort by not primary key value "
+ "isn't supported in wrapper mode."));
+ fast_order_limit = false;
+ my_free(*sort_keys);
+ *sort_keys = NULL;
+ *n_sort_keys = 0;
+ DBUG_VOID_RETURN;
+ }
+ }
+ } else if (!match_against || match_against->eq(item, true)) {
+ (*sort_keys)[i].key = grn_obj_column(ctx, matched_record_keys,
+ MRN_COLUMN_NAME_SCORE,
+ strlen(MRN_COLUMN_NAME_SCORE));
+ } else {
+ DBUG_PRINT("info", ("mroonga: fast_order_limit = false: "
+ "sort by computed value isn't supported."));
+ fast_order_limit = false;
+ my_free(*sort_keys);
+ *sort_keys = NULL;
+ *n_sort_keys = 0;
+ DBUG_VOID_RETURN;
+ }
+ (*sort_keys)[i].offset = 0;
+ if (MRN_ORDER_IS_ASC(order))
+ {
+ (*sort_keys)[i].flags = GRN_TABLE_SORT_ASC;
+ } else {
+ (*sort_keys)[i].flags = GRN_TABLE_SORT_DESC;
+ }
+ (*n_sort_keys)++;
+ }
+ DBUG_PRINT("info", ("mroonga: fast_order_limit = true"));
+ fast_order_limit = true;
+ mrn_fast_order_limit++;
+ DBUG_VOID_RETURN;
+ }
+ DBUG_PRINT("info", ("mroonga: fast_order_limit = false"));
+ fast_order_limit = false;
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::generic_store_bulk_fixed_size_string(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ grn_obj_reinit(ctx, buf, GRN_DB_SHORT_TEXT, 0);
+ GRN_TEXT_SET(ctx, buf, field->ptr, field->field_length);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_variable_size_string(Field *field,
+ grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ String value;
+ field->val_str(NULL, &value);
+ grn_obj_reinit(ctx, buf, GRN_DB_SHORT_TEXT, 0);
+ DBUG_PRINT("info", ("mroonga: length=%" MRN_FORMAT_STRING_LENGTH,
+ value.length()));
+ DBUG_PRINT("info", ("mroonga: value=%s", value.c_ptr_safe()));
+ GRN_TEXT_SET(ctx, buf, value.ptr(), value.length());
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_integer(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ long long value = field->val_int();
+ DBUG_PRINT("info", ("mroonga: value=%lld", value));
+ uint32 size = field->pack_length();
+ DBUG_PRINT("info", ("mroonga: size=%u", size));
+ Field_num *field_num = static_cast<Field_num *>(field);
+ bool is_unsigned = field_num->unsigned_flag;
+ DBUG_PRINT("info", ("mroonga: is_unsigned=%s", is_unsigned ? "true" : "false"));
+ switch (size) {
+ case 1:
+ if (is_unsigned) {
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT8, 0);
+ GRN_UINT8_SET(ctx, buf, value);
+ } else {
+ grn_obj_reinit(ctx, buf, GRN_DB_INT8, 0);
+ GRN_INT8_SET(ctx, buf, value);
+ }
+ break;
+ case 2:
+ if (is_unsigned) {
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT16, 0);
+ GRN_UINT16_SET(ctx, buf, value);
+ } else {
+ grn_obj_reinit(ctx, buf, GRN_DB_INT16, 0);
+ GRN_INT16_SET(ctx, buf, value);
+ }
+ break;
+ case 3:
+ case 4:
+ if (is_unsigned) {
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT32, 0);
+ GRN_UINT32_SET(ctx, buf, value);
+ } else {
+ grn_obj_reinit(ctx, buf, GRN_DB_INT32, 0);
+ GRN_INT32_SET(ctx, buf, value);
+ }
+ break;
+ case 8:
+ if (is_unsigned) {
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT64, 0);
+ GRN_UINT64_SET(ctx, buf, value);
+ } else {
+ grn_obj_reinit(ctx, buf, GRN_DB_INT64, 0);
+ GRN_INT64_SET(ctx, buf, value);
+ }
+ break;
+ default:
+ // Why!?
+ error = HA_ERR_UNSUPPORTED;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "unknown integer value size: <%u>: "
+ "available sizes: [1, 2, 3, 4, 8]",
+ size);
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING,
+ error, error_message);
+ break;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_unsigned_integer(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ long long signed_value = field->val_int();
+ unsigned long long unsigned_value = *((unsigned long long *)(&signed_value));
+ uint32 size = field->pack_length();
+ switch (size) {
+ case 1:
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT8, 0);
+ GRN_UINT8_SET(ctx, buf, unsigned_value);
+ break;
+ case 2:
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT16, 0);
+ GRN_UINT16_SET(ctx, buf, unsigned_value);
+ break;
+ case 3:
+ case 4:
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT32, 0);
+ GRN_UINT32_SET(ctx, buf, unsigned_value);
+ break;
+ case 8:
+ grn_obj_reinit(ctx, buf, GRN_DB_UINT64, 0);
+ GRN_UINT64_SET(ctx, buf, unsigned_value);
+ break;
+ default:
+ // Why!?
+ error = HA_ERR_UNSUPPORTED;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "unknown unsigned integer value size: <%u>: "
+ "available sizes: [1, 2, 3, 4, 8]",
+ size);
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING,
+ error, error_message);
+ break;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_float(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ double value = field->val_real();
+ uint32 size = field->pack_length();
+ switch (size) {
+ case 4:
+ case 8:
+ grn_obj_reinit(ctx, buf, GRN_DB_FLOAT, 0);
+ GRN_FLOAT_SET(ctx, buf, value);
+ break;
+ default:
+ // Why!?
+ error = HA_ERR_UNSUPPORTED;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "unknown float value size: <%u>: "
+ "available sizes: [4, 8]",
+ size);
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING,
+ error, error_message);
+ break;
+ }
+ DBUG_RETURN(error);
+}
+
+long long int ha_mroonga::get_grn_time_from_timestamp_field(Field_timestamp *field)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int grn_time = 0;
+#ifdef MRN_TIMESTAMP_USE_TIMEVAL
+ int warnings = 0;
+ struct timeval time_value;
+ if (field->get_timestamp(&time_value, &warnings)) {
+ // XXX: Should we report warnings or MySQL does?
+ } else {
+ DBUG_PRINT("info", ("mroonga: timeval tv_sec=%ld", time_value.tv_sec));
+ grn_time = GRN_TIME_PACK(time_value.tv_sec, time_value.tv_usec);
+ }
+#elif defined(MRN_TIMESTAMP_USE_MY_TIME_T)
+ unsigned long int micro_seconds;
+ my_time_t seconds = field->get_timestamp(&micro_seconds);
+ DBUG_PRINT("info", ("mroonga: my_time_t seconds=%ld", seconds));
+ grn_time = GRN_TIME_PACK(seconds, micro_seconds);
+#else
+ my_bool is_null_value;
+ long seconds = field->get_timestamp(&is_null_value);
+ DBUG_PRINT("info", ("mroonga: long seconds=%ld", seconds));
+ grn_time = GRN_TIME_PACK(seconds, 0);
+#endif
+ DBUG_RETURN(grn_time);
+}
+
+int ha_mroonga::generic_store_bulk_timestamp(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ Field_timestamp *timestamp_field = (Field_timestamp *)field;
+ long long int time = get_grn_time_from_timestamp_field(timestamp_field);
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_date(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ long long int date_value = field->val_int();
+ struct tm date;
+ memset(&date, 0, sizeof(struct tm));
+ date.tm_year = date_value / 10000 % 10000 - mrn::TimeConverter::TM_YEAR_BASE;
+ date.tm_mon = date_value / 100 % 100 - 1;
+ date.tm_mday = date_value % 100;
+ int usec = 0;
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.tm_to_grn_time(&date, usec, &truncated);
+ if (truncated) {
+ field->set_warning(MRN_SEVERITY_WARNING,
+ WARN_DATA_TRUNCATED, 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_time(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ Field_time *time_field = (Field_time *)field;
+ MYSQL_TIME mysql_time;
+ time_field->get_date(&mysql_time, Time::Options(current_thd));
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ field->set_warning(MRN_SEVERITY_WARNING,
+ WARN_DATA_TRUNCATED, 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_datetime(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ Field_datetime *datetime_field = (Field_datetime *)field;
+ MYSQL_TIME mysql_time;
+ datetime_field->get_date(&mysql_time, Time::Options(current_thd));
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_year(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+
+ int year;
+ if (field->field_length == 2) {
+ year = static_cast<int>(field->val_int() + 2000);
+ } else {
+ year = static_cast<int>(field->val_int());
+ }
+
+ DBUG_PRINT("info", ("mroonga: year=%d", year));
+ struct tm date;
+ memset(&date, 0, sizeof(struct tm));
+ date.tm_year = year - mrn::TimeConverter::TM_YEAR_BASE;
+ date.tm_mon = 0;
+ date.tm_mday = 1;
+
+ int usec = 0;
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.tm_to_grn_time(&date, usec, &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+int ha_mroonga::generic_store_bulk_datetime2(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ Field_datetimef *datetimef_field = (Field_datetimef *)field;
+ MYSQL_TIME mysql_time;
+ datetimef_field->get_date(&mysql_time, Time::Options(current_thd));
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+#endif
+
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+int ha_mroonga::generic_store_bulk_time2(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ MYSQL_TIME mysql_time;
+ field->get_date(&mysql_time, Time::Options(current_thd));
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+#endif
+
+int ha_mroonga::generic_store_bulk_new_date(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ Field_newdate *newdate_field = (Field_newdate *)field;
+ MYSQL_TIME mysql_date;
+ newdate_field->get_date(&mysql_date, Time::Options(current_thd));
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.mysql_time_to_grn_time(&mysql_date,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ grn_obj_reinit(ctx, buf, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, buf, time);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_new_decimal(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ String value;
+ Field_new_decimal *new_decimal_field = (Field_new_decimal *)field;
+ new_decimal_field->val_str(&value, NULL);
+ grn_obj_reinit(ctx, buf, GRN_DB_SHORT_TEXT, 0);
+ GRN_TEXT_SET(ctx, buf, value.ptr(), value.length());
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_blob(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ String buffer;
+ Field_blob *blob = (Field_blob *)field;
+ String *value = blob->val_str(0, &buffer);
+ grn_obj_reinit(ctx, buf, GRN_DB_TEXT, 0);
+ GRN_TEXT_SET(ctx, buf, value->ptr(), value->length());
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_store_bulk_geometry(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+#ifdef MRN_HAVE_SPATIAL
+ String buffer;
+ Field_blob *geometry = (Field_blob *)field;
+ String *value = geometry->val_str(0, &buffer);
+ const char *wkb = value->ptr();
+ int len = value->length();
+ error = mrn_set_geometry(ctx, buf, wkb, len);
+#endif
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+int ha_mroonga::generic_store_bulk_json(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ String buffer;
+ Field_json *json = static_cast<Field_json *>(field);
+ String *value = json->val_str(&buffer, NULL);
+ grn_obj_reinit(ctx, buf, GRN_DB_TEXT, 0);
+ GRN_TEXT_SET(ctx, buf, value->ptr(), value->length());
+ DBUG_RETURN(error);
+}
+#endif
+
+int ha_mroonga::generic_store_bulk(Field *field, grn_obj *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ return error;
+ switch (field->real_type()) {
+ case MYSQL_TYPE_DECIMAL:
+ error = generic_store_bulk_variable_size_string(field, buf);
+ break;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ error = generic_store_bulk_integer(field, buf);
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ error = generic_store_bulk_float(field, buf);
+ break;
+ case MYSQL_TYPE_NULL:
+ error = generic_store_bulk_unsigned_integer(field, buf);
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ error = generic_store_bulk_timestamp(field, buf);
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ error = generic_store_bulk_integer(field, buf);
+ break;
+ case MYSQL_TYPE_DATE:
+ error = generic_store_bulk_date(field, buf);
+ break;
+ case MYSQL_TYPE_TIME:
+ error = generic_store_bulk_time(field, buf);
+ break;
+ case MYSQL_TYPE_DATETIME:
+ error = generic_store_bulk_datetime(field, buf);
+ break;
+ case MYSQL_TYPE_YEAR:
+ error = generic_store_bulk_year(field, buf);
+ break;
+ case MYSQL_TYPE_NEWDATE:
+ error = generic_store_bulk_new_date(field, buf);
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ error = generic_store_bulk_variable_size_string(field, buf);
+ break;
+ case MYSQL_TYPE_BIT:
+ error = generic_store_bulk_unsigned_integer(field, buf);
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ case MYSQL_TYPE_TIMESTAMP2:
+ error = generic_store_bulk_timestamp(field, buf);
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case MYSQL_TYPE_DATETIME2:
+ error = generic_store_bulk_datetime2(field, buf);
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ case MYSQL_TYPE_TIME2:
+ error = generic_store_bulk_time2(field, buf);
+ break;
+#endif
+ case MYSQL_TYPE_NEWDECIMAL:
+ error = generic_store_bulk_new_decimal(field, buf);
+ break;
+ case MYSQL_TYPE_ENUM:
+ error = generic_store_bulk_unsigned_integer(field, buf);
+ break;
+ case MYSQL_TYPE_SET:
+ error = generic_store_bulk_unsigned_integer(field, buf);
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ error = generic_store_bulk_blob(field, buf);
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ error = generic_store_bulk_variable_size_string(field, buf);
+ break;
+ case MYSQL_TYPE_STRING:
+ error = generic_store_bulk_fixed_size_string(field, buf);
+ break;
+ case MYSQL_TYPE_GEOMETRY:
+ error = generic_store_bulk_geometry(field, buf);
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ case MYSQL_TYPE_JSON:
+ error = generic_store_bulk_json(field, buf);
+ break;
+#endif
+ default:
+ error = HA_ERR_UNSUPPORTED;
+ break;
+ }
+ DBUG_RETURN(error);
+}
+
+void ha_mroonga::storage_store_field_string(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ field->store(value, value_length, field->charset());
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_integer(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ Field_num *field_num = static_cast<Field_num *>(field);
+ bool is_unsigned = field_num->unsigned_flag;
+ switch (value_length) {
+ case 1:
+ {
+ if (is_unsigned) {
+ unsigned char field_value;
+ field_value = *((unsigned char *)value);
+ field->store(field_value, is_unsigned);
+ } else {
+ signed char field_value;
+ field_value = *((signed char *)value);
+ field->store(field_value, is_unsigned);
+ }
+ break;
+ }
+ case 2:
+ {
+ if (is_unsigned) {
+ unsigned short field_value;
+ field_value = *((unsigned short *)value);
+ field->store(field_value, is_unsigned);
+ } else {
+ short field_value;
+ field_value = *((short *)value);
+ field->store(field_value, is_unsigned);
+ }
+ break;
+ }
+ case 4:
+ {
+ if (is_unsigned) {
+ unsigned int field_value;
+ field_value = *((unsigned int *)value);
+ field->store(field_value, is_unsigned);
+ } else {
+ int field_value;
+ field_value = *((int *)value);
+ field->store(field_value, is_unsigned);
+ }
+ break;
+ }
+ case 8:
+ {
+ if (is_unsigned) {
+ unsigned long long int field_value;
+ field_value = *((unsigned long long int *)value);
+ DBUG_PRINT("info", ("mroonga: field_value=%llu", field_value));
+ field->store(field_value, is_unsigned);
+ } else {
+ long long int field_value;
+ field_value = *((long long int *)value);
+ field->store(field_value, is_unsigned);
+ }
+ break;
+ }
+ default:
+ {
+ // Why!?
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "unknown integer value size: <%d>: "
+ "available sizes: [1, 2, 4, 8]",
+ value_length);
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING,
+ HA_ERR_UNSUPPORTED, error_message);
+ storage_store_field_string(field, value, value_length);
+ break;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_unsigned_integer(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ switch (value_length) {
+ case 1:
+ {
+ unsigned char field_value;
+ field_value = *((unsigned char *)value);
+ field->store(field_value, true);
+ break;
+ }
+ case 2:
+ {
+ unsigned short field_value;
+ field_value = *((unsigned short *)value);
+ field->store(field_value, true);
+ break;
+ }
+ case 4:
+ {
+ unsigned int field_value;
+ field_value = *((unsigned int *)value);
+ field->store(field_value, true);
+ break;
+ }
+ case 8:
+ {
+ unsigned long long int field_value;
+ field_value = *((unsigned long long int *)value);
+ DBUG_PRINT("info", ("mroonga: field_value=%llu", field_value));
+ field->store(field_value, true);
+ break;
+ }
+ default:
+ {
+ // Why!?
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "unknown integer value size: <%d>: "
+ "available sizes: [1, 2, 4, 8]",
+ value_length);
+ push_warning(ha_thd(), MRN_SEVERITY_WARNING,
+ HA_ERR_UNSUPPORTED, error_message);
+ storage_store_field_string(field, value, value_length);
+ break;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_float(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ double field_value;
+ field_value = *((double *)value);
+ field->store(field_value);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_timestamp(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ Field_timestamp *timestamp_field = (Field_timestamp *)field;
+#ifdef MRN_TIMESTAMP_USE_TIMEVAL
+ struct timeval time_value;
+ GRN_TIME_UNPACK(time, time_value.tv_sec, time_value.tv_usec);
+ timestamp_field->store_timestamp(&time_value);
+#elif defined(MRN_TIMESTAMP_USE_MY_TIME_T)
+ long long int sec, usec;
+ GRN_TIME_UNPACK(time, sec, usec);
+ timestamp_field->store_TIME(static_cast<int32>(sec),
+ static_cast<int32>(usec));
+#else
+ int32 sec, usec __attribute__((unused));
+ GRN_TIME_UNPACK(time, sec, usec);
+ timestamp_field->store_timestamp(sec);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_date(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ long long int sec, usec __attribute__((unused));
+ GRN_TIME_UNPACK(time, sec, usec);
+ struct tm date;
+ time_t sec_t = static_cast<int32>(sec);
+ gmtime_r(&sec_t, &date);
+ long long int date_in_mysql =
+ (date.tm_year + mrn::TimeConverter::TM_YEAR_BASE) * 10000 +
+ (date.tm_mon + 1) * 100 +
+ date.tm_mday;
+ field->store(date_in_mysql, false);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_time(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ MYSQL_TIME mysql_time;
+ memset(&mysql_time, 0, sizeof(MYSQL_TIME));
+ mysql_time.time_type = MYSQL_TIMESTAMP_TIME;
+ mrn::TimeConverter time_converter;
+ time_converter.grn_time_to_mysql_time(time, &mysql_time);
+#ifdef MRN_FIELD_STORE_TIME_NEED_TYPE
+ Field_time *time_field = (Field_time *)field;
+ time_field->store_time(&mysql_time, mysql_time.time_type);
+#else
+ field->store_time(&mysql_time);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_datetime(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ MYSQL_TIME mysql_datetime;
+ memset(&mysql_datetime, 0, sizeof(MYSQL_TIME));
+ mysql_datetime.time_type = MYSQL_TIMESTAMP_DATETIME;
+ mrn::TimeConverter time_converter;
+ time_converter.grn_time_to_mysql_time(time, &mysql_datetime);
+#ifdef MRN_FIELD_STORE_TIME_NEED_TYPE
+ Field_datetime *datetime_field = (Field_datetime *)field;
+ datetime_field->store_time(&mysql_datetime, mysql_datetime.time_type);
+#else
+ field->store_time(&mysql_datetime);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_year(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ MYSQL_TIME mysql_time;
+ memset(&mysql_time, 0, sizeof(MYSQL_TIME));
+ mysql_time.time_type = MYSQL_TIMESTAMP_DATE;
+ mrn::TimeConverter time_converter;
+ time_converter.grn_time_to_mysql_time(time, &mysql_time);
+ DBUG_PRINT("info", ("mroonga: stored %d", mysql_time.year));
+ field->store(mysql_time.year, false);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_new_date(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ MYSQL_TIME mysql_date;
+ memset(&mysql_date, 0, sizeof(MYSQL_TIME));
+ mysql_date.time_type = MYSQL_TIMESTAMP_DATE;
+ mrn::TimeConverter time_converter;
+ time_converter.grn_time_to_mysql_time(time, &mysql_date);
+#ifdef MRN_FIELD_STORE_TIME_NEED_TYPE
+ Field_newdate *newdate_field = (Field_newdate *)field;
+ newdate_field->store_time(&mysql_date, MYSQL_TIMESTAMP_DATE);
+#else
+ field->store_time(&mysql_date);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+void ha_mroonga::storage_store_field_datetime2(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+ MYSQL_TIME mysql_datetime;
+ memset(&mysql_datetime, 0, sizeof(MYSQL_TIME));
+ mysql_datetime.time_type = MYSQL_TIMESTAMP_DATETIME;
+ mrn::TimeConverter time_converter;
+ time_converter.grn_time_to_mysql_time(time, &mysql_datetime);
+ field->store_time(&mysql_datetime);
+ DBUG_VOID_RETURN;
+}
+#endif
+
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+void ha_mroonga::storage_store_field_time2(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ long long int time = *((long long int *)value);
+
+ MYSQL_TIME mysql_time;
+ memset(&mysql_time, 0, sizeof(MYSQL_TIME));
+ mysql_time.time_type = MYSQL_TIMESTAMP_TIME;
+ mrn::TimeConverter time_converter;
+ time_converter.grn_time_to_mysql_time(time, &mysql_time);
+ field->store_time(&mysql_time);
+ DBUG_VOID_RETURN;
+}
+#endif
+
+void ha_mroonga::storage_store_field_blob(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ Field_blob *blob = (Field_blob *)field;
+ String *blob_buffer = &blob_buffers[field->field_index];
+ blob_buffer->length(0);
+ blob_buffer->reserve(value_length);
+ blob_buffer->q_append(value, value_length);
+ blob->set_ptr((uint32) value_length, (uchar *) blob_buffer->ptr());
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_field_geometry(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+#ifdef MRN_HAVE_SPATIAL
+ uchar wkb[SRID_SIZE + WKB_HEADER_SIZE + POINT_DATA_SIZE];
+ grn_geo_point *field_value = (grn_geo_point *)value;
+ int latitude, longitude;
+ latitude = field_value->latitude;
+ longitude = field_value->longitude;
+ if (grn_source_column_geo) {
+ GRN_GEO_POINT_SET(ctx, &source_point, latitude, longitude);
+ }
+ memset(wkb, 0, SRID_SIZE);
+ memset(wkb + SRID_SIZE, Geometry::wkb_ndr, 1); // wkb_ndr is meaningless.
+ int4store(wkb + SRID_SIZE + 1, Geometry::wkb_point);
+ double latitude_in_degree, longitude_in_degree;
+ latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
+ longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
+ float8store(wkb + SRID_SIZE + WKB_HEADER_SIZE,
+ longitude_in_degree);
+ float8store(wkb + SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE,
+ latitude_in_degree);
+ String *geometry_buffer = &blob_buffers[field->field_index];
+ geometry_buffer->length(0);
+ uint wkb_length = sizeof(wkb) / sizeof(*wkb);
+ Field_blob *geometry= (Field_blob *)field;
+ geometry_buffer->reserve(wkb_length);
+ geometry_buffer->q_append((const char *) wkb, wkb_length);
+ geometry->set_ptr((uint32) wkb_length, (uchar *) geometry_buffer->ptr());
+#endif
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+void ha_mroonga::storage_store_field_json(Field *field,
+ const char *value,
+ uint value_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ Field_json *json = static_cast<Field_json *>(field);
+ json->store(value, value_length, field->charset());
+ DBUG_VOID_RETURN;
+}
+#endif
+
+void ha_mroonga::storage_store_field(Field *field,
+ const char *value, uint value_length)
+{
+ field->set_notnull();
+ switch (field->real_type()) {
+ case MYSQL_TYPE_DECIMAL:
+ storage_store_field_string(field, value, value_length);
+ break;
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ storage_store_field_integer(field, value, value_length);
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ storage_store_field_float(field, value, value_length);
+ break;
+ case MYSQL_TYPE_NULL:
+ storage_store_field_unsigned_integer(field, value, value_length);
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ storage_store_field_timestamp(field, value, value_length);
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_INT24:
+ storage_store_field_integer(field, value, value_length);
+ break;
+ case MYSQL_TYPE_DATE:
+ storage_store_field_date(field, value, value_length);
+ break;
+ case MYSQL_TYPE_TIME:
+ storage_store_field_time(field, value, value_length);
+ break;
+ case MYSQL_TYPE_DATETIME:
+ storage_store_field_datetime(field, value, value_length);
+ break;
+ case MYSQL_TYPE_YEAR:
+ storage_store_field_year(field, value, value_length);
+ break;
+ case MYSQL_TYPE_NEWDATE:
+ storage_store_field_new_date(field, value, value_length);
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ storage_store_field_string(field, value, value_length);
+ break;
+ case MYSQL_TYPE_BIT:
+ storage_store_field_unsigned_integer(field, value, value_length);
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ case MYSQL_TYPE_TIMESTAMP2:
+ storage_store_field_timestamp(field, value, value_length);
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case MYSQL_TYPE_DATETIME2:
+ storage_store_field_datetime2(field, value, value_length);
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ case MYSQL_TYPE_TIME2:
+ storage_store_field_time2(field, value, value_length);
+ break;
+#endif
+ case MYSQL_TYPE_NEWDECIMAL:
+ storage_store_field_string(field, value, value_length);
+ break;
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ storage_store_field_unsigned_integer(field, value, value_length);
+ break;
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ storage_store_field_blob(field, value, value_length);
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ storage_store_field_string(field, value, value_length);
+ break;
+ case MYSQL_TYPE_GEOMETRY:
+ storage_store_field_geometry(field, value, value_length);
+ break;
+ case MYSQL_TYPE_VARCHAR_COMPRESSED:
+ case MYSQL_TYPE_BLOB_COMPRESSED:
+ DBUG_ASSERT(0);
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ case MYSQL_TYPE_JSON:
+ storage_store_field_json(field, value, value_length);
+ break;
+#endif
+ }
+}
+
+void ha_mroonga::storage_store_field_column(Field *field, bool is_primary_key,
+ int nth_column, grn_id record_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!grn_columns[nth_column]) {
+ DBUG_VOID_RETURN;
+ }
+
+ grn_obj *column = grn_columns[nth_column];
+ grn_id range_id = grn_obj_get_range(ctx, column);
+ grn_obj *range = grn_column_ranges[nth_column];
+ grn_obj *value = &new_value_buffer;
+
+ if (mrn::grn::is_table(range)) {
+ if (mrn::grn::is_vector_column(column)) {
+ grn_obj_reinit(ctx, value, range_id, GRN_OBJ_VECTOR);
+ grn_obj_get_value(ctx, column, record_id, value);
+
+ grn_obj unvectored_value;
+ GRN_TEXT_INIT(&unvectored_value, 0);
+ int n_ids = GRN_BULK_VSIZE(value) / sizeof(grn_id);
+ for (int i = 0; i < n_ids; i++) {
+ grn_id id = GRN_RECORD_VALUE_AT(value, i);
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, &unvectored_value, mrn_vector_column_delimiter);
+ }
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_length;
+ key_length = grn_table_get_key(ctx, range, id,
+ &key, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_PUT(ctx, &unvectored_value, key, key_length);
+ }
+ storage_store_field(field,
+ GRN_TEXT_VALUE(&unvectored_value),
+ GRN_TEXT_LEN(&unvectored_value));
+ GRN_OBJ_FIN(ctx, &unvectored_value);
+ } else {
+ grn_obj_reinit(ctx, value, range_id, 0);
+ grn_obj_get_value(ctx, column, record_id, value);
+
+ grn_id id = GRN_RECORD_VALUE(value);
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_length;
+ key_length = grn_table_get_key(ctx, range, id,
+ &key, GRN_TABLE_MAX_KEY_SIZE);
+ storage_store_field(field, key, key_length);
+ }
+ } else {
+ grn_obj_reinit(ctx, value, range_id, 0);
+ grn_obj_get_value(ctx, column, record_id, value);
+ if (is_primary_key && GRN_BULK_VSIZE(value) == 0) {
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_length;
+ key_length = grn_table_get_key(ctx, grn_table, record_id,
+ &key, GRN_TABLE_MAX_KEY_SIZE);
+ storage_store_field(field, key, key_length);
+ } else {
+ storage_store_field(field, GRN_BULK_HEAD(value), GRN_BULK_VSIZE(value));
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_fields(uchar *buf, grn_id record_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info", ("mroonga: stored record ID: %d", record_id));
+
+ my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(buf, table->record[0]);
+
+ Field *primary_key_field = NULL;
+ if (table->s->primary_key != MAX_INDEXES) {
+ KEY *key_info = &(table->s->key_info[table->s->primary_key]);
+ if (KEY_N_KEY_PARTS(key_info) == 1) {
+ primary_key_field = key_info->key_part[0].field;
+ }
+ }
+
+ int i;
+ int n_columns = table->s->fields;
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+
+ if (bitmap_is_set(table->read_set, field->field_index) ||
+ bitmap_is_set(table->write_set, field->field_index)) {
+ const char *column_name = field->field_name.str;
+
+ if (ignoring_no_key_columns) {
+ KEY *key_info = &(table->s->key_info[active_index]);
+ if (strcmp(key_info->key_part[0].field->field_name.str, column_name)) {
+ continue;
+ }
+ }
+
+ mrn::DebugColumnAccess debug_column_access(table, &table->write_set);
+ DBUG_PRINT("info", ("mroonga: store column %d(%d)",i,field->field_index));
+ field->move_field_offset(ptr_diff);
+ if (strcmp(MRN_COLUMN_NAME_ID, column_name) == 0) {
+ // for _id column
+ field->set_notnull();
+ field->store((int)record_id);
+ } else if (primary_key_field &&
+ strcmp(primary_key_field->field_name.str, column_name) == 0) {
+ // for primary key column
+ storage_store_field_column(field, true, i, record_id);
+ } else {
+ storage_store_field_column(field, false, i, record_id);
+ }
+ field->move_field_offset(-ptr_diff);
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_fields_for_prep_update(const uchar *old_data,
+ const uchar *new_data,
+ grn_id record_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info", ("mroonga: stored record ID: %d", record_id));
+ my_ptrdiff_t ptr_diff_old = PTR_BYTE_DIFF(old_data, table->record[0]);
+ my_ptrdiff_t ptr_diff_new = 0;
+#ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
+ if (!written_by_row_based_binlog) {
+ if (check_written_by_row_based_binlog()) {
+ written_by_row_based_binlog = 2;
+ } else {
+ written_by_row_based_binlog = 1;
+ }
+ }
+ bool need_all_columns =
+ (new_data && written_by_row_based_binlog == 2);
+#endif
+ if (new_data) {
+ ptr_diff_new = PTR_BYTE_DIFF(new_data, table->record[0]);
+ }
+ int i;
+ int n_columns = table->s->fields;
+ for (i = 0; i < n_columns; i++) {
+ Field *field = table->field[i];
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+ if (
+ !bitmap_is_set(table->read_set, field->field_index) &&
+ !bitmap_is_set(table->write_set, field->field_index) &&
+#ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
+ (
+ need_all_columns ||
+#endif
+ bitmap_is_set(&multiple_column_key_bitmap, field->field_index)
+#ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
+ )
+#endif
+ ) {
+ mrn::DebugColumnAccess debug_column_access(table, &table->write_set);
+ DBUG_PRINT("info", ("mroonga: store column %d(%d)",i,field->field_index));
+ grn_obj value;
+ GRN_OBJ_INIT(&value, GRN_BULK, 0, grn_obj_get_range(ctx, grn_columns[i]));
+ grn_obj_get_value(ctx, grn_columns[i], record_id, &value);
+ // old column
+ field->move_field_offset(ptr_diff_old);
+ storage_store_field(field, GRN_BULK_HEAD(&value), GRN_BULK_VSIZE(&value));
+ field->move_field_offset(-ptr_diff_old);
+ if (new_data) {
+ // new column
+ field->move_field_offset(ptr_diff_new);
+ storage_store_field(field, GRN_BULK_HEAD(&value), GRN_BULK_VSIZE(&value));
+ field->move_field_offset(-ptr_diff_new);
+ }
+ GRN_OBJ_FIN(ctx, &value);
+ }
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_store_fields_by_index(uchar *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint key_length;
+ void *key;
+ KEY *key_info = &table->key_info[active_index];
+ if (table->s->primary_key == active_index)
+ key_length = grn_table_cursor_get_key(ctx, cursor, &key);
+ else
+ key_length = grn_table_cursor_get_key(ctx, index_table_cursor, &key);
+
+ if (KEY_N_KEY_PARTS(key_info) == 1) {
+ my_ptrdiff_t ptr_diff = PTR_BYTE_DIFF(buf, table->record[0]);
+ Field *field = key_info->key_part->field;
+ mrn::DebugColumnAccess debug_column_access(table, &table->write_set);
+ field->move_field_offset(ptr_diff);
+ storage_store_field(field, (const char *)key, key_length);
+ field->move_field_offset(-ptr_diff);
+ } else {
+ uchar enc_buf[MAX_KEY_LENGTH];
+ uint enc_len;
+ mrn::MultipleColumnKeyCodec codec(ctx, ha_thd(), key_info);
+ codec.decode(static_cast<uchar *>(key), key_length, enc_buf, &enc_len);
+ key_restore(buf, enc_buf, key_info, enc_len);
+ }
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::storage_encode_key_normalize_min_sort_chars(Field *field,
+ uchar *buf,
+ uint size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ if (size == 0) {
+ DBUG_RETURN(0);
+ }
+ if (!field->has_charset()) {
+ DBUG_RETURN(0);
+ }
+
+ uint16 raw_min_sort_char =
+ static_cast<uint16>(field->sort_charset()->min_sort_char);
+ if (raw_min_sort_char <= UINT_MAX8) {
+ uchar min_sort_char = static_cast<uchar>(raw_min_sort_char);
+ for (uint i = size - 1; i > 0; --i) {
+ if (buf[i] != min_sort_char) {
+ break;
+ }
+ buf[i] = '\0';
+ }
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_fixed_size_string(Field *field,
+ const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ memcpy(buf, key, field->field_length);
+ *size = field->field_length;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_variable_size_string(Field *field,
+ const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ *size = uint2korr(key);
+ memcpy(buf, key + HA_KEY_BLOB_LENGTH, *size);
+ storage_encode_key_normalize_min_sort_chars(field, buf, *size);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_timestamp(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ long long int time;
+ MYSQL_TIME mysql_time;
+#ifdef MRN_MARIADB_P
+ if (field->decimals() == 0) {
+ my_time_t my_time = sint4korr(key);
+ mrn_my_tz_UTC->gmt_sec_to_TIME(&mysql_time, my_time);
+ mysql_time.second_part = 0;
+ } else {
+ Field_timestamp_hires *timestamp_hires_field =
+ (Field_timestamp_hires *)field;
+ uchar *ptr_backup = field->ptr;
+ uchar *null_ptr_backup = field->null_ptr;
+ TABLE *table_backup = field->table;
+ field->ptr = (uchar *)key;
+ field->null_ptr = (uchar *)(key - 1);
+ field->table = table;
+ Temporal::Options opt(TIME_CONV_NONE, current_thd);
+ timestamp_hires_field->get_date(&mysql_time, opt);
+ field->ptr = ptr_backup;
+ field->null_ptr = null_ptr_backup;
+ field->table = table_backup;
+ }
+#else
+ my_time_t my_time = uint4korr(key);
+ mrn_my_tz_UTC->gmt_sec_to_TIME(&mysql_time, my_time);
+#endif
+ mrn::TimeConverter time_converter;
+ time = time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &time, 8);
+ *size = 8;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_time(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ long long int time;
+#ifdef MRN_MARIADB_P
+ MYSQL_TIME mysql_time;
+ bool truncated = false;
+ if (field->decimals() == 0) {
+ long long int packed_time = sint3korr(key);
+ mysql_time.neg = false;
+ if (packed_time < 0) {
+ mysql_time.neg = true;
+ packed_time = -packed_time;
+ }
+ mysql_time.year = 0;
+ mysql_time.month = 0;
+ mysql_time.day = 0;
+ mysql_time.hour = (int)(packed_time / 10000);
+ long long int minute_part = packed_time - mysql_time.hour * 10000;
+ mysql_time.minute = (int)(minute_part / 100);
+ mysql_time.second = (int)(minute_part % 100);
+ mysql_time.second_part = 0;
+ mysql_time.time_type = MYSQL_TIMESTAMP_TIME;
+ } else {
+ Field_time_hires *time_hires_field = (Field_time_hires *)field;
+ uchar *ptr_backup = field->ptr;
+ uchar *null_ptr_backup = field->null_ptr;
+ field->ptr = (uchar *)key;
+ field->null_ptr = (uchar *)(key - 1);
+ Temporal::Options opt(TIME_CONV_NONE, current_thd);
+ time_hires_field->get_date(&mysql_time, opt);
+ field->ptr = ptr_backup;
+ field->null_ptr = null_ptr_backup;
+ }
+ mrn::TimeConverter time_converter;
+ time = time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+#else
+ int mysql_time = (int)sint3korr(key);
+ int sec =
+ mysql_time / 10000 * 60 * 60 +
+ mysql_time / 100 % 100 * 60 +
+ mysql_time % 60;
+ int usec = 0;
+ time = GRN_TIME_PACK(sec, usec);
+#endif
+ memcpy(buf, &time, 8);
+ *size = 8;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_year(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ int year = (int)key[0];
+
+ struct tm datetime;
+ memset(&datetime, 0, sizeof(struct tm));
+ datetime.tm_year = year;
+ datetime.tm_mon = 0;
+ datetime.tm_mday = 1;
+ int usec = 0;
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.tm_to_grn_time(&datetime, usec,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &time, 8);
+ *size = 8;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_datetime(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+ long long int time;
+#ifdef MRN_MARIADB_P
+ if (field->decimals() > 0) {
+ Field_datetime_hires *datetime_hires_field = (Field_datetime_hires *)field;
+ MYSQL_TIME mysql_time;
+ uchar *ptr_backup = field->ptr;
+ uchar *null_ptr_backup = field->null_ptr;
+ field->ptr = (uchar *)key;
+ field->null_ptr = (uchar *)(key - 1);
+ Temporal::Options opt(TIME_CONV_NONE, current_thd);
+ datetime_hires_field->get_date(&mysql_time, opt);
+ field->ptr = ptr_backup;
+ field->null_ptr = null_ptr_backup;
+ mrn::TimeConverter time_converter;
+ time = time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
+ } else
+#endif
+ {
+ long long int encoded_datetime = sint8korr(key);
+ uint32 part1 = (uint32)(encoded_datetime / 1000000LL);
+ uint32 part2 = (uint32)(encoded_datetime -
+ (unsigned long long int)part1 * 1000000LL);
+ struct tm date;
+ memset(&date, 0, sizeof(struct tm));
+ date.tm_year = part1 / 10000 - mrn::TimeConverter::TM_YEAR_BASE;
+ date.tm_mon = part1 / 100 % 100 - 1;
+ date.tm_mday = part1 % 100;
+ date.tm_hour = part2 / 10000;
+ date.tm_min = part2 / 100 % 100;
+ date.tm_sec = part2 % 100;
+ int usec = 0;
+ mrn::TimeConverter time_converter;
+ time = time_converter.tm_to_grn_time(&date, usec, &truncated);
+ }
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &time, 8);
+ *size = 8;
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+int ha_mroonga::storage_encode_key_timestamp2(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+
+ Field_timestampf *timestamp2_field = (Field_timestampf *)field;
+ struct timeval tm;
+ my_timestamp_from_binary(&tm, key, timestamp2_field->decimals());
+ MYSQL_TIME mysql_time;
+ mrn_my_tz_UTC->gmt_sec_to_TIME(&mysql_time, (my_time_t)tm.tv_sec);
+ mysql_time.second_part = tm.tv_usec;
+ mrn::TimeConverter time_converter;
+ long long int grn_time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &grn_time, 8);
+ *size = 8;
+
+ DBUG_RETURN(error);
+}
+#endif
+
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+int ha_mroonga::storage_encode_key_datetime2(Field *field, bool is_null,
+ const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+
+ Field_datetimef *datetime2_field = (Field_datetimef *)field;
+ longlong packed_time = is_null ? 0 :
+ my_datetime_packed_from_binary(key, datetime2_field->decimals());
+ MYSQL_TIME mysql_time;
+ TIME_from_longlong_datetime_packed(&mysql_time, packed_time);
+ mrn::TimeConverter time_converter;
+ long long int grn_time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &grn_time, 8);
+ *size = 8;
+
+ DBUG_RETURN(error);
+}
+#endif
+
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+int ha_mroonga::storage_encode_key_time2(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ bool truncated = false;
+
+ Field_timef *time2_field = (Field_timef *)field;
+ longlong packed_time =
+ my_time_packed_from_binary(key, time2_field->decimals());
+ MYSQL_TIME mysql_time;
+ TIME_from_longlong_time_packed(&mysql_time, packed_time);
+ mrn::TimeConverter time_converter;
+ long long int grn_time = time_converter.mysql_time_to_grn_time(&mysql_time,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &grn_time, 8);
+ *size = 8;
+
+ DBUG_RETURN(error);
+}
+#endif
+
+int ha_mroonga::storage_encode_key_enum(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (field->pack_length() == 1) {
+ uchar value;
+ value = key[0];
+ *size = 1;
+ memcpy(buf, &value, *size);
+ } else {
+ uint16 value;
+ mrn::value_decoder::decode(&value, key);
+ *size = 2;
+ memcpy(buf, &value, *size);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key_set(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ Field_set unpacker((uchar *)key, field->field_length, (uchar *)(key - 1),
+ field->null_bit, field->unireg_check,
+ &field->field_name,
+ field->pack_length(),
+ static_cast<Field_set*>(field)->typelib,
+ static_cast<Field_set*>(field)->charset());
+ switch (field->pack_length()) {
+ case 1:
+ {
+ int8 signed_value = (int8)(unpacker.val_int());
+ uint8 unsigned_value = *((uint8 *)&signed_value);
+ *size = 1;
+ memcpy(buf, &unsigned_value, *size);
+ }
+ break;
+ case 2:
+ {
+ int16 signed_value = (int16)(unpacker.val_int());
+ uint16 unsigned_value = *((uint16 *)&signed_value);
+ *size = 2;
+ memcpy(buf, &unsigned_value, *size);
+ }
+ break;
+ case 3:
+ case 4:
+ {
+ int32 signed_value = (int32)(unpacker.val_int());
+ uint32 unsigned_value = *((uint32 *)&signed_value);
+ *size = 4;
+ memcpy(buf, &unsigned_value, *size);
+ }
+ break;
+ case 8:
+ default:
+ {
+ int64 signed_value = (int64)(unpacker.val_int());
+ uint64 unsigned_value = *((uint64 *)&signed_value);
+ *size = 8;
+ memcpy(buf, &unsigned_value, *size);
+ }
+ break;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_key(Field *field, const uchar *key,
+ uchar *buf, uint *size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ bool truncated = false;
+ bool is_null = false;
+ const uchar *ptr = key;
+
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ DBUG_RETURN(error);
+
+ if (field->null_bit) {
+ is_null = *ptr;
+ ptr += 1;
+ }
+
+ switch (field->real_type()) {
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_TINY:
+ {
+ memcpy(buf, ptr, 1);
+ *size = 1;
+ break;
+ }
+ case MYSQL_TYPE_SHORT:
+ {
+ memcpy(buf, ptr, 2);
+ *size = 2;
+ break;
+ }
+ case MYSQL_TYPE_INT24:
+ {
+ memcpy(buf, ptr, 3);
+ buf[3] = 0;
+ *size = 4;
+ break;
+ }
+ case MYSQL_TYPE_LONG:
+ {
+ memcpy(buf, ptr, 4);
+ *size = 4;
+ break;
+ }
+ case MYSQL_TYPE_TIMESTAMP:
+ error = storage_encode_key_timestamp(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ {
+ memcpy(buf, ptr, 8);
+ *size = 8;
+ break;
+ }
+ case MYSQL_TYPE_FLOAT:
+ {
+ float float_value;
+ double double_value;
+ mrn::value_decoder::decode(&float_value, ptr);
+ double_value = float_value;
+ memcpy(buf, &double_value, 8);
+ *size = 8;
+ break;
+ }
+ case MYSQL_TYPE_DOUBLE:
+ {
+ double val;
+ mrn::value_decoder::decode(&val, ptr);
+ memcpy(buf, &val, 8);
+ *size = 8;
+ break;
+ }
+ case MYSQL_TYPE_TIME:
+ error = storage_encode_key_time(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_YEAR:
+ error = storage_encode_key_year(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_DATETIME:
+ error = storage_encode_key_datetime(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_NEWDATE:
+ {
+ uint32 encoded_date = uint3korr(ptr);
+ struct tm date;
+ memset(&date, 0, sizeof(struct tm));
+ date.tm_year = encoded_date / (16 * 32) - mrn::TimeConverter::TM_YEAR_BASE;
+ date.tm_mon = encoded_date / 32 % 16 - 1;
+ date.tm_mday = encoded_date % 32;
+ int usec = 0;
+ mrn::TimeConverter time_converter;
+ long long int time = time_converter.tm_to_grn_time(&date, usec,
+ &truncated);
+ if (truncated) {
+ if (MRN_ABORT_ON_WARNING(ha_thd())) {
+ error = MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd());
+ }
+ field->set_warning(MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(ha_thd()),
+ 1);
+ }
+ memcpy(buf, &time, 8);
+ *size = 8;
+ break;
+ }
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ case MYSQL_TYPE_TIMESTAMP2:
+ error = storage_encode_key_timestamp2(field, ptr, buf, size);
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case MYSQL_TYPE_DATETIME2:
+ error = storage_encode_key_datetime2(field, is_null, ptr, buf, size);
+ break;
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ case MYSQL_TYPE_TIME2:
+ error = storage_encode_key_time2(field, ptr, buf, size);
+ break;
+#endif
+ case MYSQL_TYPE_STRING:
+ error = storage_encode_key_fixed_size_string(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_VARCHAR:
+ case MYSQL_TYPE_BLOB:
+ error = storage_encode_key_variable_size_string(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_ENUM:
+ error = storage_encode_key_enum(field, ptr, buf, size);
+ break;
+ case MYSQL_TYPE_SET:
+ error = storage_encode_key_set(field, ptr, buf, size);
+ break;
+ default:
+ error = HA_ERR_UNSUPPORTED;
+ break;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_multiple_column_key(KEY *key_info,
+ const uchar *key,
+ uint key_length,
+ uchar *buffer,
+ uint *encoded_length)
+{
+ MRN_DBUG_ENTER_METHOD();
+ mrn::MultipleColumnKeyCodec codec(ctx, ha_thd(), key_info);
+ int error = codec.encode(key, key_length, buffer, encoded_length);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_multiple_column_key_range(KEY *key_info,
+ const uchar *start,
+ uint start_size,
+ const uchar *end,
+ uint end_size,
+ uchar *min_buffer,
+ uint *min_encoded_size,
+ uchar *max_buffer,
+ uint *max_encoded_size)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ mrn::MultipleColumnKeyCodec codec(ctx, ha_thd(), key_info);
+ uint encoded_key_size = codec.size();
+ if (start) {
+ memset(min_buffer, 0, encoded_key_size);
+ error = codec.encode(start, start_size,
+ min_buffer, min_encoded_size);
+ // TODO: handle error?
+ *min_encoded_size = encoded_key_size;
+ }
+ if (end) {
+ memset(max_buffer, 0xff, encoded_key_size);
+ error = codec.encode(end, end_size,
+ max_buffer, max_encoded_size);
+ // TODO: handle error?
+ *max_encoded_size = encoded_key_size;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_encode_multiple_column_key_range(KEY *key_info,
+ const key_range *start,
+ const key_range *end,
+ uchar *min_buffer,
+ uint *min_encoded_size,
+ uchar *max_buffer,
+ uint *max_encoded_size)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ const uchar *start_data = NULL;
+ uint start_size = 0;
+ const uchar *end_data = NULL;
+ uint end_size = 0;
+ if (start) {
+ start_data = start->key;
+ start_size = start->length;
+ }
+ if (end) {
+ end_data = end->key;
+ end_size = end->length;
+ }
+
+ int error = storage_encode_multiple_column_key_range(key_info,
+ start_data, start_size,
+ end_data, end_size,
+ min_buffer,
+ min_encoded_size,
+ max_buffer,
+ max_encoded_size);
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_reset()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ if (thd_sql_command(ha_thd()) != SQLCOM_SELECT) {
+ DBUG_RETURN(error);
+ }
+
+ TABLE_LIST *table_list = table->pos_in_table_list;
+ if (!table_list) {
+ DBUG_RETURN(error);
+ }
+
+ st_select_lex *select_lex = table_list->select_lex;
+ if (!select_lex) {
+ DBUG_RETURN(error);
+ }
+
+ List_iterator<Item_func_match> iterator(*(select_lex->ftfunc_list));
+ Item_func_match *item;
+ while ((item = iterator++)) {
+ if (item->ft_handler) {
+ mrn_generic_ft_clear(item->ft_handler);
+ }
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_reset()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_reset();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ if (alter_key_info_buffer) {
+ my_free(alter_key_info_buffer);
+ alter_key_info_buffer = NULL;
+ }
+#else
+ if (wrap_alter_key_info) {
+ my_free(wrap_alter_key_info);
+ wrap_alter_key_info = NULL;
+ }
+#endif
+ wrap_ft_init_count = 0;
+ int generic_error = generic_reset();
+ if (error == 0) {
+ error = generic_error;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_reset()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ error = generic_reset();
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::reset()
+{
+ int error = 0;
+ THD *thd = ha_thd();
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info", ("mroonga: this=%p", this));
+ clear_empty_value_records();
+ clear_search_result();
+ clear_search_result_geo();
+ if (share->wrapper_mode)
+ error = wrapper_reset();
+ else
+ error = storage_reset();
+ ignoring_no_key_columns = false;
+ inserting_with_update = false;
+ ignoring_duplicated_key = false;
+ fulltext_searching = false;
+ replacing_ = false;
+ written_by_row_based_binlog = 0;
+ mrn_lock_type = F_UNLCK;
+ mrn_clear_slot_data(thd);
+ current_ft_item = NULL;
+ DBUG_RETURN(error);
+}
+
+handler *ha_mroonga::wrapper_clone(const char *name, MEM_ROOT *mem_root)
+{
+ handler *cloned_handler;
+ MRN_DBUG_ENTER_METHOD();
+ if (!(cloned_handler = get_new_handler(table->s, mem_root,
+ table->s->db_type())))
+ DBUG_RETURN(NULL);
+ ((ha_mroonga *) cloned_handler)->is_clone = true;
+ ((ha_mroonga *) cloned_handler)->parent_for_clone = this;
+ ((ha_mroonga *) cloned_handler)->mem_root_for_clone = mem_root;
+ if (cloned_handler->ha_open(table, table->s->normalized_path.str,
+ table->db_stat, HA_OPEN_IGNORE_IF_LOCKED))
+ {
+ delete cloned_handler;
+ DBUG_RETURN(NULL);
+ }
+ DBUG_RETURN(cloned_handler);
+}
+
+handler *ha_mroonga::storage_clone(const char *name, MEM_ROOT *mem_root)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler *cloned_handler;
+ cloned_handler = handler::clone(name, mem_root);
+ DBUG_RETURN(cloned_handler);
+}
+
+handler *ha_mroonga::clone(const char *name, MEM_ROOT *mem_root)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler *cloned_handler;
+ if (share->wrapper_mode)
+ {
+ cloned_handler = wrapper_clone(name, mem_root);
+ } else {
+ cloned_handler = storage_clone(name, mem_root);
+ }
+ DBUG_RETURN(cloned_handler);
+}
+
+uint8 ha_mroonga::wrapper_table_cache_type()
+{
+ uint8 res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->table_cache_type();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+uint8 ha_mroonga::storage_table_cache_type()
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint8 type = handler::table_cache_type();
+ DBUG_RETURN(type);
+}
+
+uint8 ha_mroonga::table_cache_type()
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint8 type;
+ if (share->wrapper_mode)
+ {
+ type = wrapper_table_cache_type();
+ } else {
+ type = storage_table_cache_type();
+ }
+ DBUG_RETURN(type);
+}
+
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ
+ha_rows ha_mroonga::wrapper_multi_range_read_info_const(uint keyno,
+ RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges,
+ uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows;
+ KEY *key_info = &(table->key_info[keyno]);
+ if (mrn_is_geo_key(key_info)) {
+ rows = handler::multi_range_read_info_const(keyno, seq, seq_init_param,
+ n_ranges, bufsz, flags, cost);
+ DBUG_RETURN(rows);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+ rows = wrap_handler->multi_range_read_info_const(keyno, seq, seq_init_param,
+ n_ranges, bufsz, flags,
+ cost);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(rows);
+}
+
+ha_rows ha_mroonga::storage_multi_range_read_info_const(uint keyno,
+ RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges,
+ uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows = handler::multi_range_read_info_const(keyno, seq,
+ seq_init_param,
+ n_ranges, bufsz, flags,
+ cost);
+ DBUG_RETURN(rows);
+}
+
+ha_rows ha_mroonga::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows;
+ if (share->wrapper_mode)
+ {
+ rows = wrapper_multi_range_read_info_const(keyno, seq, seq_init_param,
+ n_ranges, bufsz,
+ flags, cost);
+ } else {
+ rows = storage_multi_range_read_info_const(keyno, seq, seq_init_param,
+ n_ranges, bufsz,
+ flags, cost);
+ }
+ DBUG_RETURN(rows);
+}
+
+ha_rows ha_mroonga::wrapper_multi_range_read_info(uint keyno, uint n_ranges,
+ uint keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ uint key_parts,
+#endif
+ uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows;
+ KEY *key_info = &(table->key_info[keyno]);
+ if (mrn_is_geo_key(key_info)) {
+ rows = handler::multi_range_read_info(keyno, n_ranges, keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ key_parts,
+#endif
+ bufsz, flags, cost);
+ DBUG_RETURN(rows);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+ rows = wrap_handler->multi_range_read_info(keyno, n_ranges, keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ key_parts,
+#endif
+ bufsz, flags, cost);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(rows);
+}
+
+ha_rows ha_mroonga::storage_multi_range_read_info(uint keyno, uint n_ranges,
+ uint keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ uint key_parts,
+#endif
+ uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows = handler::multi_range_read_info(keyno, n_ranges, keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ key_parts,
+#endif
+ bufsz, flags, cost);
+ DBUG_RETURN(rows);
+}
+
+ha_rows ha_mroonga::multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ uint key_parts,
+#endif
+ uint *bufsz, uint *flags,
+ Cost_estimate *cost)
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows;
+ if (share->wrapper_mode)
+ {
+ rows = wrapper_multi_range_read_info(keyno, n_ranges, keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ key_parts,
+#endif
+ bufsz, flags, cost);
+ } else {
+ rows = storage_multi_range_read_info(keyno, n_ranges, keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ key_parts,
+#endif
+ bufsz, flags, cost);
+ }
+ DBUG_RETURN(rows);
+}
+
+int ha_mroonga::wrapper_multi_range_read_init(RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = handler::multi_range_read_init(seq, seq_init_param,
+ n_ranges, mode, buf);
+ DBUG_RETURN(error);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+ error = wrap_handler->multi_range_read_init(seq, seq_init_param,
+ n_ranges, mode, buf);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_multi_range_read_init(RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = handler::multi_range_read_init(seq, seq_init_param,
+ n_ranges, mode, buf);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_multi_range_read_init(seq, seq_init_param,
+ n_ranges, mode, buf);
+ } else {
+ error = storage_multi_range_read_init(seq, seq_init_param,
+ n_ranges, mode, buf);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_multi_range_read_next(range_id_t *range_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = handler::multi_range_read_next(range_info);
+ DBUG_RETURN(error);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+ error = wrap_handler->multi_range_read_next(range_info);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_multi_range_read_next(range_id_t *range_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = handler::multi_range_read_next(range_info);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::multi_range_read_next(range_id_t *range_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_multi_range_read_next(range_info);
+ } else {
+ error = storage_multi_range_read_next(range_info);
+ }
+ DBUG_RETURN(error);
+}
+#else // MRN_HANDLER_HAVE_MULTI_RANGE_READ
+int ha_mroonga::wrapper_read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = handler::read_multi_range_first(found_range_p, ranges,
+ range_count, sorted, buffer);
+ DBUG_RETURN(error);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+ error = wrap_handler->read_multi_range_first(found_range_p, ranges,
+ range_count, sorted, buffer);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = handler::read_multi_range_first(found_range_p, ranges,
+ range_count, sorted, buffer);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_read_multi_range_first(found_range_p, ranges,
+ range_count, sorted, buffer);
+ } else {
+ error = storage_read_multi_range_first(found_range_p, ranges,
+ range_count, sorted, buffer);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->key_info[active_index]);
+ if (mrn_is_geo_key(key_info)) {
+ error = handler::read_multi_range_next(found_range_p);
+ DBUG_RETURN(error);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ if (fulltext_searching)
+ set_pk_bitmap();
+ error = wrap_handler->read_multi_range_next(found_range_p);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = handler::read_multi_range_next(found_range_p);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::read_multi_range_next(KEY_MULTI_RANGE **found_range_p)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_read_multi_range_next(found_range_p);
+ } else {
+ error = storage_read_multi_range_next(found_range_p);
+ }
+ DBUG_RETURN(error);
+}
+#endif // MRN_HANDLER_HAVE_MULTI_RANGE_READ
+
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+void ha_mroonga::wrapper_start_bulk_insert(ha_rows rows, uint flags)
+#else
+void ha_mroonga::wrapper_start_bulk_insert(ha_rows rows)
+#endif
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+ wrap_handler->ha_start_bulk_insert(rows, flags);
+#else
+ wrap_handler->ha_start_bulk_insert(rows);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+void ha_mroonga::storage_start_bulk_insert(ha_rows rows, uint flags)
+#else
+void ha_mroonga::storage_start_bulk_insert(ha_rows rows)
+#endif
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+void ha_mroonga::start_bulk_insert(ha_rows rows, uint flags)
+#else
+void ha_mroonga::start_bulk_insert(ha_rows rows)
+#endif
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode) {
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+ wrapper_start_bulk_insert(rows, flags);
+#else
+ wrapper_start_bulk_insert(rows);
+#endif
+ } else {
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+ storage_start_bulk_insert(rows, flags);
+#else
+ storage_start_bulk_insert(rows);
+#endif
+ }
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::wrapper_end_bulk_insert()
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_end_bulk_insert();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_end_bulk_insert()
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::end_bulk_insert()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_end_bulk_insert();
+ } else {
+ error = storage_end_bulk_insert();
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::generic_delete_all_rows(grn_obj *target_grn_table,
+ const char *function_name)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info",
+ ("mroonga: dry write: %s::%s", MRN_CLASS_NAME, function_name));
+ DBUG_RETURN(error);
+ }
+
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx, target_grn_table,
+ NULL, 0,
+ NULL, 0,
+ 0, -1,
+ 0);
+ if (cursor) {
+ while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_table_cursor_delete(ctx, cursor);
+ }
+ grn_table_cursor_close(ctx, cursor);
+ } else {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_delete_all_rows()
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_delete_all_rows();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+ if (error) {
+ DBUG_RETURN(error);
+ }
+
+ if (!wrapper_have_target_index()) {
+ DBUG_RETURN(error);
+ }
+
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->key_info[i]);
+
+ if (!(wrapper_is_target_index(key_info))) {
+ continue;
+ }
+
+ if (!grn_index_tables[i]) {
+ /* disable keys */
+ continue;
+ }
+
+ error = generic_delete_all_rows(grn_index_tables[i], __FUNCTION__);
+ if (error) {
+ break;
+ }
+ }
+
+ int grn_table_error;
+ grn_table_error = generic_delete_all_rows(grn_table, __FUNCTION__);
+ if (!error) {
+ error = grn_table_error;
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_delete_all_rows()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = generic_delete_all_rows(grn_table, __FUNCTION__);
+ if (!error) {
+ uint n_keys = table->s->keys;
+ for (uint i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &(table->key_info[i]);
+ if (!(key_info->flags & HA_NOSAME)) {
+ continue;
+ }
+
+ grn_obj *index_table = grn_index_tables[i];
+ if (!index_table) {
+ continue;
+ }
+
+ error = generic_delete_all_rows(index_table, __FUNCTION__);
+ if (error) {
+ break;
+ }
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::delete_all_rows()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_delete_all_rows();
+ } else {
+ error = storage_delete_all_rows();
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_truncate()
+{
+ int error = 0;
+ MRN_SHARE *tmp_share;
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!(tmp_share = mrn_get_share(table->s->table_name.str, table, &error)))
+ DBUG_RETURN(error);
+
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = parse_engine_table_options(ha_thd(), tmp_share->hton, table->s)
+ ? MRN_GET_ERROR_NUMBER
+ : wrap_handler->ha_truncate();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+ mrn_free_share(tmp_share);
+
+ if (!error && wrapper_have_target_index()) {
+ error = wrapper_truncate_index();
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_truncate_index()
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info",
+ ("mroonga: dry write: %s::%s", MRN_CLASS_NAME, __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ grn_rc rc;
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ KEY *key_info = &(table->key_info[i]);
+
+ if (!(wrapper_is_target_index(key_info))) {
+ continue;
+ }
+
+ if (!grn_index_tables[i]) {
+ /* disable keys */
+ continue;
+ }
+
+ rc = grn_table_truncate(ctx, grn_index_tables[i]);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+err:
+ rc = grn_table_truncate(ctx, grn_table);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_truncate()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ if (is_dry_write()) {
+ DBUG_PRINT("info", ("mroonga: dry write: ha_mroonga::%s", __FUNCTION__));
+ DBUG_RETURN(error);
+ }
+
+ grn_rc rc;
+ rc = grn_table_truncate(ctx, grn_table);
+ if (rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_WRITE);
+ }
+ error = storage_truncate_index();
+
+ if (!error && thd_sql_command(ha_thd()) == SQLCOM_TRUNCATE) {
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ long_term_share->auto_inc_value = 0;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ long_term_share->auto_inc_inited = false;
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_truncate_index()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ grn_rc rc;
+ uint i;
+ uint n_keys = table->s->keys;
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+
+ KEY *key_info = &(table->key_info[i]);
+
+ if (
+ !(key_info->flags & HA_NOSAME) &&
+ (KEY_N_KEY_PARTS(key_info) == 1 || (key_info->flags & HA_FULLTEXT))
+ ) {
+ continue;
+ }
+
+ if (!grn_index_tables[i]) {
+ /* disable keys */
+ continue;
+ }
+
+ rc = grn_table_truncate(ctx, grn_index_tables[i]);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto err;
+ }
+ }
+err:
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::truncate()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_truncate();
+ } else {
+ error = storage_truncate();
+ }
+ if (!error) {
+ operations_->clear(table->s->table_name.str,
+ table->s->table_name.length);
+ }
+ DBUG_RETURN(error);
+}
+
+double ha_mroonga::wrapper_scan_time()
+{
+ double res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->scan_time();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+double ha_mroonga::storage_scan_time()
+{
+ MRN_DBUG_ENTER_METHOD();
+ double time = handler::scan_time();
+ DBUG_RETURN(time);
+}
+
+double ha_mroonga::scan_time()
+{
+ MRN_DBUG_ENTER_METHOD();
+ double time;
+ if (share->wrapper_mode)
+ {
+ time = wrapper_scan_time();
+ } else {
+ time = storage_scan_time();
+ }
+ DBUG_RETURN(time);
+}
+
+double ha_mroonga::wrapper_read_time(uint index, uint ranges, ha_rows rows)
+{
+ double res;
+ MRN_DBUG_ENTER_METHOD();
+ if (index < MAX_KEY) {
+ KEY *key_info = &(table->key_info[index]);
+ if (mrn_is_geo_key(key_info)) {
+ res = handler::read_time(index, ranges, rows);
+ DBUG_RETURN(res);
+ }
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->read_time(share->wrap_key_nr[index], ranges, rows);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ } else {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->read_time(index, ranges, rows);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ DBUG_RETURN(res);
+}
+
+double ha_mroonga::storage_read_time(uint index, uint ranges, ha_rows rows)
+{
+ MRN_DBUG_ENTER_METHOD();
+ double time = handler::read_time(index, ranges, rows);
+ DBUG_RETURN(time);
+}
+
+double ha_mroonga::read_time(uint index, uint ranges, ha_rows rows)
+{
+ MRN_DBUG_ENTER_METHOD();
+ double time;
+ if (share->wrapper_mode)
+ {
+ time = wrapper_read_time(index, ranges, rows);
+ } else {
+ time = storage_read_time(index, ranges, rows);
+ }
+ DBUG_RETURN(time);
+}
+
+#ifdef MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
+const key_map *ha_mroonga::wrapper_keys_to_use_for_scanning()
+{
+ const key_map *res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->keys_to_use_for_scanning();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+const key_map *ha_mroonga::storage_keys_to_use_for_scanning()
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(&key_map_full);
+}
+
+const key_map *ha_mroonga::keys_to_use_for_scanning()
+{
+ MRN_DBUG_ENTER_METHOD();
+ const key_map *key_map;
+ if (share->wrapper_mode)
+ {
+ key_map = wrapper_keys_to_use_for_scanning();
+ } else {
+ key_map = storage_keys_to_use_for_scanning();
+ }
+ DBUG_RETURN(key_map);
+}
+#endif
+
+ha_rows ha_mroonga::wrapper_estimate_rows_upper_bound()
+{
+ ha_rows res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->estimate_rows_upper_bound();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+ha_rows ha_mroonga::storage_estimate_rows_upper_bound()
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows = handler::estimate_rows_upper_bound();
+ DBUG_RETURN(rows);
+}
+
+ha_rows ha_mroonga::estimate_rows_upper_bound()
+{
+ MRN_DBUG_ENTER_METHOD();
+ ha_rows rows;
+ if (share->wrapper_mode)
+ {
+ rows = wrapper_estimate_rows_upper_bound();
+ } else {
+ rows = storage_estimate_rows_upper_bound();
+ }
+ DBUG_RETURN(rows);
+}
+
+void ha_mroonga::wrapper_update_create_info(HA_CREATE_INFO* create_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->update_create_info(create_info);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_update_create_info(HA_CREATE_INFO* create_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::update_create_info(create_info);
+ if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) {
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ if (!long_term_share->auto_inc_inited) {
+ storage_info(HA_STATUS_AUTO);
+ }
+ create_info->auto_increment_value = long_term_share->auto_inc_value;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::update_create_info(HA_CREATE_INFO* create_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (!create_info->connect_string.str)
+ {
+ create_info->connect_string.str = table->s->connect_string.str;
+ create_info->connect_string.length = table->s->connect_string.length;
+ }
+ if (share->wrapper_mode)
+ wrapper_update_create_info(create_info);
+ else
+ storage_update_create_info(create_info);
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(ha_thd(), true);
+ if (slot_data) {
+ slot_data->alter_create_info = create_info;
+ if (slot_data->alter_connect_string) {
+ my_free(slot_data->alter_connect_string);
+ slot_data->alter_connect_string = NULL;
+ }
+ if (create_info->connect_string.str) {
+ slot_data->alter_connect_string =
+ mrn_my_strndup(create_info->connect_string.str,
+ create_info->connect_string.length,
+ MYF(MY_WME));
+ }
+ if (slot_data->alter_comment) {
+ my_free(slot_data->alter_comment);
+ slot_data->alter_comment = NULL;
+ }
+ if (create_info->comment.str) {
+ slot_data->alter_comment =
+ mrn_my_strndup(create_info->comment.str,
+ create_info->comment.length,
+ MYF(MY_WME));
+ }
+ if (share && share->disable_keys) {
+ slot_data->disable_keys_create_info = create_info;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::wrapper_rename_table(const char *from, const char *to,
+ MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name)
+{
+ int error = 0;
+ handler *hnd;
+ MRN_DBUG_ENTER_METHOD();
+
+ hnd = get_new_handler(tmp_share->table_share,
+ current_thd->mem_root,
+ tmp_share->hton);
+ if (!hnd)
+ {
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+
+ if ((error = hnd->ha_rename_table(from, to)))
+ {
+ delete hnd;
+ DBUG_RETURN(error);
+ }
+
+ error = wrapper_rename_index(from, to, tmp_share,
+ from_table_name, to_table_name);
+
+ delete hnd;
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_rename_index(const char *from, const char *to,
+ MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name)
+{
+ int error;
+ grn_rc rc;
+ MRN_DBUG_ENTER_METHOD();
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = ensure_database_open(from);
+ if (error)
+ DBUG_RETURN(error);
+
+ TABLE_SHARE *tmp_table_share = tmp_share->table_share;
+
+ uint i;
+ for (i = 0; i < tmp_table_share->keys; i++) {
+ const char *mysql_index_name = tmp_table_share->key_info[i].name.str;
+ mrn::IndexTableName from_index_table_name(from_table_name, mysql_index_name);
+ mrn::IndexTableName to_index_table_name(to_table_name, mysql_index_name);
+ grn_obj *index_table;
+ index_table = grn_ctx_get(ctx,
+ from_index_table_name.c_str(),
+ from_index_table_name.length());
+ if (!index_table) {
+ index_table = grn_ctx_get(ctx,
+ from_index_table_name.old_c_str(),
+ from_index_table_name.old_length());
+ }
+ if (index_table) {
+ rc = grn_table_rename(ctx, index_table,
+ to_index_table_name.c_str(),
+ to_index_table_name.length());
+ if (rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+ }
+
+ grn_obj *table = grn_ctx_get(ctx, from_table_name, strlen(from_table_name));
+ if (ctx->rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ rc = grn_table_rename(ctx, table, to_table_name,
+ strlen(to_table_name));
+ if (rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::storage_rename_table(const char *from, const char *to,
+ MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name)
+{
+ int error;
+ grn_rc rc;
+ TABLE_SHARE *tmp_table_share = tmp_share->table_share;
+ MRN_LONG_TERM_SHARE *from_long_term_share = tmp_share->long_term_share,
+ *to_long_term_share;
+ MRN_DBUG_ENTER_METHOD();
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ error = ensure_database_open(from);
+ if (error)
+ DBUG_RETURN(error);
+
+ if (!(to_long_term_share = mrn_get_long_term_share(to, strlen(to), &error)))
+ DBUG_RETURN(error);
+ to_long_term_share->auto_inc_value = from_long_term_share->auto_inc_value;
+ DBUG_PRINT("info", ("mroonga: to_auto_inc_value=%llu",
+ to_long_term_share->auto_inc_value));
+ to_long_term_share->auto_inc_inited = from_long_term_share->auto_inc_inited;
+
+ uint i;
+ for (i = 0; i < tmp_table_share->keys; i++) {
+ const char *mysql_index_name = tmp_table_share->key_info[i].name.str;
+ mrn::IndexTableName from_index_table_name(from_table_name,
+ mysql_index_name);
+ mrn::IndexTableName to_index_table_name(to_table_name,
+ mysql_index_name);
+ grn_obj *index_table;
+ index_table = grn_ctx_get(ctx,
+ from_index_table_name.c_str(),
+ from_index_table_name.length());
+ if (!index_table) {
+ index_table = grn_ctx_get(ctx,
+ from_index_table_name.old_c_str(),
+ from_index_table_name.old_length());
+ }
+ if (index_table) {
+ rc = grn_table_rename(ctx, index_table,
+ to_index_table_name.c_str(),
+ to_index_table_name.length());
+ if (rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto error_end;
+ }
+ }
+ }
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+ error = storage_rename_foreign_key(tmp_share, from_table_name, to_table_name);
+ if (error) {
+ goto error_end;
+ }
+#endif
+ {
+ grn_obj *table_obj = grn_ctx_get(ctx, from_table_name, strlen(from_table_name));
+ if (ctx->rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto error_end;
+ }
+ rc = grn_table_rename(ctx, table_obj, to_table_name,
+ strlen(to_table_name));
+ if (rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ goto error_end;
+ }
+ }
+ DBUG_RETURN(0);
+
+error_end:
+ mrn_free_long_term_share(to_long_term_share);
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+int ha_mroonga::storage_rename_foreign_key(MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name)
+{
+ int error;
+ uint i;
+ grn_obj *column, *ref_column;
+ grn_rc rc;
+ TABLE_SHARE *tmp_table_share = tmp_share->table_share;
+ uint n_columns = tmp_table_share->fields;
+ MRN_DBUG_ENTER_METHOD();
+ for (i = 0; i < n_columns; ++i) {
+ Field *field = tmp_table_share->field[i];
+
+ if (!is_foreign_key_field(from_table_name, field->field_name.str)) {
+ continue;
+ }
+
+ grn_obj *grn_from_table = grn_ctx_get(ctx, from_table_name, -1);
+ mrn::ColumnName column_name(field->field_name);
+ column = grn_obj_column(ctx,
+ grn_from_table,
+ column_name.c_str(),
+ column_name.length());
+ if (!column) {
+ continue;
+ }
+ grn_id ref_table_id = grn_obj_get_range(ctx, column);
+ grn_obj *ref_table = grn_ctx_at(ctx, ref_table_id);
+ mrn::IndexColumnName from_index_column_name(from_table_name,
+ column_name.c_str());
+ ref_column = grn_obj_column(ctx, ref_table,
+ from_index_column_name.c_str(),
+ from_index_column_name.length());
+ if (!ref_column) {
+ continue;
+ }
+ mrn::IndexColumnName to_index_column_name(to_table_name,
+ column_name.c_str());
+ rc = grn_column_rename(ctx, ref_column,
+ to_index_column_name.c_str(),
+ to_index_column_name.length());
+ if (rc != GRN_SUCCESS) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+ DBUG_RETURN(0);
+}
+#endif
+
+int ha_mroonga::rename_table(const char *from, const char *to)
+{
+ int error = 0;
+ TABLE_LIST table_list;
+ TABLE_SHARE *tmp_table_share;
+ TABLE tmp_table;
+ MRN_SHARE *tmp_share;
+ MRN_DBUG_ENTER_METHOD();
+ mrn::PathMapper to_mapper(to);
+ mrn::PathMapper from_mapper(from);
+ if (strcmp(from_mapper.db_name(), to_mapper.db_name()))
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+
+ LEX_CSTRING db_name= { from_mapper.db_name(), strlen(from_mapper.db_name()) };
+ LEX_CSTRING table_name= { from_mapper.mysql_table_name(),
+ strlen(from_mapper.mysql_table_name()) };
+ table_list.init_one_table(&db_name, &table_name, 0,TL_WRITE);
+ mrn_open_mutex_lock(NULL);
+ tmp_table_share = mrn_create_tmp_table_share(&table_list, from, &error);
+ mrn_open_mutex_unlock(NULL);
+ if (!tmp_table_share) {
+ DBUG_RETURN(error);
+ }
+ tmp_table.s = tmp_table_share;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ tmp_table.part_info = NULL;
+#endif
+ if (!(tmp_share = mrn_get_share(from, &tmp_table, &error)))
+ {
+ mrn_open_mutex_lock(NULL);
+ mrn_free_tmp_table_share(tmp_table_share);
+ mrn_open_mutex_unlock(NULL);
+ DBUG_RETURN(error);
+ }
+
+ if (tmp_share->wrapper_mode)
+ {
+ error = wrapper_rename_table(from, to, tmp_share,
+ from_mapper.table_name(),
+ to_mapper.table_name());
+ } else {
+ error = storage_rename_table(from, to, tmp_share,
+ from_mapper.table_name(),
+ to_mapper.table_name());
+ }
+
+ if (!error && to_mapper.table_name()[0] == '#') {
+ error = add_wrap_hton(to, tmp_share->hton);
+ } else if (error && from_mapper.table_name()[0] == '#') {
+ add_wrap_hton(from, tmp_share->hton);
+ }
+ if (!error) {
+ mrn_free_long_term_share(tmp_share->long_term_share);
+ tmp_share->long_term_share = NULL;
+ }
+ mrn_free_share(tmp_share);
+ mrn_open_mutex_lock(NULL);
+ mrn_free_tmp_table_share(tmp_table_share);
+ mrn_open_mutex_unlock(NULL);
+
+ DBUG_RETURN(error);
+}
+
+bool ha_mroonga::wrapper_is_crashed() const
+{
+ bool res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->is_crashed();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::storage_is_crashed() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ mrn::DatabaseRepairer repairer(ctx, ha_thd());
+ bool crashed = repairer.is_crashed();
+ DBUG_RETURN(crashed);
+}
+
+bool ha_mroonga::is_crashed() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool crashed;
+ if (share->wrapper_mode)
+ {
+ crashed = wrapper_is_crashed();
+ } else {
+ crashed = storage_is_crashed();
+ }
+ DBUG_RETURN(crashed);
+}
+
+bool ha_mroonga::wrapper_auto_repair(int error) const
+{
+ bool repaired;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_AUTO_REPAIR_HAVE_ERROR
+ repaired = wrap_handler->auto_repair(error);
+#else
+ repaired = wrap_handler->auto_repair();
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(repaired);
+}
+
+bool ha_mroonga::storage_auto_repair(int error) const
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool repaired;
+#ifdef MRN_HANDLER_AUTO_REPAIR_HAVE_ERROR
+ repaired = handler::auto_repair(error);
+#else
+ repaired = handler::auto_repair();
+#endif
+ DBUG_RETURN(repaired);
+}
+
+bool ha_mroonga::auto_repair(int error) const
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool repaired;
+ // TODO: We should consider about creating share for error =
+ // ER_CANT_OPEN_FILE. The following code just ignores the error.
+ if (share && share->wrapper_mode)
+ {
+ repaired = wrapper_auto_repair(error);
+ } else {
+ repaired = storage_auto_repair(error);
+ }
+ DBUG_RETURN(repaired);
+}
+
+bool ha_mroonga::auto_repair() const
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool repaired = auto_repair(HA_ERR_CRASHED_ON_USAGE);
+ DBUG_RETURN(repaired);
+}
+
+int ha_mroonga::generic_disable_index(int i, KEY *key_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ if (share->index_table[i]) {
+ char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
+ snprintf(index_column_name, GRN_TABLE_MAX_KEY_SIZE - 1,
+ "%s.%s", share->index_table[i], key_info[i].name.str);
+ grn_obj *index_column = grn_ctx_get(ctx,
+ index_column_name,
+ strlen(index_column_name));
+ if (index_column) {
+ grn_obj_remove(ctx, index_column);
+ }
+ } else {
+ mrn::PathMapper mapper(share->table_name);
+ mrn::IndexTableName index_table_name(mapper.table_name(),
+ key_info[i].name.str);
+ grn_obj *index_table = grn_ctx_get(ctx,
+ index_table_name.c_str(),
+ index_table_name.length());
+ if (!index_table) {
+ index_table = grn_ctx_get(ctx,
+ index_table_name.old_c_str(),
+ index_table_name.old_length());
+ }
+ if (index_table) {
+ grn_obj_remove(ctx, index_table);
+ }
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_index_tables[i] = NULL;
+ grn_index_columns[i] = NULL;
+ } else {
+ // TODO: Implement ctx->rc to error converter and use it.
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ }
+
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_disable_indexes_mroonga(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
+ uint i;
+ for (i = 0; i < table_share->keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+ if (share->wrap_key_nr[i] < MAX_KEY) {
+ continue;
+ }
+ if (!grn_index_tables[i]) {
+ DBUG_PRINT("info", ("mroonga: keys are disabled already %u", i));
+ DBUG_RETURN(0);
+ }
+ }
+ KEY *key_info = table_share->key_info;
+ for (i = 0; i < table_share->keys; i++) {
+ if (!(key_info[i].flags & HA_FULLTEXT) &&
+ !mrn_is_geo_key(&key_info[i])) {
+ continue;
+ }
+
+ int sub_error = generic_disable_index(i, key_info);
+ if (error != 0 && sub_error != 0) {
+ error = sub_error;
+ }
+ }
+ } else {
+ error = HA_ERR_WRONG_COMMAND;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_disable_indexes(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_disable_indexes(mode);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (error == HA_ERR_WRONG_COMMAND) {
+ error = 0;
+ }
+ if (!error) {
+ error = wrapper_disable_indexes_mroonga(mode);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_disable_indexes(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
+ uint i;
+ for (i = 0; i < table_share->keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+ if (!grn_index_tables[i]) {
+ DBUG_PRINT("info", ("mroonga: keys are disabled already %u", i));
+ DBUG_RETURN(0);
+ }
+ }
+ KEY *key_info = table_share->key_info;
+ for (i = 0; i < table_share->keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+ if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE &&
+ (key_info[i].flags & HA_NOSAME)) {
+ continue;
+ }
+
+ int sub_error = generic_disable_index(i, key_info);
+ if (error != 0 && sub_error != 0) {
+ error = sub_error;
+ }
+ }
+ } else {
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::disable_indexes(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ error = wrapper_disable_indexes(mode);
+ } else {
+ error = storage_disable_indexes(mode);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_enable_indexes_mroonga(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
+ uint i, j;
+ for (i = 0; i < table_share->keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+ if (share->wrap_key_nr[i] < MAX_KEY) {
+ continue;
+ }
+ if (!grn_index_columns[i]) {
+ break;
+ }
+ }
+ if (i == table_share->keys) {
+ DBUG_PRINT("info", ("mroonga: keys are enabled already"));
+ DBUG_RETURN(0);
+ }
+ KEY *p_key_info = &table->key_info[table_share->primary_key];
+ KEY *key_info = table_share->key_info;
+ uint n_keys = table_share->keys;
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, n_keys);
+ bitmap_clear_all(table->read_set);
+ mrn_set_bitmap_by_key(table->read_set, p_key_info);
+ mrn::PathMapper mapper(share->table_name);
+ for (i = 0, j = 0; i < n_keys; i++) {
+ if (!(key_info[i].flags & HA_FULLTEXT) &&
+ !mrn_is_geo_key(&key_info[i])) {
+ j++;
+ continue;
+ }
+
+ if ((error = mrn_add_index_param(share, &key_info[i], i)))
+ {
+ break;
+ }
+ index_tables[i] = NULL;
+ index_columns[i] = NULL;
+ if (!grn_index_columns[i]) {
+ if (
+ (key_info[i].flags & HA_FULLTEXT) &&
+ (error = wrapper_create_index_fulltext(mapper.table_name(),
+ i, &key_info[i],
+ index_tables, index_columns,
+ share))
+ ) {
+ break;
+ } else if (
+ mrn_is_geo_key(&key_info[i]) &&
+ (error = wrapper_create_index_geo(mapper.table_name(),
+ i, &key_info[i],
+ index_tables, index_columns,
+ share))
+ ) {
+ break;
+ }
+ grn_index_columns[i] = index_columns[i];
+ }
+ mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
+ }
+ if (!error && i > j)
+ {
+ error = wrapper_fill_indexes(ha_thd(), table->key_info, index_columns,
+ n_keys);
+ }
+ bitmap_set_all(table->read_set);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ } else {
+ error = HA_ERR_WRONG_COMMAND;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_enable_indexes(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+
+ int mroonga_error = wrapper_enable_indexes_mroonga(mode);
+
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_enable_indexes(mode);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (error == HA_ERR_WRONG_COMMAND) {
+ error = mroonga_error;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_enable_indexes(uint mode)
+{
+ int error = 0;
+ uint n_keys = table_share->keys;
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, n_keys);
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, n_keys);
+ bool have_multiple_column_index = false;
+ bool skip_unique_key = (mode == HA_KEY_SWITCH_NONUNIQ_SAVE);
+ MRN_DBUG_ENTER_METHOD();
+ if (mode == HA_KEY_SWITCH_NONUNIQ_SAVE || mode == HA_KEY_SWITCH_ALL) {
+ uint i;
+ for (i = 0; i < table_share->keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+ if (!grn_index_columns[i]) {
+ break;
+ }
+ }
+ if (i == table_share->keys) {
+ DBUG_PRINT("info", ("mroonga: keys are enabled already"));
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(0);
+ }
+ KEY *key_info = table->key_info;
+ bitmap_clear_all(table->read_set);
+ mrn::PathMapper mapper(share->table_name);
+ for (i = 0; i < n_keys; i++) {
+ if (i == table->s->primary_key) {
+ continue;
+ }
+ if (skip_unique_key && (key_info[i].flags & HA_NOSAME)) {
+ continue;
+ }
+
+ if ((error = mrn_add_index_param(share, &key_info[i], i)))
+ {
+ break;
+ }
+ index_tables[i] = NULL;
+ if (!grn_index_columns[i]) {
+ if ((error = storage_create_index(table, mapper.table_name(), grn_table,
+ share, &key_info[i], index_tables,
+ index_columns, i)))
+ {
+ break;
+ }
+ if (
+ KEY_N_KEY_PARTS(&(key_info[i])) != 1 &&
+ !(key_info[i].flags & HA_FULLTEXT)
+ ) {
+ mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
+ have_multiple_column_index = true;
+ }
+ grn_index_tables[i] = index_tables[i];
+ grn_index_columns[i] = index_columns[i];
+ } else {
+ index_columns[i] = NULL;
+ }
+ }
+ if (!error && have_multiple_column_index)
+ {
+ error = storage_add_index_multiple_columns(key_info, n_keys,
+ index_tables,
+ index_columns,
+ skip_unique_key);
+ }
+ bitmap_set_all(table->read_set);
+ } else {
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(HA_ERR_WRONG_COMMAND);
+ }
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::enable_indexes(uint mode)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ share->disable_keys = false;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_enable_indexes(mode);
+ } else {
+ error = storage_enable_indexes(mode);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_check(thd, check_opt);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ mrn::DatabaseRepairer repairer(ctx, thd);
+ if (repairer.is_corrupt()) {
+ DBUG_RETURN(HA_ADMIN_CORRUPT);
+ } else {
+ DBUG_RETURN(HA_ADMIN_OK);
+ }
+}
+
+int ha_mroonga::check(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_check(thd, check_opt);
+ } else {
+ error = storage_check(thd, check_opt);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_fill_indexes(THD *thd, KEY *key_info,
+ grn_obj **index_columns, uint n_keys)
+{
+ int error = 0;
+ KEY *p_key_info = &table->key_info[table_share->primary_key];
+ KEY *tmp_key_info;
+#ifdef MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
+ int wrapper_lock_type_backup = wrap_handler->get_lock_type();
+#endif
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_PRINT("info", ("mroonga: n_keys=%u", n_keys));
+
+ grn_bool need_lock = true;
+ if (mrn_lock_type != F_UNLCK) {
+ need_lock = false;
+ }
+#ifdef MRN_NEED_M_LOCK_TYPE_CHECK_FOR_WRAPPER_EXTERNAL_LOCK
+ if (wrapper_lock_type_backup != F_UNLCK) {
+ need_lock = false;
+ }
+#endif
+ if (need_lock) {
+ error = wrapper_external_lock(thd, F_WRLCK);
+ }
+ if (!error) {
+ if (
+ !(error = wrapper_start_stmt(thd, thr_lock_data.type)) &&
+ !(error = wrapper_rnd_init(true))
+ ) {
+ grn_obj key;
+ GRN_TEXT_INIT(&key, 0);
+ grn_bulk_space(ctx, &key, p_key_info->key_length);
+ while (!(error = wrapper_rnd_next(table->record[0])))
+ {
+ key_copy((uchar *)(GRN_TEXT_VALUE(&key)), table->record[0],
+ p_key_info, p_key_info->key_length);
+ int added;
+ grn_id record_id;
+ mrn_change_encoding(ctx, NULL);
+ record_id = grn_table_add(ctx, grn_table,
+ GRN_TEXT_VALUE(&key), p_key_info->key_length,
+ &added);
+ if (record_id == GRN_ID_NIL)
+ {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to add a new record into groonga: key=<%.*s>",
+ (int) p_key_info->key_length, GRN_TEXT_VALUE(&key));
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, error_message, MYF(0));
+ }
+ if (error)
+ break;
+
+ uint k;
+ for (k = 0; k < n_keys; k++) {
+ tmp_key_info = &key_info[k];
+ if (!(tmp_key_info->flags & HA_FULLTEXT) &&
+ !mrn_is_geo_key(tmp_key_info)) {
+ continue;
+ }
+ if (!index_columns[k]) {
+ continue;
+ }
+ DBUG_PRINT("info", ("mroonga: key_num=%u", k));
+
+ uint l;
+ for (l = 0; l < KEY_N_KEY_PARTS(tmp_key_info); l++) {
+ Field *field = tmp_key_info->key_part[l].field;
+
+ if (field->is_null())
+ continue;
+ error = mrn_change_encoding(ctx, field->charset());
+ if (error)
+ break;
+
+ error = generic_store_bulk(field, &new_value_buffer);
+ if (error) {
+ my_message(error,
+ "mroonga: wrapper: "
+ "failed to get new value for updating index.",
+ MYF(0));
+ break;
+ }
+
+ grn_obj *index_column = index_columns[k];
+ grn_rc rc;
+ rc = grn_column_index_update(ctx, index_column, record_id, l + 1,
+ NULL, &new_value_buffer);
+ grn_obj_unlink(ctx, index_column);
+ if (rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ break;
+ }
+ }
+ if (error)
+ break;
+ }
+ if (error)
+ break;
+ }
+ grn_obj_unlink(ctx, &key);
+ if (error != HA_ERR_END_OF_FILE)
+ wrapper_rnd_end();
+ else
+ error = wrapper_rnd_end();
+ }
+ if (need_lock) {
+ wrapper_external_lock(thd, F_UNLCK);
+ }
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_recreate_indexes(THD *thd)
+{
+ int error;
+ uint i, n_keys = table_share->keys;
+ KEY *p_key_info = &table->key_info[table_share->primary_key];
+ KEY *key_info = table->key_info;
+ MRN_DBUG_ENTER_METHOD();
+ mrn::PathMapper mapper(table_share->normalized_path.str);
+ bitmap_clear_all(table->read_set);
+ clear_indexes();
+ remove_grn_obj_force(mapper.table_name());
+ grn_table = NULL;
+ mrn_set_bitmap_by_key(table->read_set, p_key_info);
+ for (i = 0; i < n_keys; i++) {
+ if (!(key_info[i].flags & HA_FULLTEXT) && !mrn_is_geo_key(&key_info[i])) {
+ continue;
+ }
+ mrn::IndexTableName index_table_name(mapper.table_name(),
+ table_share->key_info[i].name.str);
+ char index_column_full_name[MRN_MAX_PATH_SIZE];
+ snprintf(index_column_full_name, MRN_MAX_PATH_SIZE,
+ "%s.%s", index_table_name.c_str(), INDEX_COLUMN_NAME);
+ remove_grn_obj_force(index_column_full_name);
+ remove_grn_obj_force(index_table_name.c_str());
+
+ char index_column_full_old_name[MRN_MAX_PATH_SIZE];
+ snprintf(index_column_full_old_name, MRN_MAX_PATH_SIZE,
+ "%s.%s", index_table_name.old_c_str(), INDEX_COLUMN_NAME);
+ remove_grn_obj_force(index_column_full_old_name);
+ remove_grn_obj_force(index_table_name.old_c_str());
+
+ mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
+ }
+ error = wrapper_create_index(table_share->normalized_path.str, table, share);
+ if (error)
+ DBUG_RETURN(error);
+ error = wrapper_open_indexes(table_share->normalized_path.str);
+ if (error)
+ DBUG_RETURN(error);
+ error = wrapper_fill_indexes(thd, key_info, grn_index_columns, n_keys);
+ bitmap_set_all(table->read_set);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_recreate_indexes(THD *thd)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (share->disable_keys)
+ DBUG_RETURN(HA_ADMIN_OK);
+
+ clear_indexes();
+
+ int n_columns = table->s->fields;
+ for (int i = 0; i < n_columns; i++) {
+ grn_obj *column = grn_columns[i];
+
+ if (!column)
+ continue;
+
+ int n_hooks = grn_obj_get_nhooks(ctx, column, GRN_HOOK_SET);
+ for (int j = 0; j < n_hooks; j++) {
+ grn_obj_delete_hook(ctx, column, GRN_HOOK_SET, j);
+ }
+ }
+
+ uint n_keys = table_share->keys;
+ mrn::PathMapper mapper(table_share->normalized_path.str);
+ for (uint i = 0; i < n_keys; i++) {
+ if (share->index_table && share->index_table[i])
+ continue;
+
+ if (i == table_share->primary_key)
+ continue;
+
+ mrn::IndexTableName index_table_name(mapper.table_name(),
+ table_share->key_info[i].name.str);
+ char index_column_full_name[MRN_MAX_PATH_SIZE];
+ snprintf(index_column_full_name, MRN_MAX_PATH_SIZE,
+ "%s.%s", index_table_name.c_str(), INDEX_COLUMN_NAME);
+ remove_grn_obj_force(index_column_full_name);
+ remove_grn_obj_force(index_table_name.c_str());
+
+ char index_column_full_old_name[MRN_MAX_PATH_SIZE];
+ snprintf(index_column_full_old_name, MRN_MAX_PATH_SIZE,
+ "%s.%s", index_table_name.old_c_str(), INDEX_COLUMN_NAME);
+ remove_grn_obj_force(index_column_full_old_name);
+ remove_grn_obj_force(index_table_name.old_c_str());
+ }
+
+ int error;
+ error = storage_create_indexes(table, mapper.table_name(), grn_table, share);
+ if (error)
+ DBUG_RETURN(HA_ADMIN_FAILED);
+
+ error = storage_open_indexes(table_share->normalized_path.str);
+ if (error)
+ DBUG_RETURN(HA_ADMIN_FAILED);
+
+ DBUG_RETURN(HA_ADMIN_OK);
+}
+
+int ha_mroonga::wrapper_repair(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int error;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_repair(thd, check_opt);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (error && error != HA_ADMIN_NOT_IMPLEMENTED)
+ DBUG_RETURN(error);
+ error = wrapper_recreate_indexes(thd);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_repair(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = storage_recreate_indexes(thd);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::repair(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ share->disable_keys = false;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_repair(thd, check_opt);
+ } else {
+ error = storage_repair(thd, check_opt);
+ }
+ DBUG_RETURN(error);
+}
+
+bool ha_mroonga::wrapper_check_and_repair(THD *thd)
+{
+ bool is_error_or_not_supported;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ is_error_or_not_supported = wrap_handler->ha_check_and_repair(thd);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(is_error_or_not_supported);
+}
+
+bool ha_mroonga::storage_check_and_repair(THD *thd)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool is_error = false;
+ mrn::DatabaseRepairer repairer(ctx, thd);
+ is_error = !repairer.repair();
+ DBUG_RETURN(is_error);
+}
+
+bool ha_mroonga::check_and_repair(THD *thd)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool is_error_or_not_supported;
+ if (share->wrapper_mode)
+ {
+ is_error_or_not_supported = wrapper_check_and_repair(thd);
+ } else {
+ is_error_or_not_supported = storage_check_and_repair(thd);
+ }
+ DBUG_RETURN(is_error_or_not_supported);
+}
+
+int ha_mroonga::wrapper_analyze(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->ha_analyze(thd, check_opt);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_analyze(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+int ha_mroonga::analyze(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_analyze(thd, check_opt);
+ } else {
+ error = storage_analyze(thd, check_opt);
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::wrapper_optimize(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(HA_ADMIN_TRY_ALTER);
+}
+
+int ha_mroonga::storage_optimize(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(HA_ADMIN_NOT_IMPLEMENTED);
+}
+
+int ha_mroonga::optimize(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error = 0;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_optimize(thd, check_opt);
+ } else {
+ error = storage_optimize(thd, check_opt);
+ }
+ DBUG_RETURN(error);
+}
+
+bool ha_mroonga::wrapper_is_fatal_error(int error_num, uint flags)
+{
+ bool res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_IS_FATAL_ERROR_HAVE_FLAGS
+ res = wrap_handler->is_fatal_error(error_num, flags);
+#else
+ res = wrap_handler->is_fatal_error(error_num);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::storage_is_fatal_error(int error_num, uint flags)
+{
+ MRN_DBUG_ENTER_METHOD();
+#ifdef MRN_HANDLER_IS_FATAL_ERROR_HAVE_FLAGS
+ bool is_fatal_error = handler::is_fatal_error(error_num, flags);
+#else
+ bool is_fatal_error = handler::is_fatal_error(error_num);
+#endif
+ DBUG_RETURN(is_fatal_error);
+}
+
+bool ha_mroonga::is_fatal_error(int error_num, uint flags)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool is_fatal_error;
+ if (share->wrapper_mode)
+ {
+ is_fatal_error = wrapper_is_fatal_error(error_num, flags);
+ } else {
+ is_fatal_error = storage_is_fatal_error(error_num, flags);
+ }
+ DBUG_RETURN(is_fatal_error);
+}
+
+bool ha_mroonga::wrapper_check_if_incompatible_data(
+ HA_CREATE_INFO *create_info, uint table_changes)
+{
+ bool res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->check_if_incompatible_data(create_info, table_changes);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::storage_check_if_incompatible_data(
+ HA_CREATE_INFO *create_info, uint table_changes)
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint n = table_share->fields;
+ for (uint i = 0; i < n; i++) {
+ Field *field = table->field[i];
+ if (field->flags & FIELD_IS_RENAMED) {
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+ }
+ }
+ DBUG_RETURN(COMPATIBLE_DATA_YES);
+}
+
+bool ha_mroonga::check_if_incompatible_data(
+ HA_CREATE_INFO *create_info, uint table_changes)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res;
+ if (
+ create_info->comment.str != table_share->comment.str ||
+ create_info->connect_string.str != table_share->connect_string.str
+ ) {
+ DBUG_RETURN(COMPATIBLE_DATA_NO);
+ }
+ if (share->wrapper_mode)
+ {
+ res = wrapper_check_if_incompatible_data(create_info, table_changes);
+ } else {
+ res = storage_check_if_incompatible_data(create_info, table_changes);
+ }
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_add_index_multiple_columns(KEY *key_info,
+ uint num_of_keys,
+ grn_obj **index_tables,
+ grn_obj **index_columns,
+ bool skip_unique_key)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ if (!(error = storage_rnd_init(true)))
+ {
+ while (!(error = storage_rnd_next(table->record[0])))
+ {
+ for (uint i = 0; i < num_of_keys; i++) {
+ KEY *current_key_info = key_info + i;
+ if (
+ KEY_N_KEY_PARTS(current_key_info) == 1 ||
+ (current_key_info->flags & HA_FULLTEXT)
+ ) {
+ continue;
+ }
+ if (skip_unique_key && (key_info[i].flags & HA_NOSAME)) {
+ continue;
+ }
+ if (!index_columns[i]) {
+ continue;
+ }
+
+ /* fix key_info.key_length */
+ for (uint j = 0; j < KEY_N_KEY_PARTS(current_key_info); j++) {
+ if (
+ !current_key_info->key_part[j].null_bit &&
+ current_key_info->key_part[j].field->null_bit
+ ) {
+ current_key_info->key_length++;
+ current_key_info->key_part[j].null_bit =
+ current_key_info->key_part[j].field->null_bit;
+ }
+ }
+ if (key_info[i].flags & HA_NOSAME) {
+ grn_id key_id;
+ if ((error = storage_write_row_unique_index(table->record[0],
+ current_key_info,
+ index_tables[i],
+ index_columns[i],
+ &key_id)))
+ {
+ if (error == HA_ERR_FOUND_DUPP_KEY)
+ {
+ error = HA_ERR_FOUND_DUPP_UNIQUE;
+ }
+ break;
+ }
+ }
+ if ((error = storage_write_row_multiple_column_index(table->record[0],
+ record_id,
+ current_key_info,
+ index_columns[i])))
+ {
+ break;
+ }
+ }
+ if (error)
+ break;
+ }
+ if (error != HA_ERR_END_OF_FILE) {
+ storage_rnd_end();
+ } else {
+ error = storage_rnd_end();
+ }
+ }
+
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+bool ha_mroonga::wrapper_is_comment_changed(TABLE *table1, TABLE *table2)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ if (table1->s->comment.length != table2->s->comment.length) {
+ DBUG_RETURN(true);
+ }
+
+ if (strncmp(table1->s->comment.str,
+ table2->s->comment.str,
+ table1->s->comment.length) == 0) {
+ DBUG_RETURN(false);
+ } else {
+ DBUG_RETURN(true);
+ }
+}
+
+enum_alter_inplace_result ha_mroonga::wrapper_check_if_supported_inplace_alter(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint n_keys;
+ uint i;
+ enum_alter_inplace_result result_mroonga = HA_ALTER_INPLACE_NO_LOCK;
+ DBUG_PRINT("info",
+ ("mroonga: handler_flags=%lu",
+ static_cast<ulong>(ha_alter_info->handler_flags)));
+
+ if (wrapper_is_comment_changed(table, altered_table)) {
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ if (
+ (ha_alter_info->handler_flags & ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX) &&
+ (ha_alter_info->handler_flags &
+ (
+ ALTER_ADD_COLUMN |
+ ALTER_DROP_COLUMN |
+ MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_TYPE |
+ MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_ORDER |
+ ALTER_COLUMN_NULLABLE |
+ ALTER_COLUMN_NOT_NULLABLE |
+ ALTER_COLUMN_STORAGE_TYPE |
+ ALTER_ADD_STORED_GENERATED_COLUMN |
+ ALTER_COLUMN_COLUMN_FORMAT
+ )
+ )
+ ) {
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ if (ha_alter_info->handler_flags & ALTER_RENAME)
+ {
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+
+ DBUG_ASSERT(ha_alter_info->key_count == altered_table->s->keys);
+ alter_key_count = 0;
+ alter_index_drop_count = 0;
+ alter_index_add_count = 0;
+ alter_handler_flags = ha_alter_info->handler_flags;
+ if (!(alter_key_info_buffer = (KEY *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &alter_key_info_buffer, sizeof(KEY) * ha_alter_info->key_count,
+ &alter_index_drop_buffer, sizeof(KEY) * ha_alter_info->index_drop_count,
+ &alter_index_add_buffer, sizeof(uint) * ha_alter_info->index_add_count,
+ &wrap_altered_table, sizeof(TABLE),
+ &wrap_altered_table_key_info, sizeof(KEY) * altered_table->s->keys,
+ &wrap_altered_table_share, sizeof(TABLE_SHARE),
+ &wrap_altered_table_share_key_info, sizeof(KEY) * altered_table->s->keys,
+ NullS))
+ ) {
+ DBUG_RETURN(HA_ALTER_ERROR);
+ }
+ *wrap_altered_table= *altered_table;
+ *wrap_altered_table_share= *altered_table->s;
+ mrn_init_sql_alloc(ha_thd(), &(wrap_altered_table_share->mem_root));
+
+ n_keys = ha_alter_info->index_drop_count;
+ for (i = 0; i < n_keys; ++i) {
+ const KEY *key = ha_alter_info->index_drop_buffer[i];
+ if (key->flags & HA_FULLTEXT || mrn_is_geo_key(key)) {
+ result_mroonga = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
+ } else {
+ memcpy(&alter_index_drop_buffer[alter_index_drop_count],
+ ha_alter_info->index_drop_buffer[i], sizeof(KEY));
+ ++alter_index_drop_count;
+ }
+ }
+ if (!alter_index_drop_count) {
+ alter_handler_flags &= ~ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX;
+ }
+ n_keys = ha_alter_info->index_add_count;
+ for (i = 0; i < n_keys; ++i) {
+ const KEY *key =
+ &altered_table->key_info[ha_alter_info->index_add_buffer[i]];
+ if (key->flags & HA_FULLTEXT || mrn_is_geo_key(key)) {
+ result_mroonga = HA_ALTER_INPLACE_EXCLUSIVE_LOCK;
+ } else {
+ alter_index_add_buffer[alter_index_add_count] =
+ ha_alter_info->index_add_buffer[i];
+ ++alter_index_add_count;
+ }
+ }
+ if (!alter_index_add_count) {
+ alter_handler_flags &= ~ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX;
+ }
+ uint add_index_pos = 0;
+ n_keys = ha_alter_info->key_count;
+ for (i = 0; i < n_keys; ++i) {
+ const KEY *key = &altered_table->key_info[i];
+ if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
+ memcpy(&alter_key_info_buffer[alter_key_count],
+ &ha_alter_info->key_info_buffer[i], sizeof(KEY));
+ memcpy(&wrap_altered_table_key_info[alter_key_count],
+ &altered_table->key_info[i], sizeof(KEY));
+ memcpy(&wrap_altered_table_share_key_info[alter_key_count],
+ &altered_table->s->key_info[i], sizeof(KEY));
+ if (add_index_pos < alter_index_add_count &&
+ alter_index_add_buffer[add_index_pos] == i) {
+ alter_index_add_buffer[add_index_pos] = alter_key_count;
+ ++add_index_pos;
+ }
+ ++alter_key_count;
+ }
+ }
+ wrap_altered_table->key_info = wrap_altered_table_key_info;
+ wrap_altered_table_share->key_info = wrap_altered_table_share_key_info;
+ wrap_altered_table_share->keys = alter_key_count;
+ wrap_altered_table->s = wrap_altered_table_share;
+
+ if (!alter_handler_flags) {
+ DBUG_RETURN(result_mroonga);
+ }
+ enum_alter_inplace_result result;
+ MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ result = wrap_handler->check_if_supported_inplace_alter(wrap_altered_table,
+ ha_alter_info);
+ MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ if (result_mroonga > result)
+ DBUG_RETURN(result);
+ DBUG_RETURN(result_mroonga);
+}
+
+enum_alter_inplace_result ha_mroonga::storage_check_if_supported_inplace_alter(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ alter_table_operations explicitly_unsupported_flags =
+ ALTER_ADD_FOREIGN_KEY |
+ ALTER_DROP_FOREIGN_KEY;
+ alter_table_operations supported_flags =
+ ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX |
+ ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX |
+ ALTER_ADD_UNIQUE_INDEX |
+ ALTER_DROP_UNIQUE_INDEX |
+ MRN_ALTER_INPLACE_INFO_ADD_VIRTUAL_COLUMN |
+ MRN_ALTER_INPLACE_INFO_ADD_STORED_BASE_COLUMN |
+ ALTER_DROP_COLUMN |
+ ALTER_COLUMN_NAME;
+ if (ha_alter_info->handler_flags & explicitly_unsupported_flags) {
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ } else if (ha_alter_info->handler_flags & supported_flags) {
+ DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK);
+ } else {
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+}
+
+enum_alter_inplace_result ha_mroonga::check_if_supported_inplace_alter(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ enum_alter_inplace_result result;
+ if (share->wrapper_mode) {
+ result = wrapper_check_if_supported_inplace_alter(altered_table,
+ ha_alter_info);
+ } else {
+ result = storage_check_if_supported_inplace_alter(altered_table,
+ ha_alter_info);
+ }
+ DBUG_RETURN(result);
+}
+
+bool ha_mroonga::wrapper_prepare_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ bool result;
+ MRN_DBUG_ENTER_METHOD();
+ if (!alter_handler_flags) {
+ DBUG_RETURN(false);
+ }
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ int error = 0;
+ MRN_SHARE *tmp_share;
+ tmp_share = mrn_get_share(altered_table->s->table_name.str,
+ altered_table,
+ &error);
+ if (error != 0) {
+ DBUG_RETURN(true);
+ }
+
+ if (parse_engine_table_options(ha_thd(),
+ tmp_share->hton,
+ wrap_altered_table->s)) {
+ mrn_free_share(tmp_share);
+ DBUG_RETURN(true);
+ }
+#endif
+
+ MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ result = wrap_handler->ha_prepare_inplace_alter_table(wrap_altered_table,
+ ha_alter_info);
+ MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ mrn_free_share(tmp_share);
+#endif
+
+ DBUG_RETURN(result);
+}
+
+bool ha_mroonga::storage_prepare_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(false);
+}
+
+bool ha_mroonga::prepare_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool result;
+ if (share->wrapper_mode) {
+ result = wrapper_prepare_inplace_alter_table(altered_table, ha_alter_info);
+ } else {
+ result = storage_prepare_inplace_alter_table(altered_table, ha_alter_info);
+ }
+ DBUG_RETURN(result);
+}
+
+bool ha_mroonga::wrapper_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ int error;
+ bool result = false;
+ uint n_keys;
+ uint i, j = 0;
+ KEY *key_info = table_share->key_info;
+ MRN_DBUG_ENTER_METHOD();
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(true);
+
+ DBUG_PRINT("info", ("mroonga: table_name=%s", share->table_name));
+ mrn::PathMapper mapper(share->table_name);
+ n_keys = ha_alter_info->index_drop_count;
+ for (i = 0; i < n_keys; ++i) {
+ const KEY *key = ha_alter_info->index_drop_buffer[i];
+ if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
+ continue;
+ }
+ while (strcmp(key_info[j].name.str, key->name.str)) {
+ ++j;
+ }
+ DBUG_PRINT("info", ("mroonga: key_name=%s", key->name.str));
+ error = drop_index(share, j);
+ if (error)
+ DBUG_RETURN(true);
+ grn_index_tables[j] = NULL;
+ grn_index_columns[j] = NULL;
+ }
+
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables,
+ ha_alter_info->key_count);
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns,
+ ha_alter_info->key_count);
+ MRN_SHARE *tmp_share;
+ TABLE_SHARE tmp_table_share;
+ char **key_tokenizer;
+ uint *key_tokenizer_length;
+ KEY *p_key_info = &table->key_info[table_share->primary_key];
+ bool need_fill_index = false;
+ memset(index_tables, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
+ memset(index_columns, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
+ tmp_table_share.keys = ha_alter_info->key_count;
+ tmp_table_share.fields = 0;
+ if (!(tmp_share = (MRN_SHARE *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &tmp_share, sizeof(*tmp_share),
+ &key_tokenizer, sizeof(char *) * (tmp_table_share.keys),
+ &key_tokenizer_length, sizeof(uint) * (tmp_table_share.keys),
+ NullS))
+ ) {
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(true);
+ }
+ tmp_share->engine = NULL;
+ tmp_share->table_share = &tmp_table_share;
+ tmp_share->index_table = NULL;
+ tmp_share->index_table_length = NULL;
+ tmp_share->key_tokenizer = key_tokenizer;
+ tmp_share->key_tokenizer_length = key_tokenizer_length;
+ bitmap_clear_all(table->read_set);
+ mrn_set_bitmap_by_key(table->read_set, p_key_info);
+ n_keys = ha_alter_info->index_add_count;
+ for (i = 0; i < n_keys; ++i) {
+ uint key_pos = ha_alter_info->index_add_buffer[i];
+ KEY *key = &altered_table->key_info[key_pos];
+ if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
+ continue;
+ }
+ if (share->disable_keys) {
+ continue;
+ }
+ if ((error = mrn_add_index_param(tmp_share, key, key_pos)))
+ {
+ break;
+ }
+ DBUG_PRINT("info", ("mroonga: add key pos=%u", key_pos));
+ if (
+ (key->flags & HA_FULLTEXT) &&
+ (error = wrapper_create_index_fulltext(mapper.table_name(),
+ key_pos,
+ key, index_tables, NULL,
+ tmp_share))
+ ) {
+ break;
+ } else if (
+ mrn_is_geo_key(key) &&
+ (error = wrapper_create_index_geo(mapper.table_name(),
+ key_pos, key,
+ index_tables, NULL, tmp_share))
+ ) {
+ break;
+ }
+ mrn_set_bitmap_by_key(table->read_set, key);
+ index_columns[key_pos] = grn_obj_column(ctx,
+ index_tables[key_pos],
+ INDEX_COLUMN_NAME,
+ strlen(INDEX_COLUMN_NAME));
+ need_fill_index = true;
+ }
+ if (!error && need_fill_index) {
+ mrn::FieldTableChanger changer(altered_table, table);
+ error = wrapper_fill_indexes(ha_thd(), altered_table->key_info,
+ index_columns, ha_alter_info->key_count);
+ }
+ bitmap_set_all(table->read_set);
+
+ if (!error && alter_handler_flags) {
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+ {
+ MRN_SHARE *alter_tmp_share;
+ alter_tmp_share = mrn_get_share(altered_table->s->table_name.str,
+ altered_table,
+ &error);
+ if (alter_tmp_share) {
+ if (parse_engine_table_options(ha_thd(),
+ alter_tmp_share->hton,
+ wrap_altered_table->s)) {
+ error = MRN_GET_ERROR_NUMBER;
+ }
+ mrn_free_share(alter_tmp_share);
+ }
+ }
+#endif
+ if (!error) {
+ MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ result = wrap_handler->ha_inplace_alter_table(wrap_altered_table,
+ ha_alter_info);
+ MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ }
+
+ if (result || error)
+ {
+ n_keys = ha_alter_info->index_add_count;
+ for (i = 0; i < n_keys; ++i) {
+ uint key_pos = ha_alter_info->index_add_buffer[i];
+ KEY *key = &altered_table->key_info[key_pos];
+ if (!(key->flags & HA_FULLTEXT || mrn_is_geo_key(key))) {
+ continue;
+ }
+ if (share->disable_keys) {
+ continue;
+ }
+ if (index_tables[key_pos])
+ {
+ grn_obj_remove(ctx, index_tables[key_pos]);
+ }
+ }
+ result = true;
+ }
+ mrn_free_share_alloc(tmp_share);
+ my_free(tmp_share);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(result);
+}
+
+bool ha_mroonga::storage_inplace_alter_table_add_index(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables,
+ ha_alter_info->key_count);
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns,
+ ha_alter_info->key_count);
+ MRN_SHARE *tmp_share;
+ TABLE_SHARE tmp_table_share;
+ char **index_table, **key_tokenizer, **col_flags, **col_type;
+ uint *index_table_length, *key_tokenizer_length, *col_flags_length, *col_type_length;
+ bool have_multiple_column_index = false;
+ memset(index_tables, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
+ memset(index_columns, 0, sizeof(grn_obj *) * ha_alter_info->key_count);
+ tmp_table_share.keys = ha_alter_info->key_count;
+ tmp_table_share.fields = 0;
+ if (!(tmp_share = (MRN_SHARE *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &tmp_share, sizeof(*tmp_share),
+ &index_table, sizeof(char *) * tmp_table_share.keys,
+ &index_table_length, sizeof(uint) * tmp_table_share.keys,
+ &key_tokenizer, sizeof(char *) * tmp_table_share.keys,
+ &key_tokenizer_length, sizeof(uint) * tmp_table_share.keys,
+ &col_flags, sizeof(char *) * tmp_table_share.fields,
+ &col_flags_length, sizeof(uint) * tmp_table_share.fields,
+ &col_type, sizeof(char *) * tmp_table_share.fields,
+ &col_type_length, sizeof(uint) * tmp_table_share.fields,
+ NullS))
+ ) {
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(true);
+ }
+ tmp_share->engine = NULL;
+ tmp_share->table_share = &tmp_table_share;
+ tmp_share->index_table = index_table;
+ tmp_share->index_table_length = index_table_length;
+ tmp_share->key_tokenizer = key_tokenizer;
+ tmp_share->key_tokenizer_length = key_tokenizer_length;
+ tmp_share->col_flags = col_flags;
+ tmp_share->col_flags_length = col_flags_length;
+ tmp_share->col_type = col_type;
+ tmp_share->col_type_length = col_type_length;
+ bitmap_clear_all(table->read_set);
+ if (table_share->primary_key != MAX_KEY) {
+ KEY *p_key_info = &table->key_info[table_share->primary_key];
+ mrn_set_bitmap_by_key(table->read_set, p_key_info);
+ }
+ int error = 0;
+ uint n_keys = ha_alter_info->index_add_count;
+ for (uint i = 0; i < n_keys; ++i) {
+ uint key_pos = ha_alter_info->index_add_buffer[i];
+ KEY *key = &altered_table->key_info[key_pos];
+ if (share->disable_keys && !(key->flags & HA_NOSAME)) {
+ continue; // key is disabled
+ }
+ if ((error = mrn_add_index_param(tmp_share, key, key_pos)))
+ {
+ break;
+ }
+ DBUG_PRINT("info", ("mroonga: add key pos=%u", key_pos));
+ mrn::PathMapper mapper(share->table_name);
+ if ((error = storage_create_index(table, mapper.table_name(), grn_table,
+ tmp_share, key, index_tables,
+ index_columns, key_pos)))
+ {
+ break;
+ }
+ if (
+ KEY_N_KEY_PARTS(key) == 1 &&
+ (key->flags & HA_NOSAME) &&
+ grn_table_size(ctx, grn_table) !=
+ grn_table_size(ctx, index_tables[key_pos])
+ ) {
+ error = HA_ERR_FOUND_DUPP_UNIQUE;
+ my_printf_error(ER_DUP_UNIQUE, ER(ER_DUP_UNIQUE), MYF(0),
+ table_share->table_name);
+ ++i;
+ break;
+ }
+ if (
+ KEY_N_KEY_PARTS(key) != 1 &&
+ !(key->flags & HA_FULLTEXT)
+ ) {
+ mrn_set_bitmap_by_key(table->read_set, key);
+ have_multiple_column_index = true;
+ }
+ }
+ if (!error && have_multiple_column_index) {
+ mrn::FieldTableChanger changer(altered_table, table);
+ error = storage_add_index_multiple_columns(altered_table->key_info,
+ ha_alter_info->key_count,
+ index_tables,
+ index_columns, false);
+ if (error == HA_ERR_FOUND_DUPP_UNIQUE) {
+ my_printf_error(ER_DUP_UNIQUE, ER(ER_DUP_UNIQUE), MYF(0),
+ table_share->table_name);
+ } else if (error) {
+ my_message(error, "failed to create multiple column index", MYF(0));
+ }
+ }
+ bitmap_set_all(table->read_set);
+
+ bool have_error = false;
+ if (error)
+ {
+ n_keys = ha_alter_info->index_add_count;
+ for (uint i = 0; i < n_keys; ++i) {
+ uint key_pos = ha_alter_info->index_add_buffer[i];
+ KEY *key =
+ &altered_table->key_info[key_pos];
+ if (share->disable_keys && !(key->flags & HA_NOSAME)) {
+ continue;
+ }
+ if (index_tables[key_pos])
+ {
+ grn_obj_remove(ctx, index_columns[key_pos]);
+ grn_obj_remove(ctx, index_tables[key_pos]);
+ }
+ }
+ have_error = true;
+ }
+ mrn_free_share_alloc(tmp_share);
+ my_free(tmp_share);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+
+ DBUG_RETURN(have_error);
+}
+
+bool ha_mroonga::storage_inplace_alter_table_drop_index(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have_error = false;
+ uint n_keys;
+ uint i, j = 0;
+ KEY *key_info = table_share->key_info;
+ mrn::PathMapper mapper(share->table_name);
+ n_keys = ha_alter_info->index_drop_count;
+ for (i = 0; i < n_keys; ++i) {
+ KEY *key = ha_alter_info->index_drop_buffer[i];
+ while (strcmp(key_info[j].name.str, key->name.str) != 0) {
+ ++j;
+ }
+ int error = drop_index(share, j);
+ if (error != 0)
+ DBUG_RETURN(true);
+ grn_index_tables[j] = NULL;
+ grn_index_columns[j] = NULL;
+ }
+
+ DBUG_RETURN(have_error);
+}
+
+bool ha_mroonga::storage_inplace_alter_table_add_column(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have_error = false;
+
+ MRN_SHARE *tmp_share;
+ TABLE_SHARE tmp_table_share;
+ char **index_table, **key_tokenizer, **col_flags, **col_type;
+ uint *index_table_length, *key_tokenizer_length, *col_flags_length, *col_type_length;
+ tmp_table_share.keys = 0;
+ tmp_table_share.fields = altered_table->s->fields;
+ tmp_share = (MRN_SHARE *)mrn_my_multi_malloc(
+ MYF(MY_WME | MY_ZEROFILL),
+ &tmp_share, sizeof(*tmp_share),
+ &index_table, sizeof(char *) * tmp_table_share.keys,
+ &index_table_length, sizeof(uint) * tmp_table_share.keys,
+ &key_tokenizer, sizeof(char *) * tmp_table_share.keys,
+ &key_tokenizer_length, sizeof(uint) * tmp_table_share.keys,
+ &col_flags, sizeof(char *) * tmp_table_share.fields,
+ &col_flags_length, sizeof(uint) * tmp_table_share.fields,
+ &col_type, sizeof(char *) * tmp_table_share.fields,
+ &col_type_length, sizeof(uint) * tmp_table_share.fields,
+ NullS);
+ if (!tmp_share) {
+ have_error = true;
+ DBUG_RETURN(have_error);
+ }
+ tmp_share->engine = NULL;
+ tmp_share->table_share = &tmp_table_share;
+ tmp_share->index_table = index_table;
+ tmp_share->index_table_length = index_table_length;
+ tmp_share->key_tokenizer = key_tokenizer;
+ tmp_share->key_tokenizer_length = key_tokenizer_length;
+ tmp_share->col_flags = col_flags;
+ tmp_share->col_flags_length = col_flags_length;
+ tmp_share->col_type = col_type;
+ tmp_share->col_type_length = col_type_length;
+
+ mrn::PathMapper mapper(share->table_name);
+ grn_obj *table_obj;
+ table_obj = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
+
+ Alter_info *alter_info = ha_alter_info->alter_info;
+ List_iterator_fast<Create_field> create_fields(alter_info->create_list);
+ for (uint i = 0; Create_field *create_field = create_fields++; i++) {
+ if (create_field->field) {
+ continue;
+ }
+
+ Field *field = altered_table->s->field[i];
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field)) {
+ continue;
+ }
+#endif
+
+ mrn::ColumnName column_name(field->field_name);
+ int error = mrn_add_column_param(tmp_share, field, i);
+ if (error) {
+ have_error = true;
+ break;
+ }
+
+ grn_obj_flags col_flags = GRN_OBJ_PERSISTENT;
+ if (!find_column_flags(field, tmp_share, i, &col_flags)) {
+ col_flags |= GRN_OBJ_COLUMN_SCALAR;
+ }
+
+ grn_obj *col_type;
+ {
+ int column_type_error_code = ER_WRONG_FIELD_SPEC;
+ col_type = find_column_type(field, tmp_share, i, column_type_error_code);
+ if (!col_type) {
+ error = column_type_error_code;
+ have_error = true;
+ break;
+ }
+ }
+ char *col_path = NULL; // we don't specify path
+
+ grn_obj *column_obj =
+ grn_column_create(ctx, table_obj,
+ column_name.c_str(),
+ column_name.length(),
+ col_path, col_flags, col_type);
+ if (ctx->rc) {
+ error = ER_WRONG_COLUMN_NAME;
+ my_message(error, ctx->errbuf, MYF(0));
+ have_error = true;
+ break;
+ }
+
+#ifdef MRN_SUPPORT_GENERATED_COLUMNS
+ if (MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field)) {
+# ifndef MRN_MARIADB_P
+ MY_BITMAP generated_column_bitmap;
+ if (bitmap_init(&generated_column_bitmap, NULL,
+ altered_table->s->fields, false)) {
+ error = HA_ERR_OUT_OF_MEM;
+ my_message(ER_OUTOFMEMORY,
+ "mroonga: storage: "
+ "failed to allocate memory for getting generated value",
+ MYF(0));
+ have_error = true;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+ mrn::SmartBitmap smart_generated_column_bitmap(&generated_column_bitmap);
+ bitmap_set_bit(&generated_column_bitmap, field->field_index);
+# endif
+
+ mrn::FieldTableChanger changer(altered_table, table);
+
+ error = storage_rnd_init(true);
+ if (error) {
+ have_error = true;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+
+ Field *altered_field = altered_table->field[i];
+ grn_obj new_value;
+ GRN_VOID_INIT(&new_value);
+ mrn::SmartGrnObj smart_new_value(ctx, &new_value);
+ while (!have_error) {
+ int next_error = storage_rnd_next(table->record[0]);
+ if (next_error == HA_ERR_END_OF_FILE) {
+ break;
+ } else if (next_error != 0) {
+ error = next_error;
+ have_error = true;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+
+# ifdef MRN_MARIADB_P
+ MRN_GENERATED_COLUMNS_UPDATE_VIRTUAL_FIELD(altered_table, altered_field);
+# else
+ if (update_generated_write_fields(&generated_column_bitmap, altered_table)) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error,
+ "mroonga: storage: "
+ "failed to update generated value for updating column",
+ MYF(0));
+ have_error = true;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+# endif
+
+ error = mrn_change_encoding(ctx, altered_field->charset());
+ if (error) {
+ my_message(error,
+ "mroonga: storage: "
+ "failed to change encoding to store generated value",
+ MYF(0));
+ have_error = true;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+ error = generic_store_bulk(altered_field, &new_value);
+ if (error) {
+ my_message(error,
+ "mroonga: storage: "
+ "failed to get generated value for updating column",
+ MYF(0));
+ have_error = true;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+
+ grn_obj_set_value(ctx, column_obj, record_id, &new_value, GRN_OBJ_SET);
+ if (ctx->rc) {
+ error = ER_ERROR_ON_WRITE;
+ my_message(error, ctx->errbuf, MYF(0));
+ break;
+ }
+ }
+
+ int end_error = storage_rnd_end();
+ if (end_error != 0 && error == 0) {
+ error = end_error;
+ grn_obj_remove(ctx, column_obj);
+ break;
+ }
+ }
+#endif
+ }
+
+ grn_obj_unlink(ctx, table_obj);
+
+ mrn_free_share_alloc(tmp_share);
+ my_free(tmp_share);
+
+ DBUG_RETURN(have_error);
+}
+
+bool ha_mroonga::storage_inplace_alter_table_drop_column(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have_error = false;
+
+ mrn::PathMapper mapper(share->table_name);
+ grn_obj *table_obj;
+ table_obj = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
+
+ Alter_info *alter_info = ha_alter_info->alter_info;
+
+ uint n_fields = table->s->fields;
+ for (uint i = 0; i < n_fields; i++) {
+ Field *field = table->field[i];
+
+ bool dropped = true;
+ List_iterator_fast<Create_field> create_fields(alter_info->create_list);
+ while (Create_field *create_field = create_fields++) {
+ if (create_field->field == field) {
+ dropped = false;
+ break;
+ }
+ }
+ if (!dropped) {
+ continue;
+ }
+
+ const char *column_name = field->field_name.str;
+ int column_name_size = field->field_name.length;
+
+ grn_obj *column_obj;
+ column_obj = grn_obj_column(ctx, table_obj, column_name, column_name_size);
+ if (column_obj) {
+ grn_obj_remove(ctx, column_obj);
+ }
+ if (ctx->rc) {
+ int error = ER_WRONG_COLUMN_NAME;
+ my_message(error, ctx->errbuf, MYF(0));
+ have_error = true;
+ break;
+ }
+ }
+ grn_obj_unlink(ctx, table_obj);
+
+ DBUG_RETURN(have_error);
+}
+
+bool ha_mroonga::storage_inplace_alter_table_rename_column(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have_error = false;
+
+ mrn::PathMapper mapper(share->table_name);
+ grn_obj *table_obj;
+ table_obj = grn_ctx_get(ctx, mapper.table_name(), strlen(mapper.table_name()));
+
+ Alter_info *alter_info = ha_alter_info->alter_info;
+ uint n_fields = table->s->fields;
+ for (uint i = 0; i < n_fields; i++) {
+ Field *field = table->field[i];
+
+ if (!(field->flags & FIELD_IS_RENAMED)) {
+ continue;
+ }
+
+ LEX_CSTRING new_name;
+ new_name.str= 0;
+ List_iterator_fast<Create_field> create_fields(alter_info->create_list);
+ while (Create_field *create_field = create_fields++) {
+ if (create_field->field == field) {
+ new_name = create_field->field_name;
+ break;
+ }
+ }
+
+ if (!new_name.str) {
+ continue;
+ }
+
+ const char *old_name = field->field_name.str;
+ grn_obj *column_obj;
+ column_obj = grn_obj_column(ctx, table_obj, old_name,
+ field->field_name.length);
+ if (column_obj) {
+ grn_column_rename(ctx, column_obj, new_name.str, new_name.length);
+ if (ctx->rc) {
+ int error = ER_WRONG_COLUMN_NAME;
+ my_message(error, ctx->errbuf, MYF(0));
+ have_error = true;
+ }
+ grn_obj_unlink(ctx, column_obj);
+ }
+
+ if (have_error) {
+ break;
+ }
+ }
+ grn_obj_unlink(ctx, table_obj);
+
+ DBUG_RETURN(have_error);
+}
+
+bool ha_mroonga::storage_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+
+ bool have_error = false;
+
+ int error = mrn_change_encoding(ctx, system_charset_info);
+ if (error) {
+ have_error = true;
+ }
+
+ alter_table_operations drop_index_related_flags =
+ ALTER_DROP_INDEX |
+ ALTER_DROP_NON_UNIQUE_NON_PRIM_INDEX |
+ ALTER_DROP_UNIQUE_INDEX |
+ ALTER_DROP_PK_INDEX;
+ if (!have_error &&
+ (ha_alter_info->handler_flags & drop_index_related_flags)) {
+ have_error = storage_inplace_alter_table_drop_index(altered_table,
+ ha_alter_info);
+ }
+
+ alter_table_operations add_column_related_flags =
+ ALTER_ADD_COLUMN;
+ if (!have_error &&
+ (ha_alter_info->handler_flags & add_column_related_flags)) {
+ have_error = storage_inplace_alter_table_add_column(altered_table, ha_alter_info);
+ }
+
+ alter_table_operations drop_column_related_flags = ALTER_DROP_COLUMN;
+ if (!have_error &&
+ (ha_alter_info->handler_flags & drop_column_related_flags)) {
+ have_error = storage_inplace_alter_table_drop_column(altered_table, ha_alter_info);
+ }
+
+ alter_table_operations rename_column_related_flags = ALTER_COLUMN_NAME;
+ if (!have_error &&
+ (ha_alter_info->handler_flags & rename_column_related_flags)) {
+ have_error = storage_inplace_alter_table_rename_column(altered_table, ha_alter_info);
+ }
+
+ alter_table_operations add_index_related_flags =
+ ALTER_ADD_INDEX |
+ ALTER_ADD_NON_UNIQUE_NON_PRIM_INDEX |
+ ALTER_ADD_UNIQUE_INDEX |
+ ALTER_ADD_PK_INDEX;
+ if (!have_error &&
+ (ha_alter_info->handler_flags & add_index_related_flags)) {
+ have_error = storage_inplace_alter_table_add_index(altered_table,
+ ha_alter_info);
+ }
+
+ DBUG_RETURN(have_error);
+}
+
+bool ha_mroonga::inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool result;
+ if (share->wrapper_mode) {
+ result = wrapper_inplace_alter_table(altered_table, ha_alter_info);
+ } else {
+ result = storage_inplace_alter_table(altered_table, ha_alter_info);
+ }
+ DBUG_RETURN(result);
+}
+
+bool ha_mroonga::wrapper_commit_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info,
+ bool commit)
+{
+ bool result;
+ MRN_DBUG_ENTER_METHOD();
+ if (!alter_handler_flags) {
+ free_root(&(wrap_altered_table_share->mem_root), MYF(0));
+ my_free(alter_key_info_buffer);
+ alter_key_info_buffer = NULL;
+ DBUG_RETURN(false);
+ }
+ MRN_SET_WRAP_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ result = wrap_handler->ha_commit_inplace_alter_table(wrap_altered_table,
+ ha_alter_info,
+ commit);
+ MRN_SET_BASE_ALTER_KEY(this, ha_alter_info);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ free_root(&(wrap_altered_table_share->mem_root), MYF(0));
+ my_free(alter_key_info_buffer);
+ alter_key_info_buffer = NULL;
+ DBUG_RETURN(result);
+}
+
+bool ha_mroonga::storage_commit_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info,
+ bool commit)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(false);
+}
+
+bool ha_mroonga::commit_inplace_alter_table(
+ TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info,
+ bool commit)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool result;
+ if (share->wrapper_mode) {
+ result = wrapper_commit_inplace_alter_table(altered_table, ha_alter_info,
+ commit);
+ } else {
+ result = storage_commit_inplace_alter_table(altered_table, ha_alter_info,
+ commit);
+ }
+ DBUG_RETURN(result);
+}
+#else
+alter_table_operations ha_mroonga::wrapper_alter_table_flags(alter_table_operations flags)
+{
+ alter_table_operations res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->alter_table_flags(flags);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+alter_table_operations ha_mroonga::storage_alter_table_flags(alter_table_operations flags)
+{
+ MRN_DBUG_ENTER_METHOD();
+ alter_table_operations res = handler::alter_table_flags(flags);
+ DBUG_RETURN(res);
+}
+
+alter_table_operations ha_mroonga::alter_table_flags(alter_table_operations flags)
+{
+ MRN_DBUG_ENTER_METHOD();
+ alter_table_operations res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_alter_table_flags(flags);
+ } else {
+ res = storage_alter_table_flags(flags);
+ }
+ DBUG_RETURN(res);
+}
+
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+int ha_mroonga::wrapper_add_index(TABLE *table_arg, KEY *key_info,
+ uint num_of_keys, handler_add_index **add)
+#else
+int ha_mroonga::wrapper_add_index(TABLE *table_arg, KEY *key_info,
+ uint num_of_keys)
+#endif
+{
+ int error = 0;
+ uint i, j, k;
+ uint n_keys = table->s->keys;
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, num_of_keys + n_keys);
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, num_of_keys + n_keys);
+ THD *thd = ha_thd();
+ MRN_SHARE *tmp_share;
+ TABLE_SHARE tmp_table_share;
+ char **key_tokenizer;
+ uint *key_tokenizer_length;
+ MRN_DBUG_ENTER_METHOD();
+ if (!(wrap_alter_key_info = (KEY *) mrn_my_malloc(sizeof(KEY) * num_of_keys,
+ MYF(MY_WME)))) {
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ KEY *p_key_info = &table->key_info[table_share->primary_key], *tmp_key_info;
+ tmp_table_share.keys = n_keys + num_of_keys;
+ tmp_table_share.fields = 0;
+ if (!(tmp_share = (MRN_SHARE *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &tmp_share, sizeof(*tmp_share),
+ &key_tokenizer, sizeof(char *) * (n_keys + num_of_keys),
+ &key_tokenizer_length, sizeof(uint) * (n_keys + num_of_keys),
+ NullS))
+ ) {
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ tmp_share->engine = NULL;
+ tmp_share->table_share = &tmp_table_share;
+ tmp_share->index_table = NULL;
+ tmp_share->index_table_length = NULL;
+ tmp_share->key_tokenizer = key_tokenizer;
+ tmp_share->key_tokenizer_length = key_tokenizer_length;
+ tmp_share->col_flags = NULL;
+ tmp_share->col_type = NULL;
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ hnd_add_index = NULL;
+#endif
+ bitmap_clear_all(table->read_set);
+ mrn_set_bitmap_by_key(table->read_set, p_key_info);
+ mrn::PathMapper mapper(share->table_name);
+ for (i = 0, j = 0; i < num_of_keys; i++) {
+ if (!(key_info[i].flags & HA_FULLTEXT) && !mrn_is_geo_key(&key_info[i])) {
+ wrap_alter_key_info[j] = key_info[i];
+ j++;
+ continue;
+ }
+ if (share->disable_keys) {
+ continue;
+ }
+ if ((error = mrn_add_index_param(tmp_share, &key_info[i], i + n_keys)))
+ {
+ break;
+ }
+ index_tables[i + n_keys] = NULL;
+ if (
+ (key_info[i].flags & HA_FULLTEXT) &&
+ (error = wrapper_create_index_fulltext(mapper.table_name(),
+ i + n_keys,
+ &key_info[i], index_tables, NULL,
+ tmp_share))
+ ) {
+ break;
+ } else if (
+ mrn_is_geo_key(&key_info[i]) &&
+ (error = wrapper_create_index_geo(mapper.table_name(),
+ i + n_keys, &key_info[i],
+ index_tables, NULL, tmp_share))
+ ) {
+ break;
+ }
+ mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
+ }
+ if (!error && i > j && !share->disable_keys) {
+ for (k = 0; k < num_of_keys; k++) {
+ tmp_key_info = &key_info[k];
+ if (!(tmp_key_info->flags & HA_FULLTEXT) &&
+ !mrn_is_geo_key(tmp_key_info)) {
+ continue;
+ }
+ index_columns[k + n_keys] = grn_obj_column(ctx,
+ index_tables[k + n_keys],
+ INDEX_COLUMN_NAME,
+ strlen(INDEX_COLUMN_NAME));
+ }
+ error = wrapper_fill_indexes(thd, key_info, &index_columns[n_keys],
+ num_of_keys);
+ }
+ bitmap_set_all(table->read_set);
+
+ if (!error && j)
+ {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ error = wrap_handler->add_index(table_arg, wrap_alter_key_info, j,
+ &hnd_add_index);
+#else
+ error = wrap_handler->add_index(table_arg, wrap_alter_key_info, j);
+#endif
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ if (error)
+ {
+ for (k = 0; k < i; k++) {
+ if (!(key_info[k].flags & HA_FULLTEXT) && !mrn_is_geo_key(&key_info[k]))
+ {
+ continue;
+ }
+ if (index_tables[k + n_keys])
+ {
+ grn_obj_remove(ctx, index_tables[k + n_keys]);
+ }
+ }
+ }
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ else {
+ *add = new handler_add_index(table_arg, key_info, num_of_keys);
+ }
+#endif
+ mrn_free_share_alloc(tmp_share);
+ my_free(tmp_share);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+int ha_mroonga::storage_add_index(TABLE *table_arg, KEY *key_info,
+ uint num_of_keys, handler_add_index **add)
+#else
+int ha_mroonga::storage_add_index(TABLE *table_arg, KEY *key_info,
+ uint num_of_keys)
+#endif
+{
+ int error = 0;
+ uint i;
+ uint n_keys = table->s->keys;
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_tables, num_of_keys + n_keys);
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(grn_obj *, index_columns, num_of_keys + n_keys);
+ MRN_SHARE *tmp_share;
+ TABLE_SHARE tmp_table_share;
+ char **index_table, **key_tokenizer, **col_flags, **col_type;
+ uint *index_table_length, *key_tokenizer_length, *col_flags_length, *col_type_length;
+ bool have_multiple_column_index = false;
+
+ MRN_DBUG_ENTER_METHOD();
+ tmp_table_share.keys = n_keys + num_of_keys;
+ tmp_table_share.fields = 0;
+ if (!(tmp_share = (MRN_SHARE *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &tmp_share, sizeof(*tmp_share),
+ &index_table, sizeof(char*) * tmp_table_share.keys,
+ &index_table_length, sizeof(uint) * tmp_table_share.keys,
+ &key_tokenizer, sizeof(char *) * tmp_table_share.keys,
+ &key_tokenizer_length, sizeof(uint) * tmp_table_share.keys,
+ &col_flags, sizeof(char *) * tmp_table_share.fields,
+ &col_flags_length, sizeof(uint) * tmp_table_share.fields,
+ &col_type, sizeof(char *) * tmp_table_share.fields,
+ &col_type_length, sizeof(uint) * tmp_table_share.fields,
+ NullS))
+ ) {
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ tmp_share->engine = NULL;
+ tmp_share->table_share = &tmp_table_share;
+ tmp_share->index_table = index_table;
+ tmp_share->index_table_length = index_table_length;
+ tmp_share->key_tokenizer = key_tokenizer;
+ tmp_share->key_tokenizer_length = key_tokenizer_length;
+ tmp_share->col_flags = col_flags;
+ tmp_share->col_flags_length = col_flags_length;
+ tmp_share->col_type = col_type;
+ tmp_share->col_type_length = col_type_length;
+ bitmap_clear_all(table->read_set);
+ mrn::PathMapper mapper(share->table_name);
+ for (i = 0; i < num_of_keys; i++) {
+ if (share->disable_keys && !(key_info[i].flags & HA_NOSAME)) {
+ continue; // key is disabled
+ }
+ index_tables[i + n_keys] = NULL;
+ index_columns[i + n_keys] = NULL;
+ if ((error = mrn_add_index_param(tmp_share, &key_info[i], i + n_keys)))
+ {
+ break;
+ }
+ if ((error = storage_create_index(table, mapper.table_name(), grn_table,
+ tmp_share, &key_info[i], index_tables,
+ index_columns, i + n_keys)))
+ {
+ break;
+ }
+ if (
+ KEY_N_KEY_PARTS(&(key_info[i])) == 1 &&
+ (key_info[i].flags & HA_NOSAME) &&
+ grn_table_size(ctx, grn_table) !=
+ grn_table_size(ctx, index_tables[i + n_keys])
+ ) {
+ error = HA_ERR_FOUND_DUPP_UNIQUE;
+ i++;
+ break;
+ }
+ if (
+ KEY_N_KEY_PARTS(&(key_info[i])) != 1 &&
+ !(key_info[i].flags & HA_FULLTEXT)
+ ) {
+ mrn_set_bitmap_by_key(table->read_set, &key_info[i]);
+ have_multiple_column_index = true;
+ }
+ }
+ if (!error && have_multiple_column_index)
+ {
+ error = storage_add_index_multiple_columns(key_info, num_of_keys,
+ index_tables + n_keys,
+ index_columns + n_keys, false);
+ }
+ bitmap_set_all(table->read_set);
+ if (error)
+ {
+ for (uint j = 0; j < i; j++) {
+ if (index_tables[j + n_keys])
+ {
+ grn_obj_remove(ctx, index_columns[j + n_keys]);
+ grn_obj_remove(ctx, index_tables[j + n_keys]);
+ }
+ }
+ }
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ else {
+ *add = new handler_add_index(table_arg, key_info, num_of_keys);
+ }
+#endif
+ mrn_free_share_alloc(tmp_share);
+ my_free(tmp_share);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_tables);
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(index_columns);
+ DBUG_RETURN(error);
+}
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+int ha_mroonga::add_index(TABLE *table_arg, KEY *key_info,
+ uint num_of_keys, handler_add_index **add)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_add_index(table_arg, key_info, num_of_keys, add);
+ } else {
+ error = storage_add_index(table_arg, key_info, num_of_keys, add);
+ }
+ DBUG_RETURN(error);
+}
+#else
+int ha_mroonga::add_index(TABLE *table_arg, KEY *key_info,
+ uint num_of_keys)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_add_index(table_arg, key_info, num_of_keys);
+ } else {
+ error = storage_add_index(table_arg, key_info, num_of_keys);
+ }
+ DBUG_RETURN(error);
+}
+#endif
+
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+int ha_mroonga::wrapper_final_add_index(handler_add_index *add, bool commit)
+{
+ int error = 0;
+ MRN_DBUG_ENTER_METHOD();
+ if (hnd_add_index)
+ {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ error = wrap_handler->final_add_index(hnd_add_index, commit);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ if (add)
+ {
+ delete add;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_final_add_index(handler_add_index *add, bool commit)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (add)
+ {
+ delete add;
+ }
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::final_add_index(handler_add_index *add, bool commit)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ if (share->wrapper_mode)
+ {
+ error = wrapper_final_add_index(add, commit);
+ } else {
+ error = storage_final_add_index(add, commit);
+ }
+ DBUG_RETURN(error);
+}
+#endif
+
+int ha_mroonga::wrapper_prepare_drop_index(TABLE *table_arg, uint *key_num,
+ uint num_of_keys)
+{
+ int res = 0;
+ uint i, j;
+ KEY *key_info = table_share->key_info;
+ MRN_DBUG_ENTER_METHOD();
+ res = mrn_change_encoding(ctx, system_charset_info);
+ if (res)
+ DBUG_RETURN(res);
+
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(uint, wrap_key_num, num_of_keys);
+ for (i = 0, j = 0; i < num_of_keys; i++) {
+ uint key_index = key_num[i];
+ if (!(key_info[key_index].flags & HA_FULLTEXT) &&
+ !mrn_is_geo_key(&key_info[key_index])) {
+ wrap_key_num[j] = share->wrap_key_nr[key_index];
+ j++;
+ continue;
+ }
+
+ res = drop_index(share, key_index);
+ if (res)
+ DBUG_RETURN(res);
+ grn_index_tables[key_index] = NULL;
+ grn_index_columns[key_index] = NULL;
+ }
+ if (j)
+ {
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->prepare_drop_index(table_arg, wrap_key_num, j);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ }
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(wrap_key_num);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_prepare_drop_index(TABLE *table_arg, uint *key_num,
+ uint num_of_keys)
+{
+ int error;
+ uint i;
+ MRN_DBUG_ENTER_METHOD();
+ error = mrn_change_encoding(ctx, system_charset_info);
+ if (error)
+ DBUG_RETURN(error);
+
+ for (i = 0; i < num_of_keys; i++) {
+ uint key_index = key_num[i];
+ error = drop_index(share, key_index);
+ if (error)
+ break;
+ grn_index_tables[key_index] = NULL;
+ grn_index_columns[key_index] = NULL;
+ }
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::prepare_drop_index(TABLE *table_arg, uint *key_num,
+ uint num_of_keys)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_prepare_drop_index(table_arg, key_num, num_of_keys);
+ } else {
+ res = storage_prepare_drop_index(table_arg, key_num, num_of_keys);
+ }
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::wrapper_final_drop_index(TABLE *table_arg)
+{
+ uint res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->final_drop_index(table_arg);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_final_drop_index(TABLE *table_arg)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::final_drop_index(TABLE *table_arg)
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_final_drop_index(table_arg);
+ } else {
+ res = storage_final_drop_index(table_arg);
+ }
+ DBUG_RETURN(res);
+}
+#endif
+
+int ha_mroonga::wrapper_update_auto_increment()
+{
+ int res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->update_auto_increment();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_update_auto_increment()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res = handler::update_auto_increment();
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ table->next_number_field->val_int()));
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::update_auto_increment()
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_update_auto_increment();
+ } else {
+ res = storage_update_auto_increment();
+ }
+ DBUG_RETURN(res);
+}
+
+void ha_mroonga::wrapper_set_next_insert_id(ulonglong id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->set_next_insert_id(id);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_set_next_insert_id(ulonglong id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::set_next_insert_id(id);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::set_next_insert_id(ulonglong id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_set_next_insert_id(id);
+ } else {
+ storage_set_next_insert_id(id);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::wrapper_get_auto_increment(ulonglong offset,
+ ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->get_auto_increment(offset, increment, nb_desired_values,
+ first_value, nb_reserved_values);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_get_auto_increment(ulonglong offset,
+ ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
+{
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ MRN_DBUG_ENTER_METHOD();
+ if (table->found_next_number_field &&
+ !table->s->next_number_keypart) {
+ if (long_term_share->auto_inc_inited) {
+ *first_value = long_term_share->auto_inc_value;
+ DBUG_PRINT("info", ("mroonga: *first_value(auto_inc_value)=%llu",
+ *first_value));
+ *nb_reserved_values = UINT_MAX64;
+ } else {
+ handler::get_auto_increment(offset, increment, nb_desired_values,
+ first_value, nb_reserved_values);
+ long_term_share->auto_inc_value = *first_value;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ long_term_share->auto_inc_inited = true;
+ }
+ } else {
+ handler::get_auto_increment(offset, increment, nb_desired_values,
+ first_value, nb_reserved_values);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_get_auto_increment(offset, increment, nb_desired_values,
+ first_value, nb_reserved_values);
+ } else {
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ storage_get_auto_increment(offset, increment, nb_desired_values,
+ first_value, nb_reserved_values);
+ long_term_share->auto_inc_value += nb_desired_values * increment;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::wrapper_restore_auto_increment(ulonglong prev_insert_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->restore_auto_increment(prev_insert_id);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_restore_auto_increment(ulonglong prev_insert_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::restore_auto_increment(prev_insert_id);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::restore_auto_increment(ulonglong prev_insert_id)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_restore_auto_increment(prev_insert_id);
+ } else {
+ storage_restore_auto_increment(prev_insert_id);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::wrapper_release_auto_increment()
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->ha_release_auto_increment();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_release_auto_increment()
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::release_auto_increment()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_release_auto_increment();
+ } else {
+ storage_release_auto_increment();
+ }
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::wrapper_check_for_upgrade(HA_CHECK_OPT *check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ int error = wrap_handler->ha_check_for_upgrade(check_opt);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(error);
+}
+
+int ha_mroonga::storage_check_for_upgrade(HA_CHECK_OPT *check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ for (uint i = 0; i < table->s->fields; ++i) {
+ grn_obj *column = grn_columns[i];
+ if (!column) {
+ continue;
+ }
+ Field *field = table->field[i];
+ grn_id column_range = grn_obj_get_range(ctx, column);
+ switch (field->real_type()) {
+ case MYSQL_TYPE_ENUM:
+ if (column_range != GRN_DB_UINT16) {
+ DBUG_RETURN(HA_ADMIN_NEEDS_ALTER);
+ }
+ break;
+ case MYSQL_TYPE_SET:
+ if (column_range != GRN_DB_UINT64) {
+ DBUG_RETURN(HA_ADMIN_NEEDS_ALTER);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ DBUG_RETURN(HA_ADMIN_OK);
+}
+
+int ha_mroonga::check_for_upgrade(HA_CHECK_OPT *check_opt)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int error;
+ if (share->wrapper_mode) {
+ error = wrapper_check_for_upgrade(check_opt);
+ } else {
+ error = storage_check_for_upgrade(check_opt);
+ }
+ DBUG_RETURN(error);
+}
+
+#ifdef MRN_HANDLER_HAVE_RESET_AUTO_INCREMENT
+int ha_mroonga::wrapper_reset_auto_increment(ulonglong value)
+{
+ int res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->ha_reset_auto_increment(value);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_reset_auto_increment(ulonglong value)
+{
+ MRN_LONG_TERM_SHARE *long_term_share = share->long_term_share;
+ MRN_DBUG_ENTER_METHOD();
+ mrn::Lock lock(&long_term_share->auto_inc_mutex);
+ long_term_share->auto_inc_value = value;
+ DBUG_PRINT("info", ("mroonga: auto_inc_value=%llu",
+ long_term_share->auto_inc_value));
+ long_term_share->auto_inc_inited = true;
+ DBUG_RETURN(0);
+}
+
+int ha_mroonga::reset_auto_increment(ulonglong value)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_reset_auto_increment(value);
+ } else {
+ res = storage_reset_auto_increment(value);
+ }
+ DBUG_RETURN(res);
+}
+#endif
+
+void ha_mroonga::set_pk_bitmap()
+{
+ MRN_DBUG_ENTER_METHOD();
+ KEY *key_info = &(table->key_info[table_share->primary_key]);
+ uint j;
+ for (j = 0; j < KEY_N_KEY_PARTS(key_info); j++) {
+ Field *field = key_info->key_part[j].field;
+ bitmap_set_bit(table->read_set, field->field_index);
+ }
+ DBUG_VOID_RETURN;
+}
+
+bool ha_mroonga::wrapper_was_semi_consistent_read()
+{
+ bool res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->was_semi_consistent_read();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::storage_was_semi_consistent_read()
+{
+ bool res;
+ MRN_DBUG_ENTER_METHOD();
+ res = handler::was_semi_consistent_read();
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::was_semi_consistent_read()
+{
+ bool res;
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ res = wrapper_was_semi_consistent_read();
+ } else {
+ res = storage_was_semi_consistent_read();
+ }
+ DBUG_RETURN(res);
+}
+
+void ha_mroonga::wrapper_try_semi_consistent_read(bool yes)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->try_semi_consistent_read(yes);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_try_semi_consistent_read(bool yes)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::try_semi_consistent_read(yes);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::try_semi_consistent_read(bool yes)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_try_semi_consistent_read(yes);
+ } else {
+ storage_try_semi_consistent_read(yes);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::wrapper_unlock_row()
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->unlock_row();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_unlock_row()
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::unlock_row();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::unlock_row()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_unlock_row();
+ } else {
+ storage_unlock_row();
+ }
+ DBUG_VOID_RETURN;
+}
+
+int ha_mroonga::wrapper_start_stmt(THD *thd, thr_lock_type lock_type)
+{
+ int res;
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->start_stmt(thd, lock_type);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_start_stmt(THD *thd, thr_lock_type lock_type)
+{
+ int res;
+ MRN_DBUG_ENTER_METHOD();
+ res = handler::start_stmt(thd, lock_type);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::start_stmt(THD *thd, thr_lock_type lock_type)
+{
+ int res;
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ res = wrapper_start_stmt(thd, lock_type);
+ } else {
+ res = storage_start_stmt(thd, lock_type);
+ }
+ DBUG_RETURN(res);
+}
+
+void ha_mroonga::wrapper_change_table_ptr(TABLE *table_arg,
+ TABLE_SHARE *share_arg)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->change_table_ptr(table_arg, share->wrap_table_share);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_change_table_ptr(TABLE *table_arg,
+ TABLE_SHARE *share_arg)
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::change_table_ptr(TABLE *table_arg, TABLE_SHARE *share_arg)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::change_table_ptr(table_arg, share_arg);
+ if (share && share->wrapper_mode)
+ {
+ wrapper_change_table_ptr(table_arg, share_arg);
+ } else {
+ storage_change_table_ptr(table_arg, share_arg);
+ }
+ DBUG_VOID_RETURN;
+}
+
+bool ha_mroonga::wrapper_is_fk_defined_on_table_or_index(uint index)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->is_fk_defined_on_table_or_index(index);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::storage_is_fk_defined_on_table_or_index(uint index)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res = handler::is_fk_defined_on_table_or_index(index);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::is_fk_defined_on_table_or_index(uint index)
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_is_fk_defined_on_table_or_index(index);
+ } else {
+ res = storage_is_fk_defined_on_table_or_index(index);
+ }
+ DBUG_RETURN(res);
+}
+
+char *ha_mroonga::wrapper_get_foreign_key_create_info()
+{
+ MRN_DBUG_ENTER_METHOD();
+ char *res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->get_foreign_key_create_info();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+char *ha_mroonga::storage_get_foreign_key_create_info()
+{
+ int error;
+ uint i;
+ grn_obj *column;
+ uint n_columns = table_share->fields;
+ char create_info_buff[2048], *create_info;
+ String create_info_str(create_info_buff, sizeof(create_info_buff),
+ system_charset_info);
+ MRN_DBUG_ENTER_METHOD();
+ create_info_str.length(0);
+ for (i = 0; i < n_columns; ++i) {
+ Field *field = table_share->field[i];
+
+ if (!is_foreign_key_field(table_share->table_name.str,
+ field->field_name.str)) {
+ continue;
+ }
+
+ mrn::ColumnName column_name(field->field_name);
+ column = grn_obj_column(ctx,
+ grn_table,
+ column_name.c_str(),
+ column_name.length());
+ if (!column) {
+ continue;
+ }
+ grn_id ref_table_id = grn_obj_get_range(ctx, column);
+ grn_obj *ref_table = grn_ctx_at(ctx, ref_table_id);
+ char ref_table_buff[NAME_LEN + 1];
+ int ref_table_name_length = grn_obj_name(ctx, ref_table, ref_table_buff,
+ NAME_LEN);
+ ref_table_buff[ref_table_name_length] = '\0';
+
+ if (create_info_str.reserve(15)) {
+ DBUG_RETURN(NULL);
+ }
+ create_info_str.q_append(",\n CONSTRAINT ", 15);
+ append_identifier(ha_thd(),
+ &create_info_str,
+ column_name.c_str(),
+ column_name.length());
+ if (create_info_str.reserve(14)) {
+ DBUG_RETURN(NULL);
+ }
+ create_info_str.q_append(" FOREIGN KEY (", 14);
+ append_identifier(ha_thd(),
+ &create_info_str,
+ column_name.c_str(),
+ column_name.length());
+ if (create_info_str.reserve(13)) {
+ DBUG_RETURN(NULL);
+ }
+ create_info_str.q_append(") REFERENCES ", 13);
+ append_identifier(ha_thd(), &create_info_str, table_share->db.str,
+ table_share->db.length);
+ if (create_info_str.reserve(1)) {
+ DBUG_RETURN(NULL);
+ }
+ create_info_str.q_append(".", 1);
+ append_identifier(ha_thd(), &create_info_str, ref_table_buff,
+ ref_table_name_length);
+ if (create_info_str.reserve(2)) {
+ DBUG_RETURN(NULL);
+ }
+ create_info_str.q_append(" (", 2);
+
+ char ref_path[FN_REFLEN + 1];
+ TABLE_LIST table_list;
+ TABLE_SHARE *tmp_ref_table_share;
+ build_table_filename(ref_path, sizeof(ref_path) - 1,
+ table_share->db.str, ref_table_buff, "", 0);
+ DBUG_PRINT("info", ("mroonga: ref_path=%s", ref_path));
+
+ LEX_CSTRING table_name= { ref_table_buff, (size_t) ref_table_name_length };
+ table_list.init_one_table(&table_share->db, &table_name, 0, TL_WRITE);
+ mrn_open_mutex_lock(table_share);
+ tmp_ref_table_share =
+ mrn_create_tmp_table_share(&table_list, ref_path, &error);
+ mrn_open_mutex_unlock(table_share);
+ if (!tmp_ref_table_share) {
+ DBUG_RETURN(NULL);
+ }
+ uint ref_pkey_nr = tmp_ref_table_share->primary_key;
+ KEY *ref_key_info = &tmp_ref_table_share->key_info[ref_pkey_nr];
+ Field *ref_field = &ref_key_info->key_part->field[0];
+ append_identifier(ha_thd(), &create_info_str, ref_field->field_name.str,
+ ref_field->field_name.length);
+ mrn_open_mutex_lock(table_share);
+ mrn_free_tmp_table_share(tmp_ref_table_share);
+ mrn_open_mutex_unlock(table_share);
+ if (create_info_str.reserve(39)) {
+ DBUG_RETURN(NULL);
+ }
+ create_info_str.q_append(") ON DELETE RESTRICT ON UPDATE RESTRICT", 39);
+ }
+ if (!(create_info = (char *) mrn_my_malloc(create_info_str.length() + 1,
+ MYF(MY_WME)))) {
+ DBUG_RETURN(NULL);
+ }
+ memcpy(create_info, create_info_str.ptr(), create_info_str.length());
+ create_info[create_info_str.length()] = '\0';
+ DBUG_RETURN(create_info);
+}
+#else
+char *ha_mroonga::storage_get_foreign_key_create_info()
+{
+ MRN_DBUG_ENTER_METHOD();
+ char *res = handler::get_foreign_key_create_info();
+ DBUG_RETURN(res);
+}
+#endif
+
+char *ha_mroonga::get_foreign_key_create_info()
+{
+ MRN_DBUG_ENTER_METHOD();
+ char *res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_get_foreign_key_create_info();
+ } else {
+ res = storage_get_foreign_key_create_info();
+ }
+ DBUG_RETURN(res);
+}
+
+#ifdef MRN_HANDLER_HAVE_GET_TABLESPACE_NAME
+char *ha_mroonga::wrapper_get_tablespace_name(THD *thd, char *name,
+ uint name_len)
+{
+ MRN_DBUG_ENTER_METHOD();
+ char *res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->get_tablespace_name(thd, name, name_len);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+char *ha_mroonga::storage_get_tablespace_name(THD *thd, char *name,
+ uint name_len)
+{
+ MRN_DBUG_ENTER_METHOD();
+ char *res = handler::get_tablespace_name(thd, name, name_len);
+ DBUG_RETURN(res);
+}
+
+char *ha_mroonga::get_tablespace_name(THD *thd, char *name, uint name_len)
+{
+ MRN_DBUG_ENTER_METHOD();
+ char *res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_get_tablespace_name(thd, name, name_len);
+ } else {
+ res = storage_get_tablespace_name(thd, name, name_len);
+ }
+ DBUG_RETURN(res);
+}
+#endif
+
+bool ha_mroonga::wrapper_can_switch_engines()
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->can_switch_engines();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::storage_can_switch_engines()
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res = handler::can_switch_engines();
+ DBUG_RETURN(res);
+}
+
+bool ha_mroonga::can_switch_engines()
+{
+ MRN_DBUG_ENTER_METHOD();
+ bool res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_can_switch_engines();
+ } else {
+ res = storage_can_switch_engines();
+ }
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::wrapper_get_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->get_foreign_key_list(thd, f_key_list);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+int ha_mroonga::storage_get_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ int error;
+ uint i;
+ grn_obj *column;
+ uint n_columns = table_share->fields;
+ MRN_DBUG_ENTER_METHOD();
+ for (i = 0; i < n_columns; ++i) {
+ Field *field = table_share->field[i];
+
+ if (!is_foreign_key_field(table_share->table_name.str,
+ field->field_name.str)) {
+ continue;
+ }
+
+ mrn::ColumnName column_name(field->field_name);
+ column = grn_obj_column(ctx,
+ grn_table,
+ column_name.c_str(),
+ column_name.length());
+ if (!column) {
+ continue;
+ }
+ grn_id ref_table_id = grn_obj_get_range(ctx, column);
+ grn_obj *ref_table = grn_ctx_at(ctx, ref_table_id);
+ FOREIGN_KEY_INFO f_key_info;
+ f_key_info.foreign_id = thd_make_lex_string(thd,
+ NULL,
+ column_name.c_str(),
+ column_name.length(),
+ TRUE);
+ f_key_info.foreign_db = thd_make_lex_string(thd, NULL,
+ table_share->db.str,
+ table_share->db.length,
+ TRUE);
+ f_key_info.foreign_table = thd_make_lex_string(thd, NULL,
+ table_share->table_name.str,
+ table_share->table_name.length,
+ TRUE);
+ f_key_info.referenced_db = f_key_info.foreign_db;
+
+ char ref_table_buff[NAME_LEN + 1];
+ int ref_table_name_length = grn_obj_name(ctx, ref_table, ref_table_buff,
+ NAME_LEN);
+ ref_table_buff[ref_table_name_length] = '\0';
+ DBUG_PRINT("info", ("mroonga: ref_table_buff=%s", ref_table_buff));
+ DBUG_PRINT("info", ("mroonga: ref_table_name_length=%d", ref_table_name_length));
+ f_key_info.referenced_table = thd_make_lex_string(thd, NULL,
+ ref_table_buff,
+ ref_table_name_length,
+ TRUE);
+ f_key_info.update_method = FK_OPTION_RESTRICT;
+ f_key_info.delete_method = FK_OPTION_RESTRICT;
+ f_key_info.referenced_key_name = thd_make_lex_string(thd, NULL, "PRIMARY",
+ 7, TRUE);
+ LEX_CSTRING *field_name = thd_make_lex_string(thd,
+ NULL,
+ column_name.c_str(),
+ column_name.length(),
+ TRUE);
+ f_key_info.foreign_fields.push_back(field_name);
+
+ char ref_path[FN_REFLEN + 1];
+ TABLE_LIST table_list;
+ TABLE_SHARE *tmp_ref_table_share;
+ build_table_filename(ref_path, sizeof(ref_path) - 1,
+ table_share->db.str, ref_table_buff, "", 0);
+ DBUG_PRINT("info", ("mroonga: ref_path=%s", ref_path));
+
+ LEX_CSTRING table_name= { ref_table_buff, (size_t) ref_table_name_length };
+ table_list.init_one_table(&table_share->db, &table_name, 0, TL_WRITE);
+ mrn_open_mutex_lock(table_share);
+ tmp_ref_table_share =
+ mrn_create_tmp_table_share(&table_list, ref_path, &error);
+ mrn_open_mutex_unlock(table_share);
+ if (!tmp_ref_table_share) {
+ DBUG_RETURN(error);
+ }
+ uint ref_pkey_nr = tmp_ref_table_share->primary_key;
+ KEY *ref_key_info = &tmp_ref_table_share->key_info[ref_pkey_nr];
+ Field *ref_field = &ref_key_info->key_part->field[0];
+ LEX_CSTRING *ref_col_name = thd_make_lex_string(thd, NULL,
+ ref_field->field_name.str,
+ ref_field->field_name.length,
+ TRUE);
+ f_key_info.referenced_fields.push_back(ref_col_name);
+ mrn_open_mutex_lock(table_share);
+ mrn_free_tmp_table_share(tmp_ref_table_share);
+ mrn_open_mutex_unlock(table_share);
+ FOREIGN_KEY_INFO *p_f_key_info =
+ (FOREIGN_KEY_INFO *) thd_memdup(thd, &f_key_info,
+ sizeof(FOREIGN_KEY_INFO));
+ if (!p_f_key_info) {
+ DBUG_RETURN(HA_ERR_OUT_OF_MEM);
+ }
+ f_key_list->push_back(p_f_key_info);
+ }
+ DBUG_RETURN(0);
+}
+#else
+int ha_mroonga::storage_get_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res = handler::get_foreign_key_list(thd, f_key_list);
+ DBUG_RETURN(res);
+}
+#endif
+
+int ha_mroonga::get_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_get_foreign_key_list(thd, f_key_list);
+ } else {
+ res = storage_get_foreign_key_list(thd, f_key_list);
+ }
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::wrapper_get_parent_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->get_parent_foreign_key_list(thd, f_key_list);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::storage_get_parent_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res = handler::get_parent_foreign_key_list(thd, f_key_list);
+ DBUG_RETURN(res);
+}
+
+int ha_mroonga::get_parent_foreign_key_list(THD *thd,
+ List<FOREIGN_KEY_INFO> *f_key_list)
+{
+ MRN_DBUG_ENTER_METHOD();
+ int res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_get_parent_foreign_key_list(thd, f_key_list);
+ } else {
+ res = storage_get_parent_foreign_key_list(thd, f_key_list);
+ }
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::wrapper_referenced_by_foreign_key()
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->referenced_by_foreign_key();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::storage_referenced_by_foreign_key()
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint res = handler::referenced_by_foreign_key();
+ DBUG_RETURN(res);
+}
+
+uint ha_mroonga::referenced_by_foreign_key()
+{
+ MRN_DBUG_ENTER_METHOD();
+ uint res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_referenced_by_foreign_key();
+ } else {
+ res = storage_referenced_by_foreign_key();
+ }
+ DBUG_RETURN(res);
+}
+
+void ha_mroonga::wrapper_init_table_handle_for_HANDLER()
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->init_table_handle_for_HANDLER();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_init_table_handle_for_HANDLER()
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::init_table_handle_for_HANDLER();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::init_table_handle_for_HANDLER()
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_init_table_handle_for_HANDLER();
+ } else {
+ storage_init_table_handle_for_HANDLER();
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::wrapper_free_foreign_key_create_info(char* str)
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->free_foreign_key_create_info(str);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+void ha_mroonga::storage_free_foreign_key_create_info(char* str)
+{
+ MRN_DBUG_ENTER_METHOD();
+ my_free(str);
+ DBUG_VOID_RETURN;
+}
+#else
+void ha_mroonga::storage_free_foreign_key_create_info(char* str)
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::free_foreign_key_create_info(str);
+ DBUG_VOID_RETURN;
+}
+#endif
+
+void ha_mroonga::free_foreign_key_create_info(char* str)
+{
+ MRN_DBUG_ENTER_METHOD();
+ if (share->wrapper_mode)
+ {
+ wrapper_free_foreign_key_create_info(str);
+ } else {
+ storage_free_foreign_key_create_info(str);
+ }
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
+bool ha_mroonga::check_written_by_row_based_binlog()
+{
+ MRN_DBUG_ENTER_METHOD();
+ THD *thd = ha_thd();
+
+ int current_stmt_binlog_row;
+#ifdef MRN_ROW_BASED_CHECK_IS_METHOD
+ current_stmt_binlog_row = thd->is_current_stmt_binlog_format_row();
+#else
+ current_stmt_binlog_row = thd->current_stmt_binlog_row_based;
+#endif
+ if (!current_stmt_binlog_row) {
+ DBUG_RETURN(false);
+ }
+
+ if (table->s->tmp_table != NO_TMP_TABLE) {
+ DBUG_RETURN(false);
+ }
+
+ if (!mrn_binlog_filter->db_ok(table->s->db.str)) {
+ DBUG_RETURN(false);
+ }
+
+ if (!thd_test_options(thd, OPTION_BIN_LOG)) {
+ DBUG_RETURN(false);
+ }
+
+ if (!mysql_bin_log.is_open()) {
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(true);
+}
+#endif
+
+#ifdef MRN_HAVE_HA_REBIND_PSI
+void ha_mroonga::wrapper_unbind_psi()
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->unbind_psi();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_unbind_psi()
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::unbind_psi()
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::unbind_psi();
+ if (share->wrapper_mode)
+ {
+ wrapper_unbind_psi();
+ } else {
+ storage_unbind_psi();
+ }
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::wrapper_rebind()
+{
+ MRN_DBUG_ENTER_METHOD();
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ wrap_handler->rebind_psi();
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::storage_rebind()
+{
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_VOID_RETURN;
+}
+
+void ha_mroonga::rebind_psi()
+{
+ MRN_DBUG_ENTER_METHOD();
+ handler::rebind_psi();
+ if (share->wrapper_mode)
+ {
+ wrapper_rebind();
+ } else {
+ storage_rebind();
+ }
+ DBUG_VOID_RETURN;
+}
+#endif
+
+my_bool ha_mroonga::wrapper_register_query_cache_table(THD *thd,
+ const char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+ my_bool res;
+ MRN_SET_WRAP_SHARE_KEY(share, table->s);
+ MRN_SET_WRAP_TABLE_KEY(this, table);
+ res = wrap_handler->register_query_cache_table(thd,
+ table_key,
+ key_length,
+ engine_callback,
+ engine_data);
+ MRN_SET_BASE_SHARE_KEY(share, table->s);
+ MRN_SET_BASE_TABLE_KEY(this, table);
+ DBUG_RETURN(res);
+}
+
+my_bool ha_mroonga::storage_register_query_cache_table(THD *thd,
+ const char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+ my_bool res = handler::register_query_cache_table(thd,
+ table_key,
+ key_length,
+ engine_callback,
+ engine_data);
+ DBUG_RETURN(res);
+}
+
+my_bool ha_mroonga::register_query_cache_table(THD *thd,
+ const char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data)
+{
+ MRN_DBUG_ENTER_METHOD();
+ my_bool res;
+ if (share->wrapper_mode)
+ {
+ res = wrapper_register_query_cache_table(thd,
+ table_key,
+ key_length,
+ engine_callback,
+ engine_data);
+ } else {
+ res = storage_register_query_cache_table(thd,
+ table_key,
+ key_length,
+ engine_callback,
+ engine_data);
+ }
+ DBUG_RETURN(res);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+namespace mrn {
+ namespace variables {
+ ulonglong get_boolean_mode_syntax_flags(THD *thd) {
+ ulonglong flags = BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT;
+#ifdef MRN_SUPPORT_THDVAR_SET
+ flags = THDVAR(thd, boolean_mode_syntax_flags);
+#endif
+ return flags;
+ }
+
+ ActionOnError get_action_on_fulltext_query_error(THD *thd) {
+ ulong action = THDVAR(thd, action_on_fulltext_query_error);
+ return static_cast<ActionOnError>(action);
+ }
+ }
+}
diff --git a/storage/mroonga/ha_mroonga.def b/storage/mroonga/ha_mroonga.def
new file mode 100644
index 00000000..7f8394fe
--- /dev/null
+++ b/storage/mroonga/ha_mroonga.def
@@ -0,0 +1,18 @@
+LIBRARY ha_mroonga
+VERSION 1.0
+EXPORTS
+ last_insert_grn_id
+ last_insert_grn_id_init
+ last_insert_grn_id_deinit
+ mroonga_snippet
+ mroonga_snippet_init
+ mroonga_snippet_deinit
+ mroonga_command
+ mroonga_command_init
+ mroonga_command_deinit
+ mroonga_escape
+ mroonga_escape_init
+ mroonga_escape_deinit
+ mroonga_normalize
+ mroonga_normalize_init
+ mroonga_normalize_deinit
diff --git a/storage/mroonga/ha_mroonga.hpp b/storage/mroonga/ha_mroonga.hpp
new file mode 100644
index 00000000..66767899
--- /dev/null
+++ b/storage/mroonga/ha_mroonga.hpp
@@ -0,0 +1,1309 @@
+/* -*- 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-1335 USA
+*/
+
+#ifndef HA_MROONGA_HPP_
+#define HA_MROONGA_HPP_
+
+#ifdef USE_PRAGMA_INTERFACE
+#pragma interface
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <groonga.h>
+#include "mrn_mysql_compat.h"
+#include <mrn_operations.hpp>
+#include <mrn_database.hpp>
+
+#if __cplusplus >= 201402
+# define mrn_override override
+#else
+# define mrn_override
+#endif
+
+#if (MYSQL_VERSION_ID >= 50514 && MYSQL_VERSION_ID < 50600)
+# define MRN_HANDLER_HAVE_FINAL_ADD_INDEX 1
+#endif
+
+#if (MYSQL_VERSION_ID >= 50603) || defined(MRN_MARIADB_P)
+# define MRN_HANDLER_HAVE_HA_RND_NEXT 1
+# define MRN_HANDLER_HAVE_HA_RND_POS 1
+# define MRN_HANDLER_HAVE_HA_INDEX_READ_MAP 1
+# define MRN_HANDLER_HAVE_HA_INDEX_READ_IDX_MAP 1
+# define MRN_HANDLER_HAVE_HA_INDEX_NEXT 1
+# define MRN_HANDLER_HAVE_HA_INDEX_PREV 1
+# define MRN_HANDLER_HAVE_HA_INDEX_FIRST 1
+# define MRN_HANDLER_HAVE_HA_INDEX_LAST 1
+# define MRN_HANDLER_HAVE_HA_INDEX_NEXT_SAME 1
+#endif
+
+#if (MYSQL_VERSION_ID >= 50604) || defined(MRN_MARIADB_P)
+# define MRN_HANDLER_HAVE_HA_CLOSE 1
+# define MRN_HANDLER_HAVE_MULTI_RANGE_READ 1
+#endif
+
+#if (MYSQL_VERSION_ID >= 50607)
+# define MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER 1
+# define MRN_HANDLER_HAVE_HA_PREPARE_INPLACE_ALTER_TABLE 1
+# define MRN_HANDLER_HAVE_HA_INPLACE_ALTER_TABLE 1
+# define MRN_HANDLER_HAVE_HA_COMMIT_INPLACE_ALTER_TABLE 1
+# define MRN_SUPPORT_FOREIGN_KEYS 1
+#endif
+
+#ifndef MRN_MARIADB_P
+# define MRN_HANDLER_HAVE_INDEX_READ_LAST_MAP
+# if MYSQL_VERSION_ID >= 50611
+# define MRN_HANDLER_HAVE_HA_INDEX_READ_LAST_MAP
+# endif
+#endif
+
+#ifdef MRN_MARIADB_P
+# define MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+#endif
+
+#if MYSQL_VERSION_ID < 50600
+# define MRN_HANDLER_HAVE_GET_TABLESPACE_NAME
+#endif
+
+#if MYSQL_VERSION_ID >= 50607
+# define MRN_HANDLER_HAVE_SET_HA_SHARE_REF
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_BIG_TABLES
+#elif defined(BIG_TABLES)
+# define MRN_BIG_TABLES
+#endif
+
+#ifdef MRN_BIG_TABLES
+# define MRN_HA_ROWS_FORMAT "llu"
+#else
+# define MRN_HA_ROWS_FORMAT "lu"
+#endif
+
+#ifdef MRN_MARIADB_P
+# define MRN_NEED_FREE_STRING_MEMALLOC_PLUGIN_VAR
+#endif
+
+#ifdef MRN_MARIADB_P
+# define MRN_HAVE_HA_EXTRA_DETACH_CHILD
+# define MRN_HAVE_HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+#define MRN_HAVE_HA_EXTRA_SKIP_SERIALIZABLE_DD_VIEW
+#define MRN_HAVE_HA_EXTRA_BEGIN_ALTER_COPY
+#define MRN_HAVE_HA_EXTRA_END_ALTER_COPY
+#define MRN_HAVE_HA_EXTRA_NO_AUTOINC_LOCKING
+#endif
+
+#if MYSQL_VERSION_ID >= 50607 && \
+ (!defined(MRN_MARIADB_P) || MYSQL_VERSION_ID < 100008)
+# define MRN_HAVE_HA_EXTRA_EXPORT
+#endif
+
+#if MYSQL_VERSION_ID >= 50617 && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_HA_EXTRA_SECONDARY_SORT_ROWID
+#endif
+
+#if MYSQL_VERSION_ID >= 50604 && !defined(MRN_MARIADB_P)
+# define MRN_TIMESTAMP_USE_TIMEVAL
+#elif defined(MRN_MARIADB_P)
+# define MRN_TIMESTAMP_USE_MY_TIME_T
+#else
+# define MRN_TIMESTAMP_USE_LONG
+#endif
+
+#if MYSQL_VERSION_ID < 50600 && !defined(MRN_MARIADB_P)
+# define MRN_FIELD_STORE_TIME_NEED_TYPE
+#endif
+
+#if MYSQL_VERSION_ID < 50706 || defined(MRN_MARIADB_P)
+# define MRN_HAVE_TL_WRITE_DELAYED
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_TL_WRITE_CONCURRENT_DEFAULT
+#endif
+
+#ifdef MRN_MARIADB_P
+# define MRN_HANDLER_AUTO_REPAIR_HAVE_ERROR
+#endif
+
+#if MYSQL_VERSION_ID >= 50604
+# define MRN_JOIN_TAB_HAVE_CONDITION
+#endif
+
+#if MYSQL_VERSION_ID < 50600
+# define MRN_RBR_UPDATE_NEED_ALL_COLUMNS
+#endif
+
+#if MYSQL_VERSION_ID >= 50500
+# define MRN_ROW_BASED_CHECK_IS_METHOD
+#endif
+
+#if MYSQL_VERSION_ID >= 50600
+# define MRN_HAVE_HA_REBIND_PSI
+#endif
+
+#if MYSQL_VERSION_ID >= 50612 && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_POINT_XY
+#endif
+
+#if (defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100000)
+# define MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+#endif
+
+#if (defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100010)
+# define MRN_HAVE_TDC_LOCK_TABLE_SHARE
+# if MYSQL_VERSION_ID >= 100100
+# define MRN_TABLE_SHARE_TDC_IS_POINTER
+# endif
+#endif
+
+#ifdef MRN_MARIADB_P
+# if MYSQL_VERSION_ID >= 50542 && MYSQL_VERSION_ID < 100000
+# define MRN_SUPPORT_THDVAR_SET
+# elif MYSQL_VERSION_ID >= 100017
+# define MRN_SUPPORT_THDVAR_SET
+# endif
+#else
+# define MRN_SUPPORT_THDVAR_SET
+#endif
+
+#ifdef MRN_MARIADB_P
+# if MYSQL_VERSION_ID < 100000
+# define MRN_SUPPORT_PARTITION
+# endif
+#else
+# define MRN_SUPPORT_PARTITION
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_FLUSH_LOGS_HAVE_BINLOG_GROUP_FLUSH
+#endif
+
+#if MYSQL_VERSION_ID < 50706 || defined(MRN_MARIADB_P)
+# define MRN_HAVE_HTON_ALTER_TABLE_FLAGS
+#endif
+
+#if MYSQL_VERSION_ID >= 50706
+# define MRN_FOREIGN_KEY_USE_CONST_STRING
+#endif
+
+#if MYSQL_VERSION_ID < 50706 || defined(MRN_MARIADB_P)
+# define MRN_HANDLER_IS_FATAL_ERROR_HAVE_FLAGS
+#endif
+
+#if MYSQL_VERSION_ID < 50706 || defined(MRN_MARIADB_P)
+# define MRN_HANDLER_HAVE_RESET_AUTO_INCREMENT
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 50709) || \
+ (defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100203)
+# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_TYPE \
+ ALTER_STORED_COLUMN_TYPE
+# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_ORDER \
+ ALTER_STORED_COLUMN_ORDER
+#else
+# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_TYPE \
+ Alter_inplace_info::ALTER_COLUMN_TYPE
+# define MRN_ALTER_INPLACE_INFO_ALTER_STORED_COLUMN_ORDER \
+ Alter_inplace_info::ALTER_COLUMN_ORDER
+#endif
+
+#if MYSQL_VERSION_ID >= 50700 && !defined(MRN_MARIADB_P)
+# define MRN_HANDLER_RECORDS_RETURN_ERROR
+#endif
+
+#if MYSQL_VERSION_ID < 80002 || defined(MRN_MARIADB_P)
+# define MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+# define MRN_ST_MYSQL_PLUGIN_HAVE_CHECK_UNINSTALL
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+# define MRN_HANDLER_OPEN_HAVE_TABLE_DEFINITION
+# define MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+# define MRN_HANDLERTON_CREATE_HAVE_PARTITIONED
+#endif
+
+#if defined(HAVE_PSI_INTERFACE) && \
+ (MYSQL_VERSION_ID < 80002 || defined(MRN_MARIADB_P))
+# define MRN_HAVE_PSI_SERVER
+#endif
+
+class ha_mroonga;
+
+/* structs */
+struct st_mrn_ft_info
+{
+ struct _ft_vft *please;
+#ifdef HA_CAN_FULLTEXT_EXT
+ struct _ft_vft_ext *could_you;
+#endif
+ grn_ctx *ctx;
+ grn_encoding encoding;
+ grn_obj *table;
+ grn_obj *result;
+ grn_obj *score_column;
+ grn_obj key;
+ grn_obj score;
+ uint active_index;
+ KEY *key_info;
+ KEY *primary_key_info;
+ grn_obj *cursor;
+ grn_obj *id_accessor;
+ grn_obj *key_accessor;
+ ha_mroonga *mroonga;
+};
+
+#ifdef MRN_SUPPORT_CUSTOM_OPTIONS
+struct ha_field_option_struct
+{
+ const char *groonga_type;
+ const char *flags;
+};
+
+struct ha_index_option_struct
+{
+ const char *tokenizer;
+ const char *normalizer;
+ const char *token_filters;
+ const char *flags;
+};
+#endif
+
+/* handler class */
+class ha_mroonga: public handler
+{
+public:
+ handler *wrap_handler;
+ bool is_clone;
+ ha_mroonga *parent_for_clone;
+ MEM_ROOT *mem_root_for_clone;
+ grn_obj key_buffer;
+ grn_id record_id;
+ grn_id *key_id;
+ grn_id *del_key_id;
+ MY_BITMAP multiple_column_key_bitmap;
+
+private:
+ THR_LOCK_DATA thr_lock_data;
+
+ // for wrapper mode (TODO: need to be confirmed)
+ uint wrap_ft_init_count;
+ MRN_SHARE *share;
+ KEY *wrap_key_info;
+ KEY *base_key_info;
+ key_part_map pk_keypart_map;
+ MEM_ROOT mem_root;
+ /// for create table and alter table
+ mutable bool analyzed_for_create;
+ mutable TABLE table_for_create;
+ mutable MRN_SHARE share_for_create;
+ mutable TABLE_SHARE table_share_for_create;
+ mutable MEM_ROOT mem_root_for_create;
+ mutable handler *wrap_handler_for_create;
+#ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ handler_add_index *hnd_add_index;
+#endif
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ alter_table_operations alter_handler_flags;
+ KEY *alter_key_info_buffer;
+ uint alter_key_count;
+ uint alter_index_drop_count;
+ KEY *alter_index_drop_buffer;
+ uint alter_index_add_count;
+ uint *alter_index_add_buffer;
+ TABLE *wrap_altered_table;
+ KEY *wrap_altered_table_key_info;
+ TABLE_SHARE *wrap_altered_table_share;
+ KEY *wrap_altered_table_share_key_info;
+#else
+ KEY *wrap_alter_key_info;
+#endif
+ int mrn_lock_type;
+
+ // for groonga objects
+ grn_ctx ctx_entity_;
+ grn_ctx *ctx;
+ grn_obj *grn_table;
+ grn_obj **grn_columns;
+ grn_obj **grn_column_ranges;
+ grn_obj **grn_index_tables;
+ grn_obj **grn_index_columns;
+
+ // buffers
+ grn_obj encoded_key_buffer;
+ grn_obj old_value_buffer;
+ grn_obj new_value_buffer;
+ grn_obj top_left_point;
+ grn_obj bottom_right_point;
+ grn_obj source_point;
+ double top_left_longitude_in_degree;
+ double bottom_right_longitude_in_degree;
+ double bottom_right_latitude_in_degree;
+ double top_left_latitude_in_degree;
+
+ // for search
+ grn_obj *grn_source_column_geo;
+ grn_obj *cursor_geo;
+ grn_table_cursor *cursor;
+ grn_table_cursor *index_table_cursor;
+ grn_obj *empty_value_records;
+ grn_table_cursor *empty_value_records_cursor;
+ grn_obj *sorted_result;
+ grn_obj *matched_record_keys;
+ String *blob_buffers;
+
+ // for error report
+ uint dup_key;
+
+ // for optimization
+ bool count_skip;
+ bool fast_order_limit;
+ bool fast_order_limit_with_index;
+
+ // for context
+ bool ignoring_duplicated_key;
+ bool inserting_with_update;
+ bool fulltext_searching;
+ bool ignoring_no_key_columns;
+ bool replacing_;
+ uint written_by_row_based_binlog;
+
+ // for ft in where clause test
+ Item_func_match *current_ft_item;
+
+ mrn::Operations *operations_;
+
+public:
+ ha_mroonga(handlerton *hton, TABLE_SHARE *share_arg);
+ ~ha_mroonga();
+ const char *table_type() const; // required
+ const char *index_type(uint inx) mrn_override;
+ const char **bas_ext() const; // required
+
+ ulonglong table_flags() const mrn_override; // required
+ ulong index_flags(uint idx, uint part, bool all_parts) const mrn_override; // required
+
+ // required
+ int create(const char *name, TABLE *form, HA_CREATE_INFO *info
+#ifdef MRN_HANDLER_CREATE_HAVE_TABLE_DEFINITION
+ ,
+ dd::Table *table_def
+#endif
+ ) mrn_override;
+ // required
+ int open(const char *name, int mode, uint open_options
+#ifdef MRN_HANDLER_OPEN_HAVE_TABLE_DEFINITION
+ ,
+ const dd::Table *table_def
+#endif
+ ) mrn_override;
+#ifndef MRN_HANDLER_HAVE_HA_CLOSE
+ int close(); // required
+#endif
+ int info(uint flag) mrn_override; // required
+
+ uint lock_count() const mrn_override;
+ THR_LOCK_DATA **store_lock(THD *thd, // required
+ THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type) mrn_override;
+ int external_lock(THD *thd, int lock_type) mrn_override;
+
+ int rnd_init(bool scan) mrn_override; // required
+ int rnd_end() mrn_override;
+#ifndef MRN_HANDLER_HAVE_HA_RND_NEXT
+ int rnd_next(uchar *buf); // required
+#endif
+#ifndef MRN_HANDLER_HAVE_HA_RND_POS
+ int rnd_pos(uchar *buf, uchar *pos); // required
+#endif
+ void position(const uchar *record) mrn_override; // required
+ int extra(enum ha_extra_function operation) mrn_override;
+ int extra_opt(enum ha_extra_function operation, ulong cache_size) mrn_override;
+
+ int delete_table(const char *name) mrn_override;
+ int write_row(const uchar *buf) mrn_override;
+ int update_row(const uchar *old_data, const uchar *new_data) mrn_override;
+ int delete_row(const uchar *buf) mrn_override;
+
+ uint max_supported_record_length() const mrn_override;
+ uint max_supported_keys() const mrn_override;
+ uint max_supported_key_parts() const mrn_override;
+ uint max_supported_key_length() const mrn_override;
+ uint max_supported_key_part_length() const mrn_override;
+
+ ha_rows records_in_range(uint inx, const key_range *min_key,
+ const key_range *max_key, page_range *pages) mrn_override;
+ int index_init(uint idx, bool sorted) mrn_override;
+ int index_end() mrn_override;
+#ifndef MRN_HANDLER_HAVE_HA_INDEX_READ_MAP
+ int index_read_map(uchar * buf, const uchar * key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+#endif
+#ifdef MRN_HANDLER_HAVE_INDEX_READ_LAST_MAP
+ int index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map);
+#endif
+#ifndef MRN_HANDLER_HAVE_HA_INDEX_NEXT
+ int index_next(uchar *buf);
+#endif
+#ifndef MRN_HANDLER_HAVE_HA_INDEX_PREV
+ int index_prev(uchar *buf);
+#endif
+#ifndef MRN_HANDLER_HAVE_HA_INDEX_FIRST
+ int index_first(uchar *buf);
+#endif
+#ifndef MRN_HANDLER_HAVE_HA_INDEX_LAST
+ int index_last(uchar *buf);
+#endif
+ int index_next_same(uchar *buf, const uchar *key, uint keylen) mrn_override;
+
+ int ft_init() mrn_override;
+ FT_INFO *ft_init_ext(uint flags, uint inx, String *key) mrn_override;
+ int ft_read(uchar *buf) mrn_override;
+
+ const Item *cond_push(const Item *cond) mrn_override;
+ void cond_pop() mrn_override;
+
+ bool get_error_message(int error, String *buf) mrn_override;
+
+ int reset() mrn_override;
+
+ handler *clone(const char *name, MEM_ROOT *mem_root) mrn_override;
+ uint8 table_cache_type() mrn_override;
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ
+ ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges, uint *bufsz,
+ uint *flags, Cost_estimate *cost) mrn_override;
+ ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ uint key_parts,
+#endif
+ uint *bufsz, uint *flags, Cost_estimate *cost) mrn_override;
+ int multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf) mrn_override;
+ int multi_range_read_next(range_id_t *range_info) mrn_override;
+#else // MRN_HANDLER_HAVE_MULTI_RANGE_READ
+ int read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer);
+ int read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
+#endif // MRN_HANDLER_HAVE_MULTI_RANGE_READ
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+ void start_bulk_insert(ha_rows rows, uint flags) mrn_override;
+#else
+ void start_bulk_insert(ha_rows rows);
+#endif
+ int end_bulk_insert() mrn_override;
+ int delete_all_rows() mrn_override;
+ int truncate() mrn_override;
+ double scan_time() mrn_override;
+ double read_time(uint index, uint ranges, ha_rows rows) mrn_override;
+#ifdef MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
+ const key_map *keys_to_use_for_scanning() mrn_override;
+#endif
+ ha_rows estimate_rows_upper_bound() mrn_override;
+ void update_create_info(HA_CREATE_INFO* create_info) mrn_override;
+ int rename_table(const char *from, const char *to) mrn_override;
+ bool is_crashed() const mrn_override;
+ bool auto_repair(int error) const mrn_override;
+ bool auto_repair() const;
+ int disable_indexes(uint mode) mrn_override;
+ int enable_indexes(uint mode) mrn_override;
+ int check(THD* thd, HA_CHECK_OPT* check_opt) mrn_override;
+ int repair(THD* thd, HA_CHECK_OPT* check_opt) mrn_override;
+ bool check_and_repair(THD *thd) mrn_override;
+ int analyze(THD* thd, HA_CHECK_OPT* check_opt) mrn_override;
+ int optimize(THD* thd, HA_CHECK_OPT* check_opt) mrn_override;
+ bool is_fatal_error(int error_num, uint flags=0) mrn_override;
+ bool check_if_incompatible_data(HA_CREATE_INFO *create_info,
+ uint table_changes) mrn_override;
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ enum_alter_inplace_result
+ check_if_supported_inplace_alter(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info) mrn_override;
+#else
+ alter_table_operations alter_table_flags(alter_table_operations flags);
+# ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys,
+ handler_add_index **add);
+ int final_add_index(handler_add_index *add, bool commit);
+# else
+ int add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
+# endif
+ int prepare_drop_index(TABLE *table_arg, uint *key_num, uint num_of_keys);
+ int final_drop_index(TABLE *table_arg);
+#endif
+ int update_auto_increment();
+ void set_next_insert_id(ulonglong id);
+ void get_auto_increment(ulonglong offset, ulonglong increment, ulonglong nb_desired_values,
+ ulonglong *first_value, ulonglong *nb_reserved_values) mrn_override;
+ void restore_auto_increment(ulonglong prev_insert_id) mrn_override;
+ void release_auto_increment() mrn_override;
+ int check_for_upgrade(HA_CHECK_OPT *check_opt) mrn_override;
+#ifdef MRN_HANDLER_HAVE_RESET_AUTO_INCREMENT
+ int reset_auto_increment(ulonglong value) mrn_override;
+#endif
+ bool was_semi_consistent_read() mrn_override;
+ void try_semi_consistent_read(bool yes) mrn_override;
+ void unlock_row() mrn_override;
+ int start_stmt(THD *thd, thr_lock_type lock_type) mrn_override;
+
+protected:
+#ifdef MRN_HANDLER_RECORDS_RETURN_ERROR
+ int records(ha_rows *num_rows);
+#else
+ ha_rows records() mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_RND_NEXT
+ int rnd_next(uchar *buf) mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_RND_POS
+ int rnd_pos(uchar *buf, uchar *pos) mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_READ_MAP
+ int index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag) mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_NEXT
+ int index_next(uchar *buf) mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_PREV
+ int index_prev(uchar *buf) mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_FIRST
+ int index_first(uchar *buf) mrn_override;
+#endif
+#ifdef MRN_HANDLER_HAVE_HA_INDEX_LAST
+ int index_last(uchar *buf) mrn_override;
+#endif
+ void change_table_ptr(TABLE *table_arg, TABLE_SHARE *share_arg) mrn_override;
+ bool is_fk_defined_on_table_or_index(uint index) mrn_override;
+ char *get_foreign_key_create_info() mrn_override;
+#ifdef MRN_HANDLER_HAVE_GET_TABLESPACE_NAME
+ char *get_tablespace_name(THD *thd, char *name, uint name_len);
+#endif
+ bool can_switch_engines() mrn_override;
+ int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list) mrn_override;
+ int get_parent_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list) mrn_override;
+ uint referenced_by_foreign_key() mrn_override;
+ void init_table_handle_for_HANDLER() mrn_override;
+ void free_foreign_key_create_info(char* str) mrn_override;
+#ifdef MRN_HAVE_HA_REBIND_PSI
+ void unbind_psi() mrn_override;
+ void rebind_psi() mrn_override;
+#endif
+ my_bool register_query_cache_table(THD *thd,
+ const char *table_key,
+ uint key_length,
+ qc_engine_callback *engine_callback,
+ ulonglong *engine_data) mrn_override;
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ bool prepare_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info) mrn_override;
+ bool inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info) mrn_override;
+ bool commit_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info,
+ bool commit) mrn_override;
+#endif
+
+private:
+ void mkdir_p(const char *directory);
+ ulonglong file_size(const char *path);
+
+ bool have_unique_index();
+
+ bool is_foreign_key_field(const char *table_name,
+ const char *field_name);
+
+ void push_warning_unsupported_spatial_index_search(enum ha_rkey_function flag);
+ void clear_cursor();
+ void clear_cursor_geo();
+ void clear_empty_value_records();
+ void clear_search_result();
+ void clear_search_result_geo();
+ void clear_indexes();
+ int add_wrap_hton(const char *path, handlerton *wrap_handlerton);
+ void remove_related_files(const char *base_path);
+ void remove_grn_obj_force(const char *name);
+ int drop_index(MRN_SHARE *target_share, uint key_index);
+ int drop_indexes_normal(const char *table_name, grn_obj *table);
+ int drop_indexes_multiple(const char *table_name, grn_obj *table,
+ const char *index_table_name_separator);
+ int drop_indexes(const char *table_name);
+ bool find_column_flags(Field *field, MRN_SHARE *mrn_share, int i,
+ grn_obj_flags *column_flags);
+ grn_obj *find_column_type(Field *field, MRN_SHARE *mrn_share, int i,
+ int error_code);
+ grn_obj *find_tokenizer(KEY *key, MRN_SHARE *mrn_share, int i);
+ grn_obj *find_tokenizer(const char *name, int name_length);
+ bool have_custom_normalizer(KEY *key) const;
+ grn_obj *find_normalizer(KEY *key);
+ grn_obj *find_normalizer(KEY *key, const char *name);
+ bool find_index_column_flags(KEY *key, grn_column_flags *index_column_flags);
+ bool find_token_filters(KEY *key, grn_obj *token_filters);
+ bool find_token_filters_put(grn_obj *token_filters,
+ const char *token_filter_name,
+ int token_filter_name_length);
+ bool find_token_filters_fill(grn_obj *token_filters,
+ const char *token_filter_names,
+ int token_filter_name_length);
+ int wrapper_get_record(uchar *buf, const uchar *key);
+ int wrapper_get_next_geo_record(uchar *buf);
+ int storage_get_next_record(uchar *buf);
+ void geo_store_rectangle(const uchar *rectangle);
+ int generic_geo_open_cursor(const uchar *key, enum ha_rkey_function find_flag);
+
+#ifdef MRN_HANDLER_HAVE_HA_CLOSE
+ int close() mrn_override;
+#endif
+ bool is_dry_write();
+ bool is_enable_optimization();
+ bool should_normalize(Field *field) const;
+ void check_count_skip(key_part_map target_key_part_map);
+ bool is_grn_zero_column_value(grn_obj *column, grn_obj *value);
+ bool is_primary_key_field(Field *field) const;
+ void check_fast_order_limit(grn_table_sort_key **sort_keys, int *n_sort_keys,
+ longlong *limit);
+
+ long long int get_grn_time_from_timestamp_field(Field_timestamp *field);
+
+ int generic_store_bulk_fixed_size_string(Field *field, grn_obj *buf);
+ int generic_store_bulk_variable_size_string(Field *field, grn_obj *buf);
+ int generic_store_bulk_integer(Field *field, grn_obj *buf);
+ int generic_store_bulk_unsigned_integer(Field *field, grn_obj *buf);
+ int generic_store_bulk_float(Field *field, grn_obj *buf);
+ int generic_store_bulk_timestamp(Field *field, grn_obj *buf);
+ int generic_store_bulk_date(Field *field, grn_obj *buf);
+ int generic_store_bulk_time(Field *field, grn_obj *buf);
+ int generic_store_bulk_datetime(Field *field, grn_obj *buf);
+ int generic_store_bulk_year(Field *field, grn_obj *buf);
+ int generic_store_bulk_new_date(Field *field, grn_obj *buf);
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ int generic_store_bulk_datetime2(Field *field, grn_obj *buf);
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ int generic_store_bulk_time2(Field *field, grn_obj *buf);
+#endif
+ int generic_store_bulk_new_decimal(Field *field, grn_obj *buf);
+ int generic_store_bulk_blob(Field *field, grn_obj *buf);
+ int generic_store_bulk_geometry(Field *field, grn_obj *buf);
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ int generic_store_bulk_json(Field *field, grn_obj *buf);
+#endif
+ int generic_store_bulk(Field *field, grn_obj *buf);
+
+ void storage_store_field_string(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_integer(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_unsigned_integer(Field *field,
+ const char *value,
+ uint value_length);
+ void storage_store_field_float(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_timestamp(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_date(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_time(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_datetime(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_year(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_new_date(Field *field,
+ const char *value, uint value_length);
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ void storage_store_field_datetime2(Field *field,
+ const char *value, uint value_length);
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ void storage_store_field_time2(Field *field,
+ const char *value, uint value_length);
+#endif
+ void storage_store_field_blob(Field *field,
+ const char *value, uint value_length);
+ void storage_store_field_geometry(Field *field,
+ const char *value, uint value_length);
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ void storage_store_field_json(Field *field,
+ const char *value, uint value_length);
+#endif
+ void storage_store_field(Field *field, const char *value, uint value_length);
+ void storage_store_field_column(Field *field, bool is_primary_key,
+ int nth_column, grn_id record_id);
+ void storage_store_fields(uchar *buf, grn_id record_id);
+ void storage_store_fields_for_prep_update(const uchar *old_data,
+ const uchar *new_data,
+ grn_id record_id);
+ void storage_store_fields_by_index(uchar *buf);
+
+ int storage_encode_key_normalize_min_sort_chars(Field *field,
+ uchar *buf,
+ uint size);
+ int storage_encode_key_fixed_size_string(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key_variable_size_string(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key_timestamp(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key_time(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key_year(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key_datetime(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+#ifdef MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+ int storage_encode_key_timestamp2(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ int storage_encode_key_datetime2(Field *field, bool is_null, const uchar *key,
+ uchar *buf, uint *size);
+#endif
+#ifdef MRN_HAVE_MYSQL_TYPE_TIME2
+ int storage_encode_key_time2(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+#endif
+ int storage_encode_key_enum(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key_set(Field *field, const uchar *key,
+ uchar *buf, uint *size);
+ int storage_encode_key(Field *field, const uchar *key, uchar *buf, uint *size);
+ int storage_encode_multiple_column_key(KEY *key_info,
+ const uchar *key, uint key_length,
+ uchar *buffer, uint *encoded_length);
+ int storage_encode_multiple_column_key_range(KEY *key_info,
+ const uchar *start,
+ uint start_size,
+ const uchar *end,
+ uint end_size,
+ uchar *min_buffer,
+ uint *min_encoded_size,
+ uchar *max_buffer,
+ uint *max_encoded_size);
+ int storage_encode_multiple_column_key_range(KEY *key_info,
+ const key_range *start,
+ const key_range *end,
+ uchar *min_buffer,
+ uint *min_encoded_size,
+ uchar *max_buffer,
+ uint *max_encoded_size);
+
+ void set_pk_bitmap();
+ int create_share_for_create() const;
+ int wrapper_create(const char *name, TABLE *table,
+ HA_CREATE_INFO *info, MRN_SHARE *tmp_share);
+ int storage_create(const char *name, TABLE *table,
+ HA_CREATE_INFO *info, MRN_SHARE *tmp_share);
+ int wrapper_create_index_fulltext_validate(KEY *key_info);
+ int wrapper_create_index_fulltext(const char *grn_table_name,
+ int i,
+ KEY *key_info,
+ grn_obj **index_tables,
+ grn_obj **index_columns,
+ MRN_SHARE *tmp_share);
+ int wrapper_create_index_geo(const char *grn_table_name,
+ int i,
+ KEY *key_info,
+ grn_obj **index_tables,
+ grn_obj **index_columns,
+ MRN_SHARE *tmp_share);
+ int wrapper_create_index(const char *name, TABLE *table, MRN_SHARE *tmp_share);
+ int storage_create_validate_pseudo_column(TABLE *table);
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+ bool storage_create_foreign_key(TABLE *table, const char *grn_table_name,
+ Field *field, grn_obj *table_obj, int &error);
+#endif
+ int storage_create_validate_index(TABLE *table);
+ int storage_create_index_table(TABLE *table, const char *grn_table_name,
+ grn_obj *grn_table, MRN_SHARE *tmp_share,
+ KEY *key_info, grn_obj **index_tables,
+ uint i);
+ int storage_create_index(TABLE *table, const char *grn_table_name,
+ grn_obj *grn_table, MRN_SHARE *tmp_share,
+ KEY *key_info, grn_obj **index_tables,
+ grn_obj **index_columns, uint i);
+ int storage_create_indexes(TABLE *table, const char *grn_table_name,
+ grn_obj *grn_table, MRN_SHARE *tmp_share);
+ int close_databases();
+ int ensure_database_open(const char *name, mrn::Database **db=NULL);
+ int ensure_database_remove(const char *name);
+ int wrapper_delete_table(const char *name, handlerton *wrap_handlerton,
+ const char *table_name);
+ int generic_delete_table(const char *name, const char *table_name);
+ int wrapper_open(const char *name, int mode, uint open_options);
+ int wrapper_open_indexes(const char *name);
+ int storage_reindex();
+ int storage_open(const char *name, int mode, uint open_options);
+ int open_table(const char *name);
+ int storage_open_columns(void);
+ void storage_close_columns(void);
+ int storage_open_indexes(const char *name);
+ void wrapper_overwrite_index_bits();
+ int wrapper_close();
+ int storage_close();
+ int generic_extra(enum ha_extra_function operation);
+ int wrapper_extra(enum ha_extra_function operation);
+ int storage_extra(enum ha_extra_function operation);
+ int wrapper_extra_opt(enum ha_extra_function operation, ulong cache_size);
+ int storage_extra_opt(enum ha_extra_function operation, ulong cache_size);
+ int generic_reset();
+ int wrapper_reset();
+ int storage_reset();
+ uint wrapper_lock_count() const;
+ uint storage_lock_count() const;
+ THR_LOCK_DATA **wrapper_store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+ THR_LOCK_DATA **storage_store_lock(THD *thd, THR_LOCK_DATA **to,
+ enum thr_lock_type lock_type);
+ int wrapper_external_lock(THD *thd, int lock_type);
+ int storage_external_lock(THD *thd, int lock_type);
+#ifdef MRN_HANDLER_START_BULK_INSERT_HAS_FLAGS
+ void wrapper_start_bulk_insert(ha_rows rows, uint flags);
+ void storage_start_bulk_insert(ha_rows rows, uint flags);
+#else
+ void wrapper_start_bulk_insert(ha_rows rows);
+ void storage_start_bulk_insert(ha_rows rows);
+#endif
+ int wrapper_end_bulk_insert();
+ int storage_end_bulk_insert();
+ bool wrapper_is_target_index(KEY *key_info);
+ bool wrapper_have_target_index();
+ int wrapper_write_row(const uchar *buf);
+ int wrapper_write_row_index(const uchar *buf);
+ int storage_write_row(const uchar *buf);
+ int storage_write_row_multiple_column_index(const uchar *buf,
+ grn_id record_id,
+ KEY *key_info,
+ grn_obj *index_column);
+ int storage_write_row_multiple_column_indexes(const uchar *buf, grn_id record_id);
+ int storage_write_row_unique_index(const uchar *buf,
+ KEY *key_info,
+ grn_obj *index_table,
+ grn_obj *index_column,
+ grn_id *key_id);
+ int storage_write_row_unique_indexes(const uchar *buf);
+ int wrapper_get_record_id(uchar *data, grn_id *record_id,
+ const char *context);
+ int wrapper_update_row(const uchar *old_data, const uchar *new_data);
+ int wrapper_update_row_index(const uchar *old_data,
+ const uchar *new_data);
+ int storage_update_row(const uchar *old_data, const uchar *new_data);
+ int storage_update_row_index(const uchar *old_data,
+ const uchar *new_data);
+ int storage_update_row_unique_indexes(const uchar *new_data);
+ int wrapper_delete_row(const uchar *buf);
+ int wrapper_delete_row_index(const uchar *buf);
+ int storage_delete_row(const uchar *buf);
+ int storage_delete_row_index(const uchar *buf);
+ int storage_delete_row_unique_index(grn_obj *index_table, grn_id del_key_id);
+ int storage_delete_row_unique_indexes();
+ int storage_prepare_delete_row_unique_index(const uchar *buf,
+ grn_id record_id,
+ KEY *key_info,
+ grn_obj *index_table,
+ grn_obj *index_column,
+ grn_id *del_key_id);
+ int storage_prepare_delete_row_unique_indexes(const uchar *buf,
+ grn_id record_id);
+ uint wrapper_max_supported_record_length() const;
+ uint storage_max_supported_record_length() const;
+ uint wrapper_max_supported_keys() const;
+ uint storage_max_supported_keys() const;
+ uint wrapper_max_supported_key_parts() const;
+ uint storage_max_supported_key_parts() const;
+ uint wrapper_max_supported_key_length() const;
+ uint storage_max_supported_key_length() const;
+ uint wrapper_max_supported_key_part_length() const;
+ uint storage_max_supported_key_part_length() const;
+ ulonglong wrapper_table_flags() const;
+ ulonglong storage_table_flags() const;
+ ulong wrapper_index_flags(uint idx, uint part, bool all_parts) const;
+ ulong storage_index_flags(uint idx, uint part, bool all_parts) const;
+ int wrapper_info(uint flag);
+ int storage_info(uint flag);
+ void storage_info_variable();
+ void storage_info_variable_records();
+ void storage_info_variable_data_file_length();
+#ifdef MRN_HANDLER_RECORDS_RETURN_ERROR
+ int wrapper_records(ha_rows *num_rows);
+ int storage_records(ha_rows *num_rows);
+#else
+ ha_rows wrapper_records();
+ ha_rows storage_records();
+#endif
+ int wrapper_rnd_init(bool scan);
+ int storage_rnd_init(bool scan);
+ int wrapper_rnd_end();
+ int storage_rnd_end();
+ int wrapper_rnd_next(uchar *buf);
+ int storage_rnd_next(uchar *buf);
+ int wrapper_rnd_pos(uchar *buf, uchar *pos);
+ int storage_rnd_pos(uchar *buf, uchar *pos);
+ void wrapper_position(const uchar *record);
+ void storage_position(const uchar *record);
+ ha_rows wrapper_records_in_range(uint key_nr, const key_range *range_min,
+ const key_range *range_max,
+ page_range *pages);
+ ha_rows storage_records_in_range(uint key_nr, const key_range *range_min,
+ const key_range *range_max,
+ page_range *pages);
+ ha_rows generic_records_in_range_geo(uint key_nr, const key_range *range_min,
+ const key_range *range_max);
+ int wrapper_index_init(uint idx, bool sorted);
+ int storage_index_init(uint idx, bool sorted);
+ int wrapper_index_end();
+ int storage_index_end();
+ int wrapper_index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+ int storage_index_read_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map,
+ enum ha_rkey_function find_flag);
+#ifdef MRN_HANDLER_HAVE_INDEX_READ_LAST_MAP
+ int wrapper_index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map);
+ int storage_index_read_last_map(uchar *buf, const uchar *key,
+ key_part_map keypart_map);
+#endif
+ int wrapper_index_next(uchar *buf);
+ int storage_index_next(uchar *buf);
+ int wrapper_index_prev(uchar *buf);
+ int storage_index_prev(uchar *buf);
+ int wrapper_index_first(uchar *buf);
+ int storage_index_first(uchar *buf);
+ int wrapper_index_last(uchar *buf);
+ int storage_index_last(uchar *buf);
+ int wrapper_index_next_same(uchar *buf, const uchar *key, uint keylen);
+ int storage_index_next_same(uchar *buf, const uchar *key, uint keylen);
+ int generic_ft_init();
+ int wrapper_ft_init();
+ int storage_ft_init();
+ FT_INFO *wrapper_ft_init_ext(uint flags, uint key_nr, String *key);
+ FT_INFO *storage_ft_init_ext(uint flags, uint key_nr, String *key);
+ void generic_ft_init_ext_add_conditions_fast_order_limit(
+ struct st_mrn_ft_info *info, grn_obj *expression);
+ grn_rc generic_ft_init_ext_prepare_expression_in_boolean_mode(
+ struct st_mrn_ft_info *info,
+ String *key,
+ grn_obj *index_column,
+ grn_obj *match_columns,
+ grn_obj *expression);
+ grn_rc generic_ft_init_ext_prepare_expression_in_normal_mode(
+ struct st_mrn_ft_info *info,
+ String *key,
+ grn_obj *index_column,
+ grn_obj *match_columns,
+ grn_obj *expression);
+ struct st_mrn_ft_info *generic_ft_init_ext_select(uint flags,
+ uint key_nr,
+ String *key);
+ FT_INFO *generic_ft_init_ext(uint flags, uint key_nr, String *key);
+ int wrapper_ft_read(uchar *buf);
+ int storage_ft_read(uchar *buf);
+ const Item *wrapper_cond_push(const Item *cond);
+ const Item *storage_cond_push(const Item *cond);
+ void wrapper_cond_pop();
+ void storage_cond_pop();
+ bool wrapper_get_error_message(int error, String *buf);
+ bool storage_get_error_message(int error, String *buf);
+ handler *wrapper_clone(const char *name, MEM_ROOT *mem_root);
+ handler *storage_clone(const char *name, MEM_ROOT *mem_root);
+ uint8 wrapper_table_cache_type();
+ uint8 storage_table_cache_type();
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ
+ ha_rows wrapper_multi_range_read_info_const(uint keyno,
+ RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges,
+ uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost);
+ ha_rows storage_multi_range_read_info_const(uint keyno,
+ RANGE_SEQ_IF *seq,
+ void *seq_init_param,
+ uint n_ranges,
+ uint *bufsz,
+ uint *flags,
+ Cost_estimate *cost);
+ ha_rows wrapper_multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ uint key_parts,
+#endif
+ uint *bufsz, uint *flags,
+ Cost_estimate *cost);
+ ha_rows storage_multi_range_read_info(uint keyno, uint n_ranges, uint keys,
+#ifdef MRN_HANDLER_HAVE_MULTI_RANGE_READ_INFO_KEY_PARTS
+ uint key_parts,
+#endif
+ uint *bufsz, uint *flags,
+ Cost_estimate *cost);
+ int wrapper_multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf);
+ int storage_multi_range_read_init(RANGE_SEQ_IF *seq, void *seq_init_param,
+ uint n_ranges, uint mode,
+ HANDLER_BUFFER *buf);
+ int wrapper_multi_range_read_next(range_id_t *range_info);
+ int storage_multi_range_read_next(range_id_t *range_info);
+#else // MRN_HANDLER_HAVE_MULTI_RANGE_READ
+ int wrapper_read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer);
+ int storage_read_multi_range_first(KEY_MULTI_RANGE **found_range_p,
+ KEY_MULTI_RANGE *ranges,
+ uint range_count,
+ bool sorted,
+ HANDLER_BUFFER *buffer);
+ int wrapper_read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
+ int storage_read_multi_range_next(KEY_MULTI_RANGE **found_range_p);
+#endif // MRN_HANDLER_HAVE_MULTI_RANGE_READ
+ int generic_delete_all_rows(grn_obj *target_grn_table,
+ const char *function_name);
+ int wrapper_delete_all_rows();
+ int storage_delete_all_rows();
+ int wrapper_truncate();
+ int wrapper_truncate_index();
+ int storage_truncate();
+ int storage_truncate_index();
+ double wrapper_scan_time();
+ double storage_scan_time();
+ double wrapper_read_time(uint index, uint ranges, ha_rows rows);
+ double storage_read_time(uint index, uint ranges, ha_rows rows);
+#ifdef MRN_HANDLER_HAVE_KEYS_TO_USE_FOR_SCANNING
+ const key_map *wrapper_keys_to_use_for_scanning();
+ const key_map *storage_keys_to_use_for_scanning();
+#endif
+ ha_rows wrapper_estimate_rows_upper_bound();
+ ha_rows storage_estimate_rows_upper_bound();
+ void wrapper_update_create_info(HA_CREATE_INFO* create_info);
+ void storage_update_create_info(HA_CREATE_INFO* create_info);
+ int wrapper_rename_table(const char *from, const char *to,
+ MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name);
+ int wrapper_rename_index(const char *from, const char *to,
+ MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name);
+ int storage_rename_table(const char *from, const char *to,
+ MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name);
+#ifdef MRN_SUPPORT_FOREIGN_KEYS
+ int storage_rename_foreign_key(MRN_SHARE *tmp_share,
+ const char *from_table_name,
+ const char *to_table_name);
+#endif
+ bool wrapper_is_crashed() const;
+ bool storage_is_crashed() const;
+ bool wrapper_auto_repair(int error) const;
+ bool storage_auto_repair(int error) const;
+ int generic_disable_index(int i, KEY *key_info);
+ int wrapper_disable_indexes_mroonga(uint mode);
+ int wrapper_disable_indexes(uint mode);
+ int storage_disable_indexes(uint mode);
+ int wrapper_enable_indexes_mroonga(uint mode);
+ int wrapper_enable_indexes(uint mode);
+ int storage_enable_indexes(uint mode);
+ int wrapper_check(THD* thd, HA_CHECK_OPT* check_opt);
+ int storage_check(THD* thd, HA_CHECK_OPT* check_opt);
+ int wrapper_fill_indexes(THD *thd, KEY *key_info,
+ grn_obj **index_columns, uint n_keys);
+ int wrapper_recreate_indexes(THD *thd);
+ int storage_recreate_indexes(THD *thd);
+ int wrapper_repair(THD* thd, HA_CHECK_OPT* check_opt);
+ int storage_repair(THD* thd, HA_CHECK_OPT* check_opt);
+ bool wrapper_check_and_repair(THD *thd);
+ bool storage_check_and_repair(THD *thd);
+ int wrapper_analyze(THD* thd, HA_CHECK_OPT* check_opt);
+ int storage_analyze(THD* thd, HA_CHECK_OPT* check_opt);
+ int wrapper_optimize(THD* thd, HA_CHECK_OPT* check_opt);
+ int storage_optimize(THD* thd, HA_CHECK_OPT* check_opt);
+ bool wrapper_is_fatal_error(int error_num, uint flags);
+ bool storage_is_fatal_error(int error_num, uint flags);
+ bool wrapper_is_comment_changed(TABLE *table1, TABLE *table2);
+ bool wrapper_check_if_incompatible_data(HA_CREATE_INFO *create_info,
+ uint table_changes);
+ bool storage_check_if_incompatible_data(HA_CREATE_INFO *create_info,
+ uint table_changes);
+ int storage_add_index_multiple_columns(KEY *key_info, uint num_of_keys,
+ grn_obj **index_tables,
+ grn_obj **index_columns,
+ bool skip_unique_key);
+#ifdef MRN_HANDLER_HAVE_CHECK_IF_SUPPORTED_INPLACE_ALTER
+ enum_alter_inplace_result
+ wrapper_check_if_supported_inplace_alter(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ enum_alter_inplace_result
+ storage_check_if_supported_inplace_alter(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool wrapper_prepare_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_prepare_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool wrapper_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_inplace_alter_table_add_index(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_inplace_alter_table_drop_index(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_inplace_alter_table_add_column(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_inplace_alter_table_drop_column(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_inplace_alter_table_rename_column(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool storage_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info);
+ bool wrapper_commit_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info,
+ bool commit);
+ bool storage_commit_inplace_alter_table(TABLE *altered_table,
+ Alter_inplace_info *ha_alter_info,
+ bool commit);
+#else
+ alter_table_operations wrapper_alter_table_flags(alter_table_operations flags);
+ alter_table_operations storage_alter_table_flags(alter_table_operations flags);
+# ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ int wrapper_add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys,
+ handler_add_index **add);
+ int storage_add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys,
+ handler_add_index **add);
+# else
+ int wrapper_add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
+ int storage_add_index(TABLE *table_arg, KEY *key_info, uint num_of_keys);
+# endif
+# ifdef MRN_HANDLER_HAVE_FINAL_ADD_INDEX
+ int wrapper_final_add_index(handler_add_index *add, bool commit);
+ int storage_final_add_index(handler_add_index *add, bool commit);
+# endif
+ int wrapper_prepare_drop_index(TABLE *table_arg, uint *key_num,
+ uint num_of_keys);
+ int storage_prepare_drop_index(TABLE *table_arg, uint *key_num,
+ uint num_of_keys);
+ int wrapper_final_drop_index(TABLE *table_arg);
+ int storage_final_drop_index(TABLE *table_arg);
+#endif
+ int wrapper_update_auto_increment();
+ int storage_update_auto_increment();
+ void wrapper_set_next_insert_id(ulonglong id);
+ void storage_set_next_insert_id(ulonglong id);
+ void wrapper_get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
+ void storage_get_auto_increment(ulonglong offset, ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong *first_value,
+ ulonglong *nb_reserved_values);
+ void wrapper_restore_auto_increment(ulonglong prev_insert_id);
+ void storage_restore_auto_increment(ulonglong prev_insert_id);
+ void wrapper_release_auto_increment();
+ void storage_release_auto_increment();
+ int wrapper_check_for_upgrade(HA_CHECK_OPT *check_opt);
+ int storage_check_for_upgrade(HA_CHECK_OPT *check_opt);
+#ifdef MRN_HANDLER_HAVE_RESET_AUTO_INCREMENT
+ int wrapper_reset_auto_increment(ulonglong value);
+ int storage_reset_auto_increment(ulonglong value);
+#endif
+ bool wrapper_was_semi_consistent_read();
+ bool storage_was_semi_consistent_read();
+ void wrapper_try_semi_consistent_read(bool yes);
+ void storage_try_semi_consistent_read(bool yes);
+ void wrapper_unlock_row();
+ void storage_unlock_row();
+ int wrapper_start_stmt(THD *thd, thr_lock_type lock_type);
+ int storage_start_stmt(THD *thd, thr_lock_type lock_type);
+ void wrapper_change_table_ptr(TABLE *table_arg, TABLE_SHARE *share_arg);
+ void storage_change_table_ptr(TABLE *table_arg, TABLE_SHARE *share_arg);
+ bool wrapper_is_fk_defined_on_table_or_index(uint index);
+ bool storage_is_fk_defined_on_table_or_index(uint index);
+ char *wrapper_get_foreign_key_create_info();
+ char *storage_get_foreign_key_create_info();
+#ifdef MRN_HANDLER_HAVE_GET_TABLESPACE_NAME
+ char *wrapper_get_tablespace_name(THD *thd, char *name, uint name_len);
+ char *storage_get_tablespace_name(THD *thd, char *name, uint name_len);
+#endif
+ bool wrapper_can_switch_engines();
+ bool storage_can_switch_engines();
+ int wrapper_get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
+ int storage_get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
+ int wrapper_get_parent_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
+ int storage_get_parent_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
+ uint wrapper_referenced_by_foreign_key();
+ uint storage_referenced_by_foreign_key();
+ void wrapper_init_table_handle_for_HANDLER();
+ void storage_init_table_handle_for_HANDLER();
+ void wrapper_free_foreign_key_create_info(char* str);
+ void storage_free_foreign_key_create_info(char* str);
+ void wrapper_set_keys_in_use();
+ void storage_set_keys_in_use();
+#ifdef MRN_RBR_UPDATE_NEED_ALL_COLUMNS
+ bool check_written_by_row_based_binlog();
+#endif
+#ifdef MRN_HAVE_HA_REBIND_PSI
+ void wrapper_unbind_psi();
+ void storage_unbind_psi();
+ void wrapper_rebind();
+ void storage_rebind();
+#endif
+ my_bool wrapper_register_query_cache_table(THD *thd,
+ const char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data);
+ my_bool storage_register_query_cache_table(THD *thd,
+ const char *table_key,
+ uint key_length,
+ qc_engine_callback
+ *engine_callback,
+ ulonglong *engine_data);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HA_MROONGA_HPP_ */
diff --git a/storage/mroonga/lib/Makefile.am b/storage/mroonga/lib/Makefile.am
new file mode 100644
index 00000000..300131db
--- /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 00000000..e8c03c63
--- /dev/null
+++ b/storage/mroonga/lib/libmrn_need_mysql_sources.am
@@ -0,0 +1,50 @@
+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 \
+ mrn_database_manager.cpp \
+ mrn_database_manager.hpp \
+ mrn_value_decoder.cpp \
+ mrn_value_decoder.hpp \
+ mrn_database_repairer.cpp \
+ mrn_database_repairer.hpp \
+ mrn_context_pool.cpp \
+ mrn_context_pool.hpp \
+ mrn_operations.cpp \
+ mrn_operations.hpp \
+ mrn_operation.cpp \
+ mrn_operation.hpp \
+ mrn_database.cpp \
+ mrn_database.hpp \
+ mrn_column_name.cpp \
+ mrn_column_name.hpp \
+ mrn_count_skip_checker.cpp \
+ mrn_count_skip_checker.hpp \
+ mrn_query_parser.cpp \
+ mrn_query_parser.hpp \
+ mrn_current_thread.hpp \
+ mrn_smart_bitmap.cpp \
+ mrn_smart_bitmap.hpp \
+ mrn_table_fields_offset_mover.cpp \
+ mrn_table_fields_offset_mover.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 00000000..fd2d942d
--- /dev/null
+++ b/storage/mroonga/lib/libmrn_no_mysql_sources.am
@@ -0,0 +1,9 @@
+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 \
+ mrn_grn.hpp
diff --git a/storage/mroonga/lib/libmysqlservices_compat_sources.am b/storage/mroonga/lib/libmysqlservices_compat_sources.am
new file mode 100644
index 00000000..bb0712a4
--- /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 00000000..4baef101
--- /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-1335 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 00000000..ed2f9f3c
--- /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-1335 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_column_name.cpp b/storage/mroonga/lib/mrn_column_name.cpp
new file mode 100644
index 00000000..173553dd
--- /dev/null
+++ b/storage/mroonga/lib/mrn_column_name.cpp
@@ -0,0 +1,69 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+#include "mrn_column_name.hpp"
+
+#include <strfunc.h>
+
+#include <string.h>
+
+// for debug
+#define MRN_CLASS_NAME "mrn::ColumnName"
+
+namespace mrn {
+ ColumnName::ColumnName(const char *mysql_name)
+ : mysql_name_(mysql_name) {
+ encode(mysql_name, strlen(mysql_name));
+ }
+
+ ColumnName::ColumnName(const LEX_CSTRING &mysql_name)
+ : mysql_name_(mysql_name.str) {
+ encode(mysql_name.str, mysql_name.length);
+ }
+
+ const char *ColumnName::mysql_name() {
+ return mysql_name_;
+ }
+
+ const char *ColumnName::c_str() {
+ return name_;
+ }
+
+ size_t ColumnName::length() {
+ return length_;
+ }
+
+ void ColumnName::encode(const char *mysql_name,
+ size_t mysql_name_length) {
+ MRN_DBUG_ENTER_METHOD();
+ uint errors;
+ length_ = mrn_strconvert(system_charset_info,
+ mysql_name,
+ mysql_name_length,
+ &my_charset_filename,
+ name_,
+ MRN_MAX_PATH_SIZE,
+ &errors);
+ name_[length_] = '\0';
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_column_name.hpp b/storage/mroonga/lib/mrn_column_name.hpp
new file mode 100644
index 00000000..abd4bf54
--- /dev/null
+++ b/storage/mroonga/lib/mrn_column_name.hpp
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 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-1335 USA
+*/
+
+#pragma once
+
+#include <mrn_constants.hpp>
+
+namespace mrn {
+ class ColumnName {
+ public:
+ ColumnName(const char *mysql_name);
+ ColumnName(const LEX_CSTRING &mysql_name);
+ const char *mysql_name();
+ const char *c_str();
+ size_t length();
+ private:
+ const char *mysql_name_;
+ char name_[MRN_MAX_PATH_SIZE];
+ size_t length_;
+
+ void encode(const char *mysql_name, size_t mysql_name_length);
+ };
+}
diff --git a/storage/mroonga/lib/mrn_condition_converter.cpp b/storage/mroonga/lib/mrn_condition_converter.cpp
new file mode 100644
index 00000000..761dfc72
--- /dev/null
+++ b/storage/mroonga/lib/mrn_condition_converter.cpp
@@ -0,0 +1,637 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 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-1335 USA
+*/
+
+#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.str)
+# define MRN_ITEM_FIELD_GET_NAME_LENGTH(item) ((item)->name.length)
+#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->real_type();
+ NormalizedType normalized_type = normalize_field_type(field_type);
+ switch (normalized_type) {
+ case STRING_TYPE:
+ if (value_item->is_of_type(Item::CONST_ITEM, STRING_RESULT) &&
+ func_type == Item_func::EQ_FUNC) {
+ convertable = have_index(field_item, GRN_OP_EQUAL);
+ }
+ break;
+ case INT_TYPE:
+ if (field_type == MYSQL_TYPE_ENUM) {
+ convertable = value_item->is_of_type(Item::CONST_ITEM, STRING_RESULT) ||
+ value_item->is_of_type(Item::CONST_ITEM, INT_RESULT);
+ } else {
+ convertable = value_item->is_of_type(Item::CONST_ITEM, INT_RESULT);
+ }
+ 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->is_of_type(Item::CONST_ITEM, STRING_RESULT) &&
+ max_item->is_of_type(Item::CONST_ITEM, STRING_RESULT)) {
+ convertable = have_index(field_item, GRN_OP_LESS);
+ }
+ break;
+ case INT_TYPE:
+ if (min_item->is_of_type(Item::CONST_ITEM, INT_RESULT) &&
+ max_item->is_of_type(Item::CONST_ITEM, INT_RESULT)) {
+ 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:
+ {
+ THD *thd= current_thd;
+ error= real_value_item->get_date(thd, mysql_time, Time::Options(thd));
+ 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:
+ {
+ THD *thd= current_thd;
+ Datetime::Options opt(TIME_FUZZY_DATES, thd);
+ error = real_value_item->get_date(thd, mysql_time, opt);
+ 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;
+ case MYSQL_TYPE_VARCHAR_COMPRESSED:
+ case MYSQL_TYPE_BLOB_COMPRESSED:
+ DBUG_ASSERT(0);
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ case MYSQL_TYPE_JSON:
+ type = STRING_TYPE;
+ break;
+#endif
+ }
+
+ 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);
+ }
+
+ unsigned int ConditionConverter::count_match_against(const Item *item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!item) {
+ DBUG_RETURN(0);
+ }
+
+ 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) {
+ unsigned int n_match_againsts = 0;
+ List_iterator<Item> iterator(*((cond_item)->argument_list()));
+ const Item *sub_item;
+ while ((sub_item = iterator++)) {
+ n_match_againsts += count_match_against(sub_item);
+ }
+ DBUG_RETURN(n_match_againsts);
+ }
+ }
+ 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(1);
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ DBUG_RETURN(0);
+ }
+
+ 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->real_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);
+ if (field_type == MYSQL_TYPE_ENUM) {
+ if (const_item->is_of_type(Item::CONST_ITEM, STRING_RESULT)) {
+ String *string;
+ string = const_item->val_str(NULL);
+ Field_enum *enum_field = static_cast<Field_enum *>(field_item->field);
+ int enum_value = find_type(string->c_ptr(),
+ enum_field->typelib,
+ FIND_TYPE_BASIC);
+ GRN_INT64_SET(ctx_, &value_, enum_value);
+ } else {
+ GRN_INT64_SET(ctx_, &value_, const_item->val_int());
+ }
+ } else {
+ 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 00000000..bf10001d
--- /dev/null
+++ b/storage/mroonga/lib/mrn_condition_converter.hpp
@@ -0,0 +1,85 @@
+/* -*- 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-1335 USA
+*/
+
+#ifndef MRN_CONDITION_CONVERTER_HPP_
+#define MRN_CONDITION_CONVERTER_HPP_
+
+#include <mrn_mysql_compat.h>
+
+#include <item_cmpfunc.h>
+
+#include <groonga.h>
+
+namespace mrn {
+ class ConditionConverter {
+ public:
+ ConditionConverter(grn_ctx *ctx, grn_obj *table, bool is_storage_mode);
+ ~ConditionConverter();
+
+ bool is_convertable(const Item *item);
+ unsigned int count_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_context_pool.cpp b/storage/mroonga/lib/mrn_context_pool.cpp
new file mode 100644
index 00000000..bbc239da
--- /dev/null
+++ b/storage/mroonga/lib/mrn_context_pool.cpp
@@ -0,0 +1,120 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#include "mrn_context_pool.hpp"
+#include "mrn_lock.hpp"
+
+#include <time.h>
+
+namespace mrn {
+ // for debug
+#define MRN_CLASS_NAME "mrn::ContextPool::Impl"
+
+ class ContextPool::Impl {
+ public:
+ Impl(mysql_mutex_t *mutex)
+ : mutex_(mutex),
+ pool_(NULL),
+ last_pull_time_(0) {
+ }
+
+ ~Impl(void) {
+ clear();
+ }
+
+ grn_ctx *pull(void) {
+ MRN_DBUG_ENTER_METHOD();
+ grn_ctx *ctx = NULL;
+
+ {
+ time_t now;
+ time(&now);
+
+ mrn::Lock lock(mutex_);
+ if (pool_) {
+ ctx = static_cast<grn_ctx *>(pool_->data);
+ list_pop(pool_);
+ if ((uint) (now - last_pull_time_) >= CLEAR_THREATHOLD_IN_SECONDS) {
+ clear();
+ }
+ }
+ last_pull_time_ = now;
+ }
+
+ if (!ctx) {
+ ctx = grn_ctx_open(0);
+ }
+
+ DBUG_RETURN(ctx);
+ }
+
+ void release(grn_ctx *ctx) {
+ MRN_DBUG_ENTER_METHOD();
+
+ {
+ mrn::Lock lock(mutex_);
+ list_push(pool_, ctx);
+ grn_ctx_use(ctx, NULL);
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ private:
+ static const int CLEAR_THREATHOLD_IN_SECONDS = 60 * 5;
+
+ mysql_mutex_t *mutex_;
+ LIST *pool_;
+ time_t last_pull_time_;
+
+ void clear(void) {
+ MRN_DBUG_ENTER_METHOD();
+ while (pool_) {
+ grn_ctx *ctx = static_cast<grn_ctx *>(pool_->data);
+ grn_ctx_close(ctx);
+ list_pop(pool_);
+ }
+ DBUG_VOID_RETURN;
+ }
+ };
+
+ // For debug
+#undef MRN_CLASS_NAME
+#define MRN_CLASS_NAME "mrn::ContextPool"
+
+ ContextPool::ContextPool(mysql_mutex_t *mutex)
+ : impl_(new Impl(mutex)) {
+ }
+
+ ContextPool::~ContextPool(void) {
+ delete impl_;
+ }
+
+ grn_ctx *ContextPool::pull(void) {
+ MRN_DBUG_ENTER_METHOD();
+ grn_ctx *ctx = impl_->pull();
+ DBUG_RETURN(ctx);
+ }
+
+ void ContextPool::release(grn_ctx *ctx) {
+ MRN_DBUG_ENTER_METHOD();
+ impl_->release(ctx);
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_context_pool.hpp b/storage/mroonga/lib/mrn_context_pool.hpp
new file mode 100644
index 00000000..22b4fed8
--- /dev/null
+++ b/storage/mroonga/lib/mrn_context_pool.hpp
@@ -0,0 +1,41 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#ifndef MRN_CONTEXT_POOL_HPP_
+#define MRN_CONTEXT_POOL_HPP_
+
+#include <mrn_mysql.h>
+
+#include <groonga.h>
+
+namespace mrn {
+ class ContextPool {
+ public:
+ ContextPool(mysql_mutex_t *mutex);
+ ~ContextPool(void);
+ grn_ctx *pull(void);
+ void release(grn_ctx *context);
+
+ private:
+ class Impl;
+ Impl *impl_;
+ };
+}
+
+#endif /* MRN_CONTEXT_POOL_HPP_ */
diff --git a/storage/mroonga/lib/mrn_count_skip_checker.cpp b/storage/mroonga/lib/mrn_count_skip_checker.cpp
new file mode 100644
index 00000000..dfa1a11d
--- /dev/null
+++ b/storage/mroonga/lib/mrn_count_skip_checker.cpp
@@ -0,0 +1,303 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2017 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-1335 USA
+*/
+
+#include "mrn_count_skip_checker.hpp"
+
+#include <item_sum.h>
+
+// for debug
+#define MRN_CLASS_NAME "mrn::CountSkipChecker"
+
+namespace mrn {
+ CountSkipChecker::CountSkipChecker(grn_ctx *ctx,
+ TABLE *table,
+ SELECT_LEX *select_lex,
+ KEY *key_info,
+ key_part_map target_key_part_map,
+ bool is_storage_mode)
+ : ctx_(ctx),
+ table_(table),
+ select_lex_(select_lex),
+ key_info_(key_info),
+ target_key_part_map_(target_key_part_map),
+ is_storage_mode_(is_storage_mode) {
+ }
+
+ CountSkipChecker::~CountSkipChecker() {
+ }
+
+ bool CountSkipChecker::check() {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (select_lex_->item_list.elements != 1) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] not only one item: %u",
+ select_lex_->item_list.elements);
+ DBUG_RETURN(false);
+ }
+ if (select_lex_->group_list.elements > 0) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] have groups: %u",
+ select_lex_->group_list.elements);
+ DBUG_RETURN(false);
+ }
+ if (MRN_SELECT_LEX_GET_HAVING_COND(select_lex_)) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] have HAVING");
+ DBUG_RETURN(false);
+ }
+ if (select_lex_->table_list.elements != 1) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] not only one table: %u",
+ select_lex_->table_list.elements);
+ DBUG_RETURN(false);
+ }
+
+ Item *info = static_cast<Item *>(select_lex_->item_list.first_node()->info);
+ if (info->type() != Item::SUM_FUNC_ITEM) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] item isn't sum function: %u",
+ info->type());
+ DBUG_RETURN(false);
+ }
+ Item_sum *sum_item = static_cast<Item_sum *>(info);
+ if (sum_item->sum_func() != Item_sum::COUNT_FUNC) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] not COUNT: %u",
+ sum_item->sum_func());
+ DBUG_RETURN(false);
+ }
+ if (ITEM_SUM_GET_NEST_LEVEL(sum_item) != 0 ||
+ ITEM_SUM_GET_AGGR_LEVEL(sum_item) != 0 ||
+ ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item) != -1 ||
+ sum_item->max_sum_func_level != -1) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] not simple COUNT(*): %d:%d:%d:%d",
+ ITEM_SUM_GET_NEST_LEVEL(sum_item),
+ ITEM_SUM_GET_AGGR_LEVEL(sum_item),
+ ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item),
+ sum_item->max_sum_func_level);
+ DBUG_RETURN(false);
+ }
+
+ Item *where = MRN_SELECT_LEX_GET_WHERE_COND(select_lex_);
+ if (!where) {
+ if (is_storage_mode_) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][true] no condition");
+ DBUG_RETURN(true);
+ } else {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] no condition with wrapper mode");
+ DBUG_RETURN(false);
+ }
+ }
+
+ bool skippable = is_skippable(where);
+ DBUG_RETURN(skippable);
+ }
+
+ bool CountSkipChecker::is_skippable(Item *where) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool skippable = false;
+ switch (where->type()) {
+ case Item::COND_ITEM:
+ {
+ Item_cond *cond_item = static_cast<Item_cond *>(where);
+ skippable = is_skippable(cond_item);
+ if (skippable) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][true] skippable multiple conditions");
+ }
+ }
+ break;
+ case Item::FUNC_ITEM:
+ {
+ Item_func *func_item = static_cast<Item_func *>(where);
+ if (func_item->functype() == Item_func::FT_FUNC) {
+ if (select_lex_->select_n_where_fields == 1) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][true] "
+ "only one full text search condition");
+ DBUG_RETURN(true);
+ } else {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] "
+ "full text search condition and more conditions: %u",
+ select_lex_->select_n_where_fields);
+ DBUG_RETURN(false);
+ }
+ } else {
+ skippable = is_skippable(func_item);
+ if (skippable) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][true] skippable condition");
+ }
+ }
+ }
+ break;
+ default:
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] unsupported top level item: %u",
+ where->type());
+ break;
+ }
+
+ DBUG_RETURN(skippable);
+ }
+
+ bool CountSkipChecker::is_skippable(Item_cond *cond_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ List_iterator<Item> iterator(*(cond_item->argument_list()));
+ Item *sub_item;
+ while ((sub_item = iterator++)) {
+ if (sub_item->type() != Item::FUNC_ITEM) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] "
+ "sub condition isn't function item: %u",
+ sub_item->type());
+ DBUG_RETURN(false);
+ }
+ if (!is_skippable(static_cast<Item_func *>(sub_item))) {
+ DBUG_RETURN(false);
+ }
+ }
+ DBUG_RETURN(true);
+ }
+
+ bool CountSkipChecker::is_skippable(Item_func *func_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ switch (func_item->functype()) {
+ case Item_func::EQ_FUNC:
+ case Item_func::EQUAL_FUNC:
+ case Item_func::NE_FUNC:
+ case Item_func::LT_FUNC:
+ case Item_func::LE_FUNC:
+ case Item_func::GE_FUNC:
+ case Item_func::GT_FUNC:
+ {
+ Item **arguments = func_item->arguments();
+ Item *left_item = arguments[0];
+ if (left_item->type() != Item::FIELD_ITEM) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] not field: %u:%u",
+ func_item->functype(),
+ left_item->type());
+ DBUG_RETURN(false);
+ }
+
+ bool skippable = is_skippable(static_cast<Item_field *>(left_item));
+ DBUG_RETURN(skippable);
+ }
+ break;
+ case Item_func::BETWEEN:
+ {
+ Item **arguments = func_item->arguments();
+ Item *target_item = arguments[0];
+ if (target_item->type() != Item::FIELD_ITEM) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] BETWEEN target isn't field: %u",
+ target_item->type());
+ DBUG_RETURN(false);
+ }
+
+ bool skippable = is_skippable(static_cast<Item_field *>(target_item));
+ DBUG_RETURN(skippable);
+ }
+ break;
+ case Item_func::MULT_EQUAL_FUNC:
+#ifdef MRN_HAVE_ITEM_EQUAL_FIELDS_ITERATOR
+ {
+ Item_equal *equal_item = static_cast<Item_equal *>(func_item);
+ Item_equal_fields_iterator iterator(*equal_item);
+ Item *field_item;
+ while ((field_item = iterator++)) {
+ bool skippable = is_skippable(static_cast<Item_field *>(field_item));
+ if (!skippable) {
+ DBUG_RETURN(skippable);
+ }
+ }
+ DBUG_RETURN(true);
+ }
+#endif
+ break;
+ default:
+ break;
+ }
+
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] unsupported function item: %u",
+ func_item->functype());
+ DBUG_RETURN(false);
+ }
+
+ bool CountSkipChecker::is_skippable(Item_field *field_item) {
+ MRN_DBUG_ENTER_METHOD();
+
+ Field *field = field_item->field;
+ if (!field) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] field is missing");
+ DBUG_RETURN(false);
+ }
+
+ if (field->table != table_) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] external table's field");
+ DBUG_RETURN(false);
+ }
+
+ if (!key_info_) {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] no active index: <%s>:<%s>",
+ *(field->table_name),
+ field->field_name.str);
+ DBUG_RETURN(false);
+ }
+
+ uint i;
+ KEY_PART_INFO *key_part = key_info_->key_part;
+ for (i = 0; i < KEY_N_KEY_PARTS(key_info_); i++) {
+ if (key_part[i].field == field) {
+ if ((target_key_part_map_ >> i) & 1) {
+ DBUG_RETURN(true);
+ } else {
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] "
+ "field's index are out of key part map: %u:%lu: <%s>:<%s>",
+ i,
+ target_key_part_map_,
+ *(field->table_name),
+ field->field_name.str);
+ DBUG_RETURN(false);
+ }
+ }
+ }
+
+ GRN_LOG(ctx_, GRN_LOG_DEBUG,
+ "[mroonga][count-skip][false] field isn't indexed: <%s>:<%s>",
+ *(field->table_name),
+ field->field_name.str);
+ DBUG_RETURN(false);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_count_skip_checker.hpp b/storage/mroonga/lib/mrn_count_skip_checker.hpp
new file mode 100644
index 00000000..8ea93cd3
--- /dev/null
+++ b/storage/mroonga/lib/mrn_count_skip_checker.hpp
@@ -0,0 +1,57 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 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-1335 USA
+*/
+
+#ifndef MRN_COUNT_SKIP_CHECKER_HPP_
+#define MRN_COUNT_SKIP_CHECKER_HPP_
+
+#include <mrn_mysql_compat.h>
+
+#include <item_cmpfunc.h>
+
+#include <groonga.h>
+
+namespace mrn {
+ class CountSkipChecker {
+ public:
+ CountSkipChecker(grn_ctx *ctx,
+ TABLE *table,
+ SELECT_LEX *select_lex,
+ KEY *key_info,
+ key_part_map target_key_part_map,
+ bool is_storage_mode);
+ ~CountSkipChecker();
+
+ bool check();
+
+ private:
+ grn_ctx *ctx_;
+ TABLE *table_;
+ SELECT_LEX *select_lex_;
+ KEY *key_info_;
+ key_part_map target_key_part_map_;
+ bool is_storage_mode_;
+
+ bool is_skippable(Item *where);
+ bool is_skippable(Item_cond *cond_item);
+ bool is_skippable(Item_func *func_item);
+ bool is_skippable(Item_field *field_item);
+ };
+}
+
+#endif /* MRN_COUNT_SKIP_CHECKER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_current_thread.hpp b/storage/mroonga/lib/mrn_current_thread.hpp
new file mode 100644
index 00000000..ee494f76
--- /dev/null
+++ b/storage/mroonga/lib/mrn_current_thread.hpp
@@ -0,0 +1,27 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#pragma once
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+# include <current_thd.h>
+#endif
diff --git a/storage/mroonga/lib/mrn_database.cpp b/storage/mroonga/lib/mrn_database.cpp
new file mode 100644
index 00000000..12f0b348
--- /dev/null
+++ b/storage/mroonga/lib/mrn_database.cpp
@@ -0,0 +1,89 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_database.hpp"
+#include "mrn_operations.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::Database"
+
+namespace mrn {
+ Database::Database(grn_ctx *ctx, grn_obj *db)
+ : ctx_(ctx),
+ db_(db),
+ broken_table_names_(NULL),
+ is_broken_(false) {
+ Operations operations(ctx_);
+ broken_table_names_ = operations.collect_processing_table_names();
+ is_broken_ = operations.is_locked();
+ }
+
+ Database::~Database(void) {
+ close();
+ }
+
+ void Database::close() {
+ MRN_DBUG_ENTER_METHOD();
+ if (db_) {
+ grn_hash_close(ctx_, broken_table_names_);
+ broken_table_names_ = NULL;
+ grn_obj_close(ctx_, db_);
+ db_ = NULL;
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ grn_rc Database::remove() {
+ MRN_DBUG_ENTER_METHOD();
+ grn_rc rc = GRN_SUCCESS;
+ if (db_) {
+ grn_hash_close(ctx_, broken_table_names_);
+ broken_table_names_ = NULL;
+ rc = grn_obj_remove(ctx_, db_);
+ if (rc == GRN_SUCCESS) {
+ db_ = NULL;
+ }
+ }
+ DBUG_RETURN(rc);
+ }
+
+ grn_obj *Database::get() {
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(db_);
+ }
+
+ bool Database::is_broken() {
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(is_broken_);
+ }
+
+ bool Database::is_broken_table(const char *name, size_t name_size) {
+ MRN_DBUG_ENTER_METHOD();
+ grn_id id = grn_hash_get(ctx_, broken_table_names_, name, name_size, NULL);
+ DBUG_RETURN(id != GRN_ID_NIL);
+ }
+
+ void Database::mark_table_repaired(const char *name, size_t name_size) {
+ MRN_DBUG_ENTER_METHOD();
+ grn_hash_delete(ctx_, broken_table_names_, name, name_size, NULL);
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_database.hpp b/storage/mroonga/lib/mrn_database.hpp
new file mode 100644
index 00000000..cf9f9d4a
--- /dev/null
+++ b/storage/mroonga/lib/mrn_database.hpp
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#ifndef MRN_DATABASE_HPP_
+#define MRN_DATABASE_HPP_
+
+#include <groonga.h>
+
+namespace mrn {
+ class Database {
+ public:
+ Database(grn_ctx *ctx, grn_obj *db);
+ ~Database(void);
+
+ void close();
+ grn_rc remove();
+ grn_obj *get();
+
+ bool is_broken();
+ bool is_broken_table(const char *name, size_t name_size);
+ void mark_table_repaired(const char *name, size_t name_size);
+
+ private:
+ grn_ctx *ctx_;
+ grn_obj *db_;
+ grn_hash *broken_table_names_;
+ bool is_broken_;
+ };
+}
+
+#endif /* MRN_DATABASE_HPP_ */
diff --git a/storage/mroonga/lib/mrn_database_manager.cpp b/storage/mroonga/lib/mrn_database_manager.cpp
new file mode 100644
index 00000000..149c556f
--- /dev/null
+++ b/storage/mroonga/lib/mrn_database_manager.cpp
@@ -0,0 +1,364 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_database_manager.hpp"
+#include "mrn_encoding.hpp"
+#include "mrn_lock.hpp"
+#include "mrn_path_mapper.hpp"
+
+#include <groonga/plugin.h>
+
+// for debug
+#define MRN_CLASS_NAME "mrn::DatabaseManager"
+
+#ifdef WIN32
+# include <direct.h>
+# define MRN_MKDIR(pathname, mode) _mkdir((pathname))
+#else
+# include <dirent.h>
+# include <unistd.h>
+# define MRN_MKDIR(pathname, mode) mkdir((pathname), (mode))
+#endif
+
+extern "C" {
+ grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(init, normalizers_mysql)(grn_ctx *ctx);
+ grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(register, normalizers_mysql)(grn_ctx *ctx);
+}
+
+namespace mrn {
+ DatabaseManager::DatabaseManager(grn_ctx *ctx, mysql_mutex_t *mutex)
+ : ctx_(ctx),
+ cache_(NULL),
+ mutex_(mutex) {
+ }
+
+ DatabaseManager::~DatabaseManager(void) {
+ if (cache_) {
+ void *db_address;
+ GRN_HASH_EACH(ctx_, cache_, id, NULL, 0, &db_address, {
+ Database *db;
+ memcpy(&db, db_address, sizeof(grn_obj *));
+ delete db;
+ });
+ grn_hash_close(ctx_, cache_);
+ }
+ }
+
+ bool DatabaseManager::init(void) {
+ MRN_DBUG_ENTER_METHOD();
+ cache_ = grn_hash_create(ctx_,
+ NULL,
+ GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_obj *),
+ GRN_OBJ_KEY_VAR_SIZE);
+ if (!cache_) {
+ GRN_LOG(ctx_, GRN_LOG_ERROR,
+ "failed to initialize hash table for caching opened databases");
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(true);
+ }
+
+ int DatabaseManager::open(const char *path, Database **db) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+ *db = NULL;
+
+ mrn::PathMapper mapper(path);
+ mrn::Lock lock(mutex_);
+
+ error = mrn::encoding::set(ctx_, system_charset_info);
+ if (error) {
+ DBUG_RETURN(error);
+ }
+
+ grn_id id;
+ void *db_address;
+ id = grn_hash_get(ctx_, cache_,
+ mapper.db_name(), strlen(mapper.db_name()),
+ &db_address);
+ if (id == GRN_ID_NIL) {
+ grn_obj *grn_db;
+ struct stat db_stat;
+ if (stat(mapper.db_path(), &db_stat)) {
+ GRN_LOG(ctx_, GRN_LOG_INFO,
+ "database not found. creating...: <%s>", mapper.db_path());
+ if (path[0] == FN_CURLIB &&
+ mrn_is_directory_separator(path[1])) {
+ ensure_database_directory();
+ }
+ grn_db = grn_db_create(ctx_, mapper.db_path(), NULL);
+ if (ctx_->rc) {
+ error = ER_CANT_CREATE_TABLE;
+ my_message(error, ctx_->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ } else {
+ grn_db = grn_db_open(ctx_, mapper.db_path());
+ if (ctx_->rc) {
+ error = ER_CANT_OPEN_FILE;
+ my_message(error, ctx_->errbuf, MYF(0));
+ DBUG_RETURN(error);
+ }
+ }
+ *db = new Database(ctx_, grn_db);
+ grn_hash_add(ctx_, cache_,
+ mapper.db_name(), strlen(mapper.db_name()),
+ &db_address, NULL);
+ memcpy(db_address, db, sizeof(Database *));
+ error = ensure_normalizers_registered((*db)->get());
+ if (!error) {
+ if ((*db)->is_broken()) {
+ error = ER_CANT_OPEN_FILE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: database: open: "
+ "The database maybe broken. "
+ "We recommend you to recreate the database. "
+ "If the database isn't broken, "
+ "you can remove this error by running "
+ "'groonga %s table_remove mroonga_operations' "
+ "on server. But the latter isn't recommended.",
+ mapper.db_path());
+ my_message(error, error_message, MYF(0));
+ }
+ }
+ } else {
+ memcpy(db, db_address, sizeof(Database *));
+ grn_ctx_use(ctx_, (*db)->get());
+ }
+
+ DBUG_RETURN(error);
+ }
+
+ void DatabaseManager::close(const char *path) {
+ MRN_DBUG_ENTER_METHOD();
+
+ mrn::PathMapper mapper(path);
+ mrn::Lock lock(mutex_);
+
+ grn_id id;
+ void *db_address;
+ id = grn_hash_get(ctx_, cache_,
+ mapper.db_name(), strlen(mapper.db_name()),
+ &db_address);
+ if (id == GRN_ID_NIL) {
+ DBUG_VOID_RETURN;
+ }
+
+ Database *db = NULL;
+ memcpy(&db, db_address, sizeof(Database *));
+ grn_ctx_use(ctx_, db->get());
+ if (db) {
+ delete db;
+ }
+
+ grn_hash_delete_by_id(ctx_, cache_, id, NULL);
+
+ DBUG_VOID_RETURN;
+ }
+
+ bool DatabaseManager::drop(const char *path) {
+ MRN_DBUG_ENTER_METHOD();
+
+ mrn::PathMapper mapper(path);
+ mrn::Lock lock(mutex_);
+
+ grn_id id;
+ void *db_address;
+ id = grn_hash_get(ctx_, cache_,
+ mapper.db_name(), strlen(mapper.db_name()),
+ &db_address);
+
+ Database *db = NULL;
+ if (id == GRN_ID_NIL) {
+ struct stat dummy;
+ if (stat(mapper.db_path(), &dummy) == 0) {
+ grn_obj *grn_db = grn_db_open(ctx_, mapper.db_path());
+ db = new Database(ctx_, grn_db);
+ }
+ } else {
+ memcpy(&db, db_address, sizeof(Database *));
+ grn_ctx_use(ctx_, db->get());
+ }
+
+ if (!db) {
+ DBUG_RETURN(false);
+ }
+
+ if (db->remove() == GRN_SUCCESS) {
+ if (id != GRN_ID_NIL) {
+ grn_hash_delete_by_id(ctx_, cache_, id, NULL);
+ }
+ delete db;
+ DBUG_RETURN(true);
+ } else {
+ GRN_LOG(ctx_, GRN_LOG_ERROR,
+ "failed to drop database: <%s>: <%s>",
+ mapper.db_path(), ctx_->errbuf);
+ if (id == GRN_ID_NIL) {
+ delete db;
+ }
+ DBUG_RETURN(false);
+ }
+ }
+
+ int DatabaseManager::clear(void) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ mrn::Lock lock(mutex_);
+
+ grn_hash_cursor *cursor;
+ cursor = grn_hash_cursor_open(ctx_, cache_,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (ctx_->rc) {
+ my_message(ER_ERROR_ON_READ, ctx_->errbuf, MYF(0));
+ DBUG_RETURN(ER_ERROR_ON_READ);
+ }
+
+ while (grn_hash_cursor_next(ctx_, cursor) != GRN_ID_NIL) {
+ if (ctx_->rc) {
+ error = ER_ERROR_ON_READ;
+ my_message(error, ctx_->errbuf, MYF(0));
+ break;
+ }
+ void *db_address;
+ Database *db;
+ grn_hash_cursor_get_value(ctx_, cursor, &db_address);
+ memcpy(&db, db_address, sizeof(Database *));
+ grn_ctx_use(ctx_, db->get());
+ grn_rc rc = grn_hash_cursor_delete(ctx_, cursor, NULL);
+ if (rc) {
+ error = ER_ERROR_ON_READ;
+ my_message(error, ctx_->errbuf, MYF(0));
+ break;
+ }
+ delete db;
+ }
+ grn_hash_cursor_close(ctx_, cursor);
+
+ DBUG_RETURN(error);
+ }
+
+ const char *DatabaseManager::error_message() {
+ MRN_DBUG_ENTER_METHOD();
+ DBUG_RETURN(ctx_->errbuf);
+ }
+
+ void DatabaseManager::mkdir_p(const char *directory) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int i = 0;
+ char sub_directory[MRN_MAX_PATH_SIZE];
+ sub_directory[0] = '\0';
+ while (true) {
+ if (mrn_is_directory_separator(directory[i]) ||
+ directory[i] == '\0') {
+ sub_directory[i] = '\0';
+ struct stat directory_status;
+ if (stat(sub_directory, &directory_status) != 0) {
+ DBUG_PRINT("info", ("mroonga: creating directory: <%s>", sub_directory));
+ GRN_LOG(ctx_, GRN_LOG_INFO, "creating directory: <%s>", sub_directory);
+ if (MRN_MKDIR(sub_directory, S_IRWXU) == 0) {
+ DBUG_PRINT("info",
+ ("mroonga: created directory: <%s>", sub_directory));
+ GRN_LOG(ctx_, GRN_LOG_INFO, "created directory: <%s>", sub_directory);
+ } else {
+ DBUG_PRINT("error",
+ ("mroonga: failed to create directory: <%s>: <%s>",
+ sub_directory, strerror(errno)));
+ GRN_LOG(ctx_, GRN_LOG_ERROR,
+ "failed to create directory: <%s>: <%s>",
+ sub_directory, strerror(errno));
+ DBUG_VOID_RETURN;
+ }
+ }
+ }
+
+ if (directory[i] == '\0') {
+ break;
+ }
+
+ sub_directory[i] = directory[i];
+ ++i;
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ void DatabaseManager::ensure_database_directory(void) {
+ MRN_DBUG_ENTER_METHOD();
+
+ const char *path_prefix = mrn::PathMapper::default_path_prefix;
+ if (!path_prefix)
+ DBUG_VOID_RETURN;
+
+ const char *last_path_separator;
+ last_path_separator = strrchr(path_prefix, FN_LIBCHAR);
+#ifdef FN_LIBCHAR2
+ if (!last_path_separator)
+ last_path_separator = strrchr(path_prefix, FN_LIBCHAR2);
+#endif
+ if (!last_path_separator)
+ DBUG_VOID_RETURN;
+ if (path_prefix == last_path_separator)
+ DBUG_VOID_RETURN;
+
+ char database_directory[MRN_MAX_PATH_SIZE];
+ size_t database_directory_length = last_path_separator - path_prefix;
+ strncpy(database_directory, path_prefix, database_directory_length);
+ database_directory[database_directory_length] = '\0';
+ mkdir_p(database_directory);
+
+ DBUG_VOID_RETURN;
+ }
+
+ int DatabaseManager::ensure_normalizers_registered(grn_obj *db) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+#ifdef WITH_GROONGA_NORMALIZER_MYSQL
+ {
+# ifdef MRN_GROONGA_NORMALIZER_MYSQL_EMBEDDED
+ GRN_PLUGIN_IMPL_NAME_TAGGED(init, normalizers_mysql)(ctx_);
+ GRN_PLUGIN_IMPL_NAME_TAGGED(register, normalizers_mysql)(ctx_);
+# else
+ grn_obj *mysql_normalizer;
+ mysql_normalizer = grn_ctx_get(ctx_, "NormalizerMySQLGeneralCI", -1);
+ if (mysql_normalizer) {
+ grn_obj_unlink(ctx_, mysql_normalizer);
+ } else {
+ grn_plugin_register(ctx_, GROONGA_NORMALIZER_MYSQL_PLUGIN_NAME);
+ }
+# endif
+ }
+#endif
+
+ DBUG_RETURN(error);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_database_manager.hpp b/storage/mroonga/lib/mrn_database_manager.hpp
new file mode 100644
index 00000000..05383af6
--- /dev/null
+++ b/storage/mroonga/lib/mrn_database_manager.hpp
@@ -0,0 +1,52 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-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-1335 USA
+*/
+
+#ifndef MRN_DATABASE_MANAGER_HPP_
+#define MRN_DATABASE_MANAGER_HPP_
+
+#include "mrn_database.hpp"
+
+#include <groonga.h>
+
+namespace mrn {
+ class DatabaseManager {
+ public:
+ DatabaseManager(grn_ctx *ctx, mysql_mutex_t *mutex);
+ ~DatabaseManager(void);
+ bool init(void);
+ int open(const char *path, Database **db);
+ void close(const char *path);
+ bool drop(const char *path);
+ int clear(void);
+ const char *error_message();
+
+ private:
+ grn_ctx *ctx_;
+ grn_hash *cache_;
+ mysql_mutex_t *mutex_;
+
+ void mkdir_p(const char *directory);
+ void ensure_database_directory(void);
+ int ensure_normalizers_registered(grn_obj *db);
+ };
+}
+
+#endif /* MRN_DATABASE_MANAGER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_database_repairer.cpp b/storage/mroonga/lib/mrn_database_repairer.cpp
new file mode 100644
index 00000000..c0c4a90e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_database_repairer.cpp
@@ -0,0 +1,300 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_constants.hpp>
+
+#include "mrn_database_repairer.hpp"
+#include "mrn_path_mapper.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::DatabaseRepairer"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#ifndef WIN32
+# include <dirent.h>
+#endif
+
+namespace mrn {
+ struct CheckResult {
+ CheckResult() :
+ is_crashed(false),
+ is_corrupt(false) {
+ }
+
+ bool is_crashed;
+ bool is_corrupt;
+ };
+
+ DatabaseRepairer::DatabaseRepairer(grn_ctx *ctx, THD *thd)
+ : ctx_(ctx),
+ thd_(thd),
+ base_directory_(NULL),
+ base_directory_buffer_(),
+ path_prefix_(NULL),
+ path_prefix_buffer_(),
+ path_prefix_length_(0),
+ mrn_db_file_suffix_length_(strlen(MRN_DB_FILE_SUFFIX)) {
+ }
+
+ DatabaseRepairer::~DatabaseRepairer() {
+ }
+
+ bool DatabaseRepairer::is_crashed(void) {
+ MRN_DBUG_ENTER_METHOD();
+
+ CheckResult result;
+ each_database(&DatabaseRepairer::check_body, &result);
+
+ DBUG_RETURN(result.is_crashed);
+ }
+
+ bool DatabaseRepairer::is_corrupt(void) {
+ MRN_DBUG_ENTER_METHOD();
+
+ CheckResult result;
+ each_database(&DatabaseRepairer::check_body, &result);
+
+ DBUG_RETURN(result.is_corrupt);
+ }
+
+ bool DatabaseRepairer::repair(void) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool succeeded = true;
+ each_database(&DatabaseRepairer::repair_body, &succeeded);
+
+ DBUG_RETURN(succeeded);
+ }
+
+ void DatabaseRepairer::each_database(EachBodyFunc each_body_func,
+ void *user_data) {
+ MRN_DBUG_ENTER_METHOD();
+
+ detect_paths();
+
+#ifdef WIN32
+ WIN32_FIND_DATA data;
+ HANDLE finder = FindFirstFile(base_directory_, &data);
+ if (finder == INVALID_HANDLE_VALUE) {
+ DBUG_VOID_RETURN;
+ }
+
+ grn_ctx ctx;
+ grn_rc rc = grn_ctx_init(&ctx, 0);
+ if (rc == GRN_SUCCESS) {
+ do {
+ each_database_body(data.cFileName, &ctx, each_body_func, user_data);
+ } while (FindNextFile(finder, &data) != 0);
+ grn_ctx_fin(&ctx);
+ } else {
+ GRN_LOG(ctx_, GRN_LOG_WARNING,
+ "[mroonga][database][repairer][each] "
+ "failed to initialize grn_ctx: %d: %s",
+ rc, grn_rc_to_string(rc));
+ }
+ FindClose(finder);
+#else
+ DIR *dir = opendir(base_directory_);
+ if (!dir) {
+ DBUG_VOID_RETURN;
+ }
+
+ grn_ctx ctx;
+ grn_rc rc = grn_ctx_init(&ctx, 0);
+ if (rc == GRN_SUCCESS) {
+ while (struct dirent *entry = readdir(dir)) {
+ each_database_body(entry->d_name, &ctx, each_body_func, user_data);
+ }
+ grn_ctx_fin(&ctx);
+ } else {
+ GRN_LOG(ctx_, GRN_LOG_WARNING,
+ "[mroonga][database][repairer][each] "
+ "failed to initialize grn_ctx: %d: %s",
+ rc, grn_rc_to_string(rc));
+ }
+ closedir(dir);
+#endif
+
+ DBUG_VOID_RETURN;
+ }
+
+ void DatabaseRepairer::each_database_body(const char *base_path,
+ grn_ctx *ctx,
+ EachBodyFunc each_body_func,
+ void *user_data) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (path_prefix_length_ > 0 &&
+ strncmp(base_path, path_prefix_, path_prefix_length_) != 0) {
+ DBUG_VOID_RETURN;
+ }
+
+ size_t path_length = strlen(base_path);
+ if (path_length <= mrn_db_file_suffix_length_) {
+ DBUG_VOID_RETURN;
+ }
+
+ if (strncmp(base_path + (path_length - mrn_db_file_suffix_length_),
+ MRN_DB_FILE_SUFFIX, mrn_db_file_suffix_length_) != 0) {
+ DBUG_VOID_RETURN;
+ }
+
+ char db_path[MRN_MAX_PATH_SIZE];
+ snprintf(db_path, MRN_MAX_PATH_SIZE,
+ "%s%c%s", base_directory_, FN_LIBCHAR, base_path);
+ grn_obj *db = grn_db_open(ctx, db_path);
+ if (!db) {
+ DBUG_VOID_RETURN;
+ }
+
+ (this->*each_body_func)(ctx, db, db_path, user_data);
+
+ grn_obj_close(ctx, db);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void DatabaseRepairer::detect_paths(void) {
+ MRN_DBUG_ENTER_METHOD();
+
+ const char *raw_path_prefix = mrn::PathMapper::default_path_prefix;
+
+ if (!raw_path_prefix) {
+ base_directory_ = ".";
+ path_prefix_ = NULL;
+ DBUG_VOID_RETURN;
+ }
+
+ strcpy(base_directory_buffer_, raw_path_prefix);
+ size_t raw_path_prefix_length = strlen(raw_path_prefix);
+ size_t separator_position = raw_path_prefix_length;
+ for (; separator_position > 0; separator_position--) {
+ if (mrn_is_directory_separator(base_directory_buffer_[separator_position])) {
+ break;
+ }
+ }
+ if (separator_position == 0 ||
+ separator_position == raw_path_prefix_length) {
+ base_directory_ = ".";
+ } else {
+ base_directory_buffer_[separator_position] = '\0';
+ base_directory_ = base_directory_buffer_;
+ strcpy(path_prefix_buffer_, raw_path_prefix + separator_position + 1);
+ path_prefix_ = path_prefix_buffer_;
+ path_prefix_length_ = strlen(path_prefix_);
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ void DatabaseRepairer::check_body(grn_ctx *ctx,
+ grn_obj *db,
+ const char *db_path,
+ void *user_data) {
+ MRN_DBUG_ENTER_METHOD();
+
+ CheckResult *result = static_cast<CheckResult *>(user_data);
+
+ if (grn_obj_is_locked(ctx, db)) {
+ result->is_crashed = true;
+ result->is_corrupt = true;
+ DBUG_VOID_RETURN;
+ }
+
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx, db,
+ NULL, 0,
+ NULL, 0,
+ 0, -1, GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ result->is_crashed = true;
+ result->is_corrupt = true;
+ DBUG_VOID_RETURN;
+ }
+
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ grn_obj *object = grn_ctx_at(ctx, id);
+
+ if (!object) {
+ if (ctx->rc == GRN_SUCCESS) {
+ continue;
+ } else {
+ result->is_corrupt = true;
+ break;
+ }
+ }
+
+ switch (object->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ case GRN_COLUMN_FIX_SIZE:
+ case GRN_COLUMN_VAR_SIZE:
+ case GRN_COLUMN_INDEX:
+ if (grn_obj_is_locked(ctx_, object)) {
+ result->is_crashed = true;
+ result->is_corrupt = true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ grn_obj_unlink(ctx, object);
+
+ if (result->is_crashed || result->is_corrupt) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void DatabaseRepairer::repair_body(grn_ctx *ctx,
+ grn_obj *db,
+ const char *db_path,
+ void *user_data) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool *succeeded = static_cast<bool *>(user_data);
+ if (grn_db_recover(ctx, db) != GRN_SUCCESS) {
+ push_warning_printf(thd_,
+ MRN_SEVERITY_WARNING,
+ ER_NOT_KEYFILE,
+ "mroonga: repair: "
+ "Failed to recover database: <%s>: <%s>",
+ db_path, ctx->errbuf);
+ *succeeded = false;
+ }
+
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_database_repairer.hpp b/storage/mroonga/lib/mrn_database_repairer.hpp
new file mode 100644
index 00000000..b56c2744
--- /dev/null
+++ b/storage/mroonga/lib/mrn_database_repairer.hpp
@@ -0,0 +1,67 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2017 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-1335 USA
+*/
+
+#ifndef MRN_DATABASE_REPAIRER_HPP_
+#define MRN_DATABASE_REPAIRER_HPP_
+
+#include <groonga.h>
+
+namespace mrn {
+ class DatabaseRepairer {
+ public:
+ DatabaseRepairer(grn_ctx *ctx, THD *thd);
+ ~DatabaseRepairer(void);
+ bool is_crashed(void);
+ bool is_corrupt(void);
+ bool repair(void);
+
+ private:
+ grn_ctx *ctx_;
+ THD *thd_;
+ const char *base_directory_;
+ char base_directory_buffer_[MRN_MAX_PATH_SIZE];
+ const char *path_prefix_;
+ char path_prefix_buffer_[MRN_MAX_PATH_SIZE];
+ size_t path_prefix_length_;
+ size_t mrn_db_file_suffix_length_;
+
+ typedef void (DatabaseRepairer::*EachBodyFunc)(grn_ctx *ctx,
+ grn_obj *db,
+ const char *db_path,
+ void *user_data);
+
+ void each_database(EachBodyFunc each_body_func, void *user_data);
+ void each_database_body(const char *base_path,
+ grn_ctx *ctx,
+ EachBodyFunc each_body_func,
+ void *user_data);
+ void detect_paths(void);
+
+ void check_body(grn_ctx *ctx,
+ grn_obj *db,
+ const char *db_path,
+ void *user_data);
+ void repair_body(grn_ctx *ctx,
+ grn_obj *db,
+ const char *db_path,
+ void *user_data);
+ };
+}
+
+#endif /* MRN_DATABASE_REPAIRER_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 00000000..cb2ce7e3
--- /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-1335 USA
+*/
+
+#include "mrn_debug_column_access.hpp"
+
+namespace mrn {
+ DebugColumnAccess::DebugColumnAccess(TABLE *table, MY_BITMAP **bitmap)
+ : table_(table),
+ bitmap_(bitmap) {
+#ifdef DBUG_ASSERT_EXISTS
+ map_ = dbug_tmp_use_all_columns(table_, bitmap_);
+#endif
+ }
+
+ DebugColumnAccess::~DebugColumnAccess() {
+#ifdef DBUG_ASSERT_EXISTS
+ 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 00000000..954e0413
--- /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-1335 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_;
+#ifdef DBUG_ASSERT_EXISTS
+ MY_BITMAP *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 00000000..369c985a
--- /dev/null
+++ b/storage/mroonga/lib/mrn_encoding.cpp
@@ -0,0 +1,242 @@
+/* -*- 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-1335 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]->cs_name.str, "utf8mb3"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "utf8mb4"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "binary"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "ascii"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "latin1"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "cp932"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "sjis"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "eucjpms"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "ujis"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->cs_name.str, "koi8r"))
+ {
+ DBUG_PRINT("info", ("mroonga: %s is %s [%p]",
+ cs[0]->coll_name.str, cs[0]->cs_name.str, 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]->coll_name.str, cs[0]->cs_name.str, cs[0]->cset));
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ int set(grn_ctx *ctx, const CHARSET_INFO *charset) {
+ MRN_DBUG_ENTER_FUNCTION();
+ int error = 0;
+
+ if (!set_raw(ctx, charset)) {
+ const char *name = "<null>";
+ const char *csname = "<null>";
+ if (charset) {
+ name = charset->coll_name.str;
+ csname = charset->cs_name.str;
+ }
+ error = ER_MRN_CHARSET_NOT_SUPPORT_NUM;
+ my_printf_error(error,
+ ER_MRN_CHARSET_NOT_SUPPORT_STR,
+ MYF(0), name, csname);
+ }
+
+ DBUG_RETURN(error);
+ }
+
+ bool set_raw(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 00000000..f321ca68
--- /dev/null
+++ b/storage/mroonga/lib/mrn_encoding.hpp
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 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-1335 USA
+*/
+
+#ifndef MRN_ENCODING_HPP_
+#define MRN_ENCODING_HPP_
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+#include <groonga.h>
+
+namespace mrn {
+ namespace encoding {
+ void init(void);
+ int set(grn_ctx *ctx, const CHARSET_INFO *charset);
+ bool set_raw(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 00000000..762a96d0
--- /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-1335 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_unlock(thd_);
+ }
+ }
+
+ 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 00000000..9bf7e811
--- /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-1335 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 00000000..d7a81f74
--- /dev/null
+++ b/storage/mroonga/lib/mrn_field_normalizer.cpp
@@ -0,0 +1,145 @@
+/* -*- 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-1335 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()->coll_name.str));
+ DBUG_PRINT("info",
+ ("mroonga: charset->csname = %s", field_->charset()->cs_name.str));
+ 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_raw(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->coll_name.str, "utf8mb3_general_ci") == 0) ||
+ (strcmp(charset_info->coll_name.str, "utf8mb4_general_ci") == 0)) {
+ normalizer_name = "NormalizerMySQLGeneralCI";
+ } else if ((strcmp(charset_info->coll_name.str, "utf8mb3_unicode_ci") == 0) ||
+ (strcmp(charset_info->coll_name.str, "utf8mb4_unicode_ci") == 0)) {
+ normalizer_name = "NormalizerMySQLUnicodeCI";
+ } else if ((strcmp(charset_info->coll_name.str, "utf8mb3_unicode_520_ci") == 0) ||
+ (strcmp(charset_info->coll_name.str, "utf8mb4_unicode_520_ci") == 0)) {
+ normalizer_name = "NormalizerMySQLUnicode520CI";
+ }
+
+ 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->coll_name.str,
+ default_normalizer_name);
+ push_warning(thread_, MRN_SEVERITY_WARNING,
+ 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 00000000..76083377
--- /dev/null
+++ b/storage/mroonga/lib/mrn_field_normalizer.hpp
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 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-1335 USA
+*/
+
+#ifndef MRN_FIELD_NORMALIZER_HPP_
+#define MRN_FIELD_NORMALIZER_HPP_
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+#include <groonga.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_grn.hpp b/storage/mroonga/lib/mrn_grn.hpp
new file mode 100644
index 00000000..f288f3e4
--- /dev/null
+++ b/storage/mroonga/lib/mrn_grn.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-1335 USA
+*/
+
+#ifndef MRN_GRN_HPP_
+#define MRN_GRN_HPP_
+
+#include <groonga.h>
+
+namespace mrn {
+ namespace grn {
+ bool is_table(grn_obj *obj) {
+ grn_id type = obj->header.type;
+ return GRN_TABLE_HASH_KEY <= type && obj->header.type <= GRN_DB;
+ }
+
+ bool is_vector_column(grn_obj *column) {
+ int column_type = (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK);
+ return column_type == GRN_OBJ_COLUMN_VECTOR;
+ }
+ }
+}
+
+#endif // MRN_GRN_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 00000000..1a19b9d1
--- /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-1335 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 00000000..da3b96db
--- /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-1335 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 00000000..62e67b3c
--- /dev/null
+++ b/storage/mroonga/lib/mrn_index_table_name.cpp
@@ -0,0 +1,136 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_index_table_name.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::IndexTableName"
+
+namespace mrn {
+ const char *IndexTableName::SEPARATOR = "#";
+ const char *IndexTableName::OLD_SEPARATOR = "-";
+
+ bool IndexTableName::is_custom_name(const char *table_name,
+ size_t table_name_length,
+ const char *index_table_name,
+ size_t index_table_name_length)
+ {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (index_table_name_length <= (table_name_length + strlen(SEPARATOR))) {
+ DBUG_RETURN(true);
+ }
+
+ if (strncmp(table_name, index_table_name, table_name_length) != 0) {
+ DBUG_RETURN(true);
+ }
+
+ if ((strncmp(OLD_SEPARATOR,
+ index_table_name + table_name_length,
+ strlen(OLD_SEPARATOR)) != 0) &&
+ (strncmp(SEPARATOR,
+ index_table_name + table_name_length,
+ strlen(SEPARATOR)) != 0)) {
+ DBUG_RETURN(true);
+ }
+
+ DBUG_RETURN(false);
+ }
+
+ 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(old_name_, MRN_MAX_KEY_SIZE,
+ "%s%s%s",
+ table_name_,
+ OLD_SEPARATOR,
+ encoded_mysql_index_name_multibyte);
+ old_length_ = strlen(old_name_);
+ snprintf(name_, MRN_MAX_KEY_SIZE,
+ "%s%s%s",
+ table_name_,
+ SEPARATOR,
+ encoded_mysql_index_name_multibyte);
+ length_ = strlen(name_);
+ }
+
+ const char *IndexTableName::c_str() {
+ return name_;
+ }
+
+ size_t IndexTableName::length() {
+ return length_;
+ }
+
+ const char *IndexTableName::old_c_str() {
+ return old_name_;
+ }
+
+ size_t IndexTableName::old_length() {
+ return old_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 00000000..80d2444b
--- /dev/null
+++ b/storage/mroonga/lib/mrn_index_table_name.hpp
@@ -0,0 +1,55 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#ifndef MRN_INDEX_TABLE_NAME_HPP_
+#define MRN_INDEX_TABLE_NAME_HPP_
+
+#include <mrn_constants.hpp>
+
+namespace mrn {
+ class IndexTableName {
+ public:
+ static const char *SEPARATOR;
+ static const char *OLD_SEPARATOR;
+
+ static bool is_custom_name(const char *table_name,
+ size_t table_name_length,
+ const char *index_table_name,
+ size_t index_table_name_length);
+
+ IndexTableName(const char *table_name, const char *mysql_index_name);
+ const char *c_str();
+ size_t length();
+ const char *old_c_str();
+ size_t old_length();
+ private:
+ const char *table_name_;
+ const char *mysql_index_name_;
+ char old_name_[MRN_MAX_KEY_SIZE];
+ size_t old_length_;
+ 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 00000000..cfeb519b
--- /dev/null
+++ b/storage/mroonga/lib/mrn_lock.cpp
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 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-1335 USA
+*/
+
+#include "mrn_lock.hpp"
+
+namespace mrn {
+ Lock::Lock(mysql_mutex_t *mutex, bool execute)
+ : mutex_(mutex),
+ execute_(execute) {
+ if (execute_) {
+ mysql_mutex_lock(mutex_);
+ }
+ }
+
+ Lock::~Lock() {
+ if (execute_) {
+ mysql_mutex_unlock(mutex_);
+ }
+ }
+}
diff --git a/storage/mroonga/lib/mrn_lock.hpp b/storage/mroonga/lib/mrn_lock.hpp
new file mode 100644
index 00000000..29337d8e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_lock.hpp
@@ -0,0 +1,37 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 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-1335 USA
+*/
+
+#ifndef MRN_LOCK_HPP_
+#define MRN_LOCK_HPP_
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+namespace mrn {
+ class Lock {
+ public:
+ Lock(mysql_mutex_t *mutex, bool execute=true);
+ ~Lock();
+ private:
+ mysql_mutex_t *mutex_;
+ bool execute_;
+ };
+}
+
+#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 00000000..62e63023
--- /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-1335 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 00000000..1c5488f8
--- /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-1335 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 00000000..73639685
--- /dev/null
+++ b/storage/mroonga/lib/mrn_multiple_column_key_codec.cpp
@@ -0,0 +1,712 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_multiple_column_key_codec.hpp"
+#include "mrn_field_normalizer.hpp"
+#include "mrn_smart_grn_obj.hpp"
+#include "mrn_time_converter.hpp"
+#include "mrn_value_decoder.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_++; } \
+}
+#define mrn_byte_order_network_to_host(buf, key, size) \
+{ \
+ uint32 size_ = (uint32)(size); \
+ uint8 *buf_ = (uint8 *)(buf); \
+ uint8 *key_ = (uint8 *)(key); \
+ while (size_) { *buf_++ = *key_++; size_--; } \
+}
+#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_); } \
+}
+#define mrn_byte_order_network_to_host(buf, key, size) \
+{ \
+ uint32 size_ = (uint32)(size); \
+ uint8 *buf_ = (uint8 *)(buf); \
+ uint8 *key_ = (uint8 *)(key) + size_; \
+ while (size_) { *buf_++ = *(--key_); size_--; } \
+}
+#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;
+ bool is_null = false;
+ 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;
+ is_null = *current_mysql_key;
+ 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);
+ uint grn_key_data_size = 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;
+ long_long_value = sint8korr(current_mysql_key);
+ encode_long_long_int(long_long_value, current_grn_key);
+ }
+ break;
+ case TYPE_NUMBER:
+ {
+ Field_num *number_field = static_cast<Field_num *>(field);
+ encode_number(current_mysql_key,
+ data_size,
+ !number_field->unsigned_flag,
+ current_grn_key);
+ }
+ break;
+ case TYPE_FLOAT:
+ {
+ float value;
+ value_decoder::decode(&value, current_mysql_key);
+ encode_float(value, data_size, current_grn_key);
+ }
+ break;
+ case TYPE_DOUBLE:
+ {
+ double value;
+ value_decoder::decode(&value, current_mysql_key);
+ encode_double(value, data_size, current_grn_key);
+ }
+ break;
+ case TYPE_DATETIME:
+ {
+ long long int mysql_datetime;
+#ifdef WORDS_BIGENDIAN
+ if (field->table && field->table->s->db_low_byte_first) {
+ mysql_datetime = sint8korr(current_mysql_key);
+ } else
+#endif
+ {
+ value_decoder::decode(&mysql_datetime, current_mysql_key);
+ }
+ TimeConverter time_converter;
+ bool truncated;
+ long long int grn_time =
+ time_converter.mysql_datetime_to_grn_time(mysql_datetime,
+ &truncated);
+ encode_long_long_int(grn_time, current_grn_key);
+ }
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case TYPE_DATETIME2:
+ {
+ Field_datetimef *datetimef_field =
+ static_cast<Field_datetimef *>(field);
+ long long int mysql_datetime_packed = is_null ? 0 :
+ my_datetime_packed_from_binary(current_mysql_key,
+ datetimef_field->decimals());
+ MYSQL_TIME mysql_time;
+ TIME_from_longlong_datetime_packed(&mysql_time, mysql_datetime_packed);
+ TimeConverter time_converter;
+ bool truncated;
+ long long int grn_time =
+ time_converter.mysql_time_to_grn_time(&mysql_time, &truncated);
+ grn_key_data_size = 8;
+ encode_long_long_int(grn_time, current_grn_key);
+ }
+ break;
+#endif
+ 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(current_mysql_key, &data_size, field, current_grn_key);
+ grn_key_data_size = data_size;
+ break;
+ }
+
+ if (error) {
+ break;
+ }
+
+ current_mysql_key += data_size;
+ current_grn_key += grn_key_data_size;
+ *grn_key_length += grn_key_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);
+ uint grn_key_data_size = 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 value;
+ decode_long_long_int(current_grn_key, &value);
+ int8store(current_mysql_key, value);
+ }
+ break;
+ case TYPE_NUMBER:
+ {
+ Field_num *number_field = static_cast<Field_num *>(field);
+ decode_number(current_grn_key,
+ grn_key_data_size,
+ !number_field->unsigned_flag,
+ current_mysql_key);
+ }
+ break;
+ case TYPE_FLOAT:
+ decode_float(current_grn_key, grn_key_data_size, current_mysql_key);
+ break;
+ case TYPE_DOUBLE:
+ decode_double(current_grn_key, grn_key_data_size, current_mysql_key);
+ break;
+ case TYPE_DATETIME:
+ {
+ long long int grn_time;
+ decode_long_long_int(current_grn_key, &grn_time);
+ TimeConverter time_converter;
+ long long int mysql_datetime =
+ time_converter.grn_time_to_mysql_datetime(grn_time);
+#ifdef WORDS_BIGENDIAN
+ if (field->table && field->table->s->db_low_byte_first) {
+ int8store(current_mysql_key, mysql_datetime);
+ } else
+#endif
+ {
+ longlongstore(current_mysql_key, mysql_datetime);
+ }
+ }
+ break;
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case TYPE_DATETIME2:
+ {
+ Field_datetimef *datetimef_field =
+ static_cast<Field_datetimef *>(field);
+ long long int grn_time;
+ grn_key_data_size = 8;
+ decode_long_long_int(current_grn_key, &grn_time);
+ TimeConverter time_converter;
+ MYSQL_TIME mysql_time;
+ mysql_time.neg = FALSE;
+ mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME;
+ time_converter.grn_time_to_mysql_time(grn_time, &mysql_time);
+ long long int mysql_datetime_packed =
+ TIME_to_longlong_datetime_packed(&mysql_time);
+ my_datetime_packed_to_binary(mysql_datetime_packed,
+ current_mysql_key,
+ datetimef_field->decimals());
+ }
+ break;
+#endif
+ case TYPE_BYTE_SEQUENCE:
+ memcpy(current_mysql_key, current_grn_key, grn_key_data_size);
+ break;
+ case TYPE_BYTE_REVERSE:
+ decode_reverse(current_grn_key, grn_key_data_size, current_mysql_key);
+ 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;
+ grn_key_data_size = data_size;
+ break;
+ }
+
+ if (error) {
+ break;
+ }
+
+ current_grn_key += 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);
+ switch (data_type) {
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ case TYPE_DATETIME2:
+ data_size = 8;
+ break;
+#endif
+ case TYPE_BYTE_BLOB:
+ data_size += HA_KEY_BLOB_LENGTH;
+ break;
+ default:
+ break;
+ }
+ total_size += data_size;
+ }
+
+ 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:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_TIMESTAMP"));
+ *data_type = TYPE_BYTE_REVERSE;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_DATE:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATE"));
+ *data_type = TYPE_BYTE_REVERSE;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_DATETIME:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_DATETIME"));
+ *data_type = TYPE_DATETIME;
+ *data_size = key_part->length;
+ break;
+ case MYSQL_TYPE_NEWDATE:
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_NEWDATE"));
+ *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_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_DATETIME2;
+ *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;
+ case MYSQL_TYPE_VARCHAR_COMPRESSED:
+ case MYSQL_TYPE_BLOB_COMPRESSED:
+ DBUG_ASSERT(0);
+#ifdef MRN_HAVE_MYSQL_TYPE_JSON
+ case MYSQL_TYPE_JSON:
+ // TODO
+ DBUG_PRINT("info", ("mroonga: MYSQL_TYPE_JSON"));
+ *data_type = TYPE_BYTE_SEQUENCE;
+ *data_size = key_part->length;
+ break;
+#endif
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_number(const uchar *mysql_key,
+ uint mysql_key_size,
+ bool is_signed,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ mrn_byte_order_host_to_network(grn_key, mysql_key, mysql_key_size);
+ if (is_signed) {
+ grn_key[0] ^= 0x80;
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_number(const uchar *grn_key,
+ uint grn_key_size,
+ bool is_signed,
+ uchar *mysql_key) {
+ MRN_DBUG_ENTER_METHOD();
+ uchar buffer[8];
+ memcpy(buffer, grn_key, grn_key_size);
+ if (is_signed) {
+ buffer[0] ^= 0x80;
+ }
+ mrn_byte_order_network_to_host(mysql_key, buffer, grn_key_size);
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_long_long_int(volatile long long int value,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ uint value_size = 8;
+ mrn_byte_order_host_to_network(grn_key, &value, value_size);
+ grn_key[0] ^= 0x80;
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_long_long_int(const uchar *grn_key,
+ long long int *value) {
+ MRN_DBUG_ENTER_METHOD();
+ uint grn_key_size = 8;
+ uchar buffer[8];
+ memcpy(buffer, grn_key, grn_key_size);
+ buffer[0] ^= 0x80;
+ mrn_byte_order_network_to_host(value, buffer, grn_key_size);
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_float(volatile float value,
+ uint value_size,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ int n_bits = (value_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, value_size);
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_float(const uchar *grn_key,
+ uint grn_key_size,
+ uchar *mysql_key) {
+ MRN_DBUG_ENTER_METHOD();
+ int int_value;
+ mrn_byte_order_network_to_host(&int_value, grn_key, grn_key_size);
+ int max_bit = (grn_key_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 value_size,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ int n_bits = (value_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, value_size);
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_double(const uchar *grn_key,
+ uint grn_key_size,
+ uchar *mysql_key) {
+ MRN_DBUG_ENTER_METHOD();
+ long long int long_long_value;
+ mrn_byte_order_network_to_host(&long_long_value, grn_key, grn_key_size);
+ int max_bit = (grn_key_size * 8 - 1);
+ long_long_value =
+ long_long_value ^ (((long_long_value ^ (1LL << max_bit)) >> max_bit) |
+ (1LL << max_bit));
+ memcpy(mysql_key, &long_long_value, sizeof(long_long_value));
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_reverse(const uchar *mysql_key,
+ uint mysql_key_size,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ for (uint i = 0; i < mysql_key_size; i++) {
+ grn_key[i] = mysql_key[mysql_key_size - i - 1];
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::decode_reverse(const uchar *grn_key,
+ uint grn_key_size,
+ uchar *mysql_key) {
+ MRN_DBUG_ENTER_METHOD();
+ for (uint i = 0; i < grn_key_size; i++) {
+ mysql_key[i] = grn_key[grn_key_size - i - 1];
+ }
+ DBUG_VOID_RETURN;
+ }
+
+ void MultipleColumnKeyCodec::encode_blob(const uchar *mysql_key,
+ uint *mysql_key_size,
+ Field *field,
+ uchar *grn_key) {
+ MRN_DBUG_ENTER_METHOD();
+ 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) {
+ if (normalized_length)
+ memcpy(grn_key, normalized, normalized_length);
+ if (normalized_length < *mysql_key_size) {
+ memset(grn_key + normalized_length,
+ '\0', *mysql_key_size - normalized_length);
+ }
+ new_blob_data_length = normalized_length;
+ } else {
+ push_warning_printf(thread_,
+ MRN_SEVERITY_WARNING,
+ MRN_ERROR_CODE_DATA_TRUNCATE(thread_),
+ "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 + *mysql_key_size,
+ &new_blob_data_length,
+ HA_KEY_BLOB_LENGTH);
+ } else {
+ memcpy(grn_key + *mysql_key_size, mysql_key, HA_KEY_BLOB_LENGTH);
+ memcpy(grn_key, mysql_key + HA_KEY_BLOB_LENGTH, *mysql_key_size);
+ }
+ *mysql_key_size += HA_KEY_BLOB_LENGTH;
+ DBUG_VOID_RETURN;
+ }
+}
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 00000000..26de08ca
--- /dev/null
+++ b/storage/mroonga/lib/mrn_multiple_column_key_codec.hpp
@@ -0,0 +1,100 @@
+/* -*- 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-1335 USA
+*/
+
+#ifndef MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
+#define MRN_MULTIPLE_COLUMN_KEY_CODEC_HPP_
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+#include <groonga.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_DATETIME,
+#ifdef MRN_HAVE_MYSQL_TYPE_DATETIME2
+ TYPE_DATETIME2,
+#endif
+ 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_number(const uchar *mysql_key,
+ uint mysql_key_size,
+ bool is_signed,
+ uchar *grn_key);
+ void decode_number(const uchar *grn_key,
+ uint grn_key_size,
+ bool is_signed,
+ uchar *mysql_key);
+ void encode_long_long_int(volatile long long int value,
+ uchar *grn_key);
+ void decode_long_long_int(const uchar *grn_key,
+ long long int *value);
+ void encode_float(volatile float value,
+ uint value_size,
+ uchar *grn_key);
+ void decode_float(const uchar *grn_key,
+ uint grn_key_size,
+ uchar *mysql_key);
+ void encode_double(volatile double value,
+ uint value_size,
+ uchar *grn_key);
+ void decode_double(const uchar *grn_key,
+ uint grn_key_size,
+ uchar *mysql_key);
+ void encode_reverse(const uchar *mysql_key,
+ uint mysql_key_size,
+ uchar *grn_key);
+ void decode_reverse(const uchar *grn_key,
+ uint grn_key_size,
+ uchar *mysql_key);
+ void encode_blob(const uchar *mysql_key,
+ uint *mysql_key_size,
+ Field *field,
+ uchar *grn_key);
+ };
+}
+
+#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 00000000..d1fdd471
--- /dev/null
+++ b/storage/mroonga/lib/mrn_mysqlservices.cpp
@@ -0,0 +1,28 @@
+/* -*- 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-1335 USA
+*/
+
+#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_operation.cpp b/storage/mroonga/lib/mrn_operation.cpp
new file mode 100644
index 00000000..e351945f
--- /dev/null
+++ b/storage/mroonga/lib/mrn_operation.cpp
@@ -0,0 +1,51 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_operation.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::Operation"
+
+namespace mrn {
+ Operation::Operation(mrn::Operations *operations,
+ const char *type,
+ const char *table_name,
+ size_t table_name_size)
+ : operations_(operations),
+ id_(operations_->start(type, table_name, table_name_size)) {
+ }
+
+ Operation::~Operation() {
+ MRN_DBUG_ENTER_METHOD();
+
+ operations_->finish(id_);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void Operation::record_target(grn_id record_id) {
+ MRN_DBUG_ENTER_METHOD();
+
+ operations_->record_target(id_, record_id);
+
+ DBUG_VOID_RETURN;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_operation.hpp b/storage/mroonga/lib/mrn_operation.hpp
new file mode 100644
index 00000000..9375cefb
--- /dev/null
+++ b/storage/mroonga/lib/mrn_operation.hpp
@@ -0,0 +1,42 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#ifndef MRN_OPERATION_HPP_
+#define MRN_OPERATION_HPP_
+
+#include <mrn_operations.hpp>
+
+namespace mrn {
+ class Operation {
+ public:
+ Operation(mrn::Operations *operations,
+ const char *type,
+ const char *table_name,
+ size_t table_name_size);
+ ~Operation();
+
+ void record_target(grn_id record_id);
+
+ private:
+ mrn::Operations *operations_;
+ grn_id id_;
+ };
+}
+
+#endif /* MRN_OPERATION_HPP_ */
diff --git a/storage/mroonga/lib/mrn_operations.cpp b/storage/mroonga/lib/mrn_operations.cpp
new file mode 100644
index 00000000..22a8901e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_operations.cpp
@@ -0,0 +1,401 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include <string.h>
+
+#include "mrn_operations.hpp"
+
+// for debug
+#define MRN_CLASS_NAME "mrn::Operations"
+
+#define TABLE_NAME "mroonga_operations"
+#define COLUMN_TYPE_NAME "type"
+#define COLUMN_TABLE_NAME "table"
+#define COLUMN_RECORD_NAME "record"
+
+namespace mrn {
+ Operations::Operations(grn_ctx *ctx)
+ : ctx_(ctx) {
+ MRN_DBUG_ENTER_METHOD();
+
+ GRN_TEXT_INIT(&text_buffer_, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_UINT32_INIT(&id_buffer_, 0);
+
+ table_ = grn_ctx_get(ctx_, TABLE_NAME, -1);
+ if (!table_) {
+ table_ = grn_table_create(ctx_,
+ TABLE_NAME, strlen(TABLE_NAME),
+ NULL,
+ GRN_OBJ_TABLE_NO_KEY | GRN_OBJ_PERSISTENT,
+ NULL, NULL);
+ columns_.type_ =
+ grn_column_create(ctx_, table_,
+ COLUMN_TYPE_NAME, strlen(COLUMN_TYPE_NAME),
+ NULL,
+ GRN_OBJ_COLUMN_SCALAR | GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx_, GRN_DB_SHORT_TEXT));
+ columns_.table_ =
+ grn_column_create(ctx_, table_,
+ COLUMN_TABLE_NAME, strlen(COLUMN_TABLE_NAME),
+ NULL,
+ GRN_OBJ_COLUMN_SCALAR | GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx_, GRN_DB_SHORT_TEXT));
+ columns_.record_ =
+ grn_column_create(ctx_, table_,
+ COLUMN_RECORD_NAME, strlen(COLUMN_RECORD_NAME),
+ NULL,
+ GRN_OBJ_COLUMN_SCALAR | GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx_, GRN_DB_UINT32));
+ } else {
+ columns_.type_ = grn_ctx_get(ctx_, TABLE_NAME "." COLUMN_TYPE_NAME, -1);
+ columns_.table_ = grn_ctx_get(ctx_, TABLE_NAME "." COLUMN_TABLE_NAME, -1);
+ columns_.record_ = grn_ctx_get(ctx_, TABLE_NAME "." COLUMN_RECORD_NAME, -1);
+ }
+
+ is_enabled_recording_ = true;
+
+ DBUG_VOID_RETURN;
+ }
+
+ Operations::~Operations() {
+ MRN_DBUG_ENTER_METHOD();
+
+ GRN_OBJ_FIN(ctx_, &id_buffer_);
+ GRN_OBJ_FIN(ctx_, &text_buffer_);
+
+ DBUG_VOID_RETURN;
+ }
+
+ bool Operations::is_locked() {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (grn_obj_is_locked(ctx_, table_) > 0)
+ DBUG_RETURN(true);
+
+ if (grn_obj_is_locked(ctx_, columns_.type_) > 0)
+ DBUG_RETURN(true);
+
+ if (grn_obj_is_locked(ctx_, columns_.table_) > 0)
+ DBUG_RETURN(true);
+
+ if (grn_obj_is_locked(ctx_, columns_.record_) > 0)
+ DBUG_RETURN(true);
+
+ DBUG_RETURN(false);
+ }
+
+ grn_id Operations::start(const char *type,
+ const char *table_name, size_t table_name_size) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!is_enabled_recording_) {
+ DBUG_RETURN(GRN_ID_NIL);
+ }
+
+ grn_id id = grn_table_add(ctx_, table_, NULL, 0, NULL);
+
+ GRN_TEXT_SETS(ctx_, &text_buffer_, type);
+ grn_obj_set_value(ctx_, columns_.type_, id, &text_buffer_, GRN_OBJ_SET);
+
+ GRN_TEXT_SET(ctx_, &text_buffer_, table_name, table_name_size);
+ grn_obj_set_value(ctx_, columns_.table_, id, &text_buffer_, GRN_OBJ_SET);
+
+ DBUG_RETURN(id);
+ }
+
+ void Operations::record_target(grn_id id, grn_id record_id) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!is_enabled_recording_) {
+ DBUG_VOID_RETURN;
+ }
+
+ GRN_UINT32_SET(ctx_, &id_buffer_, record_id);
+ grn_obj_set_value(ctx_, columns_.record_, id, &id_buffer_, GRN_OBJ_SET);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void Operations::finish(grn_id id) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!is_enabled_recording_) {
+ DBUG_VOID_RETURN;
+ }
+
+ grn_table_delete_by_id(ctx_, table_, id);
+
+ DBUG_VOID_RETURN;
+ }
+
+ void Operations::enable_recording() {
+ MRN_DBUG_ENTER_METHOD();
+
+ is_enabled_recording_ = true;
+
+ DBUG_VOID_RETURN;
+ }
+
+ void Operations::disable_recording() {
+ MRN_DBUG_ENTER_METHOD();
+
+ is_enabled_recording_ = false;
+
+ DBUG_VOID_RETURN;
+ }
+
+ grn_hash *Operations::collect_processing_table_names() {
+ MRN_DBUG_ENTER_METHOD();
+
+ grn_hash *table_names =
+ grn_hash_create(ctx_, NULL, GRN_TABLE_MAX_KEY_SIZE, 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_KEY_VAR_SIZE);
+
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx_, table_, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ GRN_LOG(ctx_, GRN_LOG_NOTICE,
+ "[operations] failed to open cursor: %s",
+ ctx_->errbuf);
+ DBUG_RETURN(table_names);
+ }
+
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx_, cursor))) {
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.table_, id, &text_buffer_);
+ if (GRN_TEXT_LEN(&text_buffer_) > 0) {
+ grn_hash_add(ctx_, table_names,
+ GRN_TEXT_VALUE(&text_buffer_),
+ GRN_TEXT_LEN(&text_buffer_),
+ NULL,
+ NULL);
+ }
+ }
+ grn_table_cursor_close(ctx_, cursor);
+
+ DBUG_RETURN(table_names);
+ }
+
+ int Operations::repair(const char *table_name, size_t table_name_size) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx_, table_, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ if (ctx_->rc) {
+ my_message(error, ctx_->errbuf, MYF(0));
+ } else {
+ my_message(error,
+ "mroonga: repair: "
+ "failed to open cursor for operations table",
+ MYF(0));
+ }
+ DBUG_RETURN(error);
+ }
+
+ grn_obj *target_table = grn_ctx_get(ctx_, table_name, table_name_size);
+ if (!target_table) {
+ GRN_LOG(ctx_, GRN_LOG_WARNING,
+ "table doesn't exist for auto repair: <%.*s>",
+ static_cast<int>(table_name_size), table_name);
+ }
+
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx_, cursor))) {
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.table_, id, &text_buffer_);
+ if (!((static_cast<size_t>(GRN_TEXT_LEN(&text_buffer_)) ==
+ table_name_size) &&
+ memcmp(GRN_TEXT_VALUE(&text_buffer_),
+ table_name,
+ table_name_size) == 0)) {
+ continue;
+ }
+
+ if (!target_table) {
+ grn_rc rc = grn_table_cursor_delete(ctx_, cursor);
+ if (rc != GRN_SUCCESS) {
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
+ GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: repair: failed to delete an orphan operation: "
+ "[%u]: <%.*s>[%s]: <%s>(%d)",
+ id,
+ static_cast<int>(table_name_size), table_name,
+ GRN_TEXT_VALUE(&text_buffer_),
+ ctx_->errbuf,
+ rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ continue;
+ }
+
+ GRN_BULK_REWIND(&id_buffer_);
+ grn_obj_get_value(ctx_, columns_.record_, id, &id_buffer_);
+ grn_id record_id = GRN_UINT32_VALUE(&id_buffer_);
+ if (record_id == GRN_ID_NIL) {
+ grn_rc rc = grn_table_cursor_delete(ctx_, cursor);
+ if (rc != GRN_SUCCESS) {
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
+ GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: repair: "
+ "failed to delete an operation that has no related record: "
+ "[%u]: <%.*s>[%s]: <%s>(%d)",
+ id,
+ static_cast<int>(table_name_size), table_name,
+ GRN_TEXT_VALUE(&text_buffer_),
+ ctx_->errbuf,
+ rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ continue;
+ }
+
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
+ GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
+ if (strcmp(GRN_TEXT_VALUE(&text_buffer_), "write") == 0 ||
+ strcmp(GRN_TEXT_VALUE(&text_buffer_), "delete") == 0) {
+ grn_rc rc = grn_table_delete_by_id(ctx_, target_table, record_id);
+ if (rc != GRN_SUCCESS) {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: repair: failed to delete an incomplete record: "
+ "[%u]: <%.*s>[%u]: <%s>(%d)",
+ id,
+ static_cast<int>(table_name_size), table_name,
+ record_id,
+ ctx_->errbuf,
+ rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+
+ rc = grn_table_cursor_delete(ctx_, cursor);
+ if (rc != GRN_SUCCESS) {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: repair: failed to delete an incomplete operation: "
+ "[%u]: <%.*s>[%u][%s]: <%s>(%d)",
+ id,
+ static_cast<int>(table_name_size), table_name,
+ record_id,
+ GRN_TEXT_VALUE(&text_buffer_),
+ ctx_->errbuf,
+ rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ } else if (strcmp(GRN_TEXT_VALUE(&text_buffer_), "update") == 0) {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ my_message(error,
+ "mroonga: repair: can't recover from crash while updating",
+ MYF(0));
+ break;
+ } else {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: repair: unknown operation type: "
+ "[%u]: <%.*s>[%u]: <%s>",
+ id,
+ static_cast<int>(table_name_size), table_name,
+ record_id,
+ GRN_TEXT_VALUE(&text_buffer_));
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx_, cursor);
+
+ DBUG_RETURN(error);
+ }
+
+ int Operations::clear(const char *table_name, size_t table_name_size) {
+ MRN_DBUG_ENTER_METHOD();
+
+ int error = 0;
+
+ grn_table_cursor *cursor;
+ cursor = grn_table_cursor_open(ctx_, table_, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ if (ctx_->rc) {
+ my_message(error, ctx_->errbuf, MYF(0));
+ } else {
+ my_message(error,
+ "mroonga: clear: "
+ "failed to open cursor for operations table",
+ MYF(0));
+ }
+ DBUG_RETURN(error);
+ }
+
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx_, cursor))) {
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.table_, id, &text_buffer_);
+ if ((static_cast<size_t>(GRN_TEXT_LEN(&text_buffer_)) ==
+ table_name_size) &&
+ memcmp(GRN_TEXT_VALUE(&text_buffer_),
+ table_name,
+ table_name_size) == 0) {
+ grn_rc rc = grn_table_cursor_delete(ctx_, cursor);
+ if (rc != GRN_SUCCESS) {
+ error = HA_ERR_CRASHED_ON_USAGE;
+ GRN_BULK_REWIND(&id_buffer_);
+ grn_obj_get_value(ctx_, columns_.record_, id, &id_buffer_);
+ GRN_BULK_REWIND(&text_buffer_);
+ grn_obj_get_value(ctx_, columns_.type_, id, &text_buffer_);
+ GRN_TEXT_PUTC(ctx_, &text_buffer_, '\0');
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "mroonga: clear: failed to delete an operation: "
+ "[%u]: <%.*s>[%u][%s]: <%s>(%d)",
+ id,
+ static_cast<int>(table_name_size), table_name,
+ GRN_UINT32_VALUE(&id_buffer_),
+ GRN_TEXT_VALUE(&text_buffer_),
+ ctx_->errbuf,
+ rc);
+ my_message(error, error_message, MYF(0));
+ break;
+ }
+ }
+ }
+ grn_table_cursor_close(ctx_, cursor);
+
+ DBUG_RETURN(error);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_operations.hpp b/storage/mroonga/lib/mrn_operations.hpp
new file mode 100644
index 00000000..803d9ab6
--- /dev/null
+++ b/storage/mroonga/lib/mrn_operations.hpp
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#ifndef MRN_OPERATIONS_HPP_
+#define MRN_OPERATIONS_HPP_
+
+#include <groonga.h>
+
+namespace mrn {
+ class Operations {
+ public:
+ Operations(grn_ctx *ctx);
+ ~Operations();
+
+ bool is_locked();
+
+ grn_id start(const char *type,
+ const char *table_name, size_t table_name_size);
+ void record_target(grn_id id, grn_id target_id);
+ void finish(grn_id id);
+
+ void enable_recording();
+ void disable_recording();
+
+ grn_hash *collect_processing_table_names();
+
+ int repair(const char *table_name, size_t table_name_size);
+ int clear(const char *table_name, size_t table_name_size);
+
+ private:
+ grn_ctx *ctx_;
+ grn_obj text_buffer_;
+ grn_obj id_buffer_;
+ grn_obj *table_;
+ struct {
+ grn_obj *type_;
+ grn_obj *table_;
+ grn_obj *record_;
+ } columns_;
+ bool is_enabled_recording_;
+ };
+}
+
+#endif /* MRN_OPERATIONS_HPP_ */
diff --git a/storage/mroonga/lib/mrn_parameters_parser.cpp b/storage/mroonga/lib/mrn_parameters_parser.cpp
new file mode 100644
index 00000000..a1db22bf
--- /dev/null
+++ b/storage/mroonga/lib/mrn_parameters_parser.cpp
@@ -0,0 +1,177 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#include "mrn_parameters_parser.hpp"
+
+#include <mrn_mysql_compat.h>
+#include <mrn_variables.hpp>
+
+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_(mrn_my_strndup(key, key_length, MYF(0))),
+ value_(mrn_my_strndup(value, value_length, MYF(0))) {
+ };
+ ~Parameter() {
+ if (key_) {
+ my_free(key_);
+ }
+ if (value_) {
+ my_free(value_);
+ }
+ };
+ };
+
+ 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 00000000..18ad769e
--- /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-1335 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 00000000..0e867b88
--- /dev/null
+++ b/storage/mroonga/lib/mrn_path_mapper.cpp
@@ -0,0 +1,229 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+
+#include "mrn_path_mapper.hpp"
+
+#include <string.h>
+
+namespace mrn {
+ char *PathMapper::default_path_prefix = NULL;
+ char *PathMapper::default_mysql_data_home_path = NULL;
+
+ PathMapper::PathMapper(const char *original_mysql_path,
+ const char *path_prefix,
+ const char *mysql_data_home_path)
+ : original_mysql_path_(original_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';
+ mysql_path_[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 (original_mysql_path_[0] == FN_CURLIB &&
+ original_mysql_path_[1] == FN_LIBCHAR) {
+ if (path_prefix_) {
+ strcpy(db_path_, path_prefix_);
+ }
+
+ int i = 2, j = strlen(db_path_), len;
+ len = strlen(original_mysql_path_);
+ while (original_mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_path_[j++] = original_mysql_path_[i++];
+ }
+ db_path_[j] = '\0';
+ } else if (mysql_data_home_path_) {
+ int len = strlen(original_mysql_path_);
+ int mysql_data_home_len = strlen(mysql_data_home_path_);
+ if (len > mysql_data_home_len &&
+ !strncmp(original_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 (original_mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_path_[j++] = original_mysql_path_[i++];
+ }
+ if (i == len) {
+ memcpy(db_path_, original_mysql_path_, len);
+ } else {
+ db_path_[j] = '\0';
+ }
+ } else {
+ strcpy(db_path_, original_mysql_path_);
+ }
+ } else {
+ strcpy(db_path_, original_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 (original_mysql_path_[0] == FN_CURLIB &&
+ original_mysql_path_[1] == FN_LIBCHAR) {
+ int i = 2, j = 0, len;
+ len = strlen(original_mysql_path_);
+ while (original_mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_name_[j++] = original_mysql_path_[i++];
+ }
+ db_name_[j] = '\0';
+ } else if (mysql_data_home_path_) {
+ int len = strlen(original_mysql_path_);
+ int mysql_data_home_len = strlen(mysql_data_home_path_);
+ if (len > mysql_data_home_len &&
+ !strncmp(original_mysql_path_,
+ mysql_data_home_path_,
+ mysql_data_home_len)) {
+ int i = mysql_data_home_len, j = 0;
+ while (original_mysql_path_[i] != FN_LIBCHAR && i < len) {
+ db_name_[j++] = original_mysql_path_[i++];
+ }
+ if (i == len) {
+ memcpy(db_name_, original_mysql_path_, len);
+ } else {
+ db_name_[j] = '\0';
+ }
+ } else {
+ strcpy(db_name_, original_mysql_path_);
+ }
+ } else {
+ strcpy(db_name_, original_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(original_mysql_path_);
+ int i = len, j = 0;
+ for (; original_mysql_path_[--i] != FN_LIBCHAR ;) {}
+ if (original_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++] = original_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(original_mysql_path_);
+ int i = len, j = 0;
+ for (; original_mysql_path_[--i] != FN_LIBCHAR ;) {}
+ for (; i < len ;) {
+ if (len - i - 1 >= 3 &&
+ strncmp(original_mysql_path_ + i + 1, "#P#", 3) == 0) {
+ break;
+ }
+ mysql_table_name_[j++] = original_mysql_path_[++i];
+ }
+ mysql_table_name_[j] = '\0';
+ return mysql_table_name_;
+ }
+
+ /**
+ * "./${db}/${table}" ==> "./${db}/${table}"
+ * "./${db}/${table}#P#xxx" ==> "./${db}/${table}"
+ */
+ const char *PathMapper::mysql_path() {
+ if (mysql_path_[0] != '\0') {
+ return mysql_path_;
+ }
+
+ int i;
+ int len = strlen(original_mysql_path_);
+ for (i = 0; i < len; i++) {
+ if (len - i >= 3 &&
+ strncmp(original_mysql_path_ + i, "#P#", 3) == 0) {
+ break;
+ }
+ mysql_path_[i] = original_mysql_path_[i];
+ }
+ mysql_path_[i] = '\0';
+ return mysql_path_;
+ }
+
+ bool PathMapper::is_internal_table_name() {
+ return mysql_table_name()[0] == '#';
+ }
+}
diff --git a/storage/mroonga/lib/mrn_path_mapper.hpp b/storage/mroonga/lib/mrn_path_mapper.hpp
new file mode 100644
index 00000000..60e99717
--- /dev/null
+++ b/storage/mroonga/lib/mrn_path_mapper.hpp
@@ -0,0 +1,55 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 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 *original_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();
+ const char *mysql_path();
+ bool is_internal_table_name();
+ bool is_temporary_table_name();
+ private:
+ const char *original_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];
+ char mysql_path_[MRN_MAX_PATH_SIZE];
+ };
+}
+
+#endif /* MRN_PATH_MAPPER_HPP_ */
diff --git a/storage/mroonga/lib/mrn_query_parser.cpp b/storage/mroonga/lib/mrn_query_parser.cpp
new file mode 100644
index 00000000..92387e25
--- /dev/null
+++ b/storage/mroonga/lib/mrn_query_parser.cpp
@@ -0,0 +1,361 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#include "mrn_query_parser.hpp"
+
+#include <mrn_variables.hpp>
+
+extern "C" {
+ /* Groonga's internal functions */
+ int grn_atoi(const char *nptr, const char *end, const char **rest);
+ uint grn_atoui(const char *nptr, const char *end, const char **rest);
+}
+
+#define MRN_CLASS_NAME "mrn::QueryParser"
+
+namespace mrn {
+ QueryParser::QueryParser(grn_ctx *ctx,
+ THD *thd,
+ grn_obj *expression,
+ grn_obj *default_column,
+ uint n_sections,
+ grn_obj *match_columns)
+ : ctx_(ctx),
+ thd_(thd),
+ expression_(expression),
+ default_column_(default_column),
+ n_sections_(n_sections),
+ match_columns_(match_columns) {
+ }
+
+ QueryParser::~QueryParser() {
+ }
+
+ grn_rc QueryParser::parse(const char *query, size_t query_length) {
+ MRN_DBUG_ENTER_METHOD();
+
+ const char *raw_query = NULL;
+ size_t raw_query_length = 0;
+ grn_operator default_operator = GRN_OP_OR;
+ grn_expr_flags expression_flags = 0;
+ parse_pragma(query,
+ query_length,
+ &raw_query,
+ &raw_query_length,
+ &default_operator,
+ &expression_flags);
+
+ grn_obj *default_column = default_column_;
+ if (match_columns_) {
+ default_column = match_columns_;
+ }
+ grn_rc rc = grn_expr_parse(ctx_,
+ expression_,
+ raw_query,
+ raw_query_length,
+ default_column,
+ GRN_OP_MATCH,
+ default_operator,
+ expression_flags);
+ if (rc != GRN_SUCCESS) {
+ char error_message[MRN_MESSAGE_BUFFER_SIZE];
+ snprintf(error_message, MRN_MESSAGE_BUFFER_SIZE,
+ "failed to parse fulltext search keyword: <%.*s>: <%s>",
+ static_cast<int>(query_length),
+ query,
+ ctx_->errbuf);
+ variables::ActionOnError action =
+ variables::get_action_on_fulltext_query_error(thd_);
+ switch (action) {
+ case variables::ACTION_ON_ERROR_ERROR:
+ my_message(ER_PARSE_ERROR, error_message, MYF(0));
+ break;
+ case variables::ACTION_ON_ERROR_ERROR_AND_LOG:
+ my_message(ER_PARSE_ERROR, error_message, MYF(0));
+ GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
+ break;
+ case variables::ACTION_ON_ERROR_IGNORE:
+ break;
+ case variables::ACTION_ON_ERROR_IGNORE_AND_LOG:
+ GRN_LOG(ctx_, GRN_LOG_ERROR, "%s", error_message);
+ break;
+ }
+ }
+
+ DBUG_RETURN(rc);
+ }
+
+ void QueryParser::parse_pragma(const char *query,
+ size_t query_length,
+ const char **raw_query,
+ size_t *raw_query_length,
+ grn_operator *default_operator,
+ grn_expr_flags *flags) {
+ MRN_DBUG_ENTER_METHOD();
+
+ const char *current_query = query;
+ size_t current_query_length = query_length;
+
+ *default_operator = GRN_OP_OR;
+
+ if (current_query_length >= 4 && memcmp(current_query, "*SS ", 4) == 0) {
+ *raw_query = current_query + 4;
+ *raw_query_length = current_query_length - 4;
+ *flags = GRN_EXPR_SYNTAX_SCRIPT;
+ DBUG_VOID_RETURN;
+ }
+
+ bool weight_specified = false;
+ *raw_query = query;
+ *raw_query_length = query_length;
+ *flags = default_expression_flags();
+ if (current_query_length >= 2 && current_query[0] == '*') {
+ bool parsed = false;
+ bool done = false;
+ current_query++;
+ current_query_length--;
+ while (!done) {
+ size_t consumed_query_length = 0;
+ switch (current_query[0]) {
+ case 'D':
+ if (parse_pragma_d(current_query + 1,
+ current_query_length - 1,
+ default_operator,
+ &consumed_query_length)) {
+ parsed = true;
+ consumed_query_length += 1;
+ current_query += consumed_query_length;
+ current_query_length -= consumed_query_length;
+ } else {
+ done = true;
+ }
+ break;
+ case 'W':
+ if (parse_pragma_w(current_query + 1,
+ current_query_length - 1,
+ &consumed_query_length)) {
+ parsed = true;
+ weight_specified = true;
+ consumed_query_length += 1;
+ current_query += consumed_query_length;
+ current_query_length -= consumed_query_length;
+ } else {
+ done = true;
+ }
+ break;
+ default:
+ done = true;
+ break;
+ }
+ }
+ if (parsed) {
+ *raw_query = current_query;
+ *raw_query_length = current_query_length;
+ }
+ }
+
+ // WORKAROUND: ignore the first '+' to support "+apple macintosh" pattern.
+ while (*raw_query_length > 0 && (*raw_query)[0] == ' ') {
+ (*raw_query)++;
+ (*raw_query_length)--;
+ }
+ if (*raw_query_length > 0 && (*raw_query)[0] == '+') {
+ (*raw_query)++;
+ (*raw_query_length)--;
+ }
+ if (!weight_specified && match_columns_) {
+ grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ bool QueryParser::parse_pragma_w(const char *query,
+ size_t query_length,
+ size_t *consumed_query_length) {
+ MRN_DBUG_ENTER_METHOD();
+
+ *consumed_query_length = 0;
+
+ grn_obj section_value_buffer;
+ GRN_UINT32_INIT(&section_value_buffer, 0);
+
+ MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(bool, specified_sections, n_sections_);
+ for (uint i = 0; i < n_sections_; ++i) {
+ specified_sections[i] = false;
+ }
+
+ uint n_weights = 0;
+ while (query_length >= 1) {
+ if (n_weights >= 1) {
+ if (query[0] != ',') {
+ break;
+ }
+ size_t n_used_query_length = 1;
+ *consumed_query_length += n_used_query_length;
+ query_length -= n_used_query_length;
+ query += n_used_query_length;
+ if (query_length == 0) {
+ break;
+ }
+ }
+
+ uint section = 0;
+ if ('1' <= query[0] && query[0] <= '9') {
+ const char *section_start = query;
+ const char *query_end = query + query_length;
+ const char *query_rest;
+ section = grn_atoui(section_start, query_end, &query_rest);
+ if (section_start == query_rest) {
+ break;
+ }
+ if (!(0 < section && section <= n_sections_)) {
+ break;
+ }
+ section -= 1;
+ specified_sections[section] = true;
+ size_t n_used_query_length = query_rest - query;
+ *consumed_query_length += n_used_query_length;
+ query_length -= n_used_query_length;
+ query += n_used_query_length;
+ } else {
+ break;
+ }
+
+ int weight = 1;
+ if (query_length >= 2 && query[0] == ':') {
+ const char *weight_start = query + 1;
+ const char *query_end = query + query_length;
+ const char *query_rest;
+ weight = grn_atoi(weight_start, query_end, &query_rest);
+ if (weight_start == query_rest) {
+ break;
+ }
+ size_t n_used_query_length = query_rest - query;
+ *consumed_query_length += n_used_query_length;
+ query_length -= n_used_query_length;
+ query += n_used_query_length;
+ }
+
+ n_weights++;
+
+ append_section(section,
+ &section_value_buffer,
+ weight,
+ n_weights);
+ }
+
+ for (uint section = 0; section < n_sections_; ++section) {
+ if (specified_sections[section]) {
+ continue;
+ }
+
+ ++n_weights;
+
+ int default_weight = 1;
+ append_section(section,
+ &section_value_buffer,
+ default_weight,
+ n_weights);
+ }
+ MRN_FREE_VARIABLE_LENGTH_ARRAYS(specified_sections);
+
+ GRN_OBJ_FIN(ctx_, &section_value_buffer);
+
+ DBUG_RETURN(n_weights > 0);
+ }
+
+ void QueryParser::append_section(uint section,
+ grn_obj *section_value_buffer,
+ int weight,
+ uint n_weights) {
+ MRN_DBUG_ENTER_METHOD();
+
+ if (!match_columns_) {
+ DBUG_VOID_RETURN;
+ }
+
+ grn_expr_append_obj(ctx_, match_columns_, default_column_, GRN_OP_PUSH, 1);
+ GRN_UINT32_SET(ctx_, section_value_buffer, section);
+ grn_expr_append_const(ctx_, match_columns_, section_value_buffer,
+ GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx_, match_columns_, GRN_OP_GET_MEMBER, 2);
+
+ if (weight != 1) {
+ grn_expr_append_const_int(ctx_, match_columns_, weight, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx_, match_columns_, GRN_OP_STAR, 2);
+ }
+
+ if (n_weights >= 2) {
+ grn_expr_append_op(ctx_, match_columns_, GRN_OP_OR, 2);
+ }
+
+ DBUG_VOID_RETURN;
+ }
+
+ bool QueryParser::parse_pragma_d(const char *query,
+ size_t query_length,
+ grn_operator *default_operator,
+ size_t *consumed_query_length) {
+ MRN_DBUG_ENTER_METHOD();
+
+ bool succeeded = true;
+ if (query_length >= 1 && query[0] == '+') {
+ *default_operator = GRN_OP_AND;
+ *consumed_query_length = 1;
+ } else if (query_length >= 1 && query[0] == '-') {
+ *default_operator = GRN_OP_AND_NOT;
+ *consumed_query_length = 1;
+ } else if (query_length >= 2 && memcmp(query, "OR", 2) == 0) {
+ *default_operator = GRN_OP_OR;
+ *consumed_query_length = 2;
+ } else {
+ succeeded = false;
+ }
+
+ DBUG_RETURN(succeeded);
+ }
+
+ grn_expr_flags QueryParser::default_expression_flags() {
+ MRN_DBUG_ENTER_METHOD();
+
+ ulonglong syntax_flags = variables::get_boolean_mode_syntax_flags(thd_);
+ grn_expr_flags expression_flags = 0;
+ if (syntax_flags == variables::BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT) {
+ expression_flags = GRN_EXPR_SYNTAX_QUERY | GRN_EXPR_ALLOW_LEADING_NOT;
+ } else {
+ if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_SYNTAX_SCRIPT) {
+ expression_flags |= GRN_EXPR_SYNTAX_SCRIPT;
+ } else {
+ expression_flags |= GRN_EXPR_SYNTAX_QUERY;
+ }
+ if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_COLUMN) {
+ expression_flags |= GRN_EXPR_ALLOW_COLUMN;
+ }
+ if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_UPDATE) {
+ expression_flags |= GRN_EXPR_ALLOW_UPDATE;
+ }
+ if (syntax_flags & variables::BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_LEADING_NOT) {
+ expression_flags |= GRN_EXPR_ALLOW_LEADING_NOT;
+ }
+ }
+
+ DBUG_RETURN(expression_flags);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_query_parser.hpp b/storage/mroonga/lib/mrn_query_parser.hpp
new file mode 100644
index 00000000..ba67394d
--- /dev/null
+++ b/storage/mroonga/lib/mrn_query_parser.hpp
@@ -0,0 +1,67 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#pragma once
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+
+#include <groonga.h>
+
+namespace mrn {
+ class QueryParser {
+ public:
+ QueryParser(grn_ctx *ctx,
+ THD *thd,
+ grn_obj *expression,
+ grn_obj *default_column,
+ uint n_sections,
+ grn_obj *match_columns=NULL);
+ ~QueryParser();
+
+ grn_rc parse(const char *query, size_t query_length);
+ void parse_pragma(const char *query,
+ size_t query_length,
+ const char **raw_query,
+ size_t *raw_query_length,
+ grn_operator *default_operator,
+ grn_expr_flags *flags);
+
+ private:
+ grn_ctx *ctx_;
+ THD *thd_;
+ grn_obj *expression_;
+ grn_obj *default_column_;
+ uint n_sections_;
+ grn_obj *match_columns_;
+
+ bool parse_pragma_w(const char *query,
+ size_t query_length,
+ size_t *consumed_query_length);
+ void append_section(uint section,
+ grn_obj *section_value_buffer,
+ int weight,
+ uint n_weights);
+ bool parse_pragma_d(const char *query,
+ size_t query_length,
+ grn_operator *default_operator,
+ size_t *consumed_query_length);
+ grn_expr_flags default_expression_flags();
+ };
+}
diff --git a/storage/mroonga/lib/mrn_smart_bitmap.cpp b/storage/mroonga/lib/mrn_smart_bitmap.cpp
new file mode 100644
index 00000000..f8fd4f72
--- /dev/null
+++ b/storage/mroonga/lib/mrn_smart_bitmap.cpp
@@ -0,0 +1,42 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#include "mrn_smart_bitmap.hpp"
+
+namespace mrn {
+ SmartBitmap::SmartBitmap(MY_BITMAP *bitmap)
+ : bitmap_(bitmap) {
+ }
+
+ SmartBitmap::~SmartBitmap() {
+ if (bitmap_) {
+ bitmap_free(bitmap_);
+ }
+ }
+
+ MY_BITMAP *SmartBitmap::get() {
+ return bitmap_;
+ }
+
+ MY_BITMAP *SmartBitmap::release() {
+ MY_BITMAP *bitmap = bitmap_;
+ bitmap_ = NULL;
+ return bitmap;
+ }
+}
diff --git a/storage/mroonga/lib/mrn_smart_bitmap.hpp b/storage/mroonga/lib/mrn_smart_bitmap.hpp
new file mode 100644
index 00000000..5cc80df0
--- /dev/null
+++ b/storage/mroonga/lib/mrn_smart_bitmap.hpp
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#pragma once
+
+#include <mrn_mysql.h>
+#include <my_bitmap.h>
+
+namespace mrn {
+ class SmartBitmap {
+ public:
+ SmartBitmap(MY_BITMAP *bitmap);
+ ~SmartBitmap();
+
+ MY_BITMAP *get();
+ MY_BITMAP *release();
+ private:
+ MY_BITMAP *bitmap_;
+ };
+}
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 00000000..845a5fb1
--- /dev/null
+++ b/storage/mroonga/lib/mrn_smart_grn_obj.cpp
@@ -0,0 +1,59 @@
+/* -*- 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-1335 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_;
+ }
+
+ grn_obj *SmartGrnObj::release() {
+ grn_obj *obj = obj_;
+ obj_ = NULL;
+ 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 00000000..9158145e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_smart_grn_obj.hpp
@@ -0,0 +1,40 @@
+/* -*- 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-1335 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();
+ grn_obj *release();
+ };
+}
+
+#endif // MRN_SMART_GRN_OBJ_HPP_
diff --git a/storage/mroonga/lib/mrn_table_fields_offset_mover.cpp b/storage/mroonga/lib/mrn_table_fields_offset_mover.cpp
new file mode 100644
index 00000000..bc2d2f25
--- /dev/null
+++ b/storage/mroonga/lib/mrn_table_fields_offset_mover.cpp
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#include "mrn_table_fields_offset_mover.hpp"
+
+namespace mrn {
+ FieldTableChanger::FieldTableChanger(TABLE *table,
+ TABLE *new_table)
+ : old_table_(table),
+ new_table_(new_table) {
+ my_ptrdiff_t diff =
+ PTR_BYTE_DIFF(new_table_->record[0], old_table_->record[0]);
+ uint n_columns = old_table_->s->fields;
+ for (uint i = 0; i < n_columns; ++i) {
+ Field *field = old_table_->field[i];
+ field->move_field_offset(diff);
+ field->table = new_table;
+ }
+ }
+
+ FieldTableChanger::~FieldTableChanger() {
+ my_ptrdiff_t diff =
+ PTR_BYTE_DIFF(new_table_->record[0], old_table_->record[0]);
+ uint n_columns = old_table_->s->fields;
+ for (uint i = 0; i < n_columns; ++i) {
+ Field *field = old_table_->field[i];
+ field->move_field_offset(-diff);
+ field->table = old_table_;
+ }
+ }
+}
diff --git a/storage/mroonga/lib/mrn_table_fields_offset_mover.hpp b/storage/mroonga/lib/mrn_table_fields_offset_mover.hpp
new file mode 100644
index 00000000..94f96772
--- /dev/null
+++ b/storage/mroonga/lib/mrn_table_fields_offset_mover.hpp
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#pragma once
+
+#include <mrn_mysql.h>
+
+namespace mrn {
+ class FieldTableChanger {
+ public:
+ FieldTableChanger(TABLE *table, TABLE *new_table);
+ ~FieldTableChanger();
+ private:
+ TABLE *old_table_;
+ TABLE *new_table_;
+ };
+}
diff --git a/storage/mroonga/lib/mrn_time_converter.cpp b/storage/mroonga/lib/mrn_time_converter.cpp
new file mode 100644
index 00000000..9bb8d89a
--- /dev/null
+++ b/storage/mroonga/lib/mrn_time_converter.cpp
@@ -0,0 +1,295 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#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;
+ }
+
+ long long int TimeConverter::mysql_datetime_to_grn_time(long long int mysql_datetime,
+ bool *truncated) {
+ MRN_DBUG_ENTER_METHOD();
+
+ MYSQL_TIME mysql_time;
+ mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME;
+ mysql_time.neg = 0;
+ mysql_time.second_part = 0;
+ mysql_time.second = (mysql_datetime % 100);
+ mysql_time.minute = (mysql_datetime / 100 % 100);
+ mysql_time.hour = (mysql_datetime / 10000 % 100);
+ mysql_time.day = (mysql_datetime / 1000000 % 100);
+ mysql_time.month = (mysql_datetime / 100000000 % 100);
+ mysql_time.year = (mysql_datetime / 10000000000LL % 10000);
+
+ long long int grn_time = mysql_time_to_grn_time(&mysql_time, truncated);
+
+ DBUG_RETURN(grn_time);
+ }
+
+ long long int TimeConverter::grn_time_to_mysql_datetime(long long int grn_time) {
+ MRN_DBUG_ENTER_METHOD();
+
+ MYSQL_TIME mysql_time;
+ mysql_time.time_type = MYSQL_TIMESTAMP_DATETIME;
+
+ grn_time_to_mysql_time(grn_time, &mysql_time);
+
+ long long int mysql_datetime =
+ (mysql_time.second * 1) +
+ (mysql_time.minute * 100) +
+ (mysql_time.hour * 10000) +
+ (mysql_time.day * 1000000) +
+ (mysql_time.month * 100000000) +
+ (mysql_time.year * 10000000000LL);
+
+ DBUG_RETURN(mysql_datetime);
+ }
+}
diff --git a/storage/mroonga/lib/mrn_time_converter.hpp b/storage/mroonga/lib/mrn_time_converter.hpp
new file mode 100644
index 00000000..2f7f00f5
--- /dev/null
+++ b/storage/mroonga/lib/mrn_time_converter.hpp
@@ -0,0 +1,51 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#ifndef MRN_TIME_CONVERTER_HPP_
+#define MRN_TIME_CONVERTER_HPP_
+
+#include <mrn_mysql_compat.h>
+
+#include <groonga.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 mysql_datetime_to_grn_time(long long int mysql_datetime,
+ 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);
+ long long int grn_time_to_mysql_datetime(long long int grn_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_value_decoder.cpp b/storage/mroonga/lib/mrn_value_decoder.cpp
new file mode 100644
index 00000000..3b2eed67
--- /dev/null
+++ b/storage/mroonga/lib/mrn_value_decoder.cpp
@@ -0,0 +1,75 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#include "mrn_value_decoder.hpp"
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_DEST_IS_POINTER
+#endif
+
+namespace mrn {
+ namespace value_decoder {
+ void decode(uint16 *dest, const uchar *source) {
+ MRN_DBUG_ENTER_FUNCTION();
+#ifdef MRN_DEST_IS_POINTER
+ ushortget(dest, source);
+#else
+ uint16 value;
+ ushortget(value, source);
+ *dest = value;
+#endif
+ DBUG_VOID_RETURN;
+ };
+
+ void decode(float *dest, const uchar *source) {
+ MRN_DBUG_ENTER_FUNCTION();
+#ifdef MRN_DEST_IS_POINTER
+ float4get(dest, source);
+#else
+ float value;
+ float4get(value, source);
+ *dest = value;
+#endif
+ DBUG_VOID_RETURN;
+ };
+
+ void decode(double *dest, const uchar *source) {
+ MRN_DBUG_ENTER_FUNCTION();
+#ifdef MRN_DEST_IS_POINTER
+ float8get(dest, source);
+#else
+ double value;
+ float8get(value, source);
+ *dest = value;
+#endif
+ DBUG_VOID_RETURN;
+ }
+ void decode(long long int *dest, const uchar *source) {
+ MRN_DBUG_ENTER_FUNCTION();
+#ifdef MRN_DEST_IS_POINTER
+ longlongget(dest, source);
+#else
+ long long int value;
+ longlongget(value, source);
+ *dest = value;
+#endif
+ DBUG_VOID_RETURN;
+ }
+ }
+}
diff --git a/storage/mroonga/lib/mrn_value_decoder.hpp b/storage/mroonga/lib/mrn_value_decoder.hpp
new file mode 100644
index 00000000..7919a88e
--- /dev/null
+++ b/storage/mroonga/lib/mrn_value_decoder.hpp
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#ifndef MRN_VALUE_DECODER_HPP_
+#define MRN_VALUE_DECODER_HPP_
+
+#include <mrn_mysql.h>
+
+namespace mrn {
+ namespace value_decoder {
+ void decode(uint16 *dest, const uchar *source);
+ void decode(float *dest, const uchar *source);
+ void decode(double *dest, const uchar *source);
+ void decode(long long int *dest, const uchar *source);
+ }
+}
+
+#endif // MRN_VALUE_DECODER_HPP_
diff --git a/storage/mroonga/lib/mrn_windows.hpp b/storage/mroonga/lib/mrn_windows.hpp
new file mode 100644
index 00000000..cfe35b41
--- /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-1335 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_ */
diff --git a/storage/mroonga/mrn_constants.hpp b/storage/mroonga/mrn_constants.hpp
new file mode 100644
index 00000000..9f21eb32
--- /dev/null
+++ b/storage/mroonga/mrn_constants.hpp
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ 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-1335 USA
+*/
+
+#ifndef MRN_CONSTANTS_HPP_
+#define MRN_CONSTANTS_HPP_
+
+#include <limits.h>
+
+#include <groonga.h>
+
+#define MRN_BUFFER_SIZE 1024
+#define MRN_MAX_KEY_SIZE GRN_TABLE_MAX_KEY_SIZE
+#if defined(MAX_PATH)
+# define MRN_MAX_PATH_SIZE (MAX_PATH + 1)
+#elif defined(PATH_MAX)
+# define MRN_MAX_PATH_SIZE (PATH_MAX)
+#elif defined(MAXPATHLEN)
+# define MRN_MAX_PATH_SIZE (MAXPATHLEN)
+#else
+# define MRN_MAX_PATH_SIZE (256)
+#endif
+#define MRN_DB_FILE_SUFFIX ".mrn"
+#define MRN_LOG_FILE_PATH "groonga.log"
+#define MRN_COLUMN_NAME_ID "_id"
+#define MRN_COLUMN_NAME_KEY "_key"
+#define MRN_COLUMN_NAME_SCORE "_score"
+#ifndef MRN_DEFAULT_TOKENIZER
+# define MRN_DEFAULT_TOKENIZER "TokenBigram"
+#endif
+
+#endif /* MRN_CONSTANTS_HPP_ */
diff --git a/storage/mroonga/mrn_err.h b/storage/mroonga/mrn_err.h
new file mode 100644
index 00000000..46eb24cc
--- /dev/null
+++ b/storage/mroonga/mrn_err.h
@@ -0,0 +1,46 @@
+/*
+ Copyright(C) 2011 Kentoku SHIBA
+ Copyright(C) 2014-2015 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-1335 USA
+*/
+
+#ifndef MRN_ERR_H_
+#define MRN_ERR_H_
+
+#define ER_MRN_INVALID_TABLE_PARAM_NUM 16501
+#define ER_MRN_INVALID_TABLE_PARAM_STR "The table parameter '%-.64s' is invalid"
+#define ER_MRN_CHARSET_NOT_SUPPORT_NUM 16502
+#define ER_MRN_CHARSET_NOT_SUPPORT_STR "The character set '%s[%s]' is not supported by groonga"
+#define ER_MRN_GEOMETRY_NOT_SUPPORT_NUM 16503
+#define ER_MRN_GEOMETRY_NOT_SUPPORT_STR "This geometry type is not supported. Groonga is supported point only"
+#define ER_MRN_ERROR_FROM_GROONGA_NUM 16504
+#define ER_MRN_ERROR_FROM_GROONGA_STR "Error from Groonga [%s]"
+#define ER_MRN_INVALID_NULL_VALUE_NUM 16505
+#define ER_MRN_INVALID_NULL_VALUE_STR "NULL value can't be used for %s"
+#define ER_MRN_UNSUPPORTED_COLUMN_FLAG_NUM 16506
+#define ER_MRN_UNSUPPORTED_COLUMN_FLAG_STR \
+ "The column flag '%-.64s' is unsupported. It is ignored"
+#define ER_MRN_INVALID_COLUMN_FLAG_NUM 16507
+#define ER_MRN_INVALID_COLUMN_FLAG_STR \
+ "The column flag '%-.64s' is invalid. It is ignored"
+#define ER_MRN_INVALID_INDEX_FLAG_NUM 16508
+#define ER_MRN_INVALID_INDEX_FLAG_STR \
+ "The index flag '%-.64s' is invalid. It is ignored"
+#define ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_NUM 16509
+#define ER_MRN_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN_STR \
+ "Index for virtual generated column is not supported: %s"
+
+#endif /* MRN_ERR_H_ */
diff --git a/storage/mroonga/mrn_macro.hpp b/storage/mroonga/mrn_macro.hpp
new file mode 100644
index 00000000..56576983
--- /dev/null
+++ b/storage/mroonga/mrn_macro.hpp
@@ -0,0 +1,30 @@
+/*
+ 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-1335 USA
+*/
+
+#ifndef MRN_MACRO_HPP_
+#define MRN_MACRO_HPP_
+
+#ifdef __cplusplus
+# define MRN_BEGIN_DECLS extern "C" {
+# define MRN_END_DECLS }
+#else
+# define MRN_BEGIN_DECLS
+# define MRN_END_DECLS
+#endif
+
+#endif /* MRN_MACRO_HPP_ */
diff --git a/storage/mroonga/mrn_mysql.h b/storage/mroonga/mrn_mysql.h
new file mode 100644
index 00000000..9573caa9
--- /dev/null
+++ b/storage/mroonga/mrn_mysql.h
@@ -0,0 +1,74 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ 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-1335 USA
+*/
+
+#ifndef MRN_MYSQL_H_
+#define MRN_MYSQL_H_
+
+#ifdef HAVE_CONFIG_H
+# include <my_global.h>
+/* We need to undefine them because my_config.h defines them. :< */
+# undef VERSION
+# undef PACKAGE
+# undef PACKAGE_BUGREPORT
+# undef PACKAGE_NAME
+# undef PACKAGE_STRING
+# undef PACKAGE_TARNAME
+# undef PACKAGE_VERSION
+#endif
+
+#include <mrn_version.h>
+
+#ifdef FORCE_FAST_MUTEX_DISABLED
+# ifdef MY_PTHREAD_FASTMUTEX
+# undef MY_PTHREAD_FASTMUTEX
+# endif
+#endif
+
+#define MYSQL_SERVER 1
+#include <mysql_version.h>
+
+#ifdef MARIADB_BASE_VERSION
+# define MRN_MARIADB_P 1
+#endif
+
+#include <sql_const.h>
+#include <sql_class.h>
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID < 80002)
+# include <probes_mysql.h>
+#endif
+#include <sql_partition.h>
+#include <rpl_filter.h>
+
+#define MRN_MESSAGE_BUFFER_SIZE 1024
+
+#define MRN_DBUG_ENTER_FUNCTION() DBUG_ENTER(__FUNCTION__)
+
+#if !defined(DBUG_OFF) && !defined(_lint)
+# define MRN_DBUG_ENTER_METHOD() \
+ char method_name[MRN_MESSAGE_BUFFER_SIZE]; \
+ method_name[0] = '\0'; \
+ strcat(method_name, MRN_CLASS_NAME); \
+ strcat(method_name, "::"); \
+ strcat(method_name, __FUNCTION__); \
+ DBUG_ENTER(method_name)
+#else
+# define MRN_DBUG_ENTER_METHOD() MRN_DBUG_ENTER_FUNCTION()
+#endif
+
+#endif /* MRN_MYSQL_H_ */
diff --git a/storage/mroonga/mrn_mysql_compat.h b/storage/mroonga/mrn_mysql_compat.h
new file mode 100644
index 00000000..538aaf51
--- /dev/null
+++ b/storage/mroonga/mrn_mysql_compat.h
@@ -0,0 +1,422 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2017 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-1335 USA
+*/
+
+#ifndef MRN_MYSQL_COMPAT_H_
+#define MRN_MYSQL_COMPAT_H_
+
+#include "mrn_mysql.h"
+
+#if MYSQL_VERSION_ID >= 50604
+# define MRN_HAVE_MYSQL_TYPE_TIMESTAMP2
+# define MRN_HAVE_MYSQL_TYPE_DATETIME2
+# define MRN_HAVE_MYSQL_TYPE_TIME2
+#endif
+
+#if MYSQL_VERSION_ID >= 50709 && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_MYSQL_TYPE_JSON
+#endif
+
+#if MYSQL_VERSION_ID < 50603
+ typedef MYSQL_ERROR Sql_condition;
+#endif
+
+#if defined(MRN_MARIADB_P)
+# if MYSQL_VERSION_ID < 100000
+ typedef COST_VECT Cost_estimate;
+# endif
+#endif
+
+#ifndef MRN_MARIADB_P
+ typedef char *range_id_t;
+#endif
+
+#if defined(MRN_MARIADB_P) || MYSQL_VERSION_ID < 80002
+ typedef st_select_lex SELECT_LEX;
+#endif
+
+#if MYSQL_VERSION_ID >= 50609
+# define MRN_KEY_HAS_USER_DEFINED_KEYPARTS
+#endif
+
+#ifdef MRN_KEY_HAS_USER_DEFINED_KEYPARTS
+# define KEY_N_KEY_PARTS(key) (key)->user_defined_key_parts
+#else
+# define KEY_N_KEY_PARTS(key) (key)->key_parts
+#endif
+
+# define mrn_init_alloc_root(PTR, SZ1, SZ2, FLAG) \
+ init_alloc_root(mrn_memory_key, PTR, SZ1, SZ2, FLAG)
+
+#if MYSQL_VERSION_ID < 100002 || !defined(MRN_MARIADB_P)
+# define GTS_TABLE 0
+#endif
+
+#if MYSQL_VERSION_ID >= 50607
+# if MYSQL_VERSION_ID >= 100007 && defined(MRN_MARIADB_P)
+# define MRN_GET_ERROR_MESSAGE thd_get_error_message(current_thd)
+# define MRN_GET_ERROR_NUMBER thd_get_error_number(current_thd)
+# define MRN_GET_CURRENT_ROW_FOR_WARNING(thd) thd_get_error_row(thd)
+# else
+# define MRN_GET_ERROR_MESSAGE current_thd->get_stmt_da()->message()
+# define MRN_GET_ERROR_NUMBER current_thd->get_stmt_da()->sql_errno()
+# if MYSQL_VERSION_ID >= 50706
+# define MRN_GET_CURRENT_ROW_FOR_WARNING(thd) \
+ thd->get_stmt_da()->current_row_for_condition()
+# else
+# define MRN_GET_CURRENT_ROW_FOR_WARNING(thd) \
+ thd->get_stmt_da()->current_row_for_warning()
+# endif
+# endif
+#else
+# define MRN_GET_ERROR_MESSAGE current_thd->stmt_da->message()
+# define MRN_GET_ERROR_NUMBER current_thd->stmt_da->sql_errno()
+# define MRN_GET_CURRENT_ROW_FOR_WARNING(thd) thd->warning_info->current_row_for_warning()
+#endif
+
+#if MYSQL_VERSION_ID >= 50607 && !defined(MRN_MARIADB_P)
+# define MRN_ITEM_HAVE_ITEM_NAME
+#endif
+
+#if MYSQL_VERSION_ID < 100000
+# define MRN_HAVE_TABLE_DEF_CACHE
+#endif
+
+#if defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100009
+# define MRN_HAVE_TDC_ACQUIRE_SHARE
+# if MYSQL_VERSION_ID < 100200
+# define MRN_TDC_ACQUIRE_SHARE_REQUIRE_KEY
+# endif
+#endif
+
+#if MYSQL_VERSION_ID >= 50613
+# define MRN_HAVE_ALTER_INFO
+#endif
+
+#if MYSQL_VERSION_ID >= 50603
+# define MRN_HAVE_GET_TABLE_DEF_KEY
+#endif
+
+#if defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100004
+# define MRN_TABLE_SHARE_HAVE_LOCK_SHARE
+#endif
+
+#ifndef TIME_FUZZY_DATE
+/* For MariaDB 10. */
+# ifdef TIME_FUZZY_DATES
+# define TIME_FUZZY_DATE TIME_FUZZY_DATES
+# endif
+#endif
+
+#if MYSQL_VERSION_ID >= 100007 && defined(MRN_MARIADB_P)
+# define MRN_USE_MYSQL_DATA_HOME
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_SEVERITY_WARNING Sql_condition::SL_WARNING
+#else
+# define MRN_SEVERITY_WARNING Sql_condition::WARN_LEVEL_WARN
+#endif
+
+#ifdef HAVE_PSI_MEMORY_INTERFACE
+#define MRN_HAVE_PSI_MEMORY_KEY
+#endif
+
+# define mrn_my_malloc(size, flags) \
+ my_malloc(mrn_memory_key, size, flags)
+# define mrn_my_strdup(string, flags) \
+ my_strdup(mrn_memory_key, string, flags)
+# define mrn_my_strndup(string, size, flags) \
+ my_strndup(mrn_memory_key, string, size, flags)
+# define mrn_my_multi_malloc(flags, ...) \
+ my_multi_malloc(mrn_memory_key, flags, __VA_ARGS__)
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_STRING_FREE(string) string.mem_free();
+#else
+# define MRN_STRING_FREE(string) string.free();
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_THD_DB_PATH(thd) ((thd)->db().str)
+#else
+# define MRN_THD_DB_PATH(thd) ((thd)->db.str)
+#endif
+
+#ifndef INT_MAX64
+# define INT_MAX64 LONGLONG_MAX
+#endif
+
+#ifdef UINT_MAX
+# define UINT_MAX64 UINT_MAX
+#else
+# define UINT_MAX64 LONGLONG_MAX
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define mrn_my_stpmov(dst, src) my_stpmov(dst, src)
+#else
+# define mrn_my_stpmov(dst, src) strmov(dst, src)
+#endif
+
+#if MYSQL_VERSION_ID >= 50607
+# if !defined(MRN_MARIADB_P)
+# define MRN_HAVE_SQL_OPTIMIZER_H
+# endif
+#endif
+
+#if MYSQL_VERSION_ID >= 50600 && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_BINLOG_H
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_SPATIAL
+#elif defined(HAVE_SPATIAL)
+# define MRN_HAVE_SPATIAL
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_FORMAT_STRING_LENGTH "zu"
+#else
+# define MRN_FORMAT_STRING_LENGTH "u"
+#endif
+
+#ifdef MRN_MARIADB_P
+# define MRN_SUPPORT_CUSTOM_OPTIONS
+#endif
+
+#ifdef MRN_MARIADB_P
+# define MRN_HAVE_ITEM_EQUAL_FIELDS_ITERATOR
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_SELECT_LEX_GET_WHERE_COND(select_lex) \
+ ((select_lex)->where_cond())
+# define MRN_SELECT_LEX_GET_HAVING_COND(select_lex) \
+ ((select_lex)->having_cond())
+# define MRN_SELECT_LEX_GET_ACTIVE_OPTIONS(select_lex) \
+ ((select_lex)->active_options())
+#else
+# define MRN_SELECT_LEX_GET_WHERE_COND(select_lex) \
+ ((select_lex)->where)
+# define MRN_SELECT_LEX_GET_HAVING_COND(select_lex) \
+ ((select_lex)->having)
+# define MRN_SELECT_LEX_GET_ACTIVE_OPTIONS(select_lex) \
+ ((select_lex)->options)
+#endif
+
+# define mrn_init_sql_alloc(thd, mem_root) \
+ init_sql_alloc(mrn_memory_key, mem_root, \
+ TABLE_ALLOC_BLOCK_SIZE, \
+ 0, \
+ MYF(thd->slave_thread ? 0 : MY_THREAD_SPECIFIC))
+
+#ifdef MRN_MARIADB_P
+# define MRN_ABORT_ON_WARNING(thd) thd->abort_on_warning
+#else
+# if MYSQL_VERSION_ID >= 50706
+# define MRN_ABORT_ON_WARNING(thd) thd->is_strict_mode()
+# else
+# define MRN_ABORT_ON_WARNING(thd) thd->abort_on_warning
+# endif
+#endif
+
+#define MRN_ERROR_CODE_DATA_TRUNCATE(thd) \
+ (MRN_ABORT_ON_WARNING(thd) ? ER_WARN_DATA_OUT_OF_RANGE : WARN_DATA_TRUNCATED)
+
+# define mrn_my_hash_init(hash, \
+ charset, \
+ default_array_elements, \
+ key_offset, \
+ key_length, \
+ get_key, \
+ free_element, \
+ flags) \
+ my_hash_init(mrn_memory_key, hash, \
+ charset, \
+ default_array_elements, \
+ key_offset, \
+ key_length, \
+ get_key, \
+ free_element, \
+ flags)
+
+#if defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100000
+# define mrn_strconvert(from_cs, \
+ from, \
+ from_length, \
+ to_cs, \
+ to, \
+ to_length, \
+ errors) \
+ strconvert((from_cs), \
+ (from), \
+ (from_length), \
+ (to_cs), \
+ (to), \
+ (to_length), \
+ (errors))
+#else
+# define mrn_strconvert(from_cs, \
+ from, \
+ from_length, \
+ to_cs, \
+ to, \
+ to_length, \
+ errors) \
+ strconvert((from_cs), \
+ (from), \
+ (to_cs), \
+ (to), \
+ (to_length), \
+ (errors))
+#endif
+
+#if MYSQL_VERSION_ID >= 50717 && !defined(MRN_MARIADB_P)
+# define mrn_is_directory_separator(c) \
+ is_directory_separator((c))
+#else
+# define mrn_is_directory_separator(c) \
+ (c == FN_LIBCHAR || c == FN_LIBCHAR2)
+#endif
+
+#if ((MYSQL_VERSION_ID < 50636) || \
+ (MYSQL_VERSION_ID >= 50700 && MYSQL_VERSION_ID < 50718)) && !defined(MRN_MARIADB_P)
+# define MRN_HAVE_MYSQL_FIELD_PART_OF_KEY_NOT_CLUSTERED
+#endif
+
+#if defined(MRN_MARIADB_P) && \
+ ((MYSQL_VERSION_ID >= 100207) || \
+ ((MYSQL_VERSION_ID >= 100126) && (MYSQL_VERSION_ID < 100200)) || \
+ ((MYSQL_VERSION_ID >= 100032) && (MYSQL_VERSION_ID < 100100)) || \
+ ((MYSQL_VERSION_ID >= 50557) && (MYSQL_VERSION_ID < 100000)))
+# define mrn_create_partition_name(out, \
+ out_length, \
+ in1, \
+ in2, \
+ name_variant, \
+ translate) \
+ create_partition_name(out, out_length, in1, in2, name_variant, translate)
+# define mrn_create_subpartition_name(out, \
+ out_length, \
+ in1, \
+ in2, \
+ in3, \
+ name_variant) \
+ create_subpartition_name(out, out_length, in1, in2, in3, name_variant)
+#else
+# define mrn_create_partition_name(out, \
+ out_length, \
+ in1, \
+ in2, \
+ name_variant, \
+ translate) \
+ (create_partition_name(out, in1, in2, name_variant, translate), 0)
+# define mrn_create_subpartition_name(out, \
+ out_length, \
+ in1, \
+ in2, \
+ in3, \
+ name_variant) \
+ (create_subpartition_name(out, in1, in2, in3, name_variant), 0)
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+# define ITEM_SUM_GET_NEST_LEVEL(sum_item) (sum_item)->base_select->nest_level
+# define ITEM_SUM_GET_AGGR_LEVEL(sum_item) (sum_item)->aggr_select->nest_level
+# define ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item) (sum_item)->max_aggr_level
+#else
+# define ITEM_SUM_GET_NEST_LEVEL(sum_item) (sum_item)->nest_level
+# define ITEM_SUM_GET_AGGR_LEVEL(sum_item) (sum_item)->aggr_level
+# define ITEM_SUM_GET_MAX_AGGR_LEVEL(sum_item) (sum_item)->max_arg_level
+#endif
+
+#if (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 80002)
+ typedef bool mrn_bool;
+#else
+ typedef my_bool mrn_bool;
+#endif
+
+#define MRN_ALLOCATE_VARIABLE_LENGTH_ARRAYS(type, variable_name, variable_size) \
+ type *variable_name = \
+ (type *)mrn_my_malloc(sizeof(type) * (variable_size), MYF(MY_WME))
+#define MRN_FREE_VARIABLE_LENGTH_ARRAYS(variable_name) \
+ my_free(variable_name)
+
+#if ((defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 100203)) || \
+ (!defined(MRN_MARIADB_P) && MYSQL_VERSION_ID >= 50711)
+# define MRN_ALTER_INPLACE_INFO_ADD_VIRTUAL_COLUMN \
+ ALTER_ADD_VIRTUAL_COLUMN
+# define MRN_ALTER_INPLACE_INFO_ADD_STORED_BASE_COLUMN \
+ ALTER_ADD_STORED_BASE_COLUMN
+# define MRN_ALTER_INPLACE_INFO_ADD_STORED_GENERATED_COLUMN \
+ ALTER_ADD_STORED_GENERATED_COLUMN
+#else
+# define MRN_ALTER_INPLACE_INFO_ADD_VIRTUAL_COLUMN 0
+# define MRN_ALTER_INPLACE_INFO_ADD_STORED_BASE_COLUMN \
+ Alter_inplace_info::ADD_COLUMN
+# define MRN_ALTER_INPLACE_INFO_ADD_STORED_GENERATED_COLUMN 0
+#endif
+
+#if (defined(HA_CAN_VIRTUAL_COLUMNS) || defined(HA_GENERATED_COLUMNS))
+# define MRN_SUPPORT_GENERATED_COLUMNS
+#endif
+
+#ifdef MRN_MARIADB_P
+# if (MYSQL_VERSION_ID >= 100200)
+# define MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field) \
+ (!field->stored_in_db())
+# define MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field) \
+ (field->vcol_info && field->vcol_info->is_stored())
+# elif (MYSQL_VERSION_ID >= 50500)
+# define MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field) \
+ (!field->stored_in_db)
+# define MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field) \
+ (field->vcol_info && field->vcol_info->is_stored())
+# else
+# define MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field) false
+# define MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field) false
+# endif
+#else
+# if (MYSQL_VERSION_ID >= 50708)
+# define MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field) \
+ (field->is_virtual_gcol())
+# define MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field) \
+ (field->is_gcol() && !field->is_virtual_gcol())
+# elif (MYSQL_VERSION_ID >= 50706)
+# define MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field) \
+ (!field->stored_in_db)
+# define MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field) \
+ (field->gcol_info && field->gcol_info->get_field_stored())
+# else
+# define MRN_GENERATED_COLUMNS_FIELD_IS_VIRTUAL(field) false
+# define MRN_GENERATED_COLUMNS_FIELD_IS_STORED(field) false
+# endif
+#endif
+
+#ifdef MRN_MARIADB_P
+# if (MYSQL_VERSION_ID >= 100203)
+# define MRN_GENERATED_COLUMNS_UPDATE_VIRTUAL_FIELD(table, field) \
+ (table->update_virtual_field(field,false))
+# else
+# define MRN_GENERATED_COLUMNS_UPDATE_VIRTUAL_FIELD(table, field) \
+ (field->vcol_info->expr_item->save_in_field(field, 0))
+# endif
+#endif
+
+#endif /* MRN_MYSQL_COMPAT_H_ */
diff --git a/storage/mroonga/mrn_table.cpp b/storage/mroonga/mrn_table.cpp
new file mode 100644
index 00000000..037a6a59
--- /dev/null
+++ b/storage/mroonga/mrn_table.cpp
@@ -0,0 +1,1198 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2017 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-1335 USA
+*/
+
+#include "mrn_mysql.h"
+
+#if MYSQL_VERSION_ID >= 50500
+# include <sql_servers.h>
+# include <sql_base.h>
+#endif
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+# include <partition_info.h>
+#endif
+#include <sql_plugin.h>
+
+#include "mrn_err.h"
+#include "mrn_table.hpp"
+#include "mrn_mysql_compat.h"
+#include "mrn_variables.hpp"
+#include <mrn_lock.hpp>
+
+#ifdef MRN_MARIADB_P
+# if MYSQL_VERSION_ID >= 100100
+# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name), TRUE)
+# else
+# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name))
+# endif
+#else
+# if MYSQL_VERSION_ID >= 50603
+# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name), TRUE)
+# else
+# define MRN_HA_RESOLVE_BY_NAME(name) ha_resolve_by_name(NULL, (name))
+# endif
+#endif
+
+#if MYSQL_VERSION_ID >= 50706 && !defined(MRN_MARIADB_P)
+# define MRN_PLUGIN_DATA(plugin, type) plugin_data<type>(plugin)
+#else
+# define MRN_PLUGIN_DATA(plugin, type) plugin_data(plugin, type)
+#endif
+
+#define LEX_STRING_IS_EMPTY(string) \
+ ((string).length == 0 || !(string).str || (string).str[0] == '\0')
+
+#define MRN_DEFAULT_STR "DEFAULT"
+#define MRN_DEFAULT_LEN (sizeof(MRN_DEFAULT_STR) - 1)
+#define MRN_GROONGA_STR "GROONGA"
+#define MRN_GROONGA_LEN (sizeof(MRN_GROONGA_STR) - 1)
+
+#ifdef MRN_HAVE_TABLE_DEF_CACHE
+extern HASH *mrn_table_def_cache;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_PSI_INTERFACE
+# ifdef WIN32
+# ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
+extern PSI_mutex_key *mrn_table_share_lock_share;
+# endif
+extern PSI_mutex_key *mrn_table_share_lock_ha_data;
+# endif
+extern PSI_mutex_key mrn_share_mutex_key;
+extern PSI_mutex_key mrn_long_term_share_auto_inc_mutex_key;
+#endif
+
+extern HASH mrn_open_tables;
+extern mysql_mutex_t mrn_open_tables_mutex;
+extern HASH mrn_long_term_share;
+extern mysql_mutex_t mrn_long_term_share_mutex;
+extern char *mrn_default_tokenizer;
+extern char *mrn_default_wrapper_engine;
+extern handlerton *mrn_hton_ptr;
+extern HASH mrn_allocated_thds;
+extern mysql_mutex_t mrn_allocated_thds_mutex;
+
+static char *mrn_get_string_between_quote(const char *ptr)
+{
+ const char *start_ptr, *end_ptr, *tmp_ptr, *esc_ptr;
+ bool find_flg = FALSE, esc_flg = FALSE;
+ MRN_DBUG_ENTER_FUNCTION();
+
+ start_ptr = strchr(ptr, '\'');
+ end_ptr = strchr(ptr, '"');
+ if (start_ptr && (!end_ptr || start_ptr < end_ptr))
+ {
+ tmp_ptr = ++start_ptr;
+ while (!find_flg)
+ {
+ if (!(end_ptr = strchr(tmp_ptr, '\'')))
+ DBUG_RETURN(NULL);
+ esc_ptr = tmp_ptr;
+ while (!find_flg)
+ {
+ esc_ptr = strchr(esc_ptr, '\\');
+ if (!esc_ptr || esc_ptr > end_ptr)
+ find_flg = TRUE;
+ else if (esc_ptr == end_ptr - 1)
+ {
+ esc_flg = TRUE;
+ tmp_ptr = end_ptr + 1;
+ break;
+ } else {
+ esc_flg = TRUE;
+ esc_ptr += 2;
+ }
+ }
+ }
+ } else if (end_ptr)
+ {
+ start_ptr = end_ptr;
+ tmp_ptr = ++start_ptr;
+ while (!find_flg)
+ {
+ if (!(end_ptr = strchr(tmp_ptr, '"')))
+ DBUG_RETURN(NULL);
+ esc_ptr = tmp_ptr;
+ while (!find_flg)
+ {
+ esc_ptr = strchr(esc_ptr, '\\');
+ if (!esc_ptr || esc_ptr > end_ptr)
+ find_flg = TRUE;
+ else if (esc_ptr == end_ptr - 1)
+ {
+ esc_flg = TRUE;
+ tmp_ptr = end_ptr + 1;
+ break;
+ } else {
+ esc_flg = TRUE;
+ esc_ptr += 2;
+ }
+ }
+ }
+ } else
+ DBUG_RETURN(NULL);
+
+ size_t length = end_ptr - start_ptr;
+ char *extracted_string = (char *)mrn_my_malloc(length + 1, MYF(MY_WME));
+ if (esc_flg) {
+ size_t extracted_index = 0;
+ const char *current_ptr = start_ptr;
+ while (current_ptr < end_ptr) {
+ if (*current_ptr != '\\') {
+ extracted_string[extracted_index] = *current_ptr;
+ ++extracted_index;
+ current_ptr++;
+ continue;
+ }
+
+ if (current_ptr + 1 == end_ptr) {
+ break;
+ }
+
+ switch (*(current_ptr + 1))
+ {
+ case 'b':
+ extracted_string[extracted_index] = '\b';
+ break;
+ case 'n':
+ extracted_string[extracted_index] = '\n';
+ break;
+ case 'r':
+ extracted_string[extracted_index] = '\r';
+ break;
+ case 't':
+ extracted_string[extracted_index] = '\t';
+ break;
+ default:
+ extracted_string[extracted_index] = *(current_ptr + 1);
+ break;
+ }
+ ++extracted_index;
+ }
+ } else {
+ memcpy(extracted_string, start_ptr, length);
+ extracted_string[length] = '\0';
+ }
+
+ DBUG_RETURN(extracted_string);
+}
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+void mrn_get_partition_info(const char *table_name, uint table_name_length,
+ const TABLE *table, partition_element **part_elem,
+ partition_element **sub_elem)
+{
+ partition_info *part_info = table->part_info;
+ partition_element *tmp_part_elem = NULL, *tmp_sub_elem = NULL;
+ bool tmp_flg = FALSE, tmp_find_flg = FALSE;
+ MRN_DBUG_ENTER_FUNCTION();
+ *part_elem = NULL;
+ *sub_elem = NULL;
+ if (!part_info)
+ DBUG_VOID_RETURN;
+
+ if (table_name && !memcmp(table_name + table_name_length - 5, "#TMP#", 5))
+ tmp_flg = TRUE;
+
+ DBUG_PRINT("info", ("mroonga table_name=%s", table_name));
+ List_iterator<partition_element> part_it(part_info->partitions);
+ while ((*part_elem = part_it++))
+ {
+ if ((*part_elem)->subpartitions.elements)
+ {
+ List_iterator<partition_element> sub_it((*part_elem)->subpartitions);
+ while ((*sub_elem = sub_it++))
+ {
+ char subpartition_name[FN_REFLEN + 1];
+ int error = mrn_create_subpartition_name(subpartition_name,
+ sizeof(subpartition_name),
+ table->s->path.str,
+ (*part_elem)->partition_name,
+ (*sub_elem)->partition_name,
+ NORMAL_PART_NAME);
+ if (error != 0)
+ DBUG_VOID_RETURN;
+ DBUG_PRINT("info", ("mroonga subpartition name=%s", subpartition_name));
+ if (table_name &&
+ memcmp(table_name, subpartition_name, table_name_length + 1) == 0)
+ DBUG_VOID_RETURN;
+ if (
+ tmp_flg &&
+ table_name &&
+ *(subpartition_name + table_name_length - 5) == '\0' &&
+ memcmp(table_name, subpartition_name, table_name_length - 5) == 0
+ ) {
+ tmp_part_elem = *part_elem;
+ tmp_sub_elem = *sub_elem;
+ tmp_flg = FALSE;
+ tmp_find_flg = TRUE;
+ }
+ }
+ } else {
+ char partition_name[FN_REFLEN + 1];
+ int error = mrn_create_partition_name(partition_name,
+ sizeof(partition_name),
+ table->s->path.str,
+ (*part_elem)->partition_name,
+ NORMAL_PART_NAME,
+ TRUE);
+ if (error != 0)
+ DBUG_VOID_RETURN;
+ DBUG_PRINT("info", ("mroonga partition name=%s", partition_name));
+ if (table_name &&
+ memcmp(table_name, partition_name, table_name_length + 1) == 0)
+ DBUG_VOID_RETURN;
+ if (
+ tmp_flg &&
+ table_name &&
+ *(partition_name + table_name_length - 5) == '\0' &&
+ memcmp(table_name, partition_name, table_name_length - 5) == 0
+ ) {
+ tmp_part_elem = *part_elem;
+ tmp_flg = FALSE;
+ tmp_find_flg = TRUE;
+ }
+ }
+ }
+ if (tmp_find_flg)
+ {
+ *part_elem = tmp_part_elem;
+ *sub_elem = tmp_sub_elem;
+ DBUG_PRINT("info", ("mroonga tmp find"));
+ DBUG_VOID_RETURN;
+ }
+ *part_elem = NULL;
+ *sub_elem = NULL;
+ DBUG_PRINT("info", ("mroonga no hit"));
+ DBUG_VOID_RETURN;
+}
+#endif
+
+#define MRN_PARAM_STR_LEN(name) name ## _length
+#define MRN_PARAM_STR(title_name, param_name) \
+ if (!strncasecmp(tmp_ptr, title_name, title_length)) \
+ { \
+ DBUG_PRINT("info", ("mroonga " title_name " start")); \
+ if (!share->param_name) \
+ { \
+ if ((share->param_name = mrn_get_string_between_quote( \
+ start_ptr))) \
+ share->MRN_PARAM_STR_LEN(param_name) = strlen(share->param_name); \
+ else { \
+ error = ER_MRN_INVALID_TABLE_PARAM_NUM; \
+ my_printf_error(error, ER_MRN_INVALID_TABLE_PARAM_STR, \
+ MYF(0), tmp_ptr); \
+ goto error; \
+ } \
+ DBUG_PRINT("info", ("mroonga " title_name "=%s", share->param_name)); \
+ } \
+ break; \
+ }
+
+#define MRN_PARAM_STR_LIST(title_name, param_name, param_pos) \
+ if (!strncasecmp(tmp_ptr, title_name, title_length)) \
+ { \
+ DBUG_PRINT("info", ("mroonga " title_name " start")); \
+ if (share->param_name && !share->param_name[param_pos]) \
+ { \
+ if ((share->param_name[param_pos] = mrn_get_string_between_quote( \
+ start_ptr))) \
+ share->MRN_PARAM_STR_LEN(param_name)[param_pos] = \
+ strlen(share->param_name[param_pos]); \
+ else { \
+ error = ER_MRN_INVALID_TABLE_PARAM_NUM; \
+ my_printf_error(error, ER_MRN_INVALID_TABLE_PARAM_STR, \
+ MYF(0), tmp_ptr); \
+ goto error; \
+ } \
+ DBUG_PRINT("info", ("mroonga " title_name "[%d]=%s", param_pos, \
+ share->param_name[param_pos])); \
+ } \
+ break; \
+ }
+
+int mrn_parse_table_param(MRN_SHARE *share, TABLE *table)
+{
+ int i, error = 0;
+ int title_length;
+ const char *sprit_ptr[2];
+ const char *tmp_ptr, *start_ptr;
+ char *params_string = NULL;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ partition_element *part_elem;
+ partition_element *sub_elem;
+#endif
+ MRN_DBUG_ENTER_FUNCTION();
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ mrn_get_partition_info(share->table_name, share->table_name_length, table,
+ &part_elem, &sub_elem);
+#endif
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ for (i = 4; i > 0; i--)
+#else
+ for (i = 2; i > 0; i--)
+#endif
+ {
+ const char *params_string_value = NULL;
+ uint params_string_length = 0;
+ switch (i)
+ {
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+ case 4:
+ if (!sub_elem || !sub_elem->part_comment)
+ continue;
+ DBUG_PRINT("info", ("mroonga create sub comment string"));
+ params_string_value = sub_elem->part_comment;
+ params_string_length = strlen(params_string_value);
+ DBUG_PRINT("info",
+ ("mroonga sub comment string=%s", params_string_value));
+ break;
+ case 3:
+ if (!part_elem || !part_elem->part_comment)
+ continue;
+ DBUG_PRINT("info", ("mroonga create part comment string"));
+ params_string_value = part_elem->part_comment;
+ params_string_length = strlen(params_string_value);
+ DBUG_PRINT("info",
+ ("mroonga part comment string=%s", params_string_value));
+ break;
+#endif
+ case 2:
+ if (LEX_STRING_IS_EMPTY(table->s->comment))
+ continue;
+ DBUG_PRINT("info", ("mroonga create comment string"));
+ params_string_value = table->s->comment.str;
+ params_string_length = table->s->comment.length;
+ DBUG_PRINT("info",
+ ("mroonga comment string=%.*s",
+ params_string_length, params_string_value));
+ break;
+ default:
+ if (LEX_STRING_IS_EMPTY(table->s->connect_string))
+ continue;
+ DBUG_PRINT("info", ("mroonga create connect_string string"));
+ params_string_value = table->s->connect_string.str;
+ params_string_length = table->s->connect_string.length;
+ DBUG_PRINT("info",
+ ("mroonga connect_string=%.*s",
+ params_string_length, params_string_value));
+ break;
+ }
+
+ if (!params_string_value) {
+ continue;
+ }
+
+ {
+ params_string = mrn_my_strndup(params_string_value,
+ params_string_length,
+ MYF(MY_WME));
+ if (!params_string) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error;
+ }
+
+ sprit_ptr[0] = params_string;
+ while (sprit_ptr[0])
+ {
+ if ((sprit_ptr[1] = strchr(sprit_ptr[0], ',')))
+ {
+ sprit_ptr[1]++;
+ }
+ tmp_ptr = sprit_ptr[0];
+ sprit_ptr[0] = sprit_ptr[1];
+ while (*tmp_ptr == ' ' || *tmp_ptr == '\r' ||
+ *tmp_ptr == '\n' || *tmp_ptr == '\t')
+ tmp_ptr++;
+
+ if (*tmp_ptr == '\0')
+ continue;
+
+ DBUG_PRINT("info", ("mroonga title_str=%s", tmp_ptr));
+ title_length = 0;
+ start_ptr = tmp_ptr;
+ while (*start_ptr != ' ' && *start_ptr != '\'' &&
+ *start_ptr != '"' && *start_ptr != '\0' &&
+ *start_ptr != '\r' && *start_ptr != '\n' &&
+ *start_ptr != '\t' && *start_ptr != ',')
+ {
+ title_length++;
+ start_ptr++;
+ }
+ DBUG_PRINT("info", ("mroonga title_length=%u", title_length));
+
+ switch (title_length)
+ {
+ case 6:
+ MRN_PARAM_STR("engine", engine);
+ break;
+ case 10:
+ MRN_PARAM_STR("normalizer", normalizer);
+ break;
+ case 13:
+ MRN_PARAM_STR("token_filters", token_filters);
+ break;
+ case 17:
+ MRN_PARAM_STR("default_tokenizer", default_tokenizer);
+ break;
+ default:
+ break;
+ }
+ }
+
+ my_free(params_string);
+ params_string = NULL;
+ }
+ }
+
+ if (!share->engine && mrn_default_wrapper_engine)
+ {
+ share->engine_length = strlen(mrn_default_wrapper_engine);
+ if (
+ !(share->engine = mrn_my_strndup(mrn_default_wrapper_engine,
+ share->engine_length,
+ MYF(MY_WME)))
+ ) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error;
+ }
+ }
+
+ if (share->engine)
+ {
+ LEX_CSTRING engine_name;
+ if (
+ (
+ share->engine_length == MRN_DEFAULT_LEN &&
+ !strncasecmp(share->engine, MRN_DEFAULT_STR, MRN_DEFAULT_LEN)
+ ) ||
+ (
+ share->engine_length == MRN_GROONGA_LEN &&
+ !strncasecmp(share->engine, MRN_GROONGA_STR, MRN_GROONGA_LEN)
+ )
+ ) {
+ my_free(share->engine);
+ share->engine = NULL;
+ share->engine_length = 0;
+ } else {
+ engine_name.str = share->engine;
+ engine_name.length = share->engine_length;
+ if (!(share->plugin = MRN_HA_RESOLVE_BY_NAME(&engine_name)))
+ {
+ my_error(ER_UNKNOWN_STORAGE_ENGINE, MYF(0), share->engine);
+ error = ER_UNKNOWN_STORAGE_ENGINE;
+ goto error;
+ }
+ share->hton = MRN_PLUGIN_DATA(share->plugin, handlerton *);
+ share->wrapper_mode = TRUE;
+ }
+ }
+
+error:
+ if (params_string)
+ my_free(params_string);
+ DBUG_RETURN(error);
+}
+
+bool mrn_is_geo_key(const KEY *key_info)
+{
+ return key_info->algorithm == HA_KEY_ALG_UNDEF &&
+ KEY_N_KEY_PARTS(key_info) == 1 &&
+ key_info->key_part[0].field->type() == MYSQL_TYPE_GEOMETRY;
+}
+
+int mrn_add_index_param(MRN_SHARE *share, KEY *key_info, int i)
+{
+ int error;
+ char *param_string = NULL;
+#if MYSQL_VERSION_ID >= 50500
+ int title_length;
+ char *sprit_ptr[2];
+ char *tmp_ptr, *start_ptr;
+#endif
+ THD *thd = current_thd;
+ MRN_DBUG_ENTER_FUNCTION();
+
+#if MYSQL_VERSION_ID >= 50500
+ if (key_info->comment.length == 0)
+ {
+ if (share->key_tokenizer[i]) {
+ my_free(share->key_tokenizer[i]);
+ }
+ share->key_tokenizer[i] = mrn_my_strdup(mrn_default_tokenizer, MYF(MY_WME));
+ if (!share->key_tokenizer[i]) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error;
+ }
+ share->key_tokenizer_length[i] = strlen(share->key_tokenizer[i]);
+
+ DBUG_RETURN(0);
+ }
+ DBUG_PRINT("info", ("mroonga create comment string"));
+ if (
+ !(param_string = mrn_my_strndup(key_info->comment.str,
+ key_info->comment.length,
+ MYF(MY_WME)))
+ ) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error_alloc_param_string;
+ }
+ DBUG_PRINT("info", ("mroonga comment string=%s", param_string));
+
+ sprit_ptr[0] = param_string;
+ while (sprit_ptr[0])
+ {
+ if ((sprit_ptr[1] = strchr(sprit_ptr[0], ',')))
+ {
+ *sprit_ptr[1] = '\0';
+ sprit_ptr[1]++;
+ }
+ tmp_ptr = sprit_ptr[0];
+ sprit_ptr[0] = sprit_ptr[1];
+ while (*tmp_ptr == ' ' || *tmp_ptr == '\r' ||
+ *tmp_ptr == '\n' || *tmp_ptr == '\t')
+ tmp_ptr++;
+
+ if (*tmp_ptr == '\0')
+ continue;
+
+ title_length = 0;
+ start_ptr = tmp_ptr;
+ while (*start_ptr != ' ' && *start_ptr != '\'' &&
+ *start_ptr != '"' && *start_ptr != '\0' &&
+ *start_ptr != '\r' && *start_ptr != '\n' &&
+ *start_ptr != '\t')
+ {
+ title_length++;
+ start_ptr++;
+ }
+
+ switch (title_length)
+ {
+ case 5:
+ MRN_PARAM_STR_LIST("table", index_table, i);
+ break;
+ case 6:
+ push_warning_printf(thd, MRN_SEVERITY_WARNING,
+ ER_WARN_DEPRECATED_SYNTAX,
+ ER(ER_WARN_DEPRECATED_SYNTAX),
+ "parser", "tokenizer");
+ MRN_PARAM_STR_LIST("parser", key_tokenizer, i);
+ break;
+ case 9:
+ MRN_PARAM_STR_LIST("tokenizer", key_tokenizer, i);
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ if (!share->key_tokenizer[i]) {
+ share->key_tokenizer[i] = mrn_my_strdup(mrn_default_tokenizer, MYF(MY_WME));
+ if (!share->key_tokenizer[i]) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error;
+ }
+ share->key_tokenizer_length[i] = strlen(share->key_tokenizer[i]);
+ }
+
+ if (param_string)
+ my_free(param_string);
+ DBUG_RETURN(0);
+
+error:
+ if (param_string)
+ my_free(param_string);
+#if MYSQL_VERSION_ID >= 50500
+error_alloc_param_string:
+#endif
+ DBUG_RETURN(error);
+}
+
+int mrn_parse_index_param(MRN_SHARE *share, TABLE *table)
+{
+ int error;
+ MRN_DBUG_ENTER_FUNCTION();
+ for (uint i = 0; i < table->s->keys; i++)
+ {
+ KEY *key_info = &table->s->key_info[i];
+ bool is_wrapper_mode = share->engine != NULL;
+
+ if (is_wrapper_mode) {
+ if (!(key_info->flags & HA_FULLTEXT) && !mrn_is_geo_key(key_info)) {
+ continue;
+ }
+ }
+
+ if ((error = mrn_add_index_param(share, key_info, i)))
+ goto error;
+ }
+ DBUG_RETURN(0);
+
+error:
+ DBUG_RETURN(error);
+}
+
+int mrn_add_column_param(MRN_SHARE *share, Field *field, int i)
+{
+ int error;
+ char *param_string = NULL;
+ int title_length;
+ char *sprit_ptr[2];
+ char *tmp_ptr, *start_ptr;
+
+ MRN_DBUG_ENTER_FUNCTION();
+
+ if (share->wrapper_mode) {
+ DBUG_RETURN(0);
+ }
+
+ DBUG_PRINT("info", ("mroonga create comment string"));
+ if (
+ !(param_string = mrn_my_strndup(field->comment.str,
+ field->comment.length,
+ MYF(MY_WME)))
+ ) {
+ error = HA_ERR_OUT_OF_MEM;
+ goto error_alloc_param_string;
+ }
+ DBUG_PRINT("info", ("mroonga comment string=%s", param_string));
+
+ sprit_ptr[0] = param_string;
+ while (sprit_ptr[0])
+ {
+ if ((sprit_ptr[1] = strchr(sprit_ptr[0], ',')))
+ {
+ *sprit_ptr[1] = '\0';
+ sprit_ptr[1]++;
+ }
+ tmp_ptr = sprit_ptr[0];
+ sprit_ptr[0] = sprit_ptr[1];
+ while (*tmp_ptr == ' ' || *tmp_ptr == '\r' ||
+ *tmp_ptr == '\n' || *tmp_ptr == '\t')
+ tmp_ptr++;
+
+ if (*tmp_ptr == '\0')
+ continue;
+
+ title_length = 0;
+ start_ptr = tmp_ptr;
+ while (*start_ptr != ' ' && *start_ptr != '\'' &&
+ *start_ptr != '"' && *start_ptr != '\0' &&
+ *start_ptr != '\r' && *start_ptr != '\n' &&
+ *start_ptr != '\t')
+ {
+ title_length++;
+ start_ptr++;
+ }
+
+ switch (title_length)
+ {
+ case 4:
+ MRN_PARAM_STR_LIST("type", col_type, i);
+ break;
+ case 5:
+ MRN_PARAM_STR_LIST("flags", col_flags, i);
+ break;
+ case 12:
+ MRN_PARAM_STR_LIST("groonga_type", col_type, i);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (param_string)
+ my_free(param_string);
+ DBUG_RETURN(0);
+
+error:
+ if (param_string)
+ my_free(param_string);
+error_alloc_param_string:
+ DBUG_RETURN(error);
+}
+
+int mrn_parse_column_param(MRN_SHARE *share, TABLE *table)
+{
+ int error;
+ MRN_DBUG_ENTER_FUNCTION();
+ for (uint i = 0; i < table->s->fields; i++)
+ {
+ Field *field = table->s->field[i];
+
+ if (LEX_STRING_IS_EMPTY(field->comment)) {
+ continue;
+ }
+
+ if ((error = mrn_add_column_param(share, field, i)))
+ goto error;
+ }
+ DBUG_RETURN(0);
+
+error:
+ DBUG_RETURN(error);
+}
+
+int mrn_free_share_alloc(
+ MRN_SHARE *share
+) {
+ uint i;
+ MRN_DBUG_ENTER_FUNCTION();
+ if (share->engine)
+ my_free(share->engine);
+ if (share->default_tokenizer)
+ my_free(share->default_tokenizer);
+ if (share->normalizer)
+ my_free(share->normalizer);
+ if (share->token_filters)
+ my_free(share->token_filters);
+ for (i = 0; i < share->table_share->keys; i++)
+ {
+ if (share->index_table && share->index_table[i])
+ my_free(share->index_table[i]);
+ if (share->key_tokenizer[i])
+ my_free(share->key_tokenizer[i]);
+ }
+ for (i = 0; i < share->table_share->fields; i++)
+ {
+ if (share->col_flags && share->col_flags[i])
+ my_free(share->col_flags[i]);
+ if (share->col_type && share->col_type[i])
+ my_free(share->col_type[i]);
+ }
+ DBUG_RETURN(0);
+}
+
+void mrn_free_long_term_share(MRN_LONG_TERM_SHARE *long_term_share)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ {
+ mrn::Lock lock(&mrn_long_term_share_mutex);
+ my_hash_delete(&mrn_long_term_share, (uchar*) long_term_share);
+ }
+ mysql_mutex_destroy(&long_term_share->auto_inc_mutex);
+ my_free(long_term_share);
+ DBUG_VOID_RETURN;
+}
+
+MRN_LONG_TERM_SHARE *mrn_get_long_term_share(const char *table_name,
+ uint table_name_length,
+ int *error)
+{
+ MRN_LONG_TERM_SHARE *long_term_share;
+ char *tmp_name;
+ MRN_DBUG_ENTER_FUNCTION();
+ DBUG_PRINT("info", ("mroonga: table_name=%s", table_name));
+ mrn::Lock lock(&mrn_long_term_share_mutex);
+ if (!(long_term_share = (MRN_LONG_TERM_SHARE*)
+ my_hash_search(&mrn_long_term_share, (uchar*) table_name,
+ table_name_length)))
+ {
+ if (!(long_term_share = (MRN_LONG_TERM_SHARE *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &long_term_share, sizeof(*long_term_share),
+ &tmp_name, table_name_length + 1,
+ NullS))
+ ) {
+ *error = HA_ERR_OUT_OF_MEM;
+ goto error_alloc_long_term_share;
+ }
+ long_term_share->table_name = tmp_name;
+ long_term_share->table_name_length = table_name_length;
+ memcpy(long_term_share->table_name, table_name, table_name_length);
+ if (mysql_mutex_init(mrn_long_term_share_auto_inc_mutex_key,
+ &long_term_share->auto_inc_mutex,
+ MY_MUTEX_INIT_FAST) != 0)
+ {
+ *error = HA_ERR_OUT_OF_MEM;
+ goto error_init_auto_inc_mutex;
+ }
+ if (my_hash_insert(&mrn_long_term_share, (uchar*) long_term_share))
+ {
+ *error = HA_ERR_OUT_OF_MEM;
+ goto error_hash_insert;
+ }
+ }
+ DBUG_RETURN(long_term_share);
+
+error_hash_insert:
+ mysql_mutex_destroy(&long_term_share->auto_inc_mutex);
+error_init_auto_inc_mutex:
+ my_free(long_term_share);
+error_alloc_long_term_share:
+ DBUG_RETURN(NULL);
+}
+
+MRN_SHARE *mrn_get_share(const char *table_name, TABLE *table, int *error)
+{
+ MRN_SHARE *share;
+ char *tmp_name, **index_table, **key_tokenizer, **col_flags, **col_type;
+ uint length, *wrap_key_nr, *index_table_length;
+ uint *key_tokenizer_length, *col_flags_length, *col_type_length, i, j;
+ KEY *wrap_key_info;
+ TABLE_SHARE *wrap_table_share;
+ MRN_DBUG_ENTER_FUNCTION();
+ length = (uint) strlen(table_name);
+ mrn::Lock lock(&mrn_open_tables_mutex);
+ if (!(share = (MRN_SHARE*) my_hash_search(&mrn_open_tables,
+ (uchar*) table_name, length)))
+ {
+ if (!(share = (MRN_SHARE *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &share, sizeof(*share),
+ &tmp_name, length + 1,
+ &index_table, sizeof(char *) * table->s->keys,
+ &index_table_length, sizeof(uint) * table->s->keys,
+ &key_tokenizer, sizeof(char *) * table->s->keys,
+ &key_tokenizer_length, sizeof(uint) * table->s->keys,
+ &col_flags, sizeof(char *) * table->s->fields,
+ &col_flags_length, sizeof(uint) * table->s->fields,
+ &col_type, sizeof(char *) * table->s->fields,
+ &col_type_length, sizeof(uint) * table->s->fields,
+ &wrap_key_nr, sizeof(*wrap_key_nr) * table->s->keys,
+ &wrap_key_info, sizeof(*wrap_key_info) * table->s->keys,
+ &wrap_table_share, sizeof(*wrap_table_share),
+ NullS))
+ ) {
+ *error = HA_ERR_OUT_OF_MEM;
+ goto error_alloc_share;
+ }
+ share->use_count = 0;
+ share->table_name_length = length;
+ share->table_name = tmp_name;
+ share->index_table = index_table;
+ share->index_table_length = index_table_length;
+ share->key_tokenizer = key_tokenizer;
+ share->key_tokenizer_length = key_tokenizer_length;
+ share->col_flags = col_flags;
+ share->col_flags_length = col_flags_length;
+ share->col_type = col_type;
+ share->col_type_length = col_type_length;
+ mrn_my_stpmov(share->table_name, table_name);
+ share->table_share = table->s;
+
+ if (
+ (*error = mrn_parse_table_param(share, table)) ||
+ (*error = mrn_parse_column_param(share, table)) ||
+ (*error = mrn_parse_index_param(share, table))
+ )
+ goto error_parse_table_param;
+
+ if (share->wrapper_mode)
+ {
+ j = 0;
+ for (i = 0; i < table->s->keys; i++)
+ {
+ if (table->s->key_info[i].algorithm != HA_KEY_ALG_FULLTEXT &&
+ !mrn_is_geo_key(&table->s->key_info[i]))
+ {
+ wrap_key_nr[i] = j;
+ memcpy(&wrap_key_info[j], &table->s->key_info[i],
+ sizeof(*wrap_key_info));
+ j++;
+ } else {
+ wrap_key_nr[i] = MAX_KEY;
+ }
+ }
+ share->wrap_keys = j;
+ share->base_keys = table->s->keys;
+ share->base_key_info = table->s->key_info;
+ share->base_primary_key = table->s->primary_key;
+ if (i)
+ {
+ share->wrap_key_nr = wrap_key_nr;
+ share->wrap_key_info = wrap_key_info;
+ if (table->s->primary_key == MAX_KEY)
+ share->wrap_primary_key = MAX_KEY;
+ else
+ share->wrap_primary_key = wrap_key_nr[table->s->primary_key];
+ } else {
+ share->wrap_key_nr = NULL;
+ share->wrap_key_info = NULL;
+ share->wrap_primary_key = MAX_KEY;
+ }
+ *wrap_table_share= *table->s;
+ mrn_init_sql_alloc(current_thd, &(wrap_table_share->mem_root));
+ wrap_table_share->keys = share->wrap_keys;
+ wrap_table_share->key_info = share->wrap_key_info;
+ wrap_table_share->primary_key = share->wrap_primary_key;
+ wrap_table_share->keys_in_use.init(share->wrap_keys);
+ wrap_table_share->keys_for_keyread.init(share->wrap_keys);
+#ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
+# ifdef WIN32
+ mysql_mutex_init(*mrn_table_share_lock_share,
+ &(wrap_table_share->LOCK_share), MY_MUTEX_INIT_SLOW);
+# else
+ mysql_mutex_init(key_TABLE_SHARE_LOCK_share,
+ &(wrap_table_share->LOCK_share), MY_MUTEX_INIT_SLOW);
+# endif
+#endif
+#ifdef WIN32
+ mysql_mutex_init(*mrn_table_share_lock_ha_data,
+ &(wrap_table_share->LOCK_ha_data), MY_MUTEX_INIT_FAST);
+#else
+ mysql_mutex_init(key_TABLE_SHARE_LOCK_ha_data,
+ &(wrap_table_share->LOCK_ha_data), MY_MUTEX_INIT_FAST);
+#endif
+ share->wrap_table_share = wrap_table_share;
+ }
+
+ if (mysql_mutex_init(mrn_share_mutex_key,
+ &share->record_mutex,
+ MY_MUTEX_INIT_FAST) != 0)
+ {
+ *error = HA_ERR_OUT_OF_MEM;
+ goto error_init_mutex;
+ }
+ thr_lock_init(&share->lock);
+ if (!(share->long_term_share = mrn_get_long_term_share(table_name, length,
+ error)))
+ {
+ goto error_get_long_term_share;
+ }
+ if (my_hash_insert(&mrn_open_tables, (uchar*) share))
+ {
+ *error = HA_ERR_OUT_OF_MEM;
+ goto error_hash_insert;
+ }
+ }
+ share->use_count++;
+ DBUG_RETURN(share);
+
+error_hash_insert:
+error_get_long_term_share:
+ mysql_mutex_destroy(&share->record_mutex);
+error_init_mutex:
+error_parse_table_param:
+ mrn_free_share_alloc(share);
+ my_free(share);
+error_alloc_share:
+ DBUG_RETURN(NULL);
+}
+
+int mrn_free_share(MRN_SHARE *share)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ mrn::Lock lock(&mrn_open_tables_mutex);
+ if (!--share->use_count)
+ {
+ my_hash_delete(&mrn_open_tables, (uchar*) share);
+ if (share->wrapper_mode)
+ plugin_unlock(NULL, share->plugin);
+ mrn_free_share_alloc(share);
+ thr_lock_delete(&share->lock);
+ mysql_mutex_destroy(&share->record_mutex);
+ if (share->wrapper_mode) {
+#ifdef MRN_TABLE_SHARE_HAVE_LOCK_SHARE
+ mysql_mutex_destroy(&(share->wrap_table_share->LOCK_share));
+#endif
+ mysql_mutex_destroy(&(share->wrap_table_share->LOCK_ha_data));
+ free_root(&(share->wrap_table_share->mem_root), MYF(0));
+ }
+ my_free(share);
+ }
+ DBUG_RETURN(0);
+}
+
+TABLE_SHARE *mrn_get_table_share(TABLE_LIST *table_list, int *error)
+{
+ TABLE_SHARE *share;
+ THD *thd = current_thd;
+ MRN_DBUG_ENTER_FUNCTION();
+#if defined(MRN_HAVE_TDC_ACQUIRE_SHARE) && \
+ !defined(MRN_TDC_ACQUIRE_SHARE_REQUIRE_KEY)
+ share = tdc_acquire_share(thd, table_list, GTS_TABLE);
+#else
+ uint key_length;
+# ifdef MRN_HAVE_GET_TABLE_DEF_KEY
+ const char *key;
+ key_length = get_table_def_key(table_list, &key);
+# else
+ char key[MAX_DBKEY_LENGTH];
+ key_length = create_table_def_key(thd, key, table_list, FALSE);
+# endif
+# ifdef MRN_HAVE_TABLE_DEF_CACHE
+ my_hash_value_type hash_value;
+ hash_value = my_calc_hash(mrn_table_def_cache, (uchar*) key, key_length);
+ share = get_table_share(thd, table_list, key, key_length, 0, error,
+ hash_value);
+# elif defined(MRN_HAVE_TDC_ACQUIRE_SHARE)
+ share = tdc_acquire_share(thd, table_list, GTS_TABLE);
+# else
+ share = get_table_share(thd, table_list, key, key_length, 0, error);
+# endif
+#endif
+ DBUG_RETURN(share);
+}
+
+TABLE_SHARE *mrn_create_tmp_table_share(TABLE_LIST *table_list, const char *path,
+ int *error)
+{
+ uint key_length;
+ TABLE_SHARE *share;
+ THD *thd = current_thd;
+
+ MRN_DBUG_ENTER_FUNCTION();
+#ifdef MRN_HAVE_GET_TABLE_DEF_KEY
+ const char *key;
+ key_length = get_table_def_key(table_list, &key);
+#else
+ char key[MAX_DBKEY_LENGTH];
+ key_length = create_table_def_key(thd, key, table_list, FALSE);
+#endif
+#if MYSQL_VERSION_ID >= 100002 && defined(MRN_MARIADB_P)
+ share = alloc_table_share(table_list->db.str, table_list->table_name.str, key,
+ key_length);
+#else
+ share = alloc_table_share(table_list, key, key_length);
+#endif
+ if (!share)
+ {
+ *error = ER_CANT_OPEN_FILE;
+ DBUG_RETURN(NULL);
+ }
+ share->tmp_table = NO_TMP_TABLE; // TODO: is this right?
+ share->path.str = (char *) path;
+ share->path.length = strlen(share->path.str);
+ share->normalized_path.str = mrn_my_strdup(path, MYF(MY_WME));
+ share->normalized_path.length = strlen(share->normalized_path.str);
+ if (open_table_def(thd, share, GTS_TABLE))
+ {
+ *error = ER_CANT_OPEN_FILE;
+ mrn_free_tmp_table_share(share);
+ DBUG_RETURN(NULL);
+ }
+ DBUG_RETURN(share);
+}
+
+void mrn_free_tmp_table_share(TABLE_SHARE *tmp_table_share)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ const char *normalized_path = tmp_table_share->normalized_path.str;
+ free_table_share(tmp_table_share);
+ my_free((char*) normalized_path);
+ DBUG_VOID_RETURN;
+}
+
+KEY *mrn_create_key_info_for_table(MRN_SHARE *share, TABLE *table, int *error)
+{
+ uint *wrap_key_nr = share->wrap_key_nr, i, j;
+ KEY *wrap_key_info;
+ MRN_DBUG_ENTER_FUNCTION();
+ if (share->wrap_keys)
+ {
+ if (!(wrap_key_info = (KEY *)
+ mrn_my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
+ &wrap_key_info, sizeof(*wrap_key_info) * share->wrap_keys,
+ NullS))
+ ) {
+ *error = HA_ERR_OUT_OF_MEM;
+ DBUG_RETURN(NULL);
+ }
+ for (i = 0; i < table->s->keys; i++)
+ {
+ j = wrap_key_nr[i];
+ if (j < MAX_KEY)
+ {
+ memcpy(&wrap_key_info[j], &table->key_info[i],
+ sizeof(*wrap_key_info));
+ }
+ }
+ } else
+ wrap_key_info = NULL;
+ *error = 0;
+ DBUG_RETURN(wrap_key_info);
+}
+
+void mrn_set_bitmap_by_key(MY_BITMAP *map, KEY *key_info)
+{
+ uint i;
+ MRN_DBUG_ENTER_FUNCTION();
+ for (i = 0; i < KEY_N_KEY_PARTS(key_info); i++)
+ {
+ Field *field = key_info->key_part[i].field;
+ bitmap_set_bit(map, field->field_index);
+ }
+ DBUG_VOID_RETURN;
+}
+
+st_mrn_slot_data *mrn_get_slot_data(THD *thd, bool can_create)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_slot_data *slot_data =
+ (st_mrn_slot_data*) thd_get_ha_data(thd, mrn_hton_ptr);
+ if (slot_data == NULL) {
+ slot_data = (st_mrn_slot_data*) malloc(sizeof(st_mrn_slot_data));
+ slot_data->last_insert_record_id = GRN_ID_NIL;
+ slot_data->first_wrap_hton = NULL;
+ slot_data->alter_create_info = NULL;
+ slot_data->disable_keys_create_info = NULL;
+ slot_data->alter_connect_string = NULL;
+ slot_data->alter_comment = NULL;
+ thd_set_ha_data(thd, mrn_hton_ptr, slot_data);
+ {
+ mrn::Lock lock(&mrn_allocated_thds_mutex);
+ if (my_hash_insert(&mrn_allocated_thds, (uchar*) thd))
+ {
+ free(slot_data);
+ DBUG_RETURN(NULL);
+ }
+ }
+ }
+ DBUG_RETURN(slot_data);
+}
+
+void mrn_clear_slot_data(THD *thd)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, FALSE);
+ if (slot_data) {
+ if (slot_data->first_wrap_hton) {
+ st_mrn_wrap_hton *tmp_wrap_hton;
+ st_mrn_wrap_hton *wrap_hton = slot_data->first_wrap_hton;
+ while (wrap_hton)
+ {
+ tmp_wrap_hton = wrap_hton->next;
+ free(wrap_hton);
+ wrap_hton = tmp_wrap_hton;
+ }
+ slot_data->first_wrap_hton = NULL;
+ }
+ slot_data->alter_create_info = NULL;
+ slot_data->disable_keys_create_info = NULL;
+ if (slot_data->alter_connect_string) {
+ my_free(slot_data->alter_connect_string);
+ slot_data->alter_connect_string = NULL;
+ }
+ if (slot_data->alter_comment) {
+ my_free(slot_data->alter_comment);
+ slot_data->alter_comment = NULL;
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/mrn_table.hpp b/storage/mroonga/mrn_table.hpp
new file mode 100644
index 00000000..5ef7bc71
--- /dev/null
+++ b/storage/mroonga/mrn_table.hpp
@@ -0,0 +1,179 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2013 Kentoku SHIBA
+ Copyright(C) 2011-2015 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-1335 USA
+*/
+
+#ifndef MRN_TABLE_HPP_
+#define MRN_TABLE_HPP_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <groonga.h>
+
+typedef struct st_mroonga_long_term_share
+{
+ char *table_name;
+ uint table_name_length;
+
+ // for auto_increment (storage mode only)
+ mysql_mutex_t auto_inc_mutex;
+ bool auto_inc_inited;
+ ulonglong auto_inc_value;
+} MRN_LONG_TERM_SHARE;
+
+typedef struct st_mroonga_share
+{
+ char *table_name;
+ uint table_name_length;
+ uint use_count;
+ mysql_mutex_t record_mutex;
+ THR_LOCK lock;
+ TABLE_SHARE *table_share;
+ TABLE_SHARE *wrap_table_share;
+ MRN_LONG_TERM_SHARE *long_term_share;
+
+ char *engine;
+ int engine_length;
+ char *default_tokenizer;
+ int default_tokenizer_length;
+ char *normalizer;
+ int normalizer_length;
+ char *token_filters;
+ int token_filters_length;
+ plugin_ref plugin;
+ handlerton *hton;
+ char **index_table;
+ char **key_tokenizer;
+ char **col_flags;
+ char **col_type;
+ uint *index_table_length;
+ uint *key_tokenizer_length;
+ uint *col_flags_length;
+ uint *col_type_length;
+ uint *wrap_key_nr;
+ uint wrap_keys;
+ uint base_keys;
+ KEY *wrap_key_info;
+ KEY *base_key_info;
+ uint wrap_primary_key;
+ uint base_primary_key;
+ bool wrapper_mode;
+ bool disable_keys;
+} MRN_SHARE;
+
+struct st_mrn_wrap_hton
+{
+ char path[FN_REFLEN + 1];
+ handlerton *hton;
+ st_mrn_wrap_hton *next;
+};
+
+struct st_mrn_slot_data
+{
+ grn_id last_insert_record_id;
+ st_mrn_wrap_hton *first_wrap_hton;
+ HA_CREATE_INFO *alter_create_info;
+ HA_CREATE_INFO *disable_keys_create_info;
+ char *alter_connect_string;
+ char *alter_comment;
+};
+
+#define MRN_SET_WRAP_ALTER_KEY(file, ha_alter_info) \
+ alter_table_operations base_handler_flags = ha_alter_info->handler_flags; \
+ ha_table_option_struct* base_option_struct = ha_alter_info->create_info->option_struct; \
+ KEY *base_key_info_buffer = ha_alter_info->key_info_buffer; \
+ uint base_key_count = ha_alter_info->key_count; \
+ uint base_index_drop_count = ha_alter_info->index_drop_count; \
+ KEY **base_index_drop_buffer = ha_alter_info->index_drop_buffer; \
+ uint base_index_add_count = ha_alter_info->index_add_count; \
+ uint *base_index_add_buffer = ha_alter_info->index_add_buffer; \
+ ha_alter_info->handler_flags = file->alter_handler_flags; \
+ ha_alter_info->create_info->option_struct = wrap_altered_table->s->option_struct; \
+ ha_alter_info->key_info_buffer = file->alter_key_info_buffer; \
+ ha_alter_info->key_count = file->alter_key_count; \
+ ha_alter_info->index_drop_count = file->alter_index_drop_count; \
+ ha_alter_info->index_drop_buffer = &file->alter_index_drop_buffer; \
+ ha_alter_info->index_add_count = file->alter_index_add_count; \
+ ha_alter_info->index_add_buffer = file->alter_index_add_buffer;
+
+#define MRN_SET_BASE_ALTER_KEY(share, table_share) \
+ ha_alter_info->handler_flags = base_handler_flags; \
+ ha_alter_info->create_info->option_struct = base_option_struct; \
+ ha_alter_info->key_info_buffer = base_key_info_buffer; \
+ ha_alter_info->key_count = base_key_count; \
+ ha_alter_info->index_drop_count = base_index_drop_count; \
+ ha_alter_info->index_drop_buffer = base_index_drop_buffer; \
+ ha_alter_info->index_add_count = base_index_add_count; \
+ ha_alter_info->index_add_buffer = base_index_add_buffer;
+
+#define MRN_SET_WRAP_SHARE_KEY(share, table_share)
+/*
+ table_share->keys = share->wrap_keys; \
+ table_share->key_info = share->wrap_key_info; \
+ table_share->primary_key = share->wrap_primary_key;
+*/
+
+#define MRN_SET_BASE_SHARE_KEY(share, table_share)
+/*
+ table_share->keys = share->base_keys; \
+ table_share->key_info = share->base_key_info; \
+ table_share->primary_key = share->base_primary_key;
+*/
+
+#define MRN_SET_WRAP_TABLE_KEY(file, table) \
+ table->key_info = file->wrap_key_info; \
+ table->s = share->wrap_table_share;
+
+#define MRN_SET_BASE_TABLE_KEY(file, table) \
+ table->key_info = file->base_key_info; \
+ table->s = share->table_share;
+
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+void mrn_get_partition_info(const char *table_name, uint table_name_length,
+ const TABLE *table, partition_element **part_elem,
+ partition_element **sub_elem);
+#endif
+int mrn_parse_table_param(MRN_SHARE *share, TABLE *table);
+bool mrn_is_geo_key(const KEY *key_info);
+int mrn_add_index_param(MRN_SHARE *share, KEY *key_info, int i);
+int mrn_parse_index_param(MRN_SHARE *share, TABLE *table);
+int mrn_add_column_param(MRN_SHARE *share, Field *field, int i);
+int mrn_parse_column_param(MRN_SHARE *share, TABLE *table);
+MRN_SHARE *mrn_get_share(const char *table_name, TABLE *table, int *error);
+int mrn_free_share_alloc(MRN_SHARE *share);
+int mrn_free_share(MRN_SHARE *share);
+MRN_LONG_TERM_SHARE *mrn_get_long_term_share(const char *table_name,
+ uint table_name_length,
+ int *error);
+void mrn_free_long_term_share(MRN_LONG_TERM_SHARE *long_term_share);
+TABLE_SHARE *mrn_get_table_share(TABLE_LIST *table_list, int *error);
+TABLE_SHARE *mrn_create_tmp_table_share(TABLE_LIST *table_list, const char *path,
+ int *error);
+void mrn_free_tmp_table_share(TABLE_SHARE *table_share);
+KEY *mrn_create_key_info_for_table(MRN_SHARE *share, TABLE *table, int *error);
+void mrn_set_bitmap_by_key(MY_BITMAP *map, KEY *key_info);
+st_mrn_slot_data *mrn_get_slot_data(THD *thd, bool can_create);
+void mrn_clear_slot_data(THD *thd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MRN_TABLE_HPP_ */
diff --git a/storage/mroonga/mrn_variables.hpp b/storage/mroonga/mrn_variables.hpp
new file mode 100644
index 00000000..8a0113c5
--- /dev/null
+++ b/storage/mroonga/mrn_variables.hpp
@@ -0,0 +1,51 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 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-1335 USA
+*/
+
+#ifndef MRN_VARIABLES_HPP_
+#define MRN_VARIABLES_HPP_
+
+#include "mrn_mysql_compat.h"
+
+extern PSI_memory_key mrn_memory_key;
+
+namespace mrn {
+ namespace variables {
+ enum BooleanModeSyntaxFlag {
+ BOOLEAN_MODE_SYNTAX_FLAG_DEFAULT = (1 << 0),
+ BOOLEAN_MODE_SYNTAX_FLAG_SYNTAX_QUERY = (1 << 1),
+ BOOLEAN_MODE_SYNTAX_FLAG_SYNTAX_SCRIPT = (1 << 2),
+ BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_COLUMN = (1 << 3),
+ BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_UPDATE = (1 << 4),
+ BOOLEAN_MODE_SYNTAX_FLAG_ALLOW_LEADING_NOT = (1 << 5)
+ };
+
+ ulonglong get_boolean_mode_syntax_flags(THD *thd);
+
+ enum ActionOnError {
+ ACTION_ON_ERROR_ERROR,
+ ACTION_ON_ERROR_ERROR_AND_LOG,
+ ACTION_ON_ERROR_IGNORE,
+ ACTION_ON_ERROR_IGNORE_AND_LOG,
+ };
+
+ ActionOnError get_action_on_fulltext_query_error(THD *thd);
+ }
+}
+
+#endif /* MRN_VARIABLES_HPP_ */
diff --git a/storage/mroonga/mrn_version.h.in b/storage/mroonga/mrn_version.h.in
new file mode 100644
index 00000000..edeecb63
--- /dev/null
+++ b/storage/mroonga/mrn_version.h.in
@@ -0,0 +1,40 @@
+/*
+ Copyright(C) 2011 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-1335 USA
+*/
+
+#ifndef MRN_VERSION_H_
+#define MRN_VERSION_H_
+
+/* Define mroonga version in string */
+#define MRN_VERSION "@MRN_VERSION@"
+
+/* Define mroonga version in hex */
+#define MRN_VERSION_IN_HEX @MRN_VERSION_IN_HEX@
+
+/* Define mroonga major version */
+#define MRN_VERSION_MAJOR @MRN_VERSION_MAJOR@
+
+/* Define mroonga minor version */
+#define MRN_VERSION_MINOR @MRN_VERSION_MINOR@
+
+/* Define mroonga micro version */
+#define MRN_VERSION_MICRO @MRN_VERSION_MICRO@
+
+/* Define to the full name and version of this package. */
+#define MRN_PACKAGE_STRING "@MRN_PACKAGE_STRING@"
+
+#endif /* MRN_VERSION_H_ */
diff --git a/storage/mroonga/mysql-test/Makefile.am b/storage/mroonga/mysql-test/Makefile.am
new file mode 100644
index 00000000..9ea677b5
--- /dev/null
+++ b/storage/mroonga/mysql-test/Makefile.am
@@ -0,0 +1,8 @@
+dist-hook:
+ if [ -n "`find mroonga -name '*.reject'`" ]; then \
+ echo "reject files exist"; \
+ exit 1; \
+ fi
+
+EXTRA_DIST = \
+ mroonga
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_64bit.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_64bit.inc
new file mode 100644
index 00000000..9d1ee1d5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_64bit.inc
@@ -0,0 +1,22 @@
+# 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-1335 USA
+
+disable_query_log;
+disable_warnings;
+let $version_compile_64bit=
+ `SELECT IF(@@version_compile_machine LIKE '%64%', 1, 0)`;
+enable_warnings;
+enable_query_log;
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_freebsd.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_freebsd.inc
new file mode 100644
index 00000000..51bbe572
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_freebsd.inc
@@ -0,0 +1,20 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--disable_query_log
+let $version_compile_os_freebsd=
+ `SELECT IF(@@version_compile_os LIKE '%freebsd%', 1, 0);`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_ha_mroonga_so.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_ha_mroonga_so.inc
new file mode 100644
index 00000000..fef9de96
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_ha_mroonga_so.inc
@@ -0,0 +1,26 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/check_windows.inc
+
+--disable_query_log
+if ($VERSION_COMPILE_OS_WIN) {
+ let ha_mroonga_so='ha_mroonga.dll';
+}
+if (!$VERSION_COMPILE_OS_WIN) {
+ let ha_mroonga_so='ha_mroonga.so';
+}
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_embedded.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_embedded.inc
new file mode 100644
index 00000000..926620eb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_embedded.inc
@@ -0,0 +1,19 @@
+# Copyright(C) 2015 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-1335 USA
+
+--disable_query_log
+let $libgroonga_embedded = `SELECT @@mroonga_libgroonga_embedded;`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_lz4.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_lz4.inc
new file mode 100644
index 00000000..2acfb1fb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_lz4.inc
@@ -0,0 +1,20 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--disable_query_log
+let $libgroonga_support_lz4 =
+ `SELECT @@mroonga_libgroonga_support_lz4;`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zlib.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zlib.inc
new file mode 100644
index 00000000..e9b8dee0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zlib.inc
@@ -0,0 +1,20 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--disable_query_log
+let $libgroonga_support_zlib =
+ `SELECT @@mroonga_libgroonga_support_zlib;`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zstd.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zstd.inc
new file mode 100644
index 00000000..bdaf5cdf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_libgroonga_support_zstd.inc
@@ -0,0 +1,20 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--disable_query_log
+let $libgroonga_support_zstd =
+ `SELECT @@mroonga_libgroonga_support_zstd;`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_mariadb.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_mariadb.inc
new file mode 100644
index 00000000..5e4a986f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_mariadb.inc
@@ -0,0 +1,19 @@
+# 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-1335 USA
+
+--disable_query_log
+let $mariadb = `SELECT LOCATE('MariaDB', @@global.version) > 0`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_osx.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_osx.inc
new file mode 100644
index 00000000..facfcc92
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_osx.inc
@@ -0,0 +1,31 @@
+# Copyright(C) 2014 Toshihisa Tashiro
+# Copyright(C) 2016 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-1335 USA
+
+--disable_query_log
+let $version_compile_os_osx=`SELECT IF(@@version_compile_os like 'osx%', 1, 0);`;
+if ($version_compile_os_osx) {
+ let $version_compile_os_osx_10_8_or_later=
+ `SELECT IF(@@version_compile_os = 'osx10.6', 0, 1);`;
+ if ($version_compile_os_osx_10_8_or_later) {
+ let $version_compile_os_osx_10_8_or_later=
+ `SELECT IF(@@version_compile_os = 'osx10.7', 0, 1);`;
+ }
+}
+if (!$version_comiple_os_osx) {
+ let $version_compile_os_osx_10_8_or_later=0;
+}
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_solaris.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_solaris.inc
new file mode 100644
index 00000000..7e942c09
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_solaris.inc
@@ -0,0 +1,20 @@
+# Copyright(C) 2016 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-1335 USA
+
+--disable_query_log
+let $version_compile_os_solaris=
+ `SELECT IF(@@version_compile_os LIKE 'sun-solaris%', 1, 0);`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_strict_sql_mode.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_strict_sql_mode.inc
new file mode 100644
index 00000000..8a4ac6c9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_strict_sql_mode.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2017 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-1335 USA
+
+--disable_query_log
+let $strict_sql_mode =
+ `SELECT @@sql_mode LIKE '%STRICT_TRANS_TABLES%' OR
+ @@sql_mode LIKE '%STRICT_ALL_TABLES%'`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_version.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_version.inc
new file mode 100644
index 00000000..8b5ea402
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_version.inc
@@ -0,0 +1,33 @@
+# Copyright(C) 2012-2017 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-1335 USA
+
+--disable_query_log
+let $version_major_minor =
+ `SELECT CAST(SUBSTRING_INDEX(@@global.version, '.', 2) AS DECIMAL(4, 2))`;
+
+let $version_5_5 = `SELECT $version_major_minor = 5.5`;
+let $version_5_6 = `SELECT $version_major_minor = 5.6`;
+let $version_5_7 = `SELECT $version_major_minor = 5.7`;
+let $version_10_0 = `SELECT $version_major_minor = 10.0`;
+let $version_10_1 = `SELECT $version_major_minor = 10.1`;
+let $version_10_2 = `SELECT $version_major_minor = 10.2`;
+
+let $version_5_5_or_later = `SELECT $version_major_minor >= 5.5`;
+let $version_5_6_or_later = `SELECT $version_major_minor >= 5.6`;
+let $version_5_7_or_later = `SELECT $version_major_minor >= 5.7`;
+let $version_10_0_or_later = `SELECT $version_major_minor >= 10.0`;
+let $version_10_2_or_later = `SELECT $version_major_minor >= 10.2`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/check_windows.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_windows.inc
new file mode 100644
index 00000000..e9fad828
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/check_windows.inc
@@ -0,0 +1,20 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# 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-1335 USA
+
+--disable_query_log
+let $VERSION_COMPILE_OS_WIN=`SELECT IF(@@version_compile_os like 'Win%', 1, 0)`;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_fractional_seconds.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_fractional_seconds.inc
new file mode 100644
index 00000000..824e960a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_fractional_seconds.inc
@@ -0,0 +1,32 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/check_mariadb.inc
+--source ../../include/mroonga/check_version.inc
+
+if ($mariadb) {
+ let $fractional_seconds = 1;
+}
+
+if (!$mariadb) {
+ if ($version_5_6) {
+ let $fractional_seconds = `SELECT @@global.version >= '5.6'`;
+ }
+}
+
+if (!$fractional_seconds) {
+ --skip fractional seconds in time values are available in MySQL version 5.6 or later or MariaDB
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_freebsd.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_freebsd.inc
new file mode 100644
index 00000000..1a93d014
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_freebsd.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/check_freebsd.inc
+
+if (!$version_compile_os_freebsd) {
+ --skip Need OS FreeBSD
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_groonga_plugin_register.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_groonga_plugin_register.inc
new file mode 100644
index 00000000..dafbc344
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_groonga_plugin_register.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_embedded.inc
+
+if ($libgroonga_embedded) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test requires plugin_register of Groonga. libgroonga embedded build doesn't support it.
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb.inc
new file mode 100644
index 00000000..df30270a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/check_mariadb.inc
+
+if (!$mariadb) {
+ --skip This test is for MariaDB
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb_10_2_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb_10_2_or_later.inc
new file mode 100644
index 00000000..6cb565ab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mariadb_10_2_or_later.inc
@@ -0,0 +1,26 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if (!$mariadb) {
+ --skip This test is for MariaDB version 10.2.x or later
+}
+
+if (!$version_10_2_or_later) {
+ --skip This test is for MariaDB version 10.2.x or later
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga.inc
new file mode 100644
index 00000000..98d387b0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga.inc
@@ -0,0 +1,47 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2013-2014 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-1335 USA
+
+--source ../../include/mroonga/check_ha_mroonga_so.inc
+
+disable_query_log;
+
+let have_mroonga_storage_engine=`SELECT 1 FROM information_schema.plugins WHERE plugin_name = "mroonga"`;
+if (!$have_mroonga_storage_engine) {
+ eval INSTALL PLUGIN mroonga SONAME $ha_mroonga_so;
+ eval INSTALL PLUGIN mroonga_stats SONAME $ha_mroonga_so;
+}
+
+let have_default_storage_engine_variable=`SELECT 1 FROM information_schema.global_variables WHERE variable_name = "default_storage_engine"`;
+if ($have_default_storage_engine_variable) {
+ let original_default_storage_engine=`SELECT variable_value FROM information_schema.global_variables WHERE variable_name = "default_storage_engine"`;
+ set default_storage_engine=Mroonga;
+}
+if (!$have_default_storage_engine_variable) {
+ let original_storage_engine=`SELECT variable_value FROM information_schema.global_variables WHERE variable_name = "storage_engine"`;
+ set storage_engine=Mroonga;
+}
+
+let have_default_tmp_storage_engine_variable=`SELECT 1 FROM information_schema.global_variables WHERE variable_name = "default_tmp_storage_engine"`;
+if ($have_default_tmp_storage_engine_variable) {
+ let original_default_tmp_storage_engine=`SELECT variable_value FROM information_schema.global_variables WHERE variable_name = "default_tmp_storage_engine"`;
+ if (!$original_default_tmp_storage_engine) {
+ let original_default_tmp_storage_engine=NULL;
+ }
+ set default_tmp_storage_engine=Mroonga;
+}
+
+enable_query_log;
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_deinit.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_deinit.inc
new file mode 100644
index 00000000..e29300b5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_deinit.inc
@@ -0,0 +1,42 @@
+# Copyright(C) 2010-2014 Kentoku SHIBA
+# Copyright(C) 2011 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-1335 USA
+
+disable_query_log;
+
+if ($have_default_storage_engine_variable) {
+ eval set default_storage_engine=$original_default_storage_engine;
+}
+if (!$have_default_storage_engine_variable) {
+ eval set storage_engine=$original_storage_engine;
+}
+
+if ($have_default_tmp_storage_engine_variable) {
+ eval set default_tmp_storage_engine=$original_default_tmp_storage_engine;
+}
+
+if (!$have_mroonga_storage_engine) {
+ UNINSTALL PLUGIN mroonga_stats;
+ UNINSTALL PLUGIN mroonga;
+}
+
+# Some test re-creates the test database. Put it back in the
+# original character set
+--source include/default_charset.inc
+disable_query_log;
+drop database test;
+create database test;
+enable_query_log;
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_helper.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_helper.inc
new file mode 100644
index 00000000..83d74867
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mroonga_helper.inc
@@ -0,0 +1,17 @@
+# Copyright(C) 2011 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-1335 USA
+
+let MYSQLD_DATADIR= `select @@datadir`;
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql.inc
new file mode 100644
index 00000000..90e98c56
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql.inc
@@ -0,0 +1,21 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($mariadb) {
+ --skip This test is for MySQL
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql_5_7_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql_5_7_or_later.inc
new file mode 100644
index 00000000..d354b151
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_mysql_5_7_or_later.inc
@@ -0,0 +1,26 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($mariadb) {
+ --skip This test is for MySQL version 5.7.x or later
+}
+
+if (!$version_5_7_or_later) {
+ --skip This test is for MySQL version 5.7.x or later
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_signed_64bit_time_t.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_signed_64bit_time_t.inc
new file mode 100644
index 00000000..d19cca5a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_signed_64bit_time_t.inc
@@ -0,0 +1,28 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/check_64bit.inc
+--source ../../include/mroonga/check_osx.inc
+
+if (!$version_compile_64bit) {
+ --skip Need a 64 binary for signed 64bit time_t
+}
+
+if ($version_compile_os_osx) {
+ if (!$version_compile_os_osx_10_8_or_later) {
+ --skip Need OS X 10.8 or later for signed 64bit time_t
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_solaris.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_solaris.inc
new file mode 100644
index 00000000..a4ab246c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_solaris.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/check_solaris.inc
+
+if (!$version_compile_os_solaris) {
+ --skip Need Solaris
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_strict_sql_mode.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_strict_sql_mode.inc
new file mode 100644
index 00000000..a490b7e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_strict_sql_mode.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/check_strict_sql_mode.inc
+
+if (!$strict_sql_mode) {
+ --skip This test is for STRICT_ALL_TABLES or STRICT_TRANS_TABLES
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0.inc
new file mode 100644
index 00000000..260e5d3c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2013-2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_10_0) {
+ --skip This test is for MariaDB version 10.0.x
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0_or_later.inc
new file mode 100644
index 00000000..35f8fb7a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_10_0_or_later.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2013-2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_10_0_or_later) {
+ --skip This test is for MariaDB version 10.0.x or later
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_5.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_5.inc
new file mode 100644
index 00000000..a04fe560
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_5.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2012-2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_5_5) {
+ --skip This test is for MySQL version 5.5.x
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6.inc
new file mode 100644
index 00000000..d23f23e5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6.inc
@@ -0,0 +1,21 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_5_6) {
+ --skip This test is for MySQL version 5.6.x
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6_or_later.inc
new file mode 100644
index 00000000..db1ac8aa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_6_or_later.inc
@@ -0,0 +1,21 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_5_6_or_later) {
+ --skip This test is for MySQL version 5.6.x or later
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7.inc
new file mode 100644
index 00000000..80f15c56
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_5_7) {
+ --skip This test is for MySQL version 5.7.x
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7_or_later.inc
new file mode 100644
index 00000000..f5898b0b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/have_version_5_7_or_later.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2015-2016 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+
+if (!$version_5_7_or_later) {
+ --skip This test is for MySQL version 5.7.x or later or MariaDB 10.0.x or later
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/load_mroonga_functions.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/load_mroonga_functions.inc
new file mode 100644
index 00000000..cbcf659f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/load_mroonga_functions.inc
@@ -0,0 +1,28 @@
+# Copyright(C) 2013-2017 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-1335 USA
+
+--source ../../include/mroonga/check_ha_mroonga_so.inc
+
+--disable_query_log
+eval CREATE FUNCTION last_insert_grn_id RETURNS INTEGER SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_snippet RETURNS STRING SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_command RETURNS STRING SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_escape RETURNS STRING SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_snippet_html RETURNS STRING SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_normalize RETURNS STRING SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_highlight_html RETURNS STRING SONAME $ha_mroonga_so;
+eval CREATE FUNCTION mroonga_query_expand RETURNS STRING SONAME $ha_mroonga_so;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/print_groonga_query_log.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/print_groonga_query_log.inc
new file mode 100644
index 00000000..d5f8c129
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/print_groonga_query_log.inc
@@ -0,0 +1,8 @@
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+perl;
+open(F, '<', $_="$ENV{MYSQLD_DATADIR}/groonga-query-log.log") or die "open(<$_): $!";
+while (<F>) {
+ s/^[^|]+\|[^|]+\|[^|]+\| *//;
+ print;
+}
+EOF
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_freebsd.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_freebsd.inc
new file mode 100644
index 00000000..51f783e7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_freebsd.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/check_freebsd.inc
+
+if ($version_compile_os_freebsd) {
+ --skip This test is not for FreeBSD
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_0_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_0_or_later.inc
new file mode 100644
index 00000000..67d6251b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_0_or_later.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2012-2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($mariadb) {
+ if ($version_10_0_or_later) {
+ --skip This test is not for MariaDB 10.x
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1.inc
new file mode 100644
index 00000000..7e4c1279
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($version_10_1) {
+ if ($mariadb) {
+ --skip This test is not for MariaDB 10.1.x
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1_or_earlier.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1_or_earlier.inc
new file mode 100644
index 00000000..506beeb9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_1_or_earlier.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($mariadb) {
+ if (!$version_10_2_or_later) {
+ --skip This test is not for MariaDB 5.x, MariaDB 10.0.x nor 10.1.x
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_2_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_2_or_later.inc
new file mode 100644
index 00000000..d40c4ddd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_10_2_or_later.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($mariadb) {
+ if ($version_10_2_or_later) {
+ --skip This test is not for MariaDB 10.2.x or later
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_5_5.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_5_5.inc
new file mode 100644
index 00000000..974851f7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mariadb_5_5.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2012-2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($version_5_5) {
+ if ($mariadb) {
+ --skip This test is not for MariaDB 5.5.x
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_5.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_5.inc
new file mode 100644
index 00000000..7446ffa5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_5.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2014-2017 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($version_5_5) {
+ if (!$mariadb) {
+ --skip This test is not for MySQL 5.5.x
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7.inc
new file mode 100644
index 00000000..6eaa60a4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($version_5_7) {
+ if (!$mariadb) {
+ --skip This test is not for MySQL 5.7.x
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7_or_later.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7_or_later.inc
new file mode 100644
index 00000000..599831e3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_mysql_5_7_or_later.inc
@@ -0,0 +1,24 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/check_version.inc
+--source ../../include/mroonga/check_mariadb.inc
+
+if ($version_5_7_or_later) {
+ if (!$mariadb) {
+ --skip This test is not for MySQL 5.7.x or later
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_osx.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_osx.inc
new file mode 100644
index 00000000..2c1da974
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_osx.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2014 Toshihisa Tashiro
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/check_osx.inc
+
+if ($VERSION_COMPILE_OS_OSX) {
+ --skip This test is not for OSX
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_signed_64bit_time_t.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_signed_64bit_time_t.inc
new file mode 100644
index 00000000..cc06b529
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_signed_64bit_time_t.inc
@@ -0,0 +1,28 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/check_64bit.inc
+--source ../../include/mroonga/check_osx.inc
+
+if ($version_compile_64bit) {
+ --skip This test is for environment that doesn't have signed 64bit time_t
+}
+
+if ($version_compile_os_osx) {
+ if (!$version_compile_os_osx_10_8_or_later) {
+ --skip This test is not for OS X 10.7 or earlier that isn't detected signed 64bit time_t availability
+ }
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_solaris.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_solaris.inc
new file mode 100644
index 00000000..b79188e4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_solaris.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/check_solaris.inc
+
+if ($version_compile_os_solaris) {
+ --skip This test is not for Solaris
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_strict_sql_mode.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_strict_sql_mode.inc
new file mode 100644
index 00000000..8bb15b03
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/skip_strict_sql_mode.inc
@@ -0,0 +1,21 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/check_strict_sql_mode.inc
+
+if ($strict_sql_mode) {
+ --skip This test is not for STRICT_ALL_TABLES nor STRICT_TRANS_TABLES
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_lz4.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_lz4.inc
new file mode 100644
index 00000000..40fc5978
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_lz4.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_support_lz4.inc
+
+if (!$libgroonga_support_lz4) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test is for libgroonga supports lz4
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zlib.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zlib.inc
new file mode 100644
index 00000000..9d0ed6c1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zlib.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_support_zlib.inc
+
+if (!$libgroonga_support_zlib) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test is for libgroonga supports zlib
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zstd.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zstd.inc
new file mode 100644
index 00000000..d09495bd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/support_libgroonga_zstd.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_support_zstd.inc
+
+if (!$libgroonga_support_zstd) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test is for libgroonga supports zstd
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/unload_mroonga_functions.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/unload_mroonga_functions.inc
new file mode 100644
index 00000000..e72baac2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/unload_mroonga_functions.inc
@@ -0,0 +1,26 @@
+# Copyright(C) 2013-2017 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-1335 USA
+
+--disable_query_log
+DROP FUNCTION last_insert_grn_id;
+DROP FUNCTION mroonga_snippet;
+DROP FUNCTION mroonga_command;
+DROP FUNCTION mroonga_escape;
+DROP FUNCTION mroonga_snippet_html;
+DROP FUNCTION mroonga_normalize;
+DROP FUNCTION mroonga_highlight_html;
+DROP FUNCTION mroonga_query_expand;
+--enable_query_log
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_lz4.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_lz4.inc
new file mode 100644
index 00000000..f82fc328
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_lz4.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_support_lz4.inc
+
+if ($libgroonga_support_lz4) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test is for libgroonga doesn't support lz4
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zlib.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zlib.inc
new file mode 100644
index 00000000..c93038b0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zlib.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_support_zlib.inc
+
+if ($libgroonga_support_zlib) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test is for libgroonga doesn't support zlib
+}
diff --git a/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zstd.inc b/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zstd.inc
new file mode 100644
index 00000000..b1c081e3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/include/mroonga/unsupport_libgroonga_zstd.inc
@@ -0,0 +1,22 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/check_libgroonga_support_zstd.inc
+
+if ($libgroonga_support_zstd) {
+ --source ../../include/mroonga/have_mroonga_deinit.inc
+ --skip This test is for libgroonga doesn't support zstd
+}
diff --git a/storage/mroonga/mysql-test/mroonga/storage/disabled.def b/storage/mroonga/mysql-test/mroonga/storage/disabled.def
new file mode 100644
index 00000000..6866adc1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/disabled.def
@@ -0,0 +1,10 @@
+alter_table_add_index_token_filters_one_token_filter : Bundled Mroonga does not support token filter yet.
+alter_table_change_token_filter : Bundled Mroonga does not support token filter yet.
+fulltext_token_filters_skip : Bundled Mroonga does not support token filter yet.
+create_table_token_filters_index_comment_multiple_token_filters : Bundled Mroonga does not support token filter yet.
+create_table_token_filters_index_comment_one_token_filter : Bundled Mroonga does not support token filter yet.
+create_table_token_filters_table_comment_multiple_token_filters : Bundled Mroonga does not support token filter yet.
+create_table_token_filters_table_comment_one_token_filter : Bundled Mroonga does not support token filter yet.
+foreign_key_create : Bundled Mroonga does not support this test yet.
+partition_insert : Bundled Mroonga does not support this test yet.
+
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_after.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_after.result
new file mode 100644
index 00000000..ecfd91bd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_after.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+ALTER TABLE diaries ADD title VARCHAR(40) AFTER id;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+id title body
+1 groonga (1) starting groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_first.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_first.result
new file mode 100644
index 00000000..40495575
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_first.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+ALTER TABLE diaries ADD title VARCHAR(40) FIRST;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `title` varchar(40) DEFAULT NULL,
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+title id body
+groonga (1) 1 starting groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_comment.result
new file mode 100644
index 00000000..de0482e6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_comment.result
@@ -0,0 +1,15 @@
+CREATE TABLE tags (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE tags ADD COLUMN name VARCHAR(64) COMMENT 'flags "COLUMN_VECTOR"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY UInt32
+column_create tags id COLUMN_SCALAR UInt32
+column_create tags name COLUMN_VECTOR ShortText
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_parameter.result
new file mode 100644
index 00000000..3580dc1b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_flags_parameter.result
@@ -0,0 +1,22 @@
+CREATE TABLE tags (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE tags ADD COLUMN name VARCHAR(64) FLAGS='COLUMN_VECTOR';
+SHOW CREATE TABLE tags;
+Table Create Table
+tags CREATE TABLE `tags` (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `name` varchar(64) DEFAULT NULL `FLAGS`='COLUMN_VECTOR',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY UInt32
+column_create tags id COLUMN_SCALAR UInt32
+column_create tags name COLUMN_VECTOR ShortText
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_comment.result
new file mode 100644
index 00000000..8a1c18b7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_comment.result
@@ -0,0 +1,23 @@
+CREATE TABLE tags (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE bugs ADD COLUMN name VARCHAR(64) COMMENT 'groonga_type "tags"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY UInt32
+column_create tags id COLUMN_SCALAR UInt32
+
+column_create bugs name COLUMN_SCALAR tags
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_parameter.result
new file mode 100644
index 00000000..63e34b98
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_groonga_type_parameter.result
@@ -0,0 +1,30 @@
+CREATE TABLE tags (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE bugs ADD COLUMN name VARCHAR(64) GROONGA_TYPE='tags';
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `name` varchar(64) DEFAULT NULL `GROONGA_TYPE`='tags',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY UInt32
+column_create tags id COLUMN_SCALAR UInt32
+
+column_create bugs name COLUMN_SCALAR tags
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_cp932.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_cp932.result
new file mode 100644
index 00000000..6fb1a107
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_cp932.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS users;
+SET NAMES cp932;
+CREATE TABLE users (
+id int PRIMARY KEY
+) DEFAULT CHARSET=cp932;
+ALTER TABLE users
+ADD COLUMN O text,
+ADD FULLTEXT INDEX (O);
+INSERT INTO users VALUES (1, "܂");
+INSERT INTO users VALUES (2, "Ȃ");
+INSERT INTO users VALUES (3, "");
+SELECT * FROM users;
+id O
+1 ܂
+2 Ȃ
+3
+SELECT * FROM users
+WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+id O
+2 Ȃ
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_PAT_KEY Int32
+column_create users @540d@524d COLUMN_SCALAR LongText
+column_create users id COLUMN_SCALAR Int32
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users @540d@524d
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_utf8.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_utf8.result
new file mode 100644
index 00000000..70c9ea0c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multibyte_utf8.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+id int PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE users
+ADD COLUMN 名前 text,
+ADD FULLTEXT INDEX (名前);
+INSERT INTO users VALUES (1, "やまだ");
+INSERT INTO users VALUES (2, "たなか");
+INSERT INTO users VALUES (3, "すずき");
+SELECT * FROM users;
+id 名前
+1 やまだ
+2 たなか
+3 すずき
+SELECT * FROM users
+WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+id 名前
+2 たなか
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_PAT_KEY Int32
+column_create users @540d@524d COLUMN_SCALAR LongText
+column_create users id COLUMN_SCALAR Int32
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users @540d@524d
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multiple.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multiple.result
new file mode 100644
index 00000000..3d89aa1e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_multiple.result
@@ -0,0 +1,44 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+id title
+1 survey
+ALTER TABLE diaries
+ADD COLUMN body VARCHAR(140) FIRST,
+ADD COLUMN published BOOLEAN AFTER id,
+ADD COLUMN created_at DATETIME;
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+body id published title created_at
+will start groonga! 1 0 survey 1970-01-01 00:00:00
+INSERT INTO diaries (title, body, published, created_at)
+VALUES ("groonga (1)", "starting groonga...", TRUE, "2014-2-9 02:09:00");
+INSERT INTO diaries (title, body, published, created_at)
+VALUES ("groonga (2)", "started groonga.", FALSE, "2014-2-9 12:19:00");
+SELECT * FROM diaries;
+body id published title created_at
+will start groonga! 1 0 survey 1970-01-01 00:00:00
+starting groonga... 2 1 groonga (1) 2014-02-09 02:09:00
+started groonga. 3 0 groonga (2) 2014-02-09 12:19:00
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `body` varchar(140) DEFAULT NULL,
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `published` tinyint(1) DEFAULT NULL,
+ `title` varchar(40) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_plain.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_plain.result
new file mode 100644
index 00000000..a3762372
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_plain.result
@@ -0,0 +1,37 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+id title
+1 survey
+ALTER TABLE diaries ADD COLUMN body VARCHAR(140);
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_type_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_type_comment.result
new file mode 100644
index 00000000..51362826
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_column_type_comment.result
@@ -0,0 +1,23 @@
+CREATE TABLE tags (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE bugs ADD COLUMN name VARCHAR(64) COMMENT 'type "tags"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY UInt32
+column_create tags id COLUMN_SCALAR UInt32
+
+column_create bugs name COLUMN_SCALAR tags
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_token_filters_one_token_filter.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_token_filters_one_token_filter.result
new file mode 100644
index 00000000..373c70e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_token_filters_one_token_filter.result
@@ -0,0 +1,22 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL
+) DEFAULT CHARSET=utf8;
+ALTER TABLE memos ADD FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_NO_KEY
+column_create memos content COLUMN_SCALAR ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_duplicated.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_duplicated.result
new file mode 100644
index 00000000..3938c6fc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_duplicated.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT
+) DEFAULT CHARSET UTF8;
+INSERT INTO ids (id) values (1), (1);
+ALTER TABLE ids ADD UNIQUE INDEX (id);
+ERROR 23000: Can't write, because of unique constraint, to table 'ids'
+SHOW CREATE TABLE ids;
+Table Create Table
+ids CREATE TABLE `ids` (
+ `id` int(11) DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT * FROM ids;
+id
+1
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_multiple_column_duplicated.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_multiple_column_duplicated.result
new file mode 100644
index 00000000..cf06223a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_index_unique_multiple_column_duplicated.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id1 INT,
+id2 INT
+) DEFAULT CHARSET=utf8mb4;
+INSERT INTO ids (id1, id2) values (1, 2), (1, 2);
+ALTER TABLE ids ADD UNIQUE INDEX (id1, id2);
+ERROR 23000: Can't write, because of unique constraint, to table 'ids'
+SHOW CREATE TABLE ids;
+Table Create Table
+ids CREATE TABLE `ids` (
+ `id1` int(11) DEFAULT NULL,
+ `id2` int(11) DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
+SELECT * FROM ids;
+id1 id2
+1 2
+1 2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_key_multiple_column_with_data.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_key_multiple_column_with_data.result
new file mode 100644
index 00000000..930f1f48
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_key_multiple_column_with_data.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS scores;
+SET NAMES UTF8;
+CREATE TABLE scores (
+id BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL,
+name CHAR(30) NOT NULL,
+score INT NOT NULL
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores
+WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+ALTER TABLE scores ADD KEY property (name, score);
+SELECT * FROM scores
+WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_primary_key.result
new file mode 100644
index 00000000..adca183f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_add_primary_key.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT NOT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+ALTER TABLE ids ADD PRIMARY KEY (id);
+SHOW CREATE TABLE ids;
+Table Create Table
+ids CREATE TABLE `ids` (
+ `id` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT * FROM ids WHERE id = 2;
+id
+2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_comment_not_for_mroonga.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_comment_not_for_mroonga.result
new file mode 100644
index 00000000..aa90e9ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_comment_not_for_mroonga.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE bugs
+CHANGE COLUMN
+tag
+tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.';
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tag` varchar(64) DEFAULT NULL COMMENT 'It must consist of only alphabet and number.',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_have_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_have_index.result
new file mode 100644
index 00000000..7be787aa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_have_index.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+title VARCHAR(32),
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE bugs CHANGE COLUMN title title VARCHAR(64);
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+ `title` varchar(64) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `title` (`title`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_after.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_after.result
new file mode 100644
index 00000000..c58ee2b7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_after.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+ALTER TABLE diaries CHANGE body description VARCHAR(140) AFTER id;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `description` varchar(140) DEFAULT NULL,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, description) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+id description title
+1 starting groonga. groonga (1)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_first.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_first.result
new file mode 100644
index 00000000..68885fa9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_first.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+ALTER TABLE diaries CHANGE body description VARCHAR(140) FIRST;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `description` varchar(140) DEFAULT NULL,
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, description) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+description id title
+starting groonga. 1 groonga (1)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_multiple.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_multiple.result
new file mode 100644
index 00000000..af5a2c3a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_multiple.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+ALTER TABLE diaries
+CHANGE body description VARCHAR(140) FIRST,
+CHANGE title subject VARCHAR(40) AFTER internal_id,
+CHANGE id internal_id INT AUTO_INCREMENT;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `description` varchar(140) DEFAULT NULL,
+ `internal_id` int(11) NOT NULL AUTO_INCREMENT,
+ `subject` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`internal_id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT IGNORE INTO diaries (subject, description)
+VALUES ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+description internal_id subject
+starting groonga. 1 groonga (1)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_no_order.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_no_order.result
new file mode 100644
index 00000000..4318f686
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_column_rename_no_order.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+ALTER TABLE diaries CHANGE body description VARCHAR(140);
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `description` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, description) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+id title description
+1 groonga (1) starting groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_decimal.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_decimal.result
new file mode 100644
index 00000000..a66f0cac
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_decimal.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+temperature DECIMAL(6, 3)
+) ENGINE InnoDB DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `temperature` decimal(6,3) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (temperature) VALUES (21.281);
+SELECT * FROM diaries;
+id temperature
+1 21.281
+ALTER TABLE diaries ENGINE = mroonga;
+SELECT * FROM diaries;
+id temperature
+1 21.281
+INSERT INTO diaries (temperature) VALUES (14.213);
+INSERT INTO diaries (temperature) VALUES (17.821);
+SELECT * FROM diaries;
+id temperature
+1 21.281
+2 14.213
+3 17.821
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `temperature` decimal(6,3) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_fulltext_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_fulltext_index.result
new file mode 100644
index 00000000..706764a5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_engine_fulltext_index.result
@@ -0,0 +1,39 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) ENGINE MyISAM DEFAULT CHARSET UTF8;
+SELECT table_name, engine
+FROM information_schema.tables
+WHERE table_name = 'diaries';
+table_name engine
+diaries MyISAM
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+id title body
+1 survey will start groonga!
+ALTER TABLE diaries ENGINE = mroonga;
+SELECT table_name, engine
+FROM information_schema.tables
+WHERE table_name = 'diaries';
+table_name engine
+diaries Mroonga
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+id title body
+1 survey will start groonga!
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AND
+MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+id title body
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_token_filter.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_token_filter.result
new file mode 100644
index 00000000..9fc3b408
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_change_token_filter.result
@@ -0,0 +1,63 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+CREATE TABLE terms (
+term VARCHAR(64) NOT NULL PRIMARY KEY,
+is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram"' DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+column_create terms is_stop_word COLUMN_SCALAR Int8
+column_create terms term COLUMN_SCALAR ShortText
+
+column_create terms content COLUMN_INDEX|WITH_POSITION memos content
+ALTER TABLE terms COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord
+column_create terms is_stop_word COLUMN_SCALAR Int8
+column_create terms term COLUMN_SCALAR ShortText
+ALTER TABLE memos DISABLE KEYS;
+ALTER TABLE memos ENABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord
+column_create terms is_stop_word COLUMN_SCALAR Int8
+column_create terms term COLUMN_SCALAR ShortText
+
+column_create terms content COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_create_fulltext.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_create_fulltext.result
new file mode 100644
index 00000000..6127df61
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_create_fulltext.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+CREATE FULLTEXT INDEX title_index on diaries (title);
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_table.result
new file mode 100644
index 00000000..7416481e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_table.result
@@ -0,0 +1,41 @@
+SET NAMES utf8;
+CREATE TABLE terms (
+term varchar(256) NOT NULL PRIMARY KEY
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"'
+ DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id int PRIMARY KEY,
+content text NOT NULL,
+FULLTEXT INDEX content_index (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+column_create terms term COLUMN_SCALAR ShortText
+
+column_create terms content_index COLUMN_INDEX|WITH_POSITION memos content
+ALTER TABLE memos DISABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+column_create terms term COLUMN_SCALAR ShortText
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_ujis.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_ujis.result
new file mode 100644
index 00000000..ff7bc5e7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_ujis.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES ujis;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=ujis;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "ŷ");
+INSERT INTO diaries VALUES (3, "ٻλ");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("ٻλ");
+id title
+3 ٻλ
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("ٻλ");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_utf8.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_utf8.result
new file mode 100644
index 00000000..cbaa8d62
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_fulltext_utf8.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_multiple_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_multiple_column.result
new file mode 100644
index 00000000..9d6cdcd9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_multiple_column.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY title_and_created_at_index (title, created_at)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_normal.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_normal.result
new file mode 100644
index 00000000..09399c12
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_normal.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY created_at_index (created_at)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_primary.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_primary.result
new file mode 100644
index 00000000..f94c98ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_primary.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_truncate.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_truncate.result
new file mode 100644
index 00000000..7b71832b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_truncate.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+first_name VARCHAR(32) NOT NULL,
+last_name VARCHAR(32) NOT NULL,
+KEY (first_name, last_name)
+);
+INSERT INTO users VALUES("Taro", "Yamada");
+INSERT INTO users VALUES("Hanako", "Tanaka");
+INSERT INTO users VALUES("Joe", "Honda");
+SELECT * FROM users;
+first_name last_name
+Taro Yamada
+Hanako Tanaka
+Joe Honda
+ALTER TABLE users DISABLE KEYS;
+TRUNCATE users;
+SELECT * FROM users;
+first_name last_name
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_updating.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_updating.result
new file mode 100644
index 00000000..8b6f94c0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_disable_keys_updating.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+c1 int NOT NULL,
+c2 text NOT NULL,
+c3 int NOT NULL,
+c4 int NOT NULL,
+PRIMARY KEY(c1),
+KEY idx1(c3,c4),
+FULLTEXT KEY ft1(c2)
+);
+INSERT INTO t1 VALUES(1, 'test1', 1, 1);
+INSERT INTO t1 VALUES(2, 'test2', 2, 2);
+INSERT INTO t1 VALUES(3, 'test3', 1, 3);
+ALTER TABLE t1 DISABLE KEYS;
+DELETE FROM t1 WHERE c1 = 2;
+UPDATE t1 SET c4 = 4 WHERE c1 = 1;
+INSERT INTO t1 VALUES(4, 'test4', 2, 4);
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_multiple.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_multiple.result
new file mode 100644
index 00000000..ea62084d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_multiple.result
@@ -0,0 +1,36 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+ALTER TABLE diaries
+DROP COLUMN title,
+DROP COLUMN body;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT * FROM diaries;
+id
+1
+INSERT INTO diaries () VALUES ();
+SELECT * FROM diaries;
+id
+1
+2
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_one.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_one.result
new file mode 100644
index 00000000..8b06caa0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_column_one.result
@@ -0,0 +1,37 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+ALTER TABLE diaries DROP COLUMN body;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT * FROM diaries;
+id title
+1 survey
+INSERT INTO diaries (title) values ("groonga (1)");
+INSERT INTO diaries (title) values ("groonga (2)");
+SELECT * FROM diaries;
+id title
+1 survey
+2 groonga (1)
+3 groonga (2)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_key_multiple_column_with_data.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_key_multiple_column_with_data.result
new file mode 100644
index 00000000..21aca41a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_key_multiple_column_with_data.result
@@ -0,0 +1,33 @@
+DROP TABLE IF EXISTS scores;
+SET NAMES UTF8;
+CREATE TABLE scores (
+id BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL,
+name CHAR(30) NOT NULL,
+score INT NOT NULL,
+KEY property (name, score)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` bigint(20) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `property` (`name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores
+WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+ALTER TABLE scores DROP KEY property;
+SELECT * FROM scores
+WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_primary_key.result
new file mode 100644
index 00000000..95914d30
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_drop_primary_key.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+ALTER TABLE ids DROP PRIMARY KEY;
+SHOW CREATE TABLE ids;
+Table Create Table
+ids CREATE TABLE `ids` (
+ `id` int(11) NOT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT * FROM ids WHERE id = 2;
+id
+2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext.result
new file mode 100644
index 00000000..e5c8a349
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_table.result
new file mode 100644
index 00000000..7b3b2863
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_table.result
@@ -0,0 +1,42 @@
+SET NAMES utf8;
+CREATE TABLE terms (
+term varchar(256) NOT NULL PRIMARY KEY
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"'
+ DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id int PRIMARY KEY,
+content text NOT NULL,
+FULLTEXT INDEX content_index (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+ALTER TABLE memos DISABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+column_create terms term COLUMN_SCALAR ShortText
+ALTER TABLE memos ENABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+column_create terms term COLUMN_SCALAR ShortText
+
+column_create terms content_index COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_ujis.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_ujis.result
new file mode 100644
index 00000000..3853cc84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_ujis.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES ujis;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=ujis;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "ŷ");
+INSERT INTO diaries VALUES (3, "ٻλ");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("ٻλ");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("ٻλ");
+id title
+3 ٻλ
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_utf8.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_utf8.result
new file mode 100644
index 00000000..e5c8a349
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_fulltext_utf8.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_multiple_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_multiple_column.result
new file mode 100644
index 00000000..e252061d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_multiple_column.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY title_and_created_at_index (title, created_at)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_normal.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_normal.result
new file mode 100644
index 00000000..0e56e78d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_normal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY created_at_index (created_at)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_primary.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_primary.result
new file mode 100644
index 00000000..722e62f9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_enable_keys_primary.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255)
+) DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_no_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_no_primary_key.result
new file mode 100644
index 00000000..ac0600e0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_no_primary_key.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+CREATE TABLE memos (
+content varchar(32)
+) DEFAULT CHARSET="utf8";
+INSERT INTO memos (content) values ("Starting Groonga...");
+INSERT INTO memos (content) values ("Started Groonga.");
+INSERT INTO memos (content) values ("Starting Mroonga...");
+ALTER TABLE memos ADD FULLTEXT INDEX content_index (content);
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `content` varchar(32) DEFAULT NULL,
+ FULLTEXT KEY `content_index` (`content`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT * FROM memos WHERE MATCH(content) AGAINST("groonga");
+content
+Starting Groonga...
+Started Groonga.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_normal.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_normal.result
new file mode 100644
index 00000000..cf6840a9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_normal.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS memos;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT
+) DEFAULT CHARSET="utf8";
+INSERT INTO memos (content) values ("Starting Groonga...");
+INSERT INTO memos (content) values ("Started Groonga.");
+INSERT INTO memos (content) values ("Starting Mroonga...");
+ALTER TABLE memos ADD FULLTEXT INDEX content_index (content);
+SELECT * FROM memos WHERE MATCH(content) AGAINST("+groonga" IN BOOLEAN MODE);
+id content
+1 Starting Groonga...
+2 Started Groonga.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_table.result
new file mode 100644
index 00000000..705d2f70
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_add_table.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS tags;
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags VARCHAR(40) COMMENT 'type "tags"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO tags (name) VALUES ("Groonga");
+INSERT INTO bugs (id, tags) VALUES (1, "Groonga Mroonga");
+SELECT * FROM bugs;
+id tags
+1 GROONGA MROONGA
+ALTER TABLE bugs ADD FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"';
+SELECT * FROM bugs
+WHERE MATCH(tags) AGAINST("Groonga");
+id tags
+1 GROONGA MROONGA
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_drop_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_drop_table.result
new file mode 100644
index 00000000..2d5e3d55
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_fulltext_drop_table.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS tags;
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags VARCHAR(40) COMMENT 'type "tags"',
+FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO tags (name) VALUES ("Groonga");
+INSERT INTO bugs (id, tags) VALUES (1, "Groonga Mroonga");
+ALTER TABLE bugs DROP INDEX bugs_tags_index;
+ALTER TABLE bugs
+ADD FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"';
+SELECT * FROM bugs
+WHERE MATCH(tags) AGAINST("Groonga");
+id tags
+1 GROONGA MROONGA
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_after.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_after.result
new file mode 100644
index 00000000..6ef97d89
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_after.result
@@ -0,0 +1,33 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+id title body
+1 groonga (1) starting groonga.
+ALTER TABLE diaries MODIFY body VARCHAR(140) AFTER id;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `body` varchar(140) DEFAULT NULL,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+id body title
+1 starting groonga. groonga (1)
+2 started groonga. groonga (2)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_first.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_first.result
new file mode 100644
index 00000000..b5d7df8d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_first.result
@@ -0,0 +1,33 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+id title body
+1 groonga (1) starting groonga.
+ALTER TABLE diaries MODIFY body VARCHAR(140) FIRST;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `body` varchar(140) DEFAULT NULL,
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+body id title
+starting groonga. 1 groonga (1)
+started groonga. 2 groonga (2)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_no_order.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_no_order.result
new file mode 100644
index 00000000..884ee68b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_modify_column_no_order.result
@@ -0,0 +1,33 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+id title body
+1 groonga (1) starting groonga.
+ALTER TABLE diaries MODIFY title VARCHAR(100);
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(100) DEFAULT NULL,
+ `body` varchar(140) DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+id title body
+1 groonga (1) starting groonga.
+2 groonga (2) started groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_recreate_anonymous_index_at_once.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_recreate_anonymous_index_at_once.result
new file mode 100644
index 00000000..6ee8f8ba
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_recreate_anonymous_index_at_once.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX (body)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("survey", "will start mroonga!");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 survey will start mroonga!
+SELECT * FROM diaries
+WHERE MATCH (body) AGAINST ("+groonga" IN BOOLEAN MODE);
+id title body
+1 survey will start groonga!
+ALTER TABLE diaries
+DROP INDEX body,
+ADD FULLTEXT INDEX (body);
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 survey will start mroonga!
+SELECT * FROM diaries
+WHERE MATCH (body) AGAINST ("+groonga" IN BOOLEAN MODE);
+id title body
+1 survey will start groonga!
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_rename_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_rename_table.result
new file mode 100644
index 00000000..84861ea7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_rename_table.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS diaries, memos;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SELECT table_name, engine
+FROM information_schema.tables
+WHERE table_name = 'diaries';
+table_name engine
+diaries Mroonga
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("groonga") AND
+MATCH(body) AGAINST("starting");
+id title body
+ALTER TABLE diaries RENAME memos;
+SELECT * FROM memos;
+id title body
+1 survey will start groonga!
+SELECT * FROM memos
+WHERE MATCH(title) AGAINST("groonga") AND
+MATCH(body) AGAINST("starting");
+id title body
+SELECT table_name, engine
+FROM information_schema.tables
+WHERE table_name = 'memos';
+table_name engine
+memos Mroonga
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_spatial.result b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_spatial.result
new file mode 100644
index 00000000..5ce6dfde
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/alter_table_spatial.result
@@ -0,0 +1,132 @@
+DROP TABLE IF EXISTS shops;
+CREATE TABLE shops (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name VARCHAR(40),
+location GEOMETRY NOT NULL
+);
+INSERT INTO shops (name, location)
+VALUES ('nezu-no-taiyaki',
+ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+VALUES ('taiyaki-kataoka',
+ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+VALUES ('soba-taiyaki-ku',
+ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+VALUES ('kuruma',
+ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+VALUES ('hirose-ya',
+ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+VALUES ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+VALUES ('omede-taiyaki',
+ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+VALUES ('onaga-ya',
+ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+VALUES ('shiro-ya',
+ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+VALUES ('fuji-ya',
+ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+VALUES ('miyoshi',
+ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+VALUES ('juju-ya',
+ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+VALUES ('tatsumi-ya',
+ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+VALUES ('tetsuji',
+ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+VALUES ('gazuma-ya',
+ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+VALUES ('honma-mon',
+ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+VALUES ('naniwa-ya',
+ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+VALUES ('kuro-dai',
+ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+VALUES ('daruma',
+ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+VALUES ('yanagi-ya',
+ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+VALUES ('sharaku',
+ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+VALUES ('takane',
+ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+VALUES ('chiyoda',
+ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+VALUES ('da-ka-po',
+ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+VALUES ('matsushima-ya',
+ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+VALUES ('kazuya',
+ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+VALUES ('furuya-kogane-an',
+ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+VALUES ('hachi-no-ie',
+ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+VALUES ('azuki-chan',
+ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+VALUES ('kuriko-an',
+ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+VALUES ('naze-ya',
+ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+VALUES ('sanoki-ya',
+ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+VALUES ('shigeta',
+ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+VALUES ('nishimi-ya',
+ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+VALUES ('hiiragi',
+ST_GeomFromText('POINT(139.711517 35.647701)'));
+ALTER TABLE shops ADD SPATIAL KEY location_index (location);
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ORDER BY id;
+id name location_text
+14 tetsuji POINT(139.76857 35.680911944444446)
+19 daruma POINT(139.7705988888889 35.68146111111111)
+26 kazuya POINT(139.760895 35.67350805555556)
+SHOW CREATE TABLE shops;
+Table Create Table
+shops CREATE TABLE `shops` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` varchar(40) DEFAULT NULL,
+ `location` geometry NOT NULL,
+ PRIMARY KEY (`id`),
+ SPATIAL KEY `location_index` (`location`)
+) ENGINE=Mroonga AUTO_INCREMENT=37 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+DROP TABLE shops;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..6a5729af
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_TODO_SPLIT_ME.result
@@ -0,0 +1,53 @@
+drop table if exists t1;
+create table t1 (c1 int auto_increment, primary key(c1));
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+c1
+1
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+c1
+2
+insert into t1 values(10);
+select c1 from t1 order by c1 desc limit 1;
+c1
+10
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+c1
+11
+insert into t1 values(6);
+select c1 from t1 order by c1 desc limit 1;
+c1
+11
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+c1
+12
+drop table t1;
+create table t1 (c1 int, c2 int auto_increment, primary key(c1), key idx1(c2));
+insert into t1 values(1, null);
+select * from t1 order by c2 desc limit 1;
+c1 c2
+1 1
+insert into t1 values(2, null);
+select * from t1 order by c2 desc limit 1;
+c1 c2
+2 2
+insert into t1 values(3, 10);
+select * from t1 order by c2 desc limit 1;
+c1 c2
+3 10
+insert into t1 values(4, null);
+select * from t1 order by c2 desc limit 1;
+c1 c2
+4 11
+insert into t1 values(5, 6);
+select * from t1 order by c2 desc limit 1;
+c1 c2
+4 11
+insert into t1 values(6, null);
+select * from t1 order by c2 desc limit 1;
+c1 c2
+6 12
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_table_param.result b/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_table_param.result
new file mode 100644
index 00000000..f997a9ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_table_param.result
@@ -0,0 +1,70 @@
+drop table if exists t1;
+create table t1 (c1 int auto_increment, primary key(c1)) auto_increment=34129;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+c1
+34129
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=Mroonga AUTO_INCREMENT=34130 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+c1
+34130
+34129
+insert into t1 values(10);
+select c1 from t1 order by c1 desc;
+c1
+34130
+34129
+10
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+c1
+34131
+34130
+34129
+10
+insert into t1 values(6);
+select c1 from t1 order by c1 desc;
+c1
+34131
+34130
+34129
+10
+6
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+c1
+34132
+34131
+34130
+34129
+10
+6
+truncate table t1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+c1
+1
+delete from t1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+c1
+2
+rename table t1 to t2;
+insert into t2 values(null);
+select c1 from t2 order by c1 desc;
+c1
+3
+2
+show create table t2;
+Table Create Table
+t2 CREATE TABLE `t2` (
+ `c1` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`c1`)
+) ENGINE=Mroonga AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+drop table t2;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_text.result b/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_text.result
new file mode 100644
index 00000000..fe5e6409
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/auto_increment_text.result
@@ -0,0 +1,15 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text
+);
+insert into diaries (body) values ("started groonga (long text)");
+select * from diaries;
+id body
+1 started groonga (long text)
+insert into diaries (body) values ("sleeping... (short text)");
+select * from diaries;
+id body
+1 started groonga (long text)
+2 sleeping... (short text)
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/binlog_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/binlog_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..340509f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/binlog_TODO_SPLIT_ME.result
@@ -0,0 +1,34 @@
+drop table if exists t1;
+show variables like 'log_bin';
+Variable_name Value
+log_bin ON
+set binlog_format="STATEMENT";
+create table t1 (c1 int primary key, c2 int) engine = mroonga;
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+c1 c2
+1 100
+2 100
+drop table t1;
+set binlog_format="ROW";
+create table t1 (c1 int primary key, c2 int) engine = mroonga;
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+c1 c2
+1 100
+2 100
+drop table t1;
+set binlog_format="MIXED";
+create table t1 (c1 int primary key, c2 int) engine = mroonga;
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+c1 c2
+1 100
+2 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result
new file mode 100644
index 00000000..4926a72a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_broken.result
@@ -0,0 +1,18 @@
+SET NAMES UTF8;
+CREATE DATABASE check_test;
+USE check_test;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT INDEX (title)
+);
+INSERT INTO diaries VALUES ('Hello');
+FLUSH TABLES;
+CHECK TABLE diaries;
+Table Op Msg_type Msg_text
+check_test.diaries check error Corrupt
+REPAIR TABLE diaries;
+Table Op Msg_type Msg_text
+check_test.diaries repair status OK
+DROP TABLE diaries;
+DROP DATABASE check_test;
+USE test;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/check_table_not_broken.result b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_not_broken.result
new file mode 100644
index 00000000..def3368e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/check_table_not_broken.result
@@ -0,0 +1,13 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+title TEXT
+);
+INSERT INTO diaries VALUES ('Hello');
+CHECK TABLE diaries;
+Table Op Msg_type Msg_text
+test.diaries check status OK
+SELECT * FROM diaries;
+title
+Hello
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_general_ci_french.result b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_general_ci_french.result
new file mode 100644
index 00000000..880092f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_general_ci_french.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+content varchar(256) COLLATE utf8_general_ci,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES ("Je suis un garçon.");
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("garcon");
+content
+Je suis un garçon.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_french.result b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_french.result
new file mode 100644
index 00000000..b9e22da4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_french.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8mb4;
+CREATE TABLE diaries (
+content varchar(256) COLLATE utf8mb4_unicode_520_ci,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8mb4;
+INSERT INTO diaries VALUES ("Je suis un garçon.");
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("+garcon" IN BOOLEAN MODE);
+content
+Je suis un garçon.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_japanese.result b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_japanese.result
new file mode 100644
index 00000000..29e55b7d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_520_ci_japanese.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8mb4;
+CREATE TABLE diaries (
+content varchar(256) COLLATE utf8mb4_unicode_520_ci,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8mb4;
+INSERT INTO diaries VALUES ("ひらがなとカタカナを覚えました。");
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+かたかな" IN BOOLEAN MODE);
+content
+ひらがなとカタカナを覚えました。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_french.result b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_french.result
new file mode 100644
index 00000000..3f24de87
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_french.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+content varchar(256) COLLATE utf8_unicode_ci,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES ("Je suis un garçon.");
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("garcon");
+content
+Je suis un garçon.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_japanese.result b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_japanese.result
new file mode 100644
index 00000000..94ef2608
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/collation_utf8_unicode_ci_japanese.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+content varchar(256) COLLATE utf8_unicode_ci,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES ("ひらがなとカタカナを覚えました。");
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("かたかな");
+content
+ひらがなとカタカナを覚えました。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_comment_index_not_for_mroonga.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_comment_index_not_for_mroonga.result
new file mode 100644
index 00000000..e09f4e83
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_comment_index_not_for_mroonga.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED,
+INDEX (id) COMMENT 'ID search is required.'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned DEFAULT NULL,
+ KEY `id` (`id`) COMMENT 'ID search is required.'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_comment_normal_not_for_mroonga.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_comment_normal_not_for_mroonga.result
new file mode 100644
index 00000000..01c4f64f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_comment_normal_not_for_mroonga.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tag` varchar(64) DEFAULT NULL COMMENT 'It must consist of only alphabet and number.',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_date_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_date_with_index.result
new file mode 100644
index 00000000..57d2c417
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_date_with_index.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+created_at DATE,
+KEY (created_at)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `created_at` date DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `created_at` (`created_at`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, created_at) VALUES ("clear day", "2012-01-29");
+INSERT INTO diaries (title, created_at) VALUES ("rainy day", "2012-01-30");
+INSERT INTO diaries (title, created_at) VALUES ("cloudy day", "2012-01-31");
+SELECT * FROM diaries;
+id title created_at
+1 clear day 2012-01-29
+2 rainy day 2012-01-30
+3 cloudy day 2012-01-31
+SELECT * FROM diaries WHERE created_at BETWEEN "2012-01-29" AND "2012-01-30";
+id title created_at
+1 clear day 2012-01-29
+2 rainy day 2012-01-30
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_date_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_date_without_index.result
new file mode 100644
index 00000000..26af0dd9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_date_without_index.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(40),
+created_at DATE
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` varchar(40) DEFAULT NULL,
+ `created_at` date DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO diaries (title, created_at) VALUES ("clear day", "2012-01-29");
+INSERT INTO diaries (title, created_at) VALUES ("rainy day", "2012-01-30");
+INSERT INTO diaries (title, created_at) VALUES ("cloudy day", "2012-01-31");
+SELECT * FROM diaries;
+id title created_at
+1 clear day 2012-01-29
+2 rainy day 2012-01-30
+3 cloudy day 2012-01-31
+SELECT * FROM diaries WHERE created_at BETWEEN "2012-01-29" AND "2012-01-30";
+id title created_at
+1 clear day 2012-01-29
+2 rainy day 2012-01-30
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_date_zero_date.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_date_zero_date.result
new file mode 100644
index 00000000..022d6c00
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_date_zero_date.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATE
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE timestamps;
+Table Create Table
+timestamps CREATE TABLE `timestamps` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `create_dt` date DEFAULT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+SET sql_mode = '';
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01");
+Warnings:
+Warning 1265 Data truncated for column 'create_dt' at row 1
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00");
+Warnings:
+Warning 1265 Data truncated for column 'create_dt' at row 1
+SET sql_mode = DEFAULT;
+SELECT * FROM timestamps;
+id create_dt
+1 2012-01-01
+2 2012-01-01
+SELECT * FROM timestamps WHERE create_dt = "2012-01-01";
+id create_dt
+1 2012-01-01
+2 2012-01-01
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_2038.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_2038.result
new file mode 100644
index 00000000..712d87ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_2038.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('2038-01-18 03:14:07', '2038-01-18 03:14:07');
+INSERT IGNORE INTO diaries (title, created_at)
+VALUES ('2038-01-20 03:14:08', '2038-01-20 03:14:08');
+Warnings:
+Warning 1265 Data truncated for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 2038-01-18 03:14:07 2038-01-18 03:14:07
+2 2038-01-20 03:14:08 1970-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_before_unix_epoch.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_before_unix_epoch.result
new file mode 100644
index 00000000..85f091cc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_before_unix_epoch.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT IGNORE INTO diaries (title, created_at)
+VALUES ('1000-01-01 00:00:00', '1000-01-01 00:00:00');
+Warnings:
+Warning 1265 Data truncated for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 1000-01-01 00:00:00 1970-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_max.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_max.result
new file mode 100644
index 00000000..9d9e2f61
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_max.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT IGNORE INTO diaries (title, created_at)
+VALUES ('9999-12-31 23:59:59', '9999-12-31 23:59:59');
+Warnings:
+Warning 1265 Data truncated for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 9999-12-31 23:59:59 1970-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_out_of_range.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_out_of_range.result
new file mode 100644
index 00000000..99611268
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_32bit_out_of_range.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT IGNORE INTO diaries (title, created_at)
+VALUES ('2012', '2012');
+Warnings:
+Warning 1265 Data truncated for column 'created_at' at row 1
+Warning 1265 Data truncated for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 2012 1970-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_2038.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_2038.result
new file mode 100644
index 00000000..f0f03a82
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_2038.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('2038-01-19 03:14:07', '2038-01-19 03:14:07');
+INSERT INTO diaries (title, created_at)
+VALUES ('2038-01-19 03:14:08', '2038-01-19 03:14:08');
+SELECT * FROM diaries;
+id title created_at
+1 2038-01-19 03:14:07 2038-01-19 03:14:07
+2 2038-01-19 03:14:08 2038-01-19 03:14:08
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_before_unix_epoch.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_before_unix_epoch.result
new file mode 100644
index 00000000..8a775960
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_before_unix_epoch.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('1000-01-02 00:00:00', '1000-01-02 00:00:00');
+SELECT * FROM diaries;
+id title created_at
+1 1000-01-02 00:00:00 1000-01-02 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_max.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_max.result
new file mode 100644
index 00000000..44d20d97
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_max.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('9999-12-31 23:59:59', '9999-12-31 23:59:59');
+SELECT * FROM diaries;
+id title created_at
+1 9999-12-31 23:59:59 9999-12-31 23:59:59
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_strict_sql_mode_out_of_range.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_strict_sql_mode_out_of_range.result
new file mode 100644
index 00000000..6617b49d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_strict_sql_mode_out_of_range.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('2012', '2012');
+ERROR 22007: Incorrect datetime value: '2012' for column `test`.`diaries`.`created_at` at row 1
+SELECT * FROM diaries;
+id title created_at
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_5_out_of_range.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_5_out_of_range.result
new file mode 100644
index 00000000..21e715e1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_5_out_of_range.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('2012', '2012');
+Warnings:
+Warning 1264 Out of range value for column 'created_at' at row 1
+Warning 1265 Data truncated for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 2012 0000-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_6_or_later_out_of_range.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_6_or_later_out_of_range.result
new file mode 100644
index 00000000..3500d651
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_64bit_version_5_6_or_later_out_of_range.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('2012', '2012');
+Warnings:
+Warning 1265 Data truncated for column 'created_at' at row 1
+Warning 1265 Data truncated for column 'created_at' at row 1
+INSERT INTO diaries (title, created_at) VALUES ('2012', '2012');
+ERROR 22007: Incorrect datetime value: '2012' for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 2012 0000-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_with_index.result
new file mode 100644
index 00000000..e7094fd4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_with_index.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME(6),
+KEY (created_at)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ("clear day", "2012-01-29 21:51:01.111111");
+INSERT INTO diaries (title, created_at)
+VALUES ("rainy day", "2012-01-30 01:23:45.333");
+INSERT INTO diaries (title, created_at)
+VALUES ("cloudy day", "2012-01-31 08:32:10.5555");
+SELECT * FROM diaries;
+id title created_at
+1 clear day 2012-01-29 21:51:01.111111
+2 rainy day 2012-01-30 01:23:45.333000
+3 cloudy day 2012-01-31 08:32:10.555500
+SELECT * FROM diaries
+WHERE created_at BETWEEN "2012-01-29 00:00:00.123456" AND
+"2012-01-31 00:00:00.999999";
+id title created_at
+1 clear day 2012-01-29 21:51:01.111111
+2 rainy day 2012-01-30 01:23:45.333000
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_without_index.result
new file mode 100644
index 00000000..028fb257
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_fractional_seconds_without_index.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME(6)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ("clear day", "2012-01-29 21:51:01.111111");
+INSERT INTO diaries (title, created_at)
+VALUES ("rainy day", "2012-01-30 01:23:45.333");
+INSERT INTO diaries (title, created_at)
+VALUES ("cloudy day", "2012-01-31 08:32:10.5555");
+SELECT * FROM diaries;
+id title created_at
+1 clear day 2012-01-29 21:51:01.111111
+2 rainy day 2012-01-30 01:23:45.333000
+3 cloudy day 2012-01-31 08:32:10.555500
+SELECT * FROM diaries
+WHERE created_at BETWEEN "2012-01-29 00:00:00.123456" AND
+"2012-01-31 00:00:00.999999";
+id title created_at
+1 clear day 2012-01-29 21:51:01.111111
+2 rainy day 2012-01-30 01:23:45.333000
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_freebsd_before_unix_epoch.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_freebsd_before_unix_epoch.result
new file mode 100644
index 00000000..a48be4da
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_freebsd_before_unix_epoch.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('1000-01-01 00:00:00', '1000-01-01 00:00:00');
+Warnings:
+Warning 1265 Data truncated for column 'created_at' at row 1
+SELECT * FROM diaries;
+id title created_at
+1 1000-01-01 00:00:00 1970-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_date.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_date.result
new file mode 100644
index 00000000..ffd6a707
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_date.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO timestamps (create_dt) VALUES ("0000-00-00 00:00:00");
+ERROR 22003: Out of range value for column 'create_dt' at row 1
+SELECT * FROM timestamps;
+id create_dt
+INSERT INTO timestamps (create_dt) VALUES ("2015-06-17 00:00:00");
+SELECT * FROM timestamps;
+id create_dt
+2 2015-06-17 00:00:00
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_month_day.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_month_day.result
new file mode 100644
index 00000000..61d2ed8d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mariadb_10_2_or_later_zero_month_day.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01 00:00:00");
+ERROR 22003: Out of range value for column 'create_dt' at row 1
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00 00:00:00");
+ERROR 22003: Out of range value for column 'create_dt' at row 1
+SELECT * FROM timestamps;
+id create_dt
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_date.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_date.result
new file mode 100644
index 00000000..0ca19e54
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_date.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO timestamps (create_dt) VALUES ("0000-00-00 00:00:00");
+ERROR 22007: Incorrect datetime value: '0000-00-00 00:00:00' for column 'create_dt' at row 1
+SELECT * FROM timestamps;
+id create_dt
+INSERT INTO timestamps (create_dt) VALUES ("2015-06-17 00:00:00");
+SELECT * FROM timestamps;
+id create_dt
+1 2015-06-17 00:00:00
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_month_day.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_month_day.result
new file mode 100644
index 00000000..94479c23
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_mysql_5_7_or_later_zero_month_day.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01 00:00:00");
+ERROR 22007: Incorrect datetime value: '2012-00-01 00:00:00' for column 'create_dt' at row 1
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00 00:00:00");
+ERROR 22007: Incorrect datetime value: '2012-01-00 00:00:00' for column 'create_dt' at row 1
+SELECT * FROM timestamps;
+id create_dt
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_null.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_null.result
new file mode 100644
index 00000000..510fa2dc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_null.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ('NULL', NULL);
+SELECT * FROM diaries;
+id title created_at
+1 NULL 1970-01-01 00:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_with_index.result
new file mode 100644
index 00000000..6f79b31f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_with_index.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME,
+KEY (created_at)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ("clear day", "2012-01-29 21:51:01");
+INSERT INTO diaries (title, created_at)
+VALUES ("rainy day", "2012-01-30 01:23:45");
+INSERT INTO diaries (title, created_at)
+VALUES ("cloudy day", "2012-01-31 08:32:10");
+SELECT * FROM diaries;
+id title created_at
+1 clear day 2012-01-29 21:51:01
+2 rainy day 2012-01-30 01:23:45
+3 cloudy day 2012-01-31 08:32:10
+SELECT * FROM diaries
+WHERE created_at BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+id title created_at
+1 clear day 2012-01-29 21:51:01
+2 rainy day 2012-01-30 01:23:45
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_without_index.result
new file mode 100644
index 00000000..8a45ece7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_without_index.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at)
+VALUES ("clear day", "2012-01-29 21:51:01");
+INSERT INTO diaries (title, created_at)
+VALUES ("rainy day", "2012-01-30 01:23:45");
+INSERT INTO diaries (title, created_at)
+VALUES ("cloudy day", "2012-01-31 08:32:10");
+SELECT * FROM diaries;
+id title created_at
+1 clear day 2012-01-29 21:51:01
+2 rainy day 2012-01-30 01:23:45
+3 cloudy day 2012-01-31 08:32:10
+SELECT * FROM diaries
+WHERE created_at BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+id title created_at
+1 clear day 2012-01-29 21:51:01
+2 rainy day 2012-01-30 01:23:45
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_date.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_date.result
new file mode 100644
index 00000000..659c5742
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_date.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+SET sql_mode='STRICT_TRANS_TABLES';
+INSERT INTO timestamps (create_dt) VALUES ("0000-00-00 00:00:00");
+ERROR 22003: Out of range value for column 'create_dt' at row 1
+SET sql_mode=default;
+SELECT * FROM timestamps;
+id create_dt
+INSERT INTO timestamps (create_dt) VALUES ("2015-06-17 00:00:00");
+SELECT * FROM timestamps;
+id create_dt
+2 2015-06-17 00:00:00
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_month_day.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_month_day.result
new file mode 100644
index 00000000..03633a50
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_datetime_zero_month_day.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS timestamps;
+CREATE TABLE timestamps (
+id INT PRIMARY KEY AUTO_INCREMENT,
+create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01 00:00:00");
+Warnings:
+Warning 1265 Data truncated for column 'create_dt' at row 1
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00 00:00:00");
+Warnings:
+Warning 1265 Data truncated for column 'create_dt' at row 1
+SELECT * FROM timestamps;
+id create_dt
+1 2012-01-01 00:00:00
+2 2012-01-01 00:00:00
+SELECT * FROM timestamps WHERE create_dt = "2012-01-01 00:00:00";
+id create_dt
+1 2012-01-01 00:00:00
+2 2012-01-01 00:00:00
+DROP TABLE timestamps;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_with_index.result
new file mode 100644
index 00000000..196e4b80
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_with_index.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+temperature DECIMAL(6, 3),
+KEY (temperature)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21.281);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14.213);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17.821);
+SELECT * FROM diaries;
+id title temperature
+1 clear day 21.281
+2 rainy day 14.213
+3 cloudy day 17.821
+SELECT * FROM diaries WHERE temperature BETWEEN "14.213" AND "17.821";
+id title temperature
+2 rainy day 14.213
+3 cloudy day 17.821
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_without_index.result
new file mode 100644
index 00000000..b67846bb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_fractional_seconds_without_index.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+temperature DECIMAL(6, 3)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21.281);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14.213);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17.821);
+SELECT * FROM diaries;
+id title temperature
+1 clear day 21.281
+2 rainy day 14.213
+3 cloudy day 17.821
+SELECT * FROM diaries WHERE temperature BETWEEN "14.213" AND "17.821";
+id title temperature
+2 rainy day 14.213
+3 cloudy day 17.821
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_with_index.result
new file mode 100644
index 00000000..620e9b69
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_with_index.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+temperature DECIMAL,
+KEY (temperature)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17);
+SELECT * FROM diaries;
+id title temperature
+1 clear day 21
+2 rainy day 14
+3 cloudy day 17
+SELECT * FROM diaries WHERE temperature BETWEEN "14" AND "17";
+id title temperature
+2 rainy day 14
+3 cloudy day 17
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_without_index.result
new file mode 100644
index 00000000..1ba47b34
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_decimal_without_index.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+temperature DECIMAL
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17);
+SELECT * FROM diaries;
+id title temperature
+1 clear day 21
+2 rainy day 14
+3 cloudy day 17
+SELECT * FROM diaries WHERE temperature BETWEEN "14" AND "17";
+id title temperature
+2 rainy day 14
+3 cloudy day 17
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_enum_less_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_enum_less_with_index.result
new file mode 100644
index 00000000..abec4eca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_enum_less_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+size ENUM("small", "medium", "large"),
+INDEX (size)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `size` enum('small','medium','large') DEFAULT NULL,
+ KEY `size` (`size`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart for child", "small");
+INSERT INTO items VALUES ("leadies' coat", "medium");
+INSERT INTO items VALUES ("parka", "large");
+INSERT INTO items VALUES ("hat", "medium");
+SELECT * FROM items;
+name size
+t-shart for child small
+leadies' coat medium
+parka large
+hat medium
+SELECT * FROM items WHERE size = "medium";
+name size
+leadies' coat medium
+hat medium
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_enum_many_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_enum_many_with_index.result
new file mode 100644
index 00000000..d116ff9e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_enum_many_with_index.result
@@ -0,0 +1,287 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+size ENUM("size1",
+"size2",
+"size3",
+"size4",
+"size5",
+"size6",
+"size7",
+"size8",
+"size9",
+"size10",
+"size11",
+"size12",
+"size13",
+"size14",
+"size15",
+"size16",
+"size17",
+"size18",
+"size19",
+"size20",
+"size21",
+"size22",
+"size23",
+"size24",
+"size25",
+"size26",
+"size27",
+"size28",
+"size29",
+"size30",
+"size31",
+"size32",
+"size33",
+"size34",
+"size35",
+"size36",
+"size37",
+"size38",
+"size39",
+"size40",
+"size41",
+"size42",
+"size43",
+"size44",
+"size45",
+"size46",
+"size47",
+"size48",
+"size49",
+"size50",
+"size51",
+"size52",
+"size53",
+"size54",
+"size55",
+"size56",
+"size57",
+"size58",
+"size59",
+"size60",
+"size61",
+"size62",
+"size63",
+"size64",
+"size65",
+"size66",
+"size67",
+"size68",
+"size69",
+"size70",
+"size71",
+"size72",
+"size73",
+"size74",
+"size75",
+"size76",
+"size77",
+"size78",
+"size79",
+"size80",
+"size81",
+"size82",
+"size83",
+"size84",
+"size85",
+"size86",
+"size87",
+"size88",
+"size89",
+"size90",
+"size91",
+"size92",
+"size93",
+"size94",
+"size95",
+"size96",
+"size97",
+"size98",
+"size99",
+"size100",
+"size101",
+"size102",
+"size103",
+"size104",
+"size105",
+"size106",
+"size107",
+"size108",
+"size109",
+"size110",
+"size111",
+"size112",
+"size113",
+"size114",
+"size115",
+"size116",
+"size117",
+"size118",
+"size119",
+"size120",
+"size121",
+"size122",
+"size123",
+"size124",
+"size125",
+"size126",
+"size127",
+"size128",
+"size129",
+"size130",
+"size131",
+"size132",
+"size133",
+"size134",
+"size135",
+"size136",
+"size137",
+"size138",
+"size139",
+"size140",
+"size141",
+"size142",
+"size143",
+"size144",
+"size145",
+"size146",
+"size147",
+"size148",
+"size149",
+"size150",
+"size151",
+"size152",
+"size153",
+"size154",
+"size155",
+"size156",
+"size157",
+"size158",
+"size159",
+"size160",
+"size161",
+"size162",
+"size163",
+"size164",
+"size165",
+"size166",
+"size167",
+"size168",
+"size169",
+"size170",
+"size171",
+"size172",
+"size173",
+"size174",
+"size175",
+"size176",
+"size177",
+"size178",
+"size179",
+"size180",
+"size181",
+"size182",
+"size183",
+"size184",
+"size185",
+"size186",
+"size187",
+"size188",
+"size189",
+"size190",
+"size191",
+"size192",
+"size193",
+"size194",
+"size195",
+"size196",
+"size197",
+"size198",
+"size199",
+"size200",
+"size201",
+"size202",
+"size203",
+"size204",
+"size205",
+"size206",
+"size207",
+"size208",
+"size209",
+"size210",
+"size211",
+"size212",
+"size213",
+"size214",
+"size215",
+"size216",
+"size217",
+"size218",
+"size219",
+"size220",
+"size221",
+"size222",
+"size223",
+"size224",
+"size225",
+"size226",
+"size227",
+"size228",
+"size229",
+"size230",
+"size231",
+"size232",
+"size233",
+"size234",
+"size235",
+"size236",
+"size237",
+"size238",
+"size239",
+"size240",
+"size241",
+"size242",
+"size243",
+"size244",
+"size245",
+"size246",
+"size247",
+"size248",
+"size249",
+"size250",
+"size251",
+"size252",
+"size253",
+"size254",
+"size255",
+"size256"),
+INDEX (size)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `size` enum('size1','size2','size3','size4','size5','size6','size7','size8','size9','size10','size11','size12','size13','size14','size15','size16','size17','size18','size19','size20','size21','size22','size23','size24','size25','size26','size27','size28','size29','size30','size31','size32','size33','size34','size35','size36','size37','size38','size39','size40','size41','size42','size43','size44','size45','size46','size47','size48','size49','size50','size51','size52','size53','size54','size55','size56','size57','size58','size59','size60','size61','size62','size63','size64','size65','size66','size67','size68','size69','size70','size71','size72','size73','size74','size75','size76','size77','size78','size79','size80','size81','size82','size83','size84','size85','size86','size87','size88','size89','size90','size91','size92','size93','size94','size95','size96','size97','size98','size99','size100','size101','size102','size103','size104','size105','size106','size107','size108','size109','size110','size111','size112','size113','size114','size115','size116','size117','size118','size119','size120','size121','size122','size123','size124','size125','size126','size127','size128','size129','size130','size131','size132','size133','size134','size135','size136','size137','size138','size139','size140','size141','size142','size143','size144','size145','size146','size147','size148','size149','size150','size151','size152','size153','size154','size155','size156','size157','size158','size159','size160','size161','size162','size163','size164','size165','size166','size167','size168','size169','size170','size171','size172','size173','size174','size175','size176','size177','size178','size179','size180','size181','size182','size183','size184','size185','size186','size187','size188','size189','size190','size191','size192','size193','size194','size195','size196','size197','size198','size199','size200','size201','size202','size203','size204','size205','size206','size207','size208','size209','size210','size211','size212','size213','size214','size215','size216','size217','size218','size219','size220','size221','size222','size223','size224','size225','size226','size227','size228','size229','size230','size231','size232','size233','size234','size235','size236','size237','size238','size239','size240','size241','size242','size243','size244','size245','size246','size247','size248','size249','size250','size251','size252','size253','size254','size255','size256') DEFAULT NULL,
+ KEY `size` (`size`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart for child", "size1");
+INSERT INTO items VALUES ("leadies' coat", "size1");
+INSERT INTO items VALUES ("parka", "size256");
+INSERT INTO items VALUES ("hat", "size256");
+SELECT * FROM items;
+name size
+t-shart for child size1
+leadies' coat size1
+parka size256
+hat size256
+SELECT * FROM items WHERE size = "size1";
+name size
+t-shart for child size1
+leadies' coat size1
+SELECT * FROM items WHERE size = "size256";
+name size
+parka size256
+hat size256
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_add_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_add_column.result
new file mode 100644
index 00000000..924c3134
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_add_column.result
@@ -0,0 +1,16 @@
+set names utf8mb4;
+CREATE TABLE logs (
+id INT,
+record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (1, json_object('message', repeat('☹', 253)));
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED;
+ALTER TABLE logs ADD FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"';
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_delete.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_delete.result
new file mode 100644
index 00000000..1ee7d8f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_delete.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+DELETE FROM logs WHERE id = 1;
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_drop_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_drop_column.result
new file mode 100644
index 00000000..5b518516
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_drop_column.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+ALTER TABLE logs DROP COLUMN message;
+SELECT * FROM logs;
+id record
+1 {"level": "info", "message": "start"}
+2 {"level": "info", "message": "restart"}
+3 {"level": "warn", "message": "abort"}
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_insert.result
new file mode 100644
index 00000000..ff22175e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_insert.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_reindex.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_reindex.result
new file mode 100644
index 00000000..fac82467
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_reindex.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+ALTER TABLE logs DISABLE KEYS;
+ALTER TABLE logs ENABLE KEYS;
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_update.result
new file mode 100644
index 00000000..71fc442d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_stored_update.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+SELECT * FROM logs WHERE MATCH(message) AGAINST("hut" IN BOOLEAN MODE);
+id record message
+2 {"level": "info", "message": "shutdown"} "shutdown"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_add_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_add_column.result
new file mode 100644
index 00000000..27c9effc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_add_column.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL;
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs;
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_delete.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_delete.result
new file mode 100644
index 00000000..260c774e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_delete.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+DELETE FROM logs WHERE id = 1;
+SELECT * FROM logs;
+id record message
+2 {"level": "info", "message": "restart"} "restart"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_drop_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_drop_column.result
new file mode 100644
index 00000000..bc9339ab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_drop_column.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+ALTER TABLE logs DROP COLUMN message;
+SELECT * FROM logs;
+id record
+1 {"level": "info", "message": "start"}
+2 {"level": "info", "message": "restart"}
+3 {"level": "warn", "message": "abort"}
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_insert.result
new file mode 100644
index 00000000..92463c94
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_insert.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs;
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_add_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_add_index.result
new file mode 100644
index 00000000..1a502edf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_add_index.result
@@ -0,0 +1,9 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+ALTER TABLE logs ADD INDEX (message);
+ERROR HY000: mroonga: storage: failed to create index: Index for virtual generated column is not supported: message
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.result
new file mode 100644
index 00000000..16acc89b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.result
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL,
+FULLTEXT INDEX (message)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+ERROR HY000: mroonga: storage: failed to create index: Index for virtual generated column is not supported: message
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mysql_5_7_or_later_add_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mysql_5_7_or_later_add_index.result
new file mode 100644
index 00000000..93046e39
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_mysql_5_7_or_later_add_index.result
@@ -0,0 +1,9 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+ALTER TABLE logs ADD INDEX (message);
+ERROR HY000: Table storage engine 'Mroonga' does not support the create option 'Index on virtual generated column'
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_update.result
new file mode 100644
index 00000000..c4e46d0d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_generated_virtual_update.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+SELECT * FROM logs;
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "shutdown"} "shutdown"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id__id.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id__id.result
new file mode 100644
index 00000000..33f31ed3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id__id.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS contents;
+CREATE TABLE contents (
+_id INT,
+content TEXT NOT NULL,
+FULLTEXT INDEX(content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO contents (content) VALUES ('first');
+INSERT INTO contents (content) VALUES ('second');
+SELECT _id, content FROM contents;
+_id content
+1 first
+2 second
+DROP TABLE contents;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id_invalid_id.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id_invalid_id.result
new file mode 100644
index 00000000..903e3a85
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga__id_invalid_id.result
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS contents;
+CREATE TABLE contents (
+_i INT,
+content TEXT NOT NULL,
+FULLTEXT INDEX(content)
+) DEFAULT CHARSET=utf8;
+ERROR HY000: [column][create] name can't start with '_' and contains only 0-9, A-Z, a-z, #, @, - or _: <_i>
+DROP TABLE IF EXISTS contents;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_other_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_other_table.result
new file mode 100644
index 00000000..767fe491
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_other_table.result
@@ -0,0 +1,30 @@
+CREATE TABLE terms (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COMMENT='default_tokenizer "TokenBigram"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+title TEXT,
+FULLTEXT INDEX (title) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO bugs (id, title) VALUES (1, "Mroonga can't build with MySQL X.Y.Z");
+SELECT * FROM terms ORDER BY name;
+name
+'
+.
+BUILD
+CAN
+MROONGA
+MYSQL
+T
+WITH
+X
+Y
+Z
+SELECT *, MATCH (title) AGAINST ("+MySQL" IN BOOLEAN MODE) AS score
+FROM bugs
+WHERE MATCH (title) AGAINST ("+MySQL" IN BOOLEAN MODE);
+id title score
+1 Mroonga can't build with MySQL X.Y.Z 1
+DROP TABLE bugs;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_vector_other_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_vector_other_table.result
new file mode 100644
index 00000000..f9fc8366
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_fulltext_vector_other_table.result
@@ -0,0 +1,38 @@
+DROP DATABASE IF EXISTS mroonga;
+CREATE DATABASE mroonga;
+USE mroonga;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags TEXT COMMENT 'flags "COLUMN_VECTOR", type "tags"',
+FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL groonga");
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY ShortText --default_tokenizer TokenDelimit
+column_create tags name COLUMN_SCALAR ShortText
+
+column_create bugs tags COLUMN_VECTOR tags
+
+column_create tags bugs_tags_index COLUMN_INDEX|WITH_POSITION bugs tags
+SELECT *, MATCH (tags) AGAINST ("+MySQL" IN BOOLEAN MODE) AS score
+FROM bugs
+WHERE MATCH (tags) AGAINST ("+MySQL" IN BOOLEAN MODE);
+id tags score
+1 Linux MySQL groonga 1
+DROP TABLE bugs;
+DROP TABLE tags;
+DROP DATABASE mroonga;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_int_other_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_int_other_table.result
new file mode 100644
index 00000000..0f57885c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_index_int_other_table.result
@@ -0,0 +1,39 @@
+DROP DATABASE IF EXISTS mroonga;
+CREATE DATABASE mroonga;
+USE mroonga;
+CREATE TABLE priorities (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+priority INT COMMENT 'type "priorities"',
+INDEX bugs_priority_index (priority) COMMENT 'table "priorities"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO bugs (id, priority) VALUES (1, 10);
+INSERT INTO bugs (id, priority) VALUES (2, 3);
+INSERT INTO bugs (id, priority) VALUES (3, -2);
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create priorities TABLE_PAT_KEY Int32
+column_create priorities id COLUMN_SCALAR Int32
+
+column_create bugs priority COLUMN_SCALAR priorities
+
+column_create priorities bugs_priority_index COLUMN_INDEX bugs priority
+SELECT *
+FROM bugs
+WHERE priority = 3;
+id priority
+2 3
+DROP TABLE bugs;
+DROP TABLE priorities;
+DROP DATABASE mroonga;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_reference.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_reference.result
new file mode 100644
index 00000000..8acf8aab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_reference.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS tags, bugs;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag TEXT COMMENT 'type "tags"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO bugs (id, tag) VALUES (1, "Linux");
+INSERT INTO bugs (id, tag) VALUES (2, "MySQL");
+INSERT INTO bugs (id, tag) VALUES (3, "groonga");
+SELECT * FROM bugs;
+id tag
+1 Linux
+2 MySQL
+3 groonga
+SELECT * FROM tags;
+name
+Linux
+MySQL
+groonga
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_lz4.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_lz4.result
new file mode 100644
index 00000000..11875e15
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_lz4.result
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS entries;
+CREATE TABLE entries (
+id INT UNSIGNED PRIMARY KEY,
+content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_LZ4"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+SELECT * FROM entries;
+id content
+1 I found Mroonga that is a MySQL storage engine to use Groonga!
+DROP TABLE entries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zlib.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zlib.result
new file mode 100644
index 00000000..5d704e3e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zlib.result
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS entries;
+CREATE TABLE entries (
+id INT UNSIGNED PRIMARY KEY,
+content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZLIB"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+SELECT * FROM entries;
+id content
+1 I found Mroonga that is a MySQL storage engine to use Groonga!
+DROP TABLE entries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zstd.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zstd.result
new file mode 100644
index 00000000..a9c917f8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_support_zstd.result
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS entries;
+CREATE TABLE entries (
+id INT UNSIGNED PRIMARY KEY,
+content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZSTD"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+SELECT * FROM entries;
+id content
+1 I found Mroonga that is a MySQL storage engine to use Groonga!
+DROP TABLE entries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_lz4.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_lz4.result
new file mode 100644
index 00000000..a9a5f55f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_lz4.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS entries;
+CREATE TABLE entries (
+id INT UNSIGNED PRIMARY KEY,
+content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_LZ4"'
+) DEFAULT CHARSET=utf8;
+Warnings:
+Warning 16506 The column flag 'COMPRESS_LZ4' is unsupported. It is ignored
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+SELECT * FROM entries;
+id content
+1 I found Mroonga that is a MySQL storage engine to use Groonga!
+DROP TABLE entries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zlib.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zlib.result
new file mode 100644
index 00000000..068ce58b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zlib.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS entries;
+CREATE TABLE entries (
+id INT UNSIGNED PRIMARY KEY,
+content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZLIB"'
+) DEFAULT CHARSET=utf8;
+Warnings:
+Warning 16506 The column flag 'COMPRESS_ZLIB' is unsupported. It is ignored
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+SELECT * FROM entries;
+id content
+1 I found Mroonga that is a MySQL storage engine to use Groonga!
+DROP TABLE entries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zstd.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zstd.result
new file mode 100644
index 00000000..b2bb3b89
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_unsupport_zstd.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS entries;
+CREATE TABLE entries (
+id INT UNSIGNED PRIMARY KEY,
+content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZSTD"'
+) DEFAULT CHARSET=utf8;
+Warnings:
+Warning 16506 The column flag 'COMPRESS_ZSTD' is unsupported. It is ignored
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+SELECT * FROM entries;
+id content
+1 I found Mroonga that is a MySQL storage engine to use Groonga!
+DROP TABLE entries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_with_not_for_mroonga_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_with_not_for_mroonga_comment.result
new file mode 100644
index 00000000..f94f5684
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_scalar_with_not_for_mroonga_comment.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS tags, bugs;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag TEXT COMMENT 'It references to tags.name, type "tags"'
+) DEFAULT CHARSET=utf8;
+SHOW FULL COLUMNS FROM bugs LIKE 'tag';
+Field Type Collation Null Key Default Extra Privileges Comment
+tag text utf8mb3_general_ci YES NULL select,insert,update,references It references to tags.name, type "tags"
+INSERT INTO bugs (id, tag) VALUES (1, "Linux");
+INSERT INTO bugs (id, tag) VALUES (2, "MySQL");
+INSERT INTO bugs (id, tag) VALUES (3, "groonga");
+SELECT * FROM bugs;
+id tag
+1 Linux
+2 MySQL
+3 groonga
+SELECT * FROM tags;
+name
+Linux
+MySQL
+groonga
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_order_by_with_function.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_order_by_with_function.result
new file mode 100644
index 00000000..468115e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_order_by_with_function.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS tags, bugs;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags TEXT COMMENT 'flags "COLUMN_VECTOR", type "tags"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL Groonga");
+INSERT INTO bugs (id, tags) VALUES (2, "MySQL Mroonga");
+INSERT INTO bugs (id, tags) VALUES (3, "Ruby Rroonga");
+SELECT * FROM tags ORDER BY SUBSTRING(name, 1, 1) ASC;
+name
+Groonga
+Linux
+Mroonga
+MySQL
+Rroonga
+Ruby
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_reference.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_reference.result
new file mode 100644
index 00000000..1eceec2b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_groonga_vector_reference.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS tags, bugs;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags VARCHAR(128) DEFAULT '' COMMENT 'flags "COLUMN_VECTOR", type "tags"'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tags` varchar(128) DEFAULT '' COMMENT 'flags "COLUMN_VECTOR", type "tags"',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL groonga");
+SELECT * FROM bugs;
+id tags
+1 Linux MySQL groonga
+SELECT * FROM tags;
+name
+Linux
+MySQL
+groonga
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_int_with_index_zero_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_int_with_index_zero_value.result
new file mode 100644
index 00000000..1afd7da9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_int_with_index_zero_value.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price INT KEY
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("hamburger", 200);
+INSERT INTO items VALUES ("smile", 0);
+INSERT INTO items VALUES ("coke", 100);
+SELECT * FROM items;
+name price
+smile 0
+coke 100
+hamburger 200
+SELECT * FROM items WHERE price = 0;
+name price
+smile 0
+SELECT * FROM items WHERE price <= 100;
+name price
+smile 0
+coke 100
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_json_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_json_insert.result
new file mode 100644
index 00000000..e6a3aa5e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_json_insert.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+INSERT INTO logs VALUES ('{"message": "start"}');
+INSERT INTO logs VALUES ('{"message": "restart"}');
+INSERT INTO logs VALUES ('{"message": "shutdown"}');
+SELECT * FROM logs;
+record
+{"message": "start"}
+{"message": "restart"}
+{"message": "shutdown"}
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_cp932.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_cp932.result
new file mode 100644
index 00000000..eb1a08f2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_cp932.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS users;
+SET NAMES cp932;
+CREATE TABLE users (
+O text,
+FULLTEXT INDEX (O)
+) DEFAULT CHARSET=cp932;
+INSERT INTO users VALUES ("܂");
+INSERT INTO users VALUES ("Ȃ");
+INSERT INTO users VALUES ("");
+SELECT * FROM users;
+O
+
+SELECT * FROM users
+WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+O
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_NO_KEY
+column_create users @540d@524d COLUMN_SCALAR LongText
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users @540d@524d
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_utf8.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_utf8.result
new file mode 100644
index 00000000..6f63b5b3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_multibyte_utf8.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+名前 text,
+FULLTEXT INDEX (名前)
+) DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES ("やまだ");
+INSERT INTO users VALUES ("たなか");
+INSERT INTO users VALUES ("すずき");
+SELECT * FROM users;
+名前
+やまだ
+たなか
+すずき
+SELECT * FROM users
+WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+名前
+たなか
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_NO_KEY
+column_create users @540d@524d COLUMN_SCALAR LongText
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users @540d@524d
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_set_16_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_16_with_index.result
new file mode 100644
index 00000000..55a12a2d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_16_with_index.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+colors SET("black",
+"dim gray",
+"dark gray",
+"gray",
+"light gray",
+"gainsboro",
+"white smoke",
+"white",
+"red",
+"orange red",
+"dark orange",
+"orange",
+"gold",
+"yellow",
+"chartreuse",
+"lawn green"),
+INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `colors` set('black','dim gray','dark gray','gray','light gray','gainsboro','white smoke','white','red','orange red','dark orange','orange','gold','yellow','chartreuse','lawn green') DEFAULT NULL,
+ KEY `colors` (`colors`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart", "black,gray");
+INSERT INTO items VALUES ("hat", "white,dark gray");
+INSERT INTO items VALUES ("parka", "chartreuse,orange");
+SELECT * FROM items;
+name colors
+t-shart black,gray
+hat dark gray,white
+parka orange,chartreuse
+SELECT * FROM items WHERE colors = "dark gray,white";
+name colors
+hat dark gray,white
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_set_24_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_24_with_index.result
new file mode 100644
index 00000000..c485acfe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_24_with_index.result
@@ -0,0 +1,48 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+colors SET("black",
+"dim gray",
+"dark gray",
+"gray",
+"light gray",
+"gainsboro",
+"white smoke",
+"white",
+"red",
+"orange red",
+"dark orange",
+"orange",
+"gold",
+"yellow",
+"chartreuse",
+"lawn green",
+"green",
+"spring green",
+"medium spring green",
+"cyan",
+"deep sky blue",
+"blue",
+"medium blue",
+"dark violet"),
+INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `colors` set('black','dim gray','dark gray','gray','light gray','gainsboro','white smoke','white','red','orange red','dark orange','orange','gold','yellow','chartreuse','lawn green','green','spring green','medium spring green','cyan','deep sky blue','blue','medium blue','dark violet') DEFAULT NULL,
+ KEY `colors` (`colors`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart", "black,white");
+INSERT INTO items VALUES ("hat", "white,lawn green");
+INSERT INTO items VALUES ("parka", "gray,medium blue");
+SELECT * FROM items;
+name colors
+t-shart black,white
+hat white,lawn green
+parka gray,medium blue
+SELECT * FROM items WHERE colors = "white,lawn green";
+name colors
+hat white,lawn green
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_set_32_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_32_with_index.result
new file mode 100644
index 00000000..7ff86090
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_32_with_index.result
@@ -0,0 +1,56 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+colors SET("black",
+"dim gray",
+"dark gray",
+"gray",
+"light gray",
+"gainsboro",
+"white smoke",
+"white",
+"red",
+"orange red",
+"dark orange",
+"orange",
+"gold",
+"yellow",
+"chartreuse",
+"lawn green",
+"green",
+"spring green",
+"medium spring green",
+"cyan",
+"deep sky blue",
+"blue",
+"medium blue",
+"dark violet",
+"dark magenta",
+"magenta",
+"dark red",
+"brown",
+"firebrick",
+"indian red",
+"light coral",
+"salmon"),
+INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `colors` set('black','dim gray','dark gray','gray','light gray','gainsboro','white smoke','white','red','orange red','dark orange','orange','gold','yellow','chartreuse','lawn green','green','spring green','medium spring green','cyan','deep sky blue','blue','medium blue','dark violet','dark magenta','magenta','dark red','brown','firebrick','indian red','light coral','salmon') DEFAULT NULL,
+ KEY `colors` (`colors`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart", "black,white");
+INSERT INTO items VALUES ("hat", "white,dark violet");
+INSERT INTO items VALUES ("parka", "green,brown,red");
+SELECT * FROM items;
+name colors
+t-shart black,white
+hat white,dark violet
+parka red,green,brown
+SELECT * FROM items WHERE colors = "white,dark violet";
+name colors
+hat white,dark violet
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_set_64_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_64_with_index.result
new file mode 100644
index 00000000..393372ae
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_64_with_index.result
@@ -0,0 +1,88 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+colors SET("black",
+"dim gray",
+"dark gray",
+"gray",
+"light gray",
+"gainsboro",
+"white smoke",
+"white",
+"red",
+"orange red",
+"dark orange",
+"orange",
+"gold",
+"yellow",
+"chartreuse",
+"lawn green",
+"green",
+"spring green",
+"medium spring green",
+"cyan",
+"deep sky blue",
+"blue",
+"medium blue",
+"dark violet",
+"dark magenta",
+"magenta",
+"dark red",
+"brown",
+"firebrick",
+"indian red",
+"light coral",
+"salmon",
+"light salmon",
+"tomato",
+"coral",
+"dark salmon",
+"rosy brown",
+"sienna",
+"saddle brown",
+"chocolate",
+"peru",
+"sandy brown",
+"burlywood",
+"tan",
+"navajo white",
+"wheat",
+"dark goldenrod",
+"goldenrod",
+"light goldenrod",
+"pale goldenrod",
+"cornsilk",
+"dark khaki",
+"khaki",
+"lemon chiffon",
+"dark olive green",
+"olive drab",
+"yellow green",
+"green yellow",
+"light green",
+"forest green",
+"dark green",
+"lime green",
+"pale green",
+"dark sea green"),
+INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `colors` set('black','dim gray','dark gray','gray','light gray','gainsboro','white smoke','white','red','orange red','dark orange','orange','gold','yellow','chartreuse','lawn green','green','spring green','medium spring green','cyan','deep sky blue','blue','medium blue','dark violet','dark magenta','magenta','dark red','brown','firebrick','indian red','light coral','salmon','light salmon','tomato','coral','dark salmon','rosy brown','sienna','saddle brown','chocolate','peru','sandy brown','burlywood','tan','navajo white','wheat','dark goldenrod','goldenrod','light goldenrod','pale goldenrod','cornsilk','dark khaki','khaki','lemon chiffon','dark olive green','olive drab','yellow green','green yellow','light green','forest green','dark green','lime green','pale green','dark sea green') DEFAULT NULL,
+ KEY `colors` (`colors`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart", "black,white,lawn green,dark violet");
+INSERT INTO items VALUES ("hat", "white,dark violet,yellow green");
+INSERT INTO items VALUES ("parka", "green,brown,red,lime green");
+SELECT * FROM items;
+name colors
+t-shart black,white,lawn green,dark violet
+hat white,dark violet,yellow green
+parka red,green,brown,lime green
+SELECT * FROM items WHERE colors = "white,dark violet,yellow green";
+name colors
+hat white,dark violet,yellow green
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_set_8_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_8_with_index.result
new file mode 100644
index 00000000..cf7aaffd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_set_8_with_index.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+colors SET("black",
+"dim gray",
+"dark gray",
+"gray",
+"light gray",
+"gainsboro",
+"white smoke",
+"white"),
+INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `name` varchar(255) DEFAULT NULL,
+ `colors` set('black','dim gray','dark gray','gray','light gray','gainsboro','white smoke','white') DEFAULT NULL,
+ KEY `colors` (`colors`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items VALUES ("t-shart", "black,gray");
+INSERT INTO items VALUES ("hat", "dim gray,dark gray");
+INSERT INTO items VALUES ("parka", "white smoke,light gray");
+SELECT * FROM items;
+name colors
+t-shart black,gray
+hat dim gray,dark gray
+parka light gray,white smoke
+SELECT * FROM items WHERE colors = "dim gray,dark gray";
+name colors
+hat dim gray,dark gray
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_bigint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_bigint_with_index.result
new file mode 100644
index 00000000..262f7755
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_bigint_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price BIGINT KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("house", 9223372036854775807);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -9223372036854775808);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("super car", 2147483648);
+SELECT * FROM items;
+name price
+discount -9223372036854775808
+coke 100
+note PC 32767
+super car 2147483648
+house 9223372036854775807
+SELECT * FROM items WHERE price <= 2147483648;
+name price
+discount -9223372036854775808
+coke 100
+note PC 32767
+super car 2147483648
+SELECT * FROM items WHERE price > 2147483647;
+name price
+super car 2147483648
+house 9223372036854775807
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_int_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_int_with_index.result
new file mode 100644
index 00000000..867b8871
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_int_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price INT KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("car", 2147483647);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -2147483647);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 16777216);
+SELECT * FROM items;
+name price
+discount -2147483647
+coke 100
+note PC 32767
+bike 16777216
+car 2147483647
+SELECT * FROM items WHERE price <= 16777216;
+name price
+discount -2147483647
+coke 100
+note PC 32767
+bike 16777216
+SELECT * FROM items WHERE price > 16777215;
+name price
+bike 16777216
+car 2147483647
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_mediumint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_mediumint_with_index.result
new file mode 100644
index 00000000..c8b4f895
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_mediumint_with_index.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price MEDIUMINT KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("car", 8388607);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -8388608);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 32768);
+SELECT * FROM items;
+name price
+discount -8388608
+coke 100
+note PC 32767
+bike 32768
+car 8388607
+SELECT * FROM items WHERE price <= 127;
+name price
+discount -8388608
+coke 100
+SELECT * FROM items WHERE price >= 32768;
+name price
+bike 32768
+car 8388607
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_smallint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_smallint_with_index.result
new file mode 100644
index 00000000..8a51ee5f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_smallint_with_index.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price SMALLINT KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -32768);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("tablet PC", 20000);
+SELECT * FROM items;
+name price
+discount -32768
+coke 100
+tablet PC 20000
+note PC 32767
+SELECT * FROM items WHERE price <= 127;
+name price
+discount -32768
+coke 100
+SELECT * FROM items WHERE price >= 128;
+name price
+tablet PC 20000
+note PC 32767
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_tinyint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_tinyint_with_index.result
new file mode 100644
index 00000000..d14efcca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_signed_tinyint_with_index.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price TINYINT KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("hamburger", 120);
+INSERT INTO items VALUES ("discount", -10);
+INSERT INTO items VALUES ("coke", 100);
+SELECT * FROM items;
+name price
+discount -10
+coke 100
+hamburger 120
+SELECT * FROM items WHERE price <= 100;
+name price
+discount -10
+coke 100
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_time_fractional_seconds_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_time_fractional_seconds_with_index.result
new file mode 100644
index 00000000..35434a00
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_time_fractional_seconds_with_index.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS running_records;
+CREATE TABLE running_records (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+average TIME(6),
+max TIME(6),
+KEY (average)
+) DEFAULT CHARSET UTF8;
+INSERT INTO running_records (title, average, max)
+VALUES ("normal condition", "01:00:00.000001", "01:05:00.000001");
+INSERT INTO running_records (title, average, max)
+VALUES ("bad condition", "12:23:34.123456", "838:59:58.999999");
+INSERT INTO running_records (title, average, max)
+VALUES ("record failure", "-838:59:59.000000", "-838:59:59.000000");
+SELECT * FROM running_records;
+id title average max
+1 normal condition 01:00:00.000001 01:05:00.000001
+2 bad condition 12:23:34.123456 838:59:58.999999
+3 record failure -838:59:59.000000 -838:59:59.000000
+SELECT * FROM running_records
+WHERE average BETWEEN "00:59:59.999999" AND "100:10:10.101010";
+id title average max
+1 normal condition 01:00:00.000001 01:05:00.000001
+2 bad condition 12:23:34.123456 838:59:58.999999
+SELECT * FROM running_records
+WHERE average BETWEEN "-838:59:59.000000" AND "01:00:00.000001";
+id title average max
+3 record failure -838:59:59.000000 -838:59:59.000000
+1 normal condition 01:00:00.000001 01:05:00.000001
+DROP TABLE running_records;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_time_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_time_with_index.result
new file mode 100644
index 00000000..a0b0350a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_time_with_index.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS running_records;
+CREATE TABLE running_records (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+average TIME,
+max TIME,
+KEY (average)
+) DEFAULT CHARSET UTF8;
+INSERT INTO running_records (title, average, max)
+VALUES ("normal condition", "01:00:00", "01:05:00");
+INSERT INTO running_records (title, average, max)
+VALUES ("bad condition", "12:23:34", "838:59:59");
+INSERT INTO running_records (title, average, max)
+VALUES ("record failure", "-838:59:59", "-838:59:59");
+SELECT * FROM running_records;
+id title average max
+1 normal condition 01:00:00 01:05:00
+2 bad condition 12:23:34 838:59:59
+3 record failure -838:59:59 -838:59:59
+SELECT * FROM running_records
+WHERE average BETWEEN "00:59:59" AND "100:10:10";
+id title average max
+1 normal condition 01:00:00 01:05:00
+2 bad condition 12:23:34 838:59:59
+SELECT * FROM running_records
+WHERE average BETWEEN "-838:59:59" AND "01:00:00";
+id title average max
+3 record failure -838:59:59 -838:59:59
+1 normal condition 01:00:00 01:05:00
+DROP TABLE running_records;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_fractional_seconds_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_fractional_seconds_with_index.result
new file mode 100644
index 00000000..7ccb1fa2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_fractional_seconds_with_index.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at TIMESTAMP(6),
+updated_at TIMESTAMP(6),
+KEY (updated_at)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at, updated_at)
+VALUES ("clear day",
+"2012-01-29 21:51:01.111111",
+"2012-01-29 21:51:02.222222");
+INSERT INTO diaries (title, created_at, updated_at)
+VALUES ("rainy day",
+"2012-01-30 01:23:45.333",
+"2012-01-30 01:23:46.444");
+INSERT INTO diaries (title, created_at, updated_at)
+VALUES ("cloudy day",
+"2012-01-31 08:32:10.5555",
+"2012-01-31 08:32:11.6666");
+SELECT * FROM diaries;
+id title created_at updated_at
+1 clear day 2012-01-29 21:51:01.111111 2012-01-29 21:51:02.222222
+2 rainy day 2012-01-30 01:23:45.333000 2012-01-30 01:23:46.444000
+3 cloudy day 2012-01-31 08:32:10.555500 2012-01-31 08:32:11.666600
+SELECT * FROM diaries
+WHERE updated_at BETWEEN "2012-01-29 00:00:00.123456" AND
+"2012-01-31 00:00:00.999999";
+id title created_at updated_at
+1 clear day 2012-01-29 21:51:01.111111 2012-01-29 21:51:02.222222
+2 rainy day 2012-01-30 01:23:45.333000 2012-01-30 01:23:46.444000
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_with_index.result
new file mode 100644
index 00000000..4c221d9e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_timestamp_with_index.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+created_at TIMESTAMP DEFAULT '2016-04-21 00:00:00',
+updated_at TIMESTAMP DEFAULT '2016-04-21 00:00:00',
+KEY (updated_at)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, created_at, updated_at)
+VALUES ("clear day", "2012-01-29 21:51:01", "2012-01-29 21:51:02");
+INSERT INTO diaries (title, created_at, updated_at)
+VALUES ("rainy day", "2012-01-30 01:23:45", "2012-01-30 01:23:46");
+INSERT INTO diaries (title, created_at, updated_at)
+VALUES ("cloudy day", "2012-01-31 08:32:10", "2012-01-31 08:32:11");
+SELECT * FROM diaries;
+id title created_at updated_at
+1 clear day 2012-01-29 21:51:01 2012-01-29 21:51:02
+2 rainy day 2012-01-30 01:23:45 2012-01-30 01:23:46
+3 cloudy day 2012-01-31 08:32:10 2012-01-31 08:32:11
+SELECT * FROM diaries
+WHERE updated_at BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+id title created_at updated_at
+1 clear day 2012-01-29 21:51:01 2012-01-29 21:51:02
+2 rainy day 2012-01-30 01:23:45 2012-01-30 01:23:46
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_tinyint_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_tinyint_without_index.result
new file mode 100644
index 00000000..8dde1bdd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_tinyint_without_index.result
@@ -0,0 +1,18 @@
+drop table if exists books;
+create table books(title varchar(255), published tinyint);
+insert into books values ("MySQL", 1);
+insert into books values ("groonga", 1);
+insert into books values ("mroonga", 0);
+select count(*) from books where published = 0;
+count(*)
+1
+select count(*) from books where published = 1;
+count(*)
+2
+select count(*) from books where published != 2;
+count(*)
+3
+select count(*) from books where published != 1;
+count(*)
+1
+drop table books;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_with_index.result
new file mode 100644
index 00000000..d16004e3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price BIGINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("house", 18446744073709551615);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("super car", 9223372036854775808);
+SELECT * FROM items;
+name price
+discount 0
+coke 100
+note PC 32767
+super car 9223372036854775808
+house 18446744073709551615
+SELECT * FROM items WHERE price <= 9223372036854775808;
+name price
+discount 0
+coke 100
+note PC 32767
+super car 9223372036854775808
+SELECT * FROM items WHERE price > 9223372036854775807;
+name price
+super car 9223372036854775808
+house 18446744073709551615
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_without_index.result
new file mode 100644
index 00000000..277580c7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_bigint_without_index.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id BIGINT UNSIGNED
+) DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES (317173755057152000);
+INSERT INTO ids VALUES (317173755057152002);
+SELECT * FROM ids;
+id
+317173755057152000
+317173755057152002
+SELECT * FROM ids WHERE id = 317173755057152000;
+id
+317173755057152000
+SELECT * FROM ids WHERE id = 317173755057152002;
+id
+317173755057152002
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_int_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_int_with_index.result
new file mode 100644
index 00000000..d14ef877
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_int_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price INT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("car", 4294967295);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 2147483648);
+SELECT * FROM items;
+name price
+discount 0
+coke 100
+note PC 32767
+bike 2147483648
+car 4294967295
+SELECT * FROM items WHERE price <= 2147483648;
+name price
+discount 0
+coke 100
+note PC 32767
+bike 2147483648
+SELECT * FROM items WHERE price > 2147483647;
+name price
+bike 2147483648
+car 4294967295
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_mediumint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_mediumint_with_index.result
new file mode 100644
index 00000000..2825aada
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_mediumint_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price MEDIUMINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("car", 16777215);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 8388607);
+SELECT * FROM items;
+name price
+discount 0
+coke 100
+note PC 32767
+bike 8388607
+car 16777215
+SELECT * FROM items WHERE price <= 8388608;
+name price
+discount 0
+coke 100
+note PC 32767
+bike 8388607
+SELECT * FROM items WHERE price >= 8388607;
+name price
+bike 8388607
+car 16777215
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_smallint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_smallint_with_index.result
new file mode 100644
index 00000000..8586d091
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_smallint_with_index.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price SMALLINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("note PC", 65535);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("tablet PC", 32767);
+SELECT * FROM items;
+name price
+discount 0
+coke 100
+tablet PC 32767
+note PC 65535
+SELECT * FROM items WHERE price <= 32768;
+name price
+discount 0
+coke 100
+tablet PC 32767
+SELECT * FROM items WHERE price >= 32767;
+name price
+tablet PC 32767
+note PC 65535
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_tinyint_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_tinyint_with_index.result
new file mode 100644
index 00000000..90adb048
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_unsigned_tinyint_with_index.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+name VARCHAR(255),
+price TINYINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES ("hamburger", 255);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+SELECT * FROM items;
+name price
+discount 0
+coke 100
+hamburger 255
+SELECT * FROM items WHERE price <= 100;
+name price
+discount 0
+coke 100
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_year_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_year_with_index.result
new file mode 100644
index 00000000..be97d4fc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_year_with_index.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS aniversary_memos;
+CREATE TABLE aniversary_memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+party_year YEAR,
+KEY (party_year)
+) DEFAULT CHARSET UTF8;
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("We need a big cake!", "11");
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("Invitations are sent.", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("Tommorow is the anniversary party day!", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("Wow! Today is the anniversary party day!", "13");
+SELECT * FROM aniversary_memos;
+id title party_year
+1 We need a big cake! 2011
+2 Invitations are sent. 2012
+3 Tommorow is the anniversary party day! 2012
+4 Wow! Today is the anniversary party day! 2013
+SELECT * FROM aniversary_memos
+WHERE party_year BETWEEN "12" AND "2013";
+id title party_year
+2 Invitations are sent. 2012
+3 Tommorow is the anniversary party day! 2012
+4 Wow! Today is the anniversary party day! 2013
+DROP TABLE aniversary_memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/column_year_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/column_year_without_index.result
new file mode 100644
index 00000000..a56271bc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/column_year_without_index.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS aniversary_memos;
+CREATE TABLE aniversary_memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+party_year YEAR
+) DEFAULT CHARSET UTF8;
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("We need a big cake!", "11");
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("Invitations are sent.", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("Tommorow is the anniversary party day!", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+VALUES ("Wow! Today is the anniversary party day!", "13");
+SELECT * FROM aniversary_memos;
+id title party_year
+1 We need a big cake! 2011
+2 Invitations are sent. 2012
+3 Tommorow is the anniversary party day! 2012
+4 Wow! Today is the anniversary party day! 2013
+SELECT * FROM aniversary_memos
+WHERE party_year BETWEEN "12" AND "2013";
+id title party_year
+2 Invitations are sent. 2012
+3 Tommorow is the anniversary party day! 2012
+4 Wow! Today is the anniversary party day! 2013
+DROP TABLE aniversary_memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/count_star.result b/storage/mroonga/mysql-test/mroonga/storage/r/count_star.result
new file mode 100644
index 00000000..ab6be3a7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/count_star.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int PRIMARY KEY
+);
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+SELECT COUNT(*) FROM ids;
+COUNT(*)
+3
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_database_name_slash.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_database_name_slash.result
new file mode 100644
index 00000000..56c868b2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_database_name_slash.result
@@ -0,0 +1,33 @@
+DROP DATABASE IF EXISTS `master/production`;
+DROP DATABASE IF EXISTS `master/development`;
+CREATE DATABASE `master/production`;
+USE `master/production`;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (title) VALUES ("clear day (production)");
+INSERT INTO diaries (title) VALUES ("rainy day (production)");
+INSERT INTO diaries (title) VALUES ("cloudy day (production)");
+SELECT * FROM diaries;
+id title
+1 clear day (production)
+2 rainy day (production)
+3 cloudy day (production)
+CREATE DATABASE `master/development`;
+USE `master/development`;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (title) VALUES ("clear day (development)");
+INSERT INTO diaries (title) VALUES ("rainy day (development)");
+INSERT INTO diaries (title) VALUES ("cloudy day (development)");
+SELECT * FROM diaries;
+id title
+1 clear day (development)
+2 rainy day (development)
+3 cloudy day (development)
+USE test;
+DROP DATABASE `master/production`;
+DROP DATABASE `master/development`;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..d2a00b77
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_TODO_SPLIT_ME.result
@@ -0,0 +1,172 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int);
+create table t2 (c1 int);
+create table t3 (c1 int);
+drop table t1,t2,t3;
+create table t1 (c1 int, c2 int, c3 int);
+create table t2 (c1 int primary key, c2 int, c3 int);
+drop table t1,t2;
+create table t1 (c1 bit);
+desc t1;
+Field Type Null Key Default Extra
+c1 bit(1) YES NULL
+drop table t1;
+create table t1 (c1 tinyint);
+desc t1;
+Field Type Null Key Default Extra
+c1 tinyint(4) YES NULL
+drop table t1;
+create table t1 (c1 smallint);
+desc t1;
+Field Type Null Key Default Extra
+c1 smallint(6) YES NULL
+drop table t1;
+create table t1 (c1 mediumint);
+desc t1;
+Field Type Null Key Default Extra
+c1 mediumint(9) YES NULL
+drop table t1;
+create table t1 (c1 int);
+desc t1;
+Field Type Null Key Default Extra
+c1 int(11) YES NULL
+drop table t1;
+create table t1 (c1 bigint);
+desc t1;
+Field Type Null Key Default Extra
+c1 bigint(20) YES NULL
+drop table t1;
+create table t1 (c1 double);
+desc t1;
+Field Type Null Key Default Extra
+c1 double YES NULL
+drop table t1;
+create table t1 (c1 float);
+desc t1;
+Field Type Null Key Default Extra
+c1 float YES NULL
+drop table t1;
+create table t1 (c1 decimal);
+desc t1;
+Field Type Null Key Default Extra
+c1 decimal(10,0) YES NULL
+drop table t1;
+create table t1 (c1 date);
+desc t1;
+Field Type Null Key Default Extra
+c1 date YES NULL
+drop table t1;
+create table t1 (c1 time);
+desc t1;
+Field Type Null Key Default Extra
+c1 time YES NULL
+drop table t1;
+create table t1 (c1 timestamp);
+desc t1;
+Field Type Null Key Default Extra
+c1 timestamp NO CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
+drop table t1;
+create table t1 (c1 datetime);
+desc t1;
+Field Type Null Key Default Extra
+c1 datetime YES NULL
+drop table t1;
+create table t1 (c1 year);
+desc t1;
+Field Type Null Key Default Extra
+c1 year(4) YES NULL
+drop table t1;
+create table t1 (c1 char(10));
+desc t1;
+Field Type Null Key Default Extra
+c1 char(10) YES NULL
+drop table t1;
+create table t1 (c1 varchar(10));
+desc t1;
+Field Type Null Key Default Extra
+c1 varchar(10) YES NULL
+drop table t1;
+create table t1 (c1 binary(10));
+desc t1;
+Field Type Null Key Default Extra
+c1 binary(10) YES NULL
+drop table t1;
+create table t1 (c1 varbinary(10));
+desc t1;
+Field Type Null Key Default Extra
+c1 varbinary(10) YES NULL
+drop table t1;
+create table t1 (c1 tinyblob);
+desc t1;
+Field Type Null Key Default Extra
+c1 tinyblob YES NULL
+drop table t1;
+create table t1 (c1 blob);
+desc t1;
+Field Type Null Key Default Extra
+c1 blob YES NULL
+drop table t1;
+create table t1 (c1 mediumblob);
+desc t1;
+Field Type Null Key Default Extra
+c1 mediumblob YES NULL
+drop table t1;
+create table t1 (c1 longblob);
+desc t1;
+Field Type Null Key Default Extra
+c1 longblob YES NULL
+drop table t1;
+create table t1 (c1 tinytext);
+desc t1;
+Field Type Null Key Default Extra
+c1 tinytext YES NULL
+drop table t1;
+create table t1 (c1 text);
+desc t1;
+Field Type Null Key Default Extra
+c1 text YES NULL
+drop table t1;
+create table t1 (c1 mediumtext);
+desc t1;
+Field Type Null Key Default Extra
+c1 mediumtext YES NULL
+drop table t1;
+create table t1 (c1 longtext);
+desc t1;
+Field Type Null Key Default Extra
+c1 longtext YES NULL
+drop table t1;
+create table t1 (c1 enum("yes","no"));
+desc t1;
+Field Type Null Key Default Extra
+c1 enum('yes','no') YES NULL
+drop table t1;
+create table t1 (c1 set("A","B","AB","O"));
+desc t1;
+Field Type Null Key Default Extra
+c1 set('A','B','AB','O') YES NULL
+drop table t1;
+create table t1 (c1 int, `_id` int) engine = mroonga;
+desc t1;
+Field Type Null Key Default Extra
+c1 int(11) YES NULL
+_id int(11) YES NULL
+drop table t1;
+create table t1 (c1 int, `_score` float) engine = mroonga;
+ERROR HY000: [column][create] name can't start with '_' and contains only 0-9, A-Z, a-z, #, @, - or _: <_score>
+create table t1 (c1 int, `_id` text) engine = mroonga;
+ERROR HY000: _id must be numeric data type
+create table t1 (c1 int, `_id` int, index(`_id`)) engine = mroonga;
+ERROR HY000: only hash index can be defined for _id
+create table t1 (_id int, c1 int, primary key (_id));
+ERROR HY000: only hash index can be defined for _id
+create table t1 (_id int, c1 int, primary key (_id) using hash);
+drop table t1;
+create table t1 (_id int, c1 int, unique key (_id));
+ERROR HY000: only hash index can be defined for _id
+create table t1 (_id int, c1 int, unique key (_id) using hash);
+drop table t1;
+create table t1 (_id int, c1 int, key (_id));
+ERROR HY000: only hash index can be defined for _id
+create table t1 (_id int, c1 int, key (_id) using hash);
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_comment.result
new file mode 100644
index 00000000..e4c4ea05
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_comment.result
@@ -0,0 +1,15 @@
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags TEXT COMMENT 'flags "COLUMN_VECTOR"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+column_create bugs tags COLUMN_VECTOR LongText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_parameter.result
new file mode 100644
index 00000000..9923b91f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_flags_parameter.result
@@ -0,0 +1,15 @@
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags TEXT FLAGS='COLUMN_VECTOR'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+column_create bugs tags COLUMN_VECTOR LongText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_comment.result
new file mode 100644
index 00000000..7dede867
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_comment.result
@@ -0,0 +1,23 @@
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) COMMENT 'groonga_type "tags"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY ShortText
+column_create tags name COLUMN_SCALAR ShortText
+
+column_create bugs tag COLUMN_SCALAR tags
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_nonexistent.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_nonexistent.result
new file mode 100644
index 00000000..99dc30aa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_nonexistent.result
@@ -0,0 +1,6 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) COMMENT 'groonga_type "Nonexistent"'
+) DEFAULT CHARSET=utf8mb4;
+ERROR HY000: unknown custom Groonga type name for <tag> column: <Nonexistent>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_parameter.result
new file mode 100644
index 00000000..fca13805
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_groonga_type_parameter.result
@@ -0,0 +1,30 @@
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) GROONGA_TYPE='tags'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tag` varchar(64) DEFAULT NULL `GROONGA_TYPE`='tags',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY ShortText
+column_create tags name COLUMN_SCALAR ShortText
+
+column_create bugs tag COLUMN_SCALAR tags
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_comment.result
new file mode 100644
index 00000000..357adfdf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_comment.result
@@ -0,0 +1,23 @@
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) COMMENT 'type "tags"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_PAT_KEY UInt32
+column_create bugs id COLUMN_SCALAR UInt32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY ShortText
+column_create tags name COLUMN_SCALAR ShortText
+
+column_create bugs tag COLUMN_SCALAR tags
+DROP TABLE bugs;
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_nonexistent.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_nonexistent.result
new file mode 100644
index 00000000..a66a2bd2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_column_type_nonexistent.result
@@ -0,0 +1,6 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) COMMENT 'type "Nonexistent"'
+) DEFAULT CHARSET=utf8mb4;
+ERROR HY000: unknown custom Groonga type name for <tag> column: <Nonexistent>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_comment_normal.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_comment_normal.result
new file mode 100644
index 00000000..b9bcb1c9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_comment_normal.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED
+) DEFAULT CHARSET=utf8
+COMMENT='Free style normal comment';
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='Free style normal comment'
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_default_tokenizer.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_default_tokenizer.result
new file mode 100644
index 00000000..0c33fac1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_default_tokenizer.result
@@ -0,0 +1,15 @@
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin
+COMMENT='default_tokenizer "TokenDelimit"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create tags TABLE_PAT_KEY ShortText --default_tokenizer TokenDelimit
+column_create tags name COLUMN_SCALAR ShortText
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_comment.result
new file mode 100644
index 00000000..8d39cac4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_comment.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'flags "WITH_POSITION|WITH_WEIGHT"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX|WITH_WEIGHT|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_medium.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_medium.result
new file mode 100644
index 00000000..e9d90b0b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_medium.result
@@ -0,0 +1,10 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+content_size INT NOT NULL,
+KEY (content_size) COMMENT 'flags "INDEX_MEDIUM"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content_size index COLUMN_INDEX|INDEX_MEDIUM memos content_size
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_small.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_small.result
new file mode 100644
index 00000000..38a83b89
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_index_small.result
@@ -0,0 +1,10 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+is_read BOOL NOT NULL,
+KEY (is_read) COMMENT 'flags "INDEX_SMALL"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#is_read index COLUMN_INDEX|INDEX_SMALL memos is_read
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_none.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_none.result
new file mode 100644
index 00000000..e90fd833
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_none.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'flags "NONE"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_parameter.result
new file mode 100644
index 00000000..1d8a6e1a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_flags_parameter.result
@@ -0,0 +1,15 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) FLAGS='WITH_POSITION|WITH_WEIGHT'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `content` varchar(64) NOT NULL,
+ FULLTEXT KEY `content` (`content`) `FLAGS`='WITH_POSITION|WITH_WEIGHT'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX|WITH_WEIGHT|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_none.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_none.result
new file mode 100644
index 00000000..3d31400f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_none.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'index_flags "NONE"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_with_position_and_with_weight.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_with_position_and_with_weight.result
new file mode 100644
index 00000000..8f0c4995
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_index_flags_with_position_and_with_weight.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'index_flags "WITH_POSITION|WITH_WEIGHT"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX|WITH_WEIGHT|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_comment.result
new file mode 100644
index 00000000..e2d405a1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_comment.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
+day content
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+ブラック" IN BOOLEAN MODE);
+day content
+2013-04-23 ブラックコーヒーを飲んだ。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_fulltext_index_bin.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_fulltext_index_bin.result
new file mode 100644
index 00000000..b6da79c7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_fulltext_index_bin.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
+day content
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+ブラック" IN BOOLEAN MODE);
+day content
+2013-04-23 ブラックコーヒーを飲んだ。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_index_bin.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_index_bin.result
new file mode 100644
index 00000000..2a05ccdc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_index_bin.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create diaries TABLE_PAT_KEY Time
+column_create diaries content COLUMN_SCALAR ShortText
+column_create diaries day COLUMN_SCALAR Time
+
+table_create diaries#content TABLE_PAT_KEY ShortText --normalizer NormalizerAuto
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create diaries#content index COLUMN_INDEX diaries content
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.result
new file mode 100644
index 00000000..9d12e2d0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES latin1;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerMySQLGeneralCI"'
+) DEFAULT CHARSET=latin1;
+INSERT INTO diaries VALUES ("2013-04-23", "I drunk a black cookie.");
+ERROR HY000: [tokenizer] failed to open normalized string
+SELECT * FROM diaries;
+day content
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_none.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_none.result
new file mode 100644
index 00000000..52c6f055
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_none.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'normalizer "none"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES ("2013-04-23", "Mroonga");
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+Mroonga" IN BOOLEAN MODE);
+day content
+2013-04-23 Mroonga
+SELECT * FROM diaries
+WHERE MATCH (content) AGAINST ("+mroonga" IN BOOLEAN MODE);
+day content
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_parameter.result
new file mode 100644
index 00000000..2fac27a0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_normalizer_parameter.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) NORMALIZER='NormalizerAuto'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `id` int(11) NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `content` (`content`) `NORMALIZER`='NormalizerAuto'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+id content
+1 1日の消費㌍は約2000㌔㌍
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_comment.result
new file mode 100644
index 00000000..29f27d15
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_comment.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id int PRIMARY KEY AUTO_INCREMENT,
+body text,
+FULLTEXT INDEX body_index (body)
+COMMENT 'parser "TokenBigramSplitSymbolAlphaDigit"'
+) DEFAULT CHARSET utf8;
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+SELECT * FROM diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ORDER BY id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+DROP TABLE diaries;
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_default.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_default.result
new file mode 100644
index 00000000..34545ecc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_default.result
@@ -0,0 +1,25 @@
+drop table if exists diaries;
+set @mroonga_default_tokenizer_backup=@@mroonga_default_tokenizer;
+set global mroonga_default_tokenizer=TokenBigramSplitSymbolAlphaDigit;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+insert into diaries (body) values ("finished Groonga.");
+select * from diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+4 finished Groonga.
+select * from diaries where match(body) against("+start" IN BOOLEAN MODE) order by id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+drop table diaries;
+set global mroonga_default_tokenizer=@mroonga_default_tokenizer_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_off.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_off.result
new file mode 100644
index 00000000..f827c0ad
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_parser_off.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS variables;
+CREATE TABLE variables (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name TEXT,
+FULLTEXT INDEX (name) COMMENT 'parser "off"'
+) DEFAULT CHARSET=utf8;
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
+INSERT INTO variables (name) VALUES ("mroonga_database_path_prefix");
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
+INSERT INTO variables (name) VALUES ("mroonga_default_tokenizer");
+INSERT INTO variables (name) VALUES ("mroonga_default_wrapper_engine");
+INSERT INTO variables (name) VALUES ("mroonga_dry_write");
+INSERT INTO variables (name) VALUES ("mroonga_enable_optimization");
+INSERT INTO variables (name) VALUES ("mroonga_libgroonga_version");
+INSERT INTO variables (name) VALUES ("mroonga_log_file");
+INSERT INTO variables (name) VALUES ("mroonga_log_level");
+INSERT INTO variables (name) VALUES ("mroonga_match_escalation_threshold");
+INSERT INTO variables (name) VALUES ("mroonga_version");
+SELECT * FROM variables;
+id name
+1 mroonga_database_path_prefix
+2 mroonga_default_tokenizer
+3 mroonga_default_wrapper_engine
+4 mroonga_dry_write
+5 mroonga_enable_optimization
+6 mroonga_libgroonga_version
+7 mroonga_log_file
+8 mroonga_log_level
+9 mroonga_match_escalation_threshold
+10 mroonga_version
+SELECT * FROM variables
+WHERE MATCH (name) AGAINST ("mroonga_default*" IN BOOLEAN MODE);
+id name
+3 mroonga_default_wrapper_engine
+2 mroonga_default_tokenizer
+DROP TABLE variables;
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_multiple_token_filters.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_multiple_token_filters.result
new file mode 100644
index 00000000..ad68ca01
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_multiple_token_filters.result
@@ -0,0 +1,22 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord,TokenFilterStopWord"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_NO_KEY
+column_create memos content COLUMN_SCALAR ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord,TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_one_token_filter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_one_token_filter.result
new file mode 100644
index 00000000..2cbb5a6b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_one_token_filter.result
@@ -0,0 +1,22 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_NO_KEY
+column_create memos content COLUMN_SCALAR ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_parameter.result
new file mode 100644
index 00000000..333cf3d5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_token_filters_parameter.result
@@ -0,0 +1,28 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) TOKEN_FILTERS='TokenFilterStopWord,TokenFilterStopWord'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `content` varchar(64) NOT NULL,
+ FULLTEXT KEY `content` (`content`) `TOKEN_FILTERS`='TokenFilterStopWord,TokenFilterStopWord'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_NO_KEY
+column_create memos content COLUMN_SCALAR ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord,TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_comment.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_comment.result
new file mode 100644
index 00000000..a3904216
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_comment.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id int PRIMARY KEY AUTO_INCREMENT,
+body text,
+FULLTEXT INDEX body_index (body)
+COMMENT 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) DEFAULT CHARSET utf8;
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+SELECT * FROM diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ORDER BY id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_default.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_default.result
new file mode 100644
index 00000000..34545ecc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_default.result
@@ -0,0 +1,25 @@
+drop table if exists diaries;
+set @mroonga_default_tokenizer_backup=@@mroonga_default_tokenizer;
+set global mroonga_default_tokenizer=TokenBigramSplitSymbolAlphaDigit;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+insert into diaries (body) values ("finished Groonga.");
+select * from diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+4 finished Groonga.
+select * from diaries where match(body) against("+start" IN BOOLEAN MODE) order by id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+drop table diaries;
+set global mroonga_default_tokenizer=@mroonga_default_tokenizer_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_off.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_off.result
new file mode 100644
index 00000000..91a5b96d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_off.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS variables;
+CREATE TABLE variables (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name TEXT,
+FULLTEXT INDEX (name) COMMENT 'tokenizer "off"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO variables (name) VALUES ("mroonga_database_path_prefix");
+INSERT INTO variables (name) VALUES ("mroonga_default_tokenizer");
+INSERT INTO variables (name) VALUES ("mroonga_default_wrapper_engine");
+INSERT INTO variables (name) VALUES ("mroonga_dry_write");
+INSERT INTO variables (name) VALUES ("mroonga_enable_optimization");
+INSERT INTO variables (name) VALUES ("mroonga_libgroonga_version");
+INSERT INTO variables (name) VALUES ("mroonga_log_file");
+INSERT INTO variables (name) VALUES ("mroonga_log_level");
+INSERT INTO variables (name) VALUES ("mroonga_match_escalation_threshold");
+INSERT INTO variables (name) VALUES ("mroonga_version");
+SELECT * FROM variables;
+id name
+1 mroonga_database_path_prefix
+2 mroonga_default_tokenizer
+3 mroonga_default_wrapper_engine
+4 mroonga_dry_write
+5 mroonga_enable_optimization
+6 mroonga_libgroonga_version
+7 mroonga_log_file
+8 mroonga_log_level
+9 mroonga_match_escalation_threshold
+10 mroonga_version
+SELECT * FROM variables
+WHERE MATCH (name) AGAINST ("mroonga_default*" IN BOOLEAN MODE);
+id name
+3 mroonga_default_wrapper_engine
+2 mroonga_default_tokenizer
+DROP TABLE variables;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_parameter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_parameter.result
new file mode 100644
index 00000000..c827abe2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_index_tokenizer_parameter.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id int PRIMARY KEY AUTO_INCREMENT,
+body text,
+FULLTEXT INDEX body_index (body) TOKENIZER='TokenBigramSplitSymbolAlphaDigit'
+) DEFAULT CHARSET utf8;
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+SELECT * FROM diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ORDER BY id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_default.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_default.result
new file mode 100644
index 00000000..dbf69362
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_default.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+DROP TABLE IF EXISTS terms;
+SET NAMES utf8;
+CREATE TABLE terms (
+term VARCHAR(64) NOT NULL PRIMARY KEY
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"' DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+id content
+1 1日の消費㌍は約2000㌔㌍
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_hash.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_hash.result
new file mode 100644
index 00000000..5e4f4afa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_normalizer_hash.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+DROP TABLE IF EXISTS terms;
+SET NAMES utf8;
+CREATE TABLE terms (
+term VARCHAR(64) NOT NULL,
+PRIMARY KEY (term) USING HASH
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"' DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+id content
+1 1日の消費㌍は約2000㌔㌍
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_multiple_token_filters.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_multiple_token_filters.result
new file mode 100644
index 00000000..8934be78
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_multiple_token_filters.result
@@ -0,0 +1,30 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+CREATE TABLE terms (
+term VARCHAR(64) NOT NULL PRIMARY KEY,
+is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord,TokenFilterStopWord"' DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord,TokenFilterStopWord
+column_create terms is_stop_word COLUMN_SCALAR Int8
+column_create terms term COLUMN_SCALAR ShortText
+
+column_create terms content COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_one_token_filter.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_one_token_filter.result
new file mode 100644
index 00000000..e3df2850
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_one_token_filter.result
@@ -0,0 +1,30 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+CREATE TABLE terms (
+term VARCHAR(64) NOT NULL PRIMARY KEY,
+is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord"' DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_PAT_KEY Int32
+column_create memos content COLUMN_SCALAR LongText
+column_create memos id COLUMN_SCALAR Int32
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create terms TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord
+column_create terms is_stop_word COLUMN_SCALAR Int8
+column_create terms term COLUMN_SCALAR ShortText
+
+column_create terms content COLUMN_INDEX|WITH_POSITION memos content
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_stop_word.result b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_stop_word.result
new file mode 100644
index 00000000..bc21ed97
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/create_table_table_token_filters_stop_word.result
@@ -0,0 +1,23 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+CREATE TABLE terms (
+term VARCHAR(64) NOT NULL PRIMARY KEY,
+is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord"' DEFAULT CHARSET=utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO terms VALUES ("and", true);
+INSERT INTO memos VALUES (1, "Hello");
+INSERT INTO memos VALUES (2, "Hello and Good-bye");
+INSERT INTO memos VALUES (3, "Good-bye");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+\"Hello and\"" IN BOOLEAN MODE);
+id content
+1 Hello
+2 Hello and Good-bye
+DROP TABLE memos;
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/delete_fulltext_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/delete_fulltext_column.result
new file mode 100644
index 00000000..5fb52294
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/delete_fulltext_column.result
@@ -0,0 +1,21 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 text, fulltext index (c2));
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+select * from t1;
+c1 c2
+10 aa ii uu ee
+20 ka ki ku ke
+30 sa si su se
+select * from t1 where match(c2) against("ki");
+c1 c2
+20 ka ki ku ke
+delete from t1 where c1=20;
+select * from t1;
+c1 c2
+10 aa ii uu ee
+30 sa si su se
+select * from t1 where match(c2) against("ki");
+c1 c2
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_btree_many_records.result b/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_btree_many_records.result
new file mode 100644
index 00000000..f318e125
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_btree_many_records.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT,
+KEY (id)
+) DEFAULT CHARSET UTF8;
+INSERT INTO ids VALUES(1);
+INSERT INTO ids VALUES(2);
+INSERT INTO ids VALUES(3);
+SELECT * FROM ids ORDER BY id;
+id
+1
+2
+3
+DELETE FROM ids WHERE id = 1;
+SELECT * FROM ids ORDER BY id;
+id
+2
+3
+DELETE FROM ids WHERE id = 2;
+SELECT * FROM ids ORDER BY id;
+id
+3
+DELETE FROM ids WHERE id = 3;
+SELECT * FROM ids ORDER BY id;
+id
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_no_unique.result b/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_no_unique.result
new file mode 100644
index 00000000..76a4ed88
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_no_unique.result
@@ -0,0 +1,19 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, c1 int, key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+_id c1
+1 100
+2 100
+3 100
+4 100
+delete from t1 where _id = 2;
+select * from t1;
+_id c1
+1 100
+3 100
+4 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_unique.result b/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_unique.result
new file mode 100644
index 00000000..6307c55f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/delete_index_hash_id_unique.result
@@ -0,0 +1,19 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, c1 int, unique key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+_id c1
+1 100
+2 100
+3 100
+4 100
+delete from t1 where _id = 2;
+select * from t1;
+_id c1
+1 100
+3 100
+4 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/delete_normal_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/delete_normal_column.result
new file mode 100644
index 00000000..34048cbe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/delete_normal_column.result
@@ -0,0 +1,34 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int, c2 int);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) DEFAULT NULL,
+ `c2` int(11) DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+insert into t1 values (4, 102);
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+4 102
+delete from t1 where c1=3;
+select * from t1;
+c1 c2
+1 100
+2 101
+4 102
+flush tables;
+delete from t1 where c1=2;
+select * from t1;
+c1 c2
+1 100
+4 102
+delete from t1;
+select * from t1;
+c1 c2
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/delete_unsigned_bigint.result b/storage/mroonga/mysql-test/mroonga/storage/r/delete_unsigned_bigint.result
new file mode 100644
index 00000000..23cc23ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/delete_unsigned_bigint.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS numbers;
+CREATE TABLE numbers (
+data BIGINT UNSIGNED
+);
+INSERT INTO numbers VALUES(18446744073709551615);
+SELECT * FROM numbers ORDER BY data;
+data
+18446744073709551615
+DELETE FROM numbers WHERE data = 18446744073709551615;
+SELECT * FROM numbers ORDER BY data;
+data
+DROP TABLE numbers;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/drop_database_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/drop_database_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..4bd97162
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/drop_database_TODO_SPLIT_ME.result
@@ -0,0 +1,14 @@
+drop database if exists groonga;
+create database groonga;
+drop database groonga;
+create database groonga;
+use groonga;
+create table t1 (c1 int primary key, c2 varchar(255)) default charset utf8;
+create table t2 (c1 int primary key, c2 varchar(255)) default charset utf8;
+drop database groonga;
+create database groonga;
+use groonga;
+create table t1 (c1 int primary key, c2 varchar(255)) default charset utf8;
+create table t2 (c1 int primary key, c2 varchar(255)) default charset utf8;
+drop table t1, t2;
+drop database groonga;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/drop_database_no_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/drop_database_no_table.result
new file mode 100644
index 00000000..ebc7db1c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/drop_database_no_table.result
@@ -0,0 +1,20 @@
+SET NAMES UTF8;
+DROP DATABASE IF EXISTS another;
+CREATE DATABASE another;
+USE another;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT INDEX (title)
+);
+DROP TABLE diaries;
+USE test;
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT INDEX (title)
+);
+DROP DATABASE another;
+SELECT mroonga_command('object_exist mroonga_operations');
+mroonga_command('object_exist mroonga_operations')
+true
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/drop_table_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/drop_table_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..99896765
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/drop_table_TODO_SPLIT_ME.result
@@ -0,0 +1,5 @@
+drop table if exists alphabet, `with-hyphen`;
+create table alphabet (c1 int primary key, c2 int, c3 int);
+drop table alphabet;
+create table `with-hyphen` (c1 int primary key, c2 int, c3 int);
+drop table `with-hyphen`;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/flush_logs.result b/storage/mroonga/mysql-test/mroonga/storage/r/flush_logs.result
new file mode 100644
index 00000000..449f6437
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/flush_logs.result
@@ -0,0 +1 @@
+flush logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_add.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_add.result
new file mode 100644
index 00000000..470d2211
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_add.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+CREATE TABLE comments (
+comment int unsigned PRIMARY KEY,
+content text NOT NULL
+);
+CREATE TABLE articles (
+content text NOT NULL,
+comment int unsigned
+);
+ALTER TABLE articles ADD FOREIGN KEY (comment) REFERENCES comments (comment);
+SHOW CREATE TABLE articles;
+Table Create Table
+articles CREATE TABLE `articles` (
+ `content` text NOT NULL,
+ `comment` int(10) unsigned DEFAULT NULL,
+ KEY `comment` (`comment`),
+ CONSTRAINT `comment` FOREIGN KEY (`comment`) REFERENCES `test`.`comments` (`comment`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+SELECT * FROM information_schema.referential_constraints;
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME
+def test comment def test PRIMARY NONE RESTRICT RESTRICT articles comments
+DROP TABLE articles;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_drop.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_drop.result
new file mode 100644
index 00000000..e5e11c99
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_alter_drop.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+CREATE TABLE comments (
+comment int unsigned PRIMARY KEY,
+content text NOT NULL
+);
+CREATE TABLE articles (
+content text NOT NULL,
+comment int unsigned,
+FOREIGN KEY (comment) REFERENCES comments (comment)
+);
+ALTER TABLE articles DROP FOREIGN KEY comment;
+SHOW CREATE TABLE articles;
+Table Create Table
+articles CREATE TABLE `articles` (
+ `content` text NOT NULL,
+ `comment` int(10) unsigned DEFAULT NULL,
+ KEY `comment` (`comment`)
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+SELECT * FROM information_schema.referential_constraints;
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME
+DROP TABLE articles;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_create.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_create.result
new file mode 100644
index 00000000..c17780c0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_create.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+CREATE TABLE comments (
+comment int unsigned PRIMARY KEY,
+content text NOT NULL
+);
+CREATE TABLE articles (
+content text NOT NULL,
+comment int unsigned,
+FOREIGN KEY (comment) REFERENCES comments (comment)
+);
+SHOW CREATE TABLE articles;
+Table Create Table
+articles CREATE TABLE `articles` (
+ `content` text NOT NULL,
+ `comment` int(10) unsigned DEFAULT NULL,
+ KEY `comment` (`comment`),
+ CONSTRAINT `comment` FOREIGN KEY (`comment`) REFERENCES `test`.`comments` (`comment`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=Mroonga DEFAULT CHARSET=latin1
+SELECT * FROM information_schema.referential_constraints;
+DROP TABLE articles;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_existent.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_existent.result
new file mode 100644
index 00000000..e16157b4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_existent.result
@@ -0,0 +1,53 @@
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+CREATE TABLE comments (
+id int unsigned PRIMARY KEY,
+content varchar(140) NOT NULL
+);
+CREATE TABLE entries (
+content varchar(140) NOT NULL,
+comment_id int unsigned,
+FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+DELETE FROM comments WHERE id = 100;
+ERROR 23000: Cannot delete or update a parent row: a foreign key constraint fails (one or more child rows exist in <entries>)
+SELECT * FROM entries;
+content comment_id
+Hello! 100
+SELECT * FROM comments;
+id content
+100 Good entry!
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create comments TABLE_PAT_KEY UInt32
+column_create comments content COLUMN_SCALAR ShortText
+column_create comments id COLUMN_SCALAR UInt32
+
+table_create entries TABLE_NO_KEY
+column_create entries content COLUMN_SCALAR ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create entries comment_id COLUMN_SCALAR comments
+
+load --table comments
+[
+["_key","content","id"],
+[100,"Good entry!",100]
+]
+
+load --table entries
+[
+["_id","comment_id","content"],
+[1,100,"Hello!"]
+]
+
+column_create comments entries-comment_id----------------------------------------------- COLUMN_INDEX entries comment_id
+DROP TABLE entries;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_nonexistent.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_nonexistent.result
new file mode 100644
index 00000000..edaba25f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_delete_nonexistent.result
@@ -0,0 +1,53 @@
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+CREATE TABLE comments (
+id int unsigned PRIMARY KEY,
+content varchar(140) NOT NULL
+);
+CREATE TABLE entries (
+content varchar(140) NOT NULL,
+comment_id int unsigned,
+FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO comments (id, content) VALUES (200, 'Very good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+DELETE FROM comments WHERE id = 200;
+SELECT * FROM entries;
+content comment_id
+Hello! 100
+SELECT * FROM comments;
+id content
+100 Good entry!
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create comments TABLE_PAT_KEY UInt32
+column_create comments content COLUMN_SCALAR ShortText
+column_create comments id COLUMN_SCALAR UInt32
+
+table_create entries TABLE_NO_KEY
+column_create entries content COLUMN_SCALAR ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create entries comment_id COLUMN_SCALAR comments
+
+load --table comments
+[
+["_key","content","id"],
+[100,"Good entry!",100]
+]
+
+load --table entries
+[
+["_id","comment_id","content"],
+[1,100,"Hello!"]
+]
+
+column_create comments entries-comment_id----------------------------------------------- COLUMN_INDEX entries comment_id
+DROP TABLE entries;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_existent.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_existent.result
new file mode 100644
index 00000000..ddc54cb3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_existent.result
@@ -0,0 +1,51 @@
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+CREATE TABLE comments (
+id int unsigned PRIMARY KEY,
+content varchar(140) NOT NULL
+);
+CREATE TABLE entries (
+content varchar(140) NOT NULL,
+comment_id int unsigned,
+FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+SELECT * FROM entries;
+content comment_id
+Hello! 100
+SELECT * FROM comments;
+id content
+100 Good entry!
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create comments TABLE_PAT_KEY UInt32
+column_create comments content COLUMN_SCALAR ShortText
+column_create comments id COLUMN_SCALAR UInt32
+
+table_create entries TABLE_NO_KEY
+column_create entries content COLUMN_SCALAR ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create entries comment_id COLUMN_SCALAR comments
+
+load --table comments
+[
+["_key","content","id"],
+[100,"Good entry!",100]
+]
+
+load --table entries
+[
+["_id","comment_id","content"],
+[1,100,"Hello!"]
+]
+
+column_create comments entries-comment_id----------------------------------------------- COLUMN_INDEX entries comment_id
+DROP TABLE entries;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_nonexistent.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_nonexistent.result
new file mode 100644
index 00000000..c220bb89
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_insert_nonexistent.result
@@ -0,0 +1,37 @@
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+CREATE TABLE comments (
+id int unsigned PRIMARY KEY,
+content varchar(140) NOT NULL
+);
+CREATE TABLE entries (
+content varchar(140) NOT NULL,
+comment_id int unsigned,
+FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 1);
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (foreign record doesn't exist: <comment_id>:<1>)
+SELECT * FROM entries;
+content comment_id
+SELECT * FROM comments;
+id content
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create comments TABLE_PAT_KEY UInt32
+column_create comments content COLUMN_SCALAR ShortText
+column_create comments id COLUMN_SCALAR UInt32
+
+table_create entries TABLE_NO_KEY
+column_create entries content COLUMN_SCALAR ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create entries comment_id COLUMN_SCALAR comments
+
+column_create comments entries-comment_id----------------------------------------------- COLUMN_INDEX entries comment_id
+DROP TABLE entries;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_rename.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_rename.result
new file mode 100644
index 00000000..798be88c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_rename.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+DROP TABLE IF EXISTS articles2;
+DROP TABLE IF EXISTS comments2;
+CREATE TABLE comments (
+comment int unsigned PRIMARY KEY,
+content text NOT NULL
+);
+CREATE TABLE articles (
+content text NOT NULL,
+comment int unsigned,
+FOREIGN KEY (comment) REFERENCES comments (comment)
+);
+RENAME TABLE comments TO comments2;
+RENAME TABLE articles TO articles2;
+SHOW CREATE TABLE articles2;
+Table Create Table
+articles2 CREATE TABLE `articles2` (
+ `content` text NOT NULL,
+ `comment` int(10) unsigned DEFAULT NULL,
+ KEY `comment` (`comment`),
+ CONSTRAINT `comment` FOREIGN KEY (`comment`) REFERENCES `test`.`comments2` (`comment`) ON DELETE RESTRICT ON UPDATE RESTRICT
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+SELECT * FROM information_schema.referential_constraints;
+CONSTRAINT_CATALOG CONSTRAINT_SCHEMA CONSTRAINT_NAME UNIQUE_CONSTRAINT_CATALOG UNIQUE_CONSTRAINT_SCHEMA UNIQUE_CONSTRAINT_NAME MATCH_OPTION UPDATE_RULE DELETE_RULE TABLE_NAME REFERENCED_TABLE_NAME
+def test comment def test PRIMARY NONE RESTRICT RESTRICT articles2 comments2
+DROP TABLE articles2;
+DROP TABLE comments2;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_existent.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_existent.result
new file mode 100644
index 00000000..9db892d5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_existent.result
@@ -0,0 +1,55 @@
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+CREATE TABLE comments (
+id int unsigned PRIMARY KEY,
+content varchar(140) NOT NULL
+);
+CREATE TABLE entries (
+content varchar(140) NOT NULL,
+comment_id int unsigned,
+FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO comments (id, content) VALUES (200, 'Very good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+UPDATE entries SET comment_id = 200 WHERE content = 'Hello!';
+SELECT * FROM entries;
+content comment_id
+Hello! 200
+SELECT * FROM comments;
+id content
+100 Good entry!
+200 Very good entry!
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create comments TABLE_PAT_KEY UInt32
+column_create comments content COLUMN_SCALAR ShortText
+column_create comments id COLUMN_SCALAR UInt32
+
+table_create entries TABLE_NO_KEY
+column_create entries content COLUMN_SCALAR ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create entries comment_id COLUMN_SCALAR comments
+
+load --table comments
+[
+["_key","content","id"],
+[100,"Good entry!",100],
+[200,"Very good entry!",200]
+]
+
+load --table entries
+[
+["_id","comment_id","content"],
+[1,200,"Hello!"]
+]
+
+column_create comments entries-comment_id----------------------------------------------- COLUMN_INDEX entries comment_id
+DROP TABLE entries;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_nonexistent.result b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_nonexistent.result
new file mode 100644
index 00000000..615c3a09
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/foreign_key_update_nonexistent.result
@@ -0,0 +1,53 @@
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+CREATE TABLE comments (
+id int unsigned PRIMARY KEY,
+content varchar(140) NOT NULL
+);
+CREATE TABLE entries (
+content varchar(140) NOT NULL,
+comment_id int unsigned,
+FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+UPDATE entries SET comment_id = 200 WHERE content = 'Hello!';
+ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (foreign record doesn't exist: <comment_id>:<200>)
+SELECT * FROM entries;
+content comment_id
+Hello! 100
+SELECT * FROM comments;
+id content
+100 Good entry!
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create comments TABLE_PAT_KEY UInt32
+column_create comments content COLUMN_SCALAR ShortText
+column_create comments id COLUMN_SCALAR UInt32
+
+table_create entries TABLE_NO_KEY
+column_create entries content COLUMN_SCALAR ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create entries comment_id COLUMN_SCALAR comments
+
+load --table comments
+[
+["_key","content","id"],
+[100,"Good entry!",100]
+]
+
+load --table entries
+[
+["_id","comment_id","content"],
+[1,100,"Hello!"]
+]
+
+column_create comments entries-comment_id----------------------------------------------- COLUMN_INDEX entries comment_id
+DROP TABLE entries;
+DROP TABLE comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_empty_query.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_empty_query.result
new file mode 100644
index 00000000..96c6ae41
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_empty_query.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT * FROM diaries;
+title
+Start groonga
+Start mroonga
+Start groonga and Ruby
+SELECT *
+FROM diaries
+WHERE MATCH(title) AGAINST("" IN BOOLEAN MODE);
+title
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_escape.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_escape.result
new file mode 100644
index 00000000..5beda03c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_escape.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("\\(groonga\\)*" IN BOOLEAN MODE);
+id content
+1 (groonga) Installed!
+3 (groonga) Upgraded!
+DROP TABLE memos;
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_leading_not.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_leading_not.result
new file mode 100644
index 00000000..758f969f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_leading_not.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("-明日 +天気" IN BOOLEAN MODE);
+id title content
+3 富士山 今日も天気がよくてきれいに見える。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_all.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_all.result
new file mode 100644
index 00000000..c8270bc3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_all.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES(1, "Groonga", "Groonga is fast.");
+INSERT INTO memos VALUES(2, "Mroonga", "Mroonga is also fast.");
+INSERT INTO memos VALUES(3, "Rroonga", "Rroonga is also fast.");
+SELECT *,
+MATCH(title, content)
+AGAINST("*W1:10,2:2DOR Groonga Mroonga" in BOOLEAN MODE) AS score
+FROM memos
+WHERE MATCH(title, content)
+AGAINST("*W1:10,2:2DOR Groonga Mroonga" in BOOLEAN MODE);
+id title content score
+1 Groonga Groonga is fast. 12
+2 Mroonga Mroonga is also fast. 12
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result
new file mode 100644
index 00000000..d10b5dad
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Yesterday was good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D- fine is be" IN BOOLEAN MODE);
+content
+Yesterday was fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result
new file mode 100644
index 00000000..82c7e799
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Yesterday was good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D- is OR be fine" IN BOOLEAN MODE);
+content
+Today is good day.
+Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result
new file mode 100644
index 00000000..c4c7b0e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Yesterday was good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D- good +day be" IN BOOLEAN MODE);
+content
+Today is good day.
+Yesterday was good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result
new file mode 100644
index 00000000..0c81bf6c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*DOR today good" IN BOOLEAN MODE)
+ORDER BY content;
+content
+Today is fine.
+Today is good day.
+Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result
new file mode 100644
index 00000000..dfeb71f0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*DOR today -good tomorrow" IN BOOLEAN MODE)
+ORDER BY content;
+content
+Today is fine.
+Tomorrow will be fine.
+Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result
new file mode 100644
index 00000000..e72cf8d4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*DOR today +good tomorrow" IN BOOLEAN MODE)
+ORDER BY content;
+content
+Today is good day.
+Tomorrow will be fine.
+Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result
new file mode 100644
index 00000000..4d1f6592
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today good" IN BOOLEAN MODE);
+content
+Today is good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.result
new file mode 100644
index 00000000..7a30baab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today fi*" IN BOOLEAN MODE);
+content
+Today is fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result
new file mode 100644
index 00000000..deda6f3b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today -good is" IN BOOLEAN MODE);
+content
+Today is fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result
new file mode 100644
index 00000000..2d25388f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today OR tomorrow day" IN BOOLEAN MODE);
+content
+Today is good day.
+Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_operator.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_operator.result
new file mode 100644
index 00000000..deb4bd85
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_operator.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*SS content @ '天気'" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*SS content @ '天気'" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 1
+3 富士山 今日も天気がよくてきれいに見える。 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_selector.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_selector.result
new file mode 100644
index 00000000..43b21bc1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_syntax_script_selector.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS items;
+DROP TABLE IF EXISTS readings;
+SET NAMES utf8;
+CREATE TABLE readings (
+reading VARCHAR(255) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE items (
+name VARCHAR(255) PRIMARY KEY,
+readings TEXT COMMENT 'flags "COLUMN_VECTOR", type "readings"',
+FULLTEXT INDEX items_index(readings) COMMENT 'table "readings"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO items VALUES("日本", "ニホン ニッポン");
+INSERT INTO items VALUES("ローマ字", "ローマジ");
+INSERT INTO items VALUES("漢字", "カンジ");
+SELECT *, MATCH(readings)
+AGAINST("*SS sub_filter(readings, 'prefix_rk_search(_key, \"niho\")')" in BOOLEAN MODE) AS score
+FROM items
+WHERE MATCH(readings)
+AGAINST("*SS sub_filter(readings, 'prefix_rk_search(_key, \"niho\")')" in BOOLEAN MODE);
+name readings score
+日本 ニホン ニッポン 1
+DROP TABLE items;
+DROP TABLE readings;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_full_spec.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_full_spec.result
new file mode 100644
index 00000000..b8f15d98
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_full_spec.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 12
+3 富士山 今日も天気がよくてきれいに見える。 2
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_no_weight.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_no_weight.result
new file mode 100644
index 00000000..42aa068a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_no_weight.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*W1,2:2 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*W1,2:2 +天気" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 3
+3 富士山 今日も天気がよくてきれいに見える。 2
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_omit_section.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_omit_section.result
new file mode 100644
index 00000000..c73d2660
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_omit_section.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*W1:2 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*W1:2 +天気" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 3
+3 富士山 今日も天気がよくてきれいに見える。 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.result
new file mode 100644
index 00000000..b1b9d5f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.result
@@ -0,0 +1,39 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+title VARCHAR(255),
+tag1 VARCHAR(10),
+tag2 VARCHAR(10),
+tag3 VARCHAR(10),
+tag4 VARCHAR(10),
+tag5 VARCHAR(10),
+tag6 VARCHAR(10),
+tag7 VARCHAR(10),
+tag8 VARCHAR(10),
+tag9 VARCHAR(10),
+tag10 VARCHAR(10),
+FULLTEXT INDEX (tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos
+VALUES("Groonga",
+"tag 1",
+"tag 2",
+"tag 3",
+"tag 4",
+"tag 5",
+"tag 6",
+"tag 7",
+"tag 8",
+"tag 9",
+"tag 10");
+SELECT title,
+MATCH(tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
+AGAINST("*W1:2,2:4,3:6,4:8,5:10,6:12,7:14,8:16,9:18,10:20 +tag"
+ in BOOLEAN MODE) AS score
+FROM memos
+WHERE MATCH(tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
+AGAINST("*W1:2,2:4,3:6,4:8,5:10,6:12,7:14,8:16,9:18,10:20 +tag"
+ in BOOLEAN MODE);
+title score
+Groonga 110
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_three_or_more_sections.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_three_or_more_sections.result
new file mode 100644
index 00000000..02db17e6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_pragma_weight_three_or_more_sections.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+category VARCHAR(10),
+content TEXT,
+FULLTEXT INDEX (title, category, content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES(1, "Hello", "日記", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気予報", "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "天気", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, category, content)
+AGAINST("*W1:2,2:10,3:1 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, category, content)
+AGAINST("*W1:2,2:10,3:1 +天気" in BOOLEAN MODE);
+id title category content score
+2 天気予報 天気 明日の富士山の天気について 13
+3 富士山 天気 今日も天気がよくてきれいに見える。 11
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error.result
new file mode 100644
index 00000000..46dd3290
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS memos;
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = ERROR;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+ERROR 42000: failed to parse fulltext search keyword: <(groonga>: <Syntax error: <(groonga||>>
+DROP TABLE memos;
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error_and_log.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error_and_log.result
new file mode 100644
index 00000000..d782357e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_error_and_log.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS memos;
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = ERROR_AND_LOG;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+ERROR 42000: failed to parse fulltext search keyword: <(groonga>: <Syntax error: <(groonga||>>
+DROP TABLE memos;
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore.result
new file mode 100644
index 00000000..fd5b8d1e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS memos;
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = "IGNORE";
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+id content
+DROP TABLE memos;
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore_and_log.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore_and_log.result
new file mode 100644
index 00000000..a485e1ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_boolean_mode_syntax_error_ignore_and_log.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS memos;
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = IGNORE_AND_LOG;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+id content
+DROP TABLE memos;
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_ascii.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_ascii.result
new file mode 100644
index 00000000..c542ba1a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_ascii.result
@@ -0,0 +1,29 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3));
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 20 ka ki ku ke ko
+3 30 sa si su se so
+4 40 ta ti tu te to
+5 50 aa ii uu ee oo
+select * from t1 where match(c3) against("su");
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 where match(c3) against("ii");
+c1 c2 c3
+1 10 aa ii uu ee oo
+5 50 aa ii uu ee oo
+select * from t1 where match(c3) against("+su" in boolean mode);
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 where match(c3) against("+ii" in boolean mode);
+c1 c2 c3
+1 10 aa ii uu ee oo
+5 50 aa ii uu ee oo
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_cp932.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_cp932.result
new file mode 100644
index 00000000..bd208d52
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_cp932.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+set names cp932;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset cp932;
+insert into t1 values(1, "̕xmR̓VCɂ‚","");
+insert into t1 values(2, "","̕xmR̓VC͕܂");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 ̕xmR̓VCɂ‚
+2 ̕xmR̓VC͕܂
+3 dummy dummy
+select * from t1 where match(c2) against("xmR");
+c1 c2 c3
+1 ̕xmR̓VCɂ‚
+select * from t1 where match(c3) against("xmR");
+c1 c2 c3
+2 ̕xmR̓VC͕܂
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_eucjpms.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_eucjpms.result
new file mode 100644
index 00000000..51360875
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_eucjpms.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+set names eucjpms;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset eucjpms;
+insert into t1 values(1, "ٻλŷˤĤ","");
+insert into t1 values(2, "","ٻλŷʬޤ");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 ٻλŷˤĤ
+2 ٻλŷʬޤ
+3 dummy dummy
+select * from t1 where match(c2) against("ٻλ");
+c1 c2 c3
+1 ٻλŷˤĤ
+select * from t1 where match(c3) against("ٻλ");
+c1 c2 c3
+2 ٻλŷʬޤ
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_japanese.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_japanese.result
new file mode 100644
index 00000000..cfff3f2e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_japanese.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8;
+insert into t1 values(1, "明日の富士山の天気について","あああああああ");
+insert into t1 values(2, "いいいいい","明日の富士山の天気は分かりません");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 明日の富士山の天気について あああああああ
+2 いいいいい 明日の富士山の天気は分かりません
+3 dummy dummy
+select * from t1 where match(c2) against("富士山");
+c1 c2 c3
+1 明日の富士山の天気について あああああああ
+select * from t1 where match(c3) against("富士山");
+c1 c2 c3
+2 いいいいい 明日の富士山の天気は分かりません
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_utf8mb4.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_utf8mb4.result
new file mode 100644
index 00000000..136585c3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_charset_utf8mb4.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8mb4;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255) CHARSET utf8mb4 COLLATE utf8mb4_general_ci,
+content TEXT CHARSET utf8mb4 COLLATE utf8mb4_general_ci,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET utf8mb4;
+INSERT INTO diaries VALUES(1, "Alphabet", "ABCDE");
+INSERT INTO diaries VALUES(2, "Mathmatics", "𝐀𝐁𝐂𝐃𝐄 | U+1D400-U+1D405");
+INSERT INTO diaries VALUES(3, "ひらがな", "あいうえお");
+SELECT *
+FROM diaries
+WHERE MATCH (content) AGAINST("ABCDE" IN BOOLEAN MODE);
+id title content
+1 Alphabet ABCDE
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_empty_query.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_empty_query.result
new file mode 100644
index 00000000..bb7b3b63
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_empty_query.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT * FROM diaries;
+title
+Start groonga
+Start mroonga
+Start groonga and Ruby
+SELECT *
+FROM diaries
+WHERE MATCH(title) AGAINST("");
+title
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_found_rows.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_found_rows.result
new file mode 100644
index 00000000..25da7011
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_found_rows.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 11, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(6, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT SQL_CALC_FOUND_ROWS * FROM diaries WHERE MATCH(content) AGAINST("今日 天気" IN BOOLEAN MODE) ORDER BY day LIMIT 0,5;
+id year month day title content
+5 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+6 2011 12 2 初雪 今日の天気は雪!
+1 2011 11 9 Hello 今日からはじめました。
+2 2011 11 10 天気 明日の富士山の天気について
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+SELECT FOUND_ROWS();
+FOUND_ROWS()
+6
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_groonga_varchar_vector.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_groonga_varchar_vector.result
new file mode 100644
index 00000000..a23d8e5b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_groonga_varchar_vector.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS bugs, tags;
+CREATE TABLE tags (
+name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COLLATE=utf8_bin
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tags VARCHAR(40) COMMENT 'type "tags", flags "COLUMN_VECTOR"',
+FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"'
+) DEFAULT CHARSET=utf8;
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL");
+INSERT INTO bugs (id, tags) VALUES (2, "MySQL groonga");
+INSERT INTO bugs (id, tags) VALUES (3, "mroonga");
+SELECT *
+FROM bugs
+WHERE MATCH (tags) AGAINST ("MySQL" IN BOOLEAN MODE);
+id tags
+1 Linux MySQL
+2 MySQL groonga
+DROP TABLE bugs, tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_index_recreate.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_index_recreate.result
new file mode 100644
index 00000000..e38913a6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_index_recreate.result
@@ -0,0 +1,32 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries where match(title) against("富士山");
+id title content
+3 富士山 今日もきれい。
+drop index title on diaries;
+select * from diaries where match(title) against("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+select * from diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+create fulltext index new_title_index on diaries (title);
+select * from diaries where match(title) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_select.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_select.result
new file mode 100644
index 00000000..c337bfcb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_select.result
@@ -0,0 +1,46 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 varchar(100), fulltext index(c2)) default charset utf8;
+create table t2 (c1 int primary key, c2 text, fulltext index(c2)) default charset utf8;
+insert into t1 values (1, "aa ii uu ee oo");
+insert into t1 values (2, "ka ki ku ke ko");
+insert into t1 values (3, "aa ii ii ii oo");
+insert into t1 values (4, "sa si su se so");
+insert into t1 values (5, "ta ti ii ii to");
+insert into t2 (c1,c2) select c1,c2 from t1;
+select * from t1;
+c1 c2
+1 aa ii uu ee oo
+2 ka ki ku ke ko
+3 aa ii ii ii oo
+4 sa si su se so
+5 ta ti ii ii to
+select * from t2;
+c1 c2
+1 aa ii uu ee oo
+2 ka ki ku ke ko
+3 aa ii ii ii oo
+4 sa si su se so
+5 ta ti ii ii to
+select * from t1 where c1=3;
+c1 c2
+3 aa ii ii ii oo
+select * from t2 where c1=3;
+c1 c2
+3 aa ii ii ii oo
+select * from t1 where c1>3 order by c1 desc;
+c1 c2
+5 ta ti ii ii to
+4 sa si su se so
+select * from t2 where c1>3 order by c1 asc;
+c1 c2
+4 sa si su se so
+5 ta ti ii ii to
+select * from t1 where c2>"s" order by c2 desc;
+c1 c2
+5 ta ti ii ii to
+4 sa si su se so
+select * from t2 where c2>"s" order by c1 asc;
+c1 c2
+4 sa si su se so
+5 ta ti ii ii to
+drop table t1,t2;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_values.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_values.result
new file mode 100644
index 00000000..5c48cadf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_insert_values.result
@@ -0,0 +1,17 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 text, fulltext index ft (c2));
+insert into t1 values (1, "hoge hoge");
+insert into t1 values (2, "fuga fuga");
+insert into t1 values (3, "moge moge");
+select * from t1;
+c1 c2
+1 hoge hoge
+2 fuga fuga
+3 moge moge
+flush tables;
+select * from t1;
+c1 c2
+1 hoge hoge
+2 fuga fuga
+3 moge moge
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_delete.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_delete.result
new file mode 100644
index 00000000..6475f9ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_delete.result
@@ -0,0 +1,23 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+delete from diaries where id = 2;
+select * from diaries where match(title, content) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries where match(title) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries where match(content) against("富士山");
+id title content
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_insert.result
new file mode 100644
index 00000000..4244af26
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_insert.result
@@ -0,0 +1,29 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+select * from diaries where match(title, content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+select * from diaries where match(title) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries where match(content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_recreate.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_recreate.result
new file mode 100644
index 00000000..8d18efaa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_recreate.result
@@ -0,0 +1,31 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries where match(title, content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+drop index title on diaries;
+select * from diaries where match(title, content) against("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+create fulltext index new_title_content_index on diaries (title, content);
+select * from diaries where match(title, content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+select * from diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_update.result
new file mode 100644
index 00000000..0e85b45a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_column_index_update.result
@@ -0,0 +1,26 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+update diaries set title = "チョモランマ" where id = 3;
+update diaries set content = "チョモランマと富士山" where id = 1;
+select * from diaries where match(title, content) against("富士山");
+id title content
+1 Hello チョモランマと富士山
+2 天気 明日の富士山の天気について
+select * from diaries where match(title) against("富士山");
+id title content
+select * from diaries where match(content) against("富士山");
+id title content
+1 Hello チョモランマと富士山
+2 天気 明日の富士山の天気について
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_index.result
new file mode 100644
index 00000000..37d7597b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_multiple_index.result
@@ -0,0 +1,23 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+title text,
+body text,
+fulltext index title_index (title),
+fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (title, body) values ("survey", "will start groonga!");
+insert into diaries (title, body) values ("groonga (1)", "starting groonga...");
+insert into diaries (title, body) values ("groonga (2)", "started groonga.");
+select * from diaries
+where match(title) against("survey") and
+match(body) against("groonga");
+id title body
+1 survey will start groonga!
+select *, match(title) against("survey"), match(body) against("groonga")
+from diaries
+where match(title) against("survey") and
+match(body) against("groonga");
+id title body match(title) against("survey") match(body) against("groonga")
+1 survey will start groonga! 1048577 149797
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_no_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_no_primary_key.result
new file mode 100644
index 00000000..db4afff0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_no_primary_key.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES("Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES("天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES("富士山", "今日も天気がよくてきれいに見える。");
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("*D+ 今日 天気" IN BOOLEAN MODE);
+title content
+富士山 今日も天気がよくてきれいに見える。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_not_match_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_not_match_against.result
new file mode 100644
index 00000000..b6d6febf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_not_match_against.result
@@ -0,0 +1,68 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3));
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,10,"ka ki ku ke ko");
+insert into t1 values(3,10,"aa ii uu ee oo");
+insert into t1 values(4,10,"ka ki ku ke ko");
+insert into t1 values(5,20,"aa ii uu ee oo");
+insert into t1 values(6,20,"ka ki ku ke ko");
+insert into t1 values(7,20,"aa ii uu ee oo");
+insert into t1 values(8,20,"ka ki ku ke ko");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 10 ka ki ku ke ko
+3 10 aa ii uu ee oo
+4 10 ka ki ku ke ko
+5 20 aa ii uu ee oo
+6 20 ka ki ku ke ko
+7 20 aa ii uu ee oo
+8 20 ka ki ku ke ko
+select * from t1 where match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+3 10 aa ii uu ee oo
+5 20 aa ii uu ee oo
+7 20 aa ii uu ee oo
+select * from t1 where not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where match(c3) against("+dummy" in boolean mode) order by c1;
+c1 c2 c3
+select * from t1 where not match(c3) against("+dummy" in boolean mode) order by c1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 10 ka ki ku ke ko
+3 10 aa ii uu ee oo
+4 10 ka ki ku ke ko
+5 20 aa ii uu ee oo
+6 20 ka ki ku ke ko
+7 20 aa ii uu ee oo
+8 20 ka ki ku ke ko
+select * from t1 where c1 = 4 and not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+4 10 ka ki ku ke ko
+select * from t1 where c1 <= 4 and not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+select * from t1 where c1 > 4 and not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where c2 = 10 and not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+select * from t1 where c2 >= 15 and not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where c2 < 15 and not match(c3) against("+uu" in boolean mode) order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_or.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_or.result
new file mode 100644
index 00000000..f1f7888c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_or.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT * FROM diaries;
+title
+Start groonga
+Start mroonga
+Start groonga and Ruby
+SELECT *
+FROM diaries
+WHERE MATCH(title) AGAINST("Ruby" IN BOOLEAN MODE) OR
+MATCH(title) AGAINST("mroonga" IN BOOLEAN MODE);
+title
+Start mroonga
+Start groonga and Ruby
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_against.result
new file mode 100644
index 00000000..d1f0d6bc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_against.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT * FROM diaries;
+title
+Start groonga
+Start mroonga
+Start groonga and Ruby
+SELECT *, MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title) AGAINST("groonga mroonga" IN BOOLEAN MODE)
+ORDER BY MATCH(title) AGAINST("groonga" IN BOOLEAN MODE);
+title score
+Start mroonga 0
+Start groonga 1
+Start groonga and Ruby 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_match.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_match.result
new file mode 100644
index 00000000..b4a07cd0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_different_match.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+body TEXT,
+FULLTEXT KEY (title),
+FULLTEXT KEY (body)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga", "I read groonga's tutorial.");
+INSERT INTO diaries VALUES("Start mroonga", "I read mroonga's tutorial.");
+INSERT INTO diaries VALUES("Start groonga and Ruby", "I installed rroonga.");
+SELECT * FROM diaries;
+title body
+Start groonga I read groonga's tutorial.
+Start mroonga I read mroonga's tutorial.
+Start groonga and Ruby I installed rroonga.
+SELECT *, MATCH(body) AGAINST("groonga" IN BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE)
+ORDER BY MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+title body score
+Start groonga and Ruby I installed rroonga. 0
+Start groonga I read groonga's tutorial. 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_no_where.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_no_where.result
new file mode 100644
index 00000000..125b35fb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_no_where.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT * FROM diaries;
+title
+Start groonga
+Start mroonga
+Start groonga and Ruby
+SELECT *, MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AS score
+FROM diaries
+ORDER BY MATCH(title) AGAINST("groonga" IN BOOLEAN MODE);
+title score
+Start mroonga 0
+Start groonga 1
+Start groonga and Ruby 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_same_match_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_same_match_against.result
new file mode 100644
index 00000000..a3a668c4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_boolean_mode_same_match_against.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT * FROM diaries;
+title
+Start groonga
+Start mroonga
+Start groonga and Ruby
+SELECT *, MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE)
+ORDER BY MATCH(title) AGAINST("groonga" IN BOOLEAN MODE);
+title score
+Start groonga 1
+Start groonga and Ruby 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_asc.result
new file mode 100644
index 00000000..7f0934d3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_asc.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs(
+message TEXT,
+FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+SELECT * FROM logs;
+message
+Error Error Error
+Warning Warning Warning
+Error Error
+Warning Warning
+Error
+Warning
+Error Error Error Error
+Warning Warning Warning Warning
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+FROM logs
+WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) ASC;
+message score
+Error 174763
+Error Error 349526
+Error Error Error 524289
+Error Error Error Error 699052
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_desc.result
new file mode 100644
index 00000000..fa577b17
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_desc.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs(
+message TEXT,
+FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+SELECT * FROM logs;
+message
+Error Error Error
+Warning Warning Warning
+Error Error
+Warning Warning
+Error
+Warning
+Error Error Error Error
+Warning Warning Warning Warning
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+FROM logs
+WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) DESC;
+message score
+Error Error Error Error 699052
+Error Error Error 524289
+Error Error 349526
+Error 174763
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_against.result
new file mode 100644
index 00000000..958883e5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_against.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs(
+message TEXT,
+FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+SELECT * FROM logs;
+message
+Error Error Error
+Warning Warning Warning
+Error Error
+Warning Warning
+Error
+Warning
+Error Error Error Error
+Warning Warning Warning Warning
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+FROM logs
+WHERE MATCH(message) AGAINST("Error Warning" IN NATURAL LANGUAGE MODE)
+ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE);
+message score
+Error 174763
+Error Error 349526
+Error Error Error 524289
+Error Error Error Error 699052
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_match.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_match.result
new file mode 100644
index 00000000..76abb660
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_different_match.result
@@ -0,0 +1,36 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs(
+message TEXT,
+host TEXT,
+FULLTEXT KEY (message),
+FULLTEXT KEY (host)
+) DEFAULT CHARSET=utf8;
+INSERT INTO logs VALUES("Error Error Error", "host1");
+INSERT INTO logs VALUES("Warning Warning Warning", "host1");
+INSERT INTO logs VALUES("Error Error", "host2");
+INSERT INTO logs VALUES("Warning Warning", "host2");
+INSERT INTO logs VALUES("Error", "host2");
+INSERT INTO logs VALUES("Warning", "host2");
+INSERT INTO logs VALUES("Error Error Error Error", "host2");
+INSERT INTO logs VALUES("Warning Warning Warning Warning", "host2");
+SELECT * FROM logs;
+message host
+Error Error Error host1
+Warning Warning Warning host1
+Error Error host2
+Warning Warning host2
+Error host2
+Warning host2
+Error Error Error Error host2
+Warning Warning Warning Warning host2
+SELECT *, MATCH(host) AGAINST("host2" IN NATURAL LANGUAGE MODE) AS score
+FROM logs
+WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ORDER BY MATCH(host) AGAINST("host2" IN NATURAL LANGUAGE MODE);
+message host score
+Error Error Error host1 0
+Error Error host2 116509
+Error host2 116509
+Error Error Error Error host2 116509
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_no_where.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_no_where.result
new file mode 100644
index 00000000..30130e6c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_no_where.result
@@ -0,0 +1,37 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs(
+message TEXT,
+FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+SELECT * FROM logs;
+message
+Error Error Error
+Warning Warning Warning
+Error Error
+Warning Warning
+Error
+Warning
+Error Error Error Error
+Warning Warning Warning Warning
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+FROM logs
+ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE);
+message score
+Warning Warning Warning 0
+Warning Warning 0
+Warning 0
+Warning Warning Warning Warning 0
+Error 174763
+Error Error 349526
+Error Error Error 524289
+Error Error Error Error 699052
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_same_match_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_same_match_against.result
new file mode 100644
index 00000000..ac2e7522
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_order_natural_language_mode_same_match_against.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs(
+message TEXT,
+FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+SELECT * FROM logs;
+message
+Error Error Error
+Warning Warning Warning
+Error Error
+Warning Warning
+Error
+Warning
+Error Error Error Error
+Warning Warning Warning Warning
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+FROM logs
+WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE);
+message score
+Error 174763
+Error Error 349526
+Error Error Error 524289
+Error Error Error Error 699052
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_two_inner_join.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_two_inner_join.result
new file mode 100644
index 00000000..e39790ed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_two_inner_join.result
@@ -0,0 +1,41 @@
+DROP TABLE IF EXISTS users, posts, comments;
+SET NAMES utf8;
+CREATE TABLE users (
+id int NOT NULL,
+name varchar(50) NOT NULL,
+PRIMARY KEY (id),
+KEY (name)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE posts (
+id int NOT NULL,
+content mediumtext,
+user_id int NOT NULL,
+PRIMARY KEY (id),
+FULLTEXT KEY (content)
+) DEFAULT CHARSET=utf8;
+CREATE TABLE comments (
+id int NOT NULL,
+user_id int NOT NULL,
+post_id int NOT NULL,
+PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES (1, "Alice"),
+(2, "Bob"),
+(3, "Calros");
+INSERT INTO posts VALUES (1, "Hello!", 1),
+(2, "World!", 2),
+(3, "Great!", 3);
+INSERT INTO comments VALUES (1, 1, 1),
+(2, 2, 1),
+(3, 3, 3);
+SELECT *
+FROM comments
+INNER JOIN posts
+ON posts.id = comments.post_id AND
+MATCH (posts.content) AGAINST ("Hello!" IN BOOLEAN MODE)
+INNER JOIN users
+ON users.id = comments.user_id AND
+users.name = "Alice";
+id user_id post_id id content user_id id name
+1 1 1 1 Hello! 1 1 Alice
+DROP TABLE users, posts, comments;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_10_0_no_such_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_10_0_no_such_key.result
new file mode 100644
index 00000000..d3ac2387
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_10_0_no_such_key.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` text,
+ `body` text,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `title_index` (`title`),
+ FULLTEXT KEY `body_index` (`body`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries FORCE INDEX(primary)
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE);
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_5_no_such_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_5_no_such_key.result
new file mode 100644
index 00000000..5f7bc98a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_5_no_such_key.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` text,
+ `body` text,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `title_index` (`title`),
+ FULLTEXT KEY `body_index` (`body`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries FORCE INDEX(primary)
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE);
+id title body
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_6_no_such_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_6_no_such_key.result
new file mode 100644
index 00000000..d3ac2387
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/fulltext_version_5_6_no_such_key.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `title` text,
+ `body` text,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `title_index` (`title`),
+ FULLTEXT KEY `body_index` (`body`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries FORCE INDEX(primary)
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE);
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_command_auto-escape.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_command_auto-escape.result
new file mode 100644
index 00000000..e07eae11
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_command_auto-escape.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES('It is Groonga');
+INSERT INTO diaries VALUES('It is Mroonga');
+SELECT mroonga_command('select',
+'table', 'diaries',
+'filter', 'title @ "Groonga"');
+mroonga_command('select',
+'table', 'diaries',
+'filter', 'title @ "Groonga"')
+[[[1],[["_id","UInt32"],["title","LongText"]],[1,"It is Groonga"]]]
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_command_select.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_command_select.result
new file mode 100644
index 00000000..1551d32c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_command_select.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT mroonga_command('select diaries --match_columns "title" --query "groonga"');
+mroonga_command('select diaries --match_columns "title" --query "groonga"')
+[[[2],[["_id","UInt32"],["title","LongText"]],[1,"Start groonga"],[3,"Start groonga and Ruby"]]]
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_command_special-database-name.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_command_special-database-name.result
new file mode 100644
index 00000000..e588408e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_command_special-database-name.result
@@ -0,0 +1,22 @@
+DROP DATABASE IF EXISTS `db-1`;
+CREATE DATABASE `db-1`;
+USE `db-1`;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command('dump --dump_plugins no');
+mroonga_command('dump --dump_plugins no')
+table_create diaries TABLE_NO_KEY
+column_create diaries title COLUMN_SCALAR LongText
+
+table_create diaries#title TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create diaries#title index COLUMN_INDEX|WITH_POSITION diaries title
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_missing.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_missing.result
new file mode 100644
index 00000000..98213e81
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_missing.result
@@ -0,0 +1,3 @@
+SET NAMES UTF8;
+SELECT mroonga_escape() AS escaped_query;
+ERROR HY000: Can't initialize function 'mroonga_escape'; mroonga_escape(): Incorrect number of arguments: 0 for 1..2
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_not_string.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_not_string.result
new file mode 100644
index 00000000..bb68bbff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_query_is_not_string.result
@@ -0,0 +1,3 @@
+SET NAMES UTF8;
+SELECT mroonga_escape(29) AS escaped_query;
+ERROR HY000: Can't initialize function 'mroonga_escape'; mroonga_escape(): The 1st query argument must be string
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_target_characters_is_not_string.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_target_characters_is_not_string.result
new file mode 100644
index 00000000..77dc420f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_error_target_characters_is_not_string.result
@@ -0,0 +1,3 @@
+SET NAMES UTF8;
+SELECT mroonga_escape('+-><~*()\"\\:', 29) AS escaped_query;
+ERROR HY000: Can't initialize function 'mroonga_escape'; mroonga_escape(): The 2st argument must be escape target characters as string
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_all.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_all.result
new file mode 100644
index 00000000..b002262a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_all.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_escape('+-><~*()\"\\:') AS escaped_query;
+escaped_query
+\+\-\>\<\~\*\(\)\"\\\:
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_custom.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_custom.result
new file mode 100644
index 00000000..c2e7d8f5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_custom.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_escape('+-><~*()\"\\:', '()<>~') AS escaped_query;
+escaped_query
++-\>\<\~*\(\)"\:
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_join.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_join.result
new file mode 100644
index 00000000..ec765b11
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_join.result
@@ -0,0 +1,26 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS users;
+DROP TABLE IF EXISTS queries;
+CREATE TABLE users (
+id INT
+);
+CREATE TABLE queries (
+user_id INT,
+query TEXT
+);
+INSERT INTO users VALUES (1);
+INSERT INTO users VALUES (2);
+INSERT INTO users VALUES (3);
+INSERT INTO queries VALUES (1, '(a)');
+INSERT INTO queries VALUES (2, '(b)');
+INSERT INTO queries VALUES (3, '(c)');
+SELECT users.id, mroonga_escape(queries.query) AS escaped_query
+FROM queries
+LEFT JOIN users ON users.id = queries.user_id
+ORDER BY users.id;
+id escaped_query
+1 \(a\)
+2 \(b\)
+3 \(c\)
+DROP TABLE queries;
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_match_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_match_against.result
new file mode 100644
index 00000000..adf6b3a4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_match_against.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET NAMES utf8mb4;
+CREATE TABLE memos (
+id INT PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8mb4;
+INSERT INTO memos VALUES(1, "(Groonga) Installed!");
+INSERT INTO memos VALUES(2, "(Mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(Groonga) Upgraded!");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST(mroonga_escape("(groonga)") IN BOOLEAN MODE);
+id content
+1 (Groonga) Installed!
+3 (Groonga) Upgraded!
+DROP TABLE memos;
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_named.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_named.result
new file mode 100644
index 00000000..c6c39fcc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_named.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_escape('+-><~*()\"\\:' AS query) AS escaped_query;
+escaped_query
+\+\-\>\<\~\*\(\)\"\\\:
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_nested.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_nested.result
new file mode 100644
index 00000000..5a57c144
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_query_nested.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries(
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+SELECT mroonga_escape(mroonga_escape('*groonga*'));
+mroonga_escape(mroonga_escape('*groonga*'))
+\\\*groonga\\\*
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_decimal.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_decimal.result
new file mode 100644
index 00000000..246f2800
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_decimal.result
@@ -0,0 +1,11 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS data;
+CREATE TABLE data (
+value DECIMAL(5, 3)
+);
+INSERT INTO data VALUES (2.9);
+SELECT mroonga_escape(value AS script)
+FROM data;
+mroonga_escape(value AS script)
+2.9
+DROP TABLE data;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_integer.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_integer.result
new file mode 100644
index 00000000..902bbd31
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_integer.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_escape(-29 AS script) AS escaped_query;
+escaped_query
+-29
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_real.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_real.result
new file mode 100644
index 00000000..178ff312
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_real.result
@@ -0,0 +1,11 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS data;
+CREATE TABLE data (
+value REAL
+);
+INSERT INTO data VALUES (2.9);
+SELECT mroonga_escape(value AS script)
+FROM data;
+mroonga_escape(value AS script)
+2.9
+DROP TABLE data;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_string.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_string.result
new file mode 100644
index 00000000..6f5e9b2a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_escape_script_string.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_escape('a\"\\\'z' AS script) AS escaped_query;
+escaped_query
+"a\"\\'z"
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_dynamic_keyword.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_dynamic_keyword.result
new file mode 100644
index 00000000..96df6506
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_dynamic_keyword.result
@@ -0,0 +1,11 @@
+CREATE TABLE keywords (
+keyword text
+);
+INSERT INTO keywords VALUES ('Mroonga');
+INSERT INTO keywords VALUES ('Groonga');
+SELECT mroonga_highlight_html('Mroonga is the Groonga based storage engine.',
+keyword) AS highlighted
+FROM keywords;
+highlighted
+<span class="keyword">Mroonga</span> is the Groonga based storage engine.
+Mroonga is the <span class="keyword">Groonga</span> based storage engine.
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_japanese.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_japanese.result
new file mode 100644
index 00000000..ca7d7968
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_japanese.result
@@ -0,0 +1,13 @@
+SET NAMES utf8;
+SELECT mroonga_highlight_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+'ロック', '更新') AS highlighted;
+highlighted
+Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照<span class="keyword">ロック</span>フリーなGroongaの性能特性をフルに活かした高速なデータ<span class="keyword">更新</span>・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照<span class="keyword">ロック</span>フリーな特性は活かすことができません。また、<span class="keyword">更新</span>処理は他のストレージエンジンがボトルネックになることが多いでしょう。
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_multiple_keywords.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_multiple_keywords.result
new file mode 100644
index 00000000..9f4a3dff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_multiple_keywords.result
@@ -0,0 +1,4 @@
+SELECT mroonga_highlight_html('Mroonga is the Groonga based storage engine.',
+'Mroonga', 'Groonga') AS highlighted;
+highlighted
+<span class="keyword">Mroonga</span> is the <span class="keyword">Groonga</span> based storage engine.
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_normalizer.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_normalizer.result
new file mode 100644
index 00000000..bf280dba
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_normalizer.result
@@ -0,0 +1,4 @@
+SELECT mroonga_highlight_html('Mroonga is the Groonga based storage engine.',
+'mroonga') AS highlighted;
+highlighted
+<span class="keyword">Mroonga</span> is the Groonga based storage engine.
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query.result
new file mode 100644
index 00000000..b2d0f509
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query.result
@@ -0,0 +1,13 @@
+SET NAMES utf8;
+SELECT mroonga_highlight_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+'ロック 更新 -ボトルネック' AS query) AS highlighted;
+highlighted
+Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照<span class="keyword">ロック</span>フリーなGroongaの性能特性をフルに活かした高速なデータ<span class="keyword">更新</span>・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照<span class="keyword">ロック</span>フリーな特性は活かすことができません。また、<span class="keyword">更新</span>処理は他のストレージエンジンがボトルネックになることが多いでしょう。
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query_pragma.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query_pragma.result
new file mode 100644
index 00000000..bd11a908
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_query_pragma.result
@@ -0,0 +1,13 @@
+SET NAMES utf8;
+SELECT mroonga_highlight_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+'*D- +ロック +更新 ボトルネック' AS query) AS highlighted;
+highlighted
+Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照<span class="keyword">ロック</span>フリーなGroongaの性能特性をフルに活かした高速なデータ<span class="keyword">更新</span>・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照<span class="keyword">ロック</span>フリーな特性は活かすことができません。また、<span class="keyword">更新</span>処理は他のストレージエンジンがボトルネックになることが多いでしょう。
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_record.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_record.result
new file mode 100644
index 00000000..fce13d9c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_highlight_html_record.result
@@ -0,0 +1,32 @@
+CREATE TABLE memos (
+content text
+);
+INSERT INTO memos VALUES ('Mroonga is a MySQL storage engine based on Groonga, the full text search engine.
+
+In MySQL 5.1 or later, Pluggable Storage Engine interface is introduced, and we can use custom storage engines easily. So we implement Mroonga, so that we can use Groonga through MySQL.
+
+By using Mroonga, you can use Groonga with SQL.');
+INSERT INTO memos VALUES ('Since Tritonn was the modified version of MySQL, we need to build it by ourselves or use binary files provided by Tritonn project, thus we cannot use the official binary files provided by MySQL.
+
+On the other hand, Mroonga is an independent program (shared library) using Pluggable Storage Engine interface, and we can dynamically load it on MySQL''s official binary. So we can use it more easily than Tritonn.');
+INSERT INTO memos VALUES ('Mroonga has two running modes.
+
+One is "storage mode", that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is "wrapper mode", that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga''s fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga''s read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.');
+SELECT mroonga_highlight_html(content, 'Mroonga') AS highlighted
+FROM memos;
+highlighted
+<span class="keyword">Mroonga</span> is a MySQL storage engine based on Groonga, the full text search engine.
+
+In MySQL 5.1 or later, Pluggable Storage Engine interface is introduced, and we can use custom storage engines easily. So we implement <span class="keyword">Mroonga</span>, so that we can use Groonga through MySQL.
+
+By using <span class="keyword">Mroonga</span>, you can use Groonga with SQL.
+Since Tritonn was the modified version of MySQL, we need to build it by ourselves or use binary files provided by Tritonn project, thus we cannot use the official binary files provided by MySQL.
+
+On the other hand, <span class="keyword">Mroonga</span> is an independent program (shared library) using Pluggable Storage Engine interface, and we can dynamically load it on MySQL's official binary. So we can use it more easily than Tritonn.
+<span class="keyword">Mroonga</span> has two running modes.
+
+One is &quot;storage mode&quot;, that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is &quot;wrapper mode&quot;, that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga's fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga's read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_grn_id.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_grn_id.result
new file mode 100644
index 00000000..42064b7f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_grn_id.result
@@ -0,0 +1,28 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, c1 int);
+select last_insert_grn_id();
+last_insert_grn_id()
+0
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+last_insert_grn_id()
+2
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+last_insert_grn_id()
+4
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+last_insert_grn_id()
+6
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+last_insert_grn_id()
+8
+select last_insert_grn_id(1);
+ERROR HY000: Can't initialize function 'last_insert_grn_id'; last_insert_grn_id must not have arguments
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_reference.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_reference.result
new file mode 100644
index 00000000..b0db86cb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_reference.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int AUTO_INCREMENT PRIMARY KEY
+);
+SELECT last_insert_id();
+last_insert_id()
+0
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+last_insert_id()
+1
+SELECT * FROM ids;
+id
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_set.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_set.result
new file mode 100644
index 00000000..ec6f2f98
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_last_insert_id_set.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int AUTO_INCREMENT PRIMARY KEY
+);
+SELECT last_insert_id();
+last_insert_id()
+0
+SELECT last_insert_id(10);
+last_insert_id(10)
+10
+SELECT last_insert_id();
+last_insert_id()
+10
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+last_insert_id()
+1
+SELECT * FROM ids;
+id
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_default.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_default.result
new file mode 100644
index 00000000..fe5cc885
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_default.result
@@ -0,0 +1,3 @@
+SELECT mroonga_normalize('aBcAbC㍑');
+mroonga_normalize('aBcAbC㍑')
+abcabcリットル
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_normalizer.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_normalizer.result
new file mode 100644
index 00000000..3d675fb0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_normalizer.result
@@ -0,0 +1,3 @@
+SELECT mroonga_normalize('aBcAbC㍑', "NormalizerAuto");
+mroonga_normalize('aBcAbC㍑', "NormalizerAuto")
+abcabcリットル
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_record.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_record.result
new file mode 100644
index 00000000..7d4192f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_normalize_record.result
@@ -0,0 +1,7 @@
+CREATE TABLE memos (
+content text
+);
+INSERT INTO memos VALUES ('aBcAbC㍑');
+SELECT mroonga_normalize(content) FROM memos;
+mroonga_normalize(content)
+abcabcリットル
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_multiple.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_multiple.result
new file mode 100644
index 00000000..9160633c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_multiple.result
@@ -0,0 +1,18 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS synonyms;
+CREATE TABLE synonyms (
+term varchar(255),
+synonym varchar(255),
+INDEX (term)
+);
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+INSERT INTO synonyms VALUES ('Mroonga', 'Mroonga');
+INSERT INTO synonyms VALUES ('Mroonga', 'Groonga MySQL');
+SELECT mroonga_query_expand('synonyms',
+'term',
+'synonym',
+'Mroonga Rroonga PGroonga') AS query;
+query
+((Mroonga) OR (Groonga MySQL)) ((Rroonga) OR (Groonga Ruby)) PGroonga
+DROP TABLE synonyms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_no_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_no_index.result
new file mode 100644
index 00000000..6a2b5d7a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_no_index.result
@@ -0,0 +1,15 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS synonyms;
+CREATE TABLE synonyms (
+term varchar(255),
+synonym varchar(255)
+);
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+SELECT mroonga_query_expand('synonyms',
+'term',
+'synonym',
+'Mroonga Rroonga PGroonga') AS query;
+query
+Mroonga ((Rroonga) OR (Groonga Ruby)) PGroonga
+DROP TABLE synonyms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_one.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_one.result
new file mode 100644
index 00000000..5f7b0f73
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_one.result
@@ -0,0 +1,16 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS synonyms;
+CREATE TABLE synonyms (
+term varchar(255),
+synonym varchar(255),
+INDEX (term)
+);
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+SELECT mroonga_query_expand('synonyms',
+'term',
+'synonym',
+'Mroonga Rroonga PGroonga') AS query;
+query
+Mroonga ((Rroonga) OR (Groonga Ruby)) PGroonga
+DROP TABLE synonyms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_pragma.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_pragma.result
new file mode 100644
index 00000000..4690cd01
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_query_expand_pragma.result
@@ -0,0 +1,17 @@
+SET NAMES UTF8;
+DROP TABLE IF EXISTS synonyms;
+CREATE TABLE synonyms (
+term varchar(255),
+synonym varchar(255),
+INDEX (term)
+);
+INSERT INTO synonyms VALUES ('D+', '[D+]');
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+SELECT mroonga_query_expand('synonyms',
+'term',
+'synonym',
+'*D+ Mroonga Rroonga PGroonga') AS query;
+query
+*D+ Mroonga ((Rroonga) OR (Groonga Ruby)) PGroonga
+DROP TABLE synonyms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_ascii.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_ascii.result
new file mode 100644
index 00000000..5766f822
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_ascii.result
@@ -0,0 +1,120 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3));
+insert into t1 values(1,10,"aa bb cc dd ee >< ff gg hh ii jj kk ll mm nn");
+insert into t1 values(2,20,"nn mm ll kk jj >< ii hh gg ff ee dd cc bb aa");
+insert into t1 values(3,30,"cc dd ee ff gg >< hh ii jj kk ll mm nn oo pp");
+insert into t1 values(4,40,"ee ff gg hh ii >< jj kk ll mm nn oo pp qq rr");
+insert into t1 values(5,50,"AA BB CC DD EE >< FF GG HH II JJ KK LL MM NN");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 0, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 0, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>')
+1 10 ...a<span class="w1"> bb</span> cc<span class="w3"> dd</span>...<br>
+...e &gt;&lt;<span class="w2"> ff</span> gg...<br>
+
+2 20 ...g<span class="w2"> ff</span> ee<span class="w3"> dd</span>...<br>
+... cc<span class="w1"> bb</span> aa...<br>
+
+3 30 ...c<span class="w3"> dd</span> ee<span class="w2"> ff</span>...<br>
+
+4 40 ...ee<span class="w2"> ff</span> gg h...<br>
+
+5 50 ...A<span class="w1"> BB</span> CC<span class="w3"> DD</span>...<br>
+...E &gt;&lt;<span class="w2"> FF</span> GG...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 0, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_bin', 0, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>')
+1 10 ... <span class="w1">bb</span> cc <span class="w3">dd</span> ...<br>
+... &gt;&lt; <span class="w2">ff</span> gg ...<br>
+
+2 20 ... <span class="w2">ff</span> ee <span class="w3">dd</span> ...<br>
+...cc <span class="w1">bb</span> aa...<br>
+
+3 30 ... <span class="w3">dd</span> ee <span class="w2">ff</span> ...<br>
+
+4 40 ...ee <span class="w2">ff</span> gg h...<br>
+
+5 50
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 1, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 1, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>')
+1 10 ... <span class="w1">bb</span> cc <span class="w3">dd</span> ...<br>
+... &gt;&lt; <span class="w2">ff</span> gg ...<br>
+
+2 20 ... <span class="w2">ff</span> ee <span class="w3">dd</span> ...<br>
+...cc <span class="w1">bb</span> aa...<br>
+
+3 30 ... <span class="w3">dd</span> ee <span class="w2">ff</span> ...<br>
+
+4 40 ...ee <span class="w2">ff</span> gg h...<br>
+
+5 50 ... <span class="w1">BB</span> CC <span class="w3">DD</span> ...<br>
+... &gt;&lt; <span class="w2">FF</span> GG ...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 1, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_bin', 1, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>')
+1 10 ... <span class="w1">bb</span> cc <span class="w3">dd</span> ...<br>
+... &gt;&lt; <span class="w2">ff</span> gg ...<br>
+
+2 20 ... <span class="w2">ff</span> ee <span class="w3">dd</span> ...<br>
+...cc <span class="w1">bb</span> aa...<br>
+
+3 30 ... <span class="w3">dd</span> ee <span class="w2">ff</span> ...<br>
+
+4 40 ...ee <span class="w2">ff</span> gg h...<br>
+
+5 50
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 0, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 0, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']')
+1 10 ...a(w1)[ bb] cc(w3)[ dd]...
+...e ><(w2)[ ff] gg...
+
+2 20 ...g(w2)[ ff] ee(w3)[ dd]...
+... cc(w1)[ bb] aa...
+
+3 30 ...c(w3)[ dd] ee(w2)[ ff]...
+
+4 40 ...ee(w2)[ ff] gg h...
+
+5 50 ...A(w1)[ BB] CC(w3)[ DD]...
+...E ><(w2)[ FF] GG...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 0, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_bin', 0, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']')
+1 10 ... (w1)[bb] cc (w3)[dd] ...
+... >< (w2)[ff] gg ...
+
+2 20 ... (w2)[ff] ee (w3)[dd] ...
+...cc (w1)[bb] aa...
+
+3 30 ... (w3)[dd] ee (w2)[ff] ...
+
+4 40 ...ee (w2)[ff] gg h...
+
+5 50
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 1, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 1, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']')
+1 10 ... (w1)[bb] cc (w3)[dd] ...
+... >< (w2)[ff] gg ...
+
+2 20 ... (w2)[ff] ee (w3)[dd] ...
+...cc (w1)[bb] aa...
+
+3 30 ... (w3)[dd] ee (w2)[ff] ...
+
+4 40 ...ee (w2)[ff] gg h...
+
+5 50 ... (w1)[BB] CC (w3)[DD] ...
+... >< (w2)[FF] GG ...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 1, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'ascii_bin', 1, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']')
+1 10 ... (w1)[bb] cc (w3)[dd] ...
+... >< (w2)[ff] gg ...
+
+2 20 ... (w2)[ff] ee (w3)[dd] ...
+...cc (w1)[bb] aa...
+
+3 30 ... (w3)[dd] ee (w2)[ff] ...
+
+4 40 ...ee (w2)[ff] gg h...
+
+5 50
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_cp932.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_cp932.result
new file mode 100644
index 00000000..a21157a0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_cp932.result
@@ -0,0 +1,91 @@
+drop table if exists t1, t2, t3;
+set names cp932;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset cp932;
+insert into t1 values(1, "","QX̕xmR̓VCɂ‚");
+insert into t1 values(2, "","QX̕xmR̓VC͕܂");
+insert into t1 values(3, "","29̕xmR̓VCɂ‚");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 0, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 0, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>')
+1 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>ɂ...<br>
+
+2 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>͕...<br>
+
+3 ...<span class="w1">29</span>̕xm...<br>
+...<span class="w2">VC</span>ɂ...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 0, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_bin', 0, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>')
+1 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>ɂ...<br>
+
+2 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>͕...<br>
+
+3 ...<span class="w3">xmR</span>...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 1, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 1, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>')
+1 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>ɂ...<br>
+
+2 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>͕...<br>
+
+3 ...<span class="w1">29</span>̕xm...<br>
+...<span class="w2">VC</span>ɂ...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 1, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_bin', 1, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>')
+1 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>ɂ...<br>
+
+2 ...<span class="w1">QX</span>̕x...<br>
+...<span class="w2">VC</span>͕...<br>
+
+3 ...<span class="w3">xmR</span>...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 0, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 0, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']')
+1 ...(w1)[QX]̕x...
+...(w2)[VC]ɂ...
+
+2 ...(w1)[QX]̕x...
+...(w2)[VC]͕...
+
+3 ...(w1)[29]̕xm...
+...(w2)[VC]ɂ...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 0, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_bin', 0, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']')
+1 ...(w1)[QX]̕x...
+...(w2)[VC]ɂ...
+
+2 ...(w1)[QX]̕x...
+...(w2)[VC]͕...
+
+3 ...(w3)[xmR]...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 1, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 1, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']')
+1 ...(w1)[QX]̕x...
+...(w2)[VC]ɂ...
+
+2 ...(w1)[QX]̕x...
+...(w2)[VC]͕...
+
+3 ...(w1)[29]̕xm...
+...(w2)[VC]ɂ...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 1, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'cp932_bin', 1, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']')
+1 ...(w1)[QX]̕x...
+...(w2)[VC]ɂ...
+
+2 ...(w1)[QX]̕x...
+...(w2)[VC]͕...
+
+3 ...(w3)[xmR]...
+
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_eucjpms.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_eucjpms.result
new file mode 100644
index 00000000..e4c6a417
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_eucjpms.result
@@ -0,0 +1,91 @@
+drop table if exists t1, t2, t3;
+set names eucjpms;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset eucjpms;
+insert into t1 values(1, "","ٻλŷˤĤ");
+insert into t1 values(2, "","ٻλŷʬޤ");
+insert into t1 values(3, "","29ٻλŷˤĤ");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 0, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 0, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>')
+1 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ˤ...<br>
+
+2 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ʬ...<br>
+
+3 ...<span class="w1">29</span>ٻ...<br>
+...<span class="w2">ŷ</span>ˤ...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 0, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 0, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>')
+1 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ˤ...<br>
+
+2 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ʬ...<br>
+
+3 ...<span class="w3">ٻλ</span>...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 1, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 1, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>')
+1 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ˤ...<br>
+
+2 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ʬ...<br>
+
+3 ...<span class="w1">29</span>ٻ...<br>
+...<span class="w2">ŷ</span>ˤ...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 1, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 1, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>')
+1 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ˤ...<br>
+
+2 ...<span class="w1"></span>...<br>
+...<span class="w2">ŷ</span>ʬ...<br>
+
+3 ...<span class="w3">ٻλ</span>...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 0, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 0, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']')
+1 ...(w1)[]...
+...(w2)[ŷ]ˤ...
+
+2 ...(w1)[]...
+...(w2)[ŷ]ʬ...
+
+3 ...(w1)[29]ٻ...
+...(w2)[ŷ]ˤ...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 0, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 0, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']')
+1 ...(w1)[]...
+...(w2)[ŷ]ˤ...
+
+2 ...(w1)[]...
+...(w2)[ŷ]ʬ...
+
+3 ...(w3)[ٻλ]...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 1, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 1, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']')
+1 ...(w1)[]...
+...(w2)[ŷ]ˤ...
+
+2 ...(w1)[]...
+...(w2)[ŷ]ʬ...
+
+3 ...(w1)[29]ٻ...
+...(w2)[ŷ]ˤ...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 1, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 1, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']')
+1 ...(w1)[]...
+...(w2)[ŷ]ˤ...
+
+2 ...(w1)[]...
+...(w2)[ŷ]ʬ...
+
+3 ...(w3)[ٻλ]...
+
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_dynamic_keyword.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_dynamic_keyword.result
new file mode 100644
index 00000000..24665fbf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_dynamic_keyword.result
@@ -0,0 +1,11 @@
+CREATE TABLE keywords (
+keyword text
+);
+INSERT INTO keywords VALUES ('Mroonga');
+INSERT INTO keywords VALUES ('Groonga');
+SELECT mroonga_snippet_html('Mroonga is the Groonga based storage engine.',
+keyword) as snippet
+FROM keywords;
+snippet
+<div class="snippet"><span class="keyword">Mroonga</span> is the Groonga based storage engine.</div>
+<div class="snippet">Mroonga is the <span class="keyword">Groonga</span> based storage engine.</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_japanese.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_japanese.result
new file mode 100644
index 00000000..f1efa42c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_japanese.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+SELECT mroonga_snippet_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+'ロック', '更新') as snippet;
+snippet
+<div class="snippet">がデフォルトのモードです。上述の参照<span class="keyword">ロック</span>フリーなGroongaの性能特性をフルに活かした高速なデータ<span class="keyword">更新</span>・全文検索・位置情報検索が特長です。</div><div class="snippet">用することができます。一方、Groongaの参照<span class="keyword">ロック</span>フリーな特性は活かすことができません。また、<span class="keyword">更新</span>処理は他のストレージエンジンがボトルネッ</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_keywords.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_keywords.result
new file mode 100644
index 00000000..013ad5b1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_keywords.result
@@ -0,0 +1,4 @@
+SELECT mroonga_snippet_html('Mroonga is the Groonga based storage engine.',
+'Mroonga', 'Groonga') as snippet;
+snippet
+<div class="snippet"><span class="keyword">Mroonga</span> is the <span class="keyword">Groonga</span> based storage engine.</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_snippets.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_snippets.result
new file mode 100644
index 00000000..d3f790b3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_multiple_snippets.result
@@ -0,0 +1,10 @@
+SELECT mroonga_snippet_html('Mroonga has two running modes.
+
+One is "storage mode", that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is "wrapper mode", that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga''s fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga''s read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.',
+'lock') as snippet;
+snippet
+<div class="snippet">ng. With this mode, you can have full benefits of Groonga described above, like fast data update, <span class="keyword">lock</span>-free full text search and geolocation search. But it does not support transactions.
+
+Another one </div><div class="snippet">f the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga's read-<span class="keyword">lock</span> free characteristic. And you might have the performance bottle neck in the storage engine in upda</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query.result
new file mode 100644
index 00000000..d05c2323
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+SELECT mroonga_snippet_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+'ロック 更新 -ボトルネック' AS query) as snippet;
+snippet
+<div class="snippet">がデフォルトのモードです。上述の参照<span class="keyword">ロック</span>フリーなGroongaの性能特性をフルに活かした高速なデータ<span class="keyword">更新</span>・全文検索・位置情報検索が特長です。</div><div class="snippet">用することができます。一方、Groongaの参照<span class="keyword">ロック</span>フリーな特性は活かすことができません。また、<span class="keyword">更新</span>処理は他のストレージエンジンがボトルネッ</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query_pragma.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query_pragma.result
new file mode 100644
index 00000000..02ce9098
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_query_pragma.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+SELECT mroonga_snippet_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+'*D- +ロック +更新 ボトルネック' AS query) as snippet;
+snippet
+<div class="snippet">がデフォルトのモードです。上述の参照<span class="keyword">ロック</span>フリーなGroongaの性能特性をフルに活かした高速なデータ<span class="keyword">更新</span>・全文検索・位置情報検索が特長です。</div><div class="snippet">用することができます。一方、Groongaの参照<span class="keyword">ロック</span>フリーな特性は活かすことができません。また、<span class="keyword">更新</span>処理は他のストレージエンジンがボトルネッ</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_record.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_record.result
new file mode 100644
index 00000000..469defbc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_html_record.result
@@ -0,0 +1,30 @@
+CREATE TABLE memos (
+content text
+);
+INSERT INTO memos VALUES ('Mroonga is a MySQL storage engine based on Groonga, the full text search engine.
+
+In MySQL 5.1 or later, Pluggable Storage Engine interface is introduced, and we can use custom storage engines easily. So we implement Mroonga, so that we can use Groonga through MySQL.
+
+By using Mroonga, you can use Groonga with SQL.');
+INSERT INTO memos VALUES ('Since Tritonn was the modified version of MySQL, we need to build it by ourselves or use binary files provided by Tritonn project, thus we cannot use the official binary files provided by MySQL.
+
+On the other hand, Mroonga is an independent program (shared library) using Pluggable Storage Engine interface, and we can dynamically load it on MySQL''s official binary. So we can use it more easily than Tritonn.');
+INSERT INTO memos VALUES ('Mroonga has two running modes.
+
+One is "storage mode", that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is "wrapper mode", that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga''s fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga''s read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.');
+SELECT mroonga_snippet_html(content, 'Mroonga') as snippet
+FROM memos;
+snippet
+<div class="snippet"><span class="keyword">Mroonga</span> is a MySQL storage engine based on Groonga, the full text search engine.
+
+In MySQL 5.1 or later, Pluggable Storage Engine interface is introduced, and we can use custom storage engines easily.</div><div class="snippet"> So we implement <span class="keyword">Mroonga</span>, so that we can use Groonga through MySQL.
+
+By using <span class="keyword">Mroonga</span>, you can use Groonga with SQL.</div>
+<div class="snippet">onn project, thus we cannot use the official binary files provided by MySQL.
+
+On the other hand, <span class="keyword">Mroonga</span> is an independent program (shared library) using Pluggable Storage Engine interface, and we can</div>
+<div class="snippet"><span class="keyword">Mroonga</span> has two running modes.
+
+One is &quot;storage mode&quot;, that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described</div>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_nonexistent_charset.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_nonexistent_charset.result
new file mode 100644
index 00000000..78cee626
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_nonexistent_charset.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_snippet("Invalid charset test", 10, 2, "nonexistent_charset",
+1, 0, "...", "...", "charset", "<", ">");
+ERROR HY000: Can't initialize function 'mroonga_snippet'; Unknown charset: <nonexistent_charset>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_unsupported_charset.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_unsupported_charset.result
new file mode 100644
index 00000000..bf967adb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_invalid_unsupported_charset.result
@@ -0,0 +1,4 @@
+SET NAMES UTF8;
+SELECT mroonga_snippet("Unsuppported charset test", 10, 2, "big5",
+1, 0, "...", "...", "charset", "<", ">");
+ERROR HY000: Can't initialize function 'mroonga_snippet'; Unknown charset: <big5>
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_japanese.result b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_japanese.result
new file mode 100644
index 00000000..05a63a3d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/function_snippet_japanese.result
@@ -0,0 +1,95 @@
+drop table if exists t1, t2, t3;
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8;
+insert into t1 values(1, "あああああ","29日の富士山の天気について");
+insert into t1 values(2, "いいいいい","29日の富士山の天気は分かりません");
+insert into t1 values(3, "ううううう","29日の富士山の天気について");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 0, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 0, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>')
+1 あああああ ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+2 いいいいい ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+3 ううううう ...<span class="w1">29日</span>の...<br>
+...<span class="w2">天気</span>に...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 0, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_bin', 0, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>')
+1 あああああ ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+2 いいいいい ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+3 ううううう ...<span class="w3">富士山</span>...<br>
+...<span class="w2">天気</span>に...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 1, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 1, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>')
+1 あああああ ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+2 いいいいい ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+3 ううううう ...<span class="w1">29日</span>の...<br>
+...<span class="w2">天気</span>に...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 1, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_bin', 1, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>')
+1 あああああ ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+2 いいいいい ...<span class="w1">29日</span>...<br>
+...<span class="w3">富士山</span>...<br>
+
+3 ううううう ...<span class="w3">富士山</span>...<br>
+...<span class="w2">天気</span>に...<br>
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 0, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 0, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']')
+1 あああああ ...(w1)[29日]...
+...(w3)[富士山]...
+
+2 いいいいい ...(w1)[29日]...
+...(w3)[富士山]...
+
+3 ううううう ...(w1)[29日]の...
+...(w2)[天気]に...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 0, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_bin', 0, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']')
+1 あああああ ...(w1)[29日]...
+...(w3)[富士山]...
+
+2 いいいいい ...(w1)[29日]...
+...(w3)[富士山]...
+
+3 ううううう ...(w3)[富士山]...
+...(w2)[天気]に...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 1, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 1, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']')
+1 あああああ ...(w1)[29日]...
+...(w3)[富士山]...
+
+2 いいいいい ...(w1)[29日]...
+...(w3)[富士山]...
+
+3 ううううう ...(w1)[29日]の...
+...(w2)[天気]に...
+
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 1, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+c1 c2 mroonga_snippet(c3, 10, 2, 'utf8_bin', 1, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']')
+1 あああああ ...(w1)[29日]...
+...(w3)[富士山]...
+
+2 いいいいい ...(w1)[29日]...
+...(w3)[富士山]...
+
+3 ううううう ...(w3)[富士山]...
+...(w2)[天気]に...
+
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/geometry_bulk_insert_null.result b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_bulk_insert_null.result
new file mode 100644
index 00000000..fc16c590
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_bulk_insert_null.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS shops;
+CREATE TABLE shops (
+location GEOMETRY NOT NULL
+);
+INSERT IGNORE INTO shops VALUES (NULL), (NULL);
+Warnings:
+Warning 1048 Column 'location' cannot be null
+Warning 1048 Column 'location' cannot be null
+SELECT ST_AsText(location) FROM shops;
+ST_AsText(location)
+POINT(0 0)
+POINT(0 0)
+DROP TABLE shops;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/geometry_contains.result b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_contains.result
new file mode 100644
index 00000000..5095232d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_contains.result
@@ -0,0 +1,167 @@
+DROP TABLE IF EXISTS shops;
+CREATE TABLE shops (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name TEXT,
+location GEOMETRY NOT NULL,
+SPATIAL KEY location_index (location)
+);
+INSERT INTO shops (name, location)
+VALUES ('nezu-no-taiyaki',
+ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+VALUES ('taiyaki-kataoka',
+ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+VALUES ('soba-taiyaki-ku',
+ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+VALUES ('kuruma',
+ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+VALUES ('hirose-ya',
+ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+VALUES ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+VALUES ('omede-taiyaki',
+ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+VALUES ('onaga-ya',
+ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+VALUES ('shiro-ya',
+ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+VALUES ('fuji-ya',
+ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+VALUES ('miyoshi',
+ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+VALUES ('juju-ya',
+ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+VALUES ('tatsumi-ya',
+ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+VALUES ('tetsuji',
+ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+VALUES ('gazuma-ya',
+ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+VALUES ('honma-mon',
+ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+VALUES ('naniwa-ya',
+ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+VALUES ('kuro-dai',
+ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+VALUES ('daruma',
+ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+VALUES ('yanagi-ya',
+ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+VALUES ('sharaku',
+ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+VALUES ('takane',
+ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+VALUES ('chiyoda',
+ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+VALUES ('da-ka-po',
+ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+VALUES ('matsushima-ya',
+ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+VALUES ('kazuya',
+ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+VALUES ('furuya-kogane-an',
+ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+VALUES ('hachi-no-ie',
+ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+VALUES ('azuki-chan',
+ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+VALUES ('kuriko-an',
+ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+VALUES ('naze-ya',
+ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+VALUES ('sanoki-ya',
+ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+VALUES ('shigeta',
+ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+VALUES ('nishimi-ya',
+ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+VALUES ('hiiragi',
+ST_GeomFromText('POINT(139.711517 35.647701)'));
+SELECT id, name, ST_AsText(location) AS location_text FROM shops;
+id name location_text
+1 nezu-no-taiyaki POINT(139.76257305555555 35.72025305555556)
+2 taiyaki-kataoka POINT(139.7155911111111 35.712521111111116)
+3 soba-taiyaki-ku POINT(139.65908805555557 35.68371194444445)
+4 kuruma POINT(139.70620694444446 35.72151611111111)
+5 hirose-ya POINT(139.68560805555555 35.71484388888889)
+6 sazare POINT(139.68504305555555 35.71465305555556)
+7 omede-taiyaki POINT(139.8171538888889 35.70051611111111)
+8 onaga-ya POINT(139.81105 35.69825388888889)
+9 shiro-ya POINT(139.63861111111112 35.70551694444445)
+10 fuji-ya POINT(139.637115 35.703938055555554)
+11 miyoshi POINT(139.53732305555556 35.644538888888896)
+12 juju-ya POINT(139.69575500000002 35.62892194444445)
+13 tatsumi-ya POINT(139.63865694444445 35.66550111111111)
+14 tetsuji POINT(139.76857 35.680911944444446)
+15 gazuma-ya POINT(139.64759805555553 35.70081694444444)
+16 honma-mon POINT(139.65257305555556 35.72273611111111)
+17 naniwa-ya POINT(139.79623388888888 35.73006111111111)
+18 kuro-dai POINT(139.70483388888888 35.650345)
+19 daruma POINT(139.7705988888889 35.68146111111111)
+20 yanagi-ya POINT(139.78398111111113 35.685341111111114)
+21 sharaku POINT(139.79484611111113 35.71696888888889)
+22 takane POINT(139.56091305555555 35.69860111111112)
+23 chiyoda POINT(139.65281694444442 35.64260111111111)
+24 da-ka-po POINT(139.72735611111113 35.62734611111111)
+25 matsushima-ya POINT(139.73738111111112 35.64055611111111)
+26 kazuya POINT(139.760895 35.67350805555556)
+27 furuya-kogane-an POINT(139.67607111111113 35.68060305555556)
+28 hachi-no-ie POINT(139.66810611111111 35.608021111111114)
+29 azuki-chan POINT(139.67320305555555 35.641510000000004)
+30 kuriko-an POINT(139.79682888888888 35.71201305555556)
+31 yume-no-aru-machi-no-taiyaki-ya-san POINT(139.71252388888888 35.61619888888889)
+32 naze-ya POINT(139.66583305555557 35.60903888888889)
+33 sanoki-ya POINT(139.7707211111111 35.66592)
+34 shigeta POINT(139.78027305555557 35.67262611111111)
+35 nishimi-ya POINT(139.77462805555555 35.671825)
+36 hiiragi POINT(139.71151694444444 35.64770111111111)
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ORDER BY id;
+id name location_text
+14 tetsuji POINT(139.76857 35.680911944444446)
+19 daruma POINT(139.7705988888889 35.68146111111111)
+26 kazuya POINT(139.760895 35.67350805555556)
+EXPLAIN
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ORDER BY id;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE shops range location_index location_index 34 NULL 36 Using where; Using filesort
+DROP TABLE shops;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_bulk_insert_null.result b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_bulk_insert_null.result
new file mode 100644
index 00000000..73573355
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_bulk_insert_null.result
@@ -0,0 +1,9 @@
+DROP TABLE IF EXISTS shops;
+CREATE TABLE shops (
+location GEOMETRY NOT NULL
+);
+INSERT INTO shops VALUES (NULL), (NULL);
+ERROR 23000: Column 'location' cannot be null
+SELECT ST_AsText(location) FROM shops;
+ST_AsText(location)
+DROP TABLE shops;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_contains.result b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_contains.result
new file mode 100644
index 00000000..2f432fc8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/geometry_strict_sql_mode_contains.result
@@ -0,0 +1,169 @@
+DROP TABLE IF EXISTS shops;
+CREATE TABLE shops (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name TEXT,
+location GEOMETRY NOT NULL,
+SPATIAL KEY location_index (location)
+);
+INSERT INTO shops (name, location)
+VALUES ('nezu-no-taiyaki',
+ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+VALUES ('taiyaki-kataoka',
+ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+VALUES ('soba-taiyaki-ku',
+ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+VALUES ('kuruma',
+ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+VALUES ('hirose-ya',
+ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+VALUES ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+VALUES ('omede-taiyaki',
+ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+VALUES ('onaga-ya',
+ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+VALUES ('shiro-ya',
+ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+VALUES ('fuji-ya',
+ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+VALUES ('miyoshi',
+ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+VALUES ('juju-ya',
+ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+VALUES ('tatsumi-ya',
+ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+VALUES ('tetsuji',
+ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+VALUES ('gazuma-ya',
+ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+VALUES ('honma-mon',
+ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+VALUES ('naniwa-ya',
+ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+VALUES ('kuro-dai',
+ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+VALUES ('daruma',
+ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+VALUES ('yanagi-ya',
+ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+VALUES ('sharaku',
+ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+VALUES ('takane',
+ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+VALUES ('chiyoda',
+ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+VALUES ('da-ka-po',
+ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+VALUES ('matsushima-ya',
+ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+VALUES ('kazuya',
+ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+VALUES ('furuya-kogane-an',
+ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+VALUES ('hachi-no-ie',
+ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+VALUES ('azuki-chan',
+ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+VALUES ('kuriko-an',
+ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+VALUES ('naze-ya',
+ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+VALUES ('sanoki-ya',
+ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+VALUES ('shigeta',
+ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+VALUES ('nishimi-ya',
+ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+VALUES ('hiiragi',
+ST_GeomFromText('POINT(139.711517 35.647701)'));
+SELECT id, name, ST_AsText(location) AS location_text FROM shops;
+id name location_text
+1 nezu-no-taiyaki POINT(139.76257305555555 35.72025305555556)
+2 taiyaki-kataoka POINT(139.7155911111111 35.712521111111116)
+3 soba-taiyaki-ku POINT(139.65908805555557 35.68371194444445)
+4 kuruma POINT(139.70620694444446 35.72151611111111)
+5 hirose-ya POINT(139.68560805555555 35.71484388888889)
+6 sazare POINT(139.68504305555555 35.71465305555556)
+7 omede-taiyaki POINT(139.8171538888889 35.70051611111111)
+8 onaga-ya POINT(139.81105 35.69825388888889)
+9 shiro-ya POINT(139.63861111111112 35.70551694444445)
+10 fuji-ya POINT(139.637115 35.703938055555554)
+11 miyoshi POINT(139.53732305555556 35.644538888888896)
+12 juju-ya POINT(139.69575500000002 35.62892194444445)
+13 tatsumi-ya POINT(139.63865694444445 35.66550111111111)
+14 tetsuji POINT(139.76857 35.680911944444446)
+15 gazuma-ya POINT(139.64759805555553 35.70081694444444)
+16 honma-mon POINT(139.65257305555556 35.72273611111111)
+17 naniwa-ya POINT(139.79623388888888 35.73006111111111)
+18 kuro-dai POINT(139.70483388888888 35.650345)
+19 daruma POINT(139.7705988888889 35.68146111111111)
+20 yanagi-ya POINT(139.78398111111113 35.685341111111114)
+21 sharaku POINT(139.79484611111113 35.71696888888889)
+22 takane POINT(139.56091305555555 35.69860111111112)
+23 chiyoda POINT(139.65281694444442 35.64260111111111)
+24 da-ka-po POINT(139.72735611111113 35.62734611111111)
+25 matsushima-ya POINT(139.73738111111112 35.64055611111111)
+26 kazuya POINT(139.760895 35.67350805555556)
+27 furuya-kogane-an POINT(139.67607111111113 35.68060305555556)
+28 hachi-no-ie POINT(139.66810611111111 35.608021111111114)
+29 azuki-chan POINT(139.67320305555555 35.641510000000004)
+30 kuriko-an POINT(139.79682888888888 35.71201305555556)
+31 yume-no-aru-machi-no-taiyaki-ya-san POINT(139.71252388888888 35.61619888888889)
+32 naze-ya POINT(139.66583305555557 35.60903888888889)
+33 sanoki-ya POINT(139.7707211111111 35.66592)
+34 shigeta POINT(139.78027305555557 35.67262611111111)
+35 nishimi-ya POINT(139.77462805555555 35.671825)
+36 hiiragi POINT(139.71151694444444 35.64770111111111)
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ORDER BY id;
+id name location_text
+14 tetsuji POINT(139.76857 35.680911944444446)
+19 daruma POINT(139.7705988888889 35.68146111111111)
+26 kazuya POINT(139.760895 35.67350805555556)
+EXPLAIN
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ORDER BY id;
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE shops NULL range location_index location_index 34 NULL 36 100.00 Using where; Using filesort
+Warnings:
+Note 1003 /* select#1 */ select `test`.`shops`.`id` AS `id`,`test`.`shops`.`name` AS `name`,st_astext(`test`.`shops`.`location`) AS `location_text` from `test`.`shops` where mbrcontains(<cache>(st_geometryfromtext('LineString(139.7727 35.6684, 139.7038 35.7121)')),`test`.`shops`.`location`) order by `test`.`shops`.`id`
+DROP TABLE shops;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/i_s.result b/storage/mroonga/mysql-test/mroonga/storage/r/i_s.result
new file mode 100644
index 00000000..c122b952
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/i_s.result
@@ -0,0 +1,7 @@
+SHOW CREATE TABLE INFORMATION_SCHEMA.MROONGA_STATS;
+Table Create Table
+Mroonga_stats CREATE TEMPORARY TABLE `Mroonga_stats` (
+ `VERSION` varchar(40) NOT NULL,
+ `rows_written` int(11) NOT NULL,
+ `rows_read` int(11) NOT NULL
+) ENGINE=MEMORY DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_datetime.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_datetime.result
new file mode 100644
index 00000000..78ed69f0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_datetime.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+created_at datetime,
+title varchar(256),
+KEY created_at_key(created_at)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES ("1000-01-01 00:00:00", "The start");
+INSERT INTO diaries VALUES ("2012-10-25 16:18:29", "Today is shiny day.");
+INSERT INTO diaries VALUES ("9999-12-31 23:59:59", "The end");
+SELECT *
+FROM diaries FORCE INDEX(created_at_key)
+WHERE created_at = "2012-10-25 16:18:29";
+created_at title
+2012-10-25 16:18:29 Today is shiny day.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_time.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_time.result
new file mode 100644
index 00000000..a55a184d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_time.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS timer;
+CREATE TABLE timer (
+id int PRIMARY KEY,
+elapsed time,
+KEY elapsed_key(elapsed)
+);
+INSERT INTO timer VALUES (1, "00:00:00");
+INSERT INTO timer VALUES (2, "15:11:12");
+INSERT INTO timer VALUES (3, "838:59:59");
+INSERT INTO timer VALUES (4, "-838:59:59");
+SELECT *
+FROM timer FORCE INDEX(elapsed_key)
+WHERE elapsed = "-838:59:59";
+id elapsed
+4 -838:59:59
+DROP TABLE timer;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_timestamp.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_timestamp.result
new file mode 100644
index 00000000..57eb6ae2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_equal_timestamp.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+created_at timestamp,
+title varchar(256),
+KEY created_at_key(created_at)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES ("1970-01-01 12:00:00", "The start");
+INSERT INTO diaries VALUES ("2012-10-05 16:18:29", "Today is shiny day.");
+INSERT INTO diaries VALUES ("2038-01-18 15:14:07", "The end");
+SELECT *
+FROM diaries FORCE INDEX(created_at_key)
+WHERE created_at = "2012-10-05 16:18:29";
+created_at title
+2012-10-05 16:18:29 Today is shiny day.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_normal_column_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_normal_column_insert.result
new file mode 100644
index 00000000..72ba7336
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_btree_normal_column_insert.result
@@ -0,0 +1,25 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, index using btree (c2));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL,
+ `c2` int(11) DEFAULT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `c2` (`c2`) USING BTREE
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+flush tables;
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_normal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_normal.result
new file mode 100644
index 00000000..5f92c086
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_normal.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, a int, key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+_id a
+1 100
+2 100
+3 100
+4 100
+select * from t1 where _id = 2;
+_id a
+2 100
+select * from t1 where _id = 20;
+_id a
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_primary.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_primary.result
new file mode 100644
index 00000000..b0bbaf09
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_primary.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (_id int, a int, PRIMARY KEY (_id) USING HASH);
+INSERT INTO t1 VALUES(null, 100);
+ERROR 23000: Column '_id' cannot be null
+INSERT INTO t1 VALUES(1,100);
+Warnings:
+Warning 1265 Data truncated for column '_id' at row 1
+INSERT INTO t1 VALUES(1,100);
+Warnings:
+Warning 1265 Data truncated for column '_id' at row 1
+INSERT INTO t1 VALUES(1,100);
+Warnings:
+Warning 1265 Data truncated for column '_id' at row 1
+INSERT INTO t1 VALUES(1,100);
+Warnings:
+Warning 1265 Data truncated for column '_id' at row 1
+SELECT * FROM t1;
+_id a
+1 100
+2 100
+3 100
+4 100
+SELECT * FROM t1 WHERE _id = 2;
+_id a
+2 100
+SELECT * FROM t1 WHERE _id = 20;
+_id a
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_unique.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_unique.result
new file mode 100644
index 00000000..1a30a1ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_id_unique.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, a int, unique key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+_id a
+1 100
+2 100
+3 100
+4 100
+select * from t1 where _id = 2;
+_id a
+2 100
+select * from t1 where _id = 20;
+_id a
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_normal_column_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_normal_column_insert.result
new file mode 100644
index 00000000..a9c3dbfe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_normal_column_insert.result
@@ -0,0 +1,25 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, index using hash (c2));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL,
+ `c2` int(11) DEFAULT NULL,
+ PRIMARY KEY (`c1`),
+ KEY `c2` (`c2`) USING HASH
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+flush tables;
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_strict_sql_mode_id_primary.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_strict_sql_mode_id_primary.result
new file mode 100644
index 00000000..8fb46156
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_hash_strict_sql_mode_id_primary.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (_id int, a int, PRIMARY KEY (_id) USING HASH);
+INSERT INTO t1 VALUES(null, 100);
+ERROR 23000: Column '_id' cannot be null
+INSERT INTO t1 VALUES(1,100);
+ERROR 01000: Data truncated for column '_id' at row 1
+INSERT INTO t1 VALUES(1,100);
+ERROR 01000: Data truncated for column '_id' at row 1
+INSERT INTO t1 VALUES(1,100);
+ERROR 01000: Data truncated for column '_id' at row 1
+INSERT INTO t1 VALUES(1,100);
+ERROR 01000: Data truncated for column '_id' at row 1
+SELECT * FROM t1;
+_id a
+SELECT * FROM t1 WHERE _id = 2;
+_id a
+SELECT * FROM t1 WHERE _id = 20;
+_id a
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_delete.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_delete.result
new file mode 100644
index 00000000..ec18eb22
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_delete.result
@@ -0,0 +1,32 @@
+drop table if exists listing;
+set names utf8;
+create table scores (
+id int primary key auto_increment not null,
+name char(30) not null,
+score int not null,
+index property (name, score)
+) default charset utf8;
+show create table scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `property` (`name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+id name score
+1 Taro Yamada 29
+2 Taro Yamada -12
+3 Jiro Yamada 27
+4 Taro Yamada 10
+delete from scores where name = "Taro Yamada" and score = 10;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+id name score
+2 Taro Yamada -12
+drop table scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_smallint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_smallint.result
new file mode 100644
index 00000000..fec0aa47
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_smallint.result
@@ -0,0 +1,65 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+id INT PRIMARY KEY AUTO_INCREMENT,
+c1 SMALLINT,
+c2 SMALLINT,
+KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `c1` smallint(6) DEFAULT NULL,
+ `c2` smallint(6) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx1` (`c1`,`c2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO t1 (c1, c2) VALUES
+(1999, 12),
+(2000, 11),
+(2001, 10),
+(2002, 9),
+(2003, 8),
+(2004, 7),
+(2005, 6),
+(2006, 5),
+(2007, 4),
+(2008, 3),
+(2009, 2),
+(2010, 1);
+SELECT * FROM t1 WHERE c1 > 2005;
+id c1 c2
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 >= 2005;
+id c1 c2
+7 2005 6
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 = 2005;
+id c1 c2
+7 2005 6
+SELECT * FROM t1 WHERE c1 <= 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+7 2005 6
+SELECT * FROM t1 WHERE c1 < 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_bigint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_bigint.result
new file mode 100644
index 00000000..4a16031b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_bigint.result
@@ -0,0 +1,65 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+id INT PRIMARY KEY AUTO_INCREMENT,
+c1 BIGINT UNSIGNED,
+c2 BIGINT UNSIGNED,
+KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `c1` bigint(20) unsigned DEFAULT NULL,
+ `c2` bigint(20) unsigned DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx1` (`c1`,`c2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO t1 (c1, c2) VALUES
+(1999, 12),
+(2000, 11),
+(2001, 10),
+(2002, 9),
+(2003, 8),
+(2004, 7),
+(2005, 6),
+(2006, 5),
+(2007, 4),
+(2008, 3),
+(2009, 2),
+(2010, 1);
+SELECT * FROM t1 WHERE c1 > 2005;
+id c1 c2
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 >= 2005;
+id c1 c2
+7 2005 6
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 = 2005;
+id c1 c2
+7 2005 6
+SELECT * FROM t1 WHERE c1 <= 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+7 2005 6
+SELECT * FROM t1 WHERE c1 < 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_int.result
new file mode 100644
index 00000000..a3ede5e7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_int.result
@@ -0,0 +1,65 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+id INT PRIMARY KEY AUTO_INCREMENT,
+c1 INT UNSIGNED,
+c2 INT UNSIGNED,
+KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `c1` int(10) unsigned DEFAULT NULL,
+ `c2` int(10) unsigned DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx1` (`c1`,`c2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO t1 (c1, c2) VALUES
+(1999, 12),
+(2000, 11),
+(2001, 10),
+(2002, 9),
+(2003, 8),
+(2004, 7),
+(2005, 6),
+(2006, 5),
+(2007, 4),
+(2008, 3),
+(2009, 2),
+(2010, 1);
+SELECT * FROM t1 WHERE c1 > 2005;
+id c1 c2
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 >= 2005;
+id c1 c2
+7 2005 6
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 = 2005;
+id c1 c2
+7 2005 6
+SELECT * FROM t1 WHERE c1 <= 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+7 2005 6
+SELECT * FROM t1 WHERE c1 < 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_smallint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_smallint.result
new file mode 100644
index 00000000..aa752b5c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_unsigned_smallint.result
@@ -0,0 +1,65 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+id INT PRIMARY KEY AUTO_INCREMENT,
+c1 SMALLINT UNSIGNED,
+c2 SMALLINT UNSIGNED,
+KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `c1` smallint(5) unsigned DEFAULT NULL,
+ `c2` smallint(5) unsigned DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx1` (`c1`,`c2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO t1 (c1, c2) VALUES
+(1999, 12),
+(2000, 11),
+(2001, 10),
+(2002, 9),
+(2003, 8),
+(2004, 7),
+(2005, 6),
+(2006, 5),
+(2007, 4),
+(2008, 3),
+(2009, 2),
+(2010, 1);
+SELECT * FROM t1 WHERE c1 > 2005;
+id c1 c2
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 >= 2005;
+id c1 c2
+7 2005 6
+8 2006 5
+9 2007 4
+10 2008 3
+11 2009 2
+12 2010 1
+SELECT * FROM t1 WHERE c1 = 2005;
+id c1 c2
+7 2005 6
+SELECT * FROM t1 WHERE c1 <= 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+7 2005 6
+SELECT * FROM t1 WHERE c1 < 2005;
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 9
+5 2003 8
+6 2004 7
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_varchar.result
new file mode 100644
index 00000000..8fb207bc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_nullable_varchar.result
@@ -0,0 +1,65 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+id INT PRIMARY KEY AUTO_INCREMENT,
+c1 VARCHAR(10),
+c2 VARCHAR(10),
+KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `c1` varchar(10) DEFAULT NULL,
+ `c2` varchar(10) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `idx1` (`c1`,`c2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO t1 (c1, c2) VALUES
+('1999', '12'),
+('2000', '11'),
+('2001', '10'),
+('2002', '09'),
+('2003', '08'),
+('2004', '07'),
+('2005', '06'),
+('2006', '05'),
+('2007', '04'),
+('2008', '03'),
+('2009', '02'),
+('2010', '01');
+SELECT * FROM t1 WHERE c1 > '2005';
+id c1 c2
+8 2006 05
+9 2007 04
+10 2008 03
+11 2009 02
+12 2010 01
+SELECT * FROM t1 WHERE c1 >= '2005';
+id c1 c2
+7 2005 06
+8 2006 05
+9 2007 04
+10 2008 03
+11 2009 02
+12 2010 01
+SELECT * FROM t1 WHERE c1 = '2005';
+id c1 c2
+7 2005 06
+SELECT * FROM t1 WHERE c1 <= '2005';
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 09
+5 2003 08
+6 2004 07
+7 2005 06
+SELECT * FROM t1 WHERE c1 < '2005';
+id c1 c2
+1 1999 12
+2 2000 11
+3 2001 10
+4 2002 09
+5 2003 08
+6 2004 07
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_asc_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_asc_asc.result
new file mode 100644
index 00000000..81e11c3d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_asc_asc.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+score3 INT,
+INDEX (score1, score2, score3)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `score3` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score1` (`score1`,`score2`,`score3`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, -100);
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 10, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 100);
+SELECT *
+FROM items
+WHERE score1 = 2
+ORDER BY score2 ASC, score3 ASC;
+id score1 score2 score3
+3 2 10 100
+7 2 20 -100
+8 2 20 0
+9 2 20 100
+4 2 30 -100
+5 2 30 0
+6 2 30 100
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_desc_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_desc_desc.result
new file mode 100644
index 00000000..be5285fc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_order_by_where_equal_desc_desc.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+score3 INT,
+INDEX (score1, score2, score3)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `score3` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score1` (`score1`,`score2`,`score3`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, -100);
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 10, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 100);
+SELECT *
+FROM items
+WHERE score1 = 2
+ORDER BY score2 DESC, score3 DESC;
+id score1 score2 score3
+6 2 30 100
+5 2 30 0
+4 2 30 -100
+9 2 20 100
+8 2 20 0
+7 2 20 -100
+3 2 10 100
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_delete.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_delete.result
new file mode 100644
index 00000000..bbc5e94d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_delete.result
@@ -0,0 +1,29 @@
+drop table if exists listing;
+set names utf8;
+create table scores (
+name char(30) not null,
+score int not null,
+primary key (name, score)
+) default charset utf8;
+show create table scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+name score
+Jiro Yamada 27
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+delete from scores where name = "Taro Yamada" and score = 10;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+name score
+Taro Yamada -12
+drop table scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_select_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_select_int.result
new file mode 100644
index 00000000..7f51a04d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_select_int.result
@@ -0,0 +1,37 @@
+drop table if exists listing;
+set names utf8;
+create table scores (
+name char(30) not null,
+score int not null,
+primary key (name, score)
+) default charset utf8;
+show create table scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+name score
+Jiro Yamada 27
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+select * from scores where name = "Taro Yamada";
+name score
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+select * from scores where name = "Taro Yamada" and score = 29;
+name score
+Taro Yamada 29
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+name score
+Taro Yamada -12
+Taro Yamada 10
+drop table scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_strict_sql_mode_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_strict_sql_mode_update.result
new file mode 100644
index 00000000..b390ca7a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_strict_sql_mode_update.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS scores;
+SET NAMES utf8;
+CREATE TABLE scores (
+name char(30) NOT NULL,
+score int NOT NULL,
+PRIMARY KEY (name, score)
+) DEFAULT CHARSET=utf8;
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES ("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 10);
+SELECT * FROM scores;
+name score
+Jiro Yamada 27
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+UPDATE scores SET name = "Taro Yamada"
+ WHERE name = "Jiro Yamada" AND score = 27;
+ERROR 01000: data truncated for primary key column: <name>
+SELECT * FROM scores
+WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+name score
+Taro Yamada -12
+Taro Yamada 10
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_update.result
new file mode 100644
index 00000000..a58a487a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_primary_update.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS scores;
+SET NAMES utf8;
+CREATE TABLE scores (
+name char(30) NOT NULL,
+score int NOT NULL,
+PRIMARY KEY (name, score)
+) DEFAULT CHARSET=utf8;
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES ("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 10);
+SELECT * FROM scores;
+name score
+Jiro Yamada 27
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+UPDATE scores SET name = "Taro Yamada"
+ WHERE name = "Jiro Yamada" AND score = 27;
+Warnings:
+Warning 1265 data truncated for primary key column: <name>
+SELECT * FROM scores
+WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+name score
+Taro Yamada -12
+Taro Yamada 10
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than.result
new file mode 100644
index 00000000..b44ba312
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score INT,
+created_at DATETIME,
+INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score` (`score`,`created_at`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+SELECT *
+FROM items
+WHERE score = 2 AND created_at > "2014-09-11 00:00:00"
+ ORDER BY created_at DESC;
+id score created_at
+4 2 2014-09-12 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than_or_equal.result
new file mode 100644
index 00000000..e02a82cf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_greater_than_or_equal.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score INT,
+created_at DATETIME,
+INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score` (`score`,`created_at`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+SELECT *
+FROM items
+WHERE score = 2 AND created_at >= "2014-09-11 00:00:00"
+ ORDER BY created_at DESC;
+id score created_at
+4 2 2014-09-12 00:00:00
+2 2 2014-09-11 00:00:00
+3 2 2014-09-11 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than.result
new file mode 100644
index 00000000..ae746e72
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score INT,
+created_at DATETIME,
+INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score` (`score`,`created_at`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+SELECT *
+FROM items
+WHERE score = 2 AND created_at < "2014-09-12 00:00:00"
+ ORDER BY created_at DESC;
+id score created_at
+2 2 2014-09-11 00:00:00
+3 2 2014-09-11 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than_or_equal.result
new file mode 100644
index 00000000..db0cca7b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_all_used_less_than_or_equal.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score INT,
+created_at DATETIME,
+INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score` (`score`,`created_at`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+SELECT *
+FROM items
+WHERE score = 2 AND created_at <= "2014-09-12 00:00:00"
+ ORDER BY created_at DESC;
+id score created_at
+4 2 2014-09-12 00:00:00
+2 2 2014-09-11 00:00:00
+3 2 2014-09-11 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than.result
new file mode 100644
index 00000000..41628e65
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score1` (`score1`,`created_at`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE score1 = 2 AND created_at > "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+8 2 0 2015-07-02 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.result
new file mode 100644
index 00000000..56919b64
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score1` (`score1`,`created_at`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE score1 = 2 AND created_at >= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+8 2 0 2015-07-02 00:00:00
+5 2 0 2015-07-01 12:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than.result
new file mode 100644
index 00000000..072200b0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score1` (`score1`,`created_at`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE score1 = 2 AND created_at < "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+2 2 0 2015-07-01 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.result
new file mode 100644
index 00000000..74c6aa46
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `score1` (`score1`,`created_at`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE score1 = 2 AND created_at <= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+5 2 0 2015-07-01 12:00:00
+2 2 0 2015-07-01 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than.result
new file mode 100644
index 00000000..aca6e54a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `created_at` (`created_at`,`score1`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE created_at > "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+4 2 0 2015-07-02 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.result
new file mode 100644
index 00000000..dd8b8f91
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `created_at` (`created_at`,`score1`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE created_at >= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+4 2 0 2015-07-02 00:00:00
+3 2 0 2015-07-01 12:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than.result
new file mode 100644
index 00000000..77fd2ce8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `created_at` (`created_at`,`score1`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE created_at < "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+2 2 0 2015-07-01 00:00:00
+1 1 0 2015-07-01 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.result
new file mode 100644
index 00000000..68daea5d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS items;
+CREATE TABLE items (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT,
+score2 INT,
+created_at DATETIME,
+INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+Table Create Table
+items CREATE TABLE `items` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `score1` int(11) DEFAULT NULL,
+ `score2` int(11) DEFAULT NULL,
+ `created_at` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `created_at` (`created_at`,`score1`,`score2`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+SELECT *
+FROM items
+WHERE created_at <= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+id score1 score2 created_at
+3 2 0 2015-07-01 12:00:00
+2 2 0 2015-07-01 00:00:00
+1 1 0 2015-07-01 00:00:00
+DROP TABLE items;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_recreate.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_recreate.result
new file mode 100644
index 00000000..53c9e8e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_recreate.result
@@ -0,0 +1,39 @@
+drop table if exists listing;
+set names utf8;
+create table listing (
+id int primary key auto_increment not null,
+last_name char(30) not null,
+first_name char(30) not null,
+index name (last_name, first_name)
+) default charset utf8;
+show create table listing;
+Table Create Table
+listing CREATE TABLE `listing` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `last_name` char(30) NOT NULL,
+ `first_name` char(30) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `name` (`last_name`,`first_name`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into listing (last_name, first_name) values("Taro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Suzuki");
+insert into listing (last_name, first_name) values("Jiro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Tanaka");
+select * from listing
+where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+id last_name first_name
+2 Taro Suzuki
+4 Taro Tanaka
+drop index name on listing;
+select * from listing
+where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+id last_name first_name
+2 Taro Suzuki
+4 Taro Tanaka
+create index new_name_index on listing (last_name, first_name);
+select * from listing
+where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+id last_name first_name
+2 Taro Suzuki
+4 Taro Tanaka
+drop table listing;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_replace.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_replace.result
new file mode 100644
index 00000000..aa236967
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_replace.result
@@ -0,0 +1,39 @@
+DROP TABLE IF EXISTS listing;
+CREATE TABLE scores (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+name CHAR(30) NOT NULL,
+score INT NOT NULL,
+INDEX property (NAME, SCORE)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `property` (`name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores;
+id name score
+1 Taro Yamada 29
+2 Taro Yamada -12
+3 Jiro Yamada 27
+4 Taro Yamada 10
+REPLACE scores (id, name, score) VALUES (3, "Taro Yamada", 28);
+SELECT * FROM scores;
+id name score
+1 Taro Yamada 29
+2 Taro Yamada -12
+3 Taro Yamada 28
+4 Taro Yamada 10
+SELECT * FROM scores WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+3 Taro Yamada 28
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_double.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_double.result
new file mode 100644
index 00000000..c75733f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_double.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS temperatures;
+CREATE TABLE temperatures (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(20),
+temperature DOUBLE,
+KEY temperature_index(temperature),
+KEY multi_index(temperature, title)
+);
+INSERT INTO temperatures VALUES (NULL, "Hot!", 28.2);
+INSERT INTO temperatures VALUES (NULL, "Snow!", -2.8);
+INSERT INTO temperatures VALUES (NULL, "Rainy!", 12.7);
+SELECT temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+temperature
+12.7
+28.2
+SELECT temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+temperature
+-2.8
+12.7
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+title temperature
+Rainy! 12.7
+Hot! 28.2
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+title temperature
+Snow! -2.8
+Rainy! 12.7
+DROP TABLE temperatures;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_float.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_float.result
new file mode 100644
index 00000000..452cae2d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_float.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS temperatures;
+CREATE TABLE temperatures (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title VARCHAR(20),
+temperature FLOAT,
+KEY temperature_index(temperature),
+KEY multi_index(temperature, title)
+);
+INSERT INTO temperatures VALUES (NULL, "Hot!", 28.2);
+INSERT INTO temperatures VALUES (NULL, "Snow!", -2.8);
+INSERT INTO temperatures VALUES (NULL, "Rainy!", 12.7);
+SELECT temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+temperature
+12.7
+28.2
+SELECT temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+temperature
+-2.8
+12.7
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+title temperature
+Rainy! 12.7
+Hot! 28.2
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+title temperature
+Snow! -2.8
+Rainy! 12.7
+DROP TABLE temperatures;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_int.result
new file mode 100644
index 00000000..adaf523b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_int.result
@@ -0,0 +1,37 @@
+DROP TABLE IF EXISTS listing;
+CREATE TABLE scores (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+name CHAR(30) NOT NULL,
+score INT NOT NULL,
+INDEX property (score, name)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `property` (`score`,`name`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores;
+id name score
+1 Taro Yamada 29
+2 Taro Yamada -12
+3 Jiro Yamada 27
+4 Taro Yamada 10
+SELECT * FROM scores WHERE score = 29;
+id name score
+1 Taro Yamada 29
+SELECT * FROM scores WHERE score = 29 AND name = "Taro Yamada";
+id name score
+1 Taro Yamada 29
+SELECT * FROM scores WHERE (score >= -12 AND score < 29) AND name = "Taro Yamada";
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_max.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_max.result
new file mode 100644
index 00000000..b6091784
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_max.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS listing;
+CREATE TABLE scores (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT NOT NULL,
+score2 INT NOT NULL,
+INDEX (score1, score2)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO scores (score1, score2) VALUES(1, 1);
+INSERT INTO scores (score1, score2) VALUES(1, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 3);
+INSERT INTO scores (score1, score2) VALUES(2, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 1);
+INSERT INTO scores (score1, score2) VALUES(2, 0);
+INSERT INTO scores (score1, score2) VALUES(2, -1);
+INSERT INTO scores (score1, score2) VALUES(2, -2);
+INSERT INTO scores (score1, score2) VALUES(2, -3);
+SELECT MAX(score2) FROM scores WHERE score1 = 2;
+MAX(score2)
+3
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_min.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_min.result
new file mode 100644
index 00000000..0792751a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_min.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS listing;
+CREATE TABLE scores (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+score1 INT NOT NULL,
+score2 INT NOT NULL,
+INDEX (score1, score2)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO scores (score1, score2) VALUES(1, 1);
+INSERT INTO scores (score1, score2) VALUES(1, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 3);
+INSERT INTO scores (score1, score2) VALUES(2, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 1);
+INSERT INTO scores (score1, score2) VALUES(2, 0);
+INSERT INTO scores (score1, score2) VALUES(2, -1);
+INSERT INTO scores (score1, score2) VALUES(2, -2);
+INSERT INTO scores (score1, score2) VALUES(2, -3);
+SELECT MIN(score2) FROM scores WHERE score1 = 2;
+MIN(score2)
+-3
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_string.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_string.result
new file mode 100644
index 00000000..62b857bb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_string.result
@@ -0,0 +1,40 @@
+drop table if exists listing;
+set names utf8;
+create table listing (
+id int primary key auto_increment not null,
+last_name char(30) not null,
+first_name char(30) not null,
+index name (last_name, first_name)
+) default charset utf8;
+show create table listing;
+Table Create Table
+listing CREATE TABLE `listing` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `last_name` char(30) NOT NULL,
+ `first_name` char(30) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `name` (`last_name`,`first_name`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into listing (last_name, first_name) values("Taro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Suzuki");
+insert into listing (last_name, first_name) values("Jiro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Tanaka");
+select * from listing;
+id last_name first_name
+1 Taro Yamada
+2 Taro Suzuki
+3 Jiro Yamada
+4 Taro Tanaka
+select * from listing where last_name = "Taro";
+id last_name first_name
+2 Taro Suzuki
+4 Taro Tanaka
+1 Taro Yamada
+select * from listing where last_name = "Taro" and first_name = "Suzuki";
+id last_name first_name
+2 Taro Suzuki
+select * from listing where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+id last_name first_name
+2 Taro Suzuki
+4 Taro Tanaka
+drop table listing;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_varchar.result
new file mode 100644
index 00000000..36b769ea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_select_varchar.result
@@ -0,0 +1,41 @@
+drop table if exists scores;
+set names utf8;
+create table scores (
+given_name varchar(30) not null,
+family_name varchar(30) not null,
+score int not null,
+primary key property (given_name, family_name, score)
+) default charset utf8;
+Warnings:
+Warning 1280 Name 'property' ignored for PRIMARY key.
+show create table scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `given_name` varchar(30) NOT NULL,
+ `family_name` varchar(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`given_name`,`family_name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into scores values("Taro", "Yamada", 29);
+insert into scores values("Taro", "Yamada", -12);
+insert into scores values("Jiro", "Yamada", 27);
+insert into scores values("Taro", "Yamada", 10);
+select * from scores;
+given_name family_name score
+Jiro Yamada 27
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+select * from scores where given_name = "Taro" and family_name = "Yamada";
+given_name family_name score
+Taro Yamada -12
+Taro Yamada 10
+Taro Yamada 29
+select * from scores where given_name = "Taro" and family_name = "Yamada" and score = 29;
+given_name family_name score
+Taro Yamada 29
+select * from scores where given_name = "Taro" and family_name = "Yamada" and (score >= -12 and score < 29);
+given_name family_name score
+Taro Yamada -12
+Taro Yamada 10
+drop table scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_32bit_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_32bit_equal.result
new file mode 100644
index 00000000..61ce4406
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_32bit_equal.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, "1000-01-01", "2012-10-05");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+INSERT IGNORE INTO ranges VALUES (2, "1000-01-01", "9999-12-31");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (3, "2012-10-25", "9999-12-31");
+Warnings:
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (4, "9999-12-31", "1000-01-01");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+SELECT * FROM ranges FORCE INDEX(range_key)
+WHERE start = "1000-01-01" AND end = "9999-12-31";
+id start end
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_64bit_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_64bit_equal.result
new file mode 100644
index 00000000..21168547
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_64bit_equal.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (2, "1000-01-02", "9999-12-31");
+INSERT INTO ranges VALUES (3, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (4, "9999-12-31", "1000-01-02");
+SELECT * FROM ranges FORCE INDEX(range_key)
+WHERE start = "1000-01-02" AND end = "9999-12-31";
+id start end
+2 1000-01-02 9999-12-31
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_index_read.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_index_read.result
new file mode 100644
index 00000000..93e34d88
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_index_read.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (2, "1000-01-02", "9999-12-31");
+INSERT INTO ranges VALUES (3, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (4, "9999-12-31", "1000-01-02");
+SELECT start, end
+FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+start end
+1000-01-02 2012-10-05
+1000-01-02 9999-12-31
+2012-10-25 9999-12-31
+9999-12-31 1000-01-02
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_asc.result
new file mode 100644
index 00000000..bc1c3c57
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_asc.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+Warnings:
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (2, "1000-01-01", "2012-10-05");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+INSERT IGNORE INTO ranges VALUES (3, "9999-12-31", "1000-01-01");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (4, "1000-01-01", "9999-12-31");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+2 1970-01-01 2012-10-05
+4 1970-01-01 1970-01-01
+1 2012-10-25 1970-01-01
+3 1970-01-01 1970-01-01
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_desc.result
new file mode 100644
index 00000000..820ee4f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_32bit_desc.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+Warnings:
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (2, "1000-01-01", "2012-10-05");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+INSERT IGNORE INTO ranges VALUES (3, "9999-12-31", "1000-01-01");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (4, "1000-01-01", "9999-12-31");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 1970-01-01 1970-01-01
+1 2012-10-25 1970-01-01
+4 1970-01-01 1970-01-01
+2 1970-01-01 2012-10-05
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_asc.result
new file mode 100644
index 00000000..c2a94a84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_asc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (2, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (3, "9999-12-31", "1000-01-02");
+INSERT INTO ranges VALUES (4, "1000-01-02", "9999-12-31");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+2 1000-01-02 2012-10-05
+4 1000-01-02 9999-12-31
+1 2012-10-25 9999-12-31
+3 9999-12-31 1000-01-02
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_desc.result
new file mode 100644
index 00000000..2d100156
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_order_64bit_desc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (2, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (3, "9999-12-31", "1000-01-02");
+INSERT INTO ranges VALUES (4, "1000-01-02", "9999-12-31");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 9999-12-31 1000-01-02
+1 2012-10-25 9999-12-31
+4 1000-01-02 9999-12-31
+2 1000-01-02 2012-10-05
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_reinsert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_reinsert.result
new file mode 100644
index 00000000..bd1bdc33
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_date_reinsert.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start DATE,
+end DATE,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2010-01-01", "2012-10-05");
+SELECT * FROM ranges;
+id start end
+1 2010-01-01 2012-10-05
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "2010-01-01", "2012-10-05");
+SELECT * FROM ranges;
+id start end
+1 2010-01-01 2012-10-05
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_index_read.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_index_read.result
new file mode 100644
index 00000000..a8546c4b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_index_read.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start datetime,
+end datetime,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "1000-01-02 00:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (2, "1000-01-02 00:00:00", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (3, "2012-10-25 16:18:29", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (4, "9999-12-31 23:59:59", "1000-01-02 00:00:00");
+SELECT start, end
+FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+start end
+1000-01-02 00:00:00 2012-10-05 16:18:29
+1000-01-02 00:00:00 9999-12-31 23:59:59
+2012-10-25 16:18:29 9999-12-31 23:59:59
+9999-12-31 23:59:59 1000-01-02 00:00:00
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.result
new file mode 100644
index 00000000..130c03ed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start datetime,
+end datetime,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, "1990-00-00 00:00:00", "2012-10-05 23:59:59");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+SELECT * FROM ranges;
+id start end
+1 1990-01-01 00:00:00 2012-10-05 23:59:59
+DELETE FROM ranges WHERE id = 1;
+INSERT IGNORE INTO ranges VALUES (1, "1990-00-00 00:00:00", "2012-10-05 23:59:59");
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+SELECT * FROM ranges;
+id start end
+1 1990-01-01 00:00:00 2012-10-05 23:59:59
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_asc.result
new file mode 100644
index 00000000..5cffb71d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_asc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start datetime,
+end datetime,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (2, "1000-01-02 00:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "9999-12-31 23:59:59", "1000-01-02 00:00:00");
+INSERT INTO ranges VALUES (4, "1000-01-02 00:00:00", "9999-12-31 23:59:59");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+2 1000-01-02 00:00:00 2012-10-05 16:18:29
+4 1000-01-02 00:00:00 9999-12-31 23:59:59
+1 2012-10-25 16:18:29 9999-12-31 23:59:59
+3 9999-12-31 23:59:59 1000-01-02 00:00:00
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_desc.result
new file mode 100644
index 00000000..4429f787
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_order_desc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start datetime,
+end datetime,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (2, "1000-01-02 00:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "9999-12-31 23:59:59", "1000-01-02 00:00:00");
+INSERT INTO ranges VALUES (4, "1000-01-02 00:00:00", "9999-12-31 23:59:59");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 9999-12-31 23:59:59 1000-01-02 00:00:00
+1 2012-10-25 16:18:29 9999-12-31 23:59:59
+4 1000-01-02 00:00:00 9999-12-31 23:59:59
+2 1000-01-02 00:00:00 2012-10-05 16:18:29
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_reinsert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_reinsert.result
new file mode 100644
index 00000000..50d5da49
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_datetime_reinsert.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start datetime,
+end datetime,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+id start end
+1 2010-01-01 00:00:00 2012-10-05 23:59:59
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+id start end
+1 2010-01-01 00:00:00 2012-10-05 23:59:59
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_decimal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_decimal.result
new file mode 100644
index 00000000..cb8a1c61
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_decimal.result
@@ -0,0 +1,36 @@
+drop table if exists t1;
+create table t1 (c1 int primary key, c2 decimal(65,30), c3 decimal(65,30), unique key uk1(c2,c3));
+insert into t1 values(1,123.456,0.000000000000000000000000000001);
+insert into t1 values(2,-123.456,123.456);
+insert into t1 values(3,98765432109876543210987654321098765.432109876543210987654321098765,-123.456);
+insert into t1 values(4,-98765432109876543210987654321098765.432109876543210987654321098765,98765432109876543210987654321098765.432109876543210987654321098765);
+insert into t1 values(5,0.000000000000000000000000000001,-98765432109876543210987654321098765.432109876543210987654321098765);
+select c1, c2, c3 from t1 force index(uk1) where c2 = -98765432109876543210987654321098765.432109876543210987654321098765 and c3 = 98765432109876543210987654321098765.432109876543210987654321098765;
+c1 c2 c3
+4 -98765432109876543210987654321098765.432109876543210987654321098765 98765432109876543210987654321098765.432109876543210987654321098765
+select c1, c2, c3 from t1 force index(uk1) order by c2, c3;
+c1 c2 c3
+4 -98765432109876543210987654321098765.432109876543210987654321098765 98765432109876543210987654321098765.432109876543210987654321098765
+2 -123.456000000000000000000000000000 123.456000000000000000000000000000
+5 0.000000000000000000000000000001 -98765432109876543210987654321098765.432109876543210987654321098765
+1 123.456000000000000000000000000000 0.000000000000000000000000000001
+3 98765432109876543210987654321098765.432109876543210987654321098765 -123.456000000000000000000000000000
+select c1, c2, c3 from t1 force index(uk1) order by c2 desc, c3 desc;
+c1 c2 c3
+3 98765432109876543210987654321098765.432109876543210987654321098765 -123.456000000000000000000000000000
+1 123.456000000000000000000000000000 0.000000000000000000000000000001
+5 0.000000000000000000000000000001 -98765432109876543210987654321098765.432109876543210987654321098765
+2 -123.456000000000000000000000000000 123.456000000000000000000000000000
+4 -98765432109876543210987654321098765.432109876543210987654321098765 98765432109876543210987654321098765.432109876543210987654321098765
+select c2, c3 from t1 force index(uk1) order by c2, c3;
+c2 c3
+-98765432109876543210987654321098765.432109876543210987654321098765 98765432109876543210987654321098765.432109876543210987654321098765
+-123.456000000000000000000000000000 123.456000000000000000000000000000
+0.000000000000000000000000000001 -98765432109876543210987654321098765.432109876543210987654321098765
+123.456000000000000000000000000000 0.000000000000000000000000000001
+98765432109876543210987654321098765.432109876543210987654321098765 -123.456000000000000000000000000000
+insert into t1 values(6,123.456,0.000000000000000000000000000001);
+ERROR 23000: Duplicate entry '123.456000000000000000000000000000-0.000000000000000000000000...' for key 'uk1'
+delete from t1 where c1 = 1;
+insert into t1 values(1,123.456,0.000000000000000000000000000001);
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_index_read.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_index_read.result
new file mode 100644
index 00000000..4e0dec32
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_index_read.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start time,
+end time,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "00:00:00", "15:11:11");
+INSERT INTO ranges VALUES (2, "00:00:00", "838:59:59");
+INSERT INTO ranges VALUES (3, "15:11:12", "838:59:59");
+INSERT INTO ranges VALUES (4, "838:59:59", "00:00:00");
+INSERT INTO ranges VALUES (5, "-838:59:59", "838:59:59");
+SELECT start, end
+FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+start end
+-838:59:59 838:59:59
+00:00:00 15:11:11
+00:00:00 838:59:59
+15:11:12 838:59:59
+838:59:59 00:00:00
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_asc.result
new file mode 100644
index 00000000..3c6520a6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_asc.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start time,
+end time,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "15:11:12", "838:59:59");
+INSERT INTO ranges VALUES (2, "00:00:00", "15:11:11");
+INSERT INTO ranges VALUES (3, "838:59:59", "00:00:00");
+INSERT INTO ranges VALUES (4, "00:00:00", "838:59:59");
+INSERT INTO ranges VALUES (5, "-838:59:59", "838:59:59");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+5 -838:59:59 838:59:59
+2 00:00:00 15:11:11
+4 00:00:00 838:59:59
+1 15:11:12 838:59:59
+3 838:59:59 00:00:00
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_desc.result
new file mode 100644
index 00000000..c1be8030
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_order_desc.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start time,
+end time,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "15:11:12", "838:59:59");
+INSERT INTO ranges VALUES (2, "00:00:00", "15:11:11");
+INSERT INTO ranges VALUES (3, "838:59:59", "00:00:00");
+INSERT INTO ranges VALUES (4, "00:00:00", "838:59:59");
+INSERT INTO ranges VALUES (5, "-838:59:59", "838:59:59");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 838:59:59 00:00:00
+1 15:11:12 838:59:59
+4 00:00:00 838:59:59
+2 00:00:00 15:11:11
+5 -838:59:59 838:59:59
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_reinsert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_reinsert.result
new file mode 100644
index 00000000..0613de3e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_time_reinsert.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start time,
+end time,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "13:21:48", "15:11:12");
+SELECT * FROM ranges;
+id start end
+1 13:21:48 15:11:12
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "13:21:48", "15:11:12");
+SELECT * FROM ranges;
+id start end
+1 13:21:48 15:11:12
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_index_read.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_index_read.result
new file mode 100644
index 00000000..92e95d92
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_index_read.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start timestamp DEFAULT '2016-04-21 00:00:00',
+end timestamp DEFAULT '2016-04-22 00:00:00',
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "1970-01-01 12:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (2, "1970-01-01 12:00:00", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (3, "2012-10-25 16:18:29", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (4, "2038-01-18 15:14:07", "1970-01-01 12:00:00");
+SELECT start, end
+FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+start end
+1970-01-01 12:00:00 2012-10-05 16:18:29
+1970-01-01 12:00:00 2038-01-18 15:14:07
+2012-10-25 16:18:29 2038-01-18 15:14:07
+2038-01-18 15:14:07 1970-01-01 12:00:00
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_asc.result
new file mode 100644
index 00000000..35bc4123
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_asc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start timestamp DEFAULT '2016-04-21 00:00:00',
+end timestamp DEFAULT '2016-04-22 00:00:00',
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (2, "1970-01-01 12:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "2038-01-18 15:14:07", "1970-01-01 12:00:00");
+INSERT INTO ranges VALUES (4, "1970-01-01 12:00:00", "2038-01-18 15:14:07");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+2 1970-01-01 12:00:00 2012-10-05 16:18:29
+4 1970-01-01 12:00:00 2038-01-18 15:14:07
+1 2012-10-25 16:18:29 2038-01-18 15:14:07
+3 2038-01-18 15:14:07 1970-01-01 12:00:00
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_desc.result
new file mode 100644
index 00000000..fbf88cf3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_order_desc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start timestamp DEFAULT '2016-04-21 00:00:00',
+end timestamp DEFAULT '2016-04-22 00:00:00',
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (2, "1970-01-01 12:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "2038-01-18 15:14:07", "1970-01-01 12:00:00");
+INSERT INTO ranges VALUES (4, "1970-01-01 12:00:00", "2038-01-18 15:14:07");
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 2038-01-18 15:14:07 1970-01-01 12:00:00
+1 2012-10-25 16:18:29 2038-01-18 15:14:07
+4 1970-01-01 12:00:00 2038-01-18 15:14:07
+2 1970-01-01 12:00:00 2012-10-05 16:18:29
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_reinsert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_reinsert.result
new file mode 100644
index 00000000..b799cc27
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_timestamp_reinsert.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id int PRIMARY KEY,
+start timestamp DEFAULT '2016-04-21 00:00:00',
+end timestamp DEFAULT '2016-04-22 00:00:00',
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+id start end
+1 2010-01-01 00:00:00 2012-10-05 23:59:59
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+id start end
+1 2010-01-01 00:00:00 2012-10-05 23:59:59
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_varchar.result
new file mode 100644
index 00000000..5c9cd959
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_varchar.result
Binary files differ
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_32bit_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_32bit_equal.result
new file mode 100644
index 00000000..ad936268
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_32bit_equal.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, 1901, 2012);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+INSERT IGNORE INTO ranges VALUES (2, 1901, 2155);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (3, 2012, 2155);
+Warnings:
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (4, 2155, 1901);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+SELECT * FROM ranges FORCE INDEX(range_key)
+WHERE start = 1901 AND end = 2155;
+id start end
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_64bit_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_64bit_equal.result
new file mode 100644
index 00000000..e96754e5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_64bit_equal.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, 1901, 2012);
+INSERT INTO ranges VALUES (2, 1901, 2155);
+INSERT INTO ranges VALUES (3, 2012, 2155);
+INSERT INTO ranges VALUES (4, 2155, 1901);
+SELECT * FROM ranges FORCE INDEX(range_key)
+WHERE start = 1901 AND end = 2155;
+id start end
+2 1901 2155
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_index_read.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_index_read.result
new file mode 100644
index 00000000..997c5e7d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_index_read.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, 1901, 2012);
+INSERT INTO ranges VALUES (2, 1901, 2155);
+INSERT INTO ranges VALUES (3, 2012, 2155);
+INSERT INTO ranges VALUES (4, 2155, 1901);
+SELECT start, end
+FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+start end
+1901 2012
+1901 2155
+2012 2155
+2155 1901
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_asc.result
new file mode 100644
index 00000000..8200263a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_asc.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, 2012, 2155);
+Warnings:
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (2, 1901, 2012);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+INSERT IGNORE INTO ranges VALUES (3, 2155, 1901);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (4, 1901, 2155);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+2 1970 2012
+4 1970 1970
+1 2012 1970
+3 1970 1970
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_desc.result
new file mode 100644
index 00000000..fc85d2a9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_32bit_desc.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT IGNORE INTO ranges VALUES (1, 2012, 2155);
+Warnings:
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (2, 1901, 2012);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+INSERT IGNORE INTO ranges VALUES (3, 2155, 1901);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+INSERT IGNORE INTO ranges VALUES (4, 1901, 2155);
+Warnings:
+Warning 1265 Data truncated for column 'start' at row 1
+Warning 1265 Data truncated for column 'end' at row 1
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 1970 1970
+1 2012 1970
+4 1970 1970
+2 1970 2012
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_asc.result
new file mode 100644
index 00000000..335b9eb9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_asc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, 2012, 2155);
+INSERT INTO ranges VALUES (2, 1901, 2012);
+INSERT INTO ranges VALUES (3, 2155, 1901);
+INSERT INTO ranges VALUES (4, 1901, 2155);
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start, end;
+id start end
+2 1901 2012
+4 1901 2155
+1 2012 2155
+3 2155 1901
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_desc.result
new file mode 100644
index 00000000..524456b7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_order_64bit_desc.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, 2012, 2155);
+INSERT INTO ranges VALUES (2, 1901, 2012);
+INSERT INTO ranges VALUES (3, 2155, 1901);
+INSERT INTO ranges VALUES (4, 1901, 2155);
+SELECT * FROM ranges FORCE INDEX(range_key)
+ORDER BY start DESC, end DESC;
+id start end
+3 2155 1901
+1 2012 2155
+4 1901 2155
+2 1901 2012
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_reinsert.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_reinsert.result
new file mode 100644
index 00000000..7362411d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_unique_year_reinsert.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ranges;
+CREATE TABLE ranges (
+id INT PRIMARY KEY,
+start YEAR,
+end YEAR,
+UNIQUE KEY range_key(start, end)
+);
+INSERT INTO ranges VALUES (1, 2010, 2012);
+SELECT * FROM ranges;
+id start end
+1 2010 2012
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, 2010, 2012);
+SELECT * FROM ranges;
+id start end
+1 2010 2012
+DROP TABLE ranges;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_int.result
new file mode 100644
index 00000000..91fef7be
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_int.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS scores;
+CREATE TABLE scores (
+id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+name CHAR(30) NOT NULL,
+score INT NOT NULL,
+KEY property (score, name)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `property` (`score`,`name`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores WHERE score = 29;
+id name score
+3 Jiro Yamada 29
+1 Taro Yamada 29
+UPDATE scores SET name = "Saburo YAMADA" WHERE id = 3;
+SELECT * FROM scores WHERE score = 29;
+id name score
+3 Saburo YAMADA 29
+1 Taro Yamada 29
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_string.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_string.result
new file mode 100644
index 00000000..5dfcd916
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_multiple_column_update_string.result
@@ -0,0 +1,34 @@
+drop table if exists listing;
+set names utf8;
+create table scores (
+id int primary key auto_increment not null,
+name char(30) not null,
+score int not null,
+index property (name, score)
+) default charset utf8;
+show create table scores;
+Table Create Table
+scores CREATE TABLE `scores` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` char(30) NOT NULL,
+ `score` int(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `property` (`name`,`score`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+id name score
+1 Taro Yamada 29
+2 Taro Yamada -12
+3 Jiro Yamada 27
+4 Taro Yamada 10
+update scores set name = "Taro Yamada" where name = "Jiro Yamada" and score = 27;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+id name score
+2 Taro Yamada -12
+4 Taro Yamada 10
+3 Taro Yamada 27
+drop table scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_exact_length.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_exact_length.result
new file mode 100644
index 00000000..95d7c78b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_exact_length.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id char(10) CHARACTER SET latin1 PRIMARY KEY
+);
+INSERT INTO ids VALUES('abcdefghij');
+INSERT INTO ids VALUES('klmnopqrst');
+INSERT INTO ids VALUES('uvwxyz0123');
+SELECT * FROM ids FORCE INDEX(PRIMARY) ORDER BY id;
+id
+abcdefghij
+klmnopqrst
+uvwxyz0123
+SELECT * FROM ids FORCE INDEX(PRIMARY) WHERE id = 'abcdefghij';
+id
+abcdefghij
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_null_character.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_null_character.result
new file mode 100644
index 00000000..f7a80206
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_null_character.result
Binary files differ
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_short.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_short.result
new file mode 100644
index 00000000..fb08c660
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_char_short.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id char(6) CHARACTER SET latin1 PRIMARY KEY
+);
+INSERT INTO ids VALUES("abcdef");
+INSERT INTO ids VALUES( "cdef");
+INSERT INTO ids VALUES( "ef");
+SELECT * FROM ids FORCE INDEX(PRIMARY) ORDER BY id;
+id
+abcdef
+cdef
+ef
+SELECT * FROM ids FORCE INDEX(PRIMARY) WHERE id = "cdef";
+id
+cdef
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_date.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_date.result
new file mode 100644
index 00000000..b1eafd2d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_date.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (day, title) VALUES ("2012-01-29", "clear day");
+INSERT INTO diaries (day, title) VALUES ("2012-01-30", "rainy day");
+INSERT INTO diaries (day, title) VALUES ("2012-01-31", "cloudy day");
+INSERT INTO diaries (day, title) VALUES ("2012-01-31", "duplicated day");
+ERROR 23000: Duplicate entry '2012-01-31' for key 'PRIMARY'
+SELECT * FROM diaries;
+day title
+2012-01-29 clear day
+2012-01-30 rainy day
+2012-01-31 cloudy day
+SELECT * FROM diaries
+WHERE day BETWEEN "2012-01-29" AND "2012-01-30";
+day title
+2012-01-29 clear day
+2012-01-30 rainy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_with_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_with_fractional_seconds.result
new file mode 100644
index 00000000..0ae41c51
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_with_fractional_seconds.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+day DATETIME(6) PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (day, title)
+VALUES ("2012-01-29 21:51:01.111111", "clear day");
+INSERT INTO diaries (day, title)
+VALUES ("2012-01-30 01:23:45.333", "rainy day");
+INSERT INTO diaries (day, title)
+VALUES ("2012-01-31 08:32:10.5555", "cloudy day");
+SELECT * FROM diaries;
+day title
+2012-01-29 21:51:01.111111 clear day
+2012-01-30 01:23:45.333000 rainy day
+2012-01-31 08:32:10.555500 cloudy day
+SELECT * FROM diaries
+WHERE day BETWEEN "2012-01-29 00:00:00.123456" AND
+"2012-01-31 00:00:00.999999";
+day title
+2012-01-29 21:51:01.111111 clear day
+2012-01-30 01:23:45.333000 rainy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_without_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_without_fractional_seconds.result
new file mode 100644
index 00000000..f5e743dc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_datetime_without_fractional_seconds.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+day DATETIME PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (day, title)
+VALUES ("2012-01-29 21:51:01", "clear day");
+INSERT INTO diaries (day, title)
+VALUES ("2012-01-30 01:23:45", "rainy day");
+INSERT INTO diaries (day, title)
+VALUES ("2012-01-31 08:32:10", "cloudy day");
+SELECT * FROM diaries;
+day title
+2012-01-29 21:51:01 clear day
+2012-01-30 01:23:45 rainy day
+2012-01-31 08:32:10 cloudy day
+SELECT * FROM diaries
+WHERE day BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+day title
+2012-01-29 21:51:01 clear day
+2012-01-30 01:23:45 rainy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_with_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_with_fractional_seconds.result
new file mode 100644
index 00000000..6a529b50
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_with_fractional_seconds.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS releases;
+CREATE TABLE releases (
+version DECIMAL(6, 3) PRIMARY KEY,
+message TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO releases (version, message) VALUES (10.000, "10th release!");
+INSERT INTO releases (version, message) VALUES (10.001, "minor fix.");
+INSERT INTO releases (version, message) VALUES (999.999, "the last release!");
+SELECT * FROM releases;
+version message
+10.000 10th release!
+10.001 minor fix.
+999.999 the last release!
+SELECT * FROM releases WHERE version BETWEEN "9.000" AND "10.001";
+version message
+10.000 10th release!
+10.001 minor fix.
+DROP TABLE releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_without_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_without_fractional_seconds.result
new file mode 100644
index 00000000..d36688bb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_decimal_without_fractional_seconds.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS releases;
+CREATE TABLE releases (
+version DECIMAL PRIMARY KEY,
+message TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO releases (version, message) VALUES (1, "the first release!!!");
+INSERT INTO releases (version, message) VALUES (10, "10th release!");
+INSERT INTO releases (version, message) VALUES (999, "the last release!");
+SELECT * FROM releases;
+version message
+1 the first release!!!
+10 10th release!
+999 the last release!
+SELECT * FROM releases WHERE version BETWEEN "1" AND "10";
+version message
+1 the first release!!!
+10 10th release!
+DROP TABLE releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_with_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_with_fractional_seconds.result
new file mode 100644
index 00000000..5437c789
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_with_fractional_seconds.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS running_records;
+CREATE TABLE running_records (
+time TIME(6) PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO running_records (time, title)
+VALUES ("01:00:00.000001", "normal condition");
+INSERT INTO running_records (time, title)
+VALUES ("12:23:34.123456", "bad condition");
+INSERT INTO running_records (time, title)
+VALUES ("-838:59:59.000000", "record failure");
+SELECT * FROM running_records;
+time title
+-838:59:59.000000 record failure
+01:00:00.000001 normal condition
+12:23:34.123456 bad condition
+SELECT * FROM running_records
+WHERE time BETWEEN "00:59:59.999999" AND "12:23:34.123456";
+time title
+01:00:00.000001 normal condition
+12:23:34.123456 bad condition
+DROP TABLE running_records;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_without_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_without_fractional_seconds.result
new file mode 100644
index 00000000..e59dee4c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_time_without_fractional_seconds.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS running_records;
+CREATE TABLE running_records (
+time TIME PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO running_records (time, title)
+VALUES ("01:00:00", "normal condition");
+INSERT INTO running_records (time, title)
+VALUES ("12:23:34", "bad condition");
+INSERT INTO running_records (time, title)
+VALUES ("-838:59:59", "record failure");
+SELECT * FROM running_records;
+time title
+-838:59:59 record failure
+01:00:00 normal condition
+12:23:34 bad condition
+SELECT * FROM running_records
+WHERE time BETWEEN "00:59:59" AND "12:23:34";
+time title
+01:00:00 normal condition
+12:23:34 bad condition
+DROP TABLE running_records;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_with_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_with_fractional_seconds.result
new file mode 100644
index 00000000..0fba3da7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_with_fractional_seconds.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+time TIMESTAMP(6) PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (time, title)
+VALUES ("2012-01-29 21:51:01.111111", "clear day");
+INSERT INTO diaries (time, title)
+VALUES ("2012-01-30 01:23:45.333", "rainy day");
+INSERT INTO diaries (time, title)
+VALUES ("2012-01-31 08:32:10.5555", "cloudy day");
+SELECT * FROM diaries;
+time title
+2012-01-29 21:51:01.111111 clear day
+2012-01-30 01:23:45.333000 rainy day
+2012-01-31 08:32:10.555500 cloudy day
+SELECT * FROM diaries
+WHERE time BETWEEN "2012-01-29 00:00:00.123456" AND
+"2012-01-31 00:00:00.999999";
+time title
+2012-01-29 21:51:01.111111 clear day
+2012-01-30 01:23:45.333000 rainy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_without_fractional_seconds.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_without_fractional_seconds.result
new file mode 100644
index 00000000..8116bda2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_timestamp_without_fractional_seconds.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+time TIMESTAMP PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (time, title) VALUES ("2012-01-29 21:51:01", "clear day");
+INSERT INTO diaries (time, title) VALUES ("2012-01-30 01:23:45", "rainy day");
+INSERT INTO diaries (time, title) VALUES ("2012-01-31 08:32:10", "cloudy day");
+SELECT * FROM diaries;
+time title
+2012-01-29 21:51:01 clear day
+2012-01-30 01:23:45 rainy day
+2012-01-31 08:32:10 cloudy day
+SELECT * FROM diaries
+WHERE time BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+time title
+2012-01-29 21:51:01 clear day
+2012-01-30 01:23:45 rainy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_varchar_null_character.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_varchar_null_character.result
new file mode 100644
index 00000000..9079d9c4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_varchar_null_character.result
Binary files differ
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_year.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_year.result
new file mode 100644
index 00000000..78c56f25
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_primary_year.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS aniversary_memos;
+CREATE TABLE aniversary_memos (
+party_year YEAR PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET UTF8;
+INSERT INTO aniversary_memos (party_year, title)
+VALUES ("11", "We need a big cake!");
+INSERT INTO aniversary_memos (party_year, title)
+VALUES ("2012", "Invitations are sent.");
+INSERT INTO aniversary_memos (party_year, title)
+VALUES ("13", "Wow! Today is the anniversary party day!");
+SELECT * FROM aniversary_memos;
+party_year title
+2011 We need a big cake!
+2012 Invitations are sent.
+2013 Wow! Today is the anniversary party day!
+SELECT * FROM aniversary_memos
+WHERE party_year BETWEEN "12" AND "2013";
+party_year title
+2012 Invitations are sent.
+2013 Wow! Today is the anniversary party day!
+DROP TABLE aniversary_memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_asc.result
new file mode 100644
index 00000000..c2adc1cd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_asc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value > 10 ORDER BY value ASC LIMIT 3;
+id value
+3 30
+1 50
+2 70
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_desc.result
new file mode 100644
index 00000000..715d299d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_desc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value > 10 ORDER BY value DESC LIMIT 3;
+id value
+4 90
+2 70
+1 50
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_asc.result
new file mode 100644
index 00000000..d562fbbb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_asc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value >= 30 ORDER BY value ASC LIMIT 3;
+id value
+3 30
+1 50
+2 70
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_desc.result
new file mode 100644
index 00000000..5ecb4699
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_greater_than_or_equal_desc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value >= 30 ORDER BY value DESC LIMIT 3;
+id value
+4 90
+2 70
+1 50
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_asc.result
new file mode 100644
index 00000000..45b3fbe1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_asc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value < 90 ORDER BY value ASC LIMIT 3;
+id value
+5 10
+3 30
+1 50
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_desc.result
new file mode 100644
index 00000000..2e896e5e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_desc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value < 90 ORDER BY value DESC LIMIT 3;
+id value
+2 70
+1 50
+3 30
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_asc.result
new file mode 100644
index 00000000..d5313c9d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_asc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value <= 70 ORDER BY value ASC LIMIT 3;
+id value
+5 10
+3 30
+1 50
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_desc.result
new file mode 100644
index 00000000..c56a4332
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_normal_less_than_or_equal_desc.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+value INT(10),
+INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+SELECT id, value FROM ids WHERE value <= 70 ORDER BY value DESC LIMIT 3;
+id value
+2 70
+1 50
+3 30
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_asc.result
new file mode 100644
index 00000000..1ca4b145
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_asc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id > 1 ORDER BY ids.id ASC LIMIT 3;
+id
+2
+3
+4
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_desc.result
new file mode 100644
index 00000000..80dcb25f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_desc.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id > 3 ORDER BY ids.id DESC LIMIT 3;
+id
+5
+4
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_asc.result
new file mode 100644
index 00000000..4c1ff997
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_asc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id >= 2 ORDER BY ids.id ASC LIMIT 3;
+id
+2
+3
+4
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_desc.result
new file mode 100644
index 00000000..4998725a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_greater_than_or_equal_desc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id >= 3 ORDER BY ids.id DESC LIMIT 3;
+id
+5
+4
+3
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_asc.result
new file mode 100644
index 00000000..8b142f30
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_asc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id < 4 ORDER BY ids.id ASC LIMIT 3;
+id
+1
+2
+3
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_desc.result
new file mode 100644
index 00000000..eaf5b87e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_desc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id < 4 ORDER BY ids.id DESC LIMIT 3;
+id
+3
+2
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_asc.result
new file mode 100644
index 00000000..e1e96c9c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_asc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id <= 4 ORDER BY ids.id ASC LIMIT 3;
+id
+1
+2
+3
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_desc.result
new file mode 100644
index 00000000..e8124ca1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_range_primary_less_than_or_equal_desc.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+SET NAMES UTF8;
+CREATE TABLE ids (
+id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+SELECT * FROM ids WHERE ids.id <= 4 ORDER BY ids.id DESC LIMIT 3;
+id
+4
+3
+2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint.result
new file mode 100644
index 00000000..77b32101
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id BIGINT,
+value BIGINT,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+SELECT * FROM ids;
+id value
+-16 1
+-8 2
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+16 -1
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+id value
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint_unsigned.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint_unsigned.result
new file mode 100644
index 00000000..b0004a3c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_bigint_unsigned.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id BIGINT UNSIGNED,
+value BIGINT UNSIGNED,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+SELECT * FROM ids;
+id value
+1 1
+2 2
+4 3
+8 4
+16 5
+32 6
+64 7
+128 8
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+id value
+4 3
+8 4
+16 5
+32 6
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_double.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_double.result
new file mode 100644
index 00000000..862a314c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_double.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id DOUBLE,
+value DOUBLE,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1.1, 16.16);
+INSERT INTO ids VALUES ( -2.2, 8.8);
+INSERT INTO ids VALUES ( -4.4, 4.4);
+INSERT INTO ids VALUES ( -8.8, 2.2);
+INSERT INTO ids VALUES (-16.6, 1.1);
+INSERT INTO ids VALUES ( 16.6, -1.1);
+INSERT INTO ids VALUES ( 8.8, -2.2);
+INSERT INTO ids VALUES ( 4.4, -4.4);
+INSERT INTO ids VALUES ( 2.2, -8.8);
+INSERT INTO ids VALUES ( 1.1, -16.16);
+SELECT * FROM ids;
+id value
+-16.6 1.1
+-8.8 2.2
+-4.4 4.4
+-2.2 8.8
+-1.1 16.16
+1.1 -16.16
+2.2 -8.8
+4.4 -4.4
+8.8 -2.2
+16.6 -1.1
+SELECT * FROM ids WHERE id BETWEEN -4.5 AND 8.9;
+id value
+-4.4 4.4
+-2.2 8.8
+-1.1 16.16
+1.1 -16.16
+2.2 -8.8
+4.4 -4.4
+8.8 -2.2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_float.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_float.result
new file mode 100644
index 00000000..04d44130
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_float.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id FLOAT,
+value FLOAT,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1.1, 16.16);
+INSERT INTO ids VALUES ( -2.2, 8.8);
+INSERT INTO ids VALUES ( -4.4, 4.4);
+INSERT INTO ids VALUES ( -8.8, 2.2);
+INSERT INTO ids VALUES (-16.6, 1.1);
+INSERT INTO ids VALUES ( 16.6, -1.1);
+INSERT INTO ids VALUES ( 8.8, -2.2);
+INSERT INTO ids VALUES ( 4.4, -4.4);
+INSERT INTO ids VALUES ( 2.2, -8.8);
+INSERT INTO ids VALUES ( 1.1, -16.16);
+SELECT * FROM ids;
+id value
+-16.6 1.1
+-8.8 2.2
+-4.4 4.4
+-2.2 8.8
+-1.1 16.16
+1.1 -16.16
+2.2 -8.8
+4.4 -4.4
+8.8 -2.2
+16.6 -1.1
+SELECT * FROM ids WHERE id BETWEEN -4.5 AND 8.9;
+id value
+-4.4 4.4
+-2.2 8.8
+-1.1 16.16
+1.1 -16.16
+2.2 -8.8
+4.4 -4.4
+8.8 -2.2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int.result
new file mode 100644
index 00000000..8d3f6f7f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT,
+value INT,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+SELECT * FROM ids;
+id value
+-16 1
+-8 2
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+16 -1
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+id value
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int_unsigned.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int_unsigned.result
new file mode 100644
index 00000000..d09f97e0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_int_unsigned.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT UNSIGNED,
+value INT UNSIGNED,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+SELECT * FROM ids;
+id value
+1 1
+2 2
+4 3
+8 4
+16 5
+32 6
+64 7
+128 8
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+id value
+4 3
+8 4
+16 5
+32 6
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint.result
new file mode 100644
index 00000000..5242f10f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id MEDIUMINT,
+value MEDIUMINT,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+SELECT * FROM ids;
+id value
+-16 1
+-8 2
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+16 -1
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+id value
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint_unsigned.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint_unsigned.result
new file mode 100644
index 00000000..41d9c0eb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_mediumint_unsigned.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id MEDIUMINT UNSIGNED,
+value MEDIUMINT UNSIGNED,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+SELECT * FROM ids;
+id value
+1 1
+2 2
+4 3
+8 4
+16 5
+32 6
+64 7
+128 8
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+id value
+4 3
+8 4
+16 5
+32 6
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint.result
new file mode 100644
index 00000000..e34b7b7d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id SMALLINT,
+value SMALLINT,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+SELECT * FROM ids;
+id value
+-16 1
+-8 2
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+16 -1
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+id value
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint_unsigned.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint_unsigned.result
new file mode 100644
index 00000000..9014f9af
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_smallint_unsigned.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id SMALLINT UNSIGNED,
+value SMALLINT UNSIGNED,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+SELECT * FROM ids;
+id value
+1 1
+2 2
+4 3
+8 4
+16 5
+32 6
+64 7
+128 8
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+id value
+4 3
+8 4
+16 5
+32 6
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint.result
new file mode 100644
index 00000000..63b27fdd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint.result
@@ -0,0 +1,38 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id TINYINT,
+value TINYINT,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+SELECT * FROM ids;
+id value
+-16 1
+-8 2
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+16 -1
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+id value
+-4 4
+-2 8
+-1 16
+1 -16
+2 -8
+4 -4
+8 -2
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint_unsigned.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint_unsigned.result
new file mode 100644
index 00000000..412b9b7c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_tinyint_unsigned.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id TINYINT UNSIGNED,
+value TINYINT UNSIGNED,
+KEY (id, value)
+);
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+SELECT * FROM ids;
+id value
+1 1
+2 2
+4 3
+8 4
+16 5
+32 6
+64 7
+128 8
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+id value
+4 3
+8 4
+16 5
+32 6
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar.result
new file mode 100644
index 00000000..c08522d0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id VARCHAR(5),
+value VARCHAR(10),
+KEY (id, value)
+) DEFAULT CHARSET=utf8 COLLATE utf8_bin;
+INSERT INTO ids VALUES ("abc", "Abc");
+INSERT INTO ids VALUES ("acd", "aBc");
+INSERT INTO ids VALUES ("ade", "abC");
+INSERT INTO ids VALUES ("aef", "abc");
+INSERT INTO ids VALUES ("ABC", "aBC");
+INSERT INTO ids VALUES ("ACD", "AbC");
+INSERT INTO ids VALUES ("ADE", "ABc");
+INSERT INTO ids VALUES ("AEF", "ABC");
+SELECT * FROM ids;
+id value
+ABC aBC
+ACD AbC
+ADE ABc
+AEF ABC
+abc Abc
+acd aBc
+ade abC
+aef abc
+SELECT * FROM ids WHERE id BETWEEN "ab" AND "ad";
+id value
+abc Abc
+acd aBc
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar_collation.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar_collation.result
new file mode 100644
index 00000000..9882f2b1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_multiple_varchar_collation.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id VARCHAR(5),
+value VARCHAR(10),
+KEY (id, value)
+) DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
+INSERT INTO ids VALUES ("abc", "Abc");
+INSERT INTO ids VALUES ("acd", "aBc");
+INSERT INTO ids VALUES ("ade", "abC");
+INSERT INTO ids VALUES ("aef", "abc");
+INSERT INTO ids VALUES ("ABC", "aBC");
+INSERT INTO ids VALUES ("ACD", "AbC");
+INSERT INTO ids VALUES ("ADE", "ABc");
+INSERT INTO ids VALUES ("AEF", "ABC");
+SELECT * FROM ids;
+id value
+abc Abc
+acd aBc
+ade abC
+aef abc
+ABC aBC
+ACD AbC
+ADE ABc
+AEF ABC
+SELECT * FROM ids WHERE id BETWEEN "ab" AND "ad";
+id value
+abc Abc
+ABC aBC
+acd aBc
+ACD AbC
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_int.result
new file mode 100644
index 00000000..67f1f4f8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_int.result
@@ -0,0 +1,55 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT,
+KEY (id)
+);
+INSERT INTO ids VALUES (1);
+INSERT INTO ids SELECT id + 1 FROM ids;
+INSERT INTO ids SELECT id + 2 FROM ids;
+INSERT INTO ids SELECT id + 4 FROM ids;
+INSERT INTO ids SELECT id + 8 FROM ids;
+INSERT INTO ids SELECT id + 16 FROM ids;
+SELECT * FROM ids;
+id
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+SELECT * FROM ids WHERE id BETWEEN 10 AND 16;
+id
+10
+11
+12
+13
+14
+15
+16
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_varchar.result
new file mode 100644
index 00000000..2cdde6c4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_normal_varchar.result
@@ -0,0 +1,55 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id VARCHAR(10),
+KEY (id)
+);
+INSERT INTO ids VALUES ("1");
+INSERT INTO ids SELECT id + "1" FROM ids;
+INSERT INTO ids SELECT id + "2" FROM ids;
+INSERT INTO ids SELECT id + "4" FROM ids;
+INSERT INTO ids SELECT id + "8" FROM ids;
+INSERT INTO ids SELECT id + "16" FROM ids;
+SELECT * FROM ids;
+id
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+SELECT * FROM ids WHERE id BETWEEN "10" AND "16";
+id
+10
+11
+12
+13
+14
+15
+16
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_int.result
new file mode 100644
index 00000000..23f63d2f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_int.result
@@ -0,0 +1,55 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT,
+PRIMARY KEY (id)
+);
+INSERT INTO ids VALUES (1);
+INSERT INTO ids SELECT id + 1 FROM ids;
+INSERT INTO ids SELECT id + 2 FROM ids;
+INSERT INTO ids SELECT id + 4 FROM ids;
+INSERT INTO ids SELECT id + 8 FROM ids;
+INSERT INTO ids SELECT id + 16 FROM ids;
+SELECT * FROM ids;
+id
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+SELECT * FROM ids WHERE id BETWEEN 10 AND 16;
+id
+10
+11
+12
+13
+14
+15
+16
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_varchar.result
new file mode 100644
index 00000000..7fa17bd7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_read_primary_varchar.result
@@ -0,0 +1,55 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id VARCHAR(10),
+PRIMARY KEY (id)
+);
+INSERT INTO ids VALUES ("1");
+INSERT INTO ids SELECT id + "1" FROM ids;
+INSERT INTO ids SELECT id + "2" FROM ids;
+INSERT INTO ids SELECT id + "4" FROM ids;
+INSERT INTO ids SELECT id + "8" FROM ids;
+INSERT INTO ids SELECT id + "16" FROM ids;
+SELECT * FROM ids;
+id
+1
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+2
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+3
+30
+31
+32
+4
+5
+6
+7
+8
+9
+SELECT * FROM ids WHERE id BETWEEN "10" AND "16";
+id
+10
+11
+12
+13
+14
+15
+16
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_all.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_all.result
new file mode 100644
index 00000000..f2a0b28b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_all.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int,
+UNIQUE KEY (id)
+);
+INSERT INTO ids VALUES (1);
+DELETE FROM ids;
+INSERT INTO ids VALUES (1);
+SELECT * FROM ids;
+id
+1
+INSERT INTO ids VALUES (1);
+ERROR 23000: Duplicate entry '1' for key 'id'
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_by_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_by_primary_key.result
new file mode 100644
index 00000000..4e10cf72
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_delete_by_primary_key.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS users;
+CREATE TABLE users (
+id int PRIMARY KEY,
+name varchar(100) NOT NULL,
+UNIQUE KEY name (name)
+) DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES (1, "Alice");
+DELETE FROM users WHERE id = 1;
+INSERT INTO users VALUES (1, "Alice");
+SELECT * FROM users;
+id name
+1 Alice
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_insert_after_error.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_insert_after_error.result
new file mode 100644
index 00000000..7b2c0b86
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_insert_after_error.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS users;
+CREATE TABLE users (
+id int PRIMARY KEY,
+name varchar(100) NOT NULL,
+UNIQUE KEY name (name)
+) DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES (1, "Alice");
+INSERT INTO users VALUES (1, "Bob");
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+INSERT INTO users VALUES (2, "Bob");
+SELECT * FROM users;
+id name
+1 Alice
+2 Bob
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_search_after_duplicated.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_search_after_duplicated.result
new file mode 100644
index 00000000..1d9d5fbb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_search_after_duplicated.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS users;
+CREATE TABLE users (
+id int PRIMARY KEY,
+name varchar(100) NOT NULL,
+UNIQUE KEY (name)
+) DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES (1, "Alice");
+INSERT INTO users VALUES (2, "Bob");
+INSERT INTO users VALUES (3, "Bob");
+ERROR 23000: Duplicate entry 'Bob' for key 'name'
+SELECT * FROM users;
+id name
+1 Alice
+2 Bob
+SELECT * FROM users WHERE name = "Bob";
+id name
+2 Bob
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_varchar.result
new file mode 100644
index 00000000..155cdf15
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_unique_varchar.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS users;
+CREATE TABLE users (
+name varchar(100) NOT NULL,
+UNIQUE KEY name (name)
+) DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES ("Alice");
+INSERT INTO users VALUES ("Bob");
+SELECT * FROM users;
+name
+Alice
+Bob
+SELECT * FROM users WHERE name = "aLiCe";
+name
+Alice
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_update_multiple_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_update_multiple_column.result
new file mode 100644
index 00000000..9165ca26
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_update_multiple_column.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS scores;
+SET NAMES utf8;
+CREATE TABLE scores (
+deleted BOOLEAN,
+value INT,
+INDEX (deleted, value)
+);
+INSERT INTO scores VALUES (FALSE, 1);
+INSERT INTO scores VALUES (FALSE, 1);
+INSERT INTO scores VALUES (FALSE, 2);
+SELECT count(*) FROM scores WHERE deleted = FALSE;
+count(*)
+3
+UPDATE scores SET deleted = TRUE WHERE value = 1;
+SELECT count(*) FROM scores WHERE deleted = FALSE;
+count(*)
+1
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/index_update_single_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/index_update_single_column.result
new file mode 100644
index 00000000..b283af17
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/index_update_single_column.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS scores;
+SET NAMES utf8;
+CREATE TABLE scores (
+value INT,
+INDEX (value)
+);
+INSERT INTO scores VALUES (21);
+INSERT INTO scores VALUES (21);
+INSERT INTO scores VALUES (22);
+SELECT count(*) FROM scores WHERE value >= 20;
+count(*)
+3
+UPDATE scores SET value = 11 WHERE value = 21;
+SELECT count(*) FROM scores WHERE value >= 20;
+count(*)
+1
+DROP TABLE scores;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_plugins.result.in b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_plugins.result.in
new file mode 100644
index 00000000..f1020453
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_plugins.result.in
@@ -0,0 +1,4 @@
+select PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TYPE
+from information_schema.plugins where plugin_name = "Mroonga";
+PLUGIN_NAME PLUGIN_VERSION PLUGIN_TYPE
+Mroonga @MRN_PLUGIN_VERSION@ STORAGE ENGINE
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_none.result b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_none.result
new file mode 100644
index 00000000..c23dab5e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_none.result
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY
+);
+SELECT AUTO_INCREMENT
+FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME = "ids";
+AUTO_INCREMENT
+NULL
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_use.result b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_use.result
new file mode 100644
index 00000000..96d1b0ad
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_auto_increment_use.result
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT AUTO_INCREMENT PRIMARY KEY
+);
+SELECT AUTO_INCREMENT
+FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME = "ids";
+AUTO_INCREMENT
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_data_length.result b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_data_length.result
new file mode 100644
index 00000000..3600c920
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/information_schema_tables_data_length.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT COUNT(*)
+FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_NAME = "diaries" AND DATA_LENGTH > 0;
+COUNT(*)
+1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/insert_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/insert_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..f8d41bb7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/insert_TODO_SPLIT_ME.result
@@ -0,0 +1,78 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 tinyint);
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 smallint);
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 mediumint);
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 int);
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 bigint);
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 float);
+insert into t1 values(0.5);
+select * from t1;
+c1
+0.5
+drop table t1;
+create table t1 (c1 double);
+insert into t1 values(0.5);
+select * from t1;
+c1
+0.5
+drop table t1;
+create table t1 (c1 date);
+insert into t1 values("2010/03/26");
+select * from t1;
+c1
+2010-03-26
+drop table t1;
+create table t1 (c1 time);
+insert into t1 values("11:22:33");
+select * from t1;
+c1
+11:22:33
+drop table t1;
+create table t1 (c1 year);
+insert into t1 values("2010");
+select * from t1;
+c1
+2010
+drop table t1;
+create table t1 (c1 datetime);
+insert into t1 values("2010/03/26 11:22:33");
+select * from t1;
+c1
+2010-03-26 11:22:33
+drop table t1;
+create table t1 (c1 int primary key, c2 int);
+insert into t1 values(1,100);
+select * from t1;
+c1 c2
+1 100
+insert into t1 values(1,200);
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+select * from t1;
+c1 c2
+1 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/insert_delayed.result b/storage/mroonga/mysql-test/mroonga/storage/r/insert_delayed.result
new file mode 100644
index 00000000..eb11e26e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/insert_delayed.result
@@ -0,0 +1,9 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT DELAYED INTO ids (id) VALUES (1);
+ERROR HY000: DELAYED option not supported for table 'ids'
+SELECT * FROM ids;
+id
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.result b/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.result
new file mode 100644
index 00000000..0d2c9dd7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS numbers;
+CREATE TABLE numbers (
+id INT,
+count INT,
+UNIQUE (id)
+);
+INSERT INTO numbers (id, count) VALUES (1, 1) ON DUPLICATE KEY UPDATE count = 2;
+INSERT INTO numbers (id, count) VALUES (1, 3) ON DUPLICATE KEY UPDATE count = 4;
+SELECT * FROM numbers;
+id count
+1 4
+INSERT INTO numbers (id, count) VALUES (2, 1) ON DUPLICATE KEY UPDATE count = 2;
+INSERT INTO numbers (id, count) VALUES (2, 3) ON DUPLICATE KEY UPDATE count = 4;
+SELECT * FROM numbers;
+id count
+1 4
+2 4
+DROP TABLE numbers;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_primary_key.result
new file mode 100644
index 00000000..94421a5c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_primary_key.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+day DATE PRIMARY KEY,
+title TEXT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-14", "clear day")
+ON DUPLICATE KEY UPDATE title = "clear day (duplicated)";
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-14", "rainy day")
+ON DUPLICATE KEY UPDATE title = "rainy day (duplicated)";
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-15", "cloudy day")
+ON DUPLICATE KEY UPDATE title = "cloudy day (duplicated)";
+SELECT * FROM diaries;
+day title
+2012-02-14 rainy day (duplicated)
+2012-02-15 cloudy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_unique_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_unique_key.result
new file mode 100644
index 00000000..1ef6f1f2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/insert_on_duplicate_key_update_unique_key.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+day DATE,
+title TEXT,
+UNIQUE KEY day (day)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-14", "clear day1")
+ON DUPLICATE KEY UPDATE title = "clear day1 (duplicated)";
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-14", "clear day2")
+ON DUPLICATE KEY UPDATE title = "clear day2 (duplicated)";
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-14", "clear day3")
+ON DUPLICATE KEY UPDATE title = "clear day3 (duplicated)";
+INSERT INTO diaries (day, title)
+VALUES ("2012-02-15", "cloudy day")
+ON DUPLICATE KEY UPDATE title = "cloudy day (duplicated)";
+SELECT * FROM diaries;
+id day title
+1 2012-02-14 clear day3 (duplicated)
+4 2012-02-15 cloudy day
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/insert_virtual_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/insert_virtual_column.result
new file mode 100644
index 00000000..624ac00d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/insert_virtual_column.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (c1 int, _id int);
+SET sql_mode="";
+INSERT INTO t1 (c1,_id) VALUES (1,1);
+Warnings:
+Warning 1265 Data truncated for column '_id' at row 1
+SET sql_mode="STRICT_ALL_TABLES";
+INSERT INTO t1 (c1,_id) VALUES (4,1);
+ERROR 01000: Data truncated for column '_id' at row 1
+SELECT * FROM t1;
+c1 _id
+1 1
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/like_unicode_ci.result b/storage/mroonga/mysql-test/mroonga/storage/r/like_unicode_ci.result
new file mode 100644
index 00000000..1cc1d924
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/like_unicode_ci.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS terms;
+SET NAMES utf8;
+CREATE TABLE terms (
+content varchar(64) NOT NULL COLLATE 'utf8_unicode_ci',
+INDEX (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO terms VALUES ('track');
+INSERT INTO terms VALUES ('trackback');
+SELECT * FROM terms WHERE content LIKE 'TRACK%';
+content
+track
+trackback
+DROP TABLE terms;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/lock_tables_read.result b/storage/mroonga/mysql-test/mroonga/storage/r/lock_tables_read.result
new file mode 100644
index 00000000..4e1db465
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/lock_tables_read.result
@@ -0,0 +1,7 @@
+DROP TABLE IF EXISTS counts;
+CREATE TABLE counts (
+id INT PRIMARY KEY AUTO_INCREMENT
+);
+LOCK TABLES counts READ;
+UNLOCK TABLES;
+DROP TABLE counts;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_multithread.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_multithread.result
new file mode 100644
index 00000000..c09ec340
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_multithread.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT INDEX ft(title)
+);
+INSERT INTO diaries VALUES("Hello mroonga!");
+INSERT INTO diaries VALUES("It's funny.");
+INSERT INTO diaries VALUES("Happy birthday!");
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+SELECT COUNT(*) FROM diaries WHERE MATCH(title) AGAINST("mroonga" IN BOOLEAN MODE);
+COUNT(*)
+1
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_single_thread.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_single_thread.result
new file mode 100644
index 00000000..c09ec340
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_after_insert_single_thread.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT INDEX ft(title)
+);
+INSERT INTO diaries VALUES("Hello mroonga!");
+INSERT INTO diaries VALUES("It's funny.");
+INSERT INTO diaries VALUES("Happy birthday!");
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+SELECT COUNT(*) FROM diaries WHERE MATCH(title) AGAINST("mroonga" IN BOOLEAN MODE);
+COUNT(*)
+1
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_disabled.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_disabled.result
new file mode 100644
index 00000000..8d29e042
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_disabled.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, "はれ", "天気がよいのは今日までみたい。");
+SET mroonga_enable_optimization=FALSE;
+SELECT COUNT(*) FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE);
+COUNT(*)
+4
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+SET mroonga_enable_optimization=TRUE;
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_and.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_and.result
new file mode 100644
index 00000000..26ca6de7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_and.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT,
+age INT,
+INDEX (id, age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id, age) VALUES (1, 28);
+INSERT INTO users (id, age) VALUES (1, 28);
+INSERT INTO users (id, age) VALUES (1, 29);
+INSERT INTO users (id, age) VALUES (2, 29);
+INSERT INTO users (id, age) VALUES (2, 29);
+INSERT INTO users (id, age) VALUES (3, 29);
+SELECT COUNT(*) FROM users WHERE id = 2 AND age = 29;
+COUNT(*)
+2
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_between.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_between.result
new file mode 100644
index 00000000..c4b1dbf7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_between.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (32),(33),(34),(35),(36),(37);
+SELECT COUNT(*) FROM users WHERE age BETWEEN 28 AND 30;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_equal.result
new file mode 100644
index 00000000..2bbcfe75
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_equal.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+SELECT COUNT(*) FROM users WHERE age = 29;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_boolean_mode.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_boolean_mode.result
new file mode 100644
index 00000000..6ec4d774
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_boolean_mode.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos (content) VALUES ('Groonga is good.');
+INSERT INTO memos (content) VALUES ('Groonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga is good.');
+INSERT INTO memos (content) VALUES ('Mroonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga uses Groonga.');
+SELECT COUNT(*) FROM memos
+WHERE MATCH(content) AGAINST('+Groonga' IN BOOLEAN MODE);
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_natural_language_mode.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_natural_language_mode.result
new file mode 100644
index 00000000..36a19589
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_full_text_search_in_natural_language_mode.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+CREATE TABLE memos (
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO memos (content) VALUES ('Groonga is good.');
+INSERT INTO memos (content) VALUES ('Groonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga is good.');
+INSERT INTO memos (content) VALUES ('Mroonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga uses Groonga.');
+SELECT COUNT(*) FROM memos
+WHERE MATCH(content) AGAINST('Groonga');
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater.result
new file mode 100644
index 00000000..4eba1922
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (1),(2),(3),(4),(5),(6);
+SELECT COUNT(*) FROM users WHERE age > 29;
+COUNT(*)
+2
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater_equal.result
new file mode 100644
index 00000000..4de49651
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_greater_equal.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (1),(2),(3),(4),(5),(6);
+SELECT COUNT(*) FROM users WHERE age >= 29;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less.result
new file mode 100644
index 00000000..a57a3b8f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (32),(33),(34),(35),(36),(37);
+SELECT COUNT(*) FROM users WHERE age < 29;
+COUNT(*)
+2
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less_equal.result
new file mode 100644
index 00000000..c770b63d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_less_equal.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (32),(33),(34),(35),(36),(37);
+SELECT COUNT(*) FROM users WHERE age <= 29;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_not_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_not_equal.result
new file mode 100644
index 00000000..a1a123e7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_not_equal.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+SELECT COUNT(*) FROM users WHERE age <> 29;
+COUNT(*)
+2
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 2
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_view.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_view.result
new file mode 100644
index 00000000..407347a4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_index_view.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS diaries, users;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+user_id INT NOT NULL,
+title VARCHAR(45) NOT NULL,
+KEY (user_id),
+FULLTEXT INDEX title_index (title)
+) DEFAULT CHARSET=UTF8;
+CREATE TABLE users (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name VARCHAR(45) NOT NULL,
+INDEX (name)
+) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
+INSERT INTO users (id, name) VALUES (1, "Alice"), (2, "Bob");
+INSERT INTO diaries (user_id, title) VALUES (1, "survey");
+INSERT INTO diaries (user_id, title) VALUES (2, "groonga (1)");
+INSERT INTO diaries (user_id, title) VALUES (2, "groonga (2)");
+CREATE VIEW articles AS
+SELECT diaries.user_id AS user_id,
+diaries.title AS title,
+users.name AS name
+FROM diaries, users
+WHERE diaries.user_id = users.id;
+SELECT COUNT(*) FROM articles WHERE name = 'Bob';
+COUNT(*)
+2
+DROP VIEW articles;
+DROP TABLE diaries, users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_multiple_conditions.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_multiple_conditions.result
new file mode 100644
index 00000000..39a0f0bd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_multiple_conditions.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT,
+age INT,
+INDEX (age)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id, age) VALUES (1, 29);
+INSERT INTO users (id, age) VALUES (2, 29);
+INSERT INTO users (id, age) VALUES (3, 29);
+SELECT COUNT(*) FROM users WHERE id = 3 AND age = 29;
+COUNT(*)
+1
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_between.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_between.result
new file mode 100644
index 00000000..26c8b6a9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_between.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+INSERT INTO users (id) VALUES (32),(33),(34),(35),(36),(37);
+SELECT COUNT(*) FROM users WHERE id BETWEEN 2 AND 4;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_equal.result
new file mode 100644
index 00000000..713a19dd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_equal.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+SELECT COUNT(*) FROM users WHERE id = 3;
+COUNT(*)
+1
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater.result
new file mode 100644
index 00000000..fe9de9e6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+INSERT INTO users (id) VALUES (-1),(-2),(-3),(-4);
+SELECT COUNT(*) FROM users WHERE id > 3;
+COUNT(*)
+2
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater_equal.result
new file mode 100644
index 00000000..2fa5213e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_greater_equal.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+INSERT INTO users (id) VALUES (-1),(-2),(-3),(-4);
+SELECT COUNT(*) FROM users WHERE id >= 3;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less.result
new file mode 100644
index 00000000..05afd7e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+SELECT COUNT(*) FROM users WHERE id < 3;
+COUNT(*)
+2
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less_equal.result
new file mode 100644
index 00000000..200f89d3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_less_equal.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+SELECT COUNT(*) FROM users WHERE id <= 3;
+COUNT(*)
+3
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_not_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_not_equal.result
new file mode 100644
index 00000000..1b253a8e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_count_skip_primary_key_not_equal.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS users;
+FLUSH STATUS;
+CREATE TABLE users (
+id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+SELECT COUNT(*) FROM users WHERE id <> 3;
+COUNT(*)
+4
+SHOW STATUS LIKE 'mroonga_count_skip';
+Variable_name Value
+Mroonga_count_skip 0
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_disabled.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_disabled.result
new file mode 100644
index 00000000..dcf0f3ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_disabled.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SET mroonga_enable_optimization=FALSE;
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+month = 11
+ORDER BY day LIMIT 1,2;
+id year month day title content
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+4 2011 11 12 帰り道 今日は天気がよくてよかった。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+SET mroonga_enable_optimization=TRUE;
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_multiple_match_againsts.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_multiple_match_againsts.result
new file mode 100644
index 00000000..124a7750
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_multiple_match_againsts.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(title),
+FULLTEXT INDEX(content)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(5, "title 1", "content a");
+INSERT INTO memos VALUES(12, "title 1", "content a");
+INSERT INTO memos VALUES(10, "title 1", "content a");
+INSERT INTO memos VALUES(4, "title 2", "content b");
+INSERT INTO memos VALUES(6, "title 2", "content b");
+INSERT INTO memos VALUES(1, "title 2", "content b");
+INSERT INTO memos VALUES(11, "title 1-a", "content a-1");
+INSERT INTO memos VALUES(3, "title 2-b", "content a-2");
+INSERT INTO memos VALUES(2, "title 2-c", "content a-3");
+INSERT INTO memos VALUES(8, "title 1-a", "content b-1");
+INSERT INTO memos VALUES(9, "title 2-b", "content b-2");
+INSERT INTO memos VALUES(7, "title 2-c", "content b-3");
+SELECT * FROM memos
+WHERE MATCH(title) AGAINST("+1" IN BOOLEAN MODE) AND
+MATCH(content) AGAINST("+a" IN BOOLEAN MODE)
+ORDER BY id
+LIMIT 1,3;
+id title content
+10 title 1 content a
+11 title 1-a content a-1
+12 title 1 content a
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_no_limit.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_no_limit.result
new file mode 100644
index 00000000..5a0ea86c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_not_optimized_no_limit.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ORDER BY day;
+id year month day title content
+7 2011 12 2 初雪 今日の天気は雪!
+1 2011 11 9 Hello 今日からはじめました。
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+4 2011 11 12 帰り道 今日は天気がよくてよかった。
+5 2011 11 13 はれ 天気がよいのは今日までみたい。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_cp932.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_cp932.result
new file mode 100644
index 00000000..d58c3cf2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_cp932.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES CP932;
+CREATE TABLE memos (
+ʎq INT UNSIGNED,
+e TEXT,
+FULLTEXT INDEX(e),
+KEY(ʎq)
+) DEFAULT CHARSET CP932;
+INSERT INTO memos VALUES(2, "͎RoB");
+INSERT INTO memos VALUES(3, "̓T{eB");
+INSERT INTO memos VALUES(1, "͓VC悭Ă悩B");
+SELECT * FROM memos
+WHERE MATCH(e) AGAINST("" IN BOOLEAN MODE)
+ORDER BY ʎq
+LIMIT 1;
+ʎq e
+1 ͓VC悭Ă悩B
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between.result
new file mode 100644
index 00000000..f1cc14b4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date BETWEEN "2011-11-11 12:23:31" AND "2011-11-11 12:23:33"
+ ORDER BY id LIMIT 1,2;
+id date content
+3 2011-11-11 12:23:32 I will do something today!
+4 2011-11-11 12:23:33 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between_over.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between_over.result
new file mode 100644
index 00000000..0374f500
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_between_over.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date BETWEEN "2011-11-11 12:23:31" AND "2011-11-11 12:23:43"
+ ORDER BY id LIMIT 1,2;
+id date content
+3 2011-11-11 12:23:32 I will do something today!
+4 2011-11-11 12:23:33 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_equal.result
new file mode 100644
index 00000000..4bc3f9d5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_equal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:34", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:34", "Tomorrow will be fine.");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:34", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:34", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date = "2011-11-11 12:23:34"
+ ORDER BY id LIMIT 1,2;
+id date content
+3 2011-11-11 12:23:34 I will do something today!
+4 2011-11-11 12:23:34 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than.result
new file mode 100644
index 00000000..56629777
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date > "2011-11-11 12:23:31"
+ ORDER BY id LIMIT 1,2;
+id date content
+4 2011-11-11 12:23:33 I don't want to anything today...
+5 2011-11-11 12:23:34 I'm sleepy today.
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than_or_equal.result
new file mode 100644
index 00000000..b03fe20f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_greater_than_or_equal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date >= "2011-11-11 12:23:31"
+ ORDER BY id LIMIT 1,2;
+id date content
+3 2011-11-11 12:23:32 I will do something today!
+4 2011-11-11 12:23:33 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than.result
new file mode 100644
index 00000000..c25f2a56
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date < "2011-11-11 12:23:33"
+ ORDER BY id LIMIT 1,2;
+id date content
+2 2011-11-11 12:23:31 Today's lucky item is flower!
+3 2011-11-11 12:23:32 I will do something today!
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than_or_equal.result
new file mode 100644
index 00000000..ef93bf8b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_datetime_less_than_or_equal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+date DATETIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(date)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+date <= "2011-11-11 12:23:33"
+ ORDER BY id LIMIT 1,2;
+id date content
+2 2011-11-11 12:23:31 Today's lucky item is flower!
+3 2011-11-11 12:23:32 I will do something today!
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_duplicated_order_by_columns.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_duplicated_order_by_columns.result
new file mode 100644
index 00000000..9ea8ea40
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_duplicated_order_by_columns.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS ids;
+FLUSH STATUS;
+SET NAMES utf8mb4;
+CREATE TABLE ids (
+id int PRIMARY KEY,
+text varchar(32),
+FULLTEXT INDEX (text)
+) DEFAULT CHARSET=utf8mb4;
+INSERT INTO ids VALUES (1, 'first');
+SELECT * FROM ids
+WHERE MATCH(text) AGAINST('+first' IN BOOLEAN MODE)
+ORDER BY id, id
+LIMIT 1;
+id text
+1 first
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_name.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_name.result
new file mode 100644
index 00000000..f20089f0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_name.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES utf8;
+CREATE TABLE memos (
+id int PRIMARY KEY,
+tag ENUM('Groonga', 'Mroonga'),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(tag),
+KEY(id)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES(1, 'Groonga', 'Groonga is great!');
+INSERT INTO memos VALUES(2, 'Mroonga', 'Mroonga is great!');
+INSERT INTO memos VALUES(3, 'Mroonga', 'Mroonga is a MySQL storage engine.');
+INSERT INTO memos VALUES(4, 'Mroonga', 'Mroonga is based on Groonga.');
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("+Groonga" IN BOOLEAN MODE) AND
+tag = 'Mroonga'
+ ORDER BY id LIMIT 1;
+id tag content
+4 Mroonga Mroonga is based on Groonga.
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_value.result
new file mode 100644
index 00000000..88ec9dd8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_enum_value.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES utf8;
+CREATE TABLE memos (
+id int PRIMARY KEY,
+tag ENUM('Groonga', 'Mroonga'),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(tag),
+KEY(id)
+) DEFAULT CHARSET=utf8;
+INSERT INTO memos VALUES(1, 'Groonga', 'Groonga is great!');
+INSERT INTO memos VALUES(2, 'Mroonga', 'Mroonga is great!');
+INSERT INTO memos VALUES(3, 'Mroonga', 'Mroonga is a MySQL storage engine.');
+INSERT INTO memos VALUES(4, 'Mroonga', 'Mroonga is based on Groonga.');
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("+Groonga" IN BOOLEAN MODE) AND
+tag = 2
+ORDER BY id LIMIT 1;
+id tag content
+4 Mroonga Mroonga is based on Groonga.
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_have_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_have_primary_key.result
new file mode 100644
index 00000000..5c18e22d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_have_primary_key.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 11, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(6, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("今日 天気" IN BOOLEAN MODE) ORDER BY day LIMIT 0,5;
+id year month day title content
+5 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+6 2011 12 2 初雪 今日の天気は雪!
+1 2011 11 9 Hello 今日からはじめました。
+2 2011 11 10 天気 明日の富士山の天気について
+4 2011 11 11 帰り道 今日は天気がよくてよかった。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between.result
new file mode 100644
index 00000000..ed86c0e1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(id)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "Today is fine.");
+INSERT INTO memos VALUES(2, "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "I will do something today!");
+INSERT INTO memos VALUES(4, "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+id BETWEEN 2 AND 4
+ORDER BY id LIMIT 1,2;
+id content
+3 I will do something today!
+4 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between_over.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between_over.result
new file mode 100644
index 00000000..a18e2a15
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_between_over.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(id)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "Today is fine.");
+INSERT INTO memos VALUES(2, "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "I will do something today!");
+INSERT INTO memos VALUES(4, "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+id BETWEEN 2 AND 6
+ORDER BY id LIMIT 1,2;
+id content
+3 I will do something today!
+4 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_equal.result
new file mode 100644
index 00000000..634fe89c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_equal.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+month = 11
+ORDER BY day LIMIT 1,2;
+id year month day title content
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+4 2011 11 12 帰り道 今日は天気がよくてよかった。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than.result
new file mode 100644
index 00000000..22305c70
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+day > 10
+ORDER BY day LIMIT 1,2;
+id year month day title content
+4 2011 11 12 帰り道 今日は天気がよくてよかった。
+5 2011 11 13 はれ 天気がよいのは今日までみたい。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than_or_equal.result
new file mode 100644
index 00000000..439f453d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_greater_than_or_equal.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+day >= 10
+ORDER BY day LIMIT 1,2;
+id year month day title content
+4 2011 11 12 帰り道 今日は天気がよくてよかった。
+5 2011 11 13 はれ 天気がよいのは今日までみたい。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than.result
new file mode 100644
index 00000000..51ec2fde
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+day < 12
+ORDER BY day LIMIT 1,2;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than_or_equal.result
new file mode 100644
index 00000000..3c4f3973
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_int_less_than_or_equal.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+day <= 12
+ORDER BY day LIMIT 1,2;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_primary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_primary_key.result
new file mode 100644
index 00000000..03364eb1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_primary_key.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 11, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(6, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("今日 天気" IN BOOLEAN MODE) ORDER BY day LIMIT 0,5;
+id year month day title content
+5 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+6 2011 12 2 初雪 今日の天気は雪!
+1 2011 11 9 Hello 今日からはじめました。
+2 2011 11 10 天気 明日の富士山の天気について
+4 2011 11 11 帰り道 今日は天気がよくてよかった。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_where_clause.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_where_clause.result
new file mode 100644
index 00000000..9730069c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_no_where_clause.result
@@ -0,0 +1,19 @@
+drop table if exists t1;
+flush status;
+create table t1 (c1 int primary key, c2 int, c3 text, _id int, key idx1(c2), fulltext index ft(c3)) default charset utf8;
+insert into t1 values(1,10,"aa ii uu ee oo",null);
+insert into t1 values(2,20,"ka ki ku ke ko",null);
+insert into t1 values(3,30,"ii si ii se ii",null);
+insert into t1 values(4,40,"ta ti tu te to",null);
+insert into t1 values(5,50,"aa ii uu ii oo",null);
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+select *, match(c3) against("ii") from t1 order by c1 desc limit 2;
+c1 c2 c3 _id match(c3) against("ii")
+5 50 aa ii uu ii oo 5 349526
+4 40 ta ti tu te to 4 0
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_asc.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_asc.result
new file mode 100644
index 00000000..a284f4dd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_asc.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ORDER BY day ASC LIMIT 1;
+id year month day title content
+7 2011 12 2 初雪 今日の天気は雪!
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_desc.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_desc.result
new file mode 100644
index 00000000..270d2639
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_desc.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ORDER BY day DESC LIMIT 1;
+id year month day title content
+5 2011 11 13 はれ 天気がよいのは今日までみたい。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_id.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_id.result
new file mode 100644
index 00000000..eb19384e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_id.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+_id INT,
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(NULL, 1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(NULL, 2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(NULL, 3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(NULL, 4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(NULL, 5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(NULL, 6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(NULL, 7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ORDER BY _id
+LIMIT 1;
+_id id year month day title content
+1 1 2011 11 9 Hello 今日からはじめました。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_match_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_match_against.result
new file mode 100644
index 00000000..80bd895a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_order_by_match_against.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ORDER BY MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+LIMIT 1;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_select_match_against.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_select_match_against.result
new file mode 100644
index 00000000..b3ed4bf6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_select_match_against.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT *, MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ORDER BY MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+LIMIT 1;
+id year month day title content MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+1 2011 11 9 Hello 今日からはじめました。 1
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between.result
new file mode 100644
index 00000000..793423f5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time BETWEEN "1:23:31" AND "1:23:33"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+3 01:23:32 I will do something today!
+4 01:23:33 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between_over.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between_over.result
new file mode 100644
index 00000000..f50417d1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_between_over.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time BETWEEN "1:23:31" AND "1:23:43"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+3 01:23:32 I will do something today!
+4 01:23:33 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_equal.result
new file mode 100644
index 00000000..26da3500
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_equal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:34", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:34", "Tomorrow will be fine.");
+INSERT INTO memos VALUES(3, "1:23:34", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:34", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time = "1:23:34"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+3 01:23:34 I will do something today!
+4 01:23:34 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than.result
new file mode 100644
index 00000000..342947cc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!" );
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time > "1:23:31"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+4 01:23:33 I don't want to anything today...
+5 01:23:34 I'm sleepy today.
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than_or_equal.result
new file mode 100644
index 00000000..adc4ec63
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_greater_than_or_equal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!" );
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time >= "1:23:31"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+3 01:23:32 I will do something today!
+4 01:23:33 I don't want to anything today...
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than.result
new file mode 100644
index 00000000..2881cc77
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time < "1:23:33"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+2 01:23:31 Today's lucky item is flower!
+3 01:23:32 I will do something today!
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than_or_equal.result
new file mode 100644
index 00000000..d1a9fc27
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_time_less_than_or_equal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE memos (
+id INT UNSIGNED NOT NULL,
+writing_time TIME,
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+writing_time <= "1:23:33"
+ ORDER BY id LIMIT 1,2;
+id writing_time content
+2 01:23:31 Today's lucky item is flower!
+3 01:23:32 I will do something today!
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_with_index.result
new file mode 100644
index 00000000..bff0d993
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_with_index.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(title),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+title = "hello"
+ ORDER BY day LIMIT 1;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_without_index.result
new file mode 100644
index 00000000..cc3173ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_varchar_equal_without_index.result
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS diaries;
+FLUSH STATUS;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(month),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+title = "hello"
+ ORDER BY day LIMIT 1;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between.result
new file mode 100644
index 00000000..5a1b1bda
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year BETWEEN "11" AND "2013" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id DESC LIMIT 1,2;
+id release_title release_year
+3 Mroonga 2.0 has been released 2012
+2 Rename Groonga storage engine to Mroonga 2011
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between_over.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between_over.result
new file mode 100644
index 00000000..b0ad41fb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_between_over.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year BETWEEN "11" AND "2015" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id DESC LIMIT 1,2;
+id release_title release_year
+4 Mroonga 3.0 has been released 2013
+3 Mroonga 2.0 has been released 2012
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_equal.result
new file mode 100644
index 00000000..08db6b38
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_equal.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine (code name Mroonga) 1.0 has been released", "11");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 1.11 has been released", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year = "11" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id DESC LIMIT 1,2;
+id release_title release_year
+2 Rename Groonga storage engine to Mroonga 2011
+1 Groonga storage engine (code name Mroonga) 1.0 has been released 2011
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than.result
new file mode 100644
index 00000000..a33cd484
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year > "11" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id ASC LIMIT 2;
+id release_title release_year
+3 Mroonga 2.0 has been released 2012
+4 Mroonga 3.0 has been released 2013
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than_or_equal.result
new file mode 100644
index 00000000..7d2471b3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_greater_than_or_equal.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year >= "11" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id ASC LIMIT 2;
+id release_title release_year
+2 Rename Groonga storage engine to Mroonga 2011
+3 Mroonga 2.0 has been released 2012
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than.result
new file mode 100644
index 00000000..cac3d6f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year < "13" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id DESC LIMIT 1,2;
+id release_title release_year
+2 Rename Groonga storage engine to Mroonga 2011
+1 Groonga storage engine (code name Mroonga) 0.1 has been released 2010
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than_or_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than_or_equal.result
new file mode 100644
index 00000000..df57f51e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/optimization_order_limit_optimized_year_less_than_or_equal.result
@@ -0,0 +1,30 @@
+DROP TABLE IF EXISTS mroonga_releases;
+FLUSH STATUS;
+CREATE TABLE mroonga_releases (
+id INT PRIMARY KEY AUTO_INCREMENT,
+release_title TEXT,
+release_year YEAR,
+KEY (release_year),
+FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+VALUES ("Mroonga 4.0 will be released", "2014");
+SELECT * FROM mroonga_releases
+WHERE release_year <= "13" AND
+MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ORDER BY id DESC LIMIT 1,2;
+id release_title release_year
+3 Mroonga 2.0 has been released 2012
+2 Rename Groonga storage engine to Mroonga 2011
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE mroonga_releases;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/partition_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/partition_insert.result
new file mode 100644
index 00000000..0252fd90
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/partition_insert.result
@@ -0,0 +1,42 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs (
+timestamp DATETIME,
+message TEXT
+) DEFAULT CHARSET=UTF8
+PARTITION BY RANGE (TO_DAYS(timestamp)) (
+PARTITION p201501 VALUES LESS THAN (TO_DAYS('2015-02-01')),
+PARTITION p201502 VALUES LESS THAN (TO_DAYS('2015-03-01')),
+PARTITION p201503 VALUES LESS THAN (TO_DAYS('2015-04-01')),
+PARTITION pfuture VALUES LESS THAN MAXVALUE
+);
+SHOW CREATE TABLE logs;
+Table Create Table
+logs CREATE TABLE `logs` (
+ `timestamp` datetime DEFAULT NULL,
+ `message` text
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+ PARTITION BY RANGE (TO_DAYS(timestamp))
+(PARTITION p201501 VALUES LESS THAN (735995) ENGINE = Mroonga,
+ PARTITION p201502 VALUES LESS THAN (736023) ENGINE = Mroonga,
+ PARTITION p201503 VALUES LESS THAN (736054) ENGINE = Mroonga,
+ PARTITION pfuture VALUES LESS THAN MAXVALUE ENGINE = Mroonga)
+INSERT INTO logs VALUES('2015-01-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-01-31 23:59:59', 'Shutdown');
+INSERT INTO logs VALUES('2015-02-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-02-28 23:59:59', 'Shutdown');
+INSERT INTO logs VALUES('2015-03-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-03-31 23:59:59', 'Shutdown');
+INSERT INTO logs VALUES('2015-04-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-04-30 23:59:59', 'Shutdown');
+SELECT * FROM logs ORDER BY timestamp;
+timestamp message
+2015-01-01 00:00:00 Start
+2015-01-31 23:59:59 Shutdown
+2015-02-01 00:00:00 Start
+2015-02-28 23:59:59 Shutdown
+2015-03-01 00:00:00 Start
+2015-03-31 23:59:59 Shutdown
+2015-04-01 00:00:00 Start
+2015-04-30 23:59:59 Shutdown
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/partition_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/partition_update.result
new file mode 100644
index 00000000..754c4f98
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/partition_update.result
@@ -0,0 +1,43 @@
+DROP TABLE IF EXISTS logs;
+SET NAMES UTF8;
+CREATE TABLE logs (
+timestamp DATETIME,
+message TEXT
+) DEFAULT CHARSET=UTF8
+PARTITION BY RANGE (TO_DAYS(timestamp)) (
+PARTITION p201501 VALUES LESS THAN (TO_DAYS('2015-02-01')),
+PARTITION p201502 VALUES LESS THAN (TO_DAYS('2015-03-01')),
+PARTITION p201503 VALUES LESS THAN (TO_DAYS('2015-04-01')),
+PARTITION pfuture VALUES LESS THAN MAXVALUE
+);
+SHOW CREATE TABLE logs;
+Table Create Table
+logs CREATE TABLE `logs` (
+ `timestamp` datetime DEFAULT NULL,
+ `message` text
+) ENGINE=Mroonga DEFAULT CHARSET=utf8
+PARTITION BY RANGE (TO_DAYS(timestamp))
+(PARTITION p201501 VALUES LESS THAN (735995) ENGINE = Mroonga,
+ PARTITION p201502 VALUES LESS THAN (736023) ENGINE = Mroonga,
+ PARTITION p201503 VALUES LESS THAN (736054) ENGINE = Mroonga,
+ PARTITION pfuture VALUES LESS THAN MAXVALUE ENGINE = Mroonga)
+INSERT INTO logs VALUES('2015-01-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-02-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-03-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-04-01 00:00:00', 'Start');
+SELECT * FROM logs ORDER BY timestamp;
+timestamp message
+2015-01-01 00:00:00 Start
+2015-02-01 00:00:00 Start
+2015-03-01 00:00:00 Start
+2015-04-01 00:00:00 Start
+UPDATE logs
+SET message = 'Started'
+ WHERE timestamp < '2015-03-01 00:00:00';
+SELECT * FROM logs ORDER BY timestamp;
+timestamp message
+2015-01-01 00:00:00 Started
+2015-02-01 00:00:00 Started
+2015-03-01 00:00:00 Start
+2015-04-01 00:00:00 Start
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result b/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result
new file mode 100644
index 00000000..24d427ed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/repair_table_no_index_file.result
@@ -0,0 +1,31 @@
+CREATE DATABASE repair_test;
+USE repair_test;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start Groonga!");
+INSERT INTO diaries (title, body) VALUES ("Groonga (1)", "starting Groonga...");
+INSERT INTO diaries (title, body) VALUES ("Groonga (2)", "started Groonga.");
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE);
+id title body
+2 Groonga (1) starting Groonga...
+FLUSH TABLES;
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE);
+ERROR HY000: system call error: No such file or directory: failed to open path: <repair_test.mrn.000010E.c>
+REPAIR TABLE diaries;
+Table Op Msg_type Msg_text
+repair_test.diaries repair status OK
+SELECT * FROM diaries;
+id title body
+1 survey will start Groonga!
+2 Groonga (1) starting Groonga...
+3 Groonga (2) started Groonga.
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE);
+id title body
+2 Groonga (1) starting Groonga...
+DROP TABLE diaries;
+DROP DATABASE repair_test;
+USE test;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/replace_geometry.result b/storage/mroonga/mysql-test/mroonga/storage/r/replace_geometry.result
new file mode 100644
index 00000000..e88a799f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/replace_geometry.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS geo_replace;
+CREATE TABLE geo_replace (
+id INT NOT NULL,
+geo GEOMETRY NOT NULL,
+PRIMARY KEY(id)
+) DEFAULT CHARSET=utf8;
+INSERT INTO geo_replace VALUES(1, POINT(100,100));
+SELECT id, ST_AsText(geo) FROM geo_replace;
+id ST_AsText(geo)
+1 POINT(100 100)
+REPLACE INTO geo_replace VALUES(1, POINT(100,200));
+SELECT id, ST_AsText(geo) FROM geo_replace;
+id ST_AsText(geo)
+1 POINT(100 200)
+INSERT INTO geo_replace VALUES(1, POINT(200,200)) ON DUPLICATE KEY UPDATE geo = POINT(200,200);
+SELECT id, ST_AsText(geo) FROM geo_replace;
+id ST_AsText(geo)
+1 POINT(200 200)
+UPDATE geo_replace SET geo = POINT(200,300);
+SELECT id, ST_AsText(geo) FROM geo_replace;
+id ST_AsText(geo)
+1 POINT(200 300)
+DROP TABLE geo_replace;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/replace_select_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/replace_select_varchar.result
new file mode 100644
index 00000000..b9aebee3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/replace_select_varchar.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS videos_master, videos_groonga;
+CREATE TABLE `videos_master` (
+`id` bigint(1) unsigned NOT NULL,
+`video_id` varchar(64) NOT NULL,
+`description` text,
+`tags_unpack` text,
+PRIMARY KEY (`video_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+CREATE TABLE `videos_groonga` (
+`id` bigint(1) unsigned NOT NULL,
+`video_id` varchar(64) NOT NULL,
+`description` text,
+`tags_unpack` text,
+PRIMARY KEY (`video_id`),
+FULLTEXT INDEX (`description`),
+FULLTEXT INDEX (`tags_unpack`)
+) DEFAULT CHARSET=utf8;
+INSERT INTO videos_master VALUES (1, "video-1", "My Familly", "familly human");
+INSERT INTO videos_master VALUES (2, "video-2", "My Cat", "family cat");
+REPLACE INTO videos_groonga
+SELECT v.id, v.video_id, v.description, NULL
+FROM videos_master AS v
+WHERE v.video_id = (video_id);
+SELECT *, MATCH(description) AGAINST("cat") FROM videos_groonga
+WHERE MATCH(description) AGAINST("cat");
+id video_id description tags_unpack MATCH(description) AGAINST("cat")
+2 video-2 My Cat 1048577
+INSERT INTO videos_master VALUES (3, "video-3", "My Dog", "family dog");
+REPLACE INTO videos_groonga
+SELECT v.id, v.video_id, v.description, NULL
+FROM videos_master AS v
+WHERE v.video_id = (video_id);
+SELECT *, MATCH(description) AGAINST("my") FROM videos_groonga
+WHERE MATCH(description) AGAINST("my")
+ORDER BY id;
+id video_id description tags_unpack MATCH(description) AGAINST("my")
+1 video-1 My Familly 209716
+2 video-2 My Cat 209716
+3 video-3 My Dog 209716
+DROP TABLE videos_master, videos_groonga;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/replace_text.result b/storage/mroonga/mysql-test/mroonga/storage/r/replace_text.result
new file mode 100644
index 00000000..c70ce337
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/replace_text.result
@@ -0,0 +1,25 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+content text,
+fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "今日からはじめました。");
+insert into diaries values(2, "明日の富士山の天気について");
+insert into diaries values(3, "今日も天気がよくてきれいに見える。");
+select * from diaries;
+id content
+1 今日からはじめました。
+2 明日の富士山の天気について
+3 今日も天気がよくてきれいに見える。
+select * from diaries where match(content) against("天気");
+id content
+2 明日の富士山の天気について
+3 今日も天気がよくてきれいに見える。
+replace into diaries values(2, "明日の天気は雨みたい。");
+select * from diaries where match(content) against("天気");
+id content
+2 明日の天気は雨みたい。
+3 今日も天気がよくてきれいに見える。
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/replace_varchar.result b/storage/mroonga/mysql-test/mroonga/storage/r/replace_varchar.result
new file mode 100644
index 00000000..fd2cb655
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/replace_varchar.result
@@ -0,0 +1,25 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+content varchar(256),
+fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "今日からはじめました。");
+insert into diaries values(2, "明日の富士山の天気について");
+insert into diaries values(3, "今日も天気がよくてきれいに見える。");
+select * from diaries;
+id content
+1 今日からはじめました。
+2 明日の富士山の天気について
+3 今日も天気がよくてきれいに見える。
+select * from diaries where match(content) against("天気");
+id content
+2 明日の富士山の天気について
+3 今日も天気がよくてきれいに見える。
+replace into diaries values(2, "明日の天気は雨みたい。");
+select * from diaries where match(content) against("天気");
+id content
+2 明日の天気は雨みたい。
+3 今日も天気がよくてきれいに見える。
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/replace_vector.result b/storage/mroonga/mysql-test/mroonga/storage/r/replace_vector.result
new file mode 100644
index 00000000..3e987631
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/replace_vector.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS vector_replace;
+DROP TABLE IF EXISTS vector_replace_vec;
+CREATE TABLE vector_replace_vec (
+vec CHAR(10) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE vector_replace (
+id INT NOT NULL,
+vec TEXT COMMENT 'flags "COLUMN_VECTOR", type "vector_replace_vec"',
+PRIMARY KEY(id)
+) DEFAULT CHARSET=utf8;
+INSERT INTO vector_replace VALUES(1, 'first second third');
+SELECT id, vec FROM vector_replace;
+id vec
+1 FIRST SECOND THIRD
+REPLACE INTO vector_replace VALUES(1, 'fourth fifth');
+SELECT id, vec FROM vector_replace;
+id vec
+1 FOURTH FIFTH
+INSERT INTO vector_replace VALUES(1, 'sixth seventh') ON DUPLICATE KEY UPDATE vec = 'sixth seventh';
+SELECT id, vec FROM vector_replace;
+id vec
+1 SIXTH SEVENTH
+UPDATE vector_replace SET vec = 'eighth nineth tenth';
+SELECT id, vec FROM vector_replace;
+id vec
+1 EIGHTH NINETH TENTH
+DROP TABLE vector_replace;
+DROP TABLE vector_replace_vec;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/replace_without_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/replace_without_key.result
new file mode 100644
index 00000000..e67f0fe4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/replace_without_key.result
@@ -0,0 +1,10 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id varchar(32) NOT NULL PRIMARY KEY,
+content text,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+REPLACE INTO diaries(content) VALUES("Hello");
+Got one of the listed errors
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_all.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_all.result
new file mode 100644
index 00000000..18318bdb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_all.result
@@ -0,0 +1,198 @@
+drop table if exists t1, t2, t3;
+create table t1(c1 int, c2 int, c3 int);
+insert into t1 values (1, 10, 100);
+insert into t1 values (2, 30, 500);
+insert into t1 values (5, 20, 200);
+insert into t1 values (3, 60, 300);
+insert into t1 values (4, 50, 600);
+insert into t1 values (6, 40, 400);
+select * from t1;
+c1 c2 c3
+1 10 100
+2 30 500
+5 20 200
+3 60 300
+4 50 600
+6 40 400
+select c1 from t1;
+c1
+1
+2
+5
+3
+4
+6
+select c2 from t1;
+c2
+10
+30
+20
+60
+50
+40
+select c3 from t1;
+c3
+100
+500
+200
+300
+600
+400
+select * from t1 where c1 <= 3;
+c1 c2 c3
+1 10 100
+2 30 500
+3 60 300
+select * from t1 where c2 > 40;
+c1 c2 c3
+3 60 300
+4 50 600
+select * from t1 where c3 = 300;
+c1 c2 c3
+3 60 300
+select * from t1 order by c1;
+c1 c2 c3
+1 10 100
+2 30 500
+3 60 300
+4 50 600
+5 20 200
+6 40 400
+select * from t1 order by c2 desc;
+c1 c2 c3
+3 60 300
+4 50 600
+6 40 400
+2 30 500
+5 20 200
+1 10 100
+select * from t1 order by c3, c1;
+c1 c2 c3
+1 10 100
+5 20 200
+3 60 300
+6 40 400
+2 30 500
+4 50 600
+drop table t1;
+create table t1 (c1 int, c2 varchar(100));
+insert into t1 values(1, "hoge");
+insert into t1 values(4, "hogefuga");
+insert into t1 values(2, "fuga");
+insert into t1 values(5, "moge");
+insert into t1 values(3, "mo");
+select * from t1;
+c1 c2
+1 hoge
+4 hogefuga
+2 fuga
+5 moge
+3 mo
+select * from t1 order by c1;
+c1 c2
+1 hoge
+2 fuga
+3 mo
+4 hogefuga
+5 moge
+select * from t1 order by c1 desc;
+c1 c2
+5 moge
+4 hogefuga
+3 mo
+2 fuga
+1 hoge
+select * from t1 order by c2;
+c1 c2
+2 fuga
+1 hoge
+4 hogefuga
+3 mo
+5 moge
+drop table t1;
+create table t1 (c1 int, c2 text);
+insert into t1 values(1, "hoge");
+insert into t1 values(4, "hogefuga");
+insert into t1 values(2, "fuga");
+insert into t1 values(5, "moge");
+insert into t1 values(3, "mo");
+select * from t1;
+c1 c2
+1 hoge
+4 hogefuga
+2 fuga
+5 moge
+3 mo
+drop table t1;
+create table t1 (c1 int, c2 int, c3 text);
+insert into t1 values(1, 20, "hoge");
+insert into t1 values(4, 60, "hogefuga");
+insert into t1 values(2, 50, "fuga");
+insert into t1 values(5, 30, "moge");
+insert into t1 values(3, 40, "mo");
+select * from t1 order by c1 asc;
+c1 c2 c3
+1 20 hoge
+2 50 fuga
+3 40 mo
+4 60 hogefuga
+5 30 moge
+select * from t1 order by c1 desc;
+c1 c2 c3
+5 30 moge
+4 60 hogefuga
+3 40 mo
+2 50 fuga
+1 20 hoge
+select * from t1 order by c2 asc;
+c1 c2 c3
+1 20 hoge
+5 30 moge
+3 40 mo
+2 50 fuga
+4 60 hogefuga
+select * from t1 order by c2 desc;
+c1 c2 c3
+4 60 hogefuga
+2 50 fuga
+3 40 mo
+5 30 moge
+1 20 hoge
+select * from t1 order by c3 asc;
+c1 c2 c3
+2 50 fuga
+1 20 hoge
+4 60 hogefuga
+3 40 mo
+5 30 moge
+select * from t1 order by c3 desc;
+c1 c2 c3
+5 30 moge
+3 40 mo
+4 60 hogefuga
+1 20 hoge
+2 50 fuga
+drop table t1;
+create table t1 (_id int, c1 int);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+select * from t1;
+_id c1
+1 100
+2 100
+3 100
+4 100
+5 100
+select * from t1 where _id < 3;
+_id c1
+1 100
+2 100
+select * from t1 where _id >= 3;
+_id c1
+3 100
+4 100
+5 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_equal.result
new file mode 100644
index 00000000..e0e3e21c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_equal.result
@@ -0,0 +1,12 @@
+DROP TABLE IF EXISTS tags;
+CREATE TABLE tags (
+name VARCHAR(16) NOT NULL,
+KEY index_name (name)
+);
+INSERT INTO tags VALUES ('mroonga');
+INSERT INTO tags VALUES ('mysql');
+INSERT INTO tags VALUES ('');
+SELECT * FROM tags WHERE name = "";
+name
+
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_not_equal.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_not_equal.result
new file mode 100644
index 00000000..3732cb28
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_empty_key_where_not_equal.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS tags;
+CREATE TABLE tags (
+name VARCHAR(16) NOT NULL,
+KEY index_name (name)
+);
+INSERT INTO tags VALUES ('mroonga');
+INSERT INTO tags VALUES ('mysql');
+INSERT INTO tags VALUES ('');
+SELECT * FROM tags WHERE name != "";
+name
+mroonga
+mysql
+DROP TABLE tags;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_with_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_with_index.result
new file mode 100644
index 00000000..a111880a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_with_index.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+name varchar(40),
+age int,
+KEY (age)
+);
+INSERT INTO users VALUES ("Alice", 20);
+INSERT INTO users VALUES ("Bob", 20);
+INSERT INTO users VALUES ("Charry", 29);
+SELECT age, COUNT(*) FROM users GROUP BY age;
+age COUNT(*)
+20 2
+29 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_without_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_without_index.result
new file mode 100644
index 00000000..93d29c2d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_group_by_without_index.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+name varchar(40),
+age int
+);
+INSERT INTO users VALUES ("Alice", 20);
+INSERT INTO users VALUES ("Bob", 20);
+INSERT INTO users VALUES ("Charry", 29);
+SELECT age, COUNT(*) FROM users GROUP BY age;
+age COUNT(*)
+20 2
+29 1
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_pkey.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_pkey.result
new file mode 100644
index 00000000..99f69f49
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_pkey.result
@@ -0,0 +1,27 @@
+drop table if exists t1, t2, t3;
+create table t1(c1 int primary key, c2 int, c3 int);
+insert into t1 values (1, 10, 100);
+insert into t1 values (2, 30, 500);
+insert into t1 values (5, 20, 200);
+insert into t1 values (3, 60, 300);
+insert into t1 values (4, 50, 600);
+insert into t1 values (6, 40, 400);
+select * from t1 where c1=1;
+c1 c2 c3
+1 10 100
+select * from t1 where c1=2;
+c1 c2 c3
+2 30 500
+select * from t1 where c1=3;
+c1 c2 c3
+3 60 300
+select * from t1 where c1=4;
+c1 c2 c3
+4 50 600
+select * from t1 where c1=5;
+c1 c2 c3
+5 20 200
+select * from t1 where c1=6;
+c1 c2 c3
+6 40 400
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/select_secondary_key.result b/storage/mroonga/mysql-test/mroonga/storage/r/select_secondary_key.result
new file mode 100644
index 00000000..1c24089e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/select_secondary_key.result
@@ -0,0 +1,55 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, c3 text, key idx1(c2), fulltext index ft(c3));
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 20 ka ki ku ke ko
+3 30 sa si su se so
+4 40 ta ti tu te to
+5 50 aa ii uu ee oo
+select * from t1 force index(idx1) where c2 = 30;
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 force index(idx1) where c2 = 20;
+c1 c2 c3
+2 20 ka ki ku ke ko
+insert into t1 values(6,30,"aa bb cc dd ee");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 20 ka ki ku ke ko
+3 30 sa si su se so
+4 40 ta ti tu te to
+5 50 aa ii uu ee oo
+6 30 aa bb cc dd ee
+select * from t1 force index(idx1) where c2 = 30;
+c1 c2 c3
+3 30 sa si su se so
+6 30 aa bb cc dd ee
+drop table t1;
+create table t1 (c1 varchar(5) primary key, c2 varchar(5), c3 text, key idx1(c2), fulltext index ft(c3))engine=mroonga;
+insert into t1 values('ab','ijk',"aa ii uu ee oo");
+insert into t1 values('bc','ghi',"ka ki ku ke ko");
+insert into t1 values('cd','efg',"sa si su se so");
+insert into t1 values('de','cde',"ta ti tu te to");
+insert into t1 values('ef','abc',"aa ii uu ee oo");
+select * from t1 force index(idx1) where c2 < 'e' order by c1 asc;
+c1 c2 c3
+de cde ta ti tu te to
+ef abc aa ii uu ee oo
+select * from t1 force index(idx1) where c2 > 'e' order by c1 asc;
+c1 c2 c3
+ab ijk aa ii uu ee oo
+bc ghi ka ki ku ke ko
+cd efg sa si su se so
+select * from t1 force index(idx1) where c2 between 'c' and 'h' order by c1 asc;
+c1 c2 c3
+bc ghi ka ki ku ke ko
+cd efg sa si su se so
+de cde ta ti tu te to
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/show_create_table_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/show_create_table_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..dd26cfaf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/show_create_table_TODO_SPLIT_ME.result
@@ -0,0 +1,25 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+drop table t1;
+create table t1 (c1 int, c2 int);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) DEFAULT NULL,
+ `c2` int(11) DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+drop table t1;
+create table t1 (c1 int primary key, c2 varchar(100));
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL,
+ `c2` varchar(100) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/sub_query_fulltext.result b/storage/mroonga/mysql-test/mroonga/storage/r/sub_query_fulltext.result
new file mode 100644
index 00000000..87c9f4ef
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/sub_query_fulltext.result
@@ -0,0 +1,35 @@
+DROP TABLE IF EXISTS diaries, users;
+CREATE TABLE users (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name TEXT
+) DEFAULT CHARSET UTF8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+user_id INT UNSIGNED NOT NULL,
+title TEXT,
+FULLTEXT INDEX (title)
+) DEFAULT CHARSET UTF8;
+INSERT INTO users (name) VALUES ("alice");
+INSERT INTO users (name) VALUES ("bob");
+INSERT INTO users (name) VALUES ("carlos");
+SELECT * FROM users;
+id name
+1 alice
+2 bob
+3 carlos
+INSERT INTO diaries (user_id, title) VALUES (1, "Hello!");
+INSERT INTO diaries (user_id, title) VALUES (2, "my name is bob");
+INSERT INTO diaries (user_id, title) VALUES (3, "my name is carlos");
+SELECT * FROM diaries;
+id user_id title
+1 1 Hello!
+2 2 my name is bob
+3 3 my name is carlos
+SELECT * FROM users
+WHERE id IN (SELECT user_id FROM diaries
+WHERE MATCH(title) AGAINST("name"))
+ORDER BY id DESC;
+id name
+3 carlos
+2 bob
+DROP TABLE diaries, users;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/temporary_table.result b/storage/mroonga/mysql-test/mroonga/storage/r/temporary_table.result
new file mode 100644
index 00000000..0a18d817
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/temporary_table.result
@@ -0,0 +1,14 @@
+DROP TEMPORARY TABLE IF EXISTS diaries;
+CREATE TEMPORARY TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (title) VALUES ("clear day");
+INSERT INTO diaries (title) VALUES ("rainy day");
+INSERT INTO diaries (title) VALUES ("cloudy day");
+SELECT * FROM diaries;
+id title
+1 clear day
+2 rainy day
+3 cloudy day
+DROP TEMPORARY TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/truncate.result b/storage/mroonga/mysql-test/mroonga/storage/r/truncate.result
new file mode 100644
index 00000000..3525e235
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/truncate.result
@@ -0,0 +1,47 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(day)
+) DEFAULT CHARSET UTF8;
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT * FROM diaries;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+2 2011 11 10 天気 明日の富士山の天気について
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ORDER BY id;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+TRUNCATE TABLE diaries;
+SELECT * FROM diaries;
+id year month day title content
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ORDER BY id;
+id year month day title content
+INSERT INTO diaries VALUES(1, 2011, 11, 11, "帰り道", "つかれたー");
+INSERT INTO diaries VALUES(2, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(3, 2011, 12, 2, "初雪", "今年はじめての雪!");
+SELECT * FROM diaries;
+id year month day title content
+1 2011 11 11 帰り道 つかれたー
+2 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+3 2011 12 2 初雪 今年はじめての雪!
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("+悪い" IN BOOLEAN MODE)
+ORDER BY id;
+id year month day title content
+2 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_binlog_row.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_binlog_row.result
new file mode 100644
index 00000000..72a913b4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_binlog_row.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS memos;
+SET SESSION binlog_format = 'ROW';
+CREATE TABLE memos (
+title varchar(20) PRIMARY KEY,
+content varchar(140) NOT NULL
+) COLLATE=utf8mb4_general_ci
+DEFAULT CHARSET=utf8mb4;
+INSERT INTO memos (title, content) VALUES ('Mroonga', 'Mroonga is great!');
+SELECT * FROM memos;
+title content
+Mroonga Mroonga is great!
+UPDATE memos SET content = 'Mroonga is very great!' WHERE title = 'Mroonga';
+SELECT * FROM memos;
+title content
+Mroonga Mroonga is very great!
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_fulltext.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_fulltext.result
new file mode 100644
index 00000000..bf81d5e0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_fulltext.result
@@ -0,0 +1,22 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 text, fulltext index (c2));
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+select * from t1;
+c1 c2
+10 aa ii uu ee
+20 ka ki ku ke
+30 sa si su se
+update t1 set c2="ta ti tu te" where c1=20;
+select * from t1;
+c1 c2
+10 aa ii uu ee
+20 ta ti tu te
+30 sa si su se
+select * from t1 where match(c2) against("ti");
+c1 c2
+20 ta ti tu te
+select * from t1 where match(c2) against("ki");
+c1 c2
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_id_hash_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_id_hash_index.result
new file mode 100644
index 00000000..35d8843a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_id_hash_index.result
@@ -0,0 +1,20 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, c1 int, key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+_id c1
+1 100
+2 100
+3 100
+4 100
+update t1 set c1 = 200 where _id = 2;
+select * from t1;
+_id c1
+1 100
+2 200
+3 100
+4 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_id_unique_hash_index.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_id_unique_hash_index.result
new file mode 100644
index 00000000..dba9c964
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_id_unique_hash_index.result
@@ -0,0 +1,20 @@
+drop table if exists t1, t2, t3;
+create table t1 (_id int, c1 int, unique key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+_id c1
+1 100
+2 100
+3 100
+4 100
+update t1 set c1 = 200 where _id = 2;
+select * from t1;
+_id c1
+1 100
+2 200
+3 100
+4 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_int.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_int.result
new file mode 100644
index 00000000..606c30a9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_int.result
@@ -0,0 +1,42 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int, c2 int);
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) DEFAULT NULL,
+ `c2` int(11) DEFAULT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+update t1 set c2=c2+100 where c1=1;
+select * from t1;
+c1 c2
+1 200
+2 101
+3 102
+update t1 set c2=c2+100 where c1=2;
+select * from t1;
+c1 c2
+1 200
+2 201
+3 102
+update t1 set c2=c2+100 where c1=3;
+select * from t1;
+c1 c2
+1 200
+2 201
+3 202
+flush tables;
+update t1 set c1=5, c2=50;
+select * from t1;
+c1 c2
+5 50
+5 50
+5 50
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_last_insert_grn_id.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_last_insert_grn_id.result
new file mode 100644
index 00000000..af592631
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_last_insert_grn_id.result
@@ -0,0 +1,29 @@
+drop table if exists memos;
+create table memos (
+_id int,
+content varchar(255),
+unique key (_id) using hash
+);
+insert into memos values (null, "今夜はさんま。");
+insert into memos values (null, "明日はgroongaをアップデート。");
+insert into memos values (null, "帰りにおだんご。");
+insert into memos values (null, "金曜日は肉の日。");
+select * from memos;
+_id content
+1 今夜はさんま。
+2 明日はgroongaをアップデート。
+3 帰りにおだんご。
+4 金曜日は肉の日。
+insert into memos values (null, "冷蔵庫に牛乳が残り1本。");
+select last_insert_grn_id();
+last_insert_grn_id()
+5
+update memos set content = "冷蔵庫に牛乳はまだたくさんある。" where _id = last_insert_grn_id();
+select * from memos;
+_id content
+1 今夜はさんま。
+2 明日はgroongaをアップデート。
+3 帰りにおだんご。
+4 金曜日は肉の日。
+5 冷蔵庫に牛乳はまだたくさんある。
+drop table memos;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/update_virtual_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/update_virtual_column.result
new file mode 100644
index 00000000..e823e128
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/update_virtual_column.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (c1 int, _id int);
+INSERT INTO t1 VALUES(1,null);
+INSERT INTO t1 VALUES(2,null);
+INSERT INTO t1 VALUES(3,null);
+SELECT * FROM t1;
+c1 _id
+1 1
+2 2
+3 3
+SET sql_mode="";
+UPDATE t1 SET _id = 10 WHERE c1 = 1;
+Warnings:
+Warning 1265 Data truncated for column '_id' at row 1
+SELECT * FROM t1;
+c1 _id
+1 1
+2 2
+3 3
+SET sql_mode="STRICT_ALL_TABLES";
+UPDATE t1 SET _id = 11 WHERE c1 = 1;
+ERROR 01000: Data truncated for column '_id' at row 1
+SELECT * FROM t1;
+c1 _id
+1 1
+2 2
+3 3
+DROP TABLE t1;
+SET sql_mode=DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_column.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_column.result
new file mode 100644
index 00000000..37826335
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_column.result
@@ -0,0 +1,18 @@
+SET @mroonga_boolean_mode_syntax_flags_backup =
+@@mroonga_boolean_mode_syntax_flags;
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY,ALLOW_COLUMN";
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+content TEXT,
+FULLTEXT KEY (title),
+FULLTEXT KEY (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Groonga", "Hello Groonga");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("content:@Hello" IN BOOLEAN MODE);
+title content
+Groonga Hello Groonga
+DROP TABLE diaries;
+SET mroonga_boolean_mode_syntax_flags =
+@mroonga_boolean_mode_syntax_flags_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_leading_not.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_leading_not.result
new file mode 100644
index 00000000..d3ccb150
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_leading_not.result
@@ -0,0 +1,16 @@
+SET @mroonga_boolean_mode_syntax_flags_backup =
+@@mroonga_boolean_mode_syntax_flags;
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY,ALLOW_LEADING_NOT";
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Groonga");
+INSERT INTO diaries VALUES("Mroonga");
+SELECT * FROM diaries WHERE MATCH(title) AGAINST("-Groonga" IN BOOLEAN MODE);
+title
+Mroonga
+DROP TABLE diaries;
+SET mroonga_boolean_mode_syntax_flags =
+@mroonga_boolean_mode_syntax_flags_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_update.result
new file mode 100644
index 00000000..55cd8742
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_allow_update.result
@@ -0,0 +1,18 @@
+SET @mroonga_boolean_mode_syntax_flags_backup =
+@@mroonga_boolean_mode_syntax_flags;
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY,ALLOW_COLUMN,ALLOW_UPDATE";
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+content TEXT,
+FULLTEXT KEY (title),
+FULLTEXT KEY (content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Groonga", "Hello Groonga");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST('content:="Hello Mroonga"' IN BOOLEAN MODE);
+title content
+Groonga Hello Mroonga
+DROP TABLE diaries;
+SET mroonga_boolean_mode_syntax_flags =
+@mroonga_boolean_mode_syntax_flags_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_query.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_query.result
new file mode 100644
index 00000000..5736fd52
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_query.result
@@ -0,0 +1,15 @@
+SET @mroonga_boolean_mode_syntax_flags_backup =
+@@mroonga_boolean_mode_syntax_flags;
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY";
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Re:Mroonga");
+SELECT * FROM diaries WHERE MATCH(title) AGAINST("Re:Mroonga" IN BOOLEAN MODE);
+title
+Re:Mroonga
+DROP TABLE diaries;
+SET mroonga_boolean_mode_syntax_flags =
+@mroonga_boolean_mode_syntax_flags_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_script.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_script.result
new file mode 100644
index 00000000..e42fa259
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_boolean_mode_syntax_flags_syntax_script.result
@@ -0,0 +1,16 @@
+SET @mroonga_boolean_mode_syntax_flags_backup =
+@@mroonga_boolean_mode_syntax_flags;
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_SCRIPT";
+SET NAMES UTF8;
+CREATE TABLE diaries (
+title TEXT,
+FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES("Re:Mroonga");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("title @ 'Re:Mroonga'" IN BOOLEAN MODE);
+title
+Re:Mroonga
+DROP TABLE diaries;
+SET mroonga_boolean_mode_syntax_flags =
+@mroonga_boolean_mode_syntax_flags_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_database_path_prefix.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_database_path_prefix.result
new file mode 100644
index 00000000..beca93b6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_database_path_prefix.result
@@ -0,0 +1,17 @@
+SET GLOBAL mroonga_database_path_prefix = "test/mroonga.data/";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_database_path_prefix';
+Variable_name Value
+mroonga_database_path_prefix test/mroonga.data/
+CREATE DATABASE clean_test;
+USE clean_test;
+CREATE TABLE counts (
+id INT PRIMARY KEY AUTO_INCREMENT
+);
+INSERT INTO counts VALUES (NULL);
+SELECT * FROM counts;
+id
+1
+DROP TABLE counts;
+DROP DATABASE clean_test;
+SET GLOBAL mroonga_database_path_prefix = NULL;
+USE test;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_new_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_new_value.result
new file mode 100644
index 00000000..959383ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_new_value.result
@@ -0,0 +1,6 @@
+SET @mroonga_default_parser_backup = @@mroonga_default_parser;
+SET GLOBAL mroonga_default_parser = "TokenBigramSplitAlpha";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_parser';
+Variable_name Value
+mroonga_default_parser TokenBigramSplitAlpha
+SET GLOBAL mroonga_default_parser = @mroonga_default_parser_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_same_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_same_value.result
new file mode 100644
index 00000000..7f441b4b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_parser_same_value.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_default_parser = "TokenBigram";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_parser';
+Variable_name Value
+mroonga_default_parser TokenBigram
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_new_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_new_value.result
new file mode 100644
index 00000000..1f457eb5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_new_value.result
@@ -0,0 +1,6 @@
+SET @mroonga_default_tokenizer_backup = @@mroonga_default_tokenizer;
+SET GLOBAL mroonga_default_tokenizer = "TokenBigramSplitAlpha";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_tokenizer';
+Variable_name Value
+mroonga_default_tokenizer TokenBigramSplitAlpha
+SET GLOBAL mroonga_default_tokenizer = @mroonga_default_tokenizer_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_same_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_same_value.result
new file mode 100644
index 00000000..9ad80e9a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_default_tokenizer_same_value.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_default_tokenizer = "TokenBigram";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_tokenizer';
+Variable_name Value
+mroonga_default_tokenizer TokenBigram
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_delete.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_delete.result
new file mode 100644
index 00000000..4238cb63
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_delete.result
@@ -0,0 +1,20 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start groonga!");
+select * from diaries;
+id body
+1 will start groonga!
+set mroonga_dry_write=true;
+delete from diaries where id = 1;
+select * from diaries;
+id body
+1 will start groonga!
+set mroonga_dry_write=false;
+delete from diaries where id = 1;
+select * from diaries;
+id body
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_insert.result
new file mode 100644
index 00000000..429398f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_insert.result
@@ -0,0 +1,22 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start groonga!");
+select * from diaries;
+id body
+1 will start groonga!
+set mroonga_dry_write=true;
+insert into diaries (body) values ("starting groonga...");
+select * from diaries;
+id body
+1 will start groonga!
+set mroonga_dry_write=false;
+insert into diaries (body) values ("started groonga.");
+select * from diaries;
+id body
+1 will start groonga!
+2 started groonga.
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_update.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_update.result
new file mode 100644
index 00000000..9cd6f5c9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_dry_write_update.result
@@ -0,0 +1,18 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start groonga!");
+set mroonga_dry_write=true;
+update diaries set body = "starting groonga..." where id = 1;
+select * from diaries;
+id body
+1 will start groonga!
+set mroonga_dry_write=false;
+update diaries set body = "starting groonga..." where id = 1;
+select * from diaries;
+id body
+1 starting groonga...
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_enable_operations_recording_insert.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_enable_operations_recording_insert.result
new file mode 100644
index 00000000..5a19ab6f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_enable_operations_recording_insert.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+title TEXT
+) DEFAULT CHARSET=utf8;
+SELECT mroonga_command('truncate mroonga_operations');
+mroonga_command('truncate mroonga_operations')
+true
+INSERT INTO diaries VALUES("Unlogged: Research for Mroonga");
+SELECT mroonga_command('load --table mroonga_operations --values "[{}]"');
+mroonga_command('load --table mroonga_operations --values "[{}]"')
+1
+SELECT mroonga_command('select mroonga_operations --output_columns _id');
+mroonga_command('select mroonga_operations --output_columns _id')
+[[[1],[["_id","UInt32"]],[2]]]
+SET GLOBAL mroonga_enable_operations_recording = false;
+FLUSH TABLES;
+SELECT mroonga_command('truncate mroonga_operations');
+mroonga_command('truncate mroonga_operations')
+true
+INSERT INTO diaries VALUES("Logged: Research for Mroonga");
+SELECT mroonga_command('load --table mroonga_operations --values "[{}]"');
+mroonga_command('load --table mroonga_operations --values "[{}]"')
+1
+SELECT mroonga_command('select mroonga_operations --output_columns _id');
+mroonga_command('select mroonga_operations --output_columns _id')
+[[[1],[["_id","UInt32"]],[1]]]
+DROP TABLE diaries;
+SELECT mroonga_command('truncate mroonga_operations');
+mroonga_command('truncate mroonga_operations')
+true
+SET GLOBAL mroonga_enable_operations_recording = default;
+FLUSH TABLES;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_disable.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_disable.result
new file mode 100644
index 00000000..789316d8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_disable.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_lock_timeout = -1;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+Variable_name Value
+mroonga_lock_timeout -1
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_invalid.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_invalid.result
new file mode 100644
index 00000000..029b1ab1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_invalid.result
@@ -0,0 +1,6 @@
+SET GLOBAL mroonga_lock_timeout = -2;
+Warnings:
+Warning 1292 Truncated incorrect mroonga_lock_timeout value: '-2'
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+Variable_name Value
+mroonga_lock_timeout -1
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_no_retry.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_no_retry.result
new file mode 100644
index 00000000..f47a2e66
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_no_retry.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_lock_timeout = 0;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+Variable_name Value
+mroonga_lock_timeout 0
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_valid.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_valid.result
new file mode 100644
index 00000000..6ec1004f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_lock_timeout_valid.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_lock_timeout = 1000;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+Variable_name Value
+mroonga_lock_timeout 1000
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_new_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_new_value.result
new file mode 100644
index 00000000..db469479
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_new_value.result
@@ -0,0 +1,6 @@
+SET @mroonga_log_file_backup = @@mroonga_log_file;
+SET GLOBAL mroonga_log_file = "new-mroonga.log";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file';
+Variable_name Value
+mroonga_log_file new-mroonga.log
+SET GLOBAL mroonga_log_file = @mroonga_log_file_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_nonexistent_path.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_nonexistent_path.result
new file mode 100644
index 00000000..1dbec1f8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_nonexistent_path.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_log_file = "nonexistent/mroonga.log";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file';
+Variable_name Value
+mroonga_log_file groonga.log
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_same_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_same_value.result
new file mode 100644
index 00000000..5824f090
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_file_same_value.result
@@ -0,0 +1,4 @@
+SET GLOBAL mroonga_log_file = "groonga.log";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file';
+Variable_name Value
+mroonga_log_file groonga.log
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_level_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_level_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..cb646ece
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_log_level_TODO_SPLIT_ME.result
@@ -0,0 +1,49 @@
+set @mroonga_log_level_backup=@@mroonga_log_level;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level NOTICE
+set global mroonga_log_level=NONE;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level NONE
+set global mroonga_log_level=EMERG;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level EMERG
+set global mroonga_log_level=ALERT;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level ALERT
+set global mroonga_log_level=CRIT;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level CRIT
+set global mroonga_log_level=ERROR;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level ERROR
+set global mroonga_log_level=WARNING;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level WARNING
+set global mroonga_log_level=NOTICE;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level NOTICE
+set global mroonga_log_level=INFO;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level INFO
+set global mroonga_log_level=DEBUG;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level DEBUG
+set global mroonga_log_level=DUMP;
+show global variables like 'mroonga_log_level';
+Variable_name Value
+mroonga_log_level DUMP
+set global mroonga_log_level=dummy;
+ERROR 42000: Variable 'mroonga_log_level' can't be set to the value of 'dummy'
+set session mroonga_log_level=NOTICE;
+ERROR HY000: Variable 'mroonga_log_level' is a GLOBAL variable and should be set with SET GLOBAL
+set global mroonga_log_level=@mroonga_log_level_backup;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_global.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_global.result
new file mode 100644
index 00000000..19abff38
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_global.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET GLOBAL mroonga_match_escalation_threshold = -1;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+tags TEXT,
+FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (title, tags) VALUES ("Hello Groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello Mroonga!", "mroonga install");
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+install" IN BOOLEAN MODE);
+id title tags
+1 Hello Groonga! groonga install
+2 Hello Mroonga! mroonga install
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+gr" IN BOOLEAN MODE);
+id title tags
+SET GLOBAL mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+gr" IN BOOLEAN MODE);
+id title tags
+SET mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+gr" IN BOOLEAN MODE);
+id title tags
+1 Hello Groonga! groonga install
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_session.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_session.result
new file mode 100644
index 00000000..30e9262b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_match_escalation_threshold_session.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+tags TEXT,
+FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8;
+INSERT INTO diaries (title, tags) VALUES ("Hello groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello mroonga!", "mroonga install");
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("install" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+2 Hello mroonga! mroonga install
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+SET mroonga_match_escalation_threshold = -1;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+SET mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_global.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_global.result
new file mode 100644
index 00000000..0181fe02
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_global.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+SET GLOBAL mroonga_max_n_records_for_estimate = 1;
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE ids range PRIMARY PRIMARY 4 NULL 1 Using where; Using index
+SET GLOBAL mroonga_max_n_records_for_estimate = DEFAULT;
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.result
new file mode 100644
index 00000000..ff574f7b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+SET GLOBAL mroonga_max_n_records_for_estimate = 1;
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE ids NULL range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using index
+Warnings:
+Note 1003 /* select#1 */ select `test`.`ids`.`id` AS `id` from `test`.`ids` where (`test`.`ids`.`id` > 5)
+SET GLOBAL mroonga_max_n_records_for_estimate = DEFAULT;
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.result
new file mode 100644
index 00000000..5ecf8969
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT,
+INDEX (id)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+DELETE FROM ids WHERE id < 2;
+SET mroonga_max_n_records_for_estimate = 1;
+EXPLAIN SELECT * FROM ids WHERE id > 0;
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE ids NULL range id id 5 NULL 1 100.00 Using where; Using index
+Warnings:
+Note 1003 /* select#1 */ select `test`.`ids`.`id` AS `id` from `test`.`ids` where (`test`.`ids`.`id` > 0)
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.result
new file mode 100644
index 00000000..b28eac5a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+SET mroonga_max_n_records_for_estimate = 1;
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE ids NULL range PRIMARY PRIMARY 4 NULL 1 100.00 Using where; Using index
+Warnings:
+Note 1003 /* select#1 */ select `test`.`ids`.`id` AS `id` from `test`.`ids` where (`test`.`ids`.`id` > 5)
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_not_found_in_limit.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_not_found_in_limit.result
new file mode 100644
index 00000000..d318a654
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_not_found_in_limit.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT,
+INDEX (id)
+) DEFAULT CHARSET=UTF8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4),(5),(6),(7);
+DELETE FROM ids WHERE id < 2;
+SET mroonga_max_n_records_for_estimate = 1;
+EXPLAIN SELECT * FROM ids WHERE id > 0;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE ids range id id 5 NULL 1 Using where; Using index
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_session.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_session.result
new file mode 100644
index 00000000..aca9d75c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_max_n_records_for_estimate_session.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+SET mroonga_max_n_records_for_estimate = 1;
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE ids range PRIMARY PRIMARY 4 NULL 1 Using where; Using index
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_empty_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_empty_value.result
new file mode 100644
index 00000000..3d7f36d1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_empty_value.result
@@ -0,0 +1,9 @@
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+SET GLOBAL mroonga_query_log_file = "";
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+Variable_name Value
+mroonga_query_log_file
+log file is changed: <groonga.log> -> <groonga-query-log.log>
+query log file is still disabled
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_null_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_null_value.result
new file mode 100644
index 00000000..aed9d91a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_disabled_null_value.result
@@ -0,0 +1,9 @@
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+SET GLOBAL mroonga_query_log_file = NULL;
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+Variable_name Value
+mroonga_query_log_file
+log file is changed: <groonga.log> -> <groonga-query-log.log>
+query log file is still disabled
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_empty_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_empty_value.result
new file mode 100644
index 00000000..22ac271e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_empty_value.result
@@ -0,0 +1,10 @@
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+SET GLOBAL mroonga_query_log_file = "";
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+Variable_name Value
+mroonga_query_log_file
+log file is changed: <groonga.log> -> <groonga-query-log.log>
+query log file is disabled: <groonga-query.log>
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_null_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_null_value.result
new file mode 100644
index 00000000..3921fb16
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_enabled_null_value.result
@@ -0,0 +1,10 @@
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+SET GLOBAL mroonga_query_log_file = NULL;
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+Variable_name Value
+mroonga_query_log_file
+log file is changed: <groonga.log> -> <groonga-query-log.log>
+query log file is disabled: <groonga-query.log>
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_new_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_new_value.result
new file mode 100644
index 00000000..7b1be136
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_new_value.result
@@ -0,0 +1,9 @@
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+Variable_name Value
+mroonga_query_log_file groonga-query.log
+log file is changed: <groonga.log> -> <groonga-query-log.log>
+query log is enabled: <groonga-query.log>
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_same_value.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_same_value.result
new file mode 100644
index 00000000..adf3d1bf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_query_log_file_same_value.result
@@ -0,0 +1,10 @@
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+SHOW GLOBAL VARIABLES LIKE "mroonga_query_log_file";
+Variable_name Value
+mroonga_query_log_file groonga-query.log
+log file is changed: <groonga.log> -> <groonga-query-log.log>
+query log file isn't changed because the requested path isn't different: <groonga-query.log>
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_vector_column_delimiter.result b/storage/mroonga/mysql-test/mroonga/storage/r/variable_vector_column_delimiter.result
new file mode 100644
index 00000000..f3c8f1e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_vector_column_delimiter.result
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS document;
+DROP TABLE IF EXISTS category;
+CREATE TABLE category (
+category CHAR(10) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COMMENT='default_tokenizer "TokenDelimit"';
+CREATE TABLE document (
+id INT NOT NULL,
+title TEXT,
+categories TEXT COMMENT 'flags "COLUMN_VECTOR", type "category"',
+PRIMARY KEY(id)
+) DEFAULT CHARSET=utf8;
+SHOW GLOBAL VARIABLES LIKE 'mroonga_vector_column_delimiter';
+Variable_name Value
+mroonga_vector_column_delimiter
+INSERT INTO document VALUES(1, "Mroonga is the fastest search engine", "it database fulltext");
+SELECT id, title, categories FROM document;
+id title categories
+1 Mroonga is the fastest search engine IT DATABASE FULLTEXT
+SET GLOBAL mroonga_vector_column_delimiter = ';';
+SHOW GLOBAL VARIABLES LIKE 'mroonga_vector_column_delimiter';
+Variable_name Value
+mroonga_vector_column_delimiter ;
+SELECT id, title, categories FROM document;
+id title categories
+1 Mroonga is the fastest search engine IT;DATABASE;FULLTEXT
+DROP TABLE document;
+DROP TABLE category;
+SET GLOBAL mroonga_vector_column_delimiter = ' ';
diff --git a/storage/mroonga/mysql-test/mroonga/storage/r/variable_version.result.in b/storage/mroonga/mysql-test/mroonga/storage/r/variable_version.result.in
new file mode 100644
index 00000000..26ff300a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/r/variable_version.result.in
@@ -0,0 +1,3 @@
+show variables like 'mroonga_version';
+Variable_name Value
+mroonga_version @MRN_VERSION@
diff --git a/storage/mroonga/mysql-test/mroonga/storage/suite.opt b/storage/mroonga/mysql-test/mroonga/storage/suite.opt
new file mode 100644
index 00000000..d5a1e519
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/suite.opt
@@ -0,0 +1 @@
+--loose-plugin-load-add=$HA_MROONGA_SO --loose-plugin-mroonga=ON
diff --git a/storage/mroonga/mysql-test/mroonga/storage/suite.pm b/storage/mroonga/mysql-test/mroonga/storage/suite.pm
new file mode 100644
index 00000000..7e4f8c17
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/suite.pm
@@ -0,0 +1,23 @@
+package My::Suite::Mroonga;
+
+@ISA = qw(My::Suite);
+
+return "No Mroonga engine" unless $ENV{HA_MROONGA_SO} or
+ $::mysqld_variables{'mroonga'} eq "ON";
+
+sub is_default { not $::opt_embedded_server }
+
+my $groonga_normalizer_mysql_dir=$::basedir . '/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql';
+my $groonga_normalizer_mysql_install_dir=$::basedir . '/lib/groonga/plugins';
+
+if (-d $groonga_normalizer_mysql_dir)
+{
+ $ENV{GRN_PLUGINS_DIR}=$groonga_normalizer_mysql_dir;
+}
+elsif (-d $groonga_normalizer_mysql_install_dir)
+{
+ $ENV{GRN_PLUGINS_DIR}=$groonga_normalizer_mysql_install_dir;
+}
+
+bless { };
+
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_after.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_after.test
new file mode 100644
index 00000000..0e348f26
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_after.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+ALTER TABLE diaries ADD title VARCHAR(40) AFTER id;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_first.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_first.test
new file mode 100644
index 00000000..4375a6f1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_first.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+ALTER TABLE diaries ADD title VARCHAR(40) FIRST;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_comment.test
new file mode 100644
index 00000000..ec9e3c9d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_comment.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE tags ADD COLUMN name VARCHAR(64) COMMENT 'flags "COLUMN_VECTOR"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_parameter.test
new file mode 100644
index 00000000..e3b7df72
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_flags_parameter.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE tags ADD COLUMN name VARCHAR(64) FLAGS='COLUMN_VECTOR';
+SHOW CREATE TABLE tags;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_comment.test
new file mode 100644
index 00000000..964426b4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_comment.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE bugs ADD COLUMN name VARCHAR(64) COMMENT 'groonga_type "tags"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_parameter.test
new file mode 100644
index 00000000..0f92c024
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_groonga_type_parameter.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE bugs ADD COLUMN name VARCHAR(64) GROONGA_TYPE='tags';
+SHOW CREATE TABLE bugs;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_cp932.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_cp932.test
new file mode 100644
index 00000000..0516186b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_cp932.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES cp932;
+
+CREATE TABLE users (
+ id int PRIMARY KEY
+) DEFAULT CHARSET=cp932;
+ALTER TABLE users
+ ADD COLUMN O text,
+ ADD FULLTEXT INDEX (O);
+
+INSERT INTO users VALUES (1, "܂");
+INSERT INTO users VALUES (2, "Ȃ");
+INSERT INTO users VALUES (3, "");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_utf8.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_utf8.test
new file mode 100644
index 00000000..0ed92333
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multibyte_utf8.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ id int PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+ALTER TABLE users
+ ADD COLUMN 名前 text,
+ ADD FULLTEXT INDEX (名前);
+
+INSERT INTO users VALUES (1, "やまだ");
+INSERT INTO users VALUES (2, "たなか");
+INSERT INTO users VALUES (3, "すずき");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multiple.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multiple.test
new file mode 100644
index 00000000..a76869ac
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_multiple.test
@@ -0,0 +1,50 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries
+ ADD COLUMN body VARCHAR(140) FIRST,
+ ADD COLUMN published BOOLEAN AFTER id,
+ ADD COLUMN created_at DATETIME;
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+
+INSERT INTO diaries (title, body, published, created_at)
+ VALUES ("groonga (1)", "starting groonga...", TRUE, "2014-2-9 02:09:00");
+INSERT INTO diaries (title, body, published, created_at)
+ VALUES ("groonga (2)", "started groonga.", FALSE, "2014-2-9 12:19:00");
+SELECT * FROM diaries;
+
+SHOW CREATE TABLE diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_plain.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_plain.test
new file mode 100644
index 00000000..3e21daab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_plain.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries ADD COLUMN body VARCHAR(140);
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+
+SHOW CREATE TABLE diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_type_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_type_comment.test
new file mode 100644
index 00000000..54fb986a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_column_type_comment.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE bugs ADD COLUMN name VARCHAR(64) COMMENT 'type "tags"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_token_filters_one_token_filter.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_token_filters_one_token_filter.test
new file mode 100644
index 00000000..8a63885a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_token_filters_one_token_filter.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE memos ADD FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_duplicated.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_duplicated.test
new file mode 100644
index 00000000..bfc527c9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_duplicated.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO ids (id) values (1), (1);
+
+--error ER_DUP_UNIQUE
+ALTER TABLE ids ADD UNIQUE INDEX (id);
+SHOW CREATE TABLE ids;
+
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_multiple_column_duplicated.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_multiple_column_duplicated.test
new file mode 100644
index 00000000..dccba803
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_index_unique_multiple_column_duplicated.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id1 INT,
+ id2 INT
+) DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO ids (id1, id2) values (1, 2), (1, 2);
+
+--error ER_DUP_UNIQUE
+ALTER TABLE ids ADD UNIQUE INDEX (id1, id2);
+SHOW CREATE TABLE ids;
+
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_key_multiple_column_with_data.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_key_multiple_column_with_data.test
new file mode 100644
index 00000000..a7d9c4a4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_key_multiple_column_with_data.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE scores (
+ id BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ name CHAR(30) NOT NULL,
+ score INT NOT NULL
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores
+ WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+ALTER TABLE scores ADD KEY property (name, score);
+SELECT * FROM scores
+ WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_primary_key.test
new file mode 100644
index 00000000..a1cf13c2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_add_primary_key.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT NOT NULL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+
+ALTER TABLE ids ADD PRIMARY KEY (id);
+SHOW CREATE TABLE ids;
+
+SELECT * FROM ids WHERE id = 2;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_comment_not_for_mroonga.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_comment_not_for_mroonga.test
new file mode 100644
index 00000000..3f7aea2a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_comment_not_for_mroonga.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE bugs
+ CHANGE COLUMN
+ tag
+ tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.';
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_have_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_have_index.test
new file mode 100644
index 00000000..0fb3f176
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_have_index.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(32),
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE bugs CHANGE COLUMN title title VARCHAR(64);
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_after.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_after.test
new file mode 100644
index 00000000..70cf4d14
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_after.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+ALTER TABLE diaries CHANGE body description VARCHAR(140) AFTER id;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, description) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_first.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_first.test
new file mode 100644
index 00000000..b959d30e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_first.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+ALTER TABLE diaries CHANGE body description VARCHAR(140) FIRST;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, description) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_multiple.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_multiple.test
new file mode 100644
index 00000000..fa97b30d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_multiple.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+ALTER TABLE diaries
+ CHANGE body description VARCHAR(140) FIRST,
+ CHANGE title subject VARCHAR(40) AFTER internal_id,
+ CHANGE id internal_id INT AUTO_INCREMENT;
+SHOW CREATE TABLE diaries;
+
+INSERT IGNORE INTO diaries (subject, description)
+ VALUES ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_no_order.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_no_order.test
new file mode 100644
index 00000000..3e02a644
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_column_rename_no_order.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+ALTER TABLE diaries CHANGE body description VARCHAR(140);
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, description) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_decimal.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_decimal.test
new file mode 100644
index 00000000..d8775f07
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_decimal.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ temperature DECIMAL(6, 3)
+) ENGINE InnoDB DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (temperature) VALUES (21.281);
+SELECT * FROM diaries;
+
+ALTER TABLE diaries ENGINE = mroonga;
+SELECT * FROM diaries;
+
+INSERT INTO diaries (temperature) VALUES (14.213);
+INSERT INTO diaries (temperature) VALUES (17.821);
+SELECT * FROM diaries;
+
+SHOW CREATE TABLE diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_fulltext_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_fulltext_index.test
new file mode 100644
index 00000000..b9dfddda
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_engine_fulltext_index.test
@@ -0,0 +1,58 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) ENGINE MyISAM DEFAULT CHARSET UTF8;
+SELECT table_name, engine
+ FROM information_schema.tables
+ WHERE table_name = 'diaries';
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+ MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+ALTER TABLE diaries ENGINE = mroonga;
+SELECT table_name, engine
+ FROM information_schema.tables
+ WHERE table_name = 'diaries';
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+ MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AND
+ MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_token_filter.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_token_filter.test
new file mode 100644
index 00000000..8efaad2a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_change_token_filter.test
@@ -0,0 +1,55 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+CREATE TABLE terms (
+ term VARCHAR(64) NOT NULL PRIMARY KEY,
+ is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram"' DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+ALTER TABLE terms COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+ALTER TABLE memos DISABLE KEYS;
+ALTER TABLE memos ENABLE KEYS;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_create_fulltext.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_create_fulltext.test
new file mode 100644
index 00000000..ed3d4a13
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_create_fulltext.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ WHERE MATCH (title) AGAINST ("富士山");
+
+CREATE FULLTEXT INDEX title_index on diaries (title);
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries DISABLE KEYS;
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_table.test
new file mode 100644
index 00000000..83ce2ca7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_table.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+CREATE TABLE terms (
+ term varchar(256) NOT NULL PRIMARY KEY
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"'
+ DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id int PRIMARY KEY,
+ content text NOT NULL,
+ FULLTEXT INDEX content_index (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+ALTER TABLE memos DISABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_ujis.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_ujis.test
new file mode 100644
index 00000000..f612272f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_ujis.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES ujis;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=ujis;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "ŷ");
+INSERT INTO diaries VALUES (3, "ٻλ");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("ٻλ");
+
+ALTER TABLE diaries DISABLE KEYS;
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("ٻλ");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_utf8.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_utf8.test
new file mode 100644
index 00000000..999415b1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_fulltext_utf8.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries DISABLE KEYS;
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_multiple_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_multiple_column.test
new file mode 100644
index 00000000..d0e7e0e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_multiple_column.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY title_and_created_at_index (title, created_at)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+ALTER TABLE diaries DISABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_normal.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_normal.test
new file mode 100644
index 00000000..e8140ff5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_normal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY created_at_index (created_at)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+ALTER TABLE diaries DISABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_primary.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_primary.test
new file mode 100644
index 00000000..390afd98
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_primary.test
@@ -0,0 +1,47 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_truncate.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_truncate.test
new file mode 100644
index 00000000..8b3e0928
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_truncate.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ first_name VARCHAR(32) NOT NULL,
+ last_name VARCHAR(32) NOT NULL,
+ KEY (first_name, last_name)
+);
+
+INSERT INTO users VALUES("Taro", "Yamada");
+INSERT INTO users VALUES("Hanako", "Tanaka");
+INSERT INTO users VALUES("Joe", "Honda");
+
+SELECT * FROM users;
+
+ALTER TABLE users DISABLE KEYS;
+TRUNCATE users;
+
+SELECT * FROM users;
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_updating.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_updating.test
new file mode 100644
index 00000000..94a3de4b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_disable_keys_updating.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ c1 int NOT NULL,
+ c2 text NOT NULL,
+ c3 int NOT NULL,
+ c4 int NOT NULL,
+ PRIMARY KEY(c1),
+ KEY idx1(c3,c4),
+ FULLTEXT KEY ft1(c2)
+);
+INSERT INTO t1 VALUES(1, 'test1', 1, 1);
+INSERT INTO t1 VALUES(2, 'test2', 2, 2);
+INSERT INTO t1 VALUES(3, 'test3', 1, 3);
+ALTER TABLE t1 DISABLE KEYS;
+DELETE FROM t1 WHERE c1 = 2;
+UPDATE t1 SET c4 = 4 WHERE c1 = 1;
+INSERT INTO t1 VALUES(4, 'test4', 2, 4);
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_multiple.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_multiple.test
new file mode 100644
index 00000000..d640249d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_multiple.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries
+ DROP COLUMN title,
+ DROP COLUMN body;
+SHOW CREATE TABLE diaries;
+SELECT * FROM diaries;
+
+INSERT INTO diaries () VALUES ();
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_one.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_one.test
new file mode 100644
index 00000000..9544eb90
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_column_one.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries DROP COLUMN body;
+SHOW CREATE TABLE diaries;
+SELECT * FROM diaries;
+
+INSERT INTO diaries (title) values ("groonga (1)");
+INSERT INTO diaries (title) values ("groonga (2)");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_key_multiple_column_with_data.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_key_multiple_column_with_data.test
new file mode 100644
index 00000000..8596e18f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_key_multiple_column_with_data.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE scores (
+ id BIGINT(20) PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ name CHAR(30) NOT NULL,
+ score INT NOT NULL,
+ KEY property (name, score)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+SELECT * FROM scores
+ WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+ALTER TABLE scores DROP KEY property;
+SELECT * FROM scores
+ WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_primary_key.test
new file mode 100644
index 00000000..e12e5b8d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_drop_primary_key.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+
+ALTER TABLE ids DROP PRIMARY KEY;
+SHOW CREATE TABLE ids;
+
+SELECT * FROM ids WHERE id = 2;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext.test
new file mode 100644
index 00000000..e7f9f548
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_table.test
new file mode 100644
index 00000000..424e51ad
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_table.test
@@ -0,0 +1,47 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+CREATE TABLE terms (
+ term varchar(256) NOT NULL PRIMARY KEY
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"'
+ DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id int PRIMARY KEY,
+ content text NOT NULL,
+ FULLTEXT INDEX content_index (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE memos DISABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+ALTER TABLE memos ENABLE KEYS;
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_ujis.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_ujis.test
new file mode 100644
index 00000000..c5889caf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_ujis.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES ujis;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=ujis;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "ŷ");
+INSERT INTO diaries VALUES (3, "ٻλ");
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("ٻλ");
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("ٻλ");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_utf8.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_utf8.test
new file mode 100644
index 00000000..e7f9f548
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_fulltext_utf8.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_multiple_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_multiple_column.test
new file mode 100644
index 00000000..7ae83d84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_multiple_column.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY title_and_created_at_index (title, created_at)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_normal.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_normal.test
new file mode 100644
index 00000000..012fae91
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_normal.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY created_at_index (created_at)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_primary.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_primary.test
new file mode 100644
index 00000000..9817aa94
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_enable_keys_primary.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255)
+) DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_no_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_no_primary_key.test
new file mode 100644
index 00000000..41fae0e7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_no_primary_key.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+CREATE TABLE memos (
+ content varchar(32)
+) DEFAULT CHARSET="utf8";
+
+INSERT INTO memos (content) values ("Starting Groonga...");
+INSERT INTO memos (content) values ("Started Groonga.");
+INSERT INTO memos (content) values ("Starting Mroonga...");
+
+ALTER TABLE memos ADD FULLTEXT INDEX content_index (content);
+SHOW CREATE TABLE memos;
+
+SELECT * FROM memos WHERE MATCH(content) AGAINST("groonga");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_normal.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_normal.test
new file mode 100644
index 00000000..dab39fc8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_normal.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2011-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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT
+) DEFAULT CHARSET="utf8";
+
+INSERT INTO memos (content) values ("Starting Groonga...");
+INSERT INTO memos (content) values ("Started Groonga.");
+INSERT INTO memos (content) values ("Starting Mroonga...");
+
+ALTER TABLE memos ADD FULLTEXT INDEX content_index (content);
+
+SELECT * FROM memos WHERE MATCH(content) AGAINST("+groonga" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_table.test
new file mode 100644
index 00000000..fd2a6008
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_add_table.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2014 HAYASHI Kentaro <hayashi@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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags;
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags VARCHAR(40) COMMENT 'type "tags"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO tags (name) VALUES ("Groonga");
+INSERT INTO bugs (id, tags) VALUES (1, "Groonga Mroonga");
+
+SELECT * FROM bugs;
+
+ALTER TABLE bugs ADD FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"';
+
+SELECT * FROM bugs
+ WHERE MATCH(tags) AGAINST("Groonga");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_drop_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_drop_table.test
new file mode 100644
index 00000000..d59e24f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_fulltext_drop_table.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags;
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags VARCHAR(40) COMMENT 'type "tags"',
+ FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO tags (name) VALUES ("Groonga");
+INSERT INTO bugs (id, tags) VALUES (1, "Groonga Mroonga");
+
+ALTER TABLE bugs DROP INDEX bugs_tags_index;
+ALTER TABLE bugs
+ ADD FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"';
+
+SELECT * FROM bugs
+ WHERE MATCH(tags) AGAINST("Groonga");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_after.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_after.test
new file mode 100644
index 00000000..fb967163
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_after.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries MODIFY body VARCHAR(140) AFTER id;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_first.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_first.test
new file mode 100644
index 00000000..86d22e3c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_first.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries MODIFY body VARCHAR(140) FIRST;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_no_order.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_no_order.test
new file mode 100644
index 00000000..d39b4fc9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_modify_column_no_order.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ body VARCHAR(140)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga.");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries MODIFY title VARCHAR(100);
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_recreate_anonymous_index_at_once.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_recreate_anonymous_index_at_once.test
new file mode 100644
index 00000000..93210e13
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_recreate_anonymous_index_at_once.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX (body)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("survey", "will start mroonga!");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH (body) AGAINST ("+groonga" IN BOOLEAN MODE);
+
+ALTER TABLE diaries
+ DROP INDEX body,
+ ADD FULLTEXT INDEX (body);
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH (body) AGAINST ("+groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_rename_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_rename_table.test
new file mode 100644
index 00000000..1102144b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_rename_table.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries, memos;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SELECT table_name, engine
+ FROM information_schema.tables
+ WHERE table_name = 'diaries';
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("groonga") AND
+ MATCH(body) AGAINST("starting");
+
+ALTER TABLE diaries RENAME memos;
+SELECT * FROM memos;
+SELECT * FROM memos
+ WHERE MATCH(title) AGAINST("groonga") AND
+ MATCH(body) AGAINST("starting");
+
+SELECT table_name, engine
+ FROM information_schema.tables
+ WHERE table_name = 'memos';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_spatial.test b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_spatial.test
new file mode 100644
index 00000000..2581fa7c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/alter_table_spatial.test
@@ -0,0 +1,151 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/not_embedded.inc
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS shops;
+--enable_warnings
+
+CREATE TABLE shops (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name VARCHAR(40),
+ location GEOMETRY NOT NULL
+);
+
+INSERT INTO shops (name, location)
+ VALUES ('nezu-no-taiyaki',
+ ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+ VALUES ('taiyaki-kataoka',
+ ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+ VALUES ('soba-taiyaki-ku',
+ ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuruma',
+ ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+ VALUES ('hirose-ya',
+ ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+ VALUES ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+ VALUES ('omede-taiyaki',
+ ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+ VALUES ('onaga-ya',
+ ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+ VALUES ('shiro-ya',
+ ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+ VALUES ('fuji-ya',
+ ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+ VALUES ('miyoshi',
+ ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+ VALUES ('juju-ya',
+ ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+ VALUES ('tatsumi-ya',
+ ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+ VALUES ('tetsuji',
+ ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+ VALUES ('gazuma-ya',
+ ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+ VALUES ('honma-mon',
+ ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+ VALUES ('naniwa-ya',
+ ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuro-dai',
+ ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+ VALUES ('daruma',
+ ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+ VALUES ('yanagi-ya',
+ ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+ VALUES ('sharaku',
+ ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+ VALUES ('takane',
+ ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+ VALUES ('chiyoda',
+ ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+ VALUES ('da-ka-po',
+ ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+ VALUES ('matsushima-ya',
+ ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+ VALUES ('kazuya',
+ ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+ VALUES ('furuya-kogane-an',
+ ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+ VALUES ('hachi-no-ie',
+ ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+ VALUES ('azuki-chan',
+ ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuriko-an',
+ ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+ VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+ VALUES ('naze-ya',
+ ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+ VALUES ('sanoki-ya',
+ ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+ VALUES ('shigeta',
+ ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+ VALUES ('nishimi-ya',
+ ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+ VALUES ('hiiragi',
+ ST_GeomFromText('POINT(139.711517 35.647701)'));
+
+ALTER TABLE shops ADD SPATIAL KEY location_index (location);
+
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+ WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ ORDER BY id;
+
+SHOW CREATE TABLE shops;
+
+DROP TABLE shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..34a517f9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_TODO_SPLIT_ME.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (c1 int auto_increment, primary key(c1));
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+insert into t1 values(10);
+select c1 from t1 order by c1 desc limit 1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+insert into t1 values(6);
+select c1 from t1 order by c1 desc limit 1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc limit 1;
+drop table t1;
+
+create table t1 (c1 int, c2 int auto_increment, primary key(c1), key idx1(c2));
+insert into t1 values(1, null);
+select * from t1 order by c2 desc limit 1;
+insert into t1 values(2, null);
+select * from t1 order by c2 desc limit 1;
+insert into t1 values(3, 10);
+select * from t1 order by c2 desc limit 1;
+insert into t1 values(4, null);
+select * from t1 order by c2 desc limit 1;
+insert into t1 values(5, 6);
+select * from t1 order by c2 desc limit 1;
+insert into t1 values(6, null);
+select * from t1 order by c2 desc limit 1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_table_param.test b/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_table_param.test
new file mode 100644
index 00000000..f5de201d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_table_param.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (c1 int auto_increment, primary key(c1)) auto_increment=34129;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+show create table t1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+insert into t1 values(10);
+select c1 from t1 order by c1 desc;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+insert into t1 values(6);
+select c1 from t1 order by c1 desc;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+truncate table t1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+delete from t1;
+insert into t1 values(null);
+select c1 from t1 order by c1 desc;
+rename table t1 to t2;
+insert into t2 values(null);
+select c1 from t2 order by c1 desc;
+show create table t2;
+drop table t2;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_text.test b/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_text.test
new file mode 100644
index 00000000..a23e09de
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/auto_increment_text.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text
+);
+insert into diaries (body) values ("started groonga (long text)");
+select * from diaries;
+insert into diaries (body) values ("sleeping... (short text)");
+select * from diaries;
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/binlog_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/binlog_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..281617e3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/binlog_TODO_SPLIT_ME.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source include/have_log_bin.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+show variables like 'log_bin';
+
+set binlog_format="STATEMENT";
+
+create table t1 (c1 int primary key, c2 int) engine = mroonga;
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+drop table t1;
+
+set binlog_format="ROW";
+
+create table t1 (c1 int primary key, c2 int) engine = mroonga;
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+drop table t1;
+
+set binlog_format="MIXED";
+
+create table t1 (c1 int primary key, c2 int) engine = mroonga;
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test
new file mode 100644
index 00000000..d438a912
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_broken.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET NAMES UTF8;
+
+CREATE DATABASE check_test;
+USE check_test;
+
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT INDEX (title)
+);
+
+INSERT INTO diaries VALUES ('Hello');
+
+--remove_file $MYSQLD_DATADIR/check_test.mrn.000010C
+
+FLUSH TABLES;
+
+CHECK TABLE diaries;
+
+REPAIR TABLE diaries;
+DROP TABLE diaries;
+
+DROP DATABASE check_test;
+USE test;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/check_table_not_broken.test b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_not_broken.test
new file mode 100644
index 00000000..c3f24494
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/check_table_not_broken.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ title TEXT
+);
+
+INSERT INTO diaries VALUES ('Hello');
+
+CHECK TABLE diaries;
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_general_ci_french.test b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_general_ci_french.test
new file mode 100644
index 00000000..1139d5eb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_general_ci_french.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ content varchar(256) COLLATE utf8_general_ci,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES ("Je suis un garçon.");
+
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("garcon");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_french.test b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_french.test
new file mode 100644
index 00000000..e0480fb5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_french.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8mb4;
+CREATE TABLE diaries (
+ content varchar(256) COLLATE utf8mb4_unicode_520_ci,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO diaries VALUES ("Je suis un garçon.");
+
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("+garcon" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_japanese.test b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_japanese.test
new file mode 100644
index 00000000..a23126c3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_520_ci_japanese.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8mb4;
+CREATE TABLE diaries (
+ content varchar(256) COLLATE utf8mb4_unicode_520_ci,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO diaries VALUES ("ひらがなとカタカナを覚えました。");
+
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+かたかな" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_french.test b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_french.test
new file mode 100644
index 00000000..2fbf5da8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_french.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ content varchar(256) COLLATE utf8_unicode_ci,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES ("Je suis un garçon.");
+
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("garcon");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_japanese.test b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_japanese.test
new file mode 100644
index 00000000..bc598fea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/collation_utf8_unicode_ci_japanese.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ content varchar(256) COLLATE utf8_unicode_ci,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES ("ひらがなとカタカナを覚えました。");
+
+SELECT * FROM diaries WHERE MATCH (content) AGAINST ("かたかな");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_comment_index_not_for_mroonga.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_comment_index_not_for_mroonga.test
new file mode 100644
index 00000000..c21ce814
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_comment_index_not_for_mroonga.test
@@ -0,0 +1,34 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED,
+ INDEX (id) COMMENT 'ID search is required.'
+) DEFAULT CHARSET=utf8;
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_comment_normal_not_for_mroonga.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_comment_normal_not_for_mroonga.test
new file mode 100644
index 00000000..f0d4aebf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_comment_normal_not_for_mroonga.test
@@ -0,0 +1,34 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.'
+) DEFAULT CHARSET=utf8;
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_date_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_date_with_index.test
new file mode 100644
index 00000000..ef53212b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_date_with_index.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ created_at DATE,
+ KEY (created_at)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, created_at) VALUES ("clear day", "2012-01-29");
+INSERT INTO diaries (title, created_at) VALUES ("rainy day", "2012-01-30");
+INSERT INTO diaries (title, created_at) VALUES ("cloudy day", "2012-01-31");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE created_at BETWEEN "2012-01-29" AND "2012-01-30";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_date_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_date_without_index.test
new file mode 100644
index 00000000..63a2a39d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_date_without_index.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(40),
+ created_at DATE
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, created_at) VALUES ("clear day", "2012-01-29");
+INSERT INTO diaries (title, created_at) VALUES ("rainy day", "2012-01-30");
+INSERT INTO diaries (title, created_at) VALUES ("cloudy day", "2012-01-31");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE created_at BETWEEN "2012-01-29" AND "2012-01-30";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_date_zero_date.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_date_zero_date.test
new file mode 100644
index 00000000..8b069cab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_date_zero_date.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# Copyright(C) 2016-2017 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-1335 USA
+
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATE
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE timestamps;
+
+SET sql_mode = '';
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01");
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00");
+SET sql_mode = DEFAULT;
+
+SELECT * FROM timestamps;
+
+SELECT * FROM timestamps WHERE create_dt = "2012-01-01";
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_2038.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_2038.test
new file mode 100644
index 00000000..c9308b95
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_2038.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('2038-01-18 03:14:07', '2038-01-18 03:14:07');
+INSERT IGNORE INTO diaries (title, created_at)
+ VALUES ('2038-01-20 03:14:08', '2038-01-20 03:14:08');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_before_unix_epoch.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_before_unix_epoch.test
new file mode 100644
index 00000000..5a6cee77
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_before_unix_epoch.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT IGNORE INTO diaries (title, created_at)
+ VALUES ('1000-01-01 00:00:00', '1000-01-01 00:00:00');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_max.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_max.test
new file mode 100644
index 00000000..502d261c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_max.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT IGNORE INTO diaries (title, created_at)
+ VALUES ('9999-12-31 23:59:59', '9999-12-31 23:59:59');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_out_of_range.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_out_of_range.test
new file mode 100644
index 00000000..aa0bf65d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_32bit_out_of_range.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT IGNORE INTO diaries (title, created_at)
+ VALUES ('2012', '2012');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_2038.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_2038.test
new file mode 100644
index 00000000..9c2a4d92
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_2038.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('2038-01-19 03:14:07', '2038-01-19 03:14:07');
+INSERT INTO diaries (title, created_at)
+ VALUES ('2038-01-19 03:14:08', '2038-01-19 03:14:08');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_before_unix_epoch.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_before_unix_epoch.test
new file mode 100644
index 00000000..942a8cc5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_before_unix_epoch.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('1000-01-02 00:00:00', '1000-01-02 00:00:00');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_max.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_max.test
new file mode 100644
index 00000000..e1df8812
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_max.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('9999-12-31 23:59:59', '9999-12-31 23:59:59');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_strict_sql_mode_out_of_range.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_strict_sql_mode_out_of_range.test
new file mode 100644
index 00000000..ba01e892
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_strict_sql_mode_out_of_range.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO diaries (title, created_at)
+ VALUES ('2012', '2012');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_5_out_of_range.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_5_out_of_range.test
new file mode 100644
index 00000000..e3115505
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_5_out_of_range.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_version_5_5.inc
+--source ../../include/mroonga/have_mysql.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('2012', '2012');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_6_or_later_out_of_range.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_6_or_later_out_of_range.test
new file mode 100644
index 00000000..cfd370ae
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_64bit_version_5_6_or_later_out_of_range.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('2012', '2012');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_with_index.test
new file mode 100644
index 00000000..7cf8be3f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_with_index.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_fractional_seconds.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME(6),
+ KEY (created_at)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ("clear day", "2012-01-29 21:51:01.111111");
+INSERT INTO diaries (title, created_at)
+ VALUES ("rainy day", "2012-01-30 01:23:45.333");
+INSERT INTO diaries (title, created_at)
+ VALUES ("cloudy day", "2012-01-31 08:32:10.5555");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE created_at BETWEEN "2012-01-29 00:00:00.123456" AND
+ "2012-01-31 00:00:00.999999";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_without_index.test
new file mode 100644
index 00000000..2b3865f3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_fractional_seconds_without_index.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_fractional_seconds.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME(6)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ("clear day", "2012-01-29 21:51:01.111111");
+INSERT INTO diaries (title, created_at)
+ VALUES ("rainy day", "2012-01-30 01:23:45.333");
+INSERT INTO diaries (title, created_at)
+ VALUES ("cloudy day", "2012-01-31 08:32:10.5555");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE created_at BETWEEN "2012-01-29 00:00:00.123456" AND
+ "2012-01-31 00:00:00.999999";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_freebsd_before_unix_epoch.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_freebsd_before_unix_epoch.test
new file mode 100644
index 00000000..cebffc7e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_freebsd_before_unix_epoch.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_freebsd.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('1000-01-01 00:00:00', '1000-01-01 00:00:00');
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_date.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_date.test
new file mode 100644
index 00000000..6cd65be5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_date.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb_10_2_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+INSERT INTO timestamps (create_dt) VALUES ("0000-00-00 00:00:00");
+
+SELECT * FROM timestamps;
+
+INSERT INTO timestamps (create_dt) VALUES ("2015-06-17 00:00:00");
+SELECT * FROM timestamps;
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_month_day.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_month_day.test
new file mode 100644
index 00000000..8639e9ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mariadb_10_2_or_later_zero_month_day.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# Copyright(C) 2016-2017 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb_10_2_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+
+--error ER_WARN_DATA_OUT_OF_RANGE
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01 00:00:00");
+--error ER_WARN_DATA_OUT_OF_RANGE
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00 00:00:00");
+
+SELECT * FROM timestamps;
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_date.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_date.test
new file mode 100644
index 00000000..e4ed57dc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_date.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO timestamps (create_dt) VALUES ("0000-00-00 00:00:00");
+
+SELECT * FROM timestamps;
+
+INSERT INTO timestamps (create_dt) VALUES ("2015-06-17 00:00:00");
+SELECT * FROM timestamps;
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_month_day.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_month_day.test
new file mode 100644
index 00000000..e2fd01b1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_mysql_5_7_or_later_zero_month_day.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01 00:00:00");
+--error ER_TRUNCATED_WRONG_VALUE
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00 00:00:00");
+
+SELECT * FROM timestamps;
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_null.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_null.test
new file mode 100644
index 00000000..e51a6623
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_null.test
@@ -0,0 +1,36 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ('NULL', NULL);
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_with_index.test
new file mode 100644
index 00000000..f93bffd9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_with_index.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME,
+ KEY (created_at)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ("clear day", "2012-01-29 21:51:01");
+INSERT INTO diaries (title, created_at)
+ VALUES ("rainy day", "2012-01-30 01:23:45");
+INSERT INTO diaries (title, created_at)
+ VALUES ("cloudy day", "2012-01-31 08:32:10");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE created_at BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_without_index.test
new file mode 100644
index 00000000..0df1be26
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_without_index.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at)
+ VALUES ("clear day", "2012-01-29 21:51:01");
+INSERT INTO diaries (title, created_at)
+ VALUES ("rainy day", "2012-01-30 01:23:45");
+INSERT INTO diaries (title, created_at)
+ VALUES ("cloudy day", "2012-01-31 08:32:10");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE created_at BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_date.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_date.test
new file mode 100644
index 00000000..b0c0e11a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_date.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+
+SET sql_mode='STRICT_TRANS_TABLES';
+--error ER_WARN_DATA_OUT_OF_RANGE
+INSERT INTO timestamps (create_dt) VALUES ("0000-00-00 00:00:00");
+SET sql_mode=default;
+
+SELECT * FROM timestamps;
+
+INSERT INTO timestamps (create_dt) VALUES ("2015-06-17 00:00:00");
+SELECT * FROM timestamps;
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_month_day.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_month_day.test
new file mode 100644
index 00000000..f3ec9465
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_datetime_zero_month_day.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# Copyright(C) 2016-2017 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-1335 USA
+
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timestamps;
+--enable_warnings
+
+CREATE TABLE timestamps (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ create_dt DATETIME
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO timestamps (create_dt) VALUES ("2012-00-01 00:00:00");
+INSERT INTO timestamps (create_dt) VALUES ("2012-01-00 00:00:00");
+
+SELECT * FROM timestamps;
+
+SELECT * FROM timestamps WHERE create_dt = "2012-01-01 00:00:00";
+
+DROP TABLE timestamps;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_with_index.test
new file mode 100644
index 00000000..cf201088
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_with_index.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ temperature DECIMAL(6, 3),
+ KEY (temperature)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21.281);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14.213);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17.821);
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE temperature BETWEEN "14.213" AND "17.821";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_without_index.test
new file mode 100644
index 00000000..83fd7564
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_fractional_seconds_without_index.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ temperature DECIMAL(6, 3)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21.281);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14.213);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17.821);
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE temperature BETWEEN "14.213" AND "17.821";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_with_index.test
new file mode 100644
index 00000000..315846cc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_with_index.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ temperature DECIMAL,
+ KEY (temperature)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17);
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE temperature BETWEEN "14" AND "17";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_without_index.test
new file mode 100644
index 00000000..6924885f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_decimal_without_index.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ temperature DECIMAL
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, temperature) VALUES ("clear day", 21);
+INSERT INTO diaries (title, temperature) VALUES ("rainy day", 14);
+INSERT INTO diaries (title, temperature) VALUES ("cloudy day", 17);
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE temperature BETWEEN "14" AND "17";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_enum_less_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_enum_less_with_index.test
new file mode 100644
index 00000000..ae85ae7a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_enum_less_with_index.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ size ENUM("small", "medium", "large"),
+ INDEX (size)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart for child", "small");
+INSERT INTO items VALUES ("leadies' coat", "medium");
+INSERT INTO items VALUES ("parka", "large");
+INSERT INTO items VALUES ("hat", "medium");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE size = "medium";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_enum_many_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_enum_many_with_index.test
new file mode 100644
index 00000000..91daafed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_enum_many_with_index.test
@@ -0,0 +1,298 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ size ENUM("size1",
+ "size2",
+ "size3",
+ "size4",
+ "size5",
+ "size6",
+ "size7",
+ "size8",
+ "size9",
+ "size10",
+ "size11",
+ "size12",
+ "size13",
+ "size14",
+ "size15",
+ "size16",
+ "size17",
+ "size18",
+ "size19",
+ "size20",
+ "size21",
+ "size22",
+ "size23",
+ "size24",
+ "size25",
+ "size26",
+ "size27",
+ "size28",
+ "size29",
+ "size30",
+ "size31",
+ "size32",
+ "size33",
+ "size34",
+ "size35",
+ "size36",
+ "size37",
+ "size38",
+ "size39",
+ "size40",
+ "size41",
+ "size42",
+ "size43",
+ "size44",
+ "size45",
+ "size46",
+ "size47",
+ "size48",
+ "size49",
+ "size50",
+ "size51",
+ "size52",
+ "size53",
+ "size54",
+ "size55",
+ "size56",
+ "size57",
+ "size58",
+ "size59",
+ "size60",
+ "size61",
+ "size62",
+ "size63",
+ "size64",
+ "size65",
+ "size66",
+ "size67",
+ "size68",
+ "size69",
+ "size70",
+ "size71",
+ "size72",
+ "size73",
+ "size74",
+ "size75",
+ "size76",
+ "size77",
+ "size78",
+ "size79",
+ "size80",
+ "size81",
+ "size82",
+ "size83",
+ "size84",
+ "size85",
+ "size86",
+ "size87",
+ "size88",
+ "size89",
+ "size90",
+ "size91",
+ "size92",
+ "size93",
+ "size94",
+ "size95",
+ "size96",
+ "size97",
+ "size98",
+ "size99",
+ "size100",
+ "size101",
+ "size102",
+ "size103",
+ "size104",
+ "size105",
+ "size106",
+ "size107",
+ "size108",
+ "size109",
+ "size110",
+ "size111",
+ "size112",
+ "size113",
+ "size114",
+ "size115",
+ "size116",
+ "size117",
+ "size118",
+ "size119",
+ "size120",
+ "size121",
+ "size122",
+ "size123",
+ "size124",
+ "size125",
+ "size126",
+ "size127",
+ "size128",
+ "size129",
+ "size130",
+ "size131",
+ "size132",
+ "size133",
+ "size134",
+ "size135",
+ "size136",
+ "size137",
+ "size138",
+ "size139",
+ "size140",
+ "size141",
+ "size142",
+ "size143",
+ "size144",
+ "size145",
+ "size146",
+ "size147",
+ "size148",
+ "size149",
+ "size150",
+ "size151",
+ "size152",
+ "size153",
+ "size154",
+ "size155",
+ "size156",
+ "size157",
+ "size158",
+ "size159",
+ "size160",
+ "size161",
+ "size162",
+ "size163",
+ "size164",
+ "size165",
+ "size166",
+ "size167",
+ "size168",
+ "size169",
+ "size170",
+ "size171",
+ "size172",
+ "size173",
+ "size174",
+ "size175",
+ "size176",
+ "size177",
+ "size178",
+ "size179",
+ "size180",
+ "size181",
+ "size182",
+ "size183",
+ "size184",
+ "size185",
+ "size186",
+ "size187",
+ "size188",
+ "size189",
+ "size190",
+ "size191",
+ "size192",
+ "size193",
+ "size194",
+ "size195",
+ "size196",
+ "size197",
+ "size198",
+ "size199",
+ "size200",
+ "size201",
+ "size202",
+ "size203",
+ "size204",
+ "size205",
+ "size206",
+ "size207",
+ "size208",
+ "size209",
+ "size210",
+ "size211",
+ "size212",
+ "size213",
+ "size214",
+ "size215",
+ "size216",
+ "size217",
+ "size218",
+ "size219",
+ "size220",
+ "size221",
+ "size222",
+ "size223",
+ "size224",
+ "size225",
+ "size226",
+ "size227",
+ "size228",
+ "size229",
+ "size230",
+ "size231",
+ "size232",
+ "size233",
+ "size234",
+ "size235",
+ "size236",
+ "size237",
+ "size238",
+ "size239",
+ "size240",
+ "size241",
+ "size242",
+ "size243",
+ "size244",
+ "size245",
+ "size246",
+ "size247",
+ "size248",
+ "size249",
+ "size250",
+ "size251",
+ "size252",
+ "size253",
+ "size254",
+ "size255",
+ "size256"),
+ INDEX (size)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart for child", "size1");
+INSERT INTO items VALUES ("leadies' coat", "size1");
+INSERT INTO items VALUES ("parka", "size256");
+INSERT INTO items VALUES ("hat", "size256");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE size = "size1";
+
+SELECT * FROM items WHERE size = "size256";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_add_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_add_column.test
new file mode 100644
index 00000000..5dc58df1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_add_column.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+set names utf8mb4;
+
+CREATE TABLE logs (
+ id INT,
+ record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (1, json_object('message', repeat('☹', 253)));
+
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED;
+ALTER TABLE logs ADD FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"';
+
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_delete.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_delete.test
new file mode 100644
index 00000000..f8e658f0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_delete.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+DELETE FROM logs WHERE id = 1;
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_drop_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_drop_column.test
new file mode 100644
index 00000000..342f954b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_drop_column.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+ALTER TABLE logs DROP COLUMN message;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_insert.test
new file mode 100644
index 00000000..009b519a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_insert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_reindex.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_reindex.test
new file mode 100644
index 00000000..18c624a3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_reindex.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+ALTER TABLE logs DISABLE KEYS;
+ALTER TABLE logs ENABLE KEYS;
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_update.test
new file mode 100644
index 00000000..07b987ce
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_stored_update.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("hut" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_add_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_add_column.test
new file mode 100644
index 00000000..ffbe2415
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_add_column.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL;
+
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_delete.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_delete.test
new file mode 100644
index 00000000..8e110a23
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_delete.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+DELETE FROM logs WHERE id = 1;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_drop_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_drop_column.test
new file mode 100644
index 00000000..2b723d46
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_drop_column.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+ALTER TABLE logs DROP COLUMN message;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_insert.test
new file mode 100644
index 00000000..7cb6895a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_insert.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_add_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_add_index.test
new file mode 100644
index 00000000..ca9bb7a4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_add_index.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mariadb_10_2_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+--error 16509
+ALTER TABLE logs ADD INDEX (message);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.test
new file mode 100644
index 00000000..49bc21c9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mariadb_10_2_or_later_create_table_with_index.test
@@ -0,0 +1,32 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mariadb_10_2_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+--error 16509
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL,
+ FULLTEXT INDEX (message)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mysql_5_7_or_later_add_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mysql_5_7_or_later_add_index.test
new file mode 100644
index 00000000..c624566c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_mysql_5_7_or_later_add_index.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+--error ER_ILLEGAL_HA_CREATE_OPTION
+ALTER TABLE logs ADD INDEX (message);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_update.test
new file mode 100644
index 00000000..76d80420
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_generated_virtual_update.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id__id.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id__id.test
new file mode 100644
index 00000000..17a69b3e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id__id.test
@@ -0,0 +1,34 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS contents;
+--enable_warnings
+
+CREATE TABLE contents (
+ _id INT,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX(content)
+) DEFAULT CHARSET=utf8;
+INSERT INTO contents (content) VALUES ('first');
+INSERT INTO contents (content) VALUES ('second');
+SELECT _id, content FROM contents;
+
+DROP TABLE contents;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id_invalid_id.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id_invalid_id.test
new file mode 100644
index 00000000..1d30d0ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga__id_invalid_id.test
@@ -0,0 +1,34 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS contents;
+--enable_warnings
+
+--error ER_CANT_CREATE_TABLE
+CREATE TABLE contents (
+ _i INT,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX(content)
+) DEFAULT CHARSET=utf8;
+
+--disable_warnings
+DROP TABLE IF EXISTS contents;
+--enable_warnings
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_other_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_other_table.test
new file mode 100644
index 00000000..d171d062
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_other_table.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+CREATE TABLE terms (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COMMENT='default_tokenizer "TokenBigram"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ title TEXT,
+ FULLTEXT INDEX (title) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO bugs (id, title) VALUES (1, "Mroonga can't build with MySQL X.Y.Z");
+
+SELECT * FROM terms ORDER BY name;
+
+SELECT *, MATCH (title) AGAINST ("+MySQL" IN BOOLEAN MODE) AS score
+ FROM bugs
+ WHERE MATCH (title) AGAINST ("+MySQL" IN BOOLEAN MODE);
+
+DROP TABLE bugs;
+DROP TABLE terms;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_vector_other_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_vector_other_table.test
new file mode 100644
index 00000000..c23f35ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_fulltext_vector_other_table.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS mroonga;
+--enable_warnings
+
+CREATE DATABASE mroonga;
+USE mroonga;
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags TEXT COMMENT 'flags "COLUMN_VECTOR", type "tags"',
+ FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL groonga");
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+SELECT *, MATCH (tags) AGAINST ("+MySQL" IN BOOLEAN MODE) AS score
+ FROM bugs
+ WHERE MATCH (tags) AGAINST ("+MySQL" IN BOOLEAN MODE);
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+DROP DATABASE mroonga;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_int_other_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_int_other_table.test
new file mode 100644
index 00000000..9e128a00
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_index_int_other_table.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS mroonga;
+--enable_warnings
+
+CREATE DATABASE mroonga;
+USE mroonga;
+
+CREATE TABLE priorities (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ priority INT COMMENT 'type "priorities"',
+ INDEX bugs_priority_index (priority) COMMENT 'table "priorities"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO bugs (id, priority) VALUES (1, 10);
+INSERT INTO bugs (id, priority) VALUES (2, 3);
+INSERT INTO bugs (id, priority) VALUES (3, -2);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+SELECT *
+ FROM bugs
+ WHERE priority = 3;
+
+DROP TABLE bugs;
+DROP TABLE priorities;
+
+DROP DATABASE mroonga;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_reference.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_reference.test
new file mode 100644
index 00000000..359dbbda
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_reference.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags, bugs;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag TEXT COMMENT 'type "tags"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO bugs (id, tag) VALUES (1, "Linux");
+INSERT INTO bugs (id, tag) VALUES (2, "MySQL");
+INSERT INTO bugs (id, tag) VALUES (3, "groonga");
+
+SELECT * FROM bugs;
+SELECT * FROM tags;
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_lz4.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_lz4.test
new file mode 100644
index 00000000..f0362241
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_lz4.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/support_libgroonga_lz4.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS entries;
+--enable_warnings
+
+CREATE TABLE entries (
+ id INT UNSIGNED PRIMARY KEY,
+ content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_LZ4"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+
+SELECT * FROM entries;
+
+DROP TABLE entries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zlib.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zlib.test
new file mode 100644
index 00000000..612b2d6a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zlib.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/support_libgroonga_zlib.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS entries;
+--enable_warnings
+
+CREATE TABLE entries (
+ id INT UNSIGNED PRIMARY KEY,
+ content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZLIB"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+
+SELECT * FROM entries;
+
+DROP TABLE entries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zstd.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zstd.test
new file mode 100644
index 00000000..74b79210
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_support_zstd.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/support_libgroonga_zstd.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS entries;
+--enable_warnings
+
+CREATE TABLE entries (
+ id INT UNSIGNED PRIMARY KEY,
+ content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZSTD"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+
+SELECT * FROM entries;
+
+DROP TABLE entries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_lz4.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_lz4.test
new file mode 100644
index 00000000..73f15477
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_lz4.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/unsupport_libgroonga_lz4.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS entries;
+--enable_warnings
+
+CREATE TABLE entries (
+ id INT UNSIGNED PRIMARY KEY,
+ content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_LZ4"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+
+SELECT * FROM entries;
+
+DROP TABLE entries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zlib.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zlib.test
new file mode 100644
index 00000000..6d97eb5a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zlib.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/unsupport_libgroonga_zlib.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS entries;
+--enable_warnings
+
+CREATE TABLE entries (
+ id INT UNSIGNED PRIMARY KEY,
+ content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZLIB"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+
+SELECT * FROM entries;
+
+DROP TABLE entries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zstd.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zstd.test
new file mode 100644
index 00000000..b9a5dce5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_unsupport_zstd.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/unsupport_libgroonga_zstd.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS entries;
+--enable_warnings
+
+CREATE TABLE entries (
+ id INT UNSIGNED PRIMARY KEY,
+ content TEXT COMMENT 'flags "COLUMN_SCALAR|COMPRESS_ZSTD"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO entries (id, content) VALUES (1, "I found Mroonga that is a MySQL storage engine to use Groonga!");
+
+SELECT * FROM entries;
+
+DROP TABLE entries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_with_not_for_mroonga_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_with_not_for_mroonga_comment.test
new file mode 100644
index 00000000..bd5894f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_scalar_with_not_for_mroonga_comment.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags, bugs;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag TEXT COMMENT 'It references to tags.name, type "tags"'
+) DEFAULT CHARSET=utf8;
+
+SHOW FULL COLUMNS FROM bugs LIKE 'tag';
+
+INSERT INTO bugs (id, tag) VALUES (1, "Linux");
+INSERT INTO bugs (id, tag) VALUES (2, "MySQL");
+INSERT INTO bugs (id, tag) VALUES (3, "groonga");
+
+SELECT * FROM bugs;
+SELECT * FROM tags;
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_order_by_with_function.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_order_by_with_function.test
new file mode 100644
index 00000000..1787c111
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_order_by_with_function.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags, bugs;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags TEXT COMMENT 'flags "COLUMN_VECTOR", type "tags"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL Groonga");
+INSERT INTO bugs (id, tags) VALUES (2, "MySQL Mroonga");
+INSERT INTO bugs (id, tags) VALUES (3, "Ruby Rroonga");
+
+SELECT * FROM tags ORDER BY SUBSTRING(name, 1, 1) ASC;
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_reference.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_reference.test
new file mode 100644
index 00000000..29ccc4e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_groonga_vector_reference.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2013-2017 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags, bugs;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags VARCHAR(128) DEFAULT '' COMMENT 'flags "COLUMN_VECTOR", type "tags"'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE bugs;
+
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL groonga");
+
+SELECT * FROM bugs;
+SELECT * FROM tags;
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_int_with_index_zero_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_int_with_index_zero_value.test
new file mode 100644
index 00000000..758f01cf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_int_with_index_zero_value.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price INT KEY
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("hamburger", 200);
+INSERT INTO items VALUES ("smile", 0);
+INSERT INTO items VALUES ("coke", 100);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price = 0;
+
+SELECT * FROM items WHERE price <= 100;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_json_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_json_insert.test
new file mode 100644
index 00000000..9e031a3a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_json_insert.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_0_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO logs VALUES ('{"message": "start"}');
+INSERT INTO logs VALUES ('{"message": "restart"}');
+INSERT INTO logs VALUES ('{"message": "shutdown"}');
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_cp932.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_cp932.test
new file mode 100644
index 00000000..be26045a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_cp932.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES cp932;
+
+CREATE TABLE users (
+ O text,
+ FULLTEXT INDEX (O)
+) DEFAULT CHARSET=cp932;
+
+INSERT INTO users VALUES ("܂");
+INSERT INTO users VALUES ("Ȃ");
+INSERT INTO users VALUES ("");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_utf8.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_utf8.test
new file mode 100644
index 00000000..efbaf31f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_multibyte_utf8.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ 名前 text,
+ FULLTEXT INDEX (名前)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES ("やまだ");
+INSERT INTO users VALUES ("たなか");
+INSERT INTO users VALUES ("すずき");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_set_16_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_16_with_index.test
new file mode 100644
index 00000000..c1f7fa3d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_16_with_index.test
@@ -0,0 +1,56 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ colors SET("black",
+ "dim gray",
+ "dark gray",
+ "gray",
+ "light gray",
+ "gainsboro",
+ "white smoke",
+ "white",
+
+ "red",
+ "orange red",
+ "dark orange",
+ "orange",
+ "gold",
+ "yellow",
+ "chartreuse",
+ "lawn green"),
+ INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart", "black,gray");
+INSERT INTO items VALUES ("hat", "white,dark gray");
+INSERT INTO items VALUES ("parka", "chartreuse,orange");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE colors = "dark gray,white";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_set_24_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_24_with_index.test
new file mode 100644
index 00000000..0b02b5e6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_24_with_index.test
@@ -0,0 +1,65 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ colors SET("black",
+ "dim gray",
+ "dark gray",
+ "gray",
+ "light gray",
+ "gainsboro",
+ "white smoke",
+ "white",
+
+ "red",
+ "orange red",
+ "dark orange",
+ "orange",
+ "gold",
+ "yellow",
+ "chartreuse",
+ "lawn green",
+
+ "green",
+ "spring green",
+ "medium spring green",
+ "cyan",
+ "deep sky blue",
+ "blue",
+ "medium blue",
+ "dark violet"),
+ INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart", "black,white");
+INSERT INTO items VALUES ("hat", "white,lawn green");
+INSERT INTO items VALUES ("parka", "gray,medium blue");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE colors = "white,lawn green";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_set_32_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_32_with_index.test
new file mode 100644
index 00000000..2dd39e8d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_32_with_index.test
@@ -0,0 +1,74 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ colors SET("black",
+ "dim gray",
+ "dark gray",
+ "gray",
+ "light gray",
+ "gainsboro",
+ "white smoke",
+ "white",
+
+ "red",
+ "orange red",
+ "dark orange",
+ "orange",
+ "gold",
+ "yellow",
+ "chartreuse",
+ "lawn green",
+
+ "green",
+ "spring green",
+ "medium spring green",
+ "cyan",
+ "deep sky blue",
+ "blue",
+ "medium blue",
+ "dark violet",
+
+ "dark magenta",
+ "magenta",
+ "dark red",
+ "brown",
+ "firebrick",
+ "indian red",
+ "light coral",
+ "salmon"),
+ INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart", "black,white");
+INSERT INTO items VALUES ("hat", "white,dark violet");
+INSERT INTO items VALUES ("parka", "green,brown,red");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE colors = "white,dark violet";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_set_64_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_64_with_index.test
new file mode 100644
index 00000000..117be846
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_64_with_index.test
@@ -0,0 +1,110 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ colors SET("black",
+ "dim gray",
+ "dark gray",
+ "gray",
+ "light gray",
+ "gainsboro",
+ "white smoke",
+ "white",
+
+ "red",
+ "orange red",
+ "dark orange",
+ "orange",
+ "gold",
+ "yellow",
+ "chartreuse",
+ "lawn green",
+
+ "green",
+ "spring green",
+ "medium spring green",
+ "cyan",
+ "deep sky blue",
+ "blue",
+ "medium blue",
+ "dark violet",
+
+ "dark magenta",
+ "magenta",
+ "dark red",
+ "brown",
+ "firebrick",
+ "indian red",
+ "light coral",
+ "salmon",
+
+ "light salmon",
+ "tomato",
+ "coral",
+ "dark salmon",
+ "rosy brown",
+ "sienna",
+ "saddle brown",
+ "chocolate",
+
+ "peru",
+ "sandy brown",
+ "burlywood",
+ "tan",
+ "navajo white",
+ "wheat",
+ "dark goldenrod",
+ "goldenrod",
+
+ "light goldenrod",
+ "pale goldenrod",
+ "cornsilk",
+ "dark khaki",
+ "khaki",
+ "lemon chiffon",
+ "dark olive green",
+ "olive drab",
+
+ "yellow green",
+ "green yellow",
+ "light green",
+ "forest green",
+ "dark green",
+ "lime green",
+ "pale green",
+ "dark sea green"),
+ INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart", "black,white,lawn green,dark violet");
+INSERT INTO items VALUES ("hat", "white,dark violet,yellow green");
+INSERT INTO items VALUES ("parka", "green,brown,red,lime green");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE colors = "white,dark violet,yellow green";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_set_8_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_8_with_index.test
new file mode 100644
index 00000000..001f4a4a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_set_8_with_index.test
@@ -0,0 +1,47 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ colors SET("black",
+ "dim gray",
+ "dark gray",
+ "gray",
+ "light gray",
+ "gainsboro",
+ "white smoke",
+ "white"),
+ INDEX (colors)
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items VALUES ("t-shart", "black,gray");
+INSERT INTO items VALUES ("hat", "dim gray,dark gray");
+INSERT INTO items VALUES ("parka", "white smoke,light gray");
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE colors = "dim gray,dark gray";
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_bigint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_bigint_with_index.test
new file mode 100644
index 00000000..4587be4d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_bigint_with_index.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price BIGINT KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("house", 9223372036854775807);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -9223372036854775808);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("super car", 2147483648);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 2147483648;
+
+SELECT * FROM items WHERE price > 2147483647;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_int_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_int_with_index.test
new file mode 100644
index 00000000..18f52ac0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_int_with_index.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price INT KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("car", 2147483647);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -2147483647);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 16777216);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 16777216;
+
+SELECT * FROM items WHERE price > 16777215;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_mediumint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_mediumint_with_index.test
new file mode 100644
index 00000000..0d37290f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_mediumint_with_index.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price MEDIUMINT KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("car", 8388607);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -8388608);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 32768);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 127;
+
+SELECT * FROM items WHERE price >= 32768;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_smallint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_smallint_with_index.test
new file mode 100644
index 00000000..ba6b4388
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_smallint_with_index.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price SMALLINT KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", -32768);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("tablet PC", 20000);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 127;
+
+SELECT * FROM items WHERE price >= 128;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_tinyint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_tinyint_with_index.test
new file mode 100644
index 00000000..5978564a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_signed_tinyint_with_index.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price TINYINT KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("hamburger", 120);
+INSERT INTO items VALUES ("discount", -10);
+INSERT INTO items VALUES ("coke", 100);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 100;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_time_fractional_seconds_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_time_fractional_seconds_with_index.test
new file mode 100644
index 00000000..05afa745
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_time_fractional_seconds_with_index.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_fractional_seconds.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS running_records;
+--enable_warnings
+
+CREATE TABLE running_records (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ average TIME(6),
+ max TIME(6),
+ KEY (average)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO running_records (title, average, max)
+ VALUES ("normal condition", "01:00:00.000001", "01:05:00.000001");
+INSERT INTO running_records (title, average, max)
+ VALUES ("bad condition", "12:23:34.123456", "838:59:58.999999");
+INSERT INTO running_records (title, average, max)
+ VALUES ("record failure", "-838:59:59.000000", "-838:59:59.000000");
+
+SELECT * FROM running_records;
+
+SELECT * FROM running_records
+ WHERE average BETWEEN "00:59:59.999999" AND "100:10:10.101010";
+
+SELECT * FROM running_records
+ WHERE average BETWEEN "-838:59:59.000000" AND "01:00:00.000001";
+
+DROP TABLE running_records;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_time_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_time_with_index.test
new file mode 100644
index 00000000..b6de0404
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_time_with_index.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS running_records;
+--enable_warnings
+
+CREATE TABLE running_records (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ average TIME,
+ max TIME,
+ KEY (average)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO running_records (title, average, max)
+ VALUES ("normal condition", "01:00:00", "01:05:00");
+INSERT INTO running_records (title, average, max)
+ VALUES ("bad condition", "12:23:34", "838:59:59");
+INSERT INTO running_records (title, average, max)
+ VALUES ("record failure", "-838:59:59", "-838:59:59");
+
+SELECT * FROM running_records;
+
+SELECT * FROM running_records
+ WHERE average BETWEEN "00:59:59" AND "100:10:10";
+
+SELECT * FROM running_records
+ WHERE average BETWEEN "-838:59:59" AND "01:00:00";
+
+DROP TABLE running_records;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_fractional_seconds_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_fractional_seconds_with_index.test
new file mode 100644
index 00000000..c4f1980a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_fractional_seconds_with_index.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_fractional_seconds.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at TIMESTAMP(6),
+ updated_at TIMESTAMP(6),
+ KEY (updated_at)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at, updated_at)
+ VALUES ("clear day",
+ "2012-01-29 21:51:01.111111",
+ "2012-01-29 21:51:02.222222");
+INSERT INTO diaries (title, created_at, updated_at)
+ VALUES ("rainy day",
+ "2012-01-30 01:23:45.333",
+ "2012-01-30 01:23:46.444");
+INSERT INTO diaries (title, created_at, updated_at)
+ VALUES ("cloudy day",
+ "2012-01-31 08:32:10.5555",
+ "2012-01-31 08:32:11.6666");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE updated_at BETWEEN "2012-01-29 00:00:00.123456" AND
+ "2012-01-31 00:00:00.999999";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_with_index.test
new file mode 100644
index 00000000..1410b4c3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_timestamp_with_index.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ created_at TIMESTAMP DEFAULT '2016-04-21 00:00:00',
+ updated_at TIMESTAMP DEFAULT '2016-04-21 00:00:00',
+ KEY (updated_at)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, created_at, updated_at)
+ VALUES ("clear day", "2012-01-29 21:51:01", "2012-01-29 21:51:02");
+INSERT INTO diaries (title, created_at, updated_at)
+ VALUES ("rainy day", "2012-01-30 01:23:45", "2012-01-30 01:23:46");
+INSERT INTO diaries (title, created_at, updated_at)
+ VALUES ("cloudy day", "2012-01-31 08:32:10", "2012-01-31 08:32:11");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE updated_at BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_tinyint_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_tinyint_without_index.test
new file mode 100644
index 00000000..08884ae5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_tinyint_without_index.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists books;
+--enable_warnings
+
+create table books(title varchar(255), published tinyint);
+insert into books values ("MySQL", 1);
+insert into books values ("groonga", 1);
+insert into books values ("mroonga", 0);
+
+select count(*) from books where published = 0;
+select count(*) from books where published = 1;
+select count(*) from books where published != 2;
+select count(*) from books where published != 1;
+
+drop table books;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_with_index.test
new file mode 100644
index 00000000..dee9bcb2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_with_index.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price BIGINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("house", 18446744073709551615);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("super car", 9223372036854775808);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 9223372036854775808;
+
+SELECT * FROM items WHERE price > 9223372036854775807;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_without_index.test
new file mode 100644
index 00000000..be97f2da
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_bigint_without_index.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id BIGINT UNSIGNED
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES (317173755057152000);
+INSERT INTO ids VALUES (317173755057152002);
+
+SELECT * FROM ids;
+
+SELECT * FROM ids WHERE id = 317173755057152000;
+
+SELECT * FROM ids WHERE id = 317173755057152002;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_int_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_int_with_index.test
new file mode 100644
index 00000000..52c98463
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_int_with_index.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price INT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("car", 4294967295);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 2147483648);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 2147483648;
+
+SELECT * FROM items WHERE price > 2147483647;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_mediumint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_mediumint_with_index.test
new file mode 100644
index 00000000..940695ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_mediumint_with_index.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price MEDIUMINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("car", 16777215);
+INSERT INTO items VALUES ("note PC", 32767);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("bike", 8388607);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 8388608;
+
+SELECT * FROM items WHERE price >= 8388607;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_smallint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_smallint_with_index.test
new file mode 100644
index 00000000..2e941449
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_smallint_with_index.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price SMALLINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("note PC", 65535);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+INSERT INTO items VALUES ("tablet PC", 32767);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 32768;
+
+SELECT * FROM items WHERE price >= 32767;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_tinyint_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_tinyint_with_index.test
new file mode 100644
index 00000000..72d436b1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_unsigned_tinyint_with_index.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ name VARCHAR(255),
+ price TINYINT UNSIGNED KEY
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES ("hamburger", 255);
+INSERT INTO items VALUES ("discount", 0);
+INSERT INTO items VALUES ("coke", 100);
+
+SELECT * FROM items;
+
+SELECT * FROM items WHERE price <= 100;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_year_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_year_with_index.test
new file mode 100644
index 00000000..799fcb29
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_year_with_index.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS aniversary_memos;
+--enable_warnings
+
+CREATE TABLE aniversary_memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ party_year YEAR,
+ KEY (party_year)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("We need a big cake!", "11");
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("Invitations are sent.", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("Tommorow is the anniversary party day!", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("Wow! Today is the anniversary party day!", "13");
+
+SELECT * FROM aniversary_memos;
+
+SELECT * FROM aniversary_memos
+ WHERE party_year BETWEEN "12" AND "2013";
+
+DROP TABLE aniversary_memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/column_year_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/column_year_without_index.test
new file mode 100644
index 00000000..49aa1eaf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/column_year_without_index.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS aniversary_memos;
+--enable_warnings
+
+CREATE TABLE aniversary_memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ party_year YEAR
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("We need a big cake!", "11");
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("Invitations are sent.", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("Tommorow is the anniversary party day!", "2012");
+INSERT INTO aniversary_memos (title, party_year)
+ VALUES ("Wow! Today is the anniversary party day!", "13");
+
+SELECT * FROM aniversary_memos;
+
+SELECT * FROM aniversary_memos
+ WHERE party_year BETWEEN "12" AND "2013";
+
+DROP TABLE aniversary_memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/count_star.test b/storage/mroonga/mysql-test/mroonga/storage/t/count_star.test
new file mode 100644
index 00000000..f20499ef
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/count_star.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int PRIMARY KEY
+);
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+
+SELECT COUNT(*) FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_database_name_slash.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_database_name_slash.test
new file mode 100644
index 00000000..52a1162b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_database_name_slash.test
@@ -0,0 +1,60 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS `master/production`;
+DROP DATABASE IF EXISTS `master/development`;
+--enable_warnings
+
+CREATE DATABASE `master/production`;
+USE `master/production`;
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (title) VALUES ("clear day (production)");
+INSERT INTO diaries (title) VALUES ("rainy day (production)");
+INSERT INTO diaries (title) VALUES ("cloudy day (production)");
+
+SELECT * FROM diaries;
+
+
+CREATE DATABASE `master/development`;
+USE `master/development`;
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (title) VALUES ("clear day (development)");
+INSERT INTO diaries (title) VALUES ("rainy day (development)");
+INSERT INTO diaries (title) VALUES ("cloudy day (development)");
+
+SELECT * FROM diaries;
+
+
+USE test;
+
+DROP DATABASE `master/production`;
+DROP DATABASE `master/development`;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..51eb67ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_TODO_SPLIT_ME.test
@@ -0,0 +1,149 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+# simple test
+create table t1 (c1 int);
+create table t2 (c1 int);
+create table t3 (c1 int);
+drop table t1,t2,t3;
+create table t1 (c1 int, c2 int, c3 int);
+create table t2 (c1 int primary key, c2 int, c3 int);
+drop table t1,t2;
+
+# data type support
+create table t1 (c1 bit);
+desc t1;
+drop table t1;
+create table t1 (c1 tinyint);
+desc t1;
+drop table t1;
+create table t1 (c1 smallint);
+desc t1;
+drop table t1;
+create table t1 (c1 mediumint);
+desc t1;
+drop table t1;
+create table t1 (c1 int);
+desc t1;
+drop table t1;
+create table t1 (c1 bigint);
+desc t1;
+drop table t1;
+create table t1 (c1 double);
+desc t1;
+drop table t1;
+create table t1 (c1 float);
+desc t1;
+drop table t1;
+create table t1 (c1 decimal);
+desc t1;
+drop table t1;
+create table t1 (c1 date);
+desc t1;
+drop table t1;
+create table t1 (c1 time);
+desc t1;
+drop table t1;
+create table t1 (c1 timestamp);
+# For MariaDB 10.2.3
+-- replace_result current_timestamp() CURRENT_TIMESTAMP
+desc t1;
+drop table t1;
+create table t1 (c1 datetime);
+desc t1;
+drop table t1;
+create table t1 (c1 year);
+desc t1;
+drop table t1;
+create table t1 (c1 char(10));
+desc t1;
+drop table t1;
+create table t1 (c1 varchar(10));
+desc t1;
+drop table t1;
+create table t1 (c1 binary(10));
+desc t1;
+drop table t1;
+create table t1 (c1 varbinary(10));
+desc t1;
+drop table t1;
+create table t1 (c1 tinyblob);
+desc t1;
+drop table t1;
+create table t1 (c1 blob);
+desc t1;
+drop table t1;
+create table t1 (c1 mediumblob);
+desc t1;
+drop table t1;
+create table t1 (c1 longblob);
+desc t1;
+drop table t1;
+create table t1 (c1 tinytext);
+desc t1;
+drop table t1;
+create table t1 (c1 text);
+desc t1;
+drop table t1;
+create table t1 (c1 mediumtext);
+desc t1;
+drop table t1;
+create table t1 (c1 longtext);
+desc t1;
+drop table t1;
+create table t1 (c1 enum("yes","no"));
+desc t1;
+drop table t1;
+create table t1 (c1 set("A","B","AB","O"));
+desc t1;
+drop table t1;
+
+# virtual columns
+create table t1 (c1 int, `_id` int) engine = mroonga;
+desc t1;
+drop table t1;
+
+# error
+--error ER_CANT_CREATE_TABLE
+create table t1 (c1 int, `_score` float) engine = mroonga;
+
+# checking for virtual columns
+--error ER_CANT_CREATE_TABLE
+create table t1 (c1 int, `_id` text) engine = mroonga;
+--error ER_CANT_CREATE_TABLE
+create table t1 (c1 int, `_id` int, index(`_id`)) engine = mroonga;
+
+# index for _id
+--error ER_CANT_CREATE_TABLE
+create table t1 (_id int, c1 int, primary key (_id));
+create table t1 (_id int, c1 int, primary key (_id) using hash);
+drop table t1;
+--error ER_CANT_CREATE_TABLE
+create table t1 (_id int, c1 int, unique key (_id));
+create table t1 (_id int, c1 int, unique key (_id) using hash);
+drop table t1;
+--error ER_CANT_CREATE_TABLE
+create table t1 (_id int, c1 int, key (_id));
+create table t1 (_id int, c1 int, key (_id) using hash);
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_comment.test
new file mode 100644
index 00000000..6bafebd8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_comment.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags TEXT COMMENT 'flags "COLUMN_VECTOR"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_parameter.test
new file mode 100644
index 00000000..3baa576a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_flags_parameter.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2013-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags TEXT FLAGS='COLUMN_VECTOR'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_comment.test
new file mode 100644
index 00000000..28f0f214
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_comment.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2013-2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) COMMENT 'groonga_type "tags"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_nonexistent.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_nonexistent.test
new file mode 100644
index 00000000..e27f169b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_nonexistent.test
@@ -0,0 +1,29 @@
+# Copyright(C) 2013-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+--error ER_CANT_CREATE_TABLE
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) COMMENT 'groonga_type "Nonexistent"'
+) DEFAULT CHARSET=utf8mb4;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_parameter.test
new file mode 100644
index 00000000..a6642872
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_groonga_type_parameter.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2013-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) GROONGA_TYPE='tags'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE bugs;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_comment.test
new file mode 100644
index 00000000..bd4b268b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_comment.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) COMMENT 'type "tags"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_nonexistent.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_nonexistent.test
new file mode 100644
index 00000000..08792d20
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_column_type_nonexistent.test
@@ -0,0 +1,29 @@
+# Copyright(C) 2013-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+--error ER_CANT_CREATE_TABLE
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) COMMENT 'type "Nonexistent"'
+) DEFAULT CHARSET=utf8mb4;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_comment_normal.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_comment_normal.test
new file mode 100644
index 00000000..8badcf84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_comment_normal.test
@@ -0,0 +1,34 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED
+) DEFAULT CHARSET=utf8
+ COMMENT='Free style normal comment';
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_default_tokenizer.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_default_tokenizer.test
new file mode 100644
index 00000000..ade4099a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_default_tokenizer.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_comment.test
new file mode 100644
index 00000000..e0273d17
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_comment.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'flags "WITH_POSITION|WITH_WEIGHT"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_medium.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_medium.test
new file mode 100644
index 00000000..d1abc4a0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_medium.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ content_size INT NOT NULL,
+ KEY (content_size) COMMENT 'flags "INDEX_MEDIUM"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_small.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_small.test
new file mode 100644
index 00000000..a519eca4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_index_small.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ is_read BOOL NOT NULL,
+ KEY (is_read) COMMENT 'flags "INDEX_SMALL"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_none.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_none.test
new file mode 100644
index 00000000..b5615ff4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_none.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'flags "NONE"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_parameter.test
new file mode 100644
index 00000000..5524c7ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_flags_parameter.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) FLAGS='WITH_POSITION|WITH_WEIGHT'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_none.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_none.test
new file mode 100644
index 00000000..3852ebd1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_none.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'index_flags "NONE"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_with_position_and_with_weight.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_with_position_and_with_weight.test
new file mode 100644
index 00000000..f557c5f3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_index_flags_with_position_and_with_weight.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'index_flags "WITH_POSITION|WITH_WEIGHT"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_comment.test
new file mode 100644
index 00000000..33d1bfda
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_comment.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
+
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+ブラック" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_fulltext_index_bin.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_fulltext_index_bin.test
new file mode 100644
index 00000000..7b3673ae
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_fulltext_index_bin.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+INSERT INTO diaries VALUES ("2013-04-23", "ブラックコーヒーを飲んだ。");
+
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+ふらつく" IN BOOLEAN MODE);
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+ブラック" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_index_bin.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_index_bin.test
new file mode 100644
index 00000000..4997dbf7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_index_bin.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.test
new file mode 100644
index 00000000..5e7c67fe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_no_utf8_charset_with_utf8_normalizer.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES latin1;
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerMySQLGeneralCI"'
+) DEFAULT CHARSET=latin1;
+
+--error ER_ERROR_ON_WRITE
+INSERT INTO diaries VALUES ("2013-04-23", "I drunk a black cookie.");
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_none.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_none.test
new file mode 100644
index 00000000..9bffd2c3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_none.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'normalizer "none"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES ("2013-04-23", "Mroonga");
+
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+Mroonga" IN BOOLEAN MODE);
+SELECT * FROM diaries
+ WHERE MATCH (content) AGAINST ("+mroonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_parameter.test
new file mode 100644
index 00000000..489e82ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_normalizer_parameter.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) NORMALIZER='NormalizerAuto'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_comment.test
new file mode 100644
index 00000000..c4bc32d1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_comment.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id int PRIMARY KEY AUTO_INCREMENT,
+ body text,
+ FULLTEXT INDEX body_index (body)
+ COMMENT 'parser "TokenBigramSplitSymbolAlphaDigit"'
+) DEFAULT CHARSET utf8;
+
+--enable_prepare_warnings
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_default.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_default.test
new file mode 100644
index 00000000..773c740b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_default.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set @mroonga_default_tokenizer_backup=@@mroonga_default_tokenizer;
+set global mroonga_default_tokenizer=TokenBigramSplitSymbolAlphaDigit;
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+insert into diaries (body) values ("finished Groonga.");
+select * from diaries;
+select * from diaries where match(body) against("+start" IN BOOLEAN MODE) order by id;
+drop table diaries;
+set global mroonga_default_tokenizer=@mroonga_default_tokenizer_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_off.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_off.test
new file mode 100644
index 00000000..2191a28c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_parser_off.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS variables;
+--enable_warnings
+
+CREATE TABLE variables (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name TEXT,
+ FULLTEXT INDEX (name) COMMENT 'parser "off"'
+) DEFAULT CHARSET=utf8;
+
+--enable_prepare_warnings
+INSERT INTO variables (name) VALUES ("mroonga_database_path_prefix");
+INSERT INTO variables (name) VALUES ("mroonga_default_tokenizer");
+INSERT INTO variables (name) VALUES ("mroonga_default_wrapper_engine");
+INSERT INTO variables (name) VALUES ("mroonga_dry_write");
+INSERT INTO variables (name) VALUES ("mroonga_enable_optimization");
+INSERT INTO variables (name) VALUES ("mroonga_libgroonga_version");
+INSERT INTO variables (name) VALUES ("mroonga_log_file");
+INSERT INTO variables (name) VALUES ("mroonga_log_level");
+INSERT INTO variables (name) VALUES ("mroonga_match_escalation_threshold");
+INSERT INTO variables (name) VALUES ("mroonga_version");
+
+SELECT * FROM variables;
+SELECT * FROM variables
+ WHERE MATCH (name) AGAINST ("mroonga_default*" IN BOOLEAN MODE);
+
+DROP TABLE variables;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_multiple_token_filters.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_multiple_token_filters.test
new file mode 100644
index 00000000..f7add5db
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_multiple_token_filters.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord,TokenFilterStopWord"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_one_token_filter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_one_token_filter.test
new file mode 100644
index 00000000..2fc98e61
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_one_token_filter.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_parameter.test
new file mode 100644
index 00000000..aaf60b02
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_token_filters_parameter.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) TOKEN_FILTERS='TokenFilterStopWord,TokenFilterStopWord'
+) DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_comment.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_comment.test
new file mode 100644
index 00000000..0d640c84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_comment.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id int PRIMARY KEY AUTO_INCREMENT,
+ body text,
+ FULLTEXT INDEX body_index (body)
+ COMMENT 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) DEFAULT CHARSET utf8;
+
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_default.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_default.test
new file mode 100644
index 00000000..773c740b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_default.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set @mroonga_default_tokenizer_backup=@@mroonga_default_tokenizer;
+set global mroonga_default_tokenizer=TokenBigramSplitSymbolAlphaDigit;
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8;
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+insert into diaries (body) values ("finished Groonga.");
+select * from diaries;
+select * from diaries where match(body) against("+start" IN BOOLEAN MODE) order by id;
+drop table diaries;
+set global mroonga_default_tokenizer=@mroonga_default_tokenizer_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_off.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_off.test
new file mode 100644
index 00000000..698202a6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_off.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2013-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS variables;
+--enable_warnings
+
+CREATE TABLE variables (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name TEXT,
+ FULLTEXT INDEX (name) COMMENT 'tokenizer "off"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO variables (name) VALUES ("mroonga_database_path_prefix");
+INSERT INTO variables (name) VALUES ("mroonga_default_tokenizer");
+INSERT INTO variables (name) VALUES ("mroonga_default_wrapper_engine");
+INSERT INTO variables (name) VALUES ("mroonga_dry_write");
+INSERT INTO variables (name) VALUES ("mroonga_enable_optimization");
+INSERT INTO variables (name) VALUES ("mroonga_libgroonga_version");
+INSERT INTO variables (name) VALUES ("mroonga_log_file");
+INSERT INTO variables (name) VALUES ("mroonga_log_level");
+INSERT INTO variables (name) VALUES ("mroonga_match_escalation_threshold");
+INSERT INTO variables (name) VALUES ("mroonga_version");
+
+SELECT * FROM variables;
+SELECT * FROM variables
+ WHERE MATCH (name) AGAINST ("mroonga_default*" IN BOOLEAN MODE);
+
+DROP TABLE variables;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_parameter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_parameter.test
new file mode 100644
index 00000000..1bf4dc10
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_index_tokenizer_parameter.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id int PRIMARY KEY AUTO_INCREMENT,
+ body text,
+ FULLTEXT INDEX body_index (body) TOKENIZER='TokenBigramSplitSymbolAlphaDigit'
+) DEFAULT CHARSET utf8;
+
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_default.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_default.test
new file mode 100644
index 00000000..c4b6fe84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_default.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+DROP TABLE IF EXISTS terms;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE terms (
+ term VARCHAR(64) NOT NULL PRIMARY KEY
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"' DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_hash.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_hash.test
new file mode 100644
index 00000000..42521f1d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_normalizer_hash.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+DROP TABLE IF EXISTS terms;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE terms (
+ term VARCHAR(64) NOT NULL,
+ PRIMARY KEY (term) USING HASH
+) COMMENT='default_tokenizer "TokenBigram", normalizer "NormalizerAuto"' DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_multiple_token_filters.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_multiple_token_filters.test
new file mode 100644
index 00000000..dc0996d2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_multiple_token_filters.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+CREATE TABLE terms (
+ term VARCHAR(64) NOT NULL PRIMARY KEY,
+ is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord,TokenFilterStopWord"' DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_one_token_filter.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_one_token_filter.test
new file mode 100644
index 00000000..ee1da6d0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_one_token_filter.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+CREATE TABLE terms (
+ term VARCHAR(64) NOT NULL PRIMARY KEY,
+ is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord"' DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_stop_word.test b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_stop_word.test
new file mode 100644
index 00000000..87a35657
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/create_table_table_token_filters_stop_word.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+CREATE TABLE terms (
+ term VARCHAR(64) NOT NULL PRIMARY KEY,
+ is_stop_word BOOL NOT NULL
+) COMMENT='default_tokenizer "TokenBigram", token_filters "TokenFilterStopWord"' DEFAULT CHARSET=utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'table "terms"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO terms VALUES ("and", true);
+
+INSERT INTO memos VALUES (1, "Hello");
+INSERT INTO memos VALUES (2, "Hello and Good-bye");
+INSERT INTO memos VALUES (3, "Good-bye");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+\"Hello and\"" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+DROP TABLE terms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/delete_fulltext_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/delete_fulltext_column.test
new file mode 100644
index 00000000..de2b24cf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/delete_fulltext_column.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 text, fulltext index (c2));
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+
+select * from t1;
+select * from t1 where match(c2) against("ki");
+delete from t1 where c1=20;
+select * from t1;
+select * from t1 where match(c2) against("ki");
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_btree_many_records.test b/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_btree_many_records.test
new file mode 100644
index 00000000..be739549
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_btree_many_records.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE ids (
+ id INT,
+ KEY (id)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO ids VALUES(1);
+INSERT INTO ids VALUES(2);
+INSERT INTO ids VALUES(3);
+
+SELECT * FROM ids ORDER BY id;
+
+DELETE FROM ids WHERE id = 1;
+SELECT * FROM ids ORDER BY id;
+
+DELETE FROM ids WHERE id = 2;
+SELECT * FROM ids ORDER BY id;
+
+DELETE FROM ids WHERE id = 3;
+SELECT * FROM ids ORDER BY id;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_no_unique.test b/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_no_unique.test
new file mode 100644
index 00000000..f42651cd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_no_unique.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, c1 int, key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+delete from t1 where _id = 2;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_unique.test b/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_unique.test
new file mode 100644
index 00000000..5bbc7979
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/delete_index_hash_id_unique.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, c1 int, unique key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+delete from t1 where _id = 2;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/delete_normal_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/delete_normal_column.test
new file mode 100644
index 00000000..b9e23e64
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/delete_normal_column.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int, c2 int);
+show create table t1;
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+insert into t1 values (4, 102);
+select * from t1;
+
+delete from t1 where c1=3;
+select * from t1;
+
+flush tables;
+
+delete from t1 where c1=2;
+select * from t1;
+
+delete from t1;
+select * from t1;
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/delete_unsigned_bigint.test b/storage/mroonga/mysql-test/mroonga/storage/t/delete_unsigned_bigint.test
new file mode 100644
index 00000000..056dcae0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/delete_unsigned_bigint.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS numbers;
+--enable_warnings
+
+CREATE TABLE numbers (
+ data BIGINT UNSIGNED
+);
+
+INSERT INTO numbers VALUES(18446744073709551615);
+
+SELECT * FROM numbers ORDER BY data;
+
+DELETE FROM numbers WHERE data = 18446744073709551615;
+SELECT * FROM numbers ORDER BY data;
+
+DROP TABLE numbers;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/drop_database_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/drop_database_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..f7bc51db
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/drop_database_TODO_SPLIT_ME.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop database if exists groonga;
+--enable_warnings
+
+create database groonga;
+drop database groonga;
+
+create database groonga;
+use groonga;
+create table t1 (c1 int primary key, c2 varchar(255)) default charset utf8;
+create table t2 (c1 int primary key, c2 varchar(255)) default charset utf8;
+drop database groonga;
+
+create database groonga;
+use groonga;
+create table t1 (c1 int primary key, c2 varchar(255)) default charset utf8;
+create table t2 (c1 int primary key, c2 varchar(255)) default charset utf8;
+drop table t1, t2;
+drop database groonga;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/drop_database_no_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/drop_database_no_table.test
new file mode 100644
index 00000000..db4a9a03
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/drop_database_no_table.test
@@ -0,0 +1,57 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP DATABASE IF EXISTS another;
+--enable_warnings
+
+CREATE DATABASE another;
+USE another;
+
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT INDEX (title)
+);
+
+DROP TABLE diaries;
+
+
+USE test;
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT INDEX (title)
+);
+
+
+DROP DATABASE another;
+
+SELECT mroonga_command('object_exist mroonga_operations');
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/drop_table_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/drop_table_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..e672f80f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/drop_table_TODO_SPLIT_ME.test
@@ -0,0 +1,29 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists alphabet, `with-hyphen`;
+--enable_warnings
+
+create table alphabet (c1 int primary key, c2 int, c3 int);
+drop table alphabet;
+
+create table `with-hyphen` (c1 int primary key, c2 int, c3 int);
+drop table `with-hyphen`;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/flush_logs.test b/storage/mroonga/mysql-test/mroonga/storage/t/flush_logs.test
new file mode 100644
index 00000000..5cb3894a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/flush_logs.test
@@ -0,0 +1,21 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+flush logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_add.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_add.test
new file mode 100644
index 00000000..03d05fe1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_add.test
@@ -0,0 +1,47 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/skip_mariadb_10_1.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+--enable_warnings
+
+CREATE TABLE comments (
+ comment int unsigned PRIMARY KEY,
+ content text NOT NULL
+);
+
+CREATE TABLE articles (
+ content text NOT NULL,
+ comment int unsigned
+);
+
+ALTER TABLE articles ADD FOREIGN KEY (comment) REFERENCES comments (comment);
+
+SHOW CREATE TABLE articles;
+
+SELECT * FROM information_schema.referential_constraints;
+
+DROP TABLE articles;
+DROP TABLE comments;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_drop.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_drop.test
new file mode 100644
index 00000000..d6ef43fa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_alter_drop.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/skip_mariadb_10_1.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+--enable_warnings
+
+CREATE TABLE comments (
+ comment int unsigned PRIMARY KEY,
+ content text NOT NULL
+);
+
+CREATE TABLE articles (
+ content text NOT NULL,
+ comment int unsigned,
+ FOREIGN KEY (comment) REFERENCES comments (comment)
+);
+
+ALTER TABLE articles DROP FOREIGN KEY comment;
+
+SHOW CREATE TABLE articles;
+
+SELECT * FROM information_schema.referential_constraints;
+
+DROP TABLE articles;
+DROP TABLE comments;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_create.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_create.test
new file mode 100644
index 00000000..4efd2052
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_create.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/skip_mariadb_10_1.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+--enable_warnings
+
+CREATE TABLE comments (
+ comment int unsigned PRIMARY KEY,
+ content text NOT NULL
+);
+
+CREATE TABLE articles (
+ content text NOT NULL,
+ comment int unsigned,
+ FOREIGN KEY (comment) REFERENCES comments (comment)
+);
+
+SHOW CREATE TABLE articles;
+
+SELECT * FROM information_schema.referential_constraints;
+
+DROP TABLE articles;
+DROP TABLE comments;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_existent.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_existent.test
new file mode 100644
index 00000000..37405696
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_existent.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_warnings
+
+CREATE TABLE comments (
+ id int unsigned PRIMARY KEY,
+ content varchar(140) NOT NULL
+);
+
+CREATE TABLE entries (
+ content varchar(140) NOT NULL,
+ comment_id int unsigned,
+ FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+--error ER_ROW_IS_REFERENCED_2
+DELETE FROM comments WHERE id = 100;
+
+SELECT * FROM entries;
+SELECT * FROM comments;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE entries;
+DROP TABLE comments;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_nonexistent.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_nonexistent.test
new file mode 100644
index 00000000..9322876b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_delete_nonexistent.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_warnings
+
+CREATE TABLE comments (
+ id int unsigned PRIMARY KEY,
+ content varchar(140) NOT NULL
+);
+
+CREATE TABLE entries (
+ content varchar(140) NOT NULL,
+ comment_id int unsigned,
+ FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO comments (id, content) VALUES (200, 'Very good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+DELETE FROM comments WHERE id = 200;
+
+SELECT * FROM entries;
+SELECT * FROM comments;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE entries;
+DROP TABLE comments;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_existent.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_existent.test
new file mode 100644
index 00000000..283efbd3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_existent.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_warnings
+
+CREATE TABLE comments (
+ id int unsigned PRIMARY KEY,
+ content varchar(140) NOT NULL
+);
+
+CREATE TABLE entries (
+ content varchar(140) NOT NULL,
+ comment_id int unsigned,
+ FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+
+SELECT * FROM entries;
+SELECT * FROM comments;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE entries;
+DROP TABLE comments;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_nonexistent.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_nonexistent.test
new file mode 100644
index 00000000..4b873f50
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_insert_nonexistent.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_warnings
+
+CREATE TABLE comments (
+ id int unsigned PRIMARY KEY,
+ content varchar(140) NOT NULL
+);
+
+CREATE TABLE entries (
+ content varchar(140) NOT NULL,
+ comment_id int unsigned,
+ FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+
+--error ER_NO_REFERENCED_ROW_2
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 1);
+
+SELECT * FROM entries;
+SELECT * FROM comments;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE entries;
+DROP TABLE comments;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_rename.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_rename.test
new file mode 100644
index 00000000..d445731b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_rename.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/skip_mariadb_10_1.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS articles;
+DROP TABLE IF EXISTS comments;
+DROP TABLE IF EXISTS articles2;
+DROP TABLE IF EXISTS comments2;
+--enable_warnings
+
+CREATE TABLE comments (
+ comment int unsigned PRIMARY KEY,
+ content text NOT NULL
+);
+
+CREATE TABLE articles (
+ content text NOT NULL,
+ comment int unsigned,
+ FOREIGN KEY (comment) REFERENCES comments (comment)
+);
+
+RENAME TABLE comments TO comments2;
+RENAME TABLE articles TO articles2;
+
+SHOW CREATE TABLE articles2;
+
+SELECT * FROM information_schema.referential_constraints;
+
+DROP TABLE articles2;
+DROP TABLE comments2;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_existent.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_existent.test
new file mode 100644
index 00000000..fc3590f3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_existent.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_warnings
+
+CREATE TABLE comments (
+ id int unsigned PRIMARY KEY,
+ content varchar(140) NOT NULL
+);
+
+CREATE TABLE entries (
+ content varchar(140) NOT NULL,
+ comment_id int unsigned,
+ FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO comments (id, content) VALUES (200, 'Very good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+UPDATE entries SET comment_id = 200 WHERE content = 'Hello!';
+
+SELECT * FROM entries;
+SELECT * FROM comments;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE entries;
+DROP TABLE comments;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_nonexistent.test b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_nonexistent.test
new file mode 100644
index 00000000..bcba6e75
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/foreign_key_update_nonexistent.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_5.inc
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_warnings
+
+CREATE TABLE comments (
+ id int unsigned PRIMARY KEY,
+ content varchar(140) NOT NULL
+);
+
+CREATE TABLE entries (
+ content varchar(140) NOT NULL,
+ comment_id int unsigned,
+ FOREIGN KEY (comment_id) REFERENCES comments (id)
+);
+
+INSERT INTO comments (id, content) VALUES (100, 'Good entry!');
+INSERT INTO entries (content, comment_id) VALUES ('Hello!', 100);
+--error ER_NO_REFERENCED_ROW_2
+UPDATE entries SET comment_id = 200 WHERE content = 'Hello!';
+
+SELECT * FROM entries;
+SELECT * FROM comments;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE entries;
+DROP TABLE comments;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_empty_query.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_empty_query.test
new file mode 100644
index 00000000..07470050
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_empty_query.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT * FROM diaries;
+
+SELECT *
+ FROM diaries
+ WHERE MATCH(title) AGAINST("" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_escape.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_escape.test
new file mode 100644
index 00000000..50cb1282
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_escape.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("\\(groonga\\)*" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_leading_not.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_leading_not.test
new file mode 100644
index 00000000..bfe2cdc0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_leading_not.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("-明日 +天気" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_all.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_all.test
new file mode 100644
index 00000000..fe904693
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_all.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES(1, "Groonga", "Groonga is fast.");
+INSERT INTO memos VALUES(2, "Mroonga", "Mroonga is also fast.");
+INSERT INTO memos VALUES(3, "Rroonga", "Rroonga is also fast.");
+
+SELECT *,
+ MATCH(title, content)
+ AGAINST("*W1:10,2:2DOR Groonga Mroonga" in BOOLEAN MODE) AS score
+ FROM memos
+ WHERE MATCH(title, content)
+ AGAINST("*W1:10,2:2DOR Groonga Mroonga" in BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test
new file mode 100644
index 00000000..af142c8d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Yesterday was good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D- fine is be" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test
new file mode 100644
index 00000000..9c04d835
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Yesterday was good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D- is OR be fine" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test
new file mode 100644
index 00000000..d1996f54
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Yesterday was good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D- good +day be" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test
new file mode 100644
index 00000000..a4c90fdd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*DOR today good" IN BOOLEAN MODE)
+ ORDER BY content;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test
new file mode 100644
index 00000000..6ac03531
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*DOR today -good tomorrow" IN BOOLEAN MODE)
+ ORDER BY content;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test
new file mode 100644
index 00000000..24681974
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011-2015 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+INSERT INTO memos VALUES ("Tomorrow will be fine.");
+INSERT INTO memos VALUES ("Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*DOR today +good tomorrow" IN BOOLEAN MODE)
+ ORDER BY content;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test
new file mode 100644
index 00000000..3e91ba89
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today good" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.test
new file mode 100644
index 00000000..bfe8bb11
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_astarisk.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today fi*" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test
new file mode 100644
index 00000000..eafacedb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today -good is" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test
new file mode 100644
index 00000000..8b7bb2e1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2011-2013 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES ("Today is good day.");
+INSERT INTO memos VALUES ("Tomorrow will be good day.");
+INSERT INTO memos VALUES ("Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today OR tomorrow day" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_operator.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_operator.test
new file mode 100644
index 00000000..3630052a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_operator.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*SS content @ '天気'" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*SS content @ '天気'" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_selector.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_selector.test
new file mode 100644
index 00000000..21d53b39
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_syntax_script_selector.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2016 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+DROP TABLE IF EXISTS readings;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE readings (
+ reading VARCHAR(255) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE items (
+ name VARCHAR(255) PRIMARY KEY,
+ readings TEXT COMMENT 'flags "COLUMN_VECTOR", type "readings"',
+ FULLTEXT INDEX items_index(readings) COMMENT 'table "readings"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO items VALUES("日本", "ニホン ニッポン");
+INSERT INTO items VALUES("ローマ字", "ローマジ");
+INSERT INTO items VALUES("漢字", "カンジ");
+
+SELECT *, MATCH(readings)
+ AGAINST("*SS sub_filter(readings, 'prefix_rk_search(_key, \"niho\")')" in BOOLEAN MODE) AS score
+ FROM items
+ WHERE MATCH(readings)
+ AGAINST("*SS sub_filter(readings, 'prefix_rk_search(_key, \"niho\")')" in BOOLEAN MODE);
+
+DROP TABLE items;
+DROP TABLE readings;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_full_spec.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_full_spec.test
new file mode 100644
index 00000000..b8aa91ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_full_spec.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_no_weight.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_no_weight.test
new file mode 100644
index 00000000..30ba517a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_no_weight.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*W1,2:2 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*W1,2:2 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_omit_section.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_omit_section.test
new file mode 100644
index 00000000..96fefd3e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_omit_section.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*W1:2 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*W1:2 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.test
new file mode 100644
index 00000000..2a8e1c19
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_ten_or_more_sections.test
@@ -0,0 +1,63 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ title VARCHAR(255),
+ tag1 VARCHAR(10),
+ tag2 VARCHAR(10),
+ tag3 VARCHAR(10),
+ tag4 VARCHAR(10),
+ tag5 VARCHAR(10),
+ tag6 VARCHAR(10),
+ tag7 VARCHAR(10),
+ tag8 VARCHAR(10),
+ tag9 VARCHAR(10),
+ tag10 VARCHAR(10),
+ FULLTEXT INDEX (tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos
+ VALUES("Groonga",
+ "tag 1",
+ "tag 2",
+ "tag 3",
+ "tag 4",
+ "tag 5",
+ "tag 6",
+ "tag 7",
+ "tag 8",
+ "tag 9",
+ "tag 10");
+
+SELECT title,
+ MATCH(tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
+ AGAINST("*W1:2,2:4,3:6,4:8,5:10,6:12,7:14,8:16,9:18,10:20 +tag"
+ in BOOLEAN MODE) AS score
+ FROM memos
+ WHERE MATCH(tag1, tag2, tag3, tag4, tag5, tag6, tag7, tag8, tag9, tag10)
+ AGAINST("*W1:2,2:4,3:6,4:8,5:10,6:12,7:14,8:16,9:18,10:20 +tag"
+ in BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_three_or_more_sections.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_three_or_more_sections.test
new file mode 100644
index 00000000..87cd8de6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_pragma_weight_three_or_more_sections.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ category VARCHAR(10),
+ content TEXT,
+ FULLTEXT INDEX (title, category, content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES(1, "Hello", "日記", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気予報", "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "天気", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, category, content)
+ AGAINST("*W1:2,2:10,3:1 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, category, content)
+ AGAINST("*W1:2,2:10,3:1 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error.test
new file mode 100644
index 00000000..83990fdc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = ERROR;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+
+-- error ER_PARSE_ERROR
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error_and_log.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error_and_log.test
new file mode 100644
index 00000000..494bf760
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_error_and_log.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = ERROR_AND_LOG;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+
+-- error ER_PARSE_ERROR
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore.test
new file mode 100644
index 00000000..828726d0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = "IGNORE";
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore_and_log.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore_and_log.test
new file mode 100644
index 00000000..d9a0adac
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_boolean_mode_syntax_error_ignore_and_log.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+SET mroonga_action_on_fulltext_query_error = IGNORE_AND_LOG;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos VALUES(1, "(groonga) Installed!");
+INSERT INTO memos VALUES(2, "(mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(groonga) Upgraded!");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("(groonga" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_ascii.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_ascii.test
new file mode 100644
index 00000000..3cf85e35
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_ascii.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3));
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+select * from t1 where match(c3) against("su");
+select * from t1 where match(c3) against("ii");
+select * from t1 where match(c3) against("+su" in boolean mode);
+select * from t1 where match(c3) against("+ii" in boolean mode);
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_cp932.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_cp932.test
new file mode 100644
index 00000000..301a85c1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_cp932.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_cp932.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names cp932;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset cp932;
+insert into t1 values(1, "̕xmR̓VCɂ‚","");
+insert into t1 values(2, "","̕xmR̓VC͕܂");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("xmR");
+select * from t1 where match(c3) against("xmR");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_eucjpms.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_eucjpms.test
new file mode 100644
index 00000000..985ce19d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_eucjpms.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_eucjpms.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names eucjpms;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset eucjpms;
+insert into t1 values(1, "ٻλŷˤĤ","");
+insert into t1 values(2, "","ٻλŷʬޤ");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("ٻλ");
+select * from t1 where match(c3) against("ٻλ");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_japanese.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_japanese.test
new file mode 100644
index 00000000..d1d80170
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_japanese.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8;
+insert into t1 values(1, "明日の富士山の天気について","あああああああ");
+insert into t1 values(2, "いいいいい","明日の富士山の天気は分かりません");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("富士山");
+select * from t1 where match(c3) against("富士山");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_utf8mb4.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_utf8mb4.test
new file mode 100644
index 00000000..9492b33b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_charset_utf8mb4.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8mb4;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255) CHARSET utf8mb4 COLLATE utf8mb4_general_ci,
+ content TEXT CHARSET utf8mb4 COLLATE utf8mb4_general_ci,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET utf8mb4;
+
+INSERT INTO diaries VALUES(1, "Alphabet", "ABCDE");
+INSERT INTO diaries VALUES(2, "Mathmatics", "𝐀𝐁𝐂𝐃𝐄 | U+1D400-U+1D405");
+INSERT INTO diaries VALUES(3, "ひらがな", "あいうえお");
+
+SELECT *
+ FROM diaries
+ WHERE MATCH (content) AGAINST("ABCDE" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_empty_query.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_empty_query.test
new file mode 100644
index 00000000..048fcd1c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_empty_query.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT * FROM diaries;
+
+SELECT *
+ FROM diaries
+ WHERE MATCH(title) AGAINST("");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_found_rows.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_found_rows.test
new file mode 100644
index 00000000..08acc357
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_found_rows.test
@@ -0,0 +1,48 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 11, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(6, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT SQL_CALC_FOUND_ROWS * FROM diaries WHERE MATCH(content) AGAINST("今日 天気" IN BOOLEAN MODE) ORDER BY day LIMIT 0,5;
+
+SELECT FOUND_ROWS();
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_groonga_varchar_vector.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_groonga_varchar_vector.test
new file mode 100644
index 00000000..4b113946
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_groonga_varchar_vector.test
@@ -0,0 +1,47 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs, tags;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(64) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COLLATE=utf8_bin
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tags VARCHAR(40) COMMENT 'type "tags", flags "COLUMN_VECTOR"',
+ FULLTEXT INDEX bugs_tags_index (tags) COMMENT 'table "tags"'
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO bugs (id, tags) VALUES (1, "Linux MySQL");
+INSERT INTO bugs (id, tags) VALUES (2, "MySQL groonga");
+INSERT INTO bugs (id, tags) VALUES (3, "mroonga");
+
+SELECT *
+ FROM bugs
+ WHERE MATCH (tags) AGAINST ("MySQL" IN BOOLEAN MODE);
+
+DROP TABLE bugs, tags;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_index_recreate.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_index_recreate.test
new file mode 100644
index 00000000..1846e37b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_index_recreate.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries where match(title) against("富士山");
+drop index title on diaries;
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+select * from diaries where match(title) against("富士山");
+select * from diaries;
+create fulltext index new_title_index on diaries (title);
+select * from diaries where match(title) against("富士山");
+select * from diaries;
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_select.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_select.test
new file mode 100644
index 00000000..c43341f7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_select.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 varchar(100), fulltext index(c2)) default charset utf8;
+create table t2 (c1 int primary key, c2 text, fulltext index(c2)) default charset utf8;
+insert into t1 values (1, "aa ii uu ee oo");
+insert into t1 values (2, "ka ki ku ke ko");
+insert into t1 values (3, "aa ii ii ii oo");
+insert into t1 values (4, "sa si su se so");
+insert into t1 values (5, "ta ti ii ii to");
+insert into t2 (c1,c2) select c1,c2 from t1;
+select * from t1;
+select * from t2;
+select * from t1 where c1=3;
+select * from t2 where c1=3;
+select * from t1 where c1>3 order by c1 desc;
+select * from t2 where c1>3 order by c1 asc;
+select * from t1 where c2>"s" order by c2 desc;
+select * from t2 where c2>"s" order by c1 asc;
+drop table t1,t2;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_values.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_values.test
new file mode 100644
index 00000000..e133073e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_insert_values.test
@@ -0,0 +1,32 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 text, fulltext index ft (c2));
+insert into t1 values (1, "hoge hoge");
+insert into t1 values (2, "fuga fuga");
+insert into t1 values (3, "moge moge");
+select * from t1;
+flush tables;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_delete.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_delete.test
new file mode 100644
index 00000000..c5199ee5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_delete.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+delete from diaries where id = 2;
+select * from diaries where match(title, content) against("富士山");
+select * from diaries where match(title) against("富士山");
+select * from diaries where match(content) against("富士山");
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_insert.test
new file mode 100644
index 00000000..799b9c81
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_insert.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries;
+select * from diaries where match(title, content) against("富士山");
+select * from diaries where match(title) against("富士山");
+select * from diaries where match(content) against("富士山");
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_recreate.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_recreate.test
new file mode 100644
index 00000000..36dcb6c0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_recreate.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8;
+
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries where match(title, content) against("富士山");
+
+drop index title on diaries;
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+select * from diaries where match(title, content) against("富士山");
+
+create fulltext index new_title_content_index on diaries (title, content);
+select * from diaries where match(title, content) against("富士山");
+
+select * from diaries;
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_update.test
new file mode 100644
index 00000000..d84888f9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_column_index_update.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8;
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+update diaries set title = "チョモランマ" where id = 3;
+update diaries set content = "チョモランマと富士山" where id = 1;
+select * from diaries where match(title, content) against("富士山");
+select * from diaries where match(title) against("富士山");
+select * from diaries where match(content) against("富士山");
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_index.test
new file mode 100644
index 00000000..7b04e9a6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_multiple_index.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ title text,
+ body text,
+ fulltext index title_index (title),
+ fulltext index body_index (body)
+) default charset utf8;
+
+insert into diaries (title, body) values ("survey", "will start groonga!");
+insert into diaries (title, body) values ("groonga (1)", "starting groonga...");
+insert into diaries (title, body) values ("groonga (2)", "started groonga.");
+
+select * from diaries
+ where match(title) against("survey") and
+ match(body) against("groonga");
+
+select *, match(title) against("survey"), match(body) against("groonga")
+ from diaries
+ where match(title) against("survey") and
+ match(body) against("groonga");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_no_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_no_primary_key.test
new file mode 100644
index 00000000..aca6a6a0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_no_primary_key.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES("Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES("天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES("富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("*D+ 今日 天気" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_not_match_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_not_match_against.test
new file mode 100644
index 00000000..b99abc8b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_not_match_against.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+# for "not match against"
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3));
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,10,"ka ki ku ke ko");
+insert into t1 values(3,10,"aa ii uu ee oo");
+insert into t1 values(4,10,"ka ki ku ke ko");
+insert into t1 values(5,20,"aa ii uu ee oo");
+insert into t1 values(6,20,"ka ki ku ke ko");
+insert into t1 values(7,20,"aa ii uu ee oo");
+insert into t1 values(8,20,"ka ki ku ke ko");
+select * from t1;
+select * from t1 where match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where not match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where match(c3) against("+dummy" in boolean mode) order by c1;
+select * from t1 where not match(c3) against("+dummy" in boolean mode) order by c1;
+select * from t1 where c1 = 4 and not match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where c1 <= 4 and not match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where c1 > 4 and not match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where c2 = 10 and not match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where c2 >= 15 and not match(c3) against("+uu" in boolean mode) order by c1;
+select * from t1 where c2 < 15 and not match(c3) against("+uu" in boolean mode) order by c1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_or.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_or.test
new file mode 100644
index 00000000..ad93bdd7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_or.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT * FROM diaries;
+
+SELECT *
+ FROM diaries
+ WHERE MATCH(title) AGAINST("Ruby" IN BOOLEAN MODE) OR
+ MATCH(title) AGAINST("mroonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_against.test
new file mode 100644
index 00000000..90b8bc8f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_against.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT * FROM diaries;
+
+SELECT *, MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title) AGAINST("groonga mroonga" IN BOOLEAN MODE)
+ ORDER BY MATCH(title) AGAINST("groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_match.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_match.test
new file mode 100644
index 00000000..fbcbce13
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_different_match.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ body TEXT,
+ FULLTEXT KEY (title),
+ FULLTEXT KEY (body)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga", "I read groonga's tutorial.");
+INSERT INTO diaries VALUES("Start mroonga", "I read mroonga's tutorial.");
+INSERT INTO diaries VALUES("Start groonga and Ruby", "I installed rroonga.");
+
+SELECT * FROM diaries;
+
+SELECT *, MATCH(body) AGAINST("groonga" IN BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE)
+ ORDER BY MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_no_where.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_no_where.test
new file mode 100644
index 00000000..a421a31b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_no_where.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT * FROM diaries;
+
+SELECT *, MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AS score
+ FROM diaries
+ ORDER BY MATCH(title) AGAINST("groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_same_match_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_same_match_against.test
new file mode 100644
index 00000000..3dbaa6bf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_boolean_mode_same_match_against.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT * FROM diaries;
+
+SELECT *, MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE)
+ ORDER BY MATCH(title) AGAINST("groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_asc.test
new file mode 100644
index 00000000..4a3af371
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_asc.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs(
+ message TEXT,
+ FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+
+SELECT * FROM logs;
+
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+ FROM logs
+ WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) ASC;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_desc.test
new file mode 100644
index 00000000..fb45c0c6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_desc.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs(
+ message TEXT,
+ FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+
+SELECT * FROM logs;
+
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+ FROM logs
+ WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) DESC;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_against.test
new file mode 100644
index 00000000..8af0e41e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_against.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs(
+ message TEXT,
+ FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+
+SELECT * FROM logs;
+
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+ FROM logs
+ WHERE MATCH(message) AGAINST("Error Warning" IN NATURAL LANGUAGE MODE)
+ ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_match.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_match.test
new file mode 100644
index 00000000..6c7eb0a6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_different_match.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2015 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs(
+ message TEXT,
+ host TEXT,
+ FULLTEXT KEY (message),
+ FULLTEXT KEY (host)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO logs VALUES("Error Error Error", "host1");
+INSERT INTO logs VALUES("Warning Warning Warning", "host1");
+INSERT INTO logs VALUES("Error Error", "host2");
+INSERT INTO logs VALUES("Warning Warning", "host2");
+INSERT INTO logs VALUES("Error", "host2");
+INSERT INTO logs VALUES("Warning", "host2");
+INSERT INTO logs VALUES("Error Error Error Error", "host2");
+INSERT INTO logs VALUES("Warning Warning Warning Warning", "host2");
+
+SELECT * FROM logs;
+
+SELECT *, MATCH(host) AGAINST("host2" IN NATURAL LANGUAGE MODE) AS score
+ FROM logs
+ WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ ORDER BY MATCH(host) AGAINST("host2" IN NATURAL LANGUAGE MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_no_where.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_no_where.test
new file mode 100644
index 00000000..917d437d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_no_where.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2015 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs(
+ message TEXT,
+ FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+
+SELECT * FROM logs;
+
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+ FROM logs
+ ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_same_match_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_same_match_against.test
new file mode 100644
index 00000000..b4dd8ade
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_order_natural_language_mode_same_match_against.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015 Kouhei Sutou
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs(
+ message TEXT,
+ FULLTEXT KEY (message)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO logs VALUES("Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning");
+INSERT INTO logs VALUES("Error Error");
+INSERT INTO logs VALUES("Warning Warning");
+INSERT INTO logs VALUES("Error");
+INSERT INTO logs VALUES("Warning");
+INSERT INTO logs VALUES("Error Error Error Error");
+INSERT INTO logs VALUES("Warning Warning Warning Warning");
+
+SELECT * FROM logs;
+
+SELECT *, MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE) AS score
+ FROM logs
+ WHERE MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE)
+ ORDER BY MATCH(message) AGAINST("Error" IN NATURAL LANGUAGE MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_two_inner_join.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_two_inner_join.test
new file mode 100644
index 00000000..538b741f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_two_inner_join.test
@@ -0,0 +1,69 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users, posts, comments;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ id int NOT NULL,
+ name varchar(50) NOT NULL,
+ PRIMARY KEY (id),
+ KEY (name)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE posts (
+ id int NOT NULL,
+ content mediumtext,
+ user_id int NOT NULL,
+ PRIMARY KEY (id),
+ FULLTEXT KEY (content)
+) DEFAULT CHARSET=utf8;
+
+CREATE TABLE comments (
+ id int NOT NULL,
+ user_id int NOT NULL,
+ post_id int NOT NULL,
+ PRIMARY KEY (id)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES (1, "Alice"),
+ (2, "Bob"),
+ (3, "Calros");
+INSERT INTO posts VALUES (1, "Hello!", 1),
+ (2, "World!", 2),
+ (3, "Great!", 3);
+INSERT INTO comments VALUES (1, 1, 1),
+ (2, 2, 1),
+ (3, 3, 3);
+
+SELECT *
+ FROM comments
+ INNER JOIN posts
+ ON posts.id = comments.post_id AND
+ MATCH (posts.content) AGAINST ("Hello!" IN BOOLEAN MODE)
+ INNER JOIN users
+ ON users.id = comments.user_id AND
+ users.name = "Alice";
+
+DROP TABLE users, posts, comments;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_10_0_no_such_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_10_0_no_such_key.test
new file mode 100644
index 00000000..606e0c0f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_10_0_no_such_key.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_version_10_0.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+-- error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT * FROM diaries FORCE INDEX(primary)
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_5_no_such_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_5_no_such_key.test
new file mode 100644
index 00000000..311a623b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_5_no_such_key.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_version_5_5.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries FORCE INDEX(primary)
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_6_no_such_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_6_no_such_key.test
new file mode 100644
index 00000000..d51636cb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/fulltext_version_5_6_no_such_key.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_version_5_6.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+-- error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT * FROM diaries FORCE INDEX(primary)
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_command_auto-escape.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_command_auto-escape.test
new file mode 100644
index 00000000..e40a703b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_command_auto-escape.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES('It is Groonga');
+INSERT INTO diaries VALUES('It is Mroonga');
+
+SELECT mroonga_command('select',
+ 'table', 'diaries',
+ 'filter', 'title @ "Groonga"');
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_command_select.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_command_select.test
new file mode 100644
index 00000000..5ba0ca77
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_command_select.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2013 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT mroonga_command('select diaries --match_columns "title" --query "groonga"');
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_command_special-database-name.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_command_special-database-name.test
new file mode 100644
index 00000000..720c547c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_command_special-database-name.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP DATABASE IF EXISTS `db-1`;
+CREATE DATABASE `db-1`;
+USE `db-1`;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command('dump --dump_plugins no');
+
+DROP TABLE diaries;
+
+--disable_query_log
+USE test;
+DROP DATABASE `db-1`;
+--enable_query_log
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_missing.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_missing.test
new file mode 100644
index 00000000..ee0b4833
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_missing.test
@@ -0,0 +1,27 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+-- error ER_CANT_INITIALIZE_UDF
+SELECT mroonga_escape() AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_not_string.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_not_string.test
new file mode 100644
index 00000000..8023de1d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_query_is_not_string.test
@@ -0,0 +1,27 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+-- error ER_CANT_INITIALIZE_UDF
+SELECT mroonga_escape(29) AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_target_characters_is_not_string.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_target_characters_is_not_string.test
new file mode 100644
index 00000000..f9cbf025
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_error_target_characters_is_not_string.test
@@ -0,0 +1,27 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+-- error ER_CANT_INITIALIZE_UDF
+SELECT mroonga_escape('+-><~*()\"\\:', 29) AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_all.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_all.test
new file mode 100644
index 00000000..9ed61499
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_all.test
@@ -0,0 +1,26 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+SELECT mroonga_escape('+-><~*()\"\\:') AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_custom.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_custom.test
new file mode 100644
index 00000000..5d1555cb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_custom.test
@@ -0,0 +1,26 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+SELECT mroonga_escape('+-><~*()\"\\:', '()<>~') AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_join.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_join.test
new file mode 100644
index 00000000..8f0090fd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_join.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+DROP TABLE IF EXISTS queries;
+--enable_warnings
+
+CREATE TABLE users (
+ id INT
+);
+
+CREATE TABLE queries (
+ user_id INT,
+ query TEXT
+);
+
+INSERT INTO users VALUES (1);
+INSERT INTO users VALUES (2);
+INSERT INTO users VALUES (3);
+
+INSERT INTO queries VALUES (1, '(a)');
+INSERT INTO queries VALUES (2, '(b)');
+INSERT INTO queries VALUES (3, '(c)');
+
+SELECT users.id, mroonga_escape(queries.query) AS escaped_query
+ FROM queries
+ LEFT JOIN users ON users.id = queries.user_id
+ ORDER BY users.id;
+
+DROP TABLE queries;
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_match_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_match_against.test
new file mode 100644
index 00000000..bab9f917
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_match_against.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET GLOBAL mroonga_default_tokenizer = TokenDelimit;
+
+SET NAMES utf8mb4;
+CREATE TABLE memos (
+ id INT PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO memos VALUES(1, "(Groonga) Installed!");
+INSERT INTO memos VALUES(2, "(Mroonga) Installed!");
+INSERT INTO memos VALUES(3, "(Groonga) Upgraded!");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST(mroonga_escape("(groonga)") IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+SET GLOBAL mroonga_default_tokenizer = TokenBigram;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_named.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_named.test
new file mode 100644
index 00000000..8c7776a2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_named.test
@@ -0,0 +1,26 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+SELECT mroonga_escape('+-><~*()\"\\:' AS query) AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_nested.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_nested.test
new file mode 100644
index 00000000..ed8e77cb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_query_nested.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries(
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Start groonga");
+INSERT INTO diaries VALUES("Start mroonga");
+INSERT INTO diaries VALUES("Start groonga and Ruby");
+
+SELECT mroonga_escape(mroonga_escape('*groonga*'));
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_decimal.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_decimal.test
new file mode 100644
index 00000000..d8d97996
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_decimal.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS data;
+--enable_warnings
+
+CREATE TABLE data (
+ value DECIMAL(5, 3)
+);
+
+INSERT INTO data VALUES (2.9);
+
+SELECT mroonga_escape(value AS script)
+ FROM data;
+
+DROP TABLE data;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_integer.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_integer.test
new file mode 100644
index 00000000..51c1df9d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_integer.test
@@ -0,0 +1,26 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+SELECT mroonga_escape(-29 AS script) AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_real.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_real.test
new file mode 100644
index 00000000..10859733
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_real.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS data;
+--enable_warnings
+
+CREATE TABLE data (
+ value REAL
+);
+
+INSERT INTO data VALUES (2.9);
+
+SELECT mroonga_escape(value AS script)
+ FROM data;
+
+DROP TABLE data;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_string.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_string.test
new file mode 100644
index 00000000..46c3b558
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_escape_script_string.test
@@ -0,0 +1,26 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+SELECT mroonga_escape('a\"\\\'z' AS script) AS escaped_query;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_dynamic_keyword.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_dynamic_keyword.test
new file mode 100644
index 00000000..3958782a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_dynamic_keyword.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS keywords;
+--enable_query_log
+--enable_warnings
+
+CREATE TABLE keywords (
+ keyword text
+);
+
+INSERT INTO keywords VALUES ('Mroonga');
+INSERT INTO keywords VALUES ('Groonga');
+
+SELECT mroonga_highlight_html('Mroonga is the Groonga based storage engine.',
+ keyword) AS highlighted
+ FROM keywords;
+
+--disable_query_log
+DROP TABLE keywords;
+--enable_query_log
+
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_japanese.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_japanese.test
new file mode 100644
index 00000000..533bf1c2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_japanese.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES utf8;
+
+SELECT mroonga_highlight_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+ 'ロック', '更新') AS highlighted;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_multiple_keywords.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_multiple_keywords.test
new file mode 100644
index 00000000..98643876
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_multiple_keywords.test
@@ -0,0 +1,25 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SELECT mroonga_highlight_html('Mroonga is the Groonga based storage engine.',
+ 'Mroonga', 'Groonga') AS highlighted;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_normalizer.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_normalizer.test
new file mode 100644
index 00000000..83e5966d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_normalizer.test
@@ -0,0 +1,25 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SELECT mroonga_highlight_html('Mroonga is the Groonga based storage engine.',
+ 'mroonga') AS highlighted;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query.test
new file mode 100644
index 00000000..e632f027
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2016-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES utf8;
+
+SELECT mroonga_highlight_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+ 'ロック 更新 -ボトルネック' AS query) AS highlighted;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query_pragma.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query_pragma.test
new file mode 100644
index 00000000..f17aa0f7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_query_pragma.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2017-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES utf8;
+
+SELECT mroonga_highlight_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+ '*D- +ロック +更新 ボトルネック' AS query) AS highlighted;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_record.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_record.test
new file mode 100644
index 00000000..07b1273e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_highlight_html_record.test
@@ -0,0 +1,55 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS memos;
+--enable_query_log
+--enable_warnings
+
+CREATE TABLE memos (
+ content text
+);
+
+INSERT INTO memos VALUES ('Mroonga is a MySQL storage engine based on Groonga, the full text search engine.
+
+In MySQL 5.1 or later, Pluggable Storage Engine interface is introduced, and we can use custom storage engines easily. So we implement Mroonga, so that we can use Groonga through MySQL.
+
+By using Mroonga, you can use Groonga with SQL.');
+
+INSERT INTO memos VALUES ('Since Tritonn was the modified version of MySQL, we need to build it by ourselves or use binary files provided by Tritonn project, thus we cannot use the official binary files provided by MySQL.
+
+On the other hand, Mroonga is an independent program (shared library) using Pluggable Storage Engine interface, and we can dynamically load it on MySQL''s official binary. So we can use it more easily than Tritonn.');
+
+INSERT INTO memos VALUES ('Mroonga has two running modes.
+
+One is "storage mode", that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is "wrapper mode", that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga''s fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga''s read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.');
+
+SELECT mroonga_highlight_html(content, 'Mroonga') AS highlighted
+ FROM memos;
+
+--disable_query_log
+DROP TABLE memos;
+--enable_query_log
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_grn_id.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_grn_id.test
new file mode 100644
index 00000000..b6bced16
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_grn_id.test
@@ -0,0 +1,48 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2013 Kentoku SHIBA
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, c1 int);
+select last_insert_grn_id();
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+insert into t1 values(null,100);
+insert into t1 values(null,100);
+select last_insert_grn_id();
+
+--error ER_CANT_INITIALIZE_UDF
+select last_insert_grn_id(1);
+
+drop table t1;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_reference.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_reference.test
new file mode 100644
index 00000000..a287da00
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_reference.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int AUTO_INCREMENT PRIMARY KEY
+);
+
+SELECT last_insert_id();
+
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_set.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_set.test
new file mode 100644
index 00000000..acb253a4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_last_insert_id_set.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int AUTO_INCREMENT PRIMARY KEY
+);
+
+SELECT last_insert_id();
+SELECT last_insert_id(10);
+SELECT last_insert_id();
+
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_default.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_default.test
new file mode 100644
index 00000000..aa2eee53
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_default.test
@@ -0,0 +1,24 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SELECT mroonga_normalize('aBcAbC㍑');
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_normalizer.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_normalizer.test
new file mode 100644
index 00000000..bb9199f0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_normalizer.test
@@ -0,0 +1,24 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SELECT mroonga_normalize('aBcAbC㍑', "NormalizerAuto");
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_record.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_record.test
new file mode 100644
index 00000000..b67ff53a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_normalize_record.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS memos;
+--enable_query_log
+--enable_warnings
+
+CREATE TABLE memos (
+ content text
+);
+
+INSERT INTO memos VALUES ('aBcAbC㍑');
+
+SELECT mroonga_normalize(content) FROM memos;
+
+--disable_query_log
+DROP TABLE memos;
+--enable_query_log
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_multiple.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_multiple.test
new file mode 100644
index 00000000..8b0ae025
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_multiple.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS synonyms;
+--enable_warnings
+
+CREATE TABLE synonyms (
+ term varchar(255),
+ synonym varchar(255),
+ INDEX (term)
+);
+
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+INSERT INTO synonyms VALUES ('Mroonga', 'Mroonga');
+INSERT INTO synonyms VALUES ('Mroonga', 'Groonga MySQL');
+
+SELECT mroonga_query_expand('synonyms',
+ 'term',
+ 'synonym',
+ 'Mroonga Rroonga PGroonga') AS query;
+
+DROP TABLE synonyms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_no_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_no_index.test
new file mode 100644
index 00000000..400503ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_no_index.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS synonyms;
+--enable_warnings
+
+CREATE TABLE synonyms (
+ term varchar(255),
+ synonym varchar(255)
+);
+
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+
+SELECT mroonga_query_expand('synonyms',
+ 'term',
+ 'synonym',
+ 'Mroonga Rroonga PGroonga') AS query;
+
+DROP TABLE synonyms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_one.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_one.test
new file mode 100644
index 00000000..22241f6b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_one.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS synonyms;
+--enable_warnings
+
+CREATE TABLE synonyms (
+ term varchar(255),
+ synonym varchar(255),
+ INDEX (term)
+);
+
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+
+SELECT mroonga_query_expand('synonyms',
+ 'term',
+ 'synonym',
+ 'Mroonga Rroonga PGroonga') AS query;
+
+DROP TABLE synonyms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_pragma.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_pragma.test
new file mode 100644
index 00000000..3627a2c4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_query_expand_pragma.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--disable_warnings
+DROP TABLE IF EXISTS synonyms;
+--enable_warnings
+
+CREATE TABLE synonyms (
+ term varchar(255),
+ synonym varchar(255),
+ INDEX (term)
+);
+
+INSERT INTO synonyms VALUES ('D+', '[D+]');
+INSERT INTO synonyms VALUES ('Rroonga', 'Rroonga');
+INSERT INTO synonyms VALUES ('Rroonga', 'Groonga Ruby');
+
+SELECT mroonga_query_expand('synonyms',
+ 'term',
+ 'synonym',
+ '*D+ Mroonga Rroonga PGroonga') AS query;
+
+DROP TABLE synonyms;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_ascii.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_ascii.test
new file mode 100644
index 00000000..72da393f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_ascii.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012-2013 Kentoku SHIBA
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3));
+insert into t1 values(1,10,"aa bb cc dd ee >< ff gg hh ii jj kk ll mm nn");
+insert into t1 values(2,20,"nn mm ll kk jj >< ii hh gg ff ee dd cc bb aa");
+insert into t1 values(3,30,"cc dd ee ff gg >< hh ii jj kk ll mm nn oo pp");
+insert into t1 values(4,40,"ee ff gg hh ii >< jj kk ll mm nn oo pp qq rr");
+insert into t1 values(5,50,"AA BB CC DD EE >< FF GG HH II JJ KK LL MM NN");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 0, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 0, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 1, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 1, 1, '...', '...<br>\n', 'bb', '<span class="w1">', '</span>', 'ff', '<span class="w2">', '</span>', 'dd', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 0, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 0, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_general_ci', 1, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'ascii_bin', 1, 0, '...', '...\n', 'bb', '(w1)[', ']', 'ff', '(w2)[', ']', 'dd', '(w3)[', ']') from t1;
+drop table t1;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_cp932.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_cp932.test
new file mode 100644
index 00000000..afaa4368
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_cp932.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012-2013 Kentoku SHIBA
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source include/have_cp932.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names cp932;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset cp932;
+insert into t1 values(1, "","QX̕xmR̓VCɂ‚");
+insert into t1 values(2, "","QX̕xmR̓VC͕܂");
+insert into t1 values(3, "","29̕xmR̓VCɂ‚");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 0, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 0, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 1, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 1, 1, '...', '...<br>\n', 'QX', '<span class="w1">', '</span>', 'VC', '<span class="w2">', '</span>', 'xmR', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 0, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 0, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_japanese_ci', 1, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'cp932_bin', 1, 0, '...', '...\n', 'QX', '(w1)[', ']', 'VC', '(w2)[', ']', 'xmR', '(w3)[', ']') from t1;
+drop table t1;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_eucjpms.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_eucjpms.test
new file mode 100644
index 00000000..cd59a216
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_eucjpms.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012-2013 Kentoku SHIBA
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source include/have_eucjpms.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names eucjpms;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset eucjpms;
+insert into t1 values(1, "","ٻλŷˤĤ");
+insert into t1 values(2, "","ٻλŷʬޤ");
+insert into t1 values(3, "","29ٻλŷˤĤ");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 0, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 0, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 1, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 1, 1, '...', '...<br>\n', '', '<span class="w1">', '</span>', 'ŷ', '<span class="w2">', '</span>', 'ٻλ', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 0, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 0, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_japanese_ci', 1, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'eucjpms_bin', 1, 0, '...', '...\n', '', '(w1)[', ']', 'ŷ', '(w2)[', ']', 'ٻλ', '(w3)[', ']') from t1;
+drop table t1;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_dynamic_keyword.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_dynamic_keyword.test
new file mode 100644
index 00000000..a92e651c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_dynamic_keyword.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS keywords;
+--enable_query_log
+--enable_warnings
+
+CREATE TABLE keywords (
+ keyword text
+);
+
+INSERT INTO keywords VALUES ('Mroonga');
+INSERT INTO keywords VALUES ('Groonga');
+
+SELECT mroonga_snippet_html('Mroonga is the Groonga based storage engine.',
+ keyword) as snippet
+ FROM keywords;
+
+--disable_query_log
+DROP TABLE keywords;
+--enable_query_log
+
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_japanese.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_japanese.test
new file mode 100644
index 00000000..fcc5a0fc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_japanese.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES utf8;
+
+SELECT mroonga_snippet_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+ 'ロック', '更新') as snippet;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_keywords.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_keywords.test
new file mode 100644
index 00000000..54953ebe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_keywords.test
@@ -0,0 +1,25 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SELECT mroonga_snippet_html('Mroonga is the Groonga based storage engine.',
+ 'Mroonga', 'Groonga') as snippet;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_snippets.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_snippets.test
new file mode 100644
index 00000000..9aac07a0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_multiple_snippets.test
@@ -0,0 +1,29 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SELECT mroonga_snippet_html('Mroonga has two running modes.
+
+One is "storage mode", that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is "wrapper mode", that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga''s fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga''s read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.',
+ 'lock') as snippet;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query.test
new file mode 100644
index 00000000..d441b0ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES utf8;
+
+SELECT mroonga_snippet_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+ 'ロック 更新 -ボトルネック' AS query) as snippet;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query_pragma.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query_pragma.test
new file mode 100644
index 00000000..0aa115d7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_query_pragma.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES utf8;
+
+SELECT mroonga_snippet_html('Mroongaには2つの動作モードがあります。
+
+1つが「ストレージモード」で、データストアも検索機能もすべてGroongaを使うモードです。これがデフォルトのモードです。上述の参照ロックフリーなGroongaの性能特性をフルに活かした高速なデータ更新・全文検索・位置情報検索が特長です。一方、トランザクションなどの機能は提供されません。
+
+もう1つが「ラッパーモード」で、MyISAMやInnoDBといった他のストレージエンジンに 全文検索機能だけ を追加するモードです。このモードではトランザクションなど他のストレージエンジンがサポートしている機能に加えてGroongaの高速な全文検索機能を利用することができます。一方、Groongaの参照ロックフリーな特性は活かすことができません。また、更新処理は他のストレージエンジンがボトルネックになることが多いでしょう。',
+ '*D- +ロック +更新 ボトルネック' AS query) as snippet;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_record.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_record.test
new file mode 100644
index 00000000..c25d140c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_html_record.test
@@ -0,0 +1,55 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+--disable_query_log
+DROP TABLE IF EXISTS memos;
+--enable_query_log
+--enable_warnings
+
+CREATE TABLE memos (
+ content text
+);
+
+INSERT INTO memos VALUES ('Mroonga is a MySQL storage engine based on Groonga, the full text search engine.
+
+In MySQL 5.1 or later, Pluggable Storage Engine interface is introduced, and we can use custom storage engines easily. So we implement Mroonga, so that we can use Groonga through MySQL.
+
+By using Mroonga, you can use Groonga with SQL.');
+
+INSERT INTO memos VALUES ('Since Tritonn was the modified version of MySQL, we need to build it by ourselves or use binary files provided by Tritonn project, thus we cannot use the official binary files provided by MySQL.
+
+On the other hand, Mroonga is an independent program (shared library) using Pluggable Storage Engine interface, and we can dynamically load it on MySQL''s official binary. So we can use it more easily than Tritonn.');
+
+INSERT INTO memos VALUES ('Mroonga has two running modes.
+
+One is "storage mode", that is the default mode, and we use Groonga for both storing data and searching. With this mode, you can have full benefits of Groonga described above, like fast data update, lock-free full text search and geolocation search. But it does not support transactions.
+
+Another one is "wrapper mode", that adds full text search function on other storage engines like MyISAM or InnoDB. With this mode, you can use Groonga''s fast full text search with having the benefits of the storage engine, ex. transaction in InnoDB. But you cannot have benefits from Groonga''s read-lock free characteristic. And you might have the performance bottle neck in the storage engine in updating data.');
+
+SELECT mroonga_snippet_html(content, 'Mroonga') as snippet
+ FROM memos;
+
+--disable_query_log
+DROP TABLE memos;
+--enable_query_log
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_nonexistent_charset.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_nonexistent_charset.test
new file mode 100644
index 00000000..c6b19acd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_nonexistent_charset.test
@@ -0,0 +1,28 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--error ER_CANT_INITIALIZE_UDF
+SELECT mroonga_snippet("Invalid charset test", 10, 2, "nonexistent_charset",
+ 1, 0, "...", "...", "charset", "<", ">");
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_unsupported_charset.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_unsupported_charset.test
new file mode 100644
index 00000000..7182dfbc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_invalid_unsupported_charset.test
@@ -0,0 +1,28 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+SET NAMES UTF8;
+
+--error ER_CANT_INITIALIZE_UDF
+SELECT mroonga_snippet("Unsuppported charset test", 10, 2, "big5",
+ 1, 0, "...", "...", "charset", "<", ">");
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_japanese.test b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_japanese.test
new file mode 100644
index 00000000..dfa373dc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/function_snippet_japanese.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012-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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8;
+insert into t1 values(1, "あああああ","29日の富士山の天気について");
+insert into t1 values(2, "いいいいい","29日の富士山の天気は分かりません");
+insert into t1 values(3, "ううううう","29日の富士山の天気について");
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 0, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 0, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 1, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 1, 1, '...', '...<br>\n', '29日', '<span class="w1">', '</span>', '天気', '<span class="w2">', '</span>', '富士山', '<span class="w3">', '</span>') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 0, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 0, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_general_ci', 1, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+select c1, c2, mroonga_snippet(c3, 10, 2, 'utf8_bin', 1, 0, '...', '...\n', '29日', '(w1)[', ']', '天気', '(w2)[', ']', '富士山', '(w3)[', ']') from t1;
+drop table t1;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/geometry_bulk_insert_null.test b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_bulk_insert_null.test
new file mode 100644
index 00000000..160fbf53
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_bulk_insert_null.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS shops;
+--enable_warnings
+
+CREATE TABLE shops (
+ location GEOMETRY NOT NULL
+);
+
+INSERT IGNORE INTO shops VALUES (NULL), (NULL);
+
+SELECT ST_AsText(location) FROM shops;
+
+DROP TABLE shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/geometry_contains.test b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_contains.test
new file mode 100644
index 00000000..7b4bd34d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_contains.test
@@ -0,0 +1,154 @@
+# Copyright(C) 2011-2016 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-1335 USA
+
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/skip_mysql_5_7.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS shops;
+--enable_warnings
+
+CREATE TABLE shops (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name TEXT,
+ location GEOMETRY NOT NULL,
+ SPATIAL KEY location_index (location)
+);
+
+INSERT INTO shops (name, location)
+ VALUES ('nezu-no-taiyaki',
+ ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+ VALUES ('taiyaki-kataoka',
+ ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+ VALUES ('soba-taiyaki-ku',
+ ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuruma',
+ ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+ VALUES ('hirose-ya',
+ ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+ VALUES ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+ VALUES ('omede-taiyaki',
+ ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+ VALUES ('onaga-ya',
+ ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+ VALUES ('shiro-ya',
+ ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+ VALUES ('fuji-ya',
+ ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+ VALUES ('miyoshi',
+ ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+ VALUES ('juju-ya',
+ ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+ VALUES ('tatsumi-ya',
+ ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+ VALUES ('tetsuji',
+ ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+ VALUES ('gazuma-ya',
+ ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+ VALUES ('honma-mon',
+ ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+ VALUES ('naniwa-ya',
+ ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuro-dai',
+ ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+ VALUES ('daruma',
+ ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+ VALUES ('yanagi-ya',
+ ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+ VALUES ('sharaku',
+ ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+ VALUES ('takane',
+ ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+ VALUES ('chiyoda',
+ ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+ VALUES ('da-ka-po',
+ ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+ VALUES ('matsushima-ya',
+ ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+ VALUES ('kazuya',
+ ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+ VALUES ('furuya-kogane-an',
+ ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+ VALUES ('hachi-no-ie',
+ ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+ VALUES ('azuki-chan',
+ ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuriko-an',
+ ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+ VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+ VALUES ('naze-ya',
+ ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+ VALUES ('sanoki-ya',
+ ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+ VALUES ('shigeta',
+ ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+ VALUES ('nishimi-ya',
+ ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+ VALUES ('hiiragi',
+ ST_GeomFromText('POINT(139.711517 35.647701)'));
+
+SELECT id, name, ST_AsText(location) AS location_text FROM shops;
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+ WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ ORDER BY id;
+
+EXPLAIN
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+ WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ ORDER BY id;
+
+DROP TABLE shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_bulk_insert_null.test b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_bulk_insert_null.test
new file mode 100644
index 00000000..5664bc4b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_bulk_insert_null.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.com>
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS shops;
+--enable_warnings
+
+CREATE TABLE shops (
+ location GEOMETRY NOT NULL
+);
+
+--error ER_BAD_NULL_ERROR
+INSERT INTO shops VALUES (NULL), (NULL);
+
+SELECT ST_AsText(location) FROM shops;
+
+DROP TABLE shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_contains.test b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_contains.test
new file mode 100644
index 00000000..a337ac6a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/geometry_strict_sql_mode_contains.test
@@ -0,0 +1,152 @@
+# Copyright(C) 2011-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS shops;
+--enable_warnings
+
+CREATE TABLE shops (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name TEXT,
+ location GEOMETRY NOT NULL,
+ SPATIAL KEY location_index (location)
+);
+
+INSERT INTO shops (name, location)
+ VALUES ('nezu-no-taiyaki',
+ ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+ VALUES ('taiyaki-kataoka',
+ ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+ VALUES ('soba-taiyaki-ku',
+ ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuruma',
+ ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+ VALUES ('hirose-ya',
+ ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+ VALUES ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+ VALUES ('omede-taiyaki',
+ ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+ VALUES ('onaga-ya',
+ ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+ VALUES ('shiro-ya',
+ ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+ VALUES ('fuji-ya',
+ ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+ VALUES ('miyoshi',
+ ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+ VALUES ('juju-ya',
+ ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+ VALUES ('tatsumi-ya',
+ ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+ VALUES ('tetsuji',
+ ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+ VALUES ('gazuma-ya',
+ ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+ VALUES ('honma-mon',
+ ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+ VALUES ('naniwa-ya',
+ ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuro-dai',
+ ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+ VALUES ('daruma',
+ ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+ VALUES ('yanagi-ya',
+ ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+ VALUES ('sharaku',
+ ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+ VALUES ('takane',
+ ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+ VALUES ('chiyoda',
+ ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+ VALUES ('da-ka-po',
+ ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+ VALUES ('matsushima-ya',
+ ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+ VALUES ('kazuya',
+ ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+ VALUES ('furuya-kogane-an',
+ ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+ VALUES ('hachi-no-ie',
+ ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+ VALUES ('azuki-chan',
+ ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuriko-an',
+ ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+ VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+ VALUES ('naze-ya',
+ ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+ VALUES ('sanoki-ya',
+ ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+ VALUES ('shigeta',
+ ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+ VALUES ('nishimi-ya',
+ ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+ VALUES ('hiiragi',
+ ST_GeomFromText('POINT(139.711517 35.647701)'));
+
+SELECT id, name, ST_AsText(location) AS location_text FROM shops;
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+ WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ ORDER BY id;
+
+EXPLAIN
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+ WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ ORDER BY id;
+
+DROP TABLE shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/i_s.test b/storage/mroonga/mysql-test/mroonga/storage/t/i_s.test
new file mode 100644
index 00000000..fdb8e205
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/i_s.test
@@ -0,0 +1,23 @@
+# Copyright (c) 2019, MariaDB
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+SHOW CREATE TABLE INFORMATION_SCHEMA.MROONGA_STATS;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_datetime.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_datetime.test
new file mode 100644
index 00000000..0b16dfbd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_datetime.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ created_at datetime,
+ title varchar(256),
+ KEY created_at_key(created_at)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES ("1000-01-01 00:00:00", "The start");
+INSERT INTO diaries VALUES ("2012-10-25 16:18:29", "Today is shiny day.");
+INSERT INTO diaries VALUES ("9999-12-31 23:59:59", "The end");
+
+SELECT *
+ FROM diaries FORCE INDEX(created_at_key)
+ WHERE created_at = "2012-10-25 16:18:29";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_time.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_time.test
new file mode 100644
index 00000000..c27e05a7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_time.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS timer;
+--enable_warnings
+
+CREATE TABLE timer (
+ id int PRIMARY KEY,
+ elapsed time,
+ KEY elapsed_key(elapsed)
+);
+
+INSERT INTO timer VALUES (1, "00:00:00");
+INSERT INTO timer VALUES (2, "15:11:12");
+INSERT INTO timer VALUES (3, "838:59:59");
+INSERT INTO timer VALUES (4, "-838:59:59");
+
+SELECT *
+ FROM timer FORCE INDEX(elapsed_key)
+ WHERE elapsed = "-838:59:59";
+
+DROP TABLE timer;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_timestamp.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_timestamp.test
new file mode 100644
index 00000000..c7b57f49
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_equal_timestamp.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ created_at timestamp,
+ title varchar(256),
+ KEY created_at_key(created_at)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES ("1970-01-01 12:00:00", "The start");
+INSERT INTO diaries VALUES ("2012-10-05 16:18:29", "Today is shiny day.");
+INSERT INTO diaries VALUES ("2038-01-18 15:14:07", "The end");
+
+SELECT *
+ FROM diaries FORCE INDEX(created_at_key)
+ WHERE created_at = "2012-10-05 16:18:29";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_normal_column_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_normal_column_insert.test
new file mode 100644
index 00000000..a922bc03
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_btree_normal_column_insert.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, index using btree (c2));
+show create table t1;
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+flush tables;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_normal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_normal.test
new file mode 100644
index 00000000..f385fb28
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_normal.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, a int, key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+select * from t1 where _id = 2;
+select * from t1 where _id = 20;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_primary.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_primary.test
new file mode 100644
index 00000000..fa22ab1f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_primary.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2016-2017 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-1335 USA
+
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (_id int, a int, PRIMARY KEY (_id) USING HASH);
+
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 VALUES(null, 100);
+INSERT INTO t1 VALUES(1,100);
+INSERT INTO t1 VALUES(1,100);
+INSERT INTO t1 VALUES(1,100);
+INSERT INTO t1 VALUES(1,100);
+
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE _id = 2;
+SELECT * FROM t1 WHERE _id = 20;
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_unique.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_unique.test
new file mode 100644
index 00000000..0a39b8d4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_id_unique.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, a int, unique key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+select * from t1 where _id = 2;
+select * from t1 where _id = 20;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_normal_column_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_normal_column_insert.test
new file mode 100644
index 00000000..341873ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_normal_column_insert.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, index using hash (c2));
+show create table t1;
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+flush tables;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_strict_sql_mode_id_primary.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_strict_sql_mode_id_primary.test
new file mode 100644
index 00000000..0f27d333
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_hash_strict_sql_mode_id_primary.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2016-2017 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-1335 USA
+
+--source ../../include/mroonga/have_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (_id int, a int, PRIMARY KEY (_id) USING HASH);
+
+--error ER_BAD_NULL_ERROR
+INSERT INTO t1 VALUES(null, 100);
+--error 1265
+INSERT INTO t1 VALUES(1,100);
+--error 1265
+INSERT INTO t1 VALUES(1,100);
+--error 1265
+INSERT INTO t1 VALUES(1,100);
+--error 1265
+INSERT INTO t1 VALUES(1,100);
+
+SELECT * FROM t1;
+SELECT * FROM t1 WHERE _id = 2;
+SELECT * FROM t1 WHERE _id = 20;
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_delete.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_delete.test
new file mode 100644
index 00000000..9507b395
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_delete.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table scores (
+ id int primary key auto_increment not null,
+ name char(30) not null,
+ score int not null,
+ index property (name, score)
+) default charset utf8;
+show create table scores;
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+delete from scores where name = "Taro Yamada" and score = 10;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+drop table scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_smallint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_smallint.test
new file mode 100644
index 00000000..b1095ae0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_smallint.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ c1 SMALLINT,
+ c2 SMALLINT,
+ KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+
+INSERT INTO t1 (c1, c2) VALUES
+ (1999, 12),
+ (2000, 11),
+ (2001, 10),
+ (2002, 9),
+ (2003, 8),
+ (2004, 7),
+ (2005, 6),
+ (2006, 5),
+ (2007, 4),
+ (2008, 3),
+ (2009, 2),
+ (2010, 1);
+
+SELECT * FROM t1 WHERE c1 > 2005;
+SELECT * FROM t1 WHERE c1 >= 2005;
+SELECT * FROM t1 WHERE c1 = 2005;
+SELECT * FROM t1 WHERE c1 <= 2005;
+SELECT * FROM t1 WHERE c1 < 2005;
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_bigint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_bigint.test
new file mode 100644
index 00000000..3f43db0c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_bigint.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ c1 BIGINT UNSIGNED,
+ c2 BIGINT UNSIGNED,
+ KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+
+INSERT INTO t1 (c1, c2) VALUES
+ (1999, 12),
+ (2000, 11),
+ (2001, 10),
+ (2002, 9),
+ (2003, 8),
+ (2004, 7),
+ (2005, 6),
+ (2006, 5),
+ (2007, 4),
+ (2008, 3),
+ (2009, 2),
+ (2010, 1);
+
+SELECT * FROM t1 WHERE c1 > 2005;
+SELECT * FROM t1 WHERE c1 >= 2005;
+SELECT * FROM t1 WHERE c1 = 2005;
+SELECT * FROM t1 WHERE c1 <= 2005;
+SELECT * FROM t1 WHERE c1 < 2005;
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_int.test
new file mode 100644
index 00000000..31e5a791
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_int.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ c1 INT UNSIGNED,
+ c2 INT UNSIGNED,
+ KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+
+INSERT INTO t1 (c1, c2) VALUES
+ (1999, 12),
+ (2000, 11),
+ (2001, 10),
+ (2002, 9),
+ (2003, 8),
+ (2004, 7),
+ (2005, 6),
+ (2006, 5),
+ (2007, 4),
+ (2008, 3),
+ (2009, 2),
+ (2010, 1);
+
+SELECT * FROM t1 WHERE c1 > 2005;
+SELECT * FROM t1 WHERE c1 >= 2005;
+SELECT * FROM t1 WHERE c1 = 2005;
+SELECT * FROM t1 WHERE c1 <= 2005;
+SELECT * FROM t1 WHERE c1 < 2005;
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_smallint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_smallint.test
new file mode 100644
index 00000000..9340c784
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_unsigned_smallint.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ c1 SMALLINT UNSIGNED,
+ c2 SMALLINT UNSIGNED,
+ KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+
+INSERT INTO t1 (c1, c2) VALUES
+ (1999, 12),
+ (2000, 11),
+ (2001, 10),
+ (2002, 9),
+ (2003, 8),
+ (2004, 7),
+ (2005, 6),
+ (2006, 5),
+ (2007, 4),
+ (2008, 3),
+ (2009, 2),
+ (2010, 1);
+
+SELECT * FROM t1 WHERE c1 > 2005;
+SELECT * FROM t1 WHERE c1 >= 2005;
+SELECT * FROM t1 WHERE c1 = 2005;
+SELECT * FROM t1 WHERE c1 <= 2005;
+SELECT * FROM t1 WHERE c1 < 2005;
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_varchar.test
new file mode 100644
index 00000000..3787489e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_nullable_varchar.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ c1 VARCHAR(10),
+ c2 VARCHAR(10),
+ KEY idx1(c1, c2)
+) DEFAULT CHARSET UTF8;
+SHOW CREATE TABLE t1;
+
+INSERT INTO t1 (c1, c2) VALUES
+ ('1999', '12'),
+ ('2000', '11'),
+ ('2001', '10'),
+ ('2002', '09'),
+ ('2003', '08'),
+ ('2004', '07'),
+ ('2005', '06'),
+ ('2006', '05'),
+ ('2007', '04'),
+ ('2008', '03'),
+ ('2009', '02'),
+ ('2010', '01');
+
+SELECT * FROM t1 WHERE c1 > '2005';
+SELECT * FROM t1 WHERE c1 >= '2005';
+SELECT * FROM t1 WHERE c1 = '2005';
+SELECT * FROM t1 WHERE c1 <= '2005';
+SELECT * FROM t1 WHERE c1 < '2005';
+
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_asc_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_asc_asc.test
new file mode 100644
index 00000000..e4f07494
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_asc_asc.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ score3 INT,
+ INDEX (score1, score2, score3)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, -100);
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 10, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 100);
+
+SELECT *
+ FROM items
+ WHERE score1 = 2
+ ORDER BY score2 ASC, score3 ASC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_desc_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_desc_desc.test
new file mode 100644
index 00000000..1d636391
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_order_by_where_equal_desc_desc.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ score3 INT,
+ INDEX (score1, score2, score3)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, -100);
+INSERT INTO items (score1, score2, score3) VALUES(1, 10, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 10, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 30, 100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, -100);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 0);
+INSERT INTO items (score1, score2, score3) VALUES(2, 20, 100);
+
+SELECT *
+ FROM items
+ WHERE score1 = 2
+ ORDER BY score2 DESC, score3 DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_delete.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_delete.test
new file mode 100644
index 00000000..19fd3c1f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_delete.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table scores (
+ name char(30) not null,
+ score int not null,
+ primary key (name, score)
+) default charset utf8;
+show create table scores;
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+delete from scores where name = "Taro Yamada" and score = 10;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+drop table scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_select_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_select_int.test
new file mode 100644
index 00000000..092b9ad9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_select_int.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table scores (
+ name char(30) not null,
+ score int not null,
+ primary key (name, score)
+) default charset utf8;
+show create table scores;
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+select * from scores where name = "Taro Yamada";
+select * from scores where name = "Taro Yamada" and score = 29;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+drop table scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_strict_sql_mode_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_strict_sql_mode_update.test
new file mode 100644
index 00000000..e99db080
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_strict_sql_mode_update.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2011-2017 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-1335 USA
+
+--source ../../include/mroonga/have_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE scores (
+ name char(30) NOT NULL,
+ score int NOT NULL,
+ PRIMARY KEY (name, score)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES ("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 10);
+
+SELECT * FROM scores;
+
+--error 1265
+UPDATE scores SET name = "Taro Yamada"
+ WHERE name = "Jiro Yamada" AND score = 27;
+
+SELECT * FROM scores
+ WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_update.test
new file mode 100644
index 00000000..e4a38ea0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_primary_update.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2011-2017 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-1335 USA
+
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE scores (
+ name char(30) NOT NULL,
+ score int NOT NULL,
+ PRIMARY KEY (name, score)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES ("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES ("Taro Yamada", 10);
+
+SELECT * FROM scores;
+
+UPDATE scores SET name = "Taro Yamada"
+ WHERE name = "Jiro Yamada" AND score = 27;
+
+SELECT * FROM scores
+ WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than.test
new file mode 100644
index 00000000..171919b1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score INT,
+ created_at DATETIME,
+ INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score = 2 AND created_at > "2014-09-11 00:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than_or_equal.test
new file mode 100644
index 00000000..67d5c44f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_greater_than_or_equal.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score INT,
+ created_at DATETIME,
+ INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score = 2 AND created_at >= "2014-09-11 00:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than.test
new file mode 100644
index 00000000..b7d0b074
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score INT,
+ created_at DATETIME,
+ INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score = 2 AND created_at < "2014-09-12 00:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than_or_equal.test
new file mode 100644
index 00000000..5576bbc3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_all_used_less_than_or_equal.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score INT,
+ created_at DATETIME,
+ INDEX (score, created_at)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score, created_at) VALUES(1, "2014-09-10 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-11 00:00:00");
+INSERT INTO items (score, created_at) VALUES(2, "2014-09-12 00:00:00");
+INSERT INTO items (score, created_at) VALUES(3, "2014-09-13 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score = 2 AND created_at <= "2014-09-12 00:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than.test
new file mode 100644
index 00000000..13c47b4a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@clear-code.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score1 = 2 AND created_at > "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.test
new file mode 100644
index 00000000..7b890430
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_greater_than_or_equal.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@clear-code.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score1 = 2 AND created_at >= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than.test
new file mode 100644
index 00000000..60b4cd27
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@clear-code.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score1 = 2 AND created_at < "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.test
new file mode 100644
index 00000000..ece1d157
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_have_prefix_less_than_or_equal.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@clear-code.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (score1, created_at, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(3, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE score1 = 2 AND created_at <= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than.test
new file mode 100644
index 00000000..924a0ac2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE created_at > "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.test
new file mode 100644
index 00000000..8636e5ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_greater_than_or_equal.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE created_at >= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than.test
new file mode 100644
index 00000000..73d53693
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE created_at < "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.test
new file mode 100644
index 00000000..630d60a7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_range_partially_used_no_prefix_less_than_or_equal.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2015 Masafumi Yokoyama <yokoyama@clear-code.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS items;
+--enable_warnings
+
+CREATE TABLE items (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT,
+ score2 INT,
+ created_at DATETIME,
+ INDEX (created_at, score1, score2)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE items;
+
+INSERT INTO items (score1, score2, created_at) VALUES(1, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 00:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-01 12:00:00");
+INSERT INTO items (score1, score2, created_at) VALUES(2, 0, "2015-07-02 00:00:00");
+
+SELECT *
+ FROM items
+ WHERE created_at <= "2015-07-01 12:00:00"
+ ORDER BY created_at DESC;
+
+DROP TABLE items;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_recreate.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_recreate.test
new file mode 100644
index 00000000..e8840b4a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_recreate.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table listing (
+ id int primary key auto_increment not null,
+ last_name char(30) not null,
+ first_name char(30) not null,
+ index name (last_name, first_name)
+) default charset utf8;
+show create table listing;
+
+insert into listing (last_name, first_name) values("Taro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Suzuki");
+insert into listing (last_name, first_name) values("Jiro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Tanaka");
+
+select * from listing
+ where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+
+drop index name on listing;
+select * from listing
+ where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+
+create index new_name_index on listing (last_name, first_name);
+select * from listing
+ where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+
+drop table listing;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_replace.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_replace.test
new file mode 100644
index 00000000..d31762b2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_replace.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS listing;
+--enable_warnings
+
+CREATE TABLE scores (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ name CHAR(30) NOT NULL,
+ score INT NOT NULL,
+ INDEX property (NAME, SCORE)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+
+SELECT * FROM scores;
+REPLACE scores (id, name, score) VALUES (3, "Taro Yamada", 28);
+SELECT * FROM scores;
+SELECT * FROM scores WHERE name = "Taro Yamada" AND (score >= -12 AND score < 29);
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_double.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_double.test
new file mode 100644
index 00000000..5730aaf8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_double.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS temperatures;
+--enable_warnings
+
+CREATE TABLE temperatures (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(20),
+ temperature DOUBLE,
+ KEY temperature_index(temperature),
+ KEY multi_index(temperature, title)
+);
+
+INSERT INTO temperatures VALUES (NULL, "Hot!", 28.2);
+INSERT INTO temperatures VALUES (NULL, "Snow!", -2.8);
+INSERT INTO temperatures VALUES (NULL, "Rainy!", 12.7);
+
+SELECT temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+SELECT temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+
+DROP TABLE temperatures;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_float.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_float.test
new file mode 100644
index 00000000..1b7132b3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_float.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS temperatures;
+--enable_warnings
+
+CREATE TABLE temperatures (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title VARCHAR(20),
+ temperature FLOAT,
+ KEY temperature_index(temperature),
+ KEY multi_index(temperature, title)
+);
+
+INSERT INTO temperatures VALUES (NULL, "Hot!", 28.2);
+INSERT INTO temperatures VALUES (NULL, "Snow!", -2.8);
+INSERT INTO temperatures VALUES (NULL, "Rainy!", 12.7);
+
+SELECT temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+SELECT temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN 10 AND 30;
+SELECT title, temperature FROM temperatures WHERE temperature BETWEEN -10 AND 20;
+
+DROP TABLE temperatures;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_int.test
new file mode 100644
index 00000000..332ecfc9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_int.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS listing;
+--enable_warnings
+
+CREATE TABLE scores (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ name CHAR(30) NOT NULL,
+ score INT NOT NULL,
+ INDEX property (score, name)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 27);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+
+SELECT * FROM scores;
+
+SELECT * FROM scores WHERE score = 29;
+
+SELECT * FROM scores WHERE score = 29 AND name = "Taro Yamada";
+
+SELECT * FROM scores WHERE (score >= -12 AND score < 29) AND name = "Taro Yamada";
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_max.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_max.test
new file mode 100644
index 00000000..bdd3b0c3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_max.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS listing;
+--enable_warnings
+
+CREATE TABLE scores (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT NOT NULL,
+ score2 INT NOT NULL,
+ INDEX (score1, score2)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO scores (score1, score2) VALUES(1, 1);
+INSERT INTO scores (score1, score2) VALUES(1, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 3);
+INSERT INTO scores (score1, score2) VALUES(2, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 1);
+INSERT INTO scores (score1, score2) VALUES(2, 0);
+INSERT INTO scores (score1, score2) VALUES(2, -1);
+INSERT INTO scores (score1, score2) VALUES(2, -2);
+INSERT INTO scores (score1, score2) VALUES(2, -3);
+
+SELECT MAX(score2) FROM scores WHERE score1 = 2;
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_min.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_min.test
new file mode 100644
index 00000000..23a16379
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_min.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS listing;
+--enable_warnings
+
+CREATE TABLE scores (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ score1 INT NOT NULL,
+ score2 INT NOT NULL,
+ INDEX (score1, score2)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO scores (score1, score2) VALUES(1, 1);
+INSERT INTO scores (score1, score2) VALUES(1, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 3);
+INSERT INTO scores (score1, score2) VALUES(2, 2);
+INSERT INTO scores (score1, score2) VALUES(2, 1);
+INSERT INTO scores (score1, score2) VALUES(2, 0);
+INSERT INTO scores (score1, score2) VALUES(2, -1);
+INSERT INTO scores (score1, score2) VALUES(2, -2);
+INSERT INTO scores (score1, score2) VALUES(2, -3);
+
+SELECT MIN(score2) FROM scores WHERE score1 = 2;
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_string.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_string.test
new file mode 100644
index 00000000..8805771e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_string.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table listing (
+ id int primary key auto_increment not null,
+ last_name char(30) not null,
+ first_name char(30) not null,
+ index name (last_name, first_name)
+) default charset utf8;
+show create table listing;
+insert into listing (last_name, first_name) values("Taro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Suzuki");
+insert into listing (last_name, first_name) values("Jiro", "Yamada");
+insert into listing (last_name, first_name) values("Taro", "Tanaka");
+select * from listing;
+select * from listing where last_name = "Taro";
+select * from listing where last_name = "Taro" and first_name = "Suzuki";
+select * from listing where last_name = "Taro" and (first_name >= "S" and first_name <= "Y");
+drop table listing;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_varchar.test
new file mode 100644
index 00000000..fad11187
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_select_varchar.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists scores;
+--enable_warnings
+
+set names utf8;
+create table scores (
+ given_name varchar(30) not null,
+ family_name varchar(30) not null,
+ score int not null,
+ primary key property (given_name, family_name, score)
+) default charset utf8;
+show create table scores;
+
+insert into scores values("Taro", "Yamada", 29);
+insert into scores values("Taro", "Yamada", -12);
+insert into scores values("Jiro", "Yamada", 27);
+insert into scores values("Taro", "Yamada", 10);
+
+select * from scores;
+select * from scores where given_name = "Taro" and family_name = "Yamada";
+select * from scores where given_name = "Taro" and family_name = "Yamada" and score = 29;
+select * from scores where given_name = "Taro" and family_name = "Yamada" and (score >= -12 and score < 29);
+
+drop table scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_32bit_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_32bit_equal.test
new file mode 100644
index 00000000..bf420af0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_32bit_equal.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, "1000-01-01", "2012-10-05");
+INSERT IGNORE INTO ranges VALUES (2, "1000-01-01", "9999-12-31");
+INSERT IGNORE INTO ranges VALUES (3, "2012-10-25", "9999-12-31");
+INSERT IGNORE INTO ranges VALUES (4, "9999-12-31", "1000-01-01");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ WHERE start = "1000-01-01" AND end = "9999-12-31";
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_64bit_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_64bit_equal.test
new file mode 100644
index 00000000..236ff40c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_64bit_equal.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (2, "1000-01-02", "9999-12-31");
+INSERT INTO ranges VALUES (3, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (4, "9999-12-31", "1000-01-02");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ WHERE start = "1000-01-02" AND end = "9999-12-31";
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_index_read.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_index_read.test
new file mode 100644
index 00000000..901d55ed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_index_read.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (2, "1000-01-02", "9999-12-31");
+INSERT INTO ranges VALUES (3, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (4, "9999-12-31", "1000-01-02");
+
+SELECT start, end
+ FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_asc.test
new file mode 100644
index 00000000..767fcce9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_asc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+INSERT IGNORE INTO ranges VALUES (2, "1000-01-01", "2012-10-05");
+INSERT IGNORE INTO ranges VALUES (3, "9999-12-31", "1000-01-01");
+INSERT IGNORE INTO ranges VALUES (4, "1000-01-01", "9999-12-31");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_desc.test
new file mode 100644
index 00000000..fa1b841a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_32bit_desc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+INSERT IGNORE INTO ranges VALUES (2, "1000-01-01", "2012-10-05");
+INSERT IGNORE INTO ranges VALUES (3, "9999-12-31", "1000-01-01");
+INSERT IGNORE INTO ranges VALUES (4, "1000-01-01", "9999-12-31");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_asc.test
new file mode 100644
index 00000000..c5147500
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_asc.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (2, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (3, "9999-12-31", "1000-01-02");
+INSERT INTO ranges VALUES (4, "1000-01-02", "9999-12-31");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_desc.test
new file mode 100644
index 00000000..3ccb4249
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_order_64bit_desc.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2012-10-25", "9999-12-31");
+INSERT INTO ranges VALUES (2, "1000-01-02", "2012-10-05");
+INSERT INTO ranges VALUES (3, "9999-12-31", "1000-01-02");
+INSERT INTO ranges VALUES (4, "1000-01-02", "9999-12-31");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_reinsert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_reinsert.test
new file mode 100644
index 00000000..a6d82c32
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_date_reinsert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start DATE,
+ end DATE,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2010-01-01", "2012-10-05");
+SELECT * FROM ranges;
+
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "2010-01-01", "2012-10-05");
+SELECT * FROM ranges;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_index_read.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_index_read.test
new file mode 100644
index 00000000..b1e4a3b8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_index_read.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start datetime,
+ end datetime,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "1000-01-02 00:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (2, "1000-01-02 00:00:00", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (3, "2012-10-25 16:18:29", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (4, "9999-12-31 23:59:59", "1000-01-02 00:00:00");
+
+SELECT start, end
+ FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.test
new file mode 100644
index 00000000..dc8cebf7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_insert_delete_insert_invalid_value.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015-2017 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-1335 USA
+
+--source ../../include/mroonga/skip_strict_sql_mode.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start datetime,
+ end datetime,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, "1990-00-00 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+
+DELETE FROM ranges WHERE id = 1;
+INSERT IGNORE INTO ranges VALUES (1, "1990-00-00 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_asc.test
new file mode 100644
index 00000000..7cb4e219
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_asc.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start datetime,
+ end datetime,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (2, "1000-01-02 00:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "9999-12-31 23:59:59", "1000-01-02 00:00:00");
+INSERT INTO ranges VALUES (4, "1000-01-02 00:00:00", "9999-12-31 23:59:59");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_desc.test
new file mode 100644
index 00000000..e2b1bb0a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_order_desc.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/skip_freebsd.inc
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start datetime,
+ end datetime,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "9999-12-31 23:59:59");
+INSERT INTO ranges VALUES (2, "1000-01-02 00:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "9999-12-31 23:59:59", "1000-01-02 00:00:00");
+INSERT INTO ranges VALUES (4, "1000-01-02 00:00:00", "9999-12-31 23:59:59");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_reinsert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_reinsert.test
new file mode 100644
index 00000000..927d8aed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_datetime_reinsert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start datetime,
+ end datetime,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_decimal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_decimal.test
new file mode 100644
index 00000000..7ae2be84
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_decimal.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 decimal(65,30), c3 decimal(65,30), unique key uk1(c2,c3));
+insert into t1 values(1,123.456,0.000000000000000000000000000001);
+insert into t1 values(2,-123.456,123.456);
+insert into t1 values(3,98765432109876543210987654321098765.432109876543210987654321098765,-123.456);
+insert into t1 values(4,-98765432109876543210987654321098765.432109876543210987654321098765,98765432109876543210987654321098765.432109876543210987654321098765);
+insert into t1 values(5,0.000000000000000000000000000001,-98765432109876543210987654321098765.432109876543210987654321098765);
+select c1, c2, c3 from t1 force index(uk1) where c2 = -98765432109876543210987654321098765.432109876543210987654321098765 and c3 = 98765432109876543210987654321098765.432109876543210987654321098765;
+select c1, c2, c3 from t1 force index(uk1) order by c2, c3;
+select c1, c2, c3 from t1 force index(uk1) order by c2 desc, c3 desc;
+select c2, c3 from t1 force index(uk1) order by c2, c3;
+--error ER_DUP_ENTRY
+insert into t1 values(6,123.456,0.000000000000000000000000000001);
+delete from t1 where c1 = 1;
+insert into t1 values(1,123.456,0.000000000000000000000000000001);
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_index_read.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_index_read.test
new file mode 100644
index 00000000..1229d887
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_index_read.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start time,
+ end time,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "00:00:00", "15:11:11");
+INSERT INTO ranges VALUES (2, "00:00:00", "838:59:59");
+INSERT INTO ranges VALUES (3, "15:11:12", "838:59:59");
+INSERT INTO ranges VALUES (4, "838:59:59", "00:00:00");
+INSERT INTO ranges VALUES (5, "-838:59:59", "838:59:59");
+
+SELECT start, end
+ FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_asc.test
new file mode 100644
index 00000000..68fbb2ac
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_asc.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start time,
+ end time,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "15:11:12", "838:59:59");
+INSERT INTO ranges VALUES (2, "00:00:00", "15:11:11");
+INSERT INTO ranges VALUES (3, "838:59:59", "00:00:00");
+INSERT INTO ranges VALUES (4, "00:00:00", "838:59:59");
+INSERT INTO ranges VALUES (5, "-838:59:59", "838:59:59");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_desc.test
new file mode 100644
index 00000000..3ae97526
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_order_desc.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start time,
+ end time,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "15:11:12", "838:59:59");
+INSERT INTO ranges VALUES (2, "00:00:00", "15:11:11");
+INSERT INTO ranges VALUES (3, "838:59:59", "00:00:00");
+INSERT INTO ranges VALUES (4, "00:00:00", "838:59:59");
+INSERT INTO ranges VALUES (5, "-838:59:59", "838:59:59");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_reinsert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_reinsert.test
new file mode 100644
index 00000000..20b08342
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_time_reinsert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start time,
+ end time,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "13:21:48", "15:11:12");
+SELECT * FROM ranges;
+
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "13:21:48", "15:11:12");
+SELECT * FROM ranges;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_index_read.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_index_read.test
new file mode 100644
index 00000000..0c3315d0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_index_read.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start timestamp DEFAULT '2016-04-21 00:00:00',
+ end timestamp DEFAULT '2016-04-22 00:00:00',
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "1970-01-01 12:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (2, "1970-01-01 12:00:00", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (3, "2012-10-25 16:18:29", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (4, "2038-01-18 15:14:07", "1970-01-01 12:00:00");
+
+SELECT start, end
+ FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_asc.test
new file mode 100644
index 00000000..2780a153
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_asc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start timestamp DEFAULT '2016-04-21 00:00:00',
+ end timestamp DEFAULT '2016-04-22 00:00:00',
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (2, "1970-01-01 12:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "2038-01-18 15:14:07", "1970-01-01 12:00:00");
+INSERT INTO ranges VALUES (4, "1970-01-01 12:00:00", "2038-01-18 15:14:07");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_desc.test
new file mode 100644
index 00000000..2e827343
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_order_desc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start timestamp DEFAULT '2016-04-21 00:00:00',
+ end timestamp DEFAULT '2016-04-22 00:00:00',
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2012-10-25 16:18:29", "2038-01-18 15:14:07");
+INSERT INTO ranges VALUES (2, "1970-01-01 12:00:00", "2012-10-05 16:18:29");
+INSERT INTO ranges VALUES (3, "2038-01-18 15:14:07", "1970-01-01 12:00:00");
+INSERT INTO ranges VALUES (4, "1970-01-01 12:00:00", "2038-01-18 15:14:07");
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_reinsert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_reinsert.test
new file mode 100644
index 00000000..36532836
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_timestamp_reinsert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id int PRIMARY KEY,
+ start timestamp DEFAULT '2016-04-21 00:00:00',
+ end timestamp DEFAULT '2016-04-22 00:00:00',
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, "2010-01-01 00:00:00", "2012-10-05 23:59:59");
+SELECT * FROM ranges;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_varchar.test
new file mode 100644
index 00000000..eb0aabde
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_varchar.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 varchar(10), c3 varchar(10), unique key uk1(c2,c3)) default charset=utf8 collate utf8_bin;
+insert into t1 values(1,'abcde','abc ');
+insert into t1 values(2,'abc\0','abcde');
+insert into t1 values(3,'abc','abc\0');
+insert into t1 values(4,'abc ','abc');
+insert into t1 values(5,'abc ','abc ');
+select c1, c2, c3 from t1 force index(uk1) where c2 = 'abc ' and c3 = 'abc';
+select c1, c2, c3 from t1 force index(uk1) order by c2, c3;
+select c1, c2, c3 from t1 force index(uk1) order by c2 desc, c3 desc;
+select c2, c3 from t1 force index(uk1) order by c2, c3;
+--error ER_DUP_ENTRY
+insert into t1 values(6,'abcde','abc ');
+delete from t1 where c1 = 1;
+insert into t1 values(1,'abcde','abc ');
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_32bit_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_32bit_equal.test
new file mode 100644
index 00000000..1d93df36
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_32bit_equal.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, 1901, 2012);
+INSERT IGNORE INTO ranges VALUES (2, 1901, 2155);
+INSERT IGNORE INTO ranges VALUES (3, 2012, 2155);
+INSERT IGNORE INTO ranges VALUES (4, 2155, 1901);
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ WHERE start = 1901 AND end = 2155;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_64bit_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_64bit_equal.test
new file mode 100644
index 00000000..5cad0231
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_64bit_equal.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, 1901, 2012);
+INSERT INTO ranges VALUES (2, 1901, 2155);
+INSERT INTO ranges VALUES (3, 2012, 2155);
+INSERT INTO ranges VALUES (4, 2155, 1901);
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ WHERE start = 1901 AND end = 2155;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_index_read.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_index_read.test
new file mode 100644
index 00000000..9bc8aaf2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_index_read.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, 1901, 2012);
+INSERT INTO ranges VALUES (2, 1901, 2155);
+INSERT INTO ranges VALUES (3, 2012, 2155);
+INSERT INTO ranges VALUES (4, 2155, 1901);
+
+SELECT start, end
+ FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_asc.test
new file mode 100644
index 00000000..8090ccc5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_asc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, 2012, 2155);
+INSERT IGNORE INTO ranges VALUES (2, 1901, 2012);
+INSERT IGNORE INTO ranges VALUES (3, 2155, 1901);
+INSERT IGNORE INTO ranges VALUES (4, 1901, 2155);
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_desc.test
new file mode 100644
index 00000000..8927d4bd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_32bit_desc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT IGNORE INTO ranges VALUES (1, 2012, 2155);
+INSERT IGNORE INTO ranges VALUES (2, 1901, 2012);
+INSERT IGNORE INTO ranges VALUES (3, 2155, 1901);
+INSERT IGNORE INTO ranges VALUES (4, 1901, 2155);
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_asc.test
new file mode 100644
index 00000000..d9d1f458
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_asc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, 2012, 2155);
+INSERT INTO ranges VALUES (2, 1901, 2012);
+INSERT INTO ranges VALUES (3, 2155, 1901);
+INSERT INTO ranges VALUES (4, 1901, 2155);
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start, end;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_desc.test
new file mode 100644
index 00000000..1a2b70eb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_order_64bit_desc.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_signed_64bit_time_t.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, 2012, 2155);
+INSERT INTO ranges VALUES (2, 1901, 2012);
+INSERT INTO ranges VALUES (3, 2155, 1901);
+INSERT INTO ranges VALUES (4, 1901, 2155);
+
+SELECT * FROM ranges FORCE INDEX(range_key)
+ ORDER BY start DESC, end DESC;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_reinsert.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_reinsert.test
new file mode 100644
index 00000000..3ee06c48
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_unique_year_reinsert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ranges;
+--enable_warnings
+
+CREATE TABLE ranges (
+ id INT PRIMARY KEY,
+ start YEAR,
+ end YEAR,
+ UNIQUE KEY range_key(start, end)
+);
+
+INSERT INTO ranges VALUES (1, 2010, 2012);
+SELECT * FROM ranges;
+
+DELETE FROM ranges WHERE id = 1;
+INSERT INTO ranges VALUES (1, 2010, 2012);
+SELECT * FROM ranges;
+
+DROP TABLE ranges;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_int.test
new file mode 100644
index 00000000..d7f9dd93
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_int.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+CREATE TABLE scores (
+ id INT PRIMARY KEY AUTO_INCREMENT NOT NULL,
+ name CHAR(30) NOT NULL,
+ score INT NOT NULL,
+ KEY property (score, name)
+) DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE scores;
+
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", -12);
+INSERT INTO scores (name, score) VALUES("Jiro Yamada", 29);
+INSERT INTO scores (name, score) VALUES("Taro Yamada", 10);
+
+SELECT * FROM scores WHERE score = 29;
+
+UPDATE scores SET name = "Saburo YAMADA" WHERE id = 3;
+SELECT * FROM scores WHERE score = 29;
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_string.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_string.test
new file mode 100644
index 00000000..6efe83ce
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_multiple_column_update_string.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists listing;
+--enable_warnings
+
+set names utf8;
+create table scores (
+ id int primary key auto_increment not null,
+ name char(30) not null,
+ score int not null,
+ index property (name, score)
+) default charset utf8;
+show create table scores;
+insert into scores (name, score) values("Taro Yamada", 29);
+insert into scores (name, score) values("Taro Yamada", -12);
+insert into scores (name, score) values("Jiro Yamada", 27);
+insert into scores (name, score) values("Taro Yamada", 10);
+select * from scores;
+update scores set name = "Taro Yamada" where name = "Jiro Yamada" and score = 27;
+select * from scores where name = "Taro Yamada" and (score >= -12 and score < 29);
+drop table scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_exact_length.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_exact_length.test
new file mode 100644
index 00000000..bd3d182d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_exact_length.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id char(10) CHARACTER SET latin1 PRIMARY KEY
+);
+
+INSERT INTO ids VALUES('abcdefghij');
+INSERT INTO ids VALUES('klmnopqrst');
+INSERT INTO ids VALUES('uvwxyz0123');
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) ORDER BY id;
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) WHERE id = 'abcdefghij';
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_null_character.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_null_character.test
new file mode 100644
index 00000000..afc0b9ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_null_character.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id char(7) CHARACTER SET latin1 COLLATE latin1_bin PRIMARY KEY
+);
+
+INSERT INTO ids VALUES("\0abcdef");
+INSERT INTO ids VALUES("ab\0cdef");
+INSERT INTO ids VALUES("abcd\0ef");
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) ORDER BY id;
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) WHERE id = "ab\0cdef";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_short.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_short.test
new file mode 100644
index 00000000..ee0887f3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_char_short.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id char(6) CHARACTER SET latin1 PRIMARY KEY
+);
+
+INSERT INTO ids VALUES("abcdef");
+INSERT INTO ids VALUES( "cdef");
+INSERT INTO ids VALUES( "ef");
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) ORDER BY id;
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) WHERE id = "cdef";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_date.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_date.test
new file mode 100644
index 00000000..455017bf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_date.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (day, title) VALUES ("2012-01-29", "clear day");
+INSERT INTO diaries (day, title) VALUES ("2012-01-30", "rainy day");
+INSERT INTO diaries (day, title) VALUES ("2012-01-31", "cloudy day");
+--error ER_DUP_ENTRY
+INSERT INTO diaries (day, title) VALUES ("2012-01-31", "duplicated day");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE day BETWEEN "2012-01-29" AND "2012-01-30";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_with_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_with_fractional_seconds.test
new file mode 100644
index 00000000..6daeed75
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_with_fractional_seconds.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_fractional_seconds.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ day DATETIME(6) PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (day, title)
+ VALUES ("2012-01-29 21:51:01.111111", "clear day");
+INSERT INTO diaries (day, title)
+ VALUES ("2012-01-30 01:23:45.333", "rainy day");
+INSERT INTO diaries (day, title)
+ VALUES ("2012-01-31 08:32:10.5555", "cloudy day");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE day BETWEEN "2012-01-29 00:00:00.123456" AND
+ "2012-01-31 00:00:00.999999";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_without_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_without_fractional_seconds.test
new file mode 100644
index 00000000..9500148e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_datetime_without_fractional_seconds.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ day DATETIME PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (day, title)
+ VALUES ("2012-01-29 21:51:01", "clear day");
+INSERT INTO diaries (day, title)
+ VALUES ("2012-01-30 01:23:45", "rainy day");
+INSERT INTO diaries (day, title)
+ VALUES ("2012-01-31 08:32:10", "cloudy day");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE day BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_with_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_with_fractional_seconds.test
new file mode 100644
index 00000000..37ccd1e5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_with_fractional_seconds.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS releases;
+--enable_warnings
+
+CREATE TABLE releases (
+ version DECIMAL(6, 3) PRIMARY KEY,
+ message TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO releases (version, message) VALUES (10.000, "10th release!");
+INSERT INTO releases (version, message) VALUES (10.001, "minor fix.");
+INSERT INTO releases (version, message) VALUES (999.999, "the last release!");
+
+SELECT * FROM releases;
+
+SELECT * FROM releases WHERE version BETWEEN "9.000" AND "10.001";
+
+DROP TABLE releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_without_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_without_fractional_seconds.test
new file mode 100644
index 00000000..477368ba
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_decimal_without_fractional_seconds.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS releases;
+--enable_warnings
+
+CREATE TABLE releases (
+ version DECIMAL PRIMARY KEY,
+ message TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO releases (version, message) VALUES (1, "the first release!!!");
+INSERT INTO releases (version, message) VALUES (10, "10th release!");
+INSERT INTO releases (version, message) VALUES (999, "the last release!");
+
+SELECT * FROM releases;
+
+SELECT * FROM releases WHERE version BETWEEN "1" AND "10";
+
+DROP TABLE releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_with_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_with_fractional_seconds.test
new file mode 100644
index 00000000..7db2825f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_with_fractional_seconds.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_fractional_seconds.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS running_records;
+--enable_warnings
+
+CREATE TABLE running_records (
+ time TIME(6) PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO running_records (time, title)
+ VALUES ("01:00:00.000001", "normal condition");
+INSERT INTO running_records (time, title)
+ VALUES ("12:23:34.123456", "bad condition");
+INSERT INTO running_records (time, title)
+ VALUES ("-838:59:59.000000", "record failure");
+
+SELECT * FROM running_records;
+
+SELECT * FROM running_records
+ WHERE time BETWEEN "00:59:59.999999" AND "12:23:34.123456";
+
+DROP TABLE running_records;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_without_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_without_fractional_seconds.test
new file mode 100644
index 00000000..721d6392
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_time_without_fractional_seconds.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS running_records;
+--enable_warnings
+
+CREATE TABLE running_records (
+ time TIME PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO running_records (time, title)
+ VALUES ("01:00:00", "normal condition");
+INSERT INTO running_records (time, title)
+ VALUES ("12:23:34", "bad condition");
+INSERT INTO running_records (time, title)
+ VALUES ("-838:59:59", "record failure");
+
+SELECT * FROM running_records;
+
+SELECT * FROM running_records
+ WHERE time BETWEEN "00:59:59" AND "12:23:34";
+
+DROP TABLE running_records;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_with_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_with_fractional_seconds.test
new file mode 100644
index 00000000..116f11a5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_with_fractional_seconds.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_mariadb_5_5.inc
+--source ../../include/mroonga/have_fractional_seconds.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ time TIMESTAMP(6) PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (time, title)
+ VALUES ("2012-01-29 21:51:01.111111", "clear day");
+INSERT INTO diaries (time, title)
+ VALUES ("2012-01-30 01:23:45.333", "rainy day");
+INSERT INTO diaries (time, title)
+ VALUES ("2012-01-31 08:32:10.5555", "cloudy day");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE time BETWEEN "2012-01-29 00:00:00.123456" AND
+ "2012-01-31 00:00:00.999999";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_without_fractional_seconds.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_without_fractional_seconds.test
new file mode 100644
index 00000000..67f03299
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_timestamp_without_fractional_seconds.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ time TIMESTAMP PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (time, title) VALUES ("2012-01-29 21:51:01", "clear day");
+INSERT INTO diaries (time, title) VALUES ("2012-01-30 01:23:45", "rainy day");
+INSERT INTO diaries (time, title) VALUES ("2012-01-31 08:32:10", "cloudy day");
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries
+ WHERE time BETWEEN "2012-01-29 00:00:00" AND "2012-01-31 00:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_varchar_null_character.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_varchar_null_character.test
new file mode 100644
index 00000000..6d458d78
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_varchar_null_character.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id varchar(7) CHARACTER SET latin1 COLLATE latin1_bin PRIMARY KEY
+);
+
+INSERT INTO ids VALUES("\0abcdef");
+INSERT INTO ids VALUES("ab\0cdef");
+INSERT INTO ids VALUES("abcd\0ef");
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) ORDER BY id;
+
+SELECT * FROM ids FORCE INDEX(PRIMARY) WHERE id = "ab\0cdef";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_year.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_year.test
new file mode 100644
index 00000000..f6bb7dc3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_primary_year.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS aniversary_memos;
+--enable_warnings
+
+CREATE TABLE aniversary_memos (
+ party_year YEAR PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO aniversary_memos (party_year, title)
+ VALUES ("11", "We need a big cake!");
+INSERT INTO aniversary_memos (party_year, title)
+ VALUES ("2012", "Invitations are sent.");
+INSERT INTO aniversary_memos (party_year, title)
+ VALUES ("13", "Wow! Today is the anniversary party day!");
+
+SELECT * FROM aniversary_memos;
+
+SELECT * FROM aniversary_memos
+ WHERE party_year BETWEEN "12" AND "2013";
+
+DROP TABLE aniversary_memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_asc.test
new file mode 100644
index 00000000..660e4370
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_asc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value > 10 ORDER BY value ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_desc.test
new file mode 100644
index 00000000..7abae60f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_desc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value > 10 ORDER BY value DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_asc.test
new file mode 100644
index 00000000..063d2ff7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_asc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value >= 30 ORDER BY value ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_desc.test
new file mode 100644
index 00000000..e3d22364
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_greater_than_or_equal_desc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value >= 30 ORDER BY value DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_asc.test
new file mode 100644
index 00000000..0efc5544
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_asc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value < 90 ORDER BY value ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_desc.test
new file mode 100644
index 00000000..c356a714
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_desc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value < 90 ORDER BY value DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_asc.test
new file mode 100644
index 00000000..b919b5f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_asc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value <= 70 ORDER BY value ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_desc.test
new file mode 100644
index 00000000..43e870a3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_normal_less_than_or_equal_desc.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT,
+ value INT(10),
+ INDEX (value)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES(1, 50);
+INSERT INTO ids VALUES(2, 70);
+INSERT INTO ids VALUES(3, 30);
+INSERT INTO ids VALUES(4, 90);
+INSERT INTO ids VALUES(5, 10);
+
+SELECT id, value FROM ids WHERE value <= 70 ORDER BY value DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_asc.test
new file mode 100644
index 00000000..c7086421
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_asc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id > 1 ORDER BY ids.id ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_desc.test
new file mode 100644
index 00000000..dd53c39c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_desc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id > 3 ORDER BY ids.id DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_asc.test
new file mode 100644
index 00000000..25dfa56f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_asc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id >= 2 ORDER BY ids.id ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_desc.test
new file mode 100644
index 00000000..b74b2533
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_greater_than_or_equal_desc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id >= 3 ORDER BY ids.id DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_asc.test
new file mode 100644
index 00000000..2848d4eb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_asc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id < 4 ORDER BY ids.id ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_desc.test
new file mode 100644
index 00000000..99854c57
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_desc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id < 4 ORDER BY ids.id DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_asc.test
new file mode 100644
index 00000000..801d6fd9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_asc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id <= 4 ORDER BY ids.id ASC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_desc.test
new file mode 100644
index 00000000..c5d2f5cd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_range_primary_less_than_or_equal_desc.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+SET NAMES UTF8;
+
+CREATE TABLE ids (
+ id INT(10) UNSIGNED PRIMARY KEY AUTO_INCREMENT
+) ENGINE=Mroonga DEFAULT CHARSET=utf8;
+
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+INSERT INTO ids VALUES();
+
+SELECT * FROM ids WHERE ids.id <= 4 ORDER BY ids.id DESC LIMIT 3;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint.test
new file mode 100644
index 00000000..cc37192e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id BIGINT,
+ value BIGINT,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint_unsigned.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint_unsigned.test
new file mode 100644
index 00000000..df0bf264
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_bigint_unsigned.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id BIGINT UNSIGNED,
+ value BIGINT UNSIGNED,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_double.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_double.test
new file mode 100644
index 00000000..df0e9e81
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_double.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id DOUBLE,
+ value DOUBLE,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1.1, 16.16);
+INSERT INTO ids VALUES ( -2.2, 8.8);
+INSERT INTO ids VALUES ( -4.4, 4.4);
+INSERT INTO ids VALUES ( -8.8, 2.2);
+INSERT INTO ids VALUES (-16.6, 1.1);
+INSERT INTO ids VALUES ( 16.6, -1.1);
+INSERT INTO ids VALUES ( 8.8, -2.2);
+INSERT INTO ids VALUES ( 4.4, -4.4);
+INSERT INTO ids VALUES ( 2.2, -8.8);
+INSERT INTO ids VALUES ( 1.1, -16.16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4.5 AND 8.9;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_float.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_float.test
new file mode 100644
index 00000000..a04f84eb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_float.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id FLOAT,
+ value FLOAT,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1.1, 16.16);
+INSERT INTO ids VALUES ( -2.2, 8.8);
+INSERT INTO ids VALUES ( -4.4, 4.4);
+INSERT INTO ids VALUES ( -8.8, 2.2);
+INSERT INTO ids VALUES (-16.6, 1.1);
+INSERT INTO ids VALUES ( 16.6, -1.1);
+INSERT INTO ids VALUES ( 8.8, -2.2);
+INSERT INTO ids VALUES ( 4.4, -4.4);
+INSERT INTO ids VALUES ( 2.2, -8.8);
+INSERT INTO ids VALUES ( 1.1, -16.16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4.5 AND 8.9;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int.test
new file mode 100644
index 00000000..aafb352b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT,
+ value INT,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int_unsigned.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int_unsigned.test
new file mode 100644
index 00000000..d82bcb9c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_int_unsigned.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT UNSIGNED,
+ value INT UNSIGNED,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint.test
new file mode 100644
index 00000000..8afe5411
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id MEDIUMINT,
+ value MEDIUMINT,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint_unsigned.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint_unsigned.test
new file mode 100644
index 00000000..70c89470
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_mediumint_unsigned.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id MEDIUMINT UNSIGNED,
+ value MEDIUMINT UNSIGNED,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint.test
new file mode 100644
index 00000000..f33b6356
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id SMALLINT,
+ value SMALLINT,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint_unsigned.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint_unsigned.test
new file mode 100644
index 00000000..4a36ef3a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_smallint_unsigned.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id SMALLINT UNSIGNED,
+ value SMALLINT UNSIGNED,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint.test
new file mode 100644
index 00000000..40d338d4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id TINYINT,
+ value TINYINT,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( -1, 16);
+INSERT INTO ids VALUES ( -2, 8);
+INSERT INTO ids VALUES ( -4, 4);
+INSERT INTO ids VALUES ( -8, 2);
+INSERT INTO ids VALUES (-16, 1);
+INSERT INTO ids VALUES ( 16, -1);
+INSERT INTO ids VALUES ( 8, -2);
+INSERT INTO ids VALUES ( 4, -4);
+INSERT INTO ids VALUES ( 2, -8);
+INSERT INTO ids VALUES ( 1, -16);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN -4 AND 8;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint_unsigned.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint_unsigned.test
new file mode 100644
index 00000000..40e91829
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_tinyint_unsigned.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id TINYINT UNSIGNED,
+ value TINYINT UNSIGNED,
+ KEY (id, value)
+);
+
+INSERT INTO ids VALUES ( 1, 1);
+INSERT INTO ids VALUES ( 2, 2);
+INSERT INTO ids VALUES ( 4, 3);
+INSERT INTO ids VALUES ( 8, 4);
+INSERT INTO ids VALUES (16, 5);
+INSERT INTO ids VALUES (32, 6);
+INSERT INTO ids VALUES (64, 7);
+INSERT INTO ids VALUES (128, 8);
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 4 AND 32;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar.test
new file mode 100644
index 00000000..bbc89e09
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id VARCHAR(5),
+ value VARCHAR(10),
+ KEY (id, value)
+) DEFAULT CHARSET=utf8 COLLATE utf8_bin;
+
+INSERT INTO ids VALUES ("abc", "Abc");
+INSERT INTO ids VALUES ("acd", "aBc");
+INSERT INTO ids VALUES ("ade", "abC");
+INSERT INTO ids VALUES ("aef", "abc");
+INSERT INTO ids VALUES ("ABC", "aBC");
+INSERT INTO ids VALUES ("ACD", "AbC");
+INSERT INTO ids VALUES ("ADE", "ABc");
+INSERT INTO ids VALUES ("AEF", "ABC");
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN "ab" AND "ad";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar_collation.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar_collation.test
new file mode 100644
index 00000000..8d695b2e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_multiple_varchar_collation.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id VARCHAR(5),
+ value VARCHAR(10),
+ KEY (id, value)
+) DEFAULT CHARSET=utf8 COLLATE utf8_unicode_ci;
+
+INSERT INTO ids VALUES ("abc", "Abc");
+INSERT INTO ids VALUES ("acd", "aBc");
+INSERT INTO ids VALUES ("ade", "abC");
+INSERT INTO ids VALUES ("aef", "abc");
+INSERT INTO ids VALUES ("ABC", "aBC");
+INSERT INTO ids VALUES ("ACD", "AbC");
+INSERT INTO ids VALUES ("ADE", "ABc");
+INSERT INTO ids VALUES ("AEF", "ABC");
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN "ab" AND "ad";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_int.test
new file mode 100644
index 00000000..abe68f79
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_int.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT,
+ KEY (id)
+);
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids SELECT id + 1 FROM ids;
+INSERT INTO ids SELECT id + 2 FROM ids;
+INSERT INTO ids SELECT id + 4 FROM ids;
+INSERT INTO ids SELECT id + 8 FROM ids;
+INSERT INTO ids SELECT id + 16 FROM ids;
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 10 AND 16;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_varchar.test
new file mode 100644
index 00000000..7203b005
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_normal_varchar.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id VARCHAR(10),
+ KEY (id)
+);
+
+INSERT INTO ids VALUES ("1");
+INSERT INTO ids SELECT id + "1" FROM ids;
+INSERT INTO ids SELECT id + "2" FROM ids;
+INSERT INTO ids SELECT id + "4" FROM ids;
+INSERT INTO ids SELECT id + "8" FROM ids;
+INSERT INTO ids SELECT id + "16" FROM ids;
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN "10" AND "16";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_int.test
new file mode 100644
index 00000000..bd286894
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_int.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT,
+ PRIMARY KEY (id)
+);
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids SELECT id + 1 FROM ids;
+INSERT INTO ids SELECT id + 2 FROM ids;
+INSERT INTO ids SELECT id + 4 FROM ids;
+INSERT INTO ids SELECT id + 8 FROM ids;
+INSERT INTO ids SELECT id + 16 FROM ids;
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN 10 AND 16;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_varchar.test
new file mode 100644
index 00000000..2a166d01
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_read_primary_varchar.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id VARCHAR(10),
+ PRIMARY KEY (id)
+);
+
+INSERT INTO ids VALUES ("1");
+INSERT INTO ids SELECT id + "1" FROM ids;
+INSERT INTO ids SELECT id + "2" FROM ids;
+INSERT INTO ids SELECT id + "4" FROM ids;
+INSERT INTO ids SELECT id + "8" FROM ids;
+INSERT INTO ids SELECT id + "16" FROM ids;
+
+SELECT * FROM ids;
+SELECT * FROM ids WHERE id BETWEEN "10" AND "16";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_all.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_all.test
new file mode 100644
index 00000000..d67d5849
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_all.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int,
+ UNIQUE KEY (id)
+);
+
+INSERT INTO ids VALUES (1);
+DELETE FROM ids;
+INSERT INTO ids VALUES (1);
+
+SELECT * FROM ids;
+
+-- error ER_DUP_ENTRY
+INSERT INTO ids VALUES (1);
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_by_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_by_primary_key.test
new file mode 100644
index 00000000..38b281f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_delete_by_primary_key.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+CREATE TABLE users (
+ id int PRIMARY KEY,
+ name varchar(100) NOT NULL,
+ UNIQUE KEY name (name)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES (1, "Alice");
+DELETE FROM users WHERE id = 1;
+INSERT INTO users VALUES (1, "Alice");
+
+SELECT * FROM users;
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_insert_after_error.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_insert_after_error.test
new file mode 100644
index 00000000..13bf0eba
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_insert_after_error.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+CREATE TABLE users (
+ id int PRIMARY KEY,
+ name varchar(100) NOT NULL,
+ UNIQUE KEY name (name)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES (1, "Alice");
+-- error ER_DUP_ENTRY
+INSERT INTO users VALUES (1, "Bob");
+INSERT INTO users VALUES (2, "Bob");
+
+SELECT * FROM users;
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_search_after_duplicated.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_search_after_duplicated.test
new file mode 100644
index 00000000..4f464cca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_search_after_duplicated.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+CREATE TABLE users (
+ id int PRIMARY KEY,
+ name varchar(100) NOT NULL,
+ UNIQUE KEY (name)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES (1, "Alice");
+
+INSERT INTO users VALUES (2, "Bob");
+-- error ER_DUP_ENTRY
+INSERT INTO users VALUES (3, "Bob");
+
+SELECT * FROM users;
+SELECT * FROM users WHERE name = "Bob";
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_varchar.test
new file mode 100644
index 00000000..22aba9b9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_unique_varchar.test
@@ -0,0 +1,36 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+CREATE TABLE users (
+ name varchar(100) NOT NULL,
+ UNIQUE KEY name (name)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES ("Alice");
+INSERT INTO users VALUES ("Bob");
+SELECT * FROM users;
+
+SELECT * FROM users WHERE name = "aLiCe";
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_update_multiple_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_update_multiple_column.test
new file mode 100644
index 00000000..9d83b461
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_update_multiple_column.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE scores (
+ deleted BOOLEAN,
+ value INT,
+ INDEX (deleted, value)
+);
+
+INSERT INTO scores VALUES (FALSE, 1);
+INSERT INTO scores VALUES (FALSE, 1);
+INSERT INTO scores VALUES (FALSE, 2);
+
+SELECT count(*) FROM scores WHERE deleted = FALSE;
+UPDATE scores SET deleted = TRUE WHERE value = 1;
+SELECT count(*) FROM scores WHERE deleted = FALSE;
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/index_update_single_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/index_update_single_column.test
new file mode 100644
index 00000000..84a94b95
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/index_update_single_column.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS scores;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE scores (
+ value INT,
+ INDEX (value)
+);
+
+INSERT INTO scores VALUES (21);
+INSERT INTO scores VALUES (21);
+INSERT INTO scores VALUES (22);
+
+SELECT count(*) FROM scores WHERE value >= 20;
+UPDATE scores SET value = 11 WHERE value = 21;
+SELECT count(*) FROM scores WHERE value >= 20;
+
+DROP TABLE scores;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_plugins.test b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_plugins.test
new file mode 100644
index 00000000..2d65b763
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_plugins.test
@@ -0,0 +1,22 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+select PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_TYPE
+ from information_schema.plugins where plugin_name = "Mroonga";
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_none.test b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_none.test
new file mode 100644
index 00000000..d9cb66c8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_none.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY
+);
+
+SELECT AUTO_INCREMENT
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_NAME = "ids";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_use.test b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_use.test
new file mode 100644
index 00000000..7723bf65
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_auto_increment_use.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT AUTO_INCREMENT PRIMARY KEY
+);
+
+SELECT AUTO_INCREMENT
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_NAME = "ids";
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_data_length.test b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_data_length.test
new file mode 100644
index 00000000..8a49ed22
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/information_schema_tables_data_length.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT COUNT(*)
+ FROM INFORMATION_SCHEMA.TABLES
+ WHERE TABLE_NAME = "diaries" AND DATA_LENGTH > 0;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/insert_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/insert_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..81e98c3e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/insert_TODO_SPLIT_ME.test
@@ -0,0 +1,89 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+# data types
+create table t1 (c1 tinyint);
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 smallint);
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 mediumint);
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 int);
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 bigint);
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 float);
+insert into t1 values(0.5);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 double);
+insert into t1 values(0.5);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 date);
+insert into t1 values("2010/03/26");
+select * from t1;
+drop table t1;
+
+create table t1 (c1 time);
+insert into t1 values("11:22:33");
+select * from t1;
+drop table t1;
+
+create table t1 (c1 year);
+insert into t1 values("2010");
+select * from t1;
+drop table t1;
+
+create table t1 (c1 datetime);
+insert into t1 values("2010/03/26 11:22:33");
+select * from t1;
+drop table t1;
+
+# duplicated key error
+create table t1 (c1 int primary key, c2 int);
+insert into t1 values(1,100);
+select * from t1;
+--error ER_DUP_ENTRY
+insert into t1 values(1,200);
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/insert_delayed.test b/storage/mroonga/mysql-test/mroonga/storage/t/insert_delayed.test
new file mode 100644
index 00000000..4d8248b3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/insert_delayed.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2014-2016 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-1335 USA
+
+skip "This test is too fragile.";
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+--error ER_DELAYED_NOT_SUPPORTED
+INSERT DELAYED INTO ids (id) VALUES (1);
+
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.test b/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.test
new file mode 100644
index 00000000..dbeb6ae3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_no_primary_key_and_unique_key_twice.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS numbers;
+--enable_warnings
+
+CREATE TABLE numbers (
+ id INT,
+ count INT,
+ UNIQUE (id)
+);
+
+INSERT INTO numbers (id, count) VALUES (1, 1) ON DUPLICATE KEY UPDATE count = 2;
+INSERT INTO numbers (id, count) VALUES (1, 3) ON DUPLICATE KEY UPDATE count = 4;
+
+SELECT * FROM numbers;
+
+INSERT INTO numbers (id, count) VALUES (2, 1) ON DUPLICATE KEY UPDATE count = 2;
+INSERT INTO numbers (id, count) VALUES (2, 3) ON DUPLICATE KEY UPDATE count = 4;
+
+SELECT * FROM numbers;
+
+DROP TABLE numbers;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_primary_key.test
new file mode 100644
index 00000000..9093560f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_primary_key.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ day DATE PRIMARY KEY,
+ title TEXT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-14", "clear day")
+ ON DUPLICATE KEY UPDATE title = "clear day (duplicated)";
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-14", "rainy day")
+ ON DUPLICATE KEY UPDATE title = "rainy day (duplicated)";
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-15", "cloudy day")
+ ON DUPLICATE KEY UPDATE title = "cloudy day (duplicated)";
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_unique_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_unique_key.test
new file mode 100644
index 00000000..5d8439f2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/insert_on_duplicate_key_update_unique_key.test
@@ -0,0 +1,47 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ day DATE,
+ title TEXT,
+ UNIQUE KEY day (day)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-14", "clear day1")
+ ON DUPLICATE KEY UPDATE title = "clear day1 (duplicated)";
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-14", "clear day2")
+ ON DUPLICATE KEY UPDATE title = "clear day2 (duplicated)";
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-14", "clear day3")
+ ON DUPLICATE KEY UPDATE title = "clear day3 (duplicated)";
+INSERT INTO diaries (day, title)
+ VALUES ("2012-02-15", "cloudy day")
+ ON DUPLICATE KEY UPDATE title = "cloudy day (duplicated)";
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/insert_virtual_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/insert_virtual_column.test
new file mode 100644
index 00000000..6c68a9ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/insert_virtual_column.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2016 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (c1 int, _id int);
+--disable_warnings
+SET sql_mode="";
+--enable_warnings
+# warning WARN_DATA_TRUNCATED
+INSERT INTO t1 (c1,_id) VALUES (1,1);
+--disable_warnings
+SET sql_mode="STRICT_ALL_TABLES";
+--enable_warnings
+# We can't use WARN_DATA_TRUNCATED here because "WXXX" isn't supported
+# MySQL 5.5, 5.6 and MariaDB 5.6. MariaDB 10.0 only supports it.
+# We share this test with all MySQL servers. So we use number here.
+--error 1265
+INSERT INTO t1 (c1,_id) VALUES (4,1);
+SELECT * FROM t1;
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/like_unicode_ci.test b/storage/mroonga/mysql-test/mroonga/storage/t/like_unicode_ci.test
new file mode 100644
index 00000000..4f5940c1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/like_unicode_ci.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS terms;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE terms (
+ content varchar(64) NOT NULL COLLATE 'utf8_unicode_ci',
+ INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO terms VALUES ('track');
+INSERT INTO terms VALUES ('trackback');
+
+SELECT * FROM terms WHERE content LIKE 'TRACK%';
+
+DROP TABLE terms;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/lock_tables_read.test b/storage/mroonga/mysql-test/mroonga/storage/t/lock_tables_read.test
new file mode 100644
index 00000000..2ce2ae94
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/lock_tables_read.test
@@ -0,0 +1,32 @@
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS counts;
+--enable_warnings
+
+CREATE TABLE counts (
+ id INT PRIMARY KEY AUTO_INCREMENT
+);
+
+LOCK TABLES counts READ;
+UNLOCK TABLES;
+
+DROP TABLE counts;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_multithread.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_multithread.test
new file mode 100644
index 00000000..4857286a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_multithread.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT INDEX ft(title)
+);
+
+INSERT INTO diaries VALUES("Hello mroonga!");
+INSERT INTO diaries VALUES("It's funny.");
+
+disable_query_log;
+CONNECT (thread2, localhost, root, ,);
+CONNECTION thread2;
+enable_query_log;
+
+INSERT INTO diaries VALUES("Happy birthday!");
+
+disable_query_log;
+DISCONNECT thread2;
+CONNECTION default;
+enable_query_log;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+SELECT COUNT(*) FROM diaries WHERE MATCH(title) AGAINST("mroonga" IN BOOLEAN MODE);
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_single_thread.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_single_thread.test
new file mode 100644
index 00000000..d0116e7f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_after_insert_single_thread.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT INDEX ft(title)
+);
+
+INSERT INTO diaries VALUES("Hello mroonga!");
+INSERT INTO diaries VALUES("It's funny.");
+INSERT INTO diaries VALUES("Happy birthday!");
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+SELECT COUNT(*) FROM diaries WHERE MATCH(title) AGAINST("mroonga" IN BOOLEAN MODE);
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_disabled.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_disabled.test
new file mode 100644
index 00000000..d84112b4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_disabled.test
@@ -0,0 +1,50 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, "はれ", "天気がよいのは今日までみたい。");
+
+SET mroonga_enable_optimization=FALSE;
+
+SELECT COUNT(*) FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE);
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+SET mroonga_enable_optimization=TRUE;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_and.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_and.test
new file mode 100644
index 00000000..691497be
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_and.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT,
+ age INT,
+ INDEX (id, age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id, age) VALUES (1, 28);
+INSERT INTO users (id, age) VALUES (1, 28);
+INSERT INTO users (id, age) VALUES (1, 29);
+INSERT INTO users (id, age) VALUES (2, 29);
+INSERT INTO users (id, age) VALUES (2, 29);
+INSERT INTO users (id, age) VALUES (3, 29);
+
+SELECT COUNT(*) FROM users WHERE id = 2 AND age = 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_between.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_between.test
new file mode 100644
index 00000000..76675fde
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_between.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (32),(33),(34),(35),(36),(37);
+
+SELECT COUNT(*) FROM users WHERE age BETWEEN 28 AND 30;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_equal.test
new file mode 100644
index 00000000..b422e06e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_equal.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+
+SELECT COUNT(*) FROM users WHERE age = 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_boolean_mode.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_boolean_mode.test
new file mode 100644
index 00000000..b59ca7f5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_boolean_mode.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos (content) VALUES ('Groonga is good.');
+INSERT INTO memos (content) VALUES ('Groonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga is good.');
+INSERT INTO memos (content) VALUES ('Mroonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga uses Groonga.');
+
+SELECT COUNT(*) FROM memos
+ WHERE MATCH(content) AGAINST('+Groonga' IN BOOLEAN MODE);
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_natural_language_mode.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_natural_language_mode.test
new file mode 100644
index 00000000..c8de7b95
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_full_text_search_in_natural_language_mode.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE memos (
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO memos (content) VALUES ('Groonga is good.');
+INSERT INTO memos (content) VALUES ('Groonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga is good.');
+INSERT INTO memos (content) VALUES ('Mroonga is very good.');
+INSERT INTO memos (content) VALUES ('Mroonga uses Groonga.');
+
+SELECT COUNT(*) FROM memos
+ WHERE MATCH(content) AGAINST('Groonga');
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater.test
new file mode 100644
index 00000000..fb5c336c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (1),(2),(3),(4),(5),(6);
+
+SELECT COUNT(*) FROM users WHERE age > 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater_equal.test
new file mode 100644
index 00000000..c897d8d8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_greater_equal.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (1),(2),(3),(4),(5),(6);
+
+SELECT COUNT(*) FROM users WHERE age >= 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less.test
new file mode 100644
index 00000000..f03156d5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (32),(33),(34),(35),(36),(37);
+
+SELECT COUNT(*) FROM users WHERE age < 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less_equal.test
new file mode 100644
index 00000000..20863705
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_less_equal.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (27);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (30);
+INSERT INTO users (age) VALUES (31);
+INSERT INTO users (age) VALUES (32),(33),(34),(35),(36),(37);
+
+SELECT COUNT(*) FROM users WHERE age <= 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_not_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_not_equal.test
new file mode 100644
index 00000000..3948d218
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_not_equal.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (28);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+INSERT INTO users (age) VALUES (29);
+
+SELECT COUNT(*) FROM users WHERE age <> 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_view.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_view.test
new file mode 100644
index 00000000..85ee2d45
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_index_view.test
@@ -0,0 +1,56 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries, users;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ user_id INT NOT NULL,
+ title VARCHAR(45) NOT NULL,
+ KEY (user_id),
+ FULLTEXT INDEX title_index (title)
+) DEFAULT CHARSET=UTF8;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name VARCHAR(45) NOT NULL,
+ INDEX (name)
+) ENGINE=InnoDB DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id, name) VALUES (1, "Alice"), (2, "Bob");
+INSERT INTO diaries (user_id, title) VALUES (1, "survey");
+INSERT INTO diaries (user_id, title) VALUES (2, "groonga (1)");
+INSERT INTO diaries (user_id, title) VALUES (2, "groonga (2)");
+
+CREATE VIEW articles AS
+ SELECT diaries.user_id AS user_id,
+ diaries.title AS title,
+ users.name AS name
+ FROM diaries, users
+ WHERE diaries.user_id = users.id;
+
+
+SELECT COUNT(*) FROM articles WHERE name = 'Bob';
+
+DROP VIEW articles;
+DROP TABLE diaries, users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_multiple_conditions.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_multiple_conditions.test
new file mode 100644
index 00000000..917d6a1b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_multiple_conditions.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT,
+ age INT,
+ INDEX (age)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id, age) VALUES (1, 29);
+INSERT INTO users (id, age) VALUES (2, 29);
+INSERT INTO users (id, age) VALUES (3, 29);
+
+SELECT COUNT(*) FROM users WHERE id = 3 AND age = 29;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_between.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_between.test
new file mode 100644
index 00000000..25d6c734
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_between.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+INSERT INTO users (id) VALUES (32),(33),(34),(35),(36),(37);
+
+SELECT COUNT(*) FROM users WHERE id BETWEEN 2 AND 4;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_equal.test
new file mode 100644
index 00000000..c0db5729
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_equal.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+
+SELECT COUNT(*) FROM users WHERE id = 3;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater.test
new file mode 100644
index 00000000..f91cf193
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+INSERT INTO users (id) VALUES (-1),(-2),(-3),(-4);
+
+SELECT COUNT(*) FROM users WHERE id > 3;
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater_equal.test
new file mode 100644
index 00000000..dd374012
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_greater_equal.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+INSERT INTO users (id) VALUES (-1),(-2),(-3),(-4);
+
+SELECT COUNT(*) FROM users WHERE id >= 3;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less.test
new file mode 100644
index 00000000..529dfde6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+
+SELECT COUNT(*) FROM users WHERE id < 3;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less_equal.test
new file mode 100644
index 00000000..d2a863ae
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_less_equal.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+
+SELECT COUNT(*) FROM users WHERE id <= 3;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_not_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_not_equal.test
new file mode 100644
index 00000000..7e8c3180
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_count_skip_primary_key_not_equal.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE users (
+ id INT PRIMARY KEY
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO users (id) VALUES (1);
+INSERT INTO users (id) VALUES (2);
+INSERT INTO users (id) VALUES (3);
+INSERT INTO users (id) VALUES (4);
+INSERT INTO users (id) VALUES (5);
+
+SELECT COUNT(*) FROM users WHERE id <> 3;
+
+SHOW STATUS LIKE 'mroonga_count_skip';
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_disabled.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_disabled.test
new file mode 100644
index 00000000..c0dab283
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_disabled.test
@@ -0,0 +1,59 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SET mroonga_enable_optimization=FALSE;
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ month = 11
+ ORDER BY day LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+SET mroonga_enable_optimization=TRUE;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_multiple_match_againsts.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_multiple_match_againsts.test
new file mode 100644
index 00000000..ce1f6360
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_multiple_match_againsts.test
@@ -0,0 +1,57 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(title),
+ FULLTEXT INDEX(content)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(5, "title 1", "content a");
+INSERT INTO memos VALUES(12, "title 1", "content a");
+INSERT INTO memos VALUES(10, "title 1", "content a");
+INSERT INTO memos VALUES(4, "title 2", "content b");
+INSERT INTO memos VALUES(6, "title 2", "content b");
+INSERT INTO memos VALUES(1, "title 2", "content b");
+INSERT INTO memos VALUES(11, "title 1-a", "content a-1");
+INSERT INTO memos VALUES(3, "title 2-b", "content a-2");
+INSERT INTO memos VALUES(2, "title 2-c", "content a-3");
+INSERT INTO memos VALUES(8, "title 1-a", "content b-1");
+INSERT INTO memos VALUES(9, "title 2-b", "content b-2");
+INSERT INTO memos VALUES(7, "title 2-c", "content b-3");
+
+SELECT * FROM memos
+ WHERE MATCH(title) AGAINST("+1" IN BOOLEAN MODE) AND
+ MATCH(content) AGAINST("+a" IN BOOLEAN MODE)
+ ORDER BY id
+ LIMIT 1,3;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_no_limit.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_no_limit.test
new file mode 100644
index 00000000..99abc046
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_not_optimized_no_limit.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ ORDER BY day;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_cp932.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_cp932.test
new file mode 100644
index 00000000..19c2bc40
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_cp932.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES CP932;
+CREATE TABLE memos (
+ ʎq INT UNSIGNED,
+ e TEXT,
+ FULLTEXT INDEX(e),
+ KEY(ʎq)
+) DEFAULT CHARSET CP932;
+
+INSERT INTO memos VALUES(2, "͎RoB");
+INSERT INTO memos VALUES(3, "̓T{eB");
+INSERT INTO memos VALUES(1, "͓VC悭Ă悩B");
+
+SELECT * FROM memos
+ WHERE MATCH(e) AGAINST("" IN BOOLEAN MODE)
+ ORDER BY ʎq
+ LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between.test
new file mode 100644
index 00000000..9ad4a696
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date BETWEEN "2011-11-11 12:23:31" AND "2011-11-11 12:23:33"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between_over.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between_over.test
new file mode 100644
index 00000000..170e9796
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_between_over.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date BETWEEN "2011-11-11 12:23:31" AND "2011-11-11 12:23:43"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_equal.test
new file mode 100644
index 00000000..32555b2a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_equal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:34", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:34", "Tomorrow will be fine.");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:34", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:34", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date = "2011-11-11 12:23:34"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than.test
new file mode 100644
index 00000000..9c4c8754
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date > "2011-11-11 12:23:31"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than_or_equal.test
new file mode 100644
index 00000000..375080ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_greater_than_or_equal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date >= "2011-11-11 12:23:31"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than.test
new file mode 100644
index 00000000..cdd4a2ba
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date < "2011-11-11 12:23:33"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than_or_equal.test
new file mode 100644
index 00000000..b0af56e0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_datetime_less_than_or_equal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ date DATETIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(date)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, "2011-11-11 12:23:30", "Today is fine.");
+INSERT INTO diaries VALUES(2, "2011-11-11 12:23:31", "Today's lucky item is flower!");
+INSERT INTO diaries VALUES(3, "2011-11-11 12:23:32", "I will do something today!");
+INSERT INTO diaries VALUES(4, "2011-11-11 12:23:33", "I don't want to anything today...");
+INSERT INTO diaries VALUES(5, "2011-11-11 12:23:34", "I'm sleepy today.");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ date <= "2011-11-11 12:23:33"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_duplicated_order_by_columns.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_duplicated_order_by_columns.test
new file mode 100644
index 00000000..e9d1ca29
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_duplicated_order_by_columns.test
@@ -0,0 +1,45 @@
+# Copyright(C) 2015 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2015 GMO Media, Inc.
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES utf8mb4;
+
+CREATE TABLE ids (
+ id int PRIMARY KEY,
+ text varchar(32),
+ FULLTEXT INDEX (text)
+) DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO ids VALUES (1, 'first');
+
+SELECT * FROM ids
+ WHERE MATCH(text) AGAINST('+first' IN BOOLEAN MODE)
+ ORDER BY id, id
+ LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_name.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_name.test
new file mode 100644
index 00000000..3a4f4faa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_name.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id int PRIMARY KEY,
+ tag ENUM('Groonga', 'Mroonga'),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(tag),
+ KEY(id)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES(1, 'Groonga', 'Groonga is great!');
+INSERT INTO memos VALUES(2, 'Mroonga', 'Mroonga is great!');
+INSERT INTO memos VALUES(3, 'Mroonga', 'Mroonga is a MySQL storage engine.');
+INSERT INTO memos VALUES(4, 'Mroonga', 'Mroonga is based on Groonga.');
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("+Groonga" IN BOOLEAN MODE) AND
+ tag = 'Mroonga'
+ ORDER BY id LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_value.test
new file mode 100644
index 00000000..b8126b3f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_enum_value.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id int PRIMARY KEY,
+ tag ENUM('Groonga', 'Mroonga'),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(tag),
+ KEY(id)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO memos VALUES(1, 'Groonga', 'Groonga is great!');
+INSERT INTO memos VALUES(2, 'Mroonga', 'Mroonga is great!');
+INSERT INTO memos VALUES(3, 'Mroonga', 'Mroonga is a MySQL storage engine.');
+INSERT INTO memos VALUES(4, 'Mroonga', 'Mroonga is based on Groonga.');
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("+Groonga" IN BOOLEAN MODE) AND
+ tag = 2
+ ORDER BY id LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_have_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_have_primary_key.test
new file mode 100644
index 00000000..64f5a605
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_have_primary_key.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 11, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(6, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("今日 天気" IN BOOLEAN MODE) ORDER BY day LIMIT 0,5;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between.test
new file mode 100644
index 00000000..2fa838ea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(id)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "Today is fine.");
+INSERT INTO memos VALUES(2, "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "I will do something today!");
+INSERT INTO memos VALUES(4, "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ id BETWEEN 2 AND 4
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between_over.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between_over.test
new file mode 100644
index 00000000..5981c99f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_between_over.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(id)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "Today is fine.");
+INSERT INTO memos VALUES(2, "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "I will do something today!");
+INSERT INTO memos VALUES(4, "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ id BETWEEN 2 AND 6
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_equal.test
new file mode 100644
index 00000000..f2158a82
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_equal.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ month = 11
+ ORDER BY day LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than.test
new file mode 100644
index 00000000..856c9f71
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ day > 10
+ ORDER BY day LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than_or_equal.test
new file mode 100644
index 00000000..6115bf68
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_greater_than_or_equal.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ day >= 10
+ ORDER BY day LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than.test
new file mode 100644
index 00000000..f5001bdf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ day < 12
+ ORDER BY day LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than_or_equal.test
new file mode 100644
index 00000000..790e8f14
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_int_less_than_or_equal.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ day <= 12
+ ORDER BY day LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_primary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_primary_key.test
new file mode 100644
index 00000000..2aad7f0f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_primary_key.test
@@ -0,0 +1,50 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 11, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(6, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("今日 天気" IN BOOLEAN MODE) ORDER BY day LIMIT 0,5;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_where_clause.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_where_clause.test
new file mode 100644
index 00000000..72889f96
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_no_where_clause.test
@@ -0,0 +1,39 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+flush status;
+create table t1 (c1 int primary key, c2 int, c3 text, _id int, key idx1(c2), fulltext index ft(c3)) default charset utf8;
+insert into t1 values(1,10,"aa ii uu ee oo",null);
+insert into t1 values(2,20,"ka ki ku ke ko",null);
+insert into t1 values(3,30,"ii si ii se ii",null);
+insert into t1 values(4,40,"ta ti tu te to",null);
+insert into t1 values(5,50,"aa ii uu ii oo",null);
+
+show status like 'mroonga_fast_order_limit';
+
+select *, match(c3) against("ii") from t1 order by c1 desc limit 2;
+
+show status like 'mroonga_fast_order_limit';
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_asc.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_asc.test
new file mode 100644
index 00000000..c58d7353
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_asc.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ ORDER BY day ASC LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_desc.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_desc.test
new file mode 100644
index 00000000..a979e88c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_desc.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ ORDER BY day DESC LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_id.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_id.test
new file mode 100644
index 00000000..6bf3c6a8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_id.test
@@ -0,0 +1,56 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ _id INT,
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(NULL, 1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(NULL, 2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(NULL, 3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(NULL, 4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(NULL, 5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(NULL, 6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(NULL, 7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ ORDER BY _id
+ LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_match_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_match_against.test
new file mode 100644
index 00000000..bd86c6a2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_order_by_match_against.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ ORDER BY MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_select_match_against.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_select_match_against.test
new file mode 100644
index 00000000..52720370
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_select_match_against.test
@@ -0,0 +1,56 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT *, MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ ORDER BY MATCH(content) AGAINST("今日" IN BOOLEAN MODE)
+ LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between.test
new file mode 100644
index 00000000..23bb7103
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time BETWEEN "1:23:31" AND "1:23:33"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between_over.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between_over.test
new file mode 100644
index 00000000..2450f8a2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_between_over.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time BETWEEN "1:23:31" AND "1:23:43"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_equal.test
new file mode 100644
index 00000000..46dc7cb5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_equal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:34", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:34", "Tomorrow will be fine.");
+INSERT INTO memos VALUES(3, "1:23:34", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:34", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time = "1:23:34"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than.test
new file mode 100644
index 00000000..62acda78
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!" );
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time > "1:23:31"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than_or_equal.test
new file mode 100644
index 00000000..ee706c5f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_greater_than_or_equal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!" );
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time >= "1:23:31"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than.test
new file mode 100644
index 00000000..01764064
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time < "1:23:33"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than_or_equal.test
new file mode 100644
index 00000000..51423125
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_time_less_than_or_equal.test
@@ -0,0 +1,49 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE memos (
+ id INT UNSIGNED NOT NULL,
+ writing_time TIME,
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(writing_time)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO memos VALUES(1, "1:23:30", "Today is fine.");
+INSERT INTO memos VALUES(2, "1:23:31", "Today's lucky item is flower!");
+INSERT INTO memos VALUES(3, "1:23:32", "I will do something today!");
+INSERT INTO memos VALUES(4, "1:23:33", "I don't want to anything today...");
+INSERT INTO memos VALUES(5, "1:23:34", "I'm sleepy today.");
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST("today" IN BOOLEAN MODE) AND
+ writing_time <= "1:23:33"
+ ORDER BY id LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_with_index.test
new file mode 100644
index 00000000..c3456c25
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_with_index.test
@@ -0,0 +1,56 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(title),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ title = "hello"
+ ORDER BY day LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_without_index.test
new file mode 100644
index 00000000..2ce06201
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_varchar_equal_without_index.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+FLUSH STATUS;
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(month),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+INSERT INTO diaries VALUES(4, 2011, 11, 12, "帰り道", "今日は天気がよくてよかった。");
+INSERT INTO diaries VALUES(5, 2011, 11, 13, "はれ", "天気がよいのは今日までみたい。");
+INSERT INTO diaries VALUES(6, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(7, 2011, 12, 2, "初雪", "今日の天気は雪!");
+
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("今日" IN BOOLEAN MODE) AND
+ title = "hello"
+ ORDER BY day LIMIT 1;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between.test
new file mode 100644
index 00000000..c07368fb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year BETWEEN "11" AND "2013" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id DESC LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between_over.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between_over.test
new file mode 100644
index 00000000..599cc8fa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_between_over.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year BETWEEN "11" AND "2015" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id DESC LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_equal.test
new file mode 100644
index 00000000..35ce6066
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_equal.test
@@ -0,0 +1,55 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine (code name Mroonga) 1.0 has been released", "11");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 1.11 has been released", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year = "11" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id DESC LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than.test
new file mode 100644
index 00000000..88bb6a27
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year > "11" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id ASC LIMIT 2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than_or_equal.test
new file mode 100644
index 00000000..64b9f831
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_greater_than_or_equal.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year >= "11" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id ASC LIMIT 2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than.test
new file mode 100644
index 00000000..5f3f89fe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year < "13" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id DESC LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than_or_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than_or_equal.test
new file mode 100644
index 00000000..5db8d96e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/optimization_order_limit_optimized_year_less_than_or_equal.test
@@ -0,0 +1,53 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS mroonga_releases;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE mroonga_releases (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ release_title TEXT,
+ release_year YEAR,
+ KEY (release_year),
+ FULLTEXT KEY (release_title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Groonga storage engine (code name Mroonga) 0.1 has been released", "10");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Rename Groonga storage engine to Mroonga", "2011");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 2.0 has been released", "2012");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 3.0 has been released", "13");
+INSERT INTO mroonga_releases (release_title, release_year)
+ VALUES ("Mroonga 4.0 will be released", "2014");
+
+SELECT * FROM mroonga_releases
+ WHERE release_year <= "13" AND
+ MATCH(release_title) AGAINST("Mroonga" IN BOOLEAN MODE)
+ ORDER BY id DESC LIMIT 1,2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE mroonga_releases;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/partition_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/partition_insert.test
new file mode 100644
index 00000000..c60a6664
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/partition_insert.test
@@ -0,0 +1,52 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/skip_mariadb_10_0_or_later.inc
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source include/have_partition.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs (
+ timestamp DATETIME,
+ message TEXT
+) DEFAULT CHARSET=UTF8
+ PARTITION BY RANGE (TO_DAYS(timestamp)) (
+ PARTITION p201501 VALUES LESS THAN (TO_DAYS('2015-02-01')),
+ PARTITION p201502 VALUES LESS THAN (TO_DAYS('2015-03-01')),
+ PARTITION p201503 VALUES LESS THAN (TO_DAYS('2015-04-01')),
+ PARTITION pfuture VALUES LESS THAN MAXVALUE
+);
+SHOW CREATE TABLE logs;
+
+INSERT INTO logs VALUES('2015-01-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-01-31 23:59:59', 'Shutdown');
+INSERT INTO logs VALUES('2015-02-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-02-28 23:59:59', 'Shutdown');
+INSERT INTO logs VALUES('2015-03-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-03-31 23:59:59', 'Shutdown');
+INSERT INTO logs VALUES('2015-04-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-04-30 23:59:59', 'Shutdown');
+
+SELECT * FROM logs ORDER BY timestamp;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/partition_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/partition_update.test
new file mode 100644
index 00000000..0620de86
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/partition_update.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/skip_mariadb_10_0_or_later.inc
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source include/have_partition.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE logs (
+ timestamp DATETIME,
+ message TEXT
+) DEFAULT CHARSET=UTF8
+ PARTITION BY RANGE (TO_DAYS(timestamp)) (
+ PARTITION p201501 VALUES LESS THAN (TO_DAYS('2015-02-01')),
+ PARTITION p201502 VALUES LESS THAN (TO_DAYS('2015-03-01')),
+ PARTITION p201503 VALUES LESS THAN (TO_DAYS('2015-04-01')),
+ PARTITION pfuture VALUES LESS THAN MAXVALUE
+);
+SHOW CREATE TABLE logs;
+
+INSERT INTO logs VALUES('2015-01-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-02-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-03-01 00:00:00', 'Start');
+INSERT INTO logs VALUES('2015-04-01 00:00:00', 'Start');
+
+SELECT * FROM logs ORDER BY timestamp;
+
+UPDATE logs
+ SET message = 'Started'
+ WHERE timestamp < '2015-03-01 00:00:00';
+
+SELECT * FROM logs ORDER BY timestamp;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test b/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test
new file mode 100644
index 00000000..0f04bd3e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/repair_table_no_index_file.test
@@ -0,0 +1,57 @@
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/skip_solaris.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+CREATE DATABASE repair_test;
+USE repair_test;
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start Groonga!");
+INSERT INTO diaries (title, body) VALUES ("Groonga (1)", "starting Groonga...");
+INSERT INTO diaries (title, body) VALUES ("Groonga (2)", "started Groonga.");
+
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE);
+
+--remove_file $MYSQLD_DATADIR/repair_test.mrn.000010E.c
+
+FLUSH TABLES;
+
+# Error ER_CANT_OPEN_FILE system call error: No such file or directory: failed to open path: <repair_test.mrn.000010E.c>
+--error ER_CANT_OPEN_FILE
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE);
+
+REPAIR TABLE diaries;
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("+starting" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+DROP DATABASE repair_test;
+USE test;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/replace_geometry.test b/storage/mroonga/mysql-test/mroonga/storage/t/replace_geometry.test
new file mode 100644
index 00000000..854a93a2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/replace_geometry.test
@@ -0,0 +1,41 @@
+# 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-1335 USA
+
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS geo_replace;
+--enable_warnings
+
+CREATE TABLE geo_replace (
+ id INT NOT NULL,
+ geo GEOMETRY NOT NULL,
+ PRIMARY KEY(id)
+) DEFAULT CHARSET=utf8;
+INSERT INTO geo_replace VALUES(1, POINT(100,100));
+SELECT id, ST_AsText(geo) FROM geo_replace;
+REPLACE INTO geo_replace VALUES(1, POINT(100,200));
+SELECT id, ST_AsText(geo) FROM geo_replace;
+INSERT INTO geo_replace VALUES(1, POINT(200,200)) ON DUPLICATE KEY UPDATE geo = POINT(200,200);
+SELECT id, ST_AsText(geo) FROM geo_replace;
+UPDATE geo_replace SET geo = POINT(200,300);
+SELECT id, ST_AsText(geo) FROM geo_replace;
+
+DROP TABLE geo_replace;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/replace_select_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/replace_select_varchar.test
new file mode 100644
index 00000000..80b56639
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/replace_select_varchar.test
@@ -0,0 +1,65 @@
+# Copyright(C) 2011 Kouhei Sutou
+#
+# 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-1335 USA
+
+# Based on #910.
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS videos_master, videos_groonga;
+--enable_warnings
+
+CREATE TABLE `videos_master` (
+ `id` bigint(1) unsigned NOT NULL,
+ `video_id` varchar(64) NOT NULL,
+ `description` text,
+ `tags_unpack` text,
+ PRIMARY KEY (`video_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+CREATE TABLE `videos_groonga` (
+ `id` bigint(1) unsigned NOT NULL,
+ `video_id` varchar(64) NOT NULL,
+ `description` text,
+ `tags_unpack` text,
+ PRIMARY KEY (`video_id`),
+ FULLTEXT INDEX (`description`),
+ FULLTEXT INDEX (`tags_unpack`)
+) DEFAULT CHARSET=utf8;
+
+
+INSERT INTO videos_master VALUES (1, "video-1", "My Familly", "familly human");
+INSERT INTO videos_master VALUES (2, "video-2", "My Cat", "family cat");
+REPLACE INTO videos_groonga
+ SELECT v.id, v.video_id, v.description, NULL
+ FROM videos_master AS v
+ WHERE v.video_id = (video_id);
+SELECT *, MATCH(description) AGAINST("cat") FROM videos_groonga
+ WHERE MATCH(description) AGAINST("cat");
+
+INSERT INTO videos_master VALUES (3, "video-3", "My Dog", "family dog");
+REPLACE INTO videos_groonga
+ SELECT v.id, v.video_id, v.description, NULL
+ FROM videos_master AS v
+ WHERE v.video_id = (video_id);
+SELECT *, MATCH(description) AGAINST("my") FROM videos_groonga
+ WHERE MATCH(description) AGAINST("my")
+ ORDER BY id;
+
+DROP TABLE videos_master, videos_groonga;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/replace_text.test b/storage/mroonga/mysql-test/mroonga/storage/t/replace_text.test
new file mode 100644
index 00000000..add74ad7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/replace_text.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ content text,
+ fulltext index (content)
+) default charset utf8;
+
+insert into diaries values(1, "今日からはじめました。");
+insert into diaries values(2, "明日の富士山の天気について");
+insert into diaries values(3, "今日も天気がよくてきれいに見える。");
+
+select * from diaries;
+
+select * from diaries where match(content) against("天気");
+
+replace into diaries values(2, "明日の天気は雨みたい。");
+select * from diaries where match(content) against("天気");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/replace_varchar.test b/storage/mroonga/mysql-test/mroonga/storage/t/replace_varchar.test
new file mode 100644
index 00000000..ef4739f1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/replace_varchar.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ content varchar(256),
+ fulltext index (content)
+) default charset utf8;
+
+insert into diaries values(1, "今日からはじめました。");
+insert into diaries values(2, "明日の富士山の天気について");
+insert into diaries values(3, "今日も天気がよくてきれいに見える。");
+
+select * from diaries;
+
+select * from diaries where match(content) against("天気");
+
+replace into diaries values(2, "明日の天気は雨みたい。");
+select * from diaries where match(content) against("天気");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/replace_vector.test b/storage/mroonga/mysql-test/mroonga/storage/t/replace_vector.test
new file mode 100644
index 00000000..72d233bc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/replace_vector.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS vector_replace;
+DROP TABLE IF EXISTS vector_replace_vec;
+--enable_warnings
+
+CREATE TABLE vector_replace_vec (
+ vec CHAR(10) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE vector_replace (
+ id INT NOT NULL,
+ vec TEXT COMMENT 'flags "COLUMN_VECTOR", type "vector_replace_vec"',
+ PRIMARY KEY(id)
+) DEFAULT CHARSET=utf8;
+INSERT INTO vector_replace VALUES(1, 'first second third');
+SELECT id, vec FROM vector_replace;
+REPLACE INTO vector_replace VALUES(1, 'fourth fifth');
+SELECT id, vec FROM vector_replace;
+INSERT INTO vector_replace VALUES(1, 'sixth seventh') ON DUPLICATE KEY UPDATE vec = 'sixth seventh';
+SELECT id, vec FROM vector_replace;
+UPDATE vector_replace SET vec = 'eighth nineth tenth';
+SELECT id, vec FROM vector_replace;
+
+DROP TABLE vector_replace;
+DROP TABLE vector_replace_vec;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/replace_without_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/replace_without_key.test
new file mode 100644
index 00000000..4e408522
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/replace_without_key.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id varchar(32) NOT NULL PRIMARY KEY,
+ content text,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8;
+
+-- error ER_ERROR_ON_WRITE, ER_NO_DEFAULT_FOR_FIELD
+REPLACE INTO diaries(content) VALUES("Hello");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_all.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_all.test
new file mode 100644
index 00000000..47f6e65c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_all.test
@@ -0,0 +1,100 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1(c1 int, c2 int, c3 int);
+insert into t1 values (1, 10, 100);
+insert into t1 values (2, 30, 500);
+insert into t1 values (5, 20, 200);
+insert into t1 values (3, 60, 300);
+insert into t1 values (4, 50, 600);
+insert into t1 values (6, 40, 400);
+
+select * from t1;
+select c1 from t1;
+select c2 from t1;
+select c3 from t1;
+
+select * from t1 where c1 <= 3;
+select * from t1 where c2 > 40;
+select * from t1 where c3 = 300;
+
+
+select * from t1 order by c1;
+select * from t1 order by c2 desc;
+select * from t1 order by c3, c1;
+
+drop table t1;
+
+
+create table t1 (c1 int, c2 varchar(100));
+insert into t1 values(1, "hoge");
+insert into t1 values(4, "hogefuga");
+insert into t1 values(2, "fuga");
+insert into t1 values(5, "moge");
+insert into t1 values(3, "mo");
+
+select * from t1;
+select * from t1 order by c1;
+select * from t1 order by c1 desc;
+select * from t1 order by c2;
+
+drop table t1;
+
+create table t1 (c1 int, c2 text);
+insert into t1 values(1, "hoge");
+insert into t1 values(4, "hogefuga");
+insert into t1 values(2, "fuga");
+insert into t1 values(5, "moge");
+insert into t1 values(3, "mo");
+
+select * from t1;
+
+drop table t1;
+
+# ORDER BY with position
+create table t1 (c1 int, c2 int, c3 text);
+insert into t1 values(1, 20, "hoge");
+insert into t1 values(4, 60, "hogefuga");
+insert into t1 values(2, 50, "fuga");
+insert into t1 values(5, 30, "moge");
+insert into t1 values(3, 40, "mo");
+select * from t1 order by c1 asc;
+select * from t1 order by c1 desc;
+select * from t1 order by c2 asc;
+select * from t1 order by c2 desc;
+select * from t1 order by c3 asc;
+select * from t1 order by c3 desc;
+drop table t1;
+
+# _id
+create table t1 (_id int, c1 int);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+insert into t1 values (null,100);
+select * from t1;
+select * from t1 where _id < 3;
+select * from t1 where _id >= 3;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_equal.test
new file mode 100644
index 00000000..686a9aa2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_equal.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(16) NOT NULL,
+ KEY index_name (name)
+);
+
+INSERT INTO tags VALUES ('mroonga');
+INSERT INTO tags VALUES ('mysql');
+INSERT INTO tags VALUES ('');
+
+SELECT * FROM tags WHERE name = "";
+
+DROP TABLE tags;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_not_equal.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_not_equal.test
new file mode 100644
index 00000000..2c40b00e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_empty_key_where_not_equal.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2014 Kenji Maruyama <mmmaru777@gmail.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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS tags;
+--enable_warnings
+
+CREATE TABLE tags (
+ name VARCHAR(16) NOT NULL,
+ KEY index_name (name)
+);
+
+INSERT INTO tags VALUES ('mroonga');
+INSERT INTO tags VALUES ('mysql');
+INSERT INTO tags VALUES ('');
+
+SELECT * FROM tags WHERE name != "";
+
+DROP TABLE tags;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_with_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_with_index.test
new file mode 100644
index 00000000..1d8e84a9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_with_index.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE users (
+ name varchar(40),
+ age int,
+ KEY (age)
+);
+
+INSERT INTO users VALUES ("Alice", 20);
+INSERT INTO users VALUES ("Bob", 20);
+INSERT INTO users VALUES ("Charry", 29);
+
+SELECT age, COUNT(*) FROM users GROUP BY age;
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_without_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_without_index.test
new file mode 100644
index 00000000..5d695d6b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_group_by_without_index.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE users (
+ name varchar(40),
+ age int
+);
+
+INSERT INTO users VALUES ("Alice", 20);
+INSERT INTO users VALUES ("Bob", 20);
+INSERT INTO users VALUES ("Charry", 29);
+
+SELECT age, COUNT(*) FROM users GROUP BY age;
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_pkey.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_pkey.test
new file mode 100644
index 00000000..8bfecaf7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_pkey.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1(c1 int primary key, c2 int, c3 int);
+insert into t1 values (1, 10, 100);
+insert into t1 values (2, 30, 500);
+insert into t1 values (5, 20, 200);
+insert into t1 values (3, 60, 300);
+insert into t1 values (4, 50, 600);
+insert into t1 values (6, 40, 400);
+
+select * from t1 where c1=1;
+select * from t1 where c1=2;
+select * from t1 where c1=3;
+select * from t1 where c1=4;
+select * from t1 where c1=5;
+select * from t1 where c1=6;
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/select_secondary_key.test b/storage/mroonga/mysql-test/mroonga/storage/t/select_secondary_key.test
new file mode 100644
index 00000000..838c01e4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/select_secondary_key.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2010 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, c3 text, key idx1(c2), fulltext index ft(c3));
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+
+select * from t1;
+select * from t1 force index(idx1) where c2 = 30;
+select * from t1 force index(idx1) where c2 = 20;
+
+insert into t1 values(6,30,"aa bb cc dd ee");
+select * from t1;
+select * from t1 force index(idx1) where c2 = 30;
+
+drop table t1;
+
+create table t1 (c1 varchar(5) primary key, c2 varchar(5), c3 text, key idx1(c2), fulltext index ft(c3))engine=mroonga;
+insert into t1 values('ab','ijk',"aa ii uu ee oo");
+insert into t1 values('bc','ghi',"ka ki ku ke ko");
+insert into t1 values('cd','efg',"sa si su se so");
+insert into t1 values('de','cde',"ta ti tu te to");
+insert into t1 values('ef','abc',"aa ii uu ee oo");
+select * from t1 force index(idx1) where c2 < 'e' order by c1 asc;
+select * from t1 force index(idx1) where c2 > 'e' order by c1 asc;
+select * from t1 force index(idx1) where c2 between 'c' and 'h' order by c1 asc;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/show_create_table_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/show_create_table_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..81004f9b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/show_create_table_TODO_SPLIT_ME.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int);
+show create table t1;
+drop table t1;
+
+create table t1 (c1 int, c2 int);
+show create table t1;
+drop table t1;
+
+create table t1 (c1 int primary key, c2 varchar(100));
+show create table t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/sub_query_fulltext.test b/storage/mroonga/mysql-test/mroonga/storage/t/sub_query_fulltext.test
new file mode 100644
index 00000000..819a27c1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/sub_query_fulltext.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries, users;
+--enable_warnings
+
+CREATE TABLE users (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name TEXT
+) DEFAULT CHARSET UTF8;
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ user_id INT UNSIGNED NOT NULL,
+ title TEXT,
+ FULLTEXT INDEX (title)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO users (name) VALUES ("alice");
+INSERT INTO users (name) VALUES ("bob");
+INSERT INTO users (name) VALUES ("carlos");
+
+SELECT * FROM users;
+
+INSERT INTO diaries (user_id, title) VALUES (1, "Hello!");
+INSERT INTO diaries (user_id, title) VALUES (2, "my name is bob");
+INSERT INTO diaries (user_id, title) VALUES (3, "my name is carlos");
+
+SELECT * FROM diaries;
+
+SELECT * FROM users
+ WHERE id IN (SELECT user_id FROM diaries
+ WHERE MATCH(title) AGAINST("name"))
+ ORDER BY id DESC;
+
+DROP TABLE diaries, users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/temporary_table.test b/storage/mroonga/mysql-test/mroonga/storage/t/temporary_table.test
new file mode 100644
index 00000000..14aa7f26
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/temporary_table.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Toshihisa Tashiro
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/skip_osx.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TEMPORARY TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TEMPORARY TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (title) VALUES ("clear day");
+INSERT INTO diaries (title) VALUES ("rainy day");
+INSERT INTO diaries (title) VALUES ("cloudy day");
+
+SELECT * FROM diaries;
+
+DROP TEMPORARY TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/truncate.test b/storage/mroonga/mysql-test/mroonga/storage/t/truncate.test
new file mode 100644
index 00000000..12adecb6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/truncate.test
@@ -0,0 +1,61 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(day)
+) DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ ORDER BY id;
+TRUNCATE TABLE diaries;
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ ORDER BY id;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 11, "帰り道", "つかれたー");
+INSERT INTO diaries VALUES(2, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(3, 2011, 12, 2, "初雪", "今年はじめての雪!");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("+悪い" IN BOOLEAN MODE)
+ ORDER BY id;
+
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_binlog_row.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_binlog_row.test
new file mode 100644
index 00000000..c97b0e4e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_binlog_row.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET SESSION binlog_format = 'ROW';
+
+CREATE TABLE memos (
+ title varchar(20) PRIMARY KEY,
+ content varchar(140) NOT NULL
+) COLLATE=utf8mb4_general_ci
+ DEFAULT CHARSET=utf8mb4;
+
+INSERT INTO memos (title, content) VALUES ('Mroonga', 'Mroonga is great!');
+SELECT * FROM memos;
+UPDATE memos SET content = 'Mroonga is very great!' WHERE title = 'Mroonga';
+SELECT * FROM memos;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_fulltext.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_fulltext.test
new file mode 100644
index 00000000..73e57dac
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_fulltext.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 text, fulltext index (c2));
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+
+select * from t1;
+update t1 set c2="ta ti tu te" where c1=20;
+select * from t1;
+select * from t1 where match(c2) against("ti");
+select * from t1 where match(c2) against("ki");
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_id_hash_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_id_hash_index.test
new file mode 100644
index 00000000..bd1d4537
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_id_hash_index.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, c1 int, key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+update t1 set c1 = 200 where _id = 2;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_id_unique_hash_index.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_id_unique_hash_index.test
new file mode 100644
index 00000000..3e05cd49
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_id_unique_hash_index.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (_id int, c1 int, unique key (_id) using hash);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+insert into t1 values(null, 100);
+select * from t1;
+update t1 set c1 = 200 where _id = 2;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_int.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_int.test
new file mode 100644
index 00000000..02151964
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_int.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int, c2 int);
+show create table t1;
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+
+update t1 set c2=c2+100 where c1=1;
+select * from t1;
+update t1 set c2=c2+100 where c1=2;
+select * from t1;
+update t1 set c2=c2+100 where c1=3;
+select * from t1;
+
+flush tables;
+
+update t1 set c1=5, c2=50;
+select * from t1;
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_last_insert_grn_id.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_last_insert_grn_id.test
new file mode 100644
index 00000000..7496f7a0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_last_insert_grn_id.test
@@ -0,0 +1,48 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+drop table if exists memos;
+--enable_warnings
+
+create table memos (
+ _id int,
+ content varchar(255),
+ unique key (_id) using hash
+);
+
+insert into memos values (null, "今夜はさんま。");
+insert into memos values (null, "明日はgroongaをアップデート。");
+insert into memos values (null, "帰りにおだんご。");
+insert into memos values (null, "金曜日は肉の日。");
+
+select * from memos;
+
+insert into memos values (null, "冷蔵庫に牛乳が残り1本。");
+select last_insert_grn_id();
+update memos set content = "冷蔵庫に牛乳はまだたくさんある。" where _id = last_insert_grn_id();
+
+select * from memos;
+
+drop table memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/update_virtual_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/update_virtual_column.test
new file mode 100644
index 00000000..c0f2aece
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/update_virtual_column.test
@@ -0,0 +1,49 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+#
+# 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+# for virtual columns
+CREATE TABLE t1 (c1 int, _id int);
+INSERT INTO t1 VALUES(1,null);
+INSERT INTO t1 VALUES(2,null);
+INSERT INTO t1 VALUES(3,null);
+SELECT * FROM t1;
+--disable_warnings
+SET sql_mode="";
+--enable_warnings
+# warning WARN_DATA_TRUNCATED
+UPDATE t1 SET _id = 10 WHERE c1 = 1;
+SELECT * FROM t1;
+--disable_warnings
+SET sql_mode="STRICT_ALL_TABLES";
+--enable_warnings
+# We can't use WARN_DATA_TRUNCATED here because "WXXX" isn't supported
+# MySQL 5.5, 5.6 and MariaDB 5.6. MariaDB 10.0 only supports it.
+# We share this test with all MySQL servers. So we use number here.
+--error 1265
+UPDATE t1 SET _id = 11 WHERE c1 = 1;
+SELECT * FROM t1;
+DROP TABLE t1;
+
+SET sql_mode=DEFAULT;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_column.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_column.test
new file mode 100644
index 00000000..b84e955f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_column.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+# TODO: Remove the check after MariaDB 5.5.42 and MariaDB 10.0.17 are released.
+--source ../../include/mroonga/have_mysql.inc
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_boolean_mode_syntax_flags_backup =
+ @@mroonga_boolean_mode_syntax_flags;
+
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY,ALLOW_COLUMN";
+
+SET NAMES UTF8;
+
+CREATE TABLE diaries (
+ title TEXT,
+ content TEXT,
+ FULLTEXT KEY (title),
+ FULLTEXT KEY (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Groonga", "Hello Groonga");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("content:@Hello" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+SET mroonga_boolean_mode_syntax_flags =
+ @mroonga_boolean_mode_syntax_flags_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_leading_not.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_leading_not.test
new file mode 100644
index 00000000..bb9eb04b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_leading_not.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+# TODO: Remove the check after MariaDB 5.5.42 and MariaDB 10.0.17 are released.
+--source ../../include/mroonga/have_mysql.inc
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_boolean_mode_syntax_flags_backup =
+ @@mroonga_boolean_mode_syntax_flags;
+
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY,ALLOW_LEADING_NOT";
+
+SET NAMES UTF8;
+
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Groonga");
+INSERT INTO diaries VALUES("Mroonga");
+
+SELECT * FROM diaries WHERE MATCH(title) AGAINST("-Groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+SET mroonga_boolean_mode_syntax_flags =
+ @mroonga_boolean_mode_syntax_flags_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_update.test
new file mode 100644
index 00000000..940b4484
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_allow_update.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+# TODO: Remove the check after MariaDB 5.5.42 and MariaDB 10.0.17 are released.
+--source ../../include/mroonga/have_mysql.inc
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_boolean_mode_syntax_flags_backup =
+ @@mroonga_boolean_mode_syntax_flags;
+
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY,ALLOW_COLUMN,ALLOW_UPDATE";
+
+SET NAMES UTF8;
+
+CREATE TABLE diaries (
+ title TEXT,
+ content TEXT,
+ FULLTEXT KEY (title),
+ FULLTEXT KEY (content)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Groonga", "Hello Groonga");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST('content:="Hello Mroonga"' IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+SET mroonga_boolean_mode_syntax_flags =
+ @mroonga_boolean_mode_syntax_flags_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_query.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_query.test
new file mode 100644
index 00000000..0da5eed7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_query.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+# TODO: Remove the check after MariaDB 5.5.42 and MariaDB 10.0.17 are released.
+--source ../../include/mroonga/have_mysql.inc
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_boolean_mode_syntax_flags_backup =
+ @@mroonga_boolean_mode_syntax_flags;
+
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_QUERY";
+
+SET NAMES UTF8;
+
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Re:Mroonga");
+
+SELECT * FROM diaries WHERE MATCH(title) AGAINST("Re:Mroonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+SET mroonga_boolean_mode_syntax_flags =
+ @mroonga_boolean_mode_syntax_flags_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_script.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_script.test
new file mode 100644
index 00000000..3c73e214
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_boolean_mode_syntax_flags_syntax_script.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+# TODO: Remove the check after MariaDB 5.5.42 and MariaDB 10.0.17 are released.
+--source ../../include/mroonga/have_mysql.inc
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_boolean_mode_syntax_flags_backup =
+ @@mroonga_boolean_mode_syntax_flags;
+
+SET mroonga_boolean_mode_syntax_flags = "SYNTAX_SCRIPT";
+
+SET NAMES UTF8;
+
+CREATE TABLE diaries (
+ title TEXT,
+ FULLTEXT KEY (title)
+) DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES("Re:Mroonga");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("title @ 'Re:Mroonga'" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+SET mroonga_boolean_mode_syntax_flags =
+ @mroonga_boolean_mode_syntax_flags_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_database_path_prefix.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_database_path_prefix.test
new file mode 100644
index 00000000..9a3b5715
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_database_path_prefix.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2012-2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_database_path_prefix = "test/mroonga.data/";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_database_path_prefix';
+CREATE DATABASE clean_test;
+USE clean_test;
+
+CREATE TABLE counts (
+ id INT PRIMARY KEY AUTO_INCREMENT
+);
+
+--file_exists $MYSQLD_DATADIR/test/mroonga.data/clean_test.mrn
+
+INSERT INTO counts VALUES (NULL);
+
+SELECT * FROM counts;
+
+DROP TABLE counts;
+DROP DATABASE clean_test;
+SET GLOBAL mroonga_database_path_prefix = NULL;
+
+USE test;
+
+--rmdir $MYSQLD_DATADIR/test/mroonga.data
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_new_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_new_value.test
new file mode 100644
index 00000000..b3bc8815
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_new_value.test
@@ -0,0 +1,25 @@
+# Copyright(C) 2014 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_default_parser_backup = @@mroonga_default_parser;
+SET GLOBAL mroonga_default_parser = "TokenBigramSplitAlpha";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_parser';
+SET GLOBAL mroonga_default_parser = @mroonga_default_parser_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_same_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_same_value.test
new file mode 100644
index 00000000..46065e41
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_parser_same_value.test
@@ -0,0 +1,22 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_default_parser = "TokenBigram";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_parser';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_new_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_new_value.test
new file mode 100644
index 00000000..5aec9b4f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_new_value.test
@@ -0,0 +1,25 @@
+# Copyright(C) 2014 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_default_tokenizer_backup = @@mroonga_default_tokenizer;
+SET GLOBAL mroonga_default_tokenizer = "TokenBigramSplitAlpha";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_tokenizer';
+SET GLOBAL mroonga_default_tokenizer = @mroonga_default_tokenizer_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_same_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_same_value.test
new file mode 100644
index 00000000..f2ee331e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_default_tokenizer_same_value.test
@@ -0,0 +1,22 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_default_tokenizer = "TokenBigram";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_default_tokenizer';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_delete.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_delete.test
new file mode 100644
index 00000000..34929331
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_delete.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8;
+
+insert into diaries (body) values ("will start groonga!");
+select * from diaries;
+
+set mroonga_dry_write=true;
+delete from diaries where id = 1;
+select * from diaries;
+
+set mroonga_dry_write=false;
+delete from diaries where id = 1;
+select * from diaries;
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_insert.test
new file mode 100644
index 00000000..ece2a65d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_insert.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8;
+
+insert into diaries (body) values ("will start groonga!");
+select * from diaries;
+
+set mroonga_dry_write=true;
+insert into diaries (body) values ("starting groonga...");
+select * from diaries;
+
+set mroonga_dry_write=false;
+insert into diaries (body) values ("started groonga.");
+select * from diaries;
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_update.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_update.test
new file mode 100644
index 00000000..a9b3005f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_dry_write_update.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8;
+
+insert into diaries (body) values ("will start groonga!");
+
+set mroonga_dry_write=true;
+update diaries set body = "starting groonga..." where id = 1;
+select * from diaries;
+
+set mroonga_dry_write=false;
+update diaries set body = "starting groonga..." where id = 1;
+select * from diaries;
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_enable_operations_recording_insert.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_enable_operations_recording_insert.test
new file mode 100644
index 00000000..2a77a013
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_enable_operations_recording_insert.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ title TEXT
+) DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command('truncate mroonga_operations');
+INSERT INTO diaries VALUES("Unlogged: Research for Mroonga");
+SELECT mroonga_command('load --table mroonga_operations --values "[{}]"');
+SELECT mroonga_command('select mroonga_operations --output_columns _id');
+
+SET GLOBAL mroonga_enable_operations_recording = false;
+FLUSH TABLES;
+
+SELECT mroonga_command('truncate mroonga_operations');
+INSERT INTO diaries VALUES("Logged: Research for Mroonga");
+SELECT mroonga_command('load --table mroonga_operations --values "[{}]"');
+SELECT mroonga_command('select mroonga_operations --output_columns _id');
+
+DROP TABLE diaries;
+SELECT mroonga_command('truncate mroonga_operations');
+
+SET GLOBAL mroonga_enable_operations_recording = default;
+FLUSH TABLES;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_disable.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_disable.test
new file mode 100644
index 00000000..bf9387c8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_disable.test
@@ -0,0 +1,28 @@
+# Copyright(C) 2014-2017 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-1335 USA
+
+--source ../../include/mroonga/have_version_10_0_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_lock_timeout = -1;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+
+
+--disable_query_log
+SET GLOBAL mroonga_lock_timeout = DEFAULT;
+--enable_query_log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_invalid.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_invalid.test
new file mode 100644
index 00000000..1126628d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_invalid.test
@@ -0,0 +1,28 @@
+# Copyright(C) 2014-2017 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-1335 USA
+
+--source ../../include/mroonga/have_version_10_0_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_lock_timeout = -2;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+
+
+--disable_query_log
+SET GLOBAL mroonga_lock_timeout = DEFAULT;
+--enable_query_log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_no_retry.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_no_retry.test
new file mode 100644
index 00000000..aae419e6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_no_retry.test
@@ -0,0 +1,27 @@
+# Copyright(C) 2014-2017 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_lock_timeout = 0;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+
+
+--disable_query_log
+SET GLOBAL mroonga_lock_timeout = DEFAULT;
+--enable_query_log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_valid.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_valid.test
new file mode 100644
index 00000000..e8eb2952
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_lock_timeout_valid.test
@@ -0,0 +1,27 @@
+# Copyright(C) 2014-2017 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_lock_timeout = 1000;
+SHOW GLOBAL VARIABLES LIKE "mroonga_lock_timeout";
+
+
+--disable_query_log
+SET GLOBAL mroonga_lock_timeout = DEFAULT;
+--enable_query_log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_new_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_new_value.test
new file mode 100644
index 00000000..b17163c8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_new_value.test
@@ -0,0 +1,25 @@
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @mroonga_log_file_backup = @@mroonga_log_file;
+SET GLOBAL mroonga_log_file = "new-mroonga.log";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file';
+SET GLOBAL mroonga_log_file = @mroonga_log_file_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_nonexistent_path.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_nonexistent_path.test
new file mode 100644
index 00000000..40000b45
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_nonexistent_path.test
@@ -0,0 +1,22 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_log_file = "nonexistent/mroonga.log";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_same_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_same_value.test
new file mode 100644
index 00000000..8333ed4b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_file_same_value.test
@@ -0,0 +1,22 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+SET GLOBAL mroonga_log_file = "groonga.log";
+SHOW GLOBAL VARIABLES LIKE 'mroonga_log_file';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_level_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_level_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..72de94c5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_log_level_TODO_SPLIT_ME.test
@@ -0,0 +1,61 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2014 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+set @mroonga_log_level_backup=@@mroonga_log_level;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=NONE;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=EMERG;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=ALERT;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=CRIT;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=ERROR;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=WARNING;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=NOTICE;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=INFO;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=DEBUG;
+show global variables like 'mroonga_log_level';
+
+set global mroonga_log_level=DUMP;
+show global variables like 'mroonga_log_level';
+
+--error ER_WRONG_VALUE_FOR_VAR
+set global mroonga_log_level=dummy;
+
+--error ER_GLOBAL_VARIABLE
+set session mroonga_log_level=NOTICE;
+
+set global mroonga_log_level=@mroonga_log_level_backup;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_global.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_global.test
new file mode 100644
index 00000000..fe026a31
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_global.test
@@ -0,0 +1,61 @@
+# Copyright(C) 2012-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+# MySQL <= 5.5 reports a wrong warning. :<
+# It has been fixed in MySQL >= 5.6 and MariaDB >= 5.3.
+--disable_warnings
+SET GLOBAL mroonga_match_escalation_threshold = -1;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ tags TEXT,
+ FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (title, tags) VALUES ("Hello Groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello Mroonga!", "mroonga install");
+
+disable_query_log;
+CONNECT (new_connection, localhost, root, ,);
+CONNECTION new_connection;
+enable_query_log;
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+install" IN BOOLEAN MODE);
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+gr" IN BOOLEAN MODE);
+
+SET GLOBAL mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+gr" IN BOOLEAN MODE);
+
+SET mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("+gr" IN BOOLEAN MODE);
+
+disable_query_log;
+CONNECTION default;
+DISCONNECT new_connection;
+enable_query_log;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_session.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_session.test
new file mode 100644
index 00000000..24c5c484
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_match_escalation_threshold_session.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ tags TEXT,
+ FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO diaries (title, tags) VALUES ("Hello groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello mroonga!", "mroonga install");
+
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("install" IN BOOLEAN MODE);
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+# MySQL <= 5.5 reports wrong a warning. :<
+# It has been fixed in MySQL >= 5.6 and MariaDB >= 5.3.
+--disable_warnings
+SET mroonga_match_escalation_threshold = -1;
+--enable_warnings
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+SET mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_global.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_global.test
new file mode 100644
index 00000000..56117e2b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_global.test
@@ -0,0 +1,60 @@
+# Copyright(C) 2015-2016 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+
+
+SET GLOBAL mroonga_max_n_records_for_estimate = 1;
+
+disable_query_log;
+CONNECT (new_connection, localhost, root, ,);
+CONNECTION new_connection;
+enable_query_log;
+
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+
+disable_query_log;
+CONNECTION default;
+DISCONNECT new_connection;
+enable_query_log;
+
+SET GLOBAL mroonga_max_n_records_for_estimate = DEFAULT;
+
+
+DROP TABLE ids;
+
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.test
new file mode 100644
index 00000000..57e2a186
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_global.test
@@ -0,0 +1,60 @@
+# Copyright(C) 2015-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+
+
+SET GLOBAL mroonga_max_n_records_for_estimate = 1;
+
+disable_query_log;
+CONNECT (new_connection, localhost, root, ,);
+CONNECTION new_connection;
+enable_query_log;
+
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+
+disable_query_log;
+CONNECTION default;
+DISCONNECT new_connection;
+enable_query_log;
+
+SET GLOBAL mroonga_max_n_records_for_estimate = DEFAULT;
+
+
+DROP TABLE ids;
+
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.test
new file mode 100644
index 00000000..f0f548f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_not_found_in_limit.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT,
+ INDEX (id)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+
+DELETE FROM ids WHERE id < 2;
+
+SET mroonga_max_n_records_for_estimate = 1;
+
+EXPLAIN SELECT * FROM ids WHERE id > 0;
+
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.test
new file mode 100644
index 00000000..b25e01b7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_mysql_5_7_or_later_session.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+
+SET mroonga_max_n_records_for_estimate = 1;
+
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_not_found_in_limit.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_not_found_in_limit.test
new file mode 100644
index 00000000..79c75308
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_not_found_in_limit.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT,
+ INDEX (id)
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4),(5),(6),(7);
+
+DELETE FROM ids WHERE id < 2;
+
+SET mroonga_max_n_records_for_estimate = 1;
+
+EXPLAIN SELECT * FROM ids WHERE id > 0;
+
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_session.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_session.test
new file mode 100644
index 00000000..59af3e6a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_max_n_records_for_estimate_session.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2015-2016 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-1335 USA
+
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=UTF8;
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+INSERT INTO ids VALUES (4);
+INSERT INTO ids VALUES (5);
+INSERT INTO ids VALUES (6);
+INSERT INTO ids VALUES (7);
+INSERT INTO ids VALUES (8);
+INSERT INTO ids VALUES (9);
+INSERT INTO ids VALUES (10);
+
+SET mroonga_max_n_records_for_estimate = 1;
+
+EXPLAIN SELECT * FROM ids WHERE id > 5;
+
+SET mroonga_max_n_records_for_estimate = DEFAULT;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_empty_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_empty_value.test
new file mode 100644
index 00000000..57c62b2b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_empty_value.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+
+SET GLOBAL mroonga_query_log_file = "";
+--source ../../include/mroonga/print_groonga_query_log.inc
+
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/groonga-query-log.log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_null_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_null_value.test
new file mode 100644
index 00000000..97590b34
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_disabled_null_value.test
@@ -0,0 +1,31 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+
+SET GLOBAL mroonga_query_log_file = NULL;
+--source ../../include/mroonga/print_groonga_query_log.inc
+
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/groonga-query-log.log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_empty_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_empty_value.test
new file mode 100644
index 00000000..3021fe12
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_empty_value.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+
+SET GLOBAL mroonga_query_log_file = "";
+--source ../../include/mroonga/print_groonga_query_log.inc
+
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/groonga-query-log.log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_null_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_null_value.test
new file mode 100644
index 00000000..f233b7ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_enabled_null_value.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+
+SET GLOBAL mroonga_query_log_file = NULL;
+--source ../../include/mroonga/print_groonga_query_log.inc
+
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/groonga-query-log.log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_new_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_new_value.test
new file mode 100644
index 00000000..a98824cf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_new_value.test
@@ -0,0 +1,33 @@
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Kentoku SHIBA
+# Copyright(C) 2017 Kentaro Hayashi <hayashi@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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+--source ../../include/mroonga/print_groonga_query_log.inc
+
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/groonga-query-log.log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_same_value.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_same_value.test
new file mode 100644
index 00000000..faeb90ba
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_query_log_file_same_value.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2014-2017 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2017 Kentaro Hayashi <hayashi@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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+
+SET GLOBAL mroonga_log_file = "groonga-query-log.log";
+
+SET GLOBAL mroonga_query_log_file = "groonga-query.log";
+--source ../../include/mroonga/print_groonga_query_log.inc
+
+SET GLOBAL mroonga_query_log_file = DEFAULT;
+SET GLOBAL mroonga_log_file = DEFAULT;
+
+--remove_file $MYSQLD_DATADIR/groonga-query-log.log
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_vector_column_delimiter.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_vector_column_delimiter.test
new file mode 100644
index 00000000..94e8cb9b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_vector_column_delimiter.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS document;
+DROP TABLE IF EXISTS category;
+--enable_warnings
+
+CREATE TABLE category (
+ category CHAR(10) PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COMMENT='default_tokenizer "TokenDelimit"';
+
+CREATE TABLE document (
+ id INT NOT NULL,
+ title TEXT,
+ categories TEXT COMMENT 'flags "COLUMN_VECTOR", type "category"',
+ PRIMARY KEY(id)
+) DEFAULT CHARSET=utf8;
+
+SHOW GLOBAL VARIABLES LIKE 'mroonga_vector_column_delimiter';
+
+INSERT INTO document VALUES(1, "Mroonga is the fastest search engine", "it database fulltext");
+SELECT id, title, categories FROM document;
+
+SET GLOBAL mroonga_vector_column_delimiter = ';';
+
+SHOW GLOBAL VARIABLES LIKE 'mroonga_vector_column_delimiter';
+
+SELECT id, title, categories FROM document;
+
+DROP TABLE document;
+DROP TABLE category;
+
+SET GLOBAL mroonga_vector_column_delimiter = ' ';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/storage/t/variable_version.test b/storage/mroonga/mysql-test/mroonga/storage/t/variable_version.test
new file mode 100644
index 00000000..d9795eab
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/storage/t/variable_version.test
@@ -0,0 +1,22 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+# show variables like 'groonga%';
+show variables like 'mroonga_version';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/disabled.def b/storage/mroonga/mysql-test/mroonga/wrapper/disabled.def
new file mode 100644
index 00000000..f3f211b6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/disabled.def
@@ -0,0 +1,2 @@
+create_table_token_filters_index_comment_multiple_token_filters : Bundled Mroonga does not support token filter yet.
+create_table_token_filters_index_comment_one_token_filter : Bundled Mroonga does not support token filter yet.
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column.result
new file mode 100644
index 00000000..2be9834c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+id title
+1 survey
+ALTER TABLE diaries ADD COLUMN body TEXT;
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_cp932.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_cp932.result
new file mode 100644
index 00000000..9628df68
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_cp932.result
@@ -0,0 +1,33 @@
+DROP TABLE IF EXISTS users;
+SET NAMES cp932;
+CREATE TABLE users (
+id int unsigned PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=cp932 COMMENT='Engine "InnoDB"';
+ALTER TABLE users
+ADD COLUMN O text,
+ADD FULLTEXT INDEX (O);
+INSERT INTO users (O) VALUES ("܂");
+INSERT INTO users (O) VALUES ("Ȃ");
+INSERT INTO users (O) VALUES ("");
+SELECT * FROM users;
+id O
+1 ܂
+2 Ȃ
+3
+SELECT * FROM users
+WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+id O
+2 Ȃ
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_HASH_KEY ShortText
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_utf8.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_utf8.result
new file mode 100644
index 00000000..abd2271f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_add_column_multibyte_utf8.result
@@ -0,0 +1,33 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+id int unsigned PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=utf8 COMMENT='Engine "InnoDB"';
+ALTER TABLE users
+ADD COLUMN 名前 text,
+ADD FULLTEXT INDEX (名前);
+INSERT INTO users (名前) VALUES ("やまだ");
+INSERT INTO users (名前) VALUES ("たなか");
+INSERT INTO users (名前) VALUES ("すずき");
+SELECT * FROM users;
+id 名前
+1 やまだ
+2 たなか
+3 すずき
+SELECT * FROM users
+WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+id 名前
+2 たなか
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_HASH_KEY ShortText
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_column_comment.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_column_comment.result
new file mode 100644
index 00000000..a56ae08d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_column_comment.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+ALTER TABLE bugs
+CHANGE COLUMN
+tag
+tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.';
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tag` varchar(64) DEFAULT NULL COMMENT 'It must consist of only alphabet and number.',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='engine "InnoDB"'
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_engine.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_engine.result
new file mode 100644
index 00000000..7197d3a9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_change_engine.result
@@ -0,0 +1,39 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) ENGINE MyISAM DEFAULT CHARSET UTF8;
+SELECT table_name, engine, table_comment
+FROM information_schema.tables
+WHERE table_name = 'diaries';
+table_name engine table_comment
+diaries MyISAM
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+id title body
+1 survey will start groonga!
+ALTER TABLE diaries ENGINE = mroonga COMMENT = 'ENGINE "InnoDB"';
+SELECT table_name, engine, table_comment
+FROM information_schema.tables
+WHERE table_name = 'diaries';
+table_name engine table_comment
+diaries Mroonga ENGINE "InnoDB"
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+id title body
+1 survey will start groonga!
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AND
+MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+id title body
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_comment_change_engine.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_comment_change_engine.result
new file mode 100644
index 00000000..05bd0e4e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_comment_change_engine.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT AUTO_INCREMENT PRIMARY KEY,
+title VARCHAR(64),
+content TEXT,
+FULLTEXT INDEX(content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+INSERT INTO memos (title, content) VALUES ("Hello", "I start to write memos!");
+INSERT INTO memos (title, content) VALUES ("groonga", "I start to use groonga!");
+INSERT INTO memos (title, content) VALUES ("mroonga", "I use mroonga too!");
+ALTER TABLE memos COMMENT='engine "MyISAM"';
+SELECT table_name, table_comment
+FROM information_schema.tables
+WHERE table_name = 'memos';
+table_name table_comment
+memos engine "MyISAM"
+SELECT * FROM memos;
+id title content
+1 Hello I start to write memos!
+2 groonga I start to use groonga!
+3 mroonga I use mroonga too!
+SELECT * FROM memos WHERE MATCH(content) AGAINST("start" IN BOOLEAN MODE);
+id title content
+1 Hello I start to write memos!
+2 groonga I start to use groonga!
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_create_fulltext.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_create_fulltext.result
new file mode 100644
index 00000000..b185bf26
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_create_fulltext.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+CREATE FULLTEXT INDEX title_index on diaries (title);
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_fulltext.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_fulltext.result
new file mode 100644
index 00000000..e71132be
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_fulltext.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_multiple_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_multiple_column.result
new file mode 100644
index 00000000..1fefc1d9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_multiple_column.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY title_and_created_at_index (title, created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_normal.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_normal.result
new file mode 100644
index 00000000..d115cefb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_normal.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY created_at_index (created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_primary.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_primary.result
new file mode 100644
index 00000000..47649911
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_primary.result
@@ -0,0 +1,23 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+ALTER TABLE diaries DISABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_updating.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_updating.result
new file mode 100644
index 00000000..06e1a12d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_disable_keys_updating.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (
+c1 int NOT NULL,
+c2 text NOT NULL,
+c3 int NOT NULL,
+c4 int NOT NULL,
+PRIMARY KEY(c1),
+KEY idx1(c3,c4),
+FULLTEXT KEY ft1(c2)
+) COMMENT='ENGINE "MyISAM"' DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES(1, 'test1', 1, 1);
+INSERT INTO t1 VALUES(2, 'test2', 2, 2);
+INSERT INTO t1 VALUES(3, 'test3', 1, 3);
+ALTER TABLE t1 DISABLE KEYS;
+DELETE FROM t1 WHERE c1 = 2;
+UPDATE t1 SET c4 = 4 WHERE c1 = 1;
+INSERT INTO t1 VALUES(4, 'test4', 2, 4);
+TRUNCATE t1;
+DROP TABLE t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_drop_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_drop_column.result
new file mode 100644
index 00000000..25cb53de
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_drop_column.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+ALTER TABLE diaries DROP COLUMN body;
+SELECT * FROM diaries;
+id title
+1 survey
+INSERT INTO diaries (title) values ("groonga (1)");
+INSERT INTO diaries (title) values ("groonga (2)");
+SELECT * FROM diaries;
+id title
+1 survey
+2 groonga (1)
+3 groonga (2)
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_fulltext.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_fulltext.result
new file mode 100644
index 00000000..b9a0f545
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_fulltext.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+FULLTEXT KEY title_index (title)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_index)
+WHERE MATCH (title) AGAINST ("富士山");
+id title
+3 富士山
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_lock_tables.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_lock_tables.result
new file mode 100644
index 00000000..341cc4f7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_lock_tables.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS memos;
+CREATE TABLE IF NOT EXISTS memos (
+id VARCHAR(45) NOT NULL PRIMARY KEY,
+text TEXT NOT NULL,
+FULLTEXT KEY (text)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+LOCK TABLES memos WRITE;
+ALTER TABLE memos DISABLE KEYS;
+INSERT INTO memos
+VALUES (00000, 'text0'),
+(00001, 'text1'),
+(00002, 'text2');
+ALTER TABLE memos ENABLE KEYS;
+UNLOCK TABLES;
+SELECT * FROM memos;
+id text
+0 text0
+1 text1
+2 text2
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_multiple_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_multiple_column.result
new file mode 100644
index 00000000..21f6b908
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_multiple_column.result
@@ -0,0 +1,28 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY title_and_created_at_index (title, created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (title_and_created_at_index)
+WHERE title = "天気" AND
+created_at = "2012-04-30 23:00:00";
+id title created_at
+2 天気 2012-04-30 23:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_normal.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_normal.result
new file mode 100644
index 00000000..2ba4f1b6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_normal.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+created_at datetime,
+KEY created_at_index (created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (created_at_index)
+WHERE created_at = "2012-04-30 20:00:00";
+id title created_at
+1 Hello 2012-04-30 20:00:00
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_primary.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_primary.result
new file mode 100644
index 00000000..a1ee9013
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_enable_keys_primary.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+ALTER TABLE diaries DISABLE KEYS;
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+ALTER TABLE diaries ENABLE KEYS;
+SELECT *
+FROM diaries
+FORCE INDEX (PRIMARY)
+WHERE id = 2;
+id title
+2 天気
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_fulltext.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_fulltext.result
new file mode 100644
index 00000000..37f03b40
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_fulltext.result
@@ -0,0 +1,34 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+FULLTEXT INDEX title_index (title)
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+id title
+1 survey
+ALTER TABLE diaries ADD COLUMN body TEXT;
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+ALTER TABLE diaries ADD FULLTEXT INDEX body_index (body);
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey") AND
+MATCH(body) AGAINST("groonga");
+id title body
+1 survey will start groonga!
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("groonga") AND
+MATCH(body) AGAINST("starting");
+id title body
+2 groonga (1) starting groonga...
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_rename_table.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_rename_table.result
new file mode 100644
index 00000000..bfbe96d1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_rename_table.result
@@ -0,0 +1,25 @@
+DROP TABLE IF EXISTS diaries, memos;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("groonga") AND
+MATCH(body) AGAINST("starting");
+id title body
+ALTER TABLE diaries RENAME memos;
+SELECT * FROM memos;
+id title body
+1 survey will start groonga!
+SELECT * FROM memos
+WHERE MATCH(title) AGAINST("groonga") AND
+MATCH(body) AGAINST("starting");
+id title body
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_spatial.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_spatial.result
new file mode 100644
index 00000000..5c66485d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/alter_table_spatial.result
@@ -0,0 +1,123 @@
+DROP TABLE IF EXISTS shops;
+CREATE TABLE shops (
+id INT PRIMARY KEY AUTO_INCREMENT,
+name TEXT,
+location GEOMETRY NOT NULL
+) COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO shops (name, location)
+VALUES ('nezu-no-taiyaki',
+ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+VALUES ('taiyaki-kataoka',
+ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+VALUES ('soba-taiyaki-ku',
+ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+VALUES ('kuruma',
+ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+VALUES ('hirose-ya',
+ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+VALUES ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+VALUES ('omede-taiyaki',
+ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+VALUES ('onaga-ya',
+ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+VALUES ('shiro-ya',
+ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+VALUES ('fuji-ya',
+ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+VALUES ('miyoshi',
+ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+VALUES ('juju-ya',
+ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+VALUES ('tatsumi-ya',
+ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+VALUES ('tetsuji',
+ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+VALUES ('gazuma-ya',
+ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+VALUES ('honma-mon',
+ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+VALUES ('naniwa-ya',
+ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+VALUES ('kuro-dai',
+ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+VALUES ('daruma',
+ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+VALUES ('yanagi-ya',
+ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+VALUES ('sharaku',
+ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+VALUES ('takane',
+ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+VALUES ('chiyoda',
+ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+VALUES ('da-ka-po',
+ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+VALUES ('matsushima-ya',
+ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+VALUES ('kazuya',
+ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+VALUES ('furuya-kogane-an',
+ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+VALUES ('hachi-no-ie',
+ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+VALUES ('azuki-chan',
+ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+VALUES ('kuriko-an',
+ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+VALUES ('naze-ya',
+ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+VALUES ('sanoki-ya',
+ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+VALUES ('shigeta',
+ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+VALUES ('nishimi-ya',
+ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+VALUES ('hiiragi',
+ST_GeomFromText('POINT(139.711517 35.647701)'));
+ALTER TABLE shops ADD SPATIAL KEY location_index (location);
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ORDER BY id;
+id name location_text
+14 tetsuji POINT(139.76857 35.680912)
+19 daruma POINT(139.770599 35.681461)
+26 kazuya POINT(139.760895 35.673508)
+DROP TABLE shops;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/auto_increment_text.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/auto_increment_text.result
new file mode 100644
index 00000000..9d45d2fe
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/auto_increment_text.result
@@ -0,0 +1,15 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text
+) comment = 'engine "innodb"';
+insert into diaries (body) values ("started groonga (long text)");
+select * from diaries;
+id body
+1 started groonga (long text)
+insert into diaries (body) values ("sleeping... (short text)");
+select * from diaries;
+id body
+1 started groonga (long text)
+2 sleeping... (short text)
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/binlog_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/binlog_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..f0792094
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/binlog_TODO_SPLIT_ME.result
@@ -0,0 +1,34 @@
+drop table if exists t1;
+show variables like 'log_bin';
+Variable_name Value
+log_bin ON
+set binlog_format="STATEMENT";
+create table t1 (c1 int primary key, c2 int) engine = mroonga COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+c1 c2
+1 100
+2 100
+drop table t1;
+set binlog_format="ROW";
+create table t1 (c1 int primary key, c2 int) engine = mroonga COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+c1 c2
+1 100
+2 100
+drop table t1;
+set binlog_format="MIXED";
+create table t1 (c1 int primary key, c2 int) engine = mroonga COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+c1 c2
+1 100
+2 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/check_table_for_upgrade.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/check_table_for_upgrade.result
new file mode 100644
index 00000000..61122f78
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/check_table_for_upgrade.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id int NOT NULL PRIMARY KEY,
+content text,
+FULLTEXT INDEX (content)
+) COMMENT='engine "InnoDB"';
+INSERT INTO memos VALUES (1, 'Hello MySQL');
+INSERT INTO memos VALUES (2, 'Hello Mroonga');
+CHECK TABLE memos FOR UPGRADE;
+Table Op Msg_type Msg_text
+test.memos check status OK
+FLUSH TABLES;
+SELECT * FROM memos
+WHERE MATCH(content) AGAINST('+mroonga' IN BOOLEAN MODE);
+id content
+2 Hello Mroonga
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_comment_index_not_for_mroonga.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_comment_index_not_for_mroonga.result
new file mode 100644
index 00000000..708055b6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_comment_index_not_for_mroonga.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64),
+INDEX (tag) COMMENT 'Tag search is required.'
+) DEFAULT CHARSET=utf8
+COMMENT='engine "InnoDB"';
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tag` varchar(64) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `tag` (`tag`) COMMENT 'Tag search is required.'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='engine "InnoDB"'
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_add_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_add_column.result
new file mode 100644
index 00000000..5b379d08
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_add_column.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED;
+ALTER TABLE logs ADD FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"';
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_delete.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_delete.result
new file mode 100644
index 00000000..24c9275b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_delete.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+DELETE FROM logs WHERE id = 1;
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_drop_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_drop_column.result
new file mode 100644
index 00000000..65a55204
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_drop_column.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+ALTER TABLE logs DROP COLUMN message;
+SELECT * FROM logs;
+id record
+1 {"level": "info", "message": "start"}
+2 {"level": "info", "message": "restart"}
+3 {"level": "warn", "message": "abort"}
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_insert.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_insert.result
new file mode 100644
index 00000000..febfd343
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_insert.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_reindex.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_reindex.result
new file mode 100644
index 00000000..c0d9452f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_reindex.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+ALTER TABLE logs DISABLE KEYS;
+ALTER TABLE logs ENABLE KEYS;
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_update.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_update.result
new file mode 100644
index 00000000..ae9c244d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_stored_update.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+SELECT * FROM logs WHERE MATCH(message) AGAINST("hut" IN BOOLEAN MODE);
+id record message
+2 {"level": "info", "message": "shutdown"} "shutdown"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_column.result
new file mode 100644
index 00000000..6daeb5e2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_column.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL;
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs;
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_fulltext_index.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_fulltext_index.result
new file mode 100644
index 00000000..82a46e3f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_fulltext_index.result
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record)
+VALUES (1, '{"level": "info", "message": "start server"}');
+ALTER TABLE logs ADD FULLTEXT INDEX (message);
+INSERT INTO logs(id, record)
+VALUES (2, '{"level": "info", "message": "start server"}');
+INSERT INTO logs(id, record)
+VALUES (3, '{"level": "warn", "message": "abort server"}');
+SELECT * FROM logs WHERE MATCH(message) AGAINST('+start' IN BOOLEAN MODE);
+id record message
+2 {"level": "info", "message": "start server"} "start server"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_index.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_index.result
new file mode 100644
index 00000000..09cd1891
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_add_index.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+level VARCHAR(255) GENERATED ALWAYS AS
+(json_unquote(json_extract(`record`, '$.level'))) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record)
+VALUES (1, '{"level": "info", "message": "start server"}');
+ALTER TABLE logs ADD INDEX (level);
+INSERT INTO logs(id, record)
+VALUES (2, '{"level": "info", "message": "start server"}');
+INSERT INTO logs(id, record)
+VALUES (3, '{"level": "warn", "message": "abort server"}');
+SELECT * FROM logs WHERE level = 'info';
+id record level
+1 {"level": "info", "message": "start server"} info
+2 {"level": "info", "message": "start server"} info
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_delete.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_delete.result
new file mode 100644
index 00000000..8c1ceaf1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_delete.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+DELETE FROM logs WHERE id = 1;
+SELECT * FROM logs;
+id record message
+2 {"level": "info", "message": "restart"} "restart"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_drop_column.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_drop_column.result
new file mode 100644
index 00000000..7d322617
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_drop_column.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+ALTER TABLE logs DROP COLUMN message;
+SELECT * FROM logs;
+id record
+1 {"level": "info", "message": "start"}
+2 {"level": "info", "message": "restart"}
+3 {"level": "warn", "message": "abort"}
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_insert.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_insert.result
new file mode 100644
index 00000000..5a0e63ed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_insert.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+SELECT * FROM logs;
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "restart"} "restart"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_update.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_update.result
new file mode 100644
index 00000000..2411f7a7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_generated_virtual_update.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY,
+record JSON,
+message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+SELECT * FROM logs;
+id record message
+1 {"level": "info", "message": "start"} "start"
+2 {"level": "info", "message": "shutdown"} "shutdown"
+3 {"level": "warn", "message": "abort"} "abort"
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_cp932.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_cp932.result
new file mode 100644
index 00000000..38185f5e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_cp932.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS users;
+SET NAMES cp932;
+CREATE TABLE users (
+id int unsigned PRIMARY KEY AUTO_INCREMENT,
+O text,
+FULLTEXT INDEX (O)
+) DEFAULT CHARSET=cp932 COMMENT='Engine "InnoDB"';
+INSERT INTO users (O) VALUES ("܂");
+INSERT INTO users (O) VALUES ("Ȃ");
+INSERT INTO users (O) VALUES ("");
+SELECT * FROM users;
+id O
+1 ܂
+2 Ȃ
+3
+SELECT * FROM users
+WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+id O
+2 Ȃ
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_HASH_KEY ShortText
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerAuto
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_utf8.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_utf8.result
new file mode 100644
index 00000000..2d313073
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_multibyte_utf8.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+id int unsigned PRIMARY KEY AUTO_INCREMENT,
+名前 text,
+FULLTEXT INDEX (名前)
+) DEFAULT CHARSET=utf8 COMMENT='Engine "InnoDB"';
+INSERT INTO users (名前) VALUES ("やまだ");
+INSERT INTO users (名前) VALUES ("たなか");
+INSERT INTO users (名前) VALUES ("すずき");
+SELECT * FROM users;
+id 名前
+1 やまだ
+2 たなか
+3 すずき
+SELECT * FROM users
+WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+id 名前
+2 たなか
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+mroonga_command("dump --dump_plugins no --dump_records no")
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+table_create users TABLE_HASH_KEY ShortText
+
+table_create users#@540d@524d TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+
+column_create users#@540d@524d index COLUMN_INDEX|WITH_POSITION users
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/column_normal_comment.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_normal_comment.result
new file mode 100644
index 00000000..9c4b974c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/column_normal_comment.result
@@ -0,0 +1,13 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY,
+tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.'
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+SHOW CREATE TABLE bugs;
+Table Create Table
+bugs CREATE TABLE `bugs` (
+ `id` int(10) unsigned NOT NULL,
+ `tag` varchar(64) DEFAULT NULL COMMENT 'It must consist of only alphabet and number.',
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='engine "InnoDB"'
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star.result
new file mode 100644
index 00000000..7822d118
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star.result
@@ -0,0 +1,11 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int PRIMARY KEY
+) COMMENT='ENGINE "InnoDB"';
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+SELECT COUNT(*) FROM ids;
+COUNT(*)
+3
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_mysql_5_7_or_later_with_index.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_mysql_5_7_or_later_with_index.result
new file mode 100644
index 00000000..141117f6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_mysql_5_7_or_later_with_index.result
@@ -0,0 +1,30 @@
+CREATE TABLE diaries_innodb (
+id INT PRIMARY KEY AUTO_INCREMENT,
+body TEXT,
+flag TINYINT(2),
+INDEX (flag)
+) ENGINE = InnoDB DEFAULT CHARSET UTF8;
+CREATE TABLE diaries_mroonga (
+id INT PRIMARY KEY AUTO_INCREMENT,
+body TEXT,
+flag TINYINT(2),
+INDEX (flag)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+INSERT INTO diaries_innodb (body) VALUES ("will start groonga!");
+INSERT INTO diaries_innodb (body) VALUES ("starting groonga...");
+INSERT INTO diaries_innodb (body) VALUES ("started groonga.");
+INSERT INTO diaries_mroonga (body) VALUES ("will start groonga!");
+INSERT INTO diaries_mroonga (body) VALUES ("starting groonga...");
+INSERT INTO diaries_mroonga (body) VALUES ("started groonga.");
+EXPLAIN SELECT COUNT(*) FROM diaries_innodb;
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE diaries_innodb NULL index NULL flag 2 NULL 3 100.00 Using index
+Warnings:
+Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`diaries_innodb`
+EXPLAIN SELECT COUNT(*) FROM diaries_mroonga;
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE diaries_mroonga NULL index NULL flag 2 NULL 3 100.00 Using index
+Warnings:
+Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from `test`.`diaries_mroonga`
+DROP TABLE diaries_innodb;
+DROP TABLE diaries_mroonga;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_with_index.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_with_index.result
new file mode 100644
index 00000000..1ebd0ba8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/count_star_with_index.result
@@ -0,0 +1,26 @@
+CREATE TABLE diaries_innodb (
+id INT PRIMARY KEY AUTO_INCREMENT,
+body TEXT,
+flag TINYINT(2),
+INDEX (flag)
+) ENGINE = InnoDB DEFAULT CHARSET UTF8;
+CREATE TABLE diaries_mroonga (
+id INT PRIMARY KEY AUTO_INCREMENT,
+body TEXT,
+flag TINYINT(2),
+INDEX (flag)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+INSERT INTO diaries_innodb (body) VALUES ("will start groonga!");
+INSERT INTO diaries_innodb (body) VALUES ("starting groonga...");
+INSERT INTO diaries_innodb (body) VALUES ("started groonga.");
+INSERT INTO diaries_mroonga (body) VALUES ("will start groonga!");
+INSERT INTO diaries_mroonga (body) VALUES ("starting groonga...");
+INSERT INTO diaries_mroonga (body) VALUES ("started groonga.");
+EXPLAIN SELECT COUNT(*) FROM diaries_innodb;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE diaries_innodb index NULL flag 2 NULL # Using index
+EXPLAIN SELECT COUNT(*) FROM diaries_mroonga;
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE diaries_mroonga index NULL flag 2 NULL # Using index
+DROP TABLE diaries_innodb;
+DROP TABLE diaries_mroonga;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..b3814331
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_TODO_SPLIT_ME.result
@@ -0,0 +1,109 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key) COMMENT = 'engine "innodb"';
+create table t2 (c1 int primary key) COMMENT = 'engine "innodb"';
+create table t3 (c1 int primary key) COMMENT = 'engine "innodb"';
+drop table t1,t2,t3;
+create table t1 (c1 int primary key, c2 int, c3 int) COMMENT = 'engine "innodb"';
+drop table t1;
+create table t1 (c1 bit primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 bit(1) NO PRI NULL
+drop table t1;
+create table t1 (c1 tinyint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 tinyint(4) NO PRI NULL
+drop table t1;
+create table t1 (c1 smallint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 smallint(6) NO PRI NULL
+drop table t1;
+create table t1 (c1 mediumint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 mediumint(9) NO PRI NULL
+drop table t1;
+create table t1 (c1 int primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 int(11) NO PRI NULL
+drop table t1;
+create table t1 (c1 bigint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 bigint(20) NO PRI NULL
+drop table t1;
+create table t1 (c1 double primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 double NO PRI NULL
+drop table t1;
+create table t1 (c1 float primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 float NO PRI NULL
+drop table t1;
+create table t1 (c1 decimal primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 decimal(10,0) NO PRI NULL
+drop table t1;
+create table t1 (c1 date primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 date NO PRI NULL
+drop table t1;
+create table t1 (c1 time primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 time NO PRI NULL
+drop table t1;
+create table t1 (c1 timestamp primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 timestamp NO PRI CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP
+drop table t1;
+create table t1 (c1 datetime primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 datetime NO PRI NULL
+drop table t1;
+create table t1 (c1 year primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 year(4) NO PRI NULL
+drop table t1;
+create table t1 (c1 char(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 char(10) NO PRI NULL
+drop table t1;
+create table t1 (c1 varchar(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 varchar(10) NO PRI NULL
+drop table t1;
+create table t1 (c1 binary(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 binary(10) NO PRI NULL
+drop table t1;
+create table t1 (c1 varbinary(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 varbinary(10) NO PRI NULL
+drop table t1;
+create table t1 (c1 enum("yes","no") primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 enum('yes','no') NO PRI NULL
+drop table t1;
+create table t1 (c1 set("A","B","AB","O") primary key) COMMENT = 'engine "innodb"';
+desc t1;
+Field Type Null Key Default Extra
+c1 set('A','B','AB','O') NO PRI NULL
+drop table t1;
+create table t1 (c1 int) COMMENT = 'engine "innodb"';
+ERROR 42000: This table type requires a primary key
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_comment_combined.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_comment_combined.result
new file mode 100644
index 00000000..3610ab6f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_comment_combined.result
@@ -0,0 +1,14 @@
+DROP TABLE IF EXISTS bugs;
+CREATE TABLE bugs (
+id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8
+COMMENT='Free style normal comment, engine "InnoDB"';
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create bugs TABLE_HASH_KEY ShortText
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+DROP TABLE bugs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_comment.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_comment.result
new file mode 100644
index 00000000..6ff4c105
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_comment.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL PRIMARY KEY,
+FULLTEXT INDEX (content) COMMENT 'flags "WITH_POSITION|WITH_WEIGHT"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX|WITH_WEIGHT|WITH_POSITION memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_none.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_none.result
new file mode 100644
index 00000000..9048b677
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_none.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL PRIMARY KEY,
+FULLTEXT INDEX (content) COMMENT 'flags "NONE"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_parameter.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_parameter.result
new file mode 100644
index 00000000..39bf778c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_flags_parameter.result
@@ -0,0 +1,16 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL PRIMARY KEY,
+FULLTEXT INDEX (content) FLAGS='WITH_POSITION|WITH_WEIGHT'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `content` varchar(64) NOT NULL,
+ PRIMARY KEY (`content`),
+ FULLTEXT KEY `content` (`content`) `FLAGS`='WITH_POSITION|WITH_WEIGHT'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "InnoDB"'
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX|WITH_WEIGHT|WITH_POSITION memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_none.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_none.result
new file mode 100644
index 00000000..e378ba3b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_none.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL PRIMARY KEY,
+FULLTEXT INDEX (content) COMMENT 'index_flags "NONE"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_with_position_and_with_weight.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_with_position_and_with_weight.result
new file mode 100644
index 00000000..1367a3ad
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_index_flags_with_position_and_with_weight.result
@@ -0,0 +1,9 @@
+SET NAMES utf8;
+CREATE TABLE memos (
+content VARCHAR(64) NOT NULL PRIMARY KEY,
+FULLTEXT INDEX (content) COMMENT 'index_flags "WITH_POSITION|WITH_WEIGHT"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+mroonga_command("dump --dump_plugins no --dump_schema no")
+column_create memos#content index COLUMN_INDEX|WITH_WEIGHT|WITH_POSITION memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_comment.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_comment.result
new file mode 100644
index 00000000..97f900a1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_comment.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `id` int(11) NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `content` (`content`) COMMENT 'normalizer "NormalizerAuto"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "InnoDB"'
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+id content
+1 1日の消費㌍は約2000㌔㌍
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_fulltext_index_bin.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_fulltext_index_bin.result
new file mode 100644
index 00000000..97f3e886
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_fulltext_index_bin.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `id` int(11) NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `content` (`content`) COMMENT 'normalizer "NormalizerAuto"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_bin COMMENT='ENGINE "InnoDB"'
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+id content
+1 1日の消費㌍は約2000㌔㌍
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_parameter.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_parameter.result
new file mode 100644
index 00000000..b81407b6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_normalizer_parameter.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content TEXT NOT NULL,
+FULLTEXT INDEX (content) NORMALIZER='NormalizerAuto'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `id` int(11) NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `content` (`content`) `NORMALIZER`='NormalizerAuto'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "InnoDB"'
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+id content
+1 1日の消費㌍は約2000㌔㌍
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_parser_comment.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_parser_comment.result
new file mode 100644
index 00000000..4d9d20dc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_parser_comment.result
@@ -0,0 +1,25 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+comment 'parser "TokenBigramSplitSymbolAlphaDigit"'
+) comment = 'engine "innodb"' default charset utf8;
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
+insert into diaries (body) values ("will start Groonga!");
+Warnings:
+Warning 1287 'parser' is deprecated and will be removed in a future release. Please use tokenizer instead
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+select * from diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+select * from diaries where match(body) against("+start" in boolean mode) order by id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_multiple_token_filters.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_multiple_token_filters.result
new file mode 100644
index 00000000..7f4885fb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_multiple_token_filters.result
@@ -0,0 +1,22 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord,TokenFilterStopWord"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_HASH_KEY ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord,TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_one_token_filter.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_one_token_filter.result
new file mode 100644
index 00000000..2d7c6748
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_one_token_filter.result
@@ -0,0 +1,22 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_HASH_KEY ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_parameter.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_parameter.result
new file mode 100644
index 00000000..4626d144
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_token_filters_index_parameter.result
@@ -0,0 +1,30 @@
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+mroonga_command("plugin_register token_filters/stop_word")
+true
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT NOT NULL PRIMARY KEY,
+content VARCHAR(64) NOT NULL,
+FULLTEXT INDEX (content) TOKEN_FILTERS='TokenFilterStopWord,TokenFilterStopWord'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+Table Create Table
+memos CREATE TABLE `memos` (
+ `id` int(11) NOT NULL,
+ `content` varchar(64) NOT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `content` (`content`) `TOKEN_FILTERS`='TokenFilterStopWord,TokenFilterStopWord'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"'
+SELECT mroonga_command("dump --dump_plugins no");
+mroonga_command("dump --dump_plugins no")
+table_create memos TABLE_HASH_KEY ShortText
+
+table_create memos#content TABLE_PAT_KEY ShortText --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI --token_filters TokenFilterStopWord,TokenFilterStopWord
+
+table_create mroonga_operations TABLE_NO_KEY
+column_create mroonga_operations record COLUMN_SCALAR UInt32
+column_create mroonga_operations table COLUMN_SCALAR ShortText
+column_create mroonga_operations type COLUMN_SCALAR ShortText
+
+column_create memos#content index COLUMN_INDEX|WITH_POSITION memos
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_comment.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_comment.result
new file mode 100644
index 00000000..34e3f88d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_comment.result
@@ -0,0 +1,21 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) comment = 'engine "innodb"' default charset utf8;
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+select * from diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+select * from diaries where match(body) against("+start" in boolean mode) order by id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_parameter.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_parameter.result
new file mode 100644
index 00000000..219d8e08
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/create_table_tokenizer_parameter.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id int PRIMARY KEY AUTO_INCREMENT,
+body text,
+FULLTEXT INDEX body_index (body) TOKENIZER='TokenBigramSplitSymbolAlphaDigit'
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET utf8;
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+SELECT * FROM diaries;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ORDER BY id;
+id body
+1 will start Groonga!
+2 starting Groonga...
+3 started Groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/delete_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/delete_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..81926396
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/delete_TODO_SPLIT_ME.result
@@ -0,0 +1,55 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int) COMMENT 'engine = "innodb"';
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL,
+ `c2` int(11) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci COMMENT='engine = "innodb"'
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+insert into t1 values (4, 102);
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+4 102
+delete from t1 where c1=3;
+select * from t1;
+c1 c2
+1 100
+2 101
+4 102
+flush tables;
+delete from t1 where c1=2;
+select * from t1;
+c1 c2
+1 100
+4 102
+delete from t1;
+select * from t1;
+c1 c2
+drop table t1;
+create table t1 (c1 int primary key, c2 text, fulltext index (c2)) COMMENT 'engine = "innodb"';
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+select * from t1;
+c1 c2
+10 aa ii uu ee
+20 ka ki ku ke
+30 sa si su se
+select * from t1 where match(c2) against("ki");
+c1 c2
+20 ka ki ku ke
+delete from t1 where c1=20;
+select * from t1;
+c1 c2
+10 aa ii uu ee
+30 sa si su se
+select * from t1 where match(c2) against("ki");
+c1 c2
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/delete_all.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/delete_all.result
new file mode 100644
index 00000000..200e978a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/delete_all.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS users;
+SET NAMES utf8;
+CREATE TABLE users (
+id int PRIMARY KEY,
+name varchar(100),
+FULLTEXT INDEX (name)
+) COMMENT 'engine = "InnoDB"' DEFAULT CHARSET=utf8;
+INSERT INTO users VALUES (1, 'Alice');
+INSERT INTO users VALUES (2, 'Bob');
+INSERT INTO users VALUES (3, 'Chris');
+SELECT * FROM users;
+id name
+1 Alice
+2 Bob
+3 Chris
+DELETE FROM users;
+SELECT * FROM users;
+id name
+DROP TABLE users;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/drop_table_new_connection.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/drop_table_new_connection.result
new file mode 100644
index 00000000..f7d5b439
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/drop_table_new_connection.result
@@ -0,0 +1,13 @@
+CREATE TABLE logs (
+id INT PRIMARY KEY AUTO_INCREMENT,
+message TEXT,
+FULLTEXT INDEX (message)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+USE test;
+DROP TABLE logs;
+CREATE TABLE logs (
+id INT PRIMARY KEY AUTO_INCREMENT,
+message TEXT,
+FULLTEXT INDEX (message)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+DROP TABLE logs;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_leading_not.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_leading_not.result
new file mode 100644
index 00000000..8614eaa7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_leading_not.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET = UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("-明日 +天気" IN BOOLEAN MODE);
+id title content
+3 富士山 今日も天気がよくてきれいに見える。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_multiple_match_against.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_multiple_match_against.result
new file mode 100644
index 00000000..1ecf18cb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_multiple_match_against.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title),
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET = UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries VALUES(1, "富士山", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気 1月1日", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "天気 4月4日", "今日も天気がよくてきれいに見える。");
+SELECT COUNT(*) FROM diaries WHERE MATCH(title) AGAINST("+天気" IN BOOLEAN MODE) AND MATCH(content) AGAINST("+今日" IN BOOLEAN MODE);
+COUNT(*)
+1
+SELECT * FROM diaries WHERE MATCH(title) AGAINST("+天気" IN BOOLEAN MODE) AND MATCH(content) AGAINST("+今日" IN BOOLEAN MODE);
+id title content
+3 天気 4月4日 今日も天気がよくてきれいに見える。
+SELECT 1 FROM diaries WHERE MATCH(title) AGAINST("+天気" IN BOOLEAN MODE) AND MATCH(content) AGAINST("+今日" IN BOOLEAN MODE);
+1
+1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result
new file mode 100644
index 00000000..190105a3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Yesterday was good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D- fine is be" IN BOOLEAN MODE);
+id content
+6 Yesterday was fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result
new file mode 100644
index 00000000..240da5c3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_or.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Yesterday was good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D- is OR be fine" IN BOOLEAN MODE);
+id content
+1 Today is good day.
+2 Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result
new file mode 100644
index 00000000..6dedd218
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.result
@@ -0,0 +1,19 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Yesterday was good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D- good +day be" IN BOOLEAN MODE);
+id content
+1 Today is good day.
+3 Yesterday was good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result
new file mode 100644
index 00000000..96d92e53
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_no_operator.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*DOR today good" IN BOOLEAN MODE)
+ORDER BY id;
+id content
+1 Today is good day.
+2 Tomorrow will be good day.
+3 Today is fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result
new file mode 100644
index 00000000..ee8d8510
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_minus.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*DOR today -good tomorrow" IN BOOLEAN MODE)
+ORDER BY id;
+id content
+2 Tomorrow will be good day.
+3 Today is fine.
+4 Tomorrow will be fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result
new file mode 100644
index 00000000..bb940432
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_or_with_plus.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*DOR today +good tomorrow" IN BOOLEAN MODE)
+ORDER BY id;
+id content
+1 Today is good day.
+2 Tomorrow will be good day.
+4 Tomorrow will be fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result
new file mode 100644
index 00000000..29975d55
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today good" IN BOOLEAN MODE);
+id content
+1 Today is good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result
new file mode 100644
index 00000000..2294308a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today -good is" IN BOOLEAN MODE);
+id content
+3 Today is fine.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result
new file mode 100644
index 00000000..b61f0637
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_default_operator_plus_with_or.result
@@ -0,0 +1,16 @@
+DROP TABLE IF EXISTS memos;
+SET NAMES utf8;
+CREATE TABLE memos (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content TEXT,
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+SELECT * FROM memos
+WHERE MATCH (content) AGAINST ("*D+ today OR tomorrow day" IN BOOLEAN MODE);
+id content
+1 Today is good day.
+2 Tomorrow will be good day.
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_full_spec.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_full_spec.result
new file mode 100644
index 00000000..e603cc27
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_full_spec.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 12
+3 富士山 今日も天気がよくてきれいに見える。 2
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_no_weight.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_no_weight.result
new file mode 100644
index 00000000..6a5dbd5c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_no_weight.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*W1,2:2 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*W1,2:2 +天気" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 3
+3 富士山 今日も天気がよくてきれいに見える。 2
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_omit_section.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_omit_section.result
new file mode 100644
index 00000000..2fe63a68
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_boolean_mode_pragma_weight_omit_section.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id INT PRIMARY KEY,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT *, MATCH(title, content)
+AGAINST("*W1:2 +天気" in BOOLEAN MODE) AS score
+FROM diaries
+WHERE MATCH(title, content)
+AGAINST("*W1:2 +天気" in BOOLEAN MODE);
+id title content score
+2 天気 明日の富士山の天気について 3
+3 富士山 今日も天気がよくてきれいに見える。 1
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_ascii.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_ascii.result
new file mode 100644
index 00000000..b58f4ad3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_ascii.result
@@ -0,0 +1,29 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 20 ka ki ku ke ko
+3 30 sa si su se so
+4 40 ta ti tu te to
+5 50 aa ii uu ee oo
+select * from t1 where match(c3) against("su");
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 where match(c3) against("ii");
+c1 c2 c3
+1 10 aa ii uu ee oo
+5 50 aa ii uu ee oo
+select * from t1 where match(c3) against("+su" in boolean mode);
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 where match(c3) against("+ii" in boolean mode);
+c1 c2 c3
+1 10 aa ii uu ee oo
+5 50 aa ii uu ee oo
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_cp932.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_cp932.result
new file mode 100644
index 00000000..d7b64010
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_cp932.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+set names cp932;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset cp932 COMMENT = 'engine "innodb"';
+insert into t1 values(1, "̕xmR̓VCɂ‚","");
+insert into t1 values(2, "","̕xmR̓VC͕܂");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 ̕xmR̓VCɂ‚
+2 ̕xmR̓VC͕܂
+3 dummy dummy
+select * from t1 where match(c2) against("xmR");
+c1 c2 c3
+1 ̕xmR̓VCɂ‚
+select * from t1 where match(c3) against("xmR");
+c1 c2 c3
+2 ̕xmR̓VC͕܂
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_eucjpms.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_eucjpms.result
new file mode 100644
index 00000000..9aa60690
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_eucjpms.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+set names eucjpms;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset eucjpms COMMENT = 'engine "innodb"';
+insert into t1 values(1, "ٻλŷˤĤ","");
+insert into t1 values(2, "","ٻλŷʬޤ");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 ٻλŷˤĤ
+2 ٻλŷʬޤ
+3 dummy dummy
+select * from t1 where match(c2) against("ٻλ");
+c1 c2 c3
+1 ٻλŷˤĤ
+select * from t1 where match(c3) against("ٻλ");
+c1 c2 c3
+2 ٻλŷʬޤ
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_japanese.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_japanese.result
new file mode 100644
index 00000000..6c73f462
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_charset_japanese.result
@@ -0,0 +1,18 @@
+drop table if exists t1, t2, t3;
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8 COMMENT = 'engine "innodb"';
+insert into t1 values(1, "明日の富士山の天気について","あああああああ");
+insert into t1 values(2, "いいいいい","明日の富士山の天気は分かりません");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 明日の富士山の天気について あああああああ
+2 いいいいい 明日の富士山の天気は分かりません
+3 dummy dummy
+select * from t1 where match(c2) against("富士山");
+c1 c2 c3
+1 明日の富士山の天気について あああああああ
+select * from t1 where match(c3) against("富士山");
+c1 c2 c3
+2 いいいいい 明日の富士山の天気は分かりません
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_index_recreate.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_index_recreate.result
new file mode 100644
index 00000000..d3bdfca0
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_index_recreate.result
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES utf8;
+CREATE TABLE diaries (
+id int PRIMARY KEY,
+title varchar(255),
+content text,
+FULLTEXT INDEX (title)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+INSERT INTO diaries VALUES (1, "Hello", "はじめました。");
+INSERT INTO diaries VALUES (2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES (3, "富士山", "今日もきれい。");
+SELECT * FROM diaries WHERE MATCH (title) AGAINST ("富士山");
+id title content
+3 富士山 今日もきれい。
+DROP INDEX title ON diaries;
+SELECT * FROM diaries WHERE MATCH (title) AGAINST ("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+SELECT * FROM diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+CREATE FULLTEXT INDEX new_title_index ON diaries (title);
+SELECT * FROM diaries WHERE MATCH (title) AGAINST ("富士山");
+id title content
+3 富士山 今日もきれい。
+SELECT * FROM diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_select.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_select.result
new file mode 100644
index 00000000..c25b47c6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_select.result
@@ -0,0 +1,70 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 varchar(100), fulltext index(c2)) default charset utf8 COMMENT = 'engine "innodb"';
+create table t2 (c1 int primary key, c2 text, fulltext index(c2)) default charset utf8 COMMENT = 'engine "innodb"';
+insert into t1 values (1, "aa ii uu ee oo");
+insert into t1 values (2, "ka ki ku ke ko");
+insert into t1 values (3, "aa ii ii ii oo");
+insert into t1 values (4, "sa si su se so");
+insert into t1 values (5, "ta ti ii ii to");
+insert into t2 values (1, "aa ii uu ee oo");
+insert into t2 values (2, "ka ki ku ke ko");
+insert into t2 values (3, "aa ii ii ii oo");
+insert into t2 values (4, "sa si su se so");
+insert into t2 values (5, "ta ti ii ii to");
+select * from t1;
+c1 c2
+1 aa ii uu ee oo
+2 ka ki ku ke ko
+3 aa ii ii ii oo
+4 sa si su se so
+5 ta ti ii ii to
+select * from t2;
+c1 c2
+1 aa ii uu ee oo
+2 ka ki ku ke ko
+3 aa ii ii ii oo
+4 sa si su se so
+5 ta ti ii ii to
+select * from t1 where c1=3;
+c1 c2
+3 aa ii ii ii oo
+select * from t2 where c1=3;
+c1 c2
+3 aa ii ii ii oo
+select * from t1 where c1>3 order by c1 desc;
+c1 c2
+5 ta ti ii ii to
+4 sa si su se so
+select * from t2 where c1>3 order by c1 asc;
+c1 c2
+4 sa si su se so
+5 ta ti ii ii to
+select * from t1 where c2>"s" order by c2 desc;
+c1 c2
+5 ta ti ii ii to
+4 sa si su se so
+select * from t2 where c2>"s" order by c1 asc;
+c1 c2
+4 sa si su se so
+5 ta ti ii ii to
+select *,match(c2) against("ii") from t1 where match(c2) against("ii") order by match(c2) against("ii") desc;
+c1 c2 match(c2) against("ii")
+3 aa ii ii ii oo 524289
+5 ta ti ii ii to 349526
+1 aa ii uu ee oo 174763
+select *,match(c2) against("ii") from t2 where match(c2) against("ii") order by match(c2) against("ii") asc;
+c1 c2 match(c2) against("ii")
+1 aa ii uu ee oo 174763
+5 ta ti ii ii to 349526
+3 aa ii ii ii oo 524289
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+c1 c2 match(c2) against("ii")
+3 aa ii ii ii oo 524289
+5 ta ti ii ii to 349526
+1 aa ii uu ee oo 174763
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+c1 c2 match(c2) against("ii")
+3 aa ii ii ii oo 524289
+5 ta ti ii ii to 349526
+1 aa ii uu ee oo 174763
+drop table t1,t2;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_values.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_values.result
new file mode 100644
index 00000000..f4719cbd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_insert_values.result
@@ -0,0 +1,17 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 text, fulltext index ft (c2)) COMMENT = 'engine "innodb"';
+insert into t1 values (1, "hoge hoge");
+insert into t1 values (2, "fuga fuga");
+insert into t1 values (3, "moge moge");
+select * from t1;
+c1 c2
+1 hoge hoge
+2 fuga fuga
+3 moge moge
+flush tables;
+select * from t1;
+c1 c2
+1 hoge hoge
+2 fuga fuga
+3 moge moge
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_many_records.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_many_records.result
new file mode 100644
index 00000000..9d1e838b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_many_records.result
@@ -0,0 +1,4381 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+fulltext index (title)
+) default charset utf8 COMMENT = 'engine "innodb"';
+set autocommit=0;
+insert into diaries values(0, "2011-07-14");
+insert into diaries values(1, "2011-07-15");
+insert into diaries values(2, "2011-07-16");
+insert into diaries values(3, "2011-07-17");
+insert into diaries values(4, "2011-07-18");
+insert into diaries values(5, "2011-07-19");
+insert into diaries values(6, "2011-07-20");
+insert into diaries values(7, "2011-07-21");
+insert into diaries values(8, "2011-07-22");
+insert into diaries values(9, "2011-07-23");
+insert into diaries values(10, "2011-07-24");
+insert into diaries values(11, "2011-07-25");
+insert into diaries values(12, "2011-07-26");
+insert into diaries values(13, "2011-07-27");
+insert into diaries values(14, "2011-07-28");
+insert into diaries values(15, "2011-07-29");
+insert into diaries values(16, "2011-07-30");
+insert into diaries values(17, "2011-07-31");
+insert into diaries values(18, "2011-08-01");
+insert into diaries values(19, "2011-08-02");
+insert into diaries values(20, "2011-08-03");
+insert into diaries values(21, "2011-08-04");
+insert into diaries values(22, "2011-08-05");
+insert into diaries values(23, "2011-08-06");
+insert into diaries values(24, "2011-08-07");
+insert into diaries values(25, "2011-08-08");
+insert into diaries values(26, "2011-08-09");
+insert into diaries values(27, "2011-08-10");
+insert into diaries values(28, "2011-08-11");
+insert into diaries values(29, "2011-08-12");
+insert into diaries values(30, "2011-08-13");
+insert into diaries values(31, "2011-08-14");
+insert into diaries values(32, "2011-08-15");
+insert into diaries values(33, "2011-08-16");
+insert into diaries values(34, "2011-08-17");
+insert into diaries values(35, "2011-08-18");
+insert into diaries values(36, "2011-08-19");
+insert into diaries values(37, "2011-08-20");
+insert into diaries values(38, "2011-08-21");
+insert into diaries values(39, "2011-08-22");
+insert into diaries values(40, "2011-08-23");
+insert into diaries values(41, "2011-08-24");
+insert into diaries values(42, "2011-08-25");
+insert into diaries values(43, "2011-08-26");
+insert into diaries values(44, "2011-08-27");
+insert into diaries values(45, "2011-08-28");
+insert into diaries values(46, "2011-08-29");
+insert into diaries values(47, "2011-08-30");
+insert into diaries values(48, "2011-08-31");
+insert into diaries values(49, "2011-09-01");
+insert into diaries values(50, "2011-09-02");
+insert into diaries values(51, "2011-09-03");
+insert into diaries values(52, "2011-09-04");
+insert into diaries values(53, "2011-09-05");
+insert into diaries values(54, "2011-09-06");
+insert into diaries values(55, "2011-09-07");
+insert into diaries values(56, "2011-09-08");
+insert into diaries values(57, "2011-09-09");
+insert into diaries values(58, "2011-09-10");
+insert into diaries values(59, "2011-09-11");
+insert into diaries values(60, "2011-09-12");
+insert into diaries values(61, "2011-09-13");
+insert into diaries values(62, "2011-09-14");
+insert into diaries values(63, "2011-09-15");
+insert into diaries values(64, "2011-09-16");
+insert into diaries values(65, "2011-09-17");
+insert into diaries values(66, "2011-09-18");
+insert into diaries values(67, "2011-09-19");
+insert into diaries values(68, "2011-09-20");
+insert into diaries values(69, "2011-09-21");
+insert into diaries values(70, "2011-09-22");
+insert into diaries values(71, "2011-09-23");
+insert into diaries values(72, "2011-09-24");
+insert into diaries values(73, "2011-09-25");
+insert into diaries values(74, "2011-09-26");
+insert into diaries values(75, "2011-09-27");
+insert into diaries values(76, "2011-09-28");
+insert into diaries values(77, "2011-09-29");
+insert into diaries values(78, "2011-09-30");
+insert into diaries values(79, "2011-10-01");
+insert into diaries values(80, "2011-10-02");
+insert into diaries values(81, "2011-10-03");
+insert into diaries values(82, "2011-10-04");
+insert into diaries values(83, "2011-10-05");
+insert into diaries values(84, "2011-10-06");
+insert into diaries values(85, "2011-10-07");
+insert into diaries values(86, "2011-10-08");
+insert into diaries values(87, "2011-10-09");
+insert into diaries values(88, "2011-10-10");
+insert into diaries values(89, "2011-10-11");
+insert into diaries values(90, "2011-10-12");
+insert into diaries values(91, "2011-10-13");
+insert into diaries values(92, "2011-10-14");
+insert into diaries values(93, "2011-10-15");
+insert into diaries values(94, "2011-10-16");
+insert into diaries values(95, "2011-10-17");
+insert into diaries values(96, "2011-10-18");
+insert into diaries values(97, "2011-10-19");
+insert into diaries values(98, "2011-10-20");
+insert into diaries values(99, "2011-10-21");
+insert into diaries values(100, "2011-10-22");
+insert into diaries values(101, "2011-10-23");
+insert into diaries values(102, "2011-10-24");
+insert into diaries values(103, "2011-10-25");
+insert into diaries values(104, "2011-10-26");
+insert into diaries values(105, "2011-10-27");
+insert into diaries values(106, "2011-10-28");
+insert into diaries values(107, "2011-10-29");
+insert into diaries values(108, "2011-10-30");
+insert into diaries values(109, "2011-10-31");
+insert into diaries values(110, "2011-11-01");
+insert into diaries values(111, "2011-11-02");
+insert into diaries values(112, "2011-11-03");
+insert into diaries values(113, "2011-11-04");
+insert into diaries values(114, "2011-11-05");
+insert into diaries values(115, "2011-11-06");
+insert into diaries values(116, "2011-11-07");
+insert into diaries values(117, "2011-11-08");
+insert into diaries values(118, "2011-11-09");
+insert into diaries values(119, "2011-11-10");
+insert into diaries values(120, "2011-11-11");
+insert into diaries values(121, "2011-11-12");
+insert into diaries values(122, "2011-11-13");
+insert into diaries values(123, "2011-11-14");
+insert into diaries values(124, "2011-11-15");
+insert into diaries values(125, "2011-11-16");
+insert into diaries values(126, "2011-11-17");
+insert into diaries values(127, "2011-11-18");
+insert into diaries values(128, "2011-11-19");
+insert into diaries values(129, "2011-11-20");
+insert into diaries values(130, "2011-11-21");
+insert into diaries values(131, "2011-11-22");
+insert into diaries values(132, "2011-11-23");
+insert into diaries values(133, "2011-11-24");
+insert into diaries values(134, "2011-11-25");
+insert into diaries values(135, "2011-11-26");
+insert into diaries values(136, "2011-11-27");
+insert into diaries values(137, "2011-11-28");
+insert into diaries values(138, "2011-11-29");
+insert into diaries values(139, "2011-11-30");
+insert into diaries values(140, "2011-12-01");
+insert into diaries values(141, "2011-12-02");
+insert into diaries values(142, "2011-12-03");
+insert into diaries values(143, "2011-12-04");
+insert into diaries values(144, "2011-12-05");
+insert into diaries values(145, "2011-12-06");
+insert into diaries values(146, "2011-12-07");
+insert into diaries values(147, "2011-12-08");
+insert into diaries values(148, "2011-12-09");
+insert into diaries values(149, "2011-12-10");
+insert into diaries values(150, "2011-12-11");
+insert into diaries values(151, "2011-12-12");
+insert into diaries values(152, "2011-12-13");
+insert into diaries values(153, "2011-12-14");
+insert into diaries values(154, "2011-12-15");
+insert into diaries values(155, "2011-12-16");
+insert into diaries values(156, "2011-12-17");
+insert into diaries values(157, "2011-12-18");
+insert into diaries values(158, "2011-12-19");
+insert into diaries values(159, "2011-12-20");
+insert into diaries values(160, "2011-12-21");
+insert into diaries values(161, "2011-12-22");
+insert into diaries values(162, "2011-12-23");
+insert into diaries values(163, "2011-12-24");
+insert into diaries values(164, "2011-12-25");
+insert into diaries values(165, "2011-12-26");
+insert into diaries values(166, "2011-12-27");
+insert into diaries values(167, "2011-12-28");
+insert into diaries values(168, "2011-12-29");
+insert into diaries values(169, "2011-12-30");
+insert into diaries values(170, "2011-12-31");
+insert into diaries values(171, "2012-01-01");
+insert into diaries values(172, "2012-01-02");
+insert into diaries values(173, "2012-01-03");
+insert into diaries values(174, "2012-01-04");
+insert into diaries values(175, "2012-01-05");
+insert into diaries values(176, "2012-01-06");
+insert into diaries values(177, "2012-01-07");
+insert into diaries values(178, "2012-01-08");
+insert into diaries values(179, "2012-01-09");
+insert into diaries values(180, "2012-01-10");
+insert into diaries values(181, "2012-01-11");
+insert into diaries values(182, "2012-01-12");
+insert into diaries values(183, "2012-01-13");
+insert into diaries values(184, "2012-01-14");
+insert into diaries values(185, "2012-01-15");
+insert into diaries values(186, "2012-01-16");
+insert into diaries values(187, "2012-01-17");
+insert into diaries values(188, "2012-01-18");
+insert into diaries values(189, "2012-01-19");
+insert into diaries values(190, "2012-01-20");
+insert into diaries values(191, "2012-01-21");
+insert into diaries values(192, "2012-01-22");
+insert into diaries values(193, "2012-01-23");
+insert into diaries values(194, "2012-01-24");
+insert into diaries values(195, "2012-01-25");
+insert into diaries values(196, "2012-01-26");
+insert into diaries values(197, "2012-01-27");
+insert into diaries values(198, "2012-01-28");
+insert into diaries values(199, "2012-01-29");
+insert into diaries values(200, "2012-01-30");
+insert into diaries values(201, "2012-01-31");
+insert into diaries values(202, "2012-02-01");
+insert into diaries values(203, "2012-02-02");
+insert into diaries values(204, "2012-02-03");
+insert into diaries values(205, "2012-02-04");
+insert into diaries values(206, "2012-02-05");
+insert into diaries values(207, "2012-02-06");
+insert into diaries values(208, "2012-02-07");
+insert into diaries values(209, "2012-02-08");
+insert into diaries values(210, "2012-02-09");
+insert into diaries values(211, "2012-02-10");
+insert into diaries values(212, "2012-02-11");
+insert into diaries values(213, "2012-02-12");
+insert into diaries values(214, "2012-02-13");
+insert into diaries values(215, "2012-02-14");
+insert into diaries values(216, "2012-02-15");
+insert into diaries values(217, "2012-02-16");
+insert into diaries values(218, "2012-02-17");
+insert into diaries values(219, "2012-02-18");
+insert into diaries values(220, "2012-02-19");
+insert into diaries values(221, "2012-02-20");
+insert into diaries values(222, "2012-02-21");
+insert into diaries values(223, "2012-02-22");
+insert into diaries values(224, "2012-02-23");
+insert into diaries values(225, "2012-02-24");
+insert into diaries values(226, "2012-02-25");
+insert into diaries values(227, "2012-02-26");
+insert into diaries values(228, "2012-02-27");
+insert into diaries values(229, "2012-02-28");
+insert into diaries values(230, "2012-02-29");
+insert into diaries values(231, "2012-03-01");
+insert into diaries values(232, "2012-03-02");
+insert into diaries values(233, "2012-03-03");
+insert into diaries values(234, "2012-03-04");
+insert into diaries values(235, "2012-03-05");
+insert into diaries values(236, "2012-03-06");
+insert into diaries values(237, "2012-03-07");
+insert into diaries values(238, "2012-03-08");
+insert into diaries values(239, "2012-03-09");
+insert into diaries values(240, "2012-03-10");
+insert into diaries values(241, "2012-03-11");
+insert into diaries values(242, "2012-03-12");
+insert into diaries values(243, "2012-03-13");
+insert into diaries values(244, "2012-03-14");
+insert into diaries values(245, "2012-03-15");
+insert into diaries values(246, "2012-03-16");
+insert into diaries values(247, "2012-03-17");
+insert into diaries values(248, "2012-03-18");
+insert into diaries values(249, "2012-03-19");
+insert into diaries values(250, "2012-03-20");
+insert into diaries values(251, "2012-03-21");
+insert into diaries values(252, "2012-03-22");
+insert into diaries values(253, "2012-03-23");
+insert into diaries values(254, "2012-03-24");
+insert into diaries values(255, "2012-03-25");
+insert into diaries values(256, "2012-03-26");
+insert into diaries values(257, "2012-03-27");
+insert into diaries values(258, "2012-03-28");
+insert into diaries values(259, "2012-03-29");
+insert into diaries values(260, "2012-03-30");
+insert into diaries values(261, "2012-03-31");
+insert into diaries values(262, "2012-04-01");
+insert into diaries values(263, "2012-04-02");
+insert into diaries values(264, "2012-04-03");
+insert into diaries values(265, "2012-04-04");
+insert into diaries values(266, "2012-04-05");
+insert into diaries values(267, "2012-04-06");
+insert into diaries values(268, "2012-04-07");
+insert into diaries values(269, "2012-04-08");
+insert into diaries values(270, "2012-04-09");
+insert into diaries values(271, "2012-04-10");
+insert into diaries values(272, "2012-04-11");
+insert into diaries values(273, "2012-04-12");
+insert into diaries values(274, "2012-04-13");
+insert into diaries values(275, "2012-04-14");
+insert into diaries values(276, "2012-04-15");
+insert into diaries values(277, "2012-04-16");
+insert into diaries values(278, "2012-04-17");
+insert into diaries values(279, "2012-04-18");
+insert into diaries values(280, "2012-04-19");
+insert into diaries values(281, "2012-04-20");
+insert into diaries values(282, "2012-04-21");
+insert into diaries values(283, "2012-04-22");
+insert into diaries values(284, "2012-04-23");
+insert into diaries values(285, "2012-04-24");
+insert into diaries values(286, "2012-04-25");
+insert into diaries values(287, "2012-04-26");
+insert into diaries values(288, "2012-04-27");
+insert into diaries values(289, "2012-04-28");
+insert into diaries values(290, "2012-04-29");
+insert into diaries values(291, "2012-04-30");
+insert into diaries values(292, "2012-05-01");
+insert into diaries values(293, "2012-05-02");
+insert into diaries values(294, "2012-05-03");
+insert into diaries values(295, "2012-05-04");
+insert into diaries values(296, "2012-05-05");
+insert into diaries values(297, "2012-05-06");
+insert into diaries values(298, "2012-05-07");
+insert into diaries values(299, "2012-05-08");
+insert into diaries values(300, "2012-05-09");
+insert into diaries values(301, "2012-05-10");
+insert into diaries values(302, "2012-05-11");
+insert into diaries values(303, "2012-05-12");
+insert into diaries values(304, "2012-05-13");
+insert into diaries values(305, "2012-05-14");
+insert into diaries values(306, "2012-05-15");
+insert into diaries values(307, "2012-05-16");
+insert into diaries values(308, "2012-05-17");
+insert into diaries values(309, "2012-05-18");
+insert into diaries values(310, "2012-05-19");
+insert into diaries values(311, "2012-05-20");
+insert into diaries values(312, "2012-05-21");
+insert into diaries values(313, "2012-05-22");
+insert into diaries values(314, "2012-05-23");
+insert into diaries values(315, "2012-05-24");
+insert into diaries values(316, "2012-05-25");
+insert into diaries values(317, "2012-05-26");
+insert into diaries values(318, "2012-05-27");
+insert into diaries values(319, "2012-05-28");
+insert into diaries values(320, "2012-05-29");
+insert into diaries values(321, "2012-05-30");
+insert into diaries values(322, "2012-05-31");
+insert into diaries values(323, "2012-06-01");
+insert into diaries values(324, "2012-06-02");
+insert into diaries values(325, "2012-06-03");
+insert into diaries values(326, "2012-06-04");
+insert into diaries values(327, "2012-06-05");
+insert into diaries values(328, "2012-06-06");
+insert into diaries values(329, "2012-06-07");
+insert into diaries values(330, "2012-06-08");
+insert into diaries values(331, "2012-06-09");
+insert into diaries values(332, "2012-06-10");
+insert into diaries values(333, "2012-06-11");
+insert into diaries values(334, "2012-06-12");
+insert into diaries values(335, "2012-06-13");
+insert into diaries values(336, "2012-06-14");
+insert into diaries values(337, "2012-06-15");
+insert into diaries values(338, "2012-06-16");
+insert into diaries values(339, "2012-06-17");
+insert into diaries values(340, "2012-06-18");
+insert into diaries values(341, "2012-06-19");
+insert into diaries values(342, "2012-06-20");
+insert into diaries values(343, "2012-06-21");
+insert into diaries values(344, "2012-06-22");
+insert into diaries values(345, "2012-06-23");
+insert into diaries values(346, "2012-06-24");
+insert into diaries values(347, "2012-06-25");
+insert into diaries values(348, "2012-06-26");
+insert into diaries values(349, "2012-06-27");
+insert into diaries values(350, "2012-06-28");
+insert into diaries values(351, "2012-06-29");
+insert into diaries values(352, "2012-06-30");
+insert into diaries values(353, "2012-07-01");
+insert into diaries values(354, "2012-07-02");
+insert into diaries values(355, "2012-07-03");
+insert into diaries values(356, "2012-07-04");
+insert into diaries values(357, "2012-07-05");
+insert into diaries values(358, "2012-07-06");
+insert into diaries values(359, "2012-07-07");
+insert into diaries values(360, "2012-07-08");
+insert into diaries values(361, "2012-07-09");
+insert into diaries values(362, "2012-07-10");
+insert into diaries values(363, "2012-07-11");
+insert into diaries values(364, "2012-07-12");
+insert into diaries values(365, "2012-07-13");
+insert into diaries values(366, "2012-07-14");
+insert into diaries values(367, "2012-07-15");
+insert into diaries values(368, "2012-07-16");
+insert into diaries values(369, "2012-07-17");
+insert into diaries values(370, "2012-07-18");
+insert into diaries values(371, "2012-07-19");
+insert into diaries values(372, "2012-07-20");
+insert into diaries values(373, "2012-07-21");
+insert into diaries values(374, "2012-07-22");
+insert into diaries values(375, "2012-07-23");
+insert into diaries values(376, "2012-07-24");
+insert into diaries values(377, "2012-07-25");
+insert into diaries values(378, "2012-07-26");
+insert into diaries values(379, "2012-07-27");
+insert into diaries values(380, "2012-07-28");
+insert into diaries values(381, "2012-07-29");
+insert into diaries values(382, "2012-07-30");
+insert into diaries values(383, "2012-07-31");
+insert into diaries values(384, "2012-08-01");
+insert into diaries values(385, "2012-08-02");
+insert into diaries values(386, "2012-08-03");
+insert into diaries values(387, "2012-08-04");
+insert into diaries values(388, "2012-08-05");
+insert into diaries values(389, "2012-08-06");
+insert into diaries values(390, "2012-08-07");
+insert into diaries values(391, "2012-08-08");
+insert into diaries values(392, "2012-08-09");
+insert into diaries values(393, "2012-08-10");
+insert into diaries values(394, "2012-08-11");
+insert into diaries values(395, "2012-08-12");
+insert into diaries values(396, "2012-08-13");
+insert into diaries values(397, "2012-08-14");
+insert into diaries values(398, "2012-08-15");
+insert into diaries values(399, "2012-08-16");
+insert into diaries values(400, "2012-08-17");
+insert into diaries values(401, "2012-08-18");
+insert into diaries values(402, "2012-08-19");
+insert into diaries values(403, "2012-08-20");
+insert into diaries values(404, "2012-08-21");
+insert into diaries values(405, "2012-08-22");
+insert into diaries values(406, "2012-08-23");
+insert into diaries values(407, "2012-08-24");
+insert into diaries values(408, "2012-08-25");
+insert into diaries values(409, "2012-08-26");
+insert into diaries values(410, "2012-08-27");
+insert into diaries values(411, "2012-08-28");
+insert into diaries values(412, "2012-08-29");
+insert into diaries values(413, "2012-08-30");
+insert into diaries values(414, "2012-08-31");
+insert into diaries values(415, "2012-09-01");
+insert into diaries values(416, "2012-09-02");
+insert into diaries values(417, "2012-09-03");
+insert into diaries values(418, "2012-09-04");
+insert into diaries values(419, "2012-09-05");
+insert into diaries values(420, "2012-09-06");
+insert into diaries values(421, "2012-09-07");
+insert into diaries values(422, "2012-09-08");
+insert into diaries values(423, "2012-09-09");
+insert into diaries values(424, "2012-09-10");
+insert into diaries values(425, "2012-09-11");
+insert into diaries values(426, "2012-09-12");
+insert into diaries values(427, "2012-09-13");
+insert into diaries values(428, "2012-09-14");
+insert into diaries values(429, "2012-09-15");
+insert into diaries values(430, "2012-09-16");
+insert into diaries values(431, "2012-09-17");
+insert into diaries values(432, "2012-09-18");
+insert into diaries values(433, "2012-09-19");
+insert into diaries values(434, "2012-09-20");
+insert into diaries values(435, "2012-09-21");
+insert into diaries values(436, "2012-09-22");
+insert into diaries values(437, "2012-09-23");
+insert into diaries values(438, "2012-09-24");
+insert into diaries values(439, "2012-09-25");
+insert into diaries values(440, "2012-09-26");
+insert into diaries values(441, "2012-09-27");
+insert into diaries values(442, "2012-09-28");
+insert into diaries values(443, "2012-09-29");
+insert into diaries values(444, "2012-09-30");
+insert into diaries values(445, "2012-10-01");
+insert into diaries values(446, "2012-10-02");
+insert into diaries values(447, "2012-10-03");
+insert into diaries values(448, "2012-10-04");
+insert into diaries values(449, "2012-10-05");
+insert into diaries values(450, "2012-10-06");
+insert into diaries values(451, "2012-10-07");
+insert into diaries values(452, "2012-10-08");
+insert into diaries values(453, "2012-10-09");
+insert into diaries values(454, "2012-10-10");
+insert into diaries values(455, "2012-10-11");
+insert into diaries values(456, "2012-10-12");
+insert into diaries values(457, "2012-10-13");
+insert into diaries values(458, "2012-10-14");
+insert into diaries values(459, "2012-10-15");
+insert into diaries values(460, "2012-10-16");
+insert into diaries values(461, "2012-10-17");
+insert into diaries values(462, "2012-10-18");
+insert into diaries values(463, "2012-10-19");
+insert into diaries values(464, "2012-10-20");
+insert into diaries values(465, "2012-10-21");
+insert into diaries values(466, "2012-10-22");
+insert into diaries values(467, "2012-10-23");
+insert into diaries values(468, "2012-10-24");
+insert into diaries values(469, "2012-10-25");
+insert into diaries values(470, "2012-10-26");
+insert into diaries values(471, "2012-10-27");
+insert into diaries values(472, "2012-10-28");
+insert into diaries values(473, "2012-10-29");
+insert into diaries values(474, "2012-10-30");
+insert into diaries values(475, "2012-10-31");
+insert into diaries values(476, "2012-11-01");
+insert into diaries values(477, "2012-11-02");
+insert into diaries values(478, "2012-11-03");
+insert into diaries values(479, "2012-11-04");
+insert into diaries values(480, "2012-11-05");
+insert into diaries values(481, "2012-11-06");
+insert into diaries values(482, "2012-11-07");
+insert into diaries values(483, "2012-11-08");
+insert into diaries values(484, "2012-11-09");
+insert into diaries values(485, "2012-11-10");
+insert into diaries values(486, "2012-11-11");
+insert into diaries values(487, "2012-11-12");
+insert into diaries values(488, "2012-11-13");
+insert into diaries values(489, "2012-11-14");
+insert into diaries values(490, "2012-11-15");
+insert into diaries values(491, "2012-11-16");
+insert into diaries values(492, "2012-11-17");
+insert into diaries values(493, "2012-11-18");
+insert into diaries values(494, "2012-11-19");
+insert into diaries values(495, "2012-11-20");
+insert into diaries values(496, "2012-11-21");
+insert into diaries values(497, "2012-11-22");
+insert into diaries values(498, "2012-11-23");
+insert into diaries values(499, "2012-11-24");
+insert into diaries values(500, "2012-11-25");
+insert into diaries values(501, "2012-11-26");
+insert into diaries values(502, "2012-11-27");
+insert into diaries values(503, "2012-11-28");
+insert into diaries values(504, "2012-11-29");
+insert into diaries values(505, "2012-11-30");
+insert into diaries values(506, "2012-12-01");
+insert into diaries values(507, "2012-12-02");
+insert into diaries values(508, "2012-12-03");
+insert into diaries values(509, "2012-12-04");
+insert into diaries values(510, "2012-12-05");
+insert into diaries values(511, "2012-12-06");
+insert into diaries values(512, "2012-12-07");
+insert into diaries values(513, "2012-12-08");
+insert into diaries values(514, "2012-12-09");
+insert into diaries values(515, "2012-12-10");
+insert into diaries values(516, "2012-12-11");
+insert into diaries values(517, "2012-12-12");
+insert into diaries values(518, "2012-12-13");
+insert into diaries values(519, "2012-12-14");
+insert into diaries values(520, "2012-12-15");
+insert into diaries values(521, "2012-12-16");
+insert into diaries values(522, "2012-12-17");
+insert into diaries values(523, "2012-12-18");
+insert into diaries values(524, "2012-12-19");
+insert into diaries values(525, "2012-12-20");
+insert into diaries values(526, "2012-12-21");
+insert into diaries values(527, "2012-12-22");
+insert into diaries values(528, "2012-12-23");
+insert into diaries values(529, "2012-12-24");
+insert into diaries values(530, "2012-12-25");
+insert into diaries values(531, "2012-12-26");
+insert into diaries values(532, "2012-12-27");
+insert into diaries values(533, "2012-12-28");
+insert into diaries values(534, "2012-12-29");
+insert into diaries values(535, "2012-12-30");
+insert into diaries values(536, "2012-12-31");
+insert into diaries values(537, "2013-01-01");
+insert into diaries values(538, "2013-01-02");
+insert into diaries values(539, "2013-01-03");
+insert into diaries values(540, "2013-01-04");
+insert into diaries values(541, "2013-01-05");
+insert into diaries values(542, "2013-01-06");
+insert into diaries values(543, "2013-01-07");
+insert into diaries values(544, "2013-01-08");
+insert into diaries values(545, "2013-01-09");
+insert into diaries values(546, "2013-01-10");
+insert into diaries values(547, "2013-01-11");
+insert into diaries values(548, "2013-01-12");
+insert into diaries values(549, "2013-01-13");
+insert into diaries values(550, "2013-01-14");
+insert into diaries values(551, "2013-01-15");
+insert into diaries values(552, "2013-01-16");
+insert into diaries values(553, "2013-01-17");
+insert into diaries values(554, "2013-01-18");
+insert into diaries values(555, "2013-01-19");
+insert into diaries values(556, "2013-01-20");
+insert into diaries values(557, "2013-01-21");
+insert into diaries values(558, "2013-01-22");
+insert into diaries values(559, "2013-01-23");
+insert into diaries values(560, "2013-01-24");
+insert into diaries values(561, "2013-01-25");
+insert into diaries values(562, "2013-01-26");
+insert into diaries values(563, "2013-01-27");
+insert into diaries values(564, "2013-01-28");
+insert into diaries values(565, "2013-01-29");
+insert into diaries values(566, "2013-01-30");
+insert into diaries values(567, "2013-01-31");
+insert into diaries values(568, "2013-02-01");
+insert into diaries values(569, "2013-02-02");
+insert into diaries values(570, "2013-02-03");
+insert into diaries values(571, "2013-02-04");
+insert into diaries values(572, "2013-02-05");
+insert into diaries values(573, "2013-02-06");
+insert into diaries values(574, "2013-02-07");
+insert into diaries values(575, "2013-02-08");
+insert into diaries values(576, "2013-02-09");
+insert into diaries values(577, "2013-02-10");
+insert into diaries values(578, "2013-02-11");
+insert into diaries values(579, "2013-02-12");
+insert into diaries values(580, "2013-02-13");
+insert into diaries values(581, "2013-02-14");
+insert into diaries values(582, "2013-02-15");
+insert into diaries values(583, "2013-02-16");
+insert into diaries values(584, "2013-02-17");
+insert into diaries values(585, "2013-02-18");
+insert into diaries values(586, "2013-02-19");
+insert into diaries values(587, "2013-02-20");
+insert into diaries values(588, "2013-02-21");
+insert into diaries values(589, "2013-02-22");
+insert into diaries values(590, "2013-02-23");
+insert into diaries values(591, "2013-02-24");
+insert into diaries values(592, "2013-02-25");
+insert into diaries values(593, "2013-02-26");
+insert into diaries values(594, "2013-02-27");
+insert into diaries values(595, "2013-02-28");
+insert into diaries values(596, "2013-03-01");
+insert into diaries values(597, "2013-03-02");
+insert into diaries values(598, "2013-03-03");
+insert into diaries values(599, "2013-03-04");
+insert into diaries values(600, "2013-03-05");
+insert into diaries values(601, "2013-03-06");
+insert into diaries values(602, "2013-03-07");
+insert into diaries values(603, "2013-03-08");
+insert into diaries values(604, "2013-03-09");
+insert into diaries values(605, "2013-03-10");
+insert into diaries values(606, "2013-03-11");
+insert into diaries values(607, "2013-03-12");
+insert into diaries values(608, "2013-03-13");
+insert into diaries values(609, "2013-03-14");
+insert into diaries values(610, "2013-03-15");
+insert into diaries values(611, "2013-03-16");
+insert into diaries values(612, "2013-03-17");
+insert into diaries values(613, "2013-03-18");
+insert into diaries values(614, "2013-03-19");
+insert into diaries values(615, "2013-03-20");
+insert into diaries values(616, "2013-03-21");
+insert into diaries values(617, "2013-03-22");
+insert into diaries values(618, "2013-03-23");
+insert into diaries values(619, "2013-03-24");
+insert into diaries values(620, "2013-03-25");
+insert into diaries values(621, "2013-03-26");
+insert into diaries values(622, "2013-03-27");
+insert into diaries values(623, "2013-03-28");
+insert into diaries values(624, "2013-03-29");
+insert into diaries values(625, "2013-03-30");
+insert into diaries values(626, "2013-03-31");
+insert into diaries values(627, "2013-04-01");
+insert into diaries values(628, "2013-04-02");
+insert into diaries values(629, "2013-04-03");
+insert into diaries values(630, "2013-04-04");
+insert into diaries values(631, "2013-04-05");
+insert into diaries values(632, "2013-04-06");
+insert into diaries values(633, "2013-04-07");
+insert into diaries values(634, "2013-04-08");
+insert into diaries values(635, "2013-04-09");
+insert into diaries values(636, "2013-04-10");
+insert into diaries values(637, "2013-04-11");
+insert into diaries values(638, "2013-04-12");
+insert into diaries values(639, "2013-04-13");
+insert into diaries values(640, "2013-04-14");
+insert into diaries values(641, "2013-04-15");
+insert into diaries values(642, "2013-04-16");
+insert into diaries values(643, "2013-04-17");
+insert into diaries values(644, "2013-04-18");
+insert into diaries values(645, "2013-04-19");
+insert into diaries values(646, "2013-04-20");
+insert into diaries values(647, "2013-04-21");
+insert into diaries values(648, "2013-04-22");
+insert into diaries values(649, "2013-04-23");
+insert into diaries values(650, "2013-04-24");
+insert into diaries values(651, "2013-04-25");
+insert into diaries values(652, "2013-04-26");
+insert into diaries values(653, "2013-04-27");
+insert into diaries values(654, "2013-04-28");
+insert into diaries values(655, "2013-04-29");
+insert into diaries values(656, "2013-04-30");
+insert into diaries values(657, "2013-05-01");
+insert into diaries values(658, "2013-05-02");
+insert into diaries values(659, "2013-05-03");
+insert into diaries values(660, "2013-05-04");
+insert into diaries values(661, "2013-05-05");
+insert into diaries values(662, "2013-05-06");
+insert into diaries values(663, "2013-05-07");
+insert into diaries values(664, "2013-05-08");
+insert into diaries values(665, "2013-05-09");
+insert into diaries values(666, "2013-05-10");
+insert into diaries values(667, "2013-05-11");
+insert into diaries values(668, "2013-05-12");
+insert into diaries values(669, "2013-05-13");
+insert into diaries values(670, "2013-05-14");
+insert into diaries values(671, "2013-05-15");
+insert into diaries values(672, "2013-05-16");
+insert into diaries values(673, "2013-05-17");
+insert into diaries values(674, "2013-05-18");
+insert into diaries values(675, "2013-05-19");
+insert into diaries values(676, "2013-05-20");
+insert into diaries values(677, "2013-05-21");
+insert into diaries values(678, "2013-05-22");
+insert into diaries values(679, "2013-05-23");
+insert into diaries values(680, "2013-05-24");
+insert into diaries values(681, "2013-05-25");
+insert into diaries values(682, "2013-05-26");
+insert into diaries values(683, "2013-05-27");
+insert into diaries values(684, "2013-05-28");
+insert into diaries values(685, "2013-05-29");
+insert into diaries values(686, "2013-05-30");
+insert into diaries values(687, "2013-05-31");
+insert into diaries values(688, "2013-06-01");
+insert into diaries values(689, "2013-06-02");
+insert into diaries values(690, "2013-06-03");
+insert into diaries values(691, "2013-06-04");
+insert into diaries values(692, "2013-06-05");
+insert into diaries values(693, "2013-06-06");
+insert into diaries values(694, "2013-06-07");
+insert into diaries values(695, "2013-06-08");
+insert into diaries values(696, "2013-06-09");
+insert into diaries values(697, "2013-06-10");
+insert into diaries values(698, "2013-06-11");
+insert into diaries values(699, "2013-06-12");
+insert into diaries values(700, "2013-06-13");
+insert into diaries values(701, "2013-06-14");
+insert into diaries values(702, "2013-06-15");
+insert into diaries values(703, "2013-06-16");
+insert into diaries values(704, "2013-06-17");
+insert into diaries values(705, "2013-06-18");
+insert into diaries values(706, "2013-06-19");
+insert into diaries values(707, "2013-06-20");
+insert into diaries values(708, "2013-06-21");
+insert into diaries values(709, "2013-06-22");
+insert into diaries values(710, "2013-06-23");
+insert into diaries values(711, "2013-06-24");
+insert into diaries values(712, "2013-06-25");
+insert into diaries values(713, "2013-06-26");
+insert into diaries values(714, "2013-06-27");
+insert into diaries values(715, "2013-06-28");
+insert into diaries values(716, "2013-06-29");
+insert into diaries values(717, "2013-06-30");
+insert into diaries values(718, "2013-07-01");
+insert into diaries values(719, "2013-07-02");
+insert into diaries values(720, "2013-07-03");
+insert into diaries values(721, "2013-07-04");
+insert into diaries values(722, "2013-07-05");
+insert into diaries values(723, "2013-07-06");
+insert into diaries values(724, "2013-07-07");
+insert into diaries values(725, "2013-07-08");
+insert into diaries values(726, "2013-07-09");
+insert into diaries values(727, "2013-07-10");
+insert into diaries values(728, "2013-07-11");
+insert into diaries values(729, "2013-07-12");
+insert into diaries values(730, "2013-07-13");
+insert into diaries values(731, "2013-07-14");
+insert into diaries values(732, "2013-07-15");
+insert into diaries values(733, "2013-07-16");
+insert into diaries values(734, "2013-07-17");
+insert into diaries values(735, "2013-07-18");
+insert into diaries values(736, "2013-07-19");
+insert into diaries values(737, "2013-07-20");
+insert into diaries values(738, "2013-07-21");
+insert into diaries values(739, "2013-07-22");
+insert into diaries values(740, "2013-07-23");
+insert into diaries values(741, "2013-07-24");
+insert into diaries values(742, "2013-07-25");
+insert into diaries values(743, "2013-07-26");
+insert into diaries values(744, "2013-07-27");
+insert into diaries values(745, "2013-07-28");
+insert into diaries values(746, "2013-07-29");
+insert into diaries values(747, "2013-07-30");
+insert into diaries values(748, "2013-07-31");
+insert into diaries values(749, "2013-08-01");
+insert into diaries values(750, "2013-08-02");
+insert into diaries values(751, "2013-08-03");
+insert into diaries values(752, "2013-08-04");
+insert into diaries values(753, "2013-08-05");
+insert into diaries values(754, "2013-08-06");
+insert into diaries values(755, "2013-08-07");
+insert into diaries values(756, "2013-08-08");
+insert into diaries values(757, "2013-08-09");
+insert into diaries values(758, "2013-08-10");
+insert into diaries values(759, "2013-08-11");
+insert into diaries values(760, "2013-08-12");
+insert into diaries values(761, "2013-08-13");
+insert into diaries values(762, "2013-08-14");
+insert into diaries values(763, "2013-08-15");
+insert into diaries values(764, "2013-08-16");
+insert into diaries values(765, "2013-08-17");
+insert into diaries values(766, "2013-08-18");
+insert into diaries values(767, "2013-08-19");
+insert into diaries values(768, "2013-08-20");
+insert into diaries values(769, "2013-08-21");
+insert into diaries values(770, "2013-08-22");
+insert into diaries values(771, "2013-08-23");
+insert into diaries values(772, "2013-08-24");
+insert into diaries values(773, "2013-08-25");
+insert into diaries values(774, "2013-08-26");
+insert into diaries values(775, "2013-08-27");
+insert into diaries values(776, "2013-08-28");
+insert into diaries values(777, "2013-08-29");
+insert into diaries values(778, "2013-08-30");
+insert into diaries values(779, "2013-08-31");
+insert into diaries values(780, "2013-09-01");
+insert into diaries values(781, "2013-09-02");
+insert into diaries values(782, "2013-09-03");
+insert into diaries values(783, "2013-09-04");
+insert into diaries values(784, "2013-09-05");
+insert into diaries values(785, "2013-09-06");
+insert into diaries values(786, "2013-09-07");
+insert into diaries values(787, "2013-09-08");
+insert into diaries values(788, "2013-09-09");
+insert into diaries values(789, "2013-09-10");
+insert into diaries values(790, "2013-09-11");
+insert into diaries values(791, "2013-09-12");
+insert into diaries values(792, "2013-09-13");
+insert into diaries values(793, "2013-09-14");
+insert into diaries values(794, "2013-09-15");
+insert into diaries values(795, "2013-09-16");
+insert into diaries values(796, "2013-09-17");
+insert into diaries values(797, "2013-09-18");
+insert into diaries values(798, "2013-09-19");
+insert into diaries values(799, "2013-09-20");
+insert into diaries values(800, "2013-09-21");
+insert into diaries values(801, "2013-09-22");
+insert into diaries values(802, "2013-09-23");
+insert into diaries values(803, "2013-09-24");
+insert into diaries values(804, "2013-09-25");
+insert into diaries values(805, "2013-09-26");
+insert into diaries values(806, "2013-09-27");
+insert into diaries values(807, "2013-09-28");
+insert into diaries values(808, "2013-09-29");
+insert into diaries values(809, "2013-09-30");
+insert into diaries values(810, "2013-10-01");
+insert into diaries values(811, "2013-10-02");
+insert into diaries values(812, "2013-10-03");
+insert into diaries values(813, "2013-10-04");
+insert into diaries values(814, "2013-10-05");
+insert into diaries values(815, "2013-10-06");
+insert into diaries values(816, "2013-10-07");
+insert into diaries values(817, "2013-10-08");
+insert into diaries values(818, "2013-10-09");
+insert into diaries values(819, "2013-10-10");
+insert into diaries values(820, "2013-10-11");
+insert into diaries values(821, "2013-10-12");
+insert into diaries values(822, "2013-10-13");
+insert into diaries values(823, "2013-10-14");
+insert into diaries values(824, "2013-10-15");
+insert into diaries values(825, "2013-10-16");
+insert into diaries values(826, "2013-10-17");
+insert into diaries values(827, "2013-10-18");
+insert into diaries values(828, "2013-10-19");
+insert into diaries values(829, "2013-10-20");
+insert into diaries values(830, "2013-10-21");
+insert into diaries values(831, "2013-10-22");
+insert into diaries values(832, "2013-10-23");
+insert into diaries values(833, "2013-10-24");
+insert into diaries values(834, "2013-10-25");
+insert into diaries values(835, "2013-10-26");
+insert into diaries values(836, "2013-10-27");
+insert into diaries values(837, "2013-10-28");
+insert into diaries values(838, "2013-10-29");
+insert into diaries values(839, "2013-10-30");
+insert into diaries values(840, "2013-10-31");
+insert into diaries values(841, "2013-11-01");
+insert into diaries values(842, "2013-11-02");
+insert into diaries values(843, "2013-11-03");
+insert into diaries values(844, "2013-11-04");
+insert into diaries values(845, "2013-11-05");
+insert into diaries values(846, "2013-11-06");
+insert into diaries values(847, "2013-11-07");
+insert into diaries values(848, "2013-11-08");
+insert into diaries values(849, "2013-11-09");
+insert into diaries values(850, "2013-11-10");
+insert into diaries values(851, "2013-11-11");
+insert into diaries values(852, "2013-11-12");
+insert into diaries values(853, "2013-11-13");
+insert into diaries values(854, "2013-11-14");
+insert into diaries values(855, "2013-11-15");
+insert into diaries values(856, "2013-11-16");
+insert into diaries values(857, "2013-11-17");
+insert into diaries values(858, "2013-11-18");
+insert into diaries values(859, "2013-11-19");
+insert into diaries values(860, "2013-11-20");
+insert into diaries values(861, "2013-11-21");
+insert into diaries values(862, "2013-11-22");
+insert into diaries values(863, "2013-11-23");
+insert into diaries values(864, "2013-11-24");
+insert into diaries values(865, "2013-11-25");
+insert into diaries values(866, "2013-11-26");
+insert into diaries values(867, "2013-11-27");
+insert into diaries values(868, "2013-11-28");
+insert into diaries values(869, "2013-11-29");
+insert into diaries values(870, "2013-11-30");
+insert into diaries values(871, "2013-12-01");
+insert into diaries values(872, "2013-12-02");
+insert into diaries values(873, "2013-12-03");
+insert into diaries values(874, "2013-12-04");
+insert into diaries values(875, "2013-12-05");
+insert into diaries values(876, "2013-12-06");
+insert into diaries values(877, "2013-12-07");
+insert into diaries values(878, "2013-12-08");
+insert into diaries values(879, "2013-12-09");
+insert into diaries values(880, "2013-12-10");
+insert into diaries values(881, "2013-12-11");
+insert into diaries values(882, "2013-12-12");
+insert into diaries values(883, "2013-12-13");
+insert into diaries values(884, "2013-12-14");
+insert into diaries values(885, "2013-12-15");
+insert into diaries values(886, "2013-12-16");
+insert into diaries values(887, "2013-12-17");
+insert into diaries values(888, "2013-12-18");
+insert into diaries values(889, "2013-12-19");
+insert into diaries values(890, "2013-12-20");
+insert into diaries values(891, "2013-12-21");
+insert into diaries values(892, "2013-12-22");
+insert into diaries values(893, "2013-12-23");
+insert into diaries values(894, "2013-12-24");
+insert into diaries values(895, "2013-12-25");
+insert into diaries values(896, "2013-12-26");
+insert into diaries values(897, "2013-12-27");
+insert into diaries values(898, "2013-12-28");
+insert into diaries values(899, "2013-12-29");
+insert into diaries values(900, "2013-12-30");
+insert into diaries values(901, "2013-12-31");
+insert into diaries values(902, "2014-01-01");
+insert into diaries values(903, "2014-01-02");
+insert into diaries values(904, "2014-01-03");
+insert into diaries values(905, "2014-01-04");
+insert into diaries values(906, "2014-01-05");
+insert into diaries values(907, "2014-01-06");
+insert into diaries values(908, "2014-01-07");
+insert into diaries values(909, "2014-01-08");
+insert into diaries values(910, "2014-01-09");
+insert into diaries values(911, "2014-01-10");
+insert into diaries values(912, "2014-01-11");
+insert into diaries values(913, "2014-01-12");
+insert into diaries values(914, "2014-01-13");
+insert into diaries values(915, "2014-01-14");
+insert into diaries values(916, "2014-01-15");
+insert into diaries values(917, "2014-01-16");
+insert into diaries values(918, "2014-01-17");
+insert into diaries values(919, "2014-01-18");
+insert into diaries values(920, "2014-01-19");
+insert into diaries values(921, "2014-01-20");
+insert into diaries values(922, "2014-01-21");
+insert into diaries values(923, "2014-01-22");
+insert into diaries values(924, "2014-01-23");
+insert into diaries values(925, "2014-01-24");
+insert into diaries values(926, "2014-01-25");
+insert into diaries values(927, "2014-01-26");
+insert into diaries values(928, "2014-01-27");
+insert into diaries values(929, "2014-01-28");
+insert into diaries values(930, "2014-01-29");
+insert into diaries values(931, "2014-01-30");
+insert into diaries values(932, "2014-01-31");
+insert into diaries values(933, "2014-02-01");
+insert into diaries values(934, "2014-02-02");
+insert into diaries values(935, "2014-02-03");
+insert into diaries values(936, "2014-02-04");
+insert into diaries values(937, "2014-02-05");
+insert into diaries values(938, "2014-02-06");
+insert into diaries values(939, "2014-02-07");
+insert into diaries values(940, "2014-02-08");
+insert into diaries values(941, "2014-02-09");
+insert into diaries values(942, "2014-02-10");
+insert into diaries values(943, "2014-02-11");
+insert into diaries values(944, "2014-02-12");
+insert into diaries values(945, "2014-02-13");
+insert into diaries values(946, "2014-02-14");
+insert into diaries values(947, "2014-02-15");
+insert into diaries values(948, "2014-02-16");
+insert into diaries values(949, "2014-02-17");
+insert into diaries values(950, "2014-02-18");
+insert into diaries values(951, "2014-02-19");
+insert into diaries values(952, "2014-02-20");
+insert into diaries values(953, "2014-02-21");
+insert into diaries values(954, "2014-02-22");
+insert into diaries values(955, "2014-02-23");
+insert into diaries values(956, "2014-02-24");
+insert into diaries values(957, "2014-02-25");
+insert into diaries values(958, "2014-02-26");
+insert into diaries values(959, "2014-02-27");
+insert into diaries values(960, "2014-02-28");
+insert into diaries values(961, "2014-03-01");
+insert into diaries values(962, "2014-03-02");
+insert into diaries values(963, "2014-03-03");
+insert into diaries values(964, "2014-03-04");
+insert into diaries values(965, "2014-03-05");
+insert into diaries values(966, "2014-03-06");
+insert into diaries values(967, "2014-03-07");
+insert into diaries values(968, "2014-03-08");
+insert into diaries values(969, "2014-03-09");
+insert into diaries values(970, "2014-03-10");
+insert into diaries values(971, "2014-03-11");
+insert into diaries values(972, "2014-03-12");
+insert into diaries values(973, "2014-03-13");
+insert into diaries values(974, "2014-03-14");
+insert into diaries values(975, "2014-03-15");
+insert into diaries values(976, "2014-03-16");
+insert into diaries values(977, "2014-03-17");
+insert into diaries values(978, "2014-03-18");
+insert into diaries values(979, "2014-03-19");
+insert into diaries values(980, "2014-03-20");
+insert into diaries values(981, "2014-03-21");
+insert into diaries values(982, "2014-03-22");
+insert into diaries values(983, "2014-03-23");
+insert into diaries values(984, "2014-03-24");
+insert into diaries values(985, "2014-03-25");
+insert into diaries values(986, "2014-03-26");
+insert into diaries values(987, "2014-03-27");
+insert into diaries values(988, "2014-03-28");
+insert into diaries values(989, "2014-03-29");
+insert into diaries values(990, "2014-03-30");
+insert into diaries values(991, "2014-03-31");
+insert into diaries values(992, "2014-04-01");
+insert into diaries values(993, "2014-04-02");
+insert into diaries values(994, "2014-04-03");
+insert into diaries values(995, "2014-04-04");
+insert into diaries values(996, "2014-04-05");
+insert into diaries values(997, "2014-04-06");
+insert into diaries values(998, "2014-04-07");
+insert into diaries values(999, "2014-04-08");
+insert into diaries values(1000, "2014-04-09");
+insert into diaries values(1001, "2014-04-10");
+insert into diaries values(1002, "2014-04-11");
+insert into diaries values(1003, "2014-04-12");
+insert into diaries values(1004, "2014-04-13");
+insert into diaries values(1005, "2014-04-14");
+insert into diaries values(1006, "2014-04-15");
+insert into diaries values(1007, "2014-04-16");
+insert into diaries values(1008, "2014-04-17");
+insert into diaries values(1009, "2014-04-18");
+insert into diaries values(1010, "2014-04-19");
+insert into diaries values(1011, "2014-04-20");
+insert into diaries values(1012, "2014-04-21");
+insert into diaries values(1013, "2014-04-22");
+insert into diaries values(1014, "2014-04-23");
+insert into diaries values(1015, "2014-04-24");
+insert into diaries values(1016, "2014-04-25");
+insert into diaries values(1017, "2014-04-26");
+insert into diaries values(1018, "2014-04-27");
+insert into diaries values(1019, "2014-04-28");
+insert into diaries values(1020, "2014-04-29");
+insert into diaries values(1021, "2014-04-30");
+insert into diaries values(1022, "2014-05-01");
+insert into diaries values(1023, "2014-05-02");
+insert into diaries values(1024, "2014-05-03");
+insert into diaries values(1025, "2014-05-04");
+insert into diaries values(1026, "2014-05-05");
+insert into diaries values(1027, "2014-05-06");
+insert into diaries values(1028, "2014-05-07");
+insert into diaries values(1029, "2014-05-08");
+insert into diaries values(1030, "2014-05-09");
+insert into diaries values(1031, "2014-05-10");
+insert into diaries values(1032, "2014-05-11");
+insert into diaries values(1033, "2014-05-12");
+insert into diaries values(1034, "2014-05-13");
+insert into diaries values(1035, "2014-05-14");
+insert into diaries values(1036, "2014-05-15");
+insert into diaries values(1037, "2014-05-16");
+insert into diaries values(1038, "2014-05-17");
+insert into diaries values(1039, "2014-05-18");
+insert into diaries values(1040, "2014-05-19");
+insert into diaries values(1041, "2014-05-20");
+insert into diaries values(1042, "2014-05-21");
+insert into diaries values(1043, "2014-05-22");
+insert into diaries values(1044, "2014-05-23");
+insert into diaries values(1045, "2014-05-24");
+insert into diaries values(1046, "2014-05-25");
+insert into diaries values(1047, "2014-05-26");
+insert into diaries values(1048, "2014-05-27");
+insert into diaries values(1049, "2014-05-28");
+insert into diaries values(1050, "2014-05-29");
+insert into diaries values(1051, "2014-05-30");
+insert into diaries values(1052, "2014-05-31");
+insert into diaries values(1053, "2014-06-01");
+insert into diaries values(1054, "2014-06-02");
+insert into diaries values(1055, "2014-06-03");
+insert into diaries values(1056, "2014-06-04");
+insert into diaries values(1057, "2014-06-05");
+insert into diaries values(1058, "2014-06-06");
+insert into diaries values(1059, "2014-06-07");
+insert into diaries values(1060, "2014-06-08");
+insert into diaries values(1061, "2014-06-09");
+insert into diaries values(1062, "2014-06-10");
+insert into diaries values(1063, "2014-06-11");
+insert into diaries values(1064, "2014-06-12");
+insert into diaries values(1065, "2014-06-13");
+insert into diaries values(1066, "2014-06-14");
+insert into diaries values(1067, "2014-06-15");
+insert into diaries values(1068, "2014-06-16");
+insert into diaries values(1069, "2014-06-17");
+insert into diaries values(1070, "2014-06-18");
+insert into diaries values(1071, "2014-06-19");
+insert into diaries values(1072, "2014-06-20");
+insert into diaries values(1073, "2014-06-21");
+insert into diaries values(1074, "2014-06-22");
+insert into diaries values(1075, "2014-06-23");
+insert into diaries values(1076, "2014-06-24");
+insert into diaries values(1077, "2014-06-25");
+insert into diaries values(1078, "2014-06-26");
+insert into diaries values(1079, "2014-06-27");
+insert into diaries values(1080, "2014-06-28");
+insert into diaries values(1081, "2014-06-29");
+insert into diaries values(1082, "2014-06-30");
+insert into diaries values(1083, "2014-07-01");
+insert into diaries values(1084, "2014-07-02");
+insert into diaries values(1085, "2014-07-03");
+insert into diaries values(1086, "2014-07-04");
+insert into diaries values(1087, "2014-07-05");
+insert into diaries values(1088, "2014-07-06");
+insert into diaries values(1089, "2014-07-07");
+insert into diaries values(1090, "2014-07-08");
+insert into diaries values(1091, "2014-07-09");
+insert into diaries values(1092, "2014-07-10");
+insert into diaries values(1093, "2014-07-11");
+insert into diaries values(1094, "2014-07-12");
+insert into diaries values(1095, "2014-07-13");
+insert into diaries values(1096, "2014-07-14");
+insert into diaries values(1097, "2014-07-15");
+insert into diaries values(1098, "2014-07-16");
+insert into diaries values(1099, "2014-07-17");
+insert into diaries values(1100, "2014-07-18");
+insert into diaries values(1101, "2014-07-19");
+insert into diaries values(1102, "2014-07-20");
+insert into diaries values(1103, "2014-07-21");
+insert into diaries values(1104, "2014-07-22");
+insert into diaries values(1105, "2014-07-23");
+insert into diaries values(1106, "2014-07-24");
+insert into diaries values(1107, "2014-07-25");
+insert into diaries values(1108, "2014-07-26");
+insert into diaries values(1109, "2014-07-27");
+insert into diaries values(1110, "2014-07-28");
+insert into diaries values(1111, "2014-07-29");
+insert into diaries values(1112, "2014-07-30");
+insert into diaries values(1113, "2014-07-31");
+insert into diaries values(1114, "2014-08-01");
+insert into diaries values(1115, "2014-08-02");
+insert into diaries values(1116, "2014-08-03");
+insert into diaries values(1117, "2014-08-04");
+insert into diaries values(1118, "2014-08-05");
+insert into diaries values(1119, "2014-08-06");
+insert into diaries values(1120, "2014-08-07");
+insert into diaries values(1121, "2014-08-08");
+insert into diaries values(1122, "2014-08-09");
+insert into diaries values(1123, "2014-08-10");
+insert into diaries values(1124, "2014-08-11");
+insert into diaries values(1125, "2014-08-12");
+insert into diaries values(1126, "2014-08-13");
+insert into diaries values(1127, "2014-08-14");
+insert into diaries values(1128, "2014-08-15");
+insert into diaries values(1129, "2014-08-16");
+insert into diaries values(1130, "2014-08-17");
+insert into diaries values(1131, "2014-08-18");
+insert into diaries values(1132, "2014-08-19");
+insert into diaries values(1133, "2014-08-20");
+insert into diaries values(1134, "2014-08-21");
+insert into diaries values(1135, "2014-08-22");
+insert into diaries values(1136, "2014-08-23");
+insert into diaries values(1137, "2014-08-24");
+insert into diaries values(1138, "2014-08-25");
+insert into diaries values(1139, "2014-08-26");
+insert into diaries values(1140, "2014-08-27");
+insert into diaries values(1141, "2014-08-28");
+insert into diaries values(1142, "2014-08-29");
+insert into diaries values(1143, "2014-08-30");
+insert into diaries values(1144, "2014-08-31");
+insert into diaries values(1145, "2014-09-01");
+insert into diaries values(1146, "2014-09-02");
+insert into diaries values(1147, "2014-09-03");
+insert into diaries values(1148, "2014-09-04");
+insert into diaries values(1149, "2014-09-05");
+insert into diaries values(1150, "2014-09-06");
+insert into diaries values(1151, "2014-09-07");
+insert into diaries values(1152, "2014-09-08");
+insert into diaries values(1153, "2014-09-09");
+insert into diaries values(1154, "2014-09-10");
+insert into diaries values(1155, "2014-09-11");
+insert into diaries values(1156, "2014-09-12");
+insert into diaries values(1157, "2014-09-13");
+insert into diaries values(1158, "2014-09-14");
+insert into diaries values(1159, "2014-09-15");
+insert into diaries values(1160, "2014-09-16");
+insert into diaries values(1161, "2014-09-17");
+insert into diaries values(1162, "2014-09-18");
+insert into diaries values(1163, "2014-09-19");
+insert into diaries values(1164, "2014-09-20");
+insert into diaries values(1165, "2014-09-21");
+insert into diaries values(1166, "2014-09-22");
+insert into diaries values(1167, "2014-09-23");
+insert into diaries values(1168, "2014-09-24");
+insert into diaries values(1169, "2014-09-25");
+insert into diaries values(1170, "2014-09-26");
+insert into diaries values(1171, "2014-09-27");
+insert into diaries values(1172, "2014-09-28");
+insert into diaries values(1173, "2014-09-29");
+insert into diaries values(1174, "2014-09-30");
+insert into diaries values(1175, "2014-10-01");
+insert into diaries values(1176, "2014-10-02");
+insert into diaries values(1177, "2014-10-03");
+insert into diaries values(1178, "2014-10-04");
+insert into diaries values(1179, "2014-10-05");
+insert into diaries values(1180, "2014-10-06");
+insert into diaries values(1181, "2014-10-07");
+insert into diaries values(1182, "2014-10-08");
+insert into diaries values(1183, "2014-10-09");
+insert into diaries values(1184, "2014-10-10");
+insert into diaries values(1185, "2014-10-11");
+insert into diaries values(1186, "2014-10-12");
+insert into diaries values(1187, "2014-10-13");
+insert into diaries values(1188, "2014-10-14");
+insert into diaries values(1189, "2014-10-15");
+insert into diaries values(1190, "2014-10-16");
+insert into diaries values(1191, "2014-10-17");
+insert into diaries values(1192, "2014-10-18");
+insert into diaries values(1193, "2014-10-19");
+insert into diaries values(1194, "2014-10-20");
+insert into diaries values(1195, "2014-10-21");
+insert into diaries values(1196, "2014-10-22");
+insert into diaries values(1197, "2014-10-23");
+insert into diaries values(1198, "2014-10-24");
+insert into diaries values(1199, "2014-10-25");
+insert into diaries values(1200, "2014-10-26");
+insert into diaries values(1201, "2014-10-27");
+insert into diaries values(1202, "2014-10-28");
+insert into diaries values(1203, "2014-10-29");
+insert into diaries values(1204, "2014-10-30");
+insert into diaries values(1205, "2014-10-31");
+insert into diaries values(1206, "2014-11-01");
+insert into diaries values(1207, "2014-11-02");
+insert into diaries values(1208, "2014-11-03");
+insert into diaries values(1209, "2014-11-04");
+insert into diaries values(1210, "2014-11-05");
+insert into diaries values(1211, "2014-11-06");
+insert into diaries values(1212, "2014-11-07");
+insert into diaries values(1213, "2014-11-08");
+insert into diaries values(1214, "2014-11-09");
+insert into diaries values(1215, "2014-11-10");
+insert into diaries values(1216, "2014-11-11");
+insert into diaries values(1217, "2014-11-12");
+insert into diaries values(1218, "2014-11-13");
+insert into diaries values(1219, "2014-11-14");
+insert into diaries values(1220, "2014-11-15");
+insert into diaries values(1221, "2014-11-16");
+insert into diaries values(1222, "2014-11-17");
+insert into diaries values(1223, "2014-11-18");
+insert into diaries values(1224, "2014-11-19");
+insert into diaries values(1225, "2014-11-20");
+insert into diaries values(1226, "2014-11-21");
+insert into diaries values(1227, "2014-11-22");
+insert into diaries values(1228, "2014-11-23");
+insert into diaries values(1229, "2014-11-24");
+insert into diaries values(1230, "2014-11-25");
+insert into diaries values(1231, "2014-11-26");
+insert into diaries values(1232, "2014-11-27");
+insert into diaries values(1233, "2014-11-28");
+insert into diaries values(1234, "2014-11-29");
+insert into diaries values(1235, "2014-11-30");
+insert into diaries values(1236, "2014-12-01");
+insert into diaries values(1237, "2014-12-02");
+insert into diaries values(1238, "2014-12-03");
+insert into diaries values(1239, "2014-12-04");
+insert into diaries values(1240, "2014-12-05");
+insert into diaries values(1241, "2014-12-06");
+insert into diaries values(1242, "2014-12-07");
+insert into diaries values(1243, "2014-12-08");
+insert into diaries values(1244, "2014-12-09");
+insert into diaries values(1245, "2014-12-10");
+insert into diaries values(1246, "2014-12-11");
+insert into diaries values(1247, "2014-12-12");
+insert into diaries values(1248, "2014-12-13");
+insert into diaries values(1249, "2014-12-14");
+insert into diaries values(1250, "2014-12-15");
+insert into diaries values(1251, "2014-12-16");
+insert into diaries values(1252, "2014-12-17");
+insert into diaries values(1253, "2014-12-18");
+insert into diaries values(1254, "2014-12-19");
+insert into diaries values(1255, "2014-12-20");
+insert into diaries values(1256, "2014-12-21");
+insert into diaries values(1257, "2014-12-22");
+insert into diaries values(1258, "2014-12-23");
+insert into diaries values(1259, "2014-12-24");
+insert into diaries values(1260, "2014-12-25");
+insert into diaries values(1261, "2014-12-26");
+insert into diaries values(1262, "2014-12-27");
+insert into diaries values(1263, "2014-12-28");
+insert into diaries values(1264, "2014-12-29");
+insert into diaries values(1265, "2014-12-30");
+insert into diaries values(1266, "2014-12-31");
+insert into diaries values(1267, "2015-01-01");
+insert into diaries values(1268, "2015-01-02");
+insert into diaries values(1269, "2015-01-03");
+insert into diaries values(1270, "2015-01-04");
+insert into diaries values(1271, "2015-01-05");
+insert into diaries values(1272, "2015-01-06");
+insert into diaries values(1273, "2015-01-07");
+insert into diaries values(1274, "2015-01-08");
+insert into diaries values(1275, "2015-01-09");
+insert into diaries values(1276, "2015-01-10");
+insert into diaries values(1277, "2015-01-11");
+insert into diaries values(1278, "2015-01-12");
+insert into diaries values(1279, "2015-01-13");
+insert into diaries values(1280, "2015-01-14");
+insert into diaries values(1281, "2015-01-15");
+insert into diaries values(1282, "2015-01-16");
+insert into diaries values(1283, "2015-01-17");
+insert into diaries values(1284, "2015-01-18");
+insert into diaries values(1285, "2015-01-19");
+insert into diaries values(1286, "2015-01-20");
+insert into diaries values(1287, "2015-01-21");
+insert into diaries values(1288, "2015-01-22");
+insert into diaries values(1289, "2015-01-23");
+insert into diaries values(1290, "2015-01-24");
+insert into diaries values(1291, "2015-01-25");
+insert into diaries values(1292, "2015-01-26");
+insert into diaries values(1293, "2015-01-27");
+insert into diaries values(1294, "2015-01-28");
+insert into diaries values(1295, "2015-01-29");
+insert into diaries values(1296, "2015-01-30");
+insert into diaries values(1297, "2015-01-31");
+insert into diaries values(1298, "2015-02-01");
+insert into diaries values(1299, "2015-02-02");
+insert into diaries values(1300, "2015-02-03");
+insert into diaries values(1301, "2015-02-04");
+insert into diaries values(1302, "2015-02-05");
+insert into diaries values(1303, "2015-02-06");
+insert into diaries values(1304, "2015-02-07");
+insert into diaries values(1305, "2015-02-08");
+insert into diaries values(1306, "2015-02-09");
+insert into diaries values(1307, "2015-02-10");
+insert into diaries values(1308, "2015-02-11");
+insert into diaries values(1309, "2015-02-12");
+insert into diaries values(1310, "2015-02-13");
+insert into diaries values(1311, "2015-02-14");
+insert into diaries values(1312, "2015-02-15");
+insert into diaries values(1313, "2015-02-16");
+insert into diaries values(1314, "2015-02-17");
+insert into diaries values(1315, "2015-02-18");
+insert into diaries values(1316, "2015-02-19");
+insert into diaries values(1317, "2015-02-20");
+insert into diaries values(1318, "2015-02-21");
+insert into diaries values(1319, "2015-02-22");
+insert into diaries values(1320, "2015-02-23");
+insert into diaries values(1321, "2015-02-24");
+insert into diaries values(1322, "2015-02-25");
+insert into diaries values(1323, "2015-02-26");
+insert into diaries values(1324, "2015-02-27");
+insert into diaries values(1325, "2015-02-28");
+insert into diaries values(1326, "2015-03-01");
+insert into diaries values(1327, "2015-03-02");
+insert into diaries values(1328, "2015-03-03");
+insert into diaries values(1329, "2015-03-04");
+insert into diaries values(1330, "2015-03-05");
+insert into diaries values(1331, "2015-03-06");
+insert into diaries values(1332, "2015-03-07");
+insert into diaries values(1333, "2015-03-08");
+insert into diaries values(1334, "2015-03-09");
+insert into diaries values(1335, "2015-03-10");
+insert into diaries values(1336, "2015-03-11");
+insert into diaries values(1337, "2015-03-12");
+insert into diaries values(1338, "2015-03-13");
+insert into diaries values(1339, "2015-03-14");
+insert into diaries values(1340, "2015-03-15");
+insert into diaries values(1341, "2015-03-16");
+insert into diaries values(1342, "2015-03-17");
+insert into diaries values(1343, "2015-03-18");
+insert into diaries values(1344, "2015-03-19");
+insert into diaries values(1345, "2015-03-20");
+insert into diaries values(1346, "2015-03-21");
+insert into diaries values(1347, "2015-03-22");
+insert into diaries values(1348, "2015-03-23");
+insert into diaries values(1349, "2015-03-24");
+insert into diaries values(1350, "2015-03-25");
+insert into diaries values(1351, "2015-03-26");
+insert into diaries values(1352, "2015-03-27");
+insert into diaries values(1353, "2015-03-28");
+insert into diaries values(1354, "2015-03-29");
+insert into diaries values(1355, "2015-03-30");
+insert into diaries values(1356, "2015-03-31");
+insert into diaries values(1357, "2015-04-01");
+insert into diaries values(1358, "2015-04-02");
+insert into diaries values(1359, "2015-04-03");
+insert into diaries values(1360, "2015-04-04");
+insert into diaries values(1361, "2015-04-05");
+insert into diaries values(1362, "2015-04-06");
+insert into diaries values(1363, "2015-04-07");
+insert into diaries values(1364, "2015-04-08");
+insert into diaries values(1365, "2015-04-09");
+insert into diaries values(1366, "2015-04-10");
+insert into diaries values(1367, "2015-04-11");
+insert into diaries values(1368, "2015-04-12");
+insert into diaries values(1369, "2015-04-13");
+insert into diaries values(1370, "2015-04-14");
+insert into diaries values(1371, "2015-04-15");
+insert into diaries values(1372, "2015-04-16");
+insert into diaries values(1373, "2015-04-17");
+insert into diaries values(1374, "2015-04-18");
+insert into diaries values(1375, "2015-04-19");
+insert into diaries values(1376, "2015-04-20");
+insert into diaries values(1377, "2015-04-21");
+insert into diaries values(1378, "2015-04-22");
+insert into diaries values(1379, "2015-04-23");
+insert into diaries values(1380, "2015-04-24");
+insert into diaries values(1381, "2015-04-25");
+insert into diaries values(1382, "2015-04-26");
+insert into diaries values(1383, "2015-04-27");
+insert into diaries values(1384, "2015-04-28");
+insert into diaries values(1385, "2015-04-29");
+insert into diaries values(1386, "2015-04-30");
+insert into diaries values(1387, "2015-05-01");
+insert into diaries values(1388, "2015-05-02");
+insert into diaries values(1389, "2015-05-03");
+insert into diaries values(1390, "2015-05-04");
+insert into diaries values(1391, "2015-05-05");
+insert into diaries values(1392, "2015-05-06");
+insert into diaries values(1393, "2015-05-07");
+insert into diaries values(1394, "2015-05-08");
+insert into diaries values(1395, "2015-05-09");
+insert into diaries values(1396, "2015-05-10");
+insert into diaries values(1397, "2015-05-11");
+insert into diaries values(1398, "2015-05-12");
+insert into diaries values(1399, "2015-05-13");
+insert into diaries values(1400, "2015-05-14");
+insert into diaries values(1401, "2015-05-15");
+insert into diaries values(1402, "2015-05-16");
+insert into diaries values(1403, "2015-05-17");
+insert into diaries values(1404, "2015-05-18");
+insert into diaries values(1405, "2015-05-19");
+insert into diaries values(1406, "2015-05-20");
+insert into diaries values(1407, "2015-05-21");
+insert into diaries values(1408, "2015-05-22");
+insert into diaries values(1409, "2015-05-23");
+insert into diaries values(1410, "2015-05-24");
+insert into diaries values(1411, "2015-05-25");
+insert into diaries values(1412, "2015-05-26");
+insert into diaries values(1413, "2015-05-27");
+insert into diaries values(1414, "2015-05-28");
+insert into diaries values(1415, "2015-05-29");
+insert into diaries values(1416, "2015-05-30");
+insert into diaries values(1417, "2015-05-31");
+insert into diaries values(1418, "2015-06-01");
+insert into diaries values(1419, "2015-06-02");
+insert into diaries values(1420, "2015-06-03");
+insert into diaries values(1421, "2015-06-04");
+insert into diaries values(1422, "2015-06-05");
+insert into diaries values(1423, "2015-06-06");
+insert into diaries values(1424, "2015-06-07");
+insert into diaries values(1425, "2015-06-08");
+insert into diaries values(1426, "2015-06-09");
+insert into diaries values(1427, "2015-06-10");
+insert into diaries values(1428, "2015-06-11");
+insert into diaries values(1429, "2015-06-12");
+insert into diaries values(1430, "2015-06-13");
+insert into diaries values(1431, "2015-06-14");
+insert into diaries values(1432, "2015-06-15");
+insert into diaries values(1433, "2015-06-16");
+insert into diaries values(1434, "2015-06-17");
+insert into diaries values(1435, "2015-06-18");
+insert into diaries values(1436, "2015-06-19");
+insert into diaries values(1437, "2015-06-20");
+insert into diaries values(1438, "2015-06-21");
+insert into diaries values(1439, "2015-06-22");
+insert into diaries values(1440, "2015-06-23");
+insert into diaries values(1441, "2015-06-24");
+insert into diaries values(1442, "2015-06-25");
+insert into diaries values(1443, "2015-06-26");
+insert into diaries values(1444, "2015-06-27");
+insert into diaries values(1445, "2015-06-28");
+insert into diaries values(1446, "2015-06-29");
+insert into diaries values(1447, "2015-06-30");
+insert into diaries values(1448, "2015-07-01");
+insert into diaries values(1449, "2015-07-02");
+insert into diaries values(1450, "2015-07-03");
+insert into diaries values(1451, "2015-07-04");
+insert into diaries values(1452, "2015-07-05");
+insert into diaries values(1453, "2015-07-06");
+insert into diaries values(1454, "2015-07-07");
+insert into diaries values(1455, "2015-07-08");
+insert into diaries values(1456, "2015-07-09");
+insert into diaries values(1457, "2015-07-10");
+insert into diaries values(1458, "2015-07-11");
+insert into diaries values(1459, "2015-07-12");
+insert into diaries values(1460, "2015-07-13");
+insert into diaries values(1461, "2015-07-14");
+insert into diaries values(1462, "2015-07-15");
+insert into diaries values(1463, "2015-07-16");
+insert into diaries values(1464, "2015-07-17");
+insert into diaries values(1465, "2015-07-18");
+insert into diaries values(1466, "2015-07-19");
+insert into diaries values(1467, "2015-07-20");
+insert into diaries values(1468, "2015-07-21");
+insert into diaries values(1469, "2015-07-22");
+insert into diaries values(1470, "2015-07-23");
+insert into diaries values(1471, "2015-07-24");
+insert into diaries values(1472, "2015-07-25");
+insert into diaries values(1473, "2015-07-26");
+insert into diaries values(1474, "2015-07-27");
+insert into diaries values(1475, "2015-07-28");
+insert into diaries values(1476, "2015-07-29");
+insert into diaries values(1477, "2015-07-30");
+insert into diaries values(1478, "2015-07-31");
+insert into diaries values(1479, "2015-08-01");
+insert into diaries values(1480, "2015-08-02");
+insert into diaries values(1481, "2015-08-03");
+insert into diaries values(1482, "2015-08-04");
+insert into diaries values(1483, "2015-08-05");
+insert into diaries values(1484, "2015-08-06");
+insert into diaries values(1485, "2015-08-07");
+insert into diaries values(1486, "2015-08-08");
+insert into diaries values(1487, "2015-08-09");
+insert into diaries values(1488, "2015-08-10");
+insert into diaries values(1489, "2015-08-11");
+insert into diaries values(1490, "2015-08-12");
+insert into diaries values(1491, "2015-08-13");
+insert into diaries values(1492, "2015-08-14");
+insert into diaries values(1493, "2015-08-15");
+insert into diaries values(1494, "2015-08-16");
+insert into diaries values(1495, "2015-08-17");
+insert into diaries values(1496, "2015-08-18");
+insert into diaries values(1497, "2015-08-19");
+insert into diaries values(1498, "2015-08-20");
+insert into diaries values(1499, "2015-08-21");
+insert into diaries values(1500, "2015-08-22");
+insert into diaries values(1501, "2015-08-23");
+insert into diaries values(1502, "2015-08-24");
+insert into diaries values(1503, "2015-08-25");
+insert into diaries values(1504, "2015-08-26");
+insert into diaries values(1505, "2015-08-27");
+insert into diaries values(1506, "2015-08-28");
+insert into diaries values(1507, "2015-08-29");
+insert into diaries values(1508, "2015-08-30");
+insert into diaries values(1509, "2015-08-31");
+insert into diaries values(1510, "2015-09-01");
+insert into diaries values(1511, "2015-09-02");
+insert into diaries values(1512, "2015-09-03");
+insert into diaries values(1513, "2015-09-04");
+insert into diaries values(1514, "2015-09-05");
+insert into diaries values(1515, "2015-09-06");
+insert into diaries values(1516, "2015-09-07");
+insert into diaries values(1517, "2015-09-08");
+insert into diaries values(1518, "2015-09-09");
+insert into diaries values(1519, "2015-09-10");
+insert into diaries values(1520, "2015-09-11");
+insert into diaries values(1521, "2015-09-12");
+insert into diaries values(1522, "2015-09-13");
+insert into diaries values(1523, "2015-09-14");
+insert into diaries values(1524, "2015-09-15");
+insert into diaries values(1525, "2015-09-16");
+insert into diaries values(1526, "2015-09-17");
+insert into diaries values(1527, "2015-09-18");
+insert into diaries values(1528, "2015-09-19");
+insert into diaries values(1529, "2015-09-20");
+insert into diaries values(1530, "2015-09-21");
+insert into diaries values(1531, "2015-09-22");
+insert into diaries values(1532, "2015-09-23");
+insert into diaries values(1533, "2015-09-24");
+insert into diaries values(1534, "2015-09-25");
+insert into diaries values(1535, "2015-09-26");
+insert into diaries values(1536, "2015-09-27");
+insert into diaries values(1537, "2015-09-28");
+insert into diaries values(1538, "2015-09-29");
+insert into diaries values(1539, "2015-09-30");
+insert into diaries values(1540, "2015-10-01");
+insert into diaries values(1541, "2015-10-02");
+insert into diaries values(1542, "2015-10-03");
+insert into diaries values(1543, "2015-10-04");
+insert into diaries values(1544, "2015-10-05");
+insert into diaries values(1545, "2015-10-06");
+insert into diaries values(1546, "2015-10-07");
+insert into diaries values(1547, "2015-10-08");
+insert into diaries values(1548, "2015-10-09");
+insert into diaries values(1549, "2015-10-10");
+insert into diaries values(1550, "2015-10-11");
+insert into diaries values(1551, "2015-10-12");
+insert into diaries values(1552, "2015-10-13");
+insert into diaries values(1553, "2015-10-14");
+insert into diaries values(1554, "2015-10-15");
+insert into diaries values(1555, "2015-10-16");
+insert into diaries values(1556, "2015-10-17");
+insert into diaries values(1557, "2015-10-18");
+insert into diaries values(1558, "2015-10-19");
+insert into diaries values(1559, "2015-10-20");
+insert into diaries values(1560, "2015-10-21");
+insert into diaries values(1561, "2015-10-22");
+insert into diaries values(1562, "2015-10-23");
+insert into diaries values(1563, "2015-10-24");
+insert into diaries values(1564, "2015-10-25");
+insert into diaries values(1565, "2015-10-26");
+insert into diaries values(1566, "2015-10-27");
+insert into diaries values(1567, "2015-10-28");
+insert into diaries values(1568, "2015-10-29");
+insert into diaries values(1569, "2015-10-30");
+insert into diaries values(1570, "2015-10-31");
+insert into diaries values(1571, "2015-11-01");
+insert into diaries values(1572, "2015-11-02");
+insert into diaries values(1573, "2015-11-03");
+insert into diaries values(1574, "2015-11-04");
+insert into diaries values(1575, "2015-11-05");
+insert into diaries values(1576, "2015-11-06");
+insert into diaries values(1577, "2015-11-07");
+insert into diaries values(1578, "2015-11-08");
+insert into diaries values(1579, "2015-11-09");
+insert into diaries values(1580, "2015-11-10");
+insert into diaries values(1581, "2015-11-11");
+insert into diaries values(1582, "2015-11-12");
+insert into diaries values(1583, "2015-11-13");
+insert into diaries values(1584, "2015-11-14");
+insert into diaries values(1585, "2015-11-15");
+insert into diaries values(1586, "2015-11-16");
+insert into diaries values(1587, "2015-11-17");
+insert into diaries values(1588, "2015-11-18");
+insert into diaries values(1589, "2015-11-19");
+insert into diaries values(1590, "2015-11-20");
+insert into diaries values(1591, "2015-11-21");
+insert into diaries values(1592, "2015-11-22");
+insert into diaries values(1593, "2015-11-23");
+insert into diaries values(1594, "2015-11-24");
+insert into diaries values(1595, "2015-11-25");
+insert into diaries values(1596, "2015-11-26");
+insert into diaries values(1597, "2015-11-27");
+insert into diaries values(1598, "2015-11-28");
+insert into diaries values(1599, "2015-11-29");
+insert into diaries values(1600, "2015-11-30");
+insert into diaries values(1601, "2015-12-01");
+insert into diaries values(1602, "2015-12-02");
+insert into diaries values(1603, "2015-12-03");
+insert into diaries values(1604, "2015-12-04");
+insert into diaries values(1605, "2015-12-05");
+insert into diaries values(1606, "2015-12-06");
+insert into diaries values(1607, "2015-12-07");
+insert into diaries values(1608, "2015-12-08");
+insert into diaries values(1609, "2015-12-09");
+insert into diaries values(1610, "2015-12-10");
+insert into diaries values(1611, "2015-12-11");
+insert into diaries values(1612, "2015-12-12");
+insert into diaries values(1613, "2015-12-13");
+insert into diaries values(1614, "2015-12-14");
+insert into diaries values(1615, "2015-12-15");
+insert into diaries values(1616, "2015-12-16");
+insert into diaries values(1617, "2015-12-17");
+insert into diaries values(1618, "2015-12-18");
+insert into diaries values(1619, "2015-12-19");
+insert into diaries values(1620, "2015-12-20");
+insert into diaries values(1621, "2015-12-21");
+insert into diaries values(1622, "2015-12-22");
+insert into diaries values(1623, "2015-12-23");
+insert into diaries values(1624, "2015-12-24");
+insert into diaries values(1625, "2015-12-25");
+insert into diaries values(1626, "2015-12-26");
+insert into diaries values(1627, "2015-12-27");
+insert into diaries values(1628, "2015-12-28");
+insert into diaries values(1629, "2015-12-29");
+insert into diaries values(1630, "2015-12-30");
+insert into diaries values(1631, "2015-12-31");
+insert into diaries values(1632, "2016-01-01");
+insert into diaries values(1633, "2016-01-02");
+insert into diaries values(1634, "2016-01-03");
+insert into diaries values(1635, "2016-01-04");
+insert into diaries values(1636, "2016-01-05");
+insert into diaries values(1637, "2016-01-06");
+insert into diaries values(1638, "2016-01-07");
+insert into diaries values(1639, "2016-01-08");
+insert into diaries values(1640, "2016-01-09");
+insert into diaries values(1641, "2016-01-10");
+insert into diaries values(1642, "2016-01-11");
+insert into diaries values(1643, "2016-01-12");
+insert into diaries values(1644, "2016-01-13");
+insert into diaries values(1645, "2016-01-14");
+insert into diaries values(1646, "2016-01-15");
+insert into diaries values(1647, "2016-01-16");
+insert into diaries values(1648, "2016-01-17");
+insert into diaries values(1649, "2016-01-18");
+insert into diaries values(1650, "2016-01-19");
+insert into diaries values(1651, "2016-01-20");
+insert into diaries values(1652, "2016-01-21");
+insert into diaries values(1653, "2016-01-22");
+insert into diaries values(1654, "2016-01-23");
+insert into diaries values(1655, "2016-01-24");
+insert into diaries values(1656, "2016-01-25");
+insert into diaries values(1657, "2016-01-26");
+insert into diaries values(1658, "2016-01-27");
+insert into diaries values(1659, "2016-01-28");
+insert into diaries values(1660, "2016-01-29");
+insert into diaries values(1661, "2016-01-30");
+insert into diaries values(1662, "2016-01-31");
+insert into diaries values(1663, "2016-02-01");
+insert into diaries values(1664, "2016-02-02");
+insert into diaries values(1665, "2016-02-03");
+insert into diaries values(1666, "2016-02-04");
+insert into diaries values(1667, "2016-02-05");
+insert into diaries values(1668, "2016-02-06");
+insert into diaries values(1669, "2016-02-07");
+insert into diaries values(1670, "2016-02-08");
+insert into diaries values(1671, "2016-02-09");
+insert into diaries values(1672, "2016-02-10");
+insert into diaries values(1673, "2016-02-11");
+insert into diaries values(1674, "2016-02-12");
+insert into diaries values(1675, "2016-02-13");
+insert into diaries values(1676, "2016-02-14");
+insert into diaries values(1677, "2016-02-15");
+insert into diaries values(1678, "2016-02-16");
+insert into diaries values(1679, "2016-02-17");
+insert into diaries values(1680, "2016-02-18");
+insert into diaries values(1681, "2016-02-19");
+insert into diaries values(1682, "2016-02-20");
+insert into diaries values(1683, "2016-02-21");
+insert into diaries values(1684, "2016-02-22");
+insert into diaries values(1685, "2016-02-23");
+insert into diaries values(1686, "2016-02-24");
+insert into diaries values(1687, "2016-02-25");
+insert into diaries values(1688, "2016-02-26");
+insert into diaries values(1689, "2016-02-27");
+insert into diaries values(1690, "2016-02-28");
+insert into diaries values(1691, "2016-02-29");
+insert into diaries values(1692, "2016-03-01");
+insert into diaries values(1693, "2016-03-02");
+insert into diaries values(1694, "2016-03-03");
+insert into diaries values(1695, "2016-03-04");
+insert into diaries values(1696, "2016-03-05");
+insert into diaries values(1697, "2016-03-06");
+insert into diaries values(1698, "2016-03-07");
+insert into diaries values(1699, "2016-03-08");
+insert into diaries values(1700, "2016-03-09");
+insert into diaries values(1701, "2016-03-10");
+insert into diaries values(1702, "2016-03-11");
+insert into diaries values(1703, "2016-03-12");
+insert into diaries values(1704, "2016-03-13");
+insert into diaries values(1705, "2016-03-14");
+insert into diaries values(1706, "2016-03-15");
+insert into diaries values(1707, "2016-03-16");
+insert into diaries values(1708, "2016-03-17");
+insert into diaries values(1709, "2016-03-18");
+insert into diaries values(1710, "2016-03-19");
+insert into diaries values(1711, "2016-03-20");
+insert into diaries values(1712, "2016-03-21");
+insert into diaries values(1713, "2016-03-22");
+insert into diaries values(1714, "2016-03-23");
+insert into diaries values(1715, "2016-03-24");
+insert into diaries values(1716, "2016-03-25");
+insert into diaries values(1717, "2016-03-26");
+insert into diaries values(1718, "2016-03-27");
+insert into diaries values(1719, "2016-03-28");
+insert into diaries values(1720, "2016-03-29");
+insert into diaries values(1721, "2016-03-30");
+insert into diaries values(1722, "2016-03-31");
+insert into diaries values(1723, "2016-04-01");
+insert into diaries values(1724, "2016-04-02");
+insert into diaries values(1725, "2016-04-03");
+insert into diaries values(1726, "2016-04-04");
+insert into diaries values(1727, "2016-04-05");
+insert into diaries values(1728, "2016-04-06");
+insert into diaries values(1729, "2016-04-07");
+insert into diaries values(1730, "2016-04-08");
+insert into diaries values(1731, "2016-04-09");
+insert into diaries values(1732, "2016-04-10");
+insert into diaries values(1733, "2016-04-11");
+insert into diaries values(1734, "2016-04-12");
+insert into diaries values(1735, "2016-04-13");
+insert into diaries values(1736, "2016-04-14");
+insert into diaries values(1737, "2016-04-15");
+insert into diaries values(1738, "2016-04-16");
+insert into diaries values(1739, "2016-04-17");
+insert into diaries values(1740, "2016-04-18");
+insert into diaries values(1741, "2016-04-19");
+insert into diaries values(1742, "2016-04-20");
+insert into diaries values(1743, "2016-04-21");
+insert into diaries values(1744, "2016-04-22");
+insert into diaries values(1745, "2016-04-23");
+insert into diaries values(1746, "2016-04-24");
+insert into diaries values(1747, "2016-04-25");
+insert into diaries values(1748, "2016-04-26");
+insert into diaries values(1749, "2016-04-27");
+insert into diaries values(1750, "2016-04-28");
+insert into diaries values(1751, "2016-04-29");
+insert into diaries values(1752, "2016-04-30");
+insert into diaries values(1753, "2016-05-01");
+insert into diaries values(1754, "2016-05-02");
+insert into diaries values(1755, "2016-05-03");
+insert into diaries values(1756, "2016-05-04");
+insert into diaries values(1757, "2016-05-05");
+insert into diaries values(1758, "2016-05-06");
+insert into diaries values(1759, "2016-05-07");
+insert into diaries values(1760, "2016-05-08");
+insert into diaries values(1761, "2016-05-09");
+insert into diaries values(1762, "2016-05-10");
+insert into diaries values(1763, "2016-05-11");
+insert into diaries values(1764, "2016-05-12");
+insert into diaries values(1765, "2016-05-13");
+insert into diaries values(1766, "2016-05-14");
+insert into diaries values(1767, "2016-05-15");
+insert into diaries values(1768, "2016-05-16");
+insert into diaries values(1769, "2016-05-17");
+insert into diaries values(1770, "2016-05-18");
+insert into diaries values(1771, "2016-05-19");
+insert into diaries values(1772, "2016-05-20");
+insert into diaries values(1773, "2016-05-21");
+insert into diaries values(1774, "2016-05-22");
+insert into diaries values(1775, "2016-05-23");
+insert into diaries values(1776, "2016-05-24");
+insert into diaries values(1777, "2016-05-25");
+insert into diaries values(1778, "2016-05-26");
+insert into diaries values(1779, "2016-05-27");
+insert into diaries values(1780, "2016-05-28");
+insert into diaries values(1781, "2016-05-29");
+insert into diaries values(1782, "2016-05-30");
+insert into diaries values(1783, "2016-05-31");
+insert into diaries values(1784, "2016-06-01");
+insert into diaries values(1785, "2016-06-02");
+insert into diaries values(1786, "2016-06-03");
+insert into diaries values(1787, "2016-06-04");
+insert into diaries values(1788, "2016-06-05");
+insert into diaries values(1789, "2016-06-06");
+insert into diaries values(1790, "2016-06-07");
+insert into diaries values(1791, "2016-06-08");
+insert into diaries values(1792, "2016-06-09");
+insert into diaries values(1793, "2016-06-10");
+insert into diaries values(1794, "2016-06-11");
+insert into diaries values(1795, "2016-06-12");
+insert into diaries values(1796, "2016-06-13");
+insert into diaries values(1797, "2016-06-14");
+insert into diaries values(1798, "2016-06-15");
+insert into diaries values(1799, "2016-06-16");
+insert into diaries values(1800, "2016-06-17");
+insert into diaries values(1801, "2016-06-18");
+insert into diaries values(1802, "2016-06-19");
+insert into diaries values(1803, "2016-06-20");
+insert into diaries values(1804, "2016-06-21");
+insert into diaries values(1805, "2016-06-22");
+insert into diaries values(1806, "2016-06-23");
+insert into diaries values(1807, "2016-06-24");
+insert into diaries values(1808, "2016-06-25");
+insert into diaries values(1809, "2016-06-26");
+insert into diaries values(1810, "2016-06-27");
+insert into diaries values(1811, "2016-06-28");
+insert into diaries values(1812, "2016-06-29");
+insert into diaries values(1813, "2016-06-30");
+insert into diaries values(1814, "2016-07-01");
+insert into diaries values(1815, "2016-07-02");
+insert into diaries values(1816, "2016-07-03");
+insert into diaries values(1817, "2016-07-04");
+insert into diaries values(1818, "2016-07-05");
+insert into diaries values(1819, "2016-07-06");
+insert into diaries values(1820, "2016-07-07");
+insert into diaries values(1821, "2016-07-08");
+insert into diaries values(1822, "2016-07-09");
+insert into diaries values(1823, "2016-07-10");
+insert into diaries values(1824, "2016-07-11");
+insert into diaries values(1825, "2016-07-12");
+insert into diaries values(1826, "2016-07-13");
+insert into diaries values(1827, "2016-07-14");
+insert into diaries values(1828, "2016-07-15");
+insert into diaries values(1829, "2016-07-16");
+insert into diaries values(1830, "2016-07-17");
+insert into diaries values(1831, "2016-07-18");
+insert into diaries values(1832, "2016-07-19");
+insert into diaries values(1833, "2016-07-20");
+insert into diaries values(1834, "2016-07-21");
+insert into diaries values(1835, "2016-07-22");
+insert into diaries values(1836, "2016-07-23");
+insert into diaries values(1837, "2016-07-24");
+insert into diaries values(1838, "2016-07-25");
+insert into diaries values(1839, "2016-07-26");
+insert into diaries values(1840, "2016-07-27");
+insert into diaries values(1841, "2016-07-28");
+insert into diaries values(1842, "2016-07-29");
+insert into diaries values(1843, "2016-07-30");
+insert into diaries values(1844, "2016-07-31");
+insert into diaries values(1845, "2016-08-01");
+insert into diaries values(1846, "2016-08-02");
+insert into diaries values(1847, "2016-08-03");
+insert into diaries values(1848, "2016-08-04");
+insert into diaries values(1849, "2016-08-05");
+insert into diaries values(1850, "2016-08-06");
+insert into diaries values(1851, "2016-08-07");
+insert into diaries values(1852, "2016-08-08");
+insert into diaries values(1853, "2016-08-09");
+insert into diaries values(1854, "2016-08-10");
+insert into diaries values(1855, "2016-08-11");
+insert into diaries values(1856, "2016-08-12");
+insert into diaries values(1857, "2016-08-13");
+insert into diaries values(1858, "2016-08-14");
+insert into diaries values(1859, "2016-08-15");
+insert into diaries values(1860, "2016-08-16");
+insert into diaries values(1861, "2016-08-17");
+insert into diaries values(1862, "2016-08-18");
+insert into diaries values(1863, "2016-08-19");
+insert into diaries values(1864, "2016-08-20");
+insert into diaries values(1865, "2016-08-21");
+insert into diaries values(1866, "2016-08-22");
+insert into diaries values(1867, "2016-08-23");
+insert into diaries values(1868, "2016-08-24");
+insert into diaries values(1869, "2016-08-25");
+insert into diaries values(1870, "2016-08-26");
+insert into diaries values(1871, "2016-08-27");
+insert into diaries values(1872, "2016-08-28");
+insert into diaries values(1873, "2016-08-29");
+insert into diaries values(1874, "2016-08-30");
+insert into diaries values(1875, "2016-08-31");
+insert into diaries values(1876, "2016-09-01");
+insert into diaries values(1877, "2016-09-02");
+insert into diaries values(1878, "2016-09-03");
+insert into diaries values(1879, "2016-09-04");
+insert into diaries values(1880, "2016-09-05");
+insert into diaries values(1881, "2016-09-06");
+insert into diaries values(1882, "2016-09-07");
+insert into diaries values(1883, "2016-09-08");
+insert into diaries values(1884, "2016-09-09");
+insert into diaries values(1885, "2016-09-10");
+insert into diaries values(1886, "2016-09-11");
+insert into diaries values(1887, "2016-09-12");
+insert into diaries values(1888, "2016-09-13");
+insert into diaries values(1889, "2016-09-14");
+insert into diaries values(1890, "2016-09-15");
+insert into diaries values(1891, "2016-09-16");
+insert into diaries values(1892, "2016-09-17");
+insert into diaries values(1893, "2016-09-18");
+insert into diaries values(1894, "2016-09-19");
+insert into diaries values(1895, "2016-09-20");
+insert into diaries values(1896, "2016-09-21");
+insert into diaries values(1897, "2016-09-22");
+insert into diaries values(1898, "2016-09-23");
+insert into diaries values(1899, "2016-09-24");
+insert into diaries values(1900, "2016-09-25");
+insert into diaries values(1901, "2016-09-26");
+insert into diaries values(1902, "2016-09-27");
+insert into diaries values(1903, "2016-09-28");
+insert into diaries values(1904, "2016-09-29");
+insert into diaries values(1905, "2016-09-30");
+insert into diaries values(1906, "2016-10-01");
+insert into diaries values(1907, "2016-10-02");
+insert into diaries values(1908, "2016-10-03");
+insert into diaries values(1909, "2016-10-04");
+insert into diaries values(1910, "2016-10-05");
+insert into diaries values(1911, "2016-10-06");
+insert into diaries values(1912, "2016-10-07");
+insert into diaries values(1913, "2016-10-08");
+insert into diaries values(1914, "2016-10-09");
+insert into diaries values(1915, "2016-10-10");
+insert into diaries values(1916, "2016-10-11");
+insert into diaries values(1917, "2016-10-12");
+insert into diaries values(1918, "2016-10-13");
+insert into diaries values(1919, "2016-10-14");
+insert into diaries values(1920, "2016-10-15");
+insert into diaries values(1921, "2016-10-16");
+insert into diaries values(1922, "2016-10-17");
+insert into diaries values(1923, "2016-10-18");
+insert into diaries values(1924, "2016-10-19");
+insert into diaries values(1925, "2016-10-20");
+insert into diaries values(1926, "2016-10-21");
+insert into diaries values(1927, "2016-10-22");
+insert into diaries values(1928, "2016-10-23");
+insert into diaries values(1929, "2016-10-24");
+insert into diaries values(1930, "2016-10-25");
+insert into diaries values(1931, "2016-10-26");
+insert into diaries values(1932, "2016-10-27");
+insert into diaries values(1933, "2016-10-28");
+insert into diaries values(1934, "2016-10-29");
+insert into diaries values(1935, "2016-10-30");
+insert into diaries values(1936, "2016-10-31");
+insert into diaries values(1937, "2016-11-01");
+insert into diaries values(1938, "2016-11-02");
+insert into diaries values(1939, "2016-11-03");
+insert into diaries values(1940, "2016-11-04");
+insert into diaries values(1941, "2016-11-05");
+insert into diaries values(1942, "2016-11-06");
+insert into diaries values(1943, "2016-11-07");
+insert into diaries values(1944, "2016-11-08");
+insert into diaries values(1945, "2016-11-09");
+insert into diaries values(1946, "2016-11-10");
+insert into diaries values(1947, "2016-11-11");
+insert into diaries values(1948, "2016-11-12");
+insert into diaries values(1949, "2016-11-13");
+insert into diaries values(1950, "2016-11-14");
+insert into diaries values(1951, "2016-11-15");
+insert into diaries values(1952, "2016-11-16");
+insert into diaries values(1953, "2016-11-17");
+insert into diaries values(1954, "2016-11-18");
+insert into diaries values(1955, "2016-11-19");
+insert into diaries values(1956, "2016-11-20");
+insert into diaries values(1957, "2016-11-21");
+insert into diaries values(1958, "2016-11-22");
+insert into diaries values(1959, "2016-11-23");
+insert into diaries values(1960, "2016-11-24");
+insert into diaries values(1961, "2016-11-25");
+insert into diaries values(1962, "2016-11-26");
+insert into diaries values(1963, "2016-11-27");
+insert into diaries values(1964, "2016-11-28");
+insert into diaries values(1965, "2016-11-29");
+insert into diaries values(1966, "2016-11-30");
+insert into diaries values(1967, "2016-12-01");
+insert into diaries values(1968, "2016-12-02");
+insert into diaries values(1969, "2016-12-03");
+insert into diaries values(1970, "2016-12-04");
+insert into diaries values(1971, "2016-12-05");
+insert into diaries values(1972, "2016-12-06");
+insert into diaries values(1973, "2016-12-07");
+insert into diaries values(1974, "2016-12-08");
+insert into diaries values(1975, "2016-12-09");
+insert into diaries values(1976, "2016-12-10");
+insert into diaries values(1977, "2016-12-11");
+insert into diaries values(1978, "2016-12-12");
+insert into diaries values(1979, "2016-12-13");
+insert into diaries values(1980, "2016-12-14");
+insert into diaries values(1981, "2016-12-15");
+insert into diaries values(1982, "2016-12-16");
+insert into diaries values(1983, "2016-12-17");
+insert into diaries values(1984, "2016-12-18");
+insert into diaries values(1985, "2016-12-19");
+insert into diaries values(1986, "2016-12-20");
+insert into diaries values(1987, "2016-12-21");
+insert into diaries values(1988, "2016-12-22");
+insert into diaries values(1989, "2016-12-23");
+insert into diaries values(1990, "2016-12-24");
+insert into diaries values(1991, "2016-12-25");
+insert into diaries values(1992, "2016-12-26");
+insert into diaries values(1993, "2016-12-27");
+insert into diaries values(1994, "2016-12-28");
+insert into diaries values(1995, "2016-12-29");
+insert into diaries values(1996, "2016-12-30");
+insert into diaries values(1997, "2016-12-31");
+insert into diaries values(1998, "2017-01-01");
+insert into diaries values(1999, "2017-01-02");
+insert into diaries values(2000, "2017-01-03");
+insert into diaries values(2001, "2017-01-04");
+insert into diaries values(2002, "2017-01-05");
+insert into diaries values(2003, "2017-01-06");
+insert into diaries values(2004, "2017-01-07");
+insert into diaries values(2005, "2017-01-08");
+insert into diaries values(2006, "2017-01-09");
+insert into diaries values(2007, "2017-01-10");
+insert into diaries values(2008, "2017-01-11");
+insert into diaries values(2009, "2017-01-12");
+insert into diaries values(2010, "2017-01-13");
+insert into diaries values(2011, "2017-01-14");
+insert into diaries values(2012, "2017-01-15");
+insert into diaries values(2013, "2017-01-16");
+insert into diaries values(2014, "2017-01-17");
+insert into diaries values(2015, "2017-01-18");
+insert into diaries values(2016, "2017-01-19");
+insert into diaries values(2017, "2017-01-20");
+insert into diaries values(2018, "2017-01-21");
+insert into diaries values(2019, "2017-01-22");
+insert into diaries values(2020, "2017-01-23");
+insert into diaries values(2021, "2017-01-24");
+insert into diaries values(2022, "2017-01-25");
+insert into diaries values(2023, "2017-01-26");
+insert into diaries values(2024, "2017-01-27");
+insert into diaries values(2025, "2017-01-28");
+insert into diaries values(2026, "2017-01-29");
+insert into diaries values(2027, "2017-01-30");
+insert into diaries values(2028, "2017-01-31");
+insert into diaries values(2029, "2017-02-01");
+insert into diaries values(2030, "2017-02-02");
+insert into diaries values(2031, "2017-02-03");
+insert into diaries values(2032, "2017-02-04");
+insert into diaries values(2033, "2017-02-05");
+insert into diaries values(2034, "2017-02-06");
+insert into diaries values(2035, "2017-02-07");
+insert into diaries values(2036, "2017-02-08");
+insert into diaries values(2037, "2017-02-09");
+insert into diaries values(2038, "2017-02-10");
+insert into diaries values(2039, "2017-02-11");
+insert into diaries values(2040, "2017-02-12");
+insert into diaries values(2041, "2017-02-13");
+insert into diaries values(2042, "2017-02-14");
+insert into diaries values(2043, "2017-02-15");
+insert into diaries values(2044, "2017-02-16");
+insert into diaries values(2045, "2017-02-17");
+insert into diaries values(2046, "2017-02-18");
+insert into diaries values(2047, "2017-02-19");
+insert into diaries values(2048, "2017-02-20");
+insert into diaries values(2049, "2017-02-21");
+insert into diaries values(2050, "2017-02-22");
+insert into diaries values(2051, "2017-02-23");
+insert into diaries values(2052, "2017-02-24");
+insert into diaries values(2053, "2017-02-25");
+insert into diaries values(2054, "2017-02-26");
+insert into diaries values(2055, "2017-02-27");
+insert into diaries values(2056, "2017-02-28");
+insert into diaries values(2057, "2017-03-01");
+insert into diaries values(2058, "2017-03-02");
+insert into diaries values(2059, "2017-03-03");
+insert into diaries values(2060, "2017-03-04");
+insert into diaries values(2061, "2017-03-05");
+insert into diaries values(2062, "2017-03-06");
+insert into diaries values(2063, "2017-03-07");
+insert into diaries values(2064, "2017-03-08");
+insert into diaries values(2065, "2017-03-09");
+insert into diaries values(2066, "2017-03-10");
+insert into diaries values(2067, "2017-03-11");
+insert into diaries values(2068, "2017-03-12");
+insert into diaries values(2069, "2017-03-13");
+insert into diaries values(2070, "2017-03-14");
+insert into diaries values(2071, "2017-03-15");
+insert into diaries values(2072, "2017-03-16");
+insert into diaries values(2073, "2017-03-17");
+insert into diaries values(2074, "2017-03-18");
+insert into diaries values(2075, "2017-03-19");
+insert into diaries values(2076, "2017-03-20");
+insert into diaries values(2077, "2017-03-21");
+insert into diaries values(2078, "2017-03-22");
+insert into diaries values(2079, "2017-03-23");
+insert into diaries values(2080, "2017-03-24");
+insert into diaries values(2081, "2017-03-25");
+insert into diaries values(2082, "2017-03-26");
+insert into diaries values(2083, "2017-03-27");
+insert into diaries values(2084, "2017-03-28");
+insert into diaries values(2085, "2017-03-29");
+insert into diaries values(2086, "2017-03-30");
+insert into diaries values(2087, "2017-03-31");
+insert into diaries values(2088, "2017-04-01");
+insert into diaries values(2089, "2017-04-02");
+insert into diaries values(2090, "2017-04-03");
+insert into diaries values(2091, "2017-04-04");
+insert into diaries values(2092, "2017-04-05");
+insert into diaries values(2093, "2017-04-06");
+insert into diaries values(2094, "2017-04-07");
+insert into diaries values(2095, "2017-04-08");
+insert into diaries values(2096, "2017-04-09");
+insert into diaries values(2097, "2017-04-10");
+insert into diaries values(2098, "2017-04-11");
+insert into diaries values(2099, "2017-04-12");
+insert into diaries values(2100, "2017-04-13");
+insert into diaries values(2101, "2017-04-14");
+insert into diaries values(2102, "2017-04-15");
+insert into diaries values(2103, "2017-04-16");
+insert into diaries values(2104, "2017-04-17");
+insert into diaries values(2105, "2017-04-18");
+insert into diaries values(2106, "2017-04-19");
+insert into diaries values(2107, "2017-04-20");
+insert into diaries values(2108, "2017-04-21");
+insert into diaries values(2109, "2017-04-22");
+insert into diaries values(2110, "2017-04-23");
+insert into diaries values(2111, "2017-04-24");
+insert into diaries values(2112, "2017-04-25");
+insert into diaries values(2113, "2017-04-26");
+insert into diaries values(2114, "2017-04-27");
+insert into diaries values(2115, "2017-04-28");
+insert into diaries values(2116, "2017-04-29");
+insert into diaries values(2117, "2017-04-30");
+insert into diaries values(2118, "2017-05-01");
+insert into diaries values(2119, "2017-05-02");
+insert into diaries values(2120, "2017-05-03");
+insert into diaries values(2121, "2017-05-04");
+insert into diaries values(2122, "2017-05-05");
+insert into diaries values(2123, "2017-05-06");
+insert into diaries values(2124, "2017-05-07");
+insert into diaries values(2125, "2017-05-08");
+insert into diaries values(2126, "2017-05-09");
+insert into diaries values(2127, "2017-05-10");
+insert into diaries values(2128, "2017-05-11");
+insert into diaries values(2129, "2017-05-12");
+insert into diaries values(2130, "2017-05-13");
+insert into diaries values(2131, "2017-05-14");
+insert into diaries values(2132, "2017-05-15");
+insert into diaries values(2133, "2017-05-16");
+insert into diaries values(2134, "2017-05-17");
+insert into diaries values(2135, "2017-05-18");
+insert into diaries values(2136, "2017-05-19");
+insert into diaries values(2137, "2017-05-20");
+insert into diaries values(2138, "2017-05-21");
+insert into diaries values(2139, "2017-05-22");
+insert into diaries values(2140, "2017-05-23");
+insert into diaries values(2141, "2017-05-24");
+insert into diaries values(2142, "2017-05-25");
+insert into diaries values(2143, "2017-05-26");
+insert into diaries values(2144, "2017-05-27");
+insert into diaries values(2145, "2017-05-28");
+insert into diaries values(2146, "2017-05-29");
+insert into diaries values(2147, "2017-05-30");
+insert into diaries values(2148, "2017-05-31");
+insert into diaries values(2149, "2017-06-01");
+insert into diaries values(2150, "2017-06-02");
+insert into diaries values(2151, "2017-06-03");
+insert into diaries values(2152, "2017-06-04");
+insert into diaries values(2153, "2017-06-05");
+insert into diaries values(2154, "2017-06-06");
+insert into diaries values(2155, "2017-06-07");
+insert into diaries values(2156, "2017-06-08");
+insert into diaries values(2157, "2017-06-09");
+insert into diaries values(2158, "2017-06-10");
+insert into diaries values(2159, "2017-06-11");
+insert into diaries values(2160, "2017-06-12");
+insert into diaries values(2161, "2017-06-13");
+insert into diaries values(2162, "2017-06-14");
+insert into diaries values(2163, "2017-06-15");
+insert into diaries values(2164, "2017-06-16");
+insert into diaries values(2165, "2017-06-17");
+insert into diaries values(2166, "2017-06-18");
+insert into diaries values(2167, "2017-06-19");
+insert into diaries values(2168, "2017-06-20");
+insert into diaries values(2169, "2017-06-21");
+insert into diaries values(2170, "2017-06-22");
+insert into diaries values(2171, "2017-06-23");
+insert into diaries values(2172, "2017-06-24");
+insert into diaries values(2173, "2017-06-25");
+insert into diaries values(2174, "2017-06-26");
+insert into diaries values(2175, "2017-06-27");
+insert into diaries values(2176, "2017-06-28");
+insert into diaries values(2177, "2017-06-29");
+insert into diaries values(2178, "2017-06-30");
+insert into diaries values(2179, "2017-07-01");
+insert into diaries values(2180, "2017-07-02");
+insert into diaries values(2181, "2017-07-03");
+insert into diaries values(2182, "2017-07-04");
+insert into diaries values(2183, "2017-07-05");
+insert into diaries values(2184, "2017-07-06");
+insert into diaries values(2185, "2017-07-07");
+insert into diaries values(2186, "2017-07-08");
+insert into diaries values(2187, "2017-07-09");
+insert into diaries values(2188, "2017-07-10");
+insert into diaries values(2189, "2017-07-11");
+insert into diaries values(2190, "2017-07-12");
+insert into diaries values(2191, "2017-07-13");
+insert into diaries values(2192, "2017-07-14");
+insert into diaries values(2193, "2017-07-15");
+insert into diaries values(2194, "2017-07-16");
+insert into diaries values(2195, "2017-07-17");
+insert into diaries values(2196, "2017-07-18");
+insert into diaries values(2197, "2017-07-19");
+insert into diaries values(2198, "2017-07-20");
+insert into diaries values(2199, "2017-07-21");
+insert into diaries values(2200, "2017-07-22");
+insert into diaries values(2201, "2017-07-23");
+insert into diaries values(2202, "2017-07-24");
+insert into diaries values(2203, "2017-07-25");
+insert into diaries values(2204, "2017-07-26");
+insert into diaries values(2205, "2017-07-27");
+insert into diaries values(2206, "2017-07-28");
+insert into diaries values(2207, "2017-07-29");
+insert into diaries values(2208, "2017-07-30");
+insert into diaries values(2209, "2017-07-31");
+insert into diaries values(2210, "2017-08-01");
+insert into diaries values(2211, "2017-08-02");
+insert into diaries values(2212, "2017-08-03");
+insert into diaries values(2213, "2017-08-04");
+insert into diaries values(2214, "2017-08-05");
+insert into diaries values(2215, "2017-08-06");
+insert into diaries values(2216, "2017-08-07");
+insert into diaries values(2217, "2017-08-08");
+insert into diaries values(2218, "2017-08-09");
+insert into diaries values(2219, "2017-08-10");
+insert into diaries values(2220, "2017-08-11");
+insert into diaries values(2221, "2017-08-12");
+insert into diaries values(2222, "2017-08-13");
+insert into diaries values(2223, "2017-08-14");
+insert into diaries values(2224, "2017-08-15");
+insert into diaries values(2225, "2017-08-16");
+insert into diaries values(2226, "2017-08-17");
+insert into diaries values(2227, "2017-08-18");
+insert into diaries values(2228, "2017-08-19");
+insert into diaries values(2229, "2017-08-20");
+insert into diaries values(2230, "2017-08-21");
+insert into diaries values(2231, "2017-08-22");
+insert into diaries values(2232, "2017-08-23");
+insert into diaries values(2233, "2017-08-24");
+insert into diaries values(2234, "2017-08-25");
+insert into diaries values(2235, "2017-08-26");
+insert into diaries values(2236, "2017-08-27");
+insert into diaries values(2237, "2017-08-28");
+insert into diaries values(2238, "2017-08-29");
+insert into diaries values(2239, "2017-08-30");
+insert into diaries values(2240, "2017-08-31");
+insert into diaries values(2241, "2017-09-01");
+insert into diaries values(2242, "2017-09-02");
+insert into diaries values(2243, "2017-09-03");
+insert into diaries values(2244, "2017-09-04");
+insert into diaries values(2245, "2017-09-05");
+insert into diaries values(2246, "2017-09-06");
+insert into diaries values(2247, "2017-09-07");
+insert into diaries values(2248, "2017-09-08");
+insert into diaries values(2249, "2017-09-09");
+insert into diaries values(2250, "2017-09-10");
+insert into diaries values(2251, "2017-09-11");
+insert into diaries values(2252, "2017-09-12");
+insert into diaries values(2253, "2017-09-13");
+insert into diaries values(2254, "2017-09-14");
+insert into diaries values(2255, "2017-09-15");
+insert into diaries values(2256, "2017-09-16");
+insert into diaries values(2257, "2017-09-17");
+insert into diaries values(2258, "2017-09-18");
+insert into diaries values(2259, "2017-09-19");
+insert into diaries values(2260, "2017-09-20");
+insert into diaries values(2261, "2017-09-21");
+insert into diaries values(2262, "2017-09-22");
+insert into diaries values(2263, "2017-09-23");
+insert into diaries values(2264, "2017-09-24");
+insert into diaries values(2265, "2017-09-25");
+insert into diaries values(2266, "2017-09-26");
+insert into diaries values(2267, "2017-09-27");
+insert into diaries values(2268, "2017-09-28");
+insert into diaries values(2269, "2017-09-29");
+insert into diaries values(2270, "2017-09-30");
+insert into diaries values(2271, "2017-10-01");
+insert into diaries values(2272, "2017-10-02");
+insert into diaries values(2273, "2017-10-03");
+insert into diaries values(2274, "2017-10-04");
+insert into diaries values(2275, "2017-10-05");
+insert into diaries values(2276, "2017-10-06");
+insert into diaries values(2277, "2017-10-07");
+insert into diaries values(2278, "2017-10-08");
+insert into diaries values(2279, "2017-10-09");
+insert into diaries values(2280, "2017-10-10");
+insert into diaries values(2281, "2017-10-11");
+insert into diaries values(2282, "2017-10-12");
+insert into diaries values(2283, "2017-10-13");
+insert into diaries values(2284, "2017-10-14");
+insert into diaries values(2285, "2017-10-15");
+insert into diaries values(2286, "2017-10-16");
+insert into diaries values(2287, "2017-10-17");
+insert into diaries values(2288, "2017-10-18");
+insert into diaries values(2289, "2017-10-19");
+insert into diaries values(2290, "2017-10-20");
+insert into diaries values(2291, "2017-10-21");
+insert into diaries values(2292, "2017-10-22");
+insert into diaries values(2293, "2017-10-23");
+insert into diaries values(2294, "2017-10-24");
+insert into diaries values(2295, "2017-10-25");
+insert into diaries values(2296, "2017-10-26");
+insert into diaries values(2297, "2017-10-27");
+insert into diaries values(2298, "2017-10-28");
+insert into diaries values(2299, "2017-10-29");
+insert into diaries values(2300, "2017-10-30");
+insert into diaries values(2301, "2017-10-31");
+insert into diaries values(2302, "2017-11-01");
+insert into diaries values(2303, "2017-11-02");
+insert into diaries values(2304, "2017-11-03");
+insert into diaries values(2305, "2017-11-04");
+insert into diaries values(2306, "2017-11-05");
+insert into diaries values(2307, "2017-11-06");
+insert into diaries values(2308, "2017-11-07");
+insert into diaries values(2309, "2017-11-08");
+insert into diaries values(2310, "2017-11-09");
+insert into diaries values(2311, "2017-11-10");
+insert into diaries values(2312, "2017-11-11");
+insert into diaries values(2313, "2017-11-12");
+insert into diaries values(2314, "2017-11-13");
+insert into diaries values(2315, "2017-11-14");
+insert into diaries values(2316, "2017-11-15");
+insert into diaries values(2317, "2017-11-16");
+insert into diaries values(2318, "2017-11-17");
+insert into diaries values(2319, "2017-11-18");
+insert into diaries values(2320, "2017-11-19");
+insert into diaries values(2321, "2017-11-20");
+insert into diaries values(2322, "2017-11-21");
+insert into diaries values(2323, "2017-11-22");
+insert into diaries values(2324, "2017-11-23");
+insert into diaries values(2325, "2017-11-24");
+insert into diaries values(2326, "2017-11-25");
+insert into diaries values(2327, "2017-11-26");
+insert into diaries values(2328, "2017-11-27");
+insert into diaries values(2329, "2017-11-28");
+insert into diaries values(2330, "2017-11-29");
+insert into diaries values(2331, "2017-11-30");
+insert into diaries values(2332, "2017-12-01");
+insert into diaries values(2333, "2017-12-02");
+insert into diaries values(2334, "2017-12-03");
+insert into diaries values(2335, "2017-12-04");
+insert into diaries values(2336, "2017-12-05");
+insert into diaries values(2337, "2017-12-06");
+insert into diaries values(2338, "2017-12-07");
+insert into diaries values(2339, "2017-12-08");
+insert into diaries values(2340, "2017-12-09");
+insert into diaries values(2341, "2017-12-10");
+insert into diaries values(2342, "2017-12-11");
+insert into diaries values(2343, "2017-12-12");
+insert into diaries values(2344, "2017-12-13");
+insert into diaries values(2345, "2017-12-14");
+insert into diaries values(2346, "2017-12-15");
+insert into diaries values(2347, "2017-12-16");
+insert into diaries values(2348, "2017-12-17");
+insert into diaries values(2349, "2017-12-18");
+insert into diaries values(2350, "2017-12-19");
+insert into diaries values(2351, "2017-12-20");
+insert into diaries values(2352, "2017-12-21");
+insert into diaries values(2353, "2017-12-22");
+insert into diaries values(2354, "2017-12-23");
+insert into diaries values(2355, "2017-12-24");
+insert into diaries values(2356, "2017-12-25");
+insert into diaries values(2357, "2017-12-26");
+insert into diaries values(2358, "2017-12-27");
+insert into diaries values(2359, "2017-12-28");
+insert into diaries values(2360, "2017-12-29");
+insert into diaries values(2361, "2017-12-30");
+insert into diaries values(2362, "2017-12-31");
+insert into diaries values(2363, "2018-01-01");
+insert into diaries values(2364, "2018-01-02");
+insert into diaries values(2365, "2018-01-03");
+insert into diaries values(2366, "2018-01-04");
+insert into diaries values(2367, "2018-01-05");
+insert into diaries values(2368, "2018-01-06");
+insert into diaries values(2369, "2018-01-07");
+insert into diaries values(2370, "2018-01-08");
+insert into diaries values(2371, "2018-01-09");
+insert into diaries values(2372, "2018-01-10");
+insert into diaries values(2373, "2018-01-11");
+insert into diaries values(2374, "2018-01-12");
+insert into diaries values(2375, "2018-01-13");
+insert into diaries values(2376, "2018-01-14");
+insert into diaries values(2377, "2018-01-15");
+insert into diaries values(2378, "2018-01-16");
+insert into diaries values(2379, "2018-01-17");
+insert into diaries values(2380, "2018-01-18");
+insert into diaries values(2381, "2018-01-19");
+insert into diaries values(2382, "2018-01-20");
+insert into diaries values(2383, "2018-01-21");
+insert into diaries values(2384, "2018-01-22");
+insert into diaries values(2385, "2018-01-23");
+insert into diaries values(2386, "2018-01-24");
+insert into diaries values(2387, "2018-01-25");
+insert into diaries values(2388, "2018-01-26");
+insert into diaries values(2389, "2018-01-27");
+insert into diaries values(2390, "2018-01-28");
+insert into diaries values(2391, "2018-01-29");
+insert into diaries values(2392, "2018-01-30");
+insert into diaries values(2393, "2018-01-31");
+insert into diaries values(2394, "2018-02-01");
+insert into diaries values(2395, "2018-02-02");
+insert into diaries values(2396, "2018-02-03");
+insert into diaries values(2397, "2018-02-04");
+insert into diaries values(2398, "2018-02-05");
+insert into diaries values(2399, "2018-02-06");
+insert into diaries values(2400, "2018-02-07");
+insert into diaries values(2401, "2018-02-08");
+insert into diaries values(2402, "2018-02-09");
+insert into diaries values(2403, "2018-02-10");
+insert into diaries values(2404, "2018-02-11");
+insert into diaries values(2405, "2018-02-12");
+insert into diaries values(2406, "2018-02-13");
+insert into diaries values(2407, "2018-02-14");
+insert into diaries values(2408, "2018-02-15");
+insert into diaries values(2409, "2018-02-16");
+insert into diaries values(2410, "2018-02-17");
+insert into diaries values(2411, "2018-02-18");
+insert into diaries values(2412, "2018-02-19");
+insert into diaries values(2413, "2018-02-20");
+insert into diaries values(2414, "2018-02-21");
+insert into diaries values(2415, "2018-02-22");
+insert into diaries values(2416, "2018-02-23");
+insert into diaries values(2417, "2018-02-24");
+insert into diaries values(2418, "2018-02-25");
+insert into diaries values(2419, "2018-02-26");
+insert into diaries values(2420, "2018-02-27");
+insert into diaries values(2421, "2018-02-28");
+insert into diaries values(2422, "2018-03-01");
+insert into diaries values(2423, "2018-03-02");
+insert into diaries values(2424, "2018-03-03");
+insert into diaries values(2425, "2018-03-04");
+insert into diaries values(2426, "2018-03-05");
+insert into diaries values(2427, "2018-03-06");
+insert into diaries values(2428, "2018-03-07");
+insert into diaries values(2429, "2018-03-08");
+insert into diaries values(2430, "2018-03-09");
+insert into diaries values(2431, "2018-03-10");
+insert into diaries values(2432, "2018-03-11");
+insert into diaries values(2433, "2018-03-12");
+insert into diaries values(2434, "2018-03-13");
+insert into diaries values(2435, "2018-03-14");
+insert into diaries values(2436, "2018-03-15");
+insert into diaries values(2437, "2018-03-16");
+insert into diaries values(2438, "2018-03-17");
+insert into diaries values(2439, "2018-03-18");
+insert into diaries values(2440, "2018-03-19");
+insert into diaries values(2441, "2018-03-20");
+insert into diaries values(2442, "2018-03-21");
+insert into diaries values(2443, "2018-03-22");
+insert into diaries values(2444, "2018-03-23");
+insert into diaries values(2445, "2018-03-24");
+insert into diaries values(2446, "2018-03-25");
+insert into diaries values(2447, "2018-03-26");
+insert into diaries values(2448, "2018-03-27");
+insert into diaries values(2449, "2018-03-28");
+insert into diaries values(2450, "2018-03-29");
+insert into diaries values(2451, "2018-03-30");
+insert into diaries values(2452, "2018-03-31");
+insert into diaries values(2453, "2018-04-01");
+insert into diaries values(2454, "2018-04-02");
+insert into diaries values(2455, "2018-04-03");
+insert into diaries values(2456, "2018-04-04");
+insert into diaries values(2457, "2018-04-05");
+insert into diaries values(2458, "2018-04-06");
+insert into diaries values(2459, "2018-04-07");
+insert into diaries values(2460, "2018-04-08");
+insert into diaries values(2461, "2018-04-09");
+insert into diaries values(2462, "2018-04-10");
+insert into diaries values(2463, "2018-04-11");
+insert into diaries values(2464, "2018-04-12");
+insert into diaries values(2465, "2018-04-13");
+insert into diaries values(2466, "2018-04-14");
+insert into diaries values(2467, "2018-04-15");
+insert into diaries values(2468, "2018-04-16");
+insert into diaries values(2469, "2018-04-17");
+insert into diaries values(2470, "2018-04-18");
+insert into diaries values(2471, "2018-04-19");
+insert into diaries values(2472, "2018-04-20");
+insert into diaries values(2473, "2018-04-21");
+insert into diaries values(2474, "2018-04-22");
+insert into diaries values(2475, "2018-04-23");
+insert into diaries values(2476, "2018-04-24");
+insert into diaries values(2477, "2018-04-25");
+insert into diaries values(2478, "2018-04-26");
+insert into diaries values(2479, "2018-04-27");
+insert into diaries values(2480, "2018-04-28");
+insert into diaries values(2481, "2018-04-29");
+insert into diaries values(2482, "2018-04-30");
+insert into diaries values(2483, "2018-05-01");
+insert into diaries values(2484, "2018-05-02");
+insert into diaries values(2485, "2018-05-03");
+insert into diaries values(2486, "2018-05-04");
+insert into diaries values(2487, "2018-05-05");
+insert into diaries values(2488, "2018-05-06");
+insert into diaries values(2489, "2018-05-07");
+insert into diaries values(2490, "2018-05-08");
+insert into diaries values(2491, "2018-05-09");
+insert into diaries values(2492, "2018-05-10");
+insert into diaries values(2493, "2018-05-11");
+insert into diaries values(2494, "2018-05-12");
+insert into diaries values(2495, "2018-05-13");
+insert into diaries values(2496, "2018-05-14");
+insert into diaries values(2497, "2018-05-15");
+insert into diaries values(2498, "2018-05-16");
+insert into diaries values(2499, "2018-05-17");
+insert into diaries values(2500, "2018-05-18");
+insert into diaries values(2501, "2018-05-19");
+insert into diaries values(2502, "2018-05-20");
+insert into diaries values(2503, "2018-05-21");
+insert into diaries values(2504, "2018-05-22");
+insert into diaries values(2505, "2018-05-23");
+insert into diaries values(2506, "2018-05-24");
+insert into diaries values(2507, "2018-05-25");
+insert into diaries values(2508, "2018-05-26");
+insert into diaries values(2509, "2018-05-27");
+insert into diaries values(2510, "2018-05-28");
+insert into diaries values(2511, "2018-05-29");
+insert into diaries values(2512, "2018-05-30");
+insert into diaries values(2513, "2018-05-31");
+insert into diaries values(2514, "2018-06-01");
+insert into diaries values(2515, "2018-06-02");
+insert into diaries values(2516, "2018-06-03");
+insert into diaries values(2517, "2018-06-04");
+insert into diaries values(2518, "2018-06-05");
+insert into diaries values(2519, "2018-06-06");
+insert into diaries values(2520, "2018-06-07");
+insert into diaries values(2521, "2018-06-08");
+insert into diaries values(2522, "2018-06-09");
+insert into diaries values(2523, "2018-06-10");
+insert into diaries values(2524, "2018-06-11");
+insert into diaries values(2525, "2018-06-12");
+insert into diaries values(2526, "2018-06-13");
+insert into diaries values(2527, "2018-06-14");
+insert into diaries values(2528, "2018-06-15");
+insert into diaries values(2529, "2018-06-16");
+insert into diaries values(2530, "2018-06-17");
+insert into diaries values(2531, "2018-06-18");
+insert into diaries values(2532, "2018-06-19");
+insert into diaries values(2533, "2018-06-20");
+insert into diaries values(2534, "2018-06-21");
+insert into diaries values(2535, "2018-06-22");
+insert into diaries values(2536, "2018-06-23");
+insert into diaries values(2537, "2018-06-24");
+insert into diaries values(2538, "2018-06-25");
+insert into diaries values(2539, "2018-06-26");
+insert into diaries values(2540, "2018-06-27");
+insert into diaries values(2541, "2018-06-28");
+insert into diaries values(2542, "2018-06-29");
+insert into diaries values(2543, "2018-06-30");
+insert into diaries values(2544, "2018-07-01");
+insert into diaries values(2545, "2018-07-02");
+insert into diaries values(2546, "2018-07-03");
+insert into diaries values(2547, "2018-07-04");
+insert into diaries values(2548, "2018-07-05");
+insert into diaries values(2549, "2018-07-06");
+insert into diaries values(2550, "2018-07-07");
+insert into diaries values(2551, "2018-07-08");
+insert into diaries values(2552, "2018-07-09");
+insert into diaries values(2553, "2018-07-10");
+insert into diaries values(2554, "2018-07-11");
+insert into diaries values(2555, "2018-07-12");
+insert into diaries values(2556, "2018-07-13");
+insert into diaries values(2557, "2018-07-14");
+insert into diaries values(2558, "2018-07-15");
+insert into diaries values(2559, "2018-07-16");
+insert into diaries values(2560, "2018-07-17");
+insert into diaries values(2561, "2018-07-18");
+insert into diaries values(2562, "2018-07-19");
+insert into diaries values(2563, "2018-07-20");
+insert into diaries values(2564, "2018-07-21");
+insert into diaries values(2565, "2018-07-22");
+insert into diaries values(2566, "2018-07-23");
+insert into diaries values(2567, "2018-07-24");
+insert into diaries values(2568, "2018-07-25");
+insert into diaries values(2569, "2018-07-26");
+insert into diaries values(2570, "2018-07-27");
+insert into diaries values(2571, "2018-07-28");
+insert into diaries values(2572, "2018-07-29");
+insert into diaries values(2573, "2018-07-30");
+insert into diaries values(2574, "2018-07-31");
+insert into diaries values(2575, "2018-08-01");
+insert into diaries values(2576, "2018-08-02");
+insert into diaries values(2577, "2018-08-03");
+insert into diaries values(2578, "2018-08-04");
+insert into diaries values(2579, "2018-08-05");
+insert into diaries values(2580, "2018-08-06");
+insert into diaries values(2581, "2018-08-07");
+insert into diaries values(2582, "2018-08-08");
+insert into diaries values(2583, "2018-08-09");
+insert into diaries values(2584, "2018-08-10");
+insert into diaries values(2585, "2018-08-11");
+insert into diaries values(2586, "2018-08-12");
+insert into diaries values(2587, "2018-08-13");
+insert into diaries values(2588, "2018-08-14");
+insert into diaries values(2589, "2018-08-15");
+insert into diaries values(2590, "2018-08-16");
+insert into diaries values(2591, "2018-08-17");
+insert into diaries values(2592, "2018-08-18");
+insert into diaries values(2593, "2018-08-19");
+insert into diaries values(2594, "2018-08-20");
+insert into diaries values(2595, "2018-08-21");
+insert into diaries values(2596, "2018-08-22");
+insert into diaries values(2597, "2018-08-23");
+insert into diaries values(2598, "2018-08-24");
+insert into diaries values(2599, "2018-08-25");
+insert into diaries values(2600, "2018-08-26");
+insert into diaries values(2601, "2018-08-27");
+insert into diaries values(2602, "2018-08-28");
+insert into diaries values(2603, "2018-08-29");
+insert into diaries values(2604, "2018-08-30");
+insert into diaries values(2605, "2018-08-31");
+insert into diaries values(2606, "2018-09-01");
+insert into diaries values(2607, "2018-09-02");
+insert into diaries values(2608, "2018-09-03");
+insert into diaries values(2609, "2018-09-04");
+insert into diaries values(2610, "2018-09-05");
+insert into diaries values(2611, "2018-09-06");
+insert into diaries values(2612, "2018-09-07");
+insert into diaries values(2613, "2018-09-08");
+insert into diaries values(2614, "2018-09-09");
+insert into diaries values(2615, "2018-09-10");
+insert into diaries values(2616, "2018-09-11");
+insert into diaries values(2617, "2018-09-12");
+insert into diaries values(2618, "2018-09-13");
+insert into diaries values(2619, "2018-09-14");
+insert into diaries values(2620, "2018-09-15");
+insert into diaries values(2621, "2018-09-16");
+insert into diaries values(2622, "2018-09-17");
+insert into diaries values(2623, "2018-09-18");
+insert into diaries values(2624, "2018-09-19");
+insert into diaries values(2625, "2018-09-20");
+insert into diaries values(2626, "2018-09-21");
+insert into diaries values(2627, "2018-09-22");
+insert into diaries values(2628, "2018-09-23");
+insert into diaries values(2629, "2018-09-24");
+insert into diaries values(2630, "2018-09-25");
+insert into diaries values(2631, "2018-09-26");
+insert into diaries values(2632, "2018-09-27");
+insert into diaries values(2633, "2018-09-28");
+insert into diaries values(2634, "2018-09-29");
+insert into diaries values(2635, "2018-09-30");
+insert into diaries values(2636, "2018-10-01");
+insert into diaries values(2637, "2018-10-02");
+insert into diaries values(2638, "2018-10-03");
+insert into diaries values(2639, "2018-10-04");
+insert into diaries values(2640, "2018-10-05");
+insert into diaries values(2641, "2018-10-06");
+insert into diaries values(2642, "2018-10-07");
+insert into diaries values(2643, "2018-10-08");
+insert into diaries values(2644, "2018-10-09");
+insert into diaries values(2645, "2018-10-10");
+insert into diaries values(2646, "2018-10-11");
+insert into diaries values(2647, "2018-10-12");
+insert into diaries values(2648, "2018-10-13");
+insert into diaries values(2649, "2018-10-14");
+insert into diaries values(2650, "2018-10-15");
+insert into diaries values(2651, "2018-10-16");
+insert into diaries values(2652, "2018-10-17");
+insert into diaries values(2653, "2018-10-18");
+insert into diaries values(2654, "2018-10-19");
+insert into diaries values(2655, "2018-10-20");
+insert into diaries values(2656, "2018-10-21");
+insert into diaries values(2657, "2018-10-22");
+insert into diaries values(2658, "2018-10-23");
+insert into diaries values(2659, "2018-10-24");
+insert into diaries values(2660, "2018-10-25");
+insert into diaries values(2661, "2018-10-26");
+insert into diaries values(2662, "2018-10-27");
+insert into diaries values(2663, "2018-10-28");
+insert into diaries values(2664, "2018-10-29");
+insert into diaries values(2665, "2018-10-30");
+insert into diaries values(2666, "2018-10-31");
+insert into diaries values(2667, "2018-11-01");
+insert into diaries values(2668, "2018-11-02");
+insert into diaries values(2669, "2018-11-03");
+insert into diaries values(2670, "2018-11-04");
+insert into diaries values(2671, "2018-11-05");
+insert into diaries values(2672, "2018-11-06");
+insert into diaries values(2673, "2018-11-07");
+insert into diaries values(2674, "2018-11-08");
+insert into diaries values(2675, "2018-11-09");
+insert into diaries values(2676, "2018-11-10");
+insert into diaries values(2677, "2018-11-11");
+insert into diaries values(2678, "2018-11-12");
+insert into diaries values(2679, "2018-11-13");
+insert into diaries values(2680, "2018-11-14");
+insert into diaries values(2681, "2018-11-15");
+insert into diaries values(2682, "2018-11-16");
+insert into diaries values(2683, "2018-11-17");
+insert into diaries values(2684, "2018-11-18");
+insert into diaries values(2685, "2018-11-19");
+insert into diaries values(2686, "2018-11-20");
+insert into diaries values(2687, "2018-11-21");
+insert into diaries values(2688, "2018-11-22");
+insert into diaries values(2689, "2018-11-23");
+insert into diaries values(2690, "2018-11-24");
+insert into diaries values(2691, "2018-11-25");
+insert into diaries values(2692, "2018-11-26");
+insert into diaries values(2693, "2018-11-27");
+insert into diaries values(2694, "2018-11-28");
+insert into diaries values(2695, "2018-11-29");
+insert into diaries values(2696, "2018-11-30");
+insert into diaries values(2697, "2018-12-01");
+insert into diaries values(2698, "2018-12-02");
+insert into diaries values(2699, "2018-12-03");
+insert into diaries values(2700, "2018-12-04");
+insert into diaries values(2701, "2018-12-05");
+insert into diaries values(2702, "2018-12-06");
+insert into diaries values(2703, "2018-12-07");
+insert into diaries values(2704, "2018-12-08");
+insert into diaries values(2705, "2018-12-09");
+insert into diaries values(2706, "2018-12-10");
+insert into diaries values(2707, "2018-12-11");
+insert into diaries values(2708, "2018-12-12");
+insert into diaries values(2709, "2018-12-13");
+insert into diaries values(2710, "2018-12-14");
+insert into diaries values(2711, "2018-12-15");
+insert into diaries values(2712, "2018-12-16");
+insert into diaries values(2713, "2018-12-17");
+insert into diaries values(2714, "2018-12-18");
+insert into diaries values(2715, "2018-12-19");
+insert into diaries values(2716, "2018-12-20");
+insert into diaries values(2717, "2018-12-21");
+insert into diaries values(2718, "2018-12-22");
+insert into diaries values(2719, "2018-12-23");
+insert into diaries values(2720, "2018-12-24");
+insert into diaries values(2721, "2018-12-25");
+insert into diaries values(2722, "2018-12-26");
+insert into diaries values(2723, "2018-12-27");
+insert into diaries values(2724, "2018-12-28");
+insert into diaries values(2725, "2018-12-29");
+insert into diaries values(2726, "2018-12-30");
+insert into diaries values(2727, "2018-12-31");
+insert into diaries values(2728, "2019-01-01");
+insert into diaries values(2729, "2019-01-02");
+insert into diaries values(2730, "2019-01-03");
+insert into diaries values(2731, "2019-01-04");
+insert into diaries values(2732, "2019-01-05");
+insert into diaries values(2733, "2019-01-06");
+insert into diaries values(2734, "2019-01-07");
+insert into diaries values(2735, "2019-01-08");
+insert into diaries values(2736, "2019-01-09");
+insert into diaries values(2737, "2019-01-10");
+insert into diaries values(2738, "2019-01-11");
+insert into diaries values(2739, "2019-01-12");
+insert into diaries values(2740, "2019-01-13");
+insert into diaries values(2741, "2019-01-14");
+insert into diaries values(2742, "2019-01-15");
+insert into diaries values(2743, "2019-01-16");
+insert into diaries values(2744, "2019-01-17");
+insert into diaries values(2745, "2019-01-18");
+insert into diaries values(2746, "2019-01-19");
+insert into diaries values(2747, "2019-01-20");
+insert into diaries values(2748, "2019-01-21");
+insert into diaries values(2749, "2019-01-22");
+insert into diaries values(2750, "2019-01-23");
+insert into diaries values(2751, "2019-01-24");
+insert into diaries values(2752, "2019-01-25");
+insert into diaries values(2753, "2019-01-26");
+insert into diaries values(2754, "2019-01-27");
+insert into diaries values(2755, "2019-01-28");
+insert into diaries values(2756, "2019-01-29");
+insert into diaries values(2757, "2019-01-30");
+insert into diaries values(2758, "2019-01-31");
+insert into diaries values(2759, "2019-02-01");
+insert into diaries values(2760, "2019-02-02");
+insert into diaries values(2761, "2019-02-03");
+insert into diaries values(2762, "2019-02-04");
+insert into diaries values(2763, "2019-02-05");
+insert into diaries values(2764, "2019-02-06");
+insert into diaries values(2765, "2019-02-07");
+insert into diaries values(2766, "2019-02-08");
+insert into diaries values(2767, "2019-02-09");
+insert into diaries values(2768, "2019-02-10");
+insert into diaries values(2769, "2019-02-11");
+insert into diaries values(2770, "2019-02-12");
+insert into diaries values(2771, "2019-02-13");
+insert into diaries values(2772, "2019-02-14");
+insert into diaries values(2773, "2019-02-15");
+insert into diaries values(2774, "2019-02-16");
+insert into diaries values(2775, "2019-02-17");
+insert into diaries values(2776, "2019-02-18");
+insert into diaries values(2777, "2019-02-19");
+insert into diaries values(2778, "2019-02-20");
+insert into diaries values(2779, "2019-02-21");
+insert into diaries values(2780, "2019-02-22");
+insert into diaries values(2781, "2019-02-23");
+insert into diaries values(2782, "2019-02-24");
+insert into diaries values(2783, "2019-02-25");
+insert into diaries values(2784, "2019-02-26");
+insert into diaries values(2785, "2019-02-27");
+insert into diaries values(2786, "2019-02-28");
+insert into diaries values(2787, "2019-03-01");
+insert into diaries values(2788, "2019-03-02");
+insert into diaries values(2789, "2019-03-03");
+insert into diaries values(2790, "2019-03-04");
+insert into diaries values(2791, "2019-03-05");
+insert into diaries values(2792, "2019-03-06");
+insert into diaries values(2793, "2019-03-07");
+insert into diaries values(2794, "2019-03-08");
+insert into diaries values(2795, "2019-03-09");
+insert into diaries values(2796, "2019-03-10");
+insert into diaries values(2797, "2019-03-11");
+insert into diaries values(2798, "2019-03-12");
+insert into diaries values(2799, "2019-03-13");
+insert into diaries values(2800, "2019-03-14");
+insert into diaries values(2801, "2019-03-15");
+insert into diaries values(2802, "2019-03-16");
+insert into diaries values(2803, "2019-03-17");
+insert into diaries values(2804, "2019-03-18");
+insert into diaries values(2805, "2019-03-19");
+insert into diaries values(2806, "2019-03-20");
+insert into diaries values(2807, "2019-03-21");
+insert into diaries values(2808, "2019-03-22");
+insert into diaries values(2809, "2019-03-23");
+insert into diaries values(2810, "2019-03-24");
+insert into diaries values(2811, "2019-03-25");
+insert into diaries values(2812, "2019-03-26");
+insert into diaries values(2813, "2019-03-27");
+insert into diaries values(2814, "2019-03-28");
+insert into diaries values(2815, "2019-03-29");
+insert into diaries values(2816, "2019-03-30");
+insert into diaries values(2817, "2019-03-31");
+insert into diaries values(2818, "2019-04-01");
+insert into diaries values(2819, "2019-04-02");
+insert into diaries values(2820, "2019-04-03");
+insert into diaries values(2821, "2019-04-04");
+insert into diaries values(2822, "2019-04-05");
+insert into diaries values(2823, "2019-04-06");
+insert into diaries values(2824, "2019-04-07");
+insert into diaries values(2825, "2019-04-08");
+insert into diaries values(2826, "2019-04-09");
+insert into diaries values(2827, "2019-04-10");
+insert into diaries values(2828, "2019-04-11");
+insert into diaries values(2829, "2019-04-12");
+insert into diaries values(2830, "2019-04-13");
+insert into diaries values(2831, "2019-04-14");
+insert into diaries values(2832, "2019-04-15");
+insert into diaries values(2833, "2019-04-16");
+insert into diaries values(2834, "2019-04-17");
+insert into diaries values(2835, "2019-04-18");
+insert into diaries values(2836, "2019-04-19");
+insert into diaries values(2837, "2019-04-20");
+insert into diaries values(2838, "2019-04-21");
+insert into diaries values(2839, "2019-04-22");
+insert into diaries values(2840, "2019-04-23");
+insert into diaries values(2841, "2019-04-24");
+insert into diaries values(2842, "2019-04-25");
+insert into diaries values(2843, "2019-04-26");
+insert into diaries values(2844, "2019-04-27");
+insert into diaries values(2845, "2019-04-28");
+insert into diaries values(2846, "2019-04-29");
+insert into diaries values(2847, "2019-04-30");
+insert into diaries values(2848, "2019-05-01");
+insert into diaries values(2849, "2019-05-02");
+insert into diaries values(2850, "2019-05-03");
+insert into diaries values(2851, "2019-05-04");
+insert into diaries values(2852, "2019-05-05");
+insert into diaries values(2853, "2019-05-06");
+insert into diaries values(2854, "2019-05-07");
+insert into diaries values(2855, "2019-05-08");
+insert into diaries values(2856, "2019-05-09");
+insert into diaries values(2857, "2019-05-10");
+insert into diaries values(2858, "2019-05-11");
+insert into diaries values(2859, "2019-05-12");
+insert into diaries values(2860, "2019-05-13");
+insert into diaries values(2861, "2019-05-14");
+insert into diaries values(2862, "2019-05-15");
+insert into diaries values(2863, "2019-05-16");
+insert into diaries values(2864, "2019-05-17");
+insert into diaries values(2865, "2019-05-18");
+insert into diaries values(2866, "2019-05-19");
+insert into diaries values(2867, "2019-05-20");
+insert into diaries values(2868, "2019-05-21");
+insert into diaries values(2869, "2019-05-22");
+insert into diaries values(2870, "2019-05-23");
+insert into diaries values(2871, "2019-05-24");
+insert into diaries values(2872, "2019-05-25");
+insert into diaries values(2873, "2019-05-26");
+insert into diaries values(2874, "2019-05-27");
+insert into diaries values(2875, "2019-05-28");
+insert into diaries values(2876, "2019-05-29");
+insert into diaries values(2877, "2019-05-30");
+insert into diaries values(2878, "2019-05-31");
+insert into diaries values(2879, "2019-06-01");
+insert into diaries values(2880, "2019-06-02");
+insert into diaries values(2881, "2019-06-03");
+insert into diaries values(2882, "2019-06-04");
+insert into diaries values(2883, "2019-06-05");
+insert into diaries values(2884, "2019-06-06");
+insert into diaries values(2885, "2019-06-07");
+insert into diaries values(2886, "2019-06-08");
+insert into diaries values(2887, "2019-06-09");
+insert into diaries values(2888, "2019-06-10");
+insert into diaries values(2889, "2019-06-11");
+insert into diaries values(2890, "2019-06-12");
+insert into diaries values(2891, "2019-06-13");
+insert into diaries values(2892, "2019-06-14");
+insert into diaries values(2893, "2019-06-15");
+insert into diaries values(2894, "2019-06-16");
+insert into diaries values(2895, "2019-06-17");
+insert into diaries values(2896, "2019-06-18");
+insert into diaries values(2897, "2019-06-19");
+insert into diaries values(2898, "2019-06-20");
+insert into diaries values(2899, "2019-06-21");
+insert into diaries values(2900, "2019-06-22");
+insert into diaries values(2901, "2019-06-23");
+insert into diaries values(2902, "2019-06-24");
+insert into diaries values(2903, "2019-06-25");
+insert into diaries values(2904, "2019-06-26");
+insert into diaries values(2905, "2019-06-27");
+insert into diaries values(2906, "2019-06-28");
+insert into diaries values(2907, "2019-06-29");
+insert into diaries values(2908, "2019-06-30");
+insert into diaries values(2909, "2019-07-01");
+insert into diaries values(2910, "2019-07-02");
+insert into diaries values(2911, "2019-07-03");
+insert into diaries values(2912, "2019-07-04");
+insert into diaries values(2913, "2019-07-05");
+insert into diaries values(2914, "2019-07-06");
+insert into diaries values(2915, "2019-07-07");
+insert into diaries values(2916, "2019-07-08");
+insert into diaries values(2917, "2019-07-09");
+insert into diaries values(2918, "2019-07-10");
+insert into diaries values(2919, "2019-07-11");
+insert into diaries values(2920, "2019-07-12");
+insert into diaries values(2921, "2019-07-13");
+insert into diaries values(2922, "2019-07-14");
+insert into diaries values(2923, "2019-07-15");
+insert into diaries values(2924, "2019-07-16");
+insert into diaries values(2925, "2019-07-17");
+insert into diaries values(2926, "2019-07-18");
+insert into diaries values(2927, "2019-07-19");
+insert into diaries values(2928, "2019-07-20");
+insert into diaries values(2929, "2019-07-21");
+insert into diaries values(2930, "2019-07-22");
+insert into diaries values(2931, "2019-07-23");
+insert into diaries values(2932, "2019-07-24");
+insert into diaries values(2933, "2019-07-25");
+insert into diaries values(2934, "2019-07-26");
+insert into diaries values(2935, "2019-07-27");
+insert into diaries values(2936, "2019-07-28");
+insert into diaries values(2937, "2019-07-29");
+insert into diaries values(2938, "2019-07-30");
+insert into diaries values(2939, "2019-07-31");
+insert into diaries values(2940, "2019-08-01");
+insert into diaries values(2941, "2019-08-02");
+insert into diaries values(2942, "2019-08-03");
+insert into diaries values(2943, "2019-08-04");
+insert into diaries values(2944, "2019-08-05");
+insert into diaries values(2945, "2019-08-06");
+insert into diaries values(2946, "2019-08-07");
+insert into diaries values(2947, "2019-08-08");
+insert into diaries values(2948, "2019-08-09");
+insert into diaries values(2949, "2019-08-10");
+insert into diaries values(2950, "2019-08-11");
+insert into diaries values(2951, "2019-08-12");
+insert into diaries values(2952, "2019-08-13");
+insert into diaries values(2953, "2019-08-14");
+insert into diaries values(2954, "2019-08-15");
+insert into diaries values(2955, "2019-08-16");
+insert into diaries values(2956, "2019-08-17");
+insert into diaries values(2957, "2019-08-18");
+insert into diaries values(2958, "2019-08-19");
+insert into diaries values(2959, "2019-08-20");
+insert into diaries values(2960, "2019-08-21");
+insert into diaries values(2961, "2019-08-22");
+insert into diaries values(2962, "2019-08-23");
+insert into diaries values(2963, "2019-08-24");
+insert into diaries values(2964, "2019-08-25");
+insert into diaries values(2965, "2019-08-26");
+insert into diaries values(2966, "2019-08-27");
+insert into diaries values(2967, "2019-08-28");
+insert into diaries values(2968, "2019-08-29");
+insert into diaries values(2969, "2019-08-30");
+insert into diaries values(2970, "2019-08-31");
+insert into diaries values(2971, "2019-09-01");
+insert into diaries values(2972, "2019-09-02");
+insert into diaries values(2973, "2019-09-03");
+insert into diaries values(2974, "2019-09-04");
+insert into diaries values(2975, "2019-09-05");
+insert into diaries values(2976, "2019-09-06");
+insert into diaries values(2977, "2019-09-07");
+insert into diaries values(2978, "2019-09-08");
+insert into diaries values(2979, "2019-09-09");
+insert into diaries values(2980, "2019-09-10");
+insert into diaries values(2981, "2019-09-11");
+insert into diaries values(2982, "2019-09-12");
+insert into diaries values(2983, "2019-09-13");
+insert into diaries values(2984, "2019-09-14");
+insert into diaries values(2985, "2019-09-15");
+insert into diaries values(2986, "2019-09-16");
+insert into diaries values(2987, "2019-09-17");
+insert into diaries values(2988, "2019-09-18");
+insert into diaries values(2989, "2019-09-19");
+insert into diaries values(2990, "2019-09-20");
+insert into diaries values(2991, "2019-09-21");
+insert into diaries values(2992, "2019-09-22");
+insert into diaries values(2993, "2019-09-23");
+insert into diaries values(2994, "2019-09-24");
+insert into diaries values(2995, "2019-09-25");
+insert into diaries values(2996, "2019-09-26");
+insert into diaries values(2997, "2019-09-27");
+insert into diaries values(2998, "2019-09-28");
+insert into diaries values(2999, "2019-09-29");
+insert into diaries values(3000, "2019-09-30");
+insert into diaries values(3001, "2019-10-01");
+insert into diaries values(3002, "2019-10-02");
+insert into diaries values(3003, "2019-10-03");
+insert into diaries values(3004, "2019-10-04");
+insert into diaries values(3005, "2019-10-05");
+insert into diaries values(3006, "2019-10-06");
+insert into diaries values(3007, "2019-10-07");
+insert into diaries values(3008, "2019-10-08");
+insert into diaries values(3009, "2019-10-09");
+insert into diaries values(3010, "2019-10-10");
+insert into diaries values(3011, "2019-10-11");
+insert into diaries values(3012, "2019-10-12");
+insert into diaries values(3013, "2019-10-13");
+insert into diaries values(3014, "2019-10-14");
+insert into diaries values(3015, "2019-10-15");
+insert into diaries values(3016, "2019-10-16");
+insert into diaries values(3017, "2019-10-17");
+insert into diaries values(3018, "2019-10-18");
+insert into diaries values(3019, "2019-10-19");
+insert into diaries values(3020, "2019-10-20");
+insert into diaries values(3021, "2019-10-21");
+insert into diaries values(3022, "2019-10-22");
+insert into diaries values(3023, "2019-10-23");
+insert into diaries values(3024, "2019-10-24");
+insert into diaries values(3025, "2019-10-25");
+insert into diaries values(3026, "2019-10-26");
+insert into diaries values(3027, "2019-10-27");
+insert into diaries values(3028, "2019-10-28");
+insert into diaries values(3029, "2019-10-29");
+insert into diaries values(3030, "2019-10-30");
+insert into diaries values(3031, "2019-10-31");
+insert into diaries values(3032, "2019-11-01");
+insert into diaries values(3033, "2019-11-02");
+insert into diaries values(3034, "2019-11-03");
+insert into diaries values(3035, "2019-11-04");
+insert into diaries values(3036, "2019-11-05");
+insert into diaries values(3037, "2019-11-06");
+insert into diaries values(3038, "2019-11-07");
+insert into diaries values(3039, "2019-11-08");
+insert into diaries values(3040, "2019-11-09");
+insert into diaries values(3041, "2019-11-10");
+insert into diaries values(3042, "2019-11-11");
+insert into diaries values(3043, "2019-11-12");
+insert into diaries values(3044, "2019-11-13");
+insert into diaries values(3045, "2019-11-14");
+insert into diaries values(3046, "2019-11-15");
+insert into diaries values(3047, "2019-11-16");
+insert into diaries values(3048, "2019-11-17");
+insert into diaries values(3049, "2019-11-18");
+insert into diaries values(3050, "2019-11-19");
+insert into diaries values(3051, "2019-11-20");
+insert into diaries values(3052, "2019-11-21");
+insert into diaries values(3053, "2019-11-22");
+insert into diaries values(3054, "2019-11-23");
+insert into diaries values(3055, "2019-11-24");
+insert into diaries values(3056, "2019-11-25");
+insert into diaries values(3057, "2019-11-26");
+insert into diaries values(3058, "2019-11-27");
+insert into diaries values(3059, "2019-11-28");
+insert into diaries values(3060, "2019-11-29");
+insert into diaries values(3061, "2019-11-30");
+insert into diaries values(3062, "2019-12-01");
+insert into diaries values(3063, "2019-12-02");
+insert into diaries values(3064, "2019-12-03");
+insert into diaries values(3065, "2019-12-04");
+insert into diaries values(3066, "2019-12-05");
+insert into diaries values(3067, "2019-12-06");
+insert into diaries values(3068, "2019-12-07");
+insert into diaries values(3069, "2019-12-08");
+insert into diaries values(3070, "2019-12-09");
+insert into diaries values(3071, "2019-12-10");
+insert into diaries values(3072, "2019-12-11");
+insert into diaries values(3073, "2019-12-12");
+insert into diaries values(3074, "2019-12-13");
+insert into diaries values(3075, "2019-12-14");
+insert into diaries values(3076, "2019-12-15");
+insert into diaries values(3077, "2019-12-16");
+insert into diaries values(3078, "2019-12-17");
+insert into diaries values(3079, "2019-12-18");
+insert into diaries values(3080, "2019-12-19");
+insert into diaries values(3081, "2019-12-20");
+insert into diaries values(3082, "2019-12-21");
+insert into diaries values(3083, "2019-12-22");
+insert into diaries values(3084, "2019-12-23");
+insert into diaries values(3085, "2019-12-24");
+insert into diaries values(3086, "2019-12-25");
+insert into diaries values(3087, "2019-12-26");
+insert into diaries values(3088, "2019-12-27");
+insert into diaries values(3089, "2019-12-28");
+insert into diaries values(3090, "2019-12-29");
+insert into diaries values(3091, "2019-12-30");
+insert into diaries values(3092, "2019-12-31");
+insert into diaries values(3093, "2020-01-01");
+insert into diaries values(3094, "2020-01-02");
+insert into diaries values(3095, "2020-01-03");
+insert into diaries values(3096, "2020-01-04");
+insert into diaries values(3097, "2020-01-05");
+insert into diaries values(3098, "2020-01-06");
+insert into diaries values(3099, "2020-01-07");
+insert into diaries values(3100, "2020-01-08");
+insert into diaries values(3101, "2020-01-09");
+insert into diaries values(3102, "2020-01-10");
+insert into diaries values(3103, "2020-01-11");
+insert into diaries values(3104, "2020-01-12");
+insert into diaries values(3105, "2020-01-13");
+insert into diaries values(3106, "2020-01-14");
+insert into diaries values(3107, "2020-01-15");
+insert into diaries values(3108, "2020-01-16");
+insert into diaries values(3109, "2020-01-17");
+insert into diaries values(3110, "2020-01-18");
+insert into diaries values(3111, "2020-01-19");
+insert into diaries values(3112, "2020-01-20");
+insert into diaries values(3113, "2020-01-21");
+insert into diaries values(3114, "2020-01-22");
+insert into diaries values(3115, "2020-01-23");
+insert into diaries values(3116, "2020-01-24");
+insert into diaries values(3117, "2020-01-25");
+insert into diaries values(3118, "2020-01-26");
+insert into diaries values(3119, "2020-01-27");
+insert into diaries values(3120, "2020-01-28");
+insert into diaries values(3121, "2020-01-29");
+insert into diaries values(3122, "2020-01-30");
+insert into diaries values(3123, "2020-01-31");
+insert into diaries values(3124, "2020-02-01");
+insert into diaries values(3125, "2020-02-02");
+insert into diaries values(3126, "2020-02-03");
+insert into diaries values(3127, "2020-02-04");
+insert into diaries values(3128, "2020-02-05");
+insert into diaries values(3129, "2020-02-06");
+insert into diaries values(3130, "2020-02-07");
+insert into diaries values(3131, "2020-02-08");
+insert into diaries values(3132, "2020-02-09");
+insert into diaries values(3133, "2020-02-10");
+insert into diaries values(3134, "2020-02-11");
+insert into diaries values(3135, "2020-02-12");
+insert into diaries values(3136, "2020-02-13");
+insert into diaries values(3137, "2020-02-14");
+insert into diaries values(3138, "2020-02-15");
+insert into diaries values(3139, "2020-02-16");
+insert into diaries values(3140, "2020-02-17");
+insert into diaries values(3141, "2020-02-18");
+insert into diaries values(3142, "2020-02-19");
+insert into diaries values(3143, "2020-02-20");
+insert into diaries values(3144, "2020-02-21");
+insert into diaries values(3145, "2020-02-22");
+insert into diaries values(3146, "2020-02-23");
+insert into diaries values(3147, "2020-02-24");
+insert into diaries values(3148, "2020-02-25");
+insert into diaries values(3149, "2020-02-26");
+insert into diaries values(3150, "2020-02-27");
+insert into diaries values(3151, "2020-02-28");
+insert into diaries values(3152, "2020-02-29");
+insert into diaries values(3153, "2020-03-01");
+insert into diaries values(3154, "2020-03-02");
+insert into diaries values(3155, "2020-03-03");
+insert into diaries values(3156, "2020-03-04");
+insert into diaries values(3157, "2020-03-05");
+insert into diaries values(3158, "2020-03-06");
+insert into diaries values(3159, "2020-03-07");
+insert into diaries values(3160, "2020-03-08");
+insert into diaries values(3161, "2020-03-09");
+insert into diaries values(3162, "2020-03-10");
+insert into diaries values(3163, "2020-03-11");
+insert into diaries values(3164, "2020-03-12");
+insert into diaries values(3165, "2020-03-13");
+insert into diaries values(3166, "2020-03-14");
+insert into diaries values(3167, "2020-03-15");
+insert into diaries values(3168, "2020-03-16");
+insert into diaries values(3169, "2020-03-17");
+insert into diaries values(3170, "2020-03-18");
+insert into diaries values(3171, "2020-03-19");
+insert into diaries values(3172, "2020-03-20");
+insert into diaries values(3173, "2020-03-21");
+insert into diaries values(3174, "2020-03-22");
+insert into diaries values(3175, "2020-03-23");
+insert into diaries values(3176, "2020-03-24");
+insert into diaries values(3177, "2020-03-25");
+insert into diaries values(3178, "2020-03-26");
+insert into diaries values(3179, "2020-03-27");
+insert into diaries values(3180, "2020-03-28");
+insert into diaries values(3181, "2020-03-29");
+insert into diaries values(3182, "2020-03-30");
+insert into diaries values(3183, "2020-03-31");
+insert into diaries values(3184, "2020-04-01");
+insert into diaries values(3185, "2020-04-02");
+insert into diaries values(3186, "2020-04-03");
+insert into diaries values(3187, "2020-04-04");
+insert into diaries values(3188, "2020-04-05");
+insert into diaries values(3189, "2020-04-06");
+insert into diaries values(3190, "2020-04-07");
+insert into diaries values(3191, "2020-04-08");
+insert into diaries values(3192, "2020-04-09");
+insert into diaries values(3193, "2020-04-10");
+insert into diaries values(3194, "2020-04-11");
+insert into diaries values(3195, "2020-04-12");
+insert into diaries values(3196, "2020-04-13");
+insert into diaries values(3197, "2020-04-14");
+insert into diaries values(3198, "2020-04-15");
+insert into diaries values(3199, "2020-04-16");
+insert into diaries values(3200, "2020-04-17");
+insert into diaries values(3201, "2020-04-18");
+insert into diaries values(3202, "2020-04-19");
+insert into diaries values(3203, "2020-04-20");
+insert into diaries values(3204, "2020-04-21");
+insert into diaries values(3205, "2020-04-22");
+insert into diaries values(3206, "2020-04-23");
+insert into diaries values(3207, "2020-04-24");
+insert into diaries values(3208, "2020-04-25");
+insert into diaries values(3209, "2020-04-26");
+insert into diaries values(3210, "2020-04-27");
+insert into diaries values(3211, "2020-04-28");
+insert into diaries values(3212, "2020-04-29");
+insert into diaries values(3213, "2020-04-30");
+insert into diaries values(3214, "2020-05-01");
+insert into diaries values(3215, "2020-05-02");
+insert into diaries values(3216, "2020-05-03");
+insert into diaries values(3217, "2020-05-04");
+insert into diaries values(3218, "2020-05-05");
+insert into diaries values(3219, "2020-05-06");
+insert into diaries values(3220, "2020-05-07");
+insert into diaries values(3221, "2020-05-08");
+insert into diaries values(3222, "2020-05-09");
+insert into diaries values(3223, "2020-05-10");
+insert into diaries values(3224, "2020-05-11");
+insert into diaries values(3225, "2020-05-12");
+insert into diaries values(3226, "2020-05-13");
+insert into diaries values(3227, "2020-05-14");
+insert into diaries values(3228, "2020-05-15");
+insert into diaries values(3229, "2020-05-16");
+insert into diaries values(3230, "2020-05-17");
+insert into diaries values(3231, "2020-05-18");
+insert into diaries values(3232, "2020-05-19");
+insert into diaries values(3233, "2020-05-20");
+insert into diaries values(3234, "2020-05-21");
+insert into diaries values(3235, "2020-05-22");
+insert into diaries values(3236, "2020-05-23");
+insert into diaries values(3237, "2020-05-24");
+insert into diaries values(3238, "2020-05-25");
+insert into diaries values(3239, "2020-05-26");
+insert into diaries values(3240, "2020-05-27");
+insert into diaries values(3241, "2020-05-28");
+insert into diaries values(3242, "2020-05-29");
+insert into diaries values(3243, "2020-05-30");
+insert into diaries values(3244, "2020-05-31");
+insert into diaries values(3245, "2020-06-01");
+insert into diaries values(3246, "2020-06-02");
+insert into diaries values(3247, "2020-06-03");
+insert into diaries values(3248, "2020-06-04");
+insert into diaries values(3249, "2020-06-05");
+insert into diaries values(3250, "2020-06-06");
+insert into diaries values(3251, "2020-06-07");
+insert into diaries values(3252, "2020-06-08");
+insert into diaries values(3253, "2020-06-09");
+insert into diaries values(3254, "2020-06-10");
+insert into diaries values(3255, "2020-06-11");
+insert into diaries values(3256, "2020-06-12");
+insert into diaries values(3257, "2020-06-13");
+insert into diaries values(3258, "2020-06-14");
+insert into diaries values(3259, "2020-06-15");
+insert into diaries values(3260, "2020-06-16");
+insert into diaries values(3261, "2020-06-17");
+insert into diaries values(3262, "2020-06-18");
+insert into diaries values(3263, "2020-06-19");
+insert into diaries values(3264, "2020-06-20");
+insert into diaries values(3265, "2020-06-21");
+insert into diaries values(3266, "2020-06-22");
+insert into diaries values(3267, "2020-06-23");
+insert into diaries values(3268, "2020-06-24");
+insert into diaries values(3269, "2020-06-25");
+insert into diaries values(3270, "2020-06-26");
+insert into diaries values(3271, "2020-06-27");
+insert into diaries values(3272, "2020-06-28");
+insert into diaries values(3273, "2020-06-29");
+insert into diaries values(3274, "2020-06-30");
+insert into diaries values(3275, "2020-07-01");
+insert into diaries values(3276, "2020-07-02");
+insert into diaries values(3277, "2020-07-03");
+insert into diaries values(3278, "2020-07-04");
+insert into diaries values(3279, "2020-07-05");
+insert into diaries values(3280, "2020-07-06");
+insert into diaries values(3281, "2020-07-07");
+insert into diaries values(3282, "2020-07-08");
+insert into diaries values(3283, "2020-07-09");
+insert into diaries values(3284, "2020-07-10");
+insert into diaries values(3285, "2020-07-11");
+insert into diaries values(3286, "2020-07-12");
+insert into diaries values(3287, "2020-07-13");
+insert into diaries values(3288, "2020-07-14");
+insert into diaries values(3289, "2020-07-15");
+insert into diaries values(3290, "2020-07-16");
+insert into diaries values(3291, "2020-07-17");
+insert into diaries values(3292, "2020-07-18");
+insert into diaries values(3293, "2020-07-19");
+insert into diaries values(3294, "2020-07-20");
+insert into diaries values(3295, "2020-07-21");
+insert into diaries values(3296, "2020-07-22");
+insert into diaries values(3297, "2020-07-23");
+insert into diaries values(3298, "2020-07-24");
+insert into diaries values(3299, "2020-07-25");
+insert into diaries values(3300, "2020-07-26");
+insert into diaries values(3301, "2020-07-27");
+insert into diaries values(3302, "2020-07-28");
+insert into diaries values(3303, "2020-07-29");
+insert into diaries values(3304, "2020-07-30");
+insert into diaries values(3305, "2020-07-31");
+insert into diaries values(3306, "2020-08-01");
+insert into diaries values(3307, "2020-08-02");
+insert into diaries values(3308, "2020-08-03");
+insert into diaries values(3309, "2020-08-04");
+insert into diaries values(3310, "2020-08-05");
+insert into diaries values(3311, "2020-08-06");
+insert into diaries values(3312, "2020-08-07");
+insert into diaries values(3313, "2020-08-08");
+insert into diaries values(3314, "2020-08-09");
+insert into diaries values(3315, "2020-08-10");
+insert into diaries values(3316, "2020-08-11");
+insert into diaries values(3317, "2020-08-12");
+insert into diaries values(3318, "2020-08-13");
+insert into diaries values(3319, "2020-08-14");
+insert into diaries values(3320, "2020-08-15");
+insert into diaries values(3321, "2020-08-16");
+insert into diaries values(3322, "2020-08-17");
+insert into diaries values(3323, "2020-08-18");
+insert into diaries values(3324, "2020-08-19");
+insert into diaries values(3325, "2020-08-20");
+insert into diaries values(3326, "2020-08-21");
+insert into diaries values(3327, "2020-08-22");
+insert into diaries values(3328, "2020-08-23");
+insert into diaries values(3329, "2020-08-24");
+insert into diaries values(3330, "2020-08-25");
+insert into diaries values(3331, "2020-08-26");
+insert into diaries values(3332, "2020-08-27");
+insert into diaries values(3333, "2020-08-28");
+insert into diaries values(3334, "2020-08-29");
+insert into diaries values(3335, "2020-08-30");
+insert into diaries values(3336, "2020-08-31");
+insert into diaries values(3337, "2020-09-01");
+insert into diaries values(3338, "2020-09-02");
+insert into diaries values(3339, "2020-09-03");
+insert into diaries values(3340, "2020-09-04");
+insert into diaries values(3341, "2020-09-05");
+insert into diaries values(3342, "2020-09-06");
+insert into diaries values(3343, "2020-09-07");
+insert into diaries values(3344, "2020-09-08");
+insert into diaries values(3345, "2020-09-09");
+insert into diaries values(3346, "2020-09-10");
+insert into diaries values(3347, "2020-09-11");
+insert into diaries values(3348, "2020-09-12");
+insert into diaries values(3349, "2020-09-13");
+insert into diaries values(3350, "2020-09-14");
+insert into diaries values(3351, "2020-09-15");
+insert into diaries values(3352, "2020-09-16");
+insert into diaries values(3353, "2020-09-17");
+insert into diaries values(3354, "2020-09-18");
+insert into diaries values(3355, "2020-09-19");
+insert into diaries values(3356, "2020-09-20");
+insert into diaries values(3357, "2020-09-21");
+insert into diaries values(3358, "2020-09-22");
+insert into diaries values(3359, "2020-09-23");
+insert into diaries values(3360, "2020-09-24");
+insert into diaries values(3361, "2020-09-25");
+insert into diaries values(3362, "2020-09-26");
+insert into diaries values(3363, "2020-09-27");
+insert into diaries values(3364, "2020-09-28");
+insert into diaries values(3365, "2020-09-29");
+insert into diaries values(3366, "2020-09-30");
+insert into diaries values(3367, "2020-10-01");
+insert into diaries values(3368, "2020-10-02");
+insert into diaries values(3369, "2020-10-03");
+insert into diaries values(3370, "2020-10-04");
+insert into diaries values(3371, "2020-10-05");
+insert into diaries values(3372, "2020-10-06");
+insert into diaries values(3373, "2020-10-07");
+insert into diaries values(3374, "2020-10-08");
+insert into diaries values(3375, "2020-10-09");
+insert into diaries values(3376, "2020-10-10");
+insert into diaries values(3377, "2020-10-11");
+insert into diaries values(3378, "2020-10-12");
+insert into diaries values(3379, "2020-10-13");
+insert into diaries values(3380, "2020-10-14");
+insert into diaries values(3381, "2020-10-15");
+insert into diaries values(3382, "2020-10-16");
+insert into diaries values(3383, "2020-10-17");
+insert into diaries values(3384, "2020-10-18");
+insert into diaries values(3385, "2020-10-19");
+insert into diaries values(3386, "2020-10-20");
+insert into diaries values(3387, "2020-10-21");
+insert into diaries values(3388, "2020-10-22");
+insert into diaries values(3389, "2020-10-23");
+insert into diaries values(3390, "2020-10-24");
+insert into diaries values(3391, "2020-10-25");
+insert into diaries values(3392, "2020-10-26");
+insert into diaries values(3393, "2020-10-27");
+insert into diaries values(3394, "2020-10-28");
+insert into diaries values(3395, "2020-10-29");
+insert into diaries values(3396, "2020-10-30");
+insert into diaries values(3397, "2020-10-31");
+insert into diaries values(3398, "2020-11-01");
+insert into diaries values(3399, "2020-11-02");
+insert into diaries values(3400, "2020-11-03");
+insert into diaries values(3401, "2020-11-04");
+insert into diaries values(3402, "2020-11-05");
+insert into diaries values(3403, "2020-11-06");
+insert into diaries values(3404, "2020-11-07");
+insert into diaries values(3405, "2020-11-08");
+insert into diaries values(3406, "2020-11-09");
+insert into diaries values(3407, "2020-11-10");
+insert into diaries values(3408, "2020-11-11");
+insert into diaries values(3409, "2020-11-12");
+insert into diaries values(3410, "2020-11-13");
+insert into diaries values(3411, "2020-11-14");
+insert into diaries values(3412, "2020-11-15");
+insert into diaries values(3413, "2020-11-16");
+insert into diaries values(3414, "2020-11-17");
+insert into diaries values(3415, "2020-11-18");
+insert into diaries values(3416, "2020-11-19");
+insert into diaries values(3417, "2020-11-20");
+insert into diaries values(3418, "2020-11-21");
+insert into diaries values(3419, "2020-11-22");
+insert into diaries values(3420, "2020-11-23");
+insert into diaries values(3421, "2020-11-24");
+insert into diaries values(3422, "2020-11-25");
+insert into diaries values(3423, "2020-11-26");
+insert into diaries values(3424, "2020-11-27");
+insert into diaries values(3425, "2020-11-28");
+insert into diaries values(3426, "2020-11-29");
+insert into diaries values(3427, "2020-11-30");
+insert into diaries values(3428, "2020-12-01");
+insert into diaries values(3429, "2020-12-02");
+insert into diaries values(3430, "2020-12-03");
+insert into diaries values(3431, "2020-12-04");
+insert into diaries values(3432, "2020-12-05");
+insert into diaries values(3433, "2020-12-06");
+insert into diaries values(3434, "2020-12-07");
+insert into diaries values(3435, "2020-12-08");
+insert into diaries values(3436, "2020-12-09");
+insert into diaries values(3437, "2020-12-10");
+insert into diaries values(3438, "2020-12-11");
+insert into diaries values(3439, "2020-12-12");
+insert into diaries values(3440, "2020-12-13");
+insert into diaries values(3441, "2020-12-14");
+insert into diaries values(3442, "2020-12-15");
+insert into diaries values(3443, "2020-12-16");
+insert into diaries values(3444, "2020-12-17");
+insert into diaries values(3445, "2020-12-18");
+insert into diaries values(3446, "2020-12-19");
+insert into diaries values(3447, "2020-12-20");
+insert into diaries values(3448, "2020-12-21");
+insert into diaries values(3449, "2020-12-22");
+insert into diaries values(3450, "2020-12-23");
+insert into diaries values(3451, "2020-12-24");
+insert into diaries values(3452, "2020-12-25");
+insert into diaries values(3453, "2020-12-26");
+insert into diaries values(3454, "2020-12-27");
+insert into diaries values(3455, "2020-12-28");
+insert into diaries values(3456, "2020-12-29");
+insert into diaries values(3457, "2020-12-30");
+insert into diaries values(3458, "2020-12-31");
+insert into diaries values(3459, "2021-01-01");
+insert into diaries values(3460, "2021-01-02");
+insert into diaries values(3461, "2021-01-03");
+insert into diaries values(3462, "2021-01-04");
+insert into diaries values(3463, "2021-01-05");
+insert into diaries values(3464, "2021-01-06");
+insert into diaries values(3465, "2021-01-07");
+insert into diaries values(3466, "2021-01-08");
+insert into diaries values(3467, "2021-01-09");
+insert into diaries values(3468, "2021-01-10");
+insert into diaries values(3469, "2021-01-11");
+insert into diaries values(3470, "2021-01-12");
+insert into diaries values(3471, "2021-01-13");
+insert into diaries values(3472, "2021-01-14");
+insert into diaries values(3473, "2021-01-15");
+insert into diaries values(3474, "2021-01-16");
+insert into diaries values(3475, "2021-01-17");
+insert into diaries values(3476, "2021-01-18");
+insert into diaries values(3477, "2021-01-19");
+insert into diaries values(3478, "2021-01-20");
+insert into diaries values(3479, "2021-01-21");
+insert into diaries values(3480, "2021-01-22");
+insert into diaries values(3481, "2021-01-23");
+insert into diaries values(3482, "2021-01-24");
+insert into diaries values(3483, "2021-01-25");
+insert into diaries values(3484, "2021-01-26");
+insert into diaries values(3485, "2021-01-27");
+insert into diaries values(3486, "2021-01-28");
+insert into diaries values(3487, "2021-01-29");
+insert into diaries values(3488, "2021-01-30");
+insert into diaries values(3489, "2021-01-31");
+insert into diaries values(3490, "2021-02-01");
+insert into diaries values(3491, "2021-02-02");
+insert into diaries values(3492, "2021-02-03");
+insert into diaries values(3493, "2021-02-04");
+insert into diaries values(3494, "2021-02-05");
+insert into diaries values(3495, "2021-02-06");
+insert into diaries values(3496, "2021-02-07");
+insert into diaries values(3497, "2021-02-08");
+insert into diaries values(3498, "2021-02-09");
+insert into diaries values(3499, "2021-02-10");
+insert into diaries values(3500, "2021-02-11");
+insert into diaries values(3501, "2021-02-12");
+insert into diaries values(3502, "2021-02-13");
+insert into diaries values(3503, "2021-02-14");
+insert into diaries values(3504, "2021-02-15");
+insert into diaries values(3505, "2021-02-16");
+insert into diaries values(3506, "2021-02-17");
+insert into diaries values(3507, "2021-02-18");
+insert into diaries values(3508, "2021-02-19");
+insert into diaries values(3509, "2021-02-20");
+insert into diaries values(3510, "2021-02-21");
+insert into diaries values(3511, "2021-02-22");
+insert into diaries values(3512, "2021-02-23");
+insert into diaries values(3513, "2021-02-24");
+insert into diaries values(3514, "2021-02-25");
+insert into diaries values(3515, "2021-02-26");
+insert into diaries values(3516, "2021-02-27");
+insert into diaries values(3517, "2021-02-28");
+insert into diaries values(3518, "2021-03-01");
+insert into diaries values(3519, "2021-03-02");
+insert into diaries values(3520, "2021-03-03");
+insert into diaries values(3521, "2021-03-04");
+insert into diaries values(3522, "2021-03-05");
+insert into diaries values(3523, "2021-03-06");
+insert into diaries values(3524, "2021-03-07");
+insert into diaries values(3525, "2021-03-08");
+insert into diaries values(3526, "2021-03-09");
+insert into diaries values(3527, "2021-03-10");
+insert into diaries values(3528, "2021-03-11");
+insert into diaries values(3529, "2021-03-12");
+insert into diaries values(3530, "2021-03-13");
+insert into diaries values(3531, "2021-03-14");
+insert into diaries values(3532, "2021-03-15");
+insert into diaries values(3533, "2021-03-16");
+insert into diaries values(3534, "2021-03-17");
+insert into diaries values(3535, "2021-03-18");
+insert into diaries values(3536, "2021-03-19");
+insert into diaries values(3537, "2021-03-20");
+insert into diaries values(3538, "2021-03-21");
+insert into diaries values(3539, "2021-03-22");
+insert into diaries values(3540, "2021-03-23");
+insert into diaries values(3541, "2021-03-24");
+insert into diaries values(3542, "2021-03-25");
+insert into diaries values(3543, "2021-03-26");
+insert into diaries values(3544, "2021-03-27");
+insert into diaries values(3545, "2021-03-28");
+insert into diaries values(3546, "2021-03-29");
+insert into diaries values(3547, "2021-03-30");
+insert into diaries values(3548, "2021-03-31");
+insert into diaries values(3549, "2021-04-01");
+insert into diaries values(3550, "2021-04-02");
+insert into diaries values(3551, "2021-04-03");
+insert into diaries values(3552, "2021-04-04");
+insert into diaries values(3553, "2021-04-05");
+insert into diaries values(3554, "2021-04-06");
+insert into diaries values(3555, "2021-04-07");
+insert into diaries values(3556, "2021-04-08");
+insert into diaries values(3557, "2021-04-09");
+insert into diaries values(3558, "2021-04-10");
+insert into diaries values(3559, "2021-04-11");
+insert into diaries values(3560, "2021-04-12");
+insert into diaries values(3561, "2021-04-13");
+insert into diaries values(3562, "2021-04-14");
+insert into diaries values(3563, "2021-04-15");
+insert into diaries values(3564, "2021-04-16");
+insert into diaries values(3565, "2021-04-17");
+insert into diaries values(3566, "2021-04-18");
+insert into diaries values(3567, "2021-04-19");
+insert into diaries values(3568, "2021-04-20");
+insert into diaries values(3569, "2021-04-21");
+insert into diaries values(3570, "2021-04-22");
+insert into diaries values(3571, "2021-04-23");
+insert into diaries values(3572, "2021-04-24");
+insert into diaries values(3573, "2021-04-25");
+insert into diaries values(3574, "2021-04-26");
+insert into diaries values(3575, "2021-04-27");
+insert into diaries values(3576, "2021-04-28");
+insert into diaries values(3577, "2021-04-29");
+insert into diaries values(3578, "2021-04-30");
+insert into diaries values(3579, "2021-05-01");
+insert into diaries values(3580, "2021-05-02");
+insert into diaries values(3581, "2021-05-03");
+insert into diaries values(3582, "2021-05-04");
+insert into diaries values(3583, "2021-05-05");
+insert into diaries values(3584, "2021-05-06");
+insert into diaries values(3585, "2021-05-07");
+insert into diaries values(3586, "2021-05-08");
+insert into diaries values(3587, "2021-05-09");
+insert into diaries values(3588, "2021-05-10");
+insert into diaries values(3589, "2021-05-11");
+insert into diaries values(3590, "2021-05-12");
+insert into diaries values(3591, "2021-05-13");
+insert into diaries values(3592, "2021-05-14");
+insert into diaries values(3593, "2021-05-15");
+insert into diaries values(3594, "2021-05-16");
+insert into diaries values(3595, "2021-05-17");
+insert into diaries values(3596, "2021-05-18");
+insert into diaries values(3597, "2021-05-19");
+insert into diaries values(3598, "2021-05-20");
+insert into diaries values(3599, "2021-05-21");
+insert into diaries values(3600, "2021-05-22");
+insert into diaries values(3601, "2021-05-23");
+insert into diaries values(3602, "2021-05-24");
+insert into diaries values(3603, "2021-05-25");
+insert into diaries values(3604, "2021-05-26");
+insert into diaries values(3605, "2021-05-27");
+insert into diaries values(3606, "2021-05-28");
+insert into diaries values(3607, "2021-05-29");
+insert into diaries values(3608, "2021-05-30");
+insert into diaries values(3609, "2021-05-31");
+insert into diaries values(3610, "2021-06-01");
+insert into diaries values(3611, "2021-06-02");
+insert into diaries values(3612, "2021-06-03");
+insert into diaries values(3613, "2021-06-04");
+insert into diaries values(3614, "2021-06-05");
+insert into diaries values(3615, "2021-06-06");
+insert into diaries values(3616, "2021-06-07");
+insert into diaries values(3617, "2021-06-08");
+insert into diaries values(3618, "2021-06-09");
+insert into diaries values(3619, "2021-06-10");
+insert into diaries values(3620, "2021-06-11");
+insert into diaries values(3621, "2021-06-12");
+insert into diaries values(3622, "2021-06-13");
+insert into diaries values(3623, "2021-06-14");
+insert into diaries values(3624, "2021-06-15");
+insert into diaries values(3625, "2021-06-16");
+insert into diaries values(3626, "2021-06-17");
+insert into diaries values(3627, "2021-06-18");
+insert into diaries values(3628, "2021-06-19");
+insert into diaries values(3629, "2021-06-20");
+insert into diaries values(3630, "2021-06-21");
+insert into diaries values(3631, "2021-06-22");
+insert into diaries values(3632, "2021-06-23");
+insert into diaries values(3633, "2021-06-24");
+insert into diaries values(3634, "2021-06-25");
+insert into diaries values(3635, "2021-06-26");
+insert into diaries values(3636, "2021-06-27");
+insert into diaries values(3637, "2021-06-28");
+insert into diaries values(3638, "2021-06-29");
+insert into diaries values(3639, "2021-06-30");
+insert into diaries values(3640, "2021-07-01");
+insert into diaries values(3641, "2021-07-02");
+insert into diaries values(3642, "2021-07-03");
+insert into diaries values(3643, "2021-07-04");
+insert into diaries values(3644, "2021-07-05");
+insert into diaries values(3645, "2021-07-06");
+insert into diaries values(3646, "2021-07-07");
+insert into diaries values(3647, "2021-07-08");
+insert into diaries values(3648, "2021-07-09");
+insert into diaries values(3649, "2021-07-10");
+insert into diaries values(3650, "2021-07-11");
+insert into diaries values(3651, "2021-07-12");
+insert into diaries values(3652, "2021-07-13");
+insert into diaries values(3653, "2021-07-14");
+insert into diaries values(3654, "2021-07-15");
+insert into diaries values(3655, "2021-07-16");
+insert into diaries values(3656, "2021-07-17");
+insert into diaries values(3657, "2021-07-18");
+insert into diaries values(3658, "2021-07-19");
+insert into diaries values(3659, "2021-07-20");
+insert into diaries values(3660, "2021-07-21");
+insert into diaries values(3661, "2021-07-22");
+insert into diaries values(3662, "2021-07-23");
+insert into diaries values(3663, "2021-07-24");
+insert into diaries values(3664, "2021-07-25");
+insert into diaries values(3665, "2021-07-26");
+insert into diaries values(3666, "2021-07-27");
+insert into diaries values(3667, "2021-07-28");
+insert into diaries values(3668, "2021-07-29");
+insert into diaries values(3669, "2021-07-30");
+insert into diaries values(3670, "2021-07-31");
+insert into diaries values(3671, "2021-08-01");
+insert into diaries values(3672, "2021-08-02");
+insert into diaries values(3673, "2021-08-03");
+insert into diaries values(3674, "2021-08-04");
+insert into diaries values(3675, "2021-08-05");
+insert into diaries values(3676, "2021-08-06");
+insert into diaries values(3677, "2021-08-07");
+insert into diaries values(3678, "2021-08-08");
+insert into diaries values(3679, "2021-08-09");
+insert into diaries values(3680, "2021-08-10");
+insert into diaries values(3681, "2021-08-11");
+insert into diaries values(3682, "2021-08-12");
+insert into diaries values(3683, "2021-08-13");
+insert into diaries values(3684, "2021-08-14");
+insert into diaries values(3685, "2021-08-15");
+insert into diaries values(3686, "2021-08-16");
+insert into diaries values(3687, "2021-08-17");
+insert into diaries values(3688, "2021-08-18");
+insert into diaries values(3689, "2021-08-19");
+insert into diaries values(3690, "2021-08-20");
+insert into diaries values(3691, "2021-08-21");
+insert into diaries values(3692, "2021-08-22");
+insert into diaries values(3693, "2021-08-23");
+insert into diaries values(3694, "2021-08-24");
+insert into diaries values(3695, "2021-08-25");
+insert into diaries values(3696, "2021-08-26");
+insert into diaries values(3697, "2021-08-27");
+insert into diaries values(3698, "2021-08-28");
+insert into diaries values(3699, "2021-08-29");
+insert into diaries values(3700, "2021-08-30");
+insert into diaries values(3701, "2021-08-31");
+insert into diaries values(3702, "2021-09-01");
+insert into diaries values(3703, "2021-09-02");
+insert into diaries values(3704, "2021-09-03");
+insert into diaries values(3705, "2021-09-04");
+insert into diaries values(3706, "2021-09-05");
+insert into diaries values(3707, "2021-09-06");
+insert into diaries values(3708, "2021-09-07");
+insert into diaries values(3709, "2021-09-08");
+insert into diaries values(3710, "2021-09-09");
+insert into diaries values(3711, "2021-09-10");
+insert into diaries values(3712, "2021-09-11");
+insert into diaries values(3713, "2021-09-12");
+insert into diaries values(3714, "2021-09-13");
+insert into diaries values(3715, "2021-09-14");
+insert into diaries values(3716, "2021-09-15");
+insert into diaries values(3717, "2021-09-16");
+insert into diaries values(3718, "2021-09-17");
+insert into diaries values(3719, "2021-09-18");
+insert into diaries values(3720, "2021-09-19");
+insert into diaries values(3721, "2021-09-20");
+insert into diaries values(3722, "2021-09-21");
+insert into diaries values(3723, "2021-09-22");
+insert into diaries values(3724, "2021-09-23");
+insert into diaries values(3725, "2021-09-24");
+insert into diaries values(3726, "2021-09-25");
+insert into diaries values(3727, "2021-09-26");
+insert into diaries values(3728, "2021-09-27");
+insert into diaries values(3729, "2021-09-28");
+insert into diaries values(3730, "2021-09-29");
+insert into diaries values(3731, "2021-09-30");
+insert into diaries values(3732, "2021-10-01");
+insert into diaries values(3733, "2021-10-02");
+insert into diaries values(3734, "2021-10-03");
+insert into diaries values(3735, "2021-10-04");
+insert into diaries values(3736, "2021-10-05");
+insert into diaries values(3737, "2021-10-06");
+insert into diaries values(3738, "2021-10-07");
+insert into diaries values(3739, "2021-10-08");
+insert into diaries values(3740, "2021-10-09");
+insert into diaries values(3741, "2021-10-10");
+insert into diaries values(3742, "2021-10-11");
+insert into diaries values(3743, "2021-10-12");
+insert into diaries values(3744, "2021-10-13");
+insert into diaries values(3745, "2021-10-14");
+insert into diaries values(3746, "2021-10-15");
+insert into diaries values(3747, "2021-10-16");
+insert into diaries values(3748, "2021-10-17");
+insert into diaries values(3749, "2021-10-18");
+insert into diaries values(3750, "2021-10-19");
+insert into diaries values(3751, "2021-10-20");
+insert into diaries values(3752, "2021-10-21");
+insert into diaries values(3753, "2021-10-22");
+insert into diaries values(3754, "2021-10-23");
+insert into diaries values(3755, "2021-10-24");
+insert into diaries values(3756, "2021-10-25");
+insert into diaries values(3757, "2021-10-26");
+insert into diaries values(3758, "2021-10-27");
+insert into diaries values(3759, "2021-10-28");
+insert into diaries values(3760, "2021-10-29");
+insert into diaries values(3761, "2021-10-30");
+insert into diaries values(3762, "2021-10-31");
+insert into diaries values(3763, "2021-11-01");
+insert into diaries values(3764, "2021-11-02");
+insert into diaries values(3765, "2021-11-03");
+insert into diaries values(3766, "2021-11-04");
+insert into diaries values(3767, "2021-11-05");
+insert into diaries values(3768, "2021-11-06");
+insert into diaries values(3769, "2021-11-07");
+insert into diaries values(3770, "2021-11-08");
+insert into diaries values(3771, "2021-11-09");
+insert into diaries values(3772, "2021-11-10");
+insert into diaries values(3773, "2021-11-11");
+insert into diaries values(3774, "2021-11-12");
+insert into diaries values(3775, "2021-11-13");
+insert into diaries values(3776, "2021-11-14");
+insert into diaries values(3777, "2021-11-15");
+insert into diaries values(3778, "2021-11-16");
+insert into diaries values(3779, "2021-11-17");
+insert into diaries values(3780, "2021-11-18");
+insert into diaries values(3781, "2021-11-19");
+insert into diaries values(3782, "2021-11-20");
+insert into diaries values(3783, "2021-11-21");
+insert into diaries values(3784, "2021-11-22");
+insert into diaries values(3785, "2021-11-23");
+insert into diaries values(3786, "2021-11-24");
+insert into diaries values(3787, "2021-11-25");
+insert into diaries values(3788, "2021-11-26");
+insert into diaries values(3789, "2021-11-27");
+insert into diaries values(3790, "2021-11-28");
+insert into diaries values(3791, "2021-11-29");
+insert into diaries values(3792, "2021-11-30");
+insert into diaries values(3793, "2021-12-01");
+insert into diaries values(3794, "2021-12-02");
+insert into diaries values(3795, "2021-12-03");
+insert into diaries values(3796, "2021-12-04");
+insert into diaries values(3797, "2021-12-05");
+insert into diaries values(3798, "2021-12-06");
+insert into diaries values(3799, "2021-12-07");
+insert into diaries values(3800, "2021-12-08");
+insert into diaries values(3801, "2021-12-09");
+insert into diaries values(3802, "2021-12-10");
+insert into diaries values(3803, "2021-12-11");
+insert into diaries values(3804, "2021-12-12");
+insert into diaries values(3805, "2021-12-13");
+insert into diaries values(3806, "2021-12-14");
+insert into diaries values(3807, "2021-12-15");
+insert into diaries values(3808, "2021-12-16");
+insert into diaries values(3809, "2021-12-17");
+insert into diaries values(3810, "2021-12-18");
+insert into diaries values(3811, "2021-12-19");
+insert into diaries values(3812, "2021-12-20");
+insert into diaries values(3813, "2021-12-21");
+insert into diaries values(3814, "2021-12-22");
+insert into diaries values(3815, "2021-12-23");
+insert into diaries values(3816, "2021-12-24");
+insert into diaries values(3817, "2021-12-25");
+insert into diaries values(3818, "2021-12-26");
+insert into diaries values(3819, "2021-12-27");
+insert into diaries values(3820, "2021-12-28");
+insert into diaries values(3821, "2021-12-29");
+insert into diaries values(3822, "2021-12-30");
+insert into diaries values(3823, "2021-12-31");
+insert into diaries values(3824, "2022-01-01");
+insert into diaries values(3825, "2022-01-02");
+insert into diaries values(3826, "2022-01-03");
+insert into diaries values(3827, "2022-01-04");
+insert into diaries values(3828, "2022-01-05");
+insert into diaries values(3829, "2022-01-06");
+insert into diaries values(3830, "2022-01-07");
+insert into diaries values(3831, "2022-01-08");
+insert into diaries values(3832, "2022-01-09");
+insert into diaries values(3833, "2022-01-10");
+insert into diaries values(3834, "2022-01-11");
+insert into diaries values(3835, "2022-01-12");
+insert into diaries values(3836, "2022-01-13");
+insert into diaries values(3837, "2022-01-14");
+insert into diaries values(3838, "2022-01-15");
+insert into diaries values(3839, "2022-01-16");
+insert into diaries values(3840, "2022-01-17");
+insert into diaries values(3841, "2022-01-18");
+insert into diaries values(3842, "2022-01-19");
+insert into diaries values(3843, "2022-01-20");
+insert into diaries values(3844, "2022-01-21");
+insert into diaries values(3845, "2022-01-22");
+insert into diaries values(3846, "2022-01-23");
+insert into diaries values(3847, "2022-01-24");
+insert into diaries values(3848, "2022-01-25");
+insert into diaries values(3849, "2022-01-26");
+insert into diaries values(3850, "2022-01-27");
+insert into diaries values(3851, "2022-01-28");
+insert into diaries values(3852, "2022-01-29");
+insert into diaries values(3853, "2022-01-30");
+insert into diaries values(3854, "2022-01-31");
+insert into diaries values(3855, "2022-02-01");
+insert into diaries values(3856, "2022-02-02");
+insert into diaries values(3857, "2022-02-03");
+insert into diaries values(3858, "2022-02-04");
+insert into diaries values(3859, "2022-02-05");
+insert into diaries values(3860, "2022-02-06");
+insert into diaries values(3861, "2022-02-07");
+insert into diaries values(3862, "2022-02-08");
+insert into diaries values(3863, "2022-02-09");
+insert into diaries values(3864, "2022-02-10");
+insert into diaries values(3865, "2022-02-11");
+insert into diaries values(3866, "2022-02-12");
+insert into diaries values(3867, "2022-02-13");
+insert into diaries values(3868, "2022-02-14");
+insert into diaries values(3869, "2022-02-15");
+insert into diaries values(3870, "2022-02-16");
+insert into diaries values(3871, "2022-02-17");
+insert into diaries values(3872, "2022-02-18");
+insert into diaries values(3873, "2022-02-19");
+insert into diaries values(3874, "2022-02-20");
+insert into diaries values(3875, "2022-02-21");
+insert into diaries values(3876, "2022-02-22");
+insert into diaries values(3877, "2022-02-23");
+insert into diaries values(3878, "2022-02-24");
+insert into diaries values(3879, "2022-02-25");
+insert into diaries values(3880, "2022-02-26");
+insert into diaries values(3881, "2022-02-27");
+insert into diaries values(3882, "2022-02-28");
+insert into diaries values(3883, "2022-03-01");
+insert into diaries values(3884, "2022-03-02");
+insert into diaries values(3885, "2022-03-03");
+insert into diaries values(3886, "2022-03-04");
+insert into diaries values(3887, "2022-03-05");
+insert into diaries values(3888, "2022-03-06");
+insert into diaries values(3889, "2022-03-07");
+insert into diaries values(3890, "2022-03-08");
+insert into diaries values(3891, "2022-03-09");
+insert into diaries values(3892, "2022-03-10");
+insert into diaries values(3893, "2022-03-11");
+insert into diaries values(3894, "2022-03-12");
+insert into diaries values(3895, "2022-03-13");
+insert into diaries values(3896, "2022-03-14");
+insert into diaries values(3897, "2022-03-15");
+insert into diaries values(3898, "2022-03-16");
+insert into diaries values(3899, "2022-03-17");
+insert into diaries values(3900, "2022-03-18");
+insert into diaries values(3901, "2022-03-19");
+insert into diaries values(3902, "2022-03-20");
+insert into diaries values(3903, "2022-03-21");
+insert into diaries values(3904, "2022-03-22");
+insert into diaries values(3905, "2022-03-23");
+insert into diaries values(3906, "2022-03-24");
+insert into diaries values(3907, "2022-03-25");
+insert into diaries values(3908, "2022-03-26");
+insert into diaries values(3909, "2022-03-27");
+insert into diaries values(3910, "2022-03-28");
+insert into diaries values(3911, "2022-03-29");
+insert into diaries values(3912, "2022-03-30");
+insert into diaries values(3913, "2022-03-31");
+insert into diaries values(3914, "2022-04-01");
+insert into diaries values(3915, "2022-04-02");
+insert into diaries values(3916, "2022-04-03");
+insert into diaries values(3917, "2022-04-04");
+insert into diaries values(3918, "2022-04-05");
+insert into diaries values(3919, "2022-04-06");
+insert into diaries values(3920, "2022-04-07");
+insert into diaries values(3921, "2022-04-08");
+insert into diaries values(3922, "2022-04-09");
+insert into diaries values(3923, "2022-04-10");
+insert into diaries values(3924, "2022-04-11");
+insert into diaries values(3925, "2022-04-12");
+insert into diaries values(3926, "2022-04-13");
+insert into diaries values(3927, "2022-04-14");
+insert into diaries values(3928, "2022-04-15");
+insert into diaries values(3929, "2022-04-16");
+insert into diaries values(3930, "2022-04-17");
+insert into diaries values(3931, "2022-04-18");
+insert into diaries values(3932, "2022-04-19");
+insert into diaries values(3933, "2022-04-20");
+insert into diaries values(3934, "2022-04-21");
+insert into diaries values(3935, "2022-04-22");
+insert into diaries values(3936, "2022-04-23");
+insert into diaries values(3937, "2022-04-24");
+insert into diaries values(3938, "2022-04-25");
+insert into diaries values(3939, "2022-04-26");
+insert into diaries values(3940, "2022-04-27");
+insert into diaries values(3941, "2022-04-28");
+insert into diaries values(3942, "2022-04-29");
+insert into diaries values(3943, "2022-04-30");
+insert into diaries values(3944, "2022-05-01");
+insert into diaries values(3945, "2022-05-02");
+insert into diaries values(3946, "2022-05-03");
+insert into diaries values(3947, "2022-05-04");
+insert into diaries values(3948, "2022-05-05");
+insert into diaries values(3949, "2022-05-06");
+insert into diaries values(3950, "2022-05-07");
+insert into diaries values(3951, "2022-05-08");
+insert into diaries values(3952, "2022-05-09");
+insert into diaries values(3953, "2022-05-10");
+insert into diaries values(3954, "2022-05-11");
+insert into diaries values(3955, "2022-05-12");
+insert into diaries values(3956, "2022-05-13");
+insert into diaries values(3957, "2022-05-14");
+insert into diaries values(3958, "2022-05-15");
+insert into diaries values(3959, "2022-05-16");
+insert into diaries values(3960, "2022-05-17");
+insert into diaries values(3961, "2022-05-18");
+insert into diaries values(3962, "2022-05-19");
+insert into diaries values(3963, "2022-05-20");
+insert into diaries values(3964, "2022-05-21");
+insert into diaries values(3965, "2022-05-22");
+insert into diaries values(3966, "2022-05-23");
+insert into diaries values(3967, "2022-05-24");
+insert into diaries values(3968, "2022-05-25");
+insert into diaries values(3969, "2022-05-26");
+insert into diaries values(3970, "2022-05-27");
+insert into diaries values(3971, "2022-05-28");
+insert into diaries values(3972, "2022-05-29");
+insert into diaries values(3973, "2022-05-30");
+insert into diaries values(3974, "2022-05-31");
+insert into diaries values(3975, "2022-06-01");
+insert into diaries values(3976, "2022-06-02");
+insert into diaries values(3977, "2022-06-03");
+insert into diaries values(3978, "2022-06-04");
+insert into diaries values(3979, "2022-06-05");
+insert into diaries values(3980, "2022-06-06");
+insert into diaries values(3981, "2022-06-07");
+insert into diaries values(3982, "2022-06-08");
+insert into diaries values(3983, "2022-06-09");
+insert into diaries values(3984, "2022-06-10");
+insert into diaries values(3985, "2022-06-11");
+insert into diaries values(3986, "2022-06-12");
+insert into diaries values(3987, "2022-06-13");
+insert into diaries values(3988, "2022-06-14");
+insert into diaries values(3989, "2022-06-15");
+insert into diaries values(3990, "2022-06-16");
+insert into diaries values(3991, "2022-06-17");
+insert into diaries values(3992, "2022-06-18");
+insert into diaries values(3993, "2022-06-19");
+insert into diaries values(3994, "2022-06-20");
+insert into diaries values(3995, "2022-06-21");
+insert into diaries values(3996, "2022-06-22");
+insert into diaries values(3997, "2022-06-23");
+insert into diaries values(3998, "2022-06-24");
+insert into diaries values(3999, "2022-06-25");
+insert into diaries values(4000, "2022-06-26");
+insert into diaries values(4001, "2022-06-27");
+insert into diaries values(4002, "2022-06-28");
+insert into diaries values(4003, "2022-06-29");
+insert into diaries values(4004, "2022-06-30");
+insert into diaries values(4005, "2022-07-01");
+insert into diaries values(4006, "2022-07-02");
+insert into diaries values(4007, "2022-07-03");
+insert into diaries values(4008, "2022-07-04");
+insert into diaries values(4009, "2022-07-05");
+insert into diaries values(4010, "2022-07-06");
+insert into diaries values(4011, "2022-07-07");
+insert into diaries values(4012, "2022-07-08");
+insert into diaries values(4013, "2022-07-09");
+insert into diaries values(4014, "2022-07-10");
+insert into diaries values(4015, "2022-07-11");
+insert into diaries values(4016, "2022-07-12");
+insert into diaries values(4017, "2022-07-13");
+insert into diaries values(4018, "2022-07-14");
+insert into diaries values(4019, "2022-07-15");
+insert into diaries values(4020, "2022-07-16");
+insert into diaries values(4021, "2022-07-17");
+insert into diaries values(4022, "2022-07-18");
+insert into diaries values(4023, "2022-07-19");
+insert into diaries values(4024, "2022-07-20");
+insert into diaries values(4025, "2022-07-21");
+insert into diaries values(4026, "2022-07-22");
+insert into diaries values(4027, "2022-07-23");
+insert into diaries values(4028, "2022-07-24");
+insert into diaries values(4029, "2022-07-25");
+insert into diaries values(4030, "2022-07-26");
+insert into diaries values(4031, "2022-07-27");
+insert into diaries values(4032, "2022-07-28");
+insert into diaries values(4033, "2022-07-29");
+insert into diaries values(4034, "2022-07-30");
+insert into diaries values(4035, "2022-07-31");
+insert into diaries values(4036, "2022-08-01");
+insert into diaries values(4037, "2022-08-02");
+insert into diaries values(4038, "2022-08-03");
+insert into diaries values(4039, "2022-08-04");
+insert into diaries values(4040, "2022-08-05");
+insert into diaries values(4041, "2022-08-06");
+insert into diaries values(4042, "2022-08-07");
+insert into diaries values(4043, "2022-08-08");
+insert into diaries values(4044, "2022-08-09");
+insert into diaries values(4045, "2022-08-10");
+insert into diaries values(4046, "2022-08-11");
+insert into diaries values(4047, "2022-08-12");
+insert into diaries values(4048, "2022-08-13");
+insert into diaries values(4049, "2022-08-14");
+insert into diaries values(4050, "2022-08-15");
+insert into diaries values(4051, "2022-08-16");
+insert into diaries values(4052, "2022-08-17");
+insert into diaries values(4053, "2022-08-18");
+insert into diaries values(4054, "2022-08-19");
+insert into diaries values(4055, "2022-08-20");
+insert into diaries values(4056, "2022-08-21");
+insert into diaries values(4057, "2022-08-22");
+insert into diaries values(4058, "2022-08-23");
+insert into diaries values(4059, "2022-08-24");
+insert into diaries values(4060, "2022-08-25");
+insert into diaries values(4061, "2022-08-26");
+insert into diaries values(4062, "2022-08-27");
+insert into diaries values(4063, "2022-08-28");
+insert into diaries values(4064, "2022-08-29");
+insert into diaries values(4065, "2022-08-30");
+insert into diaries values(4066, "2022-08-31");
+insert into diaries values(4067, "2022-09-01");
+insert into diaries values(4068, "2022-09-02");
+insert into diaries values(4069, "2022-09-03");
+insert into diaries values(4070, "2022-09-04");
+insert into diaries values(4071, "2022-09-05");
+insert into diaries values(4072, "2022-09-06");
+insert into diaries values(4073, "2022-09-07");
+insert into diaries values(4074, "2022-09-08");
+insert into diaries values(4075, "2022-09-09");
+insert into diaries values(4076, "2022-09-10");
+insert into diaries values(4077, "2022-09-11");
+insert into diaries values(4078, "2022-09-12");
+insert into diaries values(4079, "2022-09-13");
+insert into diaries values(4080, "2022-09-14");
+insert into diaries values(4081, "2022-09-15");
+insert into diaries values(4082, "2022-09-16");
+insert into diaries values(4083, "2022-09-17");
+insert into diaries values(4084, "2022-09-18");
+insert into diaries values(4085, "2022-09-19");
+insert into diaries values(4086, "2022-09-20");
+insert into diaries values(4087, "2022-09-21");
+insert into diaries values(4088, "2022-09-22");
+insert into diaries values(4089, "2022-09-23");
+insert into diaries values(4090, "2022-09-24");
+insert into diaries values(4091, "2022-09-25");
+insert into diaries values(4092, "2022-09-26");
+insert into diaries values(4093, "2022-09-27");
+insert into diaries values(4094, "2022-09-28");
+insert into diaries values(4095, "2022-09-29");
+commit;
+set autocommit=1;
+select * from diaries where match(title) against("2022-09-0") order by id;
+id title
+3824 2022-01-01
+3825 2022-01-02
+3826 2022-01-03
+3827 2022-01-04
+3828 2022-01-05
+3829 2022-01-06
+3830 2022-01-07
+3831 2022-01-08
+3832 2022-01-09
+3833 2022-01-10
+3834 2022-01-11
+3835 2022-01-12
+3836 2022-01-13
+3837 2022-01-14
+3838 2022-01-15
+3839 2022-01-16
+3840 2022-01-17
+3841 2022-01-18
+3842 2022-01-19
+3843 2022-01-20
+3844 2022-01-21
+3845 2022-01-22
+3846 2022-01-23
+3847 2022-01-24
+3848 2022-01-25
+3849 2022-01-26
+3850 2022-01-27
+3851 2022-01-28
+3852 2022-01-29
+3853 2022-01-30
+3854 2022-01-31
+3855 2022-02-01
+3856 2022-02-02
+3857 2022-02-03
+3858 2022-02-04
+3859 2022-02-05
+3860 2022-02-06
+3861 2022-02-07
+3862 2022-02-08
+3863 2022-02-09
+3864 2022-02-10
+3865 2022-02-11
+3866 2022-02-12
+3867 2022-02-13
+3868 2022-02-14
+3869 2022-02-15
+3870 2022-02-16
+3871 2022-02-17
+3872 2022-02-18
+3873 2022-02-19
+3874 2022-02-20
+3875 2022-02-21
+3876 2022-02-22
+3877 2022-02-23
+3878 2022-02-24
+3879 2022-02-25
+3880 2022-02-26
+3881 2022-02-27
+3882 2022-02-28
+3883 2022-03-01
+3884 2022-03-02
+3885 2022-03-03
+3886 2022-03-04
+3887 2022-03-05
+3888 2022-03-06
+3889 2022-03-07
+3890 2022-03-08
+3891 2022-03-09
+3892 2022-03-10
+3893 2022-03-11
+3894 2022-03-12
+3895 2022-03-13
+3896 2022-03-14
+3897 2022-03-15
+3898 2022-03-16
+3899 2022-03-17
+3900 2022-03-18
+3901 2022-03-19
+3902 2022-03-20
+3903 2022-03-21
+3904 2022-03-22
+3905 2022-03-23
+3906 2022-03-24
+3907 2022-03-25
+3908 2022-03-26
+3909 2022-03-27
+3910 2022-03-28
+3911 2022-03-29
+3912 2022-03-30
+3913 2022-03-31
+3914 2022-04-01
+3915 2022-04-02
+3916 2022-04-03
+3917 2022-04-04
+3918 2022-04-05
+3919 2022-04-06
+3920 2022-04-07
+3921 2022-04-08
+3922 2022-04-09
+3923 2022-04-10
+3924 2022-04-11
+3925 2022-04-12
+3926 2022-04-13
+3927 2022-04-14
+3928 2022-04-15
+3929 2022-04-16
+3930 2022-04-17
+3931 2022-04-18
+3932 2022-04-19
+3933 2022-04-20
+3934 2022-04-21
+3935 2022-04-22
+3936 2022-04-23
+3937 2022-04-24
+3938 2022-04-25
+3939 2022-04-26
+3940 2022-04-27
+3941 2022-04-28
+3942 2022-04-29
+3943 2022-04-30
+3944 2022-05-01
+3945 2022-05-02
+3946 2022-05-03
+3947 2022-05-04
+3948 2022-05-05
+3949 2022-05-06
+3950 2022-05-07
+3951 2022-05-08
+3952 2022-05-09
+3953 2022-05-10
+3954 2022-05-11
+3955 2022-05-12
+3956 2022-05-13
+3957 2022-05-14
+3958 2022-05-15
+3959 2022-05-16
+3960 2022-05-17
+3961 2022-05-18
+3962 2022-05-19
+3963 2022-05-20
+3964 2022-05-21
+3965 2022-05-22
+3966 2022-05-23
+3967 2022-05-24
+3968 2022-05-25
+3969 2022-05-26
+3970 2022-05-27
+3971 2022-05-28
+3972 2022-05-29
+3973 2022-05-30
+3974 2022-05-31
+3975 2022-06-01
+3976 2022-06-02
+3977 2022-06-03
+3978 2022-06-04
+3979 2022-06-05
+3980 2022-06-06
+3981 2022-06-07
+3982 2022-06-08
+3983 2022-06-09
+3984 2022-06-10
+3985 2022-06-11
+3986 2022-06-12
+3987 2022-06-13
+3988 2022-06-14
+3989 2022-06-15
+3990 2022-06-16
+3991 2022-06-17
+3992 2022-06-18
+3993 2022-06-19
+3994 2022-06-20
+3995 2022-06-21
+3996 2022-06-22
+3997 2022-06-23
+3998 2022-06-24
+3999 2022-06-25
+4000 2022-06-26
+4001 2022-06-27
+4002 2022-06-28
+4003 2022-06-29
+4004 2022-06-30
+4005 2022-07-01
+4006 2022-07-02
+4007 2022-07-03
+4008 2022-07-04
+4009 2022-07-05
+4010 2022-07-06
+4011 2022-07-07
+4012 2022-07-08
+4013 2022-07-09
+4014 2022-07-10
+4015 2022-07-11
+4016 2022-07-12
+4017 2022-07-13
+4018 2022-07-14
+4019 2022-07-15
+4020 2022-07-16
+4021 2022-07-17
+4022 2022-07-18
+4023 2022-07-19
+4024 2022-07-20
+4025 2022-07-21
+4026 2022-07-22
+4027 2022-07-23
+4028 2022-07-24
+4029 2022-07-25
+4030 2022-07-26
+4031 2022-07-27
+4032 2022-07-28
+4033 2022-07-29
+4034 2022-07-30
+4035 2022-07-31
+4036 2022-08-01
+4037 2022-08-02
+4038 2022-08-03
+4039 2022-08-04
+4040 2022-08-05
+4041 2022-08-06
+4042 2022-08-07
+4043 2022-08-08
+4044 2022-08-09
+4045 2022-08-10
+4046 2022-08-11
+4047 2022-08-12
+4048 2022-08-13
+4049 2022-08-14
+4050 2022-08-15
+4051 2022-08-16
+4052 2022-08-17
+4053 2022-08-18
+4054 2022-08-19
+4055 2022-08-20
+4056 2022-08-21
+4057 2022-08-22
+4058 2022-08-23
+4059 2022-08-24
+4060 2022-08-25
+4061 2022-08-26
+4062 2022-08-27
+4063 2022-08-28
+4064 2022-08-29
+4065 2022-08-30
+4066 2022-08-31
+4067 2022-09-01
+4068 2022-09-02
+4069 2022-09-03
+4070 2022-09-04
+4071 2022-09-05
+4072 2022-09-06
+4073 2022-09-07
+4074 2022-09-08
+4075 2022-09-09
+4076 2022-09-10
+4077 2022-09-11
+4078 2022-09-12
+4079 2022-09-13
+4080 2022-09-14
+4081 2022-09-15
+4082 2022-09-16
+4083 2022-09-17
+4084 2022-09-18
+4085 2022-09-19
+4086 2022-09-20
+4087 2022-09-21
+4088 2022-09-22
+4089 2022-09-23
+4090 2022-09-24
+4091 2022-09-25
+4092 2022-09-26
+4093 2022-09-27
+4094 2022-09-28
+4095 2022-09-29
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_matched_order.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_matched_order.result
new file mode 100644
index 00000000..def5db40
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_matched_order.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS texts;
+SET NAMES UTF8;
+CREATE TABLE texts (
+id INT PRIMARY KEY,
+matched TEXT,
+not_matched TEXT,
+FULLTEXT KEY (matched),
+FULLTEXT KEY (not_matched)
+) DEFAULT CHARSET=UTF8 COMMENT='engine "InnoDB"';
+INSERT INTO texts VALUES (1, 'Hello1', 'World1');
+INSERT INTO texts VALUES (2, 'Hello2', 'World2');
+INSERT INTO texts VALUES (3, 'Hello3', 'World3');
+SELECT id,
+matched,
+not_matched,
+MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+FROM texts
+WHERE MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE)
+ORDER BY MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE),
+id;
+id matched not_matched MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE) MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+1 Hello1 World1 1 0
+2 Hello2 World2 1 0
+3 Hello3 World3 1 0
+DROP TABLE texts;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_no_order.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_no_order.result
new file mode 100644
index 00000000..39ab80ed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_have_where_no_order.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS texts;
+SET NAMES UTF8;
+CREATE TABLE texts (
+id INT PRIMARY KEY,
+matched TEXT,
+not_matched TEXT,
+FULLTEXT KEY (matched),
+FULLTEXT KEY (not_matched)
+) DEFAULT CHARSET=UTF8 COMMENT='engine "InnoDB"';
+INSERT INTO texts VALUES (1, 'Hello1', 'World1');
+INSERT INTO texts VALUES (2, 'Hello2', 'World2');
+INSERT INTO texts VALUES (3, 'Hello3', 'World3');
+SELECT *
+FROM (SELECT id,
+matched,
+not_matched,
+MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+FROM texts
+WHERE MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE))
+AS searched_texts
+ORDER BY id;
+id matched not_matched MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE) MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+1 Hello1 World1 1 0
+2 Hello2 World2 1 0
+3 Hello3 World3 1 0
+DROP TABLE texts;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_no_where_both_order.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_no_where_both_order.result
new file mode 100644
index 00000000..f619e467
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_matched_and_not_matched_no_where_both_order.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS texts;
+SET NAMES UTF8;
+CREATE TABLE texts (
+id INT PRIMARY KEY,
+matched TEXT,
+not_matched TEXT,
+FULLTEXT KEY (matched),
+FULLTEXT KEY (not_matched)
+) DEFAULT CHARSET=UTF8 COMMENT='engine "InnoDB"';
+INSERT INTO texts VALUES (1, 'Hello1', 'World1');
+INSERT INTO texts VALUES (2, 'Hello2', 'World2');
+INSERT INTO texts VALUES (3, 'Hello3', 'World3');
+SELECT id,
+matched,
+not_matched,
+MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+FROM texts
+ORDER BY MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE),
+id;
+id matched not_matched MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE) MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+1 Hello1 World1 1 0
+2 Hello2 World2 1 0
+3 Hello3 World3 1 0
+DROP TABLE texts;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_delete.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_delete.result
new file mode 100644
index 00000000..fbdf241b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_delete.result
@@ -0,0 +1,23 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+delete from diaries where id = 2;
+select * from diaries where match(title, content) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries where match(title) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries where match(content) against("富士山");
+id title content
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_insert.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_insert.result
new file mode 100644
index 00000000..074d1991
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_insert.result
@@ -0,0 +1,29 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+select * from diaries where match(title, content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+select * from diaries where match(title) against("富士山");
+id title content
+3 富士山 今日もきれい。
+select * from diaries where match(content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_recreate.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_recreate.result
new file mode 100644
index 00000000..756a7021
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_recreate.result
@@ -0,0 +1,31 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries where match(title, content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+drop index title on diaries;
+select * from diaries where match(title, content) against("富士山");
+ERROR HY000: Can't find FULLTEXT index matching the column list
+create fulltext index new_title_content_index on diaries (title, content);
+select * from diaries where match(title, content) against("富士山");
+id title content
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+select * from diaries;
+id title content
+1 Hello はじめました。
+2 天気 明日の富士山の天気について
+3 富士山 今日もきれい。
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_update.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_update.result
new file mode 100644
index 00000000..db869eaa
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_column_index_update.result
@@ -0,0 +1,26 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+title varchar(255),
+content text,
+fulltext index (title, content),
+fulltext index (title),
+fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+update diaries set title = "チョモランマ" where id = 3;
+update diaries set content = "チョモランマと富士山" where id = 1;
+select * from diaries where match(title, content) against("富士山");
+id title content
+1 Hello チョモランマと富士山
+2 天気 明日の富士山の天気について
+select * from diaries where match(title) against("富士山");
+id title content
+select * from diaries where match(content) against("富士山");
+id title content
+1 Hello チョモランマと富士山
+2 天気 明日の富士山の天気について
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_index.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_index.result
new file mode 100644
index 00000000..7121e510
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_multiple_index.result
@@ -0,0 +1,23 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+title text,
+body text,
+fulltext index title_index (title),
+fulltext index body_index (body)
+) comment = 'engine "innodb"' default charset utf8;
+insert into diaries (title, body) values ("survey", "will start groonga!");
+insert into diaries (title, body) values ("groonga (1)", "starting groonga...");
+insert into diaries (title, body) values ("groonga (2)", "started groonga.");
+select * from diaries
+where match(title) against("survey") and
+match(body) against("groonga");
+id title body
+1 survey will start groonga!
+select *, match(title) against("survey"), match(body) against("groonga")
+from diaries
+where match(title) against("survey") and
+match(body) against("groonga");
+id title body match(title) against("survey") match(body) against("groonga")
+1 survey will start groonga! 1048577 149797
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_myisam.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_myisam.result
new file mode 100644
index 00000000..90376bdf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_myisam.result
@@ -0,0 +1,194 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 text, fulltext index ft (c2)) COMMENT = 'engine "myisam"';
+insert into t1 values (1, "hoge hoge");
+insert into t1 values (2, "fuga fuga");
+insert into t1 values (3, "moge moge");
+select * from t1;
+c1 c2
+1 hoge hoge
+2 fuga fuga
+3 moge moge
+flush tables;
+select * from t1;
+c1 c2
+1 hoge hoge
+2 fuga fuga
+3 moge moge
+drop table t1;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "myisam"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 20 ka ki ku ke ko
+3 30 sa si su se so
+4 40 ta ti tu te to
+5 50 aa ii uu ee oo
+select * from t1 where match(c3) against("su") order by c1;
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 where match(c3) against("ii") order by c1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+5 50 aa ii uu ee oo
+select * from t1 where match(c3) against("+su" in boolean mode) order by c1;
+c1 c2 c3
+3 30 sa si su se so
+select * from t1 where match(c3) against("+ii" in boolean mode) order by c1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+5 50 aa ii uu ee oo
+drop table t1;
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8 COMMENT = 'engine "myisam"';
+insert into t1 values(1, "明日の富士山の天気について","あああああああ");
+insert into t1 values(2, "いいいいい","明日の富士山の天気は分かりません");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+c1 c2 c3
+1 明日の富士山の天気について あああああああ
+2 いいいいい 明日の富士山の天気は分かりません
+3 dummy dummy
+select * from t1 where match(c2) against("富士山") order by c1;
+c1 c2 c3
+1 明日の富士山の天気について あああああああ
+select * from t1 where match(c3) against("富士山") order by c1;
+c1 c2 c3
+2 いいいいい 明日の富士山の天気は分かりません
+drop table t1;
+create table t1 (c1 int primary key, c2 varchar(100), fulltext index(c2)) default charset utf8 COMMENT = 'engine "myisam"';
+create table t2 (c1 int primary key, c2 text, fulltext index(c2)) default charset utf8 COMMENT = 'engine "myisam"';
+insert into t1 values (1, "aa ii uu ee oo");
+insert into t1 values (2, "ka ki ku ke ko");
+insert into t1 values (3, "aa ii ii ii oo");
+insert into t1 values (4, "sa si su se so");
+insert into t1 values (5, "ta ti ii ii to");
+insert into t2 (c1,c2) select c1,c2 from t1;
+select * from t1;
+c1 c2
+1 aa ii uu ee oo
+2 ka ki ku ke ko
+3 aa ii ii ii oo
+4 sa si su se so
+5 ta ti ii ii to
+select * from t2;
+c1 c2
+1 aa ii uu ee oo
+2 ka ki ku ke ko
+3 aa ii ii ii oo
+4 sa si su se so
+5 ta ti ii ii to
+select * from t1 where c1=3;
+c1 c2
+3 aa ii ii ii oo
+select * from t2 where c1=3;
+c1 c2
+3 aa ii ii ii oo
+select * from t1 where c1>3 order by c1 desc;
+c1 c2
+5 ta ti ii ii to
+4 sa si su se so
+select * from t2 where c1>3 order by c1 asc;
+c1 c2
+4 sa si su se so
+5 ta ti ii ii to
+select * from t1 where c2>"s" order by c2 desc;
+c1 c2
+5 ta ti ii ii to
+4 sa si su se so
+select * from t2 where c2>"s" order by c1 asc;
+c1 c2
+4 sa si su se so
+5 ta ti ii ii to
+select *,match(c2) against("ii") from t1 where match(c2) against("ii") order by match(c2) against("ii") desc;
+c1 c2 match(c2) against("ii")
+3 aa ii ii ii oo 524289
+5 ta ti ii ii to 349526
+1 aa ii uu ee oo 174763
+select *,match(c2) against("ii") from t2 where match(c2) against("ii") order by match(c2) against("ii") asc;
+c1 c2 match(c2) against("ii")
+1 aa ii uu ee oo 174763
+5 ta ti ii ii to 349526
+3 aa ii ii ii oo 524289
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+c1 c2 match(c2) against("ii")
+3 aa ii ii ii oo 524289
+5 ta ti ii ii to 349526
+1 aa ii uu ee oo 174763
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+c1 c2 match(c2) against("ii")
+3 aa ii ii ii oo 524289
+5 ta ti ii ii to 349526
+1 aa ii uu ee oo 174763
+drop table t1,t2;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "myisam"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,10,"ka ki ku ke ko");
+insert into t1 values(3,10,"aa ii uu ee oo");
+insert into t1 values(4,10,"ka ki ku ke ko");
+insert into t1 values(5,20,"aa ii uu ee oo");
+insert into t1 values(6,20,"ka ki ku ke ko");
+insert into t1 values(7,20,"aa ii uu ee oo");
+insert into t1 values(8,20,"ka ki ku ke ko");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 10 ka ki ku ke ko
+3 10 aa ii uu ee oo
+4 10 ka ki ku ke ko
+5 20 aa ii uu ee oo
+6 20 ka ki ku ke ko
+7 20 aa ii uu ee oo
+8 20 ka ki ku ke ko
+select *,match(c3) against("uu") from t1 where match(c3) against("uu") order by c1;
+c1 c2 c3 match(c3) against("uu")
+1 10 aa ii uu ee oo 131073
+3 10 aa ii uu ee oo 131073
+5 20 aa ii uu ee oo 131073
+7 20 aa ii uu ee oo 131073
+select * from t1 where not match(c3) against("uu");
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select *,match(c3) against("dummy") from t1 where match(c3) against("dummy");
+c1 c2 c3 match(c3) against("dummy")
+select * from t1 where not match(c3) against("dummy");
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 10 ka ki ku ke ko
+3 10 aa ii uu ee oo
+4 10 ka ki ku ke ko
+5 20 aa ii uu ee oo
+6 20 ka ki ku ke ko
+7 20 aa ii uu ee oo
+8 20 ka ki ku ke ko
+select * from t1 where c1 = 4 and not match(c3) against("uu");
+c1 c2 c3
+4 10 ka ki ku ke ko
+select * from t1 where c1 <= 4 and not match(c3) against("uu");
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+select * from t1 where c1 > 4 and not match(c3) against("uu");
+c1 c2 c3
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where c2 = 10 and not match(c3) against("uu");
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+select * from t1 where c2 >= 15 and not match(c3) against("uu");
+c1 c2 c3
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where c2 < 15 and not match(c3) against("uu");
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_not_match_against.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_not_match_against.result
new file mode 100644
index 00000000..4646aad6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_not_match_against.result
@@ -0,0 +1,68 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,10,"ka ki ku ke ko");
+insert into t1 values(3,10,"aa ii uu ee oo");
+insert into t1 values(4,10,"ka ki ku ke ko");
+insert into t1 values(5,20,"aa ii uu ee oo");
+insert into t1 values(6,20,"ka ki ku ke ko");
+insert into t1 values(7,20,"aa ii uu ee oo");
+insert into t1 values(8,20,"ka ki ku ke ko");
+select * from t1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 10 ka ki ku ke ko
+3 10 aa ii uu ee oo
+4 10 ka ki ku ke ko
+5 20 aa ii uu ee oo
+6 20 ka ki ku ke ko
+7 20 aa ii uu ee oo
+8 20 ka ki ku ke ko
+select *,match(c3) against("uu") from t1 where match(c3) against("uu") order by c1;
+c1 c2 c3 match(c3) against("uu")
+1 10 aa ii uu ee oo 131073
+3 10 aa ii uu ee oo 131073
+5 20 aa ii uu ee oo 131073
+7 20 aa ii uu ee oo 131073
+select * from t1 where not match(c3) against("uu") order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select *,match(c3) against("dummy") from t1 where match(c3) against("dummy") order by c1;
+c1 c2 c3 match(c3) against("dummy")
+select * from t1 where not match(c3) against("dummy") order by c1;
+c1 c2 c3
+1 10 aa ii uu ee oo
+2 10 ka ki ku ke ko
+3 10 aa ii uu ee oo
+4 10 ka ki ku ke ko
+5 20 aa ii uu ee oo
+6 20 ka ki ku ke ko
+7 20 aa ii uu ee oo
+8 20 ka ki ku ke ko
+select * from t1 where c1 = 4 and not match(c3) against("uu") order by c1;
+c1 c2 c3
+4 10 ka ki ku ke ko
+select * from t1 where c1 <= 4 and not match(c3) against("uu") order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+select * from t1 where c1 > 4 and not match(c3) against("uu") order by c1;
+c1 c2 c3
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where c2 = 10 and not match(c3) against("uu") order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+select * from t1 where c2 >= 15 and not match(c3) against("uu") order by c1;
+c1 c2 c3
+6 20 ka ki ku ke ko
+8 20 ka ki ku ke ko
+select * from t1 where c2 < 15 and not match(c3) against("uu") order by c1;
+c1 c2 c3
+2 10 ka ki ku ke ko
+4 10 ka ki ku ke ko
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..f79798ce
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_TODO_SPLIT_ME.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE ft(
+a INT DEFAULT 0,
+b TEXT,
+c TEXT,
+PRIMARY KEY(a),
+FULLTEXT KEY ftx1(b),
+FULLTEXT KEY ftx2(c)
+)ENGINE=Mroonga DEFAULT CHARSET=UTF8 COMMENT = 'engine "innodb"';
+INSERT INTO ft VALUES(1,'aaaaa','abcde');
+INSERT INTO ft VALUES(2,'bbbbb','bcdef');
+INSERT INTO ft VALUES(3,'ccccc','cdefg');
+INSERT INTO ft VALUES(4,'ddddd','defgh');
+INSERT INTO ft VALUES(5,'eeeee','efghi');
+SELECT a, b, c FROM ft WHERE MATCH(b) AGAINST('bbbbb' IN BOOLEAN MODE);
+a b c
+2 bbbbb bcdef
+SELECT a, b, c FROM ft WHERE MATCH(b) AGAINST('bbbbb' IN BOOLEAN MODE) ORDER BY MATCH(b) AGAINST('bbbbb' IN BOOLEAN MODE);
+a b c
+2 bbbbb bcdef
+SELECT a, b, c FROM ft WHERE MATCH(c) AGAINST('bbbbb' IN BOOLEAN MODE);
+a b c
+DROP TABLE ft;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_transaction.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_transaction.result
new file mode 100644
index 00000000..3ee15c63
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/fulltext_order_transaction.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET=UTF8;
+START TRANSACTION;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("groonga")
+ORDER BY id;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+USE test;
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("groonga")
+ORDER BY id;
+id title body
+COMMIT;
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("groonga")
+ORDER BY id;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries
+WHERE MATCH(body) AGAINST("groonga")
+ORDER BY id;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_reference.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_reference.result
new file mode 100644
index 00000000..d31d5454
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_reference.result
@@ -0,0 +1,15 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int AUTO_INCREMENT PRIMARY KEY
+) COMMENT='ENGINE "InnoDB"';
+SELECT last_insert_id();
+last_insert_id()
+0
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+last_insert_id()
+1
+SELECT * FROM ids;
+id
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_set.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_set.result
new file mode 100644
index 00000000..39791b93
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/function_last_insert_id_set.result
@@ -0,0 +1,21 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id int AUTO_INCREMENT PRIMARY KEY
+) COMMENT='ENGINE "InnoDB"';
+SELECT last_insert_id();
+last_insert_id()
+0
+SELECT last_insert_id(10);
+last_insert_id(10)
+10
+SELECT last_insert_id();
+last_insert_id()
+10
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+last_insert_id()
+1
+SELECT * FROM ids;
+id
+1
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_contains.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_contains.result
new file mode 100644
index 00000000..550554ea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_contains.result
@@ -0,0 +1,160 @@
+drop table if exists shops;
+create table shops (
+id int primary key auto_increment,
+name text,
+location geometry NOT NULL,
+spatial key location_index (location)
+) comment = 'engine "innodb"';
+insert into shops (name, location)
+values ('nezu-no-taiyaki',
+ST_GeomFromText('POINT(139.762573 35.720253)'));
+insert into shops (name, location)
+values ('taiyaki-kataoka',
+ST_GeomFromText('POINT(139.715591 35.712521)'));
+insert into shops (name, location)
+values ('soba-taiyaki-ku',
+ST_GeomFromText('POINT(139.659088 35.683712)'));
+insert into shops (name, location)
+values ('kuruma',
+ST_GeomFromText('POINT(139.706207 35.721516)'));
+insert into shops (name, location)
+values ('hirose-ya',
+ST_GeomFromText('POINT(139.685608 35.714844)'));
+insert into shops (name, location)
+values ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+insert into shops (name, location)
+values ('omede-taiyaki',
+ST_GeomFromText('POINT(139.817154 35.700516)'));
+insert into shops (name, location)
+values ('onaga-ya',
+ST_GeomFromText('POINT(139.81105 35.698254)'));
+insert into shops (name, location)
+values ('shiro-ya',
+ST_GeomFromText('POINT(139.638611 35.705517)'));
+insert into shops (name, location)
+values ('fuji-ya',
+ST_GeomFromText('POINT(139.637115 35.703938)'));
+insert into shops (name, location)
+values ('miyoshi',
+ST_GeomFromText('POINT(139.537323 35.644539)'));
+insert into shops (name, location)
+values ('juju-ya',
+ST_GeomFromText('POINT(139.695755 35.628922)'));
+insert into shops (name, location)
+values ('tatsumi-ya',
+ST_GeomFromText('POINT(139.638657 35.665501)'));
+insert into shops (name, location)
+values ('tetsuji',
+ST_GeomFromText('POINT(139.76857 35.680912)'));
+insert into shops (name, location)
+values ('gazuma-ya',
+ST_GeomFromText('POINT(139.647598 35.700817)'));
+insert into shops (name, location)
+values ('honma-mon',
+ST_GeomFromText('POINT(139.652573 35.722736)'));
+insert into shops (name, location)
+values ('naniwa-ya',
+ST_GeomFromText('POINT(139.796234 35.730061)'));
+insert into shops (name, location)
+values ('kuro-dai',
+ST_GeomFromText('POINT(139.704834 35.650345)'));
+insert into shops (name, location)
+values ('daruma',
+ST_GeomFromText('POINT(139.770599 35.681461)'));
+insert into shops (name, location)
+values ('yanagi-ya',
+ST_GeomFromText('POINT(139.783981 35.685341)'));
+insert into shops (name, location)
+values ('sharaku',
+ST_GeomFromText('POINT(139.794846 35.716969)'));
+insert into shops (name, location)
+values ('takane',
+ST_GeomFromText('POINT(139.560913 35.698601)'));
+insert into shops (name, location)
+values ('chiyoda',
+ST_GeomFromText('POINT(139.652817 35.642601)'));
+insert into shops (name, location)
+values ('da-ka-po',
+ST_GeomFromText('POINT(139.727356 35.627346)'));
+insert into shops (name, location)
+values ('matsushima-ya',
+ST_GeomFromText('POINT(139.737381 35.640556)'));
+insert into shops (name, location)
+values ('kazuya',
+ST_GeomFromText('POINT(139.760895 35.673508)'));
+insert into shops (name, location)
+values ('furuya-kogane-an',
+ST_GeomFromText('POINT(139.676071 35.680603)'));
+insert into shops (name, location)
+values ('hachi-no-ie',
+ST_GeomFromText('POINT(139.668106 35.608021)'));
+insert into shops (name, location)
+values ('azuki-chan',
+ST_GeomFromText('POINT(139.673203 35.64151)'));
+insert into shops (name, location)
+values ('kuriko-an',
+ST_GeomFromText('POINT(139.796829 35.712013)'));
+insert into shops (name, location)
+values ('yume-no-aru-machi-no-taiyaki-ya-san',
+ST_GeomFromText('POINT(139.712524 35.616199)'));
+insert into shops (name, location)
+values ('naze-ya',
+ST_GeomFromText('POINT(139.665833 35.609039)'));
+insert into shops (name, location)
+values ('sanoki-ya',
+ST_GeomFromText('POINT(139.770721 35.66592)'));
+insert into shops (name, location)
+values ('shigeta',
+ST_GeomFromText('POINT(139.780273 35.672626)'));
+insert into shops (name, location)
+values ('nishimi-ya',
+ST_GeomFromText('POINT(139.774628 35.671825)'));
+insert into shops (name, location)
+values ('hiiragi',
+ST_GeomFromText('POINT(139.711517 35.647701)'));
+select id, name, ST_AsText(location) as location_text from shops;
+id name location_text
+1 nezu-no-taiyaki POINT(139.762573 35.720253)
+2 taiyaki-kataoka POINT(139.715591 35.712521)
+3 soba-taiyaki-ku POINT(139.659088 35.683712)
+4 kuruma POINT(139.706207 35.721516)
+5 hirose-ya POINT(139.685608 35.714844)
+6 sazare POINT(139.685043 35.714653)
+7 omede-taiyaki POINT(139.817154 35.700516)
+8 onaga-ya POINT(139.81105 35.698254)
+9 shiro-ya POINT(139.638611 35.705517)
+10 fuji-ya POINT(139.637115 35.703938)
+11 miyoshi POINT(139.537323 35.644539)
+12 juju-ya POINT(139.695755 35.628922)
+13 tatsumi-ya POINT(139.638657 35.665501)
+14 tetsuji POINT(139.76857 35.680912)
+15 gazuma-ya POINT(139.647598 35.700817)
+16 honma-mon POINT(139.652573 35.722736)
+17 naniwa-ya POINT(139.796234 35.730061)
+18 kuro-dai POINT(139.704834 35.650345)
+19 daruma POINT(139.770599 35.681461)
+20 yanagi-ya POINT(139.783981 35.685341)
+21 sharaku POINT(139.794846 35.716969)
+22 takane POINT(139.560913 35.698601)
+23 chiyoda POINT(139.652817 35.642601)
+24 da-ka-po POINT(139.727356 35.627346)
+25 matsushima-ya POINT(139.737381 35.640556)
+26 kazuya POINT(139.760895 35.673508)
+27 furuya-kogane-an POINT(139.676071 35.680603)
+28 hachi-no-ie POINT(139.668106 35.608021)
+29 azuki-chan POINT(139.673203 35.64151)
+30 kuriko-an POINT(139.796829 35.712013)
+31 yume-no-aru-machi-no-taiyaki-ya-san POINT(139.712524 35.616199)
+32 naze-ya POINT(139.665833 35.609039)
+33 sanoki-ya POINT(139.770721 35.66592)
+34 shigeta POINT(139.780273 35.672626)
+35 nishimi-ya POINT(139.774628 35.671825)
+36 hiiragi POINT(139.711517 35.647701)
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location);
+id name location_text
+14 tetsuji POINT(139.76857 35.680912)
+19 daruma POINT(139.770599 35.681461)
+26 kazuya POINT(139.760895 35.673508)
+drop table shops;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_delete.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_delete.result
new file mode 100644
index 00000000..615d185f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_delete.result
@@ -0,0 +1,22 @@
+drop table if exists shops;
+create table shops (
+id int primary key auto_increment,
+name text,
+location geometry NOT NULL,
+spatial key location_index (location)
+) comment = 'engine "innodb"';
+insert into shops (name, location)
+values ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+id name location_text
+1 sazare POINT(139.685043 35.714653)
+delete from shops
+where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+id name location_text
+select id, name, ST_AsText(location) as location_text from shops;
+id name location_text
+drop table shops;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_update.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_update.result
new file mode 100644
index 00000000..adfb53e1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/geometry_update.result
@@ -0,0 +1,27 @@
+drop table if exists shops;
+create table shops (
+id int primary key auto_increment,
+name text,
+location geometry NOT NULL,
+spatial key location_index (location)
+) comment = 'engine "innodb"';
+insert into shops (name, location)
+values ('sazare',
+ST_GeomFromText('POINT(139.685043 35.714653)'));
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+id name location_text
+1 sazare POINT(139.685043 35.714653)
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.65659 35.57903, 139.66489 35.57262)'), location);
+id name location_text
+update shops set location = ST_GeomFromText('POINT(139.66116 35.57566)')
+where name = 'sazare';
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+id name location_text
+select id, name, ST_AsText(location) as location_text from shops
+where MBRContains(ST_GeomFromText('LineString(139.65659 35.57903, 139.66489 35.57262)'), location);
+id name location_text
+1 sazare POINT(139.66116 35.57566)
+drop table shops;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/index_force_index_not_used.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/index_force_index_not_used.result
new file mode 100644
index 00000000..3fbc85ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/index_force_index_not_used.result
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS ids;
+CREATE TABLE ids (
+id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET UTF8 COMMENT = 'engine "InnoDB"';
+SELECT COUNT(*) FROM ids FORCE INDEX(PRIMARY);
+COUNT(*)
+0
+DROP TABLE ids;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..93c05bff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_TODO_SPLIT_ME.result
@@ -0,0 +1,78 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 tinyint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 smallint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 mediumint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 int primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 bigint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+c1
+1
+drop table t1;
+create table t1 (c1 float primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(0.5);
+select * from t1;
+c1
+0.5
+drop table t1;
+create table t1 (c1 double primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(0.5);
+select * from t1;
+c1
+0.5
+drop table t1;
+create table t1 (c1 date primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("2010/03/26");
+select * from t1;
+c1
+2010-03-26
+drop table t1;
+create table t1 (c1 time primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("11:22:33");
+select * from t1;
+c1
+11:22:33
+drop table t1;
+create table t1 (c1 year primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("2010");
+select * from t1;
+c1
+2010
+drop table t1;
+create table t1 (c1 datetime primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("2010/03/26 11:22:33");
+select * from t1;
+c1
+2010-03-26 11:22:33
+drop table t1;
+create table t1 (c1 int primary key, c2 int) COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+select * from t1;
+c1 c2
+1 100
+insert into t1 values(1,200);
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+select * from t1;
+c1 c2
+1 100
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_bulk.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_bulk.result
new file mode 100644
index 00000000..552cf586
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_bulk.result
@@ -0,0 +1,22 @@
+drop table if exists diaries;
+set names utf8;
+create table diaries (
+id int primary key,
+content text,
+fulltext index (content)
+) default charset utf8 comment = 'engine "innodb"';
+LOCK TABLE diaries WRITE;
+insert into diaries values(1, "今日からはじめました。");
+insert into diaries values(2, "明日の富士山の天気について");
+insert into diaries values(3, "今日も天気がよくてきれいに見える。");
+UNLOCK TABLES;
+select * from diaries;
+id content
+1 今日からはじめました。
+2 明日の富士山の天気について
+3 今日も天気がよくてきれいに見える。
+select * from diaries where match(content) against("天気");
+id content
+2 明日の富士山の天気について
+3 今日も天気がよくてきれいに見える。
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.result
new file mode 100644
index 00000000..198eca2a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.result
@@ -0,0 +1,36 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+date TIMESTAMP NOT NULL,
+title VARCHAR(100) NOT NULL,
+content TEXT NOT NULL,
+PRIMARY KEY (date, title)
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "MyISAM"';
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `title` varchar(100) NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`date`,`title`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "MyISAM"'
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-04", "cloudy day", "Today is cloudy day...");
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-04", "shopping", "I buy a new shirt.");
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-05", "rainy day", "Today is rainy day...");
+SELECT * FROM diaries;
+date title content
+2012-03-04 00:00:00 cloudy day Today is cloudy day...
+2012-03-04 00:00:00 shopping I buy a new shirt.
+2012-03-05 00:00:00 rainy day Today is rainy day...
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-04", "shopping", "I buy new shoes.")
+ON DUPLICATE KEY UPDATE date = "2012-03-03",
+content = "I buy a new hat.";
+SELECT * FROM diaries;
+date title content
+2012-03-04 00:00:00 cloudy day Today is cloudy day...
+2012-03-03 00:00:00 shopping I buy a new hat.
+2012-03-05 00:00:00 rainy day Today is rainy day...
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.result
new file mode 100644
index 00000000..05a93206
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.result
@@ -0,0 +1,39 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+date TIMESTAMP NOT NULL,
+title VARCHAR(100) NOT NULL,
+content TEXT NOT NULL,
+UNIQUE INDEX (date, title)
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "MyISAM"';
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+ `title` varchar(100) NOT NULL,
+ `content` text NOT NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `date` (`date`,`title`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "MyISAM"'
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-04", "cloudy day", "Today is cloudy day...");
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-04", "shopping", "I buy a new shirt.");
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-05", "rainy day", "Today is rainy day...");
+SELECT * FROM diaries;
+id date title content
+1 2012-03-04 00:00:00 cloudy day Today is cloudy day...
+2 2012-03-04 00:00:00 shopping I buy a new shirt.
+3 2012-03-05 00:00:00 rainy day Today is rainy day...
+INSERT INTO diaries (date, title, content)
+VALUES ("2012-03-04", "shopping", "I buy new shoes.")
+ON DUPLICATE KEY UPDATE date = "2012-03-03",
+content = "I buy a new hat.";
+SELECT * FROM diaries;
+id date title content
+1 2012-03-04 00:00:00 cloudy day Today is cloudy day...
+2 2012-03-03 00:00:00 shopping I buy a new hat.
+3 2012-03-05 00:00:00 rainy day Today is rainy day...
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_disk_sweep.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_disk_sweep.result
new file mode 100644
index 00000000..aa7a32db
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_disk_sweep.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS integers;
+SET optimizer_switch='mrr_cost_based=off';
+CREATE TABLE integers (
+id INT PRIMARY KEY AUTO_INCREMENT,
+value INT,
+KEY (value)
+) COMMENT='engine "InnoDB"';
+INSERT INTO integers (value) VALUES (0), (1), (2), (3);
+EXPLAIN SELECT * FROM integers
+WHERE value IN (0, 2);
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE integers range value value 5 NULL 2 Using where; Using MRR
+SELECT * FROM integers
+WHERE value IN (0, 2);
+id value
+1 0
+3 2
+DROP TABLE integers;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_mysql_5_7_or_later_disk_sweep.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_mysql_5_7_or_later_disk_sweep.result
new file mode 100644
index 00000000..bf1e67b9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/multi_range_read_mysql_5_7_or_later_disk_sweep.result
@@ -0,0 +1,20 @@
+DROP TABLE IF EXISTS integers;
+SET optimizer_switch='mrr_cost_based=off';
+CREATE TABLE integers (
+id INT PRIMARY KEY AUTO_INCREMENT,
+value INT,
+KEY (value)
+) COMMENT='engine "InnoDB"';
+INSERT INTO integers (value) VALUES (0), (1), (2), (3);
+EXPLAIN SELECT * FROM integers
+WHERE value IN (0, 2);
+id select_type table partitions type possible_keys key key_len ref rows filtered Extra
+1 SIMPLE integers NULL range value value 5 NULL 2 100.00 Using where; Using MRR
+Warnings:
+Note 1003 /* select#1 */ select `test`.`integers`.`id` AS `id`,`test`.`integers`.`value` AS `value` from `test`.`integers` where (`test`.`integers`.`value` in (0,2))
+SELECT * FROM integers
+WHERE value IN (0, 2);
+id value
+1 0
+3 2
+DROP TABLE integers;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_TODO_SPLIT_ME.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_TODO_SPLIT_ME.result
new file mode 100644
index 00000000..66070060
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_TODO_SPLIT_ME.result
@@ -0,0 +1,53 @@
+drop table if exists t1;
+flush status;
+create table t1 (
+c1 int primary key,
+c2 int,
+c3 text,
+key idx1(c2),
+fulltext index ft(c3)
+) comment = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"ii si ii se ii");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ii oo");
+select c3, match(c3) against("ii") from t1
+where match(c3) against("ii") order by match(c3) against("ii") desc;
+c3 match(c3) against("ii")
+ii si ii se ii 524289
+aa ii uu ii oo 349526
+aa ii uu ee oo 174763
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+select c3, match(c3) against("ii") from t1
+where match(c3) against("ii") order by match(c3) against("ii") desc limit 1, 1;
+c3 match(c3) against("ii")
+aa ii uu ii oo 349526
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+select c3, match(c3) against("ii") from t1
+where match(c3) against("ii") order by match(c3) against("ii");
+c3 match(c3) against("ii")
+aa ii uu ee oo 174763
+aa ii uu ii oo 349526
+ii si ii se ii 524289
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+select c3, match(c3) against("ii") from t1
+where match(c3) against("ii") order by match(c3) against("ii") limit 1;
+c3 match(c3) against("ii")
+aa ii uu ee oo 174763
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 2
+select count(*) from t1 where match(c3) against("ii") limit 1;
+count(*)
+3
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 2
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_direction.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_direction.result
new file mode 100644
index 00000000..9dd3e6ea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_direction.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+CREATE TABLE memos (
+id int PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) COMMENT = 'engine "InnoDB"';
+INSERT INTO memos VALUES(1, "Groonga is fast");
+INSERT INTO memos VALUES(2, "Mroonga is fast");
+INSERT INTO memos VALUES(3, "Mroonga is easy");
+INSERT INTO memos VALUES(4, "Mroonga is useful");
+INSERT INTO memos VALUES(5, "Mroonga is great");
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+SELECT id, content
+FROM memos
+WHERE MATCH(content) AGAINST("+Mroonga" IN BOOLEAN MODE)
+ORDER BY id
+LIMIT 2;
+id content
+2 Mroonga is fast
+3 Mroonga is easy
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_where_clause.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_where_clause.result
new file mode 100644
index 00000000..b31d2ee5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_no_where_clause.result
@@ -0,0 +1,24 @@
+drop table if exists t1;
+flush status;
+create table t1 (
+c1 int primary key,
+c2 int,
+c3 text,
+key idx1(c2),
+fulltext index ft(c3)
+) comment = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"ii si ii se ii");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ii oo");
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+select *, match(c3) against("ii") from t1 order by c1 desc limit 1;
+c1 c2 c3 match(c3) against("ii")
+5 50 aa ii uu ii oo 349526
+show status like 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_order_by_primary_key.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_order_by_primary_key.result
new file mode 100644
index 00000000..eb5e04fc
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/optimization_order_limit_order_by_primary_key.result
@@ -0,0 +1,27 @@
+DROP TABLE IF EXISTS memos;
+FLUSH STATUS;
+CREATE TABLE memos (
+id int PRIMARY KEY,
+content TEXT,
+FULLTEXT INDEX (content)
+) COMMENT = 'engine "InnoDB"';
+INSERT INTO memos VALUES(1, "Mroonga is fast");
+INSERT INTO memos VALUES(2, "Mroonga is easy");
+INSERT INTO memos VALUES(3, "Mroonga is useful");
+INSERT INTO memos VALUES(4, "Mroonga is great");
+INSERT INTO memos VALUES(5, "Groonga is fast");
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 0
+SELECT id, content
+FROM memos
+WHERE MATCH(content) AGAINST("+Mroonga" IN BOOLEAN MODE)
+ORDER BY id DESC
+LIMIT 2;
+id content
+4 Mroonga is great
+3 Mroonga is useful
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+Variable_name Value
+Mroonga_fast_order_limit 1
+DROP TABLE memos;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/performance_schema.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/performance_schema.result
new file mode 100644
index 00000000..b06cd8af
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/performance_schema.result
@@ -0,0 +1,22 @@
+DROP TABLE IF EXISTS diaries;
+SHOW VARIABLES LIKE 'performance_schema';
+Variable_name Value
+performance_schema ON
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+content VARCHAR(255),
+FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+SHOW CREATE TABLE diaries;
+Table Create Table
+diaries CREATE TABLE `diaries` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `content` varchar(255) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `content` (`content`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "InnoDB"'
+INSERT INTO diaries (content) VALUES ("Tommorow will be shiny day!");
+SHOW TABLES FROM performance_schema LIKE 'threads';
+Tables_in_performance_schema (threads)
+threads
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result
new file mode 100644
index 00000000..8258a03b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_files.result
@@ -0,0 +1,31 @@
+CREATE DATABASE repair_test;
+USE repair_test;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX body_index (body)
+) COMMENT = 'engine "innodb"' DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+id title body
+2 groonga (1) starting groonga...
+FLUSH TABLES;
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+ERROR HY000: mroonga: failed to open table: <diaries>
+REPAIR TABLE diaries;
+Table Op Msg_type Msg_text
+repair_test.diaries repair status OK
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+id title body
+2 groonga (1) starting groonga...
+DROP TABLE diaries;
+DROP DATABASE repair_test;
+USE test;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result
new file mode 100644
index 00000000..cca7aee9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/repair_table_no_index_file.result
@@ -0,0 +1,31 @@
+CREATE DATABASE repair_test;
+USE repair_test;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX body_index (body)
+) COMMENT = 'engine "innodb"' DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+id title body
+2 groonga (1) starting groonga...
+FLUSH TABLES;
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+ERROR HY000: system call error: No such file or directory: failed to open path: <repair_test.mrn.000010A>
+REPAIR TABLE diaries;
+Table Op Msg_type Msg_text
+repair_test.diaries repair status OK
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+id title body
+2 groonga (1) starting groonga...
+DROP TABLE diaries;
+DROP DATABASE repair_test;
+USE test;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/temporary_table.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/temporary_table.result
new file mode 100644
index 00000000..d66b463d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/temporary_table.result
@@ -0,0 +1,14 @@
+DROP TEMPORARY TABLE IF EXISTS diaries;
+CREATE TEMPORARY TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT
+) DEFAULT CHARSET=UTF8 COMMENT = 'ENGINE "InnoDB"';
+INSERT INTO diaries (title) VALUES ("clear day");
+INSERT INTO diaries (title) VALUES ("rainy day");
+INSERT INTO diaries (title) VALUES ("cloudy day");
+SELECT * FROM diaries;
+id title
+1 clear day
+2 rainy day
+3 cloudy day
+DROP TEMPORARY TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_query_cache.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_query_cache.result
new file mode 100644
index 00000000..b08d1c0c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_query_cache.result
@@ -0,0 +1,28 @@
+SET @tmp_query_cache_size = @@query_cache_size;
+SET GLOBAL query_cache_size = 1048576;
+DROP TABLE IF EXISTS simple_table;
+CREATE TABLE simple_table (
+id INT PRIMARY KEY
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE simple_table;
+Table Create Table
+simple_table CREATE TABLE `simple_table` (
+ `id` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci COMMENT='ENGINE "InnoDB"'
+INSERT INTO simple_table (id) VALUES (1),(2);
+USE test;
+START TRANSACTION;
+INSERT INTO simple_table (id) VALUES (3);
+SELECT * FROM simple_table;
+id
+1
+2
+COMMIT;
+SELECT * FROM simple_table;
+id
+1
+2
+3
+DROP TABLE simple_table;
+SET GLOBAL query_cache_size = @tmp_query_cache_size;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_delete.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_delete.result
new file mode 100644
index 00000000..8c61d9e8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_delete.result
@@ -0,0 +1,40 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey") AND
+MATCH(body) AGAINST("groonga");
+id title body
+1 survey will start groonga!
+START TRANSACTION;
+DELETE FROM diaries WHERE id = 1;
+ROLLBACK;
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey") AND
+MATCH(body) AGAINST("groonga");
+id title body
+DELETE FROM diaries WHERE id = 1;
+Warnings:
+Warning 1026 failed to get record ID for deleting from groonga: key=<\0001>
+SELECT * FROM diaries;
+id title body
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey") AND
+MATCH(body) AGAINST("groonga");
+id title body
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_update.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_update.result
new file mode 100644
index 00000000..0a424e77
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/transaction_rollback_delete_update.result
@@ -0,0 +1,37 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+body TEXT,
+FULLTEXT INDEX title_index (title),
+FULLTEXT INDEX body_index (body)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey");
+id title body
+1 survey will start groonga!
+START TRANSACTION;
+DELETE FROM diaries WHERE id = 1;
+ROLLBACK;
+SELECT * FROM diaries;
+id title body
+1 survey will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey");
+id title body
+UPDATE diaries SET title = "survey day!" WHERE id = 1;
+SELECT * FROM diaries;
+id title body
+1 survey day! will start groonga!
+2 groonga (1) starting groonga...
+3 groonga (2) started groonga.
+SELECT * FROM diaries
+WHERE MATCH(title) AGAINST("survey");
+id title body
+1 survey day! will start groonga!
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/truncate.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/truncate.result
new file mode 100644
index 00000000..296f87ad
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/truncate.result
@@ -0,0 +1,47 @@
+DROP TABLE IF EXISTS diaries;
+SET NAMES UTF8;
+CREATE TABLE diaries (
+id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+year INT UNSIGNED,
+month INT UNSIGNED,
+day INT UNSIGNED,
+title VARCHAR(255),
+content TEXT,
+FULLTEXT INDEX(content),
+KEY(day)
+) DEFAULT CHARSET UTF8 COMMENT = 'engine "innodb"';
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+SELECT * FROM diaries;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+2 2011 11 10 天気 明日の富士山の天気について
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ORDER BY id;
+id year month day title content
+1 2011 11 9 Hello 今日からはじめました。
+3 2011 11 11 富士山 今日も天気がよくてきれいに見える。
+TRUNCATE TABLE diaries;
+SELECT * FROM diaries;
+id year month day title content
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ORDER BY id;
+id year month day title content
+INSERT INTO diaries VALUES(1, 2011, 11, 11, "帰り道", "つかれたー");
+INSERT INTO diaries VALUES(2, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(3, 2011, 12, 2, "初雪", "今年はじめての雪!");
+SELECT * FROM diaries;
+id year month day title content
+1 2011 11 11 帰り道 つかれたー
+2 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+3 2011 12 2 初雪 今年はじめての雪!
+SELECT * FROM diaries
+WHERE MATCH(content) AGAINST("+悪い" IN BOOLEAN MODE)
+ORDER BY id;
+id year month day title content
+2 2011 12 1 久しぶり 天気が悪いからずっと留守番。
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/update_fulltext.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/update_fulltext.result
new file mode 100644
index 00000000..655d2424
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/update_fulltext.result
@@ -0,0 +1,33 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 text, fulltext index (c2)) COMMENT = 'engine "innodb"';
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+select * from t1;
+c1 c2
+10 aa ii uu ee
+20 ka ki ku ke
+30 sa si su se
+update t1 set c2="ta ti tu te" where c1=20;
+select * from t1;
+c1 c2
+10 aa ii uu ee
+20 ta ti tu te
+30 sa si su se
+select * from t1 where match(c2) against("ti");
+c1 c2
+20 ta ti tu te
+select * from t1 where match(c2) against("ki");
+c1 c2
+update t1 set c1=40 where c1=20;
+select * from t1;
+c1 c2
+10 aa ii uu ee
+30 sa si su se
+40 ta ti tu te
+select * from t1 where match(c2) against("ti");
+c1 c2
+40 ta ti tu te
+select * from t1 where match(c2) against("ki");
+c1 c2
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/update_int.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/update_int.result
new file mode 100644
index 00000000..311debbb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/update_int.result
@@ -0,0 +1,36 @@
+drop table if exists t1, t2, t3;
+create table t1 (c1 int primary key, c2 int) COMMENT = 'engine "innodb"';
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `c1` int(11) NOT NULL,
+ `c2` int(11) DEFAULT NULL,
+ PRIMARY KEY (`c1`)
+) ENGINE=Mroonga DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci COMMENT='engine "innodb"'
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+c1 c2
+1 100
+2 101
+3 102
+update t1 set c2=c2+100 where c1=1;
+select * from t1;
+c1 c2
+1 200
+2 101
+3 102
+update t1 set c2=c2+100 where c1=2;
+select * from t1;
+c1 c2
+1 200
+2 201
+3 102
+update t1 set c2=c2+100 where c1=3;
+select * from t1;
+c1 c2
+1 200
+2 201
+3 202
+drop table t1;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_delete.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_delete.result
new file mode 100644
index 00000000..ccc28a0f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_delete.result
@@ -0,0 +1,45 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries (body) values ("will start groonga!");
+insert into diaries (body) values ("starting groonga...");
+insert into diaries (body) values ("started groonga.");
+select * from diaries;
+id body
+1 will start groonga!
+2 starting groonga...
+3 started groonga.
+set mroonga_dry_write=true;
+delete from diaries where id = 2;
+select * from diaries;
+id body
+1 will start groonga!
+3 started groonga.
+select * from diaries where match (body) against ("starting");
+id body
+select * from diaries where match (body) against ("started");
+id body
+3 started groonga.
+set mroonga_dry_write=false;
+delete from diaries where id = 3;
+select * from diaries;
+id body
+1 will start groonga!
+select * from diaries where match (body) against ("starting");
+id body
+select * from diaries where match (body) against ("started");
+id body
+insert into diaries (id, body) values (2, "sleeping...");
+select * from diaries;
+id body
+1 will start groonga!
+2 sleeping...
+select * from diaries where match (body) against ("starting");
+id body
+2 sleeping...
+select * from diaries where match (body) against ("started");
+id body
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_insert.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_insert.result
new file mode 100644
index 00000000..a9bdd38f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_insert.result
@@ -0,0 +1,34 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries (body) values ("will start groonga!");
+select * from diaries;
+id body
+1 will start groonga!
+select * from diaries where match (body) against ("groonga");
+id body
+1 will start groonga!
+set mroonga_dry_write=true;
+insert into diaries (body) values ("starting groonga...");
+select * from diaries;
+id body
+1 will start groonga!
+2 starting groonga...
+select * from diaries where match (body) against ("groonga");
+id body
+1 will start groonga!
+set mroonga_dry_write=false;
+insert into diaries (body) values ("started groonga.");
+select * from diaries;
+id body
+1 will start groonga!
+2 starting groonga...
+3 started groonga.
+select * from diaries where match (body) against ("groonga");
+id body
+1 will start groonga!
+3 started groonga.
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_update.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_update.result
new file mode 100644
index 00000000..b2fe4607
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_dry_write_update.result
@@ -0,0 +1,31 @@
+drop table if exists diaries;
+create table diaries (
+id int primary key auto_increment,
+body text,
+fulltext index body_index (body)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries (body) values ("will start groonga!");
+set mroonga_dry_write=true;
+update diaries set body = "starting groonga..." where id = 1;
+select * from diaries;
+id body
+1 starting groonga...
+select * from diaries where match (body) against ("will");
+id body
+1 starting groonga...
+select * from diaries where match (body) against ("starting");
+id body
+set mroonga_dry_write=false;
+update diaries set body = "started groonga." where id = 1;
+select * from diaries;
+id body
+1 started groonga.
+select * from diaries where match (body) against ("will");
+id body
+1 started groonga.
+select * from diaries where match (body) against ("starting");
+id body
+select * from diaries where match (body) against ("started");
+id body
+1 started groonga.
+drop table diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_global.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_global.result
new file mode 100644
index 00000000..9405879f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_global.result
@@ -0,0 +1,18 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+tags TEXT,
+FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "InnoDB"';
+INSERT INTO diaries (title, tags) VALUES ("Hello groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello mroonga!", "mroonga install");
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+SET GLOBAL mroonga_match_escalation_threshold = -1;
+USE test;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+SET GLOBAL mroonga_match_escalation_threshold = DEFAULT;
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_session.result b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_session.result
new file mode 100644
index 00000000..fa2da48c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/r/variable_match_escalation_threshold_session.result
@@ -0,0 +1,24 @@
+DROP TABLE IF EXISTS diaries;
+CREATE TABLE diaries (
+id INT PRIMARY KEY AUTO_INCREMENT,
+title TEXT,
+tags TEXT,
+FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "InnoDB"';
+INSERT INTO diaries (title, tags) VALUES ("Hello groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello mroonga!", "mroonga install");
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("install" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+2 Hello mroonga! mroonga install
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+SET mroonga_match_escalation_threshold = -1;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+SET mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+id title tags
+1 Hello groonga! groonga install
+DROP TABLE diaries;
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/suite.opt b/storage/mroonga/mysql-test/mroonga/wrapper/suite.opt
new file mode 100644
index 00000000..d5a1e519
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/suite.opt
@@ -0,0 +1 @@
+--loose-plugin-load-add=$HA_MROONGA_SO --loose-plugin-mroonga=ON
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/suite.pm b/storage/mroonga/mysql-test/mroonga/wrapper/suite.pm
new file mode 100644
index 00000000..7e4f8c17
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/suite.pm
@@ -0,0 +1,23 @@
+package My::Suite::Mroonga;
+
+@ISA = qw(My::Suite);
+
+return "No Mroonga engine" unless $ENV{HA_MROONGA_SO} or
+ $::mysqld_variables{'mroonga'} eq "ON";
+
+sub is_default { not $::opt_embedded_server }
+
+my $groonga_normalizer_mysql_dir=$::basedir . '/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql';
+my $groonga_normalizer_mysql_install_dir=$::basedir . '/lib/groonga/plugins';
+
+if (-d $groonga_normalizer_mysql_dir)
+{
+ $ENV{GRN_PLUGINS_DIR}=$groonga_normalizer_mysql_dir;
+}
+elsif (-d $groonga_normalizer_mysql_install_dir)
+{
+ $ENV{GRN_PLUGINS_DIR}=$groonga_normalizer_mysql_install_dir;
+}
+
+bless { };
+
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column.test
new file mode 100644
index 00000000..92e48bb1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries ADD COLUMN body TEXT;
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_cp932.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_cp932.test
new file mode 100644
index 00000000..21e80a74
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_cp932.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES cp932;
+
+CREATE TABLE users (
+ id int unsigned PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=cp932 COMMENT='Engine "InnoDB"';
+ALTER TABLE users
+ ADD COLUMN O text,
+ ADD FULLTEXT INDEX (O);
+
+INSERT INTO users (O) VALUES ("܂");
+INSERT INTO users (O) VALUES ("Ȃ");
+INSERT INTO users (O) VALUES ("");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_utf8.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_utf8.test
new file mode 100644
index 00000000..f98d0e0d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_add_column_multibyte_utf8.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ id int unsigned PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET=utf8 COMMENT='Engine "InnoDB"';
+ALTER TABLE users
+ ADD COLUMN 名前 text,
+ ADD FULLTEXT INDEX (名前);
+
+INSERT INTO users (名前) VALUES ("やまだ");
+INSERT INTO users (名前) VALUES ("たなか");
+INSERT INTO users (名前) VALUES ("すずき");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_column_comment.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_column_comment.test
new file mode 100644
index 00000000..024da5ec
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_column_comment.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+
+ALTER TABLE bugs
+ CHANGE COLUMN
+ tag
+ tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.';
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_engine.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_engine.test
new file mode 100644
index 00000000..fc0379f2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_change_engine.test
@@ -0,0 +1,59 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) ENGINE MyISAM DEFAULT CHARSET UTF8;
+SELECT table_name, engine, table_comment
+ FROM information_schema.tables
+ WHERE table_name = 'diaries';
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+ MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+ALTER TABLE diaries ENGINE = mroonga COMMENT = 'ENGINE "InnoDB"';
+SELECT table_name, engine, table_comment
+ FROM information_schema.tables
+ WHERE table_name = 'diaries';
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey" IN BOOLEAN MODE) AND
+ MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("groonga" IN BOOLEAN MODE) AND
+ MATCH(body) AGAINST("groonga" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_comment_change_engine.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_comment_change_engine.test
new file mode 100644
index 00000000..ff54f1b5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_comment_change_engine.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT AUTO_INCREMENT PRIMARY KEY,
+ title VARCHAR(64),
+ content TEXT,
+ FULLTEXT INDEX(content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+
+INSERT INTO memos (title, content) VALUES ("Hello", "I start to write memos!");
+INSERT INTO memos (title, content) VALUES ("groonga", "I start to use groonga!");
+INSERT INTO memos (title, content) VALUES ("mroonga", "I use mroonga too!");
+
+ALTER TABLE memos COMMENT='engine "MyISAM"';
+SELECT table_name, table_comment
+ FROM information_schema.tables
+ WHERE table_name = 'memos';
+
+SELECT * FROM memos;
+SELECT * FROM memos WHERE MATCH(content) AGAINST("start" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_create_fulltext.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_create_fulltext.test
new file mode 100644
index 00000000..80d3ee72
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_create_fulltext.test
@@ -0,0 +1,56 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ WHERE MATCH (title) AGAINST ("富士山");
+
+CREATE FULLTEXT INDEX title_index on diaries (title);
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries DISABLE KEYS;
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_fulltext.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_fulltext.test
new file mode 100644
index 00000000..867ca370
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_fulltext.test
@@ -0,0 +1,50 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries DISABLE KEYS;
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_multiple_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_multiple_column.test
new file mode 100644
index 00000000..4bf97aac
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_multiple_column.test
@@ -0,0 +1,52 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY title_and_created_at_index (title, created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+ALTER TABLE diaries DISABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_normal.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_normal.test
new file mode 100644
index 00000000..0eccfded
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_normal.test
@@ -0,0 +1,50 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY created_at_index (created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+ALTER TABLE diaries DISABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_primary.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_primary.test
new file mode 100644
index 00000000..76cce0c9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_primary.test
@@ -0,0 +1,48 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_updating.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_updating.test
new file mode 100644
index 00000000..de1af71d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_disable_keys_updating.test
@@ -0,0 +1,42 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 (
+ c1 int NOT NULL,
+ c2 text NOT NULL,
+ c3 int NOT NULL,
+ c4 int NOT NULL,
+ PRIMARY KEY(c1),
+ KEY idx1(c3,c4),
+ FULLTEXT KEY ft1(c2)
+) COMMENT='ENGINE "MyISAM"' DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES(1, 'test1', 1, 1);
+INSERT INTO t1 VALUES(2, 'test2', 2, 2);
+INSERT INTO t1 VALUES(3, 'test3', 1, 3);
+ALTER TABLE t1 DISABLE KEYS;
+DELETE FROM t1 WHERE c1 = 2;
+UPDATE t1 SET c4 = 4 WHERE c1 = 1;
+INSERT INTO t1 VALUES(4, 'test4', 2, 4);
+TRUNCATE t1;
+DROP TABLE t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_drop_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_drop_column.test
new file mode 100644
index 00000000..9a8c9722
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_drop_column.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries DROP COLUMN body;
+SELECT * FROM diaries;
+
+INSERT INTO diaries (title) values ("groonga (1)");
+INSERT INTO diaries (title) values ("groonga (2)");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_fulltext.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_fulltext.test
new file mode 100644
index 00000000..84409307
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_fulltext.test
@@ -0,0 +1,52 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ FULLTEXT KEY title_index (title)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_index)
+ WHERE MATCH (title) AGAINST ("富士山");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_lock_tables.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_lock_tables.test
new file mode 100644
index 00000000..1532c916
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_lock_tables.test
@@ -0,0 +1,45 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+CREATE TABLE IF NOT EXISTS memos (
+ id VARCHAR(45) NOT NULL PRIMARY KEY,
+ text TEXT NOT NULL,
+ FULLTEXT KEY (text)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+
+LOCK TABLES memos WRITE;
+ALTER TABLE memos DISABLE KEYS;
+
+INSERT INTO memos
+ VALUES (00000, 'text0'),
+ (00001, 'text1'),
+ (00002, 'text2');
+
+ALTER TABLE memos ENABLE KEYS;
+UNLOCK TABLES;
+
+SELECT * FROM memos;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_multiple_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_multiple_column.test
new file mode 100644
index 00000000..78707797
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_multiple_column.test
@@ -0,0 +1,54 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY title_and_created_at_index (title, created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (title_and_created_at_index)
+ WHERE title = "天気" AND
+ created_at = "2012-04-30 23:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_normal.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_normal.test
new file mode 100644
index 00000000..2427353a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_normal.test
@@ -0,0 +1,52 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ created_at datetime,
+ KEY created_at_index (created_at)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello", "2012-04-30 20:00:00");
+INSERT INTO diaries VALUES (2, "天気" , "2012-04-30 23:00:00");
+INSERT INTO diaries VALUES (3, "富士山", "2012-04-30 19:00:00");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (created_at_index)
+ WHERE created_at = "2012-04-30 20:00:00";
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_primary.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_primary.test
new file mode 100644
index 00000000..7c3c7176
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_enable_keys_primary.test
@@ -0,0 +1,50 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+ALTER TABLE diaries DISABLE KEYS;
+
+INSERT INTO diaries VALUES (1, "Hello");
+INSERT INTO diaries VALUES (2, "天気");
+INSERT INTO diaries VALUES (3, "富士山");
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+ALTER TABLE diaries ENABLE KEYS;
+
+SELECT *
+ FROM diaries
+ FORCE INDEX (PRIMARY)
+ WHERE id = 2;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_fulltext.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_fulltext.test
new file mode 100644
index 00000000..95220759
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_fulltext.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ FULLTEXT INDEX title_index (title)
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries (title) VALUES ("survey");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries ADD COLUMN body TEXT;
+UPDATE diaries SET body = "will start groonga!";
+SELECT * FROM diaries;
+
+INSERT INTO diaries (title, body) values ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) values ("groonga (2)", "started groonga.");
+SELECT * FROM diaries;
+
+ALTER TABLE diaries ADD FULLTEXT INDEX body_index (body);
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey") AND
+ MATCH(body) AGAINST("groonga");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("groonga") AND
+ MATCH(body) AGAINST("starting");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_rename_table.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_rename_table.test
new file mode 100644
index 00000000..46c57f05
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_rename_table.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries, memos;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("groonga") AND
+ MATCH(body) AGAINST("starting");
+
+ALTER TABLE diaries RENAME memos;
+SELECT * FROM memos;
+SELECT * FROM memos
+ WHERE MATCH(title) AGAINST("groonga") AND
+ MATCH(body) AGAINST("starting");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_spatial.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_spatial.test
new file mode 100644
index 00000000..c762b7ff
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/alter_table_spatial.test
@@ -0,0 +1,150 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS shops;
+--enable_warnings
+
+CREATE TABLE shops (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ name TEXT,
+ location GEOMETRY NOT NULL
+) COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO shops (name, location)
+ VALUES ('nezu-no-taiyaki',
+ ST_GeomFromText('POINT(139.762573 35.720253)'));
+INSERT INTO shops (name, location)
+ VALUES ('taiyaki-kataoka',
+ ST_GeomFromText('POINT(139.715591 35.712521)'));
+INSERT INTO shops (name, location)
+ VALUES ('soba-taiyaki-ku',
+ ST_GeomFromText('POINT(139.659088 35.683712)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuruma',
+ ST_GeomFromText('POINT(139.706207 35.721516)'));
+INSERT INTO shops (name, location)
+ VALUES ('hirose-ya',
+ ST_GeomFromText('POINT(139.685608 35.714844)'));
+INSERT INTO shops (name, location)
+ VALUES ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+INSERT INTO shops (name, location)
+ VALUES ('omede-taiyaki',
+ ST_GeomFromText('POINT(139.817154 35.700516)'));
+INSERT INTO shops (name, location)
+ VALUES ('onaga-ya',
+ ST_GeomFromText('POINT(139.81105 35.698254)'));
+INSERT INTO shops (name, location)
+ VALUES ('shiro-ya',
+ ST_GeomFromText('POINT(139.638611 35.705517)'));
+INSERT INTO shops (name, location)
+ VALUES ('fuji-ya',
+ ST_GeomFromText('POINT(139.637115 35.703938)'));
+INSERT INTO shops (name, location)
+ VALUES ('miyoshi',
+ ST_GeomFromText('POINT(139.537323 35.644539)'));
+INSERT INTO shops (name, location)
+ VALUES ('juju-ya',
+ ST_GeomFromText('POINT(139.695755 35.628922)'));
+INSERT INTO shops (name, location)
+ VALUES ('tatsumi-ya',
+ ST_GeomFromText('POINT(139.638657 35.665501)'));
+INSERT INTO shops (name, location)
+ VALUES ('tetsuji',
+ ST_GeomFromText('POINT(139.76857 35.680912)'));
+INSERT INTO shops (name, location)
+ VALUES ('gazuma-ya',
+ ST_GeomFromText('POINT(139.647598 35.700817)'));
+INSERT INTO shops (name, location)
+ VALUES ('honma-mon',
+ ST_GeomFromText('POINT(139.652573 35.722736)'));
+INSERT INTO shops (name, location)
+ VALUES ('naniwa-ya',
+ ST_GeomFromText('POINT(139.796234 35.730061)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuro-dai',
+ ST_GeomFromText('POINT(139.704834 35.650345)'));
+INSERT INTO shops (name, location)
+ VALUES ('daruma',
+ ST_GeomFromText('POINT(139.770599 35.681461)'));
+INSERT INTO shops (name, location)
+ VALUES ('yanagi-ya',
+ ST_GeomFromText('POINT(139.783981 35.685341)'));
+INSERT INTO shops (name, location)
+ VALUES ('sharaku',
+ ST_GeomFromText('POINT(139.794846 35.716969)'));
+INSERT INTO shops (name, location)
+ VALUES ('takane',
+ ST_GeomFromText('POINT(139.560913 35.698601)'));
+INSERT INTO shops (name, location)
+ VALUES ('chiyoda',
+ ST_GeomFromText('POINT(139.652817 35.642601)'));
+INSERT INTO shops (name, location)
+ VALUES ('da-ka-po',
+ ST_GeomFromText('POINT(139.727356 35.627346)'));
+INSERT INTO shops (name, location)
+ VALUES ('matsushima-ya',
+ ST_GeomFromText('POINT(139.737381 35.640556)'));
+INSERT INTO shops (name, location)
+ VALUES ('kazuya',
+ ST_GeomFromText('POINT(139.760895 35.673508)'));
+INSERT INTO shops (name, location)
+ VALUES ('furuya-kogane-an',
+ ST_GeomFromText('POINT(139.676071 35.680603)'));
+INSERT INTO shops (name, location)
+ VALUES ('hachi-no-ie',
+ ST_GeomFromText('POINT(139.668106 35.608021)'));
+INSERT INTO shops (name, location)
+ VALUES ('azuki-chan',
+ ST_GeomFromText('POINT(139.673203 35.64151)'));
+INSERT INTO shops (name, location)
+ VALUES ('kuriko-an',
+ ST_GeomFromText('POINT(139.796829 35.712013)'));
+INSERT INTO shops (name, location)
+ VALUES ('yume-no-aru-machi-no-taiyaki-ya-san',
+ ST_GeomFromText('POINT(139.712524 35.616199)'));
+INSERT INTO shops (name, location)
+ VALUES ('naze-ya',
+ ST_GeomFromText('POINT(139.665833 35.609039)'));
+INSERT INTO shops (name, location)
+ VALUES ('sanoki-ya',
+ ST_GeomFromText('POINT(139.770721 35.66592)'));
+INSERT INTO shops (name, location)
+ VALUES ('shigeta',
+ ST_GeomFromText('POINT(139.780273 35.672626)'));
+INSERT INTO shops (name, location)
+ VALUES ('nishimi-ya',
+ ST_GeomFromText('POINT(139.774628 35.671825)'));
+INSERT INTO shops (name, location)
+ VALUES ('hiiragi',
+ ST_GeomFromText('POINT(139.711517 35.647701)'));
+
+ALTER TABLE shops ADD SPATIAL KEY location_index (location);
+
+SELECT id, name, ST_AsText(location) AS location_text FROM shops
+ WHERE MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location)
+ ORDER BY id;
+
+DROP TABLE shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/auto_increment_text.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/auto_increment_text.test
new file mode 100644
index 00000000..e8cd2585
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/auto_increment_text.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text
+) comment = 'engine "innodb"';
+insert into diaries (body) values ("started groonga (long text)");
+select * from diaries;
+insert into diaries (body) values ("sleeping... (short text)");
+select * from diaries;
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/binlog_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/binlog_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..328d2f7d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/binlog_TODO_SPLIT_ME.test
@@ -0,0 +1,55 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/have_log_bin.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+show variables like 'log_bin';
+
+set binlog_format="STATEMENT";
+
+create table t1 (c1 int primary key, c2 int) engine = mroonga COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+drop table t1;
+
+set binlog_format="ROW";
+
+create table t1 (c1 int primary key, c2 int) engine = mroonga COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+drop table t1;
+
+set binlog_format="MIXED";
+
+create table t1 (c1 int primary key, c2 int) engine = mroonga COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+insert into t1 values(2,100);
+commit;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/check_table_for_upgrade.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/check_table_for_upgrade.test
new file mode 100644
index 00000000..f846cce7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/check_table_for_upgrade.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id int NOT NULL PRIMARY KEY,
+ content text,
+ FULLTEXT INDEX (content)
+) COMMENT='engine "InnoDB"';
+
+INSERT INTO memos VALUES (1, 'Hello MySQL');
+INSERT INTO memos VALUES (2, 'Hello Mroonga');
+
+CHECK TABLE memos FOR UPGRADE;
+
+FLUSH TABLES;
+
+SELECT * FROM memos
+ WHERE MATCH(content) AGAINST('+mroonga' IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_comment_index_not_for_mroonga.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_comment_index_not_for_mroonga.test
new file mode 100644
index 00000000..3213693e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_comment_index_not_for_mroonga.test
@@ -0,0 +1,37 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64),
+ INDEX (tag) COMMENT 'Tag search is required.'
+) DEFAULT CHARSET=utf8
+ COMMENT='engine "InnoDB"';
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_add_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_add_column.test
new file mode 100644
index 00000000..b1c5a80c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_add_column.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED;
+ALTER TABLE logs ADD FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"';
+
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_delete.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_delete.test
new file mode 100644
index 00000000..5ee4c000
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_delete.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+DELETE FROM logs WHERE id = 1;
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_drop_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_drop_column.test
new file mode 100644
index 00000000..4193b268
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_drop_column.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+ALTER TABLE logs DROP COLUMN message;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_insert.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_insert.test
new file mode 100644
index 00000000..bcea1738
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_insert.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_reindex.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_reindex.test
new file mode 100644
index 00000000..130d41d1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_reindex.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+ALTER TABLE logs DISABLE KEYS;
+ALTER TABLE logs ENABLE KEYS;
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("ar" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_update.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_update.test
new file mode 100644
index 00000000..77562cb6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_stored_update.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) STORED,
+ FULLTEXT INDEX(message) comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST("hut" IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_column.test
new file mode 100644
index 00000000..68567b80
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_column.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+
+ALTER TABLE logs ADD COLUMN message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL;
+
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_fulltext_index.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_fulltext_index.test
new file mode 100644
index 00000000..ebf7213b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_fulltext_index.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2017 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mariadb_10_2_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record)
+ VALUES (1, '{"level": "info", "message": "start server"}');
+
+ALTER TABLE logs ADD FULLTEXT INDEX (message);
+
+INSERT INTO logs(id, record)
+ VALUES (2, '{"level": "info", "message": "start server"}');
+INSERT INTO logs(id, record)
+ VALUES (3, '{"level": "warn", "message": "abort server"}');
+
+SELECT * FROM logs WHERE MATCH(message) AGAINST('+start' IN BOOLEAN MODE);
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_index.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_index.test
new file mode 100644
index 00000000..c5719ff7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_add_index.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2017 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ level VARCHAR(255) GENERATED ALWAYS AS
+ (json_unquote(json_extract(`record`, '$.level'))) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record)
+ VALUES (1, '{"level": "info", "message": "start server"}');
+
+ALTER TABLE logs ADD INDEX (level);
+
+INSERT INTO logs(id, record)
+ VALUES (2, '{"level": "info", "message": "start server"}');
+INSERT INTO logs(id, record)
+ VALUES (3, '{"level": "warn", "message": "abort server"}');
+
+SELECT * FROM logs WHERE level = 'info';
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_delete.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_delete.test
new file mode 100644
index 00000000..df371534
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_delete.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+DELETE FROM logs WHERE id = 1;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_drop_column.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_drop_column.test
new file mode 100644
index 00000000..b025fd79
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_drop_column.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+ALTER TABLE logs DROP COLUMN message;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_insert.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_insert.test
new file mode 100644
index 00000000..4ef127f3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_insert.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_update.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_update.test
new file mode 100644
index 00000000..fe9b662b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_generated_virtual_update.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2017 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_version_5_7_or_later.inc
+--source ../../include/mroonga/skip_mariadb_10_1_or_earlier.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS logs;
+--enable_warnings
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY,
+ record JSON,
+ message VARCHAR(255) GENERATED ALWAYS AS (json_extract(`record`, '$.message')) VIRTUAL
+) ENGINE=Mroonga DEFAULT CHARSET=utf8mb4 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO logs(id, record) VALUES (1, '{"level": "info", "message": "start"}');
+INSERT INTO logs(id, record) VALUES (2, '{"level": "info", "message": "restart"}');
+INSERT INTO logs(id, record) VALUES (3, '{"level": "warn", "message": "abort"}');
+
+UPDATE logs SET record = '{"level": "info", "message": "shutdown"}' WHERE id = 2;
+
+SELECT * FROM logs;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_cp932.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_cp932.test
new file mode 100644
index 00000000..5898e377
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_cp932.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES cp932;
+
+CREATE TABLE users (
+ id int unsigned PRIMARY KEY AUTO_INCREMENT,
+ O text,
+ FULLTEXT INDEX (O)
+) DEFAULT CHARSET=cp932 COMMENT='Engine "InnoDB"';
+
+INSERT INTO users (O) VALUES ("܂");
+INSERT INTO users (O) VALUES ("Ȃ");
+INSERT INTO users (O) VALUES ("");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (O) AGAINST ('+Ȃ' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_utf8.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_utf8.test
new file mode 100644
index 00000000..c646a1d2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_multibyte_utf8.test
@@ -0,0 +1,53 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ id int unsigned PRIMARY KEY AUTO_INCREMENT,
+ 名前 text,
+ FULLTEXT INDEX (名前)
+) DEFAULT CHARSET=utf8 COMMENT='Engine "InnoDB"';
+
+INSERT INTO users (名前) VALUES ("やまだ");
+INSERT INTO users (名前) VALUES ("たなか");
+INSERT INTO users (名前) VALUES ("すずき");
+
+SELECT * FROM users;
+
+SELECT * FROM users
+ WHERE MATCH (名前) AGAINST ('+たなか' IN BOOLEAN MODE);
+
+SELECT mroonga_command("dump --dump_plugins no --dump_records no");
+
+DROP TABLE users;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/column_normal_comment.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_normal_comment.test
new file mode 100644
index 00000000..802f5beb
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/column_normal_comment.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY,
+ tag VARCHAR(64) COMMENT 'It must consist of only alphabet and number.'
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnoDB"';
+
+SHOW CREATE TABLE bugs;
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star.test
new file mode 100644
index 00000000..de9e8108
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star.test
@@ -0,0 +1,36 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int PRIMARY KEY
+) COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO ids VALUES (1);
+INSERT INTO ids VALUES (2);
+INSERT INTO ids VALUES (3);
+
+SELECT COUNT(*) FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_mysql_5_7_or_later_with_index.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_mysql_5_7_or_later_with_index.test
new file mode 100644
index 00000000..9a082c69
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_mysql_5_7_or_later_with_index.test
@@ -0,0 +1,55 @@
+# Copyright(C) 2011-2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE diaries_innodb (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ body TEXT,
+ flag TINYINT(2),
+ INDEX (flag)
+) ENGINE = InnoDB DEFAULT CHARSET UTF8;
+
+CREATE TABLE diaries_mroonga (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ body TEXT,
+ flag TINYINT(2),
+ INDEX (flag)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries_innodb (body) VALUES ("will start groonga!");
+INSERT INTO diaries_innodb (body) VALUES ("starting groonga...");
+INSERT INTO diaries_innodb (body) VALUES ("started groonga.");
+
+INSERT INTO diaries_mroonga (body) VALUES ("will start groonga!");
+INSERT INTO diaries_mroonga (body) VALUES ("starting groonga...");
+INSERT INTO diaries_mroonga (body) VALUES ("started groonga.");
+
+EXPLAIN SELECT COUNT(*) FROM diaries_innodb;
+EXPLAIN SELECT COUNT(*) FROM diaries_mroonga;
+
+DROP TABLE diaries_innodb;
+DROP TABLE diaries_mroonga;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_with_index.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_with_index.test
new file mode 100644
index 00000000..dce0899e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/count_star_with_index.test
@@ -0,0 +1,57 @@
+# Copyright(C) 2011-2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+CREATE TABLE diaries_innodb (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ body TEXT,
+ flag TINYINT(2),
+ INDEX (flag)
+) ENGINE = InnoDB DEFAULT CHARSET UTF8;
+
+CREATE TABLE diaries_mroonga (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ body TEXT,
+ flag TINYINT(2),
+ INDEX (flag)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries_innodb (body) VALUES ("will start groonga!");
+INSERT INTO diaries_innodb (body) VALUES ("starting groonga...");
+INSERT INTO diaries_innodb (body) VALUES ("started groonga.");
+
+INSERT INTO diaries_mroonga (body) VALUES ("will start groonga!");
+INSERT INTO diaries_mroonga (body) VALUES ("starting groonga...");
+INSERT INTO diaries_mroonga (body) VALUES ("started groonga.");
+
+-- replace_column 9 #
+EXPLAIN SELECT COUNT(*) FROM diaries_innodb;
+-- replace_column 9 #
+EXPLAIN SELECT COUNT(*) FROM diaries_mroonga;
+
+DROP TABLE diaries_innodb;
+DROP TABLE diaries_mroonga;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..997410b5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_TODO_SPLIT_ME.test
@@ -0,0 +1,101 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+# simple test
+create table t1 (c1 int primary key) COMMENT = 'engine "innodb"';
+create table t2 (c1 int primary key) COMMENT = 'engine "innodb"';
+create table t3 (c1 int primary key) COMMENT = 'engine "innodb"';
+drop table t1,t2,t3;
+create table t1 (c1 int primary key, c2 int, c3 int) COMMENT = 'engine "innodb"';
+drop table t1;
+
+# data type support
+create table t1 (c1 bit primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 tinyint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 smallint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 mediumint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 int primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 bigint primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 double primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 float primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 decimal primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 date primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 time primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 timestamp primary key) COMMENT = 'engine "innodb"';
+# For MariaDB 10.2.3
+-- replace_result current_timestamp() CURRENT_TIMESTAMP
+desc t1;
+drop table t1;
+create table t1 (c1 datetime primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 year primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 char(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 varchar(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 binary(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 varbinary(10) primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 enum("yes","no") primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+create table t1 (c1 set("A","B","AB","O") primary key) COMMENT = 'engine "innodb"';
+desc t1;
+drop table t1;
+
+# error test
+--error ER_REQUIRES_PRIMARY_KEY
+create table t1 (c1 int) COMMENT = 'engine "innodb"';
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_comment_combined.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_comment_combined.test
new file mode 100644
index 00000000..e6dd9908
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_comment_combined.test
@@ -0,0 +1,35 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS bugs;
+--enable_warnings
+
+CREATE TABLE bugs (
+ id INT UNSIGNED PRIMARY KEY
+) DEFAULT CHARSET=utf8
+ COMMENT='Free style normal comment, engine "InnoDB"';
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE bugs;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_comment.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_comment.test
new file mode 100644
index 00000000..e5c66243
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_comment.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL PRIMARY KEY,
+ FULLTEXT INDEX (content) COMMENT 'flags "WITH_POSITION|WITH_WEIGHT"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_none.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_none.test
new file mode 100644
index 00000000..e8b57a93
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_none.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL PRIMARY KEY,
+ FULLTEXT INDEX (content) COMMENT 'flags "NONE"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_parameter.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_parameter.test
new file mode 100644
index 00000000..ca536cc3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_flags_parameter.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL PRIMARY KEY,
+ FULLTEXT INDEX (content) FLAGS='WITH_POSITION|WITH_WEIGHT'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_none.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_none.test
new file mode 100644
index 00000000..0b02780d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_none.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL PRIMARY KEY,
+ FULLTEXT INDEX (content) COMMENT 'index_flags "NONE"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_with_position_and_with_weight.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_with_position_and_with_weight.test
new file mode 100644
index 00000000..aa0737f4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_index_flags_with_position_and_with_weight.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2015 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ content VARCHAR(64) NOT NULL PRIMARY KEY,
+ FULLTEXT INDEX (content) COMMENT 'index_flags "WITH_POSITION|WITH_WEIGHT"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no --dump_schema no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_comment.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_comment.test
new file mode 100644
index 00000000..b393c59a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_comment.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_fulltext_index_bin.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_fulltext_index_bin.test
new file mode 100644
index 00000000..000d2d5b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_fulltext_index_bin.test
@@ -0,0 +1,40 @@
+# Copyright(C) 2016 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'normalizer "NormalizerAuto"'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
+SHOW CREATE TABLE memos;
+
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_parameter.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_parameter.test
new file mode 100644
index 00000000..354d27c6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_normalizer_parameter.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content TEXT NOT NULL,
+ FULLTEXT INDEX (content) NORMALIZER='NormalizerAuto'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+INSERT INTO memos VALUES (1, "1日の消費㌍は約2000㌔㌍");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("+カロリー" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_parser_comment.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_parser_comment.test
new file mode 100644
index 00000000..81342a74
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_parser_comment.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+ comment 'parser "TokenBigramSplitSymbolAlphaDigit"'
+) comment = 'engine "innodb"' default charset utf8;
+--enable_prepare_warnings
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+select * from diaries;
+select * from diaries where match(body) against("+start" in boolean mode) order by id;
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_multiple_token_filters.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_multiple_token_filters.test
new file mode 100644
index 00000000..45c75817
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_multiple_token_filters.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord,TokenFilterStopWord"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_one_token_filter.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_one_token_filter.test
new file mode 100644
index 00000000..64732efd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_one_token_filter.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) COMMENT 'token_filters "TokenFilterStopWord"'
+) COMMENT='engine "InnoDB"' DEFAULT CHARSET=utf8;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_parameter.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_parameter.test
new file mode 100644
index 00000000..3fb0caea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_token_filters_index_parameter.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2014 Naoya Murakami <naoya@createfield.com>
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_groonga_plugin_register.inc
+--source ../../include/mroonga/load_mroonga_functions.inc
+
+--disable_query_log
+DROP DATABASE test;
+CREATE DATABASE test;
+USE test;
+--enable_query_log
+
+SELECT mroonga_command("plugin_register token_filters/stop_word");
+
+SET NAMES utf8;
+
+CREATE TABLE memos (
+ id INT NOT NULL PRIMARY KEY,
+ content VARCHAR(64) NOT NULL,
+ FULLTEXT INDEX (content) TOKEN_FILTERS='TokenFilterStopWord,TokenFilterStopWord'
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+SHOW CREATE TABLE memos;
+
+SELECT mroonga_command("dump --dump_plugins no");
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/unload_mroonga_functions.inc
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_comment.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_comment.test
new file mode 100644
index 00000000..29233d01
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_comment.test
@@ -0,0 +1,37 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+ comment 'tokenizer "TokenBigramSplitSymbolAlphaDigit"'
+) comment = 'engine "innodb"' default charset utf8;
+insert into diaries (body) values ("will start Groonga!");
+insert into diaries (body) values ("starting Groonga...");
+insert into diaries (body) values ("started Groonga.");
+select * from diaries;
+select * from diaries where match(body) against("+start" in boolean mode) order by id;
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_parameter.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_parameter.test
new file mode 100644
index 00000000..072ad450
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/create_table_tokenizer_parameter.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source ../../include/mroonga/have_mariadb.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id int PRIMARY KEY AUTO_INCREMENT,
+ body text,
+ FULLTEXT INDEX body_index (body) TOKENIZER='TokenBigramSplitSymbolAlphaDigit'
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET utf8;
+
+INSERT INTO diaries (body) VALUES ("will start Groonga!");
+INSERT INTO diaries (body) VALUES ("starting Groonga...");
+INSERT INTO diaries (body) VALUES ("started Groonga.");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("+start" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/delete_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/delete_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..9491ba7f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/delete_TODO_SPLIT_ME.test
@@ -0,0 +1,59 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int) COMMENT 'engine = "innodb"';
+show create table t1;
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+insert into t1 values (4, 102);
+select * from t1;
+
+delete from t1 where c1=3;
+select * from t1;
+
+flush tables;
+
+delete from t1 where c1=2;
+select * from t1;
+
+delete from t1;
+select * from t1;
+
+drop table t1;
+
+create table t1 (c1 int primary key, c2 text, fulltext index (c2)) COMMENT 'engine = "innodb"';
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+
+select * from t1;
+select * from t1 where match(c2) against("ki");
+delete from t1 where c1=20;
+select * from t1;
+select * from t1 where match(c2) against("ki");
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/delete_all.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/delete_all.test
new file mode 100644
index 00000000..50ebec44
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/delete_all.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS users;
+--enable_warnings
+
+SET NAMES utf8;
+
+CREATE TABLE users (
+ id int PRIMARY KEY,
+ name varchar(100),
+ FULLTEXT INDEX (name)
+) COMMENT 'engine = "InnoDB"' DEFAULT CHARSET=utf8;
+
+INSERT INTO users VALUES (1, 'Alice');
+INSERT INTO users VALUES (2, 'Bob');
+INSERT INTO users VALUES (3, 'Chris');
+
+SELECT * FROM users;
+
+DELETE FROM users;
+
+SELECT * FROM users;
+
+DROP TABLE users;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/drop_table_new_connection.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/drop_table_new_connection.test
new file mode 100644
index 00000000..5e761376
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/drop_table_new_connection.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/not_embedded.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ message TEXT,
+ FULLTEXT INDEX (message)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+disable_query_log;
+CONNECT(drop_connection, localhost, root);
+enable_query_log;
+
+USE test;
+DROP TABLE logs;
+
+disable_query_log;
+CONNECTION default;
+enable_query_log;
+
+CREATE TABLE logs (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ message TEXT,
+ FULLTEXT INDEX (message)
+) COMMENT='ENGINE "InnoDB"' DEFAULT CHARSET=utf8;
+
+DROP TABLE logs;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_leading_not.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_leading_not.test
new file mode 100644
index 00000000..92c6b3fd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_leading_not.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET = UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT * FROM diaries WHERE MATCH(content) AGAINST("-明日 +天気" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_multiple_match_against.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_multiple_match_against.test
new file mode 100644
index 00000000..5acbbe5c
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_multiple_match_against.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title),
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET = UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries VALUES(1, "富士山", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気 1月1日", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "天気 4月4日", "今日も天気がよくてきれいに見える。");
+
+SELECT COUNT(*) FROM diaries WHERE MATCH(title) AGAINST("+天気" IN BOOLEAN MODE) AND MATCH(content) AGAINST("+今日" IN BOOLEAN MODE);
+SELECT * FROM diaries WHERE MATCH(title) AGAINST("+天気" IN BOOLEAN MODE) AND MATCH(content) AGAINST("+今日" IN BOOLEAN MODE);
+SELECT 1 FROM diaries WHERE MATCH(title) AGAINST("+天気" IN BOOLEAN MODE) AND MATCH(content) AGAINST("+今日" IN BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test
new file mode 100644
index 00000000..bbd8223b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_no_operator.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Yesterday was good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D- fine is be" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test
new file mode 100644
index 00000000..d49e7e92
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_or.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Yesterday was good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D- is OR be fine" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test
new file mode 100644
index 00000000..2f90b965
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_minus_with_plus.test
@@ -0,0 +1,43 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Yesterday was good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D- good +day be" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test
new file mode 100644
index 00000000..dffbb6e3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_no_operator.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*DOR today good" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test
new file mode 100644
index 00000000..310ca900
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_minus.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*DOR today -good tomorrow" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test
new file mode 100644
index 00000000..cd65c792
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_or_with_plus.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be fine.");
+INSERT INTO memos VALUES (NULL, "Yesterday was fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*DOR today +good tomorrow" IN BOOLEAN MODE)
+ ORDER BY id;
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test
new file mode 100644
index 00000000..3c8145f1
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_no_operator.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today good" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test
new file mode 100644
index 00000000..f7e45706
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_minus.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today -good is" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test
new file mode 100644
index 00000000..94069f9a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_default_operator_plus_with_or.test
@@ -0,0 +1,40 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE memos (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET=utf8 COMMENT='engine "InnODB"';
+
+INSERT INTO memos VALUES (NULL, "Today is good day.");
+INSERT INTO memos VALUES (NULL, "Tomorrow will be good day.");
+INSERT INTO memos VALUES (NULL, "Today is fine.");
+
+SELECT * FROM memos
+ WHERE MATCH (content) AGAINST ("*D+ today OR tomorrow day" IN BOOLEAN MODE);
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_full_spec.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_full_spec.test
new file mode 100644
index 00000000..5c36b04b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_full_spec.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*W1:10,2:2 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_no_weight.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_no_weight.test
new file mode 100644
index 00000000..a8ee6cf3
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_no_weight.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*W1,2:2 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*W1,2:2 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_omit_section.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_omit_section.test
new file mode 100644
index 00000000..63379dcd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_boolean_mode_pragma_weight_omit_section.test
@@ -0,0 +1,44 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id INT PRIMARY KEY,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX (title, content)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO diaries VALUES(1, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT *, MATCH(title, content)
+ AGAINST("*W1:2 +天気" in BOOLEAN MODE) AS score
+ FROM diaries
+ WHERE MATCH(title, content)
+ AGAINST("*W1:2 +天気" in BOOLEAN MODE);
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_ascii.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_ascii.test
new file mode 100644
index 00000000..5f42b534
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_ascii.test
@@ -0,0 +1,38 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+select * from t1 where match(c3) against("su");
+select * from t1 where match(c3) against("ii");
+select * from t1 where match(c3) against("+su" in boolean mode);
+select * from t1 where match(c3) against("+ii" in boolean mode);
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_cp932.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_cp932.test
new file mode 100644
index 00000000..b7b5ccf2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_cp932.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/have_cp932.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names cp932;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset cp932 COMMENT = 'engine "innodb"';
+insert into t1 values(1, "̕xmR̓VCɂ‚","");
+insert into t1 values(2, "","̕xmR̓VC͕܂");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("xmR");
+select * from t1 where match(c3) against("xmR");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_eucjpms.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_eucjpms.test
new file mode 100644
index 00000000..afe22027
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_eucjpms.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/have_eucjpms.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names eucjpms;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset eucjpms COMMENT = 'engine "innodb"';
+insert into t1 values(1, "ٻλŷˤĤ","");
+insert into t1 values(2, "","ٻλŷʬޤ");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("ٻλ");
+select * from t1 where match(c3) against("ٻλ");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_japanese.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_japanese.test
new file mode 100644
index 00000000..d013abb5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_charset_japanese.test
@@ -0,0 +1,35 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8 COMMENT = 'engine "innodb"';
+insert into t1 values(1, "明日の富士山の天気について","あああああああ");
+insert into t1 values(2, "いいいいい","明日の富士山の天気は分かりません");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("富士山");
+select * from t1 where match(c3) against("富士山");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_index_recreate.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_index_recreate.test
new file mode 100644
index 00000000..e6f3d811
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_index_recreate.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES utf8;
+CREATE TABLE diaries (
+ id int PRIMARY KEY,
+ title varchar(255),
+ content text,
+ FULLTEXT INDEX (title)
+) DEFAULT CHARSET=utf8 COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO diaries VALUES (1, "Hello", "はじめました。");
+INSERT INTO diaries VALUES (2, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES (3, "富士山", "今日もきれい。");
+
+SELECT * FROM diaries WHERE MATCH (title) AGAINST ("富士山");
+
+DROP INDEX title ON diaries;
+
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+SELECT * FROM diaries WHERE MATCH (title) AGAINST ("富士山");
+SELECT * FROM diaries;
+
+CREATE FULLTEXT INDEX new_title_index ON diaries (title);
+SELECT * FROM diaries WHERE MATCH (title) AGAINST ("富士山");
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_select.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_select.test
new file mode 100644
index 00000000..38adadea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_select.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 varchar(100), fulltext index(c2)) default charset utf8 COMMENT = 'engine "innodb"';
+create table t2 (c1 int primary key, c2 text, fulltext index(c2)) default charset utf8 COMMENT = 'engine "innodb"';
+insert into t1 values (1, "aa ii uu ee oo");
+insert into t1 values (2, "ka ki ku ke ko");
+insert into t1 values (3, "aa ii ii ii oo");
+insert into t1 values (4, "sa si su se so");
+insert into t1 values (5, "ta ti ii ii to");
+insert into t2 values (1, "aa ii uu ee oo");
+insert into t2 values (2, "ka ki ku ke ko");
+insert into t2 values (3, "aa ii ii ii oo");
+insert into t2 values (4, "sa si su se so");
+insert into t2 values (5, "ta ti ii ii to");
+select * from t1;
+select * from t2;
+select * from t1 where c1=3;
+select * from t2 where c1=3;
+select * from t1 where c1>3 order by c1 desc;
+select * from t2 where c1>3 order by c1 asc;
+select * from t1 where c2>"s" order by c2 desc;
+select * from t2 where c2>"s" order by c1 asc;
+select *,match(c2) against("ii") from t1 where match(c2) against("ii") order by match(c2) against("ii") desc;
+select *,match(c2) against("ii") from t2 where match(c2) against("ii") order by match(c2) against("ii") asc;
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+drop table t1,t2;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_values.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_values.test
new file mode 100644
index 00000000..b8e55db4
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_insert_values.test
@@ -0,0 +1,34 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 text, fulltext index ft (c2)) COMMENT = 'engine "innodb"';
+insert into t1 values (1, "hoge hoge");
+insert into t1 values (2, "fuga fuga");
+insert into t1 values (3, "moge moge");
+select * from t1;
+flush tables;
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_many_records.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_many_records.test
new file mode 100644
index 00000000..a036a521
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_many_records.test
@@ -0,0 +1,4135 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ fulltext index (title)
+) default charset utf8 COMMENT = 'engine "innodb"';
+
+set autocommit=0;
+insert into diaries values(0, "2011-07-14");
+insert into diaries values(1, "2011-07-15");
+insert into diaries values(2, "2011-07-16");
+insert into diaries values(3, "2011-07-17");
+insert into diaries values(4, "2011-07-18");
+insert into diaries values(5, "2011-07-19");
+insert into diaries values(6, "2011-07-20");
+insert into diaries values(7, "2011-07-21");
+insert into diaries values(8, "2011-07-22");
+insert into diaries values(9, "2011-07-23");
+insert into diaries values(10, "2011-07-24");
+insert into diaries values(11, "2011-07-25");
+insert into diaries values(12, "2011-07-26");
+insert into diaries values(13, "2011-07-27");
+insert into diaries values(14, "2011-07-28");
+insert into diaries values(15, "2011-07-29");
+insert into diaries values(16, "2011-07-30");
+insert into diaries values(17, "2011-07-31");
+insert into diaries values(18, "2011-08-01");
+insert into diaries values(19, "2011-08-02");
+insert into diaries values(20, "2011-08-03");
+insert into diaries values(21, "2011-08-04");
+insert into diaries values(22, "2011-08-05");
+insert into diaries values(23, "2011-08-06");
+insert into diaries values(24, "2011-08-07");
+insert into diaries values(25, "2011-08-08");
+insert into diaries values(26, "2011-08-09");
+insert into diaries values(27, "2011-08-10");
+insert into diaries values(28, "2011-08-11");
+insert into diaries values(29, "2011-08-12");
+insert into diaries values(30, "2011-08-13");
+insert into diaries values(31, "2011-08-14");
+insert into diaries values(32, "2011-08-15");
+insert into diaries values(33, "2011-08-16");
+insert into diaries values(34, "2011-08-17");
+insert into diaries values(35, "2011-08-18");
+insert into diaries values(36, "2011-08-19");
+insert into diaries values(37, "2011-08-20");
+insert into diaries values(38, "2011-08-21");
+insert into diaries values(39, "2011-08-22");
+insert into diaries values(40, "2011-08-23");
+insert into diaries values(41, "2011-08-24");
+insert into diaries values(42, "2011-08-25");
+insert into diaries values(43, "2011-08-26");
+insert into diaries values(44, "2011-08-27");
+insert into diaries values(45, "2011-08-28");
+insert into diaries values(46, "2011-08-29");
+insert into diaries values(47, "2011-08-30");
+insert into diaries values(48, "2011-08-31");
+insert into diaries values(49, "2011-09-01");
+insert into diaries values(50, "2011-09-02");
+insert into diaries values(51, "2011-09-03");
+insert into diaries values(52, "2011-09-04");
+insert into diaries values(53, "2011-09-05");
+insert into diaries values(54, "2011-09-06");
+insert into diaries values(55, "2011-09-07");
+insert into diaries values(56, "2011-09-08");
+insert into diaries values(57, "2011-09-09");
+insert into diaries values(58, "2011-09-10");
+insert into diaries values(59, "2011-09-11");
+insert into diaries values(60, "2011-09-12");
+insert into diaries values(61, "2011-09-13");
+insert into diaries values(62, "2011-09-14");
+insert into diaries values(63, "2011-09-15");
+insert into diaries values(64, "2011-09-16");
+insert into diaries values(65, "2011-09-17");
+insert into diaries values(66, "2011-09-18");
+insert into diaries values(67, "2011-09-19");
+insert into diaries values(68, "2011-09-20");
+insert into diaries values(69, "2011-09-21");
+insert into diaries values(70, "2011-09-22");
+insert into diaries values(71, "2011-09-23");
+insert into diaries values(72, "2011-09-24");
+insert into diaries values(73, "2011-09-25");
+insert into diaries values(74, "2011-09-26");
+insert into diaries values(75, "2011-09-27");
+insert into diaries values(76, "2011-09-28");
+insert into diaries values(77, "2011-09-29");
+insert into diaries values(78, "2011-09-30");
+insert into diaries values(79, "2011-10-01");
+insert into diaries values(80, "2011-10-02");
+insert into diaries values(81, "2011-10-03");
+insert into diaries values(82, "2011-10-04");
+insert into diaries values(83, "2011-10-05");
+insert into diaries values(84, "2011-10-06");
+insert into diaries values(85, "2011-10-07");
+insert into diaries values(86, "2011-10-08");
+insert into diaries values(87, "2011-10-09");
+insert into diaries values(88, "2011-10-10");
+insert into diaries values(89, "2011-10-11");
+insert into diaries values(90, "2011-10-12");
+insert into diaries values(91, "2011-10-13");
+insert into diaries values(92, "2011-10-14");
+insert into diaries values(93, "2011-10-15");
+insert into diaries values(94, "2011-10-16");
+insert into diaries values(95, "2011-10-17");
+insert into diaries values(96, "2011-10-18");
+insert into diaries values(97, "2011-10-19");
+insert into diaries values(98, "2011-10-20");
+insert into diaries values(99, "2011-10-21");
+insert into diaries values(100, "2011-10-22");
+insert into diaries values(101, "2011-10-23");
+insert into diaries values(102, "2011-10-24");
+insert into diaries values(103, "2011-10-25");
+insert into diaries values(104, "2011-10-26");
+insert into diaries values(105, "2011-10-27");
+insert into diaries values(106, "2011-10-28");
+insert into diaries values(107, "2011-10-29");
+insert into diaries values(108, "2011-10-30");
+insert into diaries values(109, "2011-10-31");
+insert into diaries values(110, "2011-11-01");
+insert into diaries values(111, "2011-11-02");
+insert into diaries values(112, "2011-11-03");
+insert into diaries values(113, "2011-11-04");
+insert into diaries values(114, "2011-11-05");
+insert into diaries values(115, "2011-11-06");
+insert into diaries values(116, "2011-11-07");
+insert into diaries values(117, "2011-11-08");
+insert into diaries values(118, "2011-11-09");
+insert into diaries values(119, "2011-11-10");
+insert into diaries values(120, "2011-11-11");
+insert into diaries values(121, "2011-11-12");
+insert into diaries values(122, "2011-11-13");
+insert into diaries values(123, "2011-11-14");
+insert into diaries values(124, "2011-11-15");
+insert into diaries values(125, "2011-11-16");
+insert into diaries values(126, "2011-11-17");
+insert into diaries values(127, "2011-11-18");
+insert into diaries values(128, "2011-11-19");
+insert into diaries values(129, "2011-11-20");
+insert into diaries values(130, "2011-11-21");
+insert into diaries values(131, "2011-11-22");
+insert into diaries values(132, "2011-11-23");
+insert into diaries values(133, "2011-11-24");
+insert into diaries values(134, "2011-11-25");
+insert into diaries values(135, "2011-11-26");
+insert into diaries values(136, "2011-11-27");
+insert into diaries values(137, "2011-11-28");
+insert into diaries values(138, "2011-11-29");
+insert into diaries values(139, "2011-11-30");
+insert into diaries values(140, "2011-12-01");
+insert into diaries values(141, "2011-12-02");
+insert into diaries values(142, "2011-12-03");
+insert into diaries values(143, "2011-12-04");
+insert into diaries values(144, "2011-12-05");
+insert into diaries values(145, "2011-12-06");
+insert into diaries values(146, "2011-12-07");
+insert into diaries values(147, "2011-12-08");
+insert into diaries values(148, "2011-12-09");
+insert into diaries values(149, "2011-12-10");
+insert into diaries values(150, "2011-12-11");
+insert into diaries values(151, "2011-12-12");
+insert into diaries values(152, "2011-12-13");
+insert into diaries values(153, "2011-12-14");
+insert into diaries values(154, "2011-12-15");
+insert into diaries values(155, "2011-12-16");
+insert into diaries values(156, "2011-12-17");
+insert into diaries values(157, "2011-12-18");
+insert into diaries values(158, "2011-12-19");
+insert into diaries values(159, "2011-12-20");
+insert into diaries values(160, "2011-12-21");
+insert into diaries values(161, "2011-12-22");
+insert into diaries values(162, "2011-12-23");
+insert into diaries values(163, "2011-12-24");
+insert into diaries values(164, "2011-12-25");
+insert into diaries values(165, "2011-12-26");
+insert into diaries values(166, "2011-12-27");
+insert into diaries values(167, "2011-12-28");
+insert into diaries values(168, "2011-12-29");
+insert into diaries values(169, "2011-12-30");
+insert into diaries values(170, "2011-12-31");
+insert into diaries values(171, "2012-01-01");
+insert into diaries values(172, "2012-01-02");
+insert into diaries values(173, "2012-01-03");
+insert into diaries values(174, "2012-01-04");
+insert into diaries values(175, "2012-01-05");
+insert into diaries values(176, "2012-01-06");
+insert into diaries values(177, "2012-01-07");
+insert into diaries values(178, "2012-01-08");
+insert into diaries values(179, "2012-01-09");
+insert into diaries values(180, "2012-01-10");
+insert into diaries values(181, "2012-01-11");
+insert into diaries values(182, "2012-01-12");
+insert into diaries values(183, "2012-01-13");
+insert into diaries values(184, "2012-01-14");
+insert into diaries values(185, "2012-01-15");
+insert into diaries values(186, "2012-01-16");
+insert into diaries values(187, "2012-01-17");
+insert into diaries values(188, "2012-01-18");
+insert into diaries values(189, "2012-01-19");
+insert into diaries values(190, "2012-01-20");
+insert into diaries values(191, "2012-01-21");
+insert into diaries values(192, "2012-01-22");
+insert into diaries values(193, "2012-01-23");
+insert into diaries values(194, "2012-01-24");
+insert into diaries values(195, "2012-01-25");
+insert into diaries values(196, "2012-01-26");
+insert into diaries values(197, "2012-01-27");
+insert into diaries values(198, "2012-01-28");
+insert into diaries values(199, "2012-01-29");
+insert into diaries values(200, "2012-01-30");
+insert into diaries values(201, "2012-01-31");
+insert into diaries values(202, "2012-02-01");
+insert into diaries values(203, "2012-02-02");
+insert into diaries values(204, "2012-02-03");
+insert into diaries values(205, "2012-02-04");
+insert into diaries values(206, "2012-02-05");
+insert into diaries values(207, "2012-02-06");
+insert into diaries values(208, "2012-02-07");
+insert into diaries values(209, "2012-02-08");
+insert into diaries values(210, "2012-02-09");
+insert into diaries values(211, "2012-02-10");
+insert into diaries values(212, "2012-02-11");
+insert into diaries values(213, "2012-02-12");
+insert into diaries values(214, "2012-02-13");
+insert into diaries values(215, "2012-02-14");
+insert into diaries values(216, "2012-02-15");
+insert into diaries values(217, "2012-02-16");
+insert into diaries values(218, "2012-02-17");
+insert into diaries values(219, "2012-02-18");
+insert into diaries values(220, "2012-02-19");
+insert into diaries values(221, "2012-02-20");
+insert into diaries values(222, "2012-02-21");
+insert into diaries values(223, "2012-02-22");
+insert into diaries values(224, "2012-02-23");
+insert into diaries values(225, "2012-02-24");
+insert into diaries values(226, "2012-02-25");
+insert into diaries values(227, "2012-02-26");
+insert into diaries values(228, "2012-02-27");
+insert into diaries values(229, "2012-02-28");
+insert into diaries values(230, "2012-02-29");
+insert into diaries values(231, "2012-03-01");
+insert into diaries values(232, "2012-03-02");
+insert into diaries values(233, "2012-03-03");
+insert into diaries values(234, "2012-03-04");
+insert into diaries values(235, "2012-03-05");
+insert into diaries values(236, "2012-03-06");
+insert into diaries values(237, "2012-03-07");
+insert into diaries values(238, "2012-03-08");
+insert into diaries values(239, "2012-03-09");
+insert into diaries values(240, "2012-03-10");
+insert into diaries values(241, "2012-03-11");
+insert into diaries values(242, "2012-03-12");
+insert into diaries values(243, "2012-03-13");
+insert into diaries values(244, "2012-03-14");
+insert into diaries values(245, "2012-03-15");
+insert into diaries values(246, "2012-03-16");
+insert into diaries values(247, "2012-03-17");
+insert into diaries values(248, "2012-03-18");
+insert into diaries values(249, "2012-03-19");
+insert into diaries values(250, "2012-03-20");
+insert into diaries values(251, "2012-03-21");
+insert into diaries values(252, "2012-03-22");
+insert into diaries values(253, "2012-03-23");
+insert into diaries values(254, "2012-03-24");
+insert into diaries values(255, "2012-03-25");
+insert into diaries values(256, "2012-03-26");
+insert into diaries values(257, "2012-03-27");
+insert into diaries values(258, "2012-03-28");
+insert into diaries values(259, "2012-03-29");
+insert into diaries values(260, "2012-03-30");
+insert into diaries values(261, "2012-03-31");
+insert into diaries values(262, "2012-04-01");
+insert into diaries values(263, "2012-04-02");
+insert into diaries values(264, "2012-04-03");
+insert into diaries values(265, "2012-04-04");
+insert into diaries values(266, "2012-04-05");
+insert into diaries values(267, "2012-04-06");
+insert into diaries values(268, "2012-04-07");
+insert into diaries values(269, "2012-04-08");
+insert into diaries values(270, "2012-04-09");
+insert into diaries values(271, "2012-04-10");
+insert into diaries values(272, "2012-04-11");
+insert into diaries values(273, "2012-04-12");
+insert into diaries values(274, "2012-04-13");
+insert into diaries values(275, "2012-04-14");
+insert into diaries values(276, "2012-04-15");
+insert into diaries values(277, "2012-04-16");
+insert into diaries values(278, "2012-04-17");
+insert into diaries values(279, "2012-04-18");
+insert into diaries values(280, "2012-04-19");
+insert into diaries values(281, "2012-04-20");
+insert into diaries values(282, "2012-04-21");
+insert into diaries values(283, "2012-04-22");
+insert into diaries values(284, "2012-04-23");
+insert into diaries values(285, "2012-04-24");
+insert into diaries values(286, "2012-04-25");
+insert into diaries values(287, "2012-04-26");
+insert into diaries values(288, "2012-04-27");
+insert into diaries values(289, "2012-04-28");
+insert into diaries values(290, "2012-04-29");
+insert into diaries values(291, "2012-04-30");
+insert into diaries values(292, "2012-05-01");
+insert into diaries values(293, "2012-05-02");
+insert into diaries values(294, "2012-05-03");
+insert into diaries values(295, "2012-05-04");
+insert into diaries values(296, "2012-05-05");
+insert into diaries values(297, "2012-05-06");
+insert into diaries values(298, "2012-05-07");
+insert into diaries values(299, "2012-05-08");
+insert into diaries values(300, "2012-05-09");
+insert into diaries values(301, "2012-05-10");
+insert into diaries values(302, "2012-05-11");
+insert into diaries values(303, "2012-05-12");
+insert into diaries values(304, "2012-05-13");
+insert into diaries values(305, "2012-05-14");
+insert into diaries values(306, "2012-05-15");
+insert into diaries values(307, "2012-05-16");
+insert into diaries values(308, "2012-05-17");
+insert into diaries values(309, "2012-05-18");
+insert into diaries values(310, "2012-05-19");
+insert into diaries values(311, "2012-05-20");
+insert into diaries values(312, "2012-05-21");
+insert into diaries values(313, "2012-05-22");
+insert into diaries values(314, "2012-05-23");
+insert into diaries values(315, "2012-05-24");
+insert into diaries values(316, "2012-05-25");
+insert into diaries values(317, "2012-05-26");
+insert into diaries values(318, "2012-05-27");
+insert into diaries values(319, "2012-05-28");
+insert into diaries values(320, "2012-05-29");
+insert into diaries values(321, "2012-05-30");
+insert into diaries values(322, "2012-05-31");
+insert into diaries values(323, "2012-06-01");
+insert into diaries values(324, "2012-06-02");
+insert into diaries values(325, "2012-06-03");
+insert into diaries values(326, "2012-06-04");
+insert into diaries values(327, "2012-06-05");
+insert into diaries values(328, "2012-06-06");
+insert into diaries values(329, "2012-06-07");
+insert into diaries values(330, "2012-06-08");
+insert into diaries values(331, "2012-06-09");
+insert into diaries values(332, "2012-06-10");
+insert into diaries values(333, "2012-06-11");
+insert into diaries values(334, "2012-06-12");
+insert into diaries values(335, "2012-06-13");
+insert into diaries values(336, "2012-06-14");
+insert into diaries values(337, "2012-06-15");
+insert into diaries values(338, "2012-06-16");
+insert into diaries values(339, "2012-06-17");
+insert into diaries values(340, "2012-06-18");
+insert into diaries values(341, "2012-06-19");
+insert into diaries values(342, "2012-06-20");
+insert into diaries values(343, "2012-06-21");
+insert into diaries values(344, "2012-06-22");
+insert into diaries values(345, "2012-06-23");
+insert into diaries values(346, "2012-06-24");
+insert into diaries values(347, "2012-06-25");
+insert into diaries values(348, "2012-06-26");
+insert into diaries values(349, "2012-06-27");
+insert into diaries values(350, "2012-06-28");
+insert into diaries values(351, "2012-06-29");
+insert into diaries values(352, "2012-06-30");
+insert into diaries values(353, "2012-07-01");
+insert into diaries values(354, "2012-07-02");
+insert into diaries values(355, "2012-07-03");
+insert into diaries values(356, "2012-07-04");
+insert into diaries values(357, "2012-07-05");
+insert into diaries values(358, "2012-07-06");
+insert into diaries values(359, "2012-07-07");
+insert into diaries values(360, "2012-07-08");
+insert into diaries values(361, "2012-07-09");
+insert into diaries values(362, "2012-07-10");
+insert into diaries values(363, "2012-07-11");
+insert into diaries values(364, "2012-07-12");
+insert into diaries values(365, "2012-07-13");
+insert into diaries values(366, "2012-07-14");
+insert into diaries values(367, "2012-07-15");
+insert into diaries values(368, "2012-07-16");
+insert into diaries values(369, "2012-07-17");
+insert into diaries values(370, "2012-07-18");
+insert into diaries values(371, "2012-07-19");
+insert into diaries values(372, "2012-07-20");
+insert into diaries values(373, "2012-07-21");
+insert into diaries values(374, "2012-07-22");
+insert into diaries values(375, "2012-07-23");
+insert into diaries values(376, "2012-07-24");
+insert into diaries values(377, "2012-07-25");
+insert into diaries values(378, "2012-07-26");
+insert into diaries values(379, "2012-07-27");
+insert into diaries values(380, "2012-07-28");
+insert into diaries values(381, "2012-07-29");
+insert into diaries values(382, "2012-07-30");
+insert into diaries values(383, "2012-07-31");
+insert into diaries values(384, "2012-08-01");
+insert into diaries values(385, "2012-08-02");
+insert into diaries values(386, "2012-08-03");
+insert into diaries values(387, "2012-08-04");
+insert into diaries values(388, "2012-08-05");
+insert into diaries values(389, "2012-08-06");
+insert into diaries values(390, "2012-08-07");
+insert into diaries values(391, "2012-08-08");
+insert into diaries values(392, "2012-08-09");
+insert into diaries values(393, "2012-08-10");
+insert into diaries values(394, "2012-08-11");
+insert into diaries values(395, "2012-08-12");
+insert into diaries values(396, "2012-08-13");
+insert into diaries values(397, "2012-08-14");
+insert into diaries values(398, "2012-08-15");
+insert into diaries values(399, "2012-08-16");
+insert into diaries values(400, "2012-08-17");
+insert into diaries values(401, "2012-08-18");
+insert into diaries values(402, "2012-08-19");
+insert into diaries values(403, "2012-08-20");
+insert into diaries values(404, "2012-08-21");
+insert into diaries values(405, "2012-08-22");
+insert into diaries values(406, "2012-08-23");
+insert into diaries values(407, "2012-08-24");
+insert into diaries values(408, "2012-08-25");
+insert into diaries values(409, "2012-08-26");
+insert into diaries values(410, "2012-08-27");
+insert into diaries values(411, "2012-08-28");
+insert into diaries values(412, "2012-08-29");
+insert into diaries values(413, "2012-08-30");
+insert into diaries values(414, "2012-08-31");
+insert into diaries values(415, "2012-09-01");
+insert into diaries values(416, "2012-09-02");
+insert into diaries values(417, "2012-09-03");
+insert into diaries values(418, "2012-09-04");
+insert into diaries values(419, "2012-09-05");
+insert into diaries values(420, "2012-09-06");
+insert into diaries values(421, "2012-09-07");
+insert into diaries values(422, "2012-09-08");
+insert into diaries values(423, "2012-09-09");
+insert into diaries values(424, "2012-09-10");
+insert into diaries values(425, "2012-09-11");
+insert into diaries values(426, "2012-09-12");
+insert into diaries values(427, "2012-09-13");
+insert into diaries values(428, "2012-09-14");
+insert into diaries values(429, "2012-09-15");
+insert into diaries values(430, "2012-09-16");
+insert into diaries values(431, "2012-09-17");
+insert into diaries values(432, "2012-09-18");
+insert into diaries values(433, "2012-09-19");
+insert into diaries values(434, "2012-09-20");
+insert into diaries values(435, "2012-09-21");
+insert into diaries values(436, "2012-09-22");
+insert into diaries values(437, "2012-09-23");
+insert into diaries values(438, "2012-09-24");
+insert into diaries values(439, "2012-09-25");
+insert into diaries values(440, "2012-09-26");
+insert into diaries values(441, "2012-09-27");
+insert into diaries values(442, "2012-09-28");
+insert into diaries values(443, "2012-09-29");
+insert into diaries values(444, "2012-09-30");
+insert into diaries values(445, "2012-10-01");
+insert into diaries values(446, "2012-10-02");
+insert into diaries values(447, "2012-10-03");
+insert into diaries values(448, "2012-10-04");
+insert into diaries values(449, "2012-10-05");
+insert into diaries values(450, "2012-10-06");
+insert into diaries values(451, "2012-10-07");
+insert into diaries values(452, "2012-10-08");
+insert into diaries values(453, "2012-10-09");
+insert into diaries values(454, "2012-10-10");
+insert into diaries values(455, "2012-10-11");
+insert into diaries values(456, "2012-10-12");
+insert into diaries values(457, "2012-10-13");
+insert into diaries values(458, "2012-10-14");
+insert into diaries values(459, "2012-10-15");
+insert into diaries values(460, "2012-10-16");
+insert into diaries values(461, "2012-10-17");
+insert into diaries values(462, "2012-10-18");
+insert into diaries values(463, "2012-10-19");
+insert into diaries values(464, "2012-10-20");
+insert into diaries values(465, "2012-10-21");
+insert into diaries values(466, "2012-10-22");
+insert into diaries values(467, "2012-10-23");
+insert into diaries values(468, "2012-10-24");
+insert into diaries values(469, "2012-10-25");
+insert into diaries values(470, "2012-10-26");
+insert into diaries values(471, "2012-10-27");
+insert into diaries values(472, "2012-10-28");
+insert into diaries values(473, "2012-10-29");
+insert into diaries values(474, "2012-10-30");
+insert into diaries values(475, "2012-10-31");
+insert into diaries values(476, "2012-11-01");
+insert into diaries values(477, "2012-11-02");
+insert into diaries values(478, "2012-11-03");
+insert into diaries values(479, "2012-11-04");
+insert into diaries values(480, "2012-11-05");
+insert into diaries values(481, "2012-11-06");
+insert into diaries values(482, "2012-11-07");
+insert into diaries values(483, "2012-11-08");
+insert into diaries values(484, "2012-11-09");
+insert into diaries values(485, "2012-11-10");
+insert into diaries values(486, "2012-11-11");
+insert into diaries values(487, "2012-11-12");
+insert into diaries values(488, "2012-11-13");
+insert into diaries values(489, "2012-11-14");
+insert into diaries values(490, "2012-11-15");
+insert into diaries values(491, "2012-11-16");
+insert into diaries values(492, "2012-11-17");
+insert into diaries values(493, "2012-11-18");
+insert into diaries values(494, "2012-11-19");
+insert into diaries values(495, "2012-11-20");
+insert into diaries values(496, "2012-11-21");
+insert into diaries values(497, "2012-11-22");
+insert into diaries values(498, "2012-11-23");
+insert into diaries values(499, "2012-11-24");
+insert into diaries values(500, "2012-11-25");
+insert into diaries values(501, "2012-11-26");
+insert into diaries values(502, "2012-11-27");
+insert into diaries values(503, "2012-11-28");
+insert into diaries values(504, "2012-11-29");
+insert into diaries values(505, "2012-11-30");
+insert into diaries values(506, "2012-12-01");
+insert into diaries values(507, "2012-12-02");
+insert into diaries values(508, "2012-12-03");
+insert into diaries values(509, "2012-12-04");
+insert into diaries values(510, "2012-12-05");
+insert into diaries values(511, "2012-12-06");
+insert into diaries values(512, "2012-12-07");
+insert into diaries values(513, "2012-12-08");
+insert into diaries values(514, "2012-12-09");
+insert into diaries values(515, "2012-12-10");
+insert into diaries values(516, "2012-12-11");
+insert into diaries values(517, "2012-12-12");
+insert into diaries values(518, "2012-12-13");
+insert into diaries values(519, "2012-12-14");
+insert into diaries values(520, "2012-12-15");
+insert into diaries values(521, "2012-12-16");
+insert into diaries values(522, "2012-12-17");
+insert into diaries values(523, "2012-12-18");
+insert into diaries values(524, "2012-12-19");
+insert into diaries values(525, "2012-12-20");
+insert into diaries values(526, "2012-12-21");
+insert into diaries values(527, "2012-12-22");
+insert into diaries values(528, "2012-12-23");
+insert into diaries values(529, "2012-12-24");
+insert into diaries values(530, "2012-12-25");
+insert into diaries values(531, "2012-12-26");
+insert into diaries values(532, "2012-12-27");
+insert into diaries values(533, "2012-12-28");
+insert into diaries values(534, "2012-12-29");
+insert into diaries values(535, "2012-12-30");
+insert into diaries values(536, "2012-12-31");
+insert into diaries values(537, "2013-01-01");
+insert into diaries values(538, "2013-01-02");
+insert into diaries values(539, "2013-01-03");
+insert into diaries values(540, "2013-01-04");
+insert into diaries values(541, "2013-01-05");
+insert into diaries values(542, "2013-01-06");
+insert into diaries values(543, "2013-01-07");
+insert into diaries values(544, "2013-01-08");
+insert into diaries values(545, "2013-01-09");
+insert into diaries values(546, "2013-01-10");
+insert into diaries values(547, "2013-01-11");
+insert into diaries values(548, "2013-01-12");
+insert into diaries values(549, "2013-01-13");
+insert into diaries values(550, "2013-01-14");
+insert into diaries values(551, "2013-01-15");
+insert into diaries values(552, "2013-01-16");
+insert into diaries values(553, "2013-01-17");
+insert into diaries values(554, "2013-01-18");
+insert into diaries values(555, "2013-01-19");
+insert into diaries values(556, "2013-01-20");
+insert into diaries values(557, "2013-01-21");
+insert into diaries values(558, "2013-01-22");
+insert into diaries values(559, "2013-01-23");
+insert into diaries values(560, "2013-01-24");
+insert into diaries values(561, "2013-01-25");
+insert into diaries values(562, "2013-01-26");
+insert into diaries values(563, "2013-01-27");
+insert into diaries values(564, "2013-01-28");
+insert into diaries values(565, "2013-01-29");
+insert into diaries values(566, "2013-01-30");
+insert into diaries values(567, "2013-01-31");
+insert into diaries values(568, "2013-02-01");
+insert into diaries values(569, "2013-02-02");
+insert into diaries values(570, "2013-02-03");
+insert into diaries values(571, "2013-02-04");
+insert into diaries values(572, "2013-02-05");
+insert into diaries values(573, "2013-02-06");
+insert into diaries values(574, "2013-02-07");
+insert into diaries values(575, "2013-02-08");
+insert into diaries values(576, "2013-02-09");
+insert into diaries values(577, "2013-02-10");
+insert into diaries values(578, "2013-02-11");
+insert into diaries values(579, "2013-02-12");
+insert into diaries values(580, "2013-02-13");
+insert into diaries values(581, "2013-02-14");
+insert into diaries values(582, "2013-02-15");
+insert into diaries values(583, "2013-02-16");
+insert into diaries values(584, "2013-02-17");
+insert into diaries values(585, "2013-02-18");
+insert into diaries values(586, "2013-02-19");
+insert into diaries values(587, "2013-02-20");
+insert into diaries values(588, "2013-02-21");
+insert into diaries values(589, "2013-02-22");
+insert into diaries values(590, "2013-02-23");
+insert into diaries values(591, "2013-02-24");
+insert into diaries values(592, "2013-02-25");
+insert into diaries values(593, "2013-02-26");
+insert into diaries values(594, "2013-02-27");
+insert into diaries values(595, "2013-02-28");
+insert into diaries values(596, "2013-03-01");
+insert into diaries values(597, "2013-03-02");
+insert into diaries values(598, "2013-03-03");
+insert into diaries values(599, "2013-03-04");
+insert into diaries values(600, "2013-03-05");
+insert into diaries values(601, "2013-03-06");
+insert into diaries values(602, "2013-03-07");
+insert into diaries values(603, "2013-03-08");
+insert into diaries values(604, "2013-03-09");
+insert into diaries values(605, "2013-03-10");
+insert into diaries values(606, "2013-03-11");
+insert into diaries values(607, "2013-03-12");
+insert into diaries values(608, "2013-03-13");
+insert into diaries values(609, "2013-03-14");
+insert into diaries values(610, "2013-03-15");
+insert into diaries values(611, "2013-03-16");
+insert into diaries values(612, "2013-03-17");
+insert into diaries values(613, "2013-03-18");
+insert into diaries values(614, "2013-03-19");
+insert into diaries values(615, "2013-03-20");
+insert into diaries values(616, "2013-03-21");
+insert into diaries values(617, "2013-03-22");
+insert into diaries values(618, "2013-03-23");
+insert into diaries values(619, "2013-03-24");
+insert into diaries values(620, "2013-03-25");
+insert into diaries values(621, "2013-03-26");
+insert into diaries values(622, "2013-03-27");
+insert into diaries values(623, "2013-03-28");
+insert into diaries values(624, "2013-03-29");
+insert into diaries values(625, "2013-03-30");
+insert into diaries values(626, "2013-03-31");
+insert into diaries values(627, "2013-04-01");
+insert into diaries values(628, "2013-04-02");
+insert into diaries values(629, "2013-04-03");
+insert into diaries values(630, "2013-04-04");
+insert into diaries values(631, "2013-04-05");
+insert into diaries values(632, "2013-04-06");
+insert into diaries values(633, "2013-04-07");
+insert into diaries values(634, "2013-04-08");
+insert into diaries values(635, "2013-04-09");
+insert into diaries values(636, "2013-04-10");
+insert into diaries values(637, "2013-04-11");
+insert into diaries values(638, "2013-04-12");
+insert into diaries values(639, "2013-04-13");
+insert into diaries values(640, "2013-04-14");
+insert into diaries values(641, "2013-04-15");
+insert into diaries values(642, "2013-04-16");
+insert into diaries values(643, "2013-04-17");
+insert into diaries values(644, "2013-04-18");
+insert into diaries values(645, "2013-04-19");
+insert into diaries values(646, "2013-04-20");
+insert into diaries values(647, "2013-04-21");
+insert into diaries values(648, "2013-04-22");
+insert into diaries values(649, "2013-04-23");
+insert into diaries values(650, "2013-04-24");
+insert into diaries values(651, "2013-04-25");
+insert into diaries values(652, "2013-04-26");
+insert into diaries values(653, "2013-04-27");
+insert into diaries values(654, "2013-04-28");
+insert into diaries values(655, "2013-04-29");
+insert into diaries values(656, "2013-04-30");
+insert into diaries values(657, "2013-05-01");
+insert into diaries values(658, "2013-05-02");
+insert into diaries values(659, "2013-05-03");
+insert into diaries values(660, "2013-05-04");
+insert into diaries values(661, "2013-05-05");
+insert into diaries values(662, "2013-05-06");
+insert into diaries values(663, "2013-05-07");
+insert into diaries values(664, "2013-05-08");
+insert into diaries values(665, "2013-05-09");
+insert into diaries values(666, "2013-05-10");
+insert into diaries values(667, "2013-05-11");
+insert into diaries values(668, "2013-05-12");
+insert into diaries values(669, "2013-05-13");
+insert into diaries values(670, "2013-05-14");
+insert into diaries values(671, "2013-05-15");
+insert into diaries values(672, "2013-05-16");
+insert into diaries values(673, "2013-05-17");
+insert into diaries values(674, "2013-05-18");
+insert into diaries values(675, "2013-05-19");
+insert into diaries values(676, "2013-05-20");
+insert into diaries values(677, "2013-05-21");
+insert into diaries values(678, "2013-05-22");
+insert into diaries values(679, "2013-05-23");
+insert into diaries values(680, "2013-05-24");
+insert into diaries values(681, "2013-05-25");
+insert into diaries values(682, "2013-05-26");
+insert into diaries values(683, "2013-05-27");
+insert into diaries values(684, "2013-05-28");
+insert into diaries values(685, "2013-05-29");
+insert into diaries values(686, "2013-05-30");
+insert into diaries values(687, "2013-05-31");
+insert into diaries values(688, "2013-06-01");
+insert into diaries values(689, "2013-06-02");
+insert into diaries values(690, "2013-06-03");
+insert into diaries values(691, "2013-06-04");
+insert into diaries values(692, "2013-06-05");
+insert into diaries values(693, "2013-06-06");
+insert into diaries values(694, "2013-06-07");
+insert into diaries values(695, "2013-06-08");
+insert into diaries values(696, "2013-06-09");
+insert into diaries values(697, "2013-06-10");
+insert into diaries values(698, "2013-06-11");
+insert into diaries values(699, "2013-06-12");
+insert into diaries values(700, "2013-06-13");
+insert into diaries values(701, "2013-06-14");
+insert into diaries values(702, "2013-06-15");
+insert into diaries values(703, "2013-06-16");
+insert into diaries values(704, "2013-06-17");
+insert into diaries values(705, "2013-06-18");
+insert into diaries values(706, "2013-06-19");
+insert into diaries values(707, "2013-06-20");
+insert into diaries values(708, "2013-06-21");
+insert into diaries values(709, "2013-06-22");
+insert into diaries values(710, "2013-06-23");
+insert into diaries values(711, "2013-06-24");
+insert into diaries values(712, "2013-06-25");
+insert into diaries values(713, "2013-06-26");
+insert into diaries values(714, "2013-06-27");
+insert into diaries values(715, "2013-06-28");
+insert into diaries values(716, "2013-06-29");
+insert into diaries values(717, "2013-06-30");
+insert into diaries values(718, "2013-07-01");
+insert into diaries values(719, "2013-07-02");
+insert into diaries values(720, "2013-07-03");
+insert into diaries values(721, "2013-07-04");
+insert into diaries values(722, "2013-07-05");
+insert into diaries values(723, "2013-07-06");
+insert into diaries values(724, "2013-07-07");
+insert into diaries values(725, "2013-07-08");
+insert into diaries values(726, "2013-07-09");
+insert into diaries values(727, "2013-07-10");
+insert into diaries values(728, "2013-07-11");
+insert into diaries values(729, "2013-07-12");
+insert into diaries values(730, "2013-07-13");
+insert into diaries values(731, "2013-07-14");
+insert into diaries values(732, "2013-07-15");
+insert into diaries values(733, "2013-07-16");
+insert into diaries values(734, "2013-07-17");
+insert into diaries values(735, "2013-07-18");
+insert into diaries values(736, "2013-07-19");
+insert into diaries values(737, "2013-07-20");
+insert into diaries values(738, "2013-07-21");
+insert into diaries values(739, "2013-07-22");
+insert into diaries values(740, "2013-07-23");
+insert into diaries values(741, "2013-07-24");
+insert into diaries values(742, "2013-07-25");
+insert into diaries values(743, "2013-07-26");
+insert into diaries values(744, "2013-07-27");
+insert into diaries values(745, "2013-07-28");
+insert into diaries values(746, "2013-07-29");
+insert into diaries values(747, "2013-07-30");
+insert into diaries values(748, "2013-07-31");
+insert into diaries values(749, "2013-08-01");
+insert into diaries values(750, "2013-08-02");
+insert into diaries values(751, "2013-08-03");
+insert into diaries values(752, "2013-08-04");
+insert into diaries values(753, "2013-08-05");
+insert into diaries values(754, "2013-08-06");
+insert into diaries values(755, "2013-08-07");
+insert into diaries values(756, "2013-08-08");
+insert into diaries values(757, "2013-08-09");
+insert into diaries values(758, "2013-08-10");
+insert into diaries values(759, "2013-08-11");
+insert into diaries values(760, "2013-08-12");
+insert into diaries values(761, "2013-08-13");
+insert into diaries values(762, "2013-08-14");
+insert into diaries values(763, "2013-08-15");
+insert into diaries values(764, "2013-08-16");
+insert into diaries values(765, "2013-08-17");
+insert into diaries values(766, "2013-08-18");
+insert into diaries values(767, "2013-08-19");
+insert into diaries values(768, "2013-08-20");
+insert into diaries values(769, "2013-08-21");
+insert into diaries values(770, "2013-08-22");
+insert into diaries values(771, "2013-08-23");
+insert into diaries values(772, "2013-08-24");
+insert into diaries values(773, "2013-08-25");
+insert into diaries values(774, "2013-08-26");
+insert into diaries values(775, "2013-08-27");
+insert into diaries values(776, "2013-08-28");
+insert into diaries values(777, "2013-08-29");
+insert into diaries values(778, "2013-08-30");
+insert into diaries values(779, "2013-08-31");
+insert into diaries values(780, "2013-09-01");
+insert into diaries values(781, "2013-09-02");
+insert into diaries values(782, "2013-09-03");
+insert into diaries values(783, "2013-09-04");
+insert into diaries values(784, "2013-09-05");
+insert into diaries values(785, "2013-09-06");
+insert into diaries values(786, "2013-09-07");
+insert into diaries values(787, "2013-09-08");
+insert into diaries values(788, "2013-09-09");
+insert into diaries values(789, "2013-09-10");
+insert into diaries values(790, "2013-09-11");
+insert into diaries values(791, "2013-09-12");
+insert into diaries values(792, "2013-09-13");
+insert into diaries values(793, "2013-09-14");
+insert into diaries values(794, "2013-09-15");
+insert into diaries values(795, "2013-09-16");
+insert into diaries values(796, "2013-09-17");
+insert into diaries values(797, "2013-09-18");
+insert into diaries values(798, "2013-09-19");
+insert into diaries values(799, "2013-09-20");
+insert into diaries values(800, "2013-09-21");
+insert into diaries values(801, "2013-09-22");
+insert into diaries values(802, "2013-09-23");
+insert into diaries values(803, "2013-09-24");
+insert into diaries values(804, "2013-09-25");
+insert into diaries values(805, "2013-09-26");
+insert into diaries values(806, "2013-09-27");
+insert into diaries values(807, "2013-09-28");
+insert into diaries values(808, "2013-09-29");
+insert into diaries values(809, "2013-09-30");
+insert into diaries values(810, "2013-10-01");
+insert into diaries values(811, "2013-10-02");
+insert into diaries values(812, "2013-10-03");
+insert into diaries values(813, "2013-10-04");
+insert into diaries values(814, "2013-10-05");
+insert into diaries values(815, "2013-10-06");
+insert into diaries values(816, "2013-10-07");
+insert into diaries values(817, "2013-10-08");
+insert into diaries values(818, "2013-10-09");
+insert into diaries values(819, "2013-10-10");
+insert into diaries values(820, "2013-10-11");
+insert into diaries values(821, "2013-10-12");
+insert into diaries values(822, "2013-10-13");
+insert into diaries values(823, "2013-10-14");
+insert into diaries values(824, "2013-10-15");
+insert into diaries values(825, "2013-10-16");
+insert into diaries values(826, "2013-10-17");
+insert into diaries values(827, "2013-10-18");
+insert into diaries values(828, "2013-10-19");
+insert into diaries values(829, "2013-10-20");
+insert into diaries values(830, "2013-10-21");
+insert into diaries values(831, "2013-10-22");
+insert into diaries values(832, "2013-10-23");
+insert into diaries values(833, "2013-10-24");
+insert into diaries values(834, "2013-10-25");
+insert into diaries values(835, "2013-10-26");
+insert into diaries values(836, "2013-10-27");
+insert into diaries values(837, "2013-10-28");
+insert into diaries values(838, "2013-10-29");
+insert into diaries values(839, "2013-10-30");
+insert into diaries values(840, "2013-10-31");
+insert into diaries values(841, "2013-11-01");
+insert into diaries values(842, "2013-11-02");
+insert into diaries values(843, "2013-11-03");
+insert into diaries values(844, "2013-11-04");
+insert into diaries values(845, "2013-11-05");
+insert into diaries values(846, "2013-11-06");
+insert into diaries values(847, "2013-11-07");
+insert into diaries values(848, "2013-11-08");
+insert into diaries values(849, "2013-11-09");
+insert into diaries values(850, "2013-11-10");
+insert into diaries values(851, "2013-11-11");
+insert into diaries values(852, "2013-11-12");
+insert into diaries values(853, "2013-11-13");
+insert into diaries values(854, "2013-11-14");
+insert into diaries values(855, "2013-11-15");
+insert into diaries values(856, "2013-11-16");
+insert into diaries values(857, "2013-11-17");
+insert into diaries values(858, "2013-11-18");
+insert into diaries values(859, "2013-11-19");
+insert into diaries values(860, "2013-11-20");
+insert into diaries values(861, "2013-11-21");
+insert into diaries values(862, "2013-11-22");
+insert into diaries values(863, "2013-11-23");
+insert into diaries values(864, "2013-11-24");
+insert into diaries values(865, "2013-11-25");
+insert into diaries values(866, "2013-11-26");
+insert into diaries values(867, "2013-11-27");
+insert into diaries values(868, "2013-11-28");
+insert into diaries values(869, "2013-11-29");
+insert into diaries values(870, "2013-11-30");
+insert into diaries values(871, "2013-12-01");
+insert into diaries values(872, "2013-12-02");
+insert into diaries values(873, "2013-12-03");
+insert into diaries values(874, "2013-12-04");
+insert into diaries values(875, "2013-12-05");
+insert into diaries values(876, "2013-12-06");
+insert into diaries values(877, "2013-12-07");
+insert into diaries values(878, "2013-12-08");
+insert into diaries values(879, "2013-12-09");
+insert into diaries values(880, "2013-12-10");
+insert into diaries values(881, "2013-12-11");
+insert into diaries values(882, "2013-12-12");
+insert into diaries values(883, "2013-12-13");
+insert into diaries values(884, "2013-12-14");
+insert into diaries values(885, "2013-12-15");
+insert into diaries values(886, "2013-12-16");
+insert into diaries values(887, "2013-12-17");
+insert into diaries values(888, "2013-12-18");
+insert into diaries values(889, "2013-12-19");
+insert into diaries values(890, "2013-12-20");
+insert into diaries values(891, "2013-12-21");
+insert into diaries values(892, "2013-12-22");
+insert into diaries values(893, "2013-12-23");
+insert into diaries values(894, "2013-12-24");
+insert into diaries values(895, "2013-12-25");
+insert into diaries values(896, "2013-12-26");
+insert into diaries values(897, "2013-12-27");
+insert into diaries values(898, "2013-12-28");
+insert into diaries values(899, "2013-12-29");
+insert into diaries values(900, "2013-12-30");
+insert into diaries values(901, "2013-12-31");
+insert into diaries values(902, "2014-01-01");
+insert into diaries values(903, "2014-01-02");
+insert into diaries values(904, "2014-01-03");
+insert into diaries values(905, "2014-01-04");
+insert into diaries values(906, "2014-01-05");
+insert into diaries values(907, "2014-01-06");
+insert into diaries values(908, "2014-01-07");
+insert into diaries values(909, "2014-01-08");
+insert into diaries values(910, "2014-01-09");
+insert into diaries values(911, "2014-01-10");
+insert into diaries values(912, "2014-01-11");
+insert into diaries values(913, "2014-01-12");
+insert into diaries values(914, "2014-01-13");
+insert into diaries values(915, "2014-01-14");
+insert into diaries values(916, "2014-01-15");
+insert into diaries values(917, "2014-01-16");
+insert into diaries values(918, "2014-01-17");
+insert into diaries values(919, "2014-01-18");
+insert into diaries values(920, "2014-01-19");
+insert into diaries values(921, "2014-01-20");
+insert into diaries values(922, "2014-01-21");
+insert into diaries values(923, "2014-01-22");
+insert into diaries values(924, "2014-01-23");
+insert into diaries values(925, "2014-01-24");
+insert into diaries values(926, "2014-01-25");
+insert into diaries values(927, "2014-01-26");
+insert into diaries values(928, "2014-01-27");
+insert into diaries values(929, "2014-01-28");
+insert into diaries values(930, "2014-01-29");
+insert into diaries values(931, "2014-01-30");
+insert into diaries values(932, "2014-01-31");
+insert into diaries values(933, "2014-02-01");
+insert into diaries values(934, "2014-02-02");
+insert into diaries values(935, "2014-02-03");
+insert into diaries values(936, "2014-02-04");
+insert into diaries values(937, "2014-02-05");
+insert into diaries values(938, "2014-02-06");
+insert into diaries values(939, "2014-02-07");
+insert into diaries values(940, "2014-02-08");
+insert into diaries values(941, "2014-02-09");
+insert into diaries values(942, "2014-02-10");
+insert into diaries values(943, "2014-02-11");
+insert into diaries values(944, "2014-02-12");
+insert into diaries values(945, "2014-02-13");
+insert into diaries values(946, "2014-02-14");
+insert into diaries values(947, "2014-02-15");
+insert into diaries values(948, "2014-02-16");
+insert into diaries values(949, "2014-02-17");
+insert into diaries values(950, "2014-02-18");
+insert into diaries values(951, "2014-02-19");
+insert into diaries values(952, "2014-02-20");
+insert into diaries values(953, "2014-02-21");
+insert into diaries values(954, "2014-02-22");
+insert into diaries values(955, "2014-02-23");
+insert into diaries values(956, "2014-02-24");
+insert into diaries values(957, "2014-02-25");
+insert into diaries values(958, "2014-02-26");
+insert into diaries values(959, "2014-02-27");
+insert into diaries values(960, "2014-02-28");
+insert into diaries values(961, "2014-03-01");
+insert into diaries values(962, "2014-03-02");
+insert into diaries values(963, "2014-03-03");
+insert into diaries values(964, "2014-03-04");
+insert into diaries values(965, "2014-03-05");
+insert into diaries values(966, "2014-03-06");
+insert into diaries values(967, "2014-03-07");
+insert into diaries values(968, "2014-03-08");
+insert into diaries values(969, "2014-03-09");
+insert into diaries values(970, "2014-03-10");
+insert into diaries values(971, "2014-03-11");
+insert into diaries values(972, "2014-03-12");
+insert into diaries values(973, "2014-03-13");
+insert into diaries values(974, "2014-03-14");
+insert into diaries values(975, "2014-03-15");
+insert into diaries values(976, "2014-03-16");
+insert into diaries values(977, "2014-03-17");
+insert into diaries values(978, "2014-03-18");
+insert into diaries values(979, "2014-03-19");
+insert into diaries values(980, "2014-03-20");
+insert into diaries values(981, "2014-03-21");
+insert into diaries values(982, "2014-03-22");
+insert into diaries values(983, "2014-03-23");
+insert into diaries values(984, "2014-03-24");
+insert into diaries values(985, "2014-03-25");
+insert into diaries values(986, "2014-03-26");
+insert into diaries values(987, "2014-03-27");
+insert into diaries values(988, "2014-03-28");
+insert into diaries values(989, "2014-03-29");
+insert into diaries values(990, "2014-03-30");
+insert into diaries values(991, "2014-03-31");
+insert into diaries values(992, "2014-04-01");
+insert into diaries values(993, "2014-04-02");
+insert into diaries values(994, "2014-04-03");
+insert into diaries values(995, "2014-04-04");
+insert into diaries values(996, "2014-04-05");
+insert into diaries values(997, "2014-04-06");
+insert into diaries values(998, "2014-04-07");
+insert into diaries values(999, "2014-04-08");
+insert into diaries values(1000, "2014-04-09");
+insert into diaries values(1001, "2014-04-10");
+insert into diaries values(1002, "2014-04-11");
+insert into diaries values(1003, "2014-04-12");
+insert into diaries values(1004, "2014-04-13");
+insert into diaries values(1005, "2014-04-14");
+insert into diaries values(1006, "2014-04-15");
+insert into diaries values(1007, "2014-04-16");
+insert into diaries values(1008, "2014-04-17");
+insert into diaries values(1009, "2014-04-18");
+insert into diaries values(1010, "2014-04-19");
+insert into diaries values(1011, "2014-04-20");
+insert into diaries values(1012, "2014-04-21");
+insert into diaries values(1013, "2014-04-22");
+insert into diaries values(1014, "2014-04-23");
+insert into diaries values(1015, "2014-04-24");
+insert into diaries values(1016, "2014-04-25");
+insert into diaries values(1017, "2014-04-26");
+insert into diaries values(1018, "2014-04-27");
+insert into diaries values(1019, "2014-04-28");
+insert into diaries values(1020, "2014-04-29");
+insert into diaries values(1021, "2014-04-30");
+insert into diaries values(1022, "2014-05-01");
+insert into diaries values(1023, "2014-05-02");
+insert into diaries values(1024, "2014-05-03");
+insert into diaries values(1025, "2014-05-04");
+insert into diaries values(1026, "2014-05-05");
+insert into diaries values(1027, "2014-05-06");
+insert into diaries values(1028, "2014-05-07");
+insert into diaries values(1029, "2014-05-08");
+insert into diaries values(1030, "2014-05-09");
+insert into diaries values(1031, "2014-05-10");
+insert into diaries values(1032, "2014-05-11");
+insert into diaries values(1033, "2014-05-12");
+insert into diaries values(1034, "2014-05-13");
+insert into diaries values(1035, "2014-05-14");
+insert into diaries values(1036, "2014-05-15");
+insert into diaries values(1037, "2014-05-16");
+insert into diaries values(1038, "2014-05-17");
+insert into diaries values(1039, "2014-05-18");
+insert into diaries values(1040, "2014-05-19");
+insert into diaries values(1041, "2014-05-20");
+insert into diaries values(1042, "2014-05-21");
+insert into diaries values(1043, "2014-05-22");
+insert into diaries values(1044, "2014-05-23");
+insert into diaries values(1045, "2014-05-24");
+insert into diaries values(1046, "2014-05-25");
+insert into diaries values(1047, "2014-05-26");
+insert into diaries values(1048, "2014-05-27");
+insert into diaries values(1049, "2014-05-28");
+insert into diaries values(1050, "2014-05-29");
+insert into diaries values(1051, "2014-05-30");
+insert into diaries values(1052, "2014-05-31");
+insert into diaries values(1053, "2014-06-01");
+insert into diaries values(1054, "2014-06-02");
+insert into diaries values(1055, "2014-06-03");
+insert into diaries values(1056, "2014-06-04");
+insert into diaries values(1057, "2014-06-05");
+insert into diaries values(1058, "2014-06-06");
+insert into diaries values(1059, "2014-06-07");
+insert into diaries values(1060, "2014-06-08");
+insert into diaries values(1061, "2014-06-09");
+insert into diaries values(1062, "2014-06-10");
+insert into diaries values(1063, "2014-06-11");
+insert into diaries values(1064, "2014-06-12");
+insert into diaries values(1065, "2014-06-13");
+insert into diaries values(1066, "2014-06-14");
+insert into diaries values(1067, "2014-06-15");
+insert into diaries values(1068, "2014-06-16");
+insert into diaries values(1069, "2014-06-17");
+insert into diaries values(1070, "2014-06-18");
+insert into diaries values(1071, "2014-06-19");
+insert into diaries values(1072, "2014-06-20");
+insert into diaries values(1073, "2014-06-21");
+insert into diaries values(1074, "2014-06-22");
+insert into diaries values(1075, "2014-06-23");
+insert into diaries values(1076, "2014-06-24");
+insert into diaries values(1077, "2014-06-25");
+insert into diaries values(1078, "2014-06-26");
+insert into diaries values(1079, "2014-06-27");
+insert into diaries values(1080, "2014-06-28");
+insert into diaries values(1081, "2014-06-29");
+insert into diaries values(1082, "2014-06-30");
+insert into diaries values(1083, "2014-07-01");
+insert into diaries values(1084, "2014-07-02");
+insert into diaries values(1085, "2014-07-03");
+insert into diaries values(1086, "2014-07-04");
+insert into diaries values(1087, "2014-07-05");
+insert into diaries values(1088, "2014-07-06");
+insert into diaries values(1089, "2014-07-07");
+insert into diaries values(1090, "2014-07-08");
+insert into diaries values(1091, "2014-07-09");
+insert into diaries values(1092, "2014-07-10");
+insert into diaries values(1093, "2014-07-11");
+insert into diaries values(1094, "2014-07-12");
+insert into diaries values(1095, "2014-07-13");
+insert into diaries values(1096, "2014-07-14");
+insert into diaries values(1097, "2014-07-15");
+insert into diaries values(1098, "2014-07-16");
+insert into diaries values(1099, "2014-07-17");
+insert into diaries values(1100, "2014-07-18");
+insert into diaries values(1101, "2014-07-19");
+insert into diaries values(1102, "2014-07-20");
+insert into diaries values(1103, "2014-07-21");
+insert into diaries values(1104, "2014-07-22");
+insert into diaries values(1105, "2014-07-23");
+insert into diaries values(1106, "2014-07-24");
+insert into diaries values(1107, "2014-07-25");
+insert into diaries values(1108, "2014-07-26");
+insert into diaries values(1109, "2014-07-27");
+insert into diaries values(1110, "2014-07-28");
+insert into diaries values(1111, "2014-07-29");
+insert into diaries values(1112, "2014-07-30");
+insert into diaries values(1113, "2014-07-31");
+insert into diaries values(1114, "2014-08-01");
+insert into diaries values(1115, "2014-08-02");
+insert into diaries values(1116, "2014-08-03");
+insert into diaries values(1117, "2014-08-04");
+insert into diaries values(1118, "2014-08-05");
+insert into diaries values(1119, "2014-08-06");
+insert into diaries values(1120, "2014-08-07");
+insert into diaries values(1121, "2014-08-08");
+insert into diaries values(1122, "2014-08-09");
+insert into diaries values(1123, "2014-08-10");
+insert into diaries values(1124, "2014-08-11");
+insert into diaries values(1125, "2014-08-12");
+insert into diaries values(1126, "2014-08-13");
+insert into diaries values(1127, "2014-08-14");
+insert into diaries values(1128, "2014-08-15");
+insert into diaries values(1129, "2014-08-16");
+insert into diaries values(1130, "2014-08-17");
+insert into diaries values(1131, "2014-08-18");
+insert into diaries values(1132, "2014-08-19");
+insert into diaries values(1133, "2014-08-20");
+insert into diaries values(1134, "2014-08-21");
+insert into diaries values(1135, "2014-08-22");
+insert into diaries values(1136, "2014-08-23");
+insert into diaries values(1137, "2014-08-24");
+insert into diaries values(1138, "2014-08-25");
+insert into diaries values(1139, "2014-08-26");
+insert into diaries values(1140, "2014-08-27");
+insert into diaries values(1141, "2014-08-28");
+insert into diaries values(1142, "2014-08-29");
+insert into diaries values(1143, "2014-08-30");
+insert into diaries values(1144, "2014-08-31");
+insert into diaries values(1145, "2014-09-01");
+insert into diaries values(1146, "2014-09-02");
+insert into diaries values(1147, "2014-09-03");
+insert into diaries values(1148, "2014-09-04");
+insert into diaries values(1149, "2014-09-05");
+insert into diaries values(1150, "2014-09-06");
+insert into diaries values(1151, "2014-09-07");
+insert into diaries values(1152, "2014-09-08");
+insert into diaries values(1153, "2014-09-09");
+insert into diaries values(1154, "2014-09-10");
+insert into diaries values(1155, "2014-09-11");
+insert into diaries values(1156, "2014-09-12");
+insert into diaries values(1157, "2014-09-13");
+insert into diaries values(1158, "2014-09-14");
+insert into diaries values(1159, "2014-09-15");
+insert into diaries values(1160, "2014-09-16");
+insert into diaries values(1161, "2014-09-17");
+insert into diaries values(1162, "2014-09-18");
+insert into diaries values(1163, "2014-09-19");
+insert into diaries values(1164, "2014-09-20");
+insert into diaries values(1165, "2014-09-21");
+insert into diaries values(1166, "2014-09-22");
+insert into diaries values(1167, "2014-09-23");
+insert into diaries values(1168, "2014-09-24");
+insert into diaries values(1169, "2014-09-25");
+insert into diaries values(1170, "2014-09-26");
+insert into diaries values(1171, "2014-09-27");
+insert into diaries values(1172, "2014-09-28");
+insert into diaries values(1173, "2014-09-29");
+insert into diaries values(1174, "2014-09-30");
+insert into diaries values(1175, "2014-10-01");
+insert into diaries values(1176, "2014-10-02");
+insert into diaries values(1177, "2014-10-03");
+insert into diaries values(1178, "2014-10-04");
+insert into diaries values(1179, "2014-10-05");
+insert into diaries values(1180, "2014-10-06");
+insert into diaries values(1181, "2014-10-07");
+insert into diaries values(1182, "2014-10-08");
+insert into diaries values(1183, "2014-10-09");
+insert into diaries values(1184, "2014-10-10");
+insert into diaries values(1185, "2014-10-11");
+insert into diaries values(1186, "2014-10-12");
+insert into diaries values(1187, "2014-10-13");
+insert into diaries values(1188, "2014-10-14");
+insert into diaries values(1189, "2014-10-15");
+insert into diaries values(1190, "2014-10-16");
+insert into diaries values(1191, "2014-10-17");
+insert into diaries values(1192, "2014-10-18");
+insert into diaries values(1193, "2014-10-19");
+insert into diaries values(1194, "2014-10-20");
+insert into diaries values(1195, "2014-10-21");
+insert into diaries values(1196, "2014-10-22");
+insert into diaries values(1197, "2014-10-23");
+insert into diaries values(1198, "2014-10-24");
+insert into diaries values(1199, "2014-10-25");
+insert into diaries values(1200, "2014-10-26");
+insert into diaries values(1201, "2014-10-27");
+insert into diaries values(1202, "2014-10-28");
+insert into diaries values(1203, "2014-10-29");
+insert into diaries values(1204, "2014-10-30");
+insert into diaries values(1205, "2014-10-31");
+insert into diaries values(1206, "2014-11-01");
+insert into diaries values(1207, "2014-11-02");
+insert into diaries values(1208, "2014-11-03");
+insert into diaries values(1209, "2014-11-04");
+insert into diaries values(1210, "2014-11-05");
+insert into diaries values(1211, "2014-11-06");
+insert into diaries values(1212, "2014-11-07");
+insert into diaries values(1213, "2014-11-08");
+insert into diaries values(1214, "2014-11-09");
+insert into diaries values(1215, "2014-11-10");
+insert into diaries values(1216, "2014-11-11");
+insert into diaries values(1217, "2014-11-12");
+insert into diaries values(1218, "2014-11-13");
+insert into diaries values(1219, "2014-11-14");
+insert into diaries values(1220, "2014-11-15");
+insert into diaries values(1221, "2014-11-16");
+insert into diaries values(1222, "2014-11-17");
+insert into diaries values(1223, "2014-11-18");
+insert into diaries values(1224, "2014-11-19");
+insert into diaries values(1225, "2014-11-20");
+insert into diaries values(1226, "2014-11-21");
+insert into diaries values(1227, "2014-11-22");
+insert into diaries values(1228, "2014-11-23");
+insert into diaries values(1229, "2014-11-24");
+insert into diaries values(1230, "2014-11-25");
+insert into diaries values(1231, "2014-11-26");
+insert into diaries values(1232, "2014-11-27");
+insert into diaries values(1233, "2014-11-28");
+insert into diaries values(1234, "2014-11-29");
+insert into diaries values(1235, "2014-11-30");
+insert into diaries values(1236, "2014-12-01");
+insert into diaries values(1237, "2014-12-02");
+insert into diaries values(1238, "2014-12-03");
+insert into diaries values(1239, "2014-12-04");
+insert into diaries values(1240, "2014-12-05");
+insert into diaries values(1241, "2014-12-06");
+insert into diaries values(1242, "2014-12-07");
+insert into diaries values(1243, "2014-12-08");
+insert into diaries values(1244, "2014-12-09");
+insert into diaries values(1245, "2014-12-10");
+insert into diaries values(1246, "2014-12-11");
+insert into diaries values(1247, "2014-12-12");
+insert into diaries values(1248, "2014-12-13");
+insert into diaries values(1249, "2014-12-14");
+insert into diaries values(1250, "2014-12-15");
+insert into diaries values(1251, "2014-12-16");
+insert into diaries values(1252, "2014-12-17");
+insert into diaries values(1253, "2014-12-18");
+insert into diaries values(1254, "2014-12-19");
+insert into diaries values(1255, "2014-12-20");
+insert into diaries values(1256, "2014-12-21");
+insert into diaries values(1257, "2014-12-22");
+insert into diaries values(1258, "2014-12-23");
+insert into diaries values(1259, "2014-12-24");
+insert into diaries values(1260, "2014-12-25");
+insert into diaries values(1261, "2014-12-26");
+insert into diaries values(1262, "2014-12-27");
+insert into diaries values(1263, "2014-12-28");
+insert into diaries values(1264, "2014-12-29");
+insert into diaries values(1265, "2014-12-30");
+insert into diaries values(1266, "2014-12-31");
+insert into diaries values(1267, "2015-01-01");
+insert into diaries values(1268, "2015-01-02");
+insert into diaries values(1269, "2015-01-03");
+insert into diaries values(1270, "2015-01-04");
+insert into diaries values(1271, "2015-01-05");
+insert into diaries values(1272, "2015-01-06");
+insert into diaries values(1273, "2015-01-07");
+insert into diaries values(1274, "2015-01-08");
+insert into diaries values(1275, "2015-01-09");
+insert into diaries values(1276, "2015-01-10");
+insert into diaries values(1277, "2015-01-11");
+insert into diaries values(1278, "2015-01-12");
+insert into diaries values(1279, "2015-01-13");
+insert into diaries values(1280, "2015-01-14");
+insert into diaries values(1281, "2015-01-15");
+insert into diaries values(1282, "2015-01-16");
+insert into diaries values(1283, "2015-01-17");
+insert into diaries values(1284, "2015-01-18");
+insert into diaries values(1285, "2015-01-19");
+insert into diaries values(1286, "2015-01-20");
+insert into diaries values(1287, "2015-01-21");
+insert into diaries values(1288, "2015-01-22");
+insert into diaries values(1289, "2015-01-23");
+insert into diaries values(1290, "2015-01-24");
+insert into diaries values(1291, "2015-01-25");
+insert into diaries values(1292, "2015-01-26");
+insert into diaries values(1293, "2015-01-27");
+insert into diaries values(1294, "2015-01-28");
+insert into diaries values(1295, "2015-01-29");
+insert into diaries values(1296, "2015-01-30");
+insert into diaries values(1297, "2015-01-31");
+insert into diaries values(1298, "2015-02-01");
+insert into diaries values(1299, "2015-02-02");
+insert into diaries values(1300, "2015-02-03");
+insert into diaries values(1301, "2015-02-04");
+insert into diaries values(1302, "2015-02-05");
+insert into diaries values(1303, "2015-02-06");
+insert into diaries values(1304, "2015-02-07");
+insert into diaries values(1305, "2015-02-08");
+insert into diaries values(1306, "2015-02-09");
+insert into diaries values(1307, "2015-02-10");
+insert into diaries values(1308, "2015-02-11");
+insert into diaries values(1309, "2015-02-12");
+insert into diaries values(1310, "2015-02-13");
+insert into diaries values(1311, "2015-02-14");
+insert into diaries values(1312, "2015-02-15");
+insert into diaries values(1313, "2015-02-16");
+insert into diaries values(1314, "2015-02-17");
+insert into diaries values(1315, "2015-02-18");
+insert into diaries values(1316, "2015-02-19");
+insert into diaries values(1317, "2015-02-20");
+insert into diaries values(1318, "2015-02-21");
+insert into diaries values(1319, "2015-02-22");
+insert into diaries values(1320, "2015-02-23");
+insert into diaries values(1321, "2015-02-24");
+insert into diaries values(1322, "2015-02-25");
+insert into diaries values(1323, "2015-02-26");
+insert into diaries values(1324, "2015-02-27");
+insert into diaries values(1325, "2015-02-28");
+insert into diaries values(1326, "2015-03-01");
+insert into diaries values(1327, "2015-03-02");
+insert into diaries values(1328, "2015-03-03");
+insert into diaries values(1329, "2015-03-04");
+insert into diaries values(1330, "2015-03-05");
+insert into diaries values(1331, "2015-03-06");
+insert into diaries values(1332, "2015-03-07");
+insert into diaries values(1333, "2015-03-08");
+insert into diaries values(1334, "2015-03-09");
+insert into diaries values(1335, "2015-03-10");
+insert into diaries values(1336, "2015-03-11");
+insert into diaries values(1337, "2015-03-12");
+insert into diaries values(1338, "2015-03-13");
+insert into diaries values(1339, "2015-03-14");
+insert into diaries values(1340, "2015-03-15");
+insert into diaries values(1341, "2015-03-16");
+insert into diaries values(1342, "2015-03-17");
+insert into diaries values(1343, "2015-03-18");
+insert into diaries values(1344, "2015-03-19");
+insert into diaries values(1345, "2015-03-20");
+insert into diaries values(1346, "2015-03-21");
+insert into diaries values(1347, "2015-03-22");
+insert into diaries values(1348, "2015-03-23");
+insert into diaries values(1349, "2015-03-24");
+insert into diaries values(1350, "2015-03-25");
+insert into diaries values(1351, "2015-03-26");
+insert into diaries values(1352, "2015-03-27");
+insert into diaries values(1353, "2015-03-28");
+insert into diaries values(1354, "2015-03-29");
+insert into diaries values(1355, "2015-03-30");
+insert into diaries values(1356, "2015-03-31");
+insert into diaries values(1357, "2015-04-01");
+insert into diaries values(1358, "2015-04-02");
+insert into diaries values(1359, "2015-04-03");
+insert into diaries values(1360, "2015-04-04");
+insert into diaries values(1361, "2015-04-05");
+insert into diaries values(1362, "2015-04-06");
+insert into diaries values(1363, "2015-04-07");
+insert into diaries values(1364, "2015-04-08");
+insert into diaries values(1365, "2015-04-09");
+insert into diaries values(1366, "2015-04-10");
+insert into diaries values(1367, "2015-04-11");
+insert into diaries values(1368, "2015-04-12");
+insert into diaries values(1369, "2015-04-13");
+insert into diaries values(1370, "2015-04-14");
+insert into diaries values(1371, "2015-04-15");
+insert into diaries values(1372, "2015-04-16");
+insert into diaries values(1373, "2015-04-17");
+insert into diaries values(1374, "2015-04-18");
+insert into diaries values(1375, "2015-04-19");
+insert into diaries values(1376, "2015-04-20");
+insert into diaries values(1377, "2015-04-21");
+insert into diaries values(1378, "2015-04-22");
+insert into diaries values(1379, "2015-04-23");
+insert into diaries values(1380, "2015-04-24");
+insert into diaries values(1381, "2015-04-25");
+insert into diaries values(1382, "2015-04-26");
+insert into diaries values(1383, "2015-04-27");
+insert into diaries values(1384, "2015-04-28");
+insert into diaries values(1385, "2015-04-29");
+insert into diaries values(1386, "2015-04-30");
+insert into diaries values(1387, "2015-05-01");
+insert into diaries values(1388, "2015-05-02");
+insert into diaries values(1389, "2015-05-03");
+insert into diaries values(1390, "2015-05-04");
+insert into diaries values(1391, "2015-05-05");
+insert into diaries values(1392, "2015-05-06");
+insert into diaries values(1393, "2015-05-07");
+insert into diaries values(1394, "2015-05-08");
+insert into diaries values(1395, "2015-05-09");
+insert into diaries values(1396, "2015-05-10");
+insert into diaries values(1397, "2015-05-11");
+insert into diaries values(1398, "2015-05-12");
+insert into diaries values(1399, "2015-05-13");
+insert into diaries values(1400, "2015-05-14");
+insert into diaries values(1401, "2015-05-15");
+insert into diaries values(1402, "2015-05-16");
+insert into diaries values(1403, "2015-05-17");
+insert into diaries values(1404, "2015-05-18");
+insert into diaries values(1405, "2015-05-19");
+insert into diaries values(1406, "2015-05-20");
+insert into diaries values(1407, "2015-05-21");
+insert into diaries values(1408, "2015-05-22");
+insert into diaries values(1409, "2015-05-23");
+insert into diaries values(1410, "2015-05-24");
+insert into diaries values(1411, "2015-05-25");
+insert into diaries values(1412, "2015-05-26");
+insert into diaries values(1413, "2015-05-27");
+insert into diaries values(1414, "2015-05-28");
+insert into diaries values(1415, "2015-05-29");
+insert into diaries values(1416, "2015-05-30");
+insert into diaries values(1417, "2015-05-31");
+insert into diaries values(1418, "2015-06-01");
+insert into diaries values(1419, "2015-06-02");
+insert into diaries values(1420, "2015-06-03");
+insert into diaries values(1421, "2015-06-04");
+insert into diaries values(1422, "2015-06-05");
+insert into diaries values(1423, "2015-06-06");
+insert into diaries values(1424, "2015-06-07");
+insert into diaries values(1425, "2015-06-08");
+insert into diaries values(1426, "2015-06-09");
+insert into diaries values(1427, "2015-06-10");
+insert into diaries values(1428, "2015-06-11");
+insert into diaries values(1429, "2015-06-12");
+insert into diaries values(1430, "2015-06-13");
+insert into diaries values(1431, "2015-06-14");
+insert into diaries values(1432, "2015-06-15");
+insert into diaries values(1433, "2015-06-16");
+insert into diaries values(1434, "2015-06-17");
+insert into diaries values(1435, "2015-06-18");
+insert into diaries values(1436, "2015-06-19");
+insert into diaries values(1437, "2015-06-20");
+insert into diaries values(1438, "2015-06-21");
+insert into diaries values(1439, "2015-06-22");
+insert into diaries values(1440, "2015-06-23");
+insert into diaries values(1441, "2015-06-24");
+insert into diaries values(1442, "2015-06-25");
+insert into diaries values(1443, "2015-06-26");
+insert into diaries values(1444, "2015-06-27");
+insert into diaries values(1445, "2015-06-28");
+insert into diaries values(1446, "2015-06-29");
+insert into diaries values(1447, "2015-06-30");
+insert into diaries values(1448, "2015-07-01");
+insert into diaries values(1449, "2015-07-02");
+insert into diaries values(1450, "2015-07-03");
+insert into diaries values(1451, "2015-07-04");
+insert into diaries values(1452, "2015-07-05");
+insert into diaries values(1453, "2015-07-06");
+insert into diaries values(1454, "2015-07-07");
+insert into diaries values(1455, "2015-07-08");
+insert into diaries values(1456, "2015-07-09");
+insert into diaries values(1457, "2015-07-10");
+insert into diaries values(1458, "2015-07-11");
+insert into diaries values(1459, "2015-07-12");
+insert into diaries values(1460, "2015-07-13");
+insert into diaries values(1461, "2015-07-14");
+insert into diaries values(1462, "2015-07-15");
+insert into diaries values(1463, "2015-07-16");
+insert into diaries values(1464, "2015-07-17");
+insert into diaries values(1465, "2015-07-18");
+insert into diaries values(1466, "2015-07-19");
+insert into diaries values(1467, "2015-07-20");
+insert into diaries values(1468, "2015-07-21");
+insert into diaries values(1469, "2015-07-22");
+insert into diaries values(1470, "2015-07-23");
+insert into diaries values(1471, "2015-07-24");
+insert into diaries values(1472, "2015-07-25");
+insert into diaries values(1473, "2015-07-26");
+insert into diaries values(1474, "2015-07-27");
+insert into diaries values(1475, "2015-07-28");
+insert into diaries values(1476, "2015-07-29");
+insert into diaries values(1477, "2015-07-30");
+insert into diaries values(1478, "2015-07-31");
+insert into diaries values(1479, "2015-08-01");
+insert into diaries values(1480, "2015-08-02");
+insert into diaries values(1481, "2015-08-03");
+insert into diaries values(1482, "2015-08-04");
+insert into diaries values(1483, "2015-08-05");
+insert into diaries values(1484, "2015-08-06");
+insert into diaries values(1485, "2015-08-07");
+insert into diaries values(1486, "2015-08-08");
+insert into diaries values(1487, "2015-08-09");
+insert into diaries values(1488, "2015-08-10");
+insert into diaries values(1489, "2015-08-11");
+insert into diaries values(1490, "2015-08-12");
+insert into diaries values(1491, "2015-08-13");
+insert into diaries values(1492, "2015-08-14");
+insert into diaries values(1493, "2015-08-15");
+insert into diaries values(1494, "2015-08-16");
+insert into diaries values(1495, "2015-08-17");
+insert into diaries values(1496, "2015-08-18");
+insert into diaries values(1497, "2015-08-19");
+insert into diaries values(1498, "2015-08-20");
+insert into diaries values(1499, "2015-08-21");
+insert into diaries values(1500, "2015-08-22");
+insert into diaries values(1501, "2015-08-23");
+insert into diaries values(1502, "2015-08-24");
+insert into diaries values(1503, "2015-08-25");
+insert into diaries values(1504, "2015-08-26");
+insert into diaries values(1505, "2015-08-27");
+insert into diaries values(1506, "2015-08-28");
+insert into diaries values(1507, "2015-08-29");
+insert into diaries values(1508, "2015-08-30");
+insert into diaries values(1509, "2015-08-31");
+insert into diaries values(1510, "2015-09-01");
+insert into diaries values(1511, "2015-09-02");
+insert into diaries values(1512, "2015-09-03");
+insert into diaries values(1513, "2015-09-04");
+insert into diaries values(1514, "2015-09-05");
+insert into diaries values(1515, "2015-09-06");
+insert into diaries values(1516, "2015-09-07");
+insert into diaries values(1517, "2015-09-08");
+insert into diaries values(1518, "2015-09-09");
+insert into diaries values(1519, "2015-09-10");
+insert into diaries values(1520, "2015-09-11");
+insert into diaries values(1521, "2015-09-12");
+insert into diaries values(1522, "2015-09-13");
+insert into diaries values(1523, "2015-09-14");
+insert into diaries values(1524, "2015-09-15");
+insert into diaries values(1525, "2015-09-16");
+insert into diaries values(1526, "2015-09-17");
+insert into diaries values(1527, "2015-09-18");
+insert into diaries values(1528, "2015-09-19");
+insert into diaries values(1529, "2015-09-20");
+insert into diaries values(1530, "2015-09-21");
+insert into diaries values(1531, "2015-09-22");
+insert into diaries values(1532, "2015-09-23");
+insert into diaries values(1533, "2015-09-24");
+insert into diaries values(1534, "2015-09-25");
+insert into diaries values(1535, "2015-09-26");
+insert into diaries values(1536, "2015-09-27");
+insert into diaries values(1537, "2015-09-28");
+insert into diaries values(1538, "2015-09-29");
+insert into diaries values(1539, "2015-09-30");
+insert into diaries values(1540, "2015-10-01");
+insert into diaries values(1541, "2015-10-02");
+insert into diaries values(1542, "2015-10-03");
+insert into diaries values(1543, "2015-10-04");
+insert into diaries values(1544, "2015-10-05");
+insert into diaries values(1545, "2015-10-06");
+insert into diaries values(1546, "2015-10-07");
+insert into diaries values(1547, "2015-10-08");
+insert into diaries values(1548, "2015-10-09");
+insert into diaries values(1549, "2015-10-10");
+insert into diaries values(1550, "2015-10-11");
+insert into diaries values(1551, "2015-10-12");
+insert into diaries values(1552, "2015-10-13");
+insert into diaries values(1553, "2015-10-14");
+insert into diaries values(1554, "2015-10-15");
+insert into diaries values(1555, "2015-10-16");
+insert into diaries values(1556, "2015-10-17");
+insert into diaries values(1557, "2015-10-18");
+insert into diaries values(1558, "2015-10-19");
+insert into diaries values(1559, "2015-10-20");
+insert into diaries values(1560, "2015-10-21");
+insert into diaries values(1561, "2015-10-22");
+insert into diaries values(1562, "2015-10-23");
+insert into diaries values(1563, "2015-10-24");
+insert into diaries values(1564, "2015-10-25");
+insert into diaries values(1565, "2015-10-26");
+insert into diaries values(1566, "2015-10-27");
+insert into diaries values(1567, "2015-10-28");
+insert into diaries values(1568, "2015-10-29");
+insert into diaries values(1569, "2015-10-30");
+insert into diaries values(1570, "2015-10-31");
+insert into diaries values(1571, "2015-11-01");
+insert into diaries values(1572, "2015-11-02");
+insert into diaries values(1573, "2015-11-03");
+insert into diaries values(1574, "2015-11-04");
+insert into diaries values(1575, "2015-11-05");
+insert into diaries values(1576, "2015-11-06");
+insert into diaries values(1577, "2015-11-07");
+insert into diaries values(1578, "2015-11-08");
+insert into diaries values(1579, "2015-11-09");
+insert into diaries values(1580, "2015-11-10");
+insert into diaries values(1581, "2015-11-11");
+insert into diaries values(1582, "2015-11-12");
+insert into diaries values(1583, "2015-11-13");
+insert into diaries values(1584, "2015-11-14");
+insert into diaries values(1585, "2015-11-15");
+insert into diaries values(1586, "2015-11-16");
+insert into diaries values(1587, "2015-11-17");
+insert into diaries values(1588, "2015-11-18");
+insert into diaries values(1589, "2015-11-19");
+insert into diaries values(1590, "2015-11-20");
+insert into diaries values(1591, "2015-11-21");
+insert into diaries values(1592, "2015-11-22");
+insert into diaries values(1593, "2015-11-23");
+insert into diaries values(1594, "2015-11-24");
+insert into diaries values(1595, "2015-11-25");
+insert into diaries values(1596, "2015-11-26");
+insert into diaries values(1597, "2015-11-27");
+insert into diaries values(1598, "2015-11-28");
+insert into diaries values(1599, "2015-11-29");
+insert into diaries values(1600, "2015-11-30");
+insert into diaries values(1601, "2015-12-01");
+insert into diaries values(1602, "2015-12-02");
+insert into diaries values(1603, "2015-12-03");
+insert into diaries values(1604, "2015-12-04");
+insert into diaries values(1605, "2015-12-05");
+insert into diaries values(1606, "2015-12-06");
+insert into diaries values(1607, "2015-12-07");
+insert into diaries values(1608, "2015-12-08");
+insert into diaries values(1609, "2015-12-09");
+insert into diaries values(1610, "2015-12-10");
+insert into diaries values(1611, "2015-12-11");
+insert into diaries values(1612, "2015-12-12");
+insert into diaries values(1613, "2015-12-13");
+insert into diaries values(1614, "2015-12-14");
+insert into diaries values(1615, "2015-12-15");
+insert into diaries values(1616, "2015-12-16");
+insert into diaries values(1617, "2015-12-17");
+insert into diaries values(1618, "2015-12-18");
+insert into diaries values(1619, "2015-12-19");
+insert into diaries values(1620, "2015-12-20");
+insert into diaries values(1621, "2015-12-21");
+insert into diaries values(1622, "2015-12-22");
+insert into diaries values(1623, "2015-12-23");
+insert into diaries values(1624, "2015-12-24");
+insert into diaries values(1625, "2015-12-25");
+insert into diaries values(1626, "2015-12-26");
+insert into diaries values(1627, "2015-12-27");
+insert into diaries values(1628, "2015-12-28");
+insert into diaries values(1629, "2015-12-29");
+insert into diaries values(1630, "2015-12-30");
+insert into diaries values(1631, "2015-12-31");
+insert into diaries values(1632, "2016-01-01");
+insert into diaries values(1633, "2016-01-02");
+insert into diaries values(1634, "2016-01-03");
+insert into diaries values(1635, "2016-01-04");
+insert into diaries values(1636, "2016-01-05");
+insert into diaries values(1637, "2016-01-06");
+insert into diaries values(1638, "2016-01-07");
+insert into diaries values(1639, "2016-01-08");
+insert into diaries values(1640, "2016-01-09");
+insert into diaries values(1641, "2016-01-10");
+insert into diaries values(1642, "2016-01-11");
+insert into diaries values(1643, "2016-01-12");
+insert into diaries values(1644, "2016-01-13");
+insert into diaries values(1645, "2016-01-14");
+insert into diaries values(1646, "2016-01-15");
+insert into diaries values(1647, "2016-01-16");
+insert into diaries values(1648, "2016-01-17");
+insert into diaries values(1649, "2016-01-18");
+insert into diaries values(1650, "2016-01-19");
+insert into diaries values(1651, "2016-01-20");
+insert into diaries values(1652, "2016-01-21");
+insert into diaries values(1653, "2016-01-22");
+insert into diaries values(1654, "2016-01-23");
+insert into diaries values(1655, "2016-01-24");
+insert into diaries values(1656, "2016-01-25");
+insert into diaries values(1657, "2016-01-26");
+insert into diaries values(1658, "2016-01-27");
+insert into diaries values(1659, "2016-01-28");
+insert into diaries values(1660, "2016-01-29");
+insert into diaries values(1661, "2016-01-30");
+insert into diaries values(1662, "2016-01-31");
+insert into diaries values(1663, "2016-02-01");
+insert into diaries values(1664, "2016-02-02");
+insert into diaries values(1665, "2016-02-03");
+insert into diaries values(1666, "2016-02-04");
+insert into diaries values(1667, "2016-02-05");
+insert into diaries values(1668, "2016-02-06");
+insert into diaries values(1669, "2016-02-07");
+insert into diaries values(1670, "2016-02-08");
+insert into diaries values(1671, "2016-02-09");
+insert into diaries values(1672, "2016-02-10");
+insert into diaries values(1673, "2016-02-11");
+insert into diaries values(1674, "2016-02-12");
+insert into diaries values(1675, "2016-02-13");
+insert into diaries values(1676, "2016-02-14");
+insert into diaries values(1677, "2016-02-15");
+insert into diaries values(1678, "2016-02-16");
+insert into diaries values(1679, "2016-02-17");
+insert into diaries values(1680, "2016-02-18");
+insert into diaries values(1681, "2016-02-19");
+insert into diaries values(1682, "2016-02-20");
+insert into diaries values(1683, "2016-02-21");
+insert into diaries values(1684, "2016-02-22");
+insert into diaries values(1685, "2016-02-23");
+insert into diaries values(1686, "2016-02-24");
+insert into diaries values(1687, "2016-02-25");
+insert into diaries values(1688, "2016-02-26");
+insert into diaries values(1689, "2016-02-27");
+insert into diaries values(1690, "2016-02-28");
+insert into diaries values(1691, "2016-02-29");
+insert into diaries values(1692, "2016-03-01");
+insert into diaries values(1693, "2016-03-02");
+insert into diaries values(1694, "2016-03-03");
+insert into diaries values(1695, "2016-03-04");
+insert into diaries values(1696, "2016-03-05");
+insert into diaries values(1697, "2016-03-06");
+insert into diaries values(1698, "2016-03-07");
+insert into diaries values(1699, "2016-03-08");
+insert into diaries values(1700, "2016-03-09");
+insert into diaries values(1701, "2016-03-10");
+insert into diaries values(1702, "2016-03-11");
+insert into diaries values(1703, "2016-03-12");
+insert into diaries values(1704, "2016-03-13");
+insert into diaries values(1705, "2016-03-14");
+insert into diaries values(1706, "2016-03-15");
+insert into diaries values(1707, "2016-03-16");
+insert into diaries values(1708, "2016-03-17");
+insert into diaries values(1709, "2016-03-18");
+insert into diaries values(1710, "2016-03-19");
+insert into diaries values(1711, "2016-03-20");
+insert into diaries values(1712, "2016-03-21");
+insert into diaries values(1713, "2016-03-22");
+insert into diaries values(1714, "2016-03-23");
+insert into diaries values(1715, "2016-03-24");
+insert into diaries values(1716, "2016-03-25");
+insert into diaries values(1717, "2016-03-26");
+insert into diaries values(1718, "2016-03-27");
+insert into diaries values(1719, "2016-03-28");
+insert into diaries values(1720, "2016-03-29");
+insert into diaries values(1721, "2016-03-30");
+insert into diaries values(1722, "2016-03-31");
+insert into diaries values(1723, "2016-04-01");
+insert into diaries values(1724, "2016-04-02");
+insert into diaries values(1725, "2016-04-03");
+insert into diaries values(1726, "2016-04-04");
+insert into diaries values(1727, "2016-04-05");
+insert into diaries values(1728, "2016-04-06");
+insert into diaries values(1729, "2016-04-07");
+insert into diaries values(1730, "2016-04-08");
+insert into diaries values(1731, "2016-04-09");
+insert into diaries values(1732, "2016-04-10");
+insert into diaries values(1733, "2016-04-11");
+insert into diaries values(1734, "2016-04-12");
+insert into diaries values(1735, "2016-04-13");
+insert into diaries values(1736, "2016-04-14");
+insert into diaries values(1737, "2016-04-15");
+insert into diaries values(1738, "2016-04-16");
+insert into diaries values(1739, "2016-04-17");
+insert into diaries values(1740, "2016-04-18");
+insert into diaries values(1741, "2016-04-19");
+insert into diaries values(1742, "2016-04-20");
+insert into diaries values(1743, "2016-04-21");
+insert into diaries values(1744, "2016-04-22");
+insert into diaries values(1745, "2016-04-23");
+insert into diaries values(1746, "2016-04-24");
+insert into diaries values(1747, "2016-04-25");
+insert into diaries values(1748, "2016-04-26");
+insert into diaries values(1749, "2016-04-27");
+insert into diaries values(1750, "2016-04-28");
+insert into diaries values(1751, "2016-04-29");
+insert into diaries values(1752, "2016-04-30");
+insert into diaries values(1753, "2016-05-01");
+insert into diaries values(1754, "2016-05-02");
+insert into diaries values(1755, "2016-05-03");
+insert into diaries values(1756, "2016-05-04");
+insert into diaries values(1757, "2016-05-05");
+insert into diaries values(1758, "2016-05-06");
+insert into diaries values(1759, "2016-05-07");
+insert into diaries values(1760, "2016-05-08");
+insert into diaries values(1761, "2016-05-09");
+insert into diaries values(1762, "2016-05-10");
+insert into diaries values(1763, "2016-05-11");
+insert into diaries values(1764, "2016-05-12");
+insert into diaries values(1765, "2016-05-13");
+insert into diaries values(1766, "2016-05-14");
+insert into diaries values(1767, "2016-05-15");
+insert into diaries values(1768, "2016-05-16");
+insert into diaries values(1769, "2016-05-17");
+insert into diaries values(1770, "2016-05-18");
+insert into diaries values(1771, "2016-05-19");
+insert into diaries values(1772, "2016-05-20");
+insert into diaries values(1773, "2016-05-21");
+insert into diaries values(1774, "2016-05-22");
+insert into diaries values(1775, "2016-05-23");
+insert into diaries values(1776, "2016-05-24");
+insert into diaries values(1777, "2016-05-25");
+insert into diaries values(1778, "2016-05-26");
+insert into diaries values(1779, "2016-05-27");
+insert into diaries values(1780, "2016-05-28");
+insert into diaries values(1781, "2016-05-29");
+insert into diaries values(1782, "2016-05-30");
+insert into diaries values(1783, "2016-05-31");
+insert into diaries values(1784, "2016-06-01");
+insert into diaries values(1785, "2016-06-02");
+insert into diaries values(1786, "2016-06-03");
+insert into diaries values(1787, "2016-06-04");
+insert into diaries values(1788, "2016-06-05");
+insert into diaries values(1789, "2016-06-06");
+insert into diaries values(1790, "2016-06-07");
+insert into diaries values(1791, "2016-06-08");
+insert into diaries values(1792, "2016-06-09");
+insert into diaries values(1793, "2016-06-10");
+insert into diaries values(1794, "2016-06-11");
+insert into diaries values(1795, "2016-06-12");
+insert into diaries values(1796, "2016-06-13");
+insert into diaries values(1797, "2016-06-14");
+insert into diaries values(1798, "2016-06-15");
+insert into diaries values(1799, "2016-06-16");
+insert into diaries values(1800, "2016-06-17");
+insert into diaries values(1801, "2016-06-18");
+insert into diaries values(1802, "2016-06-19");
+insert into diaries values(1803, "2016-06-20");
+insert into diaries values(1804, "2016-06-21");
+insert into diaries values(1805, "2016-06-22");
+insert into diaries values(1806, "2016-06-23");
+insert into diaries values(1807, "2016-06-24");
+insert into diaries values(1808, "2016-06-25");
+insert into diaries values(1809, "2016-06-26");
+insert into diaries values(1810, "2016-06-27");
+insert into diaries values(1811, "2016-06-28");
+insert into diaries values(1812, "2016-06-29");
+insert into diaries values(1813, "2016-06-30");
+insert into diaries values(1814, "2016-07-01");
+insert into diaries values(1815, "2016-07-02");
+insert into diaries values(1816, "2016-07-03");
+insert into diaries values(1817, "2016-07-04");
+insert into diaries values(1818, "2016-07-05");
+insert into diaries values(1819, "2016-07-06");
+insert into diaries values(1820, "2016-07-07");
+insert into diaries values(1821, "2016-07-08");
+insert into diaries values(1822, "2016-07-09");
+insert into diaries values(1823, "2016-07-10");
+insert into diaries values(1824, "2016-07-11");
+insert into diaries values(1825, "2016-07-12");
+insert into diaries values(1826, "2016-07-13");
+insert into diaries values(1827, "2016-07-14");
+insert into diaries values(1828, "2016-07-15");
+insert into diaries values(1829, "2016-07-16");
+insert into diaries values(1830, "2016-07-17");
+insert into diaries values(1831, "2016-07-18");
+insert into diaries values(1832, "2016-07-19");
+insert into diaries values(1833, "2016-07-20");
+insert into diaries values(1834, "2016-07-21");
+insert into diaries values(1835, "2016-07-22");
+insert into diaries values(1836, "2016-07-23");
+insert into diaries values(1837, "2016-07-24");
+insert into diaries values(1838, "2016-07-25");
+insert into diaries values(1839, "2016-07-26");
+insert into diaries values(1840, "2016-07-27");
+insert into diaries values(1841, "2016-07-28");
+insert into diaries values(1842, "2016-07-29");
+insert into diaries values(1843, "2016-07-30");
+insert into diaries values(1844, "2016-07-31");
+insert into diaries values(1845, "2016-08-01");
+insert into diaries values(1846, "2016-08-02");
+insert into diaries values(1847, "2016-08-03");
+insert into diaries values(1848, "2016-08-04");
+insert into diaries values(1849, "2016-08-05");
+insert into diaries values(1850, "2016-08-06");
+insert into diaries values(1851, "2016-08-07");
+insert into diaries values(1852, "2016-08-08");
+insert into diaries values(1853, "2016-08-09");
+insert into diaries values(1854, "2016-08-10");
+insert into diaries values(1855, "2016-08-11");
+insert into diaries values(1856, "2016-08-12");
+insert into diaries values(1857, "2016-08-13");
+insert into diaries values(1858, "2016-08-14");
+insert into diaries values(1859, "2016-08-15");
+insert into diaries values(1860, "2016-08-16");
+insert into diaries values(1861, "2016-08-17");
+insert into diaries values(1862, "2016-08-18");
+insert into diaries values(1863, "2016-08-19");
+insert into diaries values(1864, "2016-08-20");
+insert into diaries values(1865, "2016-08-21");
+insert into diaries values(1866, "2016-08-22");
+insert into diaries values(1867, "2016-08-23");
+insert into diaries values(1868, "2016-08-24");
+insert into diaries values(1869, "2016-08-25");
+insert into diaries values(1870, "2016-08-26");
+insert into diaries values(1871, "2016-08-27");
+insert into diaries values(1872, "2016-08-28");
+insert into diaries values(1873, "2016-08-29");
+insert into diaries values(1874, "2016-08-30");
+insert into diaries values(1875, "2016-08-31");
+insert into diaries values(1876, "2016-09-01");
+insert into diaries values(1877, "2016-09-02");
+insert into diaries values(1878, "2016-09-03");
+insert into diaries values(1879, "2016-09-04");
+insert into diaries values(1880, "2016-09-05");
+insert into diaries values(1881, "2016-09-06");
+insert into diaries values(1882, "2016-09-07");
+insert into diaries values(1883, "2016-09-08");
+insert into diaries values(1884, "2016-09-09");
+insert into diaries values(1885, "2016-09-10");
+insert into diaries values(1886, "2016-09-11");
+insert into diaries values(1887, "2016-09-12");
+insert into diaries values(1888, "2016-09-13");
+insert into diaries values(1889, "2016-09-14");
+insert into diaries values(1890, "2016-09-15");
+insert into diaries values(1891, "2016-09-16");
+insert into diaries values(1892, "2016-09-17");
+insert into diaries values(1893, "2016-09-18");
+insert into diaries values(1894, "2016-09-19");
+insert into diaries values(1895, "2016-09-20");
+insert into diaries values(1896, "2016-09-21");
+insert into diaries values(1897, "2016-09-22");
+insert into diaries values(1898, "2016-09-23");
+insert into diaries values(1899, "2016-09-24");
+insert into diaries values(1900, "2016-09-25");
+insert into diaries values(1901, "2016-09-26");
+insert into diaries values(1902, "2016-09-27");
+insert into diaries values(1903, "2016-09-28");
+insert into diaries values(1904, "2016-09-29");
+insert into diaries values(1905, "2016-09-30");
+insert into diaries values(1906, "2016-10-01");
+insert into diaries values(1907, "2016-10-02");
+insert into diaries values(1908, "2016-10-03");
+insert into diaries values(1909, "2016-10-04");
+insert into diaries values(1910, "2016-10-05");
+insert into diaries values(1911, "2016-10-06");
+insert into diaries values(1912, "2016-10-07");
+insert into diaries values(1913, "2016-10-08");
+insert into diaries values(1914, "2016-10-09");
+insert into diaries values(1915, "2016-10-10");
+insert into diaries values(1916, "2016-10-11");
+insert into diaries values(1917, "2016-10-12");
+insert into diaries values(1918, "2016-10-13");
+insert into diaries values(1919, "2016-10-14");
+insert into diaries values(1920, "2016-10-15");
+insert into diaries values(1921, "2016-10-16");
+insert into diaries values(1922, "2016-10-17");
+insert into diaries values(1923, "2016-10-18");
+insert into diaries values(1924, "2016-10-19");
+insert into diaries values(1925, "2016-10-20");
+insert into diaries values(1926, "2016-10-21");
+insert into diaries values(1927, "2016-10-22");
+insert into diaries values(1928, "2016-10-23");
+insert into diaries values(1929, "2016-10-24");
+insert into diaries values(1930, "2016-10-25");
+insert into diaries values(1931, "2016-10-26");
+insert into diaries values(1932, "2016-10-27");
+insert into diaries values(1933, "2016-10-28");
+insert into diaries values(1934, "2016-10-29");
+insert into diaries values(1935, "2016-10-30");
+insert into diaries values(1936, "2016-10-31");
+insert into diaries values(1937, "2016-11-01");
+insert into diaries values(1938, "2016-11-02");
+insert into diaries values(1939, "2016-11-03");
+insert into diaries values(1940, "2016-11-04");
+insert into diaries values(1941, "2016-11-05");
+insert into diaries values(1942, "2016-11-06");
+insert into diaries values(1943, "2016-11-07");
+insert into diaries values(1944, "2016-11-08");
+insert into diaries values(1945, "2016-11-09");
+insert into diaries values(1946, "2016-11-10");
+insert into diaries values(1947, "2016-11-11");
+insert into diaries values(1948, "2016-11-12");
+insert into diaries values(1949, "2016-11-13");
+insert into diaries values(1950, "2016-11-14");
+insert into diaries values(1951, "2016-11-15");
+insert into diaries values(1952, "2016-11-16");
+insert into diaries values(1953, "2016-11-17");
+insert into diaries values(1954, "2016-11-18");
+insert into diaries values(1955, "2016-11-19");
+insert into diaries values(1956, "2016-11-20");
+insert into diaries values(1957, "2016-11-21");
+insert into diaries values(1958, "2016-11-22");
+insert into diaries values(1959, "2016-11-23");
+insert into diaries values(1960, "2016-11-24");
+insert into diaries values(1961, "2016-11-25");
+insert into diaries values(1962, "2016-11-26");
+insert into diaries values(1963, "2016-11-27");
+insert into diaries values(1964, "2016-11-28");
+insert into diaries values(1965, "2016-11-29");
+insert into diaries values(1966, "2016-11-30");
+insert into diaries values(1967, "2016-12-01");
+insert into diaries values(1968, "2016-12-02");
+insert into diaries values(1969, "2016-12-03");
+insert into diaries values(1970, "2016-12-04");
+insert into diaries values(1971, "2016-12-05");
+insert into diaries values(1972, "2016-12-06");
+insert into diaries values(1973, "2016-12-07");
+insert into diaries values(1974, "2016-12-08");
+insert into diaries values(1975, "2016-12-09");
+insert into diaries values(1976, "2016-12-10");
+insert into diaries values(1977, "2016-12-11");
+insert into diaries values(1978, "2016-12-12");
+insert into diaries values(1979, "2016-12-13");
+insert into diaries values(1980, "2016-12-14");
+insert into diaries values(1981, "2016-12-15");
+insert into diaries values(1982, "2016-12-16");
+insert into diaries values(1983, "2016-12-17");
+insert into diaries values(1984, "2016-12-18");
+insert into diaries values(1985, "2016-12-19");
+insert into diaries values(1986, "2016-12-20");
+insert into diaries values(1987, "2016-12-21");
+insert into diaries values(1988, "2016-12-22");
+insert into diaries values(1989, "2016-12-23");
+insert into diaries values(1990, "2016-12-24");
+insert into diaries values(1991, "2016-12-25");
+insert into diaries values(1992, "2016-12-26");
+insert into diaries values(1993, "2016-12-27");
+insert into diaries values(1994, "2016-12-28");
+insert into diaries values(1995, "2016-12-29");
+insert into diaries values(1996, "2016-12-30");
+insert into diaries values(1997, "2016-12-31");
+insert into diaries values(1998, "2017-01-01");
+insert into diaries values(1999, "2017-01-02");
+insert into diaries values(2000, "2017-01-03");
+insert into diaries values(2001, "2017-01-04");
+insert into diaries values(2002, "2017-01-05");
+insert into diaries values(2003, "2017-01-06");
+insert into diaries values(2004, "2017-01-07");
+insert into diaries values(2005, "2017-01-08");
+insert into diaries values(2006, "2017-01-09");
+insert into diaries values(2007, "2017-01-10");
+insert into diaries values(2008, "2017-01-11");
+insert into diaries values(2009, "2017-01-12");
+insert into diaries values(2010, "2017-01-13");
+insert into diaries values(2011, "2017-01-14");
+insert into diaries values(2012, "2017-01-15");
+insert into diaries values(2013, "2017-01-16");
+insert into diaries values(2014, "2017-01-17");
+insert into diaries values(2015, "2017-01-18");
+insert into diaries values(2016, "2017-01-19");
+insert into diaries values(2017, "2017-01-20");
+insert into diaries values(2018, "2017-01-21");
+insert into diaries values(2019, "2017-01-22");
+insert into diaries values(2020, "2017-01-23");
+insert into diaries values(2021, "2017-01-24");
+insert into diaries values(2022, "2017-01-25");
+insert into diaries values(2023, "2017-01-26");
+insert into diaries values(2024, "2017-01-27");
+insert into diaries values(2025, "2017-01-28");
+insert into diaries values(2026, "2017-01-29");
+insert into diaries values(2027, "2017-01-30");
+insert into diaries values(2028, "2017-01-31");
+insert into diaries values(2029, "2017-02-01");
+insert into diaries values(2030, "2017-02-02");
+insert into diaries values(2031, "2017-02-03");
+insert into diaries values(2032, "2017-02-04");
+insert into diaries values(2033, "2017-02-05");
+insert into diaries values(2034, "2017-02-06");
+insert into diaries values(2035, "2017-02-07");
+insert into diaries values(2036, "2017-02-08");
+insert into diaries values(2037, "2017-02-09");
+insert into diaries values(2038, "2017-02-10");
+insert into diaries values(2039, "2017-02-11");
+insert into diaries values(2040, "2017-02-12");
+insert into diaries values(2041, "2017-02-13");
+insert into diaries values(2042, "2017-02-14");
+insert into diaries values(2043, "2017-02-15");
+insert into diaries values(2044, "2017-02-16");
+insert into diaries values(2045, "2017-02-17");
+insert into diaries values(2046, "2017-02-18");
+insert into diaries values(2047, "2017-02-19");
+insert into diaries values(2048, "2017-02-20");
+insert into diaries values(2049, "2017-02-21");
+insert into diaries values(2050, "2017-02-22");
+insert into diaries values(2051, "2017-02-23");
+insert into diaries values(2052, "2017-02-24");
+insert into diaries values(2053, "2017-02-25");
+insert into diaries values(2054, "2017-02-26");
+insert into diaries values(2055, "2017-02-27");
+insert into diaries values(2056, "2017-02-28");
+insert into diaries values(2057, "2017-03-01");
+insert into diaries values(2058, "2017-03-02");
+insert into diaries values(2059, "2017-03-03");
+insert into diaries values(2060, "2017-03-04");
+insert into diaries values(2061, "2017-03-05");
+insert into diaries values(2062, "2017-03-06");
+insert into diaries values(2063, "2017-03-07");
+insert into diaries values(2064, "2017-03-08");
+insert into diaries values(2065, "2017-03-09");
+insert into diaries values(2066, "2017-03-10");
+insert into diaries values(2067, "2017-03-11");
+insert into diaries values(2068, "2017-03-12");
+insert into diaries values(2069, "2017-03-13");
+insert into diaries values(2070, "2017-03-14");
+insert into diaries values(2071, "2017-03-15");
+insert into diaries values(2072, "2017-03-16");
+insert into diaries values(2073, "2017-03-17");
+insert into diaries values(2074, "2017-03-18");
+insert into diaries values(2075, "2017-03-19");
+insert into diaries values(2076, "2017-03-20");
+insert into diaries values(2077, "2017-03-21");
+insert into diaries values(2078, "2017-03-22");
+insert into diaries values(2079, "2017-03-23");
+insert into diaries values(2080, "2017-03-24");
+insert into diaries values(2081, "2017-03-25");
+insert into diaries values(2082, "2017-03-26");
+insert into diaries values(2083, "2017-03-27");
+insert into diaries values(2084, "2017-03-28");
+insert into diaries values(2085, "2017-03-29");
+insert into diaries values(2086, "2017-03-30");
+insert into diaries values(2087, "2017-03-31");
+insert into diaries values(2088, "2017-04-01");
+insert into diaries values(2089, "2017-04-02");
+insert into diaries values(2090, "2017-04-03");
+insert into diaries values(2091, "2017-04-04");
+insert into diaries values(2092, "2017-04-05");
+insert into diaries values(2093, "2017-04-06");
+insert into diaries values(2094, "2017-04-07");
+insert into diaries values(2095, "2017-04-08");
+insert into diaries values(2096, "2017-04-09");
+insert into diaries values(2097, "2017-04-10");
+insert into diaries values(2098, "2017-04-11");
+insert into diaries values(2099, "2017-04-12");
+insert into diaries values(2100, "2017-04-13");
+insert into diaries values(2101, "2017-04-14");
+insert into diaries values(2102, "2017-04-15");
+insert into diaries values(2103, "2017-04-16");
+insert into diaries values(2104, "2017-04-17");
+insert into diaries values(2105, "2017-04-18");
+insert into diaries values(2106, "2017-04-19");
+insert into diaries values(2107, "2017-04-20");
+insert into diaries values(2108, "2017-04-21");
+insert into diaries values(2109, "2017-04-22");
+insert into diaries values(2110, "2017-04-23");
+insert into diaries values(2111, "2017-04-24");
+insert into diaries values(2112, "2017-04-25");
+insert into diaries values(2113, "2017-04-26");
+insert into diaries values(2114, "2017-04-27");
+insert into diaries values(2115, "2017-04-28");
+insert into diaries values(2116, "2017-04-29");
+insert into diaries values(2117, "2017-04-30");
+insert into diaries values(2118, "2017-05-01");
+insert into diaries values(2119, "2017-05-02");
+insert into diaries values(2120, "2017-05-03");
+insert into diaries values(2121, "2017-05-04");
+insert into diaries values(2122, "2017-05-05");
+insert into diaries values(2123, "2017-05-06");
+insert into diaries values(2124, "2017-05-07");
+insert into diaries values(2125, "2017-05-08");
+insert into diaries values(2126, "2017-05-09");
+insert into diaries values(2127, "2017-05-10");
+insert into diaries values(2128, "2017-05-11");
+insert into diaries values(2129, "2017-05-12");
+insert into diaries values(2130, "2017-05-13");
+insert into diaries values(2131, "2017-05-14");
+insert into diaries values(2132, "2017-05-15");
+insert into diaries values(2133, "2017-05-16");
+insert into diaries values(2134, "2017-05-17");
+insert into diaries values(2135, "2017-05-18");
+insert into diaries values(2136, "2017-05-19");
+insert into diaries values(2137, "2017-05-20");
+insert into diaries values(2138, "2017-05-21");
+insert into diaries values(2139, "2017-05-22");
+insert into diaries values(2140, "2017-05-23");
+insert into diaries values(2141, "2017-05-24");
+insert into diaries values(2142, "2017-05-25");
+insert into diaries values(2143, "2017-05-26");
+insert into diaries values(2144, "2017-05-27");
+insert into diaries values(2145, "2017-05-28");
+insert into diaries values(2146, "2017-05-29");
+insert into diaries values(2147, "2017-05-30");
+insert into diaries values(2148, "2017-05-31");
+insert into diaries values(2149, "2017-06-01");
+insert into diaries values(2150, "2017-06-02");
+insert into diaries values(2151, "2017-06-03");
+insert into diaries values(2152, "2017-06-04");
+insert into diaries values(2153, "2017-06-05");
+insert into diaries values(2154, "2017-06-06");
+insert into diaries values(2155, "2017-06-07");
+insert into diaries values(2156, "2017-06-08");
+insert into diaries values(2157, "2017-06-09");
+insert into diaries values(2158, "2017-06-10");
+insert into diaries values(2159, "2017-06-11");
+insert into diaries values(2160, "2017-06-12");
+insert into diaries values(2161, "2017-06-13");
+insert into diaries values(2162, "2017-06-14");
+insert into diaries values(2163, "2017-06-15");
+insert into diaries values(2164, "2017-06-16");
+insert into diaries values(2165, "2017-06-17");
+insert into diaries values(2166, "2017-06-18");
+insert into diaries values(2167, "2017-06-19");
+insert into diaries values(2168, "2017-06-20");
+insert into diaries values(2169, "2017-06-21");
+insert into diaries values(2170, "2017-06-22");
+insert into diaries values(2171, "2017-06-23");
+insert into diaries values(2172, "2017-06-24");
+insert into diaries values(2173, "2017-06-25");
+insert into diaries values(2174, "2017-06-26");
+insert into diaries values(2175, "2017-06-27");
+insert into diaries values(2176, "2017-06-28");
+insert into diaries values(2177, "2017-06-29");
+insert into diaries values(2178, "2017-06-30");
+insert into diaries values(2179, "2017-07-01");
+insert into diaries values(2180, "2017-07-02");
+insert into diaries values(2181, "2017-07-03");
+insert into diaries values(2182, "2017-07-04");
+insert into diaries values(2183, "2017-07-05");
+insert into diaries values(2184, "2017-07-06");
+insert into diaries values(2185, "2017-07-07");
+insert into diaries values(2186, "2017-07-08");
+insert into diaries values(2187, "2017-07-09");
+insert into diaries values(2188, "2017-07-10");
+insert into diaries values(2189, "2017-07-11");
+insert into diaries values(2190, "2017-07-12");
+insert into diaries values(2191, "2017-07-13");
+insert into diaries values(2192, "2017-07-14");
+insert into diaries values(2193, "2017-07-15");
+insert into diaries values(2194, "2017-07-16");
+insert into diaries values(2195, "2017-07-17");
+insert into diaries values(2196, "2017-07-18");
+insert into diaries values(2197, "2017-07-19");
+insert into diaries values(2198, "2017-07-20");
+insert into diaries values(2199, "2017-07-21");
+insert into diaries values(2200, "2017-07-22");
+insert into diaries values(2201, "2017-07-23");
+insert into diaries values(2202, "2017-07-24");
+insert into diaries values(2203, "2017-07-25");
+insert into diaries values(2204, "2017-07-26");
+insert into diaries values(2205, "2017-07-27");
+insert into diaries values(2206, "2017-07-28");
+insert into diaries values(2207, "2017-07-29");
+insert into diaries values(2208, "2017-07-30");
+insert into diaries values(2209, "2017-07-31");
+insert into diaries values(2210, "2017-08-01");
+insert into diaries values(2211, "2017-08-02");
+insert into diaries values(2212, "2017-08-03");
+insert into diaries values(2213, "2017-08-04");
+insert into diaries values(2214, "2017-08-05");
+insert into diaries values(2215, "2017-08-06");
+insert into diaries values(2216, "2017-08-07");
+insert into diaries values(2217, "2017-08-08");
+insert into diaries values(2218, "2017-08-09");
+insert into diaries values(2219, "2017-08-10");
+insert into diaries values(2220, "2017-08-11");
+insert into diaries values(2221, "2017-08-12");
+insert into diaries values(2222, "2017-08-13");
+insert into diaries values(2223, "2017-08-14");
+insert into diaries values(2224, "2017-08-15");
+insert into diaries values(2225, "2017-08-16");
+insert into diaries values(2226, "2017-08-17");
+insert into diaries values(2227, "2017-08-18");
+insert into diaries values(2228, "2017-08-19");
+insert into diaries values(2229, "2017-08-20");
+insert into diaries values(2230, "2017-08-21");
+insert into diaries values(2231, "2017-08-22");
+insert into diaries values(2232, "2017-08-23");
+insert into diaries values(2233, "2017-08-24");
+insert into diaries values(2234, "2017-08-25");
+insert into diaries values(2235, "2017-08-26");
+insert into diaries values(2236, "2017-08-27");
+insert into diaries values(2237, "2017-08-28");
+insert into diaries values(2238, "2017-08-29");
+insert into diaries values(2239, "2017-08-30");
+insert into diaries values(2240, "2017-08-31");
+insert into diaries values(2241, "2017-09-01");
+insert into diaries values(2242, "2017-09-02");
+insert into diaries values(2243, "2017-09-03");
+insert into diaries values(2244, "2017-09-04");
+insert into diaries values(2245, "2017-09-05");
+insert into diaries values(2246, "2017-09-06");
+insert into diaries values(2247, "2017-09-07");
+insert into diaries values(2248, "2017-09-08");
+insert into diaries values(2249, "2017-09-09");
+insert into diaries values(2250, "2017-09-10");
+insert into diaries values(2251, "2017-09-11");
+insert into diaries values(2252, "2017-09-12");
+insert into diaries values(2253, "2017-09-13");
+insert into diaries values(2254, "2017-09-14");
+insert into diaries values(2255, "2017-09-15");
+insert into diaries values(2256, "2017-09-16");
+insert into diaries values(2257, "2017-09-17");
+insert into diaries values(2258, "2017-09-18");
+insert into diaries values(2259, "2017-09-19");
+insert into diaries values(2260, "2017-09-20");
+insert into diaries values(2261, "2017-09-21");
+insert into diaries values(2262, "2017-09-22");
+insert into diaries values(2263, "2017-09-23");
+insert into diaries values(2264, "2017-09-24");
+insert into diaries values(2265, "2017-09-25");
+insert into diaries values(2266, "2017-09-26");
+insert into diaries values(2267, "2017-09-27");
+insert into diaries values(2268, "2017-09-28");
+insert into diaries values(2269, "2017-09-29");
+insert into diaries values(2270, "2017-09-30");
+insert into diaries values(2271, "2017-10-01");
+insert into diaries values(2272, "2017-10-02");
+insert into diaries values(2273, "2017-10-03");
+insert into diaries values(2274, "2017-10-04");
+insert into diaries values(2275, "2017-10-05");
+insert into diaries values(2276, "2017-10-06");
+insert into diaries values(2277, "2017-10-07");
+insert into diaries values(2278, "2017-10-08");
+insert into diaries values(2279, "2017-10-09");
+insert into diaries values(2280, "2017-10-10");
+insert into diaries values(2281, "2017-10-11");
+insert into diaries values(2282, "2017-10-12");
+insert into diaries values(2283, "2017-10-13");
+insert into diaries values(2284, "2017-10-14");
+insert into diaries values(2285, "2017-10-15");
+insert into diaries values(2286, "2017-10-16");
+insert into diaries values(2287, "2017-10-17");
+insert into diaries values(2288, "2017-10-18");
+insert into diaries values(2289, "2017-10-19");
+insert into diaries values(2290, "2017-10-20");
+insert into diaries values(2291, "2017-10-21");
+insert into diaries values(2292, "2017-10-22");
+insert into diaries values(2293, "2017-10-23");
+insert into diaries values(2294, "2017-10-24");
+insert into diaries values(2295, "2017-10-25");
+insert into diaries values(2296, "2017-10-26");
+insert into diaries values(2297, "2017-10-27");
+insert into diaries values(2298, "2017-10-28");
+insert into diaries values(2299, "2017-10-29");
+insert into diaries values(2300, "2017-10-30");
+insert into diaries values(2301, "2017-10-31");
+insert into diaries values(2302, "2017-11-01");
+insert into diaries values(2303, "2017-11-02");
+insert into diaries values(2304, "2017-11-03");
+insert into diaries values(2305, "2017-11-04");
+insert into diaries values(2306, "2017-11-05");
+insert into diaries values(2307, "2017-11-06");
+insert into diaries values(2308, "2017-11-07");
+insert into diaries values(2309, "2017-11-08");
+insert into diaries values(2310, "2017-11-09");
+insert into diaries values(2311, "2017-11-10");
+insert into diaries values(2312, "2017-11-11");
+insert into diaries values(2313, "2017-11-12");
+insert into diaries values(2314, "2017-11-13");
+insert into diaries values(2315, "2017-11-14");
+insert into diaries values(2316, "2017-11-15");
+insert into diaries values(2317, "2017-11-16");
+insert into diaries values(2318, "2017-11-17");
+insert into diaries values(2319, "2017-11-18");
+insert into diaries values(2320, "2017-11-19");
+insert into diaries values(2321, "2017-11-20");
+insert into diaries values(2322, "2017-11-21");
+insert into diaries values(2323, "2017-11-22");
+insert into diaries values(2324, "2017-11-23");
+insert into diaries values(2325, "2017-11-24");
+insert into diaries values(2326, "2017-11-25");
+insert into diaries values(2327, "2017-11-26");
+insert into diaries values(2328, "2017-11-27");
+insert into diaries values(2329, "2017-11-28");
+insert into diaries values(2330, "2017-11-29");
+insert into diaries values(2331, "2017-11-30");
+insert into diaries values(2332, "2017-12-01");
+insert into diaries values(2333, "2017-12-02");
+insert into diaries values(2334, "2017-12-03");
+insert into diaries values(2335, "2017-12-04");
+insert into diaries values(2336, "2017-12-05");
+insert into diaries values(2337, "2017-12-06");
+insert into diaries values(2338, "2017-12-07");
+insert into diaries values(2339, "2017-12-08");
+insert into diaries values(2340, "2017-12-09");
+insert into diaries values(2341, "2017-12-10");
+insert into diaries values(2342, "2017-12-11");
+insert into diaries values(2343, "2017-12-12");
+insert into diaries values(2344, "2017-12-13");
+insert into diaries values(2345, "2017-12-14");
+insert into diaries values(2346, "2017-12-15");
+insert into diaries values(2347, "2017-12-16");
+insert into diaries values(2348, "2017-12-17");
+insert into diaries values(2349, "2017-12-18");
+insert into diaries values(2350, "2017-12-19");
+insert into diaries values(2351, "2017-12-20");
+insert into diaries values(2352, "2017-12-21");
+insert into diaries values(2353, "2017-12-22");
+insert into diaries values(2354, "2017-12-23");
+insert into diaries values(2355, "2017-12-24");
+insert into diaries values(2356, "2017-12-25");
+insert into diaries values(2357, "2017-12-26");
+insert into diaries values(2358, "2017-12-27");
+insert into diaries values(2359, "2017-12-28");
+insert into diaries values(2360, "2017-12-29");
+insert into diaries values(2361, "2017-12-30");
+insert into diaries values(2362, "2017-12-31");
+insert into diaries values(2363, "2018-01-01");
+insert into diaries values(2364, "2018-01-02");
+insert into diaries values(2365, "2018-01-03");
+insert into diaries values(2366, "2018-01-04");
+insert into diaries values(2367, "2018-01-05");
+insert into diaries values(2368, "2018-01-06");
+insert into diaries values(2369, "2018-01-07");
+insert into diaries values(2370, "2018-01-08");
+insert into diaries values(2371, "2018-01-09");
+insert into diaries values(2372, "2018-01-10");
+insert into diaries values(2373, "2018-01-11");
+insert into diaries values(2374, "2018-01-12");
+insert into diaries values(2375, "2018-01-13");
+insert into diaries values(2376, "2018-01-14");
+insert into diaries values(2377, "2018-01-15");
+insert into diaries values(2378, "2018-01-16");
+insert into diaries values(2379, "2018-01-17");
+insert into diaries values(2380, "2018-01-18");
+insert into diaries values(2381, "2018-01-19");
+insert into diaries values(2382, "2018-01-20");
+insert into diaries values(2383, "2018-01-21");
+insert into diaries values(2384, "2018-01-22");
+insert into diaries values(2385, "2018-01-23");
+insert into diaries values(2386, "2018-01-24");
+insert into diaries values(2387, "2018-01-25");
+insert into diaries values(2388, "2018-01-26");
+insert into diaries values(2389, "2018-01-27");
+insert into diaries values(2390, "2018-01-28");
+insert into diaries values(2391, "2018-01-29");
+insert into diaries values(2392, "2018-01-30");
+insert into diaries values(2393, "2018-01-31");
+insert into diaries values(2394, "2018-02-01");
+insert into diaries values(2395, "2018-02-02");
+insert into diaries values(2396, "2018-02-03");
+insert into diaries values(2397, "2018-02-04");
+insert into diaries values(2398, "2018-02-05");
+insert into diaries values(2399, "2018-02-06");
+insert into diaries values(2400, "2018-02-07");
+insert into diaries values(2401, "2018-02-08");
+insert into diaries values(2402, "2018-02-09");
+insert into diaries values(2403, "2018-02-10");
+insert into diaries values(2404, "2018-02-11");
+insert into diaries values(2405, "2018-02-12");
+insert into diaries values(2406, "2018-02-13");
+insert into diaries values(2407, "2018-02-14");
+insert into diaries values(2408, "2018-02-15");
+insert into diaries values(2409, "2018-02-16");
+insert into diaries values(2410, "2018-02-17");
+insert into diaries values(2411, "2018-02-18");
+insert into diaries values(2412, "2018-02-19");
+insert into diaries values(2413, "2018-02-20");
+insert into diaries values(2414, "2018-02-21");
+insert into diaries values(2415, "2018-02-22");
+insert into diaries values(2416, "2018-02-23");
+insert into diaries values(2417, "2018-02-24");
+insert into diaries values(2418, "2018-02-25");
+insert into diaries values(2419, "2018-02-26");
+insert into diaries values(2420, "2018-02-27");
+insert into diaries values(2421, "2018-02-28");
+insert into diaries values(2422, "2018-03-01");
+insert into diaries values(2423, "2018-03-02");
+insert into diaries values(2424, "2018-03-03");
+insert into diaries values(2425, "2018-03-04");
+insert into diaries values(2426, "2018-03-05");
+insert into diaries values(2427, "2018-03-06");
+insert into diaries values(2428, "2018-03-07");
+insert into diaries values(2429, "2018-03-08");
+insert into diaries values(2430, "2018-03-09");
+insert into diaries values(2431, "2018-03-10");
+insert into diaries values(2432, "2018-03-11");
+insert into diaries values(2433, "2018-03-12");
+insert into diaries values(2434, "2018-03-13");
+insert into diaries values(2435, "2018-03-14");
+insert into diaries values(2436, "2018-03-15");
+insert into diaries values(2437, "2018-03-16");
+insert into diaries values(2438, "2018-03-17");
+insert into diaries values(2439, "2018-03-18");
+insert into diaries values(2440, "2018-03-19");
+insert into diaries values(2441, "2018-03-20");
+insert into diaries values(2442, "2018-03-21");
+insert into diaries values(2443, "2018-03-22");
+insert into diaries values(2444, "2018-03-23");
+insert into diaries values(2445, "2018-03-24");
+insert into diaries values(2446, "2018-03-25");
+insert into diaries values(2447, "2018-03-26");
+insert into diaries values(2448, "2018-03-27");
+insert into diaries values(2449, "2018-03-28");
+insert into diaries values(2450, "2018-03-29");
+insert into diaries values(2451, "2018-03-30");
+insert into diaries values(2452, "2018-03-31");
+insert into diaries values(2453, "2018-04-01");
+insert into diaries values(2454, "2018-04-02");
+insert into diaries values(2455, "2018-04-03");
+insert into diaries values(2456, "2018-04-04");
+insert into diaries values(2457, "2018-04-05");
+insert into diaries values(2458, "2018-04-06");
+insert into diaries values(2459, "2018-04-07");
+insert into diaries values(2460, "2018-04-08");
+insert into diaries values(2461, "2018-04-09");
+insert into diaries values(2462, "2018-04-10");
+insert into diaries values(2463, "2018-04-11");
+insert into diaries values(2464, "2018-04-12");
+insert into diaries values(2465, "2018-04-13");
+insert into diaries values(2466, "2018-04-14");
+insert into diaries values(2467, "2018-04-15");
+insert into diaries values(2468, "2018-04-16");
+insert into diaries values(2469, "2018-04-17");
+insert into diaries values(2470, "2018-04-18");
+insert into diaries values(2471, "2018-04-19");
+insert into diaries values(2472, "2018-04-20");
+insert into diaries values(2473, "2018-04-21");
+insert into diaries values(2474, "2018-04-22");
+insert into diaries values(2475, "2018-04-23");
+insert into diaries values(2476, "2018-04-24");
+insert into diaries values(2477, "2018-04-25");
+insert into diaries values(2478, "2018-04-26");
+insert into diaries values(2479, "2018-04-27");
+insert into diaries values(2480, "2018-04-28");
+insert into diaries values(2481, "2018-04-29");
+insert into diaries values(2482, "2018-04-30");
+insert into diaries values(2483, "2018-05-01");
+insert into diaries values(2484, "2018-05-02");
+insert into diaries values(2485, "2018-05-03");
+insert into diaries values(2486, "2018-05-04");
+insert into diaries values(2487, "2018-05-05");
+insert into diaries values(2488, "2018-05-06");
+insert into diaries values(2489, "2018-05-07");
+insert into diaries values(2490, "2018-05-08");
+insert into diaries values(2491, "2018-05-09");
+insert into diaries values(2492, "2018-05-10");
+insert into diaries values(2493, "2018-05-11");
+insert into diaries values(2494, "2018-05-12");
+insert into diaries values(2495, "2018-05-13");
+insert into diaries values(2496, "2018-05-14");
+insert into diaries values(2497, "2018-05-15");
+insert into diaries values(2498, "2018-05-16");
+insert into diaries values(2499, "2018-05-17");
+insert into diaries values(2500, "2018-05-18");
+insert into diaries values(2501, "2018-05-19");
+insert into diaries values(2502, "2018-05-20");
+insert into diaries values(2503, "2018-05-21");
+insert into diaries values(2504, "2018-05-22");
+insert into diaries values(2505, "2018-05-23");
+insert into diaries values(2506, "2018-05-24");
+insert into diaries values(2507, "2018-05-25");
+insert into diaries values(2508, "2018-05-26");
+insert into diaries values(2509, "2018-05-27");
+insert into diaries values(2510, "2018-05-28");
+insert into diaries values(2511, "2018-05-29");
+insert into diaries values(2512, "2018-05-30");
+insert into diaries values(2513, "2018-05-31");
+insert into diaries values(2514, "2018-06-01");
+insert into diaries values(2515, "2018-06-02");
+insert into diaries values(2516, "2018-06-03");
+insert into diaries values(2517, "2018-06-04");
+insert into diaries values(2518, "2018-06-05");
+insert into diaries values(2519, "2018-06-06");
+insert into diaries values(2520, "2018-06-07");
+insert into diaries values(2521, "2018-06-08");
+insert into diaries values(2522, "2018-06-09");
+insert into diaries values(2523, "2018-06-10");
+insert into diaries values(2524, "2018-06-11");
+insert into diaries values(2525, "2018-06-12");
+insert into diaries values(2526, "2018-06-13");
+insert into diaries values(2527, "2018-06-14");
+insert into diaries values(2528, "2018-06-15");
+insert into diaries values(2529, "2018-06-16");
+insert into diaries values(2530, "2018-06-17");
+insert into diaries values(2531, "2018-06-18");
+insert into diaries values(2532, "2018-06-19");
+insert into diaries values(2533, "2018-06-20");
+insert into diaries values(2534, "2018-06-21");
+insert into diaries values(2535, "2018-06-22");
+insert into diaries values(2536, "2018-06-23");
+insert into diaries values(2537, "2018-06-24");
+insert into diaries values(2538, "2018-06-25");
+insert into diaries values(2539, "2018-06-26");
+insert into diaries values(2540, "2018-06-27");
+insert into diaries values(2541, "2018-06-28");
+insert into diaries values(2542, "2018-06-29");
+insert into diaries values(2543, "2018-06-30");
+insert into diaries values(2544, "2018-07-01");
+insert into diaries values(2545, "2018-07-02");
+insert into diaries values(2546, "2018-07-03");
+insert into diaries values(2547, "2018-07-04");
+insert into diaries values(2548, "2018-07-05");
+insert into diaries values(2549, "2018-07-06");
+insert into diaries values(2550, "2018-07-07");
+insert into diaries values(2551, "2018-07-08");
+insert into diaries values(2552, "2018-07-09");
+insert into diaries values(2553, "2018-07-10");
+insert into diaries values(2554, "2018-07-11");
+insert into diaries values(2555, "2018-07-12");
+insert into diaries values(2556, "2018-07-13");
+insert into diaries values(2557, "2018-07-14");
+insert into diaries values(2558, "2018-07-15");
+insert into diaries values(2559, "2018-07-16");
+insert into diaries values(2560, "2018-07-17");
+insert into diaries values(2561, "2018-07-18");
+insert into diaries values(2562, "2018-07-19");
+insert into diaries values(2563, "2018-07-20");
+insert into diaries values(2564, "2018-07-21");
+insert into diaries values(2565, "2018-07-22");
+insert into diaries values(2566, "2018-07-23");
+insert into diaries values(2567, "2018-07-24");
+insert into diaries values(2568, "2018-07-25");
+insert into diaries values(2569, "2018-07-26");
+insert into diaries values(2570, "2018-07-27");
+insert into diaries values(2571, "2018-07-28");
+insert into diaries values(2572, "2018-07-29");
+insert into diaries values(2573, "2018-07-30");
+insert into diaries values(2574, "2018-07-31");
+insert into diaries values(2575, "2018-08-01");
+insert into diaries values(2576, "2018-08-02");
+insert into diaries values(2577, "2018-08-03");
+insert into diaries values(2578, "2018-08-04");
+insert into diaries values(2579, "2018-08-05");
+insert into diaries values(2580, "2018-08-06");
+insert into diaries values(2581, "2018-08-07");
+insert into diaries values(2582, "2018-08-08");
+insert into diaries values(2583, "2018-08-09");
+insert into diaries values(2584, "2018-08-10");
+insert into diaries values(2585, "2018-08-11");
+insert into diaries values(2586, "2018-08-12");
+insert into diaries values(2587, "2018-08-13");
+insert into diaries values(2588, "2018-08-14");
+insert into diaries values(2589, "2018-08-15");
+insert into diaries values(2590, "2018-08-16");
+insert into diaries values(2591, "2018-08-17");
+insert into diaries values(2592, "2018-08-18");
+insert into diaries values(2593, "2018-08-19");
+insert into diaries values(2594, "2018-08-20");
+insert into diaries values(2595, "2018-08-21");
+insert into diaries values(2596, "2018-08-22");
+insert into diaries values(2597, "2018-08-23");
+insert into diaries values(2598, "2018-08-24");
+insert into diaries values(2599, "2018-08-25");
+insert into diaries values(2600, "2018-08-26");
+insert into diaries values(2601, "2018-08-27");
+insert into diaries values(2602, "2018-08-28");
+insert into diaries values(2603, "2018-08-29");
+insert into diaries values(2604, "2018-08-30");
+insert into diaries values(2605, "2018-08-31");
+insert into diaries values(2606, "2018-09-01");
+insert into diaries values(2607, "2018-09-02");
+insert into diaries values(2608, "2018-09-03");
+insert into diaries values(2609, "2018-09-04");
+insert into diaries values(2610, "2018-09-05");
+insert into diaries values(2611, "2018-09-06");
+insert into diaries values(2612, "2018-09-07");
+insert into diaries values(2613, "2018-09-08");
+insert into diaries values(2614, "2018-09-09");
+insert into diaries values(2615, "2018-09-10");
+insert into diaries values(2616, "2018-09-11");
+insert into diaries values(2617, "2018-09-12");
+insert into diaries values(2618, "2018-09-13");
+insert into diaries values(2619, "2018-09-14");
+insert into diaries values(2620, "2018-09-15");
+insert into diaries values(2621, "2018-09-16");
+insert into diaries values(2622, "2018-09-17");
+insert into diaries values(2623, "2018-09-18");
+insert into diaries values(2624, "2018-09-19");
+insert into diaries values(2625, "2018-09-20");
+insert into diaries values(2626, "2018-09-21");
+insert into diaries values(2627, "2018-09-22");
+insert into diaries values(2628, "2018-09-23");
+insert into diaries values(2629, "2018-09-24");
+insert into diaries values(2630, "2018-09-25");
+insert into diaries values(2631, "2018-09-26");
+insert into diaries values(2632, "2018-09-27");
+insert into diaries values(2633, "2018-09-28");
+insert into diaries values(2634, "2018-09-29");
+insert into diaries values(2635, "2018-09-30");
+insert into diaries values(2636, "2018-10-01");
+insert into diaries values(2637, "2018-10-02");
+insert into diaries values(2638, "2018-10-03");
+insert into diaries values(2639, "2018-10-04");
+insert into diaries values(2640, "2018-10-05");
+insert into diaries values(2641, "2018-10-06");
+insert into diaries values(2642, "2018-10-07");
+insert into diaries values(2643, "2018-10-08");
+insert into diaries values(2644, "2018-10-09");
+insert into diaries values(2645, "2018-10-10");
+insert into diaries values(2646, "2018-10-11");
+insert into diaries values(2647, "2018-10-12");
+insert into diaries values(2648, "2018-10-13");
+insert into diaries values(2649, "2018-10-14");
+insert into diaries values(2650, "2018-10-15");
+insert into diaries values(2651, "2018-10-16");
+insert into diaries values(2652, "2018-10-17");
+insert into diaries values(2653, "2018-10-18");
+insert into diaries values(2654, "2018-10-19");
+insert into diaries values(2655, "2018-10-20");
+insert into diaries values(2656, "2018-10-21");
+insert into diaries values(2657, "2018-10-22");
+insert into diaries values(2658, "2018-10-23");
+insert into diaries values(2659, "2018-10-24");
+insert into diaries values(2660, "2018-10-25");
+insert into diaries values(2661, "2018-10-26");
+insert into diaries values(2662, "2018-10-27");
+insert into diaries values(2663, "2018-10-28");
+insert into diaries values(2664, "2018-10-29");
+insert into diaries values(2665, "2018-10-30");
+insert into diaries values(2666, "2018-10-31");
+insert into diaries values(2667, "2018-11-01");
+insert into diaries values(2668, "2018-11-02");
+insert into diaries values(2669, "2018-11-03");
+insert into diaries values(2670, "2018-11-04");
+insert into diaries values(2671, "2018-11-05");
+insert into diaries values(2672, "2018-11-06");
+insert into diaries values(2673, "2018-11-07");
+insert into diaries values(2674, "2018-11-08");
+insert into diaries values(2675, "2018-11-09");
+insert into diaries values(2676, "2018-11-10");
+insert into diaries values(2677, "2018-11-11");
+insert into diaries values(2678, "2018-11-12");
+insert into diaries values(2679, "2018-11-13");
+insert into diaries values(2680, "2018-11-14");
+insert into diaries values(2681, "2018-11-15");
+insert into diaries values(2682, "2018-11-16");
+insert into diaries values(2683, "2018-11-17");
+insert into diaries values(2684, "2018-11-18");
+insert into diaries values(2685, "2018-11-19");
+insert into diaries values(2686, "2018-11-20");
+insert into diaries values(2687, "2018-11-21");
+insert into diaries values(2688, "2018-11-22");
+insert into diaries values(2689, "2018-11-23");
+insert into diaries values(2690, "2018-11-24");
+insert into diaries values(2691, "2018-11-25");
+insert into diaries values(2692, "2018-11-26");
+insert into diaries values(2693, "2018-11-27");
+insert into diaries values(2694, "2018-11-28");
+insert into diaries values(2695, "2018-11-29");
+insert into diaries values(2696, "2018-11-30");
+insert into diaries values(2697, "2018-12-01");
+insert into diaries values(2698, "2018-12-02");
+insert into diaries values(2699, "2018-12-03");
+insert into diaries values(2700, "2018-12-04");
+insert into diaries values(2701, "2018-12-05");
+insert into diaries values(2702, "2018-12-06");
+insert into diaries values(2703, "2018-12-07");
+insert into diaries values(2704, "2018-12-08");
+insert into diaries values(2705, "2018-12-09");
+insert into diaries values(2706, "2018-12-10");
+insert into diaries values(2707, "2018-12-11");
+insert into diaries values(2708, "2018-12-12");
+insert into diaries values(2709, "2018-12-13");
+insert into diaries values(2710, "2018-12-14");
+insert into diaries values(2711, "2018-12-15");
+insert into diaries values(2712, "2018-12-16");
+insert into diaries values(2713, "2018-12-17");
+insert into diaries values(2714, "2018-12-18");
+insert into diaries values(2715, "2018-12-19");
+insert into diaries values(2716, "2018-12-20");
+insert into diaries values(2717, "2018-12-21");
+insert into diaries values(2718, "2018-12-22");
+insert into diaries values(2719, "2018-12-23");
+insert into diaries values(2720, "2018-12-24");
+insert into diaries values(2721, "2018-12-25");
+insert into diaries values(2722, "2018-12-26");
+insert into diaries values(2723, "2018-12-27");
+insert into diaries values(2724, "2018-12-28");
+insert into diaries values(2725, "2018-12-29");
+insert into diaries values(2726, "2018-12-30");
+insert into diaries values(2727, "2018-12-31");
+insert into diaries values(2728, "2019-01-01");
+insert into diaries values(2729, "2019-01-02");
+insert into diaries values(2730, "2019-01-03");
+insert into diaries values(2731, "2019-01-04");
+insert into diaries values(2732, "2019-01-05");
+insert into diaries values(2733, "2019-01-06");
+insert into diaries values(2734, "2019-01-07");
+insert into diaries values(2735, "2019-01-08");
+insert into diaries values(2736, "2019-01-09");
+insert into diaries values(2737, "2019-01-10");
+insert into diaries values(2738, "2019-01-11");
+insert into diaries values(2739, "2019-01-12");
+insert into diaries values(2740, "2019-01-13");
+insert into diaries values(2741, "2019-01-14");
+insert into diaries values(2742, "2019-01-15");
+insert into diaries values(2743, "2019-01-16");
+insert into diaries values(2744, "2019-01-17");
+insert into diaries values(2745, "2019-01-18");
+insert into diaries values(2746, "2019-01-19");
+insert into diaries values(2747, "2019-01-20");
+insert into diaries values(2748, "2019-01-21");
+insert into diaries values(2749, "2019-01-22");
+insert into diaries values(2750, "2019-01-23");
+insert into diaries values(2751, "2019-01-24");
+insert into diaries values(2752, "2019-01-25");
+insert into diaries values(2753, "2019-01-26");
+insert into diaries values(2754, "2019-01-27");
+insert into diaries values(2755, "2019-01-28");
+insert into diaries values(2756, "2019-01-29");
+insert into diaries values(2757, "2019-01-30");
+insert into diaries values(2758, "2019-01-31");
+insert into diaries values(2759, "2019-02-01");
+insert into diaries values(2760, "2019-02-02");
+insert into diaries values(2761, "2019-02-03");
+insert into diaries values(2762, "2019-02-04");
+insert into diaries values(2763, "2019-02-05");
+insert into diaries values(2764, "2019-02-06");
+insert into diaries values(2765, "2019-02-07");
+insert into diaries values(2766, "2019-02-08");
+insert into diaries values(2767, "2019-02-09");
+insert into diaries values(2768, "2019-02-10");
+insert into diaries values(2769, "2019-02-11");
+insert into diaries values(2770, "2019-02-12");
+insert into diaries values(2771, "2019-02-13");
+insert into diaries values(2772, "2019-02-14");
+insert into diaries values(2773, "2019-02-15");
+insert into diaries values(2774, "2019-02-16");
+insert into diaries values(2775, "2019-02-17");
+insert into diaries values(2776, "2019-02-18");
+insert into diaries values(2777, "2019-02-19");
+insert into diaries values(2778, "2019-02-20");
+insert into diaries values(2779, "2019-02-21");
+insert into diaries values(2780, "2019-02-22");
+insert into diaries values(2781, "2019-02-23");
+insert into diaries values(2782, "2019-02-24");
+insert into diaries values(2783, "2019-02-25");
+insert into diaries values(2784, "2019-02-26");
+insert into diaries values(2785, "2019-02-27");
+insert into diaries values(2786, "2019-02-28");
+insert into diaries values(2787, "2019-03-01");
+insert into diaries values(2788, "2019-03-02");
+insert into diaries values(2789, "2019-03-03");
+insert into diaries values(2790, "2019-03-04");
+insert into diaries values(2791, "2019-03-05");
+insert into diaries values(2792, "2019-03-06");
+insert into diaries values(2793, "2019-03-07");
+insert into diaries values(2794, "2019-03-08");
+insert into diaries values(2795, "2019-03-09");
+insert into diaries values(2796, "2019-03-10");
+insert into diaries values(2797, "2019-03-11");
+insert into diaries values(2798, "2019-03-12");
+insert into diaries values(2799, "2019-03-13");
+insert into diaries values(2800, "2019-03-14");
+insert into diaries values(2801, "2019-03-15");
+insert into diaries values(2802, "2019-03-16");
+insert into diaries values(2803, "2019-03-17");
+insert into diaries values(2804, "2019-03-18");
+insert into diaries values(2805, "2019-03-19");
+insert into diaries values(2806, "2019-03-20");
+insert into diaries values(2807, "2019-03-21");
+insert into diaries values(2808, "2019-03-22");
+insert into diaries values(2809, "2019-03-23");
+insert into diaries values(2810, "2019-03-24");
+insert into diaries values(2811, "2019-03-25");
+insert into diaries values(2812, "2019-03-26");
+insert into diaries values(2813, "2019-03-27");
+insert into diaries values(2814, "2019-03-28");
+insert into diaries values(2815, "2019-03-29");
+insert into diaries values(2816, "2019-03-30");
+insert into diaries values(2817, "2019-03-31");
+insert into diaries values(2818, "2019-04-01");
+insert into diaries values(2819, "2019-04-02");
+insert into diaries values(2820, "2019-04-03");
+insert into diaries values(2821, "2019-04-04");
+insert into diaries values(2822, "2019-04-05");
+insert into diaries values(2823, "2019-04-06");
+insert into diaries values(2824, "2019-04-07");
+insert into diaries values(2825, "2019-04-08");
+insert into diaries values(2826, "2019-04-09");
+insert into diaries values(2827, "2019-04-10");
+insert into diaries values(2828, "2019-04-11");
+insert into diaries values(2829, "2019-04-12");
+insert into diaries values(2830, "2019-04-13");
+insert into diaries values(2831, "2019-04-14");
+insert into diaries values(2832, "2019-04-15");
+insert into diaries values(2833, "2019-04-16");
+insert into diaries values(2834, "2019-04-17");
+insert into diaries values(2835, "2019-04-18");
+insert into diaries values(2836, "2019-04-19");
+insert into diaries values(2837, "2019-04-20");
+insert into diaries values(2838, "2019-04-21");
+insert into diaries values(2839, "2019-04-22");
+insert into diaries values(2840, "2019-04-23");
+insert into diaries values(2841, "2019-04-24");
+insert into diaries values(2842, "2019-04-25");
+insert into diaries values(2843, "2019-04-26");
+insert into diaries values(2844, "2019-04-27");
+insert into diaries values(2845, "2019-04-28");
+insert into diaries values(2846, "2019-04-29");
+insert into diaries values(2847, "2019-04-30");
+insert into diaries values(2848, "2019-05-01");
+insert into diaries values(2849, "2019-05-02");
+insert into diaries values(2850, "2019-05-03");
+insert into diaries values(2851, "2019-05-04");
+insert into diaries values(2852, "2019-05-05");
+insert into diaries values(2853, "2019-05-06");
+insert into diaries values(2854, "2019-05-07");
+insert into diaries values(2855, "2019-05-08");
+insert into diaries values(2856, "2019-05-09");
+insert into diaries values(2857, "2019-05-10");
+insert into diaries values(2858, "2019-05-11");
+insert into diaries values(2859, "2019-05-12");
+insert into diaries values(2860, "2019-05-13");
+insert into diaries values(2861, "2019-05-14");
+insert into diaries values(2862, "2019-05-15");
+insert into diaries values(2863, "2019-05-16");
+insert into diaries values(2864, "2019-05-17");
+insert into diaries values(2865, "2019-05-18");
+insert into diaries values(2866, "2019-05-19");
+insert into diaries values(2867, "2019-05-20");
+insert into diaries values(2868, "2019-05-21");
+insert into diaries values(2869, "2019-05-22");
+insert into diaries values(2870, "2019-05-23");
+insert into diaries values(2871, "2019-05-24");
+insert into diaries values(2872, "2019-05-25");
+insert into diaries values(2873, "2019-05-26");
+insert into diaries values(2874, "2019-05-27");
+insert into diaries values(2875, "2019-05-28");
+insert into diaries values(2876, "2019-05-29");
+insert into diaries values(2877, "2019-05-30");
+insert into diaries values(2878, "2019-05-31");
+insert into diaries values(2879, "2019-06-01");
+insert into diaries values(2880, "2019-06-02");
+insert into diaries values(2881, "2019-06-03");
+insert into diaries values(2882, "2019-06-04");
+insert into diaries values(2883, "2019-06-05");
+insert into diaries values(2884, "2019-06-06");
+insert into diaries values(2885, "2019-06-07");
+insert into diaries values(2886, "2019-06-08");
+insert into diaries values(2887, "2019-06-09");
+insert into diaries values(2888, "2019-06-10");
+insert into diaries values(2889, "2019-06-11");
+insert into diaries values(2890, "2019-06-12");
+insert into diaries values(2891, "2019-06-13");
+insert into diaries values(2892, "2019-06-14");
+insert into diaries values(2893, "2019-06-15");
+insert into diaries values(2894, "2019-06-16");
+insert into diaries values(2895, "2019-06-17");
+insert into diaries values(2896, "2019-06-18");
+insert into diaries values(2897, "2019-06-19");
+insert into diaries values(2898, "2019-06-20");
+insert into diaries values(2899, "2019-06-21");
+insert into diaries values(2900, "2019-06-22");
+insert into diaries values(2901, "2019-06-23");
+insert into diaries values(2902, "2019-06-24");
+insert into diaries values(2903, "2019-06-25");
+insert into diaries values(2904, "2019-06-26");
+insert into diaries values(2905, "2019-06-27");
+insert into diaries values(2906, "2019-06-28");
+insert into diaries values(2907, "2019-06-29");
+insert into diaries values(2908, "2019-06-30");
+insert into diaries values(2909, "2019-07-01");
+insert into diaries values(2910, "2019-07-02");
+insert into diaries values(2911, "2019-07-03");
+insert into diaries values(2912, "2019-07-04");
+insert into diaries values(2913, "2019-07-05");
+insert into diaries values(2914, "2019-07-06");
+insert into diaries values(2915, "2019-07-07");
+insert into diaries values(2916, "2019-07-08");
+insert into diaries values(2917, "2019-07-09");
+insert into diaries values(2918, "2019-07-10");
+insert into diaries values(2919, "2019-07-11");
+insert into diaries values(2920, "2019-07-12");
+insert into diaries values(2921, "2019-07-13");
+insert into diaries values(2922, "2019-07-14");
+insert into diaries values(2923, "2019-07-15");
+insert into diaries values(2924, "2019-07-16");
+insert into diaries values(2925, "2019-07-17");
+insert into diaries values(2926, "2019-07-18");
+insert into diaries values(2927, "2019-07-19");
+insert into diaries values(2928, "2019-07-20");
+insert into diaries values(2929, "2019-07-21");
+insert into diaries values(2930, "2019-07-22");
+insert into diaries values(2931, "2019-07-23");
+insert into diaries values(2932, "2019-07-24");
+insert into diaries values(2933, "2019-07-25");
+insert into diaries values(2934, "2019-07-26");
+insert into diaries values(2935, "2019-07-27");
+insert into diaries values(2936, "2019-07-28");
+insert into diaries values(2937, "2019-07-29");
+insert into diaries values(2938, "2019-07-30");
+insert into diaries values(2939, "2019-07-31");
+insert into diaries values(2940, "2019-08-01");
+insert into diaries values(2941, "2019-08-02");
+insert into diaries values(2942, "2019-08-03");
+insert into diaries values(2943, "2019-08-04");
+insert into diaries values(2944, "2019-08-05");
+insert into diaries values(2945, "2019-08-06");
+insert into diaries values(2946, "2019-08-07");
+insert into diaries values(2947, "2019-08-08");
+insert into diaries values(2948, "2019-08-09");
+insert into diaries values(2949, "2019-08-10");
+insert into diaries values(2950, "2019-08-11");
+insert into diaries values(2951, "2019-08-12");
+insert into diaries values(2952, "2019-08-13");
+insert into diaries values(2953, "2019-08-14");
+insert into diaries values(2954, "2019-08-15");
+insert into diaries values(2955, "2019-08-16");
+insert into diaries values(2956, "2019-08-17");
+insert into diaries values(2957, "2019-08-18");
+insert into diaries values(2958, "2019-08-19");
+insert into diaries values(2959, "2019-08-20");
+insert into diaries values(2960, "2019-08-21");
+insert into diaries values(2961, "2019-08-22");
+insert into diaries values(2962, "2019-08-23");
+insert into diaries values(2963, "2019-08-24");
+insert into diaries values(2964, "2019-08-25");
+insert into diaries values(2965, "2019-08-26");
+insert into diaries values(2966, "2019-08-27");
+insert into diaries values(2967, "2019-08-28");
+insert into diaries values(2968, "2019-08-29");
+insert into diaries values(2969, "2019-08-30");
+insert into diaries values(2970, "2019-08-31");
+insert into diaries values(2971, "2019-09-01");
+insert into diaries values(2972, "2019-09-02");
+insert into diaries values(2973, "2019-09-03");
+insert into diaries values(2974, "2019-09-04");
+insert into diaries values(2975, "2019-09-05");
+insert into diaries values(2976, "2019-09-06");
+insert into diaries values(2977, "2019-09-07");
+insert into diaries values(2978, "2019-09-08");
+insert into diaries values(2979, "2019-09-09");
+insert into diaries values(2980, "2019-09-10");
+insert into diaries values(2981, "2019-09-11");
+insert into diaries values(2982, "2019-09-12");
+insert into diaries values(2983, "2019-09-13");
+insert into diaries values(2984, "2019-09-14");
+insert into diaries values(2985, "2019-09-15");
+insert into diaries values(2986, "2019-09-16");
+insert into diaries values(2987, "2019-09-17");
+insert into diaries values(2988, "2019-09-18");
+insert into diaries values(2989, "2019-09-19");
+insert into diaries values(2990, "2019-09-20");
+insert into diaries values(2991, "2019-09-21");
+insert into diaries values(2992, "2019-09-22");
+insert into diaries values(2993, "2019-09-23");
+insert into diaries values(2994, "2019-09-24");
+insert into diaries values(2995, "2019-09-25");
+insert into diaries values(2996, "2019-09-26");
+insert into diaries values(2997, "2019-09-27");
+insert into diaries values(2998, "2019-09-28");
+insert into diaries values(2999, "2019-09-29");
+insert into diaries values(3000, "2019-09-30");
+insert into diaries values(3001, "2019-10-01");
+insert into diaries values(3002, "2019-10-02");
+insert into diaries values(3003, "2019-10-03");
+insert into diaries values(3004, "2019-10-04");
+insert into diaries values(3005, "2019-10-05");
+insert into diaries values(3006, "2019-10-06");
+insert into diaries values(3007, "2019-10-07");
+insert into diaries values(3008, "2019-10-08");
+insert into diaries values(3009, "2019-10-09");
+insert into diaries values(3010, "2019-10-10");
+insert into diaries values(3011, "2019-10-11");
+insert into diaries values(3012, "2019-10-12");
+insert into diaries values(3013, "2019-10-13");
+insert into diaries values(3014, "2019-10-14");
+insert into diaries values(3015, "2019-10-15");
+insert into diaries values(3016, "2019-10-16");
+insert into diaries values(3017, "2019-10-17");
+insert into diaries values(3018, "2019-10-18");
+insert into diaries values(3019, "2019-10-19");
+insert into diaries values(3020, "2019-10-20");
+insert into diaries values(3021, "2019-10-21");
+insert into diaries values(3022, "2019-10-22");
+insert into diaries values(3023, "2019-10-23");
+insert into diaries values(3024, "2019-10-24");
+insert into diaries values(3025, "2019-10-25");
+insert into diaries values(3026, "2019-10-26");
+insert into diaries values(3027, "2019-10-27");
+insert into diaries values(3028, "2019-10-28");
+insert into diaries values(3029, "2019-10-29");
+insert into diaries values(3030, "2019-10-30");
+insert into diaries values(3031, "2019-10-31");
+insert into diaries values(3032, "2019-11-01");
+insert into diaries values(3033, "2019-11-02");
+insert into diaries values(3034, "2019-11-03");
+insert into diaries values(3035, "2019-11-04");
+insert into diaries values(3036, "2019-11-05");
+insert into diaries values(3037, "2019-11-06");
+insert into diaries values(3038, "2019-11-07");
+insert into diaries values(3039, "2019-11-08");
+insert into diaries values(3040, "2019-11-09");
+insert into diaries values(3041, "2019-11-10");
+insert into diaries values(3042, "2019-11-11");
+insert into diaries values(3043, "2019-11-12");
+insert into diaries values(3044, "2019-11-13");
+insert into diaries values(3045, "2019-11-14");
+insert into diaries values(3046, "2019-11-15");
+insert into diaries values(3047, "2019-11-16");
+insert into diaries values(3048, "2019-11-17");
+insert into diaries values(3049, "2019-11-18");
+insert into diaries values(3050, "2019-11-19");
+insert into diaries values(3051, "2019-11-20");
+insert into diaries values(3052, "2019-11-21");
+insert into diaries values(3053, "2019-11-22");
+insert into diaries values(3054, "2019-11-23");
+insert into diaries values(3055, "2019-11-24");
+insert into diaries values(3056, "2019-11-25");
+insert into diaries values(3057, "2019-11-26");
+insert into diaries values(3058, "2019-11-27");
+insert into diaries values(3059, "2019-11-28");
+insert into diaries values(3060, "2019-11-29");
+insert into diaries values(3061, "2019-11-30");
+insert into diaries values(3062, "2019-12-01");
+insert into diaries values(3063, "2019-12-02");
+insert into diaries values(3064, "2019-12-03");
+insert into diaries values(3065, "2019-12-04");
+insert into diaries values(3066, "2019-12-05");
+insert into diaries values(3067, "2019-12-06");
+insert into diaries values(3068, "2019-12-07");
+insert into diaries values(3069, "2019-12-08");
+insert into diaries values(3070, "2019-12-09");
+insert into diaries values(3071, "2019-12-10");
+insert into diaries values(3072, "2019-12-11");
+insert into diaries values(3073, "2019-12-12");
+insert into diaries values(3074, "2019-12-13");
+insert into diaries values(3075, "2019-12-14");
+insert into diaries values(3076, "2019-12-15");
+insert into diaries values(3077, "2019-12-16");
+insert into diaries values(3078, "2019-12-17");
+insert into diaries values(3079, "2019-12-18");
+insert into diaries values(3080, "2019-12-19");
+insert into diaries values(3081, "2019-12-20");
+insert into diaries values(3082, "2019-12-21");
+insert into diaries values(3083, "2019-12-22");
+insert into diaries values(3084, "2019-12-23");
+insert into diaries values(3085, "2019-12-24");
+insert into diaries values(3086, "2019-12-25");
+insert into diaries values(3087, "2019-12-26");
+insert into diaries values(3088, "2019-12-27");
+insert into diaries values(3089, "2019-12-28");
+insert into diaries values(3090, "2019-12-29");
+insert into diaries values(3091, "2019-12-30");
+insert into diaries values(3092, "2019-12-31");
+insert into diaries values(3093, "2020-01-01");
+insert into diaries values(3094, "2020-01-02");
+insert into diaries values(3095, "2020-01-03");
+insert into diaries values(3096, "2020-01-04");
+insert into diaries values(3097, "2020-01-05");
+insert into diaries values(3098, "2020-01-06");
+insert into diaries values(3099, "2020-01-07");
+insert into diaries values(3100, "2020-01-08");
+insert into diaries values(3101, "2020-01-09");
+insert into diaries values(3102, "2020-01-10");
+insert into diaries values(3103, "2020-01-11");
+insert into diaries values(3104, "2020-01-12");
+insert into diaries values(3105, "2020-01-13");
+insert into diaries values(3106, "2020-01-14");
+insert into diaries values(3107, "2020-01-15");
+insert into diaries values(3108, "2020-01-16");
+insert into diaries values(3109, "2020-01-17");
+insert into diaries values(3110, "2020-01-18");
+insert into diaries values(3111, "2020-01-19");
+insert into diaries values(3112, "2020-01-20");
+insert into diaries values(3113, "2020-01-21");
+insert into diaries values(3114, "2020-01-22");
+insert into diaries values(3115, "2020-01-23");
+insert into diaries values(3116, "2020-01-24");
+insert into diaries values(3117, "2020-01-25");
+insert into diaries values(3118, "2020-01-26");
+insert into diaries values(3119, "2020-01-27");
+insert into diaries values(3120, "2020-01-28");
+insert into diaries values(3121, "2020-01-29");
+insert into diaries values(3122, "2020-01-30");
+insert into diaries values(3123, "2020-01-31");
+insert into diaries values(3124, "2020-02-01");
+insert into diaries values(3125, "2020-02-02");
+insert into diaries values(3126, "2020-02-03");
+insert into diaries values(3127, "2020-02-04");
+insert into diaries values(3128, "2020-02-05");
+insert into diaries values(3129, "2020-02-06");
+insert into diaries values(3130, "2020-02-07");
+insert into diaries values(3131, "2020-02-08");
+insert into diaries values(3132, "2020-02-09");
+insert into diaries values(3133, "2020-02-10");
+insert into diaries values(3134, "2020-02-11");
+insert into diaries values(3135, "2020-02-12");
+insert into diaries values(3136, "2020-02-13");
+insert into diaries values(3137, "2020-02-14");
+insert into diaries values(3138, "2020-02-15");
+insert into diaries values(3139, "2020-02-16");
+insert into diaries values(3140, "2020-02-17");
+insert into diaries values(3141, "2020-02-18");
+insert into diaries values(3142, "2020-02-19");
+insert into diaries values(3143, "2020-02-20");
+insert into diaries values(3144, "2020-02-21");
+insert into diaries values(3145, "2020-02-22");
+insert into diaries values(3146, "2020-02-23");
+insert into diaries values(3147, "2020-02-24");
+insert into diaries values(3148, "2020-02-25");
+insert into diaries values(3149, "2020-02-26");
+insert into diaries values(3150, "2020-02-27");
+insert into diaries values(3151, "2020-02-28");
+insert into diaries values(3152, "2020-02-29");
+insert into diaries values(3153, "2020-03-01");
+insert into diaries values(3154, "2020-03-02");
+insert into diaries values(3155, "2020-03-03");
+insert into diaries values(3156, "2020-03-04");
+insert into diaries values(3157, "2020-03-05");
+insert into diaries values(3158, "2020-03-06");
+insert into diaries values(3159, "2020-03-07");
+insert into diaries values(3160, "2020-03-08");
+insert into diaries values(3161, "2020-03-09");
+insert into diaries values(3162, "2020-03-10");
+insert into diaries values(3163, "2020-03-11");
+insert into diaries values(3164, "2020-03-12");
+insert into diaries values(3165, "2020-03-13");
+insert into diaries values(3166, "2020-03-14");
+insert into diaries values(3167, "2020-03-15");
+insert into diaries values(3168, "2020-03-16");
+insert into diaries values(3169, "2020-03-17");
+insert into diaries values(3170, "2020-03-18");
+insert into diaries values(3171, "2020-03-19");
+insert into diaries values(3172, "2020-03-20");
+insert into diaries values(3173, "2020-03-21");
+insert into diaries values(3174, "2020-03-22");
+insert into diaries values(3175, "2020-03-23");
+insert into diaries values(3176, "2020-03-24");
+insert into diaries values(3177, "2020-03-25");
+insert into diaries values(3178, "2020-03-26");
+insert into diaries values(3179, "2020-03-27");
+insert into diaries values(3180, "2020-03-28");
+insert into diaries values(3181, "2020-03-29");
+insert into diaries values(3182, "2020-03-30");
+insert into diaries values(3183, "2020-03-31");
+insert into diaries values(3184, "2020-04-01");
+insert into diaries values(3185, "2020-04-02");
+insert into diaries values(3186, "2020-04-03");
+insert into diaries values(3187, "2020-04-04");
+insert into diaries values(3188, "2020-04-05");
+insert into diaries values(3189, "2020-04-06");
+insert into diaries values(3190, "2020-04-07");
+insert into diaries values(3191, "2020-04-08");
+insert into diaries values(3192, "2020-04-09");
+insert into diaries values(3193, "2020-04-10");
+insert into diaries values(3194, "2020-04-11");
+insert into diaries values(3195, "2020-04-12");
+insert into diaries values(3196, "2020-04-13");
+insert into diaries values(3197, "2020-04-14");
+insert into diaries values(3198, "2020-04-15");
+insert into diaries values(3199, "2020-04-16");
+insert into diaries values(3200, "2020-04-17");
+insert into diaries values(3201, "2020-04-18");
+insert into diaries values(3202, "2020-04-19");
+insert into diaries values(3203, "2020-04-20");
+insert into diaries values(3204, "2020-04-21");
+insert into diaries values(3205, "2020-04-22");
+insert into diaries values(3206, "2020-04-23");
+insert into diaries values(3207, "2020-04-24");
+insert into diaries values(3208, "2020-04-25");
+insert into diaries values(3209, "2020-04-26");
+insert into diaries values(3210, "2020-04-27");
+insert into diaries values(3211, "2020-04-28");
+insert into diaries values(3212, "2020-04-29");
+insert into diaries values(3213, "2020-04-30");
+insert into diaries values(3214, "2020-05-01");
+insert into diaries values(3215, "2020-05-02");
+insert into diaries values(3216, "2020-05-03");
+insert into diaries values(3217, "2020-05-04");
+insert into diaries values(3218, "2020-05-05");
+insert into diaries values(3219, "2020-05-06");
+insert into diaries values(3220, "2020-05-07");
+insert into diaries values(3221, "2020-05-08");
+insert into diaries values(3222, "2020-05-09");
+insert into diaries values(3223, "2020-05-10");
+insert into diaries values(3224, "2020-05-11");
+insert into diaries values(3225, "2020-05-12");
+insert into diaries values(3226, "2020-05-13");
+insert into diaries values(3227, "2020-05-14");
+insert into diaries values(3228, "2020-05-15");
+insert into diaries values(3229, "2020-05-16");
+insert into diaries values(3230, "2020-05-17");
+insert into diaries values(3231, "2020-05-18");
+insert into diaries values(3232, "2020-05-19");
+insert into diaries values(3233, "2020-05-20");
+insert into diaries values(3234, "2020-05-21");
+insert into diaries values(3235, "2020-05-22");
+insert into diaries values(3236, "2020-05-23");
+insert into diaries values(3237, "2020-05-24");
+insert into diaries values(3238, "2020-05-25");
+insert into diaries values(3239, "2020-05-26");
+insert into diaries values(3240, "2020-05-27");
+insert into diaries values(3241, "2020-05-28");
+insert into diaries values(3242, "2020-05-29");
+insert into diaries values(3243, "2020-05-30");
+insert into diaries values(3244, "2020-05-31");
+insert into diaries values(3245, "2020-06-01");
+insert into diaries values(3246, "2020-06-02");
+insert into diaries values(3247, "2020-06-03");
+insert into diaries values(3248, "2020-06-04");
+insert into diaries values(3249, "2020-06-05");
+insert into diaries values(3250, "2020-06-06");
+insert into diaries values(3251, "2020-06-07");
+insert into diaries values(3252, "2020-06-08");
+insert into diaries values(3253, "2020-06-09");
+insert into diaries values(3254, "2020-06-10");
+insert into diaries values(3255, "2020-06-11");
+insert into diaries values(3256, "2020-06-12");
+insert into diaries values(3257, "2020-06-13");
+insert into diaries values(3258, "2020-06-14");
+insert into diaries values(3259, "2020-06-15");
+insert into diaries values(3260, "2020-06-16");
+insert into diaries values(3261, "2020-06-17");
+insert into diaries values(3262, "2020-06-18");
+insert into diaries values(3263, "2020-06-19");
+insert into diaries values(3264, "2020-06-20");
+insert into diaries values(3265, "2020-06-21");
+insert into diaries values(3266, "2020-06-22");
+insert into diaries values(3267, "2020-06-23");
+insert into diaries values(3268, "2020-06-24");
+insert into diaries values(3269, "2020-06-25");
+insert into diaries values(3270, "2020-06-26");
+insert into diaries values(3271, "2020-06-27");
+insert into diaries values(3272, "2020-06-28");
+insert into diaries values(3273, "2020-06-29");
+insert into diaries values(3274, "2020-06-30");
+insert into diaries values(3275, "2020-07-01");
+insert into diaries values(3276, "2020-07-02");
+insert into diaries values(3277, "2020-07-03");
+insert into diaries values(3278, "2020-07-04");
+insert into diaries values(3279, "2020-07-05");
+insert into diaries values(3280, "2020-07-06");
+insert into diaries values(3281, "2020-07-07");
+insert into diaries values(3282, "2020-07-08");
+insert into diaries values(3283, "2020-07-09");
+insert into diaries values(3284, "2020-07-10");
+insert into diaries values(3285, "2020-07-11");
+insert into diaries values(3286, "2020-07-12");
+insert into diaries values(3287, "2020-07-13");
+insert into diaries values(3288, "2020-07-14");
+insert into diaries values(3289, "2020-07-15");
+insert into diaries values(3290, "2020-07-16");
+insert into diaries values(3291, "2020-07-17");
+insert into diaries values(3292, "2020-07-18");
+insert into diaries values(3293, "2020-07-19");
+insert into diaries values(3294, "2020-07-20");
+insert into diaries values(3295, "2020-07-21");
+insert into diaries values(3296, "2020-07-22");
+insert into diaries values(3297, "2020-07-23");
+insert into diaries values(3298, "2020-07-24");
+insert into diaries values(3299, "2020-07-25");
+insert into diaries values(3300, "2020-07-26");
+insert into diaries values(3301, "2020-07-27");
+insert into diaries values(3302, "2020-07-28");
+insert into diaries values(3303, "2020-07-29");
+insert into diaries values(3304, "2020-07-30");
+insert into diaries values(3305, "2020-07-31");
+insert into diaries values(3306, "2020-08-01");
+insert into diaries values(3307, "2020-08-02");
+insert into diaries values(3308, "2020-08-03");
+insert into diaries values(3309, "2020-08-04");
+insert into diaries values(3310, "2020-08-05");
+insert into diaries values(3311, "2020-08-06");
+insert into diaries values(3312, "2020-08-07");
+insert into diaries values(3313, "2020-08-08");
+insert into diaries values(3314, "2020-08-09");
+insert into diaries values(3315, "2020-08-10");
+insert into diaries values(3316, "2020-08-11");
+insert into diaries values(3317, "2020-08-12");
+insert into diaries values(3318, "2020-08-13");
+insert into diaries values(3319, "2020-08-14");
+insert into diaries values(3320, "2020-08-15");
+insert into diaries values(3321, "2020-08-16");
+insert into diaries values(3322, "2020-08-17");
+insert into diaries values(3323, "2020-08-18");
+insert into diaries values(3324, "2020-08-19");
+insert into diaries values(3325, "2020-08-20");
+insert into diaries values(3326, "2020-08-21");
+insert into diaries values(3327, "2020-08-22");
+insert into diaries values(3328, "2020-08-23");
+insert into diaries values(3329, "2020-08-24");
+insert into diaries values(3330, "2020-08-25");
+insert into diaries values(3331, "2020-08-26");
+insert into diaries values(3332, "2020-08-27");
+insert into diaries values(3333, "2020-08-28");
+insert into diaries values(3334, "2020-08-29");
+insert into diaries values(3335, "2020-08-30");
+insert into diaries values(3336, "2020-08-31");
+insert into diaries values(3337, "2020-09-01");
+insert into diaries values(3338, "2020-09-02");
+insert into diaries values(3339, "2020-09-03");
+insert into diaries values(3340, "2020-09-04");
+insert into diaries values(3341, "2020-09-05");
+insert into diaries values(3342, "2020-09-06");
+insert into diaries values(3343, "2020-09-07");
+insert into diaries values(3344, "2020-09-08");
+insert into diaries values(3345, "2020-09-09");
+insert into diaries values(3346, "2020-09-10");
+insert into diaries values(3347, "2020-09-11");
+insert into diaries values(3348, "2020-09-12");
+insert into diaries values(3349, "2020-09-13");
+insert into diaries values(3350, "2020-09-14");
+insert into diaries values(3351, "2020-09-15");
+insert into diaries values(3352, "2020-09-16");
+insert into diaries values(3353, "2020-09-17");
+insert into diaries values(3354, "2020-09-18");
+insert into diaries values(3355, "2020-09-19");
+insert into diaries values(3356, "2020-09-20");
+insert into diaries values(3357, "2020-09-21");
+insert into diaries values(3358, "2020-09-22");
+insert into diaries values(3359, "2020-09-23");
+insert into diaries values(3360, "2020-09-24");
+insert into diaries values(3361, "2020-09-25");
+insert into diaries values(3362, "2020-09-26");
+insert into diaries values(3363, "2020-09-27");
+insert into diaries values(3364, "2020-09-28");
+insert into diaries values(3365, "2020-09-29");
+insert into diaries values(3366, "2020-09-30");
+insert into diaries values(3367, "2020-10-01");
+insert into diaries values(3368, "2020-10-02");
+insert into diaries values(3369, "2020-10-03");
+insert into diaries values(3370, "2020-10-04");
+insert into diaries values(3371, "2020-10-05");
+insert into diaries values(3372, "2020-10-06");
+insert into diaries values(3373, "2020-10-07");
+insert into diaries values(3374, "2020-10-08");
+insert into diaries values(3375, "2020-10-09");
+insert into diaries values(3376, "2020-10-10");
+insert into diaries values(3377, "2020-10-11");
+insert into diaries values(3378, "2020-10-12");
+insert into diaries values(3379, "2020-10-13");
+insert into diaries values(3380, "2020-10-14");
+insert into diaries values(3381, "2020-10-15");
+insert into diaries values(3382, "2020-10-16");
+insert into diaries values(3383, "2020-10-17");
+insert into diaries values(3384, "2020-10-18");
+insert into diaries values(3385, "2020-10-19");
+insert into diaries values(3386, "2020-10-20");
+insert into diaries values(3387, "2020-10-21");
+insert into diaries values(3388, "2020-10-22");
+insert into diaries values(3389, "2020-10-23");
+insert into diaries values(3390, "2020-10-24");
+insert into diaries values(3391, "2020-10-25");
+insert into diaries values(3392, "2020-10-26");
+insert into diaries values(3393, "2020-10-27");
+insert into diaries values(3394, "2020-10-28");
+insert into diaries values(3395, "2020-10-29");
+insert into diaries values(3396, "2020-10-30");
+insert into diaries values(3397, "2020-10-31");
+insert into diaries values(3398, "2020-11-01");
+insert into diaries values(3399, "2020-11-02");
+insert into diaries values(3400, "2020-11-03");
+insert into diaries values(3401, "2020-11-04");
+insert into diaries values(3402, "2020-11-05");
+insert into diaries values(3403, "2020-11-06");
+insert into diaries values(3404, "2020-11-07");
+insert into diaries values(3405, "2020-11-08");
+insert into diaries values(3406, "2020-11-09");
+insert into diaries values(3407, "2020-11-10");
+insert into diaries values(3408, "2020-11-11");
+insert into diaries values(3409, "2020-11-12");
+insert into diaries values(3410, "2020-11-13");
+insert into diaries values(3411, "2020-11-14");
+insert into diaries values(3412, "2020-11-15");
+insert into diaries values(3413, "2020-11-16");
+insert into diaries values(3414, "2020-11-17");
+insert into diaries values(3415, "2020-11-18");
+insert into diaries values(3416, "2020-11-19");
+insert into diaries values(3417, "2020-11-20");
+insert into diaries values(3418, "2020-11-21");
+insert into diaries values(3419, "2020-11-22");
+insert into diaries values(3420, "2020-11-23");
+insert into diaries values(3421, "2020-11-24");
+insert into diaries values(3422, "2020-11-25");
+insert into diaries values(3423, "2020-11-26");
+insert into diaries values(3424, "2020-11-27");
+insert into diaries values(3425, "2020-11-28");
+insert into diaries values(3426, "2020-11-29");
+insert into diaries values(3427, "2020-11-30");
+insert into diaries values(3428, "2020-12-01");
+insert into diaries values(3429, "2020-12-02");
+insert into diaries values(3430, "2020-12-03");
+insert into diaries values(3431, "2020-12-04");
+insert into diaries values(3432, "2020-12-05");
+insert into diaries values(3433, "2020-12-06");
+insert into diaries values(3434, "2020-12-07");
+insert into diaries values(3435, "2020-12-08");
+insert into diaries values(3436, "2020-12-09");
+insert into diaries values(3437, "2020-12-10");
+insert into diaries values(3438, "2020-12-11");
+insert into diaries values(3439, "2020-12-12");
+insert into diaries values(3440, "2020-12-13");
+insert into diaries values(3441, "2020-12-14");
+insert into diaries values(3442, "2020-12-15");
+insert into diaries values(3443, "2020-12-16");
+insert into diaries values(3444, "2020-12-17");
+insert into diaries values(3445, "2020-12-18");
+insert into diaries values(3446, "2020-12-19");
+insert into diaries values(3447, "2020-12-20");
+insert into diaries values(3448, "2020-12-21");
+insert into diaries values(3449, "2020-12-22");
+insert into diaries values(3450, "2020-12-23");
+insert into diaries values(3451, "2020-12-24");
+insert into diaries values(3452, "2020-12-25");
+insert into diaries values(3453, "2020-12-26");
+insert into diaries values(3454, "2020-12-27");
+insert into diaries values(3455, "2020-12-28");
+insert into diaries values(3456, "2020-12-29");
+insert into diaries values(3457, "2020-12-30");
+insert into diaries values(3458, "2020-12-31");
+insert into diaries values(3459, "2021-01-01");
+insert into diaries values(3460, "2021-01-02");
+insert into diaries values(3461, "2021-01-03");
+insert into diaries values(3462, "2021-01-04");
+insert into diaries values(3463, "2021-01-05");
+insert into diaries values(3464, "2021-01-06");
+insert into diaries values(3465, "2021-01-07");
+insert into diaries values(3466, "2021-01-08");
+insert into diaries values(3467, "2021-01-09");
+insert into diaries values(3468, "2021-01-10");
+insert into diaries values(3469, "2021-01-11");
+insert into diaries values(3470, "2021-01-12");
+insert into diaries values(3471, "2021-01-13");
+insert into diaries values(3472, "2021-01-14");
+insert into diaries values(3473, "2021-01-15");
+insert into diaries values(3474, "2021-01-16");
+insert into diaries values(3475, "2021-01-17");
+insert into diaries values(3476, "2021-01-18");
+insert into diaries values(3477, "2021-01-19");
+insert into diaries values(3478, "2021-01-20");
+insert into diaries values(3479, "2021-01-21");
+insert into diaries values(3480, "2021-01-22");
+insert into diaries values(3481, "2021-01-23");
+insert into diaries values(3482, "2021-01-24");
+insert into diaries values(3483, "2021-01-25");
+insert into diaries values(3484, "2021-01-26");
+insert into diaries values(3485, "2021-01-27");
+insert into diaries values(3486, "2021-01-28");
+insert into diaries values(3487, "2021-01-29");
+insert into diaries values(3488, "2021-01-30");
+insert into diaries values(3489, "2021-01-31");
+insert into diaries values(3490, "2021-02-01");
+insert into diaries values(3491, "2021-02-02");
+insert into diaries values(3492, "2021-02-03");
+insert into diaries values(3493, "2021-02-04");
+insert into diaries values(3494, "2021-02-05");
+insert into diaries values(3495, "2021-02-06");
+insert into diaries values(3496, "2021-02-07");
+insert into diaries values(3497, "2021-02-08");
+insert into diaries values(3498, "2021-02-09");
+insert into diaries values(3499, "2021-02-10");
+insert into diaries values(3500, "2021-02-11");
+insert into diaries values(3501, "2021-02-12");
+insert into diaries values(3502, "2021-02-13");
+insert into diaries values(3503, "2021-02-14");
+insert into diaries values(3504, "2021-02-15");
+insert into diaries values(3505, "2021-02-16");
+insert into diaries values(3506, "2021-02-17");
+insert into diaries values(3507, "2021-02-18");
+insert into diaries values(3508, "2021-02-19");
+insert into diaries values(3509, "2021-02-20");
+insert into diaries values(3510, "2021-02-21");
+insert into diaries values(3511, "2021-02-22");
+insert into diaries values(3512, "2021-02-23");
+insert into diaries values(3513, "2021-02-24");
+insert into diaries values(3514, "2021-02-25");
+insert into diaries values(3515, "2021-02-26");
+insert into diaries values(3516, "2021-02-27");
+insert into diaries values(3517, "2021-02-28");
+insert into diaries values(3518, "2021-03-01");
+insert into diaries values(3519, "2021-03-02");
+insert into diaries values(3520, "2021-03-03");
+insert into diaries values(3521, "2021-03-04");
+insert into diaries values(3522, "2021-03-05");
+insert into diaries values(3523, "2021-03-06");
+insert into diaries values(3524, "2021-03-07");
+insert into diaries values(3525, "2021-03-08");
+insert into diaries values(3526, "2021-03-09");
+insert into diaries values(3527, "2021-03-10");
+insert into diaries values(3528, "2021-03-11");
+insert into diaries values(3529, "2021-03-12");
+insert into diaries values(3530, "2021-03-13");
+insert into diaries values(3531, "2021-03-14");
+insert into diaries values(3532, "2021-03-15");
+insert into diaries values(3533, "2021-03-16");
+insert into diaries values(3534, "2021-03-17");
+insert into diaries values(3535, "2021-03-18");
+insert into diaries values(3536, "2021-03-19");
+insert into diaries values(3537, "2021-03-20");
+insert into diaries values(3538, "2021-03-21");
+insert into diaries values(3539, "2021-03-22");
+insert into diaries values(3540, "2021-03-23");
+insert into diaries values(3541, "2021-03-24");
+insert into diaries values(3542, "2021-03-25");
+insert into diaries values(3543, "2021-03-26");
+insert into diaries values(3544, "2021-03-27");
+insert into diaries values(3545, "2021-03-28");
+insert into diaries values(3546, "2021-03-29");
+insert into diaries values(3547, "2021-03-30");
+insert into diaries values(3548, "2021-03-31");
+insert into diaries values(3549, "2021-04-01");
+insert into diaries values(3550, "2021-04-02");
+insert into diaries values(3551, "2021-04-03");
+insert into diaries values(3552, "2021-04-04");
+insert into diaries values(3553, "2021-04-05");
+insert into diaries values(3554, "2021-04-06");
+insert into diaries values(3555, "2021-04-07");
+insert into diaries values(3556, "2021-04-08");
+insert into diaries values(3557, "2021-04-09");
+insert into diaries values(3558, "2021-04-10");
+insert into diaries values(3559, "2021-04-11");
+insert into diaries values(3560, "2021-04-12");
+insert into diaries values(3561, "2021-04-13");
+insert into diaries values(3562, "2021-04-14");
+insert into diaries values(3563, "2021-04-15");
+insert into diaries values(3564, "2021-04-16");
+insert into diaries values(3565, "2021-04-17");
+insert into diaries values(3566, "2021-04-18");
+insert into diaries values(3567, "2021-04-19");
+insert into diaries values(3568, "2021-04-20");
+insert into diaries values(3569, "2021-04-21");
+insert into diaries values(3570, "2021-04-22");
+insert into diaries values(3571, "2021-04-23");
+insert into diaries values(3572, "2021-04-24");
+insert into diaries values(3573, "2021-04-25");
+insert into diaries values(3574, "2021-04-26");
+insert into diaries values(3575, "2021-04-27");
+insert into diaries values(3576, "2021-04-28");
+insert into diaries values(3577, "2021-04-29");
+insert into diaries values(3578, "2021-04-30");
+insert into diaries values(3579, "2021-05-01");
+insert into diaries values(3580, "2021-05-02");
+insert into diaries values(3581, "2021-05-03");
+insert into diaries values(3582, "2021-05-04");
+insert into diaries values(3583, "2021-05-05");
+insert into diaries values(3584, "2021-05-06");
+insert into diaries values(3585, "2021-05-07");
+insert into diaries values(3586, "2021-05-08");
+insert into diaries values(3587, "2021-05-09");
+insert into diaries values(3588, "2021-05-10");
+insert into diaries values(3589, "2021-05-11");
+insert into diaries values(3590, "2021-05-12");
+insert into diaries values(3591, "2021-05-13");
+insert into diaries values(3592, "2021-05-14");
+insert into diaries values(3593, "2021-05-15");
+insert into diaries values(3594, "2021-05-16");
+insert into diaries values(3595, "2021-05-17");
+insert into diaries values(3596, "2021-05-18");
+insert into diaries values(3597, "2021-05-19");
+insert into diaries values(3598, "2021-05-20");
+insert into diaries values(3599, "2021-05-21");
+insert into diaries values(3600, "2021-05-22");
+insert into diaries values(3601, "2021-05-23");
+insert into diaries values(3602, "2021-05-24");
+insert into diaries values(3603, "2021-05-25");
+insert into diaries values(3604, "2021-05-26");
+insert into diaries values(3605, "2021-05-27");
+insert into diaries values(3606, "2021-05-28");
+insert into diaries values(3607, "2021-05-29");
+insert into diaries values(3608, "2021-05-30");
+insert into diaries values(3609, "2021-05-31");
+insert into diaries values(3610, "2021-06-01");
+insert into diaries values(3611, "2021-06-02");
+insert into diaries values(3612, "2021-06-03");
+insert into diaries values(3613, "2021-06-04");
+insert into diaries values(3614, "2021-06-05");
+insert into diaries values(3615, "2021-06-06");
+insert into diaries values(3616, "2021-06-07");
+insert into diaries values(3617, "2021-06-08");
+insert into diaries values(3618, "2021-06-09");
+insert into diaries values(3619, "2021-06-10");
+insert into diaries values(3620, "2021-06-11");
+insert into diaries values(3621, "2021-06-12");
+insert into diaries values(3622, "2021-06-13");
+insert into diaries values(3623, "2021-06-14");
+insert into diaries values(3624, "2021-06-15");
+insert into diaries values(3625, "2021-06-16");
+insert into diaries values(3626, "2021-06-17");
+insert into diaries values(3627, "2021-06-18");
+insert into diaries values(3628, "2021-06-19");
+insert into diaries values(3629, "2021-06-20");
+insert into diaries values(3630, "2021-06-21");
+insert into diaries values(3631, "2021-06-22");
+insert into diaries values(3632, "2021-06-23");
+insert into diaries values(3633, "2021-06-24");
+insert into diaries values(3634, "2021-06-25");
+insert into diaries values(3635, "2021-06-26");
+insert into diaries values(3636, "2021-06-27");
+insert into diaries values(3637, "2021-06-28");
+insert into diaries values(3638, "2021-06-29");
+insert into diaries values(3639, "2021-06-30");
+insert into diaries values(3640, "2021-07-01");
+insert into diaries values(3641, "2021-07-02");
+insert into diaries values(3642, "2021-07-03");
+insert into diaries values(3643, "2021-07-04");
+insert into diaries values(3644, "2021-07-05");
+insert into diaries values(3645, "2021-07-06");
+insert into diaries values(3646, "2021-07-07");
+insert into diaries values(3647, "2021-07-08");
+insert into diaries values(3648, "2021-07-09");
+insert into diaries values(3649, "2021-07-10");
+insert into diaries values(3650, "2021-07-11");
+insert into diaries values(3651, "2021-07-12");
+insert into diaries values(3652, "2021-07-13");
+insert into diaries values(3653, "2021-07-14");
+insert into diaries values(3654, "2021-07-15");
+insert into diaries values(3655, "2021-07-16");
+insert into diaries values(3656, "2021-07-17");
+insert into diaries values(3657, "2021-07-18");
+insert into diaries values(3658, "2021-07-19");
+insert into diaries values(3659, "2021-07-20");
+insert into diaries values(3660, "2021-07-21");
+insert into diaries values(3661, "2021-07-22");
+insert into diaries values(3662, "2021-07-23");
+insert into diaries values(3663, "2021-07-24");
+insert into diaries values(3664, "2021-07-25");
+insert into diaries values(3665, "2021-07-26");
+insert into diaries values(3666, "2021-07-27");
+insert into diaries values(3667, "2021-07-28");
+insert into diaries values(3668, "2021-07-29");
+insert into diaries values(3669, "2021-07-30");
+insert into diaries values(3670, "2021-07-31");
+insert into diaries values(3671, "2021-08-01");
+insert into diaries values(3672, "2021-08-02");
+insert into diaries values(3673, "2021-08-03");
+insert into diaries values(3674, "2021-08-04");
+insert into diaries values(3675, "2021-08-05");
+insert into diaries values(3676, "2021-08-06");
+insert into diaries values(3677, "2021-08-07");
+insert into diaries values(3678, "2021-08-08");
+insert into diaries values(3679, "2021-08-09");
+insert into diaries values(3680, "2021-08-10");
+insert into diaries values(3681, "2021-08-11");
+insert into diaries values(3682, "2021-08-12");
+insert into diaries values(3683, "2021-08-13");
+insert into diaries values(3684, "2021-08-14");
+insert into diaries values(3685, "2021-08-15");
+insert into diaries values(3686, "2021-08-16");
+insert into diaries values(3687, "2021-08-17");
+insert into diaries values(3688, "2021-08-18");
+insert into diaries values(3689, "2021-08-19");
+insert into diaries values(3690, "2021-08-20");
+insert into diaries values(3691, "2021-08-21");
+insert into diaries values(3692, "2021-08-22");
+insert into diaries values(3693, "2021-08-23");
+insert into diaries values(3694, "2021-08-24");
+insert into diaries values(3695, "2021-08-25");
+insert into diaries values(3696, "2021-08-26");
+insert into diaries values(3697, "2021-08-27");
+insert into diaries values(3698, "2021-08-28");
+insert into diaries values(3699, "2021-08-29");
+insert into diaries values(3700, "2021-08-30");
+insert into diaries values(3701, "2021-08-31");
+insert into diaries values(3702, "2021-09-01");
+insert into diaries values(3703, "2021-09-02");
+insert into diaries values(3704, "2021-09-03");
+insert into diaries values(3705, "2021-09-04");
+insert into diaries values(3706, "2021-09-05");
+insert into diaries values(3707, "2021-09-06");
+insert into diaries values(3708, "2021-09-07");
+insert into diaries values(3709, "2021-09-08");
+insert into diaries values(3710, "2021-09-09");
+insert into diaries values(3711, "2021-09-10");
+insert into diaries values(3712, "2021-09-11");
+insert into diaries values(3713, "2021-09-12");
+insert into diaries values(3714, "2021-09-13");
+insert into diaries values(3715, "2021-09-14");
+insert into diaries values(3716, "2021-09-15");
+insert into diaries values(3717, "2021-09-16");
+insert into diaries values(3718, "2021-09-17");
+insert into diaries values(3719, "2021-09-18");
+insert into diaries values(3720, "2021-09-19");
+insert into diaries values(3721, "2021-09-20");
+insert into diaries values(3722, "2021-09-21");
+insert into diaries values(3723, "2021-09-22");
+insert into diaries values(3724, "2021-09-23");
+insert into diaries values(3725, "2021-09-24");
+insert into diaries values(3726, "2021-09-25");
+insert into diaries values(3727, "2021-09-26");
+insert into diaries values(3728, "2021-09-27");
+insert into diaries values(3729, "2021-09-28");
+insert into diaries values(3730, "2021-09-29");
+insert into diaries values(3731, "2021-09-30");
+insert into diaries values(3732, "2021-10-01");
+insert into diaries values(3733, "2021-10-02");
+insert into diaries values(3734, "2021-10-03");
+insert into diaries values(3735, "2021-10-04");
+insert into diaries values(3736, "2021-10-05");
+insert into diaries values(3737, "2021-10-06");
+insert into diaries values(3738, "2021-10-07");
+insert into diaries values(3739, "2021-10-08");
+insert into diaries values(3740, "2021-10-09");
+insert into diaries values(3741, "2021-10-10");
+insert into diaries values(3742, "2021-10-11");
+insert into diaries values(3743, "2021-10-12");
+insert into diaries values(3744, "2021-10-13");
+insert into diaries values(3745, "2021-10-14");
+insert into diaries values(3746, "2021-10-15");
+insert into diaries values(3747, "2021-10-16");
+insert into diaries values(3748, "2021-10-17");
+insert into diaries values(3749, "2021-10-18");
+insert into diaries values(3750, "2021-10-19");
+insert into diaries values(3751, "2021-10-20");
+insert into diaries values(3752, "2021-10-21");
+insert into diaries values(3753, "2021-10-22");
+insert into diaries values(3754, "2021-10-23");
+insert into diaries values(3755, "2021-10-24");
+insert into diaries values(3756, "2021-10-25");
+insert into diaries values(3757, "2021-10-26");
+insert into diaries values(3758, "2021-10-27");
+insert into diaries values(3759, "2021-10-28");
+insert into diaries values(3760, "2021-10-29");
+insert into diaries values(3761, "2021-10-30");
+insert into diaries values(3762, "2021-10-31");
+insert into diaries values(3763, "2021-11-01");
+insert into diaries values(3764, "2021-11-02");
+insert into diaries values(3765, "2021-11-03");
+insert into diaries values(3766, "2021-11-04");
+insert into diaries values(3767, "2021-11-05");
+insert into diaries values(3768, "2021-11-06");
+insert into diaries values(3769, "2021-11-07");
+insert into diaries values(3770, "2021-11-08");
+insert into diaries values(3771, "2021-11-09");
+insert into diaries values(3772, "2021-11-10");
+insert into diaries values(3773, "2021-11-11");
+insert into diaries values(3774, "2021-11-12");
+insert into diaries values(3775, "2021-11-13");
+insert into diaries values(3776, "2021-11-14");
+insert into diaries values(3777, "2021-11-15");
+insert into diaries values(3778, "2021-11-16");
+insert into diaries values(3779, "2021-11-17");
+insert into diaries values(3780, "2021-11-18");
+insert into diaries values(3781, "2021-11-19");
+insert into diaries values(3782, "2021-11-20");
+insert into diaries values(3783, "2021-11-21");
+insert into diaries values(3784, "2021-11-22");
+insert into diaries values(3785, "2021-11-23");
+insert into diaries values(3786, "2021-11-24");
+insert into diaries values(3787, "2021-11-25");
+insert into diaries values(3788, "2021-11-26");
+insert into diaries values(3789, "2021-11-27");
+insert into diaries values(3790, "2021-11-28");
+insert into diaries values(3791, "2021-11-29");
+insert into diaries values(3792, "2021-11-30");
+insert into diaries values(3793, "2021-12-01");
+insert into diaries values(3794, "2021-12-02");
+insert into diaries values(3795, "2021-12-03");
+insert into diaries values(3796, "2021-12-04");
+insert into diaries values(3797, "2021-12-05");
+insert into diaries values(3798, "2021-12-06");
+insert into diaries values(3799, "2021-12-07");
+insert into diaries values(3800, "2021-12-08");
+insert into diaries values(3801, "2021-12-09");
+insert into diaries values(3802, "2021-12-10");
+insert into diaries values(3803, "2021-12-11");
+insert into diaries values(3804, "2021-12-12");
+insert into diaries values(3805, "2021-12-13");
+insert into diaries values(3806, "2021-12-14");
+insert into diaries values(3807, "2021-12-15");
+insert into diaries values(3808, "2021-12-16");
+insert into diaries values(3809, "2021-12-17");
+insert into diaries values(3810, "2021-12-18");
+insert into diaries values(3811, "2021-12-19");
+insert into diaries values(3812, "2021-12-20");
+insert into diaries values(3813, "2021-12-21");
+insert into diaries values(3814, "2021-12-22");
+insert into diaries values(3815, "2021-12-23");
+insert into diaries values(3816, "2021-12-24");
+insert into diaries values(3817, "2021-12-25");
+insert into diaries values(3818, "2021-12-26");
+insert into diaries values(3819, "2021-12-27");
+insert into diaries values(3820, "2021-12-28");
+insert into diaries values(3821, "2021-12-29");
+insert into diaries values(3822, "2021-12-30");
+insert into diaries values(3823, "2021-12-31");
+insert into diaries values(3824, "2022-01-01");
+insert into diaries values(3825, "2022-01-02");
+insert into diaries values(3826, "2022-01-03");
+insert into diaries values(3827, "2022-01-04");
+insert into diaries values(3828, "2022-01-05");
+insert into diaries values(3829, "2022-01-06");
+insert into diaries values(3830, "2022-01-07");
+insert into diaries values(3831, "2022-01-08");
+insert into diaries values(3832, "2022-01-09");
+insert into diaries values(3833, "2022-01-10");
+insert into diaries values(3834, "2022-01-11");
+insert into diaries values(3835, "2022-01-12");
+insert into diaries values(3836, "2022-01-13");
+insert into diaries values(3837, "2022-01-14");
+insert into diaries values(3838, "2022-01-15");
+insert into diaries values(3839, "2022-01-16");
+insert into diaries values(3840, "2022-01-17");
+insert into diaries values(3841, "2022-01-18");
+insert into diaries values(3842, "2022-01-19");
+insert into diaries values(3843, "2022-01-20");
+insert into diaries values(3844, "2022-01-21");
+insert into diaries values(3845, "2022-01-22");
+insert into diaries values(3846, "2022-01-23");
+insert into diaries values(3847, "2022-01-24");
+insert into diaries values(3848, "2022-01-25");
+insert into diaries values(3849, "2022-01-26");
+insert into diaries values(3850, "2022-01-27");
+insert into diaries values(3851, "2022-01-28");
+insert into diaries values(3852, "2022-01-29");
+insert into diaries values(3853, "2022-01-30");
+insert into diaries values(3854, "2022-01-31");
+insert into diaries values(3855, "2022-02-01");
+insert into diaries values(3856, "2022-02-02");
+insert into diaries values(3857, "2022-02-03");
+insert into diaries values(3858, "2022-02-04");
+insert into diaries values(3859, "2022-02-05");
+insert into diaries values(3860, "2022-02-06");
+insert into diaries values(3861, "2022-02-07");
+insert into diaries values(3862, "2022-02-08");
+insert into diaries values(3863, "2022-02-09");
+insert into diaries values(3864, "2022-02-10");
+insert into diaries values(3865, "2022-02-11");
+insert into diaries values(3866, "2022-02-12");
+insert into diaries values(3867, "2022-02-13");
+insert into diaries values(3868, "2022-02-14");
+insert into diaries values(3869, "2022-02-15");
+insert into diaries values(3870, "2022-02-16");
+insert into diaries values(3871, "2022-02-17");
+insert into diaries values(3872, "2022-02-18");
+insert into diaries values(3873, "2022-02-19");
+insert into diaries values(3874, "2022-02-20");
+insert into diaries values(3875, "2022-02-21");
+insert into diaries values(3876, "2022-02-22");
+insert into diaries values(3877, "2022-02-23");
+insert into diaries values(3878, "2022-02-24");
+insert into diaries values(3879, "2022-02-25");
+insert into diaries values(3880, "2022-02-26");
+insert into diaries values(3881, "2022-02-27");
+insert into diaries values(3882, "2022-02-28");
+insert into diaries values(3883, "2022-03-01");
+insert into diaries values(3884, "2022-03-02");
+insert into diaries values(3885, "2022-03-03");
+insert into diaries values(3886, "2022-03-04");
+insert into diaries values(3887, "2022-03-05");
+insert into diaries values(3888, "2022-03-06");
+insert into diaries values(3889, "2022-03-07");
+insert into diaries values(3890, "2022-03-08");
+insert into diaries values(3891, "2022-03-09");
+insert into diaries values(3892, "2022-03-10");
+insert into diaries values(3893, "2022-03-11");
+insert into diaries values(3894, "2022-03-12");
+insert into diaries values(3895, "2022-03-13");
+insert into diaries values(3896, "2022-03-14");
+insert into diaries values(3897, "2022-03-15");
+insert into diaries values(3898, "2022-03-16");
+insert into diaries values(3899, "2022-03-17");
+insert into diaries values(3900, "2022-03-18");
+insert into diaries values(3901, "2022-03-19");
+insert into diaries values(3902, "2022-03-20");
+insert into diaries values(3903, "2022-03-21");
+insert into diaries values(3904, "2022-03-22");
+insert into diaries values(3905, "2022-03-23");
+insert into diaries values(3906, "2022-03-24");
+insert into diaries values(3907, "2022-03-25");
+insert into diaries values(3908, "2022-03-26");
+insert into diaries values(3909, "2022-03-27");
+insert into diaries values(3910, "2022-03-28");
+insert into diaries values(3911, "2022-03-29");
+insert into diaries values(3912, "2022-03-30");
+insert into diaries values(3913, "2022-03-31");
+insert into diaries values(3914, "2022-04-01");
+insert into diaries values(3915, "2022-04-02");
+insert into diaries values(3916, "2022-04-03");
+insert into diaries values(3917, "2022-04-04");
+insert into diaries values(3918, "2022-04-05");
+insert into diaries values(3919, "2022-04-06");
+insert into diaries values(3920, "2022-04-07");
+insert into diaries values(3921, "2022-04-08");
+insert into diaries values(3922, "2022-04-09");
+insert into diaries values(3923, "2022-04-10");
+insert into diaries values(3924, "2022-04-11");
+insert into diaries values(3925, "2022-04-12");
+insert into diaries values(3926, "2022-04-13");
+insert into diaries values(3927, "2022-04-14");
+insert into diaries values(3928, "2022-04-15");
+insert into diaries values(3929, "2022-04-16");
+insert into diaries values(3930, "2022-04-17");
+insert into diaries values(3931, "2022-04-18");
+insert into diaries values(3932, "2022-04-19");
+insert into diaries values(3933, "2022-04-20");
+insert into diaries values(3934, "2022-04-21");
+insert into diaries values(3935, "2022-04-22");
+insert into diaries values(3936, "2022-04-23");
+insert into diaries values(3937, "2022-04-24");
+insert into diaries values(3938, "2022-04-25");
+insert into diaries values(3939, "2022-04-26");
+insert into diaries values(3940, "2022-04-27");
+insert into diaries values(3941, "2022-04-28");
+insert into diaries values(3942, "2022-04-29");
+insert into diaries values(3943, "2022-04-30");
+insert into diaries values(3944, "2022-05-01");
+insert into diaries values(3945, "2022-05-02");
+insert into diaries values(3946, "2022-05-03");
+insert into diaries values(3947, "2022-05-04");
+insert into diaries values(3948, "2022-05-05");
+insert into diaries values(3949, "2022-05-06");
+insert into diaries values(3950, "2022-05-07");
+insert into diaries values(3951, "2022-05-08");
+insert into diaries values(3952, "2022-05-09");
+insert into diaries values(3953, "2022-05-10");
+insert into diaries values(3954, "2022-05-11");
+insert into diaries values(3955, "2022-05-12");
+insert into diaries values(3956, "2022-05-13");
+insert into diaries values(3957, "2022-05-14");
+insert into diaries values(3958, "2022-05-15");
+insert into diaries values(3959, "2022-05-16");
+insert into diaries values(3960, "2022-05-17");
+insert into diaries values(3961, "2022-05-18");
+insert into diaries values(3962, "2022-05-19");
+insert into diaries values(3963, "2022-05-20");
+insert into diaries values(3964, "2022-05-21");
+insert into diaries values(3965, "2022-05-22");
+insert into diaries values(3966, "2022-05-23");
+insert into diaries values(3967, "2022-05-24");
+insert into diaries values(3968, "2022-05-25");
+insert into diaries values(3969, "2022-05-26");
+insert into diaries values(3970, "2022-05-27");
+insert into diaries values(3971, "2022-05-28");
+insert into diaries values(3972, "2022-05-29");
+insert into diaries values(3973, "2022-05-30");
+insert into diaries values(3974, "2022-05-31");
+insert into diaries values(3975, "2022-06-01");
+insert into diaries values(3976, "2022-06-02");
+insert into diaries values(3977, "2022-06-03");
+insert into diaries values(3978, "2022-06-04");
+insert into diaries values(3979, "2022-06-05");
+insert into diaries values(3980, "2022-06-06");
+insert into diaries values(3981, "2022-06-07");
+insert into diaries values(3982, "2022-06-08");
+insert into diaries values(3983, "2022-06-09");
+insert into diaries values(3984, "2022-06-10");
+insert into diaries values(3985, "2022-06-11");
+insert into diaries values(3986, "2022-06-12");
+insert into diaries values(3987, "2022-06-13");
+insert into diaries values(3988, "2022-06-14");
+insert into diaries values(3989, "2022-06-15");
+insert into diaries values(3990, "2022-06-16");
+insert into diaries values(3991, "2022-06-17");
+insert into diaries values(3992, "2022-06-18");
+insert into diaries values(3993, "2022-06-19");
+insert into diaries values(3994, "2022-06-20");
+insert into diaries values(3995, "2022-06-21");
+insert into diaries values(3996, "2022-06-22");
+insert into diaries values(3997, "2022-06-23");
+insert into diaries values(3998, "2022-06-24");
+insert into diaries values(3999, "2022-06-25");
+insert into diaries values(4000, "2022-06-26");
+insert into diaries values(4001, "2022-06-27");
+insert into diaries values(4002, "2022-06-28");
+insert into diaries values(4003, "2022-06-29");
+insert into diaries values(4004, "2022-06-30");
+insert into diaries values(4005, "2022-07-01");
+insert into diaries values(4006, "2022-07-02");
+insert into diaries values(4007, "2022-07-03");
+insert into diaries values(4008, "2022-07-04");
+insert into diaries values(4009, "2022-07-05");
+insert into diaries values(4010, "2022-07-06");
+insert into diaries values(4011, "2022-07-07");
+insert into diaries values(4012, "2022-07-08");
+insert into diaries values(4013, "2022-07-09");
+insert into diaries values(4014, "2022-07-10");
+insert into diaries values(4015, "2022-07-11");
+insert into diaries values(4016, "2022-07-12");
+insert into diaries values(4017, "2022-07-13");
+insert into diaries values(4018, "2022-07-14");
+insert into diaries values(4019, "2022-07-15");
+insert into diaries values(4020, "2022-07-16");
+insert into diaries values(4021, "2022-07-17");
+insert into diaries values(4022, "2022-07-18");
+insert into diaries values(4023, "2022-07-19");
+insert into diaries values(4024, "2022-07-20");
+insert into diaries values(4025, "2022-07-21");
+insert into diaries values(4026, "2022-07-22");
+insert into diaries values(4027, "2022-07-23");
+insert into diaries values(4028, "2022-07-24");
+insert into diaries values(4029, "2022-07-25");
+insert into diaries values(4030, "2022-07-26");
+insert into diaries values(4031, "2022-07-27");
+insert into diaries values(4032, "2022-07-28");
+insert into diaries values(4033, "2022-07-29");
+insert into diaries values(4034, "2022-07-30");
+insert into diaries values(4035, "2022-07-31");
+insert into diaries values(4036, "2022-08-01");
+insert into diaries values(4037, "2022-08-02");
+insert into diaries values(4038, "2022-08-03");
+insert into diaries values(4039, "2022-08-04");
+insert into diaries values(4040, "2022-08-05");
+insert into diaries values(4041, "2022-08-06");
+insert into diaries values(4042, "2022-08-07");
+insert into diaries values(4043, "2022-08-08");
+insert into diaries values(4044, "2022-08-09");
+insert into diaries values(4045, "2022-08-10");
+insert into diaries values(4046, "2022-08-11");
+insert into diaries values(4047, "2022-08-12");
+insert into diaries values(4048, "2022-08-13");
+insert into diaries values(4049, "2022-08-14");
+insert into diaries values(4050, "2022-08-15");
+insert into diaries values(4051, "2022-08-16");
+insert into diaries values(4052, "2022-08-17");
+insert into diaries values(4053, "2022-08-18");
+insert into diaries values(4054, "2022-08-19");
+insert into diaries values(4055, "2022-08-20");
+insert into diaries values(4056, "2022-08-21");
+insert into diaries values(4057, "2022-08-22");
+insert into diaries values(4058, "2022-08-23");
+insert into diaries values(4059, "2022-08-24");
+insert into diaries values(4060, "2022-08-25");
+insert into diaries values(4061, "2022-08-26");
+insert into diaries values(4062, "2022-08-27");
+insert into diaries values(4063, "2022-08-28");
+insert into diaries values(4064, "2022-08-29");
+insert into diaries values(4065, "2022-08-30");
+insert into diaries values(4066, "2022-08-31");
+insert into diaries values(4067, "2022-09-01");
+insert into diaries values(4068, "2022-09-02");
+insert into diaries values(4069, "2022-09-03");
+insert into diaries values(4070, "2022-09-04");
+insert into diaries values(4071, "2022-09-05");
+insert into diaries values(4072, "2022-09-06");
+insert into diaries values(4073, "2022-09-07");
+insert into diaries values(4074, "2022-09-08");
+insert into diaries values(4075, "2022-09-09");
+insert into diaries values(4076, "2022-09-10");
+insert into diaries values(4077, "2022-09-11");
+insert into diaries values(4078, "2022-09-12");
+insert into diaries values(4079, "2022-09-13");
+insert into diaries values(4080, "2022-09-14");
+insert into diaries values(4081, "2022-09-15");
+insert into diaries values(4082, "2022-09-16");
+insert into diaries values(4083, "2022-09-17");
+insert into diaries values(4084, "2022-09-18");
+insert into diaries values(4085, "2022-09-19");
+insert into diaries values(4086, "2022-09-20");
+insert into diaries values(4087, "2022-09-21");
+insert into diaries values(4088, "2022-09-22");
+insert into diaries values(4089, "2022-09-23");
+insert into diaries values(4090, "2022-09-24");
+insert into diaries values(4091, "2022-09-25");
+insert into diaries values(4092, "2022-09-26");
+insert into diaries values(4093, "2022-09-27");
+insert into diaries values(4094, "2022-09-28");
+insert into diaries values(4095, "2022-09-29");
+commit;
+set autocommit=1;
+
+select * from diaries where match(title) against("2022-09-0") order by id;
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_matched_order.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_matched_order.test
new file mode 100644
index 00000000..306a12bd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_matched_order.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS texts;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE texts (
+ id INT PRIMARY KEY,
+ matched TEXT,
+ not_matched TEXT,
+ FULLTEXT KEY (matched),
+ FULLTEXT KEY (not_matched)
+) DEFAULT CHARSET=UTF8 COMMENT='engine "InnoDB"';
+
+INSERT INTO texts VALUES (1, 'Hello1', 'World1');
+INSERT INTO texts VALUES (2, 'Hello2', 'World2');
+INSERT INTO texts VALUES (3, 'Hello3', 'World3');
+
+SELECT id,
+ matched,
+ not_matched,
+ MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+ MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+ FROM texts
+ WHERE MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE)
+ ORDER BY MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE),
+ id;
+
+DROP TABLE texts;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_no_order.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_no_order.test
new file mode 100644
index 00000000..488af677
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_have_where_no_order.test
@@ -0,0 +1,51 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS texts;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE texts (
+ id INT PRIMARY KEY,
+ matched TEXT,
+ not_matched TEXT,
+ FULLTEXT KEY (matched),
+ FULLTEXT KEY (not_matched)
+) DEFAULT CHARSET=UTF8 COMMENT='engine "InnoDB"';
+
+INSERT INTO texts VALUES (1, 'Hello1', 'World1');
+INSERT INTO texts VALUES (2, 'Hello2', 'World2');
+INSERT INTO texts VALUES (3, 'Hello3', 'World3');
+
+SELECT *
+ FROM (SELECT id,
+ matched,
+ not_matched,
+ MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+ MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+ FROM texts
+ WHERE MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE))
+ AS searched_texts
+ ORDER BY id;
+
+DROP TABLE texts;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_no_where_both_order.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_no_where_both_order.test
new file mode 100644
index 00000000..89a0804e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_matched_and_not_matched_no_where_both_order.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2012 Kentoku SHIBA
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS texts;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE texts (
+ id INT PRIMARY KEY,
+ matched TEXT,
+ not_matched TEXT,
+ FULLTEXT KEY (matched),
+ FULLTEXT KEY (not_matched)
+) DEFAULT CHARSET=UTF8 COMMENT='engine "InnoDB"';
+
+INSERT INTO texts VALUES (1, 'Hello1', 'World1');
+INSERT INTO texts VALUES (2, 'Hello2', 'World2');
+INSERT INTO texts VALUES (3, 'Hello3', 'World3');
+
+SELECT id,
+ matched,
+ not_matched,
+ MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+ MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE)
+ FROM texts
+ ORDER BY MATCH(matched) AGAINST('+Hello' IN BOOLEAN MODE),
+ MATCH(not_matched) AGAINST('+Hello' IN BOOLEAN MODE),
+ id;
+
+DROP TABLE texts;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_delete.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_delete.test
new file mode 100644
index 00000000..0d2e0056
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_delete.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+delete from diaries where id = 2;
+select * from diaries where match(title, content) against("富士山");
+select * from diaries where match(title) against("富士山");
+select * from diaries where match(content) against("富士山");
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_insert.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_insert.test
new file mode 100644
index 00000000..2886edaf
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_insert.test
@@ -0,0 +1,42 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries;
+select * from diaries where match(title, content) against("富士山");
+select * from diaries where match(title) against("富士山");
+select * from diaries where match(content) against("富士山");
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_recreate.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_recreate.test
new file mode 100644
index 00000000..249abeed
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_recreate.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+select * from diaries where match(title, content) against("富士山");
+
+drop index title on diaries;
+--error ER_FT_MATCHING_KEY_NOT_FOUND
+select * from diaries where match(title, content) against("富士山");
+
+create fulltext index new_title_content_index on diaries (title, content);
+select * from diaries where match(title, content) against("富士山");
+
+select * from diaries;
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_update.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_update.test
new file mode 100644
index 00000000..63b5943f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_column_index_update.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ title varchar(255),
+ content text,
+ fulltext index (title, content),
+ fulltext index (title),
+ fulltext index (content)
+) default charset utf8 COMMENT = 'engine "innodb"';
+insert into diaries values(1, "Hello", "はじめました。");
+insert into diaries values(2, "天気", "明日の富士山の天気について");
+insert into diaries values(3, "富士山", "今日もきれい。");
+update diaries set title = "チョモランマ" where id = 3;
+update diaries set content = "チョモランマと富士山" where id = 1;
+select * from diaries where match(title, content) against("富士山");
+select * from diaries where match(title) against("富士山");
+select * from diaries where match(content) against("富士山");
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_index.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_index.test
new file mode 100644
index 00000000..749b08ee
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_multiple_index.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ title text,
+ body text,
+ fulltext index title_index (title),
+ fulltext index body_index (body)
+) comment = 'engine "innodb"' default charset utf8;
+
+insert into diaries (title, body) values ("survey", "will start groonga!");
+insert into diaries (title, body) values ("groonga (1)", "starting groonga...");
+insert into diaries (title, body) values ("groonga (2)", "started groonga.");
+
+select * from diaries
+ where match(title) against("survey") and
+ match(body) against("groonga");
+
+select *, match(title) against("survey"), match(body) against("groonga")
+ from diaries
+ where match(title) against("survey") and
+ match(body) against("groonga");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_myisam.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_myisam.test
new file mode 100644
index 00000000..dc92fafd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_myisam.test
@@ -0,0 +1,101 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 text, fulltext index ft (c2)) COMMENT = 'engine "myisam"';
+insert into t1 values (1, "hoge hoge");
+insert into t1 values (2, "fuga fuga");
+insert into t1 values (3, "moge moge");
+select * from t1;
+flush tables;
+select * from t1;
+drop table t1;
+
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "myisam"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"sa si su se so");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ee oo");
+select * from t1;
+select * from t1 where match(c3) against("su") order by c1;
+select * from t1 where match(c3) against("ii") order by c1;
+select * from t1 where match(c3) against("+su" in boolean mode) order by c1;
+select * from t1 where match(c3) against("+ii" in boolean mode) order by c1;
+drop table t1;
+
+set names utf8;
+create table t1 (c1 int primary key, c2 varchar(255), c3 text, fulltext index(c2), fulltext index(c3)) default charset utf8 COMMENT = 'engine "myisam"';
+insert into t1 values(1, "明日の富士山の天気について","あああああああ");
+insert into t1 values(2, "いいいいい","明日の富士山の天気は分かりません");
+insert into t1 values(3, "dummy", "dummy");
+select * from t1;
+select * from t1 where match(c2) against("富士山") order by c1;
+select * from t1 where match(c3) against("富士山") order by c1;
+drop table t1;
+
+create table t1 (c1 int primary key, c2 varchar(100), fulltext index(c2)) default charset utf8 COMMENT = 'engine "myisam"';
+create table t2 (c1 int primary key, c2 text, fulltext index(c2)) default charset utf8 COMMENT = 'engine "myisam"';
+insert into t1 values (1, "aa ii uu ee oo");
+insert into t1 values (2, "ka ki ku ke ko");
+insert into t1 values (3, "aa ii ii ii oo");
+insert into t1 values (4, "sa si su se so");
+insert into t1 values (5, "ta ti ii ii to");
+insert into t2 (c1,c2) select c1,c2 from t1;
+select * from t1;
+select * from t2;
+select * from t1 where c1=3;
+select * from t2 where c1=3;
+select * from t1 where c1>3 order by c1 desc;
+select * from t2 where c1>3 order by c1 asc;
+select * from t1 where c2>"s" order by c2 desc;
+select * from t2 where c2>"s" order by c1 asc;
+select *,match(c2) against("ii") from t1 where match(c2) against("ii") order by match(c2) against("ii") desc;
+select *,match(c2) against("ii") from t2 where match(c2) against("ii") order by match(c2) against("ii") asc;
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+select c1,c2,match(c2) against("ii") from t1 where match(c2) against("ii");
+drop table t1,t2;
+
+# for "not match against"
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "myisam"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,10,"ka ki ku ke ko");
+insert into t1 values(3,10,"aa ii uu ee oo");
+insert into t1 values(4,10,"ka ki ku ke ko");
+insert into t1 values(5,20,"aa ii uu ee oo");
+insert into t1 values(6,20,"ka ki ku ke ko");
+insert into t1 values(7,20,"aa ii uu ee oo");
+insert into t1 values(8,20,"ka ki ku ke ko");
+select * from t1;
+select *,match(c3) against("uu") from t1 where match(c3) against("uu") order by c1;
+select * from t1 where not match(c3) against("uu");
+select *,match(c3) against("dummy") from t1 where match(c3) against("dummy");
+select * from t1 where not match(c3) against("dummy");
+select * from t1 where c1 = 4 and not match(c3) against("uu");
+select * from t1 where c1 <= 4 and not match(c3) against("uu");
+select * from t1 where c1 > 4 and not match(c3) against("uu");
+select * from t1 where c2 = 10 and not match(c3) against("uu");
+select * from t1 where c2 >= 15 and not match(c3) against("uu");
+select * from t1 where c2 < 15 and not match(c3) against("uu");
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_not_match_against.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_not_match_against.test
new file mode 100644
index 00000000..473fd2d7
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_not_match_against.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int, c3 text, fulltext index ft(c3)) COMMENT = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,10,"ka ki ku ke ko");
+insert into t1 values(3,10,"aa ii uu ee oo");
+insert into t1 values(4,10,"ka ki ku ke ko");
+insert into t1 values(5,20,"aa ii uu ee oo");
+insert into t1 values(6,20,"ka ki ku ke ko");
+insert into t1 values(7,20,"aa ii uu ee oo");
+insert into t1 values(8,20,"ka ki ku ke ko");
+select * from t1;
+select *,match(c3) against("uu") from t1 where match(c3) against("uu") order by c1;
+select * from t1 where not match(c3) against("uu") order by c1;
+select *,match(c3) against("dummy") from t1 where match(c3) against("dummy") order by c1;
+select * from t1 where not match(c3) against("dummy") order by c1;
+select * from t1 where c1 = 4 and not match(c3) against("uu") order by c1;
+select * from t1 where c1 <= 4 and not match(c3) against("uu") order by c1;
+select * from t1 where c1 > 4 and not match(c3) against("uu") order by c1;
+select * from t1 where c2 = 10 and not match(c3) against("uu") order by c1;
+select * from t1 where c2 >= 15 and not match(c3) against("uu") order by c1;
+select * from t1 where c2 < 15 and not match(c3) against("uu") order by c1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..6949ecd6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_TODO_SPLIT_ME.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE ft(
+ a INT DEFAULT 0,
+ b TEXT,
+ c TEXT,
+ PRIMARY KEY(a),
+ FULLTEXT KEY ftx1(b),
+ FULLTEXT KEY ftx2(c)
+)ENGINE=Mroonga DEFAULT CHARSET=UTF8 COMMENT = 'engine "innodb"';
+
+INSERT INTO ft VALUES(1,'aaaaa','abcde');
+INSERT INTO ft VALUES(2,'bbbbb','bcdef');
+INSERT INTO ft VALUES(3,'ccccc','cdefg');
+INSERT INTO ft VALUES(4,'ddddd','defgh');
+INSERT INTO ft VALUES(5,'eeeee','efghi');
+
+SELECT a, b, c FROM ft WHERE MATCH(b) AGAINST('bbbbb' IN BOOLEAN MODE);
+SELECT a, b, c FROM ft WHERE MATCH(b) AGAINST('bbbbb' IN BOOLEAN MODE) ORDER BY MATCH(b) AGAINST('bbbbb' IN BOOLEAN MODE);
+SELECT a, b, c FROM ft WHERE MATCH(c) AGAINST('bbbbb' IN BOOLEAN MODE);
+
+DROP TABLE ft;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_transaction.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_transaction.test
new file mode 100644
index 00000000..aa510012
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/fulltext_order_transaction.test
@@ -0,0 +1,73 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET=UTF8;
+
+START TRANSACTION;
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("groonga")
+ ORDER BY id;
+
+disable_query_log;
+CONNECT(search_connection, localhost, root);
+enable_query_log;
+USE test;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("groonga")
+ ORDER BY id;
+
+disable_query_log;
+CONNECTION default;
+enable_query_log;
+COMMIT;
+
+disable_query_log;
+CONNECTION search_connection;
+enable_query_log;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("groonga")
+ ORDER BY id;
+disable_query_log;
+DISCONNECT search_connection;
+enable_query_log;
+
+disable_query_log;
+CONNECTION default;
+enable_query_log;
+SELECT * FROM diaries
+ WHERE MATCH(body) AGAINST("groonga")
+ ORDER BY id;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_reference.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_reference.test
new file mode 100644
index 00000000..0423e948
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_reference.test
@@ -0,0 +1,36 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int AUTO_INCREMENT PRIMARY KEY
+) COMMENT='ENGINE "InnoDB"';
+
+SELECT last_insert_id();
+
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_set.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_set.test
new file mode 100644
index 00000000..046e9d74
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/function_last_insert_id_set.test
@@ -0,0 +1,38 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id int AUTO_INCREMENT PRIMARY KEY
+) COMMENT='ENGINE "InnoDB"';
+
+SELECT last_insert_id();
+SELECT last_insert_id(10);
+SELECT last_insert_id();
+
+INSERT INTO ids VALUES();
+SELECT last_insert_id();
+SELECT * FROM ids;
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_contains.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_contains.test
new file mode 100644
index 00000000..80dc209a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_contains.test
@@ -0,0 +1,145 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists shops;
+--enable_warnings
+
+create table shops (
+ id int primary key auto_increment,
+ name text,
+ location geometry NOT NULL,
+ spatial key location_index (location)
+) comment = 'engine "innodb"';
+insert into shops (name, location)
+ values ('nezu-no-taiyaki',
+ ST_GeomFromText('POINT(139.762573 35.720253)'));
+insert into shops (name, location)
+ values ('taiyaki-kataoka',
+ ST_GeomFromText('POINT(139.715591 35.712521)'));
+insert into shops (name, location)
+ values ('soba-taiyaki-ku',
+ ST_GeomFromText('POINT(139.659088 35.683712)'));
+insert into shops (name, location)
+ values ('kuruma',
+ ST_GeomFromText('POINT(139.706207 35.721516)'));
+insert into shops (name, location)
+ values ('hirose-ya',
+ ST_GeomFromText('POINT(139.685608 35.714844)'));
+insert into shops (name, location)
+ values ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+insert into shops (name, location)
+ values ('omede-taiyaki',
+ ST_GeomFromText('POINT(139.817154 35.700516)'));
+insert into shops (name, location)
+ values ('onaga-ya',
+ ST_GeomFromText('POINT(139.81105 35.698254)'));
+insert into shops (name, location)
+ values ('shiro-ya',
+ ST_GeomFromText('POINT(139.638611 35.705517)'));
+insert into shops (name, location)
+ values ('fuji-ya',
+ ST_GeomFromText('POINT(139.637115 35.703938)'));
+insert into shops (name, location)
+ values ('miyoshi',
+ ST_GeomFromText('POINT(139.537323 35.644539)'));
+insert into shops (name, location)
+ values ('juju-ya',
+ ST_GeomFromText('POINT(139.695755 35.628922)'));
+insert into shops (name, location)
+ values ('tatsumi-ya',
+ ST_GeomFromText('POINT(139.638657 35.665501)'));
+insert into shops (name, location)
+ values ('tetsuji',
+ ST_GeomFromText('POINT(139.76857 35.680912)'));
+insert into shops (name, location)
+ values ('gazuma-ya',
+ ST_GeomFromText('POINT(139.647598 35.700817)'));
+insert into shops (name, location)
+ values ('honma-mon',
+ ST_GeomFromText('POINT(139.652573 35.722736)'));
+insert into shops (name, location)
+ values ('naniwa-ya',
+ ST_GeomFromText('POINT(139.796234 35.730061)'));
+insert into shops (name, location)
+ values ('kuro-dai',
+ ST_GeomFromText('POINT(139.704834 35.650345)'));
+insert into shops (name, location)
+ values ('daruma',
+ ST_GeomFromText('POINT(139.770599 35.681461)'));
+insert into shops (name, location)
+ values ('yanagi-ya',
+ ST_GeomFromText('POINT(139.783981 35.685341)'));
+insert into shops (name, location)
+ values ('sharaku',
+ ST_GeomFromText('POINT(139.794846 35.716969)'));
+insert into shops (name, location)
+ values ('takane',
+ ST_GeomFromText('POINT(139.560913 35.698601)'));
+insert into shops (name, location)
+ values ('chiyoda',
+ ST_GeomFromText('POINT(139.652817 35.642601)'));
+insert into shops (name, location)
+ values ('da-ka-po',
+ ST_GeomFromText('POINT(139.727356 35.627346)'));
+insert into shops (name, location)
+ values ('matsushima-ya',
+ ST_GeomFromText('POINT(139.737381 35.640556)'));
+insert into shops (name, location)
+ values ('kazuya',
+ ST_GeomFromText('POINT(139.760895 35.673508)'));
+insert into shops (name, location)
+ values ('furuya-kogane-an',
+ ST_GeomFromText('POINT(139.676071 35.680603)'));
+insert into shops (name, location)
+ values ('hachi-no-ie',
+ ST_GeomFromText('POINT(139.668106 35.608021)'));
+insert into shops (name, location)
+ values ('azuki-chan',
+ ST_GeomFromText('POINT(139.673203 35.64151)'));
+insert into shops (name, location)
+ values ('kuriko-an',
+ ST_GeomFromText('POINT(139.796829 35.712013)'));
+insert into shops (name, location)
+ values ('yume-no-aru-machi-no-taiyaki-ya-san',
+ ST_GeomFromText('POINT(139.712524 35.616199)'));
+insert into shops (name, location)
+ values ('naze-ya',
+ ST_GeomFromText('POINT(139.665833 35.609039)'));
+insert into shops (name, location)
+ values ('sanoki-ya',
+ ST_GeomFromText('POINT(139.770721 35.66592)'));
+insert into shops (name, location)
+ values ('shigeta',
+ ST_GeomFromText('POINT(139.780273 35.672626)'));
+insert into shops (name, location)
+ values ('nishimi-ya',
+ ST_GeomFromText('POINT(139.774628 35.671825)'));
+insert into shops (name, location)
+ values ('hiiragi',
+ ST_GeomFromText('POINT(139.711517 35.647701)'));
+select id, name, ST_AsText(location) as location_text from shops;
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.7727 35.6684, 139.7038 35.7121)'), location);
+drop table shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_delete.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_delete.test
new file mode 100644
index 00000000..cc4d50b8
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_delete.test
@@ -0,0 +1,48 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists shops;
+--enable_warnings
+
+create table shops (
+ id int primary key auto_increment,
+ name text,
+ location geometry NOT NULL,
+ spatial key location_index (location)
+) comment = 'engine "innodb"';
+
+insert into shops (name, location)
+ values ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+
+delete from shops
+ where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+
+select id, name, ST_AsText(location) as location_text from shops;
+
+drop table shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_update.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_update.test
new file mode 100644
index 00000000..b340cf71
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/geometry_update.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/have_geometry.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists shops;
+--enable_warnings
+
+create table shops (
+ id int primary key auto_increment,
+ name text,
+ location geometry NOT NULL,
+ spatial key location_index (location)
+) comment = 'engine "innodb"';
+
+insert into shops (name, location)
+ values ('sazare',
+ ST_GeomFromText('POINT(139.685043 35.714653)'));
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.65659 35.57903, 139.66489 35.57262)'), location);
+
+update shops set location = ST_GeomFromText('POINT(139.66116 35.57566)')
+ where name = 'sazare';
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.68466 35.71592, 139.68804 35.71411)'), location);
+select id, name, ST_AsText(location) as location_text from shops
+ where MBRContains(ST_GeomFromText('LineString(139.65659 35.57903, 139.66489 35.57262)'), location);
+
+drop table shops;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/index_force_index_not_used.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/index_force_index_not_used.test
new file mode 100644
index 00000000..89e87360
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/index_force_index_not_used.test
@@ -0,0 +1,32 @@
+# Copyright(C) 2013 Kentoku SHIBA
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS ids;
+--enable_warnings
+
+CREATE TABLE ids (
+ id INT PRIMARY KEY AUTO_INCREMENT
+) DEFAULT CHARSET UTF8 COMMENT = 'engine "InnoDB"';
+SELECT COUNT(*) FROM ids FORCE INDEX(PRIMARY);
+
+DROP TABLE ids;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..03aa71cd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_TODO_SPLIT_ME.test
@@ -0,0 +1,91 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+# data types
+create table t1 (c1 tinyint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 smallint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 mediumint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 int primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 bigint primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(1);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 float primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(0.5);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 double primary key) COMMENT = 'engine "innodb"';
+insert into t1 values(0.5);
+select * from t1;
+drop table t1;
+
+create table t1 (c1 date primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("2010/03/26");
+select * from t1;
+drop table t1;
+
+create table t1 (c1 time primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("11:22:33");
+select * from t1;
+drop table t1;
+
+create table t1 (c1 year primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("2010");
+select * from t1;
+drop table t1;
+
+create table t1 (c1 datetime primary key) COMMENT = 'engine "innodb"';
+insert into t1 values("2010/03/26 11:22:33");
+select * from t1;
+drop table t1;
+
+
+# duplicated key error
+create table t1 (c1 int primary key, c2 int) COMMENT = 'engine "innodb"';
+insert into t1 values(1,100);
+select * from t1;
+--error ER_DUP_ENTRY
+insert into t1 values(1,200);
+select * from t1;
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_bulk.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_bulk.test
new file mode 100644
index 00000000..e315ac5d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_bulk.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+set names utf8;
+create table diaries (
+ id int primary key,
+ content text,
+ fulltext index (content)
+) default charset utf8 comment = 'engine "innodb"';
+
+LOCK TABLE diaries WRITE;
+insert into diaries values(1, "今日からはじめました。");
+insert into diaries values(2, "明日の富士山の天気について");
+insert into diaries values(3, "今日も天気がよくてきれいに見える。");
+UNLOCK TABLES;
+
+select * from diaries;
+
+select * from diaries where match(content) against("天気");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.test
new file mode 100644
index 00000000..e7fba640
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_primary_key_myisam.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ date TIMESTAMP NOT NULL,
+ title VARCHAR(100) NOT NULL,
+ content TEXT NOT NULL,
+ PRIMARY KEY (date, title)
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "MyISAM"';
+# For MariaDB 10.2.3
+-- replace_result current_timestamp() CURRENT_TIMESTAMP
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-04", "cloudy day", "Today is cloudy day...");
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-04", "shopping", "I buy a new shirt.");
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-05", "rainy day", "Today is rainy day...");
+
+SELECT * FROM diaries;
+
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-04", "shopping", "I buy new shoes.")
+ ON DUPLICATE KEY UPDATE date = "2012-03-03",
+ content = "I buy a new hat.";
+
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.test
new file mode 100644
index 00000000..dc5d8b5a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/insert_on_duplicate_key_update_multiple_column_unique_index_myisam.test
@@ -0,0 +1,51 @@
+# 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-1335 USA
+
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ date TIMESTAMP NOT NULL,
+ title VARCHAR(100) NOT NULL,
+ content TEXT NOT NULL,
+ UNIQUE INDEX (date, title)
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "MyISAM"';
+# For MariaDB 10.2.3
+-- replace_result current_timestamp() CURRENT_TIMESTAMP
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-04", "cloudy day", "Today is cloudy day...");
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-04", "shopping", "I buy a new shirt.");
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-05", "rainy day", "Today is rainy day...");
+
+SELECT * FROM diaries;
+
+INSERT INTO diaries (date, title, content)
+ VALUES ("2012-03-04", "shopping", "I buy new shoes.")
+ ON DUPLICATE KEY UPDATE date = "2012-03-03",
+ content = "I buy a new hat.";
+SELECT * FROM diaries;
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_disk_sweep.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_disk_sweep.test
new file mode 100644
index 00000000..436904e2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_disk_sweep.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.com>
+# Copyright(C) 2013-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql.inc
+--source ../../include/mroonga/have_version_5_6_or_later.inc
+--source ../../include/mroonga/skip_mysql_5_7_or_later.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS integers;
+--enable_warnings
+
+SET optimizer_switch='mrr_cost_based=off';
+
+CREATE TABLE integers (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ value INT,
+ KEY (value)
+) COMMENT='engine "InnoDB"';
+
+INSERT INTO integers (value) VALUES (0), (1), (2), (3);
+
+EXPLAIN SELECT * FROM integers
+ WHERE value IN (0, 2);
+
+SELECT * FROM integers
+ WHERE value IN (0, 2);
+
+DROP TABLE integers;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_mysql_5_7_or_later_disk_sweep.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_mysql_5_7_or_later_disk_sweep.test
new file mode 100644
index 00000000..c883e493
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/multi_range_read_mysql_5_7_or_later_disk_sweep.test
@@ -0,0 +1,44 @@
+# Copyright(C) 2013 Kenji Maruyama <mmmaru777@gmail.com>
+# Copyright(C) 2013-2016 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-1335 USA
+
+--source ../../include/mroonga/have_mysql_5_7_or_later.inc
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS integers;
+--enable_warnings
+
+SET optimizer_switch='mrr_cost_based=off';
+
+CREATE TABLE integers (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ value INT,
+ KEY (value)
+) COMMENT='engine "InnoDB"';
+
+INSERT INTO integers (value) VALUES (0), (1), (2), (3);
+
+EXPLAIN SELECT * FROM integers
+ WHERE value IN (0, 2);
+
+SELECT * FROM integers
+ WHERE value IN (0, 2);
+
+DROP TABLE integers;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_TODO_SPLIT_ME.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_TODO_SPLIT_ME.test
new file mode 100644
index 00000000..a47e73f5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_TODO_SPLIT_ME.test
@@ -0,0 +1,60 @@
+# Copyright(C) 2010 Kentoku SHIBA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+flush status;
+create table t1 (
+ c1 int primary key,
+ c2 int,
+ c3 text,
+ key idx1(c2),
+ fulltext index ft(c3)
+) comment = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"ii si ii se ii");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ii oo");
+
+select c3, match(c3) against("ii") from t1
+ where match(c3) against("ii") order by match(c3) against("ii") desc;
+show status like 'mroonga_fast_order_limit';
+
+select c3, match(c3) against("ii") from t1
+ where match(c3) against("ii") order by match(c3) against("ii") desc limit 1, 1;
+show status like 'mroonga_fast_order_limit';
+
+select c3, match(c3) against("ii") from t1
+ where match(c3) against("ii") order by match(c3) against("ii");
+show status like 'mroonga_fast_order_limit';
+
+select c3, match(c3) against("ii") from t1
+ where match(c3) against("ii") order by match(c3) against("ii") limit 1;
+show status like 'mroonga_fast_order_limit';
+
+select count(*) from t1 where match(c3) against("ii") limit 1;
+show status like 'mroonga_fast_order_limit';
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_direction.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_direction.test
new file mode 100644
index 00000000..21180eb9
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_direction.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE memos (
+ id int PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) COMMENT = 'engine "InnoDB"';
+
+INSERT INTO memos VALUES(1, "Groonga is fast");
+INSERT INTO memos VALUES(2, "Mroonga is fast");
+INSERT INTO memos VALUES(3, "Mroonga is easy");
+INSERT INTO memos VALUES(4, "Mroonga is useful");
+INSERT INTO memos VALUES(5, "Mroonga is great");
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+SELECT id, content
+ FROM memos
+ WHERE MATCH(content) AGAINST("+Mroonga" IN BOOLEAN MODE)
+ ORDER BY id
+ LIMIT 2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_where_clause.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_where_clause.test
new file mode 100644
index 00000000..d4032829
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_no_where_clause.test
@@ -0,0 +1,46 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+flush status;
+create table t1 (
+ c1 int primary key,
+ c2 int,
+ c3 text,
+ key idx1(c2),
+ fulltext index ft(c3)
+) comment = 'engine "innodb"';
+insert into t1 values(1,10,"aa ii uu ee oo");
+insert into t1 values(2,20,"ka ki ku ke ko");
+insert into t1 values(3,30,"ii si ii se ii");
+insert into t1 values(4,40,"ta ti tu te to");
+insert into t1 values(5,50,"aa ii uu ii oo");
+
+show status like 'mroonga_fast_order_limit';
+
+select *, match(c3) against("ii") from t1 order by c1 desc limit 1;
+
+show status like 'mroonga_fast_order_limit';
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_order_by_primary_key.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_order_by_primary_key.test
new file mode 100644
index 00000000..2513df8e
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/optimization_order_limit_order_by_primary_key.test
@@ -0,0 +1,50 @@
+# Copyright(C) 2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS memos;
+--enable_warnings
+
+FLUSH STATUS;
+
+CREATE TABLE memos (
+ id int PRIMARY KEY,
+ content TEXT,
+ FULLTEXT INDEX (content)
+) COMMENT = 'engine "InnoDB"';
+
+INSERT INTO memos VALUES(1, "Mroonga is fast");
+INSERT INTO memos VALUES(2, "Mroonga is easy");
+INSERT INTO memos VALUES(3, "Mroonga is useful");
+INSERT INTO memos VALUES(4, "Mroonga is great");
+INSERT INTO memos VALUES(5, "Groonga is fast");
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+SELECT id, content
+ FROM memos
+ WHERE MATCH(content) AGAINST("+Mroonga" IN BOOLEAN MODE)
+ ORDER BY id DESC
+ LIMIT 2;
+
+SHOW STATUS LIKE 'mroonga_fast_order_limit';
+
+DROP TABLE memos;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt b/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt
new file mode 100644
index 00000000..d2ed32dd
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema-master.opt
@@ -0,0 +1 @@
+--loose-performance-schema
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema.test
new file mode 100644
index 00000000..6270ea66
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/performance_schema.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2012-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source include/have_perfschema.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SHOW VARIABLES LIKE 'performance_schema';
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ content VARCHAR(255),
+ FULLTEXT INDEX (content)
+) DEFAULT CHARSET UTF8 COMMENT = 'ENGINE "InnoDB"';
+SHOW CREATE TABLE diaries;
+
+INSERT INTO diaries (content) VALUES ("Tommorow will be shiny day!");
+
+SHOW TABLES FROM performance_schema LIKE 'threads';
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_files.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_files.test
new file mode 100644
index 00000000..5d9c5bd2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_files.test
@@ -0,0 +1,58 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/skip_solaris.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+CREATE DATABASE repair_test;
+USE repair_test;
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX body_index (body)
+) COMMENT = 'engine "innodb"' DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+
+--remove_files_wildcard $MYSQLD_DATADIR repair_test.mrn*
+
+FLUSH TABLES;
+
+# Error ER_CANT_OPEN_FILE mroonga: failed to open table: <diaries>
+--error ER_CANT_OPEN_FILE
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+
+REPAIR TABLE diaries;
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+
+DROP TABLE diaries;
+
+DROP DATABASE repair_test;
+USE test;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test
new file mode 100644
index 00000000..2fefadc2
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/repair_table_no_index_file.test
@@ -0,0 +1,58 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source ../../include/mroonga/skip_solaris.inc
+--source ../../include/mroonga/have_mroonga.inc
+--source ../../include/mroonga/have_mroonga_helper.inc
+
+CREATE DATABASE repair_test;
+USE repair_test;
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX body_index (body)
+) COMMENT = 'engine "innodb"' DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+
+--remove_file $MYSQLD_DATADIR/repair_test.mrn.000010A
+
+FLUSH TABLES;
+
+# Error ER_CANT_OPEN_FILE system call error: No such file or directory: failed to open path: <repair_test.mrn.000010A>
+--error ER_CANT_OPEN_FILE
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+
+REPAIR TABLE diaries;
+
+SELECT * FROM diaries;
+
+SELECT * FROM diaries WHERE MATCH(body) AGAINST("starting");
+
+DROP TABLE diaries;
+
+DROP DATABASE repair_test;
+USE test;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/temporary_table.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/temporary_table.test
new file mode 100644
index 00000000..e93f7f79
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/temporary_table.test
@@ -0,0 +1,39 @@
+# Copyright(C) 2012 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 Toshihisa Tashiro
+#
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/skip_osx.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TEMPORARY TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TEMPORARY TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT
+) DEFAULT CHARSET=UTF8 COMMENT = 'ENGINE "InnoDB"';
+
+INSERT INTO diaries (title) VALUES ("clear day");
+INSERT INTO diaries (title) VALUES ("rainy day");
+INSERT INTO diaries (title) VALUES ("cloudy day");
+
+SELECT * FROM diaries;
+
+DROP TEMPORARY TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_query_cache.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_query_cache.test
new file mode 100644
index 00000000..4284f60a
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_query_cache.test
@@ -0,0 +1,63 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+SET @tmp_query_cache_size = @@query_cache_size;
+SET GLOBAL query_cache_size = 1048576;
+
+--disable_warnings
+DROP TABLE IF EXISTS simple_table;
+--enable_warnings
+
+CREATE TABLE simple_table (
+ id INT PRIMARY KEY
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET=UTF8;
+SHOW CREATE TABLE simple_table;
+
+INSERT INTO simple_table (id) VALUES (1),(2);
+
+disable_query_log;
+CONNECT(second_connection, localhost, root);
+enable_query_log;
+USE test;
+START TRANSACTION;
+INSERT INTO simple_table (id) VALUES (3);
+
+disable_query_log;
+CONNECTION default;
+enable_query_log;
+SELECT * FROM simple_table;
+
+disable_query_log;
+CONNECTION second_connection;
+enable_query_log;
+COMMIT;
+
+disable_query_log;
+CONNECTION default;
+enable_query_log;
+SELECT * FROM simple_table;
+
+DROP TABLE simple_table;
+disable_query_log;
+DISCONNECT second_connection;
+enable_query_log;
+
+SET GLOBAL query_cache_size = @tmp_query_cache_size;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_delete.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_delete.test
new file mode 100644
index 00000000..8d3a569d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_delete.test
@@ -0,0 +1,58 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey") AND
+ MATCH(body) AGAINST("groonga");
+
+START TRANSACTION;
+DELETE FROM diaries WHERE id = 1;
+ROLLBACK;
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey") AND
+ MATCH(body) AGAINST("groonga");
+
+DELETE FROM diaries WHERE id = 1;
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey") AND
+ MATCH(body) AGAINST("groonga");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_update.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_update.test
new file mode 100644
index 00000000..df568a79
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/transaction_rollback_delete_update.test
@@ -0,0 +1,55 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ body TEXT,
+ FULLTEXT INDEX title_index (title),
+ FULLTEXT INDEX body_index (body)
+) COMMENT = 'ENGINE "InnoDB"' DEFAULT CHARSET UTF8;
+
+INSERT INTO diaries (title, body) VALUES ("survey", "will start groonga!");
+INSERT INTO diaries (title, body) VALUES ("groonga (1)", "starting groonga...");
+INSERT INTO diaries (title, body) VALUES ("groonga (2)", "started groonga.");
+
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey");
+
+START TRANSACTION;
+DELETE FROM diaries WHERE id = 1;
+ROLLBACK;
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey");
+
+UPDATE diaries SET title = "survey day!" WHERE id = 1;
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(title) AGAINST("survey");
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/truncate.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/truncate.test
new file mode 100644
index 00000000..f538c3d5
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/truncate.test
@@ -0,0 +1,62 @@
+# Copyright(C) 2011-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+SET NAMES UTF8;
+CREATE TABLE diaries (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ year INT UNSIGNED,
+ month INT UNSIGNED,
+ day INT UNSIGNED,
+ title VARCHAR(255),
+ content TEXT,
+ FULLTEXT INDEX(content),
+ KEY(day)
+) DEFAULT CHARSET UTF8 COMMENT = 'engine "innodb"';
+
+INSERT INTO diaries VALUES(1, 2011, 11, 9, "Hello", "今日からはじめました。");
+INSERT INTO diaries VALUES(2, 2011, 11, 10, "天気", "明日の富士山の天気について");
+INSERT INTO diaries VALUES(3, 2011, 11, 11, "富士山", "今日も天気がよくてきれいに見える。");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ ORDER BY id;
+TRUNCATE TABLE diaries;
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("+今日" IN BOOLEAN MODE)
+ ORDER BY id;
+
+INSERT INTO diaries VALUES(1, 2011, 11, 11, "帰り道", "つかれたー");
+INSERT INTO diaries VALUES(2, 2011, 12, 1, "久しぶり", "天気が悪いからずっと留守番。");
+INSERT INTO diaries VALUES(3, 2011, 12, 2, "初雪", "今年はじめての雪!");
+
+SELECT * FROM diaries;
+SELECT * FROM diaries
+ WHERE MATCH(content) AGAINST("+悪い" IN BOOLEAN MODE)
+ ORDER BY id;
+
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/update_fulltext.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/update_fulltext.test
new file mode 100644
index 00000000..fae21d7b
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/update_fulltext.test
@@ -0,0 +1,43 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 text, fulltext index (c2)) COMMENT = 'engine "innodb"';
+insert into t1 values(10, "aa ii uu ee");
+insert into t1 values(20, "ka ki ku ke");
+insert into t1 values(30, "sa si su se");
+
+select * from t1;
+update t1 set c2="ta ti tu te" where c1=20;
+select * from t1;
+select * from t1 where match(c2) against("ti");
+select * from t1 where match(c2) against("ki");
+
+update t1 set c1=40 where c1=20;
+select * from t1;
+select * from t1 where match(c2) against("ti");
+select * from t1 where match(c2) against("ki");
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/update_int.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/update_int.test
new file mode 100644
index 00000000..a42c06e6
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/update_int.test
@@ -0,0 +1,41 @@
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists t1, t2, t3;
+--enable_warnings
+
+create table t1 (c1 int primary key, c2 int) COMMENT = 'engine "innodb"';
+show create table t1;
+insert into t1 values (1, 100);
+insert into t1 values (2, 101);
+insert into t1 values (3, 102);
+select * from t1;
+
+update t1 set c2=c2+100 where c1=1;
+select * from t1;
+update t1 set c2=c2+100 where c1=2;
+select * from t1;
+update t1 set c2=c2+100 where c1=3;
+select * from t1;
+
+drop table t1;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_delete.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_delete.test
new file mode 100644
index 00000000..2669423f
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_delete.test
@@ -0,0 +1,54 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8 COMMENT = 'engine "innodb"';
+
+insert into diaries (body) values ("will start groonga!");
+insert into diaries (body) values ("starting groonga...");
+insert into diaries (body) values ("started groonga.");
+select * from diaries;
+
+set mroonga_dry_write=true;
+delete from diaries where id = 2;
+select * from diaries;
+select * from diaries where match (body) against ("starting");
+select * from diaries where match (body) against ("started");
+
+set mroonga_dry_write=false;
+delete from diaries where id = 3;
+select * from diaries;
+select * from diaries where match (body) against ("starting");
+select * from diaries where match (body) against ("started");
+
+insert into diaries (id, body) values (2, "sleeping...");
+select * from diaries;
+select * from diaries where match (body) against ("starting");
+select * from diaries where match (body) against ("started");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_insert.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_insert.test
new file mode 100644
index 00000000..5e369b24
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_insert.test
@@ -0,0 +1,46 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8 COMMENT = 'engine "innodb"';
+
+insert into diaries (body) values ("will start groonga!");
+select * from diaries;
+select * from diaries where match (body) against ("groonga");
+
+set mroonga_dry_write=true;
+insert into diaries (body) values ("starting groonga...");
+select * from diaries;
+select * from diaries where match (body) against ("groonga");
+
+set mroonga_dry_write=false;
+insert into diaries (body) values ("started groonga.");
+select * from diaries;
+select * from diaries where match (body) against ("groonga");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_update.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_update.test
new file mode 100644
index 00000000..f27e9c7d
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_dry_write_update.test
@@ -0,0 +1,47 @@
+# Copyright(C) 2011 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+drop table if exists diaries;
+--enable_warnings
+
+create table diaries (
+ id int primary key auto_increment,
+ body text,
+ fulltext index body_index (body)
+) default charset utf8 COMMENT = 'engine "innodb"';
+
+insert into diaries (body) values ("will start groonga!");
+
+set mroonga_dry_write=true;
+update diaries set body = "starting groonga..." where id = 1;
+select * from diaries;
+select * from diaries where match (body) against ("will");
+select * from diaries where match (body) against ("starting");
+
+set mroonga_dry_write=false;
+update diaries set body = "started groonga." where id = 1;
+select * from diaries;
+select * from diaries where match (body) against ("will");
+select * from diaries where match (body) against ("starting");
+select * from diaries where match (body) against ("started");
+
+drop table diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_global.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_global.test
new file mode 100644
index 00000000..a81468ea
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_global.test
@@ -0,0 +1,60 @@
+# Copyright(C) 2012-2015 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ tags TEXT,
+ FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO diaries (title, tags) VALUES ("Hello groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello mroonga!", "mroonga install");
+
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+# MySQL <= 5.5 reports a wrong warning. :<
+# It has been fixed in MySQL >= 5.6 and MariaDB >= 5.3.
+--disable_warnings
+SET GLOBAL mroonga_match_escalation_threshold = -1;
+--enable_warnings
+
+disable_query_log;
+CONNECT(search_connection, localhost, root);
+enable_query_log;
+USE test;
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+disable_query_log;
+DISCONNECT search_connection;
+CONNECTION default;
+enable_query_log;
+
+SET GLOBAL mroonga_match_escalation_threshold = DEFAULT;
+
+DROP TABLE diaries;
+
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_session.test b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_session.test
new file mode 100644
index 00000000..94f1a3ca
--- /dev/null
+++ b/storage/mroonga/mysql-test/mroonga/wrapper/t/variable_match_escalation_threshold_session.test
@@ -0,0 +1,52 @@
+# 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-1335 USA
+
+--source include/have_innodb.inc
+--source ../../include/mroonga/have_mroonga.inc
+
+--disable_warnings
+DROP TABLE IF EXISTS diaries;
+--enable_warnings
+
+CREATE TABLE diaries (
+ id INT PRIMARY KEY AUTO_INCREMENT,
+ title TEXT,
+ tags TEXT,
+ FULLTEXT INDEX tags_index (tags) COMMENT 'tokenizer "TokenDelimit"'
+) DEFAULT CHARSET=UTF8 COMMENT='ENGINE "InnoDB"';
+
+INSERT INTO diaries (title, tags) VALUES ("Hello groonga!", "groonga install");
+INSERT INTO diaries (title, tags) VALUES ("Hello mroonga!", "mroonga install");
+
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("install" IN BOOLEAN MODE);
+
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+# MySQL <= 5.5 reports a wrong warning. :<
+# It has been fixed in MySQL >= 5.6 and MariaDB >= 5.3.
+--disable_warnings
+SET mroonga_match_escalation_threshold = -1;
+--enable_warnings
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+SET mroonga_match_escalation_threshold = 0;
+SELECT * FROM diaries WHERE MATCH (tags) AGAINST ("gr" IN BOOLEAN MODE);
+
+
+DROP TABLE diaries;
+
+--source ../../include/mroonga/have_mroonga_deinit.inc
diff --git a/storage/mroonga/packages/Makefile.am b/storage/mroonga/packages/Makefile.am
new file mode 100644
index 00000000..fed925c3
--- /dev/null
+++ b/storage/mroonga/packages/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS = \
+ apt \
+ rpm \
+ source \
+ ubuntu \
+ windows \
+ yum
diff --git a/storage/mroonga/packages/apt/Makefile.am b/storage/mroonga/packages/apt/Makefile.am
new file mode 100644
index 00000000..0ebc7f67
--- /dev/null
+++ b/storage/mroonga/packages/apt/Makefile.am
@@ -0,0 +1,91 @@
+REPOSITORIES_PATH = repositories
+DISTRIBUTIONS = debian
+ARCHITECTURES = i386 amd64
+CODE_NAMES = jessie stretch
+MYSQL_VARIANTS = 5.5 mariadb-10.0
+
+all:
+
+release: download build sign-packages update-repository sign-repository upload
+
+remove-existing-packages:
+ for distribution in $(DISTRIBUTIONS); do \
+ find $(REPOSITORIES_PATH)/$${distribution}/pool \
+ -type f -delete; \
+ done
+
+download:
+ for distribution in $(DISTRIBUTIONS); do \
+ rsync -avz --progress --delete \
+ $(RSYNC_PATH)/$${distribution} $(REPOSITORIES_PATH)/; \
+ done
+
+sign-packages:
+ ./sign-packages.sh '$(GPG_UID)' '$(REPOSITORIES_PATH)/' '$(CODE_NAMES)'
+
+update-repository:
+ ./update-repository.sh '$(PACKAGE_NAME)' '$(REPOSITORIES_PATH)/' \
+ '$(ARCHITECTURES)' '$(CODE_NAMES)'
+
+sign-repository:
+ ./sign-repository.sh '$(GPG_UID)' '$(REPOSITORIES_PATH)/' '$(CODE_NAMES)'
+
+ensure-rsync-path:
+ @if test -z "$(RSYNC_PATH)"; then \
+ echo "--with-rsync-path configure option must be specified."; \
+ false; \
+ fi
+
+upload: ensure-rsync-path
+ for distribution in $(DISTRIBUTIONS); do \
+ (cd $(REPOSITORIES_PATH)/$${distribution}; \
+ rsync -avz --progress --delete \
+ dists pool $(RSYNC_PATH)/$${distribution}; \
+ ); \
+ done
+
+build: build-package-deb
+
+build-package-deb: source env.sh
+ vagrant destroy --force
+ for variant in $(MYSQL_VARIANTS); do \
+ cp env.sh tmp/; \
+ echo "MYSQL_VARIANT=$${variant}" >> tmp/env.sh; \
+ for architecture in $(ARCHITECTURES); do \
+ for code_name in $(CODE_NAMES); do \
+ rm -rf tmp/debian; \
+ if [ $${variant} = "5.5" -a $${code_name} = "stretch" ]; then \
+ continue; \
+ fi; \
+ if [ $${code_name} = "stretch" ]; then \
+ cp -rp $(srcdir)/../debian-mariadb-10.0 tmp/debian; \
+ for f in `find tmp/debian -maxdepth 2 -type f`; do \
+ RENAMED=`echo $$f | sed 's/10.0/10.1/'`; \
+ sed -i'' 's/10.0/10.1/g' $${f}; \
+ if [ $${f} = $$RENAMED ]; then \
+ continue; \
+ fi; \
+ mv $${f} $$RENAMED; \
+ done; \
+ if [ $${architecture} = "amd64" ]; then \
+ sed -i'' 's,lib/mysql/,lib/x86_64-linux-gnu/mariadb18/,' \
+ tmp/debian/mariadb-server-10.1-mroonga.install; \
+ elif [ $${architecture} = "i386" ]; then \
+ sed -i'' 's,lib/mysql/,lib/i386-linux-gnu/mariadb18/,' \
+ tmp/debian/mariadb-server-10.1-mroonga.install; \
+ fi; \
+ else \
+ cp -rp $(srcdir)/../debian-$${variant} tmp/debian; \
+ fi; \
+ id=debian-$$code_name-$$architecture; \
+ vagrant up $$id || exit 1; \
+ vagrant destroy --force $$id; \
+ done; \
+ done; \
+ done
+
+source: tmp/$(PACKAGE)-$(VERSION).tar.gz
+
+tmp/$(PACKAGE)-$(VERSION).tar.gz: $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz
+ mkdir -p tmp
+ cp $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz $@
diff --git a/storage/mroonga/packages/apt/Vagrantfile b/storage/mroonga/packages/apt/Vagrantfile
new file mode 100644
index 00000000..ee4a6aeb
--- /dev/null
+++ b/storage/mroonga/packages/apt/Vagrantfile
@@ -0,0 +1,50 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ vms = [
+ {
+ :id => "debian-jessie-i386",
+ :box => "bento/debian-8.9-i386",
+ },
+ {
+ :id => "debian-jessie-amd64",
+ :box => "bento/debian-8.9",
+ },
+ {
+ :id => "debian-stretch-i386",
+ :box => "bento/debian-9.1-i386",
+ },
+ {
+ :id => "debian-stretch-amd64",
+ :box => "bento/debian-9.1",
+ },
+ ]
+
+ vms.each do |vm|
+ config.vm.define(vm[:id]) do |node|
+ # Use official box
+ node.vm.box = vm[:box] if vm[:box]
+ # Use box and box_url until official box is released
+ node.vm.box = vm[:id] if vm[:box_url]
+ node.vm.box_url = vm[:box_url] if vm[:box_url]
+ node.vm.provision(:shell, :path => "build-deb.sh")
+ node.vm.provider("virtualbox") do |virtual_box|
+ system_n_cpus = 1
+ if File.exist?("/proc/cpuinfo")
+ system_n_cpus = File.readlines("/proc/cpuinfo").grep(/^processor/).size
+ end
+ if system_n_cpus > 1
+ vm_n_cpus = system_n_cpus / 2
+ else
+ vm_n_cpus = 1
+ end
+ virtual_box.cpus = (ENV["VM_CPUS"] || vm_n_cpus).to_i
+ virtual_box.memory = (ENV["VM_MEMORY"] || 768).to_i
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/packages/apt/build-deb.sh b/storage/mroonga/packages/apt/build-deb.sh
new file mode 100755
index 00000000..e0e03d8e
--- /dev/null
+++ b/storage/mroonga/packages/apt/build-deb.sh
@@ -0,0 +1,106 @@
+#!/bin/sh
+
+LANG=C
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+. /vagrant/tmp/env.sh
+
+code_name=$(lsb_release --codename --short)
+case "${MYSQL_VARIANT}" in
+ mariadb-*)
+ case "${code_name}" in
+ stretch)
+ mysql_server_package=mariadb-server-10.1
+ MYSQL_VARIANT=mariadb-10.1
+ ;;
+ *)
+ mysql_server_package=mariadb-server-${MYSQL_VARIANT##mariadb-}
+ ;;
+ esac
+ DEPENDED_PACKAGES="${DEPENDED_PACKAGES} libmariadb-client-lgpl-dev"
+ DEPENDED_PACKAGES="${DEPENDED_PACKAGES} libmariadbd-dev"
+ ;;
+ *)
+ mysql_server_package=mysql-server-${MYSQL_VARIANT}
+ DEPENDED_PACKAGES="${DEPENDED_PACKAGES} libmysqlclient-dev"
+ DEPENDED_PACKAGES="${DEPENDED_PACKAGES} libmysqld-dev"
+ ;;
+esac
+
+grep '^deb ' /etc/apt/sources.list | \
+ sed -e 's/^deb /deb-src /' > /etc/apt/sources.list.d/base-source.list
+
+run sudo sed -i'' -e 's/httpredir/ftp.jp/g' /etc/apt/sources.list
+
+run apt-get update
+run apt-get install -y lsb-release
+
+distribution=$(lsb_release --id --short | tr 'A-Z' 'a-z')
+case "${distribution}" in
+ debian)
+ component=main
+ run cat <<EOF > /etc/apt/sources.list.d/groonga.list
+deb http://packages.groonga.org/debian/ ${code_name} main
+deb-src http://packages.groonga.org/debian/ ${code_name} main
+EOF
+ if ! grep --quiet security /etc/apt/sources.list; then
+ run cat <<EOF > /etc/apt/sources.list.d/security.list
+deb http://security.debian.org/ ${code_name}/updates main
+deb-src http://security.debian.org/ ${code_name}/updates main
+EOF
+ fi
+ run apt-get update
+ run apt-get install -y --allow-unauthenticated groonga-keyring
+ run apt-get update
+ ;;
+ ubuntu)
+ component=universe
+ run cat <<EOF > /etc/apt/sources.list.d/security.list
+deb http://security.ubuntu.com/ubuntu ${code_name}-security main restricted
+deb-src http://security.ubuntu.com/ubuntu ${code_name}-security main restricted
+EOF
+ run sed -e 's/main/universe/' /etc/apt/sources.list > \
+ /etc/apt/sources.list.d/universe.list
+ run apt-get -y install software-properties-common
+ run add-apt-repository -y universe
+ run add-apt-repository -y ppa:groonga/ppa
+ run apt-get update
+ ;;
+esac
+
+run apt-get install -V -y build-essential devscripts ${DEPENDED_PACKAGES}
+run apt-get build-dep -y ${mysql_server_package}
+
+run mkdir -p build
+run cd build
+run tar xfz /vagrant/tmp/${PACKAGE}-${VERSION}.tar.gz
+run mv ${PACKAGE}-${VERSION} ${PACKAGE}-${MYSQL_VARIANT}-${VERSION}
+run tar cfz ${PACKAGE}-${MYSQL_VARIANT}_${VERSION}.orig.tar.gz \
+ ${PACKAGE}-${MYSQL_VARIANT}-${VERSION}
+run cd ${PACKAGE}-${MYSQL_VARIANT}-${VERSION}/
+run cp -rp /vagrant/tmp/debian debian
+# export DEB_BUILD_OPTIONS=noopt
+MYSQL_PACKAGE_INFO=$(apt-cache show ${mysql_server_package} |
+ grep Version |
+ sort |
+ tail -1)
+MYSQL_PACKAGE_VERSION=${MYSQL_PACKAGE_INFO##Version: }
+sed -i'' \
+ -e "s/MYSQL_VERSION/$MYSQL_PACKAGE_VERSION/g" \
+ -e "s/MARIADB_VERSION/$MYSQL_PACKAGE_VERSION/g" \
+ debian/control
+run debuild -us -uc
+run cd -
+
+package_initial=$(echo "${PACKAGE}" | sed -e 's/\(.\).*/\1/')
+pool_dir="/vagrant/repositories/${distribution}/pool/${code_name}/${component}/${package_initial}/${PACKAGE}"
+run mkdir -p "${pool_dir}/"
+run cp *.tar.* *.diff.gz *.dsc *.deb "${pool_dir}/"
diff --git a/storage/mroonga/packages/apt/env.sh.in b/storage/mroonga/packages/apt/env.sh.in
new file mode 100644
index 00000000..51109aee
--- /dev/null
+++ b/storage/mroonga/packages/apt/env.sh.in
@@ -0,0 +1,16 @@
+PACKAGE=@PACKAGE@
+VERSION=@VERSION@
+DEPENDED_PACKAGES="
+debhelper
+autotools-dev
+libgroonga-dev
+pkg-config
+libmecab-dev
+mecab-utils
+gdb
+libxml2-dev
+unixodbc-dev
+libssl-dev
+groonga-normalizer-mysql
+wget
+"
diff --git a/storage/mroonga/packages/apt/sign-packages.sh b/storage/mroonga/packages/apt/sign-packages.sh
new file mode 100755
index 00000000..57c985f3
--- /dev/null
+++ b/storage/mroonga/packages/apt/sign-packages.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_UID DESITINATION CODES"
+ echo " e.g.: $0 'F10399C0' repositories/ 'lenny unstable hardy karmic'"
+ exit 1
+fi
+
+GPG_UID=$1
+DESTINATION=$2
+CODES=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+for code_name in ${CODES}; do
+ case ${code_name} in
+ jessie|stretch|unstable)
+ distribution=debian
+ ;;
+ *)
+ distribution=ubuntu
+ ;;
+ esac
+
+ base_directory=${DESTINATION}${distribution}
+ debsign -pgpg2 --re-sign -k${GPG_UID} \
+ $(find ${base_directory} -name '*.dsc' -or -name '*.changes') &
+ if [ "${PARALLEL}" != "yes" ]; then
+ wait
+ fi
+done
+
+wait
diff --git a/storage/mroonga/packages/apt/sign-repository.sh b/storage/mroonga/packages/apt/sign-repository.sh
new file mode 100755
index 00000000..e0d963ff
--- /dev/null
+++ b/storage/mroonga/packages/apt/sign-repository.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_UID DESTINATION CODES"
+ echo " e.g.: $0 'F10399C0' repositories/ 'lenny unstable hardy karmic'"
+ exit 1
+fi
+
+GPG_UID=$1
+DESTINATION=$2
+CODES=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+for code_name in ${CODES}; do
+ case ${code_name} in
+ jessie|stretch|unstable)
+ distribution=debian
+ ;;
+ *)
+ distribution=ubuntu
+ ;;
+ esac
+
+ release=${DESTINATION}${distribution}/dists/${code_name}/Release
+ rm -f ${release}.gpg
+ gpg2 --sign --detach-sign --armor \
+ --local-user ${GPG_UID} \
+ --output ${release}.gpg \
+ ${release} &
+
+ if [ "${PARALLEL}" != "yes" ]; then
+ wait
+ fi
+done
+
+wait
diff --git a/storage/mroonga/packages/apt/update-repository.sh b/storage/mroonga/packages/apt/update-repository.sh
new file mode 100755
index 00000000..a95ad117
--- /dev/null
+++ b/storage/mroonga/packages/apt/update-repository.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 4 ]; then
+ echo "Usage: $0 PROJECT_NAME DESTINATION ARCHITECTURES CODES"
+ echo " e.g.: $0 mroonga repositories/ 'i386 amd64' 'lenny unstable hardy karmic'"
+ exit 1
+fi
+
+PROJECT_NAME=$1
+DESTINATION=$2
+ARCHITECTURES=$3
+CODES=$4
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+update_repository()
+{
+ distribution=$1
+ code_name=$2
+ component=$3
+
+ rm -rf dists/${code_name}
+ mkdir -p dists/${code_name}/${component}/binary-i386/
+ mkdir -p dists/${code_name}/${component}/binary-amd64/
+ mkdir -p dists/${code_name}/${component}/source/
+
+ cat <<EOF > dists/.htaccess
+Options +Indexes
+EOF
+
+ cat <<EOF > dists/${code_name}/${component}/binary-i386/Release
+Archive: ${code_name}
+Component: ${component}
+Origin: The ${PROJECT_NAME} project
+Label: The ${PROJECT_NAME} project
+Architecture: i386
+EOF
+
+ cat <<EOF > dists/${code_name}/${component}/binary-amd64/Release
+Archive: ${code_name}
+Component: ${component}
+Origin: The ${PROJECT_NAME} project
+Label: The ${PROJECT_NAME} project
+Architecture: amd64
+EOF
+
+ cat <<EOF > dists/${code_name}/${component}/source/Release
+Archive: ${code_name}
+Component: ${component}
+Origin: The ${PROJECT_NAME} project
+Label: The ${PROJECT_NAME} project
+Architecture: source
+EOF
+
+ cat <<EOF > generate-${code_name}.conf
+Dir::ArchiveDir ".";
+Dir::CacheDir ".";
+TreeDefault::Directory "pool/${code_name}/${component}";
+TreeDefault::SrcDirectory "pool/${code_name}/${component}";
+Default::Packages::Extensions ".deb";
+Default::Packages::Compress ". gzip bzip2";
+Default::Sources::Compress ". gzip bzip2";
+Default::Contents::Compress "gzip bzip2";
+
+BinDirectory "dists/${code_name}/${component}/binary-i386" {
+ Packages "dists/${code_name}/${component}/binary-i386/Packages";
+ Contents "dists/${code_name}/Contents-i386";
+ SrcPackages "dists/${code_name}/${component}/source/Sources";
+};
+
+BinDirectory "dists/${code_name}/${component}/binary-amd64" {
+ Packages "dists/${code_name}/${component}/binary-amd64/Packages";
+ Contents "dists/${code_name}/Contents-amd64";
+ SrcPackages "dists/${code_name}/${component}/source/Sources";
+};
+
+Tree "dists/${code_name}" {
+ Sections "${component}";
+ Architectures "i386 amd64 source";
+};
+EOF
+ apt-ftparchive generate generate-${code_name}.conf
+ chmod 644 dists/${code_name}/Contents-*
+
+ rm -f dists/${code_name}/Release*
+ rm -f *.db
+ cat <<EOF > release-${code_name}.conf
+APT::FTPArchive::Release::Origin "The ${PROJECT_NAME} project";
+APT::FTPArchive::Release::Label "The ${PROJECT_NAME} project";
+APT::FTPArchive::Release::Architectures "i386 amd64";
+APT::FTPArchive::Release::Codename "${code_name}";
+APT::FTPArchive::Release::Suite "${code_name}";
+APT::FTPArchive::Release::Components "${component}";
+APT::FTPArchive::Release::Description "${PACKAGE_NAME} packages";
+EOF
+ apt-ftparchive -c release-${code_name}.conf \
+ release dists/${code_name} > /tmp/Release
+ mv /tmp/Release dists/${code_name}
+}
+
+for code_name in ${CODES}; do
+ case ${code_name} in
+ jessie|stretch|unstable)
+ distribution=debian
+ component=main
+ ;;
+ *)
+ distribution=ubuntu
+ component=universe
+ ;;
+ esac
+
+ mkdir -p ${DESTINATION}${distribution}
+ (cd ${DESTINATION}${distribution}
+ update_repository $distribution $code_name $component) &
+ if [ "${PARALLEL}" != "yes" ]; then
+ wait
+ fi
+done
+
+wait
diff --git a/storage/mroonga/packages/rpm/Makefile.am b/storage/mroonga/packages/rpm/Makefile.am
new file mode 100644
index 00000000..aa1ba3ad
--- /dev/null
+++ b/storage/mroonga/packages/rpm/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = \
+ centos
diff --git a/storage/mroonga/packages/rpm/centos/Makefile.am b/storage/mroonga/packages/rpm/centos/Makefile.am
new file mode 100644
index 00000000..72d860a9
--- /dev/null
+++ b/storage/mroonga/packages/rpm/centos/Makefile.am
@@ -0,0 +1,19 @@
+EXTRA_DIST = \
+ mysql55-mroonga.spec.in \
+ mysql56-community-mroonga.spec.in \
+ mysql57-community-mroonga.spec.in \
+ mariadb-mroonga.spec.in \
+ mariadb-10.1-mroonga.spec.in \
+ mariadb-10.2-mroonga.spec.in \
+ percona-server-56-mroonga.spec.in \
+ percona-server-57-mroonga.spec.in
+
+noinst_DATA = \
+ mysql55-mroonga.spec \
+ mysql56-community-mroonga.spec \
+ mysql57-community-mroonga.spec \
+ mariadb-mroonga.spec \
+ mariadb-10.1-mroonga.spec \
+ mariadb-10.2-mroonga.spec \
+ percona-server-56-mroonga.spec \
+ percona-server-57-mroonga.spec
diff --git a/storage/mroonga/packages/rpm/centos/mariadb-mroonga.spec.in b/storage/mroonga/packages/rpm/centos/mariadb-mroonga.spec.in
new file mode 100644
index 00000000..d23c499f
--- /dev/null
+++ b/storage/mroonga/packages/rpm/centos/mariadb-mroonga.spec.in
@@ -0,0 +1,486 @@
+%define mariadb_epoch_default 1
+%define mariadb_version_default 5.5.56
+%define mariadb_release_default 2
+%define mariadb_dist_default .el7
+%define mariadb_download_base_url_default http://vault.centos.org/7.4.1708/os/Source/SPackages/
+%define mariadb_spec_file_default mariadb.spec
+
+%define _mariadb_epoch %{?mariadb_epoch:%{mariadb_epoch}}%{!?mariadb_epoch:%{mariadb_epoch_default}}
+%define _mariadb_version %{?mariadb_version:%{mariadb_version}}%{!?mariadb_version:%{mariadb_version_default}}
+%define _mariadb_release %{?mariadb_release:%{mariadb_release}}%{!?mariadb_release:%{mariadb_release_default}}
+%define _mariadb_dist %{?mariadb_dist:%{mariadb_dist}}%{!?mariadb_dist:%{mariadb_dist_default}}
+%define _mariadb_download_base_url %{?mariadb_download_base_url:%{mariadb_download_base_url}}%{!?mariadb_download_base_url:%{mariadb_download_base_url_default}}
+%define _mariadb_spec_file %{?mariadb_spec_file:%{mariadb_spec_file}}%{!?mariadb_spec_file:%{mariadb_spec_file_default}}
+
+%define _mariadb_package_version %{_mariadb_epoch}:%{_mariadb_version}-%{_mariadb_release}%{_mariadb_dist}
+
+%define groonga_required_version @REQUIRED_GROONGA_VERSION@
+
+Name: mariadb-mroonga
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: A fast fulltext searchable storage engine for MariaDB
+
+Group: Applications/Databases
+License: LGPLv2.1
+URL: http://mroonga.org/
+Source0: http://packages.groonga.org/source/mroonga/mroonga-%{version}.tar.gz
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
+BuildRequires: groonga-devel >= %{groonga_required_version}
+BuildRequires: groonga-normalizer-mysql-devel
+BuildRequires: wget
+BuildRequires: mariadb-devel = %{_mariadb_package_version}
+Requires: mariadb-server = %{_mariadb_package_version}
+Requires: mariadb = %{_mariadb_package_version}
+Requires: groonga-libs >= %{groonga_required_version}
+Requires: groonga-normalizer-mysql
+
+%description
+Mroonga is a fast fulltext searchable storage plugin for MariaDB.
+It is based on Groonga that is a fast fulltext search engine and
+column store. Groonga is good at real-time update.
+
+%package doc
+Summary: Documentation for Mroonga
+Group: Documentation
+License: LGPLv2.1
+
+%description doc
+Documentation for Mroonga
+
+
+%prep
+%setup -q -n mroonga-%{version}
+
+mariadb_full_version=%{_mariadb_version}-%{_mariadb_release}%{_mariadb_dist}
+srpm=mariadb-${mariadb_full_version}.src.rpm
+if [ ! -f ../../SRPMS/$srpm ]; then
+ wget --continue -O ../../SRPMS/$srpm %{_mariadb_download_base_url}/$srpm
+ rpm -Uvh ../../SRPMS/$srpm
+ rm ../../SRPMS/$srpm
+fi
+
+%build
+mariadb_source=../mariadb-%{_mariadb_version}
+if [ ! -d ${mariadb_source} ]; then
+ rpmbuild -bc \
+ --define 'runselftest 0' \
+ --define 'optflags -O0' \
+ ../../SPECS/%{_mariadb_spec_file}
+fi
+%configure \
+ --disable-static \
+ --with-mysql-source=${mariadb_source} \
+ %{?mroonga_configure_options}
+make %{?_smp_mflags}
+
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+rm $RPM_BUILD_ROOT%{_libdir}/mysql/plugin/*.la
+mv $RPM_BUILD_ROOT%{_datadir}/doc/mroonga/ mysql-mroonga-doc/
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+if /usr/bin/mysql -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+current_version=0
+version=$(echo %{groonga_required_version} | sed -e 's/\.//g')
+required_version=$(expr $version)
+version=$(/usr/bin/mysql -e "SHOW VARIABLES LIKE 'mroonga_libgroonga_version'" | \
+ grep mroonga | cut -f 2 | sed -e 's/\.//g')
+if [ -n "$version" ]; then
+ current_version=$(expr $version)
+fi
+install_sql=%{_datadir}/mroonga/install.sql
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+
+if [ "$1" = 2 ] ; then
+ if [ $current_version -lt $required_version ]; then
+ command="/usr/bin/mysql -u root $password_option"
+ echo "run the following command after restarting MySQL server:";
+ echo " $command < ${uninstall_sql}"
+ echo " $command < ${install_sql}"
+ exit 0
+ else
+ command="/usr/bin/mysql -u root $password_option"
+ command="${command} < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+ fi
+fi
+
+command="/usr/bin/mysql -u root $password_option < ${install_sql}"
+echo $command
+eval $command || \
+ (echo "run the following command to register Mroonga:"; \
+ echo " $command")
+
+%preun
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+
+if mysql -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+if [ "$1" = 0 ]; then
+ command="/usr/bin/mysql -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+fi
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/mysql/plugin/
+%{_datadir}/mroonga/*
+%{_datadir}/man/man1/*
+%{_datadir}/man/*/man1/*
+
+%files doc
+%defattr(-,root,root,-)
+%doc README COPYING
+%doc mysql-mroonga-doc/*
+
+%changelog
+* Thu Oct 12 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.07-1
+- new upstream release.
+
+* Fri Sep 15 2017 Kouhei Sutou <kou@clear-code.com> - 7.06-2
+- rebuild against the latest MariaDB.
+
+* Tue Aug 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.06-1
+- new upstream release.
+
+* Sat Jul 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.05-1
+- new upstream release.
+
+* Thu Jun 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.04-1
+- new upstream release.
+
+* Mon May 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.03-1
+- new upstream release.
+
+* Sat Apr 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.02-1
+- new upstream release.
+
+* Wed Mar 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.01-1
+- new upstream release.
+
+* Thu Feb 09 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.00-1
+- new upstream release.
+
+* Sat Oct 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.10-1
+- new upstream release.
+
+* Thu Sep 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.09-1
+- new upstream release.
+
+* Mon Aug 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.08-1
+- new upstream release.
+
+* Fri Jul 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.07-1
+- new upstream release.
+
+* Thu Jun 30 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.06-1
+- new upstream release.
+
+* Wed Jun 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.05-1
+- new upstream release.
+
+* Sun May 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.03-1
+- new upstream release.
+
+* Fri Apr 29 2016 HAYASHI Kentaro <hayashi@clear-code.com> - 6.02-1
+- new upstream release.
+
+* Tue Mar 29 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.01-1
+- new upstream release.
+
+* Mon Feb 29 2016 Kouhei Sutou <kou@clear-code.com> - 6.00-1
+- new upstream release.
+
+* Tue Dec 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.11-1
+- new upstream release.
+
+* Wed Dec 16 2015 Kouhei Sutou <kou@clear-code.com> - 5.10-2
+- rebuild against MariaDB on CentOS 7.2. Reported by Larry Kim. Thanks!!!
+
+* Sun Nov 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.10-1
+- new upstream release.
+
+* Thu Oct 29 2015 Kouhei Sutou <kou@cozmixng.org> - 5.09-1
+- new upstream release.
+
+* Tue Sep 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.08-1
+- new upstream release.
+
+* Mon Aug 31 2015 Kouhei Sutou <kou@clear-code.com> - 5.06-1
+- new upstream release.
+
+* Wed Jul 29 2015 Masafumi Yokoyama <yokoyama@clear-code.com> - 5.05-1
+- new upstream release.
+
+* Mon Jun 29 2015 Masafumi Yokoyama <myokoym@gmail.com> - 5.04-1
+- new upstream release.
+
+* Fri May 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.03-1
+- new upstream release.
+
+* Wed Apr 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.02-1
+- new upstream release.
+
+* Sun Mar 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.01-1
+- new upstream release.
+
+* Mon Feb 09 2015 <hayashi@clear-code.com> - 5.00-1
+- new upstream release.
+
+* Thu Jan 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 4.10-1
+- new upstream release.
+
+* Wed Jan 14 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 4.09-2
+- build against mariadb-5.5.40-2.el7_0.
+
+* Mon Dec 29 2014 Kouhei Sutou <kou@cozmixng.org> - 4.09-1
+- new upstream release.
+
+* Sat Nov 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.08-1
+- new upstream release.
+
+* Wed Oct 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.07-1
+- new upstream release.
+
+* Mon Sep 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.06-1
+- new upstream release.
+
+* Fri Aug 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.05-1
+- new upstream release.
+
+* Thu Aug 14 2014 Kouhei Sutou <kou@clear-code.com> - 4.04-4
+- build MariaDB for libmysqlservices.a.
+
+* Thu Aug 14 2014 Kouhei Sutou <kou@clear-code.com> - 4.04-3
+- support epoch in MariaDB.
+
+* Wed Aug 13 2014 Kouhei Sutou <kou@clear-code.com> - 4.04-2
+- build against mariadb-5.5.37-1.el7_0.
+
+* Sun Aug 10 2014 Kouhei Sutou <kou@clear-code.com> - 4.04-1
+- initial packaging for CentOS 7 based on mysql-mroogna package.
+
+* Tue Jul 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.04-1
+- new upstream release.
+
+* Thu May 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.03-1
+- new upstream release.
+
+* Tue Apr 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.02-1
+- new upstream release.
+
+* Sat Mar 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.01-1
+- new upstream release.
+
+* Thu Feb 13 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.00-2
+- use MySQL 5.1.73-3 on CentOS 6.
+
+* Sun Feb 09 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.00-1
+- new upstream release.
+
+* Wed Jan 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 3.12-1
+- new upstream release.
+
+* Sun Dec 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.11-1
+- new upstream release.
+
+* Sat Dec 7 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.10-2
+- use MySQL 5.1.71-1 on CentOS 6.
+
+* Fri Nov 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.10-1
+- new upstream release.
+
+* Tue Oct 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.09-1
+- new upstream release.
+
+* Sun Sep 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.08-1
+- new upstream release.
+- use MySQL 5.6.14-1 on CentOS 5.
+
+* Wed Sep 4 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.07-2
+- fix a bug that mroonga is removed accidentally on upgrade #1918.
+ Reported by @ceekz. Thanks!!!
+
+* Thu Aug 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.07-1
+- new upstream release.
+- use MySQL 5.6.13-1 on CentOS 5.
+
+* Mon Jul 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.06-1
+- new upstream release.
+- use MySQL 5.6.12-2 on CentOS 5.
+
+* Sat Jun 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.05-1
+- new upstream release.
+- use MySQL 5.6.12 on CentOS 5.
+
+* Wed May 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.04-1
+- new upstream release.
+
+* Fri May 10 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.03-2
+- use MySQL 5.6.11-2 on CentOS 5. see http://bugs.mysql.com/bug.php?id=69027
+ Reported by Y.Kentaro. Thanks!!!
+
+* Mon Apr 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.03-1
+- new upstream release.
+
+* Fri Mar 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.02-0
+- new upstream release.
+
+* Thu Feb 28 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.01-0
+- new upstream release.
+
+* Sat Feb 09 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.00-0
+- new upstream release.
+- require groonga 3.0.0 or later
+
+* Tue Feb 05 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 2.10-2
+- use MySQL 5.1.67-1 on CentOS 6.
+ Reported by wakisuke.ua. Thanks!!!
+
+* Sat Dec 29 2012 HAYASHI Kentaro <hayashi@clear-code.com> - 2.10-0
+- new upstream release.
+
+* Mon Dec 10 2012 HAYASHI Kentaro <hayashi@clear-code.com> - 2.09-1
+- use MySQL 5.1.66-2 on CentOS 6.
+ Reported by wakisuke.ua. Thanks!!!
+
+* Thu Nov 29 2012 HAYASHI Kentaro <hayashi@clear-code.com> - 2.09-0
+- new upstream release.
+- use MySQL 5.5.28 on CentOS 5.
+- use MySQL 5.1.66 on CentOS 6.
+
+* Mon Oct 29 2012 HAYASHI Kentaro <hayashi@clear-code.com> - 2.08-0
+- new upstream release.
+- add missing "DROP FUNCTION mroonga_snippet".
+ Reported by @tokuhy. Thanks!!!
+
+* Sat Sep 29 2012 HAYASHI Kentaro <hayashi@clear-code.com> - 2.07-0
+- new upstream release.
+
+* Wed Aug 29 2012 Kouhei Sutou <kou@clear-code.com> - 2.06-0
+- new upstream release.
+- make MySQL spec file name customizable.
+- make mroonga configure options customizable.
+- add missing mysql-devel BuildRequires. Reported by wing. Thanks!!!
+- use MySQL 5.5.27.
+
+* Sun Jul 29 2012 HAYASHI Kentaro <hayashi@clear-code.com> - 2.05-0
+- new upstream release.
+- use MySQL 5.5.25a.
+
+* Fri Jun 29 2012 Kouhei Sutou <kou@clear-code.com> - 2.04-0
+- new upstream release.
+- ensure deleting mroonga plugin before install.
+ Suggested by Kazuhiro Isobe. Thanks!!!
+- use MySQL 5.5.25.
+
+* Tue May 29 2012 Kouhei Sutou <kou@clear-code.com> - 2.03-0
+- new upstream release.
+- use MySQL 5.5.24.
+- make mysql_* variables customizable
+- require groonga 2.0.3 or later.
+
+* Sun Apr 29 2012 Kouhei Sutou <kou@clear-code.com> - 2.02-0
+- new upstream release.
+- use MySQL 5.5.23.
+- require groonga 2.0.2 or later.
+
+* Thu Mar 29 2012 Kouhei Sutou <kou@clear-code.com> - 2.01-0
+- new upstream release.
+- ensure plugin is uninstalled by closing all tables use mroonga.
+
+* Wed Feb 29 2012 Kouhei Sutou <kou@clear-code.com> - 2.00-0
+- new upstream release.
+- always install/uninstall plugin.
+- use MySQL 5.1.61 and 5.5.21.
+- require groonga 2.0.0 or later.
+
+* Sun Jan 29 2012 Kouhei Sutou <kou@clear-code.com> - 1.20-0
+- new upstream release.
+- require groonga 1.3.0.
+- groonga -> mroonga.
+- use MySQL 5.5.20.
+
+* Thu Dec 29 2011 Kouhei Sutou <kou@clear-code.com> - 1.11-0
+- new upstream release.
+
+* Sat Oct 29 2011 Kouhei Sutou <kou@clear-code.com> - 1.10-0
+- new upstream release.
+- groonga storage engine -> mroonga.
+
+* Thu Sep 29 2011 Kouhei Sutou <kou@clear-code.com> - 1.0.0-0
+- new upstream release.
+
+* Mon Aug 29 2011 Kouhei Sutou <kou@clear-code.com> - 0.9-0
+- new upstream release.
+
+* Fri Jul 29 2011 Kouhei Sutou <kou@clear-code.com> - 0.8-0
+- new upstream release.
+
+* Wed Jun 29 2011 Kouhei Sutou <kou@clear-code.com> - 0.7-0
+- new upstream release.
+
+* Sun May 29 2011 Kouhei Sutou <kou@clear-code.com> - 0.6-0
+- new upstream release.
+
+* Tue May 17 2011 Kouhei Sutou <kou@clear-code.com> - 0.5-2
+- use MySQL 5.5.12.
+
+* Tue Mar 29 2011 Kouhei Sutou <kou@clear-code.com> - 0.5-1
+- new upstream release.
+
+* Sat Jan 29 2011 Kouhei Sutou <kou@clear-code.com> - 0.4-4
+- do not remove plugin on upgrade.
+
+* Wed Jan 12 2011 Kouhei Sutou <kou@clear-code.com> - 0.4-3
+- rebuild without debug symbol.
+
+* Thu Dec 30 2010 Kouhei Sutou <kou@clear-code.com> - 0.4-2
+- use MySQL 5.5.8-1.
+- fix SQL literal notation.
+
+* Mon Nov 29 2010 Kouhei Sutou <kou@clear-code.com> - 0.4-1
+- use the latest MySQL.
+- new upstream release.
+
+* Sun Nov 21 2010 Kouhei Sutou <kou@clear-code.com> - 0.3-2
+- install user define function.
+
+* Fri Oct 29 2010 Kouhei Sutou <kou@clear-code.com> - 0.3-1
+- new upstream release.
+
+* Fri Oct 08 2010 Kouhei Sutou <kou@clear-code.com> - 0.2-2
+- specify target MySQL version.
+- use %{version}.
+
+* Wed Sep 29 2010 Kouhei Sutou <kou@clear-code.com> - 0.2-1
+- new upstream release.
+
+* Sun Sep 12 2010 Kouhei Sutou <kou@clear-code.com> - 0.1-3
+- require MySQL-client-community.
+
+* Fri Sep 10 2010 Kouhei Sutou <kou@clear-code.com> - 0.1-2
+- use MySQL-devel-community.
+
+* Fri Sep 03 2010 Kouhei Sutou <kou@clear-code.com> - 0.1-1
+- initial packaging for CentOS.
diff --git a/storage/mroonga/packages/rpm/centos/mysql55-mroonga.spec.in b/storage/mroonga/packages/rpm/centos/mysql55-mroonga.spec.in
new file mode 100644
index 00000000..8bd2ba54
--- /dev/null
+++ b/storage/mroonga/packages/rpm/centos/mysql55-mroonga.spec.in
@@ -0,0 +1,311 @@
+%{?scl:%scl_package mroonga}
+%{!?scl:%global pkg_name %{name}}
+%define _centos_ver %{?centos_ver:%{centos_ver}}%{!?centos_ver:5}
+
+%if %{_centos_ver} == 6
+%define mysql_version_default 5.5.52
+%define mysql_release_default 1
+%define mysql_dist_default el6
+%define mysql_download_base_url_default http://vault.centos.org/6.8/sclo/Source/rh/mysql55/
+%define mysql_spec_file_default mysql.spec
+%else
+%define mysql_version_default 5.5.45
+%define mysql_release_default 1
+%define mysql_dist_default el5
+%define mysql_download_base_url_default http://vault.centos.org/5.11/updates/SRPMS
+%define mysql_spec_file_default mysql.spec
+%endif
+
+%define _mysql_version %{?mysql_version:%{mysql_version}}%{!?mysql_version:%{mysql_version_default}}
+%define _mysql_release %{?mysql_release:%{mysql_release}}%{!?mysql_release:%{mysql_release_default}}
+%define _mysql_dist %{?mysql_dist:%{mysql_dist}}%{!?mysql_dist:%{mysql_dist_default}}
+%define _mysql_download_base_url %{?mysql_download_base_url:%{mysql_download_base_url}}%{!?mysql_download_base_url:%{mysql_download_base_url_default}}
+%define _mysql_spec_file %{?mysql_spec_file:%{mysql_spec_file}}%{!?mysql_spec_file:%{mysql_spec_file_default}}
+
+%define groonga_required_version @REQUIRED_GROONGA_VERSION@
+
+Name: %{?scl_prefix}mroonga
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: A fast fulltext searchable storage engine for MySQL
+
+Group: Applications/Databases
+License: LGPLv2.1
+URL: http://mroonga.org/
+Source0: http://packages.groonga.org/source/mroonga/mroonga-%{version}.tar.gz
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
+BuildRequires: groonga-devel >= %{groonga_required_version}
+BuildRequires: groonga-normalizer-mysql-devel
+BuildRequires: wget
+BuildRequires: which
+BuildRequires: mysql55-mysql-devel = %{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+BuildRequires: mysql55-build
+Requires: mysql55-mysql-server = %{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+Requires: mysql55-mysql = %{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+Requires: groonga-libs >= %{groonga_required_version}
+Requires: groonga-normalizer-mysql
+%{?scl:Requires: %scl_runtime}
+
+%description
+Mroonga is a fast fulltext searchable storage plugin for MySQL.
+It is based on Groonga that is a fast fulltext search engine and
+column store. Groonga is good at real-time update.
+
+%package doc
+Summary: Documentation for Mroonga
+Group: Documentation
+License: LGPLv2.1
+
+%description doc
+Documentation for Mroonga
+
+
+%prep
+%setup -q -n %{pkg_name}-%{version}
+
+mysql_full_version=%{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+srpm=mysql55-mysql-${mysql_full_version}.src.rpm
+if [ ! -f ../../SRPMS/$srpm ]; then
+ wget --continue -O ../../SRPMS/$srpm %{_mysql_download_base_url}/$srpm
+ rpm -Uvh ../../SRPMS/$srpm
+fi
+
+%build
+mysql_source=../mysql-%{_mysql_version}
+if [ ! -d ${mysql_source} ]; then
+ specs_dir=
+ MYSQL_RPMBUILD_TEST=no rpmbuild -bp \
+ --define 'runselftest 0' \
+ --define 'optflags -O0' \
+ ../../SPECS/%{_mysql_spec_file}
+fi
+%configure --disable-static --with-mysql-source=${mysql_source} \
+ --disable-fast-mutexes \
+ --with-mysql-config=`scl enable mysql55 'which mysql_config'` \
+ %{?mroonga_configure_options}
+make %{?_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+rm $RPM_BUILD_ROOT%{_libdir}/mysql/plugin/*.la
+mv $RPM_BUILD_ROOT%{_datadir}/doc/mroonga/ mysql-mroonga-doc/
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+mysql_command=`scl enable mysql55 'which mysql'`
+if $mysql_command -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+current_version=0
+version=`echo %{groonga_required_version} | sed -e 's/\.//g'`
+required_version=`expr $version`
+version=`$mysql_command -e "SHOW VARIABLES LIKE 'mroonga_libgroonga_version'" | \
+ grep mroonga | cut -f 2 | sed -e 's/\.//g'`
+if [ -n "$version" ]; then
+ current_version=`expr $version`
+fi
+install_sql=%{_datadir}/mroonga/install.sql
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+
+if [ "$1" = 2 ] ; then
+ if [ $current_version -lt $required_version ]; then
+ command="$mysql_command -u root $password_option"
+ echo "run the following command after restarting MySQL server:";
+ echo " $command < ${uninstall_sql}"
+ echo " $command < ${install_sql}"
+ exit 0
+ else
+ command="$mysql_command -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+ fi
+fi
+command="$mysql_command -u root $password_option < ${install_sql}"
+echo $command
+eval $command || \
+ (echo "run the following command to register Mroonga:"; \
+ echo " $command")
+
+%preun
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+mysql_command=`scl enable mysql55 'which mysql'`
+if $mysql_command -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+if [ "$1" = 0 ]; then
+ command="$mysql_command -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+fi
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/mysql/plugin/
+%{_datadir}/mroonga/*
+%{_datadir}/man/man1/*
+%{_datadir}/man/*/man1/*
+
+%files doc
+%defattr(-,root,root,-)
+%doc README COPYING
+%doc mysql-mroonga-doc/*
+
+%changelog
+* Thu Oct 12 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.07-1
+- new upstream release.
+
+* Tue Aug 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.06-1
+- new upstream release.
+
+* Sat Jul 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.05-1
+- new upstream release.
+
+* Thu Jun 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.04-1
+- new upstream release.
+
+* Mon May 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.03-1
+- new upstream release.
+
+* Sat Apr 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.02-1
+- new upstream release.
+
+* Wed Mar 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.01-1
+- new upstream release.
+
+* Thu Feb 09 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.00-1
+- new upstream release.
+
+* Fri Jan 13 2017 Kouhei Sutou <kou@clear-code.com> - 6.13-1
+- new upstream release.
+
+* Thu Dec 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.12-1
+- new upstream release.
+
+* Tue Nov 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.11-1
+- new upstream release.
+
+* Sat Oct 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.10-1
+- new upstream release.
+
+* Thu Sep 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.09-1
+- new upstream release.
+
+* Mon Aug 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.08-1
+- new upstream release.
+
+* Fri Jul 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.07-1
+- new upstream release.
+
+* Thu Jun 30 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.06-1
+- new upstream release.
+
+* Wed Jun 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.05-1
+- new upstream release.
+
+* Sun May 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.03-1
+- new upstream release.
+
+* Fri Apr 29 2016 HAYASHI Kentaro <hayashi@clear-code.com> - 6.02-1
+- new upstream release.
+
+* Tue Mar 29 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.01-1
+- new upstream release.
+
+* Mon Feb 29 2016 Kouhei Sutou <kou@clear-code.com> - 6.00-1
+- new upstream release.
+
+* Fri Jan 29 2016 Kouhei Sutou <kou@clear-code.com> - 5.12-1
+- new upstream release.
+
+* Sun Nov 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.10-1
+- new upstream release.
+
+* Thu Oct 29 2015 Kouhei Sutou <kou@cozmixng.org> - 5.09-1
+- new upstream release.
+
+* Tue Sep 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.08-1
+- new upstream release.
+
+* Mon Aug 31 2015 Kouhei Sutou <kou@clear-code.com> - 5.06-1
+- new upstream release.
+
+* Wed Jul 29 2015 Masafumi Yokoyama <yokoyama@clear-code.com> - 5.05-1
+- new upstream release.
+
+* Mon Jun 29 2015 Masafumi Yokoyama <myokoym@gmail.com> - 5.04-1
+- new upstream release.
+
+* Fri May 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.03-1
+- new upstream release.
+
+* Wed Apr 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.02-1
+- new upstream release.
+
+* Sun Mar 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.01-1
+- new upstream release.
+
+* Mon Feb 09 2015 <hayashi@clear-code.com> - 5.00-1
+- new upstream release.
+
+* Thu Jan 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 4.10-1
+- new upstream release.
+
+* Mon Dec 29 2014 Kouhei Sutou <kou@cozmixng.org> - 4.09-1
+- new upstream release.
+
+* Sat Nov 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.08-1
+- new upstream release.
+
+* Wed Oct 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.07-1
+- new upstream release.
+
+* Mon Sep 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.06-1
+- new upstream release.
+
+* Fri Aug 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.05-1
+- new upstream release.
+
+* Tue Jul 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.04-1
+- new upstream release.
+
+* Thu May 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.03-2
+- build against MySQL 5.6.37. Reported by YOSHIDA Mitsuo. Thanks!!!
+
+* Thu May 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.03-1
+- new upstream release.
+
+* Tue Apr 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.02-1
+- new upstream release.
+
+* Sat Mar 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.01-1
+- new upstream release.
+
+* Thu Mar 06 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.00-2
+- use MySQL 5.5.36 on CentOS 5.
+
+* Sun Feb 09 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.00-1
+- new upstream release.
+
+* Wed Jan 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 3.12-1
+- new upstream release.
+
+* Sun Dec 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.11-1
+- new upstream release.
+
+* Fri Nov 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.10-1
+- new upstream release.
+
+* Tue Oct 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.09-1
+- initial packaging for MySQL 5.5 on CentOS 5.
diff --git a/storage/mroonga/packages/rpm/centos/mysql56-community-mroonga.spec.in b/storage/mroonga/packages/rpm/centos/mysql56-community-mroonga.spec.in
new file mode 100644
index 00000000..dea7cebc
--- /dev/null
+++ b/storage/mroonga/packages/rpm/centos/mysql56-community-mroonga.spec.in
@@ -0,0 +1,374 @@
+%define _centos_ver %{?centos_ver:%{centos_ver}}%{!?centos_ver:5}
+
+%if %{_centos_ver} == 7
+%define mysql_version_default 5.6.37
+%define mysql_release_default 2
+%define mysql_dist_default el7
+%define mysql_download_base_url_default http://repo.mysql.com/yum/mysql-5.6-community/el/7/SRPMS
+%define mysql_spec_file_default mysql.spec
+%else
+%define mysql_version_default 5.6.37
+%define mysql_release_default 2
+%define mysql_dist_default el6
+%define mysql_download_base_url_default http://repo.mysql.com/yum/mysql-5.6-community/el/6/SRPMS
+%define mysql_spec_file_default mysql.spec
+%endif
+
+%define _mysql_version %{?mysql_version:%{mysql_version}}%{!?mysql_version:%{mysql_version_default}}
+%define _mysql_release %{?mysql_release:%{mysql_release}}%{!?mysql_release:%{mysql_release_default}}
+%define _mysql_dist %{?mysql_dist:%{mysql_dist}}%{!?mysql_dist:%{mysql_dist_default}}
+%define _mysql_download_base_url %{?mysql_download_base_url:%{mysql_download_base_url}}%{!?mysql_download_base_url:%{mysql_download_base_url_default}}
+%define _mysql_spec_file %{?mysql_spec_file:%{mysql_spec_file}}%{!?mysql_spec_file:%{mysql_spec_file_default}}
+
+%define groonga_required_version @REQUIRED_GROONGA_VERSION@
+
+Name: mysql-community-mroonga
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: A fast fulltext searchable storage engine for MySQL
+
+Group: Applications/Databases
+License: LGPLv2.1
+URL: http://mroonga.org/
+Source0: http://packages.groonga.org/source/mroonga/mroonga-%{version}.tar.gz
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
+BuildRequires: groonga-devel >= %{groonga_required_version}
+BuildRequires: groonga-normalizer-mysql-devel
+BuildRequires: wget
+BuildRequires: which
+BuildRequires: gcc, gcc-c++
+BuildRequires: numactl-devel
+BuildRequires: mysql-community-devel = %{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+Requires: mysql-community-server = %{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+Requires: mysql-community-client = %{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+Requires: groonga-libs >= %{groonga_required_version}
+Requires: groonga-normalizer-mysql
+
+%description
+Mroonga is a fast fulltext searchable storage plugin for MySQL.
+It is based on Groonga that is a fast fulltext search engine and
+column store. Groonga is good at real-time update.
+
+%package doc
+Summary: Documentation for Mroonga
+Group: Documentation
+License: LGPLv2.1
+
+%description doc
+Documentation for Mroonga
+
+
+%prep
+%setup -q -n mroonga-%{version}
+
+mysql_full_version=%{_mysql_version}-%{_mysql_release}.%{_mysql_dist}
+srpm=mysql-community-${mysql_full_version}.src.rpm
+if [ ! -f ../../SRPMS/$srpm ]; then
+ wget --continue -O ../../SRPMS/$srpm %{_mysql_download_base_url}/$srpm
+ rpm -Uvh ../../SRPMS/$srpm
+fi
+
+%build
+mysql_source=../mysql-%{_mysql_version}/mysql-%{_mysql_version}
+if [ ! -d ${mysql_source} ]; then
+ specs_dir=
+ MYSQL_RPMBUILD_TEST=no rpmbuild -bp \
+ --define 'runselftest 0' \
+ --define 'optflags -O0' \
+ ../../SPECS/%{_mysql_spec_file}
+fi
+%configure \
+ --disable-static \
+ --with-mysql-source=${mysql_source} \
+ --enable-fast-mutexes \
+ %{?mroonga_configure_options}
+make %{?_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+rm $RPM_BUILD_ROOT%{_libdir}/mysql/plugin/*.la
+mv $RPM_BUILD_ROOT%{_datadir}/doc/mroonga/ mysql-mroonga-doc/
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+if ! /sbin/service mysqld status > /dev/null; then
+ /sbin/service mysqld start
+ stop_after_installation=1
+else
+ stop_after_installation=0
+fi
+
+mysql_command=`which mysql`
+if $mysql_command -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+current_version=0
+version=`echo %{groonga_required_version} | sed -e 's/\.//g'`
+required_version=`expr $version`
+version=`$mysql_command -e "SHOW VARIABLES LIKE 'mroonga_libgroonga_version'" | \
+ grep mroonga | cut -f 2 | sed -e 's/\.//g'`
+if [ -n "$version" ]; then
+ current_version=`expr $version`
+fi
+install_sql=%{_datadir}/mroonga/install.sql
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+
+if [ "$1" = 2 ] ; then
+ if [ $current_version -lt $required_version ]; then
+ command="$mysql_command -u root $password_option"
+ echo "run the following command after restarting MySQL server:";
+ echo " $command < ${uninstall_sql}"
+ echo " $command < ${install_sql}"
+ exit 0
+ else
+ command="$mysql_command -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+ fi
+fi
+command="$mysql_command -u root $password_option < ${install_sql}"
+echo $command
+eval $command || \
+ (echo "run the following command to register Mroonga:"; \
+ echo " $command")
+
+if [ "$stop_after_installation" = "1" ]; then
+ /sbin/service mysqld stop
+fi
+
+%preun
+if ! /sbin/service mysqld status > /dev/null; then
+ /sbin/service mysqld start
+ stop_after_uninstallation=1
+else
+ stop_after_uninstallation=0
+fi
+
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+mysql_command=`which mysql`
+if $mysql_command -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+if [ "$1" = 0 ]; then
+ command="$mysql_command -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+fi
+
+if [ "$stop_after_uninstallation" = "1" ]; then
+ /sbin/service mysqld stop
+fi
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/mysql/plugin/
+%{_datadir}/mroonga/*
+%{_datadir}/man/man1/*
+%{_datadir}/man/*/man1/*
+
+%files doc
+%defattr(-,root,root,-)
+%doc README COPYING
+%doc mysql-mroonga-doc/*
+
+%changelog
+* Thu Oct 12 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.07-1
+- new upstream release.
+
+* Tue Aug 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.06-1
+- new upstream release.
+
+* Wed Aug 23 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.05-2
+- build against MySQL 5.6.37 on CentOS 7. Reported by Hiroshi Kagami. Thanks!!!
+
+* Sat Jul 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.05-1
+- new upstream release.
+
+* Fri Jul 21 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.04-2
+- build against MySQL 5.6.37 on CentOS 6. Reported by Hiroshi Kagami. Thanks!!!
+
+* Thu Jun 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.04-1
+- new upstream release.
+
+* Mon May 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.03-1
+- new upstream release.
+
+* Sat Apr 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.02-1
+- new upstream release.
+
+* Wed Apr 12 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.01-2
+- build against MySQL 5.6.36 Reported by @tigersun2000. Thanks!!!
+
+* Wed Mar 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.01-1
+- new upstream release.
+
+* Thu Feb 09 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.00-1
+- new upstream release.
+
+* Fri Jan 13 2017 Kouhei Sutou <kou@clear-code.com> - 6.13-1
+- new upstream release.
+
+* Thu Dec 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.12-1
+- new upstream release.
+
+* Tue Nov 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.11-1
+- new upstream release.
+
+* Sat Oct 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.10-1
+- new upstream release.
+
+* Mon Oct 24 2016 Kouhei Sutou <kou@clear-code.com> - 6.09-2
+- build against MySQL 5.6.34. Reported by Hiroshi Kagami. Thanks!!!
+
+* Thu Sep 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.09-1
+- new upstream release.
+
+* Wed Sep 14 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.08-2
+- build against MySQL 5.6.33.
+
+* Mon Aug 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.08-1
+- new upstream release.
+
+* Fri Jul 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.07-1
+- new upstream release.
+
+* Thu Jun 30 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.06-1
+- new upstream release.
+
+* Wed Jun 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.05-1
+- new upstream release.
+
+* Mon Jun 06 2016 Kouhei Sutou <kou@clear-code.com> - 6.03-2
+- build against MySQL 5.6.30.
+
+* Sun May 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.03-1
+- new upstream release.
+
+* Fri Apr 29 2016 HAYASHI Kentaro <hayashi@clear-code.com> - 6.02-1
+- new upstream release.
+
+* Tue Mar 29 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.01-1
+- new upstream release.
+
+* Mon Feb 29 2016 Kouhei Sutou <kou@clear-code.com> - 6.00-1
+- new upstream release.
+
+* Fri Jan 29 2016 Kouhei Sutou <kou@clear-code.com> - 5.12-1
+- new upstream release.
+
+* Tue Dec 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.11-1
+- new upstream release.
+
+* Wed Dec 09 2015 Kouhei Sutou <kou@clear-code.com> - 5.10-2
+- build against MySQL 5.6.28. Reported by @stealthinu. Thanks!!!
+
+* Sun Nov 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.10-1
+- new upstream release.
+
+* Thu Oct 29 2015 Kouhei Sutou <kou@cozmixng.org> - 5.09-1
+- new upstream release.
+
+* Sat Oct 03 2015 Kouhei Sutou <kou@clear-code.com> - 5.08-2
+- build against MySQL 5.6.27. Reported by @star_orihime. Thanks!!!
+
+* Tue Sep 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.08-1
+- new upstream release.
+
+* Mon Aug 31 2015 Kouhei Sutou <kou@clear-code.com> - 5.06-1
+- new upstream release.
+
+* Wed Jul 29 2015 Masafumi Yokoyama <yokoyama@clear-code.com> - 5.05-1
+- new upstream release.
+
+* Mon Jun 29 2015 Masafumi Yokoyama <myokoym@gmail.com> - 5.04-1
+- new upstream release.
+
+* Tue Jun 02 2015 Masafumi Yokoyama <yokoyama@clear-code.com> - 5.03-2
+- build against MySQL 5.6.25.
+
+* Fri May 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.03-1
+- new upstream release.
+
+* Wed Apr 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.02-1
+- new upstream release.
+
+* Fri Apr 10 2015 Kouhei Sutou <kou@clear-code.com> - 5.01-2
+- build against MySQL 5.6.24.
+
+* Sun Mar 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.01-1
+- new upstream release.
+
+* Mon Feb 09 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 5.00-1
+- new upstream release.
+
+* Wed Feb 04 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 4.10-2
+- build against MySQL 5.6.23-2 on MySQL yum repository.
+
+* Thu Jan 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 4.10-1
+- new upstream release.
+
+* Mon Dec 29 2014 Kouhei Sutou <kou@cozmixng.org> - 4.09-1
+- new upstream release.
+
+* Sat Nov 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.08-1
+- new upstream release.
+
+* Wed Oct 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.07-1
+- new upstream release.
+
+* Mon Sep 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.06-1
+- new upstream release.
+
+* Sat Sep 27 2014 Eiichi Sato <miko@cafelounge.net> - 4.05-2
+- build against MySQL 5.6.21-2 on MySQL yum repository.
+
+* Fri Aug 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.05-1
+- new upstream release.
+
+* Sat Aug 09 2014 Eiichi Sato <miko@cafelounge.net> - 4.04-2
+- build against MySQL 5.6.20-4 on MySQL yum repository.
+
+* Tue Jul 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.04-1
+- new upstream release.
+
+* Thu May 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.03-2
+- build against MySQL 5.6.37. Reported by YOSHIDA Mitsuo. Thanks!!!
+
+* Thu May 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.03-1
+- new upstream release.
+
+* Tue Apr 29 2014 Kouhei Sutou <kou@clear-code.com> - 4.02-1
+- new upstream release.
+
+* Sat Mar 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.01-1
+- new upstream release.
+
+* Thu Mar 06 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.00-2
+- use MySQL 5.5.36 on CentOS 5.
+
+* Sun Feb 09 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 4.00-1
+- new upstream release.
+
+* Wed Jan 29 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 3.12-1
+- new upstream release.
+
+* Sun Dec 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.11-1
+- new upstream release.
+
+* Fri Nov 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.10-1
+- new upstream release.
+
+* Tue Oct 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 3.09-1
+- initial packaging for MySQL 5.5 on CentOS 5.
diff --git a/storage/mroonga/packages/rpm/centos/percona-server-56-mroonga.spec.in b/storage/mroonga/packages/rpm/centos/percona-server-56-mroonga.spec.in
new file mode 100644
index 00000000..abf3bfde
--- /dev/null
+++ b/storage/mroonga/packages/rpm/centos/percona-server-56-mroonga.spec.in
@@ -0,0 +1,273 @@
+%define _centos_ver %{?centos_ver:%{centos_ver}}%{!?centos_ver:5}
+
+%define mysql_version_default 5.6.37
+%define mysql_release_default rel82.2
+%define mysql_dist_default %{?dist}
+%define mysql_download_base_url_default http://repo.percona.com/centos/%{_centos_ver}/SRPMS
+%define mysql_spec_file_default percona-server.spec
+
+%define _mysql_version %{?mysql_version:%{mysql_version}}%{!?mysql_version:%{mysql_version_default}}
+%define _mysql_release %{?mysql_release:%{mysql_release}}%{!?mysql_release:%{mysql_release_default}}
+%define _mysql_dist %{?mysql_dist:%{mysql_dist}}%{!?mysql_dist:%{mysql_dist_default}}
+%define _mysql_download_base_url %{?mysql_download_base_url:%{mysql_download_base_url}}%{!?mysql_download_base_url:%{mysql_download_base_url_default}}
+%define _mysql_spec_file %{?mysql_spec_file:%{mysql_spec_file}}%{!?mysql_spec_file:%{mysql_spec_file_default}}
+
+%define groonga_required_version @REQUIRED_GROONGA_VERSION@
+
+Name: percona-server-56-mroonga
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: A fast fulltext searchable storage engine for MySQL
+
+Group: Applications/Databases
+License: LGPLv2.1
+URL: http://mroonga.org/
+Source0: http://packages.groonga.org/source/mroonga/mroonga-%{version}.tar.gz
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
+BuildRequires: groonga-devel >= %{groonga_required_version}
+BuildRequires: groonga-normalizer-mysql-devel
+BuildRequires: wget
+BuildRequires: which
+BuildRequires: gcc
+BuildRequires: gcc-c++
+BuildRequires: Percona-Server-devel-56 = %{_mysql_version}-%{_mysql_release}%{_mysql_dist}
+BuildRequires: selinux-policy-devel
+Requires: Percona-Server-server-56 = %{_mysql_version}-%{_mysql_release}%{_mysql_dist}
+Requires: Percona-Server-client-56 = %{_mysql_version}-%{_mysql_release}%{_mysql_dist}
+Requires: groonga-libs >= %{groonga_required_version}
+Requires: groonga-normalizer-mysql
+
+%description
+Mroonga is a fast fulltext searchable storage plugin for MySQL.
+It is based on Groonga that is a fast fulltext search engine and
+column store. Groonga is good at real-time update.
+
+%package doc
+Summary: Documentation for Mroonga
+Group: Documentation
+License: LGPLv2.1
+
+%description doc
+Documentation for Mroonga
+
+
+%prep
+%setup -q -n mroonga-%{version}
+
+mysql_full_version=%{_mysql_version}-%{_mysql_release}.generic
+srpm=Percona-Server-56-${mysql_full_version}.src.rpm
+if [ ! -f ../../SRPMS/$srpm ]; then
+ wget --continue -O ../../SRPMS/$srpm %{_mysql_download_base_url}/$srpm
+ rpm -Uvh ../../SRPMS/$srpm
+fi
+
+%build
+mysql_source=../percona-server-%{_mysql_version}-$(echo %{_mysql_release} | sed -e 's/rel//')
+if [ ! -d ${mysql_source} ]; then
+ specs_dir=
+ rpmbuild -bp \
+ --define 'runselftest 0' \
+ --define 'optflags -O0' \
+ ../../SPECS/%{_mysql_spec_file}
+fi
+%configure \
+ --disable-static \
+ --with-mysql-source=${mysql_source} \
+ --enable-fast-mutexes \
+ %{?mroonga_configure_options}
+make %{?_smp_mflags}
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+rm $RPM_BUILD_ROOT%{_libdir}/mysql/plugin/*.la
+mv $RPM_BUILD_ROOT%{_datadir}/doc/mroonga/ mysql-mroonga-doc/
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post
+if ! /sbin/service mysql status > /dev/null; then
+ /sbin/service mysql start
+ stop_after_installation=1
+else
+ stop_after_installation=0
+fi
+
+mysql_command=`which mysql`
+password_option=""
+
+if $mysql_command -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+current_version=0
+version=`echo %{groonga_required_version} | sed -e 's/\.//g'`
+required_version=`expr $version`
+version=`$mysql_command -e "SHOW VARIABLES LIKE 'mroonga_libgroonga_version'" | \
+ grep mroonga | cut -f 2 | sed -e 's/\.//g'`
+if [ -n "$version" ]; then
+ current_version=`expr $version`
+fi
+install_sql=%{_datadir}/mroonga/install.sql
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+
+if [ "$1" = 2 ] ; then
+ if [ $current_version -lt $required_version ]; then
+ command="$mysql_command -u root $password_option"
+ echo "run the following command after restarting MySQL server:";
+ echo " $command < ${uninstall_sql}"
+ echo " $command < ${install_sql}"
+ exit 0
+ else
+ command="$mysql_command -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+ fi
+fi
+command="$mysql_command -u root $password_option < ${install_sql}"
+echo $command
+eval $command || \
+ (echo "run the following command to register Mroonga:"; \
+ echo " $command")
+
+if [ "$stop_after_installation" = "1" ]; then
+ /sbin/service mysql stop
+fi
+
+%preun
+if ! /sbin/service mysql status > /dev/null; then
+ /sbin/service mysql start
+ stop_after_uninstallation=1
+else
+ stop_after_uninstallation=0
+fi
+
+uninstall_sql=%{_datadir}/mroonga/uninstall.sql
+mysql_command=`which mysql`
+if $mysql_command -u root -e "quit" > /dev/null 2>&1; then
+ password_option=""
+else
+ password_option="-p"
+fi
+if [ "$1" = 0 ]; then
+ command="$mysql_command -u root $password_option < ${uninstall_sql}"
+ echo $command
+ eval $command || \
+ (echo "run the following command to unregister Mroonga:"; \
+ echo " $command")
+fi
+
+if [ "$stop_after_uninstallation" = "1" ]; then
+ /sbin/service mysql stop
+fi
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/mysql/plugin/
+%{_datadir}/mroonga/*
+%{_datadir}/man/man1/*
+%{_datadir}/man/*/man1/*
+
+%files doc
+%defattr(-,root,root,-)
+%doc README COPYING
+%doc mysql-mroonga-doc/*
+
+%changelog
+* Thu Oct 12 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.07-1
+- new upstream release.
+
+* Tue Aug 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.06-1
+- new upstream release.
+
+* Mon Aug 14 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.05-2
+- build against Percona Server 5.6.36rel82.1 Reported by @tigersun2000_twitter. Thanks!!!
+
+* Sat Jul 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.05-1
+- new upstream release.
+
+* Thu Jun 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.04-1
+- new upstream release.
+
+* Mon May 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.03-1
+- new upstream release.
+
+* Thu May 17 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.02-2
+- build against Percona Server 5.6.36. Reported by @pinpikokun. Thanks!!!
+
+* Sat Apr 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.02-1
+- new upstream release.
+
+* Wed Mar 29 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.01-1
+- new upstream release.
+
+* Thu Feb 09 2017 Kentaro Hayashi <hayashi@clear-code.com> - 7.00-1
+- new upstream release.
+
+* Fri Jan 13 2017 Kouhei Sutou <kou@clear-code.com> - 6.13-1
+- new upstream release.
+
+* Thu Dec 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.12-1
+- new upstream release.
+
+* Tue Nov 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.11-1
+- new upstream release.
+
+* Sat Oct 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.10-1
+- new upstream release.
+
+* Mon Oct 24 2016 Kouhei Sutou <kou@clear-code.com> - 6.09-2
+- build against Percona Server 5.6.33. Reported by Hiroshi Kagami. Thanks!!!
+
+* Thu Sep 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.09-1
+- new upstream release.
+
+* Mon Aug 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.08-1
+- new upstream release.
+
+* Fri Jul 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.07-1
+- new upstream release.
+
+* Thu Jun 30 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.06-1
+- new upstream release.
+
+* Wed Jun 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.05-1
+- new upstream release.
+
+* Sun May 29 2016 Kentaro Hayashi <hayashi@clear-code.com> - 6.03-1
+- new upstream release.
+
+* Fri Apr 29 2016 HAYASHI Kentaro <hayashi@clear-code.com> - 6.02-1
+- new upstream release.
+
+* Tue Mar 29 2016 Masafumi Yokoyama <yokoyama@clear-code.com> - 6.01-1
+- new upstream release.
+
+* Mon Feb 29 2016 Kouhei Sutou <kou@clear-code.com> - 6.00-1
+- new upstream release.
+
+* Fri Jan 29 2016 Kouhei Sutou <kou@clear-code.com> - 5.12-1
+- new upstream release.
+
+* Tue Dec 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.11-1
+- new upstream release.
+
+* Sun Nov 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.10-1
+- new upstream release.
+
+* Thu Oct 29 2015 Kouhei Sutou <kou@cozmixng.org> - 5.09-1
+- new upstream release.
+
+* Tue Sep 29 2015 Kouhei Sutou <kou@clear-code.com> - 5.08-1
+- new upstream release.
+
+* Mon Aug 31 2015 Kouhei Sutou <kou@clear-code.com> - 5.06-1
+- new upstream release.
+
+* Tue Mar 17 2015 Kouhei Sutou <kou@clear-code.com> - 5.00-1
+- initial release.
diff --git a/storage/mroonga/packages/source/Makefile.am b/storage/mroonga/packages/source/Makefile.am
new file mode 100644
index 00000000..efd09777
--- /dev/null
+++ b/storage/mroonga/packages/source/Makefile.am
@@ -0,0 +1,125 @@
+MROONGA_BASE = $(PACKAGE)-$(VERSION)
+MROONGA_TAR_GZ = $(MROONGA_BASE).tar.gz
+
+GROONGA_VERSION = 7.0.7
+GROONGA_BASE = groonga-$(GROONGA_VERSION)
+GROONGA_TAR_GZ = $(GROONGA_BASE).tar.gz
+
+GROONGA_NORMALIZER_MYSQL_VERSION = 1.1.1
+GROONGA_NORMALIZER_MYSQL_BASE = \
+ groonga-normalizer-mysql-$(GROONGA_NORMALIZER_MYSQL_VERSION)
+GROONGA_NORMALIZER_MYSQL_TAR_GZ = \
+ $(GROONGA_NORMALIZER_MYSQL_BASE).tar.gz
+
+MARIADB_VERSION = 10.1.28
+MARIADB_BASE = mariadb-$(MARIADB_VERSION)
+MARIADB_TAR_GZ = $(MARIADB_BASE).tar.gz
+
+MARIADB_WITH_MROONGA_BASE = $(MARIADB_BASE)-with-$(MROONGA_BASE)
+MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE = $(MARIADB_WITH_MROONGA_BASE)-for-windows
+
+GROONGA_PROJECT_DOWNLOAD_BASE = http://packages.groonga.org/source
+GROONGA_DOWNLOAD_BASE = $(GROONGA_PROJECT_DOWNLOAD_BASE)/groonga
+GROONGA_NORMALIZER_MYSQL_DOWNLOAD_BASE = \
+ $(GROONGA_PROJECT_DOWNLOAD_BASE)/groonga-normalizer-mysql
+MARIADB_DOWNLOAD_BASE = http://ftp.yz.yamagata-u.ac.jp/pub/dbms/mariadb
+
+
+CURL = curl --fail --silent --show-error
+
+all:
+
+release: download archive upload
+
+ensure-rsync-path:
+ @if test -z "$(RSYNC_PATH)"; then \
+ echo "--with-rsync-path configure option must be specified."; \
+ false; \
+ fi
+
+download: ensure-rsync-path
+ rsync -avz --progress --delete $(RSYNC_PATH)/source/mroonga/ files
+
+ARCHIVES = \
+ files/$(MROONGA_TAR_GZ) \
+ files/$(MARIADB_WITH_MROONGA_BASE).tar.gz \
+ files/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE).zip
+
+archive: $(ARCHIVES)
+
+upload: ensure-rsync-path
+ rsync -avz --progress --delete files/ $(RSYNC_PATH)/source/mroonga
+
+files/$(MROONGA_TAR_GZ): $(top_builddir)/$(MROONGA_TAR_GZ)
+ mkdir -p files
+ cp -p $< $@
+
+tmp/$(GROONGA_TAR_GZ):
+ mkdir -p tmp
+ $(CURL) --output $@ $(GROONGA_DOWNLOAD_BASE)/$(GROONGA_TAR_GZ)
+
+tmp/$(GROONGA_NORMALIZER_MYSQL_TAR_GZ):
+ mkdir -p tmp
+ $(CURL) --output $@ $(GROONGA_NORMALIZER_MYSQL_DOWNLOAD_BASE)/$(GROONGA_NORMALIZER_MYSQL_TAR_GZ)
+
+tmp/$(MARIADB_TAR_GZ):
+ mkdir -p tmp
+ $(CURL) --output $@ $(MARIADB_DOWNLOAD_BASE)/mariadb-$(MARIADB_VERSION)/source/$(MARIADB_TAR_GZ)
+
+MARIADB_WITH_MROONGA_ARCHIVES = \
+ tmp/$(GROONGA_TAR_GZ) \
+ tmp/$(GROONGA_NORMALIZER_MYSQL_TAR_GZ) \
+ tmp/$(MARIADB_TAR_GZ) \
+ $(top_builddir)/$(MROONGA_TAR_GZ)
+
+BUNDLED_MROONGA_PATH = $(MARIADB_BASE)/storage/$(PACKAGE)
+BUNDLED_GROONGA_PATH = $(BUNDLED_MROONGA_PATH)/vendor/groonga
+BUNDLED_GROONGA_NORMALIZER_MYSQL_PATH = \
+ $(BUNDLED_GROONGA_PATH)/vendor/plugins/groonga-normalizer-mysql
+
+tmp/$(MARIADB_WITH_MROONGA_BASE).stamp: $(MARIADB_WITH_MROONGA_ARCHIVES)
+ rm -rf $(MARIADB_BASE)
+ tar xf tmp/$(MARIADB_TAR_GZ)
+
+ rm -fr $(MARIADB_BASE)/storage/mroonga
+ tar xf $(top_builddir)/$(MROONGA_TAR_GZ)
+ mv $(MROONGA_BASE) $(BUNDLED_MROONGA_PATH)
+
+ mkdir -p $$(dirname $(BUNDLED_GROONGA_PATH))
+ tar xf tmp/$(GROONGA_TAR_GZ)
+ rm -rf $(GROONGA_BASE)/test
+ cd $(GROONGA_BASE)/vendor && ruby download_mecab.rb
+ cd $(GROONGA_BASE)/vendor && ruby download_lz4.rb
+ mv $(GROONGA_BASE) $(BUNDLED_GROONGA_PATH)
+
+ tar xf tmp/$(GROONGA_NORMALIZER_MYSQL_TAR_GZ)
+ rm -rf $(GROONGA_NORMALIZER_MYSQL_BASE)/test
+ mv $(GROONGA_NORMALIZER_MYSQL_BASE) $(BUNDLED_GROONGA_NORMALIZER_MYSQL_PATH)
+
+ rm -rf tmp/$(MARIADB_WITH_MROONGA_BASE)
+ mv $(MARIADB_BASE) tmp/$(MARIADB_WITH_MROONGA_BASE)
+
+ touch $@
+
+files/$(MARIADB_WITH_MROONGA_BASE).tar.gz: tmp/$(MARIADB_WITH_MROONGA_BASE).stamp
+ mkdir -p files/
+ (cd tmp && tar czf ../$@ $(MARIADB_WITH_MROONGA_BASE))
+
+PATCHES = \
+ patches/mariadb-10.0.3-windows-build.diff
+
+tmp/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE).stamp: tmp/$(MARIADB_WITH_MROONGA_BASE).stamp $(PATCHES)
+ rm -rf tmp/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE)
+ cp -a \
+ tmp/$(MARIADB_WITH_MROONGA_BASE) \
+ tmp/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE)
+ for patch in $(PATCHES); do \
+ (cd tmp/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE) && \
+ patch -p1 < $(abs_srcdir)/$${patch}); \
+ done
+
+ touch $@
+
+files/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE).zip: tmp/$(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE).stamp
+ mkdir -p files/
+ (cd tmp && zip -q -r ../$@ $(MARIADB_WITH_MROONGA_FOR_WINDOWS_BASE))
diff --git a/storage/mroonga/packages/source/patches/mariadb-10.0.3-windows-build.diff b/storage/mroonga/packages/source/patches/mariadb-10.0.3-windows-build.diff
new file mode 100644
index 00000000..c135088b
--- /dev/null
+++ b/storage/mroonga/packages/source/patches/mariadb-10.0.3-windows-build.diff
@@ -0,0 +1,9 @@
+diff -ur mariadb-10.0.2.orig/sql/sql_locale.cc mariadb-10.0.2/sql/sql_locale.cc
+--- mariadb-10.0.2.orig/sql/sql_locale.cc 2013-04-23 13:13:59.000000000 +0900
++++ mariadb-10.0.2/sql/sql_locale.cc 2013-05-19 12:55:27.590366542 +0900
+@@ -1,4 +1,4 @@
+-/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
++/* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
diff --git a/storage/mroonga/packages/ubuntu/Makefile.am b/storage/mroonga/packages/ubuntu/Makefile.am
new file mode 100644
index 00000000..7241391b
--- /dev/null
+++ b/storage/mroonga/packages/ubuntu/Makefile.am
@@ -0,0 +1,57 @@
+CODE_NAMES = trusty,xenial,zesty
+SOURCE = ../$(PACKAGE)-$(VERSION).tar.gz
+SOURCE_55_BASE = $(PACKAGE)-5.5
+SOURCE_55 = $(SOURCE_55_BASE)_$(VERSION).orig.tar.gz
+SOURCE_56_BASE = $(PACKAGE)-5.6
+SOURCE_56 = $(SOURCE_56_BASE)_$(VERSION).orig.tar.gz
+SOURCE_57_BASE = $(PACKAGE)-5.7
+SOURCE_57 = $(SOURCE_57_BASE)_$(VERSION).orig.tar.gz
+SOURCE_MARIADB_10_0_BASE = $(PACKAGE)-mariadb-10.0
+SOURCE_MARIADB_10_0 = $(SOURCE_MARIADB_10_0_BASE)_$(VERSION).orig.tar.gz
+
+all:
+
+ensure-launchpad-configuration:
+ @if test -z "$(LAUNCHPAD_UPLOADER_PGP_KEY)"; then \
+ echo "--with-launchpad-uploader-pgp-key configure option must be specified."; \
+ false; \
+ fi
+
+upload: source ensure-launchpad-configuration
+ ./upload.rb \
+ --package '$(PACKAGE)' \
+ --version '$(VERSION)' \
+ --source-archive-directory '$(builddir)/' \
+ --code-names '$(CODE_NAMES)' \
+ --debian-base-directory '$(srcdir)/../' \
+ --ppa '$(LAUNCHPAD_PPA)' \
+ --pgp-sign-key '$(LAUNCHPAD_UPLOADER_PGP_KEY)'
+
+source: $(SOURCE_55) $(SOURCE_56) $(SOURCE_57) $(SOURCE_MARIADB_10_0)
+
+$(SOURCE):
+ ln -s $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz $(SOURCE)
+
+$(SOURCE_55): $(SOURCE)
+ tar xf $(SOURCE)
+ mv $(PACKAGE)-$(VERSION) $(SOURCE_55_BASE)-$(VERSION)
+ tar cfz $(SOURCE_55) $(SOURCE_55_BASE)-$(VERSION)
+ rm -r $(SOURCE_55_BASE)-$(VERSION)
+
+$(SOURCE_56): $(SOURCE)
+ tar xf $(SOURCE)
+ mv $(PACKAGE)-$(VERSION) $(SOURCE_56_BASE)-$(VERSION)
+ tar cfz $(SOURCE_56) $(SOURCE_56_BASE)-$(VERSION)
+ rm -r $(SOURCE_56_BASE)-$(VERSION)
+
+$(SOURCE_57): $(SOURCE)
+ tar xf $(SOURCE)
+ mv $(PACKAGE)-$(VERSION) $(SOURCE_57_BASE)-$(VERSION)
+ tar cfz $(SOURCE_57) $(SOURCE_57_BASE)-$(VERSION)
+ rm -r $(SOURCE_57_BASE)-$(VERSION)
+
+$(SOURCE_MARIADB_10_0): $(SOURCE)
+ tar xf $(SOURCE)
+ mv $(PACKAGE)-$(VERSION) $(SOURCE_MARIADB_10_0_BASE)-$(VERSION)
+ tar cfz $(SOURCE_MARIADB_10_0) $(SOURCE_MARIADB_10_0_BASE)-$(VERSION)
+ rm -r $(SOURCE_MARIADB_10_0_BASE)-$(VERSION)
diff --git a/storage/mroonga/packages/ubuntu/upload.rb b/storage/mroonga/packages/ubuntu/upload.rb
new file mode 100755
index 00000000..c8ca8aa5
--- /dev/null
+++ b/storage/mroonga/packages/ubuntu/upload.rb
@@ -0,0 +1,247 @@
+#!/usr/bin/env ruby
+#
+# Copyright(C) 2014-2016 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2014 HAYASHI Kentaro <hayashi@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 version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+require "optparse"
+require "fileutils"
+require "pathname"
+require "open-uri"
+
+class Uploader
+ def initialize
+ @dput_configuration_name = "groonga-ppa"
+ @use_pbuilder = false
+ end
+
+ def run
+ ensure_dput_configuration
+
+ parse_command_line!
+
+ ensure_mysql_version
+
+ @required_groonga_version = required_groonga_version
+
+ @code_names.each do |code_name|
+ mysql55_version = @mysql55_versions[code_name]
+ mysql56_version = @mysql56_versions[code_name]
+ mysql57_version = @mysql57_versions[code_name]
+ mariadb10_0_version = @mariadb10_0_versions[code_name]
+ if mysql55_version
+ upload(code_name, "5.5", mysql55_version)
+ end
+ if mysql56_version
+ upload(code_name, "5.6", mysql56_version)
+ end
+ if mysql57_version
+ upload(code_name, "5.7", mysql57_version)
+ end
+ if mariadb10_0_version
+ upload(code_name, "mariadb-10.0", mariadb10_0_version)
+ end
+ end
+ end
+
+ private
+ def ensure_dput_configuration
+ dput_cf_path = Pathname.new("~/.dput.cf").expand_path
+ if dput_cf_path.exist?
+ dput_cf_content = dput_cf_path.read
+ else
+ dput_cf_content = ""
+ end
+ dput_cf_content.each_line do |line|
+ return if line.chomp == "[#{@dput_configuration_name}]"
+ end
+
+ dput_cf_path.open("w") do |dput_cf|
+ dput_cf.puts(dput_cf_content)
+ dput_cf.puts(<<-CONFIGURATION)
+[#{@dput_configuration_name}]
+fqdn = ppa.launchpad.net
+method = ftp
+incoming = ~groonga/ppa/ubuntu/
+login = anonymous
+allow_unsigned_uploads = 0
+ CONFIGURATION
+ end
+ end
+
+ def ensure_mysql_version
+ @mysql_versions = {}
+ @mysql55_versions = {}
+ @mysql56_versions = {}
+ @mysql57_versions = {}
+ @mariadb10_0_versions = {}
+ @code_names.each do |code_name|
+ source_names = [code_name, "#{code_name}-updates"]
+ source_names.each do |source_name|
+ allpackages_url =
+ "http://packages.ubuntu.com/#{source_name}/allpackages?format=txt.gz"
+ open(allpackages_url) do |file|
+ file.each_line do |line|
+ case line
+ when /\Amysql-server \((.+?)[\s)]/
+ @mysql_versions[code_name] = $1
+ when /\Amysql-server-5\.5 \((.+?)[\s)]/
+ @mysql55_versions[code_name] = $1
+ when /\Amysql-server-5\.6 \((.+?)[\s)]/
+ @mysql56_versions[code_name] = $1
+ when /\Amysql-server-5\.7 \((.+?)[\s)]/
+ @mysql57_versions[code_name] = $1
+ when /\Amariadb-server-10\.0 \((.+?)[\s)]/
+ @mariadb10_0_versions[code_name] = $1
+ end
+ end
+ end
+ end
+ end
+ end
+
+ def parse_command_line!
+ parser = OptionParser.new
+ parser.on("--package=NAME",
+ "The package name") do |name|
+ @package = name
+ end
+ parser.on("--version=VERSION",
+ "The version") do |version|
+ @version = version
+ end
+ parser.on("--source-archive-directory=DIRECTORY",
+ "The directory that has source archives") do |directory|
+ @source_archive_directory = Pathname.new(directory).expand_path
+ end
+ parser.on("--code-names=CODE_NAME1,CODE_NAME2,CODE_NAME3,...", Array,
+ "The target code names") do |code_names|
+ @code_names = code_names
+ end
+ parser.on("--debian-base-directory=DIRECTORY",
+ "The directory that has debianXX/ directory") do |directory|
+ @debian_base_directory = Pathname.new(directory).expand_path
+ end
+ parser.on("--ppa=PPA",
+ "The personal package archive name (groonga-ppa or groonga-nightly") do |ppa|
+ @dput_configuration_name = ppa
+ end
+ parser.on("--pgp-sign-key=KEY",
+ "The PGP key to sign .changes and .dsc") do |pgp_sign_key|
+ @pgp_sign_key = pgp_sign_key
+ end
+ parser.on("--[no-]pbuilder",
+ "Use pbuilder for build check") do |use_pbuilder|
+ @use_pbuilder = use_pbuilder
+ end
+
+ parser.parse!
+ end
+
+ def upload(code_name, mysql_short_version, mysql_version)
+ default_mysql_version = (@mysql_versions[code_name] == mysql_version)
+ deb_package_name = "#{@package}-#{mysql_short_version}"
+ in_temporary_directory do
+ source_archive =
+ @source_archive_directory + "#{deb_package_name}_#{@version}.orig.tar.gz"
+ run_command("tar", "xf", source_archive.to_s)
+ directory_name = "#{deb_package_name}-#{@version}"
+ Dir.chdir(directory_name) do
+ debian_directory =
+ @debian_base_directory + "debian-#{mysql_short_version}"
+ FileUtils.cp_r(debian_directory.to_s, "debian")
+ deb_version = "#{current_deb_version.succ}~#{code_name}1"
+ run_command("dch",
+ "--distribution", code_name,
+ "--newversion", deb_version,
+ "Build for #{code_name}.")
+ remove_versionless_mroonga = true
+ if default_mysql_version or mysql_short_version.start_with?("mariadb-")
+ remove_versionless_mroonga = false
+ end
+ if remove_versionless_mroonga
+ control_content = File.read("debian/control")
+ File.open("debian/control", "w") do |control|
+ in_mysql_server_mroonga = false
+ control_content.each_line do |line|
+ case line.chomp
+ when ""
+ if in_mysql_server_mroonga
+ in_mysql_server_mroonga = false
+ else
+ control.print(line)
+ end
+ when "Package: mysql-server-mroonga"
+ in_mysql_server_mroonga = true
+ else
+ next if in_mysql_server_mroonga
+ control.print(line)
+ end
+ end
+ end
+ end
+ run_command("sed",
+ "-i", "-e",
+ "s,MYSQL_VERSION\\|MARIADB_VERSION,#{mysql_version},",
+ "debian/control")
+ run_command("debuild",
+ "--no-lintian",
+ # Workaround for Launchpad. Launchpad doesn't accept
+ # .buildinfo yet.
+ # See also: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=853795
+ "--buildinfo-option=-O",
+ "-d",
+ "-S",
+ "-sa",
+ "-pgpg2",
+ "-k#{@pgp_sign_key}")
+ if @use_pbuilder
+ run_command("pbuilder-dist", code_name, "build",
+ "../#{deb_package_name}_#{deb_version}.dsc")
+ else
+ run_command("dput", @dput_configuration_name,
+ "../#{deb_package_name}_#{deb_version}_source.changes")
+ end
+ end
+ end
+ end
+
+ def required_groonga_version
+ File.read("../../required_groonga_version").lines.first.chomp
+ end
+
+ def current_deb_version
+ /\((.+)\)/ =~ File.read("debian/changelog").lines.first
+ $1
+ end
+
+ def in_temporary_directory
+ name = "tmp"
+ FileUtils.rm_rf(name)
+ FileUtils.mkdir_p(name)
+ Dir.chdir(name) do
+ yield
+ end
+ end
+
+ def run_command(*command_line)
+ unless system(*command_line)
+ raise "failed to run command: #{command_line.join(' ')}"
+ end
+ end
+end
+
+uploader = Uploader.new
+uploader.run
diff --git a/storage/mroonga/packages/windows/Makefile.am b/storage/mroonga/packages/windows/Makefile.am
new file mode 100644
index 00000000..240c3873
--- /dev/null
+++ b/storage/mroonga/packages/windows/Makefile.am
@@ -0,0 +1,12 @@
+EXTRA_DIST = \
+ README.md \
+ build-vc2015.bat \
+ build-vc2015-zip-32.bat \
+ build-vc2015-zip-64.bat \
+ build-vc2015-msi-32.bat \
+ build-vc2015-msi-64.bat \
+ build-vc2017.bat \
+ build-vc2017-zip-32.bat \
+ build-vc2017-zip-64.bat \
+ build-vc2017-msi-32.bat \
+ build-vc2017-msi-64.bat
diff --git a/storage/mroonga/packages/windows/README.md b/storage/mroonga/packages/windows/README.md
new file mode 100644
index 00000000..8737f262
--- /dev/null
+++ b/storage/mroonga/packages/windows/README.md
@@ -0,0 +1,21 @@
+# How to build Windows binaries
+
+## Preparation
+
+TODO...
+
+## Build with Visual C++ Express
+
+You need to use Visual Studio 2015 for Windows Desktop or later to build Mroonga with express
+edition. `build-vc2015.bat` is a build batch script to build with
+Visual Studio 2015 for Windows Desktop.
+
+Note that you can't build MSI file with Express edition. You need to
+use Professional edition or upper editions to build MSI file.
+
+## Build with Visual Studio Community
+
+You can build both zip file MSI file with Professional edition.
+But now, this feature is temporary disabled.
+If you want to create MSI package, please uncomment in `build-vc2015.bat`.
+And then, you can build MSI package with Visual Studio 2015 Community.
diff --git a/storage/mroonga/packages/windows/build-vc2015-msi-32.bat b/storage/mroonga/packages/windows/build-vc2015-msi-32.bat
new file mode 100644
index 00000000..69d803e8
--- /dev/null
+++ b/storage/mroonga/packages/windows/build-vc2015-msi-32.bat
@@ -0,0 +1,8 @@
+rmdir /S /Q build-vc2015-msi-32
+mkdir build-vc2015-msi-32
+cd build-vc2015-msi-32
+cmake ..\source -G "Visual Studio 14 2015" > config.log
+cmake --build . --config RelWithDebInfo > build.log
+cmake --build . --config RelWithDebInfo --target msi > msi.log
+move *.msi ..\
+cd ..
diff --git a/storage/mroonga/packages/windows/build-vc2015-msi-64.bat b/storage/mroonga/packages/windows/build-vc2015-msi-64.bat
new file mode 100644
index 00000000..a3d6681b
--- /dev/null
+++ b/storage/mroonga/packages/windows/build-vc2015-msi-64.bat
@@ -0,0 +1,8 @@
+rmdir /S /Q build-vc2015-msi-64
+mkdir build-vc2015-msi-64
+cd build-vc2015-msi-64
+cmake ..\source -G "Visual Studio 14 2015 Win64" > config.log
+cmake --build . --config RelWithDebInfo > build.log
+cmake --build . --config RelWithDebInfo --target msi > msi.log
+move *.msi ..\
+cd ..
diff --git a/storage/mroonga/packages/windows/build-vc2015-zip-32.bat b/storage/mroonga/packages/windows/build-vc2015-zip-32.bat
new file mode 100644
index 00000000..8247fd54
--- /dev/null
+++ b/storage/mroonga/packages/windows/build-vc2015-zip-32.bat
@@ -0,0 +1,13 @@
+rmdir /S /Q build-vc2015-zip-32
+mkdir build-vc2015-zip-32
+cd build-vc2015-zip-32
+cmake ..\source -G "Visual Studio 14 2015" ^
+ -DMRN_GROONGA_EMBED=OFF ^
+ -DMRN_GROONGA_NORMALIZER_MYSQL_EMBED=OFF ^
+ -DGRN_WITH_BUNDLED_LZ4=ON ^
+ -DGRN_WITH_BUNDLED_MECAB=ON ^
+ > config.log
+cmake --build . --config RelWithDebInfo > build.log
+cmake --build . --config RelWithDebInfo --target package > zip.log
+move *.zip ..\
+cd ..
diff --git a/storage/mroonga/packages/windows/build-vc2015-zip-64.bat b/storage/mroonga/packages/windows/build-vc2015-zip-64.bat
new file mode 100644
index 00000000..b56d80eb
--- /dev/null
+++ b/storage/mroonga/packages/windows/build-vc2015-zip-64.bat
@@ -0,0 +1,13 @@
+rmdir /S /Q build-vc2015-zip-64
+mkdir build-vc2015-zip-64
+cd build-vc2015-zip-64
+cmake ..\source -G "Visual Studio 14 2015 Win64" ^
+ -DMRN_GROONGA_EMBED=OFF ^
+ -DMRN_GROONGA_NORMALIZER_MYSQL_EMBED=OFF ^
+ -DGRN_WITH_BUNDLED_LZ4=ON ^
+ -DGRN_WITH_BUNDLED_MECAB=ON ^
+ > config.log
+cmake --build . --config RelWithDebInfo > build.log
+cmake --build . --config RelWithDebInfo --target package > zip.log
+move *.zip ..\
+cd ..
diff --git a/storage/mroonga/packages/windows/build-vc2015.bat b/storage/mroonga/packages/windows/build-vc2015.bat
new file mode 100644
index 00000000..729f181d
--- /dev/null
+++ b/storage/mroonga/packages/windows/build-vc2015.bat
@@ -0,0 +1,4 @@
+call build-vc2015-zip-32.bat
+call build-vc2015-zip-64.bat
+REM build-vc2015-msi-32.bat
+REM build-vc2015--msi-64.bat
diff --git a/storage/mroonga/packages/yum/Makefile.am b/storage/mroonga/packages/yum/Makefile.am
new file mode 100644
index 00000000..9d1bd606
--- /dev/null
+++ b/storage/mroonga/packages/yum/Makefile.am
@@ -0,0 +1,77 @@
+REPOSITORIES_PATH = repositories
+DISTRIBUTIONS = centos
+ARCHITECTURES = i386 x86_64
+MYSQL_VARIANTS = \
+ mysql55 \
+ mysql56-community \
+ mysql57-community \
+ mariadb \
+ mariadb-10.1 \
+ mariadb-10.2 \
+ percona-server-56 \
+ percona-server-57
+CENTOS_VERSIONS = 6 7
+SPEC_DIR = $(builddir)/../rpm/centos
+
+all:
+
+release: download build sign-packages update-repository upload
+
+remove-existing-packages:
+ for distribution in $(DISTRIBUTIONS); do \
+ find $${distribution} -name "*.rpm" -delete; \
+ done
+
+ensure-rsync-path:
+ @if test -z "$(RSYNC_PATH)"; then \
+ echo "--with-rsync-path configure option must be specified."; \
+ false; \
+ fi
+
+sign-packages:
+ ./sign-rpm.sh '$(GPG_UID)' '$(REPOSITORIES_PATH)/' '$(DISTRIBUTIONS)'
+
+update-repository:
+ ./update-repository.sh '$(REPOSITORIES_PATH)/' '$(DISTRIBUTIONS)'
+
+upload: ensure-rsync-path
+ for distribution in $(DISTRIBUTIONS); do \
+ rsync -avz --progress --delete --exclude .gitignore \
+ $(REPOSITORIES_PATH)/$${distribution}/ \
+ $(RSYNC_PATH)/$${distribution}; \
+ done
+
+download: ensure-rsync-path
+ mkdir -p $(REPOSITORIES_PATH)
+ for distribution in $(DISTRIBUTIONS); do \
+ rsync -avz --progress --delete \
+ $(RSYNC_PATH)/$${distribution}/ \
+ $(REPOSITORIES_PATH)/$${distribution}; \
+ done
+
+build: build-in-vm
+
+build-in-vm: source specs env.sh
+ ./build-in-vm.sh \
+ "$(PACKAGE)" \
+ "$(SPEC_DIR)" \
+ "$(MYSQL_VARIANTS)" \
+ "$(ARCHITECTURES)" \
+ "$(CENTOS_VERSIONS)"
+
+source: tmp/$(PACKAGE)-$(VERSION).tar.gz
+
+tmp/$(PACKAGE)-$(VERSION).tar.gz: $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz
+ mkdir -p tmp/
+ cp $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz tmp/
+
+$(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz:
+ cd $(abs_top_builddir) && $(MAKE) dist
+
+specs: $(SPEC_DIR)/mysql55-$(PACKAGE).spec
+specs: $(SPEC_DIR)/mysql56-community-$(PACKAGE).spec
+specs: $(SPEC_DIR)/mariadb-$(PACKAGE).spec
+specs: $(SPEC_DIR)/mariadb-10.1-$(PACKAGE).spec
+specs: $(SPEC_DIR)/mariadb-10.2-$(PACKAGE).spec
+specs: $(SPEC_DIR)/percona-server-56-$(PACKAGE).spec
+specs: $(SPEC_DIR)/percona-server-57-$(PACKAGE).spec
diff --git a/storage/mroonga/packages/yum/Vagrantfile b/storage/mroonga/packages/yum/Vagrantfile
new file mode 100644
index 00000000..af14bc9a
--- /dev/null
+++ b/storage/mroonga/packages/yum/Vagrantfile
@@ -0,0 +1,42 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ vms = [
+ {
+ :id => "centos-6-i386",
+ :box => "bento/centos-6.9-i386",
+ },
+ {
+ :id => "centos-6-x86_64",
+ :box => "bento/centos-6.9",
+ },
+ {
+ :id => "centos-7-x86_64",
+ :box => "bento/centos-7.4",
+ },
+ ]
+
+ vms.each do |vm|
+ config.vm.define(vm[:id]) do |node|
+ node.vm.box = vm[:box]
+ node.vm.provision(:shell, :path => "build-rpm.sh")
+ node.vm.provider("virtualbox") do |virtual_box|
+ system_n_cpus = 1
+ if File.exist?("/proc/cpuinfo")
+ system_n_cpus = File.readlines("/proc/cpuinfo").grep(/^processor/).size
+ end
+ if system_n_cpus > 1
+ vm_n_cpus = system_n_cpus / 2
+ else
+ vm_n_cpus = 1
+ end
+ virtual_box.cpus = vm_n_cpus
+ virtual_box.memory = (ENV["VM_MEMORY"] || 1024).to_i
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/packages/yum/build-in-vm.sh b/storage/mroonga/packages/yum/build-in-vm.sh
new file mode 100755
index 00000000..fc84e450
--- /dev/null
+++ b/storage/mroonga/packages/yum/build-in-vm.sh
@@ -0,0 +1,85 @@
+#!/bin/sh
+
+if [ $# != 5 ]; then
+ echo "Usage: $0 PACKAGE SPEC_DIR MYSQL_VARIANTS ARCHITECTURES"
+ echo " e.g.: $0 mroonga ../rpm/centos 'mysql55 mariadb' 'i386 x86_64' '6 7'"
+ exit 1
+fi
+
+PACKAGE="$1"
+SPEC_DIR="$2"
+MYSQL_VARIANTS="$3"
+ARCHITECTURES="$4"
+CENTOS_VERSIONS="$5"
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+run vagrant destroy --force
+
+for mysql_variant in ${MYSQL_VARIANTS}; do
+ rm -rf tmp/centos/
+ mkdir -p tmp/centos/
+ cp ${SPEC_DIR}/${mysql_variant}-${PACKAGE}.spec tmp/centos/
+
+ architectures="${ARCHITECTURES}"
+ case ${mysql_variant} in
+ mysql55)
+ centos_versions="6"
+ ;;
+ mysql56-community)
+ centos_versions="6 7"
+ ;;
+ mysql57-community)
+ centos_versions="6 7"
+ ;;
+ mariadb)
+ centos_versions="7"
+ ;;
+ mariadb-10.1)
+ centos_versions="6 7"
+ ;;
+ mariadb-10.2)
+ centos_versions="6 7"
+ ;;
+ percona-server-56)
+ centos_versions="6 7"
+ ;;
+ percona-server-57)
+ centos_versions="6 7"
+ ;;
+ esac
+
+ for architecture in ${architectures}; do
+ for centos_version in ${centos_versions}; do
+ skip=1
+ for given_version in ${CENTOS_VERSIONS}; do
+ if [ ${given_version} = ${centos_version} ]; then
+ skip=0
+ fi
+ done
+ if [ $skip -eq 1 ]; then
+ continue
+ fi
+ if [ ${mysql_variant} = mysql55 -a ${centos_version} = 6 -a ${architecture} = i386 ]; then
+ continue
+ fi
+ if [ ${centos_version} = 7 -a ${architecture} = i386 ]; then
+ continue
+ fi
+ id=centos-${centos_version}-${architecture}
+ vagrant up ${id}
+ build_status=$?
+ if [ $build_status -ne 0 ]; then
+ exit $build_status
+ fi
+ vagrant destroy --force ${id}
+ done
+ done
+done
diff --git a/storage/mroonga/packages/yum/build-rpm.sh b/storage/mroonga/packages/yum/build-rpm.sh
new file mode 100755
index 00000000..6ba943ae
--- /dev/null
+++ b/storage/mroonga/packages/yum/build-rpm.sh
@@ -0,0 +1,182 @@
+#!/bin/sh
+
+LANG=C
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+rpmbuild_options=
+
+. /vagrant/env.sh
+
+distribution=$(cut -d " " -f 1 /etc/redhat-release | tr "A-Z" "a-z")
+if grep -q Linux /etc/redhat-release; then
+ distribution_version=$(cut -d " " -f 4 /etc/redhat-release)
+else
+ distribution_version=$(cut -d " " -f 3 /etc/redhat-release)
+fi
+distribution_version=$(echo ${distribution_version} | sed -e 's/\..*$//g')
+
+architecture="$(arch)"
+case "${architecture}" in
+ i*86)
+ architecture=i386
+ ;;
+esac
+
+run yum groupinstall -y "Development Tools"
+run yum install -y rpm-build rpmdevtools tar wget
+
+if [ -x /usr/bin/rpmdev-setuptree ]; then
+ rm -rf .rpmmacros
+ run rpmdev-setuptree
+else
+ run cat <<EOM > ~/.rpmmacros
+%_topdir ${HOME}/rpmbuild
+EOM
+ run mkdir -p ~/rpmbuild/SOURCES
+ run mkdir -p ~/rpmbuild/SPECS
+ run mkdir -p ~/rpmbuild/BUILD
+ run mkdir -p ~/rpmbuild/RPMS
+ run mkdir -p ~/rpmbuild/SRPMS
+fi
+
+repository="/vagrant/repositories/${distribution}/${distribution_version}"
+rpm_dir="${repository}/${architecture}/Packages"
+srpm_dir="${repository}/source/SRPMS"
+run mkdir -p "${rpm_dir}" "${srpm_dir}"
+
+rpmbuild_options=""
+
+# for debug
+# rpmbuild_options="${rpmbuild_options} --define 'optflags -O0 -g3'"
+
+cd
+
+run cp /vagrant/tmp/${PACKAGE}-${VERSION}.* rpmbuild/SOURCES/
+run cp /vagrant/tmp/${distribution}/*.spec rpmbuild/SPECS/
+
+package_name=$(cd rpmbuild/SPECS; echo *.spec | sed -e 's/\.spec$//g')
+
+case ${distribution} in
+ fedora)
+ USE_MYSQLSERVICES_COMPAT=yes
+ run yum install -y mariadb-devel
+ ;;
+ centos)
+ release_rpm=groonga-release-1.3.0-1.noarch.rpm
+ if [ ${distribution_version} = 5 ]; then
+ wget http://packages.groonga.org/${distribution}/${release_rpm}
+ run yum install -y --nogpgcheck ${release_rpm}
+ rm -f ${release_rpm}
+ else
+ run yum install -y \
+ http://packages.groonga.org/${distribution}/${release_rpm}
+ fi
+ run yum makecache
+
+ case ${package_name} in
+ mysql55-${PACKAGE})
+ USE_MYSQLSERVICES_COMPAT=yes
+ run yum install -y scl-utils-build
+ if [ ${distribution_version} = 6 ]; then
+ run yum install -y centos-release-scl
+ fi
+ run yum install -y mysql55-mysql-devel mysql55-build
+ ;;
+ mysql5?-community-${PACKAGE})
+ release_rpm=mysql-community-release-el${distribution_version}-7.noarch.rpm
+ run yum -y install http://repo.mysql.com/${release_rpm}
+ if [ "${package_name}" = "mysql57-community-${PACKAGE}" ]; then
+ run yum install -y yum-utils
+ run yum-config-manager --disable mysql56-community
+ run yum-config-manager --enable mysql57-community
+ if [ ${distribution_version} = 6 ]; then
+ run yum install -y cmake28
+ fi
+ fi
+ run yum install -y mysql-community-devel
+ ;;
+ mariadb-${PACKAGE})
+ run yum install -y mariadb-devel
+ ;;
+ mariadb-10.1-${PACKAGE})
+ if [ "${architecture}" = "x86_64" ]; then
+ mariadb_architecture="amd64"
+ else
+ mariadb_architecture="x86"
+ fi
+ cat <<REPO > /etc/yum.repos.d/MariaDB.repo
+[mariadb]
+name = MariaDB
+baseurl = http://yum.mariadb.org/10.1/${distribution}${distribution_version}-${mariadb_architecture}
+gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
+gpgcheck=1
+REPO
+ run yum install -y MariaDB-devel
+ if [ ${distribution_version} = 6 ]; then
+ run yum install -y cmake28
+ fi
+ ;;
+ mariadb-10.2-${PACKAGE})
+ if [ "${architecture}" = "x86_64" ]; then
+ mariadb_architecture="amd64"
+ else
+ mariadb_architecture="x86"
+ fi
+ cat <<REPO > /etc/yum.repos.d/MariaDB.repo
+[mariadb]
+name = MariaDB
+baseurl = http://yum.mariadb.org/10.2/${distribution}${distribution_version}-${mariadb_architecture}
+gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
+gpgcheck=1
+REPO
+ run yum install -y MariaDB-devel
+ if [ ${distribution_version} = 6 ]; then
+ run yum install -y cmake28
+ fi
+ ;;
+ percona-server-56-${PACKAGE})
+ release_rpm_version=0.1-4
+ release_rpm=percona-release-${release_rpm_version}.noarch.rpm
+ run yum install -y http://www.percona.com/downloads/percona-release/redhat/${release_rpm_version}/${release_rpm}
+ run yum install -y Percona-Server-devel-56
+ ;;
+ percona-server-57-${PACKAGE})
+ release_rpm_version=0.1-4
+ release_rpm=percona-release-${release_rpm_version}.noarch.rpm
+ run yum install -y http://www.percona.com/downloads/percona-release/redhat/${release_rpm_version}/${release_rpm}
+ run yum install -y Percona-Server-devel-57
+ if [ ${distribution_version} = 6 ]; then
+ run yum install -y cmake28
+ fi
+ ;;
+ esac
+ ;;
+esac
+run yum install -y ${DEPENDED_PACKAGES}
+
+if [ "${package_name}" = "percona-server-56-${PACKAGE}" ]; then
+ if [ "${distribution_version}" = "7" ]; then
+ rpmbuild_options="$rpmbuild_options --define 'dist .el7'"
+ fi
+fi
+if [ "${package_name}" = "percona-server-57-${PACKAGE}" ]; then
+ if [ "${distribution_version}" = "7" ]; then
+ rpmbuild_options="$rpmbuild_options --define 'dist .el7'"
+ fi
+fi
+if [ "${USE_MYSQLSERVICES_COMPAT}" = "yes" ]; then
+ rpmbuild_options="$rpmbuild_options --define 'mroonga_configure_options --with-libmysqlservices-compat'"
+fi
+
+run eval rpmbuild -ba ${rpmbuild_options} rpmbuild/SPECS/${package_name}.spec
+
+run mv rpmbuild/RPMS/*/* "${rpm_dir}/"
+run mv rpmbuild/SRPMS/* "${srpm_dir}/"
diff --git a/storage/mroonga/packages/yum/env.sh.in b/storage/mroonga/packages/yum/env.sh.in
new file mode 100644
index 00000000..3d327a17
--- /dev/null
+++ b/storage/mroonga/packages/yum/env.sh.in
@@ -0,0 +1,32 @@
+PACKAGE=@PACKAGE@
+VERSION=@VERSION@
+DEPENDED_PACKAGES="
+intltool
+libtool
+gcc
+gcc-c++
+make
+gperf
+readline-devel
+openssl-devel
+zlib-devel
+time
+wget
+ncurses-devel
+sudo
+pkgconfig
+tar
+cmake
+libaio-devel
+systemtap-sdt-devel
+perl-Time-HiRes
+perl-Env
+perl-Test-Simple
+pam-devel
+selinux-policy-devel
+numactl-devel
+groonga-devel
+groonga-normalizer-mysql-devel
+cyrus-sasl-devel
+openldap-devel
+"
diff --git a/storage/mroonga/packages/yum/sign-rpm.sh b/storage/mroonga/packages/yum/sign-rpm.sh
new file mode 100755
index 00000000..27ec5711
--- /dev/null
+++ b/storage/mroonga/packages/yum/sign-rpm.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_UID DESTINATION DISTRIBUTIONS"
+ echo " e.g.: $0 'F10399C0' repositories/ 'fedora centos'"
+ exit 1
+fi
+
+GPG_UID=$1
+DESTINATION=$2
+DISTRIBUTIONS=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+unsigned_rpms()
+{
+ while read rpm; do
+ rpm --checksig "$rpm" | grep -v 'gpg OK' | grep -v 'MISSING KEYS' | cut -d":" -f1
+ done
+}
+
+if ! gpg --list-keys "${GPG_UID}" > /dev/null 2>&1; then
+ run gpg --keyserver keyserver.ubuntu.com --recv-key "${GPG_UID}"
+fi
+run mkdir -p tmp
+run gpg --armor --export "${GPG_UID}" > tmp/sign-key
+run rpm --import tmp/sign-key
+run rm -rf tmp/sign-key
+
+rpms=""
+for distribution in ${DISTRIBUTIONS}; do
+ rpms="${rpms} $(find ${DESTINATION}${distribution} -name '*.rpm' | unsigned_rpms)"
+done
+
+echo "NOTE: YOU JUST ENTER! YOU DON'T NEED TO INPUT PASSWORD!"
+echo " IT'S JUST FOR rpm COMMAND RESTRICTION!"
+run echo $rpms | xargs rpm \
+ -D "_gpg_name ${GPG_UID}" \
+ -D "_gpg_digest_algo sha1" \
+ -D "__gpg /usr/bin/gpg2" \
+ -D "__gpg_check_password_cmd /bin/true true" \
+ -D "__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-armor %{?_gpg_digest_algo:--digest-algo %{_gpg_digest_algo}} --no-secmem-warning -u \"%{_gpg_name}\" -sbo %{__signature_filename} %{__plaintext_filename}" \
+ --resign
diff --git a/storage/mroonga/packages/yum/update-repository.sh b/storage/mroonga/packages/yum/update-repository.sh
new file mode 100755
index 00000000..59eeafa5
--- /dev/null
+++ b/storage/mroonga/packages/yum/update-repository.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 2 ]; then
+ echo "Usage: $0 DESTINATION DISTRIBUTIONS"
+ echo " e.g.: $0 repositories/ 'fedora centos'"
+ exit 1
+fi
+
+DESTINATION=$1
+DISTRIBUTIONS=$2
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+for distribution in ${DISTRIBUTIONS}; do
+ for dir in ${DESTINATION}${distribution}/*/*; do
+ test -d $dir && run createrepo $dir
+ done;
+done
diff --git a/storage/mroonga/plugin_version b/storage/mroonga/plugin_version
new file mode 100644
index 00000000..120096f1
--- /dev/null
+++ b/storage/mroonga/plugin_version
@@ -0,0 +1 @@
+7.7 \ No newline at end of file
diff --git a/storage/mroonga/required_groonga_normalizer_mysql_version b/storage/mroonga/required_groonga_normalizer_mysql_version
new file mode 100644
index 00000000..66c4c226
--- /dev/null
+++ b/storage/mroonga/required_groonga_normalizer_mysql_version
@@ -0,0 +1 @@
+1.0.9
diff --git a/storage/mroonga/required_groonga_version b/storage/mroonga/required_groonga_version
new file mode 100644
index 00000000..024b4b9b
--- /dev/null
+++ b/storage/mroonga/required_groonga_version
@@ -0,0 +1 @@
+7.0.6
diff --git a/storage/mroonga/sources.am b/storage/mroonga/sources.am
new file mode 100644
index 00000000..c7ddcfa5
--- /dev/null
+++ b/storage/mroonga/sources.am
@@ -0,0 +1,12 @@
+sources = \
+ mrn_macro.hpp \
+ mrn_constants.hpp \
+ ha_mroonga.cpp \
+ ha_mroonga.hpp \
+ mrn_table.cpp \
+ mrn_table.hpp \
+ mrn_err.h \
+ mrn_mysql.h \
+ mrn_mysql_compat.h \
+ mrn_variables.hpp \
+ ha_mroonga.def
diff --git a/storage/mroonga/test/Makefile.am b/storage/mroonga/test/Makefile.am
new file mode 100644
index 00000000..ce75011b
--- /dev/null
+++ b/storage/mroonga/test/Makefile.am
@@ -0,0 +1,14 @@
+SUBDIRS = unit
+
+TESTS = run-sql-test.sh
+TESTS_ENVIRONMENT = \
+ NO_MAKE="yes"
+
+if WITH_CUTTER
+TESTS += run-unit-test.sh
+TESTS_ENVIRONMENT += CUTTER="$(CUTTER)"
+endif
+
+EXTRA_DIST = \
+ run-unit-test.sh \
+ run-sql-test.sh
diff --git a/storage/mroonga/test/run-sql-test.sh b/storage/mroonga/test/run-sql-test.sh
new file mode 100755
index 00000000..589de478
--- /dev/null
+++ b/storage/mroonga/test/run-sql-test.sh
@@ -0,0 +1,244 @@
+#!/bin/sh
+#
+# Copyright(C) 2010 Tetsuro IKEDA
+# Copyright(C) 2010-2017 Kouhei Sutou <kou@clear-code.com>
+# Copyright(C) 2011 Kazuhiko
+#
+# 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-1335 USA
+
+export BASE_DIR="$(cd $(dirname $0); pwd)"
+top_dir="$BASE_DIR/.."
+mroonga_test_dir="${top_dir}/mysql-test/mroonga"
+
+n_processors=1
+case `uname` in
+ Linux)
+ n_processors="$(grep '^processor' /proc/cpuinfo | wc -l)"
+ ;;
+ Darwin)
+ n_processors="$(/usr/sbin/sysctl -n hw.ncpu)"
+ ;;
+ *)
+ :
+ ;;
+esac
+
+if [ "$NO_MAKE" != "yes" ]; then
+ MAKE_ARGS=
+ if [ -n "$n_processors" ]; then
+ MAKE_ARGS="-j${n_processors}"
+ fi
+ make $MAKE_ARGS -C $top_dir > /dev/null || exit 1
+fi
+
+. "${top_dir}/config.sh"
+
+bundled_groonga_normalizer_mysql_dir="${top_dir}/vendor/groonga/vendor/plugins/groonga-normalizer-mysql"
+if [ -d "${bundled_groonga_normalizer_mysql_dir}" ]; then
+ GRN_PLUGINS_DIR="${bundled_groonga_normalizer_mysql_dir}"
+ export GRN_PLUGINS_DIR
+fi
+
+maria_storage_dir="${MYSQL_SOURCE_DIR}/storage/maria"
+if [ -d "${maria_storage_dir}" ]; then
+ mariadb="yes"
+else
+ mariadb="no"
+fi
+percona_udf_dir="${MYSQL_SOURCE_DIR}/plugin/percona-udf"
+if [ -d "${percona_udf_dir}" ]; then
+ percona="yes"
+else
+ percona="no"
+fi
+
+source_mysql_test_dir="${MYSQL_SOURCE_DIR}/mysql-test"
+build_mysql_test_dir="${MYSQL_BUILD_DIR}/mysql-test"
+source_test_suites_dir="${source_mysql_test_dir}/suite"
+source_test_include_dir="${source_mysql_test_dir}/include"
+build_test_suites_dir="${build_mysql_test_dir}/suite"
+build_test_include_dir="${build_mysql_test_dir}/include"
+case "${MYSQL_VERSION}" in
+ 5.1.*)
+ plugins_dir="${MYSQL_BUILD_DIR}/lib/mysql/plugin"
+ if [ ! -d "${build_test_suites_dir}" ]; then
+ mkdir -p "${build_test_suites_dir}"
+ fi
+ ;;
+ *)
+ if [ ! -d "${build_test_suites_dir}" ]; then
+ ln -s "${source_test_suites_dir}" "${build_test_suites_dir}"
+ fi
+ if [ "${mariadb}" = "yes" ]; then
+ if [ "${MRN_BUNDLED}" != "TRUE" ]; then
+ mariadb_mroonga_plugin_dir="${MYSQL_BUILD_DIR}/plugin/mroonga"
+ if [ ! -e "${mariadb_mroonga_plugin_dir}" ]; then
+ ln -s "${top_dir}" "${mariadb_mroonga_plugin_dir}"
+ fi
+ fi
+ plugins_dir=
+ elif [ "${percona}" = "yes" ]; then
+ plugins_dir="${MYSQL_SOURCE_DIR}/lib/mysql/plugin"
+ else
+ plugins_dir="${MYSQL_SOURCE_DIR}/lib/plugin"
+ fi
+ ;;
+esac
+
+same_link_p()
+{
+ src=$1
+ dest=$2
+ if [ -L "$dest" -a "$(readlink "$dest")" = "$src" ]; then
+ return 0
+ else
+ return 1
+ fi
+}
+
+mroonga_mysql_test_suite_dir="${build_test_suites_dir}/mroonga"
+if ! same_link_p "${mroonga_test_dir}" "${mroonga_mysql_test_suite_dir}"; then
+ rm -rf "${mroonga_mysql_test_suite_dir}"
+ ln -s "${mroonga_test_dir}" "${mroonga_mysql_test_suite_dir}"
+fi
+
+innodb_test_suite_dir="${build_test_suites_dir}/innodb"
+mroonga_wrapper_innodb_test_suite_name="mroonga_wrapper_innodb"
+mroonga_wrapper_innodb_test_suite_dir="${build_test_suites_dir}/${mroonga_wrapper_innodb_test_suite_name}"
+mroonga_wrapper_innodb_include_dir="${mroonga_wrapper_innodb_test_suite_dir}/include/"
+if [ "$0" -nt "$(dirname "${mroonga_wrapper_innodb_test_suite_dir}")" ]; then
+ rm -rf "${mroonga_wrapper_innodb_test_suite_dir}"
+fi
+if [ ! -d "${mroonga_wrapper_innodb_test_suite_dir}" ]; then
+ cp -rp "${innodb_test_suite_dir}" "${mroonga_wrapper_innodb_test_suite_dir}"
+ mkdir -p "${mroonga_wrapper_innodb_include_dir}"
+ cp -rp "${source_test_include_dir}"/innodb[-_]*.inc \
+ "${mroonga_wrapper_innodb_include_dir}"
+ ruby -i'' \
+ -pe "\$_.gsub!(/\\bengine\\s*=\\s*innodb\\b([^;\\n]*)/i,
+ \"ENGINE=mroonga\\\1 COMMENT='ENGINE \\\"InnoDB\\\"'\")
+ \$_.gsub!(/\\b(storage_engine\\s*=\\s*)innodb\\b([^;\\n]*)/i,
+ \"\\\1mroonga\")
+ \$_.gsub!(/^(--\\s*source\\s+)(include\\/innodb)/i,
+ \"\\\1suite/mroonga_wrapper_innodb/\\\2\")
+ " \
+ ${mroonga_wrapper_innodb_test_suite_dir}/r/*.result \
+ ${mroonga_wrapper_innodb_test_suite_dir}/t/*.test \
+ ${mroonga_wrapper_innodb_test_suite_dir}/include/*.inc
+ sed -i'' \
+ -e '1 i --source ../mroonga/include/mroonga/have_mroonga.inc' \
+ ${mroonga_wrapper_innodb_test_suite_dir}/t/*.test
+fi
+
+all_test_suite_names=""
+suite_dir="${mroonga_test_dir}/.."
+cd "${suite_dir}"
+suite_dir="$(pwd)"
+for test_suite_name in \
+ $(find mroonga -type d -name 'include' '!' -prune -o \
+ -type d '!' -name 'mroonga' \
+ '!' -name 'include' \
+ '!' -name '[tr]'); do
+ if [ -n "${all_test_suite_names}" ]; then
+ all_test_suite_names="${all_test_suite_names},"
+ fi
+ all_test_suite_names="${all_test_suite_names}${test_suite_name}"
+done
+cd -
+
+if [ -n "${plugins_dir}" ]; then
+ if [ -d "${top_dir}/.libs" ]; then
+ make -C ${top_dir} \
+ install-pluginLTLIBRARIES \
+ plugindir=${plugins_dir} > /dev/null || \
+ exit 1
+ else
+ mkdir -p "${plugins_dir}"
+ cp "${top_dir}/ha_mroonga.so" "${plugins_dir}" || exit 1
+ fi
+fi
+
+mysql_test_run_options=""
+test_suite_names=""
+test_names=""
+while [ $# -gt 0 ]; do
+ arg="$1"
+ shift
+ case "$arg" in
+ --manual-gdb|--gdb|--client-gdb|--boot-gdb|--debug|--valgrind)
+ n_processors=1
+ mysql_test_run_options="${mysql_test_run_options} ${arg}"
+ ;;
+ --*)
+ mysql_test_run_options="${mysql_test_run_options} ${arg}"
+ ;;
+ *)
+ case "$arg" in
+ */t/*.test)
+ test_suite_name=$(echo "$arg" | sed -e 's,/t/.*\.test,,g')
+ test_suite_name=$(cd "$test_suite_name" && pwd)
+ test_name=$(echo "$arg" | sed -e 's,.*/t/\(.*\)\.test,\1,g')
+ ;;
+ *)
+ if [ -d "$arg" ]; then
+ test_suite_name=$(cd "$arg" && pwd)
+ else
+ test_suite_name="$arg"
+ fi
+ test_name=""
+ ;;
+ esac
+
+ if [ -n "${test_name}" ]; then
+ if [ -n "${test_names}" ]; then
+ test_names="${test_names}|"
+ fi
+ test_names="${test_names}${test_name}"
+ fi
+
+ test_suite_name=$(echo "$test_suite_name" | sed -e "s,^${suite_dir}/,,")
+ if echo "${test_suite_names}" | grep --quiet "${test_suite_name}"; then
+ continue
+ fi
+ if [ -n "${test_suite_names}" ]; then
+ test_suite_names="${test_suite_names},"
+ fi
+ test_suite_names="${test_suite_names}${test_suite_name}"
+ ;;
+ esac
+done
+
+if [ -z "$test_suite_names" ]; then
+ test_suite_names="${all_test_suite_names}"
+fi
+
+mysql_test_run_args=""
+if [ "${percona}" != "yes" ]; then
+ mysql_test_run_args="${mysql_test_run_args} --mem"
+fi
+mysql_test_run_args="${mysql_test_run_args} --parallel=${n_processors}"
+mysql_test_run_args="${mysql_test_run_args} --retry=1"
+mysql_test_run_args="${mysql_test_run_args} --suite=${test_suite_names}"
+mysql_test_run_args="${mysql_test_run_args} --force"
+mysql_test_run_args="${mysql_test_run_args} --mysqld=--loose-plugin-load-add=ha_mroonga.so"
+mysql_test_run_args="${mysql_test_run_args} --mysqld=--loose-plugin-mroonga=ON"
+if [ -n "$test_names" ]; then
+ mysql_test_run_args="${mysql_test_run_args} --do-test=${test_names}"
+fi
+
+(cd "$build_mysql_test_dir" && \
+ perl -I . ./mysql-test-run.pl \
+ ${mysql_test_run_args} \
+ ${mysql_test_run_options})
diff --git a/storage/mroonga/test/run-unit-test.sh b/storage/mroonga/test/run-unit-test.sh
new file mode 100755
index 00000000..6d995131
--- /dev/null
+++ b/storage/mroonga/test/run-unit-test.sh
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+export BASE_DIR="`dirname $0`"
+top_dir="$BASE_DIR/.."
+
+if test -z "$NO_MAKE"; then
+ MAKE_ARGS=
+ case `uname` in
+ Linux)
+ MAKE_ARGS="-j$(grep '^processor' /proc/cpuinfo | wc -l)"
+ ;;
+ Darwin)
+ MAKE_ARGS="-j$(/usr/sbin/sysctl -n hw.ncpu)"
+ ;;
+ *)
+ :
+ ;;
+ esac
+ make $MAKE_ARGS -C $top_dir > /dev/null || exit 1
+fi
+
+if test -z "$CUTTER"; then
+ CUTTER="`make -s -C $top_dir echo-cutter`"
+fi
+export CUTTER
+
+CUTTER_ARGS=
+CUTTER_WRAPPER=
+if test x"$STOP" = x"yes"; then
+ CUTTER_ARGS="-v v --fatal-failures"
+else
+ CUTTER_ARGS="-v v"
+fi
+
+if test x"$CUTTER_DEBUG" = x"yes"; then
+ if test x"$TUI_DEBUG" = x"yes"; then
+ CUTTER_WRAPPER="$top_dir/libtool --mode=execute gdb --tui --args"
+ else
+ CUTTER_WRAPPER="$top_dir/libtool --mode=execute gdb --args"
+ fi
+ CUTTER_ARGS="--keep-opening-modules"
+elif test x"$CUTTER_CHECK_LEAK" = x"yes"; then
+ CUTTER_WRAPPER="$top_dir/libtool --mode=execute valgrind "
+ CUTTER_WRAPPER="$CUTTER_WRAPPER --leak-check=full --show-reachable=yes -v"
+ CUTTER_ARGS="--keep-opening-modules"
+fi
+
+CUTTER_ARGS="$CUTTER_ARGS -s $BASE_DIR"
+$CUTTER_WRAPPER $CUTTER $CUTTER_ARGS "$@" $BASE_DIR
diff --git a/storage/mroonga/test/unit/Makefile.am b/storage/mroonga/test/unit/Makefile.am
new file mode 100644
index 00000000..3950ce0d
--- /dev/null
+++ b/storage/mroonga/test/unit/Makefile.am
@@ -0,0 +1,27 @@
+if WITH_CUTTER
+noinst_LTLIBRARIES = \
+ test_mrn_path_mapper.la
+endif
+
+AM_CPPFLAGS = \
+ $(GROONGA_CFLAGS) \
+ $(CPPCUTTER_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/lib
+
+AM_LDFLAGS = \
+ -module \
+ -rpath $(libdir) \
+ -avoid-version \
+ -no-undefined
+
+LIBS = \
+ $(CPPCUTTER_LIBS) \
+ $(GROONGA_LIBS) \
+ $(MECAB_LIBS)
+
+test_mrn_path_mapper_la_SOURCES = \
+ test_mrn_path_mapper.cpp
+
+test_mrn_path_mapper_la_LIBADD = \
+ $(top_builddir)/lib/libmrn_no_mysql.la
diff --git a/storage/mroonga/test/unit/test_mrn_path_mapper.cpp b/storage/mroonga/test/unit/test_mrn_path_mapper.cpp
new file mode 100644
index 00000000..3ede8726
--- /dev/null
+++ b/storage/mroonga/test/unit/test_mrn_path_mapper.cpp
@@ -0,0 +1,134 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2015 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-1335 USA
+*/
+
+#include <string.h>
+#include <cppcutter.h>
+
+#include <mrn_path_mapper.hpp>
+
+namespace test_mrn_path_mapper {
+ namespace db_path {
+ namespace without_prefix {
+ void test_normal_db() {
+ mrn::PathMapper mapper("./db/", NULL);
+ cppcut_assert_equal("db.mrn", mapper.db_path());
+ }
+
+ void test_normal_table() {
+ mrn::PathMapper mapper("./db/table", NULL);
+ cppcut_assert_equal("db.mrn", mapper.db_path());
+ }
+
+ void test_temporary_table() {
+ mrn::PathMapper mapper("/tmp/mysqld.1/#sql27c5_1_0", NULL);
+ cppcut_assert_equal("/tmp/mysqld.1/#sql27c5_1_0.mrn",
+ mapper.db_path());
+ }
+ }
+
+ namespace with_prefix {
+ void test_normal_db() {
+ mrn::PathMapper mapper("./db/", "mroonga.data/");
+ cppcut_assert_equal("mroonga.data/db.mrn", mapper.db_path());
+ }
+
+ void test_normal_table() {
+ mrn::PathMapper mapper("./db/table", "mroonga.data/");
+ cppcut_assert_equal("mroonga.data/db.mrn", mapper.db_path());
+ }
+
+ void test_temporary_table() {
+ mrn::PathMapper mapper("/tmp/mysqld.1/#sql27c5_1_0", "mroonga.data/");
+ cppcut_assert_equal("/tmp/mysqld.1/#sql27c5_1_0.mrn",
+ mapper.db_path());
+ }
+ }
+ }
+
+ namespace db_name {
+ void test_normal_db() {
+ mrn::PathMapper mapper("./db/", NULL);
+ cppcut_assert_equal("db", mapper.db_name());
+ }
+
+ void test_normal_table() {
+ mrn::PathMapper mapper("./db/table", NULL);
+ cppcut_assert_equal("db", mapper.db_name());
+ }
+
+ void test_temporary_table() {
+ mrn::PathMapper mapper("/tmp/mysqld.1/#sql27c5_1_0", NULL);
+ cppcut_assert_equal("/tmp/mysqld.1/#sql27c5_1_0",
+ mapper.db_name());
+ }
+ }
+
+ namespace table_name {
+ void test_normal_table() {
+ mrn::PathMapper mapper("./db/table", NULL);
+ cppcut_assert_equal("table", mapper.table_name());
+ }
+
+ void test_temporary_table() {
+ mrn::PathMapper mapper("/tmp/mysqld.1/#sql27c5_1_0", NULL);
+ cppcut_assert_equal("#sql27c5_1_0", mapper.table_name());
+ }
+
+ void test_underscore_start_table() {
+ mrn::PathMapper mapper("./db/_table", NULL);
+ cppcut_assert_equal("@005ftable", mapper.table_name());
+ }
+ }
+
+ namespace mysql_table_name {
+ void test_normal_table() {
+ mrn::PathMapper mapper("./db/table", NULL);
+ cppcut_assert_equal("table", mapper.mysql_table_name());
+ }
+
+ void test_temporary_table() {
+ mrn::PathMapper mapper("/tmp/mysqld.1/#sql27c5_1_0", NULL);
+ cppcut_assert_equal("#sql27c5_1_0", mapper.mysql_table_name());
+ }
+
+ void test_underscore_start_table() {
+ mrn::PathMapper mapper("./db/_table", NULL);
+ cppcut_assert_equal("_table", mapper.mysql_table_name());
+ }
+ }
+
+ namespace mysql_path {
+ void test_normal_table() {
+ mrn::PathMapper mapper("./db/table");
+ cppcut_assert_equal("./db/table", mapper.mysql_path());
+ }
+
+ void test_temporary_table() {
+ mrn::PathMapper mapper("/tmp/mysqld.1/#sql27c5_1_0");
+ cppcut_assert_equal("/tmp/mysqld.1/#sql27c5_1_0",
+ mapper.mysql_path());
+ }
+
+ void test_partition_table_path() {
+ mrn::PathMapper mapper("./db/table#P#p1");
+ cppcut_assert_equal("./db/table", mapper.mysql_path());
+ }
+ }
+}
+
diff --git a/storage/mroonga/tools/Makefile.am b/storage/mroonga/tools/Makefile.am
new file mode 100644
index 00000000..b65b9300
--- /dev/null
+++ b/storage/mroonga/tools/Makefile.am
@@ -0,0 +1,6 @@
+noinstall_ruby_scripts = \
+ prepare-sphinx-html.rb \
+ upload-to-github.rb
+
+EXTRA_DIST = \
+ $(noinstall_ruby_scripts)
diff --git a/storage/mroonga/tools/prepare-sphinx-html.rb b/storage/mroonga/tools/prepare-sphinx-html.rb
new file mode 100755
index 00000000..71e12f0e
--- /dev/null
+++ b/storage/mroonga/tools/prepare-sphinx-html.rb
@@ -0,0 +1,175 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+
+if ARGV.size != 2
+ puts "Usage: #{$0} SOURCE_DIR DEST_DIR"
+ exit(false)
+end
+
+require 'pathname'
+require "fileutils"
+
+def fix_link(text, extension, language)
+ send("fix_#{extension}_link", text, language)
+end
+
+def fix_link_path(text)
+ text.gsub(/\b_(sources|static|images)\b/, '\1')
+end
+
+def fix_language_link(url, language)
+ url.gsub(/\A((?:\.\.\/){2,})([a-z]{2})\/html\//) do
+ relative_base_path = $1
+ link_language = $2
+ close_quote = $3
+ if language == "en"
+ relative_base_path = relative_base_path.gsub(/\A\.\.\//, '')
+ end
+ if link_language != "en"
+ relative_base_path += "#{link_language}/"
+ end
+ "#{relative_base_path}docs/"
+ end
+end
+
+def fix_html_link(html, language)
+ html = html.gsub(/(href|src)="(.+?)"/) do
+ attribute = $1
+ link = $2
+ link = fix_link_path(link)
+ link = fix_language_link(link, language)
+ "#{attribute}=\"#{link}\""
+ end
+ html.gsub(/(id="top-link" href=)"(.+?)"/) do
+ prefix = $1
+ top_path = $2.gsub(/\/index\.html\z/, '/')
+ top_path = "./" if ["index.html", "#"].include?(top_path)
+ "#{prefix}\"#{top_path}../\""
+ end
+end
+
+def fix_js_link(js, language)
+ fix_link_path(js)
+end
+
+LANGUAGE_TO_LOCALE = {
+ "ja" => "ja_JP",
+ "en" => "en_US",
+}
+
+def insert_facebook_html_header(html)
+ html.gsub(/<\/head>/) do
+ <<-HTML
+ <meta property="fb:page_id" content="238184682903165" /><!-- mroonga -->
+ <meta property="fb:admins" content="664204556" /><!-- kouhei.sutou -->
+ <meta property="og:type" content="product" />
+ <meta property="og:image" content="http://mroonga.org/images/logos/mroonga-icon-full-size.png" />
+ <meta property="og:site_name" content="mroonga" />
+
+ <link rel="stylesheet" href="/css/sphinx.css" type="text/css" />
+ </head>
+ HTML
+ end
+end
+
+def insert_facebook_html_fb_root(html)
+ html.gsub(/<body>/) do
+ <<-HTML
+ <body>
+ <div id="fb-root"></div>
+ HTML
+ end
+end
+
+def insert_facebook_html_buttons(html)
+ html.gsub(/(<div class="other-language-links">)/) do
+ <<-HTML
+ <div class="facebook-buttons">
+ <fb:like href="http://www.facebook.com/pages/mroonga/238184682903165"
+ layout="standard"
+ width="290"></fb:like>
+ </div>
+ #{$1}
+ HTML
+ end
+end
+
+def insert_facebook_html_footer(html, language)
+ locale = LANGUAGE_TO_LOCALE[language]
+ raise "unknown locale for language #{language.inspect}" if locale.nil?
+ html.gsub(/<\/body>/) do
+ <<-HTML
+ <script src="http://connect.facebook.net/#{locale}/all.js"></script>
+
+ <script>
+ FB.init({
+ appId : null,
+ status : true, // check login status
+ cookie : true, // enable cookies to allow the server to access the session
+ xfbml : true // parse XFBML
+ });
+ </script>
+ </body>
+ HTML
+ end
+end
+
+def insert_facebook_html(html, language)
+ html = insert_facebook_html_header(html)
+ html = insert_facebook_html_fb_root(html)
+ html = insert_facebook_html_buttons(html)
+ html = insert_facebook_html_footer(html, language)
+ html
+end
+
+source_dir, dest_dir = ARGV
+
+source_dir = Pathname.new(source_dir)
+dest_dir = Pathname.new(dest_dir)
+
+language_dirs = []
+source_dir.each_entry do |top_level_path|
+ language_dirs << top_level_path if /\A[a-z]{2}\z/ =~ top_level_path.to_s
+end
+
+language_dirs.each do |language_dir|
+ language = language_dir.to_s
+ language_source_dir = source_dir + language_dir + "html"
+ language_dest_dir = dest_dir + language_dir
+ language_source_dir.find do |source_path|
+ relative_path = source_path.relative_path_from(language_source_dir)
+ dest_path = language_dest_dir + relative_path
+ if source_path.directory?
+ dest_path.mkpath
+ else
+ case source_path.extname
+ when ".html", ".js"
+ content = source_path.read
+ extension = source_path.extname.gsub(/\A\./, '')
+ content = fix_link(content, extension, language)
+ if extension == "html"
+ content = insert_facebook_html(content, language)
+ end
+ dest_path.open("wb") do |dest|
+ dest.print(content.strip)
+ end
+ FileUtils.touch(dest_path, :mtime => source_path.mtime)
+ else
+ case source_path.basename.to_s
+ when ".buildinfo"
+ # ignore
+ else
+ FileUtils.cp(source_path, dest_path, :preserve => true)
+ end
+ end
+ end
+ end
+end
+
+dest_dir.find do |dest_path|
+ if dest_path.directory? and /\A_/ =~ dest_path.basename.to_s
+ normalized_dest_path = dest_path + ".."
+ normalized_dest_path += dest_path.basename.to_s.gsub(/\A_/, '')
+ FileUtils.mv(dest_path, normalized_dest_path)
+ end
+end
diff --git a/storage/mroonga/tools/travis/before_script.sh b/storage/mroonga/tools/travis/before_script.sh
new file mode 100755
index 00000000..a6491d0c
--- /dev/null
+++ b/storage/mroonga/tools/travis/before_script.sh
@@ -0,0 +1,95 @@
+#!/bin/bash
+#
+# Copyright(C) 2012-2016 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-1335 USA
+
+# set -x
+set -e
+
+if [ "${MROONGA_BUNDLED}" = "yes" ]; then
+ cmake_args=(-DCMAKE_BUILD_TYPE=Debug -DWITH_UNIT_TESTS=FALSE)
+ cmake_args=("${cmake_args[@]}" -DWITH_EMBEDDED_SERVER=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_ARCHIVE=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_BLACKHOLE=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_CONNECT=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_CSV=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_EXAMPLE=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_FEDERATED=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_FEDERATEDX=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_HEAP=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_MYISAMMRG=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_OQGRAPH=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_SEQUENCE=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_SPHINX=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_SPIDER=TRUE)
+ cmake_args=("${cmake_args[@]}" -DWITHOUT_TEST_SQL_DISCOVERY=TRUE)
+ if [ "${MROONGA_TEST_EMBEDDED}" = "yes" ]; then
+ cmake_args=("${cmake_args[@]}" -DWITH_EMBEDDED_SERVER=TRUE)
+ cmake_args=("${cmake_args[@]}" -DMRN_BUILD_FOR_EMBEDDED_SERVER=TRUE)
+ fi
+ cmake . "${cmake_args[@]}"
+else
+ ./autogen.sh
+
+ if [ -d /opt/mysql/ ]; then
+ PATH=$(echo /opt/mysql/server-*/bin/):$PATH
+ fi
+ configure_args=("--with-mysql-source=$PWD/vendor/mysql")
+ case "${MYSQL_VERSION}" in
+ mysql-5.6)
+ configure_args=("${configure_args[@]}" --enable-fast-mutexes)
+ ;;
+ mysql-5.7)
+ boost_archive=boost_1_59_0.tar.gz
+ curl -L -O http://downloads.sourceforge.net/project/boost/boost/1.59.0/${boost_archive}
+ sudo mkdir -p /usr/global/share
+ sudo mv ${boost_archive} /usr/global/share/
+ (cd vendor/mysql && sudo debian/rules override_dh_auto_configure)
+ ;;
+ mariadb-5.5)
+ (cd vendor/mysql && sudo debian/rules configure)
+ configure_args=("${configure_args[@]}"
+ "--with-mysql-build=$PWD/vendor/mysql/builddir")
+ ;;
+ percona-server-5.6)
+ (cd vendor/mysql && \
+ sudo debian/rules configure SKIP_DEBUG_BINARY=yes && \
+ cd builddir/libservices && \
+ sudo make > /dev/null && \
+ cd ../extra && \
+ sudo make > /dev/null)
+ configure_args=("${configure_args[@]}"
+ "--enable-fast-mutexes"
+ "--with-mysql-build=$PWD/vendor/mysql/builddir"
+ "--with-mysql-config=$PWD/vendor/mysql/builddir/scripts/mysql_config")
+ ;;
+ percona-server-5.7)
+ (cd vendor/mysql && \
+ sudo debian/rules override_dh_auto_configure SKIP_DEBUG_BINARY=yes && \
+ cd builddir/libservices && \
+ sudo make > /dev/null && \
+ cd ../extra && \
+ sudo make > /dev/null)
+ configure_args=("${configure_args[@]}"
+ "--with-mysql-build=$PWD/vendor/mysql/builddir"
+ "--with-mysql-config=$PWD/vendor/mysql/builddir/scripts/mysql_config")
+ ;;
+ *)
+ :
+ ;;
+ esac
+ ./configure "${configure_args[@]}"
+fi
diff --git a/storage/mroonga/tools/travis/install.sh b/storage/mroonga/tools/travis/install.sh
new file mode 100755
index 00000000..2c8cdbb8
--- /dev/null
+++ b/storage/mroonga/tools/travis/install.sh
@@ -0,0 +1,157 @@
+#!/bin/sh
+#
+# Copyright(C) 2012-2017 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-1335 USA
+
+set -x
+set -e
+
+# export GROONGA_MASTER=yes
+# export GROONGA_NORMALIZER_MYSQL_MASTER=yes
+
+#mariadb_download_base=http://mirror.jmu.edu/pub/mariadb
+mariadb_download_base=http://ftp.osuosl.org/pub/mariadb
+
+version=$(echo "$MYSQL_VERSION" | sed -r -e 's/^(mysql|mariadb|percona-server)-//')
+series=$(echo "$version" | sed -r -e 's/^([0-9]+\.[0-9]+).*$/\1/g')
+
+setup_mariadb_apt()
+{
+ distribution=$(lsb_release --short --id | tr 'A-Z' 'a-z')
+ code_name=$(lsb_release --short --codename)
+ component=main
+ apt_url_base="${mariadb_download_base}/repo/${series}"
+ cat <<EOF | sudo tee /etc/apt/sources.list.d/mariadb.list
+deb ${apt_url_base}/${distribution}/ ${code_name} ${component}
+deb-src ${apt_url_base}/${distribution}/ ${code_name} ${component}
+EOF
+ sudo apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db
+ sudo apt-get -qq update
+}
+
+setup_percona_apt()
+{
+ code_name=$(lsb_release --short --codename)
+ release_deb_version=0.1-4
+ release_deb=percona-release_${release_deb_version}.${code_name}_all.deb
+ wget http://www.percona.com/downloads/percona-release/ubuntu/${release_deb_version}/${release_deb}
+ sudo dpkg -i ${release_deb}
+ sudo apt-get -qq update
+}
+
+if [ "${MROONGA_BUNDLED}" = "yes" ]; then
+ mkdir -p .mroonga
+ mv * .mroonga/
+ mv .mroonga/tools ./
+ setup_mariadb_apt
+ sudo apt-get -qq -y build-dep mariadb-server
+ # Support MariaDB for now.
+ download_base=${mariadb_download_base}/${MYSQL_VERSION}
+ tar_gz=${MYSQL_VERSION}.tar.gz
+ curl -O ${download_base}/source/${tar_gz}
+ tar xzf $tar_gz
+ mv ${MYSQL_VERSION}/* ./
+ rm -rf storage/mroonga
+ mv .mroonga storage/mroonga
+ rm -rf ${MYSQL_VERSION}
+ git clone --recursive --depth 1 \
+ https://github.com/groonga/groonga.git \
+ storage/mroonga/vendor/groonga
+ git clone --recursive --depth 1 \
+ https://github.com/groonga/groonga-normalizer-mysql.git \
+ storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql
+else
+ curl --silent --location \
+ https://raw.githubusercontent.com/groonga/groonga/master/data/travis/setup.sh | sh
+ curl --silent --location \
+ https://raw.githubusercontent.com/groonga/groonga-normalizer-mysql/master/data/travis/setup.sh | sh
+ # curl --silent --location \
+ # https://raw.githubusercontent.com/clear-code/cutter/master/data/travis/setup.sh | sh
+
+ if [ ! -f /usr/lib/groonga/plugins/tokenizers/mecab.so ]; then
+ sudo apt-get -qq -y install groonga-tokenizer-mecab
+ fi
+
+ mkdir -p vendor
+ cd vendor
+
+ case "$MYSQL_VERSION" in
+ mysql-*)
+ sudo apt-get -qq update
+ sudo apt-get -qq -y build-dep mysql-server
+ if [ "$version" = "system" ]; then
+ sudo apt-get -y remove --purge \
+ mysql-server-5.6 \
+ mysql-server-core-5.6 \
+ mysql-client-5.6 \
+ mysql-client-core-5.6
+ sudo rm -rf /var/lib/mysql
+ sudo apt-get -y install \
+ mysql-server \
+ mysql-client \
+ mysql-testsuite \
+ libmysqld-dev
+ apt-get source mysql-server
+ ln -s $(find . -maxdepth 1 -type d | sort | tail -1) mysql
+ else
+ repository_deb=mysql-apt-config_0.8.3-1_all.deb
+ curl -O http://repo.mysql.com/${repository_deb}
+ sudo env MYSQL_SERVER_VERSION=mysql-${series} \
+ dpkg -i ${repository_deb}
+ sudo apt-get -qq update
+ sudo apt-get -qq -y remove --purge mysql-common
+ sudo apt-get -qq -y build-dep mysql-server
+ sudo apt-get -qq -y install \
+ mysql-server \
+ libmysqlclient-dev \
+ libmysqld-dev \
+ mysql-testsuite
+ apt-get -qq source mysql-server
+ ln -s $(find . -maxdepth 1 -type d | sort | tail -1) mysql
+ fi
+ ;;
+ mariadb-*)
+ sudo apt-get -y remove --purge \
+ mysql-server-5.6 \
+ mysql-server-core-5.6 \
+ mysql-client-5.6 \
+ mysql-client-core-5.6 \
+ mysql-common
+ sudo rm -rf /var/lib/mysql
+ setup_mariadb_apt
+ sudo apt-get -qq -y build-dep mariadb-server
+ sudo apt-get -y install \
+ mariadb-server \
+ mariadb-client \
+ mariadb-test \
+ libmariadbclient-dev
+ apt-get source mariadb-server
+ ln -s $(find . -maxdepth 1 -type d | sort | tail -1) mysql
+ ;;
+ percona-server-*)
+ setup_percona_apt
+ sudo apt-get -qq -y build-dep percona-server-server-${series}
+ sudo apt-get -qq -y install \
+ percona-server-server-${series} \
+ percona-server-client-${series} \
+ percona-server-test-${series}
+ apt-get -qq source percona-server-server-${series}
+ ln -s $(find . -maxdepth 1 -type d | sort | tail -1) mysql
+ ;;
+ esac
+
+ cd ..
+fi
diff --git a/storage/mroonga/tools/travis/script.sh b/storage/mroonga/tools/travis/script.sh
new file mode 100755
index 00000000..1c0121e0
--- /dev/null
+++ b/storage/mroonga/tools/travis/script.sh
@@ -0,0 +1,136 @@
+#!/bin/bash
+#
+# Copyright(C) 2012-2016 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-1335 USA
+
+# set -x
+set -e
+
+base_dir="$(cd $(dirname $0); pwd)"
+top_dir="${base_dir}/../.."
+
+bundled_mroonga_dir="${top_dir}/storage/mroonga"
+if [ -f "${bundled_mroonga_dir}/config.sh" ]; then
+ mroonga_dir="${bundled_mroonga_dir}"
+ . "${bundled_mroonga_dir}/config.sh"
+else
+ mroonga_dir="${top_dir}"
+ . "${top_dir}/config.sh"
+fi
+
+n_processors="$(grep '^processor' /proc/cpuinfo | wc -l)"
+if [ "${MROONGA_BUNDLED}" = "yes" ]; then
+ max_n_processors=2
+else
+ max_n_processors=4
+fi
+if (( $n_processors > $max_n_processors )); then
+ n_processors=$max_n_processors
+fi
+
+build()
+{
+ make -j${n_processors} > /dev/null
+}
+
+run_unit_test()
+{
+ if [ "${MROONGA_BUNDLED}" != "yes" ]; then
+ NO_MAKE=yes ${mroonga_dir}/test/run-unit-test.sh
+ fi
+}
+
+prepare_mysql_test_dir()
+{
+ mysql_test_dir=/usr/mysql-test
+ if [ -d /usr/lib/mysql-testsuite/ ]; then
+ sudo cp -a /usr/lib/mysql-testsuite/ ${mysql_test_dir}/
+ elif [ -d /usr/lib/mysql-test/ ]; then
+ sudo cp -a /usr/lib/mysql-test/ ${mysql_test_dir}/
+ elif [ -d /usr/share/mysql/mysql-test/ ]; then
+ sudo cp -a /usr/share/mysql/mysql-test/ ${mysql_test_dir}/
+ elif [ -d /usr/share/mysql-test/ ]; then
+ sudo cp -a /usr/share/mysql-test/ ${mysql_test_dir}/
+ elif [ -d /opt/mysql/ ]; then
+ mysql_test_dir=$(echo /opt/mysql/server-*/mysql-test)
+ else
+ sudo cp -a ${MYSQL_SOURCE_DIR}/mysql-test/ ${mysql_test_dir}/
+ fi
+ sudo chown -R $(id -u):$(id -g) ${mysql_test_dir}/
+
+ cp -a ${mroonga_dir}/mysql-test/mroonga/ ${mysql_test_dir}/suite/
+}
+
+collect_test_suite_names()
+{
+ cd ${mysql_test_dir}/suite/
+ test_suite_names=""
+ for test_suite_name in $(find mroonga -type d '!' -name '[tr]'); do
+ if [ -n "${test_suite_names}" ]; then
+ test_suite_names="${test_suite_names},"
+ fi
+ test_suite_names="${test_suite_names}${test_suite_name}"
+ done
+ cd -
+}
+
+prepare_sql_test()
+{
+ sudo make install > /dev/null
+ prepare_mysql_test_dir
+ collect_test_suite_names
+}
+
+run_sql_test()
+{
+ test_args=()
+ if [ "${MROONGA_TEST_EMBEDDED}" = "yes" ]; then
+ test_args=("${test_args[@]}" "--embedded-server")
+ fi
+ if [ "${MROONGA_TEST_PS_PROTOCOL}" = "yes" ]; then
+ test_args=("${test_args[@]}" "--ps-protocol")
+ fi
+
+ if [ "${MROONGA_BUNDLED}" = "yes" ]; then
+ # Plugins aren't supported.
+ cd ${mroonga_dir}/mysql-test/mroonga/storage
+ rm -rf alter_table/add_index/token_filters/
+ rm -rf alter_table/t/change_token_filter.test
+ rm -rf create/table/token_filters/
+ rm -rf fulltext/token_filters/
+ cd -
+
+ ${mroonga_dir}/test/run-sql-test.sh \
+ "${test_args[@]}" \
+ --parallel="${n_processors}" \
+ --retry=3
+ else
+ prepare_sql_test
+
+ cd ${mysql_test_dir}/
+ perl ./mysql-test-run.pl \
+ "${test_args[@]}" \
+ --no-check-testcases \
+ --parallel="${n_processors}" \
+ --retry=3 \
+ --suite="${test_suite_names}" \
+ --force
+ fi
+}
+
+build
+# run_unit_test
+run_sql_test
diff --git a/storage/mroonga/tools/upload-to-github.rb b/storage/mroonga/tools/upload-to-github.rb
new file mode 100755
index 00000000..572d65c3
--- /dev/null
+++ b/storage/mroonga/tools/upload-to-github.rb
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+
+if ARGV.size < 1
+ puts "Usage: #{$0} USER FILE ..."
+ puts " e.g.: #{$0} kou mroonga-1.10.tar.gz ..."
+ exit false
+end
+
+require "rubygems"
+require "github_api"
+require "mime/types"
+
+user, *files = *ARGV
+
+print "password[#{user}]: "
+system("stty -echo")
+password = STDIN.gets.chomp
+system("stty echo")
+puts
+
+github = Github.new(:login => user, :password => password)
+files.each do |file|
+ content_type = MIME::Types.type_for(file)[0].to_s
+ resource = github.repos.downloads.create("mroonga", "mroonga",
+ :name => File.basename(file),
+ :size => File.size(file),
+ :description => File.basename(file),
+ :content_type => content_type)
+ p resource
+
+ system("curl",
+ "-F", "key=#{resource.path}",
+ "-F", "acl=#{resource.acl}",
+ "-F", "success_action_status=201",
+ "-F", "Filename=#{resource.name}",
+ "-F", "AWSAccessKeyId=#{resource.accesskeyid}",
+ "-F", "Policy=#{resource.policy}",
+ "-F", "Signature=#{resource.signature}",
+ "-F", "Content-Type=#{resource.mime_type}",
+ "-F", "file=@#{file}",
+ resource.s3_url)
+end
diff --git a/storage/mroonga/udf/Makefile.am b/storage/mroonga/udf/Makefile.am
new file mode 100644
index 00000000..f3c2966f
--- /dev/null
+++ b/storage/mroonga/udf/Makefile.am
@@ -0,0 +1,10 @@
+AM_CPPFLAGS = \
+ $(MYSQL_INCLUDES) \
+ $(GROONGA_CFLAGS) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/lib
+
+noinst_LTLIBRARIES = \
+ libmrn_udf.la
+
+include sources.am
diff --git a/storage/mroonga/udf/mrn_udf_command.cpp b/storage/mroonga/udf/mrn_udf_command.cpp
new file mode 100644
index 00000000..10123c62
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_command.cpp
@@ -0,0 +1,294 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_path_mapper.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_current_thread.hpp>
+
+#include <sql_table.h>
+
+MRN_BEGIN_DECLS
+
+extern mrn::DatabaseManager *mrn_db_manager;
+extern mrn::ContextPool *mrn_context_pool;
+
+struct CommandInfo
+{
+ grn_ctx *ctx;
+ grn_obj *db;
+ bool use_shared_db;
+ grn_obj command;
+ String result;
+};
+
+MRN_API my_bool mroonga_command_init(UDF_INIT *init, UDF_ARGS *args,
+ char *message)
+{
+ CommandInfo *info = NULL;
+
+ init->ptr = NULL;
+ if (args->arg_count == 0) {
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): Wrong number of arguments: %u for 1..",
+ args->arg_count);
+ goto error;
+ }
+
+ if ((args->arg_count % 2) == 0) {
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): The number of arguments must be odd: %u",
+ args->arg_count);
+ goto error;
+ }
+
+ for (unsigned int i = 0; i < args->arg_count; ++i) {
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ // OK
+ break;
+ case REAL_RESULT:
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): Argument must be string: <%g>",
+ *reinterpret_cast<double *>(args->args[i]));
+ goto error;
+ break;
+ case INT_RESULT:
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): Argument must be string: <%lld>",
+ *reinterpret_cast<longlong *>(args->args[i]));
+ goto error;
+ break;
+ case DECIMAL_RESULT:
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): Argument must be string: <%.*s>",
+ static_cast<int>(args->lengths[i]),
+ args->args[i]);
+ goto error;
+ break;
+ default:
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): Argument must be string: <%d>(%u)",
+ args->arg_type[i],
+ i);
+ goto error;
+ break;
+ }
+ }
+ init->maybe_null = 1;
+ init->const_item = 0;
+
+ info = (CommandInfo *)mrn_my_malloc(sizeof(CommandInfo),
+ MYF(MY_WME | MY_ZEROFILL));
+ if (!info) {
+ strcpy(message, "mroonga_command(): out of memory");
+ goto error;
+ }
+
+ info->ctx = mrn_context_pool->pull();
+ {
+ const char *current_db_path = MRN_THD_DB_PATH(current_thd);
+ const char *action;
+ if (current_db_path) {
+ action = "open database";
+ char encoded_db_path[FN_REFLEN + 1];
+ uint encoded_db_path_length =
+ tablename_to_filename(current_db_path,
+ encoded_db_path,
+ sizeof(encoded_db_path));
+ encoded_db_path[encoded_db_path_length] = '\0';
+ mrn::Database *db;
+ int error = mrn_db_manager->open(encoded_db_path, &db);
+ if (error == 0) {
+ info->db = db->get();
+ grn_ctx_use(info->ctx, info->db);
+ info->use_shared_db = true;
+ }
+ } else {
+ action = "create anonymous database";
+ info->db = grn_db_create(info->ctx, NULL, NULL);
+ info->use_shared_db = false;
+ }
+ if (!info->db) {
+ grn_snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_command(): failed to %s: %s",
+ action,
+ info->ctx->errbuf);
+ goto error;
+ }
+ }
+ GRN_TEXT_INIT(&(info->command), 0);
+
+ init->ptr = (char *)info;
+
+ return FALSE;
+
+error:
+ if (info) {
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+ return TRUE;
+}
+
+static void mroonga_command_escape_value(grn_ctx *ctx,
+ grn_obj *command,
+ const char *value,
+ unsigned long value_length)
+{
+ GRN_TEXT_PUTC(ctx, command, '"');
+
+ const char *value_current = value;
+ const char *value_end = value_current + value_length;
+ while (value_current < value_end) {
+ int char_length = grn_charlen(ctx, value_current, value_end);
+
+ if (char_length == 0) {
+ break;
+ } else if (char_length == 1) {
+ switch (*value_current) {
+ case '\\':
+ case '"':
+ GRN_TEXT_PUTC(ctx, command, '\\');
+ GRN_TEXT_PUTC(ctx, command, *value_current);
+ break;
+ case '\n':
+ GRN_TEXT_PUTS(ctx, command, "\\n");
+ break;
+ default:
+ GRN_TEXT_PUTC(ctx, command, *value_current);
+ break;
+ }
+ } else {
+ GRN_TEXT_PUT(ctx, command, value_current, char_length);
+ }
+
+ value_current += char_length;
+ }
+
+ GRN_TEXT_PUTC(ctx, command, '"');
+}
+
+MRN_API char *mroonga_command(UDF_INIT *init, UDF_ARGS *args, char *result,
+ unsigned long *length, char *is_null, char *error)
+{
+ CommandInfo *info = (CommandInfo *)init->ptr;
+ grn_ctx *ctx = info->ctx;
+ int flags = 0;
+
+ if (!args->args[0]) {
+ *is_null = 1;
+ return NULL;
+ }
+
+ GRN_BULK_REWIND(&(info->command));
+ GRN_TEXT_PUT(ctx, &(info->command), args->args[0], args->lengths[0]);
+ for (unsigned int i = 1; i < args->arg_count; i += 2) {
+ if (!args->args[i] || !args->args[i + 1]) {
+ *is_null = 1;
+ return NULL;
+ }
+
+ const char *name = args->args[i];
+ unsigned long name_length = args->lengths[i];
+ GRN_TEXT_PUTS(ctx, &(info->command), " --");
+ GRN_TEXT_PUT(ctx, &(info->command), name, name_length);
+
+ const char *value = args->args[i + 1];
+ unsigned long value_length = args->lengths[i + 1];
+ GRN_TEXT_PUTS(ctx, &(info->command), " ");
+ mroonga_command_escape_value(ctx, &(info->command), value, value_length);
+ }
+
+ *is_null = 0;
+
+ grn_ctx_send(ctx,
+ GRN_TEXT_VALUE(&(info->command)),
+ GRN_TEXT_LEN(&(info->command)),
+ 0);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ goto error;
+ }
+
+ info->result.length(0);
+ do {
+ char *buffer;
+ unsigned int buffer_length;
+ grn_ctx_recv(ctx, &buffer, &buffer_length, &flags);
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_READ, ctx->errbuf, MYF(0));
+ goto error;
+ }
+ if (buffer_length > 0) {
+ if (info->result.reserve(buffer_length)) {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0), HA_ERR_OUT_OF_MEM);
+ goto error;
+ }
+ info->result.q_append(buffer, buffer_length);
+ }
+ } while (flags & GRN_CTX_MORE);
+
+ *length = info->result.length();
+ return (char *)(info->result.ptr());
+
+error:
+ *error = 1;
+ return NULL;
+}
+
+MRN_API void mroonga_command_deinit(UDF_INIT *init)
+{
+ CommandInfo *info = (CommandInfo *)init->ptr;
+ if (info) {
+ GRN_OBJ_FIN(info->ctx, &(info->command));
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ MRN_STRING_FREE(info->result);
+ my_free(info);
+ }
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_escape.cpp b/storage/mroonga/udf/mrn_udf_escape.cpp
new file mode 100644
index 00000000..72182790
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_escape.cpp
@@ -0,0 +1,245 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2013-2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_path_mapper.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_context_pool.hpp>
+
+MRN_BEGIN_DECLS
+
+extern mrn::ContextPool *mrn_context_pool;
+
+struct EscapeInfo
+{
+ grn_ctx *ctx;
+ bool script_mode;
+ grn_obj target_characters;
+ grn_obj escaped_value;
+};
+
+MRN_API my_bool mroonga_escape_init(UDF_INIT *init, UDF_ARGS *args,
+ char *message)
+{
+ EscapeInfo *info = NULL;
+ bool script_mode = false;
+
+ init->ptr = NULL;
+ if (!(1 <= args->arg_count && args->arg_count <= 2)) {
+ snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_escape(): Incorrect number of arguments: %u for 1..2",
+ args->arg_count);
+ goto error;
+ }
+
+ if (args->attribute_lengths[0] == strlen("script") &&
+ strncmp(args->attributes[0], "script", strlen("script")) == 0) {
+ switch (args->arg_type[0]) {
+ case ROW_RESULT:
+ snprintf(message,
+ MYSQL_ERRMSG_SIZE,
+ "mroonga_escape(): "
+ "The 1st script argument must be "
+ "string, integer or floating point: <row>");
+ goto error;
+ break;
+ default:
+ break;
+ }
+ script_mode = true;
+ } else {
+ if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_escape(): The 1st query argument must be string");
+ goto error;
+ }
+ }
+ if (args->arg_count == 2) {
+ if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_escape(): "
+ "The 2st argument must be escape target characters as string");
+ goto error;
+ }
+ }
+
+ init->maybe_null = 1;
+
+ info = static_cast<EscapeInfo *>(mrn_my_malloc(sizeof(EscapeInfo),
+ MYF(MY_WME | MY_ZEROFILL)));
+ if (!info) {
+ strcpy(message, "mroonga_escape(): out of memory");
+ goto error;
+ }
+
+ info->ctx = mrn_context_pool->pull();
+ info->script_mode = script_mode;
+ GRN_TEXT_INIT(&(info->target_characters), 0);
+ GRN_TEXT_INIT(&(info->escaped_value), 0);
+
+ init->ptr = reinterpret_cast<char *>(info);
+
+ return FALSE;
+
+error:
+ if (info) {
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+ return TRUE;
+}
+
+static void escape(EscapeInfo *info, UDF_ARGS *args)
+{
+ grn_ctx *ctx = info->ctx;
+
+ GRN_BULK_REWIND(&(info->escaped_value));
+ if (info->script_mode) {
+ switch (args->arg_type[0]) {
+ case STRING_RESULT:
+ {
+ char *value = args->args[0];
+ unsigned long value_length = args->lengths[0];
+ GRN_TEXT_PUTC(ctx, &(info->escaped_value), '"');
+ if (args->arg_count == 2) {
+ grn_obj special_characters;
+ GRN_TEXT_INIT(&special_characters, 0);
+ GRN_TEXT_PUT(ctx,
+ &special_characters,
+ args->args[1],
+ args->lengths[1]);
+ GRN_TEXT_PUTC(ctx, &special_characters, '\0');
+ grn_expr_syntax_escape(ctx,
+ value,
+ value_length,
+ GRN_TEXT_VALUE(&special_characters),
+ '\\',
+ &(info->escaped_value));
+ GRN_OBJ_FIN(ctx, &special_characters);
+ } else {
+ const char *special_characters = "\"\\";
+ grn_expr_syntax_escape(ctx,
+ value,
+ value_length,
+ special_characters,
+ '\\',
+ &(info->escaped_value));
+ }
+ GRN_TEXT_PUTC(ctx, &(info->escaped_value), '"');
+ }
+ break;
+ case REAL_RESULT:
+ {
+ double value = *reinterpret_cast<double *>(args->args[0]);
+ grn_text_ftoa(ctx, &(info->escaped_value), value);
+ }
+ break;
+ case INT_RESULT:
+ {
+ longlong value = *reinterpret_cast<longlong *>(args->args[0]);
+ grn_text_lltoa(ctx, &(info->escaped_value), value);
+ }
+ break;
+ case DECIMAL_RESULT:
+ {
+ grn_obj value_raw;
+ GRN_TEXT_INIT(&value_raw, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, &value_raw, args->args[0], args->lengths[0]);
+ grn_obj value;
+ GRN_FLOAT_INIT(&value, 0);
+ if (grn_obj_cast(ctx, &value_raw, &value, GRN_FALSE) == GRN_SUCCESS) {
+ grn_text_ftoa(ctx, &(info->escaped_value), GRN_FLOAT_VALUE(&value));
+ } else {
+ GRN_TEXT_PUT(ctx,
+ &(info->escaped_value),
+ args->args[0],
+ args->lengths[0]);
+ }
+ GRN_OBJ_FIN(ctx, &value);
+ GRN_OBJ_FIN(ctx, &value_raw);
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ char *query = args->args[0];
+ unsigned long query_length = args->lengths[0];
+ if (args->arg_count == 2) {
+ char *target_characters = args->args[1];
+ unsigned long target_characters_length = args->lengths[1];
+ GRN_TEXT_PUT(ctx, &(info->target_characters),
+ target_characters,
+ target_characters_length);
+ GRN_TEXT_PUTC(ctx, &(info->target_characters), '\0');
+ grn_expr_syntax_escape(ctx, query, query_length,
+ GRN_TEXT_VALUE(&(info->target_characters)),
+ GRN_QUERY_ESCAPE,
+ &(info->escaped_value));
+ } else {
+ grn_expr_syntax_escape_query(ctx, query, query_length,
+ &(info->escaped_value));
+ }
+ }
+}
+
+MRN_API char *mroonga_escape(UDF_INIT *init, UDF_ARGS *args, char *result,
+ unsigned long *length, char *is_null, char *error)
+{
+ EscapeInfo *info = reinterpret_cast<EscapeInfo *>(init->ptr);
+ grn_ctx *ctx = info->ctx;
+
+ if (!args->args[0]) {
+ *is_null = 1;
+ return NULL;
+ }
+
+ *is_null = 0;
+
+ escape(info, args);
+
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ goto error;
+ }
+
+ *length = GRN_TEXT_LEN(&(info->escaped_value));
+ return GRN_TEXT_VALUE(&(info->escaped_value));
+
+error:
+ *error = 1;
+ return NULL;
+}
+
+MRN_API void mroonga_escape_deinit(UDF_INIT *init)
+{
+ EscapeInfo *info = reinterpret_cast<EscapeInfo *>(init->ptr);
+ if (info) {
+ grn_obj_unlink(info->ctx, &(info->target_characters));
+ grn_obj_unlink(info->ctx, &(info->escaped_value));
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_highlight_html.cpp b/storage/mroonga/udf/mrn_udf_highlight_html.cpp
new file mode 100644
index 00000000..12f54a7d
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_highlight_html.cpp
@@ -0,0 +1,494 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_err.h>
+#include <mrn_encoding.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_table.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_query_parser.hpp>
+#include <mrn_current_thread.hpp>
+
+MRN_BEGIN_DECLS
+
+extern mrn::DatabaseManager *mrn_db_manager;
+extern mrn::ContextPool *mrn_context_pool;
+
+typedef struct st_mrn_highlight_html_info
+{
+ grn_ctx *ctx;
+ grn_obj *db;
+ bool use_shared_db;
+ grn_obj *keywords;
+ String result_str;
+ struct {
+ bool used;
+ grn_obj *table;
+ grn_obj *default_column;
+ } query_mode;
+} mrn_highlight_html_info;
+
+static my_bool mrn_highlight_html_prepare(mrn_highlight_html_info *info,
+ UDF_ARGS *args,
+ char *message,
+ grn_obj **keywords)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ grn_ctx *ctx = info->ctx;
+ const char *normalizer_name = "NormalizerAuto";
+ grn_obj *expr = NULL;
+ String *result_str = &(info->result_str);
+
+ *keywords = NULL;
+
+ mrn::encoding::set_raw(ctx, system_charset_info);
+ if (system_charset_info->state & (MY_CS_BINSORT | MY_CS_CSSORT)) {
+ normalizer_name = NULL;
+ }
+
+ *keywords = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_PAT_KEY,
+ grn_ctx_at(ctx, GRN_DB_SHORT_TEXT),
+ NULL);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): "
+ "failed to create grn_pat for keywords: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+ if (normalizer_name) {
+ grn_obj_set_info(ctx,
+ *keywords,
+ GRN_INFO_NORMALIZER,
+ grn_ctx_get(ctx, normalizer_name, -1));
+ }
+
+ if (info->query_mode.used) {
+ if (!info->query_mode.table) {
+ grn_obj *short_text;
+ short_text = grn_ctx_at(info->ctx, GRN_DB_SHORT_TEXT);
+ info->query_mode.table = grn_table_create(info->ctx,
+ NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY,
+ short_text,
+ NULL);
+ }
+ if (!info->query_mode.default_column) {
+ info->query_mode.default_column =
+ grn_obj_column(info->ctx,
+ info->query_mode.table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ }
+
+ grn_obj *record = NULL;
+ GRN_EXPR_CREATE_FOR_QUERY(info->ctx, info->query_mode.table, expr, record);
+ if (!expr) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): "
+ "failed to create expression: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+
+ mrn::QueryParser query_parser(info->ctx,
+ current_thd,
+ expr,
+ info->query_mode.default_column,
+ 0,
+ NULL);
+ grn_rc rc = query_parser.parse(args->args[1], args->lengths[1]);
+ if (rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): "
+ "failed to parse query: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+
+ {
+ grn_obj extracted_keywords;
+ GRN_PTR_INIT(&extracted_keywords, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_expr_get_keywords(ctx, expr, &extracted_keywords);
+
+ size_t n_keywords =
+ GRN_BULK_VSIZE(&extracted_keywords) / sizeof(grn_obj *);
+ for (size_t i = 0; i < n_keywords; ++i) {
+ grn_obj *extracted_keyword = GRN_PTR_VALUE_AT(&extracted_keywords, i);
+ grn_table_add(ctx,
+ *keywords,
+ GRN_TEXT_VALUE(extracted_keyword),
+ GRN_TEXT_LEN(extracted_keyword),
+ NULL);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): "
+ "failed to add a keyword: <%.*s>: <%s>",
+ static_cast<int>(GRN_TEXT_LEN(extracted_keyword)),
+ GRN_TEXT_VALUE(extracted_keyword),
+ ctx->errbuf);
+ GRN_OBJ_FIN(ctx, &extracted_keywords);
+ }
+ goto error;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &extracted_keywords);
+ }
+ } else {
+ for (unsigned int i = 1; i < args->arg_count; ++i) {
+ if (!args->args[i]) {
+ continue;
+ }
+ grn_table_add(ctx,
+ *keywords,
+ args->args[i],
+ args->lengths[i],
+ NULL);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): "
+ "failed to add a keyword: <%.*s>: <%s>",
+ static_cast<int>(args->lengths[i]),
+ args->args[i],
+ ctx->errbuf);
+ }
+ goto error;
+ }
+ }
+ }
+
+ result_str->set_charset(system_charset_info);
+ DBUG_RETURN(FALSE);
+
+error:
+ if (expr) {
+ grn_obj_close(ctx, expr);
+ }
+ if (*keywords) {
+ grn_obj_close(ctx, *keywords);
+ }
+ DBUG_RETURN(TRUE);
+}
+
+MRN_API my_bool mroonga_highlight_html_init(UDF_INIT *init,
+ UDF_ARGS *args,
+ char *message)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn_highlight_html_info *info = NULL;
+
+ init->ptr = NULL;
+
+ if (args->arg_count < 1) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): wrong number of arguments: %u for 1+",
+ args->arg_count);
+ goto error;
+ }
+
+
+ for (unsigned int i = 0; i < args->arg_count; ++i) {
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ /* OK */
+ break;
+ case REAL_RESULT:
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): all arguments must be string: "
+ "<%u>=<%g>",
+ i, *((double *)(args->args[i])));
+ goto error;
+ break;
+ case INT_RESULT:
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): all arguments must be string: "
+ "<%u>=<%lld>",
+ i, *((longlong *)(args->args[i])));
+ goto error;
+ break;
+ default:
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): all arguments must be string: <%u>",
+ i);
+ goto error;
+ break;
+ }
+ }
+
+ init->maybe_null = 0;
+
+ info =
+ reinterpret_cast<mrn_highlight_html_info *>(
+ mrn_my_malloc(sizeof(mrn_highlight_html_info),
+ MYF(MY_WME | MY_ZEROFILL)));
+ if (!info) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_highlight_html(): failed to allocate memory");
+ goto error;
+ }
+
+ info->ctx = mrn_context_pool->pull();
+ {
+ const char *current_db_path = MRN_THD_DB_PATH(current_thd);
+ const char *action;
+ if (current_db_path) {
+ action = "open database";
+ mrn::Database *db;
+ int error = mrn_db_manager->open(current_db_path, &db);
+ if (error == 0) {
+ info->db = db->get();
+ grn_ctx_use(info->ctx, info->db);
+ info->use_shared_db = true;
+ }
+ } else {
+ action = "create anonymous database";
+ info->db = grn_db_create(info->ctx, NULL, NULL);
+ info->use_shared_db = false;
+ }
+ if (!info->db) {
+ sprintf(message,
+ "mroonga_highlight_html(): failed to %s: %s",
+ action,
+ info->ctx->errbuf);
+ goto error;
+ }
+ }
+
+ info->query_mode.used = FALSE;
+
+ if (args->arg_count == 2 &&
+ args->attribute_lengths[1] == strlen("query") &&
+ strncmp(args->attributes[1], "query", strlen("query")) == 0) {
+ info->query_mode.used = TRUE;
+ info->query_mode.table = NULL;
+ info->query_mode.default_column = NULL;
+ }
+
+ {
+ bool all_keywords_are_constant = TRUE;
+ for (unsigned int i = 1; i < args->arg_count; ++i) {
+ if (!args->args[i]) {
+ all_keywords_are_constant = FALSE;
+ break;
+ }
+ }
+
+ if (all_keywords_are_constant) {
+ if (mrn_highlight_html_prepare(info, args, message, &(info->keywords))) {
+ goto error;
+ }
+ } else {
+ info->keywords = NULL;
+ }
+ }
+
+ init->ptr = (char *)info;
+
+ DBUG_RETURN(FALSE);
+
+error:
+ if (info) {
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+ DBUG_RETURN(TRUE);
+}
+
+static bool highlight_html(grn_ctx *ctx,
+ grn_pat *keywords,
+ const char *target,
+ size_t target_length,
+ String *output)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+
+ {
+ const char *open_tag = "<span class=\"keyword\">";
+ size_t open_tag_length = strlen(open_tag);
+ const char *close_tag = "</span>";
+ size_t close_tag_length = strlen(close_tag);
+
+ while (target_length > 0) {
+#define MAX_N_HITS 16
+ grn_pat_scan_hit hits[MAX_N_HITS];
+ const char *rest;
+ size_t previous = 0;
+ size_t chunk_length;
+
+ int n_hits = grn_pat_scan(ctx,
+ keywords,
+ target,
+ target_length,
+ hits, MAX_N_HITS, &rest);
+ for (int i = 0; i < n_hits; i++) {
+ if ((hits[i].offset - previous) > 0) {
+ grn_text_escape_xml(ctx,
+ &buffer,
+ target + previous,
+ hits[i].offset - previous);
+ }
+ GRN_TEXT_PUT(ctx, &buffer, open_tag, open_tag_length);
+ grn_text_escape_xml(ctx,
+ &buffer,
+ target + hits[i].offset,
+ hits[i].length);
+ GRN_TEXT_PUT(ctx, &buffer, close_tag, close_tag_length);
+ previous = hits[i].offset + hits[i].length;
+ }
+
+ chunk_length = rest - target;
+ if ((chunk_length - previous) > 0) {
+ grn_text_escape_xml(ctx,
+ &buffer,
+ target + previous,
+ target_length - previous);
+ }
+ target_length -= chunk_length;
+ target = rest;
+#undef MAX_N_HITS
+ }
+ }
+
+ if (output->reserve(GRN_TEXT_LEN(&buffer))) {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0), HA_ERR_OUT_OF_MEM);
+ GRN_OBJ_FIN(ctx, &buffer);
+ DBUG_RETURN(false);
+ }
+
+ output->q_append(GRN_TEXT_VALUE(&buffer), GRN_TEXT_LEN(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+ DBUG_RETURN(true);
+}
+
+MRN_API char *mroonga_highlight_html(UDF_INIT *init,
+ UDF_ARGS *args,
+ char *result,
+ unsigned long *length,
+ char *is_null,
+ char *error)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn_highlight_html_info *info =
+ reinterpret_cast<mrn_highlight_html_info *>(init->ptr);
+
+ grn_ctx *ctx = info->ctx;
+ grn_obj *keywords = info->keywords;
+ String *result_str = &(info->result_str);
+
+ if (!args->args[0]) {
+ *is_null = 1;
+ DBUG_RETURN(NULL);
+ }
+
+ if (!keywords) {
+ if (mrn_highlight_html_prepare(info, args, NULL, &keywords)) {
+ goto error;
+ }
+ }
+
+ *is_null = 0;
+ result_str->length(0);
+
+ if (!highlight_html(ctx,
+ reinterpret_cast<grn_pat *>(keywords),
+ args->args[0],
+ args->lengths[0],
+ result_str)) {
+ goto error;
+ }
+
+ if (!info->keywords) {
+ grn_rc rc = grn_obj_close(ctx, keywords);
+ if (rc != GRN_SUCCESS) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+ }
+
+ *length = result_str->length();
+ DBUG_RETURN((char *)result_str->ptr());
+
+error:
+ if (!info->keywords && keywords) {
+ grn_obj_close(ctx, keywords);
+ }
+
+ *is_null = 1;
+ *error = 1;
+
+ DBUG_RETURN(NULL);
+}
+
+MRN_API void mroonga_highlight_html_deinit(UDF_INIT *init)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn_highlight_html_info *info =
+ reinterpret_cast<mrn_highlight_html_info *>(init->ptr);
+ if (!info) {
+ DBUG_VOID_RETURN;
+ }
+
+ if (info->keywords) {
+ grn_obj_close(info->ctx, info->keywords);
+ }
+ if (info->query_mode.used) {
+ if (info->query_mode.default_column) {
+ grn_obj_close(info->ctx, info->query_mode.default_column);
+ }
+ if (info->query_mode.table) {
+ grn_obj_close(info->ctx, info->query_mode.table);
+ }
+ }
+ MRN_STRING_FREE(info->result_str);
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+
+ DBUG_VOID_RETURN;
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_last_insert_grn_id.cpp b/storage/mroonga/udf/mrn_udf_last_insert_grn_id.cpp
new file mode 100644
index 00000000..46176bc8
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_last_insert_grn_id.cpp
@@ -0,0 +1,55 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_windows.hpp>
+#include <mrn_table.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_current_thread.hpp>
+
+MRN_BEGIN_DECLS
+
+MRN_API my_bool last_insert_grn_id_init(UDF_INIT *init, UDF_ARGS *args, char *message)
+{
+ if (args->arg_count != 0) {
+ strcpy(message, "last_insert_grn_id must not have arguments");
+ return 1;
+ }
+ init->maybe_null = 0;
+ return 0;
+}
+
+MRN_API longlong last_insert_grn_id(UDF_INIT *init, UDF_ARGS *args, char *is_null, char *error)
+{
+ THD *thd = current_thd;
+ st_mrn_slot_data *slot_data = mrn_get_slot_data(thd, false);
+ if (slot_data == NULL) {
+ return 0;
+ }
+ longlong last_insert_record_id = slot_data->last_insert_record_id;
+ return last_insert_record_id;
+}
+
+MRN_API void last_insert_grn_id_deinit(UDF_INIT *init)
+{
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_normalize.cpp b/storage/mroonga/udf/mrn_udf_normalize.cpp
new file mode 100644
index 00000000..30362351
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_normalize.cpp
@@ -0,0 +1,212 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2015 Naoya Murakami <naoya@createfield.com>
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_encoding.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_table.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_current_thread.hpp>
+
+MRN_BEGIN_DECLS
+
+extern mrn::DatabaseManager *mrn_db_manager;
+extern mrn::ContextPool *mrn_context_pool;
+
+#define DEFAULT_NORMALIZER_NAME "NormalizerAuto"
+
+struct st_mrn_normalize_info
+{
+ grn_ctx *ctx;
+ grn_obj *db;
+ bool use_shared_db;
+ grn_obj *normalizer;
+ int flags;
+ String result_str;
+};
+
+MRN_API my_bool mroonga_normalize_init(UDF_INIT *init, UDF_ARGS *args,
+ char *message)
+{
+ st_mrn_normalize_info *info = NULL;
+ String *result_str = NULL;
+
+ init->ptr = NULL;
+ if (!(1 <= args->arg_count && args->arg_count <= 2)) {
+ sprintf(message,
+ "mroonga_normalize(): Incorrect number of arguments: %u for 1..2",
+ args->arg_count);
+ goto error;
+ }
+ if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_normalize(): The 1st argument must be query as string");
+ goto error;
+ }
+ if (args->arg_count == 2) {
+ if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_normalize(): "
+ "The 2st argument must be normalizer name as string");
+ goto error;
+ }
+ }
+
+ init->maybe_null = 1;
+
+ info = (st_mrn_normalize_info *)mrn_my_malloc(sizeof(st_mrn_normalize_info),
+ MYF(MY_WME | MY_ZEROFILL));
+ if (!info) {
+ strcpy(message, "mroonga_normalize(): out of memory");
+ goto error;
+ }
+
+ info->ctx = mrn_context_pool->pull();
+ {
+ const char *current_db_path = MRN_THD_DB_PATH(current_thd);
+ const char *action;
+ if (current_db_path) {
+ action = "open database";
+ mrn::Database *db;
+ int error = mrn_db_manager->open(current_db_path, &db);
+ if (error == 0) {
+ info->db = db->get();
+ grn_ctx_use(info->ctx, info->db);
+ info->use_shared_db = true;
+ }
+ } else {
+ action = "create anonymous database";
+ info->db = grn_db_create(info->ctx, NULL, NULL);
+ info->use_shared_db = false;
+ }
+ if (!info->db) {
+ sprintf(message,
+ "mroonga_normalize(): failed to %s: %s",
+ action,
+ info->ctx->errbuf);
+ goto error;
+ }
+ }
+
+ if (args->arg_count == 1) {
+ info->normalizer = grn_ctx_get(info->ctx, DEFAULT_NORMALIZER_NAME, -1);
+ } else {
+ info->normalizer = grn_ctx_get(info->ctx, args->args[1], args->lengths[1]);
+ }
+ if (!info->normalizer) {
+ sprintf(message, "mroonga_normalize(): nonexistent normalizer %.*s",
+ (int)args->lengths[1], args->args[1]);
+ goto error;
+ }
+ info->flags = 0;
+
+ result_str = &(info->result_str);
+ mrn::encoding::set_raw(info->ctx, system_charset_info);
+ result_str->set_charset(system_charset_info);
+
+ init->ptr = (char *)info;
+
+ return FALSE;
+
+error:
+ if (info) {
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+ return TRUE;
+}
+
+MRN_API char *mroonga_normalize(UDF_INIT *init, UDF_ARGS *args, char *result,
+ unsigned long *length, char *is_null, char *error)
+{
+ st_mrn_normalize_info *info = (st_mrn_normalize_info *)init->ptr;
+ grn_ctx *ctx = info->ctx;
+ String *result_str = &(info->result_str);
+
+ if (!args->args[0]) {
+ *is_null = 1;
+ return NULL;
+ }
+
+ result_str->length(0);
+ {
+ char *target = args->args[0];
+ unsigned int target_length = args->lengths[0];
+ grn_obj *grn_string;
+ const char *normalized;
+ unsigned int normalized_length_in_bytes;
+ unsigned int normalized_n_characters;
+
+ grn_string = grn_string_open(ctx,
+ target, target_length,
+ info->normalizer, info->flags);
+ grn_string_get_normalized(ctx, grn_string,
+ &normalized,
+ &normalized_length_in_bytes,
+ &normalized_n_characters);
+ if (result_str->reserve(normalized_length_in_bytes)) {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0), HA_ERR_OUT_OF_MEM);
+ goto error;
+ }
+ result_str->q_append(normalized, normalized_length_in_bytes);
+ result_str->length(normalized_length_in_bytes);
+ grn_obj_unlink(ctx, grn_string);
+ }
+ *is_null = 0;
+
+ if (ctx->rc) {
+ my_message(ER_ERROR_ON_WRITE, ctx->errbuf, MYF(0));
+ goto error;
+ }
+
+ *length = result_str->length();
+ return (char *)result_str->ptr();
+
+error:
+ *is_null = 1;
+ *error = 1;
+ return NULL;
+}
+
+MRN_API void mroonga_normalize_deinit(UDF_INIT *init)
+{
+ st_mrn_normalize_info *info = (st_mrn_normalize_info *)init->ptr;
+
+ if (info) {
+ MRN_STRING_FREE(info->result_str);
+ if (info->normalizer) {
+ grn_obj_unlink(info->ctx, info->normalizer);
+ }
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_query_expand.cpp b/storage/mroonga/udf/mrn_udf_query_expand.cpp
new file mode 100644
index 00000000..03bef321
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_query_expand.cpp
@@ -0,0 +1,282 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_path_mapper.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_current_thread.hpp>
+#include <mrn_query_parser.hpp>
+
+MRN_BEGIN_DECLS
+
+extern mrn::DatabaseManager *mrn_db_manager;
+extern mrn::ContextPool *mrn_context_pool;
+
+namespace mrn {
+ struct QueryExpandInfo {
+ grn_ctx *ctx;
+ grn_obj expanded_query;
+ grn_obj *term_column;
+ grn_obj *expanded_term_column;
+ };
+}
+
+static void mrn_query_expand_info_free(mrn::QueryExpandInfo *info)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ if (!info) {
+ DBUG_VOID_RETURN;
+ }
+
+ if (info->ctx) {
+ GRN_OBJ_FIN(info->ctx, &(info->expanded_query));
+ if (grn_obj_is_accessor(info->ctx, info->expanded_term_column)) {
+ grn_obj_unlink(info->ctx, info->expanded_term_column);
+ }
+ if (grn_obj_is_accessor(info->ctx, info->term_column)) {
+ grn_obj_unlink(info->ctx, info->term_column);
+ }
+ mrn_context_pool->release(info->ctx);
+ }
+ my_free(info);
+
+ DBUG_VOID_RETURN;
+}
+
+MRN_API my_bool mroonga_query_expand_init(UDF_INIT *init,
+ UDF_ARGS *args,
+ char *message)
+{
+ mrn::QueryExpandInfo *info = NULL;
+
+ MRN_DBUG_ENTER_FUNCTION();
+
+ init->ptr = NULL;
+ if (args->arg_count != 4) {
+ sprintf(message,
+ "mroonga_query_expand(): wrong number of arguments: %u for 4",
+ args->arg_count);
+ goto error;
+ }
+ if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_query_expand(): "
+ "the 1st argument must be table name as string");
+ goto error;
+ }
+ if (args->arg_type[1] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_query_expand(): "
+ "the 2nd argument must be term column name as string");
+ goto error;
+ }
+ if (args->arg_type[2] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_query_expand(): "
+ "the 3nd argument must be expanded term column name as string");
+ goto error;
+ }
+ if (args->arg_type[3] != STRING_RESULT) {
+ strcpy(message,
+ "mroonga_query_expand(): "
+ "the 4th argument must be query as string");
+ goto error;
+ }
+
+ init->maybe_null = 1;
+
+ info = static_cast<mrn::QueryExpandInfo *>(
+ mrn_my_malloc(sizeof(mrn::QueryExpandInfo),
+ MYF(MY_WME | MY_ZEROFILL)));
+ if (!info) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): failed to allocate memory");
+ goto error;
+ }
+
+ {
+ const char *current_db_path = MRN_THD_DB_PATH(current_thd);
+ if (!current_db_path) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): no current database");
+ goto error;
+ }
+
+ mrn::Database *db;
+ int error = mrn_db_manager->open(current_db_path, &db);
+ if (error != 0) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): failed to open database: %s",
+ mrn_db_manager->error_message());
+ goto error;
+ }
+ info->ctx = mrn_context_pool->pull();
+ grn_ctx_use(info->ctx, db->get());
+ }
+
+ GRN_TEXT_INIT(&(info->expanded_query), 0);
+
+ {
+ const char *table_name = args->args[0];
+ unsigned int table_name_length = args->lengths[0];
+ grn_obj *table = grn_ctx_get(info->ctx,
+ table_name,
+ table_name_length);
+ if (!table) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): table doesn't exist: <%.*s>",
+ static_cast<int>(table_name_length),
+ table_name);
+ goto error;
+ }
+
+ const char *term_column_name = args->args[1];
+ unsigned int term_column_name_length = args->lengths[1];
+ info->term_column = grn_obj_column(info->ctx,
+ table,
+ term_column_name,
+ term_column_name_length);
+ if (!info->term_column) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): term column doesn't exist: <%.*s.%.*s>",
+ static_cast<int>(table_name_length),
+ table_name,
+ static_cast<int>(term_column_name_length),
+ term_column_name);
+ goto error;
+ }
+
+ const char *expanded_term_column_name = args->args[2];
+ unsigned int expanded_term_column_name_length = args->lengths[2];
+ info->expanded_term_column = grn_obj_column(info->ctx,
+ table,
+ expanded_term_column_name,
+ expanded_term_column_name_length);
+ if (!info->expanded_term_column) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): "
+ "expanded term column doesn't exist: <%.*s.%.*s>",
+ static_cast<int>(table_name_length),
+ table_name,
+ static_cast<int>(expanded_term_column_name_length),
+ expanded_term_column_name);
+ goto error;
+ }
+ }
+
+ init->ptr = reinterpret_cast<char *>(info);
+
+ DBUG_RETURN(FALSE);
+
+error:
+ mrn_query_expand_info_free(info);
+ DBUG_RETURN(TRUE);
+}
+
+static void query_expand(mrn::QueryExpandInfo *info, UDF_ARGS *args)
+{
+ grn_ctx *ctx = info->ctx;
+ const char *query = args->args[3];
+ unsigned int query_length = args->lengths[3];
+
+ mrn::QueryParser query_parser(info->ctx,
+ current_thd,
+ NULL,
+ NULL,
+ 0,
+ NULL);
+ const char *raw_query;
+ size_t raw_query_length;
+ grn_operator default_operator;
+ grn_expr_flags flags;
+ query_parser.parse_pragma(query,
+ query_length,
+ &raw_query,
+ &raw_query_length,
+ &default_operator,
+ &flags);
+ GRN_TEXT_SET(info->ctx,
+ &(info->expanded_query),
+ query,
+ raw_query - query);
+ grn_expr_syntax_expand_query_by_table(ctx,
+ raw_query,
+ raw_query_length,
+ flags,
+ info->term_column,
+ info->expanded_term_column,
+ &(info->expanded_query));
+}
+
+MRN_API char *mroonga_query_expand(UDF_INIT *init,
+ UDF_ARGS *args,
+ char *result,
+ unsigned long *length,
+ char *is_null,
+ char *error)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn::QueryExpandInfo *info =
+ reinterpret_cast<mrn::QueryExpandInfo *>(init->ptr);
+ grn_ctx *ctx = info->ctx;
+
+ if (!args->args[3]) {
+ *is_null = 1;
+ DBUG_RETURN(NULL);
+ }
+
+ *is_null = 0;
+
+ query_expand(info, args);
+
+ if (ctx->rc) {
+ char message[MYSQL_ERRMSG_SIZE];
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_query_expand(): "
+ "failed to expand: %s",
+ ctx->errbuf);
+ my_message(ER_ERROR_ON_WRITE, message, MYF(0));
+ goto error;
+ }
+
+ *length = GRN_TEXT_LEN(&(info->expanded_query));
+ DBUG_RETURN(GRN_TEXT_VALUE(&(info->expanded_query)));
+
+error:
+ *error = 1;
+ DBUG_RETURN(NULL);
+}
+
+MRN_API void mroonga_query_expand_deinit(UDF_INIT *init)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+ mrn::QueryExpandInfo *info =
+ reinterpret_cast<mrn::QueryExpandInfo *>(init->ptr);
+ mrn_query_expand_info_free(info);
+ DBUG_VOID_RETURN;
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_snippet.cpp b/storage/mroonga/udf/mrn_udf_snippet.cpp
new file mode 100644
index 00000000..90d3721e
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_snippet.cpp
@@ -0,0 +1,340 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2010 Tetsuro IKEDA
+ Copyright(C) 2010-2013 Kentoku SHIBA
+ Copyright(C) 2011-2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_err.h>
+#include <mrn_encoding.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_table.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_current_thread.hpp>
+
+MRN_BEGIN_DECLS
+
+extern mrn::DatabaseManager *mrn_db_manager;
+extern mrn::ContextPool *mrn_context_pool;
+
+struct st_mrn_snip_info
+{
+ grn_ctx *ctx;
+ grn_obj *db;
+ bool use_shared_db;
+ grn_obj *snippet;
+ String result_str;
+};
+
+static my_bool mrn_snippet_prepare(st_mrn_snip_info *snip_info, UDF_ARGS *args,
+ char *message, grn_obj **snippet)
+{
+ unsigned int i;
+ CHARSET_INFO *cs;
+ grn_ctx *ctx = snip_info->ctx;
+ long long snip_max_len;
+ long long snip_max_num;
+ long long skip_leading_spaces;
+ long long html_escape;
+ int flags = GRN_SNIP_COPY_TAG;
+ grn_snip_mapping *mapping = NULL;
+ grn_rc rc;
+ String *result_str = &snip_info->result_str;
+ myf utf8_flag= current_thd->get_utf8_flag();
+
+ *snippet = NULL;
+ snip_max_len = *((long long *) args->args[1]);
+ snip_max_num = *((long long *) args->args[2]);
+
+ if (args->arg_type[3] == STRING_RESULT) {
+ if (!(cs = get_charset_by_name(args->args[3],
+ MYF(utf8_flag)))) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "Unknown charset: <%s>", args->args[3]);
+ goto error;
+ }
+ } else {
+ uint charset_id = static_cast<uint>(*((long long *) args->args[3]));
+ if (!(cs = get_charset(charset_id, MYF(0)))) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "Unknown charset ID: <%u>", charset_id);
+ goto error;
+ }
+ }
+ if (!mrn::encoding::set_raw(ctx, cs)) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "Unsupported charset: <%s>", cs->coll_name.str);
+ goto error;
+ }
+
+ if (!(cs->state & (MY_CS_BINSORT | MY_CS_CSSORT))) {
+ flags |= GRN_SNIP_NORMALIZE;
+ }
+
+ skip_leading_spaces = *((long long *) args->args[4]);
+ if (skip_leading_spaces) {
+ flags |= GRN_SNIP_SKIP_LEADING_SPACES;
+ }
+
+ html_escape = *((long long *) args->args[5]);
+ if (html_escape) {
+ mapping = (grn_snip_mapping *) -1;
+ }
+
+ *snippet = grn_snip_open(ctx, flags, static_cast<unsigned int>(snip_max_len),
+ static_cast<unsigned int>(snip_max_num),
+ "", 0, "", 0, mapping);
+ if (ctx->rc) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "Failed to open grn_snip: <%s>", ctx->errbuf);
+ goto error;
+ }
+
+ for (i = 8; i < args->arg_count; i += 3) {
+ rc = grn_snip_add_cond(ctx, *snippet,
+ args->args[i], args->lengths[i],
+ args->args[i + 1], args->lengths[i + 1],
+ args->args[i + 2], args->lengths[i + 2]);
+ if (rc) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "Failed to add a condition to grn_snip: <%s>", ctx->errbuf);
+ goto error;
+ }
+ }
+
+ result_str->set_charset(cs);
+ return FALSE;
+
+error:
+ if (*snippet) {
+ grn_obj_close(ctx, *snippet);
+ }
+ return TRUE;
+}
+
+MRN_API my_bool mroonga_snippet_init(UDF_INIT *init, UDF_ARGS *args, char *message)
+{
+ uint i;
+ st_mrn_snip_info *snip_info = NULL;
+ bool can_open_snippet = TRUE;
+ init->ptr = NULL;
+ if (args->arg_count < 11 || (args->arg_count - 11) % 3)
+ {
+ sprintf(message, "Incorrect number of arguments for mroonga_snippet(): %u",
+ args->arg_count);
+ goto error;
+ }
+ if (args->arg_type[0] != STRING_RESULT) {
+ strcpy(message, "mroonga_snippet() requires string for 1st argument");
+ goto error;
+ }
+ if (args->arg_type[1] != INT_RESULT) {
+ strcpy(message, "mroonga_snippet() requires int for 2nd argument");
+ goto error;
+ }
+ if (args->arg_type[2] != INT_RESULT) {
+ strcpy(message, "mroonga_snippet() requires int for 3rd argument");
+ goto error;
+ }
+ if (
+ args->arg_type[3] != STRING_RESULT &&
+ args->arg_type[3] != INT_RESULT
+ ) {
+ strcpy(message,
+ "mroonga_snippet() requires string or int for 4th argument");
+ goto error;
+ }
+ if (args->arg_type[4] != INT_RESULT) {
+ strcpy(message, "mroonga_snippet() requires int for 5th argument");
+ goto error;
+ }
+ if (args->arg_type[5] != INT_RESULT) {
+ strcpy(message, "mroonga_snippet() requires int for 6th argument");
+ goto error;
+ }
+ for (i = 6; i < args->arg_count; i++) {
+ if (args->arg_type[i] != STRING_RESULT) {
+ sprintf(message, "mroonga_snippet() requires string for %uth argument",
+ i);
+ goto error;
+ }
+ }
+ init->maybe_null = 1;
+
+ if (!(snip_info = (st_mrn_snip_info *) mrn_my_malloc(sizeof(st_mrn_snip_info),
+ MYF(MY_WME | MY_ZEROFILL))))
+ {
+ strcpy(message, "mroonga_snippet() out of memory");
+ goto error;
+ }
+ snip_info->ctx = mrn_context_pool->pull();
+ {
+ const char *current_db_path = MRN_THD_DB_PATH(current_thd);
+ const char *action;
+ if (current_db_path) {
+ action = "open database";
+ mrn::Database *db;
+ int error = mrn_db_manager->open(current_db_path, &db);
+ if (error == 0) {
+ snip_info->db = db->get();
+ grn_ctx_use(snip_info->ctx, snip_info->db);
+ snip_info->use_shared_db = true;
+ }
+ } else {
+ action = "create anonymous database";
+ snip_info->db = grn_db_create(snip_info->ctx, NULL, NULL);
+ snip_info->use_shared_db = false;
+ }
+ if (!snip_info->db) {
+ sprintf(message,
+ "mroonga_snippet(): failed to %s: %s",
+ action,
+ snip_info->ctx->errbuf);
+ goto error;
+ }
+ }
+
+ for (i = 1; i < args->arg_count; i++) {
+ if (!args->args[i]) {
+ can_open_snippet = FALSE;
+ break;
+ }
+ }
+ if (can_open_snippet) {
+ if (mrn_snippet_prepare(snip_info, args, message, &snip_info->snippet)) {
+ goto error;
+ }
+ }
+ init->ptr = (char *) snip_info;
+
+ return FALSE;
+
+error:
+ if (snip_info) {
+ if (!snip_info->use_shared_db) {
+ grn_obj_close(snip_info->ctx, snip_info->db);
+ }
+ mrn_context_pool->release(snip_info->ctx);
+ my_free(snip_info);
+ }
+ return TRUE;
+}
+
+MRN_API char *mroonga_snippet(UDF_INIT *init, UDF_ARGS *args, char *result,
+ unsigned long *length, char *is_null, char *error)
+{
+ st_mrn_snip_info *snip_info = (st_mrn_snip_info *) init->ptr;
+ grn_ctx *ctx = snip_info->ctx;
+ String *result_str = &snip_info->result_str;
+ char *target;
+ unsigned int target_length;
+ grn_obj *snippet = NULL;
+ grn_rc rc;
+ unsigned int i, n_results, max_tagged_length, result_length;
+
+ if (!args->args[0]) {
+ *is_null = 1;
+ return NULL;
+ }
+ *is_null = 0;
+ target = args->args[0];
+ target_length = args->lengths[0];
+
+ if (!snip_info->snippet) {
+ for (i = 1; i < args->arg_count; i++) {
+ if (!args->args[i]) {
+ my_printf_error(ER_MRN_INVALID_NULL_VALUE_NUM,
+ ER_MRN_INVALID_NULL_VALUE_STR, MYF(0),
+ "mroonga_snippet() arguments");
+ goto error;
+ }
+ }
+
+ if (mrn_snippet_prepare(snip_info, args, NULL, &snippet)) {
+ goto error;
+ }
+ } else {
+ snippet = snip_info->snippet;
+ }
+
+ rc = grn_snip_exec(ctx, snippet, target, target_length,
+ &n_results, &max_tagged_length);
+ if (rc) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+
+ result_str->length(0);
+ if (result_str->reserve((args->lengths[6] + args->lengths[7] +
+ max_tagged_length) * n_results)) {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0), HA_ERR_OUT_OF_MEM);
+ goto error;
+ }
+ for (i = 0; i < n_results; i++) {
+ result_str->q_append(args->args[6], args->lengths[6]);
+ rc = grn_snip_get_result(ctx, snippet, i,
+ (char *) result_str->ptr() + result_str->length(),
+ &result_length);
+ if (rc) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+ result_str->length(result_str->length() + result_length);
+ result_str->q_append(args->args[7], args->lengths[7]);
+ }
+
+ if (!snip_info->snippet) {
+ rc = grn_obj_close(ctx, snippet);
+ if (rc) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+ }
+
+ *length = result_str->length();
+ return (char *) result_str->ptr();
+
+error:
+ *error = 1;
+ return NULL;
+}
+
+MRN_API void mroonga_snippet_deinit(UDF_INIT *init)
+{
+ st_mrn_snip_info *snip_info = (st_mrn_snip_info *) init->ptr;
+ if (snip_info) {
+ if (snip_info->snippet) {
+ grn_obj_close(snip_info->ctx, snip_info->snippet);
+ }
+ MRN_STRING_FREE(snip_info->result_str);
+ if (!snip_info->use_shared_db) {
+ grn_obj_close(snip_info->ctx, snip_info->db);
+ }
+ mrn_context_pool->release(snip_info->ctx);
+ my_free(snip_info);
+ }
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/mrn_udf_snippet_html.cpp b/storage/mroonga/udf/mrn_udf_snippet_html.cpp
new file mode 100644
index 00000000..311c91bf
--- /dev/null
+++ b/storage/mroonga/udf/mrn_udf_snippet_html.cpp
@@ -0,0 +1,444 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/*
+ Copyright(C) 2015-2017 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-1335 USA
+*/
+
+#include <mrn_mysql.h>
+#include <mrn_mysql_compat.h>
+#include <mrn_err.h>
+#include <mrn_encoding.hpp>
+#include <mrn_windows.hpp>
+#include <mrn_table.hpp>
+#include <mrn_macro.hpp>
+#include <mrn_database_manager.hpp>
+#include <mrn_context_pool.hpp>
+#include <mrn_variables.hpp>
+#include <mrn_query_parser.hpp>
+#include <mrn_current_thread.hpp>
+
+MRN_BEGIN_DECLS
+
+extern mrn::DatabaseManager *mrn_db_manager;
+extern mrn::ContextPool *mrn_context_pool;
+
+typedef struct st_mrn_snippet_html_info
+{
+ grn_ctx *ctx;
+ grn_obj *db;
+ bool use_shared_db;
+ grn_obj *snippet;
+ String result_str;
+ struct {
+ bool used;
+ grn_obj *table;
+ grn_obj *default_column;
+ } query_mode;
+} mrn_snippet_html_info;
+
+static my_bool mrn_snippet_html_prepare(mrn_snippet_html_info *info,
+ UDF_ARGS *args,
+ char *message,
+ grn_obj **snippet)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ grn_ctx *ctx = info->ctx;
+ int flags = GRN_SNIP_SKIP_LEADING_SPACES;
+ unsigned int width = 200;
+ unsigned int max_n_results = 3;
+ const char *open_tag = "<span class=\"keyword\">";
+ const char *close_tag = "</span>";
+ grn_snip_mapping *mapping = GRN_SNIP_MAPPING_HTML_ESCAPE;
+ grn_obj *expr = NULL;
+ String *result_str = &(info->result_str);
+
+ *snippet = NULL;
+
+ mrn::encoding::set_raw(ctx, system_charset_info);
+ if (!(system_charset_info->state & (MY_CS_BINSORT | MY_CS_CSSORT))) {
+ flags |= GRN_SNIP_NORMALIZE;
+ }
+
+ *snippet = grn_snip_open(ctx, flags,
+ width, max_n_results,
+ open_tag, strlen(open_tag),
+ close_tag, strlen(close_tag),
+ mapping);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): failed to open grn_snip: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+
+ if (info->query_mode.used) {
+ if (!info->query_mode.table) {
+ grn_obj *short_text;
+ short_text = grn_ctx_at(info->ctx, GRN_DB_SHORT_TEXT);
+ info->query_mode.table = grn_table_create(info->ctx,
+ NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY,
+ short_text,
+ NULL);
+ }
+ if (!info->query_mode.default_column) {
+ info->query_mode.default_column =
+ grn_obj_column(info->ctx,
+ info->query_mode.table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ }
+
+ grn_obj *record = NULL;
+ GRN_EXPR_CREATE_FOR_QUERY(info->ctx, info->query_mode.table, expr, record);
+ if (!expr) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): "
+ "failed to create expression: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+
+ mrn::QueryParser query_parser(info->ctx,
+ current_thd,
+ expr,
+ info->query_mode.default_column,
+ 0,
+ NULL);
+ grn_rc rc = query_parser.parse(args->args[1], args->lengths[1]);
+ if (rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): "
+ "failed to parse query: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+
+ rc = grn_expr_snip_add_conditions(info->ctx,
+ expr,
+ *snippet,
+ 0,
+ NULL, NULL,
+ NULL, NULL);
+ if (rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): "
+ "failed to add conditions: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+ } else {
+ unsigned int i;
+ for (i = 1; i < args->arg_count; ++i) {
+ if (!args->args[i]) {
+ continue;
+ }
+ grn_rc rc = grn_snip_add_cond(ctx, *snippet,
+ args->args[i], args->lengths[i],
+ NULL, 0,
+ NULL, 0);
+ if (rc != GRN_SUCCESS) {
+ if (message) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): "
+ "failed to add a condition to grn_snip: <%s>",
+ ctx->errbuf);
+ }
+ goto error;
+ }
+ }
+ }
+
+ result_str->set_charset(system_charset_info);
+ DBUG_RETURN(FALSE);
+
+error:
+ if (expr) {
+ grn_obj_close(ctx, expr);
+ }
+ if (*snippet) {
+ grn_obj_close(ctx, *snippet);
+ }
+ DBUG_RETURN(TRUE);
+}
+
+MRN_API my_bool mroonga_snippet_html_init(UDF_INIT *init,
+ UDF_ARGS *args,
+ char *message)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn_snippet_html_info *info = NULL;
+
+ init->ptr = NULL;
+
+ if (args->arg_count < 1) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): wrong number of arguments: %u for 1+",
+ args->arg_count);
+ goto error;
+ }
+
+
+ for (unsigned int i = 0; i < args->arg_count; ++i) {
+ switch (args->arg_type[i]) {
+ case STRING_RESULT:
+ /* OK */
+ break;
+ case REAL_RESULT:
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): all arguments must be string: "
+ "<%u>=<%g>",
+ i, *((double *)(args->args[i])));
+ goto error;
+ break;
+ case INT_RESULT:
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): all arguments must be string: "
+ "<%u>=<%lld>",
+ i, *((longlong *)(args->args[i])));
+ goto error;
+ break;
+ default:
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): all arguments must be string: <%u>",
+ i);
+ goto error;
+ break;
+ }
+ }
+
+ init->maybe_null = 1;
+
+ info = (mrn_snippet_html_info *)mrn_my_malloc(sizeof(mrn_snippet_html_info),
+ MYF(MY_WME | MY_ZEROFILL));
+ if (!info) {
+ snprintf(message, MYSQL_ERRMSG_SIZE,
+ "mroonga_snippet_html(): failed to allocate memory");
+ goto error;
+ }
+
+ info->ctx = mrn_context_pool->pull();
+ {
+ const char *current_db_path = MRN_THD_DB_PATH(current_thd);
+ const char *action;
+ if (current_db_path) {
+ action = "open database";
+ mrn::Database *db;
+ int error = mrn_db_manager->open(current_db_path, &db);
+ if (error == 0) {
+ info->db = db->get();
+ grn_ctx_use(info->ctx, info->db);
+ info->use_shared_db = true;
+ }
+ } else {
+ action = "create anonymous database";
+ info->db = grn_db_create(info->ctx, NULL, NULL);
+ info->use_shared_db = false;
+ }
+ if (!info->db) {
+ sprintf(message,
+ "mroonga_snippet_html(): failed to %s: %s",
+ action,
+ info->ctx->errbuf);
+ goto error;
+ }
+ }
+
+ info->query_mode.used = FALSE;
+
+ if (args->arg_count == 2 &&
+ args->attribute_lengths[1] == strlen("query") &&
+ strncmp(args->attributes[1], "query", strlen("query")) == 0) {
+ info->query_mode.used = TRUE;
+ info->query_mode.table = NULL;
+ info->query_mode.default_column = NULL;
+ }
+
+ {
+ bool all_keywords_are_constant = TRUE;
+ for (unsigned int i = 1; i < args->arg_count; ++i) {
+ if (!args->args[i]) {
+ all_keywords_are_constant = FALSE;
+ break;
+ }
+ }
+
+ if (all_keywords_are_constant) {
+ if (mrn_snippet_html_prepare(info, args, message, &(info->snippet))) {
+ goto error;
+ }
+ } else {
+ info->snippet = NULL;
+ }
+ }
+
+ init->ptr = (char *)info;
+
+ DBUG_RETURN(FALSE);
+
+error:
+ if (info) {
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+ }
+ DBUG_RETURN(TRUE);
+}
+
+MRN_API char *mroonga_snippet_html(UDF_INIT *init,
+ UDF_ARGS *args,
+ char *result,
+ unsigned long *length,
+ char *is_null,
+ char *error)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn_snippet_html_info *info =
+ reinterpret_cast<mrn_snippet_html_info *>(init->ptr);
+
+ grn_ctx *ctx = info->ctx;
+ grn_obj *snippet = info->snippet;
+ String *result_str = &(info->result_str);
+
+ if (!args->args[0]) {
+ *is_null = 1;
+ DBUG_RETURN(NULL);
+ }
+
+ if (!snippet) {
+ if (mrn_snippet_html_prepare(info, args, NULL, &snippet)) {
+ goto error;
+ }
+ }
+
+ {
+ char *target = args->args[0];
+ unsigned int target_length = args->lengths[0];
+
+ unsigned int n_results, max_tagged_length;
+ {
+ grn_rc rc = grn_snip_exec(ctx, snippet, target, target_length,
+ &n_results, &max_tagged_length);
+ if (rc != GRN_SUCCESS) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+ }
+
+ *is_null = 0;
+ result_str->length(0);
+
+ {
+ const char *start_tag = "<div class=\"snippet\">";
+ const char *end_tag = "</div>";
+ size_t start_tag_length = strlen(start_tag);
+ size_t end_tag_length = strlen(end_tag);
+ unsigned int max_length_per_snippet =
+ start_tag_length + end_tag_length + max_tagged_length;
+ if (result_str->reserve(max_length_per_snippet * n_results)) {
+ my_error(ER_OUT_OF_RESOURCES, MYF(0), HA_ERR_OUT_OF_MEM);
+ goto error;
+ }
+
+ for (unsigned int i = 0; i < n_results; ++i) {
+ result_str->q_append(start_tag, start_tag_length);
+
+ unsigned int result_length;
+ grn_rc rc =
+ grn_snip_get_result(ctx, snippet, i,
+ (char *)result_str->ptr() + result_str->length(),
+ &result_length);
+ if (rc) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+ result_str->length(result_str->length() + result_length);
+
+ result_str->q_append(end_tag, end_tag_length);
+ }
+ }
+
+ if (!info->snippet) {
+ grn_rc rc = grn_obj_close(ctx, snippet);
+ if (rc != GRN_SUCCESS) {
+ my_printf_error(ER_MRN_ERROR_FROM_GROONGA_NUM,
+ ER_MRN_ERROR_FROM_GROONGA_STR, MYF(0), ctx->errbuf);
+ goto error;
+ }
+ }
+ }
+
+ *length = result_str->length();
+ DBUG_RETURN((char *)result_str->ptr());
+
+error:
+ if (!info->snippet && snippet) {
+ grn_obj_close(ctx, snippet);
+ }
+
+ *is_null = 1;
+ *error = 1;
+
+ DBUG_RETURN(NULL);
+}
+
+MRN_API void mroonga_snippet_html_deinit(UDF_INIT *init)
+{
+ MRN_DBUG_ENTER_FUNCTION();
+
+ mrn_snippet_html_info *info =
+ reinterpret_cast<mrn_snippet_html_info *>(init->ptr);
+ if (!info) {
+ DBUG_VOID_RETURN;
+ }
+
+ if (info->snippet) {
+ grn_obj_close(info->ctx, info->snippet);
+ }
+ if (info->query_mode.used) {
+ if (info->query_mode.default_column) {
+ grn_obj_close(info->ctx, info->query_mode.default_column);
+ }
+ if (info->query_mode.table) {
+ grn_obj_close(info->ctx, info->query_mode.table);
+ }
+ }
+ MRN_STRING_FREE(info->result_str);
+ if (!info->use_shared_db) {
+ grn_obj_close(info->ctx, info->db);
+ }
+ mrn_context_pool->release(info->ctx);
+ my_free(info);
+
+ DBUG_VOID_RETURN;
+}
+
+MRN_END_DECLS
diff --git a/storage/mroonga/udf/sources.am b/storage/mroonga/udf/sources.am
new file mode 100644
index 00000000..ac2f098e
--- /dev/null
+++ b/storage/mroonga/udf/sources.am
@@ -0,0 +1,9 @@
+libmrn_udf_la_SOURCES = \
+ mrn_udf_last_insert_grn_id.cpp \
+ mrn_udf_snippet.cpp \
+ mrn_udf_snippet_html.cpp \
+ mrn_udf_command.cpp \
+ mrn_udf_escape.cpp \
+ mrn_udf_normalize.cpp \
+ mrn_udf_highlight_html.cpp \
+ mrn_udf_query_expand.cpp
diff --git a/storage/mroonga/vendor/groonga/CMakeLists.txt b/storage/mroonga/vendor/groonga/CMakeLists.txt
new file mode 100644
index 00000000..27afb935
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/CMakeLists.txt
@@ -0,0 +1,662 @@
+# Copyright(C) 2012-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+# https://buildbot.askmonty.org/buildbot/builders/work-amd64-valgrind/builds/5263/steps/compile/logs/stdio
+# says CMake 2.6.2... We want to drop old software support...
+cmake_minimum_required(VERSION 2.6.2)
+# cmake_minimum_required(VERSION 2.6.4) # CentOS 5
+set(GRN_PROJECT_NAME "groonga")
+set(GRN_PROJECT_LABEL "Groonga")
+project("${GRN_PROJECT_NAME}")
+
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(GRN_BUNDLED FALSE)
+else()
+ set(GRN_BUNDLED TRUE)
+endif()
+
+if(MSVC)
+ if(MSVC_VERSION LESS 1800)
+ set(GRN_OLD_MSVC_MESSAGE "Groonga supports only MSVC 2013 or later")
+ if(GRN_BUNDLED)
+ message(STATUS ${GRN_OLD_MSVC_MESSAGE})
+ return()
+ else()
+ message(FATAL_ERROR ${GRN_OLD_MSVC_MESSAGE})
+ endif()
+ endif()
+endif()
+
+if(CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_COMPILER_IS_CLANGCC ON)
+endif()
+if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ set(CMAKE_COMPILER_IS_CLANGCXX ON)
+endif()
+
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/base_version" VERSION)
+if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/version.sh")
+ file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version.sh" GRN_VERSION)
+else()
+ if(NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/version.sh")
+ if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git" AND EXISTS "/bin/sh")
+ execute_process(COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/version-gen.sh")
+ file(READ "${CMAKE_CURRENT_BINARY_DIR}/version.sh" GRN_VERSION)
+ else()
+ set(GRN_VERSION "${VERSION}")
+ endif()
+ endif()
+endif()
+string(REGEX REPLACE "(^.*=|\n)" "" GRN_VERSION "${GRN_VERSION}")
+string(REGEX REPLACE "\\." "," GRN_VERSION_RC "${GRN_VERSION}")
+string(REGEX REPLACE "-.*$" "" GRN_VERSION_RC "${GRN_VERSION_RC}")
+
+include(CheckIncludeFile)
+include(CheckFunctionExists)
+include(CheckLibraryExists)
+include(CheckSymbolExists)
+include(CheckCCompilerFlag)
+include(CheckCXXCompilerFlag)
+include(FindPkgConfig)
+include(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake_modules/ReadFileList.cmake)
+
+if(DEFINED GRN_EMBED)
+ set(GRN_EMBED_DEFAULT ${GRN_EMBED})
+else()
+ set(GRN_EMBED_DEFAULT OFF)
+endif()
+set(GRN_EMBED ${GRN_EMBED_DEFAULT} CACHE BOOL
+ "Build as a static library to embed into an application")
+
+set(BIN_DIR "bin")
+set(SBIN_DIR "sbin")
+set(LIB_DIR "lib")
+set(INCLUDE_DIR "include")
+set(GRN_INCLUDE_DIR "include/groonga")
+set(DATA_DIR "share")
+if(NOT DEFINED GRN_DATA_DIR)
+ set(GRN_DATA_DIR "${DATA_DIR}/${GRN_PROJECT_NAME}")
+endif()
+set(CONFIG_DIR "etc")
+set(GRN_CONFIG_DIR "${CONFIG_DIR}/${GRN_PROJECT_NAME}")
+set(GRN_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/${GRN_CONFIG_DIR}/groonga.conf")
+
+set(GRN_LOG_PATH
+ "${CMAKE_INSTALL_PREFIX}/var/log/${GRN_PROJECT_NAME}/${GRN_PROJECT_NAME}.log"
+ CACHE FILEPATH "log file path")
+set(GRN_DEFAULT_ENCODING
+ "utf8"
+ CACHE STRING "Groonga's default encoding")
+set(GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD
+ 0
+ CACHE STRING "Groonga's default match escalation threshold")
+set(GRN_DEFAULT_DOCUMENT_ROOT_BASE
+ "html/admin"
+ CACHE PATH "Groonga's default document root base path")
+set(GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT
+ "share/${GRN_PROJECT_NAME}/${GRN_DEFAULT_DOCUMENT_ROOT_BASE}"
+ CACHE PATH "Groonga's default relative document root")
+set(GRN_DEFAULT_DOCUMENT_ROOT
+ "${CMAKE_INSTALL_PREFIX}/${GRN_DATA_DIR}/${GRN_DEFAULT_DOCUMENT_ROOT_BASE}"
+ CACHE PATH "Groonga's default document root")
+set(GRN_DEFAULT_DB_KEY
+ "auto"
+ CACHE STRING "Groonga's default DB key management algorithm")
+set(GRN_STACK_SIZE
+ 1024
+ CACHE STRING
+ "DANGER!!! Groonga's stack size. Normarlly, you should not change this variable.")
+set(GRN_LOCK_TIMEOUT
+ 900000
+ CACHE STRING
+ "timeout to acquire a lock.")
+set(GRN_LOCK_WAIT_TIME_NANOSECOND
+ 1000000
+ CACHE STRING
+ "wait time in nanosecond to acquire a lock.")
+set(GRN_RELATIVE_PLUGINS_DIR
+ "${LIB_DIR}/${GRN_PROJECT_NAME}/plugins")
+set(GRN_PLUGINS_DIR
+ "${CMAKE_INSTALL_PREFIX}/${GRN_RELATIVE_PLUGINS_DIR}")
+set(GRN_PLUGIN_SUFFIX "${CMAKE_SHARED_MODULE_SUFFIX}")
+set(GRN_DLL_FILENAME
+ "${CMAKE_SHARED_LIBRARY_PREFIX}groonga${CMAKE_SHARED_LIBRARY_SUFFIX}")
+set(GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE
+ "${GRN_CONFIG_DIR}/synonyms.tsv")
+set(GRN_QUERY_EXPANDER_TSV_SYNONYMS_FILE
+ "${CMAKE_INSTALL_PREFIX}/${GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE}")
+set(GRN_RELATIVE_RUBY_SCRIPTS_DIR
+ "${LIB_DIR}/${GRN_PROJECT_NAME}/scripts/ruby")
+set(GRN_RUBY_SCRIPTS_DIR
+ "${CMAKE_INSTALL_PREFIX}/${GRN_RELATIVE_RUBY_SCRIPTS_DIR}")
+
+
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
+ set(GRN_C_COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS} -std=gnu99")
+endif()
+
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGCXX)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wall")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-unused-but-set-variable")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-pointer-sign")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wformat")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wstrict-aliasing=2")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fno-strict-aliasing")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-disabled-optimization")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wfloat-equal")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wpointer-arith")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wbad-function-cast")
+ if(NOT CMAKE_COMPILER_IS_CLANGCXX)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wcast-align")
+ endif()
+ # MY_CHECK_AND_SET_COMPILER_FLAG("-Wredundant-decls")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wwrite-strings")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fexceptions")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fimplicit-templates")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-unused-parameter")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-sign-compare")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-missing-field-initializers")
+ MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-implicit-fallthrough")
+endif()
+
+if(NOT DEFINED CMAKE_C_COMPILE_OPTIONS_PIC)
+ # For old CMake
+ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGCXX)
+ MY_CHECK_AND_SET_COMPILER_FLAG("-fPIC")
+ endif()
+endif()
+
+option(GRN_WITH_DEBUG "enable debug build." OFF)
+if(GRN_WITH_DEBUG)
+ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGCXX)
+ set(GRN_C_COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS} -g3 -O0")
+ set(GRN_CXX_COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS} -g3 -O0")
+ endif()
+endif()
+
+add_definitions(
+ -DHAVE_CONFIG_H
+ )
+if(GRN_EMBED)
+ add_definitions(-DGRN_EMBEDDED)
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGCXX)
+ set(_GNU_SOURCE TRUE)
+endif()
+
+include_directories(
+ BEFORE
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib
+ )
+
+macro(ac_check_headers header)
+ string(REGEX REPLACE "[/.]" "_" output_variable_name ${header})
+ string(TOUPPER "${output_variable_name}" output_variable_name)
+ set(output_variable_name "HAVE_${output_variable_name}")
+ check_include_file(${header} ${output_variable_name})
+endmacro()
+
+macro(ac_check_funcs function)
+ string(TOUPPER "${function}" output_variable_name)
+ set(output_variable_name "HAVE_${output_variable_name}")
+ check_function_exists(${function} ${output_variable_name})
+endmacro()
+
+macro(ac_check_symbols symbol files)
+ string(TOUPPER "${symbol}" output_variable_name)
+ set(output_variable_name "HAVE_${output_variable_name}")
+ check_symbol_exists(${symbol} ${files} ${output_variable_name})
+endmacro()
+
+macro(ac_check_lib library function)
+ string(REGEX REPLACE "[/.]" "_" output_variable_base_name ${library})
+ string(TOUPPER "${output_variable_base_name}" output_variable_base_name)
+ set(output_variable_name "HAVE_LIB${output_variable_base_name}")
+ set(location "${ARG2}")
+ check_library_exists(${library} ${function} "${location}"
+ ${output_variable_name})
+ if(${output_variable_name})
+ set(${output_variable_base_name}_LIBS "${library}")
+ endif()
+endmacro()
+
+include(build/ac_macros/check_headers.m4)
+include(build/ac_macros/check_functions.m4)
+
+ac_check_symbols(fpclassify math.h)
+ac_check_lib(m fpclassify)
+
+ac_check_lib(execinfo backtrace)
+if(HAVE_LIBEXECINFO)
+ set(HAVE_BACKTRACE TRUE)
+else()
+ ac_check_funcs(backtrace)
+endif()
+ac_check_lib(rt clock_gettime)
+if(HAVE_LIBRT)
+ set(HAVE_CLOCK_GETTIME TRUE)
+endif()
+if(GRN_EMBED)
+ check_library_exists(stdc++ __cxa_begin_catch "${ARG2}"
+ STDCPP)
+ if(STDCPP)
+ set(STDCPP_LIBS "stdc++")
+ endif()
+endif()
+
+if(UNIX)
+ ac_check_headers(pthread.h)
+ ac_check_lib(pthread pthread_mutex_init)
+ if(NOT ${HAVE_LIBPTHREAD})
+ message(FATAL_ERROR "No libpthread found")
+ endif()
+ ac_check_funcs(pthread_mutexattr_setpshared)
+ ac_check_funcs(pthread_condattr_setpshared)
+endif()
+
+option(GRN_WITH_NFKC "use NFKC based UTF8 normalization." ON)
+
+if(WIN32)
+ ac_check_headers(winsock2.h)
+ if(NOT ${HAVE_WINSOCK2_H})
+ message(FATAL_ERROR "No winsock2.h found")
+ endif()
+
+ # FIXME: CMake couldn't detect ws2_32.lib on Windows 8 64bit.
+ # It may be caused by missing library search path for ws2_32.lib.
+ # It seems that Visual Studio (devenv.exe) can find it but link.exe
+ # can't. "cmake --build" can find it because it uses Visual Studio
+ # internally. So we assume that we always have ws2_32.lib on Windows.
+ # ac_check_lib(ws2_32 select)
+ set(HAVE_LIBWS2_32 TRUE)
+ set(WS2_32_LIBS "ws2_32.lib")
+
+ set(USE_SELECT TRUE)
+else()
+ ac_check_headers(sys/epoll.h)
+ if(${HAVE_SYS_EPOLL_H})
+ ac_check_funcs(epoll_create)
+ if(${HAVE_EPOLL_CREATE})
+ set(USE_EPOLL TRUE)
+ endif()
+ endif()
+
+ if(NOT USE_EPOLL)
+ ac_check_headers(sys/event.h)
+ if(${HAVE_SYS_EVENT_H})
+ ac_check_funcs(kevent)
+ if(${HAVE_KEVENT})
+ set(USE_KQUEUE TRUE)
+ endif()
+ endif()
+
+ if(NOT USE_KQUEUE)
+ ac_check_headers(poll.h)
+ if(${HAVE_SYS_POLL_H})
+ ac_check_funcs(poll)
+ if(${HAVE_POLL})
+ set(USE_POLL TRUE)
+ endif()
+ endif()
+
+ if(NOT USE_POLL)
+ ac_check_funcs(select)
+ if(${HAVE_SELECT})
+ set(USE_SELECT TRUE)
+ ac_check_headers(sys/select.h)
+ endif()
+
+ if(NOT USE_SELECT)
+ message(FATAL_ERROR "All epoll/kqueue/poll/select are missing")
+ endif()
+ endif()
+ endif()
+ endif()
+endif()
+
+set(GRN_WITH_ZLIB "auto"
+ CACHE STRING "Support data compression by zlib.")
+if(NOT ${GRN_WITH_ZLIB} STREQUAL "no")
+ ac_check_lib(z compress)
+ if(NOT HAVE_LIBZ)
+ if(${GRN_WITH_ZLIB} STREQUAL "yes")
+ message(FATAL_ERROR "No libz found")
+ endif()
+ set(GRN_WITH_ZLIB "no")
+ endif()
+endif()
+
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/bundled_lz4_version"
+ GRN_BUNDLED_LZ4_VERSION)
+string(STRIP
+ "${GRN_BUNDLED_LZ4_VERSION}"
+ GRN_BUNDLED_LZ4_VERSION)
+option(GRN_WITH_BUNDLED_LZ4 "use bundled LZ4" OFF)
+
+set(GRN_WITH_LZ4 "auto"
+ CACHE STRING "Support data compression by LZ4.")
+if(NOT ${GRN_WITH_LZ4} STREQUAL "no")
+ if(GRN_WITH_BUNDLED_LZ4)
+ set(LIBLZ4_INCLUDE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}/vendor/lz4-${GRN_BUNDLED_LZ4_VERSION}/lib")
+ set(LZ4_LIBS liblz4)
+ else()
+ if(NOT DEFINED LIBLZ4_FOUND)
+ pkg_check_modules(LIBLZ4 liblz4)
+ endif()
+ if(LIBLZ4_FOUND)
+ # According to CMake documentation, this is the recommended way to force
+ # looking in LIBRARY_DIRS first and in regular system paths otherwise.
+ #
+ # pkg_check_modules does not guarantee that LIBLZ4_LIBRARY_DIRS will be
+ # set. If it's not set we won't find the library without looking through
+ # the regular system paths.
+ find_library(LZ4_LIBS
+ NAMES ${LIBLZ4_LIBRARIES}
+ PATHS ${LIBLZ4_LIBRARY_DIRS}
+ NO_DEFAULT_PATH)
+ find_library(LZ4_LIBS
+ NAMES ${LIBLZ4_LIBRARIES})
+ set(GRN_WITH_LZ4 TRUE)
+ else()
+ if(${GRN_WITH_LZ4} STREQUAL "yes")
+ message(FATAL_ERROR "No LZ4 found")
+ endif()
+ set(GRN_WITH_LZ4 FALSE)
+ endif()
+ endif()
+endif()
+
+
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/bundled_mecab_version"
+ GRN_BUNDLED_MECAB_VERSION)
+string(STRIP
+ "${GRN_BUNDLED_MECAB_VERSION}"
+ GRN_BUNDLED_MECAB_VERSION)
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/bundled_mecab_naist_jdic_version"
+ GRN_BUNDLED_MECAB_NAIST_JDIC_VERSION)
+string(STRIP
+ "${GRN_BUNDLED_MECAB_NAIST_JDIC_VERSION}"
+ GRN_BUNDLED_MECAB_NAIST_JDIC_VERSION)
+option(GRN_WITH_BUNDLED_MECAB "use bundled MeCab" OFF)
+
+set(GRN_WITH_MECAB "auto"
+ CACHE STRING "use MeCab for morphological analysis")
+if(NOT ${GRN_WITH_MECAB} STREQUAL "no")
+ if(GRN_WITH_BUNDLED_MECAB)
+ set(MECAB_INCLUDE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}/vendor/mecab-${GRN_BUNDLED_MECAB_VERSION}/src")
+ set(MECAB_LIBRARY_DIRS
+ "${CMAKE_CURRENT_BUILD_DIR}/vendor/mecab")
+ set(MECAB_LIBRARIES libmecab)
+ else()
+ set(GRN_MECAB_CONFIG "mecab-config" CACHE FILEPATH "mecab-config path")
+ if(NOT CMAKE_CROSSCOMPILING OR DEFINED CMAKE_CROSSCOMPILING_EMULATOR)
+ find_program(GRN_MECAB_CONFIG_ABSOLUTE_PATH "${GRN_MECAB_CONFIG}")
+ endif()
+ if(EXISTS "${GRN_MECAB_CONFIG_ABSOLUTE_PATH}")
+ execute_process(COMMAND "${GRN_MECAB_CONFIG_ABSOLUTE_PATH}" --inc-dir
+ OUTPUT_VARIABLE MECAB_INCLUDE_DIRS
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND "${GRN_MECAB_CONFIG_ABSOLUTE_PATH}" --libs-only-L
+ OUTPUT_VARIABLE MECAB_LIBRARY_DIRS
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ set(MECAB_LIBRARIES "mecab")
+ ac_check_lib(${MECAB_LIBRARIES} mecab_new)
+ if(HAVE_LIBMECAB)
+ set(GRN_WITH_MECAB TRUE)
+ else()
+ if(${GRN_WITH_MECAB} STREQUAL "yes")
+ message(FATAL_ERROR
+ "No MeCab library found: "
+ "include directories: <${MECAB_INCLUDE_DIRS}>, "
+ "library directories: <${MECAB_LIBRARY_DIRS}>")
+ endif()
+ set(GRN_WITH_MECAB FALSE)
+ endif()
+ else()
+ if(${GRN_WITH_MECAB} STREQUAL "yes")
+ message(FATAL_ERROR "No mecab-config found: <${GRN_MECAB_CONFIG}>")
+ endif()
+ set(GRN_WITH_MECAB FALSE)
+ endif()
+ endif()
+else()
+ set(GRN_WITH_MECAB FALSE)
+endif()
+
+set(GRN_WITH_KYTEA "auto"
+ CACHE STRING "use KyTea for morphological analysis")
+if(NOT ${GRN_WITH_KYTEA} STREQUAL "no")
+ if(NOT DEFINED KYTEA_FOUND)
+ pkg_check_modules(KYTEA kytea)
+ endif()
+ if(KYTEA_FOUND)
+ set(GRN_WITH_KYTEA TRUE)
+ else()
+ if(${GRN_WITH_KYTEA} STREQUAL "yes")
+ message(FATAL_ERROR "No KyTea found")
+ endif()
+ set(GRN_WITH_KYTEA FALSE)
+ endif()
+else()
+ set(GRN_WITH_KYTEA FALSE)
+endif()
+
+set(GRN_WITH_LIBSTEMMER "auto"
+ CACHE STRING "use libstemmer for stemming token filter")
+if(NOT ${GRN_WITH_LIBSTEMMER} STREQUAL "no")
+ if(NOT ("${GRN_WITH_LIBSTEMMER}" STREQUAL "yes" OR
+ "${GRN_WITH_LIBSTEMMER}" STREQUAL "auto"))
+ if("${LIBSTEMMER_INCLUDE_DIRS}" STREQUAL "")
+ set(LIBSTEMMER_INCLUDE_DIRS "${GRN_WITH_LIBSTEMMER}/include")
+ endif()
+ if("${LIBSTEMMER_LIBRARY_DIRS}" STREQUAL "")
+ set(LIBSTEMMER_LIBRARY_DIRS "${GRN_WITH_LIBSTEMMER}/lib")
+ endif()
+ endif()
+ set(CMAKE_REQUIRED_INCLUDES_SAVE ${CMAKE_REQUIRED_INCLUDES})
+ set(CMAKE_REQUIRED_INCLUDES
+ ${CMAKE_REQUIRED_INCLUDES}
+ ${LIBSTEMMER_INCLUDE_DIRS})
+ ac_check_headers(libstemmer.h)
+ ac_check_lib(stemmer sb_stemmer_list "${LIBSTEMMER_LIBRARY_DIRS}")
+ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVE})
+ if(HAVE_LIBSTEMMER_H AND HAVE_LIBSTEMMER)
+ set(LIBSTEMMER_LIBRARIES "stemmer")
+ set(GRN_WITH_LIBSTEMMER TRUE)
+ else()
+ if(${GRN_WITH_LIBSTEMMER} STREQUAL "yes")
+ message(FATAL_ERROR "No libstemmer found")
+ endif()
+ set(GRN_WITH_LIBSTEMMER FALSE)
+ endif()
+else()
+ set(GRN_WITH_LIBSTEMMER FALSE)
+endif()
+
+set(GRN_WITH_ZEROMQ "auto"
+ CACHE STRING "use ZeroMQ for suggestion")
+if(NOT ${GRN_WITH_ZEROMQ} STREQUAL "no")
+ if(NOT DEFINED ZEROMQ_FOUND)
+ pkg_check_modules(ZEROMQ libzmq)
+ endif()
+ if(ZEROMQ_FOUND)
+ set(GRN_WITH_ZEROMQ TRUE)
+ else()
+ if(${GRN_WITH_ZEROMQ} STREQUAL "yes")
+ message(FATAL_ERROR "No ZeroMQ found")
+ endif()
+ set(GRN_WITH_ZEROMQ FALSE)
+ endif()
+else()
+ set(GRN_WITH_ZEROMQ FALSE)
+endif()
+
+set(GRN_WITH_LIBEVENT "auto"
+ CACHE STRING "use libevent for suggestion")
+if(NOT ${GRN_WITH_LIBEVENT} STREQUAL "no")
+ if("${GRN_WITH_LIBEVENT}" STREQUAL "yes" OR
+ "${GRN_WITH_LIBEVENT}" STREQUAL "auto")
+ set(LIBEVENT_INCLUDE_DIRS "")
+ set(LIBEVENT_LIBRARY_DIRS "")
+ else()
+ set(LIBEVENT_INCLUDE_DIRS "${GRN_WITH_LIBEVENT}/include")
+ set(LIBEVENT_LIBRARY_DIRS "${GRN_WITH_LIBEVENT}/lib")
+ endif()
+ set(CMAKE_REQUIRED_INCLUDES_SAVE ${CMAKE_REQUIRED_INCLUDES})
+ ac_check_lib(event event_init "${LIBEVENT_LIBRARY_DIRS}")
+ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVE})
+ if(HAVE_LIBEVENT)
+ set(LIBEVENT_LIBRARIES "event")
+ set(GRN_WITH_LIBEVENT TRUE)
+ else()
+ if(${GRN_WITH_LIBEVENT} STREQUAL "yes")
+ message(FATAL_ERROR "No libevent found")
+ endif()
+ set(GRN_WITH_LIBEVENT FALSE)
+ endif()
+else()
+ set(GRN_WITH_LIBEVENT FALSE)
+endif()
+
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/bundled_message_pack_version"
+ GRN_BUNDLED_MESSAGE_PACK_VERSION)
+string(STRIP
+ "${GRN_BUNDLED_MESSAGE_PACK_VERSION}"
+ GRN_BUNDLED_MESSAGE_PACK_VERSION)
+option(GRN_WITH_BUNDLED_MESSAGE_PACK "use bundled MessagePack" OFF)
+
+set(GRN_WITH_MESSAGE_PACK "auto"
+ CACHE STRING "use MessagePack for suggestion")
+if(NOT ${GRN_WITH_MESSAGE_PACK} STREQUAL "no")
+ if(GRN_WITH_BUNDLED_MESSAGE_PACK)
+ set(MESSAGE_PACK_INCLUDE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}/vendor/msgpack-${GRN_BUNDLED_MESSAGE_PACK_VERSION}/include")
+ set(MESSAGE_PACK_LIBS msgpackc)
+ else()
+ if(NOT DEFINED MESSAGE_PACK_FOUND)
+ pkg_check_modules(MESSAGE_PACK msgpack)
+ endif()
+ if(MESSAGE_PACK_FOUND)
+ find_library(MESSAGE_PACK_LIBS
+ NAMES ${MESSAGE_PACK_LIBRARIES}
+ PATHS ${MESSAGE_PACK_LIBRARY_DIRS}
+ NO_DEFAULT_PATH)
+ set(GRN_WITH_MESSAGE_PACK TRUE)
+ else()
+ if("${GRN_WITH_MESSAGE_PACK}" STREQUAL "yes" OR
+ "${GRN_WITH_MESSAGE_PACK}" STREQUAL "auto")
+ set(MESSAGE_PACK_INCLUDE_DIRS "")
+ set(MESSAGE_PACK_LIBRARY_DIRS "")
+ else()
+ set(MESSAGE_PACK_INCLUDE_DIRS "${GRN_WITH_MESSAGE_PACK}/include")
+ set(MESSAGE_PACK_LIBRARY_DIRS "${GRN_WITH_MESSAGE_PACK}/lib")
+ endif()
+ set(CMAKE_REQUIRED_INCLUDES_SAVE ${CMAKE_REQUIRED_INCLUDES})
+ ac_check_lib(msgpack msgpack_version "${MESSAGE_PACK_LIBRARY_DIRS}")
+ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVE})
+ if(HAVE_LIBMSGPACK)
+ find_library(MESSAGE_PACK_LIBS
+ NAMES "msgpack"
+ PATHS ${MESSAGE_PACK_LIBRARY_DIRS}
+ NO_DEFAULT_PATH)
+ set(GRN_WITH_MESSAGE_PACK TRUE)
+ else()
+ if(${GRN_WITH_MESSAGE_PACK} STREQUAL "yes")
+ message(FATAL_ERROR "No MessagePack found")
+ endif()
+ set(GRN_WITH_MESSAGE_PACK FALSE)
+ endif()
+ endif()
+ endif()
+else()
+ set(GRN_WITH_MESSAGE_PACK FALSE)
+endif()
+
+option(GRN_WITH_MRUBY "use mruby" OFF)
+if(GRN_WITH_MRUBY)
+ find_program(RUBY NAMES
+ "ruby2.3" "ruby23"
+ "ruby2.2" "ruby22"
+ "ruby2.1" "ruby21"
+ "ruby")
+ set(MRUBY_INCLUDE_DIRS
+ "${CMAKE_CURRENT_SOURCE_DIR}/vendor/mruby-source/include")
+ set(MRUBY_LIBS mruby)
+else()
+ set(MRUBY_INCLUDE_DIRS "")
+ set(MRUBY_LIBS "")
+endif()
+set(MRUBY_DEFINITIONS "MRB_INT64" "HAVE_ONIGMO_H")
+
+# TODO: Support using system Onigmo instead of bundled Onigmo.
+# set(GRN_WITH_ONIGMO ON)
+# set(ONIGMO_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/onigmo-source")
+# set(ONIGMO_LIBS onigmo)
+
+# TODO: It's for Onigmo static link case. If we support system Onigmo,
+# we need to remove it and add -DEXPORT to Onigmo build.
+add_definitions(-DONIG_EXTERN=extern)
+
+add_subdirectory(vendor)
+if(GRN_EMBED)
+ add_subdirectory(plugins)
+endif()
+add_subdirectory(lib)
+if(NOT GRN_EMBED)
+ add_subdirectory(src)
+ add_subdirectory(plugins)
+ add_subdirectory(include)
+ add_subdirectory(data)
+endif()
+
+configure_file(config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
+
+set(GROONGA "${CMAKE_CURRENT_BINARY_DIR}/src/groonga")
+set(GROONGA_SUGGEST_CREATE_DATASET
+ "${CMAKE_CURRENT_BINARY_DIR}/src/suggest/groonga-suggest-create-dataset")
+set(GROONGA_BENCHMARK "${CMAKE_CURRENT_BINARY_DIR}/src/groonga-benchmark")
+configure_file(config.sh.in "${CMAKE_CURRENT_BINARY_DIR}/config.sh" @ONLY)
+
+set(prefix "${CMAKE_INSTALL_PREFIX}")
+set(exec_prefix "${prefix}")
+set(bindir "${CMAKE_INSTALL_PREFIX}/${BIN_DIR}")
+set(sbindir "${CMAKE_INSTALL_PREFIX}/${SBIN_DIR}")
+set(libdir "${CMAKE_INSTALL_PREFIX}/${LIB_DIR}")
+set(includedir "${CMAKE_INSTALL_PREFIX}/${INCLUDE_DIR}")
+set(datarootdir "${CMAKE_INSTALL_PREFIX}/${DATA_DIR}")
+set(datadir "${datarootdir}")
+set(expanded_pluginsdir "${GRN_PLUGINS_DIR}")
+set(GRN_EXPANDED_DEFAULT_DOCUMENT_ROOT "${GRN_DEFAULT_DOCUMENT_ROOT}")
+set(EXEEXT "${CMAKE_EXECUTABLE_SUFFIX}")
+configure_file(groonga.pc.in "${CMAKE_CURRENT_BINARY_DIR}/groonga.pc" @ONLY)
+
+if(NOT GRN_EMBED)
+ install(
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/groonga.pc"
+ DESTINATION "${LIB_DIR}/pkgconfig/")
+endif()
+
+install(FILES
+ "COPYING"
+ "README.md"
+ DESTINATION "${GRN_DATA_DIR}")
+
+add_subdirectory(vendor/plugins)
diff --git a/storage/mroonga/vendor/groonga/COPYING b/storage/mroonga/vendor/groonga/COPYING
new file mode 100644
index 00000000..a22bbf7e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/COPYING
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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-1335 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/storage/mroonga/vendor/groonga/Makefile.am b/storage/mroonga/vendor/groonga/Makefile.am
new file mode 100644
index 00000000..1fc7028f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/Makefile.am
@@ -0,0 +1,141 @@
+# release: update-latest-release (commit) tag
+
+LOCALES = ja
+
+ACLOCAL_AMFLAGS = -I m4
+AUTOMAKE_OPTIONS = 1.9.6
+SUBDIRS = \
+ build \
+ include \
+ vendor \
+ lib \
+ plugins \
+ src \
+ examples \
+ test \
+ benchmark \
+ packages \
+ data \
+ tools \
+ doc
+#dist_data_DATA =
+EXTRA_DIST = \
+ CMakeLists.txt \
+ README.md \
+ base_version \
+ bindings \
+ bundled_lz4_version \
+ bundled_mecab_naist_jdic_version \
+ bundled_mecab_version \
+ config.h.cmake \
+ gpg_uid \
+ nginx_version \
+ version-gen.sh
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = groonga.pc
+if GRN_WITH_ARROW
+pkgconfig_DATA += groonga-arrow.pc
+endif
+
+.PHONY: FORCE
+
+FORCE:
+
+$(srcdir)/version.sh: FORCE
+ @$(SHELL_PATH) $(srcdir)/version-gen.sh
+
+include $(srcdir)/version.sh
+
+dist-hook:
+ echo "$(GRN_VERSION)" > $(distdir)/version
+ cd $(distdir) && autoreconf --install --force && find . -name autom4te.cache | xargs rm -fr
+
+benchmark:
+ cd test/benchmark && $(MAKE) benchmark
+
+tag:
+ cd $(top_srcdir) && git tag v$(VERSION) -a -m 'Groonga $(VERSION)!!!'
+
+echo-version:
+ @echo $(VERSION)
+
+update-latest-release: misc
+ @if test -z "$(OLD_RELEASE)"; then \
+ echo "\$$(OLD_RELEASE) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(OLD_RELEASE_DATE)"; then \
+ echo "\$$(OLD_RELEASE_DATE) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(NEW_RELEASE_DATE)"; then \
+ echo "\$$(NEW_RELEASE_DATE) is missing"; \
+ exit 1; \
+ fi
+ cd $(top_srcdir) && \
+ misc/update-latest-release.rb \
+ $(PACKAGE) $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/rpm/centos/groonga.spec.in \
+ packages/debian/changelog \
+ doc/source/install.rst \
+ doc/source/install/*.rst \
+ doc/locale/*/LC_MESSAGES/install.po \
+ $(GROONGA_ORG_PATH)/_config.yml
+
+update-po:
+ @for lang in $(LOCALES); do \
+ (cd $(top_srcdir)/doc/locale/$$lang/LC_MESSAGES && $(MAKE) update) \
+ done
+
+update-document:
+ @if test -z "$(GROONGA_ORG_PATH)"; then \
+ echo "\$$(GROONGA_ORG_PATH) is missing"; \
+ echo "add --with-groonga-org-path in configure"; \
+ exit 1; \
+ fi
+ rm -rf tmp-doc
+ mkdir tmp-doc
+ (cd doc && $(MAKE) clean-html)
+ (cd doc && $(MAKE) install docdir=$(abs_srcdir)/tmp-doc/install)
+ ruby $(srcdir)/tools/prepare-sphinx-html.rb tmp-doc/install tmp-doc/dist
+ rm -rf $(GROONGA_ORG_PATH)/docs
+ mv tmp-doc/dist/en $(GROONGA_ORG_PATH)/docs
+ for locale in `cd tmp-doc/dist; echo *`; do \
+ dest_base_dir=$(GROONGA_ORG_PATH)/$${locale}; \
+ mkdir -p $${dest_base_dir}; \
+ dest_dir=$${dest_base_dir}/docs; \
+ rm -rf $${dest_dir}; \
+ mv tmp-doc/dist/$${locale} $${dest_dir}; \
+ done
+
+
+update-version:
+ @if test -z "$(NEW_VERSION)"; then \
+ echo "\$$(NEW_VERSION) is missing"; \
+ exit 1; \
+ fi
+ @echo -n $(NEW_VERSION) > $(srcdir)/base_version
+
+update-files:
+ cd doc && $(MAKE) update-files
+ cd data/html && $(MAKE) update-files
+
+update-mruby:
+ cd $(top_srcdir)/vendor/mruby && make update
+
+update-nginx:
+ @if test -z "$(NEW_NGINX_VERSION)"; then \
+ echo "\$$(NEW_NGINX_VERSION) is missing"; \
+ exit 1; \
+ fi
+ cd $(top_srcdir)/vendor && ./update_nginx.sh $(NEW_NGINX_VERSION)
+
+misc:
+ @if test -z "$(CUTTER_SOURCE_PATH)"; then \
+ echo "\$$(CUTTER_SOURCE_PATH) is missing"; \
+ exit 1; \
+ fi
+ ln -s "$(CUTTER_SOURCE_PATH)/misc" misc
+
diff --git a/storage/mroonga/vendor/groonga/README.md b/storage/mroonga/vendor/groonga/README.md
new file mode 100644
index 00000000..af0b5a7d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/README.md
@@ -0,0 +1,62 @@
+# README
+
+Groonga is an open-source fulltext search engine and column store.
+
+## Reference manual
+
+See doc/source/ directory or http://groonga.org/docs/.
+
+Here are shortcut links:
+
+ * How to install: http://groonga.org/docs/install.html
+ * Tutorial: http://groonga.org/docs/tutorial.html
+ * How to build as a developer: http://groonga.org/docs/contribution/development/build.html
+
+## Community
+
+ * [@groonga on Twitter](https://twitter.com/groonga/)
+ * [Groonga page on Facebook](https://www.facebook.com/groonga)
+ * [Mailing list on SourceForge.net](http://lists.sourceforge.net/mailman/listinfo/groonga-talk)
+ * [Chat room on Gitter](https://gitter.im/groonga/public)
+
+## Bundled software
+
+### mruby
+
+ * Path: vendor/mruby-source
+ * License: The MIT license. See vendor/mruby-source/MITL for details.
+
+### Onigmo
+
+ * Path: vendor/onigmo-source
+ * License: BSD license. See vendor/onigmo-source/COPYING for details.
+
+### nginx
+
+ * Path: vendor/nginx-${VERSION}
+ * License: BSD license. See vendor/nginx-${VERSION}/LICENSE for details.
+
+## Authors
+
+### Primary authors
+
+ * Daijiro MORI <morita at razil. jp>
+ * Tasuku SUENAGA <a at razil. jp>
+ * Yutaro Shimamura <yu at razil. jp>
+ * Kouhei Sutou <kou at cozmixng. org>
+ * Kazuho Oku <kazuhooku at gmail. com>
+ * Moriyoshi Koizumi <moriyoshi at gmail. com>
+
+### Patches and modules from
+
+TODO: Update or use
+https://github.com/groonga/groonga/graphs/contributors instead.
+
+ * Daisuke Maki <dmaki at cpan. org>
+ * Kazuhiro Osawa <ko at yappo. ne. jp>
+ * Hiroyuki OYAMA <oyama at module. jp>
+ * Nguyen Anh Phu <phuna at users. sourceforge. net>
+ * Hideyuki KUROSU <hideyuki. kurosu at gmail. com>
+ * Takuo Kitame <kitame at valinux. co. jp>
+ * Yoshihiro Oyama <yos-o at smilemark. com>
+ * cZfSunOs.U <sunos at saita. ma>
diff --git a/storage/mroonga/vendor/groonga/appveyor.yml b/storage/mroonga/vendor/groonga/appveyor.yml
new file mode 100644
index 00000000..fca8c229
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/appveyor.yml
@@ -0,0 +1,72 @@
+version: "{build}"
+clone_depth: 10
+
+environment:
+ matrix:
+ - VS_VERSION: 12
+ ARCH: x86
+ - VS_VERSION: 12
+ ARCH: amd64
+ - VS_VERSION: 14
+ ARCH: x86
+ - VS_VERSION: 14
+ ARCH: amd64
+
+notifications:
+ - provider: Email
+ to:
+ - groonga-commit@lists.osdn.me
+ on_build_status_changed: true
+
+init:
+ - set PATH=C:\Ruby22\bin;%PATH%
+ - set PATH=C:\msys64\usr\bin;%PATH%
+ - call
+ "C:\Program Files (x86)\Microsoft Visual Studio %VS_VERSION%.0\VC\vcvarsall.bat"
+ %ARCH%
+# - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
+
+install:
+ - tzutil /s "Tokyo Standard Time"
+ # - choco install -y imdisk-toolkit
+ # - mkdir tmp
+ # - imdisk -a -t file -m tmp -o awe -s 1G -p "/fs:ntfs /q /y"
+
+build_script:
+ - git submodule update --init
+ - cd vendor
+ - ruby download_mecab.rb
+ - ruby download_message_pack.rb
+ - ruby download_lz4.rb
+ - cd ..
+ - set CMAKE_GENERATOR_NAME=Visual Studio %VS_VERSION%
+ - if "%VS_VERSION%" == "12"
+ set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% 2013
+ - if "%VS_VERSION%" == "14"
+ set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% 2015
+ - if "%ARCH%" == "amd64"
+ set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64
+ - cmake . -G "%CMAKE_GENERATOR_NAME%"
+ -DCMAKE_INSTALL_PREFIX=c:\groonga
+ -DGRN_WITH_MRUBY=yes
+ -DGRN_WITH_BUNDLED_MECAB=yes
+ -DGRN_WITH_BUNDLED_MESSAGE_PACK=yes
+ -DGRN_WITH_BUNDLED_LZ4=yes
+ - cmake --build . --config Debug
+ - cmake --build . --config Debug --target Install
+
+before_test:
+ - git clone --depth 1
+ https://github.com/groonga/grntest.git
+ test\command\grntest
+ - cd test\command\grntest
+ - bundle install --binstubs=..\bin
+ - cd ..\..\..
+test_script:
+ - ruby test\command\bin\grntest
+ --groonga c:\groonga\bin\groonga.exe
+ --base-directory test\command
+ --reporter mark
+ --n-workers 1
+ --timeout 60
+ test\command\suite
diff --git a/storage/mroonga/vendor/groonga/autogen.sh b/storage/mroonga/vendor/groonga/autogen.sh
new file mode 100755
index 00000000..98dcc83a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/autogen.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+./version-gen.sh
+
+case `uname -s` in
+Darwin)
+ homebrew_aclocal=/usr/local/share/aclocal
+ if [ -d $homebrew_aclocal ]; then
+ ACLOCAL_PATH="$ACLOCAL_PATH $homebrew_aclocal"
+ fi
+ gettext_prefix=/usr/local/Cellar/gettext
+ if [ -d $gettext_prefix ]; then
+ gettext_aclocal=$(ls $gettext_prefix/*/share/aclocal | \
+ gsort --version-sort | \
+ tail -n 1)
+ if [ -d $gettext_aclocal ]; then
+ ACLOCAL_PATH="$ACLOCAL_PATH $gettext_aclocal"
+ fi
+ fi
+ ;;
+FreeBSD)
+ ACLOCAL_PATH="$ACLOCAL_PATH /usr/local/share/aclocal/"
+ ;;
+esac
+
+if [ ! -e vendor/mruby-source/.git ]; then
+ rm -rf vendor/mruby-source
+fi
+git submodule update --init
+
+mkdir -p m4
+
+${AUTORECONF:-autoreconf} --force --install "$@"
diff --git a/storage/mroonga/vendor/groonga/base_version b/storage/mroonga/vendor/groonga/base_version
new file mode 100644
index 00000000..bf993904
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/base_version
@@ -0,0 +1 @@
+7.0.7 \ No newline at end of file
diff --git a/storage/mroonga/vendor/groonga/benchmark/Makefile.am b/storage/mroonga/vendor/groonga/benchmark/Makefile.am
new file mode 100644
index 00000000..a2a8b29a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/Makefile.am
@@ -0,0 +1,153 @@
+SUBDIRS = \
+ fixtures \
+ lib
+
+NONEXISTENT_CXX_SOURCE = nonexistent.cpp
+
+if WITH_BENCHMARK
+noinst_PROGRAMS = \
+ bench-table-factory \
+ bench-geo-distance \
+ bench-geo-select \
+ bench-ctx-create \
+ bench-query-optimizer \
+ bench-range-select \
+ bench-result-set \
+ bench-between-sequential \
+ bench-nfkc \
+ bench-cache
+endif
+
+EXTRA_DIST = \
+ bench-geo-select.sh \
+ bench-query-optimizer-ddl.grn \
+ geo-select-generate-grn.rb
+
+AM_CPPFLAGS = \
+ -I$(srcdir) \
+ -I$(srcdir)/lib \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib \
+ $(GROONGA_INCLUDEDIR)
+
+AM_CFLAGS = \
+ $(GLIB_CFLAGS)
+
+LIBS = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(top_builddir)/benchmark/lib/libbenchmark.la \
+ $(GLIB_LIBS)
+
+bench_table_factory_SOURCES = bench-table-factory.c
+nodist_EXTRA_bench_table_factory_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_geo_distance_SOURCES = bench-geo-distance.c
+nodist_EXTRA_bench_geo_distance_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_geo_select_SOURCES = bench-geo-select.c
+nodist_EXTRA_bench_geo_select_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_ctx_create_SOURCES = bench-ctx-create.c
+nodist_EXTRA_bench_ctx_create_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_query_optimizer_SOURCES = bench-query-optimizer.c
+nodist_EXTRA_bench_query_optimizer_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_range_select_SOURCES = bench-range-select.c
+nodist_EXTRA_bench_range_select_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_result_set_SOURCES = bench-result-set.c
+nodist_EXTRA_bench_result_set_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_between_sequential_SOURCES = bench-between-sequential.c
+nodist_EXTRA_bench_between_sequential_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_nfkc_SOURCES = bench-nfkc.c
+nodist_EXTRA_bench_nfkc_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+bench_cache_SOURCES = bench-cache.c
+nodist_EXTRA_bench_cache_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+
+benchmarks = \
+ run-bench-table-factory \
+ run-bench-geo-distance \
+ run-bench-geo-select \
+ run-bench-ctx-create \
+ run-bench-query-optimizer \
+ run-bench-range-select \
+ run-bench-result-set \
+ run-bench-between-sequential \
+ run-bench-nfkc \
+ run-bench-cache
+
+run-bench-table-factory: bench-table-factory
+ @echo $@:
+ env \
+ GRN_RUBY_SCRIPTS_DIR="$(top_srcdir)/lib/mrb/scripts" \
+ ./bench-table-factory
+
+run-bench-geo-distance: bench-geo-distance
+ @echo $@:
+ env \
+ GRN_RUBY_SCRIPTS_DIR="$(top_srcdir)/lib/mrb/scripts" \
+ ./bench-geo-distance
+
+run-bench-geo-select: bench-geo-select
+ @echo $@:
+ env \
+ RUBY="$(RUBY)" \
+ GROONGA="$(GROONGA)" \
+ GRN_RUBY_SCRIPTS_DIR="$(top_srcdir)/lib/mrb/scripts" \
+ srcdir="$(srcdir)" \
+ $(srcdir)/bench-geo-select.sh
+
+run-bench-ctx-create: bench-ctx-create
+ @echo $@:
+ env \
+ GRN_RUBY_SCRIPTS_DIR="$(top_srcdir)/lib/mrb/scripts" \
+ ./bench-ctx-create
+
+run-bench-query-optimizer: bench-query-optimizer
+ @echo $@:
+ @rm -rf tmp/query-optimizer
+ @mkdir -p tmp/query-optimizer
+ @env \
+ GRN_RUBY_SCRIPTS_DIR=$(top_srcdir)/lib/mrb/scripts \
+ ../src/groonga \
+ --file $(srcdir)/bench-query-optimizer-ddl.grn \
+ -n tmp/query-optimizer/db > /dev/null
+ env \
+ GRN_RUBY_SCRIPTS_DIR=$(top_srcdir)/lib/mrb/scripts \
+ ./bench-query-optimizer
+
+run-bench-range-select: bench-range-select
+ @echo $@:
+ @[ ! -e tmp ] && ln -s /dev/shm tmp || :
+ @mkdir -p tmp/range-select
+ env \
+ GRN_RUBY_SCRIPTS_DIR=$(top_srcdir)/lib/mrb/scripts \
+ ./bench-range-select
+
+run-bench-result-set: bench-result-set
+ @echo $@:
+ env \
+ GRN_RUBY_SCRIPTS_DIR="$(top_srcdir)/lib/mrb/scripts" \
+ ./bench-result-set
+
+run-bench-between-sequential: bench-between-sequential
+ @echo $@:
+ @[ ! -e tmp ] && ln -s /dev/shm tmp || :
+ @mkdir -p tmp/between-sequential
+ env \
+ GRN_RUBY_SCRIPTS_DIR="$(top_srcdir)/lib/mrb/scripts" \
+ ./bench-between-sequential
+
+run-bench-nfkc: bench-nfkc
+ @echo $@:
+ ./bench-nfkc
+
+run-bench-cache: bench-cache
+ @echo $@:
+ ./bench-cache
+
+benchmark: $(benchmarks)
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-between-sequential.c b/storage/mroonga/vendor/groonga/benchmark/bench-between-sequential.c
new file mode 100644
index 00000000..f0b7cf05
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-between-sequential.c
@@ -0,0 +1,276 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
+
+ CFLAGS: -O2 -g
+
+ Groonga: e2971d9a555a90724b76964cc8c8805373500b4a
+ % make --quiet -C benchmark run-bench-between-sequential
+ run-bench-between-sequential:
+ Process 10 times in each pattern
+ (total) (average) (median)
+ ( 500, 600] ( 1000): between: (0.0528s) (0.0053s) (0.0043s)
+ ( 500, 600] ( 1000): range: (0.0120s) (0.0012s) (0.2500ms)
+ ( 5000, 5100] ( 10000): between: (0.4052s) (0.0405s) (0.0395s)
+ ( 5000, 5100] ( 10000): range: (0.0197s) (0.0020s) (0.0010s)
+ ( 50000, 50100] ( 100000): between: (3.9343s) (0.3934s) (0.3900s)
+ ( 50000, 50100] ( 100000): range: (0.0969s) (0.0097s) (0.0088s)
+ (500000, 500100] (1000000): between: (38.2969s) (3.8297s) (3.7983s)
+ (500000, 500100] (1000000): range: (0.9158s) (0.0916s) (0.0900s)
+
+ Groonga: 35e4e431bb7660b3170e98c329f7219bd6723f05
+ % make --quiet -C benchmark run-bench-between-sequential
+ run-bench-between-sequential:
+ Process 10 times in each pattern
+ (total) (average) (median)
+ ( 500, 600] ( 1000): between: (0.0130s) (0.0013s) (0.2590ms)
+ ( 500, 600] ( 1000): range: (0.0124s) (0.0012s) (0.2530ms)
+ ( 5000, 5100] ( 10000): between: (0.0163s) (0.0016s) (0.6440ms)
+ ( 5000, 5100] ( 10000): range: (0.0205s) (0.0021s) (0.0011s)
+ ( 50000, 50100] ( 100000): between: (0.0611s) (0.0061s) (0.0051s)
+ ( 50000, 50100] ( 100000): range: (0.1004s) (0.0100s) (0.0091s)
+ (500000, 500100] (1000000): between: (0.4518s) (0.0452s) (0.0442s)
+ (500000, 500100] (1000000): range: (0.8866s) (0.0887s) (0.0878s)
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grn_db.h>
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+#define GET(context, name) (grn_ctx_get(context, name, strlen(name)))
+
+typedef struct _BenchmarkData
+{
+ grn_ctx context;
+ grn_obj *database;
+ guint n_records;
+ const gchar *command;
+} BenchmarkData;
+
+static void
+run_command(grn_ctx *context, const gchar *command)
+{
+ gchar *response;
+ unsigned int response_length;
+ int flags;
+
+ grn_ctx_send(context, command, strlen(command), 0);
+ grn_ctx_recv(context, &response, &response_length, &flags);
+}
+
+static void
+bench(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_ctx *context = &(data->context);
+
+ run_command(context, data->command);
+}
+
+static gchar *
+get_tmp_dir(void)
+{
+ gchar *current_dir;
+ gchar *tmp_dir;
+
+ current_dir = g_get_current_dir();
+ tmp_dir = g_build_filename(current_dir, "tmp", NULL);
+ g_free(current_dir);
+
+ return tmp_dir;
+}
+
+static void
+setup_database(BenchmarkData *data)
+{
+ grn_ctx *context = &(data->context);
+ gchar *tmp_dir;
+ gchar *database_last_component_name;
+ gchar *database_path;
+ guint i;
+
+ tmp_dir = get_tmp_dir();
+ database_last_component_name = g_strdup_printf("db-%d", data->n_records);
+ database_path = g_build_filename(tmp_dir,
+ "between-sequential",
+ database_last_component_name,
+ NULL);
+ g_free(database_last_component_name);
+
+ if (g_file_test(database_path, G_FILE_TEST_EXISTS)) {
+ data->database = grn_db_open(context, database_path);
+ run_command(context, "dump");
+ } else {
+ data->database = grn_db_create(context, database_path, NULL);
+
+ run_command(context, "table_create Entries TABLE_NO_KEY");
+ run_command(context, "column_create Entries rank COLUMN_SCALAR Int32");
+
+ run_command(context, "load --table Entries");
+ run_command(context, "[");
+ for (i = 0; i < data->n_records; i++) {
+#define BUFFER_SIZE 4096
+ gchar buffer[BUFFER_SIZE];
+ const gchar *separator;
+ if (i == (data->n_records - 1)) {
+ separator = "";
+ } else {
+ separator = ",";
+ }
+ snprintf(buffer, BUFFER_SIZE, "{\"rank\": %u}%s", i, separator);
+ run_command(context, buffer);
+#undef BUFFER_SIZE
+ }
+ run_command(context, "]");
+ }
+
+ g_free(database_path);
+}
+
+static void
+bench_startup(BenchmarkData *data)
+{
+ grn_ctx_init(&(data->context), 0);
+ setup_database(data);
+}
+
+static void
+bench_shutdown(BenchmarkData *data)
+{
+ grn_ctx *context = &(data->context);
+
+ grn_obj_close(context, data->database);
+ grn_ctx_fin(context);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchReporter *reporter;
+ gint n = 10;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+
+ g_print("Process %d times in each pattern\n", n);
+
+ bench_init(&argc, &argv);
+ reporter = bench_reporter_new();
+
+ {
+ BenchmarkData data_small_between;
+ BenchmarkData data_small_range;
+ BenchmarkData data_medium_between;
+ BenchmarkData data_medium_range;
+ BenchmarkData data_large_between;
+ BenchmarkData data_large_range;
+ BenchmarkData data_very_large_between;
+ BenchmarkData data_very_large_range;
+
+#define REGISTER(data, n_records_, min, max, is_between) \
+ do { \
+ gchar *label; \
+ label = \
+ g_strdup_printf("(%6d, %6d] (%7d): %7s", \
+ min, max, n_records_, \
+ is_between ? "between" : "range"); \
+ data.n_records = n_records_; \
+ if (is_between) { \
+ data.command = \
+ "select Entries --cache no " \
+ "--filter " \
+ "'between(rank, " #min ", \"exclude\"," \
+ " " #max ", \"include\")'"; \
+ } else { \
+ data.command = \
+ "select Entries --cache no " \
+ "--filter 'rank > " #min " && rank <= " #max "'"; \
+ } \
+ bench_startup(&data); \
+ bench_reporter_register(reporter, label, \
+ n, \
+ NULL, \
+ bench, \
+ NULL, \
+ &data); \
+ g_free(label); \
+ } while(FALSE)
+
+ REGISTER(data_small_between,
+ 1000,
+ 500, 600,
+ TRUE);
+ REGISTER(data_small_range,
+ 1000,
+ 500, 600,
+ FALSE);
+ REGISTER(data_medium_between,
+ 10000,
+ 5000, 5100,
+ TRUE);
+ REGISTER(data_medium_range,
+ 10000,
+ 5000, 5100,
+ FALSE);
+ REGISTER(data_large_between,
+ 100000,
+ 50000, 50100,
+ TRUE);
+ REGISTER(data_large_range,
+ 100000,
+ 50000, 50100,
+ FALSE);
+ REGISTER(data_very_large_between,
+ 1000000,
+ 500000, 500100,
+ TRUE);
+ REGISTER(data_very_large_range,
+ 1000000,
+ 500000, 500100,
+ FALSE);
+
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+
+ bench_shutdown(&data_small_between);
+ bench_shutdown(&data_small_range);
+ bench_shutdown(&data_medium_between);
+ bench_shutdown(&data_medium_range);
+ bench_shutdown(&data_large_between);
+ bench_shutdown(&data_large_range);
+ bench_shutdown(&data_very_large_between);
+ bench_shutdown(&data_very_large_range);
+ }
+ g_object_unref(reporter);
+
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-cache.c b/storage/mroonga/vendor/groonga/benchmark/bench-cache.c
new file mode 100644
index 00000000..104a7c19
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-cache.c
@@ -0,0 +1,155 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2017 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Groonga: eb65125330b3a8f920693ef3ad53011c7412f2c9
+ CFLAGS: -O2 -g3
+ CPU: Intel(R) Core(TM) i7-6700 CPU @ 3.40GHz
+
+ % make --silent -C benchmark run-bench-cache
+ run-bench-cache:
+ (total) (average) (median)
+ 1000: (0.0458s) (0.4576ms) (0.4170ms)
+ 10000: (0.3464s) (0.0035s) (0.0034s)
+ % GRN_CACHE_TYPE=persistent make --silent -C benchmark run-bench-cache
+ run-bench-cache:
+ (total) (average) (median)
+ 1000: (0.0480s) (0.4801ms) (0.4700ms)
+ 10000: (0.4033s) (0.0040s) (0.0040s)
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <grn_cache.h>
+
+#include "lib/benchmark.h"
+
+typedef struct _BenchmarkData
+{
+ grn_ctx *context;
+ grn_cache *cache;
+ grn_obj value;
+} BenchmarkData;
+
+static void
+bench_n(BenchmarkData *data, gint64 n)
+{
+ gint64 i;
+ grn_ctx *ctx;
+ grn_cache *cache;
+ grn_obj *value;
+ grn_obj fetch_buffer;
+
+ ctx = data->context;
+ cache = data->cache;
+ value = &(data->value);
+ GRN_TEXT_INIT(&fetch_buffer, 0);
+ for (i = 0; i < n; i++) {
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ grn_snprintf(key,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "key:%" GRN_FMT_INT64D,
+ i);
+ GRN_BULK_REWIND(&fetch_buffer);
+ grn_cache_fetch(ctx, cache, key, strlen(key), &fetch_buffer);
+ grn_cache_update(ctx, cache, key, strlen(key), value);
+ }
+ GRN_OBJ_FIN(ctx, &fetch_buffer);
+}
+
+static void
+bench_1000(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ bench_n(data, 1000);
+}
+
+static void
+bench_10000(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ bench_n(data, 10000);
+}
+
+static void
+bench_setup(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ data->cache = grn_cache_open(data->context);
+ GRN_TEXT_INIT(&(data->value), 0);
+ while (GRN_TEXT_LEN(&(data->value)) < 1024) {
+ GRN_TEXT_PUTS(data->context, &(data->value), "XXXXXXXXXXX");
+ }
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_obj_close(data->context, &(data->value));
+ grn_cache_close(data->context, data->cache);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchmarkData data;
+ BenchReporter *reporter;
+ gchar *base_dir;
+ grn_ctx ctx;
+ gint n = 100;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ grn_ctx_init(&ctx, 0);
+
+ data.context = &ctx;
+
+ base_dir = g_build_filename(g_get_tmp_dir(), "groonga-bench", NULL);
+ bench_utils_remove_path_recursive_force(base_dir);
+ g_mkdir_with_parents(base_dir, 0755);
+
+ reporter = bench_reporter_new();
+ bench_reporter_register(reporter, "1000", n,
+ bench_setup, bench_1000, bench_teardown, &data);
+ bench_reporter_register(reporter, "10000", n,
+ bench_setup, bench_10000, bench_teardown, &data);
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ grn_ctx_fin(&ctx);
+
+ bench_utils_remove_path_recursive_force(base_dir);
+
+ bench_quit();
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-ctx-create.c b/storage/mroonga/vendor/groonga/benchmark/bench-ctx-create.c
new file mode 100644
index 00000000..576ac8ee
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-ctx-create.c
@@ -0,0 +1,198 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2013-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Groonga: 6b128f318d682e50648f3b82c5f7956f3bcb3fe8
+ CFLAGS: -O0 -g3
+ % (cd benchmark/ && make --quiet run-bench-ctx-create)
+ run-bench-ctx-create:
+ (time)
+ with mruby1: 288KB (0.0091s)
+ without mruby1: 28KB (0.0240ms)
+ with mruby2: 0KB (0.0097s)
+ without mruby2: 0KB (0.0220ms)
+
+ Groonga: c4379140c02699e3c74b94cd9e7b88d372202aa5
+ CFLAGS: -O2 -g
+ % make --quiet -C benchmark run-bench-ctx-create
+ run-bench-ctx-create:
+ (time)
+ with mruby1: 524KB (0.0041s)
+ without mruby1: 32KB (0.0220ms)
+ with mruby2: 0KB (0.0040s)
+ without mruby2: 0KB (0.0200ms)
+*/
+
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+typedef struct _BenchmarkData {
+ grn_ctx context;
+ grn_obj *database;
+ guint memory_usage_before;
+} BenchmarkData;
+
+static guint
+get_memory_usage(void)
+{
+ GRegex *vm_rss_pattern;
+ gchar *status;
+ GMatchInfo *match_info;
+ gchar *vm_rss_string;
+ guint vm_rss;
+
+ g_file_get_contents("/proc/self/status", &status, NULL, NULL);
+
+ vm_rss_pattern = g_regex_new("VmRSS:\\s*(\\d*)\\s+kB", 0, 0, NULL);
+ if (!g_regex_match(vm_rss_pattern, status, 0, &match_info)) {
+ g_print("not match...: %s\n", status);
+ return 0;
+ }
+ vm_rss_string = g_match_info_fetch(match_info, 1);
+ vm_rss = atoi(vm_rss_string);
+ g_free(vm_rss_string);
+ g_match_info_free(match_info);
+ g_regex_unref(vm_rss_pattern);
+ g_free(status);
+
+ return vm_rss;
+}
+
+static void
+bench_with_mruby(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ g_setenv("GRN_MRUBY_ENABLED", "yes", TRUE);
+ grn_ctx_init(&(data->context), 0);
+ grn_ctx_use(&(data->context), data->database);
+}
+
+static void
+bench_without_mruby(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ g_setenv("GRN_MRUBY_ENABLED", "no", TRUE);
+ grn_ctx_init(&(data->context), 0);
+ grn_ctx_use(&(data->context), data->database);
+}
+
+static void
+bench_setup(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ data->memory_usage_before = get_memory_usage();
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_ctx_fin(&(data->context));
+ g_print("%3dKB ", get_memory_usage() - data->memory_usage_before);
+}
+
+static gchar *
+get_tmp_dir(void)
+{
+ gchar *current_dir;
+ gchar *tmp_dir;
+
+ current_dir = g_get_current_dir();
+ tmp_dir = g_build_filename(current_dir, "tmp", NULL);
+ g_free(current_dir);
+
+ return tmp_dir;
+}
+
+static grn_obj *
+setup_database(grn_ctx *context)
+{
+ gchar *tmp_dir;
+ gchar *database_path;
+ grn_obj *database;
+
+ tmp_dir = get_tmp_dir();
+ database_path = g_build_filename(tmp_dir, "ctx-create", "db", NULL);
+ database = grn_db_open(context, database_path);
+
+ g_free(database_path);
+
+ return database;
+}
+
+static void
+teardown_database(grn_ctx *context, grn_obj *database)
+{
+ grn_obj_close(context, database);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ grn_ctx context;
+ BenchmarkData data;
+ BenchReporter *reporter;
+ gint n = 1;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ grn_ctx_init(&context, 0);
+
+ data.database = setup_database(&context);
+
+ reporter = bench_reporter_new();
+
+#define REGISTER(label, bench_function) \
+ bench_reporter_register(reporter, label, n, \
+ bench_setup, \
+ bench_function, \
+ bench_teardown, \
+ &data)
+ REGISTER("with mruby1", bench_with_mruby);
+ REGISTER("without mruby1", bench_without_mruby);
+ REGISTER("with mruby2", bench_with_mruby);
+ REGISTER("without mruby2", bench_without_mruby);
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ teardown_database(&context, data.database);
+
+ grn_ctx_fin(&context);
+
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-geo-distance.c b/storage/mroonga/vendor/groonga/benchmark/bench-geo-distance.c
new file mode 100644
index 00000000..0b648a1c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-geo-distance.c
@@ -0,0 +1,506 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2009-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ groonga: 3ad91b868909444f66a36dbcbdbe2292ed14bd72
+ CFLAGS: -O0 -g
+ CPU: AMD Athlon(tm) 64 Processor 3000+
+
+ % test/benchmark/bench-geo-distance
+ (time)
+ rectangular (WGS84): (0.0813662)
+ rectangular (TOKYO): (0.0621928)
+ spherical (WGS84): (0.0760155)
+ spherical (TOKYO): (0.0660843)
+ hubeny (WGS84): (0.110684)
+ hubeny (TOKYO): (0.0702277)
+ % test/benchmark/bench-geo-distance
+ (time)
+ rectangular (WGS84): (0.0742154)
+ rectangular (TOKYO): (0.0816863)
+ spherical (WGS84): (0.074316)
+ spherical (TOKYO): (0.0696254)
+ hubeny (WGS84): (0.0650147)
+ hubeny (TOKYO): (0.0644057)
+ % test/benchmark/bench-geo-distance
+ (time)
+ rectangular (WGS84): (0.0781161)
+ rectangular (TOKYO): (0.0706679)
+ spherical (WGS84): (0.075739)
+ spherical (TOKYO): (0.0809402)
+ hubeny (WGS84): (0.0727023)
+ hubeny (TOKYO): (0.0718146)
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <grn_db.h>
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+#define GET(context, name) (grn_ctx_get(context, name, strlen(name)))
+
+grn_obj *grn_expr_get_value(grn_ctx *ctx, grn_obj *expr, int offset);
+
+typedef struct _BenchmarkData
+{
+ gchar *base_dir;
+ gboolean report_result;
+
+ grn_ctx *context;
+ grn_obj *database;
+ grn_obj *geo_distance_proc;
+ grn_obj *expression;
+ grn_obj *start_point;
+ grn_obj *end_point;
+} BenchmarkData;
+
+static void
+bench_geo_distance(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_proc_call(data->context, data->geo_distance_proc,
+ 2, data->expression);
+}
+
+static void
+bench_setup_common(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_ctx_init(data->context, GRN_CTX_USE_QL);
+ data->database = grn_db_create(data->context, NULL, NULL);
+ data->expression = grn_expr_create(data->context, NULL, 0);
+}
+
+static void
+bench_setup_points(gpointer user_data,
+ const gchar *start_point_string,
+ const gchar *end_point_string,
+ grn_builtin_type wgs84_or_tgs)
+{
+ BenchmarkData *data = user_data;
+ grn_obj start_point_text, end_point_text;
+
+ GRN_TEXT_INIT(&start_point_text, 0);
+ GRN_TEXT_INIT(&end_point_text, 0);
+ GRN_TEXT_SETS(data->context, &start_point_text, start_point_string);
+ GRN_TEXT_SETS(data->context, &end_point_text, end_point_string);
+
+ data->start_point = grn_obj_open(data->context, GRN_BULK, 0, wgs84_or_tgs);
+ data->end_point = grn_obj_open(data->context, GRN_BULK, 0, wgs84_or_tgs);
+ grn_obj_cast(data->context, &start_point_text, data->start_point, GRN_FALSE);
+ grn_obj_cast(data->context, &end_point_text, data->end_point, GRN_FALSE);
+ grn_ctx_push(data->context, data->start_point);
+ grn_ctx_push(data->context, data->end_point);
+
+ grn_obj_unlink(data->context, &start_point_text);
+ grn_obj_unlink(data->context, &end_point_text);
+}
+
+static void
+bench_setup_wgs84(gpointer user_data)
+{
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "127980000x502560000",
+ "128880000x503640000",
+ GRN_DB_WGS84_GEO_POINT);
+}
+
+static void
+bench_setup_tgs(gpointer user_data)
+{
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "127980000x502560000",
+ "128880000x503640000",
+ GRN_DB_TOKYO_GEO_POINT);
+}
+
+static void
+bench_setup_rectangular_wgs84(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_wgs84(user_data);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_tgs(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_tgs(user_data);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_1st_to_2nd_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "128452975x503157902",
+ "139380000x-31920000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_2nd_to_1st_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "139380000x-31920000",
+ "128452975x503157902",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_1st_to_3rd_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "128452975x503157902",
+ "-56880000x-172310000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_3rd_to_1st_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-56880000x-172310000",
+ "128452975x503157902",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_1st_to_4th_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "128452975x503157902",
+ "-122100000x66300000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_4th_to_1st_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-122100000x66300000",
+ "128452975x503157902",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_2nd_to_4th_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "139380000x-31920000",
+ "-122100000x66300000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_4th_to_2nd_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-122100000x66300000",
+ "139380000x-31920000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_1st_to_2nd_quadrant_long(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "128452975x503157902",
+ "135960000x-440760000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_2nd_to_1st_quadrant_long(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "135960000x-440760000",
+ "128452975x503157902",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_2nd_to_3rd_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "135960000x-440760000",
+ "-56880000x-172310000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_3rd_to_2nd_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-56880000x-172310000",
+ "135960000x-440760000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_3rd_to_4th_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-56880000x-172310000",
+ "-122100000x66300000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_4th_to_3rd_quadrant_short(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-122100000x66300000",
+ "-56880000x-172310000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_3rd_to_4th_quadrant_long(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-56880000x-172310000",
+ "-121926000x544351000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_rectangular_wgs84_4th_to_3rd_quadrant_long(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_common(user_data);
+ bench_setup_points(user_data,
+ "-121926000x544351000",
+ "-56880000x-172310000",
+ GRN_DB_WGS84_GEO_POINT);
+ data->geo_distance_proc = GET(data->context, "geo_distance");
+}
+
+static void
+bench_setup_spherical_wgs84(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_wgs84(user_data);
+ data->geo_distance_proc = GET(data->context, "geo_distance2");
+}
+
+static void
+bench_setup_spherical_tgs(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_tgs(user_data);
+ data->geo_distance_proc = GET(data->context, "geo_distance2");
+}
+
+static void
+bench_setup_hubeny_wgs84(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_wgs84(user_data);
+ data->geo_distance_proc = GET(data->context, "geo_distance3");
+}
+
+static void
+bench_setup_hubeny_tgs(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ bench_setup_tgs(user_data);
+ data->geo_distance_proc = GET(data->context, "geo_distance3");
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ if (data->report_result) {
+ grn_obj *result;
+ result = grn_expr_get_value(data->context, data->expression, 0);
+ g_print("result: %g\n", GRN_FLOAT_VALUE(result));
+ /* http://vldb.gsi.go.jp/ says '38820.79' in WGS84 and
+ '38816.42' in Tokyo geodetic system for a distance
+ between '127980000x502560000' and '128880000x503640000'. */
+ }
+
+ grn_obj_unlink(data->context, data->end_point);
+ grn_obj_unlink(data->context, data->start_point);
+ grn_obj_unlink(data->context, data->expression);
+ grn_obj_unlink(data->context, data->database);
+ grn_ctx_fin(data->context);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchmarkData data;
+ BenchReporter *reporter;
+ gint n = 1000;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ data.report_result = g_getenv("GROONGA_BENCH_REPORT_RESULT") != NULL;
+ data.context = g_new(grn_ctx, 1);
+
+ {
+ const gchar *groonga_bench_n;
+ groonga_bench_n = g_getenv("GROONGA_BENCH_N");
+ if (groonga_bench_n) {
+ n = atoi(groonga_bench_n);
+ }
+ }
+
+ reporter = bench_reporter_new();
+
+#define REGISTER(label, setup) \
+ bench_reporter_register(reporter, label, n, \
+ bench_setup_ ## setup, \
+ bench_geo_distance, \
+ bench_teardown, \
+ &data)
+ REGISTER("rectangular (WGS84)", rectangular_wgs84);
+ REGISTER("rectangular (TOKYO)", rectangular_tgs);
+ REGISTER("rectangular (WGS84 Tokyo to Lisbon)",
+ rectangular_wgs84_1st_to_2nd_quadrant_short);
+ REGISTER("rectangular (WGS84 Lisbon to Tokyo)",
+ rectangular_wgs84_2nd_to_1st_quadrant_short);
+ REGISTER("rectangular (WGS84 Tokyo to San Francisco)",
+ rectangular_wgs84_1st_to_2nd_quadrant_long);
+ REGISTER("rectangular (WGS84 San Francisco to Tokyo)",
+ rectangular_wgs84_2nd_to_1st_quadrant_long);
+ REGISTER("rectangular (WGS84 Brasplia to Cape Town)",
+ rectangular_wgs84_3rd_to_4th_quadrant_short);
+ REGISTER("rectangular (WGS84 Cape Town to Brasplia)",
+ rectangular_wgs84_4th_to_3rd_quadrant_short);
+ REGISTER("rectangular (WGS84 Brasplia to Sydney)",
+ rectangular_wgs84_3rd_to_4th_quadrant_long);
+ REGISTER("rectangular (WGS84 Sydney to Brasplia)",
+ rectangular_wgs84_4th_to_3rd_quadrant_long);
+ REGISTER("rectangular (WGS84 Tokyo to Brasplia)",
+ rectangular_wgs84_1st_to_4th_quadrant_short);
+ REGISTER("rectangular (WGS84 Brasplia to Tokyo)",
+ rectangular_wgs84_4th_to_1st_quadrant_short);
+ REGISTER("rectangular (WGS84 Lisbon to Cape Town)",
+ rectangular_wgs84_2nd_to_3rd_quadrant_short);
+ REGISTER("rectangular (WGS84 Cape Town to Lisbon)",
+ rectangular_wgs84_3rd_to_2nd_quadrant_short);
+ REGISTER("rectangular (WGS84 Tokyo to Cape Town)",
+ rectangular_wgs84_1st_to_3rd_quadrant_short);
+ REGISTER("rectangular (WGS84 Cape Town to Tokyo)",
+ rectangular_wgs84_3rd_to_1st_quadrant_short);
+ REGISTER("rectangular (WGS84 Lisbon to Cape Town)",
+ rectangular_wgs84_2nd_to_4th_quadrant_short);
+ REGISTER("rectangular (WGS84 Cape Town to Lisbon)",
+ rectangular_wgs84_4th_to_2nd_quadrant_short);
+ REGISTER("spherical (WGS84)", spherical_wgs84);
+ REGISTER("spherical (TOKYO)", spherical_tgs);
+ REGISTER("hubeny (WGS84)", hubeny_wgs84);
+ REGISTER("hubeny (TOKYO)", hubeny_tgs);
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ g_free(data.context);
+
+ bench_quit();
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-geo-select.c b/storage/mroonga/vendor/groonga/benchmark/bench-geo-select.c
new file mode 100644
index 00000000..dcad47fd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-geo-select.c
@@ -0,0 +1,276 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2011-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ groonga: f56f466a05d756336f26ea5c2e54e9bdf5d3d681
+ CFLAGS: -O0 -ggdb3
+ CPU: Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz stepping 05
+ % (cd test/benchmark/ && make --quiet run-bench-geo-select)
+ run-bench-geo-select:
+ (time)
+ 1st: select_in_rectangle (partial): (0.819828)
+ 2nd: select_in_rectangle (partial): (0.832293)
+ 1st: select_in_rectangle (all): (8.82504)
+ 2nd: select_in_rectangle (all): (8.97628)
+
+ % (cd test/benchmark; GRN_GEO_CURSOR_STRICTLY=yes make --quiet run-bench-geo-select)
+ run-bench-geo-select:
+ (time)
+ 1st: select_in_rectangle (partial): (0.528143)
+ 2nd: select_in_rectangle (partial): (0.518647)
+ 1st: select_in_rectangle (all): (8.77378)
+ 2nd: select_in_rectangle (all): (8.76765)
+
+ groonga: f56f466a05d756336f26ea5c2e54e9bdf5d3d681
+ CFLAGS: -O3 -ggdb3
+ CPU: Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz stepping 05
+ % (cd test/benchmark/ && make --quiet run-bench-geo-select)
+ run-bench-geo-select:
+ (time)
+ 1st: select_in_rectangle (partial): (0.415439)
+ 2nd: select_in_rectangle (partial): (0.423479)
+ 1st: select_in_rectangle (all): (4.63983)
+ 2nd: select_in_rectangle (all): (4.53055)
+
+ % (cd test/benchmark; GRN_GEO_CURSOR_STRICTLY=yes make --quiet run-bench-geo-select)
+ run-bench-geo-select:
+ (time)
+ 1st: select_in_rectangle (partial): (0.26974)
+ 2nd: select_in_rectangle (partial): (0.250247)
+ 1st: select_in_rectangle (all): (4.45263)
+ 2nd: select_in_rectangle (all): (4.61558)
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <grn_db.h>
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+#define GET(context, name) (grn_ctx_get(context, name, strlen(name)))
+
+typedef struct _BenchmarkData
+{
+ gboolean report_result;
+
+ grn_ctx *context;
+ grn_obj *database;
+ grn_obj *table;
+ grn_obj *index_column;
+ grn_obj *result;
+
+ grn_obj top_left_point;
+ grn_obj bottom_right_point;
+} BenchmarkData;
+
+static void
+set_geo_point(grn_ctx *context, grn_obj *geo_point, const gchar *geo_point_text)
+{
+ grn_obj point_text;
+
+ GRN_TEXT_INIT(&point_text, 0);
+ GRN_TEXT_PUTS(context, &point_text, geo_point_text);
+ grn_obj_cast(context, &point_text, geo_point, GRN_FALSE);
+ grn_obj_unlink(context, &point_text);
+}
+
+static void
+bench_setup_common(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ const gchar *tokyo_station = "35.68136,139.76609";
+ const gchar *ikebukuro_station = "35.72890,139.71036";
+
+ data->result = grn_table_create(data->context, NULL, 0, NULL,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
+ data->table, NULL);
+
+ set_geo_point(data->context, &(data->top_left_point),
+ ikebukuro_station);
+ set_geo_point(data->context, &(data->bottom_right_point),
+ tokyo_station);
+}
+
+static void
+bench_setup_query_partial(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ const gchar *tokyo_station = "35.68136,139.76609";
+ const gchar *ikebukuro_station = "35.72890,139.71036";
+
+ set_geo_point(data->context, &(data->top_left_point),
+ ikebukuro_station);
+ set_geo_point(data->context, &(data->bottom_right_point),
+ tokyo_station);
+}
+
+static void
+bench_setup_query_all(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ const gchar *tokyo_station = "35.0,140.0";
+ const gchar *ikebukuro_station = "36.0,139.0";
+
+ set_geo_point(data->context, &(data->top_left_point),
+ ikebukuro_station);
+ set_geo_point(data->context, &(data->bottom_right_point),
+ tokyo_station);
+}
+
+static void
+bench_setup_in_rectangle_partial(gpointer user_data)
+{
+ bench_setup_common(user_data);
+ bench_setup_query_partial(user_data);
+}
+
+static void
+bench_setup_in_rectangle_all(gpointer user_data)
+{
+ bench_setup_common(user_data);
+ bench_setup_query_all(user_data);
+}
+
+static void
+bench_geo_select_in_rectangle(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_geo_select_in_rectangle(data->context,
+ data->index_column,
+ &(data->top_left_point),
+ &(data->bottom_right_point),
+ data->result,
+ GRN_OP_OR);
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ if (data->report_result) {
+ g_print("result: %d\n", grn_table_size(data->context, data->result));
+ }
+
+ grn_obj_unlink(data->context, data->result);
+}
+
+static gchar *
+get_tmp_dir(void)
+{
+ gchar *current_dir;
+ gchar *tmp_dir;
+
+ current_dir = g_get_current_dir();
+ tmp_dir = g_build_filename(current_dir, "tmp", NULL);
+ g_free(current_dir);
+
+ return tmp_dir;
+}
+
+static void
+setup_database(BenchmarkData *data)
+{
+ gchar *tmp_dir;
+ gchar *database_path;
+
+ tmp_dir = get_tmp_dir();
+ database_path = g_build_filename(tmp_dir, "geo-select", "db", NULL);
+ data->database = grn_db_open(data->context, database_path);
+
+ data->table = GET(data->context, "Addresses");
+ data->index_column = GET(data->context, "Locations.address");
+
+ g_free(database_path);
+}
+
+static void
+teardown_database(BenchmarkData *data)
+{
+ grn_obj_unlink(data->context, data->index_column);
+ grn_obj_unlink(data->context, data->table);
+ grn_obj_unlink(data->context, data->database);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchmarkData data;
+ BenchReporter *reporter;
+ gint n = 100;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ data.report_result = g_getenv("GROONGA_BENCH_REPORT_RESULT") != NULL;
+
+ data.context = g_new(grn_ctx, 1);
+ grn_ctx_init(data.context, 0);
+
+ setup_database(&data);
+ GRN_WGS84_GEO_POINT_INIT(&(data.top_left_point), 0);
+ GRN_WGS84_GEO_POINT_INIT(&(data.bottom_right_point), 0);
+
+ {
+ const gchar *groonga_bench_n;
+ groonga_bench_n = g_getenv("GROONGA_BENCH_N");
+ if (groonga_bench_n) {
+ n = atoi(groonga_bench_n);
+ }
+ }
+
+ reporter = bench_reporter_new();
+
+#define REGISTER(label, type, area) \
+ bench_reporter_register(reporter, \
+ label, \
+ n, \
+ bench_setup_ ## type ## _ ## area, \
+ bench_geo_select_ ## type, \
+ bench_teardown, \
+ &data)
+ REGISTER("1st: select_in_rectangle (partial)", in_rectangle, partial);
+ REGISTER("2nd: select_in_rectangle (partial)", in_rectangle, partial);
+ REGISTER("1st: select_in_rectangle (all)", in_rectangle, all);
+ REGISTER("2nd: select_in_rectangle (all)", in_rectangle, all);
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ grn_obj_unlink(data.context, &(data.top_left_point));
+ grn_obj_unlink(data.context, &(data.bottom_right_point));
+ teardown_database(&data);
+
+ grn_ctx_fin(data.context);
+ g_free(data.context);
+
+ bench_quit();
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-geo-select.sh b/storage/mroonga/vendor/groonga/benchmark/bench-geo-select.sh
new file mode 100755
index 00000000..7e84c8fc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-geo-select.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+base_dir="$(dirname $0)"
+
+fixture_dir="${srcdir}/fixtures/geo-select"
+data_dir="${base_dir}/fixtures/geo-select"
+csv_xz="${fixture_dir}/13_2010.CSV.xz"
+csv="${data_dir}/13_2010.CSV"
+grn="${data_dir}/load.grn"
+
+geo_select_generate_grn_rb="${base_dir}/geo-select-generate-grn.rb"
+
+db="${base_dir}/tmp/geo-select/db"
+
+bench_geo_select="./bench-geo-select"
+
+mkdir -p "${data_dir}"
+if [ ! -s "${csv}" ] || [ "${csv}" -ot "${csv_xz}" ]; then
+ echo "extracting ${csv_xz}..."
+ xzcat "${csv_xz}" | iconv --from-code cp932 --to-code utf-8 > "${csv}"
+fi
+
+if [ ! -s "${grn}" ] || [ "${grn}" -ot "${csv}" ]; then
+ echo "generating test data..."
+ "${RUBY}" "${geo_select_generate_grn_rb}" "${csv}" "${grn}"
+fi
+
+if [ ! -s "${db}" ] || [ "${db}" -ot "${grn}" ]; then
+ echo "creating test database..."
+ rm -rf "$(dirname ${db})"
+ mkdir -p "$(dirname ${db})"
+ "${GROONGA}" -n "${db}" < "${grn}"
+fi
+
+if [ "${GROONGA_BENCH_DEBUG}" = "yes" ]; then
+ bench_geo_select="../../libtool --mode=execute gdb --args ${bench_geo_select}"
+fi
+${bench_geo_select}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-nfkc.c b/storage/mroonga/vendor/groonga/benchmark/bench-nfkc.c
new file mode 100644
index 00000000..ebae95b2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-nfkc.c
@@ -0,0 +1,275 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2015-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Groonga: ed300a833d44eaefa978b5ecf46a96ef91ae0891
+
+ CFLAGS: -O2 -g
+ % make --quiet -C benchmark run-bench-nfkc
+ run-bench-nfkc:
+ (total) (average) (median)
+ map1 - switch : (0.0060ms) (0.00060000ms) (0.00000000ms)
+ map1 - table : (0.00000000ms) (0.00000000ms) (0.00000000ms)
+ map2 - switch - no change: (0.0010ms) (0.00010000ms) (0.00000000ms)
+ map2 - table - no change: (0.00000000ms) (0.00000000ms) (0.00000000ms)
+ map2 - switch - change: (0.0010ms) (0.00010000ms) (0.00000000ms)
+ map2 - table - change: (0.0010ms) (0.00010000ms) (0.00000000ms)
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+#include "../lib/nfkc50.c"
+
+#define MAX_UNICODE 0x110000
+#define BUFFER_SIZE 0x100
+
+static inline int
+ucs2utf8(unsigned int i, unsigned char *buf)
+{
+ unsigned char *p = buf;
+ if (i < 0x80) {
+ *p++ = i;
+ } else {
+ if (i < 0x800) {
+ *p++ = (i >> 6) | 0xc0;
+ } else {
+ if (i < 0x00010000) {
+ *p++ = (i >> 12) | 0xe0;
+ } else {
+ if (i < 0x00200000) {
+ *p++ = (i >> 18) | 0xf0;
+ } else {
+ if (i < 0x04000000) {
+ *p++ = (i >> 24) | 0xf8;
+ } else if (i < 0x80000000) {
+ *p++ = (i >> 30) | 0xfc;
+ *p++ = ((i >> 24) & 0x3f) | 0x80;
+ }
+ *p++ = ((i >> 18) & 0x3f) | 0x80;
+ }
+ *p++ = ((i >> 12) & 0x3f) | 0x80;
+ }
+ *p++ = ((i >> 6) & 0x3f) | 0x80;
+ }
+ *p++ = (0x3f & i) | 0x80;
+ }
+ *p = '\0';
+ return (p - buf);
+}
+
+static void
+bench_char_type(gpointer user_data)
+{
+ uint64_t code_point;
+ char utf8[7];
+
+ for (code_point = 1; code_point < MAX_UNICODE; code_point++) {
+ ucs2utf8(code_point, (unsigned char *)utf8);
+ grn_nfkc50_char_type(utf8);
+ }
+}
+
+static void
+bench_decompose(gpointer user_data)
+{
+ uint64_t code_point;
+ char utf8[7];
+
+ for (code_point = 1; code_point < MAX_UNICODE; code_point++) {
+ ucs2utf8(code_point, (unsigned char *)utf8);
+ grn_nfkc50_decompose(utf8);
+ }
+}
+
+static void
+bench_compose_no_change(gpointer user_data)
+{
+ uint64_t prefix_code_point;
+ uint64_t suffix_code_point = 0x61; /* a */
+ char prefix_utf8[7];
+ char suffix_utf8[7];
+
+ ucs2utf8(suffix_code_point, (unsigned char *)suffix_utf8);
+ for (prefix_code_point = 1;
+ prefix_code_point < MAX_UNICODE;
+ prefix_code_point++) {
+ ucs2utf8(prefix_code_point, (unsigned char *)prefix_utf8);
+ grn_nfkc50_compose(prefix_utf8, suffix_utf8);
+ }
+}
+
+static void
+bench_compose_change(gpointer user_data)
+{
+ uint64_t prefix_code_point;
+ uint64_t suffix_code_point = 0x11ba;
+ char prefix_utf8[7];
+ char suffix_utf8[7];
+
+ ucs2utf8(suffix_code_point, (unsigned char *)suffix_utf8);
+ for (prefix_code_point = 1;
+ prefix_code_point < MAX_UNICODE;
+ prefix_code_point++) {
+ ucs2utf8(prefix_code_point, (unsigned char *)prefix_utf8);
+ grn_nfkc50_compose(prefix_utf8, suffix_utf8);
+ }
+}
+
+/*
+static void
+check_char_type(gpointer user_data)
+{
+ uint64_t code_point;
+ char utf8[7];
+
+ for (code_point = 1; code_point < MAX_UNICODE; code_point++) {
+ grn_char_type a;
+ grn_char_type b;
+
+ ucs2utf8(code_point, (unsigned char *)utf8);
+ a = grn_nfkc_char_type(utf8);
+ b = grn_nfkc50_char_type(utf8);
+ if (a == b) {
+ continue;
+ }
+ printf("%lx: %s: %d != %d\n", code_point, utf8, a, b);
+ }
+}
+
+static void
+check_decompose(gpointer user_data)
+{
+ uint64_t code_point;
+ char utf8[7];
+
+ for (code_point = 1; code_point < MAX_UNICODE; code_point++) {
+ const char *a;
+ const char *b;
+
+ ucs2utf8(code_point, (unsigned char *)utf8);
+ a = grn_nfkc_decompose(utf8);
+ b = grn_nfkc50_decompose(utf8);
+ if (a == b) {
+ continue;
+ }
+ if (!a || !b) {
+ printf("%lx: %s: %s != %s\n", code_point, utf8, a, b);
+ continue;
+ }
+ if (strcmp(a, b) != 0) {
+ printf("%lx: %s: %s != %s\n", code_point, utf8, a, b);
+ }
+ }
+}
+
+static void
+check_compose(gpointer user_data)
+{
+ uint64_t prefix_code_point;
+ uint64_t suffix_code_point;
+ char prefix_utf8[7];
+ char suffix_utf8[7];
+
+ for (prefix_code_point = 1;
+ prefix_code_point < MAX_UNICODE;
+ prefix_code_point++) {
+ ucs2utf8(prefix_code_point, (unsigned char *)prefix_utf8);
+ for (suffix_code_point = 1;
+ suffix_code_point < MAX_UNICODE;
+ suffix_code_point++) {
+ const char *a;
+ const char *b;
+
+ ucs2utf8(suffix_code_point, (unsigned char *)suffix_utf8);
+ a = grn_nfkc_compose(prefix_utf8, suffix_utf8);
+ b = grn_nfkc50_compose(prefix_utf8, suffix_utf8);
+ if (a == b) {
+ continue;
+ }
+ if (!a || !b) {
+ printf("%lx-%lx: %s-%s: %s != %s\n",
+ prefix_code_point, suffix_code_point,
+ prefix_utf8, suffix_utf8,
+ a, b);
+ continue;
+ }
+ if (strcmp(a, b) != 0) {
+ printf("%lx-%lx: %s-%s: %s != %s\n",
+ prefix_code_point, suffix_code_point,
+ prefix_utf8, suffix_utf8,
+ a, b);
+ }
+ }
+ if ((prefix_code_point % 10000) == 0) {
+ printf("%" G_GUINT64_FORMAT "\n", prefix_code_point);
+ }
+ }
+}
+*/
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchReporter *reporter;
+ gint n = 10;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ reporter = bench_reporter_new();
+
+ if (g_getenv("N")) {
+ n = atoi(g_getenv("N"));
+ }
+
+#define REGISTER(label, bench_function) \
+ bench_reporter_register(reporter, label, n, \
+ NULL, \
+ bench_function, \
+ NULL, \
+ NULL)
+ REGISTER("char_type ", bench_char_type);
+ REGISTER("decompose ", bench_decompose);
+ REGISTER("compose - no change", bench_compose_no_change);
+ REGISTER("compose - change", bench_compose_change);
+
+ /*
+ REGISTER("check - char_type", check_char_type);
+ REGISTER("check - decompose", check_decompose);
+ REGISTER("check - compose ", check_compose);
+ */
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer-ddl.grn b/storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer-ddl.grn
new file mode 100644
index 00000000..68317ae9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer-ddl.grn
@@ -0,0 +1,16 @@
+table_create Entries TABLE_PAT_KEY ShortText
+column_create Entries name COLUMN_SCALAR ShortText
+column_create Entries description COLUMN_SCALAR Text
+column_create Entries last_modified COLUMN_SCALAR Time
+
+table_create Bigram TABLE_PAT_KEY ShortText \
+ --default_tokenizer TokenBigram \
+ --normalizer NormalizerAuto
+column_create Bigram entries_name COLUMN_INDEX|WITH_POSITION \
+ Entries name
+column_create Bigram entries_description COLUMN_INDEX|WITH_POSITION \
+ Entries description
+
+table_create Times TABLE_PAT_KEY Time
+column_create Times entries_last_modified COLUMN_INDEX \
+ Entries last_modified
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer.c b/storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer.c
new file mode 100644
index 00000000..48c2cb0f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-query-optimizer.c
@@ -0,0 +1,214 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2014-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Groonga: c4379140c02699e3c74b94cd9e7b88d372202aa5
+
+ CFLAGS: -O0 -g3
+ % make --quiet -C benchmark run-bench-query-optimizer
+ run-bench-query-optimizer:
+ Process 100 times in each pattern
+ (time)
+ 1 condition: with mruby: (0.0362s)
+ 1 condition: without mruby: (0.0216s)
+ 4 conditions: with mruby: (0.0864s)
+ 4 conditions: without mruby: (0.0271s)
+
+ CFLAGS: -O2 -g
+ % make --quiet -C benchmark run-bench-query-optimizer
+ run-bench-query-optimizer:
+ Process 100 times in each pattern
+ (time)
+ 1 condition: with mruby: (0.0243s)
+ 1 condition: without mruby: (0.0159s)
+ 4 conditions: with mruby: (0.0452s)
+ 4 conditions: without mruby: (0.0188s)
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+typedef struct _BenchmarkData {
+ grn_ctx context;
+ grn_obj *database;
+ grn_bool use_mruby;
+ GString *command;
+} BenchmarkData;
+
+static void
+bench(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_ctx *context = &(data->context);
+ char *response;
+ unsigned int response_length;
+ int flags;
+
+ grn_ctx_send(context, data->command->str, data->command->len, 0);
+ grn_ctx_recv(context, &response, &response_length, &flags);
+}
+
+static void
+bench_setup(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ if (data->use_mruby) {
+ g_setenv("GRN_MRUBY_ENABLED", "yes", TRUE);
+ } else {
+ g_setenv("GRN_MRUBY_ENABLED", "no", TRUE);
+ }
+ grn_ctx_init(&(data->context), 0);
+ grn_ctx_use(&(data->context), data->database);
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_ctx_fin(&(data->context));
+}
+
+static gchar *
+get_tmp_dir(void)
+{
+ gchar *current_dir;
+ gchar *tmp_dir;
+
+ current_dir = g_get_current_dir();
+ tmp_dir = g_build_filename(current_dir, "tmp", NULL);
+ g_free(current_dir);
+
+ return tmp_dir;
+}
+
+static grn_obj *
+setup_database(grn_ctx *context)
+{
+ gchar *tmp_dir;
+ gchar *database_path;
+ grn_obj *database;
+ const gchar *warmup_command = "dump";
+ gchar *response;
+ unsigned int response_length;
+ int flags;
+
+ tmp_dir = get_tmp_dir();
+ database_path = g_build_filename(tmp_dir, "query-optimizer", "db", NULL);
+ database = grn_db_open(context, database_path);
+ grn_ctx_send(context, warmup_command, strlen(warmup_command), 0);
+ grn_ctx_recv(context, &response, &response_length, &flags);
+
+ g_free(database_path);
+
+ return database;
+}
+
+static void
+teardown_database(grn_ctx *context, grn_obj *database)
+{
+ grn_obj_close(context, database);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ grn_ctx context;
+ grn_obj *database;
+ BenchReporter *reporter;
+ gint n = 100;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ grn_ctx_init(&context, 0);
+
+ database = setup_database(&context);
+
+ reporter = bench_reporter_new();
+
+ g_print("Process %d times in each pattern\n", n);
+ {
+ BenchmarkData data_one_condition_with_mruby;
+ BenchmarkData data_one_condition_without_mruby;
+ BenchmarkData data_multiple_conditions_with_mruby;
+ BenchmarkData data_multiple_conditions_without_mruby;
+
+#define REGISTER(label, data, use_mruby_, command_) \
+ data.database = database; \
+ data.use_mruby = use_mruby_; \
+ data.command = g_string_new(command_); \
+ bench_reporter_register(reporter, label, \
+ n, \
+ bench_setup, \
+ bench, \
+ bench_teardown, \
+ &data)
+
+ REGISTER("1 condition: with mruby", data_one_condition_with_mruby,
+ GRN_TRUE,
+ "select Entries --cache no --query 'name:@Groonga'");
+ REGISTER("1 condition: without mruby", data_one_condition_without_mruby,
+ GRN_FALSE,
+ "select Entries --cache no --query 'name:@Groonga'");
+ REGISTER("4 conditions: with mruby",
+ data_multiple_conditions_with_mruby,
+ GRN_TRUE,
+ "select Entries --cache no --filter '"
+ "name @ \"Groonga\" && "
+ "description @ \"search\" && "
+ "last_modified >= \"2014-2-9 00:00:00\" && "
+ "last_modified <= \"2014-11-29 00:00:00\""
+ "'");
+ REGISTER("4 conditions: without mruby",
+ data_multiple_conditions_without_mruby,
+ GRN_FALSE,
+ "select Entries --cache no --filter '"
+ "name @ \"Groonga\" && "
+ "description @ \"search\" && "
+ "last_modified >= \"2014-2-9 00:00:00\" && "
+ "last_modified <= \"2014-11-29 00:00:00\""
+ "'");
+
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+ }
+ g_object_unref(reporter);
+
+ teardown_database(&context, database);
+
+ grn_ctx_fin(&context);
+
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-range-select.c b/storage/mroonga/vendor/groonga/benchmark/bench-range-select.c
new file mode 100644
index 00000000..11df9c10
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-range-select.c
@@ -0,0 +1,280 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2014-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Groonga: 09a4c4e00832fb90dee74c5b97b7cf0f5952f85b
+
+ CPU Intel(R) Core(TM) i7 CPU 860 @ 2.80GHz (fam: 06, model: 1e, stepping: 05)
+
+ CFLAGS: -O0 -g3
+ % make --quiet -C benchmark run-bench-range-select
+ run-bench-range-select:
+ Process 10 times in each pattern
+ (total) (average) (median)
+ ( 500, 600] ( 1000): with mruby: (0.0058s) (0.5773ms) (0.5830ms)
+ ( 500, 600] ( 1000): without mruby: (0.0062s) (0.6203ms) (0.6200ms)
+ ( 5000, 5100] ( 10000): with mruby: (0.0058s) (0.5827ms) (0.5800ms)
+ ( 5000, 5100] ( 10000): without mruby: (0.0473s) (0.0047s) (0.0048s)
+ ( 50000, 50100] ( 100000): with mruby: (0.0064s) (0.6397ms) (0.6370ms)
+ ( 50000, 50100] ( 100000): without mruby: (0.4498s) (0.0450s) (0.0442s)
+ (500000, 500100] (1000000): with mruby: (0.0057s) (0.5710ms) (0.5190ms)
+ (500000, 500100] (1000000): without mruby: (4.3193s) (0.4319s) (0.4306s)
+
+ CFLAGS: -O2 -g
+ % make --quiet -C benchmark run-bench-range-select
+ run-bench-range-select:
+ Process 10 times in each pattern
+ (total) (average) (median)
+ ( 500, 600] ( 1000): with mruby: (0.0031s) (0.3058ms) (0.2890ms)
+ ( 500, 600] ( 1000): without mruby: (0.0031s) (0.3132ms) (0.3090ms)
+ ( 5000, 5100] ( 10000): with mruby: (0.0031s) (0.3063ms) (0.3100ms)
+ ( 5000, 5100] ( 10000): without mruby: (0.0239s) (0.0024s) (0.0023s)
+ ( 50000, 50100] ( 100000): with mruby: (0.0028s) (0.2825ms) (0.2660ms)
+ ( 50000, 50100] ( 100000): without mruby: (0.2117s) (0.0212s) (0.0211s)
+ (500000, 500100] (1000000): with mruby: (0.0028s) (0.2757ms) (0.2650ms)
+ (500000, 500100] (1000000): without mruby: (2.0874s) (0.2087s) (0.2092s)
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include <grn_db.h>
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+#define GET(context, name) (grn_ctx_get(context, name, strlen(name)))
+
+typedef struct _BenchmarkData
+{
+ grn_ctx context;
+ grn_obj *database;
+ guint n_records;
+ grn_bool use_mruby;
+ const gchar *command;
+} BenchmarkData;
+
+static void
+run_command(grn_ctx *context, const gchar *command)
+{
+ gchar *response;
+ unsigned int response_length;
+ int flags;
+
+ grn_ctx_send(context, command, strlen(command), 0);
+ grn_ctx_recv(context, &response, &response_length, &flags);
+}
+
+static void
+bench(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_ctx *context = &(data->context);
+
+ run_command(context, data->command);
+}
+
+static gchar *
+get_tmp_dir(void)
+{
+ gchar *current_dir;
+ gchar *tmp_dir;
+
+ current_dir = g_get_current_dir();
+ tmp_dir = g_build_filename(current_dir, "tmp", NULL);
+ g_free(current_dir);
+
+ return tmp_dir;
+}
+
+static void
+setup_database(BenchmarkData *data)
+{
+ grn_ctx *context = &(data->context);
+ gchar *tmp_dir;
+ gchar *database_last_component_name;
+ gchar *database_path;
+ guint i;
+
+ tmp_dir = get_tmp_dir();
+ database_last_component_name =
+ g_strdup_printf("db-%d-%s-mruby",
+ data->n_records,
+ data->use_mruby ? "with" : "without");
+ database_path = g_build_filename(tmp_dir,
+ "range-select",
+ database_last_component_name,
+ NULL);
+ g_free(database_last_component_name);
+
+ if (g_file_test(database_path, G_FILE_TEST_EXISTS)) {
+ data->database = grn_db_open(context, database_path);
+ run_command(context, "dump");
+ } else {
+ data->database = grn_db_create(context, database_path, NULL);
+
+ run_command(context, "table_create Entries TABLE_NO_KEY");
+ run_command(context, "column_create Entries rank COLUMN_SCALAR Int32");
+ run_command(context, "table_create Ranks TABLE_PAT_KEY Int32");
+ run_command(context,
+ "column_create Ranks entries_rank COLUMN_INDEX Entries rank");
+
+ run_command(context, "load --table Entries");
+ run_command(context, "[");
+ for (i = 0; i < data->n_records; i++) {
+#define BUFFER_SIZE 4096
+ gchar buffer[BUFFER_SIZE];
+ const gchar *separator;
+ if (i == (data->n_records - 1)) {
+ separator = "";
+ } else {
+ separator = ",";
+ }
+ snprintf(buffer, BUFFER_SIZE, "{\"rank\": %u}%s", i, separator);
+ run_command(context, buffer);
+#undef BUFFER_SIZE
+ }
+ run_command(context, "]");
+ }
+
+ g_free(database_path);
+}
+
+static void
+bench_startup(BenchmarkData *data)
+{
+ if (data->use_mruby) {
+ g_setenv("GRN_MRUBY_ENABLED", "yes", TRUE);
+ } else {
+ g_setenv("GRN_MRUBY_ENABLED", "no", TRUE);
+ }
+ grn_ctx_init(&(data->context), 0);
+ setup_database(data);
+}
+
+static void
+bench_shutdown(BenchmarkData *data)
+{
+ grn_ctx *context = &(data->context);
+
+ grn_obj_close(context, data->database);
+ grn_ctx_fin(context);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchReporter *reporter;
+ gint n = 10;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+
+ g_print("Process %d times in each pattern\n", n);
+
+ bench_init(&argc, &argv);
+ reporter = bench_reporter_new();
+
+ {
+ BenchmarkData data_small_with_mruby;
+ BenchmarkData data_small_without_mruby;
+ BenchmarkData data_medium_with_mruby;
+ BenchmarkData data_medium_without_mruby;
+ BenchmarkData data_large_with_mruby;
+ BenchmarkData data_large_without_mruby;
+ BenchmarkData data_very_large_with_mruby;
+ BenchmarkData data_very_large_without_mruby;
+
+#define REGISTER(data, n_records_, min, max, use_mruby_) \
+ do { \
+ gchar *label; \
+ label = g_strdup_printf("(%6d, %6d] (%7d): %7s mruby", \
+ min, max, n_records_, \
+ use_mruby_ ? "with" : "without"); \
+ data.use_mruby = use_mruby_; \
+ data.n_records = n_records_; \
+ data.command = \
+ "select Entries --cache no " \
+ "--filter 'rank > " #min " && rank <= " #max "'"; \
+ bench_startup(&data); \
+ bench_reporter_register(reporter, label, \
+ n, \
+ NULL, \
+ bench, \
+ NULL, \
+ &data); \
+ g_free(label); \
+ } while(FALSE)
+
+ REGISTER(data_small_with_mruby,
+ 1000,
+ 500, 600,
+ GRN_TRUE);
+ REGISTER(data_small_without_mruby,
+ 1000,
+ 500, 600,
+ GRN_FALSE);
+ REGISTER(data_medium_with_mruby,
+ 10000,
+ 5000, 5100,
+ GRN_TRUE);
+ REGISTER(data_medium_without_mruby,
+ 10000,
+ 5000, 5100,
+ GRN_FALSE);
+ REGISTER(data_large_with_mruby,
+ 100000,
+ 50000, 50100,
+ GRN_TRUE);
+ REGISTER(data_large_without_mruby,
+ 100000,
+ 50000, 50100,
+ GRN_FALSE);
+ REGISTER(data_very_large_with_mruby,
+ 1000000,
+ 500000, 500100,
+ GRN_TRUE);
+ REGISTER(data_very_large_without_mruby,
+ 1000000,
+ 500000, 500100,
+ GRN_FALSE);
+
+#undef REGISTER
+
+ bench_reporter_run(reporter);
+
+ bench_shutdown(&data_small_with_mruby);
+ bench_shutdown(&data_small_without_mruby);
+ bench_shutdown(&data_medium_with_mruby);
+ bench_shutdown(&data_medium_without_mruby);
+ bench_shutdown(&data_large_with_mruby);
+ bench_shutdown(&data_large_without_mruby);
+ bench_shutdown(&data_very_large_with_mruby);
+ bench_shutdown(&data_very_large_without_mruby);
+ }
+ g_object_unref(reporter);
+
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-result-set.c b/storage/mroonga/vendor/groonga/benchmark/bench-result-set.c
new file mode 100644
index 00000000..bba5baea
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-result-set.c
@@ -0,0 +1,151 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2015-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+typedef struct _BenchmarkData
+{
+ gchar *base_dir;
+ grn_ctx *context;
+ grn_obj *source_table;
+ grn_obj *result_set;
+} BenchmarkData;
+
+static void
+bench_n(BenchmarkData *data, gint64 n)
+{
+ gint64 i;
+ grn_ctx *ctx;
+ grn_hash *result_set;
+
+ ctx = data->context;
+ result_set = (grn_hash *)data->result_set;
+ for (i = 0; i < n; i++) {
+ grn_id id = i;
+ grn_hash_add(ctx, result_set, &id, sizeof(grn_id), NULL, NULL);
+ }
+}
+
+static void
+bench_1000(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ bench_n(data, 1000);
+}
+
+static void
+bench_10000(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ bench_n(data, 10000);
+}
+
+static void
+bench_100000(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ bench_n(data, 100000);
+}
+
+static void
+bench_setup(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ data->result_set = grn_table_create(data->context,
+ NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY | GRN_OBJ_WITH_SUBREC,
+ data->source_table,
+ NULL);
+
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_obj_close(data->context, data->result_set);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchmarkData data;
+ BenchReporter *reporter;
+ gchar *base_dir;
+ grn_ctx ctx;
+ gint n = 100;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ data.context = &ctx;
+
+ base_dir = g_build_filename(g_get_tmp_dir(), "groonga-bench", NULL);
+ bench_utils_remove_path_recursive_force(base_dir);
+ g_mkdir_with_parents(base_dir, 0755);
+
+ {
+ gchar *database_path;
+ const gchar *source_table_name = "Sources";
+
+ grn_ctx_init(&ctx, 0);
+ database_path = g_build_filename(base_dir, "db", NULL);
+ grn_db_create(&ctx, database_path, NULL);
+ g_free(database_path);
+
+ data.source_table = grn_table_create(&ctx,
+ source_table_name,
+ strlen(source_table_name),
+ NULL,
+ GRN_TABLE_PAT_KEY | GRN_OBJ_PERSISTENT,
+ grn_ctx_at(&ctx, GRN_DB_SHORT_TEXT),
+ NULL);
+ }
+
+ reporter = bench_reporter_new();
+ bench_reporter_register(reporter, "1000", n,
+ bench_setup, bench_1000, bench_teardown, &data);
+ bench_reporter_register(reporter, "10000", n,
+ bench_setup, bench_10000, bench_teardown, &data);
+ bench_reporter_register(reporter, "100000", n,
+ bench_setup, bench_100000, bench_teardown, &data);
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ grn_ctx_fin(&ctx);
+
+ bench_utils_remove_path_recursive_force(data.base_dir);
+
+ bench_quit();
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/bench-table-factory.c b/storage/mroonga/vendor/groonga/benchmark/bench-table-factory.c
new file mode 100644
index 00000000..025b0750
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/bench-table-factory.c
@@ -0,0 +1,277 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008-2016 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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <groonga.h>
+
+#include "lib/benchmark.h"
+
+#define DEFAULT_FLAGS (GRN_OBJ_PERSISTENT | GRN_OBJ_TABLE_PAT_KEY)
+#define DEFAULT_VALUE_SIZE (1024)
+#define VALUE_TYPE_NAME "<value_type>"
+
+typedef struct _BenchmarkData
+{
+ gchar *base_dir;
+
+ grn_ctx *context;
+ const char *name;
+ unsigned name_size;
+ char *path;
+ grn_obj_flags flags;
+ grn_obj *key_type;
+ unsigned value_size;
+ grn_encoding encoding;
+} BenchmarkData;
+
+static void
+bench_normal(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_obj *table;
+ grn_obj *value_type = grn_ctx_get(data->context, VALUE_TYPE_NAME, strlen(VALUE_TYPE_NAME));
+ if (!value_type) {
+ value_type = grn_type_create(data->context, VALUE_TYPE_NAME, strlen(VALUE_TYPE_NAME),
+ 0, data->value_size);
+ }
+ table = grn_table_create(data->context,
+ data->name, data->name_size,
+ data->path, data->flags,
+ data->key_type, value_type);
+ grn_obj_close(data->context, table);
+}
+
+static void
+bench_normal_temporary(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_obj *table;
+ grn_obj *value_type = grn_ctx_get(data->context, VALUE_TYPE_NAME, strlen(VALUE_TYPE_NAME));
+ if (!value_type) {
+ value_type = grn_type_create(data->context, VALUE_TYPE_NAME, strlen(VALUE_TYPE_NAME),
+ 0, data->value_size);
+ }
+ GRN_CTX_SET_ENCODING(data->context, data->encoding);
+ table = grn_table_create(data->context,
+ data->name, data->name_size,
+ NULL, data->flags & ~GRN_OBJ_PERSISTENT,
+ data->key_type, value_type);
+ grn_obj_close(data->context, table);
+}
+
+typedef struct _grn_table_factory
+{
+ grn_ctx *context;
+ char *name;
+ unsigned name_size;
+ char *path;
+ grn_obj_flags flags;
+ grn_obj *key_type;
+ unsigned value_size;
+ grn_encoding encoding;
+} grn_table_factory;
+
+static grn_table_factory *
+grn_table_factory_create(void)
+{
+ grn_table_factory *factory;
+
+ factory = g_new0(grn_table_factory, 1);
+
+ factory->context = NULL;
+ factory->name = NULL;
+ factory->name_size = 0;
+ factory->path = NULL;
+ factory->flags = DEFAULT_FLAGS;
+ factory->key_type = NULL;
+ factory->value_size = DEFAULT_VALUE_SIZE;
+ factory->encoding = GRN_ENC_DEFAULT;
+
+ return factory;
+}
+
+static void
+grn_table_factory_set_context(grn_table_factory *factory, grn_ctx *context)
+{
+ factory->context = context;
+}
+
+static void
+grn_table_factory_set_name(grn_table_factory *factory, const char *name)
+{
+ factory->name = g_strdup(name);
+ factory->name_size = strlen(name);
+}
+
+static void
+grn_table_factory_set_path(grn_table_factory *factory, const char *path)
+{
+ factory->path = g_strdup(path);
+ if (path)
+ factory->flags |= GRN_OBJ_PERSISTENT;
+ else
+ factory->flags &= ~GRN_OBJ_PERSISTENT;
+}
+
+static void
+grn_table_factory_set_key_type(grn_table_factory *factory, grn_obj *key_type)
+{
+ factory->key_type = key_type;
+}
+
+static grn_obj *
+grn_table_factory_make(grn_table_factory *factory)
+{
+ grn_obj *value_type = grn_ctx_get(factory->context, VALUE_TYPE_NAME, strlen(VALUE_TYPE_NAME));
+ if (!value_type) {
+ value_type = grn_type_create(factory->context, VALUE_TYPE_NAME, strlen(VALUE_TYPE_NAME),
+ 0, factory->value_size);
+ }
+ GRN_CTX_SET_ENCODING(factory->context, factory->encoding);
+ return grn_table_create(factory->context,
+ factory->name, factory->name_size,
+ factory->path, factory->flags,
+ factory->key_type, value_type);
+}
+
+static void
+grn_table_factory_close(grn_table_factory *factory)
+{
+ g_free(factory->name);
+ g_free(factory->path);
+ g_free(factory);
+}
+
+static void
+bench_factory(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_table_factory *factory;
+ grn_obj *table;
+
+ factory = grn_table_factory_create();
+ grn_table_factory_set_context(factory, data->context);
+ grn_table_factory_set_name(factory, data->name);
+ grn_table_factory_set_path(factory, data->path);
+ grn_table_factory_set_key_type(factory, data->key_type);
+
+ table = grn_table_factory_make(factory);
+ grn_obj_close(data->context, table);
+
+ grn_table_factory_close(factory);
+}
+
+static void
+bench_factory_temporary(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ grn_table_factory *factory;
+ grn_obj *table;
+
+ factory = grn_table_factory_create();
+ grn_table_factory_set_context(factory, data->context);
+ grn_table_factory_set_name(factory, data->name);
+ grn_table_factory_set_key_type(factory, data->key_type);
+
+ table = grn_table_factory_make(factory);
+ grn_obj_close(data->context, table);
+
+ grn_table_factory_close(factory);
+}
+
+static void
+bench_setup(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+ const gchar *type_name;
+
+ bench_utils_remove_path_recursive_force(data->base_dir);
+ g_mkdir_with_parents(data->base_dir, 0755);
+
+ grn_ctx_init(data->context, GRN_CTX_USE_QL);
+
+ type_name = "name";
+ data->key_type = grn_type_create(data->context,
+ type_name, strlen(type_name),
+ GRN_OBJ_KEY_UINT, sizeof(grn_id));
+
+}
+
+static void
+bench_teardown(gpointer user_data)
+{
+ BenchmarkData *data = user_data;
+
+ grn_obj_close(data->context, data->key_type);
+ grn_ctx_fin(data->context);
+ bench_utils_remove_path_recursive_force(data->base_dir);
+}
+
+int
+main(int argc, gchar **argv)
+{
+ grn_rc rc;
+ BenchmarkData data;
+ BenchReporter *reporter;
+ gint n = 100;
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ g_print("failed to initialize Groonga: <%d>: %s\n",
+ rc, grn_get_global_error_message());
+ return EXIT_FAILURE;
+ }
+ bench_init(&argc, &argv);
+
+ data.context = g_new(grn_ctx, 1);
+ data.base_dir = g_build_filename(g_get_tmp_dir(), "groonga-bench", NULL);
+ data.name = "table";
+ data.name_size = strlen(data.name);
+ data.path = g_build_filename(data.base_dir, "table", NULL);
+ data.flags = DEFAULT_FLAGS;
+ data.key_type = NULL;
+ data.value_size = DEFAULT_VALUE_SIZE;
+ data.encoding = GRN_ENC_DEFAULT;
+
+ reporter = bench_reporter_new();
+ bench_reporter_register(reporter, "normal (persistent)", n,
+ bench_setup, bench_normal, bench_teardown, &data);
+ bench_reporter_register(reporter, "factory (persistent)", n,
+ bench_setup, bench_factory, bench_teardown, &data);
+ bench_reporter_register(reporter, "normal (temporary)", n,
+ bench_setup, bench_normal_temporary, bench_teardown,
+ &data);
+ bench_reporter_register(reporter, "factory (temporary)", n,
+ bench_setup, bench_factory_temporary, bench_teardown,
+ &data);
+ bench_reporter_run(reporter);
+ g_object_unref(reporter);
+
+ bench_utils_remove_path_recursive_force(data.base_dir);
+
+ g_free(data.path);
+ g_free(data.base_dir);
+ g_free(data.context);
+
+ bench_quit();
+ grn_fin();
+
+ return EXIT_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/fixtures/Makefile.am b/storage/mroonga/vendor/groonga/benchmark/fixtures/Makefile.am
new file mode 100644
index 00000000..3b7136f7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/fixtures/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = \
+ geo-select
diff --git a/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/13_2010.CSV.xz b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/13_2010.CSV.xz
new file mode 100644
index 00000000..3cef5268
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/13_2010.CSV.xz
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/Makefile.am b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/Makefile.am
new file mode 100644
index 00000000..3aa25594
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/Makefile.am
@@ -0,0 +1,4 @@
+EXTRA_DIST = \
+ README.txt \
+ 13_2010.CSV.xz \
+ format_2010.html
diff --git a/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/README.txt b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/README.txt
new file mode 100644
index 00000000..c4a0620a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/README.txt
@@ -0,0 +1,6 @@
+位置情報検索ベンチマーク用テストデータについて
+--------------------------------------------
+
+13_2010.CSV.xzは国土交通相の `位置参照情報ダウンロードサービス <http://nlftp.mlit.go.jp/isj/>`_ からダウンロードした2010年版の東京都の「大字・町丁目位置参照情報 国土交通省」です。xz圧縮しているだけでデータの編集・加工はしていません。CSVのフォーマットについてはformat_2010.htmlを参照してください。こちらもダウンロードサービスに含まれているものを編集・加工していません。
+
+`位置参照情報ダウンロードサービス利用約款 <http://nlftp.mlit.go.jp/isj/agreement.html>`_ に従い、上記のように出典を明記して利用しています。
diff --git a/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/format_2010.html b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/format_2010.html
new file mode 100644
index 00000000..5c2396c4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/fixtures/geo-select/format_2010.html
@@ -0,0 +1,111 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<title>X惌xʒuQƏ (2010)</title>
+<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
+</head>
+
+ <body>
+ <h3 align="center">X惌xʒuQƏ (2010N) f[^`</h3>
+ <table width="90%" align="center">
+ <tr>
+ <td>
+ t@C`CSV(Camma Separated Values)łB<br/>
+ R[h́AShift-JISłB<br/>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <table width="100%" align="center" border="1">
+ <tr>
+ <th></th>
+ <th>l</th>
+ <th></th>
+ </tr>
+ <tr>
+ <td>s{</td>
+ <td><br/></td>
+ <td>"s"</td>
+ </tr>
+ <tr>
+ <td>s撬</td>
+ <td>S͌SAߎwss̋於܂ށB</td>
+ <td>"c"</td>
+ </tr>
+ <tr>
+ <td>厚E</td>
+ <td>ڂ̐͊</td>
+ <td>"֓񒚖"</td>
+ </tr>
+ <tr>
+ <td>X敄En</td>
+ <td>ƂĔpiꕔj</td>
+ <td>"1"</td>
+ </tr>
+ <tr>
+ <td>Wnԍ</td>
+ <td>ʒpWn̍Wnԍi1`19Fpj</td>
+ <td>9</td>
+ </tr>
+ <tr>
+ <td>wW</td>
+ <td>
+ ʒpWn̍Wn_̂<br/>
+ iPʁF[gAkvXlA_ȉ1ʂ܂Łj
+ </td>
+ <td>-35925.9</td>
+ </tr>
+ <tr>
+ <td>xW</td>
+ <td>
+ ʒpWn̍Wn_̂<br/>
+ iPʁF[gAvXlA_ȉ1ʂ܂Łj
+ </td>
+ <td>-7446.2</td>
+ </tr>
+ <tr>
+ <td>ܓx</td>
+ <td>\ioܓxiPʁFxA_ȉ6ʂ܂Łj</td>
+ <td>35.676155</td>
+ </tr>
+ <tr>
+ <td>ox</td>
+ <td>\ioܓxiPʁFxA_ȉ6ʂ܂Łj</td>
+ <td>139.751075</td>
+ </tr>
+ <tr>
+ <td>Z\tO</td>
+ <td>1FZ\{A0FZ\{</td>
+ <td>1</td>
+ </tr>
+ <tr>
+ <td>\tO</td>
+ <td>
+ 1‚̊X敄̑\_ɑΉtꍇȂǂɁÂ1‚ɕ֋XIɑ\tO𗧂ĂĂ܂B<br/>
+ 1F\A0F\Ȃ
+ <td>1</td>
+ </tr>
+ <tr>
+ <td>XVOtO</td>
+ <td>2007Nx2008Nxf[^Ɋ܂܂tO𗧂ĂĂ܂B<br/>
+ 1FVK쐬A2F̕ύXA3F폜A0FύXȂ</td>
+ <td>0</td>
+ </tr>
+ <tr>
+ <td>XV㗚tO</td>
+ <td>2009Nxȍ~̃f[^Ɋ܂܂tO𗧂ĂĂ܂B<br/>
+ 1FVK쐬A2F̕ύXA3F폜A0FύXȂ</td>
+ <td>0</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td align="right">
+ 23N0418쐬
+ </td>
+ </tr>
+ </table>
+</body>
+
+</html>
diff --git a/storage/mroonga/vendor/groonga/benchmark/geo-distance-summary.rb b/storage/mroonga/vendor/groonga/benchmark/geo-distance-summary.rb
new file mode 100755
index 00000000..6559cb60
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/geo-distance-summary.rb
@@ -0,0 +1,140 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+
+require 'fileutils'
+require 'optparse'
+
+class BenchmarkSummary
+ attr_accessor :options
+
+ def initialize(options)
+ @options = options
+ @options[:count] ||= 10
+ end
+
+ def calc_total(data)
+ total = {}
+ @options[:count].times do |i|
+ data[i + 1].each do |key, value|
+ if total[key]
+ total[key] = total[key] + value
+ else
+ total[key] = value
+ end
+ end
+ end
+ total
+ end
+
+ def print_average(data)
+ total = calc_total(data)
+ text = "|項目|"
+ @options[:count].times do |i|
+ text << "#{i + 1}|"
+ text << "平均|\n" if i == @options[:count] - 1
+ end
+ total.each do |key, value|
+ line = [key]
+ @options[:count].times do |i|
+ data[i + 1].each do |data_key, data_value|
+ if key == data_key
+ line << data_value
+ end
+ end
+ end
+ line << [value / @options[:count].to_f]
+ text << sprintf("|%s|\n", line.join("|"))
+ end
+ puts text
+ end
+
+ def print_performance(before, after)
+ before_total = calc_total(before)
+ after_total = calc_total(after)
+ ratio = {}
+ before_total.each do |key, value|
+ ratio[key] = after_total[key] / value
+ end
+ text = "|項目|変更前|変更後|比率|備考|\n"
+ ratio.each do |key, value|
+ text << sprintf("|%s|%f|%f|%f||\n",
+ key,
+ before_total[key] / @options[:count].to_f,
+ after_total[key] / @options[:count].to_f,
+ ratio[key])
+ end
+ puts text
+ end
+
+ def parse_log(logs)
+ parse_result = {}
+ logs.each do |index, log|
+ File.open(log, "r") do |file|
+ data = file.read
+ entry = {}
+ data.split("\n").each do |line|
+ if line =~ /\s*(.+?):\s+\((.+)\)/
+ entry[$1] = $2.to_f
+ end
+ end
+ parse_result[index] = entry
+ end
+ end
+ parse_result
+ end
+end
+
+=begin
+
+Usage: geo-distance-summary.rb \
+-b run-bench-geo-distance-orig-N1000 \
+-a run-bench-geo-distance-work-N1000
+
+NOTE: expected that there are run-bench-geo-distance-orig-N1000-1.log \
+... \
+run-bench-geo-distance-orig-N1000-[N].log.
+
+=end
+
+if __FILE__ == $0
+
+ options = {}
+ parser = OptionParser.new
+ parser.on("-b", "--before PREFIX",
+ "log file name must be PREFIX-[N].log") do |prefix|
+ options[:before] = prefix
+ end
+ parser.on("-a", "--after PREFIX",
+ "log file name must be PREFIX-[N].log") do |prefix|
+ options[:after] = prefix
+ end
+ parser.on("-n", "data count") do |count|
+ options[:count] = count
+ end
+
+ parser.parse!(ARGV)
+
+ if not options.has_key?(:before) or not options.has_key?(:after)
+ puts(parser.to_s)
+ exit
+ end
+
+ bench_before_log = {}
+ bench_after_log = {}
+ Dir.glob("#{options[:before]}*.log") do |log|
+ log =~ /(.+)-(\d+)\.log$/
+ bench_before_log[$2.to_i] = log
+ end
+ Dir.glob("#{options[:after]}*.log") do |log|
+ log =~ /(.+)-(\d+)\.log$/
+ bench_after_log[$2.to_i] = log
+ end
+
+ bench = BenchmarkSummary.new(options)
+ bench_before = bench.parse_log(bench_before_log)
+ bench_after = bench.parse_log(bench_after_log)
+
+ bench.print_average(bench_before)
+ bench.print_average(bench_after)
+ bench.print_performance(bench_before, bench_after)
+end
diff --git a/storage/mroonga/vendor/groonga/benchmark/geo-select-generate-grn.rb b/storage/mroonga/vendor/groonga/benchmark/geo-select-generate-grn.rb
new file mode 100755
index 00000000..dc90f7e6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/geo-select-generate-grn.rb
@@ -0,0 +1,53 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+
+if ARGV.size != 2
+ puts "Usage: #{$0} SOURCE_CSV OUTPUT_GRN"
+ puts " e.g.: #{$0} fixtures/geo-select/13_2010.CSV fixtures/geo-select/load.grn"
+ exit(false)
+end
+
+csv, grn = ARGV
+
+require "fileutils"
+require "csv"
+
+FileUtils.mkdir_p(File.dirname(grn))
+File.open(grn, "w") do |output|
+ output.print(<<-EOH.strip)
+table_create Addresses TABLE_HASH_KEY ShortText
+column_create Addresses location COLUMN_SCALAR WGS84GeoPoint
+
+table_create Locations TABLE_PAT_KEY WGS84GeoPoint
+column_create Locations address COLUMN_INDEX Addresses location
+
+load --table Addresses
+[
+["_key", "location"]
+EOH
+
+ headers = nil
+ csv_foreach_args = [csv]
+ csv_foreach_args << {:encoding => "UTF-8"} if defined?(Encoding)
+ CSV.foreach(*csv_foreach_args) do |row|
+ if headers.nil?
+ headers = row
+ else
+ record = {}
+ headers.each_with_index do |header, i|
+ record[header] = row[i]
+ end
+ central_value_p = record["代表フラグ"] == "1"
+ next unless central_value_p
+ name =
+ record["都道府県名"] + record["市区町村名"] +
+ record["大字・町丁目"] + record["街区符号・地番"]
+ location = "%sx%s" % [record["緯度"], record["経度"]]
+ output.print(",\n[\"#{name}\", \"#{location}\"]")
+ end
+ end
+ output.print(<<-EOF)
+
+]
+EOF
+end
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/Makefile.am b/storage/mroonga/vendor/groonga/benchmark/lib/Makefile.am
new file mode 100644
index 00000000..2031b9aa
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/Makefile.am
@@ -0,0 +1,24 @@
+if WITH_BENCHMARK
+noinst_LTLIBRARIES = \
+ libbenchmark.la
+endif
+
+AM_CPPFLAGS = \
+ -I$(srcdir)
+
+AM_CFLAGS = \
+ $(GLIB_CFLAGS)
+
+CFLAGS += \
+ $(NO_BAD_FUNCTION_CAST_CFLAGS)
+
+LIBS = \
+ $(GLIB_LIBS)
+
+libbenchmark_la_SOURCES = \
+ benchmark.c \
+ benchmark.h \
+ bench-reporter.c \
+ bench-reporter.h \
+ bench-utils.c \
+ bench-utils.h
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.c b/storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.c
new file mode 100644
index 00000000..cb435976
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.c
@@ -0,0 +1,315 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+
+#include "bench-reporter.h"
+
+typedef struct _BenchItem BenchItem;
+struct _BenchItem
+{
+ gchar *label;
+ gint n;
+ BenchSetupFunc bench_setup;
+ BenchFunc bench;
+ BenchTeardownFunc bench_teardown;
+ gpointer data;
+};
+
+static BenchItem *
+bench_item_new(const gchar *label, gint n,
+ BenchSetupFunc bench_setup,
+ BenchFunc bench,
+ BenchTeardownFunc bench_teardown,
+ gpointer data)
+{
+ BenchItem *item;
+
+ item = g_slice_new(BenchItem);
+
+ item->label = g_strdup(label);
+ item->n = n;
+ item->bench_setup = bench_setup;
+ item->bench = bench;
+ item->bench_teardown = bench_teardown;
+ item->data = data;
+
+ return item;
+}
+
+static void
+bench_item_free(BenchItem *item)
+{
+ if (item->label)
+ g_free(item->label);
+
+ g_slice_free(BenchItem, item);
+}
+
+#define BENCH_REPORTER_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((obj), \
+ BENCH_TYPE_REPORTER, \
+ BenchReporterPrivate))
+
+typedef struct _BenchReporterPrivate BenchReporterPrivate;
+struct _BenchReporterPrivate
+{
+ GList *items;
+};
+
+G_DEFINE_TYPE(BenchReporter, bench_reporter, G_TYPE_OBJECT)
+
+static void dispose (GObject *object);
+
+static void
+bench_reporter_class_init(BenchReporterClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS(klass);
+
+ gobject_class->dispose = dispose;
+
+ g_type_class_add_private(gobject_class, sizeof(BenchReporterPrivate));
+}
+
+static void
+bench_reporter_init(BenchReporter *reporter)
+{
+ BenchReporterPrivate *priv;
+
+ priv = BENCH_REPORTER_GET_PRIVATE(reporter);
+
+ priv->items = NULL;
+}
+
+static void
+dispose(GObject *object)
+{
+ BenchReporterPrivate *priv;
+
+ priv = BENCH_REPORTER_GET_PRIVATE(object);
+
+ if (priv->items) {
+ g_list_foreach(priv->items, (GFunc)bench_item_free, NULL);
+ g_list_free(priv->items);
+ priv->items = NULL;
+ }
+
+ G_OBJECT_CLASS(bench_reporter_parent_class)->dispose(object);
+}
+
+BenchReporter *
+bench_reporter_new(void)
+{
+ return g_object_new(BENCH_TYPE_REPORTER, NULL);
+}
+
+void
+bench_reporter_register(BenchReporter *reporter,
+ const gchar *label, gint n,
+ BenchSetupFunc bench_setup,
+ BenchFunc bench,
+ BenchTeardownFunc bench_teardown,
+ gpointer data)
+{
+ BenchReporterPrivate *priv;
+
+ priv = BENCH_REPORTER_GET_PRIVATE(reporter);
+
+ priv->items = g_list_append(priv->items, bench_item_new(label, n,
+ bench_setup,
+ bench,
+ bench_teardown,
+ data));
+}
+
+#define INDENT " "
+
+static void
+print_header(BenchReporterPrivate *priv, gint max_label_length)
+{
+ gint n_spaces;
+
+ g_print(INDENT);
+ for (n_spaces = max_label_length + strlen(": ");
+ n_spaces > 0;
+ n_spaces--) {
+ g_print(" ");
+ }
+ g_print("(total) ");
+ g_print("(average) ");
+ g_print("(median)\n");
+}
+
+static void
+print_label(BenchReporterPrivate *priv, BenchItem *item, gint max_label_length)
+{
+ gint n_left_spaces;
+
+ g_print(INDENT);
+ if (item->label) {
+ n_left_spaces = max_label_length - strlen(item->label);
+ } else {
+ n_left_spaces = max_label_length;
+ }
+ for (; n_left_spaces > 0; n_left_spaces--) {
+ g_print(" ");
+ }
+ if (item->label)
+ g_print("%s", item->label);
+ g_print(": ");
+}
+
+static void
+report_elapsed_time(gdouble elapsed_time)
+{
+ gdouble one_second = 1.0;
+ gdouble one_millisecond = one_second / 1000.0;
+ gdouble one_microsecond = one_millisecond / 1000.0;
+
+ if (elapsed_time < one_microsecond) {
+ g_print("(%.8fms)", elapsed_time * 1000.0);
+ } else if (elapsed_time < one_millisecond) {
+ g_print("(%.4fms)", elapsed_time * 1000.0);
+ } else {
+ g_print("(%.4fs) ", elapsed_time);
+ }
+}
+
+static gdouble
+compute_total_elapsed_time(GArray *elapsed_times)
+{
+ guint i;
+ gdouble total = 0.0;
+
+ for (i = 0; i< elapsed_times->len; i++) {
+ gdouble elapsed_time = g_array_index(elapsed_times, gdouble, i);
+ total += elapsed_time;
+ }
+
+ return total;
+}
+
+static void
+report_elapsed_time_total(GArray *elapsed_times)
+{
+ report_elapsed_time(compute_total_elapsed_time(elapsed_times));
+}
+
+static void
+report_elapsed_time_average(GArray *elapsed_times)
+{
+ gdouble total;
+ gdouble average;
+
+ total = compute_total_elapsed_time(elapsed_times);
+ average = total / elapsed_times->len;
+ report_elapsed_time(average);
+}
+
+static gint
+compare_elapsed_time(gconstpointer a, gconstpointer b)
+{
+ const gdouble *elapsed_time1 = a;
+ const gdouble *elapsed_time2 = b;
+
+ if (*elapsed_time1 > *elapsed_time2) {
+ return 1;
+ } else if (*elapsed_time1 < *elapsed_time2) {
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+static void
+report_elapsed_time_median(GArray *elapsed_times)
+{
+ gdouble median;
+
+ g_array_sort(elapsed_times, compare_elapsed_time);
+ median = g_array_index(elapsed_times, gdouble, elapsed_times->len / 2);
+ report_elapsed_time(median);
+}
+
+static void
+report_elapsed_time_statistics(GArray *elapsed_times)
+{
+ report_elapsed_time_total(elapsed_times);
+ g_print(" ");
+ report_elapsed_time_average(elapsed_times);
+ g_print(" ");
+ report_elapsed_time_median(elapsed_times);
+ g_print("\n");
+}
+
+static void
+run_item(BenchReporterPrivate *priv, BenchItem *item, gint max_label_length)
+{
+ GTimer *timer;
+ GArray *elapsed_times;
+ gint i;
+
+ print_label(priv, item, max_label_length);
+
+ elapsed_times = g_array_new(FALSE, FALSE, sizeof(gdouble));
+
+ timer = g_timer_new();
+ for (i = 0; i < item->n; i++) {
+ gdouble elapsed_time;
+ if (item->bench_setup)
+ item->bench_setup(item->data);
+ g_timer_start(timer);
+ item->bench(item->data);
+ g_timer_stop(timer);
+ elapsed_time = g_timer_elapsed(timer, NULL);
+ g_array_append_val(elapsed_times, elapsed_time);
+ if (item->bench_teardown)
+ item->bench_teardown(item->data);
+ }
+ g_timer_destroy(timer);
+
+ report_elapsed_time_statistics(elapsed_times);
+
+ g_array_free(elapsed_times, TRUE);
+
+}
+
+void
+bench_reporter_run(BenchReporter *reporter)
+{
+ BenchReporterPrivate *priv;
+ GList *node;
+ gint max_label_length = 0;
+
+ priv = BENCH_REPORTER_GET_PRIVATE(reporter);
+ for (node = priv->items; node; node = g_list_next(node)) {
+ BenchItem *item = node->data;
+
+ if (item->label)
+ max_label_length = MAX(max_label_length, strlen(item->label));
+ }
+
+ print_header(priv, max_label_length);
+ for (node = priv->items; node; node = g_list_next(node)) {
+ BenchItem *item = node->data;
+
+ run_item(priv, item, max_label_length);
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.h b/storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.h
new file mode 100644
index 00000000..d2c408c7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/bench-reporter.h
@@ -0,0 +1,64 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifndef __BENCH_REPORTER_H__
+#define __BENCH_REPORTER_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define BENCH_TYPE_REPORTER (bench_reporter_get_type())
+#define BENCH_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), BENCH_TYPE_REPORTER, BenchReporter))
+#define BENCH_REPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), BENCH_TYPE_REPORTER, BenchReporterClass))
+#define BENCH_IS_REPORTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), BENCH_TYPE_REPORTER))
+#define BENCH_IS_REPORTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), BENCH_TYPE_REPORTER))
+#define BENCH_REPORTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), BENCH_TYPE_REPORTER, BenchReporterClass))
+
+typedef struct _BenchReporter BenchReporter;
+typedef struct _BenchReporterClass BenchReporterClass;
+
+typedef void (*BenchSetupFunc) (gpointer user_data);
+typedef void (*BenchFunc) (gpointer user_data);
+typedef void (*BenchTeardownFunc) (gpointer user_data);
+
+struct _BenchReporter
+{
+ GObject object;
+};
+
+struct _BenchReporterClass
+{
+ GObjectClass parent_class;
+};
+
+GType bench_reporter_get_type (void) G_GNUC_CONST;
+
+BenchReporter *bench_reporter_new (void);
+void bench_reporter_register (BenchReporter *reporter,
+ const gchar *label,
+ gint n,
+ BenchSetupFunc bench_setup,
+ BenchFunc bench,
+ BenchTeardownFunc bench_teardown,
+ gpointer data);
+void bench_reporter_run (BenchReporter *reporter);
+
+#endif /* __BENCH_REPORTER_H__ */
+
+
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.c b/storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.c
new file mode 100644
index 00000000..ef731b51
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.c
@@ -0,0 +1,83 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <errno.h>
+#include <glib/gstdio.h>
+
+#include "bench-utils.h"
+
+gboolean
+bench_utils_remove_path(const gchar *path, GError **error)
+{
+ if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
+ g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
+ "path doesn't exist: %s", path);
+ return FALSE;
+ }
+
+ if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ if (g_rmdir(path) == -1) {
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
+ "can't remove directory: %s", path);
+ return FALSE;
+ }
+ } else {
+ if (g_unlink(path) == -1) {
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
+ "can't remove path: %s", path);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+gboolean
+bench_utils_remove_path_recursive(const gchar *path, GError **error)
+{
+ if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
+ GDir *dir;
+ const gchar *name;
+
+ dir = g_dir_open(path, 0, error);
+ if (!dir)
+ return FALSE;
+
+ while ((name = g_dir_read_name(dir))) {
+ const gchar *full_path;
+
+ full_path = g_build_filename(path, name, NULL);
+ if (!bench_utils_remove_path_recursive(full_path, error))
+ return FALSE;
+ }
+
+ g_dir_close(dir);
+
+ return bench_utils_remove_path(path, error);
+ } else {
+ return bench_utils_remove_path(path, error);
+ }
+
+ return TRUE;
+}
+
+void
+bench_utils_remove_path_recursive_force(const gchar *path)
+{
+ bench_utils_remove_path_recursive(path, NULL);
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.h b/storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.h
new file mode 100644
index 00000000..b48e6f34
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/bench-utils.h
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifndef __BENCH_UTILS_H__
+#define __BENCH_UTILS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gboolean bench_utils_remove_path (const gchar *path,
+ GError **error);
+gboolean bench_utils_remove_path_recursive (const gchar *path,
+ GError **error);
+void bench_utils_remove_path_recursive_force (const gchar *path);
+
+G_END_DECLS
+
+#endif /* __BENCH_UTILS_H__ */
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/benchmark.c b/storage/mroonga/vendor/groonga/benchmark/lib/benchmark.c
new file mode 100644
index 00000000..679889a4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/benchmark.c
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008-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 version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "benchmark.h"
+
+void
+bench_init(gint *argc, gchar ***argv)
+{
+#if !GLIB_CHECK_VERSION(2, 36, 0)
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+
+ g_type_init();
+#endif
+}
+
+void
+bench_quit(void)
+{
+}
diff --git a/storage/mroonga/vendor/groonga/benchmark/lib/benchmark.h b/storage/mroonga/vendor/groonga/benchmark/lib/benchmark.h
new file mode 100644
index 00000000..7d34b8f2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/benchmark/lib/benchmark.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2; coding: utf-8 -*- */
+/*
+ Copyright (C) 2008 Kouhei Sutou <kou@cozmixng.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifndef __BENCHMARK_H__
+#define __BENCHMARK_H__
+
+#include "bench-reporter.h"
+#include "bench-utils.h"
+
+G_BEGIN_DECLS
+
+void bench_init(gint *argc, gchar ***argv);
+void bench_quit(void);
+
+G_END_DECLS
+
+#endif
diff --git a/storage/mroonga/vendor/groonga/bindings/php/config.m4 b/storage/mroonga/vendor/groonga/bindings/php/config.m4
new file mode 100644
index 00000000..c656c9d4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/php/config.m4
@@ -0,0 +1,66 @@
+
+PHP_ARG_WITH(groonga, whether groonga is available,[ --with-groonga[=DIR] With groonga support])
+
+
+if test "$PHP_GROONGA" != "no"; then
+
+
+ if test -r "$PHP_GROONGA/include/groonga.h"; then
+ PHP_GROONGA_DIR="$PHP_GROONGA"
+ PHP_ADD_INCLUDE($PHP_GROONGA_DIR/include)
+ elif test -r "$PHP_GROONGA/include/groonga/groonga.h"; then
+ PHP_GROONGA_DIR="$PHP_GROONGA"
+ PHP_ADD_INCLUDE($PHP_GROONGA_DIR/include/groonga)
+ else
+ AC_MSG_CHECKING(for groonga in default path)
+ for i in /usr /usr/local; do
+ if test -r "$i/include/groonga/groonga.h"; then
+ PHP_GROONGA_DIR=$i
+ AC_MSG_RESULT(found in $i)
+ break
+ fi
+ done
+ if test "x" = "x$PHP_GROONGA_DIR"; then
+ AC_MSG_ERROR(not found)
+ fi
+ PHP_ADD_INCLUDE($PHP_GROONGA_DIR/include)
+ fi
+
+ export OLD_CPPFLAGS="$CPPFLAGS"
+ export CPPFLAGS="$CPPFLAGS $INCLUDES -DHAVE_GROONGA"
+ AC_CHECK_HEADER([groonga.h], [], AC_MSG_ERROR('groonga.h' header not found))
+ PHP_SUBST(GROONGA_SHARED_LIBADD)
+
+
+ PHP_CHECK_LIBRARY(groonga, grn_init,
+ [
+ PHP_ADD_LIBRARY_WITH_PATH(groonga, $PHP_GROONGA_DIR/lib, GROONGA_SHARED_LIBADD)
+ ],[
+ AC_MSG_ERROR([wrong groonga lib version or lib not found])
+ ],[
+ -L$PHP_GROONGA_DIR/lib
+ ])
+ export CPPFLAGS="$OLD_CPPFLAGS"
+
+ export OLD_CPPFLAGS="$CPPFLAGS"
+ export CPPFLAGS="$CPPFLAGS $INCLUDES -DHAVE_GROONGA"
+
+ AC_MSG_CHECKING(PHP version)
+ AC_TRY_COMPILE([#include <php_version.h>], [
+#if PHP_VERSION_ID < 40000
+#error this extension requires at least PHP version 4.0.0
+#endif
+],
+[AC_MSG_RESULT(ok)],
+[AC_MSG_ERROR([need at least PHP 4.0.0])])
+
+ export CPPFLAGS="$OLD_CPPFLAGS"
+
+
+ PHP_SUBST(GROONGA_SHARED_LIBADD)
+ AC_DEFINE(HAVE_GROONGA, 1, [ ])
+
+ PHP_NEW_EXTENSION(groonga, groonga.c , $ext_shared)
+
+fi
+
diff --git a/storage/mroonga/vendor/groonga/bindings/php/config.w32 b/storage/mroonga/vendor/groonga/bindings/php/config.w32
new file mode 100644
index 00000000..d0fab53b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/php/config.w32
@@ -0,0 +1,6 @@
+ARG_WITH('groonga', 'Groonga', 'no');
+
+if (PHP_GROONGA == "yes") {
+ EXTENSION("groonga", "groonga.c");
+ AC_DEFINE("HAVE_GROONGA", 1, "groonga support");
+}
diff --git a/storage/mroonga/vendor/groonga/bindings/php/groonga.c b/storage/mroonga/vendor/groonga/bindings/php/groonga.c
new file mode 100644
index 00000000..a04bb9cd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/php/groonga.c
@@ -0,0 +1,221 @@
+
+#include "php_groonga.h"
+
+#if HAVE_GROONGA
+
+int le_grn_ctx;
+void grn_ctx_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ grn_ctx *ctx = (grn_ctx *)(rsrc->ptr);
+ grn_ctx_close(ctx);
+}
+
+zend_function_entry groonga_functions[] = {
+ PHP_FE(grn_ctx_init , grn_ctx_init_arg_info)
+ PHP_FE(grn_ctx_close , grn_ctx_close_arg_info)
+ PHP_FE(grn_ctx_connect , grn_ctx_connect_arg_info)
+ PHP_FE(grn_ctx_send , grn_ctx_send_arg_info)
+ PHP_FE(grn_ctx_recv , grn_ctx_recv_arg_info)
+ { NULL, NULL, NULL }
+};
+
+
+zend_module_entry groonga_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "groonga",
+ groonga_functions,
+ PHP_MINIT(groonga),
+ PHP_MSHUTDOWN(groonga),
+ PHP_RINIT(groonga),
+ PHP_RSHUTDOWN(groonga),
+ PHP_MINFO(groonga),
+ "0.1",
+ STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_GROONGA
+ZEND_GET_MODULE(groonga)
+#endif
+
+
+PHP_MINIT_FUNCTION(groonga)
+{
+ REGISTER_LONG_CONSTANT("GRN_CTX_USE_QL", GRN_CTX_USE_QL, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_BATCH_MODE", GRN_CTX_BATCH_MODE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_DEFAULT", GRN_ENC_DEFAULT, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_NONE", GRN_ENC_NONE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_EUC_JP", GRN_ENC_EUC_JP, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_UTF8", GRN_ENC_UTF8, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_SJIS", GRN_ENC_SJIS, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_LATIN1", GRN_ENC_LATIN1, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_ENC_KOI8R", GRN_ENC_KOI8R, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_MORE", GRN_CTX_MORE, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_TAIL", GRN_CTX_TAIL, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_HEAD", GRN_CTX_HEAD, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_QUIET", GRN_CTX_QUIET, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_QUIT", GRN_CTX_QUIT, CONST_PERSISTENT | CONST_CS);
+ REGISTER_LONG_CONSTANT("GRN_CTX_FIN", GRN_CTX_FIN, CONST_PERSISTENT | CONST_CS);
+ le_grn_ctx = zend_register_list_destructors_ex(
+ grn_ctx_dtor, NULL, "grn_ctx", module_number);
+
+ grn_init();
+
+ return SUCCESS;
+}
+
+
+PHP_MSHUTDOWN_FUNCTION(groonga)
+{
+ grn_fin();
+ return SUCCESS;
+}
+
+
+PHP_RINIT_FUNCTION(groonga)
+{
+ return SUCCESS;
+}
+
+
+PHP_RSHUTDOWN_FUNCTION(groonga)
+{
+ return SUCCESS;
+}
+
+
+PHP_MINFO_FUNCTION(groonga)
+{
+ php_info_print_box_start(0);
+ php_printf("<p>Groonga</p>\n");
+ php_printf("<p>Version 0.2 (ctx)</p>\n");
+ php_printf("<p><b>Authors:</b></p>\n");
+ php_printf("<p>yu &lt;yu@irx.jp&gt; (lead)</p>\n");
+ php_info_print_box_end();
+}
+
+
+PHP_FUNCTION(grn_ctx_init)
+{
+ grn_ctx *ctx = (grn_ctx *) malloc(sizeof(grn_ctx));
+ long res_id = -1;
+ long flags = 0;
+ grn_rc rc;
+
+ if (ctx == NULL) {
+ RETURN_FALSE; // unable to allocate memory for ctx
+ }
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flags) == FAILURE) {
+ return;
+ }
+
+ if ((rc = grn_ctx_init(ctx, flags)) != GRN_SUCCESS) {
+ RETURN_FALSE;
+ }
+
+ res_id = ZEND_REGISTER_RESOURCE(return_value, ctx, le_grn_ctx);
+ RETURN_RESOURCE(res_id);
+}
+
+
+PHP_FUNCTION(grn_ctx_close)
+{
+ zval *res = NULL;
+ int res_id = -1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &res) == FAILURE) {
+ return;
+ }
+
+ zend_list_delete(Z_LVAL_P(res)); // call grn_ctx_dtor
+ RETURN_TRUE;
+}
+
+
+PHP_FUNCTION(grn_ctx_connect)
+{
+ zval *res = NULL;
+ int res_id = -1;
+
+ grn_rc rc;
+ grn_ctx *ctx;
+ char *host = "localhost";
+ int host_len = 0;
+ long port = 10041;
+ long flags = 0;
+
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|ll", &res, &host, &host_len, &port, &flags) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ctx, grn_ctx *, &res, res_id, "grn_ctx", le_grn_ctx);
+
+ if ((rc = grn_ctx_connect(ctx, host, port, flags)) != GRN_SUCCESS) {
+ RETURN_FALSE;
+ }
+
+ RETURN_TRUE;
+}
+
+
+PHP_FUNCTION(grn_ctx_send)
+{
+ zval *res = NULL;
+ int res_id = -1;
+
+ grn_ctx *ctx;
+ char *query = NULL;
+ unsigned int query_len, qid;
+ long flags = 0;
+
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|l", &res, &query, &query_len, &flags) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ctx, grn_ctx *, &res, res_id, "grn_ctx", le_grn_ctx);
+ qid = grn_ctx_send(ctx, query, query_len, flags);
+ if (ctx->rc != GRN_SUCCESS) {
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(qid)
+
+}
+
+
+PHP_FUNCTION(grn_ctx_recv)
+{
+ zval *res,*ret = NULL;
+ int res_id = -1;
+ grn_ctx *ctx;
+
+ char *str;
+ int flags;
+ unsigned int str_len, qid;
+
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &res) == FAILURE) {
+ return;
+ }
+
+ ZEND_FETCH_RESOURCE(ctx, grn_ctx *, &res, res_id, "grn_ctx", le_grn_ctx);
+
+ qid = grn_ctx_recv(ctx, &str, &str_len, &flags);
+
+ if (ctx->rc != GRN_SUCCESS) {
+ RETURN_FALSE;
+ }
+
+ MAKE_STD_ZVAL(ret);
+ array_init(ret);
+ array_init(return_value);
+
+ add_next_index_long(ret, flags);
+ add_next_index_stringl(ret, str, str_len, 1);
+
+ add_index_zval(return_value, qid, ret);
+}
+
+#endif /* HAVE_GROONGA */
diff --git a/storage/mroonga/vendor/groonga/bindings/php/groonga.dsp b/storage/mroonga/vendor/groonga/bindings/php/groonga.dsp
new file mode 100644
index 00000000..dd7c91ce
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/php/groonga.dsp
@@ -0,0 +1,112 @@
+# Microsoft Developer Studio Project File - Name="groonga" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=groonga - Win32 Debug_TS
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "groonga.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "groonga.mak" CFG="groonga - Win32 Debug_TS"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "groonga - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "groonga - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "groonga - Win32 Release_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release_TS"
+# PROP BASE Intermediate_Dir "Release_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release_TS"
+# PROP Intermediate_Dir "Release_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GROONGA_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D "WIN32" /D "PHP_EXPORTS" /D "COMPILE_DL_GROONGA" /D ZTS=1 /D HAVE_GROONGA=1 /D ZEND_DEBUG=0 /D "NDEBUG" /D "_WINDOWS" /D "ZEND_WIN32" /D "PHP_WIN32" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x407 /d "NDEBUG"
+# ADD RSC /l 0x407 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 php4ts.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS\php_groonga.dll" /libpath:"..\..\Release_TS" /libpath:"..\..\Release_TS_Inline"
+
+!ELSEIF "$(CFG)" == "groonga - Win32 Debug_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug_TS"
+# PROP BASE Intermediate_Dir "Debug_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug_TS"
+# PROP Intermediate_Dir "Debug_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "GROONGA_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\Zend" /I "..\..\TSRM" /I "..\..\main" /D ZEND_DEBUG=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "PHP_EXPORTS" /D "COMPILE_DL_GROONGA" /D ZTS=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D HAVE_GROONGA=1 /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x407 /d "_DEBUG"
+# ADD RSC /l 0x407 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 php4ts_debug.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS\php_groonga.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
+
+!ENDIF
+
+# Begin Target
+
+# Name "groonga - Win32 Release_TS"
+# Name "groonga - Win32 Debug_TS"
+
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+
+# Begin Source File
+
+SOURCE=./groonga.c
+# End Source File
+
+# End Group
+
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+
+# Begin Source File
+
+SOURCE=.\php_groonga.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/storage/mroonga/vendor/groonga/bindings/php/php_groonga.h b/storage/mroonga/vendor/groonga/bindings/php/php_groonga.h
new file mode 100644
index 00000000..3af4427f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/php/php_groonga.h
@@ -0,0 +1,125 @@
+/*
+ +----------------------------------------------------------------------+
+ | unknown license: |
+ +----------------------------------------------------------------------+
+ | Authors: yu <yu@irx.jp> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_GROONGA_H
+#define PHP_GROONGA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <php.h>
+
+#ifdef HAVE_GROONGA
+
+#include <php_ini.h>
+#include <SAPI.h>
+#include <ext/standard/info.h>
+#include <Zend/zend_extensions.h>
+#ifdef __cplusplus
+} // extern "C"
+#endif
+#include <groonga.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern zend_module_entry groonga_module_entry;
+#define phpext_groonga_ptr &groonga_module_entry
+
+#ifdef PHP_WIN32
+#define PHP_GROONGA_API __declspec(dllexport)
+#else
+#define PHP_GROONGA_API
+#endif
+
+PHP_MINIT_FUNCTION(groonga);
+PHP_MSHUTDOWN_FUNCTION(groonga);
+PHP_RINIT_FUNCTION(groonga);
+PHP_RSHUTDOWN_FUNCTION(groonga);
+PHP_MINFO_FUNCTION(groonga);
+
+#ifdef ZTS
+#include "TSRM.h"
+#endif
+
+#define FREE_RESOURCE(resource) zend_list_delete(Z_LVAL_P(resource))
+
+#define PROP_GET_LONG(name) Z_LVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
+#define PROP_SET_LONG(name, l) zend_update_property_long(_this_ce, _this_zval, #name, strlen(#name), l TSRMLS_CC)
+
+#define PROP_GET_DOUBLE(name) Z_DVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
+#define PROP_SET_DOUBLE(name, d) zend_update_property_double(_this_ce, _this_zval, #name, strlen(#name), d TSRMLS_CC)
+
+#define PROP_GET_STRING(name) Z_STRVAL_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
+#define PROP_GET_STRLEN(name) Z_STRLEN_P(zend_read_property(_this_ce, _this_zval, #name, strlen(#name), 1 TSRMLS_CC))
+#define PROP_SET_STRING(name, s) zend_update_property_string(_this_ce, _this_zval, #name, strlen(#name), s TSRMLS_CC)
+#define PROP_SET_STRINGL(name, s, l) zend_update_property_stringl(_this_ce, _this_zval, #name, strlen(#name), s, l TSRMLS_CC)
+
+
+PHP_FUNCTION(grn_ctx_init);
+#if (PHP_MAJOR_VERSION >= 5)
+ZEND_BEGIN_ARG_INFO_EX(grn_ctx_init_arg_info, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+#else /* PHP 4.x */
+#define grn_ctx_init_arg_info NULL
+#endif
+
+PHP_FUNCTION(grn_ctx_close);
+#if (PHP_MAJOR_VERSION >= 5)
+ZEND_BEGIN_ARG_INFO_EX(grn_ctx_close_arg_info, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, res)
+ZEND_END_ARG_INFO()
+#else /* PHP 4.x */
+#define grn_ctx_close_arg_info NULL
+#endif
+
+PHP_FUNCTION(grn_ctx_connect);
+#if (PHP_MAJOR_VERSION >= 5)
+ZEND_BEGIN_ARG_INFO_EX(grn_ctx_connect_arg_info, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 4)
+ ZEND_ARG_INFO(0, res)
+ ZEND_ARG_INFO(0, host)
+ ZEND_ARG_INFO(0, port)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+#else /* PHP 4.x */
+#define grn_ctx_connect_arg_info NULL
+#endif
+
+PHP_FUNCTION(grn_ctx_send);
+#if (PHP_MAJOR_VERSION >= 5)
+ZEND_BEGIN_ARG_INFO_EX(grn_ctx_send_arg_info, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 3)
+ ZEND_ARG_INFO(0, res)
+ ZEND_ARG_INFO(0, query)
+ ZEND_ARG_INFO(0, flags)
+ZEND_END_ARG_INFO()
+#else /* PHP 4.x */
+#define grn_ctx_send_arg_info NULL
+#endif
+
+PHP_FUNCTION(grn_ctx_recv);
+#if (PHP_MAJOR_VERSION >= 5)
+ZEND_BEGIN_ARG_INFO_EX(grn_ctx_recv_arg_info, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, res)
+ZEND_END_ARG_INFO()
+#else /* PHP 4.x */
+#define grn_ctx_recv_arg_info NULL
+#endif
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* PHP_HAVE_GROONGA */
+
+#endif /* PHP_GROONGA_H */
diff --git a/storage/mroonga/vendor/groonga/bindings/php/tests/001.phpt b/storage/mroonga/vendor/groonga/bindings/php/tests/001.phpt
new file mode 100644
index 00000000..d215b3ea
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/php/tests/001.phpt
@@ -0,0 +1,29 @@
+--TEST--
+groonga connection
+--DESCRIPTION--
+required: variables_order includes "E"
+--SKIPIF--
+<?php
+if (!extension_loaded("groonga")) print "skip";
+if (!getenv('GROONGA_TEST_HOST')) print "skip";
+?>
+--FILE--
+<?php
+$host = getenv('GROONGA_TEST_HOST');
+$port = getenv('GROONGA_TEST_PORT') ? getenv('GROONGA_TEST_PORT') : 10041;
+
+$grn = grn_ctx_init();
+grn_ctx_connect($grn, $host, $port) or die("cannot connect groong server ({$host}:{$port})");
+grn_ctx_send($grn, 'table_list');
+var_dump(grn_ctx_recv($grn));
+grn_ctx_close($grn);
+--EXPECTF--
+array(1) {
+ [0]=>
+ array(2) {
+ [0]=>
+ int(0)
+ [1]=>
+ string(%d) "%s"
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/bindings/python/ql/groongaql.c b/storage/mroonga/vendor/groonga/bindings/python/ql/groongaql.c
new file mode 100644
index 00000000..27a35ab9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/python/ql/groongaql.c
@@ -0,0 +1,364 @@
+/* Copyright(C) 2007 Brazil
+
+ 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-1335 USA
+*/
+#include <Python.h>
+#include <groonga.h>
+
+/* TODO: use exception */
+
+typedef struct {
+ PyObject_HEAD
+ grn_ctx ctx;
+ int closed;
+} groongaql_ContextObject;
+
+static PyTypeObject groongaql_ContextType;
+
+/* Object methods */
+
+static PyObject *
+groongaql_ContextObject_new(PyTypeObject *type, PyObject *args, PyObject *keywds)
+{
+ grn_rc rc;
+ int flags;
+ grn_encoding encoding;
+ groongaql_ContextObject *self;
+
+ static char *kwlist[] = {"flags", "encoding", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii", kwlist,
+ &flags, &encoding)) {
+ return NULL;
+ }
+ if (!(self = (groongaql_ContextObject *)type->tp_alloc(type, 0))) {
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ rc = grn_ctx_init(&self->ctx, flags);
+ GRN_CTX_SET_ENCODING(&self->ctx, encoding);
+ Py_END_ALLOW_THREADS
+ if (rc) {
+ self->ob_type->tp_free(self);
+ return NULL;
+ }
+ self->closed = 0;
+ return (PyObject *)self;
+}
+
+static void
+groongaql_ContextObject_dealloc(groongaql_ContextObject *self)
+{
+ if (!self->closed) {
+ Py_BEGIN_ALLOW_THREADS
+ grn_ctx_fin(&self->ctx);
+ Py_END_ALLOW_THREADS
+ }
+ self->ob_type->tp_free(self);
+}
+
+/* Class methods */
+
+/* instance methods */
+
+static PyObject *
+groongaql_ContextClass_ql_connect(groongaql_ContextObject *self, PyObject *args, PyObject *keywds)
+{
+ grn_rc rc;
+ int port, flags;
+ const char *host;
+ static char *kwlist[] = {"host", "port", "flags", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "sii", kwlist,
+ &host, &port, &flags)) {
+ return NULL;
+ }
+ if (self->closed) { return NULL; }
+ Py_BEGIN_ALLOW_THREADS
+ rc = grn_ctx_connect(&self->ctx, host, port, flags);
+ Py_END_ALLOW_THREADS
+ return Py_BuildValue("i", rc);
+}
+
+static PyObject *
+groongaql_Context_ql_send(groongaql_ContextObject *self, PyObject *args, PyObject *keywds)
+{
+ grn_rc rc;
+ char *str;
+ int str_len, flags;
+ static char *kwlist[] = {"str", "flags", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, keywds, "s#i", kwlist,
+ &str,
+ &str_len,
+ &flags)) {
+ return NULL;
+ }
+ if (self->closed) { return NULL; }
+ Py_BEGIN_ALLOW_THREADS
+ rc = grn_ctx_send(&self->ctx, str, str_len, flags);
+ Py_END_ALLOW_THREADS
+ return Py_BuildValue("i", rc);
+}
+
+static PyObject *
+groongaql_Context_ql_recv(groongaql_ContextObject *self)
+{
+ grn_rc rc;
+ int flags;
+ char *str;
+ unsigned int str_len;
+
+ if (self->closed) { return NULL; }
+ Py_BEGIN_ALLOW_THREADS
+ rc = grn_ctx_recv(&self->ctx, &str, &str_len, &flags);
+ Py_END_ALLOW_THREADS
+ return Py_BuildValue("(is#i)", rc, str, str_len, flags);
+}
+
+static PyObject *
+groongaql_Context_fin(groongaql_ContextObject *self)
+{
+ grn_rc rc;
+
+ if (self->closed) { return NULL; }
+ Py_BEGIN_ALLOW_THREADS
+ rc = grn_ctx_fin(&self->ctx);
+ Py_END_ALLOW_THREADS
+ if (!rc) {
+ self->closed = 1;
+ }
+ return Py_BuildValue("i", rc);
+}
+
+static PyObject *
+groongaql_Context_ql_info_get(groongaql_ContextObject *self)
+{
+ grn_rc rc;
+ grn_ctx_info info;
+
+ if (self->closed) { return NULL; }
+ rc = grn_ctx_info_get(&self->ctx, &info);
+ /* TODO: handling unsigned int properlly */
+ /* TODO: get outbuf */
+ return Py_BuildValue("{s:i,s:i,s:i}",
+ "rc", rc,
+ "com_status", info.com_status,
+ /* "outbuf", info.outbuf, */
+ "stat", info.stat
+ );
+}
+
+/* methods of classes */
+
+static PyMethodDef groongaql_Context_methods[] = {
+ {"ql_connect", (PyCFunction)groongaql_ContextClass_ql_connect,
+ METH_VARARGS | METH_KEYWORDS,
+ "Create a remote groonga context."},
+ {"ql_send", (PyCFunction)groongaql_Context_ql_send,
+ METH_VARARGS | METH_KEYWORDS,
+ "Send message to context."},
+ {"ql_recv", (PyCFunction)groongaql_Context_ql_recv,
+ METH_NOARGS,
+ "Receive message from context."},
+ {"fin", (PyCFunction)groongaql_Context_fin,
+ METH_NOARGS,
+ "Release groonga context."},
+ {"ql_info_get", (PyCFunction)groongaql_Context_ql_info_get,
+ METH_NOARGS,
+ "Get QL context information."},
+ {NULL, NULL, 0, NULL}
+};
+
+static PyMethodDef module_methods[] = {
+ {NULL, NULL, 0, NULL}
+};
+
+/* type objects */
+
+static PyTypeObject groongaql_ContextType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "groongaql.Context", /* tp_name */
+ sizeof(groongaql_ContextObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)groongaql_ContextObject_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "groonga Context objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ groongaql_Context_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ groongaql_ContextObject_new, /* tp_new */
+};
+
+/* consts */
+
+typedef struct _ConstPair {
+ const char *name;
+ int value;
+} ConstPair;
+
+static ConstPair consts[] = {
+ /* grn_rc */
+ {"SUCCESS", GRN_SUCCESS},
+ {"END_OF_DATA", GRN_END_OF_DATA},
+ {"UNKNOWN_ERROR", GRN_UNKNOWN_ERROR},
+ {"OPERATION_NOT_PERMITTED", GRN_OPERATION_NOT_PERMITTED},
+ {"NO_SUCH_FILE_OR_DIRECTORY", GRN_NO_SUCH_FILE_OR_DIRECTORY},
+ {"NO_SUCH_PROCESS", GRN_NO_SUCH_PROCESS},
+ {"INTERRUPTED_FUNCTION_CALL", GRN_INTERRUPTED_FUNCTION_CALL},
+ {"INPUT_OUTPUT_ERROR", GRN_INPUT_OUTPUT_ERROR},
+ {"NO_SUCH_DEVICE_OR_ADDRESS", GRN_NO_SUCH_DEVICE_OR_ADDRESS},
+ {"ARG_LIST_TOO_LONG", GRN_ARG_LIST_TOO_LONG},
+ {"EXEC_FORMAT_ERROR", GRN_EXEC_FORMAT_ERROR},
+ {"BAD_FILE_DESCRIPTOR", GRN_BAD_FILE_DESCRIPTOR},
+ {"NO_CHILD_PROCESSES", GRN_NO_CHILD_PROCESSES},
+ {"RESOURCE_TEMPORARILY_UNAVAILABLE", GRN_RESOURCE_TEMPORARILY_UNAVAILABLE},
+ {"NOT_ENOUGH_SPACE", GRN_NOT_ENOUGH_SPACE},
+ {"PERMISSION_DENIED", GRN_PERMISSION_DENIED},
+ {"BAD_ADDRESS", GRN_BAD_ADDRESS},
+ {"RESOURCE_BUSY", GRN_RESOURCE_BUSY},
+ {"FILE_EXISTS", GRN_FILE_EXISTS},
+ {"IMPROPER_LINK", GRN_IMPROPER_LINK},
+ {"NO_SUCH_DEVICE", GRN_NO_SUCH_DEVICE},
+ {"NOT_A_DIRECTORY", GRN_NOT_A_DIRECTORY},
+ {"IS_A_DIRECTORY", GRN_IS_A_DIRECTORY},
+ {"INVALID_ARGUMENT", GRN_INVALID_ARGUMENT},
+ {"TOO_MANY_OPEN_FILES_IN_SYSTEM", GRN_TOO_MANY_OPEN_FILES_IN_SYSTEM},
+ {"TOO_MANY_OPEN_FILES", GRN_TOO_MANY_OPEN_FILES},
+ {"INAPPROPRIATE_I_O_CONTROL_OPERATION", GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION},
+ {"FILE_TOO_LARGE", GRN_FILE_TOO_LARGE},
+ {"NO_SPACE_LEFT_ON_DEVICE", GRN_NO_SPACE_LEFT_ON_DEVICE},
+ {"INVALID_SEEK", GRN_INVALID_SEEK},
+ {"READ_ONLY_FILE_SYSTEM", GRN_READ_ONLY_FILE_SYSTEM},
+ {"TOO_MANY_LINKS", GRN_TOO_MANY_LINKS},
+ {"BROKEN_PIPE", GRN_BROKEN_PIPE},
+ {"DOMAIN_ERROR", GRN_DOMAIN_ERROR},
+ {"RESULT_TOO_LARGE", GRN_RESULT_TOO_LARGE},
+ {"RESOURCE_DEADLOCK_AVOIDED", GRN_RESOURCE_DEADLOCK_AVOIDED},
+ {"NO_MEMORY_AVAILABLE", GRN_NO_MEMORY_AVAILABLE},
+ {"FILENAME_TOO_LONG", GRN_FILENAME_TOO_LONG},
+ {"NO_LOCKS_AVAILABLE", GRN_NO_LOCKS_AVAILABLE},
+ {"FUNCTION_NOT_IMPLEMENTED", GRN_FUNCTION_NOT_IMPLEMENTED},
+ {"DIRECTORY_NOT_EMPTY", GRN_DIRECTORY_NOT_EMPTY},
+ {"ILLEGAL_BYTE_SEQUENCE", GRN_ILLEGAL_BYTE_SEQUENCE},
+ {"SOCKET_NOT_INITIALIZED", GRN_SOCKET_NOT_INITIALIZED},
+ {"OPERATION_WOULD_BLOCK", GRN_OPERATION_WOULD_BLOCK},
+ {"ADDRESS_IS_NOT_AVAILABLE", GRN_ADDRESS_IS_NOT_AVAILABLE},
+ {"NETWORK_IS_DOWN", GRN_NETWORK_IS_DOWN},
+ {"NO_BUFFER", GRN_NO_BUFFER},
+ {"SOCKET_IS_ALREADY_CONNECTED", GRN_SOCKET_IS_ALREADY_CONNECTED},
+ {"SOCKET_IS_NOT_CONNECTED", GRN_SOCKET_IS_NOT_CONNECTED},
+ {"SOCKET_IS_ALREADY_SHUTDOWNED", GRN_SOCKET_IS_ALREADY_SHUTDOWNED},
+ {"OPERATION_TIMEOUT", GRN_OPERATION_TIMEOUT},
+ {"CONNECTION_REFUSED", GRN_CONNECTION_REFUSED},
+ {"RANGE_ERROR", GRN_RANGE_ERROR},
+ {"TOKENIZER_ERROR", GRN_TOKENIZER_ERROR},
+ {"FILE_CORRUPT", GRN_FILE_CORRUPT},
+ {"INVALID_FORMAT", GRN_INVALID_FORMAT},
+ {"OBJECT_CORRUPT", GRN_OBJECT_CORRUPT},
+ {"TOO_MANY_SYMBOLIC_LINKS", GRN_TOO_MANY_SYMBOLIC_LINKS},
+ {"NOT_SOCKET", GRN_NOT_SOCKET},
+ {"OPERATION_NOT_SUPPORTED", GRN_OPERATION_NOT_SUPPORTED},
+ {"ADDRESS_IS_IN_USE", GRN_ADDRESS_IS_IN_USE},
+ {"ZLIB_ERROR", GRN_ZLIB_ERROR},
+ {"LZO_ERROR", GRN_LZO_ERROR},
+ /* grn_encoding */
+ {"ENC_DEFAULT", GRN_ENC_DEFAULT},
+ {"ENC_NONE", GRN_ENC_NONE},
+ {"ENC_EUC_JP", GRN_ENC_EUC_JP},
+ {"ENC_UTF8", GRN_ENC_UTF8},
+ {"ENC_SJIS", GRN_ENC_SJIS},
+ {"ENC_LATIN1", GRN_ENC_LATIN1},
+ {"ENC_KOI8R", GRN_ENC_KOI8R},
+ /* grn_ctx flags */
+ {"CTX_USE_QL", GRN_CTX_USE_QL},
+ {"CTX_BATCH_MODE", GRN_CTX_BATCH_MODE},
+ {"CTX_MORE", GRN_CTX_MORE},
+ {"CTX_TAIL", GRN_CTX_TAIL},
+ {"CTX_HEAD", GRN_CTX_HEAD},
+ {"CTX_QUIET", GRN_CTX_QUIET},
+ {"CTX_QUIT", GRN_CTX_QUIT},
+ {"CTX_FIN", GRN_CTX_FIN},
+ /* end */
+ {NULL, 0}
+};
+
+#ifndef PyMODINIT_FUNC
+#define PyMODINIT_FUNC void
+#endif
+PyMODINIT_FUNC
+initgroongaql(void)
+{
+ unsigned int i;
+ PyObject *m, *dict;
+
+ if (!(m = Py_InitModule3("groongaql", module_methods,
+ "groonga ql module."))) {
+ goto exit;
+ }
+ grn_init();
+
+ /* register classes */
+
+ if (PyType_Ready(&groongaql_ContextType) < 0) { goto exit; }
+ Py_INCREF(&groongaql_ContextType);
+ PyModule_AddObject(m, "Context", (PyObject *)&groongaql_ContextType);
+
+ /* register consts */
+
+ if (!(dict = PyModule_GetDict(m))) { goto exit; }
+
+ for (i = 0; consts[i].name; i++) {
+ PyObject *v;
+ if (!(v = PyInt_FromLong(consts[i].value))) {
+ goto exit;
+ }
+ PyDict_SetItemString(dict, consts[i].name, v);
+ Py_DECREF(v);
+ }
+ if (Py_AtExit((void (*)(void))grn_fin)) { goto exit; }
+exit:
+ if (PyErr_Occurred()) {
+ PyErr_SetString(PyExc_ImportError, "groongaql: init failed");
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/bindings/python/ql/setup.py b/storage/mroonga/vendor/groonga/bindings/python/ql/setup.py
new file mode 100755
index 00000000..3b800554
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bindings/python/ql/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+from distutils.core import setup, Extension
+
+#cflags = ['-Wall', '-fPIC', '-g', '-O0']
+cflags = ['-Wall', '-fPIC', '-O3']
+
+ext = Extension('groongaql',
+ libraries = ['groonga'],
+ sources = ['groongaql.c'],
+ extra_compile_args = cflags)
+
+setup(name = 'groongaql',
+ version = '1.0',
+ description = 'python GQTP',
+ long_description = '''
+ This is a GQTP Python API package.
+ ''',
+ license='GNU LESSER GENERAL PUBLIC LICENSE',
+ author = 'Brazil',
+ author_email = 'groonga at razil.jp',
+ ext_modules = [ext]
+ )
diff --git a/storage/mroonga/vendor/groonga/build/Makefile.am b/storage/mroonga/vendor/groonga/build/Makefile.am
new file mode 100644
index 00000000..506a11dc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = \
+ cmake_modules
diff --git a/storage/mroonga/vendor/groonga/build/ac_macros/check_functions.m4 b/storage/mroonga/vendor/groonga/build/ac_macros/check_functions.m4
new file mode 100644
index 00000000..a0b424b3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/ac_macros/check_functions.m4
@@ -0,0 +1,11 @@
+# -*- autoconf -*-
+
+AC_CHECK_FUNCS(_gmtime64_s)
+AC_CHECK_FUNCS(_localtime64_s)
+AC_CHECK_FUNCS(_strtoui64)
+AC_CHECK_FUNCS(gmtime_r)
+AC_CHECK_FUNCS(localtime_r)
+AC_CHECK_FUNCS(mkstemp)
+AC_CHECK_FUNCS(strcasecmp)
+AC_CHECK_FUNCS(strncasecmp)
+AC_CHECK_FUNCS(strtoull)
diff --git a/storage/mroonga/vendor/groonga/build/ac_macros/check_headers.m4 b/storage/mroonga/vendor/groonga/build/ac_macros/check_headers.m4
new file mode 100644
index 00000000..fca84651
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/ac_macros/check_headers.m4
@@ -0,0 +1,19 @@
+# -*- autoconf -*-
+
+AC_CHECK_HEADERS(dirent.h)
+AC_CHECK_HEADERS(dlfcn.h)
+AC_CHECK_HEADERS(errno.h)
+AC_CHECK_HEADERS(execinfo.h)
+AC_CHECK_HEADERS(inttypes.h)
+AC_CHECK_HEADERS(netdb.h)
+AC_CHECK_HEADERS(signal.h)
+AC_CHECK_HEADERS(sys/mman.h)
+AC_CHECK_HEADERS(sys/param.h)
+AC_CHECK_HEADERS(sys/resource.h)
+AC_CHECK_HEADERS(sys/socket.h)
+AC_CHECK_HEADERS(sys/sysctl.h)
+AC_CHECK_HEADERS(sys/time.h)
+AC_CHECK_HEADERS(sys/wait.h)
+AC_CHECK_HEADERS(time.h)
+AC_CHECK_HEADERS(ucontext.h)
+AC_CHECK_HEADERS(unistd.h)
diff --git a/storage/mroonga/vendor/groonga/build/cmake_modules/Makefile.am b/storage/mroonga/vendor/groonga/build/cmake_modules/Makefile.am
new file mode 100644
index 00000000..83fb0f0c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/cmake_modules/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+ ReadFileList.cmake
diff --git a/storage/mroonga/vendor/groonga/build/cmake_modules/ReadFileList.cmake b/storage/mroonga/vendor/groonga/build/cmake_modules/ReadFileList.cmake
new file mode 100644
index 00000000..204f59f6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/cmake_modules/ReadFileList.cmake
@@ -0,0 +1,27 @@
+# Copyright(C) 2012 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+macro(read_file_list file_name output_variable)
+ file(READ ${file_name} ${output_variable})
+ # Remove variable declaration at the first line:
+ # "libgroonga_la_SOURCES = \" -> ""
+ string(REGEX REPLACE "^.*=[ \t]*\\\\" ""
+ ${output_variable} "${${output_variable}}")
+ # Remove white spaces: " com.c \\\n com.h \\\n" -> "com.c\\com.h"
+ string(REGEX REPLACE "[ \t\n]" "" ${output_variable} "${${output_variable}}")
+ # Convert string to list: "com.c\\com.h" -> "com.c;com.h"
+ # NOTE: List in CMake is ";" separated string.
+ string(REGEX REPLACE "\\\\" ";" ${output_variable} "${${output_variable}}")
+endmacro()
diff --git a/storage/mroonga/vendor/groonga/build/makefiles/LC_MESSAGES.am b/storage/mroonga/vendor/groonga/build/makefiles/LC_MESSAGES.am
new file mode 100644
index 00000000..acfc3da2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/makefiles/LC_MESSAGES.am
@@ -0,0 +1,5 @@
+BUILT_SOURCES =
+EXTRA_DIST =
+SUFFIXES =
+
+include $(top_srcdir)/build/makefiles/gettext.am
diff --git a/storage/mroonga/vendor/groonga/build/makefiles/gettext.am b/storage/mroonga/vendor/groonga/build/makefiles/gettext.am
new file mode 100644
index 00000000..c6e57c7b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/makefiles/gettext.am
@@ -0,0 +1,84 @@
+include $(top_srcdir)/doc/files.am
+include $(top_srcdir)/build/makefiles/sphinx-build.am
+
+CLEANFILES =
+
+EXTRA_DIST += \
+ $(po_files)
+
+if DOCUMENT_AVAILABLE
+EXTRA_DIST += \
+ $(mo_files)
+endif
+
+if DOCUMENT_BUILDABLE
+BUILT_SOURCES += \
+ mo-build-stamp
+CLEANFILES += \
+ pot-build-stamp \
+ edit-po-build-stamp \
+ mo-build-stamp
+endif
+
+SUFFIXES += .pot .po .mo .edit
+
+.PHONY: gettext update build
+
+.pot.edit:
+ if test -f $*.po; then \
+ msgmerge \
+ --quiet \
+ --sort-by-file \
+ --output-file=$@.tmp \
+ $*.po \
+ $<; \
+ else \
+ msginit \
+ --input=$< \
+ --output-file=$@.tmp \
+ --locale=$(LOCALE) \
+ --no-translator; \
+ fi
+ (echo "# -*- po -*-"; \
+ GREP_OPTIONS= grep -v '^# -\*- po -\*-' $@.tmp | \
+ GREP_OPTIONS= grep -v '^"POT-Creation-Date:') > $@
+ rm $@.tmp
+
+.edit.po:
+ msgcat --no-location --output $@ $<
+
+.po.mo:
+ msgfmt -o $@ $<
+
+if DOCUMENT_BUILDABLE
+update: edit-po-build-stamp
+build: mo-build-stamp
+else
+update:
+build:
+endif
+
+html: build
+
+gettext:
+ rm *.pot || true
+ $(SPHINX_BUILD_COMMAND) -d doctrees -b gettext $(ALLSPHINXOPTS) .
+ xgettext --language Python --output conf.pot \
+ $(top_srcdir)/doc/source/conf.py
+
+pot-build-stamp: $(absolute_source_files)
+ $(MAKE) gettext
+ @touch $@
+
+edit-po-build-stamp: pot-build-stamp
+ $(MAKE) $(edit_po_files)
+ @touch $@
+
+mo_build_stamp_dependencies = edit-po-build-stamp
+if DOCUMENT_BUILDABLE
+mo_build_stamp_dependencies += $(edit_po_files)
+endif
+
+mo-build-stamp: $(mo_build_stamp_dependencies)
+ $(MAKE) $(mo_files)
+ @touch $@
diff --git a/storage/mroonga/vendor/groonga/build/makefiles/locale.am b/storage/mroonga/vendor/groonga/build/makefiles/locale.am
new file mode 100644
index 00000000..414c19a7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/makefiles/locale.am
@@ -0,0 +1,12 @@
+SUBDIRS = LC_MESSAGES
+
+BUILT_SOURCES =
+EXTRA_DIST =
+
+include $(top_srcdir)/build/makefiles/sphinx.am
+
+init:
+ cd LC_MESSAGES && $(MAKE) $@
+
+update-po:
+ cd LC_MESSAGES && $(MAKE) update
diff --git a/storage/mroonga/vendor/groonga/build/makefiles/sphinx-build.am b/storage/mroonga/vendor/groonga/build/makefiles/sphinx-build.am
new file mode 100644
index 00000000..047823b6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/makefiles/sphinx-build.am
@@ -0,0 +1,14 @@
+# You can set these variables from the command line.
+DOCTREES_BASE = doctrees
+
+SPHINXOPTS =
+
+# Internal variables.
+SOURCE_DIR = $(abs_top_srcdir)/doc/source
+ALLSPHINXOPTS = -E $(SPHINXOPTS) $(SOURCE_DIR)
+
+SPHINX_BUILD_COMMAND = \
+ DOCUMENT_VERSION="$(DOCUMENT_VERSION)" \
+ DOCUMENT_VERSION_FULL="$(DOCUMENT_VERSION_FULL)" \
+ LOCALE="$(LOCALE)" \
+ $(SPHINX_BUILD)
diff --git a/storage/mroonga/vendor/groonga/build/makefiles/sphinx.am b/storage/mroonga/vendor/groonga/build/makefiles/sphinx.am
new file mode 100644
index 00000000..161abe06
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/build/makefiles/sphinx.am
@@ -0,0 +1,80 @@
+include $(top_srcdir)/doc/files.am
+include $(top_srcdir)/build/makefiles/sphinx-build.am
+
+$(html_files): html-build-stamp
+$(html_files_relative_from_locale_dir): html-build-stamp
+
+am__nobase_dist_doc_locale_DATA_DIST =
+if DOCUMENT_AVAILABLE
+doc_localedir = $(docdir)/$(LOCALE)
+nobase_dist_doc_locale_DATA = \
+ $(html_files_relative_from_locale_dir)
+am__nobase_dist_doc_locale_DATA_DIST += \
+ $(nobase_dist_doc_locale_DATA)
+endif
+
+document_source_files = \
+ $(absolute_source_files) \
+ $(absolute_theme_files) \
+ $(po_files_relative_from_locale_dir) \
+ $(mo_files_relative_from_locale_dir)
+
+required_build_stamps = \
+ html-build-stamp \
+ mo-build-stamp
+
+if DOCUMENT_BUILDABLE
+EXTRA_DIST += $(required_build_stamps)
+endif
+
+generated_files = \
+ $(DOCTREES_BASE) \
+ html \
+ html-build-stamp
+
+$(mo_files_relative_from_locale_dir): mo-build-stamp
+
+mo-build-stamp: $(po_files_relative_from_locale_dir)
+ cd LC_MESSAGES && $(MAKE) build
+ @touch $@
+
+if DOCUMENT_BUILDABLE
+clean-local: $(clean_targets) clean-doctrees
+
+clean-doctrees:
+ rm -rf $(DOCTREES_BASE)
+
+maintainer-clean-local:
+ rm -rf -- $(generated_files)
+endif
+
+.PHONY: help
+.PHONY: html clean-html
+
+if DOCUMENT_BUILDABLE
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+
+html: html-recursive html-build-stamp
+
+clean_targets = \
+ clean-html
+
+$(clean_targets):
+ target=`echo $@ | sed -e 's/^clean-//'`; \
+ rm -rf $${target}-build-stamp $${target}
+
+build_stamps = \
+ html-build-stamp
+
+$(build_stamps): $(document_source_files)
+ target=`echo $@ | sed -e 's/-build-stamp$$//'`; \
+ $(SPHINX_BUILD_COMMAND) \
+ -Dlanguage=$(LOCALE) \
+ -d $(DOCTREES_BASE)/$${target} \
+ -b $${target} \
+ $(ALLSPHINXOPTS) \
+ $${target}
+ @touch $@
+endif
diff --git a/storage/mroonga/vendor/groonga/bundled_lz4_version b/storage/mroonga/vendor/groonga/bundled_lz4_version
new file mode 100644
index 00000000..6a126f40
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bundled_lz4_version
@@ -0,0 +1 @@
+1.7.5
diff --git a/storage/mroonga/vendor/groonga/bundled_mecab_naist_jdic_version b/storage/mroonga/vendor/groonga/bundled_mecab_naist_jdic_version
new file mode 100644
index 00000000..495c21ef
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bundled_mecab_naist_jdic_version
@@ -0,0 +1 @@
+0.6.3b-20111013
diff --git a/storage/mroonga/vendor/groonga/bundled_mecab_version b/storage/mroonga/vendor/groonga/bundled_mecab_version
new file mode 100644
index 00000000..00445f81
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bundled_mecab_version
@@ -0,0 +1 @@
+0.996
diff --git a/storage/mroonga/vendor/groonga/bundled_message_pack_version b/storage/mroonga/vendor/groonga/bundled_message_pack_version
new file mode 100644
index 00000000..3e3c2f1e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/bundled_message_pack_version
@@ -0,0 +1 @@
+2.1.1
diff --git a/storage/mroonga/vendor/groonga/config.h.cmake b/storage/mroonga/vendor/groonga/config.h.cmake
new file mode 100644
index 00000000..ec67c5ee
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/config.h.cmake
@@ -0,0 +1,147 @@
+/* config.h.cmake. Generated from CMakeLists.txt by cmake. */
+
+/* general constants */
+#define CONFIGURE_OPTIONS "${CONFIGURE_OPTIONS}"
+
+#define HOST_CPU "${CMAKE_SYSTEM_PROCESSOR}"
+#define HOST_OS "${CMAKE_SYSTEM_NAME}"
+
+#define VERSION "${VERSION}"
+#define PACKAGE "${PROJECT_NAME}"
+#define PACKAGE_NAME "${PROJECT_NAME}"
+#define PACKAGE_LABEL "${GRN_PROJECT_LABEL}"
+#define PACKAGE_STRING "${PROJECT_NAME} ${VERSION}"
+#define PACKAGE_TARNAME "${PROJECT_NAME}"
+#define PACKAGE_URL "${PACKAGE_URL}"
+#define PACKAGE_VERSION "${VERSION}"
+
+/* Groonga related constants */
+#define GRN_CONFIG_PATH "${GRN_CONFIG_PATH}"
+#define GRN_LOG_PATH "${GRN_LOG_PATH}"
+#define GRN_VERSION "${GRN_VERSION}"
+
+#define GRN_DEFAULT_DB_KEY "${GRN_DEFAULT_DB_KEY}"
+#define GRN_DEFAULT_ENCODING "${GRN_DEFAULT_ENCODING}"
+#define GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD \
+ ${GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD}
+#define GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT \
+ "${GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT}"
+#define GRN_DEFAULT_DOCUMENT_ROOT \
+ "${GRN_DEFAULT_DOCUMENT_ROOT}"
+
+#define GRN_STACK_SIZE ${GRN_STACK_SIZE}
+
+#define GRN_LOCK_TIMEOUT ${GRN_LOCK_TIMEOUT}
+#define GRN_LOCK_WAIT_TIME_NANOSECOND \
+ ${GRN_LOCK_WAIT_TIME_NANOSECOND}
+
+#define GRN_RELATIVE_PLUGINS_DIR \
+ "${GRN_RELATIVE_PLUGINS_DIR}"
+#define GRN_PLUGINS_DIR "${GRN_PLUGINS_DIR}"
+#define GRN_PLUGIN_SUFFIX "${GRN_PLUGIN_SUFFIX}"
+
+#define GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE "${GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE}"
+#define GRN_QUERY_EXPANDER_TSV_SYNONYMS_FILE "${GRN_QUERY_EXPANDER_TSV_SYNONYMS_FILE}"
+
+#define GRN_RELATIVE_RUBY_SCRIPTS_DIR \
+ "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}"
+#define GRN_RUBY_SCRIPTS_DIR "${GRN_RUBY_SCRIPTS_DIR}"
+
+#define GRN_DLL_FILENAME L"${GRN_DLL_FILENAME}"
+
+/* build switches */
+#cmakedefine USE_MEMORY_DEBUG
+#cmakedefine USE_MAP_HUGETLB
+#cmakedefine USE_AIO
+#cmakedefine USE_DYNAMIC_MALLOC_CHANGE
+#cmakedefine USE_EPOLL
+#cmakedefine USE_EXACT_ALLOC_COUNT
+#cmakedefine USE_FAIL_MALLOC
+#cmakedefine USE_FUTEX
+#cmakedefine USE_KQUEUE
+#cmakedefine USE_MSG_MORE
+#cmakedefine USE_MSG_NOSIGNAL
+#cmakedefine USE_POLL
+#cmakedefine USE_QUERY_ABORT
+#cmakedefine USE_SELECT
+
+/* compiler specific build options */
+#cmakedefine _FILE_OFFSET_BITS @_FILE_OFFSET_BITS@
+#ifndef _GNU_SOURCE
+ #cmakedefine _GNU_SOURCE
+#endif
+#cmakedefine _ISOC99_SOURCE
+#cmakedefine _LARGE_FILES
+#cmakedefine _NETBSD_SOURCE
+#cmakedefine _XOPEN_SOURCE
+#cmakedefine _XPG4_2
+#cmakedefine __EXTENSIONS__
+
+/* build environment */
+#cmakedefine WORDS_BIGENDIAN
+
+/* packages */
+#cmakedefine GRN_WITH_BENCHMARK
+#cmakedefine GRN_WITH_CUTTER
+#cmakedefine GRN_WITH_KYTEA
+#cmakedefine GRN_WITH_LZ4
+#cmakedefine GRN_WITH_ZSTD
+#cmakedefine GRN_WITH_MECAB
+#cmakedefine GRN_WITH_MESSAGE_PACK
+#cmakedefine GRN_WITH_MRUBY
+#cmakedefine GRN_WITH_NFKC
+#cmakedefine GRN_WITH_ONIGMO
+#cmakedefine GRN_WITH_ZEROMQ
+#cmakedefine GRN_WITH_ZLIB
+
+/* headers */
+#cmakedefine HAVE_DIRENT_H
+#cmakedefine HAVE_DLFCN_H
+#cmakedefine HAVE_ERRNO_H
+#cmakedefine HAVE_EXECINFO_H
+#cmakedefine HAVE_INTTYPES_H
+#cmakedefine HAVE_LINUX_FUTEX_H
+#cmakedefine HAVE_MEMORY_H
+#cmakedefine HAVE_NETDB_H
+#cmakedefine HAVE_PTHREAD_H
+#cmakedefine HAVE_SIGNAL_H
+#cmakedefine HAVE_SYS_MMAN_H
+#cmakedefine HAVE_SYS_PARAM_H
+#cmakedefine HAVE_SYS_POLL_H
+#cmakedefine HAVE_SYS_RESOURCE_H
+#cmakedefine HAVE_SYS_SELECT_H
+#cmakedefine HAVE_SYS_SOCKET_H
+#cmakedefine HAVE_SYS_STAT_H
+#cmakedefine HAVE_SYS_SYSCALL_H
+#cmakedefine HAVE_SYS_SYSCTL_H
+#cmakedefine HAVE_SYS_TIME_H
+#cmakedefine HAVE_SYS_WAIT_H
+#cmakedefine HAVE_TIME_H
+#cmakedefine HAVE_UCONTEXT_H
+#cmakedefine HAVE_UNISTD_H
+
+/* libraries */
+#cmakedefine HAVE_LIBEDIT
+#cmakedefine HAVE_LIBEVENT
+#cmakedefine HAVE_LIBM
+#cmakedefine HAVE_LIBRT
+
+/* structs */
+#cmakedefine HAVE_MECAB_DICTIONARY_INFO_T
+
+/* functions */
+#cmakedefine HAVE__GMTIME64_S
+#cmakedefine HAVE__LOCALTIME64_S
+#cmakedefine HAVE__STRTOUI64
+#cmakedefine HAVE_BACKTRACE
+#cmakedefine HAVE_CLOCK
+#cmakedefine HAVE_CLOCK_GETTIME
+#cmakedefine HAVE_FPCLASSIFY
+#cmakedefine HAVE_GMTIME_R
+#cmakedefine HAVE_LOCALTIME_R
+#cmakedefine HAVE_MKSTEMP
+#cmakedefine HAVE_STRCASECMP
+#cmakedefine HAVE_STRNCASECMP
+#cmakedefine HAVE_STRTOULL
+#cmakedefine HAVE_PTHREAD_MUTEXATTR_SETPSHARED
+#cmakedefine HAVE_PTHREAD_CONDATTR_SETPSHARED
diff --git a/storage/mroonga/vendor/groonga/config.sh.in b/storage/mroonga/vendor/groonga/config.sh.in
new file mode 100644
index 00000000..d15e5e36
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/config.sh.in
@@ -0,0 +1,7 @@
+export CUTTER="@CUTTER@"
+export RUBY="@RUBY@"
+export GROONGA="@GROONGA@"
+export GROONGA_HTTPD="@GROONGA_HTTPD@"
+export GROONGA_SUGGEST_CREATE_DATASET="@GROONGA_SUGGEST_CREATE_DATASET@"
+export GROONGA_BENCHMARK="@GROONGA_BENCHMARK@"
+export GROONGA_MRUBY="@GROONGA_MRUBY@"
diff --git a/storage/mroonga/vendor/groonga/configure.ac b/storage/mroonga/vendor/groonga/configure.ac
new file mode 100644
index 00000000..cab122ad
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/configure.ac
@@ -0,0 +1,1788 @@
+AC_PREREQ(2.59)
+m4_define([groonga_version], m4_include(base_version))
+AC_INIT([groonga], groonga_version, [groonga@razil.jp])
+AC_CONFIG_MACRO_DIR([m4])
+AM_CONFIG_HEADER(config.h)
+
+GRN_VERSION_RC=`echo groonga_version | sed -e 's/\./,/g'`
+AC_SUBST(GRN_VERSION_RC)
+
+AM_INIT_AUTOMAKE([foreign tar-pax subdir-objects])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+PACKAGE_LABEL=Groonga
+AC_SUBST(PACKAGE_LABEL)
+AC_DEFINE_UNQUOTED(PACKAGE_LABEL, ["$PACKAGE_LABEL"], [Label of package])
+
+# for Autoconf 2.60 or earlier.
+if test -z "${datarootdir}"; then
+ datarootdir="\${prefix}/share"
+ AC_SUBST(datarootdir)
+fi
+
+# for Autoconf 2.59 or earlier.
+if test -z "${docdir}"; then
+ docdir="\${datarootdir}/doc/\${PACKAGE_TARNAME}"
+ AC_SUBST(docdir)
+fi
+
+AC_CANONICAL_HOST
+AC_DEFINE_UNQUOTED(HOST_CPU, ["$host_cpu"], [host CPU])
+AC_DEFINE_UNQUOTED(HOST_OS, ["$host_os"], [host OS])
+
+AC_MSG_CHECKING([for native Win32])
+case "$host_os" in
+ mingw*)
+ os_win32=yes
+ ;;
+ *)
+ os_win32=no
+ ;;
+esac
+AC_MSG_RESULT([$os_win32])
+
+AC_MSG_CHECKING([for some Win32 platform])
+case "$host_os" in
+ mingw*|cygwin*)
+ platform_win32=yes
+ ;;
+ *)
+ platform_win32=no
+ ;;
+esac
+AC_MSG_RESULT([$platform_win32])
+
+AM_CONDITIONAL(OS_WIN32, test "$os_win32" = "yes")
+AM_CONDITIONAL(PLATFORM_WIN32, test "$platform_win32" = "yes")
+
+AC_MSG_CHECKING([for NetBSD.])
+case "$host_os" in
+ netbsd*)
+ netbsd=yes
+ ;;
+ *)
+ netbsd=no
+ ;;
+esac
+AC_MSG_RESULT([$netbsd])
+
+AC_MSG_CHECKING([for Solaris.])
+case "$host_os" in
+ solaris*)
+ solaris=yes
+ ;;
+ *)
+ solaris=no
+ ;;
+esac
+AC_MSG_RESULT([$solaris])
+
+AC_C_BIGENDIAN
+AC_PROG_CXX
+m4_ifdef([AX_CXX_COMPILE_STDCXX_11],
+ [AX_CXX_COMPILE_STDCXX_11([ext], [optional])])
+AC_PROG_CC
+m4_ifdef([AC_PROG_CC_C99],
+ [AC_PROG_CC_C99])
+AM_PROG_CC_C_O
+m4_ifdef([PKG_PROG_PKG_CONFIG],
+ [PKG_PROG_PKG_CONFIG([0.19])
+ m4_pattern_allow(PKG_CONFIG_LIBDIR)])
+
+AC_MSG_CHECKING([for clang])
+if test "$CC" = "clang"; then
+ CLANG=yes
+else
+ CLANG=no
+fi
+AC_MSG_RESULT([$CLANG])
+
+AC_DEFUN([CHECK_CFLAG], [
+ AC_MSG_CHECKING([if gcc supports $1])
+ old_CFLAGS=$CFLAGS
+ flag=`echo '$1' | sed -e 's,^-Wno-,-W,'`
+ CFLAGS="$CFLAGS $flag -Werror"
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+ [check_cflag=yes],
+ [check_cflag=no])
+ CFLAGS="$old_CFLAGS"
+ if test "x$check_cflag" = "xyes"; then
+ CFLAGS="$CFLAGS $1"
+ fi
+ AC_MSG_RESULT([$check_cflag])
+])
+
+AC_DEFUN([CHECK_CXXFLAG], [
+ AC_MSG_CHECKING([if g++ supports $1])
+ old_CXXFLAGS=$CXXFLAGS
+ flag=`echo '$1' | sed -e 's,^-Wno-,-W,'`
+ CXXFLAGS="$CXXFLAGS $flag -Werror"
+ AC_LANG_PUSH([C++])
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
+ [check_cxxflag=yes],
+ [check_cxxflag=no])
+ AC_LANG_POP([C++])
+ CXXFLAGS="$old_CXXFLAGS"
+ if test "x$check_cxxflag" = "xyes"; then
+ CXXFLAGS="$CXXFLAGS $1"
+ fi
+ AC_MSG_RESULT([$check_cxxflag])
+])
+
+AC_DEFUN([CHECK_BUILD_FLAG], [
+ CHECK_CFLAG([$1])
+ CHECK_CXXFLAG([$1])
+])
+
+AC_DEFUN([REMOVE_CXXFLAG], [
+ AC_MSG_CHECKING([whether g++ option $1 is needed to be removed])
+ if echo "$CXXFLAGS" | grep -q -- "$1"; then
+ CXXFLAGS=`echo "$CXXFLAGS" | sed -e 's,$1,,'`
+ remove_cxxflag=yes
+ else
+ remove_cxxflag=no
+ fi
+ AC_MSG_RESULT([$remove_cxxflag])
+])
+
+TEST_CFLAGS=""
+TEST_CXXFLAGS=""
+NO_STRICT_ALIASING_CFLAGS=""
+NO_FLOAT_EQUAL_CFLAGS=""
+NO_BAD_FUNCTION_CAST_CFLAGS=""
+if test "$GCC" = "yes"; then
+ CHECK_BUILD_FLAG([-Wall])
+ if test "x$check_cflag" = "xno"; then
+ CHECK_BUILD_FLAG([-W])
+ fi
+ CHECK_BUILD_FLAG([-Wno-unused-but-set-variable]) # FIXME: enable it.
+ CHECK_CFLAG([-Wno-pointer-sign])
+ CHECK_CFLAG([-Wno-declaration-after-statement])
+
+ CHECK_BUILD_FLAG([-Wformat])
+ CHECK_BUILD_FLAG([-Wstrict-aliasing=2])
+ if test "x$check_cflag" = "xyes"; then
+ NO_STRICT_ALIASING_CFLAGS="-fno-strict-aliasing"
+ fi
+ CHECK_BUILD_FLAG([-Wdisabled-optimization])
+ CHECK_BUILD_FLAG([-Wfloat-equal])
+ if test "x$check_cflag" = "xyes"; then
+ NO_FLOAT_EQUAL_CFLAGS="-Wno-float-equal"
+ fi
+ CHECK_BUILD_FLAG([-Wpointer-arith])
+ CHECK_CFLAG([-Wbad-function-cast])
+ if test "x$check_cflag" = "xyes"; then
+ NO_BAD_FUNCTION_CAST_CFLAGS="-Wno-bad-function-cast"
+ fi
+ if test "$CLANG" = "no"; then
+ CHECK_BUILD_FLAG([-Wcast-align])
+ fi
+# CHECK_BUILD_FLAG([-Wredundant-decls])
+# CHECK_BUILD_FLAG([-Wunsafe-loop-optimizations])
+# CHECK_BUILD_FLAG([-Wunreachable-code])
+# CHECK_BUILD_FLAG([-Wswitch-enum])
+# CHECK_BUILD_FLAG([-Wshadow])
+# CHECK_BUILD_FLAG([-Wconversion])
+ CHECK_BUILD_FLAG([-Wwrite-strings])
+# CHECK_BUILD_FLAG([-Winline])
+
+ CHECK_CXXFLAG([-fexceptions])
+ CHECK_CXXFLAG([-fimplicit-templates])
+fi
+AC_SUBST(TEST_CFLAGS)
+AC_SUBST(TEST_CXXFLAGS)
+AC_SUBST(NO_STRICT_ALIASING_CFLAGS)
+AC_SUBST(NO_FLOAT_EQUAL_CFLAGS)
+AC_SUBST(NO_BAD_FUNCTION_CAST_CFLAGS)
+
+LT_INIT([dlopen win32-dll])
+LT_LANG([Windows Resource])
+LT_OUTPUT
+
+LT_CURRENT=0
+LT_REVISION=0
+LT_AGE=0
+LT_VERSION_INFO="\$(LT_CURRENT):\$(LT_REVISION):\$(LT_AGE)"
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+AC_SUBST(LT_VERSION_INFO)
+
+GRN_DLL_FILENAME="libgroonga-\$(LT_CURRENT).dll"
+AC_SUBST(GRN_DLL_FILENAME)
+
+if test "$srcdir/version.sh"; then
+ . "$srcdir/version.sh"
+ AC_SUBST(GRN_VERSION)
+ AC_DEFINE_UNQUOTED(GRN_VERSION, ["$GRN_VERSION"], [groonga version])
+fi
+
+AC_CONFIG_FILES([
+ Makefile
+ build/Makefile
+ build/cmake_modules/Makefile
+ src/Makefile
+ src/suggest/Makefile
+ src/httpd/Makefile
+ lib/Makefile
+ lib/dat/Makefile
+ lib/mrb/Makefile
+ lib/mrb/scripts/Makefile
+ lib/mrb/scripts/command_line/Makefile
+ lib/mrb/scripts/context/Makefile
+ lib/mrb/scripts/expression_tree/Makefile
+ lib/mrb/scripts/initialize/Makefile
+ lib/mrb/scripts/logger/Makefile
+ lib/mrb/scripts/query_logger/Makefile
+ lib/proc/Makefile
+ lib/ts/Makefile
+ include/Makefile
+ include/groonga/Makefile
+ plugins/Makefile
+ plugins/tokenizers/Makefile
+ plugins/suggest/Makefile
+ plugins/query_expanders/Makefile
+ plugins/ruby/Makefile
+ plugins/token_filters/Makefile
+ plugins/sharding/Makefile
+ plugins/functions/Makefile
+ plugins/expression_rewriters/Makefile
+ examples/Makefile
+ examples/dictionary/Makefile
+ examples/dictionary/edict/Makefile
+ examples/dictionary/eijiro/Makefile
+ examples/dictionary/gene95/Makefile
+ examples/dictionary/jmdict/Makefile
+ packages/Makefile
+ packages/apt/Makefile
+ packages/ubuntu/Makefile
+ packages/rpm/Makefile
+ packages/rpm/centos/Makefile
+ packages/yum/Makefile
+ packages/source/Makefile
+ packages/windows/Makefile
+ packages/windows/patches/Makefile
+ packages/windows/language-files/Makefile
+ packages/windows/setup-x64.nsi
+ data/Makefile
+ data/html/Makefile
+ data/munin/Makefile
+ data/init.d/Makefile
+ data/init.d/centos/Makefile
+ data/init.d/centos/sysconfig/Makefile
+ data/logrotate.d/Makefile
+ data/logrotate.d/centos/Makefile
+ data/systemd/Makefile
+ data/systemd/centos/Makefile
+ data/systemd/centos/sysconfig/Makefile
+ data/scripts/Makefile
+ data/tmpfiles.d/Makefile
+ tools/Makefile
+ doc/Makefile
+ doc/locale/Makefile
+ doc/locale/en/Makefile
+ doc/locale/en/LC_MESSAGES/Makefile
+ doc/locale/ja/Makefile
+ doc/locale/ja/LC_MESSAGES/Makefile
+ test/Makefile
+ test/unit/Makefile
+ test/unit/lib/Makefile
+ test/unit/fixtures/Makefile
+ test/unit/fixtures/inverted-index/Makefile
+ test/unit/fixtures/stress/Makefile
+ test/unit/fixtures/plugins/Makefile
+ test/unit/fixtures/geo/Makefile
+ test/unit/fixtures/story/Makefile
+ test/unit/fixtures/story/taiyaki/Makefile
+ test/unit/util/Makefile
+ test/unit/core/Makefile
+ test/unit/core/dat/Makefile
+ test/unit/story/Makefile
+ test/command/Makefile
+ benchmark/Makefile
+ benchmark/fixtures/Makefile
+ benchmark/fixtures/geo-select/Makefile
+ benchmark/lib/Makefile
+ vendor/Makefile
+ vendor/lz4/Makefile
+ vendor/onigmo/Makefile
+ vendor/mecab/Makefile
+ vendor/message_pack/Makefile
+ vendor/mruby/Makefile
+])
+
+if test "$GCC" = "yes"; then
+ AC_DEFINE(_GNU_SOURCE, [1], [Define to 1 if you use GCC.])
+fi
+
+if test "$netbsd" = "yes"; then
+ AC_DEFINE(_NETBSD_SOURCE, [1], [Define to 1 if you are on NetBSD.])
+fi
+
+if test "$solaris" = "yes"; then
+ AC_DEFINE(_XPG4_2, [1],
+ [Define to 1 for msghdr.msg_control if you are on Solaris.])
+ AC_DEFINE(__EXTENSIONS__, [1],
+ [Define to 1 for singal.h with _XPG4_2 if you are on Solaris.])
+fi
+
+# For debug
+AC_ARG_ENABLE(debug,
+ [AS_HELP_STRING([--enable-debug],
+ [use debug flags (default=no)])],
+ [grn_debug="$enableval"],
+ [grn_debug="no"])
+if test "x$grn_debug" != "xno"; then
+ grn_debug="yes"
+ if test "$CLANG" = "yes"; then
+ CFLAGS="$CFLAGS -O0 -g"
+ CXXFLAGS="$CXXFLAGS -O0 -g"
+ elif test "$GCC" = "yes"; then
+ CFLAGS="$CFLAGS -O0 -g3"
+ CXXFLAGS="$CXXFLAGS -O0 -g3"
+ fi
+fi
+AC_SUBST(grn_debug)
+
+AC_SEARCH_LIBS(log, m, [], [AC_MSG_ERROR("No libm found")])
+AC_MSG_CHECKING([for fpclassify])
+AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#include <math.h>],
+ [if (fpclassify(0.0)) {return 0;}]
+ )],
+ [
+ AC_DEFINE(HAVE_FPCLASSIFY, [1], [use fpclassify])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [#define _ISOC99_SOURCE
+ #include <math.h>],
+ [if (fpclassify(0.0)) {return 0;}]
+ )],
+ [
+ AC_DEFINE(_ISOC99_SOURCE, [1], [Define to 1 for fpclassify])
+ AC_DEFINE(HAVE_FPCLASSIFY, [1], [use fpclassify with _ISOC99_SOURCE])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+ ])
+
+m4_include(build/ac_macros/check_headers.m4)
+m4_include(build/ac_macros/check_functions.m4)
+
+AC_SEARCH_LIBS(backtrace, execinfo,
+ [AC_DEFINE(HAVE_BACKTRACE, [1],
+ [Define to 1 if you have the `backtrace' function.])])
+AC_SEARCH_LIBS(clock_gettime, rt,
+ [AC_DEFINE(HAVE_CLOCK_GETTIME, [1], [use clock_gettime])])
+AC_SYS_LARGEFILE
+AC_TYPE_OFF_T
+AC_TYPE_SIZE_T
+AC_CHECK_SIZEOF(off_t)
+
+# MAP_HUGETLB
+AC_ARG_ENABLE(map-hugetlb,
+ [AS_HELP_STRING([--enable-map-hugetlb],
+ [use MAP_HUGETLB. [default=no]])],
+ ,
+ [enable_map_hugetlb="no"])
+if test "x$enable_map_hugetlb" != "xno"; then
+ AC_MSG_CHECKING([for MAP_HUGETLB])
+ AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif /* HAVE_SYS_MMAN_H */
+ ],
+ [MAP_HUGETLB;]
+ )],
+ [
+ AC_DEFINE(USE_MAP_HUGETLB, [1], [use MAP_HUGETLB])
+ AC_MSG_RESULT(yes)
+ ],
+ [
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR("MAP_HUGETLB isn't available.")
+ ]
+ )
+fi
+
+# log path
+AC_ARG_WITH(log_path,
+ [AS_HELP_STRING([--with-log-path=PATH],
+ [specify groonga log path.])],
+ grn_log_path="$withval",
+ grn_log_path="\$(localstatedir)/log/\$(PACKAGE_NAME)/\$(PACKAGE_NAME).log")
+AC_SUBST(grn_log_path)
+
+# default encoding
+AC_ARG_WITH(default_encoding,
+ [AS_HELP_STRING([--with-default-encoding=ENCODING],
+ [specify groonga default encoding(euc_jp/sjis/utf8/latin1/koi8r/none)])],
+ GRN_DEFAULT_ENCODING="$withval",
+ GRN_DEFAULT_ENCODING="utf8")
+AC_DEFINE_UNQUOTED(GRN_DEFAULT_ENCODING, "$GRN_DEFAULT_ENCODING", "specified default encoding")
+
+# default match escalation threshold
+AC_ARG_WITH(match_escalation_threshold,
+ [AS_HELP_STRING([--with-match-escalation-threshold=NUMBER],
+ [specify groonga default match escalation threshold])],
+ GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD="$withval",
+ GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD="0")
+AC_DEFINE_UNQUOTED(GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD, $GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD, "specified match escalation threshold")
+
+# default DB key management algorithm
+AC_ARG_WITH(default_db_key,
+ [AS_HELP_STRING([--with-default-db-key=ALGORITHM],
+ [specify groonga default DB key (pat/dat/auto)])],
+ GRN_DEFAULT_DB_KEY="$withval",
+ GRN_DEFAULT_DB_KEY="auto")
+AC_DEFINE_UNQUOTED(GRN_DEFAULT_DB_KEY, "$GRN_DEFAULT_DB_KEY",
+ "specified default DB key management algorithm")
+
+# DANGER!!!: stack size
+GRN_STACK_SIZE=1024
+AC_ARG_WITH(stack_size,
+ [AS_HELP_STRING([--with-stack-size=SIZE],
+ [DANGER!!!
+ This option specifies stack size. (default=$GRN_STACK_SIZE)
+ Normally, you should not use this option.])],
+ GRN_STACK_SIZE="$withval")
+AC_DEFINE_UNQUOTED(GRN_STACK_SIZE, [$GRN_STACK_SIZE], [stack size])
+
+# lock timeout
+GRN_LOCK_TIMEOUT=900000
+AC_ARG_WITH(lock_timeout,
+ [AS_HELP_STRING([--with-lock-timeout=N],
+ [This option specifies how many times Groonga tries to acquire a lock.
+ Each try waits --with-lock-wait-time nanoseconds to acquire a lock.
+ It means that Groonga gives up after
+ (--with-lock-wait-time * --with-lock-timeout) nanoseconds.
+ (default=$GRN_LOCK_TIMEOUT)])],
+ GRN_LOCK_TIMEOUT="$withval")
+AC_DEFINE_UNQUOTED(GRN_LOCK_TIMEOUT,
+ [$GRN_LOCK_TIMEOUT],
+ [lock timeout])
+
+# lock wait time
+GRN_LOCK_WAIT_TIME_NANOSECOND=1000000
+AC_ARG_WITH(lock_wait_time,
+ [AS_HELP_STRING([--with-lock-wait-time=NANOSECONDS],
+ [This option specifies wait time in nanosecond to acquire a lock.
+ (default=$GRN_LOCK_WAIT_TIME_NANOSECOND)])],
+ GRN_LOCK_WAIT_TIME_NANOSECOND="$withval")
+AC_DEFINE_UNQUOTED(GRN_LOCK_WAIT_TIME_NANOSECOND,
+ [$GRN_LOCK_WAIT_TIME_NANOSECOND],
+ [lock wait time in nanosecond])
+
+if test "$os_win32" != "yes"; then
+ AC_CHECK_HEADERS(pthread.h)
+ AC_SEARCH_LIBS(pthread_create, pthread,
+ [],
+ [AC_MSG_ERROR("No libpthread found")])
+ AC_CHECK_FUNCS(pthread_mutexattr_setpshared)
+ AC_CHECK_FUNCS(pthread_condattr_setpshared)
+fi
+AC_SEARCH_LIBS(gethostbyname, nsl)
+AC_SEARCH_LIBS(socket, socket)
+AC_SEARCH_LIBS(dlopen, dl)
+
+# nfkc
+AC_ARG_ENABLE(nfkc,
+ [AS_HELP_STRING([--enable-nfkc],
+ [use nfkc based utf8 normalization. [default=yes]])],,
+ [enable_nfkc="yes"])
+if test "x$enable_nfkc" = "xyes"; then
+ AC_DEFINE(GRN_WITH_NFKC, [1], [compile with nfkc.c])
+fi
+
+# coverage
+m4_ifdef([AC_CHECK_COVERAGE], [AC_CHECK_COVERAGE])
+GENHTML_OPTIONS="--title 'groonga Code Coverage'"
+
+# microyield
+AC_MSG_CHECKING([whether enable uyield])
+AC_ARG_ENABLE(uyield,
+ [AS_HELP_STRING([--enable-uyield],
+ [build for detecting race conditions. [default=no]])],
+ ,
+ [enable_uyield="no"])
+AC_MSG_RESULT($enable_uyield)
+
+## malloc
+force_enable_dynamic_malloc_change="no"
+
+# exact-alloc-count
+AC_MSG_CHECKING([whether enable exact-alloc-count])
+AC_ARG_ENABLE(exact-alloc-count,
+ [AS_HELP_STRING([--enable-exact-alloc-count],
+ [atomic counting for memory alloc count. [default=yes]])],,
+ [enable_exact_alloc_count="yes"])
+if test "x$enable_exact_alloc_count" != "xno"; then
+ AC_DEFINE(USE_EXACT_ALLOC_COUNT, [1], [alloc_count with atomic])
+fi
+AC_MSG_RESULT($enable_exact_alloc_count)
+
+# failmalloc
+AC_MSG_CHECKING([whether enable fmalloc])
+AC_ARG_ENABLE(fmalloc,
+ [AS_HELP_STRING([--enable-fmalloc],
+ [make memory allocation failed in specified condition for debug. [default=no]])],
+ ,
+ [enable_fmalloc="no"])
+if test "x$enable_fmalloc" != "xno"; then
+ force_enable_dynamic_malloc_change="yes"
+ AC_DEFINE(USE_FAIL_MALLOC, [1], [use fmalloc])
+fi
+AC_MSG_RESULT($enable_fmalloc)
+
+# abort
+AC_MSG_CHECKING([whether enable abort])
+AC_ARG_ENABLE(abort,
+ [AS_HELP_STRING([--enable-abort],
+ [enable query abortion. [default=no]])],
+ ,
+ [enable_abort="no"])
+if test "x$enable_abort" != "xno"; then
+ force_enable_dynamic_malloc_change="yes"
+ AC_DEFINE(USE_QUERY_ABORT, [1], [use abort])
+fi
+AC_MSG_RESULT($enable_abort)
+
+# dynamic malloc change
+AC_MSG_CHECKING([whether allow dynamic memory allocation change])
+AC_ARG_ENABLE(dynamic-malloc-change,
+ [AS_HELP_STRING([--enable-dynamic-malloc-change],
+ [allow dynamic memory allocation change for testing. [default=no]])],
+ ,
+ [enable_dynamic_malloc_change="no"])
+if test "x$enable_dynamic_malloc_change" != "xyes" -a \
+ "x$force_enable_dynamic_malloc_change" = "xyes"; then
+ enable_dynamic_malloc_change="yes"
+ AC_MSG_RESULT([$enable_dynamic_malloc_change (force)])
+else
+ AC_MSG_RESULT([$enable_dynamic_malloc_change])
+fi
+
+if test "x$enable_dynamic_malloc_change" = "xyes"; then
+ AC_DEFINE(USE_DYNAMIC_MALLOC_CHANGE, [1],
+ [Define to 1 if you enable dynamic malloc change])
+fi
+
+# memory debug
+AC_MSG_CHECKING([whether debug memory management])
+AC_ARG_ENABLE(memory-debug,
+ [AS_HELP_STRING([--enable-memory-debug],
+ [debug memory management. [default=no]])],
+ ,
+ [enable_memory_debug="no"])
+AC_MSG_RESULT([$enable_memory_debug])
+
+if test "x$enable_memory_debug" = "xyes"; then
+ AC_DEFINE(USE_MEMORY_DEBUG, [1],
+ [Define to 1 if you enable debuging memory management])
+fi
+
+# epoll/kqueue/poll/select check
+AC_CHECK_HEADER(sys/epoll.h, [
+ AC_CHECK_FUNC(epoll_create, [
+ AC_TRY_RUN([
+#include <sys/epoll.h>
+int main(int argc, char **argv) { return (epoll_create(16) < 0); }
+ ],
+ [
+ have_epoll="yes"
+ AC_DEFINE(USE_EPOLL, [1], [use epoll])
+ ]
+ )
+ ])
+])
+
+if test "x$have_epoll" != "xyes"; then
+ AC_CHECK_HEADER(sys/event.h, [
+ AC_CHECK_FUNC(kevent, [
+ have_kqueue="yes"
+ AC_DEFINE(USE_KQUEUE, [1], [use kqueue])
+ ])
+ ])
+ if test "x$have_kqueue" != "xyes"; then
+ AC_CHECK_HEADER(poll.h, [
+ AC_CHECK_FUNC(poll, [
+ have_poll="yes"
+ AC_DEFINE(USE_POLL, [1], [use poll])
+ ])
+ ])
+ if test "x$have_poll" != "xyes"; then
+ if test "$os_win32" = "yes"; then
+ AC_CHECK_HEADER(winsock2.h, [have_select="yes"])
+ else
+ AC_CHECK_FUNC(select, [
+ have_select="yes"
+ AC_CHECK_HEADERS(sys/select.h)
+ ])
+ fi
+ if test "x$have_select" = "xyes"; then
+ AC_DEFINE(USE_SELECT, [1], [use select])
+ else
+ AC_MSG_ERROR([epoll/kqueue/poll/select is missing.])
+ fi
+ fi
+ fi
+fi
+
+# check MSG_MORE defined
+AC_MSG_CHECKING([whether MSG_MORE defined])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int main(int argc, char **argv)
+{
+ return MSG_MORE;
+}
+ ])],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(USE_MSG_MORE, [1], [use MSG_MORE])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+
+# check MSG_NOSIGNAL defined
+AC_MSG_CHECKING([whether MSG_NOSIGNAL defined])
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int main(int argc, char **argv)
+{
+ return MSG_NOSIGNAL;
+}
+ ])],
+ [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(USE_MSG_NOSIGNAL, [1], [use MSG_NOSIGNAL])
+ ],
+ [
+ AC_MSG_RESULT(no)
+ ])
+
+# MinGW
+if test "$os_win32" = "yes"; then
+ WINDOWS_LDFLAGS="-mwindows"
+ WINDOWS_LIBS="-ladvapi32 -lws2_32"
+else
+ WINDOWS_LDFLAGS=
+ WINDOWS_LIBS=
+fi
+AC_SUBST(WINDOWS_LDFLAGS)
+AC_SUBST(WINDOWS_LIBS)
+
+# groonga binary path
+GROONGA="${ac_pwd}/src/groonga"
+AC_SUBST(GROONGA)
+
+# groonga-benchmark binary path
+GROONGA_BENCHMARK="${ac_pwd}/src/groonga-benchmark"
+AC_SUBST(GROONGA_BENCHMARK)
+
+# groonga-suggest-create-dataset binary path
+GROONGA_SUGGEST_CREATE_DATASET="${ac_pwd}/src/suggest/groonga-suggest-create-dataset"
+AC_SUBST(GROONGA_SUGGEST_CREATE_DATASET)
+
+# groonga-mruby binary path
+GROONGA_MRUBY="${ac_pwd}/src/groonga-mruby"
+AC_SUBST(GROONGA_MRUBY)
+
+# check Cutter with GLib support if available
+REQUIRED_MINIMUM_CUTTER_VERSION=1.1.6
+REQUIRED_MINIMUM_CPPCUTTER_VERSION=1.2.0
+m4_ifdef([AC_CHECK_GCUTTER],
+ [AC_CHECK_GCUTTER(>= $REQUIRED_MINIMUM_CUTTER_VERSION)],
+ [cutter_use_cutter="no"])
+m4_ifdef([AC_CHECK_CPPCUTTER],
+ [AC_CHECK_CPPCUTTER(>= $REQUIRED_MINIMUM_CPPCUTTER_VERSION)],
+ [cutter_use_cppcutter="no"])
+
+AM_CONDITIONAL([WITH_CUTTER], [test "$cutter_use_cutter" = "yes"])
+AM_CONDITIONAL([WITH_CPPCUTTER], [test "$cutter_use_cppcutter" = "yes"])
+if test "$cutter_use_cutter" = "yes"; then
+ AC_DEFINE(GRN_WITH_CUTTER, 1, [Define to 1 if you use Cutter])
+fi
+
+# check for benchmark
+AC_ARG_ENABLE(benchmark,
+ [AS_HELP_STRING([--disable-benchmark],
+ [don't build benchmark programs.])],,
+ [enable_benchmark="yes"])
+if test "x$enable_benchmark" = "xno"; then
+ benchmark_available="no"
+else
+ REQUIRED_GLIB_VERSION=2.14.0
+ m4_ifdef([AM_PATH_GLIB_2_0],
+ [AM_PATH_GLIB_2_0($REQUIRED_GLIB_VERSION,
+ [benchmark_available="yes"],
+ [benchmark_available="no"],
+ [gobject gthread])],
+ [benchmark_available="no"])
+ AC_MSG_CHECKING(for benchmark availablity)
+ AC_MSG_RESULT($ac_benchmark_available)
+fi
+if test "$benchmark_available" = "yes"; then
+ AC_DEFINE(GRN_WITH_BENCHMARK, 1, [Define to 1 if benchamrk is available])
+fi
+AM_CONDITIONAL([WITH_BENCHMARK], [test "$benchmark_available" = "yes"])
+
+# check Ruby for HTTP test
+ac_cv_ruby_available="no"
+AC_ARG_WITH([ruby],
+ AS_HELP_STRING([--with-ruby=PATH],
+ [Ruby interpreter path (default: no)]),
+ [RUBY="$withval"],
+ [RUBY="no"])
+
+if test "x$RUBY" = "xno"; then
+ RUBY=
+else
+ if test "x$RUBY" = "xyes"; then
+ AC_PATH_PROGS(RUBY,
+ [ dnl
+ ruby2.3 ruby23 dnl
+ ruby2.2 ruby22 dnl
+ ruby2.1 ruby21 dnl
+ ruby dnl
+ ],
+ ruby-not-found)
+ if test "$RUBY" != "ruby-not-found"; then
+ ruby_version="`$RUBY --version`"
+ if echo "$ruby_version" | grep -q -- 'ruby \(2\.\)'; then
+ ac_cv_ruby_available="yes"
+ else
+ AC_MSG_WARN([$RUBY isn't Ruby 2.0 or later ($ruby_version)])
+ fi
+ fi
+ else
+ ruby_not_found_warning_message="$RUBY is not found."
+ case "$RUBY" in
+ /*)
+ AC_CHECK_FILE([$RUBY],
+ [ac_cv_ruby_available="yes"],
+ [AC_MSG_WARN([$ruby_not_found_warning_message])
+ RUBY="$RUBY-not-found"])
+ ;;
+ *)
+ ruby_not_found="$RUBY-not-found"
+ AC_PATH_PROGS(RUBY, "$RUBY", "$ruby_not_found")
+ if test "$RUBY" = "$ruby_not_found"; then
+ AC_MSG_WARN([$ruby_not_found_warning_message])
+ else
+ ac_cv_ruby_available="yes"
+ fi
+ ;;
+ esac
+ fi
+fi
+AC_SUBST(RUBY)
+AM_CONDITIONAL([WITH_RUBY], [test "$ac_cv_ruby_available" = "yes"])
+
+AM_CONDITIONAL([WITH_UNIT_TEST],
+ [test "$cutter_use_cutter" = "yes" -o \
+ "$ac_cv_ruby_available" = "yes"])
+
+AM_CONDITIONAL([WITH_COMMAND_TEST],
+ [test "$ac_cv_ruby_available" = "yes"])
+
+# check Lemon for generating .c and .h files from .y file
+lemon_available="no"
+AC_ARG_WITH([lemon],
+ AS_HELP_STRING([--with-lemon=PATH],
+ [Lemon path (default: auto)]),
+ [LEMON="$withval"],
+ [: ${LEMON:=auto}])
+
+if test "$LEMON" = "no"; then
+ LEMON=
+else
+ if test "$LEMON" = "auto"; then
+ AC_PATH_PROGS(LEMON, [lemon], none)
+ if test "$LEMON" != "none"; then
+ lemon_available="yes"
+ fi
+ elif test "$LEMON" = "yes"; then
+ AC_PATH_PROGS(LEMON, [lemon], none)
+ if test "$LEMON" = "none"; then
+ AC_MSG_WARN([lemon is not found. Disable .y compilation.])
+ else
+ lemon_available="yes"
+ fi
+ else
+ AC_CHECK_FILE([$LEMON],
+ [lemon_available="yes"],
+ [AC_MSG_WARN([$LEMON is not found. Disable .y compilation.])])
+ fi
+fi
+AC_SUBST(LEMON)
+AM_CONDITIONAL([WITH_LEMON], [test "$lemon_available" = "yes"])
+
+# libedit
+AC_ARG_ENABLE(libedit,
+ [AS_HELP_STRING([--disable-libedit],
+ [use libedit for console. [default=auto-detect]])],
+ [enable_libedit="$enableval"],
+ [enable_libedit="auto"])
+if test "x$enable_libedit" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([LIBEDIT], [libedit >= 3.0],
+ [LIBS_SAVE="$LIBS"
+ LDFLAGS_SAVE="$LDFLAGS"
+ LDFLAGS="$LIBEDIT_LIBS $LDFLAGS"
+ AC_SEARCH_LIBS(el_wline, edit,
+ [libedit_available=yes],
+ [libedit_available=no])
+ LIBS="$LIBS_SAVE"
+ LDFLAGS="$LDFLAGS_SAVE"],
+ [libedit_available=no])
+ ],
+ [libedit_available=no])
+ if test "x$libedit_available" = "xyes"; then
+ AC_DEFINE(GRN_WITH_LIBEDIT, [1], [Use libedit with multibyte support.])
+ else
+ if test "x$enable_editline" = "xyes"; then
+ AC_MSG_ERROR("No libedit found")
+ fi
+ fi
+fi
+
+# zlib
+AC_ARG_WITH(zlib,
+ [AS_HELP_STRING([--with-zlib],
+ [Support data compression by zlib. [default=auto]])],
+ [with_zlib="$withval"],
+ [with_zlib="auto"])
+GRN_WITH_ZLIB=no
+if test "x$with_zlib" != "xno"; then
+ # TODO: Support custom zlib include and lib directory by --with-zlib.
+ AC_SEARCH_LIBS(compress, z,
+ [
+ GRN_WITH_ZLIB=yes
+ AC_DEFINE(GRN_WITH_ZLIB, [1],
+ [Support data compression by zlib.])
+ ],
+ [
+ if test "x$with_zlib" != "xauto"; then
+ AC_MSG_ERROR("No libz found")
+ fi
+ ])
+fi
+AC_SUBST(GRN_WITH_ZLIB)
+
+# LZ4
+AC_ARG_WITH(lz4,
+ [AS_HELP_STRING([--with-lz4],
+ [Support data compression by LZ4. [default=auto]])],
+ [with_lz4="$withval"],
+ [with_lz4="auto"])
+if test "x$with_lz4" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([LIBLZ4],
+ [liblz4],
+ [GRN_WITH_LZ4=yes],
+ [GRN_WITH_LZ4=no])
+ ],
+ [GRN_WITH_LZ4=no])
+ if test "$GRN_WITH_LZ4" = "yes"; then
+ AC_DEFINE(GRN_WITH_LZ4, [1],
+ [Support data compression by LZ4.])
+ else
+ if test "x$with_lz4" != "xauto"; then
+ AC_MSG_ERROR("No liblz4 found")
+ fi
+ fi
+fi
+
+# Zstandard
+AC_ARG_WITH(zstd,
+ [AS_HELP_STRING([--with-zstd],
+ [Support data compression by Zstandard. [default=auto]])],
+ [with_zstd="$withval"],
+ [with_zstd="auto"])
+if test "x$with_zstd" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([LIBZSTD],
+ [libzstd],
+ [GRN_WITH_ZSTD=yes],
+ [GRN_WITH_ZSTD=no])
+ ],
+ [GRN_WITH_ZSTD=no])
+ if test "$GRN_WITH_ZSTD" = "yes"; then
+ AC_DEFINE(GRN_WITH_ZSTD, [1],
+ [Support data compression by Zstandard.])
+ else
+ if test "x$with_zstd" != "xauto"; then
+ AC_MSG_ERROR("No libzstd found")
+ fi
+ fi
+fi
+
+# jemalloc
+AC_ARG_WITH(jemalloc,
+ [AS_HELP_STRING([--with-jemalloc],
+ [Use jemalloc for memory allocation. [default=no]])],
+ [with_jemalloc="$withval"],
+ [with_jemalloc="no"])
+jemalloc_available="no"
+if test "x$with_jemalloc" != "xno"; then
+ if test "x$with_jemalloc" != "xyes"; then
+ LDFLAGS="-L$with_jemalloc $LDFLAGS"
+ fi
+ AC_SEARCH_LIBS(malloc_conf, jemalloc,
+ [jemalloc_available="yes"],
+ [AC_MSG_ERROR("No libjemalloc found")])
+fi
+
+# Apache Arrow
+AC_ARG_ENABLE(arrow,
+ [AS_HELP_STRING([--disable-arrow],
+ [enable Apache Arrow support. [default=auto-detect]])],
+ [enable_arrow="$enableval"],
+ [enable_arrow="auto"])
+if test "x$enable_arrow" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([ARROW],
+ [arrow >= 0.5.0],
+ [arrow_available=yes],
+ [arrow_available=no])
+ ],
+ [arrow_available=no])
+ if test "x$arrow_available" = "xyes"; then
+ AC_DEFINE(GRN_WITH_ARROW, [1], [Enable Apache Arrow support.])
+ else
+ if test "x$enable_arrow" = "xyes"; then
+ AC_MSG_ERROR("No Apache Arrow found")
+ fi
+ fi
+fi
+AM_CONDITIONAL([GRN_WITH_ARROW], [test "$arrow_available" = "yes"])
+
+# MeCab
+# NOTE: MUST be checked last
+
+BUNDLED_MECAB_VERSION=m4_include([bundled_mecab_version])
+AC_SUBST(BUNDLED_MECAB_VERSION)
+BUNDLED_MECAB_NAIST_JDIC_VERSION=m4_include([bundled_mecab_naist_jdic_version])
+AC_SUBST(BUNDLED_MECAB_NAIST_JDIC_VERSION)
+
+AC_ARG_WITH(mecab,
+ [AS_HELP_STRING([--with-mecab],
+ [use MeCab for morphological analysis. [default=yes]])],
+ [with_mecab="$withval"],
+ [with_mecab="yes"])
+AC_MSG_CHECKING([whether enable MeCab])
+AC_MSG_RESULT($with_mecab)
+if test "x$with_mecab" = "xyes"; then
+ # mecab-config
+ AC_ARG_WITH(mecab-config,
+ [AS_HELP_STRING([--with-mecab-config=PATH],
+ [set mecab-config location. [default=auto-detect]])],
+ [if test "$cross_compiling" = "yes"; then
+ MECAB_CONFIG="$withval"
+ else
+ AC_CHECK_FILE("$withval", MECAB_CONFIG="$withval", MECAB_CONFIG=no)
+ fi],
+ [AC_PATH_PROG(MECAB_CONFIG, mecab-config, no)])
+ if test "x$MECAB_CONFIG" = "xno"; then
+ with_mecab="no"
+ else
+ MECAB_CPPFLAGS="-I`$MECAB_CONFIG --inc-dir`"
+ MECAB_LDFLAGS="-L`$MECAB_CONFIG --libs-only-L`"
+ _SAVE_LIBS="$LIBS"
+ _SAVE_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $MECAB_LDFLAGS"
+ AC_SEARCH_LIBS(mecab_new,
+ mecab,
+ [MECAB_LIBS="-lmecab $PTHREAD_LIBS"],
+ [AC_MSG_ERROR("No libmecab found")],
+ $PTHREAD_LIBS)
+ LDFLAGS="$_SAVE_LDFLAGS"
+ LIBS="$_SAVE_LIBS"
+ _SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $MECAB_CPPFLAGS"
+ AC_CHECK_HEADER(mecab.h, , [AC_MSG_ERROR("No mecab.h found")])
+ AC_CHECK_TYPE([mecab_dictionary_info_t],
+ [AC_DEFINE([HAVE_MECAB_DICTIONARY_INFO_T],
+ [1],
+ [Define to 1 if MeCab has the type `mecab_dictionary_info_t'.])],
+ [],
+ [[#include <mecab.h>]])
+ CPPFLAGS="$_SAVE_CPPFLAGS"
+ AC_SUBST(MECAB_CPPFLAGS)
+ AC_SUBST(MECAB_LDFLAGS)
+ AC_SUBST(MECAB_LIBS)
+ fi
+fi
+if test "x$with_mecab" = "xyes"; then
+ AC_DEFINE(GRN_WITH_MECAB, [1], [use MeCab])
+fi
+AM_CONDITIONAL(WITH_MECAB, test "x$with_mecab" = "xyes")
+
+# KyTea
+REQUIRED_MINIMUM_KYTEA_VERSION=0.4.2
+AC_ARG_WITH(kytea,
+ [AS_HELP_STRING([--with-kytea],
+ [use KyTea for morphological analysis. [default=auto]])],
+ [with_kytea="$withval"],
+ [with_kytea="auto"])
+AC_MSG_CHECKING([whether enable KyTea])
+AC_MSG_RESULT($with_kytea)
+if test "x$with_kytea" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([KYTEA],
+ [kytea >= $REQUIRED_MINIMUM_KYTEA_VERSION],
+ [kytea_exists=yes],
+ [kytea_exists=no])
+ ],
+ [kytea_exists=no])
+ if test "$kytea_exists" = "no" -a "x$with_kytea" = "xyes"; then
+ AC_MSG_ERROR("No KyTea found.")
+ fi
+ with_kytea="$kytea_exists"
+fi
+if test "x$with_kytea" = "xyes"; then
+ AC_DEFINE(GRN_WITH_KYTEA, [1], [use KyTea])
+fi
+AM_CONDITIONAL(WITH_KYTEA, test "x$with_kytea" = "xyes")
+
+# libstemmer
+AC_ARG_WITH(libstemmer,
+ [AS_HELP_STRING([--with-libstemmer],
+ [use libstemmer for stemming. [default=auto]])],
+ [with_libstemmer="$withval"],
+ [with_libstemmer="auto"])
+AC_ARG_WITH(libstemmer-include,
+ [AS_HELP_STRING([--with-libstemmer-include],
+ [path to libstemmer.h. [default=auto]])])
+AC_ARG_WITH(libstemmer-lib,
+ [AS_HELP_STRING([--with-libstemmer-lib],
+ [path to libstemmer.so. [default=auto]])])
+AC_MSG_CHECKING([whether enable libstemmer])
+AC_MSG_RESULT($with_libstemmer)
+if test "x$with_libstemmer" != "xno"; then
+ LIBSTEMMER_CFLAGS=""
+ LIBSTEMMER_LDFLAGS=""
+ LIBSTEMMER_LIBS=""
+
+ CFLAGS_save="${CFLAGS}"
+ LDFLAGS_save="${LDFLAGS}"
+ if test "x$with_libstemmer" != "xauto"; then
+ if test -z "${with_libstemmer_include}"; then
+ with_libstemmer_include="${with_libstemmer}/include"
+ fi
+ LIBSTEMMER_CFLAGS="-I${with_libstemmer_include}"
+ if test -z "${with_libstemmer_lib}"; then
+ with_libstemmer_lib="${with_libstemmer}/lib"
+ fi
+ LIBSTEMMER_LDFLAGS="-L${with_libstemmer_lib}"
+ CFLAGS="${CFLAGS} ${LIBSTEMMER_CFLAGS}"
+ LDFLAGS="${LDFLAGS} ${LIBSTEMMER_LDFLAGS}"
+ fi
+ AC_CHECK_HEADERS(libstemmer.h,
+ [libstemmer_exists=yes],
+ [libstemmer_exists=no])
+ if test "$libstemmer_exists" = "yes"; then
+ AC_CHECK_LIB(stemmer, sb_stemmer_list,
+ [LIBSTEMMER_LIBS="-lstemmer"],
+ [libstemmer_exists=no])
+ fi
+ CFLAGS="${CFLAGS_save}"
+ LDFLAGS="${LDFLAGS_save}"
+
+ if test "$libstemmer_exists" = "no" -a "x$with_libstemmer" != "xauto"; then
+ AC_MSG_ERROR("No libstemmer found at ${with_libstemmer_include} and ${with_libstemmer_lib}.")
+ fi
+ with_libstemmer="$libstemmer_exists"
+fi
+if test "x$with_libstemmer" = "xyes"; then
+ AC_SUBST(LIBSTEMMER_CFLAGS)
+ AC_SUBST(LIBSTEMMER_LDFLAGS)
+ AC_SUBST(LIBSTEMMER_LIBS)
+ AC_DEFINE(GRN_WITH_LIBSTEMMER, [1], [use libstemmer])
+fi
+AM_CONDITIONAL(WITH_LIBSTEMMER, test "x$with_libstemmer" = "xyes")
+
+# futex check
+AC_ARG_ENABLE(futex,
+ [AS_HELP_STRING([--enable-futex],
+ [use futex. [default=no]])],
+ ,
+ [enable_futex="no"])
+if test "x$enable_futex" != "xno"; then
+ AC_CHECK_HEADERS(linux/futex.h sys/syscall.h, [
+ AC_DEFINE(USE_FUTEX, [1], [use futex])
+ ], [
+ AC_MSG_ERROR("linux/futex.h or sys/syscall.h not found")
+ ])
+fi
+AC_MSG_CHECKING([whether enable futex])
+AC_MSG_RESULT($enable_futex)
+
+# ZeroMQ
+AC_ARG_ENABLE(zeromq,
+ [AS_HELP_STRING([--disable-zeromq],
+ [Disable ZeroMQ used for suggestion. [default=auto-detect]])],
+ [enable_zeromq="$enableval"],
+ [enable_zeromq="auto"])
+if test "x$enable_zeromq" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([LIBZMQ],
+ [libzmq],
+ [zeromq_available=yes],
+ [zeromq_available=no])
+ ],
+ [zeromq_available=no])
+ if test "x$zeromq_available" = "xyes"; then
+ AC_DEFINE(GRN_WITH_ZEROMQ, [1], [Define to 1 if ZeroMQ is available.])
+ else
+ if test "x$enable_zeromq" = "xyes"; then
+ AC_MSG_ERROR("No ZeroMQ found")
+ fi
+ fi
+fi
+
+# libevent
+AC_ARG_WITH(libevent,
+ [AS_HELP_STRING([--without-libevent],
+ [Disable libevent used for suggestion. [default=auto]])],
+ [with_libevent="$withval"],
+ [with_libevent="auto"])
+
+# workaround for bundled groonga in MariaDB.
+if test "x$with_libevent" = "xbundled"; then
+ with_libevent=no
+fi
+
+if test "x$with_libevent" != "xno"; then
+ if test "x$with_libevent" = "xyes" -o "x$with_libevent" = "xauto"; then
+ libevent_cflags=""
+ libevent_ldflags="-levent"
+ else
+ libevent_include_dir="$with_libevent/include"
+ libevent_lib_dir="$with_libevent/lib"
+ if ! test -d "$libevent_include_dir" -a -d "$libevent_lib_dir"; then
+ AC_MSG_ERROR("No libevent found in $with_libevent.")
+ fi
+ libevent_cflags="-I$libevent_include_dir"
+ libevent_ldflags="-L$libevent_lib_dir -levent"
+ fi
+
+ _SAVE_CFLAGS="$CFLAGS"
+ _SAVE_LDFLAGS="$LDFLAGS"
+ _SAVE_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $libevent_cflags"
+ LDFLAGS="$LDFLAGS $libevent_ldflags"
+ AC_SEARCH_LIBS(event_init, event,
+ [libevent_available=yes],
+ [libevent_available=no])
+ CFLAGS="$_SAVE_CFLAGS"
+ LDFLAGS="$_SAVE_LDFLAGS"
+ LIBS="$_SAVE_LIBS"
+ if test "$libevent_available" = "yes"; then
+ AC_DEFINE(GRN_WITH_LIBEVENT, [1], [Define to 1 if libevent is available.])
+ LIBEVENT_CFLAGS="$libevent_cflags"
+ LIBEVENT_LIBS="$libevent_ldflags"
+ else
+ if test "$enable_option_checking" != "no" -a "x$with_libevent" = "xyes"; then
+ AC_MSG_ERROR("No libevent found")
+ fi
+ fi
+fi
+AC_SUBST(LIBEVENT_CFLAGS)
+AC_SUBST(LIBEVENT_LIBS)
+
+# MessagePack
+BUNDLED_MESSAGE_PACK_VERSION=m4_include([bundled_message_pack_version])
+AC_SUBST(BUNDLED_MESSAGE_PACK_VERSION)
+
+AC_ARG_ENABLE(message-pack,
+ [AS_HELP_STRING([--disable-message-pack],
+ [Disable MessagePack support. [default=auto-detect]])],
+ [enable_message_pack="$enableval"],
+ [enable_message_pack="auto"])
+if test "x$enable_message_pack" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([MESSAGE_PACK], [msgpack],
+ [message_pack_available=yes],
+ [message_pack_available=no])
+ ],
+ [message_pack_vailable=no])
+
+ if test "$message_pack_available" = "no"; then
+ AC_ARG_WITH(message-pack,
+ [AS_HELP_STRING([--with-message-pack],
+ [Specify prefix where MessagePack is installed. [default=/usr]])],
+ [with_message_pack="$withval"],
+ [with_message_pack="/usr"])
+ _SAVE_CFLAGS="$CFLAGS"
+ _SAVE_LDFLAGS="$LDFLAGS"
+ _SAVE_LIBS="$LIBS"
+ CFLAGS="$CFLAGS -I$with_message_pack/include"
+ LDFLAGS="$LDFLAGS -L$with_message_pack/lib"
+ AC_SEARCH_LIBS(msgpack_version, msgpack,
+ [message_pack_available=yes],
+ [message_pack_available=no])
+ CFLAGS="$_SAVE_CFLAGS"
+ LDFLAGS="$_SAVE_LDFLAGS"
+ LIBS="$_SAVE_LIBS"
+
+ if test "x$message_pack_available" = "xyes"; then
+ MESSAGE_PACK_CFLAGS="-I$with_message_pack/include"
+ MESSAGE_PACK_LIBS="-L$with_message_pack/lib -lmsgpackc"
+ fi
+ fi
+
+ if test "x$message_pack_available" = "xyes"; then
+ AC_DEFINE(GRN_WITH_MESSAGE_PACK, [1],
+ [Define to 1 if MessagePack is available.])
+ else
+ if test "x$enable_message_pack" = "xyes"; then
+ AC_MSG_ERROR("No MessagePack found")
+ fi
+ fi
+fi
+AC_SUBST(MESSAGE_PACK_CFLAGS)
+AC_SUBST(MESSAGE_PACK_LIBS)
+
+AM_CONDITIONAL([ENABLE_SUGGEST_LEARNER],
+ [test "$zeromq_available" = "yes" -a \
+ "$libevent_available" = "yes" -a \
+ "$message_pack_available" = "yes"])
+
+# Check built-in atomic
+case "$host" in
+ i*86*|x86_64*)
+ ;;
+ *)
+ AC_MSG_CHECKING([for platform which requires libatomic])
+ AC_CHECK_LIB(atomic, __atomic_store_8, [ATOMIC_LIBS="-latomic"])
+ AC_SUBST(ATOMIC_LIBS)
+ ;;
+esac
+
+# Document
+AC_MSG_CHECKING([whether enable document])
+AC_ARG_ENABLE(document,
+ [AS_HELP_STRING([--enable-document],
+ [enable document generation by Sphinx. [default=auto]])],
+ [enable_document="$enableval"],
+ [enable_document="auto"])
+AC_MSG_RESULT($enable_document)
+
+document_available=no
+document_buildable=no
+have_built_document=no
+if test x"$enable_document" != x"no"; then
+ if test -f "$srcdir/doc/build-stamp"; then
+ document_available=yes
+ have_built_document=yes
+ fi
+
+ if test x"$enable_document" = x"yes"; then
+ AC_PATH_PROG(SPHINX_BUILD, sphinx-build, [])
+ if test -n "$SPHINX_BUILD"; then
+ sphinx_build_version=`"$SPHINX_BUILD" --version`
+ if ! echo "$sphinx_build_version" | grep -q ' 1\.[[3-6]]'; then
+ AC_MSG_ERROR([
+sphinx-build is old: $sphinx_build_version
+Sphinx 1.3 or later is required.])
+ fi
+ document_available=yes
+ document_buildable=yes
+ else
+ AC_MSG_ERROR([
+No sphinx-build found.
+Install it and try again.
+
+How to install sphinx-build:
+
+For Debian GNU/Linux based system like Ubuntu:
+ % sudo apt-get install -y python-sphinx
+
+For Red Hat based system like CentOS:
+ % sudo yum install -y python-pip
+ % sudo pip install sphinx
+
+For OS X with Homebrew:
+ % brew install python
+ % brew install gettext
+ % export PATH="`brew --prefix gettext`/bin:\$PATH"
+ % pip install sphinx])
+ fi
+ AC_SUBST(SPHINX_BUILD)
+ fi
+fi
+
+# Check for misc.
+AC_ARG_WITH([cutter-source-path],
+ AS_HELP_STRING([--with-cutter-source-path=PATH],
+ [Specify Cutter source path for
+ groonga's release manager.]),
+ [CUTTER_SOURCE_PATH="$withval"])
+case "$CUTTER_SOURCE_PATH" in
+ ""|/*)
+ : # do nothing
+ ;;
+ *)
+ CUTTER_SOURCE_PATH="\$(top_builddir)/${CUTTER_SOURCE_PATH}"
+ ;;
+esac
+AC_SUBST(CUTTER_SOURCE_PATH)
+
+AM_CONDITIONAL([DOCUMENT_AVAILABLE],
+ [test "${document_available}" = "yes"])
+AC_MSG_CHECKING([whether document available])
+AC_MSG_RESULT($document_available)
+
+AM_CONDITIONAL([DOCUMENT_BUILDABLE],
+ [test "${document_buildable}" = "yes"])
+AC_MSG_CHECKING([whether document buildable])
+AC_MSG_RESULT($document_buildable)
+
+AM_CONDITIONAL([HAVE_BUILT_DOCUMENT],
+ [test "${have_built_document}" = "yes"])
+AC_MSG_CHECKING([whether having built document])
+AC_MSG_RESULT($have_built_document)
+
+DOCUMENT_VERSION=groonga_version
+DOCUMENT_VERSION_FULL="$GRN_VERSION"
+AC_SUBST(DOCUMENT_VERSION)
+AC_SUBST(DOCUMENT_VERSION_FULL)
+
+# Munin plugins
+AC_MSG_CHECKING([whether install munin plugins])
+AC_ARG_WITH(munin-plugins,
+ [AS_HELP_STRING([--with-munin-plugins],
+ [install Munin plugins. [default=no]])],
+ [install_munin_plugins="$withval"],
+ [install_munin_plugins="no"])
+AC_MSG_RESULT($install_munin_plugins)
+
+AM_CONDITIONAL([INSTALL_MUNIN_PLUGINS],
+ [test "${install_munin_plugins}" = "yes"])
+
+# platform
+AC_MSG_CHECKING([whether package platform])
+AC_ARG_WITH(package-platform,
+ [AS_HELP_STRING([--with-package-platform=PLATFORM],
+ [install package platform related files. [default=no]
+ (supported package platforms: centos, centos5, centos6, centos7, fedora)])],
+ [package_platform="$withval"],
+ [package_platform="no"])
+if test "$package_platform" = "centos"; then
+ distribution=$(cut -d " " -f 1 /etc/redhat-release | tr "A-Z" "a-z")
+ if grep -q Linux /etc/redhat-release; then
+ distribution_version=$(cut -d " " -f 4 /etc/redhat-release)
+ else
+ distribution_version=$(cut -d " " -f 3 /etc/redhat-release)
+ fi
+ distribution_version=$(echo ${distribution_version} | sed -e 's/\..*$//g')
+ package_platform="${package_platform}${distribution_version}"
+fi
+AC_MSG_RESULT($package_platform)
+
+AM_CONDITIONAL([CENTOS_PLATFORM],
+ [test "${package_platform}" != "no"])
+AM_CONDITIONAL([CENTOS_INIT_PLATFORM],
+ [test "${package_platform}" = "centos5" ||
+ test "${package_platform}" = "centos6"])
+AM_CONDITIONAL([CENTOS_SYSTEMD_PLATFORM],
+ [test "${package_platform}" = "centos7" ||
+ test "${package_platform}" = "fedora"])
+
+# plugins check
+relative_pluginsdir_base="\$(PACKAGE)/plugins"
+AC_SUBST(relative_pluginsdir_base)
+expanded_relative_pluginsdir_base="${PACKAGE}/plugins"
+AC_SUBST(expanded_relative_pluginsdir_base)
+
+relative_pluginsdir="lib/\$(relative_pluginsdir_base)"
+AC_SUBST(relative_pluginsdir)
+
+pluginsdir="\${libdir}/\$(relative_pluginsdir_base)"
+AC_SUBST(pluginsdir)
+expanded_pluginsdir="\${libdir}/${expanded_relative_pluginsdir_base}"
+AC_SUBST(expanded_pluginsdir)
+
+tokenizer_pluginsdir="\${pluginsdir}/tokenizers"
+AC_SUBST(tokenizer_pluginsdir)
+
+query_expander_pluginsdir="\${pluginsdir}/query_expanders"
+AC_SUBST(query_expander_pluginsdir)
+
+suggest_pluginsdir="\${pluginsdir}/suggest"
+AC_SUBST(suggest_pluginsdir)
+
+ruby_pluginsdir="\${pluginsdir}/ruby"
+AC_SUBST(ruby_pluginsdir)
+
+token_filter_pluginsdir="\${pluginsdir}/token_filters"
+AC_SUBST(token_filter_pluginsdir)
+
+sharding_pluginsdir="\${pluginsdir}/sharding"
+AC_SUBST(sharding_pluginsdir)
+
+function_pluginsdir="\${pluginsdir}/functions"
+AC_SUBST(function_pluginsdir)
+
+expression_rewriter_pluginsdir="\${pluginsdir}/expression_rewriters"
+AC_SUBST(expression_rewriter_pluginsdir)
+
+AC_MSG_CHECKING(for the suffix of plugin shared libraries)
+shrext_cmds=$(./libtool --config | grep '^shrext_cmds=')
+eval $shrext_cmds
+module=yes eval suffix="$shrext_cmds"
+AC_MSG_RESULT($suffix)
+if test -z "$suffix"; then
+ AC_MSG_ERROR([can't detect plugin suffix])
+fi
+AC_DEFINE_UNQUOTED(GRN_PLUGIN_SUFFIX, ["$suffix"], "plugin suffix")
+
+# for query expanders
+GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE_BASE="synonyms.tsv"
+GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE="etc/${PACKAGE}/${GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE_BASE}"
+AC_DEFINE_UNQUOTED(GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE,
+ ["$GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE"],
+ "The relative synonyms file for TSV query expander")
+GRN_QUERY_EXPANDER_TSV_SYNONYMS_PATH="`
+ eval echo ${sysconfdir}/${PACKAGE}/${GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE_BASE}
+`"
+AC_DEFINE_UNQUOTED(GRN_QUERY_EXPANDER_TSV_SYNONYMS_FILE,
+ ["$GRN_QUERY_EXPANDER_TSV_SYNONYMS_PATH"],
+ "The default synonyms file for TSV query expander")
+
+# for examples
+examplesdir="\$(pkgdatadir)/examples"
+AC_SUBST(examplesdir)
+
+examples_dictionarydir="\$(examplesdir)/dictionary"
+AC_SUBST(examples_dictionarydir)
+
+# for ruby scripts
+relative_ruby_scriptsdir_base="\$(PACKAGE)/scripts/ruby"
+AC_SUBST(relative_ruby_scriptsdir_base)
+relative_ruby_scriptsdir="lib/\$(relative_ruby_scriptsdir_base)"
+AC_SUBST(relative_ruby_scriptsdir)
+ruby_scriptsdir="\${libdir}/\$(relative_ruby_scriptsdir_base)"
+AC_SUBST(ruby_scriptsdir)
+
+# for document root
+GRN_DEFAULT_DOCUMENT_ROOT_BASE="html/admin"
+GRN_DEFAULT_DOCUMENT_ROOT="\${pkgdatadir}/\${GRN_DEFAULT_DOCUMENT_ROOT_BASE}"
+GRN_EXPANDED_DEFAULT_DOCUMENT_ROOT="\${datadir}/${PACKAGE}/${GRN_DEFAULT_DOCUMENT_ROOT_BASE}"
+GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT="share/\$(PACKAGE)/\$(GRN_DEFAULT_DOCUMENT_ROOT_BASE)"
+AC_SUBST(GRN_DEFAULT_DOCUMENT_ROOT_BASE)
+AC_SUBST(GRN_DEFAULT_DOCUMENT_ROOT)
+AC_SUBST(GRN_EXPANDED_DEFAULT_DOCUMENT_ROOT)
+AC_SUBST(GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT)
+
+# flags for compile groonga
+GRN_CFLAGS=""
+AC_SUBST(GRN_CFLAGS)
+GRN_DEFS=""
+GRN_DEFS="$GRN_DEFS -DGRN_DLL_FILENAME=L\\\"\"\$(GRN_DLL_FILENAME)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_PLUGINS_DIR=\\\"\"\$(pluginsdir)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_RELATIVE_PLUGINS_DIR=\\\"\"\$(relative_pluginsdir)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_RUBY_SCRIPTS_DIR=\\\"\"\$(ruby_scriptsdir)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_RELATIVE_RUBY_SCRIPTS_DIR=\\\"\"\$(relative_ruby_scriptsdir)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_LOG_PATH=\\\"\"\$(grn_log_path)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_DEFAULT_DOCUMENT_ROOT=\\\"\"\$(GRN_DEFAULT_DOCUMENT_ROOT)\"\\\""
+GRN_DEFS="$GRN_DEFS -DGRN_DEFAULT_RELATIVE_DOCUMENT_ROOT=\\\"\"\$(GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT)\"\\\""
+AC_SUBST(GRN_DEFS)
+CFLAGS="$CFLAGS $OPT_CFLAGS "
+LIBS="$LIBS $WINDOWS_LIBS"
+AC_DEFINE_UNQUOTED(CONFIGURE_OPTIONS, "$ac_configure_args", "specified configure options")
+
+# For groonga.org
+AC_ARG_WITH(groonga-org-path,
+ [AS_HELP_STRING([--with-groonga-org-path=PATH],
+ [specify a path of the groonga.org repository to update groonga.org.])],
+ [GROONGA_ORG_PATH="$withval"],
+ [GROONGA_ORG_PATH=""])
+AC_SUBST(GROONGA_ORG_PATH)
+
+# groonga-httpd
+NGINX_VERSION=m4_include([nginx_version])
+AC_SUBST(NGINX_VERSION)
+
+# groonga-httpd binary path
+GROONGA_HTTPD="${ac_pwd}/vendor/nginx-${NGINX_VERSION}/objs/nginx"
+AC_SUBST(GROONGA_HTTPD)
+
+AC_ARG_ENABLE(groonga_httpd,
+ [AS_HELP_STRING([--enable-groonga-httpd],
+ [enable nginx used for groonga-httpd. [default=yes]])],
+ [enable_groonga_httpd="$enableval"],
+ [enable_groonga_httpd="yes"])
+if test "x$enable_groonga_httpd" != "xno"; then
+ enable_groonga_httpd="yes"
+ AC_CONFIG_SUBDIRS([src/httpd])
+else
+ enable_groonga_httpd="no"
+fi
+AM_CONDITIONAL(WITH_GROONGA_HTTPD, test "$enable_groonga_httpd" = "yes")
+
+GROONGA_HTTPD_PID_PATH="`
+ test \"$prefix\" = NONE && prefix=/usr/local
+ eval echo ${localstatedir}/run/groonga/groonga-httpd.pid
+`"
+AC_SUBST(GROONGA_HTTPD_PID_PATH)
+
+# mruby
+AC_ARG_ENABLE(mruby,
+ [AS_HELP_STRING([--enable-mruby],
+ [enable mruby. [default=no]])],
+ [enable_mruby="$enableval"],
+ [enable_mruby="no"])
+
+AC_MSG_CHECKING([whether enable mruby])
+if test "x$enable_mruby" != "xyes"; then
+ enable_mruby="no"
+fi
+AC_MSG_RESULT($enable_mruby)
+
+if test "$enable_mruby" = "yes"; then
+ if test ! -f "$srcdir/vendor/mruby/mruby_build.timestamp" -a \
+ "$ac_cv_ruby_available" != "yes"; then
+ AC_MSG_ERROR(--enable-mruby requires --with-ruby)
+ fi
+ AC_DEFINE(GRN_WITH_MRUBY, [1], [Define to 1 if mruby is enabled.])
+ MRUBY_CFLAGS="-I\$(top_srcdir)/vendor/mruby-source/include"
+ GRN_WITH_MRUBY="yes"
+else
+ MRUBY_CFLAGS=""
+fi
+AC_SUBST(GRN_WITH_MRUBY)
+AC_SUBST(MRUBY_CFLAGS)
+AM_CONDITIONAL(WITH_MRUBY, test "$enable_mruby" = "yes")
+
+MRUBY_CPPFLAGS="-DMRB_INT64"
+AC_SUBST(MRUBY_CPPFLAGS)
+
+# This option is used in vendor/onigmo/configure
+AC_ARG_ENABLE(shared-onigmo,
+ [AS_HELP_STRING([--enable-shared-onigmo],
+ [use Onigmo as shared library instead of static library. [default=no]])],
+ [enable_shared_onigmo="$enableval"],
+ [enable_shared_onigmo="no"])
+AM_CONDITIONAL(WITH_SHARED_ONIGMO, test "$enable_shared_onigmo" = "yes")
+
+AC_ARG_WITH(onigmo,
+ [AS_HELP_STRING([--without-onigmo],
+ [Don't Use Onigmo. [default=bundled]])],
+ [with_onigmo="$withval"],
+ [with_onigmo="bundled"])
+if test "x$with_onigmo" != "xno"; then
+ GRN_WITH_ONIGMO="yes"
+ if test "x$with_onigmo" != "xbundled"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([ONIGMO], [onigmo],
+ [have_onigmo=yes],
+ [have_onigmo=no])
+ ],
+ [have_onigmo=no])
+ fi
+ if test "x$with_onigmo" = "xsystem" -a "$have_onigmo" = "no"; then
+ AC_MSG_ERROR("No Onigmo found")
+ fi
+ if test "x$with_onigmo" = "xbundled" -o "$have_onigmo" = "no"; then
+ AC_CONFIG_SUBDIRS([vendor/onigmo])
+ ONIGMO_CFLAGS="-I\$(top_srcdir)/vendor/onigmo-source"
+ ONIGMO_LIBS="\$(top_builddir)/vendor/onigmo-source/libonigmo.la"
+ fi
+ AC_DEFINE(GRN_WITH_ONIGMO, [1], [Use Onigmo.])
+else
+ GRN_WITH_ONIGMO="no"
+fi
+AC_SUBST(GRN_WITH_ONIGMO)
+AC_SUBST(ONIGMO_CFLAGS)
+AC_SUBST(ONIGMO_LIBS)
+AM_CONDITIONAL(WITH_BUNDLED_ONIGMO, test "$with_onigmo" != "no" -a "x$have_onigmo" != "xyes")
+
+# SSL
+GRN_WITH_SSL=no
+AC_ARG_WITH(ssl,
+ [AS_HELP_STRING([--without-ssl],
+ [Don't use SSL module for groonga-httpd. [default=auto-detect]])],
+ [with_ssl="$withval"],
+ [with_ssl="auto"])
+if test "x$with_ssl" != "xno"; then
+ m4_ifdef([PKG_CHECK_MODULES], [
+ PKG_CHECK_MODULES([SSL], [libssl],
+ [_PKG_CONFIG(SSL_LIBS_ONLY_L, [libs-only-L], [libssl])
+ SSL_LIBS_ONLY_L="$pkg_cv_SSL_LIBS_ONLY_L"
+ GRN_WITH_SSL=yes],
+ [GRN_WITH_SSL=no])
+ ],
+ [GRN_WITH_SSL=no])
+ if test "x$with_ssl" = "xyes" -a "$GRN_WITH_SSL" != "yes"; then
+ AC_MSG_ERROR("No SSL found")
+ fi
+fi
+AC_SUBST(GRN_WITH_SSL)
+AC_SUBST(SSL_CFLAGS)
+AC_SUBST(SSL_LIBS_ONLY_L)
+
+# For package
+AC_ARG_WITH(rsync-path,
+ [AS_HELP_STRING([--with-rsync-path=PATH],
+ [specify rsync path to upload groonga packages.])],
+ [RSYNC_PATH="$withval"],
+ [RSYNC_PATH="packages@packages.groonga.org:public"])
+AC_SUBST(RSYNC_PATH)
+
+AC_ARG_WITH(launchpad-ppa,
+ [AS_HELP_STRING([--with-launchpad-ppa=PPA],
+ [specify Launchpad Personal Package Archive. [default=groonga-ppa]])],
+ [LAUNCHPAD_PPA="$withval"],
+ [LAUNCHPAD_PPA="groonga-ppa"])
+AC_SUBST(LAUNCHPAD_PPA)
+
+AC_ARG_WITH(launchpad-uploader-pgp-key,
+ [AS_HELP_STRING([--with-launchpad-uploader-pgp-key=KEY],
+ [specify PGP key UID to upload Groonga packages to Launchpad.])],
+ [LAUNCHPAD_UPLOADER_PGP_KEY="$withval"],
+ [LAUNCHPAD_UPLOADER_PGP_KEY=""])
+AC_SUBST(LAUNCHPAD_UPLOADER_PGP_KEY)
+
+GPG_UID=m4_include(gpg_uid)
+AC_SUBST(GPG_UID)
+
+pkgsysconfdir="\${sysconfdir}/$PACKAGE_NAME"
+AC_SUBST(pkgsysconfdir)
+
+GRN_CONFIG_PATH="`
+ test \"$prefix\" = NONE && prefix=/usr/local
+ eval echo ${sysconfdir}/groonga/groonga.conf
+`"
+AC_DEFINE_UNQUOTED(GRN_CONFIG_PATH, ["$GRN_CONFIG_PATH"],
+ [Default command line option configuration file.])
+
+GROONGA_HTTPD_DOCUMENT_ROOT="`
+ test \"$prefix\" = NONE && prefix=/usr/local
+ eval eval eval echo ${GRN_EXPANDED_DEFAULT_DOCUMENT_ROOT}
+`"
+AC_SUBST(GROONGA_HTTPD_DOCUMENT_ROOT)
+
+GROONGA_HTTPD_DEFAULT_DATABASE_PATH="`
+ test \"$prefix\" = NONE && prefix=/usr/local
+ eval eval eval echo ${localstatedir}/lib/${PACKAGE}/db/db
+`"
+AC_SUBST(GROONGA_HTTPD_DEFAULT_DATABASE_PATH)
+
+AC_OUTPUT([
+ lib/metadata.rc
+ packages/rpm/centos/groonga.spec
+ packages/apt/debian/groonga-keyring.postrm
+ packages/apt/env.sh
+ packages/yum/env.sh
+ groonga.pc
+ groonga-arrow.pc
+ config.sh
+ groonga-httpd-conf.sh
+ data/groonga-httpd.conf
+ data/logrotate.d/centos/groonga-httpd
+ data/scripts/groonga-httpd-restart
+ data/systemd/centos/groonga-httpd.service
+ ])
+
+echo "$PACKAGE_NAME $PACKAGE_VERSION configuration:"
+echo "-----------------------"
+echo " Compiler: ${CC}"
+echo " CFLAGS: ${CFLAGS}"
+echo " CXXFLAGS: ${CXXFLAGS}"
+echo " Libraries: ${LIBS}"
+echo " Stack size: ${GRN_STACK_SIZE}"
+echo " Document: ${document_available}"
+echo " buildable: ${document_buildable}"
+echo " built: ${have_built_document}"
+echo " Munin plugins: ${install_munin_plugins}"
+echo " Package platform: ${package_platform}"
+echo
+echo "Paths:"
+echo " Install path prefix: ${prefix}"
+echo " Configuration file: ${GRN_CONFIG_PATH}"
+echo
+
+echo "Tokenizers:"
+echo " MeCab: $with_mecab"
+if test "x$with_mecab" = "xyes"; then
+ echo " CPPFLAGS: $MECAB_CPPFLAGS"
+ echo " LDFLAGS: $MECAB_LDFLAGS"
+ echo " LIBS: $MECAB_LIBS"
+fi
+echo " KyTea: $with_kytea"
+if test "x$with_kytea" = "xyes"; then
+ echo " CFLAGS: $KYTEA_CFLAGS"
+ echo " LIBS: $KYTEA_LIBS"
+fi
+echo
+
+echo "Token filters:"
+echo " libstemmer: $with_libstemmer"
+if test "x$with_libstemmer" = "xyes"; then
+ echo " CFLAGS: $LIBSTEMMER_CFLAGS"
+ echo " LIBS: $LIBSTEMMER_LIBS"
+fi
+echo
+
+echo "Libraries:"
+echo " ZeroMQ: $zeromq_available"
+if test "x$zeromq_available" = "xyes"; then
+ echo " CFLAGS: ${LIBZMQ_CFLAGS}"
+ echo " LIBS: ${LIBZMQ_LIBS}"
+fi
+echo " libevent: $libevent_available"
+if test "x$libevent_available" = "xyes"; then
+ echo " CFLAGS: ${LIBEVENT_CFLAGS}"
+ echo " LIBS: ${LIBEVENT_LIBS}"
+fi
+echo " MessagePack: $message_pack_available"
+if test "x$message_pack_available" = "xyes"; then
+ echo " CFLAGS: ${MESSAGE_PACK_CFLAGS}"
+ echo " LIBS: ${MESSAGE_PACK_LIBS}"
+fi
+echo " mruby: $enable_mruby"
+echo " jemalloc: $jemalloc_available"
+echo
+
+echo "groonga-httpd:"
+echo " enable: $enable_groonga_httpd"
+if test "$enable_groonga_httpd" = "yes"; then
+ echo " default database path: $GROONGA_HTTPD_DEFAULT_DATABASE_PATH"
+ echo " SSL: $GRN_WITH_SSL"
+ if test "$GRN_WITH_SSL" = "yes"; then
+ echo " CFLAGS: $SSL_CFLAGS"
+ echo " LIBS only -L: $SSL_LIBS_ONLY_L"
+ fi
+fi
+echo
+
+echo "Tools:"
+echo " Sphinx: ${SPHINX_BUILD}"
+echo " lemon: ${LEMON}"
+echo " Ruby: ${RUBY}"
+echo " Cutter: ${CUTTER}"
+echo
+
+echo "For packages:"
+echo " rsync path: ${RSYNC_PATH}"
+echo " Launchpad PGP key: ${LAUNCHPAD_UPLOADER_PGP_KEY}"
+echo " GPG UID: ${GPG_UID}"
+echo
+
+echo "Now type 'make' to build $PACKAGE_NAME $PACKAGE_VERSION!"
diff --git a/storage/mroonga/vendor/groonga/examples/Makefile.am b/storage/mroonga/vendor/groonga/examples/Makefile.am
new file mode 100644
index 00000000..f436342d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = dictionary
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/Makefile.am b/storage/mroonga/vendor/groonga/examples/dictionary/Makefile.am
new file mode 100644
index 00000000..ee618a21
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/Makefile.am
@@ -0,0 +1,34 @@
+SUBDIRS = \
+ edict \
+ eijiro \
+ gene95 \
+ jmdict
+
+dist_examples_dictionary_SCRIPTS = \
+ init-db.sh
+
+nobase_dist_examples_dictionary_DATA = \
+ readme.txt \
+ $(html_files)
+
+# find html -type f | sort | sed -e 's,^,\t,g'
+html_files = \
+ html/css/dictionary.css \
+ html/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png \
+ html/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png \
+ html/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png \
+ html/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png \
+ html/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png \
+ html/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png \
+ html/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png \
+ html/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png \
+ html/css/smoothness/images/ui-icons_222222_256x240.png \
+ html/css/smoothness/images/ui-icons_2e83ff_256x240.png \
+ html/css/smoothness/images/ui-icons_454545_256x240.png \
+ html/css/smoothness/images/ui-icons_888888_256x240.png \
+ html/css/smoothness/images/ui-icons_cd0a0a_256x240.png \
+ html/css/smoothness/jquery-ui-1.8.12.custom.css \
+ html/index.html \
+ html/js/dictionary.js \
+ html/js/jquery-1.7.2.js \
+ html/js/jquery-ui-1.8.18.custom.js
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/edict/Makefile.am b/storage/mroonga/vendor/groonga/examples/dictionary/edict/Makefile.am
new file mode 100644
index 00000000..376f9d52
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/edict/Makefile.am
@@ -0,0 +1,4 @@
+edictdir = $(examples_dictionarydir)/edict
+dist_edict_SCRIPTS = \
+ edict2grn.rb \
+ edict-import.sh
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/edict/edict-import.sh b/storage/mroonga/vendor/groonga/examples/dictionary/edict/edict-import.sh
new file mode 100755
index 00000000..e48700af
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/edict/edict-import.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+base_dir=$(dirname $0)
+
+if [ 1 != $# -a 2 != $# ]; then
+ echo "usage: $0 db_path [edict.gz_path]"
+ exit 1
+fi
+
+if [ -z $2 ]; then
+ edict_gz=edict.gz
+ if [ ! -f $edict_gz ]; then
+ wget -O $edict_gz http://ftp.monash.edu.au/pub/nihongo/edict.gz
+ fi
+else
+ edict_gz=$2
+fi
+
+if type gzcat > /dev/null 2>&1; then
+ zcat="gzcat"
+else
+ zcat="zcat"
+fi
+
+if $zcat $edict_gz | ${base_dir}/edict2grn.rb | groonga $1 > /dev/null; then
+ echo "edict data loaded."
+fi
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/edict/edict2grn.rb b/storage/mroonga/vendor/groonga/examples/dictionary/edict/edict2grn.rb
new file mode 100755
index 00000000..b795e25a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/edict/edict2grn.rb
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby
+
+require "English"
+require "nkf"
+require "json"
+
+print(<<HEADER.chomp)
+column_create item_dictionary edict_desc COLUMN_SCALAR ShortText
+column_create bigram item_dictionary_edict_desc COLUMN_INDEX|WITH_POSITION item_dictionary edict_desc
+load --table item_dictionary
+[
+["_key","edict_desc","kana"]
+HEADER
+
+loop do
+ raw_line = gets
+ break if raw_line.nil?
+
+ line = raw_line.encode("UTF-8", "EUC-JP")
+ key, body = line.strip.split("/", 2)
+ key = key.strip
+ if /\s*\[(.+)\]\z/ =~ key
+ key = $PREMATCH
+ reading = $1
+ body = "[#{reading}] #{body}"
+ kana = NKF.nkf("-Ww --katakana", reading)
+ else
+ kana = NKF.nkf("-Ww --katakana", key)
+ end
+ puts(",")
+ puts([key, body, kana].to_json)
+end
+puts
+puts("]")
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/Makefile.am b/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/Makefile.am
new file mode 100644
index 00000000..4059a529
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/Makefile.am
@@ -0,0 +1,4 @@
+eijirodir = $(examples_dictionarydir)/eijiro
+dist_eijiro_SCRIPTS = \
+ eijiro2grn.rb \
+ eijiro-import.sh
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro-import.sh b/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro-import.sh
new file mode 100755
index 00000000..4042d7fb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro-import.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+base_dir=$(dirname $0)
+
+if [ 2 != $# ]; then
+ echo "usage: $0 db_path eijiro.csv_path"
+ exit 1
+fi
+
+if iconv -f UCS2 -t UTF8 $2 | ${base_dir}/eijiro2grn.rb | groonga $1 > /dev/null; then
+ echo "eijiro data loaded."
+fi
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro2grn.rb b/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro2grn.rb
new file mode 100755
index 00000000..62c1e130
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/eijiro/eijiro2grn.rb
@@ -0,0 +1,61 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+
+$KCODE = 'u'
+
+require 'rubygems'
+require 'fastercsv'
+
+class String
+ def to_json
+ a = split(//).map {|char|
+ case char
+ when '"' then '\\"'
+ when '\\' then '\\\\'
+ when "\b" then '\b'
+ when "\f" then '\f'
+ when "\n" then '\n'
+ when "\r" then ''
+ when "\t" then '\t'
+ else char
+ end
+ }
+ "\"#{a.join('')}\""
+ end
+end
+
+class Array
+ def to_json
+ '[' + map {|element|
+ element.to_json
+ }.join(',') + ']'
+ end
+end
+
+puts <<END
+column_create item_dictionary eijiro_trans COLUMN_SCALAR ShortText
+column_create item_dictionary eijiro_exp COLUMN_SCALAR ShortText
+column_create item_dictionary eijiro_level COLUMN_SCALAR Int32
+column_create item_dictionary eijiro_memory COLUMN_SCALAR Int32
+column_create item_dictionary eijiro_modify COLUMN_SCALAR Int32
+column_create item_dictionary eijiro_pron COLUMN_SCALAR ShortText
+column_create item_dictionary eijiro_filelink COLUMN_SCALAR ShortText
+column_create bigram item_dictionary_eijiro_trans COLUMN_INDEX|WITH_POSITION item_dictionary eijiro_trans
+load --table item_dictionary
+[["_key","norm","eijiro_trans","eijiro_exp","eijiro_level","eijiro_memory","eijiro_modify","eijiro_pron","eijiro_filelink","kana"],
+END
+
+n = 0
+FasterCSV.new(ARGF, :row_sep => "\r\n").each {|l|
+ if n > 0
+ keyword,word,trans,exp,level,memory,modify,pron,filelink = l
+ kana = ''
+ if trans =~ /【@】(.*?)(【|$)/
+ kana = $1.split("、")
+ end
+ puts [word,keyword,trans,exp,level,memory,modify,pron,filelink,kana].map{|e| e || ''}.to_json
+ end
+ n += 1
+}
+
+puts "]"
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/gene95/Makefile.am b/storage/mroonga/vendor/groonga/examples/dictionary/gene95/Makefile.am
new file mode 100644
index 00000000..e89f13f5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/gene95/Makefile.am
@@ -0,0 +1,4 @@
+gene95dir = $(examples_dictionarydir)/gene95
+dist_gene95_SCRIPTS = \
+ gene2grn.rb \
+ gene-import.sh
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/gene95/gene-import.sh b/storage/mroonga/vendor/groonga/examples/dictionary/gene95/gene-import.sh
new file mode 100755
index 00000000..488d6c83
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/gene95/gene-import.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+base_dir=$(dirname $0)
+
+if [ 1 != $# -a 2 != $# ]; then
+ echo "usage: $0 db_path [gene.txt_path]"
+ exit 1
+fi
+
+if [ -z $2 ]; then
+ dictionary_dir=gene95-dictionary
+ gene_txt=${dictionary_dir}/gene.txt
+ if [ ! -f $gene_txt ]; then
+ gene95_tar_gz=gene95.tar.gz
+ wget -O $gene95_tar_gz \
+ http://www.namazu.org/~tsuchiya/sdic/data/gene95.tar.gz
+ mkdir -p ${dictionary_dir}
+ tar xvzf ${gene95_tar_gz} -C ${dictionary_dir}
+ fi
+else
+ gene_txt=$2
+fi
+
+if cat $gene_txt | ${base_dir}/gene2grn.rb | groonga $1 > /dev/null; then
+ echo "gene95 data loaded."
+fi
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/gene95/gene2grn.rb b/storage/mroonga/vendor/groonga/examples/dictionary/gene95/gene2grn.rb
new file mode 100755
index 00000000..c9d9a593
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/gene95/gene2grn.rb
@@ -0,0 +1,33 @@
+#!/usr/bin/env ruby
+
+require "json"
+
+print(<<HEADER.chomp)
+column_create item_dictionary gene95_desc COLUMN_SCALAR ShortText
+column_create bigram item_dictionary_gene95_desc COLUMN_INDEX|WITH_POSITION item_dictionary gene95_desc
+load --table item_dictionary
+[
+["_key","gene95_desc"]
+HEADER
+
+loop do
+ raw_key = gets
+ break if raw_key.nil?
+ raw_body = gets
+
+ key = nil
+ body = nil
+ begin
+ key = raw_key.encode("UTF-8", "Windows-31J").strip
+ body = raw_body.encode("UTF-8", "Windows-31J").strip
+ rescue EncodingError
+ $stderr.puts("Ignore:")
+ $stderr.puts(" key: <#{raw_key}>")
+ $stderr.puts(" body: <#{raw_body}>")
+ next
+ end
+ puts(",")
+ print([key, body].to_json)
+end
+puts
+puts("]")
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/dictionary.css b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/dictionary.css
new file mode 100644
index 00000000..72b5a674
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/dictionary.css
@@ -0,0 +1,3 @@
+#result {
+ margin-top: 7em;
+}
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
new file mode 100644
index 00000000..5b5dab2a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
new file mode 100644
index 00000000..ac8b229a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
new file mode 100644
index 00000000..ad3d6346
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
new file mode 100644
index 00000000..42ccba26
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
new file mode 100644
index 00000000..5a46b47c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
new file mode 100644
index 00000000..86c2baa6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
new file mode 100644
index 00000000..4443fdc1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
new file mode 100644
index 00000000..7c9fa6c6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_222222_256x240.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_222222_256x240.png
new file mode 100644
index 00000000..b273ff11
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_222222_256x240.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_2e83ff_256x240.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_2e83ff_256x240.png
new file mode 100644
index 00000000..09d1cdc8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_2e83ff_256x240.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_454545_256x240.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_454545_256x240.png
new file mode 100644
index 00000000..59bd45b9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_454545_256x240.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_888888_256x240.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_888888_256x240.png
new file mode 100644
index 00000000..6d02426c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_888888_256x240.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_cd0a0a_256x240.png b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_cd0a0a_256x240.png
new file mode 100644
index 00000000..2ab019b7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/images/ui-icons_cd0a0a_256x240.png
Binary files differ
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/jquery-ui-1.8.12.custom.css b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/jquery-ui-1.8.12.custom.css
new file mode 100644
index 00000000..c85aabae
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/css/smoothness/jquery-ui-1.8.12.custom.css
@@ -0,0 +1,578 @@
+/*
+ * jQuery UI CSS Framework 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden { display: none; }
+.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
+.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
+.ui-helper-clearfix:after { content: "."; display: block; height: 0; clear: both; visibility: hidden; }
+.ui-helper-clearfix { display: inline-block; }
+/* required comment for clearfix to work in Opera \*/
+* html .ui-helper-clearfix { height:1%; }
+.ui-helper-clearfix { display:block; }
+/* end clearfix */
+.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled { cursor: default !important; }
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
+
+
+/*
+ * jQuery UI CSS Framework 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Theming/API
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=03_highlight_soft.png&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=01_flat.png&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=02_glass.png&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
+.ui-widget .ui-widget { font-size: 1em; }
+.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
+.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_flat_75_ffffff_40x100.png) 50% 50% repeat-x; color: #222222; }
+.ui-widget-content a { color: #222222; }
+.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url(images/ui-bg_highlight-soft_75_cccccc_1x100.png) 50% 50% repeat-x; color: #222222; font-weight: bold; }
+.ui-widget-header a { color: #222222; }
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3; background: #e6e6e6 url(images/ui-bg_glass_75_e6e6e6_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #555555; }
+.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555; text-decoration: none; }
+.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999; background: #dadada url(images/ui-bg_glass_75_dadada_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-hover a, .ui-state-hover a:hover { color: #212121; text-decoration: none; }
+.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #212121; }
+.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121; text-decoration: none; }
+.ui-widget :active { outline: none; }
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1; background: #fbf9ee url(images/ui-bg_glass_55_fbf9ee_1x400.png) 50% 50% repeat-x; color: #363636; }
+.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
+.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #fef1ec url(images/ui-bg_glass_95_fef1ec_1x400.png) 50% 50% repeat-x; color: #cd0a0a; }
+.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a; }
+.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a; }
+.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
+.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
+.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
+.ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png); }
+.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png); }
+.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png); }
+.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png); }
+
+/* positioning */
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-off { background-position: -96px -144px; }
+.ui-icon-radio-on { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
+.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
+.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
+.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
+.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
+
+/* Overlays */
+.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_0_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
+ * jQuery UI Resizable 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizable#theming
+ */
+.ui-resizable { position: relative;}
+.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;
+ /* http://bugs.jqueryui.com/ticket/7233
+ - Resizable: resizable handles fail to work in IE if transparent and content overlaps
+ */
+ background-image:url(data:);
+}
+.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
+.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
+.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
+.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
+.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
+.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
+.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
+.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
+.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
+ * jQuery UI Selectable 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectable#theming
+ */
+.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
+/*
+ * jQuery UI Accordion 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion#theming
+ */
+/* IE/Win - Fix animation bug - #4615 */
+.ui-accordion { width: 100%; }
+.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
+.ui-accordion .ui-accordion-li-fix { display: inline; }
+.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
+.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
+.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
+.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
+.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
+.ui-accordion .ui-accordion-content-active { display: block; }
+/*
+ * jQuery UI Autocomplete 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete#theming
+ */
+.ui-autocomplete { position: absolute; cursor: default; }
+
+/* workarounds */
+* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
+
+/*
+ * jQuery UI Menu 1.8.12
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu#theming
+ */
+.ui-menu {
+ list-style:none;
+ padding: 2px;
+ margin: 0;
+ display:block;
+ float: left;
+}
+.ui-menu .ui-menu {
+ margin-top: -3px;
+}
+.ui-menu .ui-menu-item {
+ margin:0;
+ padding: 0;
+ zoom: 1;
+ float: left;
+ clear: left;
+ width: 100%;
+}
+.ui-menu .ui-menu-item a {
+ text-decoration:none;
+ display:block;
+ padding:.2em .4em;
+ line-height:1.5;
+ zoom:1;
+}
+.ui-menu .ui-menu-item a.ui-state-hover,
+.ui-menu .ui-menu-item a.ui-state-active {
+ font-weight: normal;
+ margin: -1px;
+}
+/*
+ * jQuery UI Button 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button#theming
+ */
+.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
+.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
+button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
+.ui-button-icons-only { width: 3.4em; }
+button.ui-button-icons-only { width: 3.7em; }
+
+/*button text element */
+.ui-button .ui-button-text { display: block; line-height: 1.4; }
+.ui-button-text-only .ui-button-text { padding: .4em 1em; }
+.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
+.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
+.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
+.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
+/* no icon support for input elements, provide padding by default */
+input.ui-button { padding: .4em 1em; }
+
+/*button icon element(s) */
+.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
+.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
+.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
+.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
+
+/*button sets*/
+.ui-buttonset { margin-right: 7px; }
+.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
+
+/* workarounds */
+button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
+/*
+ * jQuery UI Dialog 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog#theming
+ */
+.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
+.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
+.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
+.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
+.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
+.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
+.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
+.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
+.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
+.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
+.ui-draggable .ui-dialog-titlebar { cursor: move; }
+/*
+ * jQuery UI Slider 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
+ * jQuery UI Tabs 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs#theming
+ */
+.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
+.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
+.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
+.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
+.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
+.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
+.ui-tabs .ui-tabs-hide { display: none !important; }
+/*
+ * jQuery UI Datepicker 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker#theming
+ */
+.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
+.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
+.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
+.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
+.ui-datepicker .ui-datepicker-prev { left:2px; }
+.ui-datepicker .ui-datepicker-next { right:2px; }
+.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
+.ui-datepicker .ui-datepicker-next-hover { right:1px; }
+.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
+.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
+.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
+.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year { width: 49%;}
+.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
+.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
+.ui-datepicker td { border: 0; padding: 1px; }
+.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
+.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
+.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi { width:auto; }
+.ui-datepicker-multi .ui-datepicker-group { float:left; }
+.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
+.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
+.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
+.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
+.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
+.ui-datepicker-row-break { clear:both; width:100%; }
+
+/* RTL support */
+.ui-datepicker-rtl { direction: rtl; }
+.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
+.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group { float:right; }
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
+
+/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
+.ui-datepicker-cover {
+ display: none; /*sorry for IE5*/
+ display/**/: block; /*sorry for IE5*/
+ position: absolute; /*must have*/
+ z-index: -1; /*must have*/
+ filter: mask(); /*must have*/
+ top: -4px; /*must have*/
+ left: -4px; /*must have*/
+ width: 200px; /*must have*/
+ height: 200px; /*must have*/
+}/*
+ * jQuery UI Progressbar 1.8.12
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar#theming
+ */
+.ui-progressbar { height:2em; text-align: left; }
+.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } \ No newline at end of file
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/index.html b/storage/mroonga/vendor/groonga/examples/dictionary/html/index.html
new file mode 100644
index 00000000..47e81754
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/index.html
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
+<head>
+<meta http-equiv="Content-Language" content="ja" />
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<title>groonga dictionary search</title>
+<meta http-equiv="content-style-type" content="text/css" />
+<meta http-equiv="content-script-type" content="text/javascript" />
+<link type="text/css" href="css/smoothness/jquery-ui-1.8.12.custom.css" rel="stylesheet" />
+<link type="text/css" rel="stylesheet" href="css/dictionary.css" />
+</head>
+<body>
+<form action="javascript:(function(){$('.search').blur()})()" name="search" id="search">
+<input type="text" size="60" maxlength="60" name="key" class="search" />
+<input type="submit" value="検索"/>
+</form>
+<script type="text/javascript" src="js/jquery-1.7.2.js"></script>
+<script type="text/javascript" src="js/jquery-ui-1.8.18.custom.js"></script>
+<script type="text/javascript" src="js/dictionary.js"></script>
+<script type="text/javascript">
+$(document).ready(function(){
+ $(".search").autocomplete({source: dictionarySource("http://" + location.host + "/d/suggest")});
+});
+</script>
+<div id="result"></div>
+</body>
+</html>
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/js/dictionary.js b/storage/mroonga/vendor/groonga/examples/dictionary/html/js/dictionary.js
new file mode 100644
index 00000000..850c64cc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/js/dictionary.js
@@ -0,0 +1,82 @@
+function dictionarySource(url) {
+ function displayItems(items) {
+ var results = $("<dl />");
+ $.each(items,
+ function(i, val) {
+ results.append($("<dt />")
+ .append($("<span />")
+ .text(val[0])
+ .click(function() {
+ $(".search").val($(this).text());
+ $("#search").submit();
+ })));
+ results.append($("<dd />")
+ .append($("<span />").text(val[1]))
+ .append($("<span />").text(val[2]))
+ );
+ });
+ $("#result")
+ .empty()
+ .append(results);
+ };
+
+ var request_index = 0;
+ var columns = "_key,gene95_desc,edict_desc";
+ var xhr;
+ function source(request, response) {
+ function onSuccess(data, status) {
+ if (this.autocomplete_request != request_index) {
+ return;
+ }
+ var completions = data[1]["complete"];
+ var items = [];
+ if (completions && completions.length > 2) {
+ completions.shift();
+ completions.shift();
+ $.each(completions,
+ function(i, item) {
+ var key = item[0];
+ items.push(key);
+ if (items.length >= 3) {
+ return false;
+ }
+ return true;
+ });
+ }
+ if (completions.length > 0) {
+ displayItems(completions);
+ }
+ response(items);
+ }
+
+ function onError() {
+ if (this.autocomplete_request != request_index) {
+ return;
+ }
+ response([]);
+ }
+
+ if (xhr) {
+ xhr.abort();
+ }
+ xhr = $.ajax(url,
+ {
+ data: {
+ query: request.term,
+ types: 'complete',
+ table: 'item_dictionary',
+ column: 'kana',
+ limit: 25,
+ output_columns: columns,
+ frequency_threshold: 1,
+ prefix_search: "yes"
+ },
+ dataType: "jsonp",
+ autocomplete_request: ++request_index,
+ success: onSuccess,
+ error: onError
+ });
+ };
+
+ return source;
+}
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-1.7.2.js b/storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-1.7.2.js
new file mode 100644
index 00000000..75ce2617
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-1.7.2.js
@@ -0,0 +1,9404 @@
+/*!
+ * jQuery JavaScript Library v1.7.2
+ * http://jquery.com/
+ *
+ * Copyright 2011, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * Includes Sizzle.js
+ * http://sizzlejs.com/
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ *
+ * Date: Wed Mar 21 12:46:34 2012 -0700
+ */
+(function( window, undefined ) {
+
+// Use the correct document accordingly with window argument (sandbox)
+var document = window.document,
+ navigator = window.navigator,
+ location = window.location;
+var jQuery = (function() {
+
+// Define a local copy of jQuery
+var jQuery = function( selector, context ) {
+ // The jQuery object is actually just the init constructor 'enhanced'
+ return new jQuery.fn.init( selector, context, rootjQuery );
+ },
+
+ // Map over jQuery in case of overwrite
+ _jQuery = window.jQuery,
+
+ // Map over the $ in case of overwrite
+ _$ = window.$,
+
+ // A central reference to the root jQuery(document)
+ rootjQuery,
+
+ // A simple way to check for HTML strings or ID strings
+ // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
+ quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,
+
+ // Check if a string has a non-whitespace character in it
+ rnotwhite = /\S/,
+
+ // Used for trimming whitespace
+ trimLeft = /^\s+/,
+ trimRight = /\s+$/,
+
+ // Match a standalone tag
+ rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
+
+ // JSON RegExp
+ rvalidchars = /^[\],:{}\s]*$/,
+ rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g,
+
+ // Useragent RegExp
+ rwebkit = /(webkit)[ \/]([\w.]+)/,
+ ropera = /(opera)(?:.*version)?[ \/]([\w.]+)/,
+ rmsie = /(msie) ([\w.]+)/,
+ rmozilla = /(mozilla)(?:.*? rv:([\w.]+))?/,
+
+ // Matches dashed string for camelizing
+ rdashAlpha = /-([a-z]|[0-9])/ig,
+ rmsPrefix = /^-ms-/,
+
+ // Used by jQuery.camelCase as callback to replace()
+ fcamelCase = function( all, letter ) {
+ return ( letter + "" ).toUpperCase();
+ },
+
+ // Keep a UserAgent string for use with jQuery.browser
+ userAgent = navigator.userAgent,
+
+ // For matching the engine and version of the browser
+ browserMatch,
+
+ // The deferred used on DOM ready
+ readyList,
+
+ // The ready event handler
+ DOMContentLoaded,
+
+ // Save a reference to some core methods
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty,
+ push = Array.prototype.push,
+ slice = Array.prototype.slice,
+ trim = String.prototype.trim,
+ indexOf = Array.prototype.indexOf,
+
+ // [[Class]] -> type pairs
+ class2type = {};
+
+jQuery.fn = jQuery.prototype = {
+ constructor: jQuery,
+ init: function( selector, context, rootjQuery ) {
+ var match, elem, ret, doc;
+
+ // Handle $(""), $(null), or $(undefined)
+ if ( !selector ) {
+ return this;
+ }
+
+ // Handle $(DOMElement)
+ if ( selector.nodeType ) {
+ this.context = this[0] = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // The body element only exists once, optimize finding it
+ if ( selector === "body" && !context && document.body ) {
+ this.context = document;
+ this[0] = document.body;
+ this.selector = selector;
+ this.length = 1;
+ return this;
+ }
+
+ // Handle HTML strings
+ if ( typeof selector === "string" ) {
+ // Are we dealing with HTML string or an ID?
+ if ( selector.charAt(0) === "<" && selector.charAt( selector.length - 1 ) === ">" && selector.length >= 3 ) {
+ // Assume that strings that start and end with <> are HTML and skip the regex check
+ match = [ null, selector, null ];
+
+ } else {
+ match = quickExpr.exec( selector );
+ }
+
+ // Verify a match, and that no context was specified for #id
+ if ( match && (match[1] || !context) ) {
+
+ // HANDLE: $(html) -> $(array)
+ if ( match[1] ) {
+ context = context instanceof jQuery ? context[0] : context;
+ doc = ( context ? context.ownerDocument || context : document );
+
+ // If a single string is passed in and it's a single tag
+ // just do a createElement and skip the rest
+ ret = rsingleTag.exec( selector );
+
+ if ( ret ) {
+ if ( jQuery.isPlainObject( context ) ) {
+ selector = [ document.createElement( ret[1] ) ];
+ jQuery.fn.attr.call( selector, context, true );
+
+ } else {
+ selector = [ doc.createElement( ret[1] ) ];
+ }
+
+ } else {
+ ret = jQuery.buildFragment( [ match[1] ], [ doc ] );
+ selector = ( ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment ).childNodes;
+ }
+
+ return jQuery.merge( this, selector );
+
+ // HANDLE: $("#id")
+ } else {
+ elem = document.getElementById( match[2] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id !== match[2] ) {
+ return rootjQuery.find( selector );
+ }
+
+ // Otherwise, we inject the element directly into the jQuery object
+ this.length = 1;
+ this[0] = elem;
+ }
+
+ this.context = document;
+ this.selector = selector;
+ return this;
+ }
+
+ // HANDLE: $(expr, $(...))
+ } else if ( !context || context.jquery ) {
+ return ( context || rootjQuery ).find( selector );
+
+ // HANDLE: $(expr, context)
+ // (which is just equivalent to: $(context).find(expr)
+ } else {
+ return this.constructor( context ).find( selector );
+ }
+
+ // HANDLE: $(function)
+ // Shortcut for document ready
+ } else if ( jQuery.isFunction( selector ) ) {
+ return rootjQuery.ready( selector );
+ }
+
+ if ( selector.selector !== undefined ) {
+ this.selector = selector.selector;
+ this.context = selector.context;
+ }
+
+ return jQuery.makeArray( selector, this );
+ },
+
+ // Start with an empty selector
+ selector: "",
+
+ // The current version of jQuery being used
+ jquery: "1.7.2",
+
+ // The default length of a jQuery object is 0
+ length: 0,
+
+ // The number of elements contained in the matched element set
+ size: function() {
+ return this.length;
+ },
+
+ toArray: function() {
+ return slice.call( this, 0 );
+ },
+
+ // Get the Nth element in the matched element set OR
+ // Get the whole matched element set as a clean array
+ get: function( num ) {
+ return num == null ?
+
+ // Return a 'clean' array
+ this.toArray() :
+
+ // Return just the object
+ ( num < 0 ? this[ this.length + num ] : this[ num ] );
+ },
+
+ // Take an array of elements and push it onto the stack
+ // (returning the new matched element set)
+ pushStack: function( elems, name, selector ) {
+ // Build a new jQuery matched element set
+ var ret = this.constructor();
+
+ if ( jQuery.isArray( elems ) ) {
+ push.apply( ret, elems );
+
+ } else {
+ jQuery.merge( ret, elems );
+ }
+
+ // Add the old object onto the stack (as a reference)
+ ret.prevObject = this;
+
+ ret.context = this.context;
+
+ if ( name === "find" ) {
+ ret.selector = this.selector + ( this.selector ? " " : "" ) + selector;
+ } else if ( name ) {
+ ret.selector = this.selector + "." + name + "(" + selector + ")";
+ }
+
+ // Return the newly-formed element set
+ return ret;
+ },
+
+ // Execute a callback for every element in the matched set.
+ // (You can seed the arguments with an array of args, but this is
+ // only used internally.)
+ each: function( callback, args ) {
+ return jQuery.each( this, callback, args );
+ },
+
+ ready: function( fn ) {
+ // Attach the listeners
+ jQuery.bindReady();
+
+ // Add the callback
+ readyList.add( fn );
+
+ return this;
+ },
+
+ eq: function( i ) {
+ i = +i;
+ return i === -1 ?
+ this.slice( i ) :
+ this.slice( i, i + 1 );
+ },
+
+ first: function() {
+ return this.eq( 0 );
+ },
+
+ last: function() {
+ return this.eq( -1 );
+ },
+
+ slice: function() {
+ return this.pushStack( slice.apply( this, arguments ),
+ "slice", slice.call(arguments).join(",") );
+ },
+
+ map: function( callback ) {
+ return this.pushStack( jQuery.map(this, function( elem, i ) {
+ return callback.call( elem, i, elem );
+ }));
+ },
+
+ end: function() {
+ return this.prevObject || this.constructor(null);
+ },
+
+ // For internal use only.
+ // Behaves like an Array's method, not like a jQuery method.
+ push: push,
+ sort: [].sort,
+ splice: [].splice
+};
+
+// Give the init function the jQuery prototype for later instantiation
+jQuery.fn.init.prototype = jQuery.fn;
+
+jQuery.extend = jQuery.fn.extend = function() {
+ var options, name, src, copy, copyIsArray, clone,
+ target = arguments[0] || {},
+ i = 1,
+ length = arguments.length,
+ deep = false;
+
+ // Handle a deep copy situation
+ if ( typeof target === "boolean" ) {
+ deep = target;
+ target = arguments[1] || {};
+ // skip the boolean and the target
+ i = 2;
+ }
+
+ // Handle case when target is a string or something (possible in deep copy)
+ if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
+ target = {};
+ }
+
+ // extend jQuery itself if only one argument is passed
+ if ( length === i ) {
+ target = this;
+ --i;
+ }
+
+ for ( ; i < length; i++ ) {
+ // Only deal with non-null/undefined values
+ if ( (options = arguments[ i ]) != null ) {
+ // Extend the base object
+ for ( name in options ) {
+ src = target[ name ];
+ copy = options[ name ];
+
+ // Prevent never-ending loop
+ if ( target === copy ) {
+ continue;
+ }
+
+ // Recurse if we're merging plain objects or arrays
+ if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
+ if ( copyIsArray ) {
+ copyIsArray = false;
+ clone = src && jQuery.isArray(src) ? src : [];
+
+ } else {
+ clone = src && jQuery.isPlainObject(src) ? src : {};
+ }
+
+ // Never move original objects, clone them
+ target[ name ] = jQuery.extend( deep, clone, copy );
+
+ // Don't bring in undefined values
+ } else if ( copy !== undefined ) {
+ target[ name ] = copy;
+ }
+ }
+ }
+ }
+
+ // Return the modified object
+ return target;
+};
+
+jQuery.extend({
+ noConflict: function( deep ) {
+ if ( window.$ === jQuery ) {
+ window.$ = _$;
+ }
+
+ if ( deep && window.jQuery === jQuery ) {
+ window.jQuery = _jQuery;
+ }
+
+ return jQuery;
+ },
+
+ // Is the DOM ready to be used? Set to true once it occurs.
+ isReady: false,
+
+ // A counter to track how many items to wait for before
+ // the ready event fires. See #6781
+ readyWait: 1,
+
+ // Hold (or release) the ready event
+ holdReady: function( hold ) {
+ if ( hold ) {
+ jQuery.readyWait++;
+ } else {
+ jQuery.ready( true );
+ }
+ },
+
+ // Handle when the DOM is ready
+ ready: function( wait ) {
+ // Either a released hold or an DOMready/load event and not yet ready
+ if ( (wait === true && !--jQuery.readyWait) || (wait !== true && !jQuery.isReady) ) {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( !document.body ) {
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Remember that the DOM is ready
+ jQuery.isReady = true;
+
+ // If a normal DOM Ready event fired, decrement, and wait if need be
+ if ( wait !== true && --jQuery.readyWait > 0 ) {
+ return;
+ }
+
+ // If there are functions bound, to execute
+ readyList.fireWith( document, [ jQuery ] );
+
+ // Trigger any bound ready events
+ if ( jQuery.fn.trigger ) {
+ jQuery( document ).trigger( "ready" ).off( "ready" );
+ }
+ }
+ },
+
+ bindReady: function() {
+ if ( readyList ) {
+ return;
+ }
+
+ readyList = jQuery.Callbacks( "once memory" );
+
+ // Catch cases where $(document).ready() is called after the
+ // browser event has already occurred.
+ if ( document.readyState === "complete" ) {
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
+ return setTimeout( jQuery.ready, 1 );
+ }
+
+ // Mozilla, Opera and webkit nightlies currently support this event
+ if ( document.addEventListener ) {
+ // Use the handy event callback
+ document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+
+ // A fallback to window.onload, that will always work
+ window.addEventListener( "load", jQuery.ready, false );
+
+ // If IE event model is used
+ } else if ( document.attachEvent ) {
+ // ensure firing before onload,
+ // maybe late but safe also for iframes
+ document.attachEvent( "onreadystatechange", DOMContentLoaded );
+
+ // A fallback to window.onload, that will always work
+ window.attachEvent( "onload", jQuery.ready );
+
+ // If IE and not a frame
+ // continually check to see if the document is ready
+ var toplevel = false;
+
+ try {
+ toplevel = window.frameElement == null;
+ } catch(e) {}
+
+ if ( document.documentElement.doScroll && toplevel ) {
+ doScrollCheck();
+ }
+ }
+ },
+
+ // See test/unit/core.js for details concerning isFunction.
+ // Since version 1.3, DOM methods and functions like alert
+ // aren't supported. They return false on IE (#2968).
+ isFunction: function( obj ) {
+ return jQuery.type(obj) === "function";
+ },
+
+ isArray: Array.isArray || function( obj ) {
+ return jQuery.type(obj) === "array";
+ },
+
+ isWindow: function( obj ) {
+ return obj != null && obj == obj.window;
+ },
+
+ isNumeric: function( obj ) {
+ return !isNaN( parseFloat(obj) ) && isFinite( obj );
+ },
+
+ type: function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
+ },
+
+ isPlainObject: function( obj ) {
+ // Must be an Object.
+ // Because of IE, we also have to check the presence of the constructor property.
+ // Make sure that DOM nodes and window objects don't pass through, as well
+ if ( !obj || jQuery.type(obj) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
+ return false;
+ }
+
+ try {
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+ } catch ( e ) {
+ // IE8,9 Will throw exceptions on certain host objects #9897
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
+ },
+
+ isEmptyObject: function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ return true;
+ },
+
+ error: function( msg ) {
+ throw new Error( msg );
+ },
+
+ parseJSON: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+
+ // Make sure leading/trailing whitespace is removed (IE can't handle it)
+ data = jQuery.trim( data );
+
+ // Attempt to parse using the native JSON parser first
+ if ( window.JSON && window.JSON.parse ) {
+ return window.JSON.parse( data );
+ }
+
+ // Make sure the incoming data is actual JSON
+ // Logic borrowed from http://json.org/json2.js
+ if ( rvalidchars.test( data.replace( rvalidescape, "@" )
+ .replace( rvalidtokens, "]" )
+ .replace( rvalidbraces, "")) ) {
+
+ return ( new Function( "return " + data ) )();
+
+ }
+ jQuery.error( "Invalid JSON: " + data );
+ },
+
+ // Cross-browser xml parsing
+ parseXML: function( data ) {
+ if ( typeof data !== "string" || !data ) {
+ return null;
+ }
+ var xml, tmp;
+ try {
+ if ( window.DOMParser ) { // Standard
+ tmp = new DOMParser();
+ xml = tmp.parseFromString( data , "text/xml" );
+ } else { // IE
+ xml = new ActiveXObject( "Microsoft.XMLDOM" );
+ xml.async = "false";
+ xml.loadXML( data );
+ }
+ } catch( e ) {
+ xml = undefined;
+ }
+ if ( !xml || !xml.documentElement || xml.getElementsByTagName( "parsererror" ).length ) {
+ jQuery.error( "Invalid XML: " + data );
+ }
+ return xml;
+ },
+
+ noop: function() {},
+
+ // Evaluates a script in a global context
+ // Workarounds based on findings by Jim Driscoll
+ // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context
+ globalEval: function( data ) {
+ if ( data && rnotwhite.test( data ) ) {
+ // We use execScript on Internet Explorer
+ // We use an anonymous function so that context is window
+ // rather than jQuery in Firefox
+ ( window.execScript || function( data ) {
+ window[ "eval" ].call( window, data );
+ } )( data );
+ }
+ },
+
+ // Convert dashed to camelCase; used by the css and data modules
+ // Microsoft forgot to hump their vendor prefix (#9572)
+ camelCase: function( string ) {
+ return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
+ },
+
+ nodeName: function( elem, name ) {
+ return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
+ },
+
+ // args is for internal usage only
+ each: function( object, callback, args ) {
+ var name, i = 0,
+ length = object.length,
+ isObj = length === undefined || jQuery.isFunction( object );
+
+ if ( args ) {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.apply( object[ name ], args ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.apply( object[ i++ ], args ) === false ) {
+ break;
+ }
+ }
+ }
+
+ // A special, fast, case for the most common use of each
+ } else {
+ if ( isObj ) {
+ for ( name in object ) {
+ if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
+ break;
+ }
+ }
+ } else {
+ for ( ; i < length; ) {
+ if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return object;
+ },
+
+ // Use native String.trim function wherever possible
+ trim: trim ?
+ function( text ) {
+ return text == null ?
+ "" :
+ trim.call( text );
+ } :
+
+ // Otherwise use our own trimming functionality
+ function( text ) {
+ return text == null ?
+ "" :
+ text.toString().replace( trimLeft, "" ).replace( trimRight, "" );
+ },
+
+ // results is for internal usage only
+ makeArray: function( array, results ) {
+ var ret = results || [];
+
+ if ( array != null ) {
+ // The window, strings (and functions) also have 'length'
+ // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930
+ var type = jQuery.type( array );
+
+ if ( array.length == null || type === "string" || type === "function" || type === "regexp" || jQuery.isWindow( array ) ) {
+ push.call( ret, array );
+ } else {
+ jQuery.merge( ret, array );
+ }
+ }
+
+ return ret;
+ },
+
+ inArray: function( elem, array, i ) {
+ var len;
+
+ if ( array ) {
+ if ( indexOf ) {
+ return indexOf.call( array, elem, i );
+ }
+
+ len = array.length;
+ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
+
+ for ( ; i < len; i++ ) {
+ // Skip accessing in sparse arrays
+ if ( i in array && array[ i ] === elem ) {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+ },
+
+ merge: function( first, second ) {
+ var i = first.length,
+ j = 0;
+
+ if ( typeof second.length === "number" ) {
+ for ( var l = second.length; j < l; j++ ) {
+ first[ i++ ] = second[ j ];
+ }
+
+ } else {
+ while ( second[j] !== undefined ) {
+ first[ i++ ] = second[ j++ ];
+ }
+ }
+
+ first.length = i;
+
+ return first;
+ },
+
+ grep: function( elems, callback, inv ) {
+ var ret = [], retVal;
+ inv = !!inv;
+
+ // Go through the array, only saving the items
+ // that pass the validator function
+ for ( var i = 0, length = elems.length; i < length; i++ ) {
+ retVal = !!callback( elems[ i ], i );
+ if ( inv !== retVal ) {
+ ret.push( elems[ i ] );
+ }
+ }
+
+ return ret;
+ },
+
+ // arg is for internal usage only
+ map: function( elems, callback, arg ) {
+ var value, key, ret = [],
+ i = 0,
+ length = elems.length,
+ // jquery objects are treated as arrays
+ isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
+
+ // Go through the array, translating each of the items to their
+ if ( isArray ) {
+ for ( ; i < length; i++ ) {
+ value = callback( elems[ i ], i, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+
+ // Go through every key on the object,
+ } else {
+ for ( key in elems ) {
+ value = callback( elems[ key ], key, arg );
+
+ if ( value != null ) {
+ ret[ ret.length ] = value;
+ }
+ }
+ }
+
+ // Flatten any nested arrays
+ return ret.concat.apply( [], ret );
+ },
+
+ // A global GUID counter for objects
+ guid: 1,
+
+ // Bind a function to a context, optionally partially applying any
+ // arguments.
+ proxy: function( fn, context ) {
+ if ( typeof context === "string" ) {
+ var tmp = fn[ context ];
+ context = fn;
+ fn = tmp;
+ }
+
+ // Quick check to determine if target is callable, in the spec
+ // this throws a TypeError, but we will just return undefined.
+ if ( !jQuery.isFunction( fn ) ) {
+ return undefined;
+ }
+
+ // Simulated bind
+ var args = slice.call( arguments, 2 ),
+ proxy = function() {
+ return fn.apply( context, args.concat( slice.call( arguments ) ) );
+ };
+
+ // Set the guid of unique handler to the same of original handler, so it can be removed
+ proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
+
+ return proxy;
+ },
+
+ // Mutifunctional method to get and set values to a collection
+ // The value/s can optionally be executed if it's a function
+ access: function( elems, fn, key, value, chainable, emptyGet, pass ) {
+ var exec,
+ bulk = key == null,
+ i = 0,
+ length = elems.length;
+
+ // Sets many values
+ if ( key && typeof key === "object" ) {
+ for ( i in key ) {
+ jQuery.access( elems, fn, i, key[i], 1, emptyGet, value );
+ }
+ chainable = 1;
+
+ // Sets one value
+ } else if ( value !== undefined ) {
+ // Optionally, function values get executed if exec is true
+ exec = pass === undefined && jQuery.isFunction( value );
+
+ if ( bulk ) {
+ // Bulk operations only iterate when executing function values
+ if ( exec ) {
+ exec = fn;
+ fn = function( elem, key, value ) {
+ return exec.call( jQuery( elem ), value );
+ };
+
+ // Otherwise they run against the entire set
+ } else {
+ fn.call( elems, value );
+ fn = null;
+ }
+ }
+
+ if ( fn ) {
+ for (; i < length; i++ ) {
+ fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
+ }
+ }
+
+ chainable = 1;
+ }
+
+ return chainable ?
+ elems :
+
+ // Gets
+ bulk ?
+ fn.call( elems ) :
+ length ? fn( elems[0], key ) : emptyGet;
+ },
+
+ now: function() {
+ return ( new Date() ).getTime();
+ },
+
+ // Use of jQuery.browser is frowned upon.
+ // More details: http://docs.jquery.com/Utilities/jQuery.browser
+ uaMatch: function( ua ) {
+ ua = ua.toLowerCase();
+
+ var match = rwebkit.exec( ua ) ||
+ ropera.exec( ua ) ||
+ rmsie.exec( ua ) ||
+ ua.indexOf("compatible") < 0 && rmozilla.exec( ua ) ||
+ [];
+
+ return { browser: match[1] || "", version: match[2] || "0" };
+ },
+
+ sub: function() {
+ function jQuerySub( selector, context ) {
+ return new jQuerySub.fn.init( selector, context );
+ }
+ jQuery.extend( true, jQuerySub, this );
+ jQuerySub.superclass = this;
+ jQuerySub.fn = jQuerySub.prototype = this();
+ jQuerySub.fn.constructor = jQuerySub;
+ jQuerySub.sub = this.sub;
+ jQuerySub.fn.init = function init( selector, context ) {
+ if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
+ context = jQuerySub( context );
+ }
+
+ return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
+ };
+ jQuerySub.fn.init.prototype = jQuerySub.fn;
+ var rootjQuerySub = jQuerySub(document);
+ return jQuerySub;
+ },
+
+ browser: {}
+});
+
+// Populate the class2type map
+jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
+ class2type[ "[object " + name + "]" ] = name.toLowerCase();
+});
+
+browserMatch = jQuery.uaMatch( userAgent );
+if ( browserMatch.browser ) {
+ jQuery.browser[ browserMatch.browser ] = true;
+ jQuery.browser.version = browserMatch.version;
+}
+
+// Deprecated, use jQuery.browser.webkit instead
+if ( jQuery.browser.webkit ) {
+ jQuery.browser.safari = true;
+}
+
+// IE doesn't match non-breaking spaces with \s
+if ( rnotwhite.test( "\xA0" ) ) {
+ trimLeft = /^[\s\xA0]+/;
+ trimRight = /[\s\xA0]+$/;
+}
+
+// All jQuery objects should point back to these
+rootjQuery = jQuery(document);
+
+// Cleanup functions for the document ready method
+if ( document.addEventListener ) {
+ DOMContentLoaded = function() {
+ document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
+ jQuery.ready();
+ };
+
+} else if ( document.attachEvent ) {
+ DOMContentLoaded = function() {
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
+ if ( document.readyState === "complete" ) {
+ document.detachEvent( "onreadystatechange", DOMContentLoaded );
+ jQuery.ready();
+ }
+ };
+}
+
+// The DOM ready check for Internet Explorer
+function doScrollCheck() {
+ if ( jQuery.isReady ) {
+ return;
+ }
+
+ try {
+ // If IE is used, use the trick by Diego Perini
+ // http://javascript.nwbox.com/IEContentLoaded/
+ document.documentElement.doScroll("left");
+ } catch(e) {
+ setTimeout( doScrollCheck, 1 );
+ return;
+ }
+
+ // and execute any waiting functions
+ jQuery.ready();
+}
+
+return jQuery;
+
+})();
+
+
+// String to Object flags format cache
+var flagsCache = {};
+
+// Convert String-formatted flags into Object-formatted ones and store in cache
+function createFlags( flags ) {
+ var object = flagsCache[ flags ] = {},
+ i, length;
+ flags = flags.split( /\s+/ );
+ for ( i = 0, length = flags.length; i < length; i++ ) {
+ object[ flags[i] ] = true;
+ }
+ return object;
+}
+
+/*
+ * Create a callback list using the following parameters:
+ *
+ * flags: an optional list of space-separated flags that will change how
+ * the callback list behaves
+ *
+ * By default a callback list will act like an event callback list and can be
+ * "fired" multiple times.
+ *
+ * Possible flags:
+ *
+ * once: will ensure the callback list can only be fired once (like a Deferred)
+ *
+ * memory: will keep track of previous values and will call any callback added
+ * after the list has been fired right away with the latest "memorized"
+ * values (like a Deferred)
+ *
+ * unique: will ensure a callback can only be added once (no duplicate in the list)
+ *
+ * stopOnFalse: interrupt callings when a callback returns false
+ *
+ */
+jQuery.Callbacks = function( flags ) {
+
+ // Convert flags from String-formatted to Object-formatted
+ // (we check in cache first)
+ flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};
+
+ var // Actual callback list
+ list = [],
+ // Stack of fire calls for repeatable lists
+ stack = [],
+ // Last fire value (for non-forgettable lists)
+ memory,
+ // Flag to know if list was already fired
+ fired,
+ // Flag to know if list is currently firing
+ firing,
+ // First callback to fire (used internally by add and fireWith)
+ firingStart,
+ // End of the loop when firing
+ firingLength,
+ // Index of currently firing callback (modified by remove if needed)
+ firingIndex,
+ // Add one or several callbacks to the list
+ add = function( args ) {
+ var i,
+ length,
+ elem,
+ type,
+ actual;
+ for ( i = 0, length = args.length; i < length; i++ ) {
+ elem = args[ i ];
+ type = jQuery.type( elem );
+ if ( type === "array" ) {
+ // Inspect recursively
+ add( elem );
+ } else if ( type === "function" ) {
+ // Add if not in unique mode and callback is not in
+ if ( !flags.unique || !self.has( elem ) ) {
+ list.push( elem );
+ }
+ }
+ }
+ },
+ // Fire callbacks
+ fire = function( context, args ) {
+ args = args || [];
+ memory = !flags.memory || [ context, args ];
+ fired = true;
+ firing = true;
+ firingIndex = firingStart || 0;
+ firingStart = 0;
+ firingLength = list.length;
+ for ( ; list && firingIndex < firingLength; firingIndex++ ) {
+ if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
+ memory = true; // Mark as halted
+ break;
+ }
+ }
+ firing = false;
+ if ( list ) {
+ if ( !flags.once ) {
+ if ( stack && stack.length ) {
+ memory = stack.shift();
+ self.fireWith( memory[ 0 ], memory[ 1 ] );
+ }
+ } else if ( memory === true ) {
+ self.disable();
+ } else {
+ list = [];
+ }
+ }
+ },
+ // Actual Callbacks object
+ self = {
+ // Add a callback or a collection of callbacks to the list
+ add: function() {
+ if ( list ) {
+ var length = list.length;
+ add( arguments );
+ // Do we need to add the callbacks to the
+ // current firing batch?
+ if ( firing ) {
+ firingLength = list.length;
+ // With memory, if we're not firing then
+ // we should call right away, unless previous
+ // firing was halted (stopOnFalse)
+ } else if ( memory && memory !== true ) {
+ firingStart = length;
+ fire( memory[ 0 ], memory[ 1 ] );
+ }
+ }
+ return this;
+ },
+ // Remove a callback from the list
+ remove: function() {
+ if ( list ) {
+ var args = arguments,
+ argIndex = 0,
+ argLength = args.length;
+ for ( ; argIndex < argLength ; argIndex++ ) {
+ for ( var i = 0; i < list.length; i++ ) {
+ if ( args[ argIndex ] === list[ i ] ) {
+ // Handle firingIndex and firingLength
+ if ( firing ) {
+ if ( i <= firingLength ) {
+ firingLength--;
+ if ( i <= firingIndex ) {
+ firingIndex--;
+ }
+ }
+ }
+ // Remove the element
+ list.splice( i--, 1 );
+ // If we have some unicity property then
+ // we only need to do this once
+ if ( flags.unique ) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return this;
+ },
+ // Control if a given callback is in the list
+ has: function( fn ) {
+ if ( list ) {
+ var i = 0,
+ length = list.length;
+ for ( ; i < length; i++ ) {
+ if ( fn === list[ i ] ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ },
+ // Remove all callbacks from the list
+ empty: function() {
+ list = [];
+ return this;
+ },
+ // Have the list do nothing anymore
+ disable: function() {
+ list = stack = memory = undefined;
+ return this;
+ },
+ // Is it disabled?
+ disabled: function() {
+ return !list;
+ },
+ // Lock the list in its current state
+ lock: function() {
+ stack = undefined;
+ if ( !memory || memory === true ) {
+ self.disable();
+ }
+ return this;
+ },
+ // Is it locked?
+ locked: function() {
+ return !stack;
+ },
+ // Call all callbacks with the given context and arguments
+ fireWith: function( context, args ) {
+ if ( stack ) {
+ if ( firing ) {
+ if ( !flags.once ) {
+ stack.push( [ context, args ] );
+ }
+ } else if ( !( flags.once && memory ) ) {
+ fire( context, args );
+ }
+ }
+ return this;
+ },
+ // Call all the callbacks with the given arguments
+ fire: function() {
+ self.fireWith( this, arguments );
+ return this;
+ },
+ // To know if the callbacks have already been called at least once
+ fired: function() {
+ return !!fired;
+ }
+ };
+
+ return self;
+};
+
+
+
+
+var // Static reference to slice
+ sliceDeferred = [].slice;
+
+jQuery.extend({
+
+ Deferred: function( func ) {
+ var doneList = jQuery.Callbacks( "once memory" ),
+ failList = jQuery.Callbacks( "once memory" ),
+ progressList = jQuery.Callbacks( "memory" ),
+ state = "pending",
+ lists = {
+ resolve: doneList,
+ reject: failList,
+ notify: progressList
+ },
+ promise = {
+ done: doneList.add,
+ fail: failList.add,
+ progress: progressList.add,
+
+ state: function() {
+ return state;
+ },
+
+ // Deprecated
+ isResolved: doneList.fired,
+ isRejected: failList.fired,
+
+ then: function( doneCallbacks, failCallbacks, progressCallbacks ) {
+ deferred.done( doneCallbacks ).fail( failCallbacks ).progress( progressCallbacks );
+ return this;
+ },
+ always: function() {
+ deferred.done.apply( deferred, arguments ).fail.apply( deferred, arguments );
+ return this;
+ },
+ pipe: function( fnDone, fnFail, fnProgress ) {
+ return jQuery.Deferred(function( newDefer ) {
+ jQuery.each( {
+ done: [ fnDone, "resolve" ],
+ fail: [ fnFail, "reject" ],
+ progress: [ fnProgress, "notify" ]
+ }, function( handler, data ) {
+ var fn = data[ 0 ],
+ action = data[ 1 ],
+ returned;
+ if ( jQuery.isFunction( fn ) ) {
+ deferred[ handler ](function() {
+ returned = fn.apply( this, arguments );
+ if ( returned && jQuery.isFunction( returned.promise ) ) {
+ returned.promise().then( newDefer.resolve, newDefer.reject, newDefer.notify );
+ } else {
+ newDefer[ action + "With" ]( this === deferred ? newDefer : this, [ returned ] );
+ }
+ });
+ } else {
+ deferred[ handler ]( newDefer[ action ] );
+ }
+ });
+ }).promise();
+ },
+ // Get a promise for this deferred
+ // If obj is provided, the promise aspect is added to the object
+ promise: function( obj ) {
+ if ( obj == null ) {
+ obj = promise;
+ } else {
+ for ( var key in promise ) {
+ obj[ key ] = promise[ key ];
+ }
+ }
+ return obj;
+ }
+ },
+ deferred = promise.promise({}),
+ key;
+
+ for ( key in lists ) {
+ deferred[ key ] = lists[ key ].fire;
+ deferred[ key + "With" ] = lists[ key ].fireWith;
+ }
+
+ // Handle state
+ deferred.done( function() {
+ state = "resolved";
+ }, failList.disable, progressList.lock ).fail( function() {
+ state = "rejected";
+ }, doneList.disable, progressList.lock );
+
+ // Call given func if any
+ if ( func ) {
+ func.call( deferred, deferred );
+ }
+
+ // All done!
+ return deferred;
+ },
+
+ // Deferred helper
+ when: function( firstParam ) {
+ var args = sliceDeferred.call( arguments, 0 ),
+ i = 0,
+ length = args.length,
+ pValues = new Array( length ),
+ count = length,
+ pCount = length,
+ deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?
+ firstParam :
+ jQuery.Deferred(),
+ promise = deferred.promise();
+ function resolveFunc( i ) {
+ return function( value ) {
+ args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ if ( !( --count ) ) {
+ deferred.resolveWith( deferred, args );
+ }
+ };
+ }
+ function progressFunc( i ) {
+ return function( value ) {
+ pValues[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;
+ deferred.notifyWith( promise, pValues );
+ };
+ }
+ if ( length > 1 ) {
+ for ( ; i < length; i++ ) {
+ if ( args[ i ] && args[ i ].promise && jQuery.isFunction( args[ i ].promise ) ) {
+ args[ i ].promise().then( resolveFunc(i), deferred.reject, progressFunc(i) );
+ } else {
+ --count;
+ }
+ }
+ if ( !count ) {
+ deferred.resolveWith( deferred, args );
+ }
+ } else if ( deferred !== firstParam ) {
+ deferred.resolveWith( deferred, length ? [ firstParam ] : [] );
+ }
+ return promise;
+ }
+});
+
+
+
+
+jQuery.support = (function() {
+
+ var support,
+ all,
+ a,
+ select,
+ opt,
+ input,
+ fragment,
+ tds,
+ events,
+ eventName,
+ i,
+ isSupported,
+ div = document.createElement( "div" ),
+ documentElement = document.documentElement;
+
+ // Preliminary tests
+ div.setAttribute("className", "t");
+ div.innerHTML = " <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>";
+
+ all = div.getElementsByTagName( "*" );
+ a = div.getElementsByTagName( "a" )[ 0 ];
+
+ // Can't get basic test support
+ if ( !all || !all.length || !a ) {
+ return {};
+ }
+
+ // First batch of supports tests
+ select = document.createElement( "select" );
+ opt = select.appendChild( document.createElement("option") );
+ input = div.getElementsByTagName( "input" )[ 0 ];
+
+ support = {
+ // IE strips leading whitespace when .innerHTML is used
+ leadingWhitespace: ( div.firstChild.nodeType === 3 ),
+
+ // Make sure that tbody elements aren't automatically inserted
+ // IE will insert them into empty tables
+ tbody: !div.getElementsByTagName("tbody").length,
+
+ // Make sure that link elements get serialized correctly by innerHTML
+ // This requires a wrapper element in IE
+ htmlSerialize: !!div.getElementsByTagName("link").length,
+
+ // Get the style information from getAttribute
+ // (IE uses .cssText instead)
+ style: /top/.test( a.getAttribute("style") ),
+
+ // Make sure that URLs aren't manipulated
+ // (IE normalizes it by default)
+ hrefNormalized: ( a.getAttribute("href") === "/a" ),
+
+ // Make sure that element opacity exists
+ // (IE uses filter instead)
+ // Use a regex to work around a WebKit issue. See #5145
+ opacity: /^0.55/.test( a.style.opacity ),
+
+ // Verify style float existence
+ // (IE uses styleFloat instead of cssFloat)
+ cssFloat: !!a.style.cssFloat,
+
+ // Make sure that if no value is specified for a checkbox
+ // that it defaults to "on".
+ // (WebKit defaults to "" instead)
+ checkOn: ( input.value === "on" ),
+
+ // Make sure that a selected-by-default option has a working selected property.
+ // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
+ optSelected: opt.selected,
+
+ // Test setAttribute on camelCase class. If it works, we need attrFixes when doing get/setAttribute (ie6/7)
+ getSetAttribute: div.className !== "t",
+
+ // Tests for enctype support on a form(#6743)
+ enctype: !!document.createElement("form").enctype,
+
+ // Makes sure cloning an html5 element does not cause problems
+ // Where outerHTML is undefined, this still works
+ html5Clone: document.createElement("nav").cloneNode( true ).outerHTML !== "<:nav></:nav>",
+
+ // Will be defined later
+ submitBubbles: true,
+ changeBubbles: true,
+ focusinBubbles: false,
+ deleteExpando: true,
+ noCloneEvent: true,
+ inlineBlockNeedsLayout: false,
+ shrinkWrapBlocks: false,
+ reliableMarginRight: true,
+ pixelMargin: true
+ };
+
+ // jQuery.boxModel DEPRECATED in 1.3, use jQuery.support.boxModel instead
+ jQuery.boxModel = support.boxModel = (document.compatMode === "CSS1Compat");
+
+ // Make sure checked status is properly cloned
+ input.checked = true;
+ support.noCloneChecked = input.cloneNode( true ).checked;
+
+ // Make sure that the options inside disabled selects aren't marked as disabled
+ // (WebKit marks them as disabled)
+ select.disabled = true;
+ support.optDisabled = !opt.disabled;
+
+ // Test to see if it's possible to delete an expando from an element
+ // Fails in Internet Explorer
+ try {
+ delete div.test;
+ } catch( e ) {
+ support.deleteExpando = false;
+ }
+
+ if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {
+ div.attachEvent( "onclick", function() {
+ // Cloning a node shouldn't copy over any
+ // bound event handlers (IE does this)
+ support.noCloneEvent = false;
+ });
+ div.cloneNode( true ).fireEvent( "onclick" );
+ }
+
+ // Check if a radio maintains its value
+ // after being appended to the DOM
+ input = document.createElement("input");
+ input.value = "t";
+ input.setAttribute("type", "radio");
+ support.radioValue = input.value === "t";
+
+ input.setAttribute("checked", "checked");
+
+ // #11217 - WebKit loses check when the name is after the checked attribute
+ input.setAttribute( "name", "t" );
+
+ div.appendChild( input );
+ fragment = document.createDocumentFragment();
+ fragment.appendChild( div.lastChild );
+
+ // WebKit doesn't clone checked state correctly in fragments
+ support.checkClone = fragment.cloneNode( true ).cloneNode( true ).lastChild.checked;
+
+ // Check if a disconnected checkbox will retain its checked
+ // value of true after appended to the DOM (IE6/7)
+ support.appendChecked = input.checked;
+
+ fragment.removeChild( input );
+ fragment.appendChild( div );
+
+ // Technique from Juriy Zaytsev
+ // http://perfectionkills.com/detecting-event-support-without-browser-sniffing/
+ // We only care about the case where non-standard event systems
+ // are used, namely in IE. Short-circuiting here helps us to
+ // avoid an eval call (in setAttribute) which can cause CSP
+ // to go haywire. See: https://developer.mozilla.org/en/Security/CSP
+ if ( div.attachEvent ) {
+ for ( i in {
+ submit: 1,
+ change: 1,
+ focusin: 1
+ }) {
+ eventName = "on" + i;
+ isSupported = ( eventName in div );
+ if ( !isSupported ) {
+ div.setAttribute( eventName, "return;" );
+ isSupported = ( typeof div[ eventName ] === "function" );
+ }
+ support[ i + "Bubbles" ] = isSupported;
+ }
+ }
+
+ fragment.removeChild( div );
+
+ // Null elements to avoid leaks in IE
+ fragment = select = opt = div = input = null;
+
+ // Run tests that need a body at doc ready
+ jQuery(function() {
+ var container, outer, inner, table, td, offsetSupport,
+ marginDiv, conMarginTop, style, html, positionTopLeftWidthHeight,
+ paddingMarginBorderVisibility, paddingMarginBorder,
+ body = document.getElementsByTagName("body")[0];
+
+ if ( !body ) {
+ // Return for frameset docs that don't have a body
+ return;
+ }
+
+ conMarginTop = 1;
+ paddingMarginBorder = "padding:0;margin:0;border:";
+ positionTopLeftWidthHeight = "position:absolute;top:0;left:0;width:1px;height:1px;";
+ paddingMarginBorderVisibility = paddingMarginBorder + "0;visibility:hidden;";
+ style = "style='" + positionTopLeftWidthHeight + paddingMarginBorder + "5px solid #000;";
+ html = "<div " + style + "display:block;'><div style='" + paddingMarginBorder + "0;display:block;overflow:hidden;'></div></div>" +
+ "<table " + style + "' cellpadding='0' cellspacing='0'>" +
+ "<tr><td></td></tr></table>";
+
+ container = document.createElement("div");
+ container.style.cssText = paddingMarginBorderVisibility + "width:0;height:0;position:static;top:0;margin-top:" + conMarginTop + "px";
+ body.insertBefore( container, body.firstChild );
+
+ // Construct the test element
+ div = document.createElement("div");
+ container.appendChild( div );
+
+ // Check if table cells still have offsetWidth/Height when they are set
+ // to display:none and there are still other visible table cells in a
+ // table row; if so, offsetWidth/Height are not reliable for use when
+ // determining if an element has been hidden directly using
+ // display:none (it is still safe to use offsets if a parent element is
+ // hidden; don safety goggles and see bug #4512 for more information).
+ // (only IE 8 fails this test)
+ div.innerHTML = "<table><tr><td style='" + paddingMarginBorder + "0;display:none'></td><td>t</td></tr></table>";
+ tds = div.getElementsByTagName( "td" );
+ isSupported = ( tds[ 0 ].offsetHeight === 0 );
+
+ tds[ 0 ].style.display = "";
+ tds[ 1 ].style.display = "none";
+
+ // Check if empty table cells still have offsetWidth/Height
+ // (IE <= 8 fail this test)
+ support.reliableHiddenOffsets = isSupported && ( tds[ 0 ].offsetHeight === 0 );
+
+ // Check if div with explicit width and no margin-right incorrectly
+ // gets computed margin-right based on width of container. For more
+ // info see bug #3333
+ // Fails in WebKit before Feb 2011 nightlies
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ if ( window.getComputedStyle ) {
+ div.innerHTML = "";
+ marginDiv = document.createElement( "div" );
+ marginDiv.style.width = "0";
+ marginDiv.style.marginRight = "0";
+ div.style.width = "2px";
+ div.appendChild( marginDiv );
+ support.reliableMarginRight =
+ ( parseInt( ( window.getComputedStyle( marginDiv, null ) || { marginRight: 0 } ).marginRight, 10 ) || 0 ) === 0;
+ }
+
+ if ( typeof div.style.zoom !== "undefined" ) {
+ // Check if natively block-level elements act like inline-block
+ // elements when setting their display to 'inline' and giving
+ // them layout
+ // (IE < 8 does this)
+ div.innerHTML = "";
+ div.style.width = div.style.padding = "1px";
+ div.style.border = 0;
+ div.style.overflow = "hidden";
+ div.style.display = "inline";
+ div.style.zoom = 1;
+ support.inlineBlockNeedsLayout = ( div.offsetWidth === 3 );
+
+ // Check if elements with layout shrink-wrap their children
+ // (IE 6 does this)
+ div.style.display = "block";
+ div.style.overflow = "visible";
+ div.innerHTML = "<div style='width:5px;'></div>";
+ support.shrinkWrapBlocks = ( div.offsetWidth !== 3 );
+ }
+
+ div.style.cssText = positionTopLeftWidthHeight + paddingMarginBorderVisibility;
+ div.innerHTML = html;
+
+ outer = div.firstChild;
+ inner = outer.firstChild;
+ td = outer.nextSibling.firstChild.firstChild;
+
+ offsetSupport = {
+ doesNotAddBorder: ( inner.offsetTop !== 5 ),
+ doesAddBorderForTableAndCells: ( td.offsetTop === 5 )
+ };
+
+ inner.style.position = "fixed";
+ inner.style.top = "20px";
+
+ // safari subtracts parent border width here which is 5px
+ offsetSupport.fixedPosition = ( inner.offsetTop === 20 || inner.offsetTop === 15 );
+ inner.style.position = inner.style.top = "";
+
+ outer.style.overflow = "hidden";
+ outer.style.position = "relative";
+
+ offsetSupport.subtractsBorderForOverflowNotVisible = ( inner.offsetTop === -5 );
+ offsetSupport.doesNotIncludeMarginInBodyOffset = ( body.offsetTop !== conMarginTop );
+
+ if ( window.getComputedStyle ) {
+ div.style.marginTop = "1%";
+ support.pixelMargin = ( window.getComputedStyle( div, null ) || { marginTop: 0 } ).marginTop !== "1%";
+ }
+
+ if ( typeof container.style.zoom !== "undefined" ) {
+ container.style.zoom = 1;
+ }
+
+ body.removeChild( container );
+ marginDiv = div = container = null;
+
+ jQuery.extend( support, offsetSupport );
+ });
+
+ return support;
+})();
+
+
+
+
+var rbrace = /^(?:\{.*\}|\[.*\])$/,
+ rmultiDash = /([A-Z])/g;
+
+jQuery.extend({
+ cache: {},
+
+ // Please use with caution
+ uuid: 0,
+
+ // Unique for each copy of jQuery on the page
+ // Non-digits removed to match rinlinejQuery
+ expando: "jQuery" + ( jQuery.fn.jquery + Math.random() ).replace( /\D/g, "" ),
+
+ // The following elements throw uncatchable exceptions if you
+ // attempt to add expando properties to them.
+ noData: {
+ "embed": true,
+ // Ban all objects except for Flash (which handle expandos)
+ "object": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",
+ "applet": true
+ },
+
+ hasData: function( elem ) {
+ elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];
+ return !!elem && !isEmptyDataObject( elem );
+ },
+
+ data: function( elem, name, data, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var privateCache, thisCache, ret,
+ internalKey = jQuery.expando,
+ getByName = typeof name === "string",
+
+ // We have to handle DOM nodes and JS objects differently because IE6-7
+ // can't GC object references properly across the DOM-JS boundary
+ isNode = elem.nodeType,
+
+ // Only DOM nodes need the global jQuery cache; JS object data is
+ // attached directly to the object so GC can occur automatically
+ cache = isNode ? jQuery.cache : elem,
+
+ // Only defining an ID for JS objects if its cache already exists allows
+ // the code to shortcut on the same path as a DOM node with no cache
+ id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
+ isEvents = name === "events";
+
+ // Avoid doing any more work than we need to when trying to get data on an
+ // object that has no data at all
+ if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
+ return;
+ }
+
+ if ( !id ) {
+ // Only DOM nodes need a new unique ID for each element since their data
+ // ends up in the global cache
+ if ( isNode ) {
+ elem[ internalKey ] = id = ++jQuery.uuid;
+ } else {
+ id = internalKey;
+ }
+ }
+
+ if ( !cache[ id ] ) {
+ cache[ id ] = {};
+
+ // Avoids exposing jQuery metadata on plain JS objects when the object
+ // is serialized using JSON.stringify
+ if ( !isNode ) {
+ cache[ id ].toJSON = jQuery.noop;
+ }
+ }
+
+ // An object can be passed to jQuery.data instead of a key/value pair; this gets
+ // shallow copied over onto the existing cache
+ if ( typeof name === "object" || typeof name === "function" ) {
+ if ( pvt ) {
+ cache[ id ] = jQuery.extend( cache[ id ], name );
+ } else {
+ cache[ id ].data = jQuery.extend( cache[ id ].data, name );
+ }
+ }
+
+ privateCache = thisCache = cache[ id ];
+
+ // jQuery data() is stored in a separate object inside the object's internal data
+ // cache in order to avoid key collisions between internal data and user-defined
+ // data.
+ if ( !pvt ) {
+ if ( !thisCache.data ) {
+ thisCache.data = {};
+ }
+
+ thisCache = thisCache.data;
+ }
+
+ if ( data !== undefined ) {
+ thisCache[ jQuery.camelCase( name ) ] = data;
+ }
+
+ // Users should not attempt to inspect the internal events object using jQuery.data,
+ // it is undocumented and subject to change. But does anyone listen? No.
+ if ( isEvents && !thisCache[ name ] ) {
+ return privateCache.events;
+ }
+
+ // Check for both converted-to-camel and non-converted data property names
+ // If a data property was specified
+ if ( getByName ) {
+
+ // First Try to find as-is property data
+ ret = thisCache[ name ];
+
+ // Test for null|undefined property data
+ if ( ret == null ) {
+
+ // Try to find the camelCased property
+ ret = thisCache[ jQuery.camelCase( name ) ];
+ }
+ } else {
+ ret = thisCache;
+ }
+
+ return ret;
+ },
+
+ removeData: function( elem, name, pvt /* Internal Use Only */ ) {
+ if ( !jQuery.acceptData( elem ) ) {
+ return;
+ }
+
+ var thisCache, i, l,
+
+ // Reference to internal data cache key
+ internalKey = jQuery.expando,
+
+ isNode = elem.nodeType,
+
+ // See jQuery.data for more information
+ cache = isNode ? jQuery.cache : elem,
+
+ // See jQuery.data for more information
+ id = isNode ? elem[ internalKey ] : internalKey;
+
+ // If there is already no cache entry for this object, there is no
+ // purpose in continuing
+ if ( !cache[ id ] ) {
+ return;
+ }
+
+ if ( name ) {
+
+ thisCache = pvt ? cache[ id ] : cache[ id ].data;
+
+ if ( thisCache ) {
+
+ // Support array or space separated string names for data keys
+ if ( !jQuery.isArray( name ) ) {
+
+ // try the string as a key before any manipulation
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+
+ // split the camel cased version by spaces unless a key with the spaces exists
+ name = jQuery.camelCase( name );
+ if ( name in thisCache ) {
+ name = [ name ];
+ } else {
+ name = name.split( " " );
+ }
+ }
+ }
+
+ for ( i = 0, l = name.length; i < l; i++ ) {
+ delete thisCache[ name[i] ];
+ }
+
+ // If there is no data left in the cache, we want to continue
+ // and let the cache object itself get destroyed
+ if ( !( pvt ? isEmptyDataObject : jQuery.isEmptyObject )( thisCache ) ) {
+ return;
+ }
+ }
+ }
+
+ // See jQuery.data for more information
+ if ( !pvt ) {
+ delete cache[ id ].data;
+
+ // Don't destroy the parent cache unless the internal data object
+ // had been the only thing left in it
+ if ( !isEmptyDataObject(cache[ id ]) ) {
+ return;
+ }
+ }
+
+ // Browsers that fail expando deletion also refuse to delete expandos on
+ // the window, but it will allow it on all other JS objects; other browsers
+ // don't care
+ // Ensure that `cache` is not a window object #10080
+ if ( jQuery.support.deleteExpando || !cache.setInterval ) {
+ delete cache[ id ];
+ } else {
+ cache[ id ] = null;
+ }
+
+ // We destroyed the cache and need to eliminate the expando on the node to avoid
+ // false lookups in the cache for entries that no longer exist
+ if ( isNode ) {
+ // IE does not allow us to delete expando properties from nodes,
+ // nor does it have a removeAttribute function on Document nodes;
+ // we must handle all of these cases
+ if ( jQuery.support.deleteExpando ) {
+ delete elem[ internalKey ];
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( internalKey );
+ } else {
+ elem[ internalKey ] = null;
+ }
+ }
+ },
+
+ // For internal use only.
+ _data: function( elem, name, data ) {
+ return jQuery.data( elem, name, data, true );
+ },
+
+ // A method for determining if a DOM node can handle the data expando
+ acceptData: function( elem ) {
+ if ( elem.nodeName ) {
+ var match = jQuery.noData[ elem.nodeName.toLowerCase() ];
+
+ if ( match ) {
+ return !(match === true || elem.getAttribute("classid") !== match);
+ }
+ }
+
+ return true;
+ }
+});
+
+jQuery.fn.extend({
+ data: function( key, value ) {
+ var parts, part, attr, name, l,
+ elem = this[0],
+ i = 0,
+ data = null;
+
+ // Gets all values
+ if ( key === undefined ) {
+ if ( this.length ) {
+ data = jQuery.data( elem );
+
+ if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) {
+ attr = elem.attributes;
+ for ( l = attr.length; i < l; i++ ) {
+ name = attr[i].name;
+
+ if ( name.indexOf( "data-" ) === 0 ) {
+ name = jQuery.camelCase( name.substring(5) );
+
+ dataAttr( elem, name, data[ name ] );
+ }
+ }
+ jQuery._data( elem, "parsedAttrs", true );
+ }
+ }
+
+ return data;
+ }
+
+ // Sets multiple values
+ if ( typeof key === "object" ) {
+ return this.each(function() {
+ jQuery.data( this, key );
+ });
+ }
+
+ parts = key.split( ".", 2 );
+ parts[1] = parts[1] ? "." + parts[1] : "";
+ part = parts[1] + "!";
+
+ return jQuery.access( this, function( value ) {
+
+ if ( value === undefined ) {
+ data = this.triggerHandler( "getData" + part, [ parts[0] ] );
+
+ // Try to fetch any internally stored data first
+ if ( data === undefined && elem ) {
+ data = jQuery.data( elem, key );
+ data = dataAttr( elem, key, data );
+ }
+
+ return data === undefined && parts[1] ?
+ this.data( parts[0] ) :
+ data;
+ }
+
+ parts[1] = value;
+ this.each(function() {
+ var self = jQuery( this );
+
+ self.triggerHandler( "setData" + part, parts );
+ jQuery.data( this, key, value );
+ self.triggerHandler( "changeData" + part, parts );
+ });
+ }, null, value, arguments.length > 1, null, false );
+ },
+
+ removeData: function( key ) {
+ return this.each(function() {
+ jQuery.removeData( this, key );
+ });
+ }
+});
+
+function dataAttr( elem, key, data ) {
+ // If nothing was found internally, try to fetch any
+ // data from the HTML5 data-* attribute
+ if ( data === undefined && elem.nodeType === 1 ) {
+
+ var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
+
+ data = elem.getAttribute( name );
+
+ if ( typeof data === "string" ) {
+ try {
+ data = data === "true" ? true :
+ data === "false" ? false :
+ data === "null" ? null :
+ jQuery.isNumeric( data ) ? +data :
+ rbrace.test( data ) ? jQuery.parseJSON( data ) :
+ data;
+ } catch( e ) {}
+
+ // Make sure we set the data so it isn't changed later
+ jQuery.data( elem, key, data );
+
+ } else {
+ data = undefined;
+ }
+ }
+
+ return data;
+}
+
+// checks a cache object for emptiness
+function isEmptyDataObject( obj ) {
+ for ( var name in obj ) {
+
+ // if the public data object is empty, the private is still empty
+ if ( name === "data" && jQuery.isEmptyObject( obj[name] ) ) {
+ continue;
+ }
+ if ( name !== "toJSON" ) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+function handleQueueMarkDefer( elem, type, src ) {
+ var deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ defer = jQuery._data( elem, deferDataKey );
+ if ( defer &&
+ ( src === "queue" || !jQuery._data(elem, queueDataKey) ) &&
+ ( src === "mark" || !jQuery._data(elem, markDataKey) ) ) {
+ // Give room for hard-coded callbacks to fire first
+ // and eventually mark/queue something else on the element
+ setTimeout( function() {
+ if ( !jQuery._data( elem, queueDataKey ) &&
+ !jQuery._data( elem, markDataKey ) ) {
+ jQuery.removeData( elem, deferDataKey, true );
+ defer.fire();
+ }
+ }, 0 );
+ }
+}
+
+jQuery.extend({
+
+ _mark: function( elem, type ) {
+ if ( elem ) {
+ type = ( type || "fx" ) + "mark";
+ jQuery._data( elem, type, (jQuery._data( elem, type ) || 0) + 1 );
+ }
+ },
+
+ _unmark: function( force, elem, type ) {
+ if ( force !== true ) {
+ type = elem;
+ elem = force;
+ force = false;
+ }
+ if ( elem ) {
+ type = type || "fx";
+ var key = type + "mark",
+ count = force ? 0 : ( (jQuery._data( elem, key ) || 1) - 1 );
+ if ( count ) {
+ jQuery._data( elem, key, count );
+ } else {
+ jQuery.removeData( elem, key, true );
+ handleQueueMarkDefer( elem, type, "mark" );
+ }
+ }
+ },
+
+ queue: function( elem, type, data ) {
+ var q;
+ if ( elem ) {
+ type = ( type || "fx" ) + "queue";
+ q = jQuery._data( elem, type );
+
+ // Speed up dequeue by getting out quickly if this is just a lookup
+ if ( data ) {
+ if ( !q || jQuery.isArray(data) ) {
+ q = jQuery._data( elem, type, jQuery.makeArray(data) );
+ } else {
+ q.push( data );
+ }
+ }
+ return q || [];
+ }
+ },
+
+ dequeue: function( elem, type ) {
+ type = type || "fx";
+
+ var queue = jQuery.queue( elem, type ),
+ fn = queue.shift(),
+ hooks = {};
+
+ // If the fx queue is dequeued, always remove the progress sentinel
+ if ( fn === "inprogress" ) {
+ fn = queue.shift();
+ }
+
+ if ( fn ) {
+ // Add a progress sentinel to prevent the fx queue from being
+ // automatically dequeued
+ if ( type === "fx" ) {
+ queue.unshift( "inprogress" );
+ }
+
+ jQuery._data( elem, type + ".run", hooks );
+ fn.call( elem, function() {
+ jQuery.dequeue( elem, type );
+ }, hooks );
+ }
+
+ if ( !queue.length ) {
+ jQuery.removeData( elem, type + "queue " + type + ".run", true );
+ handleQueueMarkDefer( elem, type, "queue" );
+ }
+ }
+});
+
+jQuery.fn.extend({
+ queue: function( type, data ) {
+ var setter = 2;
+
+ if ( typeof type !== "string" ) {
+ data = type;
+ type = "fx";
+ setter--;
+ }
+
+ if ( arguments.length < setter ) {
+ return jQuery.queue( this[0], type );
+ }
+
+ return data === undefined ?
+ this :
+ this.each(function() {
+ var queue = jQuery.queue( this, type, data );
+
+ if ( type === "fx" && queue[0] !== "inprogress" ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ },
+ dequeue: function( type ) {
+ return this.each(function() {
+ jQuery.dequeue( this, type );
+ });
+ },
+ // Based off of the plugin by Clint Helfers, with permission.
+ // http://blindsignals.com/index.php/2009/07/jquery-delay/
+ delay: function( time, type ) {
+ time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
+ type = type || "fx";
+
+ return this.queue( type, function( next, hooks ) {
+ var timeout = setTimeout( next, time );
+ hooks.stop = function() {
+ clearTimeout( timeout );
+ };
+ });
+ },
+ clearQueue: function( type ) {
+ return this.queue( type || "fx", [] );
+ },
+ // Get a promise resolved when queues of a certain type
+ // are emptied (fx is the type by default)
+ promise: function( type, object ) {
+ if ( typeof type !== "string" ) {
+ object = type;
+ type = undefined;
+ }
+ type = type || "fx";
+ var defer = jQuery.Deferred(),
+ elements = this,
+ i = elements.length,
+ count = 1,
+ deferDataKey = type + "defer",
+ queueDataKey = type + "queue",
+ markDataKey = type + "mark",
+ tmp;
+ function resolve() {
+ if ( !( --count ) ) {
+ defer.resolveWith( elements, [ elements ] );
+ }
+ }
+ while( i-- ) {
+ if (( tmp = jQuery.data( elements[ i ], deferDataKey, undefined, true ) ||
+ ( jQuery.data( elements[ i ], queueDataKey, undefined, true ) ||
+ jQuery.data( elements[ i ], markDataKey, undefined, true ) ) &&
+ jQuery.data( elements[ i ], deferDataKey, jQuery.Callbacks( "once memory" ), true ) )) {
+ count++;
+ tmp.add( resolve );
+ }
+ }
+ resolve();
+ return defer.promise( object );
+ }
+});
+
+
+
+
+var rclass = /[\n\t\r]/g,
+ rspace = /\s+/,
+ rreturn = /\r/g,
+ rtype = /^(?:button|input)$/i,
+ rfocusable = /^(?:button|input|object|select|textarea)$/i,
+ rclickable = /^a(?:rea)?$/i,
+ rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
+ getSetAttribute = jQuery.support.getSetAttribute,
+ nodeHook, boolHook, fixSpecified;
+
+jQuery.fn.extend({
+ attr: function( name, value ) {
+ return jQuery.access( this, jQuery.attr, name, value, arguments.length > 1 );
+ },
+
+ removeAttr: function( name ) {
+ return this.each(function() {
+ jQuery.removeAttr( this, name );
+ });
+ },
+
+ prop: function( name, value ) {
+ return jQuery.access( this, jQuery.prop, name, value, arguments.length > 1 );
+ },
+
+ removeProp: function( name ) {
+ name = jQuery.propFix[ name ] || name;
+ return this.each(function() {
+ // try/catch handles cases where IE balks (such as removing a property on window)
+ try {
+ this[ name ] = undefined;
+ delete this[ name ];
+ } catch( e ) {}
+ });
+ },
+
+ addClass: function( value ) {
+ var classNames, i, l, elem,
+ setClass, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).addClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( value && typeof value === "string" ) {
+ classNames = value.split( rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 ) {
+ if ( !elem.className && classNames.length === 1 ) {
+ elem.className = value;
+
+ } else {
+ setClass = " " + elem.className + " ";
+
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {
+ setClass += classNames[ c ] + " ";
+ }
+ }
+ elem.className = jQuery.trim( setClass );
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ removeClass: function( value ) {
+ var classNames, i, l, elem, className, c, cl;
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( j ) {
+ jQuery( this ).removeClass( value.call(this, j, this.className) );
+ });
+ }
+
+ if ( (value && typeof value === "string") || value === undefined ) {
+ classNames = ( value || "" ).split( rspace );
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.nodeType === 1 && elem.className ) {
+ if ( value ) {
+ className = (" " + elem.className + " ").replace( rclass, " " );
+ for ( c = 0, cl = classNames.length; c < cl; c++ ) {
+ className = className.replace(" " + classNames[ c ] + " ", " ");
+ }
+ elem.className = jQuery.trim( className );
+
+ } else {
+ elem.className = "";
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ toggleClass: function( value, stateVal ) {
+ var type = typeof value,
+ isBool = typeof stateVal === "boolean";
+
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function( i ) {
+ jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
+ });
+ }
+
+ return this.each(function() {
+ if ( type === "string" ) {
+ // toggle individual class names
+ var className,
+ i = 0,
+ self = jQuery( this ),
+ state = stateVal,
+ classNames = value.split( rspace );
+
+ while ( (className = classNames[ i++ ]) ) {
+ // check each className given, space seperated list
+ state = isBool ? state : !self.hasClass( className );
+ self[ state ? "addClass" : "removeClass" ]( className );
+ }
+
+ } else if ( type === "undefined" || type === "boolean" ) {
+ if ( this.className ) {
+ // store className if set
+ jQuery._data( this, "__className__", this.className );
+ }
+
+ // toggle whole className
+ this.className = this.className || value === false ? "" : jQuery._data( this, "__className__" ) || "";
+ }
+ });
+ },
+
+ hasClass: function( selector ) {
+ var className = " " + selector + " ",
+ i = 0,
+ l = this.length;
+ for ( ; i < l; i++ ) {
+ if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
+ return true;
+ }
+ }
+
+ return false;
+ },
+
+ val: function( value ) {
+ var hooks, ret, isFunction,
+ elem = this[0];
+
+ if ( !arguments.length ) {
+ if ( elem ) {
+ hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
+
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
+ return ret;
+ }
+
+ ret = elem.value;
+
+ return typeof ret === "string" ?
+ // handle most common string cases
+ ret.replace(rreturn, "") :
+ // handle cases where value is null/undef or number
+ ret == null ? "" : ret;
+ }
+
+ return;
+ }
+
+ isFunction = jQuery.isFunction( value );
+
+ return this.each(function( i ) {
+ var self = jQuery(this), val;
+
+ if ( this.nodeType !== 1 ) {
+ return;
+ }
+
+ if ( isFunction ) {
+ val = value.call( this, i, self.val() );
+ } else {
+ val = value;
+ }
+
+ // Treat null/undefined as ""; convert numbers to string
+ if ( val == null ) {
+ val = "";
+ } else if ( typeof val === "number" ) {
+ val += "";
+ } else if ( jQuery.isArray( val ) ) {
+ val = jQuery.map(val, function ( value ) {
+ return value == null ? "" : value + "";
+ });
+ }
+
+ hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
+
+ // If set returns undefined, fall back to normal setting
+ if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
+ this.value = val;
+ }
+ });
+ }
+});
+
+jQuery.extend({
+ valHooks: {
+ option: {
+ get: function( elem ) {
+ // attributes.value is undefined in Blackberry 4.7 but
+ // uses .value. See #6932
+ var val = elem.attributes.value;
+ return !val || val.specified ? elem.value : elem.text;
+ }
+ },
+ select: {
+ get: function( elem ) {
+ var value, i, max, option,
+ index = elem.selectedIndex,
+ values = [],
+ options = elem.options,
+ one = elem.type === "select-one";
+
+ // Nothing was selected
+ if ( index < 0 ) {
+ return null;
+ }
+
+ // Loop through all the selected options
+ i = one ? index : 0;
+ max = one ? index + 1 : options.length;
+ for ( ; i < max; i++ ) {
+ option = options[ i ];
+
+ // Don't return options that are disabled or in a disabled optgroup
+ if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute("disabled") === null) &&
+ (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" )) ) {
+
+ // Get the specific value for the option
+ value = jQuery( option ).val();
+
+ // We don't need an array for one selects
+ if ( one ) {
+ return value;
+ }
+
+ // Multi-Selects return an array
+ values.push( value );
+ }
+ }
+
+ // Fixes Bug #2551 -- select.val() broken in IE after form.reset()
+ if ( one && !values.length && options.length ) {
+ return jQuery( options[ index ] ).val();
+ }
+
+ return values;
+ },
+
+ set: function( elem, value ) {
+ var values = jQuery.makeArray( value );
+
+ jQuery(elem).find("option").each(function() {
+ this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
+ });
+
+ if ( !values.length ) {
+ elem.selectedIndex = -1;
+ }
+ return values;
+ }
+ }
+ },
+
+ attrFn: {
+ val: true,
+ css: true,
+ html: true,
+ text: true,
+ data: true,
+ width: true,
+ height: true,
+ offset: true
+ },
+
+ attr: function( elem, name, value, pass ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set attributes on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ if ( pass && name in jQuery.attrFn ) {
+ return jQuery( elem )[ name ]( value );
+ }
+
+ // Fallback to prop when attributes are not supported
+ if ( typeof elem.getAttribute === "undefined" ) {
+ return jQuery.prop( elem, name, value );
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ // All attributes are lowercase
+ // Grab necessary hook if one is defined
+ if ( notxml ) {
+ name = name.toLowerCase();
+ hooks = jQuery.attrHooks[ name ] || ( rboolean.test( name ) ? boolHook : nodeHook );
+ }
+
+ if ( value !== undefined ) {
+
+ if ( value === null ) {
+ jQuery.removeAttr( elem, name );
+ return;
+
+ } else if ( hooks && "set" in hooks && notxml && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ elem.setAttribute( name, "" + value );
+ return value;
+ }
+
+ } else if ( hooks && "get" in hooks && notxml && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+
+ ret = elem.getAttribute( name );
+
+ // Non-existent attributes return null, we normalize to undefined
+ return ret === null ?
+ undefined :
+ ret;
+ }
+ },
+
+ removeAttr: function( elem, value ) {
+ var propName, attrNames, name, l, isBool,
+ i = 0;
+
+ if ( value && elem.nodeType === 1 ) {
+ attrNames = value.toLowerCase().split( rspace );
+ l = attrNames.length;
+
+ for ( ; i < l; i++ ) {
+ name = attrNames[ i ];
+
+ if ( name ) {
+ propName = jQuery.propFix[ name ] || name;
+ isBool = rboolean.test( name );
+
+ // See #9699 for explanation of this approach (setting first, then removal)
+ // Do not do this for boolean attributes (see #10870)
+ if ( !isBool ) {
+ jQuery.attr( elem, name, "" );
+ }
+ elem.removeAttribute( getSetAttribute ? name : propName );
+
+ // Set corresponding property to false for boolean attributes
+ if ( isBool && propName in elem ) {
+ elem[ propName ] = false;
+ }
+ }
+ }
+ }
+ },
+
+ attrHooks: {
+ type: {
+ set: function( elem, value ) {
+ // We can't allow the type property to be changed (since it causes problems in IE)
+ if ( rtype.test( elem.nodeName ) && elem.parentNode ) {
+ jQuery.error( "type property can't be changed" );
+ } else if ( !jQuery.support.radioValue && value === "radio" && jQuery.nodeName(elem, "input") ) {
+ // Setting the type on a radio button after the value resets the value in IE6-9
+ // Reset value to it's default in case type is set after value
+ // This is for element creation
+ var val = elem.value;
+ elem.setAttribute( "type", value );
+ if ( val ) {
+ elem.value = val;
+ }
+ return value;
+ }
+ }
+ },
+ // Use the value property for back compat
+ // Use the nodeHook for button elements in IE6/7 (#1954)
+ value: {
+ get: function( elem, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.get( elem, name );
+ }
+ return name in elem ?
+ elem.value :
+ null;
+ },
+ set: function( elem, value, name ) {
+ if ( nodeHook && jQuery.nodeName( elem, "button" ) ) {
+ return nodeHook.set( elem, value, name );
+ }
+ // Does not return so that setAttribute is also used
+ elem.value = value;
+ }
+ }
+ },
+
+ propFix: {
+ tabindex: "tabIndex",
+ readonly: "readOnly",
+ "for": "htmlFor",
+ "class": "className",
+ maxlength: "maxLength",
+ cellspacing: "cellSpacing",
+ cellpadding: "cellPadding",
+ rowspan: "rowSpan",
+ colspan: "colSpan",
+ usemap: "useMap",
+ frameborder: "frameBorder",
+ contenteditable: "contentEditable"
+ },
+
+ prop: function( elem, name, value ) {
+ var ret, hooks, notxml,
+ nType = elem.nodeType;
+
+ // don't get/set properties on text, comment and attribute nodes
+ if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
+ return;
+ }
+
+ notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
+
+ if ( notxml ) {
+ // Fix name and attach hooks
+ name = jQuery.propFix[ name ] || name;
+ hooks = jQuery.propHooks[ name ];
+ }
+
+ if ( value !== undefined ) {
+ if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
+ return ret;
+
+ } else {
+ return ( elem[ name ] = value );
+ }
+
+ } else {
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
+ return ret;
+
+ } else {
+ return elem[ name ];
+ }
+ }
+ },
+
+ propHooks: {
+ tabIndex: {
+ get: function( elem ) {
+ // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
+ // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ var attributeNode = elem.getAttributeNode("tabindex");
+
+ return attributeNode && attributeNode.specified ?
+ parseInt( attributeNode.value, 10 ) :
+ rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
+ 0 :
+ undefined;
+ }
+ }
+ }
+});
+
+// Add the tabIndex propHook to attrHooks for back-compat (different case is intentional)
+jQuery.attrHooks.tabindex = jQuery.propHooks.tabIndex;
+
+// Hook for boolean attributes
+boolHook = {
+ get: function( elem, name ) {
+ // Align boolean attributes with corresponding properties
+ // Fall back to attribute presence where some booleans are not supported
+ var attrNode,
+ property = jQuery.prop( elem, name );
+ return property === true || typeof property !== "boolean" && ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
+ name.toLowerCase() :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ var propName;
+ if ( value === false ) {
+ // Remove boolean attributes when set to false
+ jQuery.removeAttr( elem, name );
+ } else {
+ // value is true since we know at this point it's type boolean and not false
+ // Set boolean attributes to the same name and set the DOM property
+ propName = jQuery.propFix[ name ] || name;
+ if ( propName in elem ) {
+ // Only set the IDL specifically if it already exists on the element
+ elem[ propName ] = true;
+ }
+
+ elem.setAttribute( name, name.toLowerCase() );
+ }
+ return name;
+ }
+};
+
+// IE6/7 do not support getting/setting some attributes with get/setAttribute
+if ( !getSetAttribute ) {
+
+ fixSpecified = {
+ name: true,
+ id: true,
+ coords: true
+ };
+
+ // Use this for any attribute in IE6/7
+ // This fixes almost every IE6/7 issue
+ nodeHook = jQuery.valHooks.button = {
+ get: function( elem, name ) {
+ var ret;
+ ret = elem.getAttributeNode( name );
+ return ret && ( fixSpecified[ name ] ? ret.nodeValue !== "" : ret.specified ) ?
+ ret.nodeValue :
+ undefined;
+ },
+ set: function( elem, value, name ) {
+ // Set the existing or create a new attribute node
+ var ret = elem.getAttributeNode( name );
+ if ( !ret ) {
+ ret = document.createAttribute( name );
+ elem.setAttributeNode( ret );
+ }
+ return ( ret.nodeValue = value + "" );
+ }
+ };
+
+ // Apply the nodeHook to tabindex
+ jQuery.attrHooks.tabindex.set = nodeHook.set;
+
+ // Set width and height to auto instead of 0 on empty string( Bug #8150 )
+ // This is for removals
+ jQuery.each([ "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ set: function( elem, value ) {
+ if ( value === "" ) {
+ elem.setAttribute( name, "auto" );
+ return value;
+ }
+ }
+ });
+ });
+
+ // Set contenteditable to false on removals(#10429)
+ // Setting to empty string throws an error as an invalid value
+ jQuery.attrHooks.contenteditable = {
+ get: nodeHook.get,
+ set: function( elem, value, name ) {
+ if ( value === "" ) {
+ value = "false";
+ }
+ nodeHook.set( elem, value, name );
+ }
+ };
+}
+
+
+// Some attributes require a special call on IE
+if ( !jQuery.support.hrefNormalized ) {
+ jQuery.each([ "href", "src", "width", "height" ], function( i, name ) {
+ jQuery.attrHooks[ name ] = jQuery.extend( jQuery.attrHooks[ name ], {
+ get: function( elem ) {
+ var ret = elem.getAttribute( name, 2 );
+ return ret === null ? undefined : ret;
+ }
+ });
+ });
+}
+
+if ( !jQuery.support.style ) {
+ jQuery.attrHooks.style = {
+ get: function( elem ) {
+ // Return undefined in the case of empty string
+ // Normalize to lowercase since IE uppercases css property names
+ return elem.style.cssText.toLowerCase() || undefined;
+ },
+ set: function( elem, value ) {
+ return ( elem.style.cssText = "" + value );
+ }
+ };
+}
+
+// Safari mis-reports the default selected property of an option
+// Accessing the parent's selectedIndex property fixes it
+if ( !jQuery.support.optSelected ) {
+ jQuery.propHooks.selected = jQuery.extend( jQuery.propHooks.selected, {
+ get: function( elem ) {
+ var parent = elem.parentNode;
+
+ if ( parent ) {
+ parent.selectedIndex;
+
+ // Make sure that it also works with optgroups, see #5701
+ if ( parent.parentNode ) {
+ parent.parentNode.selectedIndex;
+ }
+ }
+ return null;
+ }
+ });
+}
+
+// IE6/7 call enctype encoding
+if ( !jQuery.support.enctype ) {
+ jQuery.propFix.enctype = "encoding";
+}
+
+// Radios and checkboxes getter/setter
+if ( !jQuery.support.checkOn ) {
+ jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = {
+ get: function( elem ) {
+ // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
+ return elem.getAttribute("value") === null ? "on" : elem.value;
+ }
+ };
+ });
+}
+jQuery.each([ "radio", "checkbox" ], function() {
+ jQuery.valHooks[ this ] = jQuery.extend( jQuery.valHooks[ this ], {
+ set: function( elem, value ) {
+ if ( jQuery.isArray( value ) ) {
+ return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
+ }
+ }
+ });
+});
+
+
+
+
+var rformElems = /^(?:textarea|input|select)$/i,
+ rtypenamespace = /^([^\.]*)?(?:\.(.+))?$/,
+ rhoverHack = /(?:^|\s)hover(\.\S+)?\b/,
+ rkeyEvent = /^key/,
+ rmouseEvent = /^(?:mouse|contextmenu)|click/,
+ rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
+ rquickIs = /^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,
+ quickParse = function( selector ) {
+ var quick = rquickIs.exec( selector );
+ if ( quick ) {
+ // 0 1 2 3
+ // [ _, tag, id, class ]
+ quick[1] = ( quick[1] || "" ).toLowerCase();
+ quick[3] = quick[3] && new RegExp( "(?:^|\\s)" + quick[3] + "(?:\\s|$)" );
+ }
+ return quick;
+ },
+ quickIs = function( elem, m ) {
+ var attrs = elem.attributes || {};
+ return (
+ (!m[1] || elem.nodeName.toLowerCase() === m[1]) &&
+ (!m[2] || (attrs.id || {}).value === m[2]) &&
+ (!m[3] || m[3].test( (attrs[ "class" ] || {}).value ))
+ );
+ },
+ hoverHack = function( events ) {
+ return jQuery.event.special.hover ? events : events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
+ };
+
+/*
+ * Helper functions for managing events -- not part of the public interface.
+ * Props to Dean Edwards' addEvent library for many of the ideas.
+ */
+jQuery.event = {
+
+ add: function( elem, types, handler, data, selector ) {
+
+ var elemData, eventHandle, events,
+ t, tns, type, namespaces, handleObj,
+ handleObjIn, quick, handlers, special;
+
+ // Don't attach events to noData or text/comment nodes (allow plain objects tho)
+ if ( elem.nodeType === 3 || elem.nodeType === 8 || !types || !handler || !(elemData = jQuery._data( elem )) ) {
+ return;
+ }
+
+ // Caller can pass in an object of custom data in lieu of the handler
+ if ( handler.handler ) {
+ handleObjIn = handler;
+ handler = handleObjIn.handler;
+ selector = handleObjIn.selector;
+ }
+
+ // Make sure that the handler has a unique ID, used to find/remove it later
+ if ( !handler.guid ) {
+ handler.guid = jQuery.guid++;
+ }
+
+ // Init the element's event structure and main handler, if this is the first
+ events = elemData.events;
+ if ( !events ) {
+ elemData.events = events = {};
+ }
+ eventHandle = elemData.handle;
+ if ( !eventHandle ) {
+ elemData.handle = eventHandle = function( e ) {
+ // Discard the second event of a jQuery.event.trigger() and
+ // when an event is called after a page has unloaded
+ return typeof jQuery !== "undefined" && (!e || jQuery.event.triggered !== e.type) ?
+ jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
+ undefined;
+ };
+ // Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
+ eventHandle.elem = elem;
+ }
+
+ // Handle multiple events separated by a space
+ // jQuery(...).bind("mouseover mouseout", fn);
+ types = jQuery.trim( hoverHack(types) ).split( " " );
+ for ( t = 0; t < types.length; t++ ) {
+
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = tns[1];
+ namespaces = ( tns[2] || "" ).split( "." ).sort();
+
+ // If event changes its type, use the special event handlers for the changed type
+ special = jQuery.event.special[ type ] || {};
+
+ // If selector defined, determine special event api type, otherwise given type
+ type = ( selector ? special.delegateType : special.bindType ) || type;
+
+ // Update special based on newly reset type
+ special = jQuery.event.special[ type ] || {};
+
+ // handleObj is passed to all event handlers
+ handleObj = jQuery.extend({
+ type: type,
+ origType: tns[1],
+ data: data,
+ handler: handler,
+ guid: handler.guid,
+ selector: selector,
+ quick: selector && quickParse( selector ),
+ namespace: namespaces.join(".")
+ }, handleObjIn );
+
+ // Init the event handler queue if we're the first
+ handlers = events[ type ];
+ if ( !handlers ) {
+ handlers = events[ type ] = [];
+ handlers.delegateCount = 0;
+
+ // Only use addEventListener/attachEvent if the special events handler returns false
+ if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
+ // Bind the global event handler to the element
+ if ( elem.addEventListener ) {
+ elem.addEventListener( type, eventHandle, false );
+
+ } else if ( elem.attachEvent ) {
+ elem.attachEvent( "on" + type, eventHandle );
+ }
+ }
+ }
+
+ if ( special.add ) {
+ special.add.call( elem, handleObj );
+
+ if ( !handleObj.handler.guid ) {
+ handleObj.handler.guid = handler.guid;
+ }
+ }
+
+ // Add to the element's handler list, delegates in front
+ if ( selector ) {
+ handlers.splice( handlers.delegateCount++, 0, handleObj );
+ } else {
+ handlers.push( handleObj );
+ }
+
+ // Keep track of which events have ever been used, for event optimization
+ jQuery.event.global[ type ] = true;
+ }
+
+ // Nullify elem to prevent memory leaks in IE
+ elem = null;
+ },
+
+ global: {},
+
+ // Detach an event or set of events from an element
+ remove: function( elem, types, handler, selector, mappedTypes ) {
+
+ var elemData = jQuery.hasData( elem ) && jQuery._data( elem ),
+ t, tns, type, origType, namespaces, origCount,
+ j, events, special, handle, eventType, handleObj;
+
+ if ( !elemData || !(events = elemData.events) ) {
+ return;
+ }
+
+ // Once for each type.namespace in types; type may be omitted
+ types = jQuery.trim( hoverHack( types || "" ) ).split(" ");
+ for ( t = 0; t < types.length; t++ ) {
+ tns = rtypenamespace.exec( types[t] ) || [];
+ type = origType = tns[1];
+ namespaces = tns[2];
+
+ // Unbind all events (on this namespace, if provided) for the element
+ if ( !type ) {
+ for ( type in events ) {
+ jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
+ }
+ continue;
+ }
+
+ special = jQuery.event.special[ type ] || {};
+ type = ( selector? special.delegateType : special.bindType ) || type;
+ eventType = events[ type ] || [];
+ origCount = eventType.length;
+ namespaces = namespaces ? new RegExp("(^|\\.)" + namespaces.split(".").sort().join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+
+ // Remove matching events
+ for ( j = 0; j < eventType.length; j++ ) {
+ handleObj = eventType[ j ];
+
+ if ( ( mappedTypes || origType === handleObj.origType ) &&
+ ( !handler || handler.guid === handleObj.guid ) &&
+ ( !namespaces || namespaces.test( handleObj.namespace ) ) &&
+ ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
+ eventType.splice( j--, 1 );
+
+ if ( handleObj.selector ) {
+ eventType.delegateCount--;
+ }
+ if ( special.remove ) {
+ special.remove.call( elem, handleObj );
+ }
+ }
+ }
+
+ // Remove generic event handler if we removed something and no more handlers exist
+ // (avoids potential for endless recursion during removal of special event handlers)
+ if ( eventType.length === 0 && origCount !== eventType.length ) {
+ if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
+ jQuery.removeEvent( elem, type, elemData.handle );
+ }
+
+ delete events[ type ];
+ }
+ }
+
+ // Remove the expando if it's no longer used
+ if ( jQuery.isEmptyObject( events ) ) {
+ handle = elemData.handle;
+ if ( handle ) {
+ handle.elem = null;
+ }
+
+ // removeData also checks for emptiness and clears the expando if empty
+ // so use it instead of delete
+ jQuery.removeData( elem, [ "events", "handle" ], true );
+ }
+ },
+
+ // Events that are safe to short-circuit if no handlers are attached.
+ // Native DOM events should not be added, they may have inline handlers.
+ customEvent: {
+ "getData": true,
+ "setData": true,
+ "changeData": true
+ },
+
+ trigger: function( event, data, elem, onlyHandlers ) {
+ // Don't do events on text and comment nodes
+ if ( elem && (elem.nodeType === 3 || elem.nodeType === 8) ) {
+ return;
+ }
+
+ // Event object or event type
+ var type = event.type || event,
+ namespaces = [],
+ cache, exclusive, i, cur, old, ontype, special, handle, eventPath, bubbleType;
+
+ // focus/blur morphs to focusin/out; ensure we're not firing them right now
+ if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
+ return;
+ }
+
+ if ( type.indexOf( "!" ) >= 0 ) {
+ // Exclusive events trigger only for the exact event (no namespaces)
+ type = type.slice(0, -1);
+ exclusive = true;
+ }
+
+ if ( type.indexOf( "." ) >= 0 ) {
+ // Namespaced trigger; create a regexp to match event type in handle()
+ namespaces = type.split(".");
+ type = namespaces.shift();
+ namespaces.sort();
+ }
+
+ if ( (!elem || jQuery.event.customEvent[ type ]) && !jQuery.event.global[ type ] ) {
+ // No jQuery handlers for this event type, and it can't have inline handlers
+ return;
+ }
+
+ // Caller can pass in an Event, Object, or just an event type string
+ event = typeof event === "object" ?
+ // jQuery.Event object
+ event[ jQuery.expando ] ? event :
+ // Object literal
+ new jQuery.Event( type, event ) :
+ // Just the event type (string)
+ new jQuery.Event( type );
+
+ event.type = type;
+ event.isTrigger = true;
+ event.exclusive = exclusive;
+ event.namespace = namespaces.join( "." );
+ event.namespace_re = event.namespace? new RegExp("(^|\\.)" + namespaces.join("\\.(?:.*\\.)?") + "(\\.|$)") : null;
+ ontype = type.indexOf( ":" ) < 0 ? "on" + type : "";
+
+ // Handle a global trigger
+ if ( !elem ) {
+
+ // TODO: Stop taunting the data cache; remove global events and always attach to document
+ cache = jQuery.cache;
+ for ( i in cache ) {
+ if ( cache[ i ].events && cache[ i ].events[ type ] ) {
+ jQuery.event.trigger( event, data, cache[ i ].handle.elem, true );
+ }
+ }
+ return;
+ }
+
+ // Clean up the event in case it is being reused
+ event.result = undefined;
+ if ( !event.target ) {
+ event.target = elem;
+ }
+
+ // Clone any incoming data and prepend the event, creating the handler arg list
+ data = data != null ? jQuery.makeArray( data ) : [];
+ data.unshift( event );
+
+ // Allow special events to draw outside the lines
+ special = jQuery.event.special[ type ] || {};
+ if ( special.trigger && special.trigger.apply( elem, data ) === false ) {
+ return;
+ }
+
+ // Determine event propagation path in advance, per W3C events spec (#9951)
+ // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
+ eventPath = [[ elem, special.bindType || type ]];
+ if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
+
+ bubbleType = special.delegateType || type;
+ cur = rfocusMorph.test( bubbleType + type ) ? elem : elem.parentNode;
+ old = null;
+ for ( ; cur; cur = cur.parentNode ) {
+ eventPath.push([ cur, bubbleType ]);
+ old = cur;
+ }
+
+ // Only add window if we got to document (e.g., not plain obj or detached DOM)
+ if ( old && old === elem.ownerDocument ) {
+ eventPath.push([ old.defaultView || old.parentWindow || window, bubbleType ]);
+ }
+ }
+
+ // Fire handlers on the event path
+ for ( i = 0; i < eventPath.length && !event.isPropagationStopped(); i++ ) {
+
+ cur = eventPath[i][0];
+ event.type = eventPath[i][1];
+
+ handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
+ if ( handle ) {
+ handle.apply( cur, data );
+ }
+ // Note that this is a bare JS function and not a jQuery handler
+ handle = ontype && cur[ ontype ];
+ if ( handle && jQuery.acceptData( cur ) && handle.apply( cur, data ) === false ) {
+ event.preventDefault();
+ }
+ }
+ event.type = type;
+
+ // If nobody prevented the default action, do it now
+ if ( !onlyHandlers && !event.isDefaultPrevented() ) {
+
+ if ( (!special._default || special._default.apply( elem.ownerDocument, data ) === false) &&
+ !(type === "click" && jQuery.nodeName( elem, "a" )) && jQuery.acceptData( elem ) ) {
+
+ // Call a native DOM method on the target with the same name name as the event.
+ // Can't use an .isFunction() check here because IE6/7 fails that test.
+ // Don't do default actions on window, that's where global variables be (#6170)
+ // IE<9 dies on focus/blur to hidden element (#1486)
+ if ( ontype && elem[ type ] && ((type !== "focus" && type !== "blur") || event.target.offsetWidth !== 0) && !jQuery.isWindow( elem ) ) {
+
+ // Don't re-trigger an onFOO event when we call its FOO() method
+ old = elem[ ontype ];
+
+ if ( old ) {
+ elem[ ontype ] = null;
+ }
+
+ // Prevent re-triggering of the same event, since we already bubbled it above
+ jQuery.event.triggered = type;
+ elem[ type ]();
+ jQuery.event.triggered = undefined;
+
+ if ( old ) {
+ elem[ ontype ] = old;
+ }
+ }
+ }
+ }
+
+ return event.result;
+ },
+
+ dispatch: function( event ) {
+
+ // Make a writable jQuery.Event from the native event object
+ event = jQuery.event.fix( event || window.event );
+
+ var handlers = ( (jQuery._data( this, "events" ) || {} )[ event.type ] || []),
+ delegateCount = handlers.delegateCount,
+ args = [].slice.call( arguments, 0 ),
+ run_all = !event.exclusive && !event.namespace,
+ special = jQuery.event.special[ event.type ] || {},
+ handlerQueue = [],
+ i, j, cur, jqcur, ret, selMatch, matched, matches, handleObj, sel, related;
+
+ // Use the fix-ed jQuery.Event rather than the (read-only) native event
+ args[0] = event;
+ event.delegateTarget = this;
+
+ // Call the preDispatch hook for the mapped type, and let it bail if desired
+ if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
+ return;
+ }
+
+ // Determine handlers that should run if there are delegated events
+ // Avoid non-left-click bubbling in Firefox (#3861)
+ if ( delegateCount && !(event.button && event.type === "click") ) {
+
+ // Pregenerate a single jQuery object for reuse with .is()
+ jqcur = jQuery(this);
+ jqcur.context = this.ownerDocument || this;
+
+ for ( cur = event.target; cur != this; cur = cur.parentNode || this ) {
+
+ // Don't process events on disabled elements (#6911, #8165)
+ if ( cur.disabled !== true ) {
+ selMatch = {};
+ matches = [];
+ jqcur[0] = cur;
+ for ( i = 0; i < delegateCount; i++ ) {
+ handleObj = handlers[ i ];
+ sel = handleObj.selector;
+
+ if ( selMatch[ sel ] === undefined ) {
+ selMatch[ sel ] = (
+ handleObj.quick ? quickIs( cur, handleObj.quick ) : jqcur.is( sel )
+ );
+ }
+ if ( selMatch[ sel ] ) {
+ matches.push( handleObj );
+ }
+ }
+ if ( matches.length ) {
+ handlerQueue.push({ elem: cur, matches: matches });
+ }
+ }
+ }
+ }
+
+ // Add the remaining (directly-bound) handlers
+ if ( handlers.length > delegateCount ) {
+ handlerQueue.push({ elem: this, matches: handlers.slice( delegateCount ) });
+ }
+
+ // Run delegates first; they may want to stop propagation beneath us
+ for ( i = 0; i < handlerQueue.length && !event.isPropagationStopped(); i++ ) {
+ matched = handlerQueue[ i ];
+ event.currentTarget = matched.elem;
+
+ for ( j = 0; j < matched.matches.length && !event.isImmediatePropagationStopped(); j++ ) {
+ handleObj = matched.matches[ j ];
+
+ // Triggered event must either 1) be non-exclusive and have no namespace, or
+ // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
+ if ( run_all || (!event.namespace && !handleObj.namespace) || event.namespace_re && event.namespace_re.test( handleObj.namespace ) ) {
+
+ event.data = handleObj.data;
+ event.handleObj = handleObj;
+
+ ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
+ .apply( matched.elem, args );
+
+ if ( ret !== undefined ) {
+ event.result = ret;
+ if ( ret === false ) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ }
+ }
+ }
+ }
+
+ // Call the postDispatch hook for the mapped type
+ if ( special.postDispatch ) {
+ special.postDispatch.call( this, event );
+ }
+
+ return event.result;
+ },
+
+ // Includes some event props shared by KeyEvent and MouseEvent
+ // *** attrChange attrName relatedNode srcElement are not normalized, non-W3C, deprecated, will be removed in 1.8 ***
+ props: "attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
+
+ fixHooks: {},
+
+ keyHooks: {
+ props: "char charCode key keyCode".split(" "),
+ filter: function( event, original ) {
+
+ // Add which for key events
+ if ( event.which == null ) {
+ event.which = original.charCode != null ? original.charCode : original.keyCode;
+ }
+
+ return event;
+ }
+ },
+
+ mouseHooks: {
+ props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
+ filter: function( event, original ) {
+ var eventDoc, doc, body,
+ button = original.button,
+ fromElement = original.fromElement;
+
+ // Calculate pageX/Y if missing and clientX/Y available
+ if ( event.pageX == null && original.clientX != null ) {
+ eventDoc = event.target.ownerDocument || document;
+ doc = eventDoc.documentElement;
+ body = eventDoc.body;
+
+ event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
+ event.pageY = original.clientY + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - ( doc && doc.clientTop || body && body.clientTop || 0 );
+ }
+
+ // Add relatedTarget, if necessary
+ if ( !event.relatedTarget && fromElement ) {
+ event.relatedTarget = fromElement === event.target ? original.toElement : fromElement;
+ }
+
+ // Add which for click: 1 === left; 2 === middle; 3 === right
+ // Note: button is not normalized, so don't use it
+ if ( !event.which && button !== undefined ) {
+ event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
+ }
+
+ return event;
+ }
+ },
+
+ fix: function( event ) {
+ if ( event[ jQuery.expando ] ) {
+ return event;
+ }
+
+ // Create a writable copy of the event object and normalize some properties
+ var i, prop,
+ originalEvent = event,
+ fixHook = jQuery.event.fixHooks[ event.type ] || {},
+ copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
+
+ event = jQuery.Event( originalEvent );
+
+ for ( i = copy.length; i; ) {
+ prop = copy[ --i ];
+ event[ prop ] = originalEvent[ prop ];
+ }
+
+ // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
+ if ( !event.target ) {
+ event.target = originalEvent.srcElement || document;
+ }
+
+ // Target should not be a text node (#504, Safari)
+ if ( event.target.nodeType === 3 ) {
+ event.target = event.target.parentNode;
+ }
+
+ // For mouse/key events; add metaKey if it's not there (#3368, IE6/7/8)
+ if ( event.metaKey === undefined ) {
+ event.metaKey = event.ctrlKey;
+ }
+
+ return fixHook.filter? fixHook.filter( event, originalEvent ) : event;
+ },
+
+ special: {
+ ready: {
+ // Make sure the ready event is setup
+ setup: jQuery.bindReady
+ },
+
+ load: {
+ // Prevent triggered image.load events from bubbling to window.load
+ noBubble: true
+ },
+
+ focus: {
+ delegateType: "focusin"
+ },
+ blur: {
+ delegateType: "focusout"
+ },
+
+ beforeunload: {
+ setup: function( data, namespaces, eventHandle ) {
+ // We only want to do this special case on windows
+ if ( jQuery.isWindow( this ) ) {
+ this.onbeforeunload = eventHandle;
+ }
+ },
+
+ teardown: function( namespaces, eventHandle ) {
+ if ( this.onbeforeunload === eventHandle ) {
+ this.onbeforeunload = null;
+ }
+ }
+ }
+ },
+
+ simulate: function( type, elem, event, bubble ) {
+ // Piggyback on a donor event to simulate a different one.
+ // Fake originalEvent to avoid donor's stopPropagation, but if the
+ // simulated event prevents default then we do the same on the donor.
+ var e = jQuery.extend(
+ new jQuery.Event(),
+ event,
+ { type: type,
+ isSimulated: true,
+ originalEvent: {}
+ }
+ );
+ if ( bubble ) {
+ jQuery.event.trigger( e, null, elem );
+ } else {
+ jQuery.event.dispatch.call( elem, e );
+ }
+ if ( e.isDefaultPrevented() ) {
+ event.preventDefault();
+ }
+ }
+};
+
+// Some plugins are using, but it's undocumented/deprecated and will be removed.
+// The 1.7 special event interface should provide all the hooks needed now.
+jQuery.event.handle = jQuery.event.dispatch;
+
+jQuery.removeEvent = document.removeEventListener ?
+ function( elem, type, handle ) {
+ if ( elem.removeEventListener ) {
+ elem.removeEventListener( type, handle, false );
+ }
+ } :
+ function( elem, type, handle ) {
+ if ( elem.detachEvent ) {
+ elem.detachEvent( "on" + type, handle );
+ }
+ };
+
+jQuery.Event = function( src, props ) {
+ // Allow instantiation without the 'new' keyword
+ if ( !(this instanceof jQuery.Event) ) {
+ return new jQuery.Event( src, props );
+ }
+
+ // Event object
+ if ( src && src.type ) {
+ this.originalEvent = src;
+ this.type = src.type;
+
+ // Events bubbling up the document may have been marked as prevented
+ // by a handler lower down the tree; reflect the correct value.
+ this.isDefaultPrevented = ( src.defaultPrevented || src.returnValue === false ||
+ src.getPreventDefault && src.getPreventDefault() ) ? returnTrue : returnFalse;
+
+ // Event type
+ } else {
+ this.type = src;
+ }
+
+ // Put explicitly provided properties onto the event object
+ if ( props ) {
+ jQuery.extend( this, props );
+ }
+
+ // Create a timestamp if incoming event doesn't have one
+ this.timeStamp = src && src.timeStamp || jQuery.now();
+
+ // Mark it as fixed
+ this[ jQuery.expando ] = true;
+};
+
+function returnFalse() {
+ return false;
+}
+function returnTrue() {
+ return true;
+}
+
+// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
+// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
+jQuery.Event.prototype = {
+ preventDefault: function() {
+ this.isDefaultPrevented = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+
+ // if preventDefault exists run it on the original event
+ if ( e.preventDefault ) {
+ e.preventDefault();
+
+ // otherwise set the returnValue property of the original event to false (IE)
+ } else {
+ e.returnValue = false;
+ }
+ },
+ stopPropagation: function() {
+ this.isPropagationStopped = returnTrue;
+
+ var e = this.originalEvent;
+ if ( !e ) {
+ return;
+ }
+ // if stopPropagation exists run it on the original event
+ if ( e.stopPropagation ) {
+ e.stopPropagation();
+ }
+ // otherwise set the cancelBubble property of the original event to true (IE)
+ e.cancelBubble = true;
+ },
+ stopImmediatePropagation: function() {
+ this.isImmediatePropagationStopped = returnTrue;
+ this.stopPropagation();
+ },
+ isDefaultPrevented: returnFalse,
+ isPropagationStopped: returnFalse,
+ isImmediatePropagationStopped: returnFalse
+};
+
+// Create mouseenter/leave events using mouseover/out and event-time checks
+jQuery.each({
+ mouseenter: "mouseover",
+ mouseleave: "mouseout"
+}, function( orig, fix ) {
+ jQuery.event.special[ orig ] = {
+ delegateType: fix,
+ bindType: fix,
+
+ handle: function( event ) {
+ var target = this,
+ related = event.relatedTarget,
+ handleObj = event.handleObj,
+ selector = handleObj.selector,
+ ret;
+
+ // For mousenter/leave call the handler if related is outside the target.
+ // NB: No relatedTarget if the mouse left/entered the browser window
+ if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
+ event.type = handleObj.origType;
+ ret = handleObj.handler.apply( this, arguments );
+ event.type = fix;
+ }
+ return ret;
+ }
+ };
+});
+
+// IE submit delegation
+if ( !jQuery.support.submitBubbles ) {
+
+ jQuery.event.special.submit = {
+ setup: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Lazy-add a submit handler when a descendant form may potentially be submitted
+ jQuery.event.add( this, "click._submit keypress._submit", function( e ) {
+ // Node name check avoids a VML-related crash in IE (#9807)
+ var elem = e.target,
+ form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? elem.form : undefined;
+ if ( form && !form._submit_attached ) {
+ jQuery.event.add( form, "submit._submit", function( event ) {
+ event._submit_bubble = true;
+ });
+ form._submit_attached = true;
+ }
+ });
+ // return undefined since we don't need an event listener
+ },
+
+ postDispatch: function( event ) {
+ // If form was submitted by the user, bubble the event up the tree
+ if ( event._submit_bubble ) {
+ delete event._submit_bubble;
+ if ( this.parentNode && !event.isTrigger ) {
+ jQuery.event.simulate( "submit", this.parentNode, event, true );
+ }
+ }
+ },
+
+ teardown: function() {
+ // Only need this for delegated form submit events
+ if ( jQuery.nodeName( this, "form" ) ) {
+ return false;
+ }
+
+ // Remove delegated handlers; cleanData eventually reaps submit handlers attached above
+ jQuery.event.remove( this, "._submit" );
+ }
+ };
+}
+
+// IE change delegation and checkbox/radio fix
+if ( !jQuery.support.changeBubbles ) {
+
+ jQuery.event.special.change = {
+
+ setup: function() {
+
+ if ( rformElems.test( this.nodeName ) ) {
+ // IE doesn't fire change on a check/radio until blur; trigger it on click
+ // after a propertychange. Eat the blur-change in special.change.handle.
+ // This still fires onchange a second time for check/radio after blur.
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ jQuery.event.add( this, "propertychange._change", function( event ) {
+ if ( event.originalEvent.propertyName === "checked" ) {
+ this._just_changed = true;
+ }
+ });
+ jQuery.event.add( this, "click._change", function( event ) {
+ if ( this._just_changed && !event.isTrigger ) {
+ this._just_changed = false;
+ jQuery.event.simulate( "change", this, event, true );
+ }
+ });
+ }
+ return false;
+ }
+ // Delegated event; lazy-add a change handler on descendant inputs
+ jQuery.event.add( this, "beforeactivate._change", function( e ) {
+ var elem = e.target;
+
+ if ( rformElems.test( elem.nodeName ) && !elem._change_attached ) {
+ jQuery.event.add( elem, "change._change", function( event ) {
+ if ( this.parentNode && !event.isSimulated && !event.isTrigger ) {
+ jQuery.event.simulate( "change", this.parentNode, event, true );
+ }
+ });
+ elem._change_attached = true;
+ }
+ });
+ },
+
+ handle: function( event ) {
+ var elem = event.target;
+
+ // Swallow native change events from checkbox/radio, we already triggered them above
+ if ( this !== elem || event.isSimulated || event.isTrigger || (elem.type !== "radio" && elem.type !== "checkbox") ) {
+ return event.handleObj.handler.apply( this, arguments );
+ }
+ },
+
+ teardown: function() {
+ jQuery.event.remove( this, "._change" );
+
+ return rformElems.test( this.nodeName );
+ }
+ };
+}
+
+// Create "bubbling" focus and blur events
+if ( !jQuery.support.focusinBubbles ) {
+ jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
+
+ // Attach a single capturing handler while someone wants focusin/focusout
+ var attaches = 0,
+ handler = function( event ) {
+ jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
+ };
+
+ jQuery.event.special[ fix ] = {
+ setup: function() {
+ if ( attaches++ === 0 ) {
+ document.addEventListener( orig, handler, true );
+ }
+ },
+ teardown: function() {
+ if ( --attaches === 0 ) {
+ document.removeEventListener( orig, handler, true );
+ }
+ }
+ };
+ });
+}
+
+jQuery.fn.extend({
+
+ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
+ var origFn, type;
+
+ // Types can be a map of types/handlers
+ if ( typeof types === "object" ) {
+ // ( types-Object, selector, data )
+ if ( typeof selector !== "string" ) { // && selector != null
+ // ( types-Object, data )
+ data = data || selector;
+ selector = undefined;
+ }
+ for ( type in types ) {
+ this.on( type, selector, data, types[ type ], one );
+ }
+ return this;
+ }
+
+ if ( data == null && fn == null ) {
+ // ( types, fn )
+ fn = selector;
+ data = selector = undefined;
+ } else if ( fn == null ) {
+ if ( typeof selector === "string" ) {
+ // ( types, selector, fn )
+ fn = data;
+ data = undefined;
+ } else {
+ // ( types, data, fn )
+ fn = data;
+ data = selector;
+ selector = undefined;
+ }
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ } else if ( !fn ) {
+ return this;
+ }
+
+ if ( one === 1 ) {
+ origFn = fn;
+ fn = function( event ) {
+ // Can use an empty set, since event contains the info
+ jQuery().off( event );
+ return origFn.apply( this, arguments );
+ };
+ // Use same guid so caller can remove using origFn
+ fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
+ }
+ return this.each( function() {
+ jQuery.event.add( this, types, fn, data, selector );
+ });
+ },
+ one: function( types, selector, data, fn ) {
+ return this.on( types, selector, data, fn, 1 );
+ },
+ off: function( types, selector, fn ) {
+ if ( types && types.preventDefault && types.handleObj ) {
+ // ( event ) dispatched jQuery.Event
+ var handleObj = types.handleObj;
+ jQuery( types.delegateTarget ).off(
+ handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
+ handleObj.selector,
+ handleObj.handler
+ );
+ return this;
+ }
+ if ( typeof types === "object" ) {
+ // ( types-object [, selector] )
+ for ( var type in types ) {
+ this.off( type, selector, types[ type ] );
+ }
+ return this;
+ }
+ if ( selector === false || typeof selector === "function" ) {
+ // ( types [, fn] )
+ fn = selector;
+ selector = undefined;
+ }
+ if ( fn === false ) {
+ fn = returnFalse;
+ }
+ return this.each(function() {
+ jQuery.event.remove( this, types, fn, selector );
+ });
+ },
+
+ bind: function( types, data, fn ) {
+ return this.on( types, null, data, fn );
+ },
+ unbind: function( types, fn ) {
+ return this.off( types, null, fn );
+ },
+
+ live: function( types, data, fn ) {
+ jQuery( this.context ).on( types, this.selector, data, fn );
+ return this;
+ },
+ die: function( types, fn ) {
+ jQuery( this.context ).off( types, this.selector || "**", fn );
+ return this;
+ },
+
+ delegate: function( selector, types, data, fn ) {
+ return this.on( types, selector, data, fn );
+ },
+ undelegate: function( selector, types, fn ) {
+ // ( namespace ) or ( selector, types [, fn] )
+ return arguments.length == 1? this.off( selector, "**" ) : this.off( types, selector, fn );
+ },
+
+ trigger: function( type, data ) {
+ return this.each(function() {
+ jQuery.event.trigger( type, data, this );
+ });
+ },
+ triggerHandler: function( type, data ) {
+ if ( this[0] ) {
+ return jQuery.event.trigger( type, data, this[0], true );
+ }
+ },
+
+ toggle: function( fn ) {
+ // Save reference to arguments for access in closure
+ var args = arguments,
+ guid = fn.guid || jQuery.guid++,
+ i = 0,
+ toggler = function( event ) {
+ // Figure out which function to execute
+ var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
+ jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
+
+ // Make sure that clicks stop
+ event.preventDefault();
+
+ // and execute the function
+ return args[ lastToggle ].apply( this, arguments ) || false;
+ };
+
+ // link all the functions, so any of them can unbind this click handler
+ toggler.guid = guid;
+ while ( i < args.length ) {
+ args[ i++ ].guid = guid;
+ }
+
+ return this.click( toggler );
+ },
+
+ hover: function( fnOver, fnOut ) {
+ return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
+ }
+});
+
+jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
+ "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
+ "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
+
+ // Handle event binding
+ jQuery.fn[ name ] = function( data, fn ) {
+ if ( fn == null ) {
+ fn = data;
+ data = null;
+ }
+
+ return arguments.length > 0 ?
+ this.on( name, null, data, fn ) :
+ this.trigger( name );
+ };
+
+ if ( jQuery.attrFn ) {
+ jQuery.attrFn[ name ] = true;
+ }
+
+ if ( rkeyEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.keyHooks;
+ }
+
+ if ( rmouseEvent.test( name ) ) {
+ jQuery.event.fixHooks[ name ] = jQuery.event.mouseHooks;
+ }
+});
+
+
+
+/*!
+ * Sizzle CSS Selector Engine
+ * Copyright 2011, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){
+
+var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
+ expando = "sizcache" + (Math.random() + '').replace('.', ''),
+ done = 0,
+ toString = Object.prototype.toString,
+ hasDuplicate = false,
+ baseHasDuplicate = true,
+ rBackslash = /\\/g,
+ rReturn = /\r\n/g,
+ rNonWord = /\W/;
+
+// Here we check if the JavaScript engine is using some sort of
+// optimization where it does not always call our comparision
+// function. If that is the case, discard the hasDuplicate value.
+// Thus far that includes Google Chrome.
+[0, 0].sort(function() {
+ baseHasDuplicate = false;
+ return 0;
+});
+
+var Sizzle = function( selector, context, results, seed ) {
+ results = results || [];
+ context = context || document;
+
+ var origContext = context;
+
+ if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
+ return [];
+ }
+
+ if ( !selector || typeof selector !== "string" ) {
+ return results;
+ }
+
+ var m, set, checkSet, extra, ret, cur, pop, i,
+ prune = true,
+ contextXML = Sizzle.isXML( context ),
+ parts = [],
+ soFar = selector;
+
+ // Reset the position of the chunker regexp (start from head)
+ do {
+ chunker.exec( "" );
+ m = chunker.exec( soFar );
+
+ if ( m ) {
+ soFar = m[3];
+
+ parts.push( m[1] );
+
+ if ( m[2] ) {
+ extra = m[3];
+ break;
+ }
+ }
+ } while ( m );
+
+ if ( parts.length > 1 && origPOS.exec( selector ) ) {
+
+ if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
+ set = posProcess( parts[0] + parts[1], context, seed );
+
+ } else {
+ set = Expr.relative[ parts[0] ] ?
+ [ context ] :
+ Sizzle( parts.shift(), context );
+
+ while ( parts.length ) {
+ selector = parts.shift();
+
+ if ( Expr.relative[ selector ] ) {
+ selector += parts.shift();
+ }
+
+ set = posProcess( selector, set, seed );
+ }
+ }
+
+ } else {
+ // Take a shortcut and set the context if the root selector is an ID
+ // (but not if it'll be faster if the inner selector is an ID)
+ if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
+ Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
+
+ ret = Sizzle.find( parts.shift(), context, contextXML );
+ context = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set )[0] :
+ ret.set[0];
+ }
+
+ if ( context ) {
+ ret = seed ?
+ { expr: parts.pop(), set: makeArray(seed) } :
+ Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
+
+ set = ret.expr ?
+ Sizzle.filter( ret.expr, ret.set ) :
+ ret.set;
+
+ if ( parts.length > 0 ) {
+ checkSet = makeArray( set );
+
+ } else {
+ prune = false;
+ }
+
+ while ( parts.length ) {
+ cur = parts.pop();
+ pop = cur;
+
+ if ( !Expr.relative[ cur ] ) {
+ cur = "";
+ } else {
+ pop = parts.pop();
+ }
+
+ if ( pop == null ) {
+ pop = context;
+ }
+
+ Expr.relative[ cur ]( checkSet, pop, contextXML );
+ }
+
+ } else {
+ checkSet = parts = [];
+ }
+ }
+
+ if ( !checkSet ) {
+ checkSet = set;
+ }
+
+ if ( !checkSet ) {
+ Sizzle.error( cur || selector );
+ }
+
+ if ( toString.call(checkSet) === "[object Array]" ) {
+ if ( !prune ) {
+ results.push.apply( results, checkSet );
+
+ } else if ( context && context.nodeType === 1 ) {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {
+ results.push( set[i] );
+ }
+ }
+
+ } else {
+ for ( i = 0; checkSet[i] != null; i++ ) {
+ if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
+ results.push( set[i] );
+ }
+ }
+ }
+
+ } else {
+ makeArray( checkSet, results );
+ }
+
+ if ( extra ) {
+ Sizzle( extra, origContext, results, seed );
+ Sizzle.uniqueSort( results );
+ }
+
+ return results;
+};
+
+Sizzle.uniqueSort = function( results ) {
+ if ( sortOrder ) {
+ hasDuplicate = baseHasDuplicate;
+ results.sort( sortOrder );
+
+ if ( hasDuplicate ) {
+ for ( var i = 1; i < results.length; i++ ) {
+ if ( results[i] === results[ i - 1 ] ) {
+ results.splice( i--, 1 );
+ }
+ }
+ }
+ }
+
+ return results;
+};
+
+Sizzle.matches = function( expr, set ) {
+ return Sizzle( expr, null, null, set );
+};
+
+Sizzle.matchesSelector = function( node, expr ) {
+ return Sizzle( expr, null, null, [node] ).length > 0;
+};
+
+Sizzle.find = function( expr, context, isXML ) {
+ var set, i, len, match, type, left;
+
+ if ( !expr ) {
+ return [];
+ }
+
+ for ( i = 0, len = Expr.order.length; i < len; i++ ) {
+ type = Expr.order[i];
+
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
+ left = match[1];
+ match.splice( 1, 1 );
+
+ if ( left.substr( left.length - 1 ) !== "\\" ) {
+ match[1] = (match[1] || "").replace( rBackslash, "" );
+ set = Expr.find[ type ]( match, context, isXML );
+
+ if ( set != null ) {
+ expr = expr.replace( Expr.match[ type ], "" );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !set ) {
+ set = typeof context.getElementsByTagName !== "undefined" ?
+ context.getElementsByTagName( "*" ) :
+ [];
+ }
+
+ return { set: set, expr: expr };
+};
+
+Sizzle.filter = function( expr, set, inplace, not ) {
+ var match, anyFound,
+ type, found, item, filter, left,
+ i, pass,
+ old = expr,
+ result = [],
+ curLoop = set,
+ isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );
+
+ while ( expr && set.length ) {
+ for ( type in Expr.filter ) {
+ if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
+ filter = Expr.filter[ type ];
+ left = match[1];
+
+ anyFound = false;
+
+ match.splice(1,1);
+
+ if ( left.substr( left.length - 1 ) === "\\" ) {
+ continue;
+ }
+
+ if ( curLoop === result ) {
+ result = [];
+ }
+
+ if ( Expr.preFilter[ type ] ) {
+ match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
+
+ if ( !match ) {
+ anyFound = found = true;
+
+ } else if ( match === true ) {
+ continue;
+ }
+ }
+
+ if ( match ) {
+ for ( i = 0; (item = curLoop[i]) != null; i++ ) {
+ if ( item ) {
+ found = filter( item, match, i, curLoop );
+ pass = not ^ found;
+
+ if ( inplace && found != null ) {
+ if ( pass ) {
+ anyFound = true;
+
+ } else {
+ curLoop[i] = false;
+ }
+
+ } else if ( pass ) {
+ result.push( item );
+ anyFound = true;
+ }
+ }
+ }
+ }
+
+ if ( found !== undefined ) {
+ if ( !inplace ) {
+ curLoop = result;
+ }
+
+ expr = expr.replace( Expr.match[ type ], "" );
+
+ if ( !anyFound ) {
+ return [];
+ }
+
+ break;
+ }
+ }
+ }
+
+ // Improper expression
+ if ( expr === old ) {
+ if ( anyFound == null ) {
+ Sizzle.error( expr );
+
+ } else {
+ break;
+ }
+ }
+
+ old = expr;
+ }
+
+ return curLoop;
+};
+
+Sizzle.error = function( msg ) {
+ throw new Error( "Syntax error, unrecognized expression: " + msg );
+};
+
+/**
+ * Utility function for retreiving the text value of an array of DOM nodes
+ * @param {Array|Element} elem
+ */
+var getText = Sizzle.getText = function( elem ) {
+ var i, node,
+ nodeType = elem.nodeType,
+ ret = "";
+
+ if ( nodeType ) {
+ if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
+ // Use textContent || innerText for elements
+ if ( typeof elem.textContent === 'string' ) {
+ return elem.textContent;
+ } else if ( typeof elem.innerText === 'string' ) {
+ // Replace IE's carriage returns
+ return elem.innerText.replace( rReturn, '' );
+ } else {
+ // Traverse it's children
+ for ( elem = elem.firstChild; elem; elem = elem.nextSibling) {
+ ret += getText( elem );
+ }
+ }
+ } else if ( nodeType === 3 || nodeType === 4 ) {
+ return elem.nodeValue;
+ }
+ } else {
+
+ // If no nodeType, this is expected to be an array
+ for ( i = 0; (node = elem[i]); i++ ) {
+ // Do not traverse comment nodes
+ if ( node.nodeType !== 8 ) {
+ ret += getText( node );
+ }
+ }
+ }
+ return ret;
+};
+
+var Expr = Sizzle.selectors = {
+ order: [ "ID", "NAME", "TAG" ],
+
+ match: {
+ ID: /#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ CLASS: /\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,
+ NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,
+ ATTR: /\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,
+ TAG: /^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,
+ CHILD: /:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,
+ POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,
+ PSEUDO: /:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
+ },
+
+ leftMatch: {},
+
+ attrMap: {
+ "class": "className",
+ "for": "htmlFor"
+ },
+
+ attrHandle: {
+ href: function( elem ) {
+ return elem.getAttribute( "href" );
+ },
+ type: function( elem ) {
+ return elem.getAttribute( "type" );
+ }
+ },
+
+ relative: {
+ "+": function(checkSet, part){
+ var isPartStr = typeof part === "string",
+ isTag = isPartStr && !rNonWord.test( part ),
+ isPartStrNotTag = isPartStr && !isTag;
+
+ if ( isTag ) {
+ part = part.toLowerCase();
+ }
+
+ for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
+ if ( (elem = checkSet[i]) ) {
+ while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
+
+ checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
+ elem || false :
+ elem === part;
+ }
+ }
+
+ if ( isPartStrNotTag ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ },
+
+ ">": function( checkSet, part ) {
+ var elem,
+ isPartStr = typeof part === "string",
+ i = 0,
+ l = checkSet.length;
+
+ if ( isPartStr && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ var parent = elem.parentNode;
+ checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
+ }
+ }
+
+ } else {
+ for ( ; i < l; i++ ) {
+ elem = checkSet[i];
+
+ if ( elem ) {
+ checkSet[i] = isPartStr ?
+ elem.parentNode :
+ elem.parentNode === part;
+ }
+ }
+
+ if ( isPartStr ) {
+ Sizzle.filter( part, checkSet, true );
+ }
+ }
+ },
+
+ "": function(checkSet, part, isXML){
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
+ },
+
+ "~": function( checkSet, part, isXML ) {
+ var nodeCheck,
+ doneName = done++,
+ checkFn = dirCheck;
+
+ if ( typeof part === "string" && !rNonWord.test( part ) ) {
+ part = part.toLowerCase();
+ nodeCheck = part;
+ checkFn = dirNodeCheck;
+ }
+
+ checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, isXML );
+ }
+ },
+
+ find: {
+ ID: function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ return m && m.parentNode ? [m] : [];
+ }
+ },
+
+ NAME: function( match, context ) {
+ if ( typeof context.getElementsByName !== "undefined" ) {
+ var ret = [],
+ results = context.getElementsByName( match[1] );
+
+ for ( var i = 0, l = results.length; i < l; i++ ) {
+ if ( results[i].getAttribute("name") === match[1] ) {
+ ret.push( results[i] );
+ }
+ }
+
+ return ret.length === 0 ? null : ret;
+ }
+ },
+
+ TAG: function( match, context ) {
+ if ( typeof context.getElementsByTagName !== "undefined" ) {
+ return context.getElementsByTagName( match[1] );
+ }
+ }
+ },
+ preFilter: {
+ CLASS: function( match, curLoop, inplace, result, not, isXML ) {
+ match = " " + match[1].replace( rBackslash, "" ) + " ";
+
+ if ( isXML ) {
+ return match;
+ }
+
+ for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
+ if ( elem ) {
+ if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n\r]/g, " ").indexOf(match) >= 0) ) {
+ if ( !inplace ) {
+ result.push( elem );
+ }
+
+ } else if ( inplace ) {
+ curLoop[i] = false;
+ }
+ }
+ }
+
+ return false;
+ },
+
+ ID: function( match ) {
+ return match[1].replace( rBackslash, "" );
+ },
+
+ TAG: function( match, curLoop ) {
+ return match[1].replace( rBackslash, "" ).toLowerCase();
+ },
+
+ CHILD: function( match ) {
+ if ( match[1] === "nth" ) {
+ if ( !match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ match[2] = match[2].replace(/^\+|\s*/g, '');
+
+ // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
+ var test = /(-?)(\d*)(?:n([+\-]?\d*))?/.exec(
+ match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
+ !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
+
+ // calculate the numbers (first)n+(last) including if they are negative
+ match[2] = (test[1] + (test[2] || 1)) - 0;
+ match[3] = test[3] - 0;
+ }
+ else if ( match[2] ) {
+ Sizzle.error( match[0] );
+ }
+
+ // TODO: Move to normal caching system
+ match[0] = done++;
+
+ return match;
+ },
+
+ ATTR: function( match, curLoop, inplace, result, not, isXML ) {
+ var name = match[1] = match[1].replace( rBackslash, "" );
+
+ if ( !isXML && Expr.attrMap[name] ) {
+ match[1] = Expr.attrMap[name];
+ }
+
+ // Handle if an un-quoted value was used
+ match[4] = ( match[4] || match[5] || "" ).replace( rBackslash, "" );
+
+ if ( match[2] === "~=" ) {
+ match[4] = " " + match[4] + " ";
+ }
+
+ return match;
+ },
+
+ PSEUDO: function( match, curLoop, inplace, result, not ) {
+ if ( match[1] === "not" ) {
+ // If we're dealing with a complex expression, or a simple one
+ if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
+ match[3] = Sizzle(match[3], null, null, curLoop);
+
+ } else {
+ var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
+
+ if ( !inplace ) {
+ result.push.apply( result, ret );
+ }
+
+ return false;
+ }
+
+ } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
+ return true;
+ }
+
+ return match;
+ },
+
+ POS: function( match ) {
+ match.unshift( true );
+
+ return match;
+ }
+ },
+
+ filters: {
+ enabled: function( elem ) {
+ return elem.disabled === false && elem.type !== "hidden";
+ },
+
+ disabled: function( elem ) {
+ return elem.disabled === true;
+ },
+
+ checked: function( elem ) {
+ return elem.checked === true;
+ },
+
+ selected: function( elem ) {
+ // Accessing this property makes selected-by-default
+ // options in Safari work properly
+ if ( elem.parentNode ) {
+ elem.parentNode.selectedIndex;
+ }
+
+ return elem.selected === true;
+ },
+
+ parent: function( elem ) {
+ return !!elem.firstChild;
+ },
+
+ empty: function( elem ) {
+ return !elem.firstChild;
+ },
+
+ has: function( elem, i, match ) {
+ return !!Sizzle( match[3], elem ).length;
+ },
+
+ header: function( elem ) {
+ return (/h\d/i).test( elem.nodeName );
+ },
+
+ text: function( elem ) {
+ var attr = elem.getAttribute( "type" ), type = elem.type;
+ // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc)
+ // use getAttribute instead to test this case
+ return elem.nodeName.toLowerCase() === "input" && "text" === type && ( attr === type || attr === null );
+ },
+
+ radio: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "radio" === elem.type;
+ },
+
+ checkbox: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "checkbox" === elem.type;
+ },
+
+ file: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "file" === elem.type;
+ },
+
+ password: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "password" === elem.type;
+ },
+
+ submit: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "submit" === elem.type;
+ },
+
+ image: function( elem ) {
+ return elem.nodeName.toLowerCase() === "input" && "image" === elem.type;
+ },
+
+ reset: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return (name === "input" || name === "button") && "reset" === elem.type;
+ },
+
+ button: function( elem ) {
+ var name = elem.nodeName.toLowerCase();
+ return name === "input" && "button" === elem.type || name === "button";
+ },
+
+ input: function( elem ) {
+ return (/input|select|textarea|button/i).test( elem.nodeName );
+ },
+
+ focus: function( elem ) {
+ return elem === elem.ownerDocument.activeElement;
+ }
+ },
+ setFilters: {
+ first: function( elem, i ) {
+ return i === 0;
+ },
+
+ last: function( elem, i, match, array ) {
+ return i === array.length - 1;
+ },
+
+ even: function( elem, i ) {
+ return i % 2 === 0;
+ },
+
+ odd: function( elem, i ) {
+ return i % 2 === 1;
+ },
+
+ lt: function( elem, i, match ) {
+ return i < match[3] - 0;
+ },
+
+ gt: function( elem, i, match ) {
+ return i > match[3] - 0;
+ },
+
+ nth: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ },
+
+ eq: function( elem, i, match ) {
+ return match[3] - 0 === i;
+ }
+ },
+ filter: {
+ PSEUDO: function( elem, match, i, array ) {
+ var name = match[1],
+ filter = Expr.filters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+
+ } else if ( name === "contains" ) {
+ return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
+
+ } else if ( name === "not" ) {
+ var not = match[3];
+
+ for ( var j = 0, l = not.length; j < l; j++ ) {
+ if ( not[j] === elem ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ } else {
+ Sizzle.error( name );
+ }
+ },
+
+ CHILD: function( elem, match ) {
+ var first, last,
+ doneName, parent, cache,
+ count, diff,
+ type = match[1],
+ node = elem;
+
+ switch ( type ) {
+ case "only":
+ case "first":
+ while ( (node = node.previousSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ if ( type === "first" ) {
+ return true;
+ }
+
+ node = elem;
+
+ /* falls through */
+ case "last":
+ while ( (node = node.nextSibling) ) {
+ if ( node.nodeType === 1 ) {
+ return false;
+ }
+ }
+
+ return true;
+
+ case "nth":
+ first = match[2];
+ last = match[3];
+
+ if ( first === 1 && last === 0 ) {
+ return true;
+ }
+
+ doneName = match[0];
+ parent = elem.parentNode;
+
+ if ( parent && (parent[ expando ] !== doneName || !elem.nodeIndex) ) {
+ count = 0;
+
+ for ( node = parent.firstChild; node; node = node.nextSibling ) {
+ if ( node.nodeType === 1 ) {
+ node.nodeIndex = ++count;
+ }
+ }
+
+ parent[ expando ] = doneName;
+ }
+
+ diff = elem.nodeIndex - last;
+
+ if ( first === 0 ) {
+ return diff === 0;
+
+ } else {
+ return ( diff % first === 0 && diff / first >= 0 );
+ }
+ }
+ },
+
+ ID: function( elem, match ) {
+ return elem.nodeType === 1 && elem.getAttribute("id") === match;
+ },
+
+ TAG: function( elem, match ) {
+ return (match === "*" && elem.nodeType === 1) || !!elem.nodeName && elem.nodeName.toLowerCase() === match;
+ },
+
+ CLASS: function( elem, match ) {
+ return (" " + (elem.className || elem.getAttribute("class")) + " ")
+ .indexOf( match ) > -1;
+ },
+
+ ATTR: function( elem, match ) {
+ var name = match[1],
+ result = Sizzle.attr ?
+ Sizzle.attr( elem, name ) :
+ Expr.attrHandle[ name ] ?
+ Expr.attrHandle[ name ]( elem ) :
+ elem[ name ] != null ?
+ elem[ name ] :
+ elem.getAttribute( name ),
+ value = result + "",
+ type = match[2],
+ check = match[4];
+
+ return result == null ?
+ type === "!=" :
+ !type && Sizzle.attr ?
+ result != null :
+ type === "=" ?
+ value === check :
+ type === "*=" ?
+ value.indexOf(check) >= 0 :
+ type === "~=" ?
+ (" " + value + " ").indexOf(check) >= 0 :
+ !check ?
+ value && result !== false :
+ type === "!=" ?
+ value !== check :
+ type === "^=" ?
+ value.indexOf(check) === 0 :
+ type === "$=" ?
+ value.substr(value.length - check.length) === check :
+ type === "|=" ?
+ value === check || value.substr(0, check.length + 1) === check + "-" :
+ false;
+ },
+
+ POS: function( elem, match, i, array ) {
+ var name = match[2],
+ filter = Expr.setFilters[ name ];
+
+ if ( filter ) {
+ return filter( elem, i, match, array );
+ }
+ }
+ }
+};
+
+var origPOS = Expr.match.POS,
+ fescape = function(all, num){
+ return "\\" + (num - 0 + 1);
+ };
+
+for ( var type in Expr.match ) {
+ Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\[]*\])(?![^\(]*\))/.source) );
+ Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, fescape) );
+}
+// Expose origPOS
+// "global" as in regardless of relation to brackets/parens
+Expr.match.globalPOS = origPOS;
+
+var makeArray = function( array, results ) {
+ array = Array.prototype.slice.call( array, 0 );
+
+ if ( results ) {
+ results.push.apply( results, array );
+ return results;
+ }
+
+ return array;
+};
+
+// Perform a simple check to determine if the browser is capable of
+// converting a NodeList to an array using builtin methods.
+// Also verifies that the returned array holds DOM nodes
+// (which is not the case in the Blackberry browser)
+try {
+ Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;
+
+// Provide a fallback method if it does not work
+} catch( e ) {
+ makeArray = function( array, results ) {
+ var i = 0,
+ ret = results || [];
+
+ if ( toString.call(array) === "[object Array]" ) {
+ Array.prototype.push.apply( ret, array );
+
+ } else {
+ if ( typeof array.length === "number" ) {
+ for ( var l = array.length; i < l; i++ ) {
+ ret.push( array[i] );
+ }
+
+ } else {
+ for ( ; array[i]; i++ ) {
+ ret.push( array[i] );
+ }
+ }
+ }
+
+ return ret;
+ };
+}
+
+var sortOrder, siblingCheck;
+
+if ( document.documentElement.compareDocumentPosition ) {
+ sortOrder = function( a, b ) {
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+ }
+
+ if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
+ return a.compareDocumentPosition ? -1 : 1;
+ }
+
+ return a.compareDocumentPosition(b) & 4 ? -1 : 1;
+ };
+
+} else {
+ sortOrder = function( a, b ) {
+ // The nodes are identical, we can exit early
+ if ( a === b ) {
+ hasDuplicate = true;
+ return 0;
+
+ // Fallback to using sourceIndex (in IE) if it's available on both nodes
+ } else if ( a.sourceIndex && b.sourceIndex ) {
+ return a.sourceIndex - b.sourceIndex;
+ }
+
+ var al, bl,
+ ap = [],
+ bp = [],
+ aup = a.parentNode,
+ bup = b.parentNode,
+ cur = aup;
+
+ // If the nodes are siblings (or identical) we can do a quick check
+ if ( aup === bup ) {
+ return siblingCheck( a, b );
+
+ // If no parents were found then the nodes are disconnected
+ } else if ( !aup ) {
+ return -1;
+
+ } else if ( !bup ) {
+ return 1;
+ }
+
+ // Otherwise they're somewhere else in the tree so we need
+ // to build up a full list of the parentNodes for comparison
+ while ( cur ) {
+ ap.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ cur = bup;
+
+ while ( cur ) {
+ bp.unshift( cur );
+ cur = cur.parentNode;
+ }
+
+ al = ap.length;
+ bl = bp.length;
+
+ // Start walking down the tree looking for a discrepancy
+ for ( var i = 0; i < al && i < bl; i++ ) {
+ if ( ap[i] !== bp[i] ) {
+ return siblingCheck( ap[i], bp[i] );
+ }
+ }
+
+ // We ended someplace up the tree so do a sibling check
+ return i === al ?
+ siblingCheck( a, bp[i], -1 ) :
+ siblingCheck( ap[i], b, 1 );
+ };
+
+ siblingCheck = function( a, b, ret ) {
+ if ( a === b ) {
+ return ret;
+ }
+
+ var cur = a.nextSibling;
+
+ while ( cur ) {
+ if ( cur === b ) {
+ return -1;
+ }
+
+ cur = cur.nextSibling;
+ }
+
+ return 1;
+ };
+}
+
+// Check to see if the browser returns elements by name when
+// querying by getElementById (and provide a workaround)
+(function(){
+ // We're going to inject a fake input element with a specified name
+ var form = document.createElement("div"),
+ id = "script" + (new Date()).getTime(),
+ root = document.documentElement;
+
+ form.innerHTML = "<a name='" + id + "'/>";
+
+ // Inject it into the root element, check its status, and remove it quickly
+ root.insertBefore( form, root.firstChild );
+
+ // The workaround has to do additional checks after a getElementById
+ // Which slows things down for other browsers (hence the branching)
+ if ( document.getElementById( id ) ) {
+ Expr.find.ID = function( match, context, isXML ) {
+ if ( typeof context.getElementById !== "undefined" && !isXML ) {
+ var m = context.getElementById(match[1]);
+
+ return m ?
+ m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ?
+ [m] :
+ undefined :
+ [];
+ }
+ };
+
+ Expr.filter.ID = function( elem, match ) {
+ var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
+
+ return elem.nodeType === 1 && node && node.nodeValue === match;
+ };
+ }
+
+ root.removeChild( form );
+
+ // release memory in IE
+ root = form = null;
+})();
+
+(function(){
+ // Check to see if the browser returns only elements
+ // when doing getElementsByTagName("*")
+
+ // Create a fake element
+ var div = document.createElement("div");
+ div.appendChild( document.createComment("") );
+
+ // Make sure no comments are found
+ if ( div.getElementsByTagName("*").length > 0 ) {
+ Expr.find.TAG = function( match, context ) {
+ var results = context.getElementsByTagName( match[1] );
+
+ // Filter out possible comments
+ if ( match[1] === "*" ) {
+ var tmp = [];
+
+ for ( var i = 0; results[i]; i++ ) {
+ if ( results[i].nodeType === 1 ) {
+ tmp.push( results[i] );
+ }
+ }
+
+ results = tmp;
+ }
+
+ return results;
+ };
+ }
+
+ // Check to see if an attribute returns normalized href attributes
+ div.innerHTML = "<a href='#'></a>";
+
+ if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
+ div.firstChild.getAttribute("href") !== "#" ) {
+
+ Expr.attrHandle.href = function( elem ) {
+ return elem.getAttribute( "href", 2 );
+ };
+ }
+
+ // release memory in IE
+ div = null;
+})();
+
+if ( document.querySelectorAll ) {
+ (function(){
+ var oldSizzle = Sizzle,
+ div = document.createElement("div"),
+ id = "__sizzle__";
+
+ div.innerHTML = "<p class='TEST'></p>";
+
+ // Safari can't handle uppercase or unicode characters when
+ // in quirks mode.
+ if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
+ return;
+ }
+
+ Sizzle = function( query, context, extra, seed ) {
+ context = context || document;
+
+ // Only use querySelectorAll on non-XML documents
+ // (ID selectors don't work in non-HTML documents)
+ if ( !seed && !Sizzle.isXML(context) ) {
+ // See if we find a selector to speed up
+ var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec( query );
+
+ if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {
+ // Speed-up: Sizzle("TAG")
+ if ( match[1] ) {
+ return makeArray( context.getElementsByTagName( query ), extra );
+
+ // Speed-up: Sizzle(".CLASS")
+ } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {
+ return makeArray( context.getElementsByClassName( match[2] ), extra );
+ }
+ }
+
+ if ( context.nodeType === 9 ) {
+ // Speed-up: Sizzle("body")
+ // The body element only exists once, optimize finding it
+ if ( query === "body" && context.body ) {
+ return makeArray( [ context.body ], extra );
+
+ // Speed-up: Sizzle("#ID")
+ } else if ( match && match[3] ) {
+ var elem = context.getElementById( match[3] );
+
+ // Check parentNode to catch when Blackberry 4.6 returns
+ // nodes that are no longer in the document #6963
+ if ( elem && elem.parentNode ) {
+ // Handle the case where IE and Opera return items
+ // by name instead of ID
+ if ( elem.id === match[3] ) {
+ return makeArray( [ elem ], extra );
+ }
+
+ } else {
+ return makeArray( [], extra );
+ }
+ }
+
+ try {
+ return makeArray( context.querySelectorAll(query), extra );
+ } catch(qsaError) {}
+
+ // qSA works strangely on Element-rooted queries
+ // We can work around this by specifying an extra ID on the root
+ // and working up from there (Thanks to Andrew Dupont for the technique)
+ // IE 8 doesn't work on object elements
+ } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
+ var oldContext = context,
+ old = context.getAttribute( "id" ),
+ nid = old || id,
+ hasParent = context.parentNode,
+ relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+ if ( !old ) {
+ context.setAttribute( "id", nid );
+ } else {
+ nid = nid.replace( /'/g, "\\$&" );
+ }
+ if ( relativeHierarchySelector && hasParent ) {
+ context = context.parentNode;
+ }
+
+ try {
+ if ( !relativeHierarchySelector || hasParent ) {
+ return makeArray( context.querySelectorAll( "[id='" + nid + "'] " + query ), extra );
+ }
+
+ } catch(pseudoError) {
+ } finally {
+ if ( !old ) {
+ oldContext.removeAttribute( "id" );
+ }
+ }
+ }
+ }
+
+ return oldSizzle(query, context, extra, seed);
+ };
+
+ for ( var prop in oldSizzle ) {
+ Sizzle[ prop ] = oldSizzle[ prop ];
+ }
+
+ // release memory in IE
+ div = null;
+ })();
+}
+
+(function(){
+ var html = document.documentElement,
+ matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;
+
+ if ( matches ) {
+ // Check to see if it's possible to do matchesSelector
+ // on a disconnected node (IE 9 fails this)
+ var disconnectedMatch = !matches.call( document.createElement( "div" ), "div" ),
+ pseudoWorks = false;
+
+ try {
+ // This should fail with an exception
+ // Gecko does not error, returns false instead
+ matches.call( document.documentElement, "[test!='']:sizzle" );
+
+ } catch( pseudoError ) {
+ pseudoWorks = true;
+ }
+
+ Sizzle.matchesSelector = function( node, expr ) {
+ // Make sure that attribute selectors are quoted
+ expr = expr.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");
+
+ if ( !Sizzle.isXML( node ) ) {
+ try {
+ if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {
+ var ret = matches.call( node, expr );
+
+ // IE 9's matchesSelector returns false on disconnected nodes
+ if ( ret || !disconnectedMatch ||
+ // As well, disconnected nodes are said to be in a document
+ // fragment in IE 9, so check for that
+ node.document && node.document.nodeType !== 11 ) {
+ return ret;
+ }
+ }
+ } catch(e) {}
+ }
+
+ return Sizzle(expr, null, null, [node]).length > 0;
+ };
+ }
+})();
+
+(function(){
+ var div = document.createElement("div");
+
+ div.innerHTML = "<div class='test e'></div><div class='test'></div>";
+
+ // Opera can't find a second classname (in 9.6)
+ // Also, make sure that getElementsByClassName actually exists
+ if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
+ return;
+ }
+
+ // Safari caches class attributes, doesn't catch changes (in 3.2)
+ div.lastChild.className = "e";
+
+ if ( div.getElementsByClassName("e").length === 1 ) {
+ return;
+ }
+
+ Expr.order.splice(1, 0, "CLASS");
+ Expr.find.CLASS = function( match, context, isXML ) {
+ if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
+ return context.getElementsByClassName(match[1]);
+ }
+ };
+
+ // release memory in IE
+ div = null;
+})();
+
+function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 && !isXML ){
+ elem[ expando ] = doneName;
+ elem.sizset = i;
+ }
+
+ if ( elem.nodeName.toLowerCase() === cur ) {
+ match = elem;
+ break;
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
+ for ( var i = 0, l = checkSet.length; i < l; i++ ) {
+ var elem = checkSet[i];
+
+ if ( elem ) {
+ var match = false;
+
+ elem = elem[dir];
+
+ while ( elem ) {
+ if ( elem[ expando ] === doneName ) {
+ match = checkSet[elem.sizset];
+ break;
+ }
+
+ if ( elem.nodeType === 1 ) {
+ if ( !isXML ) {
+ elem[ expando ] = doneName;
+ elem.sizset = i;
+ }
+
+ if ( typeof cur !== "string" ) {
+ if ( elem === cur ) {
+ match = true;
+ break;
+ }
+
+ } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
+ match = elem;
+ break;
+ }
+ }
+
+ elem = elem[dir];
+ }
+
+ checkSet[i] = match;
+ }
+ }
+}
+
+if ( document.documentElement.contains ) {
+ Sizzle.contains = function( a, b ) {
+ return a !== b && (a.contains ? a.contains(b) : true);
+ };
+
+} else if ( document.documentElement.compareDocumentPosition ) {
+ Sizzle.contains = function( a, b ) {
+ return !!(a.compareDocumentPosition(b) & 16);
+ };
+
+} else {
+ Sizzle.contains = function() {
+ return false;
+ };
+}
+
+Sizzle.isXML = function( elem ) {
+ // documentElement is verified for cases where it doesn't yet exist
+ // (such as loading iframes in IE - #4833)
+ var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
+
+ return documentElement ? documentElement.nodeName !== "HTML" : false;
+};
+
+var posProcess = function( selector, context, seed ) {
+ var match,
+ tmpSet = [],
+ later = "",
+ root = context.nodeType ? [context] : context;
+
+ // Position selectors must be done after the filter
+ // And so must :not(positional) so we move all PSEUDOs to the end
+ while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
+ later += match[0];
+ selector = selector.replace( Expr.match.PSEUDO, "" );
+ }
+
+ selector = Expr.relative[selector] ? selector + "*" : selector;
+
+ for ( var i = 0, l = root.length; i < l; i++ ) {
+ Sizzle( selector, root[i], tmpSet, seed );
+ }
+
+ return Sizzle.filter( later, tmpSet );
+};
+
+// EXPOSE
+// Override sizzle attribute retrieval
+Sizzle.attr = jQuery.attr;
+Sizzle.selectors.attrMap = {};
+jQuery.find = Sizzle;
+jQuery.expr = Sizzle.selectors;
+jQuery.expr[":"] = jQuery.expr.filters;
+jQuery.unique = Sizzle.uniqueSort;
+jQuery.text = Sizzle.getText;
+jQuery.isXMLDoc = Sizzle.isXML;
+jQuery.contains = Sizzle.contains;
+
+
+})();
+
+
+var runtil = /Until$/,
+ rparentsprev = /^(?:parents|prevUntil|prevAll)/,
+ // Note: This RegExp should be improved, or likely pulled from Sizzle
+ rmultiselector = /,/,
+ isSimple = /^.[^:#\[\.,]*$/,
+ slice = Array.prototype.slice,
+ POS = jQuery.expr.match.globalPOS,
+ // methods guaranteed to produce a unique set when starting from a unique set
+ guaranteedUnique = {
+ children: true,
+ contents: true,
+ next: true,
+ prev: true
+ };
+
+jQuery.fn.extend({
+ find: function( selector ) {
+ var self = this,
+ i, l;
+
+ if ( typeof selector !== "string" ) {
+ return jQuery( selector ).filter(function() {
+ for ( i = 0, l = self.length; i < l; i++ ) {
+ if ( jQuery.contains( self[ i ], this ) ) {
+ return true;
+ }
+ }
+ });
+ }
+
+ var ret = this.pushStack( "", "find", selector ),
+ length, n, r;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ length = ret.length;
+ jQuery.find( selector, this[i], ret );
+
+ if ( i > 0 ) {
+ // Make sure that the results are unique
+ for ( n = length; n < ret.length; n++ ) {
+ for ( r = 0; r < length; r++ ) {
+ if ( ret[r] === ret[n] ) {
+ ret.splice(n--, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ has: function( target ) {
+ var targets = jQuery( target );
+ return this.filter(function() {
+ for ( var i = 0, l = targets.length; i < l; i++ ) {
+ if ( jQuery.contains( this, targets[i] ) ) {
+ return true;
+ }
+ }
+ });
+ },
+
+ not: function( selector ) {
+ return this.pushStack( winnow(this, selector, false), "not", selector);
+ },
+
+ filter: function( selector ) {
+ return this.pushStack( winnow(this, selector, true), "filter", selector );
+ },
+
+ is: function( selector ) {
+ return !!selector && (
+ typeof selector === "string" ?
+ // If this is a positional selector, check membership in the returned set
+ // so $("p:first").is("p:last") won't return true for a doc with two "p".
+ POS.test( selector ) ?
+ jQuery( selector, this.context ).index( this[0] ) >= 0 :
+ jQuery.filter( selector, this ).length > 0 :
+ this.filter( selector ).length > 0 );
+ },
+
+ closest: function( selectors, context ) {
+ var ret = [], i, l, cur = this[0];
+
+ // Array (deprecated as of jQuery 1.7)
+ if ( jQuery.isArray( selectors ) ) {
+ var level = 1;
+
+ while ( cur && cur.ownerDocument && cur !== context ) {
+ for ( i = 0; i < selectors.length; i++ ) {
+
+ if ( jQuery( cur ).is( selectors[ i ] ) ) {
+ ret.push({ selector: selectors[ i ], elem: cur, level: level });
+ }
+ }
+
+ cur = cur.parentNode;
+ level++;
+ }
+
+ return ret;
+ }
+
+ // String
+ var pos = POS.test( selectors ) || typeof selectors !== "string" ?
+ jQuery( selectors, context || this.context ) :
+ 0;
+
+ for ( i = 0, l = this.length; i < l; i++ ) {
+ cur = this[i];
+
+ while ( cur ) {
+ if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
+ ret.push( cur );
+ break;
+
+ } else {
+ cur = cur.parentNode;
+ if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ ret = ret.length > 1 ? jQuery.unique( ret ) : ret;
+
+ return this.pushStack( ret, "closest", selectors );
+ },
+
+ // Determine the position of an element within
+ // the matched set of elements
+ index: function( elem ) {
+
+ // No argument, return index in parent
+ if ( !elem ) {
+ return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
+ }
+
+ // index in selector
+ if ( typeof elem === "string" ) {
+ return jQuery.inArray( this[0], jQuery( elem ) );
+ }
+
+ // Locate the position of the desired element
+ return jQuery.inArray(
+ // If it receives a jQuery object, the first element is used
+ elem.jquery ? elem[0] : elem, this );
+ },
+
+ add: function( selector, context ) {
+ var set = typeof selector === "string" ?
+ jQuery( selector, context ) :
+ jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
+ all = jQuery.merge( this.get(), set );
+
+ return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
+ all :
+ jQuery.unique( all ) );
+ },
+
+ andSelf: function() {
+ return this.add( this.prevObject );
+ }
+});
+
+// A painfully simple check to see if an element is disconnected
+// from a document (should be improved, where feasible).
+function isDisconnected( node ) {
+ return !node || !node.parentNode || node.parentNode.nodeType === 11;
+}
+
+jQuery.each({
+ parent: function( elem ) {
+ var parent = elem.parentNode;
+ return parent && parent.nodeType !== 11 ? parent : null;
+ },
+ parents: function( elem ) {
+ return jQuery.dir( elem, "parentNode" );
+ },
+ parentsUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "parentNode", until );
+ },
+ next: function( elem ) {
+ return jQuery.nth( elem, 2, "nextSibling" );
+ },
+ prev: function( elem ) {
+ return jQuery.nth( elem, 2, "previousSibling" );
+ },
+ nextAll: function( elem ) {
+ return jQuery.dir( elem, "nextSibling" );
+ },
+ prevAll: function( elem ) {
+ return jQuery.dir( elem, "previousSibling" );
+ },
+ nextUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "nextSibling", until );
+ },
+ prevUntil: function( elem, i, until ) {
+ return jQuery.dir( elem, "previousSibling", until );
+ },
+ siblings: function( elem ) {
+ return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
+ },
+ children: function( elem ) {
+ return jQuery.sibling( elem.firstChild );
+ },
+ contents: function( elem ) {
+ return jQuery.nodeName( elem, "iframe" ) ?
+ elem.contentDocument || elem.contentWindow.document :
+ jQuery.makeArray( elem.childNodes );
+ }
+}, function( name, fn ) {
+ jQuery.fn[ name ] = function( until, selector ) {
+ var ret = jQuery.map( this, fn, until );
+
+ if ( !runtil.test( name ) ) {
+ selector = until;
+ }
+
+ if ( selector && typeof selector === "string" ) {
+ ret = jQuery.filter( selector, ret );
+ }
+
+ ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;
+
+ if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
+ ret = ret.reverse();
+ }
+
+ return this.pushStack( ret, name, slice.call( arguments ).join(",") );
+ };
+});
+
+jQuery.extend({
+ filter: function( expr, elems, not ) {
+ if ( not ) {
+ expr = ":not(" + expr + ")";
+ }
+
+ return elems.length === 1 ?
+ jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
+ jQuery.find.matches(expr, elems);
+ },
+
+ dir: function( elem, dir, until ) {
+ var matched = [],
+ cur = elem[ dir ];
+
+ while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
+ if ( cur.nodeType === 1 ) {
+ matched.push( cur );
+ }
+ cur = cur[dir];
+ }
+ return matched;
+ },
+
+ nth: function( cur, result, dir, elem ) {
+ result = result || 1;
+ var num = 0;
+
+ for ( ; cur; cur = cur[dir] ) {
+ if ( cur.nodeType === 1 && ++num === result ) {
+ break;
+ }
+ }
+
+ return cur;
+ },
+
+ sibling: function( n, elem ) {
+ var r = [];
+
+ for ( ; n; n = n.nextSibling ) {
+ if ( n.nodeType === 1 && n !== elem ) {
+ r.push( n );
+ }
+ }
+
+ return r;
+ }
+});
+
+// Implement the identical functionality for filter and not
+function winnow( elements, qualifier, keep ) {
+
+ // Can't pass null or undefined to indexOf in Firefox 4
+ // Set to 0 to skip string check
+ qualifier = qualifier || 0;
+
+ if ( jQuery.isFunction( qualifier ) ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ var retVal = !!qualifier.call( elem, i, elem );
+ return retVal === keep;
+ });
+
+ } else if ( qualifier.nodeType ) {
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( elem === qualifier ) === keep;
+ });
+
+ } else if ( typeof qualifier === "string" ) {
+ var filtered = jQuery.grep(elements, function( elem ) {
+ return elem.nodeType === 1;
+ });
+
+ if ( isSimple.test( qualifier ) ) {
+ return jQuery.filter(qualifier, filtered, !keep);
+ } else {
+ qualifier = jQuery.filter( qualifier, filtered );
+ }
+ }
+
+ return jQuery.grep(elements, function( elem, i ) {
+ return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
+ });
+}
+
+
+
+
+function createSafeFragment( document ) {
+ var list = nodeNames.split( "|" ),
+ safeFrag = document.createDocumentFragment();
+
+ if ( safeFrag.createElement ) {
+ while ( list.length ) {
+ safeFrag.createElement(
+ list.pop()
+ );
+ }
+ }
+ return safeFrag;
+}
+
+var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
+ "header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
+ rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
+ rleadingWhitespace = /^\s+/,
+ rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,
+ rtagName = /<([\w:]+)/,
+ rtbody = /<tbody/i,
+ rhtml = /<|&#?\w+;/,
+ rnoInnerhtml = /<(?:script|style)/i,
+ rnocache = /<(?:script|object|embed|option|style)/i,
+ rnoshimcache = new RegExp("<(?:" + nodeNames + ")[\\s/>]", "i"),
+ // checked="checked" or checked
+ rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
+ rscriptType = /\/(java|ecma)script/i,
+ rcleanScript = /^\s*<!(?:\[CDATA\[|\-\-)/,
+ wrapMap = {
+ option: [ 1, "<select multiple='multiple'>", "</select>" ],
+ legend: [ 1, "<fieldset>", "</fieldset>" ],
+ thead: [ 1, "<table>", "</table>" ],
+ tr: [ 2, "<table><tbody>", "</tbody></table>" ],
+ td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
+ col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
+ area: [ 1, "<map>", "</map>" ],
+ _default: [ 0, "", "" ]
+ },
+ safeFragment = createSafeFragment( document );
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+// IE can't serialize <link> and <script> tags normally
+if ( !jQuery.support.htmlSerialize ) {
+ wrapMap._default = [ 1, "div<div>", "</div>" ];
+}
+
+jQuery.fn.extend({
+ text: function( value ) {
+ return jQuery.access( this, function( value ) {
+ return value === undefined ?
+ jQuery.text( this ) :
+ this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
+ }, null, value, arguments.length );
+ },
+
+ wrapAll: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapAll( html.call(this, i) );
+ });
+ }
+
+ if ( this[0] ) {
+ // The elements to wrap the target around
+ var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
+
+ if ( this[0].parentNode ) {
+ wrap.insertBefore( this[0] );
+ }
+
+ wrap.map(function() {
+ var elem = this;
+
+ while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
+ elem = elem.firstChild;
+ }
+
+ return elem;
+ }).append( this );
+ }
+
+ return this;
+ },
+
+ wrapInner: function( html ) {
+ if ( jQuery.isFunction( html ) ) {
+ return this.each(function(i) {
+ jQuery(this).wrapInner( html.call(this, i) );
+ });
+ }
+
+ return this.each(function() {
+ var self = jQuery( this ),
+ contents = self.contents();
+
+ if ( contents.length ) {
+ contents.wrapAll( html );
+
+ } else {
+ self.append( html );
+ }
+ });
+ },
+
+ wrap: function( html ) {
+ var isFunction = jQuery.isFunction( html );
+
+ return this.each(function(i) {
+ jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
+ });
+ },
+
+ unwrap: function() {
+ return this.parent().each(function() {
+ if ( !jQuery.nodeName( this, "body" ) ) {
+ jQuery( this ).replaceWith( this.childNodes );
+ }
+ }).end();
+ },
+
+ append: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.appendChild( elem );
+ }
+ });
+ },
+
+ prepend: function() {
+ return this.domManip(arguments, true, function( elem ) {
+ if ( this.nodeType === 1 ) {
+ this.insertBefore( elem, this.firstChild );
+ }
+ });
+ },
+
+ before: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this );
+ });
+ } else if ( arguments.length ) {
+ var set = jQuery.clean( arguments );
+ set.push.apply( set, this.toArray() );
+ return this.pushStack( set, "before", arguments );
+ }
+ },
+
+ after: function() {
+ if ( this[0] && this[0].parentNode ) {
+ return this.domManip(arguments, false, function( elem ) {
+ this.parentNode.insertBefore( elem, this.nextSibling );
+ });
+ } else if ( arguments.length ) {
+ var set = this.pushStack( this, "after", arguments );
+ set.push.apply( set, jQuery.clean(arguments) );
+ return set;
+ }
+ },
+
+ // keepData is for internal use only--do not document
+ remove: function( selector, keepData ) {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {
+ if ( !keepData && elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ jQuery.cleanData( [ elem ] );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ }
+ }
+
+ return this;
+ },
+
+ empty: function() {
+ for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName("*") );
+ }
+
+ // Remove any remaining nodes
+ while ( elem.firstChild ) {
+ elem.removeChild( elem.firstChild );
+ }
+ }
+
+ return this;
+ },
+
+ clone: function( dataAndEvents, deepDataAndEvents ) {
+ dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
+ deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
+
+ return this.map( function () {
+ return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
+ });
+ },
+
+ html: function( value ) {
+ return jQuery.access( this, function( value ) {
+ var elem = this[0] || {},
+ i = 0,
+ l = this.length;
+
+ if ( value === undefined ) {
+ return elem.nodeType === 1 ?
+ elem.innerHTML.replace( rinlinejQuery, "" ) :
+ null;
+ }
+
+
+ if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
+ ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
+ !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {
+
+ value = value.replace( rxhtmlTag, "<$1></$2>" );
+
+ try {
+ for (; i < l; i++ ) {
+ // Remove element nodes and prevent memory leaks
+ elem = this[i] || {};
+ if ( elem.nodeType === 1 ) {
+ jQuery.cleanData( elem.getElementsByTagName( "*" ) );
+ elem.innerHTML = value;
+ }
+ }
+
+ elem = 0;
+
+ // If using innerHTML throws an exception, use the fallback method
+ } catch(e) {}
+ }
+
+ if ( elem ) {
+ this.empty().append( value );
+ }
+ }, null, value, arguments.length );
+ },
+
+ replaceWith: function( value ) {
+ if ( this[0] && this[0].parentNode ) {
+ // Make sure that the elements are removed from the DOM before they are inserted
+ // this can help fix replacing a parent with child elements
+ if ( jQuery.isFunction( value ) ) {
+ return this.each(function(i) {
+ var self = jQuery(this), old = self.html();
+ self.replaceWith( value.call( this, i, old ) );
+ });
+ }
+
+ if ( typeof value !== "string" ) {
+ value = jQuery( value ).detach();
+ }
+
+ return this.each(function() {
+ var next = this.nextSibling,
+ parent = this.parentNode;
+
+ jQuery( this ).remove();
+
+ if ( next ) {
+ jQuery(next).before( value );
+ } else {
+ jQuery(parent).append( value );
+ }
+ });
+ } else {
+ return this.length ?
+ this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), "replaceWith", value ) :
+ this;
+ }
+ },
+
+ detach: function( selector ) {
+ return this.remove( selector, true );
+ },
+
+ domManip: function( args, table, callback ) {
+ var results, first, fragment, parent,
+ value = args[0],
+ scripts = [];
+
+ // We can't cloneNode fragments that contain checked, in WebKit
+ if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === "string" && rchecked.test( value ) ) {
+ return this.each(function() {
+ jQuery(this).domManip( args, table, callback, true );
+ });
+ }
+
+ if ( jQuery.isFunction(value) ) {
+ return this.each(function(i) {
+ var self = jQuery(this);
+ args[0] = value.call(this, i, table ? self.html() : undefined);
+ self.domManip( args, table, callback );
+ });
+ }
+
+ if ( this[0] ) {
+ parent = value && value.parentNode;
+
+ // If we're in a fragment, just use that instead of building a new one
+ if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {
+ results = { fragment: parent };
+
+ } else {
+ results = jQuery.buildFragment( args, this, scripts );
+ }
+
+ fragment = results.fragment;
+
+ if ( fragment.childNodes.length === 1 ) {
+ first = fragment = fragment.firstChild;
+ } else {
+ first = fragment.firstChild;
+ }
+
+ if ( first ) {
+ table = table && jQuery.nodeName( first, "tr" );
+
+ for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {
+ callback.call(
+ table ?
+ root(this[i], first) :
+ this[i],
+ // Make sure that we do not leak memory by inadvertently discarding
+ // the original fragment (which might have attached data) instead of
+ // using it; in addition, use the original fragment object for the last
+ // item instead of first because it can end up being emptied incorrectly
+ // in certain situations (Bug #8070).
+ // Fragments from the fragment cache must always be cloned and never used
+ // in place.
+ results.cacheable || ( l > 1 && i < lastIndex ) ?
+ jQuery.clone( fragment, true, true ) :
+ fragment
+ );
+ }
+ }
+
+ if ( scripts.length ) {
+ jQuery.each( scripts, function( i, elem ) {
+ if ( elem.src ) {
+ jQuery.ajax({
+ type: "GET",
+ global: false,
+ url: elem.src,
+ async: false,
+ dataType: "script"
+ });
+ } else {
+ jQuery.globalEval( ( elem.text || elem.textContent || elem.innerHTML || "" ).replace( rcleanScript, "/*$0*/" ) );
+ }
+
+ if ( elem.parentNode ) {
+ elem.parentNode.removeChild( elem );
+ }
+ });
+ }
+ }
+
+ return this;
+ }
+});
+
+function root( elem, cur ) {
+ return jQuery.nodeName(elem, "table") ?
+ (elem.getElementsByTagName("tbody")[0] ||
+ elem.appendChild(elem.ownerDocument.createElement("tbody"))) :
+ elem;
+}
+
+function cloneCopyEvent( src, dest ) {
+
+ if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {
+ return;
+ }
+
+ var type, i, l,
+ oldData = jQuery._data( src ),
+ curData = jQuery._data( dest, oldData ),
+ events = oldData.events;
+
+ if ( events ) {
+ delete curData.handle;
+ curData.events = {};
+
+ for ( type in events ) {
+ for ( i = 0, l = events[ type ].length; i < l; i++ ) {
+ jQuery.event.add( dest, type, events[ type ][ i ] );
+ }
+ }
+ }
+
+ // make the cloned public data object a copy from the original
+ if ( curData.data ) {
+ curData.data = jQuery.extend( {}, curData.data );
+ }
+}
+
+function cloneFixAttributes( src, dest ) {
+ var nodeName;
+
+ // We do not need to do anything for non-Elements
+ if ( dest.nodeType !== 1 ) {
+ return;
+ }
+
+ // clearAttributes removes the attributes, which we don't want,
+ // but also removes the attachEvent events, which we *do* want
+ if ( dest.clearAttributes ) {
+ dest.clearAttributes();
+ }
+
+ // mergeAttributes, in contrast, only merges back on the
+ // original attributes, not the events
+ if ( dest.mergeAttributes ) {
+ dest.mergeAttributes( src );
+ }
+
+ nodeName = dest.nodeName.toLowerCase();
+
+ // IE6-8 fail to clone children inside object elements that use
+ // the proprietary classid attribute value (rather than the type
+ // attribute) to identify the type of content to display
+ if ( nodeName === "object" ) {
+ dest.outerHTML = src.outerHTML;
+
+ } else if ( nodeName === "input" && (src.type === "checkbox" || src.type === "radio") ) {
+ // IE6-8 fails to persist the checked state of a cloned checkbox
+ // or radio button. Worse, IE6-7 fail to give the cloned element
+ // a checked appearance if the defaultChecked value isn't also set
+ if ( src.checked ) {
+ dest.defaultChecked = dest.checked = src.checked;
+ }
+
+ // IE6-7 get confused and end up setting the value of a cloned
+ // checkbox/radio button to an empty string instead of "on"
+ if ( dest.value !== src.value ) {
+ dest.value = src.value;
+ }
+
+ // IE6-8 fails to return the selected option to the default selected
+ // state when cloning options
+ } else if ( nodeName === "option" ) {
+ dest.selected = src.defaultSelected;
+
+ // IE6-8 fails to set the defaultValue to the correct value when
+ // cloning other types of input fields
+ } else if ( nodeName === "input" || nodeName === "textarea" ) {
+ dest.defaultValue = src.defaultValue;
+
+ // IE blanks contents when cloning scripts
+ } else if ( nodeName === "script" && dest.text !== src.text ) {
+ dest.text = src.text;
+ }
+
+ // Event data gets referenced instead of copied if the expando
+ // gets copied too
+ dest.removeAttribute( jQuery.expando );
+
+ // Clear flags for bubbling special change/submit events, they must
+ // be reattached when the newly cloned events are first activated
+ dest.removeAttribute( "_submit_attached" );
+ dest.removeAttribute( "_change_attached" );
+}
+
+jQuery.buildFragment = function( args, nodes, scripts ) {
+ var fragment, cacheable, cacheresults, doc,
+ first = args[ 0 ];
+
+ // nodes may contain either an explicit document object,
+ // a jQuery collection or context object.
+ // If nodes[0] contains a valid object to assign to doc
+ if ( nodes && nodes[0] ) {
+ doc = nodes[0].ownerDocument || nodes[0];
+ }
+
+ // Ensure that an attr object doesn't incorrectly stand in as a document object
+ // Chrome and Firefox seem to allow this to occur and will throw exception
+ // Fixes #8950
+ if ( !doc.createDocumentFragment ) {
+ doc = document;
+ }
+
+ // Only cache "small" (1/2 KB) HTML strings that are associated with the main document
+ // Cloning options loses the selected state, so don't cache them
+ // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment
+ // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache
+ // Lastly, IE6,7,8 will not correctly reuse cached fragments that were created from unknown elems #10501
+ if ( args.length === 1 && typeof first === "string" && first.length < 512 && doc === document &&
+ first.charAt(0) === "<" && !rnocache.test( first ) &&
+ (jQuery.support.checkClone || !rchecked.test( first )) &&
+ (jQuery.support.html5Clone || !rnoshimcache.test( first )) ) {
+
+ cacheable = true;
+
+ cacheresults = jQuery.fragments[ first ];
+ if ( cacheresults && cacheresults !== 1 ) {
+ fragment = cacheresults;
+ }
+ }
+
+ if ( !fragment ) {
+ fragment = doc.createDocumentFragment();
+ jQuery.clean( args, doc, fragment, scripts );
+ }
+
+ if ( cacheable ) {
+ jQuery.fragments[ first ] = cacheresults ? fragment : 1;
+ }
+
+ return { fragment: fragment, cacheable: cacheable };
+};
+
+jQuery.fragments = {};
+
+jQuery.each({
+ appendTo: "append",
+ prependTo: "prepend",
+ insertBefore: "before",
+ insertAfter: "after",
+ replaceAll: "replaceWith"
+}, function( name, original ) {
+ jQuery.fn[ name ] = function( selector ) {
+ var ret = [],
+ insert = jQuery( selector ),
+ parent = this.length === 1 && this[0].parentNode;
+
+ if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {
+ insert[ original ]( this[0] );
+ return this;
+
+ } else {
+ for ( var i = 0, l = insert.length; i < l; i++ ) {
+ var elems = ( i > 0 ? this.clone(true) : this ).get();
+ jQuery( insert[i] )[ original ]( elems );
+ ret = ret.concat( elems );
+ }
+
+ return this.pushStack( ret, name, insert.selector );
+ }
+ };
+});
+
+function getAll( elem ) {
+ if ( typeof elem.getElementsByTagName !== "undefined" ) {
+ return elem.getElementsByTagName( "*" );
+
+ } else if ( typeof elem.querySelectorAll !== "undefined" ) {
+ return elem.querySelectorAll( "*" );
+
+ } else {
+ return [];
+ }
+}
+
+// Used in clean, fixes the defaultChecked property
+function fixDefaultChecked( elem ) {
+ if ( elem.type === "checkbox" || elem.type === "radio" ) {
+ elem.defaultChecked = elem.checked;
+ }
+}
+// Finds all inputs and passes them to fixDefaultChecked
+function findInputs( elem ) {
+ var nodeName = ( elem.nodeName || "" ).toLowerCase();
+ if ( nodeName === "input" ) {
+ fixDefaultChecked( elem );
+ // Skip scripts, get other children
+ } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) {
+ jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked );
+ }
+}
+
+// Derived From: http://www.iecss.com/shimprove/javascript/shimprove.1-0-1.js
+function shimCloneNode( elem ) {
+ var div = document.createElement( "div" );
+ safeFragment.appendChild( div );
+
+ div.innerHTML = elem.outerHTML;
+ return div.firstChild;
+}
+
+jQuery.extend({
+ clone: function( elem, dataAndEvents, deepDataAndEvents ) {
+ var srcElements,
+ destElements,
+ i,
+ // IE<=8 does not properly clone detached, unknown element nodes
+ clone = jQuery.support.html5Clone || jQuery.isXMLDoc(elem) || !rnoshimcache.test( "<" + elem.nodeName + ">" ) ?
+ elem.cloneNode( true ) :
+ shimCloneNode( elem );
+
+ if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&
+ (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {
+ // IE copies events bound via attachEvent when using cloneNode.
+ // Calling detachEvent on the clone will also remove the events
+ // from the original. In order to get around this, we use some
+ // proprietary methods to clear the events. Thanks to MooTools
+ // guys for this hotness.
+
+ cloneFixAttributes( elem, clone );
+
+ // Using Sizzle here is crazy slow, so we use getElementsByTagName instead
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ // Weird iteration because IE will replace the length property
+ // with an element if you are cloning the body and one of the
+ // elements on the page has a name or id of "length"
+ for ( i = 0; srcElements[i]; ++i ) {
+ // Ensure that the destination node is not null; Fixes #9587
+ if ( destElements[i] ) {
+ cloneFixAttributes( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ // Copy the events from the original to the clone
+ if ( dataAndEvents ) {
+ cloneCopyEvent( elem, clone );
+
+ if ( deepDataAndEvents ) {
+ srcElements = getAll( elem );
+ destElements = getAll( clone );
+
+ for ( i = 0; srcElements[i]; ++i ) {
+ cloneCopyEvent( srcElements[i], destElements[i] );
+ }
+ }
+ }
+
+ srcElements = destElements = null;
+
+ // Return the cloned set
+ return clone;
+ },
+
+ clean: function( elems, context, fragment, scripts ) {
+ var checkScriptType, script, j,
+ ret = [];
+
+ context = context || document;
+
+ // !context.createElement fails in IE with an error but returns typeof 'object'
+ if ( typeof context.createElement === "undefined" ) {
+ context = context.ownerDocument || context[0] && context[0].ownerDocument || document;
+ }
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( typeof elem === "number" ) {
+ elem += "";
+ }
+
+ if ( !elem ) {
+ continue;
+ }
+
+ // Convert html string into DOM nodes
+ if ( typeof elem === "string" ) {
+ if ( !rhtml.test( elem ) ) {
+ elem = context.createTextNode( elem );
+ } else {
+ // Fix "XHTML"-style tags in all browsers
+ elem = elem.replace(rxhtmlTag, "<$1></$2>");
+
+ // Trim whitespace, otherwise indexOf won't work as expected
+ var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(),
+ wrap = wrapMap[ tag ] || wrapMap._default,
+ depth = wrap[0],
+ div = context.createElement("div"),
+ safeChildNodes = safeFragment.childNodes,
+ remove;
+
+ // Append wrapper element to unknown element safe doc fragment
+ if ( context === document ) {
+ // Use the fragment we've already created for this document
+ safeFragment.appendChild( div );
+ } else {
+ // Use a fragment created with the owner document
+ createSafeFragment( context ).appendChild( div );
+ }
+
+ // Go to html and back, then peel off extra wrappers
+ div.innerHTML = wrap[1] + elem + wrap[2];
+
+ // Move to the right depth
+ while ( depth-- ) {
+ div = div.lastChild;
+ }
+
+ // Remove IE's autoinserted <tbody> from table fragments
+ if ( !jQuery.support.tbody ) {
+
+ // String was a <table>, *may* have spurious <tbody>
+ var hasBody = rtbody.test(elem),
+ tbody = tag === "table" && !hasBody ?
+ div.firstChild && div.firstChild.childNodes :
+
+ // String was a bare <thead> or <tfoot>
+ wrap[1] === "<table>" && !hasBody ?
+ div.childNodes :
+ [];
+
+ for ( j = tbody.length - 1; j >= 0 ; --j ) {
+ if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) {
+ tbody[ j ].parentNode.removeChild( tbody[ j ] );
+ }
+ }
+ }
+
+ // IE completely kills leading whitespace when innerHTML is used
+ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {
+ div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );
+ }
+
+ elem = div.childNodes;
+
+ // Clear elements from DocumentFragment (safeFragment or otherwise)
+ // to avoid hoarding elements. Fixes #11356
+ if ( div ) {
+ div.parentNode.removeChild( div );
+
+ // Guard against -1 index exceptions in FF3.6
+ if ( safeChildNodes.length > 0 ) {
+ remove = safeChildNodes[ safeChildNodes.length - 1 ];
+
+ if ( remove && remove.parentNode ) {
+ remove.parentNode.removeChild( remove );
+ }
+ }
+ }
+ }
+ }
+
+ // Resets defaultChecked for any radios and checkboxes
+ // about to be appended to the DOM in IE 6/7 (#8060)
+ var len;
+ if ( !jQuery.support.appendChecked ) {
+ if ( elem[0] && typeof (len = elem.length) === "number" ) {
+ for ( j = 0; j < len; j++ ) {
+ findInputs( elem[j] );
+ }
+ } else {
+ findInputs( elem );
+ }
+ }
+
+ if ( elem.nodeType ) {
+ ret.push( elem );
+ } else {
+ ret = jQuery.merge( ret, elem );
+ }
+ }
+
+ if ( fragment ) {
+ checkScriptType = function( elem ) {
+ return !elem.type || rscriptType.test( elem.type );
+ };
+ for ( i = 0; ret[i]; i++ ) {
+ script = ret[i];
+ if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) {
+ scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script );
+
+ } else {
+ if ( script.nodeType === 1 ) {
+ var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType );
+
+ ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
+ }
+ fragment.appendChild( script );
+ }
+ }
+ }
+
+ return ret;
+ },
+
+ cleanData: function( elems ) {
+ var data, id,
+ cache = jQuery.cache,
+ special = jQuery.event.special,
+ deleteExpando = jQuery.support.deleteExpando;
+
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
+ continue;
+ }
+
+ id = elem[ jQuery.expando ];
+
+ if ( id ) {
+ data = cache[ id ];
+
+ if ( data && data.events ) {
+ for ( var type in data.events ) {
+ if ( special[ type ] ) {
+ jQuery.event.remove( elem, type );
+
+ // This is a shortcut to avoid jQuery.event.remove's overhead
+ } else {
+ jQuery.removeEvent( elem, type, data.handle );
+ }
+ }
+
+ // Null the DOM reference to avoid IE6/7/8 leak (#7054)
+ if ( data.handle ) {
+ data.handle.elem = null;
+ }
+ }
+
+ if ( deleteExpando ) {
+ delete elem[ jQuery.expando ];
+
+ } else if ( elem.removeAttribute ) {
+ elem.removeAttribute( jQuery.expando );
+ }
+
+ delete cache[ id ];
+ }
+ }
+ }
+});
+
+
+
+
+var ralpha = /alpha\([^)]*\)/i,
+ ropacity = /opacity=([^)]*)/,
+ // fixed for IE9, see #8346
+ rupper = /([A-Z]|^ms)/g,
+ rnum = /^[\-+]?(?:\d*\.)?\d+$/i,
+ rnumnonpx = /^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,
+ rrelNum = /^([\-+])=([\-+.\de]+)/,
+ rmargin = /^margin/,
+
+ cssShow = { position: "absolute", visibility: "hidden", display: "block" },
+
+ // order is important!
+ cssExpand = [ "Top", "Right", "Bottom", "Left" ],
+
+ curCSS,
+
+ getComputedStyle,
+ currentStyle;
+
+jQuery.fn.css = function( name, value ) {
+ return jQuery.access( this, function( elem, name, value ) {
+ return value !== undefined ?
+ jQuery.style( elem, name, value ) :
+ jQuery.css( elem, name );
+ }, name, value, arguments.length > 1 );
+};
+
+jQuery.extend({
+ // Add in style property hooks for overriding the default
+ // behavior of getting and setting a style property
+ cssHooks: {
+ opacity: {
+ get: function( elem, computed ) {
+ if ( computed ) {
+ // We should always get a number back from opacity
+ var ret = curCSS( elem, "opacity" );
+ return ret === "" ? "1" : ret;
+
+ } else {
+ return elem.style.opacity;
+ }
+ }
+ }
+ },
+
+ // Exclude the following css properties to add px
+ cssNumber: {
+ "fillOpacity": true,
+ "fontWeight": true,
+ "lineHeight": true,
+ "opacity": true,
+ "orphans": true,
+ "widows": true,
+ "zIndex": true,
+ "zoom": true
+ },
+
+ // Add in properties whose names you wish to fix before
+ // setting or getting the value
+ cssProps: {
+ // normalize float css property
+ "float": jQuery.support.cssFloat ? "cssFloat" : "styleFloat"
+ },
+
+ // Get and set the style property on a DOM Node
+ style: function( elem, name, value, extra ) {
+ // Don't set styles on text and comment nodes
+ if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
+ return;
+ }
+
+ // Make sure that we're working with the right name
+ var ret, type, origName = jQuery.camelCase( name ),
+ style = elem.style, hooks = jQuery.cssHooks[ origName ];
+
+ name = jQuery.cssProps[ origName ] || origName;
+
+ // Check if we're setting a value
+ if ( value !== undefined ) {
+ type = typeof value;
+
+ // convert relative number strings (+= or -=) to relative numbers. #7345
+ if ( type === "string" && (ret = rrelNum.exec( value )) ) {
+ value = ( +( ret[1] + 1) * +ret[2] ) + parseFloat( jQuery.css( elem, name ) );
+ // Fixes bug #9237
+ type = "number";
+ }
+
+ // Make sure that NaN and null values aren't set. See: #7116
+ if ( value == null || type === "number" && isNaN( value ) ) {
+ return;
+ }
+
+ // If a number was passed in, add 'px' to the (except for certain CSS properties)
+ if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
+ value += "px";
+ }
+
+ // If a hook was provided, use that value, otherwise just set the specified value
+ if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {
+ // Wrapped to prevent IE from throwing errors when 'invalid' values are provided
+ // Fixes bug #5509
+ try {
+ style[ name ] = value;
+ } catch(e) {}
+ }
+
+ } else {
+ // If a hook was provided get the non-computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
+ return ret;
+ }
+
+ // Otherwise just get the value from the style object
+ return style[ name ];
+ }
+ },
+
+ css: function( elem, name, extra ) {
+ var ret, hooks;
+
+ // Make sure that we're working with the right name
+ name = jQuery.camelCase( name );
+ hooks = jQuery.cssHooks[ name ];
+ name = jQuery.cssProps[ name ] || name;
+
+ // cssFloat needs a special treatment
+ if ( name === "cssFloat" ) {
+ name = "float";
+ }
+
+ // If a hook was provided get the computed value from there
+ if ( hooks && "get" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {
+ return ret;
+
+ // Otherwise, if a way to get the computed value exists, use that
+ } else if ( curCSS ) {
+ return curCSS( elem, name );
+ }
+ },
+
+ // A method for quickly swapping in/out CSS properties to get correct calculations
+ swap: function( elem, options, callback ) {
+ var old = {},
+ ret, name;
+
+ // Remember the old values, and insert the new ones
+ for ( name in options ) {
+ old[ name ] = elem.style[ name ];
+ elem.style[ name ] = options[ name ];
+ }
+
+ ret = callback.call( elem );
+
+ // Revert the old values
+ for ( name in options ) {
+ elem.style[ name ] = old[ name ];
+ }
+
+ return ret;
+ }
+});
+
+// DEPRECATED in 1.3, Use jQuery.css() instead
+jQuery.curCSS = jQuery.css;
+
+if ( document.defaultView && document.defaultView.getComputedStyle ) {
+ getComputedStyle = function( elem, name ) {
+ var ret, defaultView, computedStyle, width,
+ style = elem.style;
+
+ name = name.replace( rupper, "-$1" ).toLowerCase();
+
+ if ( (defaultView = elem.ownerDocument.defaultView) &&
+ (computedStyle = defaultView.getComputedStyle( elem, null )) ) {
+
+ ret = computedStyle.getPropertyValue( name );
+ if ( ret === "" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ ret = jQuery.style( elem, name );
+ }
+ }
+
+ // A tribute to the "awesome hack by Dean Edwards"
+ // WebKit uses "computed value (percentage if specified)" instead of "used value" for margins
+ // which is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
+ if ( !jQuery.support.pixelMargin && computedStyle && rmargin.test( name ) && rnumnonpx.test( ret ) ) {
+ width = style.width;
+ style.width = ret;
+ ret = computedStyle.width;
+ style.width = width;
+ }
+
+ return ret;
+ };
+}
+
+if ( document.documentElement.currentStyle ) {
+ currentStyle = function( elem, name ) {
+ var left, rsLeft, uncomputed,
+ ret = elem.currentStyle && elem.currentStyle[ name ],
+ style = elem.style;
+
+ // Avoid setting ret to empty string here
+ // so we don't default to auto
+ if ( ret == null && style && (uncomputed = style[ name ]) ) {
+ ret = uncomputed;
+ }
+
+ // From the awesome hack by Dean Edwards
+ // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291
+
+ // If we're not dealing with a regular pixel number
+ // but a number that has a weird ending, we need to convert it to pixels
+ if ( rnumnonpx.test( ret ) ) {
+
+ // Remember the original values
+ left = style.left;
+ rsLeft = elem.runtimeStyle && elem.runtimeStyle.left;
+
+ // Put in the new values to get a computed value out
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = elem.currentStyle.left;
+ }
+ style.left = name === "fontSize" ? "1em" : ret;
+ ret = style.pixelLeft + "px";
+
+ // Revert the changed values
+ style.left = left;
+ if ( rsLeft ) {
+ elem.runtimeStyle.left = rsLeft;
+ }
+ }
+
+ return ret === "" ? "auto" : ret;
+ };
+}
+
+curCSS = getComputedStyle || currentStyle;
+
+function getWidthOrHeight( elem, name, extra ) {
+
+ // Start with offset property
+ var val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
+ i = name === "width" ? 1 : 0,
+ len = 4;
+
+ if ( val > 0 ) {
+ if ( extra !== "border" ) {
+ for ( ; i < len; i += 2 ) {
+ if ( !extra ) {
+ val -= parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ] ) ) || 0;
+ } else {
+ val -= parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+ }
+
+ // Fall back to computed then uncomputed css if necessary
+ val = curCSS( elem, name );
+ if ( val < 0 || val == null ) {
+ val = elem.style[ name ];
+ }
+
+ // Computed unit is not pixels. Stop here and return.
+ if ( rnumnonpx.test(val) ) {
+ return val;
+ }
+
+ // Normalize "", auto, and prepare for extra
+ val = parseFloat( val ) || 0;
+
+ // Add padding, border, margin
+ if ( extra ) {
+ for ( ; i < len; i += 2 ) {
+ val += parseFloat( jQuery.css( elem, "padding" + cssExpand[ i ] ) ) || 0;
+ if ( extra !== "padding" ) {
+ val += parseFloat( jQuery.css( elem, "border" + cssExpand[ i ] + "Width" ) ) || 0;
+ }
+ if ( extra === "margin" ) {
+ val += parseFloat( jQuery.css( elem, extra + cssExpand[ i ]) ) || 0;
+ }
+ }
+ }
+
+ return val + "px";
+}
+
+jQuery.each([ "height", "width" ], function( i, name ) {
+ jQuery.cssHooks[ name ] = {
+ get: function( elem, computed, extra ) {
+ if ( computed ) {
+ if ( elem.offsetWidth !== 0 ) {
+ return getWidthOrHeight( elem, name, extra );
+ } else {
+ return jQuery.swap( elem, cssShow, function() {
+ return getWidthOrHeight( elem, name, extra );
+ });
+ }
+ }
+ },
+
+ set: function( elem, value ) {
+ return rnum.test( value ) ?
+ value + "px" :
+ value;
+ }
+ };
+});
+
+if ( !jQuery.support.opacity ) {
+ jQuery.cssHooks.opacity = {
+ get: function( elem, computed ) {
+ // IE uses filters for opacity
+ return ropacity.test( (computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || "" ) ?
+ ( parseFloat( RegExp.$1 ) / 100 ) + "" :
+ computed ? "1" : "";
+ },
+
+ set: function( elem, value ) {
+ var style = elem.style,
+ currentStyle = elem.currentStyle,
+ opacity = jQuery.isNumeric( value ) ? "alpha(opacity=" + value * 100 + ")" : "",
+ filter = currentStyle && currentStyle.filter || style.filter || "";
+
+ // IE has trouble with opacity if it does not have layout
+ // Force it by setting the zoom level
+ style.zoom = 1;
+
+ // if setting opacity to 1, and no other filters exist - attempt to remove filter attribute #6652
+ if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {
+
+ // Setting style.filter to null, "" & " " still leave "filter:" in the cssText
+ // if "filter:" is present at all, clearType is disabled, we want to avoid this
+ // style.removeAttribute is IE Only, but so apparently is this code path...
+ style.removeAttribute( "filter" );
+
+ // if there there is no filter style applied in a css rule, we are done
+ if ( currentStyle && !currentStyle.filter ) {
+ return;
+ }
+ }
+
+ // otherwise, set new filter values
+ style.filter = ralpha.test( filter ) ?
+ filter.replace( ralpha, opacity ) :
+ filter + " " + opacity;
+ }
+ };
+}
+
+jQuery(function() {
+ // This hook cannot be added until DOM ready because the support test
+ // for it is not run until after DOM ready
+ if ( !jQuery.support.reliableMarginRight ) {
+ jQuery.cssHooks.marginRight = {
+ get: function( elem, computed ) {
+ // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
+ // Work around by temporarily setting element display to inline-block
+ return jQuery.swap( elem, { "display": "inline-block" }, function() {
+ if ( computed ) {
+ return curCSS( elem, "margin-right" );
+ } else {
+ return elem.style.marginRight;
+ }
+ });
+ }
+ };
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.hidden = function( elem ) {
+ var width = elem.offsetWidth,
+ height = elem.offsetHeight;
+
+ return ( width === 0 && height === 0 ) || (!jQuery.support.reliableHiddenOffsets && ((elem.style && elem.style.display) || jQuery.css( elem, "display" )) === "none");
+ };
+
+ jQuery.expr.filters.visible = function( elem ) {
+ return !jQuery.expr.filters.hidden( elem );
+ };
+}
+
+// These hooks are used by animate to expand properties
+jQuery.each({
+ margin: "",
+ padding: "",
+ border: "Width"
+}, function( prefix, suffix ) {
+
+ jQuery.cssHooks[ prefix + suffix ] = {
+ expand: function( value ) {
+ var i,
+
+ // assumes a single number if not a string
+ parts = typeof value === "string" ? value.split(" ") : [ value ],
+ expanded = {};
+
+ for ( i = 0; i < 4; i++ ) {
+ expanded[ prefix + cssExpand[ i ] + suffix ] =
+ parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
+ }
+
+ return expanded;
+ }
+ };
+});
+
+
+
+
+var r20 = /%20/g,
+ rbracket = /\[\]$/,
+ rCRLF = /\r?\n/g,
+ rhash = /#.*$/,
+ rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/mg, // IE leaves an \r character at EOL
+ rinput = /^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,
+ // #7653, #8125, #8152: local protocol detection
+ rlocalProtocol = /^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,
+ rnoContent = /^(?:GET|HEAD)$/,
+ rprotocol = /^\/\//,
+ rquery = /\?/,
+ rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
+ rselectTextarea = /^(?:select|textarea)/i,
+ rspacesAjax = /\s+/,
+ rts = /([?&])_=[^&]*/,
+ rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,
+
+ // Keep a copy of the old load method
+ _load = jQuery.fn.load,
+
+ /* Prefilters
+ * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
+ * 2) These are called:
+ * - BEFORE asking for a transport
+ * - AFTER param serialization (s.data is a string if s.processData is true)
+ * 3) key is the dataType
+ * 4) the catchall symbol "*" can be used
+ * 5) execution will start with transport dataType and THEN continue down to "*" if needed
+ */
+ prefilters = {},
+
+ /* Transports bindings
+ * 1) key is the dataType
+ * 2) the catchall symbol "*" can be used
+ * 3) selection will start with transport dataType and THEN go to "*" if needed
+ */
+ transports = {},
+
+ // Document location
+ ajaxLocation,
+
+ // Document location segments
+ ajaxLocParts,
+
+ // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
+ allTypes = ["*/"] + ["*"];
+
+// #8138, IE may throw an exception when accessing
+// a field from window.location if document.domain has been set
+try {
+ ajaxLocation = location.href;
+} catch( e ) {
+ // Use the href attribute of an A element
+ // since IE will modify it given document.location
+ ajaxLocation = document.createElement( "a" );
+ ajaxLocation.href = "";
+ ajaxLocation = ajaxLocation.href;
+}
+
+// Segment location into parts
+ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
+
+// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
+function addToPrefiltersOrTransports( structure ) {
+
+ // dataTypeExpression is optional and defaults to "*"
+ return function( dataTypeExpression, func ) {
+
+ if ( typeof dataTypeExpression !== "string" ) {
+ func = dataTypeExpression;
+ dataTypeExpression = "*";
+ }
+
+ if ( jQuery.isFunction( func ) ) {
+ var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),
+ i = 0,
+ length = dataTypes.length,
+ dataType,
+ list,
+ placeBefore;
+
+ // For each dataType in the dataTypeExpression
+ for ( ; i < length; i++ ) {
+ dataType = dataTypes[ i ];
+ // We control if we're asked to add before
+ // any existing element
+ placeBefore = /^\+/.test( dataType );
+ if ( placeBefore ) {
+ dataType = dataType.substr( 1 ) || "*";
+ }
+ list = structure[ dataType ] = structure[ dataType ] || [];
+ // then we add to the structure accordingly
+ list[ placeBefore ? "unshift" : "push" ]( func );
+ }
+ }
+ };
+}
+
+// Base inspection function for prefilters and transports
+function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,
+ dataType /* internal */, inspected /* internal */ ) {
+
+ dataType = dataType || options.dataTypes[ 0 ];
+ inspected = inspected || {};
+
+ inspected[ dataType ] = true;
+
+ var list = structure[ dataType ],
+ i = 0,
+ length = list ? list.length : 0,
+ executeOnly = ( structure === prefilters ),
+ selection;
+
+ for ( ; i < length && ( executeOnly || !selection ); i++ ) {
+ selection = list[ i ]( options, originalOptions, jqXHR );
+ // If we got redirected to another dataType
+ // we try there if executing only and not done already
+ if ( typeof selection === "string" ) {
+ if ( !executeOnly || inspected[ selection ] ) {
+ selection = undefined;
+ } else {
+ options.dataTypes.unshift( selection );
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, selection, inspected );
+ }
+ }
+ }
+ // If we're only executing or nothing was selected
+ // we try the catchall dataType if not done already
+ if ( ( executeOnly || !selection ) && !inspected[ "*" ] ) {
+ selection = inspectPrefiltersOrTransports(
+ structure, options, originalOptions, jqXHR, "*", inspected );
+ }
+ // unnecessary when only executing (prefilters)
+ // but it'll be ignored by the caller in that case
+ return selection;
+}
+
+// A special extend for ajax options
+// that takes "flat" options (not to be deep extended)
+// Fixes #9887
+function ajaxExtend( target, src ) {
+ var key, deep,
+ flatOptions = jQuery.ajaxSettings.flatOptions || {};
+ for ( key in src ) {
+ if ( src[ key ] !== undefined ) {
+ ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
+ }
+ }
+ if ( deep ) {
+ jQuery.extend( true, target, deep );
+ }
+}
+
+jQuery.fn.extend({
+ load: function( url, params, callback ) {
+ if ( typeof url !== "string" && _load ) {
+ return _load.apply( this, arguments );
+
+ // Don't do a request if no elements are being requested
+ } else if ( !this.length ) {
+ return this;
+ }
+
+ var off = url.indexOf( " " );
+ if ( off >= 0 ) {
+ var selector = url.slice( off, url.length );
+ url = url.slice( 0, off );
+ }
+
+ // Default to a GET request
+ var type = "GET";
+
+ // If the second parameter was provided
+ if ( params ) {
+ // If it's a function
+ if ( jQuery.isFunction( params ) ) {
+ // We assume that it's the callback
+ callback = params;
+ params = undefined;
+
+ // Otherwise, build a param string
+ } else if ( typeof params === "object" ) {
+ params = jQuery.param( params, jQuery.ajaxSettings.traditional );
+ type = "POST";
+ }
+ }
+
+ var self = this;
+
+ // Request the remote document
+ jQuery.ajax({
+ url: url,
+ type: type,
+ dataType: "html",
+ data: params,
+ // Complete callback (responseText is used internally)
+ complete: function( jqXHR, status, responseText ) {
+ // Store the response as specified by the jqXHR object
+ responseText = jqXHR.responseText;
+ // If successful, inject the HTML into all the matched elements
+ if ( jqXHR.isResolved() ) {
+ // #4825: Get the actual response in case
+ // a dataFilter is present in ajaxSettings
+ jqXHR.done(function( r ) {
+ responseText = r;
+ });
+ // See if a selector was specified
+ self.html( selector ?
+ // Create a dummy div to hold the results
+ jQuery("<div>")
+ // inject the contents of the document in, removing the scripts
+ // to avoid any 'Permission Denied' errors in IE
+ .append(responseText.replace(rscript, ""))
+
+ // Locate the specified elements
+ .find(selector) :
+
+ // If not, just inject the full result
+ responseText );
+ }
+
+ if ( callback ) {
+ self.each( callback, [ responseText, status, jqXHR ] );
+ }
+ }
+ });
+
+ return this;
+ },
+
+ serialize: function() {
+ return jQuery.param( this.serializeArray() );
+ },
+
+ serializeArray: function() {
+ return this.map(function(){
+ return this.elements ? jQuery.makeArray( this.elements ) : this;
+ })
+ .filter(function(){
+ return this.name && !this.disabled &&
+ ( this.checked || rselectTextarea.test( this.nodeName ) ||
+ rinput.test( this.type ) );
+ })
+ .map(function( i, elem ){
+ var val = jQuery( this ).val();
+
+ return val == null ?
+ null :
+ jQuery.isArray( val ) ?
+ jQuery.map( val, function( val, i ){
+ return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }) :
+ { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
+ }).get();
+ }
+});
+
+// Attach a bunch of functions for handling common AJAX events
+jQuery.each( "ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split( " " ), function( i, o ){
+ jQuery.fn[ o ] = function( f ){
+ return this.on( o, f );
+ };
+});
+
+jQuery.each( [ "get", "post" ], function( i, method ) {
+ jQuery[ method ] = function( url, data, callback, type ) {
+ // shift arguments if data argument was omitted
+ if ( jQuery.isFunction( data ) ) {
+ type = type || callback;
+ callback = data;
+ data = undefined;
+ }
+
+ return jQuery.ajax({
+ type: method,
+ url: url,
+ data: data,
+ success: callback,
+ dataType: type
+ });
+ };
+});
+
+jQuery.extend({
+
+ getScript: function( url, callback ) {
+ return jQuery.get( url, undefined, callback, "script" );
+ },
+
+ getJSON: function( url, data, callback ) {
+ return jQuery.get( url, data, callback, "json" );
+ },
+
+ // Creates a full fledged settings object into target
+ // with both ajaxSettings and settings fields.
+ // If target is omitted, writes into ajaxSettings.
+ ajaxSetup: function( target, settings ) {
+ if ( settings ) {
+ // Building a settings object
+ ajaxExtend( target, jQuery.ajaxSettings );
+ } else {
+ // Extending ajaxSettings
+ settings = target;
+ target = jQuery.ajaxSettings;
+ }
+ ajaxExtend( target, settings );
+ return target;
+ },
+
+ ajaxSettings: {
+ url: ajaxLocation,
+ isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
+ global: true,
+ type: "GET",
+ contentType: "application/x-www-form-urlencoded; charset=UTF-8",
+ processData: true,
+ async: true,
+ /*
+ timeout: 0,
+ data: null,
+ dataType: null,
+ username: null,
+ password: null,
+ cache: null,
+ traditional: false,
+ headers: {},
+ */
+
+ accepts: {
+ xml: "application/xml, text/xml",
+ html: "text/html",
+ text: "text/plain",
+ json: "application/json, text/javascript",
+ "*": allTypes
+ },
+
+ contents: {
+ xml: /xml/,
+ html: /html/,
+ json: /json/
+ },
+
+ responseFields: {
+ xml: "responseXML",
+ text: "responseText"
+ },
+
+ // List of data converters
+ // 1) key format is "source_type destination_type" (a single space in-between)
+ // 2) the catchall symbol "*" can be used for source_type
+ converters: {
+
+ // Convert anything to text
+ "* text": window.String,
+
+ // Text to html (true = no transformation)
+ "text html": true,
+
+ // Evaluate text as a json expression
+ "text json": jQuery.parseJSON,
+
+ // Parse text as xml
+ "text xml": jQuery.parseXML
+ },
+
+ // For options that shouldn't be deep extended:
+ // you can add your own custom options here if
+ // and when you create one that shouldn't be
+ // deep extended (see ajaxExtend)
+ flatOptions: {
+ context: true,
+ url: true
+ }
+ },
+
+ ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
+ ajaxTransport: addToPrefiltersOrTransports( transports ),
+
+ // Main method
+ ajax: function( url, options ) {
+
+ // If url is an object, simulate pre-1.5 signature
+ if ( typeof url === "object" ) {
+ options = url;
+ url = undefined;
+ }
+
+ // Force options to be an object
+ options = options || {};
+
+ var // Create the final options object
+ s = jQuery.ajaxSetup( {}, options ),
+ // Callbacks context
+ callbackContext = s.context || s,
+ // Context for global events
+ // It's the callbackContext if one was provided in the options
+ // and if it's a DOM node or a jQuery collection
+ globalEventContext = callbackContext !== s &&
+ ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?
+ jQuery( callbackContext ) : jQuery.event,
+ // Deferreds
+ deferred = jQuery.Deferred(),
+ completeDeferred = jQuery.Callbacks( "once memory" ),
+ // Status-dependent callbacks
+ statusCode = s.statusCode || {},
+ // ifModified key
+ ifModifiedKey,
+ // Headers (they are sent all at once)
+ requestHeaders = {},
+ requestHeadersNames = {},
+ // Response headers
+ responseHeadersString,
+ responseHeaders,
+ // transport
+ transport,
+ // timeout handle
+ timeoutTimer,
+ // Cross-domain detection vars
+ parts,
+ // The jqXHR state
+ state = 0,
+ // To know if global events are to be dispatched
+ fireGlobals,
+ // Loop variable
+ i,
+ // Fake xhr
+ jqXHR = {
+
+ readyState: 0,
+
+ // Caches the header
+ setRequestHeader: function( name, value ) {
+ if ( !state ) {
+ var lname = name.toLowerCase();
+ name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
+ requestHeaders[ name ] = value;
+ }
+ return this;
+ },
+
+ // Raw string
+ getAllResponseHeaders: function() {
+ return state === 2 ? responseHeadersString : null;
+ },
+
+ // Builds headers hashtable if needed
+ getResponseHeader: function( key ) {
+ var match;
+ if ( state === 2 ) {
+ if ( !responseHeaders ) {
+ responseHeaders = {};
+ while( ( match = rheaders.exec( responseHeadersString ) ) ) {
+ responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
+ }
+ }
+ match = responseHeaders[ key.toLowerCase() ];
+ }
+ return match === undefined ? null : match;
+ },
+
+ // Overrides response content-type header
+ overrideMimeType: function( type ) {
+ if ( !state ) {
+ s.mimeType = type;
+ }
+ return this;
+ },
+
+ // Cancel the request
+ abort: function( statusText ) {
+ statusText = statusText || "abort";
+ if ( transport ) {
+ transport.abort( statusText );
+ }
+ done( 0, statusText );
+ return this;
+ }
+ };
+
+ // Callback for when everything is done
+ // It is defined here because jslint complains if it is declared
+ // at the end of the function (which would be more logical and readable)
+ function done( status, nativeStatusText, responses, headers ) {
+
+ // Called once
+ if ( state === 2 ) {
+ return;
+ }
+
+ // State is "done" now
+ state = 2;
+
+ // Clear timeout if it exists
+ if ( timeoutTimer ) {
+ clearTimeout( timeoutTimer );
+ }
+
+ // Dereference transport for early garbage collection
+ // (no matter how long the jqXHR object will be used)
+ transport = undefined;
+
+ // Cache response headers
+ responseHeadersString = headers || "";
+
+ // Set readyState
+ jqXHR.readyState = status > 0 ? 4 : 0;
+
+ var isSuccess,
+ success,
+ error,
+ statusText = nativeStatusText,
+ response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,
+ lastModified,
+ etag;
+
+ // If successful, handle type chaining
+ if ( status >= 200 && status < 300 || status === 304 ) {
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+
+ if ( ( lastModified = jqXHR.getResponseHeader( "Last-Modified" ) ) ) {
+ jQuery.lastModified[ ifModifiedKey ] = lastModified;
+ }
+ if ( ( etag = jqXHR.getResponseHeader( "Etag" ) ) ) {
+ jQuery.etag[ ifModifiedKey ] = etag;
+ }
+ }
+
+ // If not modified
+ if ( status === 304 ) {
+
+ statusText = "notmodified";
+ isSuccess = true;
+
+ // If we have data
+ } else {
+
+ try {
+ success = ajaxConvert( s, response );
+ statusText = "success";
+ isSuccess = true;
+ } catch(e) {
+ // We have a parsererror
+ statusText = "parsererror";
+ error = e;
+ }
+ }
+ } else {
+ // We extract error from statusText
+ // then normalize statusText and status for non-aborts
+ error = statusText;
+ if ( !statusText || status ) {
+ statusText = "error";
+ if ( status < 0 ) {
+ status = 0;
+ }
+ }
+ }
+
+ // Set data for the fake xhr object
+ jqXHR.status = status;
+ jqXHR.statusText = "" + ( nativeStatusText || statusText );
+
+ // Success/Error
+ if ( isSuccess ) {
+ deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
+ } else {
+ deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
+ }
+
+ // Status-dependent callbacks
+ jqXHR.statusCode( statusCode );
+ statusCode = undefined;
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajax" + ( isSuccess ? "Success" : "Error" ),
+ [ jqXHR, s, isSuccess ? success : error ] );
+ }
+
+ // Complete
+ completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
+
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
+ // Handle the global AJAX counter
+ if ( !( --jQuery.active ) ) {
+ jQuery.event.trigger( "ajaxStop" );
+ }
+ }
+ }
+
+ // Attach deferreds
+ deferred.promise( jqXHR );
+ jqXHR.success = jqXHR.done;
+ jqXHR.error = jqXHR.fail;
+ jqXHR.complete = completeDeferred.add;
+
+ // Status-dependent callbacks
+ jqXHR.statusCode = function( map ) {
+ if ( map ) {
+ var tmp;
+ if ( state < 2 ) {
+ for ( tmp in map ) {
+ statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];
+ }
+ } else {
+ tmp = map[ jqXHR.status ];
+ jqXHR.then( tmp, tmp );
+ }
+ }
+ return this;
+ };
+
+ // Remove hash character (#7531: and string promotion)
+ // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)
+ // We also use the url parameter if available
+ s.url = ( ( url || s.url ) + "" ).replace( rhash, "" ).replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
+
+ // Extract dataTypes list
+ s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().split( rspacesAjax );
+
+ // Determine if a cross-domain request is in order
+ if ( s.crossDomain == null ) {
+ parts = rurl.exec( s.url.toLowerCase() );
+ s.crossDomain = !!( parts &&
+ ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||
+ ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? 80 : 443 ) ) !=
+ ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? 80 : 443 ) ) )
+ );
+ }
+
+ // Convert data if not already a string
+ if ( s.data && s.processData && typeof s.data !== "string" ) {
+ s.data = jQuery.param( s.data, s.traditional );
+ }
+
+ // Apply prefilters
+ inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
+
+ // If request was aborted inside a prefilter, stop there
+ if ( state === 2 ) {
+ return false;
+ }
+
+ // We can fire global events as of now if asked to
+ fireGlobals = s.global;
+
+ // Uppercase the type
+ s.type = s.type.toUpperCase();
+
+ // Determine if request has content
+ s.hasContent = !rnoContent.test( s.type );
+
+ // Watch for a new set of requests
+ if ( fireGlobals && jQuery.active++ === 0 ) {
+ jQuery.event.trigger( "ajaxStart" );
+ }
+
+ // More options handling for requests with no content
+ if ( !s.hasContent ) {
+
+ // If data is available, append data to url
+ if ( s.data ) {
+ s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.data;
+ // #9682: remove data so that it's not used in an eventual retry
+ delete s.data;
+ }
+
+ // Get ifModifiedKey before adding the anti-cache parameter
+ ifModifiedKey = s.url;
+
+ // Add anti-cache in url if needed
+ if ( s.cache === false ) {
+
+ var ts = jQuery.now(),
+ // try replacing _= if it is there
+ ret = s.url.replace( rts, "$1_=" + ts );
+
+ // if nothing was replaced, add timestamp to the end
+ s.url = ret + ( ( ret === s.url ) ? ( rquery.test( s.url ) ? "&" : "?" ) + "_=" + ts : "" );
+ }
+ }
+
+ // Set the correct header, if data is being sent
+ if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
+ jqXHR.setRequestHeader( "Content-Type", s.contentType );
+ }
+
+ // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
+ if ( s.ifModified ) {
+ ifModifiedKey = ifModifiedKey || s.url;
+ if ( jQuery.lastModified[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ ifModifiedKey ] );
+ }
+ if ( jQuery.etag[ ifModifiedKey ] ) {
+ jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ ifModifiedKey ] );
+ }
+ }
+
+ // Set the Accepts header for the server, depending on the dataType
+ jqXHR.setRequestHeader(
+ "Accept",
+ s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
+ s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
+ s.accepts[ "*" ]
+ );
+
+ // Check for headers option
+ for ( i in s.headers ) {
+ jqXHR.setRequestHeader( i, s.headers[ i ] );
+ }
+
+ // Allow custom headers/mimetypes and early abort
+ if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
+ // Abort if not done already
+ jqXHR.abort();
+ return false;
+
+ }
+
+ // Install callbacks on deferreds
+ for ( i in { success: 1, error: 1, complete: 1 } ) {
+ jqXHR[ i ]( s[ i ] );
+ }
+
+ // Get transport
+ transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
+
+ // If no transport, we auto-abort
+ if ( !transport ) {
+ done( -1, "No Transport" );
+ } else {
+ jqXHR.readyState = 1;
+ // Send global event
+ if ( fireGlobals ) {
+ globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
+ }
+ // Timeout
+ if ( s.async && s.timeout > 0 ) {
+ timeoutTimer = setTimeout( function(){
+ jqXHR.abort( "timeout" );
+ }, s.timeout );
+ }
+
+ try {
+ state = 1;
+ transport.send( requestHeaders, done );
+ } catch (e) {
+ // Propagate exception as error if not done
+ if ( state < 2 ) {
+ done( -1, e );
+ // Simply rethrow otherwise
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ return jqXHR;
+ },
+
+ // Serialize an array of form elements or a set of
+ // key/values into a query string
+ param: function( a, traditional ) {
+ var s = [],
+ add = function( key, value ) {
+ // If value is a function, invoke it and return its value
+ value = jQuery.isFunction( value ) ? value() : value;
+ s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
+ };
+
+ // Set traditional to true for jQuery <= 1.3.2 behavior.
+ if ( traditional === undefined ) {
+ traditional = jQuery.ajaxSettings.traditional;
+ }
+
+ // If an array was passed in, assume that it is an array of form elements.
+ if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
+ // Serialize the form elements
+ jQuery.each( a, function() {
+ add( this.name, this.value );
+ });
+
+ } else {
+ // If traditional, encode the "old" way (the way 1.3.2 or older
+ // did it), otherwise encode params recursively.
+ for ( var prefix in a ) {
+ buildParams( prefix, a[ prefix ], traditional, add );
+ }
+ }
+
+ // Return the resulting serialization
+ return s.join( "&" ).replace( r20, "+" );
+ }
+});
+
+function buildParams( prefix, obj, traditional, add ) {
+ if ( jQuery.isArray( obj ) ) {
+ // Serialize array item.
+ jQuery.each( obj, function( i, v ) {
+ if ( traditional || rbracket.test( prefix ) ) {
+ // Treat each array item as a scalar.
+ add( prefix, v );
+
+ } else {
+ // If array item is non-scalar (array or object), encode its
+ // numeric index to resolve deserialization ambiguity issues.
+ // Note that rack (as of 1.0.0) can't currently deserialize
+ // nested arrays properly, and attempting to do so may cause
+ // a server error. Possible fixes are to modify rack's
+ // deserialization algorithm or to provide an option or flag
+ // to force array serialization to be shallow.
+ buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
+ }
+ });
+
+ } else if ( !traditional && jQuery.type( obj ) === "object" ) {
+ // Serialize object item.
+ for ( var name in obj ) {
+ buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
+ }
+
+ } else {
+ // Serialize scalar item.
+ add( prefix, obj );
+ }
+}
+
+// This is still on the jQuery object... for now
+// Want to move this to jQuery.ajax some day
+jQuery.extend({
+
+ // Counter for holding the number of active queries
+ active: 0,
+
+ // Last-Modified header cache for next request
+ lastModified: {},
+ etag: {}
+
+});
+
+/* Handles responses to an ajax request:
+ * - sets all responseXXX fields accordingly
+ * - finds the right dataType (mediates between content-type and expected dataType)
+ * - returns the corresponding response
+ */
+function ajaxHandleResponses( s, jqXHR, responses ) {
+
+ var contents = s.contents,
+ dataTypes = s.dataTypes,
+ responseFields = s.responseFields,
+ ct,
+ type,
+ finalDataType,
+ firstDataType;
+
+ // Fill responseXXX fields
+ for ( type in responseFields ) {
+ if ( type in responses ) {
+ jqXHR[ responseFields[type] ] = responses[ type ];
+ }
+ }
+
+ // Remove auto dataType and get content-type in the process
+ while( dataTypes[ 0 ] === "*" ) {
+ dataTypes.shift();
+ if ( ct === undefined ) {
+ ct = s.mimeType || jqXHR.getResponseHeader( "content-type" );
+ }
+ }
+
+ // Check if we're dealing with a known content-type
+ if ( ct ) {
+ for ( type in contents ) {
+ if ( contents[ type ] && contents[ type ].test( ct ) ) {
+ dataTypes.unshift( type );
+ break;
+ }
+ }
+ }
+
+ // Check to see if we have a response for the expected dataType
+ if ( dataTypes[ 0 ] in responses ) {
+ finalDataType = dataTypes[ 0 ];
+ } else {
+ // Try convertible dataTypes
+ for ( type in responses ) {
+ if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
+ finalDataType = type;
+ break;
+ }
+ if ( !firstDataType ) {
+ firstDataType = type;
+ }
+ }
+ // Or just use first one
+ finalDataType = finalDataType || firstDataType;
+ }
+
+ // If we found a dataType
+ // We add the dataType to the list if needed
+ // and return the corresponding response
+ if ( finalDataType ) {
+ if ( finalDataType !== dataTypes[ 0 ] ) {
+ dataTypes.unshift( finalDataType );
+ }
+ return responses[ finalDataType ];
+ }
+}
+
+// Chain conversions given the request and the original response
+function ajaxConvert( s, response ) {
+
+ // Apply the dataFilter if provided
+ if ( s.dataFilter ) {
+ response = s.dataFilter( response, s.dataType );
+ }
+
+ var dataTypes = s.dataTypes,
+ converters = {},
+ i,
+ key,
+ length = dataTypes.length,
+ tmp,
+ // Current and previous dataTypes
+ current = dataTypes[ 0 ],
+ prev,
+ // Conversion expression
+ conversion,
+ // Conversion function
+ conv,
+ // Conversion functions (transitive conversion)
+ conv1,
+ conv2;
+
+ // For each dataType in the chain
+ for ( i = 1; i < length; i++ ) {
+
+ // Create converters map
+ // with lowercased keys
+ if ( i === 1 ) {
+ for ( key in s.converters ) {
+ if ( typeof key === "string" ) {
+ converters[ key.toLowerCase() ] = s.converters[ key ];
+ }
+ }
+ }
+
+ // Get the dataTypes
+ prev = current;
+ current = dataTypes[ i ];
+
+ // If current is auto dataType, update it to prev
+ if ( current === "*" ) {
+ current = prev;
+ // If no auto and dataTypes are actually different
+ } else if ( prev !== "*" && prev !== current ) {
+
+ // Get the converter
+ conversion = prev + " " + current;
+ conv = converters[ conversion ] || converters[ "* " + current ];
+
+ // If there is no direct converter, search transitively
+ if ( !conv ) {
+ conv2 = undefined;
+ for ( conv1 in converters ) {
+ tmp = conv1.split( " " );
+ if ( tmp[ 0 ] === prev || tmp[ 0 ] === "*" ) {
+ conv2 = converters[ tmp[1] + " " + current ];
+ if ( conv2 ) {
+ conv1 = converters[ conv1 ];
+ if ( conv1 === true ) {
+ conv = conv2;
+ } else if ( conv2 === true ) {
+ conv = conv1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ // If we found no converter, dispatch an error
+ if ( !( conv || conv2 ) ) {
+ jQuery.error( "No conversion from " + conversion.replace(" "," to ") );
+ }
+ // If found converter is not an equivalence
+ if ( conv !== true ) {
+ // Convert with 1 or 2 converters accordingly
+ response = conv ? conv( response ) : conv2( conv1(response) );
+ }
+ }
+ }
+ return response;
+}
+
+
+
+
+var jsc = jQuery.now(),
+ jsre = /(\=)\?(&|$)|\?\?/i;
+
+// Default jsonp settings
+jQuery.ajaxSetup({
+ jsonp: "callback",
+ jsonpCallback: function() {
+ return jQuery.expando + "_" + ( jsc++ );
+ }
+});
+
+// Detect, normalize options and install callbacks for jsonp requests
+jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
+
+ var inspectData = ( typeof s.data === "string" ) && /^application\/x\-www\-form\-urlencoded/.test( s.contentType );
+
+ if ( s.dataTypes[ 0 ] === "jsonp" ||
+ s.jsonp !== false && ( jsre.test( s.url ) ||
+ inspectData && jsre.test( s.data ) ) ) {
+
+ var responseContainer,
+ jsonpCallback = s.jsonpCallback =
+ jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,
+ previous = window[ jsonpCallback ],
+ url = s.url,
+ data = s.data,
+ replace = "$1" + jsonpCallback + "$2";
+
+ if ( s.jsonp !== false ) {
+ url = url.replace( jsre, replace );
+ if ( s.url === url ) {
+ if ( inspectData ) {
+ data = data.replace( jsre, replace );
+ }
+ if ( s.data === data ) {
+ // Add callback manually
+ url += (/\?/.test( url ) ? "&" : "?") + s.jsonp + "=" + jsonpCallback;
+ }
+ }
+ }
+
+ s.url = url;
+ s.data = data;
+
+ // Install callback
+ window[ jsonpCallback ] = function( response ) {
+ responseContainer = [ response ];
+ };
+
+ // Clean-up function
+ jqXHR.always(function() {
+ // Set callback back to previous value
+ window[ jsonpCallback ] = previous;
+ // Call if it was a function and we have a response
+ if ( responseContainer && jQuery.isFunction( previous ) ) {
+ window[ jsonpCallback ]( responseContainer[ 0 ] );
+ }
+ });
+
+ // Use data converter to retrieve json after script execution
+ s.converters["script json"] = function() {
+ if ( !responseContainer ) {
+ jQuery.error( jsonpCallback + " was not called" );
+ }
+ return responseContainer[ 0 ];
+ };
+
+ // force json dataType
+ s.dataTypes[ 0 ] = "json";
+
+ // Delegate to script
+ return "script";
+ }
+});
+
+
+
+
+// Install script dataType
+jQuery.ajaxSetup({
+ accepts: {
+ script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
+ },
+ contents: {
+ script: /javascript|ecmascript/
+ },
+ converters: {
+ "text script": function( text ) {
+ jQuery.globalEval( text );
+ return text;
+ }
+ }
+});
+
+// Handle cache's special case and global
+jQuery.ajaxPrefilter( "script", function( s ) {
+ if ( s.cache === undefined ) {
+ s.cache = false;
+ }
+ if ( s.crossDomain ) {
+ s.type = "GET";
+ s.global = false;
+ }
+});
+
+// Bind script tag hack transport
+jQuery.ajaxTransport( "script", function(s) {
+
+ // This transport only deals with cross domain requests
+ if ( s.crossDomain ) {
+
+ var script,
+ head = document.head || document.getElementsByTagName( "head" )[0] || document.documentElement;
+
+ return {
+
+ send: function( _, callback ) {
+
+ script = document.createElement( "script" );
+
+ script.async = "async";
+
+ if ( s.scriptCharset ) {
+ script.charset = s.scriptCharset;
+ }
+
+ script.src = s.url;
+
+ // Attach handlers for all browsers
+ script.onload = script.onreadystatechange = function( _, isAbort ) {
+
+ if ( isAbort || !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+
+ // Handle memory leak in IE
+ script.onload = script.onreadystatechange = null;
+
+ // Remove the script
+ if ( head && script.parentNode ) {
+ head.removeChild( script );
+ }
+
+ // Dereference the script
+ script = undefined;
+
+ // Callback if not abort
+ if ( !isAbort ) {
+ callback( 200, "success" );
+ }
+ }
+ };
+ // Use insertBefore instead of appendChild to circumvent an IE6 bug.
+ // This arises when a base node is used (#2709 and #4378).
+ head.insertBefore( script, head.firstChild );
+ },
+
+ abort: function() {
+ if ( script ) {
+ script.onload( 0, 1 );
+ }
+ }
+ };
+ }
+});
+
+
+
+
+var // #5280: Internet Explorer will keep connections alive if we don't abort on unload
+ xhrOnUnloadAbort = window.ActiveXObject ? function() {
+ // Abort all pending requests
+ for ( var key in xhrCallbacks ) {
+ xhrCallbacks[ key ]( 0, 1 );
+ }
+ } : false,
+ xhrId = 0,
+ xhrCallbacks;
+
+// Functions to create xhrs
+function createStandardXHR() {
+ try {
+ return new window.XMLHttpRequest();
+ } catch( e ) {}
+}
+
+function createActiveXHR() {
+ try {
+ return new window.ActiveXObject( "Microsoft.XMLHTTP" );
+ } catch( e ) {}
+}
+
+// Create the request object
+// (This is still attached to ajaxSettings for backward compatibility)
+jQuery.ajaxSettings.xhr = window.ActiveXObject ?
+ /* Microsoft failed to properly
+ * implement the XMLHttpRequest in IE7 (can't request local files),
+ * so we use the ActiveXObject when it is available
+ * Additionally XMLHttpRequest can be disabled in IE7/IE8 so
+ * we need a fallback.
+ */
+ function() {
+ return !this.isLocal && createStandardXHR() || createActiveXHR();
+ } :
+ // For all other browsers, use the standard XMLHttpRequest object
+ createStandardXHR;
+
+// Determine support properties
+(function( xhr ) {
+ jQuery.extend( jQuery.support, {
+ ajax: !!xhr,
+ cors: !!xhr && ( "withCredentials" in xhr )
+ });
+})( jQuery.ajaxSettings.xhr() );
+
+// Create transport if the browser can provide an xhr
+if ( jQuery.support.ajax ) {
+
+ jQuery.ajaxTransport(function( s ) {
+ // Cross domain only allowed if supported through XMLHttpRequest
+ if ( !s.crossDomain || jQuery.support.cors ) {
+
+ var callback;
+
+ return {
+ send: function( headers, complete ) {
+
+ // Get a new xhr
+ var xhr = s.xhr(),
+ handle,
+ i;
+
+ // Open the socket
+ // Passing null username, generates a login popup on Opera (#2865)
+ if ( s.username ) {
+ xhr.open( s.type, s.url, s.async, s.username, s.password );
+ } else {
+ xhr.open( s.type, s.url, s.async );
+ }
+
+ // Apply custom fields if provided
+ if ( s.xhrFields ) {
+ for ( i in s.xhrFields ) {
+ xhr[ i ] = s.xhrFields[ i ];
+ }
+ }
+
+ // Override mime type if needed
+ if ( s.mimeType && xhr.overrideMimeType ) {
+ xhr.overrideMimeType( s.mimeType );
+ }
+
+ // X-Requested-With header
+ // For cross-domain requests, seeing as conditions for a preflight are
+ // akin to a jigsaw puzzle, we simply never set it to be sure.
+ // (it can always be set on a per-request basis or even using ajaxSetup)
+ // For same-domain requests, won't change header if already provided.
+ if ( !s.crossDomain && !headers["X-Requested-With"] ) {
+ headers[ "X-Requested-With" ] = "XMLHttpRequest";
+ }
+
+ // Need an extra try/catch for cross domain requests in Firefox 3
+ try {
+ for ( i in headers ) {
+ xhr.setRequestHeader( i, headers[ i ] );
+ }
+ } catch( _ ) {}
+
+ // Do send the request
+ // This may raise an exception which is actually
+ // handled in jQuery.ajax (so no try/catch here)
+ xhr.send( ( s.hasContent && s.data ) || null );
+
+ // Listener
+ callback = function( _, isAbort ) {
+
+ var status,
+ statusText,
+ responseHeaders,
+ responses,
+ xml;
+
+ // Firefox throws exceptions when accessing properties
+ // of an xhr when a network error occurred
+ // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)
+ try {
+
+ // Was never called and is aborted or complete
+ if ( callback && ( isAbort || xhr.readyState === 4 ) ) {
+
+ // Only called once
+ callback = undefined;
+
+ // Do not keep as active anymore
+ if ( handle ) {
+ xhr.onreadystatechange = jQuery.noop;
+ if ( xhrOnUnloadAbort ) {
+ delete xhrCallbacks[ handle ];
+ }
+ }
+
+ // If it's an abort
+ if ( isAbort ) {
+ // Abort it manually if needed
+ if ( xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+ } else {
+ status = xhr.status;
+ responseHeaders = xhr.getAllResponseHeaders();
+ responses = {};
+ xml = xhr.responseXML;
+
+ // Construct response list
+ if ( xml && xml.documentElement /* #4958 */ ) {
+ responses.xml = xml;
+ }
+
+ // When requesting binary data, IE6-9 will throw an exception
+ // on any attempt to access responseText (#11426)
+ try {
+ responses.text = xhr.responseText;
+ } catch( _ ) {
+ }
+
+ // Firefox throws an exception when accessing
+ // statusText for faulty cross-domain requests
+ try {
+ statusText = xhr.statusText;
+ } catch( e ) {
+ // We normalize with Webkit giving an empty statusText
+ statusText = "";
+ }
+
+ // Filter status for non standard behaviors
+
+ // If the request is local and we have data: assume a success
+ // (success with no data won't get notified, that's the best we
+ // can do given current implementations)
+ if ( !status && s.isLocal && !s.crossDomain ) {
+ status = responses.text ? 200 : 404;
+ // IE - #1450: sometimes returns 1223 when it should be 204
+ } else if ( status === 1223 ) {
+ status = 204;
+ }
+ }
+ }
+ } catch( firefoxAccessException ) {
+ if ( !isAbort ) {
+ complete( -1, firefoxAccessException );
+ }
+ }
+
+ // Call complete if needed
+ if ( responses ) {
+ complete( status, statusText, responses, responseHeaders );
+ }
+ };
+
+ // if we're in sync mode or it's in cache
+ // and has been retrieved directly (IE6 & IE7)
+ // we need to manually fire the callback
+ if ( !s.async || xhr.readyState === 4 ) {
+ callback();
+ } else {
+ handle = ++xhrId;
+ if ( xhrOnUnloadAbort ) {
+ // Create the active xhrs callbacks list if needed
+ // and attach the unload handler
+ if ( !xhrCallbacks ) {
+ xhrCallbacks = {};
+ jQuery( window ).unload( xhrOnUnloadAbort );
+ }
+ // Add to list of active xhrs callbacks
+ xhrCallbacks[ handle ] = callback;
+ }
+ xhr.onreadystatechange = callback;
+ }
+ },
+
+ abort: function() {
+ if ( callback ) {
+ callback(0,1);
+ }
+ }
+ };
+ }
+ });
+}
+
+
+
+
+var elemdisplay = {},
+ iframe, iframeDoc,
+ rfxtypes = /^(?:toggle|show|hide)$/,
+ rfxnum = /^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,
+ timerId,
+ fxAttrs = [
+ // height animations
+ [ "height", "marginTop", "marginBottom", "paddingTop", "paddingBottom" ],
+ // width animations
+ [ "width", "marginLeft", "marginRight", "paddingLeft", "paddingRight" ],
+ // opacity animations
+ [ "opacity" ]
+ ],
+ fxNow;
+
+jQuery.fn.extend({
+ show: function( speed, easing, callback ) {
+ var elem, display;
+
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("show", 3), speed, easing, callback );
+
+ } else {
+ for ( var i = 0, j = this.length; i < j; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ // Reset the inline display of this element to learn if it is
+ // being hidden by cascaded rules or not
+ if ( !jQuery._data(elem, "olddisplay") && display === "none" ) {
+ display = elem.style.display = "";
+ }
+
+ // Set elements which have been overridden with display: none
+ // in a stylesheet to whatever the default browser style is
+ // for such an element
+ if ( (display === "" && jQuery.css(elem, "display") === "none") ||
+ !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {
+ jQuery._data( elem, "olddisplay", defaultDisplay(elem.nodeName) );
+ }
+ }
+ }
+
+ // Set the display of most of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ elem = this[ i ];
+
+ if ( elem.style ) {
+ display = elem.style.display;
+
+ if ( display === "" || display === "none" ) {
+ elem.style.display = jQuery._data( elem, "olddisplay" ) || "";
+ }
+ }
+ }
+
+ return this;
+ }
+ },
+
+ hide: function( speed, easing, callback ) {
+ if ( speed || speed === 0 ) {
+ return this.animate( genFx("hide", 3), speed, easing, callback);
+
+ } else {
+ var elem, display,
+ i = 0,
+ j = this.length;
+
+ for ( ; i < j; i++ ) {
+ elem = this[i];
+ if ( elem.style ) {
+ display = jQuery.css( elem, "display" );
+
+ if ( display !== "none" && !jQuery._data( elem, "olddisplay" ) ) {
+ jQuery._data( elem, "olddisplay", display );
+ }
+ }
+ }
+
+ // Set the display of the elements in a second loop
+ // to avoid the constant reflow
+ for ( i = 0; i < j; i++ ) {
+ if ( this[i].style ) {
+ this[i].style.display = "none";
+ }
+ }
+
+ return this;
+ }
+ },
+
+ // Save the old toggle function
+ _toggle: jQuery.fn.toggle,
+
+ toggle: function( fn, fn2, callback ) {
+ var bool = typeof fn === "boolean";
+
+ if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {
+ this._toggle.apply( this, arguments );
+
+ } else if ( fn == null || bool ) {
+ this.each(function() {
+ var state = bool ? fn : jQuery(this).is(":hidden");
+ jQuery(this)[ state ? "show" : "hide" ]();
+ });
+
+ } else {
+ this.animate(genFx("toggle", 3), fn, fn2, callback);
+ }
+
+ return this;
+ },
+
+ fadeTo: function( speed, to, easing, callback ) {
+ return this.filter(":hidden").css("opacity", 0).show().end()
+ .animate({opacity: to}, speed, easing, callback);
+ },
+
+ animate: function( prop, speed, easing, callback ) {
+ var optall = jQuery.speed( speed, easing, callback );
+
+ if ( jQuery.isEmptyObject( prop ) ) {
+ return this.each( optall.complete, [ false ] );
+ }
+
+ // Do not change referenced properties as per-property easing will be lost
+ prop = jQuery.extend( {}, prop );
+
+ function doAnimation() {
+ // XXX 'this' does not always have a nodeName when running the
+ // test suite
+
+ if ( optall.queue === false ) {
+ jQuery._mark( this );
+ }
+
+ var opt = jQuery.extend( {}, optall ),
+ isElement = this.nodeType === 1,
+ hidden = isElement && jQuery(this).is(":hidden"),
+ name, val, p, e, hooks, replace,
+ parts, start, end, unit,
+ method;
+
+ // will store per property easing and be used to determine when an animation is complete
+ opt.animatedProperties = {};
+
+ // first pass over propertys to expand / normalize
+ for ( p in prop ) {
+ name = jQuery.camelCase( p );
+ if ( p !== name ) {
+ prop[ name ] = prop[ p ];
+ delete prop[ p ];
+ }
+
+ if ( ( hooks = jQuery.cssHooks[ name ] ) && "expand" in hooks ) {
+ replace = hooks.expand( prop[ name ] );
+ delete prop[ name ];
+
+ // not quite $.extend, this wont overwrite keys already present.
+ // also - reusing 'p' from above because we have the correct "name"
+ for ( p in replace ) {
+ if ( ! ( p in prop ) ) {
+ prop[ p ] = replace[ p ];
+ }
+ }
+ }
+ }
+
+ for ( name in prop ) {
+ val = prop[ name ];
+ // easing resolution: per property > opt.specialEasing > opt.easing > 'swing' (default)
+ if ( jQuery.isArray( val ) ) {
+ opt.animatedProperties[ name ] = val[ 1 ];
+ val = prop[ name ] = val[ 0 ];
+ } else {
+ opt.animatedProperties[ name ] = opt.specialEasing && opt.specialEasing[ name ] || opt.easing || 'swing';
+ }
+
+ if ( val === "hide" && hidden || val === "show" && !hidden ) {
+ return opt.complete.call( this );
+ }
+
+ if ( isElement && ( name === "height" || name === "width" ) ) {
+ // Make sure that nothing sneaks out
+ // Record all 3 overflow attributes because IE does not
+ // change the overflow attribute when overflowX and
+ // overflowY are set to the same value
+ opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];
+
+ // Set display property to inline-block for height/width
+ // animations on inline elements that are having width/height animated
+ if ( jQuery.css( this, "display" ) === "inline" &&
+ jQuery.css( this, "float" ) === "none" ) {
+
+ // inline-level elements accept inline-block;
+ // block-level elements need to be inline with layout
+ if ( !jQuery.support.inlineBlockNeedsLayout || defaultDisplay( this.nodeName ) === "inline" ) {
+ this.style.display = "inline-block";
+
+ } else {
+ this.style.zoom = 1;
+ }
+ }
+ }
+ }
+
+ if ( opt.overflow != null ) {
+ this.style.overflow = "hidden";
+ }
+
+ for ( p in prop ) {
+ e = new jQuery.fx( this, opt, p );
+ val = prop[ p ];
+
+ if ( rfxtypes.test( val ) ) {
+
+ // Tracks whether to show or hide based on private
+ // data attached to the element
+ method = jQuery._data( this, "toggle" + p ) || ( val === "toggle" ? hidden ? "show" : "hide" : 0 );
+ if ( method ) {
+ jQuery._data( this, "toggle" + p, method === "show" ? "hide" : "show" );
+ e[ method ]();
+ } else {
+ e[ val ]();
+ }
+
+ } else {
+ parts = rfxnum.exec( val );
+ start = e.cur();
+
+ if ( parts ) {
+ end = parseFloat( parts[2] );
+ unit = parts[3] || ( jQuery.cssNumber[ p ] ? "" : "px" );
+
+ // We need to compute starting value
+ if ( unit !== "px" ) {
+ jQuery.style( this, p, (end || 1) + unit);
+ start = ( (end || 1) / e.cur() ) * start;
+ jQuery.style( this, p, start + unit);
+ }
+
+ // If a +=/-= token was provided, we're doing a relative animation
+ if ( parts[1] ) {
+ end = ( (parts[ 1 ] === "-=" ? -1 : 1) * end ) + start;
+ }
+
+ e.custom( start, end, unit );
+
+ } else {
+ e.custom( start, val, "" );
+ }
+ }
+ }
+
+ // For JS strict compliance
+ return true;
+ }
+
+ return optall.queue === false ?
+ this.each( doAnimation ) :
+ this.queue( optall.queue, doAnimation );
+ },
+
+ stop: function( type, clearQueue, gotoEnd ) {
+ if ( typeof type !== "string" ) {
+ gotoEnd = clearQueue;
+ clearQueue = type;
+ type = undefined;
+ }
+ if ( clearQueue && type !== false ) {
+ this.queue( type || "fx", [] );
+ }
+
+ return this.each(function() {
+ var index,
+ hadTimers = false,
+ timers = jQuery.timers,
+ data = jQuery._data( this );
+
+ // clear marker counters if we know they won't be
+ if ( !gotoEnd ) {
+ jQuery._unmark( true, this );
+ }
+
+ function stopQueue( elem, data, index ) {
+ var hooks = data[ index ];
+ jQuery.removeData( elem, index, true );
+ hooks.stop( gotoEnd );
+ }
+
+ if ( type == null ) {
+ for ( index in data ) {
+ if ( data[ index ] && data[ index ].stop && index.indexOf(".run") === index.length - 4 ) {
+ stopQueue( this, data, index );
+ }
+ }
+ } else if ( data[ index = type + ".run" ] && data[ index ].stop ){
+ stopQueue( this, data, index );
+ }
+
+ for ( index = timers.length; index--; ) {
+ if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
+ if ( gotoEnd ) {
+
+ // force the next step to be the last
+ timers[ index ]( true );
+ } else {
+ timers[ index ].saveState();
+ }
+ hadTimers = true;
+ timers.splice( index, 1 );
+ }
+ }
+
+ // start the next in the queue if the last step wasn't forced
+ // timers currently will call their complete callbacks, which will dequeue
+ // but only if they were gotoEnd
+ if ( !( gotoEnd && hadTimers ) ) {
+ jQuery.dequeue( this, type );
+ }
+ });
+ }
+
+});
+
+// Animations created synchronously will run synchronously
+function createFxNow() {
+ setTimeout( clearFxNow, 0 );
+ return ( fxNow = jQuery.now() );
+}
+
+function clearFxNow() {
+ fxNow = undefined;
+}
+
+// Generate parameters to create a standard animation
+function genFx( type, num ) {
+ var obj = {};
+
+ jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice( 0, num )), function() {
+ obj[ this ] = type;
+ });
+
+ return obj;
+}
+
+// Generate shortcuts for custom animations
+jQuery.each({
+ slideDown: genFx( "show", 1 ),
+ slideUp: genFx( "hide", 1 ),
+ slideToggle: genFx( "toggle", 1 ),
+ fadeIn: { opacity: "show" },
+ fadeOut: { opacity: "hide" },
+ fadeToggle: { opacity: "toggle" }
+}, function( name, props ) {
+ jQuery.fn[ name ] = function( speed, easing, callback ) {
+ return this.animate( props, speed, easing, callback );
+ };
+});
+
+jQuery.extend({
+ speed: function( speed, easing, fn ) {
+ var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
+ complete: fn || !fn && easing ||
+ jQuery.isFunction( speed ) && speed,
+ duration: speed,
+ easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
+ };
+
+ opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
+ opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
+
+ // normalize opt.queue - true/undefined/null -> "fx"
+ if ( opt.queue == null || opt.queue === true ) {
+ opt.queue = "fx";
+ }
+
+ // Queueing
+ opt.old = opt.complete;
+
+ opt.complete = function( noUnmark ) {
+ if ( jQuery.isFunction( opt.old ) ) {
+ opt.old.call( this );
+ }
+
+ if ( opt.queue ) {
+ jQuery.dequeue( this, opt.queue );
+ } else if ( noUnmark !== false ) {
+ jQuery._unmark( this );
+ }
+ };
+
+ return opt;
+ },
+
+ easing: {
+ linear: function( p ) {
+ return p;
+ },
+ swing: function( p ) {
+ return ( -Math.cos( p*Math.PI ) / 2 ) + 0.5;
+ }
+ },
+
+ timers: [],
+
+ fx: function( elem, options, prop ) {
+ this.options = options;
+ this.elem = elem;
+ this.prop = prop;
+
+ options.orig = options.orig || {};
+ }
+
+});
+
+jQuery.fx.prototype = {
+ // Simple function for setting a style value
+ update: function() {
+ if ( this.options.step ) {
+ this.options.step.call( this.elem, this.now, this );
+ }
+
+ ( jQuery.fx.step[ this.prop ] || jQuery.fx.step._default )( this );
+ },
+
+ // Get the current size
+ cur: function() {
+ if ( this.elem[ this.prop ] != null && (!this.elem.style || this.elem.style[ this.prop ] == null) ) {
+ return this.elem[ this.prop ];
+ }
+
+ var parsed,
+ r = jQuery.css( this.elem, this.prop );
+ // Empty strings, null, undefined and "auto" are converted to 0,
+ // complex values such as "rotate(1rad)" are returned as is,
+ // simple values such as "10px" are parsed to Float.
+ return isNaN( parsed = parseFloat( r ) ) ? !r || r === "auto" ? 0 : r : parsed;
+ },
+
+ // Start an animation from one number to another
+ custom: function( from, to, unit ) {
+ var self = this,
+ fx = jQuery.fx;
+
+ this.startTime = fxNow || createFxNow();
+ this.end = to;
+ this.now = this.start = from;
+ this.pos = this.state = 0;
+ this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? "" : "px" );
+
+ function t( gotoEnd ) {
+ return self.step( gotoEnd );
+ }
+
+ t.queue = this.options.queue;
+ t.elem = this.elem;
+ t.saveState = function() {
+ if ( jQuery._data( self.elem, "fxshow" + self.prop ) === undefined ) {
+ if ( self.options.hide ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.start );
+ } else if ( self.options.show ) {
+ jQuery._data( self.elem, "fxshow" + self.prop, self.end );
+ }
+ }
+ };
+
+ if ( t() && jQuery.timers.push(t) && !timerId ) {
+ timerId = setInterval( fx.tick, fx.interval );
+ }
+ },
+
+ // Simple 'show' function
+ show: function() {
+ var dataShow = jQuery._data( this.elem, "fxshow" + this.prop );
+
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[ this.prop ] = dataShow || jQuery.style( this.elem, this.prop );
+ this.options.show = true;
+
+ // Begin the animation
+ // Make sure that we start at a small width/height to avoid any flash of content
+ if ( dataShow !== undefined ) {
+ // This show is picking up where a previous hide or show left off
+ this.custom( this.cur(), dataShow );
+ } else {
+ this.custom( this.prop === "width" || this.prop === "height" ? 1 : 0, this.cur() );
+ }
+
+ // Start by showing the element
+ jQuery( this.elem ).show();
+ },
+
+ // Simple 'hide' function
+ hide: function() {
+ // Remember where we started, so that we can go back to it later
+ this.options.orig[ this.prop ] = jQuery._data( this.elem, "fxshow" + this.prop ) || jQuery.style( this.elem, this.prop );
+ this.options.hide = true;
+
+ // Begin the animation
+ this.custom( this.cur(), 0 );
+ },
+
+ // Each step of an animation
+ step: function( gotoEnd ) {
+ var p, n, complete,
+ t = fxNow || createFxNow(),
+ done = true,
+ elem = this.elem,
+ options = this.options;
+
+ if ( gotoEnd || t >= options.duration + this.startTime ) {
+ this.now = this.end;
+ this.pos = this.state = 1;
+ this.update();
+
+ options.animatedProperties[ this.prop ] = true;
+
+ for ( p in options.animatedProperties ) {
+ if ( options.animatedProperties[ p ] !== true ) {
+ done = false;
+ }
+ }
+
+ if ( done ) {
+ // Reset the overflow
+ if ( options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {
+
+ jQuery.each( [ "", "X", "Y" ], function( index, value ) {
+ elem.style[ "overflow" + value ] = options.overflow[ index ];
+ });
+ }
+
+ // Hide the element if the "hide" operation was done
+ if ( options.hide ) {
+ jQuery( elem ).hide();
+ }
+
+ // Reset the properties, if the item has been hidden or shown
+ if ( options.hide || options.show ) {
+ for ( p in options.animatedProperties ) {
+ jQuery.style( elem, p, options.orig[ p ] );
+ jQuery.removeData( elem, "fxshow" + p, true );
+ // Toggle data is no longer needed
+ jQuery.removeData( elem, "toggle" + p, true );
+ }
+ }
+
+ // Execute the complete function
+ // in the event that the complete function throws an exception
+ // we must ensure it won't be called twice. #5684
+
+ complete = options.complete;
+ if ( complete ) {
+
+ options.complete = false;
+ complete.call( elem );
+ }
+ }
+
+ return false;
+
+ } else {
+ // classical easing cannot be used with an Infinity duration
+ if ( options.duration == Infinity ) {
+ this.now = t;
+ } else {
+ n = t - this.startTime;
+ this.state = n / options.duration;
+
+ // Perform the easing function, defaults to swing
+ this.pos = jQuery.easing[ options.animatedProperties[this.prop] ]( this.state, n, 0, 1, options.duration );
+ this.now = this.start + ( (this.end - this.start) * this.pos );
+ }
+ // Perform the next step of the animation
+ this.update();
+ }
+
+ return true;
+ }
+};
+
+jQuery.extend( jQuery.fx, {
+ tick: function() {
+ var timer,
+ timers = jQuery.timers,
+ i = 0;
+
+ for ( ; i < timers.length; i++ ) {
+ timer = timers[ i ];
+ // Checks the timer has not already been removed
+ if ( !timer() && timers[ i ] === timer ) {
+ timers.splice( i--, 1 );
+ }
+ }
+
+ if ( !timers.length ) {
+ jQuery.fx.stop();
+ }
+ },
+
+ interval: 13,
+
+ stop: function() {
+ clearInterval( timerId );
+ timerId = null;
+ },
+
+ speeds: {
+ slow: 600,
+ fast: 200,
+ // Default speed
+ _default: 400
+ },
+
+ step: {
+ opacity: function( fx ) {
+ jQuery.style( fx.elem, "opacity", fx.now );
+ },
+
+ _default: function( fx ) {
+ if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {
+ fx.elem.style[ fx.prop ] = fx.now + fx.unit;
+ } else {
+ fx.elem[ fx.prop ] = fx.now;
+ }
+ }
+ }
+});
+
+// Ensure props that can't be negative don't go there on undershoot easing
+jQuery.each( fxAttrs.concat.apply( [], fxAttrs ), function( i, prop ) {
+ // exclude marginTop, marginLeft, marginBottom and marginRight from this list
+ if ( prop.indexOf( "margin" ) ) {
+ jQuery.fx.step[ prop ] = function( fx ) {
+ jQuery.style( fx.elem, prop, Math.max(0, fx.now) + fx.unit );
+ };
+ }
+});
+
+if ( jQuery.expr && jQuery.expr.filters ) {
+ jQuery.expr.filters.animated = function( elem ) {
+ return jQuery.grep(jQuery.timers, function( fn ) {
+ return elem === fn.elem;
+ }).length;
+ };
+}
+
+// Try to restore the default display value of an element
+function defaultDisplay( nodeName ) {
+
+ if ( !elemdisplay[ nodeName ] ) {
+
+ var body = document.body,
+ elem = jQuery( "<" + nodeName + ">" ).appendTo( body ),
+ display = elem.css( "display" );
+ elem.remove();
+
+ // If the simple way fails,
+ // get element's real default display by attaching it to a temp iframe
+ if ( display === "none" || display === "" ) {
+ // No iframe to use yet, so create it
+ if ( !iframe ) {
+ iframe = document.createElement( "iframe" );
+ iframe.frameBorder = iframe.width = iframe.height = 0;
+ }
+
+ body.appendChild( iframe );
+
+ // Create a cacheable copy of the iframe document on first call.
+ // IE and Opera will allow us to reuse the iframeDoc without re-writing the fake HTML
+ // document to it; WebKit & Firefox won't allow reusing the iframe document.
+ if ( !iframeDoc || !iframe.createElement ) {
+ iframeDoc = ( iframe.contentWindow || iframe.contentDocument ).document;
+ iframeDoc.write( ( jQuery.support.boxModel ? "<!doctype html>" : "" ) + "<html><body>" );
+ iframeDoc.close();
+ }
+
+ elem = iframeDoc.createElement( nodeName );
+
+ iframeDoc.body.appendChild( elem );
+
+ display = jQuery.css( elem, "display" );
+ body.removeChild( iframe );
+ }
+
+ // Store the correct default display
+ elemdisplay[ nodeName ] = display;
+ }
+
+ return elemdisplay[ nodeName ];
+}
+
+
+
+
+var getOffset,
+ rtable = /^t(?:able|d|h)$/i,
+ rroot = /^(?:body|html)$/i;
+
+if ( "getBoundingClientRect" in document.documentElement ) {
+ getOffset = function( elem, doc, docElem, box ) {
+ try {
+ box = elem.getBoundingClientRect();
+ } catch(e) {}
+
+ // Make sure we're not dealing with a disconnected DOM node
+ if ( !box || !jQuery.contains( docElem, elem ) ) {
+ return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };
+ }
+
+ var body = doc.body,
+ win = getWindow( doc ),
+ clientTop = docElem.clientTop || body.clientTop || 0,
+ clientLeft = docElem.clientLeft || body.clientLeft || 0,
+ scrollTop = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop || body.scrollTop,
+ scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,
+ top = box.top + scrollTop - clientTop,
+ left = box.left + scrollLeft - clientLeft;
+
+ return { top: top, left: left };
+ };
+
+} else {
+ getOffset = function( elem, doc, docElem ) {
+ var computedStyle,
+ offsetParent = elem.offsetParent,
+ prevOffsetParent = elem,
+ body = doc.body,
+ defaultView = doc.defaultView,
+ prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,
+ top = elem.offsetTop,
+ left = elem.offsetLeft;
+
+ while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+ break;
+ }
+
+ computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;
+ top -= elem.scrollTop;
+ left -= elem.scrollLeft;
+
+ if ( elem === offsetParent ) {
+ top += elem.offsetTop;
+ left += elem.offsetLeft;
+
+ if ( jQuery.support.doesNotAddBorder && !(jQuery.support.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevOffsetParent = offsetParent;
+ offsetParent = elem.offsetParent;
+ }
+
+ if ( jQuery.support.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== "visible" ) {
+ top += parseFloat( computedStyle.borderTopWidth ) || 0;
+ left += parseFloat( computedStyle.borderLeftWidth ) || 0;
+ }
+
+ prevComputedStyle = computedStyle;
+ }
+
+ if ( prevComputedStyle.position === "relative" || prevComputedStyle.position === "static" ) {
+ top += body.offsetTop;
+ left += body.offsetLeft;
+ }
+
+ if ( jQuery.support.fixedPosition && prevComputedStyle.position === "fixed" ) {
+ top += Math.max( docElem.scrollTop, body.scrollTop );
+ left += Math.max( docElem.scrollLeft, body.scrollLeft );
+ }
+
+ return { top: top, left: left };
+ };
+}
+
+jQuery.fn.offset = function( options ) {
+ if ( arguments.length ) {
+ return options === undefined ?
+ this :
+ this.each(function( i ) {
+ jQuery.offset.setOffset( this, options, i );
+ });
+ }
+
+ var elem = this[0],
+ doc = elem && elem.ownerDocument;
+
+ if ( !doc ) {
+ return null;
+ }
+
+ if ( elem === doc.body ) {
+ return jQuery.offset.bodyOffset( elem );
+ }
+
+ return getOffset( elem, doc, doc.documentElement );
+};
+
+jQuery.offset = {
+
+ bodyOffset: function( body ) {
+ var top = body.offsetTop,
+ left = body.offsetLeft;
+
+ if ( jQuery.support.doesNotIncludeMarginInBodyOffset ) {
+ top += parseFloat( jQuery.css(body, "marginTop") ) || 0;
+ left += parseFloat( jQuery.css(body, "marginLeft") ) || 0;
+ }
+
+ return { top: top, left: left };
+ },
+
+ setOffset: function( elem, options, i ) {
+ var position = jQuery.css( elem, "position" );
+
+ // set position first, in-case top/left are set even on static elem
+ if ( position === "static" ) {
+ elem.style.position = "relative";
+ }
+
+ var curElem = jQuery( elem ),
+ curOffset = curElem.offset(),
+ curCSSTop = jQuery.css( elem, "top" ),
+ curCSSLeft = jQuery.css( elem, "left" ),
+ calculatePosition = ( position === "absolute" || position === "fixed" ) && jQuery.inArray("auto", [curCSSTop, curCSSLeft]) > -1,
+ props = {}, curPosition = {}, curTop, curLeft;
+
+ // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
+ if ( calculatePosition ) {
+ curPosition = curElem.position();
+ curTop = curPosition.top;
+ curLeft = curPosition.left;
+ } else {
+ curTop = parseFloat( curCSSTop ) || 0;
+ curLeft = parseFloat( curCSSLeft ) || 0;
+ }
+
+ if ( jQuery.isFunction( options ) ) {
+ options = options.call( elem, i, curOffset );
+ }
+
+ if ( options.top != null ) {
+ props.top = ( options.top - curOffset.top ) + curTop;
+ }
+ if ( options.left != null ) {
+ props.left = ( options.left - curOffset.left ) + curLeft;
+ }
+
+ if ( "using" in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ }
+};
+
+
+jQuery.fn.extend({
+
+ position: function() {
+ if ( !this[0] ) {
+ return null;
+ }
+
+ var elem = this[0],
+
+ // Get *real* offsetParent
+ offsetParent = this.offsetParent(),
+
+ // Get correct offsets
+ offset = this.offset(),
+ parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();
+
+ // Subtract element margins
+ // note: when an element has margin: auto the offsetLeft and marginLeft
+ // are the same in Safari causing offset.left to incorrectly be 0
+ offset.top -= parseFloat( jQuery.css(elem, "marginTop") ) || 0;
+ offset.left -= parseFloat( jQuery.css(elem, "marginLeft") ) || 0;
+
+ // Add offsetParent borders
+ parentOffset.top += parseFloat( jQuery.css(offsetParent[0], "borderTopWidth") ) || 0;
+ parentOffset.left += parseFloat( jQuery.css(offsetParent[0], "borderLeftWidth") ) || 0;
+
+ // Subtract the two offsets
+ return {
+ top: offset.top - parentOffset.top,
+ left: offset.left - parentOffset.left
+ };
+ },
+
+ offsetParent: function() {
+ return this.map(function() {
+ var offsetParent = this.offsetParent || document.body;
+ while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, "position") === "static") ) {
+ offsetParent = offsetParent.offsetParent;
+ }
+ return offsetParent;
+ });
+ }
+});
+
+
+// Create scrollLeft and scrollTop methods
+jQuery.each( {scrollLeft: "pageXOffset", scrollTop: "pageYOffset"}, function( method, prop ) {
+ var top = /Y/.test( prop );
+
+ jQuery.fn[ method ] = function( val ) {
+ return jQuery.access( this, function( elem, method, val ) {
+ var win = getWindow( elem );
+
+ if ( val === undefined ) {
+ return win ? (prop in win) ? win[ prop ] :
+ jQuery.support.boxModel && win.document.documentElement[ method ] ||
+ win.document.body[ method ] :
+ elem[ method ];
+ }
+
+ if ( win ) {
+ win.scrollTo(
+ !top ? val : jQuery( win ).scrollLeft(),
+ top ? val : jQuery( win ).scrollTop()
+ );
+
+ } else {
+ elem[ method ] = val;
+ }
+ }, method, val, arguments.length, null );
+ };
+});
+
+function getWindow( elem ) {
+ return jQuery.isWindow( elem ) ?
+ elem :
+ elem.nodeType === 9 ?
+ elem.defaultView || elem.parentWindow :
+ false;
+}
+
+
+
+
+// Create width, height, innerHeight, innerWidth, outerHeight and outerWidth methods
+jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
+ var clientProp = "client" + name,
+ scrollProp = "scroll" + name,
+ offsetProp = "offset" + name;
+
+ // innerHeight and innerWidth
+ jQuery.fn[ "inner" + name ] = function() {
+ var elem = this[0];
+ return elem ?
+ elem.style ?
+ parseFloat( jQuery.css( elem, type, "padding" ) ) :
+ this[ type ]() :
+ null;
+ };
+
+ // outerHeight and outerWidth
+ jQuery.fn[ "outer" + name ] = function( margin ) {
+ var elem = this[0];
+ return elem ?
+ elem.style ?
+ parseFloat( jQuery.css( elem, type, margin ? "margin" : "border" ) ) :
+ this[ type ]() :
+ null;
+ };
+
+ jQuery.fn[ type ] = function( value ) {
+ return jQuery.access( this, function( elem, type, value ) {
+ var doc, docElemProp, orig, ret;
+
+ if ( jQuery.isWindow( elem ) ) {
+ // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat
+ doc = elem.document;
+ docElemProp = doc.documentElement[ clientProp ];
+ return jQuery.support.boxModel && docElemProp ||
+ doc.body && doc.body[ clientProp ] || docElemProp;
+ }
+
+ // Get document width or height
+ if ( elem.nodeType === 9 ) {
+ // Either scroll[Width/Height] or offset[Width/Height], whichever is greater
+ doc = elem.documentElement;
+
+ // when a window > document, IE6 reports a offset[Width/Height] > client[Width/Height]
+ // so we can't use max, as it'll choose the incorrect offset[Width/Height]
+ // instead we use the correct client[Width/Height]
+ // support:IE6
+ if ( doc[ clientProp ] >= doc[ scrollProp ] ) {
+ return doc[ clientProp ];
+ }
+
+ return Math.max(
+ elem.body[ scrollProp ], doc[ scrollProp ],
+ elem.body[ offsetProp ], doc[ offsetProp ]
+ );
+ }
+
+ // Get width or height on the element
+ if ( value === undefined ) {
+ orig = jQuery.css( elem, type );
+ ret = parseFloat( orig );
+ return jQuery.isNumeric( ret ) ? ret : orig;
+ }
+
+ // Set the width or height on the element
+ jQuery( elem ).css( type, value );
+ }, type, value, arguments.length, null );
+ };
+});
+
+
+
+
+// Expose jQuery to the global object
+window.jQuery = window.$ = jQuery;
+
+// Expose jQuery as an AMD module, but only for AMD loaders that
+// understand the issues with loading multiple versions of jQuery
+// in a page that all might call define(). The loader will indicate
+// they have special allowances for multiple jQuery versions by
+// specifying define.amd.jQuery = true. Register as a named module,
+// since jQuery can be concatenated with other files that may use define,
+// but not use a proper concatenation script that understands anonymous
+// AMD modules. A named AMD is safest and most robust way to register.
+// Lowercase jquery is used because AMD module names are derived from
+// file names, and jQuery is normally delivered in a lowercase file name.
+// Do this after creating the global so that if an AMD module wants to call
+// noConflict to hide this version of jQuery, it will work.
+if ( typeof define === "function" && define.amd && define.amd.jQuery ) {
+ define( "jquery", [], function () { return jQuery; } );
+}
+
+
+
+})( window );
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-ui-1.8.18.custom.js b/storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-ui-1.8.18.custom.js
new file mode 100644
index 00000000..a212450c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/html/js/jquery-ui-1.8.18.custom.js
@@ -0,0 +1,11802 @@
+/*!
+ * jQuery UI 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI
+ */
+(function( $, undefined ) {
+
+// prevent duplicate loading
+// this is only a problem because we proxy existing functions
+// and we don't want to double proxy them
+$.ui = $.ui || {};
+if ( $.ui.version ) {
+ return;
+}
+
+$.extend( $.ui, {
+ version: "1.8.18",
+
+ keyCode: {
+ ALT: 18,
+ BACKSPACE: 8,
+ CAPS_LOCK: 20,
+ COMMA: 188,
+ COMMAND: 91,
+ COMMAND_LEFT: 91, // COMMAND
+ COMMAND_RIGHT: 93,
+ CONTROL: 17,
+ DELETE: 46,
+ DOWN: 40,
+ END: 35,
+ ENTER: 13,
+ ESCAPE: 27,
+ HOME: 36,
+ INSERT: 45,
+ LEFT: 37,
+ MENU: 93, // COMMAND_RIGHT
+ NUMPAD_ADD: 107,
+ NUMPAD_DECIMAL: 110,
+ NUMPAD_DIVIDE: 111,
+ NUMPAD_ENTER: 108,
+ NUMPAD_MULTIPLY: 106,
+ NUMPAD_SUBTRACT: 109,
+ PAGE_DOWN: 34,
+ PAGE_UP: 33,
+ PERIOD: 190,
+ RIGHT: 39,
+ SHIFT: 16,
+ SPACE: 32,
+ TAB: 9,
+ UP: 38,
+ WINDOWS: 91 // COMMAND
+ }
+});
+
+// plugins
+$.fn.extend({
+ propAttr: $.fn.prop || $.fn.attr,
+
+ _focus: $.fn.focus,
+ focus: function( delay, fn ) {
+ return typeof delay === "number" ?
+ this.each(function() {
+ var elem = this;
+ setTimeout(function() {
+ $( elem ).focus();
+ if ( fn ) {
+ fn.call( elem );
+ }
+ }, delay );
+ }) :
+ this._focus.apply( this, arguments );
+ },
+
+ scrollParent: function() {
+ var scrollParent;
+ if (($.browser.msie && (/(static|relative)/).test(this.css('position'))) || (/absolute/).test(this.css('position'))) {
+ scrollParent = this.parents().filter(function() {
+ return (/(relative|absolute|fixed)/).test($.curCSS(this,'position',1)) && (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+ }).eq(0);
+ } else {
+ scrollParent = this.parents().filter(function() {
+ return (/(auto|scroll)/).test($.curCSS(this,'overflow',1)+$.curCSS(this,'overflow-y',1)+$.curCSS(this,'overflow-x',1));
+ }).eq(0);
+ }
+
+ return (/fixed/).test(this.css('position')) || !scrollParent.length ? $(document) : scrollParent;
+ },
+
+ zIndex: function( zIndex ) {
+ if ( zIndex !== undefined ) {
+ return this.css( "zIndex", zIndex );
+ }
+
+ if ( this.length ) {
+ var elem = $( this[ 0 ] ), position, value;
+ while ( elem.length && elem[ 0 ] !== document ) {
+ // Ignore z-index if position is set to a value where z-index is ignored by the browser
+ // This makes behavior of this function consistent across browsers
+ // WebKit always returns auto if the element is positioned
+ position = elem.css( "position" );
+ if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+ // IE returns 0 when zIndex is not specified
+ // other browsers return a string
+ // we ignore the case of nested elements with an explicit value of 0
+ // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+ value = parseInt( elem.css( "zIndex" ), 10 );
+ if ( !isNaN( value ) && value !== 0 ) {
+ return value;
+ }
+ }
+ elem = elem.parent();
+ }
+ }
+
+ return 0;
+ },
+
+ disableSelection: function() {
+ return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) +
+ ".ui-disableSelection", function( event ) {
+ event.preventDefault();
+ });
+ },
+
+ enableSelection: function() {
+ return this.unbind( ".ui-disableSelection" );
+ }
+});
+
+$.each( [ "Width", "Height" ], function( i, name ) {
+ var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+ type = name.toLowerCase(),
+ orig = {
+ innerWidth: $.fn.innerWidth,
+ innerHeight: $.fn.innerHeight,
+ outerWidth: $.fn.outerWidth,
+ outerHeight: $.fn.outerHeight
+ };
+
+ function reduce( elem, size, border, margin ) {
+ $.each( side, function() {
+ size -= parseFloat( $.curCSS( elem, "padding" + this, true) ) || 0;
+ if ( border ) {
+ size -= parseFloat( $.curCSS( elem, "border" + this + "Width", true) ) || 0;
+ }
+ if ( margin ) {
+ size -= parseFloat( $.curCSS( elem, "margin" + this, true) ) || 0;
+ }
+ });
+ return size;
+ }
+
+ $.fn[ "inner" + name ] = function( size ) {
+ if ( size === undefined ) {
+ return orig[ "inner" + name ].call( this );
+ }
+
+ return this.each(function() {
+ $( this ).css( type, reduce( this, size ) + "px" );
+ });
+ };
+
+ $.fn[ "outer" + name] = function( size, margin ) {
+ if ( typeof size !== "number" ) {
+ return orig[ "outer" + name ].call( this, size );
+ }
+
+ return this.each(function() {
+ $( this).css( type, reduce( this, size, true, margin ) + "px" );
+ });
+ };
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+ var nodeName = element.nodeName.toLowerCase();
+ if ( "area" === nodeName ) {
+ var map = element.parentNode,
+ mapName = map.name,
+ img;
+ if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+ return false;
+ }
+ img = $( "img[usemap=#" + mapName + "]" )[0];
+ return !!img && visible( img );
+ }
+ return ( /input|select|textarea|button|object/.test( nodeName )
+ ? !element.disabled
+ : "a" == nodeName
+ ? element.href || isTabIndexNotNaN
+ : isTabIndexNotNaN)
+ // the element and all of its ancestors must be visible
+ && visible( element );
+}
+
+function visible( element ) {
+ return !$( element ).parents().andSelf().filter(function() {
+ return $.curCSS( this, "visibility" ) === "hidden" ||
+ $.expr.filters.hidden( this );
+ }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+ data: function( elem, i, match ) {
+ return !!$.data( elem, match[ 3 ] );
+ },
+
+ focusable: function( element ) {
+ return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+ },
+
+ tabbable: function( element ) {
+ var tabIndex = $.attr( element, "tabindex" ),
+ isTabIndexNaN = isNaN( tabIndex );
+ return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+ }
+});
+
+// support
+$(function() {
+ var body = document.body,
+ div = body.appendChild( div = document.createElement( "div" ) );
+
+ // access offsetHeight before setting the style to prevent a layout bug
+ // in IE 9 which causes the elemnt to continue to take up space even
+ // after it is removed from the DOM (#8026)
+ div.offsetHeight;
+
+ $.extend( div.style, {
+ minHeight: "100px",
+ height: "auto",
+ padding: 0,
+ borderWidth: 0
+ });
+
+ $.support.minHeight = div.offsetHeight === 100;
+ $.support.selectstart = "onselectstart" in div;
+
+ // set display to none to avoid a layout bug in IE
+ // http://dev.jquery.com/ticket/4014
+ body.removeChild( div ).style.display = "none";
+});
+
+
+
+
+
+// deprecated
+$.extend( $.ui, {
+ // $.ui.plugin is deprecated. Use the proxy pattern instead.
+ plugin: {
+ add: function( module, option, set ) {
+ var proto = $.ui[ module ].prototype;
+ for ( var i in set ) {
+ proto.plugins[ i ] = proto.plugins[ i ] || [];
+ proto.plugins[ i ].push( [ option, set[ i ] ] );
+ }
+ },
+ call: function( instance, name, args ) {
+ var set = instance.plugins[ name ];
+ if ( !set || !instance.element[ 0 ].parentNode ) {
+ return;
+ }
+
+ for ( var i = 0; i < set.length; i++ ) {
+ if ( instance.options[ set[ i ][ 0 ] ] ) {
+ set[ i ][ 1 ].apply( instance.element, args );
+ }
+ }
+ }
+ },
+
+ // will be deprecated when we switch to jQuery 1.4 - use jQuery.contains()
+ contains: function( a, b ) {
+ return document.compareDocumentPosition ?
+ a.compareDocumentPosition( b ) & 16 :
+ a !== b && a.contains( b );
+ },
+
+ // only used by resizable
+ hasScroll: function( el, a ) {
+
+ //If overflow is hidden, the element might have extra content, but the user wants to hide it
+ if ( $( el ).css( "overflow" ) === "hidden") {
+ return false;
+ }
+
+ var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+ has = false;
+
+ if ( el[ scroll ] > 0 ) {
+ return true;
+ }
+
+ // TODO: determine which cases actually cause this to happen
+ // if the element doesn't have the scroll set, see if it's possible to
+ // set the scroll
+ el[ scroll ] = 1;
+ has = ( el[ scroll ] > 0 );
+ el[ scroll ] = 0;
+ return has;
+ },
+
+ // these are odd functions, fix the API or move into individual plugins
+ isOverAxis: function( x, reference, size ) {
+ //Determines when x coordinate is over "b" element axis
+ return ( x > reference ) && ( x < ( reference + size ) );
+ },
+ isOver: function( y, x, top, left, height, width ) {
+ //Determines when x, y coordinates is over "b" element
+ return $.ui.isOverAxis( y, top, height ) && $.ui.isOverAxis( x, left, width );
+ }
+});
+
+})( jQuery );
+/*!
+ * jQuery UI Widget 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Widget
+ */
+(function( $, undefined ) {
+
+// jQuery 1.4+
+if ( $.cleanData ) {
+ var _cleanData = $.cleanData;
+ $.cleanData = function( elems ) {
+ for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
+ try {
+ $( elem ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ }
+ _cleanData( elems );
+ };
+} else {
+ var _remove = $.fn.remove;
+ $.fn.remove = function( selector, keepData ) {
+ return this.each(function() {
+ if ( !keepData ) {
+ if ( !selector || $.filter( selector, [ this ] ).length ) {
+ $( "*", this ).add( [ this ] ).each(function() {
+ try {
+ $( this ).triggerHandler( "remove" );
+ // http://bugs.jquery.com/ticket/8235
+ } catch( e ) {}
+ });
+ }
+ }
+ return _remove.call( $(this), selector, keepData );
+ });
+ };
+}
+
+$.widget = function( name, base, prototype ) {
+ var namespace = name.split( "." )[ 0 ],
+ fullName;
+ name = name.split( "." )[ 1 ];
+ fullName = namespace + "-" + name;
+
+ if ( !prototype ) {
+ prototype = base;
+ base = $.Widget;
+ }
+
+ // create selector for plugin
+ $.expr[ ":" ][ fullName ] = function( elem ) {
+ return !!$.data( elem, name );
+ };
+
+ $[ namespace ] = $[ namespace ] || {};
+ $[ namespace ][ name ] = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+ };
+
+ var basePrototype = new base();
+ // we need to make the options hash a property directly on the new instance
+ // otherwise we'll modify the options hash on the prototype that we're
+ // inheriting from
+// $.each( basePrototype, function( key, val ) {
+// if ( $.isPlainObject(val) ) {
+// basePrototype[ key ] = $.extend( {}, val );
+// }
+// });
+ basePrototype.options = $.extend( true, {}, basePrototype.options );
+ $[ namespace ][ name ].prototype = $.extend( true, basePrototype, {
+ namespace: namespace,
+ widgetName: name,
+ widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name,
+ widgetBaseClass: fullName
+ }, prototype );
+
+ $.widget.bridge( name, $[ namespace ][ name ] );
+};
+
+$.widget.bridge = function( name, object ) {
+ $.fn[ name ] = function( options ) {
+ var isMethodCall = typeof options === "string",
+ args = Array.prototype.slice.call( arguments, 1 ),
+ returnValue = this;
+
+ // allow multiple hashes to be passed on init
+ options = !isMethodCall && args.length ?
+ $.extend.apply( null, [ true, options ].concat(args) ) :
+ options;
+
+ // prevent calls to internal methods
+ if ( isMethodCall && options.charAt( 0 ) === "_" ) {
+ return returnValue;
+ }
+
+ if ( isMethodCall ) {
+ this.each(function() {
+ var instance = $.data( this, name ),
+ methodValue = instance && $.isFunction( instance[options] ) ?
+ instance[ options ].apply( instance, args ) :
+ instance;
+ // TODO: add this back in 1.9 and use $.error() (see #5972)
+// if ( !instance ) {
+// throw "cannot call methods on " + name + " prior to initialization; " +
+// "attempted to call method '" + options + "'";
+// }
+// if ( !$.isFunction( instance[options] ) ) {
+// throw "no such method '" + options + "' for " + name + " widget instance";
+// }
+// var methodValue = instance[ options ].apply( instance, args );
+ if ( methodValue !== instance && methodValue !== undefined ) {
+ returnValue = methodValue;
+ return false;
+ }
+ });
+ } else {
+ this.each(function() {
+ var instance = $.data( this, name );
+ if ( instance ) {
+ instance.option( options || {} )._init();
+ } else {
+ $.data( this, name, new object( options, this ) );
+ }
+ });
+ }
+
+ return returnValue;
+ };
+};
+
+$.Widget = function( options, element ) {
+ // allow instantiation without initializing for simple inheritance
+ if ( arguments.length ) {
+ this._createWidget( options, element );
+ }
+};
+
+$.Widget.prototype = {
+ widgetName: "widget",
+ widgetEventPrefix: "",
+ options: {
+ disabled: false
+ },
+ _createWidget: function( options, element ) {
+ // $.widget.bridge stores the plugin instance, but we do it anyway
+ // so that it's stored even before the _create function runs
+ $.data( element, this.widgetName, this );
+ this.element = $( element );
+ this.options = $.extend( true, {},
+ this.options,
+ this._getCreateOptions(),
+ options );
+
+ var self = this;
+ this.element.bind( "remove." + this.widgetName, function() {
+ self.destroy();
+ });
+
+ this._create();
+ this._trigger( "create" );
+ this._init();
+ },
+ _getCreateOptions: function() {
+ return $.metadata && $.metadata.get( this.element[0] )[ this.widgetName ];
+ },
+ _create: function() {},
+ _init: function() {},
+
+ destroy: function() {
+ this.element
+ .unbind( "." + this.widgetName )
+ .removeData( this.widgetName );
+ this.widget()
+ .unbind( "." + this.widgetName )
+ .removeAttr( "aria-disabled" )
+ .removeClass(
+ this.widgetBaseClass + "-disabled " +
+ "ui-state-disabled" );
+ },
+
+ widget: function() {
+ return this.element;
+ },
+
+ option: function( key, value ) {
+ var options = key;
+
+ if ( arguments.length === 0 ) {
+ // don't return a reference to the internal hash
+ return $.extend( {}, this.options );
+ }
+
+ if (typeof key === "string" ) {
+ if ( value === undefined ) {
+ return this.options[ key ];
+ }
+ options = {};
+ options[ key ] = value;
+ }
+
+ this._setOptions( options );
+
+ return this;
+ },
+ _setOptions: function( options ) {
+ var self = this;
+ $.each( options, function( key, value ) {
+ self._setOption( key, value );
+ });
+
+ return this;
+ },
+ _setOption: function( key, value ) {
+ this.options[ key ] = value;
+
+ if ( key === "disabled" ) {
+ this.widget()
+ [ value ? "addClass" : "removeClass"](
+ this.widgetBaseClass + "-disabled" + " " +
+ "ui-state-disabled" )
+ .attr( "aria-disabled", value );
+ }
+
+ return this;
+ },
+
+ enable: function() {
+ return this._setOption( "disabled", false );
+ },
+ disable: function() {
+ return this._setOption( "disabled", true );
+ },
+
+ _trigger: function( type, event, data ) {
+ var prop, orig,
+ callback = this.options[ type ];
+
+ data = data || {};
+ event = $.Event( event );
+ event.type = ( type === this.widgetEventPrefix ?
+ type :
+ this.widgetEventPrefix + type ).toLowerCase();
+ // the original event may come from any element
+ // so we need to reset the target on the new event
+ event.target = this.element[ 0 ];
+
+ // copy original event properties over to the new event
+ orig = event.originalEvent;
+ if ( orig ) {
+ for ( prop in orig ) {
+ if ( !( prop in event ) ) {
+ event[ prop ] = orig[ prop ];
+ }
+ }
+ }
+
+ this.element.trigger( event, data );
+
+ return !( $.isFunction(callback) &&
+ callback.call( this.element[0], event, data ) === false ||
+ event.isDefaultPrevented() );
+ }
+};
+
+})( jQuery );
+/*!
+ * jQuery UI Mouse 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var mouseHandled = false;
+$( document ).mouseup( function( e ) {
+ mouseHandled = false;
+});
+
+$.widget("ui.mouse", {
+ options: {
+ cancel: ':input,option',
+ distance: 1,
+ delay: 0
+ },
+ _mouseInit: function() {
+ var self = this;
+
+ this.element
+ .bind('mousedown.'+this.widgetName, function(event) {
+ return self._mouseDown(event);
+ })
+ .bind('click.'+this.widgetName, function(event) {
+ if (true === $.data(event.target, self.widgetName + '.preventClickEvent')) {
+ $.removeData(event.target, self.widgetName + '.preventClickEvent');
+ event.stopImmediatePropagation();
+ return false;
+ }
+ });
+
+ this.started = false;
+ },
+
+ // TODO: make sure destroying one instance of mouse doesn't mess with
+ // other instances of mouse
+ _mouseDestroy: function() {
+ this.element.unbind('.'+this.widgetName);
+ },
+
+ _mouseDown: function(event) {
+ // don't let more than one widget handle mouseStart
+ if( mouseHandled ) { return };
+
+ // we may have missed mouseup (out of window)
+ (this._mouseStarted && this._mouseUp(event));
+
+ this._mouseDownEvent = event;
+
+ var self = this,
+ btnIsLeft = (event.which == 1),
+ // event.target.nodeName works around a bug in IE 8 with
+ // disabled inputs (#7620)
+ elIsCancel = (typeof this.options.cancel == "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+ if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+ return true;
+ }
+
+ this.mouseDelayMet = !this.options.delay;
+ if (!this.mouseDelayMet) {
+ this._mouseDelayTimer = setTimeout(function() {
+ self.mouseDelayMet = true;
+ }, this.options.delay);
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted = (this._mouseStart(event) !== false);
+ if (!this._mouseStarted) {
+ event.preventDefault();
+ return true;
+ }
+ }
+
+ // Click event may never have fired (Gecko & Opera)
+ if (true === $.data(event.target, this.widgetName + '.preventClickEvent')) {
+ $.removeData(event.target, this.widgetName + '.preventClickEvent');
+ }
+
+ // these delegates are required to keep context
+ this._mouseMoveDelegate = function(event) {
+ return self._mouseMove(event);
+ };
+ this._mouseUpDelegate = function(event) {
+ return self._mouseUp(event);
+ };
+ $(document)
+ .bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+ event.preventDefault();
+
+ mouseHandled = true;
+ return true;
+ },
+
+ _mouseMove: function(event) {
+ // IE mouseup check - mouseup happened when mouse was out of window
+ if ($.browser.msie && !(document.documentMode >= 9) && !event.button) {
+ return this._mouseUp(event);
+ }
+
+ if (this._mouseStarted) {
+ this._mouseDrag(event);
+ return event.preventDefault();
+ }
+
+ if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+ this._mouseStarted =
+ (this._mouseStart(this._mouseDownEvent, event) !== false);
+ (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+ }
+
+ return !this._mouseStarted;
+ },
+
+ _mouseUp: function(event) {
+ $(document)
+ .unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+ .unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+ if (this._mouseStarted) {
+ this._mouseStarted = false;
+
+ if (event.target == this._mouseDownEvent.target) {
+ $.data(event.target, this.widgetName + '.preventClickEvent', true);
+ }
+
+ this._mouseStop(event);
+ }
+
+ return false;
+ },
+
+ _mouseDistanceMet: function(event) {
+ return (Math.max(
+ Math.abs(this._mouseDownEvent.pageX - event.pageX),
+ Math.abs(this._mouseDownEvent.pageY - event.pageY)
+ ) >= this.options.distance
+ );
+ },
+
+ _mouseDelayMet: function(event) {
+ return this.mouseDelayMet;
+ },
+
+ // These are placeholder methods, to be overridden by extending plugin
+ _mouseStart: function(event) {},
+ _mouseDrag: function(event) {},
+ _mouseStop: function(event) {},
+ _mouseCapture: function(event) { return true; }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Draggable 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Draggables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.draggable", $.ui.mouse, {
+ widgetEventPrefix: "drag",
+ options: {
+ addClasses: true,
+ appendTo: "parent",
+ axis: false,
+ connectToSortable: false,
+ containment: false,
+ cursor: "auto",
+ cursorAt: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ iframeFix: false,
+ opacity: false,
+ refreshPositions: false,
+ revert: false,
+ revertDuration: 500,
+ scope: "default",
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ snap: false,
+ snapMode: "both",
+ snapTolerance: 20,
+ stack: false,
+ zIndex: false
+ },
+ _create: function() {
+
+ if (this.options.helper == 'original' && !(/^(?:r|a|f)/).test(this.element.css("position")))
+ this.element[0].style.position = 'relative';
+
+ (this.options.addClasses && this.element.addClass("ui-draggable"));
+ (this.options.disabled && this.element.addClass("ui-draggable-disabled"));
+
+ this._mouseInit();
+
+ },
+
+ destroy: function() {
+ if(!this.element.data('draggable')) return;
+ this.element
+ .removeData("draggable")
+ .unbind(".draggable")
+ .removeClass("ui-draggable"
+ + " ui-draggable-dragging"
+ + " ui-draggable-disabled");
+ this._mouseDestroy();
+
+ return this;
+ },
+
+ _mouseCapture: function(event) {
+
+ var o = this.options;
+
+ // among others, prevent a drag on a resizable-handle
+ if (this.helper || o.disabled || $(event.target).is('.ui-resizable-handle'))
+ return false;
+
+ //Quit if we're not on a valid handle
+ this.handle = this._getHandle(event);
+ if (!this.handle)
+ return false;
+
+ if ( o.iframeFix ) {
+ $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
+ $('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>')
+ .css({
+ width: this.offsetWidth+"px", height: this.offsetHeight+"px",
+ position: "absolute", opacity: "0.001", zIndex: 1000
+ })
+ .css($(this).offset())
+ .appendTo("body");
+ });
+ }
+
+ return true;
+
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options;
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ //If ddmanager is used for droppables, set the global draggable
+ if($.ui.ddmanager)
+ $.ui.ddmanager.current = this;
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Store the helper's css position
+ this.cssPosition = this.helper.css("position");
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.positionAbs = this.element.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this.position = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Set a containment if given in the options
+ if(o.containment)
+ this._setContainment();
+
+ //Trigger event + callbacks
+ if(this._trigger("start", event) === false) {
+ this._clear();
+ return false;
+ }
+
+ //Recache the helper size
+ this._cacheHelperProportions();
+
+ //Prepare the droppable offsets
+ if ($.ui.ddmanager && !o.dropBehaviour)
+ $.ui.ddmanager.prepareOffsets(this, event);
+
+ this.helper.addClass("ui-draggable-dragging");
+ this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+ if ( $.ui.ddmanager ) $.ui.ddmanager.dragStart(this, event);
+
+ return true;
+ },
+
+ _mouseDrag: function(event, noPropagation) {
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Call plugins and callbacks and use the resulting position if something is returned
+ if (!noPropagation) {
+ var ui = this._uiHash();
+ if(this._trigger('drag', event, ui) === false) {
+ this._mouseUp({});
+ return false;
+ }
+ this.position = ui.position;
+ }
+
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ //If we are using droppables, inform the manager about the drop
+ var dropped = false;
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
+ dropped = $.ui.ddmanager.drop(this, event);
+
+ //if a drop comes from outside (a sortable)
+ if(this.dropped) {
+ dropped = this.dropped;
+ this.dropped = false;
+ }
+
+ //if the original element is removed, don't bother to continue if helper is set to "original"
+ if((!this.element[0] || !this.element[0].parentNode) && this.options.helper == "original")
+ return false;
+
+ if((this.options.revert == "invalid" && !dropped) || (this.options.revert == "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+ var self = this;
+ $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+ if(self._trigger("stop", event) !== false) {
+ self._clear();
+ }
+ });
+ } else {
+ if(this._trigger("stop", event) !== false) {
+ this._clear();
+ }
+ }
+
+ return false;
+ },
+
+ _mouseUp: function(event) {
+ if (this.options.iframeFix === true) {
+ $("div.ui-draggable-iframeFix").each(function() {
+ this.parentNode.removeChild(this);
+ }); //Remove frame helpers
+ }
+
+ //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+ if( $.ui.ddmanager ) $.ui.ddmanager.dragStop(this, event);
+
+ return $.ui.mouse.prototype._mouseUp.call(this, event);
+ },
+
+ cancel: function() {
+
+ if(this.helper.is(".ui-draggable-dragging")) {
+ this._mouseUp({});
+ } else {
+ this._clear();
+ }
+
+ return this;
+
+ },
+
+ _getHandle: function(event) {
+
+ var handle = !this.options.handle || !$(this.options.handle, this.element).length ? true : false;
+ $(this.options.handle, this.element)
+ .find("*")
+ .andSelf()
+ .each(function() {
+ if(this == event.target) handle = true;
+ });
+
+ return handle;
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options;
+ var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper == 'clone' ? this.element.clone().removeAttr('id') : this.element);
+
+ if(!helper.parents('body').length)
+ helper.appendTo((o.appendTo == 'parent' ? this.element[0].parentNode : o.appendTo));
+
+ if(helper[0] != this.element[0] && !(/(fixed|absolute)/).test(helper.css("position")))
+ helper.css("position", "absolute");
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj == 'string') {
+ obj = obj.split(' ');
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ('left' in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ('right' in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ('top' in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ('bottom' in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
+ || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
+ po = { top: 0, left: 0 };
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition == "relative") {
+ var p = this.element.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.element.css("marginLeft"),10) || 0),
+ top: (parseInt(this.element.css("marginTop"),10) || 0),
+ right: (parseInt(this.element.css("marginRight"),10) || 0),
+ bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var o = this.options;
+ if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
+ if(o.containment == 'document' || o.containment == 'window') this.containment = [
+ o.containment == 'document' ? 0 : $(window).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+ o.containment == 'document' ? 0 : $(window).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+ (o.containment == 'document' ? 0 : $(window).scrollLeft()) + $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
+ (o.containment == 'document' ? 0 : $(window).scrollTop()) + ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+
+ if(!(/^(document|window|parent)$/).test(o.containment) && o.containment.constructor != Array) {
+ var c = $(o.containment);
+ var ce = c[0]; if(!ce) return;
+ var co = c.offset();
+ var over = ($(ce).css("overflow") != 'hidden');
+
+ this.containment = [
+ (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0),
+ (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0),
+ (over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left - this.margins.right,
+ (over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - this.margins.bottom
+ ];
+ this.relative_container = c;
+
+ } else if(o.containment.constructor == Array) {
+ this.containment = o.containment;
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) pos = this.position;
+ var mod = d == "absolute" ? 1 : -1;
+ var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top // The absolute mouse position
+ + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
+ + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
+ - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left // The absolute mouse position
+ + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
+ + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
+ - ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+ var pageX = event.pageX;
+ var pageY = event.pageY;
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+ var containment;
+ if(this.containment) {
+ if (this.relative_container){
+ var co = this.relative_container.offset();
+ containment = [ this.containment[0] + co.left,
+ this.containment[1] + co.top,
+ this.containment[2] + co.left,
+ this.containment[3] + co.top ];
+ }
+ else {
+ containment = this.containment;
+ }
+
+ if(event.pageX - this.offset.click.left < containment[0]) pageX = containment[0] + this.offset.click.left;
+ if(event.pageY - this.offset.click.top < containment[1]) pageY = containment[1] + this.offset.click.top;
+ if(event.pageX - this.offset.click.left > containment[2]) pageX = containment[2] + this.offset.click.left;
+ if(event.pageY - this.offset.click.top > containment[3]) pageY = containment[3] + this.offset.click.top;
+ }
+
+ if(o.grid) {
+ //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+ var top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+ pageY = containment ? (!(top - this.offset.click.top < containment[1] || top - this.offset.click.top > containment[3]) ? top : (!(top - this.offset.click.top < containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ var left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+ pageX = containment ? (!(left - this.offset.click.left < containment[0] || left - this.offset.click.left > containment[2]) ? left : (!(left - this.offset.click.left < containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY // The absolute mouse position
+ - this.offset.click.top // Click offset (relative to the element)
+ - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
+ - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
+ + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX // The absolute mouse position
+ - this.offset.click.left // Click offset (relative to the element)
+ - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
+ - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
+ + ($.browser.safari && $.browser.version < 526 && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _clear: function() {
+ this.helper.removeClass("ui-draggable-dragging");
+ if(this.helper[0] != this.element[0] && !this.cancelHelperRemoval) this.helper.remove();
+ //if($.ui.ddmanager) $.ui.ddmanager.current = null;
+ this.helper = null;
+ this.cancelHelperRemoval = false;
+ },
+
+ // From now on bulk stuff - mainly helpers
+
+ _trigger: function(type, event, ui) {
+ ui = ui || this._uiHash();
+ $.ui.plugin.call(this, type, [event, ui]);
+ if(type == "drag") this.positionAbs = this._convertPositionTo("absolute"); //The absolute position has to be recalculated after plugins
+ return $.Widget.prototype._trigger.call(this, type, event, ui);
+ },
+
+ plugins: {},
+
+ _uiHash: function(event) {
+ return {
+ helper: this.helper,
+ position: this.position,
+ originalPosition: this.originalPosition,
+ offset: this.positionAbs
+ };
+ }
+
+});
+
+$.extend($.ui.draggable, {
+ version: "1.8.18"
+});
+
+$.ui.plugin.add("draggable", "connectToSortable", {
+ start: function(event, ui) {
+
+ var inst = $(this).data("draggable"), o = inst.options,
+ uiSortable = $.extend({}, ui, { item: inst.element });
+ inst.sortables = [];
+ $(o.connectToSortable).each(function() {
+ var sortable = $.data(this, 'sortable');
+ if (sortable && !sortable.options.disabled) {
+ inst.sortables.push({
+ instance: sortable,
+ shouldRevert: sortable.options.revert
+ });
+ sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page).
+ sortable._trigger("activate", event, uiSortable);
+ }
+ });
+
+ },
+ stop: function(event, ui) {
+
+ //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
+ var inst = $(this).data("draggable"),
+ uiSortable = $.extend({}, ui, { item: inst.element });
+
+ $.each(inst.sortables, function() {
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+
+ inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
+ this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
+
+ //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
+ if(this.shouldRevert) this.instance.options.revert = true;
+
+ //Trigger the stop of the sortable
+ this.instance._mouseStop(event);
+
+ this.instance.options.helper = this.instance.options._helper;
+
+ //If the helper has been the original item, restore properties in the sortable
+ if(inst.options.helper == 'original')
+ this.instance.currentItem.css({ top: 'auto', left: 'auto' });
+
+ } else {
+ this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
+ this.instance._trigger("deactivate", event, uiSortable);
+ }
+
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("draggable"), self = this;
+
+ var checkPos = function(o) {
+ var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
+ var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
+ var itemHeight = o.height, itemWidth = o.width;
+ var itemTop = o.top, itemLeft = o.left;
+
+ return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
+ };
+
+ $.each(inst.sortables, function(i) {
+
+ //Copy over some variables to allow calling the sortable's native _intersectsWith
+ this.instance.positionAbs = inst.positionAbs;
+ this.instance.helperProportions = inst.helperProportions;
+ this.instance.offset.click = inst.offset.click;
+
+ if(this.instance._intersectsWith(this.instance.containerCache)) {
+
+ //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
+ if(!this.instance.isOver) {
+
+ this.instance.isOver = 1;
+ //Now we fake the start of dragging for the sortable instance,
+ //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
+ //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
+ this.instance.currentItem = $(self).clone().removeAttr('id').appendTo(this.instance.element).data("sortable-item", true);
+ this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
+ this.instance.options.helper = function() { return ui.helper[0]; };
+
+ event.target = this.instance.currentItem[0];
+ this.instance._mouseCapture(event, true);
+ this.instance._mouseStart(event, true, true);
+
+ //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
+ this.instance.offset.click.top = inst.offset.click.top;
+ this.instance.offset.click.left = inst.offset.click.left;
+ this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
+ this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
+
+ inst._trigger("toSortable", event);
+ inst.dropped = this.instance.element; //draggable revert needs that
+ //hack so receive/update callbacks work (mostly)
+ inst.currentItem = inst.element;
+ this.instance.fromOutside = inst;
+
+ }
+
+ //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
+ if(this.instance.currentItem) this.instance._mouseDrag(event);
+
+ } else {
+
+ //If it doesn't intersect with the sortable, and it intersected before,
+ //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
+ if(this.instance.isOver) {
+
+ this.instance.isOver = 0;
+ this.instance.cancelHelperRemoval = true;
+
+ //Prevent reverting on this forced stop
+ this.instance.options.revert = false;
+
+ // The out event needs to be triggered independently
+ this.instance._trigger('out', event, this.instance._uiHash(this.instance));
+
+ this.instance._mouseStop(event, true);
+ this.instance.options.helper = this.instance.options._helper;
+
+ //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
+ this.instance.currentItem.remove();
+ if(this.instance.placeholder) this.instance.placeholder.remove();
+
+ inst._trigger("fromSortable", event);
+ inst.dropped = false; //draggable revert needs that
+ }
+
+ };
+
+ });
+
+ }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+ start: function(event, ui) {
+ var t = $('body'), o = $(this).data('draggable').options;
+ if (t.css("cursor")) o._cursor = t.css("cursor");
+ t.css("cursor", o.cursor);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data('draggable').options;
+ if (o._cursor) $('body').css("cursor", o._cursor);
+ }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data('draggable').options;
+ if(t.css("opacity")) o._opacity = t.css("opacity");
+ t.css('opacity', o.opacity);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data('draggable').options;
+ if(o._opacity) $(ui.helper).css('opacity', o._opacity);
+ }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+ start: function(event, ui) {
+ var i = $(this).data("draggable");
+ if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') i.overflowOffset = i.scrollParent.offset();
+ },
+ drag: function(event, ui) {
+
+ var i = $(this).data("draggable"), o = i.options, scrolled = false;
+
+ if(i.scrollParent[0] != document && i.scrollParent[0].tagName != 'HTML') {
+
+ if(!o.axis || o.axis != 'x') {
+ if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
+ else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity)
+ i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
+ }
+
+ if(!o.axis || o.axis != 'y') {
+ if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
+ else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity)
+ i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
+ }
+
+ } else {
+
+ if(!o.axis || o.axis != 'x') {
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+ }
+
+ if(!o.axis || o.axis != 'y') {
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+ }
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+ $.ui.ddmanager.prepareOffsets(i, event);
+
+ }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+ start: function(event, ui) {
+
+ var i = $(this).data("draggable"), o = i.options;
+ i.snapElements = [];
+
+ $(o.snap.constructor != String ? ( o.snap.items || ':data(draggable)' ) : o.snap).each(function() {
+ var $t = $(this); var $o = $t.offset();
+ if(this != i.element[0]) i.snapElements.push({
+ item: this,
+ width: $t.outerWidth(), height: $t.outerHeight(),
+ top: $o.top, left: $o.left
+ });
+ });
+
+ },
+ drag: function(event, ui) {
+
+ var inst = $(this).data("draggable"), o = inst.options;
+ var d = o.snapTolerance;
+
+ var x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+ y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+ for (var i = inst.snapElements.length - 1; i >= 0; i--){
+
+ var l = inst.snapElements[i].left, r = l + inst.snapElements[i].width,
+ t = inst.snapElements[i].top, b = t + inst.snapElements[i].height;
+
+ //Yes, I know, this is insane ;)
+ if(!((l-d < x1 && x1 < r+d && t-d < y1 && y1 < b+d) || (l-d < x1 && x1 < r+d && t-d < y2 && y2 < b+d) || (l-d < x2 && x2 < r+d && t-d < y1 && y1 < b+d) || (l-d < x2 && x2 < r+d && t-d < y2 && y2 < b+d))) {
+ if(inst.snapElements[i].snapping) (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ inst.snapElements[i].snapping = false;
+ continue;
+ }
+
+ if(o.snapMode != 'inner') {
+ var ts = Math.abs(t - y2) <= d;
+ var bs = Math.abs(b - y1) <= d;
+ var ls = Math.abs(l - x2) <= d;
+ var rs = Math.abs(r - x1) <= d;
+ if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
+ if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
+ if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
+ }
+
+ var first = (ts || bs || ls || rs);
+
+ if(o.snapMode != 'outer') {
+ var ts = Math.abs(t - y1) <= d;
+ var bs = Math.abs(b - y2) <= d;
+ var ls = Math.abs(l - x1) <= d;
+ var rs = Math.abs(r - x2) <= d;
+ if(ts) ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
+ if(bs) ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
+ if(ls) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
+ if(rs) ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
+ }
+
+ if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first))
+ (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+ inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+ };
+
+ }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+ start: function(event, ui) {
+
+ var o = $(this).data("draggable").options;
+
+ var group = $.makeArray($(o.stack)).sort(function(a,b) {
+ return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
+ });
+ if (!group.length) { return; }
+
+ var min = parseInt(group[0].style.zIndex) || 0;
+ $(group).each(function(i) {
+ this.style.zIndex = min + i;
+ });
+
+ this[0].style.zIndex = min + group.length;
+
+ }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+ start: function(event, ui) {
+ var t = $(ui.helper), o = $(this).data("draggable").options;
+ if(t.css("zIndex")) o._zIndex = t.css("zIndex");
+ t.css('zIndex', o.zIndex);
+ },
+ stop: function(event, ui) {
+ var o = $(this).data("draggable").options;
+ if(o._zIndex) $(ui.helper).css('zIndex', o._zIndex);
+ }
+});
+
+})(jQuery);
+/*
+ * jQuery UI Droppable 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Droppables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.mouse.js
+ * jquery.ui.draggable.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.droppable", {
+ widgetEventPrefix: "drop",
+ options: {
+ accept: '*',
+ activeClass: false,
+ addClasses: true,
+ greedy: false,
+ hoverClass: false,
+ scope: 'default',
+ tolerance: 'intersect'
+ },
+ _create: function() {
+
+ var o = this.options, accept = o.accept;
+ this.isover = 0; this.isout = 1;
+
+ this.accept = $.isFunction(accept) ? accept : function(d) {
+ return d.is(accept);
+ };
+
+ //Store the droppable's proportions
+ this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight };
+
+ // Add the reference and positions to the manager
+ $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || [];
+ $.ui.ddmanager.droppables[o.scope].push(this);
+
+ (o.addClasses && this.element.addClass("ui-droppable"));
+
+ },
+
+ destroy: function() {
+ var drop = $.ui.ddmanager.droppables[this.options.scope];
+ for ( var i = 0; i < drop.length; i++ )
+ if ( drop[i] == this )
+ drop.splice(i, 1);
+
+ this.element
+ .removeClass("ui-droppable ui-droppable-disabled")
+ .removeData("droppable")
+ .unbind(".droppable");
+
+ return this;
+ },
+
+ _setOption: function(key, value) {
+
+ if(key == 'accept') {
+ this.accept = $.isFunction(value) ? value : function(d) {
+ return d.is(value);
+ };
+ }
+ $.Widget.prototype._setOption.apply(this, arguments);
+ },
+
+ _activate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) this.element.addClass(this.options.activeClass);
+ (draggable && this._trigger('activate', event, this.ui(draggable)));
+ },
+
+ _deactivate: function(event) {
+ var draggable = $.ui.ddmanager.current;
+ if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
+ (draggable && this._trigger('deactivate', event, this.ui(draggable)));
+ },
+
+ _over: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+ if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) this.element.addClass(this.options.hoverClass);
+ this._trigger('over', event, this.ui(draggable));
+ }
+
+ },
+
+ _out: function(event) {
+
+ var draggable = $.ui.ddmanager.current;
+ if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return; // Bail if draggable and droppable are same element
+
+ if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
+ this._trigger('out', event, this.ui(draggable));
+ }
+
+ },
+
+ _drop: function(event,custom) {
+
+ var draggable = custom || $.ui.ddmanager.current;
+ if (!draggable || (draggable.currentItem || draggable.element)[0] == this.element[0]) return false; // Bail if draggable and droppable are same element
+
+ var childrenIntersection = false;
+ this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function() {
+ var inst = $.data(this, 'droppable');
+ if(
+ inst.options.greedy
+ && !inst.options.disabled
+ && inst.options.scope == draggable.options.scope
+ && inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element))
+ && $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance)
+ ) { childrenIntersection = true; return false; }
+ });
+ if(childrenIntersection) return false;
+
+ if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ if(this.options.activeClass) this.element.removeClass(this.options.activeClass);
+ if(this.options.hoverClass) this.element.removeClass(this.options.hoverClass);
+ this._trigger('drop', event, this.ui(draggable));
+ return this.element;
+ }
+
+ return false;
+
+ },
+
+ ui: function(c) {
+ return {
+ draggable: (c.currentItem || c.element),
+ helper: c.helper,
+ position: c.position,
+ offset: c.positionAbs
+ };
+ }
+
+});
+
+$.extend($.ui.droppable, {
+ version: "1.8.18"
+});
+
+$.ui.intersect = function(draggable, droppable, toleranceMode) {
+
+ if (!droppable.offset) return false;
+
+ var x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width,
+ y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height;
+ var l = droppable.offset.left, r = l + droppable.proportions.width,
+ t = droppable.offset.top, b = t + droppable.proportions.height;
+
+ switch (toleranceMode) {
+ case 'fit':
+ return (l <= x1 && x2 <= r
+ && t <= y1 && y2 <= b);
+ break;
+ case 'intersect':
+ return (l < x1 + (draggable.helperProportions.width / 2) // Right Half
+ && x2 - (draggable.helperProportions.width / 2) < r // Left Half
+ && t < y1 + (draggable.helperProportions.height / 2) // Bottom Half
+ && y2 - (draggable.helperProportions.height / 2) < b ); // Top Half
+ break;
+ case 'pointer':
+ var draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left),
+ draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top),
+ isOver = $.ui.isOver(draggableTop, draggableLeft, t, l, droppable.proportions.height, droppable.proportions.width);
+ return isOver;
+ break;
+ case 'touch':
+ return (
+ (y1 >= t && y1 <= b) || // Top edge touching
+ (y2 >= t && y2 <= b) || // Bottom edge touching
+ (y1 < t && y2 > b) // Surrounded vertically
+ ) && (
+ (x1 >= l && x1 <= r) || // Left edge touching
+ (x2 >= l && x2 <= r) || // Right edge touching
+ (x1 < l && x2 > r) // Surrounded horizontally
+ );
+ break;
+ default:
+ return false;
+ break;
+ }
+
+};
+
+/*
+ This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+ current: null,
+ droppables: { 'default': [] },
+ prepareOffsets: function(t, event) {
+
+ var m = $.ui.ddmanager.droppables[t.options.scope] || [];
+ var type = event ? event.type : null; // workaround for #2317
+ var list = (t.currentItem || t.element).find(":data(droppable)").andSelf();
+
+ droppablesLoop: for (var i = 0; i < m.length; i++) {
+
+ if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) continue; //No disabled and non-accepted
+ for (var j=0; j < list.length; j++) { if(list[j] == m[i].element[0]) { m[i].proportions.height = 0; continue droppablesLoop; } }; //Filter out elements in the current dragged item
+ m[i].visible = m[i].element.css("display") != "none"; if(!m[i].visible) continue; //If the element is not visible, continue
+
+ if(type == "mousedown") m[i]._activate.call(m[i], event); //Activate the droppable if used directly from draggables
+
+ m[i].offset = m[i].element.offset();
+ m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
+
+ }
+
+ },
+ drop: function(draggable, event) {
+
+ var dropped = false;
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
+
+ if(!this.options) return;
+ if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance))
+ dropped = this._drop.call(this, event) || dropped;
+
+ if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) {
+ this.isout = 1; this.isover = 0;
+ this._deactivate.call(this, event);
+ }
+
+ });
+ return dropped;
+
+ },
+ dragStart: function( draggable, event ) {
+ //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+ draggable.element.parents( ":not(body,html)" ).bind( "scroll.droppable", function() {
+ if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
+ });
+ },
+ drag: function(draggable, event) {
+
+ //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+ if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
+
+ //Run through all droppables and check their positions based on specific tolerance options
+ $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() {
+
+ if(this.options.disabled || this.greedyChild || !this.visible) return;
+ var intersects = $.ui.intersect(draggable, this, this.options.tolerance);
+
+ var c = !intersects && this.isover == 1 ? 'isout' : (intersects && this.isover == 0 ? 'isover' : null);
+ if(!c) return;
+
+ var parentInstance;
+ if (this.options.greedy) {
+ var parent = this.element.parents(':data(droppable):eq(0)');
+ if (parent.length) {
+ parentInstance = $.data(parent[0], 'droppable');
+ parentInstance.greedyChild = (c == 'isover' ? 1 : 0);
+ }
+ }
+
+ // we just moved into a greedy child
+ if (parentInstance && c == 'isover') {
+ parentInstance['isover'] = 0;
+ parentInstance['isout'] = 1;
+ parentInstance._out.call(parentInstance, event);
+ }
+
+ this[c] = 1; this[c == 'isout' ? 'isover' : 'isout'] = 0;
+ this[c == "isover" ? "_over" : "_out"].call(this, event);
+
+ // we just moved out of a greedy child
+ if (parentInstance && c == 'isout') {
+ parentInstance['isout'] = 0;
+ parentInstance['isover'] = 1;
+ parentInstance._over.call(parentInstance, event);
+ }
+ });
+
+ },
+ dragStop: function( draggable, event ) {
+ draggable.element.parents( ":not(body,html)" ).unbind( "scroll.droppable" );
+ //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+ if( !draggable.options.refreshPositions ) $.ui.ddmanager.prepareOffsets( draggable, event );
+ }
+};
+
+})(jQuery);
+/*
+ * jQuery UI Resizable 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Resizables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.resizable", $.ui.mouse, {
+ widgetEventPrefix: "resize",
+ options: {
+ alsoResize: false,
+ animate: false,
+ animateDuration: "slow",
+ animateEasing: "swing",
+ aspectRatio: false,
+ autoHide: false,
+ containment: false,
+ ghost: false,
+ grid: false,
+ handles: "e,s,se",
+ helper: false,
+ maxHeight: null,
+ maxWidth: null,
+ minHeight: 10,
+ minWidth: 10,
+ zIndex: 1000
+ },
+ _create: function() {
+
+ var self = this, o = this.options;
+ this.element.addClass("ui-resizable");
+
+ $.extend(this, {
+ _aspectRatio: !!(o.aspectRatio),
+ aspectRatio: o.aspectRatio,
+ originalElement: this.element,
+ _proportionallyResizeElements: [],
+ _helper: o.helper || o.ghost || o.animate ? o.helper || 'ui-resizable-helper' : null
+ });
+
+ //Wrap the element if it cannot hold child nodes
+ if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+ //Create a wrapper element and set the wrapper to the new current internal element
+ this.element.wrap(
+ $('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({
+ position: this.element.css('position'),
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight(),
+ top: this.element.css('top'),
+ left: this.element.css('left')
+ })
+ );
+
+ //Overwrite the original this.element
+ this.element = this.element.parent().data(
+ "resizable", this.element.data('resizable')
+ );
+
+ this.elementIsWrapper = true;
+
+ //Move margins to the wrapper
+ this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
+ this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
+
+ //Prevent Safari textarea resize
+ this.originalResizeStyle = this.originalElement.css('resize');
+ this.originalElement.css('resize', 'none');
+
+ //Push the actual element to our proportionallyResize internal array
+ this._proportionallyResizeElements.push(this.originalElement.css({ position: 'static', zoom: 1, display: 'block' }));
+
+ // avoid IE jump (hard set the margin)
+ this.originalElement.css({ margin: this.originalElement.css('margin') });
+
+ // fix handlers offset
+ this._proportionallyResize();
+
+ }
+
+ this.handles = o.handles || (!$('.ui-resizable-handle', this.element).length ? "e,s,se" : { n: '.ui-resizable-n', e: '.ui-resizable-e', s: '.ui-resizable-s', w: '.ui-resizable-w', se: '.ui-resizable-se', sw: '.ui-resizable-sw', ne: '.ui-resizable-ne', nw: '.ui-resizable-nw' });
+ if(this.handles.constructor == String) {
+
+ if(this.handles == 'all') this.handles = 'n,e,s,w,se,sw,ne,nw';
+ var n = this.handles.split(","); this.handles = {};
+
+ for(var i = 0; i < n.length; i++) {
+
+ var handle = $.trim(n[i]), hname = 'ui-resizable-'+handle;
+ var axis = $('<div class="ui-resizable-handle ' + hname + '"></div>');
+
+ // increase zIndex of sw, se, ne, nw axis
+ //TODO : this modifies original option
+ if(/sw|se|ne|nw/.test(handle)) axis.css({ zIndex: ++o.zIndex });
+
+ //TODO : What's going on here?
+ if ('se' == handle) {
+ axis.addClass('ui-icon ui-icon-gripsmall-diagonal-se');
+ };
+
+ //Insert into internal handles object and append to element
+ this.handles[handle] = '.ui-resizable-'+handle;
+ this.element.append(axis);
+ }
+
+ }
+
+ this._renderAxis = function(target) {
+
+ target = target || this.element;
+
+ for(var i in this.handles) {
+
+ if(this.handles[i].constructor == String)
+ this.handles[i] = $(this.handles[i], this.element).show();
+
+ //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls)
+ if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+ var axis = $(this.handles[i], this.element), padWrapper = 0;
+
+ //Checking the correct pad and border
+ padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+ //The padding type i have to apply...
+ var padPos = [ 'padding',
+ /ne|nw|n/.test(i) ? 'Top' :
+ /se|sw|s/.test(i) ? 'Bottom' :
+ /^e$/.test(i) ? 'Right' : 'Left' ].join("");
+
+ target.css(padPos, padWrapper);
+
+ this._proportionallyResize();
+
+ }
+
+ //TODO: What's that good for? There's not anything to be executed left
+ if(!$(this.handles[i]).length)
+ continue;
+
+ }
+ };
+
+ //TODO: make renderAxis a prototype function
+ this._renderAxis(this.element);
+
+ this._handles = $('.ui-resizable-handle', this.element)
+ .disableSelection();
+
+ //Matching axis name
+ this._handles.mouseover(function() {
+ if (!self.resizing) {
+ if (this.className)
+ var axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+ //Axis, default = se
+ self.axis = axis && axis[1] ? axis[1] : 'se';
+ }
+ });
+
+ //If we want to auto hide the elements
+ if (o.autoHide) {
+ this._handles.hide();
+ $(this.element)
+ .addClass("ui-resizable-autohide")
+ .hover(function() {
+ if (o.disabled) return;
+ $(this).removeClass("ui-resizable-autohide");
+ self._handles.show();
+ },
+ function(){
+ if (o.disabled) return;
+ if (!self.resizing) {
+ $(this).addClass("ui-resizable-autohide");
+ self._handles.hide();
+ }
+ });
+ }
+
+ //Initialize the mouse interaction
+ this._mouseInit();
+
+ },
+
+ destroy: function() {
+
+ this._mouseDestroy();
+
+ var _destroy = function(exp) {
+ $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+ .removeData("resizable").unbind(".resizable").find('.ui-resizable-handle').remove();
+ };
+
+ //TODO: Unwrap at same DOM position
+ if (this.elementIsWrapper) {
+ _destroy(this.element);
+ var wrapper = this.element;
+ wrapper.after(
+ this.originalElement.css({
+ position: wrapper.css('position'),
+ width: wrapper.outerWidth(),
+ height: wrapper.outerHeight(),
+ top: wrapper.css('top'),
+ left: wrapper.css('left')
+ })
+ ).remove();
+ }
+
+ this.originalElement.css('resize', this.originalResizeStyle);
+ _destroy(this.originalElement);
+
+ return this;
+ },
+
+ _mouseCapture: function(event) {
+ var handle = false;
+ for (var i in this.handles) {
+ if ($(this.handles[i])[0] == event.target) {
+ handle = true;
+ }
+ }
+
+ return !this.options.disabled && handle;
+ },
+
+ _mouseStart: function(event) {
+
+ var o = this.options, iniPos = this.element.position(), el = this.element;
+
+ this.resizing = true;
+ this.documentScroll = { top: $(document).scrollTop(), left: $(document).scrollLeft() };
+
+ // bugfix for http://dev.jquery.com/ticket/1749
+ if (el.is('.ui-draggable') || (/absolute/).test(el.css('position'))) {
+ el.css({ position: 'absolute', top: iniPos.top, left: iniPos.left });
+ }
+
+ this._renderProxy();
+
+ var curleft = num(this.helper.css('left')), curtop = num(this.helper.css('top'));
+
+ if (o.containment) {
+ curleft += $(o.containment).scrollLeft() || 0;
+ curtop += $(o.containment).scrollTop() || 0;
+ }
+
+ //Store needed variables
+ this.offset = this.helper.offset();
+ this.position = { left: curleft, top: curtop };
+ this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
+ this.originalPosition = { left: curleft, top: curtop };
+ this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
+ this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+ //Aspect Ratio
+ this.aspectRatio = (typeof o.aspectRatio == 'number') ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
+
+ var cursor = $('.ui-resizable-' + this.axis).css('cursor');
+ $('body').css('cursor', cursor == 'auto' ? this.axis + '-resize' : cursor);
+
+ el.addClass("ui-resizable-resizing");
+ this._propagate("start", event);
+ return true;
+ },
+
+ _mouseDrag: function(event) {
+
+ //Increase performance, avoid regex
+ var el = this.helper, o = this.options, props = {},
+ self = this, smp = this.originalMousePosition, a = this.axis;
+
+ var dx = (event.pageX-smp.left)||0, dy = (event.pageY-smp.top)||0;
+ var trigger = this._change[a];
+ if (!trigger) return false;
+
+ // Calculate the attrs that will be change
+ var data = trigger.apply(this, [event, dx, dy]), ie6 = $.browser.msie && $.browser.version < 7, csdif = this.sizeDiff;
+
+ // Put this in the mouseDrag handler since the user can start pressing shift while resizing
+ this._updateVirtualBoundaries(event.shiftKey);
+ if (this._aspectRatio || event.shiftKey)
+ data = this._updateRatio(data, event);
+
+ data = this._respectSize(data, event);
+
+ // plugins callbacks need to be called first
+ this._propagate("resize", event);
+
+ el.css({
+ top: this.position.top + "px", left: this.position.left + "px",
+ width: this.size.width + "px", height: this.size.height + "px"
+ });
+
+ if (!this._helper && this._proportionallyResizeElements.length)
+ this._proportionallyResize();
+
+ this._updateCache(data);
+
+ // calling the user callback at the end
+ this._trigger('resize', event, this.ui());
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+
+ this.resizing = false;
+ var o = this.options, self = this;
+
+ if(this._helper) {
+ var pr = this._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var s = { width: (self.helper.width() - soffsetw), height: (self.helper.height() - soffseth) },
+ left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
+ top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
+
+ if (!o.animate)
+ this.element.css($.extend(s, { top: top, left: left }));
+
+ self.helper.height(self.size.height);
+ self.helper.width(self.size.width);
+
+ if (this._helper && !o.animate) this._proportionallyResize();
+ }
+
+ $('body').css('cursor', 'auto');
+
+ this.element.removeClass("ui-resizable-resizing");
+
+ this._propagate("stop", event);
+
+ if (this._helper) this.helper.remove();
+ return false;
+
+ },
+
+ _updateVirtualBoundaries: function(forceAspectRatio) {
+ var o = this.options, pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b;
+
+ b = {
+ minWidth: isNumber(o.minWidth) ? o.minWidth : 0,
+ maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+ minHeight: isNumber(o.minHeight) ? o.minHeight : 0,
+ maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity
+ };
+
+ if(this._aspectRatio || forceAspectRatio) {
+ // We want to create an enclosing box whose aspect ration is the requested one
+ // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension
+ pMinWidth = b.minHeight * this.aspectRatio;
+ pMinHeight = b.minWidth / this.aspectRatio;
+ pMaxWidth = b.maxHeight * this.aspectRatio;
+ pMaxHeight = b.maxWidth / this.aspectRatio;
+
+ if(pMinWidth > b.minWidth) b.minWidth = pMinWidth;
+ if(pMinHeight > b.minHeight) b.minHeight = pMinHeight;
+ if(pMaxWidth < b.maxWidth) b.maxWidth = pMaxWidth;
+ if(pMaxHeight < b.maxHeight) b.maxHeight = pMaxHeight;
+ }
+ this._vBoundaries = b;
+ },
+
+ _updateCache: function(data) {
+ var o = this.options;
+ this.offset = this.helper.offset();
+ if (isNumber(data.left)) this.position.left = data.left;
+ if (isNumber(data.top)) this.position.top = data.top;
+ if (isNumber(data.height)) this.size.height = data.height;
+ if (isNumber(data.width)) this.size.width = data.width;
+ },
+
+ _updateRatio: function(data, event) {
+
+ var o = this.options, cpos = this.position, csize = this.size, a = this.axis;
+
+ if (isNumber(data.height)) data.width = (data.height * this.aspectRatio);
+ else if (isNumber(data.width)) data.height = (data.width / this.aspectRatio);
+
+ if (a == 'sw') {
+ data.left = cpos.left + (csize.width - data.width);
+ data.top = null;
+ }
+ if (a == 'nw') {
+ data.top = cpos.top + (csize.height - data.height);
+ data.left = cpos.left + (csize.width - data.width);
+ }
+
+ return data;
+ },
+
+ _respectSize: function(data, event) {
+
+ var el = this.helper, o = this._vBoundaries, pRatio = this._aspectRatio || event.shiftKey, a = this.axis,
+ ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+ isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height);
+
+ if (isminw) data.width = o.minWidth;
+ if (isminh) data.height = o.minHeight;
+ if (ismaxw) data.width = o.maxWidth;
+ if (ismaxh) data.height = o.maxHeight;
+
+ var dw = this.originalPosition.left + this.originalSize.width, dh = this.position.top + this.size.height;
+ var cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+
+ if (isminw && cw) data.left = dw - o.minWidth;
+ if (ismaxw && cw) data.left = dw - o.maxWidth;
+ if (isminh && ch) data.top = dh - o.minHeight;
+ if (ismaxh && ch) data.top = dh - o.maxHeight;
+
+ // fixing jump error on top/left - bug #2330
+ var isNotwh = !data.width && !data.height;
+ if (isNotwh && !data.left && data.top) data.top = null;
+ else if (isNotwh && !data.top && data.left) data.left = null;
+
+ return data;
+ },
+
+ _proportionallyResize: function() {
+
+ var o = this.options;
+ if (!this._proportionallyResizeElements.length) return;
+ var element = this.helper || this.element;
+
+ for (var i=0; i < this._proportionallyResizeElements.length; i++) {
+
+ var prel = this._proportionallyResizeElements[i];
+
+ if (!this.borderDif) {
+ var b = [prel.css('borderTopWidth'), prel.css('borderRightWidth'), prel.css('borderBottomWidth'), prel.css('borderLeftWidth')],
+ p = [prel.css('paddingTop'), prel.css('paddingRight'), prel.css('paddingBottom'), prel.css('paddingLeft')];
+
+ this.borderDif = $.map(b, function(v, i) {
+ var border = parseInt(v,10)||0, padding = parseInt(p[i],10)||0;
+ return border + padding;
+ });
+ }
+
+ if ($.browser.msie && !(!($(element).is(':hidden') || $(element).parents(':hidden').length)))
+ continue;
+
+ prel.css({
+ height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
+ width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
+ });
+
+ };
+
+ },
+
+ _renderProxy: function() {
+
+ var el = this.element, o = this.options;
+ this.elementOffset = el.offset();
+
+ if(this._helper) {
+
+ this.helper = this.helper || $('<div style="overflow:hidden;"></div>');
+
+ // fix ie6 offset TODO: This seems broken
+ var ie6 = $.browser.msie && $.browser.version < 7, ie6offset = (ie6 ? 1 : 0),
+ pxyoffset = ( ie6 ? 2 : -1 );
+
+ this.helper.addClass(this._helper).css({
+ width: this.element.outerWidth() + pxyoffset,
+ height: this.element.outerHeight() + pxyoffset,
+ position: 'absolute',
+ left: this.elementOffset.left - ie6offset +'px',
+ top: this.elementOffset.top - ie6offset +'px',
+ zIndex: ++o.zIndex //TODO: Don't modify option
+ });
+
+ this.helper
+ .appendTo("body")
+ .disableSelection();
+
+ } else {
+ this.helper = this.element;
+ }
+
+ },
+
+ _change: {
+ e: function(event, dx, dy) {
+ return { width: this.originalSize.width + dx };
+ },
+ w: function(event, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { left: sp.left + dx, width: cs.width - dx };
+ },
+ n: function(event, dx, dy) {
+ var o = this.options, cs = this.originalSize, sp = this.originalPosition;
+ return { top: sp.top + dy, height: cs.height - dy };
+ },
+ s: function(event, dx, dy) {
+ return { height: this.originalSize.height + dy };
+ },
+ se: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ sw: function(event, dx, dy) {
+ return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ },
+ ne: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
+ },
+ nw: function(event, dx, dy) {
+ return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
+ }
+ },
+
+ _propagate: function(n, event) {
+ $.ui.plugin.call(this, n, [event, this.ui()]);
+ (n != "resize" && this._trigger(n, event, this.ui()));
+ },
+
+ plugins: {},
+
+ ui: function() {
+ return {
+ originalElement: this.originalElement,
+ element: this.element,
+ helper: this.helper,
+ position: this.position,
+ size: this.size,
+ originalSize: this.originalSize,
+ originalPosition: this.originalPosition
+ };
+ }
+
+});
+
+$.extend($.ui.resizable, {
+ version: "1.8.18"
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+ start: function (event, ui) {
+ var self = $(this).data("resizable"), o = self.options;
+
+ var _store = function (exp) {
+ $(exp).each(function() {
+ var el = $(this);
+ el.data("resizable-alsoresize", {
+ width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+ left: parseInt(el.css('left'), 10), top: parseInt(el.css('top'), 10)
+ });
+ });
+ };
+
+ if (typeof(o.alsoResize) == 'object' && !o.alsoResize.parentNode) {
+ if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
+ else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
+ }else{
+ _store(o.alsoResize);
+ }
+ },
+
+ resize: function (event, ui) {
+ var self = $(this).data("resizable"), o = self.options, os = self.originalSize, op = self.originalPosition;
+
+ var delta = {
+ height: (self.size.height - os.height) || 0, width: (self.size.width - os.width) || 0,
+ top: (self.position.top - op.top) || 0, left: (self.position.left - op.left) || 0
+ },
+
+ _alsoResize = function (exp, c) {
+ $(exp).each(function() {
+ var el = $(this), start = $(this).data("resizable-alsoresize"), style = {},
+ css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ['width', 'height'] : ['width', 'height', 'top', 'left'];
+
+ $.each(css, function (i, prop) {
+ var sum = (start[prop]||0) + (delta[prop]||0);
+ if (sum && sum >= 0)
+ style[prop] = sum || null;
+ });
+
+ el.css(style);
+ });
+ };
+
+ if (typeof(o.alsoResize) == 'object' && !o.alsoResize.nodeType) {
+ $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
+ }else{
+ _alsoResize(o.alsoResize);
+ }
+ },
+
+ stop: function (event, ui) {
+ $(this).removeData("resizable-alsoresize");
+ }
+});
+
+$.ui.plugin.add("resizable", "animate", {
+
+ stop: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options;
+
+ var pr = self._proportionallyResizeElements, ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+ soffseth = ista && $.ui.hasScroll(pr[0], 'left') /* TODO - jump height */ ? 0 : self.sizeDiff.height,
+ soffsetw = ista ? 0 : self.sizeDiff.width;
+
+ var style = { width: (self.size.width - soffsetw), height: (self.size.height - soffseth) },
+ left = (parseInt(self.element.css('left'), 10) + (self.position.left - self.originalPosition.left)) || null,
+ top = (parseInt(self.element.css('top'), 10) + (self.position.top - self.originalPosition.top)) || null;
+
+ self.element.animate(
+ $.extend(style, top && left ? { top: top, left: left } : {}), {
+ duration: o.animateDuration,
+ easing: o.animateEasing,
+ step: function() {
+
+ var data = {
+ width: parseInt(self.element.css('width'), 10),
+ height: parseInt(self.element.css('height'), 10),
+ top: parseInt(self.element.css('top'), 10),
+ left: parseInt(self.element.css('left'), 10)
+ };
+
+ if (pr && pr.length) $(pr[0]).css({ width: data.width, height: data.height });
+
+ // propagating resize, and updating values for each animation step
+ self._updateCache(data);
+ self._propagate("resize", event);
+
+ }
+ }
+ );
+ }
+
+});
+
+$.ui.plugin.add("resizable", "containment", {
+
+ start: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options, el = self.element;
+ var oc = o.containment, ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc;
+ if (!ce) return;
+
+ self.containerElement = $(ce);
+
+ if (/document/.test(oc) || oc == document) {
+ self.containerOffset = { left: 0, top: 0 };
+ self.containerPosition = { left: 0, top: 0 };
+
+ self.parentData = {
+ element: $(document), left: 0, top: 0,
+ width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight
+ };
+ }
+
+ // i'm a node, so compute top, left, right, bottom
+ else {
+ var element = $(ce), p = [];
+ $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); });
+
+ self.containerOffset = element.offset();
+ self.containerPosition = element.position();
+ self.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) };
+
+ var co = self.containerOffset, ch = self.containerSize.height, cw = self.containerSize.width,
+ width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ), height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch);
+
+ self.parentData = {
+ element: ce, left: co.left, top: co.top, width: width, height: height
+ };
+ }
+ },
+
+ resize: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options,
+ ps = self.containerSize, co = self.containerOffset, cs = self.size, cp = self.position,
+ pRatio = self._aspectRatio || event.shiftKey, cop = { top:0, left:0 }, ce = self.containerElement;
+
+ if (ce[0] != document && (/static/).test(ce.css('position'))) cop = co;
+
+ if (cp.left < (self._helper ? co.left : 0)) {
+ self.size.width = self.size.width + (self._helper ? (self.position.left - co.left) : (self.position.left - cop.left));
+ if (pRatio) self.size.height = self.size.width / o.aspectRatio;
+ self.position.left = o.helper ? co.left : 0;
+ }
+
+ if (cp.top < (self._helper ? co.top : 0)) {
+ self.size.height = self.size.height + (self._helper ? (self.position.top - co.top) : self.position.top);
+ if (pRatio) self.size.width = self.size.height * o.aspectRatio;
+ self.position.top = self._helper ? co.top : 0;
+ }
+
+ self.offset.left = self.parentData.left+self.position.left;
+ self.offset.top = self.parentData.top+self.position.top;
+
+ var woset = Math.abs( (self._helper ? self.offset.left - cop.left : (self.offset.left - cop.left)) + self.sizeDiff.width ),
+ hoset = Math.abs( (self._helper ? self.offset.top - cop.top : (self.offset.top - co.top)) + self.sizeDiff.height );
+
+ var isParent = self.containerElement.get(0) == self.element.parent().get(0),
+ isOffsetRelative = /relative|absolute/.test(self.containerElement.css('position'));
+
+ if(isParent && isOffsetRelative) woset -= self.parentData.left;
+
+ if (woset + self.size.width >= self.parentData.width) {
+ self.size.width = self.parentData.width - woset;
+ if (pRatio) self.size.height = self.size.width / self.aspectRatio;
+ }
+
+ if (hoset + self.size.height >= self.parentData.height) {
+ self.size.height = self.parentData.height - hoset;
+ if (pRatio) self.size.width = self.size.height * self.aspectRatio;
+ }
+ },
+
+ stop: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options, cp = self.position,
+ co = self.containerOffset, cop = self.containerPosition, ce = self.containerElement;
+
+ var helper = $(self.helper), ho = helper.offset(), w = helper.outerWidth() - self.sizeDiff.width, h = helper.outerHeight() - self.sizeDiff.height;
+
+ if (self._helper && !o.animate && (/relative/).test(ce.css('position')))
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+
+ if (self._helper && !o.animate && (/static/).test(ce.css('position')))
+ $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h });
+
+ }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+ start: function(event, ui) {
+
+ var self = $(this).data("resizable"), o = self.options, cs = self.size;
+
+ self.ghost = self.originalElement.clone();
+ self.ghost
+ .css({ opacity: .25, display: 'block', position: 'relative', height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
+ .addClass('ui-resizable-ghost')
+ .addClass(typeof o.ghost == 'string' ? o.ghost : '');
+
+ self.ghost.appendTo(self.helper);
+
+ },
+
+ resize: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options;
+ if (self.ghost) self.ghost.css({ position: 'relative', height: self.size.height, width: self.size.width });
+ },
+
+ stop: function(event, ui){
+ var self = $(this).data("resizable"), o = self.options;
+ if (self.ghost && self.helper) self.helper.get(0).removeChild(self.ghost.get(0));
+ }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+ resize: function(event, ui) {
+ var self = $(this).data("resizable"), o = self.options, cs = self.size, os = self.originalSize, op = self.originalPosition, a = self.axis, ratio = o._aspectRatio || event.shiftKey;
+ o.grid = typeof o.grid == "number" ? [o.grid, o.grid] : o.grid;
+ var ox = Math.round((cs.width - os.width) / (o.grid[0]||1)) * (o.grid[0]||1), oy = Math.round((cs.height - os.height) / (o.grid[1]||1)) * (o.grid[1]||1);
+
+ if (/^(se|s|e)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ }
+ else if (/^(ne)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ }
+ else if (/^(sw)$/.test(a)) {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.left = op.left - ox;
+ }
+ else {
+ self.size.width = os.width + ox;
+ self.size.height = os.height + oy;
+ self.position.top = op.top - oy;
+ self.position.left = op.left - ox;
+ }
+ }
+
+});
+
+var num = function(v) {
+ return parseInt(v, 10) || 0;
+};
+
+var isNumber = function(value) {
+ return !isNaN(parseInt(value, 10));
+};
+
+})(jQuery);
+/*
+ * jQuery UI Selectable 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Selectables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.selectable", $.ui.mouse, {
+ options: {
+ appendTo: 'body',
+ autoRefresh: true,
+ distance: 0,
+ filter: '*',
+ tolerance: 'touch'
+ },
+ _create: function() {
+ var self = this;
+
+ this.element.addClass("ui-selectable");
+
+ this.dragged = false;
+
+ // cache selectee children based on filter
+ var selectees;
+ this.refresh = function() {
+ selectees = $(self.options.filter, self.element[0]);
+ selectees.addClass("ui-selectee");
+ selectees.each(function() {
+ var $this = $(this);
+ var pos = $this.offset();
+ $.data(this, "selectable-item", {
+ element: this,
+ $element: $this,
+ left: pos.left,
+ top: pos.top,
+ right: pos.left + $this.outerWidth(),
+ bottom: pos.top + $this.outerHeight(),
+ startselected: false,
+ selected: $this.hasClass('ui-selected'),
+ selecting: $this.hasClass('ui-selecting'),
+ unselecting: $this.hasClass('ui-unselecting')
+ });
+ });
+ };
+ this.refresh();
+
+ this.selectees = selectees.addClass("ui-selectee");
+
+ this._mouseInit();
+
+ this.helper = $("<div class='ui-selectable-helper'></div>");
+ },
+
+ destroy: function() {
+ this.selectees
+ .removeClass("ui-selectee")
+ .removeData("selectable-item");
+ this.element
+ .removeClass("ui-selectable ui-selectable-disabled")
+ .removeData("selectable")
+ .unbind(".selectable");
+ this._mouseDestroy();
+
+ return this;
+ },
+
+ _mouseStart: function(event) {
+ var self = this;
+
+ this.opos = [event.pageX, event.pageY];
+
+ if (this.options.disabled)
+ return;
+
+ var options = this.options;
+
+ this.selectees = $(options.filter, this.element[0]);
+
+ this._trigger("start", event);
+
+ $(options.appendTo).append(this.helper);
+ // position helper (lasso)
+ this.helper.css({
+ "left": event.clientX,
+ "top": event.clientY,
+ "width": 0,
+ "height": 0
+ });
+
+ if (options.autoRefresh) {
+ this.refresh();
+ }
+
+ this.selectees.filter('.ui-selected').each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.startselected = true;
+ if (!event.metaKey && !event.ctrlKey) {
+ selectee.$element.removeClass('ui-selected');
+ selectee.selected = false;
+ selectee.$element.addClass('ui-unselecting');
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ self._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ });
+
+ $(event.target).parents().andSelf().each(function() {
+ var selectee = $.data(this, "selectable-item");
+ if (selectee) {
+ var doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass('ui-selected');
+ selectee.$element
+ .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+ .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+ selectee.unselecting = !doSelect;
+ selectee.selecting = doSelect;
+ selectee.selected = doSelect;
+ // selectable (UN)SELECTING callback
+ if (doSelect) {
+ self._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ } else {
+ self._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ return false;
+ }
+ });
+
+ },
+
+ _mouseDrag: function(event) {
+ var self = this;
+ this.dragged = true;
+
+ if (this.options.disabled)
+ return;
+
+ var options = this.options;
+
+ var x1 = this.opos[0], y1 = this.opos[1], x2 = event.pageX, y2 = event.pageY;
+ if (x1 > x2) { var tmp = x2; x2 = x1; x1 = tmp; }
+ if (y1 > y2) { var tmp = y2; y2 = y1; y1 = tmp; }
+ this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1});
+
+ this.selectees.each(function() {
+ var selectee = $.data(this, "selectable-item");
+ //prevent helper from being selected if appendTo: selectable
+ if (!selectee || selectee.element == self.element[0])
+ return;
+ var hit = false;
+ if (options.tolerance == 'touch') {
+ hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+ } else if (options.tolerance == 'fit') {
+ hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+ }
+
+ if (hit) {
+ // SELECT
+ if (selectee.selected) {
+ selectee.$element.removeClass('ui-selected');
+ selectee.selected = false;
+ }
+ if (selectee.unselecting) {
+ selectee.$element.removeClass('ui-unselecting');
+ selectee.unselecting = false;
+ }
+ if (!selectee.selecting) {
+ selectee.$element.addClass('ui-selecting');
+ selectee.selecting = true;
+ // selectable SELECTING callback
+ self._trigger("selecting", event, {
+ selecting: selectee.element
+ });
+ }
+ } else {
+ // UNSELECT
+ if (selectee.selecting) {
+ if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+ selectee.$element.removeClass('ui-selecting');
+ selectee.selecting = false;
+ selectee.$element.addClass('ui-selected');
+ selectee.selected = true;
+ } else {
+ selectee.$element.removeClass('ui-selecting');
+ selectee.selecting = false;
+ if (selectee.startselected) {
+ selectee.$element.addClass('ui-unselecting');
+ selectee.unselecting = true;
+ }
+ // selectable UNSELECTING callback
+ self._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ if (selectee.selected) {
+ if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+ selectee.$element.removeClass('ui-selected');
+ selectee.selected = false;
+
+ selectee.$element.addClass('ui-unselecting');
+ selectee.unselecting = true;
+ // selectable UNSELECTING callback
+ self._trigger("unselecting", event, {
+ unselecting: selectee.element
+ });
+ }
+ }
+ }
+ });
+
+ return false;
+ },
+
+ _mouseStop: function(event) {
+ var self = this;
+
+ this.dragged = false;
+
+ var options = this.options;
+
+ $('.ui-unselecting', this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass('ui-unselecting');
+ selectee.unselecting = false;
+ selectee.startselected = false;
+ self._trigger("unselected", event, {
+ unselected: selectee.element
+ });
+ });
+ $('.ui-selecting', this.element[0]).each(function() {
+ var selectee = $.data(this, "selectable-item");
+ selectee.$element.removeClass('ui-selecting').addClass('ui-selected');
+ selectee.selecting = false;
+ selectee.selected = true;
+ selectee.startselected = true;
+ self._trigger("selected", event, {
+ selected: selectee.element
+ });
+ });
+ this._trigger("stop", event);
+
+ this.helper.remove();
+
+ return false;
+ }
+
+});
+
+$.extend($.ui.selectable, {
+ version: "1.8.18"
+});
+
+})(jQuery);
+/*
+ * jQuery UI Sortable 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Sortables
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.sortable", $.ui.mouse, {
+ widgetEventPrefix: "sort",
+ ready: false,
+ options: {
+ appendTo: "parent",
+ axis: false,
+ connectWith: false,
+ containment: false,
+ cursor: 'auto',
+ cursorAt: false,
+ dropOnEmpty: true,
+ forcePlaceholderSize: false,
+ forceHelperSize: false,
+ grid: false,
+ handle: false,
+ helper: "original",
+ items: '> *',
+ opacity: false,
+ placeholder: false,
+ revert: false,
+ scroll: true,
+ scrollSensitivity: 20,
+ scrollSpeed: 20,
+ scope: "default",
+ tolerance: "intersect",
+ zIndex: 1000
+ },
+ _create: function() {
+
+ var o = this.options;
+ this.containerCache = {};
+ this.element.addClass("ui-sortable");
+
+ //Get the items
+ this.refresh();
+
+ //Let's determine if the items are being displayed horizontally
+ this.floating = this.items.length ? o.axis === 'x' || (/left|right/).test(this.items[0].item.css('float')) || (/inline|table-cell/).test(this.items[0].item.css('display')) : false;
+
+ //Let's determine the parent's offset
+ this.offset = this.element.offset();
+
+ //Initialize mouse events for interaction
+ this._mouseInit();
+
+ //We're ready to go
+ this.ready = true
+
+ },
+
+ destroy: function() {
+ $.Widget.prototype.destroy.call( this );
+ this.element
+ .removeClass("ui-sortable ui-sortable-disabled");
+ this._mouseDestroy();
+
+ for ( var i = this.items.length - 1; i >= 0; i-- )
+ this.items[i].item.removeData(this.widgetName + "-item");
+
+ return this;
+ },
+
+ _setOption: function(key, value){
+ if ( key === "disabled" ) {
+ this.options[ key ] = value;
+
+ this.widget()
+ [ value ? "addClass" : "removeClass"]( "ui-sortable-disabled" );
+ } else {
+ // Don't call widget base _setOption for disable as it adds ui-state-disabled class
+ $.Widget.prototype._setOption.apply(this, arguments);
+ }
+ },
+
+ _mouseCapture: function(event, overrideHandle) {
+ var that = this;
+
+ if (this.reverting) {
+ return false;
+ }
+
+ if(this.options.disabled || this.options.type == 'static') return false;
+
+ //We have to refresh the items data once first
+ this._refreshItems(event);
+
+ //Find out if the clicked node (or one of its parents) is a actual item in this.items
+ var currentItem = null, self = this, nodes = $(event.target).parents().each(function() {
+ if($.data(this, that.widgetName + '-item') == self) {
+ currentItem = $(this);
+ return false;
+ }
+ });
+ if($.data(event.target, that.widgetName + '-item') == self) currentItem = $(event.target);
+
+ if(!currentItem) return false;
+ if(this.options.handle && !overrideHandle) {
+ var validHandle = false;
+
+ $(this.options.handle, currentItem).find("*").andSelf().each(function() { if(this == event.target) validHandle = true; });
+ if(!validHandle) return false;
+ }
+
+ this.currentItem = currentItem;
+ this._removeCurrentsFromItems();
+ return true;
+
+ },
+
+ _mouseStart: function(event, overrideHandle, noActivation) {
+
+ var o = this.options, self = this;
+ this.currentContainer = this;
+
+ //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+ this.refreshPositions();
+
+ //Create and append the visible helper
+ this.helper = this._createHelper(event);
+
+ //Cache the helper size
+ this._cacheHelperProportions();
+
+ /*
+ * - Position generation -
+ * This block generates everything position related - it's the core of draggables.
+ */
+
+ //Cache the margins of the original element
+ this._cacheMargins();
+
+ //Get the next scrolling parent
+ this.scrollParent = this.helper.scrollParent();
+
+ //The element's absolute position on the page minus margins
+ this.offset = this.currentItem.offset();
+ this.offset = {
+ top: this.offset.top - this.margins.top,
+ left: this.offset.left - this.margins.left
+ };
+
+ // Only after we got the offset, we can change the helper's position to absolute
+ // TODO: Still need to figure out a way to make relative sorting possible
+ this.helper.css("position", "absolute");
+ this.cssPosition = this.helper.css("position");
+
+ $.extend(this.offset, {
+ click: { //Where the click happened, relative to the element
+ left: event.pageX - this.offset.left,
+ top: event.pageY - this.offset.top
+ },
+ parent: this._getParentOffset(),
+ relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+ });
+
+ //Generate the original position
+ this.originalPosition = this._generatePosition(event);
+ this.originalPageX = event.pageX;
+ this.originalPageY = event.pageY;
+
+ //Adjust the mouse offset relative to the helper if 'cursorAt' is supplied
+ (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+ //Cache the former DOM position
+ this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+ //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+ if(this.helper[0] != this.currentItem[0]) {
+ this.currentItem.hide();
+ }
+
+ //Create the placeholder
+ this._createPlaceholder();
+
+ //Set a containment if given in the options
+ if(o.containment)
+ this._setContainment();
+
+ if(o.cursor) { // cursor option
+ if ($('body').css("cursor")) this._storedCursor = $('body').css("cursor");
+ $('body').css("cursor", o.cursor);
+ }
+
+ if(o.opacity) { // opacity option
+ if (this.helper.css("opacity")) this._storedOpacity = this.helper.css("opacity");
+ this.helper.css("opacity", o.opacity);
+ }
+
+ if(o.zIndex) { // zIndex option
+ if (this.helper.css("zIndex")) this._storedZIndex = this.helper.css("zIndex");
+ this.helper.css("zIndex", o.zIndex);
+ }
+
+ //Prepare scrolling
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML')
+ this.overflowOffset = this.scrollParent.offset();
+
+ //Call callbacks
+ this._trigger("start", event, this._uiHash());
+
+ //Recache the helper size
+ if(!this._preserveHelperProportions)
+ this._cacheHelperProportions();
+
+
+ //Post 'activate' events to possible containers
+ if(!noActivation) {
+ for (var i = this.containers.length - 1; i >= 0; i--) { this.containers[i]._trigger("activate", event, self._uiHash(this)); }
+ }
+
+ //Prepare possible droppables
+ if($.ui.ddmanager)
+ $.ui.ddmanager.current = this;
+
+ if ($.ui.ddmanager && !o.dropBehaviour)
+ $.ui.ddmanager.prepareOffsets(this, event);
+
+ this.dragging = true;
+
+ this.helper.addClass("ui-sortable-helper");
+ this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+ return true;
+
+ },
+
+ _mouseDrag: function(event) {
+
+ //Compute the helpers position
+ this.position = this._generatePosition(event);
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ if (!this.lastPositionAbs) {
+ this.lastPositionAbs = this.positionAbs;
+ }
+
+ //Do scrolling
+ if(this.options.scroll) {
+ var o = this.options, scrolled = false;
+ if(this.scrollParent[0] != document && this.scrollParent[0].tagName != 'HTML') {
+
+ if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity)
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+ else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity)
+ this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+
+ if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity)
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+ else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity)
+ this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+
+ } else {
+
+ if(event.pageY - $(document).scrollTop() < o.scrollSensitivity)
+ scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+ else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity)
+ scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+
+ if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity)
+ scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+ else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity)
+ scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+
+ }
+
+ if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour)
+ $.ui.ddmanager.prepareOffsets(this, event);
+ }
+
+ //Regenerate the absolute position used for position checks
+ this.positionAbs = this._convertPositionTo("absolute");
+
+ //Set the helper position
+ if(!this.options.axis || this.options.axis != "y") this.helper[0].style.left = this.position.left+'px';
+ if(!this.options.axis || this.options.axis != "x") this.helper[0].style.top = this.position.top+'px';
+
+ //Rearrange
+ for (var i = this.items.length - 1; i >= 0; i--) {
+
+ //Cache variables and intersection, continue if no intersection
+ var item = this.items[i], itemElement = item.item[0], intersection = this._intersectsWithPointer(item);
+ if (!intersection) continue;
+
+ if(itemElement != this.currentItem[0] //cannot intersect with itself
+ && this.placeholder[intersection == 1 ? "next" : "prev"]()[0] != itemElement //no useless actions that have been done before
+ && !$.ui.contains(this.placeholder[0], itemElement) //no action if the item moved is the parent of the item checked
+ && (this.options.type == 'semi-dynamic' ? !$.ui.contains(this.element[0], itemElement) : true)
+ //&& itemElement.parentNode == this.placeholder[0].parentNode // only rearrange items within the same container
+ ) {
+
+ this.direction = intersection == 1 ? "down" : "up";
+
+ if (this.options.tolerance == "pointer" || this._intersectsWithSides(item)) {
+ this._rearrange(event, item);
+ } else {
+ break;
+ }
+
+ this._trigger("change", event, this._uiHash());
+ break;
+ }
+ }
+
+ //Post events to containers
+ this._contactContainers(event);
+
+ //Interconnect with droppables
+ if($.ui.ddmanager) $.ui.ddmanager.drag(this, event);
+
+ //Call callbacks
+ this._trigger('sort', event, this._uiHash());
+
+ this.lastPositionAbs = this.positionAbs;
+ return false;
+
+ },
+
+ _mouseStop: function(event, noPropagation) {
+
+ if(!event) return;
+
+ //If we are using droppables, inform the manager about the drop
+ if ($.ui.ddmanager && !this.options.dropBehaviour)
+ $.ui.ddmanager.drop(this, event);
+
+ if(this.options.revert) {
+ var self = this;
+ var cur = self.placeholder.offset();
+
+ self.reverting = true;
+
+ $(this.helper).animate({
+ left: cur.left - this.offset.parent.left - self.margins.left + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollLeft),
+ top: cur.top - this.offset.parent.top - self.margins.top + (this.offsetParent[0] == document.body ? 0 : this.offsetParent[0].scrollTop)
+ }, parseInt(this.options.revert, 10) || 500, function() {
+ self._clear(event);
+ });
+ } else {
+ this._clear(event, noPropagation);
+ }
+
+ return false;
+
+ },
+
+ cancel: function() {
+
+ var self = this;
+
+ if(this.dragging) {
+
+ this._mouseUp({ target: null });
+
+ if(this.options.helper == "original")
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ else
+ this.currentItem.show();
+
+ //Post deactivating events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ this.containers[i]._trigger("deactivate", null, self._uiHash(this));
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", null, self._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ if (this.placeholder) {
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ if(this.placeholder[0].parentNode) this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+ if(this.options.helper != "original" && this.helper && this.helper[0].parentNode) this.helper.remove();
+
+ $.extend(this, {
+ helper: null,
+ dragging: false,
+ reverting: false,
+ _noFinalSort: null
+ });
+
+ if(this.domPosition.prev) {
+ $(this.domPosition.prev).after(this.currentItem);
+ } else {
+ $(this.domPosition.parent).prepend(this.currentItem);
+ }
+ }
+
+ return this;
+
+ },
+
+ serialize: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected);
+ var str = []; o = o || {};
+
+ $(items).each(function() {
+ var res = ($(o.item || this).attr(o.attribute || 'id') || '').match(o.expression || (/(.+)[-=_](.+)/));
+ if(res) str.push((o.key || res[1]+'[]')+'='+(o.key && o.expression ? res[1] : res[2]));
+ });
+
+ if(!str.length && o.key) {
+ str.push(o.key + '=');
+ }
+
+ return str.join('&');
+
+ },
+
+ toArray: function(o) {
+
+ var items = this._getItemsAsjQuery(o && o.connected);
+ var ret = []; o = o || {};
+
+ items.each(function() { ret.push($(o.item || this).attr(o.attribute || 'id') || ''); });
+ return ret;
+
+ },
+
+ /* Be careful with the following core functions */
+ _intersectsWith: function(item) {
+
+ var x1 = this.positionAbs.left,
+ x2 = x1 + this.helperProportions.width,
+ y1 = this.positionAbs.top,
+ y2 = y1 + this.helperProportions.height;
+
+ var l = item.left,
+ r = l + item.width,
+ t = item.top,
+ b = t + item.height;
+
+ var dyClick = this.offset.click.top,
+ dxClick = this.offset.click.left;
+
+ var isOverElement = (y1 + dyClick) > t && (y1 + dyClick) < b && (x1 + dxClick) > l && (x1 + dxClick) < r;
+
+ if( this.options.tolerance == "pointer"
+ || this.options.forcePointerForContainers
+ || (this.options.tolerance != "pointer" && this.helperProportions[this.floating ? 'width' : 'height'] > item[this.floating ? 'width' : 'height'])
+ ) {
+ return isOverElement;
+ } else {
+
+ return (l < x1 + (this.helperProportions.width / 2) // Right Half
+ && x2 - (this.helperProportions.width / 2) < r // Left Half
+ && t < y1 + (this.helperProportions.height / 2) // Bottom Half
+ && y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+ }
+ },
+
+ _intersectsWithPointer: function(item) {
+
+ var isOverElementHeight = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+ isOverElementWidth = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+ isOverElement = isOverElementHeight && isOverElementWidth,
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (!isOverElement)
+ return false;
+
+ return this.floating ?
+ ( ((horizontalDirection && horizontalDirection == "right") || verticalDirection == "down") ? 2 : 1 )
+ : ( verticalDirection && (verticalDirection == "down" ? 2 : 1) );
+
+ },
+
+ _intersectsWithSides: function(item) {
+
+ var isOverBottomHalf = $.ui.isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+ isOverRightHalf = $.ui.isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+ verticalDirection = this._getDragVerticalDirection(),
+ horizontalDirection = this._getDragHorizontalDirection();
+
+ if (this.floating && horizontalDirection) {
+ return ((horizontalDirection == "right" && isOverRightHalf) || (horizontalDirection == "left" && !isOverRightHalf));
+ } else {
+ return verticalDirection && ((verticalDirection == "down" && isOverBottomHalf) || (verticalDirection == "up" && !isOverBottomHalf));
+ }
+
+ },
+
+ _getDragVerticalDirection: function() {
+ var delta = this.positionAbs.top - this.lastPositionAbs.top;
+ return delta != 0 && (delta > 0 ? "down" : "up");
+ },
+
+ _getDragHorizontalDirection: function() {
+ var delta = this.positionAbs.left - this.lastPositionAbs.left;
+ return delta != 0 && (delta > 0 ? "right" : "left");
+ },
+
+ refresh: function(event) {
+ this._refreshItems(event);
+ this.refreshPositions();
+ return this;
+ },
+
+ _connectWith: function() {
+ var options = this.options;
+ return options.connectWith.constructor == String
+ ? [options.connectWith]
+ : options.connectWith;
+ },
+
+ _getItemsAsjQuery: function(connected) {
+
+ var self = this;
+ var items = [];
+ var queries = [];
+ var connectWith = this._connectWith();
+
+ if(connectWith && connected) {
+ for (var i = connectWith.length - 1; i >= 0; i--){
+ var cur = $(connectWith[i]);
+ for (var j = cur.length - 1; j >= 0; j--){
+ var inst = $.data(cur[j], this.widgetName);
+ if(inst && inst != this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), inst]);
+ }
+ };
+ };
+ }
+
+ queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not('.ui-sortable-placeholder'), this]);
+
+ for (var i = queries.length - 1; i >= 0; i--){
+ queries[i][0].each(function() {
+ items.push(this);
+ });
+ };
+
+ return $(items);
+
+ },
+
+ _removeCurrentsFromItems: function() {
+
+ var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+ for (var i=0; i < this.items.length; i++) {
+
+ for (var j=0; j < list.length; j++) {
+ if(list[j] == this.items[i].item[0])
+ this.items.splice(i,1);
+ };
+
+ };
+
+ },
+
+ _refreshItems: function(event) {
+
+ this.items = [];
+ this.containers = [this];
+ var items = this.items;
+ var self = this;
+ var queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]];
+ var connectWith = this._connectWith();
+
+ if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+ for (var i = connectWith.length - 1; i >= 0; i--){
+ var cur = $(connectWith[i]);
+ for (var j = cur.length - 1; j >= 0; j--){
+ var inst = $.data(cur[j], this.widgetName);
+ if(inst && inst != this && !inst.options.disabled) {
+ queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+ this.containers.push(inst);
+ }
+ };
+ };
+ }
+
+ for (var i = queries.length - 1; i >= 0; i--) {
+ var targetData = queries[i][1];
+ var _queries = queries[i][0];
+
+ for (var j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+ var item = $(_queries[j]);
+
+ item.data(this.widgetName + '-item', targetData); // Data for target checking (mouse manager)
+
+ items.push({
+ item: item,
+ instance: targetData,
+ width: 0, height: 0,
+ left: 0, top: 0
+ });
+ };
+ };
+
+ },
+
+ refreshPositions: function(fast) {
+
+ //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+ if(this.offsetParent && this.helper) {
+ this.offset.parent = this._getParentOffset();
+ }
+
+ for (var i = this.items.length - 1; i >= 0; i--){
+ var item = this.items[i];
+
+ //We ignore calculating positions of all connected containers when we're not over them
+ if(item.instance != this.currentContainer && this.currentContainer && item.item[0] != this.currentItem[0])
+ continue;
+
+ var t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+ if (!fast) {
+ item.width = t.outerWidth();
+ item.height = t.outerHeight();
+ }
+
+ var p = t.offset();
+ item.left = p.left;
+ item.top = p.top;
+ };
+
+ if(this.options.custom && this.options.custom.refreshContainers) {
+ this.options.custom.refreshContainers.call(this);
+ } else {
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ var p = this.containers[i].element.offset();
+ this.containers[i].containerCache.left = p.left;
+ this.containers[i].containerCache.top = p.top;
+ this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+ this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+ };
+ }
+
+ return this;
+ },
+
+ _createPlaceholder: function(that) {
+
+ var self = that || this, o = self.options;
+
+ if(!o.placeholder || o.placeholder.constructor == String) {
+ var className = o.placeholder;
+ o.placeholder = {
+ element: function() {
+
+ var el = $(document.createElement(self.currentItem[0].nodeName))
+ .addClass(className || self.currentItem[0].className+" ui-sortable-placeholder")
+ .removeClass("ui-sortable-helper")[0];
+
+ if(!className)
+ el.style.visibility = "hidden";
+
+ return el;
+ },
+ update: function(container, p) {
+
+ // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+ // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+ if(className && !o.forcePlaceholderSize) return;
+
+ //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+ if(!p.height()) { p.height(self.currentItem.innerHeight() - parseInt(self.currentItem.css('paddingTop')||0, 10) - parseInt(self.currentItem.css('paddingBottom')||0, 10)); };
+ if(!p.width()) { p.width(self.currentItem.innerWidth() - parseInt(self.currentItem.css('paddingLeft')||0, 10) - parseInt(self.currentItem.css('paddingRight')||0, 10)); };
+ }
+ };
+ }
+
+ //Create the placeholder
+ self.placeholder = $(o.placeholder.element.call(self.element, self.currentItem));
+
+ //Append it after the actual current item
+ self.currentItem.after(self.placeholder);
+
+ //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+ o.placeholder.update(self, self.placeholder);
+
+ },
+
+ _contactContainers: function(event) {
+
+ // get innermost container that intersects with item
+ var innermostContainer = null, innermostIndex = null;
+
+
+ for (var i = this.containers.length - 1; i >= 0; i--){
+
+ // never consider a container that's located within the item itself
+ if($.ui.contains(this.currentItem[0], this.containers[i].element[0]))
+ continue;
+
+ if(this._intersectsWith(this.containers[i].containerCache)) {
+
+ // if we've already found a container and it's more "inner" than this, then continue
+ if(innermostContainer && $.ui.contains(this.containers[i].element[0], innermostContainer.element[0]))
+ continue;
+
+ innermostContainer = this.containers[i];
+ innermostIndex = i;
+
+ } else {
+ // container doesn't intersect. trigger "out" event if necessary
+ if(this.containers[i].containerCache.over) {
+ this.containers[i]._trigger("out", event, this._uiHash(this));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ }
+
+ // if no intersecting containers found, return
+ if(!innermostContainer) return;
+
+ // move the item into the container if it's not there already
+ if(this.containers.length === 1) {
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ } else if(this.currentContainer != this.containers[innermostIndex]) {
+
+ //When entering a new container, we will find the item with the least distance and append our item near it
+ var dist = 10000; var itemWithLeastDistance = null; var base = this.positionAbs[this.containers[innermostIndex].floating ? 'left' : 'top'];
+ for (var j = this.items.length - 1; j >= 0; j--) {
+ if(!$.ui.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) continue;
+ var cur = this.items[j][this.containers[innermostIndex].floating ? 'left' : 'top'];
+ if(Math.abs(cur - base) < dist) {
+ dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j];
+ }
+ }
+
+ if(!itemWithLeastDistance && !this.options.dropOnEmpty) //Check if dropOnEmpty is enabled
+ return;
+
+ this.currentContainer = this.containers[innermostIndex];
+ itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+ this._trigger("change", event, this._uiHash());
+ this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+
+ //Update the placeholder
+ this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+ this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+ this.containers[innermostIndex].containerCache.over = 1;
+ }
+
+
+ },
+
+ _createHelper: function(event) {
+
+ var o = this.options;
+ var helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper == 'clone' ? this.currentItem.clone() : this.currentItem);
+
+ if(!helper.parents('body').length) //Add the helper to the DOM if that didn't happen already
+ $(o.appendTo != 'parent' ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+
+ if(helper[0] == this.currentItem[0])
+ this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+
+ if(helper[0].style.width == '' || o.forceHelperSize) helper.width(this.currentItem.width());
+ if(helper[0].style.height == '' || o.forceHelperSize) helper.height(this.currentItem.height());
+
+ return helper;
+
+ },
+
+ _adjustOffsetFromHelper: function(obj) {
+ if (typeof obj == 'string') {
+ obj = obj.split(' ');
+ }
+ if ($.isArray(obj)) {
+ obj = {left: +obj[0], top: +obj[1] || 0};
+ }
+ if ('left' in obj) {
+ this.offset.click.left = obj.left + this.margins.left;
+ }
+ if ('right' in obj) {
+ this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+ }
+ if ('top' in obj) {
+ this.offset.click.top = obj.top + this.margins.top;
+ }
+ if ('bottom' in obj) {
+ this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+ }
+ },
+
+ _getParentOffset: function() {
+
+
+ //Get the offsetParent and cache its position
+ this.offsetParent = this.helper.offsetParent();
+ var po = this.offsetParent.offset();
+
+ // This is a special case where we need to modify a offset calculated on start, since the following happened:
+ // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+ // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+ // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+ if(this.cssPosition == 'absolute' && this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) {
+ po.left += this.scrollParent.scrollLeft();
+ po.top += this.scrollParent.scrollTop();
+ }
+
+ if((this.offsetParent[0] == document.body) //This needs to be actually done for all browsers, since pageX/pageY includes this information
+ || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() == 'html' && $.browser.msie)) //Ugly IE fix
+ po = { top: 0, left: 0 };
+
+ return {
+ top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+ left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+ };
+
+ },
+
+ _getRelativeOffset: function() {
+
+ if(this.cssPosition == "relative") {
+ var p = this.currentItem.position();
+ return {
+ top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+ left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+ };
+ } else {
+ return { top: 0, left: 0 };
+ }
+
+ },
+
+ _cacheMargins: function() {
+ this.margins = {
+ left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+ top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+ };
+ },
+
+ _cacheHelperProportions: function() {
+ this.helperProportions = {
+ width: this.helper.outerWidth(),
+ height: this.helper.outerHeight()
+ };
+ },
+
+ _setContainment: function() {
+
+ var o = this.options;
+ if(o.containment == 'parent') o.containment = this.helper[0].parentNode;
+ if(o.containment == 'document' || o.containment == 'window') this.containment = [
+ 0 - this.offset.relative.left - this.offset.parent.left,
+ 0 - this.offset.relative.top - this.offset.parent.top,
+ $(o.containment == 'document' ? document : window).width() - this.helperProportions.width - this.margins.left,
+ ($(o.containment == 'document' ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+ ];
+
+ if(!(/^(document|window|parent)$/).test(o.containment)) {
+ var ce = $(o.containment)[0];
+ var co = $(o.containment).offset();
+ var over = ($(ce).css("overflow") != 'hidden');
+
+ this.containment = [
+ co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+ co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+ co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+ co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+ ];
+ }
+
+ },
+
+ _convertPositionTo: function(d, pos) {
+
+ if(!pos) pos = this.position;
+ var mod = d == "absolute" ? 1 : -1;
+ var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ return {
+ top: (
+ pos.top // The absolute mouse position
+ + this.offset.relative.top * mod // Only for relative positioned nodes: Relative offset from element to offset parent
+ + this.offset.parent.top * mod // The offsetParent's offset without borders (offset + border)
+ - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+ ),
+ left: (
+ pos.left // The absolute mouse position
+ + this.offset.relative.left * mod // Only for relative positioned nodes: Relative offset from element to offset parent
+ + this.offset.parent.left * mod // The offsetParent's offset without borders (offset + border)
+ - ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+ )
+ };
+
+ },
+
+ _generatePosition: function(event) {
+
+ var o = this.options, scroll = this.cssPosition == 'absolute' && !(this.scrollParent[0] != document && $.ui.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+ // This is another very weird special case that only happens for relative elements:
+ // 1. If the css position is relative
+ // 2. and the scroll parent is the document or similar to the offset parent
+ // we have to refresh the relative offset during the scroll so there are no jumps
+ if(this.cssPosition == 'relative' && !(this.scrollParent[0] != document && this.scrollParent[0] != this.offsetParent[0])) {
+ this.offset.relative = this._getRelativeOffset();
+ }
+
+ var pageX = event.pageX;
+ var pageY = event.pageY;
+
+ /*
+ * - Position constraining -
+ * Constrain the position to a mix of grid, containment.
+ */
+
+ if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+ if(this.containment) {
+ if(event.pageX - this.offset.click.left < this.containment[0]) pageX = this.containment[0] + this.offset.click.left;
+ if(event.pageY - this.offset.click.top < this.containment[1]) pageY = this.containment[1] + this.offset.click.top;
+ if(event.pageX - this.offset.click.left > this.containment[2]) pageX = this.containment[2] + this.offset.click.left;
+ if(event.pageY - this.offset.click.top > this.containment[3]) pageY = this.containment[3] + this.offset.click.top;
+ }
+
+ if(o.grid) {
+ var top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+ pageY = this.containment ? (!(top - this.offset.click.top < this.containment[1] || top - this.offset.click.top > this.containment[3]) ? top : (!(top - this.offset.click.top < this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+ var left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+ pageX = this.containment ? (!(left - this.offset.click.left < this.containment[0] || left - this.offset.click.left > this.containment[2]) ? left : (!(left - this.offset.click.left < this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+ }
+
+ }
+
+ return {
+ top: (
+ pageY // The absolute mouse position
+ - this.offset.click.top // Click offset (relative to the element)
+ - this.offset.relative.top // Only for relative positioned nodes: Relative offset from element to offset parent
+ - this.offset.parent.top // The offsetParent's offset without borders (offset + border)
+ + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+ ),
+ left: (
+ pageX // The absolute mouse position
+ - this.offset.click.left // Click offset (relative to the element)
+ - this.offset.relative.left // Only for relative positioned nodes: Relative offset from element to offset parent
+ - this.offset.parent.left // The offsetParent's offset without borders (offset + border)
+ + ($.browser.safari && this.cssPosition == 'fixed' ? 0 : ( this.cssPosition == 'fixed' ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+ )
+ };
+
+ },
+
+ _rearrange: function(event, i, a, hardRefresh) {
+
+ a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction == 'down' ? i.item[0] : i.item[0].nextSibling));
+
+ //Various things done here to improve the performance:
+ // 1. we create a setTimeout, that calls refreshPositions
+ // 2. on the instance, we have a counter variable, that get's higher after every append
+ // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+ // 4. this lets only the last addition to the timeout stack through
+ this.counter = this.counter ? ++this.counter : 1;
+ var self = this, counter = this.counter;
+
+ window.setTimeout(function() {
+ if(counter == self.counter) self.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+ },0);
+
+ },
+
+ _clear: function(event, noPropagation) {
+
+ this.reverting = false;
+ // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+ // everything else normalized again
+ var delayedTriggers = [], self = this;
+
+ // We first have to update the dom position of the actual currentItem
+ // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+ if(!this._noFinalSort && this.currentItem.parent().length) this.placeholder.before(this.currentItem);
+ this._noFinalSort = null;
+
+ if(this.helper[0] == this.currentItem[0]) {
+ for(var i in this._storedCSS) {
+ if(this._storedCSS[i] == 'auto' || this._storedCSS[i] == 'static') this._storedCSS[i] = '';
+ }
+ this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+ } else {
+ this.currentItem.show();
+ }
+
+ if(this.fromOutside && !noPropagation) delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+ if((this.fromOutside || this.domPosition.prev != this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent != this.currentItem.parent()[0]) && !noPropagation) delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+ if(!$.ui.contains(this.element[0], this.currentItem[0])) { //Node was moved out of the current element
+ if(!noPropagation) delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ if($.ui.contains(this.containers[i].element[0], this.currentItem[0]) && !noPropagation) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ }
+ };
+ };
+
+ //Post events to containers
+ for (var i = this.containers.length - 1; i >= 0; i--){
+ if(!noPropagation) delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ if(this.containers[i].containerCache.over) {
+ delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i]));
+ this.containers[i].containerCache.over = 0;
+ }
+ }
+
+ //Do what was originally in plugins
+ if(this._storedCursor) $('body').css("cursor", this._storedCursor); //Reset cursor
+ if(this._storedOpacity) this.helper.css("opacity", this._storedOpacity); //Reset opacity
+ if(this._storedZIndex) this.helper.css("zIndex", this._storedZIndex == 'auto' ? '' : this._storedZIndex); //Reset z-index
+
+ this.dragging = false;
+ if(this.cancelHelperRemoval) {
+ if(!noPropagation) {
+ this._trigger("beforeStop", event, this._uiHash());
+ for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+ return false;
+ }
+
+ if(!noPropagation) this._trigger("beforeStop", event, this._uiHash());
+
+ //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+ this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+ if(this.helper[0] != this.currentItem[0]) this.helper.remove(); this.helper = null;
+
+ if(!noPropagation) {
+ for (var i=0; i < delayedTriggers.length; i++) { delayedTriggers[i].call(this, event); }; //Trigger all delayed events
+ this._trigger("stop", event, this._uiHash());
+ }
+
+ this.fromOutside = false;
+ return true;
+
+ },
+
+ _trigger: function() {
+ if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+ this.cancel();
+ }
+ },
+
+ _uiHash: function(inst) {
+ var self = inst || this;
+ return {
+ helper: self.helper,
+ placeholder: self.placeholder || $([]),
+ position: self.position,
+ originalPosition: self.originalPosition,
+ offset: self.positionAbs,
+ item: self.currentItem,
+ sender: inst ? inst.element : null
+ };
+ }
+
+});
+
+$.extend($.ui.sortable, {
+ version: "1.8.18"
+});
+
+})(jQuery);
+/*
+ * jQuery UI Effects 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/
+ */
+;jQuery.effects || (function($, undefined) {
+
+$.effects = {};
+
+
+
+/******************************************************************************/
+/****************************** COLOR ANIMATIONS ******************************/
+/******************************************************************************/
+
+// override the animation for color styles
+$.each(['backgroundColor', 'borderBottomColor', 'borderLeftColor',
+ 'borderRightColor', 'borderTopColor', 'borderColor', 'color', 'outlineColor'],
+function(i, attr) {
+ $.fx.step[attr] = function(fx) {
+ if (!fx.colorInit) {
+ fx.start = getColor(fx.elem, attr);
+ fx.end = getRGB(fx.end);
+ fx.colorInit = true;
+ }
+
+ fx.elem.style[attr] = 'rgb(' +
+ Math.max(Math.min(parseInt((fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10), 255), 0) + ',' +
+ Math.max(Math.min(parseInt((fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10), 255), 0) + ',' +
+ Math.max(Math.min(parseInt((fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10), 255), 0) + ')';
+ };
+});
+
+// Color Conversion functions from highlightFade
+// By Blair Mitchelmore
+// http://jquery.offput.ca/highlightFade/
+
+// Parse strings looking for color tuples [255,255,255]
+function getRGB(color) {
+ var result;
+
+ // Check if we're already dealing with an array of colors
+ if ( color && color.constructor == Array && color.length == 3 )
+ return color;
+
+ // Look for rgb(num,num,num)
+ if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color))
+ return [parseInt(result[1],10), parseInt(result[2],10), parseInt(result[3],10)];
+
+ // Look for rgb(num%,num%,num%)
+ if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color))
+ return [parseFloat(result[1])*2.55, parseFloat(result[2])*2.55, parseFloat(result[3])*2.55];
+
+ // Look for #a0b1c2
+ if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color))
+ return [parseInt(result[1],16), parseInt(result[2],16), parseInt(result[3],16)];
+
+ // Look for #fff
+ if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color))
+ return [parseInt(result[1]+result[1],16), parseInt(result[2]+result[2],16), parseInt(result[3]+result[3],16)];
+
+ // Look for rgba(0, 0, 0, 0) == transparent in Safari 3
+ if (result = /rgba\(0, 0, 0, 0\)/.exec(color))
+ return colors['transparent'];
+
+ // Otherwise, we're most likely dealing with a named color
+ return colors[$.trim(color).toLowerCase()];
+}
+
+function getColor(elem, attr) {
+ var color;
+
+ do {
+ color = $.curCSS(elem, attr);
+
+ // Keep going until we find an element that has color, or we hit the body
+ if ( color != '' && color != 'transparent' || $.nodeName(elem, "body") )
+ break;
+
+ attr = "backgroundColor";
+ } while ( elem = elem.parentNode );
+
+ return getRGB(color);
+};
+
+// Some named colors to work with
+// From Interface by Stefan Petre
+// http://interface.eyecon.ro/
+
+var colors = {
+ aqua:[0,255,255],
+ azure:[240,255,255],
+ beige:[245,245,220],
+ black:[0,0,0],
+ blue:[0,0,255],
+ brown:[165,42,42],
+ cyan:[0,255,255],
+ darkblue:[0,0,139],
+ darkcyan:[0,139,139],
+ darkgrey:[169,169,169],
+ darkgreen:[0,100,0],
+ darkkhaki:[189,183,107],
+ darkmagenta:[139,0,139],
+ darkolivegreen:[85,107,47],
+ darkorange:[255,140,0],
+ darkorchid:[153,50,204],
+ darkred:[139,0,0],
+ darksalmon:[233,150,122],
+ darkviolet:[148,0,211],
+ fuchsia:[255,0,255],
+ gold:[255,215,0],
+ green:[0,128,0],
+ indigo:[75,0,130],
+ khaki:[240,230,140],
+ lightblue:[173,216,230],
+ lightcyan:[224,255,255],
+ lightgreen:[144,238,144],
+ lightgrey:[211,211,211],
+ lightpink:[255,182,193],
+ lightyellow:[255,255,224],
+ lime:[0,255,0],
+ magenta:[255,0,255],
+ maroon:[128,0,0],
+ navy:[0,0,128],
+ olive:[128,128,0],
+ orange:[255,165,0],
+ pink:[255,192,203],
+ purple:[128,0,128],
+ violet:[128,0,128],
+ red:[255,0,0],
+ silver:[192,192,192],
+ white:[255,255,255],
+ yellow:[255,255,0],
+ transparent: [255,255,255]
+};
+
+
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+
+var classAnimationActions = ['add', 'remove', 'toggle'],
+ shorthandStyles = {
+ border: 1,
+ borderBottom: 1,
+ borderColor: 1,
+ borderLeft: 1,
+ borderRight: 1,
+ borderTop: 1,
+ borderWidth: 1,
+ margin: 1,
+ padding: 1
+ };
+
+function getElementStyles() {
+ var style = document.defaultView
+ ? document.defaultView.getComputedStyle(this, null)
+ : this.currentStyle,
+ newStyle = {},
+ key,
+ camelCase;
+
+ // webkit enumerates style porperties
+ if (style && style.length && style[0] && style[style[0]]) {
+ var len = style.length;
+ while (len--) {
+ key = style[len];
+ if (typeof style[key] == 'string') {
+ camelCase = key.replace(/\-(\w)/g, function(all, letter){
+ return letter.toUpperCase();
+ });
+ newStyle[camelCase] = style[key];
+ }
+ }
+ } else {
+ for (key in style) {
+ if (typeof style[key] === 'string') {
+ newStyle[key] = style[key];
+ }
+ }
+ }
+
+ return newStyle;
+}
+
+function filterStyles(styles) {
+ var name, value;
+ for (name in styles) {
+ value = styles[name];
+ if (
+ // ignore null and undefined values
+ value == null ||
+ // ignore functions (when does this occur?)
+ $.isFunction(value) ||
+ // shorthand styles that need to be expanded
+ name in shorthandStyles ||
+ // ignore scrollbars (break in IE)
+ (/scrollbar/).test(name) ||
+
+ // only colors or values that can be converted to numbers
+ (!(/color/i).test(name) && isNaN(parseFloat(value)))
+ ) {
+ delete styles[name];
+ }
+ }
+
+ return styles;
+}
+
+function styleDifference(oldStyle, newStyle) {
+ var diff = { _: 0 }, // http://dev.jquery.com/ticket/5459
+ name;
+
+ for (name in newStyle) {
+ if (oldStyle[name] != newStyle[name]) {
+ diff[name] = newStyle[name];
+ }
+ }
+
+ return diff;
+}
+
+$.effects.animateClass = function(value, duration, easing, callback) {
+ if ($.isFunction(easing)) {
+ callback = easing;
+ easing = null;
+ }
+
+ return this.queue(function() {
+ var that = $(this),
+ originalStyleAttr = that.attr('style') || ' ',
+ originalStyle = filterStyles(getElementStyles.call(this)),
+ newStyle,
+ className = that.attr('class');
+
+ $.each(classAnimationActions, function(i, action) {
+ if (value[action]) {
+ that[action + 'Class'](value[action]);
+ }
+ });
+ newStyle = filterStyles(getElementStyles.call(this));
+ that.attr('class', className);
+
+ that.animate(styleDifference(originalStyle, newStyle), {
+ queue: false,
+ duration: duration,
+ easing: easing,
+ complete: function() {
+ $.each(classAnimationActions, function(i, action) {
+ if (value[action]) { that[action + 'Class'](value[action]); }
+ });
+ // work around bug in IE by clearing the cssText before setting it
+ if (typeof that.attr('style') == 'object') {
+ that.attr('style').cssText = '';
+ that.attr('style').cssText = originalStyleAttr;
+ } else {
+ that.attr('style', originalStyleAttr);
+ }
+ if (callback) { callback.apply(this, arguments); }
+ $.dequeue( this );
+ }
+ });
+ });
+};
+
+$.fn.extend({
+ _addClass: $.fn.addClass,
+ addClass: function(classNames, speed, easing, callback) {
+ return speed ? $.effects.animateClass.apply(this, [{ add: classNames },speed,easing,callback]) : this._addClass(classNames);
+ },
+
+ _removeClass: $.fn.removeClass,
+ removeClass: function(classNames,speed,easing,callback) {
+ return speed ? $.effects.animateClass.apply(this, [{ remove: classNames },speed,easing,callback]) : this._removeClass(classNames);
+ },
+
+ _toggleClass: $.fn.toggleClass,
+ toggleClass: function(classNames, force, speed, easing, callback) {
+ if ( typeof force == "boolean" || force === undefined ) {
+ if ( !speed ) {
+ // without speed parameter;
+ return this._toggleClass(classNames, force);
+ } else {
+ return $.effects.animateClass.apply(this, [(force?{add:classNames}:{remove:classNames}),speed,easing,callback]);
+ }
+ } else {
+ // without switch parameter;
+ return $.effects.animateClass.apply(this, [{ toggle: classNames },force,speed,easing]);
+ }
+ },
+
+ switchClass: function(remove,add,speed,easing,callback) {
+ return $.effects.animateClass.apply(this, [{ add: add, remove: remove },speed,easing,callback]);
+ }
+});
+
+
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+$.extend($.effects, {
+ version: "1.8.18",
+
+ // Saves a set of properties in a data storage
+ save: function(element, set) {
+ for(var i=0; i < set.length; i++) {
+ if(set[i] !== null) element.data("ec.storage."+set[i], element[0].style[set[i]]);
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function(element, set) {
+ for(var i=0; i < set.length; i++) {
+ if(set[i] !== null) element.css(set[i], element.data("ec.storage."+set[i]));
+ }
+ },
+
+ setMode: function(el, mode) {
+ if (mode == 'toggle') mode = el.is(':hidden') ? 'show' : 'hide'; // Set for toggle
+ return mode;
+ },
+
+ getBaseline: function(origin, original) { // Translates a [top,left] array into a baseline value
+ // this should be a little more flexible in the future to handle a string & hash
+ var y, x;
+ switch (origin[0]) {
+ case 'top': y = 0; break;
+ case 'middle': y = 0.5; break;
+ case 'bottom': y = 1; break;
+ default: y = origin[0] / original.height;
+ };
+ switch (origin[1]) {
+ case 'left': x = 0; break;
+ case 'center': x = 0.5; break;
+ case 'right': x = 1; break;
+ default: x = origin[1] / original.width;
+ };
+ return {x: x, y: y};
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function(element) {
+
+ // if the element is already wrapped, return it
+ if (element.parent().is('.ui-effects-wrapper')) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth(true),
+ height: element.outerHeight(true),
+ 'float': element.css('float')
+ },
+ wrapper = $('<div></div>')
+ .addClass('ui-effects-wrapper')
+ .css({
+ fontSize: '100%',
+ background: 'transparent',
+ border: 'none',
+ margin: 0,
+ padding: 0
+ }),
+ active = document.activeElement;
+
+ element.wrap(wrapper);
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually loose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if (element.css('position') == 'static') {
+ wrapper.css({ position: 'relative' });
+ element.css({ position: 'relative' });
+ } else {
+ $.extend(props, {
+ position: element.css('position'),
+ zIndex: element.css('z-index')
+ });
+ $.each(['top', 'left', 'bottom', 'right'], function(i, pos) {
+ props[pos] = element.css(pos);
+ if (isNaN(parseInt(props[pos], 10))) {
+ props[pos] = 'auto';
+ }
+ });
+ element.css({position: 'relative', top: 0, left: 0, right: 'auto', bottom: 'auto' });
+ }
+
+ return wrapper.css(props).show();
+ },
+
+ removeWrapper: function(element) {
+ var parent,
+ active = document.activeElement;
+
+ if (element.parent().is('.ui-effects-wrapper')) {
+ parent = element.parent().replaceWith(element);
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ return parent;
+ }
+
+ return element;
+ },
+
+ setTransition: function(element, list, factor, value) {
+ value = value || {};
+ $.each(list, function(i, x){
+ unit = element.cssUnit(x);
+ if (unit[0] > 0) value[x] = unit[0] * factor + unit[1];
+ });
+ return value;
+ }
+});
+
+
+function _normalizeArguments(effect, options, speed, callback) {
+ // shift params for method overloading
+ if (typeof effect == 'object') {
+ callback = options;
+ speed = null;
+ options = effect;
+ effect = options.effect;
+ }
+ if ($.isFunction(options)) {
+ callback = options;
+ speed = null;
+ options = {};
+ }
+ if (typeof options == 'number' || $.fx.speeds[options]) {
+ callback = speed;
+ speed = options;
+ options = {};
+ }
+ if ($.isFunction(speed)) {
+ callback = speed;
+ speed = null;
+ }
+
+ options = options || {};
+
+ speed = speed || options.duration;
+ speed = $.fx.off ? 0 : typeof speed == 'number'
+ ? speed : speed in $.fx.speeds ? $.fx.speeds[speed] : $.fx.speeds._default;
+
+ callback = callback || options.complete;
+
+ return [effect, options, speed, callback];
+}
+
+function standardSpeed( speed ) {
+ // valid standard speeds
+ if ( !speed || typeof speed === "number" || $.fx.speeds[ speed ] ) {
+ return true;
+ }
+
+ // invalid strings - treat as "normal" speed
+ if ( typeof speed === "string" && !$.effects[ speed ] ) {
+ return true;
+ }
+
+ return false;
+}
+
+$.fn.extend({
+ effect: function(effect, options, speed, callback) {
+ var args = _normalizeArguments.apply(this, arguments),
+ // TODO: make effects take actual parameters instead of a hash
+ args2 = {
+ options: args[1],
+ duration: args[2],
+ callback: args[3]
+ },
+ mode = args2.options.mode,
+ effectMethod = $.effects[effect];
+
+ if ( $.fx.off || !effectMethod ) {
+ // delegate to the original method (e.g., .show()) if possible
+ if ( mode ) {
+ return this[ mode ]( args2.duration, args2.callback );
+ } else {
+ return this.each(function() {
+ if ( args2.callback ) {
+ args2.callback.call( this );
+ }
+ });
+ }
+ }
+
+ return effectMethod.call(this, args2);
+ },
+
+ _show: $.fn.show,
+ show: function(speed) {
+ if ( standardSpeed( speed ) ) {
+ return this._show.apply(this, arguments);
+ } else {
+ var args = _normalizeArguments.apply(this, arguments);
+ args[1].mode = 'show';
+ return this.effect.apply(this, args);
+ }
+ },
+
+ _hide: $.fn.hide,
+ hide: function(speed) {
+ if ( standardSpeed( speed ) ) {
+ return this._hide.apply(this, arguments);
+ } else {
+ var args = _normalizeArguments.apply(this, arguments);
+ args[1].mode = 'hide';
+ return this.effect.apply(this, args);
+ }
+ },
+
+ // jQuery core overloads toggle and creates _toggle
+ __toggle: $.fn.toggle,
+ toggle: function(speed) {
+ if ( standardSpeed( speed ) || typeof speed === "boolean" || $.isFunction( speed ) ) {
+ return this.__toggle.apply(this, arguments);
+ } else {
+ var args = _normalizeArguments.apply(this, arguments);
+ args[1].mode = 'toggle';
+ return this.effect.apply(this, args);
+ }
+ },
+
+ // helper functions
+ cssUnit: function(key) {
+ var style = this.css(key), val = [];
+ $.each( ['em','px','%','pt'], function(i, unit){
+ if(style.indexOf(unit) > 0)
+ val = [parseFloat(style), unit];
+ });
+ return val;
+ }
+});
+
+
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+$.easing.jswing = $.easing.swing;
+
+$.extend($.easing,
+{
+ def: 'easeOutQuad',
+ swing: function (x, t, b, c, d) {
+ //alert($.easing.default);
+ return $.easing[$.easing.def](x, t, b, c, d);
+ },
+ easeInQuad: function (x, t, b, c, d) {
+ return c*(t/=d)*t + b;
+ },
+ easeOutQuad: function (x, t, b, c, d) {
+ return -c *(t/=d)*(t-2) + b;
+ },
+ easeInOutQuad: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t + b;
+ return -c/2 * ((--t)*(t-2) - 1) + b;
+ },
+ easeInCubic: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t + b;
+ },
+ easeOutCubic: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t + 1) + b;
+ },
+ easeInOutCubic: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
+ return c/2*((t-=2)*t*t + 2) + b;
+ },
+ easeInQuart: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t + b;
+ },
+ easeOutQuart: function (x, t, b, c, d) {
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
+ },
+ easeInOutQuart: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
+ },
+ easeInQuint: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t*t + b;
+ },
+ easeOutQuint: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
+ },
+ easeInOutQuint: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
+ },
+ easeInSine: function (x, t, b, c, d) {
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
+ },
+ easeOutSine: function (x, t, b, c, d) {
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
+ },
+ easeInOutSine: function (x, t, b, c, d) {
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
+ },
+ easeInExpo: function (x, t, b, c, d) {
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
+ },
+ easeOutExpo: function (x, t, b, c, d) {
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+ },
+ easeInOutExpo: function (x, t, b, c, d) {
+ if (t==0) return b;
+ if (t==d) return b+c;
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
+ },
+ easeInCirc: function (x, t, b, c, d) {
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
+ },
+ easeOutCirc: function (x, t, b, c, d) {
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
+ },
+ easeInOutCirc: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
+ },
+ easeInElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ },
+ easeOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
+ },
+ easeInOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
+ },
+ easeInBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*(t/=d)*t*((s+1)*t - s) + b;
+ },
+ easeOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
+ },
+ easeInOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
+ },
+ easeInBounce: function (x, t, b, c, d) {
+ return c - $.easing.easeOutBounce (x, d-t, 0, c, d) + b;
+ },
+ easeOutBounce: function (x, t, b, c, d) {
+ if ((t/=d) < (1/2.75)) {
+ return c*(7.5625*t*t) + b;
+ } else if (t < (2/2.75)) {
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
+ } else if (t < (2.5/2.75)) {
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
+ } else {
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
+ }
+ },
+ easeInOutBounce: function (x, t, b, c, d) {
+ if (t < d/2) return $.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
+ return $.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
+ }
+});
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+})(jQuery);
+/*
+ * jQuery UI Effects Blind 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Blind
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.blind = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
+ var direction = o.options.direction || 'vertical'; // Default direction
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
+ var ref = (direction == 'vertical') ? 'height' : 'width';
+ var distance = (direction == 'vertical') ? wrapper.height() : wrapper.width();
+ if(mode == 'show') wrapper.css(ref, 0); // Shift
+
+ // Animation
+ var animation = {};
+ animation[ref] = mode == 'show' ? distance : 0;
+
+ // Animate
+ wrapper.animate(animation, o.duration, o.options.easing, function() {
+ if(mode == 'hide') el.hide(); // Hide
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(el[0], arguments); // Callback
+ el.dequeue();
+ });
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Bounce 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Bounce
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.bounce = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
+ var direction = o.options.direction || 'up'; // Default direction
+ var distance = o.options.distance || 20; // Default distance
+ var times = o.options.times || 5; // Default # of times
+ var speed = o.duration || 250; // Default speed per bounce
+ if (/show|hide/.test(mode)) props.push('opacity'); // Avoid touching opacity to prevent clearType and PNG issues in IE
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ $.effects.createWrapper(el); // Create Wrapper
+ var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
+ var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
+ var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 3 : el.outerWidth({margin:true}) / 3);
+ if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
+ if (mode == 'hide') distance = distance / (times * 2);
+ if (mode != 'hide') times--;
+
+ // Animate
+ if (mode == 'show') { // Show Bounce
+ var animation = {opacity: 1};
+ animation[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
+ el.animate(animation, speed / 2, o.options.easing);
+ distance = distance / 2;
+ times--;
+ };
+ for (var i = 0; i < times; i++) { // Bounces
+ var animation1 = {}, animation2 = {};
+ animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
+ animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
+ el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing);
+ distance = (mode == 'hide') ? distance * 2 : distance / 2;
+ };
+ if (mode == 'hide') { // Last Bounce
+ var animation = {opacity: 0};
+ animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
+ el.animate(animation, speed / 2, o.options.easing, function(){
+ el.hide(); // Hide
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(this, arguments); // Callback
+ });
+ } else {
+ var animation1 = {}, animation2 = {};
+ animation1[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
+ animation2[ref] = (motion == 'pos' ? '+=' : '-=') + distance;
+ el.animate(animation1, speed / 2, o.options.easing).animate(animation2, speed / 2, o.options.easing, function(){
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(this, arguments); // Callback
+ });
+ };
+ el.queue('fx', function() { el.dequeue(); });
+ el.dequeue();
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Clip 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Clip
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.clip = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right','height','width'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
+ var direction = o.options.direction || 'vertical'; // Default direction
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
+ var animate = el[0].tagName == 'IMG' ? wrapper : el;
+ var ref = {
+ size: (direction == 'vertical') ? 'height' : 'width',
+ position: (direction == 'vertical') ? 'top' : 'left'
+ };
+ var distance = (direction == 'vertical') ? animate.height() : animate.width();
+ if(mode == 'show') { animate.css(ref.size, 0); animate.css(ref.position, distance / 2); } // Shift
+
+ // Animation
+ var animation = {};
+ animation[ref.size] = mode == 'show' ? distance : 0;
+ animation[ref.position] = mode == 'show' ? 0 : distance / 2;
+
+ // Animate
+ animate.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
+ if(mode == 'hide') el.hide(); // Hide
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(el[0], arguments); // Callback
+ el.dequeue();
+ }});
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Drop 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Drop
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.drop = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right','opacity'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
+ var direction = o.options.direction || 'left'; // Default Direction
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ $.effects.createWrapper(el); // Create Wrapper
+ var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
+ var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
+ var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) / 2 : el.outerWidth({margin:true}) / 2);
+ if (mode == 'show') el.css('opacity', 0).css(ref, motion == 'pos' ? -distance : distance); // Shift
+
+ // Animation
+ var animation = {opacity: mode == 'show' ? 1 : 0};
+ animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;
+
+ // Animate
+ el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
+ if(mode == 'hide') el.hide(); // Hide
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(this, arguments); // Callback
+ el.dequeue();
+ }});
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Explode 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Explode
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.explode = function(o) {
+
+ return this.queue(function() {
+
+ var rows = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
+ var cells = o.options.pieces ? Math.round(Math.sqrt(o.options.pieces)) : 3;
+
+ o.options.mode = o.options.mode == 'toggle' ? ($(this).is(':visible') ? 'hide' : 'show') : o.options.mode;
+ var el = $(this).show().css('visibility', 'hidden');
+ var offset = el.offset();
+
+ //Substract the margins - not fixing the problem yet.
+ offset.top -= parseInt(el.css("marginTop"),10) || 0;
+ offset.left -= parseInt(el.css("marginLeft"),10) || 0;
+
+ var width = el.outerWidth(true);
+ var height = el.outerHeight(true);
+
+ for(var i=0;i<rows;i++) { // =
+ for(var j=0;j<cells;j++) { // ||
+ el
+ .clone()
+ .appendTo('body')
+ .wrap('<div></div>')
+ .css({
+ position: 'absolute',
+ visibility: 'visible',
+ left: -j*(width/cells),
+ top: -i*(height/rows)
+ })
+ .parent()
+ .addClass('ui-effects-explode')
+ .css({
+ position: 'absolute',
+ overflow: 'hidden',
+ width: width/cells,
+ height: height/rows,
+ left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? (j-Math.floor(cells/2))*(width/cells) : 0),
+ top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? (i-Math.floor(rows/2))*(height/rows) : 0),
+ opacity: o.options.mode == 'show' ? 0 : 1
+ }).animate({
+ left: offset.left + j*(width/cells) + (o.options.mode == 'show' ? 0 : (j-Math.floor(cells/2))*(width/cells)),
+ top: offset.top + i*(height/rows) + (o.options.mode == 'show' ? 0 : (i-Math.floor(rows/2))*(height/rows)),
+ opacity: o.options.mode == 'show' ? 1 : 0
+ }, o.duration || 500);
+ }
+ }
+
+ // Set a timeout, to call the callback approx. when the other animations have finished
+ setTimeout(function() {
+
+ o.options.mode == 'show' ? el.css({ visibility: 'visible' }) : el.css({ visibility: 'visible' }).hide();
+ if(o.callback) o.callback.apply(el[0]); // Callback
+ el.dequeue();
+
+ $('div.ui-effects-explode').remove();
+
+ }, o.duration || 500);
+
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Fade 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Fade
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.fade = function(o) {
+ return this.queue(function() {
+ var elem = $(this),
+ mode = $.effects.setMode(elem, o.options.mode || 'hide');
+
+ elem.animate({ opacity: mode }, {
+ queue: false,
+ duration: o.duration,
+ easing: o.options.easing,
+ complete: function() {
+ (o.callback && o.callback.apply(this, arguments));
+ elem.dequeue();
+ }
+ });
+ });
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Fold 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Fold
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.fold = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'hide'); // Set Mode
+ var size = o.options.size || 15; // Default fold size
+ var horizFirst = !(!o.options.horizFirst); // Ensure a boolean value
+ var duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2;
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ var wrapper = $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
+ var widthFirst = ((mode == 'show') != horizFirst);
+ var ref = widthFirst ? ['width', 'height'] : ['height', 'width'];
+ var distance = widthFirst ? [wrapper.width(), wrapper.height()] : [wrapper.height(), wrapper.width()];
+ var percent = /([0-9]+)%/.exec(size);
+ if(percent) size = parseInt(percent[1],10) / 100 * distance[mode == 'hide' ? 0 : 1];
+ if(mode == 'show') wrapper.css(horizFirst ? {height: 0, width: size} : {height: size, width: 0}); // Shift
+
+ // Animation
+ var animation1 = {}, animation2 = {};
+ animation1[ref[0]] = mode == 'show' ? distance[0] : size;
+ animation2[ref[1]] = mode == 'show' ? distance[1] : 0;
+
+ // Animate
+ wrapper.animate(animation1, duration, o.options.easing)
+ .animate(animation2, duration, o.options.easing, function() {
+ if(mode == 'hide') el.hide(); // Hide
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(el[0], arguments); // Callback
+ el.dequeue();
+ });
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Highlight 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Highlight
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.highlight = function(o) {
+ return this.queue(function() {
+ var elem = $(this),
+ props = ['backgroundImage', 'backgroundColor', 'opacity'],
+ mode = $.effects.setMode(elem, o.options.mode || 'show'),
+ animation = {
+ backgroundColor: elem.css('backgroundColor')
+ };
+
+ if (mode == 'hide') {
+ animation.opacity = 0;
+ }
+
+ $.effects.save(elem, props);
+ elem
+ .show()
+ .css({
+ backgroundImage: 'none',
+ backgroundColor: o.options.color || '#ffff99'
+ })
+ .animate(animation, {
+ queue: false,
+ duration: o.duration,
+ easing: o.options.easing,
+ complete: function() {
+ (mode == 'hide' && elem.hide());
+ $.effects.restore(elem, props);
+ (mode == 'show' && !$.support.opacity && this.style.removeAttribute('filter'));
+ (o.callback && o.callback.apply(this, arguments));
+ elem.dequeue();
+ }
+ });
+ });
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Pulsate 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Pulsate
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.pulsate = function(o) {
+ return this.queue(function() {
+ var elem = $(this),
+ mode = $.effects.setMode(elem, o.options.mode || 'show');
+ times = ((o.options.times || 5) * 2) - 1;
+ duration = o.duration ? o.duration / 2 : $.fx.speeds._default / 2,
+ isVisible = elem.is(':visible'),
+ animateTo = 0;
+
+ if (!isVisible) {
+ elem.css('opacity', 0).show();
+ animateTo = 1;
+ }
+
+ if ((mode == 'hide' && isVisible) || (mode == 'show' && !isVisible)) {
+ times--;
+ }
+
+ for (var i = 0; i < times; i++) {
+ elem.animate({ opacity: animateTo }, duration, o.options.easing);
+ animateTo = (animateTo + 1) % 2;
+ }
+
+ elem.animate({ opacity: animateTo }, duration, o.options.easing, function() {
+ if (animateTo == 0) {
+ elem.hide();
+ }
+ (o.callback && o.callback.apply(this, arguments));
+ });
+
+ elem
+ .queue('fx', function() { elem.dequeue(); })
+ .dequeue();
+ });
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Scale 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Scale
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.puff = function(o) {
+ return this.queue(function() {
+ var elem = $(this),
+ mode = $.effects.setMode(elem, o.options.mode || 'hide'),
+ percent = parseInt(o.options.percent, 10) || 150,
+ factor = percent / 100,
+ original = { height: elem.height(), width: elem.width() };
+
+ $.extend(o.options, {
+ fade: true,
+ mode: mode,
+ percent: mode == 'hide' ? percent : 100,
+ from: mode == 'hide'
+ ? original
+ : {
+ height: original.height * factor,
+ width: original.width * factor
+ }
+ });
+
+ elem.effect('scale', o.options, o.duration, o.callback);
+ elem.dequeue();
+ });
+};
+
+$.effects.scale = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this);
+
+ // Set options
+ var options = $.extend(true, {}, o.options);
+ var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
+ var percent = parseInt(o.options.percent,10) || (parseInt(o.options.percent,10) == 0 ? 0 : (mode == 'hide' ? 0 : 100)); // Set default scaling percent
+ var direction = o.options.direction || 'both'; // Set default axis
+ var origin = o.options.origin; // The origin of the scaling
+ if (mode != 'effect') { // Set default origin and restore for show/hide
+ options.origin = origin || ['middle','center'];
+ options.restore = true;
+ }
+ var original = {height: el.height(), width: el.width()}; // Save original
+ el.from = o.options.from || (mode == 'show' ? {height: 0, width: 0} : original); // Default from state
+
+ // Adjust
+ var factor = { // Set scaling factor
+ y: direction != 'horizontal' ? (percent / 100) : 1,
+ x: direction != 'vertical' ? (percent / 100) : 1
+ };
+ el.to = {height: original.height * factor.y, width: original.width * factor.x}; // Set to state
+
+ if (o.options.fade) { // Fade option to support puff
+ if (mode == 'show') {el.from.opacity = 0; el.to.opacity = 1;};
+ if (mode == 'hide') {el.from.opacity = 1; el.to.opacity = 0;};
+ };
+
+ // Animation
+ options.from = el.from; options.to = el.to; options.mode = mode;
+
+ // Animate
+ el.effect('size', options, o.duration, o.callback);
+ el.dequeue();
+ });
+
+};
+
+$.effects.size = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right','width','height','overflow','opacity'];
+ var props1 = ['position','top','bottom','left','right','overflow','opacity']; // Always restore
+ var props2 = ['width','height','overflow']; // Copy for children
+ var cProps = ['fontSize'];
+ var vProps = ['borderTopWidth', 'borderBottomWidth', 'paddingTop', 'paddingBottom'];
+ var hProps = ['borderLeftWidth', 'borderRightWidth', 'paddingLeft', 'paddingRight'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
+ var restore = o.options.restore || false; // Default restore
+ var scale = o.options.scale || 'both'; // Default scale mode
+ var origin = o.options.origin; // The origin of the sizing
+ var original = {height: el.height(), width: el.width()}; // Save original
+ el.from = o.options.from || original; // Default from state
+ el.to = o.options.to || original; // Default to state
+ // Adjust
+ if (origin) { // Calculate baseline shifts
+ var baseline = $.effects.getBaseline(origin, original);
+ el.from.top = (original.height - el.from.height) * baseline.y;
+ el.from.left = (original.width - el.from.width) * baseline.x;
+ el.to.top = (original.height - el.to.height) * baseline.y;
+ el.to.left = (original.width - el.to.width) * baseline.x;
+ };
+ var factor = { // Set scaling factor
+ from: {y: el.from.height / original.height, x: el.from.width / original.width},
+ to: {y: el.to.height / original.height, x: el.to.width / original.width}
+ };
+ if (scale == 'box' || scale == 'both') { // Scale the css box
+ if (factor.from.y != factor.to.y) { // Vertical props scaling
+ props = props.concat(vProps);
+ el.from = $.effects.setTransition(el, vProps, factor.from.y, el.from);
+ el.to = $.effects.setTransition(el, vProps, factor.to.y, el.to);
+ };
+ if (factor.from.x != factor.to.x) { // Horizontal props scaling
+ props = props.concat(hProps);
+ el.from = $.effects.setTransition(el, hProps, factor.from.x, el.from);
+ el.to = $.effects.setTransition(el, hProps, factor.to.x, el.to);
+ };
+ };
+ if (scale == 'content' || scale == 'both') { // Scale the content
+ if (factor.from.y != factor.to.y) { // Vertical props scaling
+ props = props.concat(cProps);
+ el.from = $.effects.setTransition(el, cProps, factor.from.y, el.from);
+ el.to = $.effects.setTransition(el, cProps, factor.to.y, el.to);
+ };
+ };
+ $.effects.save(el, restore ? props : props1); el.show(); // Save & Show
+ $.effects.createWrapper(el); // Create Wrapper
+ el.css('overflow','hidden').css(el.from); // Shift
+
+ // Animate
+ if (scale == 'content' || scale == 'both') { // Scale the children
+ vProps = vProps.concat(['marginTop','marginBottom']).concat(cProps); // Add margins/font-size
+ hProps = hProps.concat(['marginLeft','marginRight']); // Add margins
+ props2 = props.concat(vProps).concat(hProps); // Concat
+ el.find("*[width]").each(function(){
+ child = $(this);
+ if (restore) $.effects.save(child, props2);
+ var c_original = {height: child.height(), width: child.width()}; // Save original
+ child.from = {height: c_original.height * factor.from.y, width: c_original.width * factor.from.x};
+ child.to = {height: c_original.height * factor.to.y, width: c_original.width * factor.to.x};
+ if (factor.from.y != factor.to.y) { // Vertical props scaling
+ child.from = $.effects.setTransition(child, vProps, factor.from.y, child.from);
+ child.to = $.effects.setTransition(child, vProps, factor.to.y, child.to);
+ };
+ if (factor.from.x != factor.to.x) { // Horizontal props scaling
+ child.from = $.effects.setTransition(child, hProps, factor.from.x, child.from);
+ child.to = $.effects.setTransition(child, hProps, factor.to.x, child.to);
+ };
+ child.css(child.from); // Shift children
+ child.animate(child.to, o.duration, o.options.easing, function(){
+ if (restore) $.effects.restore(child, props2); // Restore children
+ }); // Animate children
+ });
+ };
+
+ // Animate
+ el.animate(el.to, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
+ if (el.to.opacity === 0) {
+ el.css('opacity', el.from.opacity);
+ }
+ if(mode == 'hide') el.hide(); // Hide
+ $.effects.restore(el, restore ? props : props1); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(this, arguments); // Callback
+ el.dequeue();
+ }});
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Shake 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Shake
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.shake = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'effect'); // Set Mode
+ var direction = o.options.direction || 'left'; // Default direction
+ var distance = o.options.distance || 20; // Default distance
+ var times = o.options.times || 3; // Default # of times
+ var speed = o.duration || o.options.duration || 140; // Default speed per shake
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ $.effects.createWrapper(el); // Create Wrapper
+ var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
+ var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
+
+ // Animation
+ var animation = {}, animation1 = {}, animation2 = {};
+ animation[ref] = (motion == 'pos' ? '-=' : '+=') + distance;
+ animation1[ref] = (motion == 'pos' ? '+=' : '-=') + distance * 2;
+ animation2[ref] = (motion == 'pos' ? '-=' : '+=') + distance * 2;
+
+ // Animate
+ el.animate(animation, speed, o.options.easing);
+ for (var i = 1; i < times; i++) { // Shakes
+ el.animate(animation1, speed, o.options.easing).animate(animation2, speed, o.options.easing);
+ };
+ el.animate(animation1, speed, o.options.easing).
+ animate(animation, speed / 2, o.options.easing, function(){ // Last shake
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(this, arguments); // Callback
+ });
+ el.queue('fx', function() { el.dequeue(); });
+ el.dequeue();
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Slide 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Slide
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.slide = function(o) {
+
+ return this.queue(function() {
+
+ // Create element
+ var el = $(this), props = ['position','top','bottom','left','right'];
+
+ // Set options
+ var mode = $.effects.setMode(el, o.options.mode || 'show'); // Set Mode
+ var direction = o.options.direction || 'left'; // Default Direction
+
+ // Adjust
+ $.effects.save(el, props); el.show(); // Save & Show
+ $.effects.createWrapper(el).css({overflow:'hidden'}); // Create Wrapper
+ var ref = (direction == 'up' || direction == 'down') ? 'top' : 'left';
+ var motion = (direction == 'up' || direction == 'left') ? 'pos' : 'neg';
+ var distance = o.options.distance || (ref == 'top' ? el.outerHeight({margin:true}) : el.outerWidth({margin:true}));
+ if (mode == 'show') el.css(ref, motion == 'pos' ? (isNaN(distance) ? "-" + distance : -distance) : distance); // Shift
+
+ // Animation
+ var animation = {};
+ animation[ref] = (mode == 'show' ? (motion == 'pos' ? '+=' : '-=') : (motion == 'pos' ? '-=' : '+=')) + distance;
+
+ // Animate
+ el.animate(animation, { queue: false, duration: o.duration, easing: o.options.easing, complete: function() {
+ if(mode == 'hide') el.hide(); // Hide
+ $.effects.restore(el, props); $.effects.removeWrapper(el); // Restore
+ if(o.callback) o.callback.apply(this, arguments); // Callback
+ el.dequeue();
+ }});
+
+ });
+
+};
+
+})(jQuery);
+/*
+ * jQuery UI Effects Transfer 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Effects/Transfer
+ *
+ * Depends:
+ * jquery.effects.core.js
+ */
+(function( $, undefined ) {
+
+$.effects.transfer = function(o) {
+ return this.queue(function() {
+ var elem = $(this),
+ target = $(o.options.to),
+ endPosition = target.offset(),
+ animation = {
+ top: endPosition.top,
+ left: endPosition.left,
+ height: target.innerHeight(),
+ width: target.innerWidth()
+ },
+ startPosition = elem.offset(),
+ transfer = $('<div class="ui-effects-transfer"></div>')
+ .appendTo(document.body)
+ .addClass(o.options.className)
+ .css({
+ top: startPosition.top,
+ left: startPosition.left,
+ height: elem.innerHeight(),
+ width: elem.innerWidth(),
+ position: 'absolute'
+ })
+ .animate(animation, o.duration, o.options.easing, function() {
+ transfer.remove();
+ (o.callback && o.callback.apply(elem[0], arguments));
+ elem.dequeue();
+ });
+ });
+};
+
+})(jQuery);
+/*
+ * jQuery UI Accordion 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Accordion
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget( "ui.accordion", {
+ options: {
+ active: 0,
+ animated: "slide",
+ autoHeight: true,
+ clearStyle: false,
+ collapsible: false,
+ event: "click",
+ fillSpace: false,
+ header: "> li > :first-child,> :not(li):even",
+ icons: {
+ header: "ui-icon-triangle-1-e",
+ headerSelected: "ui-icon-triangle-1-s"
+ },
+ navigation: false,
+ navigationFilter: function() {
+ return this.href.toLowerCase() === location.href.toLowerCase();
+ }
+ },
+
+ _create: function() {
+ var self = this,
+ options = self.options;
+
+ self.running = 0;
+
+ self.element
+ .addClass( "ui-accordion ui-widget ui-helper-reset" )
+ // in lack of child-selectors in CSS
+ // we need to mark top-LIs in a UL-accordion for some IE-fix
+ .children( "li" )
+ .addClass( "ui-accordion-li-fix" );
+
+ self.headers = self.element.find( options.header )
+ .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" )
+ .bind( "mouseenter.accordion", function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).addClass( "ui-state-hover" );
+ })
+ .bind( "mouseleave.accordion", function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( "ui-state-hover" );
+ })
+ .bind( "focus.accordion", function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).addClass( "ui-state-focus" );
+ })
+ .bind( "blur.accordion", function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( "ui-state-focus" );
+ });
+
+ self.headers.next()
+ .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" );
+
+ if ( options.navigation ) {
+ var current = self.element.find( "a" ).filter( options.navigationFilter ).eq( 0 );
+ if ( current.length ) {
+ var header = current.closest( ".ui-accordion-header" );
+ if ( header.length ) {
+ // anchor within header
+ self.active = header;
+ } else {
+ // anchor within content
+ self.active = current.closest( ".ui-accordion-content" ).prev();
+ }
+ }
+ }
+
+ self.active = self._findActive( self.active || options.active )
+ .addClass( "ui-state-default ui-state-active" )
+ .toggleClass( "ui-corner-all" )
+ .toggleClass( "ui-corner-top" );
+ self.active.next().addClass( "ui-accordion-content-active" );
+
+ self._createIcons();
+ self.resize();
+
+ // ARIA
+ self.element.attr( "role", "tablist" );
+
+ self.headers
+ .attr( "role", "tab" )
+ .bind( "keydown.accordion", function( event ) {
+ return self._keydown( event );
+ })
+ .next()
+ .attr( "role", "tabpanel" );
+
+ self.headers
+ .not( self.active || "" )
+ .attr({
+ "aria-expanded": "false",
+ "aria-selected": "false",
+ tabIndex: -1
+ })
+ .next()
+ .hide();
+
+ // make sure at least one header is in the tab order
+ if ( !self.active.length ) {
+ self.headers.eq( 0 ).attr( "tabIndex", 0 );
+ } else {
+ self.active
+ .attr({
+ "aria-expanded": "true",
+ "aria-selected": "true",
+ tabIndex: 0
+ });
+ }
+
+ // only need links in tab order for Safari
+ if ( !$.browser.safari ) {
+ self.headers.find( "a" ).attr( "tabIndex", -1 );
+ }
+
+ if ( options.event ) {
+ self.headers.bind( options.event.split(" ").join(".accordion ") + ".accordion", function(event) {
+ self._clickHandler.call( self, event, this );
+ event.preventDefault();
+ });
+ }
+ },
+
+ _createIcons: function() {
+ var options = this.options;
+ if ( options.icons ) {
+ $( "<span></span>" )
+ .addClass( "ui-icon " + options.icons.header )
+ .prependTo( this.headers );
+ this.active.children( ".ui-icon" )
+ .toggleClass(options.icons.header)
+ .toggleClass(options.icons.headerSelected);
+ this.element.addClass( "ui-accordion-icons" );
+ }
+ },
+
+ _destroyIcons: function() {
+ this.headers.children( ".ui-icon" ).remove();
+ this.element.removeClass( "ui-accordion-icons" );
+ },
+
+ destroy: function() {
+ var options = this.options;
+
+ this.element
+ .removeClass( "ui-accordion ui-widget ui-helper-reset" )
+ .removeAttr( "role" );
+
+ this.headers
+ .unbind( ".accordion" )
+ .removeClass( "ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-expanded" )
+ .removeAttr( "aria-selected" )
+ .removeAttr( "tabIndex" );
+
+ this.headers.find( "a" ).removeAttr( "tabIndex" );
+ this._destroyIcons();
+ var contents = this.headers.next()
+ .css( "display", "" )
+ .removeAttr( "role" )
+ .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled" );
+ if ( options.autoHeight || options.fillHeight ) {
+ contents.css( "height", "" );
+ }
+
+ return $.Widget.prototype.destroy.call( this );
+ },
+
+ _setOption: function( key, value ) {
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ if ( key == "active" ) {
+ this.activate( value );
+ }
+ if ( key == "icons" ) {
+ this._destroyIcons();
+ if ( value ) {
+ this._createIcons();
+ }
+ }
+ // #5332 - opacity doesn't cascade to positioned elements in IE
+ // so we need to add the disabled class to the headers and panels
+ if ( key == "disabled" ) {
+ this.headers.add(this.headers.next())
+ [ value ? "addClass" : "removeClass" ](
+ "ui-accordion-disabled ui-state-disabled" );
+ }
+ },
+
+ _keydown: function( event ) {
+ if ( this.options.disabled || event.altKey || event.ctrlKey ) {
+ return;
+ }
+
+ var keyCode = $.ui.keyCode,
+ length = this.headers.length,
+ currentIndex = this.headers.index( event.target ),
+ toFocus = false;
+
+ switch ( event.keyCode ) {
+ case keyCode.RIGHT:
+ case keyCode.DOWN:
+ toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+ break;
+ case keyCode.LEFT:
+ case keyCode.UP:
+ toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+ break;
+ case keyCode.SPACE:
+ case keyCode.ENTER:
+ this._clickHandler( { target: event.target }, event.target );
+ event.preventDefault();
+ }
+
+ if ( toFocus ) {
+ $( event.target ).attr( "tabIndex", -1 );
+ $( toFocus ).attr( "tabIndex", 0 );
+ toFocus.focus();
+ return false;
+ }
+
+ return true;
+ },
+
+ resize: function() {
+ var options = this.options,
+ maxHeight;
+
+ if ( options.fillSpace ) {
+ if ( $.browser.msie ) {
+ var defOverflow = this.element.parent().css( "overflow" );
+ this.element.parent().css( "overflow", "hidden");
+ }
+ maxHeight = this.element.parent().height();
+ if ($.browser.msie) {
+ this.element.parent().css( "overflow", defOverflow );
+ }
+
+ this.headers.each(function() {
+ maxHeight -= $( this ).outerHeight( true );
+ });
+
+ this.headers.next()
+ .each(function() {
+ $( this ).height( Math.max( 0, maxHeight -
+ $( this ).innerHeight() + $( this ).height() ) );
+ })
+ .css( "overflow", "auto" );
+ } else if ( options.autoHeight ) {
+ maxHeight = 0;
+ this.headers.next()
+ .each(function() {
+ maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+ })
+ .height( maxHeight );
+ }
+
+ return this;
+ },
+
+ activate: function( index ) {
+ // TODO this gets called on init, changing the option without an explicit call for that
+ this.options.active = index;
+ // call clickHandler with custom event
+ var active = this._findActive( index )[ 0 ];
+ this._clickHandler( { target: active }, active );
+
+ return this;
+ },
+
+ _findActive: function( selector ) {
+ return selector
+ ? typeof selector === "number"
+ ? this.headers.filter( ":eq(" + selector + ")" )
+ : this.headers.not( this.headers.not( selector ) )
+ : selector === false
+ ? $( [] )
+ : this.headers.filter( ":eq(0)" );
+ },
+
+ // TODO isn't event.target enough? why the separate target argument?
+ _clickHandler: function( event, target ) {
+ var options = this.options;
+ if ( options.disabled ) {
+ return;
+ }
+
+ // called only when using activate(false) to close all parts programmatically
+ if ( !event.target ) {
+ if ( !options.collapsible ) {
+ return;
+ }
+ this.active
+ .removeClass( "ui-state-active ui-corner-top" )
+ .addClass( "ui-state-default ui-corner-all" )
+ .children( ".ui-icon" )
+ .removeClass( options.icons.headerSelected )
+ .addClass( options.icons.header );
+ this.active.next().addClass( "ui-accordion-content-active" );
+ var toHide = this.active.next(),
+ data = {
+ options: options,
+ newHeader: $( [] ),
+ oldHeader: options.active,
+ newContent: $( [] ),
+ oldContent: toHide
+ },
+ toShow = ( this.active = $( [] ) );
+ this._toggle( toShow, toHide, data );
+ return;
+ }
+
+ // get the click target
+ var clicked = $( event.currentTarget || target ),
+ clickedIsActive = clicked[0] === this.active[0];
+
+ // TODO the option is changed, is that correct?
+ // TODO if it is correct, shouldn't that happen after determining that the click is valid?
+ options.active = options.collapsible && clickedIsActive ?
+ false :
+ this.headers.index( clicked );
+
+ // if animations are still active, or the active header is the target, ignore click
+ if ( this.running || ( !options.collapsible && clickedIsActive ) ) {
+ return;
+ }
+
+ // find elements to show and hide
+ var active = this.active,
+ toShow = clicked.next(),
+ toHide = this.active.next(),
+ data = {
+ options: options,
+ newHeader: clickedIsActive && options.collapsible ? $([]) : clicked,
+ oldHeader: this.active,
+ newContent: clickedIsActive && options.collapsible ? $([]) : toShow,
+ oldContent: toHide
+ },
+ down = this.headers.index( this.active[0] ) > this.headers.index( clicked[0] );
+
+ // when the call to ._toggle() comes after the class changes
+ // it causes a very odd bug in IE 8 (see #6720)
+ this.active = clickedIsActive ? $([]) : clicked;
+ this._toggle( toShow, toHide, data, clickedIsActive, down );
+
+ // switch classes
+ active
+ .removeClass( "ui-state-active ui-corner-top" )
+ .addClass( "ui-state-default ui-corner-all" )
+ .children( ".ui-icon" )
+ .removeClass( options.icons.headerSelected )
+ .addClass( options.icons.header );
+ if ( !clickedIsActive ) {
+ clicked
+ .removeClass( "ui-state-default ui-corner-all" )
+ .addClass( "ui-state-active ui-corner-top" )
+ .children( ".ui-icon" )
+ .removeClass( options.icons.header )
+ .addClass( options.icons.headerSelected );
+ clicked
+ .next()
+ .addClass( "ui-accordion-content-active" );
+ }
+
+ return;
+ },
+
+ _toggle: function( toShow, toHide, data, clickedIsActive, down ) {
+ var self = this,
+ options = self.options;
+
+ self.toShow = toShow;
+ self.toHide = toHide;
+ self.data = data;
+
+ var complete = function() {
+ if ( !self ) {
+ return;
+ }
+ return self._completed.apply( self, arguments );
+ };
+
+ // trigger changestart event
+ self._trigger( "changestart", null, self.data );
+
+ // count elements to animate
+ self.running = toHide.size() === 0 ? toShow.size() : toHide.size();
+
+ if ( options.animated ) {
+ var animOptions = {};
+
+ if ( options.collapsible && clickedIsActive ) {
+ animOptions = {
+ toShow: $( [] ),
+ toHide: toHide,
+ complete: complete,
+ down: down,
+ autoHeight: options.autoHeight || options.fillSpace
+ };
+ } else {
+ animOptions = {
+ toShow: toShow,
+ toHide: toHide,
+ complete: complete,
+ down: down,
+ autoHeight: options.autoHeight || options.fillSpace
+ };
+ }
+
+ if ( !options.proxied ) {
+ options.proxied = options.animated;
+ }
+
+ if ( !options.proxiedDuration ) {
+ options.proxiedDuration = options.duration;
+ }
+
+ options.animated = $.isFunction( options.proxied ) ?
+ options.proxied( animOptions ) :
+ options.proxied;
+
+ options.duration = $.isFunction( options.proxiedDuration ) ?
+ options.proxiedDuration( animOptions ) :
+ options.proxiedDuration;
+
+ var animations = $.ui.accordion.animations,
+ duration = options.duration,
+ easing = options.animated;
+
+ if ( easing && !animations[ easing ] && !$.easing[ easing ] ) {
+ easing = "slide";
+ }
+ if ( !animations[ easing ] ) {
+ animations[ easing ] = function( options ) {
+ this.slide( options, {
+ easing: easing,
+ duration: duration || 700
+ });
+ };
+ }
+
+ animations[ easing ]( animOptions );
+ } else {
+ if ( options.collapsible && clickedIsActive ) {
+ toShow.toggle();
+ } else {
+ toHide.hide();
+ toShow.show();
+ }
+
+ complete( true );
+ }
+
+ // TODO assert that the blur and focus triggers are really necessary, remove otherwise
+ toHide.prev()
+ .attr({
+ "aria-expanded": "false",
+ "aria-selected": "false",
+ tabIndex: -1
+ })
+ .blur();
+ toShow.prev()
+ .attr({
+ "aria-expanded": "true",
+ "aria-selected": "true",
+ tabIndex: 0
+ })
+ .focus();
+ },
+
+ _completed: function( cancel ) {
+ this.running = cancel ? 0 : --this.running;
+ if ( this.running ) {
+ return;
+ }
+
+ if ( this.options.clearStyle ) {
+ this.toShow.add( this.toHide ).css({
+ height: "",
+ overflow: ""
+ });
+ }
+
+ // other classes are removed before the animation; this one needs to stay until completed
+ this.toHide.removeClass( "ui-accordion-content-active" );
+ // Work around for rendering bug in IE (#5421)
+ if ( this.toHide.length ) {
+ this.toHide.parent()[0].className = this.toHide.parent()[0].className;
+ }
+
+ this._trigger( "change", null, this.data );
+ }
+});
+
+$.extend( $.ui.accordion, {
+ version: "1.8.18",
+ animations: {
+ slide: function( options, additions ) {
+ options = $.extend({
+ easing: "swing",
+ duration: 300
+ }, options, additions );
+ if ( !options.toHide.size() ) {
+ options.toShow.animate({
+ height: "show",
+ paddingTop: "show",
+ paddingBottom: "show"
+ }, options );
+ return;
+ }
+ if ( !options.toShow.size() ) {
+ options.toHide.animate({
+ height: "hide",
+ paddingTop: "hide",
+ paddingBottom: "hide"
+ }, options );
+ return;
+ }
+ var overflow = options.toShow.css( "overflow" ),
+ percentDone = 0,
+ showProps = {},
+ hideProps = {},
+ fxAttrs = [ "height", "paddingTop", "paddingBottom" ],
+ originalWidth;
+ // fix width before calculating height of hidden element
+ var s = options.toShow;
+ originalWidth = s[0].style.width;
+ s.width( s.parent().width()
+ - parseFloat( s.css( "paddingLeft" ) )
+ - parseFloat( s.css( "paddingRight" ) )
+ - ( parseFloat( s.css( "borderLeftWidth" ) ) || 0 )
+ - ( parseFloat( s.css( "borderRightWidth" ) ) || 0 ) );
+
+ $.each( fxAttrs, function( i, prop ) {
+ hideProps[ prop ] = "hide";
+
+ var parts = ( "" + $.css( options.toShow[0], prop ) ).match( /^([\d+-.]+)(.*)$/ );
+ showProps[ prop ] = {
+ value: parts[ 1 ],
+ unit: parts[ 2 ] || "px"
+ };
+ });
+ options.toShow.css({ height: 0, overflow: "hidden" }).show();
+ options.toHide
+ .filter( ":hidden" )
+ .each( options.complete )
+ .end()
+ .filter( ":visible" )
+ .animate( hideProps, {
+ step: function( now, settings ) {
+ // only calculate the percent when animating height
+ // IE gets very inconsistent results when animating elements
+ // with small values, which is common for padding
+ if ( settings.prop == "height" ) {
+ percentDone = ( settings.end - settings.start === 0 ) ? 0 :
+ ( settings.now - settings.start ) / ( settings.end - settings.start );
+ }
+
+ options.toShow[ 0 ].style[ settings.prop ] =
+ ( percentDone * showProps[ settings.prop ].value )
+ + showProps[ settings.prop ].unit;
+ },
+ duration: options.duration,
+ easing: options.easing,
+ complete: function() {
+ if ( !options.autoHeight ) {
+ options.toShow.css( "height", "" );
+ }
+ options.toShow.css({
+ width: originalWidth,
+ overflow: overflow
+ });
+ options.complete();
+ }
+ });
+ },
+ bounceslide: function( options ) {
+ this.slide( options, {
+ easing: options.down ? "easeOutBounce" : "swing",
+ duration: options.down ? 1000 : 200
+ });
+ }
+ }
+});
+
+})( jQuery );
+/*
+ * jQuery UI Autocomplete 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Autocomplete
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.position.js
+ */
+(function( $, undefined ) {
+
+// used to prevent race conditions with remote data sources
+var requestIndex = 0;
+
+$.widget( "ui.autocomplete", {
+ options: {
+ appendTo: "body",
+ autoFocus: false,
+ delay: 300,
+ minLength: 1,
+ position: {
+ my: "left top",
+ at: "left bottom",
+ collision: "none"
+ },
+ source: null
+ },
+
+ pending: 0,
+
+ _create: function() {
+ var self = this,
+ doc = this.element[ 0 ].ownerDocument,
+ suppressKeyPress;
+
+ this.element
+ .addClass( "ui-autocomplete-input" )
+ .attr( "autocomplete", "off" )
+ // TODO verify these actually work as intended
+ .attr({
+ role: "textbox",
+ "aria-autocomplete": "list",
+ "aria-haspopup": "true"
+ })
+ .bind( "keydown.autocomplete", function( event ) {
+ if ( self.options.disabled || self.element.propAttr( "readOnly" ) ) {
+ return;
+ }
+
+ suppressKeyPress = false;
+ var keyCode = $.ui.keyCode;
+ switch( event.keyCode ) {
+ case keyCode.PAGE_UP:
+ self._move( "previousPage", event );
+ break;
+ case keyCode.PAGE_DOWN:
+ self._move( "nextPage", event );
+ break;
+ case keyCode.UP:
+ self._move( "previous", event );
+ // prevent moving cursor to beginning of text field in some browsers
+ event.preventDefault();
+ break;
+ case keyCode.DOWN:
+ self._move( "next", event );
+ // prevent moving cursor to end of text field in some browsers
+ event.preventDefault();
+ break;
+ case keyCode.ENTER:
+ case keyCode.NUMPAD_ENTER:
+ // when menu is open and has focus
+ if ( self.menu.active ) {
+ // #6055 - Opera still allows the keypress to occur
+ // which causes forms to submit
+ suppressKeyPress = true;
+ event.preventDefault();
+ }
+ //passthrough - ENTER and TAB both select the current element
+ case keyCode.TAB:
+ if ( !self.menu.active ) {
+ return;
+ }
+ self.menu.select( event );
+ break;
+ case keyCode.ESCAPE:
+ self.element.val( self.term );
+ self.close( event );
+ break;
+ default:
+ // keypress is triggered before the input value is changed
+ clearTimeout( self.searching );
+ self.searching = setTimeout(function() {
+ // only search if the value has changed
+ if ( self.term != self.element.val() ) {
+ self.selectedItem = null;
+ self.search( null, event );
+ }
+ }, self.options.delay );
+ break;
+ }
+ })
+ .bind( "keypress.autocomplete", function( event ) {
+ if ( suppressKeyPress ) {
+ suppressKeyPress = false;
+ event.preventDefault();
+ }
+ })
+ .bind( "focus.autocomplete", function() {
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ self.selectedItem = null;
+ self.previous = self.element.val();
+ })
+ .bind( "blur.autocomplete", function( event ) {
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ clearTimeout( self.searching );
+ // clicks on the menu (or a button to trigger a search) will cause a blur event
+ self.closing = setTimeout(function() {
+ self.close( event );
+ self._change( event );
+ }, 150 );
+ });
+ this._initSource();
+ this.response = function() {
+ return self._response.apply( self, arguments );
+ };
+ this.menu = $( "<ul></ul>" )
+ .addClass( "ui-autocomplete" )
+ .appendTo( $( this.options.appendTo || "body", doc )[0] )
+ // prevent the close-on-blur in case of a "slow" click on the menu (long mousedown)
+ .mousedown(function( event ) {
+ // clicking on the scrollbar causes focus to shift to the body
+ // but we can't detect a mouseup or a click immediately afterward
+ // so we have to track the next mousedown and close the menu if
+ // the user clicks somewhere outside of the autocomplete
+ var menuElement = self.menu.element[ 0 ];
+ if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+ setTimeout(function() {
+ $( document ).one( 'mousedown', function( event ) {
+ if ( event.target !== self.element[ 0 ] &&
+ event.target !== menuElement &&
+ !$.ui.contains( menuElement, event.target ) ) {
+ self.close();
+ }
+ });
+ }, 1 );
+ }
+
+ // use another timeout to make sure the blur-event-handler on the input was already triggered
+ setTimeout(function() {
+ clearTimeout( self.closing );
+ }, 13);
+ })
+ .menu({
+ focus: function( event, ui ) {
+ var item = ui.item.data( "item.autocomplete" );
+ if ( false !== self._trigger( "focus", event, { item: item } ) ) {
+ // use value to match what will end up in the input, if it was a key event
+ if ( /^key/.test(event.originalEvent.type) ) {
+ self.element.val( item.value );
+ }
+ }
+ },
+ selected: function( event, ui ) {
+ var item = ui.item.data( "item.autocomplete" ),
+ previous = self.previous;
+
+ // only trigger when focus was lost (click on menu)
+ if ( self.element[0] !== doc.activeElement ) {
+ self.element.focus();
+ self.previous = previous;
+ // #6109 - IE triggers two focus events and the second
+ // is asynchronous, so we need to reset the previous
+ // term synchronously and asynchronously :-(
+ setTimeout(function() {
+ self.previous = previous;
+ self.selectedItem = item;
+ }, 1);
+ }
+
+ if ( false !== self._trigger( "select", event, { item: item } ) ) {
+ self.element.val( item.value );
+ }
+ // reset the term after the select event
+ // this allows custom select handling to work properly
+ self.term = self.element.val();
+
+ self.close( event );
+ self.selectedItem = item;
+ },
+ blur: function( event, ui ) {
+ // don't set the value of the text field if it's already correct
+ // this prevents moving the cursor unnecessarily
+ if ( self.menu.element.is(":visible") &&
+ ( self.element.val() !== self.term ) ) {
+ self.element.val( self.term );
+ }
+ }
+ })
+ .zIndex( this.element.zIndex() + 1 )
+ // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
+ .css({ top: 0, left: 0 })
+ .hide()
+ .data( "menu" );
+ if ( $.fn.bgiframe ) {
+ this.menu.element.bgiframe();
+ }
+ // turning off autocomplete prevents the browser from remembering the
+ // value when navigating through history, so we re-enable autocomplete
+ // if the page is unloaded before the widget is destroyed. #7790
+ self.beforeunloadHandler = function() {
+ self.element.removeAttr( "autocomplete" );
+ };
+ $( window ).bind( "beforeunload", self.beforeunloadHandler );
+ },
+
+ destroy: function() {
+ this.element
+ .removeClass( "ui-autocomplete-input" )
+ .removeAttr( "autocomplete" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-autocomplete" )
+ .removeAttr( "aria-haspopup" );
+ this.menu.element.remove();
+ $( window ).unbind( "beforeunload", this.beforeunloadHandler );
+ $.Widget.prototype.destroy.call( this );
+ },
+
+ _setOption: function( key, value ) {
+ $.Widget.prototype._setOption.apply( this, arguments );
+ if ( key === "source" ) {
+ this._initSource();
+ }
+ if ( key === "appendTo" ) {
+ this.menu.element.appendTo( $( value || "body", this.element[0].ownerDocument )[0] )
+ }
+ if ( key === "disabled" && value && this.xhr ) {
+ this.xhr.abort();
+ }
+ },
+
+ _initSource: function() {
+ var self = this,
+ array,
+ url;
+ if ( $.isArray(this.options.source) ) {
+ array = this.options.source;
+ this.source = function( request, response ) {
+ response( $.ui.autocomplete.filter(array, request.term) );
+ };
+ } else if ( typeof this.options.source === "string" ) {
+ url = this.options.source;
+ this.source = function( request, response ) {
+ if ( self.xhr ) {
+ self.xhr.abort();
+ }
+ self.xhr = $.ajax({
+ url: url,
+ data: request,
+ dataType: "json",
+ context: {
+ autocompleteRequest: ++requestIndex
+ },
+ success: function( data, status ) {
+ if ( this.autocompleteRequest === requestIndex ) {
+ response( data );
+ }
+ },
+ error: function() {
+ if ( this.autocompleteRequest === requestIndex ) {
+ response( [] );
+ }
+ }
+ });
+ };
+ } else {
+ this.source = this.options.source;
+ }
+ },
+
+ search: function( value, event ) {
+ value = value != null ? value : this.element.val();
+
+ // always save the actual value, not the one passed as an argument
+ this.term = this.element.val();
+
+ if ( value.length < this.options.minLength ) {
+ return this.close( event );
+ }
+
+ clearTimeout( this.closing );
+ if ( this._trigger( "search", event ) === false ) {
+ return;
+ }
+
+ return this._search( value );
+ },
+
+ _search: function( value ) {
+ this.pending++;
+ this.element.addClass( "ui-autocomplete-loading" );
+
+ this.source( { term: value }, this.response );
+ },
+
+ _response: function( content ) {
+ if ( !this.options.disabled && content && content.length ) {
+ content = this._normalize( content );
+ this._suggest( content );
+ this._trigger( "open" );
+ } else {
+ this.close();
+ }
+ this.pending--;
+ if ( !this.pending ) {
+ this.element.removeClass( "ui-autocomplete-loading" );
+ }
+ },
+
+ close: function( event ) {
+ clearTimeout( this.closing );
+ if ( this.menu.element.is(":visible") ) {
+ this.menu.element.hide();
+ this.menu.deactivate();
+ this._trigger( "close", event );
+ }
+ },
+
+ _change: function( event ) {
+ if ( this.previous !== this.element.val() ) {
+ this._trigger( "change", event, { item: this.selectedItem } );
+ }
+ },
+
+ _normalize: function( items ) {
+ // assume all items have the right format when the first item is complete
+ if ( items.length && items[0].label && items[0].value ) {
+ return items;
+ }
+ return $.map( items, function(item) {
+ if ( typeof item === "string" ) {
+ return {
+ label: item,
+ value: item
+ };
+ }
+ return $.extend({
+ label: item.label || item.value,
+ value: item.value || item.label
+ }, item );
+ });
+ },
+
+ _suggest: function( items ) {
+ var ul = this.menu.element
+ .empty()
+ .zIndex( this.element.zIndex() + 1 );
+ this._renderMenu( ul, items );
+ // TODO refresh should check if the active item is still in the dom, removing the need for a manual deactivate
+ this.menu.deactivate();
+ this.menu.refresh();
+
+ // size and position menu
+ ul.show();
+ this._resizeMenu();
+ ul.position( $.extend({
+ of: this.element
+ }, this.options.position ));
+
+ if ( this.options.autoFocus ) {
+ this.menu.next( new $.Event("mouseover") );
+ }
+ },
+
+ _resizeMenu: function() {
+ var ul = this.menu.element;
+ ul.outerWidth( Math.max(
+ // Firefox wraps long text (possibly a rounding bug)
+ // so we add 1px to avoid the wrapping (#7513)
+ ul.width( "" ).outerWidth() + 1,
+ this.element.outerWidth()
+ ) );
+ },
+
+ _renderMenu: function( ul, items ) {
+ var self = this;
+ $.each( items, function( index, item ) {
+ self._renderItem( ul, item );
+ });
+ },
+
+ _renderItem: function( ul, item) {
+ return $( "<li></li>" )
+ .data( "item.autocomplete", item )
+ .append( $( "<a></a>" ).text( item.label ) )
+ .appendTo( ul );
+ },
+
+ _move: function( direction, event ) {
+ if ( !this.menu.element.is(":visible") ) {
+ this.search( null, event );
+ return;
+ }
+ if ( this.menu.first() && /^previous/.test(direction) ||
+ this.menu.last() && /^next/.test(direction) ) {
+ this.element.val( this.term );
+ this.menu.deactivate();
+ return;
+ }
+ this.menu[ direction ]( event );
+ },
+
+ widget: function() {
+ return this.menu.element;
+ }
+});
+
+$.extend( $.ui.autocomplete, {
+ escapeRegex: function( value ) {
+ return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+ },
+ filter: function(array, term) {
+ var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" );
+ return $.grep( array, function(value) {
+ return matcher.test( value.label || value.value || value );
+ });
+ }
+});
+
+}( jQuery ));
+
+/*
+ * jQuery UI Menu (not officially released)
+ *
+ * This widget isn't yet finished and the API is subject to change. We plan to finish
+ * it for the next release. You're welcome to give it a try anyway and give us feedback,
+ * as long as you're okay with migrating your code later on. We can help with that, too.
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Menu
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function($) {
+
+$.widget("ui.menu", {
+ _create: function() {
+ var self = this;
+ this.element
+ .addClass("ui-menu ui-widget ui-widget-content ui-corner-all")
+ .attr({
+ role: "listbox",
+ "aria-activedescendant": "ui-active-menuitem"
+ })
+ .click(function( event ) {
+ if ( !$( event.target ).closest( ".ui-menu-item a" ).length ) {
+ return;
+ }
+ // temporary
+ event.preventDefault();
+ self.select( event );
+ });
+ this.refresh();
+ },
+
+ refresh: function() {
+ var self = this;
+
+ // don't refresh list items that are already adapted
+ var items = this.element.children("li:not(.ui-menu-item):has(a)")
+ .addClass("ui-menu-item")
+ .attr("role", "menuitem");
+
+ items.children("a")
+ .addClass("ui-corner-all")
+ .attr("tabindex", -1)
+ // mouseenter doesn't work with event delegation
+ .mouseenter(function( event ) {
+ self.activate( event, $(this).parent() );
+ })
+ .mouseleave(function() {
+ self.deactivate();
+ });
+ },
+
+ activate: function( event, item ) {
+ this.deactivate();
+ if (this.hasScroll()) {
+ var offset = item.offset().top - this.element.offset().top,
+ scroll = this.element.scrollTop(),
+ elementHeight = this.element.height();
+ if (offset < 0) {
+ this.element.scrollTop( scroll + offset);
+ } else if (offset >= elementHeight) {
+ this.element.scrollTop( scroll + offset - elementHeight + item.height());
+ }
+ }
+ this.active = item.eq(0)
+ .children("a")
+ .addClass("ui-state-hover")
+ .attr("id", "ui-active-menuitem")
+ .end();
+ this._trigger("focus", event, { item: item });
+ },
+
+ deactivate: function() {
+ if (!this.active) { return; }
+
+ this.active.children("a")
+ .removeClass("ui-state-hover")
+ .removeAttr("id");
+ this._trigger("blur");
+ this.active = null;
+ },
+
+ next: function(event) {
+ this.move("next", ".ui-menu-item:first", event);
+ },
+
+ previous: function(event) {
+ this.move("prev", ".ui-menu-item:last", event);
+ },
+
+ first: function() {
+ return this.active && !this.active.prevAll(".ui-menu-item").length;
+ },
+
+ last: function() {
+ return this.active && !this.active.nextAll(".ui-menu-item").length;
+ },
+
+ move: function(direction, edge, event) {
+ if (!this.active) {
+ this.activate(event, this.element.children(edge));
+ return;
+ }
+ var next = this.active[direction + "All"](".ui-menu-item").eq(0);
+ if (next.length) {
+ this.activate(event, next);
+ } else {
+ this.activate(event, this.element.children(edge));
+ }
+ },
+
+ // TODO merge with previousPage
+ nextPage: function(event) {
+ if (this.hasScroll()) {
+ // TODO merge with no-scroll-else
+ if (!this.active || this.last()) {
+ this.activate(event, this.element.children(".ui-menu-item:first"));
+ return;
+ }
+ var base = this.active.offset().top,
+ height = this.element.height(),
+ result = this.element.children(".ui-menu-item").filter(function() {
+ var close = $(this).offset().top - base - height + $(this).height();
+ // TODO improve approximation
+ return close < 10 && close > -10;
+ });
+
+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
+ if (!result.length) {
+ result = this.element.children(".ui-menu-item:last");
+ }
+ this.activate(event, result);
+ } else {
+ this.activate(event, this.element.children(".ui-menu-item")
+ .filter(!this.active || this.last() ? ":first" : ":last"));
+ }
+ },
+
+ // TODO merge with nextPage
+ previousPage: function(event) {
+ if (this.hasScroll()) {
+ // TODO merge with no-scroll-else
+ if (!this.active || this.first()) {
+ this.activate(event, this.element.children(".ui-menu-item:last"));
+ return;
+ }
+
+ var base = this.active.offset().top,
+ height = this.element.height();
+ result = this.element.children(".ui-menu-item").filter(function() {
+ var close = $(this).offset().top - base + height - $(this).height();
+ // TODO improve approximation
+ return close < 10 && close > -10;
+ });
+
+ // TODO try to catch this earlier when scrollTop indicates the last page anyway
+ if (!result.length) {
+ result = this.element.children(".ui-menu-item:first");
+ }
+ this.activate(event, result);
+ } else {
+ this.activate(event, this.element.children(".ui-menu-item")
+ .filter(!this.active || this.first() ? ":last" : ":first"));
+ }
+ },
+
+ hasScroll: function() {
+ return this.element.height() < this.element[ $.fn.prop ? "prop" : "attr" ]("scrollHeight");
+ },
+
+ select: function( event ) {
+ this._trigger("selected", event, { item: this.active });
+ }
+});
+
+}(jQuery));
+/*
+ * jQuery UI Button 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Button
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var lastActive, startXPos, startYPos, clickDragged,
+ baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+ stateClasses = "ui-state-hover ui-state-active ",
+ typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+ formResetHandler = function() {
+ var buttons = $( this ).find( ":ui-button" );
+ setTimeout(function() {
+ buttons.button( "refresh" );
+ }, 1 );
+ },
+ radioGroup = function( radio ) {
+ var name = radio.name,
+ form = radio.form,
+ radios = $( [] );
+ if ( name ) {
+ if ( form ) {
+ radios = $( form ).find( "[name='" + name + "']" );
+ } else {
+ radios = $( "[name='" + name + "']", radio.ownerDocument )
+ .filter(function() {
+ return !this.form;
+ });
+ }
+ }
+ return radios;
+ };
+
+$.widget( "ui.button", {
+ options: {
+ disabled: null,
+ text: true,
+ label: null,
+ icons: {
+ primary: null,
+ secondary: null
+ }
+ },
+ _create: function() {
+ this.element.closest( "form" )
+ .unbind( "reset.button" )
+ .bind( "reset.button", formResetHandler );
+
+ if ( typeof this.options.disabled !== "boolean" ) {
+ this.options.disabled = !!this.element.propAttr( "disabled" );
+ } else {
+ this.element.propAttr( "disabled", this.options.disabled );
+ }
+
+ this._determineButtonType();
+ this.hasTitle = !!this.buttonElement.attr( "title" );
+
+ var self = this,
+ options = this.options,
+ toggleButton = this.type === "checkbox" || this.type === "radio",
+ hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
+ focusClass = "ui-state-focus";
+
+ if ( options.label === null ) {
+ options.label = this.buttonElement.html();
+ }
+
+ this.buttonElement
+ .addClass( baseClasses )
+ .attr( "role", "button" )
+ .bind( "mouseenter.button", function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).addClass( "ui-state-hover" );
+ if ( this === lastActive ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ .bind( "mouseleave.button", function() {
+ if ( options.disabled ) {
+ return;
+ }
+ $( this ).removeClass( hoverClass );
+ })
+ .bind( "click.button", function( event ) {
+ if ( options.disabled ) {
+ event.preventDefault();
+ event.stopImmediatePropagation();
+ }
+ });
+
+ this.element
+ .bind( "focus.button", function() {
+ // no need to check disabled, focus won't be triggered anyway
+ self.buttonElement.addClass( focusClass );
+ })
+ .bind( "blur.button", function() {
+ self.buttonElement.removeClass( focusClass );
+ });
+
+ if ( toggleButton ) {
+ this.element.bind( "change.button", function() {
+ if ( clickDragged ) {
+ return;
+ }
+ self.refresh();
+ });
+ // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
+ // prevents issue where button state changes but checkbox/radio checked state
+ // does not in Firefox (see ticket #6970)
+ this.buttonElement
+ .bind( "mousedown.button", function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ clickDragged = false;
+ startXPos = event.pageX;
+ startYPos = event.pageY;
+ })
+ .bind( "mouseup.button", function( event ) {
+ if ( options.disabled ) {
+ return;
+ }
+ if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
+ clickDragged = true;
+ }
+ });
+ }
+
+ if ( this.type === "checkbox" ) {
+ this.buttonElement.bind( "click.button", function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ $( this ).toggleClass( "ui-state-active" );
+ self.buttonElement.attr( "aria-pressed", self.element[0].checked );
+ });
+ } else if ( this.type === "radio" ) {
+ this.buttonElement.bind( "click.button", function() {
+ if ( options.disabled || clickDragged ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ self.buttonElement.attr( "aria-pressed", "true" );
+
+ var radio = self.element[ 0 ];
+ radioGroup( radio )
+ .not( radio )
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ });
+ } else {
+ this.buttonElement
+ .bind( "mousedown.button", function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).addClass( "ui-state-active" );
+ lastActive = this;
+ $( document ).one( "mouseup", function() {
+ lastActive = null;
+ });
+ })
+ .bind( "mouseup.button", function() {
+ if ( options.disabled ) {
+ return false;
+ }
+ $( this ).removeClass( "ui-state-active" );
+ })
+ .bind( "keydown.button", function(event) {
+ if ( options.disabled ) {
+ return false;
+ }
+ if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
+ $( this ).addClass( "ui-state-active" );
+ }
+ })
+ .bind( "keyup.button", function() {
+ $( this ).removeClass( "ui-state-active" );
+ });
+
+ if ( this.buttonElement.is("a") ) {
+ this.buttonElement.keyup(function(event) {
+ if ( event.keyCode === $.ui.keyCode.SPACE ) {
+ // TODO pass through original event correctly (just as 2nd argument doesn't work)
+ $( this ).click();
+ }
+ });
+ }
+ }
+
+ // TODO: pull out $.Widget's handling for the disabled option into
+ // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
+ // be overridden by individual plugins
+ this._setOption( "disabled", options.disabled );
+ this._resetButton();
+ },
+
+ _determineButtonType: function() {
+
+ if ( this.element.is(":checkbox") ) {
+ this.type = "checkbox";
+ } else if ( this.element.is(":radio") ) {
+ this.type = "radio";
+ } else if ( this.element.is("input") ) {
+ this.type = "input";
+ } else {
+ this.type = "button";
+ }
+
+ if ( this.type === "checkbox" || this.type === "radio" ) {
+ // we don't search against the document in case the element
+ // is disconnected from the DOM
+ var ancestor = this.element.parents().filter(":last"),
+ labelSelector = "label[for='" + this.element.attr("id") + "']";
+ this.buttonElement = ancestor.find( labelSelector );
+ if ( !this.buttonElement.length ) {
+ ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+ this.buttonElement = ancestor.filter( labelSelector );
+ if ( !this.buttonElement.length ) {
+ this.buttonElement = ancestor.find( labelSelector );
+ }
+ }
+ this.element.addClass( "ui-helper-hidden-accessible" );
+
+ var checked = this.element.is( ":checked" );
+ if ( checked ) {
+ this.buttonElement.addClass( "ui-state-active" );
+ }
+ this.buttonElement.attr( "aria-pressed", checked );
+ } else {
+ this.buttonElement = this.element;
+ }
+ },
+
+ widget: function() {
+ return this.buttonElement;
+ },
+
+ destroy: function() {
+ this.element
+ .removeClass( "ui-helper-hidden-accessible" );
+ this.buttonElement
+ .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
+ .removeAttr( "role" )
+ .removeAttr( "aria-pressed" )
+ .html( this.buttonElement.find(".ui-button-text").html() );
+
+ if ( !this.hasTitle ) {
+ this.buttonElement.removeAttr( "title" );
+ }
+
+ $.Widget.prototype.destroy.call( this );
+ },
+
+ _setOption: function( key, value ) {
+ $.Widget.prototype._setOption.apply( this, arguments );
+ if ( key === "disabled" ) {
+ if ( value ) {
+ this.element.propAttr( "disabled", true );
+ } else {
+ this.element.propAttr( "disabled", false );
+ }
+ return;
+ }
+ this._resetButton();
+ },
+
+ refresh: function() {
+ var isDisabled = this.element.is( ":disabled" );
+ if ( isDisabled !== this.options.disabled ) {
+ this._setOption( "disabled", isDisabled );
+ }
+ if ( this.type === "radio" ) {
+ radioGroup( this.element[0] ).each(function() {
+ if ( $( this ).is( ":checked" ) ) {
+ $( this ).button( "widget" )
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ $( this ).button( "widget" )
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ });
+ } else if ( this.type === "checkbox" ) {
+ if ( this.element.is( ":checked" ) ) {
+ this.buttonElement
+ .addClass( "ui-state-active" )
+ .attr( "aria-pressed", "true" );
+ } else {
+ this.buttonElement
+ .removeClass( "ui-state-active" )
+ .attr( "aria-pressed", "false" );
+ }
+ }
+ },
+
+ _resetButton: function() {
+ if ( this.type === "input" ) {
+ if ( this.options.label ) {
+ this.element.val( this.options.label );
+ }
+ return;
+ }
+ var buttonElement = this.buttonElement.removeClass( typeClasses ),
+ buttonText = $( "<span></span>", this.element[0].ownerDocument )
+ .addClass( "ui-button-text" )
+ .html( this.options.label )
+ .appendTo( buttonElement.empty() )
+ .text(),
+ icons = this.options.icons,
+ multipleIcons = icons.primary && icons.secondary,
+ buttonClasses = [];
+
+ if ( icons.primary || icons.secondary ) {
+ if ( this.options.text ) {
+ buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+ }
+
+ if ( icons.primary ) {
+ buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+ }
+
+ if ( icons.secondary ) {
+ buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+ }
+
+ if ( !this.options.text ) {
+ buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+ if ( !this.hasTitle ) {
+ buttonElement.attr( "title", buttonText );
+ }
+ }
+ } else {
+ buttonClasses.push( "ui-button-text-only" );
+ }
+ buttonElement.addClass( buttonClasses.join( " " ) );
+ }
+});
+
+$.widget( "ui.buttonset", {
+ options: {
+ items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)"
+ },
+
+ _create: function() {
+ this.element.addClass( "ui-buttonset" );
+ },
+
+ _init: function() {
+ this.refresh();
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "disabled" ) {
+ this.buttons.button( "option", key, value );
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+ },
+
+ refresh: function() {
+ var rtl = this.element.css( "direction" ) === "rtl";
+
+ this.buttons = this.element.find( this.options.items )
+ .filter( ":ui-button" )
+ .button( "refresh" )
+ .end()
+ .not( ":ui-button" )
+ .button()
+ .end()
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+ .filter( ":first" )
+ .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+ .end()
+ .filter( ":last" )
+ .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+ .end()
+ .end();
+ },
+
+ destroy: function() {
+ this.element.removeClass( "ui-buttonset" );
+ this.buttons
+ .map(function() {
+ return $( this ).button( "widget" )[ 0 ];
+ })
+ .removeClass( "ui-corner-left ui-corner-right" )
+ .end()
+ .button( "destroy" );
+
+ $.Widget.prototype.destroy.call( this );
+ }
+});
+
+}( jQuery ) );
+/*
+ * jQuery UI Datepicker 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Datepicker
+ *
+ * Depends:
+ * jquery.ui.core.js
+ */
+(function( $, undefined ) {
+
+$.extend($.ui, { datepicker: { version: "1.8.18" } });
+
+var PROP_NAME = 'datepicker';
+var dpuuid = new Date().getTime();
+var instActive;
+
+/* Date picker manager.
+ Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+ Settings for (groups of) date pickers are maintained in an instance object,
+ allowing multiple different settings on the same page. */
+
+function Datepicker() {
+ this.debug = false; // Change this to true to start debugging
+ this._curInst = null; // The current instance in use
+ this._keyEvent = false; // If the last event was a key event
+ this._disabledInputs = []; // List of date picker inputs that have been disabled
+ this._datepickerShowing = false; // True if the popup picker is showing , false if not
+ this._inDialog = false; // True if showing within a "dialog", false if not
+ this._mainDivId = 'ui-datepicker-div'; // The ID of the main datepicker division
+ this._inlineClass = 'ui-datepicker-inline'; // The name of the inline marker class
+ this._appendClass = 'ui-datepicker-append'; // The name of the append marker class
+ this._triggerClass = 'ui-datepicker-trigger'; // The name of the trigger marker class
+ this._dialogClass = 'ui-datepicker-dialog'; // The name of the dialog marker class
+ this._disableClass = 'ui-datepicker-disabled'; // The name of the disabled covering marker class
+ this._unselectableClass = 'ui-datepicker-unselectable'; // The name of the unselectable cell marker class
+ this._currentClass = 'ui-datepicker-current-day'; // The name of the current day marker class
+ this._dayOverClass = 'ui-datepicker-days-cell-over'; // The name of the day hover marker class
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ closeText: 'Done', // Display text for close link
+ prevText: 'Prev', // Display text for previous month link
+ nextText: 'Next', // Display text for next month link
+ currentText: 'Today', // Display text for current month link
+ monthNames: ['January','February','March','April','May','June',
+ 'July','August','September','October','November','December'], // Names of months for drop-down and formatting
+ monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], // For formatting
+ dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], // For formatting
+ dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], // For formatting
+ dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], // Column headings for days starting at Sunday
+ weekHeader: 'Wk', // Column header for week of the year
+ dateFormat: 'mm/dd/yy', // See format options on parseDate
+ firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+ isRTL: false, // True if right-to-left language, false if left-to-right
+ showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+ yearSuffix: '' // Additional text to append to the year in the month headers
+ };
+ this._defaults = { // Global defaults for all the date picker instances
+ showOn: 'focus', // 'focus' for popup on focus,
+ // 'button' for trigger button, or 'both' for either
+ showAnim: 'fadeIn', // Name of jQuery animation for popup
+ showOptions: {}, // Options for enhanced animations
+ defaultDate: null, // Used when field is blank: actual date,
+ // +/-number for offset from today, null for today
+ appendText: '', // Display text following the input box, e.g. showing the format
+ buttonText: '...', // Text for trigger button
+ buttonImage: '', // URL for trigger button image
+ buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+ hideIfNoPrevNext: false, // True to hide next/previous month links
+ // if not applicable, false to just disable them
+ navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+ gotoCurrent: false, // True if today link goes back to current selection instead
+ changeMonth: false, // True if month can be selected directly, false if only prev/next
+ changeYear: false, // True if year can be selected directly, false if only prev/next
+ yearRange: 'c-10:c+10', // Range of years to display in drop-down,
+ // either relative to today's year (-nn:+nn), relative to currently displayed year
+ // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+ showOtherMonths: false, // True to show dates in other months, false to leave blank
+ selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+ showWeek: false, // True to show week of the year, false to not show it
+ calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+ // takes a Date and returns the number of the week for it
+ shortYearCutoff: '+10', // Short year values < this are in the current century,
+ // > this are in the previous century,
+ // string value starting with '+' for current year + value
+ minDate: null, // The earliest selectable date, or null for no limit
+ maxDate: null, // The latest selectable date, or null for no limit
+ duration: 'fast', // Duration of display/closure
+ beforeShowDay: null, // Function that takes a date and returns an array with
+ // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or '',
+ // [2] = cell title (optional), e.g. $.datepicker.noWeekends
+ beforeShow: null, // Function that takes an input field and
+ // returns a set of custom settings for the date picker
+ onSelect: null, // Define a callback function when a date is selected
+ onChangeMonthYear: null, // Define a callback function when the month or year is changed
+ onClose: null, // Define a callback function when the datepicker is closed
+ numberOfMonths: 1, // Number of months to show at a time
+ showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+ stepMonths: 1, // Number of months to step back/forward
+ stepBigMonths: 12, // Number of months to step back/forward for the big links
+ altField: '', // Selector for an alternate field to store selected dates into
+ altFormat: '', // The date format to use for the alternate field
+ constrainInput: true, // The input is constrained by the current date format
+ showButtonPanel: false, // True to show button panel, false to not show it
+ autoSize: false, // True to size the input for the date format, false to leave as is
+ disabled: false // The initial disabled state
+ };
+ $.extend(this._defaults, this.regional['']);
+ this.dpDiv = bindHover($('<div id="' + this._mainDivId + '" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'));
+}
+
+$.extend(Datepicker.prototype, {
+ /* Class name added to elements to indicate already configured with a date picker. */
+ markerClassName: 'hasDatepicker',
+
+ //Keep track of the maximum number of rows displayed (see #7043)
+ maxRows: 4,
+
+ /* Debug logging (if enabled). */
+ log: function () {
+ if (this.debug)
+ console.log.apply('', arguments);
+ },
+
+ // TODO rename to "widget" when switching to widget factory
+ _widgetDatepicker: function() {
+ return this.dpDiv;
+ },
+
+ /* Override the default settings for all instances of the date picker.
+ @param settings object - the new settings to use as defaults (anonymous object)
+ @return the manager object */
+ setDefaults: function(settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /* Attach the date picker to a jQuery selection.
+ @param target element - the target input field or division or span
+ @param settings object - the new settings to use for this date picker instance (anonymous) */
+ _attachDatepicker: function(target, settings) {
+ // check for settings on the control itself - in namespace 'date:'
+ var inlineSettings = null;
+ for (var attrName in this._defaults) {
+ var attrValue = target.getAttribute('date:' + attrName);
+ if (attrValue) {
+ inlineSettings = inlineSettings || {};
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ var nodeName = target.nodeName.toLowerCase();
+ var inline = (nodeName == 'div' || nodeName == 'span');
+ if (!target.id) {
+ this.uuid += 1;
+ target.id = 'dp' + this.uuid;
+ }
+ var inst = this._newInst($(target), inline);
+ inst.settings = $.extend({}, settings || {}, inlineSettings || {});
+ if (nodeName == 'input') {
+ this._connectDatepicker(target, inst);
+ } else if (inline) {
+ this._inlineDatepicker(target, inst);
+ }
+ },
+
+ /* Create a new instance object. */
+ _newInst: function(target, inline) {
+ var id = target[0].id.replace(/([^A-Za-z0-9_-])/g, '\\\\$1'); // escape jQuery meta chars
+ return {id: id, input: target, // associated target
+ selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+ drawMonth: 0, drawYear: 0, // month being drawn
+ inline: inline, // is datepicker inline or not
+ dpDiv: (!inline ? this.dpDiv : // presentation div
+ bindHover($('<div class="' + this._inlineClass + ' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')))};
+ },
+
+ /* Attach the date picker to an input field. */
+ _connectDatepicker: function(target, inst) {
+ var input = $(target);
+ inst.append = $([]);
+ inst.trigger = $([]);
+ if (input.hasClass(this.markerClassName))
+ return;
+ this._attachments(input, inst);
+ input.addClass(this.markerClassName).keydown(this._doKeyDown).
+ keypress(this._doKeyPress).keyup(this._doKeyUp).
+ bind("setData.datepicker", function(event, key, value) {
+ inst.settings[key] = value;
+ }).bind("getData.datepicker", function(event, key) {
+ return this._get(inst, key);
+ });
+ this._autoSize(inst);
+ $.data(target, PROP_NAME, inst);
+ //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ },
+
+ /* Make attachments based on settings. */
+ _attachments: function(input, inst) {
+ var appendText = this._get(inst, 'appendText');
+ var isRTL = this._get(inst, 'isRTL');
+ if (inst.append)
+ inst.append.remove();
+ if (appendText) {
+ inst.append = $('<span class="' + this._appendClass + '">' + appendText + '</span>');
+ input[isRTL ? 'before' : 'after'](inst.append);
+ }
+ input.unbind('focus', this._showDatepicker);
+ if (inst.trigger)
+ inst.trigger.remove();
+ var showOn = this._get(inst, 'showOn');
+ if (showOn == 'focus' || showOn == 'both') // pop-up date picker when in the marked field
+ input.focus(this._showDatepicker);
+ if (showOn == 'button' || showOn == 'both') { // pop-up date picker when button clicked
+ var buttonText = this._get(inst, 'buttonText');
+ var buttonImage = this._get(inst, 'buttonImage');
+ inst.trigger = $(this._get(inst, 'buttonImageOnly') ?
+ $('<img/>').addClass(this._triggerClass).
+ attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+ $('<button type="button"></button>').addClass(this._triggerClass).
+ html(buttonImage == '' ? buttonText : $('<img/>').attr(
+ { src:buttonImage, alt:buttonText, title:buttonText })));
+ input[isRTL ? 'before' : 'after'](inst.trigger);
+ inst.trigger.click(function() {
+ if ($.datepicker._datepickerShowing && $.datepicker._lastInput == input[0])
+ $.datepicker._hideDatepicker();
+ else if ($.datepicker._datepickerShowing && $.datepicker._lastInput != input[0]) {
+ $.datepicker._hideDatepicker();
+ $.datepicker._showDatepicker(input[0]);
+ } else
+ $.datepicker._showDatepicker(input[0]);
+ return false;
+ });
+ }
+ },
+
+ /* Apply the maximum length for the date format. */
+ _autoSize: function(inst) {
+ if (this._get(inst, 'autoSize') && !inst.inline) {
+ var date = new Date(2009, 12 - 1, 20); // Ensure double digits
+ var dateFormat = this._get(inst, 'dateFormat');
+ if (dateFormat.match(/[DM]/)) {
+ var findMax = function(names) {
+ var max = 0;
+ var maxI = 0;
+ for (var i = 0; i < names.length; i++) {
+ if (names[i].length > max) {
+ max = names[i].length;
+ maxI = i;
+ }
+ }
+ return maxI;
+ };
+ date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+ 'monthNames' : 'monthNamesShort'))));
+ date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+ 'dayNames' : 'dayNamesShort'))) + 20 - date.getDay());
+ }
+ inst.input.attr('size', this._formatDate(inst, date).length);
+ }
+ },
+
+ /* Attach an inline date picker to a div. */
+ _inlineDatepicker: function(target, inst) {
+ var divSpan = $(target);
+ if (divSpan.hasClass(this.markerClassName))
+ return;
+ divSpan.addClass(this.markerClassName).append(inst.dpDiv).
+ bind("setData.datepicker", function(event, key, value){
+ inst.settings[key] = value;
+ }).bind("getData.datepicker", function(event, key){
+ return this._get(inst, key);
+ });
+ $.data(target, PROP_NAME, inst);
+ this._setDate(inst, this._getDefaultDate(inst), true);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+ if( inst.settings.disabled ) {
+ this._disableDatepicker( target );
+ }
+ // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+ // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+ inst.dpDiv.css( "display", "block" );
+ },
+
+ /* Pop-up the date picker in a "dialog" box.
+ @param input element - ignored
+ @param date string or Date - the initial date to display
+ @param onSelect function - the function to call when a date is selected
+ @param settings object - update the dialog date picker instance's settings (anonymous object)
+ @param pos int[2] - coordinates for the dialog's position within the screen or
+ event - with x/y coordinates or
+ leave empty for default (screen centre)
+ @return the manager object */
+ _dialogDatepicker: function(input, date, onSelect, settings, pos) {
+ var inst = this._dialogInst; // internal instance
+ if (!inst) {
+ this.uuid += 1;
+ var id = 'dp' + this.uuid;
+ this._dialogInput = $('<input type="text" id="' + id +
+ '" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');
+ this._dialogInput.keydown(this._doKeyDown);
+ $('body').append(this._dialogInput);
+ inst = this._dialogInst = this._newInst(this._dialogInput, false);
+ inst.settings = {};
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ }
+ extendRemove(inst.settings, settings || {});
+ date = (date && date.constructor == Date ? this._formatDate(inst, date) : date);
+ this._dialogInput.val(date);
+
+ this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+ if (!this._pos) {
+ var browserWidth = document.documentElement.clientWidth;
+ var browserHeight = document.documentElement.clientHeight;
+ var scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+ var scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+ this._pos = // should use actual width/height below
+ [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+ }
+
+ // move input on screen for focus, but hidden behind dialog
+ this._dialogInput.css('left', (this._pos[0] + 20) + 'px').css('top', this._pos[1] + 'px');
+ inst.settings.onSelect = onSelect;
+ this._inDialog = true;
+ this.dpDiv.addClass(this._dialogClass);
+ this._showDatepicker(this._dialogInput[0]);
+ if ($.blockUI)
+ $.blockUI(this.dpDiv);
+ $.data(this._dialogInput[0], PROP_NAME, inst);
+ return this;
+ },
+
+ /* Detach a datepicker from its control.
+ @param target element - the target input field or division or span */
+ _destroyDatepicker: function(target) {
+ var $target = $(target);
+ var inst = $.data(target, PROP_NAME);
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+ var nodeName = target.nodeName.toLowerCase();
+ $.removeData(target, PROP_NAME);
+ if (nodeName == 'input') {
+ inst.append.remove();
+ inst.trigger.remove();
+ $target.removeClass(this.markerClassName).
+ unbind('focus', this._showDatepicker).
+ unbind('keydown', this._doKeyDown).
+ unbind('keypress', this._doKeyPress).
+ unbind('keyup', this._doKeyUp);
+ } else if (nodeName == 'div' || nodeName == 'span')
+ $target.removeClass(this.markerClassName).empty();
+ },
+
+ /* Enable the date picker to a jQuery selection.
+ @param target element - the target input field or division or span */
+ _enableDatepicker: function(target) {
+ var $target = $(target);
+ var inst = $.data(target, PROP_NAME);
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+ var nodeName = target.nodeName.toLowerCase();
+ if (nodeName == 'input') {
+ target.disabled = false;
+ inst.trigger.filter('button').
+ each(function() { this.disabled = false; }).end().
+ filter('img').css({opacity: '1.0', cursor: ''});
+ }
+ else if (nodeName == 'div' || nodeName == 'span') {
+ var inline = $target.children('.' + this._inlineClass);
+ inline.children().removeClass('ui-state-disabled');
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ removeAttr("disabled");
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value == target ? null : value); }); // delete entry
+ },
+
+ /* Disable the date picker to a jQuery selection.
+ @param target element - the target input field or division or span */
+ _disableDatepicker: function(target) {
+ var $target = $(target);
+ var inst = $.data(target, PROP_NAME);
+ if (!$target.hasClass(this.markerClassName)) {
+ return;
+ }
+ var nodeName = target.nodeName.toLowerCase();
+ if (nodeName == 'input') {
+ target.disabled = true;
+ inst.trigger.filter('button').
+ each(function() { this.disabled = true; }).end().
+ filter('img').css({opacity: '0.5', cursor: 'default'});
+ }
+ else if (nodeName == 'div' || nodeName == 'span') {
+ var inline = $target.children('.' + this._inlineClass);
+ inline.children().addClass('ui-state-disabled');
+ inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+ attr("disabled", "disabled");
+ }
+ this._disabledInputs = $.map(this._disabledInputs,
+ function(value) { return (value == target ? null : value); }); // delete entry
+ this._disabledInputs[this._disabledInputs.length] = target;
+ },
+
+ /* Is the first field in a jQuery collection disabled as a datepicker?
+ @param target element - the target input field or division or span
+ @return boolean - true if disabled, false if enabled */
+ _isDisabledDatepicker: function(target) {
+ if (!target) {
+ return false;
+ }
+ for (var i = 0; i < this._disabledInputs.length; i++) {
+ if (this._disabledInputs[i] == target)
+ return true;
+ }
+ return false;
+ },
+
+ /* Retrieve the instance data for the target control.
+ @param target element - the target input field or division or span
+ @return object - the associated instance data
+ @throws error if a jQuery problem getting data */
+ _getInst: function(target) {
+ try {
+ return $.data(target, PROP_NAME);
+ }
+ catch (err) {
+ throw 'Missing instance data for this datepicker';
+ }
+ },
+
+ /* Update or retrieve the settings for a date picker attached to an input field or division.
+ @param target element - the target input field or division or span
+ @param name object - the new settings to update or
+ string - the name of the setting to change or retrieve,
+ when retrieving also 'all' for all instance settings or
+ 'defaults' for all global defaults
+ @param value any - the new value for the setting
+ (omit if above is an object or to retrieve a value) */
+ _optionDatepicker: function(target, name, value) {
+ var inst = this._getInst(target);
+ if (arguments.length == 2 && typeof name == 'string') {
+ return (name == 'defaults' ? $.extend({}, $.datepicker._defaults) :
+ (inst ? (name == 'all' ? $.extend({}, inst.settings) :
+ this._get(inst, name)) : null));
+ }
+ var settings = name || {};
+ if (typeof name == 'string') {
+ settings = {};
+ settings[name] = value;
+ }
+ if (inst) {
+ if (this._curInst == inst) {
+ this._hideDatepicker();
+ }
+ var date = this._getDateDatepicker(target, true);
+ var minDate = this._getMinMaxDate(inst, 'min');
+ var maxDate = this._getMinMaxDate(inst, 'max');
+ extendRemove(inst.settings, settings);
+ // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+ if (minDate !== null && settings['dateFormat'] !== undefined && settings['minDate'] === undefined)
+ inst.settings.minDate = this._formatDate(inst, minDate);
+ if (maxDate !== null && settings['dateFormat'] !== undefined && settings['maxDate'] === undefined)
+ inst.settings.maxDate = this._formatDate(inst, maxDate);
+ this._attachments($(target), inst);
+ this._autoSize(inst);
+ this._setDate(inst, date);
+ this._updateAlternate(inst);
+ this._updateDatepicker(inst);
+ }
+ },
+
+ // change method deprecated
+ _changeDatepicker: function(target, name, value) {
+ this._optionDatepicker(target, name, value);
+ },
+
+ /* Redraw the date picker attached to an input field or division.
+ @param target element - the target input field or division or span */
+ _refreshDatepicker: function(target) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._updateDatepicker(inst);
+ }
+ },
+
+ /* Set the dates for a jQuery selection.
+ @param target element - the target input field or division or span
+ @param date Date - the new date */
+ _setDateDatepicker: function(target, date) {
+ var inst = this._getInst(target);
+ if (inst) {
+ this._setDate(inst, date);
+ this._updateDatepicker(inst);
+ this._updateAlternate(inst);
+ }
+ },
+
+ /* Get the date(s) for the first entry in a jQuery selection.
+ @param target element - the target input field or division or span
+ @param noDefault boolean - true if no default date is to be used
+ @return Date - the current date */
+ _getDateDatepicker: function(target, noDefault) {
+ var inst = this._getInst(target);
+ if (inst && !inst.inline)
+ this._setDateFromField(inst, noDefault);
+ return (inst ? this._getDate(inst) : null);
+ },
+
+ /* Handle keystrokes. */
+ _doKeyDown: function(event) {
+ var inst = $.datepicker._getInst(event.target);
+ var handled = true;
+ var isRTL = inst.dpDiv.is('.ui-datepicker-rtl');
+ inst._keyEvent = true;
+ if ($.datepicker._datepickerShowing)
+ switch (event.keyCode) {
+ case 9: $.datepicker._hideDatepicker();
+ handled = false;
+ break; // hide on tab out
+ case 13: var sel = $('td.' + $.datepicker._dayOverClass + ':not(.' +
+ $.datepicker._currentClass + ')', inst.dpDiv);
+ if (sel[0])
+ $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+ var onSelect = $.datepicker._get(inst, 'onSelect');
+ if (onSelect) {
+ var dateStr = $.datepicker._formatDate(inst);
+
+ // trigger custom callback
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+ }
+ else
+ $.datepicker._hideDatepicker();
+ return false; // don't submit the form
+ break; // select the value on enter
+ case 27: $.datepicker._hideDatepicker();
+ break; // hide on escape
+ case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, 'stepBigMonths') :
+ -$.datepicker._get(inst, 'stepMonths')), 'M');
+ break; // previous month/year on page up/+ ctrl
+ case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, 'stepBigMonths') :
+ +$.datepicker._get(inst, 'stepMonths')), 'M');
+ break; // next month/year on page down/+ ctrl
+ case 35: if (event.ctrlKey || event.metaKey) $.datepicker._clearDate(event.target);
+ handled = event.ctrlKey || event.metaKey;
+ break; // clear on ctrl or command +end
+ case 36: if (event.ctrlKey || event.metaKey) $.datepicker._gotoToday(event.target);
+ handled = event.ctrlKey || event.metaKey;
+ break; // current on ctrl or command +home
+ case 37: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), 'D');
+ handled = event.ctrlKey || event.metaKey;
+ // -1 day on ctrl or command +left
+ if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ -$.datepicker._get(inst, 'stepBigMonths') :
+ -$.datepicker._get(inst, 'stepMonths')), 'M');
+ // next month/year on alt +left on Mac
+ break;
+ case 38: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, -7, 'D');
+ handled = event.ctrlKey || event.metaKey;
+ break; // -1 week on ctrl or command +up
+ case 39: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), 'D');
+ handled = event.ctrlKey || event.metaKey;
+ // +1 day on ctrl or command +right
+ if (event.originalEvent.altKey) $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+ +$.datepicker._get(inst, 'stepBigMonths') :
+ +$.datepicker._get(inst, 'stepMonths')), 'M');
+ // next month/year on alt +right
+ break;
+ case 40: if (event.ctrlKey || event.metaKey) $.datepicker._adjustDate(event.target, +7, 'D');
+ handled = event.ctrlKey || event.metaKey;
+ break; // +1 week on ctrl or command +down
+ default: handled = false;
+ }
+ else if (event.keyCode == 36 && event.ctrlKey) // display the date picker on ctrl+home
+ $.datepicker._showDatepicker(this);
+ else {
+ handled = false;
+ }
+ if (handled) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+ },
+
+ /* Filter entered characters - based on date format. */
+ _doKeyPress: function(event) {
+ var inst = $.datepicker._getInst(event.target);
+ if ($.datepicker._get(inst, 'constrainInput')) {
+ var chars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat'));
+ var chr = String.fromCharCode(event.charCode == undefined ? event.keyCode : event.charCode);
+ return event.ctrlKey || event.metaKey || (chr < ' ' || !chars || chars.indexOf(chr) > -1);
+ }
+ },
+
+ /* Synchronise manual entry and field/alternate field. */
+ _doKeyUp: function(event) {
+ var inst = $.datepicker._getInst(event.target);
+ if (inst.input.val() != inst.lastVal) {
+ try {
+ var date = $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
+ (inst.input ? inst.input.val() : null),
+ $.datepicker._getFormatConfig(inst));
+ if (date) { // only if valid
+ $.datepicker._setDateFromField(inst);
+ $.datepicker._updateAlternate(inst);
+ $.datepicker._updateDatepicker(inst);
+ }
+ }
+ catch (event) {
+ $.datepicker.log(event);
+ }
+ }
+ return true;
+ },
+
+ /* Pop-up the date picker for a given input field.
+ If false returned from beforeShow event handler do not show.
+ @param input element - the input field attached to the date picker or
+ event - if triggered by focus */
+ _showDatepicker: function(input) {
+ input = input.target || input;
+ if (input.nodeName.toLowerCase() != 'input') // find from button/image trigger
+ input = $('input', input.parentNode)[0];
+ if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput == input) // already here
+ return;
+ var inst = $.datepicker._getInst(input);
+ if ($.datepicker._curInst && $.datepicker._curInst != inst) {
+ $.datepicker._curInst.dpDiv.stop(true, true);
+ if ( inst && $.datepicker._datepickerShowing ) {
+ $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+ }
+ }
+ var beforeShow = $.datepicker._get(inst, 'beforeShow');
+ var beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+ if(beforeShowSettings === false){
+ //false
+ return;
+ }
+ extendRemove(inst.settings, beforeShowSettings);
+ inst.lastVal = null;
+ $.datepicker._lastInput = input;
+ $.datepicker._setDateFromField(inst);
+ if ($.datepicker._inDialog) // hide cursor
+ input.value = '';
+ if (!$.datepicker._pos) { // position below input
+ $.datepicker._pos = $.datepicker._findPos(input);
+ $.datepicker._pos[1] += input.offsetHeight; // add the height
+ }
+ var isFixed = false;
+ $(input).parents().each(function() {
+ isFixed |= $(this).css('position') == 'fixed';
+ return !isFixed;
+ });
+ if (isFixed && $.browser.opera) { // correction for Opera when fixed and scrolled
+ $.datepicker._pos[0] -= document.documentElement.scrollLeft;
+ $.datepicker._pos[1] -= document.documentElement.scrollTop;
+ }
+ var offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+ $.datepicker._pos = null;
+ //to avoid flashes on Firefox
+ inst.dpDiv.empty();
+ // determine sizing offscreen
+ inst.dpDiv.css({position: 'absolute', display: 'block', top: '-1000px'});
+ $.datepicker._updateDatepicker(inst);
+ // fix width for dynamic number of date pickers
+ // and adjust position before showing
+ offset = $.datepicker._checkOffset(inst, offset, isFixed);
+ inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+ 'static' : (isFixed ? 'fixed' : 'absolute')), display: 'none',
+ left: offset.left + 'px', top: offset.top + 'px'});
+ if (!inst.inline) {
+ var showAnim = $.datepicker._get(inst, 'showAnim');
+ var duration = $.datepicker._get(inst, 'duration');
+ var postProcess = function() {
+ var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
+ if( !! cover.length ){
+ var borders = $.datepicker._getBorders(inst.dpDiv);
+ cover.css({left: -borders[0], top: -borders[1],
+ width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()});
+ }
+ };
+ inst.dpDiv.zIndex($(input).zIndex()+1);
+ $.datepicker._datepickerShowing = true;
+ if ($.effects && $.effects[showAnim])
+ inst.dpDiv.show(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
+ else
+ inst.dpDiv[showAnim || 'show']((showAnim ? duration : null), postProcess);
+ if (!showAnim || !duration)
+ postProcess();
+ if (inst.input.is(':visible') && !inst.input.is(':disabled'))
+ inst.input.focus();
+ $.datepicker._curInst = inst;
+ }
+ },
+
+ /* Generate the date picker content. */
+ _updateDatepicker: function(inst) {
+ var self = this;
+ self.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+ var borders = $.datepicker._getBorders(inst.dpDiv);
+ instActive = inst; // for delegate hover events
+ inst.dpDiv.empty().append(this._generateHTML(inst));
+ var cover = inst.dpDiv.find('iframe.ui-datepicker-cover'); // IE6- only
+ if( !!cover.length ){ //avoid call to outerXXXX() when not in IE6
+ cover.css({left: -borders[0], top: -borders[1], width: inst.dpDiv.outerWidth(), height: inst.dpDiv.outerHeight()})
+ }
+ inst.dpDiv.find('.' + this._dayOverClass + ' a').mouseover();
+ var numMonths = this._getNumberOfMonths(inst);
+ var cols = numMonths[1];
+ var width = 17;
+ inst.dpDiv.removeClass('ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4').width('');
+ if (cols > 1)
+ inst.dpDiv.addClass('ui-datepicker-multi-' + cols).css('width', (width * cols) + 'em');
+ inst.dpDiv[(numMonths[0] != 1 || numMonths[1] != 1 ? 'add' : 'remove') +
+ 'Class']('ui-datepicker-multi');
+ inst.dpDiv[(this._get(inst, 'isRTL') ? 'add' : 'remove') +
+ 'Class']('ui-datepicker-rtl');
+ if (inst == $.datepicker._curInst && $.datepicker._datepickerShowing && inst.input &&
+ // #6694 - don't focus the input if it's already focused
+ // this breaks the change event in IE
+ inst.input.is(':visible') && !inst.input.is(':disabled') && inst.input[0] != document.activeElement)
+ inst.input.focus();
+ // deffered render of the years select (to avoid flashes on Firefox)
+ if( inst.yearshtml ){
+ var origyearshtml = inst.yearshtml;
+ setTimeout(function(){
+ //assure that inst.yearshtml didn't change.
+ if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+ inst.dpDiv.find('select.ui-datepicker-year:first').replaceWith(inst.yearshtml);
+ }
+ origyearshtml = inst.yearshtml = null;
+ }, 0);
+ }
+ },
+
+ /* Retrieve the size of left and top borders for an element.
+ @param elem (jQuery object) the element of interest
+ @return (number[2]) the left and top borders */
+ _getBorders: function(elem) {
+ var convert = function(value) {
+ return {thin: 1, medium: 2, thick: 3}[value] || value;
+ };
+ return [parseFloat(convert(elem.css('border-left-width'))),
+ parseFloat(convert(elem.css('border-top-width')))];
+ },
+
+ /* Check positioning to remain on screen. */
+ _checkOffset: function(inst, offset, isFixed) {
+ var dpWidth = inst.dpDiv.outerWidth();
+ var dpHeight = inst.dpDiv.outerHeight();
+ var inputWidth = inst.input ? inst.input.outerWidth() : 0;
+ var inputHeight = inst.input ? inst.input.outerHeight() : 0;
+ var viewWidth = document.documentElement.clientWidth + $(document).scrollLeft();
+ var viewHeight = document.documentElement.clientHeight + $(document).scrollTop();
+
+ offset.left -= (this._get(inst, 'isRTL') ? (dpWidth - inputWidth) : 0);
+ offset.left -= (isFixed && offset.left == inst.input.offset().left) ? $(document).scrollLeft() : 0;
+ offset.top -= (isFixed && offset.top == (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+ // now check if datepicker is showing outside window viewport - move to a better place if so.
+ offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+ Math.abs(offset.left + dpWidth - viewWidth) : 0);
+ offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+ Math.abs(dpHeight + inputHeight) : 0);
+
+ return offset;
+ },
+
+ /* Find an object's position on the screen. */
+ _findPos: function(obj) {
+ var inst = this._getInst(obj);
+ var isRTL = this._get(inst, 'isRTL');
+ while (obj && (obj.type == 'hidden' || obj.nodeType != 1 || $.expr.filters.hidden(obj))) {
+ obj = obj[isRTL ? 'previousSibling' : 'nextSibling'];
+ }
+ var position = $(obj).offset();
+ return [position.left, position.top];
+ },
+
+ /* Hide the date picker from view.
+ @param input element - the input field attached to the date picker */
+ _hideDatepicker: function(input) {
+ var inst = this._curInst;
+ if (!inst || (input && inst != $.data(input, PROP_NAME)))
+ return;
+ if (this._datepickerShowing) {
+ var showAnim = this._get(inst, 'showAnim');
+ var duration = this._get(inst, 'duration');
+ var self = this;
+ var postProcess = function() {
+ $.datepicker._tidyDialog(inst);
+ self._curInst = null;
+ };
+ if ($.effects && $.effects[showAnim])
+ inst.dpDiv.hide(showAnim, $.datepicker._get(inst, 'showOptions'), duration, postProcess);
+ else
+ inst.dpDiv[(showAnim == 'slideDown' ? 'slideUp' :
+ (showAnim == 'fadeIn' ? 'fadeOut' : 'hide'))]((showAnim ? duration : null), postProcess);
+ if (!showAnim)
+ postProcess();
+ this._datepickerShowing = false;
+ var onClose = this._get(inst, 'onClose');
+ if (onClose)
+ onClose.apply((inst.input ? inst.input[0] : null),
+ [(inst.input ? inst.input.val() : ''), inst]);
+ this._lastInput = null;
+ if (this._inDialog) {
+ this._dialogInput.css({ position: 'absolute', left: '0', top: '-100px' });
+ if ($.blockUI) {
+ $.unblockUI();
+ $('body').append(this.dpDiv);
+ }
+ }
+ this._inDialog = false;
+ }
+ },
+
+ /* Tidy up after a dialog display. */
+ _tidyDialog: function(inst) {
+ inst.dpDiv.removeClass(this._dialogClass).unbind('.ui-datepicker-calendar');
+ },
+
+ /* Close date picker if clicked elsewhere. */
+ _checkExternalClick: function(event) {
+ if (!$.datepicker._curInst)
+ return;
+
+ var $target = $(event.target),
+ inst = $.datepicker._getInst($target[0]);
+
+ if ( ( ( $target[0].id != $.datepicker._mainDivId &&
+ $target.parents('#' + $.datepicker._mainDivId).length == 0 &&
+ !$target.hasClass($.datepicker.markerClassName) &&
+ !$target.closest("." + $.datepicker._triggerClass).length &&
+ $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+ ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst != inst ) )
+ $.datepicker._hideDatepicker();
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustDate: function(id, offset, period) {
+ var target = $(id);
+ var inst = this._getInst(target[0]);
+ if (this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+ this._adjustInstDate(inst, offset +
+ (period == 'M' ? this._get(inst, 'showCurrentAtPos') : 0), // undo positioning
+ period);
+ this._updateDatepicker(inst);
+ },
+
+ /* Action for current link. */
+ _gotoToday: function(id) {
+ var target = $(id);
+ var inst = this._getInst(target[0]);
+ if (this._get(inst, 'gotoCurrent') && inst.currentDay) {
+ inst.selectedDay = inst.currentDay;
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+ inst.drawYear = inst.selectedYear = inst.currentYear;
+ }
+ else {
+ var date = new Date();
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ }
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a new month/year. */
+ _selectMonthYear: function(id, select, period) {
+ var target = $(id);
+ var inst = this._getInst(target[0]);
+ inst['selected' + (period == 'M' ? 'Month' : 'Year')] =
+ inst['draw' + (period == 'M' ? 'Month' : 'Year')] =
+ parseInt(select.options[select.selectedIndex].value,10);
+ this._notifyChange(inst);
+ this._adjustDate(target);
+ },
+
+ /* Action for selecting a day. */
+ _selectDay: function(id, month, year, td) {
+ var target = $(id);
+ if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+ return;
+ }
+ var inst = this._getInst(target[0]);
+ inst.selectedDay = inst.currentDay = $('a', td).html();
+ inst.selectedMonth = inst.currentMonth = month;
+ inst.selectedYear = inst.currentYear = year;
+ this._selectDate(id, this._formatDate(inst,
+ inst.currentDay, inst.currentMonth, inst.currentYear));
+ },
+
+ /* Erase the input field and hide the date picker. */
+ _clearDate: function(id) {
+ var target = $(id);
+ var inst = this._getInst(target[0]);
+ this._selectDate(target, '');
+ },
+
+ /* Update the input field with the selected date. */
+ _selectDate: function(id, dateStr) {
+ var target = $(id);
+ var inst = this._getInst(target[0]);
+ dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+ if (inst.input)
+ inst.input.val(dateStr);
+ this._updateAlternate(inst);
+ var onSelect = this._get(inst, 'onSelect');
+ if (onSelect)
+ onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
+ else if (inst.input)
+ inst.input.trigger('change'); // fire the change event
+ if (inst.inline)
+ this._updateDatepicker(inst);
+ else {
+ this._hideDatepicker();
+ this._lastInput = inst.input[0];
+ if (typeof(inst.input[0]) != 'object')
+ inst.input.focus(); // restore focus
+ this._lastInput = null;
+ }
+ },
+
+ /* Update any alternate field to synchronise with the main field. */
+ _updateAlternate: function(inst) {
+ var altField = this._get(inst, 'altField');
+ if (altField) { // update alternate field too
+ var altFormat = this._get(inst, 'altFormat') || this._get(inst, 'dateFormat');
+ var date = this._getDate(inst);
+ var dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+ $(altField).each(function() { $(this).val(dateStr); });
+ }
+ },
+
+ /* Set as beforeShowDay function to prevent selection of weekends.
+ @param date Date - the date to customise
+ @return [boolean, string] - is this date selectable?, what is its CSS class? */
+ noWeekends: function(date) {
+ var day = date.getDay();
+ return [(day > 0 && day < 6), ''];
+ },
+
+ /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+ @param date Date - the date to get the week for
+ @return number - the number of the week within the year that contains this date */
+ iso8601Week: function(date) {
+ var checkDate = new Date(date.getTime());
+ // Find Thursday of this week starting on Monday
+ checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+ var time = checkDate.getTime();
+ checkDate.setMonth(0); // Compare with Jan 1
+ checkDate.setDate(1);
+ return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+ },
+
+ /* Parse a string value into a date object.
+ See formatDate below for the possible formats.
+
+ @param format string - the expected format of the date
+ @param value string - the date in the above format
+ @param settings Object - attributes include:
+ shortYearCutoff number - the cutoff year for determining the century (optional)
+ dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ dayNames string[7] - names of the days from Sunday (optional)
+ monthNamesShort string[12] - abbreviated names of the months (optional)
+ monthNames string[12] - names of the months (optional)
+ @return Date - the extracted date value or null if value is blank */
+ parseDate: function (format, value, settings) {
+ if (format == null || value == null)
+ throw 'Invalid arguments';
+ value = (typeof value == 'object' ? value.toString() : value + '');
+ if (value == '')
+ return null;
+ var shortYearCutoff = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff;
+ shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+ var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
+ var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
+ var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
+ var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
+ var year = -1;
+ var month = -1;
+ var day = -1;
+ var doy = -1;
+ var literal = false;
+ // Check whether a format character is doubled
+ var lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
+ if (matches)
+ iFormat++;
+ return matches;
+ };
+ // Extract a number from the string value
+ var getNumber = function(match) {
+ var isDoubled = lookAhead(match);
+ var size = (match == '@' ? 14 : (match == '!' ? 20 :
+ (match == 'y' && isDoubled ? 4 : (match == 'o' ? 3 : 2))));
+ var digits = new RegExp('^\\d{1,' + size + '}');
+ var num = value.substring(iValue).match(digits);
+ if (!num)
+ throw 'Missing number at position ' + iValue;
+ iValue += num[0].length;
+ return parseInt(num[0], 10);
+ };
+ // Extract a name from the string value and convert to an index
+ var getName = function(match, shortNames, longNames) {
+ var names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+ return [ [k, v] ];
+ }).sort(function (a, b) {
+ return -(a[1].length - b[1].length);
+ });
+ var index = -1;
+ $.each(names, function (i, pair) {
+ var name = pair[1];
+ if (value.substr(iValue, name.length).toLowerCase() == name.toLowerCase()) {
+ index = pair[0];
+ iValue += name.length;
+ return false;
+ }
+ });
+ if (index != -1)
+ return index + 1;
+ else
+ throw 'Unknown name at position ' + iValue;
+ };
+ // Confirm that a literal character matches the string value
+ var checkLiteral = function() {
+ if (value.charAt(iValue) != format.charAt(iFormat))
+ throw 'Unexpected literal at position ' + iValue;
+ iValue++;
+ };
+ var iValue = 0;
+ for (var iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal)
+ if (format.charAt(iFormat) == "'" && !lookAhead("'"))
+ literal = false;
+ else
+ checkLiteral();
+ else
+ switch (format.charAt(iFormat)) {
+ case 'd':
+ day = getNumber('d');
+ break;
+ case 'D':
+ getName('D', dayNamesShort, dayNames);
+ break;
+ case 'o':
+ doy = getNumber('o');
+ break;
+ case 'm':
+ month = getNumber('m');
+ break;
+ case 'M':
+ month = getName('M', monthNamesShort, monthNames);
+ break;
+ case 'y':
+ year = getNumber('y');
+ break;
+ case '@':
+ var date = new Date(getNumber('@'));
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case '!':
+ var date = new Date((getNumber('!') - this._ticksTo1970) / 10000);
+ year = date.getFullYear();
+ month = date.getMonth() + 1;
+ day = date.getDate();
+ break;
+ case "'":
+ if (lookAhead("'"))
+ checkLiteral();
+ else
+ literal = true;
+ break;
+ default:
+ checkLiteral();
+ }
+ }
+ if (iValue < value.length){
+ throw "Extra/unparsed characters found in date: " + value.substring(iValue);
+ }
+ if (year == -1)
+ year = new Date().getFullYear();
+ else if (year < 100)
+ year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+ (year <= shortYearCutoff ? 0 : -100);
+ if (doy > -1) {
+ month = 1;
+ day = doy;
+ do {
+ var dim = this._getDaysInMonth(year, month - 1);
+ if (day <= dim)
+ break;
+ month++;
+ day -= dim;
+ } while (true);
+ }
+ var date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+ if (date.getFullYear() != year || date.getMonth() + 1 != month || date.getDate() != day)
+ throw 'Invalid date'; // E.g. 31/02/00
+ return date;
+ },
+
+ /* Standard date formats. */
+ ATOM: 'yy-mm-dd', // RFC 3339 (ISO 8601)
+ COOKIE: 'D, dd M yy',
+ ISO_8601: 'yy-mm-dd',
+ RFC_822: 'D, d M y',
+ RFC_850: 'DD, dd-M-y',
+ RFC_1036: 'D, d M y',
+ RFC_1123: 'D, d M yy',
+ RFC_2822: 'D, d M yy',
+ RSS: 'D, d M y', // RFC 822
+ TICKS: '!',
+ TIMESTAMP: '@',
+ W3C: 'yy-mm-dd', // ISO 8601
+
+ _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+ Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+ /* Format a date object into a string value.
+ The format can be combinations of the following:
+ d - day of month (no leading zero)
+ dd - day of month (two digit)
+ o - day of year (no leading zeros)
+ oo - day of year (three digit)
+ D - day name short
+ DD - day name long
+ m - month of year (no leading zero)
+ mm - month of year (two digit)
+ M - month name short
+ MM - month name long
+ y - year (two digit)
+ yy - year (four digit)
+ @ - Unix timestamp (ms since 01/01/1970)
+ ! - Windows ticks (100ns since 01/01/0001)
+ '...' - literal text
+ '' - single quote
+
+ @param format string - the desired format of the date
+ @param date Date - the date value to format
+ @param settings Object - attributes include:
+ dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
+ dayNames string[7] - names of the days from Sunday (optional)
+ monthNamesShort string[12] - abbreviated names of the months (optional)
+ monthNames string[12] - names of the months (optional)
+ @return string - the date in the above format */
+ formatDate: function (format, date, settings) {
+ if (!date)
+ return '';
+ var dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort;
+ var dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames;
+ var monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort;
+ var monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames;
+ // Check whether a format character is doubled
+ var lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
+ if (matches)
+ iFormat++;
+ return matches;
+ };
+ // Format a number, with leading zero if necessary
+ var formatNumber = function(match, value, len) {
+ var num = '' + value;
+ if (lookAhead(match))
+ while (num.length < len)
+ num = '0' + num;
+ return num;
+ };
+ // Format a name, short or long as requested
+ var formatName = function(match, value, shortNames, longNames) {
+ return (lookAhead(match) ? longNames[value] : shortNames[value]);
+ };
+ var output = '';
+ var literal = false;
+ if (date)
+ for (var iFormat = 0; iFormat < format.length; iFormat++) {
+ if (literal)
+ if (format.charAt(iFormat) == "'" && !lookAhead("'"))
+ literal = false;
+ else
+ output += format.charAt(iFormat);
+ else
+ switch (format.charAt(iFormat)) {
+ case 'd':
+ output += formatNumber('d', date.getDate(), 2);
+ break;
+ case 'D':
+ output += formatName('D', date.getDay(), dayNamesShort, dayNames);
+ break;
+ case 'o':
+ output += formatNumber('o',
+ Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+ break;
+ case 'm':
+ output += formatNumber('m', date.getMonth() + 1, 2);
+ break;
+ case 'M':
+ output += formatName('M', date.getMonth(), monthNamesShort, monthNames);
+ break;
+ case 'y':
+ output += (lookAhead('y') ? date.getFullYear() :
+ (date.getYear() % 100 < 10 ? '0' : '') + date.getYear() % 100);
+ break;
+ case '@':
+ output += date.getTime();
+ break;
+ case '!':
+ output += date.getTime() * 10000 + this._ticksTo1970;
+ break;
+ case "'":
+ if (lookAhead("'"))
+ output += "'";
+ else
+ literal = true;
+ break;
+ default:
+ output += format.charAt(iFormat);
+ }
+ }
+ return output;
+ },
+
+ /* Extract all possible characters from the date format. */
+ _possibleChars: function (format) {
+ var chars = '';
+ var literal = false;
+ // Check whether a format character is doubled
+ var lookAhead = function(match) {
+ var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) == match);
+ if (matches)
+ iFormat++;
+ return matches;
+ };
+ for (var iFormat = 0; iFormat < format.length; iFormat++)
+ if (literal)
+ if (format.charAt(iFormat) == "'" && !lookAhead("'"))
+ literal = false;
+ else
+ chars += format.charAt(iFormat);
+ else
+ switch (format.charAt(iFormat)) {
+ case 'd': case 'm': case 'y': case '@':
+ chars += '0123456789';
+ break;
+ case 'D': case 'M':
+ return null; // Accept anything
+ case "'":
+ if (lookAhead("'"))
+ chars += "'";
+ else
+ literal = true;
+ break;
+ default:
+ chars += format.charAt(iFormat);
+ }
+ return chars;
+ },
+
+ /* Get a setting value, defaulting if necessary. */
+ _get: function(inst, name) {
+ return inst.settings[name] !== undefined ?
+ inst.settings[name] : this._defaults[name];
+ },
+
+ /* Parse existing date and initialise date picker. */
+ _setDateFromField: function(inst, noDefault) {
+ if (inst.input.val() == inst.lastVal) {
+ return;
+ }
+ var dateFormat = this._get(inst, 'dateFormat');
+ var dates = inst.lastVal = inst.input ? inst.input.val() : null;
+ var date, defaultDate;
+ date = defaultDate = this._getDefaultDate(inst);
+ var settings = this._getFormatConfig(inst);
+ try {
+ date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+ } catch (event) {
+ this.log(event);
+ dates = (noDefault ? '' : dates);
+ }
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ inst.currentDay = (dates ? date.getDate() : 0);
+ inst.currentMonth = (dates ? date.getMonth() : 0);
+ inst.currentYear = (dates ? date.getFullYear() : 0);
+ this._adjustInstDate(inst);
+ },
+
+ /* Retrieve the default date shown on opening. */
+ _getDefaultDate: function(inst) {
+ return this._restrictMinMax(inst,
+ this._determineDate(inst, this._get(inst, 'defaultDate'), new Date()));
+ },
+
+ /* A date may be specified as an exact value or a relative one. */
+ _determineDate: function(inst, date, defaultDate) {
+ var offsetNumeric = function(offset) {
+ var date = new Date();
+ date.setDate(date.getDate() + offset);
+ return date;
+ };
+ var offsetString = function(offset) {
+ try {
+ return $.datepicker.parseDate($.datepicker._get(inst, 'dateFormat'),
+ offset, $.datepicker._getFormatConfig(inst));
+ }
+ catch (e) {
+ // Ignore
+ }
+ var date = (offset.toLowerCase().match(/^c/) ?
+ $.datepicker._getDate(inst) : null) || new Date();
+ var year = date.getFullYear();
+ var month = date.getMonth();
+ var day = date.getDate();
+ var pattern = /([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;
+ var matches = pattern.exec(offset);
+ while (matches) {
+ switch (matches[2] || 'd') {
+ case 'd' : case 'D' :
+ day += parseInt(matches[1],10); break;
+ case 'w' : case 'W' :
+ day += parseInt(matches[1],10) * 7; break;
+ case 'm' : case 'M' :
+ month += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ case 'y': case 'Y' :
+ year += parseInt(matches[1],10);
+ day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+ break;
+ }
+ matches = pattern.exec(offset);
+ }
+ return new Date(year, month, day);
+ };
+ var newDate = (date == null || date === '' ? defaultDate : (typeof date == 'string' ? offsetString(date) :
+ (typeof date == 'number' ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+ newDate = (newDate && newDate.toString() == 'Invalid Date' ? defaultDate : newDate);
+ if (newDate) {
+ newDate.setHours(0);
+ newDate.setMinutes(0);
+ newDate.setSeconds(0);
+ newDate.setMilliseconds(0);
+ }
+ return this._daylightSavingAdjust(newDate);
+ },
+
+ /* Handle switch to/from daylight saving.
+ Hours may be non-zero on daylight saving cut-over:
+ > 12 when midnight changeover, but then cannot generate
+ midnight datetime, so jump to 1AM, otherwise reset.
+ @param date (Date) the date to check
+ @return (Date) the corrected date */
+ _daylightSavingAdjust: function(date) {
+ if (!date) return null;
+ date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+ return date;
+ },
+
+ /* Set the date(s) directly. */
+ _setDate: function(inst, date, noChange) {
+ var clear = !date;
+ var origMonth = inst.selectedMonth;
+ var origYear = inst.selectedYear;
+ var newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+ inst.selectedDay = inst.currentDay = newDate.getDate();
+ inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+ inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+ if ((origMonth != inst.selectedMonth || origYear != inst.selectedYear) && !noChange)
+ this._notifyChange(inst);
+ this._adjustInstDate(inst);
+ if (inst.input) {
+ inst.input.val(clear ? '' : this._formatDate(inst));
+ }
+ },
+
+ /* Retrieve the date(s) directly. */
+ _getDate: function(inst) {
+ var startDate = (!inst.currentYear || (inst.input && inst.input.val() == '') ? null :
+ this._daylightSavingAdjust(new Date(
+ inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return startDate;
+ },
+
+ /* Generate the HTML for the current state of the date picker. */
+ _generateHTML: function(inst) {
+ var today = new Date();
+ today = this._daylightSavingAdjust(
+ new Date(today.getFullYear(), today.getMonth(), today.getDate())); // clear time
+ var isRTL = this._get(inst, 'isRTL');
+ var showButtonPanel = this._get(inst, 'showButtonPanel');
+ var hideIfNoPrevNext = this._get(inst, 'hideIfNoPrevNext');
+ var navigationAsDateFormat = this._get(inst, 'navigationAsDateFormat');
+ var numMonths = this._getNumberOfMonths(inst);
+ var showCurrentAtPos = this._get(inst, 'showCurrentAtPos');
+ var stepMonths = this._get(inst, 'stepMonths');
+ var isMultiMonth = (numMonths[0] != 1 || numMonths[1] != 1);
+ var currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+ new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+ var minDate = this._getMinMaxDate(inst, 'min');
+ var maxDate = this._getMinMaxDate(inst, 'max');
+ var drawMonth = inst.drawMonth - showCurrentAtPos;
+ var drawYear = inst.drawYear;
+ if (drawMonth < 0) {
+ drawMonth += 12;
+ drawYear--;
+ }
+ if (maxDate) {
+ var maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+ maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+ maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+ while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+ drawMonth--;
+ if (drawMonth < 0) {
+ drawMonth = 11;
+ drawYear--;
+ }
+ }
+ }
+ inst.drawMonth = drawMonth;
+ inst.drawYear = drawYear;
+ var prevText = this._get(inst, 'prevText');
+ prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+ this._getFormatConfig(inst)));
+ var prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+ '<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_' + dpuuid +
+ '.datepicker._adjustDate(\'#' + inst.id + '\', -' + stepMonths + ', \'M\');"' +
+ ' title="' + prevText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>' :
+ (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+ prevText +'"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'e' : 'w') + '">' + prevText + '</span></a>'));
+ var nextText = this._get(inst, 'nextText');
+ nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+ this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+ this._getFormatConfig(inst)));
+ var next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+ '<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_' + dpuuid +
+ '.datepicker._adjustDate(\'#' + inst.id + '\', +' + stepMonths + ', \'M\');"' +
+ ' title="' + nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>' :
+ (hideIfNoPrevNext ? '' : '<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+ nextText + '"><span class="ui-icon ui-icon-circle-triangle-' + ( isRTL ? 'w' : 'e') + '">' + nextText + '</span></a>'));
+ var currentText = this._get(inst, 'currentText');
+ var gotoDate = (this._get(inst, 'gotoCurrent') && inst.currentDay ? currentDate : today);
+ currentText = (!navigationAsDateFormat ? currentText :
+ this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+ var controls = (!inst.inline ? '<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
+ '.datepicker._hideDatepicker();">' + this._get(inst, 'closeText') + '</button>' : '');
+ var buttonPanel = (showButtonPanel) ? '<div class="ui-datepicker-buttonpane ui-widget-content">' + (isRTL ? controls : '') +
+ (this._isInRange(inst, gotoDate) ? '<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_' + dpuuid +
+ '.datepicker._gotoToday(\'#' + inst.id + '\');"' +
+ '>' + currentText + '</button>' : '') + (isRTL ? '' : controls) + '</div>' : '';
+ var firstDay = parseInt(this._get(inst, 'firstDay'),10);
+ firstDay = (isNaN(firstDay) ? 0 : firstDay);
+ var showWeek = this._get(inst, 'showWeek');
+ var dayNames = this._get(inst, 'dayNames');
+ var dayNamesShort = this._get(inst, 'dayNamesShort');
+ var dayNamesMin = this._get(inst, 'dayNamesMin');
+ var monthNames = this._get(inst, 'monthNames');
+ var monthNamesShort = this._get(inst, 'monthNamesShort');
+ var beforeShowDay = this._get(inst, 'beforeShowDay');
+ var showOtherMonths = this._get(inst, 'showOtherMonths');
+ var selectOtherMonths = this._get(inst, 'selectOtherMonths');
+ var calculateWeek = this._get(inst, 'calculateWeek') || this.iso8601Week;
+ var defaultDate = this._getDefaultDate(inst);
+ var html = '';
+ for (var row = 0; row < numMonths[0]; row++) {
+ var group = '';
+ this.maxRows = 4;
+ for (var col = 0; col < numMonths[1]; col++) {
+ var selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+ var cornerClass = ' ui-corner-all';
+ var calender = '';
+ if (isMultiMonth) {
+ calender += '<div class="ui-datepicker-group';
+ if (numMonths[1] > 1)
+ switch (col) {
+ case 0: calender += ' ui-datepicker-group-first';
+ cornerClass = ' ui-corner-' + (isRTL ? 'right' : 'left'); break;
+ case numMonths[1]-1: calender += ' ui-datepicker-group-last';
+ cornerClass = ' ui-corner-' + (isRTL ? 'left' : 'right'); break;
+ default: calender += ' ui-datepicker-group-middle'; cornerClass = ''; break;
+ }
+ calender += '">';
+ }
+ calender += '<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix' + cornerClass + '">' +
+ (/all|left/.test(cornerClass) && row == 0 ? (isRTL ? next : prev) : '') +
+ (/all|right/.test(cornerClass) && row == 0 ? (isRTL ? prev : next) : '') +
+ this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+ row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+ '</div><table class="ui-datepicker-calendar"><thead>' +
+ '<tr>';
+ var thead = (showWeek ? '<th class="ui-datepicker-week-col">' + this._get(inst, 'weekHeader') + '</th>' : '');
+ for (var dow = 0; dow < 7; dow++) { // days of the week
+ var day = (dow + firstDay) % 7;
+ thead += '<th' + ((dow + firstDay + 6) % 7 >= 5 ? ' class="ui-datepicker-week-end"' : '') + '>' +
+ '<span title="' + dayNames[day] + '">' + dayNamesMin[day] + '</span></th>';
+ }
+ calender += thead + '</tr></thead><tbody>';
+ var daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+ if (drawYear == inst.selectedYear && drawMonth == inst.selectedMonth)
+ inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+ var leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+ var curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+ var numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+ this.maxRows = numRows;
+ var printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+ for (var dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+ calender += '<tr>';
+ var tbody = (!showWeek ? '' : '<td class="ui-datepicker-week-col">' +
+ this._get(inst, 'calculateWeek')(printDate) + '</td>');
+ for (var dow = 0; dow < 7; dow++) { // create date picker days
+ var daySettings = (beforeShowDay ?
+ beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, '']);
+ var otherMonth = (printDate.getMonth() != drawMonth);
+ var unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+ (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+ tbody += '<td class="' +
+ ((dow + firstDay + 6) % 7 >= 5 ? ' ui-datepicker-week-end' : '') + // highlight weekends
+ (otherMonth ? ' ui-datepicker-other-month' : '') + // highlight days from other months
+ ((printDate.getTime() == selectedDate.getTime() && drawMonth == inst.selectedMonth && inst._keyEvent) || // user pressed key
+ (defaultDate.getTime() == printDate.getTime() && defaultDate.getTime() == selectedDate.getTime()) ?
+ // or defaultDate is current printedDate and defaultDate is selectedDate
+ ' ' + this._dayOverClass : '') + // highlight selected day
+ (unselectable ? ' ' + this._unselectableClass + ' ui-state-disabled': '') + // highlight unselectable days
+ (otherMonth && !showOtherMonths ? '' : ' ' + daySettings[1] + // highlight custom dates
+ (printDate.getTime() == currentDate.getTime() ? ' ' + this._currentClass : '') + // highlight selected day
+ (printDate.getTime() == today.getTime() ? ' ui-datepicker-today' : '')) + '"' + // highlight today (if different)
+ ((!otherMonth || showOtherMonths) && daySettings[2] ? ' title="' + daySettings[2] + '"' : '') + // cell title
+ (unselectable ? '' : ' onclick="DP_jQuery_' + dpuuid + '.datepicker._selectDay(\'#' +
+ inst.id + '\',' + printDate.getMonth() + ',' + printDate.getFullYear() + ', this);return false;"') + '>' + // actions
+ (otherMonth && !showOtherMonths ? '&#xa0;' : // display for other months
+ (unselectable ? '<span class="ui-state-default">' + printDate.getDate() + '</span>' : '<a class="ui-state-default' +
+ (printDate.getTime() == today.getTime() ? ' ui-state-highlight' : '') +
+ (printDate.getTime() == currentDate.getTime() ? ' ui-state-active' : '') + // highlight selected day
+ (otherMonth ? ' ui-priority-secondary' : '') + // distinguish dates from other months
+ '" href="#">' + printDate.getDate() + '</a>')) + '</td>'; // display selectable date
+ printDate.setDate(printDate.getDate() + 1);
+ printDate = this._daylightSavingAdjust(printDate);
+ }
+ calender += tbody + '</tr>';
+ }
+ drawMonth++;
+ if (drawMonth > 11) {
+ drawMonth = 0;
+ drawYear++;
+ }
+ calender += '</tbody></table>' + (isMultiMonth ? '</div>' +
+ ((numMonths[0] > 0 && col == numMonths[1]-1) ? '<div class="ui-datepicker-row-break"></div>' : '') : '');
+ group += calender;
+ }
+ html += group;
+ }
+ html += buttonPanel + ($.browser.msie && parseInt($.browser.version,10) < 7 && !inst.inline ?
+ '<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>' : '');
+ inst._keyEvent = false;
+ return html;
+ },
+
+ /* Generate the month and year header. */
+ _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+ secondary, monthNames, monthNamesShort) {
+ var changeMonth = this._get(inst, 'changeMonth');
+ var changeYear = this._get(inst, 'changeYear');
+ var showMonthAfterYear = this._get(inst, 'showMonthAfterYear');
+ var html = '<div class="ui-datepicker-title">';
+ var monthHtml = '';
+ // month selection
+ if (secondary || !changeMonth)
+ monthHtml += '<span class="ui-datepicker-month">' + monthNames[drawMonth] + '</span>';
+ else {
+ var inMinYear = (minDate && minDate.getFullYear() == drawYear);
+ var inMaxYear = (maxDate && maxDate.getFullYear() == drawYear);
+ monthHtml += '<select class="ui-datepicker-month" ' +
+ 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'M\');" ' +
+ '>';
+ for (var month = 0; month < 12; month++) {
+ if ((!inMinYear || month >= minDate.getMonth()) &&
+ (!inMaxYear || month <= maxDate.getMonth()))
+ monthHtml += '<option value="' + month + '"' +
+ (month == drawMonth ? ' selected="selected"' : '') +
+ '>' + monthNamesShort[month] + '</option>';
+ }
+ monthHtml += '</select>';
+ }
+ if (!showMonthAfterYear)
+ html += monthHtml + (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '');
+ // year selection
+ if ( !inst.yearshtml ) {
+ inst.yearshtml = '';
+ if (secondary || !changeYear)
+ html += '<span class="ui-datepicker-year">' + drawYear + '</span>';
+ else {
+ // determine range of years to display
+ var years = this._get(inst, 'yearRange').split(':');
+ var thisYear = new Date().getFullYear();
+ var determineYear = function(value) {
+ var year = (value.match(/c[+-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+ (value.match(/[+-].*/) ? thisYear + parseInt(value, 10) :
+ parseInt(value, 10)));
+ return (isNaN(year) ? thisYear : year);
+ };
+ var year = determineYear(years[0]);
+ var endYear = Math.max(year, determineYear(years[1] || ''));
+ year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+ endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+ inst.yearshtml += '<select class="ui-datepicker-year" ' +
+ 'onchange="DP_jQuery_' + dpuuid + '.datepicker._selectMonthYear(\'#' + inst.id + '\', this, \'Y\');" ' +
+ '>';
+ for (; year <= endYear; year++) {
+ inst.yearshtml += '<option value="' + year + '"' +
+ (year == drawYear ? ' selected="selected"' : '') +
+ '>' + year + '</option>';
+ }
+ inst.yearshtml += '</select>';
+
+ html += inst.yearshtml;
+ inst.yearshtml = null;
+ }
+ }
+ html += this._get(inst, 'yearSuffix');
+ if (showMonthAfterYear)
+ html += (secondary || !(changeMonth && changeYear) ? '&#xa0;' : '') + monthHtml;
+ html += '</div>'; // Close datepicker_header
+ return html;
+ },
+
+ /* Adjust one of the date sub-fields. */
+ _adjustInstDate: function(inst, offset, period) {
+ var year = inst.drawYear + (period == 'Y' ? offset : 0);
+ var month = inst.drawMonth + (period == 'M' ? offset : 0);
+ var day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) +
+ (period == 'D' ? offset : 0);
+ var date = this._restrictMinMax(inst,
+ this._daylightSavingAdjust(new Date(year, month, day)));
+ inst.selectedDay = date.getDate();
+ inst.drawMonth = inst.selectedMonth = date.getMonth();
+ inst.drawYear = inst.selectedYear = date.getFullYear();
+ if (period == 'M' || period == 'Y')
+ this._notifyChange(inst);
+ },
+
+ /* Ensure a date is within any min/max bounds. */
+ _restrictMinMax: function(inst, date) {
+ var minDate = this._getMinMaxDate(inst, 'min');
+ var maxDate = this._getMinMaxDate(inst, 'max');
+ var newDate = (minDate && date < minDate ? minDate : date);
+ newDate = (maxDate && newDate > maxDate ? maxDate : newDate);
+ return newDate;
+ },
+
+ /* Notify change of month/year. */
+ _notifyChange: function(inst) {
+ var onChange = this._get(inst, 'onChangeMonthYear');
+ if (onChange)
+ onChange.apply((inst.input ? inst.input[0] : null),
+ [inst.selectedYear, inst.selectedMonth + 1, inst]);
+ },
+
+ /* Determine the number of months to show. */
+ _getNumberOfMonths: function(inst) {
+ var numMonths = this._get(inst, 'numberOfMonths');
+ return (numMonths == null ? [1, 1] : (typeof numMonths == 'number' ? [1, numMonths] : numMonths));
+ },
+
+ /* Determine the current maximum date - ensure no time components are set. */
+ _getMinMaxDate: function(inst, minMax) {
+ return this._determineDate(inst, this._get(inst, minMax + 'Date'), null);
+ },
+
+ /* Find the number of days in a given month. */
+ _getDaysInMonth: function(year, month) {
+ return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+ },
+
+ /* Find the day of the week of the first of a month. */
+ _getFirstDayOfMonth: function(year, month) {
+ return new Date(year, month, 1).getDay();
+ },
+
+ /* Determines if we should allow a "next/prev" month display change. */
+ _canAdjustMonth: function(inst, offset, curYear, curMonth) {
+ var numMonths = this._getNumberOfMonths(inst);
+ var date = this._daylightSavingAdjust(new Date(curYear,
+ curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+ if (offset < 0)
+ date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+ return this._isInRange(inst, date);
+ },
+
+ /* Is the given date in the accepted range? */
+ _isInRange: function(inst, date) {
+ var minDate = this._getMinMaxDate(inst, 'min');
+ var maxDate = this._getMinMaxDate(inst, 'max');
+ return ((!minDate || date.getTime() >= minDate.getTime()) &&
+ (!maxDate || date.getTime() <= maxDate.getTime()));
+ },
+
+ /* Provide the configuration settings for formatting/parsing. */
+ _getFormatConfig: function(inst) {
+ var shortYearCutoff = this._get(inst, 'shortYearCutoff');
+ shortYearCutoff = (typeof shortYearCutoff != 'string' ? shortYearCutoff :
+ new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+ return {shortYearCutoff: shortYearCutoff,
+ dayNamesShort: this._get(inst, 'dayNamesShort'), dayNames: this._get(inst, 'dayNames'),
+ monthNamesShort: this._get(inst, 'monthNamesShort'), monthNames: this._get(inst, 'monthNames')};
+ },
+
+ /* Format the given date for display. */
+ _formatDate: function(inst, day, month, year) {
+ if (!day) {
+ inst.currentDay = inst.selectedDay;
+ inst.currentMonth = inst.selectedMonth;
+ inst.currentYear = inst.selectedYear;
+ }
+ var date = (day ? (typeof day == 'object' ? day :
+ this._daylightSavingAdjust(new Date(year, month, day))) :
+ this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+ return this.formatDate(this._get(inst, 'dateFormat'), date, this._getFormatConfig(inst));
+ }
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function bindHover(dpDiv) {
+ var selector = 'button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a';
+ return dpDiv.bind('mouseout', function(event) {
+ var elem = $( event.target ).closest( selector );
+ if ( !elem.length ) {
+ return;
+ }
+ elem.removeClass( "ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover" );
+ })
+ .bind('mouseover', function(event) {
+ var elem = $( event.target ).closest( selector );
+ if ($.datepicker._isDisabledDatepicker( instActive.inline ? dpDiv.parent()[0] : instActive.input[0]) ||
+ !elem.length ) {
+ return;
+ }
+ elem.parents('.ui-datepicker-calendar').find('a').removeClass('ui-state-hover');
+ elem.addClass('ui-state-hover');
+ if (elem.hasClass('ui-datepicker-prev')) elem.addClass('ui-datepicker-prev-hover');
+ if (elem.hasClass('ui-datepicker-next')) elem.addClass('ui-datepicker-next-hover');
+ });
+}
+
+/* jQuery extend now ignores nulls! */
+function extendRemove(target, props) {
+ $.extend(target, props);
+ for (var name in props)
+ if (props[name] == null || props[name] == undefined)
+ target[name] = props[name];
+ return target;
+};
+
+/* Determine whether an object is an array. */
+function isArray(a) {
+ return (a && (($.browser.safari && typeof a == 'object' && a.length) ||
+ (a.constructor && a.constructor.toString().match(/\Array\(\)/))));
+};
+
+/* Invoke the datepicker functionality.
+ @param options string - a command, optionally followed by additional parameters or
+ Object - settings for attaching new datepicker functionality
+ @return jQuery object */
+$.fn.datepicker = function(options){
+
+ /* Verify an empty collection wasn't passed - Fixes #6976 */
+ if ( !this.length ) {
+ return this;
+ }
+
+ /* Initialise the date picker. */
+ if (!$.datepicker.initialized) {
+ $(document).mousedown($.datepicker._checkExternalClick).
+ find('body').append($.datepicker.dpDiv);
+ $.datepicker.initialized = true;
+ }
+
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
+ if (typeof options == 'string' && (options == 'isDisabled' || options == 'getDate' || options == 'widget'))
+ return $.datepicker['_' + options + 'Datepicker'].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ if (options == 'option' && arguments.length == 2 && typeof arguments[1] == 'string')
+ return $.datepicker['_' + options + 'Datepicker'].
+ apply($.datepicker, [this[0]].concat(otherArgs));
+ return this.each(function() {
+ typeof options == 'string' ?
+ $.datepicker['_' + options + 'Datepicker'].
+ apply($.datepicker, [this].concat(otherArgs)) :
+ $.datepicker._attachDatepicker(this, options);
+ });
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.8.18";
+
+// Workaround for #4055
+// Add another global to avoid noConflict issues with inline event handlers
+window['DP_jQuery_' + dpuuid] = $;
+
+})(jQuery);
+/*
+ * jQuery UI Dialog 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Dialog
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ * jquery.ui.button.js
+ * jquery.ui.draggable.js
+ * jquery.ui.mouse.js
+ * jquery.ui.position.js
+ * jquery.ui.resizable.js
+ */
+(function( $, undefined ) {
+
+var uiDialogClasses =
+ 'ui-dialog ' +
+ 'ui-widget ' +
+ 'ui-widget-content ' +
+ 'ui-corner-all ',
+ sizeRelatedOptions = {
+ buttons: true,
+ height: true,
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true,
+ width: true
+ },
+ resizableRelatedOptions = {
+ maxHeight: true,
+ maxWidth: true,
+ minHeight: true,
+ minWidth: true
+ },
+ // support for jQuery 1.3.2 - handle common attrFn methods for dialog
+ attrFn = $.attrFn || {
+ val: true,
+ css: true,
+ html: true,
+ text: true,
+ data: true,
+ width: true,
+ height: true,
+ offset: true,
+ click: true
+ };
+
+$.widget("ui.dialog", {
+ options: {
+ autoOpen: true,
+ buttons: {},
+ closeOnEscape: true,
+ closeText: 'close',
+ dialogClass: '',
+ draggable: true,
+ hide: null,
+ height: 'auto',
+ maxHeight: false,
+ maxWidth: false,
+ minHeight: 150,
+ minWidth: 150,
+ modal: false,
+ position: {
+ my: 'center',
+ at: 'center',
+ collision: 'fit',
+ // ensure that the titlebar is never outside the document
+ using: function(pos) {
+ var topOffset = $(this).css(pos).offset().top;
+ if (topOffset < 0) {
+ $(this).css('top', pos.top - topOffset);
+ }
+ }
+ },
+ resizable: true,
+ show: null,
+ stack: true,
+ title: '',
+ width: 300,
+ zIndex: 1000
+ },
+
+ _create: function() {
+ this.originalTitle = this.element.attr('title');
+ // #5742 - .attr() might return a DOMElement
+ if ( typeof this.originalTitle !== "string" ) {
+ this.originalTitle = "";
+ }
+
+ this.options.title = this.options.title || this.originalTitle;
+ var self = this,
+ options = self.options,
+
+ title = options.title || '&#160;',
+ titleId = $.ui.dialog.getTitleId(self.element),
+
+ uiDialog = (self.uiDialog = $('<div></div>'))
+ .appendTo(document.body)
+ .hide()
+ .addClass(uiDialogClasses + options.dialogClass)
+ .css({
+ zIndex: options.zIndex
+ })
+ // setting tabIndex makes the div focusable
+ // setting outline to 0 prevents a border on focus in Mozilla
+ .attr('tabIndex', -1).css('outline', 0).keydown(function(event) {
+ if (options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+ event.keyCode === $.ui.keyCode.ESCAPE) {
+
+ self.close(event);
+ event.preventDefault();
+ }
+ })
+ .attr({
+ role: 'dialog',
+ 'aria-labelledby': titleId
+ })
+ .mousedown(function(event) {
+ self.moveToTop(false, event);
+ }),
+
+ uiDialogContent = self.element
+ .show()
+ .removeAttr('title')
+ .addClass(
+ 'ui-dialog-content ' +
+ 'ui-widget-content')
+ .appendTo(uiDialog),
+
+ uiDialogTitlebar = (self.uiDialogTitlebar = $('<div></div>'))
+ .addClass(
+ 'ui-dialog-titlebar ' +
+ 'ui-widget-header ' +
+ 'ui-corner-all ' +
+ 'ui-helper-clearfix'
+ )
+ .prependTo(uiDialog),
+
+ uiDialogTitlebarClose = $('<a href="#"></a>')
+ .addClass(
+ 'ui-dialog-titlebar-close ' +
+ 'ui-corner-all'
+ )
+ .attr('role', 'button')
+ .hover(
+ function() {
+ uiDialogTitlebarClose.addClass('ui-state-hover');
+ },
+ function() {
+ uiDialogTitlebarClose.removeClass('ui-state-hover');
+ }
+ )
+ .focus(function() {
+ uiDialogTitlebarClose.addClass('ui-state-focus');
+ })
+ .blur(function() {
+ uiDialogTitlebarClose.removeClass('ui-state-focus');
+ })
+ .click(function(event) {
+ self.close(event);
+ return false;
+ })
+ .appendTo(uiDialogTitlebar),
+
+ uiDialogTitlebarCloseText = (self.uiDialogTitlebarCloseText = $('<span></span>'))
+ .addClass(
+ 'ui-icon ' +
+ 'ui-icon-closethick'
+ )
+ .text(options.closeText)
+ .appendTo(uiDialogTitlebarClose),
+
+ uiDialogTitle = $('<span></span>')
+ .addClass('ui-dialog-title')
+ .attr('id', titleId)
+ .html(title)
+ .prependTo(uiDialogTitlebar);
+
+ //handling of deprecated beforeclose (vs beforeClose) option
+ //Ticket #4669 http://dev.jqueryui.com/ticket/4669
+ //TODO: remove in 1.9pre
+ if ($.isFunction(options.beforeclose) && !$.isFunction(options.beforeClose)) {
+ options.beforeClose = options.beforeclose;
+ }
+
+ uiDialogTitlebar.find("*").add(uiDialogTitlebar).disableSelection();
+
+ if (options.draggable && $.fn.draggable) {
+ self._makeDraggable();
+ }
+ if (options.resizable && $.fn.resizable) {
+ self._makeResizable();
+ }
+
+ self._createButtons(options.buttons);
+ self._isOpen = false;
+
+ if ($.fn.bgiframe) {
+ uiDialog.bgiframe();
+ }
+ },
+
+ _init: function() {
+ if ( this.options.autoOpen ) {
+ this.open();
+ }
+ },
+
+ destroy: function() {
+ var self = this;
+
+ if (self.overlay) {
+ self.overlay.destroy();
+ }
+ self.uiDialog.hide();
+ self.element
+ .unbind('.dialog')
+ .removeData('dialog')
+ .removeClass('ui-dialog-content ui-widget-content')
+ .hide().appendTo('body');
+ self.uiDialog.remove();
+
+ if (self.originalTitle) {
+ self.element.attr('title', self.originalTitle);
+ }
+
+ return self;
+ },
+
+ widget: function() {
+ return this.uiDialog;
+ },
+
+ close: function(event) {
+ var self = this,
+ maxZ, thisZ;
+
+ if (false === self._trigger('beforeClose', event)) {
+ return;
+ }
+
+ if (self.overlay) {
+ self.overlay.destroy();
+ }
+ self.uiDialog.unbind('keypress.ui-dialog');
+
+ self._isOpen = false;
+
+ if (self.options.hide) {
+ self.uiDialog.hide(self.options.hide, function() {
+ self._trigger('close', event);
+ });
+ } else {
+ self.uiDialog.hide();
+ self._trigger('close', event);
+ }
+
+ $.ui.dialog.overlay.resize();
+
+ // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
+ if (self.options.modal) {
+ maxZ = 0;
+ $('.ui-dialog').each(function() {
+ if (this !== self.uiDialog[0]) {
+ thisZ = $(this).css('z-index');
+ if(!isNaN(thisZ)) {
+ maxZ = Math.max(maxZ, thisZ);
+ }
+ }
+ });
+ $.ui.dialog.maxZ = maxZ;
+ }
+
+ return self;
+ },
+
+ isOpen: function() {
+ return this._isOpen;
+ },
+
+ // the force parameter allows us to move modal dialogs to their correct
+ // position on open
+ moveToTop: function(force, event) {
+ var self = this,
+ options = self.options,
+ saveScroll;
+
+ if ((options.modal && !force) ||
+ (!options.stack && !options.modal)) {
+ return self._trigger('focus', event);
+ }
+
+ if (options.zIndex > $.ui.dialog.maxZ) {
+ $.ui.dialog.maxZ = options.zIndex;
+ }
+ if (self.overlay) {
+ $.ui.dialog.maxZ += 1;
+ self.overlay.$el.css('z-index', $.ui.dialog.overlay.maxZ = $.ui.dialog.maxZ);
+ }
+
+ //Save and then restore scroll since Opera 9.5+ resets when parent z-Index is changed.
+ // http://ui.jquery.com/bugs/ticket/3193
+ saveScroll = { scrollTop: self.element.scrollTop(), scrollLeft: self.element.scrollLeft() };
+ $.ui.dialog.maxZ += 1;
+ self.uiDialog.css('z-index', $.ui.dialog.maxZ);
+ self.element.attr(saveScroll);
+ self._trigger('focus', event);
+
+ return self;
+ },
+
+ open: function() {
+ if (this._isOpen) { return; }
+
+ var self = this,
+ options = self.options,
+ uiDialog = self.uiDialog;
+
+ self.overlay = options.modal ? new $.ui.dialog.overlay(self) : null;
+ self._size();
+ self._position(options.position);
+ uiDialog.show(options.show);
+ self.moveToTop(true);
+
+ // prevent tabbing out of modal dialogs
+ if ( options.modal ) {
+ uiDialog.bind( "keydown.ui-dialog", function( event ) {
+ if ( event.keyCode !== $.ui.keyCode.TAB ) {
+ return;
+ }
+
+ var tabbables = $(':tabbable', this),
+ first = tabbables.filter(':first'),
+ last = tabbables.filter(':last');
+
+ if (event.target === last[0] && !event.shiftKey) {
+ first.focus(1);
+ return false;
+ } else if (event.target === first[0] && event.shiftKey) {
+ last.focus(1);
+ return false;
+ }
+ });
+ }
+
+ // set focus to the first tabbable element in the content area or the first button
+ // if there are no tabbable elements, set focus on the dialog itself
+ $(self.element.find(':tabbable').get().concat(
+ uiDialog.find('.ui-dialog-buttonpane :tabbable').get().concat(
+ uiDialog.get()))).eq(0).focus();
+
+ self._isOpen = true;
+ self._trigger('open');
+
+ return self;
+ },
+
+ _createButtons: function(buttons) {
+ var self = this,
+ hasButtons = false,
+ uiDialogButtonPane = $('<div></div>')
+ .addClass(
+ 'ui-dialog-buttonpane ' +
+ 'ui-widget-content ' +
+ 'ui-helper-clearfix'
+ ),
+ uiButtonSet = $( "<div></div>" )
+ .addClass( "ui-dialog-buttonset" )
+ .appendTo( uiDialogButtonPane );
+
+ // if we already have a button pane, remove it
+ self.uiDialog.find('.ui-dialog-buttonpane').remove();
+
+ if (typeof buttons === 'object' && buttons !== null) {
+ $.each(buttons, function() {
+ return !(hasButtons = true);
+ });
+ }
+ if (hasButtons) {
+ $.each(buttons, function(name, props) {
+ props = $.isFunction( props ) ?
+ { click: props, text: name } :
+ props;
+ var button = $('<button type="button"></button>')
+ .click(function() {
+ props.click.apply(self.element[0], arguments);
+ })
+ .appendTo(uiButtonSet);
+ // can't use .attr( props, true ) with jQuery 1.3.2.
+ $.each( props, function( key, value ) {
+ if ( key === "click" ) {
+ return;
+ }
+ if ( key in attrFn ) {
+ button[ key ]( value );
+ } else {
+ button.attr( key, value );
+ }
+ });
+ if ($.fn.button) {
+ button.button();
+ }
+ });
+ uiDialogButtonPane.appendTo(self.uiDialog);
+ }
+ },
+
+ _makeDraggable: function() {
+ var self = this,
+ options = self.options,
+ doc = $(document),
+ heightBeforeDrag;
+
+ function filteredUi(ui) {
+ return {
+ position: ui.position,
+ offset: ui.offset
+ };
+ }
+
+ self.uiDialog.draggable({
+ cancel: '.ui-dialog-content, .ui-dialog-titlebar-close',
+ handle: '.ui-dialog-titlebar',
+ containment: 'document',
+ start: function(event, ui) {
+ heightBeforeDrag = options.height === "auto" ? "auto" : $(this).height();
+ $(this).height($(this).height()).addClass("ui-dialog-dragging");
+ self._trigger('dragStart', event, filteredUi(ui));
+ },
+ drag: function(event, ui) {
+ self._trigger('drag', event, filteredUi(ui));
+ },
+ stop: function(event, ui) {
+ options.position = [ui.position.left - doc.scrollLeft(),
+ ui.position.top - doc.scrollTop()];
+ $(this).removeClass("ui-dialog-dragging").height(heightBeforeDrag);
+ self._trigger('dragStop', event, filteredUi(ui));
+ $.ui.dialog.overlay.resize();
+ }
+ });
+ },
+
+ _makeResizable: function(handles) {
+ handles = (handles === undefined ? this.options.resizable : handles);
+ var self = this,
+ options = self.options,
+ // .ui-resizable has position: relative defined in the stylesheet
+ // but dialogs have to use absolute or fixed positioning
+ position = self.uiDialog.css('position'),
+ resizeHandles = (typeof handles === 'string' ?
+ handles :
+ 'n,e,s,w,se,sw,ne,nw'
+ );
+
+ function filteredUi(ui) {
+ return {
+ originalPosition: ui.originalPosition,
+ originalSize: ui.originalSize,
+ position: ui.position,
+ size: ui.size
+ };
+ }
+
+ self.uiDialog.resizable({
+ cancel: '.ui-dialog-content',
+ containment: 'document',
+ alsoResize: self.element,
+ maxWidth: options.maxWidth,
+ maxHeight: options.maxHeight,
+ minWidth: options.minWidth,
+ minHeight: self._minHeight(),
+ handles: resizeHandles,
+ start: function(event, ui) {
+ $(this).addClass("ui-dialog-resizing");
+ self._trigger('resizeStart', event, filteredUi(ui));
+ },
+ resize: function(event, ui) {
+ self._trigger('resize', event, filteredUi(ui));
+ },
+ stop: function(event, ui) {
+ $(this).removeClass("ui-dialog-resizing");
+ options.height = $(this).height();
+ options.width = $(this).width();
+ self._trigger('resizeStop', event, filteredUi(ui));
+ $.ui.dialog.overlay.resize();
+ }
+ })
+ .css('position', position)
+ .find('.ui-resizable-se').addClass('ui-icon ui-icon-grip-diagonal-se');
+ },
+
+ _minHeight: function() {
+ var options = this.options;
+
+ if (options.height === 'auto') {
+ return options.minHeight;
+ } else {
+ return Math.min(options.minHeight, options.height);
+ }
+ },
+
+ _position: function(position) {
+ var myAt = [],
+ offset = [0, 0],
+ isVisible;
+
+ if (position) {
+ // deep extending converts arrays to objects in jQuery <= 1.3.2 :-(
+ // if (typeof position == 'string' || $.isArray(position)) {
+ // myAt = $.isArray(position) ? position : position.split(' ');
+
+ if (typeof position === 'string' || (typeof position === 'object' && '0' in position)) {
+ myAt = position.split ? position.split(' ') : [position[0], position[1]];
+ if (myAt.length === 1) {
+ myAt[1] = myAt[0];
+ }
+
+ $.each(['left', 'top'], function(i, offsetPosition) {
+ if (+myAt[i] === myAt[i]) {
+ offset[i] = myAt[i];
+ myAt[i] = offsetPosition;
+ }
+ });
+
+ position = {
+ my: myAt.join(" "),
+ at: myAt.join(" "),
+ offset: offset.join(" ")
+ };
+ }
+
+ position = $.extend({}, $.ui.dialog.prototype.options.position, position);
+ } else {
+ position = $.ui.dialog.prototype.options.position;
+ }
+
+ // need to show the dialog to get the actual offset in the position plugin
+ isVisible = this.uiDialog.is(':visible');
+ if (!isVisible) {
+ this.uiDialog.show();
+ }
+ this.uiDialog
+ // workaround for jQuery bug #5781 http://dev.jquery.com/ticket/5781
+ .css({ top: 0, left: 0 })
+ .position($.extend({ of: window }, position));
+ if (!isVisible) {
+ this.uiDialog.hide();
+ }
+ },
+
+ _setOptions: function( options ) {
+ var self = this,
+ resizableOptions = {},
+ resize = false;
+
+ $.each( options, function( key, value ) {
+ self._setOption( key, value );
+
+ if ( key in sizeRelatedOptions ) {
+ resize = true;
+ }
+ if ( key in resizableRelatedOptions ) {
+ resizableOptions[ key ] = value;
+ }
+ });
+
+ if ( resize ) {
+ this._size();
+ }
+ if ( this.uiDialog.is( ":data(resizable)" ) ) {
+ this.uiDialog.resizable( "option", resizableOptions );
+ }
+ },
+
+ _setOption: function(key, value){
+ var self = this,
+ uiDialog = self.uiDialog;
+
+ switch (key) {
+ //handling of deprecated beforeclose (vs beforeClose) option
+ //Ticket #4669 http://dev.jqueryui.com/ticket/4669
+ //TODO: remove in 1.9pre
+ case "beforeclose":
+ key = "beforeClose";
+ break;
+ case "buttons":
+ self._createButtons(value);
+ break;
+ case "closeText":
+ // ensure that we always pass a string
+ self.uiDialogTitlebarCloseText.text("" + value);
+ break;
+ case "dialogClass":
+ uiDialog
+ .removeClass(self.options.dialogClass)
+ .addClass(uiDialogClasses + value);
+ break;
+ case "disabled":
+ if (value) {
+ uiDialog.addClass('ui-dialog-disabled');
+ } else {
+ uiDialog.removeClass('ui-dialog-disabled');
+ }
+ break;
+ case "draggable":
+ var isDraggable = uiDialog.is( ":data(draggable)" );
+ if ( isDraggable && !value ) {
+ uiDialog.draggable( "destroy" );
+ }
+
+ if ( !isDraggable && value ) {
+ self._makeDraggable();
+ }
+ break;
+ case "position":
+ self._position(value);
+ break;
+ case "resizable":
+ // currently resizable, becoming non-resizable
+ var isResizable = uiDialog.is( ":data(resizable)" );
+ if (isResizable && !value) {
+ uiDialog.resizable('destroy');
+ }
+
+ // currently resizable, changing handles
+ if (isResizable && typeof value === 'string') {
+ uiDialog.resizable('option', 'handles', value);
+ }
+
+ // currently non-resizable, becoming resizable
+ if (!isResizable && value !== false) {
+ self._makeResizable(value);
+ }
+ break;
+ case "title":
+ // convert whatever was passed in o a string, for html() to not throw up
+ $(".ui-dialog-title", self.uiDialogTitlebar).html("" + (value || '&#160;'));
+ break;
+ }
+
+ $.Widget.prototype._setOption.apply(self, arguments);
+ },
+
+ _size: function() {
+ /* If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+ * divs will both have width and height set, so we need to reset them
+ */
+ var options = this.options,
+ nonContentHeight,
+ minContentHeight,
+ isVisible = this.uiDialog.is( ":visible" );
+
+ // reset content sizing
+ this.element.show().css({
+ width: 'auto',
+ minHeight: 0,
+ height: 0
+ });
+
+ if (options.minWidth > options.width) {
+ options.width = options.minWidth;
+ }
+
+ // reset wrapper sizing
+ // determine the height of all the non-content elements
+ nonContentHeight = this.uiDialog.css({
+ height: 'auto',
+ width: options.width
+ })
+ .height();
+ minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+
+ if ( options.height === "auto" ) {
+ // only needed for IE6 support
+ if ( $.support.minHeight ) {
+ this.element.css({
+ minHeight: minContentHeight,
+ height: "auto"
+ });
+ } else {
+ this.uiDialog.show();
+ var autoHeight = this.element.css( "height", "auto" ).height();
+ if ( !isVisible ) {
+ this.uiDialog.hide();
+ }
+ this.element.height( Math.max( autoHeight, minContentHeight ) );
+ }
+ } else {
+ this.element.height( Math.max( options.height - nonContentHeight, 0 ) );
+ }
+
+ if (this.uiDialog.is(':data(resizable)')) {
+ this.uiDialog.resizable('option', 'minHeight', this._minHeight());
+ }
+ }
+});
+
+$.extend($.ui.dialog, {
+ version: "1.8.18",
+
+ uuid: 0,
+ maxZ: 0,
+
+ getTitleId: function($el) {
+ var id = $el.attr('id');
+ if (!id) {
+ this.uuid += 1;
+ id = this.uuid;
+ }
+ return 'ui-dialog-title-' + id;
+ },
+
+ overlay: function(dialog) {
+ this.$el = $.ui.dialog.overlay.create(dialog);
+ }
+});
+
+$.extend($.ui.dialog.overlay, {
+ instances: [],
+ // reuse old instances due to IE memory leak with alpha transparency (see #5185)
+ oldInstances: [],
+ maxZ: 0,
+ events: $.map('focus,mousedown,mouseup,keydown,keypress,click'.split(','),
+ function(event) { return event + '.dialog-overlay'; }).join(' '),
+ create: function(dialog) {
+ if (this.instances.length === 0) {
+ // prevent use of anchors and inputs
+ // we use a setTimeout in case the overlay is created from an
+ // event that we're going to be cancelling (see #2804)
+ setTimeout(function() {
+ // handle $(el).dialog().dialog('close') (see #4065)
+ if ($.ui.dialog.overlay.instances.length) {
+ $(document).bind($.ui.dialog.overlay.events, function(event) {
+ // stop events if the z-index of the target is < the z-index of the overlay
+ // we cannot return true when we don't want to cancel the event (#3523)
+ if ($(event.target).zIndex() < $.ui.dialog.overlay.maxZ) {
+ return false;
+ }
+ });
+ }
+ }, 1);
+
+ // allow closing by pressing the escape key
+ $(document).bind('keydown.dialog-overlay', function(event) {
+ if (dialog.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+ event.keyCode === $.ui.keyCode.ESCAPE) {
+
+ dialog.close(event);
+ event.preventDefault();
+ }
+ });
+
+ // handle window resize
+ $(window).bind('resize.dialog-overlay', $.ui.dialog.overlay.resize);
+ }
+
+ var $el = (this.oldInstances.pop() || $('<div></div>').addClass('ui-widget-overlay'))
+ .appendTo(document.body)
+ .css({
+ width: this.width(),
+ height: this.height()
+ });
+
+ if ($.fn.bgiframe) {
+ $el.bgiframe();
+ }
+
+ this.instances.push($el);
+ return $el;
+ },
+
+ destroy: function($el) {
+ var indexOf = $.inArray($el, this.instances);
+ if (indexOf != -1){
+ this.oldInstances.push(this.instances.splice(indexOf, 1)[0]);
+ }
+
+ if (this.instances.length === 0) {
+ $([document, window]).unbind('.dialog-overlay');
+ }
+
+ $el.remove();
+
+ // adjust the maxZ to allow other modal dialogs to continue to work (see #4309)
+ var maxZ = 0;
+ $.each(this.instances, function() {
+ maxZ = Math.max(maxZ, this.css('z-index'));
+ });
+ this.maxZ = maxZ;
+ },
+
+ height: function() {
+ var scrollHeight,
+ offsetHeight;
+ // handle IE 6
+ if ($.browser.msie && $.browser.version < 7) {
+ scrollHeight = Math.max(
+ document.documentElement.scrollHeight,
+ document.body.scrollHeight
+ );
+ offsetHeight = Math.max(
+ document.documentElement.offsetHeight,
+ document.body.offsetHeight
+ );
+
+ if (scrollHeight < offsetHeight) {
+ return $(window).height() + 'px';
+ } else {
+ return scrollHeight + 'px';
+ }
+ // handle "good" browsers
+ } else {
+ return $(document).height() + 'px';
+ }
+ },
+
+ width: function() {
+ var scrollWidth,
+ offsetWidth;
+ // handle IE
+ if ( $.browser.msie ) {
+ scrollWidth = Math.max(
+ document.documentElement.scrollWidth,
+ document.body.scrollWidth
+ );
+ offsetWidth = Math.max(
+ document.documentElement.offsetWidth,
+ document.body.offsetWidth
+ );
+
+ if (scrollWidth < offsetWidth) {
+ return $(window).width() + 'px';
+ } else {
+ return scrollWidth + 'px';
+ }
+ // handle "good" browsers
+ } else {
+ return $(document).width() + 'px';
+ }
+ },
+
+ resize: function() {
+ /* If the dialog is draggable and the user drags it past the
+ * right edge of the window, the document becomes wider so we
+ * need to stretch the overlay. If the user then drags the
+ * dialog back to the left, the document will become narrower,
+ * so we need to shrink the overlay to the appropriate size.
+ * This is handled by shrinking the overlay before setting it
+ * to the full document size.
+ */
+ var $overlays = $([]);
+ $.each($.ui.dialog.overlay.instances, function() {
+ $overlays = $overlays.add(this);
+ });
+
+ $overlays.css({
+ width: 0,
+ height: 0
+ }).css({
+ width: $.ui.dialog.overlay.width(),
+ height: $.ui.dialog.overlay.height()
+ });
+ }
+});
+
+$.extend($.ui.dialog.overlay.prototype, {
+ destroy: function() {
+ $.ui.dialog.overlay.destroy(this.$el);
+ }
+});
+
+}(jQuery));
+/*
+ * jQuery UI Position 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Position
+ */
+(function( $, undefined ) {
+
+$.ui = $.ui || {};
+
+var horizontalPositions = /left|center|right/,
+ verticalPositions = /top|center|bottom/,
+ center = "center",
+ support = {},
+ _position = $.fn.position,
+ _offset = $.fn.offset;
+
+$.fn.position = function( options ) {
+ if ( !options || !options.of ) {
+ return _position.apply( this, arguments );
+ }
+
+ // make a copy, we don't want to modify arguments
+ options = $.extend( {}, options );
+
+ var target = $( options.of ),
+ targetElem = target[0],
+ collision = ( options.collision || "flip" ).split( " " ),
+ offset = options.offset ? options.offset.split( " " ) : [ 0, 0 ],
+ targetWidth,
+ targetHeight,
+ basePosition;
+
+ if ( targetElem.nodeType === 9 ) {
+ targetWidth = target.width();
+ targetHeight = target.height();
+ basePosition = { top: 0, left: 0 };
+ // TODO: use $.isWindow() in 1.9
+ } else if ( targetElem.setTimeout ) {
+ targetWidth = target.width();
+ targetHeight = target.height();
+ basePosition = { top: target.scrollTop(), left: target.scrollLeft() };
+ } else if ( targetElem.preventDefault ) {
+ // force left top to allow flipping
+ options.at = "left top";
+ targetWidth = targetHeight = 0;
+ basePosition = { top: options.of.pageY, left: options.of.pageX };
+ } else {
+ targetWidth = target.outerWidth();
+ targetHeight = target.outerHeight();
+ basePosition = target.offset();
+ }
+
+ // force my and at to have valid horizontal and veritcal positions
+ // if a value is missing or invalid, it will be converted to center
+ $.each( [ "my", "at" ], function() {
+ var pos = ( options[this] || "" ).split( " " );
+ if ( pos.length === 1) {
+ pos = horizontalPositions.test( pos[0] ) ?
+ pos.concat( [center] ) :
+ verticalPositions.test( pos[0] ) ?
+ [ center ].concat( pos ) :
+ [ center, center ];
+ }
+ pos[ 0 ] = horizontalPositions.test( pos[0] ) ? pos[ 0 ] : center;
+ pos[ 1 ] = verticalPositions.test( pos[1] ) ? pos[ 1 ] : center;
+ options[ this ] = pos;
+ });
+
+ // normalize collision option
+ if ( collision.length === 1 ) {
+ collision[ 1 ] = collision[ 0 ];
+ }
+
+ // normalize offset option
+ offset[ 0 ] = parseInt( offset[0], 10 ) || 0;
+ if ( offset.length === 1 ) {
+ offset[ 1 ] = offset[ 0 ];
+ }
+ offset[ 1 ] = parseInt( offset[1], 10 ) || 0;
+
+ if ( options.at[0] === "right" ) {
+ basePosition.left += targetWidth;
+ } else if ( options.at[0] === center ) {
+ basePosition.left += targetWidth / 2;
+ }
+
+ if ( options.at[1] === "bottom" ) {
+ basePosition.top += targetHeight;
+ } else if ( options.at[1] === center ) {
+ basePosition.top += targetHeight / 2;
+ }
+
+ basePosition.left += offset[ 0 ];
+ basePosition.top += offset[ 1 ];
+
+ return this.each(function() {
+ var elem = $( this ),
+ elemWidth = elem.outerWidth(),
+ elemHeight = elem.outerHeight(),
+ marginLeft = parseInt( $.curCSS( this, "marginLeft", true ) ) || 0,
+ marginTop = parseInt( $.curCSS( this, "marginTop", true ) ) || 0,
+ collisionWidth = elemWidth + marginLeft +
+ ( parseInt( $.curCSS( this, "marginRight", true ) ) || 0 ),
+ collisionHeight = elemHeight + marginTop +
+ ( parseInt( $.curCSS( this, "marginBottom", true ) ) || 0 ),
+ position = $.extend( {}, basePosition ),
+ collisionPosition;
+
+ if ( options.my[0] === "right" ) {
+ position.left -= elemWidth;
+ } else if ( options.my[0] === center ) {
+ position.left -= elemWidth / 2;
+ }
+
+ if ( options.my[1] === "bottom" ) {
+ position.top -= elemHeight;
+ } else if ( options.my[1] === center ) {
+ position.top -= elemHeight / 2;
+ }
+
+ // prevent fractions if jQuery version doesn't support them (see #5280)
+ if ( !support.fractions ) {
+ position.left = Math.round( position.left );
+ position.top = Math.round( position.top );
+ }
+
+ collisionPosition = {
+ left: position.left - marginLeft,
+ top: position.top - marginTop
+ };
+
+ $.each( [ "left", "top" ], function( i, dir ) {
+ if ( $.ui.position[ collision[i] ] ) {
+ $.ui.position[ collision[i] ][ dir ]( position, {
+ targetWidth: targetWidth,
+ targetHeight: targetHeight,
+ elemWidth: elemWidth,
+ elemHeight: elemHeight,
+ collisionPosition: collisionPosition,
+ collisionWidth: collisionWidth,
+ collisionHeight: collisionHeight,
+ offset: offset,
+ my: options.my,
+ at: options.at
+ });
+ }
+ });
+
+ if ( $.fn.bgiframe ) {
+ elem.bgiframe();
+ }
+ elem.offset( $.extend( position, { using: options.using } ) );
+ });
+};
+
+$.ui.position = {
+ fit: {
+ left: function( position, data ) {
+ var win = $( window ),
+ over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft();
+ position.left = over > 0 ? position.left - over : Math.max( position.left - data.collisionPosition.left, position.left );
+ },
+ top: function( position, data ) {
+ var win = $( window ),
+ over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop();
+ position.top = over > 0 ? position.top - over : Math.max( position.top - data.collisionPosition.top, position.top );
+ }
+ },
+
+ flip: {
+ left: function( position, data ) {
+ if ( data.at[0] === center ) {
+ return;
+ }
+ var win = $( window ),
+ over = data.collisionPosition.left + data.collisionWidth - win.width() - win.scrollLeft(),
+ myOffset = data.my[ 0 ] === "left" ?
+ -data.elemWidth :
+ data.my[ 0 ] === "right" ?
+ data.elemWidth :
+ 0,
+ atOffset = data.at[ 0 ] === "left" ?
+ data.targetWidth :
+ -data.targetWidth,
+ offset = -2 * data.offset[ 0 ];
+ position.left += data.collisionPosition.left < 0 ?
+ myOffset + atOffset + offset :
+ over > 0 ?
+ myOffset + atOffset + offset :
+ 0;
+ },
+ top: function( position, data ) {
+ if ( data.at[1] === center ) {
+ return;
+ }
+ var win = $( window ),
+ over = data.collisionPosition.top + data.collisionHeight - win.height() - win.scrollTop(),
+ myOffset = data.my[ 1 ] === "top" ?
+ -data.elemHeight :
+ data.my[ 1 ] === "bottom" ?
+ data.elemHeight :
+ 0,
+ atOffset = data.at[ 1 ] === "top" ?
+ data.targetHeight :
+ -data.targetHeight,
+ offset = -2 * data.offset[ 1 ];
+ position.top += data.collisionPosition.top < 0 ?
+ myOffset + atOffset + offset :
+ over > 0 ?
+ myOffset + atOffset + offset :
+ 0;
+ }
+ }
+};
+
+// offset setter from jQuery 1.4
+if ( !$.offset.setOffset ) {
+ $.offset.setOffset = function( elem, options ) {
+ // set position first, in-case top/left are set even on static elem
+ if ( /static/.test( $.curCSS( elem, "position" ) ) ) {
+ elem.style.position = "relative";
+ }
+ var curElem = $( elem ),
+ curOffset = curElem.offset(),
+ curTop = parseInt( $.curCSS( elem, "top", true ), 10 ) || 0,
+ curLeft = parseInt( $.curCSS( elem, "left", true ), 10) || 0,
+ props = {
+ top: (options.top - curOffset.top) + curTop,
+ left: (options.left - curOffset.left) + curLeft
+ };
+
+ if ( 'using' in options ) {
+ options.using.call( elem, props );
+ } else {
+ curElem.css( props );
+ }
+ };
+
+ $.fn.offset = function( options ) {
+ var elem = this[ 0 ];
+ if ( !elem || !elem.ownerDocument ) { return null; }
+ if ( options ) {
+ return this.each(function() {
+ $.offset.setOffset( this, options );
+ });
+ }
+ return _offset.call( this );
+ };
+}
+
+// fraction support test (older versions of jQuery don't support fractions)
+(function () {
+ var body = document.getElementsByTagName( "body" )[ 0 ],
+ div = document.createElement( "div" ),
+ testElement, testElementParent, testElementStyle, offset, offsetTotal;
+
+ //Create a "fake body" for testing based on method used in jQuery.support
+ testElement = document.createElement( body ? "div" : "body" );
+ testElementStyle = {
+ visibility: "hidden",
+ width: 0,
+ height: 0,
+ border: 0,
+ margin: 0,
+ background: "none"
+ };
+ if ( body ) {
+ $.extend( testElementStyle, {
+ position: "absolute",
+ left: "-1000px",
+ top: "-1000px"
+ });
+ }
+ for ( var i in testElementStyle ) {
+ testElement.style[ i ] = testElementStyle[ i ];
+ }
+ testElement.appendChild( div );
+ testElementParent = body || document.documentElement;
+ testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+ div.style.cssText = "position: absolute; left: 10.7432222px; top: 10.432325px; height: 30px; width: 201px;";
+
+ offset = $( div ).offset( function( _, offset ) {
+ return offset;
+ }).offset();
+
+ testElement.innerHTML = "";
+ testElementParent.removeChild( testElement );
+
+ offsetTotal = offset.top + offset.left + ( body ? 2000 : 0 );
+ support.fractions = offsetTotal > 21 && offsetTotal < 22;
+})();
+
+}( jQuery ));
+/*
+ * jQuery UI Progressbar 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Progressbar
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget( "ui.progressbar", {
+ options: {
+ value: 0,
+ max: 100
+ },
+
+ min: 0,
+
+ _create: function() {
+ this.element
+ .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .attr({
+ role: "progressbar",
+ "aria-valuemin": this.min,
+ "aria-valuemax": this.options.max,
+ "aria-valuenow": this._value()
+ });
+
+ this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+ .appendTo( this.element );
+
+ this.oldValue = this._value();
+ this._refreshValue();
+ },
+
+ destroy: function() {
+ this.element
+ .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+ .removeAttr( "role" )
+ .removeAttr( "aria-valuemin" )
+ .removeAttr( "aria-valuemax" )
+ .removeAttr( "aria-valuenow" );
+
+ this.valueDiv.remove();
+
+ $.Widget.prototype.destroy.apply( this, arguments );
+ },
+
+ value: function( newValue ) {
+ if ( newValue === undefined ) {
+ return this._value();
+ }
+
+ this._setOption( "value", newValue );
+ return this;
+ },
+
+ _setOption: function( key, value ) {
+ if ( key === "value" ) {
+ this.options.value = value;
+ this._refreshValue();
+ if ( this._value() === this.options.max ) {
+ this._trigger( "complete" );
+ }
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+ },
+
+ _value: function() {
+ var val = this.options.value;
+ // normalize invalid value
+ if ( typeof val !== "number" ) {
+ val = 0;
+ }
+ return Math.min( this.options.max, Math.max( this.min, val ) );
+ },
+
+ _percentage: function() {
+ return 100 * this._value() / this.options.max;
+ },
+
+ _refreshValue: function() {
+ var value = this.value();
+ var percentage = this._percentage();
+
+ if ( this.oldValue !== value ) {
+ this.oldValue = value;
+ this._trigger( "change" );
+ }
+
+ this.valueDiv
+ .toggle( value > this.min )
+ .toggleClass( "ui-corner-right", value === this.options.max )
+ .width( percentage.toFixed(0) + "%" );
+ this.element.attr( "aria-valuenow", value );
+ }
+});
+
+$.extend( $.ui.progressbar, {
+ version: "1.8.18"
+});
+
+})( jQuery );
+/*
+ * jQuery UI Slider 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.mouse.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+
+ widgetEventPrefix: "slide",
+
+ options: {
+ animate: false,
+ distance: 0,
+ max: 100,
+ min: 0,
+ orientation: "horizontal",
+ range: false,
+ step: 1,
+ value: 0,
+ values: null
+ },
+
+ _create: function() {
+ var self = this,
+ o = this.options,
+ existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+ handle = "<a class='ui-slider-handle ui-state-default ui-corner-all' href='#'></a>",
+ handleCount = ( o.values && o.values.length ) || 1,
+ handles = [];
+
+ this._keySliding = false;
+ this._mouseSliding = false;
+ this._animateOff = true;
+ this._handleIndex = null;
+ this._detectOrientation();
+ this._mouseInit();
+
+ this.element
+ .addClass( "ui-slider" +
+ " ui-slider-" + this.orientation +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all" +
+ ( o.disabled ? " ui-slider-disabled ui-disabled" : "" ) );
+
+ this.range = $([]);
+
+ if ( o.range ) {
+ if ( o.range === true ) {
+ if ( !o.values ) {
+ o.values = [ this._valueMin(), this._valueMin() ];
+ }
+ if ( o.values.length && o.values.length !== 2 ) {
+ o.values = [ o.values[0], o.values[0] ];
+ }
+ }
+
+ this.range = $( "<div></div>" )
+ .appendTo( this.element )
+ .addClass( "ui-slider-range" +
+ // note: this isn't the most fittingly semantic framework class for this element,
+ // but worked best visually with a variety of themes
+ " ui-widget-header" +
+ ( ( o.range === "min" || o.range === "max" ) ? " ui-slider-range-" + o.range : "" ) );
+ }
+
+ for ( var i = existingHandles.length; i < handleCount; i += 1 ) {
+ handles.push( handle );
+ }
+
+ this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( self.element ) );
+
+ this.handle = this.handles.eq( 0 );
+
+ this.handles.add( this.range ).filter( "a" )
+ .click(function( event ) {
+ event.preventDefault();
+ })
+ .hover(function() {
+ if ( !o.disabled ) {
+ $( this ).addClass( "ui-state-hover" );
+ }
+ }, function() {
+ $( this ).removeClass( "ui-state-hover" );
+ })
+ .focus(function() {
+ if ( !o.disabled ) {
+ $( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
+ $( this ).addClass( "ui-state-focus" );
+ } else {
+ $( this ).blur();
+ }
+ })
+ .blur(function() {
+ $( this ).removeClass( "ui-state-focus" );
+ });
+
+ this.handles.each(function( i ) {
+ $( this ).data( "index.ui-slider-handle", i );
+ });
+
+ this.handles
+ .keydown(function( event ) {
+ var index = $( this ).data( "index.ui-slider-handle" ),
+ allowed,
+ curVal,
+ newVal,
+ step;
+
+ if ( self.options.disabled ) {
+ return;
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ case $.ui.keyCode.END:
+ case $.ui.keyCode.PAGE_UP:
+ case $.ui.keyCode.PAGE_DOWN:
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ event.preventDefault();
+ if ( !self._keySliding ) {
+ self._keySliding = true;
+ $( this ).addClass( "ui-state-active" );
+ allowed = self._start( event, index );
+ if ( allowed === false ) {
+ return;
+ }
+ }
+ break;
+ }
+
+ step = self.options.step;
+ if ( self.options.values && self.options.values.length ) {
+ curVal = newVal = self.values( index );
+ } else {
+ curVal = newVal = self.value();
+ }
+
+ switch ( event.keyCode ) {
+ case $.ui.keyCode.HOME:
+ newVal = self._valueMin();
+ break;
+ case $.ui.keyCode.END:
+ newVal = self._valueMax();
+ break;
+ case $.ui.keyCode.PAGE_UP:
+ newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.PAGE_DOWN:
+ newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
+ break;
+ case $.ui.keyCode.UP:
+ case $.ui.keyCode.RIGHT:
+ if ( curVal === self._valueMax() ) {
+ return;
+ }
+ newVal = self._trimAlignValue( curVal + step );
+ break;
+ case $.ui.keyCode.DOWN:
+ case $.ui.keyCode.LEFT:
+ if ( curVal === self._valueMin() ) {
+ return;
+ }
+ newVal = self._trimAlignValue( curVal - step );
+ break;
+ }
+
+ self._slide( event, index, newVal );
+ })
+ .keyup(function( event ) {
+ var index = $( this ).data( "index.ui-slider-handle" );
+
+ if ( self._keySliding ) {
+ self._keySliding = false;
+ self._stop( event, index );
+ self._change( event, index );
+ $( this ).removeClass( "ui-state-active" );
+ }
+
+ });
+
+ this._refreshValue();
+
+ this._animateOff = false;
+ },
+
+ destroy: function() {
+ this.handles.remove();
+ this.range.remove();
+
+ this.element
+ .removeClass( "ui-slider" +
+ " ui-slider-horizontal" +
+ " ui-slider-vertical" +
+ " ui-slider-disabled" +
+ " ui-widget" +
+ " ui-widget-content" +
+ " ui-corner-all" )
+ .removeData( "slider" )
+ .unbind( ".slider" );
+
+ this._mouseDestroy();
+
+ return this;
+ },
+
+ _mouseCapture: function( event ) {
+ var o = this.options,
+ position,
+ normValue,
+ distance,
+ closestHandle,
+ self,
+ index,
+ allowed,
+ offset,
+ mouseOverHandle;
+
+ if ( o.disabled ) {
+ return false;
+ }
+
+ this.elementSize = {
+ width: this.element.outerWidth(),
+ height: this.element.outerHeight()
+ };
+ this.elementOffset = this.element.offset();
+
+ position = { x: event.pageX, y: event.pageY };
+ normValue = this._normValueFromMouse( position );
+ distance = this._valueMax() - this._valueMin() + 1;
+ self = this;
+ this.handles.each(function( i ) {
+ var thisDistance = Math.abs( normValue - self.values(i) );
+ if ( distance > thisDistance ) {
+ distance = thisDistance;
+ closestHandle = $( this );
+ index = i;
+ }
+ });
+
+ // workaround for bug #3736 (if both handles of a range are at 0,
+ // the first is always used as the one with least distance,
+ // and moving it is obviously prevented by preventing negative ranges)
+ if( o.range === true && this.values(1) === o.min ) {
+ index += 1;
+ closestHandle = $( this.handles[index] );
+ }
+
+ allowed = this._start( event, index );
+ if ( allowed === false ) {
+ return false;
+ }
+ this._mouseSliding = true;
+
+ self._handleIndex = index;
+
+ closestHandle
+ .addClass( "ui-state-active" )
+ .focus();
+
+ offset = closestHandle.offset();
+ mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
+ this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+ left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+ top: event.pageY - offset.top -
+ ( closestHandle.height() / 2 ) -
+ ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+ ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+ ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+ };
+
+ if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+ this._slide( event, index, normValue );
+ }
+ this._animateOff = true;
+ return true;
+ },
+
+ _mouseStart: function( event ) {
+ return true;
+ },
+
+ _mouseDrag: function( event ) {
+ var position = { x: event.pageX, y: event.pageY },
+ normValue = this._normValueFromMouse( position );
+
+ this._slide( event, this._handleIndex, normValue );
+
+ return false;
+ },
+
+ _mouseStop: function( event ) {
+ this.handles.removeClass( "ui-state-active" );
+ this._mouseSliding = false;
+
+ this._stop( event, this._handleIndex );
+ this._change( event, this._handleIndex );
+
+ this._handleIndex = null;
+ this._clickOffset = null;
+ this._animateOff = false;
+
+ return false;
+ },
+
+ _detectOrientation: function() {
+ this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+ },
+
+ _normValueFromMouse: function( position ) {
+ var pixelTotal,
+ pixelMouse,
+ percentMouse,
+ valueTotal,
+ valueMouse;
+
+ if ( this.orientation === "horizontal" ) {
+ pixelTotal = this.elementSize.width;
+ pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+ } else {
+ pixelTotal = this.elementSize.height;
+ pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+ }
+
+ percentMouse = ( pixelMouse / pixelTotal );
+ if ( percentMouse > 1 ) {
+ percentMouse = 1;
+ }
+ if ( percentMouse < 0 ) {
+ percentMouse = 0;
+ }
+ if ( this.orientation === "vertical" ) {
+ percentMouse = 1 - percentMouse;
+ }
+
+ valueTotal = this._valueMax() - this._valueMin();
+ valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+ return this._trimAlignValue( valueMouse );
+ },
+
+ _start: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+ return this._trigger( "start", event, uiHash );
+ },
+
+ _slide: function( event, index, newVal ) {
+ var otherVal,
+ newValues,
+ allowed;
+
+ if ( this.options.values && this.options.values.length ) {
+ otherVal = this.values( index ? 0 : 1 );
+
+ if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+ ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+ ) {
+ newVal = otherVal;
+ }
+
+ if ( newVal !== this.values( index ) ) {
+ newValues = this.values();
+ newValues[ index ] = newVal;
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal,
+ values: newValues
+ } );
+ otherVal = this.values( index ? 0 : 1 );
+ if ( allowed !== false ) {
+ this.values( index, newVal, true );
+ }
+ }
+ } else {
+ if ( newVal !== this.value() ) {
+ // A slide can be canceled by returning false from the slide callback
+ allowed = this._trigger( "slide", event, {
+ handle: this.handles[ index ],
+ value: newVal
+ } );
+ if ( allowed !== false ) {
+ this.value( newVal );
+ }
+ }
+ }
+ },
+
+ _stop: function( event, index ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ this._trigger( "stop", event, uiHash );
+ },
+
+ _change: function( event, index ) {
+ if ( !this._keySliding && !this._mouseSliding ) {
+ var uiHash = {
+ handle: this.handles[ index ],
+ value: this.value()
+ };
+ if ( this.options.values && this.options.values.length ) {
+ uiHash.value = this.values( index );
+ uiHash.values = this.values();
+ }
+
+ this._trigger( "change", event, uiHash );
+ }
+ },
+
+ value: function( newValue ) {
+ if ( arguments.length ) {
+ this.options.value = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, 0 );
+ return;
+ }
+
+ return this._value();
+ },
+
+ values: function( index, newValue ) {
+ var vals,
+ newValues,
+ i;
+
+ if ( arguments.length > 1 ) {
+ this.options.values[ index ] = this._trimAlignValue( newValue );
+ this._refreshValue();
+ this._change( null, index );
+ return;
+ }
+
+ if ( arguments.length ) {
+ if ( $.isArray( arguments[ 0 ] ) ) {
+ vals = this.options.values;
+ newValues = arguments[ 0 ];
+ for ( i = 0; i < vals.length; i += 1 ) {
+ vals[ i ] = this._trimAlignValue( newValues[ i ] );
+ this._change( null, i );
+ }
+ this._refreshValue();
+ } else {
+ if ( this.options.values && this.options.values.length ) {
+ return this._values( index );
+ } else {
+ return this.value();
+ }
+ }
+ } else {
+ return this._values();
+ }
+ },
+
+ _setOption: function( key, value ) {
+ var i,
+ valsLength = 0;
+
+ if ( $.isArray( this.options.values ) ) {
+ valsLength = this.options.values.length;
+ }
+
+ $.Widget.prototype._setOption.apply( this, arguments );
+
+ switch ( key ) {
+ case "disabled":
+ if ( value ) {
+ this.handles.filter( ".ui-state-focus" ).blur();
+ this.handles.removeClass( "ui-state-hover" );
+ this.handles.propAttr( "disabled", true );
+ this.element.addClass( "ui-disabled" );
+ } else {
+ this.handles.propAttr( "disabled", false );
+ this.element.removeClass( "ui-disabled" );
+ }
+ break;
+ case "orientation":
+ this._detectOrientation();
+ this.element
+ .removeClass( "ui-slider-horizontal ui-slider-vertical" )
+ .addClass( "ui-slider-" + this.orientation );
+ this._refreshValue();
+ break;
+ case "value":
+ this._animateOff = true;
+ this._refreshValue();
+ this._change( null, 0 );
+ this._animateOff = false;
+ break;
+ case "values":
+ this._animateOff = true;
+ this._refreshValue();
+ for ( i = 0; i < valsLength; i += 1 ) {
+ this._change( null, i );
+ }
+ this._animateOff = false;
+ break;
+ }
+ },
+
+ //internal value getter
+ // _value() returns value trimmed by min and max, aligned by step
+ _value: function() {
+ var val = this.options.value;
+ val = this._trimAlignValue( val );
+
+ return val;
+ },
+
+ //internal values getter
+ // _values() returns array of values trimmed by min and max, aligned by step
+ // _values( index ) returns single value trimmed by min and max, aligned by step
+ _values: function( index ) {
+ var val,
+ vals,
+ i;
+
+ if ( arguments.length ) {
+ val = this.options.values[ index ];
+ val = this._trimAlignValue( val );
+
+ return val;
+ } else {
+ // .slice() creates a copy of the array
+ // this copy gets trimmed by min and max and then returned
+ vals = this.options.values.slice();
+ for ( i = 0; i < vals.length; i+= 1) {
+ vals[ i ] = this._trimAlignValue( vals[ i ] );
+ }
+
+ return vals;
+ }
+ },
+
+ // returns the step-aligned value that val is closest to, between (inclusive) min and max
+ _trimAlignValue: function( val ) {
+ if ( val <= this._valueMin() ) {
+ return this._valueMin();
+ }
+ if ( val >= this._valueMax() ) {
+ return this._valueMax();
+ }
+ var step = ( this.options.step > 0 ) ? this.options.step : 1,
+ valModStep = (val - this._valueMin()) % step,
+ alignValue = val - valModStep;
+
+ if ( Math.abs(valModStep) * 2 >= step ) {
+ alignValue += ( valModStep > 0 ) ? step : ( -step );
+ }
+
+ // Since JavaScript has problems with large floats, round
+ // the final value to 5 digits after the decimal point (see #4124)
+ return parseFloat( alignValue.toFixed(5) );
+ },
+
+ _valueMin: function() {
+ return this.options.min;
+ },
+
+ _valueMax: function() {
+ return this.options.max;
+ },
+
+ _refreshValue: function() {
+ var oRange = this.options.range,
+ o = this.options,
+ self = this,
+ animate = ( !this._animateOff ) ? o.animate : false,
+ valPercent,
+ _set = {},
+ lastValPercent,
+ value,
+ valueMin,
+ valueMax;
+
+ if ( this.options.values && this.options.values.length ) {
+ this.handles.each(function( i, j ) {
+ valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;
+ _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+ if ( self.options.range === true ) {
+ if ( self.orientation === "horizontal" ) {
+ if ( i === 0 ) {
+ self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ } else {
+ if ( i === 0 ) {
+ self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+ }
+ if ( i === 1 ) {
+ self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ }
+ lastValPercent = valPercent;
+ });
+ } else {
+ value = this.value();
+ valueMin = this._valueMin();
+ valueMax = this._valueMax();
+ valPercent = ( valueMax !== valueMin ) ?
+ ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+ 0;
+ _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+ this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+ if ( oRange === "min" && this.orientation === "horizontal" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "horizontal" ) {
+ this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ if ( oRange === "min" && this.orientation === "vertical" ) {
+ this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+ }
+ if ( oRange === "max" && this.orientation === "vertical" ) {
+ this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+ }
+ }
+ }
+
+});
+
+$.extend( $.ui.slider, {
+ version: "1.8.18"
+});
+
+}(jQuery));
+/*
+ * jQuery UI Tabs 1.8.18
+ *
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ * jquery.ui.core.js
+ * jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+var tabId = 0,
+ listId = 0;
+
+function getNextTabId() {
+ return ++tabId;
+}
+
+function getNextListId() {
+ return ++listId;
+}
+
+$.widget( "ui.tabs", {
+ options: {
+ add: null,
+ ajaxOptions: null,
+ cache: false,
+ cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
+ collapsible: false,
+ disable: null,
+ disabled: [],
+ enable: null,
+ event: "click",
+ fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
+ idPrefix: "ui-tabs-",
+ load: null,
+ panelTemplate: "<div></div>",
+ remove: null,
+ select: null,
+ show: null,
+ spinner: "<em>Loading&#8230;</em>",
+ tabTemplate: "<li><a href='#{href}'><span>#{label}</span></a></li>"
+ },
+
+ _create: function() {
+ this._tabify( true );
+ },
+
+ _setOption: function( key, value ) {
+ if ( key == "selected" ) {
+ if (this.options.collapsible && value == this.options.selected ) {
+ return;
+ }
+ this.select( value );
+ } else {
+ this.options[ key ] = value;
+ this._tabify();
+ }
+ },
+
+ _tabId: function( a ) {
+ return a.title && a.title.replace( /\s/g, "_" ).replace( /[^\w\u00c0-\uFFFF-]/g, "" ) ||
+ this.options.idPrefix + getNextTabId();
+ },
+
+ _sanitizeSelector: function( hash ) {
+ // we need this because an id may contain a ":"
+ return hash.replace( /:/g, "\\:" );
+ },
+
+ _cookie: function() {
+ var cookie = this.cookie ||
+ ( this.cookie = this.options.cookie.name || "ui-tabs-" + getNextListId() );
+ return $.cookie.apply( null, [ cookie ].concat( $.makeArray( arguments ) ) );
+ },
+
+ _ui: function( tab, panel ) {
+ return {
+ tab: tab,
+ panel: panel,
+ index: this.anchors.index( tab )
+ };
+ },
+
+ _cleanup: function() {
+ // restore all former loading tabs labels
+ this.lis.filter( ".ui-state-processing" )
+ .removeClass( "ui-state-processing" )
+ .find( "span:data(label.tabs)" )
+ .each(function() {
+ var el = $( this );
+ el.html( el.data( "label.tabs" ) ).removeData( "label.tabs" );
+ });
+ },
+
+ _tabify: function( init ) {
+ var self = this,
+ o = this.options,
+ fragmentId = /^#.+/; // Safari 2 reports '#' for an empty hash
+
+ this.list = this.element.find( "ol,ul" ).eq( 0 );
+ this.lis = $( " > li:has(a[href])", this.list );
+ this.anchors = this.lis.map(function() {
+ return $( "a", this )[ 0 ];
+ });
+ this.panels = $( [] );
+
+ this.anchors.each(function( i, a ) {
+ var href = $( a ).attr( "href" );
+ // For dynamically created HTML that contains a hash as href IE < 8 expands
+ // such href to the full page url with hash and then misinterprets tab as ajax.
+ // Same consideration applies for an added tab with a fragment identifier
+ // since a[href=#fragment-identifier] does unexpectedly not match.
+ // Thus normalize href attribute...
+ var hrefBase = href.split( "#" )[ 0 ],
+ baseEl;
+ if ( hrefBase && ( hrefBase === location.toString().split( "#" )[ 0 ] ||
+ ( baseEl = $( "base" )[ 0 ]) && hrefBase === baseEl.href ) ) {
+ href = a.hash;
+ a.href = href;
+ }
+
+ // inline tab
+ if ( fragmentId.test( href ) ) {
+ self.panels = self.panels.add( self.element.find( self._sanitizeSelector( href ) ) );
+ // remote tab
+ // prevent loading the page itself if href is just "#"
+ } else if ( href && href !== "#" ) {
+ // required for restore on destroy
+ $.data( a, "href.tabs", href );
+
+ // TODO until #3808 is fixed strip fragment identifier from url
+ // (IE fails to load from such url)
+ $.data( a, "load.tabs", href.replace( /#.*$/, "" ) );
+
+ var id = self._tabId( a );
+ a.href = "#" + id;
+ var $panel = self.element.find( "#" + id );
+ if ( !$panel.length ) {
+ $panel = $( o.panelTemplate )
+ .attr( "id", id )
+ .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+ .insertAfter( self.panels[ i - 1 ] || self.list );
+ $panel.data( "destroy.tabs", true );
+ }
+ self.panels = self.panels.add( $panel );
+ // invalid tab href
+ } else {
+ o.disabled.push( i );
+ }
+ });
+
+ // initialization from scratch
+ if ( init ) {
+ // attach necessary classes for styling
+ this.element.addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" );
+ this.list.addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
+ this.lis.addClass( "ui-state-default ui-corner-top" );
+ this.panels.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" );
+
+ // Selected tab
+ // use "selected" option or try to retrieve:
+ // 1. from fragment identifier in url
+ // 2. from cookie
+ // 3. from selected class attribute on <li>
+ if ( o.selected === undefined ) {
+ if ( location.hash ) {
+ this.anchors.each(function( i, a ) {
+ if ( a.hash == location.hash ) {
+ o.selected = i;
+ return false;
+ }
+ });
+ }
+ if ( typeof o.selected !== "number" && o.cookie ) {
+ o.selected = parseInt( self._cookie(), 10 );
+ }
+ if ( typeof o.selected !== "number" && this.lis.filter( ".ui-tabs-selected" ).length ) {
+ o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
+ }
+ o.selected = o.selected || ( this.lis.length ? 0 : -1 );
+ } else if ( o.selected === null ) { // usage of null is deprecated, TODO remove in next release
+ o.selected = -1;
+ }
+
+ // sanity check - default to first tab...
+ o.selected = ( ( o.selected >= 0 && this.anchors[ o.selected ] ) || o.selected < 0 )
+ ? o.selected
+ : 0;
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ // A selected tab cannot become disabled.
+ o.disabled = $.unique( o.disabled.concat(
+ $.map( this.lis.filter( ".ui-state-disabled" ), function( n, i ) {
+ return self.lis.index( n );
+ })
+ ) ).sort();
+
+ if ( $.inArray( o.selected, o.disabled ) != -1 ) {
+ o.disabled.splice( $.inArray( o.selected, o.disabled ), 1 );
+ }
+
+ // highlight selected tab
+ this.panels.addClass( "ui-tabs-hide" );
+ this.lis.removeClass( "ui-tabs-selected ui-state-active" );
+ // check for length avoids error when initializing empty list
+ if ( o.selected >= 0 && this.anchors.length ) {
+ self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) ).removeClass( "ui-tabs-hide" );
+ this.lis.eq( o.selected ).addClass( "ui-tabs-selected ui-state-active" );
+
+ // seems to be expected behavior that the show callback is fired
+ self.element.queue( "tabs", function() {
+ self._trigger( "show", null,
+ self._ui( self.anchors[ o.selected ], self.element.find( self._sanitizeSelector( self.anchors[ o.selected ].hash ) )[ 0 ] ) );
+ });
+
+ this.load( o.selected );
+ }
+
+ // clean up to avoid memory leaks in certain versions of IE 6
+ // TODO: namespace this event
+ $( window ).bind( "unload", function() {
+ self.lis.add( self.anchors ).unbind( ".tabs" );
+ self.lis = self.anchors = self.panels = null;
+ });
+ // update selected after add/remove
+ } else {
+ o.selected = this.lis.index( this.lis.filter( ".ui-tabs-selected" ) );
+ }
+
+ // update collapsible
+ // TODO: use .toggleClass()
+ this.element[ o.collapsible ? "addClass" : "removeClass" ]( "ui-tabs-collapsible" );
+
+ // set or update cookie after init and add/remove respectively
+ if ( o.cookie ) {
+ this._cookie( o.selected, o.cookie );
+ }
+
+ // disable tabs
+ for ( var i = 0, li; ( li = this.lis[ i ] ); i++ ) {
+ $( li )[ $.inArray( i, o.disabled ) != -1 &&
+ // TODO: use .toggleClass()
+ !$( li ).hasClass( "ui-tabs-selected" ) ? "addClass" : "removeClass" ]( "ui-state-disabled" );
+ }
+
+ // reset cache if switching from cached to not cached
+ if ( o.cache === false ) {
+ this.anchors.removeData( "cache.tabs" );
+ }
+
+ // remove all handlers before, tabify may run on existing tabs after add or option change
+ this.lis.add( this.anchors ).unbind( ".tabs" );
+
+ if ( o.event !== "mouseover" ) {
+ var addState = function( state, el ) {
+ if ( el.is( ":not(.ui-state-disabled)" ) ) {
+ el.addClass( "ui-state-" + state );
+ }
+ };
+ var removeState = function( state, el ) {
+ el.removeClass( "ui-state-" + state );
+ };
+ this.lis.bind( "mouseover.tabs" , function() {
+ addState( "hover", $( this ) );
+ });
+ this.lis.bind( "mouseout.tabs", function() {
+ removeState( "hover", $( this ) );
+ });
+ this.anchors.bind( "focus.tabs", function() {
+ addState( "focus", $( this ).closest( "li" ) );
+ });
+ this.anchors.bind( "blur.tabs", function() {
+ removeState( "focus", $( this ).closest( "li" ) );
+ });
+ }
+
+ // set up animations
+ var hideFx, showFx;
+ if ( o.fx ) {
+ if ( $.isArray( o.fx ) ) {
+ hideFx = o.fx[ 0 ];
+ showFx = o.fx[ 1 ];
+ } else {
+ hideFx = showFx = o.fx;
+ }
+ }
+
+ // Reset certain styles left over from animation
+ // and prevent IE's ClearType bug...
+ function resetStyle( $el, fx ) {
+ $el.css( "display", "" );
+ if ( !$.support.opacity && fx.opacity ) {
+ $el[ 0 ].style.removeAttribute( "filter" );
+ }
+ }
+
+ // Show a tab...
+ var showTab = showFx
+ ? function( clicked, $show ) {
+ $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
+ $show.hide().removeClass( "ui-tabs-hide" ) // avoid flicker that way
+ .animate( showFx, showFx.duration || "normal", function() {
+ resetStyle( $show, showFx );
+ self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
+ });
+ }
+ : function( clicked, $show ) {
+ $( clicked ).closest( "li" ).addClass( "ui-tabs-selected ui-state-active" );
+ $show.removeClass( "ui-tabs-hide" );
+ self._trigger( "show", null, self._ui( clicked, $show[ 0 ] ) );
+ };
+
+ // Hide a tab, $show is optional...
+ var hideTab = hideFx
+ ? function( clicked, $hide ) {
+ $hide.animate( hideFx, hideFx.duration || "normal", function() {
+ self.lis.removeClass( "ui-tabs-selected ui-state-active" );
+ $hide.addClass( "ui-tabs-hide" );
+ resetStyle( $hide, hideFx );
+ self.element.dequeue( "tabs" );
+ });
+ }
+ : function( clicked, $hide, $show ) {
+ self.lis.removeClass( "ui-tabs-selected ui-state-active" );
+ $hide.addClass( "ui-tabs-hide" );
+ self.element.dequeue( "tabs" );
+ };
+
+ // attach tab event handler, unbind to avoid duplicates from former tabifying...
+ this.anchors.bind( o.event + ".tabs", function() {
+ var el = this,
+ $li = $(el).closest( "li" ),
+ $hide = self.panels.filter( ":not(.ui-tabs-hide)" ),
+ $show = self.element.find( self._sanitizeSelector( el.hash ) );
+
+ // If tab is already selected and not collapsible or tab disabled or
+ // or is already loading or click callback returns false stop here.
+ // Check if click handler returns false last so that it is not executed
+ // for a disabled or loading tab!
+ if ( ( $li.hasClass( "ui-tabs-selected" ) && !o.collapsible) ||
+ $li.hasClass( "ui-state-disabled" ) ||
+ $li.hasClass( "ui-state-processing" ) ||
+ self.panels.filter( ":animated" ).length ||
+ self._trigger( "select", null, self._ui( this, $show[ 0 ] ) ) === false ) {
+ this.blur();
+ return false;
+ }
+
+ o.selected = self.anchors.index( this );
+
+ self.abort();
+
+ // if tab may be closed
+ if ( o.collapsible ) {
+ if ( $li.hasClass( "ui-tabs-selected" ) ) {
+ o.selected = -1;
+
+ if ( o.cookie ) {
+ self._cookie( o.selected, o.cookie );
+ }
+
+ self.element.queue( "tabs", function() {
+ hideTab( el, $hide );
+ }).dequeue( "tabs" );
+
+ this.blur();
+ return false;
+ } else if ( !$hide.length ) {
+ if ( o.cookie ) {
+ self._cookie( o.selected, o.cookie );
+ }
+
+ self.element.queue( "tabs", function() {
+ showTab( el, $show );
+ });
+
+ // TODO make passing in node possible, see also http://dev.jqueryui.com/ticket/3171
+ self.load( self.anchors.index( this ) );
+
+ this.blur();
+ return false;
+ }
+ }
+
+ if ( o.cookie ) {
+ self._cookie( o.selected, o.cookie );
+ }
+
+ // show new tab
+ if ( $show.length ) {
+ if ( $hide.length ) {
+ self.element.queue( "tabs", function() {
+ hideTab( el, $hide );
+ });
+ }
+ self.element.queue( "tabs", function() {
+ showTab( el, $show );
+ });
+
+ self.load( self.anchors.index( this ) );
+ } else {
+ throw "jQuery UI Tabs: Mismatching fragment identifier.";
+ }
+
+ // Prevent IE from keeping other link focussed when using the back button
+ // and remove dotted border from clicked link. This is controlled via CSS
+ // in modern browsers; blur() removes focus from address bar in Firefox
+ // which can become a usability and annoying problem with tabs('rotate').
+ if ( $.browser.msie ) {
+ this.blur();
+ }
+ });
+
+ // disable click in any case
+ this.anchors.bind( "click.tabs", function(){
+ return false;
+ });
+ },
+
+ _getIndex: function( index ) {
+ // meta-function to give users option to provide a href string instead of a numerical index.
+ // also sanitizes numerical indexes to valid values.
+ if ( typeof index == "string" ) {
+ index = this.anchors.index( this.anchors.filter( "[href$=" + index + "]" ) );
+ }
+
+ return index;
+ },
+
+ destroy: function() {
+ var o = this.options;
+
+ this.abort();
+
+ this.element
+ .unbind( ".tabs" )
+ .removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" )
+ .removeData( "tabs" );
+
+ this.list.removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" );
+
+ this.anchors.each(function() {
+ var href = $.data( this, "href.tabs" );
+ if ( href ) {
+ this.href = href;
+ }
+ var $this = $( this ).unbind( ".tabs" );
+ $.each( [ "href", "load", "cache" ], function( i, prefix ) {
+ $this.removeData( prefix + ".tabs" );
+ });
+ });
+
+ this.lis.unbind( ".tabs" ).add( this.panels ).each(function() {
+ if ( $.data( this, "destroy.tabs" ) ) {
+ $( this ).remove();
+ } else {
+ $( this ).removeClass([
+ "ui-state-default",
+ "ui-corner-top",
+ "ui-tabs-selected",
+ "ui-state-active",
+ "ui-state-hover",
+ "ui-state-focus",
+ "ui-state-disabled",
+ "ui-tabs-panel",
+ "ui-widget-content",
+ "ui-corner-bottom",
+ "ui-tabs-hide"
+ ].join( " " ) );
+ }
+ });
+
+ if ( o.cookie ) {
+ this._cookie( null, o.cookie );
+ }
+
+ return this;
+ },
+
+ add: function( url, label, index ) {
+ if ( index === undefined ) {
+ index = this.anchors.length;
+ }
+
+ var self = this,
+ o = this.options,
+ $li = $( o.tabTemplate.replace( /#\{href\}/g, url ).replace( /#\{label\}/g, label ) ),
+ id = !url.indexOf( "#" ) ? url.replace( "#", "" ) : this._tabId( $( "a", $li )[ 0 ] );
+
+ $li.addClass( "ui-state-default ui-corner-top" ).data( "destroy.tabs", true );
+
+ // try to find an existing element before creating a new one
+ var $panel = self.element.find( "#" + id );
+ if ( !$panel.length ) {
+ $panel = $( o.panelTemplate )
+ .attr( "id", id )
+ .data( "destroy.tabs", true );
+ }
+ $panel.addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide" );
+
+ if ( index >= this.lis.length ) {
+ $li.appendTo( this.list );
+ $panel.appendTo( this.list[ 0 ].parentNode );
+ } else {
+ $li.insertBefore( this.lis[ index ] );
+ $panel.insertBefore( this.panels[ index ] );
+ }
+
+ o.disabled = $.map( o.disabled, function( n, i ) {
+ return n >= index ? ++n : n;
+ });
+
+ this._tabify();
+
+ if ( this.anchors.length == 1 ) {
+ o.selected = 0;
+ $li.addClass( "ui-tabs-selected ui-state-active" );
+ $panel.removeClass( "ui-tabs-hide" );
+ this.element.queue( "tabs", function() {
+ self._trigger( "show", null, self._ui( self.anchors[ 0 ], self.panels[ 0 ] ) );
+ });
+
+ this.load( 0 );
+ }
+
+ this._trigger( "add", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
+ return this;
+ },
+
+ remove: function( index ) {
+ index = this._getIndex( index );
+ var o = this.options,
+ $li = this.lis.eq( index ).remove(),
+ $panel = this.panels.eq( index ).remove();
+
+ // If selected tab was removed focus tab to the right or
+ // in case the last tab was removed the tab to the left.
+ if ( $li.hasClass( "ui-tabs-selected" ) && this.anchors.length > 1) {
+ this.select( index + ( index + 1 < this.anchors.length ? 1 : -1 ) );
+ }
+
+ o.disabled = $.map(
+ $.grep( o.disabled, function(n, i) {
+ return n != index;
+ }),
+ function( n, i ) {
+ return n >= index ? --n : n;
+ });
+
+ this._tabify();
+
+ this._trigger( "remove", null, this._ui( $li.find( "a" )[ 0 ], $panel[ 0 ] ) );
+ return this;
+ },
+
+ enable: function( index ) {
+ index = this._getIndex( index );
+ var o = this.options;
+ if ( $.inArray( index, o.disabled ) == -1 ) {
+ return;
+ }
+
+ this.lis.eq( index ).removeClass( "ui-state-disabled" );
+ o.disabled = $.grep( o.disabled, function( n, i ) {
+ return n != index;
+ });
+
+ this._trigger( "enable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
+ return this;
+ },
+
+ disable: function( index ) {
+ index = this._getIndex( index );
+ var self = this, o = this.options;
+ // cannot disable already selected tab
+ if ( index != o.selected ) {
+ this.lis.eq( index ).addClass( "ui-state-disabled" );
+
+ o.disabled.push( index );
+ o.disabled.sort();
+
+ this._trigger( "disable", null, this._ui( this.anchors[ index ], this.panels[ index ] ) );
+ }
+
+ return this;
+ },
+
+ select: function( index ) {
+ index = this._getIndex( index );
+ if ( index == -1 ) {
+ if ( this.options.collapsible && this.options.selected != -1 ) {
+ index = this.options.selected;
+ } else {
+ return this;
+ }
+ }
+ this.anchors.eq( index ).trigger( this.options.event + ".tabs" );
+ return this;
+ },
+
+ load: function( index ) {
+ index = this._getIndex( index );
+ var self = this,
+ o = this.options,
+ a = this.anchors.eq( index )[ 0 ],
+ url = $.data( a, "load.tabs" );
+
+ this.abort();
+
+ // not remote or from cache
+ if ( !url || this.element.queue( "tabs" ).length !== 0 && $.data( a, "cache.tabs" ) ) {
+ this.element.dequeue( "tabs" );
+ return;
+ }
+
+ // load remote from here on
+ this.lis.eq( index ).addClass( "ui-state-processing" );
+
+ if ( o.spinner ) {
+ var span = $( "span", a );
+ span.data( "label.tabs", span.html() ).html( o.spinner );
+ }
+
+ this.xhr = $.ajax( $.extend( {}, o.ajaxOptions, {
+ url: url,
+ success: function( r, s ) {
+ self.element.find( self._sanitizeSelector( a.hash ) ).html( r );
+
+ // take care of tab labels
+ self._cleanup();
+
+ if ( o.cache ) {
+ $.data( a, "cache.tabs", true );
+ }
+
+ self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
+ try {
+ o.ajaxOptions.success( r, s );
+ }
+ catch ( e ) {}
+ },
+ error: function( xhr, s, e ) {
+ // take care of tab labels
+ self._cleanup();
+
+ self._trigger( "load", null, self._ui( self.anchors[ index ], self.panels[ index ] ) );
+ try {
+ // Passing index avoid a race condition when this method is
+ // called after the user has selected another tab.
+ // Pass the anchor that initiated this request allows
+ // loadError to manipulate the tab content panel via $(a.hash)
+ o.ajaxOptions.error( xhr, s, index, a );
+ }
+ catch ( e ) {}
+ }
+ } ) );
+
+ // last, so that load event is fired before show...
+ self.element.dequeue( "tabs" );
+
+ return this;
+ },
+
+ abort: function() {
+ // stop possibly running animations
+ this.element.queue( [] );
+ this.panels.stop( false, true );
+
+ // "tabs" queue must not contain more than two elements,
+ // which are the callbacks for the latest clicked tab...
+ this.element.queue( "tabs", this.element.queue( "tabs" ).splice( -2, 2 ) );
+
+ // terminate pending requests from other tabs
+ if ( this.xhr ) {
+ this.xhr.abort();
+ delete this.xhr;
+ }
+
+ // take care of tab labels
+ this._cleanup();
+ return this;
+ },
+
+ url: function( index, url ) {
+ this.anchors.eq( index ).removeData( "cache.tabs" ).data( "load.tabs", url );
+ return this;
+ },
+
+ length: function() {
+ return this.anchors.length;
+ }
+});
+
+$.extend( $.ui.tabs, {
+ version: "1.8.18"
+});
+
+/*
+ * Tabs Extensions
+ */
+
+/*
+ * Rotate
+ */
+$.extend( $.ui.tabs.prototype, {
+ rotation: null,
+ rotate: function( ms, continuing ) {
+ var self = this,
+ o = this.options;
+
+ var rotate = self._rotate || ( self._rotate = function( e ) {
+ clearTimeout( self.rotation );
+ self.rotation = setTimeout(function() {
+ var t = o.selected;
+ self.select( ++t < self.anchors.length ? t : 0 );
+ }, ms );
+
+ if ( e ) {
+ e.stopPropagation();
+ }
+ });
+
+ var stop = self._unrotate || ( self._unrotate = !continuing
+ ? function(e) {
+ if (e.clientX) { // in case of a true click
+ self.rotate(null);
+ }
+ }
+ : function( e ) {
+ t = o.selected;
+ rotate();
+ });
+
+ // start rotation
+ if ( ms ) {
+ this.element.bind( "tabsshow", rotate );
+ this.anchors.bind( o.event + ".tabs", stop );
+ rotate();
+ // stop rotation
+ } else {
+ clearTimeout( self.rotation );
+ this.element.unbind( "tabsshow", rotate );
+ this.anchors.unbind( o.event + ".tabs", stop );
+ delete this._rotate;
+ delete this._unrotate;
+ }
+
+ return this;
+ }
+});
+
+})( jQuery );
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/init-db.sh b/storage/mroonga/vendor/groonga/examples/dictionary/init-db.sh
new file mode 100755
index 00000000..351d90e7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/init-db.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+if [ 1 != $# ]; then
+ echo "usage: $0 db_path"
+ exit 1
+fi
+
+if groonga-suggest-create-dataset $1 dictionary > /dev/null; then
+ echo "db initialized."
+fi
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/jmdict/Makefile.am b/storage/mroonga/vendor/groonga/examples/dictionary/jmdict/Makefile.am
new file mode 100644
index 00000000..70b4a5bc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/jmdict/Makefile.am
@@ -0,0 +1,3 @@
+jmdictdir = $(examples_dictionarydir)/jmdict
+dist_jmdict_SCRIPTS = \
+ jmdict.rb
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/jmdict/jmdict.rb b/storage/mroonga/vendor/groonga/examples/dictionary/jmdict/jmdict.rb
new file mode 100755
index 00000000..bf892678
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/jmdict/jmdict.rb
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+
+require 'rexml/document'
+require 'rexml/parsers/streamparser'
+require 'rexml/parsers/baseparser'
+require 'rexml/streamlistener'
+
+#REXML::Document.new(STDIN)
+
+class MyListener
+ include REXML::StreamListener
+ def tag_start(name, attrs)
+ # p name, attrs
+ case name
+ when 'entry'
+ @n = 0
+ end
+ end
+ def tag_end name
+ # p "tag_end: #{x}"
+ case name
+ when 'sense'
+ @n += 1
+ when 'entry'
+ @n_ents += 1
+ puts "#{@ent}:#{@n}" if (@n > 8)
+ when 'ent_seq'
+ @ent = @text
+ end
+ end
+
+ def text(text)
+ @text = text
+ end
+
+ def xmldecl(version, encoding, standalone)
+ @n_ents = 0
+ end
+end
+
+REXML::Parsers::StreamParser.new(STDIN, MyListener.new).parse
diff --git a/storage/mroonga/vendor/groonga/examples/dictionary/readme.txt b/storage/mroonga/vendor/groonga/examples/dictionary/readme.txt
new file mode 100644
index 00000000..555706e0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/examples/dictionary/readme.txt
@@ -0,0 +1,71 @@
+.. highlightlang:: none
+
+辞書検索ツール
+==============
+
+名前
+----
+
+groonga辞書検索ツール
+
+説明
+----
+
+様々な商用・非商用の辞書ファイルをインポートしてgroongaで検索できるようにします。
+
+対応している辞書
+++++++++++++++++
+
+現状では下記の辞書に対応しています。
+
+* EDICT
+
+EDICTは、Monash大学Jim Breen教授が提供している和英辞書です。下記から入手できます。
+
+http://ftp.monash.edu.au/pub/nihongo/edict.gz
+
+* GENE95
+
+GENE95は、Kurumiさん(NiftyID: GGD00145)が作成された英和辞書です。下記から入手できます。
+
+http://www.namazu.org/~tsuchiya/sdic/data/gene95.tar.gz
+
+* 英辞郎
+
+英辞郎は、EDPという団体によって編纂されている英和・和英辞書です。
+
+http://www.eijiro.jp/
+
+書店やオンラインショップなどで購入できます。
+
+データベースの初期化
+++++++++++++++++++++
+
+本ディレクトリで下記のように実行し、辞書データを格納するデータベースファイルを下記のようにして初期化します。
+
+ ./init-db.sh データベースパス名
+
+このようにして作成したデータベースについて、様々な辞書のデータをインポートすることができます。
+
+インポートの方法
+++++++++++++++++
+
+* EDICT
+
+edictディレクトリ配下で以下のように実行します。 edict.gzは自動でダウンロードします。
+
+ ./edict-import.sh データベースパス名
+
+* GENE95
+
+gene95ディレクトリ配下で下記のように実行します。 gene95.tar.gzは自動でダウンロードします。
+
+ ./gene-import.sh データベースパス名
+
+* 英辞郎
+
+英辞郎に付属のPDICツールを用いてCSVファイル形式に辞書をエクスポートします。(このとき「登録項目」ですべての項目を出力するようにします) eijiroディレクトリ配下で下記のように実行します。
+
+ ./eijiro-import.sh データベースパス名 出力したCSVファイルのパス名
+
+(英辞郎第四版で動作を確認しています)
diff --git a/storage/mroonga/vendor/groonga/gpg_uid b/storage/mroonga/vendor/groonga/gpg_uid
new file mode 100644
index 00000000..7c1a800b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/gpg_uid
@@ -0,0 +1 @@
+45499429
diff --git a/storage/mroonga/vendor/groonga/groonga-arrow.pc.in b/storage/mroonga/vendor/groonga/groonga-arrow.pc.in
new file mode 100644
index 00000000..d0b22f65
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/groonga-arrow.pc.in
@@ -0,0 +1,4 @@
+Name: Groonga Arrow
+Description: Apache Arrow support for Groonga
+Version: @VERSION@
+Requires: groonga arrow
diff --git a/storage/mroonga/vendor/groonga/groonga-httpd-conf.sh.in b/storage/mroonga/vendor/groonga/groonga-httpd-conf.sh.in
new file mode 100644
index 00000000..4dbb400f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/groonga-httpd-conf.sh.in
@@ -0,0 +1,34 @@
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+sbindir="@sbindir@"
+libdir="@libdir@"
+sysconfdir="@sysconfdir@"
+pkgsysconfdir="@pkgsysconfdir@"
+localstatedir="@localstatedir@"
+
+EXEEXT="@EXEEXT@"
+
+SED="@SED@"
+
+export GROONGA_HTTPD_MODULE_PATH="@abs_top_srcdir@/src/httpd/nginx-module"
+export GROONGA_HTTPD_IN_TREE_INCLUDE_PATH="@abs_top_srcdir@/include"
+export GROONGA_HTTPD_IN_TREE_LINK_PATH="@abs_top_builddir@/lib/.libs"
+export GROONGA_HTTPD_PREFIX="${pkgsysconfdir}/httpd"
+export GROONGA_HTTPD_BIN_PATH="${sbindir}/groonga-httpd${EXEEXT}"
+export GROONGA_HTTPD_CONF_PATH="${pkgsysconfdir}/httpd/groonga-httpd.conf"
+export GROONGA_HTTPD_ERROR_LOG_PATH="${localstatedir}/log/groonga/httpd/error.log"
+export GROONGA_HTTPD_HTTP_LOG_PATH="${localstatedir}/log/groonga/httpd/access.log"
+export GROONGA_HTTPD_GROONGA_LOG_PATH="${localstatedir}/log/groonga/httpd/groonga.log"
+export GROONGA_HTTPD_GROONGA_QUERY_LOG_PATH="${localstatedir}/log/groonga/httpd/groonga-query.log"
+export GROONGA_HTTPD_PID_PATH="@GROONGA_HTTPD_PID_PATH@"
+export GROONGA_HTTPD_DEBUG="@grn_debug@"
+export GROONGA_HTTPD_WITH_PCRE="@GRN_WITH_PCRE@"
+export GROONGA_HTTPD_PCRE_CFLAGS="@PCRE_CFLAGS@"
+export GROONGA_HTTPD_PCRE_LIBS_ONLY_L="@PCRE_LIBS_ONLY_L@"
+export GROONGA_HTTPD_WITH_ONIGMO="@GRN_WITH_ONIGMO@"
+export GROONGA_HTTPD_ONIGMO_IN_TREE_LINK_PATH="@abs_top_builddir@/vendor/onigmo-source/.libs"
+export GROONGA_HTTPD_WITH_ZLIB="@GRN_WITH_ZLIB@"
+export GROONGA_HTTPD_WITH_SSL="@GRN_WITH_SSL@"
+export GROONGA_HTTPD_SSL_CFLAGS="@SSL_CFLAGS@"
+export GROONGA_HTTPD_SSL_LIBS_ONLY_L="@SSL_LIBS_ONLY_L@"
+export GROONGA_HTTPD_WITH_MRUBY="@GRN_WITH_MRUBY@"
diff --git a/storage/mroonga/vendor/groonga/groonga.pc.in b/storage/mroonga/vendor/groonga/groonga.pc.in
new file mode 100644
index 00000000..869285d4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/groonga.pc.in
@@ -0,0 +1,20 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+document_root=@GRN_EXPANDED_DEFAULT_DOCUMENT_ROOT@
+pluginsdir=@expanded_pluginsdir@
+groonga=${bindir}/groonga@EXEEXT@
+groonga_httpd=${sbindir}/groonga-httpd@EXEEXT@
+groonga_suggest_create_dataset=${bindir}/groonga-suggest-create-dataset@EXEEXT@
+groonga_version=@GRN_VERSION@
+
+Name: Groonga
+Description: An Embeddable Fulltext Search Engine
+Version: @VERSION@
+Libs: -L${libdir} -lgroonga
+Cflags: -I${includedir}/groonga
diff --git a/storage/mroonga/vendor/groonga/include/CMakeLists.txt b/storage/mroonga/vendor/groonga/include/CMakeLists.txt
new file mode 100644
index 00000000..791395f7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/CMakeLists.txt
@@ -0,0 +1,18 @@
+# Copyright(C) 2012 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+install(FILES groonga.h DESTINATION "${GRN_INCLUDE_DIR}")
+install(DIRECTORY groonga DESTINATION "${GRN_INCLUDE_DIR}"
+ FILES_MATCHING PATTERN "*.h")
diff --git a/storage/mroonga/vendor/groonga/include/Makefile.am b/storage/mroonga/vendor/groonga/include/Makefile.am
new file mode 100644
index 00000000..c7dee710
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = groonga
+
+pkginclude_HEADERS = \
+ groonga.h \
+ groonga.hpp
+
+EXTRA_DIST = \
+ CMakeLists.txt
diff --git a/storage/mroonga/vendor/groonga/include/groonga.h b/storage/mroonga/vendor/groonga/include/groonga.h
new file mode 100644
index 00000000..4476eb1e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga.h
@@ -0,0 +1,53 @@
+/*
+ Copyright(C) 2014-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "groonga/portability.h"
+#include "groonga/groonga.h"
+
+#include "groonga/accessor.h"
+#include "groonga/array.h"
+#include "groonga/arrow.h"
+#include "groonga/cache.h"
+#include "groonga/column.h"
+#include "groonga/config.h"
+#include "groonga/dat.h"
+#include "groonga/db.h"
+#include "groonga/dump.h"
+#include "groonga/error.h"
+#include "groonga/expr.h"
+#include "groonga/file_reader.h"
+#include "groonga/geo.h"
+#include "groonga/hash.h"
+#include "groonga/id.h"
+#include "groonga/ii.h"
+#include "groonga/obj.h"
+#include "groonga/operator.h"
+#include "groonga/output.h"
+#include "groonga/pat.h"
+#include "groonga/request_canceler.h"
+#include "groonga/request_timer.h"
+#include "groonga/table.h"
+#include "groonga/thread.h"
+#include "groonga/time.h"
+#include "groonga/type.h"
+#include "groonga/util.h"
+#include "groonga/window_function.h"
+#include "groonga/windows.h"
+#include "groonga/windows_event_logger.h"
diff --git a/storage/mroonga/vendor/groonga/include/groonga.hpp b/storage/mroonga/vendor/groonga/include/groonga.hpp
new file mode 100644
index 00000000..010ea41b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga.hpp
@@ -0,0 +1,21 @@
+/*
+ Copyright(C) 2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "groonga.h"
diff --git a/storage/mroonga/vendor/groonga/include/groonga/Makefile.am b/storage/mroonga/vendor/groonga/include/groonga/Makefile.am
new file mode 100644
index 00000000..7cc4d56e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/Makefile.am
@@ -0,0 +1,43 @@
+groonga_includedir = $(pkgincludedir)/groonga
+groonga_include_HEADERS = \
+ accessor.h \
+ array.h \
+ arrow.h \
+ arrow.hpp \
+ cache.h \
+ column.h \
+ command.h \
+ config.h \
+ dat.h \
+ db.h \
+ dump.h \
+ error.h \
+ expr.h \
+ file_reader.h \
+ hash.h \
+ geo.h \
+ groonga.h \
+ id.h \
+ ii.h \
+ obj.h \
+ operator.h \
+ output.h \
+ pat.h \
+ plugin.h \
+ portability.h \
+ request_canceler.h \
+ request_timer.h \
+ scorer.h \
+ table.h \
+ thread.h \
+ time.h \
+ token.h \
+ tokenizer.h \
+ token_filter.h \
+ type.h \
+ nfkc.h \
+ normalizer.h \
+ util.h \
+ window_function.h \
+ windows.h \
+ windows_event_logger.h
diff --git a/storage/mroonga/vendor/groonga/include/groonga/accessor.h b/storage/mroonga/vendor/groonga/include/groonga/accessor.h
new file mode 100644
index 00000000..4fc062c5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/accessor.h
@@ -0,0 +1,34 @@
+/*
+ Copyright(C) 2012-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_rc grn_accessor_resolve(grn_ctx *ctx,
+ grn_obj *accessor,
+ int deep,
+ grn_obj *base_res,
+ grn_obj *res,
+ grn_operator op);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/array.h b/storage/mroonga/vendor/groonga/include/groonga/array.h
new file mode 100644
index 00000000..c16ef216
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/array.h
@@ -0,0 +1,89 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_array grn_array;
+typedef struct _grn_array_cursor grn_array_cursor;
+
+GRN_API grn_array *grn_array_create(grn_ctx *ctx, const char *path,
+ unsigned int value_size, unsigned int flags);
+GRN_API grn_array *grn_array_open(grn_ctx *ctx, const char *path);
+GRN_API grn_rc grn_array_close(grn_ctx *ctx, grn_array *array);
+GRN_API grn_id grn_array_add(grn_ctx *ctx, grn_array *array, void **value);
+GRN_API grn_id grn_array_push(grn_ctx *ctx, grn_array *array,
+ void (*func)(grn_ctx *ctx, grn_array *array,
+ grn_id id, void *func_arg),
+ void *func_arg);
+GRN_API grn_id grn_array_pull(grn_ctx *ctx, grn_array *array, grn_bool blockp,
+ void (*func)(grn_ctx *ctx, grn_array *array,
+ grn_id id, void *func_arg),
+ void *func_arg);
+GRN_API void grn_array_unblock(grn_ctx *ctx, grn_array *array);
+GRN_API int grn_array_get_value(grn_ctx *ctx, grn_array *array, grn_id id, void *valuebuf);
+GRN_API grn_rc grn_array_set_value(grn_ctx *ctx, grn_array *array, grn_id id,
+ const void *value, int flags);
+GRN_API grn_array_cursor *grn_array_cursor_open(grn_ctx *ctx, grn_array *array,
+ grn_id min, grn_id max,
+ int offset, int limit, int flags);
+GRN_API grn_id grn_array_cursor_next(grn_ctx *ctx, grn_array_cursor *cursor);
+GRN_API int grn_array_cursor_get_value(grn_ctx *ctx, grn_array_cursor *cursor, void **value);
+GRN_API grn_rc grn_array_cursor_set_value(grn_ctx *ctx, grn_array_cursor *cursor,
+ const void *value, int flags);
+GRN_API grn_rc grn_array_cursor_delete(grn_ctx *ctx, grn_array_cursor *cursor,
+ grn_table_delete_optarg *optarg);
+GRN_API void grn_array_cursor_close(grn_ctx *ctx, grn_array_cursor *cursor);
+GRN_API grn_rc grn_array_delete_by_id(grn_ctx *ctx, grn_array *array, grn_id id,
+ grn_table_delete_optarg *optarg);
+
+GRN_API grn_id grn_array_next(grn_ctx *ctx, grn_array *array, grn_id id);
+
+GRN_API void *_grn_array_get_value(grn_ctx *ctx, grn_array *array, grn_id id);
+
+#define GRN_ARRAY_EACH(ctx,array,head,tail,id,value,block) do {\
+ grn_array_cursor *_sc = grn_array_cursor_open(ctx, array, head, tail, 0, -1, 0); \
+ if (_sc) {\
+ grn_id id;\
+ while ((id = grn_array_cursor_next(ctx, _sc))) {\
+ grn_array_cursor_get_value(ctx, _sc, (void **)(value));\
+ block\
+ }\
+ grn_array_cursor_close(ctx, _sc); \
+ }\
+} while (0)
+
+#define GRN_ARRAY_EACH_BEGIN(ctx, array, cursor, head, tail, id) do {\
+ grn_array_cursor *cursor;\
+ cursor = grn_array_cursor_open((ctx), (array), (head), (tail), 0, -1, 0);\
+ if (cursor) {\
+ grn_id id;\
+ while ((id = grn_array_cursor_next(ctx, cursor))) {
+
+#define GRN_ARRAY_EACH_END(ctx, cursor)\
+ }\
+ grn_array_cursor_close(ctx, cursor);\
+ }\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/arrow.h b/storage/mroonga/vendor/groonga/include/groonga/arrow.h
new file mode 100644
index 00000000..82e945cc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/arrow.h
@@ -0,0 +1,38 @@
+/*
+ Copyright(C) 2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_rc grn_arrow_load(grn_ctx *ctx,
+ grn_obj *table,
+ const char *path);
+GRN_API grn_rc grn_arrow_dump(grn_ctx *ctx,
+ grn_obj *table,
+ const char *path);
+GRN_API grn_rc grn_arrow_dump_columns(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *columns,
+ const char *path);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/arrow.hpp b/storage/mroonga/vendor/groonga/include/groonga/arrow.hpp
new file mode 100644
index 00000000..0b434d39
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/arrow.hpp
@@ -0,0 +1,21 @@
+/*
+ Copyright(C) 2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <groonga.hpp>
diff --git a/storage/mroonga/vendor/groonga/include/groonga/cache.h b/storage/mroonga/vendor/groonga/include/groonga/cache.h
new file mode 100644
index 00000000..68325e52
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/cache.h
@@ -0,0 +1,49 @@
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_CACHE_DEFAULT_MAX_N_ENTRIES 100
+typedef struct _grn_cache grn_cache;
+
+GRN_API void grn_set_default_cache_base_path(const char *base_path);
+GRN_API const char *grn_get_default_cache_base_path(void);
+
+GRN_API grn_cache *grn_cache_open(grn_ctx *ctx);
+GRN_API grn_cache *grn_persistent_cache_open(grn_ctx *ctx,
+ const char *base_path);
+GRN_API grn_rc grn_cache_close(grn_ctx *ctx, grn_cache *cache);
+
+GRN_API grn_rc grn_cache_current_set(grn_ctx *ctx, grn_cache *cache);
+GRN_API grn_cache *grn_cache_current_get(grn_ctx *ctx);
+
+GRN_API grn_rc grn_cache_default_reopen(void);
+
+GRN_API grn_rc grn_cache_set_max_n_entries(grn_ctx *ctx,
+ grn_cache *cache,
+ unsigned int n);
+GRN_API unsigned int grn_cache_get_max_n_entries(grn_ctx *ctx,
+ grn_cache *cache);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/column.h b/storage/mroonga/vendor/groonga/include/groonga/column.h
new file mode 100644
index 00000000..6eacc89e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/column.h
@@ -0,0 +1,29 @@
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_column_flags grn_column_get_flags(grn_ctx *ctx, grn_obj *column);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/command.h b/storage/mroonga/vendor/groonga/include/groonga/command.h
new file mode 100644
index 00000000..cccb6a97
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/command.h
@@ -0,0 +1,79 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <groonga/plugin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _grn_command_input grn_command_input;
+
+GRN_PLUGIN_EXPORT grn_command_input *grn_command_input_open(grn_ctx *ctx,
+ grn_obj *command);
+GRN_PLUGIN_EXPORT grn_rc grn_command_input_close(grn_ctx *ctx,
+ grn_command_input *input);
+
+GRN_PLUGIN_EXPORT grn_obj *grn_command_input_add(grn_ctx *ctx,
+ grn_command_input *input,
+ const char *name,
+ int name_size,
+ grn_bool *added);
+GRN_PLUGIN_EXPORT grn_obj *grn_command_input_get(grn_ctx *ctx,
+ grn_command_input *input,
+ const char *name,
+ int name_size);
+GRN_PLUGIN_EXPORT grn_obj *grn_command_input_at(grn_ctx *ctx,
+ grn_command_input *input,
+ unsigned int offset);
+GRN_PLUGIN_EXPORT grn_obj *grn_command_input_get_arguments(grn_ctx *ctx,
+ grn_command_input *input);
+
+typedef void grn_command_run_func(grn_ctx *ctx,
+ grn_obj *command,
+ grn_command_input *input,
+ void *user_data);
+
+/*
+ grn_command_register() registers a command to the database which is
+ associated with `ctx'. `command_name' and `command_name_size'
+ specify the command name. Alphabetic letters ('A'-'Z' and 'a'-'z'),
+ digits ('0'-'9') and an underscore ('_') are capable characters.
+
+ `run' is called for running the command.
+
+ grn_command_register() returns GRN_SUCCESS on success, an error
+ code on failure.
+ */
+GRN_PLUGIN_EXPORT grn_rc grn_command_register(grn_ctx *ctx,
+ const char *command_name,
+ int command_name_size,
+ grn_command_run_func *run,
+ grn_expr_var *vars,
+ unsigned int n_vars,
+ void *user_data);
+
+GRN_PLUGIN_EXPORT grn_rc grn_command_run(grn_ctx *ctx,
+ grn_obj *command,
+ grn_command_input *input);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/config.h b/storage/mroonga/vendor/groonga/include/groonga/config.h
new file mode 100644
index 00000000..bf4b9419
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/config.h
@@ -0,0 +1,65 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_CONFIG_MAX_KEY_SIZE GRN_TABLE_MAX_KEY_SIZE
+#define GRN_CONFIG_MAX_VALUE_SIZE \
+ (GRN_CONFIG_VALUE_SPACE_SIZE - sizeof(uint32_t) - 1) /* 1 is for '\0' */
+#define GRN_CONFIG_VALUE_SPACE_SIZE (4 * 1024)
+
+GRN_API grn_rc grn_config_set(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char *value, int32_t value_size);
+GRN_API grn_rc grn_config_get(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char **value, uint32_t *value_size);
+
+
+GRN_API grn_rc grn_config_delete(grn_ctx *ctx,
+ const char *key, int32_t key_size);
+
+GRN_API grn_obj *grn_config_cursor_open(grn_ctx *ctx);
+GRN_API grn_bool grn_config_cursor_next(grn_ctx *ctx, grn_obj *cursor);
+GRN_API uint32_t grn_config_cursor_get_key(grn_ctx *ctx,
+ grn_obj *cursor,
+ const char **key);
+GRN_API uint32_t grn_config_cursor_get_value(grn_ctx *ctx,
+ grn_obj *cursor,
+ const char **value);
+
+/* Deprecated since 5.1.2. Use GRN_CONFIG_* instead. */
+
+#define GRN_CONF_MAX_KEY_SIZE GRN_CONFIG_MAX_KEY_SIZE
+#define GRN_CONF_MAX_VALUE_SIZE GRN_CONFIG_MAX_VALUE_SIZE
+#define GRN_CONF_VALUE_SPACE_SIZE GRN_CONFIG_VALUE_SPACE_SIZE
+
+GRN_API grn_rc grn_conf_set(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char *value, int32_t value_size);
+GRN_API grn_rc grn_conf_get(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char **value, uint32_t *value_size);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/dat.h b/storage/mroonga/vendor/groonga/include/groonga/dat.h
new file mode 100644
index 00000000..e30df402
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/dat.h
@@ -0,0 +1,100 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_dat grn_dat;
+typedef struct _grn_dat_cursor grn_dat_cursor;
+typedef struct _grn_table_scan_hit grn_dat_scan_hit;
+
+GRN_API int grn_dat_scan(grn_ctx *ctx, grn_dat *dat, const char *str,
+ unsigned int str_size, grn_dat_scan_hit *scan_hits,
+ unsigned int max_num_scan_hits, const char **str_rest);
+
+GRN_API grn_id grn_dat_lcp_search(grn_ctx *ctx, grn_dat *dat,
+ const void *key, unsigned int key_size);
+
+GRN_API grn_dat *grn_dat_create(grn_ctx *ctx, const char *path, unsigned int key_size,
+ unsigned int value_size, unsigned int flags);
+
+GRN_API grn_dat *grn_dat_open(grn_ctx *ctx, const char *path);
+
+GRN_API grn_rc grn_dat_close(grn_ctx *ctx, grn_dat *dat);
+
+GRN_API grn_rc grn_dat_remove(grn_ctx *ctx, const char *path);
+
+GRN_API grn_id grn_dat_get(grn_ctx *ctx, grn_dat *dat, const void *key,
+ unsigned int key_size, void **value);
+GRN_API grn_id grn_dat_add(grn_ctx *ctx, grn_dat *dat, const void *key,
+ unsigned int key_size, void **value, int *added);
+
+GRN_API int grn_dat_get_key(grn_ctx *ctx, grn_dat *dat, grn_id id, void *keybuf, int bufsize);
+GRN_API int grn_dat_get_key2(grn_ctx *ctx, grn_dat *dat, grn_id id, grn_obj *bulk);
+
+GRN_API grn_rc grn_dat_delete_by_id(grn_ctx *ctx, grn_dat *dat, grn_id id,
+ grn_table_delete_optarg *optarg);
+GRN_API grn_rc grn_dat_delete(grn_ctx *ctx, grn_dat *dat, const void *key, unsigned int key_size,
+ grn_table_delete_optarg *optarg);
+
+GRN_API grn_rc grn_dat_update_by_id(grn_ctx *ctx, grn_dat *dat, grn_id src_key_id,
+ const void *dest_key, unsigned int dest_key_size);
+GRN_API grn_rc grn_dat_update(grn_ctx *ctx, grn_dat *dat,
+ const void *src_key, unsigned int src_key_size,
+ const void *dest_key, unsigned int dest_key_size);
+
+GRN_API unsigned int grn_dat_size(grn_ctx *ctx, grn_dat *dat);
+
+GRN_API grn_dat_cursor *grn_dat_cursor_open(grn_ctx *ctx, grn_dat *dat,
+ const void *min, unsigned int min_size,
+ const void *max, unsigned int max_size,
+ int offset, int limit, int flags);
+GRN_API grn_id grn_dat_cursor_next(grn_ctx *ctx, grn_dat_cursor *c);
+GRN_API void grn_dat_cursor_close(grn_ctx *ctx, grn_dat_cursor *c);
+
+GRN_API int grn_dat_cursor_get_key(grn_ctx *ctx, grn_dat_cursor *c, const void **key);
+GRN_API grn_rc grn_dat_cursor_delete(grn_ctx *ctx, grn_dat_cursor *c,
+ grn_table_delete_optarg *optarg);
+
+#define GRN_DAT_EACH(ctx,dat,id,key,key_size,block) do {\
+ grn_dat_cursor *_sc = grn_dat_cursor_open(ctx, dat, NULL, 0, NULL, 0, 0, -1, 0);\
+ if (_sc) {\
+ grn_id id;\
+ unsigned int *_ks = (key_size);\
+ if (_ks) {\
+ while ((id = grn_dat_cursor_next(ctx, _sc))) {\
+ int _ks_raw = grn_dat_cursor_get_key(ctx, _sc, (const void **)(key));\
+ *(_ks) = (unsigned int)_ks_raw;\
+ block\
+ }\
+ } else {\
+ while ((id = grn_dat_cursor_next(ctx, _sc))) {\
+ grn_dat_cursor_get_key(ctx, _sc, (const void **)(key));\
+ block\
+ }\
+ }\
+ grn_dat_cursor_close(ctx, _sc);\
+ }\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/db.h b/storage/mroonga/vendor/groonga/include/groonga/db.h
new file mode 100644
index 00000000..e4217b4f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/db.h
@@ -0,0 +1,68 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_db_create_optarg grn_db_create_optarg;
+
+struct _grn_db_create_optarg {
+ char **builtin_type_names;
+ int n_builtin_type_names;
+};
+
+GRN_API grn_obj *grn_db_create(grn_ctx *ctx, const char *path, grn_db_create_optarg *optarg);
+
+#define GRN_DB_OPEN_OR_CREATE(ctx,path,optarg,db) \
+ (((db) = grn_db_open((ctx), (path))) || (db = grn_db_create((ctx), (path), (optarg))))
+
+GRN_API grn_obj *grn_db_open(grn_ctx *ctx, const char *path);
+GRN_API void grn_db_touch(grn_ctx *ctx, grn_obj *db);
+GRN_API grn_rc grn_db_recover(grn_ctx *ctx, grn_obj *db);
+GRN_API grn_rc grn_db_unmap(grn_ctx *ctx, grn_obj *db);
+GRN_API uint32_t grn_db_get_last_modified(grn_ctx *ctx, grn_obj *db);
+GRN_API grn_bool grn_db_is_dirty(grn_ctx *ctx, grn_obj *db);
+
+#define GRN_DB_EACH_BEGIN_FLAGS(ctx, cursor, id, flags) \
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, \
+ grn_ctx_db((ctx)), \
+ cursor, \
+ id, \
+ flags)
+
+#define GRN_DB_EACH_BEGIN_BY_ID(ctx, cursor, id) \
+ GRN_DB_EACH_BEGIN_FLAGS(ctx, \
+ cursor, \
+ id, \
+ GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING)
+
+#define GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) \
+ GRN_DB_EACH_BEGIN_FLAGS(ctx, \
+ cursor, \
+ id, \
+ GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING)
+
+#define GRN_DB_EACH_END(ctx, cursor) \
+ GRN_TABLE_EACH_END(ctx, cursor)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/dump.h b/storage/mroonga/vendor/groonga/include/groonga/dump.h
new file mode 100644
index 00000000..6c673ea9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/dump.h
@@ -0,0 +1,34 @@
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_rc grn_dump_table_create_flags(grn_ctx *ctx,
+ grn_table_flags flags,
+ grn_obj *buffer);
+GRN_API grn_rc grn_dump_column_create_flags(grn_ctx *ctx,
+ grn_column_flags flags,
+ grn_obj *buffer);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/error.h b/storage/mroonga/vendor/groonga/include/groonga/error.h
new file mode 100644
index 00000000..a63a52b6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/error.h
@@ -0,0 +1,29 @@
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API const char *grn_rc_to_string(grn_rc rc);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/expr.h b/storage/mroonga/vendor/groonga/include/groonga/expr.h
new file mode 100644
index 00000000..8090bc78
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/expr.h
@@ -0,0 +1,123 @@
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef unsigned int grn_expr_flags;
+
+#define GRN_EXPR_SYNTAX_QUERY (0x00)
+#define GRN_EXPR_SYNTAX_SCRIPT (0x01)
+#define GRN_EXPR_SYNTAX_OUTPUT_COLUMNS (0x20)
+#define GRN_EXPR_SYNTAX_ADJUSTER (0x40)
+#define GRN_EXPR_ALLOW_PRAGMA (0x02)
+#define GRN_EXPR_ALLOW_COLUMN (0x04)
+#define GRN_EXPR_ALLOW_UPDATE (0x08)
+#define GRN_EXPR_ALLOW_LEADING_NOT (0x10)
+#define GRN_EXPR_QUERY_NO_SYNTAX_ERROR (0x80)
+
+GRN_API grn_obj *grn_expr_create(grn_ctx *ctx, const char *name, unsigned int name_size);
+GRN_API grn_rc grn_expr_close(grn_ctx *ctx, grn_obj *expr);
+GRN_API grn_obj *grn_expr_add_var(grn_ctx *ctx, grn_obj *expr,
+ const char *name, unsigned int name_size);
+GRN_API grn_obj *grn_expr_get_var(grn_ctx *ctx, grn_obj *expr,
+ const char *name, unsigned int name_size);
+GRN_API grn_obj *grn_expr_get_var_by_offset(grn_ctx *ctx, grn_obj *expr, unsigned int offset);
+GRN_API grn_rc grn_expr_clear_vars(grn_ctx *ctx, grn_obj *expr);
+
+GRN_API void grn_expr_take_obj(grn_ctx *ctx, grn_obj *expr, grn_obj *obj);
+
+GRN_API grn_obj *grn_expr_append_obj(grn_ctx *ctx, grn_obj *expr, grn_obj *obj,
+ grn_operator op, int nargs);
+GRN_API grn_obj *grn_expr_append_const(grn_ctx *ctx, grn_obj *expr, grn_obj *obj,
+ grn_operator op, int nargs);
+GRN_API grn_obj *grn_expr_append_const_str(grn_ctx *ctx, grn_obj *expr,
+ const char *str, unsigned int str_size,
+ grn_operator op, int nargs);
+GRN_API grn_obj *grn_expr_append_const_int(grn_ctx *ctx, grn_obj *expr, int i,
+ grn_operator op, int nargs);
+GRN_API grn_rc grn_expr_append_op(grn_ctx *ctx, grn_obj *expr, grn_operator op, int nargs);
+
+GRN_API grn_rc grn_expr_get_keywords(grn_ctx *ctx, grn_obj *expr, grn_obj *keywords);
+
+GRN_API grn_rc grn_expr_syntax_escape(grn_ctx *ctx,
+ const char *query, int query_size,
+ const char *target_characters,
+ char escape_character,
+ grn_obj *escaped_query);
+GRN_API grn_rc grn_expr_syntax_escape_query(grn_ctx *ctx,
+ const char *query, int query_size,
+ grn_obj *escaped_query);
+GRN_API grn_rc grn_expr_syntax_expand_query(grn_ctx *ctx,
+ const char *query, int query_size,
+ grn_expr_flags flags,
+ grn_obj *expander,
+ grn_obj *expanded_query);
+GRN_API grn_rc grn_expr_syntax_expand_query_by_table(grn_ctx *ctx,
+ const char *query,
+ int query_size,
+ grn_expr_flags flags,
+ grn_obj *term_column,
+ grn_obj *expanded_term_column,
+ grn_obj *expanded_query);
+
+GRN_API grn_rc grn_expr_compile(grn_ctx *ctx, grn_obj *expr);
+GRN_API grn_obj *grn_expr_rewrite(grn_ctx *ctx, grn_obj *expr);
+GRN_API grn_rc grn_expr_dump_plan(grn_ctx *ctx, grn_obj *expr, grn_obj *buffer);
+GRN_API grn_obj *grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs);
+
+GRN_API grn_obj *grn_expr_alloc(grn_ctx *ctx, grn_obj *expr,
+ grn_id domain, unsigned char flags);
+
+#define GRN_EXPR_CREATE_FOR_QUERY(ctx,table,expr,var) do {\
+ if (((expr) = grn_expr_create((ctx), NULL, 0)) &&\
+ ((var) = grn_expr_add_var((ctx), (expr), NULL, 0))) {\
+ GRN_RECORD_INIT((var), 0, grn_obj_id((ctx), (table)));\
+ } else {\
+ (var) = NULL;\
+ }\
+} while (0)
+
+GRN_API grn_rc grn_expr_parse(grn_ctx *ctx, grn_obj *expr,
+ const char *str, unsigned int str_size,
+ grn_obj *default_column, grn_operator default_mode,
+ grn_operator default_op, grn_expr_flags flags);
+
+GRN_API grn_obj *grn_expr_snip(grn_ctx *ctx, grn_obj *expr, int flags,
+ unsigned int width, unsigned int max_results,
+ unsigned int n_tags,
+ const char **opentags, unsigned int *opentag_lens,
+ const char **closetags, unsigned int *closetag_lens,
+ grn_snip_mapping *mapping);
+GRN_API grn_rc grn_expr_snip_add_conditions(grn_ctx *ctx,
+ grn_obj *expr,
+ grn_obj *snip,
+ unsigned int n_tags,
+ const char **opentags,
+ unsigned int *opentag_lens,
+ const char **closetags,
+ unsigned int *closetag_lens);
+
+GRN_API unsigned int grn_expr_estimate_size(grn_ctx *ctx, grn_obj *expr);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/file_reader.h b/storage/mroonga/vendor/groonga/include/groonga/file_reader.h
new file mode 100644
index 00000000..4b3fee70
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/file_reader.h
@@ -0,0 +1,37 @@
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_file_reader grn_file_reader;
+
+GRN_API grn_file_reader *grn_file_reader_open(grn_ctx *ctx, const char *path);
+GRN_API void grn_file_reader_close(grn_ctx *ctx,
+ grn_file_reader *reader);
+
+GRN_API grn_rc grn_file_reader_read_line(grn_ctx *ctx,
+ grn_file_reader *reader,
+ grn_obj *buffer);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/geo.h b/storage/mroonga/vendor/groonga/include/groonga/geo.h
new file mode 100644
index 00000000..d1049350
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/geo.h
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API int grn_geo_table_sort(grn_ctx *ctx,
+ grn_obj *table,
+ int offset,
+ int limit,
+ grn_obj *result,
+ grn_obj *column,
+ grn_obj *geo_point);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/groonga.h b/storage/mroonga/vendor/groonga/include/groonga/groonga.h
new file mode 100644
index 00000000..0e465152
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/groonga.h
@@ -0,0 +1,1700 @@
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <stdarg.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GRN_API
+# if defined(_WIN32) || defined(_WIN64)
+# define GRN_API __declspec(dllimport)
+# else
+# define GRN_API
+# endif /* defined(_WIN32) || defined(_WIN64) */
+#endif /* GRN_API */
+
+typedef unsigned int grn_id;
+typedef uint8_t grn_bool;
+
+#define GRN_ID_NIL (0x00)
+#define GRN_ID_MAX (0x3fffffff)
+
+#define GRN_TRUE (1)
+#define GRN_FALSE (0)
+
+typedef enum {
+ GRN_SUCCESS = 0,
+ GRN_END_OF_DATA = 1,
+ GRN_UNKNOWN_ERROR = -1,
+ GRN_OPERATION_NOT_PERMITTED = -2,
+ GRN_NO_SUCH_FILE_OR_DIRECTORY = -3,
+ GRN_NO_SUCH_PROCESS = -4,
+ GRN_INTERRUPTED_FUNCTION_CALL = -5,
+ GRN_INPUT_OUTPUT_ERROR = -6,
+ GRN_NO_SUCH_DEVICE_OR_ADDRESS = -7,
+ GRN_ARG_LIST_TOO_LONG = -8,
+ GRN_EXEC_FORMAT_ERROR = -9,
+ GRN_BAD_FILE_DESCRIPTOR = -10,
+ GRN_NO_CHILD_PROCESSES = -11,
+ GRN_RESOURCE_TEMPORARILY_UNAVAILABLE = -12,
+ GRN_NOT_ENOUGH_SPACE = -13,
+ GRN_PERMISSION_DENIED = -14,
+ GRN_BAD_ADDRESS = -15,
+ GRN_RESOURCE_BUSY = -16,
+ GRN_FILE_EXISTS = -17,
+ GRN_IMPROPER_LINK = -18,
+ GRN_NO_SUCH_DEVICE = -19,
+ GRN_NOT_A_DIRECTORY = -20,
+ GRN_IS_A_DIRECTORY = -21,
+ GRN_INVALID_ARGUMENT = -22,
+ GRN_TOO_MANY_OPEN_FILES_IN_SYSTEM = -23,
+ GRN_TOO_MANY_OPEN_FILES = -24,
+ GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION = -25,
+ GRN_FILE_TOO_LARGE = -26,
+ GRN_NO_SPACE_LEFT_ON_DEVICE = -27,
+ GRN_INVALID_SEEK = -28,
+ GRN_READ_ONLY_FILE_SYSTEM = -29,
+ GRN_TOO_MANY_LINKS = -30,
+ GRN_BROKEN_PIPE = -31,
+ GRN_DOMAIN_ERROR = -32,
+ GRN_RESULT_TOO_LARGE = -33,
+ GRN_RESOURCE_DEADLOCK_AVOIDED = -34,
+ GRN_NO_MEMORY_AVAILABLE = -35,
+ GRN_FILENAME_TOO_LONG = -36,
+ GRN_NO_LOCKS_AVAILABLE = -37,
+ GRN_FUNCTION_NOT_IMPLEMENTED = -38,
+ GRN_DIRECTORY_NOT_EMPTY = -39,
+ GRN_ILLEGAL_BYTE_SEQUENCE = -40,
+ GRN_SOCKET_NOT_INITIALIZED = -41,
+ GRN_OPERATION_WOULD_BLOCK = -42,
+ GRN_ADDRESS_IS_NOT_AVAILABLE = -43,
+ GRN_NETWORK_IS_DOWN = -44,
+ GRN_NO_BUFFER = -45,
+ GRN_SOCKET_IS_ALREADY_CONNECTED = -46,
+ GRN_SOCKET_IS_NOT_CONNECTED = -47,
+ GRN_SOCKET_IS_ALREADY_SHUTDOWNED = -48,
+ GRN_OPERATION_TIMEOUT = -49,
+ GRN_CONNECTION_REFUSED = -50,
+ GRN_RANGE_ERROR = -51,
+ GRN_TOKENIZER_ERROR = -52,
+ GRN_FILE_CORRUPT = -53,
+ GRN_INVALID_FORMAT = -54,
+ GRN_OBJECT_CORRUPT = -55,
+ GRN_TOO_MANY_SYMBOLIC_LINKS = -56,
+ GRN_NOT_SOCKET = -57,
+ GRN_OPERATION_NOT_SUPPORTED = -58,
+ GRN_ADDRESS_IS_IN_USE = -59,
+ GRN_ZLIB_ERROR = -60,
+ GRN_LZ4_ERROR = -61,
+/* Just for backward compatibility. We'll remove it at 5.0.0. */
+#define GRN_LZO_ERROR GRN_LZ4_ERROR
+ GRN_STACK_OVER_FLOW = -62,
+ GRN_SYNTAX_ERROR = -63,
+ GRN_RETRY_MAX = -64,
+ GRN_INCOMPATIBLE_FILE_FORMAT = -65,
+ GRN_UPDATE_NOT_ALLOWED = -66,
+ GRN_TOO_SMALL_OFFSET = -67,
+ GRN_TOO_LARGE_OFFSET = -68,
+ GRN_TOO_SMALL_LIMIT = -69,
+ GRN_CAS_ERROR = -70,
+ GRN_UNSUPPORTED_COMMAND_VERSION = -71,
+ GRN_NORMALIZER_ERROR = -72,
+ GRN_TOKEN_FILTER_ERROR = -73,
+ GRN_COMMAND_ERROR = -74,
+ GRN_PLUGIN_ERROR = -75,
+ GRN_SCORER_ERROR = -76,
+ GRN_CANCEL = -77,
+ GRN_WINDOW_FUNCTION_ERROR = -78,
+ GRN_ZSTD_ERROR = -79
+} grn_rc;
+
+GRN_API grn_rc grn_init(void);
+GRN_API grn_rc grn_fin(void);
+
+GRN_API const char *grn_get_global_error_message(void);
+
+typedef enum {
+ GRN_ENC_DEFAULT = 0,
+ GRN_ENC_NONE,
+ GRN_ENC_EUC_JP,
+ GRN_ENC_UTF8,
+ GRN_ENC_SJIS,
+ GRN_ENC_LATIN1,
+ GRN_ENC_KOI8R
+} grn_encoding;
+
+typedef enum {
+ GRN_COMMAND_VERSION_DEFAULT = 0,
+ GRN_COMMAND_VERSION_1,
+ GRN_COMMAND_VERSION_2,
+ GRN_COMMAND_VERSION_3
+} grn_command_version;
+
+#define GRN_COMMAND_VERSION_MIN GRN_COMMAND_VERSION_1
+#define GRN_COMMAND_VERSION_STABLE GRN_COMMAND_VERSION_1
+#define GRN_COMMAND_VERSION_MAX GRN_COMMAND_VERSION_3
+
+typedef enum {
+ GRN_LOG_NONE = 0,
+ GRN_LOG_EMERG,
+ GRN_LOG_ALERT,
+ GRN_LOG_CRIT,
+ GRN_LOG_ERROR,
+ GRN_LOG_WARNING,
+ GRN_LOG_NOTICE,
+ GRN_LOG_INFO,
+ GRN_LOG_DEBUG,
+ GRN_LOG_DUMP
+} grn_log_level;
+
+GRN_API const char *grn_log_level_to_string(grn_log_level level);
+GRN_API grn_bool grn_log_level_parse(const char *string, grn_log_level *level);
+
+/* query log flags */
+#define GRN_QUERY_LOG_NONE (0x00)
+#define GRN_QUERY_LOG_COMMAND (0x01<<0)
+#define GRN_QUERY_LOG_RESULT_CODE (0x01<<1)
+#define GRN_QUERY_LOG_DESTINATION (0x01<<2)
+#define GRN_QUERY_LOG_CACHE (0x01<<3)
+#define GRN_QUERY_LOG_SIZE (0x01<<4)
+#define GRN_QUERY_LOG_SCORE (0x01<<5)
+#define GRN_QUERY_LOG_ALL\
+ (GRN_QUERY_LOG_COMMAND |\
+ GRN_QUERY_LOG_RESULT_CODE |\
+ GRN_QUERY_LOG_DESTINATION |\
+ GRN_QUERY_LOG_CACHE |\
+ GRN_QUERY_LOG_SIZE |\
+ GRN_QUERY_LOG_SCORE)
+#define GRN_QUERY_LOG_DEFAULT GRN_QUERY_LOG_ALL
+
+typedef enum {
+ GRN_CONTENT_NONE = 0,
+ GRN_CONTENT_TSV,
+ GRN_CONTENT_JSON,
+ GRN_CONTENT_XML,
+ GRN_CONTENT_MSGPACK,
+ GRN_CONTENT_GROONGA_COMMAND_LIST
+} grn_content_type;
+
+typedef struct _grn_obj grn_obj;
+typedef struct _grn_ctx grn_ctx;
+
+#define GRN_CTX_MSGSIZE (0x80)
+#define GRN_CTX_FIN (0xff)
+
+typedef union {
+ int int_value;
+ grn_id id;
+ void *ptr;
+} grn_user_data;
+
+typedef grn_obj *grn_proc_func(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data);
+
+struct _grn_ctx {
+ grn_rc rc;
+ int flags;
+ grn_encoding encoding;
+ unsigned char ntrace;
+ unsigned char errlvl;
+ unsigned char stat;
+ unsigned int seqno;
+ unsigned int subno;
+ unsigned int seqno2;
+ unsigned int errline;
+ grn_user_data user_data;
+ grn_ctx *prev;
+ grn_ctx *next;
+ const char *errfile;
+ const char *errfunc;
+ struct _grn_ctx_impl *impl;
+ void *trace[16];
+ char errbuf[GRN_CTX_MSGSIZE];
+};
+
+#define GRN_CTX_USER_DATA(ctx) (&((ctx)->user_data))
+
+/* Deprecated since 4.0.3. Don't use it. */
+#define GRN_CTX_USE_QL (0x03)
+/* Deprecated since 4.0.3. Don't use it. */
+#define GRN_CTX_BATCH_MODE (0x04)
+#define GRN_CTX_PER_DB (0x08)
+
+GRN_API grn_rc grn_ctx_init(grn_ctx *ctx, int flags);
+GRN_API grn_rc grn_ctx_fin(grn_ctx *ctx);
+GRN_API grn_ctx *grn_ctx_open(int flags);
+GRN_API grn_rc grn_ctx_close(grn_ctx *ctx);
+GRN_API grn_rc grn_ctx_set_finalizer(grn_ctx *ctx, grn_proc_func *func);
+
+GRN_API grn_rc grn_ctx_push_temporary_open_space(grn_ctx *ctx);
+GRN_API grn_rc grn_ctx_pop_temporary_open_space(grn_ctx *ctx);
+GRN_API grn_rc grn_ctx_merge_temporary_open_space(grn_ctx *ctx);
+
+GRN_API grn_encoding grn_get_default_encoding(void);
+GRN_API grn_rc grn_set_default_encoding(grn_encoding encoding);
+
+#define GRN_CTX_GET_ENCODING(ctx) ((ctx)->encoding)
+#define GRN_CTX_SET_ENCODING(ctx,enc) \
+ ((ctx)->encoding = (enc == GRN_ENC_DEFAULT) ? grn_get_default_encoding() : enc)
+
+GRN_API const char *grn_get_version(void);
+GRN_API const char *grn_get_package(void);
+GRN_API const char *grn_get_package_label(void);
+
+GRN_API grn_command_version grn_get_default_command_version(void);
+GRN_API grn_rc grn_set_default_command_version(grn_command_version version);
+GRN_API grn_command_version grn_ctx_get_command_version(grn_ctx *ctx);
+GRN_API grn_rc grn_ctx_set_command_version(grn_ctx *ctx, grn_command_version version);
+GRN_API long long int grn_ctx_get_match_escalation_threshold(grn_ctx *ctx);
+GRN_API grn_rc grn_ctx_set_match_escalation_threshold(grn_ctx *ctx, long long int threshold);
+GRN_API long long int grn_get_default_match_escalation_threshold(void);
+GRN_API grn_rc grn_set_default_match_escalation_threshold(long long int threshold);
+
+GRN_API int grn_get_lock_timeout(void);
+GRN_API grn_rc grn_set_lock_timeout(int timeout);
+
+/* grn_encoding */
+
+GRN_API const char *grn_encoding_to_string(grn_encoding encoding);
+GRN_API grn_encoding grn_encoding_parse(const char *name);
+
+/* obj */
+
+typedef uint16_t grn_obj_flags;
+typedef uint32_t grn_table_flags;
+typedef uint32_t grn_column_flags;
+
+/* flags for grn_obj_flags and grn_table_flags */
+
+#define GRN_OBJ_FLAGS_MASK (0xffff)
+
+#define GRN_OBJ_TABLE_TYPE_MASK (0x07)
+#define GRN_OBJ_TABLE_HASH_KEY (0x00)
+#define GRN_OBJ_TABLE_PAT_KEY (0x01)
+#define GRN_OBJ_TABLE_DAT_KEY (0x02)
+#define GRN_OBJ_TABLE_NO_KEY (0x03)
+
+#define GRN_OBJ_KEY_MASK (0x07<<3)
+#define GRN_OBJ_KEY_UINT (0x00<<3)
+#define GRN_OBJ_KEY_INT (0x01<<3)
+#define GRN_OBJ_KEY_FLOAT (0x02<<3)
+#define GRN_OBJ_KEY_GEO_POINT (0x03<<3)
+
+#define GRN_OBJ_KEY_WITH_SIS (0x01<<6)
+#define GRN_OBJ_KEY_NORMALIZE (0x01<<7)
+
+#define GRN_OBJ_COLUMN_TYPE_MASK (0x07)
+#define GRN_OBJ_COLUMN_SCALAR (0x00)
+#define GRN_OBJ_COLUMN_VECTOR (0x01)
+#define GRN_OBJ_COLUMN_INDEX (0x02)
+
+#define GRN_OBJ_COMPRESS_MASK (0x07<<4)
+#define GRN_OBJ_COMPRESS_NONE (0x00<<4)
+#define GRN_OBJ_COMPRESS_ZLIB (0x01<<4)
+#define GRN_OBJ_COMPRESS_LZ4 (0x02<<4)
+/* Just for backward compatibility. We'll remove it at 5.0.0. */
+#define GRN_OBJ_COMPRESS_LZO GRN_OBJ_COMPRESS_LZ4
+#define GRN_OBJ_COMPRESS_ZSTD (0x03<<4)
+
+#define GRN_OBJ_WITH_SECTION (0x01<<7)
+#define GRN_OBJ_WITH_WEIGHT (0x01<<8)
+#define GRN_OBJ_WITH_POSITION (0x01<<9)
+#define GRN_OBJ_RING_BUFFER (0x01<<10)
+
+#define GRN_OBJ_UNIT_MASK (0x0f<<8)
+#define GRN_OBJ_UNIT_DOCUMENT_NONE (0x00<<8)
+#define GRN_OBJ_UNIT_DOCUMENT_SECTION (0x01<<8)
+#define GRN_OBJ_UNIT_DOCUMENT_POSITION (0x02<<8)
+#define GRN_OBJ_UNIT_SECTION_NONE (0x03<<8)
+#define GRN_OBJ_UNIT_SECTION_POSITION (0x04<<8)
+#define GRN_OBJ_UNIT_POSITION_NONE (0x05<<8)
+#define GRN_OBJ_UNIT_USERDEF_DOCUMENT (0x06<<8)
+#define GRN_OBJ_UNIT_USERDEF_SECTION (0x07<<8)
+#define GRN_OBJ_UNIT_USERDEF_POSITION (0x08<<8)
+
+/* Don't use (0x01<<12) because it's used internally. */
+
+#define GRN_OBJ_NO_SUBREC (0x00<<13)
+#define GRN_OBJ_WITH_SUBREC (0x01<<13)
+
+#define GRN_OBJ_KEY_VAR_SIZE (0x01<<14)
+
+#define GRN_OBJ_TEMPORARY (0x00<<15)
+#define GRN_OBJ_PERSISTENT (0x01<<15)
+
+/* flags only for grn_table_flags */
+
+#define GRN_OBJ_KEY_LARGE (0x01<<16)
+
+/* flags only for grn_column_flags */
+
+#define GRN_OBJ_INDEX_SMALL (0x01<<16)
+#define GRN_OBJ_INDEX_MEDIUM (0x01<<17)
+
+/* obj types */
+
+#define GRN_VOID (0x00)
+#define GRN_BULK (0x02)
+#define GRN_PTR (0x03)
+#define GRN_UVECTOR (0x04) /* vector of fixed size data especially grn_id */
+#define GRN_PVECTOR (0x05) /* vector of grn_obj* */
+#define GRN_VECTOR (0x06) /* vector of arbitrary data */
+#define GRN_MSG (0x07)
+#define GRN_QUERY (0x08)
+#define GRN_ACCESSOR (0x09)
+#define GRN_SNIP (0x0b)
+#define GRN_PATSNIP (0x0c)
+#define GRN_STRING (0x0d)
+#define GRN_CURSOR_TABLE_HASH_KEY (0x10)
+#define GRN_CURSOR_TABLE_PAT_KEY (0x11)
+#define GRN_CURSOR_TABLE_DAT_KEY (0x12)
+#define GRN_CURSOR_TABLE_NO_KEY (0x13)
+#define GRN_CURSOR_COLUMN_INDEX (0x18)
+#define GRN_CURSOR_COLUMN_GEO_INDEX (0x1a)
+#define GRN_CURSOR_CONFIG (0x1f)
+#define GRN_TYPE (0x20)
+#define GRN_PROC (0x21)
+#define GRN_EXPR (0x22)
+#define GRN_TABLE_HASH_KEY (0x30)
+#define GRN_TABLE_PAT_KEY (0x31)
+#define GRN_TABLE_DAT_KEY (0x32)
+#define GRN_TABLE_NO_KEY (0x33)
+#define GRN_DB (0x37)
+#define GRN_COLUMN_FIX_SIZE (0x40)
+#define GRN_COLUMN_VAR_SIZE (0x41)
+#define GRN_COLUMN_INDEX (0x48)
+
+typedef struct _grn_section grn_section;
+typedef struct _grn_obj_header grn_obj_header;
+
+struct _grn_section {
+ unsigned int offset;
+ unsigned int length;
+ unsigned int weight;
+ grn_id domain;
+};
+
+struct _grn_obj_header {
+ unsigned char type;
+ unsigned char impl_flags;
+ grn_obj_flags flags;
+ grn_id domain;
+};
+
+struct _grn_obj {
+ grn_obj_header header;
+ union {
+ struct {
+ char *head;
+ char *curr;
+ char *tail;
+ } b;
+ struct {
+ grn_obj *body;
+ grn_section *sections;
+ int n_sections;
+ } v;
+ } u;
+};
+
+#define GRN_OBJ_REFER (0x01<<0)
+#define GRN_OBJ_OUTPLACE (0x01<<1)
+#define GRN_OBJ_OWN (0x01<<5)
+
+#define GRN_OBJ_INIT(obj,obj_type,obj_flags,obj_domain) do { \
+ (obj)->header.type = (obj_type);\
+ (obj)->header.impl_flags = (obj_flags);\
+ (obj)->header.flags = 0;\
+ (obj)->header.domain = (obj_domain);\
+ (obj)->u.b.head = NULL;\
+ (obj)->u.b.curr = NULL;\
+ (obj)->u.b.tail = NULL;\
+} while (0)
+
+#define GRN_OBJ_FIN(ctx,obj) (grn_obj_close((ctx), (obj)))
+
+GRN_API grn_rc grn_ctx_use(grn_ctx *ctx, grn_obj *db);
+GRN_API grn_obj *grn_ctx_db(grn_ctx *ctx);
+GRN_API grn_obj *grn_ctx_get(grn_ctx *ctx, const char *name, int name_size);
+GRN_API grn_rc grn_ctx_get_all_tables(grn_ctx *ctx, grn_obj *tables_buffer);
+GRN_API grn_rc grn_ctx_get_all_types(grn_ctx *ctx, grn_obj *types_buffer);
+GRN_API grn_rc grn_ctx_get_all_tokenizers(grn_ctx *ctx,
+ grn_obj *tokenizers_buffer);
+GRN_API grn_rc grn_ctx_get_all_normalizers(grn_ctx *ctx,
+ grn_obj *normalizers_buffer);
+GRN_API grn_rc grn_ctx_get_all_token_filters(grn_ctx *ctx,
+ grn_obj *token_filters_buffer);
+
+typedef enum {
+ GRN_DB_VOID = 0,
+ GRN_DB_DB,
+ GRN_DB_OBJECT,
+ GRN_DB_BOOL,
+ GRN_DB_INT8,
+ GRN_DB_UINT8,
+ GRN_DB_INT16,
+ GRN_DB_UINT16,
+ GRN_DB_INT32,
+ GRN_DB_UINT32,
+ GRN_DB_INT64,
+ GRN_DB_UINT64,
+ GRN_DB_FLOAT,
+ GRN_DB_TIME,
+ GRN_DB_SHORT_TEXT,
+ GRN_DB_TEXT,
+ GRN_DB_LONG_TEXT,
+ GRN_DB_TOKYO_GEO_POINT,
+ GRN_DB_WGS84_GEO_POINT
+} grn_builtin_type;
+
+typedef enum {
+ GRN_DB_MECAB = 64,
+ GRN_DB_DELIMIT,
+ GRN_DB_UNIGRAM,
+ GRN_DB_BIGRAM,
+ GRN_DB_TRIGRAM
+} grn_builtin_tokenizer;
+
+GRN_API grn_obj *grn_ctx_at(grn_ctx *ctx, grn_id id);
+GRN_API grn_bool grn_ctx_is_opened(grn_ctx *ctx, grn_id id);
+
+GRN_API grn_rc grn_plugin_register(grn_ctx *ctx, const char *name);
+GRN_API grn_rc grn_plugin_unregister(grn_ctx *ctx, const char *name);
+GRN_API grn_rc grn_plugin_register_by_path(grn_ctx *ctx, const char *path);
+GRN_API grn_rc grn_plugin_unregister_by_path(grn_ctx *ctx, const char *path);
+GRN_API const char *grn_plugin_get_system_plugins_dir(void);
+GRN_API const char *grn_plugin_get_suffix(void);
+GRN_API const char *grn_plugin_get_ruby_suffix(void);
+GRN_API grn_rc grn_plugin_get_names(grn_ctx *ctx, grn_obj *names);
+
+typedef struct {
+ const char *name;
+ unsigned int name_size;
+ grn_obj value;
+} grn_expr_var;
+
+typedef grn_rc (*grn_plugin_func)(grn_ctx *ctx);
+
+typedef enum {
+ GRN_PROC_INVALID = 0,
+ GRN_PROC_TOKENIZER,
+ GRN_PROC_COMMAND,
+ GRN_PROC_FUNCTION,
+ GRN_PROC_HOOK,
+ GRN_PROC_NORMALIZER,
+ GRN_PROC_TOKEN_FILTER,
+ GRN_PROC_SCORER,
+ GRN_PROC_WINDOW_FUNCTION
+} grn_proc_type;
+
+GRN_API grn_obj *grn_proc_create(grn_ctx *ctx,
+ const char *name, int name_size, grn_proc_type type,
+ grn_proc_func *init, grn_proc_func *next, grn_proc_func *fin,
+ unsigned int nvars, grn_expr_var *vars);
+GRN_API grn_obj *grn_proc_get_info(grn_ctx *ctx, grn_user_data *user_data,
+ grn_expr_var **vars, unsigned int *nvars, grn_obj **caller);
+GRN_API grn_proc_type grn_proc_get_type(grn_ctx *ctx, grn_obj *proc);
+
+typedef grn_obj grn_table_cursor;
+
+typedef struct {
+ grn_id rid;
+ uint32_t sid;
+ uint32_t pos;
+ uint32_t tf;
+ uint32_t weight;
+ uint32_t rest;
+} grn_posting;
+
+typedef enum {
+ GRN_OP_PUSH = 0,
+ GRN_OP_POP,
+ GRN_OP_NOP,
+ GRN_OP_CALL,
+ GRN_OP_INTERN,
+ GRN_OP_GET_REF,
+ GRN_OP_GET_VALUE,
+ GRN_OP_AND,
+ GRN_OP_AND_NOT,
+ /* Deprecated. Just for backward compatibility. */
+#define GRN_OP_BUT GRN_OP_AND_NOT
+ GRN_OP_OR,
+ GRN_OP_ASSIGN,
+ GRN_OP_STAR_ASSIGN,
+ GRN_OP_SLASH_ASSIGN,
+ GRN_OP_MOD_ASSIGN,
+ GRN_OP_PLUS_ASSIGN,
+ GRN_OP_MINUS_ASSIGN,
+ GRN_OP_SHIFTL_ASSIGN,
+ GRN_OP_SHIFTR_ASSIGN,
+ GRN_OP_SHIFTRR_ASSIGN,
+ GRN_OP_AND_ASSIGN,
+ GRN_OP_XOR_ASSIGN,
+ GRN_OP_OR_ASSIGN,
+ GRN_OP_JUMP,
+ GRN_OP_CJUMP,
+ GRN_OP_COMMA,
+ GRN_OP_BITWISE_OR,
+ GRN_OP_BITWISE_XOR,
+ GRN_OP_BITWISE_AND,
+ GRN_OP_BITWISE_NOT,
+ GRN_OP_EQUAL,
+ GRN_OP_NOT_EQUAL,
+ GRN_OP_LESS,
+ GRN_OP_GREATER,
+ GRN_OP_LESS_EQUAL,
+ GRN_OP_GREATER_EQUAL,
+ GRN_OP_IN,
+ GRN_OP_MATCH,
+ GRN_OP_NEAR,
+ GRN_OP_NEAR2,
+ GRN_OP_SIMILAR,
+ GRN_OP_TERM_EXTRACT,
+ GRN_OP_SHIFTL,
+ GRN_OP_SHIFTR,
+ GRN_OP_SHIFTRR,
+ GRN_OP_PLUS,
+ GRN_OP_MINUS,
+ GRN_OP_STAR,
+ GRN_OP_SLASH,
+ GRN_OP_MOD,
+ GRN_OP_DELETE,
+ GRN_OP_INCR,
+ GRN_OP_DECR,
+ GRN_OP_INCR_POST,
+ GRN_OP_DECR_POST,
+ GRN_OP_NOT,
+ GRN_OP_ADJUST,
+ GRN_OP_EXACT,
+ GRN_OP_LCP,
+ GRN_OP_PARTIAL,
+ GRN_OP_UNSPLIT,
+ GRN_OP_PREFIX,
+ GRN_OP_SUFFIX,
+ GRN_OP_GEO_DISTANCE1,
+ GRN_OP_GEO_DISTANCE2,
+ GRN_OP_GEO_DISTANCE3,
+ GRN_OP_GEO_DISTANCE4,
+ GRN_OP_GEO_WITHINP5,
+ GRN_OP_GEO_WITHINP6,
+ GRN_OP_GEO_WITHINP8,
+ GRN_OP_OBJ_SEARCH,
+ GRN_OP_EXPR_GET_VAR,
+ GRN_OP_TABLE_CREATE,
+ GRN_OP_TABLE_SELECT,
+ GRN_OP_TABLE_SORT,
+ GRN_OP_TABLE_GROUP,
+ GRN_OP_JSON_PUT,
+ GRN_OP_GET_MEMBER,
+ GRN_OP_REGEXP,
+ GRN_OP_FUZZY
+} grn_operator;
+
+GRN_API grn_obj *grn_obj_column(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size);
+
+/*-------------------------------------------------------------
+ * API for column
+ */
+
+#define GRN_COLUMN_NAME_ID "_id"
+#define GRN_COLUMN_NAME_ID_LEN (sizeof(GRN_COLUMN_NAME_ID) - 1)
+#define GRN_COLUMN_NAME_KEY "_key"
+#define GRN_COLUMN_NAME_KEY_LEN (sizeof(GRN_COLUMN_NAME_KEY) - 1)
+#define GRN_COLUMN_NAME_VALUE "_value"
+#define GRN_COLUMN_NAME_VALUE_LEN (sizeof(GRN_COLUMN_NAME_VALUE) - 1)
+#define GRN_COLUMN_NAME_SCORE "_score"
+#define GRN_COLUMN_NAME_SCORE_LEN (sizeof(GRN_COLUMN_NAME_SCORE) - 1)
+#define GRN_COLUMN_NAME_NSUBRECS "_nsubrecs"
+#define GRN_COLUMN_NAME_NSUBRECS_LEN (sizeof(GRN_COLUMN_NAME_NSUBRECS) - 1)
+#define GRN_COLUMN_NAME_MAX "_max"
+#define GRN_COLUMN_NAME_MAX_LEN (sizeof(GRN_COLUMN_NAME_MAX) - 1)
+#define GRN_COLUMN_NAME_MIN "_min"
+#define GRN_COLUMN_NAME_MIN_LEN (sizeof(GRN_COLUMN_NAME_MIN) - 1)
+#define GRN_COLUMN_NAME_SUM "_sum"
+#define GRN_COLUMN_NAME_SUM_LEN (sizeof(GRN_COLUMN_NAME_SUM) - 1)
+#define GRN_COLUMN_NAME_AVG "_avg"
+#define GRN_COLUMN_NAME_AVG_LEN (sizeof(GRN_COLUMN_NAME_AVG) - 1)
+
+GRN_API grn_obj *grn_column_create(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size,
+ const char *path, grn_column_flags flags, grn_obj *type);
+
+#define GRN_COLUMN_OPEN_OR_CREATE(ctx,table,name,name_size,path,flags,type,column) \
+ (((column) = grn_obj_column((ctx), (table), (name), (name_size))) ||\
+ ((column) = grn_column_create((ctx), (table), (name), (name_size), (path), (flags), (type))))
+
+GRN_API grn_rc grn_column_index_update(grn_ctx *ctx, grn_obj *column,
+ grn_id id, unsigned int section,
+ grn_obj *oldvalue, grn_obj *newvalue);
+GRN_API grn_obj *grn_column_table(grn_ctx *ctx, grn_obj *column);
+GRN_API grn_rc grn_column_truncate(grn_ctx *ctx, grn_obj *column);
+
+/*-------------------------------------------------------------
+ * API for db, table and/or column
+ */
+
+typedef enum {
+ GRN_INFO_ENCODING = 0,
+ GRN_INFO_SOURCE,
+ GRN_INFO_DEFAULT_TOKENIZER,
+ GRN_INFO_ELEMENT_SIZE,
+ GRN_INFO_CURR_MAX,
+ GRN_INFO_MAX_ELEMENT_SIZE,
+ GRN_INFO_SEG_SIZE,
+ GRN_INFO_CHUNK_SIZE,
+ GRN_INFO_MAX_SECTION,
+ GRN_INFO_HOOK_LOCAL_DATA,
+ GRN_INFO_ELEMENT_A,
+ GRN_INFO_ELEMENT_CHUNK,
+ GRN_INFO_ELEMENT_CHUNK_SIZE,
+ GRN_INFO_ELEMENT_BUFFER_FREE,
+ GRN_INFO_ELEMENT_NTERMS,
+ GRN_INFO_ELEMENT_NTERMS_VOID,
+ GRN_INFO_ELEMENT_SIZE_IN_CHUNK,
+ GRN_INFO_ELEMENT_POS_IN_CHUNK,
+ GRN_INFO_ELEMENT_SIZE_IN_BUFFER,
+ GRN_INFO_ELEMENT_POS_IN_BUFFER,
+ GRN_INFO_ELEMENT_ESTIMATE_SIZE,
+ GRN_INFO_NGRAM_UNIT_SIZE,
+ /*
+ GRN_INFO_VERSION,
+ GRN_INFO_CONFIGURE_OPTIONS,
+ GRN_INFO_CONFIG_PATH,
+ */
+ GRN_INFO_PARTIAL_MATCH_THRESHOLD,
+ GRN_INFO_II_SPLIT_THRESHOLD,
+ GRN_INFO_SUPPORT_ZLIB,
+ GRN_INFO_SUPPORT_LZ4,
+/* Just for backward compatibility. We'll remove it at 5.0.0. */
+#define GRN_INFO_SUPPORT_LZO GRN_INFO_SUPPORT_LZ4
+ GRN_INFO_NORMALIZER,
+ GRN_INFO_TOKEN_FILTERS,
+ GRN_INFO_SUPPORT_ZSTD,
+ GRN_INFO_SUPPORT_ARROW
+} grn_info_type;
+
+GRN_API grn_obj *grn_obj_get_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *valuebuf);
+GRN_API grn_rc grn_obj_set_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *value);
+GRN_API grn_obj *grn_obj_get_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_info_type type, grn_obj *value);
+GRN_API grn_rc grn_obj_set_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_info_type type, grn_obj *value);
+
+GRN_API grn_obj *grn_obj_get_value(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value);
+GRN_API int grn_obj_get_values(grn_ctx *ctx, grn_obj *obj, grn_id offset, void **values);
+
+#define GRN_COLUMN_EACH(ctx,column,id,value,block) do {\
+ int _n;\
+ grn_id id = 1;\
+ while ((_n = grn_obj_get_values(ctx, column, id, (void **)&value)) > 0) {\
+ for (; _n; _n--, id++, value++) {\
+ block\
+ }\
+ }\
+} while (0)
+
+#define GRN_OBJ_SET_MASK (0x07)
+#define GRN_OBJ_SET (0x01)
+#define GRN_OBJ_INCR (0x02)
+#define GRN_OBJ_DECR (0x03)
+#define GRN_OBJ_APPEND (0x04)
+#define GRN_OBJ_PREPEND (0x05)
+#define GRN_OBJ_GET (0x01<<4)
+#define GRN_OBJ_COMPARE (0x01<<5)
+#define GRN_OBJ_LOCK (0x01<<6)
+#define GRN_OBJ_UNLOCK (0x01<<7)
+
+GRN_API grn_rc grn_obj_set_value(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value, int flags);
+GRN_API grn_rc grn_obj_remove(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_rc grn_obj_remove_dependent(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_rc grn_obj_remove_force(grn_ctx *ctx,
+ const char *name,
+ int name_size);
+GRN_API grn_rc grn_obj_rename(grn_ctx *ctx, grn_obj *obj,
+ const char *name, unsigned int name_size);
+GRN_API grn_rc grn_table_rename(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size);
+
+GRN_API grn_rc grn_column_rename(grn_ctx *ctx, grn_obj *column,
+ const char *name, unsigned int name_size);
+
+GRN_API grn_rc grn_obj_close(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_rc grn_obj_reinit(grn_ctx *ctx, grn_obj *obj, grn_id domain, unsigned char flags);
+GRN_API void grn_obj_unlink(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API grn_user_data *grn_obj_user_data(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API grn_rc grn_obj_set_finalizer(grn_ctx *ctx, grn_obj *obj, grn_proc_func *func);
+
+GRN_API const char *grn_obj_path(grn_ctx *ctx, grn_obj *obj);
+GRN_API int grn_obj_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size);
+
+GRN_API int grn_column_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size);
+
+GRN_API grn_id grn_obj_get_range(grn_ctx *ctx, grn_obj *obj);
+
+#define GRN_OBJ_GET_DOMAIN(obj) \
+ ((obj)->header.type == GRN_TABLE_NO_KEY ? GRN_ID_NIL : (obj)->header.domain)
+
+GRN_API int grn_obj_expire(grn_ctx *ctx, grn_obj *obj, int threshold);
+GRN_API int grn_obj_check(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_rc grn_obj_lock(grn_ctx *ctx, grn_obj *obj, grn_id id, int timeout);
+GRN_API grn_rc grn_obj_unlock(grn_ctx *ctx, grn_obj *obj, grn_id id);
+GRN_API grn_rc grn_obj_clear_lock(grn_ctx *ctx, grn_obj *obj);
+GRN_API unsigned int grn_obj_is_locked(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_rc grn_obj_flush(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_rc grn_obj_flush_recursive(grn_ctx *ctx, grn_obj *obj);
+GRN_API int grn_obj_defrag(grn_ctx *ctx, grn_obj *obj, int threshold);
+
+GRN_API grn_obj *grn_obj_db(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API grn_id grn_obj_id(grn_ctx *ctx, grn_obj *obj);
+
+/* Flags for grn_fuzzy_search_optarg::flags. */
+#define GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION (0x01)
+
+typedef struct _grn_fuzzy_search_optarg grn_fuzzy_search_optarg;
+
+struct _grn_fuzzy_search_optarg {
+ unsigned int max_distance;
+ unsigned int max_expansion;
+ unsigned int prefix_match_size;
+ int flags;
+};
+
+#define GRN_MATCH_INFO_GET_MIN_RECORD_ID (0x01)
+
+typedef struct _grn_match_info grn_match_info;
+
+struct _grn_match_info {
+ int flags;
+ grn_id min;
+};
+
+typedef struct _grn_search_optarg grn_search_optarg;
+
+struct _grn_search_optarg {
+ grn_operator mode;
+ int similarity_threshold;
+ int max_interval;
+ int *weight_vector;
+ int vector_size;
+ grn_obj *proc;
+ int max_size;
+ grn_obj *scorer;
+ grn_obj *scorer_args_expr;
+ unsigned int scorer_args_expr_offset;
+ grn_fuzzy_search_optarg fuzzy;
+ grn_match_info match_info;
+};
+
+GRN_API grn_rc grn_obj_search(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
+ grn_obj *res, grn_operator op, grn_search_optarg *optarg);
+
+typedef grn_rc grn_selector_func(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op);
+
+GRN_API grn_rc grn_proc_set_selector(grn_ctx *ctx, grn_obj *proc,
+ grn_selector_func selector);
+GRN_API grn_rc grn_proc_set_selector_operator(grn_ctx *ctx,
+ grn_obj *proc,
+ grn_operator selector_op);
+GRN_API grn_operator grn_proc_get_selector_operator(grn_ctx *ctx,
+ grn_obj *proc);
+
+GRN_API grn_rc grn_proc_set_is_stable(grn_ctx *ctx,
+ grn_obj *proc,
+ grn_bool is_stable);
+GRN_API grn_bool grn_proc_is_stable(grn_ctx *ctx, grn_obj *proc);
+
+/*-------------------------------------------------------------
+ * grn_vector
+*/
+
+GRN_API unsigned int grn_vector_size(grn_ctx *ctx, grn_obj *vector);
+
+GRN_API grn_rc grn_vector_add_element(grn_ctx *ctx, grn_obj *vector,
+ const char *str, unsigned int str_len,
+ unsigned int weight, grn_id domain);
+
+GRN_API unsigned int grn_vector_get_element(grn_ctx *ctx, grn_obj *vector,
+ unsigned int offset, const char **str,
+ unsigned int *weight, grn_id *domain);
+GRN_API unsigned int grn_vector_pop_element(grn_ctx *ctx, grn_obj *vector,
+ const char **str,
+ unsigned int *weight,
+ grn_id *domain);
+
+/*-------------------------------------------------------------
+ * grn_uvector
+*/
+
+GRN_API unsigned int grn_uvector_size(grn_ctx *ctx, grn_obj *uvector);
+GRN_API unsigned int grn_uvector_element_size(grn_ctx *ctx, grn_obj *uvector);
+
+GRN_API grn_rc grn_uvector_add_element(grn_ctx *ctx, grn_obj *vector,
+ grn_id id, unsigned int weight);
+
+GRN_API grn_id grn_uvector_get_element(grn_ctx *ctx, grn_obj *uvector,
+ unsigned int offset,
+ unsigned int *weight);
+
+/*-------------------------------------------------------------
+ * API for hook
+ */
+
+GRN_API int grn_proc_call_next(grn_ctx *ctx, grn_obj *exec_info, grn_obj *in, grn_obj *out);
+GRN_API void *grn_proc_get_ctx_local_data(grn_ctx *ctx, grn_obj *exec_info);
+GRN_API void *grn_proc_get_hook_local_data(grn_ctx *ctx, grn_obj *exec_info);
+
+typedef enum {
+ GRN_HOOK_SET = 0,
+ GRN_HOOK_GET,
+ GRN_HOOK_INSERT,
+ GRN_HOOK_DELETE,
+ GRN_HOOK_SELECT
+} grn_hook_entry;
+
+GRN_API grn_rc grn_obj_add_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
+ int offset, grn_obj *proc, grn_obj *data);
+GRN_API int grn_obj_get_nhooks(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry);
+GRN_API grn_obj *grn_obj_get_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
+ int offset, grn_obj *data);
+GRN_API grn_rc grn_obj_delete_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, int offset);
+
+GRN_API grn_obj *grn_obj_open(grn_ctx *ctx, unsigned char type, grn_obj_flags flags, grn_id domain);
+
+/* Deprecated since 5.0.1. Use grn_column_find_index_data() instead. */
+GRN_API int grn_column_index(grn_ctx *ctx, grn_obj *column, grn_operator op,
+ grn_obj **indexbuf, int buf_size, int *section);
+
+/* @since 5.0.1. */
+typedef struct _grn_index_datum {
+ grn_obj *index;
+ unsigned int section;
+} grn_index_datum;
+
+/* @since 5.0.1. */
+GRN_API unsigned int grn_column_find_index_data(grn_ctx *ctx, grn_obj *column,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned int n_index_data);
+/* @since 5.1.2. */
+GRN_API uint32_t grn_column_get_all_index_data(grn_ctx *ctx,
+ grn_obj *column,
+ grn_index_datum *index_data,
+ uint32_t n_index_data);
+
+GRN_API grn_rc grn_obj_delete_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, grn_bool removep);
+GRN_API grn_rc grn_obj_path_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer);
+
+/* geo */
+
+typedef struct {
+ int latitude;
+ int longitude;
+} grn_geo_point;
+
+GRN_API grn_rc grn_geo_select_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point,
+ grn_obj *res,
+ grn_operator op);
+GRN_API unsigned int grn_geo_estimate_size_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point);
+/* Deprecated since 4.0.8. Use grn_geo_estimate_size_in_rectangle() instead. */
+GRN_API int grn_geo_estimate_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point);
+GRN_API grn_obj *grn_geo_cursor_open_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point,
+ int offset,
+ int limit);
+GRN_API grn_posting *grn_geo_cursor_next(grn_ctx *ctx, grn_obj *cursor);
+
+
+/* query & snippet */
+
+#ifndef GRN_QUERY_AND
+#define GRN_QUERY_AND '+'
+#endif /* GRN_QUERY_AND */
+#ifndef GRN_QUERY_AND_NOT
+# ifdef GRN_QUERY_BUT
+ /* Deprecated. Just for backward compatibility. */
+# define GRN_QUERY_AND_NOT GRN_QUERY_BUT
+# else
+# define GRN_QUERY_AND_NOT '-'
+# endif /* GRN_QUERY_BUT */
+#endif /* GRN_QUERY_AND_NOT */
+#ifndef GRN_QUERY_ADJ_INC
+#define GRN_QUERY_ADJ_INC '>'
+#endif /* GRN_QUERY_ADJ_POS2 */
+#ifndef GRN_QUERY_ADJ_DEC
+#define GRN_QUERY_ADJ_DEC '<'
+#endif /* GRN_QUERY_ADJ_POS1 */
+#ifndef GRN_QUERY_ADJ_NEG
+#define GRN_QUERY_ADJ_NEG '~'
+#endif /* GRN_QUERY_ADJ_NEG */
+#ifndef GRN_QUERY_PREFIX
+#define GRN_QUERY_PREFIX '*'
+#endif /* GRN_QUERY_PREFIX */
+#ifndef GRN_QUERY_PARENL
+#define GRN_QUERY_PARENL '('
+#endif /* GRN_QUERY_PARENL */
+#ifndef GRN_QUERY_PARENR
+#define GRN_QUERY_PARENR ')'
+#endif /* GRN_QUERY_PARENR */
+#ifndef GRN_QUERY_QUOTEL
+#define GRN_QUERY_QUOTEL '"'
+#endif /* GRN_QUERY_QUOTEL */
+#ifndef GRN_QUERY_QUOTER
+#define GRN_QUERY_QUOTER '"'
+#endif /* GRN_QUERY_QUOTER */
+#ifndef GRN_QUERY_ESCAPE
+#define GRN_QUERY_ESCAPE '\\'
+#endif /* GRN_QUERY_ESCAPE */
+#ifndef GRN_QUERY_COLUMN
+#define GRN_QUERY_COLUMN ':'
+#endif /* GRN_QUERY_COLUMN */
+
+typedef struct _grn_snip_mapping grn_snip_mapping;
+
+struct _grn_snip_mapping {
+ void *dummy;
+};
+
+#define GRN_SNIP_NORMALIZE (0x01<<0)
+#define GRN_SNIP_COPY_TAG (0x01<<1)
+#define GRN_SNIP_SKIP_LEADING_SPACES (0x01<<2)
+
+#define GRN_SNIP_MAPPING_HTML_ESCAPE ((grn_snip_mapping *)-1)
+
+GRN_API grn_obj *grn_snip_open(grn_ctx *ctx, int flags, unsigned int width,
+ unsigned int max_results,
+ const char *defaultopentag, unsigned int defaultopentag_len,
+ const char *defaultclosetag, unsigned int defaultclosetag_len,
+ grn_snip_mapping *mapping);
+GRN_API grn_rc grn_snip_add_cond(grn_ctx *ctx, grn_obj *snip,
+ const char *keyword, unsigned int keyword_len,
+ const char *opentag, unsigned int opentag_len,
+ const char *closetag, unsigned int closetag_len);
+GRN_API grn_rc grn_snip_set_normalizer(grn_ctx *ctx, grn_obj *snip,
+ grn_obj *normalizer);
+GRN_API grn_obj *grn_snip_get_normalizer(grn_ctx *ctx, grn_obj *snip);
+GRN_API grn_rc grn_snip_exec(grn_ctx *ctx, grn_obj *snip,
+ const char *string, unsigned int string_len,
+ unsigned int *nresults, unsigned int *max_tagged_len);
+GRN_API grn_rc grn_snip_get_result(grn_ctx *ctx, grn_obj *snip, const unsigned int index,
+ char *result, unsigned int *result_len);
+
+/* log */
+
+#define GRN_LOG_TIME (0x01<<0)
+#define GRN_LOG_TITLE (0x01<<1)
+#define GRN_LOG_MESSAGE (0x01<<2)
+#define GRN_LOG_LOCATION (0x01<<3)
+#define GRN_LOG_PID (0x01<<4)
+
+/* Deprecated since 2.1.2. Use grn_logger instead. */
+typedef struct _grn_logger_info grn_logger_info;
+
+/* Deprecated since 2.1.2. Use grn_logger instead. */
+struct _grn_logger_info {
+ grn_log_level max_level;
+ int flags;
+ void (*func)(int, const char *, const char *, const char *, const char *, void *);
+ void *func_arg;
+};
+
+/* Deprecated since 2.1.2. Use grn_logger_set() instead. */
+GRN_API grn_rc grn_logger_info_set(grn_ctx *ctx, const grn_logger_info *info);
+
+typedef struct _grn_logger grn_logger;
+
+struct _grn_logger {
+ grn_log_level max_level;
+ int flags;
+ void *user_data;
+ void (*log)(grn_ctx *ctx, grn_log_level level,
+ const char *timestamp, const char *title, const char *message,
+ const char *location, void *user_data);
+ void (*reopen)(grn_ctx *ctx, void *user_data);
+ void (*fin)(grn_ctx *ctx, void *user_data);
+};
+
+GRN_API grn_rc grn_logger_set(grn_ctx *ctx, const grn_logger *logger);
+
+GRN_API void grn_logger_set_max_level(grn_ctx *ctx, grn_log_level max_level);
+GRN_API grn_log_level grn_logger_get_max_level(grn_ctx *ctx);
+
+#ifdef __GNUC__
+# define GRN_ATTRIBUTE_PRINTF(fmt_pos) \
+ __attribute__ ((format(printf, fmt_pos, fmt_pos + 1)))
+#else
+# define GRN_ATTRIBUTE_PRINTF(fmt_pos)
+#endif /* __GNUC__ */
+
+#if defined(__clang__)
+# if __has_attribute(__alloc_size__)
+# define HAVE_ALLOC_SIZE_ATTRIBUTE
+# endif /* __has_attribute(__alloc_size__) */
+#elif defined(__GNUC__) && \
+ ((__GNUC__ >= 5) || (__GNUC__ > 4 && __GNUC_MINOR__ >= 3))
+# define HAVE_ALLOC_SIZE_ATTRIBUTE
+#endif /* __clang__ */
+
+#ifdef HAVE_ALLOC_SIZE_ATTRIBUTE
+# define GRN_ATTRIBUTE_ALLOC_SIZE(size) \
+ __attribute__ ((alloc_size(size)))
+# define GRN_ATTRIBUTE_ALLOC_SIZE_N(n, size) \
+ __attribute__ ((alloc_size(n, size)))
+#else
+# define GRN_ATTRIBUTE_ALLOC_SIZE(size)
+# define GRN_ATTRIBUTE_ALLOC_SIZE_N(n, size)
+#endif /* HAVE_ALLOC_SIZE_ATTRIBUTE */
+
+GRN_API void grn_logger_put(grn_ctx *ctx, grn_log_level level,
+ const char *file, int line, const char *func, const char *fmt, ...) GRN_ATTRIBUTE_PRINTF(6);
+GRN_API void grn_logger_putv(grn_ctx *ctx,
+ grn_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt,
+ va_list ap);
+GRN_API void grn_logger_reopen(grn_ctx *ctx);
+
+GRN_API grn_bool grn_logger_pass(grn_ctx *ctx, grn_log_level level);
+
+#ifndef GRN_LOG_DEFAULT_LEVEL
+# define GRN_LOG_DEFAULT_LEVEL GRN_LOG_NOTICE
+#endif /* GRN_LOG_DEFAULT_LEVEL */
+
+GRN_API void grn_default_logger_set_max_level(grn_log_level level);
+GRN_API grn_log_level grn_default_logger_get_max_level(void);
+GRN_API void grn_default_logger_set_flags(int flags);
+GRN_API int grn_default_logger_get_flags(void);
+GRN_API void grn_default_logger_set_path(const char *path);
+GRN_API const char *grn_default_logger_get_path(void);
+GRN_API void grn_default_logger_set_rotate_threshold_size(off_t threshold);
+GRN_API off_t grn_default_logger_get_rotate_threshold_size(void);
+
+#define GRN_LOG(ctx,level,...) do {\
+ if (grn_logger_pass(ctx, level)) {\
+ grn_logger_put(ctx, (level), __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); \
+ }\
+} while (0)
+
+typedef struct _grn_query_logger grn_query_logger;
+
+struct _grn_query_logger {
+ unsigned int flags;
+ void *user_data;
+ void (*log)(grn_ctx *ctx, unsigned int flag,
+ const char *timestamp, const char *info, const char *message,
+ void *user_data);
+ void (*reopen)(grn_ctx *ctx, void *user_data);
+ void (*fin)(grn_ctx *ctx, void *user_data);
+};
+
+GRN_API grn_bool grn_query_log_flags_parse(const char *string,
+ int string_size,
+ unsigned int *flags);
+
+GRN_API grn_rc grn_query_logger_set(grn_ctx *ctx, const grn_query_logger *logger);
+GRN_API void grn_query_logger_set_flags(grn_ctx *ctx, unsigned int flags);
+GRN_API void grn_query_logger_add_flags(grn_ctx *ctx, unsigned int flags);
+GRN_API void grn_query_logger_remove_flags(grn_ctx *ctx, unsigned int flags);
+GRN_API unsigned int grn_query_logger_get_flags(grn_ctx *ctx);
+
+GRN_API void grn_query_logger_put(grn_ctx *ctx, unsigned int flag,
+ const char *mark,
+ const char *format, ...) GRN_ATTRIBUTE_PRINTF(4);
+GRN_API void grn_query_logger_reopen(grn_ctx *ctx);
+
+GRN_API grn_bool grn_query_logger_pass(grn_ctx *ctx, unsigned int flag);
+
+GRN_API void grn_default_query_logger_set_flags(unsigned int flags);
+GRN_API unsigned int grn_default_query_logger_get_flags(void);
+GRN_API void grn_default_query_logger_set_path(const char *path);
+GRN_API const char *grn_default_query_logger_get_path(void);
+GRN_API void grn_default_query_logger_set_rotate_threshold_size(off_t threshold);
+GRN_API off_t grn_default_query_logger_get_rotate_threshold_size(void);
+
+#define GRN_QUERY_LOG(ctx, flag, mark, format, ...) do {\
+ if (grn_query_logger_pass(ctx, flag)) {\
+ grn_query_logger_put(ctx, (flag), (mark), format, __VA_ARGS__);\
+ }\
+} while (0)
+
+/* grn_bulk */
+
+#define GRN_BULK_BUFSIZE (sizeof(grn_obj) - sizeof(grn_obj_header))
+/* This assumes that GRN_BULK_BUFSIZE is less than 32 (= 0x20). */
+#define GRN_BULK_BUFSIZE_MAX 0x1f
+#define GRN_BULK_SIZE_IN_FLAGS(flags) ((flags) & GRN_BULK_BUFSIZE_MAX)
+#define GRN_BULK_OUTP(bulk) ((bulk)->header.impl_flags & GRN_OBJ_OUTPLACE)
+#define GRN_BULK_REWIND(bulk) do {\
+ if ((bulk)->header.type == GRN_VECTOR) {\
+ grn_obj *_body = (bulk)->u.v.body;\
+ if (_body) {\
+ if (GRN_BULK_OUTP(_body)) {\
+ (_body)->u.b.curr = (_body)->u.b.head;\
+ } else {\
+ (_body)->header.flags &= ~GRN_BULK_BUFSIZE_MAX;\
+ }\
+ }\
+ (bulk)->u.v.n_sections = 0;\
+ } else {\
+ if (GRN_BULK_OUTP(bulk)) {\
+ (bulk)->u.b.curr = (bulk)->u.b.head;\
+ } else {\
+ (bulk)->header.flags &= ~GRN_BULK_BUFSIZE_MAX;\
+ }\
+ }\
+} while (0)
+#define GRN_BULK_INCR_LEN(bulk,len) do {\
+ if (GRN_BULK_OUTP(bulk)) {\
+ (bulk)->u.b.curr += (len);\
+ } else {\
+ (bulk)->header.flags += (grn_obj_flags)(len);\
+ }\
+} while (0)
+#define GRN_BULK_WSIZE(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.tail - (bulk)->u.b.head)\
+ : GRN_BULK_BUFSIZE)
+#define GRN_BULK_REST(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.tail - (bulk)->u.b.curr)\
+ : GRN_BULK_BUFSIZE - GRN_BULK_SIZE_IN_FLAGS((bulk)->header.flags))
+#define GRN_BULK_VSIZE(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.curr - (bulk)->u.b.head)\
+ : GRN_BULK_SIZE_IN_FLAGS((bulk)->header.flags))
+#define GRN_BULK_EMPTYP(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.curr == (bulk)->u.b.head)\
+ : !(GRN_BULK_SIZE_IN_FLAGS((bulk)->header.flags)))
+#define GRN_BULK_HEAD(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.head)\
+ : (char *)&((bulk)->u.b.head))
+#define GRN_BULK_CURR(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.curr)\
+ : (char *)&((bulk)->u.b.head) + GRN_BULK_SIZE_IN_FLAGS((bulk)->header.flags))
+#define GRN_BULK_TAIL(bulk) \
+ (GRN_BULK_OUTP(bulk)\
+ ? ((bulk)->u.b.tail)\
+ : (char *)&((bulk)[1]))
+
+GRN_API grn_rc grn_bulk_reinit(grn_ctx *ctx, grn_obj *bulk, unsigned int size);
+GRN_API grn_rc grn_bulk_resize(grn_ctx *ctx, grn_obj *bulk, unsigned int newsize);
+GRN_API grn_rc grn_bulk_write(grn_ctx *ctx, grn_obj *bulk,
+ const char *str, unsigned int len);
+GRN_API grn_rc grn_bulk_write_from(grn_ctx *ctx, grn_obj *bulk,
+ const char *str, unsigned int from, unsigned int len);
+GRN_API grn_rc grn_bulk_reserve(grn_ctx *ctx, grn_obj *bulk, unsigned int len);
+GRN_API grn_rc grn_bulk_space(grn_ctx *ctx, grn_obj *bulk, unsigned int len);
+GRN_API grn_rc grn_bulk_truncate(grn_ctx *ctx, grn_obj *bulk, unsigned int len);
+GRN_API grn_rc grn_bulk_fin(grn_ctx *ctx, grn_obj *bulk);
+
+/* grn_text */
+
+GRN_API grn_rc grn_text_itoa(grn_ctx *ctx, grn_obj *bulk, int i);
+GRN_API grn_rc grn_text_itoa_padded(grn_ctx *ctx, grn_obj *bulk, int i, char ch, unsigned int len);
+GRN_API grn_rc grn_text_lltoa(grn_ctx *ctx, grn_obj *bulk, long long int i);
+GRN_API grn_rc grn_text_ftoa(grn_ctx *ctx, grn_obj *bulk, double d);
+GRN_API grn_rc grn_text_itoh(grn_ctx *ctx, grn_obj *bulk, int i, unsigned int len);
+GRN_API grn_rc grn_text_itob(grn_ctx *ctx, grn_obj *bulk, grn_id id);
+GRN_API grn_rc grn_text_lltob32h(grn_ctx *ctx, grn_obj *bulk, long long int i);
+GRN_API grn_rc grn_text_benc(grn_ctx *ctx, grn_obj *bulk, unsigned int v);
+GRN_API grn_rc grn_text_esc(grn_ctx *ctx, grn_obj *bulk, const char *s, unsigned int len);
+GRN_API grn_rc grn_text_urlenc(grn_ctx *ctx, grn_obj *buf,
+ const char *str, unsigned int len);
+GRN_API const char *grn_text_urldec(grn_ctx *ctx, grn_obj *buf,
+ const char *s, const char *e, char d);
+GRN_API grn_rc grn_text_escape_xml(grn_ctx *ctx, grn_obj *buf,
+ const char *s, unsigned int len);
+GRN_API grn_rc grn_text_time2rfc1123(grn_ctx *ctx, grn_obj *bulk, int sec);
+GRN_API grn_rc grn_text_printf(grn_ctx *ctx, grn_obj *bulk,
+ const char *format, ...) GRN_ATTRIBUTE_PRINTF(3);
+GRN_API grn_rc grn_text_vprintf(grn_ctx *ctx, grn_obj *bulk,
+ const char *format, va_list args);
+
+GRN_API void grn_ctx_recv_handler_set(grn_ctx *,
+ void (*func)(grn_ctx *, int, void *),
+ void *func_arg);
+
+/* various values exchanged via grn_obj */
+
+#define GRN_OBJ_DO_SHALLOW_COPY (GRN_OBJ_REFER|GRN_OBJ_OUTPLACE)
+#define GRN_OBJ_VECTOR (0x01<<7)
+
+#define GRN_OBJ_MUTABLE(obj) ((obj) && (obj)->header.type <= GRN_VECTOR)
+
+#define GRN_VALUE_FIX_SIZE_INIT(obj,flags,domain)\
+ GRN_OBJ_INIT((obj), ((flags) & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK,\
+ ((flags) & GRN_OBJ_DO_SHALLOW_COPY), (domain))
+#define GRN_VALUE_VAR_SIZE_INIT(obj,flags,domain)\
+ GRN_OBJ_INIT((obj), ((flags) & GRN_OBJ_VECTOR) ? GRN_VECTOR : GRN_BULK,\
+ ((flags) & GRN_OBJ_DO_SHALLOW_COPY), (domain))
+
+#define GRN_VOID_INIT(obj) GRN_OBJ_INIT((obj), GRN_VOID, 0, GRN_DB_VOID)
+#define GRN_TEXT_INIT(obj,flags) \
+ GRN_VALUE_VAR_SIZE_INIT(obj, flags, GRN_DB_TEXT)
+#define GRN_SHORT_TEXT_INIT(obj,flags) \
+ GRN_VALUE_VAR_SIZE_INIT(obj, flags, GRN_DB_SHORT_TEXT)
+#define GRN_LONG_TEXT_INIT(obj,flags) \
+ GRN_VALUE_VAR_SIZE_INIT(obj, flags, GRN_DB_LONG_TEXT)
+#define GRN_TEXT_SET_REF(obj,str,len) do {\
+ (obj)->u.b.head = (char *)(str);\
+ (obj)->u.b.curr = (char *)(str) + (len);\
+} while (0)
+#define GRN_TEXT_SET(ctx,obj,str,len) do {\
+ if ((obj)->header.impl_flags & GRN_OBJ_REFER) {\
+ GRN_TEXT_SET_REF((obj), (str), (len));\
+ } else {\
+ grn_bulk_write_from((ctx), (obj), (const char *)(str), 0, (unsigned int)(len));\
+ }\
+} while (0)
+#define GRN_TEXT_PUT(ctx,obj,str,len) \
+ grn_bulk_write((ctx), (obj), (const char *)(str), (unsigned int)(len))
+#define GRN_TEXT_PUTC(ctx,obj,c) do {\
+ char _c = (c); grn_bulk_write((ctx), (obj), &_c, 1);\
+} while (0)
+
+#define GRN_TEXT_PUTS(ctx,obj,str) GRN_TEXT_PUT((ctx), (obj), (str), strlen(str))
+#define GRN_TEXT_SETS(ctx,obj,str) GRN_TEXT_SET((ctx), (obj), (str), strlen(str))
+#define GRN_TEXT_VALUE(obj) GRN_BULK_HEAD(obj)
+#define GRN_TEXT_LEN(obj) GRN_BULK_VSIZE(obj)
+
+#define GRN_TEXT_EQUAL_CSTRING(bulk, string)\
+ (GRN_TEXT_LEN(bulk) == strlen(string) &&\
+ memcmp(GRN_TEXT_VALUE(bulk), string, GRN_TEXT_LEN(bulk)) == 0)
+
+#define GRN_BOOL_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_BOOL)
+#define GRN_INT8_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_INT8)
+#define GRN_UINT8_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_UINT8)
+#define GRN_INT16_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_INT16)
+#define GRN_UINT16_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_UINT16)
+#define GRN_INT32_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_INT32)
+#define GRN_UINT32_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_UINT32)
+#define GRN_INT64_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_INT64)
+#define GRN_UINT64_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_UINT64)
+#define GRN_FLOAT_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_FLOAT)
+#define GRN_TIME_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_TIME)
+#define GRN_RECORD_INIT GRN_VALUE_FIX_SIZE_INIT
+#define GRN_PTR_INIT(obj,flags,domain)\
+ GRN_OBJ_INIT((obj), ((flags) & GRN_OBJ_VECTOR) ? GRN_PVECTOR : GRN_PTR,\
+ ((flags) & (GRN_OBJ_DO_SHALLOW_COPY | GRN_OBJ_OWN)),\
+ (domain))
+#define GRN_TOKYO_GEO_POINT_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_TOKYO_GEO_POINT)
+#define GRN_WGS84_GEO_POINT_INIT(obj,flags) \
+ GRN_VALUE_FIX_SIZE_INIT(obj, flags, GRN_DB_WGS84_GEO_POINT)
+
+#define GRN_BOOL_SET(ctx,obj,val) do {\
+ unsigned char _val = (unsigned char)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(unsigned char));\
+} while (0)
+#define GRN_INT8_SET(ctx,obj,val) do {\
+ signed char _val = (signed char)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(signed char));\
+} while (0)
+#define GRN_UINT8_SET(ctx,obj,val) do {\
+ unsigned char _val = (unsigned char)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(unsigned char));\
+} while (0)
+#define GRN_INT16_SET(ctx,obj,val) do {\
+ signed short _val = (signed short)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(signed short));\
+} while (0)
+#define GRN_UINT16_SET(ctx,obj,val) do {\
+ unsigned short _val = (unsigned short)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(unsigned short));\
+} while (0)
+#define GRN_INT32_SET(ctx,obj,val) do {\
+ int _val = (int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(int));\
+} while (0)
+#define GRN_UINT32_SET(ctx,obj,val) do {\
+ unsigned int _val = (unsigned int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(unsigned int));\
+} while (0)
+#define GRN_INT64_SET(ctx,obj,val) do {\
+ long long int _val = (long long int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(long long int));\
+} while (0)
+#define GRN_UINT64_SET(ctx,obj,val) do {\
+ long long unsigned int _val = (long long unsigned int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(long long unsigned int));\
+} while (0)
+#define GRN_FLOAT_SET(ctx,obj,val) do {\
+ double _val = (double)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(double));\
+} while (0)
+#define GRN_TIME_SET GRN_INT64_SET
+#define GRN_RECORD_SET(ctx,obj,val) do {\
+ grn_id _val = (grn_id)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(grn_id));\
+} while (0)
+#define GRN_PTR_SET(ctx,obj,val) do {\
+ grn_obj *_val = (grn_obj *)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(grn_obj *));\
+} while (0)
+
+#define GRN_GEO_DEGREE2MSEC(degree)\
+ ((int)((degree) * 3600 * 1000 + ((degree) > 0 ? 0.5 : -0.5)))
+#define GRN_GEO_MSEC2DEGREE(msec)\
+ ((((int)(msec)) / 3600.0) * 0.001)
+
+#define GRN_GEO_POINT_SET(ctx,obj,_latitude,_longitude) do {\
+ grn_geo_point _val;\
+ _val.latitude = (int)(_latitude);\
+ _val.longitude = (int)(_longitude);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val, 0, sizeof(grn_geo_point));\
+} while (0)
+
+#define GRN_BOOL_SET_AT(ctx,obj,offset,val) do {\
+ unsigned char _val = (unsigned char)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset), sizeof(unsigned char));\
+} while (0)
+#define GRN_INT8_SET_AT(ctx,obj,offset,val) do {\
+ signed char _val = (signed char)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(signed char), sizeof(signed char));\
+} while (0)
+#define GRN_UINT8_SET_AT(ctx,obj,offset,val) do { \
+ unsigned char _val = (unsigned char)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(unsigned char), sizeof(unsigned char));\
+} while (0)
+#define GRN_INT16_SET_AT(ctx,obj,offset,val) do {\
+ signed short _val = (signed short)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(signed short), sizeof(signed short));\
+} while (0)
+#define GRN_UINT16_SET_AT(ctx,obj,offset,val) do { \
+ unsigned short _val = (unsigned short)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(unsigned short), sizeof(unsigned short));\
+} while (0)
+#define GRN_INT32_SET_AT(ctx,obj,offset,val) do {\
+ int _val = (int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(int), sizeof(int));\
+} while (0)
+#define GRN_UINT32_SET_AT(ctx,obj,offset,val) do { \
+ unsigned int _val = (unsigned int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(unsigned int), sizeof(unsigned int));\
+} while (0)
+#define GRN_INT64_SET_AT(ctx,obj,offset,val) do {\
+ long long int _val = (long long int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(long long int), sizeof(long long int));\
+} while (0)
+#define GRN_UINT64_SET_AT(ctx,obj,offset,val) do {\
+ long long unsigned int _val = (long long unsigned int)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(long long unsigned int),\
+ sizeof(long long unsigned int));\
+} while (0)
+#define GRN_FLOAT_SET_AT(ctx,obj,offset,val) do {\
+ double _val = (double)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(double), sizeof(double));\
+} while (0)
+#define GRN_TIME_SET_AT GRN_INT64_SET_AT
+#define GRN_RECORD_SET_AT(ctx,obj,offset,val) do {\
+ grn_id _val = (grn_id)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(grn_id), sizeof(grn_id));\
+} while (0)
+#define GRN_PTR_SET_AT(ctx,obj,offset,val) do {\
+ grn_obj *_val = (grn_obj *)(val);\
+ grn_bulk_write_from((ctx), (obj), (char *)&_val,\
+ (offset) * sizeof(grn_obj *), sizeof(grn_obj *));\
+} while (0)
+
+#define GRN_BOOL_VALUE(obj) (*((unsigned char *)GRN_BULK_HEAD(obj)))
+#define GRN_INT8_VALUE(obj) (*((signed char *)GRN_BULK_HEAD(obj)))
+#define GRN_UINT8_VALUE(obj) (*((unsigned char *)GRN_BULK_HEAD(obj)))
+#define GRN_INT16_VALUE(obj) (*((signed short *)GRN_BULK_HEAD(obj)))
+#define GRN_UINT16_VALUE(obj) (*((unsigned short *)GRN_BULK_HEAD(obj)))
+#define GRN_INT32_VALUE(obj) (*((int *)GRN_BULK_HEAD(obj)))
+#define GRN_UINT32_VALUE(obj) (*((unsigned int *)GRN_BULK_HEAD(obj)))
+#define GRN_INT64_VALUE(obj) (*((long long int *)GRN_BULK_HEAD(obj)))
+#define GRN_UINT64_VALUE(obj) (*((long long unsigned int *)GRN_BULK_HEAD(obj)))
+#define GRN_FLOAT_VALUE(obj) (*((double *)GRN_BULK_HEAD(obj)))
+#define GRN_TIME_VALUE GRN_INT64_VALUE
+#define GRN_RECORD_VALUE(obj) (*((grn_id *)GRN_BULK_HEAD(obj)))
+#define GRN_PTR_VALUE(obj) (*((grn_obj **)GRN_BULK_HEAD(obj)))
+#define GRN_GEO_POINT_VALUE(obj,_latitude,_longitude) do {\
+ grn_geo_point *_val = (grn_geo_point *)GRN_BULK_HEAD(obj);\
+ _latitude = _val->latitude;\
+ _longitude = _val->longitude;\
+} while (0)
+
+#define GRN_BOOL_VALUE_AT(obj,offset) (((unsigned char *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_INT8_VALUE_AT(obj,offset) (((signed char *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_UINT8_VALUE_AT(obj,offset) (((unsigned char *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_INT16_VALUE_AT(obj,offset) (((signed short *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_UINT16_VALUE_AT(obj,offset) (((unsigned short *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_INT32_VALUE_AT(obj,offset) (((int *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_UINT32_VALUE_AT(obj,offset) (((unsigned int *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_INT64_VALUE_AT(obj,offset) (((long long int *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_UINT64_VALUE_AT(obj,offset) (((long long unsigned int *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_FLOAT_VALUE_AT(obj,offset) (((double *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_TIME_VALUE_AT GRN_INT64_VALUE_AT
+#define GRN_RECORD_VALUE_AT(obj,offset) (((grn_id *)GRN_BULK_HEAD(obj))[offset])
+#define GRN_PTR_VALUE_AT(obj,offset) (((grn_obj **)GRN_BULK_HEAD(obj))[offset])
+
+#define GRN_BOOL_PUT(ctx,obj,val) do {\
+ unsigned char _val = (unsigned char)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(unsigned char));\
+} while (0)
+#define GRN_INT8_PUT(ctx,obj,val) do {\
+ signed char _val = (signed char)(val); grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(signed char));\
+} while (0)
+#define GRN_UINT8_PUT(ctx,obj,val) do {\
+ unsigned char _val = (unsigned char)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(unsigned char));\
+} while (0)
+#define GRN_INT16_PUT(ctx,obj,val) do {\
+ signed short _val = (signed short)(val); grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(signed short));\
+} while (0)
+#define GRN_UINT16_PUT(ctx,obj,val) do {\
+ unsigned short _val = (unsigned short)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(unsigned short));\
+} while (0)
+#define GRN_INT32_PUT(ctx,obj,val) do {\
+ int _val = (int)(val); grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(int));\
+} while (0)
+#define GRN_UINT32_PUT(ctx,obj,val) do {\
+ unsigned int _val = (unsigned int)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(unsigned int));\
+} while (0)
+#define GRN_INT64_PUT(ctx,obj,val) do {\
+ long long int _val = (long long int)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(long long int));\
+} while (0)
+#define GRN_UINT64_PUT(ctx,obj,val) do {\
+ long long unsigned int _val = (long long unsigned int)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(long long unsigned int));\
+} while (0)
+#define GRN_FLOAT_PUT(ctx,obj,val) do {\
+ double _val = (double)(val); grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(double));\
+} while (0)
+#define GRN_TIME_PUT GRN_INT64_PUT
+#define GRN_RECORD_PUT(ctx,obj,val) do {\
+ grn_id _val = (grn_id)(val); grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(grn_id));\
+} while (0)
+#define GRN_PTR_PUT(ctx,obj,val) do {\
+ grn_obj *_val = (grn_obj *)(val);\
+ grn_bulk_write((ctx), (obj), (char *)&_val, sizeof(grn_obj *));\
+} while (0)
+
+#define GRN_BULK_POP(obj, value, type, default) do {\
+ if ((size_t) GRN_BULK_VSIZE(obj) >= sizeof(type)) { \
+ GRN_BULK_INCR_LEN((obj), -(sizeof(type)));\
+ value = *(type *)(GRN_BULK_CURR(obj));\
+ } else {\
+ value = default;\
+ }\
+} while (0)
+#define GRN_BOOL_POP(obj, value) GRN_BULK_POP(obj, value, unsigned char, 0)
+#define GRN_INT8_POP(obj, value) GRN_BULK_POP(obj, value, int8_t, 0)
+#define GRN_UINT8_POP(obj, value) GRN_BULK_POP(obj, value, uint8_t, 0)
+#define GRN_INT16_POP(obj, value) GRN_BULK_POP(obj, value, int16_t, 0)
+#define GRN_UINT16_POP(obj, value) GRN_BULK_POP(obj, value, uint16_t, 0)
+#define GRN_INT32_POP(obj, value) GRN_BULK_POP(obj, value, int32_t, 0)
+#define GRN_UINT32_POP(obj, value) GRN_BULK_POP(obj, value, uint32_t, 0)
+#define GRN_INT64_POP(obj, value) GRN_BULK_POP(obj, value, int64_t, 0)
+#define GRN_UINT64_POP(obj, value) GRN_BULK_POP(obj, value, uint64_t, 0)
+#define GRN_FLOAT_POP(obj, value) GRN_BULK_POP(obj, value, double, 0.0)
+#define GRN_TIME_POP GRN_INT64_POP
+#define GRN_RECORD_POP(obj, value) GRN_BULK_POP(obj, value, grn_id, GRN_ID_NIL)
+#define GRN_PTR_POP(obj, value) GRN_BULK_POP(obj, value, grn_obj *, NULL)
+
+/* grn_str: deprecated. use grn_string instead. */
+
+typedef struct {
+ const char *orig;
+ char *norm;
+ short *checks;
+ unsigned char *ctypes;
+ int flags;
+ unsigned int orig_blen;
+ unsigned int norm_blen;
+ unsigned int length;
+ grn_encoding encoding;
+} grn_str;
+
+#define GRN_STR_REMOVEBLANK (0x01<<0)
+#define GRN_STR_WITH_CTYPES (0x01<<1)
+#define GRN_STR_WITH_CHECKS (0x01<<2)
+#define GRN_STR_NORMALIZE GRN_OBJ_KEY_NORMALIZE
+
+GRN_API grn_str *grn_str_open(grn_ctx *ctx, const char *str, unsigned int str_len,
+ int flags);
+GRN_API grn_rc grn_str_close(grn_ctx *ctx, grn_str *nstr);
+
+/* grn_string */
+
+#define GRN_STRING_REMOVE_BLANK (0x01<<0)
+#define GRN_STRING_WITH_TYPES (0x01<<1)
+#define GRN_STRING_WITH_CHECKS (0x01<<2)
+#define GRN_STRING_REMOVE_TOKENIZED_DELIMITER (0x01<<3)
+
+#define GRN_NORMALIZER_AUTO ((grn_obj *)1)
+
+#define GRN_CHAR_BLANK 0x80
+#define GRN_CHAR_IS_BLANK(c) ((c) & (GRN_CHAR_BLANK))
+#define GRN_CHAR_TYPE(c) ((c) & 0x7f)
+
+typedef enum {
+ GRN_CHAR_NULL = 0,
+ GRN_CHAR_ALPHA,
+ GRN_CHAR_DIGIT,
+ GRN_CHAR_SYMBOL,
+ GRN_CHAR_HIRAGANA,
+ GRN_CHAR_KATAKANA,
+ GRN_CHAR_KANJI,
+ GRN_CHAR_OTHERS
+} grn_char_type;
+
+GRN_API grn_obj *grn_string_open(grn_ctx *ctx,
+ const char *string,
+ unsigned int length_in_bytes,
+ grn_obj *normalizer, int flags);
+GRN_API grn_rc grn_string_get_original(grn_ctx *ctx, grn_obj *string,
+ const char **original,
+ unsigned int *length_in_bytes);
+GRN_API int grn_string_get_flags(grn_ctx *ctx, grn_obj *string);
+GRN_API grn_rc grn_string_get_normalized(grn_ctx *ctx, grn_obj *string,
+ const char **normalized,
+ unsigned int *length_in_bytes,
+ unsigned int *n_characters);
+GRN_API grn_rc grn_string_set_normalized(grn_ctx *ctx, grn_obj *string,
+ char *normalized,
+ unsigned int length_in_bytes,
+ unsigned int n_characters);
+GRN_API const short *grn_string_get_checks(grn_ctx *ctx, grn_obj *string);
+GRN_API grn_rc grn_string_set_checks(grn_ctx *ctx,
+ grn_obj *string,
+ short *checks);
+GRN_API const unsigned char *grn_string_get_types(grn_ctx *ctx, grn_obj *string);
+GRN_API grn_rc grn_string_set_types(grn_ctx *ctx,
+ grn_obj *string,
+ unsigned char *types);
+GRN_API grn_encoding grn_string_get_encoding(grn_ctx *ctx, grn_obj *string);
+
+
+GRN_API int grn_charlen(grn_ctx *ctx, const char *str, const char *end);
+
+GRN_API grn_rc grn_ctx_push(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_obj *grn_ctx_pop(grn_ctx *ctx);
+
+GRN_API int grn_obj_columns(grn_ctx *ctx, grn_obj *table,
+ const char *str, unsigned int str_size, grn_obj *res);
+
+GRN_API grn_rc grn_load(grn_ctx *ctx, grn_content_type input_type,
+ const char *table, unsigned int table_len,
+ const char *columns, unsigned int columns_len,
+ const char *values, unsigned int values_len,
+ const char *ifexists, unsigned int ifexists_len,
+ const char *each, unsigned int each_len);
+
+#define GRN_CTX_MORE (0x01<<0)
+#define GRN_CTX_TAIL (0x01<<1)
+#define GRN_CTX_HEAD (0x01<<2)
+#define GRN_CTX_QUIET (0x01<<3)
+#define GRN_CTX_QUIT (0x01<<4)
+
+GRN_API grn_rc grn_ctx_connect(grn_ctx *ctx, const char *host, int port, int flags);
+GRN_API unsigned int grn_ctx_send(grn_ctx *ctx, const char *str, unsigned int str_len, int flags);
+GRN_API unsigned int grn_ctx_recv(grn_ctx *ctx, char **str, unsigned int *str_len, int *flags);
+
+typedef struct _grn_ctx_info grn_ctx_info;
+
+struct _grn_ctx_info {
+ int fd;
+ unsigned int com_status;
+ grn_obj *outbuf;
+ unsigned char stat;
+};
+
+GRN_API grn_rc grn_ctx_info_get(grn_ctx *ctx, grn_ctx_info *info);
+
+GRN_API grn_rc grn_set_segv_handler(void);
+GRN_API grn_rc grn_set_int_handler(void);
+GRN_API grn_rc grn_set_term_handler(void);
+
+
+typedef struct _grn_table_delete_optarg grn_table_delete_optarg;
+
+struct _grn_table_delete_optarg {
+ int flags;
+ int (*func)(grn_ctx *ctx, grn_obj *, grn_id, void *);
+ void *func_arg;
+};
+
+struct _grn_table_scan_hit {
+ grn_id id;
+ unsigned int offset;
+ unsigned int length;
+};
+
+typedef struct {
+ int64_t tv_sec;
+ int32_t tv_nsec;
+} grn_timeval;
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/hash.h b/storage/mroonga/vendor/groonga/include/groonga/hash.h
new file mode 100644
index 00000000..6a008176
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/hash.h
@@ -0,0 +1,104 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_HASH_TINY (0x01<<6)
+
+typedef struct _grn_hash grn_hash;
+typedef struct _grn_hash_cursor grn_hash_cursor;
+
+GRN_API grn_hash *grn_hash_create(grn_ctx *ctx, const char *path, unsigned int key_size,
+ unsigned int value_size, unsigned int flags);
+
+GRN_API grn_hash *grn_hash_open(grn_ctx *ctx, const char *path);
+
+GRN_API grn_rc grn_hash_close(grn_ctx *ctx, grn_hash *hash);
+
+GRN_API grn_id grn_hash_add(grn_ctx *ctx, grn_hash *hash, const void *key,
+ unsigned int key_size, void **value, int *added);
+GRN_API grn_id grn_hash_get(grn_ctx *ctx, grn_hash *hash, const void *key,
+ unsigned int key_size, void **value);
+
+GRN_API int grn_hash_get_key(grn_ctx *ctx, grn_hash *hash, grn_id id, void *keybuf, int bufsize);
+GRN_API int grn_hash_get_key2(grn_ctx *ctx, grn_hash *hash, grn_id id, grn_obj *bulk);
+GRN_API int grn_hash_get_value(grn_ctx *ctx, grn_hash *hash, grn_id id, void *valuebuf);
+GRN_API grn_rc grn_hash_set_value(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ const void *value, int flags);
+
+GRN_API grn_rc grn_hash_delete_by_id(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ grn_table_delete_optarg *optarg);
+GRN_API grn_rc grn_hash_delete(grn_ctx *ctx, grn_hash *hash,
+ const void *key, unsigned int key_size,
+ grn_table_delete_optarg *optarg);
+
+GRN_API uint32_t grn_hash_size(grn_ctx *ctx, grn_hash *hash);
+
+GRN_API grn_hash_cursor *grn_hash_cursor_open(grn_ctx *ctx, grn_hash *hash,
+ const void *min, unsigned int min_size,
+ const void *max, unsigned int max_size,
+ int offset, int limit, int flags);
+GRN_API grn_id grn_hash_cursor_next(grn_ctx *ctx, grn_hash_cursor *c);
+GRN_API void grn_hash_cursor_close(grn_ctx *ctx, grn_hash_cursor *c);
+
+GRN_API int grn_hash_cursor_get_key(grn_ctx *ctx, grn_hash_cursor *c, void **key);
+GRN_API int grn_hash_cursor_get_value(grn_ctx *ctx, grn_hash_cursor *c, void **value);
+GRN_API grn_rc grn_hash_cursor_set_value(grn_ctx *ctx, grn_hash_cursor *c,
+ const void *value, int flags);
+
+GRN_API int grn_hash_cursor_get_key_value(grn_ctx *ctx, grn_hash_cursor *c,
+ void **key, unsigned int *key_size, void **value);
+
+GRN_API grn_rc grn_hash_cursor_delete(grn_ctx *ctx, grn_hash_cursor *c,
+ grn_table_delete_optarg *optarg);
+
+#define GRN_HASH_EACH(ctx,hash,id,key,key_size,value,block) do {\
+ grn_hash_cursor *_sc = grn_hash_cursor_open(ctx, hash, NULL, 0, NULL, 0, 0, -1, 0); \
+ if (_sc) {\
+ grn_id id;\
+ while ((id = grn_hash_cursor_next(ctx, _sc))) {\
+ grn_hash_cursor_get_key_value(ctx, _sc, (void **)(key),\
+ (key_size), (void **)(value));\
+ block\
+ }\
+ grn_hash_cursor_close(ctx, _sc);\
+ }\
+} while (0)
+
+#define GRN_HASH_EACH_BEGIN(ctx, hash, cursor, id) do {\
+ grn_hash_cursor *cursor;\
+ cursor = grn_hash_cursor_open((ctx), (hash),\
+ NULL, 0, NULL, 0,\
+ 0, -1, GRN_CURSOR_BY_ID);\
+ if (cursor) {\
+ grn_id id;\
+ while ((id = grn_hash_cursor_next((ctx), cursor)) != GRN_ID_NIL) {
+
+#define GRN_HASH_EACH_END(ctx, cursor)\
+ }\
+ grn_hash_cursor_close((ctx), cursor);\
+ }\
+} while(0)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/id.h b/storage/mroonga/vendor/groonga/include/groonga/id.h
new file mode 100644
index 00000000..ddd7dff1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/id.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_bool grn_id_is_builtin(grn_ctx *ctx, grn_id id);
+GRN_API grn_bool grn_id_is_builtin_type(grn_ctx *ctx, grn_id id);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/ii.h b/storage/mroonga/vendor/groonga/include/groonga/ii.h
new file mode 100644
index 00000000..d1913961
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/ii.h
@@ -0,0 +1,69 @@
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* buffered index builder */
+
+typedef struct _grn_ii grn_ii;
+typedef struct _grn_ii_buffer grn_ii_buffer;
+
+GRN_API uint32_t grn_ii_get_n_elements(grn_ctx *ctx, grn_ii *ii);
+
+GRN_API void grn_ii_cursor_set_min_enable_set(grn_bool enable);
+GRN_API grn_bool grn_ii_cursor_set_min_enable_get(void);
+
+GRN_API uint32_t grn_ii_estimate_size(grn_ctx *ctx, grn_ii *ii, grn_id tid);
+GRN_API uint32_t grn_ii_estimate_size_for_query(grn_ctx *ctx, grn_ii *ii,
+ const char *query,
+ unsigned int query_len,
+ grn_search_optarg *optarg);
+GRN_API uint32_t grn_ii_estimate_size_for_lexicon_cursor(grn_ctx *ctx,
+ grn_ii *ii,
+ grn_table_cursor *lexicon_cursor);
+
+GRN_API grn_ii_buffer *grn_ii_buffer_open(grn_ctx *ctx, grn_ii *ii,
+ long long unsigned int update_buffer_size);
+GRN_API grn_rc grn_ii_buffer_append(grn_ctx *ctx,
+ grn_ii_buffer *ii_buffer,
+ grn_id rid,
+ unsigned int section,
+ grn_obj *value);
+GRN_API grn_rc grn_ii_buffer_commit(grn_ctx *ctx, grn_ii_buffer *ii_buffer);
+GRN_API grn_rc grn_ii_buffer_close(grn_ctx *ctx, grn_ii_buffer *ii_buffer);
+
+GRN_API grn_rc grn_ii_posting_add(grn_ctx *ctx, grn_posting *pos,
+ grn_hash *s, grn_operator op);
+GRN_API void grn_ii_resolve_sel_and(grn_ctx *ctx, grn_hash *s, grn_operator op);
+
+
+/* Experimental */
+typedef struct _grn_ii_cursor grn_ii_cursor;
+GRN_API grn_ii_cursor *grn_ii_cursor_open(grn_ctx *ctx, grn_ii *ii, grn_id tid,
+ grn_id min, grn_id max, int nelements, int flags);
+GRN_API grn_posting *grn_ii_cursor_next(grn_ctx *ctx, grn_ii_cursor *c);
+GRN_API grn_posting *grn_ii_cursor_next_pos(grn_ctx *ctx, grn_ii_cursor *c);
+GRN_API grn_rc grn_ii_cursor_close(grn_ctx *ctx, grn_ii_cursor *c);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/nfkc.h b/storage/mroonga/vendor/groonga/include/groonga/nfkc.h
new file mode 100644
index 00000000..e771fd9b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/nfkc.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <groonga.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_char_type grn_nfkc_char_type(const unsigned char *utf8);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/normalizer.h b/storage/mroonga/vendor/groonga/include/groonga/normalizer.h
new file mode 100644
index 00000000..b95ef6a2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/normalizer.h
@@ -0,0 +1,53 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <stddef.h>
+
+#include <groonga/plugin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ grn_normalizer_register() registers a normalizer to the database
+ which is associated with `ctx'. `name_ptr' and `name_length' specify
+ the normalizer name. `name_length' can be `-1'. `-1' means that
+ `name_ptr` is NULL-terminated. Alphabetic letters ('A'-'Z' and
+ 'a'-'z'), digits ('0'-'9') and an underscore ('_') are capable
+ characters. `init', `next' and `fin' specify the normalizer
+ functions. `init' is called for initializing a tokenizer for a
+ document or query. `next' is called for extracting tokens one by
+ one. `fin' is called for finalizing a
+ tokenizer. grn_tokenizer_register() returns GRN_SUCCESS on success,
+ an error code on failure. See "groonga.h" for more details of
+ grn_proc_func and grn_user_data, that is used as an argument of
+ grn_proc_func.
+ */
+GRN_PLUGIN_EXPORT grn_rc grn_normalizer_register(grn_ctx *ctx,
+ const char *name_ptr,
+ int name_length,
+ grn_proc_func *init,
+ grn_proc_func *next,
+ grn_proc_func *fin);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/obj.h b/storage/mroonga/vendor/groonga/include/groonga/obj.h
new file mode 100644
index 00000000..32cc2d2c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/obj.h
@@ -0,0 +1,81 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Just for backward compatibility. Use grn_obj_is_true() instead. */
+#define GRN_OBJ_IS_TRUE(ctx, obj, result) do { \
+ result = grn_obj_is_true(ctx, obj); \
+} while (0)
+
+GRN_API grn_bool grn_obj_is_true(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API grn_bool grn_obj_is_builtin(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_bulk(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_text_family_bulk(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_table(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_scalar_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_vector_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_weight_vector_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_reference_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_data_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_index_column(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_accessor(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_key_accessor(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_type(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_text_family_type(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_tokenizer_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_function_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_selector_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_selector_only_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_normalizer_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_token_filter_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_scorer_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_window_function_proc(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_expr(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API grn_rc grn_obj_cast(grn_ctx *ctx,
+ grn_obj *src,
+ grn_obj *dest,
+ grn_bool add_record_if_not_exist);
+
+GRN_API grn_rc grn_obj_reindex(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API void grn_obj_touch(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv);
+GRN_API uint32_t grn_obj_get_last_modified(grn_ctx *ctx, grn_obj *obj);
+GRN_API grn_bool grn_obj_is_dirty(grn_ctx *ctx, grn_obj *obj);
+
+GRN_API const char *grn_obj_type_to_string(uint8_t type);
+
+GRN_API grn_bool grn_obj_name_is_column(grn_ctx *ctx,
+ const char *name,
+ int name_len);
+
+GRN_API grn_bool grn_obj_is_corrupt(grn_ctx *ctx, grn_obj *obj);
+GRN_API size_t grn_obj_get_disk_usage(grn_ctx *ctx, grn_obj *obj);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/operator.h b/storage/mroonga/vendor/groonga/include/groonga/operator.h
new file mode 100644
index 00000000..7b45ac9e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/operator.h
@@ -0,0 +1,49 @@
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef grn_bool grn_operator_exec_func(grn_ctx *ctx,
+ grn_obj *x,
+ grn_obj *y);
+
+GRN_API const char *grn_operator_to_string(grn_operator op);
+GRN_API grn_operator_exec_func *grn_operator_to_exec_func(grn_operator op);
+GRN_API grn_bool grn_operator_exec_equal(grn_ctx *ctx, grn_obj *x, grn_obj *y);
+GRN_API grn_bool grn_operator_exec_not_equal(grn_ctx *ctx,
+ grn_obj *x, grn_obj *y);
+GRN_API grn_bool grn_operator_exec_less(grn_ctx *ctx, grn_obj *x, grn_obj *y);
+GRN_API grn_bool grn_operator_exec_greater(grn_ctx *ctx, grn_obj *x, grn_obj *y);
+GRN_API grn_bool grn_operator_exec_less_equal(grn_ctx *ctx,
+ grn_obj *x, grn_obj *y);
+GRN_API grn_bool grn_operator_exec_greater_equal(grn_ctx *ctx,
+ grn_obj *x, grn_obj *y);
+GRN_API grn_bool grn_operator_exec_match(grn_ctx *ctx,
+ grn_obj *target, grn_obj *sub_text);
+GRN_API grn_bool grn_operator_exec_prefix(grn_ctx *ctx,
+ grn_obj *target, grn_obj *prefix);
+GRN_API grn_bool grn_operator_exec_regexp(grn_ctx *ctx,
+ grn_obj *target, grn_obj *pattern);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/output.h b/storage/mroonga/vendor/groonga/include/groonga/output.h
new file mode 100644
index 00000000..cc33693c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/output.h
@@ -0,0 +1,124 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_obj_format grn_obj_format;
+
+#define GRN_OBJ_FORMAT_WITH_COLUMN_NAMES (0x01<<0)
+#define GRN_OBJ_FORMAT_AS_ARRAY (0x01<<3)
+/* Deprecated since 4.0.1. It will be removed at 5.0.0.
+ Use GRN_OBJ_FORMAT_AS_ARRAY instead.*/
+#define GRN_OBJ_FORMAT_ASARRAY GRN_OBJ_FORMAT_AS_ARRAY
+#define GRN_OBJ_FORMAT_WITH_WEIGHT (0x01<<4)
+
+struct _grn_obj_format {
+ grn_obj columns;
+ const void *min;
+ const void *max;
+ unsigned int min_size;
+ unsigned int max_size;
+ int nhits;
+ int offset;
+ int limit;
+ int hits_offset;
+ int flags;
+ grn_obj *expression;
+};
+
+#define GRN_OBJ_FORMAT_INIT(format,format_nhits,format_offset,format_limit,format_hits_offset) do { \
+ GRN_PTR_INIT(&(format)->columns, GRN_OBJ_VECTOR, GRN_ID_NIL);\
+ (format)->nhits = (format_nhits);\
+ (format)->offset = (format_offset);\
+ (format)->limit = (format_limit);\
+ (format)->hits_offset = (format_hits_offset);\
+ (format)->flags = 0;\
+ (format)->expression = NULL;\
+} while (0)
+
+#define GRN_OBJ_FORMAT_FIN(ctx,format) do {\
+ int ncolumns = GRN_BULK_VSIZE(&(format)->columns) / sizeof(grn_obj *);\
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&(format)->columns);\
+ while (ncolumns--) {\
+ grn_obj *column = *columns;\
+ columns++;\
+ if (grn_obj_is_accessor((ctx), column)) {\
+ grn_obj_close((ctx), column);\
+ }\
+ }\
+ GRN_OBJ_FIN((ctx), &(format)->columns);\
+ if ((format)->expression) { GRN_OBJ_FIN((ctx), (format)->expression); } \
+} while (0)
+
+GRN_API void grn_output_obj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *obj, grn_obj_format *format);
+GRN_API void grn_output_envelope(grn_ctx *ctx, grn_rc rc,
+ grn_obj *head, grn_obj *body, grn_obj *foot,
+ const char *file, int line);
+
+GRN_API void grn_ctx_output_flush(grn_ctx *ctx, int flags);
+GRN_API void grn_ctx_output_array_open(grn_ctx *ctx,
+ const char *name, int nelements);
+GRN_API void grn_ctx_output_array_close(grn_ctx *ctx);
+GRN_API void grn_ctx_output_map_open(grn_ctx *ctx,
+ const char *name, int nelements);
+GRN_API void grn_ctx_output_map_close(grn_ctx *ctx);
+GRN_API void grn_ctx_output_null(grn_ctx *ctx);
+GRN_API void grn_ctx_output_int32(grn_ctx *ctx, int value);
+GRN_API void grn_ctx_output_int64(grn_ctx *ctx, int64_t value);
+GRN_API void grn_ctx_output_uint64(grn_ctx *ctx, uint64_t value);
+GRN_API void grn_ctx_output_float(grn_ctx *ctx, double value);
+GRN_API void grn_ctx_output_cstr(grn_ctx *ctx, const char *value);
+GRN_API void grn_ctx_output_str(grn_ctx *ctx,
+ const char *value, unsigned int value_len);
+GRN_API void grn_ctx_output_bool(grn_ctx *ctx, grn_bool value);
+GRN_API void grn_ctx_output_obj(grn_ctx *ctx,
+ grn_obj *value, grn_obj_format *format);
+GRN_API void grn_ctx_output_result_set_open(grn_ctx *ctx,
+ grn_obj *result_set,
+ grn_obj_format *format,
+ uint32_t n_additional_elements);
+GRN_API void grn_ctx_output_result_set_close(grn_ctx *ctx,
+ grn_obj *result_set,
+ grn_obj_format *format);
+GRN_API void grn_ctx_output_result_set(grn_ctx *ctx,
+ grn_obj *result_set,
+ grn_obj_format *format);
+GRN_API void grn_ctx_output_table_columns(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj_format *format);
+GRN_API void grn_ctx_output_table_records(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj_format *format);
+
+
+GRN_API grn_content_type grn_ctx_get_output_type(grn_ctx *ctx);
+GRN_API grn_rc grn_ctx_set_output_type(grn_ctx *ctx, grn_content_type type);
+GRN_API const char *grn_ctx_get_mime_type(grn_ctx *ctx);
+
+/* obsolete */
+GRN_API grn_rc grn_text_otoj(grn_ctx *ctx, grn_obj *bulk, grn_obj *obj,
+ grn_obj_format *format);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/pat.h b/storage/mroonga/vendor/groonga/include/groonga/pat.h
new file mode 100644
index 00000000..c7008515
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/pat.h
@@ -0,0 +1,102 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_pat grn_pat;
+typedef struct _grn_pat_cursor grn_pat_cursor;
+typedef struct _grn_table_scan_hit grn_pat_scan_hit;
+
+GRN_API grn_pat *grn_pat_create(grn_ctx *ctx, const char *path, unsigned int key_size,
+ unsigned int value_size, unsigned int flags);
+
+GRN_API grn_pat *grn_pat_open(grn_ctx *ctx, const char *path);
+
+GRN_API grn_rc grn_pat_close(grn_ctx *ctx, grn_pat *pat);
+
+GRN_API grn_rc grn_pat_remove(grn_ctx *ctx, const char *path);
+
+GRN_API grn_id grn_pat_get(grn_ctx *ctx, grn_pat *pat, const void *key,
+ unsigned int key_size, void **value);
+GRN_API grn_id grn_pat_add(grn_ctx *ctx, grn_pat *pat, const void *key,
+ unsigned int key_size, void **value, int *added);
+
+GRN_API int grn_pat_get_key(grn_ctx *ctx, grn_pat *pat, grn_id id, void *keybuf, int bufsize);
+GRN_API int grn_pat_get_key2(grn_ctx *ctx, grn_pat *pat, grn_id id, grn_obj *bulk);
+GRN_API int grn_pat_get_value(grn_ctx *ctx, grn_pat *pat, grn_id id, void *valuebuf);
+GRN_API grn_rc grn_pat_set_value(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ const void *value, int flags);
+
+GRN_API grn_rc grn_pat_delete_by_id(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ grn_table_delete_optarg *optarg);
+GRN_API grn_rc grn_pat_delete(grn_ctx *ctx, grn_pat *pat, const void *key, unsigned int key_size,
+ grn_table_delete_optarg *optarg);
+GRN_API int grn_pat_delete_with_sis(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ grn_table_delete_optarg *optarg);
+
+GRN_API int grn_pat_scan(grn_ctx *ctx, grn_pat *pat, const char *str, unsigned int str_len,
+ grn_pat_scan_hit *sh, unsigned int sh_size, const char **rest);
+
+GRN_API grn_rc grn_pat_prefix_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, unsigned int key_size, grn_hash *h);
+GRN_API grn_rc grn_pat_suffix_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, unsigned int key_size, grn_hash *h);
+GRN_API grn_id grn_pat_lcp_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, unsigned int key_size);
+
+GRN_API unsigned int grn_pat_size(grn_ctx *ctx, grn_pat *pat);
+
+GRN_API grn_pat_cursor *grn_pat_cursor_open(grn_ctx *ctx, grn_pat *pat,
+ const void *min, unsigned int min_size,
+ const void *max, unsigned int max_size,
+ int offset, int limit, int flags);
+GRN_API grn_id grn_pat_cursor_next(grn_ctx *ctx, grn_pat_cursor *c);
+GRN_API void grn_pat_cursor_close(grn_ctx *ctx, grn_pat_cursor *c);
+
+GRN_API int grn_pat_cursor_get_key(grn_ctx *ctx, grn_pat_cursor *c, void **key);
+GRN_API int grn_pat_cursor_get_value(grn_ctx *ctx, grn_pat_cursor *c, void **value);
+
+GRN_API int grn_pat_cursor_get_key_value(grn_ctx *ctx, grn_pat_cursor *c,
+ void **key, unsigned int *key_size, void **value);
+GRN_API grn_rc grn_pat_cursor_set_value(grn_ctx *ctx, grn_pat_cursor *c,
+ const void *value, int flags);
+GRN_API grn_rc grn_pat_cursor_delete(grn_ctx *ctx, grn_pat_cursor *c,
+ grn_table_delete_optarg *optarg);
+
+#define GRN_PAT_EACH(ctx,pat,id,key,key_size,value,block) do { \
+ grn_pat_cursor *_sc = grn_pat_cursor_open(ctx, pat, NULL, 0, NULL, 0, 0, -1, 0); \
+ if (_sc) {\
+ grn_id id;\
+ while ((id = grn_pat_cursor_next(ctx, _sc))) {\
+ grn_pat_cursor_get_key_value(ctx, _sc, (void **)(key),\
+ (key_size), (void **)(value));\
+ block\
+ }\
+ grn_pat_cursor_close(ctx, _sc);\
+ }\
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/plugin.h b/storage/mroonga/vendor/groonga/include/groonga/plugin.h
new file mode 100644
index 00000000..23d3d606
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/plugin.h
@@ -0,0 +1,217 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <stddef.h>
+
+#include <groonga.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+# define GRN_PLUGIN_IMPL_NAME_RAW(type) \
+ grn_plugin_impl_ ## type
+# define GRN_PLUGIN_IMPL_NAME_TAGGED(type, tag) \
+ GRN_PLUGIN_IMPL_NAME_RAW(type ## _ ## tag)
+# define GRN_PLUGIN_IMPL_NAME_TAGGED_EXPANDABLE(type, tag) \
+ GRN_PLUGIN_IMPL_NAME_TAGGED(type, tag)
+
+#ifdef GRN_PLUGIN_FUNCTION_TAG
+# define GRN_PLUGIN_IMPL_NAME(type) \
+ GRN_PLUGIN_IMPL_NAME_TAGGED_EXPANDABLE(type, GRN_PLUGIN_FUNCTION_TAG)
+#else /* GRN_PLUGIN_FUNCTION_TAG */
+# define GRN_PLUGIN_IMPL_NAME(type) \
+ GRN_PLUGIN_IMPL_NAME_RAW(type)
+#endif /* GRN_PLUGIN_FUNCTION_TAG */
+
+#define GRN_PLUGIN_INIT GRN_PLUGIN_IMPL_NAME(init)
+#define GRN_PLUGIN_REGISTER GRN_PLUGIN_IMPL_NAME(register)
+#define GRN_PLUGIN_FIN GRN_PLUGIN_IMPL_NAME(fin)
+
+#if defined(_WIN32) || defined(_WIN64)
+# define GRN_PLUGIN_EXPORT __declspec(dllexport)
+#else /* defined(_WIN32) || defined(_WIN64) */
+# define GRN_PLUGIN_EXPORT
+#endif /* defined(_WIN32) || defined(_WIN64) */
+
+GRN_PLUGIN_EXPORT grn_rc GRN_PLUGIN_INIT(grn_ctx *ctx);
+GRN_PLUGIN_EXPORT grn_rc GRN_PLUGIN_REGISTER(grn_ctx *ctx);
+GRN_PLUGIN_EXPORT grn_rc GRN_PLUGIN_FIN(grn_ctx *ctx);
+
+#define GRN_PLUGIN_DECLARE_FUNCTIONS(tag) \
+ extern grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(init, tag)(grn_ctx *ctx); \
+ extern grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(register, tag)(grn_ctx *ctx); \
+ extern grn_rc GRN_PLUGIN_IMPL_NAME_TAGGED(fin, tag)(grn_ctx *ctx)
+
+/*
+ Don't call these functions directly. Use GRN_PLUGIN_MALLOC(),
+ GRN_PLUGIN_CALLOC(), GRN_PLUGIN_REALLOC() and GRN_PLUGIN_FREE() instead.
+ */
+GRN_API void *grn_plugin_malloc(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+GRN_API void *grn_plugin_calloc(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+GRN_API void *grn_plugin_realloc(grn_ctx *ctx,
+ void *ptr,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(3);
+GRN_API void grn_plugin_free(grn_ctx *ctx, void *ptr, const char *file,
+ int line, const char *func);
+
+#define GRN_PLUGIN_MALLOC(ctx, size) \
+ grn_plugin_malloc((ctx), (size), __FILE__, __LINE__, __FUNCTION__)
+#define GRN_PLUGIN_MALLOCN(ctx, type, n) \
+ ((type *)(grn_plugin_malloc((ctx), sizeof(type) * (n), \
+ __FILE__, __LINE__, __FUNCTION__)))
+#define GRN_PLUGIN_CALLOC(ctx, size) \
+ grn_plugin_calloc((ctx), (size), __FILE__, __LINE__, __FUNCTION__)
+#define GRN_PLUGIN_REALLOC(ctx, ptr, size) \
+ grn_plugin_realloc((ctx), (ptr), (size), __FILE__, __LINE__, __FUNCTION__)
+#define GRN_PLUGIN_FREE(ctx, ptr) \
+ grn_plugin_free((ctx), (ptr), __FILE__, __LINE__, __FUNCTION__)
+
+#define GRN_PLUGIN_LOG(ctx, level, ...) \
+ GRN_LOG((ctx), (level), __VA_ARGS__)
+
+/*
+ Don't call grn_plugin_set_error() directly. This function is used in
+ GRN_PLUGIN_SET_ERROR().
+ */
+GRN_API void grn_plugin_set_error(grn_ctx *ctx, grn_log_level level,
+ grn_rc error_code,
+ const char *file, int line, const char *func,
+ const char *format, ...) GRN_ATTRIBUTE_PRINTF(7);
+GRN_API void grn_plugin_clear_error(grn_ctx *ctx);
+
+
+/*
+ Don't call these functions directly. grn_plugin_backtrace() and
+ grn_plugin_logtrace() are used in GRN_PLUGIN_SET_ERROR().
+ */
+GRN_API void grn_plugin_backtrace(grn_ctx *ctx);
+GRN_API void grn_plugin_logtrace(grn_ctx *ctx, grn_log_level level);
+
+/*
+ Don't use GRN_PLUGIN_SET_ERROR() directly. This macro is used in
+ GRN_PLUGIN_ERROR().
+ */
+#define GRN_PLUGIN_SET_ERROR(ctx, level, error_code, ...) do { \
+ grn_plugin_set_error(ctx, level, error_code, \
+ __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__); \
+} while (0)
+
+#define GRN_PLUGIN_ERROR(ctx, error_code, ...) \
+ GRN_PLUGIN_SET_ERROR(ctx, GRN_LOG_ERROR, error_code, __VA_ARGS__)
+
+#define GRN_PLUGIN_CLEAR_ERROR(ctx) do { \
+ grn_plugin_clear_error((ctx)); \
+} while (0)
+
+typedef struct _grn_plugin_mutex grn_plugin_mutex;
+
+GRN_API grn_plugin_mutex *grn_plugin_mutex_open(grn_ctx *ctx);
+
+/*
+ grn_plugin_mutex_create() is deprecated. Use grn_plugin_mutex_open()
+ instead.
+*/
+GRN_API grn_plugin_mutex *grn_plugin_mutex_create(grn_ctx *ctx);
+
+GRN_API void grn_plugin_mutex_close(grn_ctx *ctx, grn_plugin_mutex *mutex);
+
+/*
+ grn_plugin_mutex_destroy() is deprecated. Use grn_plugin_mutex_close()
+ instead.
+*/
+GRN_API void grn_plugin_mutex_destroy(grn_ctx *ctx, grn_plugin_mutex *mutex);
+
+GRN_API void grn_plugin_mutex_lock(grn_ctx *ctx, grn_plugin_mutex *mutex);
+
+GRN_API void grn_plugin_mutex_unlock(grn_ctx *ctx, grn_plugin_mutex *mutex);
+
+GRN_API grn_obj *grn_plugin_proc_alloc(grn_ctx *ctx, grn_user_data *user_data,
+ grn_id domain, unsigned char flags);
+
+GRN_API grn_obj *grn_plugin_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data);
+
+GRN_API grn_obj *grn_plugin_proc_get_var(grn_ctx *ctx, grn_user_data *user_data,
+ const char *name, int name_size);
+GRN_API grn_bool grn_plugin_proc_get_var_bool(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ grn_bool default_value);
+GRN_API int32_t grn_plugin_proc_get_var_int32(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ int32_t default_value);
+GRN_API const char *grn_plugin_proc_get_var_string(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ size_t *size);
+GRN_API grn_content_type grn_plugin_proc_get_var_content_type(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ grn_content_type default_value);
+
+GRN_API grn_obj *grn_plugin_proc_get_var_by_offset(grn_ctx *ctx,
+ grn_user_data *user_data,
+ unsigned int offset);
+
+GRN_API grn_obj *grn_plugin_proc_get_caller(grn_ctx *ctx,
+ grn_user_data *user_data);
+
+/* Deprecated since 5.0.9. Use grn_plugin_windows_base_dir() instead. */
+GRN_API const char *grn_plugin_win32_base_dir(void);
+GRN_API const char *grn_plugin_windows_base_dir(void);
+
+GRN_API int grn_plugin_charlen(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding);
+
+GRN_API int grn_plugin_isspace(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding);
+
+GRN_API grn_rc grn_plugin_expr_var_init(grn_ctx *ctx,
+ grn_expr_var *var,
+ const char *name,
+ int name_size);
+
+GRN_API grn_obj *grn_plugin_command_create(grn_ctx *ctx,
+ const char *name,
+ int name_size,
+ grn_proc_func func,
+ unsigned int n_vars,
+ grn_expr_var *vars);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/portability.h b/storage/mroonga/vendor/groonga/include/groonga/portability.h
new file mode 100644
index 00000000..faee70b9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/portability.h
@@ -0,0 +1,201 @@
+/*
+ Copyright(C) 2015-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef WIN32
+# ifdef __cplusplus
+# define grn_memcpy(dest, src, n) ::memcpy_s((dest), (n), (src), (n))
+# else /* __cplusplus */
+# define grn_memcpy(dest, src, n) memcpy_s((dest), (n), (src), (n))
+# endif /* __cplusplus */
+#else /* WIN32 */
+# ifdef __cplusplus
+# define grn_memcpy(dest, src, n) std::memcpy((dest), (src), (n))
+# else /* __cplusplus */
+# define grn_memcpy(dest, src, n) memcpy((dest), (src), (n))
+# endif /* __cplusplus */
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_memmove(dest, src, n) memmove_s((dest), (n), (src), (n))
+#else /* WIN32 */
+# define grn_memmove(dest, src, n) memmove((dest), (src), (n))
+#endif /* WIN32 */
+
+#define GRN_ENV_BUFFER_SIZE 1024
+
+#ifdef WIN32
+# define grn_getenv(name, dest, dest_size) do { \
+ char *dest_ = (dest); \
+ size_t dest_size_ = (dest_size); \
+ if (dest_size_ > 0) { \
+ DWORD env_size; \
+ env_size = GetEnvironmentVariableA((name), dest_, dest_size_); \
+ if (env_size == 0 || env_size > dest_size_) { \
+ dest_[0] = '\0'; \
+ } \
+ } \
+ } while (0)
+#else /* WIN32 */
+# define grn_getenv(name, dest, dest_size) do { \
+ const char *env_value = getenv((name)); \
+ char *dest_ = (dest); \
+ size_t dest_size_ = (dest_size); \
+ if (dest_size_ > 0) { \
+ if (env_value) { \
+ strncpy(dest_, env_value, dest_size_ - 1); \
+ } else { \
+ dest_[0] = '\0'; \
+ } \
+ } \
+ } while (0)
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_fopen(name, mode) _fsopen((name), (mode), _SH_DENYNO)
+#else /* WIN32 */
+# define grn_fopen(name, mode) fopen((name), (mode))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strdup_raw(string) _strdup((string))
+#else /* WIN32 */
+# define grn_strdup_raw(string) strdup((string))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_unlink(filename) _unlink((filename))
+#else /* WIN32 */
+# define grn_unlink(filename) unlink((filename))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strncat(dest, dest_size, src, n) \
+ strncat_s((dest), (dest_size), (src), (n))
+#else /* WIN32 */
+# define grn_strncat(dest, dest_size, src, n) \
+ strncat((dest), (src), (n))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strcpy(dest, dest_size, src) \
+ strcpy_s((dest), (dest_size), (src))
+#else /* WIN32 */
+# define grn_strcpy(dest, dest_size, src) \
+ strcpy((dest), (src))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strncpy(dest, dest_size, src, n) \
+ strncpy_s((dest), (dest_size), (src), (n))
+#else /* WIN32 */
+# define grn_strncpy(dest, dest_size, src, n) \
+ strncpy((dest), (src), (n))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strcat(dest, dest_size, src) \
+ strcat_s((dest), (dest_size), (src))
+#else /* WIN32 */
+# define grn_strcat(dest, dest_size, src) \
+ strcat((dest), (src))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strcasecmp(string1, string2) \
+ _stricmp((string1), (string2))
+#else /* WIN32 */
+# define grn_strcasecmp(string1, string2) \
+ strcasecmp((string1), (string2))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_strncasecmp(string1, string2, n) \
+ _strnicmp((string1), (string2), (n))
+#else /* WIN32 */
+# define grn_strncasecmp(string1, string2, n) \
+ strncasecmp((string1), (string2), (n))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_snprintf(dest, dest_size, n, ...) do { \
+ _snprintf_s((dest), (dest_size), (n) - 1, __VA_ARGS__); \
+ } while (GRN_FALSE)
+#else /* WIN32 */
+# define grn_snprintf(dest, dest_size, n, ...) \
+ snprintf((dest), (n), __VA_ARGS__)
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_vsnprintf(dest, dest_size, format, args) do { \
+ vsnprintf((dest), (dest_size), (format), (args)); \
+ (dest)[(dest_size) - 1] = '\0'; \
+ } while (GRN_FALSE)
+#else /* WIN32 */
+# define grn_vsnprintf(dest, dest_size, format, args) \
+ vsnprintf((dest), (dest_size), (format), (args))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_write(fd, buf, count) _write((fd), (buf), (count))
+#else /* WIN32 */
+# define grn_write(fd, buf, count) write((fd), (buf), (count))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_read(fd, buf, count) _read((fd), (buf), (count))
+#else /* WIN32 */
+# define grn_read(fd, buf, count) read((fd), (buf), (count))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define GRN_OPEN_CREATE_MODE (_S_IREAD | _S_IWRITE)
+# define GRN_OPEN_FLAG_BINARY _O_BINARY
+# define grn_open(fd, pathname, flags) \
+ _sopen_s(&(fd), (pathname), (flags), _SH_DENYNO, GRN_OPEN_CREATE_MODE)
+#else /* WIN32 */
+# define GRN_OPEN_CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP)
+# define GRN_OPEN_FLAG_BINARY 0
+# define grn_open(fd, pathname, flags) \
+ (fd) = open((pathname), (flags), GRN_OPEN_CREATE_MODE)
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_close(fd) _close((fd))
+#else /* WIN32 */
+# define grn_close(fd) close((fd))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_fileno(stream) _fileno((stream))
+#else /* WIN32 */
+# define grn_fileno(stream) fileno((stream))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_isatty(stream) _isatty((stream))
+#else /* WIN32 */
+# define grn_isatty(stream) isatty((stream))
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define grn_getpid() _getpid()
+#else /* WIN32 */
+# define grn_getpid() getpid()
+#endif /* WIN32 */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/request_canceler.h b/storage/mroonga/vendor/groonga/include/groonga/request_canceler.h
new file mode 100644
index 00000000..5cb4702a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/request_canceler.h
@@ -0,0 +1,37 @@
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API void grn_request_canceler_register(grn_ctx *ctx,
+ const char *request_id,
+ unsigned int size);
+GRN_API void grn_request_canceler_unregister(grn_ctx *ctx,
+ const char *request_id,
+ unsigned int size);
+GRN_API grn_bool grn_request_canceler_cancel(const char *request_id,
+ unsigned int size);
+GRN_API grn_bool grn_request_canceler_cancel_all(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/request_timer.h b/storage/mroonga/vendor/groonga/include/groonga/request_timer.h
new file mode 100644
index 00000000..4bae968b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/request_timer.h
@@ -0,0 +1,53 @@
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_request_timer {
+ void *user_data;
+ void *(*register_func)(const char *request_id,
+ unsigned int request_id_size,
+ double timeout,
+ void *user_data);
+ void (*unregister_func)(void *timer_id,
+ void *user_data);
+ void (*fin_func)(void *user_data);
+} grn_request_timer;
+
+/* Multithreading unsafe. */
+GRN_API void grn_request_timer_set(grn_request_timer *timer);
+
+/* Multithreading safety is depends on grn_request_timer. */
+GRN_API void *grn_request_timer_register(const char *request_id,
+ unsigned int request_id_size,
+ double timeout);
+/* Multithreading safety is depends on grn_request_timer. */
+GRN_API void grn_request_timer_unregister(void *timer_id);
+
+
+GRN_API double grn_get_default_request_timeout(void);
+GRN_API void grn_set_default_request_timeout(double timeout);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/scorer.h b/storage/mroonga/vendor/groonga/include/groonga/scorer.h
new file mode 100644
index 00000000..5ef4db5d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/scorer.h
@@ -0,0 +1,93 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <groonga/plugin.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef struct _grn_scorer_matched_record grn_scorer_matched_record;
+
+GRN_API grn_obj *
+ grn_scorer_matched_record_get_table(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API grn_obj *
+ grn_scorer_matched_record_get_lexicon(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API grn_id
+ grn_scorer_matched_record_get_id(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API grn_obj *
+ grn_scorer_matched_record_get_terms(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API grn_obj *
+ grn_scorer_matched_record_get_term_weights(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API unsigned int
+ grn_scorer_matched_record_get_total_term_weights(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API long long unsigned int
+ grn_scorer_matched_record_get_n_documents(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API unsigned int
+ grn_scorer_matched_record_get_n_occurrences(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API long long unsigned int
+ grn_scorer_matched_record_get_n_candidates(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API unsigned int
+ grn_scorer_matched_record_get_n_tokens(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API int
+ grn_scorer_matched_record_get_weight(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+GRN_API grn_obj *
+ grn_scorer_matched_record_get_arg(grn_ctx *ctx,
+ grn_scorer_matched_record *record,
+ unsigned int i);
+GRN_API unsigned int
+ grn_scorer_matched_record_get_n_args(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+
+
+
+typedef double grn_scorer_score_func(grn_ctx *ctx,
+ grn_scorer_matched_record *record);
+
+/*
+ grn_scorer_register() registers a plugin to the database which is
+ associated with `ctx'. `scorer_name_ptr' and `scorer_name_length' specify the
+ plugin name. Alphabetic letters ('A'-'Z' and 'a'-'z'), digits ('0'-'9') and
+ an underscore ('_') are capable characters.
+
+ `score' is called for scoring matched records one by one.
+
+ grn_scorer_register() returns GRN_SUCCESS on success, an error
+ code on failure.
+ */
+GRN_PLUGIN_EXPORT grn_rc grn_scorer_register(grn_ctx *ctx,
+ const char *scorer_name_ptr,
+ int scorer_name_length,
+ grn_scorer_score_func *score);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/table.h b/storage/mroonga/vendor/groonga/include/groonga/table.h
new file mode 100644
index 00000000..c276df99
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/table.h
@@ -0,0 +1,246 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_TABLE_MAX_KEY_SIZE (0x1000)
+
+GRN_API grn_obj *grn_table_create(grn_ctx *ctx,
+ const char *name, unsigned int name_size,
+ const char *path, grn_table_flags flags,
+ grn_obj *key_type, grn_obj *value_type);
+
+#define GRN_TABLE_OPEN_OR_CREATE(ctx,name,name_size,path,flags,key_type,value_type,table) \
+ (((table) = grn_ctx_get((ctx), (name), (name_size))) ||\
+ ((table) = grn_table_create((ctx), (name), (name_size), (path), (flags), (key_type), (value_type))))
+
+/* TODO: int *added -> grn_bool *added */
+GRN_API grn_id grn_table_add(grn_ctx *ctx, grn_obj *table,
+ const void *key, unsigned int key_size, int *added);
+GRN_API grn_id grn_table_get(grn_ctx *ctx, grn_obj *table,
+ const void *key, unsigned int key_size);
+GRN_API grn_id grn_table_at(grn_ctx *ctx, grn_obj *table, grn_id id);
+GRN_API grn_id grn_table_lcp_search(grn_ctx *ctx, grn_obj *table,
+ const void *key, unsigned int key_size);
+GRN_API int grn_table_get_key(grn_ctx *ctx, grn_obj *table,
+ grn_id id, void *keybuf, int buf_size);
+GRN_API grn_rc grn_table_delete(grn_ctx *ctx, grn_obj *table,
+ const void *key, unsigned int key_size);
+GRN_API grn_rc grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id);
+GRN_API grn_rc grn_table_update_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
+ const void *dest_key, unsigned int dest_key_size);
+GRN_API grn_rc grn_table_update(grn_ctx *ctx, grn_obj *table,
+ const void *src_key, unsigned int src_key_size,
+ const void *dest_key, unsigned int dest_key_size);
+GRN_API grn_rc grn_table_truncate(grn_ctx *ctx, grn_obj *table);
+
+#define GRN_CURSOR_ASCENDING (0x00<<0)
+#define GRN_CURSOR_DESCENDING (0x01<<0)
+#define GRN_CURSOR_GE (0x00<<1)
+#define GRN_CURSOR_GT (0x01<<1)
+#define GRN_CURSOR_LE (0x00<<2)
+#define GRN_CURSOR_LT (0x01<<2)
+#define GRN_CURSOR_BY_KEY (0x00<<3)
+#define GRN_CURSOR_BY_ID (0x01<<3)
+#define GRN_CURSOR_PREFIX (0x01<<4)
+#define GRN_CURSOR_SIZE_BY_BIT (0x01<<5)
+#define GRN_CURSOR_RK (0x01<<6)
+
+GRN_API grn_table_cursor *grn_table_cursor_open(grn_ctx *ctx, grn_obj *table,
+ const void *min, unsigned int min_size,
+ const void *max, unsigned int max_size,
+ int offset, int limit, int flags);
+GRN_API grn_rc grn_table_cursor_close(grn_ctx *ctx, grn_table_cursor *tc);
+GRN_API grn_id grn_table_cursor_next(grn_ctx *ctx, grn_table_cursor *tc);
+GRN_API int grn_table_cursor_get_key(grn_ctx *ctx, grn_table_cursor *tc, void **key);
+GRN_API int grn_table_cursor_get_value(grn_ctx *ctx, grn_table_cursor *tc, void **value);
+GRN_API grn_rc grn_table_cursor_set_value(grn_ctx *ctx, grn_table_cursor *tc,
+ const void *value, int flags);
+GRN_API grn_rc grn_table_cursor_delete(grn_ctx *ctx, grn_table_cursor *tc);
+GRN_API grn_obj *grn_table_cursor_table(grn_ctx *ctx, grn_table_cursor *tc);
+
+GRN_API grn_obj *grn_index_cursor_open(grn_ctx *ctx, grn_table_cursor *tc, grn_obj *index,
+ grn_id rid_min, grn_id rid_max, int flags);
+GRN_API grn_posting *grn_index_cursor_next(grn_ctx *ctx, grn_obj *ic, grn_id *tid);
+
+#define GRN_TABLE_EACH(ctx,table,head,tail,id,key,key_size,value,block) do {\
+ (ctx)->errlvl = GRN_LOG_NOTICE;\
+ (ctx)->rc = GRN_SUCCESS;\
+ if ((ctx)->seqno & 1) {\
+ (ctx)->subno++;\
+ } else {\
+ (ctx)->seqno++;\
+ }\
+ if (table) {\
+ switch ((table)->header.type) {\
+ case GRN_TABLE_PAT_KEY :\
+ GRN_PAT_EACH((ctx), (grn_pat *)(table), (id), (key), (key_size), (value), block);\
+ break;\
+ case GRN_TABLE_DAT_KEY :\
+ GRN_DAT_EACH((ctx), (grn_dat *)(table), (id), (key), (key_size), block);\
+ break;\
+ case GRN_TABLE_HASH_KEY :\
+ GRN_HASH_EACH((ctx), (grn_hash *)(table), (id), (key), (key_size), (value), block);\
+ break;\
+ case GRN_TABLE_NO_KEY :\
+ GRN_ARRAY_EACH((ctx), (grn_array *)(table), (head), (tail), (id), (value), block);\
+ break;\
+ }\
+ }\
+ if ((ctx)->subno) {\
+ (ctx)->subno--;\
+ } else {\
+ (ctx)->seqno++;\
+ }\
+} while (0)
+
+#define GRN_TABLE_EACH_BEGIN(ctx, table, cursor, id) do {\
+ if ((table)) {\
+ grn_table_cursor *cursor;\
+ cursor = grn_table_cursor_open((ctx), (table),\
+ NULL, 0,\
+ NULL, 0,\
+ 0, -1, GRN_CURSOR_ASCENDING);\
+ if (cursor) {\
+ grn_id id;\
+ while ((id = grn_table_cursor_next((ctx), cursor))) {
+
+#define GRN_TABLE_EACH_BEGIN_FLAGS(ctx, table, cursor, id, flags) do {\
+ if ((table)) {\
+ grn_table_cursor *cursor;\
+ cursor = grn_table_cursor_open((ctx), (table),\
+ NULL, 0,\
+ NULL, 0,\
+ 0, -1, (flags));\
+ if (cursor) {\
+ grn_id id;\
+ while ((id = grn_table_cursor_next((ctx), cursor))) {
+
+#define GRN_TABLE_EACH_BEGIN_MIN(ctx, table, cursor, id,\
+ min, min_size, flags) do {\
+ if ((table)) {\
+ grn_table_cursor *cursor;\
+ cursor = grn_table_cursor_open((ctx), (table),\
+ (min), (min_size),\
+ NULL, 0,\
+ 0, -1, (flags));\
+ if (cursor) {\
+ grn_id id;\
+ while ((id = grn_table_cursor_next((ctx), cursor))) {
+
+#define GRN_TABLE_EACH_END(ctx, cursor)\
+ }\
+ grn_table_cursor_close((ctx), cursor);\
+ }\
+ }\
+} while (0)
+
+typedef struct _grn_table_sort_key grn_table_sort_key;
+typedef unsigned char grn_table_sort_flags;
+
+#define GRN_TABLE_SORT_ASC (0x00<<0)
+#define GRN_TABLE_SORT_DESC (0x01<<0)
+
+struct _grn_table_sort_key {
+ grn_obj *key;
+ grn_table_sort_flags flags;
+ int offset;
+};
+
+GRN_API int grn_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit,
+ grn_obj *result, grn_table_sort_key *keys, int n_keys);
+
+typedef struct _grn_table_group_result grn_table_group_result;
+typedef uint32_t grn_table_group_flags;
+
+#define GRN_TABLE_GROUP_CALC_COUNT (0x01<<3)
+#define GRN_TABLE_GROUP_CALC_MAX (0x01<<4)
+#define GRN_TABLE_GROUP_CALC_MIN (0x01<<5)
+#define GRN_TABLE_GROUP_CALC_SUM (0x01<<6)
+#define GRN_TABLE_GROUP_CALC_AVG (0x01<<7)
+
+struct _grn_table_group_result {
+ grn_obj *table;
+ unsigned char key_begin;
+ unsigned char key_end;
+ int limit;
+ grn_table_group_flags flags;
+ grn_operator op;
+ unsigned int max_n_subrecs;
+ grn_obj *calc_target;
+};
+
+GRN_API grn_rc grn_table_group(grn_ctx *ctx, grn_obj *table,
+ grn_table_sort_key *keys, int n_keys,
+ grn_table_group_result *results, int n_results);
+GRN_API grn_rc grn_table_setoperation(grn_ctx *ctx, grn_obj *table1, grn_obj *table2,
+ grn_obj *res, grn_operator op);
+GRN_API grn_rc grn_table_difference(grn_ctx *ctx, grn_obj *table1, grn_obj *table2,
+ grn_obj *res1, grn_obj *res2);
+GRN_API int grn_table_columns(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size,
+ grn_obj *res);
+
+GRN_API unsigned int grn_table_size(grn_ctx *ctx, grn_obj *table);
+
+GRN_API grn_rc grn_table_rename(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size);
+
+GRN_API grn_obj *grn_table_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
+ grn_obj *res, grn_operator op);
+
+GRN_API grn_table_sort_key *grn_table_sort_key_from_str(grn_ctx *ctx,
+ const char *str, unsigned int str_size,
+ grn_obj *table, unsigned int *nkeys);
+GRN_API grn_rc grn_table_sort_key_close(grn_ctx *ctx,
+ grn_table_sort_key *keys, unsigned int nkeys);
+
+GRN_API grn_bool grn_table_is_grouped(grn_ctx *ctx, grn_obj *table);
+
+GRN_API unsigned int grn_table_max_n_subrecs(grn_ctx *ctx, grn_obj *table);
+
+GRN_API grn_obj *grn_table_create_for_group(grn_ctx *ctx,
+ const char *name,
+ unsigned int name_size,
+ const char *path,
+ grn_obj *group_key,
+ grn_obj *value_type,
+ unsigned int max_n_subrecs);
+
+GRN_API unsigned int grn_table_get_subrecs(grn_ctx *ctx, grn_obj *table,
+ grn_id id, grn_id *subrecbuf,
+ int *scorebuf, int buf_size);
+
+GRN_API grn_obj *grn_table_tokenize(grn_ctx *ctx, grn_obj *table,
+ const char *str, unsigned int str_len,
+ grn_obj *buf, grn_bool addp);
+
+GRN_API grn_rc grn_table_apply_expr(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *output_column,
+ grn_obj *expr);
+
+GRN_API grn_id grn_table_find_reference_object(grn_ctx *ctx, grn_obj *table);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/thread.h b/storage/mroonga/vendor/groonga/include/groonga/thread.h
new file mode 100644
index 00000000..20bfcb39
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/thread.h
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API uint32_t grn_thread_get_limit(void);
+GRN_API void grn_thread_set_limit(uint32_t new_limit);
+
+
+typedef uint32_t (*grn_thread_get_limit_func)(void *data);
+GRN_API void grn_thread_set_get_limit_func(grn_thread_get_limit_func func,
+ void *data);
+typedef void (*grn_thread_set_limit_func)(uint32_t new_limit, void *data);
+GRN_API void grn_thread_set_set_limit_func(grn_thread_set_limit_func func,
+ void *data);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/time.h b/storage/mroonga/vendor/groonga/include/groonga/time.h
new file mode 100644
index 00000000..9f9427a7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/time.h
@@ -0,0 +1,61 @@
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <time.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_TIMEVAL_TO_MSEC(timeval) \
+ (((timeval)->tv_sec * GRN_TIME_MSEC_PER_SEC) + \
+ ((timeval)->tv_nsec / GRN_TIME_NSEC_PER_MSEC))
+
+#define GRN_TIME_NSEC_PER_SEC 1000000000
+#define GRN_TIME_NSEC_PER_SEC_F 1000000000.0
+#define GRN_TIME_NSEC_PER_MSEC 1000000
+#define GRN_TIME_NSEC_PER_USEC (GRN_TIME_NSEC_PER_SEC / GRN_TIME_USEC_PER_SEC)
+#define GRN_TIME_MSEC_PER_SEC 1000
+#define GRN_TIME_NSEC_TO_USEC(nsec) ((nsec) / GRN_TIME_NSEC_PER_USEC)
+#define GRN_TIME_USEC_TO_NSEC(usec) ((usec) * GRN_TIME_NSEC_PER_USEC)
+
+#define GRN_TIME_USEC_PER_SEC 1000000
+#define GRN_TIME_PACK(sec, usec) ((int64_t)(sec) * GRN_TIME_USEC_PER_SEC + (usec))
+#define GRN_TIME_UNPACK(time_value, sec, usec) do {\
+ sec = (time_value) / GRN_TIME_USEC_PER_SEC;\
+ usec = (time_value) % GRN_TIME_USEC_PER_SEC;\
+} while (0)
+
+GRN_API grn_rc grn_timeval_now(grn_ctx *ctx, grn_timeval *tv);
+
+GRN_API void grn_time_now(grn_ctx *ctx, grn_obj *obj);
+
+#define GRN_TIME_NOW(ctx,obj) (grn_time_now((ctx), (obj)))
+
+GRN_API grn_bool grn_time_to_tm(grn_ctx *ctx,
+ int64_t time,
+ struct tm *tm);
+GRN_API grn_bool grn_time_from_tm(grn_ctx *ctx,
+ int64_t *time,
+ struct tm *tm);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/token.h b/storage/mroonga/vendor/groonga/include/groonga/token.h
new file mode 100644
index 00000000..c40203c6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/token.h
@@ -0,0 +1,135 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/*
+ * grn_tokenize_mode describes propose for tokenization.
+ *
+ * `GRN_TOKENIZE_GET`: Tokenize for search.
+ *
+ * `GRN_TOKENIZE_ADD`: Tokenize for adding token to index.
+ *
+ * `GRN_TOKENIZE_DELETE`: Tokenize for deleting token from index.
+ *
+ * @since 4.0.8
+ */
+typedef enum {
+ GRN_TOKENIZE_GET = 0,
+ GRN_TOKENIZE_ADD,
+ GRN_TOKENIZE_DELETE,
+ GRN_TOKENIZE_ONLY
+} grn_tokenize_mode;
+
+/*
+ grn_token_mode describes propose for tokenization.
+
+ `GRN_TOKEN_GET`: Tokenization for search.
+
+ `GRN_TOKEN_ADD`: Tokenization for adding token to index.
+
+ `GRN_TOKEN_DEL`: Tokenization for deleting token from index.
+
+ @since 4.0.7
+ @deprecated since 4.0.8. Use grn_tokenize_mode instead.
+ */
+typedef grn_tokenize_mode grn_token_mode;
+
+#define GRN_TOKEN_GET GRN_TOKENIZE_GET
+#define GRN_TOKEN_ADD GRN_TOKENIZE_ADD
+#define GRN_TOKEN_DEL GRN_TOKENIZE_DELETE
+
+/*
+ * grn_token_status is a flag set for tokenizer status codes.
+ * If a document or query contains no tokens, push an empty string with
+ * GRN_TOKEN_LAST as a token.
+ *
+ * @since 4.0.8
+ */
+typedef unsigned int grn_token_status;
+
+/*
+ * GRN_TOKEN_CONTINUE means that the next token is not the last one.
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_CONTINUE (0)
+/*
+ * GRN_TOKEN_LAST means that the next token is the last one.
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_LAST (0x01L<<0)
+/*
+ * GRN_TOKEN_OVERLAP means that ...
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_OVERLAP (0x01L<<1)
+/*
+ * GRN_TOKEN_UNMATURED means that ...
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_UNMATURED (0x01L<<2)
+/*
+ * GRN_TOKEN_REACH_END means that ...
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_REACH_END (0x01L<<3)
+/*
+ * GRN_TOKEN_SKIP means that the token is skipped
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_SKIP (0x01L<<4)
+/*
+ * GRN_TOKEN_SKIP_WITH_POSITION means that the token and postion is skipped
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_SKIP_WITH_POSITION (0x01L<<5)
+/*
+ * GRN_TOKEN_FORCE_PREIX that the token is used common prefix search
+ *
+ * @since 4.0.8
+ */
+#define GRN_TOKEN_FORCE_PREFIX (0x01L<<6)
+
+typedef struct _grn_token grn_token;
+
+GRN_PLUGIN_EXPORT grn_obj *grn_token_get_data(grn_ctx *ctx,
+ grn_token *token);
+GRN_PLUGIN_EXPORT grn_rc grn_token_set_data(grn_ctx *ctx,
+ grn_token *token,
+ const char *str_ptr,
+ int str_length);
+GRN_PLUGIN_EXPORT grn_token_status grn_token_get_status(grn_ctx *ctx,
+ grn_token *token);
+GRN_PLUGIN_EXPORT grn_rc grn_token_set_status(grn_ctx *ctx,
+ grn_token *token,
+ grn_token_status status);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/token_filter.h b/storage/mroonga/vendor/groonga/include/groonga/token_filter.h
new file mode 100644
index 00000000..982f7df7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/token_filter.h
@@ -0,0 +1,67 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <groonga/tokenizer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef void *grn_token_filter_init_func(grn_ctx *ctx,
+ grn_obj *table,
+ grn_tokenize_mode mode);
+
+typedef void grn_token_filter_filter_func(grn_ctx *ctx,
+ grn_token *current_token,
+ grn_token *next_token,
+ void *user_data);
+
+typedef void grn_token_filter_fin_func(grn_ctx *ctx,
+ void *user_data);
+
+
+/*
+ grn_token_filter_register() registers a plugin to the database which is
+ associated with `ctx'. `plugin_name_ptr' and `plugin_name_length' specify the
+ plugin name. Alphabetic letters ('A'-'Z' and 'a'-'z'), digits ('0'-'9') and
+ an underscore ('_') are capable characters.
+
+ `init', `filter' and `fin' specify the plugin functions.
+
+ `init' is called for initializing a token_filter for a document or
+ query.
+
+ `filter' is called for filtering tokens one by one.
+
+ `fin' is called for finalizing a token_filter.
+
+ grn_token_filter_register() returns GRN_SUCCESS on success, an error
+ code on failure.
+ */
+GRN_PLUGIN_EXPORT grn_rc grn_token_filter_register(grn_ctx *ctx,
+ const char *plugin_name_ptr,
+ int plugin_name_length,
+ grn_token_filter_init_func *init,
+ grn_token_filter_filter_func *filter,
+ grn_token_filter_fin_func *fin);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/tokenizer.h b/storage/mroonga/vendor/groonga/include/groonga/tokenizer.h
new file mode 100644
index 00000000..a29c9e9e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/tokenizer.h
@@ -0,0 +1,260 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include <groonga/plugin.h>
+#include <groonga/token.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#define GRN_TOKENIZER_TOKENIZED_DELIMITER_UTF8 "\xEF\xBF\xBE"
+#define GRN_TOKENIZER_TOKENIZED_DELIMITER_UTF8_LEN 3
+
+/*
+ grn_tokenizer_charlen() returns the length (#bytes) of the first character
+ in the string specified by `str_ptr' and `str_length'. If the starting bytes
+ are invalid as a character, grn_tokenizer_charlen() returns 0. See
+ grn_encoding in "groonga.h" for more details of `encoding'
+
+ Deprecated. Use grn_plugin_charlen() instead.
+ */
+int grn_tokenizer_charlen(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding);
+
+/*
+ grn_tokenizer_isspace() returns the length (#bytes) of the first character
+ in the string specified by `str_ptr' and `str_length' if it is a space
+ character. Otherwise, grn_tokenizer_isspace() returns 0.
+
+ Deprecated. Use grn_plugin_isspace() instead.
+ */
+int grn_tokenizer_isspace(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding);
+
+/*
+ grn_tokenizer_is_tokenized_delimiter() returns whether is the first
+ character in the string specified by `str_ptr' and `str_length' the
+ special tokenized delimiter character or not.
+ */
+grn_bool grn_tokenizer_is_tokenized_delimiter(grn_ctx *ctx,
+ const char *str_ptr,
+ unsigned int str_length,
+ grn_encoding encoding);
+
+/*
+ grn_tokenizer_have_tokenized_delimiter() returns whether is there
+ the special delimiter character in the string specified by `str_ptr'
+ and `str_length' the special tokenized delimiter character or not.
+ */
+GRN_PLUGIN_EXPORT grn_bool grn_tokenizer_have_tokenized_delimiter(grn_ctx *ctx,
+ const char *str_ptr,
+ unsigned int str_length,
+ grn_encoding encoding);
+
+/*
+ grn_tokenizer_query is a structure for storing a query. See the following
+ functions.
+ */
+typedef struct _grn_tokenizer_query grn_tokenizer_query;
+
+struct _grn_tokenizer_query {
+ grn_obj *normalized_query;
+ char *query_buf;
+ const char *ptr;
+ unsigned int length;
+ grn_encoding encoding;
+ unsigned int flags;
+ grn_bool have_tokenized_delimiter;
+ /* Deprecated since 4.0.8. Use tokenize_mode instead. */
+ grn_token_mode token_mode;
+ grn_tokenize_mode tokenize_mode;
+};
+
+/*
+ grn_tokenizer_query_open() parses `args' and returns a new object of
+ grn_tokenizer_query. The new object stores information of the query.
+ grn_tokenizer_query_open() normalizes the query if the target table
+ requires normalization. grn_tokenizer_query_open() returns NULL if
+ something goes wrong. Note that grn_tokenizer_query_open() must be called
+ just once in the function that initializes a tokenizer.
+
+ See `GRN_STRING_*' flags for `normalize_flags'.
+ */
+GRN_PLUGIN_EXPORT grn_tokenizer_query *grn_tokenizer_query_open(grn_ctx *ctx,
+ int num_args, grn_obj **args,
+ unsigned int normalize_flags);
+
+/*
+ grn_tokenizer_query_create() is deprecated. Use grn_tokenizer_query_open()
+ instead.
+*/
+
+grn_tokenizer_query *grn_tokenizer_query_create(grn_ctx *ctx,
+ int num_args, grn_obj **args);
+
+/*
+ grn_tokenizer_query_close() finalizes an object of grn_tokenizer_query
+ and then frees memory allocated for that object.
+ */
+GRN_PLUGIN_EXPORT void grn_tokenizer_query_close(grn_ctx *ctx, grn_tokenizer_query *query);
+
+/*
+ grn_tokenizer_query_destroy() is deprecated. Use grn_tokenizer_query_close()
+ instead.
+ */
+void grn_tokenizer_query_destroy(grn_ctx *ctx, grn_tokenizer_query *query);
+
+/*
+ grn_tokenizer_token is needed to return tokens. A grn_tokenizer_token object
+ stores a token to be returned and it must be maintained until a request for
+ next token or finalization comes.
+ */
+typedef struct _grn_tokenizer_token grn_tokenizer_token;
+
+struct _grn_tokenizer_token {
+ grn_obj str;
+ grn_obj status;
+};
+
+/*
+ grn_tokenizer_token_init() initializes `token'. Note that an initialized
+ object must be finalized by grn_tokenizer_token_fin().
+ */
+GRN_PLUGIN_EXPORT void grn_tokenizer_token_init(grn_ctx *ctx, grn_tokenizer_token *token);
+
+/*
+ grn_tokenizer_token_fin() finalizes `token' that has been initialized by
+ grn_tokenizer_token_init().
+ */
+GRN_PLUGIN_EXPORT void grn_tokenizer_token_fin(grn_ctx *ctx, grn_tokenizer_token *token);
+
+/*
+ * grn_tokenizer_status is a flag set for tokenizer status codes.
+ * If a document or query contains no tokens, push an empty string with
+ * GRN_TOKENIZER_TOKEN_LAST as a token.
+ *
+ * @deprecated since 4.0.8. Use grn_token_status instead.
+ */
+typedef grn_token_status grn_tokenizer_status;
+
+/*
+ * GRN_TOKENIZER_TOKEN_CONTINUE means that the next token is not the last one.
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_CONTINUE instead.
+ */
+#define GRN_TOKENIZER_TOKEN_CONTINUE GRN_TOKEN_CONTINUE
+/*
+ * GRN_TOKENIZER_TOKEN_LAST means that the next token is the last one.
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_LAST instead.
+ */
+#define GRN_TOKENIZER_TOKEN_LAST GRN_TOKEN_LAST
+/*
+ * GRN_TOKENIZER_TOKEN_OVERLAP means that ...
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_OVERLAP instead.
+ */
+#define GRN_TOKENIZER_TOKEN_OVERLAP GRN_TOKEN_OVERLAP
+/*
+ * GRN_TOKENIZER_TOKEN_UNMATURED means that ...
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_UNMATURED instead.
+ */
+#define GRN_TOKENIZER_TOKEN_UNMATURED GRN_TOKEN_UNMATURED
+/*
+ * GRN_TOKENIZER_TOKEN_REACH_END means that ...
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_REACH_END instead.
+ */
+#define GRN_TOKENIZER_TOKEN_REACH_END GRN_TOKEN_REACH_END
+/*
+ * GRN_TOKENIZER_TOKEN_SKIP means that the token is skipped
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_SKIP instead.
+ */
+#define GRN_TOKENIZER_TOKEN_SKIP GRN_TOKEN_SKIP
+/*
+ * GRN_TOKENIZER_TOKEN_SKIP_WITH_POSITION means that the token and postion is skipped
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_SKIP_WITH_POSITION instead.
+ */
+#define GRN_TOKENIZER_TOKEN_SKIP_WITH_POSITION GRN_TOKEN_SKIP_WITH_POSITION
+/*
+ * GRN_TOKENIZER_TOKEN_FORCE_PREIX that the token is used common prefix search
+ *
+ * @deprecated since 4.0.8. Use GRN_TOKEN_FORCE_PREIX instead.
+ */
+#define GRN_TOKENIZER_TOKEN_FORCE_PREFIX GRN_TOKEN_FORCE_PREFIX
+
+/*
+ * GRN_TOKENIZER_CONTINUE and GRN_TOKENIZER_LAST are deprecated. They
+ * are just for backward compatibility. Use
+ * GRN_TOKENIZER_TOKEN_CONTINUE and GRN_TOKENIZER_TOKEN_LAST
+ * instead.
+ */
+#define GRN_TOKENIZER_CONTINUE GRN_TOKENIZER_TOKEN_CONTINUE
+#define GRN_TOKENIZER_LAST GRN_TOKENIZER_TOKEN_LAST
+
+/*
+ grn_tokenizer_token_push() pushes the next token into `token'. Note that
+ grn_tokenizer_token_push() does not make a copy of the given string. This
+ means that you have to maintain a memory space allocated to the string.
+ Also note that the grn_tokenizer_token object must be maintained until the
+ request for the next token or finalization comes. See grn_token_status in
+ this header for more details of `status'.
+ */
+GRN_PLUGIN_EXPORT void grn_tokenizer_token_push(grn_ctx *ctx, grn_tokenizer_token *token,
+ const char *str_ptr, unsigned int str_length,
+ grn_token_status status);
+
+/*
+ grn_tokenizer_tokenized_delimiter_next() extracts the next token
+ from the string specified by `str_ptr' and `str_length' and pushes
+ the next token into `token'. It returns the string after the next
+ token. The returned string may be `NULL' when all tokens are
+ extracted.
+ */
+GRN_PLUGIN_EXPORT const char *grn_tokenizer_tokenized_delimiter_next(grn_ctx *ctx,
+ grn_tokenizer_token *token,
+ const char *str_ptr,
+ unsigned int str_length,
+ grn_encoding encoding);
+
+/*
+ grn_tokenizer_register() registers a plugin to the database which is
+ associated with `ctx'. `plugin_name_ptr' and `plugin_name_length' specify the
+ plugin name. Alphabetic letters ('A'-'Z' and 'a'-'z'), digits ('0'-'9') and
+ an underscore ('_') are capable characters. `init', `next' and `fin' specify
+ the plugin functions. `init' is called for initializing a tokenizer for a
+ document or query. `next' is called for extracting tokens one by one. `fin'
+ is called for finalizing a tokenizer. grn_tokenizer_register() returns
+ GRN_SUCCESS on success, an error code on failure. See "groonga.h" for more
+ details of grn_proc_func and grn_user_data, that is used as an argument of
+ grn_proc_func.
+ */
+GRN_PLUGIN_EXPORT grn_rc grn_tokenizer_register(grn_ctx *ctx, const char *plugin_name_ptr,
+ unsigned int plugin_name_length,
+ grn_proc_func *init, grn_proc_func *next,
+ grn_proc_func *fin);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
diff --git a/storage/mroonga/vendor/groonga/include/groonga/type.h b/storage/mroonga/vendor/groonga/include/groonga/type.h
new file mode 100644
index 00000000..7e9c1594
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/type.h
@@ -0,0 +1,40 @@
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Just for backward compatibility.
+ Use grn_type_id_is_text_family() instead. */
+#define GRN_TYPE_IS_TEXT_FAMILY(type) \
+ grn_type_id_is_text_family(NULL, (type))
+
+GRN_API grn_bool grn_type_id_is_builtin(grn_ctx *ctx, grn_id id);
+GRN_API grn_bool grn_type_id_is_number_family(grn_ctx *ctx, grn_id id);
+GRN_API grn_bool grn_type_id_is_text_family(grn_ctx *ctx, grn_id id);
+
+GRN_API grn_obj *grn_type_create(grn_ctx *ctx, const char *name, unsigned int name_size,
+ grn_obj_flags flags, unsigned int size);
+GRN_API uint32_t grn_type_size(grn_ctx *ctx, grn_obj *type);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/util.h b/storage/mroonga/vendor/groonga/include/groonga/util.h
new file mode 100644
index 00000000..4c9b704c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/util.h
@@ -0,0 +1,44 @@
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_obj *grn_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *obj);
+GRN_API grn_obj *grn_inspect_indented(grn_ctx *ctx, grn_obj *buffer,
+ grn_obj *obj, const char *indent);
+GRN_API grn_obj *grn_inspect_limited(grn_ctx *ctx,
+ grn_obj *buffer,
+ grn_obj *obj);
+GRN_API grn_obj *grn_inspect_name(grn_ctx *ctx, grn_obj *buffer, grn_obj *obj);
+GRN_API grn_obj *grn_inspect_encoding(grn_ctx *ctx, grn_obj *buffer, grn_encoding encoding);
+GRN_API grn_obj *grn_inspect_type(grn_ctx *ctx, grn_obj *buffer, unsigned char type);
+GRN_API grn_obj *grn_inspect_query_log_flags(grn_ctx *ctx,
+ grn_obj *buffer,
+ unsigned int flags);
+
+GRN_API void grn_p(grn_ctx *ctx, grn_obj *obj);
+GRN_API void grn_p_geo_point(grn_ctx *ctx, grn_geo_point *point);
+GRN_API void grn_p_ii_values(grn_ctx *ctx, grn_obj *obj);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/window_function.h b/storage/mroonga/vendor/groonga/include/groonga/window_function.h
new file mode 100644
index 00000000..56ca323c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/window_function.h
@@ -0,0 +1,73 @@
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ GRN_WINDOW_DIRECTION_ASCENDING,
+ GRN_WINDOW_DIRECTION_DESCENDING
+} grn_window_direction;
+
+typedef struct _grn_window grn_window;
+
+GRN_API grn_id grn_window_next(grn_ctx *ctx,
+ grn_window *window);
+GRN_API grn_rc grn_window_rewind(grn_ctx *ctx,
+ grn_window *window);
+GRN_API grn_rc grn_window_set_direction(grn_ctx *ctx,
+ grn_window *window,
+ grn_window_direction direction);
+GRN_API grn_obj *grn_window_get_table(grn_ctx *ctx,
+ grn_window *window);
+GRN_API grn_bool grn_window_is_sorted(grn_ctx *ctx,
+ grn_window *window);
+GRN_API size_t grn_window_get_size(grn_ctx *ctx,
+ grn_window *window);
+
+typedef struct _grn_window_definition {
+ grn_table_sort_key *sort_keys;
+ size_t n_sort_keys;
+ grn_table_sort_key *group_keys;
+ size_t n_group_keys;
+} grn_window_definition;
+
+typedef grn_rc grn_window_function_func(grn_ctx *ctx,
+ grn_obj *output_column,
+ grn_window *window,
+ grn_obj **args,
+ int n_args);
+
+GRN_API grn_obj *grn_window_function_create(grn_ctx *ctx,
+ const char *name,
+ int name_size,
+ grn_window_function_func func);
+
+
+GRN_API grn_rc grn_table_apply_window_function(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *output_column,
+ grn_window_definition *definition,
+ grn_obj *window_function_call);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/windows.h b/storage/mroonga/vendor/groonga/include/groonga/windows.h
new file mode 100644
index 00000000..fe4e5227
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/windows.h
@@ -0,0 +1,31 @@
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+GRN_API const char *grn_windows_base_dir(void);
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/include/groonga/windows_event_logger.h b/storage/mroonga/vendor/groonga/include/groonga/windows_event_logger.h
new file mode 100644
index 00000000..ca838f81
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/include/groonga/windows_event_logger.h
@@ -0,0 +1,30 @@
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_rc grn_windows_event_logger_set(grn_ctx *ctx,
+ const char *event_source_name);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/CMakeLists.txt b/storage/mroonga/vendor/groonga/lib/CMakeLists.txt
new file mode 100644
index 00000000..4f076458
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/CMakeLists.txt
@@ -0,0 +1,190 @@
+# Copyright(C) 2012-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+add_definitions(
+ -DGRN_DAT_EXPORT
+ )
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/dat
+ ${ONIGMO_INCLUDE_DIRS}
+ ${MRUBY_INCLUDE_DIRS}
+ ${LIBLZ4_INCLUDE_DIRS}
+ ${LIBZSTD_INCLUDE_DIRS}
+ ${MESSAGE_PACK_INCLUDE_DIRS})
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/c_sources.am LIBGROONGA_C_SOURCES)
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/cpp_sources.am LIBGROONGA_CPP_SOURCES)
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/dat/sources.am LIBGRNDAT_SOURCES)
+string(REGEX REPLACE "([^;]+)" "dat/\\1"
+ LIBGRNDAT_SOURCES "${LIBGRNDAT_SOURCES}")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/sources.am LIBGRNMRB_SOURCES)
+string(REGEX REPLACE "([^;]+)" "mrb/\\1"
+ LIBGRNMRB_SOURCES "${LIBGRNMRB_SOURCES}")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/proc/sources.am LIBGRNPROC_SOURCES)
+string(REGEX REPLACE "([^;]+)" "proc/\\1"
+ LIBGRNPROC_SOURCES "${LIBGRNPROC_SOURCES}")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/ts/sources.am LIBGRNTS_SOURCES)
+string(REGEX REPLACE "([^;]+)" "ts/\\1"
+ LIBGRNTS_SOURCES "${LIBGRNTS_SOURCES}")
+
+if(WIN32)
+ configure_file(
+ "metadata.rc.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/metadata.rc"
+ @ONLY)
+ set(LIBGROONGA_METADATA_SOURCES
+ "${CMAKE_CURRENT_BINARY_DIR}/metadata.rc")
+else()
+ set(LIBGROONGA_METADATA_SOURCES)
+endif()
+
+set_source_files_properties(
+ ${LIBGROONGA_C_SOURCES}
+ ${LIBGRNMRB_SOURCES}
+ ${LIBGRNPROC_SOURCES}
+ ${LIBGRNTS_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+set_source_files_properties(
+ ${LIBGROONGA_C_SOURCES}
+ ${LIBGROONGA_CPP_SOURCES}
+ ${LIBGRNMRB_SOURCES}
+ PROPERTIES
+ COMPILE_DEFINITIONS "${MRUBY_DEFINITIONS}")
+set_source_files_properties(
+ ${LIBGROONGA_CPP_SOURCES}
+ ${LIBGRNDAT_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS}")
+
+set(GRN_ALL_SOURCES
+ ${LIBGROONGA_C_SOURCES}
+ ${LIBGROONGA_CPP_SOURCES}
+ ${LIBGRNDAT_SOURCES}
+ ${LIBGRNMRB_SOURCES}
+ ${LIBGRNPROC_SOURCES}
+ ${LIBGRNTS_SOURCES}
+ ${LIBGROONGA_METADATA_SOURCES})
+if(GRN_EMBED)
+ add_library(libgroonga STATIC ${GRN_ALL_SOURCES})
+ set_target_properties(
+ libgroonga
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(libgroonga SHARED ${GRN_ALL_SOURCES})
+endif()
+set_target_properties(libgroonga PROPERTIES OUTPUT_NAME "groonga")
+
+if (HAVE_GCC_C11_ATOMICS_WITH_LIBATOMIC)
+ set(ATOMIC_LIBS atomic)
+endif()
+
+set(GRN_ALL_LIBRARIES
+ ${ATOMIC_LIBS}
+ ${EXECINFO_LIBS}
+ ${RT_LIBS}
+ ${PTHREAD_LIBS}
+ ${Z_LIBS}
+ ${LZ4_LIBS}
+ ${LIBZSTD_LIBS}
+ ${MESSAGE_PACK_LIBS}
+ ${CMAKE_DL_LIBS}
+ ${M_LIBS}
+ ${WS2_32_LIBS}
+ ${MRUBY_LIBS}
+ ${ONIGMO_LIBS})
+if(GRN_EMBED)
+ set(GRN_EMBEDDED_PLUGIN_LIBRARIES "")
+ if(GRN_WITH_MECAB)
+ list(APPEND GRN_EMBEDDED_PLUGIN_LIBRARIES mecab_tokenizer)
+ endif()
+ target_link_libraries(libgroonga
+ ${GRN_ALL_LIBRARIES}
+ ${STDCPP_LIBS}
+ ${GRN_EMBEDDED_PLUGIN_LIBRARIES})
+else()
+ target_link_libraries(libgroonga
+ ${GRN_ALL_LIBRARIES})
+ install(TARGETS libgroonga
+ ARCHIVE DESTINATION "${LIB_DIR}"
+ LIBRARY DESTINATION "${LIB_DIR}"
+ RUNTIME DESTINATION "${BIN_DIR}")
+endif()
+
+if(GRN_WITH_MRUBY)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/sources.am
+ RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/\\1"
+ RUBY_SCRIPTS "${RUBY_SCRIPTS}")
+ install(
+ FILES ${RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/command_line/sources.am
+ COMMANE_LINE_RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/command_line/\\1"
+ COMMANE_LINE_RUBY_SCRIPTS "${COMMANE_LINE_RUBY_SCRIPTS}")
+ install(
+ FILES ${COMMANE_LINE_RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}/command_line")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/context/sources.am
+ CONTEXT_RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/context/\\1"
+ CONTEXT_RUBY_SCRIPTS "${CONTEXT_RUBY_SCRIPTS}")
+ install(
+ FILES ${CONTEXT_RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}/context")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/initialize/sources.am
+ INITIALIZE_RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/initialize/\\1"
+ INITIALIZE_RUBY_SCRIPTS "${INITIALIZE_RUBY_SCRIPTS}")
+ install(
+ FILES ${INITIALIZE_RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}/initialize")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/logger/sources.am
+ LOGGER_RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/logger/\\1"
+ LOGGER_RUBY_SCRIPTS "${LOGGER_RUBY_SCRIPTS}")
+ install(
+ FILES ${LOGGER_RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}/logger")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/query_logger/sources.am
+ QUERY_LOGGER_RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/query_logger/\\1"
+ QUERY_LOGGER_RUBY_SCRIPTS "${QUERY_LOGGER_RUBY_SCRIPTS}")
+ install(
+ FILES ${QUERY_LOGGER_RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}/query_logger")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mrb/scripts/expression_tree/sources.am
+ EXPRESSION_TREE_RUBY_SCRIPTS)
+ string(REGEX REPLACE "([^;]+)" "mrb/scripts/expression_tree/\\1"
+ EXPRESSION_TREE_RUBY_SCRIPTS "${EXPRESSION_TREE_RUBY_SCRIPTS}")
+ install(
+ FILES ${EXPRESSION_TREE_RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_SCRIPTS_DIR}/expression_tree")
+endif()
+
+# Workaround GCC ICE on ARM64
+IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" AND
+ CMAKE_C_COMPILER_VERSION VERSION_GREATER "5")
+ ADD_COMPILE_FLAGS(ts/ts_expr_node.c COMPILE_FLAGS "-fno-tree-loop-vectorize")
+ENDIF()
diff --git a/storage/mroonga/vendor/groonga/lib/Makefile.am b/storage/mroonga/vendor/groonga/lib/Makefile.am
new file mode 100644
index 00000000..9a2217ee
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/Makefile.am
@@ -0,0 +1,99 @@
+SUBDIRS = \
+ dat \
+ mrb \
+ proc \
+ ts
+
+lib_LTLIBRARIES = libgroonga.la
+
+include $(top_srcdir)/version.sh
+
+AM_CPPFLAGS = \
+ $(MRUBY_CPPFLAGS)
+
+AM_CFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS) \
+ $(LIBLZ4_CFLAGS) \
+ $(LIBZSTD_CFLAGS)
+
+AM_CXXFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CXXFLAGS) \
+ $(ARROW_CFLAGS)
+
+BUNDLED_LIBRARIES_CFLAGS = \
+ $(MRUBY_CFLAGS) \
+ $(ONIGMO_CFLAGS)
+
+DEFAULT_INCLUDES = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ $(BUNDLED_LIBRARIES_CFLAGS)
+
+DEFS += -D_REENTRANT $(GRN_DEFS) -DGRN_DAT_EXPORT
+
+include c_sources.am
+include cpp_sources.am
+libgroonga_la_SOURCES = \
+ $(libgroonga_c_sources) \
+ $(libgroonga_cpp_source)
+
+#nfkc.c:
+# $(RUBY) nfkc.rb --impl=table
+
+libgroonga_la_LDFLAGS = \
+ -version-info $(LT_VERSION_INFO) \
+ -no-undefined \
+ $(WINDOWS_LDFLAGS)
+
+libgroonga_la_LIBADD = \
+ dat/libgrndat.la \
+ mrb/libgrnmrb.la \
+ proc/libgrnproc.la \
+ ts/libgrnts.la \
+ $(MESSAGE_PACK_LIBS)
+
+if WITH_MRUBY
+libgroonga_la_LIBADD += \
+ ../vendor/mruby/libmruby.la
+endif
+
+libgroonga_la_LIBADD += \
+ $(ONIGMO_LIBS) \
+ $(LIBLZ4_LIBS) \
+ $(LIBZSTD_LIBS) \
+ $(ATOMIC_LIBS) \
+ $(ARROW_LIBS)
+
+if WITH_LEMON
+BUILT_SOURCES = \
+ grn_ecmascript.c
+
+SUFFIXES = .lemon .c
+
+.lemon.c:
+ $(LEMON) $<
+endif
+
+if PLATFORM_WIN32
+libgroonga_la_SOURCES += \
+ metadata.rc
+
+.rc.lo:
+ $(LIBTOOL) $(AM_V_lt) --tag=RC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile \
+ $(RC) $(RCFLAGS) -o $@ $<
+endif
+
+EXTRA_DIST = \
+ grn_ecmascript.c \
+ grn_ecmascript.h \
+ grn_ecmascript.lemon \
+ CMakeLists.txt
+
+CLEANFILES = *.gcno *.gcda
diff --git a/storage/mroonga/vendor/groonga/lib/alloc.c b/storage/mroonga/vendor/groonga/lib/alloc.c
new file mode 100644
index 00000000..94e31901
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/alloc.c
@@ -0,0 +1,961 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_alloc.h"
+#include "grn_ctx_impl.h"
+
+static int alloc_count = 0;
+
+#ifdef USE_FAIL_MALLOC
+static int grn_fmalloc_prob = 0;
+static char *grn_fmalloc_func = NULL;
+static char *grn_fmalloc_file = NULL;
+static int grn_fmalloc_line = 0;
+#endif /* USE_FAIL_MALLOC */
+
+#ifdef USE_EXACT_ALLOC_COUNT
+# define GRN_ADD_ALLOC_COUNT(count) do { \
+ uint32_t alloced; \
+ GRN_ATOMIC_ADD_EX(&alloc_count, count, alloced); \
+} while (0)
+#else /* USE_EXACT_ALLOC_COUNT */
+# define GRN_ADD_ALLOC_COUNT(count) do { \
+ alloc_count += count; \
+} while (0)
+#endif
+
+void
+grn_alloc_init_from_env(void)
+{
+#ifdef USE_FAIL_MALLOC
+ {
+ char grn_fmalloc_prob_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_FMALLOC_PROB",
+ grn_fmalloc_prob_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_fmalloc_prob_env[0]) {
+ char grn_fmalloc_seed_env[GRN_ENV_BUFFER_SIZE];
+ grn_fmalloc_prob = strtod(grn_fmalloc_prob_env, 0) * RAND_MAX;
+ grn_getenv("GRN_FMALLOC_SEED",
+ grn_fmalloc_seed_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_fmalloc_seed_env[0]) {
+ srand((unsigned int)atoi(grn_fmalloc_seed_env));
+ } else {
+ srand((unsigned int)time(NULL));
+ }
+ }
+ }
+ {
+ static char grn_fmalloc_func_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_FMALLOC_FUNC",
+ grn_fmalloc_func_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_fmalloc_func_env[0]) {
+ grn_fmalloc_func = grn_fmalloc_func_env;
+ }
+ }
+ {
+ static char grn_fmalloc_file_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_FMALLOC_FILE",
+ grn_fmalloc_file_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_fmalloc_file_env[0]) {
+ grn_fmalloc_file = grn_fmalloc_file_env;
+ }
+ }
+ {
+ char grn_fmalloc_line_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_FMALLOC_LINE",
+ grn_fmalloc_line_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_fmalloc_line_env[0]) {
+ grn_fmalloc_line = atoi(grn_fmalloc_line_env);
+ }
+ }
+#endif /* USE_FAIL_MALLOC */
+}
+
+#ifdef USE_MEMORY_DEBUG
+static grn_critical_section grn_alloc_info_lock;
+
+void
+grn_alloc_info_init(void)
+{
+ CRITICAL_SECTION_INIT(grn_alloc_info_lock);
+}
+
+void
+grn_alloc_info_fin(void)
+{
+ CRITICAL_SECTION_FIN(grn_alloc_info_lock);
+}
+
+inline static void
+grn_alloc_info_set_backtrace(char *buffer, size_t size)
+{
+# ifdef HAVE_BACKTRACE
+# define N_TRACE_LEVEL 100
+ static void *trace[N_TRACE_LEVEL];
+ char **symbols;
+ int i, n, rest;
+
+ rest = size;
+ n = backtrace(trace, N_TRACE_LEVEL);
+ symbols = backtrace_symbols(trace, n);
+ if (symbols) {
+ for (i = 0; i < n; i++) {
+ int symbol_length;
+
+ symbol_length = strlen(symbols[i]);
+ if (symbol_length + 2 > rest) {
+ break;
+ }
+ grn_memcpy(buffer, symbols[i], symbol_length);
+ buffer += symbol_length;
+ rest -= symbol_length;
+ buffer[0] = '\n';
+ buffer++;
+ rest--;
+ buffer[0] = '\0';
+ rest--;
+ }
+ free(symbols);
+ } else {
+ buffer[0] = '\0';
+ }
+# undef N_TRACE_LEVEL
+# else /* HAVE_BACKTRACE */
+ buffer[0] = '\0';
+# endif /* HAVE_BACKTRACE */
+}
+
+inline static void
+grn_alloc_info_add(void *address, size_t size,
+ const char *file, int line, const char *func)
+{
+ grn_ctx *ctx;
+ grn_alloc_info *new_alloc_info;
+
+ ctx = &grn_gctx;
+ if (!ctx->impl) { return; }
+
+ CRITICAL_SECTION_ENTER(grn_alloc_info_lock);
+ new_alloc_info = malloc(sizeof(grn_alloc_info));
+ if (new_alloc_info) {
+ new_alloc_info->address = address;
+ new_alloc_info->size = size;
+ new_alloc_info->freed = GRN_FALSE;
+ grn_alloc_info_set_backtrace(new_alloc_info->alloc_backtrace,
+ sizeof(new_alloc_info->alloc_backtrace));
+ if (file) {
+ new_alloc_info->file = strdup(file);
+ } else {
+ new_alloc_info->file = NULL;
+ }
+ new_alloc_info->line = line;
+ if (func) {
+ new_alloc_info->func = strdup(func);
+ } else {
+ new_alloc_info->func = NULL;
+ }
+ new_alloc_info->next = ctx->impl->alloc_info;
+ ctx->impl->alloc_info = new_alloc_info;
+ }
+ CRITICAL_SECTION_LEAVE(grn_alloc_info_lock);
+}
+
+inline static void
+grn_alloc_info_change(void *old_address, void *new_address, size_t size)
+{
+ grn_ctx *ctx;
+ grn_alloc_info *alloc_info;
+
+ ctx = &grn_gctx;
+ if (!ctx->impl) { return; }
+
+ CRITICAL_SECTION_ENTER(grn_alloc_info_lock);
+ alloc_info = ctx->impl->alloc_info;
+ for (; alloc_info; alloc_info = alloc_info->next) {
+ if (alloc_info->address == old_address) {
+ alloc_info->address = new_address;
+ alloc_info->size = size;
+ grn_alloc_info_set_backtrace(alloc_info->alloc_backtrace,
+ sizeof(alloc_info->alloc_backtrace));
+ }
+ }
+ CRITICAL_SECTION_LEAVE(grn_alloc_info_lock);
+}
+
+void
+grn_alloc_info_dump(grn_ctx *ctx)
+{
+ int i = 0;
+ grn_alloc_info *alloc_info;
+
+ if (!ctx) { return; }
+ if (!ctx->impl) { return; }
+
+ alloc_info = ctx->impl->alloc_info;
+ for (; alloc_info; alloc_info = alloc_info->next) {
+ if (alloc_info->freed) {
+ printf("address[%d][freed]: %p(%" GRN_FMT_SIZE ")\n",
+ i, alloc_info->address, alloc_info->size);
+ } else {
+ printf("address[%d][not-freed]: %p(%" GRN_FMT_SIZE "): %s:%d: %s()\n%s",
+ i,
+ alloc_info->address,
+ alloc_info->size,
+ alloc_info->file ? alloc_info->file : "(unknown)",
+ alloc_info->line,
+ alloc_info->func ? alloc_info->func : "(unknown)",
+ alloc_info->alloc_backtrace);
+ }
+ i++;
+ }
+}
+
+inline static void
+grn_alloc_info_check(grn_ctx *ctx, void *address)
+{
+ grn_alloc_info *alloc_info;
+
+ if (!grn_gctx.impl) { return; }
+ /* grn_alloc_info_dump(ctx); */
+
+ CRITICAL_SECTION_ENTER(grn_alloc_info_lock);
+ alloc_info = grn_gctx.impl->alloc_info;
+ for (; alloc_info; alloc_info = alloc_info->next) {
+ if (alloc_info->address == address) {
+ if (alloc_info->freed) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "double free: %p(%" GRN_FMT_SIZE "):\n"
+ "alloc backtrace:\n"
+ "%sfree backtrace:\n"
+ "%s",
+ alloc_info->address,
+ alloc_info->size,
+ alloc_info->alloc_backtrace,
+ alloc_info->free_backtrace);
+ } else {
+ alloc_info->freed = GRN_TRUE;
+ grn_alloc_info_set_backtrace(alloc_info->free_backtrace,
+ sizeof(alloc_info->free_backtrace));
+ }
+ break;
+ }
+ }
+ CRITICAL_SECTION_LEAVE(grn_alloc_info_lock);
+}
+
+void
+grn_alloc_info_free(grn_ctx *ctx)
+{
+ grn_alloc_info *alloc_info;
+
+ if (!ctx) { return; }
+ if (!ctx->impl) { return; }
+
+ alloc_info = ctx->impl->alloc_info;
+ while (alloc_info) {
+ grn_alloc_info *current_alloc_info = alloc_info;
+ alloc_info = alloc_info->next;
+ current_alloc_info->next = NULL;
+ free(current_alloc_info->file);
+ free(current_alloc_info->func);
+ free(current_alloc_info);
+ }
+ ctx->impl->alloc_info = NULL;
+}
+
+#else /* USE_MEMORY_DEBUG */
+void
+grn_alloc_info_init(void)
+{
+}
+
+void
+grn_alloc_info_fin(void)
+{
+}
+
+# define grn_alloc_info_add(address, size, file, line, func)
+# define grn_alloc_info_change(old_address, new_address, size)
+# define grn_alloc_info_check(ctx, address)
+
+void
+grn_alloc_info_dump(grn_ctx *ctx)
+{
+}
+
+void
+grn_alloc_info_free(grn_ctx *ctx)
+{
+}
+#endif /* USE_MEMORY_DEBUG */
+
+#define GRN_CTX_SEGMENT_SIZE (1U <<22)
+#define GRN_CTX_SEGMENT_MASK (GRN_CTX_SEGMENT_SIZE - 1)
+
+#define GRN_CTX_SEGMENT_WORD (1U <<31)
+#define GRN_CTX_SEGMENT_VLEN (1U <<30)
+#define GRN_CTX_SEGMENT_LIFO (1U <<29)
+#define GRN_CTX_SEGMENT_DIRTY (1U <<28)
+
+void
+grn_alloc_init_ctx_impl(grn_ctx *ctx)
+{
+#ifdef USE_DYNAMIC_MALLOC_CHANGE
+# ifdef USE_FAIL_MALLOC
+ ctx->impl->malloc_func = grn_malloc_fail;
+ ctx->impl->calloc_func = grn_calloc_fail;
+ ctx->impl->realloc_func = grn_realloc_fail;
+ ctx->impl->strdup_func = grn_strdup_fail;
+# else
+ ctx->impl->malloc_func = grn_malloc_default;
+ ctx->impl->calloc_func = grn_calloc_default;
+ ctx->impl->realloc_func = grn_realloc_default;
+ ctx->impl->strdup_func = grn_strdup_default;
+# endif
+#endif
+
+#ifdef USE_MEMORY_DEBUG
+ ctx->impl->alloc_info = NULL;
+#endif
+}
+
+void
+grn_alloc_fin_ctx_impl(grn_ctx *ctx)
+{
+ int i;
+ grn_io_mapinfo *mi;
+ for (i = 0, mi = ctx->impl->segs; i < GRN_CTX_N_SEGMENTS; i++, mi++) {
+ if (mi->map) {
+ //GRN_LOG(ctx, GRN_LOG_NOTICE, "unmap in ctx_fin(%d,%d,%d)", i, (mi->count & GRN_CTX_SEGMENT_MASK), mi->nref);
+ if (mi->count & GRN_CTX_SEGMENT_VLEN) {
+ grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize);
+ } else {
+ grn_io_anon_unmap(ctx, mi, GRN_CTX_SEGMENT_SIZE);
+ }
+ }
+ }
+}
+
+#define ALIGN_SIZE (1<<3)
+#define ALIGN_MASK (ALIGN_SIZE-1)
+#define GRN_CTX_ALLOC_CLEAR 1
+
+static void *
+grn_ctx_alloc(grn_ctx *ctx, size_t size, int flags,
+ const char* file, int line, const char *func)
+{
+ void *res = NULL;
+ if (!ctx) { return res; }
+ if (!ctx->impl) {
+ if (ERRP(ctx, GRN_ERROR)) { return res; }
+ }
+ CRITICAL_SECTION_ENTER(ctx->impl->lock);
+ {
+ int32_t i;
+ int32_t *header;
+ grn_io_mapinfo *mi;
+ size = ((size + ALIGN_MASK) & ~ALIGN_MASK) + ALIGN_SIZE;
+ if (size > GRN_CTX_SEGMENT_SIZE) {
+ uint64_t npages = (size + (grn_pagesize - 1)) / grn_pagesize;
+ size_t aligned_size;
+ if (npages >= (1LL<<32)) {
+ MERR("too long request size=%" GRN_FMT_SIZE, size);
+ goto exit;
+ }
+ for (i = 0, mi = ctx->impl->segs;; i++, mi++) {
+ if (i >= GRN_CTX_N_SEGMENTS) {
+ MERR("all segments are full");
+ goto exit;
+ }
+ if (!mi->map) { break; }
+ }
+ aligned_size = grn_pagesize * ((size_t)npages);
+ if (!grn_io_anon_map(ctx, mi, aligned_size)) { goto exit; }
+ /* GRN_LOG(ctx, GRN_LOG_NOTICE, "map i=%d (%d)", i, npages * grn_pagesize); */
+ mi->nref = (uint32_t) npages;
+ mi->count = GRN_CTX_SEGMENT_VLEN;
+ ctx->impl->currseg = -1;
+ header = mi->map;
+ header[0] = i;
+ header[1] = (int32_t) size;
+ } else {
+ if ((i = ctx->impl->currseg) >= 0)
+ mi = &ctx->impl->segs[i];
+ if (i < 0 || size + mi->nref > GRN_CTX_SEGMENT_SIZE) {
+ for (i = 0, mi = ctx->impl->segs;; i++, mi++) {
+ if (i >= GRN_CTX_N_SEGMENTS) {
+ MERR("all segments are full");
+ goto exit;
+ }
+ if (!mi->map) { break; }
+ }
+ if (!grn_io_anon_map(ctx, mi, GRN_CTX_SEGMENT_SIZE)) { goto exit; }
+ /* GRN_LOG(ctx, GRN_LOG_NOTICE, "map i=%d", i); */
+ mi->nref = 0;
+ mi->count = GRN_CTX_SEGMENT_WORD;
+ ctx->impl->currseg = i;
+ }
+ header = (int32_t *)((byte *)mi->map + mi->nref);
+ mi->nref += size;
+ mi->count++;
+ header[0] = i;
+ header[1] = (int32_t) size;
+ if ((flags & GRN_CTX_ALLOC_CLEAR) &&
+ (mi->count & GRN_CTX_SEGMENT_DIRTY) && (size > ALIGN_SIZE)) {
+ memset(&header[2], 0, size - ALIGN_SIZE);
+ }
+ }
+ /*
+ {
+ char g = (ctx == &grn_gctx) ? 'g' : ' ';
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "+%c(%p) %s:%d(%s) (%d:%d)%p mi(%d:%d)", g, ctx, file, line, func, header[0], header[1], &header[2], mi->nref, (mi->count & GRN_CTX_SEGMENT_MASK));
+ }
+ */
+ res = &header[2];
+ }
+exit :
+ CRITICAL_SECTION_LEAVE(ctx->impl->lock);
+ return res;
+}
+
+void *
+grn_ctx_malloc(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ return grn_ctx_alloc(ctx, size, 0, file, line, func);
+}
+
+void *
+grn_ctx_calloc(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ return grn_ctx_alloc(ctx, size, GRN_CTX_ALLOC_CLEAR, file, line, func);
+}
+
+void *
+grn_ctx_realloc(grn_ctx *ctx, void *ptr, size_t size,
+ const char* file, int line, const char *func)
+{
+ void *res = NULL;
+ if (size) {
+ /* todo : expand if possible */
+ res = grn_ctx_alloc(ctx, size, 0, file, line, func);
+ if (res && ptr) {
+ int32_t *header = &((int32_t *)ptr)[-2];
+ size_t size_ = header[1];
+ grn_memcpy(res, ptr, size_ > size ? size : size_);
+ grn_ctx_free(ctx, ptr, file, line, func);
+ }
+ } else {
+ grn_ctx_free(ctx, ptr, file, line, func);
+ }
+ return res;
+}
+
+char *
+grn_ctx_strdup(grn_ctx *ctx, const char *s,
+ const char* file, int line, const char *func)
+{
+ void *res = NULL;
+ if (s) {
+ size_t size = strlen(s) + 1;
+ if ((res = grn_ctx_alloc(ctx, size, 0, file, line, func))) {
+ grn_memcpy(res, s, size);
+ }
+ }
+ return res;
+}
+
+void
+grn_ctx_free(grn_ctx *ctx, void *ptr,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return; }
+ if (!ctx->impl) {
+ ERR(GRN_INVALID_ARGUMENT,"ctx without impl passed.");
+ return;
+ }
+ CRITICAL_SECTION_ENTER(ctx->impl->lock);
+ if (ptr) {
+ int32_t *header = &((int32_t *)ptr)[-2];
+
+ if (header[0] >= GRN_CTX_N_SEGMENTS) {
+ ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed. ptr=%p seg=%d", ptr, *header);
+ goto exit;
+ }
+ /*
+ {
+ int32_t i = header[0];
+ char c = 'X', g = (ctx == &grn_gctx) ? 'g' : ' ';
+ grn_io_mapinfo *mi = &ctx->impl->segs[i];
+ if (!(mi->count & GRN_CTX_SEGMENT_VLEN) &&
+ mi->map <= (void *)header && (char *)header < ((char *)mi->map + GRN_CTX_SEGMENT_SIZE)) { c = '-'; }
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "%c%c(%p) %s:%d(%s) (%d:%d)%p mi(%d:%d)", c, g, ctx, file, line, func, header[0], header[1], &header[2], mi->nref, (mi->count & GRN_CTX_SEGMENT_MASK));
+ }
+ */
+ {
+ int32_t i = header[0];
+ grn_io_mapinfo *mi = &ctx->impl->segs[i];
+ if (mi->count & GRN_CTX_SEGMENT_VLEN) {
+ if (mi->map != header) {
+ ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed.. ptr=%p seg=%d", ptr, i);
+ goto exit;
+ }
+ //GRN_LOG(ctx, GRN_LOG_NOTICE, "umap i=%d (%d)", i, mi->nref * grn_pagesize);
+ grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize);
+ mi->map = NULL;
+ } else {
+ if (!mi->map) {
+ ERR(GRN_INVALID_ARGUMENT,"invalid ptr passed... ptr=%p seg=%d", ptr, i);
+ goto exit;
+ }
+ mi->count--;
+ if (!(mi->count & GRN_CTX_SEGMENT_MASK)) {
+ //GRN_LOG(ctx, GRN_LOG_NOTICE, "umap i=%d", i);
+ if (i == ctx->impl->currseg) {
+ mi->count |= GRN_CTX_SEGMENT_DIRTY;
+ mi->nref = 0;
+ } else {
+ grn_io_anon_unmap(ctx, mi, GRN_CTX_SEGMENT_SIZE);
+ mi->map = NULL;
+ }
+ }
+ }
+ }
+ }
+exit :
+ CRITICAL_SECTION_LEAVE(ctx->impl->lock);
+}
+
+void *
+grn_ctx_alloc_lifo(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return NULL; }
+ if (!ctx->impl) {
+ if (ERRP(ctx, GRN_ERROR)) { return NULL; }
+ }
+ {
+ int32_t i = ctx->impl->lifoseg;
+ grn_io_mapinfo *mi = &ctx->impl->segs[i];
+ if (size > GRN_CTX_SEGMENT_SIZE) {
+ uint64_t npages = (size + (grn_pagesize - 1)) / grn_pagesize;
+ size_t aligned_size;
+ if (npages >= (1LL<<32)) {
+ MERR("too long request size=%" GRN_FMT_SIZE, size);
+ return NULL;
+ }
+ for (;;) {
+ if (++i >= GRN_CTX_N_SEGMENTS) {
+ MERR("all segments are full");
+ return NULL;
+ }
+ mi++;
+ if (!mi->map) { break; }
+ }
+ aligned_size = grn_pagesize * ((size_t)npages);
+ if (!grn_io_anon_map(ctx, mi, aligned_size)) { return NULL; }
+ mi->nref = (uint32_t) npages;
+ mi->count = GRN_CTX_SEGMENT_VLEN|GRN_CTX_SEGMENT_LIFO;
+ ctx->impl->lifoseg = i;
+ return mi->map;
+ } else {
+ size = (size + ALIGN_MASK) & ~ALIGN_MASK;
+ if (i < 0 || (mi->count & GRN_CTX_SEGMENT_VLEN) || size + mi->nref > GRN_CTX_SEGMENT_SIZE) {
+ for (;;) {
+ if (++i >= GRN_CTX_N_SEGMENTS) {
+ MERR("all segments are full");
+ return NULL;
+ }
+ if (!(++mi)->map) { break; }
+ }
+ if (!grn_io_anon_map(ctx, mi, GRN_CTX_SEGMENT_SIZE)) { return NULL; }
+ mi->nref = 0;
+ mi->count = GRN_CTX_SEGMENT_WORD|GRN_CTX_SEGMENT_LIFO;
+ ctx->impl->lifoseg = i;
+ }
+ {
+ uint32_t u = mi->nref;
+ mi->nref += size;
+ return (byte *)mi->map + u;
+ }
+ }
+ }
+}
+
+void
+grn_ctx_free_lifo(grn_ctx *ctx, void *ptr,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return; }
+ if (!ctx->impl) {
+ ERR(GRN_INVALID_ARGUMENT,"ctx without impl passed.");
+ return;
+ }
+ {
+ int32_t i = ctx->impl->lifoseg, done = 0;
+ grn_io_mapinfo *mi = &ctx->impl->segs[i];
+ if (i < 0) {
+ ERR(GRN_INVALID_ARGUMENT, "lifo buffer is void");
+ return;
+ }
+ for (; i >= 0; i--, mi--) {
+ if (!(mi->count & GRN_CTX_SEGMENT_LIFO)) { continue; }
+ if (done) { break; }
+ if (mi->count & GRN_CTX_SEGMENT_VLEN) {
+ if (mi->map == ptr) { done = 1; }
+ grn_io_anon_unmap(ctx, mi, mi->nref * grn_pagesize);
+ mi->map = NULL;
+ } else {
+ if (mi->map == ptr) {
+ done = 1;
+ } else {
+ if (mi->map < ptr && ptr < (void *)((byte*)mi->map + mi->nref)) {
+ mi->nref = (uint32_t) ((uintptr_t)ptr - (uintptr_t)mi->map);
+ break;
+ }
+ }
+ grn_io_anon_unmap(ctx, mi, GRN_CTX_SEGMENT_SIZE);
+ mi->map = NULL;
+ }
+ }
+ ctx->impl->lifoseg = i;
+ }
+}
+
+#if defined(USE_DYNAMIC_MALLOC_CHANGE)
+grn_malloc_func
+grn_ctx_get_malloc(grn_ctx *ctx)
+{
+ if (!ctx || !ctx->impl) { return NULL; }
+ return ctx->impl->malloc_func;
+}
+
+void
+grn_ctx_set_malloc(grn_ctx *ctx, grn_malloc_func malloc_func)
+{
+ if (!ctx || !ctx->impl) { return; }
+ ctx->impl->malloc_func = malloc_func;
+}
+
+grn_calloc_func
+grn_ctx_get_calloc(grn_ctx *ctx)
+{
+ if (!ctx || !ctx->impl) { return NULL; }
+ return ctx->impl->calloc_func;
+}
+
+void
+grn_ctx_set_calloc(grn_ctx *ctx, grn_calloc_func calloc_func)
+{
+ if (!ctx || !ctx->impl) { return; }
+ ctx->impl->calloc_func = calloc_func;
+}
+
+grn_realloc_func
+grn_ctx_get_realloc(grn_ctx *ctx)
+{
+ if (!ctx || !ctx->impl) { return NULL; }
+ return ctx->impl->realloc_func;
+}
+
+void
+grn_ctx_set_realloc(grn_ctx *ctx, grn_realloc_func realloc_func)
+{
+ if (!ctx || !ctx->impl) { return; }
+ ctx->impl->realloc_func = realloc_func;
+}
+
+grn_strdup_func
+grn_ctx_get_strdup(grn_ctx *ctx)
+{
+ if (!ctx || !ctx->impl) { return NULL; }
+ return ctx->impl->strdup_func;
+}
+
+void
+grn_ctx_set_strdup(grn_ctx *ctx, grn_strdup_func strdup_func)
+{
+ if (!ctx || !ctx->impl) { return; }
+ ctx->impl->strdup_func = strdup_func;
+}
+
+grn_free_func
+grn_ctx_get_free(grn_ctx *ctx)
+{
+ if (!ctx || !ctx->impl) { return NULL; }
+ return ctx->impl->free_func;
+}
+
+void
+grn_ctx_set_free(grn_ctx *ctx, grn_free_func free_func)
+{
+ if (!ctx || !ctx->impl) { return; }
+ ctx->impl->free_func = free_func;
+}
+
+void *
+grn_malloc(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (ctx && ctx->impl && ctx->impl->malloc_func) {
+ return ctx->impl->malloc_func(ctx, size, file, line, func);
+ } else {
+ return grn_malloc_default(ctx, size, file, line, func);
+ }
+}
+
+void *
+grn_calloc(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (ctx && ctx->impl && ctx->impl->calloc_func) {
+ return ctx->impl->calloc_func(ctx, size, file, line, func);
+ } else {
+ return grn_calloc_default(ctx, size, file, line, func);
+ }
+}
+
+void *
+grn_realloc(grn_ctx *ctx, void *ptr, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (ctx && ctx->impl && ctx->impl->realloc_func) {
+ return ctx->impl->realloc_func(ctx, ptr, size, file, line, func);
+ } else {
+ return grn_realloc_default(ctx, ptr, size, file, line, func);
+ }
+}
+
+char *
+grn_strdup(grn_ctx *ctx, const char *string,
+ const char* file, int line, const char *func)
+{
+ if (ctx && ctx->impl && ctx->impl->strdup_func) {
+ return ctx->impl->strdup_func(ctx, string, file, line, func);
+ } else {
+ return grn_strdup_default(ctx, string, file, line, func);
+ }
+}
+
+void
+grn_free(grn_ctx *ctx, void *ptr,
+ const char* file, int line, const char *func)
+{
+ if (ctx && ctx->impl && ctx->impl->free_func) {
+ return ctx->impl->free_func(ctx, ptr, file, line, func);
+ } else {
+ return grn_free_default(ctx, ptr, file, line, func);
+ }
+}
+#endif
+
+void *
+grn_malloc_default(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return NULL; }
+ {
+ void *res = malloc(size);
+ if (res) {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, size, file, line, func);
+ } else {
+ if (!(res = malloc(size))) {
+ MERR("malloc fail (%" GRN_FMT_SIZE ")=%p (%s:%d) <%d>",
+ size, res, file, line, alloc_count);
+ } else {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, size, file, line, func);
+ }
+ }
+ return res;
+ }
+}
+
+void *
+grn_calloc_default(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return NULL; }
+ {
+ void *res = calloc(size, 1);
+ if (res) {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, size, file, line, func);
+ } else {
+ if (!(res = calloc(size, 1))) {
+ MERR("calloc fail (%" GRN_FMT_SIZE ")=%p (%s:%d) <%d>",
+ size, res, file, line, alloc_count);
+ } else {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, size, file, line, func);
+ }
+ }
+ return res;
+ }
+}
+
+void
+grn_free_default(grn_ctx *ctx, void *ptr,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return; }
+ grn_alloc_info_check(ctx, ptr);
+ {
+ free(ptr);
+ if (ptr) {
+ GRN_ADD_ALLOC_COUNT(-1);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "free fail (%s:%d) <%d>",
+ file, line, alloc_count);
+ }
+ }
+}
+
+void *
+grn_realloc_default(grn_ctx *ctx, void *ptr, size_t size,
+ const char* file, int line, const char *func)
+{
+ void *res;
+ if (!ctx) { return NULL; }
+ if (size) {
+ if (!(res = realloc(ptr, size))) {
+ if (!(res = realloc(ptr, size))) {
+ MERR("realloc fail (%p,%" GRN_FMT_SIZE ")=%p (%s:%d) <%d>",
+ ptr, size, res, file, line, alloc_count);
+ return NULL;
+ }
+ }
+ if (ptr) {
+ grn_alloc_info_change(ptr, res, size);
+ } else {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, size, file, line, func);
+ }
+ } else {
+ if (!ptr) { return NULL; }
+ grn_alloc_info_check(ctx, ptr);
+ GRN_ADD_ALLOC_COUNT(-1);
+ free(ptr);
+ res = NULL;
+ }
+ return res;
+}
+
+int
+grn_alloc_count(void)
+{
+ return alloc_count;
+}
+
+char *
+grn_strdup_default(grn_ctx *ctx, const char *s,
+ const char* file, int line, const char *func)
+{
+ if (!ctx) { return NULL; }
+ {
+ char *res = grn_strdup_raw(s);
+ if (res) {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, strlen(res) + 1, file, line, func);
+ } else {
+ if (!(res = grn_strdup_raw(s))) {
+ MERR("strdup(%p)=%p (%s:%d) <%d>", s, res, file, line, alloc_count);
+ } else {
+ GRN_ADD_ALLOC_COUNT(1);
+ grn_alloc_info_add(res, strlen(res) + 1, file, line, func);
+ }
+ }
+ return res;
+ }
+}
+
+#ifdef USE_FAIL_MALLOC
+int
+grn_fail_malloc_check(size_t size,
+ const char *file, int line, const char *func)
+{
+ if ((grn_fmalloc_file && strcmp(file, grn_fmalloc_file)) ||
+ (grn_fmalloc_line && line != grn_fmalloc_line) ||
+ (grn_fmalloc_func && strcmp(func, grn_fmalloc_func))) {
+ return 1;
+ }
+ if (grn_fmalloc_prob && grn_fmalloc_prob >= rand()) {
+ return 0;
+ }
+ return 1;
+}
+
+void *
+grn_malloc_fail(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (grn_fail_malloc_check(size, file, line, func)) {
+ return grn_malloc_default(ctx, size, file, line, func);
+ } else {
+ MERR("fail_malloc (%" GRN_FMT_SIZE ") (%s:%d@%s) <%d>",
+ size, file, line, func, alloc_count);
+ return NULL;
+ }
+}
+
+void *
+grn_calloc_fail(grn_ctx *ctx, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (grn_fail_malloc_check(size, file, line, func)) {
+ return grn_calloc_default(ctx, size, file, line, func);
+ } else {
+ MERR("fail_calloc (%" GRN_FMT_SIZE ") (%s:%d@%s) <%d>",
+ size, file, line, func, alloc_count);
+ return NULL;
+ }
+}
+
+void *
+grn_realloc_fail(grn_ctx *ctx, void *ptr, size_t size,
+ const char* file, int line, const char *func)
+{
+ if (grn_fail_malloc_check(size, file, line, func)) {
+ return grn_realloc_default(ctx, ptr, size, file, line, func);
+ } else {
+ MERR("fail_realloc (%p,%" GRN_FMT_SIZE ") (%s:%d@%s) <%d>",
+ ptr, size, file, line, func, alloc_count);
+ return NULL;
+ }
+}
+
+char *
+grn_strdup_fail(grn_ctx *ctx, const char *s,
+ const char* file, int line, const char *func)
+{
+ if (grn_fail_malloc_check(strlen(s), file, line, func)) {
+ return grn_strdup_default(ctx, s, file, line, func);
+ } else {
+ MERR("fail_strdup(%p) (%s:%d@%s) <%d>", s, file, line, func, alloc_count);
+ return NULL;
+ }
+}
+#endif /* USE_FAIL_MALLOC */
diff --git a/storage/mroonga/vendor/groonga/lib/arrow.cpp b/storage/mroonga/vendor/groonga/lib/arrow.cpp
new file mode 100644
index 00000000..5f022ed1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/arrow.cpp
@@ -0,0 +1,849 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_db.h"
+
+#ifdef GRN_WITH_ARROW
+#include <groonga/arrow.hpp>
+
+#include <arrow/api.h>
+#include <arrow/io/file.h>
+#include <arrow/ipc/api.h>
+
+#include <sstream>
+
+namespace grnarrow {
+ grn_rc status_to_rc(arrow::Status &status) {
+ switch (status.code()) {
+ case arrow::StatusCode::OK:
+ return GRN_SUCCESS;
+ case arrow::StatusCode::OutOfMemory:
+ return GRN_NO_MEMORY_AVAILABLE;
+ case arrow::StatusCode::KeyError:
+ return GRN_INVALID_ARGUMENT; // TODO
+ case arrow::StatusCode::TypeError:
+ return GRN_INVALID_ARGUMENT; // TODO
+ case arrow::StatusCode::Invalid:
+ return GRN_INVALID_ARGUMENT;
+ case arrow::StatusCode::IOError:
+ return GRN_INPUT_OUTPUT_ERROR;
+ case arrow::StatusCode::UnknownError:
+ return GRN_UNKNOWN_ERROR;
+ case arrow::StatusCode::NotImplemented:
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+ default:
+ return GRN_UNKNOWN_ERROR;
+ }
+ }
+
+ grn_bool check_status(grn_ctx *ctx,
+ arrow::Status &status,
+ const char *context) {
+ if (status.ok()) {
+ return GRN_TRUE;
+ } else {
+ auto rc = status_to_rc(status);
+ auto message = status.ToString();
+ ERR(rc, "%s: %s", context, message.c_str());
+ return GRN_FALSE;
+ }
+ }
+
+ grn_bool check_status(grn_ctx *ctx,
+ arrow::Status &status,
+ std::ostream &output) {
+ return check_status(ctx,
+ status,
+ static_cast<std::stringstream &>(output).str().c_str());
+ }
+
+ class ColumnLoadVisitor : public arrow::ArrayVisitor {
+ public:
+ ColumnLoadVisitor(grn_ctx *ctx,
+ grn_obj *grn_table,
+ std::shared_ptr<arrow::Column> &arrow_column,
+ const grn_id *ids)
+ : ctx_(ctx),
+ grn_table_(grn_table),
+ ids_(ids),
+ time_unit_(arrow::TimeUnit::SECOND) {
+ auto column_name = arrow_column->name();
+ grn_column_ = grn_obj_column(ctx_, grn_table_,
+ column_name.data(),
+ column_name.size());
+
+ auto arrow_type = arrow_column->type();
+ grn_id type_id;
+ switch (arrow_type->id()) {
+ case arrow::Type::BOOL :
+ type_id = GRN_DB_BOOL;
+ break;
+ case arrow::Type::UINT8 :
+ type_id = GRN_DB_UINT8;
+ break;
+ case arrow::Type::INT8 :
+ type_id = GRN_DB_INT8;
+ break;
+ case arrow::Type::UINT16 :
+ type_id = GRN_DB_UINT16;
+ break;
+ case arrow::Type::INT16 :
+ type_id = GRN_DB_INT16;
+ break;
+ case arrow::Type::UINT32 :
+ type_id = GRN_DB_UINT32;
+ break;
+ case arrow::Type::INT32 :
+ type_id = GRN_DB_INT32;
+ break;
+ case arrow::Type::UINT64 :
+ type_id = GRN_DB_UINT64;
+ break;
+ case arrow::Type::INT64 :
+ type_id = GRN_DB_INT64;
+ break;
+ case arrow::Type::HALF_FLOAT :
+ case arrow::Type::FLOAT :
+ case arrow::Type::DOUBLE :
+ type_id = GRN_DB_FLOAT;
+ break;
+ case arrow::Type::STRING :
+ type_id = GRN_DB_TEXT;
+ break;
+ case arrow::Type::DATE64 :
+ type_id = GRN_DB_TIME;
+ break;
+ case arrow::Type::TIMESTAMP :
+ type_id = GRN_DB_TIME;
+ {
+ auto arrow_timestamp_type =
+ std::static_pointer_cast<arrow::TimestampType>(arrow_type);
+ time_unit_ = arrow_timestamp_type->unit();
+ }
+ break;
+ default :
+ type_id = GRN_DB_VOID;
+ break;
+ }
+
+ if (type_id == GRN_DB_VOID) {
+ // TODO
+ return;
+ }
+
+ if (!grn_column_) {
+ grn_column_ = grn_column_create(ctx_,
+ grn_table_,
+ column_name.data(),
+ column_name.size(),
+ NULL,
+ GRN_OBJ_COLUMN_SCALAR,
+ grn_ctx_at(ctx_, type_id));
+ }
+ if (type_id == GRN_DB_TEXT) {
+ GRN_TEXT_INIT(&buffer_, GRN_OBJ_DO_SHALLOW_COPY);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&buffer_, 0, type_id);
+ }
+ }
+
+ ~ColumnLoadVisitor() {
+ if (grn_obj_is_accessor(ctx_, grn_column_)) {
+ grn_obj_unlink(ctx_, grn_column_);
+ }
+ GRN_OBJ_FIN(ctx_, &buffer_);
+ }
+
+ arrow::Status Visit(const arrow::BooleanArray &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::Int8Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::UInt8Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::Int16Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::UInt16Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::Int32Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::UInt32Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::Int64Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::UInt64Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::HalfFloatArray &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::FloatArray &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::DoubleArray &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::StringArray &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::Date64Array &array) {
+ return set_values(array);
+ }
+
+ arrow::Status Visit(const arrow::TimestampArray &array) {
+ return set_values(array);
+ }
+
+ private:
+ grn_ctx *ctx_;
+ grn_obj *grn_table_;
+ const grn_id *ids_;
+ arrow::TimeUnit::type time_unit_;
+ grn_obj *grn_column_;
+ grn_obj buffer_;
+
+ template <typename T>
+ arrow::Status set_values(const T &array) {
+ int64_t n_rows = array.length();
+ for (int i = 0; i < n_rows; ++i) {
+ auto id = ids_[i];
+ GRN_BULK_REWIND(&buffer_);
+ get_value(array, i);
+ grn_obj_set_value(ctx_, grn_column_, id, &buffer_, GRN_OBJ_SET);
+ }
+ return arrow::Status::OK();
+ }
+
+ void
+ get_value(const arrow::BooleanArray &array, int i) {
+ GRN_BOOL_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::UInt8Array &array, int i) {
+ GRN_UINT8_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::Int8Array &array, int i) {
+ GRN_INT8_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::UInt16Array &array, int i) {
+ GRN_UINT16_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::Int16Array &array, int i) {
+ GRN_INT16_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::UInt32Array &array, int i) {
+ GRN_UINT32_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::Int32Array &array, int i) {
+ GRN_INT32_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::UInt64Array &array, int i) {
+ GRN_UINT64_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::Int64Array &array, int i) {
+ GRN_INT64_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::HalfFloatArray &array, int i) {
+ GRN_FLOAT_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::FloatArray &array, int i) {
+ GRN_FLOAT_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::DoubleArray &array, int i) {
+ GRN_FLOAT_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::StringArray &array, int i) {
+ int32_t size;
+ const auto data = array.GetValue(i, &size);
+ GRN_TEXT_SET(ctx_, &buffer_, data, size);
+ }
+
+ void
+ get_value(const arrow::Date64Array &array, int i) {
+ GRN_TIME_SET(ctx_, &buffer_, array.Value(i));
+ }
+
+ void
+ get_value(const arrow::TimestampArray &array, int i) {
+ switch (time_unit_) {
+ case arrow::TimeUnit::SECOND :
+ GRN_TIME_SET(ctx_, &buffer_, GRN_TIME_PACK(array.Value(i), 0));
+ break;
+ case arrow::TimeUnit::MILLI :
+ GRN_TIME_SET(ctx_, &buffer_, array.Value(i) * 1000);
+ break;
+ case arrow::TimeUnit::MICRO :
+ GRN_TIME_SET(ctx_, &buffer_, array.Value(i));
+ break;
+ case arrow::TimeUnit::NANO :
+ GRN_TIME_SET(ctx_, &buffer_, array.Value(i) / 1000);
+ break;
+ }
+ }
+ };
+
+ class FileLoader {
+ public:
+ FileLoader(grn_ctx *ctx, grn_obj *grn_table)
+ : ctx_(ctx),
+ grn_table_(grn_table),
+ key_column_name_("") {
+ }
+
+ ~FileLoader() {
+ }
+
+ grn_rc load_table(const std::shared_ptr<arrow::Table> &arrow_table) {
+ int n_columns = arrow_table->num_columns();
+
+ if (key_column_name_.empty()) {
+ grn_obj ids;
+ GRN_RECORD_INIT(&ids, GRN_OBJ_VECTOR, grn_obj_id(ctx_, grn_table_));
+ auto n_records = arrow_table->num_rows();
+ for (int64_t i = 0; i < n_records; ++i) {
+ auto id = grn_table_add(ctx_, grn_table_, NULL, 0, NULL);
+ GRN_RECORD_PUT(ctx_, &ids, id);
+ }
+ for (int i = 0; i < n_columns; ++i) {
+ int64_t offset = 0;
+ auto arrow_column = arrow_table->column(i);
+ auto arrow_chunked_data = arrow_column->data();
+ for (auto arrow_array : arrow_chunked_data->chunks()) {
+ grn_id *sub_ids =
+ reinterpret_cast<grn_id *>(GRN_BULK_HEAD(&ids)) + offset;
+ ColumnLoadVisitor visitor(ctx_,
+ grn_table_,
+ arrow_column,
+ sub_ids);
+ arrow_array->Accept(&visitor);
+ offset += arrow_array->length();
+ }
+ }
+ GRN_OBJ_FIN(ctx_, &ids);
+ } else {
+ auto status = arrow::Status::NotImplemented("_key isn't supported yet");
+ check_status(ctx_, status, "[arrow][load]");
+ }
+ return ctx_->rc;
+ };
+
+ grn_rc load_record_batch(const std::shared_ptr<arrow::RecordBatch> &arrow_record_batch) {
+ std::shared_ptr<arrow::Table> arrow_table;
+ std::vector<std::shared_ptr<arrow::RecordBatch>> arrow_record_batches(1);
+ arrow_record_batches[0] = arrow_record_batch;
+ auto status =
+ arrow::Table::FromRecordBatches(arrow_record_batches, &arrow_table);
+ if (!check_status(ctx_,
+ status,
+ "[arrow][load] "
+ "failed to convert record batch to table")) {
+ return ctx_->rc;
+ }
+ return load_table(arrow_table);
+ };
+
+ private:
+ grn_ctx *ctx_;
+ grn_obj *grn_table_;
+ std::string key_column_name_;
+ };
+
+ class FileDumper {
+ public:
+ FileDumper(grn_ctx *ctx, grn_obj *grn_table, grn_obj *grn_columns)
+ : ctx_(ctx),
+ grn_table_(grn_table),
+ grn_columns_(grn_columns) {
+ }
+
+ ~FileDumper() {
+ }
+
+ grn_rc dump(arrow::io::OutputStream *output) {
+ std::vector<std::shared_ptr<arrow::Field>> fields;
+ auto n_columns = GRN_BULK_VSIZE(grn_columns_) / sizeof(grn_obj *);
+ for (auto i = 0; i < n_columns; ++i) {
+ auto column = GRN_PTR_VALUE_AT(grn_columns_, i);
+
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ column_name_size =
+ grn_column_name(ctx_, column, column_name, GRN_TABLE_MAX_KEY_SIZE);
+ std::string field_name(column_name, column_name_size);
+ std::shared_ptr<arrow::DataType> field_type;
+ switch (grn_obj_get_range(ctx_, column)) {
+ case GRN_DB_BOOL :
+ field_type = arrow::boolean();
+ break;
+ case GRN_DB_UINT8 :
+ field_type = arrow::uint8();
+ break;
+ case GRN_DB_INT8 :
+ field_type = arrow::int8();
+ break;
+ case GRN_DB_UINT16 :
+ field_type = arrow::uint16();
+ break;
+ case GRN_DB_INT16 :
+ field_type = arrow::int16();
+ break;
+ case GRN_DB_UINT32 :
+ field_type = arrow::uint32();
+ break;
+ case GRN_DB_INT32 :
+ field_type = arrow::int32();
+ break;
+ case GRN_DB_UINT64 :
+ field_type = arrow::uint64();
+ break;
+ case GRN_DB_INT64 :
+ field_type = arrow::int64();
+ break;
+ case GRN_DB_FLOAT :
+ field_type = arrow::float64();
+ break;
+ case GRN_DB_TIME :
+ field_type =
+ std::make_shared<arrow::TimestampType>(arrow::TimeUnit::MICRO);
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ field_type = arrow::utf8();
+ break;
+ default :
+ break;
+ }
+ if (!field_type) {
+ continue;
+ }
+
+ auto field = std::make_shared<arrow::Field>(field_name,
+ field_type,
+ false);
+ fields.push_back(field);
+ };
+
+ auto schema = std::make_shared<arrow::Schema>(fields);
+
+ std::shared_ptr<arrow::ipc::RecordBatchFileWriter> writer;
+ auto status =
+ arrow::ipc::RecordBatchFileWriter::Open(output, schema, &writer);
+ if (!check_status(ctx_,
+ status,
+ "[arrow][dump] failed to create file format writer")) {
+ return ctx_->rc;
+ }
+
+ std::vector<grn_id> ids;
+ int n_records_per_batch = 1000;
+ GRN_TABLE_EACH_BEGIN(ctx_, grn_table_, table_cursor, record_id) {
+ ids.push_back(record_id);
+ if (ids.size() == n_records_per_batch) {
+ write_record_batch(ids, schema, writer);
+ ids.clear();
+ }
+ } GRN_TABLE_EACH_END(ctx_, table_cursor);
+ if (!ids.empty()) {
+ write_record_batch(ids, schema, writer);
+ }
+ writer->Close();
+
+ return ctx_->rc;
+ }
+
+ private:
+ grn_ctx *ctx_;
+ grn_obj *grn_table_;
+ grn_obj *grn_columns_;
+
+ void write_record_batch(std::vector<grn_id> &ids,
+ std::shared_ptr<arrow::Schema> &schema,
+ std::shared_ptr<arrow::ipc::RecordBatchFileWriter> &writer) {
+ std::vector<std::shared_ptr<arrow::Array>> columns;
+ auto n_columns = GRN_BULK_VSIZE(grn_columns_) / sizeof(grn_obj *);
+ for (auto i = 0; i < n_columns; ++i) {
+ auto grn_column = GRN_PTR_VALUE_AT(grn_columns_, i);
+
+ arrow::Status status;
+ std::shared_ptr<arrow::Array> column;
+
+ switch (grn_obj_get_range(ctx_, grn_column)) {
+ case GRN_DB_BOOL :
+ status = build_boolean_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_UINT8 :
+ status = build_uint8_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_INT8 :
+ status = build_int8_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_UINT16 :
+ status = build_uint16_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_INT16 :
+ status = build_int16_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_UINT32 :
+ status = build_uint32_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_INT32 :
+ status = build_int32_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_UINT64 :
+ status = build_uint64_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_INT64 :
+ status = build_int64_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_FLOAT :
+ status = build_double_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_TIME :
+ status = build_timestamp_array(ids, grn_column, &column);
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ status = build_utf8_array(ids, grn_column, &column);
+ break;
+ default :
+ status =
+ arrow::Status::NotImplemented("[arrow][dumper] not supported type: TODO");
+ break;
+ }
+ if (!status.ok()) {
+ continue;
+ }
+ columns.push_back(column);
+ }
+
+ arrow::RecordBatch record_batch(schema, ids.size(), columns);
+ writer->WriteRecordBatch(record_batch);
+ }
+
+ arrow::Status build_boolean_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::BooleanBuilder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const grn_bool *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_uint8_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::UInt8Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const uint8_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_int8_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::Int8Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const int8_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_uint16_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::UInt16Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const uint16_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_int16_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::Int16Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const int16_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_uint32_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::UInt32Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const uint32_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_int32_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::Int32Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const int32_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+ arrow::Status build_uint64_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::UInt64Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const uint64_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_int64_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::Int64Builder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const int64_t *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_double_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::DoubleBuilder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(*(reinterpret_cast<const double *>(data)));
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_timestamp_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ auto timestamp_ns_data_type =
+ std::make_shared<arrow::TimestampType>(arrow::TimeUnit::MICRO);
+ arrow::TimestampBuilder builder(arrow::default_memory_pool(),
+ timestamp_ns_data_type);
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ auto timestamp_ns = *(reinterpret_cast<const int64_t *>(data));
+ builder.Append(timestamp_ns);
+ }
+ return builder.Finish(array);
+ }
+
+ arrow::Status build_utf8_array(std::vector<grn_id> &ids,
+ grn_obj *grn_column,
+ std::shared_ptr<arrow::Array> *array) {
+ arrow::StringBuilder builder(arrow::default_memory_pool());
+ for (auto id : ids) {
+ uint32_t size;
+ auto data = grn_obj_get_value_(ctx_, grn_column, id, &size);
+ builder.Append(data, size);
+ }
+ return builder.Finish(array);
+ }
+ };
+}
+#endif /* GRN_WITH_ARROW */
+
+extern "C" {
+grn_rc
+grn_arrow_load(grn_ctx *ctx,
+ grn_obj *table,
+ const char *path)
+{
+ GRN_API_ENTER;
+#ifdef GRN_WITH_ARROW
+ std::shared_ptr<arrow::io::MemoryMappedFile> input;
+ auto status =
+ arrow::io::MemoryMappedFile::Open(path, arrow::io::FileMode::READ, &input);
+ if (!grnarrow::check_status(ctx,
+ status,
+ std::ostringstream() <<
+ "[arrow][load] failed to open path: " <<
+ "<" << path << ">")) {
+ GRN_API_RETURN(ctx->rc);
+ }
+ std::shared_ptr<arrow::ipc::RecordBatchFileReader> reader;
+ status = arrow::ipc::RecordBatchFileReader::Open(input, &reader);
+ if (!grnarrow::check_status(ctx,
+ status,
+ "[arrow][load] "
+ "failed to create file format reader")) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ grnarrow::FileLoader loader(ctx, table);
+ int n_record_batches = reader->num_record_batches();
+ for (int i = 0; i < n_record_batches; ++i) {
+ std::shared_ptr<arrow::RecordBatch> record_batch;
+ status = reader->ReadRecordBatch(i, &record_batch);
+ if (!grnarrow::check_status(ctx,
+ status,
+ std::ostringstream("") <<
+ "[arrow][load] failed to get " <<
+ "the " << i << "-th " << "record")) {
+ break;
+ }
+ loader.load_record_batch(record_batch);
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+#else /* GRN_WITH_ARROW */
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[arrow][load] Apache Arrow support isn't enabled");
+#endif /* GRN_WITH_ARROW */
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_arrow_dump(grn_ctx *ctx,
+ grn_obj *table,
+ const char *path)
+{
+ GRN_API_ENTER;
+#ifdef GRN_WITH_ARROW
+ auto all_columns =
+ grn_hash_create(ctx,
+ NULL,
+ sizeof(grn_id),
+ 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
+ grn_table_columns(ctx,
+ table,
+ "", 0,
+ reinterpret_cast<grn_obj *>(all_columns));
+
+ grn_obj columns;
+ GRN_PTR_INIT(&columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_HASH_EACH_BEGIN(ctx, all_columns, cursor, id) {
+ void *key;
+ grn_hash_cursor_get_key(ctx, cursor, &key);
+ auto column_id = static_cast<grn_id *>(key);
+ auto column = grn_ctx_at(ctx, *column_id);
+ GRN_PTR_PUT(ctx, &columns, column);
+ } GRN_HASH_EACH_END(ctx, cursor);
+ grn_hash_close(ctx, all_columns);
+
+ grn_arrow_dump_columns(ctx, table, &columns, path);
+ GRN_OBJ_FIN(ctx, &columns);
+#else /* GRN_WITH_ARROW */
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[arrow][dump] Apache Arrow support isn't enabled");
+#endif /* GRN_WITH_ARROW */
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_arrow_dump_columns(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *columns,
+ const char *path)
+{
+ GRN_API_ENTER;
+#ifdef GRN_WITH_ARROW
+ std::shared_ptr<arrow::io::FileOutputStream> output;
+ auto status = arrow::io::FileOutputStream::Open(path, &output);
+ if (!grnarrow::check_status(ctx,
+ status,
+ std::stringstream() <<
+ "[arrow][dump] failed to open path: " <<
+ "<" << path << ">")) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ grnarrow::FileDumper dumper(ctx, table, columns);
+ dumper.dump(output.get());
+#else /* GRN_WITH_ARROW */
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[arrow][dump] Apache Arrow support isn't enabled");
+#endif /* GRN_WITH_ARROW */
+ GRN_API_RETURN(ctx->rc);
+}
+}
diff --git a/storage/mroonga/vendor/groonga/lib/c_sources.am b/storage/mroonga/vendor/groonga/lib/c_sources.am
new file mode 100644
index 00000000..3b76e693
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/c_sources.am
@@ -0,0 +1,112 @@
+libgroonga_c_sources = \
+ alloc.c \
+ grn_alloc.h \
+ cache.c \
+ grn_cache.h \
+ column.c \
+ com.c \
+ grn_com.h \
+ command.c \
+ config.c \
+ grn_config.h \
+ ctx.c \
+ grn_ctx.h \
+ grn_ctx_impl.h \
+ ctx_impl_mrb.c \
+ grn_ctx_impl_mrb.h \
+ grn_dat.h \
+ db.c \
+ grn_db.h \
+ dump.c \
+ ts.c \
+ grn_ts.h \
+ type.c \
+ error.c \
+ grn_error.h \
+ expr.c \
+ grn_expr.h \
+ expr_code.c \
+ grn_expr_code.h \
+ expr_executor.c \
+ grn_expr_executor.h \
+ file_lock.c \
+ grn_file_lock.h \
+ geo.c \
+ grn_geo.h \
+ grn.h \
+ hash.c \
+ grn_hash.h \
+ id.c \
+ ii.c \
+ grn_ii.h \
+ index_column.c \
+ grn_index_column.h \
+ io.c \
+ grn_io.h \
+ load.c \
+ grn_load.h \
+ logger.c \
+ grn_logger.h \
+ mrb.c \
+ grn_mrb.h \
+ grn_msgpack.h \
+ nfkc.c \
+ grn_nfkc.h \
+ nfkc50.c \
+ normalizer.c \
+ grn_normalizer.h \
+ obj.c \
+ grn_obj.h \
+ operator.c \
+ output.c \
+ grn_output.h \
+ pat.c \
+ grn_pat.h \
+ plugin.c \
+ grn_plugin.h \
+ proc.c \
+ grn_proc.h \
+ raw_string.c \
+ grn_raw_string.h \
+ report.c \
+ grn_report.h \
+ request_canceler.c \
+ grn_request_canceler.h \
+ request_timer.c \
+ grn_request_timer.h \
+ rset.c \
+ grn_rset.h \
+ scanner.c \
+ grn_scanner.h \
+ scorer.c \
+ grn_scorer.h \
+ scorers.c \
+ grn_scorers.h \
+ snip.c \
+ grn_snip.h \
+ store.c \
+ grn_store.h \
+ str.c \
+ grn_str.h \
+ string.c \
+ grn_string.h \
+ table.c \
+ thread.c \
+ time.c \
+ grn_time.h \
+ token_cursor.c \
+ grn_token_cursor.h \
+ tokenizer.c \
+ tokenizers.c \
+ grn_tokenizers.h \
+ token_filter.c \
+ util.c \
+ grn_util.h \
+ windows.c \
+ grn_windows.h \
+ windows_event_logger.c \
+ file_reader.c \
+ window_function.c \
+ grn_window_function.h \
+ window_functions.c \
+ grn_window_functions.h
diff --git a/storage/mroonga/vendor/groonga/lib/cache.c b/storage/mroonga/vendor/groonga/lib/cache.c
new file mode 100644
index 00000000..79a2c678
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/cache.c
@@ -0,0 +1,1036 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_cache.h"
+#include "grn_ctx.h"
+#include "grn_ctx_impl.h"
+#include "grn_hash.h"
+#include "grn_pat.h"
+#include "grn_store.h"
+#include "grn_db.h"
+#include "grn_file_lock.h"
+
+#include <sys/stat.h>
+
+typedef struct _grn_cache_entry_memory grn_cache_entry_memory;
+
+struct _grn_cache_entry_memory {
+ grn_cache_entry_memory *next;
+ grn_cache_entry_memory *prev;
+ grn_obj *value;
+ grn_timeval tv;
+ grn_id id;
+};
+
+typedef struct _grn_cache_entry_persistent_data {
+ grn_id next;
+ grn_id prev;
+ grn_timeval modified_time;
+} grn_cache_entry_persistent_data;
+
+/*
+ sizeof(grn_cache_entry_persistent_metadata) should be equal or smaller
+ than sizeof(grn_cache_entry_persistent_data).
+ */
+typedef struct _grn_cache_entry_persistent_metadata {
+ uint32_t max_nentries;
+ uint32_t nfetches;
+ uint32_t nhits;
+} grn_cache_entry_persistent_metadata;
+
+typedef union _grn_cache_entry_persistent {
+ grn_cache_entry_persistent_data data;
+ grn_cache_entry_persistent_metadata metadata;
+} grn_cache_entry_persistent;
+
+struct _grn_cache {
+ union {
+ struct {
+ grn_cache_entry_memory *next;
+ grn_cache_entry_memory *prev;
+ grn_hash *hash;
+ grn_mutex mutex;
+ uint32_t max_nentries;
+ uint32_t nfetches;
+ uint32_t nhits;
+ } memory;
+ struct {
+ grn_hash *keys;
+ grn_ja *values;
+ int timeout;
+ } persistent;
+ } impl;
+ grn_bool is_memory;
+ grn_ctx *ctx;
+};
+
+#define GRN_CACHE_PERSISTENT_ROOT_ID 1
+#define GRN_CACHE_PERSISTENT_ROOT_KEY "\0"
+#define GRN_CACHE_PERSISTENT_ROOT_KEY_LEN \
+ (sizeof(GRN_CACHE_PERSISTENT_ROOT_KEY) - 1)
+#define GRN_CACHE_PERSISTENT_METADATA_ID 2
+#define GRN_CACHE_PERSISTENT_METADATA_KEY "\1"
+#define GRN_CACHE_PERSISTENT_METADATA_KEY_LEN \
+ (sizeof(GRN_CACHE_PERSISTENT_METADATA_KEY) - 1)
+
+static grn_ctx grn_cache_ctx;
+static grn_cache *grn_cache_current = NULL;
+static grn_cache *grn_cache_default = NULL;
+static char grn_cache_default_base_path[PATH_MAX];
+
+void
+grn_set_default_cache_base_path(const char *base_path)
+{
+ if (base_path) {
+ grn_strcpy(grn_cache_default_base_path,
+ PATH_MAX,
+ base_path);
+ } else {
+ grn_cache_default_base_path[0] = '\0';
+ }
+}
+
+const char *
+grn_get_default_cache_base_path(void)
+{
+ if (grn_cache_default_base_path[0] == '\0') {
+ return NULL;
+ } else {
+ return grn_cache_default_base_path;
+ }
+}
+
+static void
+grn_cache_open_memory(grn_ctx *ctx, grn_cache *cache)
+{
+ cache->impl.memory.next = (grn_cache_entry_memory *)cache;
+ cache->impl.memory.prev = (grn_cache_entry_memory *)cache;
+ cache->impl.memory.hash = grn_hash_create(cache->ctx,
+ NULL,
+ GRN_CACHE_MAX_KEY_SIZE,
+ sizeof(grn_cache_entry_memory),
+ GRN_OBJ_KEY_VAR_SIZE);
+ if (!cache->impl.memory.hash) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "[cache] failed to create hash table");
+ return;
+ }
+ MUTEX_INIT(cache->impl.memory.mutex);
+
+ cache->impl.memory.max_nentries = GRN_CACHE_DEFAULT_MAX_N_ENTRIES;
+ cache->impl.memory.nfetches = 0;
+ cache->impl.memory.nhits = 0;
+}
+
+static void
+grn_cache_open_persistent(grn_ctx *ctx,
+ grn_cache *cache,
+ const char *base_path)
+{
+ grn_file_lock file_lock;
+ char *keys_path = NULL;
+ char *values_path = NULL;
+ char lock_path_buffer[PATH_MAX];
+ char keys_path_buffer[PATH_MAX];
+ char values_path_buffer[PATH_MAX];
+
+ cache->impl.persistent.timeout = 1000;
+
+ if (base_path) {
+ grn_snprintf(lock_path_buffer, PATH_MAX, PATH_MAX, "%s.lock", base_path);
+ grn_file_lock_init(ctx, &file_lock, lock_path_buffer);
+ } else {
+ grn_file_lock_init(ctx, &file_lock, NULL);
+ }
+
+ if (base_path) {
+ struct stat stat_buffer;
+
+ grn_snprintf(keys_path_buffer, PATH_MAX, PATH_MAX, "%s.keys", base_path);
+ grn_snprintf(values_path_buffer, PATH_MAX, PATH_MAX, "%s.values", base_path);
+ keys_path = keys_path_buffer;
+ values_path = values_path_buffer;
+
+ if (!grn_file_lock_acquire(ctx,
+ &file_lock,
+ cache->impl.persistent.timeout,
+ "[cache][persistent][open]")) {
+ goto exit;
+ }
+
+ if (stat(keys_path, &stat_buffer) == 0) {
+ cache->impl.persistent.keys = grn_hash_open(ctx, keys_path);
+ if (cache->impl.persistent.keys) {
+ cache->impl.persistent.values = grn_ja_open(ctx, values_path);
+ }
+ }
+ if (!cache->impl.persistent.keys) {
+ if (cache->impl.persistent.values) {
+ grn_ja_close(ctx, cache->impl.persistent.values);
+ cache->impl.persistent.values = NULL;
+ }
+ if (stat(keys_path, &stat_buffer) == 0) {
+ if (grn_hash_remove(ctx, keys_path) != GRN_SUCCESS) {
+ ERRNO_ERR("[cache][persistent] "
+ "failed to remove path for cache keys: <%s>",
+ keys_path);
+ goto exit;
+ }
+ }
+ if (stat(values_path, &stat_buffer) == 0) {
+ if (grn_ja_remove(ctx, values_path) != GRN_SUCCESS) {
+ ERRNO_ERR("[cache][persistent] "
+ "failed to remove path for cache values: <%s>",
+ values_path);
+ goto exit;
+ }
+ }
+ }
+ }
+
+ if (!cache->impl.persistent.keys) {
+ cache->impl.persistent.keys =
+ grn_hash_create(ctx,
+ keys_path,
+ GRN_CACHE_MAX_KEY_SIZE,
+ sizeof(grn_cache_entry_persistent),
+ GRN_OBJ_KEY_VAR_SIZE);
+ if (!cache->impl.persistent.keys) {
+ ERR(ctx->rc == GRN_SUCCESS ? GRN_FILE_CORRUPT : ctx->rc,
+ "[cache][persistent] failed to create cache keys storage: <%s>",
+ keys_path ? keys_path : "(memory)");
+ goto exit;
+ }
+ cache->impl.persistent.values =
+ grn_ja_create(ctx,
+ values_path,
+ 1 << 16,
+ 0);
+ if (!cache->impl.persistent.values) {
+ grn_hash_close(ctx, cache->impl.persistent.keys);
+ ERR(ctx->rc == GRN_SUCCESS ? GRN_FILE_CORRUPT : ctx->rc,
+ "[cache][persistent] failed to create cache values storage: <%s>",
+ values_path ? values_path : "(memory)");
+ goto exit;
+ }
+ }
+
+ {
+ grn_cache_entry_persistent *entry;
+ grn_id root_id;
+ int added;
+
+ root_id = grn_hash_add(ctx,
+ cache->impl.persistent.keys,
+ GRN_CACHE_PERSISTENT_ROOT_KEY,
+ GRN_CACHE_PERSISTENT_ROOT_KEY_LEN,
+ (void **)&entry,
+ &added);
+ if (root_id != GRN_CACHE_PERSISTENT_ROOT_ID) {
+ grn_ja_close(ctx, cache->impl.persistent.values);
+ grn_hash_close(ctx, cache->impl.persistent.keys);
+ if (values_path) {
+ grn_ja_remove(ctx, values_path);
+ }
+ if (keys_path) {
+ grn_hash_remove(ctx, keys_path);
+ }
+ ERR(ctx->rc == GRN_SUCCESS ? GRN_FILE_CORRUPT : ctx->rc,
+ "[cache][persistent] broken cache keys storage: broken root: <%s>",
+ keys_path ? keys_path : "(memory)");
+ return;
+ }
+
+ if (added) {
+ entry->data.next = root_id;
+ entry->data.prev = root_id;
+ entry->data.modified_time.tv_sec = 0;
+ entry->data.modified_time.tv_nsec = 0;
+ }
+ }
+
+ {
+ grn_cache_entry_persistent *entry;
+ grn_id metadata_id;
+ int added;
+
+ metadata_id = grn_hash_add(ctx,
+ cache->impl.persistent.keys,
+ GRN_CACHE_PERSISTENT_METADATA_KEY,
+ GRN_CACHE_PERSISTENT_METADATA_KEY_LEN,
+ (void **)&entry,
+ &added);
+ if (metadata_id != GRN_CACHE_PERSISTENT_METADATA_ID) {
+ grn_ja_close(ctx, cache->impl.persistent.values);
+ grn_hash_close(ctx, cache->impl.persistent.keys);
+ if (values_path) {
+ grn_ja_remove(ctx, values_path);
+ }
+ if (keys_path) {
+ grn_hash_remove(ctx, keys_path);
+ }
+ ERR(ctx->rc == GRN_SUCCESS ? GRN_FILE_CORRUPT : ctx->rc,
+ "[cache][persistent] broken cache keys storage: broken metadata: <%s>",
+ keys_path ? keys_path : "(memory)");
+ goto exit;
+ }
+
+ if (added) {
+ entry->metadata.max_nentries = GRN_CACHE_DEFAULT_MAX_N_ENTRIES;
+ entry->metadata.nfetches = 0;
+ entry->metadata.nhits = 0;
+ }
+ }
+
+exit :
+ grn_file_lock_release(ctx, &file_lock);
+ grn_file_lock_fin(ctx, &file_lock);
+}
+
+static grn_cache *
+grn_cache_open_raw(grn_ctx *ctx,
+ grn_bool is_memory,
+ const char *base_path)
+{
+ grn_cache *cache = NULL;
+
+ GRN_API_ENTER;
+ cache = GRN_CALLOC(sizeof(grn_cache));
+ if (!cache) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "[cache] failed to allocate grn_cache");
+ goto exit;
+ }
+
+ cache->ctx = ctx;
+ cache->is_memory = is_memory;
+ if (cache->is_memory) {
+ grn_cache_open_memory(ctx, cache);
+ } else {
+ grn_cache_open_persistent(ctx, cache, base_path);
+ }
+ if (ctx->rc != GRN_SUCCESS) {
+ GRN_FREE(cache);
+ cache = NULL;
+ goto exit;
+ }
+
+exit :
+ GRN_API_RETURN(cache);
+}
+
+grn_cache *
+grn_cache_open(grn_ctx *ctx)
+{
+ const char *base_path = NULL;
+ grn_bool is_memory;
+
+ if (grn_cache_default_base_path[0] != '\0') {
+ base_path = grn_cache_default_base_path;
+ }
+
+ if (base_path) {
+ is_memory = GRN_FALSE;
+ } else {
+ char grn_cache_type_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_CACHE_TYPE", grn_cache_type_env, GRN_ENV_BUFFER_SIZE);
+ if (strcmp(grn_cache_type_env, "persistent") == 0) {
+ is_memory = GRN_FALSE;
+ } else {
+ is_memory = GRN_TRUE;
+ }
+ }
+
+ return grn_cache_open_raw(ctx, is_memory, base_path);
+}
+
+grn_cache *
+grn_persistent_cache_open(grn_ctx *ctx, const char *base_path)
+{
+ grn_bool is_memory = GRN_FALSE;
+ return grn_cache_open_raw(ctx, is_memory, base_path);
+}
+
+
+static void
+grn_cache_close_memory(grn_ctx *ctx, grn_cache *cache)
+{
+ grn_cache_entry_memory *vp;
+
+ GRN_HASH_EACH(ctx, cache->impl.memory.hash, id, NULL, NULL, &vp, {
+ grn_obj_close(ctx, vp->value);
+ });
+ grn_hash_close(ctx, cache->impl.memory.hash);
+ MUTEX_FIN(cache->impl.memory.mutex);
+}
+
+static void
+grn_cache_close_persistent(grn_ctx *ctx, grn_cache *cache)
+{
+ grn_hash_close(ctx, cache->impl.persistent.keys);
+ grn_ja_close(ctx, cache->impl.persistent.values);
+}
+
+grn_rc
+grn_cache_close(grn_ctx *ctx_not_used, grn_cache *cache)
+{
+ grn_ctx *ctx = cache->ctx;
+
+ GRN_API_ENTER;
+
+ if (cache->is_memory) {
+ grn_cache_close_memory(ctx, cache);
+ } else {
+ grn_cache_close_persistent(ctx, cache);
+ }
+ GRN_FREE(cache);
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_cache_current_set(grn_ctx *ctx, grn_cache *cache)
+{
+ grn_cache_current = cache;
+ return GRN_SUCCESS;
+}
+
+grn_cache *
+grn_cache_current_get(grn_ctx *ctx)
+{
+ return grn_cache_current;
+}
+
+void
+grn_cache_init(void)
+{
+ grn_ctx *ctx = &grn_cache_ctx;
+
+ grn_ctx_init(ctx, 0);
+
+ grn_cache_default = grn_cache_open(ctx);
+ grn_cache_current_set(ctx, grn_cache_default);
+}
+
+grn_rc
+grn_cache_default_reopen(void)
+{
+ grn_ctx *ctx = &grn_cache_ctx;
+ grn_cache *new_default;
+ grn_bool default_is_current;
+
+ GRN_API_ENTER;
+
+ new_default = grn_cache_open(ctx);
+ if (!new_default) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ default_is_current = (grn_cache_default == grn_cache_current_get(ctx));
+ if (default_is_current) {
+ grn_cache_current_set(ctx, new_default);
+ }
+
+ if (grn_cache_default) {
+ grn_cache_close(ctx, grn_cache_default);
+ }
+ grn_cache_default = new_default;
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+static void
+grn_cache_expire_entry_memory(grn_cache *cache, grn_cache_entry_memory *ce)
+{
+ ce->prev->next = ce->next;
+ ce->next->prev = ce->prev;
+ grn_obj_close(cache->ctx, ce->value);
+ grn_hash_delete_by_id(cache->ctx, cache->impl.memory.hash, ce->id, NULL);
+}
+
+static void
+grn_cache_entry_persistent_delete_link(grn_cache *cache,
+ grn_cache_entry_persistent *entry)
+{
+ grn_ctx *ctx = cache->ctx;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_cache_entry_persistent *prev_entry;
+ grn_cache_entry_persistent *next_entry;
+
+ prev_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ entry->data.prev,
+ NULL);
+ next_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ entry->data.next,
+ NULL);
+ prev_entry->data.next = entry->data.next;
+ next_entry->data.prev = entry->data.prev;
+}
+
+static void
+grn_cache_entry_persistent_prepend_link(grn_cache *cache,
+ grn_cache_entry_persistent *entry,
+ grn_id entry_id,
+ grn_cache_entry_persistent *head_entry,
+ grn_id head_entry_id)
+{
+ grn_ctx *ctx = cache->ctx;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_cache_entry_persistent *head_next_entry;
+
+ entry->data.next = head_entry->data.next;
+ entry->data.prev = head_entry_id;
+ head_next_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ head_entry->data.next,
+ NULL);
+ head_next_entry->data.prev = entry_id;
+ head_entry->data.next = entry_id;
+}
+
+static void
+grn_cache_expire_entry_persistent(grn_cache *cache,
+ grn_cache_entry_persistent *entry,
+ grn_id cache_id)
+{
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_ja *values = cache->impl.persistent.values;
+
+ grn_cache_entry_persistent_delete_link(cache, entry);
+ grn_ja_put(cache->ctx, values, cache_id, NULL, 0, GRN_OBJ_SET, NULL);
+ grn_hash_delete_by_id(cache->ctx, keys, cache_id, NULL);
+}
+
+static void
+grn_cache_expire_memory_without_lock(grn_cache *cache, int32_t size)
+{
+ grn_cache_entry_memory *ce0 =
+ (grn_cache_entry_memory *)(&(cache->impl.memory));
+ while (ce0 != ce0->prev && size--) {
+ grn_cache_expire_entry_memory(cache, ce0->prev);
+ }
+}
+
+static void
+grn_cache_expire_persistent_without_lock(grn_cache *cache, int32_t size)
+{
+ grn_ctx *ctx = cache->ctx;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_cache_entry_persistent *head_entry;
+
+ head_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_ROOT_ID,
+ NULL);
+ while (head_entry->data.prev != GRN_CACHE_PERSISTENT_ROOT_ID &&
+ size > 0) {
+ grn_cache_entry_persistent *tail_entry;
+ tail_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ head_entry->data.prev,
+ NULL);
+ grn_cache_expire_entry_persistent(cache, tail_entry, head_entry->data.prev);
+ size--;
+ }
+}
+
+static grn_rc
+grn_cache_set_max_n_entries_memory(grn_ctx *ctx,
+ grn_cache *cache,
+ unsigned int n)
+{
+ uint32_t current_max_n_entries;
+
+ MUTEX_LOCK(cache->impl.memory.mutex);
+ current_max_n_entries = cache->impl.memory.max_nentries;
+ cache->impl.memory.max_nentries = n;
+ if (n < current_max_n_entries) {
+ grn_cache_expire_memory_without_lock(cache, current_max_n_entries - n);
+ }
+ MUTEX_UNLOCK(cache->impl.memory.mutex);
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_cache_set_max_n_entries_persistent(grn_ctx *ctx,
+ grn_cache *cache,
+ unsigned int n)
+{
+ grn_rc rc;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_cache_entry_persistent *metadata_entry;
+ uint32_t current_max_n_entries;
+
+ rc = grn_io_lock(ctx, keys->io, cache->impl.persistent.timeout);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ metadata_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_METADATA_ID,
+ NULL);
+
+ current_max_n_entries = metadata_entry->metadata.max_nentries;
+ metadata_entry->metadata.max_nentries = n;
+ if (n < current_max_n_entries) {
+ grn_cache_expire_persistent_without_lock(cache, current_max_n_entries - n);
+ }
+ grn_io_unlock(keys->io);
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_cache_set_max_n_entries(grn_ctx *ctx, grn_cache *cache, unsigned int n)
+{
+ if (!cache) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (cache->is_memory) {
+ return grn_cache_set_max_n_entries_memory(cache->ctx, cache, n);
+ } else {
+ return grn_cache_set_max_n_entries_persistent(cache->ctx, cache, n);
+ }
+}
+
+static uint32_t
+grn_cache_get_max_n_entries_memory(grn_ctx *ctx, grn_cache *cache)
+{
+ return cache->impl.memory.max_nentries;
+}
+
+static uint32_t
+grn_cache_get_max_n_entries_persistent(grn_ctx *ctx, grn_cache *cache)
+{
+ grn_rc rc;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_cache_entry_persistent *metadata_entry;
+ uint32_t current_max_n_entries;
+
+ rc = grn_io_lock(ctx, keys->io, cache->impl.persistent.timeout);
+ if (rc != GRN_SUCCESS) {
+ return 0;
+ }
+
+ metadata_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_METADATA_ID,
+ NULL);
+ current_max_n_entries = metadata_entry->metadata.max_nentries;
+ grn_io_unlock(keys->io);
+
+ return current_max_n_entries;
+}
+
+uint32_t
+grn_cache_get_max_n_entries(grn_ctx *ctx, grn_cache *cache)
+{
+ if (!cache) {
+ return 0;
+ }
+
+ if (cache->is_memory) {
+ return grn_cache_get_max_n_entries_memory(cache->ctx, cache);
+ } else {
+ return grn_cache_get_max_n_entries_persistent(cache->ctx, cache);
+ }
+}
+
+static void
+grn_cache_get_statistics_memory(grn_ctx *ctx, grn_cache *cache,
+ grn_cache_statistics *statistics)
+{
+ MUTEX_LOCK(cache->impl.memory.mutex);
+ statistics->nentries = GRN_HASH_SIZE(cache->impl.memory.hash);
+ statistics->max_nentries = cache->impl.memory.max_nentries;
+ statistics->nfetches = cache->impl.memory.nfetches;
+ statistics->nhits = cache->impl.memory.nhits;
+ MUTEX_UNLOCK(cache->impl.memory.mutex);
+}
+
+static void
+grn_cache_get_statistics_persistent(grn_ctx *ctx, grn_cache *cache,
+ grn_cache_statistics *statistics)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_cache_entry_persistent *metadata_entry;
+
+ rc = grn_io_lock(ctx, keys->io, cache->impl.persistent.timeout);
+ if (rc != GRN_SUCCESS) {
+ return;
+ }
+
+ metadata_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_METADATA_ID,
+ NULL);
+
+ statistics->nentries = GRN_HASH_SIZE(keys);
+ statistics->max_nentries = metadata_entry->metadata.max_nentries;
+ statistics->nfetches = metadata_entry->metadata.nfetches;
+ statistics->nhits = metadata_entry->metadata.nhits;
+
+ grn_io_unlock(keys->io);
+}
+
+void
+grn_cache_get_statistics(grn_ctx *ctx, grn_cache *cache,
+ grn_cache_statistics *statistics)
+{
+ if (cache->is_memory) {
+ return grn_cache_get_statistics_memory(ctx, cache, statistics);
+ } else {
+ return grn_cache_get_statistics_persistent(ctx, cache, statistics);
+ }
+}
+
+static grn_rc
+grn_cache_fetch_memory(grn_ctx *ctx, grn_cache *cache,
+ const char *key, uint32_t key_len,
+ grn_obj *output)
+{
+ /* TODO: How about GRN_NOT_FOUND? */
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_cache_entry_memory *ce;
+
+ MUTEX_LOCK(cache->impl.memory.mutex);
+ cache->impl.memory.nfetches++;
+ if (grn_hash_get(cache->ctx, cache->impl.memory.hash, key, key_len,
+ (void **)&ce)) {
+ if (ce->tv.tv_sec <= grn_db_get_last_modified(ctx, ctx->impl->db)) {
+ grn_cache_expire_entry_memory(cache, ce);
+ goto exit;
+ }
+ rc = GRN_SUCCESS;
+ GRN_TEXT_PUT(ctx,
+ output,
+ GRN_TEXT_VALUE(ce->value),
+ GRN_TEXT_LEN(ce->value));
+ ce->prev->next = ce->next;
+ ce->next->prev = ce->prev;
+ {
+ grn_cache_entry_memory *ce0 =
+ (grn_cache_entry_memory *)(&(cache->impl.memory));
+ ce->next = ce0->next;
+ ce->prev = ce0;
+ ce0->next->prev = ce;
+ ce0->next = ce;
+ }
+ cache->impl.memory.nhits++;
+ }
+exit :
+ MUTEX_UNLOCK(cache->impl.memory.mutex);
+ return rc;
+}
+
+static grn_rc
+grn_cache_fetch_persistent(grn_ctx *ctx, grn_cache *cache,
+ const char *key, uint32_t key_len,
+ grn_obj *output)
+{
+ /* TODO: How about GRN_NOT_FOUND? */
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_ja *values = cache->impl.persistent.values;
+ grn_id cache_id;
+ grn_cache_entry_persistent *entry;
+ grn_cache_entry_persistent *metadata_entry;
+
+ if (key_len == GRN_CACHE_PERSISTENT_ROOT_KEY_LEN &&
+ memcmp(key,
+ GRN_CACHE_PERSISTENT_ROOT_KEY,
+ GRN_CACHE_PERSISTENT_ROOT_KEY_LEN) == 0) {
+ return rc;
+ }
+
+ rc = grn_io_lock(ctx, keys->io, cache->impl.persistent.timeout);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ /* TODO: How about GRN_NOT_FOUND? */
+ rc = GRN_INVALID_ARGUMENT;
+
+ metadata_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_METADATA_ID,
+ NULL);
+ metadata_entry->metadata.nfetches++;
+
+ cache_id = grn_hash_get(cache->ctx, keys, key, key_len, (void **)&entry);
+ if (cache_id == GRN_ID_NIL) {
+ goto exit;
+ }
+
+ if (cache_id != GRN_ID_NIL) {
+ if (entry->data.modified_time.tv_sec <=
+ grn_db_get_last_modified(ctx, ctx->impl->db)) {
+ grn_cache_expire_entry_persistent(cache, entry, cache_id);
+ goto exit;
+ }
+
+ rc = GRN_SUCCESS;
+ grn_ja_get_value(ctx, values, cache_id, output);
+ grn_cache_entry_persistent_delete_link(cache, entry);
+ {
+ grn_cache_entry_persistent *head_entry;
+ head_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_ROOT_ID,
+ NULL);
+ grn_cache_entry_persistent_prepend_link(cache,
+ entry,
+ cache_id,
+ head_entry,
+ GRN_CACHE_PERSISTENT_ROOT_ID);
+ }
+ metadata_entry->metadata.nhits++;
+ }
+
+exit :
+ grn_io_unlock(keys->io);
+
+ return rc;
+}
+
+grn_rc
+grn_cache_fetch(grn_ctx *ctx, grn_cache *cache,
+ const char *key, uint32_t key_len,
+ grn_obj *output)
+{
+ if (!ctx->impl || !ctx->impl->db) { return GRN_INVALID_ARGUMENT; }
+
+ if (cache->is_memory) {
+ return grn_cache_fetch_memory(ctx, cache, key, key_len, output);
+ } else {
+ return grn_cache_fetch_persistent(ctx, cache, key, key_len, output);
+ }
+}
+
+static void
+grn_cache_update_memory(grn_ctx *ctx, grn_cache *cache,
+ const char *key, uint32_t key_len,
+ grn_obj *value)
+{
+ grn_id id;
+ int added = 0;
+ grn_cache_entry_memory *ce;
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *old = NULL;
+ grn_obj *obj = NULL;
+
+ if (cache->impl.memory.max_nentries == 0) {
+ return;
+ }
+
+ MUTEX_LOCK(cache->impl.memory.mutex);
+ obj = grn_obj_open(cache->ctx, GRN_BULK, 0, GRN_DB_TEXT);
+ if (!obj) {
+ goto exit;
+ }
+ GRN_TEXT_PUT(cache->ctx, obj, GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
+ id = grn_hash_add(cache->ctx, cache->impl.memory.hash, key, key_len,
+ (void **)&ce, &added);
+ if (id) {
+ if (!added) {
+ old = ce->value;
+ ce->prev->next = ce->next;
+ ce->next->prev = ce->prev;
+ }
+ ce->id = id;
+ ce->value = obj;
+ ce->tv = ctx->impl->tv;
+ {
+ grn_cache_entry_memory *ce0 =
+ (grn_cache_entry_memory *)(&(cache->impl.memory));
+ ce->next = ce0->next;
+ ce->prev = ce0;
+ ce0->next->prev = ce;
+ ce0->next = ce;
+ }
+ if (GRN_HASH_SIZE(cache->impl.memory.hash) >
+ cache->impl.memory.max_nentries) {
+ grn_cache_expire_entry_memory(cache, cache->impl.memory.prev);
+ }
+ } else {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+exit :
+ if (rc) { grn_obj_close(cache->ctx, obj); }
+ if (old) { grn_obj_close(cache->ctx, old); }
+ MUTEX_UNLOCK(cache->impl.memory.mutex);
+}
+
+static void
+grn_cache_update_persistent(grn_ctx *ctx, grn_cache *cache,
+ const char *key, uint32_t key_len,
+ grn_obj *value)
+{
+ grn_rc rc;
+ grn_hash *keys = cache->impl.persistent.keys;
+ grn_ja *values = cache->impl.persistent.values;
+ grn_cache_entry_persistent *metadata_entry;
+ grn_id cache_id;
+ grn_cache_entry_persistent *entry;
+ int added;
+
+ if (key_len == GRN_CACHE_PERSISTENT_ROOT_KEY_LEN &&
+ memcmp(key,
+ GRN_CACHE_PERSISTENT_ROOT_KEY,
+ GRN_CACHE_PERSISTENT_ROOT_KEY_LEN) == 0) {
+ return;
+ }
+
+ if (key_len == GRN_CACHE_PERSISTENT_METADATA_KEY_LEN &&
+ memcmp(key,
+ GRN_CACHE_PERSISTENT_METADATA_KEY,
+ GRN_CACHE_PERSISTENT_METADATA_KEY_LEN) == 0) {
+ return;
+ }
+
+ rc = grn_io_lock(ctx, keys->io, cache->impl.persistent.timeout);
+ if (rc != GRN_SUCCESS) {
+ return;
+ }
+
+ metadata_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_METADATA_ID,
+ NULL);
+ if (metadata_entry->metadata.max_nentries == 0) {
+ goto exit;
+ }
+
+ cache_id = grn_hash_add(cache->ctx, keys, key, key_len, (void **)&entry,
+ &added);
+ if (cache_id) {
+ grn_cache_entry_persistent *head_entry;
+
+ if (!added) {
+ grn_cache_entry_persistent_delete_link(cache, entry);
+ }
+ entry->data.modified_time = ctx->impl->tv;
+
+ grn_ja_put(cache->ctx, values, cache_id,
+ GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value),
+ GRN_OBJ_SET, NULL);
+
+ head_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ GRN_CACHE_PERSISTENT_ROOT_ID,
+ NULL);
+ grn_cache_entry_persistent_prepend_link(cache,
+ entry,
+ cache_id,
+ head_entry,
+ GRN_CACHE_PERSISTENT_ROOT_ID);
+ if (GRN_HASH_SIZE(keys) > metadata_entry->metadata.max_nentries) {
+ grn_cache_entry_persistent *tail_entry;
+ tail_entry =
+ (grn_cache_entry_persistent *)grn_hash_get_value_(ctx,
+ keys,
+ head_entry->data.prev,
+ NULL);
+ grn_cache_expire_entry_persistent(cache,
+ tail_entry,
+ head_entry->data.prev);
+ }
+ }
+
+exit :
+ grn_io_unlock(keys->io);
+}
+
+void
+grn_cache_update(grn_ctx *ctx, grn_cache *cache,
+ const char *key, uint32_t key_len, grn_obj *value)
+{
+ if (!ctx->impl) { return; }
+
+ if (cache->is_memory) {
+ grn_cache_update_memory(ctx, cache, key, key_len, value);
+ } else {
+ grn_cache_update_persistent(ctx, cache, key, key_len, value);
+ }
+}
+
+static void
+grn_cache_expire_memory(grn_cache *cache, int32_t size)
+{
+ MUTEX_LOCK(cache->impl.memory.mutex);
+ grn_cache_expire_memory_without_lock(cache, size);
+ MUTEX_UNLOCK(cache->impl.memory.mutex);
+}
+
+static void
+grn_cache_expire_persistent(grn_cache *cache, int32_t size)
+{
+ grn_rc rc;
+ grn_ctx *ctx = cache->ctx;
+ grn_hash *keys = cache->impl.persistent.keys;
+
+ rc = grn_io_lock(ctx, keys->io, cache->impl.persistent.timeout);
+ if (rc != GRN_SUCCESS) {
+ return;
+ }
+
+ grn_cache_expire_persistent_without_lock(cache, size);
+
+ grn_io_unlock(keys->io);
+}
+
+void
+grn_cache_expire(grn_cache *cache, int32_t size)
+{
+ if (cache->is_memory) {
+ grn_cache_expire_memory(cache, size);
+ } else {
+ grn_cache_expire_persistent(cache, size);
+ }
+}
+
+void
+grn_cache_fin(void)
+{
+ grn_ctx *ctx = &grn_cache_ctx;
+
+ grn_cache_current_set(ctx, NULL);
+
+ if (grn_cache_default) {
+ grn_cache_close(ctx, grn_cache_default);
+ grn_cache_default = NULL;
+ }
+
+ grn_ctx_fin(ctx);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/column.c b/storage/mroonga/vendor/groonga/lib/column.c
new file mode 100644
index 00000000..ecfc71b7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/column.c
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_store.h"
+#include "grn_ii.h"
+
+grn_column_flags
+grn_column_get_flags(grn_ctx *ctx, grn_obj *column)
+{
+ grn_column_flags flags = 0;
+
+ GRN_API_ENTER;
+
+ if (!column) {
+ GRN_API_RETURN(0);
+ }
+
+ switch (column->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ flags = column->header.flags;
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ flags = grn_ja_get_flags(ctx, (grn_ja *)column);
+ break;
+ case GRN_COLUMN_INDEX :
+ flags = grn_ii_get_flags(ctx, (grn_ii *)column);
+ break;
+ default :
+ break;
+ }
+
+ GRN_API_RETURN(flags);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/com.c b/storage/mroonga/vendor/groonga/lib/com.c
new file mode 100644
index 00000000..7761f483
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/com.c
@@ -0,0 +1,1202 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2009-2012 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+
+#include <stdio.h>
+#include <string.h>
+#include "grn_ctx_impl.h"
+
+#ifdef WIN32
+# include <ws2tcpip.h>
+#else
+# ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+# endif /* HAVE_SYS_SOCKET_H */
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# ifdef HAVE_SIGNAL_H
+# include <signal.h>
+# endif /* HAVE_SIGNAL_H */
+# include <sys/uio.h>
+#endif /* WIN32 */
+
+#include "grn_ctx.h"
+#include "grn_com.h"
+
+#ifndef PF_INET
+#define PF_INET AF_INET
+#endif /* PF_INET */
+
+#ifndef SOL_TCP
+# ifdef IPPROTO_TCP
+# define SOL_TCP IPPROTO_TCP
+# else
+# define SOL_TCP 6
+# endif /* IPPROTO_TCP */
+#endif /* SOL_TCP */
+
+#ifndef USE_MSG_MORE
+# ifdef MSG_MORE
+# undef MSG_MORE
+# endif
+# define MSG_MORE 0
+#endif /* USE_MSG_MORE */
+
+
+#ifndef USE_MSG_NOSIGNAL
+# ifdef MSG_NOSIGNAL
+# undef MSG_NOSIGNAL
+# endif
+# define MSG_NOSIGNAL 0
+#endif /* USE_MSG_NOSIGNAL */
+/******* grn_com_queue ********/
+
+grn_rc
+grn_com_queue_enque(grn_ctx *ctx, grn_com_queue *q, grn_com_queue_entry *e)
+{
+ CRITICAL_SECTION_ENTER(q->cs);
+ e->next = NULL;
+ *q->tail = e;
+ q->tail = &e->next;
+ CRITICAL_SECTION_LEAVE(q->cs);
+ /*
+ uint8_t i = q->last + 1;
+ e->next = NULL;
+ if (q->first == i || q->next) {
+ CRITICAL_SECTION_ENTER(q->cs);
+ if (q->first == i || q->next) {
+ *q->tail = e;
+ q->tail = &e->next;
+ } else {
+ q->bins[q->last] = e;
+ q->last = i;
+ }
+ CRITICAL_SECTION_LEAVE(q->cs);
+ } else {
+ q->bins[q->last] = e;
+ q->last = i;
+ }
+ */
+ return GRN_SUCCESS;
+}
+
+grn_com_queue_entry *
+grn_com_queue_deque(grn_ctx *ctx, grn_com_queue *q)
+{
+ grn_com_queue_entry *e = NULL;
+
+ CRITICAL_SECTION_ENTER(q->cs);
+ if (q->next) {
+ e = q->next;
+ if (!(q->next = e->next)) { q->tail = &q->next; }
+ }
+ CRITICAL_SECTION_LEAVE(q->cs);
+
+ /*
+ if (q->first == q->last) {
+ if (q->next) {
+ CRITICAL_SECTION_ENTER(q->cs);
+ e = q->next;
+ if (!(q->next = e->next)) { q->tail = &q->next; }
+ CRITICAL_SECTION_LEAVE(q->cs);
+ }
+ } else {
+ e = q->bins[q->first++];
+ }
+ */
+ return e;
+}
+
+/******* grn_msg ********/
+
+grn_obj *
+grn_msg_open(grn_ctx *ctx, grn_com *com, grn_com_queue *old)
+{
+ grn_msg *msg = NULL;
+ if (old && (msg = (grn_msg *)grn_com_queue_deque(ctx, old))) {
+ if (msg->ctx != ctx) {
+ ERR(GRN_INVALID_ARGUMENT, "ctx unmatch");
+ return NULL;
+ }
+ GRN_BULK_REWIND(&msg->qe.obj);
+ } else if ((msg = GRN_MALLOCN(grn_msg, 1))) {
+ GRN_OBJ_INIT(&msg->qe.obj, GRN_MSG, 0, GRN_DB_TEXT);
+ msg->qe.obj.header.impl_flags |= GRN_OBJ_ALLOCATED;
+ msg->ctx = ctx;
+ }
+ msg->qe.next = NULL;
+ msg->u.peer = com;
+ msg->old = old;
+ memset(&msg->header, 0, sizeof(grn_com_header));
+ return (grn_obj *)msg;
+}
+
+grn_obj *
+grn_msg_open_for_reply(grn_ctx *ctx, grn_obj *query, grn_com_queue *old)
+{
+ grn_msg *req = (grn_msg *)query, *msg = NULL;
+ if (req && (msg = (grn_msg *)grn_msg_open(ctx, req->u.peer, old))) {
+ msg->edge_id = req->edge_id;
+ msg->header.proto = req->header.proto == GRN_COM_PROTO_MBREQ
+ ? GRN_COM_PROTO_MBRES : req->header.proto;
+ }
+ return (grn_obj *)msg;
+}
+
+grn_rc
+grn_msg_close(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_msg *msg = (grn_msg *)obj;
+ if (ctx == msg->ctx) { return grn_obj_close(ctx, obj); }
+ return grn_com_queue_enque(ctx, msg->old, (grn_com_queue_entry *)msg);
+}
+
+grn_rc
+grn_msg_set_property(grn_ctx *ctx, grn_obj *obj,
+ uint16_t status, uint32_t key_size, uint8_t extra_size)
+{
+ grn_com_header *header = &((grn_msg *)obj)->header;
+ header->status = htons(status);
+ header->keylen = htons(key_size);
+ header->level = extra_size;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_msg_send(grn_ctx *ctx, grn_obj *msg, int flags)
+{
+ grn_rc rc;
+ grn_msg *m = (grn_msg *)msg;
+ grn_com *peer = m->u.peer;
+ grn_com_header *header = &m->header;
+ if (GRN_COM_QUEUE_EMPTYP(&peer->new_)) {
+ switch (header->proto) {
+ case GRN_COM_PROTO_HTTP :
+ {
+ ssize_t ret;
+ ret = send(peer->fd, GRN_BULK_HEAD(msg), GRN_BULK_VSIZE(msg), MSG_NOSIGNAL);
+ if (ret == -1) { SOERR("send"); }
+ if (ctx->rc != GRN_OPERATION_WOULD_BLOCK) {
+ grn_com_queue_enque(ctx, m->old, (grn_com_queue_entry *)msg);
+ return ctx->rc;
+ }
+ }
+ break;
+ case GRN_COM_PROTO_GQTP :
+ {
+ if (flags & GRN_CTX_MORE) { flags |= GRN_CTX_QUIET; }
+ if (ctx->stat == GRN_CTX_QUIT) { flags |= GRN_CTX_QUIT; }
+ header->qtype = (uint8_t) ctx->impl->output.type;
+ header->keylen = 0;
+ header->level = 0;
+ header->flags = flags;
+ header->status = htons((uint16_t)ctx->rc);
+ header->opaque = 0;
+ header->cas = 0;
+ //todo : MSG_DONTWAIT
+ rc = grn_com_send(ctx, peer, header,
+ GRN_BULK_HEAD(msg), GRN_BULK_VSIZE(msg), 0);
+ if (rc != GRN_OPERATION_WOULD_BLOCK) {
+ grn_com_queue_enque(ctx, m->old, (grn_com_queue_entry *)msg);
+ return rc;
+ }
+ }
+ break;
+ case GRN_COM_PROTO_MBREQ :
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+ case GRN_COM_PROTO_MBRES :
+ rc = grn_com_send(ctx, peer, header,
+ GRN_BULK_HEAD(msg), GRN_BULK_VSIZE(msg),
+ (flags & GRN_CTX_MORE) ? MSG_MORE :0);
+ if (rc != GRN_OPERATION_WOULD_BLOCK) {
+ grn_com_queue_enque(ctx, m->old, (grn_com_queue_entry *)msg);
+ return rc;
+ }
+ break;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+ MUTEX_LOCK(peer->ev->mutex);
+ rc = grn_com_queue_enque(ctx, &peer->new_, (grn_com_queue_entry *)msg);
+ COND_SIGNAL(peer->ev->cond);
+ MUTEX_UNLOCK(peer->ev->mutex);
+ return rc;
+}
+
+/******* grn_com ********/
+
+grn_rc
+grn_com_init(void)
+{
+#ifdef WIN32
+ WSADATA wd;
+ if (WSAStartup(MAKEWORD(2, 0), &wd) != 0) {
+ grn_ctx *ctx = &grn_gctx;
+ SOERR("WSAStartup");
+ }
+#else /* WIN32 */
+#ifndef USE_MSG_NOSIGNAL
+ if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+ grn_ctx *ctx = &grn_gctx;
+ SERR("signal");
+ }
+#endif /* USE_MSG_NOSIGNAL */
+#endif /* WIN32 */
+ return grn_gctx.rc;
+}
+
+void
+grn_com_fin(void)
+{
+#ifdef WIN32
+ WSACleanup();
+#endif /* WIN32 */
+}
+
+grn_rc
+grn_com_event_init(grn_ctx *ctx, grn_com_event *ev, int max_nevents, int data_size)
+{
+ ev->max_nevents = max_nevents;
+ if ((ev->hash = grn_hash_create(ctx, NULL, sizeof(grn_sock), data_size, 0))) {
+ MUTEX_INIT(ev->mutex);
+ COND_INIT(ev->cond);
+ GRN_COM_QUEUE_INIT(&ev->recv_old);
+ ev->msg_handler = NULL;
+ memset(&(ev->curr_edge_id), 0, sizeof(grn_com_addr));
+ ev->acceptor = NULL;
+ ev->opaque = NULL;
+#ifndef USE_SELECT
+# ifdef USE_EPOLL
+ if ((ev->events = GRN_MALLOC(sizeof(struct epoll_event) * max_nevents))) {
+ if ((ev->epfd = epoll_create(max_nevents)) != -1) {
+ goto exit;
+ } else {
+ SERR("epoll_create");
+ }
+ GRN_FREE(ev->events);
+ }
+# else /* USE_EPOLL */
+# ifdef USE_KQUEUE
+ if ((ev->events = GRN_MALLOC(sizeof(struct kevent) * max_nevents))) {
+ if ((ev->kqfd = kqueue()) != -1) {
+ goto exit;
+ } else {
+ SERR("kqueue");
+ }
+ GRN_FREE(ev->events);
+ }
+# else /* USE_KQUEUE */
+ if ((ev->events = GRN_MALLOC(sizeof(struct pollfd) * max_nevents))) {
+ goto exit;
+ }
+# endif /* USE_KQUEUE*/
+# endif /* USE_EPOLL */
+ grn_hash_close(ctx, ev->hash);
+ ev->hash = NULL;
+ ev->events = NULL;
+#else /* USE_SELECT */
+ goto exit;
+#endif /* USE_SELECT */
+ }
+exit :
+ return ctx->rc;
+}
+
+grn_rc
+grn_com_event_fin(grn_ctx *ctx, grn_com_event *ev)
+{
+ grn_obj *msg;
+ while ((msg = (grn_obj *)grn_com_queue_deque(ctx, &ev->recv_old))) {
+ grn_msg_close(ctx, msg);
+ }
+ if (ev->hash) { grn_hash_close(ctx, ev->hash); }
+#ifndef USE_SELECT
+ if (ev->events) { GRN_FREE(ev->events); }
+# ifdef USE_EPOLL
+ grn_close(ev->epfd);
+# endif /* USE_EPOLL */
+# ifdef USE_KQUEUE
+ grn_close(ev->kqfd);
+# endif /* USE_KQUEUE*/
+#endif /* USE_SELECT */
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_com_event_add(grn_ctx *ctx, grn_com_event *ev, grn_sock fd, int events, grn_com **com)
+{
+ grn_com *c;
+ /* todo : expand events */
+ if (!ev || *ev->hash->n_entries == (uint32_t) ev->max_nevents) {
+ if (ev) { GRN_LOG(ctx, GRN_LOG_ERROR, "too many connections (%d)", ev->max_nevents); }
+ return GRN_INVALID_ARGUMENT;
+ }
+#ifdef USE_EPOLL
+ {
+ struct epoll_event e;
+ memset(&e, 0, sizeof(struct epoll_event));
+ e.data.fd = (fd);
+ e.events = (uint32_t) events;
+ if (epoll_ctl(ev->epfd, EPOLL_CTL_ADD, (fd), &e) == -1) {
+ SERR("epoll_ctl");
+ return ctx->rc;
+ }
+ }
+#endif /* USE_EPOLL*/
+#ifdef USE_KQUEUE
+ {
+ struct kevent e;
+ /* todo: udata should have fd */
+ EV_SET(&e, (fd), events, EV_ADD, 0, 0, NULL);
+ if (kevent(ev->kqfd, &e, 1, NULL, 0, NULL) == -1) {
+ SERR("kevent");
+ return ctx->rc;
+ }
+ }
+#endif /* USE_KQUEUE */
+ {
+ if (grn_hash_add(ctx, ev->hash, &fd, sizeof(grn_sock), (void **)&c, NULL)) {
+ c->ev = ev;
+ c->fd = fd;
+ c->events = events;
+ if (com) { *com = c; }
+ }
+ }
+ return ctx->rc;
+}
+
+grn_rc
+grn_com_event_mod(grn_ctx *ctx, grn_com_event *ev, grn_sock fd, int events, grn_com **com)
+{
+ grn_com *c;
+ if (!ev) { return GRN_INVALID_ARGUMENT; }
+ if (grn_hash_get(ctx, ev->hash, &fd, sizeof(grn_sock), (void **)&c)) {
+ if (c->fd != fd) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "grn_com_event_mod fd unmatch "
+ "%" GRN_FMT_SOCKET " != %" GRN_FMT_SOCKET,
+ c->fd, fd);
+ return GRN_OBJECT_CORRUPT;
+ }
+ if (com) { *com = c; }
+ if (c->events != events) {
+#ifdef USE_EPOLL
+ struct epoll_event e;
+ memset(&e, 0, sizeof(struct epoll_event));
+ e.data.fd = (fd);
+ e.events = (uint32_t) events;
+ if (epoll_ctl(ev->epfd, EPOLL_CTL_MOD, (fd), &e) == -1) {
+ SERR("epoll_ctl");
+ return ctx->rc;
+ }
+#endif /* USE_EPOLL*/
+#ifdef USE_KQUEUE
+ // experimental
+ struct kevent e[2];
+ EV_SET(&e[0], (fd), GRN_COM_POLLIN|GRN_COM_POLLOUT, EV_DELETE, 0, 0, NULL);
+ EV_SET(&e[1], (fd), events, EV_ADD, 0, 0, NULL);
+ if (kevent(ev->kqfd, e, 2, NULL, 0, NULL) == -1) {
+ SERR("kevent");
+ return ctx->rc;
+ }
+#endif /* USE_KQUEUE */
+ c->events = events;
+ }
+ return GRN_SUCCESS;
+ }
+ return GRN_INVALID_ARGUMENT;
+}
+
+grn_rc
+grn_com_event_del(grn_ctx *ctx, grn_com_event *ev, grn_sock fd)
+{
+ if (!ev) { return GRN_INVALID_ARGUMENT; }
+ {
+ grn_com *c;
+ grn_id id = grn_hash_get(ctx, ev->hash, &fd, sizeof(grn_sock), (void **)&c);
+ if (id) {
+#ifdef USE_EPOLL
+ if (!c->closed) {
+ struct epoll_event e;
+ memset(&e, 0, sizeof(struct epoll_event));
+ e.data.fd = fd;
+ e.events = c->events;
+ if (epoll_ctl(ev->epfd, EPOLL_CTL_DEL, fd, &e) == -1) {
+ SERR("epoll_ctl");
+ return ctx->rc;
+ }
+ }
+#endif /* USE_EPOLL*/
+#ifdef USE_KQUEUE
+ struct kevent e;
+ EV_SET(&e, (fd), c->events, EV_DELETE, 0, 0, NULL);
+ if (kevent(ev->kqfd, &e, 1, NULL, 0, NULL) == -1) {
+ SERR("kevent");
+ return ctx->rc;
+ }
+#endif /* USE_KQUEUE */
+ return grn_hash_delete_by_id(ctx, ev->hash, id, NULL);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "%04x| fd(%" GRN_FMT_SOCKET ") not found in ev(%p)",
+ grn_getpid(), fd, ev);
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+}
+
+#define LISTEN_BACKLOG 0x1000
+
+grn_rc
+grn_com_event_start_accept(grn_ctx *ctx, grn_com_event *ev)
+{
+ grn_com *com = ev->acceptor;
+
+ if (com->accepting) {return ctx->rc;}
+
+ GRN_API_ENTER;
+ if (!grn_com_event_mod(ctx, ev, com->fd, GRN_COM_POLLIN, NULL)) {
+ if (listen(com->fd, LISTEN_BACKLOG) == 0) {
+ com->accepting = GRN_TRUE;
+ } else {
+ SOERR("listen - start accept");
+ }
+ }
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_com_event_stop_accept(grn_ctx *ctx, grn_com_event *ev)
+{
+ grn_com *com = ev->acceptor;
+
+ if (!com->accepting) {return ctx->rc;}
+
+ GRN_API_ENTER;
+ if (!grn_com_event_mod(ctx, ev, com->fd, 0, NULL)) {
+ if (listen(com->fd, 0) == 0) {
+ com->accepting = GRN_FALSE;
+ } else {
+ SOERR("listen - disable accept");
+ }
+ }
+ GRN_API_RETURN(ctx->rc);
+}
+
+static void
+grn_com_receiver(grn_ctx *ctx, grn_com *com)
+{
+ grn_com_event *ev = com->ev;
+ ERRCLR(ctx);
+ if (ev->acceptor == com) {
+ grn_com *ncs;
+ grn_sock fd = accept(com->fd, NULL, NULL);
+ if (fd == -1) {
+ if (errno == EMFILE) {
+ grn_com_event_stop_accept(ctx, ev);
+ } else {
+ SOERR("accept");
+ }
+ return;
+ }
+ if (grn_com_event_add(ctx, ev, fd, GRN_COM_POLLIN, (grn_com **)&ncs)) {
+ grn_sock_close(fd);
+ return;
+ }
+ ncs->has_sid = 0;
+ ncs->closed = 0;
+ ncs->opaque = NULL;
+ GRN_COM_QUEUE_INIT(&ncs->new_);
+ // GRN_LOG(ctx, GRN_LOG_NOTICE, "accepted (%d)", fd);
+ return;
+ } else {
+ grn_msg *msg = (grn_msg *)grn_msg_open(ctx, com, &ev->recv_old);
+ grn_com_recv(ctx, msg->u.peer, &msg->header, (grn_obj *)msg);
+ if (msg->u.peer /* is_edge_request(msg)*/) {
+ grn_memcpy(&msg->edge_id, &ev->curr_edge_id, sizeof(grn_com_addr));
+ if (!com->has_sid) {
+ com->has_sid = 1;
+ com->sid = ev->curr_edge_id.sid++;
+ }
+ msg->edge_id.sid = com->sid;
+ }
+ msg->acceptor = ev->acceptor;
+ ev->msg_handler(ctx, (grn_obj *)msg);
+ }
+}
+
+grn_rc
+grn_com_event_poll(grn_ctx *ctx, grn_com_event *ev, int timeout)
+{
+ int nevents;
+ grn_com *com;
+#ifdef USE_SELECT
+ uint32_t dummy;
+ grn_sock *pfd;
+ int nfds = 0;
+ fd_set rfds;
+ fd_set wfds;
+ struct timeval tv;
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ }
+ FD_ZERO(&rfds);
+ FD_ZERO(&wfds);
+ ctx->errlvl = GRN_OK;
+ ctx->rc = GRN_SUCCESS;
+ {
+ grn_hash_cursor *cursor;
+ cursor = grn_hash_cursor_open(ctx, ev->hash, NULL, 0, NULL, 0, 0, -1, 0);
+ if (cursor) {
+ grn_id id;
+ while ((id = grn_hash_cursor_next(ctx, cursor))) {
+ grn_hash_cursor_get_key_value(ctx,
+ cursor,
+ (void **)(&pfd),
+ &dummy,
+ (void **)(&com));
+ if (com->events & GRN_COM_POLLIN) { FD_SET(*pfd, &rfds); }
+ if (com->events & GRN_COM_POLLOUT) { FD_SET(*pfd, &wfds); }
+# ifndef WIN32
+ if (*pfd > nfds) { nfds = *pfd; }
+# endif /* WIN32 */
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ }
+ nevents = select(nfds + 1, &rfds, &wfds, NULL, (timeout >= 0) ? &tv : NULL);
+ if (nevents < 0) {
+ SOERR("select");
+ if (ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) { ERRCLR(ctx); }
+ return ctx->rc;
+ }
+ if (timeout < 0 && !nevents) { GRN_LOG(ctx, GRN_LOG_NOTICE, "select returns 0 events"); }
+ GRN_HASH_EACH(ctx, ev->hash, eh, &pfd, &dummy, &com, {
+ if (FD_ISSET(*pfd, &rfds)) { grn_com_receiver(ctx, com); }
+ });
+#else /* USE_SELECT */
+# ifdef USE_EPOLL
+ struct epoll_event *ep;
+ ctx->errlvl = GRN_OK;
+ ctx->rc = GRN_SUCCESS;
+ nevents = epoll_wait(ev->epfd, ev->events, ev->max_nevents, timeout);
+ if (nevents < 0) {
+ SERR("epoll_wait");
+ }
+# else /* USE_EPOLL */
+# ifdef USE_KQUEUE
+ struct kevent *ep;
+ struct timespec tv;
+ if (timeout >= 0) {
+ tv.tv_sec = timeout / 1000;
+ tv.tv_nsec = (timeout % 1000) * 1000;
+ }
+ nevents = kevent(ev->kqfd, NULL, 0, ev->events, ev->max_nevents, &tv);
+ if (nevents < 0) {
+ SERR("kevent");
+ }
+# else /* USE_KQUEUE */
+ uint32_t dummy;
+ int nfd = 0, *pfd;
+ struct pollfd *ep = ev->events;
+ ctx->errlvl = GRN_OK;
+ ctx->rc = GRN_SUCCESS;
+ GRN_HASH_EACH(ctx, ev->hash, eh, &pfd, &dummy, &com, {
+ ep->fd = *pfd;
+ // ep->events =(short) com->events;
+ ep->events = POLLIN;
+ ep->revents = 0;
+ ep++;
+ nfd++;
+ });
+ nevents = poll(ev->events, nfd, timeout);
+ if (nevents < 0) {
+ SERR("poll");
+ }
+# endif /* USE_KQUEUE */
+# endif /* USE_EPOLL */
+ if (ctx->rc != GRN_SUCCESS) {
+ if (ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
+ ERRCLR(ctx);
+ }
+ return ctx->rc;
+ }
+ if (timeout < 0 && !nevents) { GRN_LOG(ctx, GRN_LOG_NOTICE, "poll returns 0 events"); }
+ for (ep = ev->events; nevents; ep++) {
+ int efd;
+# ifdef USE_EPOLL
+ efd = ep->data.fd;
+ nevents--;
+ // todo : com = ep->data.ptr;
+ if (!grn_hash_get(ctx, ev->hash, &efd, sizeof(grn_sock), (void *)&com)) {
+ struct epoll_event e;
+ GRN_LOG(ctx, GRN_LOG_ERROR, "fd(%d) not found in ev->hash", efd);
+ memset(&e, 0, sizeof(struct epoll_event));
+ e.data.fd = efd;
+ e.events = ep->events;
+ if (epoll_ctl(ev->epfd, EPOLL_CTL_DEL, efd, &e) == -1) { SERR("epoll_ctl"); }
+ if (grn_sock_close(efd) == -1) { SOERR("close"); }
+ continue;
+ }
+ if (ep->events & GRN_COM_POLLIN) { grn_com_receiver(ctx, com); }
+# else /* USE_EPOLL */
+# ifdef USE_KQUEUE
+ efd = ep->ident;
+ nevents--;
+ // todo : com = ep->udata;
+ if (!grn_hash_get(ctx, ev->hash, &efd, sizeof(grn_sock), (void *)&com)) {
+ struct kevent e;
+ GRN_LOG(ctx, GRN_LOG_ERROR, "fd(%d) not found in ev->set", efd);
+ EV_SET(&e, efd, ep->filter, EV_DELETE, 0, 0, NULL);
+ if (kevent(ev->kqfd, &e, 1, NULL, 0, NULL) == -1) { SERR("kevent"); }
+ if (grn_sock_close(efd) == -1) { SOERR("close"); }
+ continue;
+ }
+ if (ep->filter == GRN_COM_POLLIN) { grn_com_receiver(ctx, com); }
+# else
+ efd = ep->fd;
+ if (!(ep->events & ep->revents)) { continue; }
+ nevents--;
+ if (!grn_hash_get(ctx, ev->hash, &efd, sizeof(grn_sock), (void *)&com)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "fd(%d) not found in ev->hash", efd);
+ if (grn_sock_close(efd) == -1) { SOERR("close"); }
+ continue;
+ }
+ if (ep->revents & GRN_COM_POLLIN) { grn_com_receiver(ctx, com); }
+# endif /* USE_KQUEUE */
+# endif /* USE_EPOLL */
+ }
+#endif /* USE_SELECT */
+ /* todo :
+ while (!(msg = (grn_com_msg *)grn_com_queue_deque(&recv_old))) {
+ grn_msg_close(ctx, msg);
+ }
+ */
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_com_send_http(grn_ctx *ctx, grn_com *cs, const char *path, uint32_t path_len, int flags)
+{
+ ssize_t ret;
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUTS(ctx, &buf, "GET ");
+ grn_bulk_write(ctx, &buf, path, path_len);
+ GRN_TEXT_PUTS(ctx, &buf, " HTTP/1.0\r\n\r\n");
+ // todo : refine
+ if ((ret = send(cs->fd, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf), MSG_NOSIGNAL|flags)) == -1) {
+ SOERR("send");
+ }
+ if (ret != GRN_BULK_VSIZE(&buf)) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "send %d != %d", (int)ret, (int)GRN_BULK_VSIZE(&buf));
+ }
+ grn_obj_close(ctx, &buf);
+ return ctx->rc;
+}
+
+grn_rc
+grn_com_send(grn_ctx *ctx, grn_com *cs,
+ grn_com_header *header, const char *body, uint32_t size, int flags)
+{
+ grn_rc rc = GRN_SUCCESS;
+ size_t whole_size = sizeof(grn_com_header) + size;
+ ssize_t ret;
+ header->size = htonl(size);
+ GRN_LOG(ctx, GRN_LOG_INFO, "send (%d,%x,%d,%02x,%02x,%04x)", size, header->flags, header->proto, header->qtype, header->level, header->status);
+
+ if (size) {
+#ifdef WIN32
+ WSABUF wsabufs[2];
+ DWORD n_sent;
+ wsabufs[0].buf = (char *)header;
+ wsabufs[0].len = sizeof(grn_com_header);
+ wsabufs[1].buf = (char *)body;
+ wsabufs[1].len = size;
+ if (WSASend(cs->fd, wsabufs, 2, &n_sent, 0, NULL, NULL) == SOCKET_ERROR) {
+ SOERR("WSASend");
+ }
+ ret = n_sent;
+#else /* WIN32 */
+ struct iovec msg_iov[2];
+ struct msghdr msg;
+ memset(&msg, 0, sizeof(struct msghdr));
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = msg_iov;
+ msg.msg_iovlen = 2;
+ msg_iov[0].iov_base = (char*) header;
+ msg_iov[0].iov_len = sizeof(grn_com_header);
+ msg_iov[1].iov_base = (char *)body;
+ msg_iov[1].iov_len = size;
+ if ((ret = sendmsg(cs->fd, &msg, MSG_NOSIGNAL|flags)) == -1) {
+ SOERR("sendmsg");
+ rc = ctx->rc;
+ }
+#endif /* WIN32 */
+ } else {
+ if ((ret = send(cs->fd, (const void *)header, whole_size, MSG_NOSIGNAL|flags)) == -1) {
+ SOERR("send");
+ rc = ctx->rc;
+ }
+ }
+ if ((size_t) ret != whole_size) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "sendmsg(%" GRN_FMT_SOCKET "): %" GRN_FMT_LLD " < %" GRN_FMT_LLU,
+ cs->fd, (long long int)ret, (unsigned long long int)whole_size);
+ rc = ctx->rc;
+ }
+ return rc;
+}
+
+#define RETRY_MAX 10
+
+static const char *
+scan_delimiter(const char *p, const char *e)
+{
+ while (p + 4 <= e) {
+ if (p[3] == '\n') {
+ if (p[2] == '\r') {
+ if (p[1] == '\n') {
+ if (p[0] == '\r') { return p + 4; } else { p += 2; }
+ } else { p += 2; }
+ } else { p += 4; }
+ } else { p += p[3] == '\r' ? 1 : 4; }
+ }
+ return NULL;
+}
+
+#define BUFSIZE 4096
+
+static grn_rc
+grn_com_recv_text(grn_ctx *ctx, grn_com *com,
+ grn_com_header *header, grn_obj *buf, ssize_t ret)
+{
+ const char *p;
+ int retry = 0;
+ grn_bulk_write(ctx, buf, (char *)header, ret);
+ if ((p = scan_delimiter(GRN_BULK_HEAD(buf), GRN_BULK_CURR(buf)))) {
+ header->qtype = *GRN_BULK_HEAD(buf);
+ header->proto = GRN_COM_PROTO_HTTP;
+ header->size = GRN_BULK_VSIZE(buf);
+ goto exit;
+ }
+ for (;;) {
+ if (grn_bulk_reserve(ctx, buf, BUFSIZE)) { return ctx->rc; }
+ if ((ret = recv(com->fd, GRN_BULK_CURR(buf), BUFSIZE, 0)) < 0) {
+ SOERR("recv text");
+ if (ctx->rc == GRN_OPERATION_WOULD_BLOCK ||
+ ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
+ ERRCLR(ctx);
+ continue;
+ }
+ goto exit;
+ }
+ if (ret) {
+ off_t o = GRN_BULK_VSIZE(buf);
+ p = GRN_BULK_CURR(buf);
+ GRN_BULK_INCR_LEN(buf, ret);
+ if (scan_delimiter(p - (o > 3 ? 3 : o), p + ret)) {
+ break;
+ }
+ } else {
+ if (++retry > RETRY_MAX) {
+ // ERR(GRN_RETRY_MAX, "retry max in recv text");
+ goto exit;
+ }
+ }
+ }
+ header->qtype = *GRN_BULK_HEAD(buf);
+ header->proto = GRN_COM_PROTO_HTTP;
+ header->size = GRN_BULK_VSIZE(buf);
+exit :
+ if (header->qtype == 'H') {
+ //todo : refine
+ /*
+ GRN_BULK_REWIND(buf);
+ grn_bulk_reserve(ctx, buf, BUFSIZE);
+ if ((ret = recv(com->fd, GRN_BULK_CURR(buf), BUFSIZE, 0)) < 0) {
+ SOERR("recv text body");
+ } else {
+ GRN_BULK_CURR(buf) += ret;
+ }
+ */
+ }
+ return ctx->rc;
+}
+
+grn_rc
+grn_com_recv(grn_ctx *ctx, grn_com *com, grn_com_header *header, grn_obj *buf)
+{
+ ssize_t ret;
+ int retry = 0;
+ byte *p = (byte *)header;
+ size_t rest = sizeof(grn_com_header);
+ do {
+ if ((ret = recv(com->fd, p, rest, 0)) < 0) {
+ SOERR("recv size");
+ GRN_LOG(ctx, GRN_LOG_ERROR, "recv error (%" GRN_FMT_SOCKET ")", com->fd);
+ if (ctx->rc == GRN_OPERATION_WOULD_BLOCK ||
+ ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
+ ERRCLR(ctx);
+ continue;
+ }
+ goto exit;
+ }
+ if (ret) {
+ if (header->proto < 0x80) {
+ return grn_com_recv_text(ctx, com, header, buf, ret);
+ }
+ rest -= ret, p += ret;
+ } else {
+ if (++retry > RETRY_MAX) {
+ // ERR(GRN_RETRY_MAX, "retry max in recv header (%d)", com->fd);
+ goto exit;
+ }
+ }
+ } while (rest);
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "recv (%u,%x,%d,%02x,%02x,%04x)",
+ (uint32_t)ntohl(header->size),
+ header->flags,
+ header->proto,
+ header->qtype,
+ header->level,
+ header->status);
+ {
+ uint8_t proto = header->proto;
+ size_t value_size = ntohl(header->size);
+ GRN_BULK_REWIND(buf);
+ switch (proto) {
+ case GRN_COM_PROTO_GQTP :
+ case GRN_COM_PROTO_MBREQ :
+ if (GRN_BULK_WSIZE(buf) < value_size) {
+ if (grn_bulk_resize(ctx, buf, value_size)) {
+ goto exit;
+ }
+ }
+ retry = 0;
+ for (rest = value_size; rest;) {
+ if ((ret = recv(com->fd, GRN_BULK_CURR(buf), rest, MSG_WAITALL)) < 0) {
+ SOERR("recv body");
+ if (ctx->rc == GRN_OPERATION_WOULD_BLOCK ||
+ ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
+ ERRCLR(ctx);
+ continue;
+ }
+ goto exit;
+ }
+ if (ret) {
+ rest -= ret;
+ GRN_BULK_INCR_LEN(buf, ret);
+ } else {
+ if (++retry > RETRY_MAX) {
+ // ERR(GRN_RETRY_MAX, "retry max in recv body");
+ goto exit;
+ }
+ }
+ }
+ break;
+ default :
+ GRN_LOG(ctx, GRN_LOG_ERROR, "illegal header: %d", proto);
+ ctx->rc = GRN_INVALID_FORMAT;
+ goto exit;
+ }
+ }
+exit :
+ return ctx->rc;
+}
+
+grn_com *
+grn_com_copen(grn_ctx *ctx, grn_com_event *ev, const char *dest, int port)
+{
+ grn_sock fd = -1;
+ grn_com *cs = NULL;
+
+ struct addrinfo hints, *addrinfo_list, *addrinfo_ptr;
+ char port_string[16];
+ int getaddrinfo_result;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_NUMERICSERV
+ hints.ai_flags = AI_NUMERICSERV;
+#endif
+ grn_snprintf(port_string, sizeof(port_string), sizeof(port_string),
+ "%d", port);
+
+ getaddrinfo_result = getaddrinfo(dest, port_string, &hints, &addrinfo_list);
+ if (getaddrinfo_result != 0) {
+ switch (getaddrinfo_result) {
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ ERR(GRN_NO_MEMORY_AVAILABLE, "getaddrinfo: <%s:%s>: %s",
+ dest, port_string, gai_strerror(getaddrinfo_result));
+ break;
+#endif
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ SOERR("getaddrinfo");
+ break;
+#endif
+ default:
+ ERR(GRN_INVALID_ARGUMENT, "getaddrinfo: <%s:%s>: %s",
+ dest, port_string, gai_strerror(getaddrinfo_result));
+ break;
+ }
+ return NULL;
+ }
+
+ for (addrinfo_ptr = addrinfo_list; addrinfo_ptr;
+ addrinfo_ptr = addrinfo_ptr->ai_next) {
+ fd = socket(addrinfo_ptr->ai_family, addrinfo_ptr->ai_socktype,
+ addrinfo_ptr->ai_protocol);
+ if (fd == -1) {
+ SOERR("socket");
+ continue;
+ }
+#ifdef TCP_NODELAY
+ {
+ static const int value = 1;
+ if (setsockopt(fd, 6, TCP_NODELAY,
+ (const char *)&value, sizeof(value)) != 0) {
+ SOERR("setsockopt");
+ grn_sock_close(fd);
+ continue;
+ }
+ }
+#endif
+ if (connect(fd, addrinfo_ptr->ai_addr, addrinfo_ptr->ai_addrlen) != 0) {
+ SOERR("connect");
+ grn_sock_close(fd);
+ continue;
+ }
+
+ break;
+ }
+
+ freeaddrinfo(addrinfo_list);
+
+ if (!addrinfo_ptr) {
+ return NULL;
+ }
+ ctx->errlvl = GRN_OK;
+ ctx->rc = GRN_SUCCESS;
+
+ if (ev) {
+ grn_com_event_add(ctx, ev, fd, GRN_COM_POLLIN, &cs);
+ } else {
+ cs = GRN_CALLOC(sizeof(grn_com));
+ if (cs) {
+ cs->fd = fd;
+ }
+ }
+ if (!cs) {
+ grn_sock_close(fd);
+ }
+ return cs;
+}
+
+void
+grn_com_close_(grn_ctx *ctx, grn_com *com)
+{
+ grn_sock fd = com->fd;
+ if (shutdown(fd, SHUT_RDWR) == -1) { /* SOERR("shutdown"); */ }
+ if (grn_sock_close(fd) == -1) {
+ SOERR("close");
+ } else {
+ com->closed = 1;
+ }
+}
+
+grn_rc
+grn_com_close(grn_ctx *ctx, grn_com *com)
+{
+ grn_sock fd = com->fd;
+ grn_com_event *ev = com->ev;
+ if (ev) {
+ grn_com *acceptor = ev->acceptor;
+ grn_com_event_del(ctx, ev, fd);
+ if (acceptor) { grn_com_event_start_accept(ctx, ev); }
+ }
+ if (!com->closed) { grn_com_close_(ctx, com); }
+ if (!ev) { GRN_FREE(com); }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_com_sopen(grn_ctx *ctx, grn_com_event *ev,
+ const char *bind_address, int port, grn_msg_handler *func,
+ struct hostent *he)
+{
+ grn_sock lfd = -1;
+ grn_com *cs = NULL;
+ int getaddrinfo_result;
+ struct addrinfo *bind_address_info = NULL;
+ struct addrinfo hints;
+ char port_string[6]; /* ceil(log10(65535)) + 1 ('\0')*/
+
+ GRN_API_ENTER;
+ if (!bind_address) {
+ bind_address = "0.0.0.0";
+ }
+ grn_snprintf(port_string, sizeof(port_string), sizeof(port_string),
+ "%d", port);
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_NUMERICSERV
+ hints.ai_flags = AI_NUMERICSERV;
+#endif
+ getaddrinfo_result = getaddrinfo(bind_address, port_string,
+ &hints, &bind_address_info);
+ if (getaddrinfo_result != 0) {
+ switch (getaddrinfo_result) {
+#ifdef EAI_MEMORY
+ case EAI_MEMORY:
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "getaddrinfo: <%s:%s>: %s",
+ bind_address, port_string, gai_strerror(getaddrinfo_result));
+ break;
+#endif
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ SOERR("getaddrinfo");
+ break;
+#endif
+ default:
+ ERR(GRN_INVALID_ARGUMENT,
+ "getaddrinfo: <%s:%s>: %s",
+ bind_address, port_string, gai_strerror(getaddrinfo_result));
+ break;
+ }
+ goto exit;
+ }
+ if ((lfd = socket(bind_address_info->ai_family, SOCK_STREAM, 0)) == -1) {
+ SOERR("socket");
+ goto exit;
+ }
+ grn_memcpy(&ev->curr_edge_id.addr, he->h_addr, he->h_length);
+ ev->curr_edge_id.port = htons(port);
+ ev->curr_edge_id.sid = 0;
+ {
+ int v = 1;
+#ifdef TCP_NODELAY
+ if (setsockopt(lfd, SOL_TCP, TCP_NODELAY, (void *) &v, sizeof(int)) == -1) {
+ SOERR("setsockopt");
+ goto exit;
+ }
+#endif
+ if (setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (void *) &v, sizeof(int)) == -1) {
+ SOERR("setsockopt");
+ goto exit;
+ }
+ }
+ if (bind(lfd, bind_address_info->ai_addr, bind_address_info->ai_addrlen) < 0) {
+ SOERR("bind");
+ goto exit;
+ }
+ if (listen(lfd, LISTEN_BACKLOG) < 0) {
+ SOERR("listen");
+ goto exit;
+ }
+ if (ev) {
+ if (grn_com_event_add(ctx, ev, lfd, GRN_COM_POLLIN, &cs)) { goto exit; }
+ ev->acceptor = cs;
+ ev->msg_handler = func;
+ cs->has_sid = 0;
+ cs->closed = 0;
+ cs->opaque = NULL;
+ GRN_COM_QUEUE_INIT(&cs->new_);
+ } else {
+ if (!(cs = GRN_MALLOC(sizeof(grn_com)))) { goto exit; }
+ cs->fd = lfd;
+ }
+ cs->accepting = GRN_TRUE;
+exit :
+ if (!cs && lfd != 1) { grn_sock_close(lfd); }
+ if (bind_address_info) { freeaddrinfo(bind_address_info); }
+ GRN_API_RETURN(ctx->rc);
+}
+
+
+grn_hash *grn_edges = NULL;
+void (*grn_dispatcher)(grn_ctx *ctx, grn_edge *edge);
+
+void
+grn_edges_init(grn_ctx *ctx, void (*dispatcher)(grn_ctx *ctx, grn_edge *edge))
+{
+ grn_edges = grn_hash_create(ctx, NULL, sizeof(grn_com_addr), sizeof(grn_edge), 0);
+ grn_dispatcher = dispatcher;
+}
+
+void
+grn_edges_fin(grn_ctx *ctx)
+{
+ grn_hash_close(ctx, grn_edges);
+}
+
+grn_edge *
+grn_edges_add(grn_ctx *ctx, grn_com_addr *addr, int *added)
+{
+ if (grn_io_lock(ctx, grn_edges->io, grn_lock_timeout)) {
+ return NULL;
+ } else {
+ grn_edge *edge;
+ grn_id id = grn_hash_add(ctx, grn_edges, addr, sizeof(grn_com_addr),
+ (void **)&edge, added);
+ grn_io_unlock(grn_edges->io);
+ if (id) { edge->id = id; }
+ return edge;
+ }
+}
+
+void
+grn_edges_delete(grn_ctx *ctx, grn_edge *edge)
+{
+ if (!grn_io_lock(ctx, grn_edges->io, grn_lock_timeout)) {
+ grn_hash_delete_by_id(ctx, grn_edges, edge->id, NULL);
+ grn_io_unlock(grn_edges->io);
+ }
+}
+
+grn_edge *
+grn_edges_add_communicator(grn_ctx *ctx, grn_com_addr *addr)
+{
+ int added;
+ grn_edge *edge = grn_edges_add(ctx, addr, &added);
+ if (added) {
+ grn_ctx_init(&edge->ctx, 0);
+ GRN_COM_QUEUE_INIT(&edge->recv_new);
+ GRN_COM_QUEUE_INIT(&edge->send_old);
+ edge->com = NULL;
+ edge->stat = 0 /*EDGE_IDLE*/;
+ edge->flags = GRN_EDGE_COMMUNICATOR;
+ }
+ return edge;
+}
+
+void
+grn_edge_dispatch(grn_ctx *ctx, grn_edge *edge, grn_obj *msg)
+{
+ grn_com_queue_enque(ctx, &edge->recv_new, (grn_com_queue_entry *)msg);
+ grn_dispatcher(ctx, edge);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/command.c b/storage/mroonga/vendor/groonga/lib/command.c
new file mode 100644
index 00000000..3da5871b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/command.c
@@ -0,0 +1,201 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+
+#include "grn.h"
+#include "grn_db.h"
+#include "grn_ctx_impl.h"
+
+struct _grn_command_input {
+ grn_obj *command;
+ grn_hash *arguments;
+};
+
+grn_command_input *
+grn_command_input_open(grn_ctx *ctx, grn_obj *command)
+{
+ grn_command_input *input = NULL;
+
+ GRN_API_ENTER;
+ input = GRN_MALLOC(sizeof(grn_command_input));
+ if (!input) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[command-input] failed to allocate grn_command_input");
+ goto exit;
+ }
+
+ input->command = command;
+ /* TODO: Allocate by self. */
+ {
+ uint32_t n;
+ input->arguments = grn_expr_get_vars(ctx, input->command, &n);
+ }
+
+exit :
+ GRN_API_RETURN(input);
+}
+
+grn_rc
+grn_command_input_close(grn_ctx *ctx, grn_command_input *input)
+{
+ GRN_API_ENTER;
+
+ /* TODO: Free input->arguments by self. */
+ /* grn_expr_clear_vars(ctx, input->command); */
+ GRN_FREE(input);
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_obj *
+grn_command_input_add(grn_ctx *ctx,
+ grn_command_input *input,
+ const char *name,
+ int name_size,
+ grn_bool *added)
+{
+ grn_obj *argument = NULL;
+ /* TODO: Use grn_bool */
+ int internal_added = GRN_FALSE;
+
+ GRN_API_ENTER;
+
+ if (name_size == -1) {
+ name_size = strlen(name);
+ }
+ if (input->arguments) {
+ grn_hash_add(ctx, input->arguments, name, name_size, (void **)&argument,
+ &internal_added);
+ if (internal_added) {
+ GRN_TEXT_INIT(argument, 0);
+ }
+ }
+ if (added) {
+ *added = internal_added;
+ }
+
+ GRN_API_RETURN(argument);
+}
+
+grn_obj *
+grn_command_input_get(grn_ctx *ctx,
+ grn_command_input *input,
+ const char *name,
+ int name_size)
+{
+ grn_obj *argument = NULL;
+
+ GRN_API_ENTER;
+
+ if (name_size == -1) {
+ name_size = strlen(name);
+ }
+ if (input->arguments) {
+ grn_hash_get(ctx, input->arguments, name, name_size, (void **)&argument);
+ }
+
+ GRN_API_RETURN(argument);
+}
+
+grn_obj *
+grn_command_input_at(grn_ctx *ctx,
+ grn_command_input *input,
+ unsigned int offset)
+{
+ grn_obj *argument = NULL;
+
+ GRN_API_ENTER;
+ if (input->arguments) {
+ argument = (grn_obj *)grn_hash_get_value_(ctx, input->arguments,
+ offset + 1, NULL);
+ }
+ GRN_API_RETURN(argument);
+}
+
+grn_obj *
+grn_command_input_get_arguments(grn_ctx *ctx,
+ grn_command_input *input)
+{
+ GRN_API_ENTER;
+ GRN_API_RETURN((grn_obj *)(input->arguments));
+}
+
+grn_rc
+grn_command_register(grn_ctx *ctx,
+ const char *command_name,
+ int command_name_size,
+ grn_command_run_func *run,
+ grn_expr_var *vars,
+ unsigned int n_vars,
+ void *user_data)
+{
+ GRN_API_ENTER;
+
+ if (command_name_size == -1) {
+ command_name_size = strlen(command_name);
+ }
+
+ {
+ grn_obj *command_object;
+ command_object = grn_proc_create(ctx,
+ command_name,
+ command_name_size,
+ GRN_PROC_COMMAND,
+ NULL, NULL, NULL, n_vars, vars);
+ if (!command_object) {
+ GRN_PLUGIN_ERROR(ctx, GRN_COMMAND_ERROR,
+ "[command][%.*s] failed to grn_proc_create()",
+ command_name_size, command_name);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ {
+ grn_proc *command = (grn_proc *)command_object;
+ command->callbacks.command.run = run;
+ command->user_data = user_data;
+ }
+ }
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_rc
+grn_command_run(grn_ctx *ctx,
+ grn_obj *command,
+ grn_command_input *input)
+{
+ grn_proc *proc;
+
+ GRN_API_ENTER;
+
+ proc = (grn_proc *)command;
+ if (proc->callbacks.command.run) {
+ proc->callbacks.command.run(ctx, command, input, proc->user_data);
+ } else {
+ /* TODO: REMOVE ME. For backward compatibility. */
+ uint32_t stack_curr = ctx->impl->stack_curr;
+ grn_proc_call(ctx, command, 0, command);
+ if (ctx->impl->stack_curr > stack_curr) {
+ grn_ctx_pop(ctx);
+ }
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
diff --git a/storage/mroonga/vendor/groonga/lib/config.c b/storage/mroonga/vendor/groonga/lib/config.c
new file mode 100644
index 00000000..6664e127
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/config.c
@@ -0,0 +1,289 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx_impl.h"
+#include "grn_config.h"
+
+#include <string.h>
+
+grn_rc
+grn_config_set(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char *value, int32_t value_size)
+{
+ grn_obj *db;
+ grn_hash *config;
+ void *packed_value;
+ grn_id id;
+
+ GRN_API_ENTER;
+
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "[config][set] DB isn't initialized");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (key_size == -1) {
+ key_size = strlen(key);
+ }
+ if (key_size > GRN_CONFIG_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[config][set] too large key: max=<%d>: <%d>",
+ GRN_CONFIG_MAX_KEY_SIZE, key_size);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (value_size == -1) {
+ value_size = strlen(value);
+ }
+ if (value_size > (int32_t) GRN_CONFIG_MAX_VALUE_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[config][set] too large value: max=<%" GRN_FMT_SIZE ">: <%d>",
+ GRN_CONFIG_MAX_VALUE_SIZE, value_size);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ config = ((grn_db *)db)->config;
+ {
+ grn_rc rc;
+ rc = grn_io_lock(ctx, config->io, grn_lock_timeout);
+ if (rc != GRN_SUCCESS) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(rc, "[config][set] failed to lock");
+ }
+ GRN_API_RETURN(rc);
+ }
+ id = grn_hash_add(ctx, config, key, key_size, &packed_value, NULL);
+ grn_io_unlock(config->io);
+ }
+ if (id == GRN_ID_NIL && ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[config][set] failed to set: name=<%.*s>: <%d>",
+ key_size, key, value_size);
+ }
+
+ *((uint32_t *)packed_value) = (uint32_t)value_size;
+ grn_memcpy((char *)packed_value + sizeof(uint32_t),
+ value, value_size);
+ ((char *)packed_value)[sizeof(uint32_t) + value_size] = '\0';
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_config_get(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char **value, uint32_t *value_size)
+{
+ grn_obj *db;
+ grn_hash *config;
+ grn_id id;
+ void *packed_value;
+
+ GRN_API_ENTER;
+
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "[config][get] DB isn't initialized");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (key_size == -1) {
+ key_size = strlen(key);
+ }
+ if (key_size > GRN_CONFIG_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[config][get] too large key: max=<%d>: <%d>",
+ GRN_CONFIG_MAX_KEY_SIZE, key_size);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ config = ((grn_db *)db)->config;
+ id = grn_hash_get(ctx, config, key, key_size, &packed_value);
+ if (id == GRN_ID_NIL) {
+ *value = NULL;
+ *value_size = 0;
+ GRN_API_RETURN(GRN_SUCCESS);
+ }
+
+ *value = (char *)packed_value + sizeof(uint32_t);
+ *value_size = *((uint32_t *)packed_value);
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_rc
+grn_config_delete(grn_ctx *ctx,
+ const char *key, int key_size)
+{
+ grn_obj *db;
+ grn_hash *config;
+
+ GRN_API_ENTER;
+
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "[config][delete] DB isn't initialized");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (key_size == -1) {
+ key_size = strlen(key);
+ }
+ if (key_size > GRN_CONFIG_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[config][delete] too large key: max=<%d>: <%d>",
+ GRN_CONFIG_MAX_KEY_SIZE, key_size);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ config = ((grn_db *)db)->config;
+ {
+ grn_rc rc;
+ rc = grn_io_lock(ctx, config->io, grn_lock_timeout);
+ if (rc != GRN_SUCCESS) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(rc, "[config][delete] failed to lock");
+ }
+ GRN_API_RETURN(rc);
+ }
+ rc = grn_hash_delete(ctx, config, key, key_size, NULL);
+ grn_io_unlock(config->io);
+ if (rc != GRN_SUCCESS) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(rc, "[config][delete] failed to delete");
+ }
+ }
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_obj *
+grn_config_cursor_open(grn_ctx *ctx)
+{
+ grn_obj *db;
+ grn_hash *config;
+ grn_config_cursor *cursor;
+ grn_id id;
+
+ GRN_API_ENTER;
+
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "[config][cursor][open] DB isn't initialized");
+ GRN_API_RETURN(NULL);
+ }
+ config = ((grn_db *)db)->config;
+
+ cursor = GRN_MALLOCN(grn_config_cursor, 1);
+ if (!cursor) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[config][cursor][open] failed to allocate memory for config cursor");
+ GRN_API_RETURN(NULL);
+ }
+
+ GRN_DB_OBJ_SET_TYPE(cursor, GRN_CURSOR_CONFIG);
+ cursor->hash_cursor = grn_hash_cursor_open(ctx, config,
+ NULL, -1,
+ NULL, -1,
+ 0, -1, 0);
+ if (!cursor->hash_cursor) {
+ GRN_FREE(cursor);
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[config][cursor][open] failed to allocate memory for hash cursor");
+ GRN_API_RETURN(NULL);
+ }
+
+ id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
+ DB_OBJ(cursor)->header.domain = GRN_ID_NIL;
+ DB_OBJ(cursor)->range = GRN_ID_NIL;
+ grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(cursor));
+
+ GRN_API_RETURN((grn_obj *)cursor);
+}
+
+grn_rc
+grn_config_cursor_close(grn_ctx *ctx, grn_config_cursor *cursor)
+{
+ grn_hash_cursor_close(ctx, cursor->hash_cursor);
+ GRN_FREE(cursor);
+
+ return GRN_SUCCESS;
+}
+
+grn_bool
+grn_config_cursor_next(grn_ctx *ctx, grn_obj *cursor)
+{
+ grn_bool have_next;
+ grn_config_cursor *config_cursor = (grn_config_cursor *)cursor;
+
+ GRN_API_ENTER;
+
+ have_next = grn_hash_cursor_next(ctx, config_cursor->hash_cursor) != GRN_ID_NIL;
+
+ GRN_API_RETURN(have_next);
+}
+
+uint32_t
+grn_config_cursor_get_key(grn_ctx *ctx, grn_obj *cursor, const char **key)
+{
+ void *key_raw;
+ uint32_t key_size;
+ grn_config_cursor *config_cursor = (grn_config_cursor *)cursor;
+
+ GRN_API_ENTER;
+
+ key_size = grn_hash_cursor_get_key(ctx, config_cursor->hash_cursor, &key_raw);
+ *key = key_raw;
+
+ GRN_API_RETURN(key_size);
+}
+
+uint32_t
+grn_config_cursor_get_value(grn_ctx *ctx, grn_obj *cursor, const char **value)
+{
+ void *value_raw;
+ uint32_t value_size;
+ uint32_t value_size_raw;
+ grn_config_cursor *config_cursor = (grn_config_cursor *)cursor;
+
+ GRN_API_ENTER;
+
+ value_size_raw = grn_hash_cursor_get_value(ctx,
+ config_cursor->hash_cursor,
+ &value_raw);
+ *value = (char *)value_raw + sizeof(uint32_t);
+ value_size = *((uint32_t *)value_raw);
+
+ GRN_API_RETURN(value_size);
+}
+
+/* Deprecated since 5.1.2. Use grn_config_* instead. */
+grn_rc
+grn_conf_set(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char *value, int32_t value_size)
+{
+ return grn_config_set(ctx, key, key_size, value, value_size);
+}
+
+grn_rc
+grn_conf_get(grn_ctx *ctx,
+ const char *key, int32_t key_size,
+ const char **value, uint32_t *value_size)
+{
+ return grn_config_get(ctx, key, key_size, value, value_size);
+}
+
diff --git a/storage/mroonga/vendor/groonga/lib/cpp_sources.am b/storage/mroonga/vendor/groonga/lib/cpp_sources.am
new file mode 100644
index 00000000..c1d09a97
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/cpp_sources.am
@@ -0,0 +1,3 @@
+libgroonga_cpp_source = \
+ arrow.cpp \
+ dat.cpp
diff --git a/storage/mroonga/vendor/groonga/lib/ctx.c b/storage/mroonga/vendor/groonga/lib/ctx.c
new file mode 100644
index 00000000..1fd912d4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ctx.c
@@ -0,0 +1,1873 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include <string.h>
+#include "grn_request_canceler.h"
+#include "grn_request_timer.h"
+#include "grn_tokenizers.h"
+#include "grn_ctx_impl.h"
+#include "grn_ii.h"
+#include "grn_pat.h"
+#include "grn_index_column.h"
+#include "grn_proc.h"
+#include "grn_plugin.h"
+#include "grn_snip.h"
+#include "grn_output.h"
+#include "grn_normalizer.h"
+#include "grn_mrb.h"
+#include "grn_ctx_impl_mrb.h"
+#include "grn_logger.h"
+#include "grn_cache.h"
+#include "grn_expr.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+
+#ifdef GRN_WITH_ONIGMO
+# define GRN_SUPPORT_REGEXP
+#endif /* GRN_WITH_ONIGMO */
+
+#ifdef GRN_SUPPORT_REGEXP
+# include <onigmo.h>
+#endif /* GRN_SUPPORT_REGEXP */
+
+#ifdef WIN32
+# include <share.h>
+#else /* WIN32 */
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#define GRN_CTX_INITIALIZER(enc) \
+ { GRN_SUCCESS, 0, enc, 0, GRN_LOG_NOTICE,\
+ GRN_CTX_FIN, 0, 0, 0, 0, {0}, NULL, NULL, NULL, NULL, NULL, \
+ {NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL,NULL, NULL}, ""}
+
+#define GRN_CTX_CLOSED(ctx) ((ctx)->stat == GRN_CTX_FIN)
+
+grn_ctx grn_gctx = GRN_CTX_INITIALIZER(GRN_ENC_DEFAULT);
+int grn_pagesize;
+grn_critical_section grn_glock;
+uint32_t grn_gtick;
+int grn_lock_timeout = GRN_LOCK_TIMEOUT;
+
+#ifdef USE_UYIELD
+int grn_uyield_count = 0;
+#endif
+
+static grn_bool grn_ctx_per_db = GRN_FALSE;
+
+static void
+grn_init_from_env(void)
+{
+ {
+ char grn_ctx_per_db_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_CTX_PER_DB",
+ grn_ctx_per_db_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ctx_per_db_env[0] && strcmp(grn_ctx_per_db_env, "yes") == 0) {
+ grn_ctx_per_db = GRN_TRUE;
+ }
+ }
+
+ grn_alloc_init_from_env();
+ grn_mrb_init_from_env();
+ grn_ctx_impl_mrb_init_from_env();
+ grn_io_init_from_env();
+ grn_ii_init_from_env();
+ grn_db_init_from_env();
+ grn_expr_init_from_env();
+ grn_index_column_init_from_env();
+ grn_proc_init_from_env();
+ grn_plugin_init_from_env();
+}
+
+static void
+grn_init_external_libraries(void)
+{
+#ifdef GRN_SUPPORT_REGEXP
+ onig_init();
+#endif /* GRN_SUPPORT_REGEXP */
+}
+
+static void
+grn_fin_external_libraries(void)
+{
+#ifdef GRN_SUPPORT_REGEXP
+ onig_end();
+#endif /* GRN_SUPPORT_REGEXP */
+}
+
+void
+grn_sleep(uint32_t seconds)
+{
+#ifdef WIN32
+ Sleep(seconds * 1000);
+#else // WIN32
+ sleep(seconds);
+#endif // WIN32
+}
+
+void
+grn_nanosleep(uint64_t nanoseconds)
+{
+#ifdef WIN32
+ Sleep((DWORD)(nanoseconds / 1000000));
+#else // WIN32
+ struct timespec interval;
+ interval.tv_sec = (time_t)(nanoseconds / 1000000000);
+ interval.tv_nsec = (long)(nanoseconds % 1000000000);
+ nanosleep(&interval, NULL);
+#endif // WIN32
+}
+
+const char *
+grn_get_global_error_message(void)
+{
+ return grn_gctx.errbuf;
+}
+
+static void
+grn_loader_init(grn_loader *loader)
+{
+ GRN_TEXT_INIT(&loader->values, 0);
+ GRN_UINT32_INIT(&loader->level, GRN_OBJ_VECTOR);
+ GRN_PTR_INIT(&loader->columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_UINT32_INIT(&loader->ids, GRN_OBJ_VECTOR);
+ GRN_INT32_INIT(&loader->return_codes, GRN_OBJ_VECTOR);
+ GRN_TEXT_INIT(&loader->error_messages, GRN_OBJ_VECTOR);
+ loader->id_offset = -1;
+ loader->key_offset = -1;
+ loader->table = NULL;
+ loader->last = NULL;
+ loader->ifexists = NULL;
+ loader->each = NULL;
+ loader->values_size = 0;
+ loader->nrecords = 0;
+ loader->stat = GRN_LOADER_BEGIN;
+ loader->columns_status = GRN_LOADER_COLUMNS_UNSET;
+ loader->rc = GRN_SUCCESS;
+ loader->errbuf[0] = '\0';
+ loader->output_ids = GRN_FALSE;
+ loader->output_errors = GRN_FALSE;
+}
+
+void
+grn_ctx_loader_clear(grn_ctx *ctx)
+{
+ grn_loader *loader = &ctx->impl->loader;
+ grn_obj *v = (grn_obj *)(GRN_BULK_HEAD(&loader->values));
+ grn_obj *ve = (grn_obj *)(GRN_BULK_CURR(&loader->values));
+ grn_obj **p = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
+ uint32_t i = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
+ if (ctx->impl->db) { while (i--) { grn_obj_unlink(ctx, *p++); } }
+ if (loader->ifexists) { grn_obj_unlink(ctx, loader->ifexists); }
+ if (loader->each) { grn_obj_unlink(ctx, loader->each); }
+ while (v < ve) { GRN_OBJ_FIN(ctx, v++); }
+ GRN_OBJ_FIN(ctx, &loader->values);
+ GRN_OBJ_FIN(ctx, &loader->level);
+ GRN_OBJ_FIN(ctx, &loader->columns);
+ GRN_OBJ_FIN(ctx, &loader->ids);
+ GRN_OBJ_FIN(ctx, &loader->return_codes);
+ GRN_OBJ_FIN(ctx, &loader->error_messages);
+ grn_loader_init(loader);
+}
+
+#define IMPL_SIZE ((sizeof(struct _grn_ctx_impl) + (grn_pagesize - 1)) & ~(grn_pagesize - 1))
+
+#ifdef GRN_WITH_MESSAGE_PACK
+static int
+grn_msgpack_buffer_write(void *data, const char *buf, msgpack_size_t len)
+{
+ grn_ctx *ctx = (grn_ctx *)data;
+ return grn_bulk_write(ctx, ctx->impl->output.buf, buf, len);
+}
+#endif
+
+static grn_rc
+grn_ctx_impl_init(grn_ctx *ctx)
+{
+ grn_io_mapinfo mi;
+ if (!(ctx->impl = grn_io_anon_map(ctx, &mi, IMPL_SIZE))) {
+ return ctx->rc;
+ }
+ grn_alloc_init_ctx_impl(ctx);
+ ctx->impl->encoding = ctx->encoding;
+ ctx->impl->lifoseg = -1;
+ ctx->impl->currseg = -1;
+ CRITICAL_SECTION_INIT(ctx->impl->lock);
+ if (!(ctx->impl->values = grn_array_create(ctx, NULL, sizeof(grn_db_obj *),
+ GRN_ARRAY_TINY))) {
+ CRITICAL_SECTION_FIN(ctx->impl->lock);
+ grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
+ ctx->impl = NULL;
+ return ctx->rc;
+ }
+ if (!(ctx->impl->temporary_columns = grn_pat_create(ctx, NULL,
+ GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_obj *),
+ 0))) {
+ grn_array_close(ctx, ctx->impl->values);
+ CRITICAL_SECTION_FIN(ctx->impl->lock);
+ grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
+ ctx->impl = NULL;
+ return ctx->rc;
+ }
+ if (!(ctx->impl->ios = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_io *),
+ GRN_OBJ_KEY_VAR_SIZE|GRN_HASH_TINY))) {
+ grn_array_close(ctx, ctx->impl->values);
+ grn_pat_close(ctx, ctx->impl->temporary_columns);
+ CRITICAL_SECTION_FIN(ctx->impl->lock);
+ grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
+ ctx->impl = NULL;
+ return ctx->rc;
+ }
+ ctx->impl->db = NULL;
+
+ ctx->impl->expr_vars = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_obj *), 0);
+ ctx->impl->stack_curr = 0;
+ ctx->impl->curr_expr = NULL;
+ GRN_TEXT_INIT(&ctx->impl->current_request_id, 0);
+ ctx->impl->current_request_timer_id = NULL;
+ ctx->impl->parser = NULL;
+
+ GRN_TEXT_INIT(&ctx->impl->output.names, GRN_OBJ_VECTOR);
+ GRN_UINT32_INIT(&ctx->impl->output.levels, GRN_OBJ_VECTOR);
+
+ ctx->impl->command.flags = 0;
+ if (ctx == &grn_gctx) {
+ ctx->impl->command.version = GRN_COMMAND_VERSION_STABLE;
+ } else {
+ ctx->impl->command.version = grn_get_default_command_version();
+ }
+ ctx->impl->command.keep.command = NULL;
+ ctx->impl->command.keep.version = ctx->impl->command.version;
+
+ if (ctx == &grn_gctx) {
+ ctx->impl->match_escalation_threshold =
+ GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD;
+ } else {
+ ctx->impl->match_escalation_threshold =
+ grn_get_default_match_escalation_threshold();
+ }
+
+ ctx->impl->finalizer = NULL;
+
+ ctx->impl->com = NULL;
+ ctx->impl->output.buf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT);
+ ctx->impl->output.func = NULL;
+ ctx->impl->output.data.ptr = NULL;
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_packer_init(&ctx->impl->output.msgpacker,
+ ctx, grn_msgpack_buffer_write);
+#endif
+ ctx->impl->tv.tv_sec = 0;
+ ctx->impl->tv.tv_nsec = 0;
+ ctx->impl->edge = NULL;
+ grn_loader_init(&ctx->impl->loader);
+ ctx->impl->plugin_path = NULL;
+
+ GRN_TEXT_INIT(&ctx->impl->query_log_buf, 0);
+
+ ctx->impl->previous_errbuf[0] = '\0';
+ ctx->impl->n_same_error_messages = 0;
+
+ grn_ctx_impl_mrb_init(ctx);
+
+ GRN_TEXT_INIT(&(ctx->impl->temporary_open_spaces.stack), 0);
+ ctx->impl->temporary_open_spaces.current = NULL;
+
+ return ctx->rc;
+}
+
+void
+grn_ctx_set_keep_command(grn_ctx *ctx, grn_obj *command)
+{
+ ctx->impl->command.keep.command = command;
+ ctx->impl->command.keep.version = ctx->impl->command.version;
+}
+
+static void
+grn_ctx_impl_clear_n_same_error_messagges(grn_ctx *ctx)
+{
+ if (ctx->impl->n_same_error_messages == 0) {
+ return;
+ }
+
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "(%u same messages are truncated)",
+ ctx->impl->n_same_error_messages);
+ ctx->impl->n_same_error_messages = 0;
+}
+
+grn_bool
+grn_ctx_impl_should_log(grn_ctx *ctx)
+{
+ if (!ctx->impl) {
+ return GRN_TRUE;
+ }
+
+ if (strcmp(ctx->errbuf, ctx->impl->previous_errbuf) == 0) {
+ ctx->impl->n_same_error_messages++;
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+void
+grn_ctx_impl_set_current_error_message(grn_ctx *ctx)
+{
+ if (!ctx->impl) {
+ return;
+ }
+
+ grn_ctx_impl_clear_n_same_error_messagges(ctx);
+ grn_strcpy(ctx->impl->previous_errbuf, GRN_CTX_MSGSIZE, ctx->errbuf);
+}
+
+static grn_rc
+grn_ctx_init_internal(grn_ctx *ctx, int flags)
+{
+ if (!ctx) { return GRN_INVALID_ARGUMENT; }
+ // if (ctx->stat != GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
+ ctx->rc = GRN_SUCCESS;
+ ERRCLR(ctx);
+ ctx->flags = flags;
+ if (grn_ctx_per_db) {
+ ctx->flags |= GRN_CTX_PER_DB;
+ }
+ ctx->stat = GRN_CTX_INITED;
+ ctx->encoding = grn_gctx.encoding;
+ ctx->seqno = 0;
+ ctx->seqno2 = 0;
+ ctx->subno = 0;
+ ctx->impl = NULL;
+ ctx->user_data.ptr = NULL;
+ CRITICAL_SECTION_ENTER(grn_glock);
+ ctx->next = grn_gctx.next;
+ ctx->prev = &grn_gctx;
+ grn_gctx.next->prev = ctx;
+ grn_gctx.next = ctx;
+ CRITICAL_SECTION_LEAVE(grn_glock);
+ ctx->errline = 0;
+ ctx->errfile = "";
+ ctx->errfunc = "";
+ ctx->trace[0] = NULL;
+ ctx->errbuf[0] = '\0';
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ctx_init(grn_ctx *ctx, int flags)
+{
+ grn_rc rc;
+
+ rc = grn_ctx_init_internal(ctx, flags);
+ if (rc == GRN_SUCCESS) {
+ grn_ctx_impl_init(ctx);
+ rc = ctx->rc;
+ if (rc != GRN_SUCCESS) {
+ grn_ctx_fin(ctx);
+ if (flags & GRN_CTX_ALLOCATED) {
+ CRITICAL_SECTION_ENTER(grn_glock);
+ ctx->next->prev = ctx->prev;
+ ctx->prev->next = ctx->next;
+ CRITICAL_SECTION_LEAVE(grn_glock);
+ }
+ }
+ }
+
+ return rc;
+}
+
+grn_ctx *
+grn_ctx_open(int flags)
+{
+ grn_ctx *ctx = GRN_GMALLOCN(grn_ctx, 1);
+ if (ctx) {
+ grn_ctx_init(ctx, flags|GRN_CTX_ALLOCATED);
+ if (ERRP(ctx, GRN_ERROR)) {
+ GRN_GFREE(ctx);
+ ctx = NULL;
+ }
+ }
+ return ctx;
+}
+
+grn_rc
+grn_ctx_fin(grn_ctx *ctx)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (!ctx) { return GRN_INVALID_ARGUMENT; }
+ if (ctx->stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
+ if (!(ctx->flags & GRN_CTX_ALLOCATED)) {
+ CRITICAL_SECTION_ENTER(grn_glock);
+ ctx->next->prev = ctx->prev;
+ ctx->prev->next = ctx->next;
+ CRITICAL_SECTION_LEAVE(grn_glock);
+ }
+ if (ctx->impl) {
+ grn_ctx_impl_clear_n_same_error_messagges(ctx);
+ if (ctx->impl->finalizer) {
+ ctx->impl->finalizer(ctx, 0, NULL, &(ctx->user_data));
+ }
+ {
+ grn_obj *stack;
+ grn_obj *spaces;
+ unsigned int i, n_spaces;
+
+ stack = &(ctx->impl->temporary_open_spaces.stack);
+ spaces = (grn_obj *)GRN_BULK_HEAD(stack);
+ n_spaces = GRN_BULK_VSIZE(stack) / sizeof(grn_obj);
+ for (i = 0; i < n_spaces; i++) {
+ grn_obj *space = spaces + (n_spaces - i - 1);
+ GRN_OBJ_FIN(ctx, space);
+ }
+ GRN_OBJ_FIN(ctx, stack);
+ }
+ grn_ctx_impl_mrb_fin(ctx);
+ grn_ctx_loader_clear(ctx);
+ if (ctx->impl->parser) {
+ grn_expr_parser_close(ctx);
+ }
+ GRN_OBJ_FIN(ctx, &ctx->impl->current_request_id);
+ if (ctx->impl->values) {
+#ifndef USE_MEMORY_DEBUG
+ grn_db_obj *o;
+ GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
+ grn_obj_close(ctx, *((grn_obj **)o));
+ });
+#endif
+ grn_array_close(ctx, ctx->impl->values);
+ }
+ if (ctx->impl->temporary_columns) {
+#ifndef USE_MEMORY_DEBUG
+ grn_obj *value;
+ GRN_PAT_EACH(ctx, ctx->impl->temporary_columns, id, NULL, NULL, &value, {
+ grn_obj_close(ctx, *((grn_obj **)value));
+ });
+#endif
+ grn_pat_close(ctx, ctx->impl->temporary_columns);
+ }
+ if (ctx->impl->ios) {
+ grn_hash_close(ctx, ctx->impl->ios);
+ }
+ if (ctx->impl->com) {
+ if (ctx->stat != GRN_CTX_QUIT) {
+ int flags;
+ char *str;
+ unsigned int str_len;
+ grn_ctx_send(ctx, "quit", 4, GRN_CTX_HEAD);
+ grn_ctx_recv(ctx, &str, &str_len, &flags);
+ }
+ grn_ctx_send(ctx, "ACK", 3, GRN_CTX_HEAD);
+ rc = grn_com_close(ctx, ctx->impl->com);
+ }
+ GRN_OBJ_FIN(ctx, &ctx->impl->query_log_buf);
+ GRN_OBJ_FIN(ctx, &ctx->impl->output.names);
+ GRN_OBJ_FIN(ctx, &ctx->impl->output.levels);
+ rc = grn_obj_close(ctx, ctx->impl->output.buf);
+ {
+ grn_hash **vp;
+ grn_obj *value;
+ GRN_HASH_EACH(ctx, ctx->impl->expr_vars, eid, NULL, NULL, &vp, {
+ if (*vp) {
+ GRN_HASH_EACH(ctx, *vp, id, NULL, NULL, &value, {
+ GRN_OBJ_FIN(ctx, value);
+ });
+ }
+ grn_hash_close(ctx, *vp);
+ });
+ }
+ grn_hash_close(ctx, ctx->impl->expr_vars);
+ if (ctx->impl->db && ctx->flags & GRN_CTX_PER_DB) {
+ grn_obj *db = ctx->impl->db;
+ ctx->impl->db = NULL;
+ grn_obj_close(ctx, db);
+ }
+ grn_alloc_fin_ctx_impl(ctx);
+ grn_alloc_info_dump(ctx);
+ grn_alloc_info_free(ctx);
+ CRITICAL_SECTION_FIN(ctx->impl->lock);
+ {
+ grn_io_mapinfo mi;
+ mi.map = (void *)ctx->impl;
+ grn_io_anon_unmap(ctx, &mi, IMPL_SIZE);
+ }
+ ctx->impl = NULL;
+ }
+ ctx->stat = GRN_CTX_FIN;
+ return rc;
+}
+
+grn_rc
+grn_ctx_set_finalizer(grn_ctx *ctx, grn_proc_func *finalizer)
+{
+ if (!ctx) { return GRN_INVALID_ARGUMENT; }
+ if (!ctx->impl) {
+ if (ERRP(ctx, GRN_ERROR)) { return ctx->rc; }
+ }
+ ctx->impl->finalizer = finalizer;
+ return GRN_SUCCESS;
+}
+
+grn_timeval grn_starttime;
+
+static void
+check_overcommit_memory(grn_ctx *ctx)
+{
+ FILE *file;
+ int value;
+ file = grn_fopen("/proc/sys/vm/overcommit_memory", "r");
+ if (!file) { return; }
+ value = fgetc(file);
+ if (value != '1') {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "vm.overcommit_memory kernel parameter should be 1: <%c>: "
+ "See INFO level log to resolve this",
+ value);
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "Some processings with vm.overcommit_memory != 1 "
+ "may break DB under low memory condition.");
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "To set vm.overcommit_memory to 1");
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and "
+ "restart your system or");
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "run 'sudo /sbin/sysctl vm.overcommit_memory=1' command.");
+ }
+ fclose(file);
+}
+
+grn_rc
+grn_init(void)
+{
+ grn_rc rc;
+ grn_ctx *ctx = &grn_gctx;
+ grn_init_from_env();
+ grn_init_external_libraries();
+ grn_alloc_info_init();
+ grn_logger_init();
+ grn_query_logger_init();
+ CRITICAL_SECTION_INIT(grn_glock);
+ grn_gtick = 0;
+ ctx->next = ctx;
+ ctx->prev = ctx;
+ rc = grn_ctx_init_internal(ctx, 0);
+ if (rc) {
+ goto fail_ctx_init_internal;
+ }
+ ctx->encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING);
+ rc = grn_timeval_now(ctx, &grn_starttime);
+ if (rc) {
+ goto fail_start_time;
+ }
+#ifdef WIN32
+ {
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ grn_pagesize = si.dwAllocationGranularity;
+ }
+#else /* WIN32 */
+ if ((grn_pagesize = sysconf(_SC_PAGESIZE)) == -1) {
+ SERR("_SC_PAGESIZE");
+ rc = ctx->rc;
+ goto fail_page_size;
+ }
+#endif /* WIN32 */
+ if (grn_pagesize & (grn_pagesize - 1)) {
+ GRN_LOG(ctx, GRN_LOG_CRIT, "pagesize=%x", grn_pagesize);
+ }
+ // expand_stack();
+ if ((rc = grn_com_init())) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_com_init failed (%d)", rc);
+ goto fail_com;
+ }
+ if ((rc = grn_ctx_impl_init(ctx))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_ctx_impl_init failed (%d)", rc);
+ goto fail_ctx_impl;
+ }
+ if ((rc = grn_plugins_init())) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_plugins_init failed (%d)", rc);
+ goto fail_plugins;
+ }
+ if ((rc = grn_normalizer_init())) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_normalizer_init failed (%d)", rc);
+ goto fail_normalizer;
+ }
+ if ((rc = grn_tokenizers_init())) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_tokenizers_init failed (%d)", rc);
+ goto fail_tokenizer;
+ }
+ grn_cache_init();
+ if (!grn_request_canceler_init()) {
+ rc = ctx->rc;
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "failed to initialize request canceler (%d)", rc);
+ goto fail_request_canceler;
+ }
+ if (!grn_request_timer_init()) {
+ rc = ctx->rc;
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "failed to initialize request timer (%d)", rc);
+ goto fail_request_timer;
+ }
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init: <%s>", grn_get_version());
+ check_overcommit_memory(ctx);
+ return rc;
+
+fail_request_timer:
+ grn_request_canceler_fin();
+fail_request_canceler:
+ grn_cache_fin();
+fail_tokenizer:
+ grn_normalizer_fin();
+fail_normalizer:
+ grn_plugins_fin();
+fail_plugins:
+ grn_ctx_fin(ctx);
+fail_ctx_impl:
+ grn_com_fin();
+fail_com:
+#ifndef WIN32
+fail_page_size:
+#endif /* WIN32 */
+fail_start_time:
+fail_ctx_init_internal:
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_init: <%s>: failed", grn_get_version());
+ grn_query_logger_fin(ctx);
+ grn_logger_fin(ctx);
+ CRITICAL_SECTION_FIN(grn_glock);
+ grn_alloc_info_fin();
+ grn_fin_external_libraries();
+ return rc;
+}
+
+grn_encoding
+grn_get_default_encoding(void)
+{
+ return grn_gctx.encoding;
+}
+
+grn_rc
+grn_set_default_encoding(grn_encoding encoding)
+{
+ switch (encoding) {
+ case GRN_ENC_DEFAULT :
+ grn_gctx.encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING);
+ return GRN_SUCCESS;
+ case GRN_ENC_NONE :
+ case GRN_ENC_EUC_JP :
+ case GRN_ENC_UTF8 :
+ case GRN_ENC_SJIS :
+ case GRN_ENC_LATIN1 :
+ case GRN_ENC_KOI8R :
+ grn_gctx.encoding = encoding;
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+}
+
+grn_command_version
+grn_get_default_command_version(void)
+{
+ return grn_ctx_get_command_version(&grn_gctx);
+}
+
+grn_rc
+grn_set_default_command_version(grn_command_version version)
+{
+ return grn_ctx_set_command_version(&grn_gctx, version);
+}
+
+long long int
+grn_get_default_match_escalation_threshold(void)
+{
+ return grn_ctx_get_match_escalation_threshold(&grn_gctx);
+}
+
+grn_rc
+grn_set_default_match_escalation_threshold(long long int threshold)
+{
+ return grn_ctx_set_match_escalation_threshold(&grn_gctx, threshold);
+}
+
+int
+grn_get_lock_timeout(void)
+{
+ return grn_lock_timeout;
+}
+
+grn_rc
+grn_set_lock_timeout(int timeout)
+{
+ grn_lock_timeout = timeout;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_fin(void)
+{
+ grn_ctx *ctx, *ctx_;
+ if (grn_gctx.stat == GRN_CTX_FIN) { return GRN_INVALID_ARGUMENT; }
+ for (ctx = grn_gctx.next; ctx != &grn_gctx; ctx = ctx_) {
+ ctx_ = ctx->next;
+ if (ctx->stat != GRN_CTX_FIN) { grn_ctx_fin(ctx); }
+ if (ctx->flags & GRN_CTX_ALLOCATED) {
+ ctx->next->prev = ctx->prev;
+ ctx->prev->next = ctx->next;
+ GRN_GFREE(ctx);
+ }
+ }
+ grn_query_logger_fin(ctx);
+ grn_request_timer_fin();
+ grn_request_canceler_fin();
+ grn_cache_fin();
+ grn_tokenizers_fin();
+ grn_normalizer_fin();
+ grn_plugins_fin();
+ grn_ctx_fin(ctx);
+ grn_com_fin();
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "grn_fin (%d)", grn_alloc_count());
+ grn_logger_fin(ctx);
+ CRITICAL_SECTION_FIN(grn_glock);
+ grn_alloc_info_fin();
+ grn_fin_external_libraries();
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ctx_connect(grn_ctx *ctx, const char *host, int port, int flags)
+{
+ GRN_API_ENTER;
+ if (!ctx->impl) { goto exit; }
+ {
+ grn_com *com = grn_com_copen(ctx, NULL, host, port);
+ if (com) {
+ ctx->impl->com = com;
+ }
+ }
+exit :
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_ctx_close(grn_ctx *ctx)
+{
+ grn_rc rc = grn_ctx_fin(ctx);
+ CRITICAL_SECTION_ENTER(grn_glock);
+ ctx->next->prev = ctx->prev;
+ ctx->prev->next = ctx->next;
+ CRITICAL_SECTION_LEAVE(grn_glock);
+ GRN_GFREE(ctx);
+ return rc;
+}
+
+grn_command_version
+grn_ctx_get_command_version(grn_ctx *ctx)
+{
+ if (ctx->impl) {
+ return ctx->impl->command.version;
+ } else {
+ return GRN_COMMAND_VERSION_STABLE;
+ }
+}
+
+grn_rc
+grn_ctx_set_command_version(grn_ctx *ctx, grn_command_version version)
+{
+ switch (version) {
+ case GRN_COMMAND_VERSION_DEFAULT :
+ ctx->impl->command.version = GRN_COMMAND_VERSION_STABLE;
+ return GRN_SUCCESS;
+ default :
+ if (GRN_COMMAND_VERSION_MIN <= version &&
+ version <= GRN_COMMAND_VERSION_MAX) {
+ ctx->impl->command.version = version;
+ return GRN_SUCCESS;
+ } else {
+ return GRN_UNSUPPORTED_COMMAND_VERSION;
+ }
+ }
+}
+
+grn_content_type
+grn_ctx_get_output_type(grn_ctx *ctx)
+{
+ if (ctx->impl) {
+ return ctx->impl->output.type;
+ } else {
+ return GRN_CONTENT_NONE;
+ }
+}
+
+grn_rc
+grn_ctx_set_output_type(grn_ctx *ctx, grn_content_type type)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ if (ctx->impl) {
+ ctx->impl->output.type = type;
+ switch (ctx->impl->output.type) {
+ case GRN_CONTENT_NONE :
+ ctx->impl->output.mime_type = "application/octet-stream";
+ break;
+ case GRN_CONTENT_TSV :
+ ctx->impl->output.mime_type = "text/tab-separated-values";
+ break;
+ case GRN_CONTENT_JSON :
+ ctx->impl->output.mime_type = "application/json";
+ break;
+ case GRN_CONTENT_XML :
+ ctx->impl->output.mime_type = "text/xml";
+ break;
+ case GRN_CONTENT_MSGPACK :
+ ctx->impl->output.mime_type = "application/x-msgpack";
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ ctx->impl->output.mime_type = "text/x-groonga-command-list";
+ break;
+ }
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+
+ return rc;
+}
+
+const char *
+grn_ctx_get_mime_type(grn_ctx *ctx)
+{
+ if (ctx->impl) {
+ return ctx->impl->output.mime_type;
+ } else {
+ return NULL;
+ }
+}
+
+long long int
+grn_ctx_get_match_escalation_threshold(grn_ctx *ctx)
+{
+ if (ctx->impl) {
+ return ctx->impl->match_escalation_threshold;
+ } else {
+ return GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD;
+ }
+}
+
+grn_rc
+grn_ctx_set_match_escalation_threshold(grn_ctx *ctx, long long int threshold)
+{
+ ctx->impl->match_escalation_threshold = threshold;
+ return GRN_SUCCESS;
+}
+
+grn_content_type
+grn_get_ctype(grn_obj *var)
+{
+ return grn_content_type_parse(NULL, var, GRN_CONTENT_JSON);
+}
+
+grn_content_type
+grn_content_type_parse(grn_ctx *ctx,
+ grn_obj *var,
+ grn_content_type default_value)
+{
+ grn_content_type ct = default_value;
+ if (var->header.domain == GRN_DB_INT32) {
+ ct = GRN_INT32_VALUE(var);
+ } else if (GRN_TEXT_LEN(var)) {
+ switch (*(GRN_TEXT_VALUE(var))) {
+ case 't' :
+ case 'T' :
+ ct = GRN_CONTENT_TSV;
+ break;
+ case 'j' :
+ case 'J' :
+ ct = GRN_CONTENT_JSON;
+ break;
+ case 'x' :
+ case 'X' :
+ ct = GRN_CONTENT_XML;
+ break;
+ }
+ }
+ return ct;
+}
+
+static void
+get_content_mime_type(grn_ctx *ctx, const char *p, const char *pe)
+{
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "application/octet-stream";
+
+ if (p + 2 <= pe) {
+ switch (*p) {
+ case 'c' :
+ if (p + 3 == pe && !memcmp(p, "css", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "text/css";
+ }
+ break;
+ case 'g' :
+ if (p + 3 == pe && !memcmp(p, "gif", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "image/gif";
+ }
+ break;
+ case 'h' :
+ if (p + 4 == pe && !memcmp(p, "html", 4)) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "text/html";
+ }
+ break;
+ case 'j' :
+ if (!memcmp(p, "js", 2)) {
+ if (p + 2 == pe) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "text/javascript";
+ } else if (p + 4 == pe && !memcmp(p + 2, "on", 2)) {
+ ctx->impl->output.type = GRN_CONTENT_JSON;
+ ctx->impl->output.mime_type = "application/json";
+ }
+ } else if (p + 3 == pe && !memcmp(p, "jpg", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "image/jpeg";
+ }
+ break;
+#ifdef GRN_WITH_MESSAGE_PACK
+ case 'm' :
+ if (p + 7 == pe && !memcmp(p, "msgpack", 7)) {
+ ctx->impl->output.type = GRN_CONTENT_MSGPACK;
+ ctx->impl->output.mime_type = "application/x-msgpack";
+ }
+ break;
+#endif
+ case 'p' :
+ if (p + 3 == pe && !memcmp(p, "png", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "image/png";
+ }
+ break;
+ case 't' :
+ if (p + 3 == pe && !memcmp(p, "txt", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_NONE;
+ ctx->impl->output.mime_type = "text/plain";
+ } else if (p + 3 == pe && !memcmp(p, "tsv", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_TSV;
+ ctx->impl->output.mime_type = "text/tab-separated-values";
+ }
+ break;
+ case 'x':
+ if (p + 3 == pe && !memcmp(p, "xml", 3)) {
+ ctx->impl->output.type = GRN_CONTENT_XML;
+ ctx->impl->output.mime_type = "text/xml";
+ }
+ break;
+ }
+ }
+}
+
+static void
+grn_str_get_mime_type(grn_ctx *ctx, const char *p, const char *pe,
+ const char **key_end, const char **filename_end)
+{
+ const char *pd = NULL;
+ for (; p < pe && *p != '?' && *p != '#'; p++) {
+ if (*p == '.') { pd = p; }
+ }
+ *filename_end = p;
+ if (pd && pd < p) {
+ get_content_mime_type(ctx, pd + 1, p);
+ *key_end = pd;
+ } else {
+ *key_end = pe;
+ }
+}
+
+static void
+get_command_version(grn_ctx *ctx, const char *p, const char *pe)
+{
+ grn_command_version version;
+ const char *rest;
+
+ version = grn_atoui(p, pe, &rest);
+ if (pe == rest) {
+ grn_rc rc;
+ rc = grn_ctx_set_command_version(ctx, version);
+ if (rc == GRN_UNSUPPORTED_COMMAND_VERSION) {
+ ERR(rc,
+ "unsupported command version is specified: %d: "
+ "stable command version: %d: "
+ "available command versions: %d-%d",
+ version,
+ GRN_COMMAND_VERSION_STABLE,
+ GRN_COMMAND_VERSION_MIN, GRN_COMMAND_VERSION_MAX);
+ }
+ }
+}
+
+#define INDEX_HTML "index.html"
+#define OUTPUT_TYPE "output_type"
+#define COMMAND_VERSION "command_version"
+#define REQUEST_ID "request_id"
+#define REQUEST_TIMEOUT "request_timeout"
+#define OUTPUT_PRETTY "output_pretty"
+#define EXPR_MISSING "expr_missing"
+#define OUTPUT_TYPE_LEN (sizeof(OUTPUT_TYPE) - 1)
+#define COMMAND_VERSION_LEN (sizeof(COMMAND_VERSION) - 1)
+#define REQUEST_ID_LEN (sizeof(REQUEST_ID) - 1)
+#define REQUEST_TIMEOUT_LEN (sizeof(REQUEST_TIMEOUT) - 1)
+#define OUTPUT_PRETTY_LEN (sizeof(OUTPUT_PRETTY) - 1)
+
+#define HTTP_QUERY_PAIR_DELIMITER "="
+#define HTTP_QUERY_PAIRS_DELIMITERS "&;"
+
+static inline int
+command_proc_p(grn_obj *expr)
+{
+ return (expr->header.type == GRN_PROC &&
+ ((grn_proc *)expr)->type == GRN_PROC_COMMAND);
+}
+
+grn_obj *
+grn_ctx_qe_exec_uri(grn_ctx *ctx, const char *path, uint32_t path_len)
+{
+ grn_obj buf, *expr, *val;
+ grn_obj request_id;
+ double request_timeout;
+ const char *p = path, *e = path + path_len, *v, *key_end, *filename_end;
+
+ request_timeout = grn_get_default_request_timeout();
+
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_INIT(&request_id, 0);
+ p = grn_text_urldec(ctx, &buf, p, e, '?');
+ if (!GRN_TEXT_LEN(&buf)) { GRN_TEXT_SETS(ctx, &buf, INDEX_HTML); }
+ v = GRN_TEXT_VALUE(&buf);
+ grn_str_get_mime_type(ctx, v, GRN_BULK_CURR(&buf), &key_end, &filename_end);
+ if ((GRN_TEXT_LEN(&buf) >= 2 && v[0] == 'd' && v[1] == '/')) {
+ const char *command_name = v + 2;
+ int command_name_size = key_end - command_name;
+ expr = grn_ctx_get(ctx, command_name, command_name_size);
+ if (expr && command_proc_p(expr)) {
+ while (p < e) {
+ int l;
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIR_DELIMITER);
+ v = GRN_TEXT_VALUE(&buf);
+ l = GRN_TEXT_LEN(&buf);
+ if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
+ v = GRN_TEXT_VALUE(&buf);
+ get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf));
+ } else if (l == COMMAND_VERSION_LEN &&
+ !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
+ get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf));
+ if (ctx->rc) { goto exit; }
+ } else if (l == REQUEST_ID_LEN &&
+ !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) {
+ GRN_BULK_REWIND(&request_id);
+ p = grn_text_cgidec(ctx, &request_id, p, e,
+ HTTP_QUERY_PAIRS_DELIMITERS);
+ } else if (l == REQUEST_TIMEOUT_LEN &&
+ !memcmp(v, REQUEST_TIMEOUT, REQUEST_TIMEOUT_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ request_timeout = strtod(GRN_TEXT_VALUE(&buf), NULL);
+ } else if (l == OUTPUT_PRETTY_LEN &&
+ !memcmp(v, OUTPUT_PRETTY, OUTPUT_PRETTY_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_cgidec(ctx, &buf, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
+ if (GRN_TEXT_LEN(&buf) == strlen("yes") &&
+ !memcmp(GRN_TEXT_VALUE(&buf), "yes", GRN_TEXT_LEN(&buf))) {
+ ctx->impl->output.is_pretty = GRN_TRUE;
+ } else {
+ ctx->impl->output.is_pretty = GRN_FALSE;
+ }
+ } else {
+ if (!(val = grn_expr_get_or_add_var(ctx, expr, v, l))) {
+ val = &buf;
+ }
+ grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
+ p = grn_text_cgidec(ctx, val, p, e, HTTP_QUERY_PAIRS_DELIMITERS);
+ }
+ }
+ if (request_timeout > 0 && GRN_TEXT_LEN(&request_id) == 0) {
+ grn_text_printf(ctx, &request_id, "%p", ctx);
+ }
+ if (GRN_TEXT_LEN(&request_id) > 0) {
+ GRN_TEXT_SET(ctx, &ctx->impl->current_request_id,
+ GRN_TEXT_VALUE(&request_id),
+ GRN_TEXT_LEN(&request_id));
+ grn_request_canceler_register(ctx,
+ GRN_TEXT_VALUE(&request_id),
+ GRN_TEXT_LEN(&request_id));
+ if (request_timeout > 0.0) {
+ ctx->impl->current_request_timer_id =
+ grn_request_timer_register(GRN_TEXT_VALUE(&request_id),
+ GRN_TEXT_LEN(&request_id),
+ request_timeout);
+ }
+ }
+ ctx->impl->curr_expr = expr;
+ grn_expr_exec(ctx, expr, 0);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s",
+ command_name_size, command_name);
+ }
+ } else if ((expr = grn_ctx_get(ctx, GRN_EXPR_MISSING_NAME,
+ strlen(GRN_EXPR_MISSING_NAME)))) {
+ if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) {
+ grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
+ GRN_TEXT_SET(ctx, val, v, filename_end - v);
+ }
+ ctx->impl->curr_expr = expr;
+ grn_expr_exec(ctx, expr, 0);
+ }
+exit :
+ GRN_OBJ_FIN(ctx, &request_id);
+ GRN_OBJ_FIN(ctx, &buf);
+
+ return expr;
+}
+
+grn_obj *
+grn_ctx_qe_exec(grn_ctx *ctx, const char *str, uint32_t str_len)
+{
+ char tok_type;
+ int offset = 0;
+ grn_obj buf, *expr = NULL, *val = NULL;
+ grn_obj request_id;
+ double request_timeout;
+ const char *p = str, *e = str + str_len, *v;
+
+ request_timeout = grn_get_default_request_timeout();
+
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_INIT(&request_id, 0);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ while (p < e) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ v = GRN_TEXT_VALUE(&buf);
+ switch (tok_type) {
+ case GRN_TOK_VOID :
+ p = e;
+ break;
+ case GRN_TOK_SYMBOL :
+ if (GRN_TEXT_LEN(&buf) > 2 && v[0] == '-' && v[1] == '-') {
+ int l = GRN_TEXT_LEN(&buf) - 2;
+ v += 2;
+ if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ v = GRN_TEXT_VALUE(&buf);
+ get_content_mime_type(ctx, v, GRN_BULK_CURR(&buf));
+ } else if (l == COMMAND_VERSION_LEN &&
+ !memcmp(v, COMMAND_VERSION, COMMAND_VERSION_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ get_command_version(ctx, GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf));
+ if (ctx->rc) { goto exit; }
+ } else if (l == REQUEST_ID_LEN &&
+ !memcmp(v, REQUEST_ID, REQUEST_ID_LEN)) {
+ GRN_BULK_REWIND(&request_id);
+ p = grn_text_unesc_tok(ctx, &request_id, p, e, &tok_type);
+ } else if (l == REQUEST_TIMEOUT_LEN &&
+ !memcmp(v, REQUEST_TIMEOUT, REQUEST_TIMEOUT_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ request_timeout = strtod(GRN_TEXT_VALUE(&buf), NULL);
+ } else if (l == OUTPUT_PRETTY_LEN &&
+ !memcmp(v, OUTPUT_PRETTY, OUTPUT_PRETTY_LEN)) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ if (GRN_TEXT_LEN(&buf) == strlen("yes") &&
+ !memcmp(GRN_TEXT_VALUE(&buf), "yes", GRN_TEXT_LEN(&buf))) {
+ ctx->impl->output.is_pretty = GRN_TRUE;
+ } else {
+ ctx->impl->output.is_pretty = GRN_FALSE;
+ }
+ } else if (expr && (val = grn_expr_get_or_add_var(ctx, expr, v, l))) {
+ grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
+ p = grn_text_unesc_tok(ctx, val, p, e, &tok_type);
+ } else {
+ p = e;
+ }
+ break;
+ }
+ // fallthru
+ case GRN_TOK_STRING :
+ case GRN_TOK_QUOTE :
+ if (expr && (val = grn_expr_get_var_by_offset(ctx, expr, offset++))) {
+ grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
+ GRN_TEXT_PUT(ctx, val, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ } else {
+ p = e;
+ }
+ break;
+ }
+ }
+ if (request_timeout > 0 && GRN_TEXT_LEN(&request_id) == 0) {
+ grn_text_printf(ctx, &request_id, "%p", ctx);
+ }
+ if (GRN_TEXT_LEN(&request_id) > 0) {
+ GRN_TEXT_SET(ctx, &ctx->impl->current_request_id,
+ GRN_TEXT_VALUE(&request_id),
+ GRN_TEXT_LEN(&request_id));
+ grn_request_canceler_register(ctx,
+ GRN_TEXT_VALUE(&request_id),
+ GRN_TEXT_LEN(&request_id));
+ if (request_timeout > 0.0) {
+ ctx->impl->current_request_timer_id =
+ grn_request_timer_register(GRN_TEXT_VALUE(&request_id),
+ GRN_TEXT_LEN(&request_id),
+ request_timeout);
+ }
+ }
+ ctx->impl->curr_expr = expr;
+ if (expr && command_proc_p(expr)) {
+ grn_expr_exec(ctx, expr, 0);
+ } else {
+ GRN_BULK_REWIND(&buf);
+ grn_text_unesc_tok(ctx, &buf, str, str + str_len, &tok_type);
+ if (GRN_TEXT_LEN(&buf)) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid command name: %.*s",
+ (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
+ }
+ }
+exit :
+ GRN_OBJ_FIN(ctx, &request_id);
+ GRN_OBJ_FIN(ctx, &buf);
+
+ return expr;
+}
+
+grn_rc
+grn_ctx_sendv(grn_ctx *ctx, int argc, char **argv, int flags)
+{
+ grn_obj buf;
+ GRN_API_ENTER;
+ GRN_TEXT_INIT(&buf, 0);
+ while (argc--) {
+ // todo : encode into json like syntax
+ GRN_TEXT_PUTS(ctx, &buf, *argv);
+ argv++;
+ if (argc) { GRN_TEXT_PUTC(ctx, &buf, ' '); }
+ }
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), flags);
+ GRN_OBJ_FIN(ctx, &buf);
+ GRN_API_RETURN(ctx->rc);
+}
+
+static int
+comment_command_p(const char *command, unsigned int length)
+{
+ const char *p, *e;
+
+ e = command + length;
+ for (p = command; p < e; p++) {
+ switch (*p) {
+ case '#' :
+ return GRN_TRUE;
+ case ' ' :
+ case '\t' :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+ }
+ return GRN_FALSE;
+}
+
+unsigned int
+grn_ctx_send(grn_ctx *ctx, const char *str, unsigned int str_len, int flags)
+{
+ if (!ctx) { return 0; }
+ GRN_API_ENTER;
+ if (ctx->impl) {
+ if ((flags & GRN_CTX_MORE)) { flags |= GRN_CTX_QUIET; }
+ if (ctx->stat == GRN_CTX_QUIT) { flags |= GRN_CTX_QUIT; }
+
+ ctx->impl->command.flags = flags;
+ if (ctx->impl->com) {
+ grn_rc rc;
+ grn_com_header sheader;
+ grn_timeval_now(ctx, &ctx->impl->tv);
+ sheader.proto = GRN_COM_PROTO_GQTP;
+ sheader.qtype = 0;
+ sheader.keylen = 0;
+ sheader.level = 0;
+ sheader.flags = flags;
+ sheader.status = 0;
+ sheader.opaque = 0;
+ sheader.cas = 0;
+ if ((rc = grn_com_send(ctx, ctx->impl->com, &sheader, (char *)str, str_len, 0))) {
+ ERR(rc, "grn_com_send failed");
+ }
+ goto exit;
+ } else {
+ grn_command_version command_version;
+ grn_obj *expr = NULL;
+
+ command_version = grn_ctx_get_command_version(ctx);
+ if (ctx->impl->command.keep.command) {
+ grn_obj *val;
+ expr = ctx->impl->command.keep.command;
+ ctx->impl->command.keep.command = NULL;
+ grn_ctx_set_command_version(ctx, ctx->impl->command.keep.version);
+ if ((val = grn_expr_get_var_by_offset(ctx, expr, 0))) {
+ grn_obj_reinit(ctx, val, GRN_DB_TEXT, 0);
+ GRN_TEXT_PUT(ctx, val, str, str_len);
+ }
+ grn_expr_exec(ctx, expr, 0);
+ } else {
+ if (comment_command_p(str, str_len)) { goto output; };
+ GRN_BULK_REWIND(ctx->impl->output.buf);
+ ctx->impl->output.type = GRN_CONTENT_JSON;
+ ctx->impl->output.mime_type = "application/json";
+ ctx->impl->output.is_pretty = GRN_FALSE;
+ grn_timeval_now(ctx, &ctx->impl->tv);
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_COMMAND,
+ ">", "%.*s", str_len, str);
+ if (str_len && *str == '/') {
+ expr = grn_ctx_qe_exec_uri(ctx, str + 1, str_len - 1);
+ } else {
+ expr = grn_ctx_qe_exec(ctx, str, str_len);
+ }
+ }
+ if (ctx->stat == GRN_CTX_QUITTING) { ctx->stat = GRN_CTX_QUIT; }
+ if (ctx->impl->command.keep.command) {
+ ERRCLR(ctx);
+ } else {
+ if (ctx->impl->current_request_timer_id) {
+ void *timer_id = ctx->impl->current_request_timer_id;
+ ctx->impl->current_request_timer_id = NULL;
+ grn_request_timer_unregister(timer_id);
+ }
+ if (GRN_TEXT_LEN(&ctx->impl->current_request_id) > 0) {
+ grn_obj *request_id = &ctx->impl->current_request_id;
+ grn_request_canceler_unregister(ctx,
+ GRN_TEXT_VALUE(request_id),
+ GRN_TEXT_LEN(request_id));
+ GRN_BULK_REWIND(&ctx->impl->current_request_id);
+ }
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_RESULT_CODE,
+ "<", "rc=%d", ctx->rc);
+ }
+ output :
+ if (!(ctx->impl->command.flags & GRN_CTX_QUIET) &&
+ ctx->impl->output.func) {
+ ctx->impl->output.func(ctx, GRN_CTX_TAIL, ctx->impl->output.data.ptr);
+ }
+ if (expr) { grn_expr_clear_vars(ctx, expr); }
+ grn_ctx_set_command_version(ctx, command_version);
+ goto exit;
+ }
+ }
+ ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned");
+exit :
+ GRN_API_RETURN(0);
+}
+
+unsigned int
+grn_ctx_recv(grn_ctx *ctx, char **str, unsigned int *str_len, int *flags)
+{
+ if (!ctx) { return GRN_INVALID_ARGUMENT; }
+
+ *flags = 0;
+
+ if (ctx->stat == GRN_CTX_QUIT) {
+ grn_bool have_buffer = GRN_FALSE;
+
+ if (ctx->impl &&
+ !ctx->impl->com &&
+ GRN_TEXT_LEN(ctx->impl->output.buf) > 0) {
+ have_buffer = GRN_TRUE;
+ }
+
+ *flags |= GRN_CTX_QUIT;
+ if (!have_buffer) {
+ *str = NULL;
+ *str_len = 0;
+ return 0;
+ }
+ }
+
+ GRN_API_ENTER;
+ if (ctx->impl) {
+ if (ctx->impl->com) {
+ grn_com_header header;
+ if (grn_com_recv(ctx, ctx->impl->com, &header, ctx->impl->output.buf)) {
+ *str = NULL;
+ *str_len = 0;
+ *flags = 0;
+ } else {
+ *str = GRN_BULK_HEAD(ctx->impl->output.buf);
+ *str_len = GRN_BULK_VSIZE(ctx->impl->output.buf);
+ if (header.flags & GRN_CTX_QUIT) {
+ ctx->stat = GRN_CTX_QUIT;
+ *flags |= GRN_CTX_QUIT;
+ } else {
+ if (!(header.flags & GRN_CTX_TAIL)) {
+ *flags |= GRN_CTX_MORE;
+ }
+ }
+ ctx->impl->output.type = header.qtype;
+ ctx->rc = (int16_t)ntohs(header.status);
+ ctx->errbuf[0] = '\0';
+ ctx->errline = 0;
+ ctx->errfile = NULL;
+ ctx->errfunc = NULL;
+ }
+ goto exit;
+ } else {
+ grn_obj *buf = ctx->impl->output.buf;
+ unsigned int head = 0, tail = GRN_BULK_VSIZE(buf);
+ *str = GRN_BULK_HEAD(buf) + head;
+ *str_len = tail - head;
+ GRN_BULK_REWIND(ctx->impl->output.buf);
+ goto exit;
+ }
+ }
+ ERR(GRN_INVALID_ARGUMENT, "invalid ctx assigned");
+exit :
+ GRN_API_RETURN(0);
+}
+
+void
+grn_ctx_stream_out_func(grn_ctx *ctx, int flags, void *stream)
+{
+ if (ctx && ctx->impl) {
+ grn_obj *buf = ctx->impl->output.buf;
+ uint32_t size = GRN_BULK_VSIZE(buf);
+ if (size) {
+ if (fwrite(GRN_BULK_HEAD(buf), 1, size, (FILE *)stream)) {
+ fputc('\n', (FILE *)stream);
+ fflush((FILE *)stream);
+ }
+ GRN_BULK_REWIND(buf);
+ }
+ }
+}
+
+void
+grn_ctx_recv_handler_set(grn_ctx *ctx, void (*func)(grn_ctx *, int, void *), void *func_arg)
+{
+ if (ctx && ctx->impl) {
+ ctx->impl->output.func = func;
+ ctx->impl->output.data.ptr = func_arg;
+ }
+}
+
+grn_rc
+grn_ctx_info_get(grn_ctx *ctx, grn_ctx_info *info)
+{
+ if (!ctx || !ctx->impl) { return GRN_INVALID_ARGUMENT; }
+ if (ctx->impl->com) {
+ info->fd = ctx->impl->com->fd;
+ info->com_status = ctx->impl->com_status;
+ info->outbuf = ctx->impl->output.buf;
+ info->stat = ctx->stat;
+ } else {
+ info->fd = -1;
+ info->com_status = 0;
+ info->outbuf = ctx->impl->output.buf;
+ info->stat = ctx->stat;
+ }
+ return GRN_SUCCESS;
+}
+
+#define DB_P(s) ((s) && (s)->header.type == GRN_DB)
+
+grn_rc
+grn_ctx_use(grn_ctx *ctx, grn_obj *db)
+{
+ GRN_API_ENTER;
+ if (db && !DB_P(db)) {
+ ctx->rc = GRN_INVALID_ARGUMENT;
+ } else {
+ if (!ctx->rc) {
+ ctx->impl->db = db;
+ if (db) {
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ grn_obj_get_info(ctx, db, GRN_INFO_ENCODING, &buf);
+ ctx->encoding = *(grn_encoding *)GRN_BULK_HEAD(&buf);
+ grn_obj_close(ctx, &buf);
+ }
+ }
+ }
+ GRN_API_RETURN(ctx->rc);
+}
+
+/* don't handle error inside logger functions */
+
+void
+grn_ctx_log(grn_ctx *ctx, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ grn_ctx_logv(ctx, fmt, ap);
+ va_end(ap);
+}
+
+void
+grn_ctx_logv(grn_ctx *ctx, const char *fmt, va_list ap)
+{
+ char buffer[GRN_CTX_MSGSIZE];
+ grn_vsnprintf(buffer, GRN_CTX_MSGSIZE, fmt, ap);
+ grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, buffer);
+}
+
+void
+grn_assert(grn_ctx *ctx, int cond, const char* file, int line, const char* func)
+{
+ if (!cond) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "ASSERT fail on %s %s:%d", func, file, line);
+ }
+}
+
+const char *
+grn_get_version(void)
+{
+ return GRN_VERSION;
+}
+
+const char *
+grn_get_package(void)
+{
+ return PACKAGE;
+}
+
+const char *
+grn_get_package_label(void)
+{
+ return PACKAGE_LABEL;
+}
+
+#if defined(HAVE_SIGNAL_H) && !defined(WIN32)
+static int segv_received = 0;
+static void
+segv_handler(int signal_number, siginfo_t *info, void *context)
+{
+ grn_ctx *ctx = &grn_gctx;
+
+ if (segv_received) {
+ GRN_LOG(ctx, GRN_LOG_CRIT, "SEGV received in SEGV handler.");
+ exit(EXIT_FAILURE);
+ }
+ segv_received = 1;
+
+ GRN_LOG(ctx, GRN_LOG_CRIT, "-- CRASHED!!! --");
+#ifdef HAVE_BACKTRACE
+# define N_TRACE_LEVEL 1024
+ {
+ static void *trace[N_TRACE_LEVEL];
+ int n = backtrace(trace, N_TRACE_LEVEL);
+ char **symbols = backtrace_symbols(trace, n);
+ int i;
+
+ if (symbols) {
+ for (i = 0; i < n; i++) {
+ GRN_LOG(ctx, GRN_LOG_CRIT, "%s", symbols[i]);
+ }
+ free(symbols);
+ }
+ }
+#else /* HAVE_BACKTRACE */
+ GRN_LOG(ctx, GRN_LOG_CRIT, "backtrace() isn't available.");
+#endif /* HAVE_BACKTRACE */
+ GRN_LOG(ctx, GRN_LOG_CRIT, "----------------");
+ abort();
+}
+#endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */
+
+grn_rc
+grn_set_segv_handler(void)
+{
+ grn_rc rc = GRN_SUCCESS;
+#if defined(HAVE_SIGNAL_H) && !defined(WIN32)
+ grn_ctx *ctx = &grn_gctx;
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = segv_handler;
+ action.sa_flags = SA_SIGINFO | SA_ONSTACK;
+
+ if (sigaction(SIGSEGV, &action, NULL)) {
+ SERR("failed to set SIGSEGV action");
+ rc = ctx->rc;
+ };
+#endif
+ return rc;
+}
+
+#if defined(HAVE_SIGNAL_H) && !defined(WIN32)
+static struct sigaction old_int_handler;
+static void
+int_handler(int signal_number, siginfo_t *info, void *context)
+{
+ grn_gctx.stat = GRN_CTX_QUIT;
+ sigaction(signal_number, &old_int_handler, NULL);
+}
+
+static struct sigaction old_term_handler;
+static void
+term_handler(int signal_number, siginfo_t *info, void *context)
+{
+ grn_gctx.stat = GRN_CTX_QUIT;
+ sigaction(signal_number, &old_term_handler, NULL);
+}
+#endif /* defined(HAVE_SIGNAL_H) && !defined(WIN32) */
+
+grn_rc
+grn_set_int_handler(void)
+{
+ grn_rc rc = GRN_SUCCESS;
+#if defined(HAVE_SIGNAL_H) && !defined(WIN32)
+ grn_ctx *ctx = &grn_gctx;
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = int_handler;
+ action.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGINT, &action, &old_int_handler)) {
+ SERR("failed to set SIGINT action");
+ rc = ctx->rc;
+ }
+#endif
+ return rc;
+}
+
+grn_rc
+grn_set_term_handler(void)
+{
+ grn_rc rc = GRN_SUCCESS;
+#if defined(HAVE_SIGNAL_H) && !defined(WIN32)
+ grn_ctx *ctx = &grn_gctx;
+ struct sigaction action;
+
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = term_handler;
+ action.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGTERM, &action, &old_term_handler)) {
+ SERR("failed to set SIGTERM action");
+ rc = ctx->rc;
+ }
+#endif
+ return rc;
+}
+
+void
+grn_ctx_output_flush(grn_ctx *ctx, int flags)
+{
+ if (flags & GRN_CTX_QUIET) {
+ return;
+ }
+ if (!ctx->impl->output.func) {
+ return;
+ }
+ ctx->impl->output.func(ctx, 0, ctx->impl->output.data.ptr);
+}
+
+void
+grn_ctx_output_array_open(grn_ctx *ctx, const char *name, int nelements)
+{
+ grn_output_array_open(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ name, nelements);
+}
+
+void
+grn_ctx_output_array_close(grn_ctx *ctx)
+{
+ grn_output_array_close(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type);
+}
+
+void
+grn_ctx_output_map_open(grn_ctx *ctx, const char *name, int nelements)
+{
+ grn_output_map_open(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ name, nelements);
+}
+
+void
+grn_ctx_output_map_close(grn_ctx *ctx)
+{
+ grn_output_map_close(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type);
+}
+
+void
+grn_ctx_output_null(grn_ctx *ctx)
+{
+ grn_output_null(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type);
+}
+
+void
+grn_ctx_output_int32(grn_ctx *ctx, int value)
+{
+ grn_output_int32(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value);
+}
+
+void
+grn_ctx_output_int64(grn_ctx *ctx, int64_t value)
+{
+ grn_output_int64(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value);
+}
+
+void
+grn_ctx_output_uint64(grn_ctx *ctx, uint64_t value)
+{
+ grn_output_uint64(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value);
+}
+
+void
+grn_ctx_output_float(grn_ctx *ctx, double value)
+{
+ grn_output_float(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value);
+}
+
+void
+grn_ctx_output_cstr(grn_ctx *ctx, const char *value)
+{
+ grn_output_cstr(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value);
+}
+
+void
+grn_ctx_output_str(grn_ctx *ctx, const char *value, unsigned int value_len)
+{
+ grn_output_str(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value, value_len);
+}
+
+void
+grn_ctx_output_bool(grn_ctx *ctx, grn_bool value)
+{
+ grn_output_bool(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value);
+}
+
+void
+grn_ctx_output_obj(grn_ctx *ctx, grn_obj *value, grn_obj_format *format)
+{
+ grn_output_obj(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ value, format);
+}
+
+void
+grn_ctx_output_result_set_open(grn_ctx *ctx,
+ grn_obj *result_set,
+ grn_obj_format *format,
+ uint32_t n_additional_elements)
+{
+ grn_output_result_set_open(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ result_set,
+ format,
+ n_additional_elements);
+}
+
+void
+grn_ctx_output_result_set_close(grn_ctx *ctx,
+ grn_obj *result_set,
+ grn_obj_format *format)
+{
+ grn_output_result_set_close(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ result_set,
+ format);
+}
+
+void
+grn_ctx_output_result_set(grn_ctx *ctx,
+ grn_obj *result_set,
+ grn_obj_format *format)
+{
+ grn_output_result_set(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ result_set,
+ format);
+}
+
+void
+grn_ctx_output_table_columns(grn_ctx *ctx, grn_obj *table,
+ grn_obj_format *format)
+{
+ grn_output_table_columns(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ table,
+ format);
+}
+
+void
+grn_ctx_output_table_records(grn_ctx *ctx, grn_obj *table,
+ grn_obj_format *format)
+{
+ grn_output_table_records(ctx,
+ ctx->impl->output.buf,
+ ctx->impl->output.type,
+ table,
+ format);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ctx_impl_mrb.c b/storage/mroonga/vendor/groonga/lib/ctx_impl_mrb.c
new file mode 100644
index 00000000..7f554f3f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ctx_impl_mrb.c
@@ -0,0 +1,324 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx_impl.h"
+
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+# include "grn_ctx_impl_mrb.h"
+
+# include "grn_mrb.h"
+# include "mrb/mrb_converter.h"
+# include "mrb/mrb_error.h"
+# include "mrb/mrb_id.h"
+# include "mrb/mrb_operator.h"
+# include "mrb/mrb_command_version.h"
+# include "mrb/mrb_ctx.h"
+# include "mrb/mrb_logger.h"
+# include "mrb/mrb_query_logger.h"
+# include "mrb/mrb_void.h"
+# include "mrb/mrb_bulk.h"
+# include "mrb/mrb_pointer.h"
+# include "mrb/mrb_cache.h"
+# include "mrb/mrb_object.h"
+# include "mrb/mrb_object_flags.h"
+# include "mrb/mrb_database.h"
+# include "mrb/mrb_indexable.h"
+# include "mrb/mrb_table.h"
+# include "mrb/mrb_array.h"
+# include "mrb/mrb_hash_table.h"
+# include "mrb/mrb_patricia_trie.h"
+# include "mrb/mrb_double_array_trie.h"
+# include "mrb/mrb_table_group_flags.h"
+# include "mrb/mrb_table_group_result.h"
+# include "mrb/mrb_table_sort_flags.h"
+# include "mrb/mrb_table_sort_key.h"
+# include "mrb/mrb_record.h"
+# include "mrb/mrb_column.h"
+# include "mrb/mrb_fixed_size_column.h"
+# include "mrb/mrb_variable_size_column.h"
+# include "mrb/mrb_index_column.h"
+# include "mrb/mrb_index_cursor.h"
+# include "mrb/mrb_type.h"
+# include "mrb/mrb_expr.h"
+# include "mrb/mrb_accessor.h"
+# include "mrb/mrb_procedure.h"
+# include "mrb/mrb_command.h"
+# include "mrb/mrb_command_input.h"
+# include "mrb/mrb_table_cursor.h"
+# include "mrb/mrb_table_cursor_flags.h"
+# include "mrb/mrb_content_type.h"
+# include "mrb/mrb_writer.h"
+# include "mrb/mrb_config.h"
+# include "mrb/mrb_eval_context.h"
+# include "mrb/mrb_thread.h"
+# include "mrb/mrb_window_definition.h"
+
+# include <mruby/array.h>
+# include <mruby/string.h>
+# include <mruby/variable.h>
+#endif /* GRN_WITH_MRUBY */
+
+static grn_bool grn_ctx_impl_mrb_mruby_enabled = GRN_TRUE;
+
+void
+grn_ctx_impl_mrb_init_from_env(void)
+{
+ {
+ char grn_mruby_enabled_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_MRUBY_ENABLED",
+ grn_mruby_enabled_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_mruby_enabled_env[0] &&
+ strcmp(grn_mruby_enabled_env, "no") == 0) {
+ grn_ctx_impl_mrb_mruby_enabled = GRN_FALSE;
+ }
+ }
+}
+
+#ifdef GRN_WITH_MRUBY
+static mrb_value
+mrb_kernel_load(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *path;
+
+ mrb_get_args(mrb, "z", &path);
+
+ grn_mrb_load(ctx, path);
+ if (mrb->exc) {
+ mrb_exc_raise(mrb, mrb_obj_value(mrb->exc));
+ }
+
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_true_value();
+}
+
+static mrb_value
+mrb_groonga_init(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = mrb->ud;
+
+ mrb_undef_class_method(mrb, ctx->impl->mrb.module, "init");
+
+ mrb_define_class(mrb, "LoadError", mrb_class_get(mrb, "ScriptError"));
+ mrb_define_method(mrb, mrb->kernel_module,
+ "load", mrb_kernel_load, MRB_ARGS_REQ(1));
+
+ {
+ mrb_value load_path;
+ const char *plugins_dir;
+ const char *system_ruby_scripts_dir;
+
+ load_path = mrb_ary_new(mrb);
+ plugins_dir = grn_plugin_get_system_plugins_dir();
+ mrb_ary_push(mrb, load_path,
+ mrb_str_new_cstr(mrb, plugins_dir));
+ system_ruby_scripts_dir = grn_mrb_get_system_ruby_scripts_dir(ctx);
+ mrb_ary_push(mrb, load_path,
+ mrb_str_new_cstr(mrb, system_ruby_scripts_dir));
+ mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$LOAD_PATH"), load_path);
+ }
+
+ grn_mrb_load(ctx, "require.rb");
+ grn_mrb_load(ctx, "initialize/pre.rb");
+
+ grn_mrb_converter_init(ctx);
+ grn_mrb_error_init(ctx);
+ grn_mrb_id_init(ctx);
+ grn_mrb_operator_init(ctx);
+ grn_mrb_command_version_init(ctx);
+ grn_mrb_ctx_init(ctx);
+ grn_mrb_logger_init(ctx);
+ grn_mrb_query_logger_init(ctx);
+ grn_mrb_void_init(ctx);
+ grn_mrb_bulk_init(ctx);
+ grn_mrb_pointer_init(ctx);
+ grn_mrb_cache_init(ctx);
+ grn_mrb_object_init(ctx);
+ grn_mrb_object_flags_init(ctx);
+ grn_mrb_database_init(ctx);
+ grn_mrb_indexable_init(ctx);
+ grn_mrb_table_init(ctx);
+ grn_mrb_array_init(ctx);
+ grn_mrb_hash_table_init(ctx);
+ grn_mrb_patricia_trie_init(ctx);
+ grn_mrb_double_array_trie_init(ctx);
+ grn_mrb_table_group_flags_init(ctx);
+ grn_mrb_table_group_result_init(ctx);
+ grn_mrb_table_sort_flags_init(ctx);
+ grn_mrb_table_sort_key_init(ctx);
+ grn_mrb_record_init(ctx);
+ grn_mrb_column_init(ctx);
+ grn_mrb_fixed_size_column_init(ctx);
+ grn_mrb_variable_size_column_init(ctx);
+ grn_mrb_index_column_init(ctx);
+ grn_mrb_index_cursor_init(ctx);
+ grn_mrb_type_init(ctx);
+ grn_mrb_expr_init(ctx);
+ grn_mrb_accessor_init(ctx);
+ grn_mrb_procedure_init(ctx);
+ grn_mrb_command_init(ctx);
+ grn_mrb_command_input_init(ctx);
+ grn_mrb_table_cursor_init(ctx);
+ grn_mrb_table_cursor_flags_init(ctx);
+ grn_mrb_content_type_init(ctx);
+ grn_mrb_writer_init(ctx);
+ grn_mrb_config_init(ctx);
+ grn_mrb_eval_context_init(ctx);
+ grn_mrb_thread_init(ctx);
+ grn_mrb_window_definition_init(ctx);
+
+ grn_mrb_load(ctx, "initialize/post.rb");
+
+ return mrb_nil_value();
+}
+
+static void
+grn_ctx_impl_mrb_init_bindings(grn_ctx *ctx)
+{
+ mrb_state *mrb = ctx->impl->mrb.state;
+
+ mrb->ud = ctx;
+ ctx->impl->mrb.module = mrb_define_module(mrb, "Groonga");
+ mrb_define_const(mrb,
+ ctx->impl->mrb.module,
+ "ORDER_BY_ESTIMATED_SIZE",
+ grn_mrb_is_order_by_estimated_size_enabled() ?
+ mrb_true_value() :
+ mrb_false_value());
+ mrb_define_class_method(mrb, ctx->impl->mrb.module,
+ "init", mrb_groonga_init, MRB_ARGS_NONE());
+ mrb_funcall(mrb, mrb_obj_value(ctx->impl->mrb.module), "init", 0);
+}
+
+#ifndef USE_MEMORY_DEBUG
+static void *
+grn_ctx_impl_mrb_allocf(mrb_state *mrb, void *ptr, size_t size, void *ud)
+{
+ grn_ctx *ctx = ud;
+
+ if (size == 0) {
+ if (ptr) {
+ grn_free(ctx, ptr, __FILE__, __LINE__, __FUNCTION__);
+ }
+ return NULL;
+ } else {
+ if (ptr) {
+ return grn_realloc(ctx, ptr, size, __FILE__, __LINE__, __FUNCTION__);
+ } else {
+ return grn_malloc(ctx, size, __FILE__, __LINE__, __FUNCTION__);
+ }
+ }
+}
+#endif /* USE_MEMORY_DEBUG */
+
+static void
+grn_ctx_impl_mrb_init_lazy(grn_ctx *ctx)
+{
+ if (!grn_ctx_impl_mrb_mruby_enabled) {
+ ctx->impl->mrb.state = NULL;
+ ctx->impl->mrb.base_directory[0] = '\0';
+ ctx->impl->mrb.module = NULL;
+ ctx->impl->mrb.object_class = NULL;
+ ctx->impl->mrb.checked_procs = NULL;
+ ctx->impl->mrb.registered_plugins = NULL;
+ ctx->impl->mrb.builtin.time_class = NULL;
+ ctx->impl->mrb.groonga.operator_class = NULL;
+ } else {
+ mrb_state *mrb;
+#ifdef USE_MEMORY_DEBUG
+ mrb = mrb_open();
+#else /* USE_MEMORY_DEBUG */
+ mrb = mrb_open_allocf(grn_ctx_impl_mrb_allocf, ctx);
+#endif /* USE_MEMORY_DEBUG */
+ ctx->impl->mrb.state = mrb;
+ ctx->impl->mrb.base_directory[0] = '\0';
+ grn_ctx_impl_mrb_init_bindings(ctx);
+ if (ctx->impl->mrb.state->exc) {
+ mrb_value reason;
+ reason = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
+ ERR(GRN_UNKNOWN_ERROR,
+ "failed to initialize mruby: %.*s",
+ (int)RSTRING_LEN(reason),
+ RSTRING_PTR(reason));
+ mrb_close(ctx->impl->mrb.state);
+ ctx->impl->mrb.state = NULL;
+ } else {
+ ctx->impl->mrb.checked_procs =
+ grn_hash_create(ctx, NULL, sizeof(grn_id), 0, GRN_HASH_TINY);
+ ctx->impl->mrb.registered_plugins =
+ grn_hash_create(ctx, NULL, sizeof(grn_id), 0, GRN_HASH_TINY);
+ GRN_VOID_INIT(&(ctx->impl->mrb.buffer.from));
+ GRN_VOID_INIT(&(ctx->impl->mrb.buffer.to));
+ ctx->impl->mrb.builtin.time_class = mrb_class_get(mrb, "Time");
+ }
+ }
+}
+
+static void
+grn_ctx_impl_mrb_fin_real(grn_ctx *ctx)
+{
+ if (ctx->impl->mrb.state) {
+ mrb_close(ctx->impl->mrb.state);
+ ctx->impl->mrb.state = NULL;
+ grn_hash_close(ctx, ctx->impl->mrb.checked_procs);
+ grn_hash_close(ctx, ctx->impl->mrb.registered_plugins);
+ GRN_OBJ_FIN(ctx, &(ctx->impl->mrb.buffer.from));
+ GRN_OBJ_FIN(ctx, &(ctx->impl->mrb.buffer.to));
+ }
+}
+#else /* GRN_WITH_MRUBY */
+static void
+grn_ctx_impl_mrb_init_lazy(grn_ctx *ctx)
+{
+}
+
+static void
+grn_ctx_impl_mrb_fin_real(grn_ctx *ctx)
+{
+}
+#endif /* GRN_WITH_MRUBY */
+
+void
+grn_ctx_impl_mrb_init(grn_ctx *ctx)
+{
+ ctx->impl->mrb.initialized = GRN_FALSE;
+}
+
+void
+grn_ctx_impl_mrb_fin(grn_ctx *ctx)
+{
+ if (!ctx->impl->mrb.initialized) {
+ return;
+ }
+
+ ctx->impl->mrb.initialized = GRN_FALSE;
+ grn_ctx_impl_mrb_fin_real(ctx);
+}
+
+void
+grn_ctx_impl_mrb_ensure_init(grn_ctx *ctx)
+{
+ if (!ctx->impl->mrb.initialized) {
+ ctx->impl->mrb.initialized = GRN_TRUE;
+ grn_ctx_impl_mrb_init_lazy(ctx);
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/dat.cpp b/storage/mroonga/vendor/groonga/lib/dat.cpp
new file mode 100644
index 00000000..1446be7c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat.cpp
@@ -0,0 +1,1338 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <cstring>
+#include <new>
+#include "grn_str.h"
+#include "grn_io.h"
+#include "grn_dat.h"
+#include "grn_util.h"
+#include "grn_normalizer.h"
+
+#include "dat/trie.hpp"
+#include "dat/cursor-factory.hpp"
+
+namespace {
+
+const uint32_t FILE_ID_LENGTH = 3;
+
+class CriticalSection {
+ public:
+ CriticalSection() : lock_(NULL) {}
+ explicit CriticalSection(grn_critical_section *lock) : lock_(lock) {
+ CRITICAL_SECTION_ENTER(*lock_);
+ }
+ ~CriticalSection() {
+ leave();
+ }
+
+ void enter(grn_critical_section *lock) {
+ leave();
+ lock_ = lock;
+ }
+ void leave() {
+ if (lock_ != NULL) {
+ CRITICAL_SECTION_LEAVE(*lock_);
+ lock_ = NULL;
+ }
+ }
+
+ private:
+ grn_critical_section *lock_;
+
+ // Disallows copy and assignment.
+ CriticalSection(const CriticalSection &);
+ CriticalSection &operator=(const CriticalSection &);
+};
+
+/*
+ grn_dat_remove_file() removes a file specified by `path' and then returns
+ true on success, false on failure. Note that grn_dat_remove_file() does not
+ change `ctx->rc'.
+ */
+bool
+grn_dat_remove_file(grn_ctx *ctx, const char *path)
+{
+ struct stat stat;
+
+ if (::stat(path, &stat) == -1) {
+ return false;
+ }
+
+ if (grn_unlink(path) == -1) {
+ const char *system_message = grn_strerror(errno);
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[dat][remove-file] failed to remove path: %s: <%s>",
+ system_message, path);
+ return false;
+ }
+
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[dat][remove-file] removed: <%s>", path);
+ return true;
+}
+
+grn_rc
+grn_dat_translate_error_code(grn::dat::ErrorCode error_code) {
+ switch (error_code) {
+ case grn::dat::PARAM_ERROR: {
+ return GRN_INVALID_ARGUMENT;
+ }
+ case grn::dat::IO_ERROR: {
+ return GRN_INPUT_OUTPUT_ERROR;
+ }
+ case grn::dat::FORMAT_ERROR: {
+ return GRN_INVALID_FORMAT;
+ }
+ case grn::dat::MEMORY_ERROR: {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ case grn::dat::SIZE_ERROR:
+ case grn::dat::UNEXPECTED_ERROR: {
+ return GRN_UNKNOWN_ERROR;
+ }
+ case grn::dat::STATUS_ERROR: {
+ return GRN_FILE_CORRUPT;
+ }
+ default: {
+ return GRN_UNKNOWN_ERROR;
+ }
+ }
+}
+
+void
+grn_dat_init(grn_ctx *, grn_dat *dat)
+{
+ GRN_DB_OBJ_SET_TYPE(dat, GRN_TABLE_DAT_KEY);
+ dat->io = NULL;
+ dat->header = NULL;
+ dat->file_id = 0;
+ dat->encoding = GRN_ENC_DEFAULT;
+ dat->trie = NULL;
+ dat->old_trie = NULL;
+ dat->tokenizer = NULL;
+ dat->normalizer = NULL;
+ GRN_PTR_INIT(&(dat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ CRITICAL_SECTION_INIT(dat->lock);
+ dat->is_dirty = GRN_FALSE;
+}
+
+void
+grn_dat_fin(grn_ctx *ctx, grn_dat *dat)
+{
+ CRITICAL_SECTION_FIN(dat->lock);
+ delete static_cast<grn::dat::Trie *>(dat->old_trie);
+ delete static_cast<grn::dat::Trie *>(dat->trie);
+ dat->old_trie = NULL;
+ dat->trie = NULL;
+ if (dat->io) {
+ if (dat->is_dirty) {
+ uint32_t n_dirty_opens;
+ GRN_ATOMIC_ADD_EX(&(dat->header->n_dirty_opens), -1, n_dirty_opens);
+ }
+ grn_io_close(ctx, dat->io);
+ dat->io = NULL;
+ }
+ GRN_OBJ_FIN(ctx, &(dat->token_filters));
+}
+
+/*
+ grn_dat_generate_trie_path() generates the path from `base_path' and
+ `file_id'. The generated path is stored in `trie_path'.
+ */
+void
+grn_dat_generate_trie_path(const char *base_path, char *trie_path, uint32_t file_id)
+{
+ if (!base_path || !base_path[0]) {
+ trie_path[0] = '\0';
+ return;
+ }
+ const size_t len = std::strlen(base_path);
+ grn_memcpy(trie_path, base_path, len);
+ trie_path[len] = '.';
+ grn_itoh(file_id % (1U << (4 * FILE_ID_LENGTH)),
+ trie_path + len + 1, FILE_ID_LENGTH);
+ trie_path[len + 1 + FILE_ID_LENGTH] = '\0';
+}
+
+bool
+grn_dat_open_trie_if_needed(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!dat) {
+ ERR(GRN_INVALID_ARGUMENT, "dat is null");
+ return false;
+ }
+
+ const uint32_t file_id = dat->header->file_id;
+ if (!file_id || (dat->trie && (file_id <= dat->file_id))) {
+ /*
+ There is no need to open file when no trie file is available or the
+ current trie file is the latest one.
+ */
+ return true;
+ }
+
+ CriticalSection critical_section(&dat->lock);
+
+ if (dat->trie && (file_id <= dat->file_id)) {
+ /*
+ There is no need to open file if the latest file has been opened by
+ another thread.
+ */
+ return true;
+ }
+
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, file_id);
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ grn::dat::Trie * const old_trie = static_cast<grn::dat::Trie *>(dat->old_trie);
+ grn::dat::Trie * const new_trie = new (std::nothrow) grn::dat::Trie;
+ if (!new_trie) {
+ MERR("new grn::dat::Trie failed");
+ return false;
+ }
+
+ if (trie_path[0] == '\0') {
+ try {
+ new_trie->create(trie_path);
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::create failed: %s",
+ ex.what());
+ delete new_trie;
+ return false;
+ }
+ } else {
+ try {
+ new_trie->open(trie_path);
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::open failed: %s",
+ ex.what());
+ delete new_trie;
+ return false;
+ }
+ }
+
+ dat->old_trie = trie;
+ dat->trie = new_trie;
+ dat->file_id = file_id;
+
+ critical_section.leave();
+
+ delete old_trie;
+ if (file_id >= 3) {
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, file_id - 2);
+ grn_dat_remove_file(ctx, trie_path);
+ }
+ return true;
+}
+
+bool grn_dat_rebuild_trie(grn_ctx *ctx, grn_dat *dat) {
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ grn::dat::Trie * const new_trie = new (std::nothrow) grn::dat::Trie;
+ if (!new_trie) {
+ MERR("new grn::dat::Trie failed");
+ return false;
+ }
+
+ const uint32_t file_id = dat->header->file_id;
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, file_id + 1);
+
+ for (uint64_t file_size = trie->file_size() * 2;; file_size *= 2) {
+ try {
+ new_trie->create(*trie, trie_path, file_size);
+ } catch (const grn::dat::SizeError &) {
+ continue;
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::open failed: %s",
+ ex.what());
+ delete new_trie;
+ return false;
+ }
+ break;
+ }
+
+ grn::dat::Trie * const old_trie = static_cast<grn::dat::Trie *>(dat->old_trie);
+ dat->old_trie = dat->trie;
+ dat->trie = new_trie;
+ dat->header->file_id = dat->file_id = file_id + 1;
+
+ delete old_trie;
+ if (file_id >= 2) {
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, file_id - 1);
+ grn_dat_remove_file(ctx, trie_path);
+ }
+ return true;
+}
+
+void grn_dat_cursor_init(grn_ctx *, grn_dat_cursor *cursor) {
+ GRN_DB_OBJ_SET_TYPE(cursor, GRN_CURSOR_TABLE_DAT_KEY);
+ cursor->dat = NULL;
+ cursor->cursor = NULL;
+ cursor->key = &grn::dat::Key::invalid_key();
+ cursor->curr_rec = GRN_ID_NIL;
+}
+
+void grn_dat_cursor_fin(grn_ctx *, grn_dat_cursor *cursor) {
+ delete static_cast<grn::dat::Cursor *>(cursor->cursor);
+ cursor->dat = NULL;
+ cursor->cursor = NULL;
+ cursor->key = &grn::dat::Key::invalid_key();
+ cursor->curr_rec = GRN_ID_NIL;
+}
+
+} // namespace
+
+extern "C" {
+
+grn_dat *
+grn_dat_create(grn_ctx *ctx, const char *path, uint32_t,
+ uint32_t, uint32_t flags)
+{
+ if (path) {
+ if (path[0] == '\0') {
+ path = NULL;
+ } else if (std::strlen(path) >= (PATH_MAX - (FILE_ID_LENGTH + 1))) {
+ ERR(GRN_FILENAME_TOO_LONG, "too long path");
+ return NULL;
+ }
+ }
+
+ grn_dat * const dat = static_cast<grn_dat *>(GRN_CALLOC(sizeof(grn_dat)));
+ if (!dat) {
+ return NULL;
+ }
+ grn_dat_init(ctx, dat);
+
+ dat->io = grn_io_create(ctx, path, sizeof(struct grn_dat_header),
+ 4096, 0, grn_io_auto, GRN_IO_EXPIRE_SEGMENT);
+ if (!dat->io) {
+ GRN_FREE(dat);
+ return NULL;
+ }
+ grn_io_set_type(dat->io, GRN_TABLE_DAT_KEY);
+
+ dat->header = static_cast<struct grn_dat_header *>(grn_io_header(dat->io));
+ if (!dat->header) {
+ grn_io_close(ctx, dat->io);
+ grn_dat_remove_file(ctx, path);
+ GRN_FREE(dat);
+ return NULL;
+ }
+ const grn_encoding encoding = (ctx->encoding != GRN_ENC_DEFAULT) ?
+ ctx->encoding : grn_gctx.encoding;
+ dat->header->flags = flags;
+ dat->header->encoding = encoding;
+ dat->header->tokenizer = GRN_ID_NIL;
+ dat->header->file_id = 0;
+ if (dat->header->flags & GRN_OBJ_KEY_NORMALIZE) {
+ dat->header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
+ dat->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ dat->header->normalizer = grn_obj_id(ctx, dat->normalizer);
+ } else {
+ dat->normalizer = NULL;
+ dat->header->normalizer = GRN_ID_NIL;
+ }
+ dat->encoding = encoding;
+ dat->tokenizer = NULL;
+ GRN_PTR_INIT(&(dat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+
+ dat->obj.header.flags = dat->header->flags;
+
+ return dat;
+}
+
+grn_dat *
+grn_dat_open(grn_ctx *ctx, const char *path)
+{
+ if (path && (std::strlen(path) >= (PATH_MAX - (FILE_ID_LENGTH + 1)))) {
+ ERR(GRN_FILENAME_TOO_LONG, "too long path");
+ return NULL;
+ }
+
+ grn_dat * const dat = static_cast<grn_dat *>(GRN_MALLOC(sizeof(grn_dat)));
+ if (!dat) {
+ return NULL;
+ }
+
+ grn_dat_init(ctx, dat);
+ dat->io = grn_io_open(ctx, path, grn_io_auto);
+ if (!dat->io) {
+ GRN_FREE(dat);
+ return NULL;
+ }
+
+ dat->header = (struct grn_dat_header *)grn_io_header(dat->io);
+ if (!dat->header) {
+ grn_io_close(ctx, dat->io);
+ GRN_FREE(dat);
+ return NULL;
+ }
+ dat->file_id = dat->header->file_id;
+ dat->encoding = dat->header->encoding;
+ dat->tokenizer = grn_ctx_at(ctx, dat->header->tokenizer);
+ if (dat->header->flags & GRN_OBJ_KEY_NORMALIZE) {
+ dat->header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
+ dat->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ dat->header->normalizer = grn_obj_id(ctx, dat->normalizer);
+ } else {
+ dat->normalizer = grn_ctx_at(ctx, dat->header->normalizer);
+ }
+ GRN_PTR_INIT(&(dat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ dat->obj.header.flags = dat->header->flags;
+ return dat;
+}
+
+grn_rc
+grn_dat_close(grn_ctx *ctx, grn_dat *dat)
+{
+ if (dat) {
+ grn_dat_fin(ctx, dat);
+ GRN_FREE(dat);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_remove(grn_ctx *ctx, const char *path)
+{
+ if (!path) {
+ ERR(GRN_INVALID_ARGUMENT, "path is null");
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ grn_dat * const dat = grn_dat_open(ctx, path);
+ if (!dat) {
+ return ctx->rc;
+ }
+ const uint32_t file_id = dat->header->file_id;
+ grn_dat_close(ctx, dat);
+
+ /*
+ grn_dat_remove() tries to remove (file_id + 1)th trie file because
+ grn::dat::Trie::create() might leave an incomplete file on failure.
+ */
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(path, trie_path, file_id + 1);
+ grn_dat_remove_file(ctx, trie_path);
+ for (uint32_t i = file_id; i > 0; --i) {
+ grn_dat_generate_trie_path(path, trie_path, i);
+ if (!grn_dat_remove_file(ctx, trie_path)) {
+ break;
+ }
+ }
+
+ /*
+ grn_io_remove() reports an error when it fails to remove `path'.
+ */
+ return grn_io_remove(ctx, path);
+}
+
+grn_id
+grn_dat_get(grn_ctx *ctx, grn_dat *dat, const void *key,
+ unsigned int key_size, void **)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return GRN_ID_NIL;
+ }
+ const grn::dat::Trie * const trie = static_cast<const grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return GRN_ID_NIL;
+ }
+ grn::dat::UInt32 key_pos;
+ try {
+ if (trie->search(key, key_size, &key_pos)) {
+ return trie->get_key(key_pos).id();
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::search failed: %s",
+ ex.what());
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_dat_add(grn_ctx *ctx, grn_dat *dat, const void *key,
+ unsigned int key_size, void **, int *added)
+{
+ if (!key_size) {
+ return GRN_ID_NIL;
+ } else if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return GRN_ID_NIL;
+ }
+
+ if (!dat->trie) {
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, 1);
+ grn::dat::Trie * const new_trie = new (std::nothrow) grn::dat::Trie;
+ if (!new_trie) {
+ MERR("new grn::dat::Trie failed");
+ return GRN_ID_NIL;
+ }
+ try {
+ new_trie->create(trie_path);
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::create failed: %s",
+ ex.what());
+ delete new_trie;
+ return GRN_ID_NIL;
+ }
+ dat->trie = new_trie;
+ dat->file_id = dat->header->file_id = 1;
+ }
+
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ try {
+ grn::dat::UInt32 key_pos;
+ const bool res = trie->insert(key, key_size, &key_pos);
+ if (added) {
+ *added = res ? 1 : 0;
+ }
+ return trie->get_key(key_pos).id();
+ } catch (const grn::dat::SizeError &) {
+ if (!grn_dat_rebuild_trie(ctx, dat)) {
+ return GRN_ID_NIL;
+ }
+ grn::dat::Trie * const new_trie = static_cast<grn::dat::Trie *>(dat->trie);
+ grn::dat::UInt32 key_pos;
+ const bool res = new_trie->insert(key, key_size, &key_pos);
+ if (added) {
+ *added = res ? 1 : 0;
+ }
+ return new_trie->get_key(key_pos).id();
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::insert failed: %s",
+ ex.what());
+ return GRN_ID_NIL;
+ }
+}
+
+int
+grn_dat_get_key(grn_ctx *ctx, grn_dat *dat, grn_id id, void *keybuf, int bufsize)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return 0;
+ }
+ const grn::dat::Trie * const trie = static_cast<const grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return 0;
+ }
+ const grn::dat::Key &key = trie->ith_key(id);
+ if (!key.is_valid()) {
+ return 0;
+ }
+ if (keybuf && (bufsize >= (int)key.length())) {
+ grn_memcpy(keybuf, key.ptr(), key.length());
+ }
+ return (int)key.length();
+}
+
+int
+grn_dat_get_key2(grn_ctx *ctx, grn_dat *dat, grn_id id, grn_obj *bulk)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return 0;
+ }
+ const grn::dat::Trie * const trie = static_cast<const grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return 0;
+ }
+ const grn::dat::Key &key = trie->ith_key(id);
+ if (!key.is_valid()) {
+ return 0;
+ }
+ if (bulk->header.impl_flags & GRN_OBJ_REFER) {
+ bulk->u.b.head = static_cast<char *>(const_cast<void *>(key.ptr()));
+ bulk->u.b.curr = bulk->u.b.head + key.length();
+ } else {
+ grn_bulk_write(ctx, bulk, static_cast<const char *>(key.ptr()), key.length());
+ }
+ return (int)key.length();
+}
+
+grn_rc
+grn_dat_delete_by_id(grn_ctx *ctx, grn_dat *dat, grn_id id,
+ grn_table_delete_optarg *optarg)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ } else if (!dat->trie || (id == GRN_ID_NIL)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (optarg && optarg->func) {
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->ith_entry(id).is_valid()) {
+ return GRN_INVALID_ARGUMENT;
+ } else if (!optarg->func(ctx, reinterpret_cast<grn_obj *>(dat), id, optarg->func_arg)) {
+ return GRN_SUCCESS;
+ }
+ }
+
+ try {
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->remove(id)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::remove failed: %s",
+ ex.what());
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_delete(grn_ctx *ctx, grn_dat *dat, const void *key, unsigned int key_size,
+ grn_table_delete_optarg *optarg)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ } else if (!dat->trie || !key || !key_size) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (optarg && optarg->func) {
+ try {
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ grn::dat::UInt32 key_pos;
+ if (!trie->search(key, key_size, &key_pos)) {
+ return GRN_INVALID_ARGUMENT;
+ } else if (!optarg->func(ctx, reinterpret_cast<grn_obj *>(dat),
+ trie->get_key(key_pos).id(), optarg->func_arg)) {
+ return GRN_SUCCESS;
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::search failed: %s",
+ ex.what());
+ return ctx->rc;
+ }
+ }
+
+ try {
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->remove(key, key_size)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::remove failed: %s",
+ ex.what());
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_update_by_id(grn_ctx *ctx, grn_dat *dat, grn_id src_key_id,
+ const void *dest_key, unsigned int dest_key_size)
+{
+ if (!dest_key_size) {
+ return GRN_INVALID_ARGUMENT;
+ } else if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ } else if (!dat->trie) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ try {
+ try {
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->update(src_key_id, dest_key, dest_key_size)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ } catch (const grn::dat::SizeError &) {
+ if (!grn_dat_rebuild_trie(ctx, dat)) {
+ return ctx->rc;
+ }
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->update(src_key_id, dest_key, dest_key_size)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::update failed: %s",
+ ex.what());
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_update(grn_ctx *ctx, grn_dat *dat,
+ const void *src_key, unsigned int src_key_size,
+ const void *dest_key, unsigned int dest_key_size)
+{
+ if (!dest_key_size) {
+ return GRN_INVALID_ARGUMENT;
+ } else if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ } else if (!dat->trie) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ try {
+ try {
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->update(src_key, src_key_size, dest_key, dest_key_size)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ } catch (const grn::dat::SizeError &) {
+ if (!grn_dat_rebuild_trie(ctx, dat)) {
+ return ctx->rc;
+ }
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie->update(src_key, src_key_size, dest_key, dest_key_size)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::update failed: %s",
+ ex.what());
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+int
+grn_dat_scan(grn_ctx *ctx, grn_dat *dat, const char *str,
+ unsigned int str_size, grn_dat_scan_hit *scan_hits,
+ unsigned int max_num_scan_hits, const char **str_rest)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat) || !str ||
+ !(dat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) || !scan_hits) {
+ if (str_rest) {
+ *str_rest = str;
+ }
+ return -1;
+ }
+
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ if (str_rest) {
+ *str_rest = str + str_size;
+ }
+ return 0;
+ }
+
+ if (!max_num_scan_hits || !str_size) {
+ if (str_rest) {
+ *str_rest = str;
+ }
+ return 0;
+ }
+
+ unsigned int num_scan_hits = 0;
+ try {
+ if (dat->normalizer) {
+ int flags = GRN_STRING_WITH_CHECKS;
+ grn_obj * const normalized_string = grn_string_open(ctx, str, str_size,
+ dat->normalizer,
+ flags);
+ if (!normalized_string) {
+ if (str_rest) {
+ *str_rest = str;
+ }
+ return -1;
+ }
+ grn_string_get_normalized(ctx, normalized_string, &str, &str_size, NULL);
+ const short *checks = grn_string_get_checks(ctx, normalized_string);
+ unsigned int offset = 0;
+ while (str_size) {
+ if (*checks) {
+ grn::dat::UInt32 key_pos;
+ if (trie->lcp_search(str, str_size, &key_pos)) {
+ const grn::dat::Key &key = trie->get_key(key_pos);
+ const grn::dat::UInt32 key_length = key.length();
+ if ((key_length == str_size) || (checks[key_length])) {
+ unsigned int length = 0;
+ for (grn::dat::UInt32 i = 0; i < key_length; ++i) {
+ if (checks[i] > 0) {
+ length += checks[i];
+ }
+ }
+ scan_hits[num_scan_hits].id = key.id();
+ scan_hits[num_scan_hits].offset = offset;
+ scan_hits[num_scan_hits].length = length;
+ offset += length;
+ str += key_length;
+ str_size -= key_length;
+ checks += key_length;
+ if (++num_scan_hits >= max_num_scan_hits) {
+ break;
+ }
+ continue;
+ }
+ }
+ if (*checks > 0) {
+ offset += *checks;
+ }
+ }
+ ++str;
+ --str_size;
+ ++checks;
+ }
+ if (str_rest) {
+ grn_string_get_original(ctx, normalized_string, str_rest, NULL);
+ *str_rest += offset;
+ }
+ grn_obj_close(ctx, normalized_string);
+ } else {
+ const char * const begin = str;
+ while (str_size) {
+ grn::dat::UInt32 key_pos;
+ if (trie->lcp_search(str, str_size, &key_pos)) {
+ const grn::dat::Key &key = trie->get_key(key_pos);
+ scan_hits[num_scan_hits].id = key.id();
+ scan_hits[num_scan_hits].offset = str - begin;
+ scan_hits[num_scan_hits].length = key.length();
+ str += key.length();
+ str_size -= key.length();
+ if (++num_scan_hits >= max_num_scan_hits) {
+ break;
+ }
+ } else {
+ const int char_length = grn_charlen(ctx, str, str + str_size);
+ if (char_length) {
+ str += char_length;
+ str_size -= char_length;
+ } else {
+ ++str;
+ --str_size;
+ }
+ }
+ }
+ if (str_rest) {
+ *str_rest = str;
+ }
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::lcp_search failed: %s",
+ ex.what());
+ if (str_rest) {
+ *str_rest = str;
+ }
+ return -1;
+ }
+ return static_cast<int>(num_scan_hits);
+}
+
+grn_id
+grn_dat_lcp_search(grn_ctx *ctx, grn_dat *dat,
+ const void *key, unsigned int key_size)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat) || !key ||
+ !(dat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
+ return GRN_ID_NIL;
+ }
+
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return GRN_ID_NIL;
+ }
+
+ try {
+ grn::dat::UInt32 key_pos;
+ if (!trie->lcp_search(key, key_size, &key_pos)) {
+ return GRN_ID_NIL;
+ }
+ return trie->get_key(key_pos).id();
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::PrefixCursor::open failed: %s",
+ ex.what());
+ return GRN_ID_NIL;
+ }
+}
+
+unsigned int
+grn_dat_size(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return 0;
+ }
+ const grn::dat::Trie * const trie = static_cast<const grn::dat::Trie *>(dat->trie);
+ if (trie) {
+ return trie->num_keys();
+ }
+ return 0;
+}
+
+grn_dat_cursor *
+grn_dat_cursor_open(grn_ctx *ctx, grn_dat *dat,
+ const void *min, unsigned int min_size,
+ const void *max, unsigned int max_size,
+ int offset, int limit, int flags)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return NULL;
+ }
+
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ grn_dat_cursor * const dc =
+ static_cast<grn_dat_cursor *>(GRN_MALLOC(sizeof(grn_dat_cursor)));
+ if (dc) {
+ grn_dat_cursor_init(ctx, dc);
+ }
+ return dc;
+ }
+
+ grn_dat_cursor * const dc =
+ static_cast<grn_dat_cursor *>(GRN_MALLOC(sizeof(grn_dat_cursor)));
+ if (!dc) {
+ return NULL;
+ }
+ grn_dat_cursor_init(ctx, dc);
+
+ try {
+ if ((flags & GRN_CURSOR_BY_ID) != 0) {
+ dc->cursor = grn::dat::CursorFactory::open(*trie,
+ min, min_size, max, max_size, offset, limit,
+ grn::dat::ID_RANGE_CURSOR |
+ ((flags & GRN_CURSOR_DESCENDING) ? grn::dat::DESCENDING_CURSOR : 0) |
+ ((flags & GRN_CURSOR_GT) ? grn::dat::EXCEPT_LOWER_BOUND : 0) |
+ ((flags & GRN_CURSOR_LT) ? grn::dat::EXCEPT_UPPER_BOUND : 0));
+ } else if ((flags & GRN_CURSOR_PREFIX) != 0) {
+ if (max && max_size) {
+ if ((dat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) != 0) {
+ dc->cursor = grn::dat::CursorFactory::open(*trie,
+ NULL, min_size, max, max_size, offset, limit,
+ grn::dat::PREFIX_CURSOR | grn::dat::DESCENDING_CURSOR);
+ } else {
+ // TODO: near
+ }
+ } else if (min && min_size) {
+ if ((flags & GRN_CURSOR_RK) != 0) {
+ // TODO: rk search
+ } else {
+ dc->cursor = grn::dat::CursorFactory::open(*trie,
+ min, min_size, NULL, 0, offset, limit,
+ grn::dat::PREDICTIVE_CURSOR |
+ ((flags & GRN_CURSOR_DESCENDING) ? grn::dat::DESCENDING_CURSOR : 0) |
+ ((flags & GRN_CURSOR_GT) ? grn::dat::EXCEPT_EXACT_MATCH : 0));
+ }
+ }
+ } else {
+ dc->cursor = grn::dat::CursorFactory::open(*trie,
+ min, min_size, max, max_size, offset, limit,
+ grn::dat::KEY_RANGE_CURSOR |
+ ((flags & GRN_CURSOR_DESCENDING) ? grn::dat::DESCENDING_CURSOR : 0) |
+ ((flags & GRN_CURSOR_GT) ? grn::dat::EXCEPT_LOWER_BOUND : 0) |
+ ((flags & GRN_CURSOR_LT) ? grn::dat::EXCEPT_UPPER_BOUND : 0));
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::CursorFactory::open failed: %s",
+ ex.what());
+ GRN_FREE(dc);
+ return NULL;
+ }
+ if (!dc->cursor) {
+ ERR(GRN_INVALID_ARGUMENT, "unsupported query");
+ GRN_FREE(dc);
+ return NULL;
+ }
+ dc->dat = dat;
+ return dc;
+}
+
+grn_id
+grn_dat_cursor_next(grn_ctx *ctx, grn_dat_cursor *c)
+{
+ if (!c || !c->cursor) {
+ return GRN_ID_NIL;
+ }
+ try {
+ grn::dat::Cursor * const cursor = static_cast<grn::dat::Cursor *>(c->cursor);
+ const grn::dat::Key &key = cursor->next();
+ c->key = &key;
+ c->curr_rec = key.is_valid() ? key.id() : GRN_ID_NIL;
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Cursor::next failed: %s",
+ ex.what());
+ return GRN_ID_NIL;
+ }
+ return c->curr_rec;
+}
+
+void
+grn_dat_cursor_close(grn_ctx *ctx, grn_dat_cursor *c)
+{
+ if (c) {
+ grn_dat_cursor_fin(ctx, c);
+ GRN_FREE(c);
+ }
+}
+
+int
+grn_dat_cursor_get_key(grn_ctx *ctx, grn_dat_cursor *c, const void **key)
+{
+ if (c) {
+ const grn::dat::Key &key_ref = *static_cast<const grn::dat::Key *>(c->key);
+ if (key_ref.is_valid()) {
+ *key = key_ref.ptr();
+ return (int)key_ref.length();
+ }
+ }
+ return 0;
+}
+
+grn_rc
+grn_dat_cursor_delete(grn_ctx *ctx, grn_dat_cursor *c,
+ grn_table_delete_optarg *optarg)
+{
+ if (!c || !c->cursor) {
+ return GRN_INVALID_ARGUMENT;
+ } else if (!grn_dat_open_trie_if_needed(ctx, c->dat)) {
+ return ctx->rc;
+ }
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(c->dat->trie);
+ if (!trie) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ try {
+ if (trie->remove(c->curr_rec)) {
+ return GRN_SUCCESS;
+ }
+ } catch (const grn::dat::Exception &ex) {
+ ERR(grn_dat_translate_error_code(ex.code()),
+ "grn::dat::Trie::remove failed: %s",
+ ex.what());
+ return GRN_INVALID_ARGUMENT;
+ }
+ return GRN_INVALID_ARGUMENT;
+}
+
+grn_id
+grn_dat_curr_id(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return GRN_ID_NIL;
+ }
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (trie) {
+ return trie->max_key_id();
+ }
+ return GRN_ID_NIL;
+}
+
+grn_rc
+grn_dat_truncate(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ }
+ const grn::dat::Trie * const trie = static_cast<const grn::dat::Trie *>(dat->trie);
+ if (!trie || !trie->max_key_id()) {
+ return GRN_SUCCESS;
+ }
+
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, dat->header->file_id + 1);
+ try {
+ grn::dat::Trie().create(trie_path);
+ } catch (const grn::dat::Exception &ex) {
+ const grn_rc error_code = grn_dat_translate_error_code(ex.code());
+ ERR(error_code, "grn::dat::Trie::create failed: %s", ex.what());
+ return error_code;
+ }
+ ++dat->header->file_id;
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+const char *
+_grn_dat_key(grn_ctx *ctx, grn_dat *dat, grn_id id, uint32_t *key_size)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ *key_size = 0;
+ return NULL;
+ }
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ *key_size = 0;
+ return NULL;
+ }
+ const grn::dat::Key &key = trie->ith_key(id);
+ if (!key.is_valid()) {
+ *key_size = 0;
+ return NULL;
+ }
+ *key_size = key.length();
+ return static_cast<const char *>(key.ptr());
+}
+
+grn_id
+grn_dat_next(grn_ctx *ctx, grn_dat *dat, grn_id id)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return GRN_ID_NIL;
+ }
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return GRN_ID_NIL;
+ }
+ while (id < trie->max_key_id()) {
+ if (trie->ith_key(++id).is_valid()) {
+ return id;
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_dat_at(grn_ctx *ctx, grn_dat *dat, grn_id id)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return GRN_ID_NIL;
+ }
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return GRN_ID_NIL;
+ }
+ const grn::dat::Key &key = trie->ith_key(id);
+ if (!key.is_valid()) {
+ return GRN_ID_NIL;
+ }
+ return id;
+}
+
+grn_rc
+grn_dat_clear_status_flags(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ }
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ trie->clear_status_flags();
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_repair(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ }
+ const grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ if (!trie) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io), trie_path, dat->header->file_id + 1);
+ try {
+ grn::dat::Trie().repair(*trie, trie_path);
+ } catch (const grn::dat::Exception &ex) {
+ const grn_rc error_code = grn_dat_translate_error_code(ex.code());
+ ERR(error_code, "grn::dat::Trie::create failed: %s", ex.what());
+ return error_code;
+ }
+ ++dat->header->file_id;
+ if (!grn_dat_open_trie_if_needed(ctx, dat)) {
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_flush(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!dat->io) {
+ return GRN_SUCCESS;
+ }
+
+ grn_rc rc = grn_io_flush(ctx, dat->io);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ if (dat->trie) {
+ grn::dat::Trie * const trie = static_cast<grn::dat::Trie *>(dat->trie);
+ try {
+ trie->flush();
+ } catch (const grn::dat::Exception &ex) {
+ const grn_rc error_code = grn_dat_translate_error_code(ex.code());
+ if (error_code == GRN_INPUT_OUTPUT_ERROR) {
+ SERR("grn::dat::Trie::flush failed: %s", ex.what());
+ } else {
+ ERR(error_code, "grn::dat::Trie::flush failed: %s", ex.what());
+ }
+ return error_code;
+ }
+ }
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_dat_dirty(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!dat->io) {
+ return GRN_SUCCESS;
+ }
+
+ grn_rc rc = GRN_SUCCESS;
+
+ {
+ CriticalSection critical_section(&dat->lock);
+ if (!dat->is_dirty) {
+ uint32_t n_dirty_opens;
+ dat->is_dirty = GRN_TRUE;
+ GRN_ATOMIC_ADD_EX(&(dat->header->n_dirty_opens), 1, n_dirty_opens);
+ rc = grn_io_flush(ctx, dat->io);
+ }
+ }
+
+ return rc;
+}
+
+grn_bool
+grn_dat_is_dirty(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!dat->header) {
+ return GRN_FALSE;
+ }
+
+ return dat->header->n_dirty_opens > 0;
+}
+
+grn_rc
+grn_dat_clean(grn_ctx *ctx, grn_dat *dat)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ if (!dat->io) {
+ return rc;
+ }
+
+ {
+ CriticalSection critical_section(&dat->lock);
+ if (dat->is_dirty) {
+ uint32_t n_dirty_opens;
+ dat->is_dirty = GRN_FALSE;
+ GRN_ATOMIC_ADD_EX(&(dat->header->n_dirty_opens), -1, n_dirty_opens);
+ rc = grn_io_flush(ctx, dat->io);
+ }
+ }
+
+ return rc;
+}
+
+grn_rc
+grn_dat_clear_dirty(grn_ctx *ctx, grn_dat *dat)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ if (!dat->io) {
+ return rc;
+ }
+
+ {
+ CriticalSection critical_section(&dat->lock);
+ dat->is_dirty = GRN_FALSE;
+ dat->header->n_dirty_opens = 0;
+ rc = grn_io_flush(ctx, dat->io);
+ }
+
+ return rc;
+}
+
+grn_bool
+grn_dat_is_corrupt(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!dat->io) {
+ return GRN_FALSE;
+ }
+
+ {
+ CriticalSection critical_section(&dat->lock);
+
+ if (grn_io_is_corrupt(ctx, dat->io)) {
+ return GRN_TRUE;
+ }
+
+ if (dat->header->file_id == 0) {
+ return GRN_FALSE;
+ }
+
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io),
+ trie_path,
+ dat->header->file_id);
+ struct stat stat;
+ if (::stat(trie_path, &stat) != 0) {
+ SERR("[dat][corrupt] used path doesn't exist: <%s>",
+ trie_path);
+ return GRN_TRUE;
+ }
+ }
+
+ return GRN_FALSE;
+}
+
+size_t
+grn_dat_get_disk_usage(grn_ctx *ctx, grn_dat *dat)
+{
+ if (!dat->io) {
+ return 0;
+ }
+
+ {
+ CriticalSection critical_section(&dat->lock);
+ size_t usage;
+
+ usage = grn_io_get_disk_usage(ctx, dat->io);
+
+ if (dat->header->file_id == 0) {
+ return usage;
+ }
+
+ char trie_path[PATH_MAX];
+ grn_dat_generate_trie_path(grn_io_path(dat->io),
+ trie_path,
+ dat->header->file_id);
+ struct stat stat;
+ if (::stat(trie_path, &stat) == 0) {
+ usage += stat.st_size;
+ }
+
+ return usage;
+ }
+}
+
+} // extern "C"
diff --git a/storage/mroonga/vendor/groonga/lib/dat/Makefile.am b/storage/mroonga/vendor/groonga/lib/dat/Makefile.am
new file mode 100644
index 00000000..0a58629c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/Makefile.am
@@ -0,0 +1,11 @@
+DEFS += -D_REENTRANT $(GRN_DEFS) -DGRN_DAT_EXPORT
+
+DEFAULT_INCLUDES = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include
+
+noinst_LTLIBRARIES = libgrndat.la
+
+include sources.am
+
+CLEANFILES = *.gcno *.gcda
diff --git a/storage/mroonga/vendor/groonga/lib/dat/array.hpp b/storage/mroonga/vendor/groonga/lib/dat/array.hpp
new file mode 100644
index 00000000..de60e3bd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/array.hpp
@@ -0,0 +1,98 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+// This class is used to detect an out-of-range access in debug mode.
+template <typename T>
+class GRN_DAT_API Array {
+ public:
+ Array() : ptr_(NULL), size_(0) {}
+ Array(void *ptr, UInt32 size) : ptr_(static_cast<T *>(ptr)), size_(size) {
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (size != 0));
+ }
+ template <UInt32 U>
+ explicit Array(T (&array)[U]) : ptr_(array), size_(U) {}
+ ~Array() {}
+
+ const T &operator[](UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i >= size_);
+ return ptr_[i];
+ }
+ T &operator[](UInt32 i) {
+ GRN_DAT_DEBUG_THROW_IF(i >= size_);
+ return ptr_[i];
+ }
+
+ const T *begin() const {
+ return ptr();
+ }
+ T *begin() {
+ return ptr();
+ }
+
+ const T *end() const {
+ return ptr() + size();
+ }
+ T *end() {
+ return ptr() + size();
+ }
+
+ void assign(void *ptr, UInt32 size) {
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (size != 0));
+ ptr_ = static_cast<T *>(ptr);
+ size_ = size;
+ }
+ template <UInt32 U>
+ void assign(T (&array)[U]) {
+ assign(array, U);
+ }
+
+ void swap(Array *rhs) {
+ T * const temp_ptr = ptr_;
+ ptr_ = rhs->ptr_;
+ rhs->ptr_ = temp_ptr;
+
+ const UInt32 temp_size = size_;
+ size_ = rhs->size_;
+ rhs->size_ = temp_size;
+ }
+
+ T *ptr() const {
+ return ptr_;
+ }
+ UInt32 size() const {
+ return size_;
+ }
+
+ private:
+ T *ptr_;
+ UInt32 size_;
+
+ // Disallows copy and assignment.
+ Array(const Array &);
+ Array &operator=(const Array &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/base.hpp b/storage/mroonga/vendor/groonga/lib/dat/base.hpp
new file mode 100644
index 00000000..51ec6f2f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/base.hpp
@@ -0,0 +1,67 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+// The most significant bit represents whether or not the node is a linker.
+// BASE of a linker represents the position of its associated key and BASE of
+// a non-linker represents the offset to its child nodes.
+class GRN_DAT_API Base {
+ public:
+ Base() : value_(0) {}
+
+ bool operator==(const Base &rhs) const {
+ return value_ == rhs.value_;
+ }
+
+ bool is_linker() const {
+ return (value_ & IS_LINKER_FLAG) == IS_LINKER_FLAG;
+ }
+ UInt32 offset() const {
+ GRN_DAT_DEBUG_THROW_IF(is_linker());
+ return value_;
+ }
+ UInt32 key_pos() const {
+ GRN_DAT_DEBUG_THROW_IF(!is_linker());
+ return value_ & ~IS_LINKER_FLAG;
+ }
+
+ void set_offset(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF((x & IS_LINKER_FLAG) != 0);
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_OFFSET);
+ value_ = x;
+ }
+ void set_key_pos(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF((x & IS_LINKER_FLAG) != 0);
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_OFFSET);
+ value_ = IS_LINKER_FLAG | x;
+ }
+
+ private:
+ UInt32 value_;
+
+ static const UInt32 IS_LINKER_FLAG = 0x80000000U;
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/block.hpp b/storage/mroonga/vendor/groonga/lib/dat/block.hpp
new file mode 100644
index 00000000..34e3620a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/block.hpp
@@ -0,0 +1,94 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Block {
+ public:
+ Block() : next_(0), prev_(0), first_phantom_(0), num_phantoms_(0) {}
+
+ // Blocks in the same level are stored in a doubly-linked list which is
+ // represented by the following next() and prev().
+ UInt32 next() const {
+ return next_ / BLOCK_SIZE;
+ }
+ UInt32 prev() const {
+ return prev_ / BLOCK_SIZE;
+ }
+
+ // A level indicates how easyily find_offset() can find a good offset in that
+ // block. It is easier in lower level blocks.
+ UInt32 level() const {
+ return next_ & BLOCK_MASK;
+ }
+ // A block level rises when find_offset() fails to find a good offset
+ // MAX_FAILURE_COUNT times in that block.
+ UInt32 failure_count() const {
+ return prev_ & BLOCK_MASK;
+ }
+
+ UInt32 first_phantom() const {
+ return first_phantom_;
+ }
+ UInt32 num_phantoms() const {
+ return num_phantoms_;
+ }
+
+ void set_next(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_BLOCK_ID);
+ next_ = (next_ & BLOCK_MASK) | (x * BLOCK_SIZE);
+ }
+ void set_prev(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_BLOCK_ID);
+ prev_ = (prev_ & BLOCK_MASK) | (x * BLOCK_SIZE);
+ }
+
+ void set_level(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_BLOCK_LEVEL);
+ GRN_DAT_DEBUG_THROW_IF(x > BLOCK_MASK);
+ next_ = (next_ & ~BLOCK_MASK) | x;
+ }
+ void set_failure_count(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_FAILURE_COUNT);
+ GRN_DAT_DEBUG_THROW_IF(x > BLOCK_MASK);
+ prev_ = (prev_ & ~BLOCK_MASK) | x;
+ }
+
+ void set_first_phantom(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x >= BLOCK_SIZE);
+ first_phantom_ = (UInt16)x;
+ }
+ void set_num_phantoms(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > BLOCK_SIZE);
+ num_phantoms_ = (UInt16)x;
+ }
+
+ private:
+ UInt32 next_;
+ UInt32 prev_;
+ UInt16 first_phantom_;
+ UInt16 num_phantoms_;
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/check.hpp b/storage/mroonga/vendor/groonga/lib/dat/check.hpp
new file mode 100644
index 00000000..f77148c6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/check.hpp
@@ -0,0 +1,149 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Check {
+ public:
+ Check() : value_(0) {}
+
+ bool operator==(const Check &rhs) const {
+ return value_ == rhs.value_;
+ }
+
+ // The most significant bit represents whether or not the node ID is used as
+ // an offset. Note that the MSB is independent of the other bits.
+ bool is_offset() const {
+ return (value_ & IS_OFFSET_FLAG) == IS_OFFSET_FLAG;
+ }
+
+ UInt32 except_is_offset() const {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ return value_ & ~IS_OFFSET_FLAG;
+ }
+
+ // A phantom node is a node that has never been used, and such a node is also
+ // called an empty element. Phantom nodes form a doubly linked list in each
+ // block, and the linked list is represented by next() and prev().
+ bool is_phantom() const {
+ return (value_ & IS_PHANTOM_FLAG) == IS_PHANTOM_FLAG;
+ }
+
+ UInt32 next() const {
+ GRN_DAT_DEBUG_THROW_IF(!is_phantom());
+ return (value_ >> NEXT_SHIFT) & BLOCK_MASK;
+ }
+ UInt32 prev() const {
+ GRN_DAT_DEBUG_THROW_IF(!is_phantom());
+ return (value_ >> PREV_SHIFT) & BLOCK_MASK;
+ }
+
+ // A label is attached to each non-phantom node. A label is represented by
+ // a byte except for a terminal label '\256'. Note that a phantom node always
+ // returns an invalid label with its phantom bit flag so as to reject invalid
+ // transitions.
+ UInt32 label() const {
+ return value_ & (IS_PHANTOM_FLAG | LABEL_MASK);
+ }
+
+ // A non-phantom node has the labels of the first child and the next sibling.
+ // Note that INVALID_LABEL is stored if the node has no child nodes or has
+ // no more siblings.
+ UInt32 child() const {
+ return (value_ >> CHILD_SHIFT) & LABEL_MASK;
+ }
+ UInt32 sibling() const {
+ return (value_ >> SIBLING_SHIFT) & LABEL_MASK;
+ }
+
+ void set_is_offset(bool x) {
+ if (x) {
+ GRN_DAT_DEBUG_THROW_IF(is_offset());
+ value_ |= IS_OFFSET_FLAG;
+ } else {
+ GRN_DAT_DEBUG_THROW_IF(!is_offset());
+ value_ &= ~IS_OFFSET_FLAG;
+ }
+ }
+
+ void set_except_is_offset(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ GRN_DAT_DEBUG_THROW_IF((x & IS_OFFSET_FLAG) == IS_OFFSET_FLAG);
+ value_ = (value_ & IS_OFFSET_FLAG) | x;
+ }
+
+ // To reject a transition to an incomplete node, set_is_phantom() invalidates
+ // its label and links when it becomes non-phantom.
+ void set_is_phantom(bool x) {
+ if (x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ value_ |= IS_PHANTOM_FLAG;
+ } else {
+ GRN_DAT_DEBUG_THROW_IF(!is_phantom());
+ value_ = (value_ & IS_OFFSET_FLAG) | (INVALID_LABEL << CHILD_SHIFT) |
+ (INVALID_LABEL << SIBLING_SHIFT) | INVALID_LABEL;
+ }
+ }
+
+ void set_next(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(!is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(x > BLOCK_MASK);
+ value_ = (value_ & ~(BLOCK_MASK << NEXT_SHIFT)) | (x << NEXT_SHIFT);
+ }
+ void set_prev(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(!is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(x > BLOCK_MASK);
+ value_ = (value_ & ~(BLOCK_MASK << PREV_SHIFT)) | (x << PREV_SHIFT);
+ }
+
+ void set_label(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_LABEL);
+ value_ = (value_ & ~LABEL_MASK) | x;
+ }
+
+ void set_child(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_LABEL);
+ value_ = (value_ & ~(LABEL_MASK << CHILD_SHIFT)) | (x << CHILD_SHIFT);
+ }
+ void set_sibling(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(label() > MAX_LABEL);
+ GRN_DAT_DEBUG_THROW_IF((sibling() != INVALID_LABEL) && (x == INVALID_LABEL));
+ value_ = (value_ & ~(LABEL_MASK << SIBLING_SHIFT)) | (x << SIBLING_SHIFT);
+ }
+
+ private:
+ UInt32 value_;
+
+ static const UInt32 IS_OFFSET_FLAG = 1U << 31;
+ static const UInt32 IS_PHANTOM_FLAG = 1U << 30;
+ static const UInt32 NEXT_SHIFT = 9;
+ static const UInt32 PREV_SHIFT = 18;
+ static const UInt32 CHILD_SHIFT = 9;
+ static const UInt32 SIBLING_SHIFT = 18;
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/cursor-factory.cpp b/storage/mroonga/vendor/groonga/lib/dat/cursor-factory.cpp
new file mode 100644
index 00000000..0e97e527
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/cursor-factory.cpp
@@ -0,0 +1,92 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "cursor-factory.hpp"
+#include "id-cursor.hpp"
+#include "key-cursor.hpp"
+#include "prefix-cursor.hpp"
+#include "predictive-cursor.hpp"
+
+#include <new>
+
+namespace grn {
+namespace dat {
+
+Cursor *CursorFactory::open(const Trie &trie,
+ const void *min_ptr, UInt32 min_length,
+ const void *max_ptr, UInt32 max_length,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags) {
+ const UInt32 cursor_type = flags & CURSOR_TYPE_MASK;
+ switch (cursor_type) {
+ case ID_RANGE_CURSOR: {
+ IdCursor *cursor = new (std::nothrow) IdCursor;
+ GRN_DAT_THROW_IF(MEMORY_ERROR, cursor == NULL);
+ try {
+ cursor->open(trie, String(min_ptr, min_length),
+ String(max_ptr, max_length), offset, limit, flags);
+ } catch (...) {
+ delete cursor;
+ throw;
+ }
+ return cursor;
+ }
+ case KEY_RANGE_CURSOR: {
+ KeyCursor *cursor = new (std::nothrow) KeyCursor;
+ GRN_DAT_THROW_IF(MEMORY_ERROR, cursor == NULL);
+ try {
+ cursor->open(trie, String(min_ptr, min_length),
+ String(max_ptr, max_length), offset, limit, flags);
+ } catch (...) {
+ delete cursor;
+ throw;
+ }
+ return cursor;
+ }
+ case PREFIX_CURSOR: {
+ PrefixCursor *cursor = new (std::nothrow) PrefixCursor;
+ GRN_DAT_THROW_IF(MEMORY_ERROR, cursor == NULL);
+ try {
+ cursor->open(trie, String(max_ptr, max_length), min_length,
+ offset, limit, flags);
+ } catch (...) {
+ delete cursor;
+ throw;
+ }
+ return cursor;
+ }
+ case PREDICTIVE_CURSOR: {
+ PredictiveCursor *cursor = new (std::nothrow) PredictiveCursor;
+ GRN_DAT_THROW_IF(MEMORY_ERROR, cursor == NULL);
+ try {
+ cursor->open(trie, String(min_ptr, min_length),
+ offset, limit, flags);
+ } catch (...) {
+ delete cursor;
+ throw;
+ }
+ return cursor;
+ }
+ default: {
+ GRN_DAT_THROW(PARAM_ERROR, "unknown cursor type");
+ }
+ }
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/cursor-factory.hpp b/storage/mroonga/vendor/groonga/lib/dat/cursor-factory.hpp
new file mode 100644
index 00000000..d48ab16d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/cursor-factory.hpp
@@ -0,0 +1,44 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "cursor.hpp"
+
+namespace grn {
+namespace dat {
+
+class Trie;
+
+class GRN_DAT_API CursorFactory {
+ public:
+ static Cursor *open(const Trie &trie,
+ const void *min_ptr, UInt32 min_length,
+ const void *max_ptr, UInt32 max_length,
+ UInt32 offset = 0,
+ UInt32 limit = MAX_UINT32,
+ UInt32 flags = 0);
+
+ private:
+ // Disallows copy and assignment.
+ CursorFactory(const CursorFactory &);
+ CursorFactory &operator=(const CursorFactory &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/cursor.hpp b/storage/mroonga/vendor/groonga/lib/dat/cursor.hpp
new file mode 100644
index 00000000..357b5250
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/cursor.hpp
@@ -0,0 +1,46 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "key.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Cursor {
+ public:
+ Cursor() {}
+ virtual ~Cursor() {}
+
+ virtual void close() = 0;
+
+ virtual const Key &next() = 0;
+
+ virtual UInt32 offset() const = 0;
+ virtual UInt32 limit() const = 0;
+ virtual UInt32 flags() const = 0;
+
+ private:
+ // Disallows copy and assignment.
+ Cursor(const Cursor &);
+ Cursor &operator=(const Cursor &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/dat.hpp b/storage/mroonga/vendor/groonga/lib/dat/dat.hpp
new file mode 100644
index 00000000..1afbd095
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/dat.hpp
@@ -0,0 +1,248 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifndef _MSC_VER
+# include <stddef.h>
+# include <stdint.h>
+#endif // _MSC_VER
+
+#include <cstddef>
+#include <exception>
+
+#ifdef _DEBUG
+# include <iostream>
+#endif // _DEBUG
+
+#ifndef GRN_DAT_API
+# ifdef WIN32
+# ifdef GRN_DAT_EXPORT
+# define GRN_DAT_API __declspec(dllexport)
+# else // GRN_DAT_EXPORT
+# define GRN_DAT_API __declspec(dllimport)
+# endif // GRN_DAT_EXPORT
+# else // WIN32
+# define GRN_DAT_API
+# endif // WIN32
+#endif // GRN_DAT_API
+
+#ifdef WIN32
+# define grn_memcpy(dest, src, n) ::memcpy_s((dest), (n), (src), (n))
+#else // WIN32
+# define grn_memcpy(dest, src, n) std::memcpy((dest), (src), (n))
+#endif // WIN32
+
+namespace grn {
+namespace dat {
+
+#ifdef _MSC_VER
+typedef unsigned __int8 UInt8;
+typedef unsigned __int16 UInt16;
+typedef unsigned __int32 UInt32;
+typedef unsigned __int64 UInt64;
+#else // _MSC_VER
+typedef ::uint8_t UInt8;
+typedef ::uint16_t UInt16;
+typedef ::uint32_t UInt32;
+typedef ::uint64_t UInt64;
+#endif // _MSC_VER
+
+const UInt8 MAX_UINT8 = static_cast<UInt8>(0xFFU);
+const UInt16 MAX_UINT16 = static_cast<UInt16>(0xFFFFU);
+const UInt32 MAX_UINT32 = static_cast<UInt32>(0xFFFFFFFFU);
+const UInt64 MAX_UINT64 = static_cast<UInt64>(0xFFFFFFFFFFFFFFFFULL);
+
+// If a key is a prefix of another key, such a key is associated with a special
+// terminal node which has TERMINAL_LABEL.
+const UInt16 TERMINAL_LABEL = 0x100;
+const UInt16 MIN_LABEL = '\0';
+const UInt16 MAX_LABEL = TERMINAL_LABEL;
+const UInt32 INVALID_LABEL = 0x1FF;
+const UInt32 LABEL_MASK = 0x1FF;
+
+// The MSB of BASE is used to represent whether the node is a linker node or
+// not and the other 31 bits represent the offset to its child nodes. So, the
+// number of nodes is limited to 2^31.
+const UInt32 ROOT_NODE_ID = 0;
+const UInt32 MAX_NODE_ID = 0x7FFFFFFF;
+const UInt32 MAX_NUM_NODES = MAX_NODE_ID + 1;
+const UInt32 INVALID_NODE_ID = MAX_NODE_ID + 1;
+
+// 0 is reserved for non-linker leaf nodes. For example, the root node of an
+// initial double-array is a non-linker leaf node.
+const UInt32 MAX_OFFSET = MAX_NODE_ID;
+const UInt32 INVALID_OFFSET = 0;
+
+// Phantom nodes are managed in each block because siblings are always put in
+// the same block.
+const UInt32 BLOCK_SIZE = 0x200;
+const UInt32 BLOCK_MASK = 0x1FF;
+const UInt32 MAX_BLOCK_ID = MAX_NODE_ID / BLOCK_SIZE;
+const UInt32 MAX_NUM_BLOCKS = MAX_BLOCK_ID + 1;
+
+// Blocks are divided by their levels, which indicate how easily update
+// operations can find a good offset in them. The level of a block rises when
+// find_offset() fails in that block many times. MAX_FAILURE_COUNT is the
+// threshold. Also, in order to limit the time cost, find_offset() scans at
+// most MAX_BLOCK_COUNT blocks.
+// Larger parameters bring more chances of finding good offsets but it leads to
+// more node renumberings, which are costly operations, and thus results in
+// a degradation of space/time efficiencies.
+const UInt32 MAX_FAILURE_COUNT = 4;
+const UInt32 MAX_BLOCK_COUNT = 16;
+const UInt32 MAX_BLOCK_LEVEL = 5;
+
+// Blocks in the same level compose a doubly linked list. The entry block of
+// a linked list is called a leader. INVALID_LEADER means that a linked list is
+// empty and there exists no leader.
+const UInt32 INVALID_LEADER = 0x7FFFFFFF;
+
+const UInt32 MIN_KEY_ID = 1;
+const UInt32 MAX_KEY_ID = MAX_NODE_ID;
+const UInt32 INVALID_KEY_ID = 0;
+
+// A key length is represented as a 12-bit unsigned integer in Key.
+// A key ID is represented as a 28-bit unsigned integer in Key.
+const UInt32 MAX_KEY_LENGTH = (1U << 12) - 1;
+const UInt32 MAX_NUM_KEYS = (1U << 28) - 1;
+
+const UInt64 MIN_FILE_SIZE = 1 << 16;
+const UInt64 DEFAULT_FILE_SIZE = 1 << 20;
+const UInt64 MAX_FILE_SIZE = (UInt64)1 << 40;
+const double DEFAULT_NUM_NODES_PER_KEY = 4.0;
+const double MAX_NUM_NODES_PER_KEY = 16.0;
+const double DEFAULT_AVERAGE_KEY_LENGTH = 16.0;
+const UInt32 MAX_KEY_BUF_SIZE = 0x80000000U;
+const UInt32 MAX_TOTAL_KEY_LENGTH = 0xFFFFFFFFU;
+
+const UInt32 ID_RANGE_CURSOR = 0x00001;
+const UInt32 KEY_RANGE_CURSOR = 0x00002;
+const UInt32 PREFIX_CURSOR = 0x00004;
+const UInt32 PREDICTIVE_CURSOR = 0x00008;
+const UInt32 CURSOR_TYPE_MASK = 0x000FF;
+
+const UInt32 ASCENDING_CURSOR = 0x00100;
+const UInt32 DESCENDING_CURSOR = 0x00200;
+const UInt32 CURSOR_ORDER_MASK = 0x00F00;
+
+const UInt32 EXCEPT_LOWER_BOUND = 0x01000;
+const UInt32 EXCEPT_UPPER_BOUND = 0x02000;
+const UInt32 EXCEPT_EXACT_MATCH = 0x04000;
+const UInt32 CURSOR_OPTIONS_MASK = 0xFF000;
+
+const UInt32 REMOVING_FLAG = 1U << 0;
+const UInt32 INSERTING_FLAG = 1U << 1;
+const UInt32 UPDATING_FLAG = 1U << 2;
+const UInt32 CHANGING_MASK = REMOVING_FLAG | INSERTING_FLAG | UPDATING_FLAG;
+
+const UInt32 MKQ_SORT_THRESHOLD = 10;
+
+enum ErrorCode {
+ PARAM_ERROR = -1,
+ IO_ERROR = -2,
+ FORMAT_ERROR = -3,
+ MEMORY_ERROR = -4,
+ SIZE_ERROR = -5,
+ UNEXPECTED_ERROR = -6,
+ STATUS_ERROR = -7
+};
+
+class Exception : public std::exception {
+ public:
+ Exception() throw()
+ : std::exception(),
+ file_(""),
+ line_(-1),
+ what_("") {}
+ Exception(const char *file, int line, const char *what) throw()
+ : std::exception(),
+ file_(file),
+ line_(line),
+ what_((what != NULL) ? what : "") {}
+ Exception(const Exception &ex) throw()
+ : std::exception(ex),
+ file_(ex.file_),
+ line_(ex.line_),
+ what_(ex.what_) {}
+ virtual ~Exception() throw() {}
+
+ virtual ErrorCode code() const throw() = 0;
+ virtual const char *file() const throw() {
+ return file_;
+ }
+ virtual int line() const throw() {
+ return line_;
+ }
+ virtual const char *what() const throw() {
+ return what_;
+ }
+
+ private:
+ const char *file_;
+ int line_;
+ const char *what_;
+};
+
+template <ErrorCode T>
+class Error : public Exception {
+ public:
+ Error() throw()
+ : Exception() {}
+ Error(const char *file, int line, const char *what) throw()
+ : Exception(file, line, what) {}
+ Error(const Error &ex) throw()
+ : Exception(ex) {}
+ virtual ~Error() throw() {}
+
+ virtual ErrorCode code() const throw() {
+ return T;
+ }
+};
+
+typedef Error<PARAM_ERROR> ParamError;
+typedef Error<IO_ERROR> IOError;
+typedef Error<FORMAT_ERROR> FormatError;
+typedef Error<MEMORY_ERROR> MemoryError;
+typedef Error<SIZE_ERROR> SizeError;
+typedef Error<UNEXPECTED_ERROR> UnexpectedError;
+typedef Error<STATUS_ERROR> StatusError;
+
+#define GRN_DAT_INT_TO_STR(value) #value
+#define GRN_DAT_LINE_TO_STR(line) GRN_DAT_INT_TO_STR(line)
+#define GRN_DAT_LINE_STR GRN_DAT_LINE_TO_STR(__LINE__)
+
+#define GRN_DAT_THROW(code, msg)\
+ (throw grn::dat::Error<code>(__FILE__, __LINE__,\
+ __FILE__ ":" GRN_DAT_LINE_STR ": " #code ": " msg))
+#define GRN_DAT_THROW_IF(code, cond)\
+ (void)((!(cond)) || (GRN_DAT_THROW(code, #cond), 0))
+
+#ifdef _DEBUG
+ #define GRN_DAT_DEBUG_THROW_IF(cond)\
+ GRN_DAT_THROW_IF(grn::dat::UNEXPECTED_ERROR, cond)
+ #define GRN_DAT_DEBUG_LOG(var)\
+ (std::clog << __FILE__ ":" GRN_DAT_LINE_STR ": " #var ": "\
+ << (var) << std::endl)
+#else // _DEBUG
+ #define GRN_DAT_DEBUG_THROW_IF(cond)
+ #define GRN_DAT_DEBUG_LOG(var)
+#endif // _DEBUG
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/entry.hpp b/storage/mroonga/vendor/groonga/lib/dat/entry.hpp
new file mode 100644
index 00000000..ecb9b53e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/entry.hpp
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+// The most significant bit represents whether or not the entry is valid.
+// A valid entry stores the position of its associated key and an invalid entry
+// stores the index of the next invalid entry.
+class GRN_DAT_API Entry {
+ public:
+ Entry() : value_(0) {}
+
+ bool is_valid() const {
+ return (value_ & IS_VALID_FLAG) == IS_VALID_FLAG;
+ }
+ UInt32 key_pos() const {
+ GRN_DAT_DEBUG_THROW_IF(!is_valid());
+ return value_ & ~IS_VALID_FLAG;
+ }
+ UInt32 next() const {
+ GRN_DAT_DEBUG_THROW_IF(is_valid());
+ return value_;
+ }
+
+ void set_key_pos(UInt32 x) {
+ value_ = IS_VALID_FLAG | x;
+ }
+ void set_next(UInt32 x) {
+ value_ = x;
+ }
+
+ private:
+ UInt32 value_;
+
+ static const UInt32 IS_VALID_FLAG = 0x80000000U;
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/file-impl.cpp b/storage/mroonga/vendor/groonga/lib/dat/file-impl.cpp
new file mode 100644
index 00000000..7032eff3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/file-impl.cpp
@@ -0,0 +1,279 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "file-impl.hpp"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# ifdef min
+# undef min
+# endif // min
+# ifdef max
+# undef max
+# endif // max
+#else // WIN32
+# include <fcntl.h>
+# include <sys/mman.h>
+# include <unistd.h>
+#endif // WIN32
+
+#include <algorithm>
+#include <limits>
+
+/* Must be the same value as GRN_OPEN_CREATE_MODE */
+#ifdef WIN32
+# define GRN_IO_FILE_CREATE_MODE (GENERIC_READ | GENERIC_WRITE)
+#else /* WIN32 */
+# define GRN_IO_FILE_CREATE_MODE 0640
+#endif /* WIN32 */
+
+namespace grn {
+namespace dat {
+
+#ifdef WIN32
+
+FileImpl::FileImpl()
+ : ptr_(NULL),
+ size_(0),
+ file_(INVALID_HANDLE_VALUE),
+ map_(INVALID_HANDLE_VALUE),
+ addr_(NULL) {}
+
+FileImpl::~FileImpl() {
+ if (addr_ != NULL) {
+ ::UnmapViewOfFile(addr_);
+ }
+
+ if (map_ != INVALID_HANDLE_VALUE) {
+ ::CloseHandle(map_);
+ }
+
+ if (file_ != INVALID_HANDLE_VALUE) {
+ ::CloseHandle(file_);
+ }
+}
+
+#else // WIN32
+
+FileImpl::FileImpl()
+ : ptr_(NULL),
+ size_(0),
+ fd_(-1),
+ addr_(MAP_FAILED),
+ length_(0) {}
+
+FileImpl::~FileImpl() {
+ if (addr_ != MAP_FAILED) {
+ ::munmap(addr_, length_);
+ }
+
+ if (fd_ != -1) {
+ ::close(fd_);
+ }
+}
+
+#endif // WIN32
+
+void FileImpl::create(const char *path, UInt64 size) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, size == 0);
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ size > static_cast<UInt64>(std::numeric_limits< ::size_t>::max()));
+
+ FileImpl new_impl;
+ new_impl.create_(path, size);
+ new_impl.swap(this);
+}
+
+void FileImpl::open(const char *path) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, path == NULL);
+ GRN_DAT_THROW_IF(PARAM_ERROR, path[0] == '\0');
+
+ FileImpl new_impl;
+ new_impl.open_(path);
+ new_impl.swap(this);
+}
+
+void FileImpl::close() {
+ FileImpl new_impl;
+ new_impl.swap(this);
+}
+
+#ifdef WIN32
+
+void FileImpl::swap(FileImpl *rhs) {
+ std::swap(ptr_, rhs->ptr_);
+ std::swap(size_, rhs->size_);
+ std::swap(file_, rhs->file_);
+ std::swap(map_, rhs->map_);
+ std::swap(addr_, rhs->addr_);
+}
+
+void FileImpl::flush() {
+ if (!addr_) {
+ return;
+ }
+
+ BOOL succeeded = ::FlushViewOfFile(addr_, static_cast<SIZE_T>(size_));
+ GRN_DAT_THROW_IF(IO_ERROR, !succeeded);
+
+ SYSTEMTIME system_time;
+ GetSystemTime(&system_time);
+ FILETIME file_time;
+ succeeded = SystemTimeToFileTime(&system_time, &file_time);
+ GRN_DAT_THROW_IF(IO_ERROR, !succeeded);
+
+ succeeded = SetFileTime(file_, NULL, NULL, &file_time);
+ GRN_DAT_THROW_IF(IO_ERROR, !succeeded);
+}
+
+void FileImpl::create_(const char *path, UInt64 size) {
+ if ((path != NULL) && (path[0] != '\0')) {
+ file_ = ::CreateFileA(path, GRN_IO_FILE_CREATE_MODE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ GRN_DAT_THROW_IF(IO_ERROR, file_ == INVALID_HANDLE_VALUE);
+
+ const LONG size_low = static_cast<LONG>(size & 0xFFFFFFFFU);
+ LONG size_high = static_cast<LONG>(size >> 32);
+ const DWORD file_pos = ::SetFilePointer(file_, size_low, &size_high,
+ FILE_BEGIN);
+ GRN_DAT_THROW_IF(IO_ERROR, (file_pos == INVALID_SET_FILE_POINTER) &&
+ (::GetLastError() != 0));
+ GRN_DAT_THROW_IF(IO_ERROR, ::SetEndOfFile(file_) == 0);
+
+ map_ = ::CreateFileMapping(file_, NULL, PAGE_READWRITE, 0, 0, NULL);
+ GRN_DAT_THROW_IF(IO_ERROR, map_ == INVALID_HANDLE_VALUE);
+ } else {
+ const DWORD size_low = static_cast<DWORD>(size & 0xFFFFFFFFU);
+ const DWORD size_high = static_cast<DWORD>(size >> 32);
+
+ map_ = ::CreateFileMapping(file_, NULL, PAGE_READWRITE,
+ size_high, size_low, NULL);
+ GRN_DAT_THROW_IF(IO_ERROR, map_ == INVALID_HANDLE_VALUE);
+ }
+
+ addr_ = ::MapViewOfFile(map_, FILE_MAP_WRITE, 0, 0, 0);
+ GRN_DAT_THROW_IF(IO_ERROR, addr_ == NULL);
+
+ ptr_ = addr_;
+ size_ = static_cast< ::size_t>(size);
+}
+
+void FileImpl::open_(const char *path) {
+#ifdef _MSC_VER
+ struct __stat64 st;
+ GRN_DAT_THROW_IF(IO_ERROR, ::_stat64(path, &st) == -1);
+#else // _MSC_VER
+ struct _stat st;
+ GRN_DAT_THROW_IF(IO_ERROR, ::_stat(path, &st) == -1);
+#endif // _MSC_VER
+ GRN_DAT_THROW_IF(IO_ERROR, st.st_size == 0);
+ GRN_DAT_THROW_IF(IO_ERROR,
+ static_cast<UInt64>(st.st_size) > std::numeric_limits< ::size_t>::max());
+
+ file_ = ::CreateFileA(path, GRN_IO_FILE_CREATE_MODE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ GRN_DAT_THROW_IF(IO_ERROR, file_ == NULL);
+
+ map_ = ::CreateFileMapping(file_, NULL, PAGE_READWRITE, 0, 0, NULL);
+ GRN_DAT_THROW_IF(IO_ERROR, map_ == NULL);
+
+ addr_ = ::MapViewOfFile(map_, FILE_MAP_WRITE, 0, 0, 0);
+ GRN_DAT_THROW_IF(IO_ERROR, addr_ == NULL);
+
+ ptr_ = addr_;
+ size_ = static_cast< ::size_t>(st.st_size);
+}
+
+#else // WIN32
+
+void FileImpl::swap(FileImpl *rhs) {
+ std::swap(ptr_, rhs->ptr_);
+ std::swap(size_, rhs->size_);
+ std::swap(fd_, rhs->fd_);
+ std::swap(addr_, rhs->addr_);
+ std::swap(length_, rhs->length_);
+}
+
+void FileImpl::flush() {
+ if (!addr_) {
+ return;
+ }
+
+ int result = ::msync(addr_, length_, MS_SYNC);
+ GRN_DAT_THROW_IF(IO_ERROR, result != 0);
+}
+
+void FileImpl::create_(const char *path, UInt64 size) {
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ size > static_cast<UInt64>(std::numeric_limits< ::off_t>::max()));
+
+ if ((path != NULL) && (path[0] != '\0')) {
+ fd_ = ::open(path, O_RDWR | O_CREAT | O_TRUNC, GRN_IO_FILE_CREATE_MODE);
+ GRN_DAT_THROW_IF(IO_ERROR, fd_ == -1);
+
+ const ::off_t file_size = static_cast< ::off_t>(size);
+ GRN_DAT_THROW_IF(IO_ERROR, ::ftruncate(fd_, file_size) == -1);
+ }
+
+#ifdef MAP_ANONYMOUS
+ const int flags = (fd_ == -1) ? (MAP_PRIVATE | MAP_ANONYMOUS) : MAP_SHARED;
+#else // MAP_ANONYMOUS
+ const int flags = (fd_ == -1) ? (MAP_PRIVATE | MAP_ANON) : MAP_SHARED;
+#endif // MAP_ANONYMOUS
+
+ length_ = static_cast< ::size_t>(size);
+#ifdef USE_MAP_HUGETLB
+ addr_ = ::mmap(NULL, length_, PROT_READ | PROT_WRITE,
+ flags | MAP_HUGETLB, fd_, 0);
+#endif // USE_MAP_HUGETLB
+ if (addr_ == MAP_FAILED) {
+ addr_ = ::mmap(NULL, length_, PROT_READ | PROT_WRITE, flags, fd_, 0);
+ GRN_DAT_THROW_IF(IO_ERROR, addr_ == MAP_FAILED);
+ }
+
+ ptr_ = addr_;
+ size_ = length_;
+}
+
+void FileImpl::open_(const char *path) {
+ struct stat st;
+ GRN_DAT_THROW_IF(IO_ERROR, ::stat(path, &st) == -1);
+ GRN_DAT_THROW_IF(IO_ERROR, (st.st_mode & S_IFMT) != S_IFREG);
+ GRN_DAT_THROW_IF(IO_ERROR, st.st_size == 0);
+ GRN_DAT_THROW_IF(IO_ERROR,
+ static_cast<UInt64>(st.st_size) > std::numeric_limits< ::size_t>::max());
+
+ fd_ = ::open(path, O_RDWR);
+ GRN_DAT_THROW_IF(IO_ERROR, fd_ == -1);
+
+ length_ = static_cast<std::size_t>(st.st_size);
+ addr_ = ::mmap(NULL, length_, PROT_READ | PROT_WRITE, MAP_SHARED, fd_, 0);
+ GRN_DAT_THROW_IF(IO_ERROR, addr_ == MAP_FAILED);
+
+ ptr_ = addr_;
+ size_ = length_;
+}
+
+#endif // WIN32
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/file-impl.hpp b/storage/mroonga/vendor/groonga/lib/dat/file-impl.hpp
new file mode 100644
index 00000000..7b9c8c76
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/file-impl.hpp
@@ -0,0 +1,73 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef WIN32
+# include <windows.h>
+#endif // WIN32
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+class FileImpl {
+ public:
+ FileImpl();
+ ~FileImpl();
+
+ void create(const char *path, UInt64 size);
+ void open(const char *path);
+ void close();
+
+ void *ptr() const {
+ return ptr_;
+ }
+ UInt64 size() const {
+ return size_;
+ }
+
+ void swap(FileImpl *rhs);
+
+ void flush();
+
+ private:
+ void *ptr_;
+ UInt64 size_;
+
+#ifdef WIN32
+ HANDLE file_;
+ HANDLE map_;
+ LPVOID addr_;
+#else // WIN32
+ int fd_;
+ void *addr_;
+ ::size_t length_;
+#endif // WIN32
+
+ void create_(const char *path, UInt64 size);
+ void open_(const char *path);
+
+ // Disallows copy and assignment.
+ FileImpl(const FileImpl &);
+ FileImpl &operator=(const FileImpl &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/file.cpp b/storage/mroonga/vendor/groonga/lib/dat/file.cpp
new file mode 100644
index 00000000..84f2a1fb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/file.cpp
@@ -0,0 +1,73 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "file.hpp"
+#include "file-impl.hpp"
+
+#include <new>
+
+namespace grn {
+namespace dat {
+
+File::File() : impl_(NULL) {}
+
+File::~File() {
+ delete impl_;
+}
+
+void File::create(const char *path, UInt64 size) {
+ File new_file;
+ new_file.impl_ = new (std::nothrow) FileImpl;
+ GRN_DAT_THROW_IF(MEMORY_ERROR, new_file.impl_ == NULL);
+ new_file.impl_->create(path, size);
+ new_file.swap(this);
+}
+
+void File::open(const char *path) {
+ File new_file;
+ new_file.impl_ = new (std::nothrow) FileImpl;
+ GRN_DAT_THROW_IF(MEMORY_ERROR, new_file.impl_ == NULL);
+ new_file.impl_->open(path);
+ new_file.swap(this);
+}
+
+void File::close() {
+ File().swap(this);
+}
+
+void *File::ptr() const {
+ return (impl_ != NULL) ? impl_->ptr() : NULL;
+}
+
+UInt64 File::size() const {
+ return (impl_ != NULL) ? impl_->size() : 0;
+}
+
+void File::swap(File *rhs) {
+ FileImpl * const temp = impl_;
+ impl_ = rhs->impl_;
+ rhs->impl_ = temp;
+}
+
+void File::flush() {
+ if (impl_) {
+ impl_->flush();
+ }
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/file.hpp b/storage/mroonga/vendor/groonga/lib/dat/file.hpp
new file mode 100644
index 00000000..722b93dd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/file.hpp
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+// This implementation class hides environment dependent codes required for
+// memory-mapped I/O.
+class FileImpl;
+
+class GRN_DAT_API File {
+ public:
+ File();
+ ~File();
+
+ // This function creates a file and maps the entire file to a certain range
+ // of the address space. Note that a file is truncated if exists.
+ void create(const char *path, UInt64 size);
+
+ // This function opens a file and maps the entire file to a certain range of
+ // the address space.
+ void open(const char *path);
+ void close();
+
+ void *ptr() const;
+ UInt64 size() const;
+
+ void swap(File *rhs);
+
+ void flush();
+
+ private:
+ FileImpl *impl_;
+
+ // Disallows copy and assignment.
+ File(const File &);
+ File &operator=(const File &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/header.hpp b/storage/mroonga/vendor/groonga/lib/dat/header.hpp
new file mode 100644
index 00000000..dbbb1efd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/header.hpp
@@ -0,0 +1,179 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Header {
+ public:
+ Header()
+ : file_size_(0),
+ total_key_length_(0),
+ next_key_id_(grn::dat::MIN_KEY_ID),
+ max_key_id_(0),
+ num_keys_(0),
+ max_num_keys_(0),
+ num_phantoms_(0),
+ num_zombies_(0),
+ num_blocks_(0),
+ max_num_blocks_(0),
+ next_key_pos_(0),
+ key_buf_size_(0),
+ status_flags_(0) {
+ for (UInt32 i = 0; i <= MAX_BLOCK_LEVEL; ++i) {
+ leaders_[i] = INVALID_LEADER;
+ }
+ for (UInt32 i = 0; i < (sizeof(reserved_) / sizeof(*reserved_)); ++i) {
+ reserved_[i] = 0;
+ }
+ }
+
+ UInt64 file_size() const {
+ return file_size_;
+ }
+ UInt32 total_key_length() const {
+ return total_key_length_;
+ }
+ UInt32 min_key_id() const {
+ return MIN_KEY_ID;
+ }
+ UInt32 next_key_id() const {
+ return next_key_id_;
+ }
+ UInt32 max_key_id() const {
+ return max_key_id_;
+ }
+ UInt32 num_keys() const {
+ return num_keys_;
+ }
+ UInt32 max_num_keys() const {
+ return max_num_keys_;
+ }
+ UInt32 num_nodes() const {
+ return num_blocks() * BLOCK_SIZE;
+ }
+ UInt32 num_phantoms() const {
+ return num_phantoms_;
+ }
+ UInt32 num_zombies() const {
+ return num_zombies_;
+ }
+ UInt32 max_num_nodes() const {
+ return max_num_blocks() * BLOCK_SIZE;
+ }
+ UInt32 num_blocks() const {
+ return num_blocks_;
+ }
+ UInt32 max_num_blocks() const {
+ return max_num_blocks_;
+ }
+ UInt32 next_key_pos() const {
+ return next_key_pos_;
+ }
+ UInt32 key_buf_size() const {
+ return key_buf_size_;
+ }
+ UInt32 status_flags() const {
+ return status_flags_;
+ }
+ UInt32 ith_leader(UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i > MAX_BLOCK_LEVEL);
+ return leaders_[i];
+ }
+
+ void set_file_size(UInt64 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_FILE_SIZE);
+ file_size_ = x;
+ }
+ void set_total_key_length(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_TOTAL_KEY_LENGTH);
+ total_key_length_ = x;
+ }
+ void set_next_key_id(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF((x - 1) > MAX_KEY_ID);
+ next_key_id_ = x;
+ }
+ void set_max_key_id(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_KEY_ID);
+ max_key_id_ = x;
+ }
+ void set_num_keys(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_NUM_KEYS);
+ num_keys_ = x;
+ }
+ void set_max_num_keys(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_NUM_KEYS);
+ max_num_keys_ = x;
+ }
+ void set_num_phantoms(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > max_num_nodes());
+ num_phantoms_ = x;
+ }
+ void set_num_zombies(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > max_num_nodes());
+ num_zombies_ = x;
+ }
+ void set_num_blocks(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > max_num_blocks());
+ num_blocks_ = x;
+ }
+ void set_max_num_blocks(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_NUM_BLOCKS);
+ max_num_blocks_ = x;
+ }
+ void set_next_key_pos(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > key_buf_size());
+ next_key_pos_ = x;
+ }
+ void set_key_buf_size(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(x > MAX_KEY_BUF_SIZE);
+ key_buf_size_ = x;
+ }
+ void set_status_flags(UInt32 x) {
+ status_flags_ = x;
+ }
+ void set_ith_leader(UInt32 i, UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(i > MAX_BLOCK_LEVEL);
+ GRN_DAT_DEBUG_THROW_IF((x != INVALID_LEADER) && (x >= num_blocks()));
+ leaders_[i] = x;
+ }
+
+ private:
+ UInt64 file_size_;
+ UInt32 total_key_length_;
+ UInt32 next_key_id_;
+ UInt32 max_key_id_;
+ UInt32 num_keys_;
+ UInt32 max_num_keys_;
+ UInt32 num_phantoms_;
+ UInt32 num_zombies_;
+ UInt32 num_blocks_;
+ UInt32 max_num_blocks_;
+ UInt32 next_key_pos_;
+ UInt32 key_buf_size_;
+ UInt32 leaders_[MAX_BLOCK_LEVEL + 1];
+ UInt32 status_flags_;
+ UInt32 reserved_[12];
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/id-cursor.cpp b/storage/mroonga/vendor/groonga/lib/dat/id-cursor.cpp
new file mode 100644
index 00000000..de969839
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/id-cursor.cpp
@@ -0,0 +1,184 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "id-cursor.hpp"
+
+#include <algorithm>
+
+#include "trie.hpp"
+
+namespace grn {
+namespace dat {
+
+IdCursor::IdCursor()
+ : trie_(NULL),
+ offset_(0),
+ limit_(MAX_UINT32),
+ flags_(ID_RANGE_CURSOR),
+ cur_(INVALID_KEY_ID),
+ end_(INVALID_KEY_ID),
+ count_(0) {}
+
+IdCursor::~IdCursor() {}
+
+void IdCursor::open(const Trie &trie,
+ const String &min_str,
+ const String &max_str,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags) {
+ UInt32 min_id = INVALID_KEY_ID;
+ if (min_str.ptr() != NULL) {
+ UInt32 key_pos;
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ !trie.search(min_str.ptr(), min_str.length(), &key_pos));
+ min_id = trie.get_key(key_pos).id();
+ }
+
+ UInt32 max_id = INVALID_KEY_ID;
+ if (max_str.ptr() != NULL) {
+ UInt32 key_pos;
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ !trie.search(max_str.ptr(), max_str.length(), &key_pos));
+ max_id = trie.get_key(key_pos).id();
+ }
+
+ open(trie, min_id, max_id, offset, limit, flags);
+}
+
+void IdCursor::open(const Trie &trie,
+ UInt32 min_id,
+ UInt32 max_id,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags) {
+ flags = fix_flags(flags);
+
+ IdCursor new_cursor(trie, offset, limit, flags);
+ new_cursor.init(min_id, max_id);
+ new_cursor.swap(this);
+}
+
+void IdCursor::close() {
+ IdCursor new_cursor;
+ new_cursor.swap(this);
+}
+
+const Key &IdCursor::next() {
+ if (count_ >= limit_) {
+ return Key::invalid_key();
+ }
+ while (cur_ != end_) {
+ const Key &key = trie_->ith_key(cur_);
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ ++cur_;
+ } else {
+ --cur_;
+ }
+ if (key.is_valid()) {
+ ++count_;
+ return key;
+ }
+ }
+ return Key::invalid_key();
+}
+
+IdCursor::IdCursor(const Trie &trie,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags)
+ : trie_(&trie),
+ offset_(offset),
+ limit_(limit),
+ flags_(flags),
+ cur_(INVALID_KEY_ID),
+ end_(INVALID_KEY_ID),
+ count_(0) {}
+
+UInt32 IdCursor::fix_flags(UInt32 flags) const {
+ const UInt32 cursor_type = flags & CURSOR_TYPE_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_type != 0) &&
+ (cursor_type != ID_RANGE_CURSOR));
+ flags |= ID_RANGE_CURSOR;
+
+ const UInt32 cursor_order = flags & CURSOR_ORDER_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_order != 0) &&
+ (cursor_order != ASCENDING_CURSOR) &&
+ (cursor_order != DESCENDING_CURSOR));
+ if (cursor_order == 0) {
+ flags |= ASCENDING_CURSOR;
+ }
+
+ const UInt32 cursor_options = flags & CURSOR_OPTIONS_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ cursor_options & ~(EXCEPT_LOWER_BOUND | EXCEPT_UPPER_BOUND));
+
+ return flags;
+}
+
+void IdCursor::init(UInt32 min_id, UInt32 max_id) {
+ if (min_id == INVALID_KEY_ID) {
+ min_id = trie_->min_key_id();
+ } else if ((flags_ & EXCEPT_LOWER_BOUND) == EXCEPT_LOWER_BOUND) {
+ ++min_id;
+ }
+
+ if (max_id == INVALID_KEY_ID) {
+ max_id = trie_->max_key_id();
+ } else if ((flags_ & EXCEPT_UPPER_BOUND) == EXCEPT_UPPER_BOUND) {
+ --max_id;
+ }
+
+ if ((max_id < min_id) || ((max_id - min_id) < offset_)) {
+ return;
+ }
+
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ cur_ = min_id;
+ end_ = max_id + 1;
+ for (UInt32 i = 0; (i < offset_) && (cur_ != end_); ++i) {
+ while (cur_ != end_) {
+ if (trie_->ith_key(cur_++).is_valid()) {
+ break;
+ }
+ }
+ }
+ } else {
+ cur_ = max_id;
+ end_ = min_id - 1;
+ for (UInt32 i = 0; (i < offset_) && (cur_ != end_); ++i) {
+ while (cur_ != end_) {
+ if (trie_->ith_key(cur_--).is_valid()) {
+ break;
+ }
+ }
+ }
+ }
+}
+
+void IdCursor::swap(IdCursor *cursor) {
+ std::swap(trie_, cursor->trie_);
+ std::swap(offset_, cursor->offset_);
+ std::swap(limit_, cursor->limit_);
+ std::swap(flags_, cursor->flags_);
+ std::swap(cur_, cursor->cur_);
+ std::swap(end_, cursor->end_);
+ std::swap(count_, cursor->count_);
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/id-cursor.hpp b/storage/mroonga/vendor/groonga/lib/dat/id-cursor.hpp
new file mode 100644
index 00000000..60953fae
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/id-cursor.hpp
@@ -0,0 +1,83 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "cursor.hpp"
+
+namespace grn {
+namespace dat {
+
+class Trie;
+
+class GRN_DAT_API IdCursor : public Cursor {
+ public:
+ IdCursor();
+ ~IdCursor();
+
+ void open(const Trie &trie,
+ const String &min_str,
+ const String &max_str,
+ UInt32 offset = 0,
+ UInt32 limit = MAX_UINT32,
+ UInt32 flags = 0);
+
+ void open(const Trie &trie,
+ UInt32 min_id,
+ UInt32 max_id,
+ UInt32 offset = 0,
+ UInt32 limit = MAX_UINT32,
+ UInt32 flags = 0);
+
+ void close();
+
+ const Key &next();
+
+ UInt32 offset() const {
+ return offset_;
+ }
+ UInt32 limit() const {
+ return limit_;
+ }
+ UInt32 flags() const {
+ return flags_;
+ }
+
+ private:
+ const Trie *trie_;
+ UInt32 offset_;
+ UInt32 limit_;
+ UInt32 flags_;
+
+ UInt32 cur_;
+ UInt32 end_;
+ UInt32 count_;
+
+ IdCursor(const Trie &trie, UInt32 offset, UInt32 limit, UInt32 flags);
+
+ UInt32 fix_flags(UInt32 flags) const;
+ void init(UInt32 min_id, UInt32 max_id);
+ void swap(IdCursor *cursor);
+
+ // Disallows copy and assignment.
+ IdCursor(const IdCursor &);
+ IdCursor &operator=(const IdCursor &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/key-cursor.cpp b/storage/mroonga/vendor/groonga/lib/dat/key-cursor.cpp
new file mode 100644
index 00000000..2ce04fee
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/key-cursor.cpp
@@ -0,0 +1,349 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "key-cursor.hpp"
+
+#include <algorithm>
+#include <cstring>
+
+#include "trie.hpp"
+
+namespace grn {
+namespace dat {
+
+KeyCursor::KeyCursor()
+ : trie_(NULL),
+ offset_(0),
+ limit_(MAX_UINT32),
+ flags_(KEY_RANGE_CURSOR),
+ buf_(),
+ count_(0),
+ max_count_(0),
+ finished_(false),
+ end_buf_(NULL),
+ end_str_() {}
+
+KeyCursor::~KeyCursor() {
+ if (end_buf_ != NULL) {
+ delete [] end_buf_;
+ }
+}
+
+void KeyCursor::open(const Trie &trie,
+ const String &min_str,
+ const String &max_str,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags) {
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ (min_str.ptr() == NULL) && (min_str.length() != 0));
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ (max_str.ptr() == NULL) && (max_str.length() != 0));
+
+ flags = fix_flags(flags);
+ KeyCursor new_cursor(trie, offset, limit, flags);
+ new_cursor.init(min_str, max_str);
+ new_cursor.swap(this);
+}
+
+void KeyCursor::close() {
+ KeyCursor new_cursor;
+ new_cursor.swap(this);
+}
+
+const Key &KeyCursor::next() {
+ if (finished_ || (count_ >= max_count_)) {
+ return Key::invalid_key();
+ }
+
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ return ascending_next();
+ } else {
+ return descending_next();
+ }
+}
+
+KeyCursor::KeyCursor(const Trie &trie,
+ UInt32 offset, UInt32 limit, UInt32 flags)
+ : trie_(&trie),
+ offset_(offset),
+ limit_(limit),
+ flags_(flags),
+ buf_(),
+ count_(0),
+ max_count_(0),
+ finished_(false),
+ end_buf_(NULL),
+ end_str_() {}
+
+UInt32 KeyCursor::fix_flags(UInt32 flags) const {
+ const UInt32 cursor_type = flags & CURSOR_TYPE_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_type != 0) &&
+ (cursor_type != KEY_RANGE_CURSOR));
+ flags |= KEY_RANGE_CURSOR;
+
+ const UInt32 cursor_order = flags & CURSOR_ORDER_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_order != 0) &&
+ (cursor_order != ASCENDING_CURSOR) &&
+ (cursor_order != DESCENDING_CURSOR));
+ if (cursor_order == 0) {
+ flags |= ASCENDING_CURSOR;
+ }
+
+ const UInt32 cursor_options = flags & CURSOR_OPTIONS_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ cursor_options & ~(EXCEPT_LOWER_BOUND | EXCEPT_UPPER_BOUND));
+
+ return flags;
+}
+
+void KeyCursor::init(const String &min_str, const String &max_str) {
+ if (offset_ > (MAX_UINT32 - limit_)) {
+ max_count_ = MAX_UINT32;
+ } else {
+ max_count_ = offset_ + limit_;
+ }
+
+ if (limit_ == 0) {
+ return;
+ }
+
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ ascending_init(min_str, max_str);
+ } else {
+ descending_init(min_str, max_str);
+ }
+}
+
+void KeyCursor::ascending_init(const String &min_str, const String &max_str) {
+ if (max_str.ptr() != NULL) {
+ if (max_str.length() != 0) {
+ end_buf_ = new UInt8[max_str.length()];
+ grn_memcpy(end_buf_, max_str.ptr(), max_str.length());
+ end_str_.assign(end_buf_, max_str.length());
+ }
+ }
+
+ if ((min_str.ptr() == NULL) || (min_str.length() == 0)) {
+ buf_.push_back(ROOT_NODE_ID);
+ return;
+ }
+
+ UInt32 node_id = ROOT_NODE_ID;
+ Node node;
+ for (UInt32 i = 0; i < min_str.length(); ++i) {
+ node = trie_->ith_node(node_id);
+ if (node.is_linker()) {
+ const Key &key = trie_->get_key(node.key_pos());
+ const int result = key.str().compare(min_str, i);
+ if ((result > 0) || ((result == 0) &&
+ ((flags_ & EXCEPT_LOWER_BOUND) != EXCEPT_LOWER_BOUND))) {
+ buf_.push_back(node_id);
+ } else if (node.sibling() != INVALID_LABEL) {
+ buf_.push_back(node_id ^ node.label() ^ node.sibling());
+ }
+ return;
+ } else if (node.sibling() != INVALID_LABEL) {
+ buf_.push_back(node_id ^ node.label() ^ node.sibling());
+ }
+
+ node_id = node.offset() ^ min_str[i];
+ if (trie_->ith_node(node_id).label() != min_str[i]) {
+ UInt16 label = node.child();
+ if (label == TERMINAL_LABEL) {
+ label = trie_->ith_node(node.offset() ^ label).sibling();
+ }
+ while (label != INVALID_LABEL) {
+ if (label > min_str[i]) {
+ buf_.push_back(node.offset() ^ label);
+ break;
+ }
+ label = trie_->ith_node(node.offset() ^ label).sibling();
+ }
+ return;
+ }
+ }
+
+ node = trie_->ith_node(node_id);
+ if (node.is_linker()) {
+ const Key &key = trie_->get_key(node.key_pos());
+ if ((key.length() != min_str.length()) ||
+ ((flags_ & EXCEPT_LOWER_BOUND) != EXCEPT_LOWER_BOUND)) {
+ buf_.push_back(node_id);
+ } else if (node.sibling() != INVALID_LABEL) {
+ buf_.push_back(node_id ^ node.label() ^ node.sibling());
+ }
+ return;
+ } else if (node.sibling() != INVALID_LABEL) {
+ buf_.push_back(node_id ^ node.label() ^ node.sibling());
+ }
+
+ UInt16 label = node.child();
+ if ((label == TERMINAL_LABEL) &&
+ ((flags_ & EXCEPT_LOWER_BOUND) == EXCEPT_LOWER_BOUND)) {
+ label = trie_->ith_node(node.offset() ^ label).sibling();
+ }
+ if (label != INVALID_LABEL) {
+ buf_.push_back(node.offset() ^ label);
+ }
+}
+
+void KeyCursor::descending_init(const String &min_str, const String &max_str) {
+ if (min_str.ptr() != NULL) {
+ if (min_str.length() != 0) {
+ end_buf_ = new UInt8[min_str.length()];
+ grn_memcpy(end_buf_, min_str.ptr(), min_str.length());
+ end_str_.assign(end_buf_, min_str.length());
+ }
+ }
+
+ if ((max_str.ptr() == NULL) || (max_str.length() == 0)) {
+ buf_.push_back(ROOT_NODE_ID);
+ return;
+ }
+
+ UInt32 node_id = ROOT_NODE_ID;
+ for (UInt32 i = 0; i < max_str.length(); ++i) {
+ const Base base = trie_->ith_node(node_id).base();
+ if (base.is_linker()) {
+ const Key &key = trie_->get_key(base.key_pos());
+ const int result = key.str().compare(max_str, i);
+ if ((result < 0) || ((result == 0) &&
+ ((flags_ & EXCEPT_UPPER_BOUND) != EXCEPT_UPPER_BOUND))) {
+ buf_.push_back(node_id | POST_ORDER_FLAG);
+ }
+ return;
+ }
+
+ UInt32 label = trie_->ith_node(node_id).child();
+ if (label == TERMINAL_LABEL) {
+ node_id = base.offset() ^ label;
+ buf_.push_back(node_id | POST_ORDER_FLAG);
+ label = trie_->ith_node(node_id).sibling();
+ }
+ while (label != INVALID_LABEL) {
+ node_id = base.offset() ^ label;
+ if (label < max_str[i]) {
+ buf_.push_back(node_id);
+ } else if (label > max_str[i]) {
+ return;
+ } else {
+ break;
+ }
+ label = trie_->ith_node(node_id).sibling();
+ }
+ if (label == INVALID_LABEL) {
+ return;
+ }
+ }
+
+ const Base base = trie_->ith_node(node_id).base();
+ if (base.is_linker()) {
+ const Key &key = trie_->get_key(base.key_pos());
+ if ((key.length() == max_str.length()) &&
+ ((flags_ & EXCEPT_UPPER_BOUND) != EXCEPT_UPPER_BOUND)) {
+ buf_.push_back(node_id | POST_ORDER_FLAG);
+ }
+ return;
+ }
+
+ UInt16 label = trie_->ith_node(node_id).child();
+ if ((label == TERMINAL_LABEL) &&
+ ((flags_ & EXCEPT_UPPER_BOUND) != EXCEPT_UPPER_BOUND)) {
+ buf_.push_back((base.offset() ^ label) | POST_ORDER_FLAG);
+ }
+}
+
+void KeyCursor::swap(KeyCursor *cursor) {
+ std::swap(trie_, cursor->trie_);
+ std::swap(offset_, cursor->offset_);
+ std::swap(limit_, cursor->limit_);
+ std::swap(flags_, cursor->flags_);
+ buf_.swap(&cursor->buf_);
+ std::swap(count_, cursor->count_);
+ std::swap(max_count_, cursor->max_count_);
+ std::swap(finished_, cursor->finished_);
+ std::swap(end_buf_, cursor->end_buf_);
+ end_str_.swap(&cursor->end_str_);
+}
+
+const Key &KeyCursor::ascending_next() {
+ while (!buf_.empty()) {
+ const UInt32 node_id = buf_.back();
+ buf_.pop_back();
+
+ const Node node = trie_->ith_node(node_id);
+ if (node.sibling() != INVALID_LABEL) {
+ buf_.push_back(node_id ^ node.label() ^ node.sibling());
+ }
+
+ if (node.is_linker()) {
+ const Key &key = trie_->get_key(node.key_pos());
+ if (end_buf_ != NULL) {
+ const int result = key.str().compare(end_str_);
+ if ((result > 0) || ((result == 0) &&
+ ((flags_ & EXCEPT_UPPER_BOUND) == EXCEPT_UPPER_BOUND))) {
+ finished_ = true;
+ return Key::invalid_key();
+ }
+ }
+ if (count_++ >= offset_) {
+ return key;
+ }
+ } else if (node.child() != INVALID_LABEL) {
+ buf_.push_back(node.offset() ^ node.child());
+ }
+ }
+ return Key::invalid_key();
+}
+
+const Key &KeyCursor::descending_next() {
+ while (!buf_.empty()) {
+ const bool post_order = (buf_.back() & POST_ORDER_FLAG) == POST_ORDER_FLAG;
+ const UInt32 node_id = buf_.back() & ~POST_ORDER_FLAG;
+
+ const Base base = trie_->ith_node(node_id).base();
+ if (post_order) {
+ buf_.pop_back();
+ if (base.is_linker()) {
+ const Key &key = trie_->get_key(base.key_pos());
+ if (end_buf_ != NULL) {
+ const int result = key.str().compare(end_str_);
+ if ((result < 0) || ((result == 0) &&
+ ((flags_ & EXCEPT_LOWER_BOUND) == EXCEPT_LOWER_BOUND))) {
+ finished_ = true;
+ return Key::invalid_key();
+ }
+ }
+ if (count_++ >= offset_) {
+ return key;
+ }
+ }
+ } else {
+ buf_.back() |= POST_ORDER_FLAG;
+ UInt16 label = trie_->ith_node(node_id).child();
+ while (label != INVALID_LABEL) {
+ buf_.push_back(base.offset() ^ label);
+ label = trie_->ith_node(base.offset() ^ label).sibling();
+ }
+ }
+ }
+ return Key::invalid_key();
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/key-cursor.hpp b/storage/mroonga/vendor/groonga/lib/dat/key-cursor.hpp
new file mode 100644
index 00000000..56392b63
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/key-cursor.hpp
@@ -0,0 +1,88 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "cursor.hpp"
+#include "vector.hpp"
+
+namespace grn {
+namespace dat {
+
+class Trie;
+
+class GRN_DAT_API KeyCursor : public Cursor {
+ public:
+ KeyCursor();
+ ~KeyCursor();
+
+ void open(const Trie &trie,
+ const String &min_str,
+ const String &max_str,
+ UInt32 offset = 0,
+ UInt32 limit = MAX_UINT32,
+ UInt32 flags = 0);
+
+ void close();
+
+ const Key &next();
+
+ UInt32 offset() const {
+ return offset_;
+ }
+ UInt32 limit() const {
+ return limit_;
+ }
+ UInt32 flags() const {
+ return flags_;
+ }
+
+ private:
+ const Trie *trie_;
+ UInt32 offset_;
+ UInt32 limit_;
+ UInt32 flags_;
+
+ Vector<UInt32> buf_;
+ UInt32 count_;
+ UInt32 max_count_;
+ bool finished_;
+ UInt8 *end_buf_;
+ String end_str_;
+
+ KeyCursor(const Trie &trie,
+ UInt32 offset, UInt32 limit, UInt32 flags);
+
+ UInt32 fix_flags(UInt32 flags) const;
+ void init(const String &min_str, const String &max_str);
+ void ascending_init(const String &min_str, const String &max_str);
+ void descending_init(const String &min_str, const String &max_str);
+ void swap(KeyCursor *cursor);
+
+ const Key &ascending_next();
+ const Key &descending_next();
+
+ static const UInt32 POST_ORDER_FLAG = 0x80000000U;
+
+ // Disallows copy and assignment.
+ KeyCursor(const KeyCursor &);
+ KeyCursor &operator=(const KeyCursor &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/key.hpp b/storage/mroonga/vendor/groonga/lib/dat/key.hpp
new file mode 100644
index 00000000..eb0324cd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/key.hpp
@@ -0,0 +1,110 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "string.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Key {
+ public:
+ const UInt8 &operator[](UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i >= length());
+ return buf_[i];
+ }
+
+ bool is_valid() const {
+ return id() != INVALID_KEY_ID;
+ }
+
+ String str() const {
+ return String(ptr(), length());
+ }
+
+ const void *ptr() const {
+ return buf_;
+ }
+ UInt32 length() const {
+ return (length_high_ << 4) | (id_and_length_low_ & 0x0F);
+ }
+ UInt32 id() const {
+ return id_and_length_low_ >> 4;
+ }
+
+ bool equals_to(const void *ptr, UInt32 length, UInt32 offset = 0) const {
+ if (length != this->length()) {
+ return false;
+ }
+ for ( ; offset < length; ++offset) {
+ if ((*this)[offset] != static_cast<const UInt8 *>(ptr)[offset]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Creates an object of Key from given parameters. Then, the created object
+ // is embedded into a specified buffer.
+ static const Key &create(UInt32 *buf, UInt32 key_id,
+ const void *key_ptr, UInt32 key_length) {
+ GRN_DAT_DEBUG_THROW_IF(buf == NULL);
+ GRN_DAT_DEBUG_THROW_IF(key_id > MAX_KEY_ID);
+ GRN_DAT_DEBUG_THROW_IF((key_ptr == NULL) && (key_length != 0));
+ GRN_DAT_DEBUG_THROW_IF(key_length > MAX_KEY_LENGTH);
+
+ *buf = (key_id << 4) | (key_length & 0x0F);
+ UInt8 *ptr = reinterpret_cast<UInt8 *>(buf + 1);
+ *ptr++ = key_length >> 4;
+ for (UInt32 i = 0; i < key_length; ++i) {
+ ptr[i] = static_cast<const UInt8 *>(key_ptr)[i];
+ }
+ return *reinterpret_cast<const Key *>(buf);
+ }
+
+ // Calculates how many UInt32s are required for a string. It is guaranteed
+ // that the estimated size is not less than the actual size.
+ static UInt32 estimate_size(UInt32 length) {
+ return 2 + (length / sizeof(UInt32));
+ }
+
+ // Returns a reference to an invalid key.
+ static const Key &invalid_key() {
+ static const Key invalid_key;
+ return invalid_key;
+// static const UInt32 invalid_key_buf[2] = { INVALID_KEY_ID << 4, 0 };
+// return *reinterpret_cast<const Key *>(invalid_key_buf);
+ }
+
+ private:
+ UInt32 id_and_length_low_;
+ UInt8 length_high_;
+ UInt8 buf_[3];
+
+ // Disallows instantiation.
+ Key() : id_and_length_low_(INVALID_KEY_ID << 4), length_high_(0) {}
+ ~Key() {}
+
+ // Disallows copy and assignment.
+ Key(const Key &);
+ Key &operator=(const Key &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/node.hpp b/storage/mroonga/vendor/groonga/lib/dat/node.hpp
new file mode 100644
index 00000000..29febc7d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/node.hpp
@@ -0,0 +1,127 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+// See base.hpp and check.hpp for details.
+#include "base.hpp"
+#include "check.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Node {
+ public:
+ Node() : base_(), check_() {}
+
+ Base base() const {
+ return base_;
+ }
+ bool is_linker() const {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ return base_.is_linker();
+ }
+ UInt32 offset() const {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ return base_.offset();
+ }
+ UInt32 key_pos() const {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ return base_.key_pos();
+ }
+
+ Check check() const {
+ return check_;
+ }
+ bool is_offset() const {
+ return check_.is_offset();
+ }
+ UInt32 except_is_offset() const {
+ return check_.except_is_offset();
+ }
+ bool is_phantom() const {
+ return check_.is_phantom();
+ }
+ UInt32 next() const {
+ return check_.next();
+ }
+ UInt32 prev() const {
+ return check_.prev();
+ }
+ UInt32 label() const {
+ return check_.label();
+ }
+ UInt32 child() const {
+ return check_.child();
+ }
+ UInt32 sibling() const {
+ return check_.sibling();
+ }
+
+ void set_base(Base x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ base_ = x;
+ }
+ void set_offset(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ base_.set_offset(x);
+ }
+ void set_key_pos(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(is_phantom());
+ base_.set_key_pos(x);
+ }
+
+ void set_check(Check x) {
+ check_ = x;
+ }
+ void set_is_offset(bool x) {
+ check_.set_is_offset(x);
+ }
+ void set_except_is_offset(UInt32 x) {
+ check_.set_except_is_offset(x);
+ }
+ void set_is_phantom(bool x) {
+ GRN_DAT_DEBUG_THROW_IF(base_.offset() != INVALID_OFFSET);
+ check_.set_is_phantom(x);
+ }
+ void set_next(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(base_.offset() != INVALID_OFFSET);
+ check_.set_next(x);
+ }
+ void set_prev(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(base_.offset() != INVALID_OFFSET);
+ check_.set_prev(x);
+ }
+ void set_label(UInt32 x) {
+ GRN_DAT_DEBUG_THROW_IF(offset() != INVALID_OFFSET);
+ check_.set_label(x);
+ }
+ void set_child(UInt32 x) {
+ check_.set_child(x);
+ }
+ void set_sibling(UInt32 x) {
+ check_.set_sibling(x);
+ }
+
+ private:
+ Base base_;
+ Check check_;
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.cpp b/storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.cpp
new file mode 100644
index 00000000..67520305
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.cpp
@@ -0,0 +1,206 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "predictive-cursor.hpp"
+
+#include <algorithm>
+#include <cstring>
+
+#include "trie.hpp"
+
+namespace grn {
+namespace dat {
+
+PredictiveCursor::PredictiveCursor()
+ : trie_(NULL),
+ offset_(0),
+ limit_(MAX_UINT32),
+ flags_(PREDICTIVE_CURSOR),
+ buf_(),
+ cur_(0),
+ end_(0),
+ min_length_(0) {}
+
+PredictiveCursor::~PredictiveCursor() {}
+
+void PredictiveCursor::open(const Trie &trie,
+ const String &str,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, (str.ptr() == NULL) && (str.length() != 0));
+
+ flags = fix_flags(flags);
+ PredictiveCursor new_cursor(trie, offset, limit, flags);
+ new_cursor.init(str);
+ new_cursor.swap(this);
+}
+
+void PredictiveCursor::close() {
+ PredictiveCursor new_cursor;
+ new_cursor.swap(this);
+}
+
+const Key &PredictiveCursor::next() {
+ if (cur_ == end_) {
+ return Key::invalid_key();
+ }
+
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ return ascending_next();
+ } else {
+ return descending_next();
+ }
+}
+
+PredictiveCursor::PredictiveCursor(const Trie &trie,
+ UInt32 offset, UInt32 limit, UInt32 flags)
+ : trie_(&trie),
+ offset_(offset),
+ limit_(limit),
+ flags_(flags),
+ buf_(),
+ cur_(0),
+ end_(0),
+ min_length_(0) {}
+
+UInt32 PredictiveCursor::fix_flags(UInt32 flags) const {
+ const UInt32 cursor_type = flags & CURSOR_TYPE_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_type != 0) &&
+ (cursor_type != PREDICTIVE_CURSOR));
+ flags |= PREDICTIVE_CURSOR;
+
+ const UInt32 cursor_order = flags & CURSOR_ORDER_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_order != 0) &&
+ (cursor_order != ASCENDING_CURSOR) &&
+ (cursor_order != DESCENDING_CURSOR));
+ if (cursor_order == 0) {
+ flags |= ASCENDING_CURSOR;
+ }
+
+ const UInt32 cursor_options = flags & CURSOR_OPTIONS_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, cursor_options & ~(EXCEPT_EXACT_MATCH));
+
+ return flags;
+}
+
+void PredictiveCursor::init(const String &str) {
+ if (limit_ == 0) {
+ return;
+ }
+
+ min_length_ = str.length();
+ if ((flags_ & EXCEPT_EXACT_MATCH) == EXCEPT_EXACT_MATCH) {
+ ++min_length_;
+ }
+ end_ = (offset_ > (MAX_UINT32 - limit_)) ? MAX_UINT32 : (offset_ + limit_);
+
+ UInt32 node_id = ROOT_NODE_ID;
+ for (UInt32 i = 0; i < str.length(); ++i) {
+ const Base base = trie_->ith_node(node_id).base();
+ if (base.is_linker()) {
+ if (offset_ == 0) {
+ const Key &key = trie_->get_key(base.key_pos());
+ if ((key.length() >= str.length()) &&
+ (key.str().substr(0, str.length()).compare(str, i) == 0)) {
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ node_id |= IS_ROOT_FLAG;
+ }
+ buf_.push_back(node_id);
+ }
+ }
+ return;
+ }
+
+ node_id = base.offset() ^ str[i];
+ if (trie_->ith_node(node_id).label() != str[i]) {
+ return;
+ }
+ }
+
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ node_id |= IS_ROOT_FLAG;
+ }
+ buf_.push_back(node_id);
+}
+
+void PredictiveCursor::swap(PredictiveCursor *cursor) {
+ std::swap(trie_, cursor->trie_);
+ std::swap(offset_, cursor->offset_);
+ std::swap(limit_, cursor->limit_);
+ std::swap(flags_, cursor->flags_);
+ buf_.swap(&cursor->buf_);
+ std::swap(cur_, cursor->cur_);
+ std::swap(end_, cursor->end_);
+ std::swap(min_length_, cursor->min_length_);
+}
+
+const Key &PredictiveCursor::ascending_next() {
+ while (!buf_.empty()) {
+ const bool is_root = (buf_.back() & IS_ROOT_FLAG) == IS_ROOT_FLAG;
+ const UInt32 node_id = buf_.back() & ~IS_ROOT_FLAG;
+ buf_.pop_back();
+
+ const Node node = trie_->ith_node(node_id);
+ if (!is_root && (node.sibling() != INVALID_LABEL)) {
+ buf_.push_back(node_id ^ node.label() ^ node.sibling());
+ }
+
+ if (node.is_linker()) {
+ const Key &key = trie_->get_key(node.key_pos());
+ if (key.length() >= min_length_) {
+ if (cur_++ >= offset_) {
+ return key;
+ }
+ }
+ } else if (node.child() != INVALID_LABEL) {
+ buf_.push_back(node.offset() ^ node.child());
+ }
+ }
+ return Key::invalid_key();
+}
+
+const Key &PredictiveCursor::descending_next() {
+ while (!buf_.empty()) {
+ const bool post_order = (buf_.back() & POST_ORDER_FLAG) == POST_ORDER_FLAG;
+ const UInt32 node_id = buf_.back() & ~POST_ORDER_FLAG;
+
+ const Base base = trie_->ith_node(node_id).base();
+ if (post_order) {
+ buf_.pop_back();
+ if (base.is_linker()) {
+ const Key &key = trie_->get_key(base.key_pos());
+ if (key.length() >= min_length_) {
+ if (cur_++ >= offset_) {
+ return key;
+ }
+ }
+ }
+ } else {
+ buf_.back() |= POST_ORDER_FLAG;
+ UInt16 label = trie_->ith_node(node_id).child();
+ while (label != INVALID_LABEL) {
+ buf_.push_back(base.offset() ^ label);
+ label = trie_->ith_node(base.offset() ^ label).sibling();
+ }
+ }
+ }
+ return Key::invalid_key();
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.hpp b/storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.hpp
new file mode 100644
index 00000000..88a950b8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/predictive-cursor.hpp
@@ -0,0 +1,84 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "cursor.hpp"
+#include "vector.hpp"
+
+namespace grn {
+namespace dat {
+
+class Trie;
+
+class GRN_DAT_API PredictiveCursor : public Cursor {
+ public:
+ PredictiveCursor();
+ ~PredictiveCursor();
+
+ void open(const Trie &trie,
+ const String &str,
+ UInt32 offset = 0,
+ UInt32 limit = MAX_UINT32,
+ UInt32 flags = 0);
+
+ void close();
+
+ const Key &next();
+
+ UInt32 offset() const {
+ return offset_;
+ }
+ UInt32 limit() const {
+ return limit_;
+ }
+ UInt32 flags() const {
+ return flags_;
+ }
+
+ private:
+ const Trie *trie_;
+ UInt32 offset_;
+ UInt32 limit_;
+ UInt32 flags_;
+
+ Vector<UInt32> buf_;
+ UInt32 cur_;
+ UInt32 end_;
+ UInt32 min_length_;
+
+ PredictiveCursor(const Trie &trie,
+ UInt32 offset, UInt32 limit, UInt32 flags);
+
+ UInt32 fix_flags(UInt32 flags) const;
+ void init(const String &str);
+ void swap(PredictiveCursor *cursor);
+
+ const Key &ascending_next();
+ const Key &descending_next();
+
+ static const UInt32 IS_ROOT_FLAG = 0x80000000U;
+ static const UInt32 POST_ORDER_FLAG = 0x80000000U;
+
+ // Disallows copy and assignment.
+ PredictiveCursor(const PredictiveCursor &);
+ PredictiveCursor &operator=(const PredictiveCursor &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.cpp b/storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.cpp
new file mode 100644
index 00000000..83adeb37
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.cpp
@@ -0,0 +1,175 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "prefix-cursor.hpp"
+
+#include <algorithm>
+
+#include "trie.hpp"
+
+namespace grn {
+namespace dat {
+
+PrefixCursor::PrefixCursor()
+ : trie_(NULL),
+ offset_(0),
+ limit_(MAX_UINT32),
+ flags_(PREFIX_CURSOR),
+ buf_(),
+ cur_(0),
+ end_(0) {}
+
+PrefixCursor::~PrefixCursor() {}
+
+void PrefixCursor::open(const Trie &trie,
+ const String &str,
+ UInt32 min_length,
+ UInt32 offset,
+ UInt32 limit,
+ UInt32 flags) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, (str.ptr() == NULL) && (str.length() != 0));
+ GRN_DAT_THROW_IF(PARAM_ERROR, min_length > str.length());
+
+ flags = fix_flags(flags);
+ PrefixCursor new_cursor(trie, offset, limit, flags);
+ new_cursor.init(str, min_length);
+ new_cursor.swap(this);
+}
+
+void PrefixCursor::close() {
+ PrefixCursor new_cursor;
+ new_cursor.swap(this);
+}
+
+const Key &PrefixCursor::next() {
+ if (cur_ == end_) {
+ return Key::invalid_key();
+ }
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ return trie_->get_key(buf_[cur_++]);
+ } else {
+ return trie_->get_key(buf_[--cur_]);
+ }
+}
+
+PrefixCursor::PrefixCursor(const Trie &trie,
+ UInt32 offset, UInt32 limit, UInt32 flags)
+ : trie_(&trie),
+ offset_(offset),
+ limit_(limit),
+ flags_(flags),
+ buf_(),
+ cur_(0),
+ end_(0) {}
+
+UInt32 PrefixCursor::fix_flags(UInt32 flags) const {
+ const UInt32 cursor_type = flags & CURSOR_TYPE_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_type != 0) &&
+ (cursor_type != PREFIX_CURSOR));
+ flags |= PREFIX_CURSOR;
+
+ const UInt32 cursor_order = flags & CURSOR_ORDER_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (cursor_order != 0) &&
+ (cursor_order != ASCENDING_CURSOR) &&
+ (cursor_order != DESCENDING_CURSOR));
+ if (cursor_order == 0) {
+ flags |= ASCENDING_CURSOR;
+ }
+
+ const UInt32 cursor_options = flags & CURSOR_OPTIONS_MASK;
+ GRN_DAT_THROW_IF(PARAM_ERROR, cursor_options & ~EXCEPT_EXACT_MATCH);
+
+ return flags;
+}
+
+void PrefixCursor::init(const String &str, UInt32 min_length) {
+ if ((limit_ == 0) || (offset_ > (str.length() - min_length))) {
+ return;
+ }
+
+ UInt32 node_id = ROOT_NODE_ID;
+ UInt32 i;
+ for (i = 0; i < str.length(); ++i) {
+ const Base base = trie_->ith_node(node_id).base();
+ if (base.is_linker()) {
+ const Key &key = trie_->get_key(base.key_pos());
+ if ((key.length() >= min_length) && (key.length() <= str.length()) &&
+ (str.substr(0, key.length()).compare(key.str(), i) == 0) &&
+ ((key.length() < str.length()) ||
+ ((flags_ & EXCEPT_EXACT_MATCH) != EXCEPT_EXACT_MATCH))) {
+ buf_.push_back(base.key_pos());
+ }
+ break;
+ }
+
+ if ((i >= min_length) &&
+ (trie_->ith_node(node_id).child() == TERMINAL_LABEL)) {
+ const Base linker_base =
+ trie_->ith_node(base.offset() ^ TERMINAL_LABEL).base();
+ if (linker_base.is_linker()) {
+ buf_.push_back(linker_base.key_pos());
+ }
+ }
+
+ node_id = base.offset() ^ str[i];
+ if (trie_->ith_node(node_id).label() != str[i]) {
+ break;
+ }
+ }
+
+ if ((i == str.length()) &&
+ ((flags_ & EXCEPT_EXACT_MATCH) != EXCEPT_EXACT_MATCH)) {
+ const Base base = trie_->ith_node(node_id).base();
+ if (base.is_linker()) {
+ const Key &key = trie_->get_key(base.key_pos());
+ if ((key.length() >= min_length) && (key.length() <= str.length())) {
+ buf_.push_back(base.key_pos());
+ }
+ } else if (trie_->ith_node(node_id).child() == TERMINAL_LABEL) {
+ const Base linker_base =
+ trie_->ith_node(base.offset() ^ TERMINAL_LABEL).base();
+ if (linker_base.is_linker()) {
+ buf_.push_back(linker_base.key_pos());
+ }
+ }
+ }
+
+ if (buf_.size() <= offset_) {
+ return;
+ }
+
+ if ((flags_ & ASCENDING_CURSOR) == ASCENDING_CURSOR) {
+ cur_ = offset_;
+ end_ = (limit_ < (buf_.size() - cur_)) ? (cur_ + limit_) : buf_.size();
+ } else {
+ cur_ = buf_.size() - offset_;
+ end_ = (limit_ < cur_) ? (cur_ - limit_) : 0;
+ }
+}
+
+void PrefixCursor::swap(PrefixCursor *cursor) {
+ std::swap(trie_, cursor->trie_);
+ std::swap(offset_, cursor->offset_);
+ std::swap(limit_, cursor->limit_);
+ std::swap(flags_, cursor->flags_);
+ buf_.swap(&cursor->buf_);
+ std::swap(cur_, cursor->cur_);
+ std::swap(end_, cursor->end_);
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.hpp b/storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.hpp
new file mode 100644
index 00000000..07a59186
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/prefix-cursor.hpp
@@ -0,0 +1,78 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "cursor.hpp"
+#include "vector.hpp"
+
+namespace grn {
+namespace dat {
+
+class Trie;
+
+class GRN_DAT_API PrefixCursor : public Cursor {
+ public:
+ PrefixCursor();
+ ~PrefixCursor();
+
+ void open(const Trie &trie,
+ const String &str,
+ UInt32 min_length = 0,
+ UInt32 offset = 0,
+ UInt32 limit = MAX_UINT32,
+ UInt32 flags = 0);
+
+ void close();
+
+ const Key &next();
+
+ UInt32 offset() const {
+ return offset_;
+ }
+ UInt32 limit() const {
+ return limit_;
+ }
+ UInt32 flags() const {
+ return flags_;
+ }
+
+ private:
+ const Trie *trie_;
+ UInt32 offset_;
+ UInt32 limit_;
+ UInt32 flags_;
+
+ Vector<UInt32> buf_;
+ UInt32 cur_;
+ UInt32 end_;
+
+ PrefixCursor(const Trie &trie,
+ UInt32 offset, UInt32 limit, UInt32 flags);
+
+ UInt32 fix_flags(UInt32 flags) const;
+ void init(const String &str, UInt32 min_length);
+ void swap(PrefixCursor *cursor);
+
+ // Disallows copy and assignment.
+ PrefixCursor(const PrefixCursor &);
+ PrefixCursor &operator=(const PrefixCursor &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/sources.am b/storage/mroonga/vendor/groonga/lib/dat/sources.am
new file mode 100644
index 00000000..26c9f09f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/sources.am
@@ -0,0 +1,29 @@
+libgrndat_la_SOURCES = \
+ cursor-factory.cpp \
+ file-impl.cpp \
+ file.cpp \
+ id-cursor.cpp \
+ key-cursor.cpp \
+ predictive-cursor.cpp \
+ prefix-cursor.cpp \
+ trie.cpp \
+ array.hpp \
+ base.hpp \
+ block.hpp \
+ check.hpp \
+ cursor-factory.hpp \
+ cursor.hpp \
+ dat.hpp \
+ entry.hpp \
+ file-impl.hpp \
+ file.hpp \
+ header.hpp \
+ id-cursor.hpp \
+ key-cursor.hpp \
+ key.hpp \
+ node.hpp \
+ predictive-cursor.hpp \
+ prefix-cursor.hpp \
+ string.hpp \
+ trie.hpp \
+ vector.hpp
diff --git a/storage/mroonga/vendor/groonga/lib/dat/string.hpp b/storage/mroonga/vendor/groonga/lib/dat/string.hpp
new file mode 100644
index 00000000..aead21ca
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/string.hpp
@@ -0,0 +1,173 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API String {
+ public:
+ String()
+ : ptr_(NULL),
+ length_(0) {}
+ String(const void *ptr, UInt32 length)
+ : ptr_(static_cast<const UInt8 *>(ptr)),
+ length_(length) {}
+ template <UInt32 T>
+ explicit String(const char (&str)[T])
+ : ptr_(reinterpret_cast<const UInt8 *>(str)),
+ length_(T - 1) {}
+ String(const String &rhs)
+ : ptr_(rhs.ptr_),
+ length_(rhs.length_) {}
+
+ String &operator=(const String &rhs) {
+ set_ptr(rhs.ptr());
+ set_length(rhs.length());
+ return *this;
+ }
+
+ const UInt8 &operator[](UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i >= length_);
+ return ptr_[i];
+ }
+
+ const void *ptr() const {
+ return ptr_;
+ }
+ UInt32 length() const {
+ return length_;
+ }
+
+ void set_ptr(const void *x) {
+ ptr_ = static_cast<const UInt8 *>(x);
+ }
+ void set_length(UInt32 x) {
+ length_ = x;
+ }
+
+ void assign(const void *ptr, UInt32 length) {
+ set_ptr(ptr);
+ set_length(length);
+ }
+
+ String substr(UInt32 offset = 0) const {
+ return String(ptr_ + offset, length_ - offset);
+ }
+ String substr(UInt32 offset, UInt32 length) const {
+ return String(ptr_ + offset, length);
+ }
+
+ // This function returns an integer as follows:
+ // - a negative value if *this < rhs,
+ // - zero if *this == rhs,
+ // - a positive value if *this > rhs,
+ // but if the offset is too large, the result is undefined.
+ int compare(const String &rhs, UInt32 offset = 0) const {
+ GRN_DAT_DEBUG_THROW_IF(offset > length());
+ GRN_DAT_DEBUG_THROW_IF(offset > rhs.length());
+
+ for (UInt32 i = offset; i < length(); ++i) {
+ if (i >= rhs.length()) {
+ return 1;
+ } else if ((*this)[i] != rhs[i]) {
+ return (*this)[i] - rhs[i];
+ }
+ }
+ return (length() == rhs.length()) ? 0 : -1;
+ }
+
+ bool starts_with(const String &str) const {
+ if (length() < str.length()) {
+ return false;
+ }
+ for (UInt32 i = 0; i < str.length(); ++i) {
+ if ((*this)[i] != str[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool ends_with(const String &str) const {
+ if (length() < str.length()) {
+ return false;
+ }
+ UInt32 offset = length() - str.length();
+ for (UInt32 i = 0; i < str.length(); ++i) {
+ if ((*this)[offset + i] != str[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void swap(String *rhs) {
+ const UInt8 * const ptr_temp = ptr_;
+ ptr_ = rhs->ptr_;
+ rhs->ptr_ = ptr_temp;
+
+ const UInt32 length_temp = length_;
+ length_ = rhs->length_;
+ rhs->length_ = length_temp;
+ }
+
+ private:
+ const UInt8 *ptr_;
+ UInt32 length_;
+};
+
+inline bool operator==(const String &lhs, const String &rhs) {
+ if (lhs.length() != rhs.length()) {
+ return false;
+ } else if (lhs.ptr() == rhs.ptr()) {
+ return true;
+ }
+ for (UInt32 i = 0; i < lhs.length(); ++i) {
+ if (lhs[i] != rhs[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+inline bool operator!=(const String &lhs, const String &rhs) {
+ return !(lhs == rhs);
+}
+
+inline bool operator<(const String &lhs, const String &rhs) {
+ return lhs.compare(rhs) < 0;
+}
+
+inline bool operator>(const String &lhs, const String &rhs) {
+ return rhs < lhs;
+}
+
+inline bool operator<=(const String &lhs, const String &rhs) {
+ return !(lhs > rhs);
+}
+
+inline bool operator>=(const String &lhs, const String &rhs) {
+ return !(lhs < rhs);
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/trie.cpp b/storage/mroonga/vendor/groonga/lib/dat/trie.cpp
new file mode 100644
index 00000000..b2c6a84f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/trie.cpp
@@ -0,0 +1,1225 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2011-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "trie.hpp"
+
+#include <algorithm>
+#include <cstring>
+
+#include "vector.hpp"
+
+namespace grn {
+namespace dat {
+namespace {
+
+class StatusFlagManager {
+ public:
+ StatusFlagManager(Header *header, UInt32 status_flag)
+ : header_(header), status_flag_(status_flag) {
+ header_->set_status_flags(header_->status_flags() | status_flag_);
+ }
+ ~StatusFlagManager() {
+ header_->set_status_flags(header_->status_flags() & ~status_flag_);
+ }
+
+ private:
+ Header *header_;
+ UInt32 status_flag_;
+
+ // Disallows copy and assignment.
+ StatusFlagManager(const StatusFlagManager &);
+ StatusFlagManager &operator=(const StatusFlagManager &);
+};
+
+} // namespace
+
+Trie::Trie()
+ : file_(),
+ header_(NULL),
+ nodes_(),
+ blocks_(),
+ entries_(),
+ key_buf_() {}
+
+Trie::~Trie() {}
+
+void Trie::create(const char *file_name,
+ UInt64 file_size,
+ UInt32 max_num_keys,
+ double num_nodes_per_key,
+ double average_key_length) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, (file_size != 0) && (max_num_keys != 0));
+
+ if (num_nodes_per_key < 1.0) {
+ num_nodes_per_key = DEFAULT_NUM_NODES_PER_KEY;
+ }
+ if (num_nodes_per_key > MAX_NUM_NODES_PER_KEY) {
+ num_nodes_per_key = MAX_NUM_NODES_PER_KEY;
+ }
+ GRN_DAT_THROW_IF(PARAM_ERROR, num_nodes_per_key < 1.0);
+ GRN_DAT_THROW_IF(PARAM_ERROR, num_nodes_per_key > MAX_NUM_NODES_PER_KEY);
+
+ if (average_key_length < 1.0) {
+ average_key_length = DEFAULT_AVERAGE_KEY_LENGTH;
+ }
+ GRN_DAT_THROW_IF(PARAM_ERROR, average_key_length < 1.0);
+ GRN_DAT_THROW_IF(PARAM_ERROR, average_key_length > MAX_KEY_LENGTH);
+
+ if (max_num_keys == 0) {
+ if (file_size == 0) {
+ file_size = DEFAULT_FILE_SIZE;
+ } else {
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_size < MIN_FILE_SIZE);
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_size > MAX_FILE_SIZE);
+ }
+ } else {
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_keys > MAX_NUM_KEYS);
+ }
+
+ Trie new_trie;
+ new_trie.create_file(file_name, file_size, max_num_keys,
+ num_nodes_per_key, average_key_length);
+ new_trie.swap(this);
+}
+
+void Trie::create(const Trie &trie,
+ const char *file_name,
+ UInt64 file_size,
+ UInt32 max_num_keys,
+ double num_nodes_per_key,
+ double average_key_length) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, (file_size != 0) && (max_num_keys != 0));
+
+ if (num_nodes_per_key < 1.0) {
+ if (trie.num_keys() == 0) {
+ num_nodes_per_key = DEFAULT_NUM_NODES_PER_KEY;
+ } else {
+ num_nodes_per_key = 1.0 * trie.num_nodes() / trie.num_keys();
+ if (num_nodes_per_key > MAX_NUM_NODES_PER_KEY) {
+ num_nodes_per_key = MAX_NUM_NODES_PER_KEY;
+ }
+ }
+ }
+ GRN_DAT_THROW_IF(PARAM_ERROR, num_nodes_per_key < 1.0);
+ GRN_DAT_THROW_IF(PARAM_ERROR, num_nodes_per_key > MAX_NUM_NODES_PER_KEY);
+
+ if (average_key_length < 1.0) {
+ if (trie.num_keys() == 0) {
+ average_key_length = DEFAULT_AVERAGE_KEY_LENGTH;
+ } else {
+ average_key_length = 1.0 * trie.total_key_length() / trie.num_keys();
+ }
+ }
+ GRN_DAT_THROW_IF(PARAM_ERROR, average_key_length < 1.0);
+ GRN_DAT_THROW_IF(PARAM_ERROR, average_key_length > MAX_KEY_LENGTH);
+
+ if (max_num_keys == 0) {
+ if (file_size == 0) {
+ file_size = trie.file_size();
+ }
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_size < MIN_FILE_SIZE);
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_size > MAX_FILE_SIZE);
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_size < trie.virtual_size());
+ } else {
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_keys < trie.num_keys());
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_keys < trie.max_key_id());
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_keys > MAX_NUM_KEYS);
+ }
+
+ Trie new_trie;
+ new_trie.create_file(file_name, file_size, max_num_keys,
+ num_nodes_per_key, average_key_length);
+ new_trie.build_from_trie(trie);
+ new_trie.swap(this);
+}
+
+void Trie::repair(const Trie &trie, const char *file_name) {
+ Trie new_trie;
+ new_trie.create_file(file_name, trie.file_size(), trie.max_num_keys(),
+ trie.max_num_blocks(), trie.key_buf_size());
+ new_trie.repair_trie(trie);
+ new_trie.swap(this);
+}
+
+void Trie::open(const char *file_name) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_name == NULL);
+
+ Trie new_trie;
+ new_trie.open_file(file_name);
+ new_trie.swap(this);
+}
+
+void Trie::close() {
+ Trie().swap(this);
+}
+
+void Trie::swap(Trie *trie) {
+ file_.swap(&trie->file_);
+ std::swap(header_, trie->header_);
+ nodes_.swap(&trie->nodes_);
+ blocks_.swap(&trie->blocks_);
+ entries_.swap(&trie->entries_);
+ key_buf_.swap(&trie->key_buf_);
+}
+
+void Trie::flush() {
+ file_.flush();
+}
+
+void Trie::create_file(const char *file_name,
+ UInt64 file_size,
+ UInt32 max_num_keys,
+ double num_nodes_per_key,
+ double average_key_length) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, (file_size == 0) && (max_num_keys == 0));
+ GRN_DAT_THROW_IF(PARAM_ERROR, (file_size != 0) && (max_num_keys != 0));
+ if (max_num_keys == 0) {
+ const UInt64 avail = file_size - sizeof(Header);
+ const double num_bytes_per_key = (sizeof(Node) * num_nodes_per_key)
+ + (1.0 * sizeof(Block) / BLOCK_SIZE * num_nodes_per_key)
+ + sizeof(Entry)
+ + sizeof(UInt32) + sizeof(UInt8) + average_key_length + 1.5;
+ if ((avail / num_bytes_per_key) > MAX_NUM_KEYS) {
+ max_num_keys = MAX_NUM_KEYS;
+ } else {
+ max_num_keys = (UInt32)(avail / num_bytes_per_key);
+ }
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_keys == 0);
+ }
+
+ UInt32 max_num_blocks;
+ {
+ const double max_num_nodes = num_nodes_per_key * max_num_keys;
+ GRN_DAT_THROW_IF(PARAM_ERROR, (max_num_nodes - 1.0) >= MAX_NUM_NODES);
+ max_num_blocks = ((UInt32)max_num_nodes + BLOCK_SIZE - 1) / BLOCK_SIZE;
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_blocks == 0);
+ GRN_DAT_THROW_IF(PARAM_ERROR, max_num_blocks > MAX_NUM_BLOCKS);
+ }
+
+ UInt32 key_buf_size;
+ if (file_size == 0) {
+ const double total_key_length = average_key_length * max_num_keys;
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ (total_key_length - 1.0) >= MAX_TOTAL_KEY_LENGTH);
+
+ // The last term is the estimated number of bytes that will be used for
+ // 32-bit alignment.
+ const UInt64 total_num_bytes = (UInt64)(total_key_length)
+ + (UInt64)(sizeof(UInt32) + sizeof(UInt8)) * max_num_keys
+ + (UInt32)(max_num_keys * 1.5);
+ GRN_DAT_THROW_IF(PARAM_ERROR,
+ (total_num_bytes / sizeof(UInt32)) >= MAX_KEY_BUF_SIZE);
+ key_buf_size = (UInt32)(total_num_bytes / sizeof(UInt32));
+
+ file_size = sizeof(Header)
+ + (sizeof(Block) * max_num_blocks)
+ + (sizeof(Node) * BLOCK_SIZE * max_num_blocks)
+ + (sizeof(Entry) * max_num_keys)
+ + (sizeof(UInt32) * key_buf_size);
+ } else {
+ const UInt64 avail = file_size - sizeof(Header)
+ - (sizeof(Block) * max_num_blocks)
+ - (sizeof(Node) * BLOCK_SIZE * max_num_blocks)
+ - (sizeof(Entry) * max_num_keys);
+ GRN_DAT_THROW_IF(PARAM_ERROR, (avail / sizeof(UInt32)) > MAX_KEY_BUF_SIZE);
+ key_buf_size = (UInt32)(avail / sizeof(UInt32));
+ }
+
+ create_file(file_name, file_size, max_num_keys,
+ max_num_blocks, key_buf_size);
+}
+
+void Trie::create_file(const char *file_name,
+ UInt64 file_size,
+ UInt32 max_num_keys,
+ UInt32 max_num_blocks,
+ UInt32 key_buf_size) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_size < (sizeof(Header)
+ + (sizeof(Block) * max_num_blocks)
+ + (sizeof(Node) * BLOCK_SIZE * max_num_blocks)
+ + (sizeof(Entry) * max_num_keys)
+ + (sizeof(UInt32) * key_buf_size)));
+
+ file_.create(file_name, file_size);
+
+ Header * const header = static_cast<Header *>(file_.ptr());
+ *header = Header();
+ header->set_file_size(file_size);
+ header->set_max_num_keys(max_num_keys);
+ header->set_max_num_blocks(max_num_blocks);
+ header->set_key_buf_size(key_buf_size);
+
+ map_address(file_.ptr());
+
+ reserve_node(ROOT_NODE_ID);
+ ith_node(INVALID_OFFSET).set_is_offset(true);
+}
+
+void Trie::open_file(const char *file_name) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, file_name == NULL);
+
+ file_.open(file_name);
+ map_address(file_.ptr());
+ GRN_DAT_THROW_IF(FORMAT_ERROR, file_size() != file_.size());
+}
+
+void Trie::map_address(void *address) {
+ GRN_DAT_THROW_IF(PARAM_ERROR, address == NULL);
+
+ header_ = static_cast<Header *>(address);
+ nodes_.assign(header_ + 1, max_num_nodes());
+ blocks_.assign(nodes_.end(), max_num_blocks());
+ entries_.assign(reinterpret_cast<Entry *>(blocks_.end()) - 1,
+ max_num_keys() + 1);
+ key_buf_.assign(entries_.end(), key_buf_size());
+
+ GRN_DAT_THROW_IF(UNEXPECTED_ERROR, static_cast<void *>(key_buf_.end())
+ > static_cast<void *>(static_cast<char *>(address) + file_size()));
+}
+
+void Trie::build_from_trie(const Trie &trie) {
+ GRN_DAT_THROW_IF(SIZE_ERROR, max_num_keys() < trie.num_keys());
+ GRN_DAT_THROW_IF(SIZE_ERROR, max_num_keys() < trie.max_key_id());
+
+ header_->set_total_key_length(trie.total_key_length());
+ header_->set_num_keys(trie.num_keys());
+ header_->set_max_key_id(trie.max_key_id());
+ header_->set_next_key_id(trie.next_key_id());
+ for (UInt32 i = min_key_id(); i <= max_key_id(); ++i) {
+ ith_entry(i) = trie.ith_entry(i);
+ }
+ build_from_trie(trie, ROOT_NODE_ID, ROOT_NODE_ID);
+}
+
+void Trie::build_from_trie(const Trie &trie, UInt32 src, UInt32 dest) {
+ // Keys are sorted in lexicographic order.
+ if (trie.ith_node(src).is_linker()) {
+ const Key &key = trie.get_key(trie.ith_node(src).key_pos());
+ Key::create(key_buf_.ptr() + next_key_pos(),
+ key.id(), key.ptr(), key.length());
+ ith_node(dest).set_key_pos(next_key_pos());
+ ith_entry(key.id()).set_key_pos(next_key_pos());
+ header_->set_next_key_pos(
+ next_key_pos() + Key::estimate_size(key.length()));
+ return;
+ }
+
+ const UInt32 src_offset = trie.ith_node(src).offset();
+ UInt32 dest_offset;
+ {
+ UInt16 labels[MAX_LABEL + 1];
+ UInt32 num_labels = 0;
+
+ UInt32 label = trie.ith_node(src).child();
+ while (label != INVALID_LABEL) {
+ GRN_DAT_DEBUG_THROW_IF(label > MAX_LABEL);
+ const UInt32 child = src_offset ^ label;
+ if (trie.ith_node(child).is_linker() ||
+ (trie.ith_node(child).child() != INVALID_LABEL)) {
+ labels[num_labels++] = label;
+ }
+ label = trie.ith_node(child).sibling();
+ }
+ if (num_labels == 0) {
+ return;
+ }
+
+ dest_offset = find_offset(labels, num_labels);
+ for (UInt32 i = 0; i < num_labels; ++i) {
+ const UInt32 child = dest_offset ^ labels[i];
+ reserve_node(child);
+ ith_node(child).set_label(labels[i]);
+ if ((i + 1) < num_labels) {
+ ith_node(child).set_sibling(labels[i + 1]);
+ }
+ }
+
+ GRN_DAT_DEBUG_THROW_IF(ith_node(dest_offset).is_offset());
+ ith_node(dest_offset).set_is_offset(true);
+ ith_node(dest).set_offset(dest_offset);
+ ith_node(dest).set_child(labels[0]);
+ }
+
+ UInt32 label = ith_node(dest).child();
+ while (label != INVALID_LABEL) {
+ build_from_trie(trie, src_offset ^ label, dest_offset ^ label);
+ label = ith_node(dest_offset ^ label).sibling();
+ }
+}
+
+void Trie::repair_trie(const Trie &trie) {
+ Vector<UInt32> valid_ids;
+ header_->set_max_key_id(trie.max_key_id());
+ header_->set_next_key_id(trie.max_key_id() + 1);
+ UInt32 prev_invalid_key_id = INVALID_KEY_ID;
+ for (UInt32 i = min_key_id(); i <= max_key_id(); ++i) {
+ const Entry &entry = trie.ith_entry(i);
+ if (entry.is_valid()) {
+ valid_ids.push_back(i);
+ ith_entry(i) = entry;
+ const Key &key = trie.get_key(entry.key_pos());
+ Key::create(key_buf_.ptr() + next_key_pos(),
+ key.id(), key.ptr(), key.length());
+ ith_entry(i).set_key_pos(next_key_pos());
+ header_->set_next_key_pos(
+ next_key_pos() + Key::estimate_size(key.length()));
+ header_->set_total_key_length(
+ total_key_length() + key.length());
+ header_->set_num_keys(num_keys() + 1);
+ } else {
+ if (prev_invalid_key_id == INVALID_KEY_ID) {
+ header_->set_next_key_id(i);
+ } else {
+ ith_entry(prev_invalid_key_id).set_next(i);
+ }
+ prev_invalid_key_id = i;
+ }
+ }
+ if (prev_invalid_key_id != INVALID_KEY_ID) {
+ ith_entry(prev_invalid_key_id).set_next(max_key_id() + 1);
+ }
+ mkq_sort(valid_ids.begin(), valid_ids.end(), 0);
+ build_from_keys(valid_ids.begin(), valid_ids.end(), 0, ROOT_NODE_ID);
+}
+
+void Trie::build_from_keys(const UInt32 *begin, const UInt32 *end,
+ UInt32 depth, UInt32 node_id) {
+ if ((end - begin) == 1) {
+ ith_node(node_id).set_key_pos(ith_entry(*begin).key_pos());
+ return;
+ }
+
+ UInt32 offset;
+ {
+ UInt16 labels[MAX_LABEL + 2];
+ UInt32 num_labels = 0;
+
+ const UInt32 *it = begin;
+ if (ith_key(*it).length() == depth) {
+ labels[num_labels++] = TERMINAL_LABEL;
+ ++it;
+ }
+
+ labels[num_labels++] = (UInt8)ith_key(*it)[depth];
+ for (++it; it < end; ++it) {
+ const Key &key = ith_key(*it);
+ if ((UInt8)key[depth] != labels[num_labels - 1]) {
+ labels[num_labels++] = (UInt8)key[depth];
+ }
+ }
+ labels[num_labels] = INVALID_LABEL;
+
+ offset = find_offset(labels, num_labels);
+ ith_node(node_id).set_child(labels[0]);
+ for (UInt32 i = 0; i < num_labels; ++i) {
+ const UInt32 next = offset ^ labels[i];
+ reserve_node(next);
+ ith_node(next).set_label(labels[i]);
+ ith_node(next).set_sibling(labels[i + 1]);
+ }
+
+ if (offset >= num_nodes()) {
+ reserve_block(num_blocks());
+ }
+ ith_node(offset).set_is_offset(true);
+ ith_node(node_id).set_offset(offset);
+ }
+
+ if (ith_key(*begin).length() == depth) {
+ build_from_keys(begin, begin + 1, depth + 1, offset ^ TERMINAL_LABEL);
+ ++begin;
+ }
+
+ UInt16 label = ith_key(*begin)[depth];
+ for (const UInt32 *it = begin + 1; it < end; ++it) {
+ const Key &key = ith_key(*it);
+ if ((UInt8)key[depth] != label) {
+ build_from_keys(begin, it, depth + 1, offset ^ label);
+ label = (UInt8)key[depth];
+ begin = it;
+ }
+ }
+ build_from_keys(begin, end, depth + 1, offset ^ label);
+}
+
+void Trie::mkq_sort(UInt32 *l, UInt32 *r, UInt32 depth) {
+ while ((r - l) >= MKQ_SORT_THRESHOLD) {
+ UInt32 *pl = l;
+ UInt32 *pr = r;
+ UInt32 *pivot_l = l;
+ UInt32 *pivot_r = r;
+
+ const int pivot = get_median(*l, *(l + (r - l) / 2), *(r - 1), depth);
+ for ( ; ; ) {
+ while (pl < pr) {
+ const int label = get_label(*pl, depth);
+ if (label > pivot) {
+ break;
+ } else if (label == pivot) {
+ swap_ids(pl, pivot_l);
+ ++pivot_l;
+ }
+ ++pl;
+ }
+ while (pl < pr) {
+ const int label = get_label(*--pr, depth);
+ if (label < pivot) {
+ break;
+ } else if (label == pivot) {
+ swap_ids(pr, --pivot_r);
+ }
+ }
+ if (pl >= pr) {
+ break;
+ }
+ swap_ids(pl, pr);
+ ++pl;
+ }
+ while (pivot_l > l) {
+ swap_ids(--pivot_l, --pl);
+ }
+ while (pivot_r < r) {
+ swap_ids(pivot_r, pr);
+ ++pivot_r;
+ ++pr;
+ }
+
+ if (((pl - l) > (pr - pl)) || ((r - pr) > (pr - pl))) {
+ if ((pr - pl) > 1) {
+ mkq_sort(pl, pr, depth + 1);
+ }
+
+ if ((pl - l) < (r - pr)) {
+ if ((pl - l) > 1) {
+ mkq_sort(l, pl, depth);
+ }
+ l = pr;
+ } else {
+ if ((r - pr) > 1) {
+ mkq_sort(pr, r, depth);
+ }
+ r = pl;
+ }
+ } else {
+ if ((pl - l) > 1) {
+ mkq_sort(l, pl, depth);
+ }
+
+ if ((r - pr) > 1) {
+ mkq_sort(pr, r, depth);
+ }
+
+ l = pl, r = pr;
+ if ((pr - pl) > 1) {
+ ++depth;
+ }
+ }
+ }
+
+ if ((r - l) > 1) {
+ insertion_sort(l, r, depth);
+ }
+}
+
+void Trie::insertion_sort(UInt32 *l, UInt32 *r, UInt32 depth) {
+ for (UInt32 *i = l + 1; i < r; ++i) {
+ for (UInt32 *j = i; j > l; --j) {
+ if (less_than(*(j - 1), *j, depth)) {
+ break;
+ }
+ swap_ids(j - 1, j);
+ }
+ }
+}
+
+int Trie::get_median(UInt32 a, UInt32 b, UInt32 c, UInt32 depth) const {
+ const int x = get_label(a, depth);
+ const int y = get_label(b, depth);
+ const int z = get_label(c, depth);
+ if (x < y) {
+ if (y < z) {
+ return y;
+ } else if (x < z) {
+ return z;
+ }
+ return x;
+ } else if (x < z) {
+ return x;
+ } else if (y < z) {
+ return z;
+ }
+ return y;
+}
+
+int Trie::get_label(UInt32 key_id, UInt32 depth) const {
+ const Key &key = ith_key(key_id);
+ if (depth == key.length()) {
+ return -1;
+ } else {
+ return (UInt8)key[depth];
+ }
+}
+
+bool Trie::less_than(UInt32 lhs, UInt32 rhs, UInt32 depth) const {
+ const Key &lhs_key = ith_key(lhs);
+ const Key &rhs_key = ith_key(rhs);
+ const UInt32 length = (lhs_key.length() < rhs_key.length()) ?
+ lhs_key.length() : rhs_key.length();
+ for (UInt32 i = depth; i < length; ++i) {
+ if (lhs_key[i] != rhs_key[i]) {
+ return (UInt8)lhs_key[i] < (UInt8)rhs_key[i];
+ }
+ }
+ return lhs_key.length() < rhs_key.length();
+}
+
+void Trie::swap_ids(UInt32 *lhs, UInt32 *rhs) {
+ UInt32 temp = *lhs;
+ *lhs = *rhs;
+ *rhs = temp;
+}
+
+bool Trie::search_key(const UInt8 *ptr, UInt32 length, UInt32 *key_pos) const {
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0));
+
+ UInt32 node_id = ROOT_NODE_ID;
+ UInt32 query_pos = 0;
+ if (!search_linker(ptr, length, node_id, query_pos)) {
+ return false;
+ }
+
+ const Base base = ith_node(node_id).base();
+ if (!base.is_linker()) {
+ return false;
+ }
+
+ if (get_key(base.key_pos()).equals_to(ptr, length, query_pos)) {
+ if (key_pos != NULL) {
+ *key_pos = base.key_pos();
+ }
+ return true;
+ }
+ return false;
+}
+
+bool Trie::search_linker(const UInt8 *ptr, UInt32 length,
+ UInt32 &node_id, UInt32 &query_pos) const {
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0));
+
+ for ( ; query_pos < length; ++query_pos) {
+ const Base base = ith_node(node_id).base();
+ if (base.is_linker()) {
+ return true;
+ }
+
+ const UInt32 next = base.offset() ^ ptr[query_pos];
+ if (ith_node(next).label() != ptr[query_pos]) {
+ return false;
+ }
+ node_id = next;
+ }
+
+ const Base base = ith_node(node_id).base();
+ if (base.is_linker()) {
+ return true;
+ }
+
+ const UInt32 next = base.offset() ^ TERMINAL_LABEL;
+ if (ith_node(next).label() != TERMINAL_LABEL) {
+ return false;
+ }
+ node_id = next;
+ return ith_node(next).is_linker();
+}
+
+bool Trie::lcp_search_key(const UInt8 *ptr, UInt32 length,
+ UInt32 *key_pos) const {
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0));
+
+ bool found = false;
+ UInt32 node_id = ROOT_NODE_ID;
+ UInt32 query_pos = 0;
+
+ for ( ; query_pos < length; ++query_pos) {
+ const Base base = ith_node(node_id).base();
+ if (base.is_linker()) {
+ const Key &key = get_key(base.key_pos());
+ if ((key.length() <= length) &&
+ key.equals_to(ptr, key.length(), query_pos)) {
+ if (key_pos != NULL) {
+ *key_pos = base.key_pos();
+ }
+ found = true;
+ }
+ return found;
+ }
+
+ if (ith_node(node_id).child() == TERMINAL_LABEL) {
+ const Base linker_base =
+ ith_node(base.offset() ^ TERMINAL_LABEL).base();
+ if (linker_base.is_linker()) {
+ if (key_pos != NULL) {
+ *key_pos = linker_base.key_pos();
+ }
+ found = true;
+ }
+ }
+
+ node_id = base.offset() ^ ptr[query_pos];
+ if (ith_node(node_id).label() != ptr[query_pos]) {
+ return found;
+ }
+ }
+
+ const Base base = ith_node(node_id).base();
+ if (base.is_linker()) {
+ const Key &key = get_key(base.key_pos());
+ if (key.length() <= length) {
+ if (key_pos != NULL) {
+ *key_pos = base.key_pos();
+ }
+ found = true;
+ }
+ } else if (ith_node(node_id).child() == TERMINAL_LABEL) {
+ const Base linker_base = ith_node(base.offset() ^ TERMINAL_LABEL).base();
+ if (linker_base.is_linker()) {
+ if (key_pos != NULL) {
+ *key_pos = linker_base.key_pos();
+ }
+ found = true;
+ }
+ }
+ return found;
+}
+
+bool Trie::remove_key(const UInt8 *ptr, UInt32 length) {
+ GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0);
+ StatusFlagManager status_flag_manager(header_, REMOVING_FLAG);
+
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0));
+
+ UInt32 node_id = ROOT_NODE_ID;
+ UInt32 query_pos = 0;
+ if (!search_linker(ptr, length, node_id, query_pos)) {
+ return false;
+ }
+
+ const UInt32 key_pos = ith_node(node_id).key_pos();
+ if (!get_key(key_pos).equals_to(ptr, length, query_pos)) {
+ return false;
+ }
+
+ const UInt32 key_id = get_key(key_pos).id();
+ ith_node(node_id).set_offset(INVALID_OFFSET);
+ ith_entry(key_id).set_next(next_key_id());
+
+ header_->set_next_key_id(key_id);
+ header_->set_total_key_length(total_key_length() - length);
+ header_->set_num_keys(num_keys() - 1);
+ return true;
+}
+
+bool Trie::insert_key(const UInt8 *ptr, UInt32 length, UInt32 *key_pos) {
+ GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0);
+ StatusFlagManager status_flag_manager(header_, INSERTING_FLAG);
+
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0));
+
+ UInt32 node_id = ROOT_NODE_ID;
+ UInt32 query_pos = 0;
+
+ search_linker(ptr, length, node_id, query_pos);
+ if (!insert_linker(ptr, length, node_id, query_pos)) {
+ if (key_pos != NULL) {
+ *key_pos = ith_node(node_id).key_pos();
+ }
+ return false;
+ }
+
+ const UInt32 new_key_id = next_key_id();
+ const UInt32 new_key_pos = append_key(ptr, length, new_key_id);
+
+ header_->set_total_key_length(total_key_length() + length);
+ header_->set_num_keys(num_keys() + 1);
+ if (new_key_id > max_key_id()) {
+ header_->set_max_key_id(new_key_id);
+ header_->set_next_key_id(new_key_id + 1);
+ } else {
+ header_->set_next_key_id(ith_entry(new_key_id).next());
+ }
+
+ ith_entry(new_key_id).set_key_pos(new_key_pos);
+ ith_node(node_id).set_key_pos(new_key_pos);
+ if (key_pos != NULL) {
+ *key_pos = new_key_pos;
+ }
+ return true;
+}
+
+bool Trie::insert_linker(const UInt8 *ptr, UInt32 length,
+ UInt32 &node_id, UInt32 query_pos) {
+ if (ith_node(node_id).is_linker()) {
+ const Key &key = get_key(ith_node(node_id).key_pos());
+ UInt32 i = query_pos;
+ while ((i < length) && (i < key.length())) {
+ if (ptr[i] != key[i]) {
+ break;
+ }
+ ++i;
+ }
+ if ((i == length) && (i == key.length())) {
+ return false;
+ }
+ GRN_DAT_THROW_IF(SIZE_ERROR, num_keys() >= max_num_keys());
+ GRN_DAT_DEBUG_THROW_IF(next_key_id() > max_num_keys());
+
+ for (UInt32 j = query_pos; j < i; ++j) {
+ node_id = insert_node(node_id, ptr[j]);
+ }
+ node_id = separate(ptr, length, node_id, i);
+ return true;
+ } else if (ith_node(node_id).label() == TERMINAL_LABEL) {
+ return true;
+ } else {
+ GRN_DAT_THROW_IF(SIZE_ERROR, num_keys() >= max_num_keys());
+ const UInt16 label = (query_pos < length) ?
+ (UInt16)ptr[query_pos] : (UInt16)TERMINAL_LABEL;
+ const Base base = ith_node(node_id).base();
+ if ((base.offset() == INVALID_OFFSET) ||
+ !ith_node(base.offset() ^ label).is_phantom()) {
+ resolve(node_id, label);
+ }
+ node_id = insert_node(node_id, label);
+ return true;
+ }
+}
+
+bool Trie::update_key(const Key &key, const UInt8 *ptr, UInt32 length,
+ UInt32 *key_pos) {
+ GRN_DAT_THROW_IF(STATUS_ERROR, (status_flags() & CHANGING_MASK) != 0);
+ StatusFlagManager status_flag_manager(header_, UPDATING_FLAG);
+
+ GRN_DAT_DEBUG_THROW_IF((ptr == NULL) && (length != 0));
+
+ if (!key.is_valid()) {
+ return false;
+ }
+
+ UInt32 node_id = ROOT_NODE_ID;
+ UInt32 query_pos = 0;
+
+ search_linker(ptr, length, node_id, query_pos);
+ if (!insert_linker(ptr, length, node_id, query_pos)) {
+ if (key_pos != NULL) {
+ *key_pos = ith_node(node_id).key_pos();
+ }
+ return false;
+ }
+
+ const UInt32 new_key_pos = append_key(ptr, length, key.id());
+ header_->set_total_key_length(total_key_length() + length - key.length());
+ ith_entry(key.id()).set_key_pos(new_key_pos);
+ ith_node(node_id).set_key_pos(new_key_pos);
+ if (key_pos != NULL) {
+ *key_pos = new_key_pos;
+ }
+
+ node_id = ROOT_NODE_ID;
+ query_pos = 0;
+ GRN_DAT_THROW_IF(UNEXPECTED_ERROR,
+ !search_linker(static_cast<const UInt8 *>(key.ptr()), key.length(),
+ node_id, query_pos));
+ ith_node(node_id).set_offset(INVALID_OFFSET);
+ return true;
+}
+
+UInt32 Trie::insert_node(UInt32 node_id, UInt16 label) {
+ GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes());
+ GRN_DAT_DEBUG_THROW_IF(label > MAX_LABEL);
+
+ const Base base = ith_node(node_id).base();
+ UInt32 offset;
+ if (base.is_linker() || (base.offset() == INVALID_OFFSET)) {
+ offset = find_offset(&label, 1);
+ } else {
+ offset = base.offset();
+ }
+
+ const UInt32 next = offset ^ label;
+ reserve_node(next);
+
+ ith_node(next).set_label(label);
+ if (base.is_linker()) {
+ GRN_DAT_DEBUG_THROW_IF(ith_node(offset).is_offset());
+ ith_node(offset).set_is_offset(true);
+ ith_node(next).set_key_pos(base.key_pos());
+ } else if (base.offset() == INVALID_OFFSET) {
+ GRN_DAT_DEBUG_THROW_IF(ith_node(offset).is_offset());
+ ith_node(offset).set_is_offset(true);
+ } else {
+ GRN_DAT_DEBUG_THROW_IF(!ith_node(offset).is_offset());
+ }
+ ith_node(node_id).set_offset(offset);
+
+ const UInt32 child_label = ith_node(node_id).child();
+ GRN_DAT_DEBUG_THROW_IF(child_label == label);
+ if (child_label == INVALID_LABEL) {
+ ith_node(node_id).set_child(label);
+ } else if ((label == TERMINAL_LABEL) ||
+ ((child_label != TERMINAL_LABEL) && (label < child_label))) {
+ GRN_DAT_DEBUG_THROW_IF(ith_node(offset ^ child_label).is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(ith_node(offset ^ child_label).label() != child_label);
+ ith_node(next).set_sibling(child_label);
+ ith_node(node_id).set_child(label);
+ } else {
+ UInt32 prev = offset ^ child_label;
+ GRN_DAT_DEBUG_THROW_IF(ith_node(prev).label() != child_label);
+ UInt32 sibling_label = ith_node(prev).sibling();
+ while (label > sibling_label) {
+ prev = offset ^ sibling_label;
+ GRN_DAT_DEBUG_THROW_IF(ith_node(prev).label() != sibling_label);
+ sibling_label = ith_node(prev).sibling();
+ }
+ GRN_DAT_DEBUG_THROW_IF(label == sibling_label);
+ ith_node(next).set_sibling(ith_node(prev).sibling());
+ ith_node(prev).set_sibling(label);
+ }
+ return next;
+}
+
+UInt32 Trie::append_key(const UInt8 *ptr, UInt32 length, UInt32 key_id) {
+ GRN_DAT_THROW_IF(SIZE_ERROR, key_id > max_num_keys());
+
+ const UInt32 key_pos = next_key_pos();
+ const UInt32 key_size = Key::estimate_size(length);
+
+ GRN_DAT_THROW_IF(SIZE_ERROR, key_size > (key_buf_size() - key_pos));
+ Key::create(key_buf_.ptr() + key_pos, key_id, ptr, length);
+
+ header_->set_next_key_pos(key_pos + key_size);
+ return key_pos;
+}
+
+UInt32 Trie::separate(const UInt8 *ptr, UInt32 length,
+ UInt32 node_id, UInt32 i) {
+ GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes());
+ GRN_DAT_DEBUG_THROW_IF(!ith_node(node_id).is_linker());
+ GRN_DAT_DEBUG_THROW_IF(i > length);
+
+ const UInt32 key_pos = ith_node(node_id).key_pos();
+ const Key &key = get_key(key_pos);
+
+ UInt16 labels[2];
+ labels[0] = (i < key.length()) ? (UInt16)key[i] : (UInt16)TERMINAL_LABEL;
+ labels[1] = (i < length) ? (UInt16)ptr[i] : (UInt16)TERMINAL_LABEL;
+ GRN_DAT_DEBUG_THROW_IF(labels[0] == labels[1]);
+
+ const UInt32 offset = find_offset(labels, 2);
+
+ UInt32 next = offset ^ labels[0];
+ reserve_node(next);
+ GRN_DAT_DEBUG_THROW_IF(ith_node(offset).is_offset());
+
+ ith_node(next).set_label(labels[0]);
+ ith_node(next).set_key_pos(key_pos);
+
+ next = offset ^ labels[1];
+ reserve_node(next);
+
+ ith_node(next).set_label(labels[1]);
+
+ ith_node(offset).set_is_offset(true);
+ ith_node(node_id).set_offset(offset);
+
+ if ((labels[0] == TERMINAL_LABEL) ||
+ ((labels[1] != TERMINAL_LABEL) && (labels[0] < labels[1]))) {
+ ith_node(node_id).set_child(labels[0]);
+ ith_node(offset ^ labels[0]).set_sibling(labels[1]);
+ } else {
+ ith_node(node_id).set_child(labels[1]);
+ ith_node(offset ^ labels[1]).set_sibling(labels[0]);
+ }
+ return next;
+}
+
+void Trie::resolve(UInt32 node_id, UInt16 label) {
+ GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes());
+ GRN_DAT_DEBUG_THROW_IF(ith_node(node_id).is_linker());
+ GRN_DAT_DEBUG_THROW_IF(label > MAX_LABEL);
+
+ UInt32 offset = ith_node(node_id).offset();
+ if (offset != INVALID_OFFSET) {
+ UInt16 labels[MAX_LABEL + 1];
+ UInt32 num_labels = 0;
+
+ UInt32 next_label = ith_node(node_id).child();
+ GRN_DAT_DEBUG_THROW_IF(next_label == INVALID_LABEL);
+ while (next_label != INVALID_LABEL) {
+ GRN_DAT_DEBUG_THROW_IF(next_label > MAX_LABEL);
+ labels[num_labels++] = next_label;
+ next_label = ith_node(offset ^ next_label).sibling();
+ }
+ GRN_DAT_DEBUG_THROW_IF(num_labels == 0);
+
+ labels[num_labels] = label;
+ offset = find_offset(labels, num_labels + 1);
+ migrate_nodes(node_id, offset, labels, num_labels);
+ } else {
+ offset = find_offset(&label, 1);
+ if (offset >= num_nodes()) {
+ GRN_DAT_DEBUG_THROW_IF((offset / BLOCK_SIZE) != num_blocks());
+ reserve_block(num_blocks());
+ }
+ ith_node(offset).set_is_offset(true);
+ ith_node(node_id).set_offset(offset);
+ }
+}
+
+void Trie::migrate_nodes(UInt32 node_id, UInt32 dest_offset,
+ const UInt16 *labels, UInt32 num_labels) {
+ GRN_DAT_DEBUG_THROW_IF(node_id >= num_nodes());
+ GRN_DAT_DEBUG_THROW_IF(ith_node(node_id).is_linker());
+ GRN_DAT_DEBUG_THROW_IF(labels == NULL);
+ GRN_DAT_DEBUG_THROW_IF(num_labels == 0);
+ GRN_DAT_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1));
+
+ const UInt32 src_offset = ith_node(node_id).offset();
+ GRN_DAT_DEBUG_THROW_IF(src_offset == INVALID_OFFSET);
+ GRN_DAT_DEBUG_THROW_IF(!ith_node(src_offset).is_offset());
+
+ for (UInt32 i = 0; i < num_labels; ++i) {
+ const UInt32 src_node_id = src_offset ^ labels[i];
+ const UInt32 dest_node_id = dest_offset ^ labels[i];
+ GRN_DAT_DEBUG_THROW_IF(ith_node(src_node_id).is_phantom());
+ GRN_DAT_DEBUG_THROW_IF(ith_node(src_node_id).label() != labels[i]);
+
+ reserve_node(dest_node_id);
+ ith_node(dest_node_id).set_except_is_offset(
+ ith_node(src_node_id).except_is_offset());
+ ith_node(dest_node_id).set_base(ith_node(src_node_id).base());
+ }
+ header_->set_num_zombies(num_zombies() + num_labels);
+
+ GRN_DAT_DEBUG_THROW_IF(ith_node(dest_offset).is_offset());
+ ith_node(dest_offset).set_is_offset(true);
+ ith_node(node_id).set_offset(dest_offset);
+}
+
+UInt32 Trie::find_offset(const UInt16 *labels, UInt32 num_labels) {
+ GRN_DAT_DEBUG_THROW_IF(labels == NULL);
+ GRN_DAT_DEBUG_THROW_IF(num_labels == 0);
+ GRN_DAT_DEBUG_THROW_IF(num_labels > (MAX_LABEL + 1));
+
+ // Blocks are tested in descending order of level. Basically, a lower level
+ // block contains more phantom nodes.
+ UInt32 level = 1;
+ while (num_labels >= (1U << level)) {
+ ++level;
+ }
+ level = (level < MAX_BLOCK_LEVEL) ? (MAX_BLOCK_LEVEL - level) : 0;
+
+ UInt32 block_count = 0;
+ do {
+ UInt32 leader = header_->ith_leader(level);
+ if (leader == INVALID_LEADER) {
+ // This level has no blocks and it is thus skipped.
+ continue;
+ }
+
+ UInt32 block_id = leader;
+ do {
+ const Block &block = ith_block(block_id);
+ GRN_DAT_DEBUG_THROW_IF(block.level() != level);
+
+ const UInt32 first = (block_id * BLOCK_SIZE) | block.first_phantom();
+ UInt32 node_id = first;
+ do {
+ GRN_DAT_DEBUG_THROW_IF(!ith_node(node_id).is_phantom());
+ const UInt32 offset = node_id ^ labels[0];
+ if (!ith_node(offset).is_offset()) {
+ UInt32 i = 1;
+ for ( ; i < num_labels; ++i) {
+ if (!ith_node(offset ^ labels[i]).is_phantom()) {
+ break;
+ }
+ }
+ if (i >= num_labels) {
+ return offset;
+ }
+ }
+ node_id = (block_id * BLOCK_SIZE) | ith_node(node_id).next();
+ } while (node_id != first);
+
+ const UInt32 prev = block_id;
+ const UInt32 next = block.next();
+ block_id = next;
+ ith_block(prev).set_failure_count(ith_block(prev).failure_count() + 1);
+
+ // The level of a block is updated when this function fails many times,
+ // actually MAX_FAILURE_COUNT times, in that block.
+ if (ith_block(prev).failure_count() == MAX_FAILURE_COUNT) {
+ update_block_level(prev, level + 1);
+ if (next == leader) {
+ break;
+ } else {
+ // Note that the leader might be updated in the level update.
+ leader = header_->ith_leader(level);
+ continue;
+ }
+ }
+ } while ((++block_count < MAX_BLOCK_COUNT) && (block_id != leader));
+ } while ((block_count < MAX_BLOCK_COUNT) && (level-- != 0));
+
+ return num_nodes() ^ labels[0];
+}
+
+void Trie::reserve_node(UInt32 node_id) {
+ GRN_DAT_DEBUG_THROW_IF(node_id > num_nodes());
+ if (node_id >= num_nodes()) {
+ reserve_block(node_id / BLOCK_SIZE);
+ }
+
+ Node &node = ith_node(node_id);
+ GRN_DAT_DEBUG_THROW_IF(!node.is_phantom());
+
+ const UInt32 block_id = node_id / BLOCK_SIZE;
+ Block &block = ith_block(block_id);
+ GRN_DAT_DEBUG_THROW_IF(block.num_phantoms() == 0);
+
+ const UInt32 next = (block_id * BLOCK_SIZE) | node.next();
+ const UInt32 prev = (block_id * BLOCK_SIZE) | node.prev();
+ GRN_DAT_DEBUG_THROW_IF(next >= num_nodes());
+ GRN_DAT_DEBUG_THROW_IF(prev >= num_nodes());
+
+ if ((node_id & BLOCK_MASK) == block.first_phantom()) {
+ // The first phantom node is removed from the block and the second phantom
+ // node comes first.
+ block.set_first_phantom(next & BLOCK_MASK);
+ }
+
+ ith_node(next).set_prev(prev & BLOCK_MASK);
+ ith_node(prev).set_next(next & BLOCK_MASK);
+
+ if (block.level() != MAX_BLOCK_LEVEL) {
+ const UInt32 threshold = 1U << ((MAX_BLOCK_LEVEL - block.level() - 1) * 2);
+ if (block.num_phantoms() == threshold) {
+ update_block_level(block_id, block.level() + 1);
+ }
+ }
+ block.set_num_phantoms(block.num_phantoms() - 1);
+
+ node.set_is_phantom(false);
+
+ GRN_DAT_DEBUG_THROW_IF(node.offset() != INVALID_OFFSET);
+ GRN_DAT_DEBUG_THROW_IF(node.label() != INVALID_LABEL);
+
+ header_->set_num_phantoms(num_phantoms() - 1);
+}
+
+void Trie::reserve_block(UInt32 block_id) {
+ GRN_DAT_DEBUG_THROW_IF(block_id != num_blocks());
+ GRN_DAT_THROW_IF(SIZE_ERROR, block_id >= max_num_blocks());
+
+ header_->set_num_blocks(block_id + 1);
+ ith_block(block_id).set_failure_count(0);
+ ith_block(block_id).set_first_phantom(0);
+ ith_block(block_id).set_num_phantoms(BLOCK_SIZE);
+
+ const UInt32 begin = block_id * BLOCK_SIZE;
+ const UInt32 end = begin + BLOCK_SIZE;
+ GRN_DAT_DEBUG_THROW_IF(end != num_nodes());
+
+ Base base;
+ base.set_offset(INVALID_OFFSET);
+
+ Check check;
+ check.set_is_phantom(true);
+
+ for (UInt32 i = begin; i < end; ++i) {
+ check.set_prev((i - 1) & BLOCK_MASK);
+ check.set_next((i + 1) & BLOCK_MASK);
+ ith_node(i).set_base(base);
+ ith_node(i).set_check(check);
+ }
+
+ // The level of the new block is 0.
+ set_block_level(block_id, 0);
+ header_->set_num_phantoms(num_phantoms() + BLOCK_SIZE);
+}
+
+void Trie::update_block_level(UInt32 block_id, UInt32 level) {
+ GRN_DAT_DEBUG_THROW_IF(block_id >= num_blocks());
+ GRN_DAT_DEBUG_THROW_IF(level > MAX_BLOCK_LEVEL);
+
+ unset_block_level(block_id);
+ set_block_level(block_id, level);
+}
+
+void Trie::set_block_level(UInt32 block_id, UInt32 level) {
+ GRN_DAT_DEBUG_THROW_IF(block_id >= num_blocks());
+ GRN_DAT_DEBUG_THROW_IF(level > MAX_BLOCK_LEVEL);
+
+ const UInt32 leader = header_->ith_leader(level);
+ if (leader == INVALID_LEADER) {
+ // The new block becomes the only one block of the linked list.
+ ith_block(block_id).set_next(block_id);
+ ith_block(block_id).set_prev(block_id);
+ header_->set_ith_leader(level, block_id);
+ } else {
+ // The new block is added to the end of the list.
+ const UInt32 next = leader;
+ const UInt32 prev = ith_block(leader).prev();
+ GRN_DAT_DEBUG_THROW_IF(next >= num_blocks());
+ GRN_DAT_DEBUG_THROW_IF(prev >= num_blocks());
+ ith_block(block_id).set_next(next);
+ ith_block(block_id).set_prev(prev);
+ ith_block(next).set_prev(block_id);
+ ith_block(prev).set_next(block_id);
+ }
+ ith_block(block_id).set_level(level);
+ ith_block(block_id).set_failure_count(0);
+}
+
+void Trie::unset_block_level(UInt32 block_id) {
+ GRN_DAT_DEBUG_THROW_IF(block_id >= num_blocks());
+
+ const UInt32 level = ith_block(block_id).level();
+ GRN_DAT_DEBUG_THROW_IF(level > MAX_BLOCK_LEVEL);
+
+ const UInt32 leader = header_->ith_leader(level);
+ GRN_DAT_DEBUG_THROW_IF(leader == INVALID_LEADER);
+
+ const UInt32 next = ith_block(block_id).next();
+ const UInt32 prev = ith_block(block_id).prev();
+ GRN_DAT_DEBUG_THROW_IF(next >= num_blocks());
+ GRN_DAT_DEBUG_THROW_IF(prev >= num_blocks());
+
+ if (next == block_id) {
+ // The linked list becomes empty.
+ header_->set_ith_leader(level, INVALID_LEADER);
+ } else {
+ ith_block(next).set_prev(prev);
+ ith_block(prev).set_next(next);
+ if (block_id == leader) {
+ // The second block becomes the leader of the linked list.
+ header_->set_ith_leader(level, next);
+ }
+ }
+}
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/trie.hpp b/storage/mroonga/vendor/groonga/lib/dat/trie.hpp
new file mode 100644
index 00000000..bf7d0b98
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/trie.hpp
@@ -0,0 +1,285 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "array.hpp"
+#include "header.hpp"
+#include "node.hpp"
+#include "block.hpp"
+#include "entry.hpp"
+#include "key.hpp"
+#include "file.hpp"
+
+namespace grn {
+namespace dat {
+
+class GRN_DAT_API Trie {
+ public:
+ Trie();
+ ~Trie();
+
+ void create(const char *file_name = NULL,
+ UInt64 file_size = 0,
+ UInt32 max_num_keys = 0,
+ double num_nodes_per_key = 0.0,
+ double average_key_length = 0.0);
+
+ void create(const Trie &trie,
+ const char *file_name = NULL,
+ UInt64 file_size = 0,
+ UInt32 max_num_keys = 0,
+ double num_nodes_per_key = 0.0,
+ double average_key_length = 0.0);
+
+ void repair(const Trie &trie, const char *file_name = NULL);
+
+ void open(const char *file_name);
+ void close();
+
+ void swap(Trie *trie);
+
+ // Users can access a key by its position or ID.
+ const Key &get_key(UInt32 key_pos) const {
+ GRN_DAT_DEBUG_THROW_IF(key_pos >= next_key_pos());
+ return *reinterpret_cast<const Key *>(key_buf_.ptr() + key_pos);
+ }
+ // If a specified ID is invalid, e.g. the key is already deleted, this
+ // function returns a reference to an invalid key object whose id() returns
+ // INVALID_KEY_ID.
+ const Key &ith_key(UInt32 key_id) const {
+ if ((key_id >= min_key_id()) && (key_id <= max_key_id()) &&
+ ith_entry(key_id).is_valid()) {
+ return get_key(ith_entry(key_id).key_pos());
+ }
+ return Key::invalid_key();
+ }
+
+ bool search(const void *ptr, UInt32 length, UInt32 *key_pos = NULL) const {
+ return search_key(static_cast<const UInt8 *>(ptr), length, key_pos);
+ }
+ // Longest prefix match search.
+ bool lcp_search(const void *ptr, UInt32 length,
+ UInt32 *key_pos = NULL) const {
+ return lcp_search_key(static_cast<const UInt8 *>(ptr), length, key_pos);
+ }
+
+ bool remove(UInt32 key_id) {
+ const Key &key = ith_key(key_id);
+ if (key.is_valid()) {
+ return remove(key.ptr(), key.length());
+ }
+ return false;
+ }
+ bool remove(const void *ptr, UInt32 length) {
+ return remove_key(static_cast<const UInt8 *>(ptr), length);
+ }
+
+ bool insert(const void *ptr, UInt32 length, UInt32 *key_pos = NULL) {
+ return insert_key(static_cast<const UInt8 *>(ptr), length, key_pos);
+ }
+
+ bool update(UInt32 key_id, const void *ptr, UInt32 length,
+ UInt32 *key_pos = NULL) {
+ return update_key(ith_key(key_id), static_cast<const UInt8 *>(ptr),
+ length, key_pos);
+ }
+ bool update(const void *src_ptr, UInt32 src_length,
+ const void *dest_ptr, UInt32 dest_length,
+ UInt32 *key_pos = NULL) {
+ UInt32 src_key_pos;
+ if (!search(src_ptr, src_length, &src_key_pos)) {
+ return false;
+ }
+ const Key &src_key = get_key(src_key_pos);
+ return update_key(src_key, static_cast<const UInt8 *>(dest_ptr),
+ dest_length, key_pos);
+ }
+
+ const Node &ith_node(UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i >= num_nodes());
+ return nodes_[i];
+ }
+ const Block &ith_block(UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i >= num_blocks());
+ return blocks_[i];
+ }
+ const Entry &ith_entry(UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i < min_key_id());
+ GRN_DAT_DEBUG_THROW_IF(i > max_key_id());
+ return entries_[i];
+ }
+
+ const Header &header() const {
+ return *header_;
+ }
+
+ UInt64 file_size() const {
+ return header_->file_size();
+ }
+ UInt64 virtual_size() const {
+ return sizeof(Header)
+ + (sizeof(Entry) * num_keys())
+ + (sizeof(Block) * num_blocks())
+ + (sizeof(Node) * num_nodes())
+ + total_key_length();
+ }
+ UInt32 total_key_length() const {
+ return header_->total_key_length();
+ }
+ UInt32 num_keys() const {
+ return header_->num_keys();
+ }
+ UInt32 min_key_id() const {
+ return header_->min_key_id();
+ }
+ UInt32 next_key_id() const {
+ return header_->next_key_id();
+ }
+ UInt32 max_key_id() const {
+ return header_->max_key_id();
+ }
+ UInt32 max_num_keys() const {
+ return header_->max_num_keys();
+ }
+ UInt32 num_nodes() const {
+ return header_->num_nodes();
+ }
+ UInt32 num_phantoms() const {
+ return header_->num_phantoms();
+ }
+ UInt32 num_zombies() const {
+ return header_->num_zombies();
+ }
+ UInt32 max_num_nodes() const {
+ return header_->max_num_nodes();
+ }
+ UInt32 num_blocks() const {
+ return header_->num_blocks();
+ }
+ UInt32 max_num_blocks() const {
+ return header_->max_num_blocks();
+ }
+ UInt32 next_key_pos() const {
+ return header_->next_key_pos();
+ }
+ UInt32 key_buf_size() const {
+ return header_->key_buf_size();
+ }
+ UInt32 status_flags() const {
+ return header_->status_flags();
+ }
+
+ void clear_status_flags() {
+ header_->set_status_flags(status_flags() & ~CHANGING_MASK);
+ }
+
+ void flush();
+
+ private:
+ File file_;
+ Header *header_;
+ Array<Node> nodes_;
+ Array<Block> blocks_;
+ Array<Entry> entries_;
+ Array<UInt32> key_buf_;
+
+ void create_file(const char *file_name,
+ UInt64 file_size,
+ UInt32 max_num_keys,
+ double num_nodes_per_key,
+ double average_key_length);
+ void create_file(const char *file_name,
+ UInt64 file_size,
+ UInt32 max_num_keys,
+ UInt32 max_num_blocks,
+ UInt32 key_buf_size);
+
+ void open_file(const char *file_name);
+
+ void map_address(void *address);
+
+ void build_from_trie(const Trie &trie);
+ void build_from_trie(const Trie &trie, UInt32 src, UInt32 dest);
+
+ void repair_trie(const Trie &trie);
+ void build_from_keys(const UInt32 *begin, const UInt32 *end,
+ UInt32 depth, UInt32 node_id);
+
+ void mkq_sort(UInt32 *l, UInt32 *r, UInt32 depth);
+ void insertion_sort(UInt32 *l, UInt32 *r, UInt32 depth);
+
+ inline int get_label(UInt32 key_id, UInt32 depth) const;
+ inline int get_median(UInt32 a, UInt32 b, UInt32 c, UInt32 depth) const;
+ inline bool less_than(UInt32 lhs, UInt32 rhs, UInt32 depth) const;
+ inline static void swap_ids(UInt32 *lhs, UInt32 *rhs);
+
+ bool search_key(const UInt8 *ptr, UInt32 length, UInt32 *key_pos) const;
+ bool search_linker(const UInt8 *ptr, UInt32 length,
+ UInt32 &node_id, UInt32 &query_pos) const;
+
+ bool lcp_search_key(const UInt8 *ptr, UInt32 length, UInt32 *key_pos) const;
+
+ bool remove_key(const UInt8 *ptr, UInt32 length);
+
+ bool insert_key(const UInt8 *ptr, UInt32 length, UInt32 *key_pos);
+ bool insert_linker(const UInt8 *ptr, UInt32 length,
+ UInt32 &node_id, UInt32 query_pos);
+
+ bool update_key(const Key &key, const UInt8 *ptr, UInt32 length,
+ UInt32 *key_pos);
+
+ UInt32 insert_node(UInt32 node_id, UInt16 label);
+ UInt32 append_key(const UInt8 *ptr, UInt32 length, UInt32 key_id);
+
+ UInt32 separate(const UInt8 *ptr, UInt32 length,
+ UInt32 node_id, UInt32 i);
+ void resolve(UInt32 node_id, UInt16 label);
+ void migrate_nodes(UInt32 node_id, UInt32 dest_offset,
+ const UInt16 *labels, UInt32 num_labels);
+
+ UInt32 find_offset(const UInt16 *labels, UInt32 num_labels);
+
+ void reserve_node(UInt32 node_id);
+ void reserve_block(UInt32 block_id);
+
+ void update_block_level(UInt32 block_id, UInt32 level);
+ void set_block_level(UInt32 block_id, UInt32 level);
+ void unset_block_level(UInt32 block_id);
+
+ Node &ith_node(UInt32 i) {
+ GRN_DAT_DEBUG_THROW_IF(i >= num_nodes());
+ return nodes_[i];
+ }
+ Block &ith_block(UInt32 i) {
+ GRN_DAT_DEBUG_THROW_IF(i >= num_blocks());
+ return blocks_[i];
+ }
+ Entry &ith_entry(UInt32 i) {
+ GRN_DAT_DEBUG_THROW_IF(i < min_key_id());
+ GRN_DAT_DEBUG_THROW_IF(i > (max_key_id() + 1));
+ return entries_[i];
+ }
+
+ // Disallows copy and assignment.
+ Trie(const Trie &);
+ Trie &operator=(const Trie &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/dat/vector.hpp b/storage/mroonga/vendor/groonga/lib/dat/vector.hpp
new file mode 100644
index 00000000..8a67b27b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dat/vector.hpp
@@ -0,0 +1,191 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "dat.hpp"
+
+#include <new>
+
+namespace grn {
+namespace dat {
+
+template <typename T>
+class GRN_DAT_API Vector {
+ public:
+ Vector() : buf_(NULL), size_(0), capacity_(0) {}
+ ~Vector() {
+ for (UInt32 i = 0; i < size(); ++i) {
+ buf_[i].~T();
+ }
+ delete [] reinterpret_cast<char *>(buf_);
+ }
+
+ const T &operator[](UInt32 i) const {
+ GRN_DAT_DEBUG_THROW_IF(i >= size());
+ return buf_[i];
+ }
+ T &operator[](UInt32 i) {
+ GRN_DAT_DEBUG_THROW_IF(i >= size());
+ return buf_[i];
+ }
+
+ const T &front() const {
+ GRN_DAT_DEBUG_THROW_IF(empty());
+ return buf_[0];
+ }
+ T &front() {
+ GRN_DAT_DEBUG_THROW_IF(empty());
+ return buf_[0];
+ }
+
+ const T &back() const {
+ GRN_DAT_DEBUG_THROW_IF(empty());
+ return buf_[size() - 1];
+ }
+ T &back() {
+ GRN_DAT_DEBUG_THROW_IF(empty());
+ return buf_[size() - 1];
+ }
+
+ const T *begin() const {
+ return buf_;
+ }
+ T *begin() {
+ return buf_;
+ }
+
+ const T *end() const {
+ return buf_ + size_;
+ }
+ T *end() {
+ return buf_ + size_;
+ }
+
+ void push_back() {
+ reserve(size() + 1);
+ new (&buf_[size()]) T;
+ ++size_;
+ }
+ void push_back(const T &x) {
+ reserve(size() + 1);
+ new (&buf_[size()]) T(x);
+ ++size_;
+ }
+
+ void pop_back() {
+ GRN_DAT_DEBUG_THROW_IF(empty());
+ back().~T();
+ --size_;
+ }
+
+ void clear() {
+ resize(0);
+ }
+
+ void resize(UInt32 new_size) {
+ if (new_size > capacity()) {
+ reserve(new_size);
+ }
+ for (UInt32 i = size(); i < new_size; ++i) {
+ new (&buf_[i]) T;
+ }
+ for (UInt32 i = new_size; i < size(); ++i) {
+ buf_[i].~T();
+ }
+ size_ = new_size;
+ }
+ template <typename U>
+ void resize(UInt32 new_size, const U &value) {
+ if (new_size > capacity()) {
+ reserve(new_size);
+ }
+ for (UInt32 i = size(); i < new_size; ++i) {
+ new (&buf_[i]) T(value);
+ }
+ for (UInt32 i = new_size; i < size(); ++i) {
+ buf_[i].~T();
+ }
+ size_ = new_size;
+ }
+
+ void reserve(UInt32 new_capacity) {
+ if (new_capacity <= capacity()) {
+ return;
+ } else if ((new_capacity / 2) < capacity()) {
+ if (capacity() < (MAX_UINT32 / 2)) {
+ new_capacity = capacity() * 2;
+ } else {
+ new_capacity = MAX_UINT32;
+ }
+ }
+
+ T *new_buf = reinterpret_cast<T *>(
+ new (std::nothrow) char[sizeof(new_capacity) * new_capacity]);
+ GRN_DAT_THROW_IF(MEMORY_ERROR, new_buf == NULL);
+
+ for (UInt32 i = 0; i < size(); ++i) {
+ new (&new_buf[i]) T(buf_[i]);
+ }
+ for (UInt32 i = 0; i < size(); ++i) {
+ buf_[i].~T();
+ }
+
+ T *old_buf = buf_;
+ buf_ = new_buf;
+ delete [] reinterpret_cast<char *>(old_buf);
+
+ capacity_ = new_capacity;
+ }
+
+ void swap(Vector *rhs) {
+ T * const temp_buf = buf_;
+ buf_ = rhs->buf_;
+ rhs->buf_ = temp_buf;
+
+ const UInt32 temp_size = size_;
+ size_ = rhs->size_;
+ rhs->size_ = temp_size;
+
+ const UInt32 temp_capacity = capacity_;
+ capacity_ = rhs->capacity_;
+ rhs->capacity_ = temp_capacity;
+ }
+
+ bool empty() const {
+ return size_ == 0;
+ }
+ UInt32 size() const {
+ return size_;
+ }
+ UInt32 capacity() const {
+ return capacity_;
+ }
+
+ private:
+ T *buf_;
+ UInt32 size_;
+ UInt32 capacity_;
+
+ // Disallows copy and assignment.
+ Vector(const Vector &);
+ Vector &operator=(const Vector &);
+};
+
+} // namespace dat
+} // namespace grn
diff --git a/storage/mroonga/vendor/groonga/lib/db.c b/storage/mroonga/vendor/groonga/lib/db.c
new file mode 100644
index 00000000..c3bbb64f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/db.c
@@ -0,0 +1,14052 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include "grn_config.h"
+#include "grn_db.h"
+#include "grn_obj.h"
+#include "grn_hash.h"
+#include "grn_pat.h"
+#include "grn_dat.h"
+#include "grn_ii.h"
+#include "grn_index_column.h"
+#include "grn_ctx_impl.h"
+#include "grn_token_cursor.h"
+#include "grn_tokenizers.h"
+#include "grn_proc.h"
+#include "grn_plugin.h"
+#include "grn_geo.h"
+#include "grn_scorers.h"
+#include "grn_snip.h"
+#include "grn_string.h"
+#include "grn_normalizer.h"
+#include "grn_report.h"
+#include "grn_util.h"
+#include "grn_cache.h"
+#include "grn_window_functions.h"
+#include <string.h>
+#include <math.h>
+
+typedef struct {
+ grn_id id;
+ unsigned int weight;
+} weight_uvector_entry;
+
+#define IS_WEIGHT_UVECTOR(obj) ((obj)->header.flags & GRN_OBJ_WITH_WEIGHT)
+
+#define GRN_TABLE_GROUPED (0x01<<0)
+#define GRN_TABLE_IS_GROUPED(table)\
+ ((table)->header.impl_flags & GRN_TABLE_GROUPED)
+#define GRN_TABLE_GROUPED_ON(table)\
+ ((table)->header.impl_flags |= GRN_TABLE_GROUPED)
+#define GRN_TABLE_IS_MULTI_KEYS_GROUPED(table)\
+ (GRN_TABLE_IS_GROUPED(table) &&\
+ table->header.domain == GRN_ID_NIL)
+
+#define WITH_NORMALIZE(table,key,key_size,block) do {\
+ if ((table)->normalizer && key && key_size > 0) {\
+ grn_obj *nstr;\
+ if ((nstr = grn_string_open(ctx, key, key_size,\
+ (table)->normalizer, 0))) {\
+ const char *key;\
+ unsigned int key_size;\
+ grn_string_get_normalized(ctx, nstr, &key, &key_size, NULL);\
+ block\
+ grn_obj_close(ctx, nstr);\
+ }\
+ } else {\
+ block\
+ }\
+} while (0)
+
+inline static grn_id
+grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
+ void **value, int *added);
+inline static void
+grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, double score,
+ grn_rset_posinfo *pi, int dir);
+inline static grn_id
+grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc);
+inline static int
+grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value);
+
+static void grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj);
+static void grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj);
+
+inline static void
+grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
+ grn_id *range_id, grn_obj_flags *range_flags);
+
+static char grn_db_key[GRN_ENV_BUFFER_SIZE];
+
+void
+grn_db_init_from_env(void)
+{
+ grn_getenv("GRN_DB_KEY",
+ grn_db_key,
+ GRN_ENV_BUFFER_SIZE);
+}
+
+inline static void
+gen_pathname(const char *path, char *buffer, int fno)
+{
+ size_t len = strlen(path);
+ grn_memcpy(buffer, path, len);
+ if (fno >= 0) {
+ buffer[len] = '.';
+ grn_itoh(fno, buffer + len + 1, 7);
+ buffer[len + 8] = '\0';
+ } else {
+ buffer[len] = '\0';
+ }
+}
+
+void
+grn_db_generate_pathname(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer)
+{
+ gen_pathname(grn_obj_get_io(ctx, db)->path, buffer, id);
+}
+
+typedef struct {
+ grn_obj *ptr;
+ uint32_t lock;
+ uint32_t done;
+} db_value;
+
+static const char *GRN_DB_CONFIG_PATH_FORMAT = "%s.conf";
+
+static grn_bool
+grn_db_config_create(grn_ctx *ctx, grn_db *s, const char *path,
+ const char *context_tag)
+{
+ char *config_path;
+ char config_path_buffer[PATH_MAX];
+ uint32_t flags = GRN_OBJ_KEY_VAR_SIZE;
+
+ if (path) {
+ grn_snprintf(config_path_buffer, PATH_MAX, PATH_MAX,
+ GRN_DB_CONFIG_PATH_FORMAT, path);
+ config_path = config_path_buffer;
+ } else {
+ config_path = NULL;
+ }
+ s->config = grn_hash_create(ctx, config_path,
+ GRN_CONFIG_MAX_KEY_SIZE,
+ GRN_CONFIG_VALUE_SPACE_SIZE,
+ flags);
+ if (!s->config) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "%s failed to create data store for configuration: <%s>",
+ context_tag,
+ config_path ? config_path : "(temporary)");
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_db_config_open(grn_ctx *ctx, grn_db *s, const char *path)
+{
+ char config_path[PATH_MAX];
+
+ grn_snprintf(config_path, PATH_MAX, PATH_MAX, GRN_DB_CONFIG_PATH_FORMAT, path);
+ if (grn_path_exist(config_path)) {
+ s->config = grn_hash_open(ctx, config_path);
+ if (!s->config) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[db][open] failed to open data store for configuration: <%s>",
+ config_path);
+ return GRN_FALSE;
+ }
+ return GRN_TRUE;
+ } else {
+ return grn_db_config_create(ctx, s, path, "[db][open]");
+ }
+}
+
+static grn_rc
+grn_db_config_remove(grn_ctx *ctx, const char *path)
+{
+ char config_path[PATH_MAX];
+
+ grn_snprintf(config_path, PATH_MAX, PATH_MAX, GRN_DB_CONFIG_PATH_FORMAT, path);
+ return grn_hash_remove(ctx, config_path);
+}
+
+grn_obj *
+grn_db_create(grn_ctx *ctx, const char *path, grn_db_create_optarg *optarg)
+{
+ grn_db *s = NULL;
+
+ GRN_API_ENTER;
+
+ if (path && strlen(path) > PATH_MAX - 14) {
+ ERR(GRN_INVALID_ARGUMENT, "too long path");
+ goto exit;
+ }
+
+ s = GRN_MALLOC(sizeof(grn_db));
+ if (!s) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "grn_db alloc failed");
+ goto exit;
+ }
+
+ CRITICAL_SECTION_INIT(s->lock);
+ grn_tiny_array_init(ctx, &s->values, sizeof(db_value),
+ GRN_TINY_ARRAY_CLEAR|
+ GRN_TINY_ARRAY_THREADSAFE|
+ GRN_TINY_ARRAY_USE_MALLOC);
+ s->keys = NULL;
+ s->specs = NULL;
+ s->config = NULL;
+
+ {
+ grn_bool use_default_db_key = GRN_TRUE;
+ grn_bool use_pat_as_db_keys = GRN_FALSE;
+ if (grn_db_key[0]) {
+ if (!strcmp(grn_db_key, "pat")) {
+ use_default_db_key = GRN_FALSE;
+ use_pat_as_db_keys = GRN_TRUE;
+ } else if (!strcmp(grn_db_key, "dat")) {
+ use_default_db_key = GRN_FALSE;
+ }
+ }
+
+ if (use_default_db_key && !strcmp(GRN_DEFAULT_DB_KEY, "pat")) {
+ use_pat_as_db_keys = GRN_TRUE;
+ }
+ if (use_pat_as_db_keys) {
+ s->keys = (grn_obj *)grn_pat_create(ctx, path, GRN_TABLE_MAX_KEY_SIZE,
+ 0, GRN_OBJ_KEY_VAR_SIZE);
+ } else {
+ s->keys = (grn_obj *)grn_dat_create(ctx, path, GRN_TABLE_MAX_KEY_SIZE,
+ 0, GRN_OBJ_KEY_VAR_SIZE);
+ }
+ }
+
+ if (!s->keys) {
+ goto exit;
+ }
+
+ GRN_DB_OBJ_SET_TYPE(s, GRN_DB);
+ s->obj.db = (grn_obj *)s;
+ s->obj.header.domain = GRN_ID_NIL;
+ DB_OBJ(&s->obj)->range = GRN_ID_NIL;
+ /* prepare builtin classes and load builtin plugins. */
+ if (path) {
+ {
+ char specs_path[PATH_MAX];
+ gen_pathname(path, specs_path, 0);
+ s->specs = grn_ja_create(ctx, specs_path, 65536, 0);
+ if (!s->specs) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to create specs: <%s>", specs_path);
+ goto exit;
+ }
+ }
+ if (!grn_db_config_create(ctx, s, path, "[db][create]")) {
+ goto exit;
+ }
+ grn_ctx_use(ctx, (grn_obj *)s);
+ grn_db_init_builtin_types(ctx);
+ grn_obj_flush(ctx, (grn_obj *)s);
+ GRN_API_RETURN((grn_obj *)s);
+ } else {
+ if (!grn_db_config_create(ctx, s, NULL, "[db][create]")) {
+ goto exit;
+ }
+ grn_ctx_use(ctx, (grn_obj *)s);
+ grn_db_init_builtin_types(ctx);
+ GRN_API_RETURN((grn_obj *)s);
+ }
+
+exit:
+ if (s) {
+ if (s->keys) {
+ if (s->keys->header.type == GRN_TABLE_PAT_KEY) {
+ grn_pat_close(ctx, (grn_pat *)s->keys);
+ grn_pat_remove(ctx, path);
+ } else {
+ grn_dat_close(ctx, (grn_dat *)s->keys);
+ grn_dat_remove(ctx, path);
+ }
+ }
+ if (s->specs) {
+ const char *specs_path;
+ specs_path = grn_obj_path(ctx, (grn_obj *)(s->specs));
+ grn_ja_close(ctx, s->specs);
+ grn_ja_remove(ctx, specs_path);
+ }
+ grn_tiny_array_fin(&s->values);
+ CRITICAL_SECTION_FIN(s->lock);
+ GRN_FREE(s);
+ }
+
+ GRN_API_RETURN(NULL);
+}
+
+grn_obj *
+grn_db_open(grn_ctx *ctx, const char *path)
+{
+ grn_db *s = NULL;
+
+ GRN_API_ENTER;
+
+ if (!path) {
+ ERR(GRN_INVALID_ARGUMENT, "[db][open] path is missing");
+ goto exit;
+ }
+
+ if (strlen(path) > PATH_MAX - 14) {
+ ERR(GRN_INVALID_ARGUMENT, "inappropriate path");
+ goto exit;
+ }
+
+ s = GRN_MALLOC(sizeof(grn_db));
+ if (!s) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "grn_db alloc failed");
+ goto exit;
+ }
+
+ CRITICAL_SECTION_INIT(s->lock);
+ grn_tiny_array_init(ctx, &s->values, sizeof(db_value),
+ GRN_TINY_ARRAY_CLEAR|
+ GRN_TINY_ARRAY_THREADSAFE|
+ GRN_TINY_ARRAY_USE_MALLOC);
+ s->keys = NULL;
+ s->specs = NULL;
+ s->config = NULL;
+
+ {
+ uint32_t type = grn_io_detect_type(ctx, path);
+ switch (type) {
+ case GRN_TABLE_PAT_KEY :
+ s->keys = (grn_obj *)grn_pat_open(ctx, path);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ s->keys = (grn_obj *)grn_dat_open(ctx, path);
+ break;
+ default :
+ s->keys = NULL;
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[db][open] invalid keys table's type: %#x", type);
+ goto exit;
+ }
+ break;
+ }
+ }
+
+ if (!s->keys) {
+ goto exit;
+ }
+
+ {
+ char specs_path[PATH_MAX];
+ gen_pathname(path, specs_path, 0);
+ s->specs = grn_ja_open(ctx, specs_path);
+ if (!s->specs) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[db][open] failed to open specs: <%s>", specs_path);
+ goto exit;
+ }
+ }
+ if (!grn_db_config_open(ctx, s, path)) {
+ goto exit;
+ }
+
+ GRN_DB_OBJ_SET_TYPE(s, GRN_DB);
+ s->obj.db = (grn_obj *)s;
+ s->obj.header.domain = GRN_ID_NIL;
+ DB_OBJ(&s->obj)->range = GRN_ID_NIL;
+ grn_ctx_use(ctx, (grn_obj *)s);
+ {
+ unsigned int n_records;
+
+ n_records = grn_table_size(ctx, (grn_obj *)s);
+#ifdef GRN_WITH_MECAB
+ if (grn_db_init_mecab_tokenizer(ctx)) {
+ ERRCLR(ctx);
+ }
+#endif
+ grn_db_init_builtin_tokenizers(ctx);
+ grn_db_init_builtin_normalizers(ctx);
+ grn_db_init_builtin_scorers(ctx);
+ grn_db_init_builtin_commands(ctx);
+ grn_db_init_builtin_window_functions(ctx);
+
+ if (grn_table_size(ctx, (grn_obj *)s) > n_records) {
+ grn_obj_flush(ctx, (grn_obj *)s);
+ }
+ }
+ GRN_API_RETURN((grn_obj *)s);
+
+exit:
+ if (s) {
+ if (s->specs) {
+ grn_ja_close(ctx, s->specs);
+ }
+ if (s->keys) {
+ if (s->keys->header.type == GRN_TABLE_PAT_KEY) {
+ grn_pat_close(ctx, (grn_pat *)s->keys);
+ } else {
+ grn_dat_close(ctx, (grn_dat *)s->keys);
+ }
+ }
+ grn_tiny_array_fin(&s->values);
+ CRITICAL_SECTION_FIN(s->lock);
+ GRN_FREE(s);
+ }
+
+ GRN_API_RETURN(NULL);
+}
+
+static grn_id
+grn_db_curr_id(grn_ctx *ctx, grn_obj *db)
+{
+ grn_id curr_id = GRN_ID_NIL;
+ grn_db *s = (grn_db *)db;
+ switch (s->keys->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ curr_id = grn_pat_curr_id(ctx, (grn_pat *)s->keys);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ curr_id = grn_dat_curr_id(ctx, (grn_dat *)s->keys);
+ break;
+ }
+ return curr_id;
+}
+
+/* s must be validated by caller */
+grn_rc
+grn_db_close(grn_ctx *ctx, grn_obj *db)
+{
+ grn_id id;
+ db_value *vp;
+ grn_db *s = (grn_db *)db;
+ grn_bool ctx_used_db;
+ if (!s) { return GRN_INVALID_ARGUMENT; }
+ GRN_API_ENTER;
+
+ ctx_used_db = ctx->impl && ctx->impl->db == db;
+ if (ctx_used_db) {
+#ifdef GRN_WITH_MECAB
+ grn_db_fin_mecab_tokenizer(ctx);
+#endif
+ grn_ctx_loader_clear(ctx);
+ if (ctx->impl->parser) {
+ grn_expr_parser_close(ctx);
+ }
+ }
+
+ GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
+ if (vp->ptr) { grn_obj_close(ctx, vp->ptr); }
+ });
+
+ if (ctx_used_db) {
+ if (ctx->impl->values) {
+ grn_db_obj *o;
+ GRN_ARRAY_EACH(ctx, ctx->impl->values, 0, 0, id, &o, {
+ grn_obj_close(ctx, *((grn_obj **)o));
+ });
+ grn_array_truncate(ctx, ctx->impl->values);
+ }
+ }
+
+/* grn_tiny_array_fin should be refined.. */
+#ifdef WIN32
+ {
+ grn_tiny_array *a = &s->values;
+ CRITICAL_SECTION_FIN(a->lock);
+ }
+#endif
+ grn_tiny_array_fin(&s->values);
+
+ switch (s->keys->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ grn_pat_close(ctx, (grn_pat *)s->keys);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ grn_dat_close(ctx, (grn_dat *)s->keys);
+ break;
+ }
+ CRITICAL_SECTION_FIN(s->lock);
+ if (s->specs) { grn_ja_close(ctx, s->specs); }
+ grn_hash_close(ctx, s->config);
+ GRN_FREE(s);
+
+ if (ctx_used_db) {
+ grn_cache *cache;
+ cache = grn_cache_current_get(ctx);
+ if (cache) {
+ grn_cache_expire(cache, -1);
+ }
+ ctx->impl->db = NULL;
+ }
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_obj *
+grn_ctx_get(grn_ctx *ctx, const char *name, int name_size)
+{
+ grn_obj *obj = NULL;
+ grn_obj *db;
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ return NULL;
+ }
+ GRN_API_ENTER;
+ if (GRN_DB_P(db)) {
+ grn_db *s = (grn_db *)db;
+ grn_obj *alias_table = NULL;
+ grn_obj *alias_column = NULL;
+ grn_obj alias_name_buffer;
+
+ if (name_size < 0) {
+ name_size = strlen(name);
+ }
+ GRN_TEXT_INIT(&alias_name_buffer, 0);
+ while (GRN_TRUE) {
+ grn_id id;
+
+ id = grn_table_get(ctx, s->keys, name, name_size);
+ if (id) {
+ obj = grn_ctx_at(ctx, id);
+ break;
+ }
+
+ if (!alias_column) {
+ grn_id alias_column_id;
+ const char *alias_column_name;
+ uint32_t alias_column_name_size;
+
+ grn_config_get(ctx,
+ "alias.column", -1,
+ &alias_column_name, &alias_column_name_size);
+ if (!alias_column_name) {
+ break;
+ }
+ alias_column_id = grn_table_get(ctx,
+ s->keys,
+ alias_column_name,
+ alias_column_name_size);
+ if (!alias_column_id) {
+ break;
+ }
+ alias_column = grn_ctx_at(ctx, alias_column_id);
+ if (alias_column->header.type != GRN_COLUMN_VAR_SIZE) {
+ break;
+ }
+ if (alias_column->header.flags & GRN_OBJ_VECTOR) {
+ break;
+ }
+ if (DB_OBJ(alias_column)->range != GRN_DB_SHORT_TEXT) {
+ break;
+ }
+ alias_table = grn_ctx_at(ctx, alias_column->header.domain);
+ if (alias_table->header.type == GRN_TABLE_NO_KEY) {
+ break;
+ }
+ }
+
+ {
+ grn_id alias_id;
+ alias_id = grn_table_get(ctx, alias_table, name, name_size);
+ if (!alias_id) {
+ break;
+ }
+ GRN_BULK_REWIND(&alias_name_buffer);
+ grn_obj_get_value(ctx, alias_column, alias_id, &alias_name_buffer);
+ name = GRN_TEXT_VALUE(&alias_name_buffer);
+ name_size = GRN_TEXT_LEN(&alias_name_buffer);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &alias_name_buffer);
+ }
+ GRN_API_RETURN(obj);
+}
+
+grn_obj *
+grn_ctx_db(grn_ctx *ctx)
+{
+ return (ctx && ctx->impl) ? ctx->impl->db : NULL;
+}
+
+grn_obj *
+grn_db_keys(grn_obj *s)
+{
+ return (grn_obj *)(((grn_db *)s)->keys);
+}
+
+uint32_t
+grn_obj_get_last_modified(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return 0;
+ }
+
+ return grn_obj_get_io(ctx, obj)->header->last_modified;
+}
+
+grn_bool
+grn_obj_is_dirty(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ switch (obj->header.type) {
+ case GRN_DB :
+ return grn_db_is_dirty(ctx, obj);
+ case GRN_TABLE_PAT_KEY :
+ return grn_pat_is_dirty(ctx, (grn_pat *)obj);
+ case GRN_TABLE_DAT_KEY :
+ return grn_dat_is_dirty(ctx, (grn_dat *)obj);
+ default :
+ return GRN_FALSE;
+ }
+}
+
+uint32_t
+grn_db_get_last_modified(grn_ctx *ctx, grn_obj *db)
+{
+ return grn_obj_get_last_modified(ctx, db);
+}
+
+grn_bool
+grn_db_is_dirty(grn_ctx *ctx, grn_obj *db)
+{
+ grn_obj *keys;
+
+ if (!db) {
+ return GRN_FALSE;
+ }
+
+ keys = ((grn_db *)db)->keys;
+ return grn_obj_is_dirty(ctx, keys);
+}
+
+static grn_rc
+grn_db_dirty(grn_ctx *ctx, grn_obj *db)
+{
+ grn_obj *keys;
+
+ if (!db) {
+ return GRN_SUCCESS;
+ }
+
+ keys = ((grn_db *)db)->keys;
+ switch (keys->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ return grn_pat_dirty(ctx, (grn_pat *)keys);
+ case GRN_TABLE_DAT_KEY :
+ return grn_dat_dirty(ctx, (grn_dat *)keys);
+ default :
+ return GRN_SUCCESS;
+ }
+}
+
+static grn_rc
+grn_db_clean(grn_ctx *ctx, grn_obj *db)
+{
+ grn_obj *keys;
+
+ if (!db) {
+ return GRN_SUCCESS;
+ }
+
+ keys = ((grn_db *)db)->keys;
+ switch (keys->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ return grn_pat_clean(ctx, (grn_pat *)keys);
+ case GRN_TABLE_DAT_KEY :
+ return grn_dat_clean(ctx, (grn_dat *)keys);
+ default :
+ return GRN_SUCCESS;
+ }
+}
+
+static grn_rc
+grn_db_clear_dirty(grn_ctx *ctx, grn_obj *db)
+{
+ grn_obj *keys;
+
+ if (!db) {
+ return GRN_SUCCESS;
+ }
+
+ keys = ((grn_db *)db)->keys;
+ switch (keys->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ return grn_pat_clear_dirty(ctx, (grn_pat *)keys);
+ case GRN_TABLE_DAT_KEY :
+ return grn_dat_clear_dirty(ctx, (grn_dat *)keys);
+ default :
+ return GRN_SUCCESS;
+ }
+}
+
+void
+grn_db_touch(grn_ctx *ctx, grn_obj *s)
+{
+ grn_obj_touch(ctx, s, NULL);
+}
+
+grn_bool
+grn_obj_is_corrupt(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_bool is_corrupt = GRN_FALSE;
+
+ GRN_API_ENTER;
+
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT, "[object][corrupt] object must not be NULL");
+ GRN_API_RETURN(GRN_FALSE);
+ }
+
+ switch (obj->header.type) {
+ case GRN_DB :
+ is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
+ if (!is_corrupt) {
+ is_corrupt = grn_io_is_corrupt(ctx, ((grn_db *)obj)->specs->io);
+ }
+ if (!is_corrupt) {
+ is_corrupt = grn_io_is_corrupt(ctx, ((grn_db *)obj)->config->io);
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
+ break;
+ case GRN_TABLE_DAT_KEY :
+ is_corrupt = grn_dat_is_corrupt(ctx, (grn_dat *)obj);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ is_corrupt = grn_io_is_corrupt(ctx, grn_obj_get_io(ctx, obj));
+ break;
+ case GRN_COLUMN_INDEX :
+ is_corrupt = grn_io_is_corrupt(ctx, ((grn_ii *)obj)->seg);
+ if (!is_corrupt) {
+ is_corrupt = grn_io_is_corrupt(ctx, ((grn_ii *)obj)->chunk);
+ }
+ break;
+ default :
+ break;
+ }
+
+ GRN_API_RETURN(is_corrupt);
+}
+
+#define IS_TEMP(obj) (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)
+
+static inline void
+grn_obj_touch_db(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv)
+{
+ grn_obj_get_io(ctx, obj)->header->last_modified = tv->tv_sec;
+ grn_db_dirty(ctx, obj);
+}
+
+void
+grn_obj_touch(grn_ctx *ctx, grn_obj *obj, grn_timeval *tv)
+{
+ grn_timeval tv_;
+ if (!tv) {
+ grn_timeval_now(ctx, &tv_);
+ tv = &tv_;
+ }
+ if (obj) {
+ switch (obj->header.type) {
+ case GRN_DB :
+ grn_obj_touch_db(ctx, obj, tv);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_INDEX :
+ if (!IS_TEMP(obj)) {
+ grn_obj_get_io(ctx, obj)->header->last_modified = tv->tv_sec;
+ grn_obj_touch(ctx, DB_OBJ(obj)->db, tv);
+ }
+ break;
+ }
+ }
+}
+
+grn_rc
+grn_db_check_name(grn_ctx *ctx, const char *name, unsigned int name_size)
+{
+ int len;
+ const char *name_end = name + name_size;
+ if (name_size > 0 &&
+ *name == GRN_DB_PSEUDO_COLUMN_PREFIX) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ while (name < name_end) {
+ char c = *name;
+ if ((unsigned int)((c | 0x20) - 'a') >= 26u &&
+ (unsigned int)(c - '0') >= 10u &&
+ c != '_' &&
+ c != '-' &&
+ c != '#' &&
+ c != '@') {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!(len = grn_charlen(ctx, name, name_end))) { break; }
+ name += len;
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_obj *
+grn_type_open(grn_ctx *ctx, grn_obj_spec *spec)
+{
+ struct _grn_type *res;
+ res = GRN_MALLOC(sizeof(struct _grn_type));
+ if (res) {
+ GRN_DB_OBJ_SET_TYPE(res, GRN_TYPE);
+ res->obj.header = spec->header;
+ GRN_TYPE_SIZE(&res->obj) = GRN_TYPE_SIZE(spec);
+ }
+ return (grn_obj *)res;
+}
+
+grn_obj *
+grn_proc_create(grn_ctx *ctx, const char *name, int name_size, grn_proc_type type,
+ grn_proc_func *init, grn_proc_func *next, grn_proc_func *fin,
+ unsigned int nvars, grn_expr_var *vars)
+{
+ grn_proc *res = NULL;
+ grn_id id = GRN_ID_NIL;
+ grn_id range = GRN_ID_NIL;
+ int added = 0;
+ grn_obj *db;
+ const char *path;
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "db not initialized");
+ return NULL;
+ }
+ GRN_API_ENTER;
+ path = ctx->impl->plugin_path;
+ if (path) {
+ range = grn_plugin_reference(ctx, path);
+ }
+ if (name_size < 0) {
+ name_size = strlen(name);
+ }
+ if (grn_db_check_name(ctx, name, name_size)) {
+ GRN_DB_CHECK_NAME_ERR("[proc][create]", name, name_size);
+ GRN_API_RETURN(NULL);
+ }
+ if (!GRN_DB_P(db)) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
+ GRN_API_RETURN(NULL);
+ }
+ if (name && name_size) {
+ grn_db *s = (grn_db *)db;
+ if (!(id = grn_table_get(ctx, s->keys, name, name_size))) {
+ if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "grn_table_add failed");
+ GRN_API_RETURN(NULL);
+ }
+ }
+ if (!added) {
+ db_value *vp;
+ if ((vp = grn_tiny_array_at(&s->values, id)) && (res = (grn_proc *)vp->ptr)) {
+ /* TODO: Do more robust check. */
+ if (res->funcs[PROC_INIT] ||
+ res->funcs[PROC_NEXT] ||
+ res->funcs[PROC_FIN]) {
+ ERR(GRN_INVALID_ARGUMENT, "already used name");
+ GRN_API_RETURN(NULL);
+ }
+ if (range != GRN_ID_NIL) {
+ grn_plugin_close(ctx, range);
+ }
+ GRN_API_RETURN((grn_obj *)res);
+ } else {
+ added = 1;
+ }
+ }
+ } else if (ctx->impl && ctx->impl->values) {
+ id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
+ added = 1;
+ }
+ if (!res) { res = GRN_MALLOCN(grn_proc, 1); }
+ if (res) {
+ GRN_DB_OBJ_SET_TYPE(res, GRN_PROC);
+ res->obj.db = db;
+ res->obj.id = id;
+ res->obj.header.domain = GRN_ID_NIL;
+ res->obj.header.flags = path ? GRN_OBJ_CUSTOM_NAME : 0;
+ res->obj.range = range;
+ res->type = type;
+ res->funcs[PROC_INIT] = init;
+ res->funcs[PROC_NEXT] = next;
+ res->funcs[PROC_FIN] = fin;
+ memset(&(res->callbacks), 0, sizeof(res->callbacks));
+ res->callbacks.function.selector_op = GRN_OP_NOP;
+ res->callbacks.function.is_stable = GRN_TRUE;
+ GRN_TEXT_INIT(&res->name_buf, 0);
+ res->vars = NULL;
+ res->nvars = 0;
+ if (added) {
+ if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
+ // grn_obj_delete(ctx, db, id);
+ GRN_FREE(res);
+ GRN_API_RETURN(NULL);
+ }
+ }
+ while (nvars--) {
+ grn_obj *v = grn_expr_add_var(ctx, (grn_obj *)res, vars->name, vars->name_size);
+ GRN_OBJ_INIT(v, vars->value.header.type, 0, vars->value.header.domain);
+ GRN_TEXT_PUT(ctx, v, GRN_TEXT_VALUE(&vars->value), GRN_TEXT_LEN(&vars->value));
+ vars++;
+ }
+ }
+ GRN_API_RETURN((grn_obj *)res);
+}
+
+/* grn_table */
+
+static void
+calc_rec_size(grn_table_flags flags, uint32_t max_n_subrecs, uint32_t range_size,
+ uint32_t additional_value_size,
+ uint8_t *subrec_size, uint8_t *subrec_offset,
+ uint32_t *key_size, uint32_t *value_size)
+{
+ *subrec_size = 0;
+ *subrec_offset = 0;
+ if (flags & GRN_OBJ_WITH_SUBREC) {
+ switch (flags & GRN_OBJ_UNIT_MASK) {
+ case GRN_OBJ_UNIT_DOCUMENT_NONE :
+ break;
+ case GRN_OBJ_UNIT_DOCUMENT_SECTION :
+ *subrec_offset = sizeof(grn_id);
+ *subrec_size = sizeof(uint32_t);
+ break;
+ case GRN_OBJ_UNIT_DOCUMENT_POSITION :
+ *subrec_offset = sizeof(grn_id);
+ *subrec_size = sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ case GRN_OBJ_UNIT_SECTION_NONE :
+ *key_size += sizeof(uint32_t);
+ break;
+ case GRN_OBJ_UNIT_SECTION_POSITION :
+ *key_size += sizeof(uint32_t);
+ *subrec_offset = sizeof(grn_id) + sizeof(uint32_t);
+ *subrec_size = sizeof(uint32_t);
+ break;
+ case GRN_OBJ_UNIT_POSITION_NONE :
+ *key_size += sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ case GRN_OBJ_UNIT_USERDEF_DOCUMENT :
+ *subrec_size = range_size;
+ break;
+ case GRN_OBJ_UNIT_USERDEF_SECTION :
+ *subrec_size = range_size + sizeof(uint32_t);
+ break;
+ case GRN_OBJ_UNIT_USERDEF_POSITION :
+ *subrec_size = range_size + sizeof(uint32_t) + sizeof(uint32_t);
+ break;
+ }
+ *value_size = (uintptr_t)GRN_RSET_SUBRECS_NTH((((grn_rset_recinfo *)0)->subrecs),
+ *subrec_size, max_n_subrecs);
+ } else {
+ *value_size = range_size;
+ }
+ *value_size += additional_value_size;
+}
+
+static grn_rc _grn_obj_remove(grn_ctx *ctx, grn_obj *obj, grn_bool dependent);
+
+static grn_rc
+grn_table_create_validate(grn_ctx *ctx, const char *name, unsigned int name_size,
+ const char *path, grn_table_flags flags,
+ grn_obj *key_type, grn_obj *value_type)
+{
+ grn_table_flags table_type;
+ const char *table_type_name = NULL;
+
+ table_type = (flags & GRN_OBJ_TABLE_TYPE_MASK);
+ switch (table_type) {
+ case GRN_OBJ_TABLE_HASH_KEY :
+ table_type_name = "TABLE_HASH_KEY";
+ break;
+ case GRN_OBJ_TABLE_PAT_KEY :
+ table_type_name = "TABLE_PAT_KEY";
+ break;
+ case GRN_OBJ_TABLE_DAT_KEY :
+ table_type_name = "TABLE_DAT_KEY";
+ break;
+ case GRN_OBJ_TABLE_NO_KEY :
+ table_type_name = "TABLE_NO_KEY";
+ break;
+ default :
+ table_type_name = "unknown";
+ break;
+ }
+
+ if (!key_type && table_type != GRN_OBJ_TABLE_NO_KEY &&
+ !(flags & GRN_OBJ_KEY_VAR_SIZE)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "key type is required for TABLE_HASH_KEY, TABLE_PAT_KEY or "
+ "TABLE_DAT_KEY: <%.*s>", name_size, name);
+ return ctx->rc;
+ }
+
+ if (key_type && table_type == GRN_OBJ_TABLE_NO_KEY) {
+ int key_name_size;
+ char key_name[GRN_TABLE_MAX_KEY_SIZE];
+ key_name_size = grn_obj_name(ctx, key_type, key_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "key isn't available for TABLE_NO_KEY table: <%.*s> (%.*s)",
+ name_size, name, key_name_size, key_name);
+ return ctx->rc;
+ }
+
+ if ((flags & GRN_OBJ_KEY_WITH_SIS) &&
+ table_type != GRN_OBJ_TABLE_PAT_KEY) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "key with SIS is available only for TABLE_PAT_KEY table: "
+ "<%.*s>(%s)",
+ name_size, name,
+ table_type_name);
+ return ctx->rc;
+ }
+
+ if ((flags & GRN_OBJ_KEY_NORMALIZE) &&
+ table_type == GRN_OBJ_TABLE_NO_KEY) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "key normalization isn't available for TABLE_NO_KEY table: <%.*s>",
+ name_size, name);
+ return ctx->rc;
+ }
+
+ if ((flags & GRN_OBJ_KEY_LARGE) &&
+ table_type != GRN_OBJ_TABLE_HASH_KEY) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "large key support is available only for TABLE_HASH_KEY key table: "
+ "<%.*s>(%s)",
+ name_size, name,
+ table_type_name);
+ return ctx->rc;
+ }
+
+ return ctx->rc;
+}
+
+static grn_obj *
+grn_table_create_with_max_n_subrecs(grn_ctx *ctx, const char *name,
+ unsigned int name_size, const char *path,
+ grn_table_flags flags, grn_obj *key_type,
+ grn_obj *value_type,
+ uint32_t max_n_subrecs,
+ uint32_t additional_value_size)
+{
+ grn_id id;
+ grn_id domain = GRN_ID_NIL, range = GRN_ID_NIL;
+ uint32_t key_size, value_size = 0, range_size = 0;
+ uint8_t subrec_size, subrec_offset;
+ grn_obj *res = NULL;
+ grn_obj *db;
+ char buffer[PATH_MAX];
+ if (!ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "[table][create] db not initialized");
+ return NULL;
+ }
+ if (grn_db_check_name(ctx, name, name_size)) {
+ GRN_DB_CHECK_NAME_ERR("[table][create]", name, name_size);
+ return NULL;
+ }
+ if (!GRN_DB_P(db)) {
+ ERR(GRN_INVALID_ARGUMENT, "[table][create] invalid db assigned");
+ return NULL;
+ }
+ if (grn_table_create_validate(ctx, name, name_size, path, flags,
+ key_type, value_type)) {
+ return NULL;
+ }
+ if (key_type) {
+ domain = DB_OBJ(key_type)->id;
+ switch (key_type->header.type) {
+ case GRN_TYPE :
+ {
+ grn_db_obj *t = (grn_db_obj *)key_type;
+ flags |= t->header.flags;
+ key_size = GRN_TYPE_SIZE(t);
+ if (key_size > GRN_TABLE_MAX_KEY_SIZE) {
+ int type_name_size;
+ char type_name[GRN_TABLE_MAX_KEY_SIZE];
+ type_name_size = grn_obj_name(ctx, key_type, type_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] key size too big: <%.*s> <%.*s>(%u) (max:%u)",
+ name_size, name,
+ type_name_size, type_name,
+ key_size, GRN_TABLE_MAX_KEY_SIZE);
+ return NULL;
+ }
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ key_size = sizeof(grn_id);
+ break;
+ default :
+ {
+ int key_name_size;
+ char key_name[GRN_TABLE_MAX_KEY_SIZE];
+ key_name_size = grn_obj_name(ctx, key_type, key_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] key type must be type or table: <%.*s> (%.*s)",
+ name_size, name, key_name_size, key_name);
+ return NULL;
+ }
+ break;
+ }
+ } else {
+ key_size = (flags & GRN_OBJ_KEY_VAR_SIZE) ? GRN_TABLE_MAX_KEY_SIZE : sizeof(grn_id);
+ }
+ if (value_type) {
+ range = DB_OBJ(value_type)->id;
+ switch (value_type->header.type) {
+ case GRN_TYPE :
+ {
+ grn_db_obj *t = (grn_db_obj *)value_type;
+ if (t->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ int type_name_size;
+ char type_name[GRN_TABLE_MAX_KEY_SIZE];
+ type_name_size = grn_obj_name(ctx, value_type, type_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] value type must be fixed size: <%.*s> (%.*s)",
+ name_size, name, type_name_size, type_name);
+ return NULL;
+ }
+ range_size = GRN_TYPE_SIZE(t);
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ range_size = sizeof(grn_id);
+ break;
+ default :
+ {
+ int value_name_size;
+ char value_name[GRN_TABLE_MAX_KEY_SIZE];
+ value_name_size = grn_obj_name(ctx, value_type, value_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][create] value type must be type or table: <%.*s> (%.*s)",
+ name_size, name, value_name_size, value_name);
+ return NULL;
+ }
+ break;
+ }
+ }
+
+ id = grn_obj_register(ctx, db, name, name_size);
+ if (ERRP(ctx, GRN_ERROR)) { return NULL; }
+ if (GRN_OBJ_PERSISTENT & flags) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "DDL:%u:table_create %.*s", id, name_size, name);
+ if (!path) {
+ if (GRN_DB_PERSISTENT_P(db)) {
+ grn_db_generate_pathname(ctx, db, id, buffer);
+ path = buffer;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "path not assigned for persistent table");
+ grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ return NULL;
+ }
+ } else {
+ flags |= GRN_OBJ_CUSTOM_NAME;
+ }
+ } else {
+ if (path) {
+ ERR(GRN_INVALID_ARGUMENT, "path assigned for temporary table");
+ grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ return NULL;
+ }
+ if (GRN_DB_PERSISTENT_P(db) && name && name_size) {
+ ERR(GRN_INVALID_ARGUMENT, "name assigned for temporary table");
+ grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ return NULL;
+ }
+ }
+ calc_rec_size(flags, max_n_subrecs, range_size, additional_value_size,
+ &subrec_size, &subrec_offset, &key_size, &value_size);
+ switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
+ case GRN_OBJ_TABLE_HASH_KEY :
+ res = (grn_obj *)grn_hash_create(ctx, path, key_size, value_size, flags);
+ break;
+ case GRN_OBJ_TABLE_PAT_KEY :
+ res = (grn_obj *)grn_pat_create(ctx, path, key_size, value_size, flags);
+ break;
+ case GRN_OBJ_TABLE_DAT_KEY :
+ res = (grn_obj *)grn_dat_create(ctx, path, key_size, value_size, flags);
+ break;
+ case GRN_OBJ_TABLE_NO_KEY :
+ domain = range;
+ res = (grn_obj *)grn_array_create(ctx, path, value_size, flags);
+ break;
+ }
+ if (res) {
+ DB_OBJ(res)->header.impl_flags = 0;
+ DB_OBJ(res)->header.domain = domain;
+ DB_OBJ(res)->range = range;
+ DB_OBJ(res)->max_n_subrecs = max_n_subrecs;
+ DB_OBJ(res)->subrec_size = subrec_size;
+ DB_OBJ(res)->subrec_offset = subrec_offset;
+ DB_OBJ(res)->flags.group = 0;
+ if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
+ _grn_obj_remove(ctx, res, GRN_FALSE);
+ res = NULL;
+ }
+ } else {
+ grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ }
+ return res;
+}
+
+grn_obj *
+grn_table_create(grn_ctx *ctx, const char *name, unsigned int name_size,
+ const char *path, grn_table_flags flags,
+ grn_obj *key_type, grn_obj *value_type)
+{
+ grn_obj *res;
+ GRN_API_ENTER;
+ res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
+ flags, key_type, value_type,
+ 0, 0);
+ GRN_API_RETURN(res);
+}
+
+grn_obj *
+grn_table_create_for_group(grn_ctx *ctx, const char *name,
+ unsigned int name_size, const char *path,
+ grn_obj *group_key, grn_obj *value_type,
+ unsigned int max_n_subrecs)
+{
+ grn_obj *res = NULL;
+ GRN_API_ENTER;
+ if (group_key) {
+ grn_obj *key_type;
+ key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, group_key));
+ if (key_type) {
+ res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
+ GRN_TABLE_HASH_KEY|
+ GRN_OBJ_WITH_SUBREC|
+ GRN_OBJ_UNIT_USERDEF_DOCUMENT,
+ key_type, value_type,
+ max_n_subrecs, 0);
+ grn_obj_unlink(ctx, key_type);
+ }
+ } else {
+ res = grn_table_create_with_max_n_subrecs(ctx, name, name_size, path,
+ GRN_TABLE_HASH_KEY|
+ GRN_OBJ_KEY_VAR_SIZE|
+ GRN_OBJ_WITH_SUBREC|
+ GRN_OBJ_UNIT_USERDEF_DOCUMENT,
+ NULL, value_type,
+ max_n_subrecs, 0);
+ }
+ GRN_API_RETURN(res);
+}
+
+unsigned int
+grn_table_get_subrecs(grn_ctx *ctx, grn_obj *table, grn_id id,
+ grn_id *subrecbuf, int *scorebuf, int buf_size)
+{
+ unsigned int count = 0;
+ GRN_API_ENTER;
+ if (GRN_OBJ_TABLEP(table)) {
+ uint32_t value_size;
+ grn_rset_recinfo *ri;
+ uint32_t subrec_size = DB_OBJ(table)->subrec_size;
+ uint32_t max_n_subrecs = DB_OBJ(table)->max_n_subrecs;
+ if (subrec_size < sizeof(grn_id)) { goto exit; }
+ if (!max_n_subrecs) { goto exit; }
+ ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, table, id, &value_size);
+ if (ri) {
+ byte *psubrec = (byte *)ri->subrecs;
+ uint32_t n_subrecs = (uint32_t)GRN_RSET_N_SUBRECS(ri);
+ uint32_t limit = value_size / (GRN_RSET_SCORE_SIZE + subrec_size);
+ if ((int) limit > buf_size) {
+ limit = buf_size;
+ }
+ if (limit > n_subrecs) {
+ limit = n_subrecs;
+ }
+ if (limit > max_n_subrecs) {
+ limit = max_n_subrecs;
+ }
+ for (; count < limit; count++) {
+ if (scorebuf) {
+ scorebuf[count] = *((double *)psubrec);
+ }
+ psubrec += GRN_RSET_SCORE_SIZE;
+ if (subrecbuf) {
+ subrecbuf[count] = *((grn_id *)psubrec);
+ }
+ psubrec += subrec_size;
+ }
+ }
+ }
+exit :
+ GRN_API_RETURN(count);
+}
+
+grn_obj *
+grn_table_open(grn_ctx *ctx, const char *name, unsigned int name_size, const char *path)
+{
+ grn_obj *db;
+ if (!ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "db not initialized");
+ return NULL;
+ }
+ GRN_API_ENTER;
+ if (!GRN_DB_P(db)) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
+ GRN_API_RETURN(NULL);
+ } else {
+ grn_obj *res = grn_ctx_get(ctx, name, name_size);
+ if (res) {
+ const char *path2 = grn_obj_path(ctx, res);
+ if (path && (!path2 || strcmp(path, path2))) {
+ ERR(GRN_INVALID_ARGUMENT, "path unmatch");
+ GRN_API_RETURN(NULL);
+ }
+ } else if (path) {
+ uint32_t type = grn_io_detect_type(ctx, path);
+ if (!type) { GRN_API_RETURN(NULL); }
+ switch (type) {
+ case GRN_TABLE_HASH_KEY :
+ res = (grn_obj *)grn_hash_open(ctx, path);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ res = (grn_obj *)grn_pat_open(ctx, path);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ res = (grn_obj *)grn_dat_open(ctx, path);
+ break;
+ case GRN_TABLE_NO_KEY :
+ res = (grn_obj *)grn_array_open(ctx, path);
+ break;
+ }
+ if (res) {
+ grn_id id = grn_obj_register(ctx, db, name, name_size);
+ res->header.flags |= GRN_OBJ_CUSTOM_NAME;
+ res->header.domain = GRN_ID_NIL; /* unknown */
+ DB_OBJ(res)->range = GRN_ID_NIL; /* unknown */
+ grn_db_obj_init(ctx, db, id, DB_OBJ(res));
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "path is missing");
+ }
+ GRN_API_RETURN(res);
+ }
+}
+
+grn_id
+grn_table_lcp_search(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
+{
+ grn_id id = GRN_ID_NIL;
+ GRN_API_ENTER;
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ {
+ grn_pat *pat = (grn_pat *)table;
+ WITH_NORMALIZE(pat, key, key_size, {
+ id = grn_pat_lcp_search(ctx, pat, key, key_size);
+ });
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ {
+ grn_dat *dat = (grn_dat *)table;
+ WITH_NORMALIZE(dat, key, key_size, {
+ id = grn_dat_lcp_search(ctx, dat, key, key_size);
+ });
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_hash *hash = (grn_hash *)table;
+ WITH_NORMALIZE(hash, key, key_size, {
+ id = grn_hash_get(ctx, hash, key, key_size, NULL);
+ });
+ }
+ break;
+ }
+ GRN_API_RETURN(id);
+}
+
+grn_obj *
+grn_obj_default_set_value_hook(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ if (!pctx) {
+ ERR(GRN_INVALID_ARGUMENT, "default_set_value_hook failed");
+ } else {
+ grn_obj *flags = grn_ctx_pop(ctx);
+ grn_obj *newvalue = grn_ctx_pop(ctx);
+ grn_obj *oldvalue = grn_ctx_pop(ctx);
+ grn_obj *id = grn_ctx_pop(ctx);
+ grn_hook *h = pctx->currh;
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(h);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ int section = data->section;
+ if (flags) { /* todo */ }
+ if (target) {
+ switch (target->header.type) {
+ case GRN_COLUMN_INDEX :
+ grn_ii_column_update(ctx, (grn_ii *)target,
+ GRN_UINT32_VALUE(id),
+ section, oldvalue, newvalue, NULL);
+ }
+ }
+ }
+ return NULL;
+}
+
+grn_id
+grn_table_add(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size, int *added)
+{
+ grn_id id = GRN_ID_NIL;
+ GRN_API_ENTER;
+ if (table) {
+ int added_ = 0;
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ {
+ grn_pat *pat = (grn_pat *)table;
+ WITH_NORMALIZE(pat, key, key_size, {
+ if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
+ if (grn_io_lock(ctx, pat->io, grn_lock_timeout)) {
+ id = GRN_ID_NIL;
+ } else {
+ id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
+ grn_io_unlock(pat->io);
+ }
+ } else {
+ id = grn_pat_add(ctx, pat, key, key_size, NULL, &added_);
+ }
+ });
+ if (added) { *added = added_; }
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ {
+ grn_dat *dat = (grn_dat *)table;
+ WITH_NORMALIZE(dat, key, key_size, {
+ if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
+ if (grn_io_lock(ctx, dat->io, grn_lock_timeout)) {
+ id = GRN_ID_NIL;
+ } else {
+ id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
+ grn_io_unlock(dat->io);
+ }
+ } else {
+ id = grn_dat_add(ctx, dat, key, key_size, NULL, &added_);
+ }
+ });
+ if (added) { *added = added_; }
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_hash *hash = (grn_hash *)table;
+ WITH_NORMALIZE(hash, key, key_size, {
+ if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
+ if (grn_io_lock(ctx, hash->io, grn_lock_timeout)) {
+ id = GRN_ID_NIL;
+ } else {
+ id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
+ grn_io_unlock(hash->io);
+ }
+ } else {
+ id = grn_hash_add(ctx, hash, key, key_size, NULL, &added_);
+ }
+ });
+ if (added) { *added = added_; }
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ {
+ grn_array *array = (grn_array *)table;
+ if (array->io && !(array->io->flags & GRN_IO_TEMPORARY)) {
+ if (grn_io_lock(ctx, array->io, grn_lock_timeout)) {
+ id = GRN_ID_NIL;
+ } else {
+ id = grn_array_add(ctx, array, NULL);
+ grn_io_unlock(array->io);
+ }
+ } else {
+ id = grn_array_add(ctx, array, NULL);
+ }
+ added_ = id ? 1 : 0;
+ if (added) { *added = added_; }
+ }
+ break;
+ }
+ if (added_) {
+ grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT];
+ if (hooks) {
+ // todo : grn_proc_ctx_open()
+ grn_obj id_, flags_, oldvalue_, value_;
+ grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4, {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}}};
+ GRN_UINT32_INIT(&id_, 0);
+ GRN_UINT32_INIT(&flags_, 0);
+ GRN_TEXT_INIT(&oldvalue_, 0);
+ GRN_TEXT_INIT(&value_, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&value_, key, key_size);
+ GRN_UINT32_SET(ctx, &id_, id);
+ GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
+ while (hooks) {
+ grn_ctx_push(ctx, &id_);
+ grn_ctx_push(ctx, &oldvalue_);
+ grn_ctx_push(ctx, &value_);
+ grn_ctx_push(ctx, &flags_);
+ pctx.caller = NULL;
+ pctx.currh = hooks;
+ if (hooks->proc) {
+ hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
+ } else {
+ grn_obj_default_set_value_hook(ctx, 1, &table, &pctx.user_data);
+ }
+ if (ctx->rc) { break; }
+ hooks = hooks->next;
+ pctx.offset++;
+ }
+ }
+ }
+ }
+ GRN_API_RETURN(id);
+}
+
+grn_id
+grn_table_get_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key)
+{
+ grn_id id = GRN_ID_NIL;
+ if (table->header.domain == key->header.domain) {
+ id = grn_table_get(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key));
+ } else {
+ grn_rc rc;
+ grn_obj buf;
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
+ if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
+ grn_obj *domain = grn_ctx_at(ctx, table->header.domain);
+ ERR_CAST(table, domain, key);
+ } else {
+ id = grn_table_get(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ return id;
+}
+
+grn_id
+grn_table_add_by_key(grn_ctx *ctx, grn_obj *table, grn_obj *key, int *added)
+{
+ grn_id id = GRN_ID_NIL;
+ if (table->header.domain == key->header.domain) {
+ id = grn_table_add(ctx, table, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key), added);
+ } else {
+ grn_rc rc;
+ grn_obj buf;
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, table->header.domain);
+ if ((rc = grn_obj_cast(ctx, key, &buf, GRN_TRUE))) {
+ grn_obj *domain = grn_ctx_at(ctx, table->header.domain);
+ ERR_CAST(table, domain, key);
+ } else {
+ id = grn_table_add(ctx, table, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf), added);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ return id;
+}
+
+grn_id
+grn_table_get(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
+{
+ grn_id id = GRN_ID_NIL;
+ GRN_API_ENTER;
+ if (table) {
+ if (table->header.type == GRN_DB) {
+ grn_db *db = (grn_db *)table;
+ table = db->keys;
+ }
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ WITH_NORMALIZE((grn_pat *)table, key, key_size, {
+ id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, NULL);
+ });
+ break;
+ case GRN_TABLE_DAT_KEY :
+ WITH_NORMALIZE((grn_dat *)table, key, key_size, {
+ id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, NULL);
+ });
+ break;
+ case GRN_TABLE_HASH_KEY :
+ WITH_NORMALIZE((grn_hash *)table, key, key_size, {
+ id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, NULL);
+ });
+ break;
+ }
+ }
+ GRN_API_RETURN(id);
+}
+
+grn_id
+grn_table_at(grn_ctx *ctx, grn_obj *table, grn_id id)
+{
+ GRN_API_ENTER;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_DB :
+ {
+ grn_db *db = (grn_db *)table;
+ id = grn_table_at(ctx, db->keys, id);
+ }
+ break;
+ case GRN_TABLE_PAT_KEY :
+ id = grn_pat_at(ctx, (grn_pat *)table, id);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ id = grn_dat_at(ctx, (grn_dat *)table, id);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ id = grn_hash_at(ctx, (grn_hash *)table, id);
+ break;
+ case GRN_TABLE_NO_KEY :
+ id = grn_array_at(ctx, (grn_array *)table, id);
+ break;
+ default :
+ id = GRN_ID_NIL;
+ }
+ }
+ GRN_API_RETURN(id);
+}
+
+inline static grn_id
+grn_table_add_v_inline(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
+ void **value, int *added)
+{
+ grn_id id = GRN_ID_NIL;
+ if (!key || !key_size) { return GRN_ID_NIL; }
+ if (table) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ WITH_NORMALIZE((grn_pat *)table, key, key_size, {
+ id = grn_pat_add(ctx, (grn_pat *)table, key, key_size, value, added);
+ });
+ break;
+ case GRN_TABLE_DAT_KEY :
+ WITH_NORMALIZE((grn_dat *)table, key, key_size, {
+ id = grn_dat_add(ctx, (grn_dat *)table, key, key_size, value, added);
+ });
+ break;
+ case GRN_TABLE_HASH_KEY :
+ WITH_NORMALIZE((grn_hash *)table, key, key_size, {
+ id = grn_hash_add(ctx, (grn_hash *)table, key, key_size, value, added);
+ });
+ break;
+ case GRN_TABLE_NO_KEY :
+ id = grn_array_add(ctx, (grn_array *)table, value);
+ if (added) { *added = id ? 1 : 0; }
+ break;
+ }
+ }
+ return id;
+}
+
+grn_id
+grn_table_add_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
+ void **value, int *added) {
+ grn_id id;
+ GRN_API_ENTER;
+ id = grn_table_add_v_inline(ctx, table, key, key_size, value, added);
+ GRN_API_RETURN(id);
+}
+
+grn_id
+grn_table_get_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
+ void **value)
+{
+ grn_id id = GRN_ID_NIL;
+ GRN_API_ENTER;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ WITH_NORMALIZE((grn_pat *)table, key, key_size, {
+ id = grn_pat_get(ctx, (grn_pat *)table, key, key_size, value);
+ });
+ break;
+ case GRN_TABLE_DAT_KEY :
+ WITH_NORMALIZE((grn_dat *)table, key, key_size, {
+ id = grn_dat_get(ctx, (grn_dat *)table, key, key_size, value);
+ });
+ break;
+ case GRN_TABLE_HASH_KEY :
+ WITH_NORMALIZE((grn_hash *)table, key, key_size, {
+ id = grn_hash_get(ctx, (grn_hash *)table, key, key_size, value);
+ });
+ break;
+ }
+ }
+ GRN_API_RETURN(id);
+}
+
+int
+grn_table_get_key(grn_ctx *ctx, grn_obj *table, grn_id id, void *keybuf, int buf_size)
+{
+ int r = 0;
+ GRN_API_ENTER;
+ if (table) {
+ if (table->header.type == GRN_DB) {
+ table = ((grn_db *)table)->keys;
+ }
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ r = grn_hash_get_key(ctx, (grn_hash *)table, id, keybuf, buf_size);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ r = grn_pat_get_key(ctx, (grn_pat *)table, id, keybuf, buf_size);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ r = grn_dat_get_key(ctx, (grn_dat *)table, id, keybuf, buf_size);
+ break;
+ case GRN_TABLE_NO_KEY :
+ {
+ grn_array *a = (grn_array *)table;
+ if (a->obj.header.domain) {
+ if ((unsigned int) buf_size >= a->value_size) {
+ r = grn_array_get_value(ctx, a, id, keybuf);
+ } else {
+ r = a->value_size;
+ }
+ }
+ }
+ break;
+ }
+ }
+ GRN_API_RETURN(r);
+}
+
+int
+grn_table_get_key2(grn_ctx *ctx, grn_obj *table, grn_id id, grn_obj *bulk)
+{
+ int r = 0;
+ GRN_API_ENTER;
+ if (table) {
+ if (table->header.type == GRN_DB) {
+ table = ((grn_db *)table)->keys;
+ }
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ r = grn_hash_get_key2(ctx, (grn_hash *)table, id, bulk);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ r = grn_pat_get_key2(ctx, (grn_pat *)table, id, bulk);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ r = grn_dat_get_key2(ctx, (grn_dat *)table, id, bulk);
+ break;
+ case GRN_TABLE_NO_KEY :
+ {
+ grn_array *a = (grn_array *)table;
+ if (a->obj.header.domain) {
+ if (!grn_bulk_space(ctx, bulk, a->value_size)) {
+ char *curr = GRN_BULK_CURR(bulk);
+ r = grn_array_get_value(ctx, a, id, curr - a->value_size);
+ }
+ }
+ }
+ break;
+ }
+ }
+ GRN_API_RETURN(r);
+}
+
+static grn_rc
+grn_obj_clear_value(grn_ctx *ctx, grn_obj *obj, grn_id id)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (GRN_DB_OBJP(obj)) {
+ grn_obj buf;
+ grn_id range = DB_OBJ(obj)->range;
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ switch (obj->header.type) {
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ rc = grn_obj_set_value(ctx, obj, id, &buf, GRN_OBJ_SET);
+ break;
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ return rc;
+}
+
+static void
+call_delete_hook(grn_ctx *ctx, grn_obj *table, grn_id rid, const void *key, unsigned int key_size)
+{
+ if (rid) {
+ grn_hook *hooks = DB_OBJ(table)->hooks[GRN_HOOK_DELETE];
+ if (hooks) {
+ // todo : grn_proc_ctx_open()
+ grn_obj id_, flags_, oldvalue_, value_;
+ grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4, {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}}};
+ GRN_UINT32_INIT(&id_, 0);
+ GRN_UINT32_INIT(&flags_, 0);
+ GRN_TEXT_INIT(&oldvalue_, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_INIT(&value_, 0);
+ GRN_TEXT_SET_REF(&oldvalue_, key, key_size);
+ GRN_UINT32_SET(ctx, &id_, rid);
+ GRN_UINT32_SET(ctx, &flags_, GRN_OBJ_SET);
+ while (hooks) {
+ grn_ctx_push(ctx, &id_);
+ grn_ctx_push(ctx, &oldvalue_);
+ grn_ctx_push(ctx, &value_);
+ grn_ctx_push(ctx, &flags_);
+ pctx.caller = NULL;
+ pctx.currh = hooks;
+ if (hooks->proc) {
+ hooks->proc->funcs[PROC_INIT](ctx, 1, &table, &pctx.user_data);
+ } else {
+ grn_obj_default_set_value_hook(ctx, 1, &table, &pctx.user_data);
+ }
+ if (ctx->rc) { break; }
+ hooks = hooks->next;
+ pctx.offset++;
+ }
+ }
+ }
+}
+
+static void
+clear_column_values(grn_ctx *ctx, grn_obj *table, grn_id rid)
+{
+ if (rid) {
+ grn_hash *cols;
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) { grn_obj_clear_value(ctx, col, rid); }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+ }
+}
+
+static void
+delete_reference_records_in_index(grn_ctx *ctx, grn_obj *table, grn_id id,
+ grn_obj *index)
+{
+ grn_ii *ii = (grn_ii *)index;
+ grn_ii_cursor *ii_cursor = NULL;
+ grn_posting *posting;
+ grn_obj source_ids;
+ unsigned int i, n_ids;
+ grn_obj sources;
+ grn_bool have_reference_source = GRN_FALSE;
+
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+ GRN_PTR_INIT(&sources, GRN_OBJ_VECTOR, 0);
+
+ grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
+ n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+ if (n_ids == 0) {
+ goto exit;
+ }
+
+ for (i = 0; i < n_ids; i++) {
+ grn_id source_id;
+ grn_obj *source;
+
+ source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
+ source = grn_ctx_at(ctx, source_id);
+ if (grn_obj_get_range(ctx, source) == index->header.domain) {
+ GRN_PTR_PUT(ctx, &sources, source);
+ have_reference_source = GRN_TRUE;
+ } else {
+ grn_obj_unlink(ctx, source);
+ GRN_PTR_PUT(ctx, &sources, NULL);
+ }
+ }
+
+ if (!have_reference_source) {
+ goto exit;
+ }
+
+ ii_cursor = grn_ii_cursor_open(ctx, ii, id, GRN_ID_NIL, GRN_ID_MAX,
+ ii->n_elements, 0);
+ if (!ii_cursor) {
+ goto exit;
+ }
+
+ while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
+ grn_obj *source = GRN_PTR_VALUE_AT(&sources, posting->sid - 1);
+ if (!source) {
+ continue;
+ }
+ switch (source->header.type) {
+ case GRN_COLUMN_VAR_SIZE :
+ switch (source->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_SCALAR :
+ grn_obj_clear_value(ctx, source, posting->rid);
+ break;
+ case GRN_OBJ_COLUMN_VECTOR :
+ {
+ grn_obj value;
+ grn_obj new_value;
+ GRN_TEXT_INIT(&value, 0);
+ grn_obj_get_value(ctx, source, posting->rid, &value);
+ if (value.header.type == GRN_UVECTOR) {
+ int i, n_ids;
+ GRN_RECORD_INIT(&new_value, GRN_OBJ_VECTOR, value.header.domain);
+ n_ids = GRN_BULK_VSIZE(&value) / sizeof(grn_id);
+ for (i = 0; i < n_ids; i++) {
+ grn_id reference_id = GRN_RECORD_VALUE_AT(&value, i);
+ if (reference_id == id) {
+ continue;
+ }
+ GRN_RECORD_PUT(ctx, &new_value, reference_id);
+ }
+ } else {
+ unsigned int i, n_elements;
+ GRN_TEXT_INIT(&new_value, GRN_OBJ_VECTOR);
+ n_elements = grn_vector_size(ctx, &value);
+ for (i = 0; i < n_elements; i++) {
+ const char *content;
+ unsigned int content_length;
+ unsigned int weight;
+ grn_id domain;
+ content_length =
+ grn_vector_get_element(ctx, &value, i,
+ &content, &weight, &domain);
+ if (grn_table_get(ctx, table, content, content_length) == id) {
+ continue;
+ }
+ grn_vector_add_element(ctx, &new_value, content, content_length,
+ weight, domain);
+ }
+ }
+ grn_obj_set_value(ctx, source, posting->rid, &new_value,
+ GRN_OBJ_SET);
+ GRN_OBJ_FIN(ctx, &new_value);
+ GRN_OBJ_FIN(ctx, &value);
+ }
+ break;
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ grn_obj_clear_value(ctx, source, posting->rid);
+ break;
+ }
+ }
+
+exit:
+ if (ii_cursor) {
+ grn_ii_cursor_close(ctx, ii_cursor);
+ }
+ grn_obj_unlink(ctx, &source_ids);
+ {
+ int i, n_sources;
+ n_sources = GRN_BULK_VSIZE(&sources) / sizeof(grn_obj *);
+ for (i = 0; i < n_sources; i++) {
+ grn_obj *source = GRN_PTR_VALUE_AT(&sources, i);
+ grn_obj_unlink(ctx, source);
+ }
+ grn_obj_unlink(ctx, &sources);
+ }
+}
+
+static grn_rc
+delete_reference_records(grn_ctx *ctx, grn_obj *table, grn_id id)
+{
+ grn_hash *cols;
+ grn_id *key;
+
+ cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (!cols) {
+ return ctx->rc;
+ }
+
+ if (!grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
+ grn_hash_close(ctx, cols);
+ return ctx->rc;
+ }
+
+ GRN_HASH_EACH(ctx, cols, tid, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (!col) {
+ continue;
+ }
+ if (col->header.type != GRN_COLUMN_INDEX) {
+ continue;
+ }
+ delete_reference_records_in_index(ctx, table, id, col);
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ });
+
+ grn_hash_close(ctx, cols);
+
+ return ctx->rc;
+}
+
+static grn_rc
+grn_table_delete_prepare(grn_ctx *ctx, grn_obj *table,
+ grn_id id, const void *key, unsigned int key_size)
+{
+ grn_rc rc;
+
+ rc = delete_reference_records(ctx, table, id);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ call_delete_hook(ctx, table, id, key, key_size);
+ clear_column_values(ctx, table, id);
+
+ return rc;
+}
+
+grn_rc
+grn_table_delete(grn_ctx *ctx, grn_obj *table, const void *key, unsigned int key_size)
+{
+ grn_id rid = GRN_ID_NIL;
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (table) {
+ if (key && key_size) { rid = grn_table_get(ctx, table, key, key_size); }
+ if (rid) {
+ rc = grn_table_delete_prepare(ctx, table, rid, key, key_size);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ switch (table->header.type) {
+ case GRN_DB :
+ /* todo : delete tables and columns from db */
+ break;
+ case GRN_TABLE_PAT_KEY :
+ WITH_NORMALIZE((grn_pat *)table, key, key_size, {
+ grn_pat *pat = (grn_pat *)table;
+ if (pat->io && !(pat->io->flags & GRN_IO_TEMPORARY)) {
+ if (!(rc = grn_io_lock(ctx, pat->io, grn_lock_timeout))) {
+ rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
+ grn_io_unlock(pat->io);
+ }
+ } else {
+ rc = grn_pat_delete(ctx, pat, key, key_size, NULL);
+ }
+ });
+ break;
+ case GRN_TABLE_DAT_KEY :
+ WITH_NORMALIZE((grn_dat *)table, key, key_size, {
+ grn_dat *dat = (grn_dat *)table;
+ if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
+ if (!(rc = grn_io_lock(ctx, dat->io, grn_lock_timeout))) {
+ rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
+ grn_io_unlock(dat->io);
+ }
+ } else {
+ rc = grn_dat_delete(ctx, dat, key, key_size, NULL);
+ }
+ });
+ break;
+ case GRN_TABLE_HASH_KEY :
+ WITH_NORMALIZE((grn_hash *)table, key, key_size, {
+ grn_hash *hash = (grn_hash *)table;
+ if (hash->io && !(hash->io->flags & GRN_IO_TEMPORARY)) {
+ if (!(rc = grn_io_lock(ctx, hash->io, grn_lock_timeout))) {
+ rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
+ grn_io_unlock(hash->io);
+ }
+ } else {
+ rc = grn_hash_delete(ctx, hash, key, key_size, NULL);
+ }
+ });
+ break;
+ }
+ if (rc == GRN_SUCCESS) {
+ grn_obj_touch(ctx, table, NULL);
+ }
+ }
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+_grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
+ grn_table_delete_optarg *optarg)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ if (table) {
+ if (id) {
+ const void *key = NULL;
+ unsigned int key_size = 0;
+
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ key = _grn_table_key(ctx, table, id, &key_size);
+ }
+ rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ // todo : support optarg
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ rc = grn_pat_delete_by_id(ctx, (grn_pat *)table, id, optarg);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = grn_dat_delete_by_id(ctx, (grn_dat *)table, id, optarg);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ rc = grn_hash_delete_by_id(ctx, (grn_hash *)table, id, optarg);
+ break;
+ case GRN_TABLE_NO_KEY :
+ rc = grn_array_delete_by_id(ctx, (grn_array *)table, id, optarg);
+ break;
+ }
+ }
+ }
+exit :
+ return rc;
+}
+
+grn_rc
+grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id)
+{
+ grn_rc rc;
+ grn_io *io;
+ GRN_API_ENTER;
+ if ((io = grn_obj_get_io(ctx, table)) && !(io->flags & GRN_IO_TEMPORARY)) {
+ if (!(rc = grn_io_lock(ctx, io, grn_lock_timeout))) {
+ rc = _grn_table_delete_by_id(ctx, table, id, NULL);
+ grn_io_unlock(io);
+ }
+ } else {
+ rc = _grn_table_delete_by_id(ctx, table, id, NULL);
+ }
+ if (rc == GRN_SUCCESS) {
+ grn_obj_touch(ctx, table, NULL);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc grn_ja_truncate(grn_ctx *ctx, grn_ja *ja);
+grn_rc grn_ra_truncate(grn_ctx *ctx, grn_ra *ra);
+
+grn_rc
+grn_column_truncate(grn_ctx *ctx, grn_obj *column)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (column) {
+ grn_hook *hooks;
+ switch (column->header.type) {
+ case GRN_COLUMN_INDEX :
+ rc = grn_ii_truncate(ctx, (grn_ii *)column);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
+ }
+ rc = grn_ja_truncate(ctx, (grn_ja *)column);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ for (hooks = DB_OBJ(column)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
+ }
+ rc = grn_ra_truncate(ctx, (grn_ra *)column);
+ break;
+ }
+ if (rc == GRN_SUCCESS) {
+ grn_obj_touch(ctx, column, NULL);
+ }
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_truncate(grn_ctx *ctx, grn_obj *table)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (table) {
+ grn_hook *hooks;
+ grn_hash *cols;
+ grn_obj *tokenizer;
+ grn_obj *normalizer;
+ grn_obj token_filters;
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) { grn_column_truncate(ctx, col); }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ grn_table_get_info(ctx, table, NULL, NULL, &tokenizer, &normalizer, NULL);
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
+ }
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
+ }
+ rc = grn_pat_truncate(ctx, (grn_pat *)table);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
+ }
+ rc = grn_dat_truncate(ctx, (grn_dat *)table);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ for (hooks = DB_OBJ(table)->hooks[GRN_HOOK_INSERT]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if ((rc = grn_ii_truncate(ctx, (grn_ii *)target))) { goto exit; }
+ }
+ rc = grn_hash_truncate(ctx, (grn_hash *)table);
+ break;
+ case GRN_TABLE_NO_KEY :
+ rc = grn_array_truncate(ctx, (grn_array *)table);
+ break;
+ }
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ grn_obj_set_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
+ grn_obj_set_info(ctx, table, GRN_INFO_NORMALIZER, normalizer);
+ grn_obj_set_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
+ GRN_OBJ_FIN(ctx, &token_filters);
+ }
+ if (rc == GRN_SUCCESS) {
+ grn_obj_touch(ctx, table, NULL);
+ }
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_get_info(grn_ctx *ctx, grn_obj *table, grn_table_flags *flags,
+ grn_encoding *encoding, grn_obj **tokenizer,
+ grn_obj **normalizer,
+ grn_obj **token_filters)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ if (flags) { *flags = ((grn_pat *)table)->header->flags; }
+ if (encoding) { *encoding = ((grn_pat *)table)->encoding; }
+ if (tokenizer) { *tokenizer = ((grn_pat *)table)->tokenizer; }
+ if (normalizer) { *normalizer = ((grn_pat *)table)->normalizer; }
+ if (token_filters) { *token_filters = &(((grn_pat *)table)->token_filters); }
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ if (flags) { *flags = ((grn_dat *)table)->header->flags; }
+ if (encoding) { *encoding = ((grn_dat *)table)->encoding; }
+ if (tokenizer) { *tokenizer = ((grn_dat *)table)->tokenizer; }
+ if (normalizer) { *normalizer = ((grn_dat *)table)->normalizer; }
+ if (token_filters) { *token_filters = &(((grn_dat *)table)->token_filters); }
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_HASH_KEY :
+ if (flags) { *flags = ((grn_hash *)table)->header.common->flags; }
+ if (encoding) { *encoding = ((grn_hash *)table)->encoding; }
+ if (tokenizer) { *tokenizer = ((grn_hash *)table)->tokenizer; }
+ if (normalizer) { *normalizer = ((grn_hash *)table)->normalizer; }
+ if (token_filters) { *token_filters = &(((grn_hash *)table)->token_filters); }
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_NO_KEY :
+ if (flags) { *flags = grn_array_get_flags(ctx, ((grn_array *)table)); }
+ if (encoding) { *encoding = GRN_ENC_NONE; }
+ if (tokenizer) { *tokenizer = NULL; }
+ if (normalizer) { *normalizer = NULL; }
+ if (token_filters) { *token_filters = NULL; }
+ rc = GRN_SUCCESS;
+ break;
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+unsigned int
+grn_table_size(grn_ctx *ctx, grn_obj *table)
+{
+ unsigned int n = 0;
+ GRN_API_ENTER;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_DB :
+ n = grn_table_size(ctx, ((grn_db *)table)->keys);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ n = grn_pat_size(ctx, (grn_pat *)table);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ n = grn_dat_size(ctx, (grn_dat *)table);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ n = grn_hash_size(ctx, (grn_hash *)table);
+ break;
+ case GRN_TABLE_NO_KEY :
+ n = grn_array_size(ctx, (grn_array *)table);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "not supported");
+ break;
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "invalid table assigned");
+ }
+ GRN_API_RETURN(n);
+}
+
+inline static void
+subrecs_push(byte *subrecs, int size, int n_subrecs, double score, void *body, int dir)
+{
+ byte *v;
+ double *c2;
+ int n = n_subrecs - 1, n2;
+ while (n) {
+ n2 = (n - 1) >> 1;
+ c2 = GRN_RSET_SUBRECS_NTH(subrecs,size,n2);
+ if (GRN_RSET_SUBRECS_CMP(score, *c2, dir) >= 0) { break; }
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
+ n = n2;
+ }
+ v = subrecs + n * (GRN_RSET_SCORE_SIZE + size);
+ *((double *)v) = score;
+ grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
+}
+
+inline static void
+subrecs_replace_min(byte *subrecs, int size, int n_subrecs, double score, void *body, int dir)
+{
+ byte *v;
+ int n = 0, n1, n2;
+ double *c1, *c2;
+ for (;;) {
+ n1 = n * 2 + 1;
+ n2 = n1 + 1;
+ c1 = n1 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
+ c2 = n2 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
+ if (c1 && GRN_RSET_SUBRECS_CMP(score, *c1, dir) > 0) {
+ if (c2 &&
+ GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0 &&
+ GRN_RSET_SUBRECS_CMP(*c1, *c2, dir) > 0) {
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
+ n = n2;
+ } else {
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
+ n = n1;
+ }
+ } else {
+ if (c2 && GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) {
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
+ n = n2;
+ } else {
+ break;
+ }
+ }
+ }
+ v = subrecs + n * (GRN_RSET_SCORE_SIZE + size);
+ grn_memcpy(v, &score, GRN_RSET_SCORE_SIZE);
+ grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
+}
+
+inline static void
+grn_table_add_subrec_inline(grn_obj *table, grn_rset_recinfo *ri, double score,
+ grn_rset_posinfo *pi, int dir)
+{
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ int limit = DB_OBJ(table)->max_n_subrecs;
+ ri->score += score;
+ ri->n_subrecs += 1;
+ if (limit) {
+ int subrec_size = DB_OBJ(table)->subrec_size;
+ int n_subrecs = GRN_RSET_N_SUBRECS(ri);
+ if (pi) {
+ byte *body = (byte *)pi + DB_OBJ(table)->subrec_offset;
+ if (limit < n_subrecs) {
+ if (GRN_RSET_SUBRECS_CMP(score, *((double *)(ri->subrecs)), dir) > 0) {
+ subrecs_replace_min((byte *)ri->subrecs, subrec_size, limit, score, body, dir);
+ }
+ } else {
+ subrecs_push((byte *)ri->subrecs, subrec_size, n_subrecs, score, body, dir);
+ }
+ }
+ }
+ }
+}
+
+void
+grn_table_add_subrec(grn_obj *table, grn_rset_recinfo *ri, double score,
+ grn_rset_posinfo *pi, int dir)
+{
+ grn_table_add_subrec_inline(table, ri, score, pi, dir);
+}
+
+grn_table_cursor *
+grn_table_cursor_open(grn_ctx *ctx, grn_obj *table,
+ const void *min, unsigned int min_size,
+ const void *max, unsigned int max_size,
+ int offset, int limit, int flags)
+{
+ grn_rc rc;
+ grn_table_cursor *tc = NULL;
+ unsigned int table_size;
+ if (!table) { return tc; }
+ GRN_API_ENTER;
+ table_size = grn_table_size(ctx, table);
+ if (flags & GRN_CURSOR_PREFIX) {
+ if (offset < 0) {
+ ERR(GRN_TOO_SMALL_OFFSET,
+ "can't use negative offset with GRN_CURSOR_PREFIX: %d", offset);
+ } else if (offset != 0 && offset >= (int) table_size) {
+ ERR(GRN_TOO_LARGE_OFFSET,
+ "offset is not less than table size: offset:%d, table_size:%d",
+ offset, table_size);
+ } else {
+ if (limit < -1) {
+ ERR(GRN_TOO_SMALL_LIMIT,
+ "can't use smaller limit than -1 with GRN_CURSOR_PREFIX: %d",
+ limit);
+ } else if (limit == -1) {
+ limit = table_size;
+ }
+ }
+ } else {
+ rc = grn_normalize_offset_and_limit(ctx, table_size, &offset, &limit);
+ if (rc) {
+ ERR(rc, "grn_normalize_offset_and_limit failed");
+ }
+ }
+ if (!ctx->rc) {
+ if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ {
+ grn_pat *pat = (grn_pat *)table;
+ WITH_NORMALIZE(pat, min, min_size, {
+ WITH_NORMALIZE(pat, max, max_size, {
+ grn_pat_cursor *pat_cursor;
+ pat_cursor = grn_pat_cursor_open(ctx, pat,
+ min, min_size,
+ max, max_size,
+ offset, limit, flags);
+ tc = (grn_table_cursor *)pat_cursor;
+ });
+ });
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ {
+ grn_dat *dat = (grn_dat *)table;
+ WITH_NORMALIZE(dat, min, min_size, {
+ WITH_NORMALIZE(dat, max, max_size, {
+ grn_dat_cursor *dat_cursor;
+ dat_cursor = grn_dat_cursor_open(ctx, dat,
+ min, min_size,
+ max, max_size,
+ offset, limit, flags);
+ tc = (grn_table_cursor *)dat_cursor;
+ });
+ });
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_hash *hash = (grn_hash *)table;
+ WITH_NORMALIZE(hash, min, min_size, {
+ WITH_NORMALIZE(hash, max, max_size, {
+ grn_hash_cursor *hash_cursor;
+ hash_cursor = grn_hash_cursor_open(ctx, hash,
+ min, min_size,
+ max, max_size,
+ offset, limit, flags);
+ tc = (grn_table_cursor *)hash_cursor;
+ });
+ });
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
+ GRN_ID_NIL, GRN_ID_NIL,
+ offset, limit, flags);
+ break;
+ }
+ }
+ if (tc) {
+ grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
+ DB_OBJ(tc)->header.domain = GRN_ID_NIL;
+ DB_OBJ(tc)->range = GRN_ID_NIL;
+ grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(tc));
+ }
+ GRN_API_RETURN(tc);
+}
+
+grn_table_cursor *
+grn_table_cursor_open_by_id(grn_ctx *ctx, grn_obj *table,
+ grn_id min, grn_id max, int flags)
+{
+ grn_table_cursor *tc = NULL;
+ GRN_API_ENTER;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ tc = (grn_table_cursor *)grn_pat_cursor_open(ctx, (grn_pat *)table,
+ NULL, 0, NULL, 0, 0, -1, flags);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ tc = (grn_table_cursor *)grn_dat_cursor_open(ctx, (grn_dat *)table,
+ NULL, 0, NULL, 0, 0, -1, flags);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ tc = (grn_table_cursor *)grn_hash_cursor_open(ctx, (grn_hash *)table,
+ NULL, 0, NULL, 0, 0, -1, flags);
+ break;
+ case GRN_TABLE_NO_KEY :
+ tc = (grn_table_cursor *)grn_array_cursor_open(ctx, (grn_array *)table,
+ min, max, 0, -1, flags);
+ break;
+ }
+ }
+ GRN_API_RETURN(tc);
+}
+
+grn_rc
+grn_table_cursor_close(grn_ctx *ctx, grn_table_cursor *tc)
+{
+ const char *tag = "[table][cursor][close]";
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ if (!tc) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc, "%s invalid cursor", tag);
+ } else {
+ {
+ if (DB_OBJ(tc)->finalizer) {
+ DB_OBJ(tc)->finalizer(ctx, 1, (grn_obj **)&tc, &DB_OBJ(tc)->user_data);
+ }
+ if (DB_OBJ(tc)->source) {
+ GRN_FREE(DB_OBJ(tc)->source);
+ }
+ /*
+ grn_hook_entry entry;
+ for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
+ grn_hook_free(ctx, DB_OBJ(tc)->hooks[entry]);
+ }
+ */
+ grn_obj_delete_by_id(ctx, DB_OBJ(tc)->db, DB_OBJ(tc)->id, GRN_FALSE);
+ }
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ grn_pat_cursor_close(ctx, (grn_pat_cursor *)tc);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ grn_dat_cursor_close(ctx, (grn_dat_cursor *)tc);
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ grn_hash_cursor_close(ctx, (grn_hash_cursor *)tc);
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ grn_array_cursor_close(ctx, (grn_array_cursor *)tc);
+ break;
+ default :
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+inline static grn_id
+grn_table_cursor_next_inline(grn_ctx *ctx, grn_table_cursor *tc)
+{
+ const char *tag = "[table][cursor][next]";
+ grn_id id = GRN_ID_NIL;
+ if (!tc) {
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
+ } else {
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ id = grn_pat_cursor_next(ctx, (grn_pat_cursor *)tc);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ id = grn_dat_cursor_next(ctx, (grn_dat_cursor *)tc);
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ id = grn_hash_cursor_next(ctx, (grn_hash_cursor *)tc);
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ id = grn_array_cursor_next(ctx, (grn_array_cursor *)tc);
+ break;
+ case GRN_CURSOR_COLUMN_INDEX :
+ {
+ grn_posting *ip = grn_index_cursor_next(ctx, (grn_obj *)tc, NULL);
+ if (ip) { id = ip->rid; }
+ }
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+ return id;
+}
+
+grn_id
+grn_table_cursor_next(grn_ctx *ctx, grn_table_cursor *tc)
+{
+ grn_id id;
+ GRN_API_ENTER;
+ id = grn_table_cursor_next_inline(ctx, tc);
+ GRN_API_RETURN(id);
+}
+
+int
+grn_table_cursor_get_key(grn_ctx *ctx, grn_table_cursor *tc, void **key)
+{
+ const char *tag = "[table][cursor][get-key]";
+ int len = 0;
+ GRN_API_ENTER;
+ if (!tc) {
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
+ } else {
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ len = grn_pat_cursor_get_key(ctx, (grn_pat_cursor *)tc, key);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ len = grn_dat_cursor_get_key(ctx, (grn_dat_cursor *)tc, (const void **)key);
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ len = grn_hash_cursor_get_key(ctx, (grn_hash_cursor *)tc, key);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+ GRN_API_RETURN(len);
+}
+
+inline static int
+grn_table_cursor_get_value_inline(grn_ctx *ctx, grn_table_cursor *tc, void **value)
+{
+ const char *tag = "[table][cursor][get-value]";
+ int len = 0;
+ if (!tc) {
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
+ } else {
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ len = grn_pat_cursor_get_value(ctx, (grn_pat_cursor *)tc, value);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ *value = NULL;
+ len = 0;
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ len = grn_hash_cursor_get_value(ctx, (grn_hash_cursor *)tc, value);
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ len = grn_array_cursor_get_value(ctx, (grn_array_cursor *)tc, value);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+ return len;
+}
+
+int
+grn_table_cursor_get_value(grn_ctx *ctx, grn_table_cursor *tc, void **value)
+{
+ int len;
+ GRN_API_ENTER;
+ len = grn_table_cursor_get_value_inline(ctx, tc, value);
+ GRN_API_RETURN(len);
+}
+
+grn_rc
+grn_table_cursor_set_value(grn_ctx *ctx, grn_table_cursor *tc,
+ const void *value, int flags)
+{
+ const char *tag = "[table][cursor][set-value]";
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (!tc) {
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
+ } else {
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ rc = grn_pat_cursor_set_value(ctx, (grn_pat_cursor *)tc, value, flags);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ rc = grn_hash_cursor_set_value(ctx, (grn_hash_cursor *)tc, value, flags);
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ rc = grn_array_cursor_set_value(ctx, (grn_array_cursor *)tc, value, flags);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_cursor_delete(grn_ctx *ctx, grn_table_cursor *tc)
+{
+ const char *tag = "[table][cursor][delete]";
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (!tc) {
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
+ } else {
+ grn_id id;
+ grn_obj *table;
+ const void *key = NULL;
+ unsigned int key_size = 0;
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ {
+ grn_pat_cursor *pc = (grn_pat_cursor *)tc;
+ id = pc->curr_rec;
+ table = (grn_obj *)(pc->pat);
+ key = _grn_pat_key(ctx, pc->pat, id, &key_size);
+ rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ rc = grn_pat_cursor_delete(ctx, pc, NULL);
+ }
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ {
+ grn_hash_cursor *hc = (grn_hash_cursor *)tc;
+ id = hc->curr_rec;
+ table = (grn_obj *)(hc->hash);
+ key = _grn_hash_key(ctx, hc->hash, id, &key_size);
+ rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ rc = grn_hash_cursor_delete(ctx, hc, NULL);
+ }
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ {
+ grn_array_cursor *ac = (grn_array_cursor *)tc;
+ id = ac->curr_rec;
+ table = (grn_obj *)(ac->array);
+ rc = grn_table_delete_prepare(ctx, table, id, key, key_size);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ rc = grn_array_cursor_delete(ctx, ac, NULL);
+ }
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_obj *
+grn_table_cursor_table(grn_ctx *ctx, grn_table_cursor *tc)
+{
+ const char *tag = "[table][cursor][table]";
+ grn_obj *obj = NULL;
+ GRN_API_ENTER;
+ if (!tc) {
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid cursor", tag);
+ } else {
+ switch (tc->header.type) {
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ obj = (grn_obj *)(((grn_pat_cursor *)tc)->pat);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ obj = (grn_obj *)(((grn_dat_cursor *)tc)->dat);
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ obj = (grn_obj *)(((grn_hash_cursor *)tc)->hash);
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ obj = (grn_obj *)(((grn_array_cursor *)tc)->array);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "%s invalid type %d", tag, tc->header.type);
+ break;
+ }
+ }
+ GRN_API_RETURN(obj);
+}
+
+typedef struct {
+ grn_db_obj obj;
+ grn_obj *index;
+ grn_table_cursor *tc;
+ grn_ii_cursor *iic;
+ grn_id tid;
+ grn_id rid_min;
+ grn_id rid_max;
+ int flags;
+} grn_index_cursor;
+
+grn_obj *
+grn_index_cursor_open(grn_ctx *ctx, grn_table_cursor *tc,
+ grn_obj *index, grn_id rid_min, grn_id rid_max, int flags)
+{
+ grn_index_cursor *ic = NULL;
+ GRN_API_ENTER;
+ if (tc && (ic = GRN_MALLOCN(grn_index_cursor, 1))) {
+ ic->tc = tc;
+ ic->index = index;
+ ic->iic = NULL;
+ ic->tid = GRN_ID_NIL;
+ ic->rid_min = rid_min;
+ ic->rid_max = rid_max;
+ ic->flags = flags;
+ GRN_DB_OBJ_SET_TYPE(ic, GRN_CURSOR_COLUMN_INDEX);
+ {
+ grn_id id = grn_obj_register(ctx, ctx->impl->db, NULL, 0);
+ DB_OBJ(ic)->header.domain = GRN_ID_NIL;
+ DB_OBJ(ic)->range = GRN_ID_NIL;
+ grn_db_obj_init(ctx, ctx->impl->db, id, DB_OBJ(ic));
+ }
+ }
+ GRN_API_RETURN((grn_obj *)ic);
+}
+
+grn_posting *
+grn_index_cursor_next(grn_ctx *ctx, grn_obj *c, grn_id *tid)
+{
+ grn_posting *ip = NULL;
+ grn_index_cursor *ic = (grn_index_cursor *)c;
+ GRN_API_ENTER;
+ if (ic->iic) {
+ if (ic->flags & GRN_OBJ_WITH_POSITION) {
+ ip = grn_ii_cursor_next_pos(ctx, ic->iic);
+ while (!ip && grn_ii_cursor_next(ctx, ic->iic)) {
+ ip = grn_ii_cursor_next_pos(ctx, ic->iic);
+ break;
+ }
+ } else {
+ ip = grn_ii_cursor_next(ctx, ic->iic);
+ }
+ }
+ if (!ip) {
+ while ((ic->tid = grn_table_cursor_next_inline(ctx, ic->tc))) {
+ grn_ii *ii = (grn_ii *)ic->index;
+ if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
+ if ((ic->iic = grn_ii_cursor_open(ctx, ii, ic->tid,
+ ic->rid_min, ic->rid_max,
+ ii->n_elements, ic->flags))) {
+ ip = grn_ii_cursor_next(ctx, ic->iic);
+ if (ip && ic->flags & GRN_OBJ_WITH_POSITION) {
+ ip = grn_ii_cursor_next_pos(ctx, ic->iic);
+ }
+ if (ip) {
+ break;
+ }
+ }
+ }
+ }
+ if (tid) { *tid = ic->tid; }
+ GRN_API_RETURN((grn_posting *)ip);
+}
+
+grn_rc
+grn_table_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
+ grn_operator mode, grn_obj *res, grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ {
+ grn_pat *pat = (grn_pat *)table;
+ WITH_NORMALIZE(pat, key, key_size, {
+ switch (mode) {
+ case GRN_OP_EXACT :
+ {
+ grn_id id = grn_pat_get(ctx, pat, key, key_size, NULL);
+ if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
+ }
+ // todo : support op;
+ break;
+ case GRN_OP_LCP :
+ {
+ grn_id id = grn_pat_lcp_search(ctx, pat, key, key_size);
+ if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
+ }
+ // todo : support op;
+ break;
+ case GRN_OP_SUFFIX :
+ rc = grn_pat_suffix_search(ctx, pat, key, key_size, (grn_hash *)res);
+ // todo : support op;
+ break;
+ case GRN_OP_PREFIX :
+ rc = grn_pat_prefix_search(ctx, pat, key, key_size, (grn_hash *)res);
+ // todo : support op;
+ break;
+ case GRN_OP_TERM_EXTRACT :
+ {
+ int len;
+ grn_id tid;
+ const char *sp = key;
+ const char *se = sp + key_size;
+ for (; sp < se; sp += len) {
+ if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
+ grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
+ /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
+ }
+ if (!(len = grn_charlen(ctx, sp, se))) { break; }
+ }
+ }
+ // todo : support op;
+ break;
+ default :
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc, "invalid mode %d", mode);
+ }
+ });
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ {
+ grn_dat *dat = (grn_dat *)table;
+ WITH_NORMALIZE(dat, key, key_size, {
+ switch (mode) {
+ case GRN_OP_EXACT :
+ {
+ grn_id id = grn_dat_get(ctx, dat, key, key_size, NULL);
+ if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
+ }
+ break;
+ case GRN_OP_PREFIX :
+ {
+ grn_dat_cursor *dc = grn_dat_cursor_open(ctx, dat, key, key_size, NULL, 0,
+ 0, -1, GRN_CURSOR_PREFIX);
+ if (dc) {
+ grn_id id;
+ while ((id = grn_dat_cursor_next(ctx, dc))) {
+ grn_table_add(ctx, res, &id, sizeof(grn_id), NULL);
+ }
+ grn_dat_cursor_close(ctx, dc);
+ }
+ }
+ break;
+ case GRN_OP_LCP :
+ {
+ grn_id id = grn_dat_lcp_search(ctx, dat, key, key_size);
+ if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
+ }
+ break;
+ case GRN_OP_TERM_EXTRACT :
+ {
+ int len;
+ grn_id tid;
+ const char *sp = key;
+ const char *se = sp + key_size;
+ for (; sp < se; sp += len) {
+ if ((tid = grn_dat_lcp_search(ctx, dat, sp, se - sp))) {
+ grn_table_add(ctx, res, &tid, sizeof(grn_id), NULL);
+ /* todo : nsubrec++ if GRN_OBJ_TABLE_SUBSET assigned */
+ }
+ if (!(len = grn_charlen(ctx, sp, se))) { break; }
+ }
+ }
+ // todo : support op;
+ break;
+ default :
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc, "invalid mode %d", mode);
+ }
+ });
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_hash *hash = (grn_hash *)table;
+ grn_id id = GRN_ID_NIL;
+ WITH_NORMALIZE(hash, key, key_size, {
+ id = grn_hash_get(ctx, hash, key, key_size, NULL);
+ });
+ if (id) { grn_table_add(ctx, res, &id, sizeof(grn_id), NULL); }
+ }
+ break;
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_fuzzy_search(grn_ctx *ctx, grn_obj *table, const void *key, uint32_t key_size,
+ grn_fuzzy_search_optarg *args, grn_obj *res, grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ {
+ grn_pat *pat = (grn_pat *)table;
+ if (!grn_table_size(ctx, res) && op == GRN_OP_OR) {
+ WITH_NORMALIZE(pat, key, key_size, {
+ rc = grn_pat_fuzzy_search(ctx, pat, key, key_size,
+ args, (grn_hash *)res);
+ });
+ } else {
+ grn_obj *hash;
+ hash = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ table, NULL);
+ WITH_NORMALIZE(pat, key, key_size, {
+ rc = grn_pat_fuzzy_search(ctx, pat, key, key_size,
+ args, (grn_hash *)hash);
+ });
+ if (rc == GRN_SUCCESS) {
+ rc = grn_table_setoperation(ctx, res, hash, res, op);
+ }
+ grn_obj_unlink(ctx, hash);
+ }
+ }
+ break;
+ default :
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ break;
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_id
+grn_table_next(grn_ctx *ctx, grn_obj *table, grn_id id)
+{
+ grn_id r = GRN_ID_NIL;
+ GRN_API_ENTER;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ r = grn_pat_next(ctx, (grn_pat *)table, id);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ r = grn_dat_next(ctx, (grn_dat *)table, id);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ r = grn_hash_next(ctx, (grn_hash *)table, id);
+ break;
+ case GRN_TABLE_NO_KEY :
+ r = grn_array_next(ctx, (grn_array *)table, id);
+ break;
+ }
+ }
+ GRN_API_RETURN(r);
+}
+
+static grn_rc
+grn_accessor_resolve_one_index_column(grn_ctx *ctx, grn_accessor *accessor,
+ grn_obj *current_res, grn_obj **next_res)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *column = NULL;
+ grn_id next_res_domain_id = GRN_ID_NIL;
+
+ {
+ grn_obj *index;
+ grn_obj source_ids;
+ unsigned int i, n_ids;
+
+ index = accessor->obj;
+ next_res_domain_id = index->header.domain;
+
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+ grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
+ n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+ for (i = 0; i < n_ids; i++) {
+ grn_id source_id;
+ grn_obj *source;
+
+ source_id = GRN_UINT32_VALUE_AT(&source_ids, i);
+ source = grn_ctx_at(ctx, source_id);
+ if (DB_OBJ(source)->range == next_res_domain_id) {
+ column = source;
+ break;
+ }
+ grn_obj_unlink(ctx, source);
+ }
+
+ if (!column) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+
+ {
+ grn_rc rc;
+ grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
+ *next_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ next_res_domain, NULL);
+ rc = ctx->rc;
+ grn_obj_unlink(ctx, next_res_domain);
+ if (!*next_res) {
+ return rc;
+ }
+ }
+
+ {
+ grn_obj_flags column_value_flags = 0;
+ grn_obj column_value;
+ grn_posting add_posting;
+ grn_id *tid;
+ grn_rset_recinfo *recinfo;
+
+ if (column->header.type == GRN_COLUMN_VAR_SIZE) {
+ column_value_flags |= GRN_OBJ_VECTOR;
+ }
+ GRN_VALUE_FIX_SIZE_INIT(&column_value,
+ column_value_flags,
+ next_res_domain_id);
+
+ add_posting.sid = 0;
+ add_posting.pos = 0;
+ add_posting.weight = 0;
+
+ GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
+ int i;
+ int n_elements;
+
+ add_posting.weight = recinfo->score - 1;
+
+ GRN_BULK_REWIND(&column_value);
+ grn_obj_get_value(ctx, column, *tid, &column_value);
+
+ n_elements = GRN_BULK_VSIZE(&column_value) / sizeof(grn_id);
+ for (i = 0; i < n_elements; i++) {
+ add_posting.rid = GRN_RECORD_VALUE_AT(&column_value, i);
+ rc = grn_ii_posting_add(ctx,
+ &add_posting,
+ (grn_hash *)*next_res,
+ GRN_OP_OR);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ });
+
+ GRN_OBJ_FIN(ctx, &column_value);
+ }
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, *next_res);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_accessor_resolve_one_table(grn_ctx *ctx, grn_accessor *accessor,
+ grn_obj *current_res, grn_obj **next_res)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *table;
+
+ table = accessor->obj;
+ *next_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ table, NULL);
+ if (!*next_res) {
+ return ctx->rc;
+ }
+
+ grn_report_table(ctx,
+ "[accessor][resolve]",
+ "",
+ table);
+
+ {
+ grn_posting posting;
+
+ memset(&posting, 0, sizeof(posting));
+ GRN_HASH_EACH_BEGIN(ctx, (grn_hash *)current_res, cursor, id) {
+ void *key;
+ void *value;
+ grn_id *record_id;
+ grn_rset_recinfo *recinfo;
+ grn_id next_record_id;
+
+ grn_hash_cursor_get_key_value(ctx, cursor, &key, NULL, &value);
+ record_id = key;
+ recinfo = value;
+ next_record_id = grn_table_get(ctx,
+ table,
+ record_id,
+ sizeof(grn_id));
+ if (next_record_id == GRN_ID_NIL) {
+ continue;
+ }
+
+ posting.rid = next_record_id;
+ posting.weight = recinfo->score;
+ rc = grn_ii_posting_add(ctx,
+ &posting,
+ (grn_hash *)*next_res,
+ GRN_OP_OR);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, *next_res);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_accessor_resolve_one_data_column(grn_ctx *ctx, grn_accessor *accessor,
+ grn_obj *current_res, grn_obj **next_res)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_index_datum index_datum;
+ unsigned int n_index_data;
+ grn_id next_res_domain_id = GRN_ID_NIL;
+
+ n_index_data = grn_column_get_all_index_data(ctx,
+ accessor->obj,
+ &index_datum,
+ 1);
+ if (n_index_data == 0) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ {
+ grn_obj *lexicon;
+ lexicon = grn_ctx_at(ctx, index_datum.index->header.domain);
+ if (grn_obj_id(ctx, lexicon) != current_res->header.domain) {
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+ grn_obj *expected;
+ char expected_name[GRN_TABLE_MAX_KEY_SIZE];
+ int expected_name_size;
+
+ index_name_size = grn_obj_name(ctx,
+ index_datum.index,
+ index_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ expected = grn_ctx_at(ctx, current_res->header.domain);
+ expected_name_size = grn_obj_name(ctx,
+ expected,
+ expected_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[accessor][resolve][data-column] lexicon mismatch index: "
+ "<%.*s> "
+ "expected:<%.*s>",
+ index_name_size,
+ index_name,
+ expected_name_size,
+ expected_name);
+ return ctx->rc;
+ }
+ }
+
+ next_res_domain_id = DB_OBJ(index_datum.index)->range;
+
+ grn_report_index(ctx,
+ "[accessor][resolve][data-column]",
+ "",
+ index_datum.index);
+ {
+ grn_rc rc;
+ grn_obj *next_res_domain = grn_ctx_at(ctx, next_res_domain_id);
+ *next_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ next_res_domain, NULL);
+ rc = ctx->rc;
+ grn_obj_unlink(ctx, next_res_domain);
+ if (!*next_res) {
+ return rc;
+ }
+ }
+
+ {
+ grn_id *tid;
+ grn_rset_recinfo *recinfo;
+
+ GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &tid, NULL, &recinfo, {
+ grn_ii *ii = (grn_ii *)(index_datum.index);
+ grn_ii_cursor *ii_cursor;
+ grn_posting *posting;
+
+ ii_cursor = grn_ii_cursor_open(ctx, ii, *tid,
+ GRN_ID_NIL, GRN_ID_MAX,
+ ii->n_elements,
+ 0);
+ if (!ii_cursor) {
+ continue;
+ }
+
+ while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
+ grn_posting add_posting;
+
+ if (index_datum.section > 0 && posting->sid != index_datum.section) {
+ continue;
+ }
+
+ add_posting = *posting;
+ add_posting.weight += recinfo->score - 1;
+ rc = grn_ii_posting_add(ctx,
+ &add_posting,
+ (grn_hash *)*next_res,
+ GRN_OP_OR);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_ii_cursor_close(ctx, ii_cursor);
+
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ });
+ }
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, *next_res);
+ }
+
+ return rc;
+}
+
+grn_rc
+grn_accessor_resolve(grn_ctx *ctx, grn_obj *accessor, int deep,
+ grn_obj *base_res, grn_obj *res,
+ grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_accessor *a;
+ grn_obj accessor_stack;
+ int i, n_accessors;
+ grn_obj *current_res = base_res;
+
+ GRN_PTR_INIT(&accessor_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ n_accessors = 0;
+ for (a = (grn_accessor *)accessor; a; a = a->next) {
+ if (deep == n_accessors) {
+ break;
+ }
+ GRN_PTR_PUT(ctx, &accessor_stack, a);
+ n_accessors++;
+ }
+
+ for (i = n_accessors; i > 0; i--) {
+ grn_obj *next_res = NULL;
+
+ a = (grn_accessor *)GRN_PTR_VALUE_AT(&accessor_stack, i - 1);
+ if (a->obj->header.type == GRN_COLUMN_INDEX) {
+ rc = grn_accessor_resolve_one_index_column(ctx, a,
+ current_res, &next_res);
+ } else if (grn_obj_is_table(ctx, a->obj)) {
+ rc = grn_accessor_resolve_one_table(ctx, a,
+ current_res, &next_res);
+ } else {
+ rc = grn_accessor_resolve_one_data_column(ctx, a,
+ current_res, &next_res);
+ }
+
+ if (current_res != base_res) {
+ grn_obj_unlink(ctx, current_res);
+ }
+
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+
+ current_res = next_res;
+ }
+
+ if (rc == GRN_SUCCESS && current_res != base_res) {
+ grn_id *record_id;
+ grn_rset_recinfo *recinfo;
+ GRN_HASH_EACH(ctx, (grn_hash *)current_res, id, &record_id, NULL, &recinfo, {
+ grn_posting posting;
+ posting.rid = *record_id;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = recinfo->score - 1;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ });
+ grn_obj_unlink(ctx, current_res);
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ } else {
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &accessor_stack);
+ return rc;
+}
+
+static inline void
+grn_obj_search_index_report(grn_ctx *ctx, const char *tag, grn_obj *index)
+{
+ grn_report_index(ctx, "[object][search]", tag, index);
+}
+
+static inline grn_rc
+grn_obj_search_accessor(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
+ grn_obj *res, grn_operator op, grn_search_optarg *optarg)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_accessor *a;
+ grn_obj *last_obj = NULL;
+ int n_accessors;
+
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ if (!a->next) {
+ last_obj = a->obj;
+ }
+ }
+ n_accessors = 0;
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ n_accessors++;
+ if (GRN_OBJ_INDEX_COLUMNP(a->obj)) {
+ break;
+ }
+ }
+
+ {
+ grn_obj *index;
+ grn_operator index_op = GRN_OP_MATCH;
+ if (optarg && optarg->mode != GRN_OP_EXACT) {
+ index_op = optarg->mode;
+ }
+ if (grn_column_index(ctx, last_obj, index_op, &index, 1, NULL) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ goto exit;
+ }
+
+ if (n_accessors == 1) {
+ rc = grn_obj_search(ctx, index, query, res, op, optarg);
+ } else {
+ grn_obj *base_res;
+ grn_obj *range = grn_ctx_at(ctx, DB_OBJ(index)->range);
+ base_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ range,
+ NULL);
+ rc = ctx->rc;
+ grn_obj_unlink(ctx, range);
+ if (!base_res) {
+ goto exit;
+ }
+ if (optarg) {
+ optarg->match_info.min = GRN_ID_NIL;
+ }
+ rc = grn_obj_search(ctx, index, query, base_res, GRN_OP_OR, optarg);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, base_res);
+ goto exit;
+ }
+ rc = grn_accessor_resolve(ctx, obj, n_accessors - 1, base_res, res, op);
+ grn_obj_unlink(ctx, base_res);
+ }
+ }
+
+exit :
+ return rc;
+}
+
+static grn_rc
+grn_obj_search_column_index_by_id(grn_ctx *ctx, grn_obj *obj,
+ grn_id tid,
+ grn_obj *res, grn_operator op,
+ grn_search_optarg *optarg)
+{
+ grn_ii_cursor *c;
+
+ grn_obj_search_index_report(ctx, "[id]", obj);
+
+ c = grn_ii_cursor_open(ctx, (grn_ii *)obj, tid,
+ GRN_ID_NIL, GRN_ID_MAX, 1, 0);
+ if (c) {
+ grn_posting *pos;
+ grn_hash *s = (grn_hash *)res;
+ while ((pos = grn_ii_cursor_next(ctx, c))) {
+ /* todo: support orgarg(op)
+ res_add(ctx, s, (grn_rset_posinfo *) pos,
+ get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg), op);
+ */
+ grn_hash_add(ctx, s, pos, s->key_size, NULL, NULL);
+ }
+ grn_ii_cursor_close(ctx, c);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_obj_search_column_index_by_key(grn_ctx *ctx, grn_obj *obj,
+ grn_obj *query,
+ grn_obj *res, grn_operator op,
+ grn_search_optarg *optarg)
+{
+ grn_rc rc;
+ unsigned int key_type = GRN_ID_NIL;
+ const char *key;
+ unsigned int key_len;
+ grn_obj *table;
+ grn_obj casted_query;
+ grn_bool need_cast = GRN_FALSE;
+
+ table = grn_ctx_at(ctx, obj->header.domain);
+ if (table) {
+ key_type = table->header.domain;
+ need_cast = (query->header.domain != key_type);
+ grn_obj_unlink(ctx, table);
+ }
+ if (need_cast) {
+ GRN_OBJ_INIT(&casted_query, GRN_BULK, 0, key_type);
+ rc = grn_obj_cast(ctx, query, &casted_query, GRN_FALSE);
+ if (rc != GRN_SUCCESS)
+ goto fail;
+ query = &casted_query;
+ }
+
+ key = GRN_BULK_HEAD(query);
+ key_len = GRN_BULK_VSIZE(query);
+
+ if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ const char *tag;
+ if (optarg) {
+ switch (optarg->mode) {
+ case GRN_OP_MATCH :
+ tag = "[key][match]";
+ break;
+ case GRN_OP_EXACT :
+ tag = "[key][exact]";
+ break;
+ case GRN_OP_NEAR :
+ tag = "[key][near]";
+ break;
+ case GRN_OP_NEAR2 :
+ tag = "[key][near2]";
+ break;
+ case GRN_OP_SIMILAR :
+ tag = "[key][similar]";
+ break;
+ case GRN_OP_REGEXP :
+ tag = "[key][regexp]";
+ break;
+ case GRN_OP_FUZZY :
+ tag = "[key][fuzzy]";
+ break;
+ default :
+ tag = "[key][unknown]";
+ break;
+ }
+ } else {
+ tag = "[key][exact]";
+ }
+ grn_obj_search_index_report(ctx, tag, obj);
+ }
+ rc = grn_ii_sel(ctx, (grn_ii *)obj, key, key_len,
+ (grn_hash *)res, op, optarg);
+ fail:
+ if (need_cast) {
+ GRN_OBJ_FIN(ctx, &casted_query);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_search_column_index(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
+ grn_obj *res, grn_operator op,
+ grn_search_optarg *optarg)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+
+ if (DB_OBJ(obj)->range == res->header.domain) {
+ switch (query->header.type) {
+ case GRN_BULK :
+ if (query->header.domain == obj->header.domain &&
+ GRN_BULK_VSIZE(query) == sizeof(grn_id)) {
+ grn_id tid = GRN_RECORD_VALUE(query);
+ rc = grn_obj_search_column_index_by_id(ctx, obj, tid, res, op, optarg);
+ } else {
+ rc = grn_obj_search_column_index_by_key(ctx, obj, query,
+ res, op, optarg);
+ }
+ break;
+ case GRN_QUERY :
+ rc = GRN_FUNCTION_NOT_IMPLEMENTED;
+ break;
+ }
+ }
+
+ return rc;
+}
+
+grn_rc
+grn_obj_search(grn_ctx *ctx, grn_obj *obj, grn_obj *query,
+ grn_obj *res, grn_operator op, grn_search_optarg *optarg)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (GRN_ACCESSORP(obj)) {
+ rc = grn_obj_search_accessor(ctx, obj, query, res, op, optarg);
+ } else if (GRN_DB_OBJP(obj)) {
+ switch (obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ {
+ const void *key = GRN_BULK_HEAD(query);
+ uint32_t key_size = GRN_BULK_VSIZE(query);
+ grn_operator mode = optarg ? optarg->mode : GRN_OP_EXACT;
+ if (key && key_size) {
+ if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ const char *tag;
+ if (optarg) {
+ switch (optarg->mode) {
+ case GRN_OP_EXACT :
+ tag = "[table][exact]";
+ break;
+ case GRN_OP_LCP :
+ tag = "[table][lcp]";
+ break;
+ case GRN_OP_SUFFIX :
+ tag = "[table][suffix]";
+ break;
+ case GRN_OP_PREFIX :
+ tag = "[table][prefix]";
+ break;
+ case GRN_OP_TERM_EXTRACT :
+ tag = "[table][term-extract]";
+ break;
+ case GRN_OP_FUZZY :
+ tag = "[table][fuzzy]";
+ break;
+ default :
+ tag = "[table][unknown]";
+ break;
+ }
+ } else {
+ tag = "[table][exact]";
+ }
+ grn_obj_search_index_report(ctx, tag, obj);
+ }
+ if (optarg && optarg->mode == GRN_OP_FUZZY) {
+ rc = grn_table_fuzzy_search(ctx, obj, key, key_size,
+ &(optarg->fuzzy), res, op);
+ } else {
+ rc = grn_table_search(ctx, obj, key, key_size, mode, res, op);
+ }
+ }
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ rc = grn_obj_search_column_index(ctx, obj, query, res, op, optarg);
+ break;
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+#define GRN_TABLE_GROUP_BY_KEY 0
+#define GRN_TABLE_GROUP_BY_VALUE 1
+#define GRN_TABLE_GROUP_BY_COLUMN_VALUE 2
+
+#define GRN_TABLE_GROUP_FILTER_PREFIX 0
+#define GRN_TABLE_GROUP_FILTER_SUFFIX (1L<<2)
+
+inline static void
+grn_table_group_add_subrec(grn_ctx *ctx,
+ grn_obj *table,
+ grn_rset_recinfo *ri, double score,
+ grn_rset_posinfo *pi, int dir,
+ grn_obj *calc_target,
+ grn_obj *value_buffer)
+{
+ grn_table_group_flags flags;
+
+ if (!(DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC)) {
+ return;
+ }
+
+ grn_table_add_subrec_inline(table, ri, score, pi, dir);
+
+ flags = DB_OBJ(table)->flags.group;
+
+ if (!(flags & (GRN_TABLE_GROUP_CALC_MAX |
+ GRN_TABLE_GROUP_CALC_MIN |
+ GRN_TABLE_GROUP_CALC_SUM |
+ GRN_TABLE_GROUP_CALC_AVG))) {
+ return;
+ }
+
+ GRN_BULK_REWIND(value_buffer);
+ grn_obj_get_value(ctx, calc_target, pi->rid, value_buffer);
+ grn_rset_recinfo_update_calc_values(ctx, ri, table, value_buffer);
+}
+
+static grn_bool
+accelerated_table_group(grn_ctx *ctx, grn_obj *table, grn_obj *key,
+ grn_table_group_result *result)
+{
+ grn_obj *res = result->table;
+ grn_obj *calc_target = result->calc_target;
+ if (key->header.type == GRN_ACCESSOR) {
+ grn_accessor *a = (grn_accessor *)key;
+ if (a->action == GRN_ACCESSOR_GET_KEY &&
+ a->next && a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
+ a->next->obj && !a->next->next) {
+ grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
+ int idp = GRN_OBJ_TABLEP(range);
+ grn_table_cursor *tc;
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_bool processed = GRN_TRUE;
+ grn_obj value_buffer;
+ GRN_VOID_INIT(&value_buffer);
+ switch (a->next->obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ {
+ grn_id id;
+ grn_ra *ra = (grn_ra *)a->next->obj;
+ unsigned int element_size = (ra)->header->element_size;
+ grn_ra_cache cache;
+ GRN_RA_CACHE_INIT(ra, &cache);
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ void *v, *value;
+ grn_id *id_;
+ uint32_t key_size;
+ grn_rset_recinfo *ri = NULL;
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+ id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
+ v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
+ if (idp && *((grn_id *)v) &&
+ grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
+ continue;
+ }
+ if ((!idp || *((grn_id *)v)) &&
+ grn_table_add_v_inline(ctx, res, v, element_size, &value, NULL)) {
+ grn_table_group_add_subrec(ctx, res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ calc_target,
+ &value_buffer);
+ }
+ }
+ GRN_RA_CACHE_FIN(ra, &cache);
+ }
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ if (idp) { /* todo : support other type */
+ grn_id id;
+ grn_ja *ja = (grn_ja *)a->next->obj;
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ grn_io_win jw;
+ unsigned int len = 0;
+ void *value;
+ grn_id *v, *id_;
+ uint32_t key_size;
+ grn_rset_recinfo *ri = NULL;
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+ id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
+ if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
+ while (len) {
+ if ((*v != GRN_ID_NIL) &&
+ grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
+ grn_table_group_add_subrec(ctx, res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ calc_target,
+ &value_buffer);
+ }
+ v++;
+ len -= sizeof(grn_id);
+ }
+ grn_ja_unref(ctx, &jw);
+ }
+ }
+ } else {
+ processed = GRN_FALSE;
+ }
+ break;
+ default :
+ processed = GRN_FALSE;
+ break;
+ }
+ GRN_OBJ_FIN(ctx, &value_buffer);
+ grn_table_cursor_close(ctx, tc);
+ return processed;
+ }
+ }
+ }
+ return GRN_FALSE;
+}
+
+static void
+grn_table_group_single_key_records(grn_ctx *ctx, grn_obj *table,
+ grn_obj *key, grn_table_group_result *result)
+{
+ grn_obj bulk;
+ grn_obj value_buffer;
+ grn_table_cursor *tc;
+ grn_obj *res = result->table;
+ grn_obj *calc_target = result->calc_target;
+
+ GRN_TEXT_INIT(&bulk, 0);
+ GRN_VOID_INIT(&value_buffer);
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
+ int idp = GRN_OBJ_TABLEP(range);
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ void *value;
+ grn_rset_recinfo *ri = NULL;
+ GRN_BULK_REWIND(&bulk);
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+ grn_obj_get_value(ctx, key, id, &bulk);
+ switch (bulk.header.type) {
+ case GRN_UVECTOR :
+ {
+ grn_bool is_reference;
+ unsigned int element_size;
+ uint8_t *elements;
+ int i, n_elements;
+
+ is_reference = !grn_type_id_is_builtin(ctx, bulk.header.type);
+
+ element_size = grn_uvector_element_size(ctx, &bulk);
+ elements = GRN_BULK_HEAD(&bulk);
+ n_elements = GRN_BULK_VSIZE(&bulk) / element_size;
+ for (i = 0; i < n_elements; i++) {
+ uint8_t *element = elements + (element_size * i);
+
+ if (is_reference) {
+ grn_id id = *((grn_id *)element);
+ if (id == GRN_ID_NIL) {
+ continue;
+ }
+ }
+
+ if (!grn_table_add_v_inline(ctx, res, element, element_size,
+ &value, NULL)) {
+ continue;
+ }
+
+ grn_table_group_add_subrec(ctx, res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ calc_target,
+ &value_buffer);
+ }
+ }
+ break;
+ case GRN_VECTOR :
+ {
+ unsigned int i, n_elements;
+ n_elements = grn_vector_size(ctx, &bulk);
+ for (i = 0; i < n_elements; i++) {
+ const char *content;
+ unsigned int content_length;
+ content_length = grn_vector_get_element(ctx, &bulk, i,
+ &content, NULL, NULL);
+ if (grn_table_add_v_inline(ctx, res,
+ content, content_length,
+ &value, NULL)) {
+ grn_table_group_add_subrec(ctx, res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ calc_target,
+ &value_buffer);
+ }
+ }
+ }
+ break;
+ case GRN_BULK :
+ {
+ if ((!idp || *((grn_id *)GRN_BULK_HEAD(&bulk))) &&
+ grn_table_add_v_inline(ctx, res,
+ GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
+ &value, NULL)) {
+ grn_table_group_add_subrec(ctx, res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ calc_target,
+ &value_buffer);
+ }
+ }
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "invalid column");
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_OBJ_FIN(ctx, &value_buffer);
+ GRN_OBJ_FIN(ctx, &bulk);
+}
+
+#define GRN_TABLE_GROUP_ALL_NAME "_all"
+#define GRN_TABLE_GROUP_ALL_NAME_LEN (sizeof(GRN_TABLE_GROUP_ALL_NAME) - 1)
+
+static void
+grn_table_group_all_records(grn_ctx *ctx, grn_obj *table,
+ grn_table_group_result *result)
+{
+ grn_obj value_buffer;
+ grn_table_cursor *tc;
+ grn_obj *res = result->table;
+ grn_obj *calc_target = result->calc_target;
+
+ GRN_VOID_INIT(&value_buffer);
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ void *value;
+ if (grn_table_add_v_inline(ctx, res,
+ GRN_TABLE_GROUP_ALL_NAME,
+ GRN_TABLE_GROUP_ALL_NAME_LEN,
+ &value, NULL)) {
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ grn_rset_recinfo *ri = NULL;
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+ grn_table_group_add_subrec(ctx, res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ calc_target,
+ &value_buffer);
+ }
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_OBJ_FIN(ctx, &value_buffer);
+}
+
+grn_rc
+grn_table_group_with_range_gap(grn_ctx *ctx, grn_obj *table,
+ grn_table_sort_key *group_key,
+ grn_obj *res, uint32_t range_gap)
+{
+ grn_obj *key = group_key->key;
+ if (key->header.type == GRN_ACCESSOR) {
+ grn_accessor *a = (grn_accessor *)key;
+ if (a->action == GRN_ACCESSOR_GET_KEY &&
+ a->next && a->next->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
+ a->next->obj && !a->next->next) {
+ grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, key));
+ int idp = GRN_OBJ_TABLEP(range);
+ grn_table_cursor *tc;
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL,
+ 0, 0, -1, 0))) {
+ switch (a->next->obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ {
+ grn_id id;
+ grn_ra *ra = (grn_ra *)a->next->obj;
+ unsigned int element_size = (ra)->header->element_size;
+ grn_ra_cache cache;
+ GRN_RA_CACHE_INIT(ra, &cache);
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ void *v, *value;
+ grn_id *id_;
+ uint32_t key_size;
+ grn_rset_recinfo *ri = NULL;
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+ id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
+ v = grn_ra_ref_cache(ctx, ra, *id_, &cache);
+ if (idp && *((grn_id *)v) &&
+ grn_table_at(ctx, range, *((grn_id *)v)) == GRN_ID_NIL) {
+ continue;
+ }
+ if ((!idp || *((grn_id *)v))) {
+ grn_id id;
+ if (element_size == sizeof(uint32_t)) {
+ uint32_t quantized = (*(uint32_t *)v);
+ quantized -= quantized % range_gap;
+ id = grn_table_add_v_inline(ctx, res, &quantized,
+ element_size, &value, NULL);
+ } else {
+ id = grn_table_add_v_inline(ctx, res, v,
+ element_size, &value, NULL);
+ }
+ if (id) {
+ grn_table_add_subrec_inline(res, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0);
+ }
+ }
+ }
+ GRN_RA_CACHE_FIN(ra, &cache);
+ }
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ if (idp) { /* todo : support other type */
+ grn_id id;
+ grn_ja *ja = (grn_ja *)a->next->obj;
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ grn_io_win jw;
+ unsigned int len = 0;
+ void *value;
+ grn_id *v, *id_;
+ uint32_t key_size;
+ grn_rset_recinfo *ri = NULL;
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+ id_ = (grn_id *)_grn_table_key(ctx, table, id, &key_size);
+ if ((v = grn_ja_ref(ctx, ja, *id_, &jw, &len))) {
+ while (len) {
+ if ((*v != GRN_ID_NIL) &&
+ grn_table_add_v_inline(ctx, res, v, sizeof(grn_id), &value, NULL)) {
+ grn_table_add_subrec_inline(res, value, ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0);
+ }
+ v++;
+ len -= sizeof(grn_id);
+ }
+ grn_ja_unref(ctx, &jw);
+ }
+ }
+ } else {
+ return 0;
+ }
+ break;
+ default :
+ return 0;
+ }
+ grn_table_cursor_close(ctx, tc);
+ GRN_TABLE_GROUPED_ON(res);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static inline void
+grn_table_group_multi_keys_add_record(grn_ctx *ctx,
+ grn_table_sort_key *keys,
+ int n_keys,
+ grn_table_group_result *results,
+ int n_results,
+ grn_id id,
+ grn_rset_recinfo *ri,
+ grn_obj *vector,
+ grn_obj *bulk)
+{
+ int r;
+ grn_table_group_result *rp;
+
+ for (r = 0, rp = results; r < n_results; r++, rp++) {
+ void *value;
+ int i;
+ int end;
+
+ if (rp->key_end > n_keys) {
+ end = n_keys;
+ } else {
+ end = rp->key_end + 1;
+ }
+ GRN_BULK_REWIND(bulk);
+ grn_text_benc(ctx, bulk, end - rp->key_begin);
+ for (i = rp->key_begin; i < end; i++) {
+ grn_section section = vector->u.v.sections[i];
+ grn_text_benc(ctx, bulk, section.length);
+ }
+ {
+ grn_obj *body = vector->u.v.body;
+ if (body) {
+ GRN_TEXT_PUT(ctx, bulk, GRN_BULK_HEAD(body), GRN_BULK_VSIZE(body));
+ }
+ }
+ for (i = rp->key_begin; i < end; i++) {
+ grn_section section = vector->u.v.sections[i];
+ grn_text_benc(ctx, bulk, section.weight);
+ grn_text_benc(ctx, bulk, section.domain);
+ }
+
+ // todo : cut off GRN_ID_NIL
+ if (grn_table_add_v_inline(ctx, rp->table,
+ GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk),
+ &value, NULL)) {
+ grn_table_group_add_subrec(ctx, rp->table, value,
+ ri ? ri->score : 0,
+ (grn_rset_posinfo *)&id, 0,
+ rp->calc_target,
+ bulk);
+ }
+ }
+}
+
+static void
+grn_table_group_multi_keys_scalar_records(grn_ctx *ctx,
+ grn_obj *table,
+ grn_table_sort_key *keys,
+ int n_keys,
+ grn_table_group_result *results,
+ int n_results)
+{
+ grn_id id;
+ grn_table_cursor *tc;
+ grn_obj bulk;
+ grn_obj vector;
+
+ tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!tc) {
+ return;
+ }
+
+ GRN_TEXT_INIT(&bulk, 0);
+ GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_VOID);
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ int k;
+ grn_table_sort_key *kp;
+ grn_rset_recinfo *ri = NULL;
+
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+
+ GRN_BULK_REWIND(&vector);
+ for (k = 0, kp = keys; k < n_keys; k++, kp++) {
+ GRN_BULK_REWIND(&bulk);
+ grn_obj_get_value(ctx, kp->key, id, &bulk);
+ grn_vector_add_element(ctx, &vector,
+ GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
+ 0,
+ bulk.header.domain);
+ }
+
+ grn_table_group_multi_keys_add_record(ctx, keys, n_keys, results, n_results,
+ id, ri, &vector, &bulk);
+ }
+ GRN_OBJ_FIN(ctx, &vector);
+ GRN_OBJ_FIN(ctx, &bulk);
+ grn_table_cursor_close(ctx, tc);
+}
+
+static inline void
+grn_table_group_multi_keys_vector_record(grn_ctx *ctx,
+ grn_table_sort_key *keys,
+ grn_obj *key_buffers,
+ int nth_key,
+ int n_keys,
+ grn_table_group_result *results,
+ int n_results,
+ grn_id id,
+ grn_rset_recinfo *ri,
+ grn_obj *vector,
+ grn_obj *bulk)
+{
+ int k;
+ grn_table_sort_key *kp;
+
+ for (k = nth_key, kp = &(keys[nth_key]); k < n_keys; k++, kp++) {
+ grn_obj *key_buffer = &(key_buffers[k]);
+ switch (key_buffer->header.type) {
+ case GRN_UVECTOR :
+ {
+ unsigned int n_vector_elements;
+ grn_id domain;
+ grn_id *ids;
+ unsigned int i, n_ids;
+
+ n_vector_elements = grn_vector_size(ctx, vector);
+ domain = key_buffer->header.domain;
+ ids = (grn_id *)GRN_BULK_HEAD(key_buffer);
+ n_ids = GRN_BULK_VSIZE(key_buffer) / sizeof(grn_id);
+ for (i = 0; i < n_ids; i++) {
+ grn_id element_id = ids[i];
+ grn_vector_add_element(ctx, vector,
+ (const char *)(&element_id), sizeof(grn_id),
+ 0,
+ domain);
+ grn_table_group_multi_keys_vector_record(ctx,
+ keys, key_buffers,
+ k + 1, n_keys,
+ results, n_results,
+ id, ri, vector, bulk);
+ while (grn_vector_size(ctx, vector) != n_vector_elements) {
+ const char *content;
+ grn_vector_pop_element(ctx, vector, &content, NULL, NULL);
+ }
+ }
+ return;
+ }
+ break;
+ case GRN_VECTOR :
+ {
+ unsigned int n_vector_elements;
+ unsigned int i, n_key_elements;
+
+ n_vector_elements = grn_vector_size(ctx, vector);
+ n_key_elements = grn_vector_size(ctx, key_buffer);
+ for (i = 0; i < n_key_elements; i++) {
+ const char *content;
+ unsigned int content_length;
+ grn_id domain;
+ content_length = grn_vector_get_element(ctx, key_buffer, i,
+ &content, NULL, &domain);
+ grn_vector_add_element(ctx, vector,
+ content, content_length,
+ 0,
+ domain);
+ grn_table_group_multi_keys_vector_record(ctx,
+ keys, key_buffers,
+ k + 1, n_keys,
+ results, n_results,
+ id, ri, vector, bulk);
+ while (grn_vector_size(ctx, vector) != n_vector_elements) {
+ grn_vector_pop_element(ctx, vector, &content, NULL, NULL);
+ }
+ }
+ return;
+ }
+ break;
+ default :
+ grn_vector_add_element(ctx, vector,
+ GRN_BULK_HEAD(key_buffer),
+ GRN_BULK_VSIZE(key_buffer),
+ 0,
+ key_buffer->header.domain);
+ }
+ }
+
+ if (k == n_keys) {
+ grn_table_group_multi_keys_add_record(ctx,
+ keys, n_keys,
+ results, n_results,
+ id, ri, vector, bulk);
+ }
+}
+
+static void
+grn_table_group_multi_keys_vector_records(grn_ctx *ctx,
+ grn_obj *table,
+ grn_table_sort_key *keys,
+ int n_keys,
+ grn_table_group_result *results,
+ int n_results)
+{
+ grn_id id;
+ grn_table_cursor *tc;
+ grn_obj bulk;
+ grn_obj vector;
+ grn_obj *key_buffers;
+ int k;
+
+ tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!tc) {
+ return;
+ }
+
+ key_buffers = GRN_MALLOCN(grn_obj, n_keys);
+ if (!key_buffers) {
+ grn_table_cursor_close(ctx, tc);
+ return;
+ }
+
+ GRN_TEXT_INIT(&bulk, 0);
+ GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_VOID);
+ for (k = 0; k < n_keys; k++) {
+ GRN_VOID_INIT(&(key_buffers[k]));
+ }
+ while ((id = grn_table_cursor_next_inline(ctx, tc))) {
+ grn_table_sort_key *kp;
+ grn_rset_recinfo *ri = NULL;
+
+ if (DB_OBJ(table)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_cursor_get_value_inline(ctx, tc, (void **)&ri);
+ }
+
+ for (k = 0, kp = keys; k < n_keys; k++, kp++) {
+ grn_obj *key_buffer = &(key_buffers[k]);
+ GRN_BULK_REWIND(key_buffer);
+ grn_obj_get_value(ctx, kp->key, id, key_buffer);
+ }
+
+ GRN_BULK_REWIND(&vector);
+ grn_table_group_multi_keys_vector_record(ctx,
+ keys, key_buffers, 0, n_keys,
+ results, n_results,
+ id, ri, &vector, &bulk);
+ }
+ for (k = 0; k < n_keys; k++) {
+ GRN_OBJ_FIN(ctx, &(key_buffers[k]));
+ }
+ GRN_FREE(key_buffers);
+ GRN_OBJ_FIN(ctx, &vector);
+ GRN_OBJ_FIN(ctx, &bulk);
+ grn_table_cursor_close(ctx, tc);
+}
+
+grn_rc
+grn_table_group(grn_ctx *ctx, grn_obj *table,
+ grn_table_sort_key *keys, int n_keys,
+ grn_table_group_result *results, int n_results)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_bool group_by_all_records = GRN_FALSE;
+ if (n_keys == 0 && n_results == 1) {
+ group_by_all_records = GRN_TRUE;
+ } else if (!table || !n_keys || !n_results) {
+ ERR(GRN_INVALID_ARGUMENT, "table or n_keys or n_results is void");
+ return GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_ENTER;
+ {
+ int k, r;
+ grn_table_sort_key *kp;
+ grn_table_group_result *rp;
+ for (k = 0, kp = keys; k < n_keys; k++, kp++) {
+ if ((kp->flags & GRN_TABLE_GROUP_BY_COLUMN_VALUE) && !kp->key) {
+ ERR(GRN_INVALID_ARGUMENT, "column missing in (%d)", k);
+ goto exit;
+ }
+ }
+ for (r = 0, rp = results; r < n_results; r++, rp++) {
+ if (!rp->table) {
+ grn_table_flags flags;
+ grn_obj *key_type = NULL;
+ uint32_t additional_value_size;
+
+ flags = GRN_TABLE_HASH_KEY|
+ GRN_OBJ_WITH_SUBREC|
+ GRN_OBJ_UNIT_USERDEF_DOCUMENT;
+ if (group_by_all_records) {
+ key_type = grn_ctx_at(ctx, GRN_DB_SHORT_TEXT);
+ } else if (n_keys == 1) {
+ key_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, keys[0].key));
+ } else {
+ flags |= GRN_OBJ_KEY_VAR_SIZE;
+ }
+ additional_value_size = grn_rset_recinfo_calc_values_size(ctx,
+ rp->flags);
+ rp->table = grn_table_create_with_max_n_subrecs(ctx, NULL, 0, NULL,
+ flags,
+ key_type, table,
+ rp->max_n_subrecs,
+ additional_value_size);
+ if (key_type) {
+ grn_obj_unlink(ctx, key_type);
+ }
+ if (!rp->table) {
+ goto exit;
+ }
+ DB_OBJ(rp->table)->flags.group = rp->flags;
+ }
+ }
+ if (group_by_all_records) {
+ grn_table_group_all_records(ctx, table, results);
+ } else if (n_keys == 1 && n_results == 1) {
+ if (!accelerated_table_group(ctx, table, keys->key, results)) {
+ grn_table_group_single_key_records(ctx, table, keys->key, results);
+ }
+ } else {
+ grn_bool have_vector = GRN_FALSE;
+ for (k = 0, kp = keys; k < n_keys; k++, kp++) {
+ grn_id range_id;
+ grn_obj_flags range_flags = 0;
+ grn_obj_get_range_info(ctx, kp->key, &range_id, &range_flags);
+ if (range_flags == GRN_OBJ_VECTOR) {
+ have_vector = GRN_TRUE;
+ break;
+ }
+ }
+ if (have_vector) {
+ grn_table_group_multi_keys_vector_records(ctx, table,
+ keys, n_keys,
+ results, n_results);
+ } else {
+ grn_table_group_multi_keys_scalar_records(ctx, table,
+ keys, n_keys,
+ results, n_results);
+ }
+ }
+ for (r = 0, rp = results; r < n_results; r++, rp++) {
+ GRN_TABLE_GROUPED_ON(rp->table);
+ }
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_setoperation(grn_ctx *ctx, grn_obj *table1, grn_obj *table2, grn_obj *res,
+ grn_operator op)
+{
+ void *key = NULL, *value1 = NULL, *value2 = NULL;
+ uint32_t value_size = 0;
+ uint32_t key_size = 0;
+ grn_bool have_subrec;
+
+ GRN_API_ENTER;
+ if (!table1) {
+ ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] table1 is NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+ if (!table2) {
+ ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] table2 is NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+ if (!res) {
+ ERR(GRN_INVALID_ARGUMENT, "[table][setoperation] result table is NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (table1 != res) {
+ if (table2 == res) {
+ grn_obj *t = table1;
+ table1 = table2;
+ table2 = t;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][setoperation] table1 or table2 must be result table");
+ GRN_API_RETURN(ctx->rc);
+ }
+ }
+ have_subrec = ((DB_OBJ(table1)->header.flags & GRN_OBJ_WITH_SUBREC) &&
+ (DB_OBJ(table2)->header.flags & GRN_OBJ_WITH_SUBREC));
+ switch (table1->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ value_size = ((grn_hash *)table1)->value_size;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ value_size = ((grn_pat *)table1)->value_size;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ value_size = 0;
+ break;
+ case GRN_TABLE_NO_KEY :
+ value_size = ((grn_array *)table1)->value_size;
+ break;
+ }
+ switch (table2->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ if (value_size < ((grn_hash *)table2)->value_size) {
+ value_size = ((grn_hash *)table2)->value_size;
+ }
+ break;
+ case GRN_TABLE_PAT_KEY :
+ if (value_size < ((grn_pat *)table2)->value_size) {
+ value_size = ((grn_pat *)table2)->value_size;
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ value_size = 0;
+ break;
+ case GRN_TABLE_NO_KEY :
+ if (value_size < ((grn_array *)table2)->value_size) {
+ value_size = ((grn_array *)table2)->value_size;
+ }
+ break;
+ }
+ switch (op) {
+ case GRN_OP_OR :
+ if (have_subrec) {
+ int added;
+ GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
+ if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, &added)) {
+ if (added) {
+ grn_memcpy(value1, value2, value_size);
+ } else {
+ grn_rset_recinfo *ri1 = value1;
+ grn_rset_recinfo *ri2 = value2;
+ grn_table_add_subrec_inline(table1, ri1, ri2->score, NULL, 0);
+ }
+ }
+ });
+ } else {
+ GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
+ if (grn_table_add_v_inline(ctx, table1, key, key_size, &value1, NULL)) {
+ grn_memcpy(value1, value2, value_size);
+ }
+ });
+ }
+ break;
+ case GRN_OP_AND :
+ if (have_subrec) {
+ GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
+ if (grn_table_get_v(ctx, table2, key, key_size, &value2)) {
+ grn_rset_recinfo *ri1 = value1;
+ grn_rset_recinfo *ri2 = value2;
+ ri1->score += ri2->score;
+ } else {
+ _grn_table_delete_by_id(ctx, table1, id, NULL);
+ }
+ });
+ } else {
+ GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, &value1, {
+ if (!grn_table_get_v(ctx, table2, key, key_size, &value2)) {
+ _grn_table_delete_by_id(ctx, table1, id, NULL);
+ }
+ });
+ }
+ break;
+ case GRN_OP_AND_NOT :
+ GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
+ grn_table_delete(ctx, table1, key, key_size);
+ });
+ break;
+ case GRN_OP_ADJUST :
+ if (have_subrec) {
+ GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
+ if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
+ grn_rset_recinfo *ri1 = value1;
+ grn_rset_recinfo *ri2 = value2;
+ ri1->score += ri2->score;
+ }
+ });
+ } else {
+ GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, &value2, {
+ if (grn_table_get_v(ctx, table1, key, key_size, &value1)) {
+ grn_memcpy(value1, value2, value_size);
+ }
+ });
+ }
+ break;
+ default :
+ break;
+ }
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_table_difference(grn_ctx *ctx, grn_obj *table1, grn_obj *table2,
+ grn_obj *res1, grn_obj *res2)
+{
+ void *key = NULL;
+ uint32_t key_size = 0;
+ if (table1 != res1 || table2 != res2) { return GRN_INVALID_ARGUMENT; }
+ if (grn_table_size(ctx, table1) > grn_table_size(ctx, table2)) {
+ GRN_TABLE_EACH(ctx, table2, 0, 0, id, &key, &key_size, NULL, {
+ grn_id id1;
+ if ((id1 = grn_table_get(ctx, table1, key, key_size))) {
+ _grn_table_delete_by_id(ctx, table1, id1, NULL);
+ _grn_table_delete_by_id(ctx, table2, id, NULL);
+ }
+ });
+ } else {
+ GRN_TABLE_EACH(ctx, table1, 0, 0, id, &key, &key_size, NULL, {
+ grn_id id2;
+ if ((id2 = grn_table_get(ctx, table2, key, key_size))) {
+ _grn_table_delete_by_id(ctx, table1, id, NULL);
+ _grn_table_delete_by_id(ctx, table2, id2, NULL);
+ }
+ });
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_obj *grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj,
+ const char *name, unsigned int name_size);
+
+static grn_obj *
+grn_obj_column_(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
+{
+ grn_id table_id = DB_OBJ(table)->id;
+ grn_obj *column = NULL;
+
+ if (table_id & GRN_OBJ_TMP_OBJECT) {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ void *value = NULL;
+ grn_snprintf(column_name, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
+ "%u%c%.*s", table_id, GRN_DB_DELIMITER, name_size, name);
+ grn_pat_get(ctx, ctx->impl->temporary_columns,
+ column_name, strlen(column_name),
+ &value);
+ if (value) {
+ column = *((grn_obj **)value);
+ }
+ } else {
+ char buf[GRN_TABLE_MAX_KEY_SIZE];
+ int len = grn_obj_name(ctx, table, buf, GRN_TABLE_MAX_KEY_SIZE);
+ if (len) {
+ buf[len++] = GRN_DB_DELIMITER;
+ if (len + name_size <= GRN_TABLE_MAX_KEY_SIZE) {
+ grn_memcpy(buf + len, name, name_size);
+ column = grn_ctx_get(ctx, buf, len + name_size);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "name is too long");
+ }
+ }
+ }
+
+ return column;
+}
+
+grn_obj *
+grn_obj_column(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
+{
+ grn_obj *column = NULL;
+ GRN_API_ENTER;
+ if (GRN_OBJ_TABLEP(table)) {
+ if (grn_db_check_name(ctx, name, name_size) ||
+ !(column = grn_obj_column_(ctx, table, name, name_size))) {
+ column = grn_obj_get_accessor(ctx, table, name, name_size);
+ }
+ } else if (GRN_ACCESSORP(table)) {
+ column = grn_obj_get_accessor(ctx, table, name, name_size);
+ }
+ GRN_API_RETURN(column);
+}
+
+int
+grn_table_columns(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size,
+ grn_obj *res)
+{
+ int n = 0;
+ grn_id id;
+
+ GRN_API_ENTER;
+
+ if (!GRN_OBJ_TABLEP(table)) {
+ GRN_API_RETURN(n);
+ }
+
+ id = DB_OBJ(table)->id;
+
+ if (id == GRN_ID_NIL) {
+ GRN_API_RETURN(n);
+ }
+
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ char search_key[GRN_TABLE_MAX_KEY_SIZE];
+ grn_pat_cursor *cursor;
+ grn_snprintf(search_key, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
+ "%u%c%.*s", id, GRN_DB_DELIMITER, name_size, name);
+ cursor = grn_pat_cursor_open(ctx, ctx->impl->temporary_columns,
+ search_key, strlen(search_key),
+ NULL, 0,
+ 0, -1, GRN_CURSOR_PREFIX);
+ if (cursor) {
+ grn_id column_id;
+ while ((column_id = grn_pat_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ column_id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN;
+ grn_hash_add(ctx, (grn_hash *)res,
+ &column_id, sizeof(grn_id),
+ NULL, NULL);
+ n++;
+ }
+ grn_pat_cursor_close(ctx, cursor);
+ }
+ } else {
+ grn_db *s = (grn_db *)DB_OBJ(table)->db;
+ if (s->keys) {
+ grn_obj bulk;
+ GRN_TEXT_INIT(&bulk, 0);
+ grn_table_get_key2(ctx, s->keys, id, &bulk);
+ GRN_TEXT_PUTC(ctx, &bulk, GRN_DB_DELIMITER);
+ grn_bulk_write(ctx, &bulk, name, name_size);
+ grn_table_search(ctx, s->keys, GRN_BULK_HEAD(&bulk), GRN_BULK_VSIZE(&bulk),
+ GRN_OP_PREFIX, res, GRN_OP_OR);
+ grn_obj_close(ctx, &bulk);
+ n = grn_table_size(ctx, res);
+ }
+ }
+
+ GRN_API_RETURN(n);
+}
+
+const char *
+_grn_table_key(grn_ctx *ctx, grn_obj *table, grn_id id, uint32_t *key_size)
+{
+ GRN_ASSERT(table);
+ if (table->header.type == GRN_DB) { table = ((grn_db *)table)->keys; }
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ return _grn_hash_key(ctx, (grn_hash *)table, id, key_size);
+ case GRN_TABLE_PAT_KEY :
+ return _grn_pat_key(ctx, (grn_pat *)table, id, key_size);
+ case GRN_TABLE_DAT_KEY :
+ return _grn_dat_key(ctx, (grn_dat *)table, id, key_size);
+ case GRN_TABLE_NO_KEY :
+ {
+ grn_array *a = (grn_array *)table;
+ const char *v;
+ if (a->obj.header.domain && a->value_size &&
+ (v = _grn_array_get_value(ctx, a, id))) {
+ *key_size = a->value_size;
+ return v;
+ } else {
+ *key_size = 0;
+ }
+ }
+ break;
+ }
+ return NULL;
+}
+
+/* column */
+
+grn_obj *
+grn_column_create(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size,
+ const char *path, grn_column_flags flags, grn_obj *type)
+{
+ grn_db *s;
+ uint32_t value_size;
+ grn_obj *db= NULL, *res = NULL;
+ grn_id id = GRN_ID_NIL;
+ grn_id range = GRN_ID_NIL;
+ grn_id domain = GRN_ID_NIL;
+ grn_bool is_persistent_table;
+ char fullname[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int fullname_size;
+ char buffer[PATH_MAX];
+
+ GRN_API_ENTER;
+ if (!table) {
+ ERR(GRN_INVALID_ARGUMENT, "[column][create] table is missing");
+ goto exit;
+ }
+ if (!type) {
+ ERR(GRN_INVALID_ARGUMENT, "[column][create] type is missing");
+ goto exit;
+ }
+ if (!name || !name_size) {
+ ERR(GRN_INVALID_ARGUMENT, "[column][create] name is missing");
+ goto exit;
+ }
+ db = DB_OBJ(table)->db;
+ s = (grn_db *)db;
+ if (!GRN_DB_P(s)) {
+ int table_name_len;
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ table_name_len = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][create] invalid db assigned: <%.*s>.<%.*s>",
+ table_name_len, table_name, name_size, name);
+ goto exit;
+ }
+
+ if (grn_db_check_name(ctx, name, name_size)) {
+ GRN_DB_CHECK_NAME_ERR("[column][create]", name, name_size);
+ goto exit;
+ }
+
+ domain = DB_OBJ(table)->id;
+ is_persistent_table = !(domain & GRN_OBJ_TMP_OBJECT);
+
+ if (!domain) {
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[column][create] [todo] table-less column isn't supported yet");
+ goto exit;
+ }
+
+ {
+ int table_name_len;
+ if (is_persistent_table) {
+ table_name_len = grn_table_get_key(ctx, s->keys, domain,
+ fullname, GRN_TABLE_MAX_KEY_SIZE);
+ } else {
+ grn_snprintf(fullname, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
+ "%u", domain);
+ table_name_len = strlen(fullname);
+ }
+ if (name_size + 1 + table_name_len > GRN_TABLE_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][create] too long column name: required name_size(%d) < %d"
+ ": <%.*s>.<%.*s>",
+ name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - table_name_len,
+ table_name_len, fullname, name_size, name);
+ goto exit;
+ }
+ fullname[table_name_len] = GRN_DB_DELIMITER;
+ grn_memcpy(fullname + table_name_len + 1, name, name_size);
+ fullname_size = table_name_len + 1 + name_size;
+ }
+
+ range = DB_OBJ(type)->id;
+ switch (type->header.type) {
+ case GRN_TYPE :
+ {
+ grn_db_obj *t = (grn_db_obj *)type;
+ flags |= t->header.flags & ~GRN_OBJ_KEY_MASK;
+ value_size = GRN_TYPE_SIZE(t);
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ value_size = sizeof(grn_id);
+ break;
+ default :
+ /*
+ if (type == grn_type_any) {
+ value_size = sizeof(grn_id) + sizeof(grn_id);
+ }
+ */
+ value_size = sizeof(grn_id);
+ }
+
+ if (is_persistent_table) {
+ id = grn_obj_register(ctx, db, fullname, fullname_size);
+ if (ERRP(ctx, GRN_ERROR)) { goto exit; }
+
+ {
+ uint32_t table_name_size = 0;
+ const char *table_name;
+ table_name = _grn_table_key(ctx, ctx->impl->db, domain, &table_name_size);
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "DDL:%u:column_create %.*s %.*s",
+ id,
+ table_name_size, table_name,
+ name_size, name);
+ }
+ } else {
+ int added;
+ id = grn_pat_add(ctx, ctx->impl->temporary_columns,
+ fullname, fullname_size, NULL,
+ &added);
+ if (!id) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[column][create][temporary] "
+ "failed to register temporary column name: <%.*s>",
+ fullname_size, fullname);
+ goto exit;
+ } else if (!added) {
+ id = GRN_ID_NIL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[column][create][temporary] already used name was assigned: <%.*s>",
+ fullname_size, fullname);
+ goto exit;
+ }
+ id |= GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN;
+ }
+
+ if (is_persistent_table && flags & GRN_OBJ_PERSISTENT) {
+ if (!path) {
+ if (GRN_DB_PERSISTENT_P(db)) {
+ grn_db_generate_pathname(ctx, db, id, buffer);
+ path = buffer;
+ } else {
+ int table_name_len;
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ table_name_len = grn_obj_name(ctx, table, table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][create] path not assigned for persistent column"
+ ": <%.*s>.<%.*s>",
+ table_name_len, table_name, name_size, name);
+ goto exit;
+ }
+ } else {
+ flags |= GRN_OBJ_CUSTOM_NAME;
+ }
+ } else {
+ if (path) {
+ int table_name_len;
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ table_name_len = grn_obj_name(ctx, table, table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][create] path assigned for temporary column"
+ ": <%.*s>.<%.*s>",
+ table_name_len, table_name, name_size, name);
+ goto exit;
+ }
+ }
+ switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_SCALAR :
+ if ((flags & GRN_OBJ_KEY_VAR_SIZE) || value_size > sizeof(int64_t)) {
+ res = (grn_obj *)grn_ja_create(ctx, path, value_size, flags);
+ } else {
+ res = (grn_obj *)grn_ra_create(ctx, path, value_size);
+ }
+ break;
+ case GRN_OBJ_COLUMN_VECTOR :
+ res = (grn_obj *)grn_ja_create(ctx, path, value_size * 30/*todo*/, flags);
+ //todo : zlib support
+ break;
+ case GRN_OBJ_COLUMN_INDEX :
+ res = (grn_obj *)grn_ii_create(ctx, path, table, flags); //todo : ii layout support
+ break;
+ }
+ if (res) {
+ DB_OBJ(res)->header.domain = domain;
+ DB_OBJ(res)->header.impl_flags = 0;
+ DB_OBJ(res)->range = range;
+ DB_OBJ(res)->header.flags = flags;
+ res->header.flags = flags;
+ if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
+ _grn_obj_remove(ctx, res, GRN_FALSE);
+ res = NULL;
+ } else {
+ grn_obj_touch(ctx, res, NULL);
+ }
+ }
+exit :
+ if (!res && id) { grn_obj_delete_by_id(ctx, db, id, GRN_TRUE); }
+ GRN_API_RETURN(res);
+}
+
+grn_obj *
+grn_column_open(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size,
+ const char *path, grn_obj *type)
+{
+ grn_id domain;
+ grn_obj *res = NULL;
+ grn_db *s;
+ char fullname[GRN_TABLE_MAX_KEY_SIZE];
+ GRN_API_ENTER;
+ if (!table || !type || !name || !name_size) {
+ ERR(GRN_INVALID_ARGUMENT, "missing type or name");
+ goto exit;
+ }
+ s = (grn_db *)DB_OBJ(table)->db;
+ if (!GRN_DB_P(s)) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
+ goto exit;
+ }
+ if (grn_db_check_name(ctx, name, name_size)) {
+ GRN_DB_CHECK_NAME_ERR("[column][open]", name, name_size);
+ goto exit;
+ }
+ if ((domain = DB_OBJ(table)->id)) {
+ int len = grn_table_get_key(ctx, s->keys, domain, fullname, GRN_TABLE_MAX_KEY_SIZE);
+ if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT, "too long column name");
+ goto exit;
+ }
+ fullname[len] = GRN_DB_DELIMITER;
+ grn_memcpy(fullname + len + 1, name, name_size);
+ name_size += len + 1;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "todo : not supported yet");
+ goto exit;
+ }
+ res = grn_ctx_get(ctx, fullname, name_size);
+ if (res) {
+ const char *path2 = grn_obj_path(ctx, res);
+ if (path && (!path2 || strcmp(path, path2))) { goto exit; }
+ } else if (path) {
+ uint32_t dbtype = grn_io_detect_type(ctx, path);
+ if (!dbtype) { goto exit; }
+ switch (dbtype) {
+ case GRN_COLUMN_VAR_SIZE :
+ res = (grn_obj *)grn_ja_open(ctx, path);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ res = (grn_obj *)grn_ra_open(ctx, path);
+ break;
+ case GRN_COLUMN_INDEX :
+ res = (grn_obj *)grn_ii_open(ctx, path, table);
+ break;
+ }
+ if (res) {
+ grn_id id = grn_obj_register(ctx, (grn_obj *)s, fullname, name_size);
+ DB_OBJ(res)->header.domain = domain;
+ DB_OBJ(res)->range = DB_OBJ(type)->id;
+ res->header.flags |= GRN_OBJ_CUSTOM_NAME;
+ grn_db_obj_init(ctx, (grn_obj *)s, id, DB_OBJ(res));
+ }
+ }
+exit :
+ GRN_API_RETURN(res);
+}
+
+/*
+typedef struct {
+ grn_id id;
+ int flags;
+} grn_column_set_value_arg;
+
+static grn_rc
+default_column_set_value(grn_ctx *ctx, grn_proc_ctx *pctx, grn_obj *in, grn_obj *out)
+{
+ grn_user_data *data = grn_proc_ctx_get_local_data(pctx);
+ if (data) {
+ grn_column_set_value_arg *arg = data->ptr;
+ unsigned int value_size = in->u.p.size; //todo
+ if (!pctx->obj) { return GRN_ID_NIL; }
+ switch (pctx->obj->header.type) {
+ case GRN_COLUMN_VAR_SIZE :
+ return grn_ja_put(ctx, (grn_ja *)pctx->obj, arg->id,
+ in->u.p.ptr, value_size, 0, NULL); // todo type->flag
+ case GRN_COLUMN_FIX_SIZE :
+ if (((grn_ra *)pctx->obj)->header->element_size < value_size) {
+ ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", value_size);
+ return GRN_INVALID_ARGUMENT;
+ } else {
+ void *v = grn_ra_ref(ctx, (grn_ra *)pctx->obj, arg->id);
+ if (!v) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ grn_memcpy(v, in->u.p.ptr, value_size);
+ grn_ra_unref(ctx, (grn_ra *)pctx->obj, arg->id);
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ // todo : how??
+ break;
+ }
+ return GRN_SUCCESS;
+ } else {
+ ERR(GRN_OBJECT_CORRUPT, "grn_proc_ctx_get_local_data failed");
+ return ctx->rc;
+ }
+}
+*/
+
+/**** grn_vector ****/
+
+//#define VECTOR(obj) ((grn_vector *)obj)
+
+/*
+#define INITIAL_VECTOR_SIZE 256
+
+int
+grn_vector_delimit(grn_ctx *ctx, grn_obj *vector)
+{
+ grn_vector *v = VECTOR(vector);
+ uint32_t *offsets;
+ if (!(v->n_entries & (INITIAL_VECTOR_SIZE - 1))) {
+ offsets = GRN_REALLOC(v->offsets, sizeof(uint32_t) *
+ (v->n_entries + INITIAL_VECTOR_SIZE));
+ if (!offsets) { return -1; }
+ v->offsets = offsets;
+ }
+ v->offsets[v->n_entries] = GRN_BULK_VSIZE(vector);
+ return ++(v->n_entries);
+}
+*/
+
+static unsigned int
+grn_uvector_element_size_internal(grn_ctx *ctx, grn_obj *uvector)
+{
+ unsigned int element_size;
+
+ if (IS_WEIGHT_UVECTOR(uvector)) {
+ element_size = sizeof(weight_uvector_entry);
+ } else {
+ switch (uvector->header.domain) {
+ case GRN_DB_BOOL :
+ element_size = sizeof(grn_bool);
+ break;
+ case GRN_DB_INT8 :
+ element_size = sizeof(int8_t);
+ break;
+ case GRN_DB_UINT8 :
+ element_size = sizeof(uint8_t);
+ break;
+ case GRN_DB_INT16 :
+ element_size = sizeof(int16_t);
+ break;
+ case GRN_DB_UINT16 :
+ element_size = sizeof(uint16_t);
+ break;
+ case GRN_DB_INT32 :
+ element_size = sizeof(int32_t);
+ break;
+ case GRN_DB_UINT32 :
+ element_size = sizeof(uint32_t);
+ break;
+ case GRN_DB_INT64 :
+ element_size = sizeof(int64_t);
+ break;
+ case GRN_DB_UINT64 :
+ element_size = sizeof(uint64_t);
+ break;
+ case GRN_DB_FLOAT :
+ element_size = sizeof(double);
+ break;
+ case GRN_DB_TIME :
+ element_size = sizeof(int64_t);
+ break;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ element_size = sizeof(grn_geo_point);
+ break;
+ default :
+ element_size = sizeof(grn_id);
+ break;
+ }
+ }
+
+ return element_size;
+}
+
+static unsigned int
+grn_uvector_size_internal(grn_ctx *ctx, grn_obj *uvector)
+{
+ unsigned int element_size;
+
+ element_size = grn_uvector_element_size_internal(ctx, uvector);
+ return GRN_BULK_VSIZE(uvector) / element_size;
+}
+
+unsigned int
+grn_vector_size(grn_ctx *ctx, grn_obj *vector)
+{
+ unsigned int size;
+ if (!vector) {
+ ERR(GRN_INVALID_ARGUMENT, "vector is null");
+ return 0;
+ }
+ GRN_API_ENTER;
+ switch (vector->header.type) {
+ case GRN_BULK :
+ size = GRN_BULK_VSIZE(vector);
+ break;
+ case GRN_UVECTOR :
+ size = grn_uvector_size_internal(ctx, vector);
+ break;
+ case GRN_VECTOR :
+ size = vector->u.v.n_sections;
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "not vector");
+ size = 0;
+ break;
+ }
+ GRN_API_RETURN(size);
+}
+
+static grn_obj *
+grn_vector_body(grn_ctx *ctx, grn_obj *v)
+{
+ if (!v) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid argument");
+ return NULL;
+ }
+ switch (v->header.type) {
+ case GRN_VECTOR :
+ if (!v->u.v.body) {
+ v->u.v.body = grn_obj_open(ctx, GRN_BULK, 0, v->header.domain);
+ }
+ return v->u.v.body;
+ case GRN_BULK :
+ case GRN_UVECTOR :
+ return v;
+ default :
+ return NULL;
+ }
+}
+
+unsigned int
+grn_vector_get_element(grn_ctx *ctx, grn_obj *vector,
+ unsigned int offset, const char **str,
+ unsigned int *weight, grn_id *domain)
+{
+ unsigned int length = 0;
+ GRN_API_ENTER;
+ if (!vector || vector->header.type != GRN_VECTOR) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid vector");
+ goto exit;
+ }
+ if ((unsigned int) vector->u.v.n_sections <= offset) {
+ ERR(GRN_RANGE_ERROR, "offset out of range");
+ goto exit;
+ }
+ {
+ grn_section *vp = &vector->u.v.sections[offset];
+ grn_obj *body = grn_vector_body(ctx, vector);
+ *str = GRN_BULK_HEAD(body) + vp->offset;
+ if (weight) { *weight = vp->weight; }
+ if (domain) { *domain = vp->domain; }
+ length = vp->length;
+ }
+exit :
+ GRN_API_RETURN(length);
+}
+
+unsigned int
+grn_vector_pop_element(grn_ctx *ctx, grn_obj *vector,
+ const char **str, unsigned int *weight, grn_id *domain)
+{
+ unsigned int offset, length = 0;
+ GRN_API_ENTER;
+ if (!vector || vector->header.type != GRN_VECTOR) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid vector");
+ goto exit;
+ }
+ if (!vector->u.v.n_sections) {
+ ERR(GRN_RANGE_ERROR, "offset out of range");
+ goto exit;
+ }
+ offset = --vector->u.v.n_sections;
+ {
+ grn_section *vp = &vector->u.v.sections[offset];
+ grn_obj *body = grn_vector_body(ctx, vector);
+ *str = GRN_BULK_HEAD(body) + vp->offset;
+ if (weight) { *weight = vp->weight; }
+ if (domain) { *domain = vp->domain; }
+ length = vp->length;
+ grn_bulk_truncate(ctx, body, vp->offset);
+ }
+exit :
+ GRN_API_RETURN(length);
+}
+
+#define W_SECTIONS_UNIT 8
+#define S_SECTIONS_UNIT (1 << W_SECTIONS_UNIT)
+#define M_SECTIONS_UNIT (S_SECTIONS_UNIT - 1)
+
+grn_rc
+grn_vector_delimit(grn_ctx *ctx, grn_obj *v, unsigned int weight, grn_id domain)
+{
+ if (v->header.type != GRN_VECTOR) { return GRN_INVALID_ARGUMENT; }
+ if (!(v->u.v.n_sections & M_SECTIONS_UNIT)) {
+ grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
+ (v->u.v.n_sections + S_SECTIONS_UNIT));
+ if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
+ v->u.v.sections = vp;
+ }
+ {
+ grn_obj *body = grn_vector_body(ctx, v);
+ grn_section *vp = &v->u.v.sections[v->u.v.n_sections];
+ vp->offset = v->u.v.n_sections ? vp[-1].offset + vp[-1].length : 0;
+ vp->length = GRN_BULK_VSIZE(body) - vp->offset;
+ vp->weight = weight;
+ vp->domain = domain;
+ }
+ v->u.v.n_sections++;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_vector_decode(grn_ctx *ctx, grn_obj *v, const char *data, uint32_t data_size)
+{
+ uint8_t *p = (uint8_t *)data;
+ uint8_t *pe = p + data_size;
+ uint32_t n, n0 = v->u.v.n_sections;
+ GRN_B_DEC(n, p);
+ if (((n0 + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT) !=
+ ((n0 + n + M_SECTIONS_UNIT) >> W_SECTIONS_UNIT)) {
+ grn_section *vp = GRN_REALLOC(v->u.v.sections, sizeof(grn_section) *
+ ((n0 + n + M_SECTIONS_UNIT) & ~M_SECTIONS_UNIT));
+ if (!vp) { return GRN_NO_MEMORY_AVAILABLE; }
+ v->u.v.sections = vp;
+ }
+ {
+ grn_section *vp;
+ grn_obj *body = grn_vector_body(ctx, v);
+ uint32_t offset = GRN_BULK_VSIZE(body);
+ uint32_t o = 0, l, i;
+ for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
+ if (pe <= p) { return GRN_INVALID_ARGUMENT; }
+ GRN_B_DEC(l, p);
+ vp->length = l;
+ vp->offset = offset + o;
+ vp->weight = 0;
+ vp->domain = 0;
+ o += l;
+ }
+ if (pe < p + o) { return GRN_INVALID_ARGUMENT; }
+ grn_bulk_write(ctx, body, (char *)p, o);
+ p += o;
+ if (p < pe) {
+ for (i = n, vp = v->u.v.sections + n0; i; i--, vp++) {
+ if (pe <= p) { return GRN_INVALID_ARGUMENT; }
+ GRN_B_DEC(vp->weight, p);
+ GRN_B_DEC(vp->domain, p);
+ }
+ }
+ }
+ v->u.v.n_sections += n;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_vector_add_element(grn_ctx *ctx, grn_obj *vector,
+ const char *str, unsigned int str_len,
+ unsigned int weight, grn_id domain)
+{
+ grn_obj *body;
+ GRN_API_ENTER;
+ if (!vector) {
+ ERR(GRN_INVALID_ARGUMENT, "vector is null");
+ goto exit;
+ }
+ if ((body = grn_vector_body(ctx, vector))) {
+ grn_bulk_write(ctx, body, str, str_len);
+ grn_vector_delimit(ctx, vector, weight, domain);
+ }
+exit :
+ GRN_API_RETURN(ctx->rc);
+}
+
+/*
+grn_obj *
+grn_sections_to_vector(grn_ctx *ctx, grn_obj *sections)
+{
+ grn_obj *vector = grn_vector_open(ctx, 0);
+ if (vector) {
+ grn_section *vp;
+ int i;
+ for (i = sections->u.v.n_sections, vp = sections->u.v.sections; i; i--, vp++) {
+ grn_text_benc(ctx, vector, vp->weight);
+ grn_text_benc(ctx, vector, vp->domain);
+ grn_bulk_write(ctx, vector, vp->str, vp->str_len);
+ grn_vector_delimit(ctx, vector);
+ }
+ }
+ return vector;
+}
+
+grn_obj *
+grn_vector_to_sections(grn_ctx *ctx, grn_obj *vector, grn_obj *sections)
+{
+ if (!sections) {
+ sections = grn_obj_open(ctx, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, 0);
+ }
+ if (sections) {
+ int i, n = grn_vector_size(ctx, vector);
+ sections->u.v.src = vector;
+ for (i = 0; i < n; i++) {
+ unsigned int size;
+ const uint8_t *pe, *p = (uint8_t *)grn_vector_fetch(ctx, vector, i, &size);
+ if (p) {
+ grn_id domain;
+ unsigned int weight;
+ pe = p + size;
+ if (p < pe) {
+ GRN_B_DEC(weight, p);
+ if (p < pe) {
+ GRN_B_DEC(domain, p);
+ if (p <= pe) {
+ grn_vector_add(ctx, sections, (char *)p, pe - p, weight, domain);
+ }
+ }
+ }
+ }
+ }
+ }
+ return sections;
+}
+*/
+
+/**** uvector ****/
+
+unsigned int
+grn_uvector_size(grn_ctx *ctx, grn_obj *uvector)
+{
+ unsigned int size;
+
+ if (!uvector) {
+ ERR(GRN_INVALID_ARGUMENT, "uvector must not be NULL");
+ return 0;
+ }
+
+ if (uvector->header.type != GRN_UVECTOR) {
+ grn_obj type_name;
+ GRN_TEXT_INIT(&type_name, 0);
+ grn_inspect_type(ctx, &type_name, uvector->header.type);
+ ERR(GRN_INVALID_ARGUMENT, "must be GRN_UVECTOR: %.*s",
+ (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
+ GRN_OBJ_FIN(ctx, &type_name);
+ return 0;
+ }
+
+ GRN_API_ENTER;
+ size = grn_uvector_size_internal(ctx, uvector);
+ GRN_API_RETURN(size);
+}
+
+unsigned int
+grn_uvector_element_size(grn_ctx *ctx, grn_obj *uvector)
+{
+ unsigned int element_size;
+
+ if (!uvector) {
+ ERR(GRN_INVALID_ARGUMENT, "uvector must not be NULL");
+ return 0;
+ }
+
+ if (uvector->header.type != GRN_UVECTOR) {
+ grn_obj type_name;
+ GRN_TEXT_INIT(&type_name, 0);
+ grn_inspect_type(ctx, &type_name, uvector->header.type);
+ ERR(GRN_INVALID_ARGUMENT, "must be GRN_UVECTOR: %.*s",
+ (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
+ GRN_OBJ_FIN(ctx, &type_name);
+ return 0;
+ }
+
+ GRN_API_ENTER;
+ element_size = grn_uvector_element_size_internal(ctx, uvector);
+ GRN_API_RETURN(element_size);
+}
+
+grn_rc
+grn_uvector_add_element(grn_ctx *ctx, grn_obj *uvector,
+ grn_id id, unsigned int weight)
+{
+ GRN_API_ENTER;
+ if (!uvector) {
+ ERR(GRN_INVALID_ARGUMENT, "uvector is null");
+ goto exit;
+ }
+ if (IS_WEIGHT_UVECTOR(uvector)) {
+ weight_uvector_entry entry;
+ entry.id = id;
+ entry.weight = weight;
+ grn_bulk_write(ctx, uvector,
+ (const char *)&entry, sizeof(weight_uvector_entry));
+ } else {
+ grn_bulk_write(ctx, uvector,
+ (const char *)&id, sizeof(grn_id));
+ }
+exit :
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_id
+grn_uvector_get_element(grn_ctx *ctx, grn_obj *uvector,
+ unsigned int offset, unsigned int *weight)
+{
+ grn_id id = GRN_ID_NIL;
+
+ GRN_API_ENTER;
+ if (!uvector || uvector->header.type != GRN_UVECTOR) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid uvector");
+ goto exit;
+ }
+
+ if (IS_WEIGHT_UVECTOR(uvector)) {
+ const weight_uvector_entry *entry;
+ const weight_uvector_entry *entries_start;
+ const weight_uvector_entry *entries_end;
+
+ entries_start = (const weight_uvector_entry *)GRN_BULK_HEAD(uvector);
+ entries_end = (const weight_uvector_entry *)GRN_BULK_CURR(uvector);
+ if (offset > entries_end - entries_start) {
+ ERR(GRN_RANGE_ERROR, "offset out of range");
+ goto exit;
+ }
+
+ entry = entries_start + offset;
+ id = entry->id;
+ if (weight) { *weight = entry->weight; }
+ } else {
+ const grn_id *ids_start;
+ const grn_id *ids_end;
+
+ ids_start = (const grn_id *)GRN_BULK_HEAD(uvector);
+ ids_end = (const grn_id *)GRN_BULK_CURR(uvector);
+ if (offset > ids_end - ids_start) {
+ ERR(GRN_RANGE_ERROR, "offset out of range");
+ goto exit;
+ }
+ id = ids_start[offset];
+ if (weight) { *weight = 0; }
+ }
+exit :
+ GRN_API_RETURN(id);
+}
+
+/**** accessor ****/
+
+static grn_accessor *
+accessor_new(grn_ctx *ctx)
+{
+ grn_accessor *res = GRN_MALLOCN(grn_accessor, 1);
+ if (res) {
+ res->header.type = GRN_ACCESSOR;
+ res->header.impl_flags = GRN_OBJ_ALLOCATED;
+ res->header.flags = 0;
+ res->header.domain = GRN_ID_NIL;
+ res->range = GRN_ID_NIL;
+ res->action = GRN_ACCESSOR_VOID;
+ res->offset = 0;
+ res->obj = NULL;
+ res->next = NULL;
+ }
+ return res;
+}
+
+inline static grn_bool
+grn_obj_get_accessor_rset_value(grn_ctx *ctx, grn_obj *obj,
+ grn_accessor **res, uint8_t action)
+{
+ grn_bool succeeded = GRN_FALSE;
+ grn_accessor **rp;
+
+ for (rp = res; GRN_TRUE; rp = &(*rp)->next) {
+ *rp = accessor_new(ctx);
+ (*rp)->obj = obj;
+
+#define CHECK_GROUP_CALC_FLAG(flag) do { \
+ if (GRN_TABLE_IS_GROUPED(obj)) { \
+ grn_table_group_flags flags; \
+ flags = DB_OBJ(obj)->flags.group; \
+ if (flags & flag) { \
+ succeeded = GRN_TRUE; \
+ (*rp)->action = action; \
+ goto exit; \
+ } \
+ } \
+ } while(GRN_FALSE)
+ switch (action) {
+ case GRN_ACCESSOR_GET_SCORE :
+ if (DB_OBJ(obj)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ (*rp)->action = action;
+ succeeded = GRN_TRUE;
+ goto exit;
+ }
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_MAX);
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_MIN);
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_SUM);
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ CHECK_GROUP_CALC_FLAG(GRN_TABLE_GROUP_CALC_AVG);
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ if (GRN_TABLE_IS_GROUPED(obj)) {
+ (*rp)->action = action;
+ succeeded = GRN_TRUE;
+ goto exit;
+ }
+ break;
+ }
+#undef CHECK_GROUP_CALC_FLAG
+
+ switch (obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ break;
+ case GRN_TABLE_NO_KEY :
+ if (!obj->header.domain) {
+ goto exit;
+ }
+ (*rp)->action = GRN_ACCESSOR_GET_VALUE;
+ break;
+ default :
+ /* lookup failed */
+ goto exit;
+ }
+ if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
+ goto exit;
+ }
+ }
+
+exit :
+ if (!succeeded) {
+ grn_obj_close(ctx, (grn_obj *)*res);
+ *res = NULL;
+ }
+
+ return succeeded;
+}
+
+static grn_obj *
+grn_obj_get_accessor(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
+{
+ grn_accessor *res = NULL, **rp = NULL, **rp0 = NULL;
+ grn_bool is_chained = GRN_FALSE;
+ if (!obj) { return NULL; }
+ GRN_API_ENTER;
+ if (obj->header.type == GRN_ACCESSOR) {
+ is_chained = GRN_TRUE;
+ for (rp0 = (grn_accessor **)&obj; *rp0; rp0 = &(*rp0)->next) {
+ res = *rp0;
+ }
+ switch (res->action) {
+ case GRN_ACCESSOR_GET_KEY :
+ obj = grn_ctx_at(ctx, res->obj->header.domain);
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ case GRN_ACCESSOR_GET_SCORE :
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ case GRN_ACCESSOR_GET_MAX :
+ case GRN_ACCESSOR_GET_MIN :
+ case GRN_ACCESSOR_GET_SUM :
+ case GRN_ACCESSOR_GET_AVG :
+ obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ obj = grn_ctx_at(ctx, DB_OBJ(res->obj)->range);
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ /* todo */
+ break;
+ }
+ }
+ if (!obj) {
+ res = NULL;
+ goto exit;
+ }
+ {
+ size_t len;
+ const char *sp, *se = name + name_size;
+ if (*name == GRN_DB_DELIMITER) { name++; }
+ for (sp = name; (len = grn_charlen(ctx, sp, se)); sp += len) {
+ if (*sp == GRN_DB_DELIMITER) { break; }
+ }
+ if (!(len = sp - name)) { goto exit; }
+ if (*name == GRN_DB_PSEUDO_COLUMN_PREFIX) { /* pseudo column */
+ int done = 0;
+ if (len < 2) { goto exit; }
+ switch (name[1]) {
+ case 'k' : /* key */
+ if (len != GRN_COLUMN_NAME_KEY_LEN ||
+ memcmp(name, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN)) {
+ goto exit;
+ }
+ for (rp = &res; !done; rp = &(*rp)->next) {
+ *rp = accessor_new(ctx);
+ (*rp)->obj = obj;
+ if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(obj)) {
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ done++;
+ break;
+ }
+ if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ switch (obj->header.type) {
+ case GRN_DB :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ rp = &(*rp)->next;
+ *rp = accessor_new(ctx);
+ (*rp)->obj = obj;
+ (*rp)->action = GRN_ACCESSOR_GET_DB_OBJ;
+ done++;
+ break;
+ case GRN_TYPE :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ done++;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ break;
+ case GRN_TABLE_NO_KEY :
+ if (obj->header.domain) {
+ (*rp)->action = GRN_ACCESSOR_GET_VALUE;
+ break;
+ }
+ /* fallthru */
+ default :
+ /* lookup failed */
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ }
+ break;
+ case 'i' : /* id */
+ if (len != GRN_COLUMN_NAME_ID_LEN ||
+ memcmp(name, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN)) {
+ goto exit;
+ }
+ for (rp = &res; !done; rp = &(*rp)->next) {
+ *rp = accessor_new(ctx);
+ (*rp)->obj = obj;
+ if (!obj->header.domain) {
+ (*rp)->action = GRN_ACCESSOR_GET_ID;
+ done++;
+ } else {
+ if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ switch (obj->header.type) {
+ case GRN_DB :
+ case GRN_TYPE :
+ (*rp)->action = GRN_ACCESSOR_GET_ID;
+ done++;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_NO_KEY :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ break;
+ default :
+ /* lookup failed */
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ }
+ }
+ break;
+ case 'v' : /* value */
+ if (len != GRN_COLUMN_NAME_VALUE_LEN ||
+ memcmp(name, GRN_COLUMN_NAME_VALUE, GRN_COLUMN_NAME_VALUE_LEN)) {
+ goto exit;
+ }
+ for (rp = &res; !done; rp = &(*rp)->next) {
+ *rp = accessor_new(ctx);
+ (*rp)->obj = obj;
+ if (!obj->header.domain) {
+ if (DB_OBJ((*rp)->obj)->range) {
+ (*rp)->action = GRN_ACCESSOR_GET_VALUE;
+ done++;
+ } else {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ done++;
+ } else {
+ if (!(obj = grn_ctx_at(ctx, obj->header.domain))) {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ switch (obj->header.type) {
+ case GRN_DB :
+ case GRN_TYPE :
+ if (DB_OBJ((*rp)->obj)->range) {
+ (*rp)->action = GRN_ACCESSOR_GET_VALUE;
+ done++;
+ } else {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ break;
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_NO_KEY :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ break;
+ default :
+ /* lookup failed */
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ }
+ }
+ break;
+ case 's' : /* score, sum */
+ if (len == GRN_COLUMN_NAME_SCORE_LEN &&
+ memcmp(name, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) {
+ if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
+ GRN_ACCESSOR_GET_SCORE)) {
+ goto exit;
+ }
+ } else if (len == GRN_COLUMN_NAME_SUM_LEN &&
+ memcmp(name,
+ GRN_COLUMN_NAME_SUM,
+ GRN_COLUMN_NAME_SUM_LEN) == 0) {
+ if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
+ GRN_ACCESSOR_GET_SUM)) {
+ goto exit;
+ }
+ } else {
+ goto exit;
+ }
+ break;
+ case 'n' : /* nsubrecs */
+ if (len != GRN_COLUMN_NAME_NSUBRECS_LEN ||
+ memcmp(name,
+ GRN_COLUMN_NAME_NSUBRECS,
+ GRN_COLUMN_NAME_NSUBRECS_LEN)) {
+ goto exit;
+ }
+ if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
+ GRN_ACCESSOR_GET_NSUBRECS)) {
+ goto exit;
+ }
+ break;
+ case 'm' : /* max, min */
+ if (len == GRN_COLUMN_NAME_MAX_LEN &&
+ memcmp(name,
+ GRN_COLUMN_NAME_MAX,
+ GRN_COLUMN_NAME_MAX_LEN) == 0) {
+ if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
+ GRN_ACCESSOR_GET_MAX)) {
+ goto exit;
+ }
+ } else if (len == GRN_COLUMN_NAME_MIN_LEN &&
+ memcmp(name,
+ GRN_COLUMN_NAME_MIN,
+ GRN_COLUMN_NAME_MIN_LEN) == 0) {
+ if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
+ GRN_ACCESSOR_GET_MIN)) {
+ goto exit;
+ }
+ } else {
+ goto exit;
+ }
+ break;
+ case 'a' : /* avg */
+ if (len == GRN_COLUMN_NAME_AVG_LEN &&
+ memcmp(name,
+ GRN_COLUMN_NAME_AVG,
+ GRN_COLUMN_NAME_AVG_LEN) == 0) {
+ if (!grn_obj_get_accessor_rset_value(ctx, obj, &res,
+ GRN_ACCESSOR_GET_AVG)) {
+ goto exit;
+ }
+ } else {
+ goto exit;
+ }
+ break;
+ default :
+ res = NULL;
+ goto exit;
+ }
+ } else {
+ /* if obj->header.type == GRN_TYPE ... lookup table */
+ for (rp = &res; ; rp = &(*rp)->next) {
+ grn_obj *column = grn_obj_column_(ctx, obj, name, len);
+ if (column) {
+ *rp = accessor_new(ctx);
+ (*rp)->obj = column;
+ /*
+ switch (column->header.type) {
+ case GRN_COLUMN_VAR_SIZE :
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ break;
+ case GRN_COLUMN_INDEX :
+ break;
+ }
+ */
+ (*rp)->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
+ break;
+ } else {
+ grn_id next_obj_id;
+ next_obj_id = obj->header.domain;
+ if (!next_obj_id) {
+ // ERR(GRN_INVALID_ARGUMENT, "no such column: <%s>", name);
+ if (!is_chained) {
+ grn_obj_close(ctx, (grn_obj *)res);
+ }
+ res = NULL;
+ goto exit;
+ }
+ *rp = accessor_new(ctx);
+ (*rp)->obj = obj;
+ obj = grn_ctx_at(ctx, next_obj_id);
+ if (!obj) {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ switch (obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_NO_KEY :
+ (*rp)->action = GRN_ACCESSOR_GET_KEY;
+ break;
+ default :
+ /* lookup failed */
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ }
+ }
+ }
+ if (sp != se) {
+ if (!grn_obj_get_accessor(ctx, (grn_obj *)res, sp, se - sp)) {
+ if (!is_chained) {
+ grn_obj_close(ctx, (grn_obj *)res);
+ res = NULL;
+ goto exit;
+ }
+ }
+ }
+ }
+ if (rp0) { *rp0 = res; }
+ exit :
+ GRN_API_RETURN((grn_obj *)res);
+}
+
+inline static grn_bool
+grn_column_is_vector(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj_flags type;
+
+ if (column->header.type != GRN_COLUMN_VAR_SIZE) {
+ return GRN_FALSE;
+ }
+
+ type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
+ return type == GRN_OBJ_COLUMN_VECTOR;
+}
+
+inline static grn_bool
+grn_column_is_index(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj_flags type;
+
+ if (column->header.type == GRN_ACCESSOR) {
+ grn_accessor *a;
+ for (a = (grn_accessor *)column; a; a = a->next) {
+ if (a->next) {
+ continue;
+ }
+ if (a->action != GRN_ACCESSOR_GET_COLUMN_VALUE) {
+ return GRN_FALSE;
+ }
+
+ column = a->obj;
+ }
+ }
+
+ if (column->header.type != GRN_COLUMN_INDEX) {
+ return GRN_FALSE;
+ }
+
+ type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
+ return type == GRN_OBJ_COLUMN_INDEX;
+}
+
+inline static void
+grn_obj_get_range_info(grn_ctx *ctx, grn_obj *obj,
+ grn_id *range_id, grn_obj_flags *range_flags)
+{
+ if (!obj) {
+ *range_id = GRN_ID_NIL;
+ } else if (grn_obj_is_proc(ctx, obj)) {
+ /* TODO */
+ *range_id = GRN_ID_NIL;
+ } else if (GRN_DB_OBJP(obj)) {
+ *range_id = DB_OBJ(obj)->range;
+ if (grn_column_is_vector(ctx, obj)) {
+ *range_flags = GRN_OBJ_VECTOR;
+ }
+ } else if (obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a;
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ *range_id = GRN_DB_UINT32;
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ if (GRN_DB_OBJP(a->obj)) {
+ *range_id = DB_OBJ(a->obj)->range;
+ }
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ *range_id = GRN_DB_FLOAT;
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ *range_id = GRN_DB_INT32;
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ case GRN_ACCESSOR_GET_MIN :
+ case GRN_ACCESSOR_GET_SUM :
+ *range_id = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ *range_id = GRN_DB_FLOAT;
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ grn_obj_get_range_info(ctx, a->obj, range_id, range_flags);
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->header.domain; }
+ break;
+ default :
+ if (GRN_DB_OBJP(a->obj)) { *range_id = DB_OBJ(a->obj)->range; }
+ break;
+ }
+ }
+ }
+}
+
+grn_id
+grn_obj_get_range(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_id range_id = GRN_ID_NIL;
+ grn_obj_flags range_flags = 0;
+
+ grn_obj_get_range_info(ctx, obj, &range_id, &range_flags);
+
+ return range_id;
+}
+
+int
+grn_obj_is_persistent(grn_ctx *ctx, grn_obj *obj)
+{
+ int res = 0;
+ if (GRN_DB_OBJP(obj)) {
+ res = IS_TEMP(obj) ? 0 : 1;
+ } else if (obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a;
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_SCORE :
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ case GRN_ACCESSOR_GET_MAX :
+ case GRN_ACCESSOR_GET_MIN :
+ case GRN_ACCESSOR_GET_SUM :
+ case GRN_ACCESSOR_GET_AVG :
+ res = 0;
+ break;
+ case GRN_ACCESSOR_GET_ID :
+ case GRN_ACCESSOR_GET_VALUE :
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ case GRN_ACCESSOR_GET_KEY :
+ if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
+ break;
+ default :
+ if (GRN_DB_OBJP(a->obj)) { res = IS_TEMP(obj) ? 0 : 1; }
+ break;
+ }
+ }
+ }
+ return res;
+}
+
+#define SRC2RECORD() do {\
+ grn_obj *table = grn_ctx_at(ctx, dest->header.domain);\
+ if (GRN_OBJ_TABLEP(table)) {\
+ grn_obj *p_key = src;\
+ grn_id id;\
+ if (table->header.type != GRN_TABLE_NO_KEY) {\
+ grn_obj key;\
+ GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);\
+ if (src->header.domain != table->header.domain) {\
+ rc = grn_obj_cast(ctx, src, &key, GRN_TRUE);\
+ p_key = &key;\
+ }\
+ if (!rc) {\
+ if (GRN_BULK_VSIZE(p_key)) {\
+ if (add_record_if_not_exist) {\
+ id = grn_table_add_by_key(ctx, table, p_key, NULL);\
+ } else {\
+ id = grn_table_get_by_key(ctx, table, p_key);\
+ }\
+ if (id) {\
+ GRN_RECORD_SET(ctx, dest, id);\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ } else {\
+ GRN_RECORD_SET(ctx, dest, GRN_ID_NIL);\
+ }\
+ }\
+ GRN_OBJ_FIN(ctx, &key);\
+ } else {\
+ grn_obj record_id;\
+ GRN_UINT32_INIT(&record_id, 0);\
+ rc = grn_obj_cast(ctx, src, &record_id, GRN_TRUE);\
+ if (!rc) {\
+ id = GRN_UINT32_VALUE(&record_id);\
+ if (id) {\
+ GRN_RECORD_SET(ctx, dest, id);\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ }\
+ }\
+ } else {\
+ rc = GRN_FUNCTION_NOT_IMPLEMENTED;\
+ }\
+} while (0)
+
+inline static grn_rc
+grn_obj_cast_bool(grn_ctx *ctx, grn_obj *src, grn_obj *dest,
+ grn_bool add_record_if_not_exist)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ switch (dest->header.domain) {
+ case GRN_DB_BOOL :
+ GRN_BOOL_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_INT8 :
+ GRN_INT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_UINT8 :
+ GRN_UINT8_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_INT16 :
+ GRN_INT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_UINT16 :
+ GRN_UINT16_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_INT32 :
+ GRN_INT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_UINT32 :
+ GRN_UINT32_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_INT64 :
+ GRN_INT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_UINT64 :
+ GRN_UINT64_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_TIME :
+ GRN_TIME_SET(ctx, dest, GRN_BOOL_VALUE(src));
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ {
+ const char *bool_text;
+ bool_text = GRN_BOOL_VALUE(src) ? "true" : "false";
+ GRN_TEXT_PUTS(ctx, dest, bool_text);
+ }
+ break;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ default :
+ SRC2RECORD();
+ break;
+ }
+ return rc;
+}
+
+#define NUM2DEST(getvalue,totext,tobool,totime,tofloat)\
+ switch (dest->header.domain) {\
+ case GRN_DB_BOOL :\
+ tobool(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_INT8 :\
+ GRN_INT8_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_UINT8 :\
+ GRN_UINT8_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_INT16 :\
+ GRN_INT16_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_UINT16 :\
+ GRN_UINT16_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_INT32 :\
+ GRN_INT32_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_UINT32 :\
+ GRN_UINT32_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_TIME :\
+ totime(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_INT64 :\
+ GRN_INT64_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_UINT64 :\
+ GRN_UINT64_SET(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_FLOAT :\
+ tofloat(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ totext(ctx, dest, getvalue(src));\
+ break;\
+ case GRN_DB_TOKYO_GEO_POINT :\
+ case GRN_DB_WGS84_GEO_POINT :\
+ rc = GRN_INVALID_ARGUMENT;\
+ break;\
+ default :\
+ SRC2RECORD();\
+ break;\
+ }
+
+#define TEXT2DEST(type,tonum,setvalue) do {\
+ const char *cur, *str = GRN_TEXT_VALUE(src);\
+ const char *str_end = GRN_BULK_CURR(src);\
+ type i = tonum(str, str_end, &cur);\
+ if (cur == str_end) {\
+ setvalue(ctx, dest, i);\
+ } else if (cur != str) {\
+ const char *rest;\
+ grn_obj buf;\
+ GRN_VOID_INIT(&buf);\
+ rc = grn_aton(ctx, str, str_end, &rest, &buf);\
+ if (!rc) {\
+ rc = grn_obj_cast(ctx, &buf, dest, add_record_if_not_exist);\
+ }\
+ GRN_OBJ_FIN(ctx, &buf);\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+} while (0)
+
+#define NUM2BOOL(ctx, dest, value) GRN_BOOL_SET(ctx, dest, value != 0)
+#define FLOAT2BOOL(ctx, dest, value) do {\
+ double value_ = value;\
+ GRN_BOOL_SET(ctx, dest, value_ < -DBL_EPSILON || DBL_EPSILON < value_);\
+} while (0)
+
+#define NUM2TIME(ctx, dest, value)\
+ GRN_TIME_SET(ctx, dest, (long long int)(value) * GRN_TIME_USEC_PER_SEC);
+#define TIME2TIME(ctx, dest, value)\
+ GRN_TIME_SET(ctx, dest, value);
+#define FLOAT2TIME(ctx, dest, value) do {\
+ int64_t usec = llround(value * GRN_TIME_USEC_PER_SEC);\
+ GRN_TIME_SET(ctx, dest, usec);\
+} while (0)
+
+#define NUM2FLOAT(ctx, dest, value)\
+ GRN_FLOAT_SET(ctx, dest, value);
+#define TIME2FLOAT(ctx, dest, value)\
+ GRN_FLOAT_SET(ctx, dest, (double)(value) / GRN_TIME_USEC_PER_SEC);
+#define FLOAT2FLOAT(ctx, dest, value)\
+ GRN_FLOAT_SET(ctx, dest, value);
+
+static grn_rc
+grn_obj_cast_record(grn_ctx *ctx,
+ grn_obj *src,
+ grn_obj *dest,
+ grn_bool add_record_if_not_exist)
+{
+ grn_obj *src_table;
+ grn_obj *dest_table;
+ const char *key;
+ uint32_t key_size;
+ grn_id dest_id;
+
+ if (src->header.domain == dest->header.domain) {
+ GRN_RECORD_SET(ctx, dest, GRN_RECORD_VALUE(src));
+ return GRN_SUCCESS;
+ }
+
+ src_table = grn_ctx_at(ctx, src->header.domain);
+ if (!src_table) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (src_table->header.type == GRN_TABLE_NO_KEY) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ dest_table = grn_ctx_at(ctx, dest->header.domain);
+ if (!dest_table) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ switch (dest_table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ break;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (GRN_RECORD_VALUE(src) == GRN_ID_NIL) {
+ GRN_RECORD_SET(ctx, dest, GRN_RECORD_VALUE(src));
+ return GRN_SUCCESS;
+ }
+
+ key = _grn_table_key(ctx, src_table, GRN_RECORD_VALUE(src), &key_size);
+ if (add_record_if_not_exist) {
+ dest_id = grn_table_add(ctx, dest_table, key, key_size, NULL);
+ } else {
+ dest_id = grn_table_get(ctx, dest_table, key, key_size);
+ }
+ GRN_RECORD_SET(ctx, dest, dest_id);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_obj_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest,
+ grn_bool add_record_if_not_exist)
+{
+ grn_rc rc = GRN_SUCCESS;
+ switch (src->header.domain) {
+ case GRN_DB_BOOL :
+ rc = grn_obj_cast_bool(ctx, src, dest, add_record_if_not_exist);
+ break;
+ case GRN_DB_INT8 :
+ NUM2DEST(GRN_INT8_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_UINT8 :
+ NUM2DEST(GRN_UINT8_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_INT16 :
+ NUM2DEST(GRN_INT16_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_UINT16 :
+ NUM2DEST(GRN_UINT16_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_INT32 :
+ NUM2DEST(GRN_INT32_VALUE, grn_text_itoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_UINT32 :
+ NUM2DEST(GRN_UINT32_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_INT64 :
+ NUM2DEST(GRN_INT64_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_TIME :
+ NUM2DEST(GRN_TIME_VALUE, grn_text_lltoa, NUM2BOOL, TIME2TIME, TIME2FLOAT);
+ break;
+ case GRN_DB_UINT64 :
+ NUM2DEST(GRN_UINT64_VALUE, grn_text_lltoa, NUM2BOOL, NUM2TIME, NUM2FLOAT);
+ break;
+ case GRN_DB_FLOAT :
+ NUM2DEST(GRN_FLOAT_VALUE, grn_text_ftoa, FLOAT2BOOL, FLOAT2TIME,
+ FLOAT2FLOAT);
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ switch (dest->header.domain) {
+ case GRN_DB_BOOL :
+ GRN_BOOL_SET(ctx, dest, GRN_TEXT_LEN(src) > 0);
+ break;
+ case GRN_DB_INT8 :
+ TEXT2DEST(int8_t, grn_atoi8, GRN_INT8_SET);
+ break;
+ case GRN_DB_UINT8 :
+ TEXT2DEST(uint8_t, grn_atoui8, GRN_UINT8_SET);
+ break;
+ case GRN_DB_INT16 :
+ TEXT2DEST(int16_t, grn_atoi16, GRN_INT16_SET);
+ break;
+ case GRN_DB_UINT16 :
+ TEXT2DEST(uint16_t, grn_atoui16, GRN_UINT16_SET);
+ break;
+ case GRN_DB_INT32 :
+ TEXT2DEST(int32_t, grn_atoi, GRN_INT32_SET);
+ break;
+ case GRN_DB_UINT32 :
+ TEXT2DEST(uint32_t, grn_atoui, GRN_UINT32_SET);
+ break;
+ case GRN_DB_TIME :
+ {
+ grn_timeval v;
+ int len = GRN_TEXT_LEN(src);
+ char *str = GRN_TEXT_VALUE(src);
+ if (grn_str2timeval(str, len, &v)) {
+ double d;
+ char *end;
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUT(ctx, &buf, str, len);
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ errno = 0;
+ d = strtod(GRN_TEXT_VALUE(&buf), &end);
+ if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
+ v.tv_sec = d;
+ v.tv_nsec = ((d - v.tv_sec) * GRN_TIME_NSEC_PER_SEC);
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ GRN_TIME_SET(ctx, dest,
+ GRN_TIME_PACK((int64_t)v.tv_sec,
+ GRN_TIME_NSEC_TO_USEC(v.tv_nsec)));
+ }
+ break;
+ case GRN_DB_INT64 :
+ TEXT2DEST(int64_t, grn_atoll, GRN_INT64_SET);
+ break;
+ case GRN_DB_UINT64 :
+ TEXT2DEST(int64_t, grn_atoll, GRN_UINT64_SET);
+ break;
+ case GRN_DB_FLOAT :
+ {
+ double d;
+ char *end;
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUT(ctx, &buf, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ errno = 0;
+ d = strtod(GRN_TEXT_VALUE(&buf), &end);
+ if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
+ GRN_FLOAT_SET(ctx, dest, d);
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
+ break;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ {
+ int latitude, longitude;
+ double degree;
+ const char *cur, *str = GRN_TEXT_VALUE(src);
+ const char *str_end = GRN_BULK_CURR(src);
+ if (str == str_end) {
+ GRN_GEO_POINT_SET(ctx, dest, 0, 0);
+ } else {
+ char *end;
+ grn_obj buf, *buf_p = NULL;
+ latitude = grn_atoi(str, str_end, &cur);
+ if (cur < str_end && cur[0] == '.') {
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ buf_p = &buf;
+ errno = 0;
+ degree = strtod(GRN_TEXT_VALUE(buf_p), &end);
+ if (errno) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ latitude = GRN_GEO_DEGREE2MSEC(degree);
+ cur = str + (end - GRN_TEXT_VALUE(buf_p));
+ }
+ }
+ if (!rc && (cur[0] == 'x' || cur[0] == ',') && cur + 1 < str_end) {
+ const char *c = cur + 1;
+ longitude = grn_atoi(c, str_end, &cur);
+ if (cur < str_end && cur[0] == '.') {
+ if (!buf_p) {
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUT(ctx, &buf, str, GRN_TEXT_LEN(src));
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ buf_p = &buf;
+ }
+ errno = 0;
+ degree = strtod(GRN_TEXT_VALUE(buf_p) + (c - str), &end);
+ if (errno) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ longitude = GRN_GEO_DEGREE2MSEC(degree);
+ cur = str + (end - GRN_TEXT_VALUE(buf_p));
+ }
+ }
+ if (!rc && cur == str_end) {
+ if ((GRN_GEO_MIN_LATITUDE <= latitude &&
+ latitude <= GRN_GEO_MAX_LATITUDE) &&
+ (GRN_GEO_MIN_LONGITUDE <= longitude &&
+ longitude <= GRN_GEO_MAX_LONGITUDE)) {
+ GRN_GEO_POINT_SET(ctx, dest, latitude, longitude);
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ if (buf_p) { GRN_OBJ_FIN(ctx, buf_p); }
+ }
+ }
+ break;
+ default :
+ SRC2RECORD();
+ break;
+ }
+ break;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ if (src->header.domain == dest->header.domain) {
+ GRN_TEXT_PUT(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
+ } else {
+ int latitude, longitude;
+ double latitude_in_degree, longitude_in_degree;
+ GRN_GEO_POINT_VALUE(src, latitude, longitude);
+ latitude_in_degree = GRN_GEO_MSEC2DEGREE(latitude);
+ longitude_in_degree = GRN_GEO_MSEC2DEGREE(longitude);
+ /* TokyoGeoPoint <-> WGS84GeoPoint is based on
+ http://www.jalan.net/jw/jwp0200/jww0203.do
+
+ jx: longitude in degree in Tokyo Geodetic System.
+ jy: latitude in degree in Tokyo Geodetic System.
+ wx: longitude in degree in WGS 84.
+ wy: latitude in degree in WGS 84.
+
+ jy = wy * 1.000106961 - wx * 0.000017467 - 0.004602017
+ jx = wx * 1.000083049 + wy * 0.000046047 - 0.010041046
+
+ wy = jy - jy * 0.00010695 + jx * 0.000017464 + 0.0046017
+ wx = jx - jy * 0.000046038 - jx * 0.000083043 + 0.010040
+ */
+ if (dest->header.domain == GRN_DB_TOKYO_GEO_POINT) {
+ double wgs84_latitude_in_degree = latitude_in_degree;
+ double wgs84_longitude_in_degree = longitude_in_degree;
+ int tokyo_latitude, tokyo_longitude;
+ double tokyo_latitude_in_degree, tokyo_longitude_in_degree;
+ tokyo_latitude_in_degree =
+ wgs84_latitude_in_degree * 1.000106961 -
+ wgs84_longitude_in_degree * 0.000017467 -
+ 0.004602017;
+ tokyo_longitude_in_degree =
+ wgs84_longitude_in_degree * 1.000083049 +
+ wgs84_latitude_in_degree * 0.000046047 -
+ 0.010041046;
+ tokyo_latitude = GRN_GEO_DEGREE2MSEC(tokyo_latitude_in_degree);
+ tokyo_longitude = GRN_GEO_DEGREE2MSEC(tokyo_longitude_in_degree);
+ GRN_GEO_POINT_SET(ctx, dest, tokyo_latitude, tokyo_longitude);
+ } else {
+ double tokyo_latitude_in_degree = latitude_in_degree;
+ double tokyo_longitude_in_degree = longitude_in_degree;
+ int wgs84_latitude, wgs84_longitude;
+ double wgs84_latitude_in_degree, wgs84_longitude_in_degree;
+ wgs84_latitude_in_degree =
+ tokyo_latitude_in_degree -
+ tokyo_latitude_in_degree * 0.00010695 +
+ tokyo_longitude_in_degree * 0.000017464 +
+ 0.0046017;
+ wgs84_longitude_in_degree =
+ tokyo_longitude_in_degree -
+ tokyo_latitude_in_degree * 0.000046038 -
+ tokyo_longitude_in_degree * 0.000083043 +
+ 0.010040;
+ wgs84_latitude = GRN_GEO_DEGREE2MSEC(wgs84_latitude_in_degree);
+ wgs84_longitude = GRN_GEO_DEGREE2MSEC(wgs84_longitude_in_degree);
+ GRN_GEO_POINT_SET(ctx, dest, wgs84_latitude, wgs84_longitude);
+ }
+ }
+ break;
+ case GRN_VOID :
+ rc = grn_obj_reinit(ctx, dest, dest->header.domain, dest->header.flags);
+ break;
+ default :
+ if (src->header.domain >= GRN_N_RESERVED_TYPES) {
+ grn_obj *table;
+ table = grn_ctx_at(ctx, src->header.domain);
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ rc = grn_obj_cast_record(ctx, src, dest, add_record_if_not_exist);
+ break;
+ default :
+ rc = GRN_FUNCTION_NOT_IMPLEMENTED;
+ break;
+ }
+ } else {
+ rc = GRN_FUNCTION_NOT_IMPLEMENTED;
+ }
+ break;
+ }
+ return rc;
+}
+
+const char *
+grn_accessor_get_value_(grn_ctx *ctx, grn_accessor *a, grn_id id, uint32_t *size)
+{
+ const char *value = NULL;
+ for (;;) {
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ value = (const char *)(uintptr_t)id;
+ *size = GRN_OBJ_GET_VALUE_IMD;
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ value = _grn_table_key(ctx, a->obj, id, size);
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ value = grn_obj_get_value_(ctx, a->obj, id, size);
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
+ value = (const char *)&((grn_rset_recinfo *)value)->score;
+ *size = sizeof(double);
+ }
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
+ value = (const char *)&((grn_rset_recinfo *)value)->n_subrecs;
+ *size = sizeof(int);
+ }
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
+ value =
+ (const char *)grn_rset_recinfo_get_max_(ctx,
+ (grn_rset_recinfo *)value,
+ a->obj);
+ *size = GRN_RSET_MAX_SIZE;
+ }
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
+ value =
+ (const char *)grn_rset_recinfo_get_min_(ctx,
+ (grn_rset_recinfo *)value,
+ a->obj);
+ *size = GRN_RSET_MIN_SIZE;
+ }
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
+ value =
+ (const char *)grn_rset_recinfo_get_sum_(ctx,
+ (grn_rset_recinfo *)value,
+ a->obj);
+ *size = GRN_RSET_SUM_SIZE;
+ }
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ if ((value = grn_obj_get_value_(ctx, a->obj, id, size))) {
+ value =
+ (const char *)grn_rset_recinfo_get_avg_(ctx,
+ (grn_rset_recinfo *)value,
+ a->obj);
+ *size = GRN_RSET_AVG_SIZE;
+ }
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ /* todo : support vector */
+ value = grn_obj_get_value_(ctx, a->obj, id, size);
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ value = _grn_table_key(ctx, ((grn_db *)ctx->impl->db)->keys, id, size);
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ /* todo */
+ break;
+ }
+ if (value && (a = a->next)) {
+ id = *((grn_id *)value);
+ } else {
+ break;
+ }
+ }
+ return value;
+}
+
+static grn_obj *
+grn_accessor_get_value(grn_ctx *ctx, grn_accessor *a, grn_id id, grn_obj *value)
+{
+ uint32_t vs = 0;
+ uint32_t size0;
+ void *vp = NULL;
+ if (!value) {
+ if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) { return NULL; }
+ } else {
+ value->header.type = GRN_BULK;
+ }
+ size0 = GRN_BULK_VSIZE(value);
+ for (;;) {
+ grn_bulk_truncate(ctx, value, size0);
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ GRN_UINT32_PUT(ctx, value, id);
+ value->header.domain = GRN_DB_UINT32;
+ vp = GRN_BULK_HEAD(value) + size0;
+ vs = GRN_BULK_VSIZE(value) - size0;
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ if (!a->next && GRN_TABLE_IS_MULTI_KEYS_GROUPED(a->obj)) {
+ grn_obj_ensure_vector(ctx, value);
+ if (id) {
+ grn_obj raw_vector;
+ GRN_TEXT_INIT(&raw_vector, 0);
+ grn_table_get_key2(ctx, a->obj, id, &raw_vector);
+ grn_vector_decode(ctx, value,
+ GRN_BULK_HEAD(&raw_vector),
+ GRN_BULK_VSIZE(&raw_vector));
+ GRN_OBJ_FIN(ctx, &raw_vector);
+ }
+ vp = NULL;
+ vs = 0;
+ } else {
+ if (id) {
+ grn_table_get_key2(ctx, a->obj, id, value);
+ vp = GRN_BULK_HEAD(value) + size0;
+ vs = GRN_BULK_VSIZE(value) - size0;
+ } else {
+ vp = NULL;
+ vs = 0;
+ }
+ value->header.domain = a->obj->header.domain;
+ }
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ grn_obj_get_value(ctx, a->obj, id, value);
+ vp = GRN_BULK_HEAD(value) + size0;
+ vs = GRN_BULK_VSIZE(value) - size0;
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ if (id) {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ GRN_FLOAT_PUT(ctx, value, ri->score);
+ } else {
+ GRN_FLOAT_PUT(ctx, value, 0.0);
+ }
+ value->header.domain = GRN_DB_FLOAT;
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ if (id) {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ GRN_INT32_PUT(ctx, value, ri->n_subrecs);
+ } else {
+ GRN_INT32_PUT(ctx, value, 0);
+ }
+ value->header.domain = GRN_DB_INT32;
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ if (id) {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int64_t max;
+ max = grn_rset_recinfo_get_max(ctx, ri, a->obj);
+ GRN_INT64_PUT(ctx, value, max);
+ } else {
+ GRN_INT64_PUT(ctx, value, 0);
+ }
+ value->header.domain = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ if (id) {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int64_t min;
+ min = grn_rset_recinfo_get_min(ctx, ri, a->obj);
+ GRN_INT64_PUT(ctx, value, min);
+ } else {
+ GRN_INT64_PUT(ctx, value, 0);
+ }
+ value->header.domain = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ if (id) {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int64_t sum;
+ sum = grn_rset_recinfo_get_sum(ctx, ri, a->obj);
+ GRN_INT64_PUT(ctx, value, sum);
+ } else {
+ GRN_INT64_PUT(ctx, value, 0);
+ }
+ value->header.domain = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ if (id) {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ double avg;
+ avg = grn_rset_recinfo_get_avg(ctx, ri, a->obj);
+ GRN_FLOAT_PUT(ctx, value, avg);
+ } else {
+ GRN_FLOAT_PUT(ctx, value, 0.0);
+ }
+ value->header.domain = GRN_DB_FLOAT;
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ /* todo : support vector */
+ grn_obj_get_value(ctx, a->obj, id, value);
+ vp = GRN_BULK_HEAD(value) + size0;
+ vs = GRN_BULK_VSIZE(value) - size0;
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ value = grn_ctx_at(ctx, id);
+ grn_obj_close(ctx, value);
+ return value;
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ /* todo */
+ break;
+ }
+ if ((a = a->next)) {
+ if (vs > 0) {
+ id = *((grn_id *)vp);
+ } else {
+ id = GRN_ID_NIL;
+ }
+ } else {
+ break;
+ }
+ }
+ return value;
+}
+
+static grn_rc
+grn_accessor_set_value(grn_ctx *ctx, grn_accessor *a, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (!value) { value = grn_obj_open(ctx, GRN_BULK, 0, 0); }
+ if (value) {
+ grn_obj buf;
+ void *vp = NULL;
+ GRN_TEXT_INIT(&buf, 0);
+ for (;;) {
+ GRN_BULK_REWIND(&buf);
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_KEY :
+ grn_table_get_key2(ctx, a->obj, id, &buf);
+ vp = GRN_BULK_HEAD(&buf);
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ if (a->next) {
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ vp = GRN_BULK_HEAD(&buf);
+ } else {
+ rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
+ }
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ {
+ grn_rset_recinfo *ri;
+ if (a->next) {
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
+ vp = &ri->score;
+ } else {
+ uint32_t size;
+ if ((ri = (grn_rset_recinfo *) grn_obj_get_value_(ctx, a->obj, id, &size))) {
+ // todo : flags support
+ if (value->header.domain == GRN_DB_FLOAT) {
+ ri->score = GRN_FLOAT_VALUE(value);
+ } else {
+ grn_obj buf;
+ GRN_FLOAT_INIT(&buf, 0);
+ grn_obj_cast(ctx, value, &buf, GRN_FALSE);
+ ri->score = GRN_FLOAT_VALUE(&buf);
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ }
+ }
+ }
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
+ vp = &ri->n_subrecs;
+ }
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
+ if (value->header.type == GRN_DB_INT64) {
+ grn_rset_recinfo_set_max(ctx, ri, a->obj, GRN_INT64_VALUE(value));
+ } else {
+ grn_obj value_int64;
+ GRN_INT64_INIT(&value_int64, 0);
+ if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
+ grn_rset_recinfo_set_max(ctx, ri, a->obj,
+ GRN_INT64_VALUE(&value_int64));
+ }
+ GRN_OBJ_FIN(ctx, &value_int64);
+ }
+ }
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
+ if (value->header.type == GRN_DB_INT64) {
+ grn_rset_recinfo_set_min(ctx, ri, a->obj, GRN_INT64_VALUE(value));
+ } else {
+ grn_obj value_int64;
+ GRN_INT64_INIT(&value_int64, 0);
+ if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
+ grn_rset_recinfo_set_min(ctx, ri, a->obj,
+ GRN_INT64_VALUE(&value_int64));
+ }
+ GRN_OBJ_FIN(ctx, &value_int64);
+ }
+ }
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
+ if (value->header.type == GRN_DB_INT64) {
+ grn_rset_recinfo_set_sum(ctx, ri, a->obj, GRN_INT64_VALUE(value));
+ } else {
+ grn_obj value_int64;
+ GRN_INT64_INIT(&value_int64, 0);
+ if (!grn_obj_cast(ctx, value, &value_int64, GRN_FALSE)) {
+ grn_rset_recinfo_set_sum(ctx, ri, a->obj,
+ GRN_INT64_VALUE(&value_int64));
+ }
+ GRN_OBJ_FIN(ctx, &value_int64);
+ }
+ }
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)GRN_BULK_HEAD(&buf);
+ if (value->header.type == GRN_DB_FLOAT) {
+ grn_rset_recinfo_set_avg(ctx, ri, a->obj, GRN_FLOAT_VALUE(value));
+ } else {
+ grn_obj value_float;
+ GRN_FLOAT_INIT(&value_float, 0);
+ if (!grn_obj_cast(ctx, value, &value_float, GRN_FALSE)) {
+ grn_rset_recinfo_set_avg(ctx, ri, a->obj,
+ GRN_FLOAT_VALUE(&value_float));
+ }
+ GRN_OBJ_FIN(ctx, &value_float);
+ }
+ }
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ /* todo : support vector */
+ if (a->next) {
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ vp = GRN_BULK_HEAD(&buf);
+ } else {
+ rc = grn_obj_set_value(ctx, a->obj, id, value, flags);
+ }
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ /* todo */
+ break;
+ }
+ if ((a = a->next)) {
+ id = *((grn_id *)vp);
+ } else {
+ break;
+ }
+ }
+ grn_obj_close(ctx, &buf);
+ }
+ return rc;
+}
+
+#define INCRDECR(op) \
+ switch (DB_OBJ(obj)->range) {\
+ case GRN_DB_INT8 :\
+ if (s == sizeof(int8_t)) {\
+ int8_t *vp = (int8_t *)p;\
+ *vp op *(int8_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_UINT8 :\
+ if (s == sizeof(uint8_t)) {\
+ uint8_t *vp = (uint8_t *)p;\
+ *vp op *(int8_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_INT16 :\
+ if (s == sizeof(int16_t)) {\
+ int16_t *vp = (int16_t *)p;\
+ *vp op *(int16_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_UINT16 :\
+ if (s == sizeof(uint16_t)) {\
+ uint16_t *vp = (uint16_t *)p;\
+ *vp op *(int16_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_INT32 :\
+ if (s == sizeof(int32_t)) {\
+ int32_t *vp = (int32_t *)p;\
+ *vp op *(int32_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_UINT32 :\
+ if (s == sizeof(uint32_t)) {\
+ uint32_t *vp = (uint32_t *)p;\
+ *vp op *(int32_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_INT64 :\
+ case GRN_DB_TIME :\
+ if (s == sizeof(int64_t)) {\
+ int64_t *vp = (int64_t *)p;\
+ *vp op *(int64_t *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ case GRN_DB_FLOAT :\
+ if (s == sizeof(double)) {\
+ double *vp = (double *)p;\
+ *vp op *(double *)v;\
+ rc = GRN_SUCCESS;\
+ } else {\
+ rc = GRN_INVALID_ARGUMENT;\
+ }\
+ break;\
+ default :\
+ rc = GRN_OPERATION_NOT_SUPPORTED;\
+ break;\
+ }
+
+uint32_t
+grn_obj_size(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) { return 0; }
+ switch (obj->header.type) {
+ case GRN_VOID :
+ case GRN_BULK :
+ case GRN_PTR :
+ case GRN_UVECTOR :
+ case GRN_PVECTOR :
+ case GRN_MSG :
+ return GRN_BULK_VSIZE(obj);
+ case GRN_VECTOR :
+ return obj->u.v.body ? GRN_BULK_VSIZE(obj->u.v.body) : 0;
+ default :
+ return 0;
+ }
+}
+
+inline static int
+call_hook(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value, int flags)
+{
+ grn_hook *hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET];
+ void *v = GRN_BULK_HEAD(value);
+ unsigned int s = grn_obj_size(ctx, value);
+ if (hooks || obj->header.type == GRN_COLUMN_VAR_SIZE) {
+ grn_obj oldbuf, *oldvalue;
+ GRN_TEXT_INIT(&oldbuf, 0);
+ oldvalue = grn_obj_get_value(ctx, obj, id, &oldbuf);
+ if (flags & GRN_OBJ_SET) {
+ void *ov;
+ unsigned int os;
+ ov = GRN_BULK_HEAD(oldvalue);
+ os = grn_obj_size(ctx, oldvalue);
+ if ((ov && v && os == s && !memcmp(ov, v, s)) &&
+ !(obj->header.type == GRN_COLUMN_FIX_SIZE &&
+ grn_bulk_is_zero(ctx, value))) {
+ grn_obj_close(ctx, oldvalue);
+ return 0;
+ }
+ }
+ if (hooks) {
+ // todo : grn_proc_ctx_open()
+ grn_obj id_, flags_;
+ grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4, {{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}}};
+ GRN_UINT32_INIT(&id_, 0);
+ GRN_UINT32_INIT(&flags_, 0);
+ GRN_UINT32_SET(ctx, &id_, id);
+ GRN_UINT32_SET(ctx, &flags_, flags);
+ while (hooks) {
+ grn_ctx_push(ctx, &id_);
+ grn_ctx_push(ctx, oldvalue);
+ grn_ctx_push(ctx, value);
+ grn_ctx_push(ctx, &flags_);
+ pctx.caller = NULL;
+ pctx.currh = hooks;
+ if (hooks->proc) {
+ hooks->proc->funcs[PROC_INIT](ctx, 1, &obj, &pctx.user_data);
+ } else {
+ grn_obj_default_set_value_hook(ctx, 1, &obj, &pctx.user_data);
+ }
+ if (ctx->rc) {
+ grn_obj_close(ctx, oldvalue);
+ return 1;
+ }
+ hooks = hooks->next;
+ pctx.offset++;
+ }
+ }
+ grn_obj_close(ctx, oldvalue);
+ }
+ return 0;
+}
+
+static grn_rc
+grn_obj_set_value_table_pat_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_id range = DB_OBJ(obj)->range;
+ void *v = GRN_BULK_HEAD(value);
+ grn_obj buf;
+
+ if (call_hook(ctx, obj, id, value, flags)) {
+ if (ctx->rc) {
+ rc = ctx->rc;
+ }
+ return rc;
+ }
+
+ if (range != value->header.domain) {
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
+ v = GRN_BULK_HEAD(&buf);
+ }
+ }
+ rc = grn_pat_set_value(ctx, (grn_pat *)obj, id, v, flags);
+ if (range != value->header.domain) {
+ grn_obj_close(ctx, &buf);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_table_hash_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_id range = DB_OBJ(obj)->range;
+ void *v = GRN_BULK_HEAD(value);
+ grn_obj buf;
+
+ if (call_hook(ctx, obj, id, value, flags)) {
+ if (ctx->rc) {
+ rc = ctx->rc;
+ }
+ return rc;
+ }
+
+ if (range != value->header.domain) {
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
+ v = GRN_BULK_HEAD(&buf);
+ }
+ }
+ rc = grn_hash_set_value(ctx, (grn_hash *)obj, id, v, flags);
+ if (range != value->header.domain) {
+ grn_obj_close(ctx, &buf);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_table_no_key(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_id range = DB_OBJ(obj)->range;
+ void *v = GRN_BULK_HEAD(value);
+ grn_obj buf;
+
+ if (call_hook(ctx, obj, id, value, flags)) {
+ if (ctx->rc) {
+ rc = ctx->rc;
+ }
+ return rc;
+ }
+
+ if (range != value->header.domain) {
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
+ v = GRN_BULK_HEAD(&buf);
+ }
+ }
+ rc = grn_array_set_value(ctx, (grn_array *)obj, id, v, flags);
+ if (range != value->header.domain) {
+ grn_obj_close(ctx, &buf);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_column_var_size_scalar(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_id range = DB_OBJ(obj)->range;
+ void *v = GRN_BULK_HEAD(value);
+ unsigned int s = grn_obj_size(ctx, value);
+ grn_obj buf;
+ grn_id buf_domain = GRN_DB_VOID;
+
+ if (call_hook(ctx, obj, id, value, flags)) {
+ if (ctx->rc) {
+ rc = ctx->rc;
+ }
+ return rc;
+ }
+
+ switch (flags & GRN_OBJ_SET_MASK) {
+ case GRN_OBJ_INCR :
+ case GRN_OBJ_DECR :
+ if (value->header.domain == GRN_DB_INT32 ||
+ value->header.domain == GRN_DB_INT64) {
+ /* do nothing */
+ } else if (GRN_DB_INT8 <= value->header.domain &&
+ value->header.domain < GRN_DB_INT32) {
+ buf_domain = GRN_DB_INT32;
+ } else {
+ buf_domain = GRN_DB_INT64;
+ }
+ break;
+ default :
+ if (range != value->header.domain) {
+ buf_domain = range;
+ }
+ break;
+ }
+
+ if (buf_domain != GRN_DB_VOID) {
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, buf_domain);
+ if (grn_obj_cast(ctx, value, &buf, GRN_TRUE) == GRN_SUCCESS) {
+ v = GRN_BULK_HEAD(&buf);
+ s = GRN_BULK_VSIZE(&buf);
+ }
+ }
+
+ rc = grn_ja_put(ctx, (grn_ja *)obj, id, v, s, flags, NULL);
+
+ if (buf_domain != GRN_DB_VOID) {
+ grn_obj_close(ctx, &buf);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_column_var_size_vector_uvector(grn_ctx *ctx, grn_obj *column,
+ grn_id id, grn_obj *value,
+ int flags)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj uvector;
+ grn_obj_flags uvector_flags = 0;
+ grn_bool need_convert = GRN_FALSE;
+ grn_bool need_cast = GRN_FALSE;
+ grn_id column_range_id;
+ void *raw_value;
+ unsigned int size;
+
+ if (column->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ if (!IS_WEIGHT_UVECTOR(value)) {
+ need_convert = GRN_TRUE;
+ }
+ } else {
+ if (IS_WEIGHT_UVECTOR(value)) {
+ need_convert = GRN_TRUE;
+ uvector_flags = GRN_OBJ_WITH_WEIGHT;
+ }
+ }
+ column_range_id = DB_OBJ(column)->range;
+ if (column_range_id != value->header.domain) {
+ need_convert = GRN_TRUE;
+ need_cast = GRN_TRUE;
+ }
+
+ if (need_convert) {
+ unsigned int i, n;
+
+ GRN_VALUE_FIX_SIZE_INIT(&uvector, GRN_OBJ_VECTOR, column_range_id);
+ uvector.header.flags |= uvector_flags;
+ n = grn_uvector_size(ctx, value);
+ if (need_cast) {
+ grn_obj value_record;
+ grn_obj casted_record;
+
+ GRN_VALUE_FIX_SIZE_INIT(&value_record, 0, value->header.domain);
+ GRN_VALUE_FIX_SIZE_INIT(&casted_record, 0, column_range_id);
+ for (i = 0; i < n; i++) {
+ grn_id id;
+ grn_id casted_id;
+ unsigned int weight = 0;
+
+ GRN_BULK_REWIND(&value_record);
+ GRN_BULK_REWIND(&casted_record);
+
+ id = grn_uvector_get_element(ctx, value, i, NULL);
+ GRN_RECORD_SET(ctx, &value_record, id);
+ rc = grn_obj_cast(ctx, &value_record, &casted_record, GRN_TRUE);
+ if (rc != GRN_SUCCESS) {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ grn_obj inspected;
+ column_name_size = grn_obj_name(ctx,
+ column,
+ column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, &value_record);
+ ERR(rc,
+ "[column][set-value] failed to cast: <%.*s>: <%.*s>",
+ column_name_size,
+ column_name,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ break;
+ }
+ casted_id = GRN_RECORD_VALUE(&casted_record);
+ grn_uvector_add_element(ctx, &uvector, casted_id, weight);
+ }
+
+ GRN_OBJ_FIN(ctx, &value_record);
+ GRN_OBJ_FIN(ctx, &casted_record);
+ } else {
+ for (i = 0; i < n; i++) {
+ grn_id id;
+ unsigned int weight = 0;
+ id = grn_uvector_get_element(ctx, value, i, NULL);
+ grn_uvector_add_element(ctx, &uvector, id, weight);
+ }
+ }
+ raw_value = GRN_BULK_HEAD(&uvector);
+ size = GRN_BULK_VSIZE(&uvector);
+ } else {
+ raw_value = GRN_BULK_HEAD(value);
+ size = GRN_BULK_VSIZE(value);
+ }
+
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ja_put(ctx, (grn_ja *)column, id, raw_value, size, flags, NULL);
+ }
+
+ if (need_convert) {
+ GRN_OBJ_FIN(ctx, &uvector);
+ }
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_column_var_size_vector(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_id range = DB_OBJ(obj)->range;
+ void *v = GRN_BULK_HEAD(value);
+ unsigned int s = grn_obj_size(ctx, value);
+ grn_obj *lexicon = grn_ctx_at(ctx, range);
+
+ if (call_hook(ctx, obj, id, value, flags)) {
+ if (ctx->rc) {
+ rc = ctx->rc;
+ }
+ return rc;
+ }
+
+ if (value->header.type == GRN_UVECTOR) {
+ rc = grn_obj_set_value_column_var_size_vector_uvector(ctx, obj,
+ id, value,
+ flags);
+ return rc;
+ }
+
+ if (GRN_OBJ_TABLEP(lexicon)) {
+ grn_obj uvector;
+ GRN_RECORD_INIT(&uvector, GRN_OBJ_VECTOR, range);
+ if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ uvector.header.flags |= GRN_OBJ_WITH_WEIGHT;
+ }
+ switch (value->header.type) {
+ case GRN_BULK :
+ {
+ unsigned int token_flags = 0;
+ grn_token_cursor *token_cursor;
+ if (v && s &&
+ (token_cursor = grn_token_cursor_open(ctx, lexicon, v, s,
+ GRN_TOKEN_ADD, token_flags))) {
+ while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
+ grn_id tid = grn_token_cursor_next(ctx, token_cursor);
+ grn_uvector_add_element(ctx, &uvector, tid, 0);
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ rc = grn_ja_put(ctx, (grn_ja *)obj, id,
+ GRN_BULK_HEAD(&uvector), GRN_BULK_VSIZE(&uvector),
+ flags, NULL);
+ }
+ break;
+ case GRN_VECTOR :
+ {
+ unsigned int n;
+ n = grn_vector_size(ctx, value);
+ if (n > 0) {
+ unsigned int i;
+ grn_obj value_buf, cast_buf;
+ GRN_OBJ_INIT(&value_buf, GRN_BULK, 0, GRN_DB_VOID);
+ GRN_OBJ_INIT(&cast_buf, GRN_BULK, 0, lexicon->header.domain);
+ for (i = 0; i < n; i++) {
+ grn_id tid;
+ const char *element;
+ unsigned int element_length;
+ unsigned int weight;
+ grn_id element_domain;
+
+ element_length = grn_vector_get_element(ctx, value, i,
+ &element, &weight,
+ &element_domain);
+ if (element_domain != lexicon->header.domain) {
+ GRN_BULK_REWIND(&cast_buf);
+ GRN_BULK_REWIND(&value_buf);
+ grn_bulk_write(ctx, &value_buf, element, element_length);
+ value_buf.header.domain = element_domain;
+ rc = grn_obj_cast(ctx, &value_buf, &cast_buf, GRN_TRUE);
+ if (rc) {
+ grn_obj *range_obj;
+ range_obj = grn_ctx_at(ctx, range);
+ ERR_CAST(obj, range_obj, &value_buf);
+ grn_obj_unlink(ctx, range_obj);
+ } else {
+ element = GRN_BULK_HEAD(&cast_buf);
+ element_length = GRN_BULK_VSIZE(&cast_buf);
+ }
+ } else {
+ rc = GRN_SUCCESS;
+ }
+ if (rc) {
+ continue;
+ }
+ tid = grn_table_add(ctx, lexicon, element, element_length, NULL);
+ grn_uvector_add_element(ctx, &uvector, tid, weight);
+ }
+ GRN_OBJ_FIN(ctx, &value_buf);
+ GRN_OBJ_FIN(ctx, &cast_buf);
+ }
+ }
+ rc = grn_ja_put(ctx, (grn_ja *)obj, id,
+ GRN_BULK_HEAD(&uvector), GRN_BULK_VSIZE(&uvector),
+ flags, NULL);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "vector, uvector or bulk required");
+ break;
+ }
+ grn_obj_close(ctx, &uvector);
+ } else {
+ switch (value->header.type) {
+ case GRN_BULK :
+ if (!GRN_BULK_VSIZE(value)) {
+ rc = grn_ja_put(ctx, (grn_ja *)obj, id, NULL, 0, flags, NULL);
+ } else {
+ grn_obj v;
+ GRN_OBJ_INIT(&v, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, GRN_DB_TEXT);
+ v.u.v.body = value;
+ grn_vector_delimit(ctx, &v, 0, GRN_ID_NIL);
+ rc = grn_ja_putv(ctx, (grn_ja *)obj, id, &v, 0);
+ grn_obj_close(ctx, &v);
+ }
+ break;
+ case GRN_VECTOR :
+ rc = grn_ja_putv(ctx, (grn_ja *)obj, id, value, 0);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "vector or bulk required");
+ break;
+ }
+ }
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_column_fix_size(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_id range = DB_OBJ(obj)->range;
+ void *v = GRN_BULK_HEAD(value);
+ unsigned int s = grn_obj_size(ctx, value);
+ grn_obj buf, *value_ = value;
+ uint32_t element_size = ((grn_ra *)obj)->header->element_size;
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ if (range != value->header.domain) {
+ rc = grn_obj_cast(ctx, value, &buf, GRN_TRUE);
+ if (rc) {
+ grn_obj *range_obj;
+ range_obj = grn_ctx_at(ctx, range);
+ ERR_CAST(obj, range_obj, value);
+ grn_obj_unlink(ctx, range_obj);
+ } else {
+ value_ = &buf;
+ v = GRN_BULK_HEAD(&buf);
+ s = GRN_BULK_VSIZE(&buf);
+ }
+ } else {
+ rc = GRN_SUCCESS;
+ }
+ if (rc) {
+ /* do nothing because it already has error. */
+ } else if (element_size < s) {
+ ERR(GRN_INVALID_ARGUMENT, "too long value (%d)", s);
+ } else {
+ void *p = grn_ra_ref(ctx, (grn_ra *)obj, id);
+ if (!p) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ return rc;
+ }
+ switch (flags & GRN_OBJ_SET_MASK) {
+ case GRN_OBJ_SET :
+ if (call_hook(ctx, obj, id, value_, flags)) {
+ if (ctx->rc) {
+ rc = ctx->rc;
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ grn_ra_unref(ctx, (grn_ra *)obj, id);
+ return rc;
+ }
+ if (element_size != s) {
+ if (!s) {
+ memset(p, 0, element_size);
+ } else {
+ void *b;
+ if ((b = GRN_CALLOC(element_size))) {
+ grn_memcpy(b, v, s);
+ grn_memcpy(p, b, element_size);
+ GRN_FREE(b);
+ }
+ }
+ } else {
+ grn_memcpy(p, v, s);
+ }
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_OBJ_INCR :
+ /* todo : support hook */
+ INCRDECR(+=);
+ break;
+ case GRN_OBJ_DECR :
+ /* todo : support hook */
+ INCRDECR(-=);
+ break;
+ default :
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ break;
+ }
+ grn_ra_unref(ctx, (grn_ra *)obj, id);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_value_column_index(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ column_name_size = grn_obj_name(ctx, obj, column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "can't set value to index column directly: <%.*s>",
+ column_name_size, column_name);
+ return ctx->rc;
+}
+
+grn_rc
+grn_obj_set_value(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_obj *value, int flags)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (!GRN_DB_OBJP(obj)) {
+ if (obj->header.type == GRN_ACCESSOR) {
+ rc = grn_accessor_set_value(ctx, (grn_accessor *)obj, id, value, flags);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "not db_obj");
+ }
+ } else {
+ switch (obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ rc = grn_obj_set_value_table_pat_key(ctx, obj, id, value, flags);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ break;
+ case GRN_TABLE_HASH_KEY :
+ rc = grn_obj_set_value_table_hash_key(ctx, obj, id, value, flags);
+ break;
+ case GRN_TABLE_NO_KEY :
+ rc = grn_obj_set_value_table_no_key(ctx, obj, id, value, flags);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_SCALAR :
+ rc = grn_obj_set_value_column_var_size_scalar(ctx, obj, id, value,
+ flags);
+ break;
+ case GRN_OBJ_COLUMN_VECTOR :
+ rc = grn_obj_set_value_column_var_size_vector(ctx, obj, id, value,
+ flags);
+ break;
+ default :
+ ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
+ break;
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ rc = grn_obj_set_value_column_fix_size(ctx, obj, id, value, flags);
+ break;
+ case GRN_COLUMN_INDEX :
+ rc = grn_obj_set_value_column_index(ctx, obj, id, value, flags);
+ break;
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+const char *
+grn_obj_get_value_(grn_ctx *ctx, grn_obj *obj, grn_id id, uint32_t *size)
+{
+ const char *value = NULL;
+ *size = 0;
+ switch (obj->header.type) {
+ case GRN_ACCESSOR :
+ value = grn_accessor_get_value_(ctx, (grn_accessor *)obj, id, size);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ value = grn_pat_get_value_(ctx, (grn_pat *)obj, id, size);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
+ break;
+ case GRN_TABLE_HASH_KEY :
+ value = grn_hash_get_value_(ctx, (grn_hash *)obj, id, size);
+ break;
+ case GRN_TABLE_NO_KEY :
+ if ((value = _grn_array_get_value(ctx, (grn_array *)obj, id))) {
+ *size = ((grn_array *)obj)->value_size;
+ }
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ {
+ grn_io_win jw;
+ if ((value = grn_ja_ref(ctx, (grn_ja *)obj, id, &jw, size))) {
+ grn_ja_unref(ctx, &jw);
+ }
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ if ((value = grn_ra_ref(ctx, (grn_ra *)obj, id))) {
+ grn_ra_unref(ctx, (grn_ra *)obj, id);
+ *size = ((grn_ra *)obj)->header->element_size;
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "todo: GRN_COLUMN_INDEX");
+ break;
+ }
+ return value;
+}
+
+static void
+grn_obj_get_value_expr(grn_ctx *ctx, grn_obj *expr, grn_id id, grn_obj *value)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *code;
+
+ if (e->codes_curr != 1) {
+ return;
+ }
+
+ code = e->codes;
+ if (code->op != GRN_OP_GET_VALUE) {
+ return;
+ }
+
+ if (!code->value) {
+ return;
+ }
+
+ switch (code->value->header.type) {
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ grn_obj_get_value(ctx, code->value, id, value);
+ break;
+ default :
+ break;
+ }
+}
+
+static void
+grn_obj_get_value_column_index(grn_ctx *ctx, grn_obj *index_column,
+ grn_id id, grn_obj *value)
+{
+ grn_ii *ii = (grn_ii *)index_column;
+ grn_obj_ensure_bulk(ctx, value);
+ if (id) {
+ GRN_UINT32_SET(ctx, value, grn_ii_estimate_size(ctx, ii, id));
+ } else {
+ GRN_UINT32_SET(ctx, value, 0);
+ }
+ value->header.domain = GRN_DB_UINT32;
+}
+
+static grn_obj *
+grn_obj_get_value_column_vector(grn_ctx *ctx, grn_obj *obj,
+ grn_id id, grn_obj *value)
+{
+ grn_obj *lexicon;
+
+ lexicon = grn_ctx_at(ctx, DB_OBJ(obj)->range);
+ if (lexicon && !GRN_OBJ_TABLEP(lexicon) &&
+ (lexicon->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
+ grn_obj_ensure_vector(ctx, value);
+ if (id) {
+ grn_obj v_;
+ GRN_TEXT_INIT(&v_, 0);
+ grn_ja_get_value(ctx, (grn_ja *)obj, id, &v_);
+ grn_vector_decode(ctx, value, GRN_TEXT_VALUE(&v_), GRN_TEXT_LEN(&v_));
+ GRN_OBJ_FIN(ctx, &v_);
+ }
+ } else {
+ grn_obj_ensure_bulk(ctx, value);
+ if (id) {
+ grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
+ }
+ value->header.type = GRN_UVECTOR;
+ if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ value->header.flags |= GRN_OBJ_WITH_WEIGHT;
+ } else {
+ value->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
+ }
+ }
+
+ return value;
+}
+
+grn_obj *
+grn_obj_get_value(grn_ctx *ctx, grn_obj *obj, grn_id id, grn_obj *value)
+{
+ GRN_API_ENTER;
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
+ goto exit;
+ }
+ if (!value) {
+ if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
+ goto exit;
+ }
+ }
+ switch (value->header.type) {
+ case GRN_VOID :
+ grn_obj_reinit(ctx, value, GRN_DB_TEXT, 0);
+ break;
+ case GRN_BULK :
+ case GRN_VECTOR :
+ case GRN_UVECTOR :
+ case GRN_MSG :
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
+ goto exit;
+ }
+ switch (obj->header.type) {
+ case GRN_ACCESSOR :
+ grn_obj_ensure_bulk(ctx, value);
+ value = grn_accessor_get_value(ctx, (grn_accessor *)obj, id, value);
+ break;
+ case GRN_EXPR :
+ grn_obj_get_value_expr(ctx, obj, id, value);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ {
+ grn_pat *pat = (grn_pat *)obj;
+ uint32_t size = pat->value_size;
+ grn_obj_ensure_bulk(ctx, value);
+ if (id) {
+ if (grn_bulk_space(ctx, value, size)) {
+ MERR("grn_bulk_space failed");
+ goto exit;
+ }
+ {
+ char *curr = GRN_BULK_CURR(value);
+ grn_pat_get_value(ctx, pat, id, curr - size);
+ }
+ }
+ value->header.type = GRN_BULK;
+ value->header.domain = grn_obj_get_range(ctx, obj);
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "GRN_TABLE_DAT_KEY not supported");
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_bool processed = GRN_FALSE;
+ grn_obj_ensure_bulk(ctx, value);
+ value->header.domain = grn_obj_get_range(ctx, obj);
+ if (id) {
+ if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(obj)) {
+ grn_obj *domain;
+ domain = grn_ctx_at(ctx, value->header.domain);
+ if (GRN_OBJ_TABLEP(domain)) {
+ grn_id subrec_id;
+ if (grn_table_get_subrecs(ctx, obj, id, &subrec_id, NULL, 1) == 1) {
+ GRN_RECORD_SET(ctx, value, subrec_id);
+ processed = GRN_TRUE;
+ }
+ }
+ }
+ if (!processed) {
+ grn_hash *hash = (grn_hash *)obj;
+ uint32_t size = hash->value_size;
+ if (grn_bulk_space(ctx, value, size)) {
+ MERR("grn_bulk_space failed");
+ goto exit;
+ }
+ {
+ char *curr = GRN_BULK_CURR(value);
+ grn_hash_get_value(ctx, hash, id, curr - size);
+ }
+ }
+ }
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ {
+ grn_array *array = (grn_array *)obj;
+ uint32_t size = array->value_size;
+ grn_obj_ensure_bulk(ctx, value);
+ if (id) {
+ if (grn_bulk_space(ctx, value, size)) {
+ MERR("grn_bulk_space failed");
+ goto exit;
+ }
+ {
+ char *curr = GRN_BULK_CURR(value);
+ grn_array_get_value(ctx, array, id, curr - size);
+ }
+ }
+ value->header.type = GRN_BULK;
+ value->header.domain = grn_obj_get_range(ctx, obj);
+ }
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_VECTOR :
+ grn_obj_get_value_column_vector(ctx, obj, id, value);
+ break;
+ case GRN_OBJ_COLUMN_SCALAR :
+ grn_obj_ensure_bulk(ctx, value);
+ if (id) {
+ grn_ja_get_value(ctx, (grn_ja *)obj, id, value);
+ }
+ value->header.type = GRN_BULK;
+ break;
+ default :
+ ERR(GRN_FILE_CORRUPT, "invalid GRN_OBJ_COLUMN_TYPE");
+ break;
+ }
+ value->header.domain = grn_obj_get_range(ctx, obj);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ grn_obj_ensure_bulk(ctx, value);
+ value->header.type = GRN_BULK;
+ value->header.domain = grn_obj_get_range(ctx, obj);
+ if (id) {
+ unsigned int element_size;
+ void *v = grn_ra_ref(ctx, (grn_ra *)obj, id);
+ if (v) {
+ element_size = ((grn_ra *)obj)->header->element_size;
+ grn_bulk_write(ctx, value, v, element_size);
+ grn_ra_unref(ctx, (grn_ra *)obj, id);
+ }
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ grn_obj_get_value_column_index(ctx, obj, id, value);
+ break;
+ }
+exit :
+ GRN_API_RETURN(value);
+}
+
+int
+grn_obj_get_values(grn_ctx *ctx, grn_obj *obj, grn_id offset, void **values)
+{
+ int nrecords = -1;
+ GRN_API_ENTER;
+ if (obj->header.type == GRN_COLUMN_FIX_SIZE) {
+ grn_obj *domain = grn_column_table(ctx, obj);
+ if (domain) {
+ int table_size = (int)grn_table_size(ctx, domain);
+ if (0 < offset && offset <= (grn_id) table_size) {
+ grn_ra *ra = (grn_ra *)obj;
+ void *p = grn_ra_ref(ctx, ra, offset);
+ if (p) {
+ if ((offset >> ra->element_width) == ((unsigned int) table_size >> ra->element_width)) {
+ nrecords = (table_size & ra->element_mask) + 1 - (offset & ra->element_mask);
+ } else {
+ nrecords = ra->element_mask + 1 - (offset & ra->element_mask);
+ }
+ if (values) { *values = p; }
+ grn_ra_unref(ctx, ra, offset);
+ } else {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "ra get failed");
+ }
+ } else {
+ nrecords = 0;
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "no domain found");
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "obj is not a fix sized column");
+ }
+ GRN_API_RETURN(nrecords);
+}
+
+grn_rc
+grn_column_index_update(grn_ctx *ctx, grn_obj *column,
+ grn_id id, unsigned int section,
+ grn_obj *oldvalue, grn_obj *newvalue)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (column->header.type != GRN_COLUMN_INDEX) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid column assigned");
+ } else {
+ rc = grn_ii_column_update(ctx, (grn_ii *)column, id, section, oldvalue, newvalue, NULL);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_obj *
+grn_column_table(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj *obj = NULL;
+ grn_db_obj *col = DB_OBJ(column);
+ GRN_API_ENTER;
+ if (col) {
+ obj = grn_ctx_at(ctx, col->header.domain);
+ }
+ GRN_API_RETURN(obj);
+}
+
+grn_obj *
+grn_obj_get_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *valuebuf)
+{
+ GRN_API_ENTER;
+ switch (type) {
+ case GRN_INFO_SUPPORT_ZLIB :
+ if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "failed to open value buffer for GRN_INFO_ZLIB_SUPPORT");
+ goto exit;
+ }
+#ifdef GRN_WITH_ZLIB
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
+#else
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
+#endif
+ break;
+ case GRN_INFO_SUPPORT_LZ4 :
+ if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "failed to open value buffer for GRN_INFO_LZ4_SUPPORT");
+ goto exit;
+ }
+#ifdef GRN_WITH_LZ4
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
+#else /* GRN_WITH_LZ4 */
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
+#endif /* GRN_WITH_LZ4 */
+ break;
+ case GRN_INFO_SUPPORT_ZSTD :
+ if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "failed to open value buffer for GRN_INFO_ZSTD_SUPPORT");
+ goto exit;
+ }
+#ifdef GRN_WITH_ZSTD
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
+#else /* GRN_WITH_ZSTD */
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
+#endif /* GRN_WITH_ZSTD */
+ break;
+ case GRN_INFO_SUPPORT_ARROW :
+ if (!valuebuf && !(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_BOOL))) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "failed to open value buffer for GRN_INFO_ARROW_SUPPORT");
+ goto exit;
+ }
+#ifdef GRN_WITH_ARROW
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_TRUE);
+#else /* GRN_WITH_ARROW */
+ GRN_BOOL_PUT(ctx, valuebuf, GRN_FALSE);
+#endif /* GRN_WITH_ARROW */
+ break;
+ default :
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
+ goto exit;
+ }
+ switch (type) {
+ case GRN_INFO_ENCODING :
+ if (!valuebuf) {
+ if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
+ goto exit;
+ }
+ }
+ {
+ grn_encoding enc;
+ if (obj->header.type == GRN_DB) { obj = ((grn_db *)obj)->keys; }
+ switch (obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ enc = ((grn_pat *)obj)->encoding;
+ grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
+ break;
+ case GRN_TABLE_DAT_KEY :
+ enc = ((grn_dat *)obj)->encoding;
+ grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
+ break;
+ case GRN_TABLE_HASH_KEY :
+ enc = ((grn_hash *)obj)->encoding;
+ grn_bulk_write(ctx, valuebuf, (const char *)&enc, sizeof(grn_encoding));
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
+ }
+ }
+ break;
+ case GRN_INFO_SOURCE :
+ if (!valuebuf) {
+ if (!(valuebuf = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_info failed");
+ goto exit;
+ }
+ }
+ if (!GRN_DB_OBJP(obj)) {
+ ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
+ goto exit;
+ }
+ grn_bulk_write(ctx, valuebuf, DB_OBJ(obj)->source, DB_OBJ(obj)->source_size);
+ break;
+ case GRN_INFO_DEFAULT_TOKENIZER :
+ switch (DB_OBJ(obj)->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ valuebuf = ((grn_hash *)obj)->tokenizer;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ valuebuf = ((grn_pat *)obj)->tokenizer;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ valuebuf = ((grn_dat *)obj)->tokenizer;
+ break;
+ }
+ break;
+ case GRN_INFO_NORMALIZER :
+ switch (DB_OBJ(obj)->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ valuebuf = ((grn_hash *)obj)->normalizer;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ valuebuf = ((grn_pat *)obj)->normalizer;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ valuebuf = ((grn_dat *)obj)->normalizer;
+ break;
+ }
+ break;
+ case GRN_INFO_TOKEN_FILTERS :
+ if (!valuebuf) {
+ if (!(valuebuf = grn_obj_open(ctx, GRN_PVECTOR, 0, 0))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "grn_obj_get_info: failed to allocate value buffer");
+ goto exit;
+ }
+ }
+ {
+ grn_obj *token_filters = NULL;
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ token_filters = &(((grn_hash *)obj)->token_filters);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ token_filters = &(((grn_pat *)obj)->token_filters);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ token_filters = &(((grn_dat *)obj)->token_filters);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT,
+ /* TODO: Show type name instead of type ID */
+ "[info][get][token-filters] target object must be one of "
+ "GRN_TABLE_HASH_KEY, GRN_TABLE_PAT_KEY and GRN_TABLE_DAT_KEY: %d",
+ obj->header.type);
+ break;
+ }
+ if (token_filters) {
+ grn_bulk_write(ctx,
+ valuebuf,
+ GRN_BULK_HEAD(token_filters),
+ GRN_BULK_VSIZE(token_filters));
+ }
+ }
+ break;
+ default :
+ /* todo */
+ break;
+ }
+ }
+exit :
+ GRN_API_RETURN(valuebuf);
+}
+
+static void
+update_source_hook(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_id *s = DB_OBJ(obj)->source;
+ int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
+ grn_obj_default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
+ grn_obj *source, data;
+ GRN_TEXT_INIT(&data, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
+ for (i = 1; i <= n; i++, s++) {
+ hook_data.section = i;
+ if ((source = grn_ctx_at(ctx, *s))) {
+ switch (source->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ grn_obj_add_hook(ctx, source, GRN_HOOK_INSERT, 0, NULL, &data);
+ grn_obj_add_hook(ctx, source, GRN_HOOK_DELETE, 0, NULL, &data);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ grn_obj_add_hook(ctx, source, GRN_HOOK_SET, 0, NULL, &data);
+ break;
+ default :
+ /* invalid target */
+ break;
+ }
+ }
+ }
+ grn_obj_close(ctx, &data);
+}
+
+static void
+del_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, grn_obj *hld)
+{
+ int i;
+ void *hld_value = NULL;
+ uint32_t hld_size = 0;
+ grn_hook **last;
+ hld_value = GRN_BULK_HEAD(hld);
+ hld_size = GRN_BULK_VSIZE(hld);
+ if (!hld_size) { return; }
+ for (i = 0, last = &DB_OBJ(obj)->hooks[entry]; *last; i++, last = &(*last)->next) {
+ if (!memcmp(GRN_NEXT_ADDR(*last), hld_value, hld_size)) {
+ grn_obj_delete_hook(ctx, obj, entry, i);
+ return;
+ }
+ }
+}
+
+static void
+delete_source_hook(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_id *s = DB_OBJ(obj)->source;
+ int i, n = DB_OBJ(obj)->source_size / sizeof(grn_id);
+ grn_obj_default_set_value_hook_data hook_data = { DB_OBJ(obj)->id, 0 };
+ grn_obj *source, data;
+ GRN_TEXT_INIT(&data, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&data, &hook_data, sizeof(hook_data));
+ for (i = 1; i <= n; i++, s++) {
+ hook_data.section = i;
+
+ source = grn_ctx_at(ctx, *s);
+ if (!source) {
+ ERRCLR(ctx);
+ continue;
+ }
+
+ switch (source->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ del_hook(ctx, source, GRN_HOOK_INSERT, &data);
+ del_hook(ctx, source, GRN_HOOK_DELETE, &data);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ del_hook(ctx, source, GRN_HOOK_SET, &data);
+ break;
+ default :
+ /* invalid target */
+ break;
+ }
+ }
+ grn_obj_close(ctx, &data);
+}
+
+#define N_HOOK_ENTRIES 5
+
+grn_rc
+grn_hook_pack(grn_ctx *ctx, grn_db_obj *obj, grn_obj *buf)
+{
+ grn_rc rc;
+ grn_hook_entry e;
+ for (e = 0; e < N_HOOK_ENTRIES; e++) {
+ grn_hook *hooks;
+ for (hooks = obj->hooks[e]; hooks; hooks = hooks->next) {
+ grn_id id = hooks->proc ? hooks->proc->obj.id : 0;
+ if ((rc = grn_text_benc(ctx, buf, id + 1))) { goto exit; }
+ if ((rc = grn_text_benc(ctx, buf, hooks->hld_size))) { goto exit; }
+ if ((rc = grn_bulk_write(ctx, buf, (char *)GRN_NEXT_ADDR(hooks), hooks->hld_size))) { goto exit; }
+ }
+ if ((rc = grn_text_benc(ctx, buf, 0))) { goto exit; }
+ }
+exit :
+ return rc;
+}
+
+static grn_rc
+grn_hook_unpack(grn_ctx *ctx, grn_db_obj *obj, const char *buf, uint32_t buf_size)
+{
+ grn_hook_entry e;
+ const uint8_t *p = (uint8_t *)buf, *pe = p + buf_size;
+ for (e = 0; e < N_HOOK_ENTRIES; e++) {
+ grn_hook *new, **last = &obj->hooks[e];
+ for (;;) {
+ grn_id id;
+ uint32_t hld_size;
+ GRN_B_DEC(id, p);
+ if (!id--) { break; }
+ if (p >= pe) { return GRN_FILE_CORRUPT; }
+ GRN_B_DEC(hld_size, p);
+ if (p >= pe) { return GRN_FILE_CORRUPT; }
+ if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (id) {
+ new->proc = (grn_proc *)grn_ctx_at(ctx, id);
+ if (!new->proc) {
+ GRN_FREE(new);
+ return ctx->rc;
+ }
+ } else {
+ new->proc = NULL;
+ }
+ if ((new->hld_size = hld_size)) {
+ grn_memcpy(GRN_NEXT_ADDR(new), p, hld_size);
+ p += hld_size;
+ }
+ *last = new;
+ last = &new->next;
+ if (p >= pe) { return GRN_FILE_CORRUPT; }
+ }
+ *last = NULL;
+ }
+ return GRN_SUCCESS;
+}
+
+static void
+grn_token_filters_pack(grn_ctx *ctx,
+ grn_obj *token_filters,
+ grn_obj *buffer)
+{
+ unsigned int i, n_token_filters;
+
+ n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
+ for (i = 0; i < n_token_filters; i++) {
+ grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
+ grn_id token_filter_id;
+
+ token_filter_id = grn_obj_id(ctx, token_filter);
+ GRN_RECORD_PUT(ctx, buffer, token_filter_id);
+ }
+}
+
+static grn_bool
+grn_obj_encoded_spec_equal(grn_ctx *ctx,
+ grn_obj *encoded_spec1,
+ grn_obj *encoded_spec2)
+{
+ unsigned int i, n_elements;
+
+ if (encoded_spec1->header.type != GRN_VECTOR) {
+ return GRN_FALSE;
+ }
+
+ if (encoded_spec1->header.type != encoded_spec2->header.type) {
+ return GRN_FALSE;
+ }
+
+ n_elements = grn_vector_size(ctx, encoded_spec1);
+ if (grn_vector_size(ctx, encoded_spec2) != n_elements) {
+ return GRN_FALSE;
+ }
+
+ for (i = 0; i < n_elements; i++) {
+ const char *content1;
+ const char *content2;
+ unsigned int content_size1;
+ unsigned int content_size2;
+ unsigned int weight1;
+ unsigned int weight2;
+ grn_id domain1;
+ grn_id domain2;
+
+ content_size1 = grn_vector_get_element(ctx,
+ encoded_spec1,
+ i,
+ &content1,
+ &weight1,
+ &domain1);
+ content_size2 = grn_vector_get_element(ctx,
+ encoded_spec2,
+ i,
+ &content2,
+ &weight2,
+ &domain2);
+ if (content_size1 != content_size2) {
+ return GRN_FALSE;
+ }
+ if (memcmp(content1, content2, content_size1) != 0) {
+ return GRN_FALSE;
+ }
+ if (weight1 != weight2) {
+ return GRN_FALSE;
+ }
+ if (domain1 != domain2) {
+ return GRN_FALSE;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+void
+grn_obj_spec_save(grn_ctx *ctx, grn_db_obj *obj)
+{
+ grn_db *s;
+ grn_obj v, *b;
+ grn_obj_spec spec;
+ grn_bool need_update = GRN_TRUE;
+
+ if (obj->id & GRN_OBJ_TMP_OBJECT) { return; }
+ if (!ctx->impl || !GRN_DB_OBJP(obj)) { return; }
+ if (!(s = (grn_db *)ctx->impl->db) || !s->specs) { return; }
+ if (obj->header.type == GRN_PROC && obj->range == GRN_ID_NIL) {
+ return;
+ }
+ GRN_OBJ_INIT(&v, GRN_VECTOR, 0, GRN_DB_TEXT);
+ if (!(b = grn_vector_body(ctx, &v))) { return; }
+ spec.header = obj->header;
+ spec.range = obj->range;
+ grn_bulk_write(ctx, b, (void *)&spec, sizeof(grn_obj_spec));
+ grn_vector_delimit(ctx, &v, 0, 0);
+ if (obj->header.flags & GRN_OBJ_CUSTOM_NAME) {
+ GRN_TEXT_PUTS(ctx, b, grn_obj_path(ctx, (grn_obj *)obj));
+ }
+ grn_vector_delimit(ctx, &v, 0, 0);
+ grn_bulk_write(ctx, b, obj->source, obj->source_size);
+ grn_vector_delimit(ctx, &v, 0, 0);
+ grn_hook_pack(ctx, obj, b);
+ grn_vector_delimit(ctx, &v, 0, 0);
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ grn_token_filters_pack(ctx, &(((grn_hash *)obj)->token_filters), b);
+ grn_vector_delimit(ctx, &v, 0, 0);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ grn_token_filters_pack(ctx, &(((grn_pat *)obj)->token_filters), b);
+ grn_vector_delimit(ctx, &v, 0, 0);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ grn_token_filters_pack(ctx, &(((grn_dat *)obj)->token_filters), b);
+ grn_vector_delimit(ctx, &v, 0, 0);
+ break;
+ case GRN_EXPR :
+ grn_expr_pack(ctx, b, (grn_obj *)obj);
+ grn_vector_delimit(ctx, &v, 0, 0);
+ break;
+ }
+
+ {
+ grn_io_win jw;
+ uint32_t current_spec_raw_len;
+ char *current_spec_raw;
+
+ current_spec_raw = grn_ja_ref(ctx,
+ s->specs,
+ obj->id,
+ &jw,
+ &current_spec_raw_len);
+ if (current_spec_raw) {
+ grn_rc rc;
+ grn_obj current_spec;
+
+ GRN_OBJ_INIT(&current_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
+ rc = grn_vector_decode(ctx,
+ &current_spec,
+ current_spec_raw,
+ current_spec_raw_len);
+ if (rc == GRN_SUCCESS) {
+ need_update = !grn_obj_encoded_spec_equal(ctx, &v, &current_spec);
+ }
+ GRN_OBJ_FIN(ctx, &current_spec);
+ grn_ja_unref(ctx, &jw);
+ }
+ }
+
+ if (!need_update) {
+ grn_obj_close(ctx, &v);
+ return;
+ }
+
+ {
+ const char *name;
+ uint32_t name_size = 0;
+ const char *range_name = NULL;
+ uint32_t range_name_size = 0;
+
+ name = _grn_table_key(ctx, s->keys, obj->id, &name_size);
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ if (obj->range != GRN_ID_NIL) {
+ range_name = _grn_table_key(ctx, s->keys, obj->range, &range_name_size);
+ }
+ break;
+ default :
+ break;
+ }
+ /* TODO: reduce log level. */
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "spec:%u:update:%.*s:%u(%s):%u%s%.*s%s",
+ obj->id,
+ name_size, name,
+ obj->header.type,
+ grn_obj_type_to_string(obj->header.type),
+ obj->range,
+ range_name_size == 0 ? "" : "(",
+ range_name_size, range_name,
+ range_name_size == 0 ? "" : ")");
+ }
+ grn_ja_putv(ctx, s->specs, obj->id, &v, 0);
+ grn_obj_close(ctx, &v);
+}
+
+inline static void
+grn_obj_set_info_source_invalid_lexicon_error(grn_ctx *ctx,
+ const char *message,
+ grn_obj *actual_type,
+ grn_obj *expected_type,
+ grn_obj *index_column,
+ grn_obj *source)
+{
+ char actual_type_name[GRN_TABLE_MAX_KEY_SIZE];
+ int actual_type_name_size;
+ char expected_type_name[GRN_TABLE_MAX_KEY_SIZE];
+ int expected_type_name_size;
+ char index_column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_column_name_size;
+ char source_name[GRN_TABLE_MAX_KEY_SIZE];
+ int source_name_size;
+
+ actual_type_name_size = grn_obj_name(ctx, actual_type,
+ actual_type_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ expected_type_name_size = grn_obj_name(ctx, expected_type,
+ expected_type_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ index_column_name_size = grn_obj_name(ctx, index_column,
+ index_column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+
+ source_name_size = grn_obj_name(ctx, source,
+ source_name, GRN_TABLE_MAX_KEY_SIZE);
+ if (grn_obj_is_table(ctx, source)) {
+ source_name[source_name_size] = '\0';
+ grn_strncat(source_name,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "._key",
+ GRN_TABLE_MAX_KEY_SIZE - source_name_size - 1);
+ source_name_size = strlen(source_name);
+ }
+
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][index][source] %s: "
+ "<%.*s> -> <%.*s>: "
+ "index-column:<%.*s> "
+ "source:<%.*s>",
+ message,
+ actual_type_name_size, actual_type_name,
+ expected_type_name_size, expected_type_name,
+ index_column_name_size, index_column_name,
+ source_name_size, source_name);
+}
+
+inline static grn_rc
+grn_obj_set_info_source_validate(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
+{
+ grn_id lexicon_id;
+ grn_obj *lexicon = NULL;
+ grn_id lexicon_domain_id;
+ grn_obj *lexicon_domain = NULL;
+ grn_bool lexicon_domain_is_table;
+ grn_bool lexicon_have_tokenizer;
+ grn_id *source_ids;
+ int i, n_source_ids;
+
+ lexicon_id = obj->header.domain;
+ lexicon = grn_ctx_at(ctx, lexicon_id);
+ if (!lexicon) {
+ goto exit;
+ }
+
+ lexicon_domain_id = lexicon->header.domain;
+ lexicon_domain = grn_ctx_at(ctx, lexicon_domain_id);
+ if (!lexicon_domain) {
+ goto exit;
+ }
+
+ source_ids = (grn_id *)GRN_BULK_HEAD(value);
+ n_source_ids = GRN_BULK_VSIZE(value) / sizeof(grn_id);
+ if (n_source_ids > 1 && !(obj->header.flags & GRN_OBJ_WITH_SECTION)) {
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+ index_name_size = grn_obj_name(ctx, obj,
+ index_name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "grn_obj_set_info(): GRN_INFO_SOURCE: "
+ "multi column index must be created with WITH_SECTION flag: <%.*s>",
+ index_name_size, index_name);
+ goto exit;
+ }
+
+ lexicon_domain_is_table = grn_obj_is_table(ctx, lexicon_domain);
+ {
+ grn_obj *tokenizer;
+ grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
+ lexicon_have_tokenizer = (tokenizer != NULL);
+ }
+
+ for (i = 0; i < n_source_ids; i++) {
+ grn_id source_id = source_ids[i];
+ grn_obj *source;
+ grn_id source_type_id;
+ grn_obj *source_type;
+
+ source = grn_ctx_at(ctx, source_id);
+ if (!source) {
+ continue;
+ }
+ if (grn_obj_is_table(ctx, source)) {
+ source_type_id = source->header.domain;
+ } else {
+ source_type_id = DB_OBJ(source)->range;
+ }
+ source_type = grn_ctx_at(ctx, source_type_id);
+ if (!lexicon_have_tokenizer) {
+ if (grn_obj_is_table(ctx, source_type)) {
+ if (lexicon_id != source_type_id) {
+ grn_obj_set_info_source_invalid_lexicon_error(
+ ctx,
+ "index table must equal to source type",
+ lexicon,
+ source_type,
+ obj,
+ source);
+ }
+ } else {
+ if (!(lexicon_domain_id == source_type_id ||
+ (grn_type_id_is_text_family(ctx, lexicon_domain_id) &&
+ grn_type_id_is_text_family(ctx, source_type_id)))) {
+ grn_obj_set_info_source_invalid_lexicon_error(
+ ctx,
+ "index table's key must equal source type",
+ lexicon_domain,
+ source_type,
+ obj,
+ source);
+ }
+ }
+ }
+ grn_obj_unlink(ctx, source);
+ if (ctx->rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ }
+
+exit:
+ if (lexicon) {
+ grn_obj_unlink(ctx, lexicon);
+ }
+ if (lexicon_domain) {
+ grn_obj_unlink(ctx, lexicon_domain);
+ }
+ return ctx->rc;
+}
+
+inline static void
+grn_obj_set_info_source_log(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
+{
+ grn_obj buf;
+ grn_id *vp = (grn_id *)GRN_BULK_HEAD(value);
+ uint32_t vs = GRN_BULK_VSIZE(value), s = 0;
+ grn_id id;
+ const char *n;
+
+ id = DB_OBJ(obj)->id;
+ n = _grn_table_key(ctx, ctx->impl->db, id, &s);
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUT(ctx, &buf, n, s);
+ GRN_TEXT_PUTC(ctx, &buf, ' ');
+ while (vs) {
+ n = _grn_table_key(ctx, ctx->impl->db, *vp++, &s);
+ GRN_TEXT_PUT(ctx, &buf, n, s);
+ vs -= sizeof(grn_id);
+ if (vs) { GRN_TEXT_PUTC(ctx, &buf, ','); }
+ }
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "DDL:%u:set_source %.*s",
+ id,
+ (int)GRN_BULK_VSIZE(&buf), GRN_BULK_HEAD(&buf));
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+inline static grn_rc
+grn_obj_set_info_source_update(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
+{
+ void *v = GRN_BULK_HEAD(value);
+ uint32_t s = GRN_BULK_VSIZE(value);
+ if (s) {
+ void *v2 = GRN_MALLOC(s);
+ if (!v2) {
+ return ctx->rc;
+ }
+ grn_memcpy(v2, v, s);
+ if (DB_OBJ(obj)->source) { GRN_FREE(DB_OBJ(obj)->source); }
+ DB_OBJ(obj)->source = v2;
+ DB_OBJ(obj)->source_size = s;
+
+ if (obj->header.type == GRN_COLUMN_INDEX) {
+ update_source_hook(ctx, obj);
+ grn_index_column_build(ctx, obj);
+ }
+ } else {
+ DB_OBJ(obj)->source = NULL;
+ DB_OBJ(obj)->source_size = 0;
+ }
+
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_obj_set_info_source(grn_ctx *ctx, grn_obj *obj, grn_obj *value)
+{
+ grn_rc rc;
+
+ rc = grn_obj_set_info_source_validate(ctx, obj, value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ grn_obj_set_info_source_log(ctx, obj, value);
+ rc = grn_obj_set_info_source_update(ctx, obj, value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ grn_obj_spec_save(ctx, DB_OBJ(obj));
+
+ return rc;
+}
+
+static grn_rc
+grn_obj_set_info_token_filters(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *token_filters)
+{
+ grn_obj *current_token_filters;
+ unsigned int i, n_current_token_filters, n_token_filters;
+ grn_obj token_filter_names;
+
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ current_token_filters = &(((grn_hash *)table)->token_filters);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ current_token_filters = &(((grn_pat *)table)->token_filters);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ current_token_filters = &(((grn_dat *)table)->token_filters);
+ break;
+ default :
+ /* TODO: Show type name instead of type ID */
+ ERR(GRN_INVALID_ARGUMENT,
+ "[info][set][token-filters] target object must be one of "
+ "GRN_TABLE_HASH_KEY, GRN_TABLE_PAT_KEY and GRN_TABLE_DAT_KEY: %d",
+ table->header.type);
+ return ctx->rc;
+ }
+
+ n_current_token_filters =
+ GRN_BULK_VSIZE(current_token_filters) / sizeof(grn_obj *);
+ n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
+
+ GRN_TEXT_INIT(&token_filter_names, 0);
+ GRN_BULK_REWIND(current_token_filters);
+ for (i = 0; i < n_token_filters; i++) {
+ grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
+ char token_filter_name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int token_filter_name_size;
+
+ GRN_PTR_PUT(ctx, current_token_filters, token_filter);
+
+ if (i > 0) {
+ GRN_TEXT_PUTC(ctx, &token_filter_names, ',');
+ }
+ token_filter_name_size = grn_obj_name(ctx,
+ token_filter,
+ token_filter_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_PUT(ctx,
+ &token_filter_names,
+ token_filter_name,
+ token_filter_name_size);
+ }
+ if (n_token_filters > 0 || n_token_filters != n_current_token_filters) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:%u:set_token_filters %.*s",
+ DB_OBJ(table)->id,
+ (int)GRN_BULK_VSIZE(&token_filter_names),
+ GRN_BULK_HEAD(&token_filter_names));
+ }
+ GRN_OBJ_FIN(ctx, &token_filter_names);
+ grn_obj_spec_save(ctx, DB_OBJ(table));
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_obj_set_info(grn_ctx *ctx, grn_obj *obj, grn_info_type type, grn_obj *value)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_set_info failed");
+ goto exit;
+ }
+ switch (type) {
+ case GRN_INFO_SOURCE :
+ if (!GRN_DB_OBJP(obj)) {
+ ERR(GRN_INVALID_ARGUMENT, "only db_obj can accept GRN_INFO_SOURCE");
+ goto exit;
+ }
+ rc = grn_obj_set_info_source(ctx, obj, value);
+ break;
+ case GRN_INFO_DEFAULT_TOKENIZER :
+ if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
+ switch (DB_OBJ(obj)->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ ((grn_hash *)obj)->tokenizer = value;
+ ((grn_hash *)obj)->header.common->tokenizer = grn_obj_id(ctx, value);
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ ((grn_pat *)obj)->tokenizer = value;
+ ((grn_pat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ ((grn_dat *)obj)->tokenizer = value;
+ ((grn_dat *)obj)->header->tokenizer = grn_obj_id(ctx, value);
+ rc = GRN_SUCCESS;
+ break;
+ }
+ }
+ break;
+ case GRN_INFO_NORMALIZER :
+ if (!value || DB_OBJ(value)->header.type == GRN_PROC) {
+ switch (DB_OBJ(obj)->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ ((grn_hash *)obj)->normalizer = value;
+ ((grn_hash *)obj)->header.common->normalizer = grn_obj_id(ctx, value);
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ ((grn_pat *)obj)->normalizer = value;
+ ((grn_pat *)obj)->header->normalizer = grn_obj_id(ctx, value);
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ ((grn_dat *)obj)->normalizer = value;
+ ((grn_dat *)obj)->header->normalizer = grn_obj_id(ctx, value);
+ rc = GRN_SUCCESS;
+ break;
+ }
+ }
+ break;
+ case GRN_INFO_TOKEN_FILTERS :
+ rc = grn_obj_set_info_token_filters(ctx, obj, value);
+ break;
+ default :
+ /* todo */
+ break;
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_obj *
+grn_obj_get_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_info_type type, grn_obj *valuebuf)
+{
+ GRN_API_ENTER;
+ GRN_API_RETURN(valuebuf);
+}
+
+grn_rc
+grn_obj_set_element_info(grn_ctx *ctx, grn_obj *obj, grn_id id,
+ grn_info_type type, grn_obj *value)
+{
+ GRN_API_ENTER;
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+static void
+grn_hook_free(grn_ctx *ctx, grn_hook *h)
+{
+ grn_hook *curr, *next;
+ for (curr = h; curr; curr = next) {
+ next = curr->next;
+ GRN_FREE(curr);
+ }
+}
+
+grn_rc
+grn_obj_add_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
+ int offset, grn_obj *proc, grn_obj *hld)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ if (!GRN_DB_OBJP(obj)) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ int i;
+ void *hld_value = NULL;
+ uint32_t hld_size = 0;
+ grn_hook *new, **last = &DB_OBJ(obj)->hooks[entry];
+ if (hld) {
+ hld_value = GRN_BULK_HEAD(hld);
+ hld_size = GRN_BULK_VSIZE(hld);
+ }
+ if (!(new = GRN_MALLOC(sizeof(grn_hook) + hld_size))) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ new->proc = (grn_proc *)proc;
+ new->hld_size = hld_size;
+ if (hld_size) {
+ grn_memcpy(GRN_NEXT_ADDR(new), hld_value, hld_size);
+ }
+ for (i = 0; i != offset && *last; i++) { last = &(*last)->next; }
+ new->next = *last;
+ *last = new;
+ grn_obj_spec_save(ctx, DB_OBJ(obj));
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+int
+grn_obj_get_nhooks(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
+{
+ int res = 0;
+ GRN_API_ENTER;
+ {
+ grn_hook *hook = DB_OBJ(obj)->hooks[entry];
+ while (hook) {
+ res++;
+ hook = hook->next;
+ }
+ }
+ GRN_API_RETURN(res);
+}
+
+grn_obj *
+grn_obj_get_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry,
+ int offset, grn_obj *hldbuf)
+{
+ grn_obj *res = NULL;
+ GRN_API_ENTER;
+ {
+ int i;
+ grn_hook *hook = DB_OBJ(obj)->hooks[entry];
+ for (i = 0; i < offset; i++) {
+ hook = hook->next;
+ if (!hook) { return NULL; }
+ }
+ res = (grn_obj *)hook->proc;
+ grn_bulk_write(ctx, hldbuf, (char *)GRN_NEXT_ADDR(hook), hook->hld_size);
+ }
+ GRN_API_RETURN(res);
+}
+
+grn_rc
+grn_obj_delete_hook(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry, int offset)
+{
+ GRN_API_ENTER;
+ {
+ int i = 0;
+ grn_hook *h, **last = &DB_OBJ(obj)->hooks[entry];
+ for (;;) {
+ if (!(h = *last)) { return GRN_INVALID_ARGUMENT; }
+ if (++i > offset) { break; }
+ last = &h->next;
+ }
+ *last = h->next;
+ GRN_FREE(h);
+ }
+ grn_obj_spec_save(ctx, DB_OBJ(obj));
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+static grn_rc
+remove_index(grn_ctx *ctx, grn_obj *obj, grn_hook_entry entry)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_hook *h0, *hooks = DB_OBJ(obj)->hooks[entry];
+ DB_OBJ(obj)->hooks[entry] = NULL; /* avoid mutual recursive call */
+ while (hooks) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (!target) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int length;
+ char hook_name[GRN_TABLE_MAX_KEY_SIZE];
+ int hook_name_length;
+
+ length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
+ hook_name_length = grn_table_get_key(ctx,
+ ctx->impl->db,
+ data->target,
+ hook_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "[column][remove][index] "
+ "hook has a dangling reference: <%.*s> -> <%.*s>",
+ length, name,
+ hook_name_length, hook_name);
+ rc = ctx->rc;
+ } else if (target->header.type == GRN_COLUMN_INDEX) {
+ //TODO: multicolumn MULTI_COLUMN_INDEXP
+ rc = _grn_obj_remove(ctx, target, GRN_FALSE);
+ } else {
+ //TODO: err
+ char fn[GRN_TABLE_MAX_KEY_SIZE];
+ int flen;
+ flen = grn_obj_name(ctx, target, fn, GRN_TABLE_MAX_KEY_SIZE);
+ fn[flen] = '\0';
+ ERR(GRN_UNKNOWN_ERROR, "column has unsupported hooks, col=%s",fn);
+ rc = ctx->rc;
+ }
+ if (rc != GRN_SUCCESS) {
+ DB_OBJ(obj)->hooks[entry] = hooks;
+ break;
+ }
+ h0 = hooks;
+ hooks = hooks->next;
+ GRN_FREE(h0);
+ }
+ return rc;
+}
+
+static grn_rc
+remove_columns(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_hash *cols;
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
+ GRN_HASH_EACH_BEGIN(ctx, cols, cursor, id) {
+ grn_id *key;
+ grn_obj *col;
+
+ grn_hash_cursor_get_key(ctx, cursor, (void **)&key);
+ col = grn_ctx_at(ctx, *key);
+
+ if (!col) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_table_get_key(ctx, ctx->impl->db, *key,
+ name, GRN_TABLE_MAX_KEY_SIZE);
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[object][remove] column is broken: <%.*s>",
+ name_size, name);
+ } else {
+ ERR(ctx->rc,
+ "[object][remove] column is broken: <%.*s>: %s",
+ name_size, name,
+ ctx->errbuf);
+ }
+ rc = ctx->rc;
+ break;
+ }
+
+ rc = _grn_obj_remove(ctx, col, GRN_FALSE);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, col);
+ break;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+ grn_hash_close(ctx, cols);
+ }
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_db_index_columns(grn_ctx *ctx, grn_obj *db)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *obj = grn_ctx_at(ctx, id);
+ if (obj && obj->header.type == GRN_COLUMN_INDEX) {
+ rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, obj);
+ break;
+ }
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_db_reference_columns(grn_ctx *ctx, grn_obj *db)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *obj = grn_ctx_at(ctx, id);
+ grn_obj *range = NULL;
+
+ if (!obj) {
+ continue;
+ }
+
+ switch (obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ if (!DB_OBJ(obj)->range) {
+ break;
+ }
+
+ range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
+ if (!range) {
+ break;
+ }
+
+ switch (range->header.type) {
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
+ break;
+ }
+ break;
+ }
+
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_db_reference_tables(grn_ctx *ctx, grn_obj *db)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *obj = grn_ctx_at(ctx, id);
+ grn_obj *domain = NULL;
+
+ if (!obj) {
+ continue;
+ }
+
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ if (!obj->header.domain) {
+ break;
+ }
+
+ domain = grn_ctx_at(ctx, obj->header.domain);
+ if (!domain) {
+ break;
+ }
+
+ switch (domain->header.type) {
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
+ break;
+ }
+ break;
+ }
+
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_db_all_tables(grn_ctx *ctx, grn_obj *db)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *obj = grn_ctx_at(ctx, id);
+
+ if (!obj) {
+ continue;
+ }
+
+ switch (obj->header.type) {
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
+ break;
+ }
+
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_db(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path)
+{
+ grn_rc rc = GRN_SUCCESS;
+ const char *io_spath;
+ char *spath;
+ grn_db *s = (grn_db *)db;
+ unsigned char key_type;
+
+ rc = _grn_obj_remove_db_index_columns(ctx, db);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_db_reference_columns(ctx, db);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_db_reference_tables(ctx, db);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_db_all_tables(ctx, db);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (s->specs &&
+ (io_spath = grn_obj_path(ctx, (grn_obj *)s->specs)) && *io_spath != '\0') {
+ if (!(spath = GRN_STRDUP(io_spath))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_spath);
+ return ctx->rc;
+ }
+ } else {
+ spath = NULL;
+ }
+
+ key_type = s->keys->header.type;
+
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) {
+ if (spath) {
+ GRN_FREE(spath);
+ }
+ return rc;
+ }
+
+ if (spath) {
+ rc = grn_ja_remove(ctx, spath);
+ GRN_FREE(spath);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ if (path) {
+ switch (key_type) {
+ case GRN_TABLE_PAT_KEY :
+ rc = grn_pat_remove(ctx, path);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = grn_dat_remove(ctx, path);
+ break;
+ }
+ if (rc == GRN_SUCCESS) {
+ rc = grn_db_config_remove(ctx, path);
+ } else {
+ grn_db_config_remove(ctx, path);
+ }
+ }
+
+ return rc;
+}
+
+static grn_rc
+remove_reference_tables(grn_ctx *ctx, grn_obj *table, grn_obj *db)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_bool is_close_opened_object_mode = GRN_FALSE;
+ grn_id table_id;
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int table_name_size;
+ grn_table_cursor *cursor;
+
+ if (grn_thread_get_limit() == 1) {
+ is_close_opened_object_mode = GRN_TRUE;
+ }
+
+ table_id = DB_OBJ(table)->id;
+ table_name_size = grn_obj_name(ctx, table, table_name, GRN_TABLE_MAX_KEY_SIZE);
+ if ((cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_BY_ID))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *object;
+ grn_bool is_removed = GRN_FALSE;
+
+ if (is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (!object) {
+ ERRCLR(ctx);
+ if (is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ continue;
+ }
+
+ switch (object->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ if (DB_OBJ(object)->id == table_id) {
+ break;
+ }
+
+ if (object->header.domain == table_id) {
+ rc = _grn_obj_remove(ctx, object, GRN_TRUE);
+ is_removed = (grn_table_at(ctx, db, id) == GRN_ID_NIL);
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ if (object->header.domain == table_id) {
+ break;
+ }
+ if (DB_OBJ(object)->range == table_id) {
+ rc = _grn_obj_remove(ctx, object, GRN_FALSE);
+ is_removed = (grn_table_at(ctx, db, id) == GRN_ID_NIL);
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ break;
+ default:
+ break;
+ }
+
+ if (!is_removed) {
+ grn_obj_unlink(ctx, object);
+ }
+
+ if (is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ }
+
+ return rc;
+}
+
+static grn_bool
+is_removable_table(grn_ctx *ctx, grn_obj *table, grn_obj *db)
+{
+ grn_id table_id;
+ grn_id reference_object_id;
+
+ table_id = DB_OBJ(table)->id;
+ if (table_id & GRN_OBJ_TMP_OBJECT) {
+ return GRN_TRUE;
+ }
+
+ reference_object_id = grn_table_find_reference_object(ctx, table);
+ if (reference_object_id == GRN_ID_NIL) {
+ return GRN_TRUE;
+ }
+
+ {
+ grn_obj *db;
+ const char *table_name;
+ int table_name_size;
+ grn_obj *reference_object;
+ const char *reference_object_name;
+ int reference_object_name_size;
+
+ db = grn_ctx_db(ctx);
+
+ table_name = _grn_table_key(ctx, db, table_id,&table_name_size);
+
+ reference_object = grn_ctx_at(ctx, reference_object_id);
+ reference_object_name = _grn_table_key(ctx,
+ db,
+ reference_object_id,
+ &reference_object_name_size);
+ if (reference_object) {
+ if (grn_obj_is_table(ctx, reference_object)) {
+ ERR(GRN_OPERATION_NOT_PERMITTED,
+ "[table][remove] a table that references the table exists: "
+ "<%.*s._key> -> <%.*s>",
+ reference_object_name_size, reference_object_name,
+ table_name_size, table_name);
+ } else {
+ ERR(GRN_OPERATION_NOT_PERMITTED,
+ "[table][remove] a column that references the table exists: "
+ "<%.*s> -> <%.*s>",
+ reference_object_name_size, reference_object_name,
+ table_name_size, table_name);
+ }
+ } else {
+ ERR(GRN_OPERATION_NOT_PERMITTED,
+ "[table][remove] a dangling object that references the table exists: "
+ "<%.*s(%u)> -> <%.*s>",
+ reference_object_name_size,
+ reference_object_name,
+ reference_object_id,
+ table_name_size, table_name);
+ }
+ }
+
+ return GRN_FALSE;
+}
+
+static inline grn_rc
+_grn_obj_remove_spec(grn_ctx *ctx, grn_obj *db, grn_id id, uint8_t type)
+{
+ const char *name;
+ uint32_t name_size = 0;
+
+ name = _grn_table_key(ctx, db, id, &name_size);
+ /* TODO: reduce log level. */
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "spec:%u:remove:%.*s:%u(%s)",
+ id,
+ name_size, name,
+ type,
+ grn_obj_type_to_string(type));
+
+ return grn_ja_put(ctx, ((grn_db *)db)->specs, id, NULL, 0, GRN_OBJ_SET, NULL);
+}
+
+static grn_rc
+_grn_obj_remove_pat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path, grn_bool dependent)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ if (dependent) {
+ rc = remove_reference_tables(ctx, obj, db);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ } else {
+ if (!is_removable_table(ctx, obj, db)) {
+ return ctx->rc;
+ }
+ }
+
+ rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = remove_columns(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_pat_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_dat(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path, grn_bool dependent)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ if (dependent) {
+ rc = remove_reference_tables(ctx, obj, db);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ } else {
+ if (!is_removable_table(ctx, obj, db)) {
+ return ctx->rc;
+ }
+ }
+
+ rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = remove_columns(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_dat_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_hash(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path, grn_bool dependent)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ if (dependent) {
+ rc = remove_reference_tables(ctx, obj, db);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ } else {
+ if (!is_removable_table(ctx, obj, db)) {
+ return ctx->rc;
+ }
+ }
+
+ rc = remove_index(ctx, obj, GRN_HOOK_INSERT);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = remove_columns(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_hash_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_array(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path, grn_bool dependent)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ if (dependent) {
+ rc = remove_reference_tables(ctx, obj, db);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ } else {
+ if (!is_removable_table(ctx, obj, db)) {
+ return ctx->rc;
+ }
+ }
+
+ rc = remove_columns(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_array_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_ja(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ rc = remove_index(ctx, obj, GRN_HOOK_SET);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_ja_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_ra(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ rc = remove_index(ctx, obj, GRN_HOOK_SET);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_ra_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_index(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ delete_source_hook(ctx, obj);
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_ii_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_db_obj(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t type;
+
+ type = obj->header.type;
+
+ rc = grn_obj_close(ctx, obj);
+ if (rc != GRN_SUCCESS) { return rc; }
+
+ if (path) {
+ rc = grn_io_remove(ctx, path);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ if (!(id & GRN_OBJ_TMP_OBJECT)) {
+ rc = _grn_obj_remove_spec(ctx, db, id, type);
+ if (rc != GRN_SUCCESS) { return rc; }
+ rc = grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ if (rc != GRN_SUCCESS) { return rc; }
+ }
+
+ grn_obj_touch(ctx, db, NULL);
+
+ return rc;
+}
+
+static grn_rc
+_grn_obj_remove_other(grn_ctx *ctx, grn_obj *obj, grn_obj *db, grn_id id,
+ const char *path)
+{
+ return grn_obj_close(ctx, obj);
+}
+
+static grn_rc
+_grn_obj_remove(grn_ctx *ctx, grn_obj *obj, grn_bool dependent)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_id id = GRN_ID_NIL;
+ grn_obj *db = NULL;
+ const char *io_path;
+ char *path;
+ grn_bool is_temporary_open_target = GRN_FALSE;
+
+ if (ctx->impl && ctx->impl->db) {
+ grn_id id;
+ uint32_t s = 0;
+ const char *n;
+
+ id = DB_OBJ(obj)->id;
+ n = _grn_table_key(ctx, ctx->impl->db, id, &s);
+ if (s > 0) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "DDL:%u:obj_remove %.*s", id, s, n);
+ }
+ }
+ if (obj->header.type != GRN_PROC &&
+ (io_path = grn_obj_path(ctx, obj)) && *io_path != '\0') {
+ if (!(path = GRN_STRDUP(io_path))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
+ return ctx->rc;
+ }
+ } else {
+ path = NULL;
+ }
+ if (GRN_DB_OBJP(obj)) {
+ id = DB_OBJ(obj)->id;
+ db = DB_OBJ(obj)->db;
+ }
+ switch (obj->header.type) {
+ case GRN_DB :
+ rc = _grn_obj_remove_db(ctx, obj, db, id, path);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ rc = _grn_obj_remove_pat(ctx, obj, db, id, path, dependent);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = _grn_obj_remove_dat(ctx, obj, db, id, path, dependent);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ case GRN_TABLE_HASH_KEY :
+ rc = _grn_obj_remove_hash(ctx, obj, db, id, path, dependent);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ case GRN_TABLE_NO_KEY :
+ rc = _grn_obj_remove_array(ctx, obj, db, id, path, dependent);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ rc = _grn_obj_remove_ja(ctx, obj, db, id, path);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ rc = _grn_obj_remove_ra(ctx, obj, db, id, path);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ case GRN_COLUMN_INDEX :
+ rc = _grn_obj_remove_index(ctx, obj, db, id, path);
+ is_temporary_open_target = GRN_TRUE;
+ break;
+ default :
+ if (GRN_DB_OBJP(obj)) {
+ rc = _grn_obj_remove_db_obj(ctx, obj, db, id, path);
+ } else {
+ rc = _grn_obj_remove_other(ctx, obj, db, id, path);
+ }
+ }
+ if (path) {
+ GRN_FREE(path);
+ } else {
+ is_temporary_open_target = GRN_FALSE;
+ }
+
+ if (is_temporary_open_target && rc == GRN_SUCCESS) {
+ grn_obj *space;
+ space = ctx->impl->temporary_open_spaces.current;
+ if (space) {
+ unsigned int i, n_elements;
+ n_elements = GRN_BULK_VSIZE(space) / sizeof(grn_obj *);
+ for (i = 0; i < n_elements; i++) {
+ if (GRN_PTR_VALUE_AT(space, i) == obj) {
+ GRN_PTR_SET_AT(ctx, space, i, NULL);
+ }
+ }
+ }
+ }
+
+ return rc;
+}
+
+grn_rc
+grn_obj_remove(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
+ grn_io *io = grn_obj_get_io(ctx, ctx->impl->db);
+ rc = grn_io_lock(ctx, io, grn_lock_timeout);
+ if (rc == GRN_SUCCESS) {
+ rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
+ grn_io_unlock(io);
+ }
+ } else {
+ rc = _grn_obj_remove(ctx, obj, GRN_FALSE);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_obj_remove_dependent(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ if (ctx->impl && ctx->impl->db && ctx->impl->db != obj) {
+ grn_io *io = grn_obj_get_io(ctx, ctx->impl->db);
+ rc = grn_io_lock(ctx, io, grn_lock_timeout);
+ if (rc == GRN_SUCCESS) {
+ rc = _grn_obj_remove(ctx, obj, GRN_TRUE);
+ grn_io_unlock(io);
+ }
+ } else {
+ rc = _grn_obj_remove(ctx, obj, GRN_TRUE);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_obj_remove_force(grn_ctx *ctx, const char *name, int name_size)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *db;
+ grn_id obj_id;
+ char path[PATH_MAX];
+
+ GRN_API_ENTER;
+
+ if (!(ctx->impl && ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[object][remove][force] database isn't initialized");
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ db = ctx->impl->db;
+ if (name_size == -1) {
+ name_size = strlen(name);
+ }
+ obj_id = grn_table_get(ctx, db, name, name_size);
+ if (obj_id == GRN_ID_NIL) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[object][remove][force] nonexistent object: <%.*s>",
+ name_size, name);
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ grn_obj_delete_by_id(ctx, db, obj_id, GRN_TRUE);
+ grn_obj_path_by_id(ctx, db, obj_id, path);
+ grn_io_remove_if_exist(ctx, path);
+ grn_strcat(path, PATH_MAX, ".c");
+ grn_io_remove_if_exist(ctx, path);
+
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_update_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
+ const void *dest_key, unsigned int dest_key_size)
+{
+ grn_rc rc = GRN_OPERATION_NOT_SUPPORTED;
+ GRN_API_ENTER;
+ if (table->header.type == GRN_TABLE_DAT_KEY) {
+ grn_dat *dat = (grn_dat *)table;
+ if (dat->io && !(dat->io->flags & GRN_IO_TEMPORARY)) {
+ if (grn_io_lock(ctx, dat->io, grn_lock_timeout)) {
+ rc = ctx->rc;
+ } else {
+ rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
+ grn_io_unlock(dat->io);
+ }
+ } else {
+ rc = grn_dat_update_by_id(ctx, dat, id, dest_key, dest_key_size);
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_update(grn_ctx *ctx, grn_obj *table,
+ const void *src_key, unsigned int src_key_size,
+ const void *dest_key, unsigned int dest_key_size)
+{
+ grn_rc rc = GRN_OPERATION_NOT_SUPPORTED;
+ GRN_API_ENTER;
+ if (table->header.type == GRN_TABLE_DAT_KEY) {
+ rc = grn_dat_update(ctx, (grn_dat *)table,
+ src_key, src_key_size,
+ dest_key, dest_key_size);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_obj_rename(grn_ctx *ctx, grn_obj *obj, const char *name, unsigned int name_size)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (ctx && ctx->impl && GRN_DB_P(ctx->impl->db) && GRN_DB_OBJP(obj) && !IS_TEMP(obj)) {
+ grn_db *s = (grn_db *)ctx->impl->db;
+ grn_obj *keys = (grn_obj *)s->keys;
+ rc = grn_table_update_by_id(ctx, keys, DB_OBJ(obj)->id, name, name_size);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_table_rename(grn_ctx *ctx, grn_obj *table, const char *name, unsigned int name_size)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_hash *cols;
+
+ GRN_API_ENTER;
+
+ if (!GRN_OBJ_TABLEP(table)) {
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int table_name_size;
+ table_name_size = grn_obj_name(ctx, table, table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][rename] isn't table: <%.*s> -> <%.*s>",
+ table_name_size, table_name,
+ name_size, name);
+ goto exit;
+ }
+ if (IS_TEMP(table)) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][rename] temporary table doesn't have name: "
+ "(anonymous) -> <%.*s>",
+ name_size, name);
+ goto exit;
+ }
+
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ grn_table_columns(ctx, table, "", 0, (grn_obj *)cols);
+ if (!(rc = grn_obj_rename(ctx, table, name, name_size))) {
+ grn_id *key;
+ char fullname[GRN_TABLE_MAX_KEY_SIZE];
+ grn_memcpy(fullname, name, name_size);
+ fullname[name_size] = GRN_DB_DELIMITER;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) {
+ int colname_len = grn_column_name(ctx, col, fullname + name_size + 1,
+ GRN_TABLE_MAX_KEY_SIZE - name_size - 1);
+ if (colname_len) {
+ if ((rc = grn_obj_rename(ctx, col, fullname,
+ name_size + 1 + colname_len))) {
+ break;
+ }
+ }
+ }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+exit:
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_column_rename(grn_ctx *ctx, grn_obj *column, const char *name, unsigned int name_size)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(column)) {
+ char fullname[GRN_TABLE_MAX_KEY_SIZE];
+ grn_db *s = (grn_db *)DB_OBJ(column)->db;
+ int len = grn_table_get_key(ctx, s->keys, DB_OBJ(column)->header.domain,
+ fullname, GRN_TABLE_MAX_KEY_SIZE);
+ if (name_size + 1 + len > GRN_TABLE_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][rename] too long column name: required name_size(%d) < %d"
+ ": <%.*s>.<%.*s>",
+ name_size, GRN_TABLE_MAX_KEY_SIZE - 1 - len,
+ len, fullname, name_size, name);
+ goto exit;
+ }
+ fullname[len] = GRN_DB_DELIMITER;
+ grn_memcpy(fullname + len + 1, name, name_size);
+ name_size += len + 1;
+ rc = grn_obj_rename(ctx, column, fullname, name_size);
+ if (rc == GRN_SUCCESS) {
+ grn_obj_touch(ctx, column, NULL);
+ }
+ }
+exit :
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_obj_path_rename(grn_ctx *ctx, const char *old_path, const char *new_path)
+{
+ GRN_API_ENTER;
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+/* db must be validated by caller */
+grn_id
+grn_obj_register(grn_ctx *ctx, grn_obj *db, const char *name, unsigned int name_size)
+{
+ grn_id id = GRN_ID_NIL;
+ if (name && name_size) {
+ grn_db *s = (grn_db *)db;
+ int added;
+ if (!(id = grn_table_add(ctx, s->keys, name, name_size, &added))) {
+ grn_rc rc;
+ rc = ctx->rc;
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+ ERR(rc,
+ "[object][register] failed to register a name: <%.*s>%s%s%s",
+ name_size, name,
+ ctx->rc == GRN_SUCCESS ? "" : ": <",
+ ctx->rc == GRN_SUCCESS ? "" : ctx->errbuf,
+ ctx->rc == GRN_SUCCESS ? "" : ">");
+ } else if (!added) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[object][register] already used name was assigned: <%.*s>",
+ name_size, name);
+ id = GRN_ID_NIL;
+ }
+ } else if (ctx->impl && ctx->impl->values) {
+ id = grn_array_add(ctx, ctx->impl->values, NULL) | GRN_OBJ_TMP_OBJECT;
+ }
+ return id;
+}
+
+grn_rc
+grn_obj_delete_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, grn_bool removep)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (id) {
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (ctx->impl) {
+ if (id & GRN_OBJ_TMP_COLUMN) {
+ if (ctx->impl->temporary_columns) {
+ rc = grn_pat_delete_by_id(ctx, ctx->impl->temporary_columns,
+ id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT),
+ NULL);
+ }
+ } else {
+ if (ctx->impl->values) {
+ rc = grn_array_delete_by_id(ctx, ctx->impl->values,
+ id & ~GRN_OBJ_TMP_OBJECT, NULL);
+ }
+ }
+ }
+ } else {
+ db_value *vp;
+ grn_db *s = (grn_db *)db;
+ if ((vp = grn_tiny_array_at(&s->values, id))) {
+ GRN_ASSERT(!vp->lock);
+ vp->lock = 0;
+ vp->ptr = NULL;
+ vp->done = 0;
+ }
+ if (removep) {
+ switch (s->keys->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ rc = grn_pat_delete_by_id(ctx, (grn_pat *)s->keys, id, NULL);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = grn_dat_delete_by_id(ctx, (grn_dat *)s->keys, id, NULL);
+ break;
+ }
+ } else {
+ rc = GRN_SUCCESS;
+ }
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+
+grn_rc
+grn_obj_path_by_id(grn_ctx *ctx, grn_obj *db, grn_id id, char *buffer)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ if (!GRN_DB_P(db) || !buffer) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ grn_db_generate_pathname(ctx, db, id, buffer);
+ }
+ GRN_API_RETURN(rc);
+}
+
+/* db must be validated by caller */
+grn_rc
+grn_db_obj_init(grn_ctx *ctx, grn_obj *db, grn_id id, grn_db_obj *obj)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (id) {
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (id & GRN_OBJ_TMP_COLUMN) {
+ if (ctx->impl && ctx->impl->temporary_columns) {
+ grn_id real_id = id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT);
+ rc = grn_pat_set_value(ctx, ctx->impl->temporary_columns,
+ real_id, &obj, GRN_OBJ_SET);
+ }
+ } else {
+ if (ctx->impl && ctx->impl->values) {
+ rc = grn_array_set_value(ctx, ctx->impl->values,
+ id & ~GRN_OBJ_TMP_OBJECT, &obj, GRN_OBJ_SET);
+ }
+ }
+ } else {
+ db_value *vp;
+ vp = grn_tiny_array_at(&((grn_db *)db)->values, id);
+ if (!vp) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ ERR(rc, "grn_tiny_array_at failed (%d)", id);
+ return rc;
+ }
+ vp->lock = 1;
+ vp->ptr = (grn_obj *)obj;
+ }
+ }
+ obj->id = id;
+ obj->db = db;
+ obj->source = NULL;
+ obj->source_size = 0;
+ {
+ grn_hook_entry entry;
+ for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
+ obj->hooks[entry] = NULL;
+ }
+ }
+ grn_obj_spec_save(ctx, obj);
+ return rc;
+}
+
+#define GET_PATH(spec,decoded_spec,buffer,s,id) do {\
+ if (spec->header.flags & GRN_OBJ_CUSTOM_NAME) {\
+ const char *path;\
+ unsigned int size = grn_vector_get_element(ctx,\
+ decoded_spec,\
+ GRN_SERIALIZED_SPEC_INDEX_PATH,\
+ &path,\
+ NULL,\
+ NULL);\
+ if (size > PATH_MAX) { ERR(GRN_FILENAME_TOO_LONG, "too long path"); }\
+ grn_memcpy(buffer, path, size);\
+ buffer[size] = '\0';\
+ } else {\
+ grn_db_generate_pathname(ctx, (grn_obj *)s, id, buffer);\
+ }\
+} while (0)
+
+#define UNPACK_INFO(spec,decoded_spec) do {\
+ if (vp->ptr) {\
+ const char *p;\
+ uint32_t size;\
+ grn_db_obj *r = DB_OBJ(vp->ptr);\
+ r->header = spec->header;\
+ r->id = id;\
+ r->range = spec->range;\
+ r->db = (grn_obj *)s;\
+ size = grn_vector_get_element(ctx,\
+ decoded_spec,\
+ GRN_SERIALIZED_SPEC_INDEX_SOURCE,\
+ &p,\
+ NULL,\
+ NULL);\
+ if (size) {\
+ if ((r->source = GRN_MALLOC(size))) {\
+ grn_memcpy(r->source, p, size);\
+ r->source_size = size;\
+ }\
+ }\
+ size = grn_vector_get_element(ctx,\
+ decoded_spec,\
+ GRN_SERIALIZED_SPEC_INDEX_HOOK,\
+ &p,\
+ NULL,\
+ NULL);\
+ grn_hook_unpack(ctx, r, p, size);\
+ }\
+} while (0)
+
+static void
+grn_token_filters_unpack(grn_ctx *ctx,
+ grn_obj *token_filters,
+ grn_obj *spec_vector)
+{
+ grn_id *token_filter_ids;
+ unsigned int element_size;
+ unsigned int i, n_token_filter_ids;
+
+ if (grn_vector_size(ctx, spec_vector) <= GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS) {
+ return;
+ }
+
+ element_size = grn_vector_get_element(ctx,
+ spec_vector,
+ GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS,
+ (const char **)(&token_filter_ids),
+ NULL,
+ NULL);
+ n_token_filter_ids = element_size / sizeof(grn_id);
+ for (i = 0; i < n_token_filter_ids; i++) {
+ grn_id token_filter_id = token_filter_ids[i];
+ grn_obj *token_filter;
+
+ token_filter = grn_ctx_at(ctx, token_filter_id);
+ if (!token_filter) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "nonexistent token filter ID: %d", token_filter_id);
+ return;
+ }
+ GRN_PTR_PUT(ctx, token_filters, token_filter);
+ }
+}
+
+grn_bool
+grn_db_spec_unpack(grn_ctx *ctx,
+ grn_id id,
+ void *encoded_spec,
+ uint32_t encoded_spec_size,
+ grn_obj_spec **spec,
+ grn_obj *decoded_spec,
+ const char *error_message_tag)
+{
+ grn_obj *db;
+ grn_db *db_raw;
+ grn_rc rc;
+ uint32_t spec_size;
+
+ db = ctx->impl->db;
+ db_raw = (grn_db *)db;
+
+ rc = grn_vector_decode(ctx,
+ decoded_spec,
+ encoded_spec,
+ encoded_spec_size);
+ if (rc != GRN_SUCCESS) {
+ const char *name;
+ uint32_t name_size;
+ name = _grn_table_key(ctx, db, id, &name_size);
+ GRN_LOG((ctx), GRN_LOG_ERROR,
+ "%s: failed to decode spec: <%u>(<%.*s>):<%u>: %s",
+ error_message_tag,
+ id,
+ name_size, name,
+ encoded_spec_size,
+ grn_rc_to_string(rc));
+ return GRN_FALSE;
+ }
+
+ spec_size = grn_vector_get_element(ctx,
+ decoded_spec,
+ GRN_SERIALIZED_SPEC_INDEX_SPEC,
+ (const char **)spec,
+ NULL,
+ NULL);
+ if (spec_size == 0) {
+ const char *name;
+ uint32_t name_size;
+ name = _grn_table_key(ctx, db, id, &name_size);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "%s: spec value is empty: <%u>(<%.*s>)",
+ error_message_tag,
+ id,
+ name_size, name);
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+grn_obj *
+grn_ctx_at(grn_ctx *ctx, grn_id id)
+{
+ grn_obj *res = NULL;
+ if (!ctx || !ctx->impl || !id) { return res; }
+ GRN_API_ENTER;
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (id & GRN_OBJ_TMP_COLUMN) {
+ if (ctx->impl->temporary_columns) {
+ grn_id real_id = id & ~(GRN_OBJ_TMP_COLUMN | GRN_OBJ_TMP_OBJECT);
+ grn_obj **tmp_obj;
+ uint32_t size;
+ tmp_obj = (grn_obj **)grn_pat_get_value_(ctx,
+ ctx->impl->temporary_columns,
+ real_id,
+ &size);
+ if (tmp_obj) {
+ res = *tmp_obj;
+ }
+ }
+ } else {
+ if (ctx->impl->values) {
+ grn_obj **tmp_obj;
+ tmp_obj = _grn_array_get_value(ctx, ctx->impl->values,
+ id & ~GRN_OBJ_TMP_OBJECT);
+ if (tmp_obj) {
+ res = *tmp_obj;
+ }
+ }
+ }
+ } else {
+ grn_db *s = (grn_db *)ctx->impl->db;
+ if (s) {
+ db_value *vp;
+ uint32_t l, *pl, ntrial;
+ if (!(vp = grn_tiny_array_at(&s->values, id))) { goto exit; }
+#ifdef USE_NREF
+ pl = &vp->lock;
+ for (ntrial = 0;; ntrial++) {
+ GRN_ATOMIC_ADD_EX(pl, 1, l);
+ if (l < GRN_IO_MAX_REF) { break; }
+ if (ntrial >= 10) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
+ break;
+ }
+ GRN_ATOMIC_ADD_EX(pl, -1, l);
+ GRN_FUTEX_WAIT(pl);
+ }
+#endif /* USE_NREF */
+ if (s->specs && !vp->ptr /* && !vp->done */) {
+#ifndef USE_NREF
+ pl = &vp->lock;
+ for (ntrial = 0;; ntrial++) {
+ GRN_ATOMIC_ADD_EX(pl, 1, l);
+ if (l < GRN_IO_MAX_REF) { break; }
+ if (ntrial >= 10) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%p,%d)", vp->ptr, vp->lock);
+ break;
+ }
+ GRN_ATOMIC_ADD_EX(pl, -1, l);
+ GRN_FUTEX_WAIT(pl);
+ }
+#endif /* USE_NREF */
+ if (!l) {
+ grn_io_win iw;
+ uint32_t encoded_spec_size;
+ void *encoded_spec;
+
+ encoded_spec = grn_ja_ref(ctx, s->specs, id, &iw, &encoded_spec_size);
+ if (encoded_spec) {
+ grn_bool success;
+ grn_obj_spec *spec;
+ grn_obj decoded_spec;
+
+ GRN_OBJ_INIT(&decoded_spec, GRN_VECTOR, 0, GRN_DB_TEXT);
+ success = grn_db_spec_unpack(ctx,
+ id,
+ encoded_spec,
+ encoded_spec_size,
+ &spec,
+ &decoded_spec,
+ "grn_ctx_at");
+ if (success) {
+ char buffer[PATH_MAX];
+ switch (spec->header.type) {
+ case GRN_TYPE :
+ vp->ptr = (grn_obj *)grn_type_open(ctx, spec);
+ UNPACK_INFO(spec, &decoded_spec);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ vp->ptr = (grn_obj *)grn_hash_open(ctx, buffer);
+ if (vp->ptr) {
+ grn_hash *hash = (grn_hash *)(vp->ptr);
+ grn_obj_flags flags = vp->ptr->header.flags;
+ UNPACK_INFO(spec, &decoded_spec);
+ vp->ptr->header.flags = flags;
+ grn_token_filters_unpack(ctx,
+ &(hash->token_filters),
+ &decoded_spec);
+ }
+ break;
+ case GRN_TABLE_PAT_KEY :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ vp->ptr = (grn_obj *)grn_pat_open(ctx, buffer);
+ if (vp->ptr) {
+ grn_pat *pat = (grn_pat *)(vp->ptr);
+ grn_obj_flags flags = vp->ptr->header.flags;
+ UNPACK_INFO(spec, &decoded_spec);
+ vp->ptr->header.flags = flags;
+ grn_token_filters_unpack(ctx,
+ &(pat->token_filters),
+ &decoded_spec);
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ vp->ptr = (grn_obj *)grn_dat_open(ctx, buffer);
+ if (vp->ptr) {
+ grn_dat *dat = (grn_dat *)(vp->ptr);
+ grn_obj_flags flags = vp->ptr->header.flags;
+ UNPACK_INFO(spec, &decoded_spec);
+ vp->ptr->header.flags = flags;
+ grn_token_filters_unpack(ctx,
+ &(dat->token_filters),
+ &decoded_spec);
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ vp->ptr = (grn_obj *)grn_array_open(ctx, buffer);
+ UNPACK_INFO(spec, &decoded_spec);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ vp->ptr = (grn_obj *)grn_ja_open(ctx, buffer);
+ UNPACK_INFO(spec, &decoded_spec);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ vp->ptr = (grn_obj *)grn_ra_open(ctx, buffer);
+ UNPACK_INFO(spec, &decoded_spec);
+ break;
+ case GRN_COLUMN_INDEX :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ {
+ grn_obj *table = grn_ctx_at(ctx, spec->header.domain);
+ vp->ptr = (grn_obj *)grn_ii_open(ctx, buffer, table);
+ }
+ UNPACK_INFO(spec, &decoded_spec);
+ break;
+ case GRN_PROC :
+ GET_PATH(spec, &decoded_spec, buffer, s, id);
+ grn_plugin_register(ctx, buffer);
+ break;
+ case GRN_EXPR :
+ {
+ const char *p;
+ uint32_t size;
+ uint8_t *u;
+ size = grn_vector_get_element(ctx,
+ &decoded_spec,
+ GRN_SERIALIZED_SPEC_INDEX_EXPR,
+ &p,
+ NULL,
+ NULL);
+ u = (uint8_t *)p;
+ vp->ptr = grn_expr_open(ctx, spec, u, u + size);
+ }
+ break;
+ }
+ if (!vp->ptr) {
+ const char *name;
+ uint32_t name_size = 0;
+ name = _grn_table_key(ctx, (grn_obj *)s, id, &name_size);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "grn_ctx_at: failed to open object: "
+ "<%u>(<%.*s>):<%u>(<%s>)",
+ id,
+ name_size, name,
+ spec->header.type,
+ grn_obj_type_to_string(spec->header.type));
+ }
+ }
+ GRN_OBJ_FIN(ctx, &decoded_spec);
+ grn_ja_unref(ctx, &iw);
+ }
+#ifndef USE_NREF
+ GRN_ATOMIC_ADD_EX(pl, -1, l);
+#endif /* USE_NREF */
+ vp->done = 1;
+ GRN_FUTEX_WAKE(&vp->ptr);
+ } else {
+ for (ntrial = 0; !vp->ptr; ntrial++) {
+ if (ntrial >= 1000) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "max trial in ctx_at(%d,%p,%d)!", id, vp->ptr, vp->lock);
+ break;
+ }
+ GRN_FUTEX_WAIT(&vp->ptr);
+ }
+ }
+ if (vp->ptr) {
+ switch (vp->ptr->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ {
+ grn_obj *space;
+ space = ctx->impl->temporary_open_spaces.current;
+ if (space) {
+ GRN_PTR_PUT(ctx, space, vp->ptr);
+ }
+ }
+ break;
+ }
+ }
+ }
+ res = vp->ptr;
+ if (res && res->header.type == GRN_PROC) {
+ grn_plugin_ensure_registered(ctx, res);
+ }
+ }
+ }
+exit :
+ GRN_API_RETURN(res);
+}
+
+grn_bool
+grn_ctx_is_opened(grn_ctx *ctx, grn_id id)
+{
+ grn_bool is_opened = GRN_FALSE;
+
+ if (!ctx || !ctx->impl || !id) {
+ return GRN_FALSE;
+ }
+
+ GRN_API_ENTER;
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (ctx->impl->values) {
+ grn_obj **tmp_obj;
+ tmp_obj = _grn_array_get_value(ctx, ctx->impl->values,
+ id & ~GRN_OBJ_TMP_OBJECT);
+ if (tmp_obj) {
+ is_opened = GRN_TRUE;
+ }
+ }
+ } else {
+ grn_db *s = (grn_db *)ctx->impl->db;
+ if (s) {
+ db_value *vp;
+ vp = grn_tiny_array_at(&s->values, id);
+ if (vp && vp->ptr) {
+ is_opened = GRN_TRUE;
+ }
+ }
+ }
+ GRN_API_RETURN(is_opened);
+}
+
+grn_obj *
+grn_obj_open(grn_ctx *ctx, unsigned char type, grn_obj_flags flags, grn_id domain)
+{
+ grn_obj *obj = GRN_MALLOCN(grn_obj, 1);
+ if (obj) {
+ GRN_OBJ_INIT(obj, type, flags, domain);
+ obj->header.impl_flags |= GRN_OBJ_ALLOCATED;
+ }
+ return obj;
+}
+
+grn_obj *
+grn_obj_graft(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_obj *new = grn_obj_open(ctx, obj->header.type, obj->header.impl_flags, obj->header.domain);
+ if (new) {
+ /* todo : deep copy if (obj->header.impl_flags & GRN_OBJ_DO_SHALLOW_COPY) */
+ new->u.b.head = obj->u.b.head;
+ new->u.b.curr = obj->u.b.curr;
+ new->u.b.tail = obj->u.b.tail;
+ obj->u.b.head = NULL;
+ obj->u.b.curr = NULL;
+ obj->u.b.tail = NULL;
+ }
+ return new;
+}
+
+grn_rc
+grn_pvector_fin(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc;
+ if (obj->header.impl_flags & GRN_OBJ_OWN) {
+ /*
+ * Note that GRN_OBJ_OWN should not be used outside the DB API function
+ * because grn_obj_close is a DB API function.
+ */
+ unsigned int i, n_elements;
+ n_elements = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
+ for (i = 0; i < n_elements; i++) {
+ grn_obj *element = GRN_PTR_VALUE_AT(obj, n_elements - i - 1);
+ if (element) {
+ grn_obj_close(ctx, element);
+ }
+ }
+ }
+ obj->header.type = GRN_VOID;
+ rc = grn_bulk_fin(ctx, obj);
+ if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) {
+ GRN_FREE(obj);
+ }
+ return rc;
+}
+
+static void
+grn_table_close_columns(grn_ctx *ctx, grn_obj *table)
+{
+ grn_hash *columns;
+ int n_columns;
+
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
+ if (!columns) {
+ return;
+ }
+
+ n_columns = grn_table_columns(ctx, table, "", 0, (grn_obj *)columns);
+ if (n_columns > 0) {
+ grn_hash_cursor *cursor;
+ cursor = grn_hash_cursor_open(ctx, columns, NULL, 0, NULL, 0, 0, -1, 0);
+ if (cursor) {
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_id *id;
+ grn_obj *column;
+
+ grn_hash_cursor_get_key(ctx, cursor, (void **)&id);
+ column = grn_ctx_at(ctx, *id);
+ if (column) {
+ grn_obj_close(ctx, column);
+ }
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ }
+
+ grn_hash_close(ctx, columns);
+}
+
+grn_rc
+grn_obj_close(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ GRN_API_ENTER;
+ if (obj) {
+ if (grn_obj_is_table(ctx, obj) &&
+ (DB_OBJ(obj)->id & GRN_OBJ_TMP_OBJECT)) {
+ grn_table_close_columns(ctx, obj);
+ }
+ if (GRN_DB_OBJP(obj)) {
+ grn_hook_entry entry;
+ if (DB_OBJ(obj)->finalizer) {
+ DB_OBJ(obj)->finalizer(ctx, 1, &obj, &DB_OBJ(obj)->user_data);
+ }
+ if (DB_OBJ(obj)->source) {
+ GRN_FREE(DB_OBJ(obj)->source);
+ }
+ for (entry = 0; entry < N_HOOK_ENTRIES; entry++) {
+ grn_hook_free(ctx, DB_OBJ(obj)->hooks[entry]);
+ }
+ grn_obj_delete_by_id(ctx, DB_OBJ(obj)->db, DB_OBJ(obj)->id, GRN_FALSE);
+ }
+ switch (obj->header.type) {
+ case GRN_VECTOR :
+ if (obj->u.v.body && !(obj->header.impl_flags & GRN_OBJ_REFER)) {
+ grn_obj_close(ctx, obj->u.v.body);
+ }
+ if (obj->u.v.sections) { GRN_FREE(obj->u.v.sections); }
+ if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_VOID :
+ case GRN_BULK :
+ case GRN_UVECTOR :
+ case GRN_MSG :
+ obj->header.type = GRN_VOID;
+ rc = grn_bulk_fin(ctx, obj);
+ if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
+ break;
+ case GRN_PTR :
+ if (obj->header.impl_flags & GRN_OBJ_OWN) {
+ if (GRN_BULK_VSIZE(obj) == sizeof(grn_obj *)) {
+ grn_obj_close(ctx, GRN_PTR_VALUE(obj));
+ }
+ }
+ obj->header.type = GRN_VOID;
+ rc = grn_bulk_fin(ctx, obj);
+ if (obj->header.impl_flags & GRN_OBJ_ALLOCATED) { GRN_FREE(obj); }
+ break;
+ case GRN_PVECTOR :
+ rc = grn_pvector_fin(ctx, obj);
+ break;
+ case GRN_ACCESSOR :
+ {
+ grn_accessor *p, *n;
+ for (p = (grn_accessor *)obj; p; p = n) {
+ n = p->next;
+ GRN_FREE(p);
+ }
+ }
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_SNIP :
+ rc = grn_snip_close(ctx, (grn_snip *)obj);
+ break;
+ case GRN_STRING :
+ rc = grn_string_close(ctx, obj);
+ break;
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ grn_pat_cursor_close(ctx, (grn_pat_cursor *)obj);
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ grn_dat_cursor_close(ctx, (grn_dat_cursor *)obj);
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ grn_hash_cursor_close(ctx, (grn_hash_cursor *)obj);
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ grn_array_cursor_close(ctx, (grn_array_cursor *)obj);
+ break;
+ case GRN_CURSOR_COLUMN_INDEX :
+ {
+ grn_index_cursor *ic = (grn_index_cursor *)obj;
+ if (ic->iic) { grn_ii_cursor_close(ctx, ic->iic); }
+ GRN_FREE(ic);
+ }
+ break;
+ case GRN_CURSOR_COLUMN_GEO_INDEX :
+ grn_geo_cursor_close(ctx, obj);
+ break;
+ case GRN_CURSOR_CONFIG :
+ grn_config_cursor_close(ctx, (grn_config_cursor *)obj);
+ break;
+ case GRN_TYPE :
+ GRN_FREE(obj);
+ rc = GRN_SUCCESS;
+ break;
+ case GRN_DB :
+ rc = grn_db_close(ctx, obj);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ rc = grn_pat_close(ctx, (grn_pat *)obj);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = grn_dat_close(ctx, (grn_dat *)obj);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ rc = grn_hash_close(ctx, (grn_hash *)obj);
+ break;
+ case GRN_TABLE_NO_KEY :
+ rc = grn_array_close(ctx, (grn_array *)obj);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ rc = grn_ja_close(ctx, (grn_ja *)obj);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ rc = grn_ra_close(ctx, (grn_ra *)obj);
+ break;
+ case GRN_COLUMN_INDEX :
+ rc = grn_ii_close(ctx, (grn_ii *)obj);
+ break;
+ case GRN_PROC :
+ {
+ uint32_t i;
+ grn_proc *p = (grn_proc *)obj;
+ /*
+ if (obj->header.domain) {
+ grn_hash_delete(ctx, ctx->impl->qe, &obj->header.domain, sizeof(grn_id), NULL);
+ }
+ */
+ for (i = 0; i < p->nvars; i++) {
+ grn_obj_close(ctx, &p->vars[i].value);
+ }
+ GRN_REALLOC(p->vars, 0);
+ grn_obj_close(ctx, &p->name_buf);
+ if (p->obj.range != GRN_ID_NIL) {
+ grn_plugin_close(ctx, p->obj.range);
+ }
+ GRN_FREE(obj);
+ rc = GRN_SUCCESS;
+ }
+ break;
+ case GRN_EXPR :
+ rc = grn_expr_close(ctx, obj);
+ break;
+ }
+ }
+ GRN_API_RETURN(rc);
+}
+
+void
+grn_obj_unlink(grn_ctx *ctx, grn_obj *obj)
+{
+ if (obj &&
+ (!GRN_DB_OBJP(obj) ||
+ (((grn_db_obj *)obj)->id & GRN_OBJ_TMP_OBJECT) ||
+ (((grn_db_obj *)obj)->id == GRN_ID_NIL) ||
+ obj->header.type == GRN_DB)) {
+ grn_obj_close(ctx, obj);
+ } else if (GRN_DB_OBJP(obj)) {
+#ifdef USE_NREF
+ grn_db_obj *dob = DB_OBJ(obj);
+ grn_db *s = (grn_db *)dob->db;
+ db_value *vp = grn_tiny_array_at(&s->values, dob->id);
+ if (vp) {
+ uint32_t l, *pl = &vp->lock;
+ if (!vp->lock) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "invalid unlink(%p,%d)", obj, vp->lock);
+ return;
+ }
+ GRN_ATOMIC_ADD_EX(pl, -1, l);
+ if (l == 1) {
+ GRN_ATOMIC_ADD_EX(pl, GRN_IO_MAX_REF, l);
+ if (l == GRN_IO_MAX_REF) {
+#ifdef CALL_FINALIZER
+ grn_obj_close(ctx, obj);
+ vp->done = 0;
+ if (dob->finalizer) {
+ dob->finalizer(ctx, 1, &obj, &dob->user_data);
+ dob->finalizer = NULL;
+ dob->user_data.ptr = NULL;
+ }
+#endif /* CALL_FINALIZER */
+ }
+ GRN_ATOMIC_ADD_EX(pl, -GRN_IO_MAX_REF, l);
+ GRN_FUTEX_WAKE(pl);
+ }
+ }
+#endif /* USE_NREF */
+ }
+}
+
+#define VECTOR_CLEAR(ctx,obj) do {\
+ if ((obj)->u.v.body && !((obj)->header.impl_flags & GRN_OBJ_REFER)) {\
+ grn_obj_close((ctx), (obj)->u.v.body);\
+ }\
+ if ((obj)->u.v.sections) { GRN_FREE((obj)->u.v.sections); }\
+ (obj)->header.impl_flags &= ~GRN_OBJ_DO_SHALLOW_COPY;\
+ (obj)->u.b.head = NULL;\
+ (obj)->u.b.curr = NULL;\
+ (obj)->u.b.tail = NULL;\
+} while (0)
+
+static void
+grn_obj_ensure_vector(grn_ctx *ctx, grn_obj *obj)
+{
+ if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
+ obj->header.type = GRN_VECTOR;
+ obj->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
+}
+
+static void
+grn_obj_ensure_bulk(grn_ctx *ctx, grn_obj *obj)
+{
+ if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
+ obj->header.type = GRN_BULK;
+ obj->header.flags &= ~GRN_OBJ_WITH_WEIGHT;
+}
+
+grn_rc
+grn_obj_reinit(grn_ctx *ctx, grn_obj *obj, grn_id domain, unsigned char flags)
+{
+ if (!GRN_OBJ_MUTABLE(obj)) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid obj assigned");
+ } else {
+ switch (obj->header.type) {
+ case GRN_PTR :
+ if (obj->header.impl_flags & GRN_OBJ_OWN) {
+ if (GRN_BULK_VSIZE(obj) == sizeof(grn_obj *)) {
+ grn_obj_close(ctx, GRN_PTR_VALUE(obj));
+ }
+ obj->header.impl_flags &= ~GRN_OBJ_OWN;
+ }
+ break;
+ case GRN_PVECTOR :
+ if (obj->header.impl_flags & GRN_OBJ_OWN) {
+ unsigned int i, n_elements;
+ n_elements = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
+ for (i = 0; i < n_elements; i++) {
+ grn_obj *element = GRN_PTR_VALUE_AT(obj, i);
+ grn_obj_close(ctx, element);
+ }
+ obj->header.impl_flags &= ~GRN_OBJ_OWN;
+ }
+ break;
+ default :
+ break;
+ }
+
+ switch (domain) {
+ case GRN_DB_VOID :
+ if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
+ obj->header.type = GRN_VOID;
+ obj->header.domain = domain;
+ GRN_BULK_REWIND(obj);
+ break;
+ case GRN_DB_OBJECT :
+ case GRN_DB_BOOL :
+ case GRN_DB_INT8 :
+ case GRN_DB_UINT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_INT64 :
+ case GRN_DB_UINT64 :
+ case GRN_DB_FLOAT :
+ case GRN_DB_TIME :
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
+ obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
+ obj->header.domain = domain;
+ GRN_BULK_REWIND(obj);
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ if (flags & GRN_OBJ_VECTOR) {
+ if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
+ obj->header.type = GRN_VECTOR;
+ if (obj->u.v.body) {
+ grn_obj_reinit(ctx, obj->u.v.body, domain, 0);
+ }
+ obj->u.v.n_sections = 0;
+ } else {
+ if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
+ obj->header.type = GRN_BULK;
+ }
+ obj->header.domain = domain;
+ GRN_BULK_REWIND(obj);
+ break;
+ default :
+ {
+ grn_obj *d = grn_ctx_at(ctx, domain);
+ if (!d) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid domain assigned");
+ } else {
+ if (d->header.type == GRN_TYPE && (d->header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
+ if (flags & GRN_OBJ_VECTOR) {
+ if (obj->header.type != GRN_VECTOR) { grn_bulk_fin(ctx, obj); }
+ obj->header.type = GRN_VECTOR;
+ } else {
+ if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
+ obj->header.type = GRN_BULK;
+ }
+ } else {
+ if (obj->header.type == GRN_VECTOR) { VECTOR_CLEAR(ctx, obj); }
+ obj->header.type = (flags & GRN_OBJ_VECTOR) ? GRN_UVECTOR : GRN_BULK;
+ }
+ obj->header.domain = domain;
+ GRN_BULK_REWIND(obj);
+ }
+ }
+ break;
+ }
+ }
+ return ctx->rc;
+}
+
+grn_rc
+grn_obj_reinit_for(grn_ctx *ctx, grn_obj *obj, grn_obj *domain_obj)
+{
+ grn_id domain = GRN_ID_NIL;
+ grn_obj_flags flags = 0;
+
+ if (!GRN_DB_OBJP(domain_obj) && domain_obj->header.type != GRN_ACCESSOR) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect_limited(ctx, &inspected, domain_obj);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[reinit] invalid domain object: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+
+ if (grn_column_is_index(ctx, domain_obj)) {
+ domain = GRN_DB_UINT32;
+ } else {
+ grn_obj_get_range_info(ctx, domain_obj, &domain, &flags);
+ if (GRN_OBJ_TABLEP(domain_obj) &&
+ domain_obj->header.type != GRN_TABLE_NO_KEY) {
+ domain = domain_obj->header.domain;
+ }
+ }
+ return grn_obj_reinit(ctx, obj, domain, flags);
+}
+
+const char *
+grn_obj_path(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_io *io;
+ const char *path = NULL;
+ GRN_API_ENTER;
+ if (obj->header.type == GRN_PROC) {
+ path = grn_plugin_path(ctx, DB_OBJ(obj)->range);
+ GRN_API_RETURN(path);
+ }
+ io = grn_obj_get_io(ctx, obj);
+ if (io && !(io->flags & GRN_IO_TEMPORARY)) { path = io->path; }
+ GRN_API_RETURN(path);
+}
+
+int
+grn_obj_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
+{
+ int len = 0;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) {
+ if (DB_OBJ(obj)->id) {
+ grn_db *s = (grn_db *)DB_OBJ(obj)->db;
+ grn_id id = DB_OBJ(obj)->id;
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (id & GRN_OBJ_TMP_COLUMN) {
+ grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
+ len = grn_pat_get_key(ctx, ctx->impl->temporary_columns,
+ real_id, namebuf, buf_size);
+ }
+ } else {
+ len = grn_table_get_key(ctx, s->keys, id, namebuf, buf_size);
+ }
+ }
+ }
+ GRN_API_RETURN(len);
+}
+
+int
+grn_column_name(grn_ctx *ctx, grn_obj *obj, char *namebuf, int buf_size)
+{
+ int len = 0;
+ char buf[GRN_TABLE_MAX_KEY_SIZE];
+ if (!obj) { return len; }
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) {
+ grn_id id = DB_OBJ(obj)->id;
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (id & GRN_OBJ_TMP_COLUMN) {
+ grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
+ len = grn_pat_get_key(ctx, ctx->impl->temporary_columns,
+ real_id, buf, GRN_TABLE_MAX_KEY_SIZE);
+ }
+ } else if (id && id < GRN_ID_MAX) {
+ grn_db *s = (grn_db *)DB_OBJ(obj)->db;
+ len = grn_table_get_key(ctx, s->keys, id, buf, GRN_TABLE_MAX_KEY_SIZE);
+ }
+ if (len) {
+ int cl;
+ char *p = buf, *p0 = p, *pe = p + len;
+ for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
+ if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
+ }
+ len = pe - p0;
+ if (len && len <= buf_size) {
+ grn_memcpy(namebuf, p0, len);
+ }
+ }
+ } else if (obj->header.type == GRN_ACCESSOR) {
+ grn_obj name;
+ grn_accessor *a;
+
+ GRN_TEXT_INIT(&name, 0);
+
+#define ADD_DELMITER() do { \
+ if (GRN_TEXT_LEN(&name) > 0) { \
+ GRN_TEXT_PUTC(ctx, &name, GRN_DB_DELIMITER); \
+ } \
+ } while (GRN_FALSE)
+
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_ID);
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ if (!a->next) {
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_KEY);
+ }
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ if (!a->next) {
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_VALUE);
+ }
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_SCORE);
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_NSUBRECS);
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_MAX);
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_MIN);
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_SUM);
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ ADD_DELMITER();
+ GRN_TEXT_PUTS(ctx, &name, GRN_COLUMN_NAME_AVG);
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ ADD_DELMITER();
+ {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ column_name_size = grn_column_name(ctx, a->obj,
+ column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_PUT(ctx, &name, column_name, column_name_size);
+ }
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ case GRN_ACCESSOR_LOOKUP :
+ case GRN_ACCESSOR_FUNCALL :
+ break;
+ }
+ }
+#undef ADD_DELIMITER
+
+ len = GRN_TEXT_LEN(&name);
+ if (len > 0 && len <= buf_size) {
+ grn_memcpy(namebuf, GRN_TEXT_VALUE(&name), len);
+ }
+
+ GRN_OBJ_FIN(ctx, &name);
+ }
+ GRN_API_RETURN(len);
+}
+
+grn_rc
+grn_column_name_(grn_ctx *ctx, grn_obj *obj, grn_obj *buf)
+{
+ if (GRN_DB_OBJP(obj)) {
+ uint32_t len = 0;
+ const char *p = NULL;
+ grn_id id = DB_OBJ(obj)->id;
+ if (id & GRN_OBJ_TMP_OBJECT) {
+ if (id & GRN_OBJ_TMP_COLUMN) {
+ grn_id real_id = id & ~(GRN_OBJ_TMP_OBJECT | GRN_OBJ_TMP_COLUMN);
+ p = _grn_pat_key(ctx, ctx->impl->temporary_columns, real_id, &len);
+ }
+ } else if (id && id < GRN_ID_MAX) {
+ grn_db *s = (grn_db *)DB_OBJ(obj)->db;
+ p = _grn_table_key(ctx, s->keys, id, &len);
+ }
+ if (len) {
+ int cl;
+ const char *p0 = p, *pe = p + len;
+ for (; p < pe && (cl = grn_charlen(ctx, p, pe)); p += cl) {
+ if (*p == GRN_DB_DELIMITER && cl == 1) { p0 = p + cl; }
+ }
+ GRN_TEXT_PUT(ctx, buf, p0, pe - p0);
+ }
+ } else if (obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a;
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ GRN_TEXT_PUT(ctx, buf, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN);
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ if (!a->next) {
+ GRN_TEXT_PUT(ctx, buf, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN);
+ }
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ if (!a->next) {
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_VALUE,
+ GRN_COLUMN_NAME_VALUE_LEN);
+ }
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_SCORE,
+ GRN_COLUMN_NAME_SCORE_LEN);
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_NSUBRECS,
+ GRN_COLUMN_NAME_NSUBRECS_LEN);
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_MAX,
+ GRN_COLUMN_NAME_MAX_LEN);
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_MIN,
+ GRN_COLUMN_NAME_MIN_LEN);
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_SUM,
+ GRN_COLUMN_NAME_SUM_LEN);
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ GRN_TEXT_PUT(ctx, buf,
+ GRN_COLUMN_NAME_AVG,
+ GRN_COLUMN_NAME_AVG_LEN);
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ grn_column_name_(ctx, a->obj, buf);
+ if (a->next) { GRN_TEXT_PUTC(ctx, buf, '.'); }
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ case GRN_ACCESSOR_LOOKUP :
+ case GRN_ACCESSOR_FUNCALL :
+ break;
+ }
+ }
+ }
+ return ctx->rc;
+}
+
+int
+grn_obj_expire(grn_ctx *ctx, grn_obj *obj, int threshold)
+{
+ GRN_API_ENTER;
+ GRN_API_RETURN(0);
+}
+
+int
+grn_obj_check(grn_ctx *ctx, grn_obj *obj)
+{
+ GRN_API_ENTER;
+ GRN_API_RETURN(0);
+}
+
+grn_rc
+grn_obj_lock(grn_ctx *ctx, grn_obj *obj, grn_id id, int timeout)
+{
+ grn_rc rc = GRN_SUCCESS;
+ GRN_API_ENTER;
+ rc = grn_io_lock(ctx, grn_obj_get_io(ctx, obj), timeout);
+ if (rc == GRN_SUCCESS && obj && obj->header.type == GRN_COLUMN_INDEX) {
+ rc = grn_io_lock(ctx, ((grn_ii *)obj)->chunk, timeout);
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_obj_unlock(grn_ctx *ctx, grn_obj *obj, grn_id id)
+{
+ GRN_API_ENTER;
+ if (obj && obj->header.type == GRN_COLUMN_INDEX) {
+ grn_io_unlock(((grn_ii *)obj)->chunk);
+ }
+ grn_io_unlock(grn_obj_get_io(ctx, obj));
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_user_data *
+grn_obj_user_data(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!GRN_DB_OBJP(obj)) { return NULL; }
+ return &DB_OBJ(obj)->user_data;
+}
+
+grn_rc
+grn_obj_set_finalizer(grn_ctx *ctx, grn_obj *obj, grn_proc_func *func)
+{
+ if (!GRN_DB_OBJP(obj)) { return GRN_INVALID_ARGUMENT; }
+ DB_OBJ(obj)->finalizer = func;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_obj_clear_lock(grn_ctx *ctx, grn_obj *obj)
+{
+ GRN_API_ENTER;
+ switch (obj->header.type) {
+ case GRN_DB:
+ {
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *tbl = grn_ctx_at(ctx, id);
+ if (tbl) {
+ switch (tbl->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ grn_obj_clear_lock(ctx, tbl);
+ break;
+ }
+ } else {
+ if (ctx->rc != GRN_SUCCESS) {
+ ERRCLR(ctx);
+ }
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ }
+ grn_io_clear_lock(grn_obj_get_io(ctx, obj));
+ {
+ grn_db *db = (grn_db *)obj;
+ if (db->specs) {
+ grn_obj_clear_lock(ctx, (grn_obj *)(db->specs));
+ }
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ grn_array_queue_lock_clear(ctx, (grn_array *)obj);
+ /* fallthru */
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ {
+ grn_hash *cols;
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) { grn_obj_clear_lock(ctx, col); }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+ grn_io_clear_lock(grn_obj_get_io(ctx, obj));
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE:
+ case GRN_COLUMN_VAR_SIZE:
+ grn_io_clear_lock(grn_obj_get_io(ctx, obj));
+ break;
+ case GRN_COLUMN_INDEX:
+ grn_io_clear_lock(grn_obj_get_io(ctx, obj));
+ if (obj) {
+ grn_io_clear_lock(((grn_ii *)obj)->chunk);
+ }
+ break;
+ }
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+unsigned int
+grn_obj_is_locked(grn_ctx *ctx, grn_obj *obj)
+{
+ unsigned int res = 0;
+ GRN_API_ENTER;
+ res = grn_io_is_locked(grn_obj_get_io(ctx, obj));
+ if (obj && obj->header.type == GRN_COLUMN_INDEX) {
+ res += grn_io_is_locked(((grn_ii *)obj)->chunk);
+ }
+ GRN_API_RETURN(res);
+}
+
+grn_rc
+grn_obj_flush(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ GRN_API_ENTER;
+
+ switch (obj->header.type) {
+ case GRN_DB :
+ {
+ grn_db *db = (grn_db *)obj;
+ rc = grn_obj_flush(ctx, db->keys);
+ if (rc == GRN_SUCCESS && db->specs) {
+ rc = grn_obj_flush(ctx, (grn_obj *)(db->specs));
+ }
+ if (rc == GRN_SUCCESS) {
+ rc = grn_obj_flush(ctx, (grn_obj *)(db->config));
+ }
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ rc = grn_dat_flush(ctx, (grn_dat *)obj);
+ break;
+ case GRN_COLUMN_INDEX :
+ rc = grn_ii_flush(ctx, (grn_ii *)obj);
+ break;
+ default :
+ {
+ grn_io *io;
+ io = grn_obj_get_io(ctx, obj);
+ if (io) {
+ rc = grn_io_flush(ctx, io);
+ }
+ }
+ break;
+ }
+
+ if (rc == GRN_SUCCESS &&
+ GRN_DB_OBJP(obj) &&
+ DB_OBJ(obj)->id != GRN_ID_NIL &&
+ !IS_TEMP(obj)) {
+ rc = grn_db_clean(ctx, DB_OBJ(obj)->db);
+ }
+
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_obj_flush_recursive(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ GRN_API_ENTER;
+ switch (obj->header.type) {
+ case GRN_DB :
+ {
+ grn_table_cursor *cursor;
+ grn_id id;
+
+ cursor = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ while ((id = grn_table_cursor_next_inline(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *table = grn_ctx_at(ctx, id);
+ rc = GRN_SUCCESS;
+ if (table) {
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ rc = grn_obj_flush_recursive(ctx, table);
+ break;
+ }
+ } else {
+ if (ctx->rc != GRN_SUCCESS) {
+ ERRCLR(ctx);
+ }
+ }
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ }
+ if (rc == GRN_SUCCESS) {
+ rc = grn_obj_flush(ctx, obj);
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ {
+ grn_hash *columns;
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (!columns) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)columns) > 0) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
+ grn_obj *column = grn_ctx_at(ctx, *key);
+ if (column) {
+ rc = grn_obj_flush(ctx, column);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ });
+ }
+ grn_hash_close(ctx, columns);
+ }
+
+ if (rc == GRN_SUCCESS) {
+ rc = grn_obj_flush(ctx, obj);
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ rc = grn_obj_flush(ctx, obj);
+ break;
+ default :
+ {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, obj);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[flush] object must be DB, table or column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ rc = ctx->rc;
+ GRN_OBJ_FIN(ctx, &inspected);
+ }
+ break;
+ }
+
+ GRN_API_RETURN(rc);
+}
+
+grn_obj *
+grn_obj_db(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_obj *db = NULL;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) { db = DB_OBJ(obj)->db; }
+ GRN_API_RETURN(db);
+}
+
+grn_id
+grn_obj_id(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_id id = GRN_ID_NIL;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) {
+ id = DB_OBJ(obj)->id;
+ }
+ GRN_API_RETURN(id);
+}
+
+int
+grn_obj_defrag(grn_ctx *ctx, grn_obj *obj, int threshold)
+{
+ int r = 0;
+ GRN_API_ENTER;
+ switch (obj->header.type) {
+ case GRN_DB:
+ {
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next_inline(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *ja = grn_ctx_at(ctx, id);
+ if (ja && ja->header.type == GRN_COLUMN_VAR_SIZE) {
+ r += grn_ja_defrag(ctx, (grn_ja *)ja, threshold);
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ {
+ grn_hash *cols;
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) {
+ r += grn_obj_defrag(ctx, col, threshold);
+ grn_obj_unlink(ctx, col);
+ }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+ }
+ break;
+ case GRN_COLUMN_VAR_SIZE:
+ r = grn_ja_defrag(ctx, (grn_ja *)obj, threshold);
+ break;
+ }
+ GRN_API_RETURN(r);
+}
+
+/**** sort ****/
+
+typedef struct {
+ grn_id id;
+ uint32_t size;
+ const void *value;
+} sort_reference_entry;
+
+enum {
+ KEY_ID = 0,
+ KEY_BULK,
+ KEY_INT8,
+ KEY_INT16,
+ KEY_INT32,
+ KEY_INT64,
+ KEY_UINT8,
+ KEY_UINT16,
+ KEY_UINT32,
+ KEY_UINT64,
+ KEY_FLOAT32,
+ KEY_FLOAT64,
+};
+
+#define CMPNUM(type) do {\
+ if (as) {\
+ if (bs) {\
+ type va = *((type *)(ap));\
+ type vb = *((type *)(bp));\
+ if (va != vb) { return va > vb; }\
+ } else {\
+ return 1;\
+ }\
+ } else {\
+ if (bs) { return 0; }\
+ }\
+} while (0)
+
+inline static int
+compare_reference(grn_ctx *ctx,
+ sort_reference_entry *a, sort_reference_entry *b,
+ grn_table_sort_key *keys, int n_keys)
+{
+ int i;
+ uint8_t type;
+ uint32_t as, bs;
+ const unsigned char *ap, *bp;
+ for (i = 0; i < n_keys; i++, keys++) {
+ if (i) {
+ const char *ap_raw, *bp_raw;
+ if (keys->flags & GRN_TABLE_SORT_DESC) {
+ ap_raw = grn_obj_get_value_(ctx, keys->key, b->id, &as);
+ bp_raw = grn_obj_get_value_(ctx, keys->key, a->id, &bs);
+ } else {
+ ap_raw = grn_obj_get_value_(ctx, keys->key, a->id, &as);
+ bp_raw = grn_obj_get_value_(ctx, keys->key, b->id, &bs);
+ }
+ ap = (const unsigned char *)ap_raw;
+ bp = (const unsigned char *)bp_raw;
+ } else {
+ if (keys->flags & GRN_TABLE_SORT_DESC) {
+ ap = b->value; as = b->size;
+ bp = a->value; bs = a->size;
+ } else {
+ ap = a->value; as = a->size;
+ bp = b->value; bs = b->size;
+ }
+ }
+ type = keys->offset;
+ switch (type) {
+ case KEY_ID :
+ if (ap != bp) { return ap > bp; }
+ break;
+ case KEY_BULK :
+ for (;; ap++, bp++, as--, bs--) {
+ if (!as) { if (bs) { return 0; } else { break; } }
+ if (!bs) { return 1; }
+ if (*ap < *bp) { return 0; }
+ if (*ap > *bp) { return 1; }
+ }
+ break;
+ case KEY_INT8 :
+ CMPNUM(int8_t);
+ break;
+ case KEY_INT16 :
+ CMPNUM(int16_t);
+ break;
+ case KEY_INT32 :
+ CMPNUM(int32_t);
+ break;
+ case KEY_INT64 :
+ CMPNUM(int64_t);
+ break;
+ case KEY_UINT8 :
+ CMPNUM(uint8_t);
+ break;
+ case KEY_UINT16 :
+ CMPNUM(uint16_t);
+ break;
+ case KEY_UINT32 :
+ CMPNUM(uint32_t);
+ break;
+ case KEY_UINT64 :
+ CMPNUM(uint64_t);
+ break;
+ case KEY_FLOAT32 :
+ if (as) {
+ if (bs) {
+ float va = *((float *)(ap));
+ float vb = *((float *)(bp));
+ if (va < vb || va > vb) { return va > vb; }
+ } else {
+ return 1;
+ }
+ } else {
+ if (bs) { return 0; }
+ }
+ break;
+ case KEY_FLOAT64 :
+ if (as) {
+ if (bs) {
+ double va = *((double *)(ap));
+ double vb = *((double *)(bp));
+ if (va < vb || va > vb) { return va > vb; }
+ } else {
+ return 1;
+ }
+ } else {
+ if (bs) { return 0; }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+inline static void
+swap_reference(sort_reference_entry *a, sort_reference_entry *b)
+{
+ sort_reference_entry c_ = *a;
+ *a = *b;
+ *b = c_;
+}
+
+inline static sort_reference_entry *
+part_reference(grn_ctx *ctx,
+ sort_reference_entry *b, sort_reference_entry *e,
+ grn_table_sort_key *keys, int n_keys)
+{
+ sort_reference_entry *c;
+ intptr_t d = e - b;
+ if (compare_reference(ctx, b, e, keys, n_keys)) {
+ swap_reference(b, e);
+ }
+ if (d < 2) { return NULL; }
+ c = b + (d >> 1);
+ if (compare_reference(ctx, b, c, keys, n_keys)) {
+ swap_reference(b, c);
+ } else {
+ if (compare_reference(ctx, c, e, keys, n_keys)) {
+ swap_reference(c, e);
+ }
+ }
+ if (d < 3) { return NULL; }
+ b++;
+ swap_reference(b, c);
+ c = b;
+ for (;;) {
+ do {
+ b++;
+ } while (compare_reference(ctx, c, b, keys, n_keys));
+ do {
+ e--;
+ } while (compare_reference(ctx, e, c, keys, n_keys));
+ if (b >= e) { break; }
+ swap_reference(b, e);
+ }
+ swap_reference(c, e);
+ return e;
+}
+
+static void
+sort_reference(grn_ctx *ctx,
+ sort_reference_entry *head, sort_reference_entry *tail,
+ int from, int to,
+ grn_table_sort_key *keys, int n_keys)
+{
+ sort_reference_entry *c;
+ if (head < tail && (c = part_reference(ctx, head, tail, keys, n_keys))) {
+ intptr_t m = c - head + 1;
+ if (from < m - 1) {
+ sort_reference(ctx, head, c - 1, from, to, keys, n_keys);
+ }
+ if (m < to) {
+ sort_reference(ctx, c + 1, tail, from - m, to - m, keys, n_keys);
+ }
+ }
+}
+
+static sort_reference_entry *
+pack_reference(grn_ctx *ctx, grn_obj *table,
+ sort_reference_entry *head, sort_reference_entry *tail,
+ grn_table_sort_key *keys, int n_keys)
+{
+ int i = 0;
+ sort_reference_entry e, c;
+ grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!tc) { return NULL; }
+ if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
+ c.value = grn_obj_get_value_(ctx, keys->key, c.id, &c.size);
+ while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
+ e.value = grn_obj_get_value_(ctx, keys->key, e.id, &e.size);
+ if (compare_reference(ctx, &c, &e, keys, n_keys)) {
+ *head++ = e;
+ } else {
+ *tail-- = e;
+ }
+ i++;
+ }
+ *head = c;
+ i++;
+ }
+ grn_table_cursor_close(ctx, tc);
+ return i > 2 ? head : NULL;
+}
+
+static int
+grn_table_sort_reference(grn_ctx *ctx, grn_obj *table,
+ int offset, int limit,
+ grn_obj *result,
+ grn_table_sort_key *keys, int n_keys)
+{
+ int e, n;
+ sort_reference_entry *array, *ep;
+ e = offset + limit;
+ n = grn_table_size(ctx, table);
+ if (!(array = GRN_MALLOC(sizeof(sort_reference_entry) * n))) {
+ return 0;
+ }
+ if ((ep = pack_reference(ctx, table, array, array + n - 1, keys, n_keys))) {
+ intptr_t m = ep - array + 1;
+ if (offset < m - 1) {
+ sort_reference(ctx, array, ep - 1, offset, e, keys, n_keys);
+ }
+ if (m < e) {
+ sort_reference(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys);
+ }
+ }
+ {
+ int i;
+ grn_id *v;
+ for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
+ if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
+ *v = ep->id;
+ }
+ GRN_FREE(array);
+ return i;
+ }
+}
+
+
+typedef struct {
+ grn_id id;
+ grn_obj value;
+} sort_value_entry;
+
+inline static int
+compare_value(grn_ctx *ctx,
+ sort_value_entry *a, sort_value_entry *b,
+ grn_table_sort_key *keys, int n_keys,
+ grn_obj *a_buffer, grn_obj *b_buffer)
+{
+ int i;
+ uint8_t type;
+ uint32_t as, bs;
+ const unsigned char *ap, *bp;
+ for (i = 0; i < n_keys; i++, keys++) {
+ if (i) {
+ GRN_BULK_REWIND(a_buffer);
+ GRN_BULK_REWIND(b_buffer);
+ if (keys->flags & GRN_TABLE_SORT_DESC) {
+ grn_obj_get_value(ctx, keys->key, b->id, a_buffer);
+ grn_obj_get_value(ctx, keys->key, a->id, b_buffer);
+ } else {
+ grn_obj_get_value(ctx, keys->key, a->id, a_buffer);
+ grn_obj_get_value(ctx, keys->key, b->id, b_buffer);
+ }
+ ap = (const unsigned char *)GRN_BULK_HEAD(a_buffer);
+ as = GRN_BULK_VSIZE(a_buffer);
+ bp = (const unsigned char *)GRN_BULK_HEAD(b_buffer);
+ bs = GRN_BULK_VSIZE(b_buffer);
+ } else {
+ if (keys->flags & GRN_TABLE_SORT_DESC) {
+ ap = (const unsigned char *)GRN_BULK_HEAD(&b->value);
+ as = GRN_BULK_VSIZE(&b->value);
+ bp = (const unsigned char *)GRN_BULK_HEAD(&a->value);
+ bs = GRN_BULK_VSIZE(&a->value);
+ } else {
+ ap = (const unsigned char *)GRN_BULK_HEAD(&a->value);
+ as = GRN_BULK_VSIZE(&a->value);
+ bp = (const unsigned char *)GRN_BULK_HEAD(&b->value);
+ bs = GRN_BULK_VSIZE(&b->value);
+ }
+ }
+ type = keys->offset;
+ switch (type) {
+ case KEY_ID :
+ if (ap != bp) { return ap > bp; }
+ break;
+ case KEY_BULK :
+ for (;; ap++, bp++, as--, bs--) {
+ if (!as) { if (bs) { return 0; } else { break; } }
+ if (!bs) { return 1; }
+ if (*ap < *bp) { return 0; }
+ if (*ap > *bp) { return 1; }
+ }
+ break;
+ case KEY_INT8 :
+ CMPNUM(int8_t);
+ break;
+ case KEY_INT16 :
+ CMPNUM(int16_t);
+ break;
+ case KEY_INT32 :
+ CMPNUM(int32_t);
+ break;
+ case KEY_INT64 :
+ CMPNUM(int64_t);
+ break;
+ case KEY_UINT8 :
+ CMPNUM(uint8_t);
+ break;
+ case KEY_UINT16 :
+ CMPNUM(uint16_t);
+ break;
+ case KEY_UINT32 :
+ CMPNUM(uint32_t);
+ break;
+ case KEY_UINT64 :
+ CMPNUM(uint64_t);
+ break;
+ case KEY_FLOAT32 :
+ if (as) {
+ if (bs) {
+ float va = *((float *)(ap));
+ float vb = *((float *)(bp));
+ if (va < vb || va > vb) { return va > vb; }
+ } else {
+ return 1;
+ }
+ } else {
+ if (bs) { return 0; }
+ }
+ break;
+ case KEY_FLOAT64 :
+ if (as) {
+ if (bs) {
+ double va = *((double *)(ap));
+ double vb = *((double *)(bp));
+ if (va < vb || va > vb) { return va > vb; }
+ } else {
+ return 1;
+ }
+ } else {
+ if (bs) { return 0; }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+inline static void
+swap_value(sort_value_entry *a, sort_value_entry *b)
+{
+ sort_value_entry c_ = *a;
+ *a = *b;
+ *b = c_;
+}
+
+inline static sort_value_entry *
+part_value(grn_ctx *ctx,
+ sort_value_entry *b, sort_value_entry *e,
+ grn_table_sort_key *keys, int n_keys,
+ grn_obj *a_buffer, grn_obj *b_buffer)
+{
+ sort_value_entry *c;
+ intptr_t d = e - b;
+ if (compare_value(ctx, b, e, keys, n_keys, a_buffer, b_buffer)) {
+ swap_value(b, e);
+ }
+ if (d < 2) { return NULL; }
+ c = b + (d >> 1);
+ if (compare_value(ctx, b, c, keys, n_keys, a_buffer, b_buffer)) {
+ swap_value(b, c);
+ } else {
+ if (compare_value(ctx, c, e, keys, n_keys, a_buffer, b_buffer)) {
+ swap_value(c, e);
+ }
+ }
+ if (d < 3) { return NULL; }
+ b++;
+ swap_value(b, c);
+ c = b;
+ for (;;) {
+ do {
+ b++;
+ } while (compare_value(ctx, c, b, keys, n_keys, a_buffer, b_buffer));
+ do {
+ e--;
+ } while (compare_value(ctx, e, c, keys, n_keys, a_buffer, b_buffer));
+ if (b >= e) { break; }
+ swap_value(b, e);
+ }
+ swap_value(c, e);
+ return e;
+}
+
+static void
+sort_value(grn_ctx *ctx,
+ sort_value_entry *head, sort_value_entry *tail,
+ int from, int to,
+ grn_table_sort_key *keys, int n_keys,
+ grn_obj *a_buffer, grn_obj *b_buffer)
+{
+ sort_value_entry *c;
+ if (head < tail && (c = part_value(ctx, head, tail, keys, n_keys,
+ a_buffer, b_buffer))) {
+ intptr_t m = c - head + 1;
+ if (from < m - 1) {
+ sort_value(ctx, head, c - 1, from, to, keys, n_keys, a_buffer, b_buffer);
+ }
+ if (m < to) {
+ sort_value(ctx, c + 1, tail, from - m, to - m, keys, n_keys,
+ a_buffer, b_buffer);
+ }
+ }
+}
+
+static sort_value_entry *
+pack_value(grn_ctx *ctx, grn_obj *table,
+ sort_value_entry *head, sort_value_entry *tail,
+ grn_table_sort_key *keys, int n_keys,
+ grn_obj *a_buffer, grn_obj *b_buffer)
+{
+ int i = 0;
+ sort_value_entry e, c;
+ grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!tc) { return NULL; }
+ if ((c.id = grn_table_cursor_next_inline(ctx, tc))) {
+ GRN_TEXT_INIT(&c.value, 0);
+ grn_obj_get_value(ctx, keys->key, c.id, &c.value);
+ while ((e.id = grn_table_cursor_next_inline(ctx, tc))) {
+ GRN_TEXT_INIT(&e.value, 0);
+ grn_obj_get_value(ctx, keys->key, e.id, &e.value);
+ if (compare_value(ctx, &c, &e, keys, n_keys, a_buffer, b_buffer)) {
+ *head++ = e;
+ } else {
+ *tail-- = e;
+ }
+ i++;
+ }
+ *head = c;
+ i++;
+ }
+ grn_table_cursor_close(ctx, tc);
+ return i > 2 ? head : NULL;
+}
+
+static int
+grn_table_sort_value(grn_ctx *ctx, grn_obj *table,
+ int offset, int limit,
+ grn_obj *result,
+ grn_table_sort_key *keys, int n_keys)
+{
+ int e, n;
+ sort_value_entry *array, *ep;
+ e = offset + limit;
+ n = grn_table_size(ctx, table);
+ if (!(array = GRN_MALLOC(sizeof(sort_value_entry) * n))) {
+ return 0;
+ }
+ {
+ grn_obj a_buffer;
+ grn_obj b_buffer;
+ GRN_TEXT_INIT(&a_buffer, 0);
+ GRN_TEXT_INIT(&b_buffer, 0);
+ if ((ep = pack_value(ctx, table, array, array + n - 1, keys, n_keys,
+ &a_buffer, &b_buffer))) {
+ intptr_t m = ep - array + 1;
+ if (offset < m - 1) {
+ sort_value(ctx, array, ep - 1, offset, e, keys, n_keys,
+ &a_buffer, &b_buffer);
+ }
+ if (m < e) {
+ sort_value(ctx, ep + 1, array + n - 1, offset - m, e - m, keys, n_keys,
+ &a_buffer, &b_buffer);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &a_buffer);
+ GRN_OBJ_FIN(ctx, &b_buffer);
+ }
+ {
+ int i;
+ grn_id *v;
+ for (i = 0, ep = array + offset; i < limit && ep < array + n; i++, ep++) {
+ if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
+ *v = ep->id;
+ }
+ GRN_FREE(array);
+ return i;
+ }
+}
+
+static grn_bool
+is_compressed_column(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_obj *target_obj;
+
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ if (obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a = (grn_accessor *)obj;
+ while (a->next) {
+ a = a->next;
+ }
+ target_obj = a->obj;
+ } else {
+ target_obj = obj;
+ }
+
+ if (target_obj->header.type != GRN_COLUMN_VAR_SIZE) {
+ return GRN_FALSE;
+ }
+
+ switch (target_obj->header.flags & GRN_OBJ_COMPRESS_MASK) {
+ case GRN_OBJ_COMPRESS_ZLIB :
+ case GRN_OBJ_COMPRESS_LZ4 :
+ case GRN_OBJ_COMPRESS_ZSTD :
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+}
+
+static grn_bool
+is_sub_record_accessor(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_accessor *accessor;
+
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ if (obj->header.type != GRN_ACCESSOR) {
+ return GRN_FALSE;
+ }
+
+ for (accessor = (grn_accessor *)obj; accessor; accessor = accessor->next) {
+ switch (accessor->action) {
+ case GRN_ACCESSOR_GET_VALUE :
+ if (GRN_TABLE_IS_MULTI_KEYS_GROUPED(accessor->obj)) {
+ return GRN_TRUE;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return GRN_FALSE;
+}
+
+static grn_bool
+is_encoded_pat_key_accessor(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_accessor *accessor;
+
+ if (!grn_obj_is_accessor(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ accessor = (grn_accessor *)obj;
+ while (accessor->next) {
+ accessor = accessor->next;
+ }
+
+ if (accessor->action != GRN_ACCESSOR_GET_KEY) {
+ return GRN_FALSE;
+ }
+
+ if (accessor->obj->header.type != GRN_TABLE_PAT_KEY) {
+ return GRN_FALSE;
+ }
+
+ return grn_pat_is_key_encoded(ctx, (grn_pat *)(accessor->obj));
+}
+
+static int
+range_is_idp(grn_obj *obj)
+{
+ if (obj && obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a;
+ for (a = (grn_accessor *)obj; a; a = a->next) {
+ if (a->action == GRN_ACCESSOR_GET_ID) { return 1; }
+ }
+ }
+ return 0;
+}
+
+int
+grn_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit,
+ grn_obj *result, grn_table_sort_key *keys, int n_keys)
+{
+ grn_rc rc;
+ grn_obj *index;
+ int n, e, i = 0;
+ GRN_API_ENTER;
+ if (!n_keys || !keys) {
+ WARN(GRN_INVALID_ARGUMENT, "keys is null");
+ goto exit;
+ }
+ if (!table) {
+ WARN(GRN_INVALID_ARGUMENT, "table is null");
+ goto exit;
+ }
+ if (!(result && result->header.type == GRN_TABLE_NO_KEY)) {
+ WARN(GRN_INVALID_ARGUMENT, "result is not a array");
+ goto exit;
+ }
+ n = grn_table_size(ctx, table);
+ if ((rc = grn_normalize_offset_and_limit(ctx, n, &offset, &limit))) {
+ ERR(rc, "grn_normalize_offset_and_limit failed");
+ goto exit;
+ } else {
+ e = offset + limit;
+ }
+ if (keys->flags & GRN_TABLE_SORT_GEO) {
+ if (n_keys == 2) {
+ i = grn_geo_table_sort(ctx, table, offset, limit, result,
+ keys[0].key, keys[1].key);
+ } else {
+ i = 0;
+ }
+ goto exit;
+ }
+ if (n_keys == 1 && !GRN_ACCESSORP(keys->key) &&
+ grn_column_index(ctx, keys->key, GRN_OP_LESS, &index, 1, NULL)) {
+ grn_id tid;
+ grn_pat *lexicon = (grn_pat *)grn_ctx_at(ctx, index->header.domain);
+ grn_pat_cursor *pc = grn_pat_cursor_open(ctx, lexicon, NULL, 0, NULL, 0,
+ 0 /* offset : can be used in unique index */,
+ -1 /* limit : can be used in unique index */,
+ (keys->flags & GRN_TABLE_SORT_DESC)
+ ? GRN_CURSOR_DESCENDING
+ : GRN_CURSOR_ASCENDING);
+ if (pc) {
+ while (i < e && (tid = grn_pat_cursor_next(ctx, pc))) {
+ grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
+ if (ic) {
+ grn_posting *posting;
+ while (i < e && (posting = grn_ii_cursor_next(ctx, ic))) {
+ if (offset <= i) {
+ grn_id *v;
+ if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
+ *v = posting->rid;
+ }
+ i++;
+ }
+ grn_ii_cursor_close(ctx, ic);
+ }
+ }
+ grn_pat_cursor_close(ctx, pc);
+ }
+ } else {
+ int j;
+ grn_bool have_compressed_column = GRN_FALSE;
+ grn_bool have_sub_record_accessor = GRN_FALSE;
+ grn_bool have_encoded_pat_key_accessor = GRN_FALSE;
+ grn_bool have_index_value_get = GRN_FALSE;
+ grn_table_sort_key *kp;
+ for (kp = keys, j = n_keys; j; kp++, j--) {
+ if (is_compressed_column(ctx, kp->key)) {
+ have_compressed_column = GRN_TRUE;
+ }
+ if (is_sub_record_accessor(ctx, kp->key)) {
+ have_sub_record_accessor = GRN_TRUE;
+ }
+ if (is_encoded_pat_key_accessor(ctx, kp->key)) {
+ have_encoded_pat_key_accessor = GRN_TRUE;
+ }
+ if (range_is_idp(kp->key)) {
+ kp->offset = KEY_ID;
+ } else {
+ grn_obj *range = grn_ctx_at(ctx, grn_obj_get_range(ctx, kp->key));
+ if (range->header.type == GRN_TYPE) {
+ if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ kp->offset = KEY_BULK;
+ } else {
+ uint8_t key_type = range->header.flags & GRN_OBJ_KEY_MASK;
+ switch (key_type) {
+ case GRN_OBJ_KEY_UINT :
+ case GRN_OBJ_KEY_GEO_POINT :
+ switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
+ case 1 :
+ kp->offset = KEY_UINT8;
+ break;
+ case 2 :
+ kp->offset = KEY_UINT16;
+ break;
+ case 4 :
+ kp->offset = KEY_UINT32;
+ break;
+ case 8 :
+ kp->offset = KEY_UINT64;
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "unsupported uint value");
+ goto exit;
+ }
+ break;
+ case GRN_OBJ_KEY_INT :
+ switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
+ case 1 :
+ kp->offset = KEY_INT8;
+ break;
+ case 2 :
+ kp->offset = KEY_INT16;
+ break;
+ case 4 :
+ kp->offset = KEY_INT32;
+ break;
+ case 8 :
+ kp->offset = KEY_INT64;
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "unsupported int value");
+ goto exit;
+ }
+ break;
+ case GRN_OBJ_KEY_FLOAT :
+ switch (GRN_TYPE_SIZE(DB_OBJ(range))) {
+ case 4 :
+ kp->offset = KEY_FLOAT32;
+ break;
+ case 8 :
+ kp->offset = KEY_FLOAT64;
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "unsupported float value");
+ goto exit;
+ }
+ break;
+ }
+ }
+ } else {
+ if (kp->key->header.type == GRN_COLUMN_INDEX) {
+ have_index_value_get = GRN_TRUE;
+ }
+ kp->offset = KEY_UINT32;
+ }
+ }
+ }
+ if (have_compressed_column ||
+ have_sub_record_accessor ||
+ have_encoded_pat_key_accessor ||
+ have_index_value_get) {
+ i = grn_table_sort_value(ctx, table, offset, limit, result,
+ keys, n_keys);
+ } else {
+ i = grn_table_sort_reference(ctx, table, offset, limit, result,
+ keys, n_keys);
+ }
+ }
+exit :
+ GRN_API_RETURN(i);
+}
+
+static grn_obj *
+deftype(grn_ctx *ctx, const char *name,
+ grn_obj_flags flags, unsigned int size)
+{
+ grn_obj *o = grn_ctx_get(ctx, name, strlen(name));
+ if (!o) { o = grn_type_create(ctx, name, strlen(name), flags, size); }
+ return o;
+}
+
+grn_rc
+grn_db_init_builtin_types(grn_ctx *ctx)
+{
+ grn_id id;
+ grn_obj *obj, *db = ctx->impl->db;
+ char buf[] = "Sys00";
+ grn_obj_register(ctx, db, buf, 5);
+ obj = deftype(ctx, "Object",
+ GRN_OBJ_KEY_UINT, sizeof(uint64_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_OBJECT) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Bool",
+ GRN_OBJ_KEY_UINT, sizeof(uint8_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_BOOL) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Int8",
+ GRN_OBJ_KEY_INT, sizeof(int8_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_INT8) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "UInt8",
+ GRN_OBJ_KEY_UINT, sizeof(uint8_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT8) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Int16",
+ GRN_OBJ_KEY_INT, sizeof(int16_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_INT16) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "UInt16",
+ GRN_OBJ_KEY_UINT, sizeof(uint16_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT16) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Int32",
+ GRN_OBJ_KEY_INT, sizeof(int32_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_INT32) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "UInt32",
+ GRN_OBJ_KEY_UINT, sizeof(uint32_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT32) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Int64",
+ GRN_OBJ_KEY_INT, sizeof(int64_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_INT64) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "UInt64",
+ GRN_OBJ_KEY_UINT, sizeof(uint64_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_UINT64) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Float",
+ GRN_OBJ_KEY_FLOAT, sizeof(double));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_FLOAT) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Time",
+ GRN_OBJ_KEY_INT, sizeof(int64_t));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_TIME) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "ShortText",
+ GRN_OBJ_KEY_VAR_SIZE, GRN_TABLE_MAX_KEY_SIZE);
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_SHORT_TEXT) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "Text",
+ GRN_OBJ_KEY_VAR_SIZE, 1 << 16);
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_TEXT) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "LongText",
+ GRN_OBJ_KEY_VAR_SIZE, 1U << 31);
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_LONG_TEXT) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "TokyoGeoPoint",
+ GRN_OBJ_KEY_GEO_POINT, sizeof(grn_geo_point));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_TOKYO_GEO_POINT) { return GRN_FILE_CORRUPT; }
+ obj = deftype(ctx, "WGS84GeoPoint",
+ GRN_OBJ_KEY_GEO_POINT, sizeof(grn_geo_point));
+ if (!obj || DB_OBJ(obj)->id != GRN_DB_WGS84_GEO_POINT) { return GRN_FILE_CORRUPT; }
+ for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_DB_MECAB; id++) {
+ grn_itoh(id, buf + 3, 2);
+ grn_obj_register(ctx, db, buf, 5);
+ }
+#ifdef GRN_WITH_MECAB
+ if (grn_db_init_mecab_tokenizer(ctx)) {
+ ERRCLR(ctx);
+#endif
+ grn_obj_register(ctx, db, "TokenMecab", 10);
+#ifdef GRN_WITH_MECAB
+ }
+#endif
+ grn_db_init_builtin_tokenizers(ctx);
+ grn_db_init_builtin_normalizers(ctx);
+ grn_db_init_builtin_scorers(ctx);
+ for (id = grn_db_curr_id(ctx, db) + 1; id < 128; id++) {
+ grn_itoh(id, buf + 3, 2);
+ grn_obj_register(ctx, db, buf, 5);
+ }
+ grn_db_init_builtin_commands(ctx);
+ grn_db_init_builtin_window_functions(ctx);
+ for (id = grn_db_curr_id(ctx, db) + 1; id < GRN_N_RESERVED_TYPES; id++) {
+ grn_itoh(id, buf + 3, 2);
+ grn_obj_register(ctx, db, buf, 5);
+ }
+ return ctx->rc;
+}
+
+#define MULTI_COLUMN_INDEXP(i) (DB_OBJ(i)->source_size > sizeof(grn_id))
+
+static grn_obj *
+grn_index_column_get_tokenizer(grn_ctx *ctx, grn_obj *index_column)
+{
+ grn_obj *tokenizer;
+ grn_obj *lexicon;
+
+ lexicon = grn_ctx_at(ctx, index_column->header.domain);
+ if (!lexicon) {
+ return NULL;
+ }
+
+ grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
+ return tokenizer;
+}
+
+static grn_bool
+is_full_text_searchable_index(grn_ctx *ctx, grn_obj *index_column)
+{
+ grn_obj *tokenizer;
+
+ tokenizer = grn_index_column_get_tokenizer(ctx, index_column);
+ return tokenizer != NULL;
+}
+
+static int
+grn_column_find_index_data_column_equal(grn_ctx *ctx, grn_obj *obj,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned int n_index_data,
+ grn_obj **index_buf, int buf_size,
+ int *section_buf)
+{
+ int n = 0;
+ grn_obj **ip = index_buf;
+ grn_hook *hooks;
+
+ for (hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ int section;
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if (obj->header.type != GRN_COLUMN_FIX_SIZE) {
+ if (is_full_text_searchable_index(ctx, target)) { continue; }
+ }
+ section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
+ if (section_buf) { *section_buf = section; }
+ if (n < buf_size) {
+ *ip++ = target;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+
+ return n;
+}
+
+static grn_bool
+is_valid_regexp_index(grn_ctx *ctx, grn_obj *index_column)
+{
+ grn_obj *tokenizer;
+
+ tokenizer = grn_index_column_get_tokenizer(ctx, index_column);
+ /* TODO: Restrict to TokenRegexp? */
+ return tokenizer != NULL;
+}
+
+static int
+grn_column_find_index_data_column_match(grn_ctx *ctx, grn_obj *obj,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned int n_index_data,
+ grn_obj **index_buf, int buf_size,
+ int *section_buf)
+{
+ int n = 0;
+ grn_obj **ip = index_buf;
+ grn_hook_entry hook_entry;
+ grn_hook *hooks;
+ grn_bool prefer_full_text_search_index = GRN_FALSE;
+
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ hook_entry = GRN_HOOK_INSERT;
+ break;
+ default :
+ hook_entry = GRN_HOOK_SET;
+ break;
+ }
+
+ if (op != GRN_OP_REGEXP && !grn_column_is_vector(ctx, obj)) {
+ prefer_full_text_search_index = GRN_TRUE;
+ }
+
+ if (prefer_full_text_search_index) {
+ for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ int section;
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if (!is_full_text_searchable_index(ctx, target)) { continue; }
+ section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
+ if (section_buf) { *section_buf = section; }
+ if (n < buf_size) {
+ *ip++ = target;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+ }
+
+ for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ int section;
+
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ if (op == GRN_OP_REGEXP && !is_valid_regexp_index(ctx, target)) {
+ continue;
+ }
+
+ if (prefer_full_text_search_index) {
+ if (is_full_text_searchable_index(ctx, target)) { continue; }
+ }
+
+ section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
+ if (section_buf) { *section_buf = section; }
+ if (n < buf_size) {
+ *ip++ = target;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+
+ return n;
+}
+
+static int
+grn_column_find_index_data_column_range(grn_ctx *ctx, grn_obj *obj,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned int n_index_data,
+ grn_obj **index_buf, int buf_size,
+ int *section_buf)
+{
+ int n = 0;
+ grn_obj **ip = index_buf;
+ grn_hook_entry hook_entry;
+ grn_hook *hooks;
+
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ hook_entry = GRN_HOOK_INSERT;
+ break;
+ default :
+ hook_entry = GRN_HOOK_SET;
+ break;
+ }
+
+ for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ int section;
+ if (!target) { continue; }
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+ section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
+ if (section_buf) { *section_buf = section; }
+ {
+ grn_obj *tokenizer, *lexicon = grn_ctx_at(ctx, target->header.domain);
+ if (!lexicon) { continue; }
+ if (lexicon->header.type != GRN_TABLE_PAT_KEY) { continue; }
+ /* FIXME: GRN_TABLE_DAT_KEY should be supported */
+ grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
+ if (tokenizer) { continue; }
+ }
+ if (n < buf_size) {
+ *ip++ = target;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+
+ return n;
+}
+
+static grn_bool
+is_valid_match_index(grn_ctx *ctx, grn_obj *index_column)
+{
+ return GRN_TRUE;
+}
+
+static grn_bool
+is_valid_range_index(grn_ctx *ctx, grn_obj *index_column)
+{
+ grn_obj *tokenizer;
+ grn_obj *lexicon;
+
+ lexicon = grn_ctx_at(ctx, index_column->header.domain);
+ if (!lexicon) { return GRN_FALSE; }
+ /* FIXME: GRN_TABLE_DAT_KEY should be supported */
+ if (lexicon->header.type != GRN_TABLE_PAT_KEY) {
+ grn_obj_unlink(ctx, lexicon);
+ return GRN_FALSE;
+ }
+
+ grn_table_get_info(ctx, lexicon, NULL, NULL, &tokenizer, NULL, NULL);
+ grn_obj_unlink(ctx, lexicon);
+ if (tokenizer) { return GRN_FALSE; }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+is_valid_index(grn_ctx *ctx, grn_obj *index_column, grn_operator op)
+{
+ switch (op) {
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ return is_valid_match_index(ctx, index_column);
+ break;
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_CALL :
+ return is_valid_range_index(ctx, index_column);
+ break;
+ case GRN_OP_REGEXP :
+ return is_valid_regexp_index(ctx, index_column);
+ break;
+ default :
+ return GRN_FALSE;
+ break;
+ }
+}
+
+static int
+find_section(grn_ctx *ctx, grn_obj *index_column, grn_obj *indexed_column)
+{
+ int section = 0;
+ grn_id indexed_column_id;
+ grn_id *source_ids;
+ int i, n_source_ids;
+
+ indexed_column_id = DB_OBJ(indexed_column)->id;
+
+ source_ids = DB_OBJ(index_column)->source;
+ n_source_ids = DB_OBJ(index_column)->source_size / sizeof(grn_id);
+ for (i = 0; i < n_source_ids; i++) {
+ grn_id source_id = source_ids[i];
+ if (source_id == indexed_column_id) {
+ section = i + 1;
+ break;
+ }
+ }
+
+ return section;
+}
+
+static int
+grn_column_find_index_data_accessor_index_column(grn_ctx *ctx, grn_accessor *a,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned int n_index_data,
+ grn_obj **index_buf,
+ int buf_size,
+ int *section_buf)
+{
+ grn_obj *index_column = a->obj;
+ int section = 0;
+
+ if (!is_valid_index(ctx, index_column, op)) {
+ return 0;
+ }
+
+ if (a->next) {
+ int specified_section;
+ grn_bool is_invalid_section;
+ if (a->next->next) {
+ return 0;
+ }
+ specified_section = find_section(ctx, index_column, a->next->obj);
+ is_invalid_section = (specified_section == 0);
+ if (is_invalid_section) {
+ return 0;
+ }
+ section = specified_section;
+ if (section_buf) {
+ *section_buf = section;
+ }
+ }
+ if (buf_size > 0) {
+ *index_buf = index_column;
+ }
+ if (n_index_data > 0) {
+ index_data[0].index = index_column;
+ index_data[0].section = section;
+ }
+
+ return 1;
+}
+
+static grn_bool
+grn_column_find_index_data_accessor_is_key_search(grn_ctx *ctx,
+ grn_accessor *accessor,
+ grn_operator op)
+{
+ if (accessor->next) {
+ return GRN_FALSE;
+ }
+
+ if (accessor->action != GRN_ACCESSOR_GET_KEY) {
+ return GRN_FALSE;
+ }
+
+ if (!grn_obj_is_table(ctx, accessor->obj)) {
+ return GRN_FALSE;
+ }
+
+ switch (op) {
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ switch (accessor->obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+ case GRN_OP_EQUAL :
+ switch (accessor->obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+ default :
+ return GRN_FALSE;
+ }
+}
+
+static int
+grn_column_find_index_data_accessor_match(grn_ctx *ctx, grn_obj *obj,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned n_index_data,
+ grn_obj **index_buf, int buf_size,
+ int *section_buf)
+{
+ int n = 0;
+ grn_obj **ip = index_buf;
+ grn_accessor *a = (grn_accessor *)obj;
+
+ while (a) {
+ grn_hook *hooks;
+ grn_bool found = GRN_FALSE;
+ grn_hook_entry entry = (grn_hook_entry)-1;
+
+ if (a->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
+ GRN_OBJ_INDEX_COLUMNP(a->obj)) {
+ return grn_column_find_index_data_accessor_index_column(ctx, a, op,
+ index_data,
+ n_index_data,
+ index_buf,
+ buf_size,
+ section_buf);
+ }
+
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_KEY :
+ entry = GRN_HOOK_INSERT;
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ entry = GRN_HOOK_SET;
+ break;
+ default :
+ break;
+ }
+
+ if (entry == (grn_hook_entry)-1) {
+ break;
+ }
+
+ for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+
+ if (target->header.type != GRN_COLUMN_INDEX) { continue; }
+
+ found = GRN_TRUE;
+ if (!a->next) {
+ int section;
+
+ if (!is_valid_index(ctx, target, op)) {
+ continue;
+ }
+
+ section = (MULTI_COLUMN_INDEXP(target)) ? data->section : 0;
+ if (section_buf) {
+ *section_buf = section;
+ }
+ if (n < buf_size) {
+ *ip++ = target;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+ }
+
+ if (!found &&
+ grn_column_find_index_data_accessor_is_key_search(ctx, a, op)) {
+ grn_obj *index;
+ int section = 0;
+
+ if ((grn_obj *)a == obj) {
+ index = a->obj;
+ } else {
+ index = (grn_obj *)a;
+ }
+
+ found = GRN_TRUE;
+ if (section_buf) {
+ *section_buf = section;
+ }
+ if (n < buf_size) {
+ *ip++ = index;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = index;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+
+ if (!found &&
+ a->next &&
+ grn_obj_is_table(ctx, a->obj) &&
+ a->obj->header.domain == a->next->obj->header.domain) {
+ grn_obj *index = (grn_obj *)a;
+ int section = 0;
+
+ found = GRN_TRUE;
+ if (section_buf) {
+ *section_buf = section;
+ }
+ if (n < buf_size) {
+ *ip++ = index;
+ }
+ if ((unsigned int) n < n_index_data) {
+ index_data[n].index = index;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+
+ if (!found) {
+ break;
+ }
+ a = a->next;
+ }
+
+ return n;
+}
+
+static int
+grn_column_find_index_data_accessor(grn_ctx *ctx, grn_obj *obj,
+ grn_operator op,
+ grn_index_datum *index_data,
+ unsigned n_index_data,
+ grn_obj **index_buf, int buf_size,
+ int *section_buf)
+{
+ int n = 0;
+
+ if (section_buf) {
+ *section_buf = 0;
+ }
+ switch (op) {
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_TERM_EXTRACT :
+ if (buf_size > 0) {
+ index_buf[n] = obj;
+ }
+ if (n_index_data > 0) {
+ index_data[n].index = obj;
+ index_data[n].section = 0;
+ }
+ n++;
+ break;
+ case GRN_OP_PREFIX :
+ {
+ grn_accessor *a = (grn_accessor *)obj;
+ if (a->action == GRN_ACCESSOR_GET_KEY) {
+ if (a->obj->header.type == GRN_TABLE_PAT_KEY) {
+ if (buf_size > 0) {
+ index_buf[n] = obj;
+ }
+ if (n_index_data > 0) {
+ index_data[n].index = obj;
+ index_data[n].section = 0;
+ }
+ n++;
+ }
+ /* FIXME: GRN_TABLE_DAT_KEY should be supported */
+ }
+ }
+ break;
+ case GRN_OP_SUFFIX :
+ {
+ grn_accessor *a = (grn_accessor *)obj;
+ if (a->action == GRN_ACCESSOR_GET_KEY) {
+ if (a->obj->header.type == GRN_TABLE_PAT_KEY &&
+ a->obj->header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ if (buf_size > 0) {
+ index_buf[n] = obj;
+ }
+ if (n_index_data > 0) {
+ index_data[n].index = obj;
+ index_data[n].section = 0;
+ }
+ n++;
+ }
+ }
+ }
+ break;
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_CALL :
+ case GRN_OP_REGEXP :
+ case GRN_OP_FUZZY :
+ n = grn_column_find_index_data_accessor_match(ctx, obj, op,
+ index_data, n_index_data,
+ index_buf, buf_size,
+ section_buf);
+ break;
+ default :
+ break;
+ }
+
+ return n;
+}
+
+int
+grn_column_index(grn_ctx *ctx, grn_obj *obj, grn_operator op,
+ grn_obj **index_buf, int buf_size, int *section_buf)
+{
+ int n = 0;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) {
+ switch (op) {
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ n = grn_column_find_index_data_column_equal(ctx, obj, op,
+ NULL, 0,
+ index_buf, buf_size,
+ section_buf);
+ break;
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_REGEXP :
+ case GRN_OP_FUZZY :
+ n = grn_column_find_index_data_column_match(ctx, obj, op,
+ NULL, 0,
+ index_buf, buf_size,
+ section_buf);
+ break;
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_CALL :
+ n = grn_column_find_index_data_column_range(ctx, obj, op,
+ NULL, 0,
+ index_buf, buf_size,
+ section_buf);
+ break;
+ default :
+ break;
+ }
+ } else if (GRN_ACCESSORP(obj)) {
+ n = grn_column_find_index_data_accessor(ctx, obj, op,
+ NULL, 0,
+ index_buf, buf_size,
+ section_buf);
+ }
+ GRN_API_RETURN(n);
+}
+
+unsigned int
+grn_column_find_index_data(grn_ctx *ctx, grn_obj *obj, grn_operator op,
+ grn_index_datum *index_data,
+ unsigned int n_index_data)
+{
+ unsigned int n = 0;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) {
+ switch (op) {
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ n = grn_column_find_index_data_column_equal(ctx, obj, op,
+ index_data, n_index_data,
+ NULL, 0, NULL);
+ break;
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_REGEXP :
+ case GRN_OP_FUZZY :
+ n = grn_column_find_index_data_column_match(ctx, obj, op,
+ index_data, n_index_data,
+ NULL, 0, NULL);
+ break;
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_CALL :
+ n = grn_column_find_index_data_column_range(ctx, obj, op,
+ index_data, n_index_data,
+ NULL, 0, NULL);
+ break;
+ default :
+ break;
+ }
+ } else if (GRN_ACCESSORP(obj)) {
+ n = grn_column_find_index_data_accessor(ctx, obj, op,
+ index_data, n_index_data,
+ NULL, 0, NULL);
+ }
+ GRN_API_RETURN(n);
+}
+
+static uint32_t
+grn_column_get_all_index_data_column(grn_ctx *ctx,
+ grn_obj *obj,
+ grn_index_datum *index_data,
+ uint32_t n_index_data)
+{
+ uint32_t n = 0;
+ grn_hook_entry hook_entry;
+ grn_hook *hooks;
+
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ hook_entry = GRN_HOOK_INSERT;
+ break;
+ default :
+ hook_entry = GRN_HOOK_SET;
+ break;
+ }
+
+ for (hooks = DB_OBJ(obj)->hooks[hook_entry]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ int section = 0;
+ if (!target) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int length;
+ char hook_name[GRN_TABLE_MAX_KEY_SIZE];
+ int hook_name_length;
+
+ length = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
+ hook_name_length = grn_table_get_key(ctx,
+ ctx->impl->db,
+ data->target,
+ hook_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "[column][indexes][all] "
+ "hook has a dangling reference: <%.*s> -> <%.*s>",
+ length, name,
+ hook_name_length, hook_name);
+ continue;
+ }
+ if (target->header.type != GRN_COLUMN_INDEX) {
+ continue;
+ }
+ if (MULTI_COLUMN_INDEXP(target)) {
+ section = data->section;
+ }
+ if (n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+
+ return n;
+}
+
+static uint32_t
+grn_column_get_all_index_data_accessor_index_column(grn_ctx *ctx,
+ grn_accessor *a,
+ grn_index_datum *index_data,
+ uint32_t n_index_data)
+{
+ grn_obj *index_column = a->obj;
+ int section = 0;
+
+ if (a->next) {
+ int specified_section;
+ grn_bool is_invalid_section;
+ if (a->next->next) {
+ return 0;
+ }
+ specified_section = find_section(ctx, index_column, a->next->obj);
+ is_invalid_section = (specified_section == 0);
+ if (is_invalid_section) {
+ return 0;
+ }
+ section = specified_section;
+ }
+ if (n_index_data > 0) {
+ index_data[0].index = index_column;
+ index_data[0].section = section;
+ }
+
+ return 1;
+}
+
+static uint32_t
+grn_column_get_all_index_data_accessor(grn_ctx *ctx,
+ grn_obj *obj,
+ grn_index_datum *index_data,
+ uint32_t n_index_data)
+{
+ uint32_t n = 0;
+ grn_accessor *a = (grn_accessor *)obj;
+
+ while (a) {
+ grn_hook *hooks;
+ grn_bool found = GRN_FALSE;
+ grn_hook_entry entry = (grn_hook_entry)-1;
+
+ if (a->action == GRN_ACCESSOR_GET_COLUMN_VALUE &&
+ GRN_OBJ_INDEX_COLUMNP(a->obj)) {
+ return grn_column_get_all_index_data_accessor_index_column(ctx,
+ a,
+ index_data,
+ n_index_data);
+ }
+
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_KEY :
+ entry = GRN_HOOK_INSERT;
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ entry = GRN_HOOK_SET;
+ break;
+ default :
+ break;
+ }
+
+ if (entry == (grn_hook_entry)-1) {
+ break;
+ }
+
+ for (hooks = DB_OBJ(a->obj)->hooks[entry]; hooks; hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+
+ if (target->header.type != GRN_COLUMN_INDEX) {
+ continue;
+ }
+
+ found = GRN_TRUE;
+ if (!a->next) {
+ int section = 0;
+
+ if (MULTI_COLUMN_INDEXP(target)) {
+ section = data->section;
+ }
+ if (n < n_index_data) {
+ index_data[n].index = target;
+ index_data[n].section = section;
+ }
+ n++;
+ }
+ }
+
+ if (!found) {
+ break;
+ }
+ a = a->next;
+ }
+
+ return n;
+}
+
+uint32_t
+grn_column_get_all_index_data(grn_ctx *ctx,
+ grn_obj *obj,
+ grn_index_datum *index_data,
+ uint32_t n_index_data)
+{
+ uint32_t n = 0;
+ GRN_API_ENTER;
+ if (GRN_DB_OBJP(obj)) {
+ n = grn_column_get_all_index_data_column(ctx, obj,
+ index_data, n_index_data);
+ } else if (GRN_ACCESSORP(obj)) {
+ n = grn_column_get_all_index_data_accessor(ctx, obj,
+ index_data, n_index_data);
+ }
+ GRN_API_RETURN(n);
+}
+
+grn_rc
+grn_obj_columns(grn_ctx *ctx, grn_obj *table,
+ const char *str, unsigned int str_size, grn_obj *res)
+{
+ grn_obj *col;
+ const char *p = (char *)str, *q, *r, *pe = p + str_size, *tokbuf[256];
+ while (p < pe) {
+ int i, n = grn_tokenize(p, pe - p, tokbuf, 256, &q);
+ for (i = 0; i < n; i++) {
+ r = tokbuf[i];
+ while (p < r && (' ' == *p || ',' == *p)) { p++; }
+ if (p < r) {
+ if (r[-1] == '*') {
+ grn_hash *cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (cols) {
+ grn_id *key;
+ grn_table_columns(ctx, table, p, r - p - 1, (grn_obj *)cols);
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ if ((col = grn_ctx_at(ctx, *key))) { GRN_PTR_PUT(ctx, res, col); }
+ });
+ grn_hash_close(ctx, cols);
+ }
+ {
+ grn_obj *type = grn_ctx_at(ctx, table->header.domain);
+ if (GRN_OBJ_TABLEP(type)) {
+ grn_obj *ai = grn_obj_column(ctx, table,
+ GRN_COLUMN_NAME_ID,
+ GRN_COLUMN_NAME_ID_LEN);
+ if (ai) {
+ if (ai->header.type == GRN_ACCESSOR) {
+ grn_id *key;
+ grn_accessor *id_accessor;
+ for (id_accessor = ((grn_accessor *)ai)->next;
+ id_accessor;
+ id_accessor = id_accessor->next) {
+ grn_obj *target_table = id_accessor->obj;
+
+ cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (!cols) {
+ continue;
+ }
+ grn_table_columns(ctx, target_table,
+ p, r - p - 1, (grn_obj *)cols);
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ if ((col = grn_ctx_at(ctx, *key))) {
+ grn_accessor *a;
+ grn_accessor *ac;
+ ac = accessor_new(ctx);
+ GRN_PTR_PUT(ctx, res, (grn_obj *)ac);
+ for (a = (grn_accessor *)ai; a; a = a->next) {
+ if (a->action != GRN_ACCESSOR_GET_ID) {
+ ac->action = a->action;
+ ac->obj = a->obj;
+ ac->next = accessor_new(ctx);
+ if (!(ac = ac->next)) { break; }
+ } else {
+ ac->action = GRN_ACCESSOR_GET_COLUMN_VALUE;
+ ac->obj = col;
+ ac->next = NULL;
+ break;
+ }
+ }
+ }
+ });
+ grn_hash_close(ctx, cols);
+ }
+ }
+ grn_obj_unlink(ctx, ai);
+ }
+ }
+ }
+ } else if ((col = grn_obj_column(ctx, table, p, r - p))) {
+ GRN_PTR_PUT(ctx, res, col);
+ }
+ }
+ p = r;
+ }
+ p = q;
+ }
+ return ctx->rc;
+}
+
+static grn_table_sort_key *
+grn_table_sort_key_from_str_geo(grn_ctx *ctx, const char *str, unsigned int str_size,
+ grn_obj *table, unsigned int *nkeys)
+{
+ const char **tokbuf;
+ const char *p = str, *pe = str + str_size;
+ grn_table_sort_key *keys = NULL, *k = NULL;
+ while ((*p++ != '(')) { if (p == pe) { return NULL; } }
+ str = p;
+ while ((*p != ')')) { if (++p == pe) { return NULL; } }
+ str_size = p - str;
+ p = str;
+ if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
+ grn_id domain = GRN_ID_NIL;
+ int i, n = grn_tokenize(str, str_size, tokbuf, str_size, NULL);
+ if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
+ k = keys;
+ for (i = 0; i < n; i++) {
+ const char *r = tokbuf[i];
+ while (p < r && (' ' == *p || ',' == *p)) { p++; }
+ if (p < r) {
+ k->flags = GRN_TABLE_SORT_ASC;
+ k->offset = 0;
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ k->flags = GRN_TABLE_SORT_DESC;
+ p++;
+ }
+ if (k == keys) {
+ if (!(k->key = grn_obj_column(ctx, table, p, r - p))) {
+ WARN(GRN_INVALID_ARGUMENT, "invalid sort key: <%.*s>(<%.*s>)",
+ (int)(tokbuf[i] - p), p, str_size, str);
+ break;
+ }
+ domain = grn_obj_get_range(ctx, k->key);
+ } else {
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, &buf, p + 1, r - p - 2); /* should be quoted */
+ k->key = grn_obj_open(ctx, GRN_BULK, 0, domain);
+ grn_obj_cast(ctx, &buf, k->key, GRN_FALSE);
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ k->flags |= GRN_TABLE_SORT_GEO;
+ k++;
+ }
+ p = r;
+ }
+ }
+ GRN_FREE(tokbuf);
+ }
+ if (!ctx->rc && k - keys > 0) {
+ *nkeys = k - keys;
+ } else {
+ grn_table_sort_key_close(ctx, keys, k - keys);
+ *nkeys = 0;
+ keys = NULL;
+ }
+ return keys;
+}
+
+grn_table_sort_key *
+grn_table_sort_key_from_str(grn_ctx *ctx, const char *str, unsigned int str_size,
+ grn_obj *table, unsigned int *nkeys)
+{
+ const char *p = str;
+ const char **tokbuf;
+ grn_table_sort_key *keys = NULL, *k = NULL;
+
+ if (str_size == 0) {
+ return NULL;
+ }
+
+ if ((keys = grn_table_sort_key_from_str_geo(ctx, str, str_size, table, nkeys))) {
+ return keys;
+ }
+ if ((tokbuf = GRN_MALLOCN(const char *, str_size))) {
+ int i, n = grn_tokenize(str, str_size, tokbuf, str_size, NULL);
+ if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
+ k = keys;
+ for (i = 0; i < n; i++) {
+ const char *r = tokbuf[i];
+ while (p < r && (' ' == *p || ',' == *p)) { p++; }
+ if (p < r) {
+ k->flags = GRN_TABLE_SORT_ASC;
+ k->offset = 0;
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ k->flags = GRN_TABLE_SORT_DESC;
+ p++;
+ }
+ if ((k->key = grn_obj_column(ctx, table, p, r - p))) {
+ k++;
+ } else {
+ if (r - p == GRN_COLUMN_NAME_SCORE_LEN &&
+ memcmp(p, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN) == 0) {
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int table_name_size;
+ table_name_size = grn_obj_name(ctx, table,
+ table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ if (table_name_size == 0) {
+ grn_strcpy(table_name, GRN_TABLE_MAX_KEY_SIZE, "(anonymous)");
+ table_name_size = strlen(table_name);
+ }
+ GRN_LOG(ctx, GRN_WARN,
+ "ignore invalid sort key: <%.*s>: "
+ "table:<%*.s> keys:<%.*s>",
+ (int)(r - p), p,
+ table_name_size, table_name,
+ str_size, str);
+ } else {
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int table_name_size;
+ table_name_size = grn_obj_name(ctx, table,
+ table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ if (table_name_size == 0) {
+ grn_strcpy(table_name, GRN_TABLE_MAX_KEY_SIZE, "(anonymous)");
+ table_name_size = strlen(table_name);
+ }
+ WARN(GRN_INVALID_ARGUMENT,
+ "invalid sort key: <%.*s>: "
+ "table:<%.*s> keys:<%.*s>",
+ (int)(r - p), p,
+ table_name_size, table_name,
+ str_size, str);
+ break;
+ }
+ }
+ }
+ p = r;
+ }
+ }
+ GRN_FREE(tokbuf);
+ }
+ if (!ctx->rc && k - keys > 0) {
+ *nkeys = k - keys;
+ } else {
+ grn_table_sort_key_close(ctx, keys, k - keys);
+ *nkeys = 0;
+ keys = NULL;
+ }
+ return keys;
+}
+
+grn_rc
+grn_table_sort_key_close(grn_ctx *ctx, grn_table_sort_key *keys, unsigned int nkeys)
+{
+ unsigned int i;
+ if (keys) {
+ for (i = 0; i < nkeys; i++) {
+ grn_obj *key = keys[i].key;
+ if (!grn_obj_is_column(ctx, key)) {
+ grn_obj_unlink(ctx, key);
+ }
+ }
+ GRN_FREE(keys);
+ }
+ return ctx->rc;
+}
+
+grn_bool
+grn_table_is_grouped(grn_ctx *ctx, grn_obj *table)
+{
+ if (GRN_OBJ_TABLEP(table) && GRN_TABLE_IS_GROUPED(table)) {
+ return GRN_TRUE;
+ }
+ return GRN_FALSE;
+}
+
+unsigned int
+grn_table_max_n_subrecs(grn_ctx *ctx, grn_obj *table)
+{
+ if (GRN_OBJ_TABLEP(table)) {
+ return DB_OBJ(table)->max_n_subrecs;
+ }
+ return 0;
+}
+
+grn_obj *
+grn_table_tokenize(grn_ctx *ctx, grn_obj *table,
+ const char *str, unsigned int str_len,
+ grn_obj *buf, grn_bool addp)
+{
+ grn_token_cursor *token_cursor = NULL;
+ grn_tokenize_mode mode = addp ? GRN_TOKENIZE_ADD : GRN_TOKENIZE_GET;
+ GRN_API_ENTER;
+ if (!(token_cursor = grn_token_cursor_open(ctx, table, str, str_len, mode, 0))) {
+ goto exit;
+ }
+ if (buf) {
+ GRN_BULK_REWIND(buf);
+ } else {
+ if (!(buf = grn_obj_open(ctx, GRN_UVECTOR, 0, DB_OBJ(table)->id))) {
+ goto exit;
+ }
+ }
+ while (token_cursor->status != GRN_TOKEN_CURSOR_DONE && token_cursor->status != GRN_TOKEN_CURSOR_DONE_SKIP) {
+ grn_id tid;
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ GRN_RECORD_PUT(ctx, buf, tid);
+ }
+ }
+exit :
+ if (token_cursor) {
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ GRN_API_RETURN(buf);
+}
+
+static void
+grn_db_recover_database_remove_orphan_inspect(grn_ctx *ctx, grn_obj *db)
+{
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, db, cursor, id, GRN_CURSOR_BY_ID) {
+ void *key;
+ int key_size;
+
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+#define INSPECT "inspect"
+#define INSPECT_LEN (sizeof(INSPECT) - 1)
+ if (key_size == INSPECT_LEN && memcmp(key, INSPECT, INSPECT_LEN) == 0) {
+ if (!grn_ctx_at(ctx, id)) {
+ ERRCLR(ctx);
+ grn_obj_delete_by_id(ctx, db, id, GRN_TRUE);
+ }
+ break;
+ }
+#undef INSPECT
+#undef INSPECT_LEN
+ } GRN_TABLE_EACH_END(ctx, cursor);
+}
+
+static void
+grn_db_recover_database(grn_ctx *ctx, grn_obj *db)
+{
+ if (grn_obj_is_locked(ctx, db)) {
+ ERR(GRN_OBJECT_CORRUPT,
+ "[db][recover] database may be broken. Please re-create the database");
+ return;
+ }
+
+ grn_db_clear_dirty(ctx, db);
+ grn_db_recover_database_remove_orphan_inspect(ctx, db);
+}
+
+static void
+grn_db_recover_table(grn_ctx *ctx, grn_obj *table)
+{
+ if (!grn_obj_is_locked(ctx, table)) {
+ return;
+ }
+
+ {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+ name_size = grn_obj_name(ctx, table, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "[db][recover] table may be broken: <%.*s>: "
+ "please truncate the table (or clear lock of the table) "
+ "and load data again",
+ (int)name_size, name);
+ }
+}
+
+static void
+grn_db_recover_data_column(grn_ctx *ctx, grn_obj *data_column)
+{
+ if (!grn_obj_is_locked(ctx, data_column)) {
+ return;
+ }
+
+ {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+ name_size = grn_obj_name(ctx, data_column, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "[db][recover] column may be broken: <%.*s>: "
+ "please truncate the column (or clear lock of the column) "
+ "and load data again",
+ (int)name_size, name);
+ }
+}
+
+static void
+grn_db_recover_index_column(grn_ctx *ctx, grn_obj *index_column)
+{
+ if (!grn_obj_is_locked(ctx, index_column)) {
+ return;
+ }
+
+ grn_index_column_rebuild(ctx, index_column);
+}
+
+static grn_bool
+grn_db_recover_is_builtin(grn_ctx *ctx, grn_id id, grn_table_cursor *cursor)
+{
+ void *key;
+ const char *name;
+ int name_size;
+
+ if (id < GRN_N_RESERVED_TYPES) {
+ return GRN_TRUE;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ name = key;
+
+#define NAME_EQUAL(value) \
+ (name_size == strlen(value) && memcmp(name, value, strlen(value)) == 0)
+
+ if (NAME_EQUAL("inspect")) {
+ /* Just for compatibility. It's needed for users who used
+ Groonga master at between 2016-02-03 and 2016-02-26. */
+ return GRN_TRUE;
+ }
+
+#undef NAME_EQUAL
+
+ return GRN_FALSE;
+}
+
+grn_rc
+grn_db_recover(grn_ctx *ctx, grn_obj *db)
+{
+ grn_table_cursor *cursor;
+ grn_id id;
+ grn_bool is_close_opened_object_mode;
+
+ GRN_API_ENTER;
+
+ is_close_opened_object_mode = (grn_thread_get_limit() == 1);
+
+ grn_db_recover_database(ctx, db);
+ if (ctx->rc != GRN_SUCCESS) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ cursor = grn_table_cursor_open(ctx, db,
+ NULL, 0, NULL, 0,
+ 0, -1,
+ GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *object;
+
+ if (is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ if ((object = grn_ctx_at(ctx, id))) {
+ switch (object->header.type) {
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ grn_db_recover_table(ctx, object);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ grn_db_recover_data_column(ctx, object);
+ break;
+ case GRN_COLUMN_INDEX :
+ grn_db_recover_index_column(ctx, object);
+ break;
+ default:
+ break;
+ }
+ grn_obj_unlink(ctx, object);
+ } else {
+ if (grn_db_recover_is_builtin(ctx, id, cursor)) {
+ ERRCLR(ctx);
+ }
+ }
+
+ if (is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_db_unmap(grn_ctx *ctx, grn_obj *db)
+{
+ grn_id id;
+ db_value *vp;
+ grn_db *s = (grn_db *)db;
+
+ GRN_API_ENTER;
+
+ GRN_TINY_ARRAY_EACH(&s->values, 1, grn_db_curr_id(ctx, db), id, vp, {
+ grn_obj *obj = vp->ptr;
+
+ if (obj) {
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ grn_obj_close(ctx, obj);
+ break;
+ }
+ }
+ });
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+static grn_rc
+grn_ctx_get_all_objects(grn_ctx *ctx, grn_obj *objects_buffer,
+ grn_bool (*predicate)(grn_ctx *ctx, grn_obj *object))
+{
+ grn_obj *db;
+ grn_table_cursor *cursor;
+ grn_id id;
+
+ GRN_API_ENTER;
+
+ db = ctx->impl->db;
+ if (!db) {
+ ERR(GRN_INVALID_ARGUMENT, "DB isn't associated");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *object;
+
+ if ((object = grn_ctx_at(ctx, id))) {
+ if (predicate(ctx, object)) {
+ GRN_PTR_PUT(ctx, objects_buffer, object);
+ } else {
+ grn_obj_unlink(ctx, object);
+ }
+ } else {
+ if (ctx->rc != GRN_SUCCESS) {
+ ERRCLR(ctx);
+ }
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_ctx_get_all_tables(grn_ctx *ctx, grn_obj *tables_buffer)
+{
+ return grn_ctx_get_all_objects(ctx, tables_buffer, grn_obj_is_table);
+}
+
+grn_rc
+grn_ctx_get_all_types(grn_ctx *ctx, grn_obj *types_buffer)
+{
+ return grn_ctx_get_all_objects(ctx, types_buffer, grn_obj_is_type);
+}
+
+grn_rc
+grn_ctx_get_all_tokenizers(grn_ctx *ctx, grn_obj *tokenizers_buffer)
+{
+ return grn_ctx_get_all_objects(ctx, tokenizers_buffer,
+ grn_obj_is_tokenizer_proc);
+}
+
+grn_rc
+grn_ctx_get_all_normalizers(grn_ctx *ctx, grn_obj *normalizers_buffer)
+{
+ return grn_ctx_get_all_objects(ctx, normalizers_buffer,
+ grn_obj_is_normalizer_proc);
+}
+
+grn_rc
+grn_ctx_get_all_token_filters(grn_ctx *ctx, grn_obj *token_filters_buffer)
+{
+ return grn_ctx_get_all_objects(ctx, token_filters_buffer,
+ grn_obj_is_token_filter_proc);
+}
+
+grn_rc
+grn_ctx_push_temporary_open_space(grn_ctx *ctx)
+{
+ grn_obj *stack;
+ grn_obj *space;
+ grn_obj buffer;
+
+ GRN_API_ENTER;
+
+ stack = &(ctx->impl->temporary_open_spaces.stack);
+ GRN_VOID_INIT(&buffer);
+ grn_bulk_write(ctx, stack, (const char *)&buffer, sizeof(grn_obj));
+ space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
+ GRN_PTR_INIT(space, GRN_OBJ_VECTOR | GRN_OBJ_OWN, GRN_ID_NIL);
+
+ ctx->impl->temporary_open_spaces.current = space;
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_ctx_pop_temporary_open_space(grn_ctx *ctx)
+{
+ grn_obj *stack;
+ grn_obj *space;
+
+ GRN_API_ENTER;
+
+ stack = &(ctx->impl->temporary_open_spaces.stack);
+ if (GRN_BULK_EMPTYP(stack)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[ctx][temporary-open-spaces][pop] too much pop");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ space = ctx->impl->temporary_open_spaces.current;
+ GRN_OBJ_FIN(ctx, space);
+ grn_bulk_truncate(ctx, stack, GRN_BULK_VSIZE(stack) - sizeof(grn_obj));
+
+ if (GRN_BULK_EMPTYP(stack)) {
+ space = NULL;
+ } else {
+ space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
+ }
+ ctx->impl->temporary_open_spaces.current = space;
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_ctx_merge_temporary_open_space(grn_ctx *ctx)
+{
+ grn_obj *stack;
+ grn_obj *space;
+ grn_obj *next_space;
+
+ GRN_API_ENTER;
+
+ stack = &(ctx->impl->temporary_open_spaces.stack);
+ if ((unsigned long) GRN_BULK_VSIZE(stack) < (unsigned long) sizeof(grn_obj) * 2) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[ctx][temporary-open-spaces][merge] "
+ "merge requires at least two spaces");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ space = ctx->impl->temporary_open_spaces.current;
+ next_space = ctx->impl->temporary_open_spaces.current - 1;
+ {
+ unsigned int i, n_elements;
+ n_elements = GRN_BULK_VSIZE(space) / sizeof(grn_obj *);
+ for (i = 0; i < n_elements; i++) {
+ grn_obj *element = GRN_PTR_VALUE_AT(space, i);
+ GRN_PTR_PUT(ctx, next_space, element);
+ }
+ }
+ GRN_BULK_REWIND(space);
+ GRN_OBJ_FIN(ctx, space);
+ grn_bulk_truncate(ctx, stack, GRN_BULK_VSIZE(stack) - sizeof(grn_obj));
+
+ if (GRN_BULK_EMPTYP(stack)) {
+ space = NULL;
+ } else {
+ space = ((grn_obj *)GRN_BULK_CURR(stack)) - 1;
+ }
+ ctx->impl->temporary_open_spaces.current = space;
+
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/dump.c b/storage/mroonga/vendor/groonga/lib/dump.c
new file mode 100644
index 00000000..72017fe3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/dump.c
@@ -0,0 +1,112 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx.h"
+
+grn_rc
+grn_dump_table_create_flags(grn_ctx *ctx,
+ grn_table_flags flags,
+ grn_obj *buffer)
+{
+ GRN_API_ENTER;
+
+ switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
+ case GRN_OBJ_TABLE_HASH_KEY:
+ GRN_TEXT_PUTS(ctx, buffer, "TABLE_HASH_KEY");
+ break;
+ case GRN_OBJ_TABLE_PAT_KEY:
+ GRN_TEXT_PUTS(ctx, buffer, "TABLE_PAT_KEY");
+ break;
+ case GRN_OBJ_TABLE_DAT_KEY:
+ GRN_TEXT_PUTS(ctx, buffer, "TABLE_DAT_KEY");
+ break;
+ case GRN_OBJ_TABLE_NO_KEY:
+ GRN_TEXT_PUTS(ctx, buffer, "TABLE_NO_KEY");
+ break;
+ }
+ if (flags & GRN_OBJ_KEY_LARGE) {
+ GRN_TEXT_PUTS(ctx, buffer, "|KEY_LARGE");
+ }
+ if (flags & GRN_OBJ_KEY_WITH_SIS) {
+ GRN_TEXT_PUTS(ctx, buffer, "|KEY_WITH_SIS");
+ }
+ if (flags & GRN_OBJ_KEY_NORMALIZE) {
+ GRN_TEXT_PUTS(ctx, buffer, "|KEY_NORMALIZE");
+ }
+ if (flags & GRN_OBJ_PERSISTENT) {
+ GRN_TEXT_PUTS(ctx, buffer, "|PERSISTENT");
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_dump_column_create_flags(grn_ctx *ctx,
+ grn_column_flags flags,
+ grn_obj *buffer)
+{
+ GRN_API_ENTER;
+
+ switch (flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_SCALAR:
+ GRN_TEXT_PUTS(ctx, buffer, "COLUMN_SCALAR");
+ break;
+ case GRN_OBJ_COLUMN_VECTOR:
+ GRN_TEXT_PUTS(ctx, buffer, "COLUMN_VECTOR");
+ if (flags & GRN_OBJ_WITH_WEIGHT) {
+ GRN_TEXT_PUTS(ctx, buffer, "|WITH_WEIGHT");
+ }
+ break;
+ case GRN_OBJ_COLUMN_INDEX:
+ GRN_TEXT_PUTS(ctx, buffer, "COLUMN_INDEX");
+ if (flags & GRN_OBJ_WITH_SECTION) {
+ GRN_TEXT_PUTS(ctx, buffer, "|WITH_SECTION");
+ }
+ if (flags & GRN_OBJ_WITH_WEIGHT) {
+ GRN_TEXT_PUTS(ctx, buffer, "|WITH_WEIGHT");
+ }
+ if (flags & GRN_OBJ_WITH_POSITION) {
+ GRN_TEXT_PUTS(ctx, buffer, "|WITH_POSITION");
+ }
+ if (flags & GRN_OBJ_INDEX_SMALL) {
+ GRN_TEXT_PUTS(ctx, buffer, "|INDEX_SMALL");
+ }
+ if (flags & GRN_OBJ_INDEX_MEDIUM) {
+ GRN_TEXT_PUTS(ctx, buffer, "|INDEX_MEDIUM");
+ }
+ break;
+ }
+ switch (flags & GRN_OBJ_COMPRESS_MASK) {
+ case GRN_OBJ_COMPRESS_NONE:
+ break;
+ case GRN_OBJ_COMPRESS_ZLIB:
+ GRN_TEXT_PUTS(ctx, buffer, "|COMPRESS_ZLIB");
+ break;
+ case GRN_OBJ_COMPRESS_LZ4:
+ GRN_TEXT_PUTS(ctx, buffer, "|COMPRESS_LZ4");
+ break;
+ case GRN_OBJ_COMPRESS_ZSTD:
+ GRN_TEXT_PUTS(ctx, buffer, "|COMPRESS_ZSTD");
+ break;
+ }
+ if (flags & GRN_OBJ_PERSISTENT) {
+ GRN_TEXT_PUTS(ctx, buffer, "|PERSISTENT");
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/error.c b/storage/mroonga/vendor/groonga/lib/error.c
new file mode 100644
index 00000000..9fd03291
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/error.c
@@ -0,0 +1,454 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_error.h"
+#include "grn_windows.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#include <string.h>
+
+#ifdef WIN32
+
+grn_rc
+grn_windows_error_code_to_rc(int error_code)
+{
+ grn_rc rc;
+
+ switch (error_code) {
+ case ERROR_FILE_NOT_FOUND :
+ case ERROR_PATH_NOT_FOUND :
+ rc = GRN_NO_SUCH_FILE_OR_DIRECTORY;
+ break;
+ case ERROR_TOO_MANY_OPEN_FILES :
+ rc = GRN_TOO_MANY_OPEN_FILES;
+ break;
+ case ERROR_ACCESS_DENIED :
+ rc = GRN_PERMISSION_DENIED;
+ break;
+ case ERROR_INVALID_HANDLE :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_ARENA_TRASHED :
+ rc = GRN_ADDRESS_IS_NOT_AVAILABLE;
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY :
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ break;
+ case ERROR_INVALID_BLOCK :
+ case ERROR_BAD_ENVIRONMENT :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_BAD_FORMAT :
+ rc = GRN_INVALID_FORMAT;
+ break;
+ case ERROR_INVALID_DATA :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_OUTOFMEMORY :
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ break;
+ case ERROR_INVALID_DRIVE :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_WRITE_PROTECT :
+ rc = GRN_PERMISSION_DENIED;
+ break;
+ case ERROR_BAD_LENGTH :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_SEEK :
+ rc = GRN_INVALID_SEEK;
+ break;
+ case ERROR_NOT_SUPPORTED :
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ break;
+ case ERROR_NETWORK_ACCESS_DENIED :
+ rc = GRN_OPERATION_NOT_PERMITTED;
+ break;
+ case ERROR_FILE_EXISTS :
+ rc = GRN_FILE_EXISTS;
+ break;
+ case ERROR_INVALID_PARAMETER :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_BROKEN_PIPE :
+ rc = GRN_BROKEN_PIPE;
+ break;
+ case ERROR_CALL_NOT_IMPLEMENTED :
+ rc = GRN_FUNCTION_NOT_IMPLEMENTED;
+ break;
+ case ERROR_INVALID_NAME :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_BUSY_DRIVE :
+ case ERROR_PATH_BUSY :
+ rc = GRN_RESOURCE_BUSY;
+ break;
+ case ERROR_BAD_ARGUMENTS :
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ case ERROR_BUSY :
+ rc = GRN_RESOURCE_BUSY;
+ break;
+ case ERROR_ALREADY_EXISTS :
+ rc = GRN_FILE_EXISTS;
+ break;
+ case ERROR_BAD_EXE_FORMAT :
+ rc = GRN_EXEC_FORMAT_ERROR;
+ break;
+ case ERROR_NO_SYSTEM_RESOURCES :
+ rc = GRN_RESOURCE_TEMPORARILY_UNAVAILABLE;
+ break;
+ default:
+ rc = GRN_UNKNOWN_ERROR;
+ break;
+ }
+
+ return rc;
+}
+
+# define LANG_ID_NEUTRAL() MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
+# define LANG_ID_USER_DEFAULT() MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)
+# define LANG_ID_SYSTEM_DEFAULT() MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT)
+
+const char *
+grn_current_error_message(void)
+{
+# define ERROR_MESSAGE_BUFFER_SIZE 4096
+ int error_code = GetLastError();
+ static WCHAR utf16_message[ERROR_MESSAGE_BUFFER_SIZE];
+ DWORD written_utf16_chars;
+ static char message[ERROR_MESSAGE_BUFFER_SIZE];
+
+ written_utf16_chars = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error_code,
+ LANG_ID_USER_DEFAULT(),
+ utf16_message,
+ ERROR_MESSAGE_BUFFER_SIZE,
+ NULL);
+ if (written_utf16_chars >= 2) {
+ if (utf16_message[written_utf16_chars - 1] == L'\n') {
+ utf16_message[written_utf16_chars - 1] = L'\0';
+ written_utf16_chars--;
+ }
+ if (utf16_message[written_utf16_chars - 1] == L'\r') {
+ utf16_message[written_utf16_chars - 1] = L'\0';
+ written_utf16_chars--;
+ }
+ }
+
+ {
+ UINT code_page;
+ DWORD convert_flags = 0;
+ int written_bytes;
+
+ code_page = grn_windows_encoding_to_code_page(grn_get_default_encoding());
+ written_bytes = WideCharToMultiByte(code_page,
+ convert_flags,
+ utf16_message,
+ written_utf16_chars,
+ message,
+ ERROR_MESSAGE_BUFFER_SIZE,
+ NULL,
+ NULL);
+ }
+
+ return message;
+
+# undef ERROR_MESSAGE_BUFFER_SIZE
+}
+#else
+const char *
+grn_current_error_message(void)
+{
+ return strerror(errno);
+}
+#endif
+
+const char *
+grn_strerror(int error_code)
+{
+#ifdef WIN32
+# define MESSAGE_BUFFER_SIZE 1024
+ static char message[MESSAGE_BUFFER_SIZE];
+ strerror_s(message, MESSAGE_BUFFER_SIZE, error_code);
+ return message;
+# undef MESSAGE_BUFFER_SIZE
+#else /* WIN32 */
+ return strerror(error_code);
+#endif /* WIN32 */
+}
+
+const char *
+grn_rc_to_string(grn_rc rc)
+{
+ const char *message = "invalid grn_rc";
+
+ switch (rc) {
+ case GRN_SUCCESS :
+ message = "success";
+ break;
+ case GRN_END_OF_DATA :
+ message = "end of data";
+ break;
+ case GRN_UNKNOWN_ERROR :
+ message = "unknown error";
+ break;
+ case GRN_OPERATION_NOT_PERMITTED :
+ message = "operation not permitted";
+ break;
+ case GRN_NO_SUCH_FILE_OR_DIRECTORY :
+ message = "no such file or directory";
+ break;
+ case GRN_NO_SUCH_PROCESS :
+ message = "no such process";
+ break;
+ case GRN_INTERRUPTED_FUNCTION_CALL :
+ message = "interrupted function call";
+ break;
+ case GRN_INPUT_OUTPUT_ERROR :
+ message = "input output error";
+ break;
+ case GRN_NO_SUCH_DEVICE_OR_ADDRESS :
+ message = "no such device or address";
+ break;
+ case GRN_ARG_LIST_TOO_LONG :
+ message = "argument list is too long";
+ break;
+ case GRN_EXEC_FORMAT_ERROR :
+ message = "exec format error";
+ break;
+ case GRN_BAD_FILE_DESCRIPTOR :
+ message = "bad file descriptor";
+ break;
+ case GRN_NO_CHILD_PROCESSES :
+ message = "no child processes";
+ break;
+ case GRN_RESOURCE_TEMPORARILY_UNAVAILABLE :
+ message = "resource temporarily unavailable";
+ break;
+ case GRN_NOT_ENOUGH_SPACE :
+ message = "not enough space";
+ break;
+ case GRN_PERMISSION_DENIED :
+ message = "permission denied";
+ break;
+ case GRN_BAD_ADDRESS :
+ message = "bad address";
+ break;
+ case GRN_RESOURCE_BUSY :
+ message = "resource busy";
+ break;
+ case GRN_FILE_EXISTS :
+ message = "file exists";
+ break;
+ case GRN_IMPROPER_LINK :
+ message = "improper link";
+ break;
+ case GRN_NO_SUCH_DEVICE :
+ message = "no such device";
+ break;
+ case GRN_NOT_A_DIRECTORY :
+ message = "not a directory";
+ break;
+ case GRN_IS_A_DIRECTORY :
+ message = "is a directory";
+ break;
+ case GRN_INVALID_ARGUMENT :
+ message = "invalid argument";
+ break;
+ case GRN_TOO_MANY_OPEN_FILES_IN_SYSTEM :
+ message = "too many open files in system";
+ break;
+ case GRN_TOO_MANY_OPEN_FILES :
+ message = "too many open files";
+ break;
+ case GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION :
+ message = "inappropriate I/O control operation";
+ break;
+ case GRN_FILE_TOO_LARGE :
+ message = "file too large";
+ break;
+ case GRN_NO_SPACE_LEFT_ON_DEVICE :
+ message = "no space left on device";
+ break;
+ case GRN_INVALID_SEEK :
+ message = "invalid seek";
+ break;
+ case GRN_READ_ONLY_FILE_SYSTEM :
+ message = "read only file system";
+ break;
+ case GRN_TOO_MANY_LINKS :
+ message = "too many links";
+ break;
+ case GRN_BROKEN_PIPE :
+ message = "broken pipe";
+ break;
+ case GRN_DOMAIN_ERROR :
+ message = "domain error";
+ break;
+ case GRN_RESULT_TOO_LARGE :
+ message = "result too large";
+ break;
+ case GRN_RESOURCE_DEADLOCK_AVOIDED :
+ message = "resource deadlock avoided";
+ break;
+ case GRN_NO_MEMORY_AVAILABLE :
+ message = "no memory available";
+ break;
+ case GRN_FILENAME_TOO_LONG :
+ message = "filename too long";
+ break;
+ case GRN_NO_LOCKS_AVAILABLE :
+ message = "no locks available";
+ break;
+ case GRN_FUNCTION_NOT_IMPLEMENTED :
+ message = "function not implemented";
+ break;
+ case GRN_DIRECTORY_NOT_EMPTY :
+ message = "directory not empty";
+ break;
+ case GRN_ILLEGAL_BYTE_SEQUENCE :
+ message = "illegal byte sequence";
+ break;
+ case GRN_SOCKET_NOT_INITIALIZED :
+ message = "socket not initialized";
+ break;
+ case GRN_OPERATION_WOULD_BLOCK :
+ message = "operation would block";
+ break;
+ case GRN_ADDRESS_IS_NOT_AVAILABLE :
+ message = "address is not available";
+ break;
+ case GRN_NETWORK_IS_DOWN :
+ message = "network is down";
+ break;
+ case GRN_NO_BUFFER :
+ message = "no buffer";
+ break;
+ case GRN_SOCKET_IS_ALREADY_CONNECTED :
+ message = "socket is already connected";
+ break;
+ case GRN_SOCKET_IS_NOT_CONNECTED :
+ message = "socket is not connected";
+ break;
+ case GRN_SOCKET_IS_ALREADY_SHUTDOWNED :
+ message = "socket is already shutdowned";
+ break;
+ case GRN_OPERATION_TIMEOUT :
+ message = "operation timeout";
+ break;
+ case GRN_CONNECTION_REFUSED :
+ message = "connection refused";
+ break;
+ case GRN_RANGE_ERROR :
+ message = "range error";
+ break;
+ case GRN_TOKENIZER_ERROR :
+ message = "tokenizer error";
+ break;
+ case GRN_FILE_CORRUPT :
+ message = "file corrupt";
+ break;
+ case GRN_INVALID_FORMAT :
+ message = "invalid format";
+ break;
+ case GRN_OBJECT_CORRUPT :
+ message = "object corrupt";
+ break;
+ case GRN_TOO_MANY_SYMBOLIC_LINKS :
+ message = "too many symbolic links";
+ break;
+ case GRN_NOT_SOCKET :
+ message = "not socket";
+ break;
+ case GRN_OPERATION_NOT_SUPPORTED :
+ message = "operation not supported";
+ break;
+ case GRN_ADDRESS_IS_IN_USE :
+ message = "address is in use";
+ break;
+ case GRN_ZLIB_ERROR :
+ message = "zlib error";
+ break;
+ case GRN_LZ4_ERROR :
+ message = "LZ4 error";
+ break;
+ case GRN_STACK_OVER_FLOW :
+ message = "stack over flow";
+ break;
+ case GRN_SYNTAX_ERROR :
+ message = "syntax error";
+ break;
+ case GRN_RETRY_MAX :
+ message = "retry max";
+ break;
+ case GRN_INCOMPATIBLE_FILE_FORMAT :
+ message = "incompatible file format";
+ break;
+ case GRN_UPDATE_NOT_ALLOWED :
+ message = "update not allowed";
+ break;
+ case GRN_TOO_SMALL_OFFSET :
+ message = "too small offset";
+ break;
+ case GRN_TOO_LARGE_OFFSET :
+ message = "too large offset";
+ break;
+ case GRN_TOO_SMALL_LIMIT :
+ message = "too small limit";
+ break;
+ case GRN_CAS_ERROR :
+ message = "cas error";
+ break;
+ case GRN_UNSUPPORTED_COMMAND_VERSION :
+ message = "unsupported command version";
+ break;
+ case GRN_NORMALIZER_ERROR :
+ message = "normalizer error";
+ break;
+ case GRN_TOKEN_FILTER_ERROR :
+ message = "token filter error";
+ break;
+ case GRN_COMMAND_ERROR :
+ message = "command error";
+ break;
+ case GRN_PLUGIN_ERROR :
+ message = "plugin error";
+ break;
+ case GRN_SCORER_ERROR :
+ message = "scorer error";
+ break;
+ case GRN_CANCEL :
+ message = "cancel";
+ break;
+ case GRN_WINDOW_FUNCTION_ERROR :
+ message = "window function error";
+ break;
+ case GRN_ZSTD_ERROR :
+ message = "Zstandard error";
+ break;
+ }
+
+ return message;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/expr.c b/storage/mroonga/vendor/groonga/lib/expr.c
new file mode 100644
index 00000000..b4de00b2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/expr.c
@@ -0,0 +1,9294 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include "grn_db.h"
+#include "grn_ctx_impl.h"
+#include "grn_ctx_impl_mrb.h"
+#include <string.h>
+#include "grn_ii.h"
+#include "grn_geo.h"
+#include "grn_expr.h"
+#include "grn_expr_code.h"
+#include "grn_expr_executor.h"
+#include "grn_scanner.h"
+#include "grn_util.h"
+#include "grn_report.h"
+#include "grn_token_cursor.h"
+#include "grn_mrb.h"
+#include "mrb/mrb_expr.h"
+
+#ifdef GRN_WITH_ONIGMO
+# define GRN_SUPPORT_REGEXP
+#endif
+
+#ifdef GRN_SUPPORT_REGEXP
+# include "grn_normalizer.h"
+# include <onigmo.h>
+#endif
+
+static double grn_table_select_enough_filtered_ratio = 0.0;
+static int grn_table_select_max_n_enough_filtered_records = 1000;
+static grn_bool grn_table_select_and_min_skip_enable = GRN_TRUE;
+static grn_bool grn_scan_info_regexp_dot_asterisk_enable = GRN_TRUE;
+
+void
+grn_expr_init_from_env(void)
+{
+ {
+ char grn_table_select_enough_filtered_ratio_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_TABLE_SELECT_ENOUGH_FILTERED_RATIO",
+ grn_table_select_enough_filtered_ratio_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_table_select_enough_filtered_ratio_env[0]) {
+ grn_table_select_enough_filtered_ratio =
+ atof(grn_table_select_enough_filtered_ratio_env);
+ }
+ }
+
+ {
+ char grn_table_select_max_n_enough_filtered_records_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_TABLE_SELECT_MAX_N_ENOUGH_FILTERED_RECORDS",
+ grn_table_select_max_n_enough_filtered_records_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_table_select_max_n_enough_filtered_records_env[0]) {
+ grn_table_select_max_n_enough_filtered_records =
+ atoi(grn_table_select_max_n_enough_filtered_records_env);
+ }
+ }
+
+ {
+ char grn_table_select_and_min_skip_enable_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_TABLE_SELECT_AND_MIN_SKIP_ENABLE",
+ grn_table_select_and_min_skip_enable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (strcmp(grn_table_select_and_min_skip_enable_env, "no") == 0) {
+ grn_table_select_and_min_skip_enable = GRN_FALSE;
+ } else {
+ grn_table_select_and_min_skip_enable = GRN_TRUE;
+ }
+ }
+
+ {
+ char grn_scan_info_regexp_dot_asterisk_enable_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_SCAN_INFO_REGEXP_DOT_ASTERISK_ENABLE",
+ grn_scan_info_regexp_dot_asterisk_enable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (strcmp(grn_scan_info_regexp_dot_asterisk_enable_env, "no") == 0) {
+ grn_scan_info_regexp_dot_asterisk_enable = GRN_FALSE;
+ } else {
+ grn_scan_info_regexp_dot_asterisk_enable = GRN_TRUE;
+ }
+ }
+}
+
+grn_obj *
+grn_expr_alloc(grn_ctx *ctx, grn_obj *expr, grn_id domain, unsigned char flags)
+{
+ grn_obj *res = NULL;
+ grn_expr *e = (grn_expr *)expr;
+ if (e) {
+ if (e->values_curr >= e->values_size) {
+ // todo : expand values.
+ ERR(GRN_NO_MEMORY_AVAILABLE, "no more e->values");
+ return NULL;
+ }
+ res = &e->values[e->values_curr++];
+ if (e->values_curr > e->values_tail) { e->values_tail = e->values_curr; }
+ grn_obj_reinit(ctx, res, domain, flags);
+ }
+ return res;
+}
+
+grn_hash *
+grn_expr_get_vars(grn_ctx *ctx, grn_obj *expr, unsigned int *nvars)
+{
+ grn_hash *vars = NULL;
+ if (expr->header.type == GRN_PROC || expr->header.type == GRN_EXPR) {
+ grn_id id = DB_OBJ(expr)->id;
+ grn_expr *e = (grn_expr *)expr;
+ int added = 0;
+ grn_hash **vp;
+ if (grn_hash_add(ctx, ctx->impl->expr_vars, &id, sizeof(grn_id), (void **)&vp, &added)) {
+ if (!*vp) {
+ *vp = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj),
+ GRN_OBJ_KEY_VAR_SIZE|GRN_OBJ_TEMPORARY|GRN_HASH_TINY);
+ if (*vp) {
+ uint32_t i;
+ grn_obj *value;
+ grn_expr_var *v;
+ for (v = e->vars, i = e->nvars; i; v++, i--) {
+ grn_hash_add(ctx, *vp, v->name, v->name_size, (void **)&value, &added);
+ GRN_OBJ_INIT(value, v->value.header.type, 0, v->value.header.domain);
+ GRN_TEXT_PUT(ctx, value, GRN_TEXT_VALUE(&v->value), GRN_TEXT_LEN(&v->value));
+ }
+ }
+ }
+ vars = *vp;
+ }
+ }
+ *nvars = vars ? GRN_HASH_SIZE(vars) : 0;
+ return vars;
+}
+
+grn_rc
+grn_expr_clear_vars(grn_ctx *ctx, grn_obj *expr)
+{
+ if (expr->header.type == GRN_PROC || expr->header.type == GRN_EXPR) {
+ grn_hash **vp;
+ grn_id eid, id = DB_OBJ(expr)->id;
+ if ((eid = grn_hash_get(ctx, ctx->impl->expr_vars, &id, sizeof(grn_id), (void **)&vp))) {
+ if (*vp) {
+ grn_obj *value;
+ GRN_HASH_EACH(ctx, *vp, i, NULL, NULL, (void **)&value, {
+ GRN_OBJ_FIN(ctx, value);
+ });
+ grn_hash_close(ctx, *vp);
+ }
+ grn_hash_delete_by_id(ctx, ctx->impl->expr_vars, eid, NULL);
+ }
+ }
+ return ctx->rc;
+}
+
+grn_obj *
+grn_proc_get_info(grn_ctx *ctx, grn_user_data *user_data,
+ grn_expr_var **vars, unsigned int *nvars, grn_obj **caller)
+{
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ if (caller) { *caller = pctx->caller; }
+ if (pctx->proc) {
+ if (vars) {
+ *vars = pctx->proc->vars;
+ // *vars = grn_expr_get_vars(ctx, (grn_obj *)pctx->proc, nvars);
+ }
+ if (nvars) { *nvars = pctx->proc->nvars; }
+ } else {
+ if (vars) { *vars = NULL; }
+ if (nvars) { *nvars = 0; }
+ }
+ return (grn_obj *)pctx->proc;
+}
+
+grn_obj *
+grn_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data)
+{
+ uint32_t n;
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ if (pctx->proc) {
+ return (grn_obj *)grn_expr_get_vars(ctx, (grn_obj *)pctx->proc, &n);
+ } else {
+ return NULL;
+ }
+}
+
+grn_obj *
+grn_proc_get_var(grn_ctx *ctx, grn_user_data *user_data, const char *name, unsigned int name_size)
+{
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ return pctx->proc ? grn_expr_get_var(ctx, (grn_obj *)pctx->proc, name, name_size) : NULL;
+}
+
+grn_obj *
+grn_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data, unsigned int offset)
+{
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ return pctx->proc ? grn_expr_get_var_by_offset(ctx, (grn_obj *)pctx->proc, offset) : NULL;
+}
+
+grn_obj *
+grn_proc_get_or_add_var(grn_ctx *ctx, grn_user_data *user_data,
+ const char *name, unsigned int name_size)
+{
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ return pctx->proc ? grn_expr_get_or_add_var(ctx, (grn_obj *)pctx->proc, name, name_size) : NULL;
+}
+
+grn_obj *
+grn_proc_alloc(grn_ctx *ctx, grn_user_data *user_data, grn_id domain, unsigned char flags)
+{
+ grn_proc_ctx *pctx = (grn_proc_ctx *)user_data;
+ return pctx->caller ? grn_expr_alloc(ctx, (grn_obj *)pctx->caller, domain, flags) : NULL;
+}
+
+grn_proc_type
+grn_proc_get_type(grn_ctx *ctx, grn_obj *proc)
+{
+ grn_proc *proc_ = (grn_proc *)proc;
+ return proc_ ? proc_->type : GRN_PROC_INVALID;
+}
+
+grn_rc
+grn_proc_set_selector(grn_ctx *ctx, grn_obj *proc, grn_selector_func selector)
+{
+ grn_proc *proc_ = (grn_proc *)proc;
+ if (!grn_obj_is_function_proc(ctx, proc)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ proc_->callbacks.function.selector = selector;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_proc_set_selector_operator(grn_ctx *ctx, grn_obj *proc, grn_operator op)
+{
+ grn_proc *proc_ = (grn_proc *)proc;
+ if (!grn_obj_is_function_proc(ctx, proc)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ proc_->callbacks.function.selector_op = op;
+ return GRN_SUCCESS;
+}
+
+grn_operator
+grn_proc_get_selector_operator(grn_ctx *ctx, grn_obj *proc)
+{
+ grn_proc *proc_ = (grn_proc *)proc;
+ if (!grn_obj_is_function_proc(ctx, proc)) {
+ return GRN_OP_NOP;
+ }
+ return proc_->callbacks.function.selector_op;
+}
+
+grn_rc
+grn_proc_set_is_stable(grn_ctx *ctx, grn_obj *proc, grn_bool is_stable)
+{
+ grn_proc *proc_ = (grn_proc *)proc;
+ if (!grn_obj_is_function_proc(ctx, proc)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ proc_->callbacks.function.is_stable = is_stable;
+ return GRN_SUCCESS;
+}
+
+grn_bool
+grn_proc_is_stable(grn_ctx *ctx, grn_obj *proc)
+{
+ grn_proc *proc_ = (grn_proc *)proc;
+ if (!grn_obj_is_function_proc(ctx, proc)) {
+ return GRN_FALSE;
+ }
+ return proc_->callbacks.function.is_stable;
+}
+
+/* grn_expr */
+
+grn_obj *
+grn_ctx_pop(grn_ctx *ctx)
+{
+ if (ctx && ctx->impl && ctx->impl->stack_curr) {
+ return ctx->impl->stack[--ctx->impl->stack_curr];
+ }
+ return NULL;
+}
+
+grn_rc
+grn_ctx_push(grn_ctx *ctx, grn_obj *obj)
+{
+ if (ctx && ctx->impl && ctx->impl->stack_curr < GRN_STACK_SIZE) {
+ ctx->impl->stack[ctx->impl->stack_curr++] = obj;
+ return GRN_SUCCESS;
+ }
+ return GRN_STACK_OVER_FLOW;
+}
+
+grn_obj *
+grn_expr_alloc_const(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ uint32_t id = e->nconsts % GRN_EXPR_CONST_BLK_SIZE;
+ uint32_t blk_id = e->nconsts / GRN_EXPR_CONST_BLK_SIZE;
+
+ if (id == 0) {
+ uint32_t nblks = blk_id + 1;
+ grn_obj **blks = (grn_obj **)GRN_REALLOC(e->const_blks,
+ sizeof(grn_obj *) * nblks);
+ if (!blks) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "realloc failed");
+ return NULL;
+ }
+ e->const_blks = blks;
+ blks[blk_id] = GRN_MALLOCN(grn_obj, GRN_EXPR_CONST_BLK_SIZE);
+ if (!blks[blk_id]) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "malloc failed");
+ return NULL;
+ }
+ }
+ e->nconsts++;
+ return &e->const_blks[blk_id][id];
+}
+
+void
+grn_obj_pack(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_text_benc(ctx, buf, obj->header.type);
+ if (GRN_DB_OBJP(obj)) {
+ grn_text_benc(ctx, buf, DB_OBJ(obj)->id);
+ } else {
+ // todo : support vector, query, accessor, snip..
+ uint32_t vs = GRN_BULK_VSIZE(obj);
+ grn_text_benc(ctx, buf, obj->header.domain);
+ grn_text_benc(ctx, buf, vs);
+ if (vs) { GRN_TEXT_PUT(ctx, buf, GRN_BULK_HEAD(obj), vs); }
+ }
+}
+
+const uint8_t *
+grn_obj_unpack(grn_ctx *ctx, const uint8_t *p, const uint8_t *pe, uint8_t type, uint8_t flags, grn_obj *obj)
+{
+ grn_id domain;
+ uint32_t vs;
+ GRN_B_DEC(domain, p);
+ GRN_OBJ_INIT(obj, type, flags, domain);
+ GRN_B_DEC(vs, p);
+ if (pe < p + vs) {
+ ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
+ return p;
+ }
+ grn_bulk_write(ctx, obj, (const char *)p, vs);
+ return p + vs;
+}
+
+typedef enum {
+ GRN_EXPR_PACK_TYPE_NULL = 0,
+ GRN_EXPR_PACK_TYPE_VARIABLE = 1,
+ GRN_EXPR_PACK_TYPE_OTHERS = 2
+} grn_expr_pack_type;
+
+void
+grn_expr_pack(grn_ctx *ctx, grn_obj *buf, grn_obj *expr)
+{
+ grn_expr_code *c;
+ grn_expr_var *v;
+ grn_expr *e = (grn_expr *)expr;
+ uint32_t i, j;
+ grn_text_benc(ctx, buf, e->nvars);
+ for (i = e->nvars, v = e->vars; i; i--, v++) {
+ grn_text_benc(ctx, buf, v->name_size);
+ if (v->name_size) { GRN_TEXT_PUT(ctx, buf, v->name, v->name_size); }
+ grn_obj_pack(ctx, buf, &v->value);
+ }
+ i = e->codes_curr;
+ grn_text_benc(ctx, buf, i);
+ for (c = e->codes; i; i--, c++) {
+ grn_text_benc(ctx, buf, c->op);
+ grn_text_benc(ctx, buf, c->nargs);
+ if (!c->value) {
+ grn_text_benc(ctx, buf, GRN_EXPR_PACK_TYPE_NULL);
+ } else {
+ for (j = 0, v = e->vars; j < e->nvars; j++, v++) {
+ if (&v->value == c->value) {
+ grn_text_benc(ctx, buf, GRN_EXPR_PACK_TYPE_VARIABLE);
+ grn_text_benc(ctx, buf, j);
+ break;
+ }
+ }
+ if (j == e->nvars) {
+ grn_text_benc(ctx, buf, GRN_EXPR_PACK_TYPE_OTHERS);
+ grn_obj_pack(ctx, buf, c->value);
+ }
+ }
+ }
+}
+
+const uint8_t *
+grn_expr_unpack(grn_ctx *ctx, const uint8_t *p, const uint8_t *pe, grn_obj *expr)
+{
+ grn_obj *v;
+ grn_expr_pack_type type;
+ uint32_t i, n, ns;
+ grn_expr_code *code;
+ grn_expr *e = (grn_expr *)expr;
+ GRN_B_DEC(n, p);
+ for (i = 0; i < n; i++) {
+ uint32_t object_type;
+ GRN_B_DEC(ns, p);
+ v = grn_expr_add_var(ctx, expr, ns ? (const char *)p : NULL, ns);
+ p += ns;
+ GRN_B_DEC(object_type, p);
+ if (GRN_TYPE <= object_type && object_type <= GRN_COLUMN_INDEX) { /* error */ }
+ p = grn_obj_unpack(ctx, p, pe, object_type, 0, v);
+ if (pe < p) {
+ ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
+ return p;
+ }
+ }
+ GRN_B_DEC(n, p);
+ /* confirm e->codes_size >= n */
+ e->codes_curr = n;
+ for (i = 0, code = e->codes; i < n; i++, code++) {
+ GRN_B_DEC(code->op, p);
+ GRN_B_DEC(code->nargs, p);
+ GRN_B_DEC(type, p);
+ switch (type) {
+ case GRN_EXPR_PACK_TYPE_NULL :
+ code->value = NULL;
+ break;
+ case GRN_EXPR_PACK_TYPE_VARIABLE :
+ {
+ uint32_t offset;
+ GRN_B_DEC(offset, p);
+ code->value = &e->vars[i].value;
+ }
+ break;
+ case GRN_EXPR_PACK_TYPE_OTHERS :
+ {
+ uint32_t object_type;
+ GRN_B_DEC(object_type, p);
+ if (GRN_TYPE <= object_type && object_type <= GRN_COLUMN_INDEX) {
+ grn_id id;
+ GRN_B_DEC(id, p);
+ code->value = grn_ctx_at(ctx, id);
+ } else {
+ if (!(v = grn_expr_alloc_const(ctx, expr))) { return NULL; }
+ p = grn_obj_unpack(ctx, p, pe, object_type, GRN_OBJ_EXPRCONST, v);
+ code->value = v;
+ }
+ }
+ break;
+ }
+ if (pe < p) {
+ ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
+ return p;
+ }
+ }
+ return p;
+}
+
+grn_obj *
+grn_expr_open(grn_ctx *ctx, grn_obj_spec *spec, const uint8_t *p, const uint8_t *pe)
+{
+ grn_expr *expr = NULL;
+ if ((expr = GRN_MALLOCN(grn_expr, 1))) {
+ int size = GRN_STACK_SIZE;
+ expr->const_blks = NULL;
+ expr->nconsts = 0;
+ GRN_TEXT_INIT(&expr->name_buf, 0);
+ GRN_TEXT_INIT(&expr->dfi, 0);
+ GRN_PTR_INIT(&expr->objs, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ expr->vars = NULL;
+ expr->nvars = 0;
+ GRN_DB_OBJ_SET_TYPE(expr, GRN_EXPR);
+ if ((expr->values = GRN_MALLOCN(grn_obj, size))) {
+ int i;
+ for (i = 0; i < size; i++) {
+ GRN_OBJ_INIT(&expr->values[i], GRN_BULK, GRN_OBJ_EXPRVALUE, GRN_ID_NIL);
+ }
+ expr->values_curr = 0;
+ expr->values_tail = 0;
+ expr->values_size = size;
+ if ((expr->codes = GRN_MALLOCN(grn_expr_code, size))) {
+ expr->codes_curr = 0;
+ expr->codes_size = size;
+ expr->obj.header = spec->header;
+ if (grn_expr_unpack(ctx, p, pe, (grn_obj *)expr) == pe) {
+ goto exit;
+ } else {
+ ERR(GRN_INVALID_FORMAT, "benced image is corrupt");
+ }
+ GRN_FREE(expr->codes);
+ }
+ GRN_FREE(expr->values);
+ }
+ GRN_FREE(expr);
+ expr = NULL;
+ }
+exit :
+ return (grn_obj *)expr;
+}
+
+/* Pass ownership of `obj` to `expr`. */
+void
+grn_expr_take_obj(grn_ctx *ctx, grn_obj *expr, grn_obj *obj)
+{
+ grn_expr *e = (grn_expr *)expr;
+ GRN_PTR_PUT(ctx, &(e->objs), obj);
+}
+
+/* data flow info */
+typedef struct {
+ grn_expr_code *code;
+ grn_id domain;
+ unsigned char type;
+} grn_expr_dfi;
+
+static grn_expr_dfi *
+grn_expr_dfi_pop(grn_expr *expr)
+{
+ if ((size_t) GRN_BULK_VSIZE(&expr->dfi) >= sizeof(grn_expr_dfi)) {
+ grn_expr_dfi *dfi;
+ GRN_BULK_INCR_LEN(&expr->dfi, -((ssize_t)(sizeof(grn_expr_dfi))));
+ dfi = (grn_expr_dfi *)GRN_BULK_CURR(&expr->dfi);
+ expr->code0 = dfi->code;
+ return dfi;
+ } else {
+ expr->code0 = NULL;
+ return NULL;
+ }
+}
+
+static void
+grn_expr_dfi_put(grn_ctx *ctx, grn_expr *expr, uint8_t type, grn_id domain,
+ grn_expr_code *code)
+{
+ grn_expr_dfi dfi;
+ dfi.type = type;
+ dfi.domain = domain;
+ dfi.code = code;
+ if (expr->code0) {
+ expr->code0->modify = code ? (code - expr->code0) : 0;
+ }
+ grn_bulk_write(ctx, &expr->dfi, (char *)&dfi, sizeof(grn_expr_dfi));
+ expr->code0 = NULL;
+}
+
+grn_obj *
+grn_expr_create(grn_ctx *ctx, const char *name, unsigned int name_size)
+{
+ grn_id id;
+ grn_obj *db;
+ grn_expr *expr = NULL;
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "db not initialized");
+ return NULL;
+ }
+ if (name_size) {
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[expr][create] named expression isn't implemented yet");
+ return NULL;
+ }
+ GRN_API_ENTER;
+ if (grn_db_check_name(ctx, name, name_size)) {
+ GRN_DB_CHECK_NAME_ERR("[expr][create]", name, name_size);
+ GRN_API_RETURN(NULL);
+ }
+ if (!GRN_DB_P(db)) {
+ ERR(GRN_INVALID_ARGUMENT, "named expr is not supported");
+ GRN_API_RETURN(NULL);
+ }
+ id = grn_obj_register(ctx, db, name, name_size);
+ if (id && (expr = GRN_MALLOCN(grn_expr, 1))) {
+ int size = GRN_STACK_SIZE;
+ expr->const_blks = NULL;
+ expr->nconsts = 0;
+ GRN_TEXT_INIT(&expr->name_buf, 0);
+ GRN_TEXT_INIT(&expr->dfi, 0);
+ GRN_PTR_INIT(&expr->objs, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ expr->code0 = NULL;
+ expr->vars = NULL;
+ expr->nvars = 0;
+ expr->cacheable = 1;
+ expr->taintable = 0;
+ expr->values_curr = 0;
+ expr->values_tail = 0;
+ expr->values_size = size;
+ expr->codes_curr = 0;
+ expr->codes_size = size;
+ GRN_DB_OBJ_SET_TYPE(expr, GRN_EXPR);
+ expr->obj.header.domain = GRN_ID_NIL;
+ expr->obj.range = GRN_ID_NIL;
+ if (!grn_db_obj_init(ctx, db, id, DB_OBJ(expr))) {
+ if ((expr->values = GRN_MALLOCN(grn_obj, size))) {
+ int i;
+ for (i = 0; i < size; i++) {
+ GRN_OBJ_INIT(&expr->values[i], GRN_BULK, GRN_OBJ_EXPRVALUE, GRN_ID_NIL);
+ }
+ if ((expr->codes = GRN_MALLOCN(grn_expr_code, size))) {
+ goto exit;
+ }
+ GRN_FREE(expr->values);
+ }
+ }
+ GRN_FREE(expr);
+ expr = NULL;
+ }
+exit :
+ GRN_API_RETURN((grn_obj *)expr);
+}
+
+grn_rc
+grn_expr_close(grn_ctx *ctx, grn_obj *expr)
+{
+ uint32_t i, j;
+ grn_expr *e = (grn_expr *)expr;
+ GRN_API_ENTER;
+ /*
+ if (e->obj.header.domain) {
+ grn_hash_delete(ctx, ctx->impl->qe, &e->obj.header.domain, sizeof(grn_id), NULL);
+ }
+ */
+ grn_expr_clear_vars(ctx, expr);
+ if (e->const_blks) {
+ uint32_t nblks = e->nconsts + GRN_EXPR_CONST_BLK_SIZE - 1;
+ nblks /= GRN_EXPR_CONST_BLK_SIZE;
+ for (i = 0; i < nblks; i++) {
+ uint32_t end;
+ if (i < nblks - 1) {
+ end = GRN_EXPR_CONST_BLK_SIZE;
+ } else {
+ end = ((e->nconsts - 1) % GRN_EXPR_CONST_BLK_SIZE) + 1;
+ }
+ for (j = 0; j < end; j++) {
+ grn_obj *const_obj = &e->const_blks[i][j];
+ grn_obj_close(ctx, const_obj);
+ }
+ GRN_FREE(e->const_blks[i]);
+ }
+ GRN_FREE(e->const_blks);
+ }
+ grn_obj_close(ctx, &e->name_buf);
+ grn_obj_close(ctx, &e->dfi);
+ for (;;) {
+ grn_obj *obj;
+ GRN_PTR_POP(&e->objs, obj);
+ if (obj) {
+#ifdef USE_MEMORY_DEBUG
+ grn_obj_unlink(ctx, obj);
+#else
+ if (obj->header.type) {
+ if (obj->header.type == GRN_TABLE_HASH_KEY &&
+ ((grn_hash *)obj)->value_size == sizeof(grn_obj)) {
+ grn_obj *value;
+ GRN_HASH_EACH(ctx, (grn_hash *)obj, id, NULL, NULL, (void **)&value, {
+ GRN_OBJ_FIN(ctx, value);
+ });
+ }
+ grn_obj_unlink(ctx, obj);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "GRN_VOID object is tried to be unlinked");
+ }
+#endif
+ } else { break; }
+ }
+ grn_obj_close(ctx, &e->objs);
+ for (i = 0; i < e->nvars; i++) {
+ grn_obj_close(ctx, &e->vars[i].value);
+ }
+ if (e->vars) { GRN_FREE(e->vars); }
+ for (i = 0; i < e->values_tail; i++) {
+ grn_obj_close(ctx, &e->values[i]);
+ }
+ GRN_FREE(e->values);
+ GRN_FREE(e->codes);
+ GRN_FREE(e);
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_obj *
+grn_expr_add_var(grn_ctx *ctx, grn_obj *expr, const char *name, unsigned int name_size)
+{
+ uint32_t i;
+ char *p;
+ grn_expr_var *v;
+ grn_obj *res = NULL;
+ grn_expr *e = (grn_expr *)expr;
+ GRN_API_ENTER;
+ if (DB_OBJ(expr)->id & GRN_OBJ_TMP_OBJECT) {
+ res = grn_expr_get_or_add_var(ctx, expr, name, name_size);
+ } else {
+ if (!e->vars) {
+ if (!(e->vars = GRN_MALLOCN(grn_expr_var, GRN_STACK_SIZE))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "malloc failed");
+ }
+ }
+ if (e->vars && e->nvars < GRN_STACK_SIZE) {
+ v = e->vars + e->nvars++;
+ if (name_size) {
+ GRN_TEXT_PUT(ctx, &e->name_buf, name, name_size);
+ } else {
+ uint32_t ol = GRN_TEXT_LEN(&e->name_buf);
+ GRN_TEXT_PUTC(ctx, &e->name_buf, '$');
+ grn_text_itoa(ctx, &e->name_buf, e->nvars);
+ name_size = GRN_TEXT_LEN(&e->name_buf) - ol;
+ }
+ v->name_size = name_size;
+ res = &v->value;
+ GRN_VOID_INIT(res);
+ for (i = e->nvars, p = GRN_TEXT_VALUE(&e->name_buf), v = e->vars; i; i--, v++) {
+ v->name = p;
+ p += v->name_size;
+ }
+ }
+ }
+ GRN_API_RETURN(res);
+}
+
+grn_obj *
+grn_expr_get_var(grn_ctx *ctx, grn_obj *expr, const char *name, unsigned int name_size)
+{
+ uint32_t n;
+ grn_obj *res = NULL;
+ grn_hash *vars = grn_expr_get_vars(ctx, expr, &n);
+ if (vars) { grn_hash_get(ctx, vars, name, name_size, (void **)&res); }
+ return res;
+}
+
+grn_obj *
+grn_expr_get_or_add_var(grn_ctx *ctx, grn_obj *expr, const char *name, unsigned int name_size)
+{
+ uint32_t n;
+ grn_obj *res = NULL;
+ grn_hash *vars = grn_expr_get_vars(ctx, expr, &n);
+ if (vars) {
+ int added = 0;
+ char name_buf[16];
+ if (!name_size) {
+ char *rest;
+ name_buf[0] = '$';
+ grn_itoa((int)GRN_HASH_SIZE(vars) + 1, name_buf + 1, name_buf + 16, &rest);
+ name_size = rest - name_buf;
+ name = name_buf;
+ }
+ grn_hash_add(ctx, vars, name, name_size, (void **)&res, &added);
+ if (added) { GRN_TEXT_INIT(res, 0); }
+ }
+ return res;
+}
+
+grn_obj *
+grn_expr_get_var_by_offset(grn_ctx *ctx, grn_obj *expr, unsigned int offset)
+{
+ uint32_t n;
+ grn_obj *res = NULL;
+ grn_hash *vars = grn_expr_get_vars(ctx, expr, &n);
+ if (vars) { res = (grn_obj *)grn_hash_get_value_(ctx, vars, offset + 1, NULL); }
+ return res;
+}
+
+#define EXPRVP(x) ((x)->header.impl_flags & GRN_OBJ_EXPRVALUE)
+
+#define CONSTP(obj) ((obj) && ((obj)->header.impl_flags & GRN_OBJ_EXPRCONST))
+
+#define PUSH_CODE(e,o,v,n,c) do {\
+ (c) = &(e)->codes[e->codes_curr++];\
+ (c)->value = (v);\
+ (c)->nargs = (n);\
+ (c)->op = (o);\
+ (c)->flags = 0;\
+ (c)->modify = 0;\
+} while (0)
+
+#define APPEND_UNARY_MINUS_OP(e) do { \
+ grn_expr_code *code_; \
+ grn_id domain; \
+ unsigned char type; \
+ grn_obj *x; \
+ dfi = grn_expr_dfi_pop(e); \
+ code_ = dfi->code; \
+ domain = dfi->domain; \
+ type = dfi->type; \
+ x = code_->value; \
+ if (CONSTP(x)) { \
+ switch (domain) { \
+ case GRN_DB_INT32: \
+ { \
+ int value; \
+ value = GRN_INT32_VALUE(x); \
+ if (value == (int)0x80000000) { \
+ domain = GRN_DB_INT64; \
+ x->header.domain = domain; \
+ GRN_INT64_SET(ctx, x, -((long long int)value)); \
+ } else { \
+ GRN_INT32_SET(ctx, x, -value); \
+ } \
+ } \
+ break; \
+ case GRN_DB_UINT32: \
+ { \
+ unsigned int value; \
+ value = GRN_UINT32_VALUE(x); \
+ if (value > (unsigned int)0x80000000) { \
+ domain = GRN_DB_INT64; \
+ x->header.domain = domain; \
+ GRN_INT64_SET(ctx, x, -((long long int)value)); \
+ } else { \
+ domain = GRN_DB_INT32; \
+ x->header.domain = domain; \
+ GRN_INT32_SET(ctx, x, -((int)value)); \
+ } \
+ } \
+ break; \
+ case GRN_DB_INT64: \
+ GRN_INT64_SET(ctx, x, -GRN_INT64_VALUE(x)); \
+ break; \
+ case GRN_DB_FLOAT: \
+ GRN_FLOAT_SET(ctx, x, -GRN_FLOAT_VALUE(x)); \
+ break; \
+ default: \
+ PUSH_CODE(e, op, obj, nargs, code); \
+ break; \
+ } \
+ } else { \
+ PUSH_CODE(e, op, obj, nargs, code); \
+ } \
+ grn_expr_dfi_put(ctx, e, type, domain, code_); \
+} while (0)
+
+#define PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code) do { \
+ PUSH_CODE(e, op, obj, nargs, code); \
+ { \
+ int i = nargs; \
+ while (i--) { \
+ dfi = grn_expr_dfi_pop(e); \
+ } \
+ } \
+ grn_expr_dfi_put(ctx, e, type, domain, code); \
+} while (0)
+
+static void
+grn_expr_append_obj_resolve_const(grn_ctx *ctx,
+ grn_obj *obj,
+ grn_id to_domain)
+{
+ grn_obj dest;
+
+ GRN_OBJ_INIT(&dest, GRN_BULK, 0, to_domain);
+ if (!grn_obj_cast(ctx, obj, &dest, GRN_FALSE)) {
+ grn_obj_reinit(ctx, obj, to_domain, 0);
+ grn_bulk_write(ctx, obj, GRN_BULK_HEAD(&dest), GRN_BULK_VSIZE(&dest));
+ }
+ GRN_OBJ_FIN(ctx, &dest);
+}
+
+grn_obj *
+grn_expr_append_obj(grn_ctx *ctx, grn_obj *expr, grn_obj *obj, grn_operator op, int nargs)
+{
+ uint8_t type = GRN_VOID;
+ grn_id domain = GRN_ID_NIL;
+ grn_expr_dfi *dfi;
+ grn_expr_code *code;
+ grn_obj *res = NULL;
+ grn_expr *e = (grn_expr *)expr;
+ GRN_API_ENTER;
+ if (e->codes_curr >= e->codes_size) {
+ grn_expr_dfi *dfis = (grn_expr_dfi *)GRN_BULK_HEAD(&e->dfi);
+ size_t i, n_dfis = GRN_BULK_VSIZE(&e->dfi) / sizeof(grn_expr_dfi);
+ uint32_t new_codes_size = e->codes_size * 2;
+ size_t n_bytes = sizeof(grn_expr_code) * new_codes_size;
+ grn_expr_code *new_codes = (grn_expr_code *)GRN_MALLOC(n_bytes);
+ if (!new_codes) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "stack is full");
+ goto exit;
+ }
+ grn_memcpy(new_codes, e->codes, sizeof(grn_expr_code) * e->codes_size);
+ if (e->code0 >= e->codes && e->code0 < e->codes + e->codes_size) {
+ e->code0 = new_codes + (e->code0 - e->codes);
+ }
+ for (i = 0; i < n_dfis; i++) {
+ if (dfis[i].code >= e->codes && dfis[i].code < e->codes + e->codes_size) {
+ dfis[i].code = new_codes + (dfis[i].code - e->codes);
+ }
+ }
+ GRN_FREE(e->codes);
+ e->codes = new_codes;
+ e->codes_size = new_codes_size;
+ }
+ {
+ switch (op) {
+ case GRN_OP_PUSH :
+ if (obj) {
+ PUSH_CODE(e, op, obj, nargs, code);
+ grn_expr_dfi_put(ctx, e, obj->header.type, GRN_OBJ_GET_DOMAIN(obj),
+ code);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "obj not assigned for GRN_OP_PUSH");
+ goto exit;
+ }
+ break;
+ case GRN_OP_NOP :
+ /* nop */
+ break;
+ case GRN_OP_POP :
+ if (obj) {
+ ERR(GRN_INVALID_ARGUMENT, "obj assigned for GRN_OP_POP");
+ goto exit;
+ } else {
+ PUSH_CODE(e, op, obj, nargs, code);
+ dfi = grn_expr_dfi_pop(e);
+ }
+ break;
+ case GRN_OP_CALL :
+ {
+ grn_obj *proc = NULL;
+ /*
+ * This is for keeping backward compatibility. We want to
+ * handle all "nargs" means that "N items on stack are used (N
+ * items are popped)" but "nargs" for OP_CALL is used as "N
+ * arguments" not "N items on stack are used" historically. It
+ * means that called function isn't included in "nargs".
+ *
+ * We adjust "nargs" here to handle "code->nargs" more easily.
+ * If we don't adjust "nargs" here, we need to care
+ * "code->nargs" at all locations that use "code->nargs". We
+ * need to use "code->nargs + 1" for OP_CALL and "code->nargs"
+ * for not OP_CALL to compute N items should be popped. It's
+ * wired. So we adjust "nargs" here.
+ */
+ nargs++;
+ if (e->codes_curr - (nargs - 1) > 0) {
+ int i;
+ grn_expr_code *code;
+ code = &(e->codes[e->codes_curr - 1]);
+ for (i = 0; i < nargs - 1; i++) {
+ int rest_n_codes = 1;
+ while (rest_n_codes > 0) {
+ rest_n_codes += code->nargs;
+ if (code->value) {
+ rest_n_codes--;
+ }
+ rest_n_codes--;
+ code--;
+ }
+ }
+ proc = code->value;
+ }
+ if (!proc) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid function call expression");
+ goto exit;
+ }
+ if (!(grn_obj_is_function_proc(ctx, proc) ||
+ grn_obj_is_scorer_proc(ctx, proc) ||
+ grn_obj_is_window_function_proc(ctx, proc))) {
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ switch (proc->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ case GRN_COLUMN_FIX_SIZE:
+ case GRN_COLUMN_VAR_SIZE:
+ case GRN_COLUMN_INDEX:
+ grn_inspect_name(ctx, &buffer, proc);
+ break;
+ default:
+ grn_inspect(ctx, &buffer, proc);
+ break;
+ }
+ ERR(GRN_INVALID_ARGUMENT, "invalid function: <%.*s>",
+ (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+ goto exit;
+ }
+
+ PUSH_CODE(e, op, obj, nargs, code);
+ {
+ int i = nargs - 1;
+ while (i--) { dfi = grn_expr_dfi_pop(e); }
+ }
+ if (!obj) { dfi = grn_expr_dfi_pop(e); }
+ // todo : increment e->values_tail.
+ /* cannot identify type of return value */
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ if (!grn_proc_is_stable(ctx, proc)) {
+ e->cacheable = 0;
+ }
+ }
+ break;
+ case GRN_OP_INTERN :
+ if (obj && CONSTP(obj)) {
+ grn_obj *value;
+ value = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj));
+ if (!value) { value = grn_ctx_get(ctx, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); }
+ if (value) {
+ obj = value;
+ op = GRN_OP_PUSH;
+ type = obj->header.type;
+ domain = GRN_OBJ_GET_DOMAIN(obj);
+ }
+ }
+ PUSH_CODE(e, op, obj, nargs, code);
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_EQUAL :
+ PUSH_CODE(e, op, obj, nargs, code);
+ if (nargs) {
+ grn_id xd, yd = GRN_ID_NIL;
+ grn_obj *x, *y = NULL;
+ int i = nargs - 1;
+ if (obj) {
+ xd = GRN_OBJ_GET_DOMAIN(obj);
+ x = obj;
+ } else {
+ dfi = grn_expr_dfi_pop(e);
+ x = dfi->code->value;
+ xd = dfi->domain;
+ }
+ while (i--) {
+ dfi = grn_expr_dfi_pop(e);
+ y = dfi->code->value;
+ yd = dfi->domain;
+ }
+ if (CONSTP(x)) {
+ if (CONSTP(y)) {
+ /* todo */
+ } else {
+ if (xd != yd) {
+ grn_expr_append_obj_resolve_const(ctx, x, yd);
+ }
+ }
+ } else {
+ if (CONSTP(y)) {
+ if (xd != yd) {
+ grn_expr_append_obj_resolve_const(ctx, y, xd);
+ }
+ }
+ }
+ }
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_TABLE_CREATE :
+ case GRN_OP_EXPR_GET_VAR :
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_GEO_DISTANCE1 :
+ case GRN_OP_GEO_DISTANCE2 :
+ case GRN_OP_GEO_DISTANCE3 :
+ case GRN_OP_GEO_DISTANCE4 :
+ case GRN_OP_GEO_WITHINP5 :
+ case GRN_OP_GEO_WITHINP6 :
+ case GRN_OP_GEO_WITHINP8 :
+ case GRN_OP_OBJ_SEARCH :
+ case GRN_OP_TABLE_SELECT :
+ case GRN_OP_TABLE_SORT :
+ case GRN_OP_TABLE_GROUP :
+ case GRN_OP_JSON_PUT :
+ case GRN_OP_GET_REF :
+ case GRN_OP_ADJUST :
+ case GRN_OP_TERM_EXTRACT :
+ case GRN_OP_REGEXP :
+ PUSH_CODE(e, op, obj, nargs, code);
+ if (nargs) {
+ int i = nargs - 1;
+ if (!obj) { dfi = grn_expr_dfi_pop(e); }
+ while (i--) { dfi = grn_expr_dfi_pop(e); }
+ }
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_AND :
+ case GRN_OP_OR :
+ case GRN_OP_AND_NOT :
+ PUSH_CODE(e, op, obj, nargs, code);
+ if (nargs != 2) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "nargs(%d) != 2 in relative op", nargs);
+ }
+ if (obj) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "obj assigned to relative op");
+ }
+ {
+ int i = nargs;
+ while (i--) {
+ dfi = grn_expr_dfi_pop(e);
+ if (dfi) {
+ dfi->code->flags |= GRN_EXPR_CODE_RELATIONAL_EXPRESSION;
+ } else {
+ ERR(GRN_SYNTAX_ERROR, "stack under flow in relative op");
+ }
+ }
+ }
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_NOT :
+ if (nargs == 1) {
+ PUSH_CODE(e, op, obj, nargs, code);
+ }
+ break;
+ case GRN_OP_PLUS :
+ if (nargs > 1) {
+ PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code);
+ }
+ break;
+ case GRN_OP_MINUS :
+ if (nargs == 1) {
+ APPEND_UNARY_MINUS_OP(e);
+ } else {
+ PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code);
+ }
+ break;
+ case GRN_OP_BITWISE_NOT :
+ dfi = grn_expr_dfi_pop(e);
+ if (dfi) {
+ type = dfi->type;
+ domain = dfi->domain;
+ switch (domain) {
+ case GRN_DB_UINT8 :
+ domain = GRN_DB_INT16;
+ break;
+ case GRN_DB_UINT16 :
+ domain = GRN_DB_INT32;
+ break;
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ domain = GRN_DB_INT64;
+ break;
+ }
+ }
+ PUSH_CODE(e, op, obj, nargs, code);
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_STAR :
+ case GRN_OP_SLASH :
+ case GRN_OP_MOD :
+ case GRN_OP_SHIFTL :
+ case GRN_OP_SHIFTR :
+ case GRN_OP_SHIFTRR :
+ case GRN_OP_BITWISE_OR :
+ case GRN_OP_BITWISE_XOR :
+ case GRN_OP_BITWISE_AND :
+ PUSH_N_ARGS_ARITHMETIC_OP(e, op, obj, nargs, code);
+ break;
+ case GRN_OP_INCR :
+ case GRN_OP_DECR :
+ case GRN_OP_INCR_POST :
+ case GRN_OP_DECR_POST :
+ {
+ dfi = grn_expr_dfi_pop(e);
+ if (dfi) {
+ type = dfi->type;
+ domain = dfi->domain;
+ if (dfi->code) {
+ if (dfi->code->op == GRN_OP_GET_VALUE) {
+ dfi->code->op = GRN_OP_GET_REF;
+ }
+ if (dfi->code->value && grn_obj_is_persistent(ctx, dfi->code->value)) {
+ e->cacheable = 0;
+ e->taintable = 1;
+ }
+ }
+ }
+ PUSH_CODE(e, op, obj, nargs, code);
+ }
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_GET_VALUE :
+ {
+ grn_id vdomain = GRN_ID_NIL;
+ if (obj) {
+ if (nargs == 1) {
+ grn_obj *v = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (v) { vdomain = GRN_OBJ_GET_DOMAIN(v); }
+ } else {
+ dfi = grn_expr_dfi_pop(e);
+ vdomain = dfi->domain;
+ }
+ if (vdomain && CONSTP(obj) && obj->header.type == GRN_BULK) {
+ grn_obj *table = grn_ctx_at(ctx, vdomain);
+ grn_obj *col = grn_obj_column(ctx, table, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
+ if (col) {
+ obj = col;
+ type = col->header.type;
+ domain = grn_obj_get_range(ctx, col);
+ grn_expr_take_obj(ctx, (grn_obj *)e, col);
+ }
+ } else {
+ domain = grn_obj_get_range(ctx, obj);
+ }
+ PUSH_CODE(e, op, obj, nargs, code);
+ } else {
+ grn_expr_dfi *dfi0;
+ dfi0 = grn_expr_dfi_pop(e);
+ if (nargs == 1) {
+ grn_obj *v = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (v) { vdomain = GRN_OBJ_GET_DOMAIN(v); }
+ } else {
+ dfi = grn_expr_dfi_pop(e);
+ vdomain = dfi->domain;
+ }
+ if (dfi0->code->op == GRN_OP_PUSH) {
+ dfi0->code->op = op;
+ dfi0->code->nargs = nargs;
+ obj = dfi0->code->value;
+ if (vdomain && obj && CONSTP(obj) && obj->header.type == GRN_BULK) {
+ grn_obj *table = grn_ctx_at(ctx, vdomain);
+ grn_obj *col = grn_obj_column(ctx, table, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
+ if (col) {
+ dfi0->code->value = col;
+ type = col->header.type;
+ domain = grn_obj_get_range(ctx, col);
+ grn_obj_unlink(ctx, col);
+ }
+ } else {
+ domain = grn_obj_get_range(ctx, obj);
+ }
+ code = dfi0->code;
+ } else {
+ PUSH_CODE(e, op, obj, nargs, code);
+ }
+ }
+ }
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_ASSIGN :
+ case GRN_OP_STAR_ASSIGN :
+ case GRN_OP_SLASH_ASSIGN :
+ case GRN_OP_MOD_ASSIGN :
+ case GRN_OP_PLUS_ASSIGN :
+ case GRN_OP_MINUS_ASSIGN :
+ case GRN_OP_SHIFTL_ASSIGN :
+ case GRN_OP_SHIFTR_ASSIGN :
+ case GRN_OP_SHIFTRR_ASSIGN :
+ case GRN_OP_AND_ASSIGN :
+ case GRN_OP_OR_ASSIGN :
+ case GRN_OP_XOR_ASSIGN :
+ {
+ if (obj) {
+ type = obj->header.type;
+ domain = GRN_OBJ_GET_DOMAIN(obj);
+ } else {
+ dfi = grn_expr_dfi_pop(e);
+ if (dfi) {
+ type = dfi->type;
+ domain = dfi->domain;
+ }
+ }
+ dfi = grn_expr_dfi_pop(e);
+ if (dfi && (dfi->code)) {
+ if (dfi->code->op == GRN_OP_GET_VALUE) {
+ dfi->code->op = GRN_OP_GET_REF;
+ }
+ if (dfi->code->value && grn_obj_is_persistent(ctx, dfi->code->value)) {
+ e->cacheable = 0;
+ e->taintable = 1;
+ }
+ }
+ PUSH_CODE(e, op, obj, nargs, code);
+ }
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ case GRN_OP_JUMP :
+ dfi = grn_expr_dfi_pop(e);
+ PUSH_CODE(e, op, obj, nargs, code);
+ break;
+ case GRN_OP_CJUMP :
+ dfi = grn_expr_dfi_pop(e);
+ PUSH_CODE(e, op, obj, nargs, code);
+ break;
+ case GRN_OP_COMMA :
+ PUSH_CODE(e, op, obj, nargs, code);
+ break;
+ case GRN_OP_GET_MEMBER :
+ dfi = grn_expr_dfi_pop(e);
+ dfi = grn_expr_dfi_pop(e);
+ if (dfi) {
+ type = dfi->type;
+ domain = dfi->domain;
+ if (dfi->code) {
+ if (dfi->code->op == GRN_OP_GET_VALUE) {
+ dfi->code->op = GRN_OP_GET_REF;
+ }
+ }
+ }
+ PUSH_CODE(e, op, obj, nargs, code);
+ grn_expr_dfi_put(ctx, e, type, domain, code);
+ break;
+ default :
+ break;
+ }
+ }
+exit :
+ if (!ctx->rc) { res = obj; }
+ GRN_API_RETURN(res);
+}
+#undef PUSH_N_ARGS_ARITHMETIC_OP
+#undef APPEND_UNARY_MINUS_OP
+
+grn_obj *
+grn_expr_append_const(grn_ctx *ctx, grn_obj *expr, grn_obj *obj,
+ grn_operator op, int nargs)
+{
+ grn_obj *res = NULL;
+ GRN_API_ENTER;
+ if (!obj) {
+ ERR(GRN_SYNTAX_ERROR, "constant is null");
+ goto exit;
+ }
+ if (GRN_DB_OBJP(obj) || GRN_ACCESSORP(obj)) {
+ res = obj;
+ } else {
+ if ((res = grn_expr_alloc_const(ctx, expr))) {
+ switch (obj->header.type) {
+ case GRN_VOID :
+ case GRN_BULK :
+ case GRN_UVECTOR :
+ GRN_OBJ_INIT(res, obj->header.type, 0, obj->header.domain);
+ grn_bulk_write(ctx, res, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
+ break;
+ default :
+ res = NULL;
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "unsupported type");
+ goto exit;
+ }
+ res->header.impl_flags |= GRN_OBJ_EXPRCONST;
+ }
+ }
+ grn_expr_append_obj(ctx, expr, res, op, nargs); /* constant */
+exit :
+ GRN_API_RETURN(res);
+}
+
+static grn_obj *
+grn_expr_add_str(grn_ctx *ctx, grn_obj *expr, const char *str, unsigned int str_size)
+{
+ grn_obj *res = NULL;
+ if ((res = grn_expr_alloc_const(ctx, expr))) {
+ GRN_TEXT_INIT(res, 0);
+ grn_bulk_write(ctx, res, str, str_size);
+ res->header.impl_flags |= GRN_OBJ_EXPRCONST;
+ }
+ return res;
+}
+
+grn_obj *
+grn_expr_append_const_str(grn_ctx *ctx, grn_obj *expr, const char *str, unsigned int str_size,
+ grn_operator op, int nargs)
+{
+ grn_obj *res;
+ GRN_API_ENTER;
+ res = grn_expr_add_str(ctx, expr, str, str_size);
+ grn_expr_append_obj(ctx, expr, res, op, nargs); /* constant */
+ GRN_API_RETURN(res);
+}
+
+grn_obj *
+grn_expr_append_const_int(grn_ctx *ctx, grn_obj *expr, int i,
+ grn_operator op, int nargs)
+{
+ grn_obj *res = NULL;
+ GRN_API_ENTER;
+ if ((res = grn_expr_alloc_const(ctx, expr))) {
+ GRN_INT32_INIT(res, 0);
+ GRN_INT32_SET(ctx, res, i);
+ res->header.impl_flags |= GRN_OBJ_EXPRCONST;
+ }
+ grn_expr_append_obj(ctx, expr, res, op, nargs); /* constant */
+ GRN_API_RETURN(res);
+}
+
+grn_rc
+grn_expr_append_op(grn_ctx *ctx, grn_obj *expr, grn_operator op, int nargs)
+{
+ grn_expr_append_obj(ctx, expr, NULL, op, nargs);
+ return ctx->rc;
+}
+
+grn_rc
+grn_expr_compile(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_obj_spec_save(ctx, DB_OBJ(expr));
+ return ctx->rc;
+}
+
+grn_obj *
+grn_expr_rewrite(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_obj *rewritten = NULL;
+
+ GRN_API_ENTER;
+
+#ifdef GRN_WITH_MRUBY
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ GRN_API_RETURN(NULL);
+ }
+ if (ctx->impl->mrb.state) {
+ rewritten = grn_mrb_expr_rewrite(ctx, expr);
+ }
+#endif
+
+ GRN_API_RETURN(rewritten);
+}
+
+#define WITH_SPSAVE(block) do {\
+ ctx->impl->stack_curr = sp - ctx->impl->stack;\
+ e->values_curr = vp - e->values;\
+ block\
+ vp = e->values + e->values_curr;\
+ sp = ctx->impl->stack + ctx->impl->stack_curr;\
+ s0 = sp[-1];\
+ s1 = sp[-2];\
+} while (0)
+
+#define GEO_RESOLUTION 3600000
+#define GEO_RADIOUS 6357303
+#define GEO_BES_C1 6334834
+#define GEO_BES_C2 6377397
+#define GEO_BES_C3 0.006674
+#define GEO_GRS_C1 6335439
+#define GEO_GRS_C2 6378137
+#define GEO_GRS_C3 0.006694
+#define GEO_INT2RAD(x) ((M_PI * x) / (GEO_RESOLUTION * 180))
+
+#define VAR_SET_VALUE(ctx,var,value) do {\
+ if (GRN_DB_OBJP(value)) {\
+ (var)->header.type = GRN_PTR;\
+ (var)->header.domain = DB_OBJ(value)->id;\
+ GRN_PTR_SET(ctx, (var), (value));\
+ } else {\
+ (var)->header.type = (value)->header.type;\
+ (var)->header.domain = (value)->header.domain;\
+ GRN_TEXT_SET(ctx, (var), GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));\
+ }\
+} while (0)
+
+grn_rc
+grn_proc_call(grn_ctx *ctx, grn_obj *proc, int nargs, grn_obj *caller)
+{
+ grn_proc_ctx pctx;
+ grn_obj *obj = NULL, **args;
+ grn_proc *p = (grn_proc *)proc;
+ if ((uint32_t) nargs > ctx->impl->stack_curr) { return GRN_INVALID_ARGUMENT; }
+ GRN_API_ENTER;
+ if (grn_obj_is_selector_only_proc(ctx, proc)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_obj_name(ctx, proc, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "selector only proc can't be called: <%.*s>",
+ name_size, name);
+ GRN_API_RETURN(ctx->rc);
+ }
+ args = ctx->impl->stack + ctx->impl->stack_curr - nargs;
+ pctx.proc = p;
+ pctx.caller = caller;
+ pctx.user_data.ptr = NULL;
+ if (p->funcs[PROC_INIT]) {
+ grn_obj *sub_obj;
+ sub_obj = p->funcs[PROC_INIT](ctx, nargs, args, &pctx.user_data);
+ if (sub_obj) {
+ obj = sub_obj;
+ }
+ }
+ pctx.phase = PROC_NEXT;
+ if (p->funcs[PROC_NEXT]) {
+ grn_obj *sub_obj;
+ sub_obj = p->funcs[PROC_NEXT](ctx, nargs, args, &pctx.user_data);
+ if (sub_obj) {
+ obj = sub_obj;
+ }
+ }
+ pctx.phase = PROC_FIN;
+ if (p->funcs[PROC_FIN]) {
+ grn_obj *sub_obj;
+ sub_obj = p->funcs[PROC_FIN](ctx, nargs, args, &pctx.user_data);
+ if (sub_obj) {
+ obj = sub_obj;
+ }
+ }
+ ctx->impl->stack_curr -= nargs;
+ grn_ctx_push(ctx, obj);
+ GRN_API_RETURN(ctx->rc);
+}
+
+#define PUSH1(v) do {\
+ if (EXPRVP(v)) {\
+ vp++;\
+ if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
+ }\
+ s1 = s0;\
+ *sp++ = s0 = v;\
+} while (0)
+
+#define POP1(v) do {\
+ if (EXPRVP(s0)) { vp--; }\
+ v = s0;\
+ s0 = s1;\
+ sp--;\
+ if (sp < s_) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\
+ s1 = sp[-2];\
+} while (0)
+
+#define ALLOC1(value) do {\
+ s1 = s0;\
+ *sp++ = s0 = value = vp++;\
+ if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
+} while (0)
+
+#define POP1ALLOC1(arg,value) do {\
+ arg = s0;\
+ if (EXPRVP(s0)) {\
+ value = s0;\
+ } else {\
+ if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\
+ sp[-1] = s0 = value = vp++;\
+ if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
+ s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\
+ }\
+} while (0)
+
+#define POP2ALLOC1(arg1,arg2,value) do {\
+ if (EXPRVP(s0)) { vp--; }\
+ if (EXPRVP(s1)) { vp--; }\
+ arg2 = s0;\
+ arg1 = s1;\
+ sp--;\
+ if (sp < s_ + 1) { ERR(GRN_INVALID_ARGUMENT, "stack underflow"); goto exit; }\
+ s1 = sp[-2];\
+ sp[-1] = s0 = value = vp++;\
+ if (vp - e->values > e->values_tail) { e->values_tail = vp - e->values; }\
+ s0->header.impl_flags |= GRN_OBJ_EXPRVALUE;\
+} while (0)
+
+#define INTEGER_ARITHMETIC_OPERATION_PLUS(x, y) ((x) + (y))
+#define FLOAT_ARITHMETIC_OPERATION_PLUS(x, y) ((double)(x) + (double)(y))
+#define INTEGER_ARITHMETIC_OPERATION_MINUS(x, y) ((x) - (y))
+#define FLOAT_ARITHMETIC_OPERATION_MINUS(x, y) ((double)(x) - (double)(y))
+#define INTEGER_ARITHMETIC_OPERATION_STAR(x, y) ((x) * (y))
+#define FLOAT_ARITHMETIC_OPERATION_STAR(x, y) ((double)(x) * (double)(y))
+#define INTEGER_ARITHMETIC_OPERATION_SLASH(x, y) ((x) / (y))
+#define FLOAT_ARITHMETIC_OPERATION_SLASH(x, y) ((double)(x) / (double)(y))
+#define INTEGER_ARITHMETIC_OPERATION_MOD(x, y) ((x) % (y))
+#define FLOAT_ARITHMETIC_OPERATION_MOD(x, y) (fmod((x), (y)))
+#define INTEGER_ARITHMETIC_OPERATION_SHIFTL(x, y) ((x) << (y))
+#define FLOAT_ARITHMETIC_OPERATION_SHIFTL(x, y) \
+ ((long long int)(x) << (long long int)(y))
+#define INTEGER_ARITHMETIC_OPERATION_SHIFTR(x, y) ((x) >> (y))
+#define FLOAT_ARITHMETIC_OPERATION_SHIFTR(x, y) \
+ ((long long int)(x) >> (long long int)(y))
+#define INTEGER8_ARITHMETIC_OPERATION_SHIFTRR(x, y) \
+ ((uint8_t)(x) >> (y))
+#define INTEGER16_ARITHMETIC_OPERATION_SHIFTRR(x, y) \
+ ((uint16_t)(x) >> (y))
+#define INTEGER32_ARITHMETIC_OPERATION_SHIFTRR(x, y) \
+ ((unsigned int)(x) >> (y))
+#define INTEGER64_ARITHMETIC_OPERATION_SHIFTRR(x, y) \
+ ((long long unsigned int)(x) >> (y))
+#define FLOAT_ARITHMETIC_OPERATION_SHIFTRR(x, y) \
+ ((long long unsigned int)(x) >> (long long unsigned int)(y))
+
+#define INTEGER_ARITHMETIC_OPERATION_BITWISE_OR(x, y) ((x) | (y))
+#define FLOAT_ARITHMETIC_OPERATION_BITWISE_OR(x, y) \
+ ((long long int)(x) | (long long int)(y))
+#define INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) ((x) ^ (y))
+#define FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR(x, y) \
+ ((long long int)(x) ^ (long long int)(y))
+#define INTEGER_ARITHMETIC_OPERATION_BITWISE_AND(x, y) ((x) & (y))
+#define FLOAT_ARITHMETIC_OPERATION_BITWISE_AND(x, y) \
+ ((long long int)(x) & (long long int)(y))
+
+#define INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x))
+#define FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS(x) (-(x))
+#define INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) (~(x))
+#define FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT(x) \
+ (~((long long int)(x)))
+
+#define TEXT_ARITHMETIC_OPERATION(operator) do { \
+ long long int x_; \
+ long long int y_; \
+ \
+ res->header.domain = GRN_DB_INT64; \
+ \
+ GRN_INT64_SET(ctx, res, 0); \
+ grn_obj_cast(ctx, x, res, GRN_FALSE); \
+ x_ = GRN_INT64_VALUE(res); \
+ \
+ GRN_INT64_SET(ctx, res, 0); \
+ grn_obj_cast(ctx, y, res, GRN_FALSE); \
+ y_ = GRN_INT64_VALUE(res); \
+ \
+ GRN_INT64_SET(ctx, res, x_ operator y_); \
+} while (0)
+
+#define TEXT_UNARY_ARITHMETIC_OPERATION(unary_operator) do { \
+ long long int x_; \
+ \
+ res->header.domain = GRN_DB_INT64; \
+ \
+ GRN_INT64_SET(ctx, res, 0); \
+ grn_obj_cast(ctx, x, res, GRN_FALSE); \
+ x_ = GRN_INT64_VALUE(res); \
+ \
+ GRN_INT64_SET(ctx, res, unary_operator x_); \
+} while (0)
+
+#define ARITHMETIC_OPERATION_NO_CHECK(y) do {} while (0)
+#define ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y) do { \
+ if ((long long int)y == 0) { \
+ ERR(GRN_INVALID_ARGUMENT, "divisor should not be 0"); \
+ goto exit; \
+ } \
+} while (0)
+
+
+#define NUMERIC_ARITHMETIC_OPERATION_DISPATCH(set, get, x_, y, res, \
+ integer_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error) do { \
+ switch (y->header.domain) { \
+ case GRN_DB_INT8 : \
+ { \
+ int8_t y_; \
+ y_ = GRN_INT8_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT8 : \
+ { \
+ uint8_t y_; \
+ y_ = GRN_UINT8_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_INT16 : \
+ { \
+ int16_t y_; \
+ y_ = GRN_INT16_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT16 : \
+ { \
+ uint16_t y_; \
+ y_ = GRN_UINT16_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_INT32 : \
+ { \
+ int y_; \
+ y_ = GRN_INT32_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT32 : \
+ { \
+ unsigned int y_; \
+ y_ = GRN_UINT32_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_TIME : \
+ { \
+ long long int y_; \
+ y_ = GRN_TIME_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_INT64 : \
+ { \
+ long long int y_; \
+ y_ = GRN_INT64_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT64 : \
+ { \
+ long long unsigned int y_; \
+ y_ = GRN_UINT64_VALUE(y); \
+ right_expression_check(y_); \
+ set(ctx, res, integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_FLOAT : \
+ { \
+ double y_; \
+ y_ = GRN_FLOAT_VALUE(y); \
+ right_expression_check(y_); \
+ res->header.domain = GRN_DB_FLOAT; \
+ GRN_FLOAT_SET(ctx, res, float_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_SHORT_TEXT : \
+ case GRN_DB_TEXT : \
+ case GRN_DB_LONG_TEXT : \
+ set(ctx, res, 0); \
+ if (grn_obj_cast(ctx, y, res, GRN_FALSE)) { \
+ ERR(GRN_INVALID_ARGUMENT, \
+ "not a numerical format: <%.*s>", \
+ (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y)); \
+ goto exit; \
+ } \
+ set(ctx, res, integer_operation(x_, get(res))); \
+ break; \
+ default : \
+ invalid_type_error; \
+ break; \
+ } \
+} while (0)
+
+
+#define ARITHMETIC_OPERATION_DISPATCH(x, y, res, \
+ integer8_operation, \
+ integer16_operation, \
+ integer32_operation, \
+ integer64_operation, \
+ float_operation, \
+ left_expression_check, \
+ right_expression_check, \
+ text_operation, \
+ invalid_type_error) do { \
+ switch (x->header.domain) { \
+ case GRN_DB_INT8 : \
+ { \
+ int8_t x_; \
+ x_ = GRN_INT8_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT8_SET, \
+ GRN_INT8_VALUE, \
+ x_, y, res, \
+ integer8_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_UINT8 : \
+ { \
+ uint8_t x_; \
+ x_ = GRN_UINT8_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT8_SET, \
+ GRN_UINT8_VALUE, \
+ x_, y, res, \
+ integer8_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_INT16 : \
+ { \
+ int16_t x_; \
+ x_ = GRN_INT16_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT16_SET, \
+ GRN_INT16_VALUE, \
+ x_, y, res, \
+ integer16_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_UINT16 : \
+ { \
+ uint16_t x_; \
+ x_ = GRN_UINT16_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT16_SET, \
+ GRN_UINT16_VALUE, \
+ x_, y, res, \
+ integer16_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_INT32 : \
+ { \
+ int x_; \
+ x_ = GRN_INT32_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT32_SET, \
+ GRN_INT32_VALUE, \
+ x_, y, res, \
+ integer32_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_UINT32 : \
+ { \
+ unsigned int x_; \
+ x_ = GRN_UINT32_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT32_SET, \
+ GRN_UINT32_VALUE, \
+ x_, y, res, \
+ integer32_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_INT64 : \
+ { \
+ long long int x_; \
+ x_ = GRN_INT64_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_INT64_SET, \
+ GRN_INT64_VALUE, \
+ x_, y, res, \
+ integer64_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_TIME : \
+ { \
+ long long int x_; \
+ x_ = GRN_TIME_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_TIME_SET, \
+ GRN_TIME_VALUE, \
+ x_, y, res, \
+ integer64_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_UINT64 : \
+ { \
+ long long unsigned int x_; \
+ x_ = GRN_UINT64_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_UINT64_SET, \
+ GRN_UINT64_VALUE, \
+ x_, y, res, \
+ integer64_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_FLOAT : \
+ { \
+ double x_; \
+ x_ = GRN_FLOAT_VALUE(x); \
+ left_expression_check(x_); \
+ NUMERIC_ARITHMETIC_OPERATION_DISPATCH(GRN_FLOAT_SET, \
+ GRN_FLOAT_VALUE, \
+ x_, y, res, \
+ float_operation, \
+ float_operation, \
+ right_expression_check, \
+ invalid_type_error); \
+ } \
+ break; \
+ case GRN_DB_SHORT_TEXT : \
+ case GRN_DB_TEXT : \
+ case GRN_DB_LONG_TEXT : \
+ text_operation; \
+ break; \
+ default: \
+ invalid_type_error; \
+ break; \
+ } \
+ code++; \
+} while (0)
+
+#define ARITHMETIC_BINARY_OPERATION_DISPATCH(operator, \
+ integer8_operation, \
+ integer16_operation, \
+ integer32_operation, \
+ integer64_operation, \
+ float_operation, \
+ left_expression_check, \
+ right_expression_check, \
+ text_operation, \
+ invalid_type_error) do { \
+ grn_obj *x, *y; \
+ \
+ POP2ALLOC1(x, y, res); \
+ if (x->header.type == GRN_VECTOR || y->header.type == GRN_VECTOR) { \
+ grn_obj inspected_x; \
+ grn_obj inspected_y; \
+ GRN_TEXT_INIT(&inspected_x, 0); \
+ GRN_TEXT_INIT(&inspected_y, 0); \
+ grn_inspect(ctx, &inspected_x, x); \
+ grn_inspect(ctx, &inspected_y, y); \
+ ERR(GRN_INVALID_ARGUMENT, \
+ "<%s> doesn't support vector: <%.*s> %s <%.*s>", \
+ operator, \
+ (int)GRN_TEXT_LEN(&inspected_x), GRN_TEXT_VALUE(&inspected_x), \
+ operator, \
+ (int)GRN_TEXT_LEN(&inspected_y), GRN_TEXT_VALUE(&inspected_y)); \
+ GRN_OBJ_FIN(ctx, &inspected_x); \
+ GRN_OBJ_FIN(ctx, &inspected_y); \
+ goto exit; \
+ } \
+ if (y != res) { \
+ res->header.domain = x->header.domain; \
+ } \
+ ARITHMETIC_OPERATION_DISPATCH(x, y, res, \
+ integer8_operation, \
+ integer16_operation, \
+ integer32_operation, \
+ integer64_operation, \
+ float_operation, \
+ left_expression_check, \
+ right_expression_check, \
+ text_operation, \
+ invalid_type_error); \
+ if (y == res) { \
+ res->header.domain = x->header.domain; \
+ } \
+} while (0)
+
+#define SIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) \
+ ((y == -1) ? -(x) : (x) / (y))
+#define UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH(x, y) ((x) / (y))
+#define FLOAT_DIVISION_OPERATION_SLASH(x, y) ((double)(x) / (double)(y))
+#define SIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((y == -1) ? 0 : (x) % (y))
+#define UNSIGNED_INTEGER_DIVISION_OPERATION_MOD(x, y) ((x) % (y))
+#define FLOAT_DIVISION_OPERATION_MOD(x, y) (fmod((x), (y)))
+
+#define DIVISION_OPERATION_DISPATCH_RIGHT(set, get, x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation) do { \
+ switch (y->header.domain) { \
+ case GRN_DB_INT8 : \
+ { \
+ int y_; \
+ y_ = GRN_INT8_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, signed_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT8 : \
+ { \
+ int y_; \
+ y_ = GRN_UINT8_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, unsigned_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_INT16 : \
+ { \
+ int y_; \
+ y_ = GRN_INT16_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, signed_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT16 : \
+ { \
+ int y_; \
+ y_ = GRN_UINT16_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, unsigned_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_INT32 : \
+ { \
+ int y_; \
+ y_ = GRN_INT32_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, signed_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT32 : \
+ { \
+ unsigned int y_; \
+ y_ = GRN_UINT32_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, unsigned_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_TIME : \
+ { \
+ long long int y_; \
+ y_ = GRN_TIME_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, signed_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_INT64 : \
+ { \
+ long long int y_; \
+ y_ = GRN_INT64_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, signed_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_UINT64 : \
+ { \
+ long long unsigned int y_; \
+ y_ = GRN_UINT64_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ set(ctx, res, unsigned_integer_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_FLOAT : \
+ { \
+ double y_; \
+ y_ = GRN_FLOAT_VALUE(y); \
+ ARITHMETIC_OPERATION_ZERO_DIVISION_CHECK(y_); \
+ res->header.domain = GRN_DB_FLOAT; \
+ GRN_FLOAT_SET(ctx, res, float_operation(x_, y_)); \
+ } \
+ break; \
+ case GRN_DB_SHORT_TEXT : \
+ case GRN_DB_TEXT : \
+ case GRN_DB_LONG_TEXT : \
+ set(ctx, res, 0); \
+ if (grn_obj_cast(ctx, y, res, GRN_FALSE)) { \
+ ERR(GRN_INVALID_ARGUMENT, \
+ "not a numerical format: <%.*s>", \
+ (int)GRN_TEXT_LEN(y), GRN_TEXT_VALUE(y)); \
+ goto exit; \
+ } \
+ /* The following "+ 0" is needed to suppress warnings that say */ \
+ /* comparison is always false due to limited range of data type */ \
+ set(ctx, res, signed_integer_operation(x_, (get(res) + 0))); \
+ break; \
+ default : \
+ break; \
+ } \
+} while (0)
+
+#define DIVISION_OPERATION_DISPATCH_LEFT(x, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation, \
+ invalid_type_error) do { \
+ switch (x->header.domain) { \
+ case GRN_DB_INT8 : \
+ { \
+ int x_; \
+ x_ = GRN_INT8_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT8_SET, \
+ GRN_INT8_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_UINT8 : \
+ { \
+ int x_; \
+ x_ = GRN_UINT8_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT8_SET, \
+ (int)GRN_UINT8_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_INT16 : \
+ { \
+ int x_; \
+ x_ = GRN_INT16_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT16_SET, \
+ GRN_INT16_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_UINT16 : \
+ { \
+ int x_; \
+ x_ = GRN_UINT16_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT16_SET, \
+ (int)GRN_UINT16_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_INT32 : \
+ { \
+ int x_; \
+ x_ = GRN_INT32_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT32_SET, \
+ GRN_INT32_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_UINT32 : \
+ { \
+ unsigned int x_; \
+ x_ = GRN_UINT32_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT32_SET, \
+ GRN_UINT32_VALUE, \
+ x_, y, res, \
+ unsigned_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_INT64 : \
+ { \
+ long long int x_; \
+ x_ = GRN_INT64_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_INT64_SET, \
+ GRN_INT64_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_TIME : \
+ { \
+ long long int x_; \
+ x_ = GRN_TIME_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_TIME_SET, \
+ GRN_TIME_VALUE, \
+ x_, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_UINT64 : \
+ { \
+ long long unsigned int x_; \
+ x_ = GRN_UINT64_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_UINT64_SET, \
+ GRN_UINT64_VALUE, \
+ x_, y, res, \
+ unsigned_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_FLOAT : \
+ { \
+ double x_; \
+ x_ = GRN_FLOAT_VALUE(x); \
+ DIVISION_OPERATION_DISPATCH_RIGHT(GRN_FLOAT_SET, \
+ GRN_FLOAT_VALUE, \
+ x_, y, res, \
+ float_operation, \
+ float_operation, \
+ float_operation); \
+ } \
+ break; \
+ case GRN_DB_SHORT_TEXT : \
+ case GRN_DB_TEXT : \
+ case GRN_DB_LONG_TEXT : \
+ invalid_type_error; \
+ break; \
+ default: \
+ break; \
+ } \
+ code++; \
+} while (0)
+
+#define DIVISION_OPERATION_DISPATCH(signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation, \
+ invalid_type_error) do { \
+ grn_obj *x, *y; \
+ \
+ POP2ALLOC1(x, y, res); \
+ if (y != res) { \
+ res->header.domain = x->header.domain; \
+ } \
+ DIVISION_OPERATION_DISPATCH_LEFT(x, y, res, \
+ signed_integer_operation, \
+ unsigned_integer_operation, \
+ float_operation, \
+ invalid_type_error); \
+ if (y == res) { \
+ res->header.domain = x->header.domain; \
+ } \
+} while (0)
+
+#define ARITHMETIC_UNARY_OPERATION_DISPATCH(integer_operation, \
+ float_operation, \
+ left_expression_check, \
+ right_expression_check, \
+ text_operation, \
+ invalid_type_error) do { \
+ grn_obj *x; \
+ POP1ALLOC1(x, res); \
+ res->header.domain = x->header.domain; \
+ switch (x->header.domain) { \
+ case GRN_DB_INT8 : \
+ { \
+ int8_t x_; \
+ x_ = GRN_INT8_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT8_SET(ctx, res, integer_operation(x_)); \
+ } \
+ break; \
+ case GRN_DB_UINT8 : \
+ { \
+ int16_t x_; \
+ x_ = GRN_UINT8_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT16_SET(ctx, res, integer_operation(x_)); \
+ res->header.domain = GRN_DB_INT16; \
+ } \
+ break; \
+ case GRN_DB_INT16 : \
+ { \
+ int16_t x_; \
+ x_ = GRN_INT16_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT16_SET(ctx, res, integer_operation(x_)); \
+ } \
+ break; \
+ case GRN_DB_UINT16 : \
+ { \
+ int x_; \
+ x_ = GRN_UINT16_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT32_SET(ctx, res, integer_operation(x_)); \
+ res->header.domain = GRN_DB_INT32; \
+ } \
+ break; \
+ case GRN_DB_INT32 : \
+ { \
+ int x_; \
+ x_ = GRN_INT32_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT32_SET(ctx, res, integer_operation(x_)); \
+ } \
+ break; \
+ case GRN_DB_UINT32 : \
+ { \
+ long long int x_; \
+ x_ = GRN_UINT32_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT64_SET(ctx, res, integer_operation(x_)); \
+ res->header.domain = GRN_DB_INT64; \
+ } \
+ break; \
+ case GRN_DB_INT64 : \
+ { \
+ long long int x_; \
+ x_ = GRN_INT64_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_INT64_SET(ctx, res, integer_operation(x_)); \
+ } \
+ break; \
+ case GRN_DB_TIME : \
+ { \
+ long long int x_; \
+ x_ = GRN_TIME_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_TIME_SET(ctx, res, integer_operation(x_)); \
+ } \
+ break; \
+ case GRN_DB_UINT64 : \
+ { \
+ long long unsigned int x_; \
+ x_ = GRN_UINT64_VALUE(x); \
+ left_expression_check(x_); \
+ if (x_ > (long long unsigned int)INT64_MAX) { \
+ ERR(GRN_INVALID_ARGUMENT, \
+ "too large UInt64 value to inverse sign: " \
+ "<%" GRN_FMT_LLU ">", \
+ x_); \
+ goto exit; \
+ } else { \
+ long long int signed_x_; \
+ signed_x_ = x_; \
+ GRN_INT64_SET(ctx, res, integer_operation(signed_x_)); \
+ res->header.domain = GRN_DB_INT64; \
+ } \
+ } \
+ break; \
+ case GRN_DB_FLOAT : \
+ { \
+ double x_; \
+ x_ = GRN_FLOAT_VALUE(x); \
+ left_expression_check(x_); \
+ GRN_FLOAT_SET(ctx, res, float_operation(x_)); \
+ } \
+ break; \
+ case GRN_DB_SHORT_TEXT : \
+ case GRN_DB_TEXT : \
+ case GRN_DB_LONG_TEXT : \
+ text_operation; \
+ break; \
+ default: \
+ invalid_type_error; \
+ break; \
+ } \
+ code++; \
+} while (0)
+
+#define EXEC_OPERATE(operate_sentence, assign_sentence) \
+ operate_sentence \
+ assign_sentence
+
+#define EXEC_OPERATE_POST(operate_sentence, assign_sentence) \
+ assign_sentence \
+ operate_sentence
+
+#define UNARY_OPERATE_AND_ASSIGN_DISPATCH(exec_operate, delta, \
+ set_flags) do { \
+ grn_obj *var, *col, value; \
+ grn_id rid; \
+ \
+ POP1ALLOC1(var, res); \
+ if (var->header.type != GRN_PTR) { \
+ ERR(GRN_INVALID_ARGUMENT, "invalid variable type: 0x%0x", \
+ var->header.type); \
+ goto exit; \
+ } \
+ if (GRN_BULK_VSIZE(var) != (sizeof(grn_obj *) + sizeof(grn_id))) { \
+ ERR(GRN_INVALID_ARGUMENT, \
+ "invalid variable size: " \
+ "expected: %" GRN_FMT_SIZE \
+ "actual: %" GRN_FMT_SIZE, \
+ (sizeof(grn_obj *) + sizeof(grn_id)), GRN_BULK_VSIZE(var)); \
+ goto exit; \
+ } \
+ col = GRN_PTR_VALUE(var); \
+ rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); \
+ res->header.type = GRN_VOID; \
+ res->header.domain = DB_OBJ(col)->range; \
+ switch (DB_OBJ(col)->range) { \
+ case GRN_DB_INT32 : \
+ GRN_INT32_INIT(&value, 0); \
+ GRN_INT32_SET(ctx, &value, delta); \
+ break; \
+ case GRN_DB_UINT32 : \
+ GRN_UINT32_INIT(&value, 0); \
+ GRN_UINT32_SET(ctx, &value, delta); \
+ break; \
+ case GRN_DB_INT64 : \
+ GRN_INT64_INIT(&value, 0); \
+ GRN_INT64_SET(ctx, &value, delta); \
+ break; \
+ case GRN_DB_UINT64 : \
+ GRN_UINT64_INIT(&value, 0); \
+ GRN_UINT64_SET(ctx, &value, delta); \
+ break; \
+ case GRN_DB_FLOAT : \
+ GRN_FLOAT_INIT(&value, 0); \
+ GRN_FLOAT_SET(ctx, &value, delta); \
+ break; \
+ case GRN_DB_TIME : \
+ GRN_TIME_INIT(&value, 0); \
+ GRN_TIME_SET(ctx, &value, GRN_TIME_PACK(delta, 0)); \
+ break; \
+ default: \
+ ERR(GRN_INVALID_ARGUMENT, \
+ "invalid increment target type: %d " \
+ "(FIXME: type name is needed)", DB_OBJ(col)->range); \
+ goto exit; \
+ break; \
+ } \
+ exec_operate(grn_obj_set_value(ctx, col, rid, &value, set_flags);, \
+ grn_obj_get_value(ctx, col, rid, res);); \
+ code++; \
+} while (0)
+
+#define ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(integer8_operation, \
+ integer16_operation, \
+ integer32_operation, \
+ integer64_operation, \
+ float_operation, \
+ left_expression_check, \
+ right_expression_check,\
+ text_operation) do { \
+ grn_obj *value, *var, *res; \
+ if (code->value) { \
+ value = code->value; \
+ POP1ALLOC1(var, res); \
+ } else { \
+ POP2ALLOC1(var, value, res); \
+ } \
+ if (var->header.type == GRN_PTR && \
+ GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) { \
+ grn_obj *col = GRN_PTR_VALUE(var); \
+ grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *)); \
+ grn_obj variable_value, casted_value; \
+ grn_id domain; \
+ \
+ value = GRN_OBJ_RESOLVE(ctx, value); \
+ \
+ domain = grn_obj_get_range(ctx, col); \
+ GRN_OBJ_INIT(&variable_value, GRN_BULK, 0, domain); \
+ grn_obj_get_value(ctx, col, rid, &variable_value); \
+ \
+ GRN_OBJ_INIT(&casted_value, GRN_BULK, 0, domain); \
+ if (grn_obj_cast(ctx, value, &casted_value, GRN_FALSE)) { \
+ ERR(GRN_INVALID_ARGUMENT, "invalid value: string"); \
+ GRN_OBJ_FIN(ctx, &variable_value); \
+ GRN_OBJ_FIN(ctx, &casted_value); \
+ POP1(res); \
+ goto exit; \
+ } \
+ grn_obj_reinit(ctx, res, domain, 0); \
+ ARITHMETIC_OPERATION_DISPATCH((&variable_value), (&casted_value), \
+ res, \
+ integer8_operation, \
+ integer16_operation, \
+ integer32_operation, \
+ integer64_operation, \
+ float_operation, \
+ left_expression_check, \
+ right_expression_check, \
+ text_operation,); \
+ grn_obj_set_value(ctx, col, rid, res, GRN_OBJ_SET); \
+ GRN_OBJ_FIN(ctx, (&variable_value)); \
+ GRN_OBJ_FIN(ctx, (&casted_value)); \
+ } else { \
+ ERR(GRN_INVALID_ARGUMENT, "left hand expression isn't column."); \
+ POP1(res); \
+ } \
+} while (0)
+
+inline static void
+grn_expr_exec_get_member_vector(grn_ctx *ctx,
+ grn_obj *expr,
+ grn_obj *column_and_record_id,
+ grn_obj *index,
+ grn_obj *result)
+{
+ grn_obj *column;
+ grn_id record_id;
+ grn_obj values;
+ int i;
+
+ column = GRN_PTR_VALUE(column_and_record_id);
+ record_id = *((grn_id *)(&(GRN_PTR_VALUE_AT(column_and_record_id, 1))));
+ GRN_TEXT_INIT(&values, 0);
+ grn_obj_get_value(ctx, column, record_id, &values);
+
+ i = GRN_UINT32_VALUE(index);
+ if (values.header.type == GRN_UVECTOR) {
+ int n_elements = 0;
+ grn_obj *range;
+ grn_id range_id = DB_OBJ(column)->range;
+
+ grn_obj_reinit(ctx, result, range_id, 0);
+ range = grn_ctx_at(ctx, range_id);
+ if (range) {
+ switch (range->header.type) {
+ case GRN_TYPE :
+ n_elements = GRN_BULK_VSIZE(&values) / grn_type_size(ctx, range);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ n_elements = GRN_BULK_VSIZE(&values) / sizeof(grn_id);
+ break;
+ }
+ }
+ if (n_elements > i) {
+#define GET_UVECTOR_ELEMENT_AS(type) do { \
+ GRN_ ## type ## _SET(ctx, \
+ result, \
+ GRN_ ## type ## _VALUE_AT(&values, i)); \
+ } while (GRN_FALSE)
+ switch (values.header.domain) {
+ case GRN_DB_BOOL :
+ GET_UVECTOR_ELEMENT_AS(BOOL);
+ break;
+ case GRN_DB_INT8 :
+ GET_UVECTOR_ELEMENT_AS(INT8);
+ break;
+ case GRN_DB_UINT8 :
+ GET_UVECTOR_ELEMENT_AS(UINT8);
+ break;
+ case GRN_DB_INT16 :
+ GET_UVECTOR_ELEMENT_AS(INT16);
+ break;
+ case GRN_DB_UINT16 :
+ GET_UVECTOR_ELEMENT_AS(UINT16);
+ break;
+ case GRN_DB_INT32 :
+ GET_UVECTOR_ELEMENT_AS(INT32);
+ break;
+ case GRN_DB_UINT32 :
+ GET_UVECTOR_ELEMENT_AS(UINT32);
+ break;
+ case GRN_DB_INT64 :
+ GET_UVECTOR_ELEMENT_AS(INT64);
+ break;
+ case GRN_DB_UINT64 :
+ GET_UVECTOR_ELEMENT_AS(UINT64);
+ break;
+ case GRN_DB_FLOAT :
+ GET_UVECTOR_ELEMENT_AS(FLOAT);
+ break;
+ case GRN_DB_TIME :
+ GET_UVECTOR_ELEMENT_AS(TIME);
+ break;
+ default :
+ GET_UVECTOR_ELEMENT_AS(RECORD);
+ break;
+ }
+#undef GET_UVECTOR_ELEMENT_AS
+ }
+ } else {
+ if (values.u.v.n_sections > i) {
+ const char *content;
+ unsigned int content_length;
+ grn_id domain;
+
+ content_length = grn_vector_get_element(ctx, &values, i,
+ &content, NULL, &domain);
+ grn_obj_reinit(ctx, result, domain, 0);
+ grn_bulk_write(ctx, result, content, content_length);
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &values);
+}
+
+inline static void
+grn_expr_exec_get_member_table(grn_ctx *ctx,
+ grn_obj *expr,
+ grn_obj *table,
+ grn_obj *key,
+ grn_obj *result)
+{
+ grn_id id;
+
+ if (table->header.domain == key->header.domain) {
+ id = grn_table_get(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key));
+ } else {
+ grn_obj casted_key;
+ GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain);
+ if (grn_obj_cast(ctx, key, &casted_key, GRN_FALSE) == GRN_SUCCESS) {
+ id = grn_table_get(ctx, table,
+ GRN_BULK_HEAD(&casted_key),
+ GRN_BULK_VSIZE(&casted_key));
+ } else {
+ id = GRN_ID_NIL;
+ }
+ GRN_OBJ_FIN(ctx, &casted_key);
+ }
+
+ grn_obj_reinit(ctx, result, DB_OBJ(table)->id, 0);
+ GRN_RECORD_SET(ctx, result, id);
+}
+
+static inline grn_bool
+grn_expr_exec_is_simple_expr(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+
+ if (expr->header.type != GRN_EXPR) {
+ return GRN_FALSE;
+ }
+
+ if (e->codes_curr != 1) {
+ return GRN_FALSE;
+ }
+
+ switch (e->codes[0].op) {
+ case GRN_OP_PUSH :
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+}
+
+static inline grn_obj *
+grn_expr_exec_simple(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+
+ return e->codes[0].value;
+}
+
+grn_obj *
+grn_expr_exec(grn_ctx *ctx, grn_obj *expr, int nargs)
+{
+ grn_obj *val = NULL;
+ uint32_t stack_curr = ctx->impl->stack_curr;
+ GRN_API_ENTER;
+ if (grn_expr_exec_is_simple_expr(ctx, expr)) {
+ val = grn_expr_exec_simple(ctx, expr);
+ GRN_API_RETURN(val);
+ }
+ if (expr->header.type == GRN_PROC) {
+ grn_proc *proc = (grn_proc *)expr;
+ if (proc->type == GRN_PROC_COMMAND) {
+ grn_command_input *input;
+ input = grn_command_input_open(ctx, expr);
+ grn_command_run(ctx, expr, input);
+ grn_command_input_close(ctx, input);
+ GRN_API_RETURN(NULL);
+ } else {
+ grn_proc_call(ctx, expr, nargs, expr);
+ }
+ } else {
+ grn_expr *e = (grn_expr *)expr;
+ register grn_obj **s_ = ctx->impl->stack;
+ register grn_obj *s0 = NULL;
+ register grn_obj *s1 = NULL;
+ register grn_obj **sp;
+ register grn_obj *vp = e->values;
+ grn_obj *res = NULL, *v0 = grn_expr_get_var_by_offset(ctx, expr, 0);
+ grn_expr_code *code = e->codes, *ce = &e->codes[e->codes_curr];
+ sp = s_ + stack_curr;
+ while (code < ce) {
+ switch (code->op) {
+ case GRN_OP_NOP :
+ code++;
+ break;
+ case GRN_OP_PUSH :
+ PUSH1(code->value);
+ code++;
+ break;
+ case GRN_OP_POP :
+ {
+ grn_obj *obj;
+ POP1(obj);
+ code++;
+ }
+ break;
+ case GRN_OP_GET_REF :
+ {
+ grn_obj *col, *rec;
+ if (code->nargs == 1) {
+ rec = v0;
+ if (code->value) {
+ col = code->value;
+ ALLOC1(res);
+ } else {
+ POP1ALLOC1(col, res);
+ }
+ } else {
+ if (code->value) {
+ col = code->value;
+ POP1ALLOC1(rec, res);
+ } else {
+ POP2ALLOC1(rec, col, res);
+ }
+ }
+ if (col->header.type == GRN_BULK) {
+ grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec));
+ col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col));
+ if (col) { grn_expr_take_obj(ctx, (grn_obj *)e, col); }
+ }
+ if (col) {
+ res->header.type = GRN_PTR;
+ res->header.domain = GRN_ID_NIL;
+ GRN_PTR_SET(ctx, res, col);
+ GRN_UINT32_PUT(ctx, res, GRN_RECORD_VALUE(rec));
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "col resolve failed");
+ goto exit;
+ }
+ code++;
+ }
+ break;
+ case GRN_OP_CALL :
+ {
+ grn_obj *proc;
+ if (code->value) {
+ if (sp < s_ + code->nargs - 1) {
+ ERR(GRN_INVALID_ARGUMENT, "stack error");
+ goto exit;
+ }
+ proc = code->value;
+ WITH_SPSAVE({
+ grn_proc_call(ctx, proc, code->nargs - 1, expr);
+ });
+ } else {
+ int offset = code->nargs;
+ if (sp < s_ + offset) {
+ ERR(GRN_INVALID_ARGUMENT, "stack error");
+ goto exit;
+ }
+ proc = sp[-offset];
+ if (grn_obj_is_window_function_proc(ctx, proc)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, proc);
+ ERR(GRN_INVALID_ARGUMENT,
+ "window function can't be executed for each record: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ goto exit;
+ } else {
+ WITH_SPSAVE({
+ grn_proc_call(ctx, proc, code->nargs - 1, expr);
+ });
+ }
+ if (ctx->rc) {
+ goto exit;
+ }
+ POP1(res);
+ {
+ grn_obj *proc_;
+ POP1(proc_);
+ if (proc != proc_) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "stack may be corrupt");
+ }
+ }
+ PUSH1(res);
+ }
+ }
+ code++;
+ break;
+ case GRN_OP_INTERN :
+ {
+ grn_obj *obj;
+ POP1(obj);
+ obj = GRN_OBJ_RESOLVE(ctx, obj);
+ res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj));
+ if (!res) { res = grn_ctx_get(ctx, GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj)); }
+ if (!res) {
+ ERR(GRN_INVALID_ARGUMENT, "intern failed");
+ goto exit;
+ }
+ PUSH1(res);
+ }
+ code++;
+ break;
+ case GRN_OP_TABLE_CREATE :
+ {
+ grn_obj *value_type, *key_type, *flags, *name;
+ POP1(value_type);
+ value_type = GRN_OBJ_RESOLVE(ctx, value_type);
+ POP1(key_type);
+ key_type = GRN_OBJ_RESOLVE(ctx, key_type);
+ POP1(flags);
+ flags = GRN_OBJ_RESOLVE(ctx, flags);
+ POP1(name);
+ name = GRN_OBJ_RESOLVE(ctx, name);
+ res = grn_table_create(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name),
+ NULL, GRN_UINT32_VALUE(flags),
+ key_type, value_type);
+ PUSH1(res);
+ }
+ code++;
+ break;
+ case GRN_OP_EXPR_GET_VAR :
+ {
+ grn_obj *name, *expr;
+ POP1(name);
+ name = GRN_OBJ_RESOLVE(ctx, name);
+ POP1(expr);
+ expr = GRN_OBJ_RESOLVE(ctx, expr);
+ switch (name->header.domain) {
+ case GRN_DB_INT32 :
+ res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT32_VALUE(name));
+ break;
+ case GRN_DB_UINT32 :
+ res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT32_VALUE(name));
+ break;
+ case GRN_DB_INT64 :
+ res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_INT64_VALUE(name));
+ break;
+ case GRN_DB_UINT64 :
+ res = grn_expr_get_var_by_offset(ctx, expr, (unsigned int) GRN_UINT64_VALUE(name));
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ res = grn_expr_get_var(ctx, expr, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name));
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "invalid type");
+ goto exit;
+ }
+ PUSH1(res);
+ }
+ code++;
+ break;
+ case GRN_OP_ASSIGN :
+ {
+ grn_obj *value, *var;
+ if (code->value) {
+ value = code->value;
+ } else {
+ POP1(value);
+ }
+ value = GRN_OBJ_RESOLVE(ctx, value);
+ POP1(var);
+ // var = GRN_OBJ_RESOLVE(ctx, var);
+ if (var->header.type == GRN_PTR &&
+ GRN_BULK_VSIZE(var) == (sizeof(grn_obj *) + sizeof(grn_id))) {
+ grn_obj *col = GRN_PTR_VALUE(var);
+ grn_id rid = *(grn_id *)(GRN_BULK_HEAD(var) + sizeof(grn_obj *));
+ grn_obj_set_value(ctx, col, rid, value, GRN_OBJ_SET);
+ } else {
+ VAR_SET_VALUE(ctx, var, value);
+ }
+ PUSH1(value);
+ }
+ code++;
+ break;
+ case GRN_OP_STAR_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ FLOAT_ARITHMETIC_OPERATION_STAR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable *= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_SLASH_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_SLASH,
+ INTEGER_ARITHMETIC_OPERATION_SLASH,
+ INTEGER_ARITHMETIC_OPERATION_SLASH,
+ INTEGER_ARITHMETIC_OPERATION_SLASH,
+ FLOAT_ARITHMETIC_OPERATION_SLASH,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable /= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_MOD_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_MOD,
+ INTEGER_ARITHMETIC_OPERATION_MOD,
+ INTEGER_ARITHMETIC_OPERATION_MOD,
+ INTEGER_ARITHMETIC_OPERATION_MOD,
+ FLOAT_ARITHMETIC_OPERATION_MOD,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable %%= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_PLUS_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ FLOAT_ARITHMETIC_OPERATION_PLUS,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable += \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_MINUS_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ FLOAT_ARITHMETIC_OPERATION_MINUS,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable -= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_SHIFTL_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ FLOAT_ARITHMETIC_OPERATION_SHIFTL,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable <<= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_SHIFTR_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ FLOAT_ARITHMETIC_OPERATION_SHIFTR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable >>= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_SHIFTRR_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER8_ARITHMETIC_OPERATION_SHIFTRR,
+ INTEGER16_ARITHMETIC_OPERATION_SHIFTRR,
+ INTEGER32_ARITHMETIC_OPERATION_SHIFTRR,
+ INTEGER64_ARITHMETIC_OPERATION_SHIFTRR,
+ FLOAT_ARITHMETIC_OPERATION_SHIFTRR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT,
+ "variable >>>= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_AND_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ FLOAT_ARITHMETIC_OPERATION_BITWISE_AND,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable &= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_OR_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ FLOAT_ARITHMETIC_OPERATION_BITWISE_OR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable |= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_XOR_ASSIGN :
+ ARITHMETIC_OPERATION_AND_ASSIGN_DISPATCH(
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT, "variable ^= \"string\" isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_JUMP :
+ code += code->nargs + 1;
+ break;
+ case GRN_OP_CJUMP :
+ {
+ grn_obj *v;
+ POP1(v);
+ if (!grn_obj_is_true(ctx, v)) {
+ code += code->nargs;
+ }
+ }
+ code++;
+ break;
+ case GRN_OP_GET_VALUE :
+ {
+ grn_obj *col, *rec;
+ do {
+ if (code->nargs == 1) {
+ rec = v0;
+ if (code->value) {
+ col = code->value;
+ ALLOC1(res);
+ } else {
+ POP1ALLOC1(col, res);
+ }
+ } else {
+ if (code->value) {
+ col = code->value;
+ POP1ALLOC1(rec, res);
+ } else {
+ POP2ALLOC1(rec, col, res);
+ }
+ }
+ if (col->header.type == GRN_BULK) {
+ grn_obj *table = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(rec));
+ col = grn_obj_column(ctx, table, GRN_BULK_HEAD(col), GRN_BULK_VSIZE(col));
+ if (col) { grn_expr_take_obj(ctx, (grn_obj *)expr, col); }
+ }
+ if (!col) {
+ ERR(GRN_INVALID_ARGUMENT, "col resolve failed");
+ goto exit;
+ }
+ grn_obj_reinit_for(ctx, res, col);
+ grn_obj_get_value(ctx, col, GRN_RECORD_VALUE(rec), res);
+ code++;
+ } while (code < ce && code->op == GRN_OP_GET_VALUE);
+ }
+ break;
+ case GRN_OP_OBJ_SEARCH :
+ {
+ grn_obj *op, *query, *index;
+ // todo : grn_search_optarg optarg;
+ POP1(op);
+ op = GRN_OBJ_RESOLVE(ctx, op);
+ POP1(res);
+ res = GRN_OBJ_RESOLVE(ctx, res);
+ POP1(query);
+ query = GRN_OBJ_RESOLVE(ctx, query);
+ POP1(index);
+ index = GRN_OBJ_RESOLVE(ctx, index);
+ grn_obj_search(ctx, index, query, res,
+ (grn_operator)GRN_UINT32_VALUE(op), NULL);
+ }
+ code++;
+ break;
+ case GRN_OP_TABLE_SELECT :
+ {
+ grn_obj *op, *res, *expr, *table;
+ POP1(op);
+ op = GRN_OBJ_RESOLVE(ctx, op);
+ POP1(res);
+ res = GRN_OBJ_RESOLVE(ctx, res);
+ POP1(expr);
+ expr = GRN_OBJ_RESOLVE(ctx, expr);
+ POP1(table);
+ table = GRN_OBJ_RESOLVE(ctx, table);
+ WITH_SPSAVE({
+ grn_table_select(ctx, table, expr, res, (grn_operator)GRN_UINT32_VALUE(op));
+ });
+ PUSH1(res);
+ }
+ code++;
+ break;
+ case GRN_OP_TABLE_SORT :
+ {
+ grn_obj *keys_, *res, *limit, *table;
+ POP1(keys_);
+ keys_ = GRN_OBJ_RESOLVE(ctx, keys_);
+ POP1(res);
+ res = GRN_OBJ_RESOLVE(ctx, res);
+ POP1(limit);
+ limit = GRN_OBJ_RESOLVE(ctx, limit);
+ POP1(table);
+ table = GRN_OBJ_RESOLVE(ctx, table);
+ {
+ grn_table_sort_key *keys;
+ const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256];
+ int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL);
+ if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
+ int i, n_keys = 0;
+ for (i = 0; i < n; i++) {
+ uint32_t len = (uint32_t) (tokbuf[i] - p);
+ grn_obj *col = grn_obj_column(ctx, table, p, len);
+ if (col) {
+ keys[n_keys].key = col;
+ keys[n_keys].flags = GRN_TABLE_SORT_ASC;
+ keys[n_keys].offset = 0;
+ n_keys++;
+ } else {
+ if (p[0] == ':' && p[1] == 'd' && len == 2 && n_keys) {
+ keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC;
+ }
+ }
+ p = tokbuf[i] + 1;
+ }
+ WITH_SPSAVE({
+ grn_table_sort(ctx, table, 0, GRN_INT32_VALUE(limit), res, keys, n_keys);
+ });
+ for (i = 0; i < n_keys; i++) {
+ grn_obj_unlink(ctx, keys[i].key);
+ }
+ GRN_FREE(keys);
+ }
+ }
+ }
+ code++;
+ break;
+ case GRN_OP_TABLE_GROUP :
+ {
+ grn_obj *res, *keys_, *table;
+ POP1(res);
+ res = GRN_OBJ_RESOLVE(ctx, res);
+ POP1(keys_);
+ keys_ = GRN_OBJ_RESOLVE(ctx, keys_);
+ POP1(table);
+ table = GRN_OBJ_RESOLVE(ctx, table);
+ {
+ grn_table_sort_key *keys;
+ grn_table_group_result results;
+ const char *p = GRN_BULK_HEAD(keys_), *tokbuf[256];
+ int n = grn_str_tok(p, GRN_BULK_VSIZE(keys_), ' ', tokbuf, 256, NULL);
+ if ((keys = GRN_MALLOCN(grn_table_sort_key, n))) {
+ int i, n_keys = 0;
+ for (i = 0; i < n; i++) {
+ uint32_t len = (uint32_t) (tokbuf[i] - p);
+ grn_obj *col = grn_obj_column(ctx, table, p, len);
+ if (col) {
+ keys[n_keys].key = col;
+ keys[n_keys].flags = GRN_TABLE_SORT_ASC;
+ keys[n_keys].offset = 0;
+ n_keys++;
+ } else if (n_keys) {
+ if (p[0] == ':' && p[1] == 'd' && len == 2) {
+ keys[n_keys - 1].flags |= GRN_TABLE_SORT_DESC;
+ } else {
+ keys[n_keys - 1].offset = grn_atoi(p, p + len, NULL);
+ }
+ }
+ p = tokbuf[i] + 1;
+ }
+ /* todo : support multi-results */
+ results.table = res;
+ results.key_begin = 0;
+ results.key_end = 0;
+ results.limit = 0;
+ results.flags = 0;
+ results.op = GRN_OP_OR;
+ WITH_SPSAVE({
+ grn_table_group(ctx, table, keys, n_keys, &results, 1);
+ });
+ for (i = 0; i < n_keys; i++) {
+ grn_obj_unlink(ctx, keys[i].key);
+ }
+ GRN_FREE(keys);
+ }
+ }
+ }
+ code++;
+ break;
+ case GRN_OP_JSON_PUT :
+ {
+ grn_obj_format format;
+ grn_obj *str, *table, *res;
+ POP1(res);
+ res = GRN_OBJ_RESOLVE(ctx, res);
+ POP1(str);
+ str = GRN_OBJ_RESOLVE(ctx, str);
+ POP1(table);
+ table = GRN_OBJ_RESOLVE(ctx, table);
+ GRN_OBJ_FORMAT_INIT(&format, grn_table_size(ctx, table), 0, -1, 0);
+ format.flags = 0;
+ grn_obj_columns(ctx, table,
+ GRN_TEXT_VALUE(str), GRN_TEXT_LEN(str), &format.columns);
+ grn_text_otoj(ctx, res, table, &format);
+ GRN_OBJ_FORMAT_FIN(ctx, &format);
+ }
+ code++;
+ break;
+ case GRN_OP_AND :
+ {
+ grn_obj *x, *y;
+ grn_obj *result = NULL;
+ POP2ALLOC1(x, y, res);
+ if (grn_obj_is_true(ctx, x)) {
+ if (grn_obj_is_true(ctx, y)) {
+ result = y;
+ }
+ }
+ if (result) {
+ if (res != result) {
+ grn_obj_reinit(ctx, res, result->header.domain, 0);
+ grn_obj_cast(ctx, result, res, GRN_FALSE);
+ }
+ } else {
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, GRN_FALSE);
+ }
+ }
+ code++;
+ break;
+ case GRN_OP_OR :
+ {
+ grn_obj *x, *y;
+ grn_obj *result;
+ POP2ALLOC1(x, y, res);
+ if (grn_obj_is_true(ctx, x)) {
+ result = x;
+ } else {
+ if (grn_obj_is_true(ctx, y)) {
+ result = y;
+ } else {
+ result = NULL;
+ }
+ }
+ if (result) {
+ if (res != result) {
+ grn_obj_reinit(ctx, res, result->header.domain, 0);
+ grn_obj_cast(ctx, result, res, GRN_FALSE);
+ }
+ } else {
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, GRN_FALSE);
+ }
+ }
+ code++;
+ break;
+ case GRN_OP_AND_NOT :
+ {
+ grn_obj *x, *y;
+ grn_bool is_true;
+ POP2ALLOC1(x, y, res);
+ if (!grn_obj_is_true(ctx, x) || grn_obj_is_true(ctx, y)) {
+ is_true = GRN_FALSE;
+ } else {
+ is_true = GRN_TRUE;
+ }
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, is_true);
+ }
+ code++;
+ break;
+ case GRN_OP_ADJUST :
+ {
+ /* todo */
+ }
+ code++;
+ break;
+ case GRN_OP_MATCH :
+ {
+ grn_obj *x, *y;
+ grn_bool matched;
+ POP1(y);
+ POP1(x);
+ WITH_SPSAVE({
+ matched = grn_operator_exec_match(ctx, x, y);
+ });
+ ALLOC1(res);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, matched);
+ }
+ code++;
+ break;
+ case GRN_OP_EQUAL :
+ {
+ grn_bool is_equal;
+ grn_obj *x, *y;
+ POP2ALLOC1(x, y, res);
+ is_equal = grn_operator_exec_equal(ctx, x, y);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, is_equal);
+ }
+ code++;
+ break;
+ case GRN_OP_NOT_EQUAL :
+ {
+ grn_bool is_not_equal;
+ grn_obj *x, *y;
+ POP2ALLOC1(x, y, res);
+ is_not_equal = grn_operator_exec_not_equal(ctx, x, y);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, is_not_equal);
+ }
+ code++;
+ break;
+ case GRN_OP_PREFIX :
+ {
+ grn_obj *x, *y;
+ grn_bool matched;
+ POP1(y);
+ POP1(x);
+ WITH_SPSAVE({
+ matched = grn_operator_exec_prefix(ctx, x, y);
+ });
+ ALLOC1(res);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, matched);
+ }
+ code++;
+ break;
+ case GRN_OP_SUFFIX :
+ {
+ grn_obj *x, *y;
+ grn_bool matched = GRN_FALSE;
+ POP2ALLOC1(x, y, res);
+ if (GRN_TEXT_LEN(x) >= GRN_TEXT_LEN(y) &&
+ !memcmp(GRN_TEXT_VALUE(x) + GRN_TEXT_LEN(x) - GRN_TEXT_LEN(y),
+ GRN_TEXT_VALUE(y), GRN_TEXT_LEN(y))) {
+ matched = GRN_TRUE;
+ }
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, matched);
+ }
+ code++;
+ break;
+ case GRN_OP_LESS :
+ {
+ grn_bool r;
+ grn_obj *x, *y;
+ POP2ALLOC1(x, y, res);
+ r = grn_operator_exec_less(ctx, x, y);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, r);
+ }
+ code++;
+ break;
+ case GRN_OP_GREATER :
+ {
+ grn_bool r;
+ grn_obj *x, *y;
+ POP2ALLOC1(x, y, res);
+ r = grn_operator_exec_greater(ctx, x, y);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, r);
+ }
+ code++;
+ break;
+ case GRN_OP_LESS_EQUAL :
+ {
+ grn_bool r;
+ grn_obj *x, *y;
+ POP2ALLOC1(x, y, res);
+ r = grn_operator_exec_less_equal(ctx, x, y);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, r);
+ }
+ code++;
+ break;
+ case GRN_OP_GREATER_EQUAL :
+ {
+ grn_bool r;
+ grn_obj *x, *y;
+ POP2ALLOC1(x, y, res);
+ r = grn_operator_exec_greater_equal(ctx, x, y);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, r);
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_DISTANCE1 :
+ {
+ grn_obj *value;
+ double lng1, lat1, lng2, lat2, x, y, d;
+ POP1(value);
+ lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1ALLOC1(value, res);
+ lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
+ y = (lat2 - lat1);
+ d = sqrt((x * x) + (y * y)) * GEO_RADIOUS;
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_FLOAT;
+ GRN_FLOAT_SET(ctx, res, d);
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_DISTANCE2 :
+ {
+ grn_obj *value;
+ double lng1, lat1, lng2, lat2, x, y, d;
+ POP1(value);
+ lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1ALLOC1(value, res);
+ lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ x = sin(fabs(lng2 - lng1) * 0.5);
+ y = sin(fabs(lat2 - lat1) * 0.5);
+ d = asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GEO_RADIOUS;
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_FLOAT;
+ GRN_FLOAT_SET(ctx, res, d);
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_DISTANCE3 :
+ {
+ grn_obj *value;
+ double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d;
+ POP1(value);
+ lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1ALLOC1(value, res);
+ lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ p = (lat1 + lat2) * 0.5;
+ q = (1 - GEO_BES_C3 * sin(p) * sin(p));
+ m = GEO_BES_C1 / sqrt(q * q * q);
+ n = GEO_BES_C2 / sqrt(q);
+ x = n * cos(p) * fabs(lng1 - lng2);
+ y = m * fabs(lat1 - lat2);
+ d = sqrt((x * x) + (y * y));
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_FLOAT;
+ GRN_FLOAT_SET(ctx, res, d);
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_DISTANCE4 :
+ {
+ grn_obj *value;
+ double lng1, lat1, lng2, lat2, p, q, m, n, x, y, d;
+ POP1(value);
+ lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1ALLOC1(value, res);
+ lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ p = (lat1 + lat2) * 0.5;
+ q = (1 - GEO_GRS_C3 * sin(p) * sin(p));
+ m = GEO_GRS_C1 / sqrt(q * q * q);
+ n = GEO_GRS_C2 / sqrt(q);
+ x = n * cos(p) * fabs(lng1 - lng2);
+ y = m * fabs(lat1 - lat2);
+ d = sqrt((x * x) + (y * y));
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_FLOAT;
+ GRN_FLOAT_SET(ctx, res, d);
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_WITHINP5 :
+ {
+ int r;
+ grn_obj *value;
+ double lng0, lat0, lng1, lat1, x, y, d;
+ POP1(value);
+ lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1ALLOC1(value, res);
+ x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5);
+ y = (lat1 - lat0);
+ d = sqrt((x * x) + (y * y)) * GEO_RADIOUS;
+ switch (value->header.domain) {
+ case GRN_DB_INT32 :
+ r = d <= GRN_INT32_VALUE(value);
+ break;
+ case GRN_DB_FLOAT :
+ r = d <= GRN_FLOAT_VALUE(value);
+ break;
+ default :
+ r = 0;
+ break;
+ }
+ GRN_INT32_SET(ctx, res, r);
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_INT32;
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_WITHINP6 :
+ {
+ int r;
+ grn_obj *value;
+ double lng0, lat0, lng1, lat1, lng2, lat2, x, y, d;
+ POP1(value);
+ lng0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat0 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lat1 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1(value);
+ lng2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ POP1ALLOC1(value, res);
+ lat2 = GEO_INT2RAD(GRN_INT32_VALUE(value));
+ x = (lng1 - lng0) * cos((lat0 + lat1) * 0.5);
+ y = (lat1 - lat0);
+ d = (x * x) + (y * y);
+ x = (lng2 - lng1) * cos((lat1 + lat2) * 0.5);
+ y = (lat2 - lat1);
+ r = d <= (x * x) + (y * y);
+ GRN_INT32_SET(ctx, res, r);
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_INT32;
+ }
+ code++;
+ break;
+ case GRN_OP_GEO_WITHINP8 :
+ {
+ int r;
+ grn_obj *value;
+ int64_t ln0, la0, ln1, la1, ln2, la2, ln3, la3;
+ POP1(value);
+ ln0 = GRN_INT32_VALUE(value);
+ POP1(value);
+ la0 = GRN_INT32_VALUE(value);
+ POP1(value);
+ ln1 = GRN_INT32_VALUE(value);
+ POP1(value);
+ la1 = GRN_INT32_VALUE(value);
+ POP1(value);
+ ln2 = GRN_INT32_VALUE(value);
+ POP1(value);
+ la2 = GRN_INT32_VALUE(value);
+ POP1(value);
+ ln3 = GRN_INT32_VALUE(value);
+ POP1ALLOC1(value, res);
+ la3 = GRN_INT32_VALUE(value);
+ r = ((ln2 <= ln0) && (ln0 <= ln3) && (la2 <= la0) && (la0 <= la3));
+ GRN_INT32_SET(ctx, res, r);
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_INT32;
+ }
+ code++;
+ break;
+ case GRN_OP_PLUS :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "+",
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ INTEGER_ARITHMETIC_OPERATION_PLUS,
+ FLOAT_ARITHMETIC_OPERATION_PLUS,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ if (x == res) {
+ grn_obj_cast(ctx, y, res, GRN_FALSE);
+ } else if (y == res) {
+ grn_obj buffer;
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_obj_cast(ctx, x, &buffer, GRN_FALSE);
+ grn_obj_cast(ctx, y, &buffer, GRN_FALSE);
+ GRN_BULK_REWIND(res);
+ grn_obj_cast(ctx, &buffer, res, GRN_FALSE);
+ GRN_OBJ_FIN(ctx, &buffer);
+ } else {
+ GRN_BULK_REWIND(res);
+ grn_obj_cast(ctx, x, res, GRN_FALSE);
+ grn_obj_cast(ctx, y, res, GRN_FALSE);
+ }
+ }
+ ,);
+ break;
+ case GRN_OP_MINUS :
+ if (code->nargs == 1) {
+ ARITHMETIC_UNARY_OPERATION_DISPATCH(
+ INTEGER_UNARY_ARITHMETIC_OPERATION_MINUS,
+ FLOAT_UNARY_ARITHMETIC_OPERATION_MINUS,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ long long int x_;
+
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_INT64;
+
+ GRN_INT64_SET(ctx, res, 0);
+ grn_obj_cast(ctx, x, res, GRN_FALSE);
+ x_ = GRN_INT64_VALUE(res);
+
+ GRN_INT64_SET(ctx, res, -x_);
+ }
+ ,);
+ } else {
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "-",
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ INTEGER_ARITHMETIC_OPERATION_MINUS,
+ FLOAT_ARITHMETIC_OPERATION_MINUS,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT,
+ "\"string\" - \"string\" "
+ "isn't supported");
+ goto exit;
+ }
+ ,);
+ }
+ break;
+ case GRN_OP_STAR :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "*",
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ INTEGER_ARITHMETIC_OPERATION_STAR,
+ FLOAT_ARITHMETIC_OPERATION_STAR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ ERR(GRN_INVALID_ARGUMENT,
+ "\"string\" * \"string\" "
+ "isn't supported");
+ goto exit;
+ }
+ ,);
+ break;
+ case GRN_OP_SLASH :
+ DIVISION_OPERATION_DISPATCH(
+ SIGNED_INTEGER_DIVISION_OPERATION_SLASH,
+ UNSIGNED_INTEGER_DIVISION_OPERATION_SLASH,
+ FLOAT_DIVISION_OPERATION_SLASH,
+ {
+ ERR(GRN_INVALID_ARGUMENT,
+ "\"string\" / \"string\" "
+ "isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_MOD :
+ DIVISION_OPERATION_DISPATCH(
+ SIGNED_INTEGER_DIVISION_OPERATION_MOD,
+ UNSIGNED_INTEGER_DIVISION_OPERATION_MOD,
+ FLOAT_DIVISION_OPERATION_MOD,
+ {
+ ERR(GRN_INVALID_ARGUMENT,
+ "\"string\" %% \"string\" "
+ "isn't supported");
+ goto exit;
+ });
+ break;
+ case GRN_OP_BITWISE_NOT :
+ ARITHMETIC_UNARY_OPERATION_DISPATCH(
+ INTEGER_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT,
+ FLOAT_UNARY_ARITHMETIC_OPERATION_BITWISE_NOT,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ TEXT_UNARY_ARITHMETIC_OPERATION(~),);
+ break;
+ case GRN_OP_BITWISE_OR :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "|",
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_OR,
+ FLOAT_ARITHMETIC_OPERATION_BITWISE_OR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ TEXT_ARITHMETIC_OPERATION(|),);
+ break;
+ case GRN_OP_BITWISE_XOR :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "^",
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_XOR,
+ FLOAT_ARITHMETIC_OPERATION_BITWISE_XOR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ TEXT_ARITHMETIC_OPERATION(^),);
+ break;
+ case GRN_OP_BITWISE_AND :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "&",
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ INTEGER_ARITHMETIC_OPERATION_BITWISE_AND,
+ FLOAT_ARITHMETIC_OPERATION_BITWISE_AND,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ TEXT_ARITHMETIC_OPERATION(&),);
+ break;
+ case GRN_OP_SHIFTL :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ "<<",
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTL,
+ FLOAT_ARITHMETIC_OPERATION_SHIFTL,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ TEXT_ARITHMETIC_OPERATION(<<),);
+ break;
+ case GRN_OP_SHIFTR :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ ">>",
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ INTEGER_ARITHMETIC_OPERATION_SHIFTR,
+ FLOAT_ARITHMETIC_OPERATION_SHIFTR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ TEXT_ARITHMETIC_OPERATION(>>),);
+ break;
+ case GRN_OP_SHIFTRR :
+ ARITHMETIC_BINARY_OPERATION_DISPATCH(
+ ">>>",
+ INTEGER8_ARITHMETIC_OPERATION_SHIFTRR,
+ INTEGER16_ARITHMETIC_OPERATION_SHIFTRR,
+ INTEGER32_ARITHMETIC_OPERATION_SHIFTRR,
+ INTEGER64_ARITHMETIC_OPERATION_SHIFTRR,
+ FLOAT_ARITHMETIC_OPERATION_SHIFTRR,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ ARITHMETIC_OPERATION_NO_CHECK,
+ {
+ long long unsigned int x_;
+ long long unsigned int y_;
+
+ res->header.type = GRN_BULK;
+ res->header.domain = GRN_DB_INT64;
+
+ GRN_INT64_SET(ctx, res, 0);
+ grn_obj_cast(ctx, x, res, GRN_FALSE);
+ x_ = GRN_INT64_VALUE(res);
+
+ GRN_INT64_SET(ctx, res, 0);
+ grn_obj_cast(ctx, y, res, GRN_FALSE);
+ y_ = GRN_INT64_VALUE(res);
+
+ GRN_INT64_SET(ctx, res, x_ >> y_);
+ }
+ ,);
+ break;
+ case GRN_OP_INCR :
+ UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_INCR);
+ break;
+ case GRN_OP_DECR :
+ UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE, 1, GRN_OBJ_DECR);
+ break;
+ case GRN_OP_INCR_POST :
+ UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_INCR);
+ break;
+ case GRN_OP_DECR_POST :
+ UNARY_OPERATE_AND_ASSIGN_DISPATCH(EXEC_OPERATE_POST, 1, GRN_OBJ_DECR);
+ break;
+ case GRN_OP_NOT :
+ {
+ grn_obj *value;
+ grn_bool value_boolean;
+ POP1ALLOC1(value, res);
+ GRN_OBJ_IS_TRUE(ctx, value, value_boolean);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, !value_boolean);
+ }
+ code++;
+ break;
+ case GRN_OP_GET_MEMBER :
+ {
+ grn_obj *receiver, *index_or_key;
+ POP2ALLOC1(receiver, index_or_key, res);
+ if (receiver->header.type == GRN_PTR) {
+ grn_obj *index = index_or_key;
+ grn_expr_exec_get_member_vector(ctx, expr, receiver, index, res);
+ } else {
+ grn_obj *key = index_or_key;
+ grn_expr_exec_get_member_table(ctx, expr, receiver, key, res);
+ }
+ code++;
+ }
+ break;
+ case GRN_OP_REGEXP :
+ {
+ grn_obj *target, *pattern;
+ grn_bool matched;
+ POP1(pattern);
+ POP1(target);
+ WITH_SPSAVE({
+ matched = grn_operator_exec_regexp(ctx, target, pattern);
+ });
+ ALLOC1(res);
+ grn_obj_reinit(ctx, res, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, res, matched);
+ }
+ code++;
+ break;
+ default :
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "not implemented operator assigned");
+ goto exit;
+ break;
+ }
+ }
+ ctx->impl->stack_curr = sp - s_;
+ }
+ if (ctx->impl->stack_curr + nargs > stack_curr) {
+ val = grn_ctx_pop(ctx);
+ }
+exit :
+ if (ctx->impl->stack_curr + nargs > stack_curr) {
+ /*
+ GRN_LOG(ctx, GRN_LOG_WARNING, "nargs=%d stack balance=%d",
+ nargs, stack_curr - ctx->impl->stack_curr);
+ */
+ ctx->impl->stack_curr = stack_curr - nargs;
+ }
+ GRN_API_RETURN(val);
+}
+
+grn_obj *
+grn_expr_get_value(grn_ctx *ctx, grn_obj *expr, int offset)
+{
+ grn_obj *res = NULL;
+ grn_expr *e = (grn_expr *)expr;
+ GRN_API_ENTER;
+ if (0 <= offset && (uint) offset < e->values_size) {
+ res = &e->values[offset];
+ }
+ GRN_API_RETURN(res);
+}
+
+#define DEFAULT_WEIGHT 5
+#define DEFAULT_DECAYSTEP 2
+#define DEFAULT_MAX_INTERVAL 10
+#define DEFAULT_SIMILARITY_THRESHOLD 0
+#define DEFAULT_TERM_EXTRACT_POLICY 0
+#define DEFAULT_WEIGHT_VECTOR_SIZE 4096
+
+#define GRN_SCAN_INFO_MAX_N_ARGS 128
+
+struct _grn_scan_info {
+ uint32_t start;
+ uint32_t end;
+ int32_t nargs;
+ int flags;
+ grn_operator op;
+ grn_operator logical_op;
+ grn_obj wv;
+ grn_obj index;
+ grn_obj *query;
+ grn_obj *args[GRN_SCAN_INFO_MAX_N_ARGS];
+ int max_interval;
+ int similarity_threshold;
+ grn_obj scorers;
+ grn_obj scorer_args_exprs;
+ grn_obj scorer_args_expr_offsets;
+ struct {
+ grn_bool specified;
+ int start;
+ } position;
+};
+
+#define SI_FREE(si) do {\
+ GRN_OBJ_FIN(ctx, &(si)->wv);\
+ GRN_OBJ_FIN(ctx, &(si)->index);\
+ GRN_OBJ_FIN(ctx, &(si)->scorers);\
+ GRN_OBJ_FIN(ctx, &(si)->scorer_args_exprs);\
+ GRN_OBJ_FIN(ctx, &(si)->scorer_args_expr_offsets);\
+ GRN_FREE(si);\
+} while (0)
+
+#define SI_ALLOC_RAW(si, st) do {\
+ if (((si) = GRN_MALLOCN(scan_info, 1))) {\
+ GRN_INT32_INIT(&(si)->wv, GRN_OBJ_VECTOR);\
+ GRN_PTR_INIT(&(si)->index, GRN_OBJ_VECTOR, GRN_ID_NIL);\
+ (si)->logical_op = GRN_OP_OR;\
+ (si)->flags = SCAN_PUSH;\
+ (si)->nargs = 0;\
+ (si)->max_interval = DEFAULT_MAX_INTERVAL;\
+ (si)->similarity_threshold = DEFAULT_SIMILARITY_THRESHOLD;\
+ (si)->start = (st);\
+ (si)->query = NULL;\
+ GRN_PTR_INIT(&(si)->scorers, GRN_OBJ_VECTOR, GRN_ID_NIL);\
+ GRN_PTR_INIT(&(si)->scorer_args_exprs, GRN_OBJ_VECTOR, GRN_ID_NIL);\
+ GRN_UINT32_INIT(&(si)->scorer_args_expr_offsets, GRN_OBJ_VECTOR);\
+ (si)->position.specified = GRN_FALSE;\
+ (si)->position.start = 0;\
+ }\
+} while (0)
+
+#define SI_ALLOC(si, i, st) do {\
+ SI_ALLOC_RAW(si, st);\
+ if (!(si)) {\
+ int j;\
+ for (j = 0; j < i; j++) { SI_FREE(sis[j]); }\
+ GRN_FREE(sis);\
+ return NULL;\
+ }\
+} while (0)
+
+static scan_info **
+put_logical_op(grn_ctx *ctx, scan_info **sis, int *ip, grn_operator op, int start)
+{
+ int nparens = 1, ndifops = 0, i = *ip, j = i, r = 0;
+ while (j--) {
+ scan_info *s_ = sis[j];
+ if (s_->flags & SCAN_POP) {
+ ndifops++;
+ nparens++;
+ } else {
+ if (s_->flags & SCAN_PUSH) {
+ if (!(--nparens)) {
+ if (!r) {
+ if (ndifops) {
+ if (j && op != GRN_OP_AND_NOT) {
+ nparens = 1;
+ ndifops = 0;
+ r = j;
+ } else {
+ SI_ALLOC(s_, i, start);
+ s_->flags = SCAN_POP;
+ s_->logical_op = op;
+ sis[i++] = s_;
+ *ip = i;
+ break;
+ }
+ } else {
+ s_->flags &= ~SCAN_PUSH;
+ s_->logical_op = op;
+ break;
+ }
+ } else {
+ if (ndifops) {
+ SI_ALLOC(s_, i, start);
+ s_->flags = SCAN_POP;
+ s_->logical_op = op;
+ sis[i++] = s_;
+ *ip = i;
+ } else {
+ s_->flags &= ~SCAN_PUSH;
+ s_->logical_op = op;
+ grn_memcpy(&sis[i], &sis[j], sizeof(scan_info *) * (r - j));
+ grn_memmove(&sis[j], &sis[r], sizeof(scan_info *) * (i - r));
+ grn_memcpy(&sis[i + j - r], &sis[i], sizeof(scan_info *) * (r - j));
+ }
+ break;
+ }
+ }
+ } else {
+ if ((op == GRN_OP_AND_NOT) || (op != s_->logical_op)) {
+ ndifops++;
+ }
+ }
+ }
+ }
+ if (j < 0) {
+ ERR(GRN_INVALID_ARGUMENT, "unmatched nesting level");
+ for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
+ GRN_FREE(sis);
+ return NULL;
+ }
+ return sis;
+}
+
+/* TODO: Remove me if nobody doesn't want to reuse the implementation again. */
+#if 0
+static const char *opstrs[] = {
+ "PUSH",
+ "POP",
+ "NOP",
+ "CALL",
+ "INTERN",
+ "GET_REF",
+ "GET_VALUE",
+ "AND",
+ "AND_NOT",
+ "OR",
+ "ASSIGN",
+ "STAR_ASSIGN",
+ "SLASH_ASSIGN",
+ "MOD_ASSIGN",
+ "PLUS_ASSIGN",
+ "MINUS_ASSIGN",
+ "SHIFTL_ASSIGN",
+ "SHIFTR_ASSIGN",
+ "SHIFTRR_ASSIGN",
+ "AND_ASSIGN",
+ "XOR_ASSIGN",
+ "OR_ASSIGN",
+ "JUMP",
+ "CJUMP",
+ "COMMA",
+ "BITWISE_OR",
+ "BITWISE_XOR",
+ "BITWISE_AND",
+ "BITWISE_NOT",
+ "EQUAL",
+ "NOT_EQUAL",
+ "LESS",
+ "GREATER",
+ "LESS_EQUAL",
+ "GREATER_EQUAL",
+ "IN",
+ "MATCH",
+ "NEAR",
+ "NEAR2",
+ "SIMILAR",
+ "TERM_EXTRACT",
+ "SHIFTL",
+ "SHIFTR",
+ "SHIFTRR",
+ "PLUS",
+ "MINUS",
+ "STAR",
+ "SLASH",
+ "MOD",
+ "DELETE",
+ "INCR",
+ "DECR",
+ "INCR_POST",
+ "DECR_POST",
+ "NOT",
+ "ADJUST",
+ "EXACT",
+ "LCP",
+ "PARTIAL",
+ "UNSPLIT",
+ "PREFIX",
+ "SUFFIX",
+ "GEO_DISTANCE1",
+ "GEO_DISTANCE2",
+ "GEO_DISTANCE3",
+ "GEO_DISTANCE4",
+ "GEO_WITHINP5",
+ "GEO_WITHINP6",
+ "GEO_WITHINP8",
+ "OBJ_SEARCH",
+ "EXPR_GET_VAR",
+ "TABLE_CREATE",
+ "TABLE_SELECT",
+ "TABLE_SORT",
+ "TABLE_GROUP",
+ "JSON_PUT"
+};
+
+static void
+put_value(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ int len;
+ char namebuf[GRN_TABLE_MAX_KEY_SIZE];
+ if ((len = grn_column_name(ctx, obj, namebuf, GRN_TABLE_MAX_KEY_SIZE))) {
+ GRN_TEXT_PUT(ctx, buf, namebuf, len);
+ } else {
+ grn_text_otoj(ctx, buf, obj, NULL);
+ }
+}
+
+static grn_rc
+grn_expr_inspect_internal(grn_ctx *ctx, grn_obj *buf, grn_obj *expr)
+{
+ uint32_t i, j;
+ grn_expr_var *var;
+ grn_expr_code *code;
+ grn_expr *e = (grn_expr *)expr;
+ grn_hash *vars = grn_expr_get_vars(ctx, expr, &i);
+ GRN_TEXT_PUTS(ctx, buf, "noname");
+ GRN_TEXT_PUTC(ctx, buf, '(');
+ {
+ int i = 0;
+ grn_obj *value;
+ const char *name;
+ uint32_t name_len;
+ GRN_HASH_EACH(ctx, vars, id, &name, &name_len, &value, {
+ if (i++) { GRN_TEXT_PUTC(ctx, buf, ','); }
+ GRN_TEXT_PUT(ctx, buf, name, name_len);
+ GRN_TEXT_PUTC(ctx, buf, ':');
+ put_value(ctx, buf, value);
+ });
+ }
+ GRN_TEXT_PUTC(ctx, buf, ')');
+ GRN_TEXT_PUTC(ctx, buf, '{');
+ for (j = 0, code = e->codes; j < e->codes_curr; j++, code++) {
+ if (j) { GRN_TEXT_PUTC(ctx, buf, ','); }
+ grn_text_itoa(ctx, buf, code->modify);
+ if (code->op == GRN_OP_PUSH) {
+ for (i = 0, var = e->vars; i < e->nvars; i++, var++) {
+ if (&var->value == code->value) {
+ GRN_TEXT_PUTC(ctx, buf, '?');
+ if (var->name_size) {
+ GRN_TEXT_PUT(ctx, buf, var->name, var->name_size);
+ } else {
+ grn_text_itoa(ctx, buf, (int)i);
+ }
+ break;
+ }
+ }
+ if (i == e->nvars) {
+ put_value(ctx, buf, code->value);
+ }
+ } else {
+ if (code->value) {
+ put_value(ctx, buf, code->value);
+ GRN_TEXT_PUTC(ctx, buf, ' ');
+ }
+ GRN_TEXT_PUTS(ctx, buf, opstrs[code->op]);
+ }
+ }
+ GRN_TEXT_PUTC(ctx, buf, '}');
+ return GRN_SUCCESS;
+}
+
+#define EXPRLOG(name,expr) do {\
+ grn_obj strbuf;\
+ GRN_TEXT_INIT(&strbuf, 0);\
+ grn_expr_inspect_internal(ctx, &strbuf, (expr));\
+ GRN_TEXT_PUTC(ctx, &strbuf, '\0');\
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "%s=(%s)", (name), GRN_TEXT_VALUE(&strbuf));\
+ GRN_OBJ_FIN(ctx, &strbuf);\
+} while (0)
+#endif
+
+
+static void
+scan_info_put_index(grn_ctx *ctx, scan_info *si,
+ grn_obj *index, uint32_t sid, int32_t weight,
+ grn_obj *scorer,
+ grn_obj *scorer_args_expr,
+ uint32_t scorer_args_expr_offset)
+{
+ GRN_PTR_PUT(ctx, &si->index, index);
+ GRN_UINT32_PUT(ctx, &si->wv, sid);
+ GRN_INT32_PUT(ctx, &si->wv, weight);
+ GRN_PTR_PUT(ctx, &si->scorers, scorer);
+ GRN_PTR_PUT(ctx, &si->scorer_args_exprs, scorer_args_expr);
+ GRN_UINT32_PUT(ctx, &si->scorer_args_expr_offsets, scorer_args_expr_offset);
+ {
+ int i, ni = (GRN_BULK_VSIZE(&si->index) / sizeof(grn_obj *)) - 1;
+ grn_obj **pi = &GRN_PTR_VALUE_AT(&si->index, ni);
+ for (i = 0; i < ni; i++, pi--) {
+ if (index == pi[-1]) {
+ if (i) {
+ int32_t *pw = &GRN_INT32_VALUE_AT(&si->wv, (ni - i) * 2);
+ grn_memmove(pw + 2, pw, sizeof(int32_t) * 2 * i);
+ pw[0] = (int32_t) sid;
+ pw[1] = weight;
+ grn_memmove(pi + 1, pi, sizeof(grn_obj *) * i);
+ pi[0] = index;
+ }
+ return;
+ }
+ }
+ }
+}
+
+static int32_t
+get_weight(grn_ctx *ctx, grn_expr_code *ec, uint32_t *offset)
+{
+ if (ec->modify == 2 && ec[2].op == GRN_OP_STAR &&
+ ec[1].value && ec[1].value->header.type == GRN_BULK) {
+ if (offset) {
+ *offset = 2;
+ }
+ if (ec[1].value->header.domain == GRN_DB_INT32 ||
+ ec[1].value->header.domain == GRN_DB_UINT32) {
+ return GRN_INT32_VALUE(ec[1].value);
+ } else {
+ int32_t weight = 1;
+ grn_obj weight_buffer;
+ GRN_INT32_INIT(&weight_buffer, 0);
+ if (!grn_obj_cast(ctx, ec[1].value, &weight_buffer, GRN_FALSE)) {
+ weight = GRN_INT32_VALUE(&weight_buffer);
+ }
+ grn_obj_unlink(ctx, &weight_buffer);
+ return weight;
+ }
+ } else {
+ if (offset) {
+ *offset = 0;
+ }
+ return 1;
+ }
+}
+
+scan_info *
+grn_scan_info_open(grn_ctx *ctx, int start)
+{
+ scan_info *si = GRN_MALLOCN(scan_info, 1);
+
+ if (!si) {
+ return NULL;
+ }
+
+ GRN_INT32_INIT(&si->wv, GRN_OBJ_VECTOR);
+ GRN_PTR_INIT(&si->index, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ si->logical_op = GRN_OP_OR;
+ si->flags = SCAN_PUSH;
+ si->nargs = 0;
+ si->max_interval = DEFAULT_MAX_INTERVAL;
+ si->similarity_threshold = DEFAULT_SIMILARITY_THRESHOLD;
+ si->start = start;
+ GRN_PTR_INIT(&si->scorers, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_PTR_INIT(&si->scorer_args_exprs, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_UINT32_INIT(&si->scorer_args_expr_offsets, GRN_OBJ_VECTOR);
+ si->position.specified = GRN_FALSE;
+ si->position.start = 0;
+
+ return si;
+}
+
+void
+grn_scan_info_close(grn_ctx *ctx, scan_info *si)
+{
+ SI_FREE(si);
+}
+
+void
+grn_scan_info_put_index(grn_ctx *ctx, scan_info *si,
+ grn_obj *index, uint32_t sid, int32_t weight,
+ grn_obj *scorer,
+ grn_obj *scorer_args_expr,
+ uint32_t scorer_args_expr_offset)
+{
+ scan_info_put_index(ctx, si, index, sid, weight,
+ scorer,
+ scorer_args_expr,
+ scorer_args_expr_offset);
+}
+
+scan_info **
+grn_scan_info_put_logical_op(grn_ctx *ctx, scan_info **sis, int *ip,
+ grn_operator op, int start)
+{
+ return put_logical_op(ctx, sis, ip, op, start);
+}
+
+int32_t
+grn_expr_code_get_weight(grn_ctx *ctx, grn_expr_code *ec, uint32_t *offset)
+{
+ return get_weight(ctx, ec, offset);
+}
+
+int
+grn_scan_info_get_flags(scan_info *si)
+{
+ return si->flags;
+}
+
+void
+grn_scan_info_set_flags(scan_info *si, int flags)
+{
+ si->flags = flags;
+}
+
+grn_operator
+grn_scan_info_get_logical_op(scan_info *si)
+{
+ return si->logical_op;
+}
+
+void
+grn_scan_info_set_logical_op(scan_info *si, grn_operator logical_op)
+{
+ si->logical_op = logical_op;
+}
+
+grn_operator
+grn_scan_info_get_op(scan_info *si)
+{
+ return si->op;
+}
+
+void
+grn_scan_info_set_op(scan_info *si, grn_operator op)
+{
+ si->op = op;
+}
+
+void
+grn_scan_info_set_end(scan_info *si, uint32_t end)
+{
+ si->end = end;
+}
+
+void
+grn_scan_info_set_query(scan_info *si, grn_obj *query)
+{
+ si->query = query;
+}
+
+int
+grn_scan_info_get_max_interval(scan_info *si)
+{
+ return si->max_interval;
+}
+
+void
+grn_scan_info_set_max_interval(scan_info *si, int max_interval)
+{
+ si->max_interval = max_interval;
+}
+
+int
+grn_scan_info_get_similarity_threshold(scan_info *si)
+{
+ return si->similarity_threshold;
+}
+
+void
+grn_scan_info_set_similarity_threshold(scan_info *si, int similarity_threshold)
+{
+ si->similarity_threshold = similarity_threshold;
+}
+
+grn_bool
+grn_scan_info_push_arg(scan_info *si, grn_obj *arg)
+{
+ if (si->nargs >= GRN_SCAN_INFO_MAX_N_ARGS) {
+ return GRN_FALSE;
+ }
+
+ si->args[si->nargs++] = arg;
+ return GRN_TRUE;
+}
+
+grn_obj *
+grn_scan_info_get_arg(grn_ctx *ctx, scan_info *si, int i)
+{
+ if (i >= si->nargs) {
+ return NULL;
+ }
+ return si->args[i];
+}
+
+int
+grn_scan_info_get_start_position(scan_info *si)
+{
+ return si->position.start;
+}
+
+void
+grn_scan_info_set_start_position(scan_info *si, int start)
+{
+ si->position.specified = GRN_TRUE;
+ si->position.start = start;
+}
+
+void
+grn_scan_info_reset_position(scan_info *si)
+{
+ si->position.specified = GRN_FALSE;
+}
+
+static uint32_t
+scan_info_build_match_expr_codes_find_index(grn_ctx *ctx, scan_info *si,
+ grn_expr *expr, uint32_t i,
+ grn_obj **index,
+ int *sid)
+{
+ grn_expr_code *ec;
+ uint32_t offset = 1;
+ grn_index_datum index_datum;
+ unsigned int n_index_data = 0;
+
+ ec = &(expr->codes[i]);
+ switch (ec->value->header.type) {
+ case GRN_ACCESSOR :
+ n_index_data = grn_column_find_index_data(ctx, ec->value, si->op,
+ &index_datum, 1);
+ if (n_index_data > 0) {
+ grn_accessor *a = (grn_accessor *)(ec->value);
+ *sid = index_datum.section;
+ if (a->next && a->obj != index_datum.index) {
+ *index = ec->value;
+ } else {
+ *index = index_datum.index;
+ }
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ n_index_data = grn_column_find_index_data(ctx, ec->value, si->op,
+ &index_datum, 1);
+ if (n_index_data > 0) {
+ *index = index_datum.index;
+ *sid = index_datum.section;
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ {
+ uint32_t n_rest_codes;
+
+ *index = ec->value;
+
+ n_rest_codes = expr->codes_curr - i;
+ if (n_rest_codes >= 2 &&
+ ec[1].value &&
+ (ec[1].value->header.domain == GRN_DB_INT32 ||
+ ec[1].value->header.domain == GRN_DB_UINT32) &&
+ ec[2].op == GRN_OP_GET_MEMBER) {
+ if (ec[1].value->header.domain == GRN_DB_INT32) {
+ *sid = GRN_INT32_VALUE(ec[1].value) + 1;
+ } else {
+ *sid = GRN_UINT32_VALUE(ec[1].value) + 1;
+ }
+ offset += 2;
+ }
+ }
+ break;
+ default :
+ break;
+ }
+
+ return offset;
+}
+
+static uint32_t
+scan_info_build_match_expr_codes(grn_ctx *ctx,
+ scan_info *si,
+ grn_expr *expr,
+ uint32_t i,
+ int32_t weight)
+{
+ grn_expr_code *ec;
+ grn_obj *index = NULL;
+ int sid = 0;
+ uint32_t offset = 0;
+
+ ec = &(expr->codes[i]);
+ if (!ec->value) {
+ return i + 1;
+ }
+
+ switch (ec->value->header.type) {
+ case GRN_ACCESSOR :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ offset = scan_info_build_match_expr_codes_find_index(ctx, si, expr, i,
+ &index, &sid);
+ i += offset - 1;
+ if (index) {
+ if (ec->value->header.type == GRN_ACCESSOR) {
+ si->flags |= SCAN_ACCESSOR;
+ }
+ scan_info_put_index(ctx, si, index, sid,
+ get_weight(ctx, &(expr->codes[i]), &offset) + weight,
+ NULL, NULL, 0);
+ i += offset;
+ }
+ break;
+ case GRN_PROC :
+ if (!grn_obj_is_scorer_proc(ctx, ec->value)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, ec->value);
+ ERR(GRN_INVALID_ARGUMENT,
+ "procedure must be scorer: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return expr->codes_curr;
+ }
+ i++;
+ offset = scan_info_build_match_expr_codes_find_index(ctx, si, expr, i,
+ &index, &sid);
+ i += offset;
+ if (index) {
+ uint32_t scorer_args_expr_offset = 0;
+ if (expr->codes[i].op != GRN_OP_CALL) {
+ scorer_args_expr_offset = i;
+ }
+ while (i < expr->codes_curr && expr->codes[i].op != GRN_OP_CALL) {
+ i++;
+ }
+ scan_info_put_index(ctx, si, index, sid,
+ get_weight(ctx, &(expr->codes[i]), &offset) + weight,
+ ec->value,
+ (grn_obj *)expr,
+ scorer_args_expr_offset);
+ i += offset;
+ }
+ break;
+ default :
+ {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_obj_name(ctx, ec->value, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "invalid match target: <%.*s>",
+ name_size, name);
+ return expr->codes_curr;
+ }
+ break;
+ }
+
+ return i + 1;
+}
+
+static void
+scan_info_build_match_expr(grn_ctx *ctx,
+ scan_info *si,
+ grn_expr *expr,
+ int32_t weight)
+{
+ uint32_t i;
+ i = 0;
+ while (i < expr->codes_curr) {
+ i = scan_info_build_match_expr_codes(ctx, si, expr, i, weight);
+ }
+}
+
+static grn_bool
+is_index_searchable_regexp(grn_ctx *ctx, grn_obj *regexp)
+{
+ const char *regexp_raw;
+ const char *regexp_raw_end;
+ grn_bool escaping = GRN_FALSE;
+ grn_bool dot = GRN_FALSE;
+
+ if (!(regexp->header.domain == GRN_DB_SHORT_TEXT ||
+ regexp->header.domain == GRN_DB_TEXT ||
+ regexp->header.domain == GRN_DB_LONG_TEXT)) {
+ return GRN_FALSE;
+ }
+
+ regexp_raw = GRN_TEXT_VALUE(regexp);
+ regexp_raw_end = regexp_raw + GRN_TEXT_LEN(regexp);
+
+ while (regexp_raw < regexp_raw_end) {
+ unsigned int char_len;
+
+ char_len = grn_charlen(ctx, regexp_raw, regexp_raw_end);
+ if (char_len == 0) {
+ return GRN_FALSE;
+ }
+
+ if (char_len == 1) {
+ if (escaping) {
+ escaping = GRN_FALSE;
+ switch (regexp_raw[0]) {
+ case 'Z' :
+ case 'b' :
+ case 'B' :
+ case 'd' :
+ case 'D' :
+ case 'h' :
+ case 'H' :
+ case 'p' :
+ case 's' :
+ case 'S' :
+ case 'w' :
+ case 'W' :
+ case 'X' :
+ case 'k' :
+ case 'g' :
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ case '8' :
+ case '9' :
+ return GRN_FALSE;
+ default :
+ break;
+ }
+ } else {
+ switch (regexp_raw[0]) {
+ case '.' :
+ escaping = GRN_FALSE;
+ if (dot) {
+ return GRN_FALSE;
+ }
+ dot = GRN_TRUE;
+ break;
+ case '*' :
+ escaping = GRN_FALSE;
+ if (!dot) {
+ return GRN_FALSE;
+ }
+ if (!grn_scan_info_regexp_dot_asterisk_enable) {
+ return GRN_FALSE;
+ }
+ dot = GRN_FALSE;
+ break;
+ case '[' :
+ case ']' :
+ case '|' :
+ case '?' :
+ case '+' :
+ case '{' :
+ case '}' :
+ case '^' :
+ case '$' :
+ case '(' :
+ case ')' :
+ escaping = GRN_FALSE;
+ return GRN_FALSE;
+ case '\\' :
+ if (dot) {
+ return GRN_FALSE;
+ }
+ escaping = GRN_TRUE;
+ break;
+ default :
+ if (dot) {
+ return GRN_FALSE;
+ }
+ escaping = GRN_FALSE;
+ break;
+ }
+ }
+ } else {
+ escaping = GRN_FALSE;
+ }
+
+ regexp_raw += char_len;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+scan_info_build_match(grn_ctx *ctx, scan_info *si, int32_t weight)
+{
+ grn_obj **p, **pe;
+
+ if (si->op == GRN_OP_REGEXP) {
+ p = si->args;
+ pe = si->args + si->nargs;
+ for (; p < pe; p++) {
+ if ((*p)->header.type == GRN_BULK &&
+ !is_index_searchable_regexp(ctx, *p)) {
+ return;
+ }
+ }
+ }
+
+ p = si->args;
+ pe = si->args + si->nargs;
+ for (; p < pe; p++) {
+ if ((*p)->header.type == GRN_EXPR) {
+ scan_info_build_match_expr(ctx, si, (grn_expr *)(*p), weight);
+ } else if ((*p)->header.type == GRN_COLUMN_INDEX) {
+ scan_info_put_index(ctx, si, *p, 0, 1 + weight, NULL, NULL, 0);
+ } else if (grn_obj_is_proc(ctx, *p)) {
+ break;
+ } else if (GRN_DB_OBJP(*p)) {
+ grn_index_datum index_datum;
+ unsigned int n_index_data;
+ n_index_data = grn_column_find_index_data(ctx, *p, si->op,
+ &index_datum, 1);
+ if (n_index_data > 0) {
+ scan_info_put_index(ctx, si,
+ index_datum.index, index_datum.section, 1 + weight,
+ NULL, NULL, 0);
+ }
+ } else if (GRN_ACCESSORP(*p)) {
+ grn_index_datum index_datum;
+ unsigned int n_index_data;
+ si->flags |= SCAN_ACCESSOR;
+ n_index_data = grn_column_find_index_data(ctx, *p, si->op,
+ &index_datum, 1);
+ if (n_index_data > 0) {
+ grn_obj *index;
+ if (((grn_accessor *)(*p))->next) {
+ index = *p;
+ } else {
+ index = index_datum.index;
+ }
+ scan_info_put_index(ctx, si,
+ index, index_datum.section, 1 + weight,
+ NULL, NULL, 0);
+ }
+ } else {
+ switch (si->op) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ if (si->nargs == 3 &&
+ *p == si->args[2] &&
+ (*p)->header.domain == GRN_DB_INT32) {
+ si->max_interval = GRN_INT32_VALUE(*p);
+ } else {
+ si->query = *p;
+ }
+ break;
+ case GRN_OP_SIMILAR :
+ if (si->nargs == 3 &&
+ *p == si->args[2] &&
+ (*p)->header.domain == GRN_DB_INT32) {
+ si->similarity_threshold = GRN_INT32_VALUE(*p);
+ } else {
+ si->query = *p;
+ }
+ break;
+ default :
+ si->query = *p;
+ break;
+ }
+ }
+ }
+}
+
+static grn_bool
+grn_scan_info_build_full_not(grn_ctx *ctx,
+ scan_info **sis,
+ int *i,
+ grn_expr_code *codes,
+ grn_expr_code *code,
+ grn_expr_code *code_end,
+ grn_operator *next_code_op)
+{
+ scan_info *last_si;
+
+ if (*i == 0) {
+ return GRN_TRUE;
+ }
+
+ last_si = sis[*i - 1];
+ switch (last_si->op) {
+ case GRN_OP_LESS :
+ last_si->op = GRN_OP_GREATER_EQUAL;
+ last_si->end++;
+ break;
+ case GRN_OP_LESS_EQUAL :
+ last_si->op = GRN_OP_GREATER;
+ last_si->end++;
+ break;
+ case GRN_OP_GREATER :
+ last_si->op = GRN_OP_LESS_EQUAL;
+ last_si->end++;
+ break;
+ case GRN_OP_GREATER_EQUAL :
+ last_si->op = GRN_OP_LESS;
+ last_si->end++;
+ break;
+ case GRN_OP_NOT_EQUAL :
+ last_si->op = GRN_OP_EQUAL;
+ last_si->end++;
+ break;
+ default :
+ if (*i == 1) {
+ if (GRN_BULK_VSIZE(&(last_si->index)) > 0) {
+ scan_info *all_records_si = NULL;
+ SI_ALLOC_RAW(all_records_si, 0);
+ if (!all_records_si) {
+ return GRN_FALSE;
+ }
+ all_records_si->op = GRN_OP_CALL;
+ all_records_si->args[all_records_si->nargs++] =
+ grn_ctx_get(ctx, "all_records", -1);
+ last_si->logical_op = GRN_OP_AND_NOT;
+ last_si->flags &= ~SCAN_PUSH;
+ sis[*i] = sis[*i - 1];
+ sis[*i - 1] = all_records_si;
+ (*i)++;
+ } else {
+ if (last_si->op == GRN_OP_EQUAL) {
+ last_si->op = GRN_OP_NOT_EQUAL;
+ last_si->end++;
+ } else {
+ return GRN_FALSE;
+ }
+ }
+ } else {
+ grn_expr_code *next_code = code + 1;
+
+ if (next_code >= code_end) {
+ return GRN_FALSE;
+ }
+
+ switch (next_code->op) {
+ case GRN_OP_AND :
+ *next_code_op = GRN_OP_AND_NOT;
+ break;
+ case GRN_OP_AND_NOT :
+ *next_code_op = GRN_OP_AND;
+ break;
+ case GRN_OP_OR :
+ {
+ scan_info *all_records_si = NULL;
+ SI_ALLOC_RAW(all_records_si, 0);
+ if (!all_records_si) {
+ return GRN_FALSE;
+ }
+ all_records_si->op = GRN_OP_CALL;
+ all_records_si->args[all_records_si->nargs++] =
+ grn_ctx_get(ctx, "all_records", -1);
+ sis[*i] = sis[*i - 1];
+ sis[*i - 1] = all_records_si;
+ (*i)++;
+ put_logical_op(ctx, sis, i, GRN_OP_AND_NOT, code - codes);
+ }
+ break;
+ default :
+ return GRN_FALSE;
+ break;
+ }
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static scan_info **
+grn_scan_info_build_full(grn_ctx *ctx, grn_obj *expr, int *n,
+ grn_operator op, grn_bool record_exist)
+{
+ grn_obj *var;
+ scan_stat stat;
+ int i, m = 0, o = 0;
+ int n_nots = 0;
+ scan_info **sis, *si = NULL;
+ grn_expr_code *c, *ce;
+ grn_expr *e = (grn_expr *)expr;
+ grn_operator next_code_op;
+
+ if (!(var = grn_expr_get_var_by_offset(ctx, expr, 0))) { return NULL; }
+ for (stat = SCAN_START, c = e->codes, ce = &e->codes[e->codes_curr]; c < ce; c++) {
+ switch (c->op) {
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_GEO_WITHINP5 :
+ case GRN_OP_GEO_WITHINP6 :
+ case GRN_OP_GEO_WITHINP8 :
+ case GRN_OP_TERM_EXTRACT :
+ case GRN_OP_REGEXP :
+ if (stat < SCAN_COL1 || SCAN_CONST < stat) { return NULL; }
+ stat = SCAN_START;
+ m++;
+ break;
+ case GRN_OP_BITWISE_OR :
+ case GRN_OP_BITWISE_XOR :
+ case GRN_OP_BITWISE_AND :
+ case GRN_OP_BITWISE_NOT :
+ case GRN_OP_SHIFTL :
+ case GRN_OP_SHIFTR :
+ case GRN_OP_SHIFTRR :
+ case GRN_OP_PLUS :
+ case GRN_OP_MINUS :
+ case GRN_OP_STAR :
+ case GRN_OP_MOD :
+ if (stat < SCAN_COL1 || SCAN_CONST < stat) { return NULL; }
+ stat = SCAN_START;
+ if (m != o + 1) { return NULL; }
+ break;
+ case GRN_OP_AND :
+ case GRN_OP_OR :
+ case GRN_OP_AND_NOT :
+ case GRN_OP_ADJUST :
+ switch (stat) {
+ case SCAN_START :
+ o++;
+ if (o >= m) { return NULL; }
+ break;
+ case SCAN_CONST :
+ o++;
+ m++;
+ if (o >= m) { return NULL; }
+ stat = SCAN_START;
+ break;
+ default :
+ return NULL;
+ break;
+ }
+ break;
+ case GRN_OP_PUSH :
+ {
+ grn_bool is_completed_term = GRN_FALSE;
+ if (c->modify > 0) {
+ switch ((c + c->modify)->op) {
+ case GRN_OP_AND :
+ case GRN_OP_OR :
+ case GRN_OP_AND_NOT :
+ case GRN_OP_ADJUST :
+ is_completed_term = GRN_TRUE;
+ break;
+ default :
+ is_completed_term = GRN_FALSE;
+ break;
+ }
+ }
+ if (is_completed_term) {
+ m++;
+ stat = SCAN_START;
+ } else {
+ stat = (c->value == var) ? SCAN_VAR : SCAN_CONST;
+ }
+ }
+ break;
+ case GRN_OP_GET_VALUE :
+ switch (stat) {
+ case SCAN_START :
+ case SCAN_CONST :
+ case SCAN_VAR :
+ stat = SCAN_COL1;
+ break;
+ case SCAN_COL1 :
+ stat = SCAN_COL2;
+ break;
+ case SCAN_COL2 :
+ break;
+ default :
+ return NULL;
+ break;
+ }
+ break;
+ case GRN_OP_CALL :
+ if ((c->flags & GRN_EXPR_CODE_RELATIONAL_EXPRESSION) || c + 1 == ce) {
+ stat = SCAN_START;
+ m++;
+ } else {
+ stat = SCAN_COL2;
+ }
+ break;
+ case GRN_OP_GET_REF :
+ switch (stat) {
+ case SCAN_START :
+ stat = SCAN_COL1;
+ break;
+ default :
+ return NULL;
+ break;
+ }
+ break;
+ case GRN_OP_GET_MEMBER :
+ switch (stat) {
+ case SCAN_CONST :
+ {
+ grn_expr_code *prev_c = c - 1;
+ if (prev_c->value->header.domain < GRN_DB_INT8 ||
+ prev_c->value->header.domain > GRN_DB_UINT64) {
+ return NULL;
+ }
+ }
+ stat = SCAN_COL1;
+ break;
+ default :
+ return NULL;
+ break;
+ }
+ break;
+ case GRN_OP_NOT :
+ n_nots++;
+ break;
+ default :
+ return NULL;
+ break;
+ }
+ }
+ if (stat || m != o + 1) { return NULL; }
+ if (!(sis = GRN_MALLOCN(scan_info *, m + m + o + n_nots))) { return NULL; }
+
+ next_code_op = -1;
+ for (i = 0, stat = SCAN_START, c = e->codes, ce = &e->codes[e->codes_curr]; c < ce; c++) {
+ grn_operator code_op;
+ if (next_code_op == (grn_operator)-1) {
+ code_op = c->op;
+ } else {
+ code_op = next_code_op;
+ next_code_op = -1;
+ }
+ switch (code_op) {
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_GEO_WITHINP5 :
+ case GRN_OP_GEO_WITHINP6 :
+ case GRN_OP_GEO_WITHINP8 :
+ case GRN_OP_TERM_EXTRACT :
+ case GRN_OP_REGEXP :
+ stat = SCAN_START;
+ si->op = code_op;
+ si->end = c - e->codes;
+ sis[i++] = si;
+ {
+ int32_t weight = 0;
+ if (c->value && c->value->header.domain == GRN_DB_INT32) {
+ weight = GRN_INT32_VALUE(c->value);
+ }
+ scan_info_build_match(ctx, si, weight);
+ }
+ if (ctx->rc != GRN_SUCCESS) {
+ int j;
+ for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
+ GRN_FREE(sis);
+ return NULL;
+ }
+ si = NULL;
+ break;
+ case GRN_OP_AND :
+ case GRN_OP_OR :
+ case GRN_OP_AND_NOT :
+ case GRN_OP_ADJUST :
+ if (stat == SCAN_CONST) {
+ si->op = GRN_OP_PUSH;
+ si->end = si->start;
+ sis[i++] = si;
+ si = NULL;
+ }
+ if (!put_logical_op(ctx, sis, &i, code_op, c - e->codes)) { return NULL; }
+ stat = SCAN_START;
+ break;
+ case GRN_OP_PUSH :
+ if (!si) { SI_ALLOC(si, i, c - e->codes); }
+ if (c->value == var) {
+ stat = SCAN_VAR;
+ } else {
+ if (si->nargs < GRN_SCAN_INFO_MAX_N_ARGS) {
+ si->args[si->nargs++] = c->value;
+ }
+ if (stat == SCAN_START) { si->flags |= SCAN_PRE_CONST; }
+ stat = SCAN_CONST;
+ }
+ if (c->modify > 0) {
+ grn_bool is_completed_term = GRN_FALSE;
+ switch ((c + c->modify)->op) {
+ case GRN_OP_AND :
+ case GRN_OP_OR :
+ case GRN_OP_AND_NOT :
+ case GRN_OP_ADJUST :
+ is_completed_term = GRN_TRUE;
+ break;
+ default :
+ is_completed_term = GRN_FALSE;
+ break;
+ }
+ if (is_completed_term) {
+ si->op = GRN_OP_PUSH;
+ si->end = si->start;
+ sis[i++] = si;
+ si = NULL;
+ stat = SCAN_START;
+ }
+ }
+ break;
+ case GRN_OP_GET_VALUE :
+ switch (stat) {
+ case SCAN_START :
+ if (!si) { SI_ALLOC(si, i, c - e->codes); }
+ // fallthru
+ case SCAN_CONST :
+ case SCAN_VAR :
+ stat = SCAN_COL1;
+ if (si->nargs < GRN_SCAN_INFO_MAX_N_ARGS) {
+ si->args[si->nargs++] = c->value;
+ }
+ break;
+ case SCAN_COL1 :
+ {
+ int j;
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ GRN_TEXT_PUTS(ctx, &inspected, "<");
+ grn_inspect_name(ctx, &inspected, c->value);
+ GRN_TEXT_PUTS(ctx, &inspected, ">: <");
+ grn_inspect(ctx, &inspected, expr);
+ GRN_TEXT_PUTS(ctx, &inspected, ">");
+ ERR(GRN_INVALID_ARGUMENT,
+ "invalid expression: can't use column as a value: %.*s",
+ (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ SI_FREE(si);
+ for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
+ GRN_FREE(sis);
+ return NULL;
+ }
+ stat = SCAN_COL2;
+ break;
+ case SCAN_COL2 :
+ break;
+ default :
+ break;
+ }
+ break;
+ case GRN_OP_CALL :
+ if (!si) { SI_ALLOC(si, i, c - e->codes); }
+ if ((c->flags & GRN_EXPR_CODE_RELATIONAL_EXPRESSION) || c + 1 == ce) {
+ stat = SCAN_START;
+ si->op = code_op;
+ si->end = c - e->codes;
+ sis[i++] = si;
+ /* better index resolving framework for functions should be implemented */
+ if (grn_obj_is_selector_proc(ctx, si->args[0])) {
+ grn_obj *selector;
+ grn_obj **p;
+ grn_obj **pe;
+ grn_operator selector_op;
+
+ selector = si->args[0];
+ p = si->args + 1;
+ pe = si->args + si->nargs;
+ selector_op = grn_proc_get_selector_operator(ctx, selector);
+ for (; p < pe; p++) {
+ if (GRN_DB_OBJP(*p)) {
+ grn_index_datum index_datum;
+ unsigned int n_index_data;
+ n_index_data = grn_column_find_index_data(ctx, *p, selector_op,
+ &index_datum, 1);
+ if (n_index_data > 0) {
+ scan_info_put_index(ctx, si,
+ index_datum.index, index_datum.section, 1,
+ NULL, NULL, 0);
+ }
+ } else if (GRN_ACCESSORP(*p)) {
+ grn_index_datum index_datum;
+ unsigned int n_index_data;
+ si->flags |= SCAN_ACCESSOR;
+ n_index_data = grn_column_find_index_data(ctx, *p, selector_op,
+ &index_datum, 1);
+ if (n_index_data > 0) {
+ scan_info_put_index(ctx, si,
+ index_datum.index, index_datum.section, 1,
+ NULL, NULL, 0);
+ }
+ } else {
+ si->query = *p;
+ }
+ }
+ }
+ si = NULL;
+ } else {
+ stat = SCAN_COL2;
+ }
+ break;
+ case GRN_OP_GET_REF :
+ switch (stat) {
+ case SCAN_START :
+ if (!si) { SI_ALLOC(si, i, c - e->codes); }
+ stat = SCAN_COL1;
+ if (si->nargs < GRN_SCAN_INFO_MAX_N_ARGS) {
+ si->args[si->nargs++] = c->value;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case GRN_OP_GET_MEMBER :
+ {
+ grn_obj *start_position;
+ grn_obj buffer;
+ start_position = si->args[--si->nargs];
+ GRN_INT32_INIT(&buffer, 0);
+ grn_obj_cast(ctx, start_position, &buffer, GRN_FALSE);
+ grn_scan_info_set_start_position(si, GRN_INT32_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+ }
+ stat = SCAN_COL1;
+ break;
+ case GRN_OP_NOT :
+ {
+ grn_bool valid;
+ valid = grn_scan_info_build_full_not(ctx,
+ sis,
+ &i,
+ e->codes,
+ c,
+ ce,
+ &next_code_op);
+ if (!valid) {
+ int j;
+ for (j = 0; j < i; j++) {
+ SI_FREE(sis[j]);
+ }
+ GRN_FREE(sis);
+ return NULL;
+ }
+ }
+ break;
+ default :
+ break;
+ }
+ }
+ if (op == GRN_OP_OR && !record_exist) {
+ // for debug
+ if (!(sis[0]->flags & SCAN_PUSH) || (sis[0]->logical_op != op)) {
+ int j;
+ ERR(GRN_INVALID_ARGUMENT, "invalid expr");
+ for (j = 0; j < i; j++) { SI_FREE(sis[j]); }
+ GRN_FREE(sis);
+ return NULL;
+ } else {
+ sis[0]->flags &= ~SCAN_PUSH;
+ sis[0]->logical_op = op;
+ }
+ } else {
+ if (!put_logical_op(ctx, sis, &i, op, c - e->codes)) { return NULL; }
+ }
+ *n = i;
+ return sis;
+}
+
+static scan_info **
+grn_scan_info_build_simple_open(grn_ctx *ctx, int *n, grn_operator logical_op)
+{
+ scan_info **sis;
+ scan_info *si;
+
+ sis = GRN_MALLOCN(scan_info *, 1);
+ if (!sis) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[scan_info][build] failed to allocate memory for scan_info **");
+ return NULL;
+ }
+
+ si = grn_scan_info_open(ctx, 0);
+ if (!si) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[scan_info][build] failed to allocate memory for scan_info *");
+ GRN_FREE(sis);
+ return NULL;
+ }
+
+ si->flags &= ~SCAN_PUSH;
+ si->logical_op = logical_op;
+
+ sis[0] = si;
+ *n = 1;
+
+ return sis;
+}
+
+static scan_info **
+grn_scan_info_build_simple_value(grn_ctx *ctx,
+ grn_obj *expr,
+ int *n,
+ grn_operator logical_op,
+ grn_bool record_exist)
+{
+ grn_expr *e = (grn_expr *)expr;
+ scan_info **sis;
+ scan_info *si;
+ grn_expr_code *target = e->codes;
+
+ switch (target->op) {
+ case GRN_OP_PUSH :
+ case GRN_OP_GET_VALUE :
+ break;
+ default :
+ return NULL;
+ break;
+ }
+
+ sis = grn_scan_info_build_simple_open(ctx, n, logical_op);
+ if (!sis) {
+ return NULL;
+ }
+
+ si = sis[0];
+ si->end = 0;
+ si->op = target->op;
+ return sis;
+}
+
+static scan_info **
+grn_scan_info_build_simple_operation(grn_ctx *ctx,
+ grn_obj *expr,
+ int *n,
+ grn_operator logical_op,
+ grn_bool record_exist)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *target;
+ grn_expr_code *constant;
+ grn_expr_code *operator;
+ scan_info **sis;
+ scan_info *si;
+
+ target = e->codes + 0;
+ constant = e->codes + 1;
+ operator = e->codes + 2;
+
+ if (target->op != GRN_OP_GET_VALUE) {
+ return NULL;
+ }
+ if (target->nargs != 1) {
+ return NULL;
+ }
+ if (!target->value) {
+ return NULL;
+ }
+
+ if (constant->op != GRN_OP_PUSH) {
+ return NULL;
+ }
+ if (constant->nargs != 1) {
+ return NULL;
+ }
+ if (!constant->value) {
+ return NULL;
+ }
+
+ if (operator->nargs != 2) {
+ return NULL;
+ }
+ switch (operator->op) {
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_TERM_EXTRACT :
+ case GRN_OP_REGEXP :
+ break;
+ default :
+ return NULL;
+ break;
+ }
+
+ sis = grn_scan_info_build_simple_open(ctx, n, logical_op);
+ if (!sis) {
+ return NULL;
+ }
+
+ si = sis[0];
+ si->end = 2;
+ si->op = operator->op;
+ si->args[si->nargs++] = target->value;
+ si->args[si->nargs++] = constant->value;
+ {
+ int32_t weight = 0;
+ if (operator->value && operator->value->header.domain == GRN_DB_INT32) {
+ weight = GRN_INT32_VALUE(operator->value);
+ }
+ scan_info_build_match(ctx, si, weight);
+ }
+ return sis;
+}
+
+static scan_info **
+grn_scan_info_build_simple_and_operations(grn_ctx *ctx,
+ grn_obj *expr,
+ int *n,
+ grn_operator logical_op,
+ grn_bool record_exist)
+{
+ grn_expr *e = (grn_expr *)expr;
+ scan_info **sis = NULL;
+ int n_sis = 0;
+ int i;
+ int nth_sis;
+
+ for (i = 0, nth_sis = 0; (uint) i < e->codes_curr; i += 3, nth_sis++) {
+ grn_expr_code *target = e->codes + i;
+ grn_expr_code *constant = e->codes + i + 1;
+ grn_expr_code *operator = e->codes + i + 2;
+
+ if (target->op != GRN_OP_GET_VALUE) {
+ return NULL;
+ }
+ if (target->nargs != 1) {
+ return NULL;
+ }
+ if (!target->value) {
+ return NULL;
+ }
+
+ if (constant->op != GRN_OP_PUSH) {
+ return NULL;
+ }
+ if (constant->nargs != 1) {
+ return NULL;
+ }
+ if (!constant->value) {
+ return NULL;
+ }
+
+ if (operator->nargs != 2) {
+ return NULL;
+ }
+ switch (operator->op) {
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_PREFIX :
+ case GRN_OP_SUFFIX :
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ case GRN_OP_TERM_EXTRACT :
+ case GRN_OP_REGEXP :
+ break;
+ default :
+ return NULL;
+ break;
+ }
+
+ if (nth_sis > 0) {
+ grn_expr_code *logical_operator = e->codes + i + 3;
+
+ if (logical_operator->op != GRN_OP_AND) {
+ return NULL;
+ }
+ if (logical_operator->nargs != 2) {
+ return NULL;
+ }
+
+ i++;
+ }
+ }
+ n_sis = nth_sis;
+
+ sis = GRN_CALLOC(sizeof(scan_info *) * n_sis);
+ if (!sis) {
+ return NULL;
+ }
+
+ for (i = 0, nth_sis = 0; (uint) i < e->codes_curr; i += 3, nth_sis++) {
+ grn_expr_code *target = e->codes + i;
+ grn_expr_code *constant = e->codes + i + 1;
+ grn_expr_code *operator = e->codes + i + 2;
+ scan_info *si;
+
+ sis[nth_sis] = si = grn_scan_info_open(ctx, i);
+ if (!si) {
+ goto exit;
+ }
+ si->args[si->nargs++] = target->value;
+ si->args[si->nargs++] = constant->value;
+ si->op = operator->op;
+ si->end = i + 2;
+ si->flags &= ~SCAN_PUSH;
+ if (nth_sis == 0) {
+ si->logical_op = logical_op;
+ } else {
+ si->logical_op = GRN_OP_AND;
+ }
+ {
+ int32_t weight = 0;
+ if (operator->value && operator->value->header.domain == GRN_DB_INT32) {
+ weight = GRN_INT32_VALUE(operator->value);
+ }
+ scan_info_build_match(ctx, si, weight);
+ }
+
+ if (nth_sis > 0) {
+ i++;
+ }
+ }
+
+ *n = n_sis;
+ return sis;
+
+exit :
+ if (n_sis > 0) {
+ for (i = 0; i < n_sis; i++) {
+ scan_info *si = sis[i];
+ if (si) {
+ grn_scan_info_close(ctx, si);
+ }
+ }
+ GRN_FREE(sis);
+ }
+
+ return NULL;
+}
+
+static scan_info **
+grn_scan_info_build_simple(grn_ctx *ctx, grn_obj *expr, int *n,
+ grn_operator logical_op, grn_bool record_exist)
+{
+ grn_expr *e = (grn_expr *)expr;
+
+ if (e->codes_curr == 1) {
+ return grn_scan_info_build_simple_value(ctx,
+ expr,
+ n,
+ logical_op,
+ record_exist);
+ } else if (e->codes_curr == 3) {
+ return grn_scan_info_build_simple_operation(ctx,
+ expr,
+ n,
+ logical_op,
+ record_exist);
+ } else if (e->codes_curr % 4 == 3) {
+ return grn_scan_info_build_simple_and_operations(ctx,
+ expr,
+ n,
+ logical_op,
+ record_exist);
+ }
+
+ return NULL;
+}
+
+scan_info **
+grn_scan_info_build(grn_ctx *ctx, grn_obj *expr, int *n,
+ grn_operator op, grn_bool record_exist)
+{
+ scan_info **sis;
+
+ sis = grn_scan_info_build_simple(ctx, expr, n, op, record_exist);
+#ifdef GRN_WITH_MRUBY
+ if (!sis) {
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ return NULL;
+ }
+ if (ctx->impl->mrb.state) {
+ return grn_mrb_scan_info_build(ctx, expr, n, op, record_exist);
+ }
+ }
+#endif
+ if (!sis) {
+ sis = grn_scan_info_build_full(ctx, expr, n, op, record_exist);
+ }
+ return sis;
+}
+
+void
+grn_inspect_scan_info_list(grn_ctx *ctx, grn_obj *buffer, scan_info **sis, int n)
+{
+ int i;
+
+ for (i = 0; i < n; i++) {
+ scan_info *si = sis[i];
+
+ grn_text_printf(ctx, buffer, "[%d]\n", i);
+ grn_text_printf(ctx, buffer,
+ " op: <%s>\n",
+ grn_operator_to_string(si->op));
+ grn_text_printf(ctx, buffer,
+ " logical_op: <%s>\n",
+ grn_operator_to_string(si->logical_op));
+
+ if (si->op == GRN_OP_CALL) {
+ int i;
+ for (i = 0; i < si->nargs; i++) {
+ grn_text_printf(ctx, buffer, " args[%d]: <", i);
+ grn_inspect(ctx, buffer, si->args[i]);
+ GRN_TEXT_PUTS(ctx, buffer, ">\n");
+ }
+ } else {
+ GRN_TEXT_PUTS(ctx, buffer, " index: <");
+ grn_inspect(ctx, buffer, &(si->index));
+ GRN_TEXT_PUTS(ctx, buffer, ">\n");
+
+ GRN_TEXT_PUTS(ctx, buffer, " query: <");
+ grn_inspect(ctx, buffer, si->query);
+ GRN_TEXT_PUTS(ctx, buffer, ">\n");
+ }
+
+ grn_text_printf(ctx, buffer,
+ " expr: <%d..%d>\n", si->start, si->end);
+ }
+}
+
+void
+grn_p_scan_info_list(grn_ctx *ctx, scan_info **sis, int n)
+{
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect_scan_info_list(ctx, &inspected, sis, n);
+ printf("%.*s\n",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+}
+
+inline static int32_t
+exec_result_to_score(grn_ctx *ctx, grn_obj *result, grn_obj *score_buffer)
+{
+ if (!result) {
+ return 0;
+ }
+
+ switch (result->header.type) {
+ case GRN_VOID :
+ return 0;
+ case GRN_BULK :
+ switch (result->header.domain) {
+ case GRN_DB_BOOL :
+ return GRN_BOOL_VALUE(result) ? 1 : 0;
+ case GRN_DB_INT32 :
+ return GRN_INT32_VALUE(result);
+ default :
+ GRN_BULK_REWIND(score_buffer);
+ if (grn_obj_cast(ctx, result, score_buffer, GRN_FALSE) != GRN_SUCCESS) {
+ return 1;
+ }
+ return GRN_INT32_VALUE(score_buffer);
+ }
+ case GRN_UVECTOR :
+ case GRN_PVECTOR :
+ case GRN_VECTOR :
+ return 1;
+ default :
+ return 1; /* TODO: 1 is reasonable? */
+ }
+}
+
+static void
+grn_table_select_sequential(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
+ grn_obj *v, grn_obj *res, grn_operator op)
+{
+ grn_obj *result;
+ grn_obj score_buffer;
+ int32_t score;
+ grn_id id, *idp;
+ grn_table_cursor *tc;
+ grn_hash_cursor *hc;
+ grn_hash *s = (grn_hash *)res;
+ grn_expr_executor *executor;
+
+ executor = grn_expr_executor_open(ctx, expr);
+ if (!executor) {
+ return;
+ }
+ GRN_INT32_INIT(&score_buffer, 0);
+ switch (op) {
+ case GRN_OP_OR :
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, 0))) {
+ while ((id = grn_table_cursor_next(ctx, tc))) {
+ result = grn_expr_executor_exec(ctx, executor, id);
+ if (ctx->rc) {
+ break;
+ }
+ score = exec_result_to_score(ctx, result, &score_buffer);
+ if (score > 0) {
+ grn_rset_recinfo *ri;
+ if (grn_hash_add(ctx, s, &id, s->key_size, (void **)&ri, NULL)) {
+ grn_table_add_subrec(res, ri, score, (grn_rset_posinfo *)&id, 1);
+ }
+ }
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ break;
+ case GRN_OP_AND :
+ if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) {
+ while (grn_hash_cursor_next(ctx, hc)) {
+ grn_hash_cursor_get_key(ctx, hc, (void **) &idp);
+ result = grn_expr_executor_exec(ctx, executor, *idp);
+ if (ctx->rc) {
+ break;
+ }
+ score = exec_result_to_score(ctx, result, &score_buffer);
+ if (score > 0) {
+ grn_rset_recinfo *ri;
+ grn_hash_cursor_get_value(ctx, hc, (void **) &ri);
+ grn_table_add_subrec(res, ri, score, (grn_rset_posinfo *)idp, 1);
+ } else {
+ grn_hash_cursor_delete(ctx, hc, NULL);
+ }
+ }
+ grn_hash_cursor_close(ctx, hc);
+ }
+ break;
+ case GRN_OP_AND_NOT :
+ if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) {
+ while (grn_hash_cursor_next(ctx, hc)) {
+ grn_hash_cursor_get_key(ctx, hc, (void **) &idp);
+ result = grn_expr_executor_exec(ctx, executor, *idp);
+ if (ctx->rc) {
+ break;
+ }
+ score = exec_result_to_score(ctx, result, &score_buffer);
+ if (score > 0) {
+ grn_hash_cursor_delete(ctx, hc, NULL);
+ }
+ }
+ grn_hash_cursor_close(ctx, hc);
+ }
+ break;
+ case GRN_OP_ADJUST :
+ if ((hc = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0, 0, -1, 0))) {
+ while (grn_hash_cursor_next(ctx, hc)) {
+ grn_hash_cursor_get_key(ctx, hc, (void **) &idp);
+ result = grn_expr_executor_exec(ctx, executor, *idp);
+ if (ctx->rc) {
+ break;
+ }
+ score = exec_result_to_score(ctx, result, &score_buffer);
+ if (score > 0) {
+ grn_rset_recinfo *ri;
+ grn_hash_cursor_get_value(ctx, hc, (void **) &ri);
+ grn_table_add_subrec(res, ri, score, (grn_rset_posinfo *)idp, 1);
+ }
+ }
+ grn_hash_cursor_close(ctx, hc);
+ }
+ break;
+ default :
+ break;
+ }
+ GRN_OBJ_FIN(ctx, &score_buffer);
+ grn_expr_executor_close(ctx, executor);
+}
+
+static inline void
+grn_table_select_index_report(grn_ctx *ctx, const char *tag, grn_obj *index)
+{
+ grn_report_index(ctx, "[table][select]", tag, index);
+}
+
+static inline void
+grn_table_select_index_not_used_report(grn_ctx *ctx,
+ const char *tag,
+ grn_obj *index,
+ const char *reason)
+{
+ grn_report_index_not_used(ctx, "[table][select]", tag, index, reason);
+}
+
+static inline grn_bool
+grn_table_select_index_use_sequential_search(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *res,
+ grn_operator logical_op,
+ const char *tag,
+ grn_obj *index)
+{
+ int n_records;
+ int n_filtered_records;
+ double filtered_ratio;
+ grn_obj reason;
+
+ if (logical_op != GRN_OP_AND) {
+ return GRN_FALSE;
+ }
+
+ n_records = grn_table_size(ctx, table);
+ n_filtered_records = grn_table_size(ctx, res);
+ if (n_records == 0) {
+ filtered_ratio = 1.0;
+ } else {
+ filtered_ratio = (double)n_filtered_records / (double)n_records;
+ }
+
+ if (filtered_ratio >= grn_table_select_enough_filtered_ratio) {
+ return GRN_FALSE;
+ }
+
+ if (n_filtered_records > grn_table_select_max_n_enough_filtered_records) {
+ return GRN_FALSE;
+ }
+
+ GRN_TEXT_INIT(&reason, 0);
+ grn_text_printf(ctx, &reason,
+ "enough filtered: %.2f%%(%d/%d) < %.2f%% && %d <= %d",
+ filtered_ratio * 100,
+ n_filtered_records,
+ n_records,
+ grn_table_select_enough_filtered_ratio * 100,
+ n_filtered_records,
+ grn_table_select_max_n_enough_filtered_records);
+ GRN_TEXT_PUTC(ctx, &reason, '\0');
+ grn_table_select_index_not_used_report(ctx,
+ tag,
+ index,
+ GRN_TEXT_VALUE(&reason));
+ GRN_OBJ_FIN(ctx, &reason);
+ return GRN_TRUE;
+}
+
+static inline grn_bool
+grn_table_select_index_equal(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ scan_info *si,
+ grn_obj *res)
+{
+ grn_bool processed = GRN_FALSE;
+
+ if (GRN_BULK_VSIZE(si->query) == 0) {
+ /* We can't use index for empty value. */
+ return GRN_FALSE;
+ }
+
+ if (si->flags & SCAN_ACCESSOR) {
+ if (index->header.type == GRN_ACCESSOR && !((grn_accessor *)index)->next) {
+ grn_obj dest;
+ grn_accessor *a = (grn_accessor *)index;
+ grn_posting posting;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ grn_table_select_index_report(ctx, "[equal][accessor][id]", table);
+ GRN_UINT32_INIT(&dest, 0);
+ if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
+ posting.rid = GRN_UINT32_VALUE(&dest);
+ if (posting.rid) {
+ if (posting.rid == grn_table_at(ctx, table, posting.rid)) {
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res,
+ si->logical_op);
+ }
+ }
+ processed = GRN_TRUE;
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
+ GRN_OBJ_FIN(ctx, &dest);
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ grn_table_select_index_report(ctx, "[equal][accessor][key]", table);
+ GRN_OBJ_INIT(&dest, GRN_BULK, 0, table->header.domain);
+ if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
+ if ((posting.rid = grn_table_get(ctx, table,
+ GRN_BULK_HEAD(&dest),
+ GRN_BULK_VSIZE(&dest)))) {
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res,
+ si->logical_op);
+ }
+ processed = GRN_TRUE;
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
+ GRN_OBJ_FIN(ctx, &dest);
+ break;
+ }
+ }
+ } else {
+ const char *tag = "[equal]";
+ grn_obj *domain = grn_ctx_at(ctx, index->header.domain);
+
+ if (domain) {
+ grn_bool optimizable = GRN_FALSE;
+
+ if (domain->header.domain == GRN_DB_SHORT_TEXT) {
+ grn_obj *normalizer = NULL;
+ grn_table_get_info(ctx, domain, NULL, NULL, NULL, &normalizer, NULL);
+ if (normalizer == grn_ctx_get(ctx, "NormalizerAuto", -1)) {
+ optimizable = GRN_TRUE;
+ }
+ } else {
+ optimizable = GRN_TRUE;
+ }
+ if (optimizable &&
+ grn_table_select_index_use_sequential_search(ctx,
+ table,
+ res,
+ si->logical_op,
+ tag,
+ index)) {
+ domain = NULL;
+ }
+ }
+
+ if (domain) {
+ grn_id tid;
+
+ grn_table_select_index_report(ctx, tag, index);
+
+ if (GRN_OBJ_GET_DOMAIN(si->query) == DB_OBJ(domain)->id) {
+ tid = GRN_RECORD_VALUE(si->query);
+ } else {
+ tid = grn_table_get(ctx, domain,
+ GRN_BULK_HEAD(si->query),
+ GRN_BULK_VSIZE(si->query));
+ }
+ if (tid != GRN_ID_NIL) {
+ uint32_t sid;
+ int32_t weight;
+ grn_ii *ii = (grn_ii *)index;
+ grn_ii_cursor *ii_cursor;
+
+ sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
+ weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
+ ii_cursor = grn_ii_cursor_open(ctx, ii, tid,
+ GRN_ID_NIL, GRN_ID_MAX,
+ ii->n_elements, 0);
+ if (ii_cursor) {
+ grn_posting *posting;
+ while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
+ grn_posting new_posting;
+
+ if (!(sid == 0 || posting->sid == sid)) {
+ continue;
+ }
+
+ if (si->position.specified) {
+ while ((posting = grn_ii_cursor_next_pos(ctx, ii_cursor))) {
+ if ((int) posting->pos == si->position.start) {
+ break;
+ }
+ }
+ if (!posting) {
+ continue;
+ }
+ }
+
+ new_posting = *posting;
+ new_posting.weight *= weight;
+ grn_ii_posting_add(ctx, &new_posting, (grn_hash *)res,
+ si->logical_op);
+ }
+ grn_ii_cursor_close(ctx, ii_cursor);
+ }
+ }
+ processed = GRN_TRUE;
+ }
+ if (processed) {
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
+ }
+ }
+
+ return processed;
+}
+
+static inline grn_bool
+grn_table_select_index_not_equal(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ scan_info *si,
+ grn_obj *res)
+{
+ grn_bool processed = GRN_FALSE;
+
+ if (GRN_BULK_VSIZE(si->query) == 0) {
+ /* We can't use index for empty value. */
+ return GRN_FALSE;
+ }
+
+ if (si->logical_op != GRN_OP_AND) {
+ /* We can't use index for OR and AND_NOT. */
+ return GRN_FALSE;
+ }
+
+ if (si->flags & SCAN_ACCESSOR) {
+ if (index->header.type == GRN_ACCESSOR && !((grn_accessor *)index)->next) {
+ grn_obj dest;
+ grn_accessor *a = (grn_accessor *)index;
+ grn_id id;
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ grn_table_select_index_report(ctx, "[not-equal][accessor][id]", table);
+ GRN_UINT32_INIT(&dest, 0);
+ if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
+ id = GRN_UINT32_VALUE(&dest);
+ if (id != GRN_ID_NIL) {
+ if (id == grn_table_at(ctx, table, id)) {
+ grn_hash_delete(ctx, (grn_hash *)res, &id, sizeof(grn_id), NULL);
+ }
+ }
+ processed = GRN_TRUE;
+ }
+ GRN_OBJ_FIN(ctx, &dest);
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ grn_table_select_index_report(ctx, "[not-equal][accessor][key]", table);
+ GRN_OBJ_INIT(&dest, GRN_BULK, 0, table->header.domain);
+ if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
+ id = grn_table_get(ctx, table,
+ GRN_BULK_HEAD(&dest),
+ GRN_BULK_VSIZE(&dest));
+ if (id != GRN_ID_NIL) {
+ grn_hash_delete(ctx, (grn_hash *)res, &id, sizeof(grn_id), NULL);
+ }
+ processed = GRN_TRUE;
+ }
+ GRN_OBJ_FIN(ctx, &dest);
+ break;
+ }
+ }
+ } else {
+ grn_obj *domain = grn_ctx_at(ctx, index->header.domain);
+ if (domain) {
+ grn_id tid;
+ if (GRN_OBJ_GET_DOMAIN(si->query) == DB_OBJ(domain)->id) {
+ tid = GRN_RECORD_VALUE(si->query);
+ } else {
+ tid = grn_table_get(ctx, domain,
+ GRN_BULK_HEAD(si->query),
+ GRN_BULK_VSIZE(si->query));
+ }
+ if (tid == GRN_ID_NIL) {
+ processed = GRN_TRUE;
+ } else {
+ uint32_t sid;
+ int32_t weight;
+ grn_ii *ii = (grn_ii *)index;
+ grn_ii_cursor *ii_cursor;
+
+ grn_table_select_index_report(ctx, "[not-equal]", index);
+
+ sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
+ weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
+ ii_cursor = grn_ii_cursor_open(ctx, ii, tid,
+ GRN_ID_NIL, GRN_ID_MAX,
+ ii->n_elements, 0);
+ if (ii_cursor) {
+ grn_posting *posting;
+ while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
+ if (!(sid == 0 || posting->sid == sid)) {
+ continue;
+ }
+
+ if (si->position.specified) {
+ while ((posting = grn_ii_cursor_next_pos(ctx, ii_cursor))) {
+ if ((int) posting->pos == si->position.start) {
+ break;
+ }
+ }
+ if (!posting) {
+ continue;
+ }
+ }
+
+ grn_hash_delete(ctx, (grn_hash *)res,
+ &(posting->rid), sizeof(grn_id),
+ NULL);
+ }
+ grn_ii_cursor_close(ctx, ii_cursor);
+ processed = GRN_TRUE;
+ }
+ }
+ }
+ }
+
+ return processed;
+}
+
+static grn_bool
+grn_table_select_index_prefix(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ scan_info *si,
+ grn_obj *res)
+{
+ grn_bool processed = GRN_FALSE;
+ if (si->flags & SCAN_ACCESSOR) {
+ if (index->header.type == GRN_ACCESSOR &&
+ !((grn_accessor *)index)->next) {
+ grn_obj dest;
+ grn_accessor *a = (grn_accessor *)index;
+ grn_posting posting;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ if (si->op == GRN_OP_SUFFIX) {
+ grn_table_select_index_report(ctx,
+ "[suffix][accessor][key]", table);
+ } else {
+ grn_table_select_index_report(ctx,
+ "[prefix][accessor][key]", table);
+ }
+ GRN_OBJ_INIT(&dest, GRN_BULK, 0, table->header.domain);
+ if (!grn_obj_cast(ctx, si->query, &dest, GRN_FALSE)) {
+ grn_hash *pres;
+ if ((pres = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY))) {
+ grn_id *key;
+ grn_table_search(ctx, table,
+ GRN_BULK_HEAD(&dest), GRN_BULK_VSIZE(&dest),
+ si->op, (grn_obj *)pres, GRN_OP_OR);
+ GRN_HASH_EACH(ctx, pres, id, &key, NULL, NULL, {
+ posting.rid = *key;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res,
+ si->logical_op);
+ });
+ grn_hash_close(ctx, pres);
+ }
+ processed = GRN_TRUE;
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
+ GRN_OBJ_FIN(ctx, &dest);
+ }
+ }
+ } else {
+ grn_obj **indexes = &GRN_PTR_VALUE(&si->index);
+ int i, n_indexes = GRN_BULK_VSIZE(&si->index)/sizeof(grn_obj *);
+ for (i = 0; i < n_indexes; i++) {
+ grn_obj *index = indexes[i];
+ grn_obj *lexicon = grn_ctx_at(ctx, index->header.domain);
+ if (lexicon) {
+ grn_hash *keys;
+ if ((keys = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY))) {
+ grn_id *key;
+ if (si->op == GRN_OP_SUFFIX) {
+ grn_table_select_index_report(ctx, "[suffix]", index);
+ } else {
+ grn_table_select_index_report(ctx, "[prefix]", index);
+ }
+ grn_table_search(ctx, lexicon,
+ GRN_BULK_HEAD(si->query),
+ GRN_BULK_VSIZE(si->query),
+ si->op, (grn_obj *)keys, GRN_OP_OR);
+ grn_obj_unlink(ctx, lexicon);
+ GRN_HASH_EACH(ctx, keys, id, &key, NULL, NULL, {
+ grn_ii_at(ctx, (grn_ii *)index, *key, (grn_hash *)res, si->logical_op);
+ });
+ grn_hash_close(ctx, keys);
+ }
+ grn_obj_unlink(ctx, lexicon);
+ }
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, si->logical_op);
+ processed = GRN_TRUE;
+ }
+ return processed;
+}
+
+static grn_bool
+grn_table_select_index_suffix(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ scan_info *si,
+ grn_obj *res)
+{
+ grn_obj *domain;
+ if (si->flags & SCAN_ACCESSOR) {
+ domain = table;
+ } else {
+ domain = grn_ctx_at(ctx, index->header.domain);
+ }
+ if (domain->header.type != GRN_TABLE_PAT_KEY) {
+ return GRN_FALSE;
+ }
+ if (!(domain->header.flags & GRN_OBJ_KEY_WITH_SIS)) {
+ return GRN_FALSE;
+ }
+ return grn_table_select_index_prefix(ctx, table, index, si, res);
+}
+
+static inline grn_bool
+grn_table_select_index_match(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ scan_info *si,
+ grn_obj *res,
+ grn_id *min_id)
+{
+ grn_obj wv, **ip = &GRN_PTR_VALUE(&si->index);
+ int j;
+ int n_indexes = GRN_BULK_VSIZE(&si->index)/sizeof(grn_obj *);
+ int32_t *wp = &GRN_INT32_VALUE(&si->wv);
+ grn_search_optarg optarg;
+ grn_bool minimum_min_id_is_set = GRN_FALSE;
+ grn_id minimum_min_id = GRN_ID_NIL;
+ unsigned int previous_n_hits = grn_table_size(ctx, res);
+
+ GRN_INT32_INIT(&wv, GRN_OBJ_VECTOR);
+ if (si->op == GRN_OP_MATCH) {
+ optarg.mode = GRN_OP_EXACT;
+ } else {
+ optarg.mode = si->op;
+ }
+ optarg.max_interval = 0;
+ optarg.similarity_threshold = 0;
+ switch (si->op) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ optarg.max_interval = si->max_interval;
+ break;
+ case GRN_OP_SIMILAR :
+ optarg.similarity_threshold = si->similarity_threshold;
+ break;
+ default :
+ break;
+ }
+ optarg.weight_vector = (int *)GRN_BULK_HEAD(&wv);
+ /* optarg.vector_size = GRN_BULK_VSIZE(&si->wv); */
+ optarg.vector_size = 1;
+ optarg.proc = NULL;
+ optarg.max_size = 0;
+ optarg.match_info.flags |= GRN_MATCH_INFO_GET_MIN_RECORD_ID;
+ ctx->flags |= GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
+ for (j = 0; j < n_indexes; j++, ip++, wp += 2) {
+ uint32_t sid = (uint32_t) wp[0];
+ int32_t weight = wp[1];
+ if (grn_table_select_and_min_skip_enable) {
+ optarg.match_info.min = *min_id;
+ } else {
+ optarg.match_info.min = GRN_ID_NIL;
+ }
+ if (sid) {
+ int weight_index = sid - 1;
+ int current_vector_size;
+ current_vector_size = GRN_BULK_VSIZE(&wv)/sizeof(int32_t);
+ if (weight_index < current_vector_size) {
+ ((int *)GRN_BULK_HEAD(&wv))[weight_index] = weight;
+ } else {
+ GRN_INT32_SET_AT(ctx, &wv, weight_index, weight);
+ }
+ optarg.weight_vector = &GRN_INT32_VALUE(&wv);
+ optarg.vector_size = GRN_BULK_VSIZE(&wv)/sizeof(int32_t);
+ } else {
+ optarg.weight_vector = NULL;
+ optarg.vector_size = weight;
+ }
+ optarg.scorer = GRN_PTR_VALUE_AT(&(si->scorers), j);
+ optarg.scorer_args_expr =
+ GRN_PTR_VALUE_AT(&(si->scorer_args_exprs), j);
+ optarg.scorer_args_expr_offset =
+ GRN_UINT32_VALUE_AT(&(si->scorer_args_expr_offsets), j);
+ if (j < n_indexes - 1) {
+ if (sid && ip[0] == ip[1]) { continue; }
+ } else {
+ ctx->flags &= ~GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
+ }
+ grn_obj_search(ctx, ip[0], si->query, res, si->logical_op, &optarg);
+ if (optarg.weight_vector) {
+ int i;
+ for (i = 0; i < optarg.vector_size; i++) {
+ optarg.weight_vector[i] = 0;
+ }
+ }
+ GRN_BULK_REWIND(&wv);
+ if (!minimum_min_id_is_set ||
+ optarg.match_info.min < minimum_min_id) {
+ minimum_min_id_is_set = GRN_TRUE;
+ minimum_min_id = optarg.match_info.min;
+ }
+ }
+ if ((si->logical_op == GRN_OP_AND) ||
+ (si->logical_op == GRN_OP_OR && previous_n_hits == 0)) {
+ *min_id = minimum_min_id;
+ } else {
+ *min_id = GRN_ID_NIL;
+ }
+ GRN_OBJ_FIN(ctx, &wv);
+
+ return GRN_TRUE;
+}
+
+static inline grn_bool
+grn_table_select_index_call_selector(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ scan_info *si,
+ grn_obj *selector,
+ grn_obj *res)
+{
+ grn_bool processed = GRN_FALSE;
+ grn_proc *proc = (grn_proc *)selector;
+ grn_rc rc;
+
+ if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ char tag[GRN_TABLE_MAX_KEY_SIZE];
+ name_size = grn_obj_name(ctx,
+ (grn_obj *)selector,
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ grn_snprintf(tag, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
+ "[selector][%.*s]",
+ name_size, name);
+ grn_table_select_index_report(ctx, tag, index);
+ }
+
+ if (index && index->header.type == GRN_ACCESSOR) {
+ grn_operator selector_op;
+ grn_obj *accessor = index;
+ grn_accessor *a = (grn_accessor *)accessor;
+
+ selector_op = grn_proc_get_selector_operator(ctx, selector);
+ if (a->next) {
+ unsigned int accessor_deep = 0;
+ grn_obj *base_table = NULL;
+ grn_obj *base_index = NULL;
+ grn_obj *base_res = NULL;
+
+ for (; a; a = a->next) {
+ if (a->next) {
+ accessor_deep++;
+ } else {
+ grn_index_datum index_data;
+ unsigned int n_index_datum;
+
+ if (grn_obj_is_table(ctx, a->obj)) {
+ base_table = a->obj;
+ } else {
+ base_table = grn_ctx_at(ctx, a->obj->header.domain);
+ }
+ n_index_datum = grn_column_find_index_data(ctx,
+ a->obj,
+ selector_op,
+ &index_data,
+ 1);
+ if (n_index_datum > 0) {
+ base_index = index_data.index;
+ }
+ base_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ base_table, NULL);
+ }
+ }
+ rc = proc->callbacks.function.selector(ctx,
+ base_table,
+ base_index,
+ si->nargs,
+ si->args,
+ base_res,
+ GRN_OP_OR);
+ if (rc == GRN_SUCCESS) {
+ grn_accessor_resolve(ctx,
+ accessor,
+ accessor_deep,
+ base_res,
+ res,
+ si->logical_op);
+ }
+ grn_obj_close(ctx, base_res);
+ } else {
+ grn_index_datum index_data;
+ unsigned int n_index_datum;
+ grn_obj *target_index = NULL;
+
+ n_index_datum = grn_column_find_index_data(ctx,
+ a->obj,
+ selector_op,
+ &index_data,
+ 1);
+ if (n_index_datum > 0) {
+ target_index = index_data.index;
+ }
+ rc = proc->callbacks.function.selector(ctx,
+ table,
+ target_index,
+ si->nargs,
+ si->args,
+ res,
+ si->logical_op);
+ }
+ } else {
+ rc = proc->callbacks.function.selector(ctx,
+ table,
+ index,
+ si->nargs,
+ si->args,
+ res,
+ si->logical_op);
+ }
+
+ if (rc) {
+ /* TODO: report error */
+ } else {
+ processed = GRN_TRUE;
+ }
+
+ return processed;
+}
+
+static inline grn_bool
+grn_table_select_index_range_key(grn_ctx *ctx,
+ grn_obj *table,
+ scan_info *si,
+ grn_operator logical_op,
+ grn_obj *res)
+{
+ const char *tag = "[range][key]";
+ grn_bool processed = GRN_FALSE;
+ grn_obj key;
+
+ if (grn_table_select_index_use_sequential_search(ctx,
+ table,
+ res,
+ logical_op,
+ tag,
+ table)) {
+ return GRN_FALSE;
+ }
+
+ GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);
+ if (grn_obj_cast(ctx, si->query, &key, GRN_FALSE) == GRN_SUCCESS) {
+ grn_table_cursor *cursor;
+ const void *min = NULL, *max = NULL;
+ unsigned int min_size = 0, max_size = 0;
+ int offset = 0;
+ int limit = -1;
+ int flags = GRN_CURSOR_ASCENDING;
+
+ grn_table_select_index_report(ctx, tag, table);
+
+ switch (si->op) {
+ case GRN_OP_LESS :
+ flags |= GRN_CURSOR_LT;
+ max = GRN_BULK_HEAD(&key);
+ max_size = GRN_BULK_VSIZE(&key);
+ break;
+ case GRN_OP_GREATER :
+ flags |= GRN_CURSOR_GT;
+ min = GRN_BULK_HEAD(&key);
+ min_size = GRN_BULK_VSIZE(&key);
+ break;
+ case GRN_OP_LESS_EQUAL :
+ flags |= GRN_CURSOR_LE;
+ max = GRN_BULK_HEAD(&key);
+ max_size = GRN_BULK_VSIZE(&key);
+ break;
+ case GRN_OP_GREATER_EQUAL :
+ flags |= GRN_CURSOR_GE;
+ min = GRN_BULK_HEAD(&key);
+ min_size = GRN_BULK_VSIZE(&key);
+ break;
+ default :
+ break;
+ }
+ cursor = grn_table_cursor_open(ctx, table,
+ min, min_size, max, max_size,
+ offset, limit, flags);
+ if (cursor) {
+ uint32_t sid;
+ int32_t weight;
+
+ sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
+ weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
+
+ if (sid == 0) {
+ grn_posting posting = {0};
+
+ posting.weight = weight - 1;
+ while ((posting.rid = grn_table_cursor_next(ctx, cursor))) {
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, logical_op);
+ }
+ }
+ processed = GRN_TRUE;
+ grn_table_cursor_close(ctx, cursor);
+ }
+
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, logical_op);
+ }
+ GRN_OBJ_FIN(ctx, &key);
+
+ return processed;
+}
+
+static inline grn_bool
+grn_table_select_index_range_column(grn_ctx *ctx, grn_obj *table,
+ grn_obj *index,
+ scan_info *si, grn_operator logical_op,
+ grn_obj *res)
+{
+ const char *tag = "[range]";
+ grn_bool processed = GRN_FALSE;
+ grn_obj *index_table;
+ grn_obj range;
+
+ index_table = grn_ctx_at(ctx, index->header.domain);
+ if (!index_table) {
+ return GRN_FALSE;
+ }
+
+ if (grn_table_select_index_use_sequential_search(ctx,
+ table,
+ res,
+ logical_op,
+ tag,
+ index_table)) {
+ grn_obj_unlink(ctx, index_table);
+ return GRN_FALSE;
+ }
+
+ GRN_OBJ_INIT(&range, GRN_BULK, 0, index_table->header.domain);
+ if (grn_obj_cast(ctx, si->query, &range, GRN_FALSE) == GRN_SUCCESS) {
+ grn_table_cursor *cursor;
+ const void *min = NULL, *max = NULL;
+ unsigned int min_size = 0, max_size = 0;
+ int offset = 0;
+ int limit = -1;
+ int flags = GRN_CURSOR_ASCENDING;
+
+ grn_table_select_index_report(ctx, "[range]", index);
+
+ switch (si->op) {
+ case GRN_OP_LESS :
+ flags |= GRN_CURSOR_LT;
+ max = GRN_BULK_HEAD(&range);
+ max_size = GRN_BULK_VSIZE(&range);
+ break;
+ case GRN_OP_GREATER :
+ flags |= GRN_CURSOR_GT;
+ min = GRN_BULK_HEAD(&range);
+ min_size = GRN_BULK_VSIZE(&range);
+ break;
+ case GRN_OP_LESS_EQUAL :
+ flags |= GRN_CURSOR_LE;
+ max = GRN_BULK_HEAD(&range);
+ max_size = GRN_BULK_VSIZE(&range);
+ break;
+ case GRN_OP_GREATER_EQUAL :
+ flags |= GRN_CURSOR_GE;
+ min = GRN_BULK_HEAD(&range);
+ min_size = GRN_BULK_VSIZE(&range);
+ break;
+ default :
+ break;
+ }
+ cursor = grn_table_cursor_open(ctx, index_table,
+ min, min_size, max, max_size,
+ offset, limit, flags);
+ if (cursor) {
+ grn_id tid;
+ uint32_t sid;
+ int32_t weight;
+ grn_ii *ii = (grn_ii *)index;
+
+ sid = GRN_UINT32_VALUE_AT(&(si->wv), 0);
+ weight = GRN_INT32_VALUE_AT(&(si->wv), 1);
+ while ((tid = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_ii_cursor *ii_cursor;
+
+ ii_cursor = grn_ii_cursor_open(ctx, ii, tid,
+ GRN_ID_NIL, GRN_ID_MAX,
+ ii->n_elements, 0);
+ if (ii_cursor) {
+ grn_posting *posting;
+ while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
+ grn_posting new_posting;
+
+ if (!(sid == 0 || posting->sid == sid)) {
+ continue;
+ }
+
+ if (si->position.specified) {
+ while ((posting = grn_ii_cursor_next_pos(ctx, ii_cursor))) {
+ if ((int) posting->pos == si->position.start) {
+ break;
+ }
+ }
+ if (!posting) {
+ continue;
+ }
+ }
+
+ new_posting = *posting;
+ new_posting.weight *= weight;
+ grn_ii_posting_add(ctx, &new_posting, (grn_hash *)res, logical_op);
+ }
+ }
+ grn_ii_cursor_close(ctx, ii_cursor);
+ }
+ processed = GRN_TRUE;
+ grn_table_cursor_close(ctx, cursor);
+ }
+
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, logical_op);
+ }
+ GRN_OBJ_FIN(ctx, &range);
+
+ grn_obj_unlink(ctx, index_table);
+
+ return processed;
+}
+
+static inline grn_bool
+grn_table_select_index_range_accessor(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *accessor,
+ scan_info *si,
+ grn_operator op,
+ grn_obj *res)
+{
+ grn_rc rc;
+ grn_accessor *a;
+ grn_obj *last_obj = NULL;
+ int n_accessors;
+ grn_bool have_resolver = GRN_FALSE;
+ grn_obj *base_res = NULL;
+
+ for (a = (grn_accessor *)accessor; a; a = a->next) {
+ if (!a->next) {
+ last_obj = a->obj;
+ }
+ }
+ n_accessors = 0;
+ for (a = (grn_accessor *)accessor; a; a = a->next) {
+ n_accessors++;
+ if (GRN_OBJ_INDEX_COLUMNP(a->obj) ||
+ grn_obj_is_table(ctx, a->obj)) {
+ have_resolver = GRN_TRUE;
+ break;
+ }
+ }
+
+ {
+ grn_obj *index;
+ grn_obj *range;
+
+ if (grn_obj_is_table(ctx, last_obj)) {
+ index = last_obj;
+ range = last_obj;
+ base_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ range,
+ NULL);
+ if (!base_res) {
+ return GRN_FALSE;
+ }
+ if (!grn_table_select_index_range_key(ctx, last_obj, si, GRN_OP_OR,
+ base_res)) {
+ grn_obj_unlink(ctx, base_res);
+ return GRN_FALSE;
+ }
+ } else {
+ if (grn_column_index(ctx, last_obj, si->op, &index, 1, NULL) == 0) {
+ return GRN_FALSE;
+ }
+
+ range = grn_ctx_at(ctx, DB_OBJ(index)->range);
+ base_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ range,
+ NULL);
+ if (!base_res) {
+ return GRN_FALSE;
+ }
+ if (!grn_table_select_index_range_column(ctx, table, index, si, GRN_OP_OR,
+ base_res)) {
+ grn_obj_unlink(ctx, base_res);
+ return GRN_FALSE;
+ }
+ }
+ grn_table_select_index_report(ctx, "[range][accessor]", index);
+ }
+
+ if (n_accessors == 1 && have_resolver) {
+ rc = grn_accessor_resolve(ctx, accessor, 1, base_res, res, op);
+ } else {
+ rc = grn_accessor_resolve(ctx, accessor, n_accessors - 1, base_res, res, op);
+ }
+ grn_obj_unlink(ctx, base_res);
+
+ return rc == GRN_SUCCESS;
+}
+
+static inline grn_bool
+grn_table_select_index_range(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ scan_info *si, grn_obj *res)
+{
+ if (si->flags & SCAN_ACCESSOR) {
+ switch (index->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ /* table == index */
+ return grn_table_select_index_range_key(ctx, table, si,
+ si->logical_op, res);
+ case GRN_ACCESSOR :
+ return grn_table_select_index_range_accessor(ctx, table, index, si,
+ si->logical_op, res);
+ default :
+ return GRN_FALSE;
+ }
+ } else {
+ return grn_table_select_index_range_column(ctx, table, index, si,
+ si->logical_op, res);
+ }
+}
+
+static inline grn_bool
+grn_table_select_index(grn_ctx *ctx, grn_obj *table, scan_info *si,
+ grn_obj *res, grn_id *min_id)
+{
+ grn_bool processed = GRN_FALSE;
+ if (!si->query) {
+ if (si->op != GRN_OP_CALL || !grn_obj_is_selector_proc(ctx, si->args[0])) {
+ return processed;
+ }
+ }
+ if (GRN_BULK_VSIZE(&si->index)) {
+ grn_obj *index = GRN_PTR_VALUE(&si->index);
+ switch (si->op) {
+ case GRN_OP_EQUAL :
+ processed = grn_table_select_index_equal(ctx, table, index, si, res);
+ break;
+ case GRN_OP_NOT_EQUAL :
+ processed = grn_table_select_index_not_equal(ctx, table, index, si, res);
+ break;
+ case GRN_OP_PREFIX :
+ processed = grn_table_select_index_prefix(ctx, table, index, si, res);
+ break;
+ case GRN_OP_SUFFIX :
+ processed = grn_table_select_index_suffix(ctx, table, index, si, res);
+ break;
+ case GRN_OP_MATCH :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ case GRN_OP_SIMILAR :
+ case GRN_OP_REGEXP :
+ processed = grn_table_select_index_match(ctx,
+ table,
+ index,
+ si,
+ res,
+ min_id);
+ break;
+ case GRN_OP_TERM_EXTRACT :
+ if (si->flags & SCAN_ACCESSOR) {
+ if (index->header.type == GRN_ACCESSOR &&
+ !((grn_accessor *)index)->next) {
+ grn_accessor *a = (grn_accessor *)index;
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_KEY :
+ grn_table_select_index_report(ctx, "[term-extract][accessor][key]",
+ table);
+ grn_table_search(ctx, table,
+ GRN_TEXT_VALUE(si->query), GRN_TEXT_LEN(si->query),
+ GRN_OP_TERM_EXTRACT, res, si->logical_op);
+ processed = GRN_TRUE;
+ break;
+ }
+ }
+ }
+ break;
+ case GRN_OP_CALL :
+ if (grn_obj_is_selector_proc(ctx, si->args[0])) {
+ processed = grn_table_select_index_call_selector(ctx,
+ table,
+ index,
+ si,
+ si->args[0],
+ res);
+ }
+ break;
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ processed = grn_table_select_index_range(ctx, table, index, si, res);
+ break;
+ default :
+ /* todo : implement */
+ /* todo : handle SCAN_PRE_CONST */
+ break;
+ }
+ } else {
+ switch (si->op) {
+ case GRN_OP_CALL :
+ if (grn_obj_is_selector_proc(ctx, si->args[0])) {
+ grn_rc rc;
+ grn_proc *proc = (grn_proc *)(si->args[0]);
+ if (grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ char proc_name[GRN_TABLE_MAX_KEY_SIZE];
+ int proc_name_size;
+ char tag[GRN_TABLE_MAX_KEY_SIZE];
+ proc_name_size = grn_obj_name(ctx, (grn_obj *)proc,
+ proc_name, GRN_TABLE_MAX_KEY_SIZE);
+ proc_name[proc_name_size] = '\0';
+ grn_snprintf(tag, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
+ "[selector][no-index][%s]", proc_name);
+ grn_table_select_index_report(ctx, tag, table);
+ }
+ rc = proc->callbacks.function.selector(ctx,
+ table,
+ NULL,
+ si->nargs,
+ si->args,
+ res,
+ si->logical_op);
+ if (rc) {
+ if (rc == GRN_FUNCTION_NOT_IMPLEMENTED) {
+ ERRCLR(ctx);
+ } else {
+ /* TODO: report error */
+ }
+ } else {
+ processed = GRN_TRUE;
+ }
+ }
+ default :
+ break;
+ }
+ }
+ return processed;
+}
+
+grn_obj *
+grn_table_select(grn_ctx *ctx, grn_obj *table, grn_obj *expr,
+ grn_obj *res, grn_operator op)
+{
+ grn_obj *v;
+ unsigned int res_size;
+ grn_bool res_created = GRN_FALSE;
+ if (res) {
+ if (res->header.type != GRN_TABLE_HASH_KEY ||
+ (res->header.domain != DB_OBJ(table)->id)) {
+ ERR(GRN_INVALID_ARGUMENT, "hash table required");
+ return NULL;
+ }
+ } else {
+ if (!(res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, table, NULL))) {
+ return NULL;
+ }
+ res_created = GRN_TRUE;
+ }
+ if (!(v = grn_expr_get_var_by_offset(ctx, expr, 0))) {
+ ERR(GRN_INVALID_ARGUMENT, "at least one variable must be defined");
+ return NULL;
+ }
+ GRN_API_ENTER;
+ res_size = GRN_HASH_SIZE((grn_hash *)res);
+ if (op == GRN_OP_OR || res_size) {
+ int i;
+ grn_scanner *scanner;
+ scanner = grn_scanner_open(ctx, expr, op, res_size > 0);
+ if (scanner) {
+ grn_obj res_stack;
+ grn_expr *e = (grn_expr *)scanner->expr;
+ grn_expr_code *codes = e->codes;
+ uint32_t codes_curr = e->codes_curr;
+ grn_id min_id = GRN_ID_NIL;
+ v = grn_expr_get_var_by_offset(ctx, (grn_obj *)e, 0);
+ GRN_PTR_INIT(&res_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ for (i = 0; (uint) i < scanner->n_sis; i++) {
+ scan_info *si = scanner->sis[i];
+ if (si->flags & SCAN_POP) {
+ grn_obj *res_;
+ GRN_PTR_POP(&res_stack, res_);
+ grn_table_setoperation(ctx, res_, res, res_, si->logical_op);
+ grn_obj_close(ctx, res);
+ res = res_;
+ min_id = GRN_ID_NIL;
+ } else {
+ grn_bool processed = GRN_FALSE;
+ if (si->flags & SCAN_PUSH) {
+ grn_obj *res_ = NULL;
+ res_ = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, table, NULL);
+ if (!res_) {
+ break;
+ }
+ GRN_PTR_PUT(ctx, &res_stack, res);
+ res = res_;
+ min_id = GRN_ID_NIL;
+ }
+ if (si->logical_op != GRN_OP_AND) {
+ min_id = GRN_ID_NIL;
+ }
+ processed = grn_table_select_index(ctx, table, si, res, &min_id);
+ if (!processed) {
+ if (ctx->rc) { break; }
+ e->codes = codes + si->start;
+ e->codes_curr = si->end - si->start + 1;
+ grn_table_select_sequential(ctx, table, (grn_obj *)e, v,
+ res, si->logical_op);
+ min_id = GRN_ID_NIL;
+ }
+ }
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "filter(%d)", grn_table_size(ctx, res));
+ if (ctx->rc) {
+ if (res_created) {
+ grn_obj_close(ctx, res);
+ }
+ res = NULL;
+ break;
+ }
+ }
+
+ i = 0;
+ if (!res_created) { i++; }
+ for (; (uint) i < GRN_BULK_VSIZE(&res_stack) / sizeof(grn_obj *); i++) {
+ grn_obj *stacked_res;
+ stacked_res = *((grn_obj **)GRN_BULK_HEAD(&res_stack) + i);
+ grn_obj_close(ctx, stacked_res);
+ }
+ GRN_OBJ_FIN(ctx, &res_stack);
+ e->codes = codes;
+ e->codes_curr = codes_curr;
+
+ grn_scanner_close(ctx, scanner);
+ } else {
+ if (!ctx->rc) {
+ grn_table_select_sequential(ctx, table, expr, v, res, op);
+ if (ctx->rc) {
+ if (res_created) {
+ grn_obj_close(ctx, res);
+ }
+ res = NULL;
+ }
+ }
+ }
+ }
+ GRN_API_RETURN(res);
+}
+
+/* grn_expr_parse */
+
+grn_obj *
+grn_ptr_value_at(grn_obj *obj, int offset)
+{
+ int size = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
+ if (offset < 0) { offset = size + offset; }
+ return (0 <= offset && offset < size)
+ ? (((grn_obj **)GRN_BULK_HEAD(obj))[offset])
+ : NULL;
+}
+
+int32_t
+grn_int32_value_at(grn_obj *obj, int offset)
+{
+ int size = GRN_BULK_VSIZE(obj) / sizeof(int32_t);
+ if (offset < 0) { offset = size + offset; }
+ return (0 <= offset && offset < size)
+ ? (((int32_t *)GRN_BULK_HEAD(obj))[offset])
+ : 0;
+}
+
+/* grn_expr_create_from_str */
+
+#include "grn_snip.h"
+
+typedef struct {
+ grn_ctx *ctx;
+ grn_obj *e;
+ grn_obj *v;
+ const char *str;
+ const char *cur;
+ const char *str_end;
+ grn_obj *table;
+ grn_obj *default_column;
+ grn_obj buf;
+ grn_obj token_stack;
+ grn_obj column_stack;
+ grn_obj op_stack;
+ grn_obj mode_stack;
+ grn_obj max_interval_stack;
+ grn_obj similarity_threshold_stack;
+ grn_obj weight_stack;
+ grn_operator default_op;
+ grn_select_optarg opt;
+ grn_operator default_mode;
+ grn_expr_flags flags;
+ grn_expr_flags default_flags;
+ int escalation_threshold;
+ int escalation_decaystep;
+ int weight_offset;
+ grn_hash *weight_set;
+ snip_cond *snip_conds;
+ grn_hash *object_literal;
+ int paren_depth;
+ struct {
+ const char *string;
+ size_t string_length;
+ int token;
+ int weight;
+ } pending_token;
+} efs_info;
+
+typedef struct {
+ grn_operator op;
+ int weight;
+} efs_op;
+
+inline static void
+skip_space(grn_ctx *ctx, efs_info *q)
+{
+ unsigned int len;
+ while (q->cur < q->str_end && grn_isspace(q->cur, ctx->encoding)) {
+ /* null check and length check */
+ if (!(len = grn_charlen(ctx, q->cur, q->str_end))) {
+ q->cur = q->str_end;
+ break;
+ }
+ q->cur += len;
+ }
+}
+
+static grn_bool
+parse_query_op(efs_info *q, efs_op *op, grn_operator *mode, int *option)
+{
+ grn_bool found = GRN_TRUE;
+ const char *start, *end = q->cur;
+ switch (*end) {
+ case 'S' :
+ *mode = GRN_OP_SIMILAR;
+ start = ++end;
+ *option = grn_atoi(start, q->str_end, (const char **)&end);
+ if (start == end) { *option = DEFAULT_SIMILARITY_THRESHOLD; }
+ q->cur = end;
+ break;
+ case 'N' :
+ *mode = GRN_OP_NEAR;
+ start = ++end;
+ *option = grn_atoi(start, q->str_end, (const char **)&end);
+ if (start == end) { *option = DEFAULT_MAX_INTERVAL; }
+ q->cur = end;
+ break;
+ case 'n' :
+ *mode = GRN_OP_NEAR2;
+ start = ++end;
+ *option = grn_atoi(start, q->str_end, (const char **)&end);
+ if (start == end) { *option = DEFAULT_MAX_INTERVAL; }
+ q->cur = end;
+ break;
+ case 'T' :
+ *mode = GRN_OP_TERM_EXTRACT;
+ start = ++end;
+ *option = grn_atoi(start, q->str_end, (const char **)&end);
+ if (start == end) { *option = DEFAULT_TERM_EXTRACT_POLICY; }
+ q->cur = end;
+ break;
+ case 'X' : /* force exact mode */
+ op->op = GRN_OP_AND;
+ *mode = GRN_OP_EXACT;
+ *option = 0;
+ start = ++end;
+ q->cur = end;
+ break;
+ default :
+ found = GRN_FALSE;
+ break;
+ }
+ return found;
+}
+
+#define DISABLE_UNUSED_CODE 1
+#ifndef DISABLE_UNUSED_CODE
+static const char *
+get_weight_vector(grn_ctx *ctx, efs_info *query, const char *source)
+{
+ const char *p;
+
+ if (!query->opt.weight_vector &&
+ !query->weight_set &&
+ !(query->opt.weight_vector = GRN_CALLOC(sizeof(int) * DEFAULT_WEIGHT_VECTOR_SIZE))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "get_weight_vector malloc fail");
+ return source;
+ }
+ for (p = source; p < query->str_end; ) {
+ unsigned int key;
+ int value;
+
+ /* key, key is not zero */
+ key = grn_atoui(p, query->str_end, &p);
+ if (!key || key > GRN_ID_MAX) { break; }
+
+ /* value */
+ if (*p == ':') {
+ p++;
+ value = grn_atoi(p, query->str_end, &p);
+ } else {
+ value = 1;
+ }
+
+ if (query->weight_set) {
+ int *pval;
+ if (grn_hash_add(ctx, query->weight_set, &key, sizeof(unsigned int), (void **)&pval, NULL)) {
+ *pval = value;
+ }
+ } else if (key < DEFAULT_WEIGHT_VECTOR_SIZE) {
+ query->opt.weight_vector[key - 1] = value;
+ } else {
+ GRN_FREE(query->opt.weight_vector);
+ query->opt.weight_vector = NULL;
+ if (!(query->weight_set = grn_hash_create(ctx, NULL, sizeof(unsigned int), sizeof(int),
+ 0))) {
+ return source;
+ }
+ p = source; /* reparse */
+ continue;
+ }
+ if (*p != ',') { break; }
+ p++;
+ }
+ return p;
+}
+
+static void
+get_pragma(grn_ctx *ctx, efs_info *q)
+{
+ const char *start, *end = q->cur;
+ while (end < q->str_end && *end == GRN_QUERY_PREFIX) {
+ if (++end >= q->str_end) { break; }
+ switch (*end) {
+ case 'E' :
+ start = ++end;
+ q->escalation_threshold = grn_atoi(start, q->str_end, (const char **)&end);
+ while (end < q->str_end && (('0' <= *end && *end <= '9') || *end == '-')) { end++; }
+ if (*end == ',') {
+ start = ++end;
+ q->escalation_decaystep = grn_atoi(start, q->str_end, (const char **)&end);
+ }
+ q->cur = end;
+ break;
+ case 'D' :
+ start = ++end;
+ while (end < q->str_end && *end != GRN_QUERY_PREFIX && !grn_isspace(end, ctx->encoding)) {
+ end++;
+ }
+ if (end > start) {
+ switch (*start) {
+ case 'O' :
+ q->default_op = GRN_OP_OR;
+ break;
+ case GRN_QUERY_AND :
+ q->default_op = GRN_OP_AND;
+ break;
+ case GRN_QUERY_AND_NOT :
+ q->default_op = GRN_OP_AND_NOT;
+ break;
+ case GRN_QUERY_ADJ_INC :
+ q->default_op = GRN_OP_ADJUST;
+ break;
+ }
+ }
+ q->cur = end;
+ break;
+ case 'W' :
+ start = ++end;
+ end = (char *)get_weight_vector(ctx, q, start);
+ q->cur = end;
+ break;
+ }
+ }
+}
+
+static int
+section_weight_cb(grn_ctx *ctx, grn_hash *r, const void *rid, int sid, void *arg)
+{
+ int *w;
+ grn_hash *s = (grn_hash *)arg;
+ if (s && grn_hash_get(ctx, s, &sid, sizeof(grn_id), (void **)&w)) {
+ return *w;
+ } else {
+ return 0;
+ }
+}
+#endif
+
+#include "grn_ecmascript.h"
+#include "grn_ecmascript.c"
+
+static grn_rc
+grn_expr_parser_open(grn_ctx *ctx)
+{
+ if (!ctx->impl->parser) {
+ ctx->impl->parser = grn_expr_parserAlloc(malloc);
+ }
+ return ctx->rc;
+}
+
+#define PARSE(token) grn_expr_parser(ctx->impl->parser, (token), 0, q)
+
+static void
+parse_query_accept_string(grn_ctx *ctx, efs_info *efsi,
+ const char *str, unsigned int str_size)
+{
+ grn_obj *column, *token;
+ grn_operator mode;
+ int32_t weight;
+
+ GRN_PTR_PUT(ctx, &efsi->token_stack,
+ grn_expr_add_str(ctx, efsi->e, str, str_size));
+ {
+ efs_info *q = efsi;
+ PARSE(GRN_EXPR_TOKEN_QSTRING);
+ }
+
+ GRN_PTR_POP(&efsi->token_stack, token);
+ column = grn_ptr_value_at(&efsi->column_stack, -1);
+ grn_expr_append_const(efsi->ctx, efsi->e, column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(efsi->ctx, efsi->e, token, GRN_OP_PUSH, 1);
+
+ mode = grn_int32_value_at(&efsi->mode_stack, -1);
+ weight = grn_int32_value_at(&efsi->weight_stack, -1);
+ switch (mode) {
+ case GRN_OP_ASSIGN :
+ grn_expr_append_op(efsi->ctx, efsi->e, mode, 2);
+ break;
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ {
+ int max_interval;
+ max_interval = grn_int32_value_at(&efsi->max_interval_stack, -1);
+ grn_expr_append_const_int(efsi->ctx, efsi->e, max_interval,
+ GRN_OP_PUSH, 1);
+ if (weight == 0) {
+ grn_expr_append_op(efsi->ctx, efsi->e, mode, 3);
+ } else {
+ grn_expr_append_const_int(efsi->ctx, efsi->e, weight, mode, 3);
+ }
+ }
+ break;
+ case GRN_OP_SIMILAR :
+ {
+ int similarity_threshold;
+ similarity_threshold =
+ grn_int32_value_at(&efsi->similarity_threshold_stack, -1);
+ grn_expr_append_const_int(efsi->ctx, efsi->e, similarity_threshold,
+ GRN_OP_PUSH, 1);
+ if (weight == 0) {
+ grn_expr_append_op(efsi->ctx, efsi->e, mode, 3);
+ } else {
+ grn_expr_append_const_int(efsi->ctx, efsi->e, weight, mode, 3);
+ }
+ }
+ break;
+ default :
+ if (weight == 0) {
+ grn_expr_append_op(efsi->ctx, efsi->e, mode, 2);
+ } else {
+ grn_expr_append_const_int(efsi->ctx, efsi->e, weight, mode, 2);
+ }
+ break;
+ }
+}
+
+static void
+parse_query_flush_pending_token(grn_ctx *ctx, efs_info *q)
+{
+ const char *cur_keep;
+
+ if (!(q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
+ return;
+ }
+
+ if (q->pending_token.string_length == 0) {
+ return;
+ }
+
+ cur_keep = q->cur;
+ q->cur = q->pending_token.string;
+ if (q->pending_token.token == GRN_EXPR_TOKEN_ADJUST ||
+ q->pending_token.token == GRN_EXPR_TOKEN_NEGATIVE) {
+ GRN_INT32_PUT(ctx, &q->weight_stack, q->pending_token.weight);
+ }
+ PARSE(q->pending_token.token);
+ q->cur = cur_keep;
+
+ q->pending_token.string = NULL;
+ q->pending_token.string_length = 0;
+ q->pending_token.token = 0;
+ q->pending_token.weight = 0;
+}
+
+static void
+parse_query_accept_logical_op(grn_ctx *ctx,
+ efs_info *q,
+ const char *string,
+ unsigned int string_length,
+ int token)
+{
+ if (!(q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
+ PARSE(token);
+ return;
+ }
+
+ if (q->pending_token.string_length > 0) {
+ parse_query_accept_string(ctx,
+ q,
+ q->pending_token.string,
+ q->pending_token.string_length);
+ }
+
+ q->pending_token.string = string;
+ q->pending_token.string_length = string_length;
+ q->pending_token.token = token;
+}
+
+static void
+parse_query_accept_adjust(grn_ctx *ctx,
+ efs_info *q,
+ const char *string,
+ unsigned int string_length,
+ int token,
+ int weight)
+{
+ if (!(q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
+ GRN_INT32_PUT(ctx, &q->weight_stack, weight);
+ PARSE(token);
+ return;
+ }
+
+ if (q->pending_token.string_length > 0) {
+ parse_query_accept_string(ctx,
+ q,
+ q->pending_token.string,
+ q->pending_token.string_length);
+ }
+
+ q->pending_token.string = string;
+ q->pending_token.string_length = string_length;
+ q->pending_token.token = token;
+ q->pending_token.weight = weight;
+}
+
+static grn_rc
+parse_query_word(grn_ctx *ctx, efs_info *q)
+{
+ const char *end;
+ unsigned int len;
+ GRN_BULK_REWIND(&q->buf);
+ for (end = q->cur;; ) {
+ /* null check and length check */
+ if (!(len = grn_charlen(ctx, end, q->str_end))) {
+ q->cur = q->str_end;
+ break;
+ }
+ if (grn_isspace(end, ctx->encoding) ||
+ *end == GRN_QUERY_PARENL || *end == GRN_QUERY_PARENR) {
+ q->cur = end;
+ break;
+ }
+ if (q->flags & GRN_EXPR_ALLOW_COLUMN && *end == GRN_QUERY_COLUMN) {
+ grn_operator mode;
+ grn_obj *c = grn_obj_column(ctx, q->table,
+ GRN_TEXT_VALUE(&q->buf),
+ GRN_TEXT_LEN(&q->buf));
+ if (c && end + 1 < q->str_end) {
+ switch (end[1]) {
+ case '!' :
+ mode = GRN_OP_NOT_EQUAL;
+ q->cur = end + 2;
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ mode = GRN_OP_ASSIGN;
+ q->cur = end + 2;
+ } else {
+ mode = GRN_OP_EQUAL;
+ q->cur = end + 1;
+ }
+ break;
+ case '<' :
+ if (end + 2 < q->str_end && end[2] == '=') {
+ mode = GRN_OP_LESS_EQUAL;
+ q->cur = end + 3;
+ } else {
+ mode = GRN_OP_LESS;
+ q->cur = end + 2;
+ }
+ break;
+ case '>' :
+ if (end + 2 < q->str_end && end[2] == '=') {
+ mode = GRN_OP_GREATER_EQUAL;
+ q->cur = end + 3;
+ } else {
+ mode = GRN_OP_GREATER;
+ q->cur = end + 2;
+ }
+ break;
+ case '@' :
+ mode = GRN_OP_MATCH;
+ q->cur = end + 2;
+ break;
+ case '^' :
+ mode = GRN_OP_PREFIX;
+ q->cur = end + 2;
+ break;
+ case '$' :
+ mode = GRN_OP_SUFFIX;
+ q->cur = end + 2;
+ break;
+ case '~' :
+ mode = GRN_OP_REGEXP;
+ q->cur = end + 2;
+ break;
+ default :
+ mode = GRN_OP_EQUAL;
+ q->cur = end + 1;
+ break;
+ }
+ } else if (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
+ GRN_TEXT_PUT(ctx, &q->buf, end, len);
+ end += len;
+ continue;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "column lookup failed");
+ q->cur = q->str_end;
+ return ctx->rc;
+ }
+ parse_query_flush_pending_token(ctx, q);
+ PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
+ PARSE(GRN_EXPR_TOKEN_RELATIVE_OP);
+
+ grn_expr_take_obj(ctx, q->e, c);
+ GRN_PTR_PUT(ctx, &q->column_stack, c);
+ GRN_INT32_PUT(ctx, &q->mode_stack, mode);
+
+ return GRN_SUCCESS;
+ } else if (GRN_TEXT_LEN(&q->buf) > 0 && *end == GRN_QUERY_PREFIX) {
+ q->cur = end + 1;
+ GRN_INT32_PUT(ctx, &q->mode_stack, GRN_OP_PREFIX);
+ break;
+ } else if (*end == GRN_QUERY_ESCAPE) {
+ end += len;
+ if (!(len = grn_charlen(ctx, end, q->str_end))) {
+ q->cur = q->str_end;
+ break;
+ }
+ }
+ GRN_TEXT_PUT(ctx, &q->buf, end, len);
+ end += len;
+ }
+ parse_query_flush_pending_token(ctx, q);
+ parse_query_accept_string(ctx,
+ q,
+ GRN_TEXT_VALUE(&q->buf),
+ GRN_TEXT_LEN(&q->buf));
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+parse_query(grn_ctx *ctx, efs_info *q)
+{
+ int option = 0;
+ grn_operator mode;
+ efs_op op_, *op = &op_;
+ grn_bool first_token = GRN_TRUE;
+ grn_bool only_first_and = GRN_FALSE;
+ grn_bool block_started = GRN_FALSE;
+
+ op->op = q->default_op;
+ op->weight = DEFAULT_WEIGHT;
+ while (!ctx->rc) {
+ skip_space(ctx, q);
+
+ if (q->cur >= q->str_end) { goto exit; }
+ if (*q->cur == '\0') { goto exit; }
+
+ only_first_and = GRN_FALSE;
+ switch (*q->cur) {
+ case GRN_QUERY_PARENR :
+ if (q->paren_depth == 0 && q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
+ const char parenr = GRN_QUERY_PARENR;
+ parse_query_flush_pending_token(ctx, q);
+ parse_query_accept_string(ctx, q, &parenr, 1);
+ } else {
+ parse_query_flush_pending_token(ctx, q);
+ PARSE(GRN_EXPR_TOKEN_PARENR);
+ q->paren_depth--;
+ }
+ q->cur++;
+ break;
+ case GRN_QUERY_QUOTEL :
+ q->cur++;
+
+ {
+ grn_bool closed = GRN_FALSE;
+ const char *start, *s;
+ start = s = q->cur;
+ GRN_BULK_REWIND(&q->buf);
+ while (1) {
+ unsigned int len;
+ if (s >= q->str_end) {
+ q->cur = s;
+ break;
+ }
+ len = grn_charlen(ctx, s, q->str_end);
+ if (len == 0) {
+ /* invalid string containing malformed multibyte char */
+ goto exit;
+ } else if (len == 1) {
+ if (*s == GRN_QUERY_QUOTER) {
+ q->cur = s + 1;
+ closed = GRN_TRUE;
+ break;
+ } else if (*s == GRN_QUERY_ESCAPE && s + 1 < q->str_end) {
+ s++;
+ len = grn_charlen(ctx, s, q->str_end);
+ }
+ }
+ GRN_TEXT_PUT(ctx, &q->buf, s, len);
+ s += len;
+ }
+ if (!closed && (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
+ q->cur = start - 1;
+ parse_query_word(ctx, q);
+ } else {
+ parse_query_flush_pending_token(ctx, q);
+ parse_query_accept_string(ctx,
+ q,
+ GRN_TEXT_VALUE(&q->buf),
+ GRN_TEXT_LEN(&q->buf));
+ }
+ }
+
+ break;
+ case GRN_QUERY_PREFIX :
+ q->cur++;
+ if (parse_query_op(q, op, &mode, &option)) {
+ switch (mode) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ GRN_INT32_PUT(ctx, &q->max_interval_stack, option);
+ break;
+ case GRN_OP_SIMILAR :
+ GRN_INT32_PUT(ctx, &q->similarity_threshold_stack, option);
+ break;
+ default :
+ break;
+ }
+ GRN_INT32_PUT(ctx, &q->mode_stack, mode);
+ parse_query_flush_pending_token(ctx, q);
+ PARSE(GRN_EXPR_TOKEN_RELATIVE_OP);
+ } else {
+ q->cur--;
+ parse_query_word(ctx, q);
+ }
+ break;
+ case GRN_QUERY_AND :
+ if (first_token) {
+ only_first_and = GRN_TRUE;
+ } else {
+ op->op = GRN_OP_AND;
+ parse_query_accept_logical_op(ctx,
+ q,
+ q->cur, 1,
+ GRN_EXPR_TOKEN_LOGICAL_AND);
+ }
+ q->cur++;
+ break;
+ case GRN_QUERY_AND_NOT :
+ if (first_token) {
+ if (q->flags & GRN_EXPR_ALLOW_LEADING_NOT) {
+ grn_obj *all_records = grn_ctx_get(ctx, "all_records", 11);
+ if (all_records) {
+ /* dummy token */
+ PARSE(GRN_EXPR_TOKEN_QSTRING);
+ grn_expr_append_obj(ctx, q->e, all_records, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, q->e, GRN_OP_CALL, 0);
+ }
+ } else if (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
+ parse_query_flush_pending_token(ctx, q);
+ parse_query_accept_string(ctx, q, q->cur, 1);
+ q->cur++;
+ break;
+ }
+ }
+ op->op = GRN_OP_AND_NOT;
+ parse_query_accept_logical_op(ctx,
+ q,
+ q->cur, 1,
+ GRN_EXPR_TOKEN_LOGICAL_AND_NOT);
+ q->cur++;
+ break;
+ case GRN_QUERY_ADJ_INC :
+ if (op->weight < 127) { op->weight++; }
+ op->op = GRN_OP_ADJUST;
+ parse_query_accept_adjust(ctx,
+ q,
+ q->cur, 1,
+ GRN_EXPR_TOKEN_ADJUST,
+ op->weight);
+ q->cur++;
+ break;
+ case GRN_QUERY_ADJ_DEC :
+ if (op->weight > -128) { op->weight--; }
+ op->op = GRN_OP_ADJUST;
+ parse_query_accept_adjust(ctx,
+ q,
+ q->cur, 1,
+ GRN_EXPR_TOKEN_ADJUST,
+ op->weight);
+ q->cur++;
+ break;
+ case GRN_QUERY_ADJ_NEG :
+ if (first_token) {
+ parse_query_flush_pending_token(ctx, q);
+ parse_query_accept_string(ctx, q, q->cur, 1);
+ } else {
+ op->op = GRN_OP_ADJUST;
+ parse_query_accept_adjust(ctx,
+ q,
+ q->cur, 1,
+ GRN_EXPR_TOKEN_NEGATIVE,
+ -DEFAULT_WEIGHT);
+ }
+ q->cur++;
+ break;
+ case GRN_QUERY_PARENL :
+ parse_query_flush_pending_token(ctx, q);
+ PARSE(GRN_EXPR_TOKEN_PARENL);
+ q->cur++;
+ q->paren_depth++;
+ block_started = GRN_TRUE;
+ break;
+ case 'O' :
+ if (q->cur + 2 < q->str_end && q->cur[1] == 'R' && q->cur[2] == ' ') {
+ if (first_token && (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR)) {
+ parse_query_flush_pending_token(ctx, q);
+ parse_query_accept_string(ctx, q, q->cur, 2);
+ } else {
+ parse_query_accept_logical_op(ctx,
+ q,
+ q->cur, 2,
+ GRN_EXPR_TOKEN_LOGICAL_OR);
+ }
+ q->cur += 2;
+ break;
+ }
+ /* fallthru */
+ default :
+ parse_query_word(ctx, q);
+ break;
+ }
+ first_token = block_started;
+ block_started = GRN_FALSE;
+ }
+exit :
+ if (q->flags & GRN_EXPR_QUERY_NO_SYNTAX_ERROR) {
+ if (q->pending_token.string_length > 0) {
+ parse_query_accept_string(ctx,
+ q,
+ q->pending_token.string,
+ q->pending_token.string_length);
+ } else if (only_first_and) {
+ const char query_and[] = {GRN_QUERY_AND};
+ parse_query_accept_string(ctx,
+ q,
+ query_and,
+ 1);
+ }
+ if (q->paren_depth > 0) {
+ int paren_depth = q->paren_depth;
+ while (paren_depth > 0) {
+ const char parenl = GRN_QUERY_PARENL;
+ parse_query_accept_string(ctx, q, &parenl, 1);
+ PARSE(GRN_EXPR_TOKEN_PARENR);
+ paren_depth--;
+ }
+ }
+ }
+ PARSE(0);
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+get_string(grn_ctx *ctx, efs_info *q, char quote)
+{
+ const char *s;
+ unsigned int len;
+ grn_rc rc = GRN_END_OF_DATA;
+ GRN_BULK_REWIND(&q->buf);
+ for (s = q->cur + 1; s < q->str_end; s += len) {
+ if (!(len = grn_charlen(ctx, s, q->str_end))) { break; }
+ if (len == 1) {
+ if (*s == quote) {
+ s++;
+ rc = GRN_SUCCESS;
+ break;
+ }
+ if (*s == GRN_QUERY_ESCAPE && s + 1 < q->str_end) {
+ s++;
+ if (!(len = grn_charlen(ctx, s, q->str_end))) { break; }
+ }
+ }
+ GRN_TEXT_PUT(ctx, &q->buf, s, len);
+ }
+ q->cur = s;
+ return rc;
+}
+
+static grn_obj *
+resolve_top_level_name(grn_ctx *ctx, const char *name, unsigned int name_size)
+{
+ unsigned int i;
+ unsigned int first_delimiter_position = 0;
+ unsigned int n_delimiters = 0;
+ grn_obj *top_level_object;
+ grn_obj *object;
+
+ for (i = 0; i < name_size; i++) {
+ if (name[i] != GRN_DB_DELIMITER) {
+ continue;
+ }
+
+ if (n_delimiters == 0) {
+ first_delimiter_position = i;
+ }
+ n_delimiters++;
+ }
+
+ if (n_delimiters < 2) {
+ return grn_ctx_get(ctx, name, name_size);
+ }
+
+ top_level_object = grn_ctx_get(ctx, name, first_delimiter_position);
+ if (!top_level_object) {
+ return NULL;
+ }
+ object = grn_obj_column(ctx, top_level_object,
+ name + first_delimiter_position + 1,
+ name_size - first_delimiter_position - 1);
+ grn_obj_unlink(ctx, top_level_object);
+ return object;
+}
+
+static grn_rc
+get_identifier(grn_ctx *ctx, efs_info *q, grn_obj *name_resolve_context)
+{
+ const char *s;
+ unsigned int len;
+ grn_rc rc = GRN_SUCCESS;
+ for (s = q->cur; s < q->str_end; s += len) {
+ if (!(len = grn_charlen(ctx, s, q->str_end))) {
+ rc = GRN_END_OF_DATA;
+ goto exit;
+ }
+ if (grn_isspace(s, ctx->encoding)) { goto done; }
+ if (len == 1) {
+ switch (*s) {
+ case '\0' : case '(' : case ')' : case '{' : case '}' :
+ case '[' : case ']' : case ',' : case ':' : case '@' :
+ case '?' : case '"' : case '*' : case '+' : case '-' :
+ case '|' : case '/' : case '%' : case '!' : case '^' :
+ case '&' : case '>' : case '<' : case '=' : case '~' :
+ /* case '.' : */
+ goto done;
+ break;
+ }
+ }
+ }
+done :
+ len = s - q->cur;
+ switch (*q->cur) {
+ case 'd' :
+ if (len == 6 && !memcmp(q->cur, "delete", 6)) {
+ PARSE(GRN_EXPR_TOKEN_DELETE);
+ goto exit;
+ }
+ break;
+ case 'f' :
+ if (len == 5 && !memcmp(q->cur, "false", 5)) {
+ grn_obj buf;
+ PARSE(GRN_EXPR_TOKEN_BOOLEAN);
+ GRN_BOOL_INIT(&buf, 0);
+ GRN_BOOL_SET(ctx, &buf, 0);
+ grn_expr_append_const(ctx, q->e, &buf, GRN_OP_PUSH, 1);
+ GRN_OBJ_FIN(ctx, &buf);
+ goto exit;
+ }
+ break;
+ case 'i' :
+ if (len == 2 && !memcmp(q->cur, "in", 2)) {
+ PARSE(GRN_EXPR_TOKEN_IN);
+ goto exit;
+ }
+ break;
+ case 'n' :
+ if (len == 4 && !memcmp(q->cur, "null", 4)) {
+ grn_obj buf;
+ PARSE(GRN_EXPR_TOKEN_NULL);
+ GRN_VOID_INIT(&buf);
+ grn_expr_append_const(ctx, q->e, &buf, GRN_OP_PUSH, 1);
+ GRN_OBJ_FIN(ctx, &buf);
+ goto exit;
+ }
+ break;
+ case 't' :
+ if (len == 4 && !memcmp(q->cur, "true", 4)) {
+ grn_obj buf;
+ PARSE(GRN_EXPR_TOKEN_BOOLEAN);
+ GRN_BOOL_INIT(&buf, 0);
+ GRN_BOOL_SET(ctx, &buf, 1);
+ grn_expr_append_const(ctx, q->e, &buf, GRN_OP_PUSH, 1);
+ GRN_OBJ_FIN(ctx, &buf);
+ goto exit;
+ }
+ break;
+ }
+ {
+ grn_obj *obj;
+ const char *name = q->cur;
+ unsigned int name_size = s - q->cur;
+ if (name_resolve_context) {
+ if ((obj = grn_obj_column(ctx, name_resolve_context, name, name_size))) {
+ if (obj->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, q->e, obj);
+ }
+ PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
+ grn_expr_append_obj(ctx, q->e, obj, GRN_OP_GET_VALUE, 2);
+ goto exit;
+ }
+ }
+ if ((obj = grn_expr_get_var(ctx, q->e, name, name_size))) {
+ PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
+ grn_expr_append_obj(ctx, q->e, obj, GRN_OP_PUSH, 1);
+ goto exit;
+ }
+ if ((obj = grn_obj_column(ctx, q->table, name, name_size))) {
+ if (obj->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, q->e, obj);
+ }
+ PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
+ grn_expr_append_obj(ctx, q->e, obj, GRN_OP_GET_VALUE, 1);
+ goto exit;
+ }
+ if ((obj = resolve_top_level_name(ctx, name, name_size))) {
+ if (obj->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, q->e, obj);
+ }
+ PARSE(GRN_EXPR_TOKEN_IDENTIFIER);
+ grn_expr_append_obj(ctx, q->e, obj, GRN_OP_PUSH, 1);
+ goto exit;
+ }
+ if (q->flags & GRN_EXPR_SYNTAX_OUTPUT_COLUMNS) {
+ PARSE(GRN_EXPR_TOKEN_NONEXISTENT_COLUMN);
+ } else {
+ rc = GRN_SYNTAX_ERROR;
+ ERR(rc,
+ "[expr][parse] unknown identifier: <%.*s>",
+ (int)name_size,
+ name);
+ }
+ }
+exit :
+ q->cur = s;
+ return rc;
+}
+
+static void
+set_tos_minor_to_curr(grn_ctx *ctx, efs_info *q)
+{
+ yyParser *parser = ctx->impl->parser;
+ yyStackEntry *yytos = parser->yytos;
+ yytos->minor.yy0 = ((grn_expr *)(q->e))->codes_curr;
+}
+
+static grn_obj *
+parse_script_extract_name_resolve_context(grn_ctx *ctx, efs_info *q)
+{
+ grn_expr *expr = (grn_expr *)(q->e);
+ grn_expr_code *code_start;
+ grn_expr_code *code_last;
+
+ if (expr->codes_curr == 0) {
+ return NULL;
+ }
+
+ code_start = expr->codes;
+ code_last = code_start + (expr->codes_curr - 1);
+ switch (code_last->op) {
+ case GRN_OP_GET_MEMBER :
+ {
+ unsigned int n_used_codes_for_key;
+ grn_expr_code *code_key;
+ grn_expr_code *code_receiver;
+
+ code_key = code_last - 1;
+ if (code_key < code_start) {
+ return NULL;
+ }
+
+ n_used_codes_for_key = grn_expr_code_n_used_codes(ctx,
+ code_start,
+ code_key);
+ if (n_used_codes_for_key == 0) {
+ return NULL;
+ }
+ code_receiver = code_key - n_used_codes_for_key;
+ if (code_receiver < code_start) {
+ return NULL;
+ }
+ return code_receiver->value;
+ }
+ break;
+ default :
+ /* TODO: Support other operators. */
+ return NULL;
+ break;
+ }
+}
+
+static grn_rc
+parse_script(grn_ctx *ctx, efs_info *q)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *name_resolve_context = NULL;
+ for (;;) {
+ grn_obj *current_name_resolve_context = name_resolve_context;
+ name_resolve_context = NULL;
+ skip_space(ctx, q);
+ if (q->cur >= q->str_end) { rc = GRN_END_OF_DATA; goto exit; }
+ switch (*q->cur) {
+ case '\0' :
+ rc = GRN_END_OF_DATA;
+ goto exit;
+ break;
+ case '(' :
+ PARSE(GRN_EXPR_TOKEN_PARENL);
+ q->cur++;
+ break;
+ case ')' :
+ PARSE(GRN_EXPR_TOKEN_PARENR);
+ q->cur++;
+ break;
+ case '{' :
+ PARSE(GRN_EXPR_TOKEN_BRACEL);
+ q->cur++;
+ break;
+ case '}' :
+ PARSE(GRN_EXPR_TOKEN_BRACER);
+ q->cur++;
+ break;
+ case '[' :
+ PARSE(GRN_EXPR_TOKEN_BRACKETL);
+ q->cur++;
+ break;
+ case ']' :
+ PARSE(GRN_EXPR_TOKEN_BRACKETR);
+ q->cur++;
+ break;
+ case ',' :
+ PARSE(GRN_EXPR_TOKEN_COMMA);
+ q->cur++;
+ break;
+ case '.' :
+ PARSE(GRN_EXPR_TOKEN_DOT);
+ name_resolve_context = parse_script_extract_name_resolve_context(ctx, q);
+ q->cur++;
+ break;
+ case ':' :
+ PARSE(GRN_EXPR_TOKEN_COLON);
+ q->cur++;
+ set_tos_minor_to_curr(ctx, q);
+ grn_expr_append_op(ctx, q->e, GRN_OP_JUMP, 0);
+ break;
+ case '@' :
+ switch (q->cur[1]) {
+ case '^' :
+ PARSE(GRN_EXPR_TOKEN_PREFIX);
+ q->cur += 2;
+ break;
+ case '$' :
+ PARSE(GRN_EXPR_TOKEN_SUFFIX);
+ q->cur += 2;
+ break;
+ case '~' :
+ PARSE(GRN_EXPR_TOKEN_REGEXP);
+ q->cur += 2;
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_MATCH);
+ q->cur++;
+ break;
+ }
+ break;
+ case '~' :
+ PARSE(GRN_EXPR_TOKEN_BITWISE_NOT);
+ q->cur++;
+ break;
+ case '?' :
+ PARSE(GRN_EXPR_TOKEN_QUESTION);
+ q->cur++;
+ set_tos_minor_to_curr(ctx, q);
+ grn_expr_append_op(ctx, q->e, GRN_OP_CJUMP, 0);
+ break;
+ case '"' :
+ if ((rc = get_string(ctx, q, '"'))) { goto exit; }
+ PARSE(GRN_EXPR_TOKEN_STRING);
+ grn_expr_append_const(ctx, q->e, &q->buf, GRN_OP_PUSH, 1);
+ break;
+ case '\'' :
+ if ((rc = get_string(ctx, q, '\''))) { goto exit; }
+ PARSE(GRN_EXPR_TOKEN_STRING);
+ grn_expr_append_const(ctx, q->e, &q->buf, GRN_OP_PUSH, 1);
+ break;
+ case '*' :
+ switch (q->cur[1]) {
+ case 'N' :
+ {
+ const char *next_start = q->cur + 2;
+ const char *end;
+ int max_interval;
+ max_interval = grn_atoi(next_start, q->str_end, &end);
+ if (end == next_start) {
+ max_interval = DEFAULT_MAX_INTERVAL;
+ } else {
+ next_start = end;
+ }
+ GRN_INT32_PUT(ctx, &q->max_interval_stack, max_interval);
+ PARSE(GRN_EXPR_TOKEN_NEAR);
+ q->cur = next_start;
+ }
+ break;
+ case 'S' :
+ PARSE(GRN_EXPR_TOKEN_SIMILAR);
+ q->cur += 2;
+ break;
+ case 'T' :
+ PARSE(GRN_EXPR_TOKEN_TERM_EXTRACT);
+ q->cur += 2;
+ break;
+ case '>' :
+ PARSE(GRN_EXPR_TOKEN_ADJUST);
+ q->cur += 2;
+ break;
+ case '<' :
+ PARSE(GRN_EXPR_TOKEN_ADJUST);
+ q->cur += 2;
+ break;
+ case '~' :
+ PARSE(GRN_EXPR_TOKEN_ADJUST);
+ q->cur += 2;
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_STAR_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'*=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_STAR);
+ q->cur++;
+ break;
+ }
+ break;
+ case '+' :
+ switch (q->cur[1]) {
+ case '+' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_INCR);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'++' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_PLUS_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'+=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_PLUS);
+ q->cur++;
+ break;
+ }
+ break;
+ case '-' :
+ switch (q->cur[1]) {
+ case '-' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_DECR);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'--' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_MINUS_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'-=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_MINUS);
+ q->cur++;
+ break;
+ }
+ break;
+ case '|' :
+ switch (q->cur[1]) {
+ case '|' :
+ PARSE(GRN_EXPR_TOKEN_LOGICAL_OR);
+ q->cur += 2;
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_OR_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'|=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_BITWISE_OR);
+ q->cur++;
+ break;
+ }
+ break;
+ case '/' :
+ switch (q->cur[1]) {
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_SLASH_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'/=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_SLASH);
+ q->cur++;
+ break;
+ }
+ break;
+ case '%' :
+ switch (q->cur[1]) {
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_MOD_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'%%=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_MOD);
+ q->cur++;
+ break;
+ }
+ break;
+ case '!' :
+ switch (q->cur[1]) {
+ case '=' :
+ PARSE(GRN_EXPR_TOKEN_NOT_EQUAL);
+ q->cur += 2;
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_NOT);
+ q->cur++;
+ break;
+ }
+ break;
+ case '^' :
+ switch (q->cur[1]) {
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ q->cur += 2;
+ PARSE(GRN_EXPR_TOKEN_XOR_ASSIGN);
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'^=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_BITWISE_XOR);
+ q->cur++;
+ break;
+ }
+ break;
+ case '&' :
+ switch (q->cur[1]) {
+ case '&' :
+ PARSE(GRN_EXPR_TOKEN_LOGICAL_AND);
+ q->cur += 2;
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_AND_ASSIGN);
+ q->cur += 2;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'&=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ case '!' :
+ PARSE(GRN_EXPR_TOKEN_LOGICAL_AND_NOT);
+ q->cur += 2;
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_BITWISE_AND);
+ q->cur++;
+ break;
+ }
+ break;
+ case '>' :
+ switch (q->cur[1]) {
+ case '>' :
+ switch (q->cur[2]) {
+ case '>' :
+ switch (q->cur[3]) {
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_SHIFTRR_ASSIGN);
+ q->cur += 4;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'>>>=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_SHIFTRR);
+ q->cur += 3;
+ break;
+ }
+ break;
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_SHIFTR_ASSIGN);
+ q->cur += 3;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'>>=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_SHIFTR);
+ q->cur += 2;
+ break;
+ }
+ break;
+ case '=' :
+ PARSE(GRN_EXPR_TOKEN_GREATER_EQUAL);
+ q->cur += 2;
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_GREATER);
+ q->cur++;
+ break;
+ }
+ break;
+ case '<' :
+ switch (q->cur[1]) {
+ case '<' :
+ switch (q->cur[2]) {
+ case '=' :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_SHIFTL_ASSIGN);
+ q->cur += 3;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'<<=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_SHIFTL);
+ q->cur += 2;
+ break;
+ }
+ break;
+ case '=' :
+ PARSE(GRN_EXPR_TOKEN_LESS_EQUAL);
+ q->cur += 2;
+ break;
+ default :
+ PARSE(GRN_EXPR_TOKEN_LESS);
+ q->cur++;
+ break;
+ }
+ break;
+ case '=' :
+ switch (q->cur[1]) {
+ case '=' :
+ PARSE(GRN_EXPR_TOKEN_EQUAL);
+ q->cur += 2;
+ break;
+ default :
+ if (q->flags & GRN_EXPR_ALLOW_UPDATE) {
+ PARSE(GRN_EXPR_TOKEN_ASSIGN);
+ q->cur++;
+ } else {
+ ERR(GRN_UPDATE_NOT_ALLOWED,
+ "'=' is not allowed: <%.*s>", (int)(q->str_end - q->str), q->str);
+ }
+ break;
+ }
+ break;
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ {
+ const char *rest;
+ int64_t int64 = grn_atoll(q->cur, q->str_end, &rest);
+ // checks to see grn_atoll was appropriate
+ // (NOTE: *q->cur begins with a digit. Thus, grn_atoll parses at least
+ // one char.)
+ if (q->str_end != rest &&
+ (*rest == '.' || *rest == 'e' || *rest == 'E' ||
+ (*rest >= '0' && *rest <= '9'))) {
+ char *rest_float;
+ double d = strtod(q->cur, &rest_float);
+ grn_obj floatbuf;
+ GRN_FLOAT_INIT(&floatbuf, 0);
+ GRN_FLOAT_SET(ctx, &floatbuf, d);
+ grn_expr_append_const(ctx, q->e, &floatbuf, GRN_OP_PUSH, 1);
+ rest = rest_float;
+ } else {
+ const char *rest64 = rest;
+ grn_atoui(q->cur, q->str_end, &rest);
+ // checks to see grn_atoi failed (see above NOTE)
+ if ((int64 > UINT32_MAX) ||
+ (q->str_end != rest && *rest >= '0' && *rest <= '9')) {
+ grn_obj int64buf;
+ GRN_INT64_INIT(&int64buf, 0);
+ GRN_INT64_SET(ctx, &int64buf, int64);
+ grn_expr_append_const(ctx, q->e, &int64buf, GRN_OP_PUSH, 1);
+ rest = rest64;
+ } else if (int64 > INT32_MAX || int64 < INT32_MIN) {
+ grn_obj int64buf;
+ GRN_INT64_INIT(&int64buf, 0);
+ GRN_INT64_SET(ctx, &int64buf, int64);
+ grn_expr_append_const(ctx, q->e, &int64buf, GRN_OP_PUSH, 1);
+ } else {
+ grn_obj int32buf;
+ GRN_INT32_INIT(&int32buf, 0);
+ GRN_INT32_SET(ctx, &int32buf, (int32_t)int64);
+ grn_expr_append_const(ctx, q->e, &int32buf, GRN_OP_PUSH, 1);
+ }
+ }
+ PARSE(GRN_EXPR_TOKEN_DECIMAL);
+ q->cur = rest;
+ }
+ break;
+ default :
+ if ((rc = get_identifier(ctx, q, current_name_resolve_context))) {
+ goto exit;
+ }
+ break;
+ }
+ if (ctx->rc) { rc = ctx->rc; break; }
+ }
+exit :
+ PARSE(0);
+ return rc;
+}
+
+grn_rc
+grn_expr_parse(grn_ctx *ctx, grn_obj *expr,
+ const char *str, unsigned int str_size,
+ grn_obj *default_column, grn_operator default_mode,
+ grn_operator default_op, grn_expr_flags flags)
+{
+ efs_info efsi;
+ if (grn_expr_parser_open(ctx)) { return ctx->rc; }
+ GRN_API_ENTER;
+ efsi.ctx = ctx;
+ efsi.str = str;
+ if ((efsi.v = grn_expr_get_var_by_offset(ctx, expr, 0)) &&
+ (efsi.table = grn_ctx_at(ctx, efsi.v->header.domain))) {
+ GRN_TEXT_INIT(&efsi.buf, 0);
+ GRN_INT32_INIT(&efsi.op_stack, GRN_OBJ_VECTOR);
+ GRN_INT32_INIT(&efsi.mode_stack, GRN_OBJ_VECTOR);
+ GRN_INT32_INIT(&efsi.max_interval_stack, GRN_OBJ_VECTOR);
+ GRN_INT32_INIT(&efsi.similarity_threshold_stack, GRN_OBJ_VECTOR);
+ GRN_INT32_INIT(&efsi.weight_stack, GRN_OBJ_VECTOR);
+ GRN_PTR_INIT(&efsi.column_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_PTR_INIT(&efsi.token_stack, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ efsi.e = expr;
+ efsi.str = str;
+ efsi.cur = str;
+ efsi.str_end = str + str_size;
+ efsi.default_column = default_column;
+ GRN_PTR_PUT(ctx, &efsi.column_stack, default_column);
+ GRN_INT32_PUT(ctx, &efsi.op_stack, default_op);
+ GRN_INT32_PUT(ctx, &efsi.mode_stack, default_mode);
+ GRN_INT32_PUT(ctx, &efsi.weight_stack, 0);
+ efsi.default_flags = efsi.flags = flags;
+ efsi.escalation_threshold = GRN_DEFAULT_MATCH_ESCALATION_THRESHOLD;
+ efsi.escalation_decaystep = DEFAULT_DECAYSTEP;
+ efsi.weight_offset = 0;
+ memset(&(efsi.opt), 0, sizeof(grn_select_optarg));
+ efsi.opt.weight_vector = NULL;
+ efsi.weight_set = NULL;
+ efsi.object_literal = NULL;
+ efsi.paren_depth = 0;
+ efsi.pending_token.string = NULL;
+ efsi.pending_token.string_length = 0;
+ efsi.pending_token.token = 0;
+
+ if (flags & (GRN_EXPR_SYNTAX_SCRIPT |
+ GRN_EXPR_SYNTAX_OUTPUT_COLUMNS |
+ GRN_EXPR_SYNTAX_ADJUSTER)) {
+ efs_info *q = &efsi;
+ if (flags & GRN_EXPR_SYNTAX_OUTPUT_COLUMNS) {
+ PARSE(GRN_EXPR_TOKEN_START_OUTPUT_COLUMNS);
+ } else if (flags & GRN_EXPR_SYNTAX_ADJUSTER) {
+ PARSE(GRN_EXPR_TOKEN_START_ADJUSTER);
+ }
+ parse_script(ctx, &efsi);
+ } else {
+ parse_query(ctx, &efsi);
+ }
+
+ /*
+ grn_obj strbuf;
+ GRN_TEXT_INIT(&strbuf, 0);
+ grn_expr_inspect_internal(ctx, &strbuf, expr);
+ GRN_TEXT_PUTC(ctx, &strbuf, '\0');
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "query=(%s)", GRN_TEXT_VALUE(&strbuf));
+ GRN_OBJ_FIN(ctx, &strbuf);
+ */
+
+ /*
+ efsi.opt.vector_size = DEFAULT_WEIGHT_VECTOR_SIZE;
+ efsi.opt.func = efsi.weight_set ? section_weight_cb : NULL;
+ efsi.opt.func_arg = efsi.weight_set;
+ efsi.snip_conds = NULL;
+ */
+ GRN_OBJ_FIN(ctx, &efsi.op_stack);
+ GRN_OBJ_FIN(ctx, &efsi.mode_stack);
+ GRN_OBJ_FIN(ctx, &efsi.max_interval_stack);
+ GRN_OBJ_FIN(ctx, &efsi.similarity_threshold_stack);
+ GRN_OBJ_FIN(ctx, &efsi.weight_stack);
+ GRN_OBJ_FIN(ctx, &efsi.column_stack);
+ GRN_OBJ_FIN(ctx, &efsi.token_stack);
+ GRN_OBJ_FIN(ctx, &efsi.buf);
+ if (efsi.object_literal) {
+ grn_obj *value;
+ GRN_HASH_EACH(ctx, efsi.object_literal, i, NULL, NULL, (void **)&value, {
+ GRN_OBJ_FIN(ctx, value);
+ });
+ grn_hash_close(ctx, efsi.object_literal);
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "variable is not defined correctly");
+ }
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_expr_parser_close(grn_ctx *ctx)
+{
+ if (ctx->impl->parser) {
+ yyParser *parser = (yyParser *)ctx->impl->parser;
+ ctx->impl->parser = NULL;
+ grn_expr_parserFree(parser, free);
+ }
+ return ctx->rc;
+}
+
+typedef grn_rc (*grn_expr_syntax_expand_term_func)(grn_ctx *ctx,
+ const char *term,
+ unsigned int term_len,
+ grn_obj *substituted_term,
+ grn_user_data *user_data);
+static grn_rc
+grn_expr_syntax_expand_term_by_func(grn_ctx *ctx,
+ const char *term, unsigned int term_len,
+ grn_obj *expanded_term,
+ grn_user_data *user_data)
+{
+ grn_rc rc;
+ grn_obj *expander = user_data->ptr;
+ grn_obj grn_term;
+ grn_obj *caller;
+ grn_obj *rc_object;
+ int nargs = 0;
+
+ GRN_TEXT_INIT(&grn_term, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, &grn_term, term, term_len);
+ grn_ctx_push(ctx, &grn_term);
+ nargs++;
+ grn_ctx_push(ctx, expanded_term);
+ nargs++;
+
+ caller = grn_expr_create(ctx, NULL, 0);
+ rc = grn_proc_call(ctx, expander, nargs, caller);
+ GRN_OBJ_FIN(ctx, &grn_term);
+ rc_object = grn_ctx_pop(ctx);
+ rc = GRN_INT32_VALUE(rc_object);
+ grn_obj_unlink(ctx, caller);
+
+ return rc;
+}
+
+typedef struct {
+ grn_obj *table;
+ grn_obj *column;
+} grn_expr_syntax_expand_term_by_column_data;
+
+static grn_rc
+grn_expr_syntax_expand_term_by_column(grn_ctx *ctx,
+ const char *term, unsigned int term_len,
+ grn_obj *expanded_term,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_END_OF_DATA;
+ grn_id id;
+ grn_expr_syntax_expand_term_by_column_data *data = user_data->ptr;
+ grn_obj *table, *column;
+
+ table = data->table;
+ column = data->column;
+ if ((id = grn_table_get(ctx, table, term, term_len))) {
+ if ((column->header.type == GRN_COLUMN_VAR_SIZE) &&
+ ((column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR)) {
+ unsigned int i, n;
+ grn_obj values;
+ GRN_TEXT_INIT(&values, GRN_OBJ_VECTOR);
+ grn_obj_get_value(ctx, column, id, &values);
+ n = grn_vector_size(ctx, &values);
+ if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
+ for (i = 0; i < n; i++) {
+ const char *value;
+ unsigned int length;
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
+ }
+ if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
+ length = grn_vector_get_element(ctx, &values, i, &value, NULL, NULL);
+ GRN_TEXT_PUT(ctx, expanded_term, value, length);
+ if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
+ }
+ if (n > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
+ GRN_OBJ_FIN(ctx, &values);
+ } else {
+ grn_obj_get_value(ctx, column, id, expanded_term);
+ }
+ rc = GRN_SUCCESS;
+ }
+ return rc;
+}
+
+typedef struct {
+ grn_obj *table;
+ grn_obj *term_column;
+ grn_obj *expanded_term_column;
+} grn_expr_syntax_expand_term_by_table_data;
+
+static grn_rc
+grn_expr_syntax_expand_term_by_table(grn_ctx *ctx,
+ const char *term, unsigned int term_len,
+ grn_obj *expanded_term,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_END_OF_DATA;
+ grn_expr_syntax_expand_term_by_table_data *data = user_data->ptr;
+ grn_obj *table;
+ grn_obj *term_column;
+ grn_obj *expanded_term_column;
+ grn_obj *expression;
+ grn_obj *variable;
+ grn_obj *found_terms;
+ int n_terms;
+
+ table = data->table;
+ term_column = data->term_column;
+ expanded_term_column = data->expanded_term_column;
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, expression, variable);
+ if (ctx->rc != GRN_SUCCESS) {
+ ERR(ctx->rc,
+ "[query][expand][table] "
+ "failed to create expression: <%s>",
+ ctx->errbuf);
+ return ctx->rc;
+ }
+ grn_expr_append_const(ctx, expression, term_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_const_str(ctx, expression, term, term_len, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, expression, GRN_OP_EQUAL, 2);
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, expression);
+ ERR(ctx->rc,
+ "[query][expand][table] "
+ "failed to build expression: <%s>",
+ ctx->errbuf);
+ return ctx->rc;
+ }
+
+ found_terms = grn_table_select(ctx, table, expression, NULL, GRN_OP_OR);
+ grn_obj_close(ctx, expression);
+ if (!found_terms) {
+ ERR(ctx->rc,
+ "[query][expand][table] "
+ "failed to find term: <%.*s>: <%s>",
+ (int)term_len,
+ term,
+ ctx->errbuf);
+ return ctx->rc;
+ }
+
+ n_terms = grn_table_size(ctx, found_terms);
+ if (n_terms == 0) {
+ grn_obj_close(ctx, found_terms);
+ return rc;
+ }
+
+ {
+ int nth_term;
+
+ GRN_TEXT_PUTC(ctx, expanded_term, '(');
+ nth_term = 0;
+ GRN_TABLE_EACH_BEGIN(ctx, found_terms, cursor, id) {
+ void *key;
+ grn_id record_id;
+
+ grn_table_cursor_get_key(ctx, cursor, &key);
+ record_id = *((grn_id *)key);
+ if (grn_obj_is_vector_column(ctx, expanded_term_column)) {
+ unsigned int j, n_values;
+ grn_obj values;
+ GRN_TEXT_INIT(&values, GRN_OBJ_VECTOR);
+ grn_obj_get_value(ctx, expanded_term_column, record_id, &values);
+ n_values = grn_vector_size(ctx, &values);
+ n_terms += n_values - 1;
+ for (j = 0; j < n_values; j++) {
+ const char *value;
+ unsigned int length;
+ if (nth_term > 0) {
+ GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
+ }
+ if (n_terms > 1) {
+ GRN_TEXT_PUTC(ctx, expanded_term, '(');
+ }
+ length = grn_vector_get_element(ctx, &values, j, &value, NULL, NULL);
+ GRN_TEXT_PUT(ctx, expanded_term, value, length);
+ if (n_terms > 1) {
+ GRN_TEXT_PUTC(ctx, expanded_term, ')');
+ }
+ nth_term++;
+ }
+ GRN_OBJ_FIN(ctx, &values);
+ } else {
+ if (nth_term > 0) {
+ GRN_TEXT_PUTS(ctx, expanded_term, " OR ");
+ }
+ if (n_terms > 1) { GRN_TEXT_PUTC(ctx, expanded_term, '('); }
+ grn_obj_get_value(ctx, expanded_term_column, record_id, expanded_term);
+ if (n_terms > 1) { GRN_TEXT_PUTC(ctx, expanded_term, ')'); }
+ nth_term++;
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ GRN_TEXT_PUTC(ctx, expanded_term, ')');
+ }
+ rc = GRN_SUCCESS;
+ grn_obj_close(ctx, found_terms);
+
+ return rc;
+}
+
+static grn_rc
+grn_expr_syntax_expand_query_terms(grn_ctx *ctx,
+ const char *query, unsigned int query_size,
+ grn_expr_flags flags,
+ grn_obj *expanded_query,
+ grn_expr_syntax_expand_term_func expand_term_func,
+ grn_user_data *user_data)
+{
+ grn_obj buf;
+ unsigned int len;
+ const char *start, *cur = query, *query_end = query + (size_t)query_size;
+ GRN_TEXT_INIT(&buf, 0);
+ for (;;) {
+ while (cur < query_end && grn_isspace(cur, ctx->encoding)) {
+ if (!(len = grn_charlen(ctx, cur, query_end))) { goto exit; }
+ GRN_TEXT_PUT(ctx, expanded_query, cur, len);
+ cur += len;
+ }
+ if (query_end <= cur) { break; }
+ switch (*cur) {
+ case '\0' :
+ goto exit;
+ break;
+ case GRN_QUERY_AND :
+ case GRN_QUERY_ADJ_INC :
+ case GRN_QUERY_ADJ_DEC :
+ case GRN_QUERY_ADJ_NEG :
+ case GRN_QUERY_AND_NOT :
+ case GRN_QUERY_PARENL :
+ case GRN_QUERY_PARENR :
+ case GRN_QUERY_PREFIX :
+ GRN_TEXT_PUTC(ctx, expanded_query, *cur);
+ cur++;
+ break;
+ case GRN_QUERY_QUOTEL :
+ GRN_BULK_REWIND(&buf);
+ for (start = cur++; cur < query_end; cur += len) {
+ if (!(len = grn_charlen(ctx, cur, query_end))) {
+ goto exit;
+ } else if (len == 1) {
+ if (*cur == GRN_QUERY_QUOTER) {
+ cur++;
+ break;
+ } else if (cur + 1 < query_end && *cur == GRN_QUERY_ESCAPE) {
+ cur++;
+ len = grn_charlen(ctx, cur, query_end);
+ }
+ }
+ GRN_TEXT_PUT(ctx, &buf, cur, len);
+ }
+ if (expand_term_func(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf),
+ expanded_query, user_data)) {
+ GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
+ }
+ break;
+ case 'O' :
+ if (cur + 2 <= query_end && cur[1] == 'R' &&
+ (cur + 2 == query_end || grn_isspace(cur + 2, ctx->encoding))) {
+ GRN_TEXT_PUT(ctx, expanded_query, cur, 2);
+ cur += 2;
+ break;
+ }
+ /* fallthru */
+ default :
+ for (start = cur; cur < query_end; cur += len) {
+ if (!(len = grn_charlen(ctx, cur, query_end))) {
+ goto exit;
+ } else if (grn_isspace(cur, ctx->encoding)) {
+ break;
+ } else if (len == 1) {
+ if (*cur == GRN_QUERY_PARENL ||
+ *cur == GRN_QUERY_PARENR ||
+ *cur == GRN_QUERY_PREFIX) {
+ break;
+ } else if (flags & GRN_EXPR_ALLOW_COLUMN && *cur == GRN_QUERY_COLUMN) {
+ if (cur + 1 < query_end) {
+ switch (cur[1]) {
+ case '!' :
+ case '@' :
+ case '^' :
+ case '$' :
+ cur += 2;
+ break;
+ case '=' :
+ cur += (flags & GRN_EXPR_ALLOW_UPDATE) ? 2 : 1;
+ break;
+ case '<' :
+ case '>' :
+ cur += (cur + 2 < query_end && cur[2] == '=') ? 3 : 2;
+ break;
+ default :
+ cur += 1;
+ break;
+ }
+ } else {
+ cur += 1;
+ }
+ GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
+ start = cur;
+ break;
+ }
+ }
+ }
+ if (start < cur) {
+ if (expand_term_func(ctx, start, cur - start,
+ expanded_query, user_data)) {
+ GRN_TEXT_PUT(ctx, expanded_query, start, cur - start);
+ }
+ }
+ break;
+ }
+ }
+exit :
+ GRN_OBJ_FIN(ctx, &buf);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_expr_syntax_expand_query(grn_ctx *ctx,
+ const char *query, int query_size,
+ grn_expr_flags flags,
+ grn_obj *expander,
+ grn_obj *expanded_query)
+{
+ GRN_API_ENTER;
+
+ if (query_size < 0) {
+ query_size = strlen(query);
+ }
+
+ switch (expander->header.type) {
+ case GRN_PROC :
+ if (((grn_proc *)expander)->type == GRN_PROC_FUNCTION) {
+ grn_user_data user_data;
+ user_data.ptr = expander;
+ grn_expr_syntax_expand_query_terms(ctx,
+ query, query_size,
+ flags,
+ expanded_query,
+ grn_expr_syntax_expand_term_by_func,
+ &user_data);
+ } else {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_obj_name(ctx, expander, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[query][expand][proc] "
+ "proc query expander must be a function proc: <%.*s>",
+ name_size, name);
+ }
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ {
+ grn_obj *expansion_table;
+ expansion_table = grn_column_table(ctx, expander);
+ if (expansion_table) {
+ grn_user_data user_data;
+ grn_expr_syntax_expand_term_by_column_data data;
+ user_data.ptr = &data;
+ data.table = expansion_table;
+ data.column = expander;
+ grn_expr_syntax_expand_query_terms(ctx,
+ query, query_size,
+ flags,
+ expanded_query,
+ grn_expr_syntax_expand_term_by_column,
+ &user_data);
+ } else {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_obj_name(ctx, expander, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[query][expand][column] "
+ "failed to get table of query expansion column: <%.*s>",
+ name_size, name);
+ }
+ }
+ break;
+ default :
+ {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ grn_obj type_name;
+
+ name_size = grn_obj_name(ctx, expander, name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_INIT(&type_name, 0);
+ grn_inspect_type(ctx, &type_name, expander->header.type);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[query][expand] "
+ "query expander must be a data column or function proc: <%.*s>(%.*s)",
+ name_size, name,
+ (int)GRN_TEXT_LEN(&type_name), GRN_TEXT_VALUE(&type_name));
+ GRN_OBJ_FIN(ctx, &type_name);
+ }
+ break;
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_expr_syntax_expand_query_by_table(grn_ctx *ctx,
+ const char *query, int query_size,
+ grn_expr_flags flags,
+ grn_obj *term_column,
+ grn_obj *expanded_term_column,
+ grn_obj *expanded_query)
+{
+ grn_obj *table;
+ grn_bool term_column_is_key;
+
+ GRN_API_ENTER;
+
+ if (query_size < 0) {
+ query_size = strlen(query);
+ }
+
+ if (!grn_obj_is_data_column(ctx, expanded_term_column)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, expanded_term_column);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[query][expand][table] "
+ "expanded term column must be a data column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(ctx->rc);
+ }
+ table = grn_column_table(ctx, expanded_term_column);
+
+ if (!term_column) {
+ term_column_is_key = GRN_TRUE;
+ } else {
+ if (grn_obj_is_key_accessor(ctx, term_column)) {
+ term_column_is_key = GRN_TRUE;
+ } else if (grn_obj_is_data_column(ctx, term_column)) {
+ term_column_is_key = GRN_FALSE;
+ } else {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, term_column);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[query][expand][table] "
+ "term column must be NULL, _key or a data column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(ctx->rc);
+ }
+ if (term_column->header.domain != expanded_term_column->header.domain) {
+ grn_obj inspected_term_column;
+ grn_obj inspected_expanded_term_column;
+ GRN_TEXT_INIT(&inspected_term_column, 0);
+ GRN_TEXT_INIT(&inspected_expanded_term_column, 0);
+ grn_inspect(ctx, &inspected_term_column, term_column);
+ grn_inspect(ctx, &inspected_expanded_term_column, expanded_term_column);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[query][expand][table] "
+ "term column and expanded term column must belong to the same table: "
+ "term column: <%.*s>, "
+ "expanded term column: <%*.s>",
+ (int)GRN_TEXT_LEN(&inspected_term_column),
+ GRN_TEXT_VALUE(&inspected_term_column),
+ (int)GRN_TEXT_LEN(&inspected_expanded_term_column),
+ GRN_TEXT_VALUE(&inspected_expanded_term_column));
+ GRN_OBJ_FIN(ctx, &inspected_term_column);
+ GRN_OBJ_FIN(ctx, &inspected_expanded_term_column);
+ GRN_API_RETURN(ctx->rc);
+ }
+ }
+
+ if (term_column_is_key) {
+ grn_user_data user_data;
+ grn_expr_syntax_expand_term_by_column_data data;
+ user_data.ptr = &data;
+ data.table = table;
+ data.column = expanded_term_column;
+ grn_expr_syntax_expand_query_terms(ctx,
+ query, query_size,
+ flags,
+ expanded_query,
+ grn_expr_syntax_expand_term_by_column,
+ &user_data);
+ } else {
+ grn_user_data user_data;
+ grn_expr_syntax_expand_term_by_table_data data;
+ user_data.ptr = &data;
+ data.table = table;
+ data.term_column = term_column;
+ data.expanded_term_column = expanded_term_column;
+ grn_expr_syntax_expand_query_terms(ctx,
+ query, query_size,
+ flags,
+ expanded_query,
+ grn_expr_syntax_expand_term_by_table,
+ &user_data);
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_expr_get_keywords(grn_ctx *ctx, grn_obj *expr, grn_obj *keywords)
+{
+ int i, n;
+ scan_info **sis, *si;
+ GRN_API_ENTER;
+ if ((sis = grn_scan_info_build(ctx, expr, &n, GRN_OP_OR, GRN_FALSE))) {
+ int butp = 0, nparens = 0, npbut = 0;
+ grn_obj but_stack;
+ GRN_UINT32_INIT(&but_stack, GRN_OBJ_VECTOR);
+ for (i = n; i--;) {
+ si = sis[i];
+ if (si->flags & SCAN_POP) {
+ nparens++;
+ if (si->logical_op == GRN_OP_AND_NOT) {
+ GRN_UINT32_PUT(ctx, &but_stack, npbut);
+ npbut = nparens;
+ butp = 1 - butp;
+ }
+ } else {
+ if (butp == (si->logical_op == GRN_OP_AND_NOT) &&
+ si->query) {
+ switch (si->op) {
+ case GRN_OP_MATCH :
+ if (keywords->header.type == GRN_PVECTOR) {
+ GRN_PTR_PUT(ctx, keywords, si->query);
+ } else {
+ grn_vector_add_element(ctx,
+ keywords,
+ GRN_TEXT_VALUE(si->query),
+ GRN_TEXT_LEN(si->query),
+ 0,
+ GRN_DB_TEXT);
+ }
+ break;
+ case GRN_OP_SIMILAR :
+ if (keywords->header.type == GRN_VECTOR &&
+ GRN_BULK_VSIZE(&(si->index)) > 0) {
+ grn_token_cursor *token_cursor;
+ unsigned int token_flags = 0;
+ grn_obj *index = GRN_PTR_VALUE(&(si->index));
+ grn_obj *lexicon;
+
+ lexicon = grn_ctx_at(ctx, index->header.domain);
+ token_cursor = grn_token_cursor_open(ctx,
+ lexicon,
+ GRN_TEXT_VALUE(si->query),
+ GRN_TEXT_LEN(si->query),
+ GRN_TOKENIZE_GET,
+ token_flags);
+ if (token_cursor) {
+ grn_obj *source_table;
+ uint32_t n_records_threshold;
+ source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, index));
+ n_records_threshold = grn_table_size(ctx, source_table) / 2;
+ while (token_cursor->status != GRN_TOKEN_CURSOR_DONE) {
+ grn_id token_id;
+ uint32_t n_estimated_records;
+ token_id = grn_token_cursor_next(ctx, token_cursor);
+ if (token_id == GRN_ID_NIL) {
+ continue;
+ }
+ n_estimated_records =
+ grn_ii_estimate_size(ctx, (grn_ii *)index, token_id);
+ if (n_estimated_records >= n_records_threshold) {
+ continue;
+ }
+ grn_vector_add_element(ctx,
+ keywords,
+ token_cursor->curr,
+ token_cursor->curr_size,
+ 0,
+ GRN_DB_TEXT);
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ }
+ break;
+ default :
+ break;
+ }
+ }
+ if (si->flags & SCAN_PUSH) {
+ if (nparens == npbut) {
+ butp = 1 - butp;
+ GRN_UINT32_POP(&but_stack, npbut);
+ }
+ nparens--;
+ }
+ }
+ }
+ GRN_OBJ_FIN(ctx, &but_stack);
+ for (i = n; i--;) { SI_FREE(sis[i]); }
+ GRN_FREE(sis);
+ }
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_rc
+grn_expr_snip_add_conditions(grn_ctx *ctx, grn_obj *expr, grn_obj *snip,
+ unsigned int n_tags,
+ const char **opentags, unsigned int *opentag_lens,
+ const char **closetags, unsigned int *closetag_lens)
+{
+ grn_rc rc;
+ grn_obj keywords;
+
+ GRN_API_ENTER;
+
+ GRN_PTR_INIT(&keywords, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ rc = grn_expr_get_keywords(ctx, expr, &keywords);
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FIN(ctx, &keywords);
+ GRN_API_RETURN(rc);
+ }
+
+ if (n_tags) {
+ int i;
+ for (i = 0;; i = (i + 1) % n_tags) {
+ grn_obj *keyword;
+ GRN_PTR_POP(&keywords, keyword);
+ if (!keyword) { break; }
+ grn_snip_add_cond(ctx, snip,
+ GRN_TEXT_VALUE(keyword), GRN_TEXT_LEN(keyword),
+ opentags[i], opentag_lens[i],
+ closetags[i], closetag_lens[i]);
+ }
+ } else {
+ for (;;) {
+ grn_obj *keyword;
+ GRN_PTR_POP(&keywords, keyword);
+ if (!keyword) { break; }
+ grn_snip_add_cond(ctx, snip,
+ GRN_TEXT_VALUE(keyword), GRN_TEXT_LEN(keyword),
+ NULL, 0, NULL, 0);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &keywords);
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_obj *
+grn_expr_snip(grn_ctx *ctx, grn_obj *expr, int flags,
+ unsigned int width, unsigned int max_results,
+ unsigned int n_tags,
+ const char **opentags, unsigned int *opentag_lens,
+ const char **closetags, unsigned int *closetag_lens,
+ grn_snip_mapping *mapping)
+{
+ grn_obj *res = NULL;
+ GRN_API_ENTER;
+ if ((res = grn_snip_open(ctx, flags, width, max_results,
+ NULL, 0, NULL, 0, mapping))) {
+ grn_expr_snip_add_conditions(ctx, expr, res,
+ n_tags,
+ opentags, opentag_lens,
+ closetags, closetag_lens);
+ }
+ GRN_API_RETURN(res);
+}
+
+/*
+ So far, grn_column_filter() is nothing but a very rough prototype.
+ Although GRN_COLUMN_EACH() can accelerate many range queries,
+ the following stuff must be resolved one by one.
+
+ * support accessors as column
+ * support tables which have deleted records
+ * support various operators
+ * support various column types
+*/
+grn_rc
+grn_column_filter(grn_ctx *ctx, grn_obj *column,
+ grn_operator operator,
+ grn_obj *value, grn_obj *result_set,
+ grn_operator set_operation)
+{
+ uint32_t *vp;
+ grn_posting posting;
+ uint32_t value_ = grn_atoui(GRN_TEXT_VALUE(value), GRN_BULK_CURR(value), NULL);
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ GRN_COLUMN_EACH(ctx, column, id, vp, {
+ if (*vp < value_) {
+ posting.rid = id;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)result_set, set_operation);
+ }
+ });
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)result_set, set_operation);
+ return ctx->rc;
+}
+
+grn_rc
+grn_expr_syntax_escape(grn_ctx *ctx, const char *string, int string_size,
+ const char *target_characters,
+ char escape_character,
+ grn_obj *escaped_string)
+{
+ grn_rc rc = GRN_SUCCESS;
+ const char *current, *string_end;
+
+ if (!string) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ GRN_API_ENTER;
+ if (string_size < 0) {
+ string_size = strlen(string);
+ }
+ string_end = string + string_size;
+
+ current = string;
+ while (current < string_end) {
+ unsigned int char_size;
+ char_size = grn_charlen(ctx, current, string_end);
+ switch (char_size) {
+ case 0 :
+ /* string includes malformed multibyte character. */
+ return GRN_INVALID_ARGUMENT;
+ break;
+ case 1 :
+ if (strchr(target_characters, *current)) {
+ GRN_TEXT_PUTC(ctx, escaped_string, escape_character);
+ }
+ GRN_TEXT_PUT(ctx, escaped_string, current, char_size);
+ current += char_size;
+ break;
+ default :
+ GRN_TEXT_PUT(ctx, escaped_string, current, char_size);
+ current += char_size;
+ break;
+ }
+ }
+
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_expr_syntax_escape_query(grn_ctx *ctx, const char *query, int query_size,
+ grn_obj *escaped_query)
+{
+ const char target_characters[] = {
+ GRN_QUERY_AND,
+ GRN_QUERY_AND_NOT,
+ GRN_QUERY_ADJ_INC,
+ GRN_QUERY_ADJ_DEC,
+ GRN_QUERY_ADJ_NEG,
+ GRN_QUERY_PREFIX,
+ GRN_QUERY_PARENL,
+ GRN_QUERY_PARENR,
+ GRN_QUERY_QUOTEL,
+ GRN_QUERY_ESCAPE,
+ GRN_QUERY_COLUMN,
+ '\0',
+ };
+ return grn_expr_syntax_escape(ctx, query, query_size,
+ target_characters, GRN_QUERY_ESCAPE,
+ escaped_query);
+}
+
+grn_rc
+grn_expr_dump_plan(grn_ctx *ctx, grn_obj *expr, grn_obj *buffer)
+{
+ int n;
+ scan_info **sis;
+
+ GRN_API_ENTER;
+ sis = grn_scan_info_build(ctx, expr, &n, GRN_OP_OR, GRN_FALSE);
+ if (sis) {
+ int i;
+ grn_inspect_scan_info_list(ctx, buffer, sis, n);
+ for (i = 0; i < n; i++) {
+ SI_FREE(sis[i]);
+ }
+ GRN_FREE(sis);
+ } else {
+ GRN_TEXT_PUTS(ctx, buffer, "sequential search\n");
+ }
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+static unsigned int
+grn_expr_estimate_size_raw(grn_ctx *ctx, grn_obj *expr, grn_obj *table)
+{
+ return grn_table_size(ctx, table);
+}
+
+unsigned int
+grn_expr_estimate_size(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_obj *table;
+ grn_obj *variable;
+ unsigned int size;
+
+ variable = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (!variable) {
+ ERR(GRN_INVALID_ARGUMENT, "at least one variable must be defined");
+ return 0;
+ }
+
+ table = grn_ctx_at(ctx, variable->header.domain);
+ if (!table) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "variable refers unknown domain: <%u>", variable->header.domain);
+ return 0;
+ }
+
+ GRN_API_ENTER;
+#ifdef GRN_WITH_MRUBY
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ GRN_API_RETURN(0);
+ }
+ if (ctx->impl->mrb.state) {
+ size = grn_mrb_expr_estimate_size(ctx, expr, table);
+ } else {
+ size = grn_expr_estimate_size_raw(ctx, expr, table);
+ }
+#else
+ size = grn_expr_estimate_size_raw(ctx, expr, table);
+#endif
+ GRN_API_RETURN(size);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/expr_code.c b/storage/mroonga/vendor/groonga/lib/expr_code.c
new file mode 100644
index 00000000..a2dfc60b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/expr_code.c
@@ -0,0 +1,55 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_expr_code.h"
+
+unsigned int
+grn_expr_code_n_used_codes(grn_ctx *ctx,
+ grn_expr_code *start,
+ grn_expr_code *target)
+{
+ unsigned int n_codes;
+ int i, n_args;
+ grn_expr_code *sub_code;
+
+ if (start == target) {
+ return 0;
+ }
+
+ n_args = target->nargs;
+ if (target->value) {
+ n_args--;
+ if (n_args == 0) {
+ return 1;
+ }
+ }
+
+ n_codes = 1;
+ sub_code = target - 1;
+ for (i = 0; i < n_args; i++) {
+ int sub_n_codes;
+ sub_n_codes = grn_expr_code_n_used_codes(ctx, start, sub_code);
+ n_codes += sub_n_codes;
+ sub_code -= sub_n_codes;
+ if (sub_code < start) {
+ /* TODO: report error */
+ return 0;
+ }
+ }
+
+ return n_codes;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/expr_executor.c b/storage/mroonga/vendor/groonga/lib/expr_executor.c
new file mode 100644
index 00000000..bc78a650
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/expr_executor.c
@@ -0,0 +1,945 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_ctx_impl.h"
+#include "grn_expr_executor.h"
+
+#ifdef GRN_WITH_ONIGMO
+# define GRN_SUPPORT_REGEXP
+#endif
+
+#ifdef GRN_SUPPORT_REGEXP
+# include "grn_normalizer.h"
+# include <onigmo.h>
+#endif
+
+typedef union {
+ struct {
+ grn_obj result_buffer;
+ } constant;
+ struct {
+ grn_obj *column;
+ grn_obj value_buffer;
+ } value;
+#ifdef GRN_SUPPORT_REGEXP
+ struct {
+ grn_obj result_buffer;
+ OnigRegex regex;
+ grn_obj value_buffer;
+ grn_obj *normalizer;
+ } simple_regexp;
+#endif /* GRN_SUPPORT_REGEXP */
+ struct {
+ grn_proc_ctx proc_ctx;
+ int n_args;
+ } proc;
+ struct {
+ grn_obj result_buffer;
+ grn_ra *ra;
+ grn_ra_cache ra_cache;
+ unsigned int ra_element_size;
+ grn_obj value_buffer;
+ grn_obj constant_buffer;
+ grn_operator_exec_func *exec;
+ } simple_condition_ra;
+ struct {
+ grn_bool need_exec;
+ grn_obj result_buffer;
+ grn_obj value_buffer;
+ grn_obj constant_buffer;
+ grn_operator_exec_func *exec;
+ } simple_condition;
+} grn_expr_executor_data;
+
+typedef grn_obj *(*grn_expr_executor_exec_func)(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id);
+typedef void (*grn_expr_executor_fin_func)(grn_ctx *ctx,
+ grn_expr_executor *executor);
+
+struct _grn_expr_executor {
+ grn_obj *expr;
+ grn_obj *variable;
+ grn_expr_executor_exec_func exec;
+ grn_expr_executor_fin_func fin;
+ grn_expr_executor_data data;
+};
+
+static void
+grn_expr_executor_init_general(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+}
+
+static grn_obj *
+grn_expr_executor_exec_general(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ GRN_RECORD_SET(ctx, executor->variable, id);
+ return grn_expr_exec(ctx, executor->expr, 0);
+}
+
+static void
+grn_expr_executor_fin_general(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+}
+
+static grn_bool
+grn_expr_executor_is_constant(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *target;
+
+ if (e->codes_curr != 1) {
+ return GRN_FALSE;
+ }
+
+ target = &(e->codes[0]);
+
+ if (target->op != GRN_OP_PUSH) {
+ return GRN_FALSE;
+ }
+ if (!target->value) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_constant(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_obj *result_buffer = &(executor->data.constant.result_buffer);
+ grn_obj *result;
+
+ GRN_VOID_INIT(result_buffer);
+ result = grn_expr_exec(ctx, executor->expr, 0);
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_obj_reinit(ctx,
+ result_buffer,
+ result->header.domain,
+ result->header.flags);
+ /* TODO: Support vector */
+ grn_bulk_write(ctx,
+ result_buffer,
+ GRN_BULK_HEAD(result),
+ GRN_BULK_VSIZE(result));
+ }
+}
+
+static grn_obj *
+grn_expr_executor_exec_constant(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ return &(executor->data.constant.result_buffer);
+}
+
+static void
+grn_expr_executor_fin_constant(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ GRN_OBJ_FIN(ctx, &(executor->data.constant.result_buffer));
+}
+
+static grn_bool
+grn_expr_executor_is_value(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *target;
+
+ if (e->codes_curr != 1) {
+ return GRN_FALSE;
+ }
+
+ target = &(e->codes[0]);
+
+ if (target->op != GRN_OP_GET_VALUE) {
+ return GRN_FALSE;
+ }
+ if (!target->value) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_value(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_expr *e = (grn_expr *)(executor->expr);
+
+ executor->data.value.column = e->codes[0].value;
+ GRN_VOID_INIT(&(executor->data.value.value_buffer));
+}
+
+static grn_obj *
+grn_expr_executor_exec_value(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_obj *value_buffer = &(executor->data.value.value_buffer);
+
+ GRN_BULK_REWIND(value_buffer);
+ grn_obj_get_value(ctx, executor->data.value.column, id, value_buffer);
+
+ return value_buffer;
+}
+
+static void
+grn_expr_executor_fin_value(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ GRN_OBJ_FIN(ctx, &(executor->data.value.value_buffer));
+}
+
+#ifdef GRN_SUPPORT_REGEXP
+static grn_bool
+grn_expr_executor_is_simple_regexp(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *target;
+ grn_expr_code *pattern;
+ grn_expr_code *operator;
+
+ if (e->codes_curr != 3) {
+ return GRN_FALSE;
+ }
+
+ target = &(e->codes[0]);
+ pattern = &(e->codes[1]);
+ operator = &(e->codes[2]);
+
+ if (operator->op != GRN_OP_REGEXP) {
+ return GRN_FALSE;
+ }
+ if (operator->nargs != 2) {
+ return GRN_FALSE;
+ }
+
+ if (target->op != GRN_OP_GET_VALUE) {
+ return GRN_FALSE;
+ }
+ if (target->nargs != 1) {
+ return GRN_FALSE;
+ }
+ if (!target->value) {
+ return GRN_FALSE;
+ }
+ if (target->value->header.type != GRN_COLUMN_VAR_SIZE) {
+ return GRN_FALSE;
+ }
+ if ((target->value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) !=
+ GRN_OBJ_COLUMN_SCALAR) {
+ return GRN_FALSE;
+ }
+ switch (grn_obj_get_range(ctx, target->value)) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+
+ if (pattern->op != GRN_OP_PUSH) {
+ return GRN_FALSE;
+ }
+ if (pattern->nargs != 1) {
+ return GRN_FALSE;
+ }
+ if (!pattern->value) {
+ return GRN_FALSE;
+ }
+ if (pattern->value->header.type != GRN_BULK) {
+ return GRN_FALSE;
+ }
+ switch (pattern->value->header.domain) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_simple_regexp(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_expr *e = (grn_expr *)(executor->expr);
+ grn_obj *result_buffer = &(executor->data.simple_regexp.result_buffer);
+ OnigEncoding onig_encoding;
+ int onig_result;
+ OnigErrorInfo onig_error_info;
+ grn_obj *pattern;
+
+ GRN_BOOL_INIT(result_buffer, 0);
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+
+ if (ctx->encoding == GRN_ENC_NONE) {
+ executor->data.simple_regexp.regex = NULL;
+ return;
+ }
+
+ switch (ctx->encoding) {
+ case GRN_ENC_EUC_JP :
+ onig_encoding = ONIG_ENCODING_EUC_JP;
+ break;
+ case GRN_ENC_UTF8 :
+ onig_encoding = ONIG_ENCODING_UTF8;
+ break;
+ case GRN_ENC_SJIS :
+ onig_encoding = ONIG_ENCODING_CP932;
+ break;
+ case GRN_ENC_LATIN1 :
+ onig_encoding = ONIG_ENCODING_ISO_8859_1;
+ break;
+ case GRN_ENC_KOI8R :
+ onig_encoding = ONIG_ENCODING_KOI8_R;
+ break;
+ default :
+ executor->data.simple_regexp.regex = NULL;
+ return;
+ }
+
+ pattern = e->codes[1].value;
+ onig_result = onig_new(&(executor->data.simple_regexp.regex),
+ GRN_TEXT_VALUE(pattern),
+ GRN_TEXT_VALUE(pattern) + GRN_TEXT_LEN(pattern),
+ ONIG_OPTION_ASCII_RANGE |
+ ONIG_OPTION_MULTILINE,
+ onig_encoding,
+ ONIG_SYNTAX_RUBY,
+ &onig_error_info);
+ if (onig_result != ONIG_NORMAL) {
+ char message[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str(message, onig_result, onig_error_info);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[expr-executor][regexp] "
+ "failed to create regular expression object: <%.*s>: %s",
+ (int)GRN_TEXT_LEN(pattern), GRN_TEXT_VALUE(pattern),
+ message);
+ return;
+ }
+
+ GRN_VOID_INIT(&(executor->data.simple_regexp.value_buffer));
+
+ executor->data.simple_regexp.normalizer =
+ grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+}
+
+static grn_obj *
+grn_expr_executor_exec_simple_regexp(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_expr *e = (grn_expr *)(executor->expr);
+ OnigRegex regex = executor->data.simple_regexp.regex;
+ grn_obj *value_buffer = &(executor->data.simple_regexp.value_buffer);
+ grn_obj *result_buffer = &(executor->data.simple_regexp.result_buffer);
+
+ if (ctx->rc) {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+ return result_buffer;
+ }
+
+ if (!regex) {
+ return result_buffer;
+ }
+
+ grn_obj_reinit_for(ctx, value_buffer, e->codes[0].value);
+ grn_obj_get_value(ctx, e->codes[0].value, id, value_buffer);
+ {
+ grn_obj *norm_target;
+ const char *norm_target_raw;
+ unsigned int norm_target_raw_length_in_bytes;
+
+ norm_target = grn_string_open(ctx,
+ GRN_TEXT_VALUE(value_buffer),
+ GRN_TEXT_LEN(value_buffer),
+ executor->data.simple_regexp.normalizer,
+ 0);
+ grn_string_get_normalized(ctx, norm_target,
+ &norm_target_raw,
+ &norm_target_raw_length_in_bytes,
+ NULL);
+
+ {
+ OnigPosition position;
+ position = onig_search(regex,
+ norm_target_raw,
+ norm_target_raw + norm_target_raw_length_in_bytes,
+ norm_target_raw,
+ norm_target_raw + norm_target_raw_length_in_bytes,
+ NULL,
+ ONIG_OPTION_NONE);
+ grn_obj_close(ctx, norm_target);
+ GRN_BOOL_SET(ctx, result_buffer, (position != ONIG_MISMATCH));
+ return result_buffer;
+ }
+ }
+}
+
+static void
+grn_expr_executor_fin_simple_regexp(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_regexp.result_buffer));
+
+ if (!executor->data.simple_regexp.regex) {
+ return;
+ }
+
+ onig_free(executor->data.simple_regexp.regex);
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_regexp.value_buffer));
+}
+#endif /* GRN_SUPPORT_REGEXP */
+
+static grn_bool
+grn_expr_executor_is_proc(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_obj *first;
+ grn_proc *proc;
+
+ if (e->codes_curr < 2) {
+ return GRN_FALSE;
+ }
+
+ first = e->codes[0].value;
+ if (!grn_obj_is_function_proc(ctx, first)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)first;
+ if (!(proc->funcs[PROC_INIT] &&
+ proc->funcs[PROC_NEXT])) {
+ return GRN_FALSE;
+ }
+
+ if (e->codes[e->codes_curr - 1].op != GRN_OP_CALL) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_proc(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_proc_ctx *proc_ctx = &(executor->data.proc.proc_ctx);
+ grn_expr *expr;
+ grn_proc *proc;
+
+ expr = (grn_expr *)(executor->expr);
+ proc = (grn_proc *)(expr->codes[0].value);
+ proc_ctx->proc = proc;
+ proc_ctx->caller = executor->expr;
+ proc_ctx->phase = PROC_INIT;
+
+ executor->data.proc.n_args = expr->codes[expr->codes_curr - 1].nargs - 1;
+
+ proc->funcs[PROC_INIT](ctx, 0, NULL, &(proc_ctx->user_data));
+}
+
+static grn_obj *
+grn_expr_executor_exec_proc(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_proc_ctx *proc_ctx = &(executor->data.proc.proc_ctx);
+ int n_args = executor->data.proc.n_args;
+ grn_proc *proc;
+ grn_expr *expr;
+ grn_obj **args;
+ uint32_t values_curr;
+ uint32_t values_tail;
+ grn_obj *result;
+
+ proc = proc_ctx->proc;
+ proc_ctx->phase = PROC_NEXT;
+ GRN_RECORD_SET(ctx, executor->variable, id);
+
+ expr = (grn_expr *)(executor->expr);
+ values_curr = expr->values_curr;
+ values_tail = expr->values_tail;
+
+ expr->codes += 1;
+ expr->codes_curr -= 2;
+ grn_expr_exec(ctx, executor->expr, 0);
+ expr->codes_curr += 2;
+ expr->codes -= 1;
+
+ args = ctx->impl->stack + ctx->impl->stack_curr;
+ ctx->impl->stack_curr += n_args;
+ expr->values_curr = expr->values_tail;
+ result = proc->funcs[PROC_NEXT](ctx,
+ n_args,
+ args,
+ &(proc_ctx->user_data));
+ ctx->impl->stack_curr -= n_args;
+
+ expr->values_tail = values_tail;
+ expr->values_curr = values_curr;
+
+ return result;
+}
+
+static void
+grn_expr_executor_fin_proc(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_proc_ctx *proc_ctx = &(executor->data.proc.proc_ctx);
+ grn_proc *proc;
+
+ proc = proc_ctx->proc;
+ proc_ctx->phase = PROC_FIN;
+ if (proc->funcs[PROC_FIN]) {
+ proc->funcs[PROC_FIN](ctx, 0, NULL, &(proc_ctx->user_data));
+ }
+}
+
+static grn_bool
+grn_expr_executor_is_simple_condition_ra(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *target;
+ grn_expr_code *constant;
+ grn_expr_code *operator;
+
+ if (e->codes_curr != 3) {
+ return GRN_FALSE;
+ }
+
+ target = &(e->codes[0]);
+ constant = &(e->codes[1]);
+ operator = &(e->codes[2]);
+
+ switch (operator->op) {
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+ if (operator->nargs != 2) {
+ return GRN_FALSE;
+ }
+
+ if (target->op != GRN_OP_GET_VALUE) {
+ return GRN_FALSE;
+ }
+ if (target->nargs != 1) {
+ return GRN_FALSE;
+ }
+ if (target->value->header.type != GRN_COLUMN_FIX_SIZE) {
+ return GRN_FALSE;
+ }
+
+ if (constant->op != GRN_OP_PUSH) {
+ return GRN_FALSE;
+ }
+ if (constant->nargs != 1) {
+ return GRN_FALSE;
+ }
+ if (!constant->value) {
+ return GRN_FALSE;
+ }
+ if (constant->value->header.type != GRN_BULK) {
+ return GRN_FALSE;
+ }
+
+ {
+ grn_obj constant_buffer;
+ grn_rc rc;
+ GRN_VOID_INIT(&constant_buffer);
+ grn_obj_reinit_for(ctx, &constant_buffer, target->value);
+ rc = grn_obj_cast(ctx, constant->value, &constant_buffer, GRN_FALSE);
+ GRN_OBJ_FIN(ctx, &constant_buffer);
+ if (rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_simple_condition_ra(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_expr *e = (grn_expr *)(executor->expr);
+ grn_obj *target;
+ grn_obj *constant;
+ grn_operator op;
+ grn_obj *result_buffer;
+ grn_obj *value_buffer;
+ grn_obj *constant_buffer;
+
+ target = e->codes[0].value;
+ constant = e->codes[1].value;
+ op = e->codes[2].op;
+
+ result_buffer = &(executor->data.simple_condition_ra.result_buffer);
+ GRN_BOOL_INIT(result_buffer, 0);
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+
+ value_buffer = &(executor->data.simple_condition_ra.value_buffer);
+ GRN_VOID_INIT(value_buffer);
+ grn_obj_reinit_for(ctx, value_buffer, target);
+
+ executor->data.simple_condition_ra.ra = (grn_ra *)target;
+ GRN_RA_CACHE_INIT(executor->data.simple_condition_ra.ra,
+ &(executor->data.simple_condition_ra.ra_cache));
+ grn_ra_info(ctx,
+ executor->data.simple_condition_ra.ra,
+ &(executor->data.simple_condition_ra.ra_element_size));
+
+ executor->data.simple_condition_ra.exec = grn_operator_to_exec_func(op);
+
+ constant_buffer = &(executor->data.simple_condition_ra.constant_buffer);
+ GRN_VOID_INIT(constant_buffer);
+ grn_obj_reinit_for(ctx, constant_buffer, target);
+ grn_obj_cast(ctx, constant, constant_buffer, GRN_FALSE);
+}
+
+static grn_obj *
+grn_expr_executor_exec_simple_condition_ra(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_obj *result_buffer = &(executor->data.simple_condition_ra.result_buffer);
+ grn_obj *value_buffer = &(executor->data.simple_condition_ra.value_buffer);
+ grn_obj *constant_buffer =
+ &(executor->data.simple_condition_ra.constant_buffer);
+
+ if (ctx->rc) {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+ return result_buffer;
+ }
+
+ {
+ grn_ra *ra = executor->data.simple_condition_ra.ra;
+ grn_ra_cache *ra_cache = &(executor->data.simple_condition_ra.ra_cache);
+ unsigned int ra_element_size =
+ executor->data.simple_condition_ra.ra_element_size;
+ void *raw_value;
+ raw_value = grn_ra_ref_cache(ctx, ra, id, ra_cache);
+ GRN_BULK_REWIND(value_buffer);
+ grn_bulk_write(ctx, value_buffer, raw_value, ra_element_size);
+ }
+
+ if (executor->data.simple_condition_ra.exec(ctx,
+ value_buffer,
+ constant_buffer)) {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_TRUE);
+ } else {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+ }
+ return result_buffer;
+}
+
+static void
+grn_expr_executor_fin_simple_condition_ra(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition_ra.result_buffer));
+ GRN_RA_CACHE_FIN(executor->data.simple_condition_ra.ra,
+ &(executor->data.simple_condition_ra.ra_cache));
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition_ra.value_buffer));
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition_ra.constant_buffer));
+}
+
+static grn_bool
+grn_expr_executor_is_simple_condition(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+ grn_expr_code *target;
+ grn_expr_code *constant;
+ grn_expr_code *operator;
+
+ if (e->codes_curr != 3) {
+ return GRN_FALSE;
+ }
+
+ target = &(e->codes[0]);
+ constant = &(e->codes[1]);
+ operator = &(e->codes[2]);
+
+ switch (operator->op) {
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ case GRN_OP_LESS :
+ case GRN_OP_GREATER :
+ case GRN_OP_LESS_EQUAL :
+ case GRN_OP_GREATER_EQUAL :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+ if (operator->nargs != 2) {
+ return GRN_FALSE;
+ }
+
+ if (target->op != GRN_OP_GET_VALUE) {
+ return GRN_FALSE;
+ }
+ if (target->nargs != 1) {
+ return GRN_FALSE;
+ }
+ if (!grn_obj_is_scalar_column(ctx, target->value)) {
+ return GRN_FALSE;
+ }
+
+ if (constant->op != GRN_OP_PUSH) {
+ return GRN_FALSE;
+ }
+ if (constant->nargs != 1) {
+ return GRN_FALSE;
+ }
+ if (!constant->value) {
+ return GRN_FALSE;
+ }
+ if (constant->value->header.type != GRN_BULK) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_expr_executor_init_simple_condition(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ grn_expr *e = (grn_expr *)(executor->expr);
+ grn_obj *target;
+ grn_obj *constant;
+ grn_operator op;
+ grn_obj *result_buffer;
+ grn_obj *value_buffer;
+ grn_obj *constant_buffer;
+ grn_rc rc;
+
+ target = e->codes[0].value;
+ constant = e->codes[1].value;
+ op = e->codes[2].op;
+
+ executor->data.simple_condition.need_exec = GRN_TRUE;
+
+ result_buffer = &(executor->data.simple_condition.result_buffer);
+ GRN_BOOL_INIT(result_buffer, 0);
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+
+ value_buffer = &(executor->data.simple_condition.value_buffer);
+ GRN_VOID_INIT(value_buffer);
+ grn_obj_reinit_for(ctx, value_buffer, target);
+
+ executor->data.simple_condition.exec = grn_operator_to_exec_func(op);
+
+ constant_buffer = &(executor->data.simple_condition.constant_buffer);
+ GRN_VOID_INIT(constant_buffer);
+ grn_obj_reinit_for(ctx, constant_buffer, target);
+ rc = grn_obj_cast(ctx, constant, constant_buffer, GRN_FALSE);
+ if (rc != GRN_SUCCESS) {
+ grn_obj *type;
+
+ type = grn_ctx_at(ctx, constant_buffer->header.domain);
+ if (grn_obj_is_table(ctx, type)) {
+ GRN_BOOL_SET(ctx, result_buffer, (op == GRN_OP_NOT_EQUAL));
+ executor->data.simple_condition.need_exec = GRN_FALSE;
+ } else {
+ int type_name_size;
+ char type_name[GRN_TABLE_MAX_KEY_SIZE];
+ grn_obj inspected;
+
+ type_name_size = grn_obj_name(ctx, type, type_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, constant);
+ ERR(rc,
+ "[expr-executor][condition] "
+ "failed to cast to <%.*s>: <%.*s>",
+ type_name_size, type_name,
+ (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
+ }
+ }
+}
+
+static grn_obj *
+grn_expr_executor_exec_simple_condition(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id)
+{
+ grn_expr *e = (grn_expr *)(executor->expr);
+ grn_obj *target;
+ grn_obj *result_buffer = &(executor->data.simple_condition.result_buffer);
+ grn_obj *value_buffer = &(executor->data.simple_condition.value_buffer);
+ grn_obj *constant_buffer = &(executor->data.simple_condition.constant_buffer);
+
+ if (ctx->rc) {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+ return result_buffer;
+ }
+
+ if (!executor->data.simple_condition.need_exec) {
+ return result_buffer;
+ }
+
+ target = e->codes[0].value;
+ GRN_BULK_REWIND(value_buffer);
+ grn_obj_get_value(ctx, target, id, value_buffer);
+
+ if (executor->data.simple_condition.exec(ctx, value_buffer, constant_buffer)) {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_TRUE);
+ } else {
+ GRN_BOOL_SET(ctx, result_buffer, GRN_FALSE);
+ }
+ return result_buffer;
+}
+
+static void
+grn_expr_executor_fin_simple_condition(grn_ctx *ctx,
+ grn_expr_executor *executor)
+{
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition.result_buffer));
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition.value_buffer));
+ GRN_OBJ_FIN(ctx, &(executor->data.simple_condition.constant_buffer));
+}
+
+grn_expr_executor *
+grn_expr_executor_open(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_obj *variable;
+ grn_expr_executor *executor;
+
+ GRN_API_ENTER;
+
+ if (!grn_obj_is_expr(ctx, expr)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, expr);
+ ERR(ctx->rc,
+ "[expr-executor][open] invalid expression: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(NULL);
+ }
+
+ variable = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (!variable) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, expr);
+ ERR(ctx->rc,
+ "[expr-executor][open] expression has no variable: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(NULL);
+ }
+
+ executor = GRN_CALLOC(sizeof(grn_expr_executor));
+ if (!executor) {
+ ERR(ctx->rc,
+ "[expr-executor][open] failed to allocate: %s",
+ ctx->errbuf);
+ GRN_API_RETURN(NULL);
+ }
+
+ executor->expr = expr;
+ executor->variable = variable;
+ if (grn_expr_executor_is_constant(ctx, expr)) {
+ grn_expr_executor_init_constant(ctx, executor);
+ executor->exec = grn_expr_executor_exec_constant;
+ executor->fin = grn_expr_executor_fin_constant;
+ } else if (grn_expr_executor_is_value(ctx, expr)) {
+ grn_expr_executor_init_value(ctx, executor);
+ executor->exec = grn_expr_executor_exec_value;
+ executor->fin = grn_expr_executor_fin_value;
+#ifdef GRN_SUPPORT_REGEXP
+ } else if (grn_expr_executor_is_simple_regexp(ctx, expr)) {
+ grn_expr_executor_init_simple_regexp(ctx, executor);
+ executor->exec = grn_expr_executor_exec_simple_regexp;
+ executor->fin = grn_expr_executor_fin_simple_regexp;
+#endif /* GRN_SUPPORT_REGEXP */
+ } else if (grn_expr_executor_is_proc(ctx, expr)) {
+ grn_expr_executor_init_proc(ctx, executor);
+ executor->exec = grn_expr_executor_exec_proc;
+ executor->fin = grn_expr_executor_fin_proc;
+ } else if (grn_expr_executor_is_simple_condition_ra(ctx, expr)) {
+ grn_expr_executor_init_simple_condition_ra(ctx, executor);
+ executor->exec = grn_expr_executor_exec_simple_condition_ra;
+ executor->fin = grn_expr_executor_fin_simple_condition_ra;
+ } else if (grn_expr_executor_is_simple_condition(ctx, expr)) {
+ grn_expr_executor_init_simple_condition(ctx, executor);
+ executor->exec = grn_expr_executor_exec_simple_condition;
+ executor->fin = grn_expr_executor_fin_simple_condition;
+ } else {
+ grn_expr_executor_init_general(ctx, executor);
+ executor->exec = grn_expr_executor_exec_general;
+ executor->fin = grn_expr_executor_fin_general;
+ }
+
+ GRN_API_RETURN(executor);
+}
+
+grn_obj *
+grn_expr_executor_exec(grn_ctx *ctx, grn_expr_executor *executor, grn_id id)
+{
+ grn_obj *value;
+
+ GRN_API_ENTER;
+
+ if (!executor) {
+ GRN_API_RETURN(NULL);
+ }
+
+ value = executor->exec(ctx, executor, id);
+
+ GRN_API_RETURN(value);
+}
+
+grn_rc
+grn_expr_executor_close(grn_ctx *ctx, grn_expr_executor *executor)
+{
+ GRN_API_ENTER;
+
+ if (!executor) {
+ GRN_API_RETURN(GRN_SUCCESS);
+ }
+
+ executor->fin(ctx, executor);
+ GRN_FREE(executor);
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/file_lock.c b/storage/mroonga/vendor/groonga/lib/file_lock.c
new file mode 100644
index 00000000..3cf8acf1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/file_lock.c
@@ -0,0 +1,121 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_file_lock.h"
+#include "grn_ctx.h"
+
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <io.h>
+# include <share.h>
+#else /* WIN32 */
+# include <sys/types.h>
+# include <fcntl.h>
+#endif /* WIN32 */
+
+#ifdef WIN32
+# define GRN_FILE_LOCK_IS_INVALID(file_lock) \
+ ((file_lock)->handle == INVALID_HANDLE_VALUE)
+#else /* WIN32 */
+# define GRN_FILE_LOCK_IS_INVALID(file_lock) \
+ ((file_lock)->fd == -1)
+#endif /* WIN32 */
+
+void
+grn_file_lock_init(grn_ctx *ctx,
+ grn_file_lock *file_lock,
+ const char *path)
+{
+ file_lock->path = path;
+#ifdef WIN32
+ file_lock->handle = INVALID_HANDLE_VALUE;
+#else /* WIN32 */
+ file_lock->fd = -1;
+#endif /* WIN32 */
+}
+
+grn_bool
+grn_file_lock_acquire(grn_ctx *ctx,
+ grn_file_lock *file_lock,
+ int timeout,
+ const char *error_message_tag)
+{
+ int i;
+ int n_lock_tries = timeout;
+
+ if (!file_lock->path) {
+ return GRN_TRUE;
+ }
+
+ for (i = 0; i < n_lock_tries; i++) {
+#ifdef WIN32
+ file_lock->handle = CreateFile(file_lock->path,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+#else /* WIN32 */
+ file_lock->fd = open(file_lock->path, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+#endif
+ if (!GRN_FILE_LOCK_IS_INVALID(file_lock)) {
+ break;
+ }
+ grn_nanosleep(GRN_LOCK_WAIT_TIME_NANOSECOND);
+ }
+
+ if (GRN_FILE_LOCK_IS_INVALID(file_lock)) {
+ ERR(GRN_NO_LOCKS_AVAILABLE,
+ "%s failed to acquire lock: <%s>",
+ error_message_tag, file_lock->path);
+ return GRN_FALSE;
+ } else {
+ return GRN_TRUE;
+ }
+}
+
+void
+grn_file_lock_release(grn_ctx *ctx, grn_file_lock *file_lock)
+{
+ if (GRN_FILE_LOCK_IS_INVALID(file_lock)) {
+ return;
+ }
+
+#ifdef WIN32
+ CloseHandle(file_lock->handle);
+ DeleteFile(file_lock->path);
+
+ file_lock->handle = INVALID_HANDLE_VALUE;
+#else /* WIN32 */
+ close(file_lock->fd);
+ unlink(file_lock->path);
+
+ file_lock->fd = -1;
+#endif /* WIN32 */
+ file_lock->path = NULL;
+}
+
+void
+grn_file_lock_fin(grn_ctx *ctx, grn_file_lock *file_lock)
+{
+ if (!GRN_FILE_LOCK_IS_INVALID(file_lock)) {
+ grn_file_lock_release(ctx, file_lock);
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/file_reader.c b/storage/mroonga/vendor/groonga/lib/file_reader.c
new file mode 100644
index 00000000..0ba23274
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/file_reader.c
@@ -0,0 +1,109 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx.h"
+#include "grn_str.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <share.h>
+#endif /* WIN32 */
+
+struct _grn_file_reader {
+ FILE *file;
+ grn_bool file_need_close;
+};
+
+grn_file_reader *
+grn_file_reader_open(grn_ctx *ctx, const char *path)
+{
+ grn_file_reader *reader;
+ FILE *file;
+ grn_bool file_need_close;
+
+ GRN_API_ENTER;
+
+ if (!path) {
+ ERR(GRN_INVALID_ARGUMENT, "[file-reader][open] path must not NULL");
+ GRN_API_RETURN(NULL);
+ }
+
+ if (strcmp(path, "-") == 0) {
+ file = stdin;
+ file_need_close = GRN_FALSE;
+ } else {
+ file = grn_fopen(path, "r");
+ if (!file) {
+ SERR("[file-reader][open] failed to open path: <%s>", path);
+ GRN_API_RETURN(NULL);
+ }
+ file_need_close = GRN_TRUE;
+ }
+
+ reader = GRN_MALLOC(sizeof(grn_file_reader));
+ reader->file = file;
+ reader->file_need_close = file_need_close;
+
+ GRN_API_RETURN(reader);
+}
+
+void
+grn_file_reader_close(grn_ctx *ctx, grn_file_reader *reader)
+{
+ if (!reader) {
+ return;
+ }
+
+ if (reader->file_need_close) {
+ if (fclose(reader->file) != 0) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "[file-reader][close] failed to close: <%s>",
+ grn_strerror(errno));
+ }
+ }
+
+ GRN_FREE(reader);
+}
+
+grn_rc
+grn_file_reader_read_line(grn_ctx *ctx,
+ grn_file_reader *reader,
+ grn_obj *buffer)
+{
+ grn_rc rc = GRN_END_OF_DATA;
+
+ for (;;) {
+ size_t len;
+
+#define BUFFER_SIZE 4096
+ grn_bulk_reserve(ctx, buffer, BUFFER_SIZE);
+ if (!fgets(GRN_BULK_CURR(buffer), BUFFER_SIZE, reader->file)) {
+ break;
+ }
+#undef BUFFER_SIZE
+
+ if (!(len = strlen(GRN_BULK_CURR(buffer)))) { break; }
+ GRN_BULK_INCR_LEN(buffer, len);
+ rc = GRN_SUCCESS;
+ if (GRN_BULK_CURR(buffer)[-1] == '\n') { break; }
+ }
+
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/geo.c b/storage/mroonga/vendor/groonga/lib/geo.c
new file mode 100644
index 00000000..ec37985e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/geo.c
@@ -0,0 +1,2789 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_geo.h"
+#include "grn_pat.h"
+#include "grn_util.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#define GRN_GEO_POINT_IN_NORTH_EAST(point) \
+ ((point)->latitude >= 0 && (point)->longitude >= 0)
+#define GRN_GEO_POINT_IN_NORTH_WEST(point) \
+ ((point)->latitude >= 0 && (point)->longitude < 0)
+#define GRN_GEO_POINT_IN_SOUTH_WEST(point) \
+ ((point)->latitude < 0 && (point)->longitude < 0)
+#define GRN_GEO_POINT_IN_SOUTH_EAST(point) \
+ ((point)->latitude < 0 && (point)->longitude >= 0)
+
+#define GRN_GEO_LONGITUDE_IS_WRAPPED(top_left, bottom_right) \
+ ((top_left)->longitude > 0 && (bottom_right)->longitude < 0)
+
+typedef struct {
+ grn_id id;
+ double d;
+} geo_entry;
+
+typedef struct
+{
+ grn_geo_point key;
+ int key_size;
+} mesh_entry;
+
+typedef struct {
+ grn_obj *pat;
+ grn_obj top_left_point_buffer;
+ grn_obj bottom_right_point_buffer;
+ grn_geo_point *top_left;
+ grn_geo_point *bottom_right;
+} in_rectangle_data;
+
+typedef struct {
+ grn_geo_point min;
+ grn_geo_point max;
+ int rectangle_common_bit;
+ uint8_t rectangle_common_key[sizeof(grn_geo_point)];
+} in_rectangle_area_data;
+
+static int
+compute_diff_bit(uint8_t *geo_key1, uint8_t *geo_key2)
+{
+ size_t i;
+ int j, diff_bit = 0;
+
+ for (i = 0; i < sizeof(grn_geo_point); i++) {
+ if (geo_key1[i] != geo_key2[i]) {
+ diff_bit = 8;
+ for (j = 0; j < 8; j++) {
+ if ((geo_key1[i] & (1 << (7 - j))) != (geo_key2[i] & (1 << (7 - j)))) {
+ diff_bit = j;
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ return i * 8 + diff_bit;
+}
+
+static void
+compute_min_and_max_key(uint8_t *key_base, int diff_bit,
+ uint8_t *key_min, uint8_t *key_max)
+{
+ int diff_byte, diff_bit_mask;
+
+ diff_byte = diff_bit / 8;
+ diff_bit_mask = 0xff >> (diff_bit % 8);
+
+ if (diff_byte == sizeof(grn_geo_point)) {
+ if (key_min) { grn_memcpy(key_min, key_base, diff_byte); }
+ if (key_max) { grn_memcpy(key_max, key_base, diff_byte); }
+ } else {
+ if (key_min) {
+ grn_memcpy(key_min, key_base, diff_byte + 1);
+ key_min[diff_byte] &= ~diff_bit_mask;
+ memset(key_min + diff_byte + 1, 0,
+ sizeof(grn_geo_point) - diff_byte - 1);
+ }
+
+ if (key_max) {
+ grn_memcpy(key_max, key_base, diff_byte + 1);
+ key_max[diff_byte] |= diff_bit_mask;
+ memset(key_max + diff_byte + 1, 0xff,
+ sizeof(grn_geo_point) - diff_byte - 1);
+ }
+ }
+}
+
+static void
+compute_min_and_max(grn_geo_point *base_point, int diff_bit,
+ grn_geo_point *geo_min, grn_geo_point *geo_max)
+{
+ uint8_t geo_key_base[sizeof(grn_geo_point)];
+ uint8_t geo_key_min[sizeof(grn_geo_point)];
+ uint8_t geo_key_max[sizeof(grn_geo_point)];
+
+ grn_gton(geo_key_base, base_point, sizeof(grn_geo_point));
+ compute_min_and_max_key(geo_key_base, diff_bit,
+ geo_min ? geo_key_min : NULL,
+ geo_max ? geo_key_max : NULL);
+ if (geo_min) {
+ grn_ntog((uint8_t *)geo_min, geo_key_min, sizeof(grn_geo_point));
+ }
+ if (geo_max) {
+ grn_ntog((uint8_t *)geo_max, geo_key_max, sizeof(grn_geo_point));
+ }
+}
+
+/* #define GEO_DEBUG */
+
+#ifdef GEO_DEBUG
+#include <stdio.h>
+
+static void
+inspect_mesh(grn_ctx *ctx, grn_geo_point *key, int key_size, int n)
+{
+ grn_geo_point min, max;
+
+ printf("mesh: %d:%d\n", n, key_size);
+
+ printf("key: ");
+ grn_p_geo_point(ctx, key);
+
+ compute_min_and_max(key, key_size, &min, &max);
+ printf("min: ");
+ grn_p_geo_point(ctx, &min);
+ printf("max: ");
+ grn_p_geo_point(ctx, &max);
+}
+
+static void
+inspect_mesh_entry(grn_ctx *ctx, mesh_entry *entries, int n)
+{
+ mesh_entry *entry;
+
+ entry = entries + n;
+ inspect_mesh(ctx, &(entry->key), entry->key_size, n);
+}
+
+static void
+inspect_tid(grn_ctx *ctx, grn_id tid, grn_geo_point *point, double d)
+{
+ printf("tid: %d:%g", tid, d);
+ grn_p_geo_point(ctx, point);
+}
+
+static void
+inspect_key(grn_ctx *ctx, uint8_t *key)
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+ int j;
+ for (j = 0; j < 8; j++) {
+ printf("%d", (key[i] & (1 << (7 - j))) >> (7 - j));
+ }
+ printf(" ");
+ }
+ printf("\n");
+}
+
+static void
+print_key_mark(grn_ctx *ctx, int target_bit)
+{
+ int i;
+
+ for (i = 0; i < target_bit; i++) {
+ printf(" ");
+ if (i > 0 && i % 8 == 0) {
+ printf(" ");
+ }
+ }
+ if (i > 0 && i % 8 == 0) {
+ printf(" ");
+ }
+ printf("^\n");
+}
+
+static void
+inspect_cursor_entry(grn_ctx *ctx, grn_geo_cursor_entry *entry)
+{
+ grn_geo_point point;
+
+ printf("entry: ");
+ grn_ntog((uint8_t *)&point, entry->key, sizeof(grn_geo_point));
+ grn_p_geo_point(ctx, &point);
+ inspect_key(ctx, entry->key);
+ print_key_mark(ctx, entry->target_bit);
+
+ printf(" target bit: %d\n", entry->target_bit);
+
+#define INSPECT_STATUS_FLAG(name) \
+ ((entry->status_flags & GRN_GEO_CURSOR_ENTRY_STATUS_ ## name) ? "true" : "false")
+
+ printf(" top included: %s\n", INSPECT_STATUS_FLAG(TOP_INCLUDED));
+ printf("bottom included: %s\n", INSPECT_STATUS_FLAG(BOTTOM_INCLUDED));
+ printf(" left included: %s\n", INSPECT_STATUS_FLAG(LEFT_INCLUDED));
+ printf(" right included: %s\n", INSPECT_STATUS_FLAG(RIGHT_INCLUDED));
+ printf(" latitude inner: %s\n", INSPECT_STATUS_FLAG(LATITUDE_INNER));
+ printf("longitude inner: %s\n", INSPECT_STATUS_FLAG(LONGITUDE_INNER));
+
+#undef INSPECT_STATUS_FLAG
+}
+
+static void
+inspect_cursor_entry_targets(grn_ctx *ctx, grn_geo_cursor_entry *entry,
+ uint8_t *top_left_key, uint8_t *bottom_right_key,
+ grn_geo_cursor_entry *next_entry0,
+ grn_geo_cursor_entry *next_entry1)
+{
+ printf("entry: ");
+ inspect_key(ctx, entry->key);
+ printf("top-left: ");
+ inspect_key(ctx, top_left_key);
+ printf("bottom-right: ");
+ inspect_key(ctx, bottom_right_key);
+ printf("next-entry-0: ");
+ inspect_key(ctx, next_entry0->key);
+ printf("next-entry-1: ");
+ inspect_key(ctx, next_entry1->key);
+ printf(" ");
+ print_key_mark(ctx, entry->target_bit + 1);
+}
+#else
+# define inspect_mesh(...)
+# define inspect_mesh_entry(...)
+# define inspect_tid(...)
+# define inspect_key(...)
+# define print_key_mark(...)
+# define inspect_cursor_entry(...)
+# define inspect_cursor_entry_targets(...)
+#endif
+
+static int
+grn_geo_table_sort_detect_far_point(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ grn_pat *pat, geo_entry *entries,
+ grn_pat_cursor *pc, int n,
+ grn_bool accessorp,
+ grn_geo_point *base_point,
+ double *d_far, int *diff_bit)
+{
+ int i = 0, diff_bit_prev, diff_bit_current;
+ grn_id tid;
+ geo_entry *ep, *p;
+ double d;
+ uint8_t geo_key_prev[sizeof(grn_geo_point)];
+ uint8_t geo_key_curr[sizeof(grn_geo_point)];
+ grn_geo_point point;
+
+ *d_far = 0.0;
+ grn_gton(geo_key_curr, base_point, sizeof(grn_geo_point));
+ *diff_bit = sizeof(grn_geo_point) * 8;
+ diff_bit_current = sizeof(grn_geo_point) * 8;
+ grn_memcpy(&point, base_point, sizeof(grn_geo_point));
+ ep = entries;
+ inspect_mesh(ctx, &point, *diff_bit, -1);
+ while ((tid = grn_pat_cursor_next(ctx, pc))) {
+ grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
+ if (ic) {
+ grn_posting *posting;
+ grn_gton(geo_key_prev, &point, sizeof(grn_geo_point));
+ grn_pat_get_key(ctx, pat, tid, &point, sizeof(grn_geo_point));
+ grn_gton(geo_key_curr, &point, sizeof(grn_geo_point));
+ d = grn_geo_distance_rectangle_raw(ctx, base_point, &point);
+ inspect_tid(ctx, tid, &point, d);
+
+ diff_bit_prev = diff_bit_current;
+ diff_bit_current = compute_diff_bit(geo_key_curr, geo_key_prev);
+#ifdef GEO_DEBUG
+ printf("diff: %d:%d:%d\n", *diff_bit, diff_bit_prev, diff_bit_current);
+#endif
+ if ((diff_bit_current % 2) == 1) {
+ diff_bit_current--;
+ }
+ if (diff_bit_current < diff_bit_prev && *diff_bit > diff_bit_current) {
+ if (i == n) {
+ grn_ii_cursor_close(ctx, ic);
+ break;
+ }
+ *diff_bit = diff_bit_current;
+ }
+
+ if (d > *d_far) {
+ *d_far = d;
+ }
+ while ((posting = grn_ii_cursor_next(ctx, ic))) {
+ grn_id rid = accessorp
+ ? grn_table_get(ctx, table, &posting->rid, sizeof(grn_id))
+ : posting->rid;
+ if (rid) {
+ for (p = ep; entries < p && p[-1].d > d; p--) {
+ p->id = p[-1].id;
+ p->d = p[-1].d;
+ }
+ p->id = rid;
+ p->d = d;
+ if (i < n) {
+ ep++;
+ i++;
+ }
+ }
+ }
+ grn_ii_cursor_close(ctx, ic);
+ }
+ }
+
+ return i;
+}
+
+typedef enum {
+ MESH_LEFT_TOP,
+ MESH_RIGHT_TOP,
+ MESH_RIGHT_BOTTOM,
+ MESH_LEFT_BOTTOM
+} mesh_position;
+
+/*
+ meshes should have
+ 86 >= spaces when include_base_point_hash == GRN_FALSE,
+ 87 >= spaces when include_base_point_hash == GRN_TRUE.
+*/
+static int
+grn_geo_get_meshes_for_circle(grn_ctx *ctx, grn_geo_point *base_point,
+ double d_far, int diff_bit,
+ int include_base_point_mesh,
+ mesh_entry *meshes)
+{
+ double d;
+ int n_meshes;
+ int lat_diff, lng_diff;
+ mesh_position position;
+ grn_geo_point geo_base, geo_min, geo_max;
+
+ compute_min_and_max(base_point, diff_bit - 2, &geo_min, &geo_max);
+
+ lat_diff = (geo_max.latitude - geo_min.latitude + 1) / 2;
+ lng_diff = (geo_max.longitude - geo_min.longitude + 1) / 2;
+ geo_base.latitude = geo_min.latitude + lat_diff;
+ geo_base.longitude = geo_min.longitude + lng_diff;
+ if (base_point->latitude >= geo_base.latitude) {
+ if (base_point->longitude >= geo_base.longitude) {
+ position = MESH_RIGHT_TOP;
+ } else {
+ position = MESH_LEFT_TOP;
+ }
+ } else {
+ if (base_point->longitude >= geo_base.longitude) {
+ position = MESH_RIGHT_BOTTOM;
+ } else {
+ position = MESH_LEFT_BOTTOM;
+ }
+ }
+ /*
+ base_point: b
+ geo_min: i
+ geo_max: a
+ geo_base: x: must be at the left bottom in the top right mesh.
+
+ e.g.: base_point is at the left bottom mesh case:
+ +------+------+
+ | | a|
+ | |x |
+ ^+------+------+
+ || | |
+ lng_diff || b | |
+ \/i------+------+
+ <------>
+ lat_diff
+
+ grn_min + lat_diff -> the right mesh.
+ grn_min + lng_diff -> the top mesh.
+ */
+#ifdef GEO_DEBUG
+ grn_p_geo_point(ctx, base_point);
+ printf("base: ");
+ grn_p_geo_point(ctx, &geo_base);
+ printf("min: ");
+ grn_p_geo_point(ctx, &geo_min);
+ printf("max: ");
+ grn_p_geo_point(ctx, &geo_max);
+ printf("diff: %d (%d, %d)\n", diff_bit, lat_diff, lng_diff);
+ switch (position) {
+ case MESH_LEFT_TOP :
+ printf("position: left-top\n");
+ break;
+ case MESH_RIGHT_TOP :
+ printf("position: right-top\n");
+ break;
+ case MESH_RIGHT_BOTTOM :
+ printf("position: right-bottom\n");
+ break;
+ case MESH_LEFT_BOTTOM :
+ printf("position: left-bottom\n");
+ break;
+ }
+#endif
+
+ n_meshes = 0;
+
+#define add_mesh(lat_diff_,lng_diff_,key_size_) do {\
+ meshes[n_meshes].key.latitude = geo_base.latitude + (lat_diff_);\
+ meshes[n_meshes].key.longitude = geo_base.longitude + (lng_diff_);\
+ meshes[n_meshes].key_size = key_size_;\
+ n_meshes++;\
+} while (0)
+
+ if (include_base_point_mesh || position != MESH_LEFT_TOP) {
+ add_mesh(0, -lng_diff, diff_bit);
+ }
+ if (include_base_point_mesh || position != MESH_RIGHT_TOP) {
+ add_mesh(0, 0, diff_bit);
+ }
+ if (include_base_point_mesh || position != MESH_RIGHT_BOTTOM) {
+ add_mesh(-lat_diff, 0, diff_bit);
+ }
+ if (include_base_point_mesh || position != MESH_LEFT_BOTTOM) {
+ add_mesh(-lat_diff, -lng_diff, diff_bit);
+ }
+
+ /*
+ b: base_point
+ x: geo_base
+ 0-83: sub meshes. 0-83 are added order.
+
+ j: -5 -4 -3 -2 -1 0 1 2 3 4
+ +---+---+---+---+---+---+---+---+---+---+
+ |74 |75 |76 |77 |78 |79 |80 |81 |82 |83 | 4
+ +---+---+---+---+---+---+---+---+---+---+
+ |64 |65 |66 |67 |68 |69 |70 |71 |72 |73 | 3
+ +---+---+---+---+---+---+---+---+---+---+
+ |54 |55 |56 |57 |58 |59 |60 |61 |62 |63 | 2
+ +---+---+---+---+---+---+---+---+---+---+
+ |48 |49 |50 | b | |51 |52 |53 | 1
+ +---+---+---+ | +---+---+---+
+ |42 |43 |44 | |x |45 |46 |47 | 0
+ +---+---+---+-------+-------+---+---+---+
+ |36 |37 |38 | | |39 |40 |41 | -1
+ +---+---+---+ base meshes +---+---+---+
+ |30 |31 |32 | | |33 |34 |35 | -2
+ +---+---+---+---+---+---+---+---+---+---+
+ |20 |21 |22 |23 |24 |25 |26 |27 |28 |29 | -3
+ +---+---+---+---+---+---+---+---+---+---+
+ |10 |11 |12 |13 |14 |15 |16 |17 |18 |19 | -4
+ +---+---+---+---+---+---+---+---+---+---+
+ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -5
+ +---+---+---+---+---+---+---+---+---+---+
+ i
+ */
+ {
+ int i, j, n_sub_meshes, lat, lat_min, lat_max, lng, lng_min, lng_max;
+ n_sub_meshes = 0;
+ for (i = -5; i < 5; i++) {
+ lat_min = ((lat_diff + 1) / 2) * i;
+ lat_max = ((lat_diff + 1) / 2) * (i + 1) - 1;
+ for (j = -5; j < 5; j++) {
+ if (-3 < i && i < 2 && -3 < j && j < 2) {
+ continue;
+ }
+ lng_min = ((lng_diff + 1) / 2) * j;
+ lng_max = ((lng_diff + 1) / 2) * (j + 1) - 1;
+ if (base_point->latitude <= geo_base.latitude + lat_min) {
+ lat = geo_base.latitude + lat_min;
+ } else if (geo_base.latitude + lat_max < base_point->latitude) {
+ lat = geo_base.latitude + lat_max;
+ } else {
+ lat = base_point->latitude;
+ }
+ if (base_point->longitude <= geo_base.longitude + lng_min) {
+ lng = geo_base.longitude + lng_min;
+ } else if (geo_base.longitude + lng_max < base_point->longitude) {
+ lng = geo_base.longitude + lng_max;
+ } else {
+ lng = base_point->longitude;
+ }
+ meshes[n_meshes].key.latitude = lat;
+ meshes[n_meshes].key.longitude = lng;
+ d = grn_geo_distance_rectangle_raw(ctx, base_point,
+ &(meshes[n_meshes].key));
+ if (d < d_far) {
+#ifdef GEO_DEBUG
+ printf("sub-mesh: %d: (%d,%d): (%d,%d;%d,%d)\n",
+ n_sub_meshes, base_point->latitude, base_point->longitude,
+ geo_base.latitude + lat_min,
+ geo_base.latitude + lat_max,
+ geo_base.longitude + lng_min,
+ geo_base.longitude + lng_max);
+ grn_p_geo_point(ctx, &(meshes[n_meshes].key));
+#endif
+ meshes[n_meshes].key_size = diff_bit + 2;
+ n_meshes++;
+ }
+ n_sub_meshes++;
+ }
+ }
+ }
+
+#undef add_mesh
+
+ return n_meshes;
+}
+
+static int
+grn_geo_table_sort_collect_points(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ grn_pat *pat,
+ geo_entry *entries, int n_entries,
+ int n, grn_bool accessorp,
+ grn_geo_point *base_point,
+ double d_far, int diff_bit)
+{
+ int n_meshes;
+ mesh_entry meshes[86];
+ geo_entry *ep, *p;
+
+ n_meshes = grn_geo_get_meshes_for_circle(ctx, base_point, d_far, diff_bit,
+ GRN_FALSE, meshes);
+
+ ep = entries + n_entries;
+ while (n_meshes--) {
+ grn_id tid;
+ grn_pat_cursor *pc = grn_pat_cursor_open(ctx, pat,
+ &(meshes[n_meshes].key),
+ meshes[n_meshes].key_size,
+ NULL, 0,
+ 0, -1,
+ GRN_CURSOR_PREFIX|GRN_CURSOR_SIZE_BY_BIT);
+ inspect_mesh_entry(ctx, meshes, n_meshes);
+ if (pc) {
+ while ((tid = grn_pat_cursor_next(ctx, pc))) {
+ grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
+ if (ic) {
+ double d;
+ grn_geo_point pos;
+ grn_posting *posting;
+ grn_pat_get_key(ctx, pat, tid, &pos, sizeof(grn_geo_point));
+ d = grn_geo_distance_rectangle_raw(ctx, base_point, &pos);
+ inspect_tid(ctx, tid, &pos, d);
+ while ((posting = grn_ii_cursor_next(ctx, ic))) {
+ grn_id rid = accessorp
+ ? grn_table_get(ctx, table, &posting->rid, sizeof(grn_id))
+ : posting->rid;
+ if (rid) {
+ for (p = ep; entries < p && p[-1].d > d; p--) {
+ p->id = p[-1].id;
+ p->d = p[-1].d;
+ }
+ p->id = rid;
+ p->d = d;
+ if (n_entries < n) {
+ ep++;
+ n_entries++;
+ }
+ }
+ }
+ grn_ii_cursor_close(ctx, ic);
+ }
+ }
+ grn_pat_cursor_close(ctx, pc);
+ }
+ }
+ return n_entries;
+}
+
+static inline grn_obj *
+find_geo_sort_index(grn_ctx *ctx, grn_obj *key)
+{
+ grn_obj *index = NULL;
+
+ if (GRN_ACCESSORP(key)) {
+ grn_accessor *accessor = (grn_accessor *)key;
+ if (accessor->action != GRN_ACCESSOR_GET_KEY) {
+ return NULL;
+ }
+ if (!(DB_OBJ(accessor->obj)->id & GRN_OBJ_TMP_OBJECT)) {
+ return NULL;
+ }
+ if (accessor->obj->header.type != GRN_TABLE_HASH_KEY) {
+ return NULL;
+ }
+ if (!accessor->next) {
+ return NULL;
+ }
+ grn_column_index(ctx, accessor->next->obj, GRN_OP_LESS, &index, 1, NULL);
+ } else {
+ grn_column_index(ctx, key, GRN_OP_LESS, &index, 1, NULL);
+ }
+
+ return index;
+}
+
+static inline int
+grn_geo_table_sort_by_distance(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ grn_pat *pat,
+ grn_pat_cursor *pc,
+ grn_bool accessorp,
+ grn_geo_point *base_point,
+ int offset,
+ int limit,
+ grn_obj *result)
+{
+ int n_entries = 0, e = offset + limit;
+ geo_entry *entries;
+
+ if ((entries = GRN_MALLOC(sizeof(geo_entry) * (e + 1)))) {
+ int n, diff_bit;
+ double d_far;
+ geo_entry *ep;
+ grn_bool need_not_indexed_records;
+ grn_hash *indexed_records = NULL;
+
+ n = grn_geo_table_sort_detect_far_point(ctx, table, index, pat,
+ entries, pc, e, accessorp,
+ base_point,
+ &d_far, &diff_bit);
+ if (diff_bit > 0) {
+ n = grn_geo_table_sort_collect_points(ctx, table, index, pat,
+ entries, n, e, accessorp,
+ base_point, d_far, diff_bit);
+ }
+ need_not_indexed_records = offset + limit > n;
+ if (need_not_indexed_records) {
+ indexed_records = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ }
+ for (ep = entries + offset;
+ n_entries < limit && ep < entries + n;
+ n_entries++, ep++) {
+ grn_id *sorted_id;
+ if (!grn_array_add(ctx, (grn_array *)result, (void **)&sorted_id)) {
+ if (indexed_records) {
+ grn_hash_close(ctx, indexed_records);
+ indexed_records = NULL;
+ }
+ break;
+ }
+ *sorted_id = ep->id;
+ if (indexed_records) {
+ grn_hash_add(ctx, indexed_records, &(ep->id), sizeof(grn_id),
+ NULL, NULL);
+ }
+ }
+ GRN_FREE(entries);
+ if (indexed_records) {
+ GRN_TABLE_EACH(ctx, table, GRN_ID_NIL, GRN_ID_MAX, id, NULL, NULL, NULL, {
+ if (!grn_hash_get(ctx, indexed_records, &id, sizeof(grn_id), NULL)) {
+ grn_id *sorted_id;
+ if (grn_array_add(ctx, (grn_array *)result, (void **)&sorted_id)) {
+ *sorted_id = id;
+ }
+ n_entries++;
+ if (n_entries == limit) {
+ break;
+ }
+ };
+ });
+ grn_hash_close(ctx, indexed_records);
+ }
+ }
+
+ return n_entries;
+}
+
+int
+grn_geo_table_sort(grn_ctx *ctx, grn_obj *table, int offset, int limit,
+ grn_obj *result, grn_obj *column, grn_obj *geo_point)
+{
+ grn_obj *index;
+ int i = 0;
+
+ GRN_API_ENTER;
+
+ if (offset < 0 || limit < 0) {
+ unsigned int size;
+ grn_rc rc;
+ size = grn_table_size(ctx, table);
+ rc = grn_normalize_offset_and_limit(ctx, size, &offset, &limit);
+ if (rc != GRN_SUCCESS) {
+ ERR(rc,
+ "[sort][geo] failed to normalize offset and limit: "
+ "offset:%d limit:%d table-size:%u",
+ offset, limit, size);
+ GRN_API_RETURN(i);
+ }
+ }
+
+ if ((index = find_geo_sort_index(ctx, column))) {
+ grn_id tid;
+ grn_pat *pat = (grn_pat *)grn_ctx_at(ctx, index->header.domain);
+ grn_id domain;
+ grn_pat_cursor *pc;
+ if (!pat) {
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+ char lexicon_name[GRN_TABLE_MAX_KEY_SIZE];
+ int lexicon_name_size;
+ index_name_size = grn_obj_name(ctx,
+ index,
+ index_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ lexicon_name_size = grn_table_get_key(ctx,
+ grn_ctx_db(ctx),
+ index->header.domain,
+ lexicon_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "[sort][geo] lexicon is broken: <%.*s>: <%.*s>(%d)",
+ index_name_size, index_name,
+ lexicon_name_size, lexicon_name,
+ index->header.domain);
+ GRN_API_RETURN(i);
+ }
+ domain = pat->obj.header.domain;
+ pc = grn_pat_cursor_open(ctx, pat, NULL, 0,
+ GRN_BULK_HEAD(geo_point),
+ GRN_BULK_VSIZE(geo_point),
+ 0, -1, GRN_CURSOR_PREFIX);
+ if (pc) {
+ if (domain != GRN_DB_TOKYO_GEO_POINT && domain != GRN_DB_WGS84_GEO_POINT) {
+ int e = offset + limit;
+ while (i < e && (tid = grn_pat_cursor_next(ctx, pc))) {
+ grn_ii_cursor *ic = grn_ii_cursor_open(ctx, (grn_ii *)index, tid, 0, 0, 1, 0);
+ if (ic) {
+ grn_posting *posting;
+ while (i < e && (posting = grn_ii_cursor_next(ctx, ic))) {
+ if (offset <= i) {
+ grn_id *v;
+ if (!grn_array_add(ctx, (grn_array *)result, (void **)&v)) { break; }
+ *v = posting->rid;
+ }
+ i++;
+ }
+ grn_ii_cursor_close(ctx, ic);
+ }
+ }
+ } else {
+ grn_geo_point *base_point = (grn_geo_point *)GRN_BULK_HEAD(geo_point);
+ i = grn_geo_table_sort_by_distance(ctx, table, index, pat,
+ pc,
+ GRN_ACCESSORP(column),
+ base_point,
+ offset, limit, result);
+ }
+ grn_pat_cursor_close(ctx, pc);
+ }
+ }
+ GRN_API_RETURN(i);
+}
+
+grn_rc
+grn_geo_resolve_approximate_type(grn_ctx *ctx, grn_obj *type_name,
+ grn_geo_approximate_type *type)
+{
+ grn_rc rc;
+ grn_obj approximate_type;
+
+ GRN_TEXT_INIT(&approximate_type, 0);
+ rc = grn_obj_cast(ctx, type_name, &approximate_type, GRN_FALSE);
+ if (rc == GRN_SUCCESS) {
+ const char *name;
+ unsigned int size;
+ name = GRN_TEXT_VALUE(&approximate_type);
+ size = GRN_TEXT_LEN(&approximate_type);
+ if ((strncmp("rectangle", name, size) == 0) ||
+ (strncmp("rect", name, size) == 0)) {
+ *type = GRN_GEO_APPROXIMATE_RECTANGLE;
+ } else if ((strncmp("sphere", name, size) == 0) ||
+ (strncmp("sphr", name, size) == 0)) {
+ *type = GRN_GEO_APPROXIMATE_SPHERE;
+ } else if ((strncmp("ellipsoid", name, size) == 0) ||
+ (strncmp("ellip", name, size) == 0)) {
+ *type = GRN_GEO_APPROXIMATE_ELLIPSOID;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "geo distance approximate type must be one of "
+ "[rectangle, rect, sphere, sphr, ellipsoid, ellip]"
+ ": <%.*s>",
+ size, name);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &approximate_type);
+
+ return rc;
+}
+
+typedef double (*grn_geo_distance_raw_func)(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2);
+
+grn_rc
+grn_selector_geo_in_circle(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
+
+ if (!(nargs == 4 || nargs == 5)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "geo_in_circle(): requires 3 or 4 arguments but was <%d> arguments",
+ nargs - 1);
+ return ctx->rc;
+ }
+
+ if (!index) {
+ grn_obj *point_column;
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ point_column = args[1];
+ column_name_size = grn_obj_name(ctx, point_column,
+ column_name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "geo_in_circle(): index for <%.*s> is missing",
+ column_name_size, column_name);
+ return ctx->rc;
+ }
+
+ if (nargs == 5) {
+ if (grn_geo_resolve_approximate_type(ctx, args[4], &type) != GRN_SUCCESS) {
+ return ctx->rc;
+ }
+ }
+
+ {
+ grn_obj *center_point, *distance;
+ center_point = args[2];
+ distance = args[3];
+ grn_geo_select_in_circle(ctx, index, center_point, distance, type, res, op);
+ }
+
+ return ctx->rc;
+}
+
+static grn_geo_distance_raw_func
+grn_geo_resolve_distance_raw_func (grn_ctx *ctx,
+ grn_geo_approximate_type approximate_type,
+ grn_id domain)
+{
+ grn_geo_distance_raw_func distance_raw_func = NULL;
+
+ switch (approximate_type) {
+ case GRN_GEO_APPROXIMATE_RECTANGLE :
+ distance_raw_func = grn_geo_distance_rectangle_raw;
+ break;
+ case GRN_GEO_APPROXIMATE_SPHERE :
+ distance_raw_func = grn_geo_distance_sphere_raw;
+ break;
+ case GRN_GEO_APPROXIMATE_ELLIPSOID :
+ if (domain == GRN_DB_WGS84_GEO_POINT) {
+ distance_raw_func = grn_geo_distance_ellipsoid_raw_wgs84;
+ } else {
+ distance_raw_func = grn_geo_distance_ellipsoid_raw_tokyo;
+ }
+ break;
+ default :
+ break;
+ }
+
+ return distance_raw_func;
+}
+
+grn_rc
+grn_geo_select_in_circle(grn_ctx *ctx, grn_obj *index,
+ grn_obj *center_point, grn_obj *distance,
+ grn_geo_approximate_type approximate_type,
+ grn_obj *res, grn_operator op)
+{
+ grn_id domain;
+ double center_longitude, center_latitude;
+ double d;
+ grn_obj *pat, *point_on_circle = NULL, center_point_, point_on_circle_;
+ grn_geo_point *center, on_circle;
+ grn_geo_distance_raw_func distance_raw_func;
+ pat = grn_ctx_at(ctx, index->header.domain);
+ if (!pat) {
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+ char lexicon_name[GRN_TABLE_MAX_KEY_SIZE];
+ int lexicon_name_size;
+ index_name_size = grn_obj_name(ctx,
+ index,
+ index_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ lexicon_name_size = grn_table_get_key(ctx,
+ grn_ctx_db(ctx),
+ index->header.domain,
+ lexicon_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "geo_in_circle(): lexicon is broken: <%.*s>: <%.*s>(%d)",
+ index_name_size, index_name,
+ lexicon_name_size, lexicon_name,
+ index->header.domain);
+ goto exit;
+ }
+ domain = pat->header.domain;
+ if (domain != GRN_DB_TOKYO_GEO_POINT && domain != GRN_DB_WGS84_GEO_POINT) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size = 0;
+ grn_obj *domain_object;
+ domain_object = grn_ctx_at(ctx, domain);
+ if (domain_object) {
+ name_size = grn_obj_name(ctx, domain_object, name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_obj_unlink(ctx, domain_object);
+ } else {
+ grn_strcpy(name, GRN_TABLE_MAX_KEY_SIZE, "(null)");
+ name_size = strlen(name);
+ }
+ ERR(GRN_INVALID_ARGUMENT,
+ "geo_in_circle(): index table must be "
+ "TokyoGeoPoint or WGS84GeoPoint key type table: <%.*s>",
+ name_size, name);
+ goto exit;
+ }
+
+ if (center_point->header.domain != domain) {
+ GRN_OBJ_INIT(&center_point_, GRN_BULK, 0, domain);
+ if (grn_obj_cast(ctx, center_point, &center_point_, GRN_FALSE)) { goto exit; }
+ center_point = &center_point_;
+ }
+ center = GRN_GEO_POINT_VALUE_RAW(center_point);
+ center_longitude = GRN_GEO_INT2RAD(center->longitude);
+ center_latitude = GRN_GEO_INT2RAD(center->latitude);
+
+ distance_raw_func = grn_geo_resolve_distance_raw_func(ctx,
+ approximate_type,
+ domain);
+ if (!distance_raw_func) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "unknown approximate type: <%d>", approximate_type);
+ goto exit;
+ }
+
+ switch (distance->header.domain) {
+ case GRN_DB_INT32 :
+ d = GRN_INT32_VALUE(distance);
+ on_circle.latitude = center->latitude + GRN_GEO_RAD2INT(d / (double)GRN_GEO_RADIUS);
+ on_circle.longitude = center->longitude;
+ break;
+ case GRN_DB_UINT32 :
+ d = GRN_UINT32_VALUE(distance);
+ on_circle.latitude = center->latitude + GRN_GEO_RAD2INT(d / (double)GRN_GEO_RADIUS);
+ on_circle.longitude = center->longitude;
+ break;
+ case GRN_DB_INT64 :
+ d = GRN_INT64_VALUE(distance);
+ on_circle.latitude = center->latitude + GRN_GEO_RAD2INT(d / (double)GRN_GEO_RADIUS);
+ on_circle.longitude = center->longitude;
+ break;
+ case GRN_DB_UINT64 :
+ d = GRN_UINT64_VALUE(distance);
+ on_circle.latitude = center->latitude + GRN_GEO_RAD2INT(d / (double)GRN_GEO_RADIUS);
+ on_circle.longitude = center->longitude;
+ break;
+ case GRN_DB_FLOAT :
+ d = GRN_FLOAT_VALUE(distance);
+ on_circle.latitude = center->latitude + GRN_GEO_RAD2INT(d / (double)GRN_GEO_RADIUS);
+ on_circle.longitude = center->longitude;
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ GRN_OBJ_INIT(&point_on_circle_, GRN_BULK, 0, domain);
+ if (grn_obj_cast(ctx, distance, &point_on_circle_, GRN_FALSE)) { goto exit; }
+ point_on_circle = &point_on_circle_;
+ /* fallthru */
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ if (!point_on_circle) {
+ if (domain != distance->header.domain) { /* todo */ goto exit; }
+ point_on_circle = distance;
+ }
+ GRN_GEO_POINT_VALUE(point_on_circle,
+ on_circle.latitude, on_circle.longitude);
+ d = distance_raw_func(ctx, center, &on_circle);
+ if (point_on_circle == &point_on_circle_) {
+ grn_obj_unlink(ctx, point_on_circle);
+ }
+ break;
+ default :
+ goto exit;
+ }
+ {
+ int n_meshes, diff_bit;
+ double d_far;
+ mesh_entry meshes[87];
+ uint8_t geo_key1[sizeof(grn_geo_point)];
+ uint8_t geo_key2[sizeof(grn_geo_point)];
+
+ d_far = grn_geo_distance_rectangle_raw(ctx, center, &on_circle);
+ grn_gton(geo_key1, center, sizeof(grn_geo_point));
+ grn_gton(geo_key2, &on_circle, sizeof(grn_geo_point));
+ diff_bit = compute_diff_bit(geo_key1, geo_key2);
+#ifdef GEO_DEBUG
+ printf("center point: ");
+ grn_p_geo_point(ctx, center);
+ printf("point on circle: ");
+ grn_p_geo_point(ctx, &on_circle);
+ printf("diff: %d\n", diff_bit);
+#endif
+ if ((diff_bit % 2) == 1) {
+ diff_bit--;
+ }
+ n_meshes = grn_geo_get_meshes_for_circle(ctx, center,
+ d_far, diff_bit, GRN_TRUE,
+ meshes);
+ while (n_meshes--) {
+ grn_table_cursor *tc;
+ tc = grn_table_cursor_open(ctx, pat,
+ &(meshes[n_meshes].key),
+ meshes[n_meshes].key_size,
+ NULL, 0,
+ 0, -1,
+ GRN_CURSOR_PREFIX|GRN_CURSOR_SIZE_BY_BIT);
+ inspect_mesh_entry(ctx, meshes, n_meshes);
+ if (tc) {
+ grn_id tid;
+ grn_geo_point point;
+ while ((tid = grn_table_cursor_next(ctx, tc))) {
+ double point_distance;
+ grn_table_get_key(ctx, pat, tid, &point, sizeof(grn_geo_point));
+ point_distance = distance_raw_func(ctx, &point, center);
+ if (point_distance <= d) {
+ inspect_tid(ctx, tid, &point, point_distance);
+ grn_ii_at(ctx, (grn_ii *)index, tid, (grn_hash *)res, op);
+ }
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ }
+ }
+exit :
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ return ctx->rc;
+}
+
+grn_rc
+grn_selector_geo_in_rectangle(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ if (nargs == 4) {
+ grn_obj *top_left_point, *bottom_right_point;
+ top_left_point = args[2];
+ bottom_right_point = args[3];
+ grn_geo_select_in_rectangle(ctx, index,
+ top_left_point, bottom_right_point,
+ res, op);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "geo_in_rectangle(): requires 3 arguments but was <%d> arguments",
+ nargs - 1);
+ }
+ return ctx->rc;
+}
+
+static void
+in_rectangle_data_fill(grn_ctx *ctx, grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point,
+ const char *process_name,
+ in_rectangle_data *data)
+{
+ grn_id domain;
+ const char *domain_name;
+
+ data->pat = grn_ctx_at(ctx, index->header.domain);
+ if (!data->pat) {
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+ char lexicon_name[GRN_TABLE_MAX_KEY_SIZE];
+ int lexicon_name_size;
+ index_name_size = grn_obj_name(ctx,
+ index,
+ index_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ lexicon_name_size = grn_table_get_key(ctx,
+ grn_ctx_db(ctx),
+ index->header.domain,
+ lexicon_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_OBJECT_CORRUPT,
+ "%s: lexicon lexicon is broken: <%.*s>: <%.*s>(%d)",
+ process_name,
+ index_name_size, index_name,
+ lexicon_name_size, lexicon_name,
+ index->header.domain);
+ return;
+ }
+
+ domain = data->pat->header.domain;
+ if (domain != GRN_DB_TOKYO_GEO_POINT && domain != GRN_DB_WGS84_GEO_POINT) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size = 0;
+ grn_obj *domain_object;
+ domain_object = grn_ctx_at(ctx, domain);
+ if (domain_object) {
+ name_size = grn_obj_name(ctx, domain_object, name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_obj_unlink(ctx, domain_object);
+ } else {
+ grn_strcpy(name, GRN_TABLE_MAX_KEY_SIZE, "(null)");
+ name_size = strlen(name);
+ }
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: index table must be "
+ "TokyoGeoPoint or WGS84GeoPoint key type table: <%.*s>",
+ process_name, name_size, name);
+ return;
+ }
+
+ if (domain == GRN_DB_TOKYO_GEO_POINT) {
+ domain_name = "TokyoGeoPoint";
+ } else {
+ domain_name = "WGS84GeoPoint";
+ }
+
+ if (top_left_point->header.domain != domain) {
+ grn_obj_reinit(ctx, &(data->top_left_point_buffer), domain, GRN_BULK);
+ if (grn_obj_cast(ctx, top_left_point, &(data->top_left_point_buffer),
+ GRN_FALSE)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: failed to cast to %s: <%.*s>",
+ process_name, domain_name,
+ (int)GRN_TEXT_LEN(top_left_point),
+ GRN_TEXT_VALUE(top_left_point));
+ return;
+ }
+ top_left_point = &(data->top_left_point_buffer);
+ }
+ data->top_left = GRN_GEO_POINT_VALUE_RAW(top_left_point);
+
+ if (bottom_right_point->header.domain != domain) {
+ grn_obj_reinit(ctx, &(data->bottom_right_point_buffer), domain, GRN_BULK);
+ if (grn_obj_cast(ctx, bottom_right_point, &(data->bottom_right_point_buffer),
+ GRN_FALSE)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: failed to cast to %s: <%.*s>",
+ process_name, domain_name,
+ (int)GRN_TEXT_LEN(bottom_right_point),
+ GRN_TEXT_VALUE(bottom_right_point));
+ return;
+ }
+ bottom_right_point = &(data->bottom_right_point_buffer);
+ }
+ data->bottom_right = GRN_GEO_POINT_VALUE_RAW(bottom_right_point);
+}
+
+static void
+in_rectangle_data_validate(grn_ctx *ctx,
+ const char *process_name,
+ in_rectangle_data *data)
+{
+ grn_geo_point *top_left, *bottom_right;
+
+ top_left = data->top_left;
+ bottom_right = data->bottom_right;
+
+ if (top_left->latitude >= GRN_GEO_MAX_LATITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: top left point's latitude is too big: "
+ "<%d>(max:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MAX_LATITUDE, top_left->latitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (top_left->latitude <= GRN_GEO_MIN_LATITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: top left point's latitude is too small: "
+ "<%d>(min:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MIN_LATITUDE, top_left->latitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (top_left->longitude >= GRN_GEO_MAX_LONGITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: top left point's longitude is too big: "
+ "<%d>(max:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MAX_LONGITUDE, top_left->longitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (top_left->longitude <= GRN_GEO_MIN_LONGITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: top left point's longitude is too small: "
+ "<%d>(min:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MIN_LONGITUDE, top_left->longitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (bottom_right->latitude >= GRN_GEO_MAX_LATITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: bottom right point's latitude is too big: "
+ "<%d>(max:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MAX_LATITUDE, bottom_right->latitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (bottom_right->latitude <= GRN_GEO_MIN_LATITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: bottom right point's latitude is too small: "
+ "<%d>(min:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MIN_LATITUDE, bottom_right->latitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (bottom_right->longitude >= GRN_GEO_MAX_LONGITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: bottom right point's longitude is too big: "
+ "<%d>(max:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MAX_LONGITUDE, bottom_right->longitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+
+ if (bottom_right->longitude <= GRN_GEO_MIN_LONGITUDE) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s: bottom right point's longitude is too small: "
+ "<%d>(min:%d): (%d,%d) (%d,%d)",
+ process_name,
+ GRN_GEO_MIN_LONGITUDE, bottom_right->longitude,
+ top_left->latitude, top_left->longitude,
+ bottom_right->latitude, bottom_right->longitude);
+ return;
+ }
+}
+
+static void
+in_rectangle_area_data_compute(grn_ctx *ctx,
+ grn_geo_point *top_left,
+ grn_geo_point *bottom_right,
+ in_rectangle_area_data *data)
+{
+ int latitude_distance, longitude_distance;
+ int diff_bit;
+ grn_geo_point base;
+ grn_geo_point *geo_point_input;
+ uint8_t geo_key_input[sizeof(grn_geo_point)];
+ uint8_t geo_key_base[sizeof(grn_geo_point)];
+ uint8_t geo_key_top_left[sizeof(grn_geo_point)];
+ uint8_t geo_key_bottom_right[sizeof(grn_geo_point)];
+
+ latitude_distance = top_left->latitude - bottom_right->latitude;
+ longitude_distance = bottom_right->longitude - top_left->longitude;
+ if (latitude_distance > longitude_distance) {
+ geo_point_input = bottom_right;
+ base.latitude = bottom_right->latitude;
+ base.longitude = bottom_right->longitude - longitude_distance;
+ } else {
+ geo_point_input = top_left;
+ base.latitude = top_left->latitude - latitude_distance;
+ base.longitude = top_left->longitude;
+ }
+ grn_gton(geo_key_input, geo_point_input, sizeof(grn_geo_point));
+ grn_gton(geo_key_base, &base, sizeof(grn_geo_point));
+ diff_bit = compute_diff_bit(geo_key_input, geo_key_base);
+ compute_min_and_max(&base, diff_bit, &(data->min), &(data->max));
+
+ grn_gton(geo_key_top_left, top_left, sizeof(grn_geo_point));
+ grn_gton(geo_key_bottom_right, bottom_right, sizeof(grn_geo_point));
+ data->rectangle_common_bit =
+ compute_diff_bit(geo_key_top_left, geo_key_bottom_right) - 1;
+ compute_min_and_max_key(geo_key_top_left, data->rectangle_common_bit + 1,
+ data->rectangle_common_key, NULL);
+
+#ifdef GEO_DEBUG
+ printf("base: ");
+ grn_p_geo_point(ctx, &base);
+ printf("min: ");
+ grn_p_geo_point(ctx, &(data->min));
+ printf("max: ");
+ grn_p_geo_point(ctx, &(data->max));
+ printf("top-left: ");
+ grn_p_geo_point(ctx, top_left);
+ printf("bottom-right: ");
+ grn_p_geo_point(ctx, bottom_right);
+ printf("rectangle-common-bit:%10d\n", data->rectangle_common_bit);
+ printf("distance(latitude): %10d\n", latitude_distance);
+ printf("distance(longitude): %10d\n", longitude_distance);
+#endif
+}
+
+static grn_rc
+in_rectangle_data_prepare(grn_ctx *ctx, grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point,
+ const char *process_name,
+ in_rectangle_data *data)
+{
+ if (!index) {
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "%s: index column is missing", process_name);
+ goto exit;
+ }
+
+ in_rectangle_data_fill(ctx, index, top_left_point, bottom_right_point,
+ process_name, data);
+ if (ctx->rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ in_rectangle_data_validate(ctx, process_name, data);
+ if (ctx->rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+exit :
+ return ctx->rc;
+}
+
+#define SAME_BIT_P(a, b, n_bit)\
+ ((((uint8_t *)(a))[(n_bit) / 8] & (1 << (7 - ((n_bit) % 8)))) ==\
+ (((uint8_t *)(b))[(n_bit) / 8] & (1 << (7 - ((n_bit) % 8)))))
+
+#define CURSOR_ENTRY_UPDATE_STATUS(entry, name, other_key) do {\
+ if (SAME_BIT_P((entry)->key, (other_key), (entry)->target_bit)) {\
+ (entry)->status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_ ## name;\
+ } else {\
+ (entry)->status_flags &= ~GRN_GEO_CURSOR_ENTRY_STATUS_ ## name;\
+ }\
+} while (0)
+
+#define CURSOR_ENTRY_CHECK_STATUS(entry, name)\
+ ((entry)->status_flags & GRN_GEO_CURSOR_ENTRY_STATUS_ ## name)
+#define CURSOR_ENTRY_IS_INNER(entry)\
+ (((entry)->status_flags &\
+ (GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER |\
+ GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER)) ==\
+ (GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER |\
+ GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER))
+#define CURSOR_ENTRY_INCLUDED_IN_LATITUDE_DIRECTION(entry)\
+ ((entry)->status_flags &\
+ (GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER |\
+ GRN_GEO_CURSOR_ENTRY_STATUS_TOP_INCLUDED |\
+ GRN_GEO_CURSOR_ENTRY_STATUS_BOTTOM_INCLUDED))
+#define CURSOR_ENTRY_INCLUDED_IN_LONGITUDE_DIRECTION(entry)\
+ ((entry)->status_flags &\
+ (GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER |\
+ GRN_GEO_CURSOR_ENTRY_STATUS_LEFT_INCLUDED |\
+ GRN_GEO_CURSOR_ENTRY_STATUS_RIGHT_INCLUDED))
+
+#define SET_N_BIT(a, n_bit)\
+ (((uint8_t *)(a))[((n_bit) / 8)] ^= (1 << (7 - ((n_bit) % 8))))
+
+#define N_BIT(a, n_bit)\
+ ((((uint8_t *)(a))[((n_bit) / 8)] &\
+ (1 << (7 - ((n_bit) % 8)))) >> (1 << (7 - ((n_bit) % 8))))
+
+static grn_bool
+extract_rectangle_in_area(grn_ctx *ctx,
+ grn_geo_area_type area_type,
+ const grn_geo_point *top_left,
+ const grn_geo_point *bottom_right,
+ grn_geo_point *area_top_left,
+ grn_geo_point *area_bottom_right)
+{
+ grn_bool out_of_area = GRN_FALSE;
+ grn_bool cover_all_areas = GRN_FALSE;
+
+ if ((GRN_GEO_POINT_IN_NORTH_WEST(top_left) &&
+ GRN_GEO_POINT_IN_SOUTH_EAST(bottom_right)) ||
+ (GRN_GEO_POINT_IN_NORTH_EAST(top_left) &&
+ GRN_GEO_POINT_IN_SOUTH_WEST(bottom_right))) {
+ cover_all_areas = GRN_TRUE;
+ }
+
+ switch (area_type) {
+ case GRN_GEO_AREA_NORTH_EAST :
+ if (cover_all_areas ||
+ GRN_GEO_POINT_IN_NORTH_EAST(top_left) ||
+ GRN_GEO_POINT_IN_NORTH_EAST(bottom_right)) {
+ area_top_left->latitude = MAX(top_left->latitude, 0);
+ area_bottom_right->latitude = MAX(bottom_right->latitude, 0);
+ if (GRN_GEO_LONGITUDE_IS_WRAPPED(top_left, bottom_right)) {
+ area_top_left->longitude = top_left->longitude;
+ area_bottom_right->longitude = GRN_GEO_MAX_LONGITUDE;
+ } else {
+ area_top_left->longitude = MAX(top_left->longitude, 0);
+ area_bottom_right->longitude = MAX(bottom_right->longitude, 0);
+ }
+ } else {
+ out_of_area = GRN_TRUE;
+ }
+ break;
+ case GRN_GEO_AREA_NORTH_WEST :
+ if (cover_all_areas ||
+ GRN_GEO_POINT_IN_NORTH_WEST(top_left) ||
+ GRN_GEO_POINT_IN_NORTH_WEST(bottom_right)) {
+ area_top_left->latitude = MAX(top_left->latitude, 0);
+ area_bottom_right->latitude = MAX(bottom_right->latitude, 0);
+ if (GRN_GEO_LONGITUDE_IS_WRAPPED(top_left, bottom_right)) {
+ area_top_left->longitude = GRN_GEO_MIN_LONGITUDE;
+ area_bottom_right->longitude = bottom_right->longitude;
+ } else {
+ area_top_left->longitude = MIN(top_left->longitude, -1);
+ area_bottom_right->longitude = MIN(bottom_right->longitude, -1);
+ }
+ } else {
+ out_of_area = GRN_TRUE;
+ }
+ break;
+ case GRN_GEO_AREA_SOUTH_WEST :
+ if (cover_all_areas ||
+ GRN_GEO_POINT_IN_SOUTH_WEST(top_left) ||
+ GRN_GEO_POINT_IN_SOUTH_WEST(bottom_right)) {
+ area_top_left->latitude = MIN(top_left->latitude, -1);
+ area_bottom_right->latitude = MIN(bottom_right->latitude, -1);
+ if (GRN_GEO_LONGITUDE_IS_WRAPPED(top_left, bottom_right)) {
+ area_top_left->longitude = GRN_GEO_MIN_LONGITUDE;
+ area_bottom_right->longitude = bottom_right->longitude;
+ } else {
+ area_top_left->longitude = MIN(top_left->longitude, -1);
+ area_bottom_right->longitude = MIN(bottom_right->longitude, -1);
+ }
+ } else {
+ out_of_area = GRN_TRUE;
+ }
+ break;
+ case GRN_GEO_AREA_SOUTH_EAST :
+ if (cover_all_areas ||
+ GRN_GEO_POINT_IN_SOUTH_EAST(top_left) ||
+ GRN_GEO_POINT_IN_SOUTH_EAST(bottom_right)) {
+ area_top_left->latitude = MIN(top_left->latitude, -1);
+ area_bottom_right->latitude = MIN(bottom_right->latitude, -1);
+ if (GRN_GEO_LONGITUDE_IS_WRAPPED(top_left, bottom_right)) {
+ area_top_left->longitude = top_left->longitude;
+ area_bottom_right->longitude = GRN_GEO_MAX_LONGITUDE;
+ } else {
+ area_top_left->longitude = MAX(top_left->longitude, 0);
+ area_bottom_right->longitude = MAX(bottom_right->longitude, 0);
+ }
+ } else {
+ out_of_area = GRN_TRUE;
+ }
+ break;
+ default :
+ out_of_area = GRN_TRUE;
+ break;
+ }
+
+ return out_of_area;
+}
+
+static void
+grn_geo_cursor_area_init(grn_ctx *ctx,
+ grn_geo_cursor_area *area,
+ grn_geo_area_type area_type,
+ const grn_geo_point *top_left,
+ const grn_geo_point *bottom_right)
+{
+ grn_geo_point area_top_left, area_bottom_right;
+ in_rectangle_area_data data;
+ grn_geo_cursor_entry *entry;
+ grn_bool out_of_area;
+
+ out_of_area = extract_rectangle_in_area(ctx,
+ area_type,
+ top_left,
+ bottom_right,
+ &area_top_left,
+ &area_bottom_right);
+ if (out_of_area) {
+ area->current_entry = -1;
+ return;
+ }
+
+ area->current_entry = 0;
+ grn_memcpy(&(area->top_left), &area_top_left, sizeof(grn_geo_point));
+ grn_memcpy(&(area->bottom_right), &area_bottom_right, sizeof(grn_geo_point));
+ grn_gton(area->top_left_key, &area_top_left, sizeof(grn_geo_point));
+ grn_gton(area->bottom_right_key, &area_bottom_right, sizeof(grn_geo_point));
+
+ entry = &(area->entries[area->current_entry]);
+ in_rectangle_area_data_compute(ctx,
+ &area_top_left,
+ &area_bottom_right,
+ &data);
+ entry->target_bit = data.rectangle_common_bit;
+ grn_memcpy(entry->key, data.rectangle_common_key, sizeof(grn_geo_point));
+ entry->status_flags =
+ GRN_GEO_CURSOR_ENTRY_STATUS_TOP_INCLUDED |
+ GRN_GEO_CURSOR_ENTRY_STATUS_BOTTOM_INCLUDED |
+ GRN_GEO_CURSOR_ENTRY_STATUS_LEFT_INCLUDED |
+ GRN_GEO_CURSOR_ENTRY_STATUS_RIGHT_INCLUDED;
+ if (data.min.latitude == area_bottom_right.latitude &&
+ data.max.latitude == area_top_left.latitude) {
+ entry->status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER;
+ }
+ if (data.min.longitude == area_top_left.longitude &&
+ data.max.longitude == area_bottom_right.longitude) {
+ entry->status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER;
+ }
+}
+
+grn_obj *
+grn_geo_cursor_open_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point,
+ int offset,
+ int limit)
+{
+ grn_geo_cursor_in_rectangle *cursor = NULL;
+ in_rectangle_data data;
+
+ GRN_API_ENTER;
+ GRN_VOID_INIT(&(data.top_left_point_buffer));
+ GRN_VOID_INIT(&(data.bottom_right_point_buffer));
+ if (in_rectangle_data_prepare(ctx, index, top_left_point, bottom_right_point,
+ "geo_in_rectangle()", &data)) {
+ goto exit;
+ }
+
+ cursor = GRN_MALLOCN(grn_geo_cursor_in_rectangle, 1);
+ if (!cursor) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[geo][cursor][in-rectangle] failed to allocate memory for geo cursor");
+ goto exit;
+ }
+
+ cursor->pat = data.pat;
+ cursor->index = index;
+ grn_memcpy(&(cursor->top_left), data.top_left, sizeof(grn_geo_point));
+ grn_memcpy(&(cursor->bottom_right), data.bottom_right, sizeof(grn_geo_point));
+ cursor->pat_cursor = NULL;
+ cursor->ii_cursor = NULL;
+ cursor->offset = offset;
+ cursor->rest = limit;
+
+ cursor->current_area = GRN_GEO_AREA_NORTH_EAST;
+ {
+ grn_geo_area_type area_type;
+ const grn_geo_point *top_left = &(cursor->top_left);
+ const grn_geo_point *bottom_right = &(cursor->bottom_right);
+ for (area_type = GRN_GEO_AREA_NORTH_EAST;
+ area_type < GRN_GEO_AREA_LAST;
+ area_type++) {
+ grn_geo_cursor_area_init(ctx, &(cursor->areas[area_type]),
+ area_type, top_left, bottom_right);
+ }
+ }
+ {
+ char minimum_reduce_bit_env[GRN_ENV_BUFFER_SIZE];
+ cursor->minimum_reduce_bit = 0;
+ grn_getenv("GRN_GEO_IN_RECTANGLE_MINIMUM_REDUCE_BIT",
+ minimum_reduce_bit_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (minimum_reduce_bit_env[0]) {
+ cursor->minimum_reduce_bit = atoi(minimum_reduce_bit_env);
+ }
+ if (cursor->minimum_reduce_bit < 1) {
+ cursor->minimum_reduce_bit = 1;
+ }
+ }
+ GRN_DB_OBJ_SET_TYPE(cursor, GRN_CURSOR_COLUMN_GEO_INDEX);
+ {
+ grn_obj *db;
+ grn_id id;
+ db = grn_ctx_db(ctx);
+ id = grn_obj_register(ctx, db, NULL, 0);
+ DB_OBJ(cursor)->header.domain = GRN_ID_NIL;
+ DB_OBJ(cursor)->range = GRN_ID_NIL;
+ grn_db_obj_init(ctx, db, id, DB_OBJ(cursor));
+ }
+
+exit :
+ grn_obj_unlink(ctx, &(data.top_left_point_buffer));
+ grn_obj_unlink(ctx, &(data.bottom_right_point_buffer));
+ GRN_API_RETURN((grn_obj *)cursor);
+}
+
+static inline grn_bool
+grn_geo_cursor_entry_next_push(grn_ctx *ctx,
+ grn_geo_cursor_in_rectangle *cursor,
+ grn_geo_cursor_entry *entry)
+{
+ grn_geo_cursor_entry *next_entry;
+ grn_geo_point entry_base;
+ grn_table_cursor *pat_cursor;
+ grn_bool pushed = GRN_FALSE;
+
+ grn_ntog((uint8_t*)(&entry_base), entry->key, sizeof(grn_geo_point));
+ pat_cursor = grn_table_cursor_open(ctx,
+ cursor->pat,
+ &entry_base,
+ entry->target_bit + 1,
+ NULL, 0,
+ 0, -1,
+ GRN_CURSOR_PREFIX|GRN_CURSOR_SIZE_BY_BIT);
+ if (pat_cursor) {
+ if (grn_table_cursor_next(ctx, pat_cursor)) {
+ grn_geo_cursor_area *area;
+ area = &(cursor->areas[cursor->current_area]);
+ next_entry = &(area->entries[++area->current_entry]);
+ grn_memcpy(next_entry, entry, sizeof(grn_geo_cursor_entry));
+ pushed = GRN_TRUE;
+ }
+ grn_table_cursor_close(ctx, pat_cursor);
+ }
+
+ return pushed;
+}
+
+static inline grn_bool
+grn_geo_cursor_entry_next(grn_ctx *ctx,
+ grn_geo_cursor_in_rectangle *cursor,
+ grn_geo_cursor_entry *entry)
+{
+ uint8_t *top_left_key;
+ uint8_t *bottom_right_key;
+ int max_target_bit = GRN_GEO_KEY_MAX_BITS - cursor->minimum_reduce_bit;
+ grn_geo_cursor_area *area = NULL;
+
+ while (cursor->current_area < GRN_GEO_AREA_LAST) {
+ area = &(cursor->areas[cursor->current_area]);
+ if (area->current_entry >= 0) {
+ break;
+ }
+ cursor->current_area++;
+ area = NULL;
+ }
+
+ if (!area) {
+ return GRN_FALSE;
+ }
+
+ top_left_key = area->top_left_key;
+ bottom_right_key = area->bottom_right_key;
+ grn_memcpy(entry,
+ &(area->entries[area->current_entry--]),
+ sizeof(grn_geo_cursor_entry));
+ while (GRN_TRUE) {
+ grn_geo_cursor_entry next_entry0, next_entry1;
+ grn_bool pushed = GRN_FALSE;
+
+ /*
+ top_left_key: tl
+ bottom_right_key: br
+
+ e.g.: top_left_key is at the top left sub mesh and
+ bottom_right_key is at the bottom right sub mesh.
+ top_left_key is also at the top left - bottom right
+ sub-sub mesh and
+ bottom_right_key is at the bottom right - bottom left
+ sub-sub mesh.
+
+ ^latitude +----+----+----+----+
+ | 1 |1010|1011|1110|1111|
+ | | | | | |
+ | 1 +----+----+----+----+
+ \/ 0 |1000|1001|1100|1101|
+ | | tl | | |
+ +----+----+----+----+
+ 1 |0010|0011|0110|0111|
+ | | | | |
+ 0 +----+----+----+----+
+ 0 |0000|0001|0100|0101|
+ | | | br | |
+ +----+----+----+----+
+ 0 1 0 1
+ |-------| |-------|
+ 0 1
+ <------>
+ longitude
+
+ entry.target_bit + 1 -> next_entry0
+ entry.target_bit + 1 and entry.key ^ (entry.target_bit + 1) in bit
+ -> next_entry1
+
+ entry: represents the biggest mesh.
+ (1010, 1011, 1110, 1111,
+ 1000, 1001, 1100, 1101,
+ 0010, 0011, 0110, 0111,
+ 0000, 0001, 0100, 0101)
+ next_entry0: represents bottom sub-mesh.
+ (0010, 0011, 0110, 0111,
+ 0000, 0001, 0100, 0101)
+ next_entry1: represents top sub-mesh.
+ (1010, 1011, 1110, 1111,
+ 1000, 1001, 1100, 1101)
+
+ entry->status_flags = TOP_INCLUDED |
+ BOTTOM_INCLUDED |
+ LEFT_INCLUDED |
+ RIGHT_INCLUDED
+ next_entry0->status_flags = BOTTOM_INCLUDED |
+ LEFT_INCLUDED |
+ RIGHT_INCLUDED
+ next_entry1->status_flags = TOP_INCLUDED |
+ LEFT_INCLUDED |
+ RIGHT_INCLUDED
+
+ Both next_entry1 and next_entry0 are pushed to the stack in cursor.
+ */
+
+#ifdef GEO_DEBUG
+ inspect_cursor_entry(ctx, entry);
+#endif
+
+ if (entry->target_bit >= max_target_bit) {
+#ifdef GEO_DEBUG
+ printf("%d: force stopping to reduce a mesh\n", entry->target_bit);
+#endif
+ break;
+ }
+
+ if (CURSOR_ENTRY_IS_INNER(entry)) {
+#ifdef GEO_DEBUG
+ printf("%d: inner entries\n", entry->target_bit);
+#endif
+ break;
+ }
+
+ grn_memcpy(&next_entry0, entry, sizeof(grn_geo_cursor_entry));
+ next_entry0.target_bit++;
+ grn_memcpy(&next_entry1, entry, sizeof(grn_geo_cursor_entry));
+ next_entry1.target_bit++;
+ SET_N_BIT(next_entry1.key, next_entry1.target_bit);
+
+#ifdef GEO_DEBUG
+ inspect_cursor_entry_targets(ctx, entry, top_left_key, bottom_right_key,
+ &next_entry0, &next_entry1);
+#endif
+
+ if ((entry->target_bit + 1) % 2 == 0) {
+ if (CURSOR_ENTRY_CHECK_STATUS(entry, TOP_INCLUDED)) {
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry0, TOP_INCLUDED, top_left_key);
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry1, TOP_INCLUDED, top_left_key);
+ }
+ if (CURSOR_ENTRY_CHECK_STATUS(entry, BOTTOM_INCLUDED)) {
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry0, BOTTOM_INCLUDED,
+ bottom_right_key);
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry1, BOTTOM_INCLUDED,
+ bottom_right_key);
+ }
+
+ if (CURSOR_ENTRY_CHECK_STATUS(entry, TOP_INCLUDED) &&
+ !CURSOR_ENTRY_CHECK_STATUS(entry, BOTTOM_INCLUDED) &&
+ CURSOR_ENTRY_CHECK_STATUS(&next_entry1, TOP_INCLUDED)) {
+ next_entry0.status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER;
+ } else if (!CURSOR_ENTRY_CHECK_STATUS(entry, TOP_INCLUDED) &&
+ CURSOR_ENTRY_CHECK_STATUS(entry, BOTTOM_INCLUDED) &&
+ CURSOR_ENTRY_CHECK_STATUS(&next_entry0, BOTTOM_INCLUDED)) {
+ next_entry1.status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER;
+ }
+
+ if (CURSOR_ENTRY_INCLUDED_IN_LATITUDE_DIRECTION(&next_entry1)) {
+ if (grn_geo_cursor_entry_next_push(ctx, cursor, &next_entry1)) {
+ pushed = GRN_TRUE;
+#ifdef GEO_DEBUG
+ printf("%d: latitude: push 1\n", next_entry1.target_bit);
+#endif
+ }
+ }
+ if (CURSOR_ENTRY_INCLUDED_IN_LATITUDE_DIRECTION(&next_entry0)) {
+ if (grn_geo_cursor_entry_next_push(ctx, cursor, &next_entry0)) {
+ pushed = GRN_TRUE;
+#ifdef GEO_DEBUG
+ printf("%d: latitude: push 0\n", next_entry0.target_bit);
+#endif
+ }
+ }
+ } else {
+ if (CURSOR_ENTRY_CHECK_STATUS(entry, RIGHT_INCLUDED)) {
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry0, RIGHT_INCLUDED,
+ bottom_right_key);
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry1, RIGHT_INCLUDED,
+ bottom_right_key);
+ }
+ if (CURSOR_ENTRY_CHECK_STATUS(entry, LEFT_INCLUDED)) {
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry0, LEFT_INCLUDED, top_left_key);
+ CURSOR_ENTRY_UPDATE_STATUS(&next_entry1, LEFT_INCLUDED, top_left_key);
+ }
+
+ if (CURSOR_ENTRY_CHECK_STATUS(entry, LEFT_INCLUDED) &&
+ !CURSOR_ENTRY_CHECK_STATUS(entry, RIGHT_INCLUDED) &&
+ CURSOR_ENTRY_CHECK_STATUS(&next_entry0, LEFT_INCLUDED)) {
+ next_entry1.status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER;
+ } else if (!CURSOR_ENTRY_CHECK_STATUS(entry, LEFT_INCLUDED) &&
+ CURSOR_ENTRY_CHECK_STATUS(entry, RIGHT_INCLUDED) &&
+ CURSOR_ENTRY_CHECK_STATUS(&next_entry1, RIGHT_INCLUDED)) {
+ next_entry0.status_flags |= GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER;
+ }
+
+ if (CURSOR_ENTRY_INCLUDED_IN_LONGITUDE_DIRECTION(&next_entry1)) {
+ if (grn_geo_cursor_entry_next_push(ctx, cursor, &next_entry1)) {
+ pushed = GRN_TRUE;
+#ifdef GEO_DEBUG
+ printf("%d: longitude: push 1\n", next_entry1.target_bit);
+#endif
+ }
+ }
+ if (CURSOR_ENTRY_INCLUDED_IN_LONGITUDE_DIRECTION(&next_entry0)) {
+ if (grn_geo_cursor_entry_next_push(ctx, cursor, &next_entry0)) {
+ pushed = GRN_TRUE;
+#ifdef GEO_DEBUG
+ printf("%d: longitude: push 0\n", next_entry0.target_bit);
+#endif
+ }
+ }
+ }
+
+ if (pushed) {
+#ifdef GEO_DEBUG
+ int i;
+
+ printf("%d: pushed\n", entry->target_bit);
+ printf("stack:\n");
+ for (i = area->current_entry; i >= 0; i--) {
+ grn_geo_cursor_entry *stack_entry;
+ stack_entry = &(area->entries[i]);
+ printf("%2d: ", i);
+ inspect_key(ctx, stack_entry->key);
+ printf(" ");
+ print_key_mark(ctx, stack_entry->target_bit);
+ }
+#endif
+ grn_memcpy(entry,
+ &(area->entries[area->current_entry--]),
+ sizeof(grn_geo_cursor_entry));
+#ifdef GEO_DEBUG
+ printf("%d: pop entry\n", entry->target_bit);
+#endif
+ } else {
+ break;
+ }
+ }
+
+#ifdef GEO_DEBUG
+ printf("found:\n");
+ inspect_cursor_entry(ctx, entry);
+#endif
+
+ return GRN_TRUE;
+}
+
+typedef grn_bool (*grn_geo_cursor_callback)(grn_ctx *ctx, grn_posting *posting, void *user_data);
+
+static void
+grn_geo_cursor_each(grn_ctx *ctx, grn_obj *geo_cursor,
+ grn_geo_cursor_callback callback, void *user_data)
+{
+ grn_geo_cursor_in_rectangle *cursor;
+ grn_obj *pat;
+ grn_table_cursor *pat_cursor;
+ grn_ii *ii;
+ grn_ii_cursor *ii_cursor;
+ grn_posting *posting = NULL;
+ grn_geo_point *current, *top_left, *bottom_right;
+ grn_id index_id;
+
+ cursor = (grn_geo_cursor_in_rectangle *)geo_cursor;
+ if (cursor->rest == 0) {
+ return;
+ }
+
+ pat = cursor->pat;
+ pat_cursor = cursor->pat_cursor;
+ ii = (grn_ii *)(cursor->index);
+ ii_cursor = cursor->ii_cursor;
+ current = &(cursor->current);
+ top_left = &(cursor->top_left);
+ bottom_right = &(cursor->bottom_right);
+
+ while (GRN_TRUE) {
+ if (!pat_cursor) {
+ grn_geo_cursor_entry entry;
+ grn_geo_point entry_base;
+ if (!grn_geo_cursor_entry_next(ctx, cursor, &entry)) {
+ cursor->rest = 0;
+ return;
+ }
+ grn_ntog((uint8_t*)(&entry_base), entry.key, sizeof(grn_geo_point));
+ if (!(cursor->pat_cursor = pat_cursor =
+ grn_table_cursor_open(ctx,
+ pat,
+ &entry_base,
+ entry.target_bit + 1,
+ NULL, 0,
+ 0, -1,
+ GRN_CURSOR_PREFIX|GRN_CURSOR_SIZE_BY_BIT))) {
+ cursor->rest = 0;
+ return;
+ }
+#ifdef GEO_DEBUG
+ inspect_mesh(ctx, &entry_base, entry.target_bit, 0);
+#endif
+ }
+
+ while (ii_cursor || (index_id = grn_table_cursor_next(ctx, pat_cursor))) {
+ if (!ii_cursor) {
+ grn_table_get_key(ctx, pat, index_id, current, sizeof(grn_geo_point));
+ if (grn_geo_in_rectangle_raw(ctx, current, top_left, bottom_right)) {
+ inspect_tid(ctx, index_id, current, 0);
+ if (!(cursor->ii_cursor = ii_cursor =
+ grn_ii_cursor_open(ctx,
+ ii,
+ index_id,
+ GRN_ID_NIL,
+ GRN_ID_MAX,
+ ii->n_elements,
+ 0))) {
+ continue;
+ }
+ } else {
+ continue;
+ }
+ }
+
+ while ((posting = grn_ii_cursor_next(ctx, ii_cursor))) {
+ if (cursor->offset == 0) {
+ grn_bool keep_each;
+ keep_each = callback(ctx, posting, user_data);
+ if (cursor->rest > 0) {
+ if (--(cursor->rest) == 0) {
+ keep_each = GRN_FALSE;
+ }
+ }
+ if (!keep_each) {
+ return;
+ }
+ } else {
+ cursor->offset--;
+ }
+ }
+ grn_ii_cursor_close(ctx, ii_cursor);
+ cursor->ii_cursor = ii_cursor = NULL;
+ }
+ grn_table_cursor_close(ctx, pat_cursor);
+ cursor->pat_cursor = pat_cursor = NULL;
+ }
+}
+
+static grn_bool
+grn_geo_cursor_next_callback(grn_ctx *ctx, grn_posting *posting,
+ void *user_data)
+{
+ grn_posting **return_posting = user_data;
+ *return_posting = posting;
+ return GRN_FALSE;
+}
+
+grn_posting *
+grn_geo_cursor_next(grn_ctx *ctx, grn_obj *geo_cursor)
+{
+ grn_posting *posting = NULL;
+ grn_geo_cursor_each(ctx, geo_cursor, grn_geo_cursor_next_callback, &posting);
+ return (grn_posting *)posting;
+}
+
+grn_rc
+grn_geo_cursor_close(grn_ctx *ctx, grn_obj *geo_cursor)
+{
+ grn_geo_cursor_in_rectangle *cursor;
+
+ if (!geo_cursor) { return GRN_INVALID_ARGUMENT; }
+
+ cursor = (grn_geo_cursor_in_rectangle *)geo_cursor;
+ if (cursor->pat) { grn_obj_unlink(ctx, cursor->pat); }
+ if (cursor->index) { grn_obj_unlink(ctx, cursor->index); }
+ if (cursor->pat_cursor) { grn_table_cursor_close(ctx, cursor->pat_cursor); }
+ if (cursor->ii_cursor) { grn_ii_cursor_close(ctx, cursor->ii_cursor); }
+ GRN_FREE(cursor);
+
+ return GRN_SUCCESS;
+}
+
+typedef struct {
+ grn_hash *res;
+ grn_operator op;
+} grn_geo_select_in_rectangle_data;
+
+static grn_bool
+grn_geo_select_in_rectangle_callback(grn_ctx *ctx, grn_posting *posting,
+ void *user_data)
+{
+ grn_geo_select_in_rectangle_data *data = user_data;
+ grn_ii_posting_add(ctx, posting, data->res, data->op);
+ return GRN_TRUE;
+}
+
+grn_rc
+grn_geo_select_in_rectangle(grn_ctx *ctx, grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point,
+ grn_obj *res, grn_operator op)
+{
+ grn_obj *cursor;
+
+ cursor = grn_geo_cursor_open_in_rectangle(ctx, index,
+ top_left_point, bottom_right_point,
+ 0, -1);
+ if (cursor) {
+ grn_geo_select_in_rectangle_data data;
+ data.res = (grn_hash *)res;
+ data.op = op;
+ grn_geo_cursor_each(ctx, cursor, grn_geo_select_in_rectangle_callback,
+ &data);
+ grn_obj_unlink(ctx, cursor);
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ }
+
+ return ctx->rc;
+}
+
+static grn_rc
+geo_point_get(grn_ctx *ctx, grn_obj *pat, int flags, grn_geo_point *geo_point)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_id id;
+ grn_table_cursor *cursor = NULL;
+
+ cursor = grn_table_cursor_open(ctx, pat,
+ NULL, 0,
+ NULL, 0,
+ 0, 1,
+ GRN_CURSOR_BY_KEY | flags);
+ if (!cursor) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ id = grn_table_cursor_next(ctx, cursor);
+ if (id == GRN_ID_NIL) {
+ rc = GRN_END_OF_DATA;
+ } else {
+ void *key;
+ int key_size;
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ grn_memcpy(geo_point, key, key_size);
+ }
+
+exit:
+ if (cursor) {
+ grn_table_cursor_close(ctx, cursor);
+ }
+ return rc;
+}
+
+uint32_t
+grn_geo_estimate_size_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point)
+{
+ uint32_t n = 0;
+ int total_records;
+ grn_rc rc;
+ in_rectangle_data data;
+
+ GRN_VOID_INIT(&(data.top_left_point_buffer));
+ GRN_VOID_INIT(&(data.bottom_right_point_buffer));
+ if (in_rectangle_data_prepare(ctx, index, top_left_point, bottom_right_point,
+ "grn_geo_estimate_in_rectangle()", &data)) {
+ goto exit;
+ }
+
+ total_records = grn_table_size(ctx, data.pat);
+ if (total_records > 0) {
+ grn_geo_point min, max;
+ int select_latitude_distance, select_longitude_distance;
+ int total_latitude_distance, total_longitude_distance;
+ double select_ratio;
+ double estimated_n_records;
+ in_rectangle_area_data area_data;
+
+ rc = geo_point_get(ctx, data.pat, GRN_CURSOR_ASCENDING, &min);
+ if (!rc) {
+ rc = geo_point_get(ctx, data.pat, GRN_CURSOR_DESCENDING, &max);
+ }
+ if (rc) {
+ if (rc == GRN_END_OF_DATA) {
+ n = total_records;
+ rc = GRN_SUCCESS;
+ }
+ goto exit;
+ }
+
+ in_rectangle_area_data_compute(ctx,
+ data.top_left,
+ data.bottom_right,
+ &area_data);
+ select_latitude_distance =
+ abs(area_data.max.latitude - area_data.min.latitude);
+ select_longitude_distance =
+ abs(area_data.max.longitude - area_data.min.longitude);
+ total_latitude_distance = abs(max.latitude - min.latitude);
+ total_longitude_distance = abs(max.longitude - min.longitude);
+
+ select_ratio = 1.0;
+ if (select_latitude_distance < total_latitude_distance) {
+ select_ratio *= ((double)select_latitude_distance /
+ (double)total_latitude_distance);
+ }
+ if (select_longitude_distance < total_longitude_distance) {
+ select_ratio *= ((double)select_longitude_distance /
+ (double)total_longitude_distance);
+ }
+ estimated_n_records = ceil(total_records * select_ratio);
+ n = (uint32_t)estimated_n_records;
+ }
+
+exit :
+ grn_obj_unlink(ctx, &(data.top_left_point_buffer));
+ grn_obj_unlink(ctx, &(data.bottom_right_point_buffer));
+ return n;
+}
+
+int
+grn_geo_estimate_in_rectangle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *top_left_point,
+ grn_obj *bottom_right_point)
+{
+ uint32_t size;
+
+ size = grn_geo_estimate_size_in_rectangle(ctx,
+ index,
+ top_left_point,
+ bottom_right_point);
+ if (ctx->rc != GRN_SUCCESS) {
+ return -1;
+ }
+
+ return size;
+}
+
+grn_bool
+grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center,
+ grn_obj *radius_or_point,
+ grn_geo_approximate_type approximate_type)
+{
+ grn_bool r = GRN_FALSE;
+ grn_obj center_, radius_or_point_;
+ grn_id domain = point->header.domain;
+ if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) {
+ grn_geo_distance_raw_func distance_raw_func;
+ double d;
+ if (center->header.domain != domain) {
+ GRN_OBJ_INIT(&center_, GRN_BULK, 0, domain);
+ if (grn_obj_cast(ctx, center, &center_, GRN_FALSE)) { goto exit; }
+ center = &center_;
+ }
+
+ distance_raw_func = grn_geo_resolve_distance_raw_func(ctx,
+ approximate_type,
+ domain);
+ if (!distance_raw_func) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "unknown approximate type: <%d>", approximate_type);
+ goto exit;
+ }
+ d = distance_raw_func(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point),
+ GRN_GEO_POINT_VALUE_RAW(center));
+ switch (radius_or_point->header.domain) {
+ case GRN_DB_INT32 :
+ r = d <= GRN_INT32_VALUE(radius_or_point);
+ break;
+ case GRN_DB_UINT32 :
+ r = d <= GRN_UINT32_VALUE(radius_or_point);
+ break;
+ case GRN_DB_INT64 :
+ r = d <= GRN_INT64_VALUE(radius_or_point);
+ break;
+ case GRN_DB_UINT64 :
+ r = d <= GRN_UINT64_VALUE(radius_or_point);
+ break;
+ case GRN_DB_FLOAT :
+ r = d <= GRN_FLOAT_VALUE(radius_or_point);
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ GRN_OBJ_INIT(&radius_or_point_, GRN_BULK, 0, domain);
+ if (grn_obj_cast(ctx, radius_or_point, &radius_or_point_, GRN_FALSE)) { goto exit; }
+ radius_or_point = &radius_or_point_;
+ /* fallthru */
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ if (domain != radius_or_point->header.domain) { /* todo */ goto exit; }
+ r = d <= distance_raw_func(ctx,
+ GRN_GEO_POINT_VALUE_RAW(radius_or_point),
+ GRN_GEO_POINT_VALUE_RAW(center));
+ break;
+ default :
+ goto exit;
+ }
+ } else {
+ /* todo */
+ }
+exit :
+ return r;
+}
+
+grn_bool
+grn_geo_in_rectangle_raw(grn_ctx *ctx, grn_geo_point *point,
+ grn_geo_point *top_left, grn_geo_point *bottom_right)
+{
+ if (point->latitude > top_left->latitude) {
+ return GRN_FALSE;
+ }
+ if (point->latitude < bottom_right->latitude) {
+ return GRN_FALSE;
+ }
+
+ if (GRN_GEO_LONGITUDE_IS_WRAPPED(top_left, bottom_right)) {
+ if (point->longitude >= top_left->longitude) {
+ return GRN_TRUE;
+ }
+ if (point->longitude <= bottom_right->longitude) {
+ return GRN_TRUE;
+ }
+ return GRN_FALSE;
+ } else {
+ if (point->longitude < top_left->longitude) {
+ return GRN_FALSE;
+ }
+ if (point->longitude > bottom_right->longitude) {
+ return GRN_FALSE;
+ }
+ return GRN_TRUE;
+ }
+}
+
+grn_bool
+grn_geo_in_rectangle(grn_ctx *ctx, grn_obj *point,
+ grn_obj *top_left, grn_obj *bottom_right)
+{
+ grn_bool r = GRN_FALSE;
+ grn_obj top_left_, bottom_right_;
+ grn_id domain = point->header.domain;
+ if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) {
+ if (top_left->header.domain != domain) {
+ GRN_OBJ_INIT(&top_left_, GRN_BULK, 0, domain);
+ if (grn_obj_cast(ctx, top_left, &top_left_, GRN_FALSE)) { goto exit; }
+ top_left = &top_left_;
+ }
+ if (bottom_right->header.domain != domain) {
+ GRN_OBJ_INIT(&bottom_right_, GRN_BULK, 0, domain);
+ if (grn_obj_cast(ctx, bottom_right, &bottom_right_, GRN_FALSE)) { goto exit; }
+ bottom_right = &bottom_right_;
+ }
+ r = grn_geo_in_rectangle_raw(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point),
+ GRN_GEO_POINT_VALUE_RAW(top_left),
+ GRN_GEO_POINT_VALUE_RAW(bottom_right));
+ } else {
+ /* todo */
+ }
+exit :
+ return r;
+}
+
+typedef enum {
+ LONGITUDE_SHORT,
+ LONGITUDE_LONG,
+} distance_type;
+
+typedef enum {
+ QUADRANT_1ST,
+ QUADRANT_2ND,
+ QUADRANT_3RD,
+ QUADRANT_4TH,
+ QUADRANT_1ST_TO_2ND,
+ QUADRANT_1ST_TO_3RD,
+ QUADRANT_1ST_TO_4TH,
+ QUADRANT_2ND_TO_1ST,
+ QUADRANT_2ND_TO_3RD,
+ QUADRANT_2ND_TO_4TH,
+ QUADRANT_3RD_TO_1ST,
+ QUADRANT_3RD_TO_2ND,
+ QUADRANT_3RD_TO_4TH,
+ QUADRANT_4TH_TO_1ST,
+ QUADRANT_4TH_TO_2ND,
+ QUADRANT_4TH_TO_3RD,
+} quadrant_type;
+
+static distance_type
+geo_longitude_distance_type(int start_longitude, int end_longitude)
+{
+ int diff_longitude;
+ int east_to_west;
+ int west_to_east;
+ if (start_longitude >= 0) {
+ diff_longitude = abs(start_longitude - end_longitude);
+ } else {
+ diff_longitude = abs(end_longitude - start_longitude);
+ }
+ east_to_west = start_longitude > 0 && end_longitude < 0;
+ west_to_east = start_longitude < 0 && end_longitude > 0;
+ if (start_longitude != end_longitude &&
+ (east_to_west || west_to_east) &&
+ diff_longitude > 180 * GRN_GEO_RESOLUTION) {
+ return LONGITUDE_LONG;
+ } else {
+ return LONGITUDE_SHORT;
+ }
+}
+
+static inline quadrant_type
+geo_quadrant_type(grn_geo_point *point1, grn_geo_point *point2)
+{
+#define QUADRANT_1ST_WITH_AXIS(point) \
+ (point->longitude >= 0) && (point->latitude >= 0)
+#define QUADRANT_2ND_WITH_AXIS(point) \
+ (point->longitude <= 0) && (point->latitude >= 0)
+#define QUADRANT_3RD_WITH_AXIS(point) \
+ (point->longitude <= 0) && (point->latitude <= 0)
+#define QUADRANT_4TH_WITH_AXIS(point) \
+ (point->longitude >= 0) && (point->latitude <= 0)
+
+ if (QUADRANT_1ST_WITH_AXIS(point1) && QUADRANT_1ST_WITH_AXIS(point2)) {
+ return QUADRANT_1ST;
+ } else if (QUADRANT_2ND_WITH_AXIS(point1) && QUADRANT_2ND_WITH_AXIS(point2)) {
+ return QUADRANT_2ND;
+ } else if (QUADRANT_3RD_WITH_AXIS(point1) && QUADRANT_3RD_WITH_AXIS(point2)) {
+ return QUADRANT_3RD;
+ } else if (QUADRANT_4TH_WITH_AXIS(point1) && QUADRANT_4TH_WITH_AXIS(point2)) {
+ return QUADRANT_4TH;
+ } else {
+ if (point1->longitude > 0 && point2->longitude < 0 &&
+ point1->latitude >= 0 && point2->latitude >= 0) {
+ return QUADRANT_1ST_TO_2ND;
+ } else if (point1->longitude < 0 && point2->longitude > 0 &&
+ point1->latitude >= 0 && point2->latitude >= 0) {
+ return QUADRANT_2ND_TO_1ST;
+ } else if (point1->longitude < 0 && point2->longitude > 0 &&
+ point1->latitude <= 0 && point2->latitude <= 0) {
+ return QUADRANT_3RD_TO_4TH;
+ } else if (point1->longitude > 0 && point2->longitude < 0 &&
+ point1->latitude <= 0 && point2->latitude <= 0) {
+ return QUADRANT_4TH_TO_3RD;
+ } else if (point1->longitude >= 0 && point2->longitude >= 0 &&
+ point1->latitude > 0 && point2->latitude < 0) {
+ return QUADRANT_1ST_TO_4TH;
+ } else if (point1->longitude >= 0 && point2->longitude >= 0 &&
+ point1->latitude < 0 && point2->latitude > 0) {
+ return QUADRANT_4TH_TO_1ST;
+ } else if (point1->longitude <= 0 && point2->longitude <= 0 &&
+ point1->latitude > 0 && point2->latitude < 0) {
+ return QUADRANT_2ND_TO_3RD;
+ } else if (point1->longitude <= 0 && point2->longitude <= 0 &&
+ point1->latitude < 0 && point2->latitude > 0) {
+ return QUADRANT_3RD_TO_2ND;
+ } else if (point1->longitude >= 0 && point2->longitude <= 0 &&
+ point1->latitude > 0 && point2->latitude < 0) {
+ return QUADRANT_1ST_TO_3RD;
+ } else if (point1->longitude <= 0 && point2->longitude >= 0 &&
+ point1->latitude < 0 && point2->latitude > 0) {
+ return QUADRANT_3RD_TO_1ST;
+ } else if (point1->longitude <= 0 && point2->longitude >= 0 &&
+ point1->latitude > 0 && point2->latitude < 0) {
+ return QUADRANT_2ND_TO_4TH;
+ } else if (point1->longitude >= 0 && point2->longitude <= 0 &&
+ point1->latitude < 0 && point2->latitude > 0) {
+ return QUADRANT_4TH_TO_2ND;
+ } else {
+ /* FIXME */
+ return QUADRANT_1ST;
+ }
+ }
+#undef QUADRANT_1ST_WITH_AXIS
+#undef QUADRANT_2ND_WITH_AXIS
+#undef QUADRANT_3RD_WITH_AXIS
+#undef QUADRANT_4TH_WITH_AXIS
+}
+
+static inline double
+geo_distance_rectangle_square_root(double start_longitude, double start_latitude,
+ double end_longitude, double end_latitude)
+{
+ double diff_longitude;
+ double x, y;
+
+ diff_longitude = end_longitude - start_longitude;
+ x = diff_longitude * cos((start_latitude + end_latitude) * 0.5);
+ y = end_latitude - start_latitude;
+ return sqrt((x * x) + (y * y));
+}
+
+static inline double
+geo_distance_rectangle_short_dist_type(quadrant_type quad_type,
+ double lng1, double lat1,
+ double lng2, double lat2)
+{
+ double distance;
+ double longitude_delta, latitude_delta;
+
+ if (quad_type == QUADRANT_1ST_TO_4TH ||
+ quad_type == QUADRANT_4TH_TO_1ST ||
+ quad_type == QUADRANT_2ND_TO_3RD ||
+ quad_type == QUADRANT_3RD_TO_2ND) {
+ longitude_delta = lng2 - lng1;
+ if (longitude_delta > 0 || longitude_delta < 0) {
+ if (lat2 > lat1) {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ } else {
+ distance = geo_distance_rectangle_square_root(lng2,
+ lat2,
+ lng1,
+ lat1) * GRN_GEO_RADIUS;
+ }
+ } else {
+ latitude_delta = fabs(lat1) + fabs(lat2);
+ distance = sqrt(latitude_delta * latitude_delta) * GRN_GEO_RADIUS;
+ }
+ } else if (quad_type == QUADRANT_1ST_TO_3RD ||
+ quad_type == QUADRANT_2ND_TO_4TH) {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ } else if (quad_type == QUADRANT_3RD_TO_1ST ||
+ quad_type == QUADRANT_4TH_TO_2ND) {
+ distance = geo_distance_rectangle_square_root(lng2,
+ lat2,
+ lng1,
+ lat1) * GRN_GEO_RADIUS;
+ } else if (quad_type == QUADRANT_1ST_TO_2ND ||
+ quad_type == QUADRANT_2ND_TO_1ST ||
+ quad_type == QUADRANT_3RD_TO_4TH ||
+ quad_type == QUADRANT_4TH_TO_3RD) {
+ if (lat2 > lat1) {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ } else if (lat2 < lat1) {
+ distance = geo_distance_rectangle_square_root(lng2,
+ lat2,
+ lng1,
+ lat1) * GRN_GEO_RADIUS;
+ } else {
+ longitude_delta = lng2 - lng1;
+ distance = longitude_delta * cos(lat1);
+ distance = sqrt(distance * distance) * GRN_GEO_RADIUS;
+ }
+ } else {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ }
+ return distance;
+}
+
+static inline double
+geo_distance_rectangle_long_dist_type(quadrant_type quad_type,
+ double lng1, double lat1,
+ double lng2, double lat2)
+{
+#define M_2PI 6.28318530717958647692
+
+ double distance;
+
+ if (quad_type == QUADRANT_1ST_TO_2ND ||
+ quad_type == QUADRANT_4TH_TO_3RD) {
+ if (lat1 > lat2) {
+ distance = geo_distance_rectangle_square_root(lng2 + M_2PI,
+ lat2,
+ lng1,
+ lat1) * GRN_GEO_RADIUS;
+ } else {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2 + M_2PI,
+ lat2) * GRN_GEO_RADIUS;
+ }
+ } else if (quad_type == QUADRANT_2ND_TO_1ST ||
+ quad_type == QUADRANT_3RD_TO_4TH) {
+ if (lat1 > lat2) {
+ distance = geo_distance_rectangle_square_root(lng2,
+ lat2,
+ lng1 + M_2PI,
+ lat1) * GRN_GEO_RADIUS;
+ } else {
+ distance = geo_distance_rectangle_square_root(lng1 + M_2PI,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ }
+ } else if (quad_type == QUADRANT_1ST_TO_3RD) {
+ distance = geo_distance_rectangle_square_root(lng2 + M_2PI,
+ lat2,
+ lng1,
+ lat1) * GRN_GEO_RADIUS;
+ } else if (quad_type == QUADRANT_3RD_TO_1ST) {
+ distance = geo_distance_rectangle_square_root(lng1 + M_2PI,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ } else if (quad_type == QUADRANT_2ND_TO_4TH) {
+ distance = geo_distance_rectangle_square_root(lng2,
+ lat2,
+ lng1 + M_2PI,
+ lat1) * GRN_GEO_RADIUS;
+ } else if (quad_type == QUADRANT_4TH_TO_2ND) {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2 + M_2PI,
+ lat2) * GRN_GEO_RADIUS;
+ } else {
+ if (lng1 > lng2) {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2 + M_2PI,
+ lat2) * GRN_GEO_RADIUS;
+ } else {
+ distance = geo_distance_rectangle_square_root(lng2,
+ lat2,
+ lng1 + M_2PI,
+ lat1) * GRN_GEO_RADIUS;
+ }
+ }
+ return distance;
+#undef M_2PI
+}
+
+double
+grn_geo_distance_rectangle_raw(grn_ctx *ctx,
+ grn_geo_point *point1, grn_geo_point *point2)
+{
+
+ double lng1, lat1, lng2, lat2, distance;
+ distance_type dist_type;
+ quadrant_type quad_type;
+
+ lat1 = GRN_GEO_INT2RAD(point1->latitude);
+ lng1 = GRN_GEO_INT2RAD(point1->longitude);
+ lat2 = GRN_GEO_INT2RAD(point2->latitude);
+ lng2 = GRN_GEO_INT2RAD(point2->longitude);
+ quad_type = geo_quadrant_type(point1, point2);
+ if (quad_type <= QUADRANT_4TH) {
+ distance = geo_distance_rectangle_square_root(lng1,
+ lat1,
+ lng2,
+ lat2) * GRN_GEO_RADIUS;
+ } else {
+ dist_type = geo_longitude_distance_type(point1->longitude,
+ point2->longitude);
+ if (dist_type == LONGITUDE_SHORT) {
+ distance = geo_distance_rectangle_short_dist_type(quad_type,
+ lng1, lat1,
+ lng2, lat2);
+ } else {
+ distance = geo_distance_rectangle_long_dist_type(quad_type,
+ lng1, lat1,
+ lng2, lat2);
+ }
+ }
+ return distance;
+}
+
+double
+grn_geo_distance_sphere_raw(grn_ctx *ctx,
+ grn_geo_point *point1, grn_geo_point *point2)
+{
+ double lng1, lat1, lng2, lat2, x, y;
+
+ lat1 = GRN_GEO_INT2RAD(point1->latitude);
+ lng1 = GRN_GEO_INT2RAD(point1->longitude);
+ lat2 = GRN_GEO_INT2RAD(point2->latitude);
+ lng2 = GRN_GEO_INT2RAD(point2->longitude);
+ x = sin(fabs(lng2 - lng1) * 0.5);
+ y = sin(fabs(lat2 - lat1) * 0.5);
+ return asin(sqrt((y * y) + cos(lat1) * cos(lat2) * x * x)) * 2 * GRN_GEO_RADIUS;
+}
+
+double
+grn_geo_distance_ellipsoid_raw(grn_ctx *ctx,
+ grn_geo_point *point1, grn_geo_point *point2,
+ int c1, int c2, double c3)
+{
+ double lng1, lat1, lng2, lat2, p, q, r, m, n, x, y;
+
+ lat1 = GRN_GEO_INT2RAD(point1->latitude);
+ lng1 = GRN_GEO_INT2RAD(point1->longitude);
+ lat2 = GRN_GEO_INT2RAD(point2->latitude);
+ lng2 = GRN_GEO_INT2RAD(point2->longitude);
+ p = (lat1 + lat2) * 0.5;
+ q = (1 - c3 * sin(p) * sin(p));
+ r = sqrt(q);
+ m = c1 / (q * r);
+ n = c2 / r;
+ x = n * cos(p) * fabs(lng1 - lng2);
+ y = m * fabs(lat1 - lat2);
+ return sqrt((x * x) + (y * y));
+}
+
+double
+grn_geo_distance_ellipsoid_raw_tokyo(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2)
+{
+ return grn_geo_distance_ellipsoid_raw(ctx, point1, point2,
+ GRN_GEO_BES_C1,
+ GRN_GEO_BES_C2,
+ GRN_GEO_BES_C3);
+}
+
+double
+grn_geo_distance_ellipsoid_raw_wgs84(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2)
+{
+ return grn_geo_distance_ellipsoid_raw(ctx, point1, point2,
+ GRN_GEO_GRS_C1,
+ GRN_GEO_GRS_C2,
+ GRN_GEO_GRS_C3);
+}
+
+double
+grn_geo_distance(grn_ctx *ctx, grn_obj *point1, grn_obj *point2,
+ grn_geo_approximate_type type)
+{
+ double d = 0.0;
+
+ switch (type) {
+ case GRN_GEO_APPROXIMATE_RECTANGLE :
+ d = grn_geo_distance_rectangle(ctx, point1, point2);
+ break;
+ case GRN_GEO_APPROXIMATE_SPHERE :
+ d = grn_geo_distance_sphere(ctx, point1, point2);
+ break;
+ case GRN_GEO_APPROXIMATE_ELLIPSOID :
+ d = grn_geo_distance_ellipsoid(ctx, point1, point2);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "unknown approximate type: <%d>", type);
+ break;
+ }
+ return d;
+}
+
+double
+grn_geo_distance_rectangle(grn_ctx *ctx, grn_obj *point1, grn_obj *point2)
+{
+ double d = 0;
+ grn_bool point1_initialized = GRN_FALSE;
+ grn_bool point2_initialized = GRN_FALSE;
+ grn_obj point1_, point2_;
+ grn_id domain1 = point1->header.domain;
+ grn_id domain2 = point2->header.domain;
+ if (domain1 == GRN_DB_TOKYO_GEO_POINT || domain1 == GRN_DB_WGS84_GEO_POINT) {
+ if (domain1 != domain2) {
+ GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain1);
+ point2_initialized = GRN_TRUE;
+ if (grn_obj_cast(ctx, point2, &point2_, GRN_FALSE)) { goto exit; }
+ point2 = &point2_;
+ }
+ } else if (domain2 == GRN_DB_TOKYO_GEO_POINT ||
+ domain2 == GRN_DB_WGS84_GEO_POINT) {
+ GRN_OBJ_INIT(&point1_, GRN_BULK, 0, domain2);
+ point1_initialized = GRN_TRUE;
+ if (grn_obj_cast(ctx, point1, &point1_, GRN_FALSE)) { goto exit; }
+ point1 = &point1_;
+ } else if ((GRN_DB_SHORT_TEXT <= domain1 && domain1 <= GRN_DB_LONG_TEXT) &&
+ (GRN_DB_SHORT_TEXT <= domain2 && domain2 <= GRN_DB_LONG_TEXT)) {
+ GRN_OBJ_INIT(&point1_, GRN_BULK, 0, GRN_DB_WGS84_GEO_POINT);
+ point1_initialized = GRN_TRUE;
+ if (grn_obj_cast(ctx, point1, &point1_, GRN_FALSE)) { goto exit; }
+ point1 = &point1_;
+
+ GRN_OBJ_INIT(&point2_, GRN_BULK, 0, GRN_DB_WGS84_GEO_POINT);
+ point2_initialized = GRN_TRUE;
+ if (grn_obj_cast(ctx, point2, &point2_, GRN_FALSE)) { goto exit; }
+ point2 = &point2_;
+ } else {
+ goto exit;
+ }
+ d = grn_geo_distance_rectangle_raw(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point1),
+ GRN_GEO_POINT_VALUE_RAW(point2));
+exit :
+ if (point1_initialized) {
+ GRN_OBJ_FIN(ctx, &point1_);
+ }
+ if (point2_initialized) {
+ GRN_OBJ_FIN(ctx, &point2_);
+ }
+ return d;
+}
+
+double
+grn_geo_distance_sphere(grn_ctx *ctx, grn_obj *point1, grn_obj *point2)
+{
+ double d = 0;
+ grn_bool point2_initialized = GRN_FALSE;
+ grn_obj point2_;
+ grn_id domain = point1->header.domain;
+ if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) {
+ if (point2->header.domain != domain) {
+ GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain);
+ point2_initialized = GRN_TRUE;
+ if (grn_obj_cast(ctx, point2, &point2_, GRN_FALSE)) { goto exit; }
+ point2 = &point2_;
+ }
+ d = grn_geo_distance_sphere_raw(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point1),
+ GRN_GEO_POINT_VALUE_RAW(point2));
+ } else {
+ /* todo */
+ }
+exit :
+ if (point2_initialized) {
+ GRN_OBJ_FIN(ctx, &point2_);
+ }
+ return d;
+}
+
+double
+grn_geo_distance_ellipsoid(grn_ctx *ctx, grn_obj *point1, grn_obj *point2)
+{
+ double d = 0;
+ grn_bool point2_initialized = GRN_FALSE;
+ grn_obj point2_;
+ grn_id domain = point1->header.domain;
+ if (domain == GRN_DB_TOKYO_GEO_POINT || domain == GRN_DB_WGS84_GEO_POINT) {
+ if (point2->header.domain != domain) {
+ GRN_OBJ_INIT(&point2_, GRN_BULK, 0, domain);
+ point2_initialized = GRN_TRUE;
+ if (grn_obj_cast(ctx, point2, &point2_, GRN_FALSE)) { goto exit; }
+ point2 = &point2_;
+ }
+ if (domain == GRN_DB_TOKYO_GEO_POINT) {
+ d = grn_geo_distance_ellipsoid_raw_tokyo(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point1),
+ GRN_GEO_POINT_VALUE_RAW(point2));
+ } else {
+ d = grn_geo_distance_ellipsoid_raw_wgs84(ctx,
+ GRN_GEO_POINT_VALUE_RAW(point1),
+ GRN_GEO_POINT_VALUE_RAW(point2));
+ }
+ } else {
+ /* todo */
+ }
+exit :
+ if (point2_initialized) {
+ GRN_OBJ_FIN(ctx, &point2_);
+ }
+ return d;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/grn.h b/storage/mroonga/vendor/groonga/lib/grn.h
new file mode 100644
index 00000000..17a8c4e6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn.h
@@ -0,0 +1,759 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef WIN32
+# ifdef __GNUC__
+# define __MINGW_MSVC_COMPAT_WARNINGS
+# endif /* __GNUC__ */
+
+# ifdef __GNUC__
+# include <w32api.h>
+# define GRN_MINIMUM_WINDOWS_VERSION WindowsVista
+# else /* __GNUC__ */
+# define GRN_MINIMUM_WINDOWS_VERSION 0x0600 /* Vista */
+# endif /* __GNUC__ */
+
+# ifdef WINVER
+# undef WINVER
+# endif /* WINVER */
+# define WINVER GRN_MINIMUM_WINDOWS_VERSION
+# ifdef _WIN32_WINNT
+# undef _WIN32_WINNT
+# endif /* _WIN32_WINNT */
+# define _WIN32_WINNT GRN_MINIMUM_WINDOWS_VERSION
+# ifdef NTDDI_VERSION
+# undef NTDDI_VERSION
+# endif /* NTDDI_VERSION */
+# define NTDDI_VERSION GRN_MINIMUM_WINDOWS_VERSION
+
+# ifdef WIN32_LEAN_AND_MEAN
+# undef WIN32_LEAN_AND_MEAN
+# endif /* WIN32_LEAN_AND_MEAN */
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+# define __STDC_LIMIT_MACROS
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <sys/types.h>
+
+#ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif /* HAVE_SYS_PARAM_H */
+
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif /* HAVE_SYS_MMAN_H */
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif /* HAVE_SYS_TIME_H */
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#ifdef WIN32
+# define GRN_API __declspec(dllexport)
+# ifdef GROONGA_MAIN
+# define GRN_VAR __declspec(dllimport)
+# else
+# define GRN_VAR __declspec(dllexport) extern
+# endif /* GROONGA_MAIN */
+#else
+# define GRN_API
+# define GRN_VAR extern
+#endif
+
+#ifdef WIN32
+# include <basetsd.h>
+# include <process.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <windows.h>
+# include <stddef.h>
+# include <windef.h>
+# include <float.h>
+# include <time.h>
+# include <sys/types.h>
+
+# ifndef __GNUC__
+# define PATH_MAX (MAX_PATH - 1)
+# ifndef __cplusplus
+# define inline _inline
+# endif
+# endif
+
+# ifndef __GNUC__
+typedef SSIZE_T ssize_t;
+typedef int pid_t;
+typedef int64_t off64_t;
+# endif
+
+# undef MSG_WAITALL
+# define MSG_WAITALL 0 /* before Vista, not supported... */
+# define SHUT_RDWR SD_BOTH
+
+typedef SOCKET grn_sock;
+# define grn_sock_close(sock) closesocket(sock)
+
+# define CALLBACK __stdcall
+
+# ifndef __GNUC__
+# include <intrin.h>
+# include <sys/timeb.h>
+# include <errno.h>
+# endif
+
+#else /* WIN32 */
+
+# define GROONGA_API
+
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif /* HAVE_UNISTD_H */
+
+# ifndef __off64_t_defined
+typedef off_t off64_t;
+# endif
+
+# ifndef PATH_MAX
+# if defined(MAXPATHLEN)
+# define PATH_MAX MAXPATHLEN
+# else /* MAXPATHLEN */
+# define PATH_MAX 1024
+# endif /* MAXPATHLEN */
+# endif /* PATH_MAX */
+# ifndef INT_LEAST8_MAX
+typedef char int_least8_t;
+# endif /* INT_LEAST8_MAX */
+# ifndef UINT_LEAST8_MAX
+typedef unsigned char uint_least8_t;
+# endif /* UINT_LEAST8_MAX */
+typedef int grn_sock;
+# define grn_sock_close(sock) close(sock)
+# define CALLBACK
+
+#endif /* WIN32 */
+
+#ifndef INT8_MAX
+# define INT8_MAX (127)
+#endif /* INT8_MAX */
+
+#ifndef INT8_MIN
+# define INT8_MIN (-128)
+#endif /* INT8_MIN */
+
+#ifndef INT16_MAX
+# define INT16_MAX (32767)
+#endif /* INT16_MAX */
+
+#ifndef INT16_MIN
+# define INT16_MIN (-32768)
+#endif /* INT16_MIN */
+
+#ifndef INT32_MAX
+# define INT32_MAX (2147483647)
+#endif /* INT32_MAX */
+
+#ifndef INT32_MIN
+# define INT32_MIN (-2147483648)
+#endif /* INT32_MIN */
+
+#ifndef UINT32_MAX
+# define UINT32_MAX (4294967295)
+#endif /* UINT32_MAX */
+
+#ifndef INT64_MAX
+# define INT64_MAX (9223372036854775807)
+#endif /* INT64_MAX */
+
+#ifndef INT64_MIN
+# define INT64_MIN (-9223372036854775808)
+#endif /* INT64_MIN */
+
+
+#ifdef WIN32
+# define grn_lseek(fd, offset, whence) _lseeki64(fd, offset, whence)
+#else /* WIN32 */
+# define grn_lseek(fd, offset, whence) lseek(fd, offset, whence)
+#endif /* WIN32 */
+
+
+#ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+typedef pthread_t grn_thread;
+typedef void * grn_thread_func_result;
+# define GRN_THREAD_FUNC_RETURN_VALUE NULL
+# define THREAD_CREATE(thread,func,arg) \
+ (pthread_create(&(thread), NULL, (func), (arg)))
+# define THREAD_JOIN(thread) (pthread_join(thread, NULL))
+typedef pthread_mutex_t grn_mutex;
+# define MUTEX_INIT(m) pthread_mutex_init(&m, NULL)
+# define MUTEX_LOCK(m) pthread_mutex_lock(&m)
+# define MUTEX_LOCK_CHECK(m) (MUTEX_LOCK(m) == 0)
+# define MUTEX_UNLOCK(m) pthread_mutex_unlock(&m)
+# define MUTEX_FIN(m) pthread_mutex_destroy(&m)
+# ifdef HAVE_PTHREAD_MUTEXATTR_SETPSHARED
+# define MUTEX_INIT_SHARED(m) do {\
+ pthread_mutexattr_t mutexattr;\
+ pthread_mutexattr_init(&mutexattr);\
+ pthread_mutexattr_setpshared(&mutexattr, PTHREAD_PROCESS_SHARED);\
+ pthread_mutex_init(&m, &mutexattr);\
+} while (0)
+# else
+# define MUTEX_INIT_SHARED MUTEX_INIT
+# endif /* HAVE_PTHREAD_MUTEXATTR_SETPSHARED */
+
+typedef pthread_mutex_t grn_critical_section;
+# define CRITICAL_SECTION_INIT(cs) pthread_mutex_init(&(cs), NULL)
+# define CRITICAL_SECTION_ENTER(cs) pthread_mutex_lock(&(cs))
+# define CRITICAL_SECTION_LEAVE(cs) pthread_mutex_unlock(&(cs))
+# define CRITICAL_SECTION_FIN(cs)
+
+typedef pthread_cond_t grn_cond;
+# define COND_INIT(c) pthread_cond_init(&c, NULL)
+# define COND_SIGNAL(c) pthread_cond_signal(&c)
+# define COND_WAIT(c,m) pthread_cond_wait(&c, &m)
+# define COND_BROADCAST(c) pthread_cond_broadcast(&c)
+# ifdef HAVE_PTHREAD_CONDATTR_SETPSHARED
+# define COND_INIT_SHARED(c) do {\
+ pthread_condattr_t condattr;\
+ pthread_condattr_init(&condattr);\
+ pthread_condattr_setpshared(&condattr, PTHREAD_PROCESS_SHARED);\
+ pthread_cond_init(&c, &condattr);\
+} while (0)
+# else
+# define COND_INIT_SHARED COND_INIT
+# endif /* HAVE_PTHREAD_CONDATTR_SETPSHARE */
+# define COND_FIN(c) pthread_cond_destroy(&c)
+
+typedef pthread_key_t grn_thread_key;
+# define THREAD_KEY_CREATE(key, destr) pthread_key_create(key, destr)
+# define THREAD_KEY_DELETE(key) pthread_key_delete(key)
+# define THREAD_SETSPECIFIC(key, value) pthread_setspecific(key, value)
+# define THREAD_GETSPECIFIC(key) pthread_getspecific(key)
+
+#if defined(USE_UYIELD)
+ extern int grn_uyield_count;
+ #define GRN_TEST_YIELD() do {\
+ if (((++grn_uyield_count) & (0x20 - 1)) == 0) {\
+ sched_yield();\
+ if (grn_uyield_count > 0x1000) {\
+ grn_uyield_count = (uint32_t)time(NULL) % 0x1000;\
+ }\
+ }\
+ } while (0)
+
+ #undef assert
+ #define assert(assert_expr) do {\
+ if (!(assert_expr)){\
+ fprintf(stderr, "assertion failed: %s\n", #assert_expr);\
+ abort();\
+ }\
+ GRN_TEST_YIELD();\
+ } while (0)
+
+ #define if (if_cond) \
+ if ((((++grn_uyield_count) & (0x100 - 1)) != 0 || (sched_yield() * 0) == 0) && (if_cond))
+ #define while(while_cond) \
+ while ((((++grn_uyield_count) & (0x100 - 1)) != 0 || (sched_yield() * 0) == 0) && (while_cond))
+
+ #if !defined(_POSIX_PRIORITY_SCHEDULING)
+ #define sched_yield() grn_nanosleep(1000000 * 20)
+ #endif
+# else /* USE_UYIELD */
+ #define GRN_TEST_YIELD() do {} while (0)
+# endif /* USE_UYIELD */
+
+#else /* HAVE_PTHREAD_H */
+
+/* todo */
+typedef int grn_thread_key;
+# define THREAD_KEY_CREATE(key,destr)
+# define THREAD_KEY_DELETE(key)
+# define THREAD_SETSPECIFIC(key)
+# define THREAD_GETSPECIFIC(key,value)
+
+# ifdef WIN32
+typedef uintptr_t grn_thread;
+typedef unsigned int grn_thread_func_result;
+# define GRN_THREAD_FUNC_RETURN_VALUE 0
+# define THREAD_CREATE(thread,func,arg) \
+ (((thread)=_beginthreadex(NULL, 0, (func), (arg), 0, NULL)) == (grn_thread)0)
+# define THREAD_JOIN(thread) \
+ (WaitForSingleObject((HANDLE)(thread), INFINITE) == WAIT_FAILED)
+typedef HANDLE grn_mutex;
+# define MUTEX_INIT(m) ((m) = CreateMutex(0, FALSE, NULL))
+# define MUTEX_LOCK(m) WaitForSingleObject((m), INFINITE)
+# define MUTEX_LOCK_CHECK(m) (MUTEX_LOCK(m) == WAIT_OBJECT_0)
+# define MUTEX_UNLOCK(m) ReleaseMutex(m)
+# define MUTEX_FIN(m) CloseHandle(m)
+typedef CRITICAL_SECTION grn_critical_section;
+# define CRITICAL_SECTION_INIT(cs) InitializeCriticalSection(&(cs))
+# define CRITICAL_SECTION_ENTER(cs) EnterCriticalSection(&(cs))
+# define CRITICAL_SECTION_LEAVE(cs) LeaveCriticalSection(&(cs))
+# define CRITICAL_SECTION_FIN(cs) DeleteCriticalSection(&(cs))
+
+typedef struct
+{
+ int waiters_count_;
+ HANDLE waiters_count_lock_;
+ HANDLE sema_;
+ HANDLE waiters_done_;
+ size_t was_broadcast_;
+} grn_cond;
+
+# define COND_INIT(c) do { \
+ (c).waiters_count_ = 0; \
+ (c).sema_ = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); \
+ MUTEX_INIT((c).waiters_count_lock_); \
+ (c).waiters_done_ = CreateEvent(NULL, FALSE, FALSE, NULL); \
+} while (0)
+
+# define COND_SIGNAL(c) do { \
+ MUTEX_LOCK((c).waiters_count_lock_); \
+ { \
+ int have_waiters = (c).waiters_count_ > 0; \
+ MUTEX_UNLOCK((c).waiters_count_lock_); \
+ if (have_waiters) { \
+ ReleaseSemaphore((c).sema_, 1, 0); \
+ } \
+ } \
+} while (0)
+
+# define COND_BROADCAST(c) do { \
+ MUTEX_LOCK((c).waiters_count_lock_); \
+ { \
+ int have_waiters = (c).waiters_count_ > 0; \
+ if ((c).waiters_count_ > 0) { \
+ (c).was_broadcast_ = 1; \
+ have_waiters = 1; \
+ } \
+ if (have_waiters) { \
+ ReleaseSemaphore((c).sema_, (c).waiters_count_, 0); \
+ MUTEX_UNLOCK((c).waiters_count_lock_); \
+ WaitForSingleObject((c).waiters_done_, INFINITE); \
+ (c).was_broadcast_ = 0; \
+ } \
+ else { \
+ MUTEX_UNLOCK((c).waiters_count_lock_); \
+ } \
+ } \
+} while (0)
+
+# define COND_WAIT(c,m) do { \
+ MUTEX_LOCK((c).waiters_count_lock_); \
+ (c).waiters_count_++; \
+ MUTEX_UNLOCK((c).waiters_count_lock_); \
+ SignalObjectAndWait((m), (c).sema_, INFINITE, FALSE); \
+ MUTEX_LOCK((c).waiters_count_lock_); \
+ (c).waiters_count_--; \
+ { \
+ int last_waiter = (c).was_broadcast_ && (c).waiters_count_ == 0; \
+ MUTEX_UNLOCK((c).waiters_count_lock_); \
+ if (last_waiter) { \
+ SignalObjectAndWait((c).waiters_done_, (m), INFINITE, FALSE); \
+ } \
+ else { \
+ WaitForSingleObject((m), FALSE); \
+ } \
+ } \
+} while (0)
+
+# define COND_FIN(c) do { \
+ CloseHandle((c).waiters_done_); \
+ MUTEX_FIN((c).waiters_count_lock_); \
+ CloseHandle((c).sema_); \
+} while (0)
+
+# else /* WIN32 */
+/* todo */
+typedef int grn_cond;
+# define COND_INIT(c) ((c) = 0)
+# define COND_SIGNAL(c)
+# define COND_WAIT(c,m) do { \
+ MUTEX_UNLOCK(m); \
+ grn_nanosleep(1000000); \
+ MUTEX_LOCK(m); \
+} while (0)
+# define COND_FIN(c)
+/* todo : must be enhanced! */
+
+# endif /* WIN32 */
+
+# define MUTEX_INIT_SHARED MUTEX_INIT
+# define COND_INIT_SHARED COND_INIT
+
+# define GRN_TEST_YIELD() do {} while (0)
+
+#endif /* HAVE_PTHREAD_H */
+
+#define MUTEX_LOCK_ENSURE(ctx_, mutex) do { \
+ grn_ctx *ctx__ = (ctx_); \
+ do { \
+ grn_ctx *ctx = ctx__; \
+ if (MUTEX_LOCK_CHECK(mutex)) { \
+ break; \
+ } \
+ if (ctx) { \
+ SERR("MUTEX_LOCK"); \
+ } \
+ grn_nanosleep(1000000); \
+ } while (GRN_TRUE); \
+} while (GRN_FALSE)
+
+/* format string for printf */
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+# define GRN_FMT_INT32D PRId32
+# define GRN_FMT_INT32U PRIu32
+# define GRN_FMT_INT64D PRId64
+# define GRN_FMT_INT64U PRIu64
+#else /* HAVE_INTTYPES_H */
+# ifdef WIN32
+# define GRN_FMT_INT32D "I32d"
+# define GRN_FMT_INT32U "I32u"
+# define GRN_FMT_INT64D "I64d"
+# define GRN_FMT_INT64U "I64u"
+# else /* WIN32 */
+# define GRN_FMT_INT32D "d"
+# define GRN_FMT_INT32U "u"
+# ifdef __x86_64__
+# define GRN_FMT_INT64D "ld"
+# define GRN_FMT_INT64U "lu"
+# else /* __x86_64__ */
+# define GRN_FMT_INT64D "lld"
+# define GRN_FMT_INT64U "llu"
+# endif /* __x86_64__ */
+# endif /* WIN32 */
+#endif /* HAVE_INTTYPES_H */
+
+#ifdef WIN32
+# define GRN_FMT_LLD "I64d"
+# define GRN_FMT_LLU "I64u"
+# define GRN_FMT_SIZE "Iu"
+# define GRN_FMT_SSIZE "Id"
+# ifdef WIN64
+# define GRN_FMT_SOCKET GRN_FMT_INT64U
+# define GRN_FMT_DWORD "lu"
+# else /* WIN64 */
+# define GRN_FMT_SOCKET GRN_FMT_INT32U
+# define GRN_FMT_DWORD "u"
+# endif /* WIN64 */
+# define GRN_FMT_OFF64_T GRN_FMT_LLD
+#else /* WIN32 */
+# define GRN_FMT_LLD "lld"
+# define GRN_FMT_LLU "llu"
+# define GRN_FMT_SIZE "zu"
+# define GRN_FMT_SSIZE "zd"
+# define GRN_FMT_SOCKET "d"
+# define GRN_FMT_OFF64_T "jd"
+#endif /* WIN32 */
+
+#ifdef __GNUC__
+# if (defined(__i386__) || defined(__x86_64__)) /* ATOMIC ADD */
+/*
+ * GRN_ATOMIC_ADD_EX() performs { r = *p; *p += i; } atomically.
+ */
+# define GRN_ATOMIC_ADD_EX(p, i, r) \
+ __asm__ __volatile__ ("lock xaddl %0, %1" : "=r"(r), "+m"(*p) : "0"(i))
+/*
+ * GRN_BIT_SCAN_REV() finds the most significant 1 bit of `v'. Then, `r' is set
+ * to the index of the found bit. Note that `v' must not be 0.
+ */
+# define GRN_BIT_SCAN_REV(v, r) \
+ __asm__ __volatile__ ("bsrl %1, %%eax; movl %%eax, %0" : "=r"(r) : "r"(v) : "%eax")
+/*
+ * GRN_BIT_SCAN_REV0() is similar to GRN_BIT_SCAN_REV() but if `v' is 0, `r' is
+ * set to 0.
+ */
+# define GRN_BIT_SCAN_REV0(v, r) \
+ __asm__ __volatile__ ("bsrl %1, %%eax; cmovzl %1, %%eax; movl %%eax, %0" : "=r"(r) : "r"(v) : "%eax", "cc")
+# elif (defined(__PPC__) || defined(__ppc__)) /* ATOMIC ADD */
+# define GRN_ATOMIC_ADD_EX(p,i,r) \
+ __asm__ __volatile__ ("\n1:\n\tlwarx %0, 0, %1\n\tadd %0, %0, %2\n\tstwcx. %0, 0, %1\n\tbne- 1b\n\tsub %0, %0, %2" : "=&r" (r) : "r" (p), "r" (i) : "cc", "memory")
+/* todo */
+# define GRN_BIT_SCAN_REV(v,r) for (r = 31; r && !((1 << r) & v); r--)
+# define GRN_BIT_SCAN_REV0(v,r) GRN_BIT_SCAN_REV(v,r)
+# elif (defined(__sun) && defined(__SVR4)) /* ATOMIC ADD */
+# include <atomic.h>
+# define GRN_ATOMIC_ADD_EX(p,i,r) \
+ (r = atomic_add_32_nv(p, i) - i)
+/* todo */
+# define GRN_BIT_SCAN_REV(v,r) for (r = 31; r && !((1 << r) & v); r--)
+# define GRN_BIT_SCAN_REV0(v,r) GRN_BIT_SCAN_REV(v,r)
+# elif defined(__ATOMIC_SEQ_CST) /* GCC atomic builtins */
+# define GRN_ATOMIC_ADD_EX(p,i,r) \
+ (r = __atomic_fetch_add(p, i, __ATOMIC_SEQ_CST))
+# define GRN_BIT_SCAN_REV(v,r) for (r = 31; r && !((1 << r) & v); r--)
+# define GRN_BIT_SCAN_REV0(v,r) GRN_BIT_SCAN_REV(v,r)
+# else /* ATOMIC ADD */
+/* todo */
+# define GRN_BIT_SCAN_REV(v,r) for (r = 31; r && !((1 << r) & v); r--)
+# define GRN_BIT_SCAN_REV0(v,r) GRN_BIT_SCAN_REV(v,r)
+# endif /* ATOMIC ADD */
+
+# ifdef __i386__ /* ATOMIC 64BIT SET */
+# define GRN_SET_64BIT(p,v) \
+ __asm__ __volatile__ ("\txchgl %%esi, %%ebx\n1:\n\tmovl (%0), %%eax\n\tmovl 4(%0), %%edx\n\tlock; cmpxchg8b (%0)\n\tjnz 1b\n\txchgl %%ebx, %%esi" : : "D"(p), "S"(*(((uint32_t *)&(v))+0)), "c"(*(((uint32_t *)&(v))+1)) : "ax", "dx", "memory")
+# elif defined(__x86_64__) /* ATOMIC 64BIT SET */
+# define GRN_SET_64BIT(p,v) \
+ (*(p) = (v))
+# elif (defined(__sun) && defined(__SVR4)) /* ATOMIC 64BIT SET */
+/* todo */
+# define GRN_SET_64BIT(p,v) \
+ (void)atomic_swap_64(p, v)
+# elif defined(__ATOMIC_SEQ_CST) /* GCC atomic builtins */
+# define GRN_SET_64BIT(p,v) \
+ __atomic_store_n(p, v, __ATOMIC_SEQ_CST)
+# else
+# warning Need atomic 64bit operation support. The current implementation may break data.
+# define GRN_SET_64BIT(p,v) \
+ (*(p) = (v))
+# endif /* ATOMIC 64BIT SET */
+
+#elif (defined(WIN32) || defined (_WIN64)) /* __GNUC__ */
+
+# define GRN_ATOMIC_ADD_EX(p,i,r) \
+ ((r) = InterlockedExchangeAdd((p), (i)))
+# if defined(_WIN64) /* ATOMIC 64BIT SET */
+# define GRN_SET_64BIT(p,v) \
+ (*(p) = (v))
+# else /* ATOMIC 64BIT SET */
+# define GRN_SET_64BIT(p,v) do {\
+ uint32_t v1, v2; \
+ uint64_t *p2= (p); \
+ v1 = *(((uint32_t *)&(v))+0);\
+ v2 = *(((uint32_t *)&(v))+1);\
+ __asm _set_loop: \
+ __asm mov esi, p2 \
+ __asm mov ebx, v1 \
+ __asm mov ecx, v2 \
+ __asm mov eax, dword ptr [esi] \
+ __asm mov edx, dword ptr [esi + 4] \
+ __asm lock cmpxchg8b qword ptr [esi] \
+ __asm jnz _set_loop \
+} while (0)
+/* TODO: use _InterlockedCompareExchange64 or inline asm */
+# endif /* ATOMIC 64BIT SET */
+
+/* todo */
+# define GRN_BIT_SCAN_REV(v,r) for (r = 31; r && !((1 << r) & v); r--)
+# define GRN_BIT_SCAN_REV0(v,r) GRN_BIT_SCAN_REV(v,r)
+
+#else /* __GNUC__ */
+
+# if (defined(__sun) && defined(__SVR4)) /* ATOMIC ADD */
+# define __FUNCTION__ ""
+# include <atomic.h>
+# define GRN_ATOMIC_ADD_EX(p,i,r) \
+ (r = atomic_add_32_nv(p, i) - i)
+/* todo */
+# define GRN_SET_64BIT(p,v) \
+ (void)atomic_swap_64(p, v)
+# endif /* ATOMIC ADD */
+/* todo */
+# define GRN_BIT_SCAN_REV(v,r) for (r = 31; r && !((1 << r) & v); r--)
+# define GRN_BIT_SCAN_REV0(v,r) GRN_BIT_SCAN_REV(v,r)
+
+#endif /* __GNUC__ */
+
+typedef uint8_t byte;
+
+#define GRN_ID_WIDTH 30
+
+#ifdef __GNUC__
+inline static int
+grn_str_greater(const uint8_t *ap, uint32_t as, const uint8_t *bp, uint32_t bs)
+{
+ for (;; ap++, bp++, as--, bs--) {
+ if (!as) { return 0; }
+ if (!bs) { return 1; }
+ if (*ap < *bp) { return 0; }
+ if (*ap > *bp) { return 1; }
+ }
+}
+#else /* __GNUC__ */
+# define grn_str_greater(ap,as,bp,bs)\
+ (((as) > (bs)) ? (memcmp((ap), (bp), (bs)) >= 0) : (memcmp((ap), (bp), (as)) > 0))
+#endif /* __GNUC__ */
+
+#ifdef WORDS_BIGENDIAN
+# define grn_hton(buf,key,size) do {\
+ uint32_t size_ = (uint32_t)size;\
+ uint8_t *buf_ = (uint8_t *)buf;\
+ uint8_t *key_ = (uint8_t *)key;\
+ while (size_--) { *buf_++ = *key_++; }\
+} while (0)
+# define grn_ntohi(buf,key,size) do {\
+ uint32_t size_ = (uint32_t)size;\
+ uint8_t *buf_ = (uint8_t *)buf;\
+ uint8_t *key_ = (uint8_t *)key;\
+ if (size_) { *buf_++ = 0x80 ^ *key_++; size_--; }\
+ while (size_) { *buf_++ = *key_++; size_--; }\
+} while (0)
+#else /* WORDS_BIGENDIAN */
+# define grn_hton(buf,key,size) do {\
+ uint32_t size_ = (uint32_t)size;\
+ uint8_t *buf_ = (uint8_t *)buf;\
+ uint8_t *key_ = (uint8_t *)key + size;\
+ while (size_--) { *buf_++ = *(--key_); }\
+} while (0)
+# define grn_ntohi(buf,key,size) do {\
+ uint32_t size_ = (uint32_t)size;\
+ uint8_t *buf_ = (uint8_t *)buf;\
+ uint8_t *key_ = (uint8_t *)key + size;\
+ while (size_ > 1) { *buf_++ = *(--key_); size_--; }\
+ if (size_) { *buf_ = 0x80 ^ *(--key_); } \
+} while (0)
+#endif /* WORDS_BIGENDIAN */
+#define grn_ntoh(buf,key,size) grn_hton(buf,key,size)
+
+#ifndef __GNUC_PREREQ
+# if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define __GNUC_PREREQ(maj, min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+# else
+# define __GNUC_PREREQ(maj, min) 0
+# endif /* defined(__GNUC__) && defined(__GNUC_MINOR__) */
+#endif /* __GNUC_PREREQ */
+
+#ifdef _MSC_VER
+# define grn_bswap_uint64(in, out) ((out) = _byteswap_uint64(in))
+#else /* _MSC_VER */
+# if defined(__GNUC__) && __GNUC_PREREQ(4, 3)
+# define grn_bswap_uint64(in, out) ((out) = __builtin_bswap64(in))
+# else /* defined(__GNUC__) && __GNUC_PREREQ(4, 3) */
+# define grn_bswap_uint64(in, out) do {\
+ uint64_t temp_ = (in);\
+ (out) = (temp_ << 56) |\
+ ((temp_ & (0xFFULL << 8)) << 40) |\
+ ((temp_ & (0xFFULL << 16)) << 24) |\
+ ((temp_ & (0xFFULL << 24)) << 8) |\
+ ((temp_ & (0xFFULL << 32)) >> 8) |\
+ ((temp_ & (0xFFULL << 40)) >> 24) |\
+ ((temp_ & (0xFFULL << 48)) >> 40) |\
+ (temp_ >> 56);\
+} while (0)
+# endif /* __GNUC__ */
+#endif /* _MSC_VER */
+
+#ifdef WORDS_BIGENDIAN
+# define grn_hton_uint64(in, out) ((out) = (in))
+#else /* WORDS_BIGENDIAN */
+# define grn_hton_uint64(in, out) grn_bswap_uint64(in, out)
+#endif /* WORDS_BIGENDIAN */
+#define grn_ntoh_uint64(in, out) grn_hton_uint64(in, out)
+
+#define grn_gton(keybuf,key,size) do {\
+ const grn_geo_point *point_ = (const grn_geo_point *)key;\
+ uint64_t la_ = (uint32_t)point_->latitude;\
+ uint64_t lo_ = (uint32_t)point_->longitude;\
+ uint64_t result_;\
+ la_ = (la_ | (la_ << 16)) & 0x0000FFFF0000FFFFULL;\
+ la_ = (la_ | (la_ << 8)) & 0x00FF00FF00FF00FFULL;\
+ la_ = (la_ | (la_ << 4)) & 0x0F0F0F0F0F0F0F0FULL;\
+ la_ = (la_ | (la_ << 2)) & 0x3333333333333333ULL;\
+ la_ = (la_ | (la_ << 1)) & 0x5555555555555555ULL;\
+ lo_ = (lo_ | (lo_ << 16)) & 0x0000FFFF0000FFFFULL;\
+ lo_ = (lo_ | (lo_ << 8)) & 0x00FF00FF00FF00FFULL;\
+ lo_ = (lo_ | (lo_ << 4)) & 0x0F0F0F0F0F0F0F0FULL;\
+ lo_ = (lo_ | (lo_ << 2)) & 0x3333333333333333ULL;\
+ lo_ = (lo_ | (lo_ << 1)) & 0x5555555555555555ULL;\
+ result_ = (la_ << 1) | lo_;\
+ grn_hton_uint64(result_, result_);\
+ grn_memcpy(keybuf, &result_, sizeof(result_));\
+} while (0)
+
+#define grn_ntog(keybuf,key,size) do {\
+ grn_geo_point *point_ = (grn_geo_point *)keybuf;\
+ uint64_t key_ = *(const uint64_t *)key;\
+ uint64_t la_, lo_;\
+ grn_ntoh_uint64(key_, key_);\
+ la_ = (key_ >> 1) & 0x5555555555555555ULL;\
+ lo_ = key_ & 0x5555555555555555ULL;\
+ la_ = (la_ | (la_ >> 1)) & 0x3333333333333333ULL;\
+ la_ = (la_ | (la_ >> 2)) & 0x0F0F0F0F0F0F0F0FULL;\
+ la_ = (la_ | (la_ >> 4)) & 0x00FF00FF00FF00FFULL;\
+ la_ = (la_ | (la_ >> 8)) & 0x0000FFFF0000FFFFULL;\
+ la_ = (la_ | (la_ >> 16)) & 0x00000000FFFFFFFFULL;\
+ lo_ = (lo_ | (lo_ >> 1)) & 0x3333333333333333ULL;\
+ lo_ = (lo_ | (lo_ >> 2)) & 0x0F0F0F0F0F0F0F0FULL;\
+ lo_ = (lo_ | (lo_ >> 4)) & 0x00FF00FF00FF00FFULL;\
+ lo_ = (lo_ | (lo_ >> 8)) & 0x0000FFFF0000FFFFULL;\
+ lo_ = (lo_ | (lo_ >> 16)) & 0x00000000FFFFFFFFULL;\
+ point_->latitude = la_;\
+ point_->longitude = lo_;\
+} while (0)
+
+#ifdef HAVE__STRTOUI64
+# define strtoull(nptr,endptr,base) _strtoui64(nptr,endptr,base)
+#endif /* HAVE__STRTOUI64 */
+
+#ifdef USE_FUTEX
+# include <linux/futex.h>
+# include <sys/syscall.h>
+
+# define GRN_FUTEX_WAIT(p) do {\
+ int err;\
+ struct timespec timeout = {1, 0};\
+ while (1) {\
+ if (!(err = syscall(SYS_futex, p, FUTEX_WAIT, *p, &timeout))) {\
+ break;\
+ }\
+ if (err == ETIMEDOUT) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT, "timeout in GRN_FUTEX_WAIT(%p)", p);\
+ break;\
+ } else if (err != EWOULDBLOCK) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT, "error %d in GRN_FUTEX_WAIT(%p)", err);\
+ break;\
+ }\
+ }\
+} while(0)
+
+# define GRN_FUTEX_WAKE(p) syscall(SYS_futex, p, FUTEX_WAKE, 1)
+#else /* USE_FUTEX */
+# define GRN_FUTEX_WAIT(p) grn_nanosleep(1000000)
+# define GRN_FUTEX_WAKE(p)
+#endif /* USE_FUTEX */
+
+#ifndef HOST_NAME_MAX
+# ifdef _POSIX_HOST_NAME_MAX
+# define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+# else /* POSIX_HOST_NAME_MAX */
+# define HOST_NAME_MAX 128
+# endif /* POSIX_HOST_NAME_MAX */
+#endif /* HOST_NAME_MAX */
+
+#define GRN_NEXT_ADDR(p) (((byte *)(p)) + sizeof(*(p)))
+
+GRN_API void grn_sleep(uint32_t seconds);
+GRN_API void grn_nanosleep(uint64_t nanoseconds);
+
+#include <groonga.h>
diff --git a/storage/mroonga/vendor/groonga/lib/grn_alloc.h b/storage/mroonga/vendor/groonga/lib/grn_alloc.h
new file mode 100644
index 00000000..c9059113
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_alloc.h
@@ -0,0 +1,163 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_alloc_init_from_env(void);
+
+void grn_alloc_init_ctx_impl(grn_ctx *ctx);
+void grn_alloc_fin_ctx_impl(grn_ctx *ctx);
+
+void grn_alloc_info_init(void);
+void grn_alloc_info_fin(void);
+
+void grn_alloc_info_dump(grn_ctx *ctx);
+void grn_alloc_info_free(grn_ctx *ctx);
+
+#define GRN_MALLOC(s) grn_malloc(ctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_CALLOC(s) grn_calloc(ctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_REALLOC(p,s) grn_realloc(ctx,p,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_STRDUP(s) grn_strdup(ctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_GMALLOC(s) grn_malloc(&grn_gctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_GCALLOC(s) grn_calloc(&grn_gctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_GREALLOC(p,s) grn_realloc(&grn_gctx,p,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_GSTRDUP(s) grn_strdup(&grn_gctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_FREE(p) grn_free(ctx,p,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_MALLOCN(t,n) ((t *)(GRN_MALLOC(sizeof(t) * (n))))
+#define GRN_GFREE(p) grn_free(&grn_gctx,p,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_GMALLOCN(t,n) ((t *)(GRN_GMALLOC(sizeof(t) * (n))))
+
+#define GRN_CTX_ALLOC(ctx,s) grn_ctx_calloc(ctx,s,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_CTX_FREE(ctx,p) grn_ctx_free(ctx,p,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_CTX_ALLOC_L(ctx,s) grn_ctx_alloc_lifo(ctx,s,f,__FILE__,__LINE__,__FUNCTION__)
+#define GRN_CTX_FREE_L(ctx,p) grn_ctx_free_lifo(ctx,p,__FILE__,__LINE__,__FUNCTION__)
+
+void *grn_ctx_malloc(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void *grn_ctx_calloc(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void *grn_ctx_realloc(grn_ctx *ctx,
+ void *ptr,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(3);
+char *grn_ctx_strdup(grn_ctx *ctx, const char *s,
+ const char* file, int line, const char *func);
+void grn_ctx_free(grn_ctx *ctx, void *ptr,
+ const char* file, int line, const char *func);
+void *grn_ctx_alloc_lifo(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void grn_ctx_free_lifo(grn_ctx *ctx, void *ptr,
+ const char* file, int line, const char *func);
+
+#ifdef USE_DYNAMIC_MALLOC_CHANGE
+typedef void *(*grn_malloc_func) (grn_ctx *ctx, size_t size,
+ const char *file, int line, const char *func);
+typedef void *(*grn_calloc_func) (grn_ctx *ctx, size_t size,
+ const char *file, int line, const char *func);
+typedef void *(*grn_realloc_func) (grn_ctx *ctx, void *ptr, size_t size,
+ const char *file, int line, const char *func);
+typedef char *(*grn_strdup_func) (grn_ctx *ctx, const char *string,
+ const char *file, int line, const char *func);
+typedef void (*grn_free_func) (grn_ctx *ctx, void *ptr,
+ const char *file, int line, const char *func);
+grn_malloc_func grn_ctx_get_malloc(grn_ctx *ctx);
+void grn_ctx_set_malloc(grn_ctx *ctx, grn_malloc_func malloc_func);
+grn_calloc_func grn_ctx_get_calloc(grn_ctx *ctx);
+void grn_ctx_set_calloc(grn_ctx *ctx, grn_calloc_func calloc_func);
+grn_realloc_func grn_ctx_get_realloc(grn_ctx *ctx);
+void grn_ctx_set_realloc(grn_ctx *ctx, grn_realloc_func realloc_func);
+grn_strdup_func grn_ctx_get_strdup(grn_ctx *ctx);
+void grn_ctx_set_strdup(grn_ctx *ctx, grn_strdup_func strdup_func);
+grn_free_func grn_ctx_get_free(grn_ctx *ctx);
+void grn_ctx_set_free(grn_ctx *ctx, grn_free_func free_func);
+
+void *grn_malloc(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void *grn_calloc(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void *grn_realloc(grn_ctx *ctx,
+ void *ptr,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(3);
+char *grn_strdup(grn_ctx *ctx, const char *s, const char* file, int line, const char *func);
+void grn_free(grn_ctx *ctx, void *ptr, const char *file, int line, const char *func);
+#else
+# define grn_malloc grn_malloc_default
+# define grn_calloc grn_calloc_default
+# define grn_realloc grn_realloc_default
+# define grn_strdup grn_strdup_default
+# define grn_free grn_free_default
+#endif
+
+GRN_API void *grn_malloc_default(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void *grn_calloc_default(grn_ctx *ctx,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(2);
+void *grn_realloc_default(grn_ctx *ctx,
+ void *ptr,
+ size_t size,
+ const char *file,
+ int line,
+ const char *func) GRN_ATTRIBUTE_ALLOC_SIZE(3);
+GRN_API char *grn_strdup_default(grn_ctx *ctx, const char *s, const char* file, int line, const char *func);
+GRN_API void grn_free_default(grn_ctx *ctx, void *ptr, const char* file, int line, const char *func);
+
+#ifdef USE_FAIL_MALLOC
+int grn_fail_malloc_check(size_t size, const char *file, int line, const char *func);
+void *grn_malloc_fail(grn_ctx *ctx, size_t size, const char* file, int line, const char *func);
+void *grn_calloc_fail(grn_ctx *ctx, size_t size, const char* file, int line, const char *func);
+void *grn_realloc_fail(grn_ctx *ctx, void *ptr, size_t size, const char* file, int line, const char *func);
+char *grn_strdup_fail(grn_ctx *ctx, const char *s, const char* file, int line, const char *func);
+#endif
+
+int grn_alloc_count(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_cache.h b/storage/mroonga/vendor/groonga/lib/grn_cache.h
new file mode 100644
index 00000000..a0cb9c37
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_cache.h
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_CACHE_MAX_KEY_SIZE GRN_HASH_MAX_KEY_SIZE_LARGE
+
+typedef struct {
+ uint32_t nentries;
+ uint32_t max_nentries;
+ uint32_t nfetches;
+ uint32_t nhits;
+} grn_cache_statistics;
+
+void grn_cache_init(void);
+grn_rc grn_cache_fetch(grn_ctx *ctx, grn_cache *cache,
+ const char *str, uint32_t str_size,
+ grn_obj *output);
+void grn_cache_update(grn_ctx *ctx, grn_cache *cache,
+ const char *str, uint32_t str_size, grn_obj *value);
+void grn_cache_expire(grn_cache *cache, int32_t size);
+void grn_cache_fin(void);
+void grn_cache_get_statistics(grn_ctx *ctx, grn_cache *cache,
+ grn_cache_statistics *statistics);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_com.h b/storage/mroonga/vendor/groonga/lib/grn_com.h
new file mode 100644
index 00000000..505e87a5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_com.h
@@ -0,0 +1,250 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_str.h"
+#include "grn_hash.h"
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif /* HAVE_NETDB_H */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******* grn_com_queue ********/
+
+typedef struct _grn_com_queue grn_com_queue;
+typedef struct _grn_com_queue_entry grn_com_queue_entry;
+
+#define GRN_COM_QUEUE_BINSIZE (0x100)
+
+struct _grn_com_queue_entry {
+ grn_obj obj;
+ struct _grn_com_queue_entry *next;
+};
+
+struct _grn_com_queue {
+ grn_com_queue_entry *bins[GRN_COM_QUEUE_BINSIZE];
+ grn_com_queue_entry *next;
+ grn_com_queue_entry **tail;
+ uint8_t first;
+ uint8_t last;
+ grn_critical_section cs;
+};
+
+#define GRN_COM_QUEUE_INIT(q) do {\
+ (q)->next = NULL;\
+ (q)->tail = &(q)->next;\
+ (q)->first = 0;\
+ (q)->last = 0;\
+ CRITICAL_SECTION_INIT((q)->cs);\
+} while (0)
+
+#define GRN_COM_QUEUE_EMPTYP(q) (((q)->first == (q)->last) && !(q)->next)
+
+GRN_API grn_rc grn_com_queue_enque(grn_ctx *ctx, grn_com_queue *q, grn_com_queue_entry *e);
+GRN_API grn_com_queue_entry *grn_com_queue_deque(grn_ctx *ctx, grn_com_queue *q);
+
+/******* grn_com ********/
+
+#ifdef USE_SELECT
+# ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+# endif /* HAVE_SYS_SELECT_H */
+# define GRN_COM_POLLIN 1
+# define GRN_COM_POLLOUT 2
+#else /* USE_SELECT */
+# ifdef USE_EPOLL
+# include <sys/epoll.h>
+# define GRN_COM_POLLIN EPOLLIN
+# define GRN_COM_POLLOUT EPOLLOUT
+# else /* USE_EPOLL */
+# ifdef USE_KQUEUE
+# include <sys/event.h>
+# define GRN_COM_POLLIN EVFILT_READ
+# define GRN_COM_POLLOUT EVFILT_WRITE
+# else /* USE_KQUEUE */
+# include <poll.h>
+# define GRN_COM_POLLIN POLLIN
+# define GRN_COM_POLLOUT POLLOUT
+# endif /* USE_KQUEUE */
+# endif /* USE_EPOLL */
+#endif /* USE_SELECT */
+
+typedef struct _grn_com grn_com;
+typedef struct _grn_com_event grn_com_event;
+typedef struct _grn_com_addr grn_com_addr;
+typedef void grn_com_callback(grn_ctx *ctx, grn_com_event *, grn_com *);
+typedef void grn_msg_handler(grn_ctx *ctx, grn_obj *msg);
+
+enum {
+ grn_com_ok = 0,
+ grn_com_emem,
+ grn_com_erecv_head,
+ grn_com_erecv_body,
+ grn_com_eproto,
+};
+
+struct _grn_com_addr {
+ uint32_t addr;
+ uint16_t port;
+ uint16_t sid;
+};
+
+struct _grn_com {
+ grn_sock fd;
+ int events;
+ uint16_t sid;
+ uint8_t has_sid;
+ uint8_t closed;
+ grn_com_queue new_;
+ grn_com_event *ev;
+ void *opaque;
+ grn_bool accepting;
+};
+
+struct _grn_com_event {
+ struct _grn_hash *hash;
+ int max_nevents;
+ grn_ctx *ctx;
+ grn_mutex mutex;
+ grn_cond cond;
+ grn_com_queue recv_old;
+ grn_msg_handler *msg_handler;
+ grn_com_addr curr_edge_id;
+ grn_com *acceptor;
+ void *opaque;
+#ifndef USE_SELECT
+#ifdef USE_EPOLL
+ int epfd;
+ struct epoll_event *events;
+#else /* USE_EPOLL */
+#ifdef USE_KQUEUE
+ int kqfd;
+ struct kevent *events;
+#else /* USE_KQUEUE */
+ int dummy; /* dummy */
+ struct pollfd *events;
+#endif /* USE_KQUEUE */
+#endif /* USE_EPOLL */
+#endif /* USE_SELECT */
+};
+
+grn_rc grn_com_init(void);
+void grn_com_fin(void);
+GRN_API grn_rc grn_com_event_init(grn_ctx *ctx, grn_com_event *ev, int max_nevents, int data_size);
+GRN_API grn_rc grn_com_event_fin(grn_ctx *ctx, grn_com_event *ev);
+GRN_API grn_rc grn_com_event_start_accept(grn_ctx *ctx, grn_com_event *ev);
+grn_rc grn_com_event_stop_accept(grn_ctx *ctx, grn_com_event *ev);
+grn_rc grn_com_event_add(grn_ctx *ctx, grn_com_event *ev, grn_sock fd, int events, grn_com **com);
+grn_rc grn_com_event_mod(grn_ctx *ctx, grn_com_event *ev, grn_sock fd, int events, grn_com **com);
+GRN_API grn_rc grn_com_event_del(grn_ctx *ctx, grn_com_event *ev, grn_sock fd);
+GRN_API grn_rc grn_com_event_poll(grn_ctx *ctx, grn_com_event *ev, int timeout);
+grn_rc grn_com_event_each(grn_ctx *ctx, grn_com_event *ev, grn_com_callback *func);
+
+/******* grn_com_gqtp ********/
+
+#define GRN_COM_PROTO_HTTP 0x47
+#define GRN_COM_PROTO_GQTP 0xc7
+#define GRN_COM_PROTO_MBREQ 0x80
+#define GRN_COM_PROTO_MBRES 0x81
+
+typedef struct _grn_com_header grn_com_header;
+
+struct _grn_com_header {
+ uint8_t proto;
+ uint8_t qtype;
+ uint16_t keylen;
+ uint8_t level;
+ uint8_t flags;
+ uint16_t status;
+ uint32_t size;
+ uint32_t opaque;
+ uint64_t cas;
+};
+
+GRN_API grn_com *grn_com_copen(grn_ctx *ctx, grn_com_event *ev, const char *dest, int port);
+GRN_API grn_rc grn_com_sopen(grn_ctx *ctx, grn_com_event *ev,
+ const char *bind_address, int port,
+ grn_msg_handler *func, struct hostent *he);
+
+GRN_API void grn_com_close_(grn_ctx *ctx, grn_com *com);
+GRN_API grn_rc grn_com_close(grn_ctx *ctx, grn_com *com);
+
+GRN_API grn_rc grn_com_send(grn_ctx *ctx, grn_com *cs,
+ grn_com_header *header, const char *body, uint32_t size, int flags);
+grn_rc grn_com_recv(grn_ctx *ctx, grn_com *cs, grn_com_header *header, grn_obj *buf);
+GRN_API grn_rc grn_com_send_http(grn_ctx *ctx, grn_com *cs, const char *path, uint32_t path_len, int flags);
+
+/******* grn_msg ********/
+
+typedef struct _grn_msg grn_msg;
+
+struct _grn_msg {
+ grn_com_queue_entry qe;
+ union {
+ grn_com *peer;
+ grn_sock fd;
+ } u;
+ grn_ctx *ctx;
+ grn_com_queue *old;
+ grn_com_header header;
+ grn_com_addr edge_id;
+ grn_com *acceptor;
+};
+
+GRN_API grn_rc grn_msg_send(grn_ctx *ctx, grn_obj *msg, int flags);
+GRN_API grn_obj *grn_msg_open_for_reply(grn_ctx *ctx, grn_obj *query, grn_com_queue *old);
+GRN_API grn_obj *grn_msg_open(grn_ctx *ctx, grn_com *com, grn_com_queue *old);
+GRN_API grn_rc grn_msg_set_property(grn_ctx *ctx, grn_obj *obj,
+ uint16_t status, uint32_t key_size, uint8_t extra_size);
+GRN_API grn_rc grn_msg_close(grn_ctx *ctx, grn_obj *msg);
+
+/******* grn_edge ********/
+
+#define GRN_EDGE_WORKER 0
+#define GRN_EDGE_COMMUNICATOR 1
+
+typedef struct {
+ grn_com_queue_entry eq;
+ grn_ctx ctx;
+ grn_com_queue recv_new;
+ grn_com_queue send_old;
+ grn_com *com;
+ grn_com_addr *addr;
+ grn_msg *msg;
+ uint8_t stat;
+ uint8_t flags;
+ grn_id id;
+} grn_edge;
+
+GRN_VAR grn_hash *grn_edges;
+GRN_API void grn_edges_init(grn_ctx *ctx, void (*dispatcher)(grn_ctx *ctx, grn_edge *edge));
+GRN_API void grn_edges_fin(grn_ctx *ctx);
+GRN_API grn_edge *grn_edges_add(grn_ctx *ctx, grn_com_addr *addr, int *added);
+grn_edge *grn_edges_add_communicator(grn_ctx *ctx, grn_com_addr *addr);
+GRN_API void grn_edges_delete(grn_ctx *ctx, grn_edge *edge);
+void grn_edge_dispatch(grn_ctx *ctx, grn_edge *edge, grn_obj *msg);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_config.h b/storage/mroonga/vendor/groonga/lib/grn_config.h
new file mode 100644
index 00000000..75e23a46
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_config.h
@@ -0,0 +1,37 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_db.h"
+#include "grn_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ grn_db_obj obj;
+ grn_hash_cursor *hash_cursor;
+} grn_config_cursor;
+
+grn_rc grn_config_cursor_close(grn_ctx *ctx, grn_config_cursor *cursor);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ctx.h b/storage/mroonga/vendor/groonga/lib/grn_ctx.h
new file mode 100644
index 00000000..9e82785f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ctx.h
@@ -0,0 +1,501 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_error.h"
+
+#include <errno.h>
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#define GRN_BREAK_POINT raise(SIGTRAP)
+#endif /* HAVE_SIGNAL_H */
+
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif /* HAVE_EXECINFO_H */
+
+#include "grn_io.h"
+#include "grn_alloc.h"
+#include "grn_time.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**** api in/out ****/
+
+#define GRN_API_ENTER do {\
+ if ((ctx)->seqno & 1) {\
+ (ctx)->subno++;\
+ } else {\
+ (ctx)->errlvl = GRN_OK;\
+ if ((ctx)->rc != GRN_CANCEL) {\
+ (ctx)->rc = GRN_SUCCESS;\
+ }\
+ (ctx)->seqno++;\
+ }\
+ GRN_TEST_YIELD();\
+} while (0)
+
+/* CAUTION!! : pass only variables or constants as r */
+#define GRN_API_RETURN(r) do {\
+ if (ctx->subno) {\
+ ctx->subno--;\
+ } else {\
+ ctx->seqno++;\
+ }\
+ GRN_TEST_YIELD();\
+ return r;\
+} while (0)
+
+/**** error handling ****/
+
+#define GRN_EMERG GRN_LOG_EMERG
+#define GRN_ALERT GRN_LOG_ALERT
+#define GRN_CRIT GRN_LOG_CRIT
+#define GRN_ERROR GRN_LOG_ERROR
+#define GRN_WARN GRN_LOG_WARNING
+#define GRN_OK GRN_LOG_NOTICE
+
+#define ERRCLR(ctx) do {\
+ if (ctx) {\
+ ((grn_ctx *)ctx)->errlvl = GRN_OK;\
+ if (((grn_ctx *)ctx)->rc != GRN_CANCEL) {\
+ ((grn_ctx *)ctx)->rc = GRN_SUCCESS;\
+ ((grn_ctx *)ctx)->errbuf[0] = '\0';\
+ }\
+ }\
+ errno = 0;\
+ grn_gctx.errlvl = GRN_OK;\
+ grn_gctx.rc = GRN_SUCCESS;\
+} while (0)
+
+#ifdef HAVE_BACKTRACE
+#define BACKTRACE(ctx) ((ctx)->ntrace = (unsigned char)backtrace((ctx)->trace, 16))
+#else /* HAVE_BACKTRACE */
+#define BACKTRACE(ctx)
+#endif /* HAVE_BACKTRACE */
+
+GRN_API grn_bool grn_ctx_impl_should_log(grn_ctx *ctx);
+GRN_API void grn_ctx_impl_set_current_error_message(grn_ctx *ctx);
+
+#ifdef HAVE_BACKTRACE
+#define LOGTRACE(ctx,lvl) do {\
+ int i;\
+ char **p;\
+ BACKTRACE(ctx);\
+ p = backtrace_symbols((ctx)->trace, (ctx)->ntrace);\
+ if (!p) {\
+ GRN_LOG((ctx), lvl, "backtrace_symbols failed");\
+ } else {\
+ for (i = 0; i < (ctx)->ntrace; i++) {\
+ GRN_LOG((ctx), lvl, "%s", p[i]);\
+ }\
+ free(p);\
+ }\
+} while (0)
+#else /* HAVE_BACKTRACE */
+#define LOGTRACE(ctx,msg)
+#endif /* HAVE_BACKTRACE */
+
+#define ERRSET(ctx,lvl,r,...) do {\
+ grn_ctx *ctx_ = (grn_ctx *)ctx;\
+ ctx_->errlvl = (lvl);\
+ if (ctx_->rc != GRN_CANCEL) {\
+ ctx_->rc = (r);\
+ }\
+ ctx_->errfile = __FILE__;\
+ ctx_->errline = __LINE__;\
+ ctx_->errfunc = __FUNCTION__;\
+ grn_ctx_log(ctx, __VA_ARGS__);\
+ if (grn_ctx_impl_should_log(ctx)) {\
+ grn_ctx_impl_set_current_error_message(ctx);\
+ GRN_LOG(ctx, lvl, __VA_ARGS__);\
+ if (lvl <= GRN_LOG_ERROR) { LOGTRACE(ctx, lvl); }\
+ }\
+} while (0)
+
+#define ERRP(ctx,lvl) \
+ (((ctx) && ((grn_ctx *)(ctx))->errlvl <= (lvl)) || (grn_gctx.errlvl <= (lvl)))
+
+#ifdef ERR
+# undef ERR
+#endif /* ERR */
+#define CRIT(rc,...) ERRSET(ctx, GRN_CRIT, (rc), __VA_ARGS__)
+#define ERR(rc,...) ERRSET(ctx, GRN_ERROR, (rc), __VA_ARGS__)
+#define WARN(rc,...) ERRSET(ctx, GRN_WARN, (rc), __VA_ARGS__)
+#define MERR(...) ERRSET(ctx, GRN_ALERT, GRN_NO_MEMORY_AVAILABLE, __VA_ARGS__)
+#define ALERT(...) ERRSET(ctx, GRN_ALERT, GRN_SUCCESS, __VA_ARGS__)
+
+#define ERR_CAST(column, range, element) do {\
+ grn_obj inspected;\
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];\
+ int column_name_size;\
+ char range_name[GRN_TABLE_MAX_KEY_SIZE];\
+ int range_name_size;\
+ GRN_TEXT_INIT(&inspected, 0);\
+ grn_inspect(ctx, &inspected, element);\
+ column_name_size = grn_obj_name(ctx, column, column_name,\
+ GRN_TABLE_MAX_KEY_SIZE);\
+ range_name_size = grn_obj_name(ctx, range, range_name,\
+ GRN_TABLE_MAX_KEY_SIZE);\
+ ERR(GRN_INVALID_ARGUMENT, "<%.*s>: failed to cast to <%.*s>: <%.*s>",\
+ column_name_size, column_name,\
+ range_name_size, range_name,\
+ (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));\
+ GRN_OBJ_FIN(ctx, &inspected);\
+} while (0)
+
+#define USER_MESSAGE_SIZE 1024
+
+#ifdef WIN32
+
+#define SERR(...) do {\
+ grn_rc rc;\
+ int error_code;\
+ const char *system_message;\
+ char user_message[USER_MESSAGE_SIZE];\
+ error_code = GetLastError();\
+ system_message = grn_current_error_message();\
+ rc = grn_windows_error_code_to_rc(error_code);\
+ grn_snprintf(user_message,\
+ USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
+ __VA_ARGS__);\
+ ERR(rc, "system error[%d]: %s: %s",\
+ error_code, system_message, user_message);\
+} while (0)
+
+#define SOERR(...) do {\
+ grn_rc rc;\
+ const char *m;\
+ char user_message[USER_MESSAGE_SIZE];\
+ int e = WSAGetLastError();\
+ switch (e) {\
+ case WSANOTINITIALISED :\
+ rc = GRN_SOCKET_NOT_INITIALIZED;\
+ m = "please call grn_com_init first";\
+ break;\
+ case WSAEFAULT :\
+ rc = GRN_BAD_ADDRESS;\
+ m = "bad address";\
+ break;\
+ case WSAEINVAL :\
+ rc = GRN_INVALID_ARGUMENT;\
+ m = "invalid argument";\
+ break;\
+ case WSAEMFILE :\
+ rc = GRN_TOO_MANY_OPEN_FILES;\
+ m = "too many sockets";\
+ break;\
+ case WSAEWOULDBLOCK :\
+ rc = GRN_OPERATION_WOULD_BLOCK;\
+ m = "operation would block";\
+ break;\
+ case WSAENOTSOCK :\
+ rc = GRN_NOT_SOCKET;\
+ m = "given fd is not socket fd";\
+ break;\
+ case WSAEOPNOTSUPP :\
+ rc = GRN_OPERATION_NOT_SUPPORTED;\
+ m = "operation is not supported";\
+ break;\
+ case WSAEADDRINUSE :\
+ rc = GRN_ADDRESS_IS_IN_USE;\
+ m = "address is already in use";\
+ break;\
+ case WSAEADDRNOTAVAIL :\
+ rc = GRN_ADDRESS_IS_NOT_AVAILABLE;\
+ m = "address is not available";\
+ break;\
+ case WSAENETDOWN :\
+ rc = GRN_NETWORK_IS_DOWN;\
+ m = "network is down";\
+ break;\
+ case WSAENOBUFS :\
+ rc = GRN_NO_BUFFER;\
+ m = "no buffer";\
+ break;\
+ case WSAEISCONN :\
+ rc = GRN_SOCKET_IS_ALREADY_CONNECTED;\
+ m = "socket is already connected";\
+ break;\
+ case WSAENOTCONN :\
+ rc = GRN_SOCKET_IS_NOT_CONNECTED;\
+ m = "socket is not connected";\
+ break;\
+ case WSAESHUTDOWN :\
+ rc = GRN_SOCKET_IS_ALREADY_SHUTDOWNED;\
+ m = "socket is already shutdowned";\
+ break;\
+ case WSAETIMEDOUT :\
+ rc = GRN_OPERATION_TIMEOUT;\
+ m = "connection time out";\
+ break;\
+ case WSAECONNREFUSED :\
+ rc = GRN_CONNECTION_REFUSED;\
+ m = "connection refused";\
+ break;\
+ case WSAEINTR :\
+ rc = GRN_INTERRUPTED_FUNCTION_CALL;\
+ m = "interrupted function call";\
+ break;\
+ default:\
+ rc = GRN_UNKNOWN_ERROR;\
+ m = "unknown error";\
+ break;\
+ }\
+ grn_snprintf(user_message,\
+ USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
+ __VA_ARGS__);\
+ ERR(rc, "socket error[%d]: %s: %s",\
+ e, m, user_message);\
+} while (0)
+
+#define ERRNO_ERR(...) do {\
+ grn_rc rc;\
+ int errno_keep = errno;\
+ grn_bool show_errno = GRN_FALSE;\
+ const char *system_message;\
+ char user_message[USER_MESSAGE_SIZE];\
+ system_message = grn_strerror(errno);\
+ switch (errno_keep) {\
+ case EPERM : rc = GRN_OPERATION_NOT_PERMITTED; break;\
+ case ENOENT : rc = GRN_NO_SUCH_FILE_OR_DIRECTORY; break;\
+ case ESRCH : rc = GRN_NO_SUCH_PROCESS; break;\
+ case EINTR : rc = GRN_INTERRUPTED_FUNCTION_CALL; break;\
+ case EIO : rc = GRN_INPUT_OUTPUT_ERROR; break;\
+ case E2BIG : rc = GRN_ARG_LIST_TOO_LONG; break;\
+ case ENOEXEC : rc = GRN_EXEC_FORMAT_ERROR; break;\
+ case EBADF : rc = GRN_BAD_FILE_DESCRIPTOR; break;\
+ case ECHILD : rc = GRN_NO_CHILD_PROCESSES; break;\
+ case EAGAIN: rc = GRN_OPERATION_WOULD_BLOCK; break;\
+ case ENOMEM : rc = GRN_NO_MEMORY_AVAILABLE; break;\
+ case EACCES : rc = GRN_PERMISSION_DENIED; break;\
+ case EFAULT : rc = GRN_BAD_ADDRESS; break;\
+ case EEXIST : rc = GRN_FILE_EXISTS; break;\
+ /* case EXDEV : */\
+ case ENODEV : rc = GRN_NO_SUCH_DEVICE; break;\
+ case ENOTDIR : rc = GRN_NOT_A_DIRECTORY; break;\
+ case EISDIR : rc = GRN_IS_A_DIRECTORY; break;\
+ case EINVAL : rc = GRN_INVALID_ARGUMENT; break;\
+ case EMFILE : rc = GRN_TOO_MANY_OPEN_FILES; break;\
+ case ENOTTY : rc = GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION; break;\
+ case EFBIG : rc = GRN_FILE_TOO_LARGE; break;\
+ case ENOSPC : rc = GRN_NO_SPACE_LEFT_ON_DEVICE; break;\
+ case ESPIPE : rc = GRN_INVALID_SEEK; break;\
+ case EROFS : rc = GRN_READ_ONLY_FILE_SYSTEM; break;\
+ case EMLINK : rc = GRN_TOO_MANY_LINKS; break;\
+ case EPIPE : rc = GRN_BROKEN_PIPE; break;\
+ case EDOM : rc = GRN_DOMAIN_ERROR; break;\
+ case ERANGE : rc = GRN_RANGE_ERROR; break;\
+ case EDEADLOCK : rc = GRN_RESOURCE_DEADLOCK_AVOIDED; break;\
+ case ENAMETOOLONG : rc = GRN_FILENAME_TOO_LONG; break;\
+ case EILSEQ : rc = GRN_ILLEGAL_BYTE_SEQUENCE; break;\
+ /* case STRUNCATE : */\
+ default :\
+ rc = GRN_UNKNOWN_ERROR;\
+ show_errno = GRN_TRUE;\
+ break;\
+ }\
+ grn_snprintf(user_message,\
+ USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
+ __VA_ARGS__);\
+ if (show_errno) {\
+ ERR(rc, "system call error[%d]: %s: %s",\
+ errno_keep, system_message, user_message);\
+ } else {\
+ ERR(rc, "system call error: %s: %s",\
+ system_message, user_message);\
+ }\
+} while (0)
+
+#else /* WIN32 */
+
+#define SERR(...) do {\
+ grn_rc rc;\
+ int errno_keep = errno;\
+ grn_bool show_errno = GRN_FALSE;\
+ const char *system_message = grn_current_error_message();\
+ char user_message[USER_MESSAGE_SIZE];\
+ switch (errno_keep) {\
+ case ELOOP : rc = GRN_TOO_MANY_SYMBOLIC_LINKS; break;\
+ case ENAMETOOLONG : rc = GRN_FILENAME_TOO_LONG; break;\
+ case ENOENT : rc = GRN_NO_SUCH_FILE_OR_DIRECTORY; break;\
+ case ENOMEM : rc = GRN_NO_MEMORY_AVAILABLE; break;\
+ case ENOTDIR : rc = GRN_NOT_A_DIRECTORY; break;\
+ case EPERM : rc = GRN_OPERATION_NOT_PERMITTED; break;\
+ case ESRCH : rc = GRN_NO_SUCH_PROCESS; break;\
+ case EINTR : rc = GRN_INTERRUPTED_FUNCTION_CALL; break;\
+ case EIO : rc = GRN_INPUT_OUTPUT_ERROR; break;\
+ case ENXIO : rc = GRN_NO_SUCH_DEVICE_OR_ADDRESS; break;\
+ case E2BIG : rc = GRN_ARG_LIST_TOO_LONG; break;\
+ case ENOEXEC : rc = GRN_EXEC_FORMAT_ERROR; break;\
+ case EBADF : rc = GRN_BAD_FILE_DESCRIPTOR; break;\
+ case ECHILD : rc = GRN_NO_CHILD_PROCESSES; break;\
+ case EACCES : rc = GRN_PERMISSION_DENIED; break;\
+ case EFAULT : rc = GRN_BAD_ADDRESS; break;\
+ case EBUSY : rc = GRN_RESOURCE_BUSY; break;\
+ case EEXIST : rc = GRN_FILE_EXISTS; break;\
+ case ENODEV : rc = GRN_NO_SUCH_DEVICE; break;\
+ case EISDIR : rc = GRN_IS_A_DIRECTORY; break;\
+ case EINVAL : rc = GRN_INVALID_ARGUMENT; break;\
+ case EMFILE : rc = GRN_TOO_MANY_OPEN_FILES; break;\
+ case EFBIG : rc = GRN_FILE_TOO_LARGE; break;\
+ case ENOSPC : rc = GRN_NO_SPACE_LEFT_ON_DEVICE; break;\
+ case EROFS : rc = GRN_READ_ONLY_FILE_SYSTEM; break;\
+ case EMLINK : rc = GRN_TOO_MANY_LINKS; break;\
+ case EPIPE : rc = GRN_BROKEN_PIPE; break;\
+ case EDOM : rc = GRN_DOMAIN_ERROR; break;\
+ case ERANGE : rc = GRN_RANGE_ERROR; break;\
+ case ENOTSOCK : rc = GRN_NOT_SOCKET; break;\
+ case EADDRINUSE : rc = GRN_ADDRESS_IS_IN_USE; break;\
+ case ENETDOWN : rc = GRN_NETWORK_IS_DOWN; break;\
+ case ENOBUFS : rc = GRN_NO_BUFFER; break;\
+ case EISCONN : rc = GRN_SOCKET_IS_ALREADY_CONNECTED; break;\
+ case ENOTCONN : rc = GRN_SOCKET_IS_NOT_CONNECTED; break;\
+ /*\
+ case ESOCKTNOSUPPORT :\
+ case EOPNOTSUPP :\
+ case EPFNOSUPPORT :\
+ */\
+ case EPROTONOSUPPORT : rc = GRN_OPERATION_NOT_SUPPORTED; break;\
+ case ESHUTDOWN : rc = GRN_SOCKET_IS_ALREADY_SHUTDOWNED; break;\
+ case ETIMEDOUT : rc = GRN_OPERATION_TIMEOUT; break;\
+ case ECONNREFUSED: rc = GRN_CONNECTION_REFUSED; break;\
+ case EAGAIN: rc = GRN_OPERATION_WOULD_BLOCK; break;\
+ default :\
+ rc = GRN_UNKNOWN_ERROR;\
+ show_errno = GRN_TRUE;\
+ break;\
+ }\
+ grn_snprintf(user_message,\
+ USER_MESSAGE_SIZE, USER_MESSAGE_SIZE,\
+ __VA_ARGS__);\
+ if (show_errno) {\
+ ERR(rc, "system call error[%d]: %s: %s",\
+ errno_keep, system_message, user_message);\
+ } else {\
+ ERR(rc, "system call error: %s: %s",\
+ system_message, user_message);\
+ }\
+} while (0)
+
+#define SOERR(...) SERR(__VA_ARGS__)
+
+#define ERRNO_ERR(...) SERR(__VA_ARGS__)
+
+#endif /* WIN32 */
+
+#define GERR(rc,...) ERRSET(&grn_gctx, GRN_ERROR, (rc), __VA_ARGS__)
+#define GMERR(...) ERRSET(&grn_gctx, GRN_ALERT, GRN_NO_MEMORY_AVAILABLE, __VA_ARGS__)
+
+#ifdef DEBUG
+#define GRN_ASSERT(s) grn_assert(ctx,(s),__FILE__,__LINE__,__FUNCTION__)
+#else
+#define GRN_ASSERT(s)
+#endif
+
+void grn_assert(grn_ctx *ctx, int cond, const char* file, int line, const char* func);
+
+/**** grn_ctx ****/
+
+GRN_VAR grn_ctx grn_gctx;
+extern int grn_pagesize;
+extern grn_critical_section grn_glock;
+extern uint32_t grn_gtick;
+extern int grn_lock_timeout;
+
+#define GRN_CTX_ALLOCATED (0x80)
+#define GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND (0x40)
+
+extern grn_timeval grn_starttime;
+
+GRN_API void grn_ctx_log(grn_ctx *ctx, const char *fmt, ...) GRN_ATTRIBUTE_PRINTF(2);
+GRN_API void grn_ctx_logv(grn_ctx *ctx, const char *fmt, va_list ap);
+void grn_ctx_loader_clear(grn_ctx *ctx);
+void grn_log_reopen(grn_ctx *ctx);
+
+GRN_API grn_rc grn_ctx_sendv(grn_ctx *ctx, int argc, char **argv, int flags);
+void grn_ctx_set_keep_command(grn_ctx *ctx, grn_obj *command);
+
+grn_content_type grn_get_ctype(grn_obj *var);
+grn_content_type grn_content_type_parse(grn_ctx *ctx,
+ grn_obj *var,
+ grn_content_type default_value);
+
+/**** db_obj ****/
+
+/* flag values used for grn_obj.header.impl_flags */
+
+#define GRN_OBJ_ALLOCATED (0x01<<2) /* allocated by ctx */
+#define GRN_OBJ_EXPRVALUE (0x01<<3) /* value allocated by grn_expr */
+#define GRN_OBJ_EXPRCONST (0x01<<4) /* constant allocated by grn_expr */
+
+typedef struct _grn_hook grn_hook;
+
+typedef struct {
+ grn_obj_header header;
+ grn_id range; /* table: type of subrecords, column: type of values */
+ /* -- compatible with grn_accessor -- */
+ grn_id id;
+ grn_obj *db;
+ grn_user_data user_data;
+ grn_proc_func *finalizer;
+ grn_hook *hooks[5];
+ void *source;
+ uint32_t source_size;
+ uint32_t max_n_subrecs;
+ uint8_t subrec_size;
+ uint8_t subrec_offset;
+ uint8_t record_unit;
+ uint8_t subrec_unit;
+ union {
+ grn_table_group_flags group;
+ } flags;
+ // grn_obj_flags flags;
+} grn_db_obj;
+
+#define GRN_DB_OBJ_SET_TYPE(db_obj,obj_type) do {\
+ (db_obj)->obj.header.type = (obj_type);\
+ (db_obj)->obj.header.impl_flags = 0;\
+ (db_obj)->obj.header.flags = 0;\
+ (db_obj)->obj.header.domain = GRN_ID_NIL;\
+ (db_obj)->obj.id = GRN_ID_NIL;\
+ (db_obj)->obj.user_data.ptr = NULL;\
+ (db_obj)->obj.finalizer = NULL;\
+ (db_obj)->obj.hooks[0] = NULL;\
+ (db_obj)->obj.hooks[1] = NULL;\
+ (db_obj)->obj.hooks[2] = NULL;\
+ (db_obj)->obj.hooks[3] = NULL;\
+ (db_obj)->obj.hooks[4] = NULL;\
+ (db_obj)->obj.source = NULL;\
+ (db_obj)->obj.source_size = 0;\
+} while (0)
+
+/**** receive handler ****/
+
+GRN_API void grn_ctx_stream_out_func(grn_ctx *c, int flags, void *stream);
+
+grn_rc grn_db_init_builtin_procs(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ctx_impl.h b/storage/mroonga/vendor/groonga/lib/grn_ctx_impl.h
new file mode 100644
index 00000000..8f300f09
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ctx_impl.h
@@ -0,0 +1,237 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifndef GRN_CTX_H
+# include "grn_ctx.h"
+#endif /* GRN_CTX_H */
+
+#ifndef GRN_COM_H
+# include "grn_com.h"
+#endif /* GRN_COM_H */
+
+#include "grn_msgpack.h"
+
+#ifdef GRN_WITH_MRUBY
+# include <mruby.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**** grn_expr ****/
+
+#define GRN_EXPR_MISSING_NAME "expr_missing"
+
+/**** grn_ctx_impl ****/
+
+#define GRN_CTX_INITED 0x00
+#define GRN_CTX_QUITTING 0x0f
+
+typedef enum {
+ GRN_LOADER_BEGIN = 0,
+ GRN_LOADER_TOKEN,
+ GRN_LOADER_STRING,
+ GRN_LOADER_SYMBOL,
+ GRN_LOADER_NUMBER,
+ GRN_LOADER_STRING_ESC,
+ GRN_LOADER_UNICODE0,
+ GRN_LOADER_UNICODE1,
+ GRN_LOADER_UNICODE2,
+ GRN_LOADER_UNICODE3,
+ GRN_LOADER_END
+} grn_loader_stat;
+
+/*
+ * Status of target columns used in Format 1.
+ * Target columns are specified via --columns or the first array in a Format 1
+ * JSON object.
+ */
+typedef enum {
+ GRN_LOADER_COLUMNS_UNSET = 0, /* Columns are not available. */
+ GRN_LOADER_COLUMNS_SET, /* Columns are available. */
+ GRN_LOADER_COLUMNS_BROKEN /* Columns are specified but broken. */
+} grn_loader_columns_status;
+
+typedef struct {
+ grn_obj values;
+ grn_obj level;
+ grn_obj columns;
+ grn_obj ids;
+ grn_obj return_codes;
+ grn_obj error_messages;
+ uint32_t emit_level;
+ int32_t id_offset; /* Position of _id in values or -1 if _id is N/A. */
+ int32_t key_offset; /* Position of _key in values or -1 if _key is N/A. */
+ grn_obj *table;
+ grn_obj *last;
+ grn_obj *ifexists;
+ grn_obj *each;
+ uint32_t unichar;
+ uint32_t values_size;
+ uint32_t nrecords;
+ grn_loader_stat stat;
+ grn_content_type input_type;
+ grn_loader_columns_status columns_status;
+ grn_rc rc;
+ char errbuf[GRN_CTX_MSGSIZE];
+ grn_bool output_ids;
+ grn_bool output_errors;
+} grn_loader;
+
+#define GRN_CTX_N_SEGMENTS 512
+
+#ifdef USE_MEMORY_DEBUG
+typedef struct _grn_alloc_info grn_alloc_info;
+struct _grn_alloc_info
+{
+ void *address;
+ int freed;
+ size_t size;
+ char alloc_backtrace[4096];
+ char free_backtrace[4096];
+ char *file;
+ int line;
+ char *func;
+ grn_alloc_info *next;
+};
+#endif
+
+typedef struct _grn_mrb_data grn_mrb_data;
+struct _grn_mrb_data {
+ grn_bool initialized;
+#ifdef GRN_WITH_MRUBY
+ mrb_state *state;
+ char base_directory[PATH_MAX];
+ struct RClass *module;
+ struct RClass *object_class;
+ grn_hash *checked_procs;
+ grn_hash *registered_plugins;
+ struct {
+ grn_obj from;
+ grn_obj to;
+ } buffer;
+ struct {
+ struct RClass *time_class;
+ } builtin;
+ struct {
+ struct RClass *operator_class;
+ } groonga;
+#endif
+};
+
+struct _grn_ctx_impl {
+ grn_encoding encoding;
+
+ /* memory pool portion */
+ int32_t lifoseg;
+ int32_t currseg;
+ grn_critical_section lock;
+ grn_io_mapinfo segs[GRN_CTX_N_SEGMENTS];
+
+#ifdef USE_DYNAMIC_MALLOC_CHANGE
+ /* memory allocation portion */
+ grn_malloc_func malloc_func;
+ grn_calloc_func calloc_func;
+ grn_realloc_func realloc_func;
+ grn_strdup_func strdup_func;
+ grn_free_func free_func;
+#endif
+
+#ifdef USE_MEMORY_DEBUG
+ /* memory debug portion */
+ grn_alloc_info *alloc_info;
+#endif
+
+ /* expression portion */
+ grn_obj *stack[GRN_STACK_SIZE];
+ uint32_t stack_curr;
+ grn_hash *expr_vars;
+ grn_obj *curr_expr;
+ grn_obj current_request_id;
+ void *current_request_timer_id;
+ void *parser;
+ grn_timeval tv;
+
+ /* loader portion */
+ grn_edge *edge;
+ grn_loader loader;
+
+ /* plugin portion */
+ const char *plugin_path;
+
+ /* output portion */
+ struct {
+ grn_obj *buf;
+ void (*func)(grn_ctx *, int, void *);
+ union {
+ void *ptr;
+ int fd;
+ uint32_t u32;
+ uint64_t u64;
+ } data;
+ grn_content_type type;
+ const char *mime_type;
+ grn_bool is_pretty;
+ grn_obj names;
+ grn_obj levels;
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_packer msgpacker;
+#endif
+ } output;
+
+ struct {
+ int flags;
+ grn_command_version version;
+ struct {
+ grn_obj *command;
+ grn_command_version version;
+ } keep;
+ } command;
+
+ /* match escalation portion */
+ int64_t match_escalation_threshold;
+
+ /* lifetime portion */
+ grn_proc_func *finalizer;
+
+ grn_obj *db;
+ grn_array *values; /* temporary objects */
+ grn_pat *temporary_columns;
+ grn_hash *ios; /* IOs */
+ grn_com *com;
+ unsigned int com_status;
+
+ grn_obj query_log_buf;
+
+ char previous_errbuf[GRN_CTX_MSGSIZE];
+ unsigned int n_same_error_messages;
+
+ grn_mrb_data mrb;
+
+ struct {
+ grn_obj stack;
+ grn_obj *current;
+ } temporary_open_spaces;
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ctx_impl_mrb.h b/storage/mroonga/vendor/groonga/lib/grn_ctx_impl_mrb.h
new file mode 100644
index 00000000..e3d619ab
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ctx_impl_mrb.h
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_ctx_impl_mrb_init_from_env(void);
+void grn_ctx_impl_mrb_init(grn_ctx *ctx);
+void grn_ctx_impl_mrb_fin(grn_ctx *ctx);
+GRN_API void grn_ctx_impl_mrb_ensure_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_dat.h b/storage/mroonga/vendor/groonga/lib/grn_dat.h
new file mode 100644
index 00000000..7d0d0c8d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_dat.h
@@ -0,0 +1,95 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2011-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _grn_dat {
+ grn_db_obj obj;
+ grn_io *io;
+ struct grn_dat_header *header;
+ uint32_t file_id;
+ grn_encoding encoding;
+ void *trie;
+ void *old_trie;
+ grn_obj *tokenizer;
+ grn_obj *normalizer;
+ grn_obj token_filters;
+ grn_critical_section lock;
+ grn_bool is_dirty;
+};
+
+struct grn_dat_header {
+ uint32_t flags;
+ grn_encoding encoding;
+ grn_id tokenizer;
+ uint32_t file_id;
+ grn_id normalizer;
+ uint32_t n_dirty_opens;
+ uint32_t reserved[234];
+};
+
+struct _grn_dat_cursor {
+ grn_db_obj obj;
+ grn_dat *dat;
+ void *cursor;
+ const void *key;
+ grn_id curr_rec;
+};
+
+GRN_API grn_id grn_dat_curr_id(grn_ctx *ctx, grn_dat *dat);
+
+/*
+ Currently, grn_dat_truncate() is available if the grn_dat object is
+ associated with a file.
+ */
+GRN_API grn_rc grn_dat_truncate(grn_ctx *ctx, grn_dat *dat);
+
+GRN_API const char *_grn_dat_key(grn_ctx *ctx, grn_dat *dat, grn_id id,
+ uint32_t *key_size);
+GRN_API grn_id grn_dat_next(grn_ctx *ctx, grn_dat *dat, grn_id id);
+GRN_API grn_id grn_dat_at(grn_ctx *ctx, grn_dat *dat, grn_id id);
+
+GRN_API grn_rc grn_dat_clear_status_flags(grn_ctx *ctx, grn_dat *dat);
+
+/*
+ Currently, grn_dat_repair() is available if the grn_dat object is associated
+ with a file.
+ */
+GRN_API grn_rc grn_dat_repair(grn_ctx *ctx, grn_dat *dat);
+
+GRN_API grn_rc grn_dat_flush(grn_ctx *ctx, grn_dat *dat);
+
+grn_rc grn_dat_dirty(grn_ctx *ctx, grn_dat *dat);
+grn_bool grn_dat_is_dirty(grn_ctx *ctx, grn_dat *dat);
+grn_rc grn_dat_clean(grn_ctx *ctx, grn_dat *dat);
+grn_rc grn_dat_clear_dirty(grn_ctx *ctx, grn_dat *dat);
+
+grn_bool grn_dat_is_corrupt(grn_ctx *ctx, grn_dat *dat);
+
+size_t grn_dat_get_disk_usage(grn_ctx *ctx, grn_dat *dat);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_db.h b/storage/mroonga/vendor/groonga/lib/grn_db.h
new file mode 100644
index 00000000..d3a6b48b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_db.h
@@ -0,0 +1,493 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_store.h"
+#include "grn_rset.h"
+
+#include <groonga/command.h>
+#include <groonga/token_filter.h>
+#include <groonga/scorer.h>
+
+#include <float.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_DB_DELIMITER '.'
+#define GRN_DB_PSEUDO_COLUMN_PREFIX '_'
+
+#define GRN_N_RESERVED_TYPES 256
+
+typedef struct _grn_db grn_db;
+typedef struct _grn_proc grn_proc;
+
+struct _grn_db {
+ grn_db_obj obj;
+ grn_obj *keys;
+ grn_ja *specs;
+ grn_hash *config;
+ grn_tiny_array values;
+ grn_critical_section lock;
+};
+
+#define GRN_SERIALIZED_SPEC_INDEX_SPEC 0
+#define GRN_SERIALIZED_SPEC_INDEX_PATH 1
+#define GRN_SERIALIZED_SPEC_INDEX_SOURCE 2
+#define GRN_SERIALIZED_SPEC_INDEX_HOOK 3
+#define GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS 4
+#define GRN_SERIALIZED_SPEC_INDEX_EXPR 4
+
+typedef struct {
+ grn_obj_header header;
+ grn_id range;
+} grn_obj_spec;
+
+grn_bool grn_db_spec_unpack(grn_ctx *ctx,
+ grn_id id,
+ void *encoded_spec,
+ uint32_t encoded_spec_size,
+ grn_obj_spec **spec,
+ grn_obj *decoded_spec,
+ const char *error_message_tag);
+
+#define GRN_DB_SPEC_EACH_BEGIN(ctx, cursor, id, spec) do { \
+ grn_obj *db = grn_ctx_db((ctx)); \
+ grn_db *db_raw = (grn_db *)db; \
+ grn_obj decoded_spec; \
+ grn_io_win iw; \
+ grn_bool iw_need_unref = GRN_FALSE; \
+ GRN_OBJ_INIT(&decoded_spec, GRN_VECTOR, 0, GRN_DB_TEXT); \
+ GRN_TABLE_EACH_BEGIN((ctx), db, cursor, id) { \
+ void *encoded_spec; \
+ uint32_t encoded_spec_size; \
+ grn_bool success; \
+ grn_obj_spec *spec; \
+ \
+ if (iw_need_unref) { \
+ grn_ja_unref(ctx, &iw); \
+ iw_need_unref = GRN_FALSE; \
+ } \
+ encoded_spec = grn_ja_ref((ctx), \
+ db_raw->specs, \
+ id, \
+ &iw, \
+ &encoded_spec_size); \
+ if (!encoded_spec) { \
+ continue; \
+ } \
+ iw_need_unref = GRN_TRUE; \
+ \
+ GRN_BULK_REWIND(&decoded_spec); \
+ success = grn_db_spec_unpack(ctx, \
+ id, \
+ encoded_spec, \
+ encoded_spec_size, \
+ &spec, \
+ &decoded_spec, \
+ __FUNCTION__); \
+ if (!success) { \
+ continue; \
+ } \
+
+#define GRN_DB_SPEC_EACH_END(ctx, cursor) \
+ } GRN_TABLE_EACH_END(ctx, cursor); \
+ if (iw_need_unref) { \
+ grn_ja_unref(ctx, &iw); \
+ } \
+ GRN_OBJ_FIN((ctx), &decoded_spec); \
+} while(GRN_FALSE)
+
+void grn_db_init_from_env(void);
+
+GRN_API grn_rc grn_db_close(grn_ctx *ctx, grn_obj *db);
+
+grn_obj *grn_db_keys(grn_obj *s);
+
+void grn_db_generate_pathname(grn_ctx *ctx,
+ grn_obj *db,
+ grn_id id,
+ char *buffer);
+
+grn_rc _grn_table_delete_by_id(grn_ctx *ctx, grn_obj *table, grn_id id,
+ grn_table_delete_optarg *optarg);
+
+grn_id grn_table_get_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
+ void **value);
+grn_id grn_table_add_v(grn_ctx *ctx, grn_obj *table, const void *key, int key_size,
+ void **value, int *added);
+grn_id grn_table_add_by_key(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *key,
+ int *added);
+GRN_API grn_rc grn_table_get_info(grn_ctx *ctx, grn_obj *table, grn_table_flags *flags,
+ grn_encoding *encoding, grn_obj **tokenizer,
+ grn_obj **normalizer,
+ grn_obj **token_filters);
+const char *_grn_table_key(grn_ctx *ctx, grn_obj *table, grn_id id, uint32_t *key_size);
+
+grn_rc grn_table_search(grn_ctx *ctx, grn_obj *table,
+ const void *key, uint32_t key_size,
+ grn_operator mode, grn_obj *res, grn_operator op);
+
+grn_rc grn_table_fuzzy_search(grn_ctx *ctx, grn_obj *table,
+ const void *key, uint32_t key_size,
+ grn_fuzzy_search_optarg *args, grn_obj *res, grn_operator op);
+
+grn_id grn_table_next(grn_ctx *ctx, grn_obj *table, grn_id id);
+
+int grn_table_get_key2(grn_ctx *ctx, grn_obj *table, grn_id id, grn_obj *bulk);
+
+grn_table_cursor *grn_table_cursor_open_by_id(grn_ctx *ctx, grn_obj *table,
+ grn_id min, grn_id max, int flags);
+
+void grn_table_add_subrec(grn_obj *table, grn_rset_recinfo *ri, double score,
+ grn_rset_posinfo *pi, int dir);
+
+grn_obj *grn_obj_graft(grn_ctx *ctx, grn_obj *obj);
+
+grn_rc grn_column_name_(grn_ctx *ctx, grn_obj *obj, grn_obj *buf);
+
+
+typedef enum {
+ PROC_INIT = 0,
+ PROC_NEXT,
+ PROC_FIN
+} grn_proc_phase;
+
+struct _grn_type {
+ grn_db_obj obj;
+};
+
+#define GRN_TYPE_SIZE(type) ((type)->range)
+
+#define GRN_TABLE_SORT_GEO (0x02<<0)
+
+#define GRN_OBJ_TMP_OBJECT 0x80000000
+#define GRN_OBJ_TMP_COLUMN 0x40000000
+
+#define GRN_DB_OBJP(obj) \
+ (obj &&\
+ ((GRN_SNIP == ((grn_db_obj *)obj)->header.type) ||\
+ ((GRN_CURSOR_TABLE_HASH_KEY <= ((grn_db_obj *)obj)->header.type) &&\
+ (((grn_db_obj *)obj)->header.type <= GRN_COLUMN_INDEX))))
+
+#define GRN_OBJ_TABLEP(obj) \
+ (obj &&\
+ (GRN_TABLE_HASH_KEY <= ((grn_db_obj *)obj)->header.type) &&\
+ (((grn_db_obj *)obj)->header.type <= GRN_DB))
+
+#define GRN_OBJ_INDEX_COLUMNP(obj) \
+ (obj &&\
+ DB_OBJ(obj)->header.type == GRN_COLUMN_INDEX)
+
+#define GRN_OBJ_VECTOR_COLUMNP(obj) \
+ (obj &&\
+ DB_OBJ(obj)->header.type == GRN_COLUMN_VAR_SIZE &&\
+ (DB_OBJ(obj)->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR)
+
+#define GRN_OBJ_WEIGHT_VECTOR_COLUMNP(obj) \
+ (GRN_OBJ_VECTOR_COLUMNP(obj) &&\
+ (DB_OBJ(obj)->header.flags & GRN_OBJ_WITH_WEIGHT))
+
+struct _grn_hook {
+ grn_hook *next;
+ grn_proc *proc;
+ uint32_t hld_size;
+};
+
+typedef struct _grn_proc_ctx grn_proc_ctx;
+
+struct _grn_proc_ctx {
+ grn_user_data user_data;
+ grn_proc *proc;
+ grn_obj *caller;
+ // grn_obj *obj;
+ grn_hook *hooks;
+ grn_hook *currh;
+ grn_proc_phase phase;
+ unsigned short nargs;
+ unsigned short offset;
+ grn_user_data data[16];
+};
+
+struct _grn_proc {
+ grn_db_obj obj;
+ grn_obj name_buf;
+ grn_expr_var *vars;
+ uint32_t nvars;
+ /* -- compatible with grn_expr -- */
+ grn_proc_type type;
+ grn_proc_func *funcs[3];
+
+ union {
+ struct {
+ grn_selector_func *selector;
+ grn_operator selector_op;
+ grn_bool is_stable;
+ } function;
+ struct {
+ grn_command_run_func *run;
+ } command;
+ struct {
+ grn_token_filter_init_func *init;
+ grn_token_filter_filter_func *filter;
+ grn_token_filter_fin_func *fin;
+ } token_filter;
+ struct {
+ grn_scorer_score_func *score;
+ } scorer;
+ grn_window_function_func *window_function;
+ } callbacks;
+
+ void *user_data;
+
+ grn_id module;
+ // uint32_t nargs;
+ // uint32_t nresults;
+ // grn_obj results[16];
+};
+
+#define GRN_PROC_GET_VARS() (grn_proc_get_vars(ctx, user_data))
+#define GRN_PROC_GET_VAR(name) (grn_proc_get_var(ctx, user_data, name, strlen(name)))
+#define GRN_PROC_GET_VAR_BY_OFFSET(offset) (grn_proc_get_var_by_offset(ctx, user_data, offset))
+#define GRN_PROC_GET_OR_ADD_VAR(name) (grn_proc_get_or_add_var(ctx, user_data, name, strlen(name)))
+#define GRN_PROC_ALLOC(domain, flags) (grn_proc_alloc(ctx, user_data, domain, flags))
+
+grn_obj *grn_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data);
+
+grn_obj *grn_proc_get_var(grn_ctx *ctx, grn_user_data *user_data,
+ const char *name, unsigned int name_size);
+
+GRN_API grn_obj *grn_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data,
+ unsigned int offset);
+GRN_API grn_obj *grn_proc_get_or_add_var(grn_ctx *ctx, grn_user_data *user_data,
+ const char *name, unsigned int name_size);
+
+GRN_API grn_obj *grn_proc_alloc(grn_ctx *ctx, grn_user_data *user_data,
+ grn_id domain, unsigned char flags);
+
+GRN_API grn_rc grn_proc_call(grn_ctx *ctx, grn_obj *proc,
+ int nargs, grn_obj *caller);
+
+grn_obj *grn_expr_get_or_add_var(grn_ctx *ctx, grn_obj *expr,
+ const char *name, unsigned int name_size);
+
+
+typedef struct _grn_accessor grn_accessor;
+
+struct _grn_accessor {
+ grn_obj_header header;
+ grn_id range;
+ /* -- compatible with grn_db_obj -- */
+ uint8_t action;
+ int offset;
+ grn_obj *obj;
+ grn_accessor *next;
+};
+
+enum {
+ GRN_ACCESSOR_VOID = 0,
+ GRN_ACCESSOR_GET_ID,
+ GRN_ACCESSOR_GET_KEY,
+ GRN_ACCESSOR_GET_VALUE,
+ GRN_ACCESSOR_GET_SCORE,
+ GRN_ACCESSOR_GET_NSUBRECS,
+ GRN_ACCESSOR_GET_MAX,
+ GRN_ACCESSOR_GET_MIN,
+ GRN_ACCESSOR_GET_SUM,
+ GRN_ACCESSOR_GET_AVG,
+ GRN_ACCESSOR_GET_COLUMN_VALUE,
+ GRN_ACCESSOR_GET_DB_OBJ,
+ GRN_ACCESSOR_LOOKUP,
+ GRN_ACCESSOR_FUNCALL
+};
+
+#define DB_OBJ(obj) ((grn_db_obj *)obj)
+
+GRN_API const char *grn_obj_get_value_(grn_ctx *ctx, grn_obj *obj, grn_id id, uint32_t *size);
+
+/* vector */
+
+/*
+typedef struct _grn_vector grn_vector;
+
+struct _grn_vector {
+ grn_obj str;
+ uint32_t *offsets;
+ int n_entries;
+};
+
+const char *grn_vector_fetch(grn_ctx *ctx, grn_obj *vector, int i, unsigned int *size);
+int grn_vector_delimit(grn_ctx *ctx, grn_obj *vector);
+int grn_vector_size(grn_ctx *ctx, grn_obj *vector);
+*/
+
+grn_rc grn_vector_delimit(grn_ctx *ctx, grn_obj *v, unsigned int weight, grn_id domain);
+grn_rc grn_vector_decode(grn_ctx *ctx, grn_obj *v, const char *data, uint32_t data_size);
+
+
+grn_rc grn_db_init_builtin_types(grn_ctx *ctx);
+
+/* flag value used for grn_obj.header.flags */
+
+#define GRN_OBJ_CUSTOM_NAME (0x01<<12) /* db_obj which has custom name */
+
+#define GRN_OBJ_RESOLVE(ctx,obj) \
+ (((obj)->header.type != GRN_PTR)\
+ ? (obj)\
+ : GRN_PTR_VALUE(obj)\
+ ? GRN_PTR_VALUE(obj)\
+ : grn_ctx_at((ctx), (obj)->header.domain))
+
+/* expr */
+
+typedef struct _grn_expr grn_expr;
+
+#define GRN_EXPR_CODE_RELATIONAL_EXPRESSION (0x01)
+
+typedef struct {
+ grn_obj *value;
+ int32_t nargs;
+ grn_operator op;
+ uint8_t flags;
+ int32_t modify;
+} grn_expr_code;
+
+#define GRN_EXPR_CONST_BLK_SIZE GRN_STACK_SIZE
+
+struct _grn_expr {
+ grn_db_obj obj;
+ grn_obj name_buf;
+ grn_expr_var *vars;
+ uint32_t nvars;
+ /* -- compatible with grn_proc -- */
+
+ uint16_t cacheable;
+ uint16_t taintable;
+ grn_obj **const_blks;
+ grn_obj *values;
+ grn_expr_code *codes;
+ uint32_t nconsts;
+ uint32_t values_curr;
+ uint32_t values_tail;
+ uint32_t values_size;
+ uint32_t codes_curr;
+ uint32_t codes_size;
+
+ grn_obj objs;
+ grn_obj dfi;
+ grn_expr_code *code0;
+};
+
+grn_rc grn_expr_parser_close(grn_ctx *ctx);
+
+/**
+ * grn_table_open:
+ * @name: The table name to be opened. `NULL` means anonymous table.
+ * @path: The path of the table to be opened.
+ *
+ * Opens an existing table. The table is associated with @name in DB
+ * that is used by @ctx. grn_ctx_get() is better rather than this
+ * function when you want to open a permanent named table that is
+ * registered in DB.
+ **/
+GRN_API grn_obj *grn_table_open(grn_ctx *ctx,
+ const char *name, unsigned int name_size,
+ const char *path);
+
+/**
+ * grn_column_open:
+ * @table: The table for the opened column.
+ * @name: The column name to be opened.
+ * @path: The path of the column to be opened.
+ * @type: The type of the column value.
+ *
+ * Opens an existing permanent column. The column is associated with
+ * @name in @table. grn_ctx_get() is better rather than this function
+ * when you want to open a column of an permanent table in DB.
+ **/
+grn_obj *grn_column_open(grn_ctx *ctx, grn_obj *table,
+ const char *name, unsigned int name_size,
+ const char *path, grn_obj *type);
+
+/**
+ * grn_obj_path_rename:
+ * @old_path: The current file path.
+ * @new_path: The new file path.
+ *
+ * It renames object's path that is stored in @old_path to @new_path.
+ **/
+grn_rc grn_obj_path_rename(grn_ctx *ctx, const char *old_path, const char *new_path);
+
+grn_rc grn_db_check_name(grn_ctx *ctx, const char *name, unsigned int name_size);
+#define GRN_DB_CHECK_NAME_ERR(error_context, name, name_size) \
+ ERR(GRN_INVALID_ARGUMENT,\
+ "%s name can't start with '%c' and contains only 0-9, A-Z, a-z, #, @, - or _: <%.*s>",\
+ error_context, GRN_DB_PSEUDO_COLUMN_PREFIX, name_size, name)
+
+#define GRN_DB_P(s) ((s) && ((grn_db *)s)->obj.header.type == GRN_DB)
+#define GRN_DB_PERSISTENT_P(s) (((grn_db *)s)->specs)
+
+#define GRN_OBJ_GET_VALUE_IMD (0xffffffffU)
+
+grn_rc grn_db_obj_init(grn_ctx *ctx, grn_obj *db, grn_id id, grn_db_obj *obj);
+
+#define GRN_ACCESSORP(obj) \
+ ((obj) && (((grn_obj *)(obj))->header.type == GRN_ACCESSOR))
+
+grn_id grn_obj_register(grn_ctx *ctx, grn_obj *db, const char *name, unsigned int name_size);
+int grn_obj_is_persistent(grn_ctx *ctx, grn_obj *obj);
+void grn_obj_spec_save(grn_ctx *ctx, grn_db_obj *obj);
+
+grn_rc grn_obj_reinit_for(grn_ctx *ctx, grn_obj *obj, grn_obj *domain_obj);
+
+void grn_expr_pack(grn_ctx *ctx, grn_obj *buf, grn_obj *expr);
+GRN_API grn_rc grn_expr_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *expr);
+grn_hash *grn_expr_get_vars(grn_ctx *ctx, grn_obj *expr, unsigned int *nvars);
+grn_obj *grn_expr_open(grn_ctx *ctx, grn_obj_spec *spec, const uint8_t *p, const uint8_t *pe);
+
+GRN_API grn_rc grn_table_group_with_range_gap(grn_ctx *ctx, grn_obj *table,
+ grn_table_sort_key *group_key,
+ grn_obj *result_set,
+ uint32_t range_gap);
+
+GRN_API grn_rc grn_column_filter(grn_ctx *ctx, grn_obj *column,
+ grn_operator op,
+ grn_obj *value, grn_obj *result_set,
+ grn_operator set_op);
+
+typedef struct {
+ grn_id target;
+ unsigned int section;
+} grn_obj_default_set_value_hook_data;
+
+grn_obj *grn_obj_default_set_value_hook(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data);
+
+grn_rc grn_pvector_fin(grn_ctx *ctx, grn_obj *obj);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c
new file mode 100644
index 00000000..cfabcc91
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.c
@@ -0,0 +1,2542 @@
+/*
+** 2000-05-29
+**
+** The author disclaims copyright to this source code. In place of
+** a legal notice, here is a blessing:
+**
+** May you do good and not evil.
+** May you find forgiveness for yourself and forgive others.
+** May you share freely, never taking more than you give.
+**
+*************************************************************************
+** Driver template for the LEMON parser generator.
+**
+** The "lemon" program processes an LALR(1) input grammar file, then uses
+** this template to construct a parser. The "lemon" program inserts text
+** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the
+** interstitial "-" characters) contained in this template is changed into
+** the value of the %name directive from the grammar. Otherwise, the content
+** of this template is copied straight through into the generate parser
+** source file.
+**
+** The following is the concatenation of all %include directives from the
+** input grammar file:
+*/
+#include <stdio.h>
+/************ Begin %include sections from the grammar ************************/
+#line 4 "grn_ecmascript.lemon"
+
+#ifdef assert
+# undef assert
+#endif
+#define assert GRN_ASSERT
+#line 34 "grn_ecmascript.c"
+/**************** End of %include directives **********************************/
+/* These constants specify the various numeric values for terminal symbols
+** in a format understandable to "makeheaders". This section is blank unless
+** "lemon" is run with the "-m" command-line option.
+***************** Begin makeheaders token definitions *************************/
+/**************** End makeheaders token definitions ***************************/
+
+/* The next sections is a series of control #defines.
+** various aspects of the generated parser.
+** YYCODETYPE is the data type used to store the integer codes
+** that represent terminal and non-terminal symbols.
+** "unsigned char" is used if there are fewer than
+** 256 symbols. Larger types otherwise.
+** YYNOCODE is a number of type YYCODETYPE that is not used for
+** any terminal or nonterminal symbol.
+** YYFALLBACK If defined, this indicates that one or more tokens
+** (also known as: "terminal symbols") have fall-back
+** values which should be used if the original symbol
+** would not parse. This permits keywords to sometimes
+** be used as identifiers, for example.
+** YYACTIONTYPE is the data type used for "action codes" - numbers
+** that indicate what to do in response to the next
+** token.
+** grn_expr_parserTOKENTYPE is the data type used for minor type for terminal
+** symbols. Background: A "minor type" is a semantic
+** value associated with a terminal or non-terminal
+** symbols. For example, for an "ID" terminal symbol,
+** the minor type might be the name of the identifier.
+** Each non-terminal can have a different minor type.
+** Terminal symbols all have the same minor type, though.
+** This macros defines the minor type for terminal
+** symbols.
+** YYMINORTYPE is the data type used for all minor types.
+** This is typically a union of many types, one of
+** which is grn_expr_parserTOKENTYPE. The entry in the union
+** for terminal symbols is called "yy0".
+** YYSTACKDEPTH is the maximum depth of the parser's stack. If
+** zero the stack is dynamically sized using realloc()
+** grn_expr_parserARG_SDECL A static variable declaration for the %extra_argument
+** grn_expr_parserARG_PDECL A parameter declaration for the %extra_argument
+** grn_expr_parserARG_STORE Code to store %extra_argument into yypParser
+** grn_expr_parserARG_FETCH Code to extract %extra_argument from yypParser
+** YYERRORSYMBOL is the code number of the error symbol. If not
+** defined, then do no error processing.
+** YYNSTATE the combined number of states.
+** YYNRULE the number of rules in the grammar
+** YY_MAX_SHIFT Maximum value for shift actions
+** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions
+** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions
+** YY_MIN_REDUCE Maximum value for reduce actions
+** YY_ERROR_ACTION The yy_action[] code for syntax error
+** YY_ACCEPT_ACTION The yy_action[] code for accept
+** YY_NO_ACTION The yy_action[] code for no-op
+*/
+#ifndef INTERFACE
+# define INTERFACE 1
+#endif
+/************* Begin control #defines *****************************************/
+#define YYCODETYPE unsigned char
+#define YYNOCODE 115
+#define YYACTIONTYPE unsigned short int
+#define grn_expr_parserTOKENTYPE int
+typedef union {
+ int yyinit;
+ grn_expr_parserTOKENTYPE yy0;
+ void * yy217;
+} YYMINORTYPE;
+#ifndef YYSTACKDEPTH
+#define YYSTACKDEPTH 100
+#endif
+#define grn_expr_parserARG_SDECL efs_info *efsi ;
+#define grn_expr_parserARG_PDECL , efs_info *efsi
+#define grn_expr_parserARG_FETCH efs_info *efsi = yypParser->efsi
+#define grn_expr_parserARG_STORE yypParser->efsi = efsi
+#define YYNSTATE 145
+#define YYNRULE 136
+#define YY_MAX_SHIFT 144
+#define YY_MIN_SHIFTREDUCE 232
+#define YY_MAX_SHIFTREDUCE 367
+#define YY_MIN_REDUCE 368
+#define YY_MAX_REDUCE 503
+#define YY_ERROR_ACTION 504
+#define YY_ACCEPT_ACTION 505
+#define YY_NO_ACTION 506
+/************* End control #defines *******************************************/
+
+/* Define the yytestcase() macro to be a no-op if is not already defined
+** otherwise.
+**
+** Applications can choose to define yytestcase() in the %include section
+** to a macro that can assist in verifying code coverage. For production
+** code the yytestcase() macro should be turned off. But it is useful
+** for testing.
+*/
+#ifndef yytestcase
+# define yytestcase(X)
+#endif
+
+
+/* Next are the tables used to determine what action to take based on the
+** current state and lookahead token. These tables are used to implement
+** functions that take a state number and lookahead value and return an
+** action integer.
+**
+** Suppose the action integer is N. Then the action is determined as
+** follows
+**
+** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead
+** token onto the stack and goto state N.
+**
+** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then
+** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE.
+**
+** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE
+** and YY_MAX_REDUCE
+**
+** N == YY_ERROR_ACTION A syntax error has occurred.
+**
+** N == YY_ACCEPT_ACTION The parser accepts its input.
+**
+** N == YY_NO_ACTION No such action. Denotes unused
+** slots in the yy_action[] table.
+**
+** The action table is constructed as a single large table named yy_action[].
+** Given state S and lookahead X, the action is computed as either:
+**
+** (A) N = yy_action[ yy_shift_ofst[S] + X ]
+** (B) N = yy_default[S]
+**
+** The (A) formula is preferred. The B formula is used instead if:
+** (1) The yy_shift_ofst[S]+X value is out of range, or
+** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or
+** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT.
+** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that
+** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X.
+** Hence only tests (1) and (2) need to be evaluated.)
+**
+** The formulas above are for computing the action when the lookahead is
+** a terminal symbol. If the lookahead is a non-terminal (as occurs after
+** a reduce action) then the yy_reduce_ofst[] array is used in place of
+** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of
+** YY_SHIFT_USE_DFLT.
+**
+** The following are the tables generated in this section:
+**
+** yy_action[] A single table containing all actions.
+** yy_lookahead[] A table containing the lookahead for each entry in
+** yy_action. Used to detect hash collisions.
+** yy_shift_ofst[] For each state, the offset into yy_action for
+** shifting terminals.
+** yy_reduce_ofst[] For each state, the offset into yy_action for
+** shifting non-terminals after a reduce.
+** yy_default[] Default action for each state.
+**
+*********** Begin parsing tables **********************************************/
+#define YY_ACTTAB_COUNT (1794)
+static const YYACTIONTYPE yy_action[] = {
+ /* 0 */ 3, 72, 115, 115, 136, 131, 323, 2, 363, 54,
+ /* 10 */ 83, 129, 1, 232, 71, 505, 79, 112, 10, 241,
+ /* 20 */ 79, 75, 112, 112, 91, 126, 125, 139, 138, 137,
+ /* 30 */ 120, 88, 103, 116, 104, 104, 104, 91, 75, 241,
+ /* 40 */ 241, 75, 75, 323, 74, 457, 84, 83, 144, 9,
+ /* 50 */ 236, 71, 66, 65, 53, 52, 51, 69, 68, 67,
+ /* 60 */ 64, 63, 61, 60, 59, 348, 349, 350, 351, 352,
+ /* 70 */ 4, 127, 70, 58, 57, 75, 127, 127, 91, 126,
+ /* 80 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 90 */ 104, 91, 75, 78, 456, 75, 75, 78, 76, 115,
+ /* 100 */ 115, 136, 235, 323, 2, 499, 54, 83, 129, 1,
+ /* 110 */ 5, 71, 78, 118, 110, 82, 78, 75, 118, 118,
+ /* 120 */ 91, 126, 125, 139, 138, 137, 120, 88, 103, 116,
+ /* 130 */ 104, 104, 104, 91, 75, 315, 133, 75, 75, 7,
+ /* 140 */ 300, 62, 77, 346, 73, 110, 133, 362, 136, 66,
+ /* 150 */ 65, 299, 343, 239, 69, 68, 67, 64, 63, 61,
+ /* 160 */ 60, 59, 348, 349, 350, 351, 352, 4, 50, 49,
+ /* 170 */ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39,
+ /* 180 */ 38, 37, 31, 30, 66, 65, 312, 56, 55, 69,
+ /* 190 */ 68, 67, 64, 63, 61, 60, 59, 348, 349, 350,
+ /* 200 */ 351, 352, 4, 111, 238, 313, 75, 314, 314, 91,
+ /* 210 */ 126, 125, 139, 138, 137, 120, 88, 103, 116, 104,
+ /* 220 */ 104, 104, 91, 75, 36, 35, 75, 75, 7, 237,
+ /* 230 */ 62, 6, 346, 73, 309, 240, 357, 28, 75, 87,
+ /* 240 */ 87, 91, 126, 125, 139, 138, 137, 120, 88, 103,
+ /* 250 */ 116, 104, 104, 104, 91, 75, 304, 234, 75, 75,
+ /* 260 */ 11, 87, 7, 23, 62, 233, 346, 73, 297, 298,
+ /* 270 */ 357, 7, 356, 66, 65, 346, 73, 130, 69, 68,
+ /* 280 */ 67, 64, 63, 61, 60, 59, 348, 349, 350, 351,
+ /* 290 */ 352, 4, 354, 7, 8, 62, 135, 346, 73, 345,
+ /* 300 */ 317, 356, 32, 29, 316, 132, 28, 66, 65, 364,
+ /* 310 */ 24, 34, 69, 68, 67, 64, 63, 61, 60, 59,
+ /* 320 */ 348, 349, 350, 351, 352, 4, 353, 26, 355, 348,
+ /* 330 */ 349, 350, 351, 352, 4, 33, 25, 370, 66, 65,
+ /* 340 */ 370, 370, 370, 69, 68, 67, 64, 63, 61, 60,
+ /* 350 */ 59, 348, 349, 350, 351, 352, 4, 75, 314, 314,
+ /* 360 */ 91, 126, 125, 139, 138, 137, 120, 88, 103, 116,
+ /* 370 */ 104, 104, 104, 91, 75, 370, 370, 75, 75, 370,
+ /* 380 */ 370, 370, 370, 370, 370, 311, 28, 370, 370, 370,
+ /* 390 */ 370, 75, 306, 306, 91, 126, 125, 139, 138, 137,
+ /* 400 */ 120, 88, 103, 116, 104, 104, 104, 91, 75, 370,
+ /* 410 */ 370, 75, 75, 370, 370, 370, 370, 370, 114, 118,
+ /* 420 */ 370, 370, 370, 75, 118, 118, 91, 126, 125, 139,
+ /* 430 */ 138, 137, 120, 88, 103, 116, 104, 104, 104, 91,
+ /* 440 */ 75, 121, 303, 75, 75, 75, 121, 121, 91, 126,
+ /* 450 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 460 */ 104, 91, 75, 370, 370, 75, 75, 370, 7, 370,
+ /* 470 */ 62, 127, 346, 73, 370, 75, 127, 127, 91, 126,
+ /* 480 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 490 */ 104, 91, 75, 455, 370, 75, 75, 7, 370, 62,
+ /* 500 */ 370, 346, 73, 370, 370, 370, 370, 370, 370, 28,
+ /* 510 */ 370, 370, 370, 66, 65, 370, 370, 370, 69, 68,
+ /* 520 */ 67, 64, 63, 61, 60, 59, 348, 349, 128, 351,
+ /* 530 */ 352, 4, 370, 370, 370, 370, 370, 370, 370, 370,
+ /* 540 */ 370, 370, 66, 65, 370, 370, 370, 69, 68, 67,
+ /* 550 */ 64, 63, 61, 60, 59, 348, 349, 350, 351, 352,
+ /* 560 */ 4, 75, 360, 360, 91, 126, 125, 139, 138, 137,
+ /* 570 */ 120, 88, 103, 116, 104, 104, 104, 91, 75, 370,
+ /* 580 */ 370, 75, 75, 75, 359, 359, 91, 126, 125, 139,
+ /* 590 */ 138, 137, 120, 88, 103, 116, 104, 104, 104, 91,
+ /* 600 */ 75, 370, 370, 75, 75, 75, 254, 254, 91, 126,
+ /* 610 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 620 */ 104, 91, 75, 370, 370, 75, 75, 75, 253, 253,
+ /* 630 */ 91, 126, 125, 139, 138, 137, 120, 88, 103, 116,
+ /* 640 */ 104, 104, 104, 91, 75, 370, 370, 75, 75, 75,
+ /* 650 */ 252, 252, 91, 126, 125, 139, 138, 137, 120, 88,
+ /* 660 */ 103, 116, 104, 104, 104, 91, 75, 370, 370, 75,
+ /* 670 */ 75, 75, 251, 251, 91, 126, 125, 139, 138, 137,
+ /* 680 */ 120, 88, 103, 116, 104, 104, 104, 91, 75, 370,
+ /* 690 */ 370, 75, 75, 75, 250, 250, 91, 126, 125, 139,
+ /* 700 */ 138, 137, 120, 88, 103, 116, 104, 104, 104, 91,
+ /* 710 */ 75, 370, 370, 75, 75, 75, 249, 249, 91, 126,
+ /* 720 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 730 */ 104, 91, 75, 370, 370, 75, 75, 75, 248, 248,
+ /* 740 */ 91, 126, 125, 139, 138, 137, 120, 88, 103, 116,
+ /* 750 */ 104, 104, 104, 91, 75, 370, 370, 75, 75, 75,
+ /* 760 */ 247, 247, 91, 126, 125, 139, 138, 137, 120, 88,
+ /* 770 */ 103, 116, 104, 104, 104, 91, 75, 370, 370, 75,
+ /* 780 */ 75, 75, 246, 246, 91, 126, 125, 139, 138, 137,
+ /* 790 */ 120, 88, 103, 116, 104, 104, 104, 91, 75, 370,
+ /* 800 */ 370, 75, 75, 75, 245, 245, 91, 126, 125, 139,
+ /* 810 */ 138, 137, 120, 88, 103, 116, 104, 104, 104, 91,
+ /* 820 */ 75, 370, 370, 75, 75, 75, 244, 244, 91, 126,
+ /* 830 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 840 */ 104, 91, 75, 370, 370, 75, 75, 75, 307, 307,
+ /* 850 */ 91, 126, 125, 139, 138, 137, 120, 88, 103, 116,
+ /* 860 */ 104, 104, 104, 91, 75, 370, 370, 75, 75, 75,
+ /* 870 */ 302, 302, 91, 126, 125, 139, 138, 137, 120, 88,
+ /* 880 */ 103, 116, 104, 104, 104, 91, 75, 370, 370, 75,
+ /* 890 */ 75, 75, 255, 255, 91, 126, 125, 139, 138, 137,
+ /* 900 */ 120, 88, 103, 116, 104, 104, 104, 91, 75, 370,
+ /* 910 */ 370, 75, 75, 75, 143, 143, 91, 126, 125, 139,
+ /* 920 */ 138, 137, 120, 88, 103, 116, 104, 104, 104, 91,
+ /* 930 */ 75, 370, 370, 75, 75, 75, 243, 243, 91, 126,
+ /* 940 */ 125, 139, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 950 */ 104, 91, 75, 370, 370, 75, 75, 75, 242, 242,
+ /* 960 */ 91, 126, 125, 139, 138, 137, 120, 88, 103, 116,
+ /* 970 */ 104, 104, 104, 91, 75, 370, 75, 75, 75, 122,
+ /* 980 */ 370, 113, 139, 138, 137, 120, 88, 103, 116, 104,
+ /* 990 */ 104, 104, 122, 75, 370, 75, 75, 75, 122, 370,
+ /* 1000 */ 370, 134, 138, 137, 120, 88, 103, 116, 104, 104,
+ /* 1010 */ 104, 122, 75, 370, 75, 75, 75, 122, 370, 370,
+ /* 1020 */ 142, 138, 137, 120, 88, 103, 116, 104, 104, 104,
+ /* 1030 */ 122, 75, 370, 75, 75, 75, 122, 370, 370, 370,
+ /* 1040 */ 141, 137, 120, 88, 103, 116, 104, 104, 104, 122,
+ /* 1050 */ 75, 370, 75, 75, 75, 122, 370, 370, 370, 370,
+ /* 1060 */ 140, 120, 88, 103, 116, 104, 104, 104, 122, 75,
+ /* 1070 */ 370, 370, 75, 75, 370, 370, 370, 370, 27, 22,
+ /* 1080 */ 21, 20, 19, 18, 17, 16, 15, 14, 13, 12,
+ /* 1090 */ 75, 370, 370, 122, 370, 370, 370, 370, 370, 124,
+ /* 1100 */ 88, 103, 116, 104, 104, 104, 122, 75, 370, 370,
+ /* 1110 */ 75, 75, 75, 370, 370, 122, 370, 370, 370, 370,
+ /* 1120 */ 297, 298, 89, 103, 116, 104, 104, 104, 122, 75,
+ /* 1130 */ 370, 75, 75, 75, 122, 370, 370, 370, 370, 370,
+ /* 1140 */ 370, 90, 103, 116, 104, 104, 104, 122, 75, 370,
+ /* 1150 */ 370, 75, 75, 370, 370, 86, 85, 81, 80, 323,
+ /* 1160 */ 74, 324, 84, 83, 144, 9, 454, 71, 370, 86,
+ /* 1170 */ 85, 81, 80, 323, 74, 370, 84, 83, 144, 9,
+ /* 1180 */ 370, 71, 370, 75, 370, 370, 122, 370, 370, 370,
+ /* 1190 */ 370, 370, 370, 370, 92, 116, 104, 104, 104, 122,
+ /* 1200 */ 75, 370, 370, 75, 75, 75, 370, 370, 122, 370,
+ /* 1210 */ 370, 370, 370, 370, 370, 370, 93, 116, 104, 104,
+ /* 1220 */ 104, 122, 75, 370, 370, 75, 75, 75, 370, 370,
+ /* 1230 */ 122, 370, 370, 370, 370, 370, 370, 370, 94, 116,
+ /* 1240 */ 104, 104, 104, 122, 75, 370, 75, 75, 75, 122,
+ /* 1250 */ 370, 370, 370, 370, 370, 370, 370, 95, 116, 104,
+ /* 1260 */ 104, 104, 122, 75, 370, 75, 75, 75, 122, 370,
+ /* 1270 */ 370, 370, 370, 370, 370, 370, 96, 116, 104, 104,
+ /* 1280 */ 104, 122, 75, 370, 75, 75, 75, 122, 370, 370,
+ /* 1290 */ 370, 370, 370, 370, 370, 97, 116, 104, 104, 104,
+ /* 1300 */ 122, 75, 370, 75, 75, 75, 122, 370, 370, 370,
+ /* 1310 */ 370, 370, 370, 370, 98, 116, 104, 104, 104, 122,
+ /* 1320 */ 75, 370, 75, 75, 75, 122, 370, 370, 370, 370,
+ /* 1330 */ 370, 370, 370, 99, 116, 104, 104, 104, 122, 75,
+ /* 1340 */ 370, 75, 75, 75, 122, 370, 370, 370, 370, 370,
+ /* 1350 */ 370, 370, 100, 116, 104, 104, 104, 122, 75, 370,
+ /* 1360 */ 75, 75, 75, 122, 370, 370, 370, 370, 370, 370,
+ /* 1370 */ 370, 101, 116, 104, 104, 104, 122, 75, 370, 75,
+ /* 1380 */ 75, 75, 122, 370, 370, 370, 370, 370, 370, 370,
+ /* 1390 */ 102, 116, 104, 104, 104, 122, 75, 370, 75, 75,
+ /* 1400 */ 75, 122, 370, 370, 370, 370, 370, 370, 370, 105,
+ /* 1410 */ 116, 104, 104, 104, 122, 75, 370, 75, 75, 75,
+ /* 1420 */ 122, 370, 370, 370, 370, 370, 370, 370, 107, 116,
+ /* 1430 */ 104, 104, 104, 122, 75, 370, 75, 75, 75, 122,
+ /* 1440 */ 370, 370, 370, 370, 370, 370, 370, 109, 116, 104,
+ /* 1450 */ 104, 104, 122, 75, 370, 75, 75, 75, 122, 370,
+ /* 1460 */ 370, 370, 370, 370, 370, 370, 370, 117, 104, 104,
+ /* 1470 */ 104, 122, 75, 370, 75, 75, 75, 122, 370, 370,
+ /* 1480 */ 370, 370, 370, 370, 370, 370, 119, 104, 104, 104,
+ /* 1490 */ 122, 75, 370, 75, 75, 75, 122, 370, 370, 370,
+ /* 1500 */ 237, 75, 370, 370, 122, 123, 104, 104, 104, 122,
+ /* 1510 */ 75, 370, 370, 75, 75, 293, 293, 122, 75, 370,
+ /* 1520 */ 75, 75, 75, 122, 370, 370, 370, 370, 370, 370,
+ /* 1530 */ 370, 370, 370, 106, 106, 106, 122, 75, 370, 75,
+ /* 1540 */ 75, 75, 122, 370, 370, 370, 370, 370, 370, 370,
+ /* 1550 */ 370, 370, 108, 108, 108, 122, 75, 370, 75, 75,
+ /* 1560 */ 75, 122, 370, 370, 370, 370, 370, 370, 370, 370,
+ /* 1570 */ 370, 370, 285, 285, 122, 75, 370, 75, 75, 75,
+ /* 1580 */ 122, 370, 370, 370, 370, 75, 370, 370, 122, 370,
+ /* 1590 */ 370, 284, 284, 122, 75, 370, 370, 75, 75, 296,
+ /* 1600 */ 296, 122, 75, 370, 75, 75, 75, 122, 370, 370,
+ /* 1610 */ 370, 370, 370, 370, 370, 370, 370, 370, 295, 295,
+ /* 1620 */ 122, 75, 370, 75, 75, 75, 122, 370, 370, 370,
+ /* 1630 */ 370, 370, 370, 370, 370, 370, 370, 294, 294, 122,
+ /* 1640 */ 75, 370, 75, 75, 75, 122, 370, 370, 370, 370,
+ /* 1650 */ 370, 370, 370, 370, 370, 370, 293, 293, 122, 75,
+ /* 1660 */ 370, 75, 75, 75, 122, 370, 370, 370, 370, 75,
+ /* 1670 */ 370, 370, 122, 370, 370, 292, 292, 122, 75, 370,
+ /* 1680 */ 370, 75, 75, 291, 291, 122, 75, 370, 75, 75,
+ /* 1690 */ 75, 122, 370, 370, 370, 370, 370, 370, 370, 370,
+ /* 1700 */ 370, 370, 290, 290, 122, 75, 370, 75, 75, 75,
+ /* 1710 */ 122, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ /* 1720 */ 370, 289, 289, 122, 75, 370, 75, 75, 75, 122,
+ /* 1730 */ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ /* 1740 */ 288, 288, 122, 75, 370, 75, 75, 75, 122, 370,
+ /* 1750 */ 370, 370, 370, 75, 370, 370, 122, 370, 370, 287,
+ /* 1760 */ 287, 122, 75, 370, 370, 75, 75, 286, 286, 122,
+ /* 1770 */ 75, 370, 75, 75, 75, 122, 370, 370, 370, 370,
+ /* 1780 */ 370, 370, 370, 370, 370, 370, 283, 283, 122, 75,
+ /* 1790 */ 370, 370, 75, 75,
+};
+static const YYCODETYPE yy_lookahead[] = {
+ /* 0 */ 1, 2, 107, 108, 109, 12, 7, 8, 68, 10,
+ /* 10 */ 11, 12, 13, 82, 15, 77, 78, 79, 105, 83,
+ /* 20 */ 82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 30 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 103,
+ /* 40 */ 104, 103, 104, 7, 8, 0, 10, 11, 12, 13,
+ /* 50 */ 82, 15, 53, 54, 50, 51, 52, 58, 59, 60,
+ /* 60 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 70 */ 71, 79, 55, 56, 57, 83, 84, 85, 86, 87,
+ /* 80 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 90 */ 98, 99, 100, 78, 0, 103, 104, 82, 53, 107,
+ /* 100 */ 108, 109, 82, 7, 8, 30, 10, 11, 12, 13,
+ /* 110 */ 16, 15, 78, 79, 81, 11, 82, 83, 84, 85,
+ /* 120 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 130 */ 96, 97, 98, 99, 100, 112, 113, 103, 104, 8,
+ /* 140 */ 14, 10, 16, 12, 13, 112, 113, 108, 109, 53,
+ /* 150 */ 54, 101, 102, 82, 58, 59, 60, 61, 62, 63,
+ /* 160 */ 64, 65, 66, 67, 68, 69, 70, 71, 36, 37,
+ /* 170 */ 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ /* 180 */ 48, 49, 3, 4, 53, 54, 55, 53, 54, 58,
+ /* 190 */ 59, 60, 61, 62, 63, 64, 65, 66, 67, 68,
+ /* 200 */ 69, 70, 71, 80, 82, 74, 83, 84, 85, 86,
+ /* 210 */ 87, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ /* 220 */ 97, 98, 99, 100, 34, 35, 103, 104, 8, 82,
+ /* 230 */ 10, 8, 12, 13, 111, 14, 16, 16, 83, 84,
+ /* 240 */ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ /* 250 */ 95, 96, 97, 98, 99, 100, 9, 82, 103, 104,
+ /* 260 */ 105, 106, 8, 16, 10, 82, 12, 13, 59, 60,
+ /* 270 */ 16, 8, 16, 53, 54, 12, 13, 41, 58, 59,
+ /* 280 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ /* 290 */ 70, 71, 72, 8, 71, 10, 73, 12, 13, 9,
+ /* 300 */ 68, 16, 31, 5, 66, 55, 16, 53, 54, 12,
+ /* 310 */ 30, 33, 58, 59, 60, 61, 62, 63, 64, 65,
+ /* 320 */ 66, 67, 68, 69, 70, 71, 72, 29, 72, 66,
+ /* 330 */ 67, 68, 69, 70, 71, 32, 30, 114, 53, 54,
+ /* 340 */ 114, 114, 114, 58, 59, 60, 61, 62, 63, 64,
+ /* 350 */ 65, 66, 67, 68, 69, 70, 71, 83, 84, 85,
+ /* 360 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 370 */ 96, 97, 98, 99, 100, 114, 114, 103, 104, 114,
+ /* 380 */ 114, 114, 114, 114, 114, 111, 16, 114, 114, 114,
+ /* 390 */ 114, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 400 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 410 */ 114, 103, 104, 114, 114, 114, 114, 114, 110, 79,
+ /* 420 */ 114, 114, 114, 83, 84, 85, 86, 87, 88, 89,
+ /* 430 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ /* 440 */ 100, 79, 72, 103, 104, 83, 84, 85, 86, 87,
+ /* 450 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 460 */ 98, 99, 100, 114, 114, 103, 104, 114, 8, 114,
+ /* 470 */ 10, 79, 12, 13, 114, 83, 84, 85, 86, 87,
+ /* 480 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 490 */ 98, 99, 100, 0, 114, 103, 104, 8, 114, 10,
+ /* 500 */ 114, 12, 13, 114, 114, 114, 114, 114, 114, 16,
+ /* 510 */ 114, 114, 114, 53, 54, 114, 114, 114, 58, 59,
+ /* 520 */ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ /* 530 */ 70, 71, 114, 114, 114, 114, 114, 114, 114, 114,
+ /* 540 */ 114, 114, 53, 54, 114, 114, 114, 58, 59, 60,
+ /* 550 */ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ /* 560 */ 71, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 570 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 580 */ 114, 103, 104, 83, 84, 85, 86, 87, 88, 89,
+ /* 590 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ /* 600 */ 100, 114, 114, 103, 104, 83, 84, 85, 86, 87,
+ /* 610 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 620 */ 98, 99, 100, 114, 114, 103, 104, 83, 84, 85,
+ /* 630 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 640 */ 96, 97, 98, 99, 100, 114, 114, 103, 104, 83,
+ /* 650 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 660 */ 94, 95, 96, 97, 98, 99, 100, 114, 114, 103,
+ /* 670 */ 104, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 680 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 690 */ 114, 103, 104, 83, 84, 85, 86, 87, 88, 89,
+ /* 700 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ /* 710 */ 100, 114, 114, 103, 104, 83, 84, 85, 86, 87,
+ /* 720 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 730 */ 98, 99, 100, 114, 114, 103, 104, 83, 84, 85,
+ /* 740 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 750 */ 96, 97, 98, 99, 100, 114, 114, 103, 104, 83,
+ /* 760 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 770 */ 94, 95, 96, 97, 98, 99, 100, 114, 114, 103,
+ /* 780 */ 104, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 790 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 800 */ 114, 103, 104, 83, 84, 85, 86, 87, 88, 89,
+ /* 810 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ /* 820 */ 100, 114, 114, 103, 104, 83, 84, 85, 86, 87,
+ /* 830 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 840 */ 98, 99, 100, 114, 114, 103, 104, 83, 84, 85,
+ /* 850 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 860 */ 96, 97, 98, 99, 100, 114, 114, 103, 104, 83,
+ /* 870 */ 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
+ /* 880 */ 94, 95, 96, 97, 98, 99, 100, 114, 114, 103,
+ /* 890 */ 104, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+ /* 900 */ 92, 93, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 910 */ 114, 103, 104, 83, 84, 85, 86, 87, 88, 89,
+ /* 920 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ /* 930 */ 100, 114, 114, 103, 104, 83, 84, 85, 86, 87,
+ /* 940 */ 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 950 */ 98, 99, 100, 114, 114, 103, 104, 83, 84, 85,
+ /* 960 */ 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ /* 970 */ 96, 97, 98, 99, 100, 114, 83, 103, 104, 86,
+ /* 980 */ 114, 88, 89, 90, 91, 92, 93, 94, 95, 96,
+ /* 990 */ 97, 98, 99, 100, 114, 83, 103, 104, 86, 114,
+ /* 1000 */ 114, 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ /* 1010 */ 98, 99, 100, 114, 83, 103, 104, 86, 114, 114,
+ /* 1020 */ 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
+ /* 1030 */ 99, 100, 114, 83, 103, 104, 86, 114, 114, 114,
+ /* 1040 */ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ /* 1050 */ 100, 114, 83, 103, 104, 86, 114, 114, 114, 114,
+ /* 1060 */ 91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
+ /* 1070 */ 114, 114, 103, 104, 114, 114, 114, 114, 17, 18,
+ /* 1080 */ 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
+ /* 1090 */ 83, 114, 114, 86, 114, 114, 114, 114, 114, 92,
+ /* 1100 */ 93, 94, 95, 96, 97, 98, 99, 100, 114, 114,
+ /* 1110 */ 103, 104, 83, 114, 114, 86, 114, 114, 114, 114,
+ /* 1120 */ 59, 60, 93, 94, 95, 96, 97, 98, 99, 100,
+ /* 1130 */ 114, 83, 103, 104, 86, 114, 114, 114, 114, 114,
+ /* 1140 */ 114, 93, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 1150 */ 114, 103, 104, 114, 114, 3, 4, 5, 6, 7,
+ /* 1160 */ 8, 9, 10, 11, 12, 13, 0, 15, 114, 3,
+ /* 1170 */ 4, 5, 6, 7, 8, 114, 10, 11, 12, 13,
+ /* 1180 */ 114, 15, 114, 83, 114, 114, 86, 114, 114, 114,
+ /* 1190 */ 114, 114, 114, 114, 94, 95, 96, 97, 98, 99,
+ /* 1200 */ 100, 114, 114, 103, 104, 83, 114, 114, 86, 114,
+ /* 1210 */ 114, 114, 114, 114, 114, 114, 94, 95, 96, 97,
+ /* 1220 */ 98, 99, 100, 114, 114, 103, 104, 83, 114, 114,
+ /* 1230 */ 86, 114, 114, 114, 114, 114, 114, 114, 94, 95,
+ /* 1240 */ 96, 97, 98, 99, 100, 114, 83, 103, 104, 86,
+ /* 1250 */ 114, 114, 114, 114, 114, 114, 114, 94, 95, 96,
+ /* 1260 */ 97, 98, 99, 100, 114, 83, 103, 104, 86, 114,
+ /* 1270 */ 114, 114, 114, 114, 114, 114, 94, 95, 96, 97,
+ /* 1280 */ 98, 99, 100, 114, 83, 103, 104, 86, 114, 114,
+ /* 1290 */ 114, 114, 114, 114, 114, 94, 95, 96, 97, 98,
+ /* 1300 */ 99, 100, 114, 83, 103, 104, 86, 114, 114, 114,
+ /* 1310 */ 114, 114, 114, 114, 94, 95, 96, 97, 98, 99,
+ /* 1320 */ 100, 114, 83, 103, 104, 86, 114, 114, 114, 114,
+ /* 1330 */ 114, 114, 114, 94, 95, 96, 97, 98, 99, 100,
+ /* 1340 */ 114, 83, 103, 104, 86, 114, 114, 114, 114, 114,
+ /* 1350 */ 114, 114, 94, 95, 96, 97, 98, 99, 100, 114,
+ /* 1360 */ 83, 103, 104, 86, 114, 114, 114, 114, 114, 114,
+ /* 1370 */ 114, 94, 95, 96, 97, 98, 99, 100, 114, 83,
+ /* 1380 */ 103, 104, 86, 114, 114, 114, 114, 114, 114, 114,
+ /* 1390 */ 94, 95, 96, 97, 98, 99, 100, 114, 83, 103,
+ /* 1400 */ 104, 86, 114, 114, 114, 114, 114, 114, 114, 94,
+ /* 1410 */ 95, 96, 97, 98, 99, 100, 114, 83, 103, 104,
+ /* 1420 */ 86, 114, 114, 114, 114, 114, 114, 114, 94, 95,
+ /* 1430 */ 96, 97, 98, 99, 100, 114, 83, 103, 104, 86,
+ /* 1440 */ 114, 114, 114, 114, 114, 114, 114, 94, 95, 96,
+ /* 1450 */ 97, 98, 99, 100, 114, 83, 103, 104, 86, 114,
+ /* 1460 */ 114, 114, 114, 114, 114, 114, 114, 95, 96, 97,
+ /* 1470 */ 98, 99, 100, 114, 83, 103, 104, 86, 114, 114,
+ /* 1480 */ 114, 114, 114, 114, 114, 114, 95, 96, 97, 98,
+ /* 1490 */ 99, 100, 114, 83, 103, 104, 86, 114, 114, 114,
+ /* 1500 */ 82, 83, 114, 114, 86, 95, 96, 97, 98, 99,
+ /* 1510 */ 100, 114, 114, 103, 104, 97, 98, 99, 100, 114,
+ /* 1520 */ 83, 103, 104, 86, 114, 114, 114, 114, 114, 114,
+ /* 1530 */ 114, 114, 114, 96, 97, 98, 99, 100, 114, 83,
+ /* 1540 */ 103, 104, 86, 114, 114, 114, 114, 114, 114, 114,
+ /* 1550 */ 114, 114, 96, 97, 98, 99, 100, 114, 83, 103,
+ /* 1560 */ 104, 86, 114, 114, 114, 114, 114, 114, 114, 114,
+ /* 1570 */ 114, 114, 97, 98, 99, 100, 114, 83, 103, 104,
+ /* 1580 */ 86, 114, 114, 114, 114, 83, 114, 114, 86, 114,
+ /* 1590 */ 114, 97, 98, 99, 100, 114, 114, 103, 104, 97,
+ /* 1600 */ 98, 99, 100, 114, 83, 103, 104, 86, 114, 114,
+ /* 1610 */ 114, 114, 114, 114, 114, 114, 114, 114, 97, 98,
+ /* 1620 */ 99, 100, 114, 83, 103, 104, 86, 114, 114, 114,
+ /* 1630 */ 114, 114, 114, 114, 114, 114, 114, 97, 98, 99,
+ /* 1640 */ 100, 114, 83, 103, 104, 86, 114, 114, 114, 114,
+ /* 1650 */ 114, 114, 114, 114, 114, 114, 97, 98, 99, 100,
+ /* 1660 */ 114, 83, 103, 104, 86, 114, 114, 114, 114, 83,
+ /* 1670 */ 114, 114, 86, 114, 114, 97, 98, 99, 100, 114,
+ /* 1680 */ 114, 103, 104, 97, 98, 99, 100, 114, 83, 103,
+ /* 1690 */ 104, 86, 114, 114, 114, 114, 114, 114, 114, 114,
+ /* 1700 */ 114, 114, 97, 98, 99, 100, 114, 83, 103, 104,
+ /* 1710 */ 86, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+ /* 1720 */ 114, 97, 98, 99, 100, 114, 83, 103, 104, 86,
+ /* 1730 */ 114, 114, 114, 114, 114, 114, 114, 114, 114, 114,
+ /* 1740 */ 97, 98, 99, 100, 114, 83, 103, 104, 86, 114,
+ /* 1750 */ 114, 114, 114, 83, 114, 114, 86, 114, 114, 97,
+ /* 1760 */ 98, 99, 100, 114, 114, 103, 104, 97, 98, 99,
+ /* 1770 */ 100, 114, 83, 103, 104, 86, 114, 114, 114, 114,
+ /* 1780 */ 114, 114, 114, 114, 114, 114, 97, 98, 99, 100,
+ /* 1790 */ 114, 114, 103, 104,
+};
+#define YY_SHIFT_USE_DFLT (1794)
+#define YY_SHIFT_COUNT (144)
+#define YY_SHIFT_MIN (-60)
+#define YY_SHIFT_MAX (1166)
+static const short yy_shift_ofst[] = {
+ /* 0 */ -1, 460, 96, 131, 285, 131, 489, 489, 489, 489,
+ /* 10 */ 220, 254, 489, 489, 489, 489, 489, 489, 489, 489,
+ /* 20 */ 489, 489, 489, 489, 489, 489, 489, 489, 489, 489,
+ /* 30 */ 489, 489, 489, 489, 489, 489, 489, 489, 489, 489,
+ /* 40 */ 489, 489, 489, 489, 489, 489, 489, 489, 489, 489,
+ /* 50 */ 489, 489, 489, 489, 96, 489, 489, 489, 489, 489,
+ /* 60 */ 489, 489, 489, 489, 489, 489, 489, 489, 489, 489,
+ /* 70 */ 489, 263, -7, -60, 36, 223, -7, -60, 1152, 1166,
+ /* 80 */ 36, 36, 36, 36, 36, 36, 36, 256, 132, 132,
+ /* 90 */ 132, 1061, 4, 4, 4, 4, 4, 4, 4, 4,
+ /* 100 */ 4, 4, 4, 4, 17, 4, 17, 4, 17, 4,
+ /* 110 */ 45, 94, 493, 179, 247, 126, 134, 134, 290, 134,
+ /* 120 */ 190, 370, 209, 134, 190, 179, 298, 221, 75, 104,
+ /* 130 */ 232, 236, 238, 250, 271, 297, 280, 278, 303, 271,
+ /* 140 */ 278, 303, 271, 306, 104,
+};
+#define YY_REDUCE_USE_DFLT (-106)
+#define YY_REDUCE_COUNT (87)
+#define YY_REDUCE_MIN (-105)
+#define YY_REDUCE_MAX (1689)
+static const short yy_reduce_ofst[] = {
+ /* 0 */ -62, -8, 34, 123, 155, 274, 308, 340, 362, 392,
+ /* 10 */ 478, 500, 522, 544, 566, 588, 610, 632, 654, 676,
+ /* 20 */ 698, 720, 742, 764, 786, 808, 830, 852, 874, 893,
+ /* 30 */ 912, 931, 950, 969, 1007, 1029, 1048, 1100, 1122, 1144,
+ /* 40 */ 1163, 1182, 1201, 1220, 1239, 1258, 1277, 1296, 1315, 1334,
+ /* 50 */ 1353, 1372, 1391, 1410, 1418, 1437, 1456, 1475, 1494, 1502,
+ /* 60 */ 1521, 1540, 1559, 1578, 1586, 1605, 1624, 1643, 1662, 1670,
+ /* 70 */ 1689, -64, 33, -105, 15, 50, 23, 39, -69, -69,
+ /* 80 */ -32, 20, 71, 122, 147, 175, 183, -87,
+};
+static const YYACTIONTYPE yy_default[] = {
+ /* 0 */ 504, 437, 504, 444, 504, 446, 441, 504, 504, 504,
+ /* 10 */ 504, 504, 504, 504, 504, 504, 504, 504, 504, 504,
+ /* 20 */ 504, 504, 504, 504, 504, 504, 504, 504, 504, 504,
+ /* 30 */ 504, 504, 504, 504, 504, 504, 504, 504, 504, 504,
+ /* 40 */ 504, 504, 504, 504, 504, 504, 504, 504, 504, 504,
+ /* 50 */ 504, 504, 504, 504, 504, 504, 504, 504, 504, 504,
+ /* 60 */ 504, 504, 504, 504, 504, 504, 504, 504, 504, 504,
+ /* 70 */ 504, 504, 501, 437, 504, 477, 504, 504, 504, 504,
+ /* 80 */ 504, 504, 504, 504, 504, 504, 504, 504, 469, 399,
+ /* 90 */ 398, 475, 413, 412, 411, 410, 409, 408, 407, 406,
+ /* 100 */ 405, 404, 403, 470, 472, 402, 418, 401, 417, 400,
+ /* 110 */ 504, 504, 504, 392, 504, 504, 471, 416, 504, 415,
+ /* 120 */ 468, 504, 475, 414, 397, 464, 463, 504, 486, 482,
+ /* 130 */ 504, 504, 504, 503, 394, 504, 504, 467, 466, 465,
+ /* 140 */ 396, 395, 393, 504, 504,
+};
+/********** End of lemon-generated parsing tables *****************************/
+
+/* The next table maps tokens (terminal symbols) into fallback tokens.
+** If a construct like the following:
+**
+** %fallback ID X Y Z.
+**
+** appears in the grammar, then ID becomes a fallback token for X, Y,
+** and Z. Whenever one of the tokens X, Y, or Z is input to the parser
+** but it does not parse, the type of the token is changed to ID and
+** the parse is retried before an error is thrown.
+**
+** This feature can be used, for example, to cause some keywords in a language
+** to revert to identifiers if they keyword does not apply in the context where
+** it appears.
+*/
+#ifdef YYFALLBACK
+static const YYCODETYPE yyFallback[] = {
+};
+#endif /* YYFALLBACK */
+
+/* The following structure represents a single element of the
+** parser's stack. Information stored includes:
+**
+** + The state number for the parser at this level of the stack.
+**
+** + The value of the token stored at this level of the stack.
+** (In other words, the "major" token.)
+**
+** + The semantic value stored at this level of the stack. This is
+** the information used by the action routines in the grammar.
+** It is sometimes called the "minor" token.
+**
+** After the "shift" half of a SHIFTREDUCE action, the stateno field
+** actually contains the reduce action for the second half of the
+** SHIFTREDUCE.
+*/
+struct yyStackEntry {
+ YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */
+ YYCODETYPE major; /* The major token value. This is the code
+ ** number for the token at this stack level */
+ YYMINORTYPE minor; /* The user-supplied minor token value. This
+ ** is the value of the token */
+};
+typedef struct yyStackEntry yyStackEntry;
+
+/* The state of the parser is completely contained in an instance of
+** the following structure */
+struct yyParser {
+ yyStackEntry *yytos; /* Pointer to top element of the stack */
+#ifdef YYTRACKMAXSTACKDEPTH
+ int yyhwm; /* High-water mark of the stack */
+#endif
+#ifndef YYNOERRORRECOVERY
+ int yyerrcnt; /* Shifts left before out of the error */
+#endif
+ grn_expr_parserARG_SDECL /* A place to hold %extra_argument */
+#if YYSTACKDEPTH<=0
+ int yystksz; /* Current side of the stack */
+ yyStackEntry *yystack; /* The parser's stack */
+ yyStackEntry yystk0; /* First stack entry */
+#else
+ yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */
+#endif
+};
+typedef struct yyParser yyParser;
+
+#ifndef NDEBUG
+#include <stdio.h>
+static FILE *yyTraceFILE = 0;
+static char *yyTracePrompt = 0;
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/*
+** Turn parser tracing on by giving a stream to which to write the trace
+** and a prompt to preface each trace message. Tracing is turned off
+** by making either argument NULL
+**
+** Inputs:
+** <ul>
+** <li> A FILE* to which trace output should be written.
+** If NULL, then tracing is turned off.
+** <li> A prefix string written at the beginning of every
+** line of trace output. If NULL, then tracing is
+** turned off.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void grn_expr_parserTrace(FILE *TraceFILE, char *zTracePrompt){
+ yyTraceFILE = TraceFILE;
+ yyTracePrompt = zTracePrompt;
+ if( yyTraceFILE==0 ) yyTracePrompt = 0;
+ else if( yyTracePrompt==0 ) yyTraceFILE = 0;
+}
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing shifts, the names of all terminals and nonterminals
+** are required. The following table supplies these names */
+static const char *const yyTokenName[] = {
+ "$", "START_OUTPUT_COLUMNS", "START_ADJUSTER", "LOGICAL_AND",
+ "LOGICAL_AND_NOT", "LOGICAL_OR", "NEGATIVE", "QSTRING",
+ "PARENL", "PARENR", "ADJUST", "RELATIVE_OP",
+ "IDENTIFIER", "BRACEL", "BRACER", "EVAL",
+ "COMMA", "ASSIGN", "STAR_ASSIGN", "SLASH_ASSIGN",
+ "MOD_ASSIGN", "PLUS_ASSIGN", "MINUS_ASSIGN", "SHIFTL_ASSIGN",
+ "SHIFTR_ASSIGN", "SHIFTRR_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN",
+ "OR_ASSIGN", "QUESTION", "COLON", "BITWISE_OR",
+ "BITWISE_XOR", "BITWISE_AND", "EQUAL", "NOT_EQUAL",
+ "LESS", "GREATER", "LESS_EQUAL", "GREATER_EQUAL",
+ "IN", "MATCH", "NEAR", "NEAR2",
+ "SIMILAR", "TERM_EXTRACT", "LCP", "PREFIX",
+ "SUFFIX", "REGEXP", "SHIFTL", "SHIFTR",
+ "SHIFTRR", "PLUS", "MINUS", "STAR",
+ "SLASH", "MOD", "DELETE", "INCR",
+ "DECR", "NOT", "BITWISE_NOT", "EXACT",
+ "PARTIAL", "UNSPLIT", "DECIMAL", "HEX_INTEGER",
+ "STRING", "BOOLEAN", "NULL", "BRACKETL",
+ "BRACKETR", "DOT", "NONEXISTENT_COLUMN", "error",
+ "suppress_unused_variable_warning", "input", "query", "expression",
+ "output_columns", "adjuster", "query_element", "primary_expression",
+ "assignment_expression", "conditional_expression", "lefthand_side_expression", "logical_or_expression",
+ "logical_and_expression", "bitwise_or_expression", "bitwise_xor_expression", "bitwise_and_expression",
+ "equality_expression", "relational_expression", "shift_expression", "additive_expression",
+ "multiplicative_expression", "unary_expression", "postfix_expression", "call_expression",
+ "member_expression", "arguments", "member_expression_part", "object_literal",
+ "array_literal", "elision", "element_list", "property_name_and_value_list",
+ "property_name_and_value", "property_name", "argument_list", "output_column",
+ "adjust_expression", "adjust_match_expression",
+};
+#endif /* NDEBUG */
+
+#ifndef NDEBUG
+/* For tracing reduce actions, the names of all rules are required.
+*/
+static const char *const yyRuleName[] = {
+ /* 0 */ "query ::= query query_element",
+ /* 1 */ "query ::= query LOGICAL_AND query_element",
+ /* 2 */ "query ::= query LOGICAL_AND_NOT query_element",
+ /* 3 */ "query ::= query LOGICAL_OR query_element",
+ /* 4 */ "query ::= query NEGATIVE query_element",
+ /* 5 */ "query_element ::= ADJUST query_element",
+ /* 6 */ "query_element ::= RELATIVE_OP query_element",
+ /* 7 */ "query_element ::= IDENTIFIER RELATIVE_OP query_element",
+ /* 8 */ "query_element ::= BRACEL expression BRACER",
+ /* 9 */ "query_element ::= EVAL primary_expression",
+ /* 10 */ "expression ::= expression COMMA assignment_expression",
+ /* 11 */ "assignment_expression ::= lefthand_side_expression ASSIGN assignment_expression",
+ /* 12 */ "assignment_expression ::= lefthand_side_expression STAR_ASSIGN assignment_expression",
+ /* 13 */ "assignment_expression ::= lefthand_side_expression SLASH_ASSIGN assignment_expression",
+ /* 14 */ "assignment_expression ::= lefthand_side_expression MOD_ASSIGN assignment_expression",
+ /* 15 */ "assignment_expression ::= lefthand_side_expression PLUS_ASSIGN assignment_expression",
+ /* 16 */ "assignment_expression ::= lefthand_side_expression MINUS_ASSIGN assignment_expression",
+ /* 17 */ "assignment_expression ::= lefthand_side_expression SHIFTL_ASSIGN assignment_expression",
+ /* 18 */ "assignment_expression ::= lefthand_side_expression SHIFTR_ASSIGN assignment_expression",
+ /* 19 */ "assignment_expression ::= lefthand_side_expression SHIFTRR_ASSIGN assignment_expression",
+ /* 20 */ "assignment_expression ::= lefthand_side_expression AND_ASSIGN assignment_expression",
+ /* 21 */ "assignment_expression ::= lefthand_side_expression XOR_ASSIGN assignment_expression",
+ /* 22 */ "assignment_expression ::= lefthand_side_expression OR_ASSIGN assignment_expression",
+ /* 23 */ "conditional_expression ::= logical_or_expression QUESTION assignment_expression COLON assignment_expression",
+ /* 24 */ "logical_or_expression ::= logical_or_expression LOGICAL_OR logical_and_expression",
+ /* 25 */ "logical_and_expression ::= logical_and_expression LOGICAL_AND bitwise_or_expression",
+ /* 26 */ "logical_and_expression ::= logical_and_expression LOGICAL_AND_NOT bitwise_or_expression",
+ /* 27 */ "bitwise_or_expression ::= bitwise_or_expression BITWISE_OR bitwise_xor_expression",
+ /* 28 */ "bitwise_xor_expression ::= bitwise_xor_expression BITWISE_XOR bitwise_and_expression",
+ /* 29 */ "bitwise_and_expression ::= bitwise_and_expression BITWISE_AND equality_expression",
+ /* 30 */ "equality_expression ::= equality_expression EQUAL relational_expression",
+ /* 31 */ "equality_expression ::= equality_expression NOT_EQUAL relational_expression",
+ /* 32 */ "relational_expression ::= relational_expression LESS shift_expression",
+ /* 33 */ "relational_expression ::= relational_expression GREATER shift_expression",
+ /* 34 */ "relational_expression ::= relational_expression LESS_EQUAL shift_expression",
+ /* 35 */ "relational_expression ::= relational_expression GREATER_EQUAL shift_expression",
+ /* 36 */ "relational_expression ::= relational_expression IN shift_expression",
+ /* 37 */ "relational_expression ::= relational_expression MATCH shift_expression",
+ /* 38 */ "relational_expression ::= relational_expression NEAR shift_expression",
+ /* 39 */ "relational_expression ::= relational_expression NEAR2 shift_expression",
+ /* 40 */ "relational_expression ::= relational_expression SIMILAR shift_expression",
+ /* 41 */ "relational_expression ::= relational_expression TERM_EXTRACT shift_expression",
+ /* 42 */ "relational_expression ::= relational_expression LCP shift_expression",
+ /* 43 */ "relational_expression ::= relational_expression PREFIX shift_expression",
+ /* 44 */ "relational_expression ::= relational_expression SUFFIX shift_expression",
+ /* 45 */ "relational_expression ::= relational_expression REGEXP shift_expression",
+ /* 46 */ "shift_expression ::= shift_expression SHIFTL additive_expression",
+ /* 47 */ "shift_expression ::= shift_expression SHIFTR additive_expression",
+ /* 48 */ "shift_expression ::= shift_expression SHIFTRR additive_expression",
+ /* 49 */ "additive_expression ::= additive_expression PLUS multiplicative_expression",
+ /* 50 */ "additive_expression ::= additive_expression MINUS multiplicative_expression",
+ /* 51 */ "multiplicative_expression ::= multiplicative_expression STAR unary_expression",
+ /* 52 */ "multiplicative_expression ::= multiplicative_expression SLASH unary_expression",
+ /* 53 */ "multiplicative_expression ::= multiplicative_expression MOD unary_expression",
+ /* 54 */ "unary_expression ::= DELETE unary_expression",
+ /* 55 */ "unary_expression ::= INCR unary_expression",
+ /* 56 */ "unary_expression ::= DECR unary_expression",
+ /* 57 */ "unary_expression ::= PLUS unary_expression",
+ /* 58 */ "unary_expression ::= MINUS unary_expression",
+ /* 59 */ "unary_expression ::= NOT unary_expression",
+ /* 60 */ "unary_expression ::= BITWISE_NOT unary_expression",
+ /* 61 */ "unary_expression ::= ADJUST unary_expression",
+ /* 62 */ "unary_expression ::= EXACT unary_expression",
+ /* 63 */ "unary_expression ::= PARTIAL unary_expression",
+ /* 64 */ "unary_expression ::= UNSPLIT unary_expression",
+ /* 65 */ "postfix_expression ::= lefthand_side_expression INCR",
+ /* 66 */ "postfix_expression ::= lefthand_side_expression DECR",
+ /* 67 */ "call_expression ::= member_expression arguments",
+ /* 68 */ "object_literal ::= BRACEL property_name_and_value_list BRACER",
+ /* 69 */ "property_name_and_value_list ::=",
+ /* 70 */ "property_name_and_value ::= property_name COLON assignment_expression",
+ /* 71 */ "member_expression_part ::= BRACKETL expression BRACKETR",
+ /* 72 */ "arguments ::= PARENL argument_list PARENR",
+ /* 73 */ "argument_list ::=",
+ /* 74 */ "argument_list ::= assignment_expression",
+ /* 75 */ "argument_list ::= argument_list COMMA assignment_expression",
+ /* 76 */ "output_columns ::=",
+ /* 77 */ "output_columns ::= output_column",
+ /* 78 */ "output_columns ::= output_columns COMMA",
+ /* 79 */ "output_columns ::= output_columns COMMA output_column",
+ /* 80 */ "output_column ::= STAR",
+ /* 81 */ "output_column ::= NONEXISTENT_COLUMN",
+ /* 82 */ "output_column ::= assignment_expression",
+ /* 83 */ "adjuster ::= adjuster PLUS adjust_expression",
+ /* 84 */ "adjust_expression ::= adjust_match_expression STAR DECIMAL",
+ /* 85 */ "adjust_match_expression ::= IDENTIFIER MATCH STRING",
+ /* 86 */ "input ::= query",
+ /* 87 */ "input ::= expression",
+ /* 88 */ "input ::= START_OUTPUT_COLUMNS output_columns",
+ /* 89 */ "input ::= START_ADJUSTER adjuster",
+ /* 90 */ "query ::= query_element",
+ /* 91 */ "query_element ::= QSTRING",
+ /* 92 */ "query_element ::= PARENL query PARENR",
+ /* 93 */ "expression ::= assignment_expression",
+ /* 94 */ "assignment_expression ::= conditional_expression",
+ /* 95 */ "conditional_expression ::= logical_or_expression",
+ /* 96 */ "logical_or_expression ::= logical_and_expression",
+ /* 97 */ "logical_and_expression ::= bitwise_or_expression",
+ /* 98 */ "bitwise_or_expression ::= bitwise_xor_expression",
+ /* 99 */ "bitwise_xor_expression ::= bitwise_and_expression",
+ /* 100 */ "bitwise_and_expression ::= equality_expression",
+ /* 101 */ "equality_expression ::= relational_expression",
+ /* 102 */ "relational_expression ::= shift_expression",
+ /* 103 */ "shift_expression ::= additive_expression",
+ /* 104 */ "additive_expression ::= multiplicative_expression",
+ /* 105 */ "multiplicative_expression ::= unary_expression",
+ /* 106 */ "unary_expression ::= postfix_expression",
+ /* 107 */ "postfix_expression ::= lefthand_side_expression",
+ /* 108 */ "lefthand_side_expression ::= call_expression",
+ /* 109 */ "lefthand_side_expression ::= member_expression",
+ /* 110 */ "member_expression ::= primary_expression",
+ /* 111 */ "member_expression ::= member_expression member_expression_part",
+ /* 112 */ "primary_expression ::= object_literal",
+ /* 113 */ "primary_expression ::= PARENL expression PARENR",
+ /* 114 */ "primary_expression ::= IDENTIFIER",
+ /* 115 */ "primary_expression ::= array_literal",
+ /* 116 */ "primary_expression ::= DECIMAL",
+ /* 117 */ "primary_expression ::= HEX_INTEGER",
+ /* 118 */ "primary_expression ::= STRING",
+ /* 119 */ "primary_expression ::= BOOLEAN",
+ /* 120 */ "primary_expression ::= NULL",
+ /* 121 */ "array_literal ::= BRACKETL elision BRACKETR",
+ /* 122 */ "array_literal ::= BRACKETL element_list elision BRACKETR",
+ /* 123 */ "array_literal ::= BRACKETL element_list BRACKETR",
+ /* 124 */ "elision ::= COMMA",
+ /* 125 */ "elision ::= elision COMMA",
+ /* 126 */ "element_list ::= assignment_expression",
+ /* 127 */ "element_list ::= elision assignment_expression",
+ /* 128 */ "element_list ::= element_list elision assignment_expression",
+ /* 129 */ "property_name_and_value_list ::= property_name_and_value",
+ /* 130 */ "property_name_and_value_list ::= property_name_and_value_list COMMA property_name_and_value",
+ /* 131 */ "property_name ::= STRING",
+ /* 132 */ "member_expression_part ::= DOT IDENTIFIER",
+ /* 133 */ "adjuster ::=",
+ /* 134 */ "adjuster ::= adjust_expression",
+ /* 135 */ "adjust_expression ::= adjust_match_expression",
+};
+#endif /* NDEBUG */
+
+
+#if YYSTACKDEPTH<=0
+/*
+** Try to increase the size of the parser stack. Return the number
+** of errors. Return 0 on success.
+*/
+static int yyGrowStack(yyParser *p){
+ int newSize;
+ int idx;
+ yyStackEntry *pNew;
+
+ newSize = p->yystksz*2 + 100;
+ idx = p->yytos ? (int)(p->yytos - p->yystack) : 0;
+ if( p->yystack==&p->yystk0 ){
+ pNew = malloc(newSize*sizeof(pNew[0]));
+ if( pNew ) pNew[0] = p->yystk0;
+ }else{
+ pNew = realloc(p->yystack, newSize*sizeof(pNew[0]));
+ }
+ if( pNew ){
+ p->yystack = pNew;
+ p->yytos = &p->yystack[idx];
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n",
+ yyTracePrompt, p->yystksz, newSize);
+ }
+#endif
+ p->yystksz = newSize;
+ }
+ return pNew==0;
+}
+#endif
+
+/* Datatype of the argument to the memory allocated passed as the
+** second argument to grn_expr_parserAlloc() below. This can be changed by
+** putting an appropriate #define in the %include section of the input
+** grammar.
+*/
+#ifndef YYMALLOCARGTYPE
+# define YYMALLOCARGTYPE size_t
+#endif
+
+/* Initialize a new parser that has already been allocated.
+*/
+void grn_expr_parserInit(void *yypParser){
+ yyParser *pParser = (yyParser*)yypParser;
+#ifdef YYTRACKMAXSTACKDEPTH
+ pParser->yyhwm = 0;
+#endif
+#if YYSTACKDEPTH<=0
+ pParser->yytos = NULL;
+ pParser->yystack = NULL;
+ pParser->yystksz = 0;
+ if( yyGrowStack(pParser) ){
+ pParser->yystack = &pParser->yystk0;
+ pParser->yystksz = 1;
+ }
+#endif
+#ifndef YYNOERRORRECOVERY
+ pParser->yyerrcnt = -1;
+#endif
+ pParser->yytos = pParser->yystack;
+ pParser->yystack[0].stateno = 0;
+ pParser->yystack[0].major = 0;
+}
+
+#ifndef grn_expr_parser_ENGINEALWAYSONSTACK
+/*
+** This function allocates a new parser.
+** The only argument is a pointer to a function which works like
+** malloc.
+**
+** Inputs:
+** A pointer to the function used to allocate memory.
+**
+** Outputs:
+** A pointer to a parser. This pointer is used in subsequent calls
+** to grn_expr_parser and grn_expr_parserFree.
+*/
+void *grn_expr_parserAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){
+ yyParser *pParser;
+ pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
+ if( pParser ) grn_expr_parserInit(pParser);
+ return pParser;
+}
+#endif /* grn_expr_parser_ENGINEALWAYSONSTACK */
+
+
+/* The following function deletes the "minor type" or semantic value
+** associated with a symbol. The symbol can be either a terminal
+** or nonterminal. "yymajor" is the symbol code, and "yypminor" is
+** a pointer to the value to be deleted. The code used to do the
+** deletions is derived from the %destructor and/or %token_destructor
+** directives of the input grammar.
+*/
+static void yy_destructor(
+ yyParser *yypParser, /* The parser */
+ YYCODETYPE yymajor, /* Type code for object to destroy */
+ YYMINORTYPE *yypminor /* The object to be destroyed */
+){
+ grn_expr_parserARG_FETCH;
+ switch( yymajor ){
+ /* Here is inserted the actions which take place when a
+ ** terminal or non-terminal is destroyed. This can happen
+ ** when the symbol is popped from the stack during a
+ ** reduce or during error processing or when a parser is
+ ** being destroyed before it is finished parsing.
+ **
+ ** Note: during a reduce, the only symbols destroyed are those
+ ** which appear on the RHS of the rule, but which are *not* used
+ ** inside the C code.
+ */
+/********* Begin destructor definitions ***************************************/
+ case 76: /* suppress_unused_variable_warning */
+{
+#line 14 "grn_ecmascript.lemon"
+
+ (void)efsi;
+
+#line 1006 "grn_ecmascript.c"
+}
+ break;
+/********* End destructor definitions *****************************************/
+ default: break; /* If no destructor action specified: do nothing */
+ }
+}
+
+/*
+** Pop the parser's stack once.
+**
+** If there is a destructor routine associated with the token which
+** is popped from the stack, then call it.
+*/
+static void yy_pop_parser_stack(yyParser *pParser){
+ yyStackEntry *yytos;
+ assert( pParser->yytos!=0 );
+ assert( pParser->yytos > pParser->yystack );
+ yytos = pParser->yytos--;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sPopping %s\n",
+ yyTracePrompt,
+ yyTokenName[yytos->major]);
+ }
+#endif
+ yy_destructor(pParser, yytos->major, &yytos->minor);
+}
+
+/*
+** Clear all secondary memory allocations from the parser
+*/
+void grn_expr_parserFinalize(void *p){
+ yyParser *pParser = (yyParser*)p;
+ while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
+#if YYSTACKDEPTH<=0
+ if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
+#endif
+}
+
+#ifndef grn_expr_parser_ENGINEALWAYSONSTACK
+/*
+** Deallocate and destroy a parser. Destructors are called for
+** all stack elements before shutting the parser down.
+**
+** If the YYPARSEFREENEVERNULL macro exists (for example because it
+** is defined in a %include section of the input grammar) then it is
+** assumed that the input pointer is never NULL.
+*/
+void grn_expr_parserFree(
+ void *p, /* The parser to be deleted */
+ void (*freeProc)(void*) /* Function used to reclaim memory */
+){
+#ifndef YYPARSEFREENEVERNULL
+ if( p==0 ) return;
+#endif
+ grn_expr_parserFinalize(p);
+ (*freeProc)(p);
+}
+#endif /* grn_expr_parser_ENGINEALWAYSONSTACK */
+
+/*
+** Return the peak depth of the stack for a parser.
+*/
+#ifdef YYTRACKMAXSTACKDEPTH
+int grn_expr_parserStackPeak(void *p){
+ yyParser *pParser = (yyParser*)p;
+ return pParser->yyhwm;
+}
+#endif
+
+/*
+** Find the appropriate action for a parser given the terminal
+** look-ahead token iLookAhead.
+*/
+static unsigned int yy_find_shift_action(
+ yyParser *pParser, /* The parser */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+ int stateno = pParser->yytos->stateno;
+
+ if( stateno>=YY_MIN_REDUCE ) return stateno;
+ assert( stateno <= YY_SHIFT_COUNT );
+ do{
+ i = yy_shift_ofst[stateno];
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+#ifdef YYFALLBACK
+ YYCODETYPE iFallback; /* Fallback token */
+ if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
+ && (iFallback = yyFallback[iLookAhead])!=0 ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]);
+ }
+#endif
+ assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */
+ iLookAhead = iFallback;
+ continue;
+ }
+#endif
+#ifdef YYWILDCARD
+ {
+ int j = i - iLookAhead + YYWILDCARD;
+ if(
+#if YY_SHIFT_MIN+YYWILDCARD<0
+ j>=0 &&
+#endif
+#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
+ j<YY_ACTTAB_COUNT &&
+#endif
+ yy_lookahead[j]==YYWILDCARD && iLookAhead>0
+ ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
+ yyTracePrompt, yyTokenName[iLookAhead],
+ yyTokenName[YYWILDCARD]);
+ }
+#endif /* NDEBUG */
+ return yy_action[j];
+ }
+ }
+#endif /* YYWILDCARD */
+ return yy_default[stateno];
+ }else{
+ return yy_action[i];
+ }
+ }while(1);
+}
+
+/*
+** Find the appropriate action for a parser given the non-terminal
+** look-ahead token iLookAhead.
+*/
+static int yy_find_reduce_action(
+ int stateno, /* Current state number */
+ YYCODETYPE iLookAhead /* The look-ahead token */
+){
+ int i;
+#ifdef YYERRORSYMBOL
+ if( stateno>YY_REDUCE_COUNT ){
+ return yy_default[stateno];
+ }
+#else
+ assert( stateno<=YY_REDUCE_COUNT );
+#endif
+ i = yy_reduce_ofst[stateno];
+ assert( i!=YY_REDUCE_USE_DFLT );
+ assert( iLookAhead!=YYNOCODE );
+ i += iLookAhead;
+#ifdef YYERRORSYMBOL
+ if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){
+ return yy_default[stateno];
+ }
+#else
+ assert( i>=0 && i<YY_ACTTAB_COUNT );
+ assert( yy_lookahead[i]==iLookAhead );
+#endif
+ return yy_action[i];
+}
+
+/*
+** The following routine is called if the stack overflows.
+*/
+static void yyStackOverflow(yyParser *yypParser){
+ grn_expr_parserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will execute if the parser
+ ** stack every overflows */
+/******** Begin %stack_overflow code ******************************************/
+/******** End %stack_overflow code ********************************************/
+ grn_expr_parserARG_STORE; /* Suppress warning about unused %extra_argument var */
+}
+
+/*
+** Print tracing information for a SHIFT action
+*/
+#ifndef NDEBUG
+static void yyTraceShift(yyParser *yypParser, int yyNewState){
+ if( yyTraceFILE ){
+ if( yyNewState<YYNSTATE ){
+ fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n",
+ yyTracePrompt,yyTokenName[yypParser->yytos->major],
+ yyNewState);
+ }else{
+ fprintf(yyTraceFILE,"%sShift '%s'\n",
+ yyTracePrompt,yyTokenName[yypParser->yytos->major]);
+ }
+ }
+}
+#else
+# define yyTraceShift(X,Y)
+#endif
+
+/*
+** Perform a shift action.
+*/
+static void yy_shift(
+ yyParser *yypParser, /* The parser to be shifted */
+ int yyNewState, /* The new state to shift in */
+ int yyMajor, /* The major token to shift in */
+ grn_expr_parserTOKENTYPE yyMinor /* The minor token to shift in */
+){
+ yyStackEntry *yytos;
+ yypParser->yytos++;
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+ yypParser->yyhwm++;
+ assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) );
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){
+ yypParser->yytos--;
+ yyStackOverflow(yypParser);
+ return;
+ }
+#else
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){
+ if( yyGrowStack(yypParser) ){
+ yypParser->yytos--;
+ yyStackOverflow(yypParser);
+ return;
+ }
+ }
+#endif
+ if( yyNewState > YY_MAX_SHIFT ){
+ yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+ }
+ yytos = yypParser->yytos;
+ yytos->stateno = (YYACTIONTYPE)yyNewState;
+ yytos->major = (YYCODETYPE)yyMajor;
+ yytos->minor.yy0 = yyMinor;
+ yyTraceShift(yypParser, yyNewState);
+}
+
+/* The following table contains information about every rule that
+** is used during the reduce.
+*/
+static const struct {
+ YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
+ unsigned char nrhs; /* Number of right-hand side symbols in the rule */
+} yyRuleInfo[] = {
+ { 78, 2 },
+ { 78, 3 },
+ { 78, 3 },
+ { 78, 3 },
+ { 78, 3 },
+ { 82, 2 },
+ { 82, 2 },
+ { 82, 3 },
+ { 82, 3 },
+ { 82, 2 },
+ { 79, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 84, 3 },
+ { 85, 5 },
+ { 87, 3 },
+ { 88, 3 },
+ { 88, 3 },
+ { 89, 3 },
+ { 90, 3 },
+ { 91, 3 },
+ { 92, 3 },
+ { 92, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 93, 3 },
+ { 94, 3 },
+ { 94, 3 },
+ { 94, 3 },
+ { 95, 3 },
+ { 95, 3 },
+ { 96, 3 },
+ { 96, 3 },
+ { 96, 3 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 97, 2 },
+ { 98, 2 },
+ { 98, 2 },
+ { 99, 2 },
+ { 103, 3 },
+ { 107, 0 },
+ { 108, 3 },
+ { 102, 3 },
+ { 101, 3 },
+ { 110, 0 },
+ { 110, 1 },
+ { 110, 3 },
+ { 80, 0 },
+ { 80, 1 },
+ { 80, 2 },
+ { 80, 3 },
+ { 111, 1 },
+ { 111, 1 },
+ { 111, 1 },
+ { 81, 3 },
+ { 112, 3 },
+ { 113, 3 },
+ { 77, 1 },
+ { 77, 1 },
+ { 77, 2 },
+ { 77, 2 },
+ { 78, 1 },
+ { 82, 1 },
+ { 82, 3 },
+ { 79, 1 },
+ { 84, 1 },
+ { 85, 1 },
+ { 87, 1 },
+ { 88, 1 },
+ { 89, 1 },
+ { 90, 1 },
+ { 91, 1 },
+ { 92, 1 },
+ { 93, 1 },
+ { 94, 1 },
+ { 95, 1 },
+ { 96, 1 },
+ { 97, 1 },
+ { 98, 1 },
+ { 86, 1 },
+ { 86, 1 },
+ { 100, 1 },
+ { 100, 2 },
+ { 83, 1 },
+ { 83, 3 },
+ { 83, 1 },
+ { 83, 1 },
+ { 83, 1 },
+ { 83, 1 },
+ { 83, 1 },
+ { 83, 1 },
+ { 83, 1 },
+ { 104, 3 },
+ { 104, 4 },
+ { 104, 3 },
+ { 105, 1 },
+ { 105, 2 },
+ { 106, 1 },
+ { 106, 2 },
+ { 106, 3 },
+ { 107, 1 },
+ { 107, 3 },
+ { 109, 1 },
+ { 102, 2 },
+ { 81, 0 },
+ { 81, 1 },
+ { 112, 1 },
+};
+
+static void yy_accept(yyParser*); /* Forward Declaration */
+
+/*
+** Perform a reduce action and the shift that must immediately
+** follow the reduce.
+*/
+static void yy_reduce(
+ yyParser *yypParser, /* The parser */
+ unsigned int yyruleno /* Number of the rule by which to reduce */
+){
+ int yygoto; /* The next state */
+ int yyact; /* The next action */
+ yyStackEntry *yymsp; /* The top of the parser's stack */
+ int yysize; /* Amount to pop the stack */
+ grn_expr_parserARG_FETCH;
+ yymsp = yypParser->yytos;
+#ifndef NDEBUG
+ if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt,
+ yyRuleName[yyruleno], yymsp[-yysize].stateno);
+ }
+#endif /* NDEBUG */
+
+ /* Check that the stack is large enough to grow by a single entry
+ ** if the RHS of the rule is empty. This ensures that there is room
+ ** enough on the stack to push the LHS value */
+ if( yyRuleInfo[yyruleno].nrhs==0 ){
+#ifdef YYTRACKMAXSTACKDEPTH
+ if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
+ yypParser->yyhwm++;
+ assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack));
+ }
+#endif
+#if YYSTACKDEPTH>0
+ if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+#else
+ if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){
+ if( yyGrowStack(yypParser) ){
+ yyStackOverflow(yypParser);
+ return;
+ }
+ yymsp = yypParser->yytos;
+ }
+#endif
+ }
+
+ switch( yyruleno ){
+ /* Beginning here are the reduction cases. A typical example
+ ** follows:
+ ** case 0:
+ ** #line <lineno> <grammarfile>
+ ** { ... } // User supplied code
+ ** #line <lineno> <thisfile>
+ ** break;
+ */
+/********** Begin reduce actions **********************************************/
+ YYMINORTYPE yylhsminor;
+ case 0: /* query ::= query query_element */
+#line 53 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, grn_int32_value_at(&efsi->op_stack, -1), 2);
+}
+#line 1462 "grn_ecmascript.c"
+ break;
+ case 1: /* query ::= query LOGICAL_AND query_element */
+ case 25: /* logical_and_expression ::= logical_and_expression LOGICAL_AND bitwise_or_expression */ yytestcase(yyruleno==25);
+#line 56 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND, 2);
+}
+#line 1470 "grn_ecmascript.c"
+ break;
+ case 2: /* query ::= query LOGICAL_AND_NOT query_element */
+ case 26: /* logical_and_expression ::= logical_and_expression LOGICAL_AND_NOT bitwise_or_expression */ yytestcase(yyruleno==26);
+#line 59 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND_NOT, 2);
+}
+#line 1478 "grn_ecmascript.c"
+ break;
+ case 3: /* query ::= query LOGICAL_OR query_element */
+ case 24: /* logical_or_expression ::= logical_or_expression LOGICAL_OR logical_and_expression */ yytestcase(yyruleno==24);
+#line 62 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_OR, 2);
+}
+#line 1486 "grn_ecmascript.c"
+ break;
+ case 4: /* query ::= query NEGATIVE query_element */
+#line 65 "grn_ecmascript.lemon"
+{
+ int weight;
+ GRN_INT32_POP(&efsi->weight_stack, weight);
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ADJUST, 2);
+}
+#line 1495 "grn_ecmascript.c"
+ break;
+ case 5: /* query_element ::= ADJUST query_element */
+#line 74 "grn_ecmascript.lemon"
+{
+ int weight;
+ GRN_INT32_POP(&efsi->weight_stack, weight);
+}
+#line 1503 "grn_ecmascript.c"
+ break;
+ case 6: /* query_element ::= RELATIVE_OP query_element */
+#line 78 "grn_ecmascript.lemon"
+{
+ int mode;
+ GRN_INT32_POP(&efsi->mode_stack, mode);
+}
+#line 1511 "grn_ecmascript.c"
+ break;
+ case 7: /* query_element ::= IDENTIFIER RELATIVE_OP query_element */
+#line 82 "grn_ecmascript.lemon"
+{
+ int mode;
+ grn_obj *c;
+ GRN_PTR_POP(&efsi->column_stack, c);
+ GRN_INT32_POP(&efsi->mode_stack, mode);
+ switch (mode) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ {
+ int max_interval;
+ GRN_INT32_POP(&efsi->max_interval_stack, max_interval);
+ }
+ break;
+ case GRN_OP_SIMILAR :
+ {
+ int similarity_threshold;
+ GRN_INT32_POP(&efsi->similarity_threshold_stack, similarity_threshold);
+ }
+ break;
+ default :
+ break;
+ }
+}
+#line 1538 "grn_ecmascript.c"
+ break;
+ case 8: /* query_element ::= BRACEL expression BRACER */
+ case 9: /* query_element ::= EVAL primary_expression */ yytestcase(yyruleno==9);
+#line 105 "grn_ecmascript.lemon"
+{
+ efsi->flags = efsi->default_flags;
+}
+#line 1546 "grn_ecmascript.c"
+ break;
+ case 10: /* expression ::= expression COMMA assignment_expression */
+#line 113 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_COMMA, 2);
+}
+#line 1553 "grn_ecmascript.c"
+ break;
+ case 11: /* assignment_expression ::= lefthand_side_expression ASSIGN assignment_expression */
+#line 118 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ASSIGN, 2);
+}
+#line 1560 "grn_ecmascript.c"
+ break;
+ case 12: /* assignment_expression ::= lefthand_side_expression STAR_ASSIGN assignment_expression */
+#line 121 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_STAR_ASSIGN, 2);
+}
+#line 1567 "grn_ecmascript.c"
+ break;
+ case 13: /* assignment_expression ::= lefthand_side_expression SLASH_ASSIGN assignment_expression */
+#line 124 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SLASH_ASSIGN, 2);
+}
+#line 1574 "grn_ecmascript.c"
+ break;
+ case 14: /* assignment_expression ::= lefthand_side_expression MOD_ASSIGN assignment_expression */
+#line 127 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MOD_ASSIGN, 2);
+}
+#line 1581 "grn_ecmascript.c"
+ break;
+ case 15: /* assignment_expression ::= lefthand_side_expression PLUS_ASSIGN assignment_expression */
+#line 130 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS_ASSIGN, 2);
+}
+#line 1588 "grn_ecmascript.c"
+ break;
+ case 16: /* assignment_expression ::= lefthand_side_expression MINUS_ASSIGN assignment_expression */
+#line 133 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MINUS_ASSIGN, 2);
+}
+#line 1595 "grn_ecmascript.c"
+ break;
+ case 17: /* assignment_expression ::= lefthand_side_expression SHIFTL_ASSIGN assignment_expression */
+#line 136 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTL_ASSIGN, 2);
+}
+#line 1602 "grn_ecmascript.c"
+ break;
+ case 18: /* assignment_expression ::= lefthand_side_expression SHIFTR_ASSIGN assignment_expression */
+#line 139 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTR_ASSIGN, 2);
+}
+#line 1609 "grn_ecmascript.c"
+ break;
+ case 19: /* assignment_expression ::= lefthand_side_expression SHIFTRR_ASSIGN assignment_expression */
+#line 142 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTRR_ASSIGN, 2);
+}
+#line 1616 "grn_ecmascript.c"
+ break;
+ case 20: /* assignment_expression ::= lefthand_side_expression AND_ASSIGN assignment_expression */
+#line 145 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND_ASSIGN, 2);
+}
+#line 1623 "grn_ecmascript.c"
+ break;
+ case 21: /* assignment_expression ::= lefthand_side_expression XOR_ASSIGN assignment_expression */
+#line 148 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_XOR_ASSIGN, 2);
+}
+#line 1630 "grn_ecmascript.c"
+ break;
+ case 22: /* assignment_expression ::= lefthand_side_expression OR_ASSIGN assignment_expression */
+#line 151 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_OR_ASSIGN, 2);
+}
+#line 1637 "grn_ecmascript.c"
+ break;
+ case 23: /* conditional_expression ::= logical_or_expression QUESTION assignment_expression COLON assignment_expression */
+#line 156 "grn_ecmascript.lemon"
+{
+ grn_expr *e = (grn_expr *)efsi->e;
+ e->codes[yymsp[-3].minor.yy0].nargs = yymsp[-1].minor.yy0 - yymsp[-3].minor.yy0;
+ e->codes[yymsp[-1].minor.yy0].nargs = e->codes_curr - yymsp[-1].minor.yy0 - 1;
+}
+#line 1646 "grn_ecmascript.c"
+ break;
+ case 27: /* bitwise_or_expression ::= bitwise_or_expression BITWISE_OR bitwise_xor_expression */
+#line 176 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_OR, 2);
+}
+#line 1653 "grn_ecmascript.c"
+ break;
+ case 28: /* bitwise_xor_expression ::= bitwise_xor_expression BITWISE_XOR bitwise_and_expression */
+#line 181 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_XOR, 2);
+}
+#line 1660 "grn_ecmascript.c"
+ break;
+ case 29: /* bitwise_and_expression ::= bitwise_and_expression BITWISE_AND equality_expression */
+#line 186 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_AND, 2);
+}
+#line 1667 "grn_ecmascript.c"
+ break;
+ case 30: /* equality_expression ::= equality_expression EQUAL relational_expression */
+#line 191 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_EQUAL, 2);
+}
+#line 1674 "grn_ecmascript.c"
+ break;
+ case 31: /* equality_expression ::= equality_expression NOT_EQUAL relational_expression */
+#line 194 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NOT_EQUAL, 2);
+}
+#line 1681 "grn_ecmascript.c"
+ break;
+ case 32: /* relational_expression ::= relational_expression LESS shift_expression */
+#line 199 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_LESS, 2);
+}
+#line 1688 "grn_ecmascript.c"
+ break;
+ case 33: /* relational_expression ::= relational_expression GREATER shift_expression */
+#line 202 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_GREATER, 2);
+}
+#line 1695 "grn_ecmascript.c"
+ break;
+ case 34: /* relational_expression ::= relational_expression LESS_EQUAL shift_expression */
+#line 205 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_LESS_EQUAL, 2);
+}
+#line 1702 "grn_ecmascript.c"
+ break;
+ case 35: /* relational_expression ::= relational_expression GREATER_EQUAL shift_expression */
+#line 208 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_GREATER_EQUAL, 2);
+}
+#line 1709 "grn_ecmascript.c"
+ break;
+ case 36: /* relational_expression ::= relational_expression IN shift_expression */
+#line 211 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_IN, 2);
+}
+#line 1716 "grn_ecmascript.c"
+ break;
+ case 37: /* relational_expression ::= relational_expression MATCH shift_expression */
+ case 85: /* adjust_match_expression ::= IDENTIFIER MATCH STRING */ yytestcase(yyruleno==85);
+#line 214 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MATCH, 2);
+}
+#line 1724 "grn_ecmascript.c"
+ break;
+ case 38: /* relational_expression ::= relational_expression NEAR shift_expression */
+#line 217 "grn_ecmascript.lemon"
+{
+ {
+ int max_interval;
+ GRN_INT32_POP(&efsi->max_interval_stack, max_interval);
+ grn_expr_append_const_int(efsi->ctx, efsi->e, max_interval,
+ GRN_OP_PUSH, 1);
+ }
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NEAR, 3);
+}
+#line 1737 "grn_ecmascript.c"
+ break;
+ case 39: /* relational_expression ::= relational_expression NEAR2 shift_expression */
+#line 226 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NEAR2, 2);
+}
+#line 1744 "grn_ecmascript.c"
+ break;
+ case 40: /* relational_expression ::= relational_expression SIMILAR shift_expression */
+#line 229 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SIMILAR, 2);
+}
+#line 1751 "grn_ecmascript.c"
+ break;
+ case 41: /* relational_expression ::= relational_expression TERM_EXTRACT shift_expression */
+#line 232 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_TERM_EXTRACT, 2);
+}
+#line 1758 "grn_ecmascript.c"
+ break;
+ case 42: /* relational_expression ::= relational_expression LCP shift_expression */
+#line 235 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_LCP, 2);
+}
+#line 1765 "grn_ecmascript.c"
+ break;
+ case 43: /* relational_expression ::= relational_expression PREFIX shift_expression */
+#line 238 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PREFIX, 2);
+}
+#line 1772 "grn_ecmascript.c"
+ break;
+ case 44: /* relational_expression ::= relational_expression SUFFIX shift_expression */
+#line 241 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SUFFIX, 2);
+}
+#line 1779 "grn_ecmascript.c"
+ break;
+ case 45: /* relational_expression ::= relational_expression REGEXP shift_expression */
+#line 244 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_REGEXP, 2);
+}
+#line 1786 "grn_ecmascript.c"
+ break;
+ case 46: /* shift_expression ::= shift_expression SHIFTL additive_expression */
+#line 249 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTL, 2);
+}
+#line 1793 "grn_ecmascript.c"
+ break;
+ case 47: /* shift_expression ::= shift_expression SHIFTR additive_expression */
+#line 252 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTR, 2);
+}
+#line 1800 "grn_ecmascript.c"
+ break;
+ case 48: /* shift_expression ::= shift_expression SHIFTRR additive_expression */
+#line 255 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTRR, 2);
+}
+#line 1807 "grn_ecmascript.c"
+ break;
+ case 49: /* additive_expression ::= additive_expression PLUS multiplicative_expression */
+ case 83: /* adjuster ::= adjuster PLUS adjust_expression */ yytestcase(yyruleno==83);
+#line 260 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS, 2);
+}
+#line 1815 "grn_ecmascript.c"
+ break;
+ case 50: /* additive_expression ::= additive_expression MINUS multiplicative_expression */
+#line 263 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MINUS, 2);
+}
+#line 1822 "grn_ecmascript.c"
+ break;
+ case 51: /* multiplicative_expression ::= multiplicative_expression STAR unary_expression */
+ case 84: /* adjust_expression ::= adjust_match_expression STAR DECIMAL */ yytestcase(yyruleno==84);
+#line 268 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_STAR, 2);
+}
+#line 1830 "grn_ecmascript.c"
+ break;
+ case 52: /* multiplicative_expression ::= multiplicative_expression SLASH unary_expression */
+#line 271 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SLASH, 2);
+}
+#line 1837 "grn_ecmascript.c"
+ break;
+ case 53: /* multiplicative_expression ::= multiplicative_expression MOD unary_expression */
+#line 274 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MOD, 2);
+}
+#line 1844 "grn_ecmascript.c"
+ break;
+ case 54: /* unary_expression ::= DELETE unary_expression */
+#line 279 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_DELETE, 1);
+}
+#line 1851 "grn_ecmascript.c"
+ break;
+ case 55: /* unary_expression ::= INCR unary_expression */
+#line 282 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be incremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_INCR, 1);
+ }
+}
+#line 1872 "grn_ecmascript.c"
+ break;
+ case 56: /* unary_expression ::= DECR unary_expression */
+#line 299 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be decremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_DECR, 1);
+ }
+}
+#line 1893 "grn_ecmascript.c"
+ break;
+ case 57: /* unary_expression ::= PLUS unary_expression */
+#line 316 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS, 1);
+}
+#line 1900 "grn_ecmascript.c"
+ break;
+ case 58: /* unary_expression ::= MINUS unary_expression */
+#line 319 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MINUS, 1);
+}
+#line 1907 "grn_ecmascript.c"
+ break;
+ case 59: /* unary_expression ::= NOT unary_expression */
+#line 322 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NOT, 1);
+}
+#line 1914 "grn_ecmascript.c"
+ break;
+ case 60: /* unary_expression ::= BITWISE_NOT unary_expression */
+#line 325 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_NOT, 1);
+}
+#line 1921 "grn_ecmascript.c"
+ break;
+ case 61: /* unary_expression ::= ADJUST unary_expression */
+#line 328 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ADJUST, 1);
+}
+#line 1928 "grn_ecmascript.c"
+ break;
+ case 62: /* unary_expression ::= EXACT unary_expression */
+#line 331 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_EXACT, 1);
+}
+#line 1935 "grn_ecmascript.c"
+ break;
+ case 63: /* unary_expression ::= PARTIAL unary_expression */
+#line 334 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PARTIAL, 1);
+}
+#line 1942 "grn_ecmascript.c"
+ break;
+ case 64: /* unary_expression ::= UNSPLIT unary_expression */
+#line 337 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_UNSPLIT, 1);
+}
+#line 1949 "grn_ecmascript.c"
+ break;
+ case 65: /* postfix_expression ::= lefthand_side_expression INCR */
+#line 342 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be incremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_INCR_POST, 1);
+ }
+}
+#line 1970 "grn_ecmascript.c"
+ break;
+ case 66: /* postfix_expression ::= lefthand_side_expression DECR */
+#line 359 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be decremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_DECR_POST, 1);
+ }
+}
+#line 1991 "grn_ecmascript.c"
+ break;
+ case 67: /* call_expression ::= member_expression arguments */
+#line 380 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_CALL, yymsp[0].minor.yy0);
+}
+#line 1998 "grn_ecmascript.c"
+ break;
+ case 68: /* object_literal ::= BRACEL property_name_and_value_list BRACER */
+#line 408 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr_take_obj(ctx, efsi->e, (grn_obj *)(efsi->object_literal));
+ grn_expr_append_obj(ctx, efsi->e, (grn_obj *)(efsi->object_literal),
+ GRN_OP_PUSH, 1);
+ efsi->object_literal = NULL;
+}
+#line 2009 "grn_ecmascript.c"
+ break;
+ case 69: /* property_name_and_value_list ::= */
+#line 416 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+
+ efsi->object_literal =
+ grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj),
+ GRN_OBJ_KEY_VAR_SIZE|GRN_OBJ_TEMPORARY|GRN_HASH_TINY);
+ if (!efsi->object_literal) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "couldn't create hash table for parsing object literal: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ }
+}
+#line 2025 "grn_ecmascript.c"
+ break;
+ case 70: /* property_name_and_value ::= property_name COLON assignment_expression */
+#line 431 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_obj *property = e->codes[e->codes_curr - 3].value;
+ grn_obj *value = e->codes[e->codes_curr - 1].value;
+
+ if (!efsi->object_literal) {
+ efsi->object_literal =
+ grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj),
+ GRN_OBJ_KEY_VAR_SIZE|GRN_OBJ_TEMPORARY|GRN_HASH_TINY);
+ }
+
+ if (!efsi->object_literal) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "couldn't create hash table for parsing object literal: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_obj *buf;
+ int added;
+ if (grn_hash_add(ctx, (grn_hash *)efsi->object_literal,
+ GRN_TEXT_VALUE(property), GRN_TEXT_LEN(property),
+ (void **)&buf, &added)) {
+ if (added) {
+ GRN_OBJ_INIT(buf, value->header.type, 0, value->header.domain);
+ GRN_TEXT_PUT(ctx, buf, GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
+ grn_expr_dfi_pop(e);
+ e->codes_curr -= 3;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated property name: <%.*s>",
+ (int)GRN_TEXT_LEN(property),
+ GRN_TEXT_VALUE(property));
+ }
+ } else {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to add a property to object literal: <%.*s>",
+ (int)GRN_TEXT_LEN(property),
+ GRN_TEXT_VALUE(property));
+ }
+ }
+}
+#line 2070 "grn_ecmascript.c"
+ break;
+ case 71: /* member_expression_part ::= BRACKETL expression BRACKETR */
+#line 475 "grn_ecmascript.lemon"
+{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_GET_MEMBER, 2);
+}
+#line 2077 "grn_ecmascript.c"
+ break;
+ case 72: /* arguments ::= PARENL argument_list PARENR */
+#line 480 "grn_ecmascript.lemon"
+{ yymsp[-2].minor.yy0 = yymsp[-1].minor.yy0; }
+#line 2082 "grn_ecmascript.c"
+ break;
+ case 73: /* argument_list ::= */
+#line 481 "grn_ecmascript.lemon"
+{ yymsp[1].minor.yy0 = 0; }
+#line 2087 "grn_ecmascript.c"
+ break;
+ case 74: /* argument_list ::= assignment_expression */
+#line 482 "grn_ecmascript.lemon"
+{ yymsp[0].minor.yy0 = 1; }
+#line 2092 "grn_ecmascript.c"
+ break;
+ case 75: /* argument_list ::= argument_list COMMA assignment_expression */
+#line 483 "grn_ecmascript.lemon"
+{ yylhsminor.yy0 = yymsp[-2].minor.yy0 + 1; }
+#line 2097 "grn_ecmascript.c"
+ yymsp[-2].minor.yy0 = yylhsminor.yy0;
+ break;
+ case 76: /* output_columns ::= */
+#line 485 "grn_ecmascript.lemon"
+{
+ yymsp[1].minor.yy0 = 0;
+}
+#line 2105 "grn_ecmascript.c"
+ break;
+ case 77: /* output_columns ::= output_column */
+#line 488 "grn_ecmascript.lemon"
+{
+ yylhsminor.yy0 = yymsp[0].minor.yy0;
+}
+#line 2112 "grn_ecmascript.c"
+ yymsp[0].minor.yy0 = yylhsminor.yy0;
+ break;
+ case 78: /* output_columns ::= output_columns COMMA */
+#line 493 "grn_ecmascript.lemon"
+{
+ yylhsminor.yy0 = yymsp[-1].minor.yy0;
+}
+#line 2120 "grn_ecmascript.c"
+ yymsp[-1].minor.yy0 = yylhsminor.yy0;
+ break;
+ case 79: /* output_columns ::= output_columns COMMA output_column */
+#line 498 "grn_ecmascript.lemon"
+{
+ if (yymsp[-2].minor.yy0 == 0) {
+ yylhsminor.yy0 = yymsp[0].minor.yy0;
+ } else if (yymsp[0].minor.yy0 == 0) {
+ yylhsminor.yy0 = yymsp[-2].minor.yy0;
+ } else {
+ if (yymsp[0].minor.yy0 == 1) {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_COMMA, 2);
+ }
+ yylhsminor.yy0 = 1;
+ }
+}
+#line 2137 "grn_ecmascript.c"
+ yymsp[-2].minor.yy0 = yylhsminor.yy0;
+ break;
+ case 80: /* output_column ::= STAR */
+#line 511 "grn_ecmascript.lemon"
+{
+ grn_ctx *ctx = efsi->ctx;
+ grn_obj *expr = efsi->e;
+ grn_obj *variable = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (variable) {
+ grn_id table_id = GRN_OBJ_GET_DOMAIN(variable);
+ grn_obj *table = grn_ctx_at(ctx, table_id);
+ grn_obj columns_buffer;
+ int n_columns;
+ grn_obj **columns;
+
+ GRN_PTR_INIT(&columns_buffer, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_obj_columns(ctx, table, "*", strlen("*"), &columns_buffer);
+ n_columns = GRN_BULK_VSIZE(&columns_buffer) / sizeof(grn_obj *);
+ columns = (grn_obj **)GRN_BULK_HEAD(&columns_buffer);
+
+ if (n_columns == 0) {
+ /* do nothing */
+ } else if (n_columns == 1) {
+ grn_obj *column = columns[0];
+ grn_expr_append_const(ctx, expr, column, GRN_OP_GET_VALUE, 1);
+ if (column->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, expr, column);
+ }
+ } else {
+ grn_expr *e = (grn_expr *)expr;
+ grn_bool have_column;
+ int i;
+
+ have_column = (e->codes_curr > 0);
+ for (i = 0; i < n_columns; i++) {
+ grn_obj *column = columns[i];
+ grn_expr_append_const(ctx, expr, column, GRN_OP_GET_VALUE, 1);
+ if (have_column || i > 0) {
+ grn_expr_append_op(ctx, expr, GRN_OP_COMMA, 2);
+ }
+ if (column->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, expr, column);
+ }
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &columns_buffer);
+
+ yymsp[0].minor.yy0 = n_columns;
+ } else {
+ /* TODO: report error */
+ yymsp[0].minor.yy0 = 0;
+ }
+}
+#line 2192 "grn_ecmascript.c"
+ break;
+ case 81: /* output_column ::= NONEXISTENT_COLUMN */
+#line 561 "grn_ecmascript.lemon"
+{
+ yymsp[0].minor.yy0 = 0;
+}
+#line 2199 "grn_ecmascript.c"
+ break;
+ case 82: /* output_column ::= assignment_expression */
+#line 564 "grn_ecmascript.lemon"
+{
+ yymsp[0].minor.yy0 = 1;
+}
+#line 2206 "grn_ecmascript.c"
+ break;
+ default:
+ /* (86) input ::= query */ yytestcase(yyruleno==86);
+ /* (87) input ::= expression */ yytestcase(yyruleno==87);
+ /* (88) input ::= START_OUTPUT_COLUMNS output_columns */ yytestcase(yyruleno==88);
+ /* (89) input ::= START_ADJUSTER adjuster */ yytestcase(yyruleno==89);
+ /* (90) query ::= query_element (OPTIMIZED OUT) */ assert(yyruleno!=90);
+ /* (91) query_element ::= QSTRING */ yytestcase(yyruleno==91);
+ /* (92) query_element ::= PARENL query PARENR */ yytestcase(yyruleno==92);
+ /* (93) expression ::= assignment_expression (OPTIMIZED OUT) */ assert(yyruleno!=93);
+ /* (94) assignment_expression ::= conditional_expression (OPTIMIZED OUT) */ assert(yyruleno!=94);
+ /* (95) conditional_expression ::= logical_or_expression */ yytestcase(yyruleno==95);
+ /* (96) logical_or_expression ::= logical_and_expression */ yytestcase(yyruleno==96);
+ /* (97) logical_and_expression ::= bitwise_or_expression */ yytestcase(yyruleno==97);
+ /* (98) bitwise_or_expression ::= bitwise_xor_expression */ yytestcase(yyruleno==98);
+ /* (99) bitwise_xor_expression ::= bitwise_and_expression */ yytestcase(yyruleno==99);
+ /* (100) bitwise_and_expression ::= equality_expression */ yytestcase(yyruleno==100);
+ /* (101) equality_expression ::= relational_expression */ yytestcase(yyruleno==101);
+ /* (102) relational_expression ::= shift_expression */ yytestcase(yyruleno==102);
+ /* (103) shift_expression ::= additive_expression */ yytestcase(yyruleno==103);
+ /* (104) additive_expression ::= multiplicative_expression */ yytestcase(yyruleno==104);
+ /* (105) multiplicative_expression ::= unary_expression (OPTIMIZED OUT) */ assert(yyruleno!=105);
+ /* (106) unary_expression ::= postfix_expression (OPTIMIZED OUT) */ assert(yyruleno!=106);
+ /* (107) postfix_expression ::= lefthand_side_expression */ yytestcase(yyruleno==107);
+ /* (108) lefthand_side_expression ::= call_expression (OPTIMIZED OUT) */ assert(yyruleno!=108);
+ /* (109) lefthand_side_expression ::= member_expression */ yytestcase(yyruleno==109);
+ /* (110) member_expression ::= primary_expression (OPTIMIZED OUT) */ assert(yyruleno!=110);
+ /* (111) member_expression ::= member_expression member_expression_part */ yytestcase(yyruleno==111);
+ /* (112) primary_expression ::= object_literal (OPTIMIZED OUT) */ assert(yyruleno!=112);
+ /* (113) primary_expression ::= PARENL expression PARENR */ yytestcase(yyruleno==113);
+ /* (114) primary_expression ::= IDENTIFIER */ yytestcase(yyruleno==114);
+ /* (115) primary_expression ::= array_literal (OPTIMIZED OUT) */ assert(yyruleno!=115);
+ /* (116) primary_expression ::= DECIMAL */ yytestcase(yyruleno==116);
+ /* (117) primary_expression ::= HEX_INTEGER */ yytestcase(yyruleno==117);
+ /* (118) primary_expression ::= STRING */ yytestcase(yyruleno==118);
+ /* (119) primary_expression ::= BOOLEAN */ yytestcase(yyruleno==119);
+ /* (120) primary_expression ::= NULL */ yytestcase(yyruleno==120);
+ /* (121) array_literal ::= BRACKETL elision BRACKETR */ yytestcase(yyruleno==121);
+ /* (122) array_literal ::= BRACKETL element_list elision BRACKETR */ yytestcase(yyruleno==122);
+ /* (123) array_literal ::= BRACKETL element_list BRACKETR */ yytestcase(yyruleno==123);
+ /* (124) elision ::= COMMA */ yytestcase(yyruleno==124);
+ /* (125) elision ::= elision COMMA */ yytestcase(yyruleno==125);
+ /* (126) element_list ::= assignment_expression (OPTIMIZED OUT) */ assert(yyruleno!=126);
+ /* (127) element_list ::= elision assignment_expression */ yytestcase(yyruleno==127);
+ /* (128) element_list ::= element_list elision assignment_expression */ yytestcase(yyruleno==128);
+ /* (129) property_name_and_value_list ::= property_name_and_value (OPTIMIZED OUT) */ assert(yyruleno!=129);
+ /* (130) property_name_and_value_list ::= property_name_and_value_list COMMA property_name_and_value */ yytestcase(yyruleno==130);
+ /* (131) property_name ::= STRING */ yytestcase(yyruleno==131);
+ /* (132) member_expression_part ::= DOT IDENTIFIER */ yytestcase(yyruleno==132);
+ /* (133) adjuster ::= */ yytestcase(yyruleno==133);
+ /* (134) adjuster ::= adjust_expression (OPTIMIZED OUT) */ assert(yyruleno!=134);
+ /* (135) adjust_expression ::= adjust_match_expression */ yytestcase(yyruleno==135);
+ break;
+/********** End reduce actions ************************************************/
+ };
+ assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
+ yygoto = yyRuleInfo[yyruleno].lhs;
+ yysize = yyRuleInfo[yyruleno].nrhs;
+ yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
+ if( yyact <= YY_MAX_SHIFTREDUCE ){
+ if( yyact>YY_MAX_SHIFT ){
+ yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
+ }
+ yymsp -= yysize-1;
+ yypParser->yytos = yymsp;
+ yymsp->stateno = (YYACTIONTYPE)yyact;
+ yymsp->major = (YYCODETYPE)yygoto;
+ yyTraceShift(yypParser, yyact);
+ }else{
+ assert( yyact == YY_ACCEPT_ACTION );
+ yypParser->yytos -= yysize;
+ yy_accept(yypParser);
+ }
+}
+
+/*
+** The following code executes when the parse fails
+*/
+#ifndef YYNOERRORRECOVERY
+static void yy_parse_failed(
+ yyParser *yypParser /* The parser */
+){
+ grn_expr_parserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt);
+ }
+#endif
+ while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser);
+ /* Here code is inserted which will be executed whenever the
+ ** parser fails */
+/************ Begin %parse_failure code ***************************************/
+/************ End %parse_failure code *****************************************/
+ grn_expr_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+#endif /* YYNOERRORRECOVERY */
+
+/*
+** The following code executes when a syntax error first occurs.
+*/
+static void yy_syntax_error(
+ yyParser *yypParser, /* The parser */
+ int yymajor, /* The major type of the error token */
+ grn_expr_parserTOKENTYPE yyminor /* The minor type of the error token */
+){
+ grn_expr_parserARG_FETCH;
+#define TOKEN yyminor
+/************ Begin %syntax_error code ****************************************/
+#line 20 "grn_ecmascript.lemon"
+
+ {
+ grn_ctx *ctx = efsi->ctx;
+ grn_obj message;
+ GRN_TEXT_INIT(&message, 0);
+ GRN_TEXT_PUT(ctx, &message, efsi->str, efsi->cur - efsi->str);
+ GRN_TEXT_PUTC(ctx, &message, '|');
+ if (efsi->cur < efsi->str_end) {
+ GRN_TEXT_PUTC(ctx, &message, efsi->cur[0]);
+ GRN_TEXT_PUTC(ctx, &message, '|');
+ GRN_TEXT_PUT(ctx, &message,
+ efsi->cur + 1, efsi->str_end - (efsi->cur + 1));
+ } else {
+ GRN_TEXT_PUTC(ctx, &message, '|');
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_SYNTAX_ERROR, "Syntax error: <%.*s>",
+ (int)GRN_TEXT_LEN(&message), GRN_TEXT_VALUE(&message));
+ } else {
+ ERR(ctx->rc, "Syntax error: <%.*s>: %s",
+ (int)GRN_TEXT_LEN(&message), GRN_TEXT_VALUE(&message),
+ ctx->errbuf);
+ }
+ GRN_OBJ_FIN(ctx, &message);
+ }
+#line 2341 "grn_ecmascript.c"
+/************ End %syntax_error code ******************************************/
+ grn_expr_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/*
+** The following is executed when the parser accepts
+*/
+static void yy_accept(
+ yyParser *yypParser /* The parser */
+){
+ grn_expr_parserARG_FETCH;
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt);
+ }
+#endif
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ assert( yypParser->yytos==yypParser->yystack );
+ /* Here code is inserted which will be executed whenever the
+ ** parser accepts */
+/*********** Begin %parse_accept code *****************************************/
+/*********** End %parse_accept code *******************************************/
+ grn_expr_parserARG_STORE; /* Suppress warning about unused %extra_argument variable */
+}
+
+/* The main parser program.
+** The first argument is a pointer to a structure obtained from
+** "grn_expr_parserAlloc" which describes the current state of the parser.
+** The second argument is the major token number. The third is
+** the minor token. The fourth optional argument is whatever the
+** user wants (and specified in the grammar) and is available for
+** use by the action routines.
+**
+** Inputs:
+** <ul>
+** <li> A pointer to the parser (an opaque structure.)
+** <li> The major token number.
+** <li> The minor token number.
+** <li> An option argument of a grammar-specified type.
+** </ul>
+**
+** Outputs:
+** None.
+*/
+void grn_expr_parser(
+ void *yyp, /* The parser */
+ int yymajor, /* The major token code number */
+ grn_expr_parserTOKENTYPE yyminor /* The value for the token */
+ grn_expr_parserARG_PDECL /* Optional %extra_argument parameter */
+){
+ YYMINORTYPE yyminorunion;
+ unsigned int yyact; /* The parser action. */
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ int yyendofinput; /* True if we are at the end of input */
+#endif
+#ifdef YYERRORSYMBOL
+ int yyerrorhit = 0; /* True if yymajor has invoked an error */
+#endif
+ yyParser *yypParser; /* The parser */
+
+ yypParser = (yyParser*)yyp;
+ assert( yypParser->yytos!=0 );
+#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
+ yyendofinput = (yymajor==0);
+#endif
+ grn_expr_parserARG_STORE;
+
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+
+ do{
+ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
+ if( yyact <= YY_MAX_SHIFTREDUCE ){
+ yy_shift(yypParser,yyact,yymajor,yyminor);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt--;
+#endif
+ yymajor = YYNOCODE;
+ }else if( yyact <= YY_MAX_REDUCE ){
+ yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
+ }else{
+ assert( yyact == YY_ERROR_ACTION );
+ yyminorunion.yy0 = yyminor;
+#ifdef YYERRORSYMBOL
+ int yymx;
+#endif
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt);
+ }
+#endif
+#ifdef YYERRORSYMBOL
+ /* A syntax error has occurred.
+ ** The response to an error depends upon whether or not the
+ ** grammar defines an error token "ERROR".
+ **
+ ** This is what we do if the grammar does define ERROR:
+ **
+ ** * Call the %syntax_error function.
+ **
+ ** * Begin popping the stack until we enter a state where
+ ** it is legal to shift the error symbol, then shift
+ ** the error symbol.
+ **
+ ** * Set the error count to three.
+ **
+ ** * Begin accepting and shifting new tokens. No new error
+ ** processing will occur until three tokens have been
+ ** shifted successfully.
+ **
+ */
+ if( yypParser->yyerrcnt<0 ){
+ yy_syntax_error(yypParser,yymajor,yyminor);
+ }
+ yymx = yypParser->yytos->major;
+ if( yymx==YYERRORSYMBOL || yyerrorhit ){
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ fprintf(yyTraceFILE,"%sDiscard input token %s\n",
+ yyTracePrompt,yyTokenName[yymajor]);
+ }
+#endif
+ yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion);
+ yymajor = YYNOCODE;
+ }else{
+ while( yypParser->yytos >= yypParser->yystack
+ && yymx != YYERRORSYMBOL
+ && (yyact = yy_find_reduce_action(
+ yypParser->yytos->stateno,
+ YYERRORSYMBOL)) >= YY_MIN_REDUCE
+ ){
+ yy_pop_parser_stack(yypParser);
+ }
+ if( yypParser->yytos < yypParser->yystack || yymajor==0 ){
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ yymajor = YYNOCODE;
+ }else if( yymx!=YYERRORSYMBOL ){
+ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
+ }
+ }
+ yypParser->yyerrcnt = 3;
+ yyerrorhit = 1;
+#elif defined(YYNOERRORRECOVERY)
+ /* If the YYNOERRORRECOVERY macro is defined, then do not attempt to
+ ** do any kind of error recovery. Instead, simply invoke the syntax
+ ** error routine and continue going as if nothing had happened.
+ **
+ ** Applications can set this macro (for example inside %include) if
+ ** they intend to abandon the parse upon the first syntax error seen.
+ */
+ yy_syntax_error(yypParser,yymajor, yyminor);
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ yymajor = YYNOCODE;
+
+#else /* YYERRORSYMBOL is not defined */
+ /* This is what we do if the grammar does not define ERROR:
+ **
+ ** * Report an error message, and throw away the input token.
+ **
+ ** * If the input token is $, then fail the parse.
+ **
+ ** As before, subsequent error messages are suppressed until
+ ** three input tokens have been successfully shifted.
+ */
+ if( yypParser->yyerrcnt<=0 ){
+ yy_syntax_error(yypParser,yymajor, yyminor);
+ }
+ yypParser->yyerrcnt = 3;
+ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
+ if( yyendofinput ){
+ yy_parse_failed(yypParser);
+#ifndef YYNOERRORRECOVERY
+ yypParser->yyerrcnt = -1;
+#endif
+ }
+ yymajor = YYNOCODE;
+#endif
+ }
+ }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack );
+#ifndef NDEBUG
+ if( yyTraceFILE ){
+ yyStackEntry *i;
+ char cDiv = '[';
+ fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt);
+ for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){
+ fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]);
+ cDiv = ' ';
+ }
+ fprintf(yyTraceFILE,"]\n");
+ }
+#endif
+ return;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ecmascript.h b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.h
new file mode 100644
index 00000000..15272b0a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.h
@@ -0,0 +1,74 @@
+#define GRN_EXPR_TOKEN_START_OUTPUT_COLUMNS 1
+#define GRN_EXPR_TOKEN_START_ADJUSTER 2
+#define GRN_EXPR_TOKEN_LOGICAL_AND 3
+#define GRN_EXPR_TOKEN_LOGICAL_AND_NOT 4
+#define GRN_EXPR_TOKEN_LOGICAL_OR 5
+#define GRN_EXPR_TOKEN_NEGATIVE 6
+#define GRN_EXPR_TOKEN_QSTRING 7
+#define GRN_EXPR_TOKEN_PARENL 8
+#define GRN_EXPR_TOKEN_PARENR 9
+#define GRN_EXPR_TOKEN_ADJUST 10
+#define GRN_EXPR_TOKEN_RELATIVE_OP 11
+#define GRN_EXPR_TOKEN_IDENTIFIER 12
+#define GRN_EXPR_TOKEN_BRACEL 13
+#define GRN_EXPR_TOKEN_BRACER 14
+#define GRN_EXPR_TOKEN_EVAL 15
+#define GRN_EXPR_TOKEN_COMMA 16
+#define GRN_EXPR_TOKEN_ASSIGN 17
+#define GRN_EXPR_TOKEN_STAR_ASSIGN 18
+#define GRN_EXPR_TOKEN_SLASH_ASSIGN 19
+#define GRN_EXPR_TOKEN_MOD_ASSIGN 20
+#define GRN_EXPR_TOKEN_PLUS_ASSIGN 21
+#define GRN_EXPR_TOKEN_MINUS_ASSIGN 22
+#define GRN_EXPR_TOKEN_SHIFTL_ASSIGN 23
+#define GRN_EXPR_TOKEN_SHIFTR_ASSIGN 24
+#define GRN_EXPR_TOKEN_SHIFTRR_ASSIGN 25
+#define GRN_EXPR_TOKEN_AND_ASSIGN 26
+#define GRN_EXPR_TOKEN_XOR_ASSIGN 27
+#define GRN_EXPR_TOKEN_OR_ASSIGN 28
+#define GRN_EXPR_TOKEN_QUESTION 29
+#define GRN_EXPR_TOKEN_COLON 30
+#define GRN_EXPR_TOKEN_BITWISE_OR 31
+#define GRN_EXPR_TOKEN_BITWISE_XOR 32
+#define GRN_EXPR_TOKEN_BITWISE_AND 33
+#define GRN_EXPR_TOKEN_EQUAL 34
+#define GRN_EXPR_TOKEN_NOT_EQUAL 35
+#define GRN_EXPR_TOKEN_LESS 36
+#define GRN_EXPR_TOKEN_GREATER 37
+#define GRN_EXPR_TOKEN_LESS_EQUAL 38
+#define GRN_EXPR_TOKEN_GREATER_EQUAL 39
+#define GRN_EXPR_TOKEN_IN 40
+#define GRN_EXPR_TOKEN_MATCH 41
+#define GRN_EXPR_TOKEN_NEAR 42
+#define GRN_EXPR_TOKEN_NEAR2 43
+#define GRN_EXPR_TOKEN_SIMILAR 44
+#define GRN_EXPR_TOKEN_TERM_EXTRACT 45
+#define GRN_EXPR_TOKEN_LCP 46
+#define GRN_EXPR_TOKEN_PREFIX 47
+#define GRN_EXPR_TOKEN_SUFFIX 48
+#define GRN_EXPR_TOKEN_REGEXP 49
+#define GRN_EXPR_TOKEN_SHIFTL 50
+#define GRN_EXPR_TOKEN_SHIFTR 51
+#define GRN_EXPR_TOKEN_SHIFTRR 52
+#define GRN_EXPR_TOKEN_PLUS 53
+#define GRN_EXPR_TOKEN_MINUS 54
+#define GRN_EXPR_TOKEN_STAR 55
+#define GRN_EXPR_TOKEN_SLASH 56
+#define GRN_EXPR_TOKEN_MOD 57
+#define GRN_EXPR_TOKEN_DELETE 58
+#define GRN_EXPR_TOKEN_INCR 59
+#define GRN_EXPR_TOKEN_DECR 60
+#define GRN_EXPR_TOKEN_NOT 61
+#define GRN_EXPR_TOKEN_BITWISE_NOT 62
+#define GRN_EXPR_TOKEN_EXACT 63
+#define GRN_EXPR_TOKEN_PARTIAL 64
+#define GRN_EXPR_TOKEN_UNSPLIT 65
+#define GRN_EXPR_TOKEN_DECIMAL 66
+#define GRN_EXPR_TOKEN_HEX_INTEGER 67
+#define GRN_EXPR_TOKEN_STRING 68
+#define GRN_EXPR_TOKEN_BOOLEAN 69
+#define GRN_EXPR_TOKEN_NULL 70
+#define GRN_EXPR_TOKEN_BRACKETL 71
+#define GRN_EXPR_TOKEN_BRACKETR 72
+#define GRN_EXPR_TOKEN_DOT 73
+#define GRN_EXPR_TOKEN_NONEXISTENT_COLUMN 74
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ecmascript.lemon b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.lemon
new file mode 100644
index 00000000..234ea41c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ecmascript.lemon
@@ -0,0 +1,581 @@
+/* -*- mode: c; c-basic-offset: 2 -*- */
+%name grn_expr_parser
+%token_prefix GRN_EXPR_TOKEN_
+%include {
+#ifdef assert
+# undef assert
+#endif
+#define assert GRN_ASSERT
+}
+
+%token_type { int }
+
+%type suppress_unused_variable_warning { void * }
+%destructor suppress_unused_variable_warning {
+ (void)efsi;
+}
+
+%extra_argument { efs_info *efsi }
+
+%syntax_error {
+ {
+ grn_ctx *ctx = efsi->ctx;
+ grn_obj message;
+ GRN_TEXT_INIT(&message, 0);
+ GRN_TEXT_PUT(ctx, &message, efsi->str, efsi->cur - efsi->str);
+ GRN_TEXT_PUTC(ctx, &message, '|');
+ if (efsi->cur < efsi->str_end) {
+ GRN_TEXT_PUTC(ctx, &message, efsi->cur[0]);
+ GRN_TEXT_PUTC(ctx, &message, '|');
+ GRN_TEXT_PUT(ctx, &message,
+ efsi->cur + 1, efsi->str_end - (efsi->cur + 1));
+ } else {
+ GRN_TEXT_PUTC(ctx, &message, '|');
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_SYNTAX_ERROR, "Syntax error: <%.*s>",
+ (int)GRN_TEXT_LEN(&message), GRN_TEXT_VALUE(&message));
+ } else {
+ ERR(ctx->rc, "Syntax error: <%.*s>: %s",
+ (int)GRN_TEXT_LEN(&message), GRN_TEXT_VALUE(&message),
+ ctx->errbuf);
+ }
+ GRN_OBJ_FIN(ctx, &message);
+ }
+}
+
+input ::= query.
+input ::= expression.
+input ::= START_OUTPUT_COLUMNS output_columns.
+input ::= START_ADJUSTER adjuster.
+
+query ::= query_element.
+query ::= query query_element. {
+ grn_expr_append_op(efsi->ctx, efsi->e, grn_int32_value_at(&efsi->op_stack, -1), 2);
+}
+query ::= query LOGICAL_AND query_element. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND, 2);
+}
+query ::= query LOGICAL_AND_NOT query_element.{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND_NOT, 2);
+}
+query ::= query LOGICAL_OR query_element.{
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_OR, 2);
+}
+query ::= query NEGATIVE query_element.{
+ int weight;
+ GRN_INT32_POP(&efsi->weight_stack, weight);
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ADJUST, 2);
+}
+
+query_element ::= QSTRING.
+query_element ::= PARENL query PARENR.
+
+query_element ::= ADJUST query_element.{
+ int weight;
+ GRN_INT32_POP(&efsi->weight_stack, weight);
+}
+query_element ::= RELATIVE_OP query_element.{
+ int mode;
+ GRN_INT32_POP(&efsi->mode_stack, mode);
+}
+query_element ::= IDENTIFIER RELATIVE_OP query_element. {
+ int mode;
+ grn_obj *c;
+ GRN_PTR_POP(&efsi->column_stack, c);
+ GRN_INT32_POP(&efsi->mode_stack, mode);
+ switch (mode) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ {
+ int max_interval;
+ GRN_INT32_POP(&efsi->max_interval_stack, max_interval);
+ }
+ break;
+ case GRN_OP_SIMILAR :
+ {
+ int similarity_threshold;
+ GRN_INT32_POP(&efsi->similarity_threshold_stack, similarity_threshold);
+ }
+ break;
+ default :
+ break;
+ }
+}
+query_element ::= BRACEL expression BRACER. {
+ efsi->flags = efsi->default_flags;
+}
+query_element ::= EVAL primary_expression. {
+ efsi->flags = efsi->default_flags;
+}
+
+expression ::= assignment_expression.
+expression ::= expression COMMA assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_COMMA, 2);
+}
+
+assignment_expression ::= conditional_expression.
+assignment_expression ::= lefthand_side_expression ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression STAR_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_STAR_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression SLASH_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SLASH_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression MOD_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MOD_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression PLUS_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression MINUS_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MINUS_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression SHIFTL_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTL_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression SHIFTR_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTR_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression SHIFTRR_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTRR_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression AND_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression XOR_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_XOR_ASSIGN, 2);
+}
+assignment_expression ::= lefthand_side_expression OR_ASSIGN assignment_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_OR_ASSIGN, 2);
+}
+
+conditional_expression ::= logical_or_expression.
+conditional_expression ::= logical_or_expression QUESTION(A) assignment_expression COLON(B) assignment_expression. {
+ grn_expr *e = (grn_expr *)efsi->e;
+ e->codes[A].nargs = B - A;
+ e->codes[B].nargs = e->codes_curr - B - 1;
+}
+
+logical_or_expression ::= logical_and_expression.
+logical_or_expression ::= logical_or_expression LOGICAL_OR logical_and_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_OR, 2);
+}
+
+logical_and_expression ::= bitwise_or_expression.
+logical_and_expression ::= logical_and_expression LOGICAL_AND bitwise_or_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND, 2);
+}
+logical_and_expression ::= logical_and_expression LOGICAL_AND_NOT bitwise_or_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_AND_NOT, 2);
+}
+
+bitwise_or_expression ::= bitwise_xor_expression.
+bitwise_or_expression ::= bitwise_or_expression BITWISE_OR bitwise_xor_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_OR, 2);
+}
+
+bitwise_xor_expression ::= bitwise_and_expression.
+bitwise_xor_expression ::= bitwise_xor_expression BITWISE_XOR bitwise_and_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_XOR, 2);
+}
+
+bitwise_and_expression ::= equality_expression.
+bitwise_and_expression ::= bitwise_and_expression BITWISE_AND equality_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_AND, 2);
+}
+
+equality_expression ::= relational_expression.
+equality_expression ::= equality_expression EQUAL relational_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_EQUAL, 2);
+}
+equality_expression ::= equality_expression NOT_EQUAL relational_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NOT_EQUAL, 2);
+}
+
+relational_expression ::= shift_expression.
+relational_expression ::= relational_expression LESS shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_LESS, 2);
+}
+relational_expression ::= relational_expression GREATER shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_GREATER, 2);
+}
+relational_expression ::= relational_expression LESS_EQUAL shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_LESS_EQUAL, 2);
+}
+relational_expression ::= relational_expression GREATER_EQUAL shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_GREATER_EQUAL, 2);
+}
+relational_expression ::= relational_expression IN shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_IN, 2);
+}
+relational_expression ::= relational_expression MATCH shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MATCH, 2);
+}
+relational_expression ::= relational_expression NEAR shift_expression. {
+ {
+ int max_interval;
+ GRN_INT32_POP(&efsi->max_interval_stack, max_interval);
+ grn_expr_append_const_int(efsi->ctx, efsi->e, max_interval,
+ GRN_OP_PUSH, 1);
+ }
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NEAR, 3);
+}
+relational_expression ::= relational_expression NEAR2 shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NEAR2, 2);
+}
+relational_expression ::= relational_expression SIMILAR shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SIMILAR, 2);
+}
+relational_expression ::= relational_expression TERM_EXTRACT shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_TERM_EXTRACT, 2);
+}
+relational_expression ::= relational_expression LCP shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_LCP, 2);
+}
+relational_expression ::= relational_expression PREFIX shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PREFIX, 2);
+}
+relational_expression ::= relational_expression SUFFIX shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SUFFIX, 2);
+}
+relational_expression ::= relational_expression REGEXP shift_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_REGEXP, 2);
+}
+
+shift_expression ::= additive_expression.
+shift_expression ::= shift_expression SHIFTL additive_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTL, 2);
+}
+shift_expression ::= shift_expression SHIFTR additive_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTR, 2);
+}
+shift_expression ::= shift_expression SHIFTRR additive_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SHIFTRR, 2);
+}
+
+additive_expression ::= multiplicative_expression.
+additive_expression ::= additive_expression PLUS multiplicative_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS, 2);
+}
+additive_expression ::= additive_expression MINUS multiplicative_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MINUS, 2);
+}
+
+multiplicative_expression ::= unary_expression.
+multiplicative_expression ::= multiplicative_expression STAR unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_STAR, 2);
+}
+multiplicative_expression ::= multiplicative_expression SLASH unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_SLASH, 2);
+}
+multiplicative_expression ::= multiplicative_expression MOD unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MOD, 2);
+}
+
+unary_expression ::= postfix_expression.
+unary_expression ::= DELETE unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_DELETE, 1);
+}
+unary_expression ::= INCR unary_expression. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be incremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_INCR, 1);
+ }
+}
+unary_expression ::= DECR unary_expression. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be decremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_DECR, 1);
+ }
+}
+unary_expression ::= PLUS unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS, 1);
+}
+unary_expression ::= MINUS unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MINUS, 1);
+}
+unary_expression ::= NOT unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_NOT, 1);
+}
+unary_expression ::= BITWISE_NOT unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_BITWISE_NOT, 1);
+}
+unary_expression ::= ADJUST unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_ADJUST, 1);
+}
+unary_expression ::= EXACT unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_EXACT, 1);
+}
+unary_expression ::= PARTIAL unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PARTIAL, 1);
+}
+unary_expression ::= UNSPLIT unary_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_UNSPLIT, 1);
+}
+
+postfix_expression ::= lefthand_side_expression.
+postfix_expression ::= lefthand_side_expression INCR. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be incremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_INCR_POST, 1);
+ }
+}
+postfix_expression ::= lefthand_side_expression DECR. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_expr_dfi *dfi_;
+ unsigned int const_p;
+
+ dfi_ = grn_expr_dfi_pop(e);
+ const_p = CONSTP(dfi_->code->value);
+ grn_expr_dfi_put(ctx, e, dfi_->type, dfi_->domain, dfi_->code);
+ if (const_p) {
+ ERR(GRN_SYNTAX_ERROR,
+ "constant can't be decremented: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_DECR_POST, 1);
+ }
+}
+
+lefthand_side_expression ::= call_expression.
+lefthand_side_expression ::= member_expression.
+
+call_expression ::= member_expression arguments(A). {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_CALL, A);
+}
+
+member_expression ::= primary_expression.
+member_expression ::= member_expression member_expression_part.
+
+primary_expression ::= object_literal.
+primary_expression ::= PARENL expression PARENR.
+primary_expression ::= IDENTIFIER.
+primary_expression ::= array_literal.
+primary_expression ::= DECIMAL.
+primary_expression ::= HEX_INTEGER.
+primary_expression ::= STRING.
+primary_expression ::= BOOLEAN.
+primary_expression ::= NULL.
+
+array_literal ::= BRACKETL elision BRACKETR.
+array_literal ::= BRACKETL element_list elision BRACKETR.
+array_literal ::= BRACKETL element_list BRACKETR.
+
+elision ::= COMMA.
+elision ::= elision COMMA.
+
+element_list ::= assignment_expression.
+element_list ::= elision assignment_expression.
+element_list ::= element_list elision assignment_expression.
+
+object_literal ::= BRACEL property_name_and_value_list BRACER. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr_take_obj(ctx, efsi->e, (grn_obj *)(efsi->object_literal));
+ grn_expr_append_obj(ctx, efsi->e, (grn_obj *)(efsi->object_literal),
+ GRN_OP_PUSH, 1);
+ efsi->object_literal = NULL;
+}
+
+property_name_and_value_list ::= . {
+ grn_ctx *ctx = efsi->ctx;
+
+ efsi->object_literal =
+ grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj),
+ GRN_OBJ_KEY_VAR_SIZE|GRN_OBJ_TEMPORARY|GRN_HASH_TINY);
+ if (!efsi->object_literal) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "couldn't create hash table for parsing object literal: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ }
+}
+property_name_and_value_list ::= property_name_and_value.
+property_name_and_value_list ::= property_name_and_value_list COMMA property_name_and_value.
+
+property_name_and_value ::= property_name COLON assignment_expression. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_expr *e = (grn_expr *)(efsi->e);
+ grn_obj *property = e->codes[e->codes_curr - 3].value;
+ grn_obj *value = e->codes[e->codes_curr - 1].value;
+
+ if (!efsi->object_literal) {
+ efsi->object_literal =
+ grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, sizeof(grn_obj),
+ GRN_OBJ_KEY_VAR_SIZE|GRN_OBJ_TEMPORARY|GRN_HASH_TINY);
+ }
+
+ if (!efsi->object_literal) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "couldn't create hash table for parsing object literal: <%.*s>",
+ (int)(efsi->str_end - efsi->str), efsi->str);
+ } else {
+ grn_obj *buf;
+ int added;
+ if (grn_hash_add(ctx, (grn_hash *)efsi->object_literal,
+ GRN_TEXT_VALUE(property), GRN_TEXT_LEN(property),
+ (void **)&buf, &added)) {
+ if (added) {
+ GRN_OBJ_INIT(buf, value->header.type, 0, value->header.domain);
+ GRN_TEXT_PUT(ctx, buf, GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
+ grn_expr_dfi_pop(e);
+ e->codes_curr -= 3;
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated property name: <%.*s>",
+ (int)GRN_TEXT_LEN(property),
+ GRN_TEXT_VALUE(property));
+ }
+ } else {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to add a property to object literal: <%.*s>",
+ (int)GRN_TEXT_LEN(property),
+ GRN_TEXT_VALUE(property));
+ }
+ }
+}
+
+property_name ::= STRING.
+
+member_expression_part ::= BRACKETL expression BRACKETR. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_GET_MEMBER, 2);
+}
+member_expression_part ::= DOT IDENTIFIER.
+
+arguments(A) ::= PARENL argument_list(B) PARENR. { A = B; }
+argument_list(A) ::= . { A = 0; }
+argument_list(A) ::= assignment_expression. { A = 1; }
+argument_list(A) ::= argument_list(B) COMMA assignment_expression. { A = B + 1; }
+
+output_columns(N_STACKED_COLUMNS) ::= . {
+ N_STACKED_COLUMNS = 0;
+}
+output_columns(N_STACKED_COLUMNS) ::= output_column(SUB_N_STACKED_COLUMNS). {
+ N_STACKED_COLUMNS = SUB_N_STACKED_COLUMNS;
+}
+/* Accept "column1,,,,,,column2" */
+output_columns(N_STACKED_COLUMNS) ::=
+ output_columns(SUB_N_STACKED_COLUMNS) COMMA. {
+ N_STACKED_COLUMNS = SUB_N_STACKED_COLUMNS;
+}
+output_columns(N_STACKED_COLUMNS) ::=
+ output_columns(SUB_N_STACKED_COLUMNS) COMMA
+ output_column(NEW_N_STACKED_COLUMNS). {
+ if (SUB_N_STACKED_COLUMNS == 0) {
+ N_STACKED_COLUMNS = NEW_N_STACKED_COLUMNS;
+ } else if (NEW_N_STACKED_COLUMNS == 0) {
+ N_STACKED_COLUMNS = SUB_N_STACKED_COLUMNS;
+ } else {
+ if (NEW_N_STACKED_COLUMNS == 1) {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_COMMA, 2);
+ }
+ N_STACKED_COLUMNS = 1;
+ }
+}
+
+output_column(N_STACKED_COLUMNS) ::= STAR. {
+ grn_ctx *ctx = efsi->ctx;
+ grn_obj *expr = efsi->e;
+ grn_obj *variable = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (variable) {
+ grn_id table_id = GRN_OBJ_GET_DOMAIN(variable);
+ grn_obj *table = grn_ctx_at(ctx, table_id);
+ grn_obj columns_buffer;
+ int n_columns;
+ grn_obj **columns;
+
+ GRN_PTR_INIT(&columns_buffer, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_obj_columns(ctx, table, "*", strlen("*"), &columns_buffer);
+ n_columns = GRN_BULK_VSIZE(&columns_buffer) / sizeof(grn_obj *);
+ columns = (grn_obj **)GRN_BULK_HEAD(&columns_buffer);
+
+ if (n_columns == 0) {
+ /* do nothing */
+ } else if (n_columns == 1) {
+ grn_obj *column = columns[0];
+ grn_expr_append_const(ctx, expr, column, GRN_OP_GET_VALUE, 1);
+ if (column->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, expr, column);
+ }
+ } else {
+ grn_expr *e = (grn_expr *)expr;
+ grn_bool have_column;
+ int i;
+
+ have_column = (e->codes_curr > 0);
+ for (i = 0; i < n_columns; i++) {
+ grn_obj *column = columns[i];
+ grn_expr_append_const(ctx, expr, column, GRN_OP_GET_VALUE, 1);
+ if (have_column || i > 0) {
+ grn_expr_append_op(ctx, expr, GRN_OP_COMMA, 2);
+ }
+ if (column->header.type == GRN_ACCESSOR) {
+ grn_expr_take_obj(ctx, expr, column);
+ }
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &columns_buffer);
+
+ N_STACKED_COLUMNS = n_columns;
+ } else {
+ /* TODO: report error */
+ N_STACKED_COLUMNS = 0;
+ }
+}
+output_column(N_STACKED_COLUMNS) ::= NONEXISTENT_COLUMN. {
+ N_STACKED_COLUMNS = 0;
+}
+output_column(N_STACKED_COLUMNS) ::= assignment_expression. {
+ N_STACKED_COLUMNS = 1;
+}
+
+adjuster ::= .
+adjuster ::= adjust_expression.
+adjuster ::= adjuster PLUS adjust_expression. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_PLUS, 2);
+}
+
+adjust_expression ::= adjust_match_expression.
+adjust_expression ::= adjust_match_expression STAR DECIMAL. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_STAR, 2);
+}
+
+adjust_match_expression ::= IDENTIFIER MATCH STRING. {
+ grn_expr_append_op(efsi->ctx, efsi->e, GRN_OP_MATCH, 2);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/grn_error.h b/storage/mroonga/vendor/groonga/lib/grn_error.h
new file mode 100644
index 00000000..6917de83
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_error.h
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API const char *grn_current_error_message(void);
+GRN_API const char *grn_strerror(int error_code);
+
+GRN_API grn_rc grn_windows_error_code_to_rc(int error_code);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_expr.h b/storage/mroonga/vendor/groonga/lib/grn_expr.h
new file mode 100644
index 00000000..e270e185
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_expr.h
@@ -0,0 +1,86 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SCAN_ACCESSOR (0x01)
+#define SCAN_PUSH (0x02)
+#define SCAN_POP (0x04)
+#define SCAN_PRE_CONST (0x08)
+
+typedef enum {
+ SCAN_START = 0,
+ SCAN_VAR,
+ SCAN_COL1,
+ SCAN_COL2,
+ SCAN_CONST
+} scan_stat;
+
+typedef struct _grn_scan_info scan_info;
+typedef grn_bool (*grn_scan_info_each_arg_callback)(grn_ctx *ctx, grn_obj *obj, void *user_data);
+
+void grn_expr_init_from_env(void);
+
+scan_info **grn_scan_info_build(grn_ctx *ctx, grn_obj *expr, int *n,
+ grn_operator op, grn_bool record_exist);
+
+scan_info *grn_scan_info_open(grn_ctx *ctx, int start);
+void grn_scan_info_close(grn_ctx *ctx, scan_info *si);
+void grn_scan_info_put_index(grn_ctx *ctx, scan_info *si, grn_obj *index,
+ uint32_t sid, int32_t weight,
+ grn_obj *scorer,
+ grn_obj *scorer_args_expr,
+ uint32_t scorer_args_expr_offset);
+scan_info **grn_scan_info_put_logical_op(grn_ctx *ctx, scan_info **sis, int *ip,
+ grn_operator op, int start);
+int grn_scan_info_get_flags(scan_info *si);
+void grn_scan_info_set_flags(scan_info *si, int flags);
+grn_operator grn_scan_info_get_logical_op(scan_info *si);
+void grn_scan_info_set_logical_op(scan_info *si, grn_operator logical_op);
+grn_operator grn_scan_info_get_op(scan_info *si);
+void grn_scan_info_set_op(scan_info *si, grn_operator op);
+void grn_scan_info_set_end(scan_info *si, uint32_t end);
+void grn_scan_info_set_query(scan_info *si, grn_obj *query);
+int grn_scan_info_get_max_interval(scan_info *si);
+void grn_scan_info_set_max_interval(scan_info *si, int max_interval);
+int grn_scan_info_get_similarity_threshold(scan_info *si);
+void grn_scan_info_set_similarity_threshold(scan_info *si, int similarity_threshold);
+grn_bool grn_scan_info_push_arg(scan_info *si, grn_obj *arg);
+grn_obj *grn_scan_info_get_arg(grn_ctx *ctx, scan_info *si, int i);
+int grn_scan_info_get_start_position(scan_info *si);
+void grn_scan_info_set_start_position(scan_info *si, int start);
+void grn_scan_info_reset_position(scan_info *si);
+
+int32_t grn_expr_code_get_weight(grn_ctx *ctx, grn_expr_code *ec, uint32_t *offset);
+grn_rc grn_expr_code_inspect_indented(grn_ctx *ctx,
+ grn_obj *buffer,
+ grn_expr_code *code,
+ const char *indent);
+void grn_p_expr_code(grn_ctx *ctx, grn_expr_code *code);
+
+grn_obj *grn_expr_alloc_const(grn_ctx *ctx, grn_obj *expr);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_expr_code.h b/storage/mroonga/vendor/groonga/lib/grn_expr_code.h
new file mode 100644
index 00000000..48c907d5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_expr_code.h
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+unsigned int grn_expr_code_n_used_codes(grn_ctx *ctx,
+ grn_expr_code *start,
+ grn_expr_code *target);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_expr_executor.h b/storage/mroonga/vendor/groonga/lib/grn_expr_executor.h
new file mode 100644
index 00000000..1f2a1f4e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_expr_executor.h
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_expr_executor grn_expr_executor;
+
+grn_expr_executor *grn_expr_executor_open(grn_ctx *ctx,
+ grn_obj *expr);
+grn_obj *grn_expr_executor_exec(grn_ctx *ctx,
+ grn_expr_executor *executor,
+ grn_id id);
+grn_rc grn_expr_executor_close(grn_ctx *ctx,
+ grn_expr_executor *executor);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_file_lock.h b/storage/mroonga/vendor/groonga/lib/grn_file_lock.h
new file mode 100644
index 00000000..538e88af
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_file_lock.h
@@ -0,0 +1,48 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ const char *path;
+#ifdef WIN32
+ HANDLE handle;
+#else /* WIN32 */
+ int fd;
+#endif /* WIN32 */
+} grn_file_lock;
+
+void grn_file_lock_init(grn_ctx *ctx,
+ grn_file_lock *file_lock,
+ const char *path);
+grn_bool grn_file_lock_acquire(grn_ctx *ctx,
+ grn_file_lock *file_lock,
+ int timeout,
+ const char *error_message_tag);
+void grn_file_lock_release(grn_ctx *ctx, grn_file_lock *file_lock);
+void grn_file_lock_fin(grn_ctx *ctx, grn_file_lock *file_lock);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_geo.h b/storage/mroonga/vendor/groonga/lib/grn_geo.h
new file mode 100644
index 00000000..9597336a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_geo.h
@@ -0,0 +1,200 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ii.h"
+#include "grn_db.h"
+
+#if defined(WIN32) || defined(__sun)
+# define _USE_MATH_DEFINES
+# ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+# endif
+
+# ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+# endif
+#endif /* WIN32 or __sun */
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_GEO_RESOLUTION 3600000
+#define GRN_GEO_RADIUS 6357303
+#define GRN_GEO_BES_C1 6334834
+#define GRN_GEO_BES_C2 6377397
+#define GRN_GEO_BES_C3 0.006674
+#define GRN_GEO_GRS_C1 6335439
+#define GRN_GEO_GRS_C2 6378137
+#define GRN_GEO_GRS_C3 0.006694
+#define GRN_GEO_INT2RAD(x) ((M_PI / (GRN_GEO_RESOLUTION * 180)) * (x))
+#define GRN_GEO_RAD2INT(x) ((int)(((GRN_GEO_RESOLUTION * 180) / M_PI) * (x)))
+
+#define GRN_GEO_MAX_LATITUDE 324000000 /* 90 * 60 * 60 * 1000 */
+#define GRN_GEO_MAX_LONGITUDE (648000000 - 1) /* 180 * 60 * 60 * 1000 - 1 */
+#define GRN_GEO_MIN_LATITUDE -GRN_GEO_MAX_LATITUDE
+#define GRN_GEO_MIN_LONGITUDE -GRN_GEO_MAX_LONGITUDE
+
+#define GRN_GEO_POINT_VALUE_RAW(obj) (grn_geo_point *)GRN_BULK_HEAD(obj)
+#define GRN_GEO_POINT_VALUE_RADIUS(obj,_latitude,_longitude) do {\
+ grn_geo_point *_val = (grn_geo_point *)GRN_BULK_HEAD(obj);\
+ _latitude = GRN_GEO_INT2RAD(_val->latitude);\
+ _longitude = GRN_GEO_INT2RAD(_val->longitude);\
+} while (0)
+
+#define GRN_GEO_KEY_MAX_BITS 64
+
+typedef enum {
+ GRN_GEO_APPROXIMATE_RECTANGLE,
+ GRN_GEO_APPROXIMATE_SPHERE,
+ GRN_GEO_APPROXIMATE_ELLIPSOID
+} grn_geo_approximate_type;
+
+typedef enum {
+ GRN_GEO_CURSOR_ENTRY_STATUS_NONE = 0,
+ GRN_GEO_CURSOR_ENTRY_STATUS_TOP_INCLUDED = 1 << 0,
+ GRN_GEO_CURSOR_ENTRY_STATUS_BOTTOM_INCLUDED = 1 << 1,
+ GRN_GEO_CURSOR_ENTRY_STATUS_LEFT_INCLUDED = 1 << 2,
+ GRN_GEO_CURSOR_ENTRY_STATUS_RIGHT_INCLUDED = 1 << 3,
+ GRN_GEO_CURSOR_ENTRY_STATUS_LATITUDE_INNER = 1 << 4,
+ GRN_GEO_CURSOR_ENTRY_STATUS_LONGITUDE_INNER = 1 << 5
+} grn_geo_cursor_entry_status_flag;
+
+typedef enum {
+ GRN_GEO_AREA_NORTH_EAST,
+ GRN_GEO_AREA_NORTH_WEST,
+ GRN_GEO_AREA_SOUTH_WEST,
+ GRN_GEO_AREA_SOUTH_EAST,
+ GRN_GEO_AREA_LAST
+} grn_geo_area_type;
+
+#define GRN_GEO_N_AREAS GRN_GEO_AREA_LAST
+
+typedef struct {
+ uint8_t key[sizeof(grn_geo_point)];
+ int target_bit;
+ int status_flags;
+} grn_geo_cursor_entry;
+
+typedef struct {
+ grn_geo_point top_left;
+ grn_geo_point bottom_right;
+ uint8_t top_left_key[sizeof(grn_geo_point)];
+ uint8_t bottom_right_key[sizeof(grn_geo_point)];
+ int current_entry;
+ grn_geo_cursor_entry entries[GRN_GEO_KEY_MAX_BITS];
+} grn_geo_cursor_area;
+
+typedef struct {
+ grn_db_obj obj;
+ grn_obj *pat;
+ grn_obj *index;
+ grn_geo_point top_left;
+ grn_geo_point bottom_right;
+ grn_geo_point current;
+ grn_table_cursor *pat_cursor;
+ grn_ii_cursor *ii_cursor;
+ int offset;
+ int rest;
+ int minimum_reduce_bit;
+ grn_geo_area_type current_area;
+ grn_geo_cursor_area areas[GRN_GEO_N_AREAS];
+} grn_geo_cursor_in_rectangle;
+
+grn_rc grn_geo_cursor_close(grn_ctx *ctx, grn_obj *geo_cursor);
+
+
+grn_rc grn_geo_resolve_approximate_type(grn_ctx *ctx, grn_obj *type_name,
+ grn_geo_approximate_type *type);
+
+/**
+ * grn_geo_select_in_circle:
+ * @index: the index column for TokyoGeoPoint or WGS84GeoPpoint type.
+ * @center_point: the center point of the target circle. (ShortText, Text,
+ * LongText, TokyoGeoPoint or WGS84GeoPoint)
+ * @distance: the radius of the target circle (Int32,
+ * UInt32, Int64, UInt64 or Float) or the point
+ * on the circumference of the target circle. (ShortText, Text, LongText,
+ * TokyoGeoPoint or WGS84GeoPoint)
+ * @approximate_type: the approximate type to compute
+ * distance.
+ * @res: the table to store found record IDs. It must be
+ * GRN_TABLE_HASH_KEY type table.
+ * @op: the operator for matched records.
+ *
+ * It selects records that are in the circle specified by
+ * @center_point and @distance from @center_point. Records
+ * are searched by @index. Found records are added to @res
+ * table with @op operation.
+ **/
+grn_rc grn_geo_select_in_circle(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *center_point,
+ grn_obj *distance,
+ grn_geo_approximate_type approximate_type,
+ grn_obj *res,
+ grn_operator op);
+
+grn_rc grn_selector_geo_in_circle(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op);
+grn_rc grn_selector_geo_in_rectangle(grn_ctx *ctx,
+ grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op);
+
+GRN_API grn_bool grn_geo_in_circle(grn_ctx *ctx, grn_obj *point, grn_obj *center,
+ grn_obj *radius_or_point,
+ grn_geo_approximate_type approximate_type);
+GRN_API grn_bool grn_geo_in_rectangle(grn_ctx *ctx, grn_obj *point,
+ grn_obj *top_left, grn_obj *bottom_right);
+grn_bool grn_geo_in_rectangle_raw(grn_ctx *ctx, grn_geo_point *point,
+ grn_geo_point *top_left,
+ grn_geo_point *bottom_right);
+double grn_geo_distance(grn_ctx *ctx, grn_obj *point1, grn_obj *point2,
+ grn_geo_approximate_type type);
+GRN_API double grn_geo_distance_rectangle(grn_ctx *ctx, grn_obj *point1,
+ grn_obj *point2);
+GRN_API double grn_geo_distance_sphere(grn_ctx *ctx, grn_obj *point1,
+ grn_obj *point2);
+GRN_API double grn_geo_distance_ellipsoid(grn_ctx *ctx, grn_obj *point1,
+ grn_obj *point2);
+double grn_geo_distance_rectangle_raw(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2);
+double grn_geo_distance_sphere_raw(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2);
+double grn_geo_distance_ellipsoid_raw(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2,
+ int c1, int c2, double c3);
+double grn_geo_distance_ellipsoid_raw_tokyo(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2);
+double grn_geo_distance_ellipsoid_raw_wgs84(grn_ctx *ctx,
+ grn_geo_point *point1,
+ grn_geo_point *point2);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_hash.h b/storage/mroonga/vendor/groonga/lib/grn_hash.h
new file mode 100644
index 00000000..4038909b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_hash.h
@@ -0,0 +1,378 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**** grn_tiny_array ****/
+
+/*
+ * grn_tiny_array_init() accepts a logical OR of the following flags.
+ * Note that other flags, such as (1 << 30), will be ignored.
+ *
+ * - GRN_TINY_ARRAY_CLEAR specifies to initialize a new block with zeros.
+ * It is valid only iff specified with GRN_TINY_ARRAY_USE_MALLOC.
+ * - GRN_TINY_ARRAY_THREADSAFE specifies to create a critical section when
+ * allocating memory.
+ * - GRN_TINY_ARRAY_USE_MALLOC specifies to use GRN_MALLOC/CALLOC/FREE instead
+ * of GRN_CTX_ALLOC/FREE.
+ */
+#define GRN_TINY_ARRAY_CLEAR (1 << 0)
+#define GRN_TINY_ARRAY_THREADSAFE (1 << 1)
+#define GRN_TINY_ARRAY_USE_MALLOC (1 << 2)
+
+/*
+ * - GRN_TINY_ARRAY_FACTOR is the global parameter of grn_tiny_array.
+ * - GRN_TINY_ARRAY_GET_OFFSET() returns the offset of a specified block.
+ * - GRN_TINY_ARRAY_BASE_BLOCK_SIZE is the number of elements in the first
+ * block.
+ * - GRN_TINY_ARRAY_GET_BLOCK_SIZE() returns the number of elements in a
+ * specified block.
+ * - GRN_TINY_ARRAY_NUM_BLOCKS is the maximum number of blocks.
+ */
+#define GRN_TINY_ARRAY_FACTOR 0
+#define GRN_TINY_ARRAY_GET_OFFSET(block_id) \
+ (1 << ((block_id) << GRN_TINY_ARRAY_FACTOR))
+#define GRN_TINY_ARRAY_BASE_BLOCK_SIZE \
+ (GRN_TINY_ARRAY_GET_OFFSET(1) - GRN_TINY_ARRAY_GET_OFFSET(0))
+#define GRN_TINY_ARRAY_GET_BLOCK_SIZE(block_id) \
+ (GRN_TINY_ARRAY_BASE_BLOCK_SIZE * GRN_TINY_ARRAY_GET_OFFSET(block_id))
+#define GRN_TINY_ARRAY_NUM_BLOCKS (32 >> GRN_TINY_ARRAY_FACTOR)
+
+/*
+ * grn_tiny_array uses several blocks to emulate an array.
+ * The k-th block, blocks[k - 1], consists of 2^(k-1) elements.
+ */
+typedef struct _grn_tiny_array grn_tiny_array;
+
+struct _grn_tiny_array {
+ grn_ctx *ctx;
+ grn_id max;
+ uint16_t element_size;
+ uint16_t flags;
+ void *blocks[GRN_TINY_ARRAY_NUM_BLOCKS];
+ grn_critical_section lock;
+};
+
+#define GRN_TINY_ARRAY_EACH(array, head, tail, key, value, block) do { \
+ int _block_id; \
+ const grn_id _head = (head); \
+ const grn_id _tail = (tail); \
+ for (_block_id = 0, (key) = (_head); \
+ _block_id < GRN_TINY_ARRAY_NUM_BLOCKS && (key) <= (_tail); \
+ _block_id++) { \
+ int _id = GRN_TINY_ARRAY_GET_BLOCK_SIZE(_block_id); \
+ (value) = (array)->blocks[_block_id]; \
+ if (value) { \
+ while (_id-- && (key) <= (_tail)) { \
+ { \
+ block \
+ } \
+ (key)++; \
+ (value) = (void *)((byte *)(value) + (array)->element_size); \
+ } \
+ } else { \
+ (key) += _id; \
+ } \
+ } \
+} while (0)
+
+GRN_API void grn_tiny_array_init(grn_ctx *ctx, grn_tiny_array *array,
+ uint16_t element_size, uint16_t flags);
+GRN_API void grn_tiny_array_fin(grn_tiny_array *array);
+GRN_API void *grn_tiny_array_at(grn_tiny_array *array, grn_id id);
+GRN_API grn_id grn_tiny_array_id(grn_tiny_array *array,
+ const void *element_address);
+
+/**** grn_tiny_bitmap ****/
+
+typedef struct _grn_tiny_bitmap grn_tiny_bitmap;
+
+struct _grn_tiny_bitmap {
+ grn_ctx *ctx;
+ void *blocks[GRN_TINY_ARRAY_NUM_BLOCKS];
+};
+
+/**** grn_array ****/
+
+#define GRN_ARRAY_TINY (0x01<<6)
+
+/*
+ * grn_array uses grn_io or grn_tiny_array to represent an array.
+ *
+ * To create a grn_tiny_array-based grn_array, specify the GRN_ARRAY_TINY flag
+ * to grn_array_create(). Note that a grn_tiny_array-based grn_array is not
+ * backed by a file.
+ */
+struct _grn_array {
+ grn_db_obj obj;
+ grn_ctx *ctx;
+ uint32_t value_size;
+ int32_t n_keys;
+ grn_table_sort_key *keys;
+ uint32_t *n_garbages;
+ uint32_t *n_entries;
+
+ /* For grn_io_array. */
+ grn_io *io;
+ struct grn_array_header *header;
+ uint32_t *lock;
+
+ /* For grn_tiny_array. */
+ uint32_t n_garbages_buf;
+ uint32_t n_entries_buf;
+ grn_id garbages;
+ grn_tiny_array array;
+ grn_tiny_bitmap bitmap;
+};
+
+struct _grn_array_cursor {
+ grn_db_obj obj;
+ grn_array *array;
+ grn_ctx *ctx;
+ grn_id curr_rec;
+ grn_id tail;
+ unsigned int rest;
+ int dir;
+};
+
+/*
+ * grn_array_size() returns the number of entries in an array.
+ * If the array was truncated by another process but `array` still refers to
+ * the old one, this function returns 0.
+ */
+uint32_t grn_array_size(grn_ctx *ctx, grn_array *array);
+
+uint32_t grn_array_get_flags(grn_ctx *ctx, grn_array *array);
+
+grn_rc grn_array_truncate(grn_ctx *ctx, grn_array *array);
+grn_rc grn_array_copy_sort_key(grn_ctx *ctx, grn_array *array,
+ grn_table_sort_key *keys, int n_keys);
+
+/* grn_table_queue */
+
+typedef struct _grn_table_queue grn_table_queue;
+
+struct _grn_table_queue {
+ grn_mutex mutex;
+ grn_cond cond;
+ grn_id head;
+ grn_id tail;
+ grn_id cap;
+ grn_bool unblock_requested;
+};
+
+GRN_API void grn_array_queue_lock_clear(grn_ctx *ctx, grn_array *array);
+GRN_API void grn_array_clear_curr_rec(grn_ctx *ctx, grn_array *array);
+GRN_API grn_table_queue *grn_array_queue(grn_ctx *ctx, grn_array *array);
+GRN_API uint32_t grn_table_queue_size(grn_table_queue *queue);
+GRN_API void grn_table_queue_head_increment(grn_table_queue *queue);
+GRN_API void grn_table_queue_tail_increment(grn_table_queue *queue);
+GRN_API grn_id grn_table_queue_head(grn_table_queue *queue);
+GRN_API grn_id grn_table_queue_tail(grn_table_queue *queue);
+
+/**** grn_hash ****/
+
+#define GRN_HASH_MAX_KEY_SIZE_NORMAL GRN_TABLE_MAX_KEY_SIZE
+#define GRN_HASH_MAX_KEY_SIZE_LARGE (0xffff)
+
+#define GRN_HASH_IS_LARGE_KEY(hash)\
+ ((hash)->key_size > GRN_HASH_MAX_KEY_SIZE_NORMAL)
+
+typedef struct _grn_hash_header_common grn_hash_header_common;
+typedef struct _grn_hash_header_normal grn_hash_header_normal;
+typedef struct _grn_hash_header_large grn_hash_header_large;
+
+struct _grn_hash {
+ grn_db_obj obj;
+ grn_ctx *ctx;
+ uint32_t key_size;
+ grn_encoding encoding;
+ uint32_t value_size;
+ uint32_t entry_size;
+ uint32_t *n_garbages;
+ uint32_t *n_entries;
+ uint32_t *max_offset;
+ grn_obj *tokenizer;
+ grn_obj *normalizer;
+ grn_obj token_filters;
+
+ /* For grn_io_hash. */
+ grn_io *io;
+ union {
+ grn_hash_header_common *common;
+ grn_hash_header_normal *normal;
+ grn_hash_header_large *large;
+ } header;
+ uint32_t *lock;
+ // uint32_t nref;
+ // unsigned int max_n_subrecs;
+ // unsigned int record_size;
+ // unsigned int subrec_size;
+ // grn_rec_unit record_unit;
+ // grn_rec_unit subrec_unit;
+ // uint8_t arrayp;
+ // grn_recordh *curr_rec;
+ // grn_set_cursor *cursor;
+ // int limit;
+ // void *userdata;
+ // grn_id subrec_id;
+
+ /* For grn_tiny_hash. */
+ uint32_t max_offset_;
+ uint32_t n_garbages_;
+ uint32_t n_entries_;
+ grn_id *index;
+ grn_id garbages;
+ grn_tiny_array a;
+ grn_tiny_bitmap bitmap;
+};
+
+#define GRN_HASH_HEADER_COMMON_FIELDS\
+ uint32_t flags;\
+ grn_encoding encoding;\
+ uint32_t key_size;\
+ uint32_t value_size;\
+ grn_id tokenizer;\
+ uint32_t curr_rec;\
+ uint32_t curr_key_normal;\
+ uint32_t idx_offset;\
+ uint32_t entry_size;\
+ uint32_t max_offset;\
+ uint32_t n_entries;\
+ uint32_t n_garbages;\
+ uint32_t lock;\
+ grn_id normalizer;\
+ uint32_t truncated;\
+ uint64_t curr_key_large;\
+ uint32_t reserved[12]
+
+struct _grn_hash_header_common {
+ GRN_HASH_HEADER_COMMON_FIELDS;
+};
+
+struct _grn_hash_header_normal {
+ GRN_HASH_HEADER_COMMON_FIELDS;
+ grn_id garbages[GRN_HASH_MAX_KEY_SIZE_NORMAL];
+ grn_table_queue queue;
+};
+
+struct _grn_hash_header_large {
+ GRN_HASH_HEADER_COMMON_FIELDS;
+ grn_id garbages[GRN_HASH_MAX_KEY_SIZE_LARGE];
+ grn_table_queue queue;
+};
+
+struct _grn_hash_cursor {
+ grn_db_obj obj;
+ grn_hash *hash;
+ grn_ctx *ctx;
+ grn_id curr_rec;
+ grn_id tail;
+ unsigned int rest;
+ int dir;
+};
+
+/* deprecated */
+
+#define GRN_TABLE_SORT_BY_KEY 0
+#define GRN_TABLE_SORT_BY_ID (1L<<1)
+#define GRN_TABLE_SORT_BY_VALUE (1L<<2)
+#define GRN_TABLE_SORT_RES_ID 0
+#define GRN_TABLE_SORT_RES_KEY (1L<<3)
+#define GRN_TABLE_SORT_AS_BIN 0
+#define GRN_TABLE_SORT_AS_NUMBER (1L<<4)
+#define GRN_TABLE_SORT_AS_SIGNED 0
+#define GRN_TABLE_SORT_AS_UNSIGNED (1L<<5)
+#define GRN_TABLE_SORT_AS_INT32 0
+#define GRN_TABLE_SORT_AS_INT64 (1L<<6)
+#define GRN_TABLE_SORT_NO_PROC 0
+#define GRN_TABLE_SORT_WITH_PROC (1L<<7)
+
+typedef struct _grn_table_sort_optarg grn_table_sort_optarg;
+
+struct _grn_table_sort_optarg {
+ grn_table_sort_flags flags;
+ int (*compar)(grn_ctx *ctx,
+ grn_obj *table1, void *target1, unsigned int target1_size,
+ grn_obj *table2, void *target2, unsigned int target2_size,
+ void *compare_arg);
+ void *compar_arg;
+ grn_obj *proc;
+ int offset;
+};
+
+GRN_API int grn_hash_sort(grn_ctx *ctx, grn_hash *hash, int limit,
+ grn_array *result, grn_table_sort_optarg *optarg);
+
+grn_rc grn_hash_lock(grn_ctx *ctx, grn_hash *hash, int timeout);
+grn_rc grn_hash_unlock(grn_ctx *ctx, grn_hash *hash);
+grn_rc grn_hash_clear_lock(grn_ctx *ctx, grn_hash *hash);
+
+#define GRN_HASH_SIZE(hash) (*((hash)->n_entries))
+
+/* private */
+typedef enum {
+ grn_rec_document = 0,
+ grn_rec_section,
+ grn_rec_position,
+ grn_rec_userdef,
+ grn_rec_none
+} grn_rec_unit;
+
+GRN_API grn_rc grn_hash_truncate(grn_ctx *ctx, grn_hash *hash);
+
+int grn_rec_unit_size(grn_rec_unit unit, int rec_size);
+
+const char * _grn_hash_key(grn_ctx *ctx, grn_hash *hash, grn_id id, uint32_t *key_size);
+
+int grn_hash_get_key_value(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ void *keybuf, int bufsize, void *valuebuf);
+
+int _grn_hash_get_key_value(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ void **key, void **value);
+
+grn_id grn_hash_next(grn_ctx *ctx, grn_hash *hash, grn_id id);
+
+/* only valid for hash tables, GRN_OBJ_KEY_VAR_SIZE && GRN_HASH_TINY */
+const char *_grn_hash_strkey_by_val(void *v, uint16_t *size);
+
+const char *grn_hash_get_value_(grn_ctx *ctx, grn_hash *hash, grn_id id, uint32_t *size);
+
+grn_rc grn_hash_remove(grn_ctx *ctx, const char *path);
+grn_rc grn_array_remove(grn_ctx *ctx, const char *path);
+
+grn_id grn_hash_at(grn_ctx *ctx, grn_hash *hash, grn_id id);
+grn_id grn_array_at(grn_ctx *ctx, grn_array *array, grn_id id);
+
+void grn_hash_check(grn_ctx *ctx, grn_hash *hash);
+
+grn_bool grn_hash_is_large_total_key_size(grn_ctx *ctx, grn_hash *hash);
+
+uint64_t grn_hash_total_key_size(grn_ctx *ctx, grn_hash *hash);
+uint64_t grn_hash_max_total_key_size(grn_ctx *ctx, grn_hash *hash);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ii.h b/storage/mroonga/vendor/groonga/lib/grn_ii.h
new file mode 100644
index 00000000..0598c9e7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ii.h
@@ -0,0 +1,192 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+/* "ii" is for inverted index */
+
+#include "grn.h"
+#include "grn_hash.h"
+#include "grn_io.h"
+#include "grn_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _grn_ii {
+ grn_db_obj obj;
+ grn_io *seg; /* I/O for a variety of segments */
+ grn_io *chunk; /* I/O for posting chunks */
+ grn_obj *lexicon; /* Lexicon table */
+ grn_table_flags lflags;
+ grn_encoding encoding; /* Character encoding */
+ /* This member is used for matching */
+ uint32_t n_elements; /* Number of elements in postings */
+ /* rid, [sid], tf, [weight] and [pos] */
+ struct grn_ii_header *header;
+};
+
+/* BGQ is buffer garbage queue? */
+#define GRN_II_BGQSIZE 16
+#define GRN_II_MAX_LSEG 0x10000
+#define GRN_II_W_TOTAL_CHUNK 40
+#define GRN_II_W_CHUNK 22
+#define GRN_II_W_LEAST_CHUNK (GRN_II_W_TOTAL_CHUNK - 32)
+#define GRN_II_MAX_CHUNK (1 << (GRN_II_W_TOTAL_CHUNK - GRN_II_W_CHUNK))
+#define GRN_II_N_CHUNK_VARIATION (GRN_II_W_CHUNK - GRN_II_W_LEAST_CHUNK)
+
+#define GRN_II_MAX_CHUNK_SMALL (1 << (GRN_II_W_TOTAL_CHUNK - GRN_II_W_CHUNK - 8))
+/* GRN_II_MAX_CHUNK_MEDIUM has enough space for the following source:
+ * * Single source.
+ * * Source is a fixed size column or _key of a table.
+ * * Source column is a scalar column.
+ * * Lexicon doesn't have tokenizer.
+ */
+#define GRN_II_MAX_CHUNK_MEDIUM (1 << (GRN_II_W_TOTAL_CHUNK - GRN_II_W_CHUNK - 4))
+
+#define GRN_II_PSEG_NOT_ASSIGNED 0xffffffff
+
+struct grn_ii_header {
+ uint64_t total_chunk_size;
+ uint64_t bmax;
+ uint32_t flags;
+ uint32_t amax;
+ uint32_t smax;
+ uint32_t param1;
+ uint32_t param2;
+ uint32_t pnext;
+ uint32_t bgqhead;
+ uint32_t bgqtail;
+ uint32_t bgqbody[GRN_II_BGQSIZE];
+ uint32_t reserved[288];
+ uint32_t ainfo[GRN_II_MAX_LSEG]; /* array info */
+ uint32_t binfo[GRN_II_MAX_LSEG]; /* buffer info */
+ uint32_t free_chunks[GRN_II_N_CHUNK_VARIATION + 1];
+ uint32_t garbages[GRN_II_N_CHUNK_VARIATION + 1];
+ uint32_t ngarbages[GRN_II_N_CHUNK_VARIATION + 1];
+ uint8_t chunks[GRN_II_MAX_CHUNK >> 3];
+};
+
+struct _grn_ii_pos {
+ struct _grn_ii_pos *next;
+ uint32_t pos;
+};
+
+struct _grn_ii_updspec {
+ uint32_t rid;
+ uint32_t sid;
+ int32_t weight;
+ int32_t tf; /* number of postings successfully stored to index */
+ int32_t atf; /* actual number of postings */
+ int32_t offset;
+ struct _grn_ii_pos *pos;
+ struct _grn_ii_pos *tail;
+ /* grn_vgram_vnode *vnodes; */
+};
+
+typedef struct _grn_ii_updspec grn_ii_updspec;
+
+void grn_ii_init_from_env(void);
+
+GRN_API grn_ii *grn_ii_create(grn_ctx *ctx, const char *path, grn_obj *lexicon,
+ uint32_t flags);
+GRN_API grn_ii *grn_ii_open(grn_ctx *ctx, const char *path, grn_obj *lexicon);
+GRN_API grn_rc grn_ii_close(grn_ctx *ctx, grn_ii *ii);
+GRN_API grn_rc grn_ii_remove(grn_ctx *ctx, const char *path);
+grn_rc grn_ii_info(grn_ctx *ctx, grn_ii *ii, uint64_t *seg_size, uint64_t *chunk_size);
+grn_column_flags grn_ii_get_flags(grn_ctx *ctx, grn_ii *ii);
+grn_rc grn_ii_update_one(grn_ctx *ctx, grn_ii *ii, uint32_t key, grn_ii_updspec *u,
+ grn_hash *h);
+grn_rc grn_ii_delete_one(grn_ctx *ctx, grn_ii *ii, uint32_t key, grn_ii_updspec *u,
+ grn_hash *h);
+grn_ii_updspec *grn_ii_updspec_open(grn_ctx *ctx, uint32_t rid, uint32_t sid);
+grn_rc grn_ii_updspec_close(grn_ctx *ctx, grn_ii_updspec *u);
+grn_rc grn_ii_updspec_add(grn_ctx *ctx, grn_ii_updspec *u, int pos, int32_t weight);
+int grn_ii_updspec_cmp(grn_ii_updspec *a, grn_ii_updspec *b);
+
+void grn_ii_expire(grn_ctx *ctx, grn_ii *ii);
+grn_rc grn_ii_flush(grn_ctx *ctx, grn_ii *ii);
+size_t grn_ii_get_disk_usage(grn_ctx *ctx, grn_ii *ii);
+
+grn_ii_cursor *grn_ii_cursor_openv1(grn_ii *ii, uint32_t key);
+grn_rc grn_ii_cursor_openv2(grn_ii_cursor **cursors, int ncursors);
+
+uint32_t grn_ii_max_section(grn_ii *ii);
+
+const char *grn_ii_path(grn_ii *ii);
+grn_obj *grn_ii_lexicon(grn_ii *ii);
+
+/*
+grn_rc grn_ii_upd(grn_ctx *ctx, grn_ii *ii, grn_id rid, grn_vgram *vgram,
+ const char *oldvalue, unsigned int oldvalue_len,
+ const char *newvalue, unsigned int newvalue_len);
+grn_rc grn_ii_update(grn_ctx *ctx, grn_ii *ii, grn_id rid, grn_vgram *vgram,
+ unsigned int section,
+ grn_values *oldvalues, grn_values *newvalues);
+*/
+
+typedef struct _grn_select_optarg grn_select_optarg;
+
+struct _grn_select_optarg {
+ grn_operator mode;
+ int similarity_threshold;
+ int max_interval;
+ int *weight_vector;
+ int vector_size;
+ int (*func)(grn_ctx *, grn_hash *, const void *, int, void *);
+ void *func_arg;
+ int max_size;
+ grn_obj *scorer;
+ grn_obj *scorer_args_expr;
+ unsigned int scorer_args_expr_offset;
+ grn_fuzzy_search_optarg fuzzy;
+ grn_match_info *match_info;
+};
+
+GRN_API grn_rc grn_ii_column_update(grn_ctx *ctx, grn_ii *ii, grn_id id,
+ unsigned int section, grn_obj *oldvalue,
+ grn_obj *newvalue, grn_obj *posting);
+grn_rc grn_ii_term_extract(grn_ctx *ctx, grn_ii *ii, const char *string,
+ unsigned int string_len, grn_hash *s,
+ grn_operator op, grn_select_optarg *optarg);
+grn_rc grn_ii_similar_search(grn_ctx *ctx, grn_ii *ii, const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_select_optarg *optarg);
+GRN_API grn_rc grn_ii_select(grn_ctx *ctx, grn_ii *ii, const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_select_optarg *optarg);
+grn_rc grn_ii_sel(grn_ctx *ctx, grn_ii *ii, const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_search_optarg *optarg);
+
+void grn_ii_resolve_sel_and(grn_ctx *ctx, grn_hash *s, grn_operator op);
+
+grn_rc grn_ii_at(grn_ctx *ctx, grn_ii *ii, grn_id id, grn_hash *s, grn_operator op);
+
+void grn_ii_inspect_values(grn_ctx *ctx, grn_ii *ii, grn_obj *buf);
+void grn_ii_cursor_inspect(grn_ctx *ctx, grn_ii_cursor *c, grn_obj *buf);
+
+grn_rc grn_ii_truncate(grn_ctx *ctx, grn_ii *ii);
+grn_rc grn_ii_build(grn_ctx *ctx, grn_ii *ii, uint64_t sparsity);
+
+typedef struct grn_ii_builder_options grn_ii_builder_options;
+
+grn_rc grn_ii_build2(grn_ctx *ctx, grn_ii *ii,
+ const grn_ii_builder_options *options);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_index_column.h b/storage/mroonga/vendor/groonga/lib/grn_index_column.h
new file mode 100644
index 00000000..b9142d5c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_index_column.h
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_index_column_init_from_env(void);
+grn_rc grn_index_column_build(grn_ctx *ctx, grn_obj *index_column);
+grn_rc grn_index_column_rebuild(grn_ctx *ctx, grn_obj *index_column);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_io.h b/storage/mroonga/vendor/groonga/lib/grn_io.h
new file mode 100644
index 00000000..bc5ecf7f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_io.h
@@ -0,0 +1,487 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_error.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+# define GRN_IO_FILE_CREATE_MODE (GENERIC_READ | GENERIC_WRITE)
+#else /* WIN32 */
+# define GRN_IO_FILE_CREATE_MODE 0644
+#endif /* WIN32 */
+
+typedef enum {
+ grn_io_rdonly,
+ grn_io_wronly,
+ grn_io_rdwr
+} grn_io_rw_mode;
+
+typedef enum {
+ grn_io_auto,
+ grn_io_manual
+} grn_io_mode;
+
+/**** grn_io ****/
+
+typedef struct _grn_io grn_io;
+
+typedef struct {
+ grn_io *io;
+ grn_ctx *ctx;
+ uint8_t mode;
+ uint8_t tiny_p;
+ uint32_t pseg;
+ uint32_t segment;
+ uint32_t offset;
+ uint32_t size;
+ uint32_t nseg;
+ off_t pos;
+ void *addr;
+ uint32_t diff;
+ int32_t cached;
+#ifdef WIN32
+ HANDLE fmo;
+#endif /* WIN32 */
+ void *uncompressed_value;
+} grn_io_win;
+
+typedef struct {
+ void *map;
+ uint32_t nref;
+ uint32_t count;
+#ifdef WIN32
+ HANDLE fmo;
+#endif /* WIN32 */
+} grn_io_mapinfo;
+
+typedef struct _grn_io_array_info grn_io_array_info;
+
+struct _grn_io_header {
+ char idstr[16];
+ uint32_t type;
+ uint32_t version;
+ uint32_t flags;
+ uint32_t header_size;
+ uint32_t segment_size;
+ uint32_t max_segment;
+ uint32_t n_arrays;
+ uint32_t lock;
+ uint64_t curr_size;
+ uint32_t segment_tail;
+ uint32_t last_modified;
+};
+
+struct _grn_io {
+ char path[PATH_MAX];
+ struct _grn_io_header *header;
+ byte *user_header;
+ grn_io_mapinfo *maps;
+ uint32_t base;
+ uint32_t base_seg;
+ grn_io_mode mode;
+ struct _grn_io_fileinfo *fis;
+ grn_io_array_info *ainfo;
+ uint32_t max_map_seg;
+ uint32_t nmaps;
+ uint32_t nref;
+ uint32_t count;
+ uint8_t flags;
+ uint32_t *lock;
+};
+
+GRN_API grn_io *grn_io_create(grn_ctx *ctx, const char *path,
+ uint32_t header_size, uint32_t segment_size,
+ uint32_t max_segment, grn_io_mode mode,
+ unsigned int flags);
+grn_io *grn_io_open(grn_ctx *ctx, const char *path, grn_io_mode mode);
+GRN_API grn_rc grn_io_close(grn_ctx *ctx, grn_io *io);
+grn_rc grn_io_remove(grn_ctx *ctx, const char *path);
+grn_rc grn_io_remove_if_exist(grn_ctx *ctx, const char *path);
+grn_rc grn_io_size(grn_ctx *ctx, grn_io *io, uint64_t *size);
+grn_rc grn_io_rename(grn_ctx *ctx, const char *old_name, const char *new_name);
+GRN_API void *grn_io_header(grn_io *io);
+
+void *grn_io_win_map(grn_io *io, grn_ctx *ctx, grn_io_win *iw, uint32_t segment,
+ uint32_t offset, uint32_t size, grn_io_rw_mode mode);
+grn_rc grn_io_win_unmap(grn_io_win *iw);
+
+typedef struct _grn_io_ja_einfo grn_io_ja_einfo;
+typedef struct _grn_io_ja_ehead grn_io_ja_ehead;
+
+struct _grn_io_ja_einfo {
+ uint32_t pos;
+ uint32_t size;
+};
+
+struct _grn_io_ja_ehead {
+ uint32_t size;
+ uint32_t key;
+};
+
+grn_rc grn_io_read_ja(grn_io *io, grn_ctx *ctx, grn_io_ja_einfo *einfo, uint32_t epos,
+ uint32_t key, uint32_t segment, uint32_t offset,
+ void **value, uint32_t *value_len);
+grn_rc grn_io_write_ja(grn_io *io, grn_ctx *ctx,
+ uint32_t key, uint32_t segment, uint32_t offset,
+ void *value, uint32_t value_len);
+
+grn_rc grn_io_write_ja_ehead(grn_io *io, grn_ctx *ctx, uint32_t key,
+ uint32_t segment, uint32_t offset, uint32_t value_len);
+
+#define GRN_TABLE_ADD (0x01<<6)
+#define GRN_TABLE_ADDED (0x01<<7)
+
+#define GRN_IO_MAX_RETRY (0x10000)
+#define GRN_IO_MAX_REF (0x80000000)
+
+#define GRN_IO_EXPIRE_GTICK (0x01)
+#define GRN_IO_EXPIRE_SEGMENT (0x02)
+#define GRN_IO_TEMPORARY (0x04)
+
+void grn_io_seg_map_(grn_ctx *ctx, grn_io *io, uint32_t segno, grn_io_mapinfo *info);
+
+/* arguments must be validated by caller;
+ * io mustn't be NULL;
+ * segno must be in valid range;
+ * addr must be set NULL;
+ */
+#define GRN_IO_SEG_REF(io,segno,addr) do {\
+ grn_io_mapinfo *info = &(io)->maps[segno];\
+ uint32_t nref, retry, *pnref = &info->nref;\
+ if (io->flags & GRN_IO_EXPIRE_SEGMENT) {\
+ if (io->flags & GRN_IO_EXPIRE_GTICK) {\
+ for (retry = 0; !info->map || info->count != grn_gtick; retry++) {\
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);\
+ if (nref) {\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ if (retry >= GRN_IO_MAX_RETRY) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "deadlock detected! in GRN_IO_SEG_REF(%p, %u)", io, segno);\
+ break;\
+ }\
+ GRN_FUTEX_WAIT(pnref);\
+ } else {\
+ info->count = grn_gtick;\
+ if (!info->map) {\
+ grn_io_seg_map_(ctx, io, segno, info);\
+ if (!info->map) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "mmap failed! in GRN_IO_SEG_REF(%p, %u): %s",\
+ io, segno, grn_current_error_message());\
+ }\
+ }\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ GRN_FUTEX_WAKE(pnref);\
+ break;\
+ }\
+ }\
+ } else {\
+ for (retry = 0;; retry++) {\
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);\
+ if (nref >= GRN_IO_MAX_REF) {\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ if (retry >= GRN_IO_MAX_RETRY) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "deadlock detected!! in GRN_IO_SEG_REF(%p, %u, %u)",\
+ io, segno, nref);\
+ *pnref = 0; /* force reset */ \
+ break;\
+ }\
+ GRN_FUTEX_WAIT(pnref);\
+ continue;\
+ }\
+ if (nref >= 0x40000000) {\
+ ALERT("strange nref value!! in GRN_IO_SEG_REF(%p, %u, %u)",\
+ io, segno, nref); \
+ }\
+ if (!info->map) {\
+ if (nref) {\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ if (retry >= GRN_IO_MAX_RETRY) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "deadlock detected!!! in GRN_IO_SEG_REF(%p, %u, %u)",\
+ io, segno, nref);\
+ break;\
+ }\
+ GRN_FUTEX_WAIT(pnref);\
+ continue;\
+ } else {\
+ grn_io_seg_map_(ctx, io, segno, info);\
+ if (!info->map) {\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "mmap failed!!! in GRN_IO_SEG_REF(%p, %u, %u): %s",\
+ io, segno, nref, grn_current_error_message());\
+ }\
+ \
+ GRN_FUTEX_WAKE(pnref);\
+ }\
+ }\
+ break;\
+ }\
+ info->count = grn_gtick;\
+ }\
+ } else {\
+ for (retry = 0; !info->map; retry++) {\
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);\
+ if (nref) {\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ if (retry >= GRN_IO_MAX_RETRY) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "deadlock detected!!!! in GRN_IO_SEG_REF(%p, %u)",\
+ io, segno);\
+ break;\
+ }\
+ GRN_FUTEX_WAIT(pnref);\
+ } else {\
+ if (!info->map) {\
+ grn_io_seg_map_(ctx, io, segno, info);\
+ if (!info->map) {\
+ GRN_LOG(ctx, GRN_LOG_CRIT,\
+ "mmap failed!!!! in GRN_IO_SEG_REF(%p, %u): %s",\
+ io, segno, grn_current_error_message());\
+ }\
+ }\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ GRN_FUTEX_WAKE(pnref);\
+ break;\
+ }\
+ }\
+ info->count = grn_gtick;\
+ }\
+ addr = info->map;\
+} while (0)
+
+#define GRN_IO_SEG_UNREF(io,segno) do {\
+ if (GRN_IO_EXPIRE_SEGMENT ==\
+ (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {\
+ uint32_t nref, *pnref = &(io)->maps[segno].nref;\
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);\
+ }\
+} while (0)
+
+uint32_t grn_io_base_seg(grn_io *io);
+const char *grn_io_path(grn_io *io);
+
+typedef struct _grn_io_array_spec grn_io_array_spec;
+
+struct _grn_io_array_spec {
+ uint32_t w_of_element;
+ uint32_t max_n_segments;
+};
+
+struct _grn_io_array_info {
+ uint32_t w_of_elm_in_a_segment;
+ uint32_t elm_mask_in_a_segment;
+ uint32_t max_n_segments;
+ uint32_t element_size;
+ uint32_t *segments;
+ void **addrs;
+};
+
+grn_io *grn_io_create_with_array(grn_ctx *ctx, const char *path, uint32_t header_size,
+ uint32_t segment_size, grn_io_mode mode,
+ int n_arrays, grn_io_array_spec *array_specs);
+
+void *grn_io_array_at(grn_ctx *ctx, grn_io *io, uint32_t array, off_t offset, int *flags);
+
+void grn_io_segment_alloc(grn_ctx *ctx, grn_io *io, grn_io_array_info *ai,
+ uint32_t lseg, int *flags, void **p);
+
+GRN_API grn_rc grn_io_lock(grn_ctx *ctx, grn_io *io, int timeout);
+GRN_API void grn_io_unlock(grn_io *io);
+void grn_io_clear_lock(grn_io *io);
+uint32_t grn_io_is_locked(grn_io *io);
+grn_bool grn_io_is_corrupt(grn_ctx *ctx, grn_io *io);
+size_t grn_io_get_disk_usage(grn_ctx *ctx, grn_io *io);
+
+#define GRN_IO_ARRAY_AT(io,array,offset,flags,res) do {\
+ grn_io_array_info *ainfo = &(io)->ainfo[array];\
+ uint32_t lseg = (offset) >> ainfo->w_of_elm_in_a_segment;\
+ void **p_ = &ainfo->addrs[lseg];\
+ if (!*p_) {\
+ grn_io_segment_alloc(ctx, (io), ainfo, lseg, (flags), p_);\
+ if (!*p_) { (res) = NULL; break; }\
+ }\
+ *((byte **)(&(res))) = (((byte *)*p_) + \
+ (((offset) & ainfo->elm_mask_in_a_segment) * ainfo->element_size));\
+} while (0)
+
+#define GRN_IO_ARRAY_BIT_AT(io,array,offset,res) do {\
+ uint8_t *ptr_;\
+ int flags_ = 0;\
+ GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
+ res = ptr_ ? ((*ptr_ >> ((offset) & 7)) & 1) : 0;\
+} while (0)
+
+#define GRN_IO_ARRAY_BIT_ON(io,array,offset) do {\
+ uint8_t *ptr_;\
+ int flags_ = GRN_TABLE_ADD;\
+ GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
+ if (ptr_) { *ptr_ |= (1 << ((offset) & 7)); }\
+} while (0)
+
+#define GRN_IO_ARRAY_BIT_OFF(io,array,offset) do {\
+ uint8_t *ptr_;\
+ int flags_ = GRN_TABLE_ADD;\
+ GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
+ if (ptr_) { *ptr_ &= ~(1 << ((offset) & 7)); }\
+} while (0)
+
+#define GRN_IO_ARRAY_BIT_FLIP(io,array,offset) do {\
+ uint8_t *ptr_;\
+ int flags_ = GRN_TABLE_ADD;\
+ GRN_IO_ARRAY_AT((io), (array), ((offset) >> 3) + 1, &flags_, ptr_);\
+ if (ptr_) { *ptr_ ^= (1 << ((offset) & 7)); }\
+} while (0)
+
+void *grn_io_anon_map(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length);
+void grn_io_anon_unmap(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length);
+uint32_t grn_io_detect_type(grn_ctx *ctx, const char *path);
+grn_rc grn_io_set_type(grn_io *io, uint32_t type);
+uint32_t grn_io_get_type(grn_io *io);
+
+void grn_io_init_from_env(void);
+
+uint32_t grn_io_expire(grn_ctx *ctx, grn_io *io, int count_thresh, uint32_t limit);
+
+grn_rc grn_io_flush(grn_ctx *ctx, grn_io *io);
+
+/* encode/decode */
+
+#define GRN_B_ENC(v,p) do {\
+ uint8_t *_p = (uint8_t *)p; \
+ uint32_t _v = v; \
+ if (_v < 0x8f) { \
+ *_p++ = _v; \
+ } else if (_v < 0x408f) { \
+ _v -= 0x8f; \
+ *_p++ = 0xc0 + (_v >> 8); \
+ *_p++ = _v & 0xff; \
+ } else if (_v < 0x20408f) { \
+ _v -= 0x408f; \
+ *_p++ = 0xa0 + (_v >> 16); \
+ *_p++ = (_v >> 8) & 0xff; \
+ *_p++ = _v & 0xff; \
+ } else if (_v < 0x1020408f) { \
+ _v -= 0x20408f; \
+ *_p++ = 0x90 + (_v >> 24); \
+ *_p++ = (_v >> 16) & 0xff; \
+ *_p++ = (_v >> 8) & 0xff; \
+ *_p++ = _v & 0xff; \
+ } else { \
+ *_p++ = 0x8f; \
+ grn_memcpy(_p, &_v, sizeof(uint32_t));\
+ _p += sizeof(uint32_t); \
+ } \
+ p = _p; \
+} while (0)
+
+#define GRN_B_ENC_SIZE(v) \
+ ((v) < 0x8f ? 1 : ((v) < 0x408f ? 2 : ((v) < 0x20408f ? 3 : ((v) < 0x1020408f ? 4 : 5))))
+
+#define GRN_B_DEC(v,p) do { \
+ uint8_t *_p = (uint8_t *)p; \
+ uint32_t _v = *_p++; \
+ switch (_v >> 4) { \
+ case 0x08 : \
+ if (_v == 0x8f) { \
+ grn_memcpy(&_v, _p, sizeof(uint32_t));\
+ _p += sizeof(uint32_t); \
+ } \
+ break; \
+ case 0x09 : \
+ _v = (_v - 0x90) * 0x100 + *_p++; \
+ _v = _v * 0x100 + *_p++; \
+ _v = _v * 0x100 + *_p++ + 0x20408f; \
+ break; \
+ case 0x0a : \
+ case 0x0b : \
+ _v = (_v - 0xa0) * 0x100 + *_p++; \
+ _v = _v * 0x100 + *_p++ + 0x408f; \
+ break; \
+ case 0x0c : \
+ case 0x0d : \
+ case 0x0e : \
+ case 0x0f : \
+ _v = (_v - 0xc0) * 0x100 + *_p++ + 0x8f; \
+ break; \
+ } \
+ v = _v; \
+ p = _p; \
+} while (0)
+
+#define GRN_B_SKIP(p) do { \
+ uint8_t *_p = (uint8_t *)p; \
+ uint32_t _v = *_p++; \
+ switch (_v >> 4) { \
+ case 0x08 : \
+ if (_v == 0x8f) { \
+ _p += sizeof(uint32_t); \
+ } \
+ break; \
+ case 0x09 : \
+ _p += 3; \
+ break; \
+ case 0x0a : \
+ case 0x0b : \
+ _p += 2; \
+ break; \
+ case 0x0c : \
+ case 0x0d : \
+ case 0x0e : \
+ case 0x0f : \
+ _p += 1; \
+ break; \
+ } \
+ p = _p; \
+} while (0)
+
+#define GRN_B_COPY(p2,p1) do { \
+ uint32_t size = 0, _v = *p1++; \
+ *p2++ = _v; \
+ switch (_v >> 4) { \
+ case 0x08 : \
+ size = (_v == 0x8f) ? 4 : 0; \
+ break; \
+ case 0x09 : \
+ size = 3; \
+ break; \
+ case 0x0a : \
+ case 0x0b : \
+ size = 2; \
+ break; \
+ case 0x0c : \
+ case 0x0d : \
+ case 0x0e : \
+ case 0x0f : \
+ size = 1; \
+ break; \
+ } \
+ while (size--) { *p2++ = *p1++; } \
+} while (0)
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_load.h b/storage/mroonga/vendor/groonga/lib/grn_load.h
new file mode 100644
index 00000000..a3b909b2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_load.h
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_raw_string.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_JSON_LOAD_OPEN_BRACKET 0x40000000
+#define GRN_JSON_LOAD_OPEN_BRACE 0x40000001
+
+typedef struct grn_load_input_ {
+ grn_content_type type;
+ grn_raw_string table;
+ grn_raw_string columns;
+ grn_raw_string values;
+ grn_raw_string if_exists;
+ grn_raw_string each;
+ grn_bool output_ids;
+ grn_bool output_errors;
+ uint32_t emit_level;
+} grn_load_input;
+
+void grn_load_internal(grn_ctx *ctx, grn_load_input *input);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_logger.h b/storage/mroonga/vendor/groonga/lib/grn_logger.h
new file mode 100644
index 00000000..58d745cf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_logger.h
@@ -0,0 +1,35 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_logger_init(void);
+void grn_logger_fin(grn_ctx *ctx);
+
+void grn_query_logger_init(void);
+void grn_query_logger_fin(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_mrb.h b/storage/mroonga/vendor/groonga/lib/grn_mrb.h
new file mode 100644
index 00000000..d1e20a66
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_mrb.h
@@ -0,0 +1,42 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+
+#ifdef GRN_WITH_MRUBY
+# include <mruby.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_init_from_env(void);
+
+#ifdef GRN_WITH_MRUBY
+GRN_API mrb_value grn_mrb_load(grn_ctx *ctx, const char *path);
+GRN_API const char *grn_mrb_get_system_ruby_scripts_dir(grn_ctx *ctx);
+grn_bool grn_mrb_is_order_by_estimated_size_enabled(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_msgpack.h b/storage/mroonga/vendor/groonga/lib/grn_msgpack.h
new file mode 100644
index 00000000..3452d588
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_msgpack.h
@@ -0,0 +1,46 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#ifdef GRN_WITH_MESSAGE_PACK
+# include <msgpack.h>
+
+# if MSGPACK_VERSION_MAJOR < 1
+typedef unsigned int msgpack_size_t;
+
+# define msgpack_pack_str(packer, size) msgpack_pack_raw(packer, size)
+# define msgpack_pack_str_body(packer, value, size) \
+ msgpack_pack_raw_body(packer, value, size)
+
+# define MSGPACK_OBJECT_STR MSGPACK_OBJECT_RAW
+# define MSGPACK_OBJECT_FLOAT MSGPACK_OBJECT_DOUBLE
+
+# define MSGPACK_OBJECT_STR_PTR(object) (object)->via.raw.ptr
+# define MSGPACK_OBJECT_STR_SIZE(object) (object)->via.raw.size
+
+# define MSGPACK_OBJECT_FLOAT_VALUE(object) (object)->via.dec
+# else /* MSGPACK_VERSION_MAJOR < 1 */
+typedef size_t msgpack_size_t;
+
+# define MSGPACK_OBJECT_STR_PTR(object) (object)->via.str.ptr
+# define MSGPACK_OBJECT_STR_SIZE(object) (object)->via.str.size
+
+# define MSGPACK_OBJECT_FLOAT_VALUE(object) (object)->via.f64
+# endif /* MSGPACK_VERSION_MAJOR < 1 */
+#endif /* GRN_WITH_MESSAGE_PACK */
diff --git a/storage/mroonga/vendor/groonga/lib/grn_nfkc.h b/storage/mroonga/vendor/groonga/lib/grn_nfkc.h
new file mode 100644
index 00000000..33119d55
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_nfkc.h
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+grn_char_type grn_nfkc50_char_type(const unsigned char *utf8);
+
+const char *grn_nfkc_decompose(const unsigned char *utf8);
+const char *grn_nfkc50_decompose(const unsigned char *utf8);
+
+const char *grn_nfkc_compose(const unsigned char *prefix_utf8,
+ const unsigned char *suffix_utf8);
+const char *grn_nfkc50_compose(const unsigned char *prefix_utf8,
+ const unsigned char *suffix_utf8);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_normalizer.h b/storage/mroonga/vendor/groonga/lib/grn_normalizer.h
new file mode 100644
index 00000000..2ff50047
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_normalizer.h
@@ -0,0 +1,42 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_NORMALIZER_AUTO_NAME "NormalizerAuto"
+
+grn_rc grn_normalizer_init(void);
+grn_rc grn_normalizer_fin(void);
+
+grn_rc grn_normalizer_normalize(grn_ctx *ctx,
+ grn_obj *normalizer,
+ grn_obj *string);
+
+grn_rc grn_db_init_builtin_normalizers(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_obj.h b/storage/mroonga/vendor/groonga/lib/grn_obj.h
new file mode 100644
index 00000000..48eb503b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_obj.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_io.h"
+#include "grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+grn_io *grn_obj_get_io(grn_ctx *ctx, grn_obj *obj);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_output.h b/storage/mroonga/vendor/groonga/lib/grn_output.h
new file mode 100644
index 00000000..14364107
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_output.h
@@ -0,0 +1,127 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_store.h"
+#include "grn_ctx_impl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API void grn_output_array_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *name, int nelements);
+GRN_API void grn_output_array_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type);
+GRN_API void grn_output_map_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *name, int nelements);
+GRN_API void grn_output_map_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type);
+GRN_API void grn_output_null(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type);
+void grn_output_int32(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ int32_t value);
+GRN_API void grn_output_int64(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ int64_t value);
+GRN_API void grn_output_uint64(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ uint64_t value);
+void grn_output_float(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ double value);
+GRN_API void grn_output_cstr(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *value);
+GRN_API void grn_output_str(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ const char *value, size_t value_len);
+GRN_API void grn_output_bool(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_bool value);
+
+GRN_API void grn_output_result_set_open(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format,
+ uint32_t n_additional_elements);
+GRN_API void grn_output_result_set_close(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format);
+GRN_API void grn_output_result_set(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format);
+GRN_API void grn_output_table_columns(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table,
+ grn_obj_format *format);
+GRN_API void grn_output_table_records(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table,
+ grn_obj_format *format);
+
+grn_rc grn_output_format_set_columns(grn_ctx *ctx, grn_obj_format *format,
+ grn_obj *table,
+ const char *columns, int columns_len);
+
+#define GRN_OUTPUT_ARRAY_OPEN(name,nelements) \
+ (grn_ctx_output_array_open(ctx, name, nelements))
+#define GRN_OUTPUT_ARRAY_CLOSE() \
+ (grn_ctx_output_array_close(ctx))
+#define GRN_OUTPUT_MAP_OPEN(name,nelements) \
+ (grn_ctx_output_map_open(ctx, name, nelements))
+#define GRN_OUTPUT_MAP_CLOSE() \
+ (grn_ctx_output_map_close(ctx))
+#define GRN_OUTPUT_NULL() \
+ (grn_ctx_output_null(ctx))
+#define GRN_OUTPUT_INT32(value) \
+ (grn_ctx_output_int32(ctx, value))
+#define GRN_OUTPUT_INT64(value) \
+ (grn_ctx_output_int64(ctx, value))
+#define GRN_OUTPUT_UINT64(value) \
+ (grn_ctx_output_uint64(ctx, value))
+#define GRN_OUTPUT_FLOAT(value) \
+ (grn_ctx_output_float(ctx, value))
+#define GRN_OUTPUT_CSTR(value)\
+ (grn_ctx_output_cstr(ctx, value))
+#define GRN_OUTPUT_STR(value,value_len)\
+ (grn_ctx_output_str(ctx, value, value_len))
+#define GRN_OUTPUT_BOOL(value)\
+ (grn_ctx_output_bool(ctx, value))
+#define GRN_OUTPUT_OBJ(obj,format)\
+ (grn_ctx_output_obj(ctx, obj, format))
+#define GRN_OUTPUT_RESULT_SET_OPEN(result_set,format,n_additional_elements)\
+ (grn_ctx_output_result_set_open(ctx, result_set, format, n_additional_elements))
+#define GRN_OUTPUT_RESULT_SET_CLOSE(result_set,format)\
+ (grn_ctx_output_result_set_close(ctx, result_set, format))
+#define GRN_OUTPUT_RESULT_SET(result_set,format,n_additional_elements)\
+ (grn_ctx_output_result_set(ctx, result_set, format, n_additional_elements))
+#define GRN_OUTPUT_TABLE_COLUMNS(table,format)\
+ (grn_ctx_output_table_columns(ctx, table, format))
+#define GRN_OUTPUT_TABLE_RECORDS(table,format)\
+ (grn_ctx_output_table_records(ctx, table, format))
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_pat.h b/storage/mroonga/vendor/groonga/lib/grn_pat.h
new file mode 100644
index 00000000..1a7e3cfb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_pat.h
@@ -0,0 +1,129 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_db.h"
+#include "grn_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_PAT_MAX_KEY_SIZE GRN_TABLE_MAX_KEY_SIZE
+#define GRN_PAT_MAX_TOTAL_KEY_SIZE (UINT32_MAX - 1)
+
+struct _grn_pat {
+ grn_db_obj obj;
+ grn_io *io;
+ struct grn_pat_header *header;
+ grn_encoding encoding;
+ uint32_t key_size;
+ uint32_t value_size;
+ grn_obj *tokenizer;
+ grn_obj *normalizer;
+ grn_obj token_filters;
+ grn_id *cache;
+ uint32_t cache_size;
+ grn_bool is_dirty;
+ grn_critical_section lock;
+};
+
+#define GRN_PAT_NDELINFOS 0x100
+
+typedef struct {
+ grn_id d; /* The ID of a deleting node. */
+ grn_id ld; /* The ID of the parent node of a deleting node. */
+ /* delinfo->ld is set if required. */
+ uint32_t stat; /* DL_EMPTY, DL_PHASE1, or DL_PHASE2. */
+ uint32_t shared; /* This flag is used if GRN_OBJ_KEY_WITH_SIS is set. */
+} grn_pat_delinfo;
+
+struct grn_pat_header {
+ uint32_t flags;
+ grn_encoding encoding;
+ uint32_t key_size;
+ uint32_t value_size;
+ grn_id tokenizer;
+ uint32_t n_entries;
+ uint32_t curr_rec;
+ int32_t curr_key;
+ int32_t curr_del;
+ int32_t curr_del2;
+ int32_t curr_del3;
+ uint32_t n_garbages;
+ grn_id normalizer;
+ uint32_t truncated;
+ uint32_t n_dirty_opens;
+ uint32_t reserved[1002];
+ grn_pat_delinfo delinfos[GRN_PAT_NDELINFOS];
+ grn_id garbages[GRN_PAT_MAX_KEY_SIZE + 1];
+};
+
+struct _grn_pat_cursor_entry {
+ grn_id id;
+ uint16_t check;
+};
+
+typedef struct _grn_pat_cursor_entry grn_pat_cursor_entry;
+
+struct _grn_pat_cursor {
+ grn_db_obj obj;
+ grn_id curr_rec; /* ID of the latest record */
+ grn_pat *pat;
+ grn_ctx *ctx;
+ unsigned int size; /* stack size (the maximum number of entries) */
+ unsigned int sp; /* stack pointer (the number of entries) */
+ grn_id tail; /* sentinel (the end of the traversal) */
+ unsigned int rest; /* limit rest (the number of remaining records) */
+ grn_pat_cursor_entry *ss; /* stack buffer (pointer to entries) */
+ uint8_t curr_key[GRN_TABLE_MAX_KEY_SIZE];
+};
+
+GRN_API grn_id grn_pat_curr_id(grn_ctx *ctx, grn_pat *pat);
+
+/* private */
+GRN_API grn_rc grn_pat_truncate(grn_ctx *ctx, grn_pat *pat);
+const char *_grn_pat_key(grn_ctx *ctx, grn_pat *pat, grn_id id, uint32_t *key_size);
+grn_id grn_pat_next(grn_ctx *ctx, grn_pat *pat, grn_id id);
+const char *grn_pat_get_value_(grn_ctx *ctx, grn_pat *pat, grn_id id, uint32_t *size);
+GRN_API grn_id grn_pat_at(grn_ctx *ctx, grn_pat *pat, grn_id id);
+void grn_pat_check(grn_ctx *ctx, grn_pat *pat);
+void grn_pat_inspect_nodes(grn_ctx *ctx, grn_pat *pat, grn_obj *buf);
+void grn_pat_cursor_inspect(grn_ctx *ctx, grn_pat_cursor *c, grn_obj *buf);
+
+grn_rc grn_pat_cache_enable(grn_ctx *ctx, grn_pat *pat, uint32_t cache_size);
+void grn_pat_cache_disable(grn_ctx *ctx, grn_pat *pat);
+
+GRN_API grn_rc grn_pat_fuzzy_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, unsigned int key_size,
+ grn_fuzzy_search_optarg *args, grn_hash *h);
+
+uint32_t grn_pat_total_key_size(grn_ctx *ctx, grn_pat *pat);
+
+grn_bool grn_pat_is_key_encoded(grn_ctx *ctx, grn_pat *pat);
+
+grn_rc grn_pat_dirty(grn_ctx *ctx, grn_pat *pat);
+grn_bool grn_pat_is_dirty(grn_ctx *ctx, grn_pat *pat);
+grn_rc grn_pat_clean(grn_ctx *ctx, grn_pat *pat);
+grn_rc grn_pat_clear_dirty(grn_ctx *ctx, grn_pat *pat);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_plugin.h b/storage/mroonga/vendor/groonga/lib/grn_plugin.h
new file mode 100644
index 00000000..0bed139c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_plugin.h
@@ -0,0 +1,62 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_store.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+typedef HINSTANCE grn_dl;
+typedef FARPROC grn_dl_symbol;
+
+#else
+typedef void * grn_dl;
+typedef void * grn_dl_symbol;
+#endif
+
+typedef struct _grn_plugin grn_plugin;
+
+struct _grn_plugin {
+ char path[PATH_MAX];
+ grn_dl dl;
+ grn_plugin_func init_func;
+ grn_plugin_func register_func;
+ grn_plugin_func unregister_func;
+ grn_plugin_func fin_func;
+ int refcount;
+};
+
+void grn_plugin_init_from_env(void);
+grn_rc grn_plugins_init(void);
+grn_rc grn_plugins_fin(void);
+grn_id grn_plugin_open(grn_ctx *ctx, const char *filename);
+grn_rc grn_plugin_close(grn_ctx *ctx, grn_id id);
+grn_id grn_plugin_reference(grn_ctx *ctx, const char *filename);
+const char *grn_plugin_path(grn_ctx *ctx, grn_id id);
+char *grn_plugin_find_path(grn_ctx *ctx, const char *name);
+void grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_proc.h b/storage/mroonga/vendor/groonga/lib/grn_proc.h
new file mode 100644
index 00000000..267ef01b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_proc.h
@@ -0,0 +1,152 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_SELECT_DEFAULT_LIMIT 10
+#define GRN_SELECT_DEFAULT_OUTPUT_COLUMNS "_id, _key, *"
+
+#define GRN_SELECT_INTERNAL_VAR_CONDITION "$condition"
+#define GRN_SELECT_INTERNAL_VAR_CONDITION_LEN \
+ (sizeof(GRN_SELECT_INTERNAL_VAR_CONDITION) - 1)
+
+void grn_proc_init_from_env(void);
+
+GRN_VAR const char *grn_document_root;
+void grn_db_init_builtin_commands(grn_ctx *ctx);
+
+void grn_proc_init_clearlock(grn_ctx *ctx);
+void grn_proc_init_column_copy(grn_ctx *ctx);
+void grn_proc_init_column_create(grn_ctx *ctx);
+void grn_proc_init_column_list(grn_ctx *ctx);
+void grn_proc_init_column_remove(grn_ctx *ctx);
+void grn_proc_init_column_rename(grn_ctx *ctx);
+void grn_proc_init_config_get(grn_ctx *ctx);
+void grn_proc_init_config_set(grn_ctx *ctx);
+void grn_proc_init_config_delete(grn_ctx *ctx);
+void grn_proc_init_define_selector(grn_ctx *ctx);
+void grn_proc_init_dump(grn_ctx *ctx);
+void grn_proc_init_edit_distance(grn_ctx *ctx);
+void grn_proc_init_fuzzy_search(grn_ctx *ctx);
+void grn_proc_init_highlight(grn_ctx *ctx);
+void grn_proc_init_highlight_full(grn_ctx *ctx);
+void grn_proc_init_highlight_html(grn_ctx *ctx);
+void grn_proc_init_in_records(grn_ctx *ctx);
+void grn_proc_init_lock_acquire(grn_ctx *ctx);
+void grn_proc_init_lock_clear(grn_ctx *ctx);
+void grn_proc_init_lock_release(grn_ctx *ctx);
+void grn_proc_init_object_exist(grn_ctx *ctx);
+void grn_proc_init_object_inspect(grn_ctx *ctx);
+void grn_proc_init_object_list(grn_ctx *ctx);
+void grn_proc_init_object_remove(grn_ctx *ctx);
+void grn_proc_init_query_expand(grn_ctx *ctx);
+void grn_proc_init_query_log_flags_get(grn_ctx *ctx);
+void grn_proc_init_query_log_flags_set(grn_ctx *ctx);
+void grn_proc_init_query_log_flags_add(grn_ctx *ctx);
+void grn_proc_init_query_log_flags_remove(grn_ctx *ctx);
+void grn_proc_init_schema(grn_ctx *ctx);
+void grn_proc_init_select(grn_ctx *ctx);
+void grn_proc_init_snippet(grn_ctx *ctx);
+void grn_proc_init_snippet_html(grn_ctx *ctx);
+void grn_proc_init_table_copy(grn_ctx *ctx);
+void grn_proc_init_table_create(grn_ctx *ctx);
+void grn_proc_init_table_list(grn_ctx *ctx);
+void grn_proc_init_table_remove(grn_ctx *ctx);
+void grn_proc_init_table_rename(grn_ctx *ctx);
+void grn_proc_init_table_tokenize(grn_ctx *ctx);
+void grn_proc_init_tokenize(grn_ctx *ctx);
+
+grn_bool grn_proc_option_value_bool(grn_ctx *ctx,
+ grn_obj *option,
+ grn_bool default_value);
+int32_t grn_proc_option_value_int32(grn_ctx *ctx,
+ grn_obj *option,
+ int32_t default_value);
+const char *grn_proc_option_value_string(grn_ctx *ctx,
+ grn_obj *option,
+ size_t *size);
+grn_content_type grn_proc_option_value_content_type(grn_ctx *ctx,
+ grn_obj *option,
+ grn_content_type default_value);
+grn_operator grn_proc_option_value_mode(grn_ctx *ctx,
+ grn_obj *option,
+ grn_operator default_mode,
+ const char *context);
+
+
+void grn_proc_output_object_name(grn_ctx *ctx, grn_obj *obj);
+void grn_proc_output_object_id_name(grn_ctx *ctx, grn_id id);
+
+grn_bool grn_proc_table_set_token_filters(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *token_filter_names);
+
+grn_column_flags grn_proc_column_parse_flags(grn_ctx *ctx,
+ const char *error_message_tag,
+ const char *text,
+ const char *end);
+
+grn_bool grn_proc_select_output_columns_open(grn_ctx *ctx,
+ grn_obj_format *format,
+ grn_obj *result_set,
+ int n_hits,
+ int offset,
+ int limit,
+ const char *columns,
+ int columns_len,
+ grn_obj *condition,
+ uint32_t n_additional_elements);
+grn_bool grn_proc_select_output_columns_close(grn_ctx *ctx,
+ grn_obj_format *format,
+ grn_obj *result_set);
+grn_bool grn_proc_select_output_columns(grn_ctx *ctx,
+ grn_obj *res,
+ int n_hits,
+ int offset,
+ int limit,
+ const char *columns,
+ int columns_len,
+ grn_obj *condition);
+
+grn_rc grn_proc_syntax_expand_query(grn_ctx *ctx,
+ const char *query,
+ unsigned int query_len,
+ grn_expr_flags flags,
+ const char *query_expander_name,
+ unsigned int query_expander_name_len,
+ const char *term_column_name,
+ unsigned int term_column_name_len,
+ const char *expanded_term_column_name,
+ unsigned int expanded_term_column_name_len,
+ grn_obj *expanded_query,
+ const char *error_message_tag);
+
+grn_expr_flags grn_proc_expr_query_flags_parse(grn_ctx *ctx,
+ const char *query_flags,
+ size_t query_flags_size,
+ const char *error_message_tag);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_raw_string.h b/storage/mroonga/vendor/groonga/lib/grn_raw_string.h
new file mode 100644
index 00000000..2b5fdc9c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_raw_string.h
@@ -0,0 +1,62 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_RAW_STRING_INIT(string) do { \
+ string.value = NULL; \
+ string.length = 0; \
+ } while (GRN_FALSE)
+
+#define GRN_RAW_STRING_SET(string, bulk) \
+ if (bulk && GRN_TEXT_LEN(bulk) > 0) { \
+ string.value = GRN_TEXT_VALUE(bulk); \
+ string.length = GRN_TEXT_LEN(bulk); \
+ } else { \
+ string.value = NULL; \
+ string.length = 0; \
+ }
+
+#define GRN_RAW_STRING_FILL(string, bulk) \
+ if (bulk && GRN_TEXT_LEN(bulk) > 0) { \
+ string.value = GRN_TEXT_VALUE(bulk); \
+ string.length = GRN_TEXT_LEN(bulk); \
+ }
+
+#define GRN_RAW_STRING_EQUAL_CSTRING(string, cstring) \
+ (cstring ? \
+ (string.length == strlen(cstring) && \
+ memcmp(string.value, cstring, string.length) == 0) : \
+ (string.length == 0))
+
+typedef struct {
+ const char *value;
+ size_t length;
+} grn_raw_string;
+
+void grn_raw_string_lstrip(grn_ctx *ctx, grn_raw_string *string);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_report.h b/storage/mroonga/vendor/groonga/lib/grn_report.h
new file mode 100644
index 00000000..bb76caf7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_report.h
@@ -0,0 +1,47 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const grn_log_level GRN_REPORT_INDEX_LOG_LEVEL;
+
+void grn_report_index(grn_ctx *ctx,
+ const char *action,
+ const char *tag,
+ grn_obj *index);
+
+void grn_report_index_not_used(grn_ctx *ctx,
+ const char *action,
+ const char *tag,
+ grn_obj *index,
+ const char *reason);
+
+void grn_report_table(grn_ctx *ctx,
+ const char *action,
+ const char *tag,
+ grn_obj *table);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_request_canceler.h b/storage/mroonga/vendor/groonga/lib/grn_request_canceler.h
new file mode 100644
index 00000000..ddb4031a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_request_canceler.h
@@ -0,0 +1,28 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+grn_bool grn_request_canceler_init(void);
+void grn_request_canceler_fin(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_request_timer.h b/storage/mroonga/vendor/groonga/lib/grn_request_timer.h
new file mode 100644
index 00000000..4a45751c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_request_timer.h
@@ -0,0 +1,28 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+grn_bool grn_request_timer_init(void);
+void grn_request_timer_fin(void);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_rset.h b/storage/mroonga/vendor/groonga/lib/grn_rset.h
new file mode 100644
index 00000000..5ca6e8d5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_rset.h
@@ -0,0 +1,114 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ double score;
+ int n_subrecs;
+ int subrecs[1];
+} grn_rset_recinfo;
+
+typedef struct {
+ grn_id rid;
+ uint32_t sid;
+ uint32_t pos;
+} grn_rset_posinfo;
+
+#define GRN_RSET_UTIL_BIT (0x80000000)
+
+#define GRN_RSET_N_SUBRECS_SIZE (sizeof(int))
+#define GRN_RSET_MAX_SIZE (sizeof(int64_t))
+#define GRN_RSET_MIN_SIZE (sizeof(int64_t))
+#define GRN_RSET_SUM_SIZE (sizeof(int64_t))
+#define GRN_RSET_AVG_SIZE (sizeof(double))
+
+#define GRN_RSET_SCORE_SIZE (sizeof(double))
+
+#define GRN_RSET_N_SUBRECS(ri) ((ri)->n_subrecs & ~GRN_RSET_UTIL_BIT)
+
+#define GRN_RSET_SUBREC_SIZE(subrec_size) \
+ (GRN_RSET_SCORE_SIZE + subrec_size)
+#define GRN_RSET_SUBRECS_CMP(a,b,dir) (((a) - (b))*(dir))
+#define GRN_RSET_SUBRECS_NTH(subrecs,size,n) \
+ ((double *)((byte *)subrecs + n * GRN_RSET_SUBREC_SIZE(size)))
+#define GRN_RSET_SUBRECS_COPY(subrecs,size,n,src) \
+ (grn_memcpy(GRN_RSET_SUBRECS_NTH(subrecs, size, n), src, GRN_RSET_SUBREC_SIZE(size)))
+#define GRN_RSET_SUBRECS_SIZE(subrec_size,n) \
+ (GRN_RSET_SUBREC_SIZE(subrec_size) * n)
+
+uint32_t grn_rset_recinfo_calc_values_size(grn_ctx *ctx,
+ grn_table_group_flags flags);
+void grn_rset_recinfo_update_calc_values(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ grn_obj *value);
+
+int64_t *grn_rset_recinfo_get_max_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+int64_t grn_rset_recinfo_get_max(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+void grn_rset_recinfo_set_max(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ int64_t max);
+
+int64_t *grn_rset_recinfo_get_min_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+int64_t grn_rset_recinfo_get_min(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+void grn_rset_recinfo_set_min(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ int64_t min);
+
+int64_t *grn_rset_recinfo_get_sum_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+int64_t grn_rset_recinfo_get_sum(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+void grn_rset_recinfo_set_sum(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ int64_t sum);
+
+double *grn_rset_recinfo_get_avg_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+double grn_rset_recinfo_get_avg(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table);
+void grn_rset_recinfo_set_avg(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ double avg);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_scanner.h b/storage/mroonga/vendor/groonga/lib/grn_scanner.h
new file mode 100644
index 00000000..8ea8597b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_scanner.h
@@ -0,0 +1,40 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_expr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _grn_scaner {
+ grn_obj *expr;
+ grn_obj *source_expr;
+ scan_info **sis;
+ unsigned int n_sis;
+} grn_scanner;
+
+grn_scanner *grn_scanner_open(grn_ctx *ctx, grn_obj *expr,
+ grn_operator op, grn_bool record_exist);
+void grn_scanner_close(grn_ctx *ctx, grn_scanner *scanner);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_scorer.h b/storage/mroonga/vendor/groonga/lib/grn_scorer.h
new file mode 100644
index 00000000..04e8bfd5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_scorer.h
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_ctx.h"
+#include "grn_db.h"
+
+#include <groonga/scorer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _grn_scorer_matched_record {
+ grn_obj *table;
+ grn_obj *lexicon;
+ grn_id id;
+ grn_obj terms;
+ grn_obj term_weights;
+ uint32_t total_term_weights;
+ uint64_t n_documents;
+ uint32_t n_occurrences;
+ uint64_t n_candidates;
+ uint32_t n_tokens;
+ int weight;
+ grn_obj *args_expr;
+ unsigned int args_expr_offset;
+};
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_scorers.h b/storage/mroonga/vendor/groonga/lib/grn_scorers.h
new file mode 100644
index 00000000..1f136a9c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_scorers.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+grn_rc grn_db_init_builtin_scorers(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_snip.h b/storage/mroonga/vendor/groonga/lib/grn_snip.h
new file mode 100644
index 00000000..3989a17d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_snip.h
@@ -0,0 +1,125 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_str.h"
+#include "grn_db.h"
+
+#define ASIZE 256U
+#define MAX_SNIP_TAG_COUNT 512U
+#define MAX_SNIP_COND_COUNT 32U
+#define MAX_SNIP_RESULT_COUNT 16U
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define SNIPCOND_NONSTOP 0
+#define SNIPCOND_STOP 1
+#define SNIPCOND_ACROSS 2
+
+#define GRN_QUERY_SCAN_ALLOCCONDS 0x0002
+
+typedef struct _snip_cond
+{
+ /* initial parameters */
+ const char *opentag;
+ const char *closetag;
+ size_t opentag_len;
+ size_t closetag_len;
+ grn_obj *keyword;
+
+ /* Tuned BM pre */
+ size_t bmBc[ASIZE];
+ size_t shift;
+
+ /* Tuned BM temporal result */
+ size_t found;
+ size_t last_found;
+ size_t last_offset;
+ size_t start_offset;
+ size_t end_offset;
+ size_t found_alpha_head;
+
+ /* search result */
+ int count;
+
+ /* stop flag */
+ int_least8_t stopflag;
+} snip_cond;
+
+typedef struct
+{
+ size_t start_offset;
+ size_t end_offset;
+ snip_cond *cond;
+} _snip_tag_result;
+
+typedef struct
+{
+ size_t start_offset;
+ size_t end_offset;
+ unsigned int first_tag_result_idx;
+ unsigned int last_tag_result_idx;
+ unsigned int tag_count;
+} _snip_result;
+
+typedef struct _grn_snip
+{
+ grn_db_obj obj;
+ grn_encoding encoding;
+ int flags;
+ size_t width;
+ unsigned int max_results;
+ const char *defaultopentag;
+ const char *defaultclosetag;
+ size_t defaultopentag_len;
+ size_t defaultclosetag_len;
+
+ grn_snip_mapping *mapping;
+
+ snip_cond cond[MAX_SNIP_COND_COUNT];
+ unsigned int cond_len;
+
+ unsigned int tag_count;
+ unsigned int snip_count;
+
+ const char *string;
+ grn_obj *nstr;
+
+ _snip_result snip_result[MAX_SNIP_RESULT_COUNT];
+ _snip_tag_result tag_result[MAX_SNIP_TAG_COUNT];
+
+ size_t max_tagged_len;
+
+ grn_obj *normalizer;
+} grn_snip;
+
+grn_rc grn_snip_close(grn_ctx *ctx, grn_snip *snip);
+grn_rc grn_snip_cond_init(grn_ctx *ctx, snip_cond *sc, const char *keyword, unsigned int keyword_len,
+ grn_encoding enc, grn_obj *normalizer, int flags);
+void grn_snip_cond_reinit(snip_cond *cond);
+grn_rc grn_snip_cond_close(grn_ctx *ctx, snip_cond *cond);
+void grn_bm_tunedbm(grn_ctx *ctx, snip_cond *cond, grn_obj *string, int flags);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_store.h b/storage/mroonga/vendor/groonga/lib/grn_store.h
new file mode 100644
index 00000000..8de6fd66
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_store.h
@@ -0,0 +1,216 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_hash.h"
+#include "grn_io.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**** fixed sized elements ****/
+
+typedef struct _grn_ra grn_ra;
+
+struct _grn_ra {
+ grn_db_obj obj;
+ grn_io *io;
+ int element_width;
+ int element_mask;
+ struct grn_ra_header *header;
+};
+
+struct grn_ra_header {
+ uint32_t element_size;
+ uint32_t nrecords; /* nrecords is not maintained by default */
+ uint32_t reserved[10];
+};
+
+grn_ra *grn_ra_create(grn_ctx *ctx, const char *path, unsigned int element_size);
+grn_ra *grn_ra_open(grn_ctx *ctx, const char *path);
+grn_rc grn_ra_info(grn_ctx *ctx, grn_ra *ra, unsigned int *element_size);
+grn_rc grn_ra_close(grn_ctx *ctx, grn_ra *ra);
+grn_rc grn_ra_remove(grn_ctx *ctx, const char *path);
+void *grn_ra_ref(grn_ctx *ctx, grn_ra *ra, grn_id id);
+grn_rc grn_ra_unref(grn_ctx *ctx, grn_ra *ra, grn_id id);
+
+typedef struct _grn_ra_cache grn_ra_cache;
+
+struct _grn_ra_cache {
+ void *p;
+ int32_t seg;
+};
+
+#define GRN_RA_CACHE_INIT(ra,c) do {\
+ (c)->p = NULL; (c)->seg = -1;\
+} while (0)
+
+#define GRN_RA_CACHE_FIN(ra,c) do {\
+ if ((c)->seg != -1) { GRN_IO_SEG_UNREF((ra)->io, (c)->seg); }\
+} while (0);
+
+void *grn_ra_ref_cache(grn_ctx *ctx, grn_ra *ra, grn_id id, grn_ra_cache *cache);
+
+/**** variable sized elements ****/
+
+typedef struct _grn_ja grn_ja;
+
+struct _grn_ja {
+ grn_db_obj obj;
+ grn_io *io;
+ struct grn_ja_header *header;
+};
+
+GRN_API grn_ja *grn_ja_create(grn_ctx *ctx, const char *path,
+ uint32_t max_element_size, uint32_t flags);
+grn_ja *grn_ja_open(grn_ctx *ctx, const char *path);
+grn_rc grn_ja_info(grn_ctx *ctx, grn_ja *ja, unsigned int *max_element_size);
+grn_column_flags grn_ja_get_flags(grn_ctx *ctx, grn_ja *ja);
+GRN_API grn_rc grn_ja_close(grn_ctx *ctx, grn_ja *ja);
+grn_rc grn_ja_remove(grn_ctx *ctx, const char *path);
+grn_rc grn_ja_put(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ void *value, uint32_t value_len, int flags, uint64_t *cas);
+int grn_ja_at(grn_ctx *ctx, grn_ja *ja, grn_id id, void *valbuf, int buf_size);
+
+GRN_API void *grn_ja_ref(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw,
+ uint32_t *value_len);
+grn_obj *grn_ja_get_value(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *value);
+
+GRN_API grn_rc grn_ja_unref(grn_ctx *ctx, grn_io_win *iw);
+int grn_ja_defrag(grn_ctx *ctx, grn_ja *ja, int threshold);
+
+GRN_API grn_rc grn_ja_putv(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ grn_obj *vector, int flags);
+GRN_API uint32_t grn_ja_size(grn_ctx *ctx, grn_ja *ja, grn_id id);
+
+void grn_ja_check(grn_ctx *ctx, grn_ja *ja);
+
+#define GRN_JA_READER_INITIAL_REF_SEG_IDS_SIZE 16
+
+/*
+ * grn_ja_reader is designed to improve the performance of sequential access.
+ */
+typedef struct {
+ grn_ja *ja; /* Target jagged array (without ref. count). */
+ uint32_t einfo_seg_id; /* ID of the current header segment. */
+ void *einfo_seg_addr; /* Address of the current header segment. */
+ void *einfo; /* Header of the current value. */
+ grn_bool ref_avail; /* grn_ja_reader_ref() is available or not. */
+ uint32_t ref_seg_id; /* ID of the current referenced segment. */
+ void *ref_seg_addr; /* Address of the current referenced segment. */
+ uint32_t *ref_seg_ids; /* IDs of referenced segments. */
+ uint32_t nref_seg_ids; /* Number of referenced segments. */
+ uint32_t ref_seg_ids_size; /* Maximum number of referenced segments. */
+ uint32_t body_seg_id; /* ID of the current body segment. */
+ uint32_t body_seg_offset; /* Offset in the current body segment. */
+ void *body_seg_addr; /* Address of the current body segment. */
+ uint32_t value_size; /* Size of the current value. */
+ uint32_t packed_size; /* Compressed size of the current value. */
+ void *packed_buf; /* Buffer for decompression. */
+ uint32_t packed_buf_size; /* Size of the buffer for decompression. */
+ void *stream; /* Stream of a compression library. */
+} grn_ja_reader;
+
+/*
+ * grn_ja_reader_init() initializes a reader.
+ * An initialized reader must be finalized by grn_ja_reader_fin().
+ */
+grn_rc grn_ja_reader_init(grn_ctx *ctx, grn_ja_reader *reader, grn_ja *ja);
+
+/* grn_ja_reader_fin() finalizes a reader. */
+grn_rc grn_ja_reader_fin(grn_ctx *ctx, grn_ja_reader *reader);
+
+/*
+ * grn_ja_reader_open() creates a reader.
+ * A created reader must be destroyed by grn_ja_reader_close().
+ */
+grn_rc grn_ja_reader_open(grn_ctx *ctx, grn_ja *ja, grn_ja_reader **reader);
+
+/* grn_ja_reader_close() destroys a reader. */
+grn_rc grn_ja_reader_close(grn_ctx *ctx, grn_ja_reader *reader);
+
+/*
+ * grn_ja_reader_seek() prepares to access a value specified by `id`.
+ * On success, `reader->value_size` is set.
+ */
+grn_rc grn_ja_reader_seek(grn_ctx *ctx, grn_ja_reader *reader, grn_id id);
+
+/*
+ * grn_ja_reader_ref() gets the address to the current value.
+ * This function is available if `reader->ref_avail` is true.
+ */
+grn_rc grn_ja_reader_ref(grn_ctx *ctx, grn_ja_reader *reader, void **addr);
+
+/* grn_ja_reader_unref() frees refereces returned by grn_ja_reader_ref(). */
+grn_rc grn_ja_reader_unref(grn_ctx *ctx, grn_ja_reader *reader);
+
+/* grn_ja_reader_read() reads the current value to `buf`. */
+grn_rc grn_ja_reader_read(grn_ctx *ctx, grn_ja_reader *reader, void *buf);
+
+/*
+ * grn_ja_reader_pread() reads a part of the current value to `buf`.
+ * If `offset` and `size` are invalid, the behavior is undefined.
+ * FIXME: Compressed values are not supported yet.
+ */
+grn_rc grn_ja_reader_pread(grn_ctx *ctx, grn_ja_reader *reader,
+ size_t offset, size_t size, void *buf);
+
+/*
+typedef struct _grn_vgram_vnode
+{
+ struct _grn_vgram_vnode *car;
+ struct _grn_vgram_vnode *cdr;
+ grn_id tid;
+ grn_id vid;
+ int freq;
+ int len;
+} grn_vgram_vnode;
+
+typedef struct _grn_vgram grn_vgram;
+struct _grn_vgram {
+ void *vgram;
+};
+
+struct _grn_vgram_buf {
+ size_t len;
+ grn_id *tvs;
+ grn_id *tvp;
+ grn_id *tve;
+ grn_vgram_vnode *vps;
+ grn_vgram_vnode *vpp;
+ grn_vgram_vnode *vpe;
+};
+
+grn_vgram *grn_vgram_create(const char *path);
+grn_vgram *grn_vgram_open(const char *path);
+grn_rc grn_vgram_close(grn_vgram *vgram);
+grn_rc grn_vgram_update(grn_vgram *vgram, grn_id rid, grn_vgram_buf *b, grn_hash *terms);
+
+grn_vgram_buf *grn_vgram_buf_open(size_t len);
+grn_rc grn_vgram_buf_add(grn_vgram_buf *b, grn_id tid);
+grn_rc grn_vgram_buf_close(grn_vgram_buf *b);
+
+*/
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_str.h b/storage/mroonga/vendor/groonga/lib/grn_str.h
new file mode 100644
index 00000000..9efd28e3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_str.h
@@ -0,0 +1,116 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include <groonga/nfkc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ GETOPT_OP_NONE = 0,
+ GETOPT_OP_ON,
+ GETOPT_OP_OFF,
+ GETOPT_OP_UPDATE
+} grn_str_getopt_op;
+
+typedef struct {
+ const char opt; /* ends opt == 0 && longopt == NULL */
+ const char *longopt;
+ const char **arg; /* if NULL, no arg are required */
+ int flag;
+ grn_str_getopt_op op;
+} grn_str_getopt_opt;
+
+GRN_API size_t grn_str_len(grn_ctx *ctx, const char *str, grn_encoding encoding, const char **last);
+
+#define GRN_STR_BLANK 0x80
+#define GRN_STR_ISBLANK(c) (c & 0x80)
+#define GRN_STR_CTYPE(c) (c & 0x7f)
+
+GRN_API int grn_isspace(const char *s, grn_encoding encoding);
+int8_t grn_atoi8(const char *nptr, const char *end, const char **rest);
+uint8_t grn_atoui8(const char *nptr, const char *end, const char **rest);
+int16_t grn_atoi16(const char *nptr, const char *end, const char **rest);
+uint16_t grn_atoui16(const char *nptr, const char *end, const char **rest);
+GRN_API int grn_atoi(const char *nptr, const char *end, const char **rest);
+GRN_API unsigned int grn_atoui(const char *nptr, const char *end, const char **rest);
+unsigned int grn_htoui(const char *nptr, const char *end, const char **rest);
+GRN_API int64_t grn_atoll(const char *nptr, const char *end, const char **rest);
+GRN_API uint64_t grn_atoull(const char *nptr, const char *end, const char **rest);
+grn_rc grn_itoa(int i, char *p, char *end, char **rest);
+grn_rc grn_lltoa(int64_t i, char *p, char *end, char **rest);
+grn_rc grn_ulltoa(uint64_t i, char *p, char *end, char **rest);
+GRN_API grn_rc grn_aton(grn_ctx *ctx, const char *p, const char *end, const char **rest, grn_obj *res);
+
+GRN_API void grn_itoh(unsigned int i, char *p, unsigned int len);
+int grn_str_tok(const char *str, size_t str_len, char delim, const char **tokbuf, int buf_size, const char **rest);
+GRN_API int grn_str_getopt(int argc, char * const argv[], const grn_str_getopt_opt *opts, int *flags);
+
+extern int grn_str_margin_size;
+
+char *grn_itob(grn_id id, char *p);
+grn_id grn_btoi(char *b);
+
+grn_rc grn_substring(grn_ctx *ctx, char **str, char **str_end, int start, int end, grn_encoding encoding);
+
+GRN_API int grn_charlen_(grn_ctx *ctx, const char *str, const char *end, grn_encoding encoding);
+GRN_API grn_str *grn_str_open_(grn_ctx *ctx, const char *str, unsigned int str_len, int flags, grn_encoding encoding);
+
+#define GRN_BULK_SET_CURR(buf,p) do {\
+ if (GRN_BULK_OUTP(buf)) {\
+ (buf)->u.b.curr = (char *)(p);\
+ } else {\
+ (buf)->header.flags = (char *)(p) - GRN_BULK_HEAD(buf);\
+ }\
+} while (0)
+
+grn_rc grn_text_ulltoa(grn_ctx *ctx, grn_obj *buf, unsigned long long int i);
+
+GRN_API const char *grn_text_cgidec(grn_ctx *ctx, grn_obj *buf,
+ const char *p, const char *e,
+ const char *delimiters);
+
+#define GRN_TOK_VOID (0x00)
+#define GRN_TOK_SYMBOL (0x01)
+#define GRN_TOK_STRING (0x02)
+#define GRN_TOK_QUOTE (0x03)
+
+GRN_API const char *grn_text_unesc_tok(grn_ctx *ctx, grn_obj *buf,
+ const char *p, const char *e,
+ char *tok_type);
+
+GRN_API void grn_str_url_path_normalize(grn_ctx *ctx,
+ const char *path, size_t path_len,
+ char *buf, size_t buf_len);
+
+#define GRN_OBJ_FORMAT_XML_ELEMENT_MASK (0x01<<1)
+#define GRN_OBJ_FORMAT_XML_ELEMENT_RESULTSET (0x00<<1)
+#define GRN_OBJ_FORMAT_XML_ELEMENT_NAVIGATIONENTRY (0x01<<1)
+
+#include <stdio.h>
+GRN_API grn_rc grn_text_fgets(grn_ctx *ctx, grn_obj *buf, FILE *fp);
+
+grn_bool grn_bulk_is_zero(grn_ctx *ctx, grn_obj *obj);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_string.h b/storage/mroonga/vendor/groonga/lib/grn_string.h
new file mode 100644
index 00000000..39e76c96
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_string.h
@@ -0,0 +1,51 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_db.h"
+#include "grn_str.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ grn_obj_header header;
+ const char *original;
+ unsigned int original_length_in_bytes;
+ char *normalized;
+ unsigned int normalized_length_in_bytes;
+ unsigned int n_characters;
+ short *checks;
+ unsigned char *ctypes;
+ grn_encoding encoding;
+ int flags;
+} grn_string;
+
+grn_obj *grn_string_open_(grn_ctx *ctx, const char *str, unsigned int str_len,
+ grn_obj *normalizer, int flags, grn_encoding encoding);
+grn_rc grn_string_close(grn_ctx *ctx, grn_obj *string);
+grn_rc grn_string_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *string);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_time.h b/storage/mroonga/vendor/groonga/lib/grn_time.h
new file mode 100644
index 00000000..b34f6687
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_time.h
@@ -0,0 +1,40 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GRN_TIMEVAL_STR_SIZE
+#define GRN_TIMEVAL_STR_SIZE 0x100
+#endif /* GRN_TIMEVAL_STR_SIZE */
+#ifndef GRN_TIMEVAL_STR_FORMAT
+#define GRN_TIMEVAL_STR_FORMAT "%04d-%02d-%02d %02d:%02d:%02d.%06d"
+#endif /* GRN_TIMEVAL_STR_FORMAT */
+
+GRN_API grn_rc grn_timeval2str(grn_ctx *ctx, grn_timeval *tv, char *buf, size_t buf_size);
+struct tm *grn_timeval2tm(grn_ctx *ctx, grn_timeval *tv, struct tm *tm_buffer);
+grn_rc grn_str2timeval(const char *str, uint32_t str_len, grn_timeval *tv);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_token_cursor.h b/storage/mroonga/vendor/groonga/lib/grn_token_cursor.h
new file mode 100644
index 00000000..a89f4c68
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_token_cursor.h
@@ -0,0 +1,81 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_ctx.h"
+#include "grn_db.h"
+
+#include <groonga/tokenizer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_TOKENIZER_BEGIN_MARK_UTF8 "\xEF\xBF\xAF"
+#define GRN_TOKENIZER_BEGIN_MARK_UTF8_LEN 3
+#define GRN_TOKENIZER_END_MARK_UTF8 "\xEF\xBF\xB0"
+#define GRN_TOKENIZER_END_MARK_UTF8_LEN 3
+
+typedef enum {
+ GRN_TOKEN_CURSOR_DOING = 0,
+ GRN_TOKEN_CURSOR_DONE,
+ GRN_TOKEN_CURSOR_DONE_SKIP,
+ GRN_TOKEN_CURSOR_NOT_FOUND
+} grn_token_cursor_status;
+
+struct _grn_token {
+ grn_obj data;
+ grn_token_status status;
+};
+
+typedef struct {
+ grn_obj *table;
+ const unsigned char *orig;
+ const unsigned char *curr;
+ uint32_t orig_blen;
+ uint32_t curr_size;
+ int32_t pos;
+ grn_tokenize_mode mode;
+ grn_token_cursor_status status;
+ grn_bool force_prefix;
+ grn_obj_flags table_flags;
+ grn_encoding encoding;
+ grn_obj *tokenizer;
+ grn_proc_ctx pctx;
+ struct {
+ grn_obj *objects;
+ void **data;
+ } token_filter;
+ uint32_t variant;
+ grn_obj *nstr;
+} grn_token_cursor;
+
+#define GRN_TOKEN_CURSOR_ENABLE_TOKENIZED_DELIMITER (0x01L<<0)
+
+GRN_API grn_token_cursor *grn_token_cursor_open(grn_ctx *ctx, grn_obj *table,
+ const char *str, size_t str_len,
+ grn_tokenize_mode mode,
+ unsigned int flags);
+
+GRN_API grn_id grn_token_cursor_next(grn_ctx *ctx, grn_token_cursor *token_cursor);
+GRN_API grn_rc grn_token_cursor_close(grn_ctx *ctx, grn_token_cursor *token_cursor);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_tokenizers.h b/storage/mroonga/vendor/groonga/lib/grn_tokenizers.h
new file mode 100644
index 00000000..81ac2ab6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_tokenizers.h
@@ -0,0 +1,38 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern grn_obj *grn_tokenizer_uvector;
+
+grn_rc grn_tokenizers_init(void);
+grn_rc grn_tokenizers_fin(void);
+
+grn_rc grn_db_init_mecab_tokenizer(grn_ctx *ctx);
+void grn_db_fin_mecab_tokenizer(grn_ctx *ctx);
+grn_rc grn_db_init_builtin_tokenizers(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_ts.h b/storage/mroonga/vendor/groonga/lib/grn_ts.h
new file mode 100644
index 00000000..83f4dca8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_ts.h
@@ -0,0 +1,48 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * grn_ts_select() finds records passing through a filter and writes the values
+ * of output columns (the evaluation results of output expressions) into the
+ * output buffer (`ctx->impl->outbuf`).
+ *
+ * Note that the first `offset` records will be discarded and at most `limit`
+ * records will be output.
+ *
+ * On success, grn_ts_select() returns GRN_SUCCESS.
+ * On failure, grn_ts_select() returns an error code and set the details into
+ * `ctx`.
+ */
+grn_rc grn_ts_select(grn_ctx *ctx, grn_obj *table,
+ const char *filter_ptr, size_t filter_len,
+ const char *scorer_ptr, size_t scorer_len,
+ const char *sortby_ptr, size_t sortby_len,
+ const char *output_columns_ptr, size_t output_columns_len,
+ size_t offset, size_t limit);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_util.h b/storage/mroonga/vendor/groonga/lib/grn_util.h
new file mode 100644
index 00000000..5b888fd5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_util.h
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+#include "grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GRN_API grn_rc grn_normalize_offset_and_limit(grn_ctx *ctx, int size, int *offset, int *limit);
+
+GRN_API char *grn_path_separator_to_system(char *dest, char *groonga_path);
+
+void grn_p_record(grn_ctx *ctx, grn_obj *table, grn_id id);
+
+/*
+ * grn_mkstemp generates a unique filename from path_template, creates a
+ * file with permissions 0600 and returns a open file desciptor for the file.
+ * The last 6 bytes of path_template must be "XXXXXX" and these are replaced
+ * with a string that makes the filename unique.
+ */
+int grn_mkstemp(char *path_template);
+grn_bool grn_path_exist(const char *path);
+
+int grn_tokenize(const char *str, size_t str_len,
+ const char **tokbuf, int buf_size,
+ const char **rest);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_window_function.h b/storage/mroonga/vendor/groonga/lib/grn_window_function.h
new file mode 100644
index 00000000..c5894241
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_window_function.h
@@ -0,0 +1,40 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016-2017 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+struct _grn_window {
+ grn_obj *table;
+ grn_obj *grouped_table;
+ grn_obj ids;
+ size_t n_ids;
+ ssize_t current_index;
+ grn_window_direction direction;
+ grn_bool is_sorted;
+};
+
+grn_rc grn_window_init(grn_ctx *ctx,
+ grn_window *window,
+ grn_obj *table,
+ grn_bool is_sorted);
+grn_rc grn_window_fin(grn_ctx *ctx, grn_window *window);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_window_functions.h b/storage/mroonga/vendor/groonga/lib/grn_window_functions.h
new file mode 100644
index 00000000..c44e65a1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_window_functions.h
@@ -0,0 +1,26 @@
+/*
+ Copyright(C) 2016 Brazil
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+grn_rc grn_db_init_builtin_window_functions(grn_ctx *ctx);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/grn_windows.h b/storage/mroonga/vendor/groonga/lib/grn_windows.h
new file mode 100644
index 00000000..aee18aec
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/grn_windows.h
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+GRN_API UINT grn_windows_encoding_to_code_page(grn_encoding encoding);
+#endif /* WIN32 */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/hash.c b/storage/mroonga/vendor/groonga/lib/hash.c
new file mode 100644
index 00000000..8cdae7ba
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/hash.c
@@ -0,0 +1,3720 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn_hash.h"
+#include "grn_output.h"
+#include <string.h>
+#include <limits.h>
+
+#include "grn_store.h"
+#include "grn_normalizer.h"
+
+/* grn_tiny_array */
+
+/* Requirements: id != GRN_ID_NIL. */
+inline static int
+grn_tiny_array_get_block_id(grn_id id)
+{
+ int most_significant_one_bit_offset;
+ GRN_BIT_SCAN_REV(id, most_significant_one_bit_offset);
+ return most_significant_one_bit_offset >> GRN_TINY_ARRAY_FACTOR;
+}
+
+/* Requirements: id != GRN_ID_NIL. */
+inline static void *
+grn_tiny_array_get(grn_tiny_array *array, grn_id id) {
+ const int block_id = grn_tiny_array_get_block_id(id);
+ uint8_t * const block = (uint8_t *)array->blocks[block_id];
+ if (block) {
+ const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
+ return block + (id - offset) * array->element_size;
+ }
+ return NULL;
+}
+
+/* Requirements: id != GRN_ID_NIL. */
+inline static void *
+grn_tiny_array_put(grn_tiny_array *array, grn_id id) {
+ const int block_id = grn_tiny_array_get_block_id(id);
+ void ** const block = &array->blocks[block_id];
+ const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
+ if (!*block) {
+ grn_ctx * const ctx = array->ctx;
+ if (array->flags & GRN_TINY_ARRAY_THREADSAFE) {
+ CRITICAL_SECTION_ENTER(array->lock);
+ }
+ if (!*block) {
+ const size_t block_size =
+ GRN_TINY_ARRAY_GET_BLOCK_SIZE(block_id) * array->element_size;
+ if (array->flags & GRN_TINY_ARRAY_USE_MALLOC) {
+ if (array->flags & GRN_TINY_ARRAY_CLEAR) {
+ *block = GRN_CALLOC(block_size);
+ } else {
+ *block = GRN_MALLOC(block_size);
+ }
+ } else {
+ *block = GRN_CTX_ALLOC(ctx, block_size);
+ }
+ }
+ if (array->flags & GRN_TINY_ARRAY_THREADSAFE) {
+ CRITICAL_SECTION_LEAVE(array->lock);
+ }
+ if (!*block) {
+ return NULL;
+ }
+ }
+ if (id > array->max) {
+ array->max = id;
+ }
+ return (uint8_t *)*block + (id - offset) * array->element_size;
+}
+
+inline static void *
+grn_tiny_array_at_inline(grn_tiny_array *array, grn_id id)
+{
+ return id ? grn_tiny_array_put(array, id) : NULL;
+}
+
+void
+grn_tiny_array_init(grn_ctx *ctx, grn_tiny_array *array,
+ uint16_t element_size, uint16_t flags)
+{
+ array->ctx = ctx;
+ array->max = 0;
+ array->element_size = element_size;
+ array->flags = flags;
+ memset(array->blocks, 0, sizeof(array->blocks));
+ if (flags & GRN_TINY_ARRAY_THREADSAFE) {
+ CRITICAL_SECTION_INIT(array->lock);
+ }
+}
+
+void
+grn_tiny_array_fin(grn_tiny_array *array)
+{
+ int block_id;
+ grn_ctx * const ctx = array->ctx;
+ for (block_id = 0; block_id < GRN_TINY_ARRAY_NUM_BLOCKS; block_id++) {
+ if (array->blocks[block_id]) {
+ if (array->flags & GRN_TINY_ARRAY_USE_MALLOC) {
+ GRN_FREE(array->blocks[block_id]);
+ } else {
+ GRN_CTX_FREE(ctx, array->blocks[block_id]);
+ }
+ array->blocks[block_id] = NULL;
+ }
+ }
+}
+
+void *
+grn_tiny_array_at(grn_tiny_array *array, grn_id id)
+{
+ return grn_tiny_array_at_inline(array, id);
+}
+
+grn_id
+grn_tiny_array_id(grn_tiny_array *array, const void *element_address)
+{
+ const uint8_t * const ptr = (const uint8_t *)element_address;
+ uint32_t block_id, offset = 1;
+ for (block_id = 0; block_id < GRN_TINY_ARRAY_NUM_BLOCKS; block_id++) {
+ const uint32_t block_size = GRN_TINY_ARRAY_GET_BLOCK_SIZE(block_id);
+ const uint8_t * const block = (const uint8_t *)array->blocks[block_id];
+ if (block) {
+ if (block <= ptr && ptr < (block + block_size * array->element_size)) {
+ return offset + ((ptr - block) / array->element_size);
+ }
+ }
+ offset += block_size;
+ }
+ return GRN_ID_NIL;
+}
+
+/* grn_tiny_bitmap */
+
+static void
+grn_tiny_bitmap_init(grn_ctx *ctx, grn_tiny_bitmap *bitmap)
+{
+ bitmap->ctx = ctx;
+ memset(bitmap->blocks, 0, sizeof(bitmap->blocks));
+}
+
+static void
+grn_tiny_bitmap_fin(grn_tiny_bitmap *bitmap)
+{
+ int block_id;
+ grn_ctx * const ctx = bitmap->ctx;
+ for (block_id = 0; block_id < GRN_TINY_ARRAY_NUM_BLOCKS; block_id++) {
+ if (bitmap->blocks[block_id]) {
+ GRN_CTX_FREE(ctx, bitmap->blocks[block_id]);
+ bitmap->blocks[block_id] = NULL;
+ }
+ }
+}
+
+/* Requirements: bit_id != GRN_ID_NIL. */
+inline static uint8_t *
+grn_tiny_bitmap_get_byte(grn_tiny_bitmap *bitmap, grn_id bit_id) {
+ const uint32_t byte_id = (bit_id >> 3) + 1;
+ const int block_id = grn_tiny_array_get_block_id(byte_id);
+ uint8_t * const block = (uint8_t *)bitmap->blocks[block_id];
+ if (block) {
+ const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
+ return block + byte_id - offset;
+ }
+ return NULL;
+}
+
+/* Requirements: bit_id != GRN_ID_NIL. */
+inline static uint8_t *
+grn_tiny_bitmap_put_byte(grn_tiny_bitmap *bitmap, grn_id bit_id) {
+ const uint32_t byte_id = (bit_id >> 3) + 1;
+ const int block_id = grn_tiny_array_get_block_id(byte_id);
+ void ** const block = &bitmap->blocks[block_id];
+ const size_t offset = GRN_TINY_ARRAY_GET_OFFSET(block_id);
+ if (!*block) {
+ grn_ctx * const ctx = bitmap->ctx;
+ *block = GRN_CTX_ALLOC(ctx, GRN_TINY_ARRAY_GET_BLOCK_SIZE(block_id));
+ if (!*block) {
+ return NULL;
+ }
+ }
+ return (uint8_t *)*block + byte_id - offset;
+}
+
+/* Requirements: bit_id != GRN_ID_NIL. */
+/* Return value: 1/0 on success, -1 on failure. */
+/* Note: A bitmap is extended if needed. */
+inline static int
+grn_tiny_bitmap_put(grn_tiny_bitmap *bitmap, grn_id bit_id)
+{
+ uint8_t * const ptr = grn_tiny_bitmap_put_byte(bitmap, bit_id);
+ return ptr ? ((*ptr >> (bit_id & 7)) & 1) : -1;
+}
+
+/* Requirements: bit_id != GRN_ID_NIL. */
+inline static uint8_t *
+grn_tiny_bitmap_get_and_set(grn_tiny_bitmap *bitmap, grn_id bit_id,
+ grn_bool bit)
+{
+ uint8_t * const ptr = grn_tiny_bitmap_get_byte(bitmap, bit_id);
+ if (ptr) {
+ /* This branch will be removed because the given `bit' is constant. */
+ if (bit) {
+ *ptr |= 1 << (bit_id & 7);
+ } else {
+ *ptr &= ~(1 << (bit_id & 7));
+ }
+ }
+ return ptr;
+}
+
+/* Requirements: bit_id != GRN_ID_NIL. */
+/* Note: A bitmap is extended if needed. */
+inline static uint8_t *
+grn_tiny_bitmap_put_and_set(grn_tiny_bitmap *bitmap, grn_id bit_id,
+ grn_bool bit)
+{
+ uint8_t * const ptr = grn_tiny_bitmap_put_byte(bitmap, bit_id);
+ if (ptr) {
+ /* This branch will be removed because the given `bit' is constant. */
+ if (bit) {
+ *ptr |= 1 << (bit_id & 7);
+ } else {
+ *ptr &= ~(1 << (bit_id & 7));
+ }
+ }
+ return ptr;
+}
+
+/* grn_io_array */
+
+#define GRN_ARRAY_MAX (GRN_ID_MAX - 8)
+
+inline static void *
+grn_io_array_at_inline(grn_ctx *ctx, grn_io *io, uint32_t segment_id,
+ uint64_t offset, int flags)
+{
+ void *ptr;
+ GRN_IO_ARRAY_AT(io, segment_id, offset, &flags, ptr);
+ return ptr;
+}
+
+/*
+ * grn_io_array_bit_at() returns 1/0 on success, -1 on failure.
+ */
+inline static int
+grn_io_array_bit_at(grn_ctx *ctx, grn_io *io,
+ uint32_t segment_id, uint32_t offset)
+{
+ uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
+ ctx, io, segment_id, (offset >> 3) + 1, 0);
+ return ptr ? ((*ptr >> (offset & 7)) & 1) : -1;
+}
+
+/*
+ * The following functions, grn_io_array_bit_*(), return a non-NULL pointer on
+ * success, a NULL pointer on failure.
+ */
+inline static void *
+grn_io_array_bit_on(grn_ctx *ctx, grn_io *io,
+ uint32_t segment_id, uint32_t offset)
+{
+ uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
+ ctx, io, segment_id, (offset >> 3) + 1, GRN_TABLE_ADD);
+ if (ptr) {
+ *ptr |= 1 << (offset & 7);
+ }
+ return ptr;
+}
+
+inline static void *
+grn_io_array_bit_off(grn_ctx *ctx, grn_io *io,
+ uint32_t segment_id, uint32_t offset)
+{
+ uint8_t * const ptr = (uint8_t *)grn_io_array_at_inline(
+ ctx, io, segment_id, (offset >> 3) + 1, GRN_TABLE_ADD);
+ if (ptr) {
+ *ptr &= ~(1 << (offset & 7));
+ }
+ return ptr;
+}
+
+/* grn_table_queue */
+
+static void
+grn_table_queue_lock_init(grn_ctx *ctx, grn_table_queue *queue)
+{
+ MUTEX_INIT_SHARED(queue->mutex);
+ COND_INIT_SHARED(queue->cond);
+}
+
+static void
+grn_table_queue_init(grn_ctx *ctx, grn_table_queue *queue)
+{
+ queue->head = 0;
+ queue->tail = 0;
+ queue->cap = GRN_ARRAY_MAX;
+ queue->unblock_requested = GRN_FALSE;
+ grn_table_queue_lock_init(ctx, queue);
+}
+
+uint32_t
+grn_table_queue_size(grn_table_queue *queue)
+{
+ return (queue->head < queue->tail)
+ ? 2 * queue->cap + queue->head - queue->tail
+ : queue->head - queue->tail;
+}
+
+void
+grn_table_queue_head_increment(grn_table_queue *queue)
+{
+ if (queue->head == 2 * queue->cap) {
+ queue->head = 1;
+ } else {
+ queue->head++;
+ }
+}
+
+void
+grn_table_queue_tail_increment(grn_table_queue *queue)
+{
+ if (queue->tail == 2 * queue->cap) {
+ queue->tail = 1;
+ } else {
+ queue->tail++;
+ }
+}
+
+grn_id
+grn_table_queue_head(grn_table_queue *queue)
+{
+ return queue->head > queue->cap
+ ? queue->head - queue->cap
+ : queue->head;
+}
+
+grn_id
+grn_table_queue_tail(grn_table_queue *queue)
+{
+ return queue->tail > queue->cap
+ ? queue->tail - queue->cap
+ : queue->tail;
+}
+
+/* grn_array */
+
+#define GRN_ARRAY_SEGMENT_SIZE 0x400000
+
+/* Header of grn_io-based grn_array. */
+struct grn_array_header {
+ uint32_t flags;
+ uint32_t curr_rec;
+ uint32_t value_size;
+ uint32_t n_entries;
+ uint32_t n_garbages;
+ grn_id garbages;
+ uint32_t lock;
+ uint32_t truncated;
+ uint32_t reserved[8];
+ grn_table_queue queue;
+};
+
+/*
+ * A grn_io-based grn_array consists of the following 2 segments.
+ * GRN_ARRAY_VALUE_SEGMENT: stores values.
+ * GRN_ARRAY_BITMAP_SEGMENT: stores whether entries are valid or not.
+ */
+enum {
+ GRN_ARRAY_VALUE_SEGMENT = 0,
+ GRN_ARRAY_BITMAP_SEGMENT = 1
+};
+
+inline static grn_bool
+grn_array_is_io_array(grn_array *array)
+{
+ return array->io != NULL;
+}
+
+inline static void *
+grn_array_io_entry_at(grn_ctx *ctx, grn_array *array, grn_id id, int flags)
+{
+ return grn_io_array_at_inline(ctx, array->io, GRN_ARRAY_VALUE_SEGMENT, id, flags);
+}
+
+inline static void *
+grn_array_entry_at(grn_ctx *ctx, grn_array *array, grn_id id, int flags)
+{
+ if (grn_array_is_io_array(array)) {
+ return grn_array_io_entry_at(ctx, array, id, flags);
+ } else {
+ return grn_tiny_array_at_inline(&array->array, id);
+ }
+}
+
+/* grn_array_bitmap_at() returns 1/0 on success, -1 on failure. */
+inline static int
+grn_array_bitmap_at(grn_ctx *ctx, grn_array *array, grn_id id)
+{
+ if (grn_array_is_io_array(array)) {
+ return grn_io_array_bit_at(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id);
+ } else {
+ return grn_tiny_bitmap_put(&array->bitmap, id);
+ }
+}
+
+static grn_rc
+grn_array_init_tiny_array(grn_ctx *ctx, grn_array *array, const char *path,
+ uint32_t value_size, uint32_t flags)
+{
+ if (path) {
+ ERR(GRN_INVALID_ARGUMENT, "failed to create tiny array");
+ return ctx->rc;
+ }
+ array->obj.header.flags = flags;
+ array->ctx = ctx;
+ array->value_size = value_size;
+ array->n_keys = 0;
+ array->keys = NULL;
+ array->n_garbages = &array->n_garbages_buf;
+ array->n_entries = &array->n_entries_buf;
+ array->n_garbages_buf = 0;
+ array->n_entries_buf = 0;
+ array->io = NULL;
+ array->header = NULL;
+ array->garbages = GRN_ID_NIL;
+ grn_tiny_array_init(ctx, &array->array, value_size, GRN_TINY_ARRAY_CLEAR);
+ grn_tiny_bitmap_init(ctx, &array->bitmap);
+ return GRN_SUCCESS;
+}
+
+static grn_io *
+grn_array_create_io_array(grn_ctx *ctx, const char *path, uint32_t value_size)
+{
+ uint32_t w_of_element = 0;
+ grn_io_array_spec array_spec[2];
+
+ while ((1U << w_of_element) < value_size) {
+ w_of_element++;
+ }
+
+ array_spec[GRN_ARRAY_VALUE_SEGMENT].w_of_element = w_of_element;
+ array_spec[GRN_ARRAY_VALUE_SEGMENT].max_n_segments =
+ 1U << (30 - (22 - w_of_element));
+ array_spec[GRN_ARRAY_BITMAP_SEGMENT].w_of_element = 0;
+ array_spec[GRN_ARRAY_BITMAP_SEGMENT].max_n_segments = 1U << (30 - (22 + 3));
+ return grn_io_create_with_array(ctx, path, sizeof(struct grn_array_header),
+ GRN_ARRAY_SEGMENT_SIZE, grn_io_auto,
+ 2, array_spec);
+}
+
+static grn_rc
+grn_array_init_io_array(grn_ctx *ctx, grn_array *array, const char *path,
+ uint32_t value_size, uint32_t flags)
+{
+ grn_io *io;
+ struct grn_array_header *header;
+
+ io = grn_array_create_io_array(ctx, path, value_size);
+ if (!io) {
+ return ctx->rc;
+ }
+ grn_io_set_type(io, GRN_TABLE_NO_KEY);
+
+ header = grn_io_header(io);
+ header->flags = flags;
+ header->curr_rec = 0;
+ header->lock = 0;
+ header->value_size = value_size;
+ header->n_entries = 0;
+ header->n_garbages = 0;
+ header->garbages = GRN_ID_NIL;
+ header->truncated = GRN_FALSE;
+ grn_table_queue_init(ctx, &header->queue);
+ array->obj.header.flags = flags;
+ array->ctx = ctx;
+ array->value_size = value_size;
+ array->n_keys = 0;
+ array->keys = NULL;
+ array->n_garbages = &header->n_garbages;
+ array->n_entries = &header->n_entries;
+ array->io = io;
+ array->header = header;
+ array->lock = &header->lock;
+ return GRN_SUCCESS;
+}
+
+void
+grn_array_queue_lock_clear(grn_ctx *ctx, grn_array *array)
+{
+ struct grn_array_header *header;
+ header = grn_io_header(array->io);
+ grn_table_queue_lock_init(ctx, &header->queue);
+}
+
+grn_table_queue *
+grn_array_queue(grn_ctx *ctx, grn_array *array)
+{
+ if (grn_array_is_io_array(array)) {
+ struct grn_array_header *header;
+ header = grn_io_header(array->io);
+ return &header->queue;
+ } else {
+ return NULL;
+ }
+}
+
+static grn_rc
+grn_array_init(grn_ctx *ctx, grn_array *array,
+ const char *path, uint32_t value_size, uint32_t flags)
+{
+ if (flags & GRN_ARRAY_TINY) {
+ return grn_array_init_tiny_array(ctx, array, path, value_size, flags);
+ } else {
+ return grn_array_init_io_array(ctx, array, path, value_size, flags);
+ }
+}
+
+grn_array *
+grn_array_create(grn_ctx *ctx, const char *path, uint32_t value_size, uint32_t flags)
+{
+ if (ctx) {
+ grn_array * const array = (grn_array *)GRN_CALLOC(sizeof(grn_array));
+ if (array) {
+ GRN_DB_OBJ_SET_TYPE(array, GRN_TABLE_NO_KEY);
+ if (!grn_array_init(ctx, array, path, value_size, flags)) {
+ return array;
+ }
+ GRN_FREE(array);
+ }
+ }
+ return NULL;
+}
+
+grn_array *
+grn_array_open(grn_ctx *ctx, const char *path)
+{
+ if (ctx) {
+ grn_io * const io = grn_io_open(ctx, path, grn_io_auto);
+ if (io) {
+ struct grn_array_header * const header = grn_io_header(io);
+ uint32_t io_type = grn_io_get_type(io);
+ if (io_type == GRN_TABLE_NO_KEY) {
+ grn_array * const array = (grn_array *)GRN_MALLOC(sizeof(grn_array));
+ if (array) {
+ if (!(header->flags & GRN_ARRAY_TINY)) {
+ GRN_DB_OBJ_SET_TYPE(array, GRN_TABLE_NO_KEY);
+ array->obj.header.flags = header->flags;
+ array->ctx = ctx;
+ array->value_size = header->value_size;
+ array->n_keys = 0;
+ array->keys = NULL;
+ array->n_garbages = &header->n_garbages;
+ array->n_entries = &header->n_entries;
+ array->io = io;
+ array->header = header;
+ array->lock = &header->lock;
+ return array;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid array flags. (%x)", header->flags);
+ }
+ GRN_FREE(array);
+ }
+ } else {
+ ERR(GRN_INVALID_FORMAT,
+ "[table][array] file type must be %#04x: <%#04x>",
+ GRN_TABLE_NO_KEY, io_type);
+ }
+ grn_io_close(ctx, io);
+ }
+ }
+ return NULL;
+}
+
+/*
+ * grn_array_error_if_truncated() logs an error and returns its error code if
+ * an array is truncated by another process.
+ * Otherwise, this function returns GRN_SUCCESS.
+ * Note that `ctx` and `array` must be valid.
+ *
+ * FIXME: An array should be reopened if possible.
+ */
+static grn_rc
+grn_array_error_if_truncated(grn_ctx *ctx, grn_array *array)
+{
+ if (array->header && array->header->truncated) {
+ ERR(GRN_FILE_CORRUPT,
+ "array is truncated, please unmap or reopen the database");
+ return GRN_FILE_CORRUPT;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_array_close(grn_ctx *ctx, grn_array *array)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (!ctx || !array) { return GRN_INVALID_ARGUMENT; }
+ if (array->keys) { GRN_FREE(array->keys); }
+ if (grn_array_is_io_array(array)) {
+ rc = grn_io_close(ctx, array->io);
+ } else {
+ GRN_ASSERT(ctx == array->ctx);
+ grn_tiny_array_fin(&array->array);
+ grn_tiny_bitmap_fin(&array->bitmap);
+ }
+ GRN_FREE(array);
+ return rc;
+}
+
+grn_rc
+grn_array_remove(grn_ctx *ctx, const char *path)
+{
+ if (!ctx || !path) { return GRN_INVALID_ARGUMENT; }
+ return grn_io_remove(ctx, path);
+}
+
+uint32_t
+grn_array_size(grn_ctx *ctx, grn_array *array)
+{
+ if (grn_array_error_if_truncated(ctx, array) != GRN_SUCCESS) {
+ return 0;
+ }
+ return *array->n_entries;
+}
+
+uint32_t
+grn_array_get_flags(grn_ctx *ctx, grn_array *array)
+{
+ return array->header->flags;
+}
+
+grn_rc
+grn_array_truncate(grn_ctx *ctx, grn_array *array)
+{
+ grn_rc rc;
+ char *path = NULL;
+ uint32_t value_size, flags;
+
+ if (!ctx || !array) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_array_error_if_truncated(ctx, array);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (grn_array_is_io_array(array)) {
+ const char * const io_path = grn_io_path(array->io);
+ if (io_path && *io_path) {
+ path = GRN_STRDUP(io_path);
+ if (!path) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ }
+ value_size = array->value_size;
+ flags = array->obj.header.flags;
+
+ if (grn_array_is_io_array(array)) {
+ if (path) {
+ /* Only an I/O array with a valid path uses the `truncated` flag. */
+ array->header->truncated = GRN_TRUE;
+ }
+ rc = grn_io_close(ctx, array->io);
+ if (!rc) {
+ array->io = NULL;
+ if (path) {
+ rc = grn_io_remove(ctx, path);
+ }
+ }
+ }
+ if (!rc) {
+ rc = grn_array_init(ctx, array, path, value_size, flags);
+ }
+ if (path) { GRN_FREE(path); }
+ return rc;
+}
+
+inline static grn_id
+grn_array_get_max_id(grn_array *array)
+{
+ return grn_array_is_io_array(array) ? array->header->curr_rec : array->array.max;
+}
+
+inline static void *
+grn_array_get_value_inline(grn_ctx *ctx, grn_array *array, grn_id id)
+{
+ if (!ctx || !array) {
+ return NULL;
+ }
+ if (grn_array_error_if_truncated(ctx, array) != GRN_SUCCESS) {
+ return NULL;
+ }
+ if (*array->n_garbages) {
+ /*
+ * grn_array_bitmap_at() is a time-consuming function, so it is called only
+ * when there are garbages in the array.
+ */
+ if (grn_array_bitmap_at(ctx, array, id) != 1) {
+ return NULL;
+ }
+ } else if (id == 0 || id > grn_array_get_max_id(array)) {
+ return NULL;
+ }
+ return grn_array_entry_at(ctx, array, id, 0);
+}
+
+int
+grn_array_get_value(grn_ctx *ctx, grn_array *array, grn_id id, void *valuebuf)
+{
+ void * const value = grn_array_get_value_inline(ctx, array, id);
+ if (value) {
+ if (valuebuf) {
+ grn_memcpy(valuebuf, value, array->value_size);
+ }
+ return array->value_size;
+ }
+ return 0;
+}
+
+void *
+_grn_array_get_value(grn_ctx *ctx, grn_array *array, grn_id id)
+{
+ return grn_array_get_value_inline(ctx, array, id);
+}
+
+inline static grn_rc
+grn_array_set_value_inline(grn_ctx *ctx, grn_array *array, grn_id id,
+ const void *value, int flags)
+{
+ void *entry;
+ entry = grn_array_entry_at(ctx, array, id, 0);
+ if (!entry) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+
+ switch ((flags & GRN_OBJ_SET_MASK)) {
+ case GRN_OBJ_SET :
+ grn_memcpy(entry, value, array->value_size);
+ return GRN_SUCCESS;
+ case GRN_OBJ_INCR :
+ switch (array->value_size) {
+ case sizeof(int32_t) :
+ *((int32_t *)entry) += *((int32_t *)value);
+ return GRN_SUCCESS;
+ case sizeof(int64_t) :
+ *((int64_t *)entry) += *((int64_t *)value);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ break;
+ case GRN_OBJ_DECR :
+ switch (array->value_size) {
+ case sizeof(int32_t) :
+ *((int32_t *)entry) -= *((int32_t *)value);
+ return GRN_SUCCESS;
+ case sizeof(int64_t) :
+ *((int64_t *)entry) -= *((int64_t *)value);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ break;
+ default :
+ /* todo : support other types. */
+ return GRN_INVALID_ARGUMENT;
+ }
+}
+
+grn_rc
+grn_array_set_value(grn_ctx *ctx, grn_array *array, grn_id id,
+ const void *value, int flags)
+{
+ grn_rc rc;
+
+ if (!ctx || !array || !value) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ rc = grn_array_error_if_truncated(ctx, array);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (*array->n_garbages) {
+ /*
+ * grn_array_bitmap_at() is a time-consuming function, so it is called only
+ * when there are garbages in the array.
+ */
+ if (grn_array_bitmap_at(ctx, array, id) != 1) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ } else if (id == 0 || id > grn_array_get_max_id(array)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ return grn_array_set_value_inline(ctx, array, id, value, flags);
+}
+
+grn_rc
+grn_array_delete_by_id(grn_ctx *ctx, grn_array *array, grn_id id,
+ grn_table_delete_optarg *optarg)
+{
+ grn_rc rc;
+ if (!ctx || !array) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ rc = grn_array_error_if_truncated(ctx, array);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (grn_array_bitmap_at(ctx, array, id) != 1) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ {
+ rc = GRN_SUCCESS;
+ /* lock */
+ if (grn_array_is_io_array(array)) {
+ if (array->value_size >= sizeof(grn_id)) {
+ struct grn_array_header * const header = array->header;
+ void * const entry = grn_array_io_entry_at(ctx, array, id, 0);
+ if (!entry) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ *((grn_id *)entry) = header->garbages;
+ header->garbages = id;
+ }
+ }
+ if (!rc) {
+ (*array->n_entries)--;
+ (*array->n_garbages)++;
+ /*
+ * The following grn_io_array_bit_off() fails iff a problem has
+ * occurred after the above grn_array_bitmap_at(). That is to say,
+ * an unexpected case.
+ */
+ grn_io_array_bit_off(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id);
+ }
+ } else {
+ if (array->value_size >= sizeof(grn_id)) {
+ void * const entry = grn_tiny_array_get(&array->array, id);
+ if (!entry) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ *((grn_id *)entry) = array->garbages;
+ array->garbages = id;
+ }
+ }
+ if (!rc) {
+ (*array->n_entries)--;
+ (*array->n_garbages)++;
+ /*
+ * The following grn_io_array_bit_off() fails iff a problem has
+ * occurred after the above grn_array_bitmap_at(). That is to say,
+ * an unexpected case.
+ */
+ grn_tiny_bitmap_get_and_set(&array->bitmap, id, 0);
+ }
+ }
+ /* unlock */
+ return rc;
+ }
+}
+
+grn_id
+grn_array_at(grn_ctx *ctx, grn_array *array, grn_id id)
+{
+ if (grn_array_error_if_truncated(ctx, array) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (*array->n_garbages) {
+ /*
+ * grn_array_bitmap_at() is a time-consuming function, so it is called only
+ * when there are garbages in the array.
+ */
+ if (grn_array_bitmap_at(ctx, array, id) != 1) {
+ return GRN_ID_NIL;
+ }
+ } else if (id > grn_array_get_max_id(array)) {
+ return GRN_ID_NIL;
+ }
+ return id;
+}
+
+grn_rc
+grn_array_copy_sort_key(grn_ctx *ctx, grn_array *array,
+ grn_table_sort_key *keys, int n_keys)
+{
+ array->keys = (grn_table_sort_key *)GRN_MALLOCN(grn_table_sort_key, n_keys);
+ if (!array->keys) {
+ return ctx->rc;
+ }
+ grn_memcpy(array->keys, keys, sizeof(grn_table_sort_key) * n_keys);
+ array->n_keys = n_keys;
+ return GRN_SUCCESS;
+}
+
+void
+grn_array_cursor_close(grn_ctx *ctx, grn_array_cursor *cursor)
+{
+ GRN_ASSERT(cursor->ctx == ctx);
+ GRN_FREE(cursor);
+}
+
+grn_array_cursor *
+grn_array_cursor_open(grn_ctx *ctx, grn_array *array, grn_id min, grn_id max,
+ int offset, int limit, int flags)
+{
+ grn_array_cursor *cursor;
+ if (!array || !ctx) { return NULL; }
+ if (grn_array_error_if_truncated(ctx, array) != GRN_SUCCESS) {
+ return NULL;
+ }
+
+ cursor = (grn_array_cursor *)GRN_MALLOCN(grn_array_cursor, 1);
+ if (!cursor) { return NULL; }
+
+ GRN_DB_OBJ_SET_TYPE(cursor, GRN_CURSOR_TABLE_NO_KEY);
+ cursor->array = array;
+ cursor->ctx = ctx;
+ cursor->obj.header.flags = flags;
+ cursor->obj.header.domain = GRN_ID_NIL;
+
+ if (flags & GRN_CURSOR_DESCENDING) {
+ cursor->dir = -1;
+ if (max) {
+ cursor->curr_rec = max;
+ if (!(flags & GRN_CURSOR_LT)) { cursor->curr_rec++; }
+ } else {
+ cursor->curr_rec = grn_array_get_max_id(array) + 1;
+ }
+ if (min) {
+ cursor->tail = min;
+ if ((flags & GRN_CURSOR_GT)) { cursor->tail++; }
+ } else {
+ cursor->tail = GRN_ID_NIL + 1;
+ }
+ if (cursor->curr_rec < cursor->tail) { cursor->tail = cursor->curr_rec; }
+ } else {
+ cursor->dir = 1;
+ if (min) {
+ cursor->curr_rec = min;
+ if (!(flags & GRN_CURSOR_GT)) { cursor->curr_rec--; }
+ } else {
+ cursor->curr_rec = GRN_ID_NIL;
+ }
+ if (max) {
+ cursor->tail = max;
+ if ((flags & GRN_CURSOR_LT)) { cursor->tail--; }
+ } else {
+ cursor->tail = grn_array_get_max_id(array);
+ }
+ if (cursor->tail < cursor->curr_rec) { cursor->tail = cursor->curr_rec; }
+ }
+
+ if (*array->n_garbages) {
+ while (offset && cursor->curr_rec != cursor->tail) {
+ cursor->curr_rec += cursor->dir;
+ if (grn_array_bitmap_at(ctx, cursor->array, cursor->curr_rec) == 1) {
+ offset--;
+ }
+ }
+ } else {
+ cursor->curr_rec += cursor->dir * offset;
+ }
+ cursor->rest = (limit < 0) ? GRN_ARRAY_MAX : limit;
+ return cursor;
+}
+
+grn_id
+grn_array_cursor_next(grn_ctx *ctx, grn_array_cursor *cursor)
+{
+ if (cursor && cursor->rest) {
+ while (cursor->curr_rec != cursor->tail) {
+ cursor->curr_rec += cursor->dir;
+ if (*cursor->array->n_garbages) {
+ if (grn_array_bitmap_at(ctx, cursor->array, cursor->curr_rec) != 1) {
+ continue;
+ }
+ }
+ cursor->rest--;
+ return cursor->curr_rec;
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_array_next(grn_ctx *ctx, grn_array *array, grn_id id)
+{
+ grn_id max_id;
+ if (grn_array_error_if_truncated(ctx, array) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ max_id = grn_array_get_max_id(array);
+ while (++id <= max_id) {
+ if (!*array->n_garbages ||
+ grn_array_bitmap_at(ctx, array, id) == 1) {
+ return id;
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+int
+grn_array_cursor_get_value(grn_ctx *ctx, grn_array_cursor *cursor, void **value)
+{
+ if (cursor && value) {
+ void * const entry = grn_array_entry_at(ctx, cursor->array, cursor->curr_rec, 0);
+ if (entry) {
+ *value = entry;
+ return cursor->array->value_size;
+ }
+ }
+ return 0;
+}
+
+grn_rc
+grn_array_cursor_set_value(grn_ctx *ctx, grn_array_cursor *cursor,
+ const void *value, int flags)
+{
+ return grn_array_set_value_inline(ctx, cursor->array, cursor->curr_rec,
+ value, flags);
+}
+
+grn_rc
+grn_array_cursor_delete(grn_ctx *ctx, grn_array_cursor *cursor,
+ grn_table_delete_optarg *optarg)
+{
+ return grn_array_delete_by_id(ctx, cursor->array, cursor->curr_rec, optarg);
+}
+
+inline static grn_id
+grn_array_add_to_tiny_array(grn_ctx *ctx, grn_array *array, void **value)
+{
+ grn_id id = array->garbages;
+ void *entry;
+ if (id) {
+ /* These operations fail iff the array is broken. */
+ entry = grn_tiny_array_get(&array->array, id);
+ if (!entry) {
+ return GRN_ID_NIL;
+ }
+ array->garbages = *(grn_id *)entry;
+ memset(entry, 0, array->value_size);
+ (*array->n_garbages)--;
+ if (!grn_tiny_bitmap_get_and_set(&array->bitmap, id, 1)) {
+ /* Actually, it is difficult to recover from this error. */
+ *(grn_id *)entry = array->garbages;
+ array->garbages = id;
+ (*array->n_garbages)++;
+ return GRN_ID_NIL;
+ }
+ } else {
+ id = array->array.max + 1;
+ if (!grn_tiny_bitmap_put_and_set(&array->bitmap, id, 1)) {
+ return GRN_ID_NIL;
+ }
+ entry = grn_tiny_array_put(&array->array, id);
+ if (!entry) {
+ grn_tiny_bitmap_get_and_set(&array->bitmap, id, 0);
+ return GRN_ID_NIL;
+ }
+ array->array.max = id;
+ }
+ (*array->n_entries)++;
+ if (value) { *value = entry; }
+ return id;
+}
+
+inline static grn_id
+grn_array_add_to_io_array(grn_ctx *ctx, grn_array *array, void **value)
+{
+ grn_id id;
+ void *entry;
+ struct grn_array_header *header;
+ if (grn_array_error_if_truncated(ctx, array) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ header = array->header;
+ id = header->garbages;
+ if (id) {
+ /* These operations fail iff the array is broken. */
+ entry = grn_array_io_entry_at(ctx, array, id, GRN_TABLE_ADD);
+ if (!entry) {
+ return GRN_ID_NIL;
+ }
+ header->garbages = *(grn_id *)entry;
+ memset(entry, 0, header->value_size);
+ (*array->n_garbages)--;
+ if (!grn_io_array_bit_on(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id)) {
+ /* Actually, it is difficult to recover from this error. */
+ *(grn_id *)entry = array->garbages;
+ array->garbages = id;
+ (*array->n_garbages)++;
+ return GRN_ID_NIL;
+ }
+ } else {
+ if (header->curr_rec >= GRN_ARRAY_MAX) { return GRN_ID_NIL; }
+ id = header->curr_rec + 1;
+ if (!grn_io_array_bit_on(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id)) {
+ return GRN_ID_NIL;
+ }
+ entry = grn_array_io_entry_at(ctx, array, id, GRN_TABLE_ADD);
+ if (!entry) {
+ grn_io_array_bit_off(ctx, array->io, GRN_ARRAY_BITMAP_SEGMENT, id);
+ return GRN_ID_NIL;
+ }
+ header->curr_rec = id;
+ }
+ (*array->n_entries)++;
+ if (value) { *value = entry; }
+ return id;
+}
+
+void
+grn_array_clear_curr_rec(grn_ctx *ctx, grn_array *array)
+{
+ struct grn_array_header * const header = array->header;
+ header->curr_rec = GRN_ID_NIL;
+}
+
+grn_id
+grn_array_add(grn_ctx *ctx, grn_array *array, void **value)
+{
+ if (ctx && array) {
+ if (grn_array_is_io_array(array)) {
+ return grn_array_add_to_io_array(ctx, array, value);
+ } else {
+ return grn_array_add_to_tiny_array(ctx, array, value);
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_array_push(grn_ctx *ctx, grn_array *array,
+ void (*func)(grn_ctx *, grn_array *, grn_id, void *),
+ void *func_arg)
+{
+ grn_id id = GRN_ID_NIL;
+ grn_table_queue *queue = grn_array_queue(ctx, array);
+ if (queue) {
+ MUTEX_LOCK(queue->mutex);
+ if (grn_table_queue_head(queue) == queue->cap) {
+ grn_array_clear_curr_rec(ctx, array);
+ }
+ id = grn_array_add(ctx, array, NULL);
+ if (func) {
+ func(ctx, array, id, func_arg);
+ }
+ if (grn_table_queue_size(queue) == queue->cap) {
+ grn_table_queue_tail_increment(queue);
+ }
+ grn_table_queue_head_increment(queue);
+ COND_SIGNAL(queue->cond);
+ MUTEX_UNLOCK(queue->mutex);
+ } else {
+ ERR(GRN_OPERATION_NOT_SUPPORTED, "only persistent arrays support push");
+ }
+ return id;
+}
+
+grn_id
+grn_array_pull(grn_ctx *ctx, grn_array *array, grn_bool blockp,
+ void (*func)(grn_ctx *, grn_array *, grn_id, void *),
+ void *func_arg)
+{
+ grn_id id = GRN_ID_NIL;
+ grn_table_queue *queue = grn_array_queue(ctx, array);
+ if (queue) {
+ MUTEX_LOCK(queue->mutex);
+ queue->unblock_requested = GRN_FALSE;
+ while (grn_table_queue_size(queue) == 0) {
+ if (!blockp || queue->unblock_requested) {
+ MUTEX_UNLOCK(queue->mutex);
+ GRN_OUTPUT_BOOL(0);
+ return id;
+ }
+ COND_WAIT(queue->cond, queue->mutex);
+ }
+ grn_table_queue_tail_increment(queue);
+ id = grn_table_queue_tail(queue);
+ if (func) {
+ func(ctx, array, id, func_arg);
+ }
+ MUTEX_UNLOCK(queue->mutex);
+ } else {
+ ERR(GRN_OPERATION_NOT_SUPPORTED, "only persistent arrays support pull");
+ }
+ return id;
+}
+
+void
+grn_array_unblock(grn_ctx *ctx, grn_array *array)
+{
+ grn_table_queue *queue = grn_array_queue(ctx, array);
+ if (!queue) {
+ return;
+ }
+
+ queue->unblock_requested = GRN_TRUE;
+ COND_BROADCAST(queue->cond);
+}
+
+/* grn_hash : hash table */
+
+#define GRN_HASH_MAX_SEGMENT 0x400
+#define GRN_HASH_HEADER_SIZE_NORMAL 0x9000
+#define GRN_HASH_HEADER_SIZE_LARGE\
+ (GRN_HASH_HEADER_SIZE_NORMAL +\
+ (sizeof(grn_id) *\
+ (GRN_HASH_MAX_KEY_SIZE_LARGE - GRN_HASH_MAX_KEY_SIZE_NORMAL)))
+#define GRN_HASH_SEGMENT_SIZE 0x400000
+#define GRN_HASH_KEY_MAX_N_SEGMENTS_NORMAL 0x400
+#define GRN_HASH_KEY_MAX_N_SEGMENTS_LARGE 0x40000
+#define W_OF_KEY_IN_A_SEGMENT 22
+#define GRN_HASH_KEY_MAX_TOTAL_SIZE_NORMAL\
+ (((uint64_t)(1) << W_OF_KEY_IN_A_SEGMENT) *\
+ GRN_HASH_KEY_MAX_N_SEGMENTS_NORMAL - 1)
+#define GRN_HASH_KEY_MAX_TOTAL_SIZE_LARGE\
+ (((uint64_t)(1) << W_OF_KEY_IN_A_SEGMENT) *\
+ GRN_HASH_KEY_MAX_N_SEGMENTS_LARGE - 1)
+#define IDX_MASK_IN_A_SEGMENT 0xfffff
+
+typedef struct {
+ uint8_t key[4];
+ uint8_t value[1];
+} grn_plain_hash_entry;
+
+typedef struct {
+ uint32_t hash_value;
+ uint8_t key_and_value[1];
+} grn_rich_hash_entry;
+
+typedef struct {
+ uint32_t hash_value;
+ uint16_t flag;
+ uint16_t key_size;
+ union {
+ uint8_t buf[sizeof(uint32_t)];
+ uint32_t offset;
+ } key;
+ uint8_t value[1];
+} grn_io_hash_entry_normal;
+
+typedef struct {
+ uint32_t hash_value;
+ uint16_t flag;
+ uint16_t key_size;
+ union {
+ uint8_t buf[sizeof(uint64_t)];
+ uint64_t offset;
+ } key;
+ uint8_t value[1];
+} grn_io_hash_entry_large;
+
+typedef struct {
+ uint32_t hash_value;
+ uint16_t flag;
+ uint16_t key_size;
+ union {
+ uint8_t buf[sizeof(void *)];
+ void *ptr;
+ } key;
+ uint8_t value[1];
+} grn_tiny_hash_entry;
+
+/*
+ * hash_value is valid even if the entry is grn_plain_hash_entry. In this case,
+ * its hash_value equals its key.
+ * flag, key_size and key.buf are valid if the entry has a variable length key.
+ */
+typedef struct {
+ uint32_t hash_value;
+ uint16_t flag;
+ uint16_t key_size;
+} grn_hash_entry_header;
+
+typedef union {
+ uint32_t hash_value;
+ grn_hash_entry_header header;
+ grn_plain_hash_entry plain_entry;
+ grn_rich_hash_entry rich_entry;
+ grn_io_hash_entry_normal io_entry_normal;
+ grn_io_hash_entry_large io_entry_large;
+ grn_tiny_hash_entry tiny_entry;
+} grn_hash_entry;
+
+typedef struct {
+ uint32_t key;
+ uint8_t dummy[1];
+} entry;
+
+typedef struct {
+ uint32_t key;
+ uint16_t flag;
+ uint16_t size;
+ uint32_t str;
+ uint8_t dummy[1];
+} entry_str;
+
+typedef struct {
+ uint32_t key;
+ uint16_t flag;
+ uint16_t size;
+ char *str;
+ uint8_t dummy[1];
+} entry_astr;
+
+enum {
+ GRN_HASH_KEY_SEGMENT = 0,
+ GRN_HASH_ENTRY_SEGMENT = 1,
+ GRN_HASH_INDEX_SEGMENT = 2,
+ GRN_HASH_BITMAP_SEGMENT = 3
+};
+
+inline static int
+grn_hash_name(grn_ctx *ctx, grn_hash *hash, char *buffer, int buffer_size)
+{
+ int name_size;
+
+ if (DB_OBJ(hash)->id == GRN_ID_NIL) {
+ grn_strcpy(buffer, buffer_size, "(anonymous)");
+ name_size = strlen(buffer);
+ } else {
+ name_size = grn_obj_name(ctx, (grn_obj *)hash, buffer, buffer_size);
+ }
+
+ return name_size;
+}
+
+inline static grn_bool
+grn_hash_is_io_hash(grn_hash *hash)
+{
+ return hash->io != NULL;
+}
+
+inline static void *
+grn_io_hash_entry_at(grn_ctx *ctx, grn_hash *hash, grn_id id, int flags)
+{
+ return grn_io_array_at_inline(ctx, hash->io, GRN_HASH_ENTRY_SEGMENT, id, flags);
+}
+
+/* todo : error handling */
+inline static void *
+grn_hash_entry_at(grn_ctx *ctx, grn_hash *hash, grn_id id, int flags)
+{
+ if (grn_hash_is_io_hash(hash)) {
+ return grn_io_hash_entry_at(ctx, hash, id, flags);
+ } else {
+ return grn_tiny_array_at_inline(&hash->a, id);
+ }
+}
+
+inline static grn_bool
+grn_hash_bitmap_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
+{
+ if (grn_hash_is_io_hash(hash)) {
+ return grn_io_array_bit_at(ctx, hash->io, GRN_HASH_BITMAP_SEGMENT, id) == 1;
+ } else {
+ return grn_tiny_bitmap_put(&hash->bitmap, id) == 1;
+ }
+}
+
+inline static grn_id *
+grn_io_hash_idx_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
+{
+ return grn_io_array_at_inline(ctx, hash->io, GRN_HASH_INDEX_SEGMENT,
+ id, GRN_TABLE_ADD);
+}
+
+inline static grn_id *
+grn_hash_idx_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
+{
+ if (grn_hash_is_io_hash(hash)) {
+ id = (id & *hash->max_offset) + hash->header.common->idx_offset;
+ return grn_io_hash_idx_at(ctx, hash, id);
+ } else {
+ return hash->index + (id & *hash->max_offset);
+ }
+}
+
+inline static void *
+grn_io_hash_key_at(grn_ctx *ctx, grn_hash *hash, uint64_t pos)
+{
+ return grn_io_array_at_inline(ctx, hash->io, GRN_HASH_KEY_SEGMENT,
+ pos, GRN_TABLE_ADD);
+}
+
+#define HASH_IMMEDIATE 1
+
+#define MAX_INDEX_SIZE ((GRN_HASH_MAX_SEGMENT * (IDX_MASK_IN_A_SEGMENT + 1)) >> 1)
+
+inline static uint16_t
+grn_hash_entry_get_key_size(grn_hash *hash, grn_hash_entry *entry)
+{
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ return entry->header.key_size;
+ } else {
+ return hash->key_size;
+ }
+}
+
+inline static char *
+grn_hash_entry_get_key(grn_ctx *ctx, grn_hash *hash, grn_hash_entry *entry)
+{
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (grn_hash_is_io_hash(hash)) {
+ if (grn_hash_is_large_total_key_size(ctx, hash)) {
+ if (entry->io_entry_large.flag & HASH_IMMEDIATE) {
+ return (char *)entry->io_entry_large.key.buf;
+ } else {
+ return (char *)grn_io_hash_key_at(ctx, hash,
+ entry->io_entry_large.key.offset);
+ }
+ } else {
+ if (entry->io_entry_normal.flag & HASH_IMMEDIATE) {
+ return (char *)entry->io_entry_normal.key.buf;
+ } else {
+ return (char *)grn_io_hash_key_at(ctx, hash,
+ entry->io_entry_normal.key.offset);
+ }
+ }
+ } else {
+ if (entry->tiny_entry.flag & HASH_IMMEDIATE) {
+ return (char *)entry->tiny_entry.key.buf;
+ } else {
+ return entry->tiny_entry.key.ptr;
+ }
+ }
+ } else {
+ if (hash->key_size == sizeof(uint32_t)) {
+ return (char *)entry->plain_entry.key;
+ } else {
+ return (char *)entry->rich_entry.key_and_value;
+ }
+ }
+}
+
+inline static void *
+grn_hash_entry_get_value(grn_ctx *ctx, grn_hash *hash, grn_hash_entry *entry)
+{
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (grn_hash_is_io_hash(hash)) {
+ if (grn_hash_is_large_total_key_size(ctx, hash)) {
+ return entry->io_entry_large.value;
+ } else {
+ return entry->io_entry_normal.value;
+ }
+ } else {
+ return entry->tiny_entry.value;
+ }
+ } else {
+ if (hash->key_size == sizeof(uint32_t)) {
+ return entry->plain_entry.value;
+ } else {
+ return entry->rich_entry.key_and_value + hash->key_size;
+ }
+ }
+}
+
+inline static grn_rc
+grn_io_hash_entry_put_key(grn_ctx *ctx, grn_hash *hash,
+ grn_hash_entry *entry,
+ const void *key, unsigned int key_size)
+{
+ grn_bool is_large_mode;
+ grn_bool key_exist;
+ uint64_t key_offset;
+ grn_io_hash_entry_normal *io_entry_normal = &(entry->io_entry_normal);
+ grn_io_hash_entry_large *io_entry_large = &(entry->io_entry_large);
+
+ is_large_mode = grn_hash_is_large_total_key_size(ctx, hash);
+
+ if (is_large_mode) {
+ key_exist = (io_entry_large->key_size > 0);
+ } else {
+ key_exist = (io_entry_normal->key_size > 0);
+ }
+
+ if (key_exist > 0) {
+ if (is_large_mode) {
+ key_offset = io_entry_large->key.offset;
+ } else {
+ key_offset = io_entry_normal->key.offset;
+ }
+ } else {
+ uint64_t segment_id;
+ grn_hash_header_common *header;
+ uint64_t curr_key;
+ uint64_t max_total_size;
+
+ header = hash->header.common;
+ if (key_size >= GRN_HASH_SEGMENT_SIZE) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_hash_name(ctx, hash, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[hash][key][put] too long key: <%.*s>: max=%u: key size=%u",
+ name_size, name,
+ GRN_HASH_SEGMENT_SIZE,
+ key_size);
+ return ctx->rc;
+ }
+
+ if (is_large_mode) {
+ curr_key = header->curr_key_large;
+ max_total_size = GRN_HASH_KEY_MAX_TOTAL_SIZE_LARGE;
+ } else {
+ curr_key = header->curr_key_normal;
+ max_total_size = GRN_HASH_KEY_MAX_TOTAL_SIZE_NORMAL;
+ }
+
+ if (key_size > (max_total_size - curr_key)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_hash_name(ctx, hash, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_NOT_ENOUGH_SPACE,
+ "[hash][key][put] total key size is over: <%.*s>: "
+ "max=%" GRN_FMT_INT64U ": "
+ "current=%" GRN_FMT_INT64U ": "
+ "new key size=%u",
+ name_size, name,
+ max_total_size,
+ curr_key,
+ key_size);
+ return ctx->rc;
+ }
+ key_offset = curr_key;
+ segment_id = (key_offset + key_size) >> W_OF_KEY_IN_A_SEGMENT;
+ if ((key_offset >> W_OF_KEY_IN_A_SEGMENT) != segment_id) {
+ key_offset = segment_id << W_OF_KEY_IN_A_SEGMENT;
+ if (is_large_mode) {
+ header->curr_key_large = key_offset;
+ } else {
+ header->curr_key_normal = key_offset;
+ }
+ }
+ if (is_large_mode) {
+ header->curr_key_large += key_size;
+ io_entry_large->key.offset = key_offset;
+ } else {
+ header->curr_key_normal += key_size;
+ io_entry_normal->key.offset = key_offset;
+ }
+ }
+
+ {
+ void * const key_ptr = grn_io_hash_key_at(ctx, hash, key_offset);
+ if (!key_ptr) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_hash_name(ctx, hash, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[hash][key][put] failed to allocate for new key: <%.*s>: "
+ "new offset:%" GRN_FMT_INT64U " "
+ "key size:%u",
+ name_size, name,
+ key_offset,
+ key_size);
+ return ctx->rc;
+ }
+ grn_memcpy(key_ptr, key, key_size);
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_hash_entry_put_key(grn_ctx *ctx, grn_hash *hash,
+ grn_hash_entry *entry, uint32_t hash_value,
+ const void *key, unsigned int key_size)
+{
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (grn_hash_is_io_hash(hash)) {
+ grn_bool is_large_mode;
+ uint8_t *buffer;
+ size_t buffer_size;
+ uint16_t flag;
+
+ is_large_mode = grn_hash_is_large_total_key_size(ctx, hash);
+ if (is_large_mode) {
+ buffer = entry->io_entry_large.key.buf;
+ buffer_size = sizeof(entry->io_entry_large.key.buf);
+ } else {
+ buffer = entry->io_entry_normal.key.buf;
+ buffer_size = sizeof(entry->io_entry_normal.key.buf);
+ }
+
+ if (key_size <= buffer_size) {
+ grn_memcpy(buffer, key, key_size);
+ flag = HASH_IMMEDIATE;
+ } else {
+ const grn_rc rc =
+ grn_io_hash_entry_put_key(ctx, hash, entry, key, key_size);
+ if (rc) {
+ return rc;
+ }
+ flag = 0;
+ }
+
+ if (is_large_mode) {
+ entry->io_entry_large.flag = flag;
+ entry->io_entry_large.hash_value = hash_value;
+ entry->io_entry_large.key_size = key_size;
+ } else {
+ entry->io_entry_normal.flag = flag;
+ entry->io_entry_normal.hash_value = hash_value;
+ entry->io_entry_normal.key_size = key_size;
+ }
+ } else {
+ if (key_size <= sizeof(entry->tiny_entry.key.buf)) {
+ grn_memcpy(entry->tiny_entry.key.buf, key, key_size);
+ entry->tiny_entry.flag = HASH_IMMEDIATE;
+ } else {
+ grn_ctx * const ctx = hash->ctx;
+ entry->tiny_entry.key.ptr = GRN_CTX_ALLOC(ctx, key_size);
+ if (!entry->tiny_entry.key.ptr) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ grn_memcpy(entry->tiny_entry.key.ptr, key, key_size);
+ entry->tiny_entry.flag = 0;
+ }
+ entry->tiny_entry.hash_value = hash_value;
+ entry->tiny_entry.key_size = key_size;
+ }
+ } else {
+ if (hash->key_size == sizeof(uint32_t)) {
+ *(uint32_t *)entry->plain_entry.key = hash_value;
+ } else {
+ entry->rich_entry.hash_value = hash_value;
+ grn_memcpy(entry->rich_entry.key_and_value, key, key_size);
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_hash_entry_compare_key() returns GRN_TRUE if the entry key equals the
+ * specified key, or GRN_FALSE otherwise.
+ */
+inline static grn_bool
+grn_hash_entry_compare_key(grn_ctx *ctx, grn_hash *hash,
+ grn_hash_entry *entry, uint32_t hash_value,
+ const void *key, unsigned int key_size)
+{
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (entry->hash_value != hash_value ||
+ entry->header.key_size != key_size) {
+ return GRN_FALSE;
+ }
+ if (grn_hash_is_io_hash(hash)) {
+ if (grn_hash_is_large_total_key_size(ctx, hash)) {
+ if (entry->io_entry_large.flag & HASH_IMMEDIATE) {
+ return !memcmp(key, entry->io_entry_large.key.buf, key_size);
+ } else {
+ const void * const entry_key_ptr =
+ grn_io_hash_key_at(ctx, hash, entry->io_entry_large.key.offset);
+ return !memcmp(key, entry_key_ptr, key_size);
+ }
+ } else {
+ if (entry->io_entry_normal.flag & HASH_IMMEDIATE) {
+ return !memcmp(key, entry->io_entry_normal.key.buf, key_size);
+ } else {
+ const void * const entry_key_ptr =
+ grn_io_hash_key_at(ctx, hash, entry->io_entry_normal.key.offset);
+ return !memcmp(key, entry_key_ptr, key_size);
+ }
+ }
+ } else {
+ if (entry->tiny_entry.flag & HASH_IMMEDIATE) {
+ return !memcmp(key, entry->tiny_entry.key.buf, key_size);
+ } else {
+ return !memcmp(key, entry->tiny_entry.key.ptr, key_size);
+ }
+ }
+ } else {
+ if (entry->hash_value != hash_value) {
+ return GRN_FALSE;
+ }
+ if (key_size == sizeof(uint32_t)) {
+ return GRN_TRUE;
+ } else {
+ return !memcmp(key, entry->rich_entry.key_and_value, key_size);
+ }
+ }
+}
+
+inline static char *
+get_key(grn_ctx *ctx, grn_hash *hash, entry_str *n)
+{
+ return grn_hash_entry_get_key(ctx, hash, (grn_hash_entry *)n);
+}
+
+inline static void *
+get_value(grn_ctx *ctx, grn_hash *hash, entry_str *n)
+{
+ return grn_hash_entry_get_value(ctx, hash, (grn_hash_entry *)n);
+}
+
+inline static int
+match_key(grn_ctx *ctx, grn_hash *hash, entry_str *ee, uint32_t h,
+ const char *key, unsigned int len)
+{
+ return grn_hash_entry_compare_key(ctx, hash, (grn_hash_entry *)ee,
+ h, key, len);
+}
+
+#define GARBAGE (0xffffffff)
+
+inline static uint32_t
+grn_io_hash_calculate_entry_size(uint32_t key_size, uint32_t value_size,
+ uint32_t flags)
+{
+ if (flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (flags & GRN_OBJ_KEY_LARGE) {
+ return (uintptr_t)((grn_io_hash_entry_large *)0)->value + value_size;
+ } else {
+ return (uintptr_t)((grn_io_hash_entry_normal *)0)->value + value_size;
+ }
+ } else {
+ if (key_size == sizeof(uint32_t)) {
+ return (uintptr_t)((grn_plain_hash_entry *)0)->value + value_size;
+ } else {
+ return (uintptr_t)((grn_rich_hash_entry *)0)->key_and_value
+ + key_size + value_size;
+ }
+ }
+}
+
+static grn_io *
+grn_io_hash_create_io(grn_ctx *ctx, const char *path,
+ uint32_t header_size, uint32_t entry_size,
+ uint32_t flags)
+{
+ uint32_t w_of_element = 0;
+ grn_io_array_spec array_spec[4];
+
+ while ((1U << w_of_element) < entry_size) {
+ w_of_element++;
+ }
+
+ array_spec[GRN_HASH_KEY_SEGMENT].w_of_element = 0;
+ if (flags & GRN_OBJ_KEY_LARGE) {
+ array_spec[GRN_HASH_KEY_SEGMENT].max_n_segments =
+ GRN_HASH_KEY_MAX_N_SEGMENTS_LARGE;
+ } else {
+ array_spec[GRN_HASH_KEY_SEGMENT].max_n_segments =
+ GRN_HASH_KEY_MAX_N_SEGMENTS_NORMAL;
+ }
+ array_spec[GRN_HASH_ENTRY_SEGMENT].w_of_element = w_of_element;
+ array_spec[GRN_HASH_ENTRY_SEGMENT].max_n_segments =
+ 1U << (30 - (22 - w_of_element));
+ array_spec[GRN_HASH_INDEX_SEGMENT].w_of_element = 2;
+ array_spec[GRN_HASH_INDEX_SEGMENT].max_n_segments = 1U << (30 - (22 - 2));
+ array_spec[GRN_HASH_BITMAP_SEGMENT].w_of_element = 0;
+ array_spec[GRN_HASH_BITMAP_SEGMENT].max_n_segments = 1U << (30 - (22 + 3));
+ return grn_io_create_with_array(ctx, path, header_size,
+ GRN_HASH_SEGMENT_SIZE,
+ grn_io_auto, 4, array_spec);
+}
+
+static grn_rc
+grn_io_hash_init(grn_ctx *ctx, grn_hash *hash, const char *path,
+ uint32_t key_size, uint32_t value_size, uint32_t flags,
+ grn_encoding encoding, uint32_t init_size)
+{
+ grn_io *io;
+ grn_hash_header_common *header;
+ uint32_t header_size, entry_size, max_offset;
+
+ if (key_size <= GRN_HASH_MAX_KEY_SIZE_NORMAL) {
+ header_size = GRN_HASH_HEADER_SIZE_NORMAL;
+ } else {
+ header_size = GRN_HASH_HEADER_SIZE_LARGE;
+ }
+ entry_size = grn_io_hash_calculate_entry_size(key_size, value_size, flags);
+
+ io = grn_io_hash_create_io(ctx, path, header_size, entry_size, flags);
+ if (!io) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ grn_io_set_type(io, GRN_TABLE_HASH_KEY);
+
+ max_offset = IDX_MASK_IN_A_SEGMENT + 1;
+ while (max_offset < init_size * 2) {
+ max_offset *= 2;
+ }
+ max_offset--;
+
+ if (encoding == GRN_ENC_DEFAULT) {
+ encoding = ctx->encoding;
+ }
+
+ hash->key_size = key_size;
+
+ header = grn_io_header(io);
+ header->flags = flags;
+ header->encoding = encoding;
+ header->key_size = key_size;
+ header->curr_rec = 0;
+ header->curr_key_normal = 0;
+ header->curr_key_large = 0;
+ header->lock = 0;
+ header->idx_offset = 0;
+ header->value_size = value_size;
+ header->entry_size = entry_size;
+ header->max_offset = max_offset;
+ header->n_entries = 0;
+ header->n_garbages = 0;
+ header->tokenizer = GRN_ID_NIL;
+ if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
+ header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
+ hash->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ header->normalizer = grn_obj_id(ctx, hash->normalizer);
+ } else {
+ hash->normalizer = NULL;
+ header->normalizer = GRN_ID_NIL;
+ }
+ header->truncated = GRN_FALSE;
+ GRN_PTR_INIT(&(hash->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ {
+ grn_table_queue *queue;
+ if (GRN_HASH_IS_LARGE_KEY(hash)) {
+ queue = &(((grn_hash_header_large *)(header))->queue);
+ } else {
+ queue = &(((grn_hash_header_normal *)(header))->queue);
+ }
+ grn_table_queue_init(ctx, queue);
+ }
+
+ hash->obj.header.flags = (header->flags & GRN_OBJ_FLAGS_MASK);
+ hash->ctx = ctx;
+ hash->encoding = encoding;
+ hash->value_size = value_size;
+ hash->entry_size = entry_size;
+ hash->n_garbages = &header->n_garbages;
+ hash->n_entries = &header->n_entries;
+ hash->max_offset = &header->max_offset;
+ hash->io = io;
+ hash->header.common = header;
+ hash->lock = &header->lock;
+ hash->tokenizer = NULL;
+ return GRN_SUCCESS;
+}
+
+#define INITIAL_INDEX_SIZE 256U
+
+static uint32_t
+grn_tiny_hash_calculate_entry_size(uint32_t key_size, uint32_t value_size,
+ uint32_t flags)
+{
+ uint32_t entry_size;
+ if (flags & GRN_OBJ_KEY_VAR_SIZE) {
+ entry_size = (uintptr_t)((grn_tiny_hash_entry *)0)->value + value_size;
+ } else {
+ if (key_size == sizeof(uint32_t)) {
+ entry_size = (uintptr_t)((grn_plain_hash_entry *)0)->value + value_size;
+ } else {
+ entry_size = (uintptr_t)((grn_rich_hash_entry *)0)->key_and_value
+ + key_size + value_size;
+ }
+ }
+ if (entry_size != sizeof(uint32_t)) {
+ entry_size += sizeof(uintptr_t) - 1;
+ entry_size &= ~(sizeof(uintptr_t) - 1);
+ }
+ return entry_size;
+}
+
+static grn_rc
+grn_tiny_hash_init(grn_ctx *ctx, grn_hash *hash, const char *path,
+ uint32_t key_size, uint32_t value_size, uint32_t flags,
+ grn_encoding encoding)
+{
+ uint32_t entry_size;
+
+ if (path) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ hash->index = GRN_CTX_ALLOC(ctx, INITIAL_INDEX_SIZE * sizeof(grn_id));
+ if (!hash->index) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+
+ entry_size = grn_tiny_hash_calculate_entry_size(key_size, value_size, flags);
+ hash->obj.header.flags = flags;
+ hash->ctx = ctx;
+ hash->key_size = key_size;
+ hash->encoding = encoding;
+ hash->value_size = value_size;
+ hash->entry_size = entry_size;
+ hash->n_garbages = &hash->n_garbages_;
+ hash->n_entries = &hash->n_entries_;
+ hash->max_offset = &hash->max_offset_;
+ hash->max_offset_ = INITIAL_INDEX_SIZE - 1;
+ hash->io = NULL;
+ hash->header.common = NULL;
+ hash->n_garbages_ = 0;
+ hash->n_entries_ = 0;
+ hash->garbages = GRN_ID_NIL;
+ hash->tokenizer = NULL;
+ hash->normalizer = NULL;
+ GRN_PTR_INIT(&(hash->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_tiny_array_init(ctx, &hash->a, entry_size, GRN_TINY_ARRAY_CLEAR);
+ grn_tiny_bitmap_init(ctx, &hash->bitmap);
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_hash_init(grn_ctx *ctx, grn_hash *hash, const char *path,
+ uint32_t key_size, uint32_t value_size, uint32_t flags)
+{
+ if (flags & GRN_HASH_TINY) {
+ return grn_tiny_hash_init(ctx, hash, path, key_size, value_size,
+ flags, ctx->encoding);
+ } else {
+ return grn_io_hash_init(ctx, hash, path, key_size, value_size,
+ flags, ctx->encoding, 0);
+ }
+}
+
+grn_hash *
+grn_hash_create(grn_ctx *ctx, const char *path, uint32_t key_size, uint32_t value_size,
+ uint32_t flags)
+{
+ grn_hash *hash;
+ if (!ctx) {
+ return NULL;
+ }
+ if (key_size > GRN_HASH_MAX_KEY_SIZE_LARGE) {
+ return NULL;
+ }
+ hash = (grn_hash *)GRN_CALLOC(sizeof(grn_hash));
+ if (!hash) {
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(hash, GRN_TABLE_HASH_KEY);
+ if (grn_hash_init(ctx, hash, path, key_size, value_size, flags)) {
+ GRN_FREE(hash);
+ return NULL;
+ }
+ return hash;
+}
+
+grn_hash *
+grn_hash_open(grn_ctx *ctx, const char *path)
+{
+ if (ctx) {
+ grn_io * const io = grn_io_open(ctx, path, grn_io_auto);
+ if (io) {
+ grn_hash_header_common * const header = grn_io_header(io);
+ uint32_t io_type = grn_io_get_type(io);
+ if (io_type == GRN_TABLE_HASH_KEY) {
+ grn_hash * const hash = (grn_hash *)GRN_MALLOC(sizeof(grn_hash));
+ if (hash) {
+ if (!(header->flags & GRN_HASH_TINY)) {
+ GRN_DB_OBJ_SET_TYPE(hash, GRN_TABLE_HASH_KEY);
+ hash->ctx = ctx;
+ hash->key_size = header->key_size;
+ hash->encoding = header->encoding;
+ hash->value_size = header->value_size;
+ hash->entry_size = header->entry_size;
+ hash->n_garbages = &header->n_garbages;
+ hash->n_entries = &header->n_entries;
+ hash->max_offset = &header->max_offset;
+ hash->io = io;
+ hash->header.common = header;
+ hash->lock = &header->lock;
+ hash->tokenizer = grn_ctx_at(ctx, header->tokenizer);
+ if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
+ header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
+ hash->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ header->normalizer = grn_obj_id(ctx, hash->normalizer);
+ } else {
+ hash->normalizer = grn_ctx_at(ctx, header->normalizer);
+ }
+ GRN_PTR_INIT(&(hash->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ hash->obj.header.flags = header->flags;
+ return hash;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "invalid hash flag. (%x)", header->flags);
+ }
+ GRN_FREE(hash);
+ }
+ } else {
+ ERR(GRN_INVALID_FORMAT,
+ "[table][hash] file type must be %#04x: <%#04x>",
+ GRN_TABLE_HASH_KEY, io_type);
+ }
+ grn_io_close(ctx, io);
+ }
+ }
+ return NULL;
+}
+
+/*
+ * grn_hash_error_if_truncated() logs an error and returns its error code if
+ * a hash is truncated by another process.
+ * Otherwise, this function returns GRN_SUCCESS.
+ * Note that `ctx` and `hash` must be valid.
+ *
+ * FIXME: A hash should be reopened if possible.
+ */
+static grn_rc
+grn_hash_error_if_truncated(grn_ctx *ctx, grn_hash *hash)
+{
+ if (hash->header.common && hash->header.common->truncated) {
+ ERR(GRN_FILE_CORRUPT,
+ "hash is truncated, please unmap or reopen the database");
+ return GRN_FILE_CORRUPT;
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_tiny_hash_fin(grn_ctx *ctx, grn_hash *hash)
+{
+ if (!hash->index) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ GRN_OBJ_FIN(ctx, &(hash->token_filters));
+
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ uint32_t num_remaining_entries = *hash->n_entries;
+ grn_id *hash_ptr;
+ for (hash_ptr = hash->index; num_remaining_entries; hash_ptr++) {
+ const grn_id id = *hash_ptr;
+ if (id && id != GARBAGE) {
+ grn_tiny_hash_entry * const entry =
+ (grn_tiny_hash_entry *)grn_tiny_array_get(&hash->a, id);
+ GRN_ASSERT(entry);
+ num_remaining_entries--;
+ if (entry && !(entry->flag & HASH_IMMEDIATE)) {
+ GRN_CTX_FREE(ctx, entry->key.ptr);
+ }
+ }
+ }
+ }
+ grn_tiny_array_fin(&hash->a);
+ grn_tiny_bitmap_fin(&hash->bitmap);
+ GRN_CTX_FREE(ctx, hash->index);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_hash_close(grn_ctx *ctx, grn_hash *hash)
+{
+ grn_rc rc;
+ if (!ctx || !hash) { return GRN_INVALID_ARGUMENT; }
+ if (grn_hash_is_io_hash(hash)) {
+ rc = grn_io_close(ctx, hash->io);
+ GRN_OBJ_FIN(ctx, &(hash->token_filters));
+ } else {
+ GRN_ASSERT(ctx == hash->ctx);
+ rc = grn_tiny_hash_fin(ctx, hash);
+ }
+ GRN_FREE(hash);
+ return rc;
+}
+
+grn_rc
+grn_hash_remove(grn_ctx *ctx, const char *path)
+{
+ if (!ctx || !path) { return GRN_INVALID_ARGUMENT; }
+ return grn_io_remove(ctx, path);
+}
+
+grn_rc
+grn_hash_truncate(grn_ctx *ctx, grn_hash *hash)
+{
+ grn_rc rc;
+ char *path = NULL;
+ uint32_t key_size, value_size, flags;
+
+ if (!ctx || !hash) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ rc = grn_hash_error_if_truncated(ctx, hash);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ if (grn_hash_is_io_hash(hash)) {
+ const char * const io_path = grn_io_path(hash->io);
+ if (io_path && *io_path) {
+ path = GRN_STRDUP(io_path);
+ if (!path) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ }
+ key_size = hash->key_size;
+ value_size = hash->value_size;
+ flags = hash->obj.header.flags;
+
+ if (grn_hash_is_io_hash(hash)) {
+ if (path) {
+ /* Only an I/O hash with a valid path uses the `truncated` flag. */
+ hash->header.common->truncated = GRN_TRUE;
+ }
+ rc = grn_io_close(ctx, hash->io);
+ if (!rc) {
+ hash->io = NULL;
+ if (path) {
+ rc = grn_io_remove(ctx, path);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &(hash->token_filters));
+ }
+ if (!rc) {
+ rc = grn_hash_init(ctx, hash, path, key_size, value_size, flags);
+ }
+ if (path) {
+ GRN_FREE(path);
+ }
+ return rc;
+}
+
+inline static uint32_t
+grn_hash_calculate_hash_value(const void *ptr, uint32_t size)
+{
+ uint32_t i;
+ uint32_t hash_value = 0;
+ for (i = 0; i < size; i++) {
+ hash_value = (hash_value * 1021) + ((const uint8_t *)ptr)[i];
+ }
+ return hash_value;
+}
+
+inline static uint32_t
+grn_hash_calculate_step(uint32_t hash_value)
+{
+ return (hash_value >> 2) | 0x1010101;
+}
+
+static grn_rc
+grn_hash_reset(grn_ctx *ctx, grn_hash *hash, uint32_t expected_n_entries)
+{
+ grn_id *new_index = NULL;
+ uint32_t new_index_size = INITIAL_INDEX_SIZE;
+ grn_id *src_ptr = NULL, *dest_ptr = NULL;
+ uint32_t src_offset = 0, dest_offset = 0;
+ const uint32_t n_entries = *hash->n_entries;
+ const uint32_t max_offset = *hash->max_offset;
+
+ if (!expected_n_entries) {
+ expected_n_entries = n_entries * 2;
+ }
+ if (expected_n_entries > INT_MAX) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ while (new_index_size <= expected_n_entries) {
+ new_index_size *= 2;
+ }
+
+ if (grn_hash_is_io_hash(hash)) {
+ uint32_t i;
+ src_offset = hash->header.common->idx_offset;
+ dest_offset = MAX_INDEX_SIZE - src_offset;
+ for (i = 0; i < new_index_size; i += (IDX_MASK_IN_A_SEGMENT + 1)) {
+ /*
+ * The following grn_io_hash_idx_at() allocates memory for a new segment
+ * and returns a pointer to the new segment. It's actually bad manners
+ * but faster than calling grn_io_hash_idx_at() for each element.
+ */
+ dest_ptr = grn_io_hash_idx_at(ctx, hash, i + dest_offset);
+ if (!dest_ptr) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ memset(dest_ptr, 0, GRN_HASH_SEGMENT_SIZE);
+ }
+ } else {
+ GRN_ASSERT(ctx == hash->ctx);
+ new_index = GRN_CTX_ALLOC(ctx, new_index_size * sizeof(grn_id));
+ if (!new_index) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ src_ptr = hash->index;
+ }
+
+ {
+ uint32_t src_pos, count;
+ const uint32_t new_max_offset = new_index_size - 1;
+ for (count = 0, src_pos = 0; count < n_entries && src_pos <= max_offset;
+ src_pos++, src_ptr++) {
+ uint32_t i, step;
+ grn_id entry_id;
+ grn_hash_entry *entry;
+ if (grn_hash_is_io_hash(hash) && !(src_pos & IDX_MASK_IN_A_SEGMENT)) {
+ src_ptr = grn_io_hash_idx_at(ctx, hash, src_pos + src_offset);
+ if (!src_ptr) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ entry_id = *src_ptr;
+ if (!entry_id || (entry_id == GARBAGE)) {
+ continue;
+ }
+ entry = grn_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
+ if (!entry) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ step = grn_hash_calculate_step(entry->hash_value);
+ for (i = entry->hash_value; ; i += step) {
+ i &= new_max_offset;
+ if (grn_hash_is_io_hash(hash)) {
+ dest_ptr = grn_io_hash_idx_at(ctx, hash, i + dest_offset);
+ if (!dest_ptr) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ } else {
+ dest_ptr = new_index + i;
+ }
+ if (!*dest_ptr) {
+ break;
+ }
+ }
+ *dest_ptr = entry_id;
+ count++;
+ }
+ *hash->max_offset = new_max_offset;
+ *hash->n_garbages = 0;
+ }
+
+ if (grn_hash_is_io_hash(hash)) {
+ hash->header.common->idx_offset = dest_offset;
+ } else {
+ grn_id * const old_index = hash->index;
+ hash->index = new_index;
+ GRN_CTX_FREE(ctx, old_index);
+ }
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_hash_lock(grn_ctx *ctx, grn_hash *hash, int timeout)
+{
+ static int _ncalls = 0, _ncolls = 0;
+ uint32_t count;
+ _ncalls++;
+ for (count = 0;; count++) {
+ uint32_t lock;
+ GRN_ATOMIC_ADD_EX(hash->lock, 1, lock);
+ if (lock) {
+ GRN_ATOMIC_ADD_EX(hash->lock, -1, lock);
+ if (!timeout || (timeout > 0 && (uint32_t) timeout == count)) { break; }
+ if (!(++_ncolls % 1000000) && (_ncolls > _ncalls)) {
+ if (_ncolls < 0 || _ncalls < 0) {
+ _ncolls = 0; _ncalls = 0;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "hash(%p) collisions(%d/%d)", hash, _ncolls, _ncalls);
+ }
+ }
+ grn_nanosleep(GRN_LOCK_WAIT_TIME_NANOSECOND);
+ continue;
+ }
+ return GRN_SUCCESS;
+ }
+ ERR(GRN_RESOURCE_DEADLOCK_AVOIDED, "grn_hash_lock");
+ return ctx->rc;
+}
+
+grn_rc
+grn_hash_unlock(grn_ctx *ctx, grn_hash *hash)
+{
+ uint32_t lock;
+ GRN_ATOMIC_ADD_EX(hash->lock, -1, lock);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_hash_clear_lock(grn_ctx *ctx, grn_hash *hash)
+{
+ *hash->lock = 0;
+ return GRN_SUCCESS;
+}
+
+uint32_t
+grn_hash_size(grn_ctx *ctx, grn_hash *hash)
+{
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ return *hash->n_entries;
+}
+
+inline static grn_id
+grn_io_hash_add(grn_ctx *ctx, grn_hash *hash, uint32_t hash_value,
+ const void *key, unsigned int key_size, void **value)
+{
+ grn_id entry_id;
+ grn_hash_entry *entry;
+ grn_hash_header_common * const header = hash->header.common;
+ grn_id *garbages;
+
+ if (GRN_HASH_IS_LARGE_KEY(hash)) {
+ garbages = hash->header.large->garbages;
+ } else {
+ garbages = hash->header.normal->garbages;
+ }
+
+ entry_id = garbages[key_size - 1];
+ if (entry_id) {
+ entry = grn_io_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
+ if (!entry) {
+ return GRN_ID_NIL;
+ }
+ garbages[key_size - 1] = *(grn_id *)entry;
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ /* keep entry->io_entry's hash_value, flag, key_size and key. */
+ if (grn_hash_is_large_total_key_size(ctx, hash)) {
+ memset(entry->io_entry_large.value, 0, header->value_size);
+ } else {
+ memset(entry->io_entry_normal.value, 0, header->value_size);
+ }
+ } else {
+ memset(entry, 0, header->entry_size);
+ }
+ } else {
+ entry_id = header->curr_rec + 1;
+ entry = grn_hash_entry_at(ctx, hash, entry_id, GRN_TABLE_ADD);
+ if (!entry) {
+ return GRN_ID_NIL;
+ }
+ header->curr_rec = entry_id;
+ }
+
+ if (!grn_io_array_bit_on(ctx, hash->io, GRN_HASH_BITMAP_SEGMENT, entry_id)) {
+ /* TODO: error handling. */
+ }
+
+ if (grn_hash_entry_put_key(ctx, hash, entry, hash_value, key, key_size)) {
+ grn_hash_delete_by_id(ctx, hash, entry_id, NULL);
+ return GRN_ID_NIL;
+ }
+
+ if (value) {
+ *value = grn_hash_entry_get_value(ctx, hash, entry);
+ }
+ return entry_id;
+}
+
+inline static grn_id
+grn_tiny_hash_add(grn_ctx *ctx, grn_hash *hash, uint32_t hash_value,
+ const void *key, unsigned int key_size, void **value)
+{
+ grn_id entry_id;
+ grn_hash_entry *entry;
+ if (hash->garbages) {
+ entry_id = hash->garbages;
+ entry = (grn_hash_entry *)grn_tiny_array_get(&hash->a, entry_id);
+ hash->garbages = *(grn_id *)entry;
+ memset(entry, 0, hash->entry_size);
+ } else {
+ entry_id = hash->a.max + 1;
+ entry = (grn_hash_entry *)grn_tiny_array_put(&hash->a, entry_id);
+ if (!entry) {
+ return GRN_ID_NIL;
+ }
+ }
+
+ if (!grn_tiny_bitmap_put_and_set(&hash->bitmap, entry_id, 1)) {
+ /* TODO: error handling. */
+ }
+
+ if (grn_hash_entry_put_key(ctx, hash, entry, hash_value, key, key_size)) {
+ /* TODO: error handling. */
+ }
+
+ if (value) {
+ *value = grn_hash_entry_get_value(ctx, hash, entry);
+ }
+ return entry_id;
+}
+
+grn_id
+grn_hash_add(grn_ctx *ctx, grn_hash *hash, const void *key,
+ unsigned int key_size, void **value, int *added)
+{
+ uint32_t hash_value;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (!key || !key_size) {
+ return GRN_ID_NIL;
+ }
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (key_size > hash->key_size) {
+ ERR(GRN_INVALID_ARGUMENT, "too long key");
+ return GRN_ID_NIL;
+ }
+ hash_value = grn_hash_calculate_hash_value(key, key_size);
+ } else {
+ if (key_size != hash->key_size) {
+ ERR(GRN_INVALID_ARGUMENT, "key size unmatch");
+ return GRN_ID_NIL;
+ }
+ if (key_size == sizeof(uint32_t)) {
+ hash_value = *((uint32_t *)key);
+ } else {
+ hash_value = grn_hash_calculate_hash_value(key, key_size);
+ }
+ }
+
+ {
+ uint32_t i;
+ const uint32_t step = grn_hash_calculate_step(hash_value);
+ grn_id id, *index, *garbage_index = NULL;
+ grn_hash_entry *entry;
+
+ /* lock */
+ if ((*hash->n_entries + *hash->n_garbages) * 2 > *hash->max_offset) {
+ if (*hash->max_offset > (1 << 29)) {
+ ERR(GRN_TOO_LARGE_OFFSET, "hash table size limit");
+ return GRN_ID_NIL;
+ }
+ grn_hash_reset(ctx, hash, 0);
+ }
+
+ for (i = hash_value; ; i += step) {
+ index = grn_hash_idx_at(ctx, hash, i);
+ if (!index) {
+ return GRN_ID_NIL;
+ }
+ id = *index;
+ if (!id) {
+ break;
+ }
+ if (id == GARBAGE) {
+ if (!garbage_index) {
+ garbage_index = index;
+ }
+ continue;
+ }
+
+ entry = grn_hash_entry_at(ctx, hash, id, GRN_TABLE_ADD);
+ if (!entry) {
+ return GRN_ID_NIL;
+ }
+ if (grn_hash_entry_compare_key(ctx, hash, entry, hash_value,
+ key, key_size)) {
+ if (value) {
+ *value = grn_hash_entry_get_value(ctx, hash, entry);
+ }
+ if (added) {
+ *added = 0;
+ }
+ return id;
+ }
+ }
+
+ if (grn_hash_is_io_hash(hash)) {
+ id = grn_io_hash_add(ctx, hash, hash_value, key, key_size, value);
+ } else {
+ id = grn_tiny_hash_add(ctx, hash, hash_value, key, key_size, value);
+ }
+ if (!id) {
+ return GRN_ID_NIL;
+ }
+ if (garbage_index) {
+ (*hash->n_garbages)--;
+ index = garbage_index;
+ }
+ *index = id;
+ (*hash->n_entries)++;
+ /* unlock */
+
+ if (added) {
+ *added = 1;
+ }
+ return id;
+ }
+}
+
+grn_id
+grn_hash_get(grn_ctx *ctx, grn_hash *hash, const void *key,
+ unsigned int key_size, void **value)
+{
+ uint32_t hash_value;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (key_size > hash->key_size) {
+ return GRN_ID_NIL;
+ }
+ hash_value = grn_hash_calculate_hash_value(key, key_size);
+ } else {
+ if (key_size != hash->key_size) {
+ return GRN_ID_NIL;
+ }
+ if (key_size == sizeof(uint32_t)) {
+ hash_value = *((uint32_t *)key);
+ } else {
+ hash_value = grn_hash_calculate_hash_value(key, key_size);
+ }
+ }
+
+ {
+ uint32_t i;
+ const uint32_t step = grn_hash_calculate_step(hash_value);
+ for (i = hash_value; ; i += step) {
+ grn_id id;
+ grn_id * const index = grn_hash_idx_at(ctx, hash, i);
+ if (!index) {
+ return GRN_ID_NIL;
+ }
+ id = *index;
+ if (!id) {
+ return GRN_ID_NIL;
+ }
+ if (id != GARBAGE) {
+ grn_hash_entry * const entry = grn_hash_entry_at(ctx, hash, id, 0);
+ if (entry) {
+ if (grn_hash_entry_compare_key(ctx, hash, entry, hash_value,
+ key, key_size)) {
+ if (value) {
+ *value = grn_hash_entry_get_value(ctx, hash, entry);
+ }
+ return id;
+ }
+ }
+ }
+ }
+ }
+}
+
+inline static grn_hash_entry *
+grn_hash_get_entry(grn_ctx *ctx, grn_hash *hash, grn_id id)
+{
+ if (!grn_hash_bitmap_at(ctx, hash, id)) {
+ return NULL;
+ }
+ return grn_hash_entry_at(ctx, hash, id, 0);
+}
+
+const char *
+_grn_hash_key(grn_ctx *ctx, grn_hash *hash, grn_id id, uint32_t *key_size)
+{
+ grn_hash_entry * const entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ *key_size = 0;
+ return NULL;
+ }
+ *key_size = grn_hash_entry_get_key_size(hash, entry);
+ return grn_hash_entry_get_key(ctx, hash, entry);
+}
+
+int
+grn_hash_get_key(grn_ctx *ctx, grn_hash *hash, grn_id id, void *keybuf, int bufsize)
+{
+ int key_size;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return 0;
+ }
+ key_size = grn_hash_entry_get_key_size(hash, entry);
+ if (bufsize >= key_size) {
+ grn_memcpy(keybuf, grn_hash_entry_get_key(ctx, hash, entry), key_size);
+ }
+ return key_size;
+}
+
+int
+grn_hash_get_key2(grn_ctx *ctx, grn_hash *hash, grn_id id, grn_obj *bulk)
+{
+ int key_size;
+ char *key;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return 0;
+ }
+ key_size = grn_hash_entry_get_key_size(hash, entry);
+ key = grn_hash_entry_get_key(ctx, hash, entry);
+ if (bulk->header.impl_flags & GRN_OBJ_REFER) {
+ bulk->u.b.head = key;
+ bulk->u.b.curr = key + key_size;
+ } else {
+ grn_bulk_write(ctx, bulk, key, key_size);
+ }
+ return key_size;
+}
+
+int
+grn_hash_get_value(grn_ctx *ctx, grn_hash *hash, grn_id id, void *valuebuf)
+{
+ void *value;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return 0;
+ }
+ value = grn_hash_entry_get_value(ctx, hash, entry);
+ if (!value) {
+ return 0;
+ }
+ if (valuebuf) {
+ grn_memcpy(valuebuf, value, hash->value_size);
+ }
+ return hash->value_size;
+}
+
+const char *
+grn_hash_get_value_(grn_ctx *ctx, grn_hash *hash, grn_id id, uint32_t *size)
+{
+ const void *value;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return NULL;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return NULL;
+ }
+ value = grn_hash_entry_get_value(ctx, hash, entry);
+ if (!value) {
+ return NULL;
+ }
+ if (size) {
+ *size = hash->value_size;
+ }
+ return (const char *)value;
+}
+
+int
+grn_hash_get_key_value(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ void *keybuf, int bufsize, void *valuebuf)
+{
+ void *value;
+ int key_size;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return 0;
+ }
+ key_size = grn_hash_entry_get_key_size(hash, entry);
+ if (bufsize >= key_size) {
+ grn_memcpy(keybuf, grn_hash_entry_get_key(ctx, hash, entry), key_size);
+ }
+ value = grn_hash_entry_get_value(ctx, hash, entry);
+ if (!value) {
+ return 0;
+ }
+ if (valuebuf) {
+ grn_memcpy(valuebuf, value, hash->value_size);
+ }
+ return key_size;
+}
+
+int
+_grn_hash_get_key_value(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ void **key, void **value)
+{
+ int key_size;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return 0;
+ }
+ key_size = grn_hash_entry_get_key_size(hash, entry);
+ *key = grn_hash_entry_get_key(ctx, hash, entry);
+ *value = grn_hash_entry_get_value(ctx, hash, entry);
+ return *value ? key_size : 0;
+}
+
+grn_rc
+grn_hash_set_value(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ const void *value, int flags)
+{
+ void *entry_value;
+ grn_hash_entry *entry;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (!value) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ entry = grn_hash_get_entry(ctx, hash, id);
+ if (!entry) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ entry_value = grn_hash_entry_get_value(ctx, hash, entry);
+ if (!entry_value) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+
+ switch (flags & GRN_OBJ_SET_MASK) {
+ case GRN_OBJ_SET :
+ grn_memcpy(entry_value, value, hash->value_size);
+ return GRN_SUCCESS;
+ case GRN_OBJ_INCR :
+ switch (hash->value_size) {
+ case sizeof(int32_t) :
+ *((int32_t *)entry_value) += *((int32_t *)value);
+ return GRN_SUCCESS;
+ case sizeof(int64_t) :
+ *((int64_t *)entry_value) += *((int64_t *)value);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ break;
+ case GRN_OBJ_DECR :
+ switch (hash->value_size) {
+ case sizeof(int32_t) :
+ *((int32_t *)entry_value) -= *((int32_t *)value);
+ return GRN_SUCCESS;
+ case sizeof(int64_t) :
+ *((int64_t *)entry_value) -= *((int64_t *)value);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "flags = %d", flags);
+ return ctx->rc;
+ }
+}
+
+#define DELETE_IT do {\
+ *ep = GARBAGE;\
+ if (grn_hash_is_io_hash(hash)) {\
+ uint32_t size = key_size - 1;\
+ grn_id *garbages;\
+ if (GRN_HASH_IS_LARGE_KEY(hash)) {\
+ garbages = hash->header.large->garbages;\
+ } else {\
+ garbages = hash->header.normal->garbages;\
+ }\
+ ee->key = garbages[size];\
+ garbages[size] = e;\
+ grn_io_array_bit_off(ctx, hash->io, GRN_HASH_BITMAP_SEGMENT, e);\
+ } else {\
+ ee->key = hash->garbages;\
+ hash->garbages = e;\
+ if ((hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) && !(ee->flag & HASH_IMMEDIATE)) {\
+ grn_ctx *ctx = hash->ctx;\
+ GRN_CTX_FREE(ctx, ((entry_astr *)ee)->str);\
+ }\
+ grn_tiny_bitmap_get_and_set(&hash->bitmap, e, 0);\
+ }\
+ (*hash->n_entries)--;\
+ (*hash->n_garbages)++;\
+ rc = GRN_SUCCESS;\
+} while (0)
+
+grn_rc
+grn_hash_delete_by_id(grn_ctx *ctx, grn_hash *hash, grn_id id,
+ grn_table_delete_optarg *optarg)
+{
+ entry_str *ee;
+ grn_rc rc;
+ if (!hash || !id) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_hash_error_if_truncated(ctx, hash);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = GRN_INVALID_ARGUMENT;
+ /* lock */
+ ee = grn_hash_entry_at(ctx, hash, id, 0);
+ if (ee) {
+ grn_id e, *ep;
+ uint32_t i, key_size, h = ee->key, s = grn_hash_calculate_step(h);
+ key_size = (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) ? ee->size : hash->key_size;
+ for (i = h; ; i += s) {
+ if (!(ep = grn_hash_idx_at(ctx, hash, i))) { return GRN_NO_MEMORY_AVAILABLE; }
+ if (!(e = *ep)) { break; }
+ if (e == id) {
+ DELETE_IT;
+ break;
+ }
+ }
+ }
+ /* unlock */
+ return rc;
+}
+
+grn_rc
+grn_hash_delete(grn_ctx *ctx, grn_hash *hash, const void *key, uint32_t key_size,
+ grn_table_delete_optarg *optarg)
+{
+ uint32_t h, i, m, s;
+ grn_rc rc = grn_hash_error_if_truncated(ctx, hash);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = GRN_INVALID_ARGUMENT;
+ if (hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ if (key_size > hash->key_size) { return GRN_INVALID_ARGUMENT; }
+ h = grn_hash_calculate_hash_value(key, key_size);
+ } else {
+ if (key_size != hash->key_size) { return GRN_INVALID_ARGUMENT; }
+ if (key_size == sizeof(uint32_t)) {
+ h = *((uint32_t *)key);
+ } else {
+ h = grn_hash_calculate_hash_value(key, key_size);
+ }
+ }
+ s = grn_hash_calculate_step(h);
+ {
+ grn_id e, *ep;
+ /* lock */
+ m = *hash->max_offset;
+ for (i = h; ; i += s) {
+ if (!(ep = grn_hash_idx_at(ctx, hash, i))) { return GRN_NO_MEMORY_AVAILABLE; }
+ if (!(e = *ep)) { break; }
+ if (e == GARBAGE) { continue; }
+ {
+ entry_str * const ee = grn_hash_entry_at(ctx, hash, e, 0);
+ if (ee && match_key(ctx, hash, ee, h, key, key_size)) {
+ DELETE_IT;
+ break;
+ }
+ }
+ }
+ /* unlock */
+ return rc;
+ }
+}
+
+/* only valid for hash tables, GRN_OBJ_KEY_VAR_SIZE && GRN_HASH_TINY */
+const char *
+_grn_hash_strkey_by_val(void *v, uint16_t *size)
+{
+ entry_astr *n = (entry_astr *)((uintptr_t)v -
+ (uintptr_t)&((entry_astr *)0)->dummy);
+ *size = n->size;
+ return (n->flag & HASH_IMMEDIATE) ? (char *)&n->str : n->str;
+}
+
+void
+grn_hash_cursor_close(grn_ctx *ctx, grn_hash_cursor *c)
+{
+ GRN_ASSERT(c->ctx == ctx);
+ GRN_FREE(c);
+}
+
+#define HASH_CURR_MAX(hash) \
+ ((grn_hash_is_io_hash(hash)) ? (hash)->header.common->curr_rec : (hash)->a.max)
+
+grn_hash_cursor *
+grn_hash_cursor_open(grn_ctx *ctx, grn_hash *hash,
+ const void *min, uint32_t min_size,
+ const void *max, uint32_t max_size,
+ int offset, int limit, int flags)
+{
+ grn_hash_cursor *c;
+ if (!hash || !ctx) { return NULL; }
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return NULL;
+ }
+ if (!(c = GRN_MALLOCN(grn_hash_cursor, 1))) { return NULL; }
+ GRN_DB_OBJ_SET_TYPE(c, GRN_CURSOR_TABLE_HASH_KEY);
+ c->hash = hash;
+ c->ctx = ctx;
+ c->obj.header.flags = flags;
+ c->obj.header.domain = GRN_ID_NIL;
+ if (flags & GRN_CURSOR_DESCENDING) {
+ c->dir = -1;
+ if (max) {
+ if (!(c->curr_rec = grn_hash_get(ctx, hash, max, max_size, NULL))) {
+ c->tail = GRN_ID_NIL;
+ goto exit;
+ }
+ if (!(flags & GRN_CURSOR_LT)) { c->curr_rec++; }
+ } else {
+ c->curr_rec = HASH_CURR_MAX(hash) + 1;
+ }
+ if (min) {
+ if (!(c->tail = grn_hash_get(ctx, hash, min, min_size, NULL))) {
+ c->curr_rec = GRN_ID_NIL;
+ goto exit;
+ }
+ if ((flags & GRN_CURSOR_GT)) { c->tail++; }
+ } else {
+ c->tail = GRN_ID_NIL + 1;
+ }
+ if (c->curr_rec < c->tail) { c->tail = c->curr_rec; }
+ } else {
+ c->dir = 1;
+ if (min) {
+ if (!(c->curr_rec = grn_hash_get(ctx, hash, min, min_size, NULL))) {
+ c->tail = GRN_ID_NIL;
+ goto exit;
+ }
+ if (!(flags & GRN_CURSOR_GT)) { c->curr_rec--; }
+ } else {
+ c->curr_rec = GRN_ID_NIL;
+ }
+ if (max) {
+ if (!(c->tail = grn_hash_get(ctx, hash, max, max_size, NULL))) {
+ c->curr_rec = GRN_ID_NIL;
+ goto exit;
+ }
+ if ((flags & GRN_CURSOR_LT)) { c->tail--; }
+ } else {
+ c->tail = HASH_CURR_MAX(hash);
+ }
+ if (c->tail < c->curr_rec) { c->tail = c->curr_rec; }
+ }
+ if (*hash->n_entries != HASH_CURR_MAX(hash)) {
+ while (offset && c->curr_rec != c->tail) {
+ c->curr_rec += c->dir;
+ if (grn_hash_bitmap_at(ctx, c->hash, c->curr_rec)) { offset--; }
+ }
+ } else {
+ c->curr_rec += c->dir * offset;
+ }
+exit :
+ c->rest = (limit < 0) ? GRN_ARRAY_MAX : limit;
+ return c;
+}
+
+grn_id
+grn_hash_cursor_next(grn_ctx *ctx, grn_hash_cursor *c)
+{
+ if (c && c->rest) {
+ while (c->curr_rec != c->tail) {
+ c->curr_rec += c->dir;
+ if (*c->hash->n_entries != HASH_CURR_MAX(c->hash)) {
+ if (!grn_hash_bitmap_at(ctx, c->hash, c->curr_rec)) { continue; }
+ }
+ c->rest--;
+ return c->curr_rec;
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_hash_next(grn_ctx *ctx, grn_hash *hash, grn_id id)
+{
+ grn_id max = HASH_CURR_MAX(hash);
+ while (++id <= max) {
+ if (grn_hash_bitmap_at(ctx, hash, id)) { return id; }
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_hash_at(grn_ctx *ctx, grn_hash *hash, grn_id id)
+{
+ return grn_hash_bitmap_at(ctx, hash, id) ? id : GRN_ID_NIL;
+}
+
+int
+grn_hash_cursor_get_key(grn_ctx *ctx, grn_hash_cursor *c, void **key)
+{
+ int key_size;
+ entry_str *ee;
+ if (!c) { return 0; }
+ ee = grn_hash_entry_at(ctx, c->hash, c->curr_rec, 0);
+ if (!ee) { return 0; }
+ key_size = (c->hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) ? ee->size : c->hash->key_size;
+ *key = get_key(ctx, c->hash, ee);
+ return key_size;
+}
+
+int
+grn_hash_cursor_get_value(grn_ctx *ctx, grn_hash_cursor *c, void **value)
+{
+ void *v;
+ entry_str *ee;
+ if (!c) { return 0; }
+ ee = grn_hash_entry_at(ctx, c->hash, c->curr_rec, 0);
+ if (ee && (v = get_value(ctx, c->hash, ee))) {
+ *value = v;
+ return c->hash->value_size;
+ }
+ return 0;
+}
+
+int
+grn_hash_cursor_get_key_value(grn_ctx *ctx, grn_hash_cursor *c,
+ void **key, uint32_t *key_size, void **value)
+{
+ entry_str *ee;
+ if (!c) { return GRN_INVALID_ARGUMENT; }
+ ee = grn_hash_entry_at(ctx, c->hash, c->curr_rec, 0);
+ if (!ee) { return GRN_INVALID_ARGUMENT; }
+ if (key_size) {
+ *key_size = (c->hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) ? ee->size : c->hash->key_size;
+ }
+ if (key) { *key = get_key(ctx, c->hash, ee); }
+ if (value) { *value = get_value(ctx, c->hash, ee); }
+ return c->hash->value_size;
+}
+
+grn_rc
+grn_hash_cursor_set_value(grn_ctx *ctx, grn_hash_cursor *c,
+ const void *value, int flags)
+{
+ if (!c) { return GRN_INVALID_ARGUMENT; }
+ return grn_hash_set_value(ctx, c->hash, c->curr_rec, value, flags);
+}
+
+grn_rc
+grn_hash_cursor_delete(grn_ctx *ctx, grn_hash_cursor *c,
+ grn_table_delete_optarg *optarg)
+{
+ if (!c) { return GRN_INVALID_ARGUMENT; }
+ return grn_hash_delete_by_id(ctx, c->hash, c->curr_rec, optarg);
+}
+
+/* sort */
+
+#define PREPARE_VAL(e,ep,es) do {\
+ if ((arg->flags & GRN_TABLE_SORT_BY_VALUE)) {\
+ ep = ((const uint8_t *)(get_value(ctx, hash, (entry_str *)(e))));\
+ es = hash->value_size;\
+ } else {\
+ ep = ((const uint8_t *)(get_key(ctx, hash, (entry_str *)(e))));\
+ es = ((hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)\
+ ? ((entry_str *)(e))->size : hash->key_size); \
+ }\
+ ep += arg->offset;\
+ es -= arg->offset;\
+} while (0)
+
+#define COMPARE_VAL_(ap,as,bp,bs)\
+ (arg->compar\
+ ? arg->compar(ctx,\
+ (grn_obj *)hash, (void *)(ap), as,\
+ (grn_obj *)hash, (void *)(bp), bs, arg->compar_arg)\
+ : ((arg->flags & GRN_TABLE_SORT_AS_NUMBER)\
+ ? ((arg->flags & GRN_TABLE_SORT_AS_UNSIGNED)\
+ ? ((arg->flags & GRN_TABLE_SORT_AS_INT64)\
+ ? *((uint64_t *)(ap)) > *((uint64_t *)(bp))\
+ : *((uint32_t *)(ap)) > *((uint32_t *)(bp)))\
+ : ((arg->flags & GRN_TABLE_SORT_AS_INT64)\
+ ? *((int64_t *)(ap)) > *((int64_t *)(bp))\
+ : *((int32_t *)(ap)) > *((int32_t *)(bp))))\
+ : grn_str_greater(ap, as, bp, bs)))
+
+#define COMPARE_VAL(ap,as,bp,bs)\
+ ((dir) ? COMPARE_VAL_((bp),(bs),(ap),(as)) : COMPARE_VAL_((ap),(as),(bp),(bs)))
+
+inline static entry **
+pack(grn_ctx *ctx, grn_hash *hash, entry **res, grn_table_sort_optarg *arg, int dir)
+{
+ uint32_t n;
+ uint32_t cs, es;
+ const uint8_t *cp, *ep;
+ entry **head, **tail, *e, *c;
+ grn_id id, m = HASH_CURR_MAX(hash);
+ for (id = m >> 1;;id = (id == m) ? 1 : id + 1) {
+ if (grn_hash_bitmap_at(ctx, hash, id)) { break; }
+ }
+ c = grn_hash_entry_at(ctx, hash, id, 0);
+ if (!c) { return NULL; }
+ PREPARE_VAL(c, cp, cs);
+ head = res;
+ n = *hash->n_entries - 1;
+ tail = res + n;
+ while (n--) {
+ do {
+ id = (id == m) ? 1 : id + 1;
+ } while (!grn_hash_bitmap_at(ctx, hash, id));
+ e = grn_hash_entry_at(ctx, hash, id, 0);
+ if (!e) { return NULL; }
+ PREPARE_VAL(e, ep, es);
+ if (COMPARE_VAL(cp, cs, ep, es)) {
+ *head++ = e;
+ } else {
+ *tail-- = e;
+ }
+ }
+ *head = c;
+ return *hash->n_entries > 2 ? head : NULL;
+}
+
+inline static void
+swap(entry **a, entry **b)
+{
+ entry *c_ = *a;
+ *a = *b;
+ *b = c_;
+}
+
+#define SWAP(a,ap,as,b,bp,bs) do {\
+ const uint8_t *cp_ = ap;\
+ uint32_t cs_ = as;\
+ ap = bp; bp = cp_;\
+ as = bs; bs = cs_;\
+ swap(a,b);\
+} while (0)
+
+inline static entry **
+part(grn_ctx *ctx, entry **b, entry **e, grn_table_sort_optarg *arg, grn_hash *hash, int dir)
+{
+ entry **c;
+ const uint8_t *bp, *cp, *ep;
+ uint32_t bs, cs, es;
+ intptr_t d = e - b;
+ PREPARE_VAL(*b, bp, bs);
+ PREPARE_VAL(*e, ep, es);
+ if (COMPARE_VAL(bp, bs, ep, es)) {
+ SWAP(b, bp, bs, e, ep, es);
+ }
+ if (d < 2) { return NULL; }
+ c = b + (d >> 1);
+ PREPARE_VAL(*c, cp, cs);
+ if (COMPARE_VAL(bp, bs, cp, cs)) {
+ SWAP(b, bp, bs, c, cp, cs);
+ } else {
+ if (COMPARE_VAL(cp, cs, ep, es)) {
+ SWAP(c, cp, cs, e, ep, es);
+ }
+ }
+ if (d < 3) { return NULL; }
+ b++;
+ swap(b, c);
+ c = b;
+ PREPARE_VAL(*c, cp, cs);
+ for (;;) {
+ do {
+ b++;
+ PREPARE_VAL(*b, bp, bs);
+ } while (COMPARE_VAL(cp, cs, bp, bs));
+ do {
+ e--;
+ PREPARE_VAL(*e, ep, es);
+ } while (COMPARE_VAL(ep, es, cp, cs));
+ if (b >= e) { break; }
+ SWAP(b, bp, bs, e, ep, es);
+ }
+ SWAP(c, cp, cs, e, ep, es);
+ return e;
+}
+
+static void
+_sort(grn_ctx *ctx, entry **head, entry **tail, int limit,
+ grn_table_sort_optarg *arg, grn_hash *hash, int dir)
+{
+ entry **c;
+ if (head < tail && (c = part(ctx, head, tail, arg, hash, dir))) {
+ intptr_t rest = limit - 1 - (c - head);
+ _sort(ctx, head, c - 1, limit, arg, hash, dir);
+ if (rest > 0) { _sort(ctx, c + 1, tail, (int)rest, arg, hash, dir); }
+ }
+}
+
+static void
+sort(grn_ctx *ctx,
+ grn_hash *hash, entry **res, int limit, grn_table_sort_optarg *arg, int dir)
+{
+ entry **c = pack(ctx, hash, res, arg, dir);
+ if (c) {
+ intptr_t rest = limit - 1 - (c - res);
+ _sort(ctx, res, c - 1, limit, arg, hash, dir);
+ if (rest > 0 ) {
+ _sort(ctx, c + 1, res + *hash->n_entries - 1, (int)rest, arg, hash, dir);
+ }
+ }
+}
+
+typedef struct {
+ grn_id id;
+ int32_t v;
+} val32;
+
+#define PREPARE_VAL32(id,e,ep) do {\
+ (ep)->id = id;\
+ (ep)->v = (arg->flags & GRN_TABLE_SORT_BY_ID)\
+ ? (int32_t) id\
+ : (*((int32_t *)((byte *)((arg->flags & GRN_TABLE_SORT_BY_VALUE)\
+ ? get_value(ctx, hash, (e))\
+ : get_key(ctx, hash, (e))) + arg->offset)));\
+} while (0)
+
+#define COMPARE_VAL32_(ap,bp) \
+ (arg->compar\
+ ? arg->compar(ctx,\
+ (grn_obj *)hash, (void *)&(ap)->v, sizeof(uint32_t),\
+ (grn_obj *)hash, (void *)&(bp)->v, sizeof(uint32_t),\
+ arg->compar_arg)\
+ : ((arg->flags & GRN_TABLE_SORT_AS_NUMBER)\
+ ? ((arg->flags & GRN_TABLE_SORT_AS_UNSIGNED)\
+ ? *((uint32_t *)&(ap)->v) > *((uint32_t *)&(bp)->v)\
+ : *((int32_t *)&(ap)->v) > *((int32_t *)&(bp)->v))\
+ : memcmp(&(ap)->v, &(bp)->v, sizeof(uint32_t)) > 0))
+
+#define COMPARE_VAL32(ap,bp)\
+ ((dir) ? COMPARE_VAL32_((bp),(ap)) : COMPARE_VAL32_((ap),(bp)))
+
+inline static val32 *
+pack_val32(grn_ctx *ctx, grn_hash *hash, val32 *res, grn_table_sort_optarg *arg, int dir)
+{
+ uint32_t n;
+ entry_str *e, *c;
+ val32 *head, *tail, cr, er;
+ grn_id id, m = HASH_CURR_MAX(hash);
+ for (id = m >> 1;;id = (id == m) ? 1 : id + 1) {
+ if (grn_hash_bitmap_at(ctx, hash, id)) { break; }
+ }
+ c = grn_hash_entry_at(ctx, hash, id, 0);
+ if (!c) { return NULL; }
+ PREPARE_VAL32(id, c, &cr);
+ head = res;
+ n = *hash->n_entries - 1;
+ tail = res + n;
+ while (n--) {
+ do {
+ id = (id == m) ? 1 : id + 1;
+ } while (!grn_hash_bitmap_at(ctx, hash, id));
+ e = grn_hash_entry_at(ctx, hash, id, 0);
+ if (!e) { return NULL; }
+ PREPARE_VAL32(id, e, &er);
+ if (COMPARE_VAL32(&cr, &er)) {
+ *head++ = er;
+ } else {
+ *tail-- = er;
+ }
+ }
+ *head = cr;
+ return *hash->n_entries > 2 ? head : NULL;
+}
+
+#define SWAP_VAL32(ap,bp) do {\
+ val32 cr_ = *ap;\
+ *ap = *bp;\
+ *bp = cr_;\
+} while (0)
+
+inline static val32 *
+part_val32(grn_ctx *ctx,
+ val32 *b, val32 *e, grn_table_sort_optarg *arg, grn_hash *hash, int dir)
+{
+ val32 *c;
+ intptr_t d = e - b;
+ if (COMPARE_VAL32(b, e)) { SWAP_VAL32(b, e); }
+ if (d < 2) { return NULL; }
+ c = b + (d >> 1);
+ if (COMPARE_VAL32(b, c)) {
+ SWAP_VAL32(b, c);
+ } else {
+ if (COMPARE_VAL32(c, e)) { SWAP_VAL32(c, e); }
+ }
+ if (d < 3) { return NULL; }
+ b++;
+ SWAP_VAL32(b, c);
+ c = b;
+ for (;;) {
+ do { b++; } while (COMPARE_VAL32(c, b));
+ do { e--; } while (COMPARE_VAL32(e, c));
+ if (b >= e) { break; }
+ SWAP_VAL32(b, e);
+ }
+ SWAP_VAL32(c, e);
+ return e;
+}
+
+static void
+_sort_val32(grn_ctx *ctx, val32 *head, val32 *tail, int limit,
+ grn_table_sort_optarg *arg, grn_hash *hash, int dir)
+{
+ val32 *c;
+ if (head < tail && (c = part_val32(ctx, head, tail, arg, hash, dir))) {
+ intptr_t rest = limit - 1 - (c - head);
+ _sort_val32(ctx, head, c - 1, limit, arg, hash, dir);
+ if (rest > 0) { _sort_val32(ctx, c + 1, tail, (int)rest, arg, hash, dir); }
+ }
+}
+
+static void
+sort_val32(grn_ctx *ctx,
+ grn_hash *hash, val32 *res, int limit, grn_table_sort_optarg *arg, int dir)
+{
+ val32 *c = pack_val32(ctx, hash, res, arg, dir);
+ if (c) {
+ intptr_t rest = limit - 1 - (c - res);
+ _sort_val32(ctx, res, c - 1, limit, arg, hash, dir);
+ if (rest > 0 ) {
+ _sort_val32(ctx, c + 1, res + *hash->n_entries - 1, (int)rest, arg, hash, dir);
+ }
+ }
+}
+
+inline static grn_id
+entry2id(grn_ctx *ctx, grn_hash *hash, entry *e)
+{
+ entry *e2;
+ grn_id id, *ep;
+ uint32_t i, h = e->key, s = grn_hash_calculate_step(h);
+ for (i = h; ; i += s) {
+ if (!(ep = grn_hash_idx_at(ctx, hash, i))) { return GRN_ID_NIL; }
+ if (!(id = *ep)) { break; }
+ if (id != GARBAGE) {
+ e2 = grn_hash_entry_at(ctx, hash, id, 0);
+ if (!e2) { return GRN_ID_NIL; }
+ if (e2 == e) { break; }
+ }
+ }
+ return id;
+}
+
+int
+grn_hash_sort(grn_ctx *ctx, grn_hash *hash,
+ int limit, grn_array *result, grn_table_sort_optarg *optarg)
+{
+ entry **res;
+ if (!result || !*hash->n_entries) { return 0; }
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return 0;
+ }
+ if (!(res = GRN_MALLOC(sizeof(entry *) * *hash->n_entries))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "allocation of entries failed on grn_hash_sort !");
+ return 0;
+ }
+ if (limit < 0) {
+ limit += *hash->n_entries + 1;
+ if (limit < 0) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "limit is too small in grn_hash_sort !");
+ return 0;
+ }
+ }
+ if ((uint) limit > (uint) *hash->n_entries) { limit = *hash->n_entries; }
+ /* hash->limit = limit; */
+ if (optarg) {
+ int dir = (optarg->flags & GRN_TABLE_SORT_DESC);
+ if ((optarg->flags & GRN_TABLE_SORT_BY_ID) ||
+ (optarg->flags & GRN_TABLE_SORT_BY_VALUE)
+ ? ((hash->value_size - optarg->offset) == sizeof(uint32_t))
+ : (!(hash->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)
+ && hash->key_size == sizeof(uint32_t))) {
+ if (sizeof(entry *) != sizeof(val32)) {
+ GRN_FREE(res);
+ if (!(res = GRN_MALLOC(sizeof(val32) * *hash->n_entries))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "allocation of entries failed on grn_hash_sort !");
+ return 0;
+ }
+ }
+ sort_val32(ctx, hash, (val32 *)res, limit, optarg, dir);
+ {
+ int i;
+ grn_id *v;
+ val32 *rp = (val32 *)res;
+ for (i = 0; i < limit; i++, rp++) {
+ if (!grn_array_add(ctx, result, (void **)&v)) { break; }
+ if (!(*v = rp->id)) { break; }
+ }
+ GRN_FREE(res);
+ return i;
+ }
+ } else {
+ sort(ctx, hash, res, limit, optarg, dir);
+ }
+ } else {
+ grn_table_sort_optarg opt = {0, NULL, NULL, NULL, 0};
+ sort(ctx, hash, res, limit, &opt, 0);
+ }
+ {
+ int i;
+ grn_id *v;
+ entry **rp = res;
+ for (i = 0; i < limit; i++, rp++) {
+ if (!grn_array_add(ctx, result, (void **)&v)) { break; }
+ if (!(*v = entry2id(ctx, hash, *rp))) { break; }
+ }
+ GRN_FREE(res);
+ return i;
+ }
+}
+
+void
+grn_hash_check(grn_ctx *ctx, grn_hash *hash)
+{
+ char buf[8];
+ grn_hash_header_common *h = hash->header.common;
+ if (grn_hash_error_if_truncated(ctx, hash) != GRN_SUCCESS) {
+ return;
+ }
+ GRN_OUTPUT_ARRAY_OPEN("RESULT", 1);
+ GRN_OUTPUT_MAP_OPEN("SUMMARY", 26);
+ GRN_OUTPUT_CSTR("flags");
+ grn_itoh(h->flags, buf, 8);
+ GRN_OUTPUT_STR(buf, 8);
+ GRN_OUTPUT_CSTR("key_size");
+ GRN_OUTPUT_INT64(hash->key_size);
+ GRN_OUTPUT_CSTR("value_size");
+ GRN_OUTPUT_INT64(hash->value_size);
+ GRN_OUTPUT_CSTR("tokenizer");
+ GRN_OUTPUT_INT64(h->tokenizer);
+ GRN_OUTPUT_CSTR("normalizer");
+ GRN_OUTPUT_INT64(h->normalizer);
+ GRN_OUTPUT_CSTR("curr_rec");
+ GRN_OUTPUT_INT64(h->curr_rec);
+ GRN_OUTPUT_CSTR("curr_key_normal");
+ GRN_OUTPUT_UINT64(h->curr_key_normal);
+ GRN_OUTPUT_CSTR("curr_key_large");
+ GRN_OUTPUT_UINT64(h->curr_key_large);
+ GRN_OUTPUT_CSTR("idx_offset");
+ GRN_OUTPUT_INT64(h->idx_offset);
+ GRN_OUTPUT_CSTR("entry_size");
+ GRN_OUTPUT_INT64(hash->entry_size);
+ GRN_OUTPUT_CSTR("max_offset");
+ GRN_OUTPUT_INT64(*hash->max_offset);
+ GRN_OUTPUT_CSTR("n_entries");
+ GRN_OUTPUT_INT64(*hash->n_entries);
+ GRN_OUTPUT_CSTR("n_garbages");
+ GRN_OUTPUT_INT64(*hash->n_garbages);
+ GRN_OUTPUT_CSTR("lock");
+ GRN_OUTPUT_INT64(h->lock);
+ GRN_OUTPUT_MAP_CLOSE();
+ GRN_OUTPUT_ARRAY_CLOSE();
+}
+
+/* rhash : grn_hash with subrecs */
+
+#ifdef USE_GRN_INDEX2
+
+static uint32_t default_flags = GRN_HASH_TINY;
+
+grn_rc
+grn_rhash_init(grn_ctx *ctx, grn_hash *hash, grn_rec_unit record_unit, int record_size,
+ grn_rec_unit subrec_unit, int subrec_size, unsigned int max_n_subrecs)
+{
+ grn_rc rc;
+ record_size = grn_rec_unit_size(record_unit, record_size);
+ subrec_size = grn_rec_unit_size(subrec_unit, subrec_size);
+ if (record_unit != grn_rec_userdef && subrec_unit != grn_rec_userdef) {
+ subrec_size -= record_size;
+ }
+ if (!hash) { return GRN_INVALID_ARGUMENT; }
+ if (record_size < 0) { return GRN_INVALID_ARGUMENT; }
+ if ((default_flags & GRN_HASH_TINY)) {
+ rc = grn_tiny_hash_init(ctx, hash, NULL, record_size,
+ max_n_subrecs * (GRN_RSET_SCORE_SIZE + subrec_size),
+ default_flags, GRN_ENC_NONE);
+ } else {
+ rc = grn_io_hash_init(ctx, hash, NULL, record_size,
+ max_n_subrecs * (GRN_RSET_SCORE_SIZE + subrec_size),
+ default_flags, GRN_ENC_NONE, 0);
+ }
+ if (rc) { return rc; }
+ hash->record_unit = record_unit;
+ hash->subrec_unit = subrec_unit;
+ hash->subrec_size = subrec_size;
+ hash->max_n_subrecs = max_n_subrecs;
+ return rc;
+}
+
+grn_rc
+grn_rhash_fin(grn_ctx *ctx, grn_hash *hash)
+{
+ grn_rc rc;
+ if (grn_hash_is_io_hash(hash)) {
+ rc = grn_io_close(ctx, hash->io);
+ } else {
+ GRN_ASSERT(ctx == hash->ctx);
+ rc = grn_tiny_hash_fin(ctx, hash);
+ }
+ return rc;
+}
+
+inline static void
+subrecs_push(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
+{
+ byte *v;
+ int *c2;
+ int n = n_subrecs - 1, n2;
+ while (n) {
+ n2 = (n - 1) >> 1;
+ c2 = GRN_RSET_SUBRECS_NTH(subrecs,size,n2);
+ if (GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) { break; }
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
+ n = n2;
+ }
+ v = subrecs + n * (size + GRN_RSET_SCORE_SIZE);
+ *((int *)v) = score;
+ grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
+}
+
+inline static void
+subrecs_replace_min(byte *subrecs, int size, int n_subrecs, int score, void *body, int dir)
+{
+ byte *v;
+ int n = 0, n1, n2, *c1, *c2;
+ for (;;) {
+ n1 = n * 2 + 1;
+ n2 = n1 + 1;
+ c1 = n1 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n1) : NULL;
+ c2 = n2 < n_subrecs ? GRN_RSET_SUBRECS_NTH(subrecs,size,n2) : NULL;
+ if (c1 && GRN_RSET_SUBRECS_CMP(score, *c1, dir) > 0) {
+ if (c2 &&
+ GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0 &&
+ GRN_RSET_SUBRECS_CMP(*c1, *c2, dir) > 0) {
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
+ n = n2;
+ } else {
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c1);
+ n = n1;
+ }
+ } else {
+ if (c2 && GRN_RSET_SUBRECS_CMP(score, *c2, dir) > 0) {
+ GRN_RSET_SUBRECS_COPY(subrecs,size,n,c2);
+ n = n2;
+ } else {
+ break;
+ }
+ }
+ }
+ v = subrecs + n * (size + GRN_RSET_SCORE_SIZE);
+ grn_memcpy(v, &score, GRN_RSET_SCORE_SIZE);
+ grn_memcpy(v + GRN_RSET_SCORE_SIZE, body, size);
+}
+
+void
+grn_rhash_add_subrec(grn_hash *s, grn_rset_recinfo *ri, int score, void *body, int dir)
+{
+ int limit = s->max_n_subrecs;
+ ri->score += score;
+ ri->n_subrecs += 1;
+ if (limit) {
+ int ssize = s->subrec_size;
+ int n_subrecs = GRN_RSET_N_SUBRECS(ri);
+ if (limit < n_subrecs) {
+ if (GRN_RSET_SUBRECS_CMP(score, *ri->subrecs, dir) > 0) {
+ subrecs_replace_min(ri->subrecs, ssize, limit, score, body, dir);
+ }
+ } else {
+ subrecs_push(ri->subrecs, ssize, n_subrecs, score, body, dir);
+ }
+ }
+}
+
+grn_hash *
+grn_rhash_group(grn_hash *s, int limit, grn_group_optarg *optarg)
+{
+ grn_ctx *ctx = s->ctx;
+ grn_hash *g, h;
+ grn_rset_recinfo *ri;
+ grn_rec_unit unit;
+ grn_hash_cursor *c;
+ grn_id rh;
+ byte *key, *ekey, *gkey = NULL;
+ int funcp, dir;
+ unsigned int rsize;
+ if (!s || !s->index) { return NULL; }
+ if (optarg) {
+ unit = grn_rec_userdef;
+ rsize = optarg->key_size;
+ funcp = optarg->func ? 1 : 0;
+ dir = (optarg->mode == grn_sort_ascending) ? -1 : 1;
+ } else {
+ unit = grn_rec_document;
+ rsize = grn_rec_unit_size(unit, sizeof(grn_id));
+ funcp = 0;
+ dir = 1;
+ }
+ if (funcp) {
+ gkey = GRN_MALLOC(rsize ? rsize : 8192);
+ if (!gkey) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "allocation for gkey failed !");
+ return NULL;
+ }
+ } else {
+ if (s->key_size <= rsize) { return NULL; }
+ }
+ if (!(c = grn_hash_cursor_open(s->ctx, s, NULL, 0, NULL, -1, 0))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_hash_cursor_open on grn_hash_group failed !");
+ if (gkey) { GRN_FREE(gkey); }
+ return NULL;
+ }
+ grn_memcpy(&h, s, sizeof(grn_hash));
+ g = s;
+ s = &h;
+ if (grn_rhash_init(ctx, g, unit, rsize, s->record_unit, s->key_size, limit)) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_rhash_init in grn_hash_group failed !");
+ grn_hash_cursor_close(s->ctx, c);
+ if (gkey) { GRN_FREE(gkey); }
+ return NULL;
+ }
+ while ((rh = grn_hash_cursor_next(ctx, c))) {
+ grn_hash_cursor_get_key_value(ctx, c, (void **)&key, NULL, (void **)&ri);
+ if (funcp) {
+ if (optarg->func((grn_records *)s,
+ (grn_recordh *)(intptr_t)rh, gkey, optarg->func_arg)) { continue; }
+ ekey = key;
+ } else {
+ gkey = key;
+ ekey = key + rsize;
+ }
+ {
+ grn_rset_recinfo *gri;
+ if (grn_hash_add(ctx, g, gkey, rsize, (void **)&gri, NULL)) {
+ grn_rhash_add_subrec(g, gri, ri->score, ekey, dir);
+ }
+ }
+ }
+ grn_hash_cursor_close(s->ctx, c);
+ grn_rhash_fin(s->ctx, s);
+ if (funcp) { GRN_FREE(gkey); }
+ return g;
+}
+
+grn_rc
+grn_rhash_subrec_info(grn_ctx *ctx, grn_hash *s, grn_id rh, int index,
+ grn_id *rid, int *section, int *pos, int *score, void **subrec)
+{
+ grn_rset_posinfo *pi;
+ grn_rset_recinfo *ri;
+ int *p, unit_size = GRN_RSET_SCORE_SIZE + s->subrec_size;
+ if (!s || !rh || index < 0) { return GRN_INVALID_ARGUMENT; }
+ if ((unsigned int)index >= s->max_n_subrecs) { return GRN_INVALID_ARGUMENT; }
+ {
+ entry_str *ee;
+ if (!grn_hash_bitmap_at(ctx, s, rh)) { return GRN_INVALID_ARGUMENT; }
+ ee = grn_hash_entry_at(ctx, s, rh, 0);
+ if (!ee) { return GRN_INVALID_ARGUMENT; }
+ pi = (grn_rset_posinfo *)get_key(ctx, s, ee);
+ ri = get_value(ctx, s, ee);
+ if (!pi || !ri) { return GRN_INVALID_ARGUMENT; }
+ }
+ if (index >= ri->n_subrecs) { return GRN_INVALID_ARGUMENT; }
+ p = (int *)(ri->subrecs + index * unit_size);
+ if (score) { *score = p[0]; }
+ if (subrec) { *subrec = &p[1]; }
+ switch (s->record_unit) {
+ case grn_rec_document :
+ if (rid) { *rid = pi->rid; }
+ if (section) { *section = (s->subrec_unit != grn_rec_userdef) ? p[1] : 0; }
+ if (pos) { *pos = (s->subrec_unit == grn_rec_position) ? p[2] : 0; }
+ break;
+ case grn_rec_section :
+ if (rid) { *rid = pi->rid; }
+ if (section) { *section = pi->sid; }
+ if (pos) { *pos = (s->subrec_unit == grn_rec_position) ? p[1] : 0; }
+ break;
+ default :
+ pi = (grn_rset_posinfo *)&p[1];
+ switch (s->subrec_unit) {
+ case grn_rec_document :
+ if (rid) { *rid = pi->rid; }
+ if (section) { *section = 0; }
+ if (pos) { *pos = 0; }
+ break;
+ case grn_rec_section :
+ if (rid) { *rid = pi->rid; }
+ if (section) { *section = pi->sid; }
+ if (pos) { *pos = 0; }
+ break;
+ case grn_rec_position :
+ if (rid) { *rid = pi->rid; }
+ if (section) { *section = pi->sid; }
+ if (pos) { *pos = pi->pos; }
+ break;
+ default :
+ if (rid) { *rid = 0; }
+ if (section) { *section = 0; }
+ if (pos) { *pos = 0; }
+ break;
+ }
+ break;
+ }
+ return GRN_SUCCESS;
+}
+#endif /* USE_GRN_INDEX2 */
+
+grn_bool
+grn_hash_is_large_total_key_size(grn_ctx *ctx, grn_hash *hash)
+{
+ return (hash->header.common->flags & GRN_OBJ_KEY_LARGE) == GRN_OBJ_KEY_LARGE;
+}
+
+uint64_t
+grn_hash_total_key_size(grn_ctx *ctx, grn_hash *hash)
+{
+ if (grn_hash_is_large_total_key_size(ctx, hash)) {
+ return hash->header.common->curr_key_large;
+ } else {
+ return hash->header.common->curr_key_normal;
+ }
+}
+
+uint64_t
+grn_hash_max_total_key_size(grn_ctx *ctx, grn_hash *hash)
+{
+ if (grn_hash_is_large_total_key_size(ctx, hash)) {
+ return GRN_HASH_KEY_MAX_TOTAL_SIZE_LARGE;
+ } else {
+ return GRN_HASH_KEY_MAX_TOTAL_SIZE_NORMAL;
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/icudump.c b/storage/mroonga/vendor/groonga/lib/icudump.c
new file mode 100644
index 00000000..91751f94
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/icudump.c
@@ -0,0 +1,298 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2010 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include <stdio.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <string.h>
+#include <unicode/utf.h>
+#include <unicode/uchar.h>
+#include <unicode/unorm.h>
+#include <unicode/ustring.h>
+
+#define MAX_UNICODE 0x110000
+#define BUF_SIZE 0x100
+
+static int
+ucs2utf(unsigned int i, unsigned char *buf)
+{
+ unsigned char *p = buf;
+ if (i < 0x80) {
+ *p++ = i;
+ } else {
+ if (i < 0x800) {
+ *p++ = (i >> 6) | 0xc0;
+ } else {
+ if (i < 0x00010000) {
+ *p++ = (i >> 12) | 0xe0;
+ } else {
+ if (i < 0x00200000) {
+ *p++ = (i >> 18) | 0xf0;
+ } else {
+ if (i < 0x04000000) {
+ *p++ = (i >> 24) | 0xf8;
+ } else if (i < 0x80000000) {
+ *p++ = (i >> 30) | 0xfc;
+ *p++ = ((i >> 24) & 0x3f) | 0x80;
+ }
+ *p++ = ((i >> 18) & 0x3f) | 0x80;
+ }
+ *p++ = ((i >> 12) & 0x3f) | 0x80;
+ }
+ *p++ = ((i >> 6) & 0x3f) | 0x80;
+ }
+ *p++ = (0x3f & i) | 0x80;
+ }
+ *p = '\0';
+ return (p - buf);
+}
+
+void
+blockcode(void)
+{
+ UChar32 ch;
+ unsigned char *p, src[7];
+ UBlockCode code, lc = -1;
+ for (ch = 1; ch < MAX_UNICODE; ch++) {
+ if (!U_IS_UNICODE_CHAR(ch)) { continue; }
+ code = ublock_getCode(ch);
+ if (code != lc) {
+ ucs2utf(ch, src);
+ for (p = src; *p; p++) {
+ printf("%x:", *p);
+ }
+ printf("\t%04x\t%d\n", ch, code);
+ }
+ lc = code;
+ }
+}
+
+int
+normalize(const char *str, char *res, UNormalizationMode mode)
+{
+ UErrorCode rc;
+ int32_t ulen, nlen;
+ UChar ubuf[BUF_SIZE], nbuf[BUF_SIZE];
+ rc = U_ZERO_ERROR;
+ u_strFromUTF8(ubuf, BUF_SIZE, &ulen, str, -1, &rc);
+ if (rc != U_ZERO_ERROR /*&& rc != U_STRING_NOT_TERMINATED_WARNING*/) {
+ return -1;
+ }
+ rc = U_ZERO_ERROR;
+ nlen = unorm_normalize(ubuf, ulen, mode, 0, nbuf, BUF_SIZE, &rc);
+ if (rc != U_ZERO_ERROR /*&& rc != U_STRING_NOT_TERMINATED_WARNING*/) {
+ return -1;
+ }
+ rc = U_ZERO_ERROR;
+ u_strToUTF8(res, BUF_SIZE, NULL, nbuf, nlen, &rc);
+ if (rc != U_ZERO_ERROR /*&& rc != U_BUFFER_OVERFLOW_ERROR*/) {
+ return -1;
+ }
+ return 0;
+}
+
+void
+dump(UNormalizationMode mode)
+{
+ UChar32 ch;
+ char str[7], norm[BUF_SIZE];
+ for (ch = 1; ch < MAX_UNICODE; ch++) {
+ if (!U_IS_UNICODE_CHAR(ch)) { continue; }
+ ucs2utf(ch, (unsigned char *)str);
+ if (normalize(str, norm, mode)) {
+ printf("ch=%04x error occure\n", ch);
+ continue;
+ }
+ if (strcmp(norm, str)) {
+ printf("%04x\t%s\t%s\n", ch, str, norm);
+ }
+ }
+}
+
+void
+ccdump(void)
+{
+ UChar32 ch;
+ char str[7], nfd[BUF_SIZE], nfc[BUF_SIZE];
+ for (ch = 1; ch < MAX_UNICODE; ch++) {
+ if (!U_IS_UNICODE_CHAR(ch)) { continue; }
+ ucs2utf(ch, (unsigned char *)str);
+ if (normalize(str, nfd, UNORM_NFD)) {
+ printf("ch=%04x error occure\n", ch);
+ continue;
+ }
+ if (normalize(str, nfc, UNORM_NFC)) {
+ printf("ch=%04x error occure\n", ch);
+ continue;
+ }
+ if (strcmp(nfd, nfc)) {
+ printf("%04x\t%s\t%s\n", ch, nfd, nfc);
+ }
+ }
+}
+
+enum {
+ ctype_null = 0,
+ ctype_alpha,
+ ctype_digit,
+ ctype_symbol,
+ ctype_hiragana,
+ ctype_katakana,
+ ctype_kanji,
+ ctype_others
+};
+
+static const char *ctypes[] = {
+ "GRN_CHAR_NULL",
+ "GRN_CHAR_ALPHA",
+ "GRN_CHAR_DIGIT",
+ "GRN_CHAR_SYMBOL",
+ "GRN_CHAR_HIRAGANA",
+ "GRN_CHAR_KATAKANA",
+ "GRN_CHAR_KANJI",
+ "GRN_CHAR_OTHERS"
+};
+
+void
+gcdump(void)
+{
+ UChar32 ch;
+ unsigned char *p, src[7];
+ int ctype, lc = -1;
+ for (ch = 1; ch < MAX_UNICODE; ch++) {
+ UCharCategory cat;
+ UBlockCode code;
+ if (!U_IS_UNICODE_CHAR(ch)) { continue; }
+ code = ublock_getCode(ch);
+ switch (code) {
+ case UBLOCK_CJK_RADICALS_SUPPLEMENT: /* cjk radicals */
+ case UBLOCK_KANGXI_RADICALS: /* kanji radicals */
+ case UBLOCK_BOPOMOFO: /* bopomofo letter */
+ case UBLOCK_HANGUL_COMPATIBILITY_JAMO: /* hangul letter */
+ case UBLOCK_KANBUN: /* kaeri ten used in kanbun ex. re-ten */
+ case UBLOCK_BOPOMOFO_EXTENDED: /* bopomofo extended letter */
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A: /* cjk letter */
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS: /* cjk letter */
+ case UBLOCK_YI_SYLLABLES: /* Yi syllables */
+ case UBLOCK_YI_RADICALS: /* Yi radicals */
+ case UBLOCK_HANGUL_SYLLABLES: /* hangul syllables */
+ case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS: /* cjk letter */
+ case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B: /* cjk letter */
+ case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT: /* cjk letter */
+ case UBLOCK_CJK_STROKES: /* kakijun*/
+ ctype = ctype_kanji;
+ break;
+ case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: /* symbols ex. JIS mark */
+ case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: /* ex. (kabu) */
+ case UBLOCK_CJK_COMPATIBILITY: /* symbols ex. ton doll */
+ case UBLOCK_CJK_COMPATIBILITY_FORMS: /* symbols ex. tategaki kagi-kakko */
+ ctype = ctype_symbol;
+ break;
+ case UBLOCK_HIRAGANA:
+ ctype = ctype_hiragana;
+ break;
+ case UBLOCK_KATAKANA:
+ case UBLOCK_KATAKANA_PHONETIC_EXTENSIONS:
+ ctype = ctype_katakana;
+ break;
+ default:
+ cat = u_charType(ch);
+ switch (cat) {
+ case U_UPPERCASE_LETTER:
+ case U_LOWERCASE_LETTER:
+ case U_TITLECASE_LETTER:
+ case U_MODIFIER_LETTER:
+ case U_OTHER_LETTER:
+ ctype = ctype_alpha;
+ break;
+ case U_DECIMAL_DIGIT_NUMBER:
+ case U_LETTER_NUMBER:
+ case U_OTHER_NUMBER:
+ ctype = ctype_digit;
+ break;
+ case U_DASH_PUNCTUATION:
+ case U_START_PUNCTUATION:
+ case U_END_PUNCTUATION:
+ case U_CONNECTOR_PUNCTUATION:
+ case U_OTHER_PUNCTUATION:
+ case U_MATH_SYMBOL:
+ case U_CURRENCY_SYMBOL:
+ case U_MODIFIER_SYMBOL:
+ case U_OTHER_SYMBOL:
+ ctype = ctype_symbol;
+ break;
+ default:
+ ctype = ctype_others;
+ break;
+ }
+ break;
+ }
+ if (ctype != lc) {
+ ucs2utf(ch, src);
+ for (p = src; *p; p++) {
+ printf("%x:", *p);
+ }
+ printf("\t%04x\t%s\n", ch, ctypes[ctype]);
+ }
+ lc = ctype;
+ }
+}
+
+struct option options[] = {
+ {"bc", 0, NULL, 'b'},
+ {"nfd", 0, NULL, 'd'},
+ {"nfkd", 0, NULL, 'D'},
+ {"nfc", 0, NULL, 'c'},
+ {"nfkc", 0, NULL, 'C'},
+ {"cc", 0, NULL, 'o'},
+ {"gc", 0, NULL, 'g'},
+ {"version", 0, NULL, 'v'},
+};
+
+int
+main(int argc, char **argv)
+{
+ switch (getopt_long(argc, argv, "bdDcCogv", options, NULL)) {
+ case 'b' :
+ blockcode();
+ break;
+ case 'd' :
+ dump(UNORM_NFD);
+ break;
+ case 'D' :
+ dump(UNORM_NFKD);
+ break;
+ case 'c' :
+ dump(UNORM_NFC);
+ break;
+ case 'C' :
+ dump(UNORM_NFKC);
+ break;
+ case 'o' :
+ ccdump();
+ break;
+ case 'g' :
+ gcdump();
+ break;
+ case 'v' :
+ printf("%s\n", U_UNICODE_VERSION);
+ break;
+ default :
+ fputs("usage: icudump --[bc|nfd|nfkd|nfc|nfkc|cc|gc|version]\n", stderr);
+ break;
+ }
+ return 0;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/id.c b/storage/mroonga/vendor/groonga/lib/id.c
new file mode 100644
index 00000000..96eae9f9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/id.c
@@ -0,0 +1,36 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_db.h"
+
+grn_bool
+grn_id_is_builtin(grn_ctx *ctx, grn_id id)
+{
+ if (id == GRN_ID_NIL) {
+ return GRN_FALSE;
+ } else {
+ return id < GRN_N_RESERVED_TYPES;
+ }
+}
+
+grn_bool
+grn_id_is_builtin_type(grn_ctx *ctx, grn_id id)
+{
+ return GRN_DB_OBJECT <= id && id <= GRN_DB_WGS84_GEO_POINT;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ii.c b/storage/mroonga/vendor/groonga/lib/ii.c
new file mode 100644
index 00000000..3e402e15
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ii.c
@@ -0,0 +1,12815 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <io.h>
+# include <share.h>
+#endif /* WIN32 */
+
+#include "grn_ii.h"
+#include "grn_ctx_impl.h"
+#include "grn_token_cursor.h"
+#include "grn_pat.h"
+#include "grn_db.h"
+#include "grn_output.h"
+#include "grn_scorer.h"
+#include "grn_util.h"
+
+#ifdef GRN_WITH_ONIGMO
+# define GRN_II_SELECT_ENABLE_SEQUENTIAL_SEARCH
+#endif
+
+#ifdef GRN_II_SELECT_ENABLE_SEQUENTIAL_SEARCH
+# include "grn_string.h"
+# include <onigmo.h>
+#endif
+
+#define MAX_PSEG 0x20000
+#define MAX_PSEG_SMALL 0x00200
+/* MAX_PSEG_MEDIUM has enough space for the following source:
+ * * Single source.
+ * * Source is a fixed size column or _key of a table.
+ * * Source column is a scalar column.
+ * * Lexicon doesn't have tokenizer.
+ */
+#define MAX_PSEG_MEDIUM 0x10000
+#define S_CHUNK (1 << GRN_II_W_CHUNK)
+#define W_SEGMENT 18
+#define S_SEGMENT (1 << W_SEGMENT)
+#define W_ARRAY_ELEMENT 3
+#define S_ARRAY_ELEMENT (1 << W_ARRAY_ELEMENT)
+#define W_ARRAY (W_SEGMENT - W_ARRAY_ELEMENT)
+#define ARRAY_MASK_IN_A_SEGMENT ((1 << W_ARRAY) - 1)
+
+#define S_GARBAGE (1<<12)
+
+#define CHUNK_SPLIT 0x80000000
+#define CHUNK_SPLIT_THRESHOLD 0x60000
+
+#define MAX_N_ELEMENTS 5
+
+#define DEFINE_NAME(ii) \
+ const char *name; \
+ char name_buffer[GRN_TABLE_MAX_KEY_SIZE]; \
+ int name_size; \
+ do { \
+ if (DB_OBJ(ii)->id == GRN_ID_NIL) { \
+ name = "(temporary)"; \
+ name_size = strlen(name); \
+ } else { \
+ name_size = grn_obj_name(ctx, (grn_obj *)ii, \
+ name_buffer, GRN_TABLE_MAX_KEY_SIZE); \
+ name = name_buffer; \
+ } \
+ } while (GRN_FALSE)
+
+#define LSEG(pos) ((pos) >> 16)
+#define LPOS(pos) (((pos) & 0xffff) << 2)
+#define SEG2POS(seg,pos) ((((uint32_t)(seg)) << 16) + (((uint32_t)(pos)) >> 2))
+
+#ifndef S_IRUSR
+# define S_IRUSR 0400
+#endif /* S_IRUSR */
+#ifndef S_IWUSR
+# define S_IWUSR 0200
+#endif /* S_IWUSR */
+
+static grn_bool grn_ii_cursor_set_min_enable = GRN_TRUE;
+static double grn_ii_select_too_many_index_match_ratio = -1;
+static double grn_ii_estimate_size_for_query_reduce_ratio = 0.9;
+static grn_bool grn_ii_overlap_token_skip_enable = GRN_FALSE;
+static uint32_t grn_ii_builder_block_threshold_force = 0;
+static uint32_t grn_ii_max_n_segments_small = MAX_PSEG_SMALL;
+static uint32_t grn_ii_max_n_chunks_small = GRN_II_MAX_CHUNK_SMALL;
+
+void
+grn_ii_init_from_env(void)
+{
+ {
+ char grn_ii_cursor_set_min_enable_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_CURSOR_SET_MIN_ENABLE",
+ grn_ii_cursor_set_min_enable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (strcmp(grn_ii_cursor_set_min_enable_env, "no") == 0) {
+ grn_ii_cursor_set_min_enable = GRN_FALSE;
+ } else {
+ grn_ii_cursor_set_min_enable = GRN_TRUE;
+ }
+ }
+
+ {
+ char grn_ii_select_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_SELECT_TOO_MANY_INDEX_MATCH_RATIO",
+ grn_ii_select_too_many_index_match_ratio_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ii_select_too_many_index_match_ratio_env[0]) {
+ grn_ii_select_too_many_index_match_ratio =
+ atof(grn_ii_select_too_many_index_match_ratio_env);
+ }
+ }
+
+ {
+ char grn_ii_estimate_size_for_query_reduce_ratio_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_ESTIMATE_SIZE_FOR_QUERY_REDUCE_RATIO",
+ grn_ii_estimate_size_for_query_reduce_ratio_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ii_estimate_size_for_query_reduce_ratio_env[0]) {
+ grn_ii_estimate_size_for_query_reduce_ratio =
+ atof(grn_ii_estimate_size_for_query_reduce_ratio_env);
+ }
+ }
+
+ {
+ char grn_ii_overlap_token_skip_enable_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_OVERLAP_TOKEN_SKIP_ENABLE",
+ grn_ii_overlap_token_skip_enable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ii_overlap_token_skip_enable_env[0]) {
+ grn_ii_overlap_token_skip_enable = GRN_TRUE;
+ } else {
+ grn_ii_overlap_token_skip_enable = GRN_FALSE;
+ }
+ }
+
+ {
+ char grn_ii_builder_block_threshold_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_BUILDER_BLOCK_THRESHOLD",
+ grn_ii_builder_block_threshold_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ii_builder_block_threshold_env[0]) {
+ grn_ii_builder_block_threshold_force =
+ grn_atoui(grn_ii_builder_block_threshold_env,
+ grn_ii_builder_block_threshold_env +
+ strlen(grn_ii_builder_block_threshold_env),
+ NULL);
+ } else {
+ grn_ii_builder_block_threshold_force = 0;
+ }
+ }
+
+ {
+ char grn_ii_max_n_segments_small_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_MAX_N_SEGMENTS_SMALL",
+ grn_ii_max_n_segments_small_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ii_max_n_segments_small_env[0]) {
+ grn_ii_max_n_segments_small =
+ grn_atoui(grn_ii_max_n_segments_small_env,
+ grn_ii_max_n_segments_small_env +
+ strlen(grn_ii_max_n_segments_small_env),
+ NULL);
+ if (grn_ii_max_n_segments_small > MAX_PSEG) {
+ grn_ii_max_n_segments_small = MAX_PSEG;
+ }
+ }
+ }
+
+ {
+ char grn_ii_max_n_chunks_small_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_II_MAX_N_CHUNKS_SMALL",
+ grn_ii_max_n_chunks_small_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ii_max_n_chunks_small_env[0]) {
+ grn_ii_max_n_chunks_small =
+ grn_atoui(grn_ii_max_n_chunks_small_env,
+ grn_ii_max_n_chunks_small_env +
+ strlen(grn_ii_max_n_chunks_small_env),
+ NULL);
+ if (grn_ii_max_n_chunks_small > GRN_II_MAX_CHUNK) {
+ grn_ii_max_n_chunks_small = GRN_II_MAX_CHUNK;
+ }
+ }
+ }
+}
+
+void
+grn_ii_cursor_set_min_enable_set(grn_bool enable)
+{
+ grn_ii_cursor_set_min_enable = enable;
+}
+
+grn_bool
+grn_ii_cursor_set_min_enable_get(void)
+{
+ return grn_ii_cursor_set_min_enable;
+}
+
+/* segment */
+
+inline static uint32_t
+segment_get(grn_ctx *ctx, grn_ii *ii)
+{
+ uint32_t pseg;
+ if (ii->header->bgqtail == ((ii->header->bgqhead + 1) & (GRN_II_BGQSIZE - 1))) {
+ pseg = ii->header->bgqbody[ii->header->bgqtail];
+ ii->header->bgqtail = (ii->header->bgqtail + 1) & (GRN_II_BGQSIZE - 1);
+ } else {
+ pseg = ii->header->pnext;
+#ifndef CUT_OFF_COMPATIBILITY
+ if (!pseg) {
+ uint32_t pmax = 0;
+ char *used;
+ uint32_t i, max_segment = ii->seg->header->max_segment;
+ used = GRN_CALLOC(max_segment);
+ if (!used) { return max_segment; }
+ for (i = 0; i < GRN_II_MAX_LSEG && i < max_segment; i++) {
+ if ((pseg = ii->header->ainfo[i]) != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (pseg > pmax) { pmax = pseg; }
+ used[pseg] = 1;
+ }
+ if ((pseg = ii->header->binfo[i]) != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (pseg > pmax) { pmax = pseg; }
+ used[pseg] = 1;
+ }
+ }
+ for (pseg = 0; pseg < max_segment && used[pseg]; pseg++) ;
+ GRN_FREE(used);
+ ii->header->pnext = pmax + 1;
+ } else
+#endif /* CUT_OFF_COMPATIBILITY */
+ if (ii->header->pnext < ii->seg->header->max_segment) {
+ ii->header->pnext++;
+ }
+ }
+ return pseg;
+}
+
+inline static grn_rc
+segment_get_clear(grn_ctx *ctx, grn_ii *ii, uint32_t *pseg)
+{
+ uint32_t seg = segment_get(ctx, ii);
+ if (seg < ii->seg->header->max_segment) {
+ void *p = NULL;
+ GRN_IO_SEG_REF(ii->seg, seg, p);
+ if (!p) { return GRN_NO_MEMORY_AVAILABLE; }
+ memset(p, 0, S_SEGMENT);
+ GRN_IO_SEG_UNREF(ii->seg, seg);
+ *pseg = seg;
+ return GRN_SUCCESS;
+ } else {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+}
+
+inline static grn_rc
+buffer_segment_new(grn_ctx *ctx, grn_ii *ii, uint32_t *segno)
+{
+ uint32_t lseg, pseg;
+ if (*segno < GRN_II_MAX_LSEG) {
+ if (ii->header->binfo[*segno] != GRN_II_PSEG_NOT_ASSIGNED) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ lseg = *segno;
+ } else {
+ for (lseg = 0; lseg < GRN_II_MAX_LSEG; lseg++) {
+ if (ii->header->binfo[lseg] == GRN_II_PSEG_NOT_ASSIGNED) { break; }
+ }
+ if (lseg == GRN_II_MAX_LSEG) { return GRN_NO_MEMORY_AVAILABLE; }
+ *segno = lseg;
+ }
+ pseg = segment_get(ctx, ii);
+ if (pseg < ii->seg->header->max_segment) {
+ ii->header->binfo[lseg] = pseg;
+ if (lseg >= ii->header->bmax) { ii->header->bmax = lseg + 1; }
+ return GRN_SUCCESS;
+ } else {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+}
+
+static grn_rc
+buffer_segment_reserve(grn_ctx *ctx, grn_ii *ii,
+ uint32_t *lseg0, uint32_t *pseg0,
+ uint32_t *lseg1, uint32_t *pseg1)
+{
+ uint32_t i = 0;
+ for (;; i++) {
+ if (i == GRN_II_MAX_LSEG) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][segment][reserve] "
+ "couldn't find a free buffer: <%.*s>: max:<%u>",
+ name_size, name,
+ GRN_II_MAX_LSEG);
+ return ctx->rc;
+ }
+ if (ii->header->binfo[i] == GRN_II_PSEG_NOT_ASSIGNED) { break; }
+ }
+ *lseg0 = i++;
+ for (;; i++) {
+ if (i == GRN_II_MAX_LSEG) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][segment][reserve] "
+ "couldn't find two free buffers: "
+ "<%.*s>: "
+ "found:<%u>, max:<%u>",
+ name_size, name,
+ *lseg0, GRN_II_MAX_LSEG);
+ return ctx->rc;
+ }
+ if (ii->header->binfo[i] == GRN_II_PSEG_NOT_ASSIGNED) { break; }
+ }
+ *lseg1 = i;
+ if ((*pseg0 = segment_get(ctx, ii)) == ii->seg->header->max_segment) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][segment][reserve] "
+ "couldn't allocate a free segment: <%.*s>: "
+ "buffer:<%u>, max:<%u>",
+ name_size, name,
+ *lseg0, ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ if ((*pseg1 = segment_get(ctx, ii)) == ii->seg->header->max_segment) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][segment][reserve] "
+ "couldn't allocate two free segments: "
+ "<%.*s>: "
+ "found:<%u>, not-found:<%u>, max:<%u>",
+ name_size, name,
+ *lseg0, *lseg1, ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ /*
+ {
+ uint32_t pseg;
+ char *used = GRN_CALLOC(ii->seg->header->max_segment);
+ if (!used) { return GRN_NO_MEMORY_AVAILABLE; }
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ if ((pseg = ii->header->ainfo[i]) != GRN_II_PSEG_NOT_ASSIGNED) {
+ used[pseg] = 1;
+ }
+ if ((pseg = ii->header->binfo[i]) != GRN_II_PSEG_NOT_ASSIGNED) {
+ used[pseg] = 1;
+ }
+ }
+ for (pseg = 0;; pseg++) {
+ if (pseg == ii->seg->header->max_segment) {
+ GRN_FREE(used);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (!used[pseg]) { break; }
+ }
+ *pseg0 = pseg++;
+ for (;; pseg++) {
+ if (pseg == ii->seg->header->max_segment) {
+ GRN_FREE(used);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (!used[pseg]) { break; }
+ }
+ *pseg1 = pseg;
+ GRN_FREE(used);
+ }
+ */
+ return ctx->rc;
+}
+
+#define BGQENQUE(lseg) do {\
+ if (ii->header->binfo[lseg] != GRN_II_PSEG_NOT_ASSIGNED) {\
+ ii->header->bgqbody[ii->header->bgqhead] = ii->header->binfo[lseg];\
+ ii->header->bgqhead = (ii->header->bgqhead + 1) & (GRN_II_BGQSIZE - 1);\
+ GRN_ASSERT(ii->header->bgqhead != ii->header->bgqtail);\
+ }\
+} while (0)
+
+inline static void
+buffer_segment_update(grn_ii *ii, uint32_t lseg, uint32_t pseg)
+{
+ BGQENQUE(lseg);
+ // smb_wmb();
+ ii->header->binfo[lseg] = pseg;
+ if (lseg >= ii->header->bmax) { ii->header->bmax = lseg + 1; }
+}
+
+inline static void
+buffer_segment_clear(grn_ii *ii, uint32_t lseg)
+{
+ BGQENQUE(lseg);
+ // smb_wmb();
+ ii->header->binfo[lseg] = GRN_II_PSEG_NOT_ASSIGNED;
+}
+
+/* chunk */
+
+#define HEADER_CHUNK_AT(ii,offset) \
+ ((((ii)->header->chunks[((offset) >> 3)]) >> ((offset) & 7)) & 1)
+
+#define HEADER_CHUNK_ON(ii,offset) \
+ (((ii)->header->chunks[((offset) >> 3)]) |= (1 << ((offset) & 7)))
+
+#define HEADER_CHUNK_OFF(ii,offset) \
+ (((ii)->header->chunks[((offset) >> 3)]) &= ~(1 << ((offset) & 7)))
+
+#define N_GARBAGES_TH 1
+
+#define N_GARBAGES ((S_GARBAGE - (sizeof(uint32_t) * 4))/(sizeof(uint32_t)))
+
+typedef struct {
+ uint32_t head;
+ uint32_t tail;
+ uint32_t nrecs;
+ uint32_t next;
+ uint32_t recs[N_GARBAGES];
+} grn_ii_ginfo;
+
+#define WIN_MAP(chunk,ctx,iw,seg,pos,size,mode)\
+ grn_io_win_map(chunk, ctx, iw,\
+ ((seg) >> GRN_II_N_CHUNK_VARIATION),\
+ (((seg) & ((1 << GRN_II_N_CHUNK_VARIATION) - 1)) << GRN_II_W_LEAST_CHUNK) + (pos),\
+ size, mode)
+/*
+static int new_histogram[32];
+static int free_histogram[32];
+*/
+static grn_rc
+chunk_new(grn_ctx *ctx, grn_ii *ii, uint32_t *res, uint32_t size)
+{
+ uint32_t n_chunks;
+
+ n_chunks = ii->chunk->header->max_segment;
+
+ /*
+ if (size) {
+ int m, es = size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ new_histogram[m]++;
+ }
+ */
+ if (size > S_CHUNK) {
+ int j;
+ uint32_t n = (size + S_CHUNK - 1) >> GRN_II_W_CHUNK, i;
+ for (i = 0, j = -1; i < n_chunks; i++) {
+ if (HEADER_CHUNK_AT(ii, i)) {
+ j = i;
+ } else {
+ if (i == j + n) {
+ j++;
+ *res = j << GRN_II_N_CHUNK_VARIATION;
+ for (; j <= (int) i; j++) { HEADER_CHUNK_ON(ii, j); }
+ return GRN_SUCCESS;
+ }
+ }
+ }
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][chunk][new] index is full: "
+ "<%.*s>: "
+ "size:<%u>, n-chunks:<%u>",
+ name_size, name,
+ size, n_chunks);
+ }
+ return ctx->rc;
+ } else {
+ uint32_t *vp;
+ int m, aligned_size;
+ if (size > (1 << GRN_II_W_LEAST_CHUNK)) {
+ int es = size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ } else {
+ m = GRN_II_W_LEAST_CHUNK;
+ }
+ aligned_size = 1 << (m - GRN_II_W_LEAST_CHUNK);
+ if (ii->header->ngarbages[m - GRN_II_W_LEAST_CHUNK] > N_GARBAGES_TH) {
+ grn_ii_ginfo *ginfo;
+ uint32_t *gseg;
+ grn_io_win iw, iw_;
+ iw_.addr = NULL;
+ gseg = &ii->header->garbages[m - GRN_II_W_LEAST_CHUNK];
+ while (*gseg != GRN_II_PSEG_NOT_ASSIGNED) {
+ ginfo = WIN_MAP(ii->chunk, ctx, &iw, *gseg, 0, S_GARBAGE, grn_io_rdwr);
+ //GRN_IO_SEG_MAP2(ii->chunk, *gseg, ginfo);
+ if (!ginfo) {
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][chunk][new] failed to allocate garbage segment: "
+ "<%.*s>: "
+ "n-garbages:<%u>, size:<%u>, n-chunks:<%u>",
+ name_size, name,
+ ii->header->ngarbages[m - GRN_II_W_LEAST_CHUNK],
+ size,
+ n_chunks);
+ }
+ return ctx->rc;
+ }
+ if (ginfo->next != GRN_II_PSEG_NOT_ASSIGNED ||
+ ginfo->nrecs > N_GARBAGES_TH) {
+ *res = ginfo->recs[ginfo->tail];
+ if (++ginfo->tail == N_GARBAGES) { ginfo->tail = 0; }
+ ginfo->nrecs--;
+ ii->header->ngarbages[m - GRN_II_W_LEAST_CHUNK]--;
+ if (!ginfo->nrecs) {
+ HEADER_CHUNK_OFF(ii, *gseg);
+ *gseg = ginfo->next;
+ }
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ grn_io_win_unmap(&iw);
+ return GRN_SUCCESS;
+ }
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ iw_ = iw;
+ gseg = &ginfo->next;
+ }
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ }
+ vp = &ii->header->free_chunks[m - GRN_II_W_LEAST_CHUNK];
+ if (*vp == GRN_II_PSEG_NOT_ASSIGNED) {
+ int i = 0;
+ while (HEADER_CHUNK_AT(ii, i)) {
+ if (++i >= (int) n_chunks) {
+ DEFINE_NAME(ii);
+ MERR("[ii][chunk][new] failed to find a free chunk: "
+ "<%.*s>: "
+ "index:<%u>, size:<%u>, n-chunks:<%u>",
+ name_size, name,
+ m - GRN_II_W_LEAST_CHUNK,
+ size,
+ n_chunks);
+ return ctx->rc;
+ }
+ }
+ HEADER_CHUNK_ON(ii, i);
+ *vp = i << GRN_II_N_CHUNK_VARIATION;
+ }
+ *res = *vp;
+ *vp += 1 << (m - GRN_II_W_LEAST_CHUNK);
+ if (!(*vp & ((1 << GRN_II_N_CHUNK_VARIATION) - 1))) {
+ *vp = GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ return GRN_SUCCESS;
+ }
+}
+
+static grn_rc
+chunk_free(grn_ctx *ctx, grn_ii *ii,
+ uint32_t offset, uint32_t dummy, uint32_t size)
+{
+ /*
+ if (size) {
+ int m, es = size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ free_histogram[m]++;
+ }
+ */
+ grn_io_win iw, iw_;
+ grn_ii_ginfo *ginfo= 0;
+ uint32_t seg, m, *gseg;
+ seg = offset >> GRN_II_N_CHUNK_VARIATION;
+ if (size > S_CHUNK) {
+ int n = (size + S_CHUNK - 1) >> GRN_II_W_CHUNK;
+ for (; n--; seg++) { HEADER_CHUNK_OFF(ii, seg); }
+ return GRN_SUCCESS;
+ }
+ if (size > (1 << GRN_II_W_LEAST_CHUNK)) {
+ int es = size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ } else {
+ m = GRN_II_W_LEAST_CHUNK;
+ }
+ gseg = &ii->header->garbages[m - GRN_II_W_LEAST_CHUNK];
+ iw_.addr = NULL;
+ while (*gseg != GRN_II_PSEG_NOT_ASSIGNED) {
+ ginfo = WIN_MAP(ii->chunk, ctx, &iw, *gseg, 0, S_GARBAGE, grn_io_rdwr);
+ // GRN_IO_SEG_MAP2(ii->chunk, *gseg, ginfo);
+ if (!ginfo) {
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (ginfo->nrecs < N_GARBAGES) { break; }
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ iw_ = iw;
+ gseg = &ginfo->next;
+ }
+ if (*gseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_rc rc;
+ if ((rc = chunk_new(ctx, ii, gseg, S_GARBAGE))) {
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ return rc;
+ }
+ ginfo = WIN_MAP(ii->chunk, ctx, &iw, *gseg, 0, S_GARBAGE, grn_io_rdwr);
+ /*
+ uint32_t i = 0;
+ while (HEADER_CHUNK_AT(ii, i)) {
+ if (++i >= ii->chunk->header->max_segment) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ HEADER_CHUNK_ON(ii, i);
+ *gseg = i;
+ GRN_IO_SEG_MAP2(ii->chunk, *gseg, ginfo);
+ */
+ if (!ginfo) {
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ ginfo->head = 0;
+ ginfo->tail = 0;
+ ginfo->nrecs = 0;
+ ginfo->next = GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ if (iw_.addr) { grn_io_win_unmap(&iw_); }
+ ginfo->recs[ginfo->head] = offset;
+ if (++ginfo->head == N_GARBAGES) { ginfo->head = 0; }
+ ginfo->nrecs++;
+ grn_io_win_unmap(&iw);
+ ii->header->ngarbages[m - GRN_II_W_LEAST_CHUNK]++;
+ return GRN_SUCCESS;
+}
+
+#define UNIT_SIZE 0x80
+#define UNIT_MASK (UNIT_SIZE - 1)
+
+/* <generated> */
+static uint8_t *
+pack_1(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 7;
+ v += *p++ << 6;
+ v += *p++ << 5;
+ v += *p++ << 4;
+ v += *p++ << 3;
+ v += *p++ << 2;
+ v += *p++ << 1;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_1(uint32_t *p, uint8_t *dp)
+{
+ *p++ = (*dp >> 7);
+ *p++ = ((*dp >> 6) & 0x1);
+ *p++ = ((*dp >> 5) & 0x1);
+ *p++ = ((*dp >> 4) & 0x1);
+ *p++ = ((*dp >> 3) & 0x1);
+ *p++ = ((*dp >> 2) & 0x1);
+ *p++ = ((*dp >> 1) & 0x1);
+ *p++ = (*dp++ & 0x1);
+ return dp;
+}
+static uint8_t *
+pack_2(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 6;
+ v += *p++ << 4;
+ v += *p++ << 2;
+ *rp++ = v + *p++;
+ v = *p++ << 6;
+ v += *p++ << 4;
+ v += *p++ << 2;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_2(uint32_t *p, uint8_t *dp)
+{
+ *p++ = (*dp >> 6);
+ *p++ = ((*dp >> 4) & 0x3);
+ *p++ = ((*dp >> 2) & 0x3);
+ *p++ = (*dp++ & 0x3);
+ *p++ = (*dp >> 6);
+ *p++ = ((*dp >> 4) & 0x3);
+ *p++ = ((*dp >> 2) & 0x3);
+ *p++ = (*dp++ & 0x3);
+ return dp;
+}
+static uint8_t *
+pack_3(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 5;
+ v += *p++ << 2;
+ *rp++ = v + (*p >> 1); v = *p++ << 7;
+ v += *p++ << 4;
+ v += *p++ << 1;
+ *rp++ = v + (*p >> 2); v = *p++ << 6;
+ v += *p++ << 3;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_3(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ *p++ = (*dp >> 5);
+ *p++ = ((*dp >> 2) & 0x7);
+ v = ((*dp++ << 1) & 0x7); *p++ = v + (*dp >> 7);
+ *p++ = ((*dp >> 4) & 0x7);
+ *p++ = ((*dp >> 1) & 0x7);
+ v = ((*dp++ << 2) & 0x7); *p++ = v + (*dp >> 6);
+ *p++ = ((*dp >> 3) & 0x7);
+ *p++ = (*dp++ & 0x7);
+ return dp;
+}
+static uint8_t *
+pack_4(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 4;
+ *rp++ = v + *p++;
+ v = *p++ << 4;
+ *rp++ = v + *p++;
+ v = *p++ << 4;
+ *rp++ = v + *p++;
+ v = *p++ << 4;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_4(uint32_t *p, uint8_t *dp)
+{
+ *p++ = (*dp >> 4);
+ *p++ = (*dp++ & 0xf);
+ *p++ = (*dp >> 4);
+ *p++ = (*dp++ & 0xf);
+ *p++ = (*dp >> 4);
+ *p++ = (*dp++ & 0xf);
+ *p++ = (*dp >> 4);
+ *p++ = (*dp++ & 0xf);
+ return dp;
+}
+static uint8_t *
+pack_5(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 3;
+ *rp++ = v + (*p >> 2); v = *p++ << 6;
+ v += *p++ << 1;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 1); v = *p++ << 7;
+ v += *p++ << 2;
+ *rp++ = v + (*p >> 3); v = *p++ << 5;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_5(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ *p++ = (*dp >> 3);
+ v = ((*dp++ << 2) & 0x1f); *p++ = v + (*dp >> 6);
+ *p++ = ((*dp >> 1) & 0x1f);
+ v = ((*dp++ << 4) & 0x1f); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 1) & 0x1f); *p++ = v + (*dp >> 7);
+ *p++ = ((*dp >> 2) & 0x1f);
+ v = ((*dp++ << 3) & 0x1f); *p++ = v + (*dp >> 5);
+ *p++ = (*dp++ & 0x1f);
+ return dp;
+}
+static uint8_t *
+pack_6(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 2;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 2); v = *p++ << 6;
+ *rp++ = v + *p++;
+ v = *p++ << 2;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 2); v = *p++ << 6;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_6(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ *p++ = (*dp >> 2);
+ v = ((*dp++ << 4) & 0x3f); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 2) & 0x3f); *p++ = v + (*dp >> 6);
+ *p++ = (*dp++ & 0x3f);
+ *p++ = (*dp >> 2);
+ v = ((*dp++ << 4) & 0x3f); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 2) & 0x3f); *p++ = v + (*dp >> 6);
+ *p++ = (*dp++ & 0x3f);
+ return dp;
+}
+static uint8_t *
+pack_7(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ v = *p++ << 1;
+ *rp++ = v + (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 1); v = *p++ << 7;
+ *rp++ = v + *p++;
+ return rp;
+}
+static uint8_t *
+unpack_7(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ *p++ = (*dp >> 1);
+ v = ((*dp++ << 6) & 0x7f); *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 5) & 0x7f); *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 4) & 0x7f); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 3) & 0x7f); *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 2) & 0x7f); *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 1) & 0x7f); *p++ = v + (*dp >> 7);
+ *p++ = (*dp++ & 0x7f);
+ return dp;
+}
+static uint8_t *
+pack_8(uint32_t *p, uint8_t *rp)
+{
+ *rp++ = *p++;
+ *rp++ = *p++;
+ *rp++ = *p++;
+ *rp++ = *p++;
+ *rp++ = *p++;
+ *rp++ = *p++;
+ *rp++ = *p++;
+ *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_8(uint32_t *p, uint8_t *dp)
+{
+ *p++ = *dp++;
+ *p++ = *dp++;
+ *p++ = *dp++;
+ *p++ = *dp++;
+ *p++ = *dp++;
+ *p++ = *dp++;
+ *p++ = *dp++;
+ *p++ = *dp++;
+ return dp;
+}
+static uint8_t *
+pack_9(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_9(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 2) & 0x1ff); *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 3) & 0x1ff); *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 4) & 0x1ff); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 5) & 0x1ff); *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 6) & 0x1ff); *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 7) & 0x1ff); *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 8) & 0x1ff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_10(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_10(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 4) & 0x3ff); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 6) & 0x3ff); *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 8) & 0x3ff); *p++ = v + *dp++;
+ v = *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 4) & 0x3ff); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 6) & 0x3ff); *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 8) & 0x3ff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_11(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_11(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 6) & 0x7ff); *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 9) & 0x7ff); v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 4) & 0x7ff); *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 7) & 0x7ff); *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 10) & 0x7ff); v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 5) & 0x7ff); *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 8) & 0x7ff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_12(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_12(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 8) & 0xfff); *p++ = v + *dp++;
+ v = *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 8) & 0xfff); *p++ = v + *dp++;
+ v = *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 8) & 0xfff); *p++ = v + *dp++;
+ v = *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 8) & 0xfff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_13(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_13(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 10) & 0x1fff); v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 7) & 0x1fff); *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 12) & 0x1fff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 9) & 0x1fff); v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 6) & 0x1fff); *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 11) & 0x1fff); v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 8) & 0x1fff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_14(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_14(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 12) & 0x3fff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 10) & 0x3fff); v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 8) & 0x3fff); *p++ = v + *dp++;
+ v = *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 12) & 0x3fff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 10) & 0x3fff); v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 8) & 0x3fff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_15(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_15(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 7; *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 14) & 0x7fff); v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 13) & 0x7fff); v += *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 12) & 0x7fff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 11) & 0x7fff); v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 10) & 0x7fff); v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 9) & 0x7fff); v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 8) & 0x7fff); *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_16(uint32_t *p, uint8_t *rp)
+{
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_16(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_17(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_17(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 9; v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 10) & 0x1ffff); v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 11) & 0x1ffff); v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 12) & 0x1ffff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 13) & 0x1ffff); v += *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 14) & 0x1ffff); v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 15) & 0x1ffff); v += *dp++ << 7; *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 16) & 0x1ffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_18(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_18(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 10; v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 12) & 0x3ffff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 14) & 0x3ffff); v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 16) & 0x3ffff); v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 10; v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 12) & 0x3ffff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 14) & 0x3ffff); v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 16) & 0x3ffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_19(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 17); *rp++ = (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_19(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 11; v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 14) & 0x7ffff); v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 17) & 0x7ffff); v += *dp++ << 9; v += *dp++ << 1;
+ *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 12) & 0x7ffff); v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 15) & 0x7ffff); v += *dp++ << 7; *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 18) & 0x7ffff); v += *dp++ << 10; v += *dp++ << 2;
+ *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 13) & 0x7ffff); v += *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 16) & 0x7ffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_20(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_20(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 16) & 0xfffff); v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 16) & 0xfffff); v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 16) & 0xfffff); v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 16) & 0xfffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_21(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 17); *rp++ = (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 19); *rp++ = (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_21(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 13; v += *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 18) & 0x1fffff); v += *dp++ << 10; v += *dp++ << 2;
+ *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 15) & 0x1fffff); v += *dp++ << 7; *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 20) & 0x1fffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 17) & 0x1fffff); v += *dp++ << 9; v += *dp++ << 1;
+ *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 14) & 0x1fffff); v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 19) & 0x1fffff); v += *dp++ << 11; v += *dp++ << 3;
+ *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 16) & 0x1fffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_22(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_22(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 14; v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 20) & 0x3fffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 18) & 0x3fffff); v += *dp++ << 10; v += *dp++ << 2;
+ *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 16) & 0x3fffff); v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 14; v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 20) & 0x3fffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 18) & 0x3fffff); v += *dp++ << 10; v += *dp++ << 2;
+ *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 16) & 0x3fffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_23(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 21); *rp++ = (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 19); *rp++ = (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 17); *rp++ = (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_23(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 15; v += *dp++ << 7; *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 22) & 0x7fffff); v += *dp++ << 14; v += *dp++ << 6;
+ *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 21) & 0x7fffff); v += *dp++ << 13; v += *dp++ << 5;
+ *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 20) & 0x7fffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 19) & 0x7fffff); v += *dp++ << 11; v += *dp++ << 3;
+ *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 18) & 0x7fffff); v += *dp++ << 10; v += *dp++ << 2;
+ *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 17) & 0x7fffff); v += *dp++ << 9; v += *dp++ << 1;
+ *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 16) & 0x7fffff); v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_24(uint32_t *p, uint8_t *rp)
+{
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_24(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_25(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 17); *rp++ = (*p >> 9); *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 19); *rp++ = (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 21); *rp++ = (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 23); *rp++ = (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_25(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 17; v += *dp++ << 9; v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 18) & 0x1ffffff); v += *dp++ << 10; v += *dp++ << 2;
+ *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 19) & 0x1ffffff); v += *dp++ << 11; v += *dp++ << 3;
+ *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 20) & 0x1ffffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 21) & 0x1ffffff); v += *dp++ << 13; v += *dp++ << 5;
+ *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 22) & 0x1ffffff); v += *dp++ << 14; v += *dp++ << 6;
+ *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 23) & 0x1ffffff); v += *dp++ << 15; v += *dp++ << 7;
+ *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 24) & 0x1ffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_26(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 18); *rp++ = (*p >> 10); *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_26(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 18; v += *dp++ << 10; v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 20) & 0x3ffffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 22) & 0x3ffffff); v += *dp++ << 14; v += *dp++ << 6;
+ *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 24) & 0x3ffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ v = *dp++ << 18; v += *dp++ << 10; v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 20) & 0x3ffffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 22) & 0x3ffffff); v += *dp++ << 14; v += *dp++ << 6;
+ *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 24) & 0x3ffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_27(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 19); *rp++ = (*p >> 11); *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 25); *rp++ = (*p >> 17); *rp++ = (*p >> 9);
+ *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 23); *rp++ = (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 26); *rp++ = (*p >> 18); *rp++ = (*p >> 10);
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 21); *rp++ = (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_27(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 19; v += *dp++ << 11; v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 22) & 0x7ffffff); v += *dp++ << 14; v += *dp++ << 6;
+ *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 25) & 0x7ffffff); v += *dp++ << 17; v += *dp++ << 9;
+ v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 20) & 0x7ffffff); v += *dp++ << 12; v += *dp++ << 4;
+ *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 23) & 0x7ffffff); v += *dp++ << 15; v += *dp++ << 7;
+ *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 26) & 0x7ffffff); v += *dp++ << 18; v += *dp++ << 10;
+ v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 21) & 0x7ffffff); v += *dp++ << 13; v += *dp++ << 5;
+ *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 24) & 0x7ffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_28(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 20); *rp++ = (*p >> 12); *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_28(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 20; v += *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 24) & 0xfffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ v = *dp++ << 20; v += *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 24) & 0xfffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ v = *dp++ << 20; v += *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 24) & 0xfffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ v = *dp++ << 20; v += *dp++ << 12; v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 24) & 0xfffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_29(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 21); *rp++ = (*p >> 13); *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 26); *rp++ = (*p >> 18); *rp++ = (*p >> 10);
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 23); *rp++ = (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 28); *rp++ = (*p >> 20); *rp++ = (*p >> 12);
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 25); *rp++ = (*p >> 17); *rp++ = (*p >> 9);
+ *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 27); *rp++ = (*p >> 19); *rp++ = (*p >> 11);
+ *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_29(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 21; v += *dp++ << 13; v += *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 26) & 0x1fffffff); v += *dp++ << 18; v += *dp++ << 10;
+ v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 23) & 0x1fffffff); v += *dp++ << 15; v += *dp++ << 7;
+ *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 28) & 0x1fffffff); v += *dp++ << 20; v += *dp++ << 12;
+ v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 25) & 0x1fffffff); v += *dp++ << 17; v += *dp++ << 9;
+ v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 22) & 0x1fffffff); v += *dp++ << 14; v += *dp++ << 6;
+ *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 27) & 0x1fffffff); v += *dp++ << 19; v += *dp++ << 11;
+ v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 24) & 0x1fffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_30(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 28); *rp++ = (*p >> 20); *rp++ = (*p >> 12);
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 26); *rp++ = (*p >> 18); *rp++ = (*p >> 10);
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 22); *rp++ = (*p >> 14); *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 28); *rp++ = (*p >> 20); *rp++ = (*p >> 12);
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 26); *rp++ = (*p >> 18); *rp++ = (*p >> 10);
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8);
+ *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_30(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 22; v += *dp++ << 14; v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 28) & 0x3fffffff); v += *dp++ << 20; v += *dp++ << 12;
+ v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 26) & 0x3fffffff); v += *dp++ << 18; v += *dp++ << 10;
+ v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 24) & 0x3fffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ v = *dp++ << 22; v += *dp++ << 14; v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 28) & 0x3fffffff); v += *dp++ << 20; v += *dp++ << 12;
+ v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 26) & 0x3fffffff); v += *dp++ << 18; v += *dp++ << 10;
+ v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 24) & 0x3fffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_31(uint32_t *p, uint8_t *rp)
+{
+ uint8_t v;
+ *rp++ = (*p >> 23); *rp++ = (*p >> 15); *rp++ = (*p >> 7); v = *p++ << 1;
+ *rp++ = v + (*p >> 30); *rp++ = (*p >> 22); *rp++ = (*p >> 14);
+ *rp++ = (*p >> 6); v = *p++ << 2;
+ *rp++ = v + (*p >> 29); *rp++ = (*p >> 21); *rp++ = (*p >> 13);
+ *rp++ = (*p >> 5); v = *p++ << 3;
+ *rp++ = v + (*p >> 28); *rp++ = (*p >> 20); *rp++ = (*p >> 12);
+ *rp++ = (*p >> 4); v = *p++ << 4;
+ *rp++ = v + (*p >> 27); *rp++ = (*p >> 19); *rp++ = (*p >> 11);
+ *rp++ = (*p >> 3); v = *p++ << 5;
+ *rp++ = v + (*p >> 26); *rp++ = (*p >> 18); *rp++ = (*p >> 10);
+ *rp++ = (*p >> 2); v = *p++ << 6;
+ *rp++ = v + (*p >> 25); *rp++ = (*p >> 17); *rp++ = (*p >> 9);
+ *rp++ = (*p >> 1); v = *p++ << 7;
+ *rp++ = v + (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8);
+ *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_31(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 23; v += *dp++ << 15; v += *dp++ << 7; *p++ = v + (*dp >> 1);
+ v = ((*dp++ << 30) & 0x7fffffff); v += *dp++ << 22; v += *dp++ << 14;
+ v += *dp++ << 6; *p++ = v + (*dp >> 2);
+ v = ((*dp++ << 29) & 0x7fffffff); v += *dp++ << 21; v += *dp++ << 13;
+ v += *dp++ << 5; *p++ = v + (*dp >> 3);
+ v = ((*dp++ << 28) & 0x7fffffff); v += *dp++ << 20; v += *dp++ << 12;
+ v += *dp++ << 4; *p++ = v + (*dp >> 4);
+ v = ((*dp++ << 27) & 0x7fffffff); v += *dp++ << 19; v += *dp++ << 11;
+ v += *dp++ << 3; *p++ = v + (*dp >> 5);
+ v = ((*dp++ << 26) & 0x7fffffff); v += *dp++ << 18; v += *dp++ << 10;
+ v += *dp++ << 2; *p++ = v + (*dp >> 6);
+ v = ((*dp++ << 25) & 0x7fffffff); v += *dp++ << 17; v += *dp++ << 9;
+ v += *dp++ << 1; *p++ = v + (*dp >> 7);
+ v = ((*dp++ << 24) & 0x7fffffff); v += *dp++ << 16; v += *dp++ << 8;
+ *p++ = v + *dp++;
+ return dp;
+}
+static uint8_t *
+pack_32(uint32_t *p, uint8_t *rp)
+{
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ *rp++ = (*p >> 24); *rp++ = (*p >> 16); *rp++ = (*p >> 8); *rp++ = *p++;
+ return rp;
+}
+static uint8_t *
+unpack_32(uint32_t *p, uint8_t *dp)
+{
+ uint32_t v;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ v = *dp++ << 24; v += *dp++ << 16; v += *dp++ << 8; *p++ = v + *dp++;
+ return dp;
+}
+/* </generated> */
+
+static uint8_t *
+pack_(uint32_t *p, uint32_t i, int w, uint8_t *rp)
+{
+ while (i >= 8) {
+ switch (w) {
+ case 0 : break;
+ case 1 : rp = pack_1(p, rp); break;
+ case 2 : rp = pack_2(p, rp); break;
+ case 3 : rp = pack_3(p, rp); break;
+ case 4 : rp = pack_4(p, rp); break;
+ case 5 : rp = pack_5(p, rp); break;
+ case 6 : rp = pack_6(p, rp); break;
+ case 7 : rp = pack_7(p, rp); break;
+ case 8 : rp = pack_8(p, rp); break;
+ case 9 : rp = pack_9(p, rp); break;
+ case 10 : rp = pack_10(p, rp); break;
+ case 11 : rp = pack_11(p, rp); break;
+ case 12 : rp = pack_12(p, rp); break;
+ case 13 : rp = pack_13(p, rp); break;
+ case 14 : rp = pack_14(p, rp); break;
+ case 15 : rp = pack_15(p, rp); break;
+ case 16 : rp = pack_16(p, rp); break;
+ case 17 : rp = pack_17(p, rp); break;
+ case 18 : rp = pack_18(p, rp); break;
+ case 19 : rp = pack_19(p, rp); break;
+ case 20 : rp = pack_20(p, rp); break;
+ case 21 : rp = pack_21(p, rp); break;
+ case 22 : rp = pack_22(p, rp); break;
+ case 23 : rp = pack_23(p, rp); break;
+ case 24 : rp = pack_24(p, rp); break;
+ case 25 : rp = pack_25(p, rp); break;
+ case 26 : rp = pack_26(p, rp); break;
+ case 27 : rp = pack_27(p, rp); break;
+ case 28 : rp = pack_28(p, rp); break;
+ case 29 : rp = pack_29(p, rp); break;
+ case 30 : rp = pack_30(p, rp); break;
+ case 31 : rp = pack_31(p, rp); break;
+ case 32 : rp = pack_32(p, rp); break;
+ }
+ p += 8;
+ i -= 8;
+ }
+ {
+ int b;
+ uint8_t v;
+ uint32_t *pe = p + i;
+ for (b = 8 - w, v = 0; p < pe;) {
+ if (b > 0) {
+ v += *p++ << b;
+ b -= w;
+ } else if (b < 0) {
+ *rp++ = v + (*p >> -b);
+ b += 8;
+ v = 0;
+ } else {
+ *rp++ = v + *p++;
+ b = 8 - w;
+ v = 0;
+ }
+ }
+ if (b + w != 8) { *rp++ = v; }
+ return rp;
+ }
+}
+
+static uint8_t *
+pack(uint32_t *p, uint32_t i, uint8_t *freq, uint8_t *rp)
+{
+ int32_t k, w;
+ uint8_t ebuf[UNIT_SIZE], *ep = ebuf;
+ uint32_t s, *pe = p + i, r, th = i - (i >> 3);
+ for (w = 0, s = 0; w <= 32; w++) {
+ if ((s += freq[w]) >= th) { break; }
+ }
+ if (i == s) {
+ *rp++ = w;
+ return pack_(p, i, w, rp);
+ }
+ r = 1 << w;
+ *rp++ = w + 0x80;
+ *rp++ = i - s;
+ if (r >= UNIT_SIZE) {
+ uint32_t first, *last = &first;
+ for (k = 0; p < pe; p++, k++) {
+ if (*p >= r) {
+ GRN_B_ENC(*p - r, ep);
+ *last = k;
+ last = p;
+ }
+ }
+ *last = 0;
+ *rp++ = (uint8_t) first;
+ } else {
+ for (k = 0; p < pe; p++, k++) {
+ if (*p >= r) {
+ *ep++ = k;
+ GRN_B_ENC(*p - r, ep);
+ *p = 0;
+ }
+ }
+ }
+ rp = pack_(p - i, i, w, rp);
+ grn_memcpy(rp, ebuf, ep - ebuf);
+ return rp + (ep - ebuf);
+}
+
+int
+grn_p_enc(grn_ctx *ctx, uint32_t *data, uint32_t data_size, uint8_t **res)
+{
+ uint8_t *rp, freq[33];
+ uint32_t j, *dp, *dpe, d, w, buf[UNIT_SIZE];
+ *res = rp = GRN_MALLOC(data_size * sizeof(uint32_t) * 2);
+ GRN_B_ENC(data_size, rp);
+ memset(freq, 0, 33);
+ for (j = 0, dp = data, dpe = dp + data_size; dp < dpe; j++, dp++) {
+ if (j == UNIT_SIZE) {
+ rp = pack(buf, j, freq, rp);
+ memset(freq, 0, 33);
+ j = 0;
+ }
+ if ((d = buf[j] = *dp)) {
+ GRN_BIT_SCAN_REV(d, w);
+ freq[w + 1]++;
+ } else {
+ freq[0]++;
+ }
+ }
+ if (j) { rp = pack(buf, j, freq, rp); }
+ return rp - *res;
+}
+
+#define USE_P_ENC (1<<0) /* Use PForDelta */
+#define CUT_OFF (1<<1) /* Deprecated */
+#define ODD (1<<2) /* Variable size data */
+
+typedef struct {
+ uint32_t *data;
+ uint32_t data_size;
+ uint32_t flags;
+} datavec;
+
+static grn_rc
+datavec_reset(grn_ctx *ctx, datavec *dv, uint32_t dvlen,
+ size_t unitsize, size_t totalsize)
+{
+ uint32_t i;
+ if (!dv[0].data || dv[dvlen].data < dv[0].data + totalsize) {
+ if (dv[0].data) { GRN_FREE(dv[0].data); }
+ if (!(dv[0].data = GRN_MALLOC(totalsize * sizeof(uint32_t)))) {
+ MERR("[ii][data-vector][reset] failed to allocate data: "
+ "length:<%u>, "
+ "unit-size:<%" GRN_FMT_SIZE ">, "
+ "total-size:<%" GRN_FMT_SIZE ">",
+ dvlen,
+ unitsize,
+ totalsize);
+ return ctx->rc;
+ }
+ dv[dvlen].data = dv[0].data + totalsize;
+ }
+ for (i = 1; i < dvlen; i++) {
+ dv[i].data = dv[i - 1].data + unitsize;
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+datavec_init(grn_ctx *ctx, datavec *dv, uint32_t dvlen,
+ size_t unitsize, size_t totalsize)
+{
+ uint32_t i;
+ if (!totalsize) {
+ memset(dv, 0, sizeof(datavec) * (dvlen + 1));
+ return GRN_SUCCESS;
+ }
+ if (!(dv[0].data = GRN_MALLOC(totalsize * sizeof(uint32_t)))) {
+ MERR("[ii][data-vector][init] failed to allocate data: "
+ "length:<%u>, "
+ "unit-size:<%" GRN_FMT_SIZE ">, "
+ "total-size:<%" GRN_FMT_SIZE ">",
+ dvlen,
+ unitsize,
+ totalsize);
+ return ctx->rc;
+ }
+ dv[dvlen].data = dv[0].data + totalsize;
+ for (i = 1; i < dvlen; i++) {
+ dv[i].data = dv[i - 1].data + unitsize;
+ }
+ return GRN_SUCCESS;
+}
+
+static void
+datavec_fin(grn_ctx *ctx, datavec *dv)
+{
+ if (dv[0].data) { GRN_FREE(dv[0].data); }
+}
+
+size_t
+grn_p_encv(grn_ctx *ctx, datavec *dv, uint32_t dvlen, uint8_t *res)
+{
+ uint8_t *rp = res, freq[33];
+ uint32_t pgap, usep, l, df, data_size, *dp, *dpe;
+ if (!dvlen || !(df = dv[0].data_size)) { return 0; }
+ for (usep = 0, data_size = 0, l = 0; l < dvlen; l++) {
+ uint32_t dl = dv[l].data_size;
+ if (dl < df || ((dl > df) && (l != dvlen - 1))) {
+ /* invalid argument */
+ return 0;
+ }
+ usep += (dv[l].flags & USE_P_ENC) << l;
+ data_size += dl;
+ }
+ pgap = data_size - df * dvlen;
+ if (!usep) {
+ GRN_B_ENC((df << 1) + 1, rp);
+ for (l = 0; l < dvlen; l++) {
+ for (dp = dv[l].data, dpe = dp + dv[l].data_size; dp < dpe; dp++) {
+ GRN_B_ENC(*dp, rp);
+ }
+ }
+ } else {
+ uint32_t buf[UNIT_SIZE];
+ GRN_B_ENC((usep << 1), rp);
+ GRN_B_ENC(df, rp);
+ if (dv[dvlen - 1].flags & ODD) {
+ GRN_B_ENC(pgap, rp);
+ } else {
+ GRN_ASSERT(!pgap);
+ }
+ for (l = 0; l < dvlen; l++) {
+ dp = dv[l].data;
+ dpe = dp + dv[l].data_size;
+ if ((dv[l].flags & USE_P_ENC)) {
+ uint32_t j = 0, d;
+ memset(freq, 0, 33);
+ while (dp < dpe) {
+ if (j == UNIT_SIZE) {
+ rp = pack(buf, j, freq, rp);
+ memset(freq, 0, 33);
+ j = 0;
+ }
+ if ((d = buf[j++] = *dp++)) {
+ uint32_t w;
+ GRN_BIT_SCAN_REV(d, w);
+ freq[w + 1]++;
+ } else {
+ freq[0]++;
+ }
+ }
+ if (j) { rp = pack(buf, j, freq, rp); }
+ } else {
+ while (dp < dpe) { GRN_B_ENC(*dp++, rp); }
+ }
+ }
+ }
+ return rp - res;
+}
+
+#define GRN_B_DEC_CHECK(v,p,pe) do { \
+ uint8_t *_p = (uint8_t *)p; \
+ uint32_t _v; \
+ if (_p >= pe) { return 0; } \
+ _v = *_p++; \
+ switch (_v >> 4) { \
+ case 0x08 : \
+ if (_v == 0x8f) { \
+ if (_p + sizeof(uint32_t) > pe) { return 0; } \
+ grn_memcpy(&_v, _p, sizeof(uint32_t)); \
+ _p += sizeof(uint32_t); \
+ } \
+ break; \
+ case 0x09 : \
+ if (_p + 3 > pe) { return 0; } \
+ _v = (_v - 0x90) * 0x100 + *_p++; \
+ _v = _v * 0x100 + *_p++; \
+ _v = _v * 0x100 + *_p++ + 0x20408f; \
+ break; \
+ case 0x0a : \
+ case 0x0b : \
+ if (_p + 2 > pe) { return 0; } \
+ _v = (_v - 0xa0) * 0x100 + *_p++; \
+ _v = _v * 0x100 + *_p++ + 0x408f; \
+ break; \
+ case 0x0c : \
+ case 0x0d : \
+ case 0x0e : \
+ case 0x0f : \
+ if (_p + 1 > pe) { return 0; } \
+ _v = (_v - 0xc0) * 0x100 + *_p++ + 0x8f; \
+ break; \
+ } \
+ v = _v; \
+ p = _p; \
+} while (0)
+
+static uint8_t *
+unpack(uint8_t *dp, uint8_t *dpe, int i, uint32_t *rp)
+{
+ uint8_t ne = 0, k = 0, w = *dp++;
+ uint32_t m, *p = rp;
+ if (w & 0x80) {
+ ne = *dp++;
+ w -= 0x80;
+ m = (1 << w) - 1;
+ if (m >= UNIT_MASK) { k = *dp++; }
+ } else {
+ m = (1 << w) - 1;
+ }
+ if (w) {
+ while (i >= 8) {
+ if (dp + w > dpe) { return NULL; }
+ switch (w) {
+ case 1 : dp = unpack_1(p, dp); break;
+ case 2 : dp = unpack_2(p, dp); break;
+ case 3 : dp = unpack_3(p, dp); break;
+ case 4 : dp = unpack_4(p, dp); break;
+ case 5 : dp = unpack_5(p, dp); break;
+ case 6 : dp = unpack_6(p, dp); break;
+ case 7 : dp = unpack_7(p, dp); break;
+ case 8 : dp = unpack_8(p, dp); break;
+ case 9 : dp = unpack_9(p, dp); break;
+ case 10 : dp = unpack_10(p, dp); break;
+ case 11 : dp = unpack_11(p, dp); break;
+ case 12 : dp = unpack_12(p, dp); break;
+ case 13 : dp = unpack_13(p, dp); break;
+ case 14 : dp = unpack_14(p, dp); break;
+ case 15 : dp = unpack_15(p, dp); break;
+ case 16 : dp = unpack_16(p, dp); break;
+ case 17 : dp = unpack_17(p, dp); break;
+ case 18 : dp = unpack_18(p, dp); break;
+ case 19 : dp = unpack_19(p, dp); break;
+ case 20 : dp = unpack_20(p, dp); break;
+ case 21 : dp = unpack_21(p, dp); break;
+ case 22 : dp = unpack_22(p, dp); break;
+ case 23 : dp = unpack_23(p, dp); break;
+ case 24 : dp = unpack_24(p, dp); break;
+ case 25 : dp = unpack_25(p, dp); break;
+ case 26 : dp = unpack_26(p, dp); break;
+ case 27 : dp = unpack_27(p, dp); break;
+ case 28 : dp = unpack_28(p, dp); break;
+ case 29 : dp = unpack_29(p, dp); break;
+ case 30 : dp = unpack_30(p, dp); break;
+ case 31 : dp = unpack_31(p, dp); break;
+ case 32 : dp = unpack_32(p, dp); break;
+ }
+ i -= 8;
+ p += 8;
+ }
+ {
+ int b;
+ uint32_t v, *pe;
+ for (b = 8 - w, v = 0, pe = p + i; p < pe && dp < dpe;) {
+ if (b > 0) {
+ *p++ = v + ((*dp >> b) & m);
+ b -= w;
+ v = 0;
+ } else if (b < 0) {
+ v += (*dp++ << -b) & m;
+ b += 8;
+ } else {
+ *p++ = v + (*dp++ & m);
+ b = 8 - w;
+ v = 0;
+ }
+ }
+ if (b + w != 8) { dp++; }
+ }
+ } else {
+ memset(p, 0, sizeof(uint32_t) * i);
+ }
+ if (ne) {
+ if (m >= UNIT_MASK) {
+ uint32_t *pp;
+ while (ne--) {
+ pp = &rp[k];
+ k = *pp;
+ GRN_B_DEC_CHECK(*pp, dp, dpe);
+ *pp += (m + 1);
+ }
+ } else {
+ while (ne--) {
+ k = *dp++;
+ GRN_B_DEC_CHECK(rp[k], dp, dpe);
+ rp[k] += (m + 1);
+ }
+ }
+ }
+ return dp;
+}
+
+int
+grn_p_dec(grn_ctx *ctx, uint8_t *data, uint32_t data_size, uint32_t nreq, uint32_t **res)
+{
+ uint8_t *dp = data, *dpe = data + data_size;
+ uint32_t rest, orig_size, *rp, *rpe;
+ GRN_B_DEC(orig_size, dp);
+ if (!orig_size) {
+ if (!nreq || nreq > data_size) { nreq = data_size; }
+ if ((*res = rp = GRN_MALLOC(nreq * 4))) {
+ for (rpe = rp + nreq; dp < data + data_size && rp < rpe; rp++) {
+ GRN_B_DEC(*rp, dp);
+ }
+ }
+ return rp - *res;
+ } else {
+ if (!(*res = rp = GRN_MALLOC(orig_size * sizeof(uint32_t)))) {
+ return 0;
+ }
+ if (!nreq || nreq > orig_size) { nreq = orig_size; }
+ for (rest = nreq; rest >= UNIT_SIZE; rest -= UNIT_SIZE) {
+ if (!(dp = unpack(dp, dpe, UNIT_SIZE, rp))) { return 0; }
+ rp += UNIT_SIZE;
+ }
+ if (rest) { if (!(dp = unpack(dp, dpe, rest, rp))) { return 0; } }
+ GRN_ASSERT(data + data_size == dp);
+ return nreq;
+ }
+}
+
+int
+grn_p_decv(grn_ctx *ctx, uint8_t *data, uint32_t data_size, datavec *dv, uint32_t dvlen)
+{
+ size_t size;
+ uint32_t df, l, i, *rp, nreq;
+ uint8_t *dp = data, *dpe = data + data_size;
+ if (!data_size) {
+ dv[0].data_size = 0;
+ return 0;
+ }
+ for (nreq = 0; nreq < dvlen; nreq++) {
+ if (dv[nreq].flags & CUT_OFF) { break; }
+ }
+ if (!nreq) { return 0; }
+ GRN_B_DEC_CHECK(df, dp, dpe);
+ if ((df & 1)) {
+ df >>= 1;
+ size = nreq == dvlen ? data_size : df * nreq;
+ if (dv[dvlen].data < dv[0].data + size) {
+ if (dv[0].data) { GRN_FREE(dv[0].data); }
+ if (!(rp = GRN_MALLOC(size * sizeof(uint32_t)))) { return 0; }
+ dv[dvlen].data = rp + size;
+ } else {
+ rp = dv[0].data;
+ }
+ for (l = 0; l < dvlen; l++) {
+ if (dv[l].flags & CUT_OFF) { break; }
+ dv[l].data = rp;
+ if (l < dvlen - 1) {
+ for (i = 0; i < df; i++, rp++) { GRN_B_DEC_CHECK(*rp, dp, dpe); }
+ } else {
+ for (i = 0; dp < dpe; i++, rp++) { GRN_B_DEC_CHECK(*rp, dp, dpe); }
+ }
+ dv[l].data_size = i;
+ }
+ } else {
+ uint32_t n, rest, usep = df >> 1;
+ GRN_B_DEC_CHECK(df, dp, dpe);
+ if (dv[dvlen -1].flags & ODD) {
+ GRN_B_DEC_CHECK(rest, dp, dpe);
+ } else {
+ rest = 0;
+ }
+ size = df * nreq + (nreq == dvlen ? rest : 0);
+ if (dv[dvlen].data < dv[0].data + size) {
+ if (dv[0].data) { GRN_FREE(dv[0].data); }
+ if (!(rp = GRN_MALLOC(size * sizeof(uint32_t)))) { return 0; }
+ dv[dvlen].data = rp + size;
+ } else {
+ rp = dv[0].data;
+ }
+ for (l = 0; l < dvlen; l++) {
+ if (dv[l].flags & CUT_OFF) { break; }
+ dv[l].data = rp;
+ dv[l].data_size = n = (l < dvlen - 1) ? df : df + rest;
+ if (usep & (1 << l)) {
+ for (; n >= UNIT_SIZE; n -= UNIT_SIZE) {
+ if (!(dp = unpack(dp, dpe, UNIT_SIZE, rp))) { return 0; }
+ rp += UNIT_SIZE;
+ }
+ if (n) {
+ if (!(dp = unpack(dp, dpe, n, rp))) { return 0; }
+ rp += n;
+ }
+ dv[l].flags |= USE_P_ENC;
+ } else {
+ for (; n; n--, rp++) {
+ GRN_B_DEC_CHECK(*rp, dp, dpe);
+ }
+ }
+ }
+ GRN_ASSERT(dp == dpe);
+ if (dp != dpe) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "data_size=%d, %" GRN_FMT_LLD,
+ data_size, (long long int)(dpe - dp));
+ }
+ }
+ return rp - dv[0].data;
+}
+
+int
+grn_b_enc(grn_ctx *ctx, uint32_t *data, uint32_t data_size, uint8_t **res)
+{
+ uint8_t *rp;
+ uint32_t *dp, i;
+ *res = rp = GRN_MALLOC(data_size * sizeof(uint32_t) * 2);
+ GRN_B_ENC(data_size, rp);
+ for (i = data_size, dp = data; i; i--, dp++) {
+ GRN_B_ENC(*dp, rp);
+ }
+ return rp - *res;
+}
+
+int
+grn_b_dec(grn_ctx *ctx, uint8_t *data, uint32_t data_size, uint32_t **res)
+{
+ uint32_t i, *rp, orig_size;
+ uint8_t *dp = data;
+ GRN_B_DEC(orig_size, dp);
+ *res = rp = GRN_MALLOC(orig_size * sizeof(uint32_t));
+ for (i = orig_size; i; i--, rp++) {
+ GRN_B_DEC(*rp, dp);
+ }
+ return orig_size;
+}
+
+/* buffer */
+
+typedef struct {
+ uint32_t tid;
+ uint32_t size_in_chunk;
+ uint32_t pos_in_chunk;
+ uint16_t size_in_buffer;
+ uint16_t pos_in_buffer;
+} buffer_term;
+
+typedef struct {
+ uint16_t step;
+ uint16_t jump;
+} buffer_rec;
+
+typedef struct {
+ uint32_t chunk;
+ uint32_t chunk_size;
+ uint32_t buffer_free;
+ uint16_t nterms;
+ uint16_t nterms_void;
+} buffer_header;
+
+struct grn_ii_buffer {
+ buffer_header header;
+ buffer_term terms[(S_SEGMENT - sizeof(buffer_header))/sizeof(buffer_term)];
+};
+
+typedef struct grn_ii_buffer buffer;
+
+inline static uint32_t
+buffer_open(grn_ctx *ctx, grn_ii *ii, uint32_t pos, buffer_term **bt, buffer **b)
+{
+ byte *p = NULL;
+ uint16_t lseg = (uint16_t) (LSEG(pos));
+ uint32_t pseg = ii->header->binfo[lseg];
+ if (pseg != GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_IO_SEG_REF(ii->seg, pseg, p);
+ if (!p) { return GRN_II_PSEG_NOT_ASSIGNED; }
+ if (b) { *b = (buffer *)p; }
+ if (bt) { *bt = (buffer_term *)(p + LPOS(pos)); }
+ }
+ return pseg;
+}
+
+inline static grn_rc
+buffer_close(grn_ctx *ctx, grn_ii *ii, uint32_t pseg)
+{
+ if (pseg >= ii->seg->header->max_segment) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid pseg buffer_close(%d)", pseg);
+ return GRN_INVALID_ARGUMENT;
+ }
+ GRN_IO_SEG_UNREF(ii->seg, pseg);
+ return GRN_SUCCESS;
+}
+
+typedef struct {
+ uint32_t rid;
+ uint32_t sid;
+} docid;
+
+#define BUFFER_REC_DEL(r) ((r)->jump = 1)
+#define BUFFER_REC_DELETED(r) ((r)->jump == 1)
+
+#define BUFFER_REC_AT(b,pos) ((buffer_rec *)(b) + (pos))
+#define BUFFER_REC_POS(b,rec) ((uint16_t)((rec) - (buffer_rec *)(b)))
+
+inline static void
+buffer_term_dump(grn_ctx *ctx, grn_ii *ii, buffer *b, buffer_term *bt)
+{
+ int pos, rid, sid;
+ uint8_t *p;
+ buffer_rec *r;
+
+ if (!grn_logger_pass(ctx, GRN_LOG_DEBUG)) {
+ return;
+ }
+
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "b=(%x %u %u %u)", b->header.chunk, b->header.chunk_size,
+ b->header.buffer_free, b->header.nterms);
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "bt=(%u %u %u %u %u)", bt->tid, bt->size_in_chunk, bt->pos_in_chunk,
+ bt->size_in_buffer, bt->pos_in_buffer);
+ for (pos = bt->pos_in_buffer; pos; pos = r->step) {
+ r = BUFFER_REC_AT(b, pos);
+ p = GRN_NEXT_ADDR(r);
+ GRN_B_DEC(rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(sid, p);
+ } else {
+ sid = 1;
+ }
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "%d=(%d:%d),(%d:%d)", pos, r->jump, r->step, rid, sid);
+ }
+}
+
+inline static grn_rc
+check_jump(grn_ctx *ctx, grn_ii *ii, buffer *b, buffer_rec *r, int j)
+{
+ uint16_t i = BUFFER_REC_POS(b, r);
+ uint8_t *p;
+ buffer_rec *r2;
+ docid id, id2;
+ if (!j) { return GRN_SUCCESS; }
+ p = GRN_NEXT_ADDR(r);
+ GRN_B_DEC(id.rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(id.sid, p);
+ } else {
+ id.sid = 1;
+ }
+ if (j == 1) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "deleting! %d(%d:%d)", i, id.rid, id.sid);
+ return GRN_SUCCESS;
+ }
+ r2 = BUFFER_REC_AT(b, j);
+ p = GRN_NEXT_ADDR(r2);
+ GRN_B_DEC(id2.rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(id2.sid, p);
+ } else {
+ id2.sid = 1;
+ }
+ if (r2->step == i) {
+ GRN_LOG(ctx, GRN_LOG_EMERG, "cycle! %d(%d:%d)<->%d(%d:%d)",
+ i, id.rid, id.sid, j, id2.rid, id2.sid);
+ return GRN_FILE_CORRUPT;
+ }
+ if (id2.rid < id.rid || (id2.rid == id.rid && id2.sid <= id.sid)) {
+ GRN_LOG(ctx, GRN_LOG_CRIT,
+ "invalid jump! %d(%d:%d)(%d:%d)->%d(%d:%d)(%d:%d)",
+ i, r->jump, r->step, id.rid, id.sid, j, r2->jump, r2->step,
+ id2.rid, id2.sid);
+ return GRN_FILE_CORRUPT;
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+set_jump_r(grn_ctx *ctx, grn_ii *ii, buffer *b, buffer_rec *from, int to)
+{
+ int i, j, max_jump = 100;
+ buffer_rec *r, *r2;
+ for (r = from, j = to; j > 1 && max_jump--; r = BUFFER_REC_AT(b, r->step)) {
+ r2 = BUFFER_REC_AT(b, j);
+ if (r == r2) { break; }
+ if (BUFFER_REC_DELETED(r2)) { break; }
+ if (j == (i = r->jump)) { break; }
+ if (j == r->step) { break; }
+ if (check_jump(ctx, ii, b, r, j)) {
+ ERR(GRN_FILE_CORRUPT, "check_jump failed");
+ return ctx->rc;
+ }
+ r->jump = j;
+ j = i;
+ if (!r->step) { return GRN_FILE_CORRUPT; }
+ }
+ return GRN_SUCCESS;
+}
+
+#define GET_NUM_BITS(x,n) do {\
+ n = x;\
+ n = (n & 0x55555555) + ((n >> 1) & 0x55555555);\
+ n = (n & 0x33333333) + ((n >> 2) & 0x33333333);\
+ n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F);\
+ n = (n & 0x00FF00FF) + ((n >> 8) & 0x00FF00FF);\
+ n = (n & 0x0000FFFF) + ((n >>16) & 0x0000FFFF);\
+} while (0)
+
+inline static grn_rc
+buffer_put(grn_ctx *ctx, grn_ii *ii, buffer *b, buffer_term *bt,
+ buffer_rec *rnew, uint8_t *bs, grn_ii_updspec *u, int size)
+{
+ uint8_t *p;
+ docid id_curr = {0, 0}, id_start = {0, 0}, id_post = {0, 0};
+ buffer_rec *r_curr, *r_start = NULL;
+ uint16_t last = 0, *lastp = &bt->pos_in_buffer, pos = BUFFER_REC_POS(b, rnew);
+ int vdelta = 0, delta, delta0 = 0, vhops = 0, nhops = 0, reset = 1;
+ grn_memcpy(GRN_NEXT_ADDR(rnew), bs, size - sizeof(buffer_rec));
+ for (;;) {
+ if (!*lastp) {
+ rnew->step = 0;
+ rnew->jump = 0;
+ // smb_wmb();
+ *lastp = pos;
+ if (bt->size_in_buffer++ > 1) {
+ buffer_rec *rhead = BUFFER_REC_AT(b, bt->pos_in_buffer);
+ rhead->jump = pos;
+ if (!(bt->size_in_buffer & 1)) {
+ int n;
+ buffer_rec *r = BUFFER_REC_AT(b, rhead->step), *r2;
+ GET_NUM_BITS(bt->size_in_buffer, n);
+ while (n-- && (r->jump > 1)) {
+ r2 = BUFFER_REC_AT(b, r->jump);
+ if (BUFFER_REC_DELETED(r2)) { break; }
+ r = r2;
+ }
+ if (r != rnew) { set_jump_r(ctx, ii, b, r, last); }
+ }
+ }
+ break;
+ }
+ r_curr = BUFFER_REC_AT(b, *lastp);
+ p = GRN_NEXT_ADDR(r_curr);
+ GRN_B_DEC(id_curr.rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(id_curr.sid, p);
+ } else {
+ id_curr.sid = 1;
+ }
+ if (id_curr.rid < id_post.rid ||
+ (id_curr.rid == id_post.rid && id_curr.sid < id_post.sid)) {
+ {
+ DEFINE_NAME(ii);
+ CRIT(GRN_FILE_CORRUPT,
+ "[ii][buffer][put] loop is found: "
+ "<%.*s>: "
+ "(%d:%d)->(%d:%d)",
+ name_size, name,
+ id_post.rid, id_post.sid, id_curr.rid, id_curr.sid);
+ }
+ buffer_term_dump(ctx, ii, b, bt);
+ bt->pos_in_buffer = 0;
+ bt->size_in_buffer = 0;
+ lastp = &bt->pos_in_buffer;
+ continue;
+ }
+ id_post.rid = id_curr.rid;
+ id_post.sid = id_curr.sid;
+ if (u->rid < id_curr.rid || (u->rid == id_curr.rid && u->sid <= id_curr.sid)) {
+ uint16_t step = *lastp, jump = r_curr->jump;
+ if (u->rid == id_curr.rid) {
+ if (u->sid == 0) {
+ while (id_curr.rid == u->rid) {
+ BUFFER_REC_DEL(r_curr);
+ if (!(step = r_curr->step)) { break; }
+ r_curr = BUFFER_REC_AT(b, step);
+ p = GRN_NEXT_ADDR(r_curr);
+ GRN_B_DEC(id_curr.rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(id_curr.sid, p);
+ } else {
+ id_curr.sid = 1;
+ }
+ }
+ } else if (u->sid == id_curr.sid) {
+ BUFFER_REC_DEL(r_curr);
+ step = r_curr->step;
+ }
+ }
+ rnew->step = step;
+ rnew->jump = check_jump(ctx, ii, b, rnew, jump) ? 0 : jump;
+ // smb_wmb();
+ *lastp = pos;
+ break;
+ }
+
+ if (reset) {
+ r_start = r_curr;
+ id_start.rid = id_curr.rid;
+ id_start.sid = id_curr.sid;
+ if (!(delta0 = u->rid - id_start.rid)) { delta0 = u->sid - id_start.sid; }
+ nhops = 0;
+ vhops = 1;
+ vdelta = delta0 >> 1;
+ } else {
+ if (!(delta = id_curr.rid - id_start.rid)) {
+ delta = id_curr.sid - id_start.sid;
+ }
+ if (vdelta < delta) {
+ vdelta += (delta0 >> ++vhops);
+ r_start = r_curr;
+ }
+ if (nhops > vhops) {
+ set_jump_r(ctx, ii, b, r_start, *lastp);
+ } else {
+ nhops++;
+ }
+ }
+
+ last = *lastp;
+ lastp = &r_curr->step;
+ reset = 0;
+ {
+ uint16_t posj = r_curr->jump;
+ if (posj > 1) {
+ buffer_rec *rj = BUFFER_REC_AT(b, posj);
+ if (!BUFFER_REC_DELETED(rj)) {
+ docid idj;
+ p = GRN_NEXT_ADDR(rj);
+ GRN_B_DEC(idj.rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(idj.sid, p);
+ } else {
+ idj.sid = 1;
+ }
+ if (idj.rid < u->rid || (idj.rid == u->rid && idj.sid < u->sid)) {
+ last = posj;
+ lastp = &rj->step;
+ } else {
+ reset = 1;
+ }
+ }
+ }
+ }
+ }
+ return ctx->rc;
+}
+
+/* array */
+
+inline static uint32_t *
+array_at(grn_ctx *ctx, grn_ii *ii, uint32_t id)
+{
+ byte *p = NULL;
+ uint32_t seg, pseg;
+ if (id > GRN_ID_MAX) { return NULL; }
+ seg = id >> W_ARRAY;
+ if ((pseg = ii->header->ainfo[seg]) == GRN_II_PSEG_NOT_ASSIGNED) {
+ return NULL;
+ }
+ GRN_IO_SEG_REF(ii->seg, pseg, p);
+ if (!p) { return NULL; }
+ return (uint32_t *)(p + (id & ARRAY_MASK_IN_A_SEGMENT) * S_ARRAY_ELEMENT);
+}
+
+inline static uint32_t *
+array_get(grn_ctx *ctx, grn_ii *ii, uint32_t id)
+{
+ byte *p = NULL;
+ uint16_t seg;
+ uint32_t pseg;
+ if (id > GRN_ID_MAX) { return NULL; }
+ seg = id >> W_ARRAY;
+ if ((pseg = ii->header->ainfo[seg]) == GRN_II_PSEG_NOT_ASSIGNED) {
+ if (segment_get_clear(ctx, ii, &pseg)) { return NULL; }
+ ii->header->ainfo[seg] = pseg;
+ if (seg >= ii->header->amax) { ii->header->amax = seg + 1; }
+ }
+ GRN_IO_SEG_REF(ii->seg, pseg, p);
+ if (!p) { return NULL; }
+ return (uint32_t *)(p + (id & ARRAY_MASK_IN_A_SEGMENT) * S_ARRAY_ELEMENT);
+}
+
+inline static void
+array_unref(grn_ii *ii, uint32_t id)
+{
+ GRN_IO_SEG_UNREF(ii->seg, ii->header->ainfo[id >> W_ARRAY]);
+}
+
+/* updspec */
+
+grn_ii_updspec *
+grn_ii_updspec_open(grn_ctx *ctx, uint32_t rid, uint32_t sid)
+{
+ grn_ii_updspec *u;
+ if (!(u = GRN_MALLOC(sizeof(grn_ii_updspec)))) { return NULL; }
+ u->rid = rid;
+ u->sid = sid;
+ u->weight = 0;
+ u->tf = 0;
+ u->atf = 0;
+ u->pos = NULL;
+ u->tail = NULL;
+ // u->vnodes = NULL;
+ return u;
+}
+
+#define GRN_II_MAX_TF 0x1ffff
+
+grn_rc
+grn_ii_updspec_add(grn_ctx *ctx, grn_ii_updspec *u, int pos, int32_t weight)
+{
+ struct _grn_ii_pos *p;
+ u->atf++;
+ if (u->tf >= GRN_II_MAX_TF) { return GRN_SUCCESS; }
+ if (!(p = GRN_MALLOC(sizeof(struct _grn_ii_pos)))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ u->weight += weight;
+ p->pos = pos;
+ p->next = NULL;
+ if (u->tail) {
+ u->tail->next = p;
+ } else {
+ u->pos = p;
+ }
+ u->tail = p;
+ u->tf++;
+ return GRN_SUCCESS;
+}
+
+int
+grn_ii_updspec_cmp(grn_ii_updspec *a, grn_ii_updspec *b)
+{
+ struct _grn_ii_pos *pa, *pb;
+ if (a->rid != b->rid) { return a->rid - b->rid; }
+ if (a->sid != b->sid) { return a->sid - b->sid; }
+ if (a->weight != b->weight) { return a->weight - b->weight; }
+ if (a->tf != b->tf) { return a->tf - b->tf; }
+ for (pa = a->pos, pb = b->pos; pa && pb; pa = pa->next, pb = pb->next) {
+ if (pa->pos != pb->pos) { return pa->pos - pb->pos; }
+ }
+ if (pa) { return 1; }
+ if (pb) { return -1; }
+ return 0;
+}
+
+grn_rc
+grn_ii_updspec_close(grn_ctx *ctx, grn_ii_updspec *u)
+{
+ struct _grn_ii_pos *p = u->pos, *q;
+ while (p) {
+ q = p->next;
+ GRN_FREE(p);
+ p = q;
+ }
+ GRN_FREE(u);
+ return GRN_SUCCESS;
+}
+
+inline static uint8_t *
+encode_rec(grn_ctx *ctx, grn_ii *ii, grn_ii_updspec *u, unsigned int *size, int deletep)
+{
+ uint8_t *br, *p;
+ struct _grn_ii_pos *pp;
+ uint32_t lpos, tf, weight;
+ if (deletep) {
+ tf = 0;
+ weight = 0;
+ } else {
+ tf = u->tf;
+ weight = u->weight;
+ }
+ if (!(br = GRN_MALLOC((tf + 4) * 5))) {
+ return NULL;
+ }
+ p = br;
+ GRN_B_ENC(u->rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_ENC(u->sid, p);
+ } else {
+ u->sid = 1;
+ }
+ GRN_B_ENC(tf, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { GRN_B_ENC(weight, p); }
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ for (lpos = 0, pp = u->pos; pp && tf--; lpos = pp->pos, pp = pp->next) {
+ GRN_B_ENC(pp->pos - lpos, p);
+ }
+ }
+ while (((intptr_t)p & 0x03)) { *p++ = 0; }
+ *size = (unsigned int) ((p - br) + sizeof(buffer_rec));
+ return br;
+}
+
+typedef struct {
+ grn_ii *ii;
+ grn_hash *h;
+} lexicon_deletable_arg;
+
+#ifdef CASCADE_DELETE_LEXICON
+static int
+lexicon_deletable(grn_ctx *ctx, grn_obj *lexicon, grn_id tid, void *arg)
+{
+ uint32_t *a;
+ grn_hash *h = ((lexicon_deletable_arg *)arg)->h;
+ grn_ii *ii = ((lexicon_deletable_arg *)arg)->ii;
+ if (!h) { return 0; }
+ if ((a = array_at(ctx, ii, tid))) {
+ if (a[0]) {
+ array_unref(ii, tid);
+ return 0;
+ }
+ array_unref(ii, tid);
+ }
+ {
+ grn_ii_updspec **u;
+ if (!grn_hash_get(ctx, h, &tid, sizeof(grn_id), (void **) &u)) {
+ return (ERRP(ctx, GRN_ERROR)) ? 0 : 1;
+ }
+ if (!(*u)->tf || !(*u)->sid) { return 1; }
+ return 0;
+ }
+}
+#endif /* CASCADE_DELETE_LEXICON */
+
+inline static void
+lexicon_delete(grn_ctx *ctx, grn_ii *ii, uint32_t tid, grn_hash *h)
+{
+#ifdef CASCADE_DELETE_LEXICON
+ lexicon_deletable_arg arg = {ii, h};
+ grn_table_delete_optarg optarg = {0, lexicon_deletable, &arg};
+ _grn_table_delete_by_id(ctx, ii->lexicon, tid, &optarg);
+#endif /* CASCADE_DELETE_LEXICON */
+}
+
+typedef struct {
+ grn_id rid;
+ uint32_t sid;
+ uint32_t tf;
+ uint32_t weight;
+ uint32_t flags;
+} docinfo;
+
+#define GETNEXTC() do {\
+ if (sdf) {\
+ uint32_t dgap = *srp++;\
+ cid.rid += dgap;\
+ if (dgap) { cid.sid = 0; }\
+ snp += cid.tf;\
+ cid.tf = 1 + *stp++;\
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { cid.weight = *sop++; }\
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {\
+ cid.sid += 1 + *ssp++;\
+ } else {\
+ cid.sid = 1;\
+ }\
+ sdf--;\
+ } else {\
+ cid.rid = 0;\
+ }\
+} while (0)
+
+#define PUTNEXT_(id) do {\
+ uint32_t dgap = id.rid - lid.rid;\
+ uint32_t sgap = (dgap ? id.sid : id.sid - lid.sid) - 1;\
+ *ridp++ = dgap;\
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {\
+ *sidp++ = sgap;\
+ }\
+ *tfp++ = id.tf - 1;\
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { *weightp++ = id.weight; }\
+ lid.rid = id.rid;\
+ lid.sid = id.sid;\
+} while (0)
+
+#define PUTNEXTC() do {\
+ if (cid.rid) {\
+ if (cid.tf) {\
+ if (lid.rid > cid.rid || (lid.rid == cid.rid && lid.sid >= cid.sid)) {\
+ DEFINE_NAME(ii);\
+ CRIT(GRN_FILE_CORRUPT,\
+ "[ii][broken] posting in list is larger than posting in chunk: "\
+ "<%.*s>: (%d:%d) -> (%d:%d)",\
+ name_size, name, lid.rid, lid.sid, cid.rid, cid.sid);\
+ break;\
+ }\
+ PUTNEXT_(cid);\
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {\
+ uint32_t i;\
+ for (i = 0; i < cid.tf; i++) {\
+ *posp++ = snp[i];\
+ spos += snp[i];\
+ }\
+ }\
+ } else {\
+ DEFINE_NAME(ii);\
+ CRIT(GRN_FILE_CORRUPT,\
+ "[ii][broken] invalid posting in chunk: <%.*s>: (%d,%d)",\
+ name_size, name, bt->tid, cid.rid);\
+ break;\
+ }\
+ }\
+ GETNEXTC();\
+} while (0)
+
+#define GETNEXTB() do {\
+ if (nextb) {\
+ uint32_t lrid = bid.rid, lsid = bid.sid;\
+ buffer_rec *br = BUFFER_REC_AT(sb, nextb);\
+ sbp = GRN_NEXT_ADDR(br);\
+ GRN_B_DEC(bid.rid, sbp);\
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {\
+ GRN_B_DEC(bid.sid, sbp);\
+ } else {\
+ bid.sid = 1;\
+ }\
+ if (lrid > bid.rid || (lrid == bid.rid && lsid >= bid.sid)) {\
+ DEFINE_NAME(ii);\
+ CRIT(GRN_FILE_CORRUPT,\
+ "[ii][broken] postings in block aren't sorted: "\
+ "<%.*s>: (%d:%d) -> (%d:%d)",\
+ name_size, name, lrid, lsid, bid.rid, bid.sid);\
+ break;\
+ }\
+ nextb = br->step;\
+ } else {\
+ bid.rid = 0;\
+ }\
+} while (0)
+
+#define PUTNEXTB() do {\
+ if (bid.rid && bid.sid) {\
+ GRN_B_DEC(bid.tf, sbp);\
+ if (bid.tf > 0) {\
+ if (lid.rid > bid.rid || (lid.rid == bid.rid && lid.sid >= bid.sid)) {\
+ DEFINE_NAME(ii);\
+ CRIT(GRN_FILE_CORRUPT,\
+ "[ii][broken] posting in list is larger than posting in buffer: "\
+ "<%.*s>: (%d:%d) -> (%d:%d)",\
+ name_size, name, lid.rid, lid.sid, bid.rid, bid.sid);\
+ break;\
+ }\
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {\
+ GRN_B_DEC(bid.weight, sbp);\
+ }\
+ PUTNEXT_(bid);\
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {\
+ while (bid.tf--) { GRN_B_DEC(*posp, sbp); spos += *posp++; }\
+ }\
+ }\
+ }\
+ GETNEXTB();\
+} while (0)
+
+#define MERGE_BC(cond) do {\
+ if (bid.rid) {\
+ if (cid.rid) {\
+ if (cid.rid < bid.rid) {\
+ PUTNEXTC();\
+ if (ctx->rc != GRN_SUCCESS) { break; }\
+ } else {\
+ if (bid.rid < cid.rid) {\
+ PUTNEXTB();\
+ if (ctx->rc != GRN_SUCCESS) { break; }\
+ } else {\
+ if (bid.sid) {\
+ if (cid.sid < bid.sid) {\
+ PUTNEXTC();\
+ if (ctx->rc != GRN_SUCCESS) { break; }\
+ } else {\
+ if (bid.sid == cid.sid) { GETNEXTC(); }\
+ PUTNEXTB();\
+ if (ctx->rc != GRN_SUCCESS) { break; }\
+ }\
+ } else {\
+ GETNEXTC();\
+ }\
+ }\
+ }\
+ } else {\
+ PUTNEXTB();\
+ if (ctx->rc != GRN_SUCCESS) { break; }\
+ }\
+ } else {\
+ if (cid.rid) {\
+ PUTNEXTC();\
+ if (ctx->rc != GRN_SUCCESS) { break; }\
+ } else {\
+ break;\
+ }\
+ }\
+} while (cond)
+
+typedef struct {
+ uint32_t segno;
+ uint32_t size;
+ uint32_t dgap;
+} chunk_info;
+
+static grn_rc
+chunk_flush(grn_ctx *ctx, grn_ii *ii, chunk_info *cinfo, uint8_t *enc, uint32_t encsize)
+{
+ uint8_t *dc;
+ uint32_t dcn;
+ grn_io_win dw;
+ if (encsize) {
+ chunk_new(ctx, ii, &dcn, encsize);
+ if (ctx->rc == GRN_SUCCESS) {
+ if ((dc = WIN_MAP(ii->chunk, ctx, &dw, dcn, 0, encsize, grn_io_wronly))) {
+ grn_memcpy(dc, enc, encsize);
+ grn_io_win_unmap(&dw);
+ cinfo->segno = dcn;
+ cinfo->size = encsize;
+ } else {
+ chunk_free(ctx, ii, dcn, 0, encsize);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][chunk][flush] failed to allocate a destination chunk: "
+ "<%.*s> :"
+ "segment:<%u>, size:<%u>",
+ name_size, name,
+ dcn, encsize);
+ }
+ }
+ }
+ } else {
+ cinfo->segno = 0;
+ cinfo->size = 0;
+ }
+ return ctx->rc;
+}
+
+static grn_rc
+chunk_merge(grn_ctx *ctx, grn_ii *ii, buffer *sb, buffer_term *bt,
+ chunk_info *cinfo, grn_id rid, datavec *dv,
+ uint16_t *nextbp, uint8_t **sbpp, docinfo *bidp, int32_t *balance)
+{
+ grn_io_win sw;
+ uint64_t spos = 0;
+ uint32_t segno = cinfo->segno, size = cinfo->size, sdf = 0, ndf = 0;
+ uint32_t *ridp = NULL, *sidp = NULL, *tfp, *weightp = NULL, *posp = NULL;
+ docinfo cid = {0, 0, 0, 0, 0}, lid = {0, 0, 0, 0, 0}, bid = *bidp;
+ uint8_t *scp = WIN_MAP(ii->chunk, ctx, &sw, segno, 0, size, grn_io_rdonly);
+
+ if (scp) {
+ uint16_t nextb = *nextbp;
+ uint32_t snn = 0, *srp, *ssp = NULL, *stp, *sop = NULL, *snp;
+ uint8_t *sbp = *sbpp;
+ datavec rdv[MAX_N_ELEMENTS + 1];
+ size_t bufsize = S_SEGMENT * ii->n_elements;
+ datavec_init(ctx, rdv, ii->n_elements, 0, 0);
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ rdv[ii->n_elements - 1].flags = ODD;
+ }
+ bufsize += grn_p_decv(ctx, scp, cinfo->size, rdv, ii->n_elements);
+ // (df in chunk list) = a[1] - sdf;
+ {
+ int j = 0;
+ sdf = rdv[j].data_size;
+ srp = rdv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { ssp = rdv[j++].data; }
+ stp = rdv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { sop = rdv[j++].data; }
+ snn = rdv[j].data_size;
+ snp = rdv[j].data;
+ }
+ datavec_reset(ctx, dv, ii->n_elements, sdf + S_SEGMENT, bufsize);
+ if (ctx->rc == GRN_SUCCESS) {
+ {
+ int j = 0;
+ ridp = dv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { sidp = dv[j++].data; }
+ tfp = dv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { weightp = dv[j++].data; }
+ posp = dv[j].data;
+ }
+ GETNEXTC();
+ MERGE_BC(bid.rid <= rid || cid.rid);
+ if (ctx->rc == GRN_SUCCESS) {
+ *sbpp = sbp;
+ *nextbp = nextb;
+ *bidp = bid;
+ GRN_ASSERT(posp < dv[ii->n_elements].data);
+ ndf = ridp - dv[0].data;
+ }
+ }
+ datavec_fin(ctx, rdv);
+ grn_io_win_unmap(&sw);
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][chunk][merge] failed to allocate a source chunk: "
+ "<%.*s> :"
+ "record:<%u>, segment:<%u>, size:<%u>",
+ name_size, name,
+ rid,
+ segno,
+ size);
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ int j = 0;
+ uint8_t *enc;
+ uint32_t encsize;
+ uint32_t np = posp - dv[ii->n_elements - 1].data;
+ uint32_t f_s = (ndf < 3) ? 0 : USE_P_ENC;
+ uint32_t f_d = ((ndf < 16) || (ndf <= (lid.rid >> 8))) ? 0 : USE_P_ENC;
+ dv[j].data_size = ndf; dv[j++].flags = f_d;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ dv[j].data_size = ndf; dv[j++].flags = f_s;
+ }
+ dv[j].data_size = ndf; dv[j++].flags = f_s;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ dv[j].data_size = ndf; dv[j++].flags = f_s;
+ }
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ uint32_t f_p = ((np < 32) || (np <= (spos >> 13))) ? 0 : USE_P_ENC;
+ dv[j].data_size = np; dv[j].flags = f_p|ODD;
+ }
+ if ((enc = GRN_MALLOC((ndf * 4 + np) * 2))) {
+ encsize = grn_p_encv(ctx, dv, ii->n_elements, enc);
+ chunk_flush(ctx, ii, cinfo, enc, encsize);
+ if (ctx->rc == GRN_SUCCESS) {
+ chunk_free(ctx, ii, segno, 0, size);
+ }
+ GRN_FREE(enc);
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][chunk][merge] failed to allocate a encode buffer: "
+ "<%.*s> :"
+ "record:<%u>, segment:<%u>, size:<%u>",
+ name_size, name,
+ rid,
+ segno,
+ size);
+ }
+ }
+ *balance += (ndf - sdf);
+ return ctx->rc;
+}
+
+static void
+buffer_merge_dump_datavec(grn_ctx *ctx,
+ grn_ii *ii,
+ datavec *dv,
+ datavec *rdv)
+{
+ int i, j;
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ for (i = 0; (uint) i < ii->n_elements; i++) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "rdv[%d] data_size=%d, flags=%d",
+ i, rdv[i].data_size, rdv[i].flags);
+ GRN_BULK_REWIND(&buffer);
+ for (j = 0; (uint) j < rdv[i].data_size;) {
+ grn_text_printf(ctx, &buffer, " %d", rdv[i].data[j]);
+ j++;
+ if (!(j % 32) || (uint) j == rdv[i].data_size) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "rdv[%d].data[%d]%.*s",
+ i, j,
+ (int)GRN_TEXT_LEN(&buffer),
+ GRN_TEXT_VALUE(&buffer));
+ GRN_BULK_REWIND(&buffer);
+ }
+ }
+ }
+
+ for (i = 0; (uint) i < ii->n_elements; i++) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "dv[%d] data_size=%d, flags=%d",
+ i, dv[i].data_size, dv[i].flags);
+ GRN_BULK_REWIND(&buffer);
+ for (j = 0; (uint) j < dv[i].data_size;) {
+ grn_text_printf(ctx, &buffer, " %d", dv[i].data[j]);
+ j++;
+ if (!(j % 32) || (uint) j == dv[i].data_size) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "dv[%d].data[%d]%.*s",
+ i, j,
+ (int)GRN_TEXT_LEN(&buffer),
+ GRN_TEXT_VALUE(&buffer));
+ GRN_BULK_REWIND(&buffer);
+ }
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &buffer);
+}
+
+/* If dc doesn't have enough space, program may be crashed.
+ * TODO: Support auto space extension or max size check.
+ */
+static grn_rc
+buffer_merge(grn_ctx *ctx, grn_ii *ii, uint32_t seg, grn_hash *h,
+ buffer *sb, uint8_t *sc, buffer *db, uint8_t *dc)
+{
+ buffer_term *bt;
+ uint8_t *sbp = NULL, *dcp = dc;
+ datavec dv[MAX_N_ELEMENTS + 1];
+ datavec rdv[MAX_N_ELEMENTS + 1];
+ uint16_t n = db->header.nterms, nterms_void = 0;
+ size_t unitsize = (S_SEGMENT + sb->header.chunk_size / sb->header.nterms) * 2;
+ // size_t unitsize = (S_SEGMENT + sb->header.chunk_size) * 2 + (1<<24);
+ size_t totalsize = unitsize * ii->n_elements;
+ //todo : realloc
+ datavec_init(ctx, dv, ii->n_elements, unitsize, totalsize);
+ if (ctx->rc != GRN_SUCCESS) {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][buffer][merge] failed to initialize data vector: "
+ "<%.*s>: "
+ "unit-size:<%" GRN_FMT_SIZE ">, "
+ "total-size:<%" GRN_FMT_SIZE ">",
+ name_size, name,
+ unitsize,
+ totalsize);
+ return ctx->rc;
+ }
+ datavec_init(ctx, rdv, ii->n_elements, 0, 0);
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ rdv[ii->n_elements - 1].flags = ODD;
+ }
+ for (bt = db->terms; n; n--, bt++) {
+ uint16_t nextb;
+ uint64_t spos = 0;
+ int32_t balance = 0;
+ uint32_t *ridp, *sidp = NULL, *tfp, *weightp = NULL, *posp, nchunks = 0;
+ uint32_t nvchunks = 0;
+ chunk_info *cinfo = NULL;
+ grn_id crid = GRN_ID_NIL;
+ docinfo cid = {0, 0, 0, 0, 0}, lid = {0, 0, 0, 0, 0}, bid = {0, 0, 0, 0, 0};
+ uint32_t sdf = 0, snn = 0, ndf;
+ uint32_t *srp = NULL, *ssp = NULL, *stp = NULL, *sop = NULL, *snp = NULL;
+ if (!bt->tid) {
+ nterms_void++;
+ continue;
+ }
+ if (!bt->pos_in_buffer) {
+ GRN_ASSERT(!bt->size_in_buffer);
+ if (bt->size_in_chunk) {
+ grn_memcpy(dcp, sc + bt->pos_in_chunk, bt->size_in_chunk);
+ bt->pos_in_chunk = (uint32_t)(dcp - dc);
+ dcp += bt->size_in_chunk;
+ }
+ continue;
+ }
+ nextb = bt->pos_in_buffer;
+ GETNEXTB();
+ if (sc && bt->size_in_chunk) {
+ uint8_t *scp = sc + bt->pos_in_chunk;
+ uint8_t *sce = scp + bt->size_in_chunk;
+ size_t size = S_SEGMENT * ii->n_elements;
+ if ((bt->tid & CHUNK_SPLIT)) {
+ int i;
+ GRN_B_DEC(nchunks, scp);
+ if (!(cinfo = GRN_MALLOCN(chunk_info, nchunks + 1))) {
+ datavec_fin(ctx, dv);
+ datavec_fin(ctx, rdv);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][merge] failed to allocate chunk info: "
+ "<%.*s> :"
+ "segment:<%u>, "
+ "n-chunks:<%u>, "
+ "unit-size:<%" GRN_FMT_SIZE ">, "
+ "total-size:<%" GRN_FMT_SIZE ">",
+ name_size, name,
+ seg,
+ nchunks,
+ unitsize,
+ totalsize);
+ }
+ return ctx->rc;
+ }
+ for (i = 0; (uint) i < nchunks; i++) {
+ GRN_B_DEC(cinfo[i].segno, scp);
+ GRN_B_DEC(cinfo[i].size, scp);
+ GRN_B_DEC(cinfo[i].dgap, scp);
+ crid += cinfo[i].dgap;
+ if (bid.rid <= crid) {
+ chunk_merge(ctx, ii, sb, bt, &cinfo[i], crid, dv,
+ &nextb, &sbp, &bid, &balance);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (cinfo) { GRN_FREE(cinfo); }
+ datavec_fin(ctx, dv);
+ datavec_fin(ctx, rdv);
+ {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][buffer][merge] failed to merge chunk: "
+ "<%.*s>: "
+ "chunk:<%u>, "
+ "n-chunks:<%u>",
+ name_size, name,
+ i,
+ nchunks);
+ }
+ return ctx->rc;
+ }
+ }
+ if (cinfo[i].size) {
+ nvchunks++;
+ } else {
+ crid -= cinfo[i].dgap;
+ cinfo[i + 1].dgap += cinfo[i].dgap;
+ }
+ }
+ }
+ if (sce > scp) {
+ size += grn_p_decv(ctx, scp, sce - scp, rdv, ii->n_elements);
+ {
+ int j = 0;
+ sdf = rdv[j].data_size;
+ srp = rdv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { ssp = rdv[j++].data; }
+ stp = rdv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { sop = rdv[j++].data; }
+ snn = rdv[j].data_size;
+ snp = rdv[j].data;
+ }
+ datavec_reset(ctx, dv, ii->n_elements, sdf + S_SEGMENT, size);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (cinfo) { GRN_FREE(cinfo); }
+ datavec_fin(ctx, dv);
+ datavec_fin(ctx, rdv);
+ {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][buffer][merge] failed to reset data vector: "
+ "<%.*s>: "
+ "unit-size:<%" GRN_FMT_SIZE ">, "
+ "total-size:<%" GRN_FMT_SIZE ">",
+ name_size, name,
+ (size_t)(sdf + S_SEGMENT),
+ size);
+ }
+ return ctx->rc;
+ }
+ }
+ }
+ {
+ int j = 0;
+ ridp = dv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { sidp = dv[j++].data; }
+ tfp = dv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { weightp = dv[j++].data; }
+ posp = dv[j].data;
+ }
+ GETNEXTC();
+ MERGE_BC(1);
+ if (ctx->rc != GRN_SUCCESS) {
+ if (cinfo) { GRN_FREE(cinfo); }
+ datavec_fin(ctx, dv);
+ datavec_fin(ctx, rdv);
+ {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][buffer][merge] failed to merge chunk: <%.*s>",
+ name_size, name);
+ }
+ return ctx->rc;
+ }
+ GRN_ASSERT(posp < dv[ii->n_elements].data);
+ ndf = ridp - dv[0].data;
+ /*
+ {
+ grn_obj buf;
+ uint32_t rid, sid, tf, i, pos, *pp;
+ GRN_TEXT_INIT(&buf, 0);
+ rid = 0;
+ pp = dv[3].data;
+ for (i = 0; i < ndf; i++) {
+ GRN_BULK_REWIND(&buf);
+ rid += dv[0].data[i];
+ if (dv[0].data[i]) { sid = 0; }
+ sid += dv[1].data[i] + 1;
+ tf = dv[2].data[i] + 1;
+ pos = 0;
+ grn_text_itoa(ctx, &buf, rid);
+ GRN_TEXT_PUTC(ctx, &buf, ':');
+ grn_text_itoa(ctx, &buf, sid);
+ GRN_TEXT_PUTC(ctx, &buf, ':');
+ grn_text_itoa(ctx, &buf, tf);
+ GRN_TEXT_PUTC(ctx, &buf, ':');
+ while (tf--) {
+ pos += *pp++;
+ grn_text_itoa(ctx, &buf, pos);
+ if (tf) { GRN_TEXT_PUTC(ctx, &buf, ','); }
+ }
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "Posting:%s", GRN_TEXT_VALUE(&buf));
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ */
+ {
+ grn_id tid = bt->tid & GRN_ID_MAX;
+ uint32_t *a = array_at(ctx, ii, tid);
+ if (!a) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "array_entry not found tid=%d", tid);
+ memset(bt, 0, sizeof(buffer_term));
+ nterms_void++;
+ } else {
+ if (!ndf && !nvchunks) {
+ a[0] = 0;
+ a[1] = 0;
+ lexicon_delete(ctx, ii, tid, h);
+ memset(bt, 0, sizeof(buffer_term));
+ nterms_void++;
+ } else if ((ii->header->flags & GRN_OBJ_WITH_SECTION)
+ && !nvchunks && ndf == 1 && lid.rid < 0x100000 &&
+ lid.sid < 0x800 && lid.tf == 1 && lid.weight == 0) {
+ a[0] = (lid.rid << 12) + (lid.sid << 1) + 1;
+ a[1] = (ii->header->flags & GRN_OBJ_WITH_POSITION) ? posp[-1] : 0;
+ memset(bt, 0, sizeof(buffer_term));
+ nterms_void++;
+ } else if (!(ii->header->flags & GRN_OBJ_WITH_SECTION)
+ && !nvchunks && ndf == 1 && lid.tf == 1 && lid.weight == 0) {
+ a[0] = (lid.rid << 1) + 1;
+ a[1] = (ii->header->flags & GRN_OBJ_WITH_POSITION) ? posp[-1] : 0;
+ memset(bt, 0, sizeof(buffer_term));
+ nterms_void++;
+ } else {
+ int j = 0;
+ uint8_t *dcp0;
+ uint32_t encsize;
+ uint32_t f_s = (ndf < 3) ? 0 : USE_P_ENC;
+ uint32_t f_d = ((ndf < 16) || (ndf <= (lid.rid >> 8))) ? 0 : USE_P_ENC;
+ dv[j].data_size = ndf; dv[j++].flags = f_d;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ dv[j].data_size = ndf; dv[j++].flags = f_s;
+ }
+ dv[j].data_size = ndf; dv[j++].flags = f_s;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ dv[j].data_size = ndf; dv[j++].flags = f_s;
+ }
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ uint32_t np = posp - dv[ii->n_elements - 1].data;
+ uint32_t f_p = ((np < 32) || (np <= (spos >> 13))) ? 0 : USE_P_ENC;
+ dv[j].data_size = np; dv[j].flags = f_p|ODD;
+ }
+ dcp0 = dcp;
+ a[1] = (bt->size_in_chunk ? a[1] : 0) + (ndf - sdf) + balance;
+ if (nvchunks) {
+ int i;
+ GRN_B_ENC(nvchunks, dcp);
+ for (i = 0; (uint) i < nchunks; i++) {
+ if (cinfo[i].size) {
+ GRN_B_ENC(cinfo[i].segno, dcp);
+ GRN_B_ENC(cinfo[i].size, dcp);
+ GRN_B_ENC(cinfo[i].dgap, dcp);
+ }
+ }
+ }
+ encsize = grn_p_encv(ctx, dv, ii->n_elements, dcp);
+
+ if (grn_logger_pass(ctx, GRN_LOG_DEBUG)) {
+ if (sb->header.chunk_size + S_SEGMENT <= (dcp - dc) + encsize) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "cs(%d)+(%d)=(%d)"
+ "<=(%" GRN_FMT_LLD ")+(%d)="
+ "(%" GRN_FMT_LLD ")",
+ sb->header.chunk_size,
+ S_SEGMENT,
+ sb->header.chunk_size + S_SEGMENT,
+ (long long int)(dcp - dc),
+ encsize,
+ (long long int)((dcp - dc) + encsize));
+ buffer_merge_dump_datavec(ctx, ii, dv, rdv);
+ }
+ }
+
+ if (encsize > CHUNK_SPLIT_THRESHOLD &&
+ (cinfo || (cinfo = GRN_MALLOCN(chunk_info, nchunks + 1))) &&
+ !chunk_flush(ctx, ii, &cinfo[nchunks], dcp, encsize)) {
+ int i;
+ cinfo[nchunks].dgap = lid.rid - crid;
+ nvchunks++;
+ dcp = dcp0;
+ GRN_B_ENC(nvchunks, dcp);
+ for (i = 0; (uint) i <= nchunks; i++) {
+ if (cinfo[i].size) {
+ GRN_B_ENC(cinfo[i].segno, dcp);
+ GRN_B_ENC(cinfo[i].size, dcp);
+ GRN_B_ENC(cinfo[i].dgap, dcp);
+ }
+ }
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "split (%d) encsize=%d", tid, encsize);
+ bt->tid |= CHUNK_SPLIT;
+ } else {
+ dcp += encsize;
+ if (!nvchunks) {
+ bt->tid &= ~CHUNK_SPLIT;
+ }
+ }
+ bt->pos_in_chunk = (uint32_t)(dcp0 - dc);
+ bt->size_in_chunk = (uint32_t)(dcp - dcp0);
+ bt->size_in_buffer = 0;
+ bt->pos_in_buffer = 0;
+ }
+ array_unref(ii, tid);
+ }
+ }
+ if (cinfo) { GRN_FREE(cinfo); }
+ }
+ datavec_fin(ctx, rdv);
+ datavec_fin(ctx, dv);
+ db->header.chunk_size = (uint32_t)(dcp - dc);
+ db->header.buffer_free =
+ S_SEGMENT - sizeof(buffer_header) - db->header.nterms * sizeof(buffer_term);
+ db->header.nterms_void = nterms_void;
+ return ctx->rc;
+}
+
+static void
+fake_map(grn_ctx *ctx, grn_io *io, grn_io_win *iw, void *addr, uint32_t seg, uint32_t size)
+{
+ iw->ctx = ctx;
+ iw->diff = 0;
+ iw->io = io;
+ iw->mode = grn_io_wronly;
+ iw->segment = ((seg) >> GRN_II_N_CHUNK_VARIATION);
+ iw->offset = (((seg) & ((1 << GRN_II_N_CHUNK_VARIATION) - 1)) << GRN_II_W_LEAST_CHUNK);
+ iw->size = size;
+ iw->cached = 0;
+ iw->addr = addr;
+}
+
+static grn_rc
+buffer_flush(grn_ctx *ctx, grn_ii *ii, uint32_t seg, grn_hash *h)
+{
+ grn_io_win sw, dw;
+ buffer *sb, *db = NULL;
+ uint8_t *dc, *sc = NULL;
+ uint32_t ds, pseg, scn, dcn = 0;
+ if (ii->header->binfo[seg] == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ CRIT(GRN_FILE_CORRUPT,
+ "[ii][buffer][flush] invalid segment: "
+ "<%.*s> :"
+ "request:<%u>, max:<%u>",
+ name_size, name,
+ seg, ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ if ((ds = segment_get(ctx, ii)) == ii->seg->header->max_segment) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][flush] segment is full: "
+ "<%.*s> :"
+ "request:<%u>, max:<%u>",
+ name_size, name,
+ seg, ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ pseg = buffer_open(ctx, ii, SEG2POS(seg, 0), NULL, &sb);
+ if (pseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][flush] failed to open buffer: "
+ "<%.*s> :"
+ "segment:<%u>, position:<%u>, max:<%u>",
+ name_size, name,
+ seg, SEG2POS(seg, 0), ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ {
+ GRN_IO_SEG_REF(ii->seg, ds, db);
+ if (db) {
+ uint32_t actual_chunk_size = 0;
+ uint32_t max_dest_chunk_size = sb->header.chunk_size + S_SEGMENT;
+ if ((dc = GRN_MALLOC(max_dest_chunk_size * 2))) {
+ if ((scn = sb->header.chunk) == GRN_II_PSEG_NOT_ASSIGNED ||
+ (sc = WIN_MAP(ii->chunk, ctx, &sw, scn, 0,
+ sb->header.chunk_size, grn_io_rdonly))) {
+ uint16_t n = sb->header.nterms;
+ memset(db, 0, S_SEGMENT);
+ grn_memcpy(db->terms, sb->terms, n * sizeof(buffer_term));
+ db->header.nterms = n;
+ buffer_merge(ctx, ii, seg, h, sb, sc, db, dc);
+ if (ctx->rc == GRN_SUCCESS) {
+ actual_chunk_size = db->header.chunk_size;
+ if (actual_chunk_size > 0) {
+ chunk_new(ctx, ii, &dcn, actual_chunk_size);
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_rc rc;
+ db->header.chunk =
+ actual_chunk_size ? dcn : GRN_II_PSEG_NOT_ASSIGNED;
+ fake_map(ctx, ii->chunk, &dw, dc, dcn, actual_chunk_size);
+ rc = grn_io_win_unmap(&dw);
+ if (rc == GRN_SUCCESS) {
+ buffer_segment_update(ii, seg, ds);
+ ii->header->total_chunk_size += actual_chunk_size;
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win_unmap(&sw);
+ chunk_free(ctx, ii, scn, 0, sb->header.chunk_size);
+ ii->header->total_chunk_size -= sb->header.chunk_size;
+ }
+ } else {
+ GRN_FREE(dc);
+ if (actual_chunk_size) {
+ chunk_free(ctx, ii, dcn, 0, actual_chunk_size);
+ }
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) { grn_io_win_unmap(&sw); }
+ {
+ DEFINE_NAME(ii);
+ ERR(rc,
+ "[ii][buffer][flush] failed to unmap a destination chunk: "
+ "<%.*s> : "
+ "segment:<%u>, destination-segment:<%u>, actual-size:<%u>",
+ name_size, name,
+ seg,
+ dcn,
+ actual_chunk_size);
+ }
+ }
+ } else {
+ GRN_FREE(dc);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) { grn_io_win_unmap(&sw); }
+ }
+ } else {
+ GRN_FREE(dc);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) { grn_io_win_unmap(&sw); }
+ }
+ } else {
+ GRN_FREE(dc);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][flush] failed to map a source chunk: "
+ "<%.*s> :"
+ "segment:<%u>, source-segment:<%u>, chunk-size:<%u>",
+ name_size, name,
+ seg,
+ scn,
+ sb->header.chunk_size);
+ }
+ }
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][flush] failed to allocate a destination chunk: "
+ "<%.*s> :"
+ "segment:<%u>, destination-segment:<%u>",
+ name_size, name,
+ seg,
+ ds);
+ }
+ GRN_IO_SEG_UNREF(ii->seg, ds);
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][flush] failed to allocate a destination segment: "
+ "<%.*s> :"
+ "segment:<%u>, destination-segment:<%u>",
+ name_size, name,
+ seg,
+ ds);
+ }
+ buffer_close(ctx, ii, pseg);
+ }
+ return ctx->rc;
+}
+
+void
+grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg)
+{
+ grn_io_win sw;
+ buffer *sb;
+ uint8_t *sc = NULL;
+ uint32_t pseg, scn, nterms_with_corrupt_chunk = 0, nterm_with_chunk = 0;
+ uint32_t ndeleted_terms_with_value = 0;
+ buffer_term *bt;
+ uint8_t *sbp = NULL;
+ datavec rdv[MAX_N_ELEMENTS + 1];
+ uint16_t n;
+ int nterms_void = 0;
+ int size_in_buffer = 0;
+ grn_obj buf;
+ size_t lower_bound;
+ int64_t nloops = 0, nviolations = 0;
+ if (ii->header->binfo[seg] == GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_OUTPUT_BOOL(GRN_FALSE);
+ return;
+ }
+ pseg = buffer_open(ctx, ii, SEG2POS(seg, 0), NULL, &sb);
+ if (pseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_OUTPUT_BOOL(GRN_FALSE);
+ return;
+ }
+ lower_bound =
+ (sb->header.buffer_free + sizeof(buffer_term) * sb->header.nterms)
+ / sizeof(buffer_rec);
+ datavec_init(ctx, rdv, ii->n_elements, 0, 0);
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ rdv[ii->n_elements - 1].flags = ODD;
+ }
+ GRN_OUTPUT_MAP_OPEN("BUFFER", -1);
+ GRN_OUTPUT_CSTR("buffer id");
+ GRN_OUTPUT_INT64(seg);
+ if ((scn = sb->header.chunk) == GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_OUTPUT_CSTR("void chunk size");
+ GRN_OUTPUT_INT64(sb->header.chunk_size);
+ } else {
+ if ((sc = WIN_MAP(ii->chunk, ctx, &sw, scn, 0, sb->header.chunk_size,
+ grn_io_rdonly))) {
+ GRN_OUTPUT_CSTR("chunk size");
+ GRN_OUTPUT_INT64(sb->header.chunk_size);
+ } else {
+ GRN_OUTPUT_CSTR("unmappable chunk size");
+ GRN_OUTPUT_INT64(sb->header.chunk_size);
+ }
+ }
+ GRN_OUTPUT_CSTR("buffer term");
+ GRN_OUTPUT_ARRAY_OPEN("TERMS", sb->header.nterms);
+
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, ii->lexicon->header.domain);
+ for (bt = sb->terms, n = sb->header.nterms; n; n--, bt++) {
+ grn_id tid, tid_;
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_size;
+ uint16_t nextb;
+ uint32_t nchunks = 0;
+ chunk_info *cinfo = NULL;
+ grn_id crid = GRN_ID_NIL;
+ docinfo bid = {0, 0, 0, 0, 0};
+ uint32_t sdf = 0, snn = 0;
+ uint32_t *srp = NULL, *ssp = NULL, *stp = NULL, *sop = NULL, *snp = NULL;
+ if (!bt->tid && !bt->pos_in_buffer && !bt->size_in_buffer) {
+ nterms_void++;
+ continue;
+ }
+ GRN_OUTPUT_ARRAY_OPEN("TERM", -1);
+ tid = (bt->tid & GRN_ID_MAX);
+ key_size = grn_table_get_key(ctx, ii->lexicon, tid, key,
+ GRN_TABLE_MAX_KEY_SIZE);
+ tid_ = grn_table_get(ctx, ii->lexicon, key, key_size);
+ GRN_TEXT_SET(ctx, &buf, key, key_size);
+ GRN_OUTPUT_OBJ(&buf, NULL);
+ GRN_OUTPUT_INT64(bt->tid);
+ GRN_OUTPUT_INT64(tid_);
+ nextb = bt->pos_in_buffer;
+ size_in_buffer += bt->size_in_buffer;
+ if (tid != tid_ && (bt->size_in_buffer || bt->size_in_chunk)) {
+ ndeleted_terms_with_value++;
+ }
+ GETNEXTB();
+ GRN_OUTPUT_INT64(bt->size_in_buffer);
+ GRN_OUTPUT_INT64(bt->size_in_chunk);
+ if (sc && bt->size_in_chunk) {
+ uint8_t *scp = sc + bt->pos_in_chunk;
+ uint8_t *sce = scp + bt->size_in_chunk;
+ size_t size = S_SEGMENT * ii->n_elements;
+ if ((bt->tid & CHUNK_SPLIT)) {
+ int i;
+ GRN_B_DEC(nchunks, scp);
+ if (!(cinfo = GRN_MALLOCN(chunk_info, nchunks + 1))) {
+ datavec_fin(ctx, rdv);
+ GRN_OBJ_FIN(ctx, &buf);
+ return;
+ }
+ for (i = 0; (uint) i < nchunks; i++) {
+ GRN_B_DEC(cinfo[i].segno, scp);
+ GRN_B_DEC(cinfo[i].size, scp);
+ GRN_B_DEC(cinfo[i].dgap, scp);
+ crid += cinfo[i].dgap;
+ }
+ }
+ if (sce > scp) {
+ size += grn_p_decv(ctx, scp, sce - scp, rdv, ii->n_elements);
+ {
+ int j = 0;
+ sdf = rdv[j].data_size;
+ GRN_OUTPUT_INT64(sdf);
+ srp = rdv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) { ssp = rdv[j++].data; }
+ if (sdf != rdv[j].data_size) {
+ nterms_with_corrupt_chunk++;
+ }
+ stp = rdv[j++].data;
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) { sop = rdv[j++].data; }
+ GRN_OUTPUT_INT64(rdv[j].data_size);
+ snn = rdv[j].data_size;
+ snp = rdv[j].data;
+ }
+ nterm_with_chunk++;
+ }
+ }
+ {
+ uint16_t pos;
+ grn_id rid, sid, rid_ = 0, sid_ = 0;
+ uint8_t *p;
+ buffer_rec *r;
+ for (pos = bt->pos_in_buffer; pos; pos = r->step) {
+ if (pos < lower_bound) {
+ nviolations++;
+ }
+ r = BUFFER_REC_AT(sb, pos);
+ p = GRN_NEXT_ADDR(r);
+ GRN_B_DEC(rid, p);
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(sid, p);
+ } else {
+ sid = 1;
+ }
+ if (rid < rid_ || (rid == rid_ && sid < sid_)) {
+ nloops++;
+ }
+ rid_ = rid;
+ sid_ = sid;
+ }
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ if (cinfo) { GRN_FREE(cinfo); }
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+
+ GRN_OUTPUT_ARRAY_CLOSE();
+ GRN_OUTPUT_CSTR("buffer free");
+ GRN_OUTPUT_INT64(sb->header.buffer_free);
+ GRN_OUTPUT_CSTR("size in buffer");
+ GRN_OUTPUT_INT64(size_in_buffer);
+ GRN_OUTPUT_CSTR("nterms");
+ GRN_OUTPUT_INT64(sb->header.nterms);
+ if (nterms_void != sb->header.nterms_void) {
+ GRN_OUTPUT_CSTR("nterms void gap");
+ GRN_OUTPUT_INT64(nterms_void - sb->header.nterms_void);
+ }
+ GRN_OUTPUT_CSTR("nterms with chunk");
+ GRN_OUTPUT_INT64(nterm_with_chunk);
+ if (nterms_with_corrupt_chunk) {
+ GRN_OUTPUT_CSTR("nterms with corrupt chunk");
+ GRN_OUTPUT_INT64(nterms_with_corrupt_chunk);
+ }
+ if (ndeleted_terms_with_value) {
+ GRN_OUTPUT_CSTR("number of deleted terms with value");
+ GRN_OUTPUT_INT64(ndeleted_terms_with_value);
+ }
+ if (nloops) {
+ GRN_OUTPUT_CSTR("number of loops");
+ GRN_OUTPUT_INT64(nloops);
+ }
+ if (nviolations) {
+ GRN_OUTPUT_CSTR("number of violations");
+ GRN_OUTPUT_INT64(nviolations);
+ }
+ GRN_OUTPUT_MAP_CLOSE();
+ datavec_fin(ctx, rdv);
+ if (sc) { grn_io_win_unmap(&sw); }
+ buffer_close(ctx, ii, pseg);
+}
+
+typedef struct {
+ buffer_term *bt;
+ const char *key;
+ uint32_t key_size;
+} term_sort;
+
+static int
+term_compar(const void *t1, const void *t2)
+{
+ int r;
+ const term_sort *x = (term_sort *)t1, *y = (term_sort *)t2;
+ if (x->key_size > y->key_size) {
+ r = memcmp(x->key, y->key, y->key_size);
+ return r ? r : x->key_size - y->key_size;
+ } else {
+ r = memcmp(x->key, y->key, x->key_size);
+ return r ? r : x->key_size - y->key_size;
+ }
+}
+
+static grn_rc
+term_split(grn_ctx *ctx, grn_obj *lexicon, buffer *sb, buffer *db0, buffer *db1)
+{
+ uint16_t i, n, *nt;
+ buffer_term *bt;
+ uint32_t s, th = (sb->header.chunk_size + sb->header.nterms) >> 1;
+ term_sort *ts = GRN_MALLOC(sb->header.nterms * sizeof(term_sort));
+ if (!ts) { return GRN_NO_MEMORY_AVAILABLE; }
+ for (i = 0, n = sb->header.nterms, bt = sb->terms; n; bt++, n--) {
+ if (bt->tid) {
+ grn_id tid = bt->tid & GRN_ID_MAX;
+ ts[i].key = _grn_table_key(ctx, lexicon, tid, &ts[i].key_size);
+ ts[i].bt = bt;
+ i++;
+ }
+ }
+ qsort(ts, i, sizeof(term_sort), term_compar);
+ memset(db0, 0, S_SEGMENT);
+ bt = db0->terms;
+ nt = &db0->header.nterms;
+ for (s = 0; n + 1 < i && s <= th; n++, bt++) {
+ grn_memcpy(bt, ts[n].bt, sizeof(buffer_term));
+ (*nt)++;
+ s += ts[n].bt->size_in_chunk + 1;
+ }
+ memset(db1, 0, S_SEGMENT);
+ bt = db1->terms;
+ nt = &db1->header.nterms;
+ for (; n < i; n++, bt++) {
+ grn_memcpy(bt, ts[n].bt, sizeof(buffer_term));
+ (*nt)++;
+ }
+ GRN_FREE(ts);
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "d0=%d d1=%d",
+ db0->header.nterms, db1->header.nterms);
+ return GRN_SUCCESS;
+}
+
+static void
+array_update(grn_ctx *ctx, grn_ii *ii, uint32_t dls, buffer *db)
+{
+ uint16_t n;
+ buffer_term *bt;
+ uint32_t *a, pos = SEG2POS(dls, sizeof(buffer_header));
+ for (n = db->header.nterms, bt = db->terms; n; n--, bt++) {
+ if (bt->tid) {
+ grn_id tid = bt->tid & GRN_ID_MAX;
+ if ((a = array_at(ctx, ii, tid))) {
+ a[0] = pos;
+ array_unref(ii, tid);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "array_at failed (%d)", tid);
+ }
+ }
+ pos += sizeof(buffer_term) >> 2;
+ }
+}
+
+static grn_rc
+buffer_split(grn_ctx *ctx, grn_ii *ii, uint32_t seg, grn_hash *h)
+{
+ grn_io_win sw, dw0, dw1;
+ buffer *sb, *db0 = NULL, *db1 = NULL;
+ uint8_t *sc = NULL, *dc0, *dc1;
+ uint32_t dps0 = 0, dps1 = 0, dls0 = 0, dls1 = 0, sps, scn, dcn0 = 0, dcn1 = 0;
+ if (ii->header->binfo[seg] == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ CRIT(GRN_FILE_CORRUPT,
+ "[ii][buffer][split] invalid segment: "
+ "<%.*s> :"
+ "request:<%u>, max:<%u>",
+ name_size, name,
+ seg, ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ buffer_segment_reserve(ctx, ii, &dls0, &dps0, &dls1, &dps1);
+ if (ctx->rc != GRN_SUCCESS) {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][buffer][split] failed to reserve buffer segments: "
+ "<%.*s> :"
+ "request:<%u>, max:<%u>",
+ name_size, name,
+ seg, ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ sps = buffer_open(ctx, ii, SEG2POS(seg, 0), NULL, &sb);
+ if (sps == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][split] failed to open buffer: "
+ "<%.*s> :"
+ "segment:<%u>, position:<%u>, max-segment:<%u>",
+ name_size, name,
+ seg, SEG2POS(seg, 0), ii->seg->header->max_segment);
+ } else {
+ GRN_IO_SEG_REF(ii->seg, dps0, db0);
+ if (db0) {
+ GRN_IO_SEG_REF(ii->seg, dps1, db1);
+ if (db1) {
+ uint32_t actual_db0_chunk_size = 0;
+ uint32_t actual_db1_chunk_size = 0;
+ uint32_t max_dest_chunk_size = sb->header.chunk_size + S_SEGMENT;
+ if ((dc0 = GRN_MALLOC(max_dest_chunk_size * 2))) {
+ if ((dc1 = GRN_MALLOC(max_dest_chunk_size * 2))) {
+ if ((scn = sb->header.chunk) == GRN_II_PSEG_NOT_ASSIGNED ||
+ (sc = WIN_MAP(ii->chunk, ctx, &sw, scn, 0,
+ sb->header.chunk_size, grn_io_rdonly))) {
+ term_split(ctx, ii->lexicon, sb, db0, db1);
+ buffer_merge(ctx, ii, seg, h, sb, sc, db0, dc0);
+ if (ctx->rc == GRN_SUCCESS) {
+ actual_db0_chunk_size = db0->header.chunk_size;
+ if (actual_db0_chunk_size > 0) {
+ chunk_new(ctx, ii, &dcn0, actual_db0_chunk_size);
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_rc rc;
+ db0->header.chunk =
+ actual_db0_chunk_size ? dcn0 : GRN_II_PSEG_NOT_ASSIGNED;
+ fake_map(ctx, ii->chunk, &dw0, dc0, dcn0, actual_db0_chunk_size);
+ rc = grn_io_win_unmap(&dw0);
+ if (rc == GRN_SUCCESS) {
+ buffer_merge(ctx, ii, seg, h, sb, sc, db1, dc1);
+ if (ctx->rc == GRN_SUCCESS) {
+ actual_db1_chunk_size = db1->header.chunk_size;
+ if (actual_db1_chunk_size > 0) {
+ chunk_new(ctx, ii, &dcn1, actual_db1_chunk_size);
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ fake_map(ctx, ii->chunk, &dw1, dc1, dcn1,
+ actual_db1_chunk_size);
+ rc = grn_io_win_unmap(&dw1);
+ if (rc == GRN_SUCCESS) {
+ db1->header.chunk =
+ actual_db1_chunk_size ? dcn1 : GRN_II_PSEG_NOT_ASSIGNED;
+ buffer_segment_update(ii, dls0, dps0);
+ buffer_segment_update(ii, dls1, dps1);
+ array_update(ctx, ii, dls0, db0);
+ array_update(ctx, ii, dls1, db1);
+ buffer_segment_clear(ii, seg);
+ ii->header->total_chunk_size += actual_db0_chunk_size;
+ ii->header->total_chunk_size += actual_db1_chunk_size;
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win_unmap(&sw);
+ chunk_free(ctx, ii, scn, 0, sb->header.chunk_size);
+ ii->header->total_chunk_size -= sb->header.chunk_size;
+ }
+ } else {
+ if (actual_db1_chunk_size) {
+ chunk_free(ctx, ii, dcn1, 0, actual_db1_chunk_size);
+ }
+ if (actual_db0_chunk_size) {
+ chunk_free(ctx, ii, dcn0, 0, actual_db0_chunk_size);
+ }
+ GRN_FREE(dc1);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win_unmap(&sw);
+ }
+ {
+ DEFINE_NAME(ii);
+ ERR(rc,
+ "[ii][buffer[merge] "
+ "failed to unmap a destination chunk2: "
+ "<%.*s> :"
+ "segment:<%u>, "
+ "destination-chunk1:<%u>, "
+ "destination-chunk2:<%u>, "
+ "actual-size1:<%u>, "
+ "actual-size2:<%u>",
+ name_size, name,
+ seg,
+ dcn0,
+ dcn1,
+ actual_db0_chunk_size,
+ actual_db1_chunk_size);
+ }
+ }
+ } else {
+ if (actual_db0_chunk_size) {
+ chunk_free(ctx, ii, dcn0, 0, actual_db0_chunk_size);
+ }
+ GRN_FREE(dc1);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win_unmap(&sw);
+ }
+ }
+ } else {
+ if (actual_db0_chunk_size) {
+ chunk_free(ctx, ii, dcn0, 0, actual_db0_chunk_size);
+ }
+ GRN_FREE(dc1);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win_unmap(&sw);
+ }
+ }
+ } else {
+ if (actual_db0_chunk_size) {
+ chunk_free(ctx, ii, dcn0, 0, actual_db0_chunk_size);
+ }
+ GRN_FREE(dc1);
+ GRN_FREE(dc0);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win_unmap(&sw);
+ }
+ {
+ DEFINE_NAME(ii);
+ ERR(rc,
+ "[ii][buffer[merge] "
+ "failed to unmap a destination chunk1: "
+ "<%.*s> :"
+ "segment:<%u>, "
+ "destination-chunk1:<%u>, "
+ "actual-size1:<%u>",
+ name_size, name,
+ seg,
+ dcn0,
+ actual_db0_chunk_size);
+ }
+ }
+ } else {
+ GRN_FREE(dc1);
+ GRN_FREE(dc0);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) { grn_io_win_unmap(&sw); }
+ }
+ } else {
+ GRN_FREE(dc1);
+ GRN_FREE(dc0);
+ if (scn != GRN_II_PSEG_NOT_ASSIGNED) { grn_io_win_unmap(&sw); }
+ }
+ } else {
+ GRN_FREE(dc1);
+ GRN_FREE(dc0);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][split] failed to map a source chunk: "
+ "<%.*s> :"
+ "segment:<%u>, "
+ "source-segment:<%u>, "
+ "chunk-size:<%u>",
+ name_size, name,
+ seg,
+ scn,
+ sb->header.chunk_size);
+ }
+ }
+ } else {
+ GRN_FREE(dc0);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][split] "
+ "failed to allocate a destination chunk2: "
+ "<%.*s> :"
+ "segment:<%u>, "
+ "destination-segment1:<%u>, "
+ "destination-segment2:<%u>",
+ name_size, name,
+ seg,
+ dps0,
+ dps1);
+ }
+ }
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][split] failed to allocate a destination chunk1: "
+ "<%.*s>: "
+ "segment:<%u>, "
+ "destination-segment1:<%u>, "
+ "destination-segment2:<%u>",
+ name_size, name,
+ seg,
+ dps0,
+ dps1);
+ }
+ GRN_IO_SEG_UNREF(ii->seg, dps1);
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][split] failed to allocate a destination segment2: "
+ "<%.*s>: "
+ "segment:<%u>, "
+ "destination-segment1:<%u>, "
+ "destination-segment2:<%u>",
+ name_size, name,
+ seg,
+ dps0,
+ dps1);
+ }
+ GRN_IO_SEG_UNREF(ii->seg, dps0);
+ } else {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][split] failed to allocate a destination segment1: "
+ "<%.*s>: "
+ "segment:<%u>, "
+ "destination-segment1:<%u>, "
+ "destination-segment2:<%u>",
+ name_size, name,
+ seg,
+ dps0,
+ dps1);
+ }
+ buffer_close(ctx, ii, sps);
+ }
+ return ctx->rc;
+}
+
+#define SCALE_FACTOR 2048
+#define MAX_NTERMS 8192
+#define SPLIT_COND(ii, buffer)\
+ ((buffer)->header.nterms > 1024 ||\
+ ((buffer)->header.nterms > 1 &&\
+ (buffer)->header.chunk_size * 100 > (ii)->header->total_chunk_size))
+
+inline static void
+buffer_new_find_segment(grn_ctx *ctx,
+ grn_ii *ii,
+ int size,
+ grn_id tid,
+ grn_hash *h,
+ buffer **b,
+ uint32_t *lseg,
+ uint32_t *pseg)
+{
+ uint32_t *a;
+
+ a = array_at(ctx, ii, tid);
+ if (!a) {
+ return;
+ }
+
+ for (;;) {
+ uint32_t pos = a[0];
+ if (!pos || (pos & 1)) { break; }
+ *pseg = buffer_open(ctx, ii, pos, NULL, b);
+ if (*pseg == GRN_II_PSEG_NOT_ASSIGNED) { break; }
+ if ((*b)->header.buffer_free >= size + sizeof(buffer_term)) {
+ *lseg = LSEG(pos);
+ break;
+ }
+ buffer_close(ctx, ii, *pseg);
+ if (SPLIT_COND(ii, (*b))) {
+ /* ((S_SEGMENT - sizeof(buffer_header) + ii->header->bmax -
+ (*b)->header.nterms * sizeof(buffer_term)) * 4 <
+ (*b)->header.chunk_size) */
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "nterms=%d chunk=%d total=%" GRN_FMT_INT64U,
+ (*b)->header.nterms,
+ (*b)->header.chunk_size,
+ ii->header->total_chunk_size >> 10);
+ if (buffer_split(ctx, ii, LSEG(pos), h)) { break; }
+ } else {
+ if (S_SEGMENT - sizeof(buffer_header)
+ - (*b)->header.nterms * sizeof(buffer_term)
+ < size + sizeof(buffer_term)) {
+ break;
+ }
+ if (buffer_flush(ctx, ii, LSEG(pos), h)) { break; }
+ }
+ }
+
+ array_unref(ii, tid);
+}
+
+inline static void
+buffer_new_lexicon_pat(grn_ctx *ctx,
+ grn_ii *ii,
+ int size,
+ grn_id id,
+ grn_hash *h,
+ buffer **b,
+ uint32_t *lseg,
+ uint32_t *pseg)
+{
+ grn_pat_cursor *cursor;
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_size;
+
+ key_size = grn_table_get_key(ctx, ii->lexicon, id, key,
+ GRN_TABLE_MAX_KEY_SIZE);
+ if (ii->lexicon->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ grn_obj *tokenizer = NULL;
+
+ grn_table_get_info(ctx, ii->lexicon, NULL, NULL, &tokenizer, NULL, NULL);
+ if (tokenizer) {
+ /* For natural language */
+ cursor = grn_pat_cursor_open(ctx,
+ (grn_pat *)(ii->lexicon),
+ key,
+ key_size,
+ NULL,
+ 0,
+ 0,
+ -1,
+ GRN_CURSOR_ASCENDING|GRN_CURSOR_GT);
+ if (cursor) {
+ grn_id tid;
+ while (ctx->rc == GRN_SUCCESS &&
+ *lseg == GRN_II_PSEG_NOT_ASSIGNED &&
+ (tid = grn_pat_cursor_next(ctx, cursor))) {
+ buffer_new_find_segment(ctx, ii, size, tid, h, b, lseg, pseg);
+ }
+ grn_pat_cursor_close(ctx, cursor);
+ }
+ } else {
+ /* For text data */
+ int target_key_size = key_size;
+ int reduced_key_size = 0;
+
+ while (*lseg == GRN_II_PSEG_NOT_ASSIGNED && target_key_size > 0) {
+ grn_id tid;
+
+ cursor = grn_pat_cursor_open(ctx,
+ (grn_pat *)(ii->lexicon),
+ key, target_key_size,
+ NULL, 0, 0, -1,
+ GRN_CURSOR_PREFIX);
+ if (!cursor) {
+ break;
+ }
+
+ if (reduced_key_size == 0) {
+ while (ctx->rc == GRN_SUCCESS &&
+ *lseg == GRN_II_PSEG_NOT_ASSIGNED &&
+ (tid = grn_pat_cursor_next(ctx, cursor))) {
+ buffer_new_find_segment(ctx, ii, size, tid, h, b, lseg, pseg);
+ }
+ } else {
+ while (ctx->rc == GRN_SUCCESS &&
+ *lseg == GRN_II_PSEG_NOT_ASSIGNED &&
+ (tid = grn_pat_cursor_next(ctx, cursor))) {
+ void *current_key;
+ int current_key_size;
+
+ current_key_size = grn_pat_cursor_get_key(ctx, cursor, &current_key);
+ if (memcmp(((char *)current_key) + target_key_size,
+ key + target_key_size,
+ reduced_key_size) == 0) {
+ continue;
+ }
+ buffer_new_find_segment(ctx, ii, size, tid, h, b, lseg, pseg);
+ }
+ }
+ grn_pat_cursor_close(ctx, cursor);
+
+ if (reduced_key_size == 0) {
+ reduced_key_size = 1;
+ } else {
+ reduced_key_size *= 2;
+ }
+ target_key_size -= reduced_key_size;
+ }
+ }
+ } else {
+ /* For other data */
+ cursor = grn_pat_cursor_open(ctx,
+ (grn_pat *)(ii->lexicon),
+ NULL, 0, key, key_size, 0, -1,
+ GRN_CURSOR_PREFIX);
+ if (cursor) {
+ grn_id tid;
+ while (ctx->rc == GRN_SUCCESS &&
+ *lseg == GRN_II_PSEG_NOT_ASSIGNED &&
+ (tid = grn_pat_cursor_next(ctx, cursor))) {
+ buffer_new_find_segment(ctx, ii, size, tid, h, b, lseg, pseg);
+ }
+ grn_pat_cursor_close(ctx, cursor);
+ }
+ }
+}
+
+inline static void
+buffer_new_lexicon_other(grn_ctx *ctx,
+ grn_ii *ii,
+ int size,
+ grn_id id,
+ grn_hash *h,
+ buffer **b,
+ uint32_t *lseg,
+ uint32_t *pseg)
+{
+ GRN_TABLE_EACH_BEGIN(ctx, ii->lexicon, cursor, tid) {
+ if (ctx->rc != GRN_SUCCESS || *lseg != GRN_II_PSEG_NOT_ASSIGNED) {
+ break;
+ }
+ buffer_new_find_segment(ctx, ii, size, tid, h, b, lseg, pseg);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+}
+
+
+inline static uint32_t
+buffer_new(grn_ctx *ctx, grn_ii *ii, int size, uint32_t *pos,
+ buffer_term **bt, buffer_rec **br, buffer **bp, grn_id id, grn_hash *h)
+{
+ buffer *b = NULL;
+ uint16_t offset;
+ uint32_t lseg = GRN_II_PSEG_NOT_ASSIGNED, pseg = GRN_II_PSEG_NOT_ASSIGNED;
+ if (S_SEGMENT - sizeof(buffer_header) < size + sizeof(buffer_term)) {
+ DEFINE_NAME(ii);
+ MERR("[ii][buffer][new] requested size is too large: "
+ "<%.*s> :"
+ "requested:<%" GRN_FMT_SIZE ">, max:<%" GRN_FMT_SIZE ">",
+ name_size, name,
+ (size_t)(size + sizeof(buffer_term)),
+ (size_t)(S_SEGMENT - sizeof(buffer_header)));
+ return GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ if (ii->lexicon->header.type == GRN_TABLE_PAT_KEY) {
+ buffer_new_lexicon_pat(ctx, ii, size, id, h, &b, &lseg, &pseg);
+ } else {
+ buffer_new_lexicon_other(ctx, ii, size, id, h, &b, &lseg, &pseg);
+ }
+ if (lseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ if (buffer_segment_new(ctx, ii, &lseg) ||
+ (pseg = buffer_open(ctx, ii, SEG2POS(lseg, 0), NULL, &b)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ return GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ memset(b, 0, S_SEGMENT);
+ b->header.buffer_free = S_SEGMENT - sizeof(buffer_header);
+ b->header.chunk = GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ if (b->header.nterms_void) {
+ for (offset = 0; offset < b->header.nterms; offset++) {
+ if (!b->terms[offset].tid) { break; }
+ }
+ if (offset == b->header.nterms) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "inconsistent buffer(%d)", lseg);
+ b->header.nterms_void = 0;
+ b->header.nterms++;
+ b->header.buffer_free -= size + sizeof(buffer_term);
+ } else {
+ b->header.nterms_void--;
+ b->header.buffer_free -= size;
+ }
+ } else {
+ offset = b->header.nterms++;
+ b->header.buffer_free -= size + sizeof(buffer_term);
+ }
+ *pos = SEG2POS(lseg, (sizeof(buffer_header) + sizeof(buffer_term) * offset));
+ *bt = &b->terms[offset];
+ *br = (buffer_rec *)(((byte *)&b->terms[b->header.nterms]) + b->header.buffer_free);
+ *bp = b;
+ return pseg;
+}
+
+/* ii */
+
+static grn_ii *
+_grn_ii_create(grn_ctx *ctx, grn_ii *ii, const char *path, grn_obj *lexicon, uint32_t flags)
+{
+ int i;
+ uint32_t max_n_segments;
+ uint32_t max_n_chunks;
+ grn_io *seg, *chunk;
+ char path2[PATH_MAX];
+ struct grn_ii_header *header;
+ grn_table_flags lflags;
+ grn_encoding encoding;
+ grn_obj *tokenizer;
+ /*
+ for (i = 0; i < 32; i++) {
+ new_histogram[i] = 0;
+ free_histogram[i] = 0;
+ }
+ */
+ if (grn_table_get_info(ctx, lexicon, &lflags, &encoding, &tokenizer,
+ NULL, NULL)) {
+ return NULL;
+ }
+ if (path && strlen(path) + 6 >= PATH_MAX) { return NULL; }
+
+ if (flags & GRN_OBJ_INDEX_SMALL) {
+ max_n_segments = grn_ii_max_n_segments_small;
+ max_n_chunks = grn_ii_max_n_chunks_small;
+ } else if (flags & GRN_OBJ_INDEX_MEDIUM) {
+ max_n_segments = MAX_PSEG_MEDIUM;
+ max_n_chunks = GRN_II_MAX_CHUNK_MEDIUM;
+ } else {
+ max_n_segments = MAX_PSEG;
+ max_n_chunks = GRN_II_MAX_CHUNK;
+ }
+
+ seg = grn_io_create(ctx,
+ path,
+ sizeof(struct grn_ii_header),
+ S_SEGMENT,
+ max_n_segments,
+ grn_io_auto,
+ GRN_IO_EXPIRE_SEGMENT);
+ if (!seg) { return NULL; }
+ if (path) {
+ grn_strcpy(path2, PATH_MAX, path);
+ grn_strcat(path2, PATH_MAX, ".c");
+ chunk = grn_io_create(ctx, path2, 0, S_CHUNK, max_n_chunks, grn_io_auto,
+ GRN_IO_EXPIRE_SEGMENT);
+ } else {
+ chunk = grn_io_create(ctx, NULL, 0, S_CHUNK, max_n_chunks, grn_io_auto, 0);
+ }
+ if (!chunk) {
+ grn_io_close(ctx, seg);
+ grn_io_remove(ctx, path);
+ return NULL;
+ }
+ header = grn_io_header(seg);
+ grn_io_set_type(seg, GRN_COLUMN_INDEX);
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ header->ainfo[i] = GRN_II_PSEG_NOT_ASSIGNED;
+ header->binfo[i] = GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ for (i = 0; i <= GRN_II_N_CHUNK_VARIATION; i++) {
+ header->free_chunks[i] = GRN_II_PSEG_NOT_ASSIGNED;
+ header->garbages[i] = GRN_II_PSEG_NOT_ASSIGNED;
+ }
+ header->flags = flags;
+ ii->seg = seg;
+ ii->chunk = chunk;
+ ii->lexicon = lexicon;
+ ii->lflags = lflags;
+ ii->encoding = encoding;
+ ii->header = header;
+ ii->n_elements = 2;
+ if ((flags & GRN_OBJ_WITH_SECTION)) { ii->n_elements++; }
+ if ((flags & GRN_OBJ_WITH_WEIGHT)) { ii->n_elements++; }
+ if ((flags & GRN_OBJ_WITH_POSITION)) { ii->n_elements++; }
+ return ii;
+}
+
+grn_ii *
+grn_ii_create(grn_ctx *ctx, const char *path, grn_obj *lexicon, uint32_t flags)
+{
+ grn_ii *ii = NULL;
+ if (!(ii = GRN_MALLOCN(grn_ii, 1))) {
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(ii, GRN_COLUMN_INDEX);
+ if (!_grn_ii_create(ctx, ii, path, lexicon, flags)) {
+ GRN_FREE(ii);
+ return NULL;
+ }
+ return ii;
+}
+
+grn_rc
+grn_ii_remove(grn_ctx *ctx, const char *path)
+{
+ grn_rc rc;
+ char buffer[PATH_MAX];
+ if (!path || strlen(path) > PATH_MAX - 4) { return GRN_INVALID_ARGUMENT; }
+ if ((rc = grn_io_remove(ctx, path))) { goto exit; }
+ grn_snprintf(buffer, PATH_MAX, PATH_MAX,
+ "%-.256s.c", path);
+ rc = grn_io_remove(ctx, buffer);
+exit :
+ return rc;
+}
+
+grn_rc
+grn_ii_truncate(grn_ctx *ctx, grn_ii *ii)
+{
+ grn_rc rc;
+ const char *io_segpath, *io_chunkpath;
+ char *segpath, *chunkpath = NULL;
+ grn_obj *lexicon;
+ uint32_t flags;
+ if ((io_segpath = grn_io_path(ii->seg)) && *io_segpath != '\0') {
+ if (!(segpath = GRN_STRDUP(io_segpath))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%-.256s>", io_segpath);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if ((io_chunkpath = grn_io_path(ii->chunk)) && *io_chunkpath != '\0') {
+ if (!(chunkpath = GRN_STRDUP(io_chunkpath))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%-.256s>", io_chunkpath);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ } else {
+ chunkpath = NULL;
+ }
+ } else {
+ segpath = NULL;
+ }
+ lexicon = ii->lexicon;
+ flags = ii->header->flags;
+ if ((rc = grn_io_close(ctx, ii->seg))) { goto exit; }
+ if ((rc = grn_io_close(ctx, ii->chunk))) { goto exit; }
+ ii->seg = NULL;
+ ii->chunk = NULL;
+ if (segpath && (rc = grn_io_remove(ctx, segpath))) { goto exit; }
+ if (chunkpath && (rc = grn_io_remove(ctx, chunkpath))) { goto exit; }
+ if (!_grn_ii_create(ctx, ii, segpath, lexicon, flags)) {
+ rc = GRN_UNKNOWN_ERROR;
+ }
+exit:
+ if (segpath) { GRN_FREE(segpath); }
+ if (chunkpath) { GRN_FREE(chunkpath); }
+ return rc;
+}
+
+grn_ii *
+grn_ii_open(grn_ctx *ctx, const char *path, grn_obj *lexicon)
+{
+ grn_io *seg, *chunk;
+ grn_ii *ii;
+ char path2[PATH_MAX];
+ struct grn_ii_header *header;
+ uint32_t io_type;
+ grn_table_flags lflags;
+ grn_encoding encoding;
+ grn_obj *tokenizer;
+ if (grn_table_get_info(ctx, lexicon, &lflags, &encoding, &tokenizer,
+ NULL, NULL)) {
+ return NULL;
+ }
+ if (strlen(path) + 6 >= PATH_MAX) { return NULL; }
+ grn_strcpy(path2, PATH_MAX, path);
+ grn_strcat(path2, PATH_MAX, ".c");
+ seg = grn_io_open(ctx, path, grn_io_auto);
+ if (!seg) { return NULL; }
+ chunk = grn_io_open(ctx, path2, grn_io_auto);
+ if (!chunk) {
+ grn_io_close(ctx, seg);
+ return NULL;
+ }
+ header = grn_io_header(seg);
+ io_type = grn_io_get_type(seg);
+ if (io_type != GRN_COLUMN_INDEX) {
+ ERR(GRN_INVALID_FORMAT,
+ "[column][index] file type must be %#04x: <%#04x>",
+ GRN_COLUMN_INDEX, io_type);
+ grn_io_close(ctx, seg);
+ grn_io_close(ctx, chunk);
+ return NULL;
+ }
+ if (!(ii = GRN_MALLOCN(grn_ii, 1))) {
+ grn_io_close(ctx, seg);
+ grn_io_close(ctx, chunk);
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(ii, GRN_COLUMN_INDEX);
+ ii->seg = seg;
+ ii->chunk = chunk;
+ ii->lexicon = lexicon;
+ ii->lflags = lflags;
+ ii->encoding = encoding;
+ ii->header = header;
+ ii->n_elements = 2;
+ if ((header->flags & GRN_OBJ_WITH_SECTION)) { ii->n_elements++; }
+ if ((header->flags & GRN_OBJ_WITH_WEIGHT)) { ii->n_elements++; }
+ if ((header->flags & GRN_OBJ_WITH_POSITION)) { ii->n_elements++; }
+ return ii;
+}
+
+grn_rc
+grn_ii_close(grn_ctx *ctx, grn_ii *ii)
+{
+ grn_rc rc;
+ if (!ii) { return GRN_INVALID_ARGUMENT; }
+ if ((rc = grn_io_close(ctx, ii->seg))) { return rc; }
+ if ((rc = grn_io_close(ctx, ii->chunk))) { return rc; }
+ GRN_FREE(ii);
+ /*
+ {
+ int i;
+ for (i = 0; i < 32; i++) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "new[%d]=%d free[%d]=%d",
+ i, new_histogram[i],
+ i, free_histogram[i]);
+ }
+ }
+ */
+ return rc;
+}
+
+grn_rc
+grn_ii_info(grn_ctx *ctx, grn_ii *ii, uint64_t *seg_size, uint64_t *chunk_size)
+{
+ grn_rc rc;
+
+ if (seg_size) {
+ if ((rc = grn_io_size(ctx, ii->seg, seg_size))) {
+ return rc;
+ }
+ }
+
+ if (chunk_size) {
+ if ((rc = grn_io_size(ctx, ii->chunk, chunk_size))) {
+ return rc;
+ }
+ }
+
+ return GRN_SUCCESS;
+}
+
+grn_column_flags
+grn_ii_get_flags(grn_ctx *ctx, grn_ii *ii)
+{
+ if (!ii) {
+ return 0;
+ }
+
+ return ii->header->flags;
+}
+
+uint32_t
+grn_ii_get_n_elements(grn_ctx *ctx, grn_ii *ii)
+{
+ if (!ii) {
+ return 0;
+ }
+
+ return ii->n_elements;
+}
+
+void
+grn_ii_expire(grn_ctx *ctx, grn_ii *ii)
+{
+ /*
+ grn_io_expire(ctx, ii->seg, 128, 1000000);
+ */
+ grn_io_expire(ctx, ii->chunk, 0, 1000000);
+}
+
+grn_rc
+grn_ii_flush(grn_ctx *ctx, grn_ii *ii)
+{
+ grn_rc rc;
+
+ rc = grn_io_flush(ctx, ii->seg);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_io_flush(ctx, ii->chunk);
+ }
+
+ return rc;
+}
+
+size_t
+grn_ii_get_disk_usage(grn_ctx *ctx, grn_ii *ii)
+{
+ size_t usage;
+
+ usage = grn_io_get_disk_usage(ctx, ii->seg);
+ usage += grn_io_get_disk_usage(ctx, ii->chunk);
+
+ return usage;
+}
+
+#define BIT11_01(x) ((x >> 1) & 0x7ff)
+#define BIT31_12(x) (x >> 12)
+
+grn_rc
+grn_ii_update_one(grn_ctx *ctx, grn_ii *ii, grn_id tid, grn_ii_updspec *u, grn_hash *h)
+{
+ buffer *b;
+ uint8_t *bs;
+ buffer_rec *br = NULL;
+ buffer_term *bt;
+ uint32_t pseg = 0, pos = 0, size, *a;
+ if (!tid) { return ctx->rc; }
+ if (!u->tf || !u->sid) { return grn_ii_delete_one(ctx, ii, tid, u, h); }
+ if (u->sid > ii->header->smax) { ii->header->smax = u->sid; }
+ if (!(a = array_get(ctx, ii, tid))) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to allocate an array: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid);
+ return ctx->rc;
+ }
+ if (!(bs = encode_rec(ctx, ii, u, &size, 0))) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to encode a record: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid);
+ goto exit;
+ }
+ for (;;) {
+ if (a[0]) {
+ if (!(a[0] & 1)) {
+ pos = a[0];
+ if ((pseg = buffer_open(ctx, ii, pos, &bt, &b)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to allocate a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>: "
+ "segment:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ pos);
+ goto exit;
+ }
+ if (b->header.buffer_free < size) {
+ int bfb = b->header.buffer_free;
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "flushing a[0]=%d seg=%d(%p) free=%d",
+ a[0], LSEG(a[0]), b, b->header.buffer_free);
+ buffer_close(ctx, ii, pseg);
+ if (SPLIT_COND(ii, b)) {
+ /*((S_SEGMENT - sizeof(buffer_header) + ii->header->bmax -
+ b->header.nterms * sizeof(buffer_term)) * 4 <
+ b->header.chunk_size)*/
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "nterms=%d chunk=%d total=%" GRN_FMT_INT64U,
+ b->header.nterms,
+ b->header.chunk_size,
+ ii->header->total_chunk_size >> 10);
+ buffer_split(ctx, ii, LSEG(pos), h);
+ if (ctx->rc != GRN_SUCCESS) {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][update][one] failed to split a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "segment:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ pos);
+ goto exit;
+ }
+ continue;
+ }
+ buffer_flush(ctx, ii, LSEG(pos), h);
+ if (ctx->rc != GRN_SUCCESS) {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][update][one] failed to flush a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "segment:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ pos);
+ goto exit;
+ }
+ if (a[0] != pos) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "grn_ii_update_one: a[0] changed %d->%d", a[0], pos);
+ continue;
+ }
+ if ((pseg = buffer_open(ctx, ii, pos, &bt, &b)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_LOG(ctx, GRN_LOG_CRIT, "buffer not found a[0]=%d", a[0]);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to reallocate a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>: "
+ "segment:<%u>, new-segment:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ pos, a[0]);
+ }
+ goto exit;
+ }
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "flushed a[0]=%d seg=%d(%p) free=%d->%d nterms=%d v=%d",
+ a[0], LSEG(a[0]), b, bfb, b->header.buffer_free,
+ b->header.nterms, b->header.nterms_void);
+ if (b->header.buffer_free < size) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] buffer is full: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "segment:<%u>, new-segment:<%u>, free:<%u>, required:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ pos, a[0], b->header.buffer_free, size);
+ buffer_close(ctx, ii, pseg);
+ /* todo: direct merge */
+ goto exit;
+ }
+ }
+ b->header.buffer_free -= size;
+ br = (buffer_rec *)(((byte *)&b->terms[b->header.nterms])
+ + b->header.buffer_free);
+ } else {
+ grn_ii_updspec u2;
+ uint32_t size2 = 0, v = a[0];
+ struct _grn_ii_pos pos2;
+ pos2.pos = a[1];
+ pos2.next = NULL;
+ u2.pos = &pos2;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ u2.rid = BIT31_12(v);
+ u2.sid = BIT11_01(v);
+ } else {
+ u2.rid = v >> 1;
+ u2.sid = 1;
+ }
+ u2.tf = 1;
+ u2.weight = 0;
+ if (u2.rid != u->rid || u2.sid != u->sid) {
+ uint8_t *bs2 = encode_rec(ctx, ii, &u2, &size2, 0);
+ if (!bs2) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to encode a record2: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>",
+ name_size, name,
+ u2.rid, u2.sid, tid);
+ goto exit;
+ }
+ pseg = buffer_new(ctx, ii, size + size2, &pos, &bt, &br, &b, tid, h);
+ if (pseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_FREE(bs2);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to create a buffer2: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>: "
+ "size:<%u>",
+ name_size, name,
+ u2.rid, u2.sid, tid,
+ size + size2);
+ }
+ goto exit;
+ }
+ bt->tid = tid;
+ bt->size_in_chunk = 0;
+ bt->pos_in_chunk = 0;
+ bt->size_in_buffer = 0;
+ bt->pos_in_buffer = 0;
+ buffer_put(ctx, ii, b, bt, br, bs2, &u2, size2);
+ if (ctx->rc != GRN_SUCCESS) {
+ GRN_FREE(bs2);
+ buffer_close(ctx, ii, pseg);
+ {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to put to buffer: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>",
+ name_size, name,
+ u2.rid, u2.sid, tid);
+ }
+ goto exit;
+ }
+ br = (buffer_rec *)(((byte *)br) + size2);
+ GRN_FREE(bs2);
+ }
+ }
+ }
+ break;
+ }
+ if (!br) {
+ if (u->tf == 1 && u->weight == 0) {
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ if (u->rid < 0x100000 && u->sid < 0x800) {
+ a[0] = (u->rid << 12) + (u->sid << 1) + 1;
+ a[1] = u->pos->pos;
+ goto exit;
+ }
+ } else {
+ a[0] = (u->rid << 1) + 1;
+ a[1] = u->pos->pos;
+ goto exit;
+ }
+ }
+ pseg = buffer_new(ctx, ii, size, &pos, &bt, &br, &b, tid, h);
+ if (pseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][one] failed to create a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>: "
+ "size:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ size);
+ goto exit;
+ }
+ bt->tid = tid;
+ bt->size_in_chunk = 0;
+ bt->pos_in_chunk = 0;
+ bt->size_in_buffer = 0;
+ bt->pos_in_buffer = 0;
+ }
+ buffer_put(ctx, ii, b, bt, br, bs, u, size);
+ buffer_close(ctx, ii, pseg);
+ if (!a[0] || (a[0] & 1)) { a[0] = pos; }
+exit :
+ array_unref(ii, tid);
+ if (bs) { GRN_FREE(bs); }
+ if (u->tf != u->atf) {
+ grn_obj *source_table;
+ char source_table_name[GRN_TABLE_MAX_KEY_SIZE];
+ int source_table_name_size;
+ char term[GRN_TABLE_MAX_KEY_SIZE];
+ int term_size;
+
+ source_table = grn_ctx_at(ctx, DB_OBJ(ii)->range);
+ if (source_table) {
+ source_table_name_size = grn_obj_name(ctx,
+ source_table,
+ source_table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ } else {
+ grn_strcpy(source_table_name, GRN_TABLE_MAX_KEY_SIZE, "(null)");
+ source_table_name_size = strlen(source_table_name);
+ }
+ term_size = grn_table_get_key(ctx, ii->lexicon, tid,
+ term, GRN_TABLE_MAX_KEY_SIZE);
+ {
+ DEFINE_NAME(ii);
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][update][one] too many postings: "
+ "<%.*s>: "
+ "record:<%.*s>(%d), "
+ "n-postings:<%d>, "
+ "n-discarded-postings:<%d>, "
+ "term:<%d>(<%.*s>)",
+ name_size, name,
+ source_table_name_size, source_table_name,
+ u->rid,
+ u->atf,
+ u->atf - u->tf,
+ tid, term_size, term);
+ }
+ }
+ grn_ii_expire(ctx, ii);
+ return ctx->rc;
+}
+
+grn_rc
+grn_ii_delete_one(grn_ctx *ctx, grn_ii *ii, grn_id tid, grn_ii_updspec *u, grn_hash *h)
+{
+ buffer *b;
+ uint8_t *bs = NULL;
+ buffer_rec *br;
+ buffer_term *bt;
+ uint32_t pseg, size, *a;
+ if (!tid) { return ctx->rc; }
+ if (!(a = array_at(ctx, ii, tid))) {
+ return ctx->rc;
+ }
+ for (;;) {
+ if (!a[0]) { goto exit; }
+ if (a[0] & 1) {
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ uint32_t rid = BIT31_12(a[0]);
+ uint32_t sid = BIT11_01(a[0]);
+ if (u->rid == rid && (!u->sid || u->sid == sid)) {
+ a[0] = 0;
+ lexicon_delete(ctx, ii, tid, h);
+ }
+ } else {
+ uint32_t rid = a[0] >> 1;
+ if (u->rid == rid) {
+ a[0] = 0;
+ lexicon_delete(ctx, ii, tid, h);
+ }
+ }
+ goto exit;
+ }
+ if (!(bs = encode_rec(ctx, ii, u, &size, 1))) {
+ DEFINE_NAME(ii);
+ MERR("[ii][delete][one] failed to encode a record: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid);
+ goto exit;
+ }
+ if ((pseg = buffer_open(ctx, ii, a[0], &bt, &b)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ MERR("[ii][delete][one] failed to allocate a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "position:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ a[0]);
+ goto exit;
+ }
+ if (b->header.buffer_free < size) {
+ uint32_t _a = a[0];
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "flushing! b=%p free=%d, seg(%d)",
+ b, b->header.buffer_free, LSEG(a[0]));
+ buffer_close(ctx, ii, pseg);
+ buffer_flush(ctx, ii, LSEG(a[0]), h);
+ if (ctx->rc != GRN_SUCCESS) {
+ DEFINE_NAME(ii);
+ ERR(ctx->rc,
+ "[ii][delete][one] failed to flush a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "position:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ a[0]);
+ goto exit;
+ }
+ if (a[0] != _a) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "grn_ii_delete_one: a[0] changed %d->%d)",
+ a[0], _a);
+ continue;
+ }
+ if ((pseg = buffer_open(ctx, ii, a[0], &bt, &b)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ DEFINE_NAME(ii);
+ MERR("[ii][delete][one] failed to reallocate a buffer: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "position:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ a[0]);
+ goto exit;
+ }
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "flushed! b=%p free=%d, seg(%d)",
+ b, b->header.buffer_free, LSEG(a[0]));
+ if (b->header.buffer_free < size) {
+ DEFINE_NAME(ii);
+ MERR("[ii][delete][one] buffer is full: "
+ "<%.*s>: "
+ "<%u>:<%u><%u>: "
+ "segment:<%u>, free:<%u>, required:<%u>",
+ name_size, name,
+ u->rid, u->sid, tid,
+ a[0], b->header.buffer_free, size);
+ buffer_close(ctx, ii, pseg);
+ goto exit;
+ }
+ }
+
+ b->header.buffer_free -= size;
+ br = (buffer_rec *)(((byte *)&b->terms[b->header.nterms]) + b->header.buffer_free);
+ buffer_put(ctx, ii, b, bt, br, bs, u, size);
+ buffer_close(ctx, ii, pseg);
+ break;
+ }
+exit :
+ array_unref(ii, tid);
+ if (bs) { GRN_FREE(bs); }
+ return ctx->rc;
+}
+
+#define CHUNK_USED 1
+#define BUFFER_USED 2
+#define SOLE_DOC_USED 4
+#define SOLE_POS_USED 8
+
+struct _grn_ii_cursor {
+ grn_db_obj obj;
+ grn_ctx *ctx;
+ grn_ii *ii;
+ grn_id id;
+ grn_posting *post;
+
+ grn_id min; /* Minimum record ID */
+ grn_id max;
+ grn_posting pc;
+ grn_posting pb;
+
+ uint32_t cdf; /* Document frequency */
+ uint32_t *cdp;
+ uint32_t *crp; /* Record ID */
+ uint32_t *csp; /* Section ID */
+ uint32_t *ctp; /* Term frequency */
+ uint32_t *cwp; /* Weight */
+ uint32_t *cpp; /* Position */
+
+ uint8_t *bp;
+
+ int nelements;
+ uint32_t nchunks;
+ uint32_t curr_chunk;
+ chunk_info *cinfo;
+ grn_io_win iw;
+ uint8_t *cp;
+ uint8_t *cpe;
+ datavec rdv[MAX_N_ELEMENTS + 1];
+
+ struct grn_ii_buffer *buf;
+ uint16_t stat;
+ uint16_t nextb;
+ uint32_t buffer_pseg;
+ int flags;
+ uint32_t *ppseg;
+
+ int weight;
+
+ uint32_t prev_chunk_rid;
+};
+
+static grn_bool
+buffer_is_reused(grn_ctx *ctx, grn_ii *ii, grn_ii_cursor *c)
+{
+ if (*c->ppseg != c->buffer_pseg) {
+ uint32_t i;
+ for (i = ii->header->bgqtail; i != ii->header->bgqhead;
+ i = (i + 1) & (GRN_II_BGQSIZE - 1)) {
+ if (ii->header->bgqbody[i] == c->buffer_pseg) { return GRN_FALSE; }
+ }
+ return GRN_TRUE;
+ }
+ return GRN_FALSE;
+}
+
+static int
+chunk_is_reused(grn_ctx *ctx, grn_ii *ii, grn_ii_cursor *c, uint32_t offset, uint32_t size)
+{
+ if (*c->ppseg != c->buffer_pseg) {
+ uint32_t i, m, gseg;
+ if (size > S_CHUNK) { return 1; }
+ if (size > (1 << GRN_II_W_LEAST_CHUNK)) {
+ int es = size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ } else {
+ m = GRN_II_W_LEAST_CHUNK;
+ }
+ gseg = ii->header->garbages[m - GRN_II_W_LEAST_CHUNK];
+ while (gseg != GRN_II_PSEG_NOT_ASSIGNED) {
+ grn_io_win iw;
+ grn_ii_ginfo *ginfo = WIN_MAP(ii->chunk, ctx, &iw, gseg, 0, S_GARBAGE,
+ grn_io_rdwr);
+ if (!ginfo) { break; }
+ for (i = 0; i < ginfo->nrecs; i++) {
+ if (ginfo->recs[i] == offset) {
+ grn_io_win_unmap(&iw);
+ return 0;
+ }
+ }
+ gseg = ginfo->next;
+ grn_io_win_unmap(&iw);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+#define GRN_II_CURSOR_CMP(c1,c2) \
+ (((c1)->post->rid > (c2)->post->rid) || \
+ (((c1)->post->rid == (c2)->post->rid) && \
+ (((c1)->post->sid > (c2)->post->sid) || \
+ (((c1)->post->sid == (c2)->post->sid) && \
+ ((c1)->post->pos > (c2)->post->pos)))))
+
+grn_ii_cursor *
+grn_ii_cursor_open(grn_ctx *ctx, grn_ii *ii, grn_id tid,
+ grn_id min, grn_id max, int nelements, int flags)
+{
+ grn_ii_cursor *c = NULL;
+ uint32_t pos, *a;
+ if (!(a = array_at(ctx, ii, tid))) { return NULL; }
+ for (;;) {
+ c = NULL;
+ if (!(pos = a[0])) { goto exit; }
+ if (!(c = GRN_MALLOC(sizeof(grn_ii_cursor)))) { goto exit; }
+ memset(c, 0, sizeof(grn_ii_cursor));
+ c->ctx = ctx;
+ c->ii = ii;
+ c->id = tid;
+ c->min = min;
+ c->max = max;
+ c->nelements = nelements;
+ c->flags = flags;
+ c->weight = 0;
+ if (pos & 1) {
+ c->stat = 0;
+ if ((ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ c->pb.rid = BIT31_12(pos);
+ c->pb.sid = BIT11_01(pos);
+ } else {
+ c->pb.rid = pos >> 1;
+ c->pb.sid = 1;
+ }
+ c->pb.tf = 1;
+ c->pb.weight = 0;
+ c->pb.pos = a[1];
+ } else {
+ uint32_t chunk;
+ buffer_term *bt;
+ c->buffer_pseg = buffer_open(ctx, ii, pos, &bt, &c->buf);
+ if (c->buffer_pseg == GRN_II_PSEG_NOT_ASSIGNED) {
+ GRN_FREE(c);
+ c = NULL;
+ goto exit;
+ }
+ c->ppseg = &ii->header->binfo[LSEG(pos)];
+ if (bt->size_in_chunk && (chunk = c->buf->header.chunk) != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (!(c->cp = WIN_MAP(ii->chunk, ctx, &c->iw, chunk, bt->pos_in_chunk,
+ bt->size_in_chunk, grn_io_rdonly))) {
+ buffer_close(ctx, ii, c->buffer_pseg);
+ GRN_FREE(c);
+ c = NULL;
+ goto exit;
+ }
+ if (buffer_is_reused(ctx, ii, c)) {
+ grn_ii_cursor_close(ctx, c);
+ continue;
+ }
+ c->cpe = c->cp + bt->size_in_chunk;
+ if ((bt->tid & CHUNK_SPLIT)) {
+ int i;
+ grn_id crid;
+ GRN_B_DEC(c->nchunks, c->cp);
+ if (chunk_is_reused(ctx, ii, c, chunk, c->buf->header.chunk_size)) {
+ grn_ii_cursor_close(ctx, c);
+ continue;
+ }
+ if (!(c->cinfo = GRN_MALLOCN(chunk_info, c->nchunks))) {
+ buffer_close(ctx, ii, c->buffer_pseg);
+ grn_io_win_unmap(&c->iw);
+ GRN_FREE(c);
+ c = NULL;
+ goto exit;
+ }
+ for (i = 0, crid = GRN_ID_NIL; (uint) i < c->nchunks; i++) {
+ GRN_B_DEC(c->cinfo[i].segno, c->cp);
+ GRN_B_DEC(c->cinfo[i].size, c->cp);
+ GRN_B_DEC(c->cinfo[i].dgap, c->cp);
+ crid += c->cinfo[i].dgap;
+ if (crid < min) {
+ c->pc.rid = crid;
+ c->curr_chunk = i + 1;
+ }
+ }
+ if (chunk_is_reused(ctx, ii, c, chunk, c->buf->header.chunk_size)) {
+ grn_ii_cursor_close(ctx, c);
+ continue;
+ }
+ }
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ c->rdv[ii->n_elements - 1].flags = ODD;
+ }
+ }
+ c->nextb = bt->pos_in_buffer;
+ c->stat = CHUNK_USED|BUFFER_USED;
+ }
+ if (pos == a[0]) { break; }
+ grn_ii_cursor_close(ctx, c);
+ }
+exit :
+ array_unref(ii, tid);
+ return c;
+}
+
+static inline void
+grn_ii_cursor_set_min(grn_ctx *ctx, grn_ii_cursor *c, grn_id min)
+{
+ if (c->min >= min) {
+ return;
+ }
+
+ if (grn_ii_cursor_set_min_enable) {
+ grn_id old_min = c->min;
+ c->min = min;
+ if (c->buf &&
+ c->pc.rid != GRN_ID_NIL &&
+ c->pc.rid < c->min &&
+ c->prev_chunk_rid < c->min &&
+ c->curr_chunk < c->nchunks) {
+ uint32_t i;
+ uint32_t skip_chunk = 0;
+ grn_id rid = c->prev_chunk_rid;
+
+ if (c->curr_chunk > 0) {
+ i = c->curr_chunk - 1;
+ } else {
+ i = 0;
+ }
+ for (; i < c->nchunks; i++) {
+ rid += c->cinfo[i].dgap;
+ if (rid < c->min) {
+ skip_chunk = i + 1;
+ } else {
+ rid -= c->cinfo[i].dgap;
+ break;
+ }
+ }
+ if (skip_chunk > c->curr_chunk) {
+ uint32_t old_chunk = c->curr_chunk;
+ grn_bool old_chunk_used = (c->stat & CHUNK_USED);
+ c->pc.rid = rid;
+ c->pc.rest = 0;
+ c->prev_chunk_rid = rid - c->cinfo[skip_chunk - 1].dgap;
+ c->curr_chunk = skip_chunk;
+ c->crp = c->cdp + c->cdf;
+ c->stat |= CHUNK_USED;
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "[ii][cursor][min] skip: %p: min(%u->%u): chunk(%u->%u): "
+ "chunk-used(%-.256s->%-.256s)",
+ c,
+ old_min, min,
+ old_chunk, c->curr_chunk,
+ old_chunk_used ? "true" : "false",
+ (c->stat & CHUNK_USED) ? "true" : "false");
+ }
+ }
+ }
+}
+
+typedef struct {
+ grn_bool include_garbage;
+} grn_ii_cursor_next_options;
+
+static inline grn_posting *
+grn_ii_cursor_next_internal(grn_ctx *ctx, grn_ii_cursor *c,
+ grn_ii_cursor_next_options *options)
+{
+ const grn_bool include_garbage = options->include_garbage;
+ if (c->buf) {
+ for (;;) {
+ if (c->stat & CHUNK_USED) {
+ for (;;) {
+ if (c->crp < c->cdp + c->cdf) {
+ uint32_t dgap = *c->crp++;
+ c->pc.rid += dgap;
+ if (dgap) { c->pc.sid = 0; }
+ if ((c->ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ c->pc.sid += 1 + *c->csp++;
+ } else {
+ c->pc.sid = 1;
+ }
+ c->cpp += c->pc.rest;
+ c->pc.rest = c->pc.tf = 1 + *c->ctp++;
+ if ((c->ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ c->pc.weight = *c->cwp++;
+ } else {
+ c->pc.weight = 0;
+ }
+ c->pc.pos = 0;
+ /*
+ {
+ static int count = 0;
+ int tf = c->pc.tf, pos = 0, *pp = (int *)c->cpp;
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ grn_text_itoa(ctx, &buf, c->pc.rid);
+ GRN_TEXT_PUTC(ctx, &buf, ':');
+ grn_text_itoa(ctx, &buf, c->pc.sid);
+ GRN_TEXT_PUTC(ctx, &buf, ':');
+ grn_text_itoa(ctx, &buf, c->pc.tf);
+ GRN_TEXT_PUTC(ctx, &buf, '(');
+ while (tf--) {
+ pos += *pp++;
+ count++;
+ grn_text_itoa(ctx, &buf, pos);
+ if (tf) { GRN_TEXT_PUTC(ctx, &buf, ':'); }
+ }
+ GRN_TEXT_PUTC(ctx, &buf, ')');
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "posting(%d):%-.256s", count, GRN_TEXT_VALUE(&buf));
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ */
+ } else {
+ if (c->curr_chunk <= c->nchunks) {
+ if (c->curr_chunk == c->nchunks) {
+ if (c->cp < c->cpe) {
+ int decoded_size;
+ decoded_size =
+ grn_p_decv(ctx, c->cp, c->cpe - c->cp,
+ c->rdv, c->ii->n_elements);
+ if (decoded_size == 0) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][chunk][last] "
+ "chunk(%d) is changed by another thread "
+ "while decoding: %p",
+ c->cinfo[c->curr_chunk].segno,
+ c);
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ if (buffer_is_reused(ctx, c->ii, c)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][chunk][last] "
+ "buffer is reused by another thread: %p",
+ c);
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ if (chunk_is_reused(ctx, c->ii, c,
+ c->buf->header.chunk,
+ c->buf->header.chunk_size)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][chunk][last] "
+ "chunk(%d) is reused by another thread: %p",
+ c->buf->header.chunk,
+ c);
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ } else {
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ } else {
+ uint8_t *cp;
+ grn_io_win iw;
+ uint32_t size = c->cinfo[c->curr_chunk].size;
+ if (size && (cp = WIN_MAP(c->ii->chunk, ctx, &iw,
+ c->cinfo[c->curr_chunk].segno, 0,
+ size, grn_io_rdonly))) {
+ int decoded_size;
+ decoded_size =
+ grn_p_decv(ctx, cp, size, c->rdv, c->ii->n_elements);
+ grn_io_win_unmap(&iw);
+ if (decoded_size == 0) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][chunk] "
+ "chunk(%d) is changed by another thread "
+ "while decoding: %p",
+ c->cinfo[c->curr_chunk].segno,
+ c);
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ if (chunk_is_reused(ctx, c->ii, c,
+ c->cinfo[c->curr_chunk].segno, size)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][chunk] "
+ "chunk(%d) is reused by another thread: %p",
+ c->cinfo[c->curr_chunk].segno,
+ c);
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ } else {
+ c->pc.rid = GRN_ID_NIL;
+ break;
+ }
+ }
+ {
+ int j = 0;
+ c->cdf = c->rdv[j].data_size;
+ c->crp = c->cdp = c->rdv[j++].data;
+ if ((c->ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ c->csp = c->rdv[j++].data;
+ }
+ c->ctp = c->rdv[j++].data;
+ if ((c->ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ c->cwp = c->rdv[j++].data;
+ }
+ if ((c->ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ c->cpp = c->rdv[j].data;
+ }
+ }
+ c->prev_chunk_rid = c->pc.rid;
+ c->pc.rid = GRN_ID_NIL;
+ c->pc.sid = 0;
+ c->pc.rest = 0;
+ c->curr_chunk++;
+ continue;
+ } else {
+ c->pc.rid = GRN_ID_NIL;
+ }
+ }
+ break;
+ }
+ }
+ if (c->stat & BUFFER_USED) {
+ for (;;) {
+ if (c->nextb) {
+ uint32_t lrid = c->pb.rid, lsid = c->pb.sid; /* for check */
+ buffer_rec *br = BUFFER_REC_AT(c->buf, c->nextb);
+ if (buffer_is_reused(ctx, c->ii, c)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][buffer] "
+ "buffer(%d,%d) is reused by another thread: %p",
+ c->buffer_pseg, *c->ppseg,
+ c);
+ c->pb.rid = GRN_ID_NIL;
+ break;
+ }
+ c->bp = GRN_NEXT_ADDR(br);
+ GRN_B_DEC(c->pb.rid, c->bp);
+ if ((c->ii->header->flags & GRN_OBJ_WITH_SECTION)) {
+ GRN_B_DEC(c->pb.sid, c->bp);
+ } else {
+ c->pb.sid = 1;
+ }
+ if (lrid > c->pb.rid || (lrid == c->pb.rid && lsid >= c->pb.sid)) {
+ DEFINE_NAME(c->ii);
+ ERR(GRN_FILE_CORRUPT,
+ "[ii][broken][cursor][next][buffer] "
+ "posting in list in buffer isn't sorted: "
+ "<%.*s>: (%d:%d) -> (%d:%d) (%d->%d)",
+ name_size, name,
+ lrid, lsid,
+ c->pb.rid, c->pb.sid,
+ c->buffer_pseg, *c->ppseg);
+ c->pb.rid = GRN_ID_NIL;
+ break;
+ }
+ if (c->pb.rid < c->min) {
+ c->pb.rid = 0;
+ if (br->jump > 0 && !BUFFER_REC_DELETED(br)) {
+ buffer_rec *jump_br = BUFFER_REC_AT(c->buf, br->jump);
+ if (BUFFER_REC_DELETED(jump_br)) {
+ c->nextb = br->step;
+ } else {
+ uint8_t *jump_bp;
+ uint32_t jump_rid;
+ jump_bp = GRN_NEXT_ADDR(jump_br);
+ GRN_B_DEC(jump_rid, jump_bp);
+ if (jump_rid < c->min) {
+ c->nextb = br->jump;
+ } else {
+ c->nextb = br->step;
+ }
+ }
+ } else {
+ c->nextb = br->step;
+ }
+ continue;
+ }
+ c->nextb = br->step;
+ GRN_B_DEC(c->pb.tf, c->bp);
+ if ((c->ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ GRN_B_DEC(c->pb.weight, c->bp);
+ } else {
+ c->pb.weight = 0;
+ }
+ c->pb.rest = c->pb.tf;
+ c->pb.pos = 0;
+ } else {
+ c->pb.rid = 0;
+ }
+ break;
+ }
+ }
+ if (c->pb.rid) {
+ if (c->pc.rid) {
+ if (c->pc.rid < c->pb.rid) {
+ c->stat = CHUNK_USED;
+ if (include_garbage || (c->pc.tf && c->pc.sid)) {
+ c->post = &c->pc;
+ break;
+ }
+ } else {
+ if (c->pb.rid < c->pc.rid) {
+ c->stat = BUFFER_USED;
+ if (include_garbage || (c->pb.tf && c->pb.sid)) {
+ c->post = &c->pb;
+ break;
+ }
+ } else {
+ if (c->pb.sid) {
+ if (c->pc.sid < c->pb.sid) {
+ c->stat = CHUNK_USED;
+ if (include_garbage || (c->pc.tf && c->pc.sid)) {
+ c->post = &c->pc;
+ break;
+ }
+ } else {
+ c->stat = BUFFER_USED;
+ if (c->pb.sid == c->pc.sid) { c->stat |= CHUNK_USED; }
+ if (include_garbage || (c->pb.tf)) {
+ c->post = &c->pb;
+ break;
+ }
+ }
+ } else {
+ c->stat = CHUNK_USED;
+ }
+ }
+ }
+ } else {
+ c->stat = BUFFER_USED;
+ if (include_garbage || (c->pb.tf && c->pb.sid)) {
+ c->post = &c->pb;
+ break;
+ }
+ }
+ } else {
+ if (c->pc.rid) {
+ c->stat = CHUNK_USED;
+ if (include_garbage || (c->pc.tf && c->pc.sid)) {
+ c->post = &c->pc;
+ break;
+ }
+ } else {
+ c->post = NULL;
+ return NULL;
+ }
+ }
+ }
+ } else {
+ if (c->stat & SOLE_DOC_USED) {
+ c->post = NULL;
+ return NULL;
+ } else {
+ c->post = &c->pb;
+ c->stat |= SOLE_DOC_USED;
+ if (c->post->rid < c->min) {
+ c->post = NULL;
+ return NULL;
+ }
+ }
+ }
+ return c->post;
+}
+
+grn_posting *
+grn_ii_cursor_next(grn_ctx *ctx, grn_ii_cursor *c)
+{
+ grn_ii_cursor_next_options options = {
+ .include_garbage = GRN_FALSE
+ };
+ return grn_ii_cursor_next_internal(ctx, c, &options);
+}
+
+grn_posting *
+grn_ii_cursor_next_pos(grn_ctx *ctx, grn_ii_cursor *c)
+{
+ uint32_t gap;
+ if ((c->ii->header->flags & GRN_OBJ_WITH_POSITION)) {
+ if (c->nelements == (int) c->ii->n_elements) {
+ if (c->buf) {
+ if (c->post == &c->pc) {
+ if (c->pc.rest) {
+ c->pc.rest--;
+ c->pc.pos += *c->cpp++;
+ } else {
+ return NULL;
+ }
+ } else if (c->post == &c->pb) {
+ if (buffer_is_reused(ctx, c->ii, c)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][cursor][next][pos][buffer] "
+ "buffer(%d,%d) is reused by another thread: %p",
+ c->buffer_pseg, *c->ppseg,
+ c);
+ return NULL;
+ }
+ if (c->pb.rest) {
+ c->pb.rest--;
+ GRN_B_DEC(gap, c->bp);
+ c->pb.pos += gap;
+ } else {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ } else {
+ if (c->stat & SOLE_POS_USED) {
+ return NULL;
+ } else {
+ c->stat |= SOLE_POS_USED;
+ }
+ }
+ }
+ } else {
+ if (c->stat & SOLE_POS_USED) {
+ return NULL;
+ } else {
+ c->stat |= SOLE_POS_USED;
+ }
+ }
+ return c->post;
+}
+
+grn_rc
+grn_ii_cursor_close(grn_ctx *ctx, grn_ii_cursor *c)
+{
+ if (!c) { return GRN_INVALID_ARGUMENT; }
+ datavec_fin(ctx, c->rdv);
+ if (c->cinfo) { GRN_FREE(c->cinfo); }
+ if (c->buf) { buffer_close(ctx, c->ii, c->buffer_pseg); }
+ if (c->cp) { grn_io_win_unmap(&c->iw); }
+ GRN_FREE(c);
+ return GRN_SUCCESS;
+}
+
+uint32_t
+grn_ii_get_chunksize(grn_ctx *ctx, grn_ii *ii, grn_id tid)
+{
+ uint32_t res, pos, *a;
+ a = array_at(ctx, ii, tid);
+ if (!a) { return 0; }
+ if ((pos = a[0])) {
+ if (pos & 1) {
+ res = 0;
+ } else {
+ buffer *buf;
+ uint32_t pseg;
+ buffer_term *bt;
+ if ((pseg = buffer_open(ctx, ii, pos, &bt, &buf)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ res = 0;
+ } else {
+ res = bt->size_in_chunk;
+ buffer_close(ctx, ii, pseg);
+ }
+ }
+ } else {
+ res = 0;
+ }
+ array_unref(ii, tid);
+ return res;
+}
+
+uint32_t
+grn_ii_estimate_size(grn_ctx *ctx, grn_ii *ii, grn_id tid)
+{
+ uint32_t res, pos, *a;
+ a = array_at(ctx, ii, tid);
+ if (!a) { return 0; }
+ if ((pos = a[0])) {
+ if (pos & 1) {
+ res = 1;
+ } else {
+ buffer *buf;
+ uint32_t pseg;
+ buffer_term *bt;
+ if ((pseg = buffer_open(ctx, ii, pos, &bt, &buf)) == GRN_II_PSEG_NOT_ASSIGNED) {
+ res = 0;
+ } else {
+ res = a[1] + bt->size_in_buffer + 2;
+ buffer_close(ctx, ii, pseg);
+ }
+ }
+ } else {
+ res = 0;
+ }
+ array_unref(ii, tid);
+ return res;
+}
+
+int
+grn_ii_entry_info(grn_ctx *ctx, grn_ii *ii, grn_id tid, unsigned int *a,
+ unsigned int *chunk, unsigned int *chunk_size,
+ unsigned int *buffer_free,
+ unsigned int *nterms, unsigned int *nterms_void,
+ unsigned int *bt_tid,
+ unsigned int *size_in_chunk, unsigned int *pos_in_chunk,
+ unsigned int *size_in_buffer, unsigned int *pos_in_buffer)
+{
+ buffer *b;
+ buffer_term *bt;
+ uint32_t pseg, *ap;
+ ERRCLR(NULL);
+ ap = array_at(ctx, ii, tid);
+ if (!ap) { return 0; }
+ a[0] = *ap;
+ array_unref(ii, tid);
+ if (!a[0]) { return 1; }
+ if (a[0] & 1) { return 2; }
+ if ((pseg = buffer_open(ctx, ii, a[0], &bt, &b)) == GRN_II_PSEG_NOT_ASSIGNED) { return 3; }
+ *chunk = b->header.chunk;
+ *chunk_size = b->header.chunk_size;
+ *buffer_free = b->header.buffer_free;
+ *nterms = b->header.nterms;
+ *bt_tid = bt->tid;
+ *size_in_chunk = bt->size_in_chunk;
+ *pos_in_chunk = bt->pos_in_chunk;
+ *size_in_buffer = bt->size_in_buffer;
+ *pos_in_buffer = bt->pos_in_buffer;
+ buffer_close(ctx, ii, pseg);
+ return 4;
+}
+
+const char *
+grn_ii_path(grn_ii *ii)
+{
+ return grn_io_path(ii->seg);
+}
+
+uint32_t
+grn_ii_max_section(grn_ii *ii)
+{
+ return ii->header->smax;
+}
+
+grn_obj *
+grn_ii_lexicon(grn_ii *ii)
+{
+ return ii->lexicon;
+}
+
+/* private classes */
+
+/* b-heap */
+
+typedef struct {
+ int n_entries;
+ int n_bins;
+ grn_ii_cursor **bins;
+} cursor_heap;
+
+static inline cursor_heap *
+cursor_heap_open(grn_ctx *ctx, int max)
+{
+ cursor_heap *h = GRN_MALLOC(sizeof(cursor_heap));
+ if (!h) { return NULL; }
+ h->bins = GRN_MALLOC(sizeof(grn_ii_cursor *) * max);
+ if (!h->bins) {
+ GRN_FREE(h);
+ return NULL;
+ }
+ h->n_entries = 0;
+ h->n_bins = max;
+ return h;
+}
+
+static inline grn_rc
+cursor_heap_push(grn_ctx *ctx, cursor_heap *h, grn_ii *ii, grn_id tid, uint32_t offset2,
+ int weight, grn_id min)
+{
+ int n, n2;
+ grn_ii_cursor *c, *c2;
+ if (h->n_entries >= h->n_bins) {
+ int max = h->n_bins * 2;
+ grn_ii_cursor **bins = GRN_REALLOC(h->bins, sizeof(grn_ii_cursor *) * max);
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "expanded cursor_heap to %d,%p", max, bins);
+ if (!bins) { return GRN_NO_MEMORY_AVAILABLE; }
+ h->n_bins = max;
+ h->bins = bins;
+ }
+ {
+ if (!(c = grn_ii_cursor_open(ctx, ii, tid, min, GRN_ID_MAX,
+ ii->n_elements, 0))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "cursor open failed");
+ return ctx->rc;
+ }
+ if (!grn_ii_cursor_next(ctx, c)) {
+ grn_ii_cursor_close(ctx, c);
+ return GRN_END_OF_DATA;
+ }
+ if (!grn_ii_cursor_next_pos(ctx, c)) {
+ if (grn_logger_pass(ctx, GRN_LOG_ERROR)) {
+ char token[GRN_TABLE_MAX_KEY_SIZE];
+ int token_size;
+ token_size = grn_table_get_key(ctx,
+ c->ii->lexicon,
+ c->id,
+ &token,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "[ii][cursor][heap][push] invalid cursor: "
+ "%p: token:<%.*s>(%u)",
+ c, token_size, token, c->id);
+ }
+ grn_ii_cursor_close(ctx, c);
+ return GRN_END_OF_DATA;
+ }
+ if (weight) {
+ c->weight = weight;
+ }
+ n = h->n_entries++;
+ while (n) {
+ n2 = (n - 1) >> 1;
+ c2 = h->bins[n2];
+ if (GRN_II_CURSOR_CMP(c, c2)) { break; }
+ h->bins[n] = c2;
+ n = n2;
+ }
+ h->bins[n] = c;
+ }
+ return GRN_SUCCESS;
+}
+
+static inline grn_rc
+cursor_heap_push2(cursor_heap *h)
+{
+ grn_rc rc = GRN_SUCCESS;
+ return rc;
+}
+
+static inline grn_ii_cursor *
+cursor_heap_min(cursor_heap *h)
+{
+ return h->n_entries ? h->bins[0] : NULL;
+}
+
+static inline void
+cursor_heap_recalc_min(cursor_heap *h)
+{
+ int n = 0, n1, n2, m;
+ if ((m = h->n_entries) > 1) {
+ grn_ii_cursor *c = h->bins[0], *c1, *c2;
+ for (;;) {
+ n1 = n * 2 + 1;
+ n2 = n1 + 1;
+ c1 = n1 < m ? h->bins[n1] : NULL;
+ c2 = n2 < m ? h->bins[n2] : NULL;
+ if (c1 && GRN_II_CURSOR_CMP(c, c1)) {
+ if (c2 && GRN_II_CURSOR_CMP(c, c2) && GRN_II_CURSOR_CMP(c1, c2)) {
+ h->bins[n] = c2;
+ n = n2;
+ } else {
+ h->bins[n] = c1;
+ n = n1;
+ }
+ } else {
+ if (c2 && GRN_II_CURSOR_CMP(c, c2)) {
+ h->bins[n] = c2;
+ n = n2;
+ } else {
+ h->bins[n] = c;
+ break;
+ }
+ }
+ }
+ }
+}
+
+static inline void
+cursor_heap_pop(grn_ctx *ctx, cursor_heap *h, grn_id min)
+{
+ if (h->n_entries) {
+ grn_ii_cursor *c = h->bins[0];
+ grn_ii_cursor_set_min(ctx, c, min);
+ if (!grn_ii_cursor_next(ctx, c)) {
+ grn_ii_cursor_close(ctx, c);
+ h->bins[0] = h->bins[--h->n_entries];
+ } else if (!grn_ii_cursor_next_pos(ctx, c)) {
+ if (grn_logger_pass(ctx, GRN_LOG_ERROR)) {
+ char token[GRN_TABLE_MAX_KEY_SIZE];
+ int token_size;
+ token_size = grn_table_get_key(ctx,
+ c->ii->lexicon,
+ c->id,
+ &token,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "[ii][cursor][heap][pop] invalid cursor: "
+ "%p: token:<%.*s>(%u)",
+ c, token_size, token, c->id);
+ }
+ grn_ii_cursor_close(ctx, c);
+ h->bins[0] = h->bins[--h->n_entries];
+ }
+ if (h->n_entries > 1) { cursor_heap_recalc_min(h); }
+ }
+}
+
+static inline void
+cursor_heap_pop_pos(grn_ctx *ctx, cursor_heap *h)
+{
+ if (h->n_entries) {
+ grn_ii_cursor *c = h->bins[0];
+ if (!grn_ii_cursor_next_pos(ctx, c)) {
+ if (!grn_ii_cursor_next(ctx, c)) {
+ grn_ii_cursor_close(ctx, c);
+ h->bins[0] = h->bins[--h->n_entries];
+ } else if (!grn_ii_cursor_next_pos(ctx, c)) {
+ if (grn_logger_pass(ctx, GRN_LOG_ERROR)) {
+ char token[GRN_TABLE_MAX_KEY_SIZE];
+ int token_size;
+ token_size = grn_table_get_key(ctx,
+ c->ii->lexicon,
+ c->id,
+ &token,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "[ii][cursor][heap][pop][position] invalid cursor: "
+ "%p: token:<%.*s>(%u)",
+ c, token_size, token, c->id);
+ }
+ grn_ii_cursor_close(ctx, c);
+ h->bins[0] = h->bins[--h->n_entries];
+ }
+ }
+ if (h->n_entries > 1) { cursor_heap_recalc_min(h); }
+ }
+}
+
+static inline void
+cursor_heap_close(grn_ctx *ctx, cursor_heap *h)
+{
+ int i;
+ if (!h) { return; }
+ for (i = h->n_entries; i--;) { grn_ii_cursor_close(ctx, h->bins[i]); }
+ GRN_FREE(h->bins);
+ GRN_FREE(h);
+}
+
+/* update */
+#ifdef USE_VGRAM
+
+inline static grn_rc
+index_add(grn_ctx *ctx, grn_id rid, grn_obj *lexicon, grn_ii *ii, grn_vgram *vgram,
+ const char *value, size_t value_len)
+{
+ grn_hash *h;
+ unsigned int token_flags = 0;
+ grn_token_cursor *token_cursor;
+ grn_ii_updspec **u;
+ grn_id tid, *tp;
+ grn_rc r, rc = GRN_SUCCESS;
+ grn_vgram_buf *sbuf = NULL;
+ if (!rid) { return GRN_INVALID_ARGUMENT; }
+ if (!(token_cursor = grn_token_cursor_open(ctx, lexicon, value, value_len,
+ GRN_TOKEN_ADD, token_flags))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (vgram) { sbuf = grn_vgram_buf_open(value_len); }
+ h = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!h) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_hash_create on index_add failed !");
+ grn_token_cursor_close(ctx, token_cursor);
+ if (sbuf) { grn_vgram_buf_close(sbuf); }
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ while (!token_cursor->status) {
+ (tid = grn_token_cursor_next(ctx, token_cursor));
+ if (tid) {
+ if (!grn_hash_add(ctx, h, &tid, sizeof(grn_id), (void **) &u, NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, 1))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "grn_ii_updspec_open on index_add failed!");
+ goto exit;
+ }
+ }
+ if (grn_ii_updspec_add(ctx, *u, token_cursor->pos, 0)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "grn_ii_updspec_add on index_add failed!");
+ goto exit;
+ }
+ if (sbuf) { grn_vgram_buf_add(sbuf, tid); }
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ // todo : support vgram
+ // if (sbuf) { grn_vgram_update(vgram, rid, sbuf, (grn_set *)h); }
+ GRN_HASH_EACH(ctx, h, id, &tp, NULL, &u, {
+ if ((r = grn_ii_update_one(ctx, ii, *tp, *u, h))) { rc = r; }
+ grn_ii_updspec_close(ctx, *u);
+ });
+ grn_hash_close(ctx, h);
+ if (sbuf) { grn_vgram_buf_close(sbuf); }
+ return rc;
+exit:
+ grn_hash_close(ctx, h);
+ grn_token_cursor_close(ctx, token_cursor);
+ if (sbuf) { grn_vgram_buf_close(sbuf); }
+ return GRN_NO_MEMORY_AVAILABLE;
+}
+
+inline static grn_rc
+index_del(grn_ctx *ctx, grn_id rid, grn_obj *lexicon, grn_ii *ii, grn_vgram *vgram,
+ const char *value, size_t value_len)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_hash *h;
+ unsigned int token_flags = 0;
+ grn_token_cursor *token_cursor;
+ grn_ii_updspec **u;
+ grn_id tid, *tp;
+ if (!rid) { return GRN_INVALID_ARGUMENT; }
+ if (!(token_cursor = grn_token_cursor_open(ctx, lexicon, value, value_len,
+ GRN_TOKEN_DEL, token_flags))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ h = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!h) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_hash_create on index_del failed !");
+ grn_token_cursor_close(ctx, token_cursor);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ while (!token_cursor->status) {
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ if (!grn_hash_add(ctx, h, &tid, sizeof(grn_id), (void **) &u, NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, 0))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_open on index_del failed !");
+ grn_hash_close(ctx, h);
+ grn_token_cursor_close(ctx, token_cursor);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ GRN_HASH_EACH(ctx, h, id, &tp, NULL, &u, {
+ if (*tp) {
+ grn_rc r;
+ r = grn_ii_delete_one(ctx, ii, *tp, *u, NULL);
+ if (r) {
+ rc = r;
+ }
+ }
+ grn_ii_updspec_close(ctx, *u);
+ });
+ grn_hash_close(ctx, h);
+ return rc;
+}
+
+grn_rc
+grn_ii_upd(grn_ctx *ctx, grn_ii *ii, grn_id rid, grn_vgram *vgram,
+ const char *oldvalue, unsigned int oldvalue_len,
+ const char *newvalue, unsigned int newvalue_len)
+{
+ grn_rc rc;
+ grn_obj *lexicon = ii->lexicon;
+ if (!rid) { return GRN_INVALID_ARGUMENT; }
+ if (oldvalue && *oldvalue) {
+ if ((rc = index_del(ctx, rid, lexicon, ii, vgram, oldvalue, oldvalue_len))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "index_del on grn_ii_upd failed !");
+ goto exit;
+ }
+ }
+ if (newvalue && *newvalue) {
+ rc = index_add(ctx, rid, lexicon, ii, vgram, newvalue, newvalue_len);
+ }
+exit :
+ return rc;
+}
+
+grn_rc
+grn_ii_update(grn_ctx *ctx, grn_ii *ii, grn_id rid, grn_vgram *vgram, unsigned int section,
+ grn_values *oldvalues, grn_values *newvalues)
+{
+ int j;
+ grn_value *v;
+ unsigned int token_flags = 0;
+ grn_token_cursor *token_cursor;
+ grn_rc rc = GRN_SUCCESS;
+ grn_hash *old, *new;
+ grn_id tid, *tp;
+ grn_ii_updspec **u, **un;
+ grn_obj *lexicon = ii->lexicon;
+ if (!lexicon || !ii || !rid) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "grn_ii_update: invalid argument");
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (newvalues) {
+ new = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!new) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_hash_create on grn_ii_update failed !");
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ for (j = newvalues->n_values, v = newvalues->values; j; j--, v++) {
+ if ((token_cursor = grn_token_cursor_open(ctx, lexicon, v->str,
+ v->str_len, GRN_TOKEN_ADD,
+ token_flags))) {
+ while (!token_cursor->status) {
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ if (!grn_hash_add(ctx, new, &tid, sizeof(grn_id), (void **) &u,
+ NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, section))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_open on grn_ii_update failed!");
+ grn_token_cursor_close(ctx, token_cursor);
+ grn_hash_close(ctx, new);
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ }
+ if (grn_ii_updspec_add(ctx, *u, token_cursor->pos, v->weight)) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_add on grn_ii_update failed!");
+ grn_token_cursor_close(ctx, token_cursor);
+ grn_hash_close(ctx, new);
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ }
+ if (!GRN_HASH_SIZE(new)) {
+ grn_hash_close(ctx, new);
+ new = NULL;
+ }
+ } else {
+ new = NULL;
+ }
+ if (oldvalues) {
+ old = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!old) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_hash_create(ctx, NULL, old) on grn_ii_update failed!");
+ if (new) { grn_hash_close(ctx, new); }
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ for (j = oldvalues->n_values, v = oldvalues->values; j; j--, v++) {
+ if ((token_cursor = grn_token_cursor_open(ctx, lexicon, v->str,
+ v->str_len, GRN_TOKEN_DEL,
+ token_flags))) {
+ while (!token_cursor->status) {
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ if (!grn_hash_add(ctx, old, &tid, sizeof(grn_id), (void **) &u,
+ NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, section))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_open on grn_ii_update failed!");
+ grn_token_cursor_close(ctx, token_cursor);
+ if (new) { grn_hash_close(ctx, new); };
+ grn_hash_close(ctx, old);
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ }
+ if (grn_ii_updspec_add(ctx, *u, token_cursor->pos, v->weight)) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_add on grn_ii_update failed!");
+ grn_token_cursor_close(ctx, token_cursor);
+ if (new) { grn_hash_close(ctx, new); };
+ grn_hash_close(ctx, old);
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ }
+ } else {
+ old = NULL;
+ }
+ if (old) {
+ grn_id eid;
+ GRN_HASH_EACH(ctx, old, id, &tp, NULL, &u, {
+ if (new && (eid = grn_hash_get(ctx, new, tp, sizeof(grn_id),
+ (void **) &un))) {
+ if (!grn_ii_updspec_cmp(*u, *un)) {
+ grn_ii_updspec_close(ctx, *un);
+ grn_hash_delete_by_id(ctx, new, eid, NULL);
+ }
+ } else {
+ grn_rc r;
+ r = grn_ii_delete_one(ctx, ii, *tp, *u, new);
+ if (r) {
+ rc = r;
+ }
+ }
+ grn_ii_updspec_close(ctx, *u);
+ });
+ grn_hash_close(ctx, old);
+ }
+ if (new) {
+ GRN_HASH_EACH(ctx, new, id, &tp, NULL, &u, {
+ grn_rc r;
+ if ((r = grn_ii_update_one(ctx, ii, *tp, *u, new))) { rc = r; }
+ grn_ii_updspec_close(ctx, *u);
+ });
+ grn_hash_close(ctx, new);
+ } else {
+ if (!section) {
+ /* todo: delete key when all sections deleted */
+ }
+ }
+exit :
+ return rc;
+}
+#endif /* USE_VGRAM */
+
+static grn_rc
+grn_vector2updspecs(grn_ctx *ctx, grn_ii *ii, grn_id rid, unsigned int section,
+ grn_obj *in, grn_obj *out, grn_tokenize_mode mode,
+ grn_obj *posting)
+{
+ int j;
+ grn_id tid;
+ grn_section *v;
+ grn_token_cursor *token_cursor;
+ grn_ii_updspec **u;
+ grn_hash *h = (grn_hash *)out;
+ grn_obj *lexicon = ii->lexicon;
+ if (in->u.v.body) {
+ const char *head = GRN_BULK_HEAD(in->u.v.body);
+ for (j = in->u.v.n_sections, v = in->u.v.sections; j; j--, v++) {
+ unsigned int token_flags = 0;
+ if (v->length &&
+ (token_cursor = grn_token_cursor_open(ctx, lexicon, head + v->offset,
+ v->length, mode,
+ token_flags))) {
+ while (!token_cursor->status) {
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ if (posting) { GRN_RECORD_PUT(ctx, posting, tid); }
+ if (!grn_hash_add(ctx, h, &tid, sizeof(grn_id), (void **) &u,
+ NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, section))) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][spec] failed to create an update spec: "
+ "<%.*s>: "
+ "record:<%u>:<%u>, token:<%u>:<%d>:<%u>",
+ name_size, name,
+ rid, section,
+ tid, token_cursor->pos, v->weight);
+ grn_token_cursor_close(ctx, token_cursor);
+ return ctx->rc;
+ }
+ }
+ if (grn_ii_updspec_add(ctx, *u, token_cursor->pos, v->weight)) {
+ DEFINE_NAME(ii);
+ MERR("[ii][update][spec] failed to add to update spec: "
+ "<%.*s>: "
+ "record:<%u>:<%u>, token:<%u>:<%d>:<%u>",
+ name_size, name,
+ rid, section,
+ tid, token_cursor->pos, v->weight);
+ grn_token_cursor_close(ctx, token_cursor);
+ return ctx->rc;
+ }
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ }
+ }
+ return ctx->rc;
+}
+
+static grn_rc
+grn_uvector2updspecs_data(grn_ctx *ctx, grn_ii *ii, grn_id rid,
+ unsigned int section, grn_obj *in, grn_obj *out,
+ grn_tokenize_mode mode, grn_obj *posting)
+{
+ int i, n;
+ grn_hash *h = (grn_hash *)out;
+ grn_obj *lexicon = ii->lexicon;
+ unsigned int element_size;
+
+ n = grn_uvector_size(ctx, in);
+ element_size = grn_uvector_element_size(ctx, in);
+ for (i = 0; i < n; i++) {
+ grn_obj *tokenizer;
+ grn_token_cursor *token_cursor;
+ unsigned int token_flags = 0;
+ const char *element;
+
+ tokenizer = grn_obj_get_info(ctx, lexicon, GRN_INFO_DEFAULT_TOKENIZER,
+ NULL);
+
+ element = GRN_BULK_HEAD(in) + (element_size * i);
+ token_cursor = grn_token_cursor_open(ctx, lexicon,
+ element, element_size,
+ mode, token_flags);
+ if (!token_cursor) {
+ continue;
+ }
+
+ while (!token_cursor->status) {
+ grn_id tid;
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ grn_ii_updspec **u;
+ int pos;
+
+ if (posting) { GRN_RECORD_PUT(ctx, posting, tid); }
+ if (!grn_hash_add(ctx, h, &tid, sizeof(grn_id), (void **)&u, NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, section))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_open on grn_uvector2updspecs_data failed!");
+ grn_token_cursor_close(ctx, token_cursor);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ if (tokenizer) {
+ pos = token_cursor->pos;
+ } else {
+ pos = i;
+ }
+ if (grn_ii_updspec_add(ctx, *u, pos, 0)) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_add on grn_uvector2updspecs failed!");
+ grn_token_cursor_close(ctx, token_cursor);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ }
+
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_uvector2updspecs_id(grn_ctx *ctx, grn_ii *ii, grn_id rid,
+ unsigned int section, grn_obj *in, grn_obj *out)
+{
+ int i, n;
+ grn_ii_updspec **u;
+ grn_hash *h = (grn_hash *)out;
+
+ n = grn_vector_size(ctx, in);
+ for (i = 0; i < n; i++) {
+ grn_id id;
+ unsigned int weight;
+
+ id = grn_uvector_get_element(ctx, in, i, &weight);
+ if (!grn_hash_add(ctx, h, &id, sizeof(grn_id), (void **)&u, NULL)) {
+ break;
+ }
+ if (!*u) {
+ if (!(*u = grn_ii_updspec_open(ctx, rid, section))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_open on grn_ii_update failed!");
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ if (grn_ii_updspec_add(ctx, *u, i, weight)) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_ii_updspec_add on grn_ii_update failed!");
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_uvector2updspecs(grn_ctx *ctx, grn_ii *ii, grn_id rid,
+ unsigned int section, grn_obj *in, grn_obj *out,
+ grn_tokenize_mode mode, grn_obj *posting)
+{
+ if (in->header.domain < GRN_N_RESERVED_TYPES) {
+ return grn_uvector2updspecs_data(ctx, ii, rid, section, in, out,
+ mode, posting);
+ } else {
+ return grn_uvector2updspecs_id(ctx, ii, rid, section, in, out);
+ }
+}
+
+grn_rc
+grn_ii_column_update(grn_ctx *ctx, grn_ii *ii, grn_id rid, unsigned int section,
+ grn_obj *oldvalue, grn_obj *newvalue, grn_obj *posting)
+{
+ grn_id *tp;
+ grn_bool do_grn_ii_updspec_cmp = GRN_TRUE;
+ grn_ii_updspec **u, **un;
+ grn_obj *old_, *old = oldvalue, *new_, *new = newvalue, oldv, newv;
+ grn_obj buf, *post = NULL;
+
+ if (!ii) {
+ ERR(GRN_INVALID_ARGUMENT, "[ii][column][update] ii is NULL");
+ return ctx->rc;
+ }
+ if (!ii->lexicon) {
+ ERR(GRN_INVALID_ARGUMENT, "[ii][column][update] lexicon is NULL");
+ return ctx->rc;
+ }
+ if (rid == GRN_ID_NIL) {
+ ERR(GRN_INVALID_ARGUMENT, "[ii][column][update] record ID is nil");
+ return ctx->rc;
+ }
+ if (old || new) {
+ unsigned char type = GRN_VOID;
+ if (old) {
+ type = (ii->obj.header.domain == old->header.domain)
+ ? GRN_UVECTOR
+ : old->header.type;
+ }
+ if (new) {
+ type = (ii->obj.header.domain == new->header.domain)
+ ? GRN_UVECTOR
+ : new->header.type;
+ }
+ if (type == GRN_VECTOR) {
+ grn_obj *tokenizer;
+ grn_table_get_info(ctx, ii->lexicon, NULL, NULL, &tokenizer, NULL, NULL);
+ if (tokenizer) {
+ grn_obj old_elem, new_elem;
+ unsigned int i, max_n;
+ unsigned int old_n = 0, new_n = 0;
+ if (old) {
+ old_n = grn_vector_size(ctx, old);
+ }
+ if (new) {
+ new_n = grn_vector_size(ctx, new);
+ }
+ max_n = (old_n > new_n) ? old_n : new_n;
+ GRN_OBJ_INIT(&old_elem, GRN_BULK, GRN_OBJ_DO_SHALLOW_COPY, old->header.domain);
+ GRN_OBJ_INIT(&new_elem, GRN_BULK, GRN_OBJ_DO_SHALLOW_COPY, new->header.domain);
+ for (i = 0; i < max_n; i++) {
+ grn_rc rc;
+ grn_obj *old_p = NULL, *new_p = NULL;
+ if (i < old_n) {
+ const char *str;
+ unsigned int size = grn_vector_get_element(ctx, old, i, &str, NULL, NULL);
+ GRN_TEXT_SET_REF(&old_elem, str, size);
+ old_p = &old_elem;
+ }
+ if (i < new_n) {
+ const char *str;
+ unsigned int size = grn_vector_get_element(ctx, new, i, &str, NULL, NULL);
+ GRN_TEXT_SET_REF(&new_elem, str, size);
+ new_p = &new_elem;
+ }
+ rc = grn_ii_column_update(ctx, ii, rid, section + i, old_p, new_p, posting);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &old_elem);
+ GRN_OBJ_FIN(ctx, &new_elem);
+ return ctx->rc;
+ }
+ }
+ }
+ if (posting) {
+ GRN_RECORD_INIT(&buf, GRN_OBJ_VECTOR, grn_obj_id(ctx, ii->lexicon));
+ post = &buf;
+ }
+ if (grn_io_lock(ctx, ii->seg, grn_lock_timeout)) { return ctx->rc; }
+ if (new) {
+ unsigned char type = (ii->obj.header.domain == new->header.domain)
+ ? GRN_UVECTOR
+ : new->header.type;
+ switch (type) {
+ case GRN_BULK :
+ {
+ if (grn_bulk_is_zero(ctx, new)) {
+ do_grn_ii_updspec_cmp = GRN_FALSE;
+ }
+ new_ = new;
+ GRN_OBJ_INIT(&newv, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, GRN_DB_TEXT);
+ newv.u.v.body = new;
+ new = &newv;
+ grn_vector_delimit(ctx, new, 0, GRN_ID_NIL);
+ if (new_ != newvalue) { grn_obj_close(ctx, new_); }
+ }
+ /* fallthru */
+ case GRN_VECTOR :
+ new_ = new;
+ new = (grn_obj *)grn_hash_create(ctx, NULL, sizeof(grn_id),
+ sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!new) {
+ DEFINE_NAME(ii);
+ MERR("[ii][column][update][new][vector] failed to create a hash table: "
+ "<%.*s>: ",
+ name_size, name);
+ } else {
+ grn_vector2updspecs(ctx, ii, rid, section, new_, new,
+ GRN_TOKEN_ADD, post);
+ }
+ if (new_ != newvalue) { grn_obj_close(ctx, new_); }
+ if (ctx->rc != GRN_SUCCESS) { goto exit; }
+ break;
+ case GRN_UVECTOR :
+ new_ = new;
+ new = (grn_obj *)grn_hash_create(ctx, NULL, sizeof(grn_id),
+ sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!new) {
+ DEFINE_NAME(ii);
+ MERR("[ii][column][update][new][uvector] failed to create a hash table: "
+ "<%.*s>: ",
+ name_size, name);
+ } else {
+ if (new_->header.type == GRN_UVECTOR) {
+ grn_uvector2updspecs(ctx, ii, rid, section, new_, new,
+ GRN_TOKEN_ADD, post);
+ } else {
+ grn_obj uvector;
+ unsigned int weight = 0;
+ GRN_VALUE_FIX_SIZE_INIT(&uvector, GRN_OBJ_VECTOR,
+ new_->header.domain);
+ if (new_->header.impl_flags & GRN_OBJ_WITH_WEIGHT) {
+ uvector.header.impl_flags |= GRN_OBJ_WITH_WEIGHT;
+ }
+ grn_uvector_add_element(ctx, &uvector, GRN_RECORD_VALUE(new_),
+ weight);
+ grn_uvector2updspecs(ctx, ii, rid, section, &uvector, new,
+ GRN_TOKEN_ADD, post);
+ GRN_OBJ_FIN(ctx, &uvector);
+ }
+ }
+ if (new_ != newvalue) { grn_obj_close(ctx, new_); }
+ if (ctx->rc != GRN_SUCCESS) { goto exit; }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ break;
+ default :
+ {
+ DEFINE_NAME(ii);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[ii][column][update][new] invalid object: "
+ "<%.*s>: "
+ "<%-.256s>(%#x)",
+ name_size, name,
+ grn_obj_type_to_string(type),
+ type);
+ }
+ goto exit;
+ }
+ }
+ if (posting) {
+ grn_ii_updspec *u_;
+ uint32_t offset = 0;
+ grn_id tid_ = 0, gap, tid, *tpe;
+ grn_table_sort_optarg arg = {GRN_TABLE_SORT_ASC|
+ GRN_TABLE_SORT_AS_NUMBER|
+ GRN_TABLE_SORT_AS_UNSIGNED, NULL, NULL, 0, 0};
+ grn_array *sorted = grn_array_create(ctx, NULL, sizeof(grn_id), 0);
+ grn_hash_sort(ctx, (grn_hash *)new, -1, sorted, &arg);
+ GRN_TEXT_PUT(ctx, posting, ((grn_hash *)new)->n_entries, sizeof(uint32_t));
+ GRN_ARRAY_EACH(ctx, sorted, 0, 0, id, &tp, {
+ grn_hash_get_key(ctx, (grn_hash *)new, *tp, &tid, sizeof(grn_id));
+ gap = tid - tid_;
+ GRN_TEXT_PUT(ctx, posting, &gap, sizeof(grn_id));
+ tid_ = tid;
+ });
+ GRN_ARRAY_EACH(ctx, sorted, 0, 0, id, &tp, {
+ grn_hash_get_value(ctx, (grn_hash *)new, *tp, &u_);
+ u_->offset = offset++;
+ GRN_TEXT_PUT(ctx, posting, &u_->tf, sizeof(int32_t));
+ });
+ tpe = (grn_id *)GRN_BULK_CURR(post);
+ for (tp = (grn_id *)GRN_BULK_HEAD(post); tp < tpe; tp++) {
+ grn_hash_get(ctx, (grn_hash *)new, (void *)tp, sizeof(grn_id),
+ (void **)&u);
+ GRN_TEXT_PUT(ctx, posting, &(*u)->offset, sizeof(int32_t));
+ }
+ GRN_OBJ_FIN(ctx, post);
+ grn_array_close(ctx, sorted);
+ }
+
+ if (old) {
+ unsigned char type = (ii->obj.header.domain == old->header.domain)
+ ? GRN_UVECTOR
+ : old->header.type;
+ switch (type) {
+ case GRN_BULK :
+ {
+ // const char *str = GRN_BULK_HEAD(old);
+ // unsigned int str_len = GRN_BULK_VSIZE(old);
+ old_ = old;
+ GRN_OBJ_INIT(&oldv, GRN_VECTOR, GRN_OBJ_DO_SHALLOW_COPY, GRN_DB_TEXT);
+ oldv.u.v.body = old;
+ old = &oldv;
+ grn_vector_delimit(ctx, old, 0, GRN_ID_NIL);
+ if (old_ != oldvalue) { grn_obj_close(ctx, old_); }
+ }
+ /* fallthru */
+ case GRN_VECTOR :
+ old_ = old;
+ old = (grn_obj *)grn_hash_create(ctx, NULL, sizeof(grn_id),
+ sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!old) {
+ DEFINE_NAME(ii);
+ MERR("[ii][column][update][old][vector] failed to create a hash table: "
+ "<%.*s>: ",
+ name_size, name);
+ } else {
+ grn_vector2updspecs(ctx, ii, rid, section, old_, old,
+ GRN_TOKEN_DEL, NULL);
+ }
+ if (old_ != oldvalue) { grn_obj_close(ctx, old_); }
+ if (ctx->rc != GRN_SUCCESS) { goto exit; }
+ break;
+ case GRN_UVECTOR :
+ old_ = old;
+ old = (grn_obj *)grn_hash_create(ctx, NULL, sizeof(grn_id),
+ sizeof(grn_ii_updspec *),
+ GRN_HASH_TINY);
+ if (!old) {
+ DEFINE_NAME(ii);
+ MERR("[ii][column][update][old][uvector] failed to create a hash table: "
+ "<%.*s>: ",
+ name_size, name);
+ } else {
+ if (old_->header.type == GRN_UVECTOR) {
+ grn_uvector2updspecs(ctx, ii, rid, section, old_, old,
+ GRN_TOKEN_DEL, NULL);
+ } else {
+ grn_obj uvector;
+ unsigned int weight = 0;
+ GRN_VALUE_FIX_SIZE_INIT(&uvector, GRN_OBJ_VECTOR,
+ old_->header.domain);
+ if (old_->header.impl_flags & GRN_OBJ_WITH_WEIGHT) {
+ uvector.header.impl_flags |= GRN_OBJ_WITH_WEIGHT;
+ }
+ grn_uvector_add_element(ctx, &uvector, GRN_RECORD_VALUE(old_),
+ weight);
+ grn_uvector2updspecs(ctx, ii, rid, section, &uvector, old,
+ GRN_TOKEN_DEL, NULL);
+ GRN_OBJ_FIN(ctx, &uvector);
+ }
+ }
+ if (old_ != oldvalue) { grn_obj_close(ctx, old_); }
+ if (ctx->rc != GRN_SUCCESS) { goto exit; }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ break;
+ default :
+ {
+ DEFINE_NAME(ii);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[ii][column][update][old] invalid object: "
+ "<%.*s>: "
+ "<%-.256s>(%#x)",
+ name_size, name,
+ grn_obj_type_to_string(type),
+ type);
+ }
+ goto exit;
+ }
+ }
+
+ if (old) {
+ grn_id eid;
+ grn_hash *o = (grn_hash *)old;
+ grn_hash *n = (grn_hash *)new;
+ GRN_HASH_EACH(ctx, o, id, &tp, NULL, &u, {
+ if (n && (eid = grn_hash_get(ctx, n, tp, sizeof(grn_id),
+ (void **) &un))) {
+ if (do_grn_ii_updspec_cmp && !grn_ii_updspec_cmp(*u, *un)) {
+ grn_ii_updspec_close(ctx, *un);
+ grn_hash_delete_by_id(ctx, n, eid, NULL);
+ }
+ } else {
+ grn_ii_delete_one(ctx, ii, *tp, *u, n);
+ }
+ grn_ii_updspec_close(ctx, *u);
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ });
+ }
+ if (new) {
+ grn_hash *n = (grn_hash *)new;
+ GRN_HASH_EACH(ctx, n, id, &tp, NULL, &u, {
+ grn_ii_update_one(ctx, ii, *tp, *u, n);
+ grn_ii_updspec_close(ctx, *u);
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ });
+ } else {
+ if (!section) {
+ /* todo: delete key when all sections deleted */
+ }
+ }
+exit :
+ grn_io_unlock(ii->seg);
+ if (old && old != oldvalue) { grn_obj_close(ctx, old); }
+ if (new && new != newvalue) { grn_obj_close(ctx, new); }
+ return ctx->rc;
+}
+
+/* token_info */
+
+typedef struct {
+ cursor_heap *cursors;
+ int offset;
+ int pos;
+ int size;
+ int ntoken;
+ grn_posting *p;
+} token_info;
+
+#define EX_NONE 0
+#define EX_PREFIX 1
+#define EX_SUFFIX 2
+#define EX_BOTH 3
+#define EX_FUZZY 4
+
+inline static void
+token_info_expand_both(grn_ctx *ctx, grn_obj *lexicon, grn_ii *ii,
+ const char *key, unsigned int key_size, token_info *ti)
+{
+ int s = 0;
+ grn_hash *h, *g;
+ uint32_t *offset2;
+ grn_hash_cursor *c;
+ grn_id *tp, *tq;
+ if ((h = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, 0))) {
+ grn_table_search(ctx, lexicon, key, key_size,
+ GRN_OP_PREFIX, (grn_obj *)h, GRN_OP_OR);
+ if (GRN_HASH_SIZE(h)) {
+ if ((ti->cursors = cursor_heap_open(ctx, GRN_HASH_SIZE(h) + 256))) {
+ if ((c = grn_hash_cursor_open(ctx, h, NULL, 0, NULL, 0, 0, -1, 0))) {
+ uint32_t key2_size;
+ const char *key2;
+ while (grn_hash_cursor_next(ctx, c)) {
+ grn_hash_cursor_get_key(ctx, c, (void **) &tp);
+ key2 = _grn_table_key(ctx, lexicon, *tp, &key2_size);
+ if (!key2) { break; }
+ if ((lexicon->header.type != GRN_TABLE_PAT_KEY) ||
+ !(lexicon->header.flags & GRN_OBJ_KEY_WITH_SIS) ||
+ key2_size <= 2) { // todo: refine
+ if ((s = grn_ii_estimate_size(ctx, ii, *tp))) {
+ cursor_heap_push(ctx, ti->cursors, ii, *tp, 0, 0, GRN_ID_NIL);
+ ti->ntoken++;
+ ti->size += s;
+ }
+ } else {
+ if ((g = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_HASH_TINY))) {
+ grn_pat_suffix_search(ctx, (grn_pat *)lexicon, key2, key2_size,
+ g);
+ GRN_HASH_EACH(ctx, g, id, &tq, NULL, &offset2, {
+ if ((s = grn_ii_estimate_size(ctx, ii, *tq))) {
+ cursor_heap_push(ctx, ti->cursors, ii, *tq,
+ /* *offset2 */ 0, 0, GRN_ID_NIL);
+ ti->ntoken++;
+ ti->size += s;
+ }
+ });
+ grn_hash_close(ctx, g);
+ }
+ }
+ }
+ grn_hash_cursor_close(ctx, c);
+ }
+ }
+ }
+ grn_hash_close(ctx, h);
+ }
+}
+
+inline static grn_rc
+token_info_close(grn_ctx *ctx, token_info *ti)
+{
+ cursor_heap_close(ctx, ti->cursors);
+ GRN_FREE(ti);
+ return GRN_SUCCESS;
+}
+
+inline static token_info *
+token_info_open(grn_ctx *ctx, grn_obj *lexicon, grn_ii *ii,
+ const char *key, unsigned int key_size, uint32_t offset,
+ int mode, grn_fuzzy_search_optarg *args, grn_id min)
+{
+ int s = 0;
+ grn_hash *h;
+ token_info *ti;
+ grn_id tid;
+ grn_id *tp;
+ if (!key) { return NULL; }
+ if (!(ti = GRN_MALLOC(sizeof(token_info)))) { return NULL; }
+ ti->cursors = NULL;
+ ti->size = 0;
+ ti->ntoken = 0;
+ ti->offset = offset;
+ switch (mode) {
+ case EX_BOTH :
+ token_info_expand_both(ctx, lexicon, ii, key, key_size, ti);
+ break;
+ case EX_NONE :
+ if ((tid = grn_table_get(ctx, lexicon, key, key_size)) &&
+ (s = grn_ii_estimate_size(ctx, ii, tid)) &&
+ (ti->cursors = cursor_heap_open(ctx, 1))) {
+ cursor_heap_push(ctx, ti->cursors, ii, tid, 0, 0, min);
+ ti->ntoken++;
+ ti->size = s;
+ }
+ break;
+ case EX_PREFIX :
+ if ((h = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, 0))) {
+ grn_table_search(ctx, lexicon, key, key_size,
+ GRN_OP_PREFIX, (grn_obj *)h, GRN_OP_OR);
+ if (GRN_HASH_SIZE(h)) {
+ if ((ti->cursors = cursor_heap_open(ctx, GRN_HASH_SIZE(h)))) {
+ GRN_HASH_EACH(ctx, h, id, &tp, NULL, NULL, {
+ if ((s = grn_ii_estimate_size(ctx, ii, *tp))) {
+ cursor_heap_push(ctx, ti->cursors, ii, *tp, 0, 0, min);
+ ti->ntoken++;
+ ti->size += s;
+ }
+ });
+ }
+ }
+ grn_hash_close(ctx, h);
+ }
+ break;
+ case EX_SUFFIX :
+ if ((h = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, 0))) {
+ grn_table_search(ctx, lexicon, key, key_size,
+ GRN_OP_SUFFIX, (grn_obj *)h, GRN_OP_OR);
+ if (GRN_HASH_SIZE(h)) {
+ if ((ti->cursors = cursor_heap_open(ctx, GRN_HASH_SIZE(h)))) {
+ uint32_t *offset2;
+ GRN_HASH_EACH(ctx, h, id, &tp, NULL, &offset2, {
+ if ((s = grn_ii_estimate_size(ctx, ii, *tp))) {
+ cursor_heap_push(ctx, ti->cursors, ii, *tp, /* *offset2 */ 0, 0, min);
+ ti->ntoken++;
+ ti->size += s;
+ }
+ });
+ }
+ }
+ grn_hash_close(ctx, h);
+ }
+ break;
+ case EX_FUZZY :
+ if ((h = (grn_hash *)grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ grn_ctx_at(ctx, GRN_DB_UINT32), NULL))) {
+ grn_table_fuzzy_search(ctx, lexicon, key, key_size,
+ args, (grn_obj *)h, GRN_OP_OR);
+ if (GRN_HASH_SIZE(h)) {
+ if ((ti->cursors = cursor_heap_open(ctx, GRN_HASH_SIZE(h)))) {
+ grn_rset_recinfo *ri;
+ GRN_HASH_EACH(ctx, h, id, &tp, NULL, (void **)&ri, {
+ if ((s = grn_ii_estimate_size(ctx, ii, *tp))) {
+ cursor_heap_push(ctx, ti->cursors, ii, *tp, 0, ri->score - 1, min);
+ ti->ntoken++;
+ ti->size += s;
+ }
+ });
+ }
+ }
+ grn_obj_close(ctx, (grn_obj *)h);
+ }
+ break;
+ }
+ if (cursor_heap_push2(ti->cursors)) {
+ token_info_close(ctx, ti);
+ return NULL;
+ }
+ {
+ grn_ii_cursor *ic;
+ if (ti->cursors && (ic = cursor_heap_min(ti->cursors))) {
+ grn_posting *p = ic->post;
+ ti->pos = p->pos - ti->offset;
+ ti->p = p;
+ } else {
+ token_info_close(ctx, ti);
+ ti = NULL;
+ }
+ }
+ return ti;
+}
+
+static inline grn_rc
+token_info_skip(grn_ctx *ctx, token_info *ti, uint32_t rid, uint32_t sid)
+{
+ grn_ii_cursor *c;
+ grn_posting *p;
+ for (;;) {
+ if (!(c = cursor_heap_min(ti->cursors))) { return GRN_END_OF_DATA; }
+ p = c->post;
+ if (p->rid > rid || (p->rid == rid && p->sid >= sid)) { break; }
+ cursor_heap_pop(ctx, ti->cursors, rid);
+ }
+ ti->pos = p->pos - ti->offset;
+ ti->p = p;
+ return GRN_SUCCESS;
+}
+
+static inline grn_rc
+token_info_skip_pos(grn_ctx *ctx, token_info *ti, uint32_t rid, uint32_t sid, uint32_t pos)
+{
+ grn_ii_cursor *c;
+ grn_posting *p;
+ pos += ti->offset;
+ for (;;) {
+ if (!(c = cursor_heap_min(ti->cursors))) { return GRN_END_OF_DATA; }
+ p = c->post;
+ if (p->rid != rid || p->sid != sid || p->pos >= pos) { break; }
+ cursor_heap_pop_pos(ctx, ti->cursors);
+ }
+ ti->pos = p->pos - ti->offset;
+ ti->p = p;
+ return GRN_SUCCESS;
+}
+
+inline static int
+token_compare(const void *a, const void *b)
+{
+ const token_info *t1 = *((token_info **)a), *t2 = *((token_info **)b);
+ return t1->size - t2->size;
+}
+
+#define TOKEN_CANDIDATE_NODE_SIZE 32
+#define TOKEN_CANDIDATE_ADJACENT_MAX_SIZE 16
+#define TOKEN_CANDIDATE_QUEUE_SIZE 64
+#define TOKEN_CANDIDATE_SIZE 16
+
+typedef struct {
+ grn_id tid;
+ const unsigned char *token;
+ uint32_t token_size;
+ int32_t pos;
+ grn_token_cursor_status status;
+ int ef;
+ uint32_t estimated_size;
+ uint8_t adjacent[TOKEN_CANDIDATE_ADJACENT_MAX_SIZE]; /* Index of adjacent node from top */
+ uint8_t n_adjacent;
+} token_candidate_node;
+
+typedef struct {
+ uint32_t *candidates; /* Standing bits indicate index of token_candidate_node */
+ int top;
+ int rear;
+ int size;
+} token_candidate_queue;
+
+inline static void
+token_candidate_adjacent_set(grn_ctx *ctx, grn_token_cursor *token_cursor,
+ token_candidate_node *top, token_candidate_node *curr)
+{
+ grn_bool exists_adjacent = GRN_FALSE;
+ token_candidate_node *adj;
+ for (adj = top; adj < curr; adj++) {
+ if (token_cursor->curr <= adj->token + adj->token_size) {
+ if (adj->n_adjacent < TOKEN_CANDIDATE_ADJACENT_MAX_SIZE) {
+ adj->adjacent[adj->n_adjacent] = curr - top;
+ adj->n_adjacent++;
+ exists_adjacent = GRN_TRUE;
+ }
+ }
+ }
+ if (!exists_adjacent) {
+ adj = curr - 1;
+ if (adj->n_adjacent < TOKEN_CANDIDATE_ADJACENT_MAX_SIZE) {
+ adj->adjacent[adj->n_adjacent] = curr - top;
+ adj->n_adjacent++;
+ }
+ }
+}
+
+inline static grn_rc
+token_candidate_init(grn_ctx *ctx, grn_ii *ii, grn_token_cursor *token_cursor,
+ grn_id tid, int ef, token_candidate_node **nodes, int *n_nodes,
+ uint32_t *max_estimated_size)
+{
+ grn_rc rc;
+ token_candidate_node *top, *curr;
+ int size = TOKEN_CANDIDATE_NODE_SIZE;
+
+ *nodes = GRN_MALLOC(TOKEN_CANDIDATE_NODE_SIZE * sizeof(token_candidate_node));
+ if (!*nodes) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ top = *nodes;
+ curr = top;
+
+#define TOKEN_CANDIDATE_NODE_SET() { \
+ curr->tid = tid; \
+ curr->token = token_cursor->curr; \
+ curr->token_size = token_cursor->curr_size; \
+ curr->pos = token_cursor->pos; \
+ curr->status = token_cursor->status; \
+ curr->ef = ef; \
+ curr->estimated_size = grn_ii_estimate_size(ctx, ii, tid); \
+ curr->n_adjacent = 0; \
+}
+ TOKEN_CANDIDATE_NODE_SET();
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "[ii][overlap_token_skip] tid=%u pos=%d estimated_size=%u",
+ curr->tid, curr->pos, curr->estimated_size);
+ *max_estimated_size = curr->estimated_size;
+ curr++;
+
+ while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
+ if (curr - top >= size) {
+ if (!(*nodes = GRN_REALLOC(*nodes,
+ (curr - top + TOKEN_CANDIDATE_NODE_SIZE) * sizeof(token_candidate_node)))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ top = *nodes;
+ curr = top + size;
+ size += TOKEN_CANDIDATE_NODE_SIZE;
+ }
+ tid = grn_token_cursor_next(ctx, token_cursor);
+ if (token_cursor->status != GRN_TOKEN_CURSOR_DONE_SKIP) {
+ if (token_cursor->force_prefix) { ef |= EX_PREFIX; }
+ TOKEN_CANDIDATE_NODE_SET();
+ token_candidate_adjacent_set(ctx, token_cursor, top, curr);
+ if (curr->estimated_size > *max_estimated_size) {
+ *max_estimated_size = curr->estimated_size;
+ }
+ curr++;
+ }
+ }
+ *n_nodes = curr - top;
+ rc = GRN_SUCCESS;
+ return rc;
+#undef TOKEN_CANDIDATE_NODE_SET
+}
+
+inline static grn_rc
+token_candidate_queue_init(grn_ctx *ctx, token_candidate_queue *q)
+{
+ q->top = 0;
+ q->rear = 0;
+ q->size = TOKEN_CANDIDATE_QUEUE_SIZE;
+
+ q->candidates = GRN_MALLOC(TOKEN_CANDIDATE_QUEUE_SIZE * sizeof(uint32_t));
+ if (!q->candidates) {
+ q->size = 0;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+token_candidate_enqueue(grn_ctx *ctx, token_candidate_queue *q, uint32_t candidate)
+{
+ if (q->rear >= q->size) {
+ if (!(q->candidates =
+ GRN_REALLOC(q->candidates,
+ (q->rear + TOKEN_CANDIDATE_QUEUE_SIZE) * sizeof(uint32_t)))) {
+ q->size = 0;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ q->size += TOKEN_CANDIDATE_QUEUE_SIZE;
+ }
+ *(q->candidates + q->rear) = candidate;
+ q->rear++;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+token_candidate_dequeue(grn_ctx *ctx, token_candidate_queue *q, uint32_t *candidate)
+{
+ if (q->top == q->rear) {
+ return GRN_END_OF_DATA;
+ }
+ *candidate = *(q->candidates + q->top);
+ q->top++;
+ return GRN_SUCCESS;
+}
+
+inline static void
+token_candidate_queue_fin(grn_ctx *ctx, token_candidate_queue *q)
+{
+ GRN_FREE(q->candidates);
+}
+
+inline static token_candidate_node*
+token_candidate_last_node(grn_ctx *ctx, token_candidate_node *nodes, uint32_t candidate, int offset)
+{
+ int i;
+ GRN_BIT_SCAN_REV(candidate, i);
+ return nodes + i + offset;
+}
+
+inline static uint64_t
+token_candidate_score(grn_ctx *ctx, token_candidate_node *nodes, uint32_t candidate,
+ int offset, uint32_t max_estimated_size)
+{
+ int i, last;
+ uint64_t score = 0;
+ GRN_BIT_SCAN_REV(candidate, last);
+ for (i = 0; i <= last; i++) {
+ if (candidate & (1 << i)) {
+ token_candidate_node *node = nodes + i + offset;
+ if (node->estimated_size > 0) {
+ score += max_estimated_size / node->estimated_size;
+ }
+ }
+ }
+ return score;
+}
+
+inline static grn_rc
+token_candidate_select(grn_ctx *ctx, token_candidate_node *nodes,
+ int offset, int limit, int end,
+ uint32_t *selected_candidate, uint32_t max_estimated_size)
+{
+ grn_rc rc;
+ token_candidate_queue q;
+ uint32_t candidate;
+ uint64_t max_score = 0;
+ int i, min_n_nodes = 0;
+
+ if (offset + limit > end) {
+ limit = end - offset;
+ }
+ rc = token_candidate_queue_init(ctx, &q);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = token_candidate_enqueue(ctx, &q, 1);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ while (token_candidate_dequeue(ctx, &q, &candidate) != GRN_END_OF_DATA) {
+ token_candidate_node *candidate_last_node =
+ token_candidate_last_node(ctx, nodes, candidate, offset);
+ for (i = 0; i < candidate_last_node->n_adjacent; i++) {
+ int adjacent, n_nodes = 0;
+ uint32_t new_candidate;
+ adjacent = candidate_last_node->adjacent[i] - offset;
+ if (adjacent > limit) {
+ break;
+ }
+ new_candidate = candidate | (1 << adjacent);
+ GET_NUM_BITS(new_candidate, n_nodes);
+ if (min_n_nodes > 0 && n_nodes > min_n_nodes + 1) {
+ goto exit;
+ }
+ rc = token_candidate_enqueue(ctx, &q, new_candidate);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ if (adjacent == limit) {
+ if (min_n_nodes == 0) {
+ min_n_nodes = n_nodes;
+ }
+ if (n_nodes >= min_n_nodes && n_nodes <= min_n_nodes + 1) {
+ uint64_t score;
+ score = token_candidate_score(ctx, nodes, new_candidate, offset, max_estimated_size);
+ if (score > max_score) {
+ max_score = score;
+ *selected_candidate = new_candidate;
+ }
+ }
+ }
+ }
+ }
+ rc = GRN_SUCCESS;
+exit :
+ token_candidate_queue_fin(ctx, &q);
+ return rc;
+}
+
+inline static grn_rc
+token_candidate_build(grn_ctx *ctx, grn_obj *lexicon, grn_ii *ii,
+ token_info **tis, uint32_t *n,
+ token_candidate_node *nodes, uint32_t selected_candidate,
+ int offset, grn_id min)
+{
+ grn_rc rc = GRN_END_OF_DATA;
+ token_info *ti;
+ const char *key;
+ uint32_t size;
+ int i, last = 0;
+ GRN_BIT_SCAN_REV(selected_candidate, last);
+ for (i = 1; i <= last; i++) {
+ if (selected_candidate & (1 << i)) {
+ token_candidate_node *node = nodes + i + offset;
+ switch (node->status) {
+ case GRN_TOKEN_CURSOR_DOING :
+ key = _grn_table_key(ctx, lexicon, node->tid, &size);
+ ti = token_info_open(ctx, lexicon, ii, key, size, node->pos,
+ EX_NONE, NULL, min);
+ break;
+ case GRN_TOKEN_CURSOR_DONE :
+ if (node->tid) {
+ key = _grn_table_key(ctx, lexicon, node->tid, &size);
+ ti = token_info_open(ctx, lexicon, ii, key, size, node->pos,
+ node->ef & EX_PREFIX, NULL, min);
+ break;
+ } /* else fallthru */
+ default :
+ ti = token_info_open(ctx, lexicon, ii, (char *)node->token,
+ node->token_size, node->pos,
+ node->ef & EX_PREFIX, NULL, min);
+ break;
+ }
+ if (!ti) {
+ goto exit;
+ }
+ tis[(*n)++] = ti;
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "[ii][overlap_token_skip] tid=%u pos=%d estimated_size=%u",
+ node->tid, node->pos, node->estimated_size);
+ }
+ }
+ rc = GRN_SUCCESS;
+exit :
+ return rc;
+}
+
+inline static grn_rc
+token_info_build_skipping_overlap(grn_ctx *ctx, grn_obj *lexicon, grn_ii *ii,
+ token_info **tis, uint32_t *n,
+ grn_token_cursor *token_cursor,
+ grn_id tid, int ef, grn_id min)
+{
+ grn_rc rc;
+ token_candidate_node *nodes = NULL;
+ int n_nodes = 0, offset = 0, limit = TOKEN_CANDIDATE_SIZE - 1;
+ uint32_t max_estimated_size;
+
+ rc = token_candidate_init(ctx, ii, token_cursor, tid, ef, &nodes, &n_nodes, &max_estimated_size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ while (offset < n_nodes - 1) {
+ uint32_t selected_candidate = 0;
+ rc = token_candidate_select(ctx, nodes, offset, limit, n_nodes - 1,
+ &selected_candidate, max_estimated_size);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ rc = token_candidate_build(ctx, lexicon, ii, tis, n, nodes, selected_candidate, offset, min);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ offset += limit;
+ }
+ rc = GRN_SUCCESS;
+exit :
+ if (nodes) {
+ GRN_FREE(nodes);
+ }
+ return rc;
+}
+
+inline static grn_rc
+token_info_build(grn_ctx *ctx, grn_obj *lexicon, grn_ii *ii, const char *string, unsigned int string_len,
+ token_info **tis, uint32_t *n, grn_bool *only_skip_token, grn_id min,
+ grn_operator mode)
+{
+ token_info *ti;
+ const char *key;
+ uint32_t size;
+ grn_rc rc = GRN_END_OF_DATA;
+ unsigned int token_flags = GRN_TOKEN_CURSOR_ENABLE_TOKENIZED_DELIMITER;
+ grn_token_cursor *token_cursor = grn_token_cursor_open(ctx, lexicon,
+ string, string_len,
+ GRN_TOKEN_GET,
+ token_flags);
+ *only_skip_token = GRN_FALSE;
+ if (!token_cursor) { return GRN_NO_MEMORY_AVAILABLE; }
+ if (mode == GRN_OP_UNSPLIT) {
+ if ((ti = token_info_open(ctx, lexicon, ii, (char *)token_cursor->orig,
+ token_cursor->orig_blen, 0, EX_BOTH, NULL, min))) {
+ tis[(*n)++] = ti;
+ rc = GRN_SUCCESS;
+ }
+ } else {
+ grn_id tid;
+ int ef;
+ switch (mode) {
+ case GRN_OP_PREFIX :
+ ef = EX_PREFIX;
+ break;
+ case GRN_OP_SUFFIX :
+ ef = EX_SUFFIX;
+ break;
+ case GRN_OP_PARTIAL :
+ ef = EX_BOTH;
+ break;
+ default :
+ ef = EX_NONE;
+ break;
+ }
+ tid = grn_token_cursor_next(ctx, token_cursor);
+ if (token_cursor->force_prefix) { ef |= EX_PREFIX; }
+ switch (token_cursor->status) {
+ case GRN_TOKEN_CURSOR_DOING :
+ key = _grn_table_key(ctx, lexicon, tid, &size);
+ ti = token_info_open(ctx, lexicon, ii, key, size, token_cursor->pos,
+ ef & EX_SUFFIX, NULL, min);
+ break;
+ case GRN_TOKEN_CURSOR_DONE :
+ ti = token_info_open(ctx, lexicon, ii, (const char *)token_cursor->curr,
+ token_cursor->curr_size, 0, ef, NULL, min);
+ /*
+ key = _grn_table_key(ctx, lexicon, tid, &size);
+ ti = token_info_open(ctx, lexicon, ii, token_cursor->curr, token_cursor->curr_size, token_cursor->pos, ef, NULL, GRN_ID_NIL);
+ ti = token_info_open(ctx, lexicon, ii, (char *)token_cursor->orig,
+ token_cursor->orig_blen, token_cursor->pos, ef, NULL, GRN_ID_NIL);
+ */
+ break;
+ case GRN_TOKEN_CURSOR_NOT_FOUND :
+ ti = token_info_open(ctx, lexicon, ii, (char *)token_cursor->orig,
+ token_cursor->orig_blen, 0, ef, NULL, min);
+ break;
+ case GRN_TOKEN_CURSOR_DONE_SKIP :
+ *only_skip_token = GRN_TRUE;
+ goto exit;
+ default :
+ goto exit;
+ }
+ if (!ti) { goto exit ; }
+ tis[(*n)++] = ti;
+
+ if (grn_ii_overlap_token_skip_enable) {
+ rc = token_info_build_skipping_overlap(ctx, lexicon, ii, tis, n, token_cursor, tid, ef, min);
+ goto exit;
+ }
+
+ while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
+ tid = grn_token_cursor_next(ctx, token_cursor);
+ if (token_cursor->force_prefix) { ef |= EX_PREFIX; }
+ switch (token_cursor->status) {
+ case GRN_TOKEN_CURSOR_DONE_SKIP :
+ continue;
+ case GRN_TOKEN_CURSOR_DOING :
+ key = _grn_table_key(ctx, lexicon, tid, &size);
+ ti = token_info_open(ctx, lexicon, ii, key, size, token_cursor->pos,
+ EX_NONE, NULL, min);
+ break;
+ case GRN_TOKEN_CURSOR_DONE :
+ if (tid) {
+ key = _grn_table_key(ctx, lexicon, tid, &size);
+ ti = token_info_open(ctx, lexicon, ii, key, size, token_cursor->pos,
+ ef & EX_PREFIX, NULL, min);
+ break;
+ } /* else fallthru */
+ default :
+ ti = token_info_open(ctx, lexicon, ii, (char *)token_cursor->curr,
+ token_cursor->curr_size, token_cursor->pos,
+ ef & EX_PREFIX, NULL, min);
+ break;
+ }
+ if (!ti) {
+ goto exit;
+ }
+ tis[(*n)++] = ti;
+ }
+ rc = GRN_SUCCESS;
+ }
+exit :
+ grn_token_cursor_close(ctx, token_cursor);
+ return rc;
+}
+
+inline static grn_rc
+token_info_build_fuzzy(grn_ctx *ctx, grn_obj *lexicon, grn_ii *ii,
+ const char *string, unsigned int string_len,
+ token_info **tis, uint32_t *n, grn_bool *only_skip_token,
+ grn_id min, grn_operator mode, grn_fuzzy_search_optarg *args)
+{
+ token_info *ti;
+ grn_rc rc = GRN_END_OF_DATA;
+ unsigned int token_flags = GRN_TOKEN_CURSOR_ENABLE_TOKENIZED_DELIMITER;
+ grn_token_cursor *token_cursor = grn_token_cursor_open(ctx, lexicon,
+ string, string_len,
+ GRN_TOKENIZE_ONLY,
+ token_flags);
+ *only_skip_token = GRN_FALSE;
+ if (!token_cursor) { return GRN_NO_MEMORY_AVAILABLE; }
+ grn_token_cursor_next(ctx, token_cursor);
+ switch (token_cursor->status) {
+ case GRN_TOKEN_CURSOR_DONE_SKIP :
+ *only_skip_token = GRN_TRUE;
+ goto exit;
+ case GRN_TOKEN_CURSOR_DOING :
+ case GRN_TOKEN_CURSOR_DONE :
+ ti = token_info_open(ctx, lexicon, ii, (const char *)token_cursor->curr,
+ token_cursor->curr_size, token_cursor->pos, EX_FUZZY,
+ args, min);
+ break;
+ default :
+ ti = NULL;
+ break;
+ }
+ if (!ti) {
+ goto exit ;
+ }
+ tis[(*n)++] = ti;
+ while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
+ grn_token_cursor_next(ctx, token_cursor);
+ switch (token_cursor->status) {
+ case GRN_TOKEN_CURSOR_DONE_SKIP :
+ continue;
+ case GRN_TOKEN_CURSOR_DOING :
+ case GRN_TOKEN_CURSOR_DONE :
+ ti = token_info_open(ctx, lexicon, ii, (const char *)token_cursor->curr,
+ token_cursor->curr_size, token_cursor->pos, EX_FUZZY,
+ args, min);
+ break;
+ default :
+ break;
+ }
+ if (!ti) {
+ goto exit;
+ }
+ tis[(*n)++] = ti;
+ }
+ rc = GRN_SUCCESS;
+exit :
+ grn_token_cursor_close(ctx, token_cursor);
+ return rc;
+}
+
+static void
+token_info_clear_offset(token_info **tis, uint32_t n)
+{
+ token_info **tie;
+ for (tie = tis + n; tis < tie; tis++) { (*tis)->offset = 0; }
+}
+
+/* select */
+
+inline static void
+res_add(grn_ctx *ctx, grn_hash *s, grn_rset_posinfo *pi, double score,
+ grn_operator op)
+{
+ grn_rset_recinfo *ri;
+ switch (op) {
+ case GRN_OP_OR :
+ if (grn_hash_add(ctx, s, pi, s->key_size, (void **)&ri, NULL)) {
+ if (s->obj.header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_table_add_subrec((grn_obj *)s, ri, score, pi, 1);
+ }
+ }
+ break;
+ case GRN_OP_AND :
+ if (grn_hash_get(ctx, s, pi, s->key_size, (void **)&ri)) {
+ if (s->obj.header.flags & GRN_OBJ_WITH_SUBREC) {
+ ri->n_subrecs |= GRN_RSET_UTIL_BIT;
+ grn_table_add_subrec((grn_obj *)s, ri, score, pi, 1);
+ }
+ }
+ break;
+ case GRN_OP_AND_NOT :
+ {
+ grn_id id;
+ if ((id = grn_hash_get(ctx, s, pi, s->key_size, (void **)&ri))) {
+ grn_hash_delete_by_id(ctx, s, id, NULL);
+ }
+ }
+ break;
+ case GRN_OP_ADJUST :
+ if (grn_hash_get(ctx, s, pi, s->key_size, (void **)&ri)) {
+ if (s->obj.header.flags & GRN_OBJ_WITH_SUBREC) {
+ ri->score += score;
+ }
+ }
+ break;
+ default :
+ break;
+ }
+}
+
+grn_rc
+grn_ii_posting_add(grn_ctx *ctx, grn_posting *pos, grn_hash *s, grn_operator op)
+{
+ res_add(ctx, s, (grn_rset_posinfo *)(pos), (1 + pos->weight), op);
+ return ctx->rc;
+}
+
+#ifdef USE_BHEAP
+
+/* todo */
+
+#else /* USE_BHEAP */
+
+struct _btr_node {
+ struct _btr_node *car;
+ struct _btr_node *cdr;
+ token_info *ti;
+};
+
+typedef struct _btr_node btr_node;
+
+typedef struct {
+ int n;
+ token_info *min;
+ token_info *max;
+ btr_node *root;
+ btr_node *nodes;
+} btr;
+
+inline static void
+bt_zap(btr *bt)
+{
+ bt->n = 0;
+ bt->min = NULL;
+ bt->max = NULL;
+ bt->root = NULL;
+}
+
+inline static btr *
+bt_open(grn_ctx *ctx, int size)
+{
+ btr *bt = GRN_MALLOC(sizeof(btr));
+ if (bt) {
+ bt_zap(bt);
+ if (!(bt->nodes = GRN_MALLOC(sizeof(btr_node) * size))) {
+ GRN_FREE(bt);
+ bt = NULL;
+ }
+ }
+ return bt;
+}
+
+inline static void
+bt_close(grn_ctx *ctx, btr *bt)
+{
+ if (!bt) { return; }
+ GRN_FREE(bt->nodes);
+ GRN_FREE(bt);
+}
+
+inline static void
+bt_push(btr *bt, token_info *ti)
+{
+ int pos = ti->pos, minp = 1, maxp = 1;
+ btr_node *node, *new, **last;
+ new = bt->nodes + bt->n++;
+ new->ti = ti;
+ new->car = NULL;
+ new->cdr = NULL;
+ for (last = &bt->root; (node = *last);) {
+ if (pos < node->ti->pos) {
+ last = &node->car;
+ maxp = 0;
+ } else {
+ last = &node->cdr;
+ minp = 0;
+ }
+ }
+ *last = new;
+ if (minp) { bt->min = ti; }
+ if (maxp) { bt->max = ti; }
+}
+
+inline static void
+bt_pop(btr *bt)
+{
+ btr_node *node, *min, *newmin, **last;
+ for (last = &bt->root; (min = *last) && min->car; last = &min->car) ;
+ if (min) {
+ int pos = min->ti->pos, minp = 1, maxp = 1;
+ *last = min->cdr;
+ min->cdr = NULL;
+ for (last = &bt->root; (node = *last);) {
+ if (pos < node->ti->pos) {
+ last = &node->car;
+ maxp = 0;
+ } else {
+ last = &node->cdr;
+ minp = 0;
+ }
+ }
+ *last = min;
+ if (maxp) { bt->max = min->ti; }
+ if (!minp) {
+ for (newmin = bt->root; newmin->car; newmin = newmin->car) ;
+ bt->min = newmin->ti;
+ }
+ }
+}
+
+#endif /* USE_BHEAP */
+
+typedef enum {
+ grn_wv_none = 0,
+ grn_wv_static,
+ grn_wv_dynamic,
+ grn_wv_constant
+} grn_wv_mode;
+
+inline static double
+get_weight(grn_ctx *ctx, grn_hash *s, grn_id rid, int sid,
+ grn_wv_mode wvm, grn_select_optarg *optarg)
+{
+ switch (wvm) {
+ case grn_wv_none :
+ return 1;
+ case grn_wv_static :
+ return sid <= optarg->vector_size ? optarg->weight_vector[sid - 1] : 0;
+ case grn_wv_dynamic :
+ /* todo : support hash with keys
+ if (s->keys) {
+ uint32_t key_size;
+ const char *key = _grn_table_key(ctx, s->keys, rid, &key_size);
+ // todo : change grn_select_optarg
+ return key ? optarg->func(s, key, key_size, sid, optarg->func_arg) : 0;
+ }
+ */
+ /* todo : cast */
+ return optarg->func(ctx, (void *)s, (void *)(intptr_t)rid, sid,
+ optarg->func_arg);
+ case grn_wv_constant :
+ return optarg->vector_size;
+ default :
+ return 1;
+ }
+}
+
+grn_rc
+grn_ii_similar_search(grn_ctx *ctx, grn_ii *ii,
+ const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_select_optarg *optarg)
+{
+ int *w1, limit;
+ grn_id tid, *tp, max_size;
+ grn_rc rc = GRN_SUCCESS;
+ grn_hash *h;
+ grn_token_cursor *token_cursor;
+ unsigned int token_flags = GRN_TOKEN_CURSOR_ENABLE_TOKENIZED_DELIMITER;
+ grn_obj *lexicon = ii->lexicon;
+ if (!lexicon || !ii || !string || !string_len || !s || !optarg) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!(h = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(int), 0))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (!(token_cursor = grn_token_cursor_open(ctx, lexicon, string, string_len,
+ GRN_TOKEN_GET, token_flags))) {
+ grn_hash_close(ctx, h);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (!(max_size = optarg->max_size)) { max_size = 1048576; }
+ while (token_cursor->status != GRN_TOKEN_CURSOR_DONE &&
+ token_cursor->status != GRN_TOKEN_CURSOR_DONE_SKIP) {
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ if (grn_hash_add(ctx, h, &tid, sizeof(grn_id), (void **)&w1, NULL)) {
+ (*w1)++;
+ }
+ }
+ if (tid && token_cursor->curr_size) {
+ if (optarg->mode == GRN_OP_UNSPLIT) {
+ grn_table_search(ctx, lexicon, token_cursor->curr,
+ token_cursor->curr_size,
+ GRN_OP_PREFIX, (grn_obj *)h, GRN_OP_OR);
+ }
+ if (optarg->mode == GRN_OP_PARTIAL) {
+ grn_table_search(ctx, lexicon, token_cursor->curr,
+ token_cursor->curr_size,
+ GRN_OP_SUFFIX, (grn_obj *)h, GRN_OP_OR);
+ }
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ {
+ grn_hash_cursor *c = grn_hash_cursor_open(ctx, h, NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (!c) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_hash_cursor_open on grn_ii_similar_search failed !");
+ grn_hash_close(ctx, h);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ while (grn_hash_cursor_next(ctx, c)) {
+ uint32_t es;
+ grn_hash_cursor_get_key_value(ctx, c, (void **) &tp, NULL, (void **) &w1);
+ if ((es = grn_ii_estimate_size(ctx, ii, *tp))) {
+ *w1 += max_size / es;
+ } else {
+ grn_hash_cursor_delete(ctx, c, NULL);
+ }
+ }
+ grn_hash_cursor_close(ctx, c);
+ }
+ limit = optarg->similarity_threshold
+ ? (optarg->similarity_threshold > (int) GRN_HASH_SIZE(h)
+ ? GRN_HASH_SIZE(h)
+ : optarg->similarity_threshold)
+ : (GRN_HASH_SIZE(h) >> 3) + 1;
+ if (GRN_HASH_SIZE(h)) {
+ grn_id j, id;
+ int w2, rep;
+ grn_ii_cursor *c;
+ grn_posting *pos;
+ grn_wv_mode wvm = grn_wv_none;
+ grn_table_sort_optarg arg = {
+ GRN_TABLE_SORT_DESC|GRN_TABLE_SORT_BY_VALUE|GRN_TABLE_SORT_AS_NUMBER,
+ NULL,
+ NULL,
+ 0, 0
+ };
+ grn_array *sorted = grn_array_create(ctx, NULL, sizeof(grn_id), 0);
+ if (!sorted) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_hash_sort on grn_ii_similar_search failed !");
+ grn_hash_close(ctx, h);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ grn_hash_sort(ctx, h, limit, sorted, &arg);
+ /* todo support subrec
+ rep = (s->record_unit == grn_rec_position || s->subrec_unit == grn_rec_position);
+ */
+ rep = 0;
+ if (optarg->func) {
+ wvm = grn_wv_dynamic;
+ } else if (optarg->vector_size) {
+ wvm = optarg->weight_vector ? grn_wv_static : grn_wv_constant;
+ }
+ for (j = 1; j <= (uint) limit; j++) {
+ grn_array_get_value(ctx, sorted, j, &id);
+ _grn_hash_get_key_value(ctx, h, id, (void **) &tp, (void **) &w1);
+ if (!*tp || !(c = grn_ii_cursor_open(ctx, ii, *tp, GRN_ID_NIL, GRN_ID_MAX,
+ rep
+ ? ii->n_elements
+ : ii->n_elements - 1, 0))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "cursor open failed (%d)", *tp);
+ continue;
+ }
+ if (rep) {
+ while (grn_ii_cursor_next(ctx, c)) {
+ pos = c->post;
+ if ((w2 = get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg)) > 0) {
+ while (grn_ii_cursor_next_pos(ctx, c)) {
+ res_add(ctx, s, (grn_rset_posinfo *) pos,
+ *w1 * w2 * (1 + pos->weight), op);
+ }
+ }
+ }
+ } else {
+ while (grn_ii_cursor_next(ctx, c)) {
+ pos = c->post;
+ if ((w2 = get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg)) > 0) {
+ res_add(ctx, s, (grn_rset_posinfo *) pos,
+ *w1 * w2 * (pos->tf + pos->weight), op);
+ }
+ }
+ }
+ grn_ii_cursor_close(ctx, c);
+ }
+ grn_array_close(ctx, sorted);
+ }
+ grn_hash_close(ctx, h);
+ grn_ii_resolve_sel_and(ctx, s, op);
+ // grn_hash_cursor_clear(r);
+ return rc;
+}
+
+#define TERM_EXTRACT_EACH_POST 0
+#define TERM_EXTRACT_EACH_TERM 1
+
+grn_rc
+grn_ii_term_extract(grn_ctx *ctx, grn_ii *ii, const char *string,
+ unsigned int string_len, grn_hash *s,
+ grn_operator op, grn_select_optarg *optarg)
+{
+ grn_rset_posinfo pi;
+ grn_id tid;
+ const char *p, *pe;
+ grn_obj *nstr;
+ const char *normalized;
+ unsigned int normalized_length_in_bytes;
+ grn_ii_cursor *c;
+ grn_posting *pos;
+ int skip, rep, policy;
+ grn_rc rc = GRN_SUCCESS;
+ grn_wv_mode wvm = grn_wv_none;
+ if (!ii || !string || !string_len || !s || !optarg) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!(nstr = grn_string_open(ctx, string, string_len, NULL, 0))) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ policy = optarg->max_interval;
+ if (optarg->func) {
+ wvm = grn_wv_dynamic;
+ } else if (optarg->vector_size) {
+ wvm = optarg->weight_vector ? grn_wv_static : grn_wv_constant;
+ }
+ /* todo support subrec
+ if (policy == TERM_EXTRACT_EACH_POST) {
+ if ((rc = grn_records_reopen(s, grn_rec_section, grn_rec_none, 0))) { goto exit; }
+ }
+ rep = (s->record_unit == grn_rec_position || s->subrec_unit == grn_rec_position);
+ */
+ rep = 0;
+ grn_string_get_normalized(ctx, nstr, &normalized, &normalized_length_in_bytes,
+ NULL);
+ for (p = normalized, pe = p + normalized_length_in_bytes; p < pe; p += skip) {
+ if ((tid = grn_table_lcp_search(ctx, ii->lexicon, p, pe - p))) {
+ if (policy == TERM_EXTRACT_EACH_POST) {
+ if (!(skip = grn_table_get_key(ctx, ii->lexicon, tid, NULL, 0))) { break; }
+ } else {
+ if (!(skip = (int)grn_charlen(ctx, p, pe))) { break; }
+ }
+ if (!(c = grn_ii_cursor_open(ctx, ii, tid, GRN_ID_NIL, GRN_ID_MAX,
+ rep
+ ? ii->n_elements
+ : ii->n_elements - 1, 0))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "cursor open failed (%d)", tid);
+ continue;
+ }
+ if (rep) {
+ while (grn_ii_cursor_next(ctx, c)) {
+ pos = c->post;
+ while (grn_ii_cursor_next_pos(ctx, c)) {
+ res_add(ctx, s, (grn_rset_posinfo *) pos,
+ get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg), op);
+ }
+ }
+ } else {
+ while (grn_ii_cursor_next(ctx, c)) {
+ if (policy == TERM_EXTRACT_EACH_POST) {
+ pi.rid = c->post->rid;
+ pi.sid = p - normalized;
+ res_add(ctx, s, &pi, pi.sid + 1, op);
+ } else {
+ pos = c->post;
+ res_add(ctx, s, (grn_rset_posinfo *) pos,
+ get_weight(ctx, s, pos->rid, pos->sid, wvm, optarg), op);
+ }
+ }
+ }
+ grn_ii_cursor_close(ctx, c);
+ } else {
+ if (!(skip = (int)grn_charlen(ctx, p, pe))) {
+ break;
+ }
+ }
+ }
+ grn_obj_close(ctx, nstr);
+ return rc;
+}
+
+typedef struct {
+ grn_id rid;
+ uint32_t sid;
+ uint32_t start_pos;
+ uint32_t end_pos;
+ uint32_t tf;
+ uint32_t weight;
+} grn_ii_select_cursor_posting;
+
+typedef struct {
+ btr *bt;
+ grn_ii *ii;
+ token_info **tis;
+ uint32_t n_tis;
+ int max_interval;
+ grn_operator mode;
+ grn_ii_select_cursor_posting posting;
+ const char *string;
+ unsigned int string_len;
+ grn_bool done;
+ grn_ii_select_cursor_posting unshifted_posting;
+ grn_bool have_unshifted_posting;
+} grn_ii_select_cursor;
+
+static grn_rc
+grn_ii_select_cursor_close(grn_ctx *ctx,
+ grn_ii_select_cursor *cursor)
+{
+ token_info **tip;
+
+ if (!cursor) {
+ return GRN_SUCCESS;
+ }
+
+ for (tip = cursor->tis; tip < cursor->tis + cursor->n_tis; tip++) {
+ if (*tip) {
+ token_info_close(ctx, *tip);
+ }
+ }
+ if (cursor->tis) {
+ GRN_FREE(cursor->tis);
+ }
+ bt_close(ctx, cursor->bt);
+ GRN_FREE(cursor);
+
+ return GRN_SUCCESS;
+}
+
+static grn_ii_select_cursor *
+grn_ii_select_cursor_open(grn_ctx *ctx,
+ grn_ii *ii,
+ const char *string,
+ unsigned int string_len,
+ grn_select_optarg *optarg)
+{
+ grn_operator mode = GRN_OP_EXACT;
+ grn_ii_select_cursor *cursor;
+
+ if (string_len == 0) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[ii][select][cursor][open] empty string");
+ return NULL;
+ }
+
+ if (optarg) {
+ mode = optarg->mode;
+ }
+ switch (mode) {
+ case GRN_OP_EXACT :
+ case GRN_OP_FUZZY :
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT,
+ "[ii][select][cursor][open] "
+ "EXACT, FUZZY, NEAR and NEAR2 are only supported mode: %-.256s",
+ grn_operator_to_string(mode));
+ break;
+ }
+
+ cursor = GRN_CALLOC(sizeof(grn_ii_select_cursor));
+ if (!cursor) {
+ ERR(ctx->rc,
+ "[ii][select][cursor][open] failed to allocate cursor: %-.256s",
+ ctx->errbuf);
+ return NULL;
+ }
+
+ cursor->ii = ii;
+ cursor->mode = mode;
+
+ if (!(cursor->tis = GRN_MALLOC(sizeof(token_info *) * string_len * 2))) {
+ ERR(ctx->rc,
+ "[ii][select][cursor][open] failed to allocate token info container: %-.256s",
+ ctx->errbuf);
+ GRN_FREE(cursor);
+ return NULL;
+ }
+ cursor->n_tis = 0;
+ if (cursor->mode == GRN_OP_FUZZY) {
+ grn_bool only_skip_token = GRN_FALSE;
+ grn_id previous_min = GRN_ID_NIL;
+ if (token_info_build_fuzzy(ctx, ii->lexicon, ii, string, string_len,
+ cursor->tis, &(cursor->n_tis),
+ &only_skip_token, previous_min,
+ cursor->mode, &(optarg->fuzzy)) != GRN_SUCCESS) {
+ grn_ii_select_cursor_close(ctx, cursor);
+ return NULL;
+ }
+ } else {
+ grn_bool only_skip_token = GRN_FALSE;
+ grn_id previous_min = GRN_ID_NIL;
+ if (token_info_build(ctx, ii->lexicon, ii, string, string_len,
+ cursor->tis, &(cursor->n_tis),
+ &only_skip_token, previous_min,
+ cursor->mode) != GRN_SUCCESS) {
+ grn_ii_select_cursor_close(ctx, cursor);
+ return NULL;
+ }
+ }
+ if (cursor->n_tis == 0) {
+ grn_ii_select_cursor_close(ctx, cursor);
+ return NULL;
+ }
+
+ switch (cursor->mode) {
+ case GRN_OP_NEAR2 :
+ token_info_clear_offset(cursor->tis, cursor->n_tis);
+ cursor->mode = GRN_OP_NEAR;
+ /* fallthru */
+ case GRN_OP_NEAR :
+ if (!(cursor->bt = bt_open(ctx, cursor->n_tis))) {
+ ERR(ctx->rc,
+ "[ii][select][cursor][open] failed to allocate btree: %-.256s",
+ ctx->errbuf);
+ grn_ii_select_cursor_close(ctx, cursor);
+ return NULL;
+ }
+ cursor->max_interval = optarg->max_interval;
+ break;
+ default :
+ break;
+ }
+ qsort(cursor->tis, cursor->n_tis, sizeof(token_info *), token_compare);
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[ii][select][cursor][open] n=%d <%.*s>",
+ cursor->n_tis,
+ string_len, string);
+
+ cursor->string = string;
+ cursor->string_len = string_len;
+
+ cursor->done = GRN_FALSE;
+
+ cursor->have_unshifted_posting = GRN_FALSE;
+
+ return cursor;
+}
+
+static grn_ii_select_cursor_posting *
+grn_ii_select_cursor_next(grn_ctx *ctx,
+ grn_ii_select_cursor *cursor)
+{
+ btr *bt = cursor->bt;
+ token_info **tis = cursor->tis;
+ token_info **tie = tis + cursor->n_tis;
+ uint32_t n_tis = cursor->n_tis;
+ int max_interval = cursor->max_interval;
+ grn_operator mode = cursor->mode;
+
+ if (cursor->have_unshifted_posting) {
+ cursor->have_unshifted_posting = GRN_FALSE;
+ return &(cursor->unshifted_posting);
+ }
+
+ if (cursor->done) {
+ return NULL;
+ }
+
+ for (;;) {
+ grn_id rid;
+ grn_id sid;
+ grn_id next_rid;
+ grn_id next_sid;
+ token_info **tip;
+
+ rid = (*tis)->p->rid;
+ sid = (*tis)->p->sid;
+ for (tip = tis + 1, next_rid = rid, next_sid = sid + 1;
+ tip < tie;
+ tip++) {
+ token_info *ti = *tip;
+ if (token_info_skip(ctx, ti, rid, sid)) { return NULL; }
+ if (ti->p->rid != rid || ti->p->sid != sid) {
+ next_rid = ti->p->rid;
+ next_sid = ti->p->sid;
+ break;
+ }
+ }
+
+ if (tip == tie) {
+ int start_pos = 0;
+ int pos = 0;
+ int end_pos = 0;
+ int score = 0;
+ int tf = 0;
+ int tscore = 0;
+
+#define SKIP_OR_BREAK(pos) {\
+ if (token_info_skip_pos(ctx, ti, rid, sid, pos)) { break; } \
+ if (ti->p->rid != rid || ti->p->sid != sid) { \
+ next_rid = ti->p->rid; \
+ next_sid = ti->p->sid; \
+ break; \
+ } \
+}
+
+#define RETURN_POSTING() do { \
+ cursor->posting.rid = rid; \
+ cursor->posting.sid = sid; \
+ cursor->posting.start_pos = start_pos; \
+ cursor->posting.end_pos = end_pos; \
+ cursor->posting.tf = tf; \
+ cursor->posting.weight = tscore; \
+ if (token_info_skip_pos(ctx, *tis, rid, sid, pos) != GRN_SUCCESS) { \
+ if (token_info_skip(ctx, *tis, next_rid, next_sid) != GRN_SUCCESS) { \
+ cursor->done = GRN_TRUE; \
+ } \
+ } \
+ return &(cursor->posting); \
+} while (GRN_FALSE)
+
+ if (n_tis == 1) {
+ start_pos = pos = end_pos = (*tis)->p->pos;
+ pos++;
+ tf = (*tis)->p->tf;
+ tscore = (*tis)->p->weight + (*tis)->cursors->bins[0]->weight;
+ RETURN_POSTING();
+ } else if (mode == GRN_OP_NEAR) {
+ bt_zap(bt);
+ for (tip = tis; tip < tie; tip++) {
+ token_info *ti = *tip;
+ SKIP_OR_BREAK(pos);
+ bt_push(bt, ti);
+ }
+ if (tip == tie) {
+ for (;;) {
+ token_info *ti;
+ int min;
+ int max;
+
+ ti = bt->min;
+ min = ti->pos;
+ max = bt->max->pos;
+ if (min > max) {
+ char ii_name[GRN_TABLE_MAX_KEY_SIZE];
+ int ii_name_size;
+ ii_name_size = grn_obj_name(ctx,
+ (grn_obj *)(cursor->ii),
+ ii_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_FILE_CORRUPT,
+ "[ii][select][cursor][near] "
+ "max position must be larger than min position: "
+ "min:<%d> max:<%d> ii:<%.*s> string:<%.*s>",
+ min, max,
+ ii_name_size, ii_name,
+ cursor->string_len,
+ cursor->string);
+ return NULL;
+ }
+ if ((max_interval < 0) || (max - min <= max_interval)) {
+ /* TODO: Set start_pos, pos, end_pos, tf and tscore */
+ RETURN_POSTING();
+ if (ti->pos == max + 1) {
+ break;
+ }
+ SKIP_OR_BREAK(max + 1);
+ } else {
+ if (ti->pos == max - max_interval) {
+ break;
+ }
+ SKIP_OR_BREAK(max - max_interval);
+ }
+ bt_pop(bt);
+ }
+ }
+ } else {
+ int count = 0;
+ for (tip = tis; ; tip++) {
+ token_info *ti;
+
+ if (tip == tie) { tip = tis; }
+ ti = *tip;
+ SKIP_OR_BREAK(pos);
+ if (ti->pos == pos) {
+ score += ti->p->weight + ti->cursors->bins[0]->weight;
+ count++;
+ if ((int) ti->p->pos > end_pos) {
+ end_pos = ti->p->pos;
+ }
+ } else {
+ score = ti->p->weight + ti->cursors->bins[0]->weight;
+ count = 1;
+ start_pos = pos = ti->pos;
+ end_pos = ti->p->pos;
+ }
+ if (count == (int) n_tis) {
+ pos++;
+ if ((int) ti->p->pos > end_pos) {
+ end_pos = ti->p->pos;
+ }
+ tf = 1;
+ tscore += score;
+ RETURN_POSTING();
+ }
+ }
+ }
+#undef SKIP_OR_BREAK
+ }
+ if (token_info_skip(ctx, *tis, next_rid, next_sid)) {
+ return NULL;
+ }
+ }
+}
+
+static void
+grn_ii_select_cursor_unshift(grn_ctx *ctx,
+ grn_ii_select_cursor *cursor,
+ grn_ii_select_cursor_posting *posting)
+{
+ cursor->unshifted_posting = *posting;
+ cursor->have_unshifted_posting = GRN_TRUE;
+}
+
+static grn_rc
+grn_ii_parse_regexp_query(grn_ctx *ctx,
+ const char *log_tag,
+ const char *string, unsigned int string_len,
+ grn_obj *parsed_strings)
+{
+ grn_bool escaping = GRN_FALSE;
+ int nth_char = 0;
+ const char *current = string;
+ const char *string_end = string + string_len;
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ while (current < string_end) {
+ const char *target;
+ int char_len;
+
+ char_len = grn_charlen(ctx, current, string_end);
+ if (char_len == 0) {
+ GRN_OBJ_FIN(ctx, &buffer);
+ ERR(GRN_INVALID_ARGUMENT,
+ "%-.256s invalid encoding character: <%.*s|%#x|>",
+ log_tag,
+ (int)(current - string), string,
+ *current);
+ return ctx->rc;
+ }
+ target = current;
+ current += char_len;
+
+ if (escaping) {
+ escaping = GRN_FALSE;
+ if (char_len == 1) {
+ switch (*target) {
+ case 'A' :
+ if (nth_char == 0) {
+ target = GRN_TOKENIZER_BEGIN_MARK_UTF8;
+ char_len = GRN_TOKENIZER_BEGIN_MARK_UTF8_LEN;
+ }
+ break;
+ case 'z' :
+ if (current == string_end) {
+ target = GRN_TOKENIZER_END_MARK_UTF8;
+ char_len = GRN_TOKENIZER_END_MARK_UTF8_LEN;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+ } else {
+ if (char_len == 1) {
+ if (*target == '\\') {
+ escaping = GRN_TRUE;
+ continue;
+ } else if (*target == '.' &&
+ grn_charlen(ctx, current, string_end) == 1 &&
+ *current == '*') {
+ if (GRN_TEXT_LEN(&buffer) > 0) {
+ grn_vector_add_element(ctx,
+ parsed_strings,
+ GRN_TEXT_VALUE(&buffer),
+ GRN_TEXT_LEN(&buffer),
+ 0,
+ GRN_DB_TEXT);
+ GRN_BULK_REWIND(&buffer);
+ }
+ current++;
+ nth_char++;
+ continue;
+ }
+ }
+ }
+
+ GRN_TEXT_PUT(ctx, &buffer, target, char_len);
+ nth_char++;
+ }
+ if (GRN_TEXT_LEN(&buffer) > 0) {
+ grn_vector_add_element(ctx,
+ parsed_strings,
+ GRN_TEXT_VALUE(&buffer),
+ GRN_TEXT_LEN(&buffer),
+ 0,
+ GRN_DB_TEXT);
+ }
+ GRN_OBJ_FIN(ctx, &buffer);
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_ii_select_regexp(grn_ctx *ctx, grn_ii *ii,
+ const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_select_optarg *optarg)
+{
+ grn_rc rc;
+ grn_obj parsed_strings;
+ unsigned int n_parsed_strings;
+
+ GRN_TEXT_INIT(&parsed_strings, GRN_OBJ_VECTOR);
+ rc = grn_ii_parse_regexp_query(ctx, "[ii][select][regexp]",
+ string, string_len, &parsed_strings);
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FIN(ctx, &parsed_strings);
+ return rc;
+ }
+
+ if (optarg) {
+ optarg->mode = GRN_OP_EXACT;
+ }
+
+ n_parsed_strings = grn_vector_size(ctx, &parsed_strings);
+ if (n_parsed_strings == 1) {
+ const char *parsed_string;
+ unsigned int parsed_string_len;
+ parsed_string_len = grn_vector_get_element(ctx,
+ &parsed_strings,
+ 0,
+ &parsed_string,
+ NULL,
+ NULL);
+ rc = grn_ii_select(ctx, ii,
+ parsed_string,
+ parsed_string_len,
+ s, op, optarg);
+ } else {
+ int i;
+ grn_ii_select_cursor **cursors;
+ grn_bool have_error = GRN_FALSE;
+
+ cursors = GRN_CALLOC(sizeof(grn_ii_select_cursor *) * n_parsed_strings);
+ for (i = 0; (uint) i < n_parsed_strings; i++) {
+ const char *parsed_string;
+ unsigned int parsed_string_len;
+ parsed_string_len = grn_vector_get_element(ctx,
+ &parsed_strings,
+ i,
+ &parsed_string,
+ NULL,
+ NULL);
+ cursors[i] = grn_ii_select_cursor_open(ctx,
+ ii,
+ parsed_string,
+ parsed_string_len,
+ optarg);
+ if (!cursors[i]) {
+ have_error = GRN_TRUE;
+ break;
+ }
+ }
+
+ while (!have_error) {
+ grn_ii_select_cursor_posting *posting;
+ uint32_t pos;
+
+ posting = grn_ii_select_cursor_next(ctx, cursors[0]);
+ if (!posting) {
+ break;
+ }
+
+ pos = posting->end_pos;
+ for (i = 1; (uint) i < n_parsed_strings; i++) {
+ grn_ii_select_cursor_posting *posting_i;
+
+ for (;;) {
+ posting_i = grn_ii_select_cursor_next(ctx, cursors[i]);
+ if (!posting_i) {
+ break;
+ }
+
+ if (posting_i->rid == posting->rid &&
+ posting_i->sid == posting->sid &&
+ posting_i->start_pos > pos) {
+ grn_ii_select_cursor_unshift(ctx, cursors[i], posting_i);
+ break;
+ }
+ if (posting_i->rid > posting->rid) {
+ grn_ii_select_cursor_unshift(ctx, cursors[i], posting_i);
+ break;
+ }
+ }
+
+ if (!posting_i) {
+ break;
+ }
+
+ if (posting_i->rid != posting->rid || posting_i->sid != posting->sid) {
+ break;
+ }
+
+ pos = posting_i->end_pos;
+ }
+
+ if ((uint) i == n_parsed_strings) {
+ grn_rset_posinfo pi = {posting->rid, posting->sid, pos};
+ double record_score = 1.0;
+ res_add(ctx, s, &pi, record_score, op);
+ }
+ }
+
+ for (i = 0; (uint) i < n_parsed_strings; i++) {
+ if (cursors[i]) {
+ grn_ii_select_cursor_close(ctx, cursors[i]);
+ }
+ }
+ GRN_FREE(cursors);
+ }
+ GRN_OBJ_FIN(ctx, &parsed_strings);
+
+ if (optarg) {
+ optarg->mode = GRN_OP_REGEXP;
+ }
+
+ return rc;
+}
+
+#ifdef GRN_II_SELECT_ENABLE_SEQUENTIAL_SEARCH
+static grn_bool
+grn_ii_select_sequential_search_should_use(grn_ctx *ctx,
+ grn_ii *ii,
+ const char *raw_query,
+ unsigned int raw_query_len,
+ grn_hash *result,
+ grn_operator op,
+ grn_wv_mode wvm,
+ grn_select_optarg *optarg,
+ token_info **token_infos,
+ uint32_t n_token_infos,
+ double too_many_index_match_ratio)
+{
+ int n_sources;
+
+ if (too_many_index_match_ratio < 0.0) {
+ return GRN_FALSE;
+ }
+
+ if (op != GRN_OP_AND) {
+ return GRN_FALSE;
+ }
+
+ if (optarg->mode != GRN_OP_EXACT) {
+ return GRN_FALSE;
+ }
+
+ n_sources = ii->obj.source_size / sizeof(grn_id);
+ if (n_sources == 0) {
+ return GRN_FALSE;
+ }
+
+ {
+ uint32_t i;
+ int n_existing_records;
+
+ n_existing_records = GRN_HASH_SIZE(result);
+ for (i = 0; i < n_token_infos; i++) {
+ token_info *info = token_infos[i];
+ if (n_existing_records <= (info->size * too_many_index_match_ratio)) {
+ return GRN_TRUE;
+ }
+ }
+ return GRN_FALSE;
+ }
+}
+
+static void
+grn_ii_select_sequential_search_body(grn_ctx *ctx,
+ grn_ii *ii,
+ grn_obj *normalizer,
+ grn_encoding encoding,
+ OnigRegex regex,
+ grn_hash *result,
+ grn_operator op,
+ grn_wv_mode wvm,
+ grn_select_optarg *optarg)
+{
+ int i, n_sources;
+ grn_id *source_ids = ii->obj.source;
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ n_sources = ii->obj.source_size / sizeof(grn_id);
+ for (i = 0; i < n_sources; i++) {
+ grn_id source_id = source_ids[i];
+ grn_obj *source;
+ grn_obj *accessor;
+
+ source = grn_ctx_at(ctx, source_id);
+ switch (source->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ accessor = grn_obj_column(ctx,
+ (grn_obj *)result,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ break;
+ default :
+ {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ column_name_size = grn_column_name(ctx, source,
+ column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ accessor = grn_obj_column(ctx, (grn_obj *)result, column_name,
+ column_name_size);
+ }
+ break;
+ }
+
+ {
+ grn_hash_cursor *cursor;
+ grn_id id;
+ cursor = grn_hash_cursor_open(ctx, result, NULL, 0, NULL, 0, 0, -1, 0);
+ while ((id = grn_hash_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ OnigPosition position;
+ grn_obj *value;
+ const char *normalized_value;
+ unsigned int normalized_value_length;
+
+ GRN_BULK_REWIND(&buffer);
+ grn_obj_get_value(ctx, accessor, id, &buffer);
+ value = grn_string_open_(ctx,
+ GRN_TEXT_VALUE(&buffer),
+ GRN_TEXT_LEN(&buffer),
+ normalizer, 0, encoding);
+ grn_string_get_normalized(ctx, value,
+ &normalized_value, &normalized_value_length,
+ NULL);
+ position = onig_search(regex,
+ normalized_value,
+ normalized_value + normalized_value_length,
+ normalized_value,
+ normalized_value + normalized_value_length,
+ NULL,
+ 0);
+ if (position != ONIG_MISMATCH) {
+ grn_id *record_id;
+ grn_rset_posinfo info;
+ double score;
+
+ grn_hash_cursor_get_key(ctx, cursor, (void **)&record_id);
+
+ info.rid = *record_id;
+ info.sid = i + 1;
+ info.pos = 0;
+ score = get_weight(ctx, result, info.rid, info.sid, wvm, optarg);
+ res_add(ctx, result, &info, score, op);
+ }
+ grn_obj_unlink(ctx, value);
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ grn_obj_unlink(ctx, accessor);
+ }
+ grn_obj_unlink(ctx, &buffer);
+}
+
+static grn_bool
+grn_ii_select_sequential_search(grn_ctx *ctx,
+ grn_ii *ii,
+ const char *raw_query,
+ unsigned int raw_query_len,
+ grn_hash *result,
+ grn_operator op,
+ grn_wv_mode wvm,
+ grn_select_optarg *optarg,
+ token_info **token_infos,
+ uint32_t n_token_infos)
+{
+ grn_bool processed = GRN_TRUE;
+
+ {
+ if (!grn_ii_select_sequential_search_should_use(ctx,
+ ii,
+ raw_query,
+ raw_query_len,
+ result,
+ op,
+ wvm,
+ optarg,
+ token_infos,
+ n_token_infos,
+ grn_ii_select_too_many_index_match_ratio)) {
+ return GRN_FALSE;
+ }
+ }
+
+ {
+ grn_encoding encoding;
+ grn_obj *normalizer;
+ int nflags = 0;
+ grn_obj *query;
+ const char *normalized_query;
+ unsigned int normalized_query_length;
+
+ grn_table_get_info(ctx, ii->lexicon,
+ NULL, &encoding, NULL, &normalizer, NULL);
+ query = grn_string_open_(ctx, raw_query, raw_query_len,
+ normalizer, nflags, encoding);
+ grn_string_get_normalized(ctx, query,
+ &normalized_query, &normalized_query_length,
+ NULL);
+ {
+ OnigRegex regex;
+ int onig_result;
+ OnigErrorInfo error_info;
+ onig_result = onig_new(&regex,
+ normalized_query,
+ normalized_query + normalized_query_length,
+ ONIG_OPTION_NONE,
+ ONIG_ENCODING_UTF8,
+ ONIG_SYNTAX_ASIS,
+ &error_info);
+ if (onig_result == ONIG_NORMAL) {
+ grn_ii_select_sequential_search_body(ctx, ii, normalizer, encoding,
+ regex, result, op, wvm, optarg);
+ onig_free(regex);
+ } else {
+ char message[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str(message, onig_result, error_info);
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[ii][select][sequential] "
+ "failed to create regular expression object: %-.256s",
+ message);
+ processed = GRN_FALSE;
+ }
+ }
+ grn_obj_unlink(ctx, query);
+ }
+
+ return processed;
+}
+#endif
+
+grn_rc
+grn_ii_select(grn_ctx *ctx, grn_ii *ii,
+ const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_select_optarg *optarg)
+{
+ btr *bt = NULL;
+ grn_rc rc = GRN_SUCCESS;
+ int rep, orp, weight, max_interval = 0;
+ token_info *ti, **tis = NULL, **tip, **tie;
+ uint32_t n = 0, rid, sid, nrid, nsid;
+ grn_bool only_skip_token = GRN_FALSE;
+ grn_operator mode = GRN_OP_EXACT;
+ grn_wv_mode wvm = grn_wv_none;
+ grn_obj *lexicon = ii->lexicon;
+ grn_scorer_score_func *score_func = NULL;
+ grn_scorer_matched_record record;
+ grn_id previous_min = GRN_ID_NIL;
+ grn_id current_min = GRN_ID_NIL;
+ grn_bool set_min_enable_for_and_query = GRN_FALSE;
+
+ if (!lexicon || !ii || !s) { return GRN_INVALID_ARGUMENT; }
+ if (optarg) {
+ mode = optarg->mode;
+ if (optarg->func) {
+ wvm = grn_wv_dynamic;
+ } else if (optarg->vector_size) {
+ wvm = optarg->weight_vector ? grn_wv_static : grn_wv_constant;
+ }
+ if (optarg->match_info) {
+ if (optarg->match_info->flags & GRN_MATCH_INFO_GET_MIN_RECORD_ID) {
+ previous_min = optarg->match_info->min;
+ set_min_enable_for_and_query = GRN_TRUE;
+ }
+ }
+ }
+ if (mode == GRN_OP_SIMILAR) {
+ return grn_ii_similar_search(ctx, ii, string, string_len, s, op, optarg);
+ }
+ if (mode == GRN_OP_TERM_EXTRACT) {
+ return grn_ii_term_extract(ctx, ii, string, string_len, s, op, optarg);
+ }
+ if (mode == GRN_OP_REGEXP) {
+ return grn_ii_select_regexp(ctx, ii, string, string_len, s, op, optarg);
+ }
+ /* todo : support subrec
+ rep = (s->record_unit == grn_rec_position || s->subrec_unit == grn_rec_position);
+ orp = (s->record_unit == grn_rec_position || op == GRN_OP_OR);
+ */
+ rep = 0;
+ orp = op == GRN_OP_OR;
+ if (!string_len) { goto exit; }
+ if (!(tis = GRN_MALLOC(sizeof(token_info *) * string_len * 2))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (mode == GRN_OP_FUZZY) {
+ if (token_info_build_fuzzy(ctx, lexicon, ii, string, string_len,
+ tis, &n, &only_skip_token, previous_min,
+ mode, &(optarg->fuzzy)) ||
+ !n) {
+ goto exit;
+ }
+ } else {
+ if (token_info_build(ctx, lexicon, ii, string, string_len,
+ tis, &n, &only_skip_token, previous_min, mode) ||
+ !n) {
+ goto exit;
+ }
+ }
+ switch (mode) {
+ case GRN_OP_NEAR2 :
+ token_info_clear_offset(tis, n);
+ mode = GRN_OP_NEAR;
+ /* fallthru */
+ case GRN_OP_NEAR :
+ if (!(bt = bt_open(ctx, n))) { rc = GRN_NO_MEMORY_AVAILABLE; goto exit; }
+ max_interval = optarg->max_interval;
+ break;
+ default :
+ break;
+ }
+ qsort(tis, n, sizeof(token_info *), token_compare);
+ tie = tis + n;
+ /*
+ for (tip = tis; tip < tie; tip++) {
+ ti = *tip;
+ grn_log("o=%d n=%d s=%d r=%d", ti->offset, ti->ntoken, ti->size, ti->rid);
+ }
+ */
+ GRN_LOG(ctx, GRN_LOG_INFO, "n=%d (%.*s)", n, string_len, string);
+ /* todo : array as result
+ if (n == 1 && (*tis)->cursors->n_entries == 1 && op == GRN_OP_OR
+ && !GRN_HASH_SIZE(s) && !s->garbages
+ && s->record_unit == grn_rec_document && !s->max_n_subrecs
+ && grn_ii_max_section(ii) == 1) {
+ grn_ii_cursor *c = (*tis)->cursors->bins[0];
+ if ((rc = grn_hash_array_init(s, (*tis)->size + 32768))) { goto exit; }
+ do {
+ grn_rset_recinfo *ri;
+ grn_posting *p = c->post;
+ if ((weight = get_weight(ctx, s, p->rid, p->sid, wvm, optarg))) {
+ GRN_HASH_INT_ADD(s, p, ri);
+ ri->score = (p->tf + p->score) * weight;
+ ri->n_subrecs = 1;
+ }
+ } while (grn_ii_cursor_next(ctx, c));
+ goto exit;
+ }
+ */
+#ifdef GRN_II_SELECT_ENABLE_SEQUENTIAL_SEARCH
+ if (grn_ii_select_sequential_search(ctx, ii, string, string_len,
+ s, op, wvm, optarg, tis, n)) {
+ goto exit;
+ }
+#endif
+
+ if (optarg && optarg->scorer) {
+ grn_proc *scorer = (grn_proc *)(optarg->scorer);
+ score_func = scorer->callbacks.scorer.score;
+ record.table = grn_ctx_at(ctx, s->obj.header.domain);
+ record.lexicon = lexicon;
+ record.id = GRN_ID_NIL;
+ GRN_RECORD_INIT(&(record.terms), GRN_OBJ_VECTOR, lexicon->header.domain);
+ GRN_UINT32_INIT(&(record.term_weights), GRN_OBJ_VECTOR);
+ record.total_term_weights = 0;
+ record.n_documents = grn_table_size(ctx, record.table);
+ record.n_occurrences = 0;
+ record.n_candidates = 0;
+ record.n_tokens = 0;
+ record.weight = 0;
+ record.args_expr = optarg->scorer_args_expr;
+ record.args_expr_offset = optarg->scorer_args_expr_offset;
+ }
+
+ for (;;) {
+ rid = (*tis)->p->rid;
+ sid = (*tis)->p->sid;
+ for (tip = tis + 1, nrid = rid, nsid = sid + 1; tip < tie; tip++) {
+ ti = *tip;
+ if (token_info_skip(ctx, ti, rid, sid)) { goto exit; }
+ if (ti->p->rid != rid || ti->p->sid != sid) {
+ nrid = ti->p->rid;
+ nsid = ti->p->sid;
+ break;
+ }
+ }
+ weight = get_weight(ctx, s, rid, sid, wvm, optarg);
+ if (tip == tie && weight != 0) {
+ grn_rset_posinfo pi = {rid, sid, 0};
+ if (orp || grn_hash_get(ctx, s, &pi, s->key_size, NULL)) {
+ int count = 0, noccur = 0, pos = 0, score = 0, tscore = 0, min, max;
+
+ if (score_func) {
+ GRN_BULK_REWIND(&(record.terms));
+ GRN_BULK_REWIND(&(record.term_weights));
+ record.n_candidates = 0;
+ record.n_tokens = 0;
+ }
+
+#define SKIP_OR_BREAK(pos) {\
+ if (token_info_skip_pos(ctx, ti, rid, sid, pos)) { break; } \
+ if (ti->p->rid != rid || ti->p->sid != sid) { \
+ nrid = ti->p->rid; \
+ nsid = ti->p->sid; \
+ break; \
+ } \
+}
+ if (n == 1 && !rep) {
+ noccur = (*tis)->p->tf;
+ tscore = (*tis)->p->weight + (*tis)->cursors->bins[0]->weight;
+ if (score_func) {
+ GRN_RECORD_PUT(ctx, &(record.terms), (*tis)->cursors->bins[0]->id);
+ GRN_UINT32_PUT(ctx, &(record.term_weights), tscore);
+ record.n_occurrences = noccur;
+ record.n_candidates = (*tis)->size;
+ record.n_tokens = (*tis)->ntoken;
+ }
+ } else if (mode == GRN_OP_NEAR) {
+ bt_zap(bt);
+ for (tip = tis; tip < tie; tip++) {
+ ti = *tip;
+ SKIP_OR_BREAK(pos);
+ bt_push(bt, ti);
+ }
+ if (tip == tie) {
+ for (;;) {
+ ti = bt->min; min = ti->pos; max = bt->max->pos;
+ if (min > max) {
+ char ii_name[GRN_TABLE_MAX_KEY_SIZE];
+ int ii_name_size;
+ ii_name_size = grn_obj_name(ctx, (grn_obj *)ii, ii_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_FILE_CORRUPT,
+ "[ii][select][near] "
+ "max position must be larger than min position: "
+ "min:<%d> max:<%d> ii:<%.*s> string:<%.*s>",
+ min, max,
+ ii_name_size, ii_name,
+ string_len, string);
+ rc = ctx->rc;
+ goto exit;
+ }
+ if ((max_interval < 0) || (max - min <= max_interval)) {
+ if (rep) { pi.pos = min; res_add(ctx, s, &pi, weight, op); }
+ noccur++;
+ if (ti->pos == max + 1) {
+ break;
+ }
+ SKIP_OR_BREAK(max + 1);
+ } else {
+ if (ti->pos == max - max_interval) {
+ break;
+ }
+ SKIP_OR_BREAK(max - max_interval);
+ }
+ bt_pop(bt);
+ }
+ }
+ } else {
+ for (tip = tis; ; tip++) {
+ if (tip == tie) { tip = tis; }
+ ti = *tip;
+ SKIP_OR_BREAK(pos);
+ if (ti->pos == pos) {
+ score += ti->p->weight + ti->cursors->bins[0]->weight; count++;
+ } else {
+ score = ti->p->weight + ti->cursors->bins[0]->weight; count = 1;
+ pos = ti->pos;
+ if (noccur == 0 && score_func) {
+ GRN_BULK_REWIND(&(record.terms));
+ GRN_BULK_REWIND(&(record.term_weights));
+ record.n_candidates = 0;
+ record.n_tokens = 0;
+ }
+ }
+ if (noccur == 0 && score_func) {
+ GRN_RECORD_PUT(ctx, &(record.terms), ti->cursors->bins[0]->id);
+ GRN_UINT32_PUT(ctx, &(record.term_weights),
+ ti->p->weight + ti->cursors->bins[0]->weight);
+ record.n_candidates += ti->size;
+ record.n_tokens += ti->ntoken;
+ }
+ if ((uint) count == n) {
+ if (rep) {
+ pi.pos = pos; res_add(ctx, s, &pi, (score + 1) * weight, op);
+ }
+ tscore += score;
+ score = 0; count = 0; pos++;
+ noccur++;
+ }
+ }
+ }
+ if (noccur && !rep) {
+ double record_score;
+ if (score_func) {
+ record.id = rid;
+ record.weight = weight;
+ record.n_occurrences = noccur;
+ record.total_term_weights = tscore;
+ record_score = score_func(ctx, &record) * weight;
+ } else {
+ record_score = (noccur + tscore) * weight;
+ }
+ if (set_min_enable_for_and_query) {
+ if (current_min == GRN_ID_NIL) {
+ current_min = rid;
+ }
+ }
+ res_add(ctx, s, &pi, record_score, op);
+ }
+#undef SKIP_OR_BREAK
+ }
+ }
+ if (token_info_skip(ctx, *tis, nrid, nsid)) { goto exit; }
+ }
+exit :
+ if (score_func) {
+ GRN_OBJ_FIN(ctx, &(record.terms));
+ GRN_OBJ_FIN(ctx, &(record.term_weights));
+ }
+
+ if (set_min_enable_for_and_query) {
+ if (current_min > previous_min) {
+ optarg->match_info->min = current_min;
+ }
+ }
+
+ for (tip = tis; tip < tis + n; tip++) {
+ if (*tip) { token_info_close(ctx, *tip); }
+ }
+ if (tis) { GRN_FREE(tis); }
+ if (!only_skip_token) {
+ grn_ii_resolve_sel_and(ctx, s, op);
+ }
+ // grn_hash_cursor_clear(r);
+ bt_close(ctx, bt);
+#ifdef DEBUG
+ {
+ uint32_t segno = GRN_II_MAX_LSEG, nnref = 0;
+ grn_io_mapinfo *info = ii->seg->maps;
+ for (; segno; segno--, info++) { if (info->nref) { nnref++; } }
+ GRN_LOG(ctx, GRN_LOG_INFO, "nnref=%d", nnref);
+ }
+#endif /* DEBUG */
+ return rc;
+}
+
+static uint32_t
+grn_ii_estimate_size_for_query_regexp(grn_ctx *ctx, grn_ii *ii,
+ const char *query, unsigned int query_len,
+ grn_search_optarg *optarg)
+{
+ grn_rc rc;
+ grn_obj parsed_query;
+ uint32_t size;
+
+ GRN_TEXT_INIT(&parsed_query, 0);
+ rc = grn_ii_parse_regexp_query(ctx, "[ii][estimate-size][query][regexp]",
+ query, query_len, &parsed_query);
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FIN(ctx, &parsed_query);
+ return 0;
+ }
+
+ if (optarg) {
+ optarg->mode = GRN_OP_EXACT;
+ }
+
+ size = grn_ii_estimate_size_for_query(ctx, ii,
+ GRN_TEXT_VALUE(&parsed_query),
+ GRN_TEXT_LEN(&parsed_query),
+ optarg);
+ GRN_OBJ_FIN(ctx, &parsed_query);
+
+ if (optarg) {
+ optarg->mode = GRN_OP_REGEXP;
+ }
+
+ return size;
+}
+
+uint32_t
+grn_ii_estimate_size_for_query(grn_ctx *ctx, grn_ii *ii,
+ const char *query, unsigned int query_len,
+ grn_search_optarg *optarg)
+{
+ grn_rc rc;
+ grn_obj *lexicon = ii->lexicon;
+ token_info **tis = NULL;
+ uint32_t i;
+ uint32_t n_tis = 0;
+ grn_bool only_skip_token = GRN_FALSE;
+ grn_operator mode = GRN_OP_EXACT;
+ double estimated_size = 0;
+ double normalized_ratio = 1.0;
+ grn_id min = GRN_ID_NIL;
+
+ if (query_len == 0) {
+ return 0;
+ }
+
+ if (optarg) {
+ switch (optarg->mode) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ mode = optarg->mode;
+ break;
+ case GRN_OP_SIMILAR :
+ mode = optarg->mode;
+ break;
+ case GRN_OP_REGEXP :
+ mode = optarg->mode;
+ break;
+ case GRN_OP_FUZZY :
+ mode = optarg->mode;
+ default :
+ break;
+ }
+ if (optarg->match_info.flags & GRN_MATCH_INFO_GET_MIN_RECORD_ID) {
+ min = optarg->match_info.min;
+ }
+ }
+
+ if (mode == GRN_OP_REGEXP) {
+ return grn_ii_estimate_size_for_query_regexp(ctx, ii, query, query_len,
+ optarg);
+ }
+
+ tis = GRN_MALLOC(sizeof(token_info *) * query_len * 2);
+ if (!tis) {
+ return 0;
+ }
+
+ switch (mode) {
+ case GRN_OP_FUZZY :
+ rc = token_info_build_fuzzy(ctx, lexicon, ii, query, query_len,
+ tis, &n_tis, &only_skip_token, min,
+ mode, &(optarg->fuzzy));
+ break;
+ default :
+ rc = token_info_build(ctx, lexicon, ii, query, query_len,
+ tis, &n_tis, &only_skip_token, min, mode);
+ break;
+ }
+
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ for (i = 0; i < n_tis; i++) {
+ token_info *ti = tis[i];
+ double term_estimated_size;
+ term_estimated_size = ((double)ti->size / ti->ntoken);
+ if (i == 0) {
+ estimated_size = term_estimated_size;
+ } else {
+ if (term_estimated_size < estimated_size) {
+ estimated_size = term_estimated_size;
+ }
+ normalized_ratio *= grn_ii_estimate_size_for_query_reduce_ratio;
+ }
+ }
+
+ estimated_size *= normalized_ratio;
+ if (estimated_size > 0.0 && estimated_size < 1.0) {
+ estimated_size = 1.0;
+ }
+
+exit :
+ for (i = 0; i < n_tis; i++) {
+ token_info *ti = tis[i];
+ if (ti) {
+ token_info_close(ctx, ti);
+ }
+ }
+ if (tis) {
+ GRN_FREE(tis);
+ }
+
+ return estimated_size;
+}
+
+uint32_t
+grn_ii_estimate_size_for_lexicon_cursor(grn_ctx *ctx, grn_ii *ii,
+ grn_table_cursor *lexicon_cursor)
+{
+ grn_id term_id;
+ uint32_t estimated_size = 0;
+
+ while ((term_id = grn_table_cursor_next(ctx, lexicon_cursor)) != GRN_ID_NIL) {
+ uint32_t term_estimated_size;
+ term_estimated_size = grn_ii_estimate_size(ctx, ii, term_id);
+ estimated_size += term_estimated_size;
+ }
+
+ return estimated_size;
+}
+
+grn_rc
+grn_ii_sel(grn_ctx *ctx, grn_ii *ii, const char *string, unsigned int string_len,
+ grn_hash *s, grn_operator op, grn_search_optarg *optarg)
+{
+ ERRCLR(ctx);
+ GRN_LOG(ctx, GRN_LOG_INFO, "grn_ii_sel > (%.*s)", string_len, string);
+ {
+ grn_select_optarg arg;
+ if (!s) { return GRN_INVALID_ARGUMENT; }
+ memset(&arg, 0, sizeof(grn_select_optarg));
+ arg.mode = GRN_OP_EXACT;
+ if (optarg) {
+ switch (optarg->mode) {
+ case GRN_OP_NEAR :
+ case GRN_OP_NEAR2 :
+ arg.mode = optarg->mode;
+ arg.max_interval = optarg->max_interval;
+ break;
+ case GRN_OP_SIMILAR :
+ arg.mode = optarg->mode;
+ arg.similarity_threshold = optarg->similarity_threshold;
+ break;
+ case GRN_OP_REGEXP :
+ arg.mode = optarg->mode;
+ break;
+ case GRN_OP_FUZZY :
+ arg.mode = optarg->mode;
+ arg.fuzzy = optarg->fuzzy;
+ break;
+ default :
+ break;
+ }
+ if (optarg->vector_size != 0) {
+ arg.weight_vector = optarg->weight_vector;
+ arg.vector_size = optarg->vector_size;
+ }
+ arg.scorer = optarg->scorer;
+ arg.scorer_args_expr = optarg->scorer_args_expr;
+ arg.scorer_args_expr_offset = optarg->scorer_args_expr_offset;
+ arg.match_info = &(optarg->match_info);
+ }
+ /* todo : support subrec
+ grn_rset_init(ctx, s, grn_rec_document, 0, grn_rec_none, 0, 0);
+ */
+ if (grn_ii_select(ctx, ii, string, string_len, s, op, &arg)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "grn_ii_select on grn_ii_sel(1) failed !");
+ return ctx->rc;
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO, "exact: %d", GRN_HASH_SIZE(s));
+ if (op == GRN_OP_OR) {
+ grn_id min = GRN_ID_NIL;
+ if ((int64_t)GRN_HASH_SIZE(s) <= ctx->impl->match_escalation_threshold) {
+ arg.mode = GRN_OP_UNSPLIT;
+ if (arg.match_info) {
+ if (arg.match_info->flags & GRN_MATCH_INFO_GET_MIN_RECORD_ID) {
+ min = arg.match_info->min;
+ arg.match_info->min = GRN_ID_NIL;
+ }
+ }
+ if (grn_ii_select(ctx, ii, string, string_len, s, op, &arg)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "grn_ii_select on grn_ii_sel(2) failed !");
+ return ctx->rc;
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO, "unsplit: %d", GRN_HASH_SIZE(s));
+ if (arg.match_info) {
+ if (arg.match_info->flags & GRN_MATCH_INFO_GET_MIN_RECORD_ID) {
+ if (min > GRN_ID_NIL && min < arg.match_info->min) {
+ arg.match_info->min = min;
+ }
+ }
+ }
+ }
+ if ((int64_t)GRN_HASH_SIZE(s) <= ctx->impl->match_escalation_threshold) {
+ arg.mode = GRN_OP_PARTIAL;
+ if (arg.match_info) {
+ if (arg.match_info->flags & GRN_MATCH_INFO_GET_MIN_RECORD_ID) {
+ min = arg.match_info->min;
+ arg.match_info->min = GRN_ID_NIL;
+ }
+ }
+ if (grn_ii_select(ctx, ii, string, string_len, s, op, &arg)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "grn_ii_select on grn_ii_sel(3) failed !");
+ return ctx->rc;
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO, "partial: %d", GRN_HASH_SIZE(s));
+ if (arg.match_info) {
+ if (arg.match_info->flags & GRN_MATCH_INFO_GET_MIN_RECORD_ID) {
+ if (min > GRN_ID_NIL && min < arg.match_info->min) {
+ arg.match_info->min = min;
+ }
+ }
+ }
+ }
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO, "hits=%d", GRN_HASH_SIZE(s));
+ return GRN_SUCCESS;
+ }
+}
+
+grn_rc
+grn_ii_at(grn_ctx *ctx, grn_ii *ii, grn_id id, grn_hash *s, grn_operator op)
+{
+ int rep = 0;
+ grn_ii_cursor *c;
+ grn_posting *pos;
+ if ((c = grn_ii_cursor_open(ctx, ii, id, GRN_ID_NIL, GRN_ID_MAX,
+ rep ? ii->n_elements : ii->n_elements - 1, 0))) {
+ while ((pos = grn_ii_cursor_next(ctx, c))) {
+ res_add(ctx, s, (grn_rset_posinfo *) pos, (1 + pos->weight), op);
+ }
+ grn_ii_cursor_close(ctx, c);
+ }
+ return ctx->rc;
+}
+
+void
+grn_ii_resolve_sel_and(grn_ctx *ctx, grn_hash *s, grn_operator op)
+{
+ if (op == GRN_OP_AND
+ && !(ctx->flags & GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND)) {
+ grn_id eid;
+ grn_rset_recinfo *ri;
+ grn_hash_cursor *c = grn_hash_cursor_open(ctx, s, NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (c) {
+ while ((eid = grn_hash_cursor_next(ctx, c))) {
+ grn_hash_cursor_get_value(ctx, c, (void **) &ri);
+ if ((ri->n_subrecs & GRN_RSET_UTIL_BIT)) {
+ ri->n_subrecs &= ~GRN_RSET_UTIL_BIT;
+ } else {
+ grn_hash_delete_by_id(ctx, s, eid, NULL);
+ }
+ }
+ grn_hash_cursor_close(ctx, c);
+ }
+ }
+}
+
+void
+grn_ii_cursor_inspect(grn_ctx *ctx, grn_ii_cursor *c, grn_obj *buf)
+{
+ grn_obj key_buf;
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_size;
+ int i = 0;
+ grn_ii_cursor_next_options options = {
+ .include_garbage = GRN_TRUE
+ };
+
+ GRN_TEXT_PUTS(ctx, buf, " #<");
+ key_size = grn_table_get_key(ctx, c->ii->lexicon, c->id,
+ key, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_OBJ_INIT(&key_buf, GRN_BULK, 0, c->ii->lexicon->header.domain);
+ GRN_TEXT_SET(ctx, &key_buf, key, key_size);
+ grn_inspect(ctx, buf, &key_buf);
+ GRN_OBJ_FIN(ctx, &key_buf);
+
+ GRN_TEXT_PUTS(ctx, buf, "\n elements:[\n ");
+ while (grn_ii_cursor_next_internal(ctx, c, &options)) {
+ grn_posting *pos = c->post;
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buf, ",\n ");
+ }
+ i++;
+ GRN_TEXT_PUTS(ctx, buf, "{status:");
+ if (pos->tf && pos->sid) {
+ GRN_TEXT_PUTS(ctx, buf, "available");
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "garbage");
+ }
+ GRN_TEXT_PUTS(ctx, buf, ", rid:");
+ grn_text_lltoa(ctx, buf, pos->rid);
+ GRN_TEXT_PUTS(ctx, buf, ", sid:");
+ grn_text_lltoa(ctx, buf, pos->sid);
+ GRN_TEXT_PUTS(ctx, buf, ", pos:");
+ grn_text_lltoa(ctx, buf, pos->pos);
+ GRN_TEXT_PUTS(ctx, buf, ", tf:");
+ grn_text_lltoa(ctx, buf, pos->tf);
+ GRN_TEXT_PUTS(ctx, buf, ", weight:");
+ grn_text_lltoa(ctx, buf, pos->weight);
+ GRN_TEXT_PUTS(ctx, buf, ", rest:");
+ grn_text_lltoa(ctx, buf, pos->rest);
+ GRN_TEXT_PUTS(ctx, buf, "}");
+ }
+ GRN_TEXT_PUTS(ctx, buf, "\n ]\n >");
+}
+
+void
+grn_ii_inspect_values(grn_ctx *ctx, grn_ii *ii, grn_obj *buf)
+{
+ grn_table_cursor *tc;
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ if ((tc = grn_table_cursor_open(ctx, ii->lexicon, NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_ASCENDING))) {
+ int i = 0;
+ grn_id tid;
+ grn_ii_cursor *c;
+ while ((tid = grn_table_cursor_next(ctx, tc))) {
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buf, ",");
+ }
+ i++;
+ GRN_TEXT_PUTS(ctx, buf, "\n");
+ if ((c = grn_ii_cursor_open(ctx, ii, tid, GRN_ID_NIL, GRN_ID_MAX,
+ ii->n_elements,
+ GRN_OBJ_WITH_POSITION|GRN_OBJ_WITH_SECTION))) {
+ grn_ii_cursor_inspect(ctx, c, buf);
+ grn_ii_cursor_close(ctx, c);
+ }
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+}
+
+/********************** buffered index builder ***********************/
+
+const grn_id II_BUFFER_TYPE_MASK = 0xc0000000;
+#define II_BUFFER_TYPE_RID 0x80000000
+#define II_BUFFER_TYPE_WEIGHT 0x40000000
+#define II_BUFFER_TYPE(id) (((id) & II_BUFFER_TYPE_MASK))
+#define II_BUFFER_PACK(value, type) ((value) | (type))
+#define II_BUFFER_UNPACK(id, type) ((id) & ~(type))
+#define II_BUFFER_ORDER GRN_CURSOR_BY_KEY
+const uint16_t II_BUFFER_NTERMS_PER_BUFFER = 16380;
+const uint32_t II_BUFFER_PACKED_BUF_SIZE = 0x4000000;
+const char *TMPFILE_PATH = "grn_ii_buffer_tmp";
+const uint32_t II_BUFFER_NCOUNTERS_MARGIN = 0x100000;
+const size_t II_BUFFER_BLOCK_SIZE = 0x1000000;
+const uint32_t II_BUFFER_BLOCK_READ_UNIT_SIZE = 0x200000;
+
+typedef struct {
+ unsigned int sid; /* Section ID */
+ unsigned int weight; /* Weight */
+ const char *p; /* Value address */
+ uint32_t len; /* Value length */
+ char *buf; /* Buffer address */
+ uint32_t cap; /* Buffer size */
+} ii_buffer_value;
+
+/* ii_buffer_counter is associated with a combination of a block an a term. */
+typedef struct {
+ uint32_t nrecs; /* Number of records or sections */
+ uint32_t nposts; /* Number of occurrences */
+
+ /* Information of the last value */
+ grn_id last_rid; /* Record ID */
+ uint32_t last_sid; /* Section ID */
+ uint32_t last_tf; /* Term frequency */
+ uint32_t last_weight; /* Total weight */
+ uint32_t last_pos; /* Token position */
+
+ /* Meaning of offset_* is different before/after encoding. */
+ /* Before encoding: size in encoded sequence */
+ /* After encoding: Offset in encoded sequence */
+ uint32_t offset_rid; /* Record ID */
+ uint32_t offset_sid; /* Section ID */
+ uint32_t offset_tf; /* Term frequency */
+ uint32_t offset_weight; /* Weight */
+ uint32_t offset_pos; /* Token position */
+} ii_buffer_counter;
+
+typedef struct {
+ off64_t head;
+ off64_t tail;
+ uint32_t nextsize;
+ uint8_t *buffer;
+ uint32_t buffersize;
+ uint8_t *bufcur;
+ uint32_t rest;
+ grn_id tid;
+ uint32_t nrecs;
+ uint32_t nposts;
+ grn_id *recs;
+ uint32_t *tfs;
+ uint32_t *posts;
+} ii_buffer_block;
+
+struct _grn_ii_buffer {
+ grn_obj *lexicon; /* Global lexicon */
+ grn_obj *tmp_lexicon; /* Temporary lexicon for each block */
+ ii_buffer_block *blocks; /* Blocks */
+ uint32_t nblocks; /* Number of blocks */
+ int tmpfd; /* Descriptor of temporary file */
+ char tmpfpath[PATH_MAX]; /* Path of temporary file */
+ uint64_t update_buffer_size;
+
+ // stuff for parsing
+ off64_t filepos; /* Write position of temporary file */
+ grn_id *block_buf; /* Buffer for the current block */
+ size_t block_buf_size; /* Size of block_buf */
+ size_t block_pos; /* Write position of block_buf */
+ ii_buffer_counter *counters; /* Status of terms */
+ uint32_t ncounters; /* Number of counters */
+ size_t total_size;
+ size_t curr_size;
+ ii_buffer_value *values; /* Values in block */
+ unsigned int nvalues; /* Number of values in block */
+ unsigned int max_nvalues; /* Size of values */
+ grn_id last_rid;
+
+ // stuff for merging
+ grn_ii *ii;
+ uint32_t lseg;
+ uint32_t dseg;
+ buffer *term_buffer;
+ datavec data_vectors[MAX_N_ELEMENTS + 1];
+ uint8_t *packed_buf;
+ size_t packed_buf_size;
+ size_t packed_len;
+ size_t total_chunk_size;
+};
+
+/* block_new returns a new ii_buffer_block to store block information. */
+static ii_buffer_block *
+block_new(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ ii_buffer_block *block;
+ if (!(ii_buffer->nblocks & 0x3ff)) {
+ ii_buffer_block *blocks;
+ if (!(blocks = GRN_REALLOC(ii_buffer->blocks,
+ (ii_buffer->nblocks + 0x400) *
+ sizeof(ii_buffer_block)))) {
+ return NULL;
+ }
+ ii_buffer->blocks = blocks;
+ }
+ block = &ii_buffer->blocks[ii_buffer->nblocks];
+ block->head = ii_buffer->filepos;
+ block->rest = 0;
+ block->buffer = NULL;
+ block->buffersize = 0;
+ return block;
+}
+
+/* allocate_outbuf allocates memory to flush a block. */
+static uint8_t *
+allocate_outbuf(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ size_t bufsize = 0, bufsize_ = 0;
+ uint32_t flags = ii_buffer->ii->header->flags;
+ ii_buffer_counter *counter = ii_buffer->counters;
+ grn_id tid, tid_max = grn_table_size(ctx, ii_buffer->tmp_lexicon);
+ for (tid = 1; tid <= tid_max; counter++, tid++) {
+ counter->offset_tf += GRN_B_ENC_SIZE(counter->last_tf - 1);
+ counter->last_rid = 0;
+ counter->last_tf = 0;
+ bufsize += 5;
+ bufsize += GRN_B_ENC_SIZE(counter->nrecs);
+ bufsize += GRN_B_ENC_SIZE(counter->nposts);
+ bufsize += counter->offset_rid;
+ if ((flags & GRN_OBJ_WITH_SECTION)) {
+ bufsize += counter->offset_sid;
+ }
+ bufsize += counter->offset_tf;
+ if ((flags & GRN_OBJ_WITH_WEIGHT)) {
+ bufsize += counter->offset_weight;
+ }
+ if ((flags & GRN_OBJ_WITH_POSITION)) {
+ bufsize += counter->offset_pos;
+ }
+ if (bufsize_ + II_BUFFER_BLOCK_READ_UNIT_SIZE < bufsize) {
+ bufsize += sizeof(uint32_t);
+ bufsize_ = bufsize;
+ }
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO, "flushing:%d bufsize:%" GRN_FMT_SIZE,
+ ii_buffer->nblocks, bufsize);
+ return (uint8_t *)GRN_MALLOC(bufsize);
+}
+
+/*
+ * The temporary file format is roughly as follows:
+ *
+ * File = Block...
+ * Block = Unit...
+ * Unit = TermChunk (key order)
+ * NextUnitSize (The first unit size is kept on memory)
+ * Chunk = Term...
+ * Term = ID (gtid)
+ * NumRecordsOrSections (nrecs), NumOccurrences (nposts)
+ * RecordID... (rid, diff)
+ * [SectionID... (sid, diff)]
+ * TermFrequency... (tf, diff)
+ * [Weight... (weight, diff)]
+ * [Position... (pos, diff)]
+ */
+
+/*
+ * encode_terms encodes terms in ii_buffer->tmp_lexicon and returns the
+ * expected temporary file size.
+ */
+static size_t
+encode_terms(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ uint8_t *outbuf, ii_buffer_block *block)
+{
+ grn_id tid;
+ uint8_t *outbufp = outbuf;
+ uint8_t *outbufp_ = outbuf;
+ grn_table_cursor *tc;
+ /* The first size is written into block->nextsize. */
+ uint8_t *pnext = (uint8_t *)&block->nextsize;
+ uint32_t flags = ii_buffer->ii->header->flags;
+ tc = grn_table_cursor_open(ctx, ii_buffer->tmp_lexicon,
+ NULL, 0, NULL, 0, 0, -1, II_BUFFER_ORDER);
+ while ((tid = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_size = grn_table_get_key(ctx, ii_buffer->tmp_lexicon, tid,
+ key, GRN_TABLE_MAX_KEY_SIZE);
+ /* gtid is a global term ID, not in a temporary lexicon. */
+ grn_id gtid = grn_table_add(ctx, ii_buffer->lexicon, key, key_size, NULL);
+ ii_buffer_counter *counter = &ii_buffer->counters[tid - 1];
+ if (counter->nrecs) {
+ uint32_t offset_rid = counter->offset_rid;
+ uint32_t offset_sid = counter->offset_sid;
+ uint32_t offset_tf = counter->offset_tf;
+ uint32_t offset_weight = counter->offset_weight;
+ uint32_t offset_pos = counter->offset_pos;
+ GRN_B_ENC(gtid, outbufp);
+ GRN_B_ENC(counter->nrecs, outbufp);
+ GRN_B_ENC(counter->nposts, outbufp);
+ ii_buffer->total_size += counter->nrecs + counter->nposts;
+ counter->offset_rid = outbufp - outbuf;
+ outbufp += offset_rid;
+ if ((flags & GRN_OBJ_WITH_SECTION)) {
+ counter->offset_sid = outbufp - outbuf;
+ outbufp += offset_sid;
+ }
+ counter->offset_tf = outbufp - outbuf;
+ outbufp += offset_tf;
+ if ((flags & GRN_OBJ_WITH_WEIGHT)) {
+ counter->offset_weight = outbufp - outbuf;
+ outbufp += offset_weight;
+ }
+ if ((flags & GRN_OBJ_WITH_POSITION)) {
+ counter->offset_pos = outbufp - outbuf;
+ outbufp += offset_pos;
+ }
+ }
+ if (outbufp_ + II_BUFFER_BLOCK_READ_UNIT_SIZE < outbufp) {
+ uint32_t size = outbufp - outbufp_ + sizeof(uint32_t);
+ grn_memcpy(pnext, &size, sizeof(uint32_t));
+ pnext = outbufp;
+ outbufp += sizeof(uint32_t);
+ outbufp_ = outbufp;
+ }
+ }
+ grn_table_cursor_close(ctx, tc);
+ if (outbufp_ < outbufp) {
+ uint32_t size = outbufp - outbufp_;
+ grn_memcpy(pnext, &size, sizeof(uint32_t));
+ }
+ return outbufp - outbuf;
+}
+
+/* encode_postings encodes data in ii_buffer->block_buf. */
+static void
+encode_postings(grn_ctx *ctx, grn_ii_buffer *ii_buffer, uint8_t *outbuf)
+{
+ grn_id rid = 0;
+ unsigned int sid = 1;
+ unsigned int weight = 0;
+ uint32_t pos = 0;
+ uint32_t rest;
+ grn_id *bp = ii_buffer->block_buf;
+ uint32_t flags = ii_buffer->ii->header->flags;
+ for (rest = ii_buffer->block_pos; rest; bp++, rest--) {
+ grn_id id = *bp;
+ switch (II_BUFFER_TYPE(id)) {
+ case II_BUFFER_TYPE_RID :
+ rid = II_BUFFER_UNPACK(id, II_BUFFER_TYPE_RID);
+ if ((flags & GRN_OBJ_WITH_SECTION) && rest) {
+ sid = *++bp;
+ rest--;
+ }
+ weight = 0;
+ pos = 0;
+ break;
+ case II_BUFFER_TYPE_WEIGHT :
+ weight = II_BUFFER_UNPACK(id, II_BUFFER_TYPE_WEIGHT);
+ break;
+ default :
+ {
+ ii_buffer_counter *counter = &ii_buffer->counters[id - 1];
+ if (counter->last_rid == rid && counter->last_sid == sid) {
+ counter->last_tf++;
+ counter->last_weight += weight;
+ } else {
+ if (counter->last_tf) {
+ uint8_t *p = outbuf + counter->offset_tf;
+ GRN_B_ENC(counter->last_tf - 1, p);
+ counter->offset_tf = p - outbuf;
+ if (flags & GRN_OBJ_WITH_WEIGHT) {
+ p = outbuf + counter->offset_weight;
+ GRN_B_ENC(counter->last_weight, p);
+ counter->offset_weight = p - outbuf;
+ }
+ }
+ {
+ uint8_t *p = outbuf + counter->offset_rid;
+ GRN_B_ENC(rid - counter->last_rid, p);
+ counter->offset_rid = p - outbuf;
+ }
+ if (flags & GRN_OBJ_WITH_SECTION) {
+ uint8_t *p = outbuf + counter->offset_sid;
+ if (counter->last_rid != rid) {
+ GRN_B_ENC(sid - 1, p);
+ } else {
+ GRN_B_ENC(sid - counter->last_sid - 1, p);
+ }
+ counter->offset_sid = p - outbuf;
+ }
+ counter->last_rid = rid;
+ counter->last_sid = sid;
+ counter->last_tf = 1;
+ counter->last_weight = weight;
+ counter->last_pos = 0;
+ }
+ if ((flags & GRN_OBJ_WITH_POSITION) && rest) {
+ uint8_t *p = outbuf + counter->offset_pos;
+ pos = *++bp;
+ rest--;
+ GRN_B_ENC(pos - counter->last_pos, p);
+ counter->offset_pos = p - outbuf;
+ counter->last_pos = pos;
+ }
+ }
+ break;
+ }
+ }
+}
+
+/* encode_last_tf encodes last_tf and last_weight in counters. */
+static void
+encode_last_tf(grn_ctx *ctx, grn_ii_buffer *ii_buffer, uint8_t *outbuf)
+{
+ ii_buffer_counter *counter = ii_buffer->counters;
+ grn_id tid, tid_max = grn_table_size(ctx, ii_buffer->tmp_lexicon);
+ for (tid = 1; tid <= tid_max; counter++, tid++) {
+ uint8_t *p = outbuf + counter->offset_tf;
+ GRN_B_ENC(counter->last_tf - 1, p);
+ }
+ if ((ii_buffer->ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ for (tid = 1; tid <= tid_max; counter++, tid++) {
+ uint8_t *p = outbuf + counter->offset_weight;
+ GRN_B_ENC(counter->last_weight, p);
+ }
+ }
+}
+
+/*
+ * grn_ii_buffer_flush flushes the current block (ii_buffer->block_buf,
+ * counters and tmp_lexicon) to a temporary file (ii_buffer->tmpfd).
+ * Also, block information is stored into ii_buffer->blocks.
+ */
+static void
+grn_ii_buffer_flush(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ size_t encsize;
+ uint8_t *outbuf;
+ ii_buffer_block *block;
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "flushing:%d npostings:%" GRN_FMT_SIZE,
+ ii_buffer->nblocks, ii_buffer->block_pos);
+ if (!(block = block_new(ctx, ii_buffer))) { return; }
+ if (!(outbuf = allocate_outbuf(ctx, ii_buffer))) { return; }
+ encsize = encode_terms(ctx, ii_buffer, outbuf, block);
+ encode_postings(ctx, ii_buffer, outbuf);
+ encode_last_tf(ctx, ii_buffer, outbuf);
+ {
+ ssize_t r = grn_write(ii_buffer->tmpfd, outbuf, encsize);
+ if (r != (ssize_t) encsize) {
+ ERR(GRN_INPUT_OUTPUT_ERROR,
+ "write returned %" GRN_FMT_LLD " != %" GRN_FMT_LLU,
+ (long long int)r, (unsigned long long int)encsize);
+ GRN_FREE(outbuf);
+ return;
+ }
+ ii_buffer->filepos += r;
+ block->tail = ii_buffer->filepos;
+ }
+ GRN_FREE(outbuf);
+ memset(ii_buffer->counters, 0,
+ grn_table_size(ctx, ii_buffer->tmp_lexicon) *
+ sizeof(ii_buffer_counter));
+ grn_obj_close(ctx, ii_buffer->tmp_lexicon);
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "flushed: %d encsize:%" GRN_FMT_SIZE,
+ ii_buffer->nblocks, encsize);
+ ii_buffer->tmp_lexicon = NULL;
+ ii_buffer->nblocks++;
+ ii_buffer->block_pos = 0;
+}
+
+const uint32_t PAT_CACHE_SIZE = 1<<20;
+
+/*
+ * get_tmp_lexicon returns a temporary lexicon.
+ *
+ * Note that a lexicon is created for each block and ii_buffer->tmp_lexicon is
+ * closed in grn_ii_buffer_flush.
+ */
+static grn_obj *
+get_tmp_lexicon(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ grn_obj *tmp_lexicon = ii_buffer->tmp_lexicon;
+ if (!tmp_lexicon) {
+ grn_obj *domain = grn_ctx_at(ctx, ii_buffer->lexicon->header.domain);
+ grn_obj *range = grn_ctx_at(ctx, DB_OBJ(ii_buffer->lexicon)->range);
+ grn_obj *tokenizer;
+ grn_obj *normalizer;
+ grn_obj *token_filters;
+ grn_table_flags flags;
+ grn_table_get_info(ctx, ii_buffer->lexicon, &flags, NULL,
+ &tokenizer, &normalizer, &token_filters);
+ flags &= ~GRN_OBJ_PERSISTENT;
+ tmp_lexicon = grn_table_create(ctx, NULL, 0, NULL, flags, domain, range);
+ if (tmp_lexicon) {
+ ii_buffer->tmp_lexicon = tmp_lexicon;
+ grn_obj_set_info(ctx, tmp_lexicon,
+ GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
+ grn_obj_set_info(ctx, tmp_lexicon,
+ GRN_INFO_NORMALIZER, normalizer);
+ grn_obj_set_info(ctx, tmp_lexicon,
+ GRN_INFO_TOKEN_FILTERS, token_filters);
+ if ((flags & GRN_OBJ_TABLE_TYPE_MASK) == GRN_OBJ_TABLE_PAT_KEY) {
+ grn_pat_cache_enable(ctx, (grn_pat *)tmp_lexicon, PAT_CACHE_SIZE);
+ }
+ }
+ }
+ return tmp_lexicon;
+}
+
+/* get_buffer_counter returns a counter associated with tid. */
+static ii_buffer_counter *
+get_buffer_counter(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ grn_obj *tmp_lexicon, grn_id tid)
+{
+ if (tid > ii_buffer->ncounters) {
+ ii_buffer_counter *counters;
+ uint32_t ncounters =
+ grn_table_size(ctx, tmp_lexicon) + II_BUFFER_NCOUNTERS_MARGIN;
+ counters = GRN_REALLOC(ii_buffer->counters,
+ ncounters * sizeof(ii_buffer_counter));
+ if (!counters) { return NULL; }
+ memset(&counters[ii_buffer->ncounters], 0,
+ (ncounters - ii_buffer->ncounters) * sizeof(ii_buffer_counter));
+ ii_buffer->ncounters = ncounters;
+ ii_buffer->counters = counters;
+ }
+ return &ii_buffer->counters[tid - 1];
+}
+
+/*
+ * grn_ii_buffer_tokenize_value tokenizes a value.
+ *
+ * The result is written into the current block (ii_buffer->tmp_lexicon,
+ * ii_buffer->block_buf, ii_buffer->counters, etc.).
+ */
+static void
+grn_ii_buffer_tokenize_value(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ grn_id rid, const ii_buffer_value *value)
+{
+ grn_obj *tmp_lexicon;
+ if ((tmp_lexicon = get_tmp_lexicon(ctx, ii_buffer))) {
+ unsigned int token_flags = 0;
+ grn_token_cursor *token_cursor;
+ grn_id *buffer = ii_buffer->block_buf;
+ uint32_t block_pos = ii_buffer->block_pos;
+ uint32_t ii_flags = ii_buffer->ii->header->flags;
+ buffer[block_pos++] = II_BUFFER_PACK(rid, II_BUFFER_TYPE_RID);
+ if (ii_flags & GRN_OBJ_WITH_SECTION) {
+ buffer[block_pos++] = value->sid;
+ }
+ if (value->weight) {
+ buffer[block_pos++] = II_BUFFER_PACK(value->weight,
+ II_BUFFER_TYPE_WEIGHT);
+ }
+ if ((token_cursor = grn_token_cursor_open(ctx, tmp_lexicon,
+ value->p, value->len,
+ GRN_TOKEN_ADD, token_flags))) {
+ while (!token_cursor->status) {
+ grn_id tid;
+ if ((tid = grn_token_cursor_next(ctx, token_cursor))) {
+ ii_buffer_counter *counter;
+ counter = get_buffer_counter(ctx, ii_buffer, tmp_lexicon, tid);
+ if (!counter) { return; }
+ buffer[block_pos++] = tid;
+ if (ii_flags & GRN_OBJ_WITH_POSITION) {
+ buffer[block_pos++] = token_cursor->pos;
+ }
+ if (counter->last_rid != rid) {
+ counter->offset_rid += GRN_B_ENC_SIZE(rid - counter->last_rid);
+ counter->last_rid = rid;
+ counter->offset_sid += GRN_B_ENC_SIZE(value->sid - 1);
+ counter->last_sid = value->sid;
+ if (counter->last_tf) {
+ counter->offset_tf += GRN_B_ENC_SIZE(counter->last_tf - 1);
+ counter->last_tf = 0;
+ counter->offset_weight += GRN_B_ENC_SIZE(counter->last_weight);
+ counter->last_weight = 0;
+ }
+ counter->last_pos = 0;
+ counter->nrecs++;
+ } else if (counter->last_sid != value->sid) {
+ counter->offset_rid += GRN_B_ENC_SIZE(0);
+ counter->offset_sid +=
+ GRN_B_ENC_SIZE(value->sid - counter->last_sid - 1);
+ counter->last_sid = value->sid;
+ if (counter->last_tf) {
+ counter->offset_tf += GRN_B_ENC_SIZE(counter->last_tf - 1);
+ counter->last_tf = 0;
+ counter->offset_weight += GRN_B_ENC_SIZE(counter->last_weight);
+ counter->last_weight = 0;
+ }
+ counter->last_pos = 0;
+ counter->nrecs++;
+ }
+ counter->offset_pos +=
+ GRN_B_ENC_SIZE(token_cursor->pos - counter->last_pos);
+ counter->last_pos = token_cursor->pos;
+ counter->last_tf++;
+ counter->last_weight += value->weight;
+ counter->nposts++;
+ }
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+ ii_buffer->block_pos = block_pos;
+ }
+}
+
+/*
+ * grn_ii_buffer_tokenize tokenizes ii_buffer->values.
+ *
+ * grn_ii_buffer_tokenize estimates the size of tokenized values.
+ * If the remaining space of the current block is not enough to store the new
+ * tokenized values, the current block is flushed.
+ * Then, grn_ii_buffer_tokenize tokenizes values.
+ */
+static void
+grn_ii_buffer_tokenize(grn_ctx *ctx, grn_ii_buffer *ii_buffer, grn_id rid)
+{
+ unsigned int i;
+ uint32_t est_len = 0;
+ for (i = 0; i < ii_buffer->nvalues; i++) {
+ est_len += ii_buffer->values[i].len * 2 + 2;
+ }
+ if (ii_buffer->block_buf_size < ii_buffer->block_pos + est_len) {
+ grn_ii_buffer_flush(ctx, ii_buffer);
+ }
+ if (ii_buffer->block_buf_size < est_len) {
+ grn_id *block_buf = (grn_id *)GRN_REALLOC(ii_buffer->block_buf,
+ est_len * sizeof(grn_id));
+ if (block_buf) {
+ ii_buffer->block_buf = block_buf;
+ ii_buffer->block_buf_size = est_len;
+ }
+ }
+
+ for (i = 0; i < ii_buffer->nvalues; i++) {
+ const ii_buffer_value *value = &ii_buffer->values[i];
+ if (value->len) {
+ uint32_t est_len = value->len * 2 + 2;
+ if (ii_buffer->block_buf_size >= ii_buffer->block_pos + est_len) {
+ grn_ii_buffer_tokenize_value(ctx, ii_buffer, rid, value);
+ }
+ }
+ }
+ ii_buffer->nvalues = 0;
+}
+
+/* grn_ii_buffer_fetch fetches the next term. */
+static void
+grn_ii_buffer_fetch(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ ii_buffer_block *block)
+{
+ if (!block->rest) {
+ /* Read the next unit. */
+ if (block->head < block->tail) {
+ size_t bytesize = block->nextsize;
+ if (block->buffersize < block->nextsize) {
+ void *r = GRN_REALLOC(block->buffer, bytesize);
+ if (r) {
+ block->buffer = (uint8_t *)r;
+ block->buffersize = block->nextsize;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "realloc: %" GRN_FMT_LLU,
+ (unsigned long long int)bytesize);
+ return;
+ }
+ }
+ {
+ off64_t seeked_position;
+ seeked_position = grn_lseek(ii_buffer->tmpfd, block->head, SEEK_SET);
+ if (seeked_position != block->head) {
+ ERRNO_ERR("failed to "
+ "grn_lseek(%" GRN_FMT_OFF64_T ") -> %" GRN_FMT_OFF64_T,
+ block->head,
+ seeked_position);
+ return;
+ }
+ }
+ {
+ size_t read_bytesize;
+ read_bytesize = grn_read(ii_buffer->tmpfd, block->buffer, bytesize);
+ if (read_bytesize != bytesize) {
+ SERR("failed to grn_read(%" GRN_FMT_SIZE ") -> %" GRN_FMT_SIZE,
+ bytesize, read_bytesize);
+ return;
+ }
+ }
+ block->head += bytesize;
+ block->bufcur = block->buffer;
+ if (block->head >= block->tail) {
+ if (block->head > block->tail) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "fetch error: %" GRN_FMT_INT64D " > %" GRN_FMT_INT64D,
+ block->head, block->tail);
+ }
+ block->rest = block->nextsize;
+ block->nextsize = 0;
+ } else {
+ block->rest = block->nextsize - sizeof(uint32_t);
+ grn_memcpy(&block->nextsize,
+ &block->buffer[block->rest], sizeof(uint32_t));
+ }
+ }
+ }
+ if (block->rest) {
+ uint8_t *p = block->bufcur;
+ GRN_B_DEC(block->tid, p);
+ GRN_B_DEC(block->nrecs, p);
+ GRN_B_DEC(block->nposts, p);
+ block->rest -= (p - block->bufcur);
+ block->bufcur = p;
+ } else {
+ block->tid = 0;
+ }
+}
+
+/* grn_ii_buffer_chunk_flush flushes the current buffer for packed postings. */
+static void
+grn_ii_buffer_chunk_flush(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ grn_io_win io_win;
+ uint32_t chunk_number;
+ chunk_new(ctx, ii_buffer->ii, &chunk_number, ii_buffer->packed_len);
+ GRN_LOG(ctx, GRN_LOG_INFO, "chunk:%d, packed_len:%" GRN_FMT_SIZE,
+ chunk_number, ii_buffer->packed_len);
+ fake_map(ctx, ii_buffer->ii->chunk, &io_win, ii_buffer->packed_buf,
+ chunk_number, ii_buffer->packed_len);
+ grn_io_win_unmap(&io_win);
+ ii_buffer->term_buffer->header.chunk = chunk_number;
+ ii_buffer->term_buffer->header.chunk_size = ii_buffer->packed_len;
+ ii_buffer->term_buffer->header.buffer_free =
+ S_SEGMENT - sizeof(buffer_header) -
+ ii_buffer->term_buffer->header.nterms * sizeof(buffer_term);
+ ii_buffer->term_buffer->header.nterms_void = 0;
+ buffer_segment_update(ii_buffer->ii, ii_buffer->lseg, ii_buffer->dseg);
+ ii_buffer->ii->header->total_chunk_size += ii_buffer->packed_len;
+ ii_buffer->total_chunk_size += ii_buffer->packed_len;
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "nterms=%d chunk=%d total=%" GRN_FMT_INT64U "KB",
+ ii_buffer->term_buffer->header.nterms,
+ ii_buffer->term_buffer->header.chunk_size,
+ ii_buffer->ii->header->total_chunk_size >> 10);
+ ii_buffer->term_buffer = NULL;
+ ii_buffer->packed_buf = NULL;
+ ii_buffer->packed_len = 0;
+ ii_buffer->packed_buf_size = 0;
+ ii_buffer->curr_size = 0;
+}
+
+/*
+ * merge_hit_blocks merges hit blocks into ii_buffer->data_vectors.
+ * merge_hit_blocks returns the estimated maximum size in bytes.
+ */
+static size_t
+merge_hit_blocks(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ ii_buffer_block *hits[], int nhits)
+{
+ uint64_t nrecs = 0;
+ uint64_t nposts = 0;
+ size_t max_size;
+ uint64_t flags = ii_buffer->ii->header->flags;
+ int i;
+ for (i = 0; i < nhits; i++) {
+ ii_buffer_block *block = hits[i];
+ nrecs += block->nrecs;
+ nposts += block->nposts;
+ }
+ ii_buffer->curr_size += nrecs + nposts;
+ max_size = nrecs * (ii_buffer->ii->n_elements);
+ if (flags & GRN_OBJ_WITH_POSITION) { max_size += nposts - nrecs; }
+ datavec_reset(ctx, ii_buffer->data_vectors,
+ ii_buffer->ii->n_elements, nrecs, max_size);
+ {
+ int i;
+ uint32_t lr = 0; /* Last rid */
+ uint64_t spos = 0;
+ uint32_t *ridp, *sidp = NULL, *tfp, *weightp = NULL, *posp = NULL;
+ {
+ /* Get write positions in datavec. */
+ int j = 0;
+ ridp = ii_buffer->data_vectors[j++].data;
+ if (flags & GRN_OBJ_WITH_SECTION) {
+ sidp = ii_buffer->data_vectors[j++].data;
+ }
+ tfp = ii_buffer->data_vectors[j++].data;
+ if (flags & GRN_OBJ_WITH_WEIGHT) {
+ weightp = ii_buffer->data_vectors[j++].data;
+ }
+ if (flags & GRN_OBJ_WITH_POSITION) {
+ posp = ii_buffer->data_vectors[j++].data;
+ }
+ }
+ for (i = 0; i < nhits; i++) {
+ /* Read postings from hit blocks and join the postings into datavec. */
+ ii_buffer_block *block = hits[i];
+ uint8_t *p = block->bufcur;
+ uint32_t n = block->nrecs;
+ if (n) {
+ GRN_B_DEC(*ridp, p);
+ *ridp -= lr;
+ lr += *ridp++;
+ while (--n) {
+ GRN_B_DEC(*ridp, p);
+ lr += *ridp++;
+ }
+ }
+ if ((flags & GRN_OBJ_WITH_SECTION)) {
+ for (n = block->nrecs; n; n--) {
+ GRN_B_DEC(*sidp++, p);
+ }
+ }
+ for (n = block->nrecs; n; n--) {
+ GRN_B_DEC(*tfp++, p);
+ }
+ if ((flags & GRN_OBJ_WITH_WEIGHT)) {
+ for (n = block->nrecs; n; n--) {
+ GRN_B_DEC(*weightp++, p);
+ }
+ }
+ if ((flags & GRN_OBJ_WITH_POSITION)) {
+ for (n = block->nposts; n; n--) {
+ GRN_B_DEC(*posp, p);
+ spos += *posp++;
+ }
+ }
+ block->rest -= (p - block->bufcur);
+ block->bufcur = p;
+ grn_ii_buffer_fetch(ctx, ii_buffer, block);
+ }
+ {
+ /* Set size and flags of datavec. */
+ int j = 0;
+ uint32_t f_s = (nrecs < 3) ? 0 : USE_P_ENC;
+ uint32_t f_d = ((nrecs < 16) || (nrecs <= (lr >> 8))) ? 0 : USE_P_ENC;
+ ii_buffer->data_vectors[j].data_size = nrecs;
+ ii_buffer->data_vectors[j++].flags = f_d;
+ if ((flags & GRN_OBJ_WITH_SECTION)) {
+ ii_buffer->data_vectors[j].data_size = nrecs;
+ ii_buffer->data_vectors[j++].flags = f_s;
+ }
+ ii_buffer->data_vectors[j].data_size = nrecs;
+ ii_buffer->data_vectors[j++].flags = f_s;
+ if ((flags & GRN_OBJ_WITH_WEIGHT)) {
+ ii_buffer->data_vectors[j].data_size = nrecs;
+ ii_buffer->data_vectors[j++].flags = f_s;
+ }
+ if ((flags & GRN_OBJ_WITH_POSITION)) {
+ uint32_t f_p = (((nposts < 32) ||
+ (nposts <= (spos >> 13))) ? 0 : USE_P_ENC);
+ ii_buffer->data_vectors[j].data_size = nposts;
+ ii_buffer->data_vectors[j++].flags = f_p|ODD;
+ }
+ }
+ }
+ return (max_size + ii_buffer->ii->n_elements) * 4;
+}
+
+static buffer *
+get_term_buffer(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ if (!ii_buffer->term_buffer) {
+ uint32_t lseg;
+ void *term_buffer;
+ for (lseg = 0; lseg < GRN_II_MAX_LSEG; lseg++) {
+ if (ii_buffer->ii->header->binfo[lseg] == GRN_II_PSEG_NOT_ASSIGNED) { break; }
+ }
+ if (lseg == GRN_II_MAX_LSEG) {
+ DEFINE_NAME(ii_buffer->ii);
+ MERR("[ii][buffer][term-buffer] couldn't find a free buffer: "
+ "<%.*s>",
+ name_size, name);
+ return NULL;
+ }
+ ii_buffer->lseg = lseg;
+ ii_buffer->dseg = segment_get(ctx, ii_buffer->ii);
+ GRN_IO_SEG_REF(ii_buffer->ii->seg, ii_buffer->dseg, term_buffer);
+ ii_buffer->term_buffer = (buffer *)term_buffer;
+ }
+ return ii_buffer->term_buffer;
+}
+
+/*
+ * try_in_place_packing tries to pack a posting in an array element.
+ *
+ * The requirements are as follows:
+ * - nposts == 1
+ * - nhits == 1 && nrecs == 1 && tf == 0
+ * - weight == 0
+ * - !(flags & GRN_OBJ_WITH_SECTION) || (rid < 0x100000 && sid < 0x800)
+ */
+static grn_bool
+try_in_place_packing(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ grn_id tid, ii_buffer_block *hits[], int nhits)
+{
+ if (nhits == 1 && hits[0]->nrecs == 1 && hits[0]->nposts == 1) {
+ grn_id rid;
+ uint32_t sid = 1, tf, pos = 0, weight = 0;
+ ii_buffer_block *block = hits[0];
+ uint8_t *p = block->bufcur;
+ uint32_t flags = ii_buffer->ii->header->flags;
+ GRN_B_DEC(rid, p);
+ if (flags & GRN_OBJ_WITH_SECTION) {
+ GRN_B_DEC(sid, p);
+ sid++;
+ }
+ GRN_B_DEC(tf, p);
+ if (tf != 0) { GRN_LOG(ctx, GRN_LOG_WARNING, "tf=%d", tf); }
+ if (flags & GRN_OBJ_WITH_WEIGHT) { GRN_B_DEC(weight, p); }
+ if (flags & GRN_OBJ_WITH_POSITION) { GRN_B_DEC(pos, p); }
+ if (!weight) {
+ if (flags & GRN_OBJ_WITH_SECTION) {
+ if (rid < 0x100000 && sid < 0x800) {
+ uint32_t *a = array_get(ctx, ii_buffer->ii, tid);
+ a[0] = (rid << 12) + (sid << 1) + 1;
+ a[1] = pos;
+ array_unref(ii_buffer->ii, tid);
+ } else {
+ return GRN_FALSE;
+ }
+ } else {
+ uint32_t *a = array_get(ctx, ii_buffer->ii, tid);
+ a[0] = (rid << 1) + 1;
+ a[1] = pos;
+ array_unref(ii_buffer->ii, tid);
+ }
+ block->rest -= (p - block->bufcur);
+ block->bufcur = p;
+ grn_ii_buffer_fetch(ctx, ii_buffer, block);
+ return GRN_TRUE;
+ }
+ }
+ return GRN_FALSE;
+}
+
+/* grn_ii_buffer_merge merges hit blocks and pack it. */
+static void
+grn_ii_buffer_merge(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ grn_id tid, ii_buffer_block *hits[], int nhits)
+{
+ if (!try_in_place_packing(ctx, ii_buffer, tid, hits, nhits)) {
+ /* Merge hit blocks and reserve a buffer for packed data. */
+ size_t max_size = merge_hit_blocks(ctx, ii_buffer, hits, nhits);
+ if (ii_buffer->packed_buf &&
+ ii_buffer->packed_buf_size < ii_buffer->packed_len + max_size) {
+ grn_ii_buffer_chunk_flush(ctx, ii_buffer);
+ }
+ if (!ii_buffer->packed_buf) {
+ size_t buf_size = (max_size > II_BUFFER_PACKED_BUF_SIZE)
+ ? max_size : II_BUFFER_PACKED_BUF_SIZE;
+ if ((ii_buffer->packed_buf = GRN_MALLOC(buf_size))) {
+ ii_buffer->packed_buf_size = buf_size;
+ }
+ }
+ {
+ /* Pack postings into the current buffer. */
+ uint16_t nterm;
+ size_t packed_len;
+ buffer_term *bt;
+ uint32_t *a;
+ buffer *term_buffer;
+
+ a = array_get(ctx, ii_buffer->ii, tid);
+ if (!a) {
+ DEFINE_NAME(ii_buffer->ii);
+ MERR("[ii][buffer][merge] failed to allocate an array: "
+ "<%.*s>: "
+ "<%u>",
+ name_size, name,
+ tid);
+ return;
+ }
+ term_buffer = get_term_buffer(ctx, ii_buffer);
+ if (!term_buffer) {
+ DEFINE_NAME(ii_buffer->ii);
+ MERR("[ii][buffer][merge] failed to allocate a term buffer: "
+ "<%.*s>: "
+ "<%u>",
+ name_size, name,
+ tid);
+ return;
+ }
+ nterm = term_buffer->header.nterms++;
+ bt = &term_buffer->terms[nterm];
+ a[0] = SEG2POS(ii_buffer->lseg,
+ (sizeof(buffer_header) + sizeof(buffer_term) * nterm));
+ packed_len = grn_p_encv(ctx, ii_buffer->data_vectors,
+ ii_buffer->ii->n_elements,
+ ii_buffer->packed_buf +
+ ii_buffer->packed_len);
+ a[1] = ii_buffer->data_vectors[0].data_size;
+ bt->tid = tid;
+ bt->size_in_buffer = 0;
+ bt->pos_in_buffer = 0;
+ bt->size_in_chunk = packed_len;
+ bt->pos_in_chunk = ii_buffer->packed_len;
+ ii_buffer->packed_len += packed_len;
+ if (((ii_buffer->curr_size * ii_buffer->update_buffer_size) +
+ (ii_buffer->total_size * term_buffer->header.nterms * 16)) >=
+ (ii_buffer->total_size * II_BUFFER_NTERMS_PER_BUFFER * 16)) {
+ grn_ii_buffer_chunk_flush(ctx, ii_buffer);
+ }
+ array_unref(ii_buffer->ii, tid);
+ }
+ }
+}
+
+grn_ii_buffer *
+grn_ii_buffer_open(grn_ctx *ctx, grn_ii *ii,
+ long long unsigned int update_buffer_size)
+{
+ if (ii && ii->lexicon) {
+ grn_ii_buffer *ii_buffer = GRN_MALLOCN(grn_ii_buffer, 1);
+ if (ii_buffer) {
+ ii_buffer->ii = ii;
+ ii_buffer->lexicon = ii->lexicon;
+ ii_buffer->tmp_lexicon = NULL;
+ ii_buffer->nblocks = 0;
+ ii_buffer->blocks = NULL;
+ ii_buffer->ncounters = II_BUFFER_NCOUNTERS_MARGIN;
+ ii_buffer->block_pos = 0;
+ ii_buffer->filepos = 0;
+ ii_buffer->curr_size = 0;
+ ii_buffer->total_size = 0;
+ ii_buffer->update_buffer_size = update_buffer_size;
+ ii_buffer->counters = GRN_CALLOC(ii_buffer->ncounters *
+ sizeof(ii_buffer_counter));
+ ii_buffer->term_buffer = NULL;
+ ii_buffer->packed_buf = NULL;
+ ii_buffer->packed_len = 0;
+ ii_buffer->packed_buf_size = 0;
+ ii_buffer->total_chunk_size = 0;
+ ii_buffer->values = NULL;
+ ii_buffer->nvalues = 0;
+ ii_buffer->max_nvalues = 0;
+ ii_buffer->last_rid = 0;
+ if (ii_buffer->counters) {
+ ii_buffer->block_buf = GRN_MALLOCN(grn_id, II_BUFFER_BLOCK_SIZE);
+ if (ii_buffer->block_buf) {
+ grn_snprintf(ii_buffer->tmpfpath, PATH_MAX, PATH_MAX,
+ "%-.256sXXXXXX", grn_io_path(ii->seg));
+ ii_buffer->block_buf_size = II_BUFFER_BLOCK_SIZE;
+ ii_buffer->tmpfd = grn_mkstemp(ii_buffer->tmpfpath);
+ if (ii_buffer->tmpfd != -1) {
+ grn_table_flags flags;
+ grn_table_get_info(ctx, ii->lexicon, &flags, NULL, NULL, NULL,
+ NULL);
+ if ((flags & GRN_OBJ_TABLE_TYPE_MASK) == GRN_OBJ_TABLE_PAT_KEY) {
+ grn_pat_cache_enable(ctx, (grn_pat *)ii->lexicon,
+ PAT_CACHE_SIZE);
+ }
+ return ii_buffer;
+ } else {
+ SERR("failed grn_mkstemp(%-.256s)",
+ ii_buffer->tmpfpath);
+ }
+ GRN_FREE(ii_buffer->block_buf);
+ }
+ GRN_FREE(ii_buffer->counters);
+ }
+ GRN_FREE(ii_buffer);
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "ii or ii->lexicon is NULL");
+ }
+ return NULL;
+}
+
+static void
+ii_buffer_value_init(grn_ctx *ctx, ii_buffer_value *value)
+{
+ value->sid = 0;
+ value->weight = 0;
+ value->p = NULL;
+ value->len = 0;
+ value->buf = NULL;
+ value->cap = 0;
+}
+
+static void
+ii_buffer_value_fin(grn_ctx *ctx, ii_buffer_value *value)
+{
+ if (value->buf) {
+ GRN_FREE(value->buf);
+ }
+}
+
+/*
+ * ii_buffer_values_append appends a value to ii_buffer.
+ * This function deep-copies the value if need_copy == GRN_TRUE.
+ */
+static void
+ii_buffer_values_append(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ unsigned int sid, unsigned weight,
+ const char *p, uint32_t len, grn_bool need_copy)
+{
+ if (ii_buffer->nvalues == ii_buffer->max_nvalues) {
+ unsigned int i;
+ unsigned int new_max_nvalues = ii_buffer->max_nvalues * 2;
+ unsigned int new_size;
+ ii_buffer_value *new_values;
+ if (new_max_nvalues == 0) {
+ new_max_nvalues = 1;
+ }
+ new_size = new_max_nvalues * sizeof(ii_buffer_value);
+ new_values = (ii_buffer_value *)GRN_REALLOC(ii_buffer->values, new_size);
+ if (!new_values) {
+ return;
+ }
+ for (i = ii_buffer->max_nvalues; i < new_max_nvalues; i++) {
+ ii_buffer_value_init(ctx, &new_values[i]);
+ }
+ ii_buffer->values = new_values;
+ ii_buffer->max_nvalues = new_max_nvalues;
+ }
+
+ {
+ ii_buffer_value *value = &ii_buffer->values[ii_buffer->nvalues];
+ if (need_copy) {
+ if (len > value->cap) {
+ char *new_buf = (char *)GRN_REALLOC(value->buf, len);
+ if (!new_buf) {
+ return;
+ }
+ value->buf = new_buf;
+ value->cap = len;
+ }
+ grn_memcpy(value->buf, p, len);
+ p = value->buf;
+ }
+ value->sid = sid;
+ value->weight = weight;
+ value->p = p;
+ value->len = len;
+ ii_buffer->nvalues++;
+ }
+}
+
+grn_rc
+grn_ii_buffer_append(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ grn_id rid, unsigned int sid, grn_obj *value)
+{
+ if (rid != ii_buffer->last_rid) {
+ if (ii_buffer->last_rid) {
+ grn_ii_buffer_tokenize(ctx, ii_buffer, ii_buffer->last_rid);
+ }
+ ii_buffer->last_rid = rid;
+ }
+ ii_buffer_values_append(ctx, ii_buffer, sid, 0,
+ GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value),
+ GRN_TRUE);
+ return ctx->rc;
+}
+
+/*
+ * grn_ii_buffer_commit completes tokenization and builds an inverted index
+ * from data in a temporary file.
+ */
+grn_rc
+grn_ii_buffer_commit(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ /* Tokenize the remaining values and free resources. */
+ if (ii_buffer->last_rid && ii_buffer->nvalues) {
+ grn_ii_buffer_tokenize(ctx, ii_buffer, ii_buffer->last_rid);
+ }
+ if (ii_buffer->block_pos) {
+ grn_ii_buffer_flush(ctx, ii_buffer);
+ }
+ if (ii_buffer->tmpfd != -1) {
+ grn_close(ii_buffer->tmpfd);
+ }
+ if (ii_buffer->block_buf) {
+ GRN_FREE(ii_buffer->block_buf);
+ ii_buffer->block_buf = NULL;
+ }
+ if (ii_buffer->counters) {
+ GRN_FREE(ii_buffer->counters);
+ ii_buffer->counters = NULL;
+ }
+
+ if (ii_buffer->update_buffer_size &&
+ ii_buffer->update_buffer_size < 20) {
+ if (ii_buffer->update_buffer_size < 10) {
+ ii_buffer->update_buffer_size =
+ ii_buffer->total_size >> (10 - ii_buffer->update_buffer_size);
+ } else {
+ ii_buffer->update_buffer_size =
+ ii_buffer->total_size << (ii_buffer->update_buffer_size - 10);
+ }
+ }
+
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "nblocks=%d, update_buffer_size=%" GRN_FMT_INT64U,
+ ii_buffer->nblocks, ii_buffer->update_buffer_size);
+
+ datavec_init(ctx, ii_buffer->data_vectors, ii_buffer->ii->n_elements, 0, 0);
+ grn_open(ii_buffer->tmpfd,
+ ii_buffer->tmpfpath,
+ O_RDONLY | GRN_OPEN_FLAG_BINARY);
+ if (ii_buffer->tmpfd == -1) {
+ ERRNO_ERR("failed to open path: <%-.256s>", ii_buffer->tmpfpath);
+ return ctx->rc;
+ }
+ {
+ /* Fetch the first term of each block. */
+ uint32_t i;
+ for (i = 0; i < ii_buffer->nblocks; i++) {
+ grn_ii_buffer_fetch(ctx, ii_buffer, &ii_buffer->blocks[i]);
+ }
+ }
+ {
+ ii_buffer_block **hits;
+ if ((hits = GRN_MALLOCN(ii_buffer_block *, ii_buffer->nblocks))) {
+ grn_id tid;
+ grn_table_cursor *tc;
+ tc = grn_table_cursor_open(ctx, ii_buffer->lexicon,
+ NULL, 0, NULL, 0, 0, -1, II_BUFFER_ORDER);
+ if (tc) {
+ while ((tid = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ /*
+ * Find blocks which contain the current term.
+ * Then, merge the postings.
+ */
+ int nrests = 0;
+ int nhits = 0;
+ uint32_t i;
+ for (i = 0; i < ii_buffer->nblocks; i++) {
+ if (ii_buffer->blocks[i].tid == tid) {
+ hits[nhits++] = &ii_buffer->blocks[i];
+ }
+ if (ii_buffer->blocks[i].tid) { nrests++; }
+ }
+ if (nhits) { grn_ii_buffer_merge(ctx, ii_buffer, tid, hits, nhits); }
+ if (!nrests) { break; }
+ }
+ if (ii_buffer->packed_len) {
+ grn_ii_buffer_chunk_flush(ctx, ii_buffer);
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_FREE(hits);
+ }
+ }
+ datavec_fin(ctx, ii_buffer->data_vectors);
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "tmpfile_size:%" GRN_FMT_INT64D " > total_chunk_size:%" GRN_FMT_SIZE,
+ ii_buffer->filepos, ii_buffer->total_chunk_size);
+ grn_close(ii_buffer->tmpfd);
+ if (grn_unlink(ii_buffer->tmpfpath) == 0) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[ii][buffer][commit] removed temporary path: <%-.256s>",
+ ii_buffer->tmpfpath);
+ } else {
+ ERRNO_ERR("[ii][buffer][commit] failed to remove temporary path: <%-.256s>",
+ ii_buffer->tmpfpath);
+ }
+ ii_buffer->tmpfd = -1;
+ return ctx->rc;
+}
+
+grn_rc
+grn_ii_buffer_close(grn_ctx *ctx, grn_ii_buffer *ii_buffer)
+{
+ uint32_t i;
+ grn_table_flags flags;
+ grn_table_get_info(ctx, ii_buffer->ii->lexicon, &flags, NULL, NULL, NULL,
+ NULL);
+ if ((flags & GRN_OBJ_TABLE_TYPE_MASK) == GRN_OBJ_TABLE_PAT_KEY) {
+ grn_pat_cache_disable(ctx, (grn_pat *)ii_buffer->ii->lexicon);
+ }
+ if (ii_buffer->tmp_lexicon) {
+ grn_obj_close(ctx, ii_buffer->tmp_lexicon);
+ }
+ if (ii_buffer->tmpfd != -1) {
+ grn_close(ii_buffer->tmpfd);
+ if (grn_unlink(ii_buffer->tmpfpath) == 0) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[ii][buffer][close] removed temporary path: <%-.256s>",
+ ii_buffer->tmpfpath);
+ } else {
+ ERRNO_ERR("[ii][buffer][close] failed to remove temporary path: <%-.256s>",
+ ii_buffer->tmpfpath);
+ }
+ }
+ if (ii_buffer->block_buf) {
+ GRN_FREE(ii_buffer->block_buf);
+ }
+ if (ii_buffer->counters) {
+ GRN_FREE(ii_buffer->counters);
+ }
+ if (ii_buffer->blocks) {
+ for (i = 0; i < ii_buffer->nblocks; i++) {
+ if (ii_buffer->blocks[i].buffer) {
+ GRN_FREE(ii_buffer->blocks[i].buffer);
+ }
+ }
+ GRN_FREE(ii_buffer->blocks);
+ }
+ if (ii_buffer->values) {
+ for (i = 0; i < ii_buffer->max_nvalues; i++) {
+ ii_buffer_value_fin(ctx, &ii_buffer->values[i]);
+ }
+ GRN_FREE(ii_buffer->values);
+ }
+ GRN_FREE(ii_buffer);
+ return ctx->rc;
+}
+
+/*
+ * grn_ii_buffer_parse tokenizes values to be indexed.
+ *
+ * For each record of the target table, grn_ii_buffer_parse makes a list of
+ * target values and calls grn_ii_buffer_tokenize. To make a list of target
+ * values, ii_buffer_values_append is called for each value. Note that
+ * ii_buffer_values_append is called for each element for a vector.
+ */
+static void
+grn_ii_buffer_parse(grn_ctx *ctx, grn_ii_buffer *ii_buffer,
+ grn_obj *target, int ncols, grn_obj **cols)
+{
+ grn_table_cursor *tc;
+ grn_obj *vobjs;
+ if ((vobjs = GRN_MALLOCN(grn_obj, ncols))) {
+ int i;
+ for (i = 0; i < ncols; i++) {
+ GRN_TEXT_INIT(&vobjs[i], 0);
+ }
+ if ((tc = grn_table_cursor_open(ctx, target,
+ NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_BY_ID))) {
+ grn_id rid;
+ while ((rid = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ unsigned int j;
+ int sid;
+ grn_obj **col;
+ for (sid = 1, col = cols; sid <= ncols; sid++, col++) {
+ grn_obj *rv = &vobjs[sid - 1];
+ grn_obj_reinit_for(ctx, rv, *col);
+ if (GRN_OBJ_TABLEP(*col)) {
+ grn_table_get_key2(ctx, *col, rid, rv);
+ } else {
+ grn_obj_get_value(ctx, *col, rid, rv);
+ }
+ switch (rv->header.type) {
+ case GRN_BULK :
+ ii_buffer_values_append(ctx, ii_buffer, sid, 0,
+ GRN_TEXT_VALUE(rv), GRN_TEXT_LEN(rv),
+ GRN_FALSE);
+ break;
+ case GRN_UVECTOR :
+ {
+ unsigned int size;
+ unsigned int elem_size;
+ size = grn_uvector_size(ctx, rv);
+ elem_size = grn_uvector_element_size(ctx, rv);
+ for (j = 0; j < size; j++) {
+ ii_buffer_values_append(ctx, ii_buffer, sid, 0,
+ GRN_BULK_HEAD(rv) + (elem_size * j),
+ elem_size, GRN_FALSE);
+ }
+ }
+ break;
+ case GRN_VECTOR :
+ if (rv->u.v.body) {
+ int j;
+ int n_sections = rv->u.v.n_sections;
+ grn_section *sections = rv->u.v.sections;
+ const char *head = GRN_BULK_HEAD(rv->u.v.body);
+ for (j = 0; j < n_sections; j++) {
+ grn_section *section = sections + j;
+ if (section->length == 0) {
+ continue;
+ }
+ ii_buffer_values_append(ctx, ii_buffer, sid, section->weight,
+ head + section->offset,
+ section->length, GRN_FALSE);
+ }
+ }
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT,
+ "[index] invalid object assigned as value");
+ break;
+ }
+ }
+ grn_ii_buffer_tokenize(ctx, ii_buffer, rid);
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ for (i = 0; i < ncols; i++) {
+ GRN_OBJ_FIN(ctx, &vobjs[i]);
+ }
+ GRN_FREE(vobjs);
+ }
+}
+
+grn_rc
+grn_ii_build(grn_ctx *ctx, grn_ii *ii, uint64_t sparsity)
+{
+ grn_ii_buffer *ii_buffer;
+
+ {
+ /* Do nothing if there are no targets. */
+ grn_obj *data_table = grn_ctx_at(ctx, DB_OBJ(ii)->range);
+ if (!data_table) {
+ return ctx->rc;
+ }
+ if (grn_table_size(ctx, data_table) == 0) {
+ return ctx->rc;
+ }
+ }
+
+ ii_buffer = grn_ii_buffer_open(ctx, ii, sparsity);
+ if (ii_buffer) {
+ grn_id *source = (grn_id *)ii->obj.source;
+ if (ii->obj.source_size && ii->obj.source) {
+ int ncols = ii->obj.source_size / sizeof(grn_id);
+ grn_obj **cols = GRN_MALLOCN(grn_obj *, ncols);
+ if (cols) {
+ int i;
+ for (i = 0; i < ncols; i++) {
+ if (!(cols[i] = grn_ctx_at(ctx, source[i]))) { break; }
+ }
+ if (i == ncols) { /* All the source columns are available. */
+ grn_obj *target = cols[0];
+ if (!GRN_OBJ_TABLEP(target)) {
+ target = grn_ctx_at(ctx, target->header.domain);
+ }
+ if (target) {
+ grn_ii_buffer_parse(ctx, ii_buffer, target, ncols, cols);
+ grn_ii_buffer_commit(ctx, ii_buffer);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "failed to resolve the target");
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "failed to resolve a column (%d)", i);
+ }
+ GRN_FREE(cols);
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "ii->obj.source is void");
+ }
+ grn_ii_buffer_close(ctx, ii_buffer);
+ }
+ return ctx->rc;
+}
+
+/*
+ * ==========================================================================
+ * The following part provides constants, structures and functions for static
+ * indexing.
+ * ==========================================================================
+ */
+
+#define GRN_II_BUILDER_BUFFER_CHUNK_SIZE (S_CHUNK >> 2)
+
+#define GRN_II_BUILDER_MAX_LEXICON_CACHE_SIZE (1 << 24)
+
+#define GRN_II_BUILDER_MIN_BLOCK_THRESHOLD 1
+#define GRN_II_BUILDER_MAX_BLOCK_THRESHOLD (1 << 28)
+
+#define GRN_II_BUILDER_MIN_FILE_BUF_SIZE (1 << 12)
+#define GRN_II_BUILDER_MAX_FILE_BUF_SIZE (1 << 30)
+
+#define GRN_II_BUILDER_MIN_BLOCK_BUF_SIZE (1 << 12)
+#define GRN_II_BUILDER_MAX_BLOCK_BUF_SIZE (1 << 30)
+
+#define GRN_II_BUILDER_MIN_CHUNK_THRESHOLD 1
+#define GRN_II_BUILDER_MAX_CHUNK_THRESHOLD (1 << 28)
+
+#define GRN_II_BUILDER_MIN_BUFFER_MAX_N_TERMS 1
+#define GRN_II_BUILDER_MAX_BUFFER_MAX_N_TERMS \
+ ((S_SEGMENT - sizeof(buffer_header)) / sizeof(buffer_term))
+
+struct grn_ii_builder_options {
+ uint32_t lexicon_cache_size; /* Cache size of temporary lexicon */
+ /* A block is flushed if builder->n reaches this value. */
+ uint32_t block_threshold;
+ uint32_t file_buf_size; /* Buffer size for buffered output */
+ uint32_t block_buf_size; /* Buffer size for buffered input */
+ /* A chunk is flushed if chunk->n reaches this value. */
+ uint32_t chunk_threshold;
+ uint32_t buffer_max_n_terms; /* Maximum number of terms in each buffer */
+};
+
+static const grn_ii_builder_options grn_ii_builder_default_options = {
+ 0x80000, /* lexicon_cache_size */
+ 0x4000000, /* block_threshold */
+ 0x10000, /* file_buf_size */
+ 0x10000, /* block_buf_size */
+ 0x1000, /* chunk_threshold */
+ 0x3000, /* buffer_max_n_terms */
+};
+
+/* grn_ii_builder_options_init fills options with the default options. */
+void
+grn_ii_builder_options_init(grn_ii_builder_options *options)
+{
+ *options = grn_ii_builder_default_options;
+}
+
+/* grn_ii_builder_options_fix fixes out-of-range options. */
+static void
+grn_ii_builder_options_fix(grn_ii_builder_options *options)
+{
+ if (options->lexicon_cache_size > GRN_II_BUILDER_MAX_LEXICON_CACHE_SIZE) {
+ options->lexicon_cache_size = GRN_II_BUILDER_MAX_LEXICON_CACHE_SIZE;
+ }
+
+ if (options->block_threshold < GRN_II_BUILDER_MIN_BLOCK_THRESHOLD) {
+ options->block_threshold = GRN_II_BUILDER_MIN_BLOCK_THRESHOLD;
+ }
+ if (options->block_threshold > GRN_II_BUILDER_MAX_BLOCK_THRESHOLD) {
+ options->block_threshold = GRN_II_BUILDER_MAX_BLOCK_THRESHOLD;
+ }
+
+ if (options->file_buf_size < GRN_II_BUILDER_MIN_FILE_BUF_SIZE) {
+ options->file_buf_size = GRN_II_BUILDER_MIN_FILE_BUF_SIZE;
+ }
+ if (options->file_buf_size > GRN_II_BUILDER_MAX_FILE_BUF_SIZE) {
+ options->file_buf_size = GRN_II_BUILDER_MAX_FILE_BUF_SIZE;
+ }
+
+ if (options->block_buf_size < GRN_II_BUILDER_MIN_BLOCK_BUF_SIZE) {
+ options->block_buf_size = GRN_II_BUILDER_MIN_BLOCK_BUF_SIZE;
+ }
+ if (options->block_buf_size > GRN_II_BUILDER_MAX_BLOCK_BUF_SIZE) {
+ options->block_buf_size = GRN_II_BUILDER_MAX_BLOCK_BUF_SIZE;
+ }
+
+ if (options->chunk_threshold < GRN_II_BUILDER_MIN_CHUNK_THRESHOLD) {
+ options->chunk_threshold = GRN_II_BUILDER_MIN_CHUNK_THRESHOLD;
+ }
+ if (options->chunk_threshold > GRN_II_BUILDER_MAX_CHUNK_THRESHOLD) {
+ options->chunk_threshold = GRN_II_BUILDER_MAX_CHUNK_THRESHOLD;
+ }
+
+ if (options->buffer_max_n_terms < GRN_II_BUILDER_MIN_BUFFER_MAX_N_TERMS) {
+ options->buffer_max_n_terms = GRN_II_BUILDER_MIN_BUFFER_MAX_N_TERMS;
+ }
+ if (options->buffer_max_n_terms > GRN_II_BUILDER_MAX_BUFFER_MAX_N_TERMS) {
+ options->buffer_max_n_terms = GRN_II_BUILDER_MAX_BUFFER_MAX_N_TERMS;
+ }
+}
+
+#define GRN_II_BUILDER_TERM_INPLACE_SIZE\
+ (sizeof(grn_ii_builder_term) - (uintptr_t)&((grn_ii_builder_term *)0)->dummy)
+
+typedef struct {
+ grn_id rid; /* Last record ID */
+ uint32_t sid; /* Last section ID */
+ /* Last position (GRN_OBJ_WITH_POSITION) or frequency. */
+ uint32_t pos_or_freq;
+ uint32_t offset; /* Buffer write offset */
+ uint32_t size; /* Buffer size */
+ uint32_t dummy; /* Padding */
+ uint8_t *buf; /* Buffer (to be freed) */
+} grn_ii_builder_term;
+
+/* grn_ii_builder_term_is_inplace returns whether a term buffer is inplace. */
+inline static grn_bool
+grn_ii_builder_term_is_inplace(grn_ii_builder_term *term)
+{
+ return term->size == GRN_II_BUILDER_TERM_INPLACE_SIZE;
+}
+
+/* grn_ii_builder_term_get_buf returns a term buffer. */
+inline static uint8_t *
+grn_ii_builder_term_get_buf(grn_ii_builder_term *term)
+{
+ if (grn_ii_builder_term_is_inplace(term)) {
+ return (uint8_t *)&term->dummy;
+ } else {
+ return term->buf;
+ }
+}
+
+/*
+ * grn_ii_builder_term_init initializes a term. Note that an initialized term
+ * must be finalized by grn_ii_builder_term_fin.
+ */
+static void
+grn_ii_builder_term_init(grn_ctx *ctx, grn_ii_builder_term *term)
+{
+ term->rid = GRN_ID_NIL;
+ term->sid = 0;
+ term->pos_or_freq = 0;
+ term->offset = 0;
+ term->size = GRN_II_BUILDER_TERM_INPLACE_SIZE;
+}
+
+/* grn_ii_builder_term_fin finalizes a term. */
+static void
+grn_ii_builder_term_fin(grn_ctx *ctx, grn_ii_builder_term *term)
+{
+ if (!grn_ii_builder_term_is_inplace(term)) {
+ GRN_FREE(term->buf);
+ }
+}
+
+/* grn_ii_builder_term_reinit reinitializes a term. */
+static void
+grn_ii_builder_term_reinit(grn_ctx *ctx, grn_ii_builder_term *term)
+{
+ grn_ii_builder_term_fin(ctx, term);
+ grn_ii_builder_term_init(ctx, term);
+}
+
+/* grn_ii_builder_term_extend extends a term buffer. */
+static grn_rc
+grn_ii_builder_term_extend(grn_ctx *ctx, grn_ii_builder_term *term)
+{
+ uint8_t *buf;
+ uint32_t size = term->size * 2;
+ if (grn_ii_builder_term_is_inplace(term)) {
+ buf = (uint8_t *)GRN_MALLOC(size);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for term buffer: size = %u", size);
+ return ctx->rc;
+ }
+ grn_memcpy(buf, &term->dummy, term->offset);
+ } else {
+ buf = (uint8_t *)GRN_REALLOC(term->buf, size);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to reallocate memory for term buffer: size = %u", size);
+ return ctx->rc;
+ }
+ }
+ term->buf = buf;
+ term->size = size;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_term_append appends an integer to a term buffer. */
+inline static grn_rc
+grn_ii_builder_term_append(grn_ctx *ctx, grn_ii_builder_term *term,
+ uint64_t value)
+{
+ uint8_t *p;
+ if (value < (uint64_t)1 << 5) {
+ if (term->offset + 1 > term->size) {
+ grn_rc rc = grn_ii_builder_term_extend(ctx, term);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ p = grn_ii_builder_term_get_buf(term) + term->offset;
+ p[0] = (uint8_t)value;
+ term->offset++;
+ return GRN_SUCCESS;
+ } else if (value < (uint64_t)1 << 13) {
+ if (term->offset + 2 > term->size) {
+ grn_rc rc = grn_ii_builder_term_extend(ctx, term);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ p = grn_ii_builder_term_get_buf(term) + term->offset;
+ p[0] = (uint8_t)((value & 0x1f) | (1 << 5));
+ p[1] = (uint8_t)(value >> 5);
+ term->offset += 2;
+ return GRN_SUCCESS;
+ } else {
+ uint8_t i, n;
+ if (value < (uint64_t)1 << 21) {
+ n = 3;
+ } else if (value < (uint64_t)1 << 29) {
+ n = 4;
+ } else if (value < (uint64_t)1 << 37) {
+ n = 5;
+ } else if (value < (uint64_t)1 << 45) {
+ n = 6;
+ } else if (value < (uint64_t)1 << 53) {
+ n = 7;
+ } else {
+ n = 8;
+ }
+ if (term->offset + n > term->size) {
+ grn_rc rc = grn_ii_builder_term_extend(ctx, term);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ p = grn_ii_builder_term_get_buf(term) + term->offset;
+ p[0] = (uint8_t)(value & 0x1f) | ((n - 1) << 5);
+ value >>= 5;
+ for (i = 1; i < n; i++) {
+ p[i] = (uint8_t)value;
+ value >>= 8;
+ }
+ term->offset += n;
+ return GRN_SUCCESS;
+ }
+}
+
+typedef struct {
+ uint64_t offset; /* File offset */
+ uint32_t rest; /* Remaining size */
+ uint8_t *buf; /* Buffer (to be freed) */
+ uint8_t *cur; /* Current pointer */
+ uint8_t *end; /* End pointer */
+ uint32_t tid; /* Term ID */
+} grn_ii_builder_block;
+
+/*
+ * grn_ii_builder_block_init initializes a block. Note that an initialized
+ * block must be finalized by grn_ii_builder_block_fin.
+ */
+static void
+grn_ii_builder_block_init(grn_ctx *ctx, grn_ii_builder_block *block)
+{
+ block->offset = 0;
+ block->rest = 0;
+ block->buf = NULL;
+ block->cur = NULL;
+ block->end = NULL;
+ block->tid = GRN_ID_NIL;
+}
+
+/* grn_ii_builder_block_fin finalizes a block. */
+static void
+grn_ii_builder_block_fin(grn_ctx *ctx, grn_ii_builder_block *block)
+{
+ if (block->buf) {
+ GRN_FREE(block->buf);
+ }
+}
+
+/*
+ * grn_ii_builder_block_next reads the next integer. Note that this function
+ * returns GRN_END_OF_DATA if it reaches the end of a block.
+ */
+inline static grn_rc
+grn_ii_builder_block_next(grn_ctx *ctx, grn_ii_builder_block *block,
+ uint64_t *value)
+{
+ uint8_t n;
+ if (block->cur == block->end) {
+ return GRN_END_OF_DATA;
+ }
+ n = (*block->cur >> 5) + 1;
+ if (n > block->end - block->cur) {
+ return GRN_END_OF_DATA;
+ }
+ *value = 0;
+ switch (n) {
+ case 8 :
+ *value |= (uint64_t)block->cur[7] << 53;
+ case 7 :
+ *value |= (uint64_t)block->cur[6] << 45;
+ case 6 :
+ *value |= (uint64_t)block->cur[5] << 37;
+ case 5 :
+ *value |= (uint64_t)block->cur[4] << 29;
+ case 4 :
+ *value |= (uint64_t)block->cur[3] << 21;
+ case 3 :
+ *value |= (uint64_t)block->cur[2] << 13;
+ case 2 :
+ *value |= (uint64_t)block->cur[1] << 5;
+ case 1 :
+ *value |= block->cur[0] & 0x1f;
+ break;
+ }
+ block->cur += n;
+ return GRN_SUCCESS;
+}
+
+typedef struct {
+ grn_ii *ii; /* Inverted index */
+ uint32_t buf_id; /* Buffer ID */
+ uint32_t buf_seg_id; /* Buffer segment ID */
+ buffer *buf; /* Buffer (to be unreferenced) */
+ uint32_t chunk_id; /* Chunk ID */
+ uint32_t chunk_seg_id; /* Chunk segment ID */
+ uint8_t *chunk; /* Chunk (to be unreferenced) */
+ uint32_t chunk_offset; /* Chunk write position */
+ uint32_t chunk_size; /* Chunk size */
+} grn_ii_builder_buffer;
+
+/*
+ * grn_ii_builder_buffer_init initializes a buffer. Note that a buffer must be
+ * finalized by grn_ii_builder_buffer_fin.
+ */
+static void
+grn_ii_builder_buffer_init(grn_ctx *ctx, grn_ii_builder_buffer *buf,
+ grn_ii *ii)
+{
+ buf->ii = ii;
+ buf->buf_id = 0;
+ buf->buf_seg_id = 0;
+ buf->buf = NULL;
+ buf->chunk_id = 0;
+ buf->chunk_seg_id = 0;
+ buf->chunk = NULL;
+ buf->chunk_offset = 0;
+ buf->chunk_size = 0;
+}
+
+/* grn_ii_builder_buffer_fin finalizes a buffer. */
+static void
+grn_ii_builder_buffer_fin(grn_ctx *ctx, grn_ii_builder_buffer *buf)
+{
+ if (buf->buf) {
+ GRN_IO_SEG_UNREF(buf->ii->seg, buf->buf_seg_id);
+ }
+ if (buf->chunk) {
+ GRN_IO_SEG_UNREF(buf->ii->chunk, buf->chunk_seg_id);
+ }
+}
+
+/* grn_ii_builder_buffer_is_assigned returns whether a buffer is assigned. */
+static grn_bool
+grn_ii_builder_buffer_is_assigned(grn_ctx *ctx, grn_ii_builder_buffer *buf)
+{
+ return buf->buf != NULL;
+}
+
+/* grn_ii_builder_buffer_assign assigns a buffer. */
+static grn_rc
+grn_ii_builder_buffer_assign(grn_ctx *ctx, grn_ii_builder_buffer *buf,
+ size_t min_chunk_size)
+{
+ void *seg;
+ size_t chunk_size;
+ grn_rc rc;
+
+ /* Create a buffer. */
+ buf->buf_id = GRN_II_PSEG_NOT_ASSIGNED;
+ rc = buffer_segment_new(ctx, buf->ii, &buf->buf_id);
+ if (rc != GRN_SUCCESS) {
+ if (ctx->rc != GRN_SUCCESS) {
+ ERR(rc, "failed to allocate segment for buffer");
+ }
+ return rc;
+ }
+ buf->buf_seg_id = buf->ii->header->binfo[buf->buf_id];
+ GRN_IO_SEG_REF(buf->ii->seg, buf->buf_seg_id, seg);
+ if (!seg) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR,
+ "failed access buffer segment: buf_id = %u, seg_id = %u",
+ buf->buf_id, buf->buf_seg_id);
+ }
+ return ctx->rc;
+ }
+ buf->buf = (buffer *)seg;
+
+ /* Create a chunk. */
+ chunk_size = GRN_II_BUILDER_BUFFER_CHUNK_SIZE;
+ while (chunk_size < min_chunk_size) {
+ chunk_size *= 2;
+ }
+ rc = chunk_new(ctx, buf->ii, &buf->chunk_id, chunk_size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf->chunk_seg_id = buf->chunk_id >> GRN_II_N_CHUNK_VARIATION;
+ GRN_IO_SEG_REF(buf->ii->chunk, buf->chunk_seg_id, seg);
+ if (!seg) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR,
+ "failed access chunk segment: chunk_id = %u, seg_id = %u",
+ buf->chunk_id, buf->chunk_seg_id);
+ }
+ return ctx->rc;
+ }
+ buf->chunk = (uint8_t *)seg;
+ buf->chunk += (buf->chunk_id & ((1 << GRN_II_N_CHUNK_VARIATION) - 1)) <<
+ GRN_II_W_LEAST_CHUNK;
+ buf->chunk_offset = 0;
+ buf->chunk_size = chunk_size;
+
+ buf->buf->header.chunk = buf->chunk_id;
+ buf->buf->header.chunk_size = chunk_size;
+ buf->buf->header.buffer_free = S_SEGMENT - sizeof(buffer_header);
+ buf->buf->header.nterms = 0;
+ buf->buf->header.nterms_void = 0;
+ buf->ii->header->total_chunk_size += chunk_size;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_buffer_flush flushes a buffer. */
+static grn_rc
+grn_ii_builder_buffer_flush(grn_ctx *ctx, grn_ii_builder_buffer *buf)
+{
+ grn_ii *ii;
+
+ buf->buf->header.buffer_free = S_SEGMENT - sizeof(buffer_header) -
+ buf->buf->header.nterms * sizeof(buffer_term);
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "n_terms = %u, chunk_offset = %u, chunk_size = %u, total = %"
+ GRN_FMT_INT64U "KB",
+ buf->buf->header.nterms,
+ buf->chunk_offset,
+ buf->buf->header.chunk_size,
+ buf->ii->header->total_chunk_size >> 10);
+
+ ii = buf->ii;
+ grn_ii_builder_buffer_fin(ctx, buf);
+ grn_ii_builder_buffer_init(ctx, buf, ii);
+ return GRN_SUCCESS;
+}
+
+typedef struct {
+ grn_id tid; /* Term ID */
+ uint32_t n; /* Number of integers in buffers */
+ grn_id rid; /* Record ID */
+ uint32_t rid_gap; /* Record ID gap */
+ uint64_t pos_sum; /* Sum of position gaps */
+
+ uint32_t offset; /* Write offset */
+ uint32_t size; /* Buffer size */
+ grn_id *rid_buf; /* Buffer for record IDs (to be freed) */
+ uint32_t *sid_buf; /* Buffer for section IDs (to be freed) */
+ uint32_t *freq_buf; /* Buffer for frequencies (to be freed) */
+ uint32_t *weight_buf; /* Buffer for weights (to be freed) */
+
+ uint32_t pos_offset; /* Write offset of pos_buf */
+ uint32_t pos_size; /* Buffer size of pos_buf */
+ uint32_t *pos_buf; /* Buffer for positions (to be freed) */
+
+ size_t enc_offset; /* Write offset of enc_buf */
+ size_t enc_size; /* Buffer size of enc_buf */
+ uint8_t *enc_buf; /* Buffer for encoded data (to be freed) */
+} grn_ii_builder_chunk;
+
+/*
+ * grn_ii_builder_chunk_init initializes a chunk. Note that an initialized
+ * chunk must be finalized by grn_ii_builder_chunk_fin.
+ */
+static void
+grn_ii_builder_chunk_init(grn_ctx *ctx, grn_ii_builder_chunk *chunk)
+{
+ chunk->tid = GRN_ID_NIL;
+ chunk->n = 0;
+ chunk->rid = GRN_ID_NIL;
+ chunk->rid_gap = 0;
+ chunk->pos_sum = 0;
+
+ chunk->offset = 0;
+ chunk->size = 0;
+ chunk->rid_buf = NULL;
+ chunk->sid_buf = NULL;
+ chunk->freq_buf = NULL;
+ chunk->weight_buf = NULL;
+
+ chunk->pos_offset = 0;
+ chunk->pos_size = 0;
+ chunk->pos_buf = NULL;
+
+ chunk->enc_offset = 0;
+ chunk->enc_size = 0;
+ chunk->enc_buf = NULL;
+}
+
+/* grn_ii_builder_chunk_fin finalizes a chunk. */
+static void
+grn_ii_builder_chunk_fin(grn_ctx *ctx, grn_ii_builder_chunk *chunk)
+{
+ if (chunk->enc_buf) {
+ GRN_FREE(chunk->enc_buf);
+ }
+ if (chunk->pos_buf) {
+ GRN_FREE(chunk->pos_buf);
+ }
+ if (chunk->weight_buf) {
+ GRN_FREE(chunk->weight_buf);
+ }
+ if (chunk->freq_buf) {
+ GRN_FREE(chunk->freq_buf);
+ }
+ if (chunk->sid_buf) {
+ GRN_FREE(chunk->sid_buf);
+ }
+ if (chunk->rid_buf) {
+ GRN_FREE(chunk->rid_buf);
+ }
+}
+
+/*
+ * grn_ii_builder_chunk_clear clears stats except rid and buffers except
+ * enc_buf.
+ */
+static void
+grn_ii_builder_chunk_clear(grn_ctx *ctx, grn_ii_builder_chunk *chunk)
+{
+ chunk->n = 0;
+ chunk->rid_gap = 0;
+ chunk->pos_sum = 0;
+ chunk->offset = 0;
+ chunk->pos_offset = 0;
+}
+
+/*
+ * grn_ii_builder_chunk_extend_bufs extends buffers except pos_buf and enc_buf.
+ */
+static grn_rc
+grn_ii_builder_chunk_extend_bufs(grn_ctx *ctx, grn_ii_builder_chunk *chunk,
+ uint32_t ii_flags)
+{
+ uint32_t *buf, size = chunk->size ? chunk->size * 2 : 1;
+ size_t n_bytes = size * sizeof(uint32_t);
+
+ buf = (uint32_t *)GRN_REALLOC(chunk->rid_buf, n_bytes);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for record IDs: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ chunk->rid_buf = buf;
+
+ if (ii_flags & GRN_OBJ_WITH_SECTION) {
+ buf = (uint32_t *)GRN_REALLOC(chunk->sid_buf, n_bytes);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for section IDs:"
+ " n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ chunk->sid_buf = buf;
+ }
+
+ buf = (uint32_t *)GRN_REALLOC(chunk->freq_buf, n_bytes);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for frequencies: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ chunk->freq_buf = buf;
+
+ if (ii_flags & GRN_OBJ_WITH_WEIGHT) {
+ buf = (uint32_t *)GRN_REALLOC(chunk->weight_buf, n_bytes);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for weights: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ chunk->weight_buf = buf;
+ }
+
+ chunk->size = size;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_chunk_extend_pos_buf extends pos_buf. */
+static grn_rc
+grn_ii_builder_chunk_extend_pos_buf(grn_ctx *ctx, grn_ii_builder_chunk *chunk)
+{
+ uint32_t *buf, size = chunk->pos_size ? chunk->pos_size * 2 : 1;
+ size_t n_bytes = size * sizeof(uint32_t);
+ buf = (uint32_t *)GRN_REALLOC(chunk->pos_buf, n_bytes);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for positions: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ chunk->pos_buf = buf;
+ chunk->pos_size = size;
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ii_builder_chunk_reserve_enc_buf estimates a size that is enough to
+ * store encoded data and allocates memory to enc_buf.
+ */
+static grn_rc
+grn_ii_builder_chunk_reserve_enc_buf(grn_ctx *ctx, grn_ii_builder_chunk *chunk,
+ uint32_t n_cinfos)
+{
+ size_t rich_size = (chunk->n + 4) * sizeof(uint32_t) +
+ n_cinfos * sizeof(chunk_info);
+ if (chunk->enc_size < rich_size) {
+ size_t size = chunk->enc_size ? chunk->enc_size * 2 : 1;
+ uint8_t *buf;
+ while (size < rich_size) {
+ size *= 2;
+ }
+ buf = GRN_REALLOC(chunk->enc_buf, size);
+ if (!buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for encoding: size = %" GRN_FMT_SIZE,
+ size);
+ return ctx->rc;
+ }
+ chunk->enc_buf = buf;
+ chunk->enc_size = size;
+ }
+ chunk->enc_offset = 0;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_chunk_encode encodes a chunk buffer. */
+static void
+grn_ii_builder_chunk_encode_buf(grn_ctx *ctx, grn_ii_builder_chunk *chunk,
+ uint32_t *values, uint32_t n_values,
+ grn_bool use_p_enc)
+{
+ uint8_t *p = chunk->enc_buf + chunk->enc_offset;
+ uint32_t i;
+ if (use_p_enc) {
+ uint8_t freq[33];
+ uint32_t buf[UNIT_SIZE];
+ while (n_values >= UNIT_SIZE) {
+ memset(freq, 0, 33);
+ for (i = 0; i < UNIT_SIZE; i++) {
+ buf[i] = values[i];
+ if (buf[i]) {
+ uint32_t w;
+ GRN_BIT_SCAN_REV(buf[i], w);
+ freq[w + 1]++;
+ } else {
+ freq[0]++;
+ }
+ }
+ p = pack(buf, UNIT_SIZE, freq, p);
+ values += UNIT_SIZE;
+ n_values -= UNIT_SIZE;
+ }
+ if (n_values) {
+ memset(freq, 0, 33);
+ for (i = 0; i < n_values; i++) {
+ buf[i] = values[i];
+ if (buf[i]) {
+ uint32_t w;
+ GRN_BIT_SCAN_REV(buf[i], w);
+ freq[w + 1]++;
+ } else {
+ freq[0]++;
+ }
+ }
+ p = pack(buf, n_values, freq, p);
+ }
+ } else {
+ for (i = 0; i < n_values; i++) {
+ GRN_B_ENC(values[i], p);
+ }
+ }
+ chunk->enc_offset = p - chunk->enc_buf;
+}
+
+/* grn_ii_builder_chunk_encode encodes a chunk. */
+static grn_rc
+grn_ii_builder_chunk_encode(grn_ctx *ctx, grn_ii_builder_chunk *chunk,
+ chunk_info *cinfos, uint32_t n_cinfos)
+{
+ grn_rc rc;
+ uint8_t *p;
+ uint8_t shift = 0, use_p_enc_flags = 0;
+ uint8_t rid_use_p_enc, rest_use_p_enc, pos_use_p_enc = 0;
+
+ /* Choose an encoding. */
+ rid_use_p_enc = chunk->offset >= 16 && chunk->offset > (chunk->rid >> 8);
+ use_p_enc_flags |= rid_use_p_enc << shift++;
+ rest_use_p_enc = chunk->offset >= 3;
+ if (chunk->sid_buf) {
+ use_p_enc_flags |= rest_use_p_enc << shift++;
+ }
+ use_p_enc_flags |= rest_use_p_enc << shift++;
+ if (chunk->weight_buf) {
+ use_p_enc_flags |= rest_use_p_enc << shift++;
+ }
+ if (chunk->pos_buf) {
+ pos_use_p_enc = chunk->pos_offset >= 32 &&
+ chunk->pos_offset > (chunk->pos_sum >> 13);
+ use_p_enc_flags |= pos_use_p_enc << shift++;
+ }
+
+ rc = grn_ii_builder_chunk_reserve_enc_buf(ctx, chunk, n_cinfos);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ /* Encode a header. */
+ p = chunk->enc_buf;
+ if (n_cinfos) {
+ uint32_t i;
+ GRN_B_ENC(n_cinfos, p);
+ for (i = 0; i < n_cinfos; i++) {
+ GRN_B_ENC(cinfos[i].segno, p);
+ GRN_B_ENC(cinfos[i].size, p);
+ GRN_B_ENC(cinfos[i].dgap, p);
+ }
+ }
+ if (use_p_enc_flags) {
+ GRN_B_ENC(use_p_enc_flags << 1, p);
+ GRN_B_ENC(chunk->offset, p);
+ if (chunk->pos_buf) {
+ GRN_B_ENC(chunk->pos_offset - chunk->offset, p);
+ }
+ } else {
+ GRN_B_ENC((chunk->offset << 1) | 1, p);
+ }
+ chunk->enc_offset = p - chunk->enc_buf;
+
+ /* Encode a body. */
+ grn_ii_builder_chunk_encode_buf(ctx, chunk, chunk->rid_buf, chunk->offset,
+ rid_use_p_enc);
+ if (chunk->sid_buf) {
+ grn_ii_builder_chunk_encode_buf(ctx, chunk, chunk->sid_buf, chunk->offset,
+ rest_use_p_enc);
+ }
+ grn_ii_builder_chunk_encode_buf(ctx, chunk, chunk->freq_buf, chunk->offset,
+ rest_use_p_enc);
+ if (chunk->weight_buf) {
+ grn_ii_builder_chunk_encode_buf(ctx, chunk, chunk->weight_buf,
+ chunk->offset, rest_use_p_enc);
+ }
+ if (chunk->pos_buf) {
+ grn_ii_builder_chunk_encode_buf(ctx, chunk, chunk->pos_buf,
+ chunk->pos_offset, pos_use_p_enc);
+ }
+
+ return GRN_SUCCESS;
+}
+
+typedef struct {
+ grn_ii *ii; /* Building inverted index */
+ grn_ii_builder_options options; /* Options */
+
+ grn_obj *src_table; /* Source table */
+ grn_obj **srcs; /* Source columns (to be freed) */
+ uint32_t n_srcs; /* Number of source columns */
+ uint8_t sid_bits; /* Number of bits for section ID */
+ uint64_t sid_mask; /* Mask bits for section ID */
+
+ grn_obj *lexicon; /* Block lexicon (to be closed) */
+ grn_obj *tokenizer; /* Lexicon's tokenizer */
+ grn_obj *normalizer; /* Lexicon's normalzier */
+
+ uint32_t n; /* Number of integers appended to the current block */
+ grn_id rid; /* Record ID */
+ uint32_t sid; /* Section ID */
+ uint32_t pos; /* Position */
+
+ grn_ii_builder_term *terms; /* Terms (to be freed) */
+ uint32_t n_terms; /* Number of distinct terms */
+ uint32_t max_n_terms; /* Maximum number of distinct terms */
+ uint32_t terms_size; /* Buffer size of terms */
+
+ /* A temporary file to save blocks. */
+ char path[PATH_MAX]; /* File path */
+ int fd; /* File descriptor (to be closed) */
+ uint8_t *file_buf; /* File buffer for buffered output (to be freed) */
+ uint32_t file_buf_offset; /* File buffer write offset */
+
+ grn_ii_builder_block *blocks; /* Blocks (to be freed) */
+ uint32_t n_blocks; /* Number of blocks */
+ uint32_t blocks_size; /* Buffer size of blocks */
+
+ grn_ii_builder_buffer buf; /* Buffer (to be finalized) */
+ grn_ii_builder_chunk chunk; /* Chunk (to be finalized) */
+
+ uint32_t df; /* Document frequency (number of sections) */
+ chunk_info *cinfos; /* Chunk headers (to be freed) */
+ uint32_t n_cinfos; /* Number of chunks */
+ uint32_t cinfos_size; /* Size of cinfos */
+} grn_ii_builder;
+
+/*
+ * grn_ii_builder_init initializes a builder. Note that an initialized builder
+ * must be finalized by grn_ii_builder_fin.
+ */
+static grn_rc
+grn_ii_builder_init(grn_ctx *ctx, grn_ii_builder *builder,
+ grn_ii *ii, const grn_ii_builder_options *options)
+{
+ builder->ii = ii;
+ builder->options = *options;
+ if (grn_ii_builder_block_threshold_force > 0) {
+ builder->options.block_threshold = grn_ii_builder_block_threshold_force;
+ }
+ grn_ii_builder_options_fix(&builder->options);
+
+ builder->src_table = NULL;
+ builder->srcs = NULL;
+ builder->n_srcs = 0;
+ builder->sid_bits = 0;
+ builder->sid_mask = 0;
+
+ builder->lexicon = NULL;
+ builder->tokenizer = NULL;
+ builder->normalizer = NULL;
+
+ builder->n = 0;
+ builder->rid = GRN_ID_NIL;
+ builder->sid = 0;
+ builder->pos = 0;
+
+ builder->terms = NULL;
+ builder->n_terms = 0;
+ builder->max_n_terms = 0;
+ builder->terms_size = 0;
+
+ builder->path[0] = '\0';
+ builder->fd = -1;
+ builder->file_buf = NULL;
+ builder->file_buf_offset = 0;
+
+ builder->blocks = NULL;
+ builder->n_blocks = 0;
+ builder->blocks_size = 0;
+
+ grn_ii_builder_buffer_init(ctx, &builder->buf, ii);
+ grn_ii_builder_chunk_init(ctx, &builder->chunk);
+
+ builder->df = 0;
+ builder->cinfos = NULL;
+ builder->n_cinfos = 0;
+ builder->cinfos_size = 0;
+
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_fin_terms finalizes terms. */
+static void
+grn_ii_builder_fin_terms(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ if (builder->terms) {
+ uint32_t i;
+ for (i = 0; i < builder->max_n_terms; i++) {
+ grn_ii_builder_term_fin(ctx, &builder->terms[i]);
+ }
+ GRN_FREE(builder->terms);
+
+ /* To avoid double finalization. */
+ builder->terms = NULL;
+ }
+}
+
+/* grn_ii_builder_fin finalizes a builder. */
+static grn_rc
+grn_ii_builder_fin(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ if (builder->cinfos) {
+ GRN_FREE(builder->cinfos);
+ }
+ grn_ii_builder_chunk_fin(ctx, &builder->chunk);
+ grn_ii_builder_buffer_fin(ctx, &builder->buf);
+ if (builder->blocks) {
+ uint32_t i;
+ for (i = 0; i < builder->n_blocks; i++) {
+ grn_ii_builder_block_fin(ctx, &builder->blocks[i]);
+ }
+ GRN_FREE(builder->blocks);
+ }
+ if (builder->file_buf) {
+ GRN_FREE(builder->file_buf);
+ }
+ if (builder->fd != -1) {
+ grn_close(builder->fd);
+ if (grn_unlink(builder->path) == 0) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[ii][builder][fin] removed path: <%-.256s>",
+ builder->path);
+ } else {
+ ERRNO_ERR("[ii][builder][fin] failed to remove path: <%-.256s>",
+ builder->path);
+ }
+ }
+ grn_ii_builder_fin_terms(ctx, builder);
+ if (builder->lexicon) {
+ grn_obj_close(ctx, builder->lexicon);
+ }
+ if (builder->srcs) {
+ GRN_FREE(builder->srcs);
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ii_builder_open creates a builder. Note that a builder must be closed by
+ * grn_ii_builder_close.
+ */
+static grn_rc
+grn_ii_builder_open(grn_ctx *ctx, grn_ii *ii,
+ const grn_ii_builder_options *options,
+ grn_ii_builder **builder)
+{
+ grn_rc rc;
+ grn_ii_builder *new_builder = GRN_MALLOCN(grn_ii_builder, 1);
+ if (!new_builder) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (!options) {
+ options = &grn_ii_builder_default_options;
+ }
+ rc = grn_ii_builder_init(ctx, new_builder, ii, options);
+ if (rc != GRN_SUCCESS) {
+ GRN_FREE(new_builder);
+ return rc;
+ }
+ *builder = new_builder;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_close closes a builder. */
+static grn_rc
+grn_ii_builder_close(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_rc rc;
+ if (!builder) {
+ ERR(GRN_INVALID_ARGUMENT, "builder is null");
+ return ctx->rc;
+ }
+ rc = grn_ii_builder_fin(ctx, builder);
+ GRN_FREE(builder);
+ return rc;
+}
+
+/* grn_ii_builder_create_lexicon creates a block lexicon. */
+static grn_rc
+grn_ii_builder_create_lexicon(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_table_flags flags;
+ grn_obj *domain = grn_ctx_at(ctx, builder->ii->lexicon->header.domain);
+ grn_obj *range = grn_ctx_at(ctx, DB_OBJ(builder->ii->lexicon)->range);
+ grn_obj *tokenizer, *normalizer, *token_filters;
+ grn_rc rc = grn_table_get_info(ctx, builder->ii->lexicon, &flags, NULL,
+ &tokenizer, &normalizer, &token_filters);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ flags &= ~GRN_OBJ_PERSISTENT;
+ builder->lexicon = grn_table_create(ctx, NULL, 0, NULL,
+ flags, domain, range);
+ if (!builder->lexicon) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR, "[index] failed to create a block lexicon");
+ }
+ return ctx->rc;
+ }
+ builder->tokenizer = tokenizer;
+ builder->normalizer = normalizer;
+ rc = grn_obj_set_info(ctx, builder->lexicon,
+ GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_obj_set_info(ctx, builder->lexicon,
+ GRN_INFO_NORMALIZER, normalizer);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_obj_set_info(ctx, builder->lexicon,
+ GRN_INFO_TOKEN_FILTERS, token_filters);
+ }
+ }
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if ((flags & GRN_OBJ_TABLE_TYPE_MASK) == GRN_OBJ_TABLE_PAT_KEY) {
+ if (builder->options.lexicon_cache_size) {
+ rc = grn_pat_cache_enable(ctx, (grn_pat *)builder->lexicon,
+ builder->options.lexicon_cache_size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ii_builder_extend_terms extends a buffer for terms in order to make
+ * terms[n_terms - 1] available.
+ */
+static grn_rc
+grn_ii_builder_extend_terms(grn_ctx *ctx, grn_ii_builder *builder,
+ uint32_t n_terms)
+{
+ if (n_terms <= builder->n_terms) {
+ return GRN_SUCCESS;
+ }
+
+ if (n_terms > builder->max_n_terms) {
+ uint32_t i;
+ if (n_terms > builder->terms_size) {
+ /* Resize builder->terms for new terms. */
+ size_t n_bytes;
+ uint32_t terms_size = builder->terms_size ? builder->terms_size * 2 : 1;
+ grn_ii_builder_term *terms;
+ while (terms_size < n_terms) {
+ terms_size *= 2;
+ }
+ n_bytes = terms_size * sizeof(grn_ii_builder_term);
+ terms = (grn_ii_builder_term *)GRN_REALLOC(builder->terms, n_bytes);
+ if (!terms) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for terms: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ builder->terms = terms;
+ builder->terms_size = terms_size;
+ }
+ /* Initialize new terms. */
+ for (i = builder->max_n_terms; i < n_terms; i++) {
+ grn_ii_builder_term_init(ctx, &builder->terms[i]);
+ }
+ builder->max_n_terms = n_terms;
+ }
+
+ builder->n += n_terms - builder->n_terms;
+ builder->n_terms = n_terms;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_get_term gets a term associated with tid. */
+inline static grn_rc
+grn_ii_builder_get_term(grn_ctx *ctx, grn_ii_builder *builder, grn_id tid,
+ grn_ii_builder_term **term)
+{
+ uint32_t n_terms = tid;
+ if (n_terms > builder->n_terms) {
+ grn_rc rc = grn_ii_builder_extend_terms(ctx, builder, n_terms);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ *term = &builder->terms[tid - 1];
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_flush_file_buf flushes buffered data as a block. */
+static grn_rc
+grn_ii_builder_flush_file_buf(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ if (builder->file_buf_offset) {
+ ssize_t size = grn_write(builder->fd, builder->file_buf,
+ builder->file_buf_offset);
+ if ((uint64_t)size != builder->file_buf_offset) {
+ SERR("failed to write data: expected = %u, actual = %" GRN_FMT_INT64D,
+ builder->file_buf_offset, (int64_t)size);
+ }
+ builder->file_buf_offset = 0;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_flush_term flushes a term and clears it */
+static grn_rc
+grn_ii_builder_flush_term(grn_ctx *ctx, grn_ii_builder *builder,
+ grn_ii_builder_term *term)
+{
+ grn_rc rc;
+ uint8_t *term_buf;
+
+ /* Append sentinels. */
+ if (term->rid != GRN_ID_NIL) {
+ if (builder->ii->header->flags & GRN_OBJ_WITH_POSITION) {
+ rc = grn_ii_builder_term_append(ctx, term, 0);
+ } else {
+ rc = grn_ii_builder_term_append(ctx, term, term->pos_or_freq);
+ }
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ rc = grn_ii_builder_term_append(ctx, term, 0);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ {
+ /* Put the global term ID. */
+ int key_size;
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ uint8_t *p;
+ uint32_t rest, value;
+ grn_rc rc;
+ grn_id local_tid = term - builder->terms + 1, global_tid;
+ key_size = grn_table_get_key(ctx, builder->lexicon, local_tid,
+ key, GRN_TABLE_MAX_KEY_SIZE);
+ if (!key_size) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR, "failed to get key: tid = %u", local_tid);
+ }
+ return ctx->rc;
+ }
+ global_tid = grn_table_add(ctx, builder->ii->lexicon, key, key_size, NULL);
+ if (global_tid == GRN_ID_NIL) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR,
+ "failed to get global term ID: tid = %u, key = \"%.*s\"",
+ local_tid, key_size, key);
+ }
+ return ctx->rc;
+ }
+
+ rest = builder->options.file_buf_size - builder->file_buf_offset;
+ if (rest < 10) {
+ rc = grn_ii_builder_flush_file_buf(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ value = global_tid;
+ p = builder->file_buf + builder->file_buf_offset;
+ if (value < 1U << 5) {
+ p[0] = (uint8_t)value;
+ builder->file_buf_offset++;
+ } else if (value < 1U << 13) {
+ p[0] = (uint8_t)((value & 0x1f) | (1 << 5));
+ p[1] = (uint8_t)(value >> 5);
+ builder->file_buf_offset += 2;
+ } else {
+ uint8_t i, n;
+ if (value < 1U << 21) {
+ n = 3;
+ } else if (value < 1U << 29) {
+ n = 4;
+ } else {
+ n = 5;
+ }
+ p[0] = (uint8_t)(value & 0x1f) | ((n - 1) << 5);
+ value >>= 5;
+ for (i = 1; i < n; i++) {
+ p[i] = (uint8_t)value;
+ value >>= 8;
+ }
+ builder->file_buf_offset += n;
+ }
+ }
+
+ /* Flush a term buffer. */
+ term_buf = grn_ii_builder_term_get_buf(term);
+ if (term->offset > builder->options.file_buf_size) {
+ ssize_t size;
+ rc = grn_ii_builder_flush_file_buf(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ size = grn_write(builder->fd, term_buf, term->offset);
+ if ((uint64_t)size != term->offset) {
+ SERR("failed to write data: expected = %u, actual = %" GRN_FMT_INT64D,
+ term->offset, (int64_t)size);
+ }
+ } else {
+ uint32_t rest = builder->options.file_buf_size - builder->file_buf_offset;
+ if (term->offset <= rest) {
+ grn_memcpy(builder->file_buf + builder->file_buf_offset,
+ term_buf, term->offset);
+ builder->file_buf_offset += term->offset;
+ } else {
+ grn_memcpy(builder->file_buf + builder->file_buf_offset,
+ term_buf, rest);
+ builder->file_buf_offset += rest;
+ rc = grn_ii_builder_flush_file_buf(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->file_buf_offset = term->offset - rest;
+ grn_memcpy(builder->file_buf, term_buf + rest, builder->file_buf_offset);
+ }
+ }
+ grn_ii_builder_term_reinit(ctx, term);
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ii_builder_create_file creates a temporary file and allocates memory for
+ * buffered output.
+ */
+static grn_rc
+grn_ii_builder_create_file(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_snprintf(builder->path, PATH_MAX, PATH_MAX,
+ "%-.256sXXXXXX", grn_io_path(builder->ii->seg));
+ builder->fd = grn_mkstemp(builder->path);
+ if (builder->fd == -1) {
+ SERR("failed to create a temporary file: path = \"%-.256s\"",
+ builder->path);
+ return ctx->rc;
+ }
+ builder->file_buf = (uint8_t *)GRN_MALLOC(builder->options.file_buf_size);
+ if (!builder->file_buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for buffered output: size = %u",
+ builder->options.file_buf_size);
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_register_block registers a block. */
+static grn_rc
+grn_ii_builder_register_block(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_ii_builder_block *block;
+ uint64_t file_offset = grn_lseek(builder->fd, 0, SEEK_CUR);
+ if (file_offset == (uint64_t)-1) {
+ SERR("failed to get file offset");
+ return ctx->rc;
+ }
+ if (builder->n_blocks >= builder->blocks_size) {
+ size_t n_bytes;
+ uint32_t blocks_size = 1;
+ grn_ii_builder_block *blocks;
+ while (blocks_size <= builder->n_blocks) {
+ blocks_size *= 2;
+ }
+ n_bytes = blocks_size * sizeof(grn_ii_builder_block);
+ blocks = (grn_ii_builder_block *)GRN_REALLOC(builder->blocks, n_bytes);
+ if (!blocks) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for block: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ builder->blocks = blocks;
+ builder->blocks_size = blocks_size;
+ }
+ block = &builder->blocks[builder->n_blocks];
+ grn_ii_builder_block_init(ctx, block);
+ if (!builder->n_blocks) {
+ block->offset = 0;
+ } else {
+ grn_ii_builder_block *prev_block = &builder->blocks[builder->n_blocks - 1];
+ block->offset = prev_block->offset + prev_block->rest;
+ }
+ block->rest = (uint32_t)(file_offset - block->offset);
+ builder->n_blocks++;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_flush_block flushes a block to a temporary file. */
+static grn_rc
+grn_ii_builder_flush_block(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_rc rc;
+ grn_table_cursor *cursor;
+
+ if (!builder->n) {
+ /* Do nothing if there are no output data. */
+ return GRN_SUCCESS;
+ }
+ if (builder->fd == -1) {
+ rc = grn_ii_builder_create_file(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+
+ /* Flush terms into a temporary file. */
+ cursor = grn_table_cursor_open(ctx, builder->lexicon,
+ NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_BY_KEY);
+ for (;;) {
+ grn_id tid = grn_table_cursor_next(ctx, cursor);
+ if (tid == GRN_ID_NIL) {
+ break;
+ }
+ rc = grn_ii_builder_flush_term(ctx, builder, &builder->terms[tid - 1]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ rc = grn_ii_builder_flush_file_buf(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ /* Register a block and clear the current data. */
+ rc = grn_ii_builder_register_block(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_table_truncate(ctx, builder->lexicon);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->rid = GRN_ID_NIL;
+ builder->n_terms = 0;
+ builder->n = 0;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_append_token appends a token. */
+static grn_rc
+grn_ii_builder_append_token(grn_ctx *ctx, grn_ii_builder *builder,
+ grn_id rid, uint32_t sid, uint32_t weight,
+ grn_id tid, uint32_t pos)
+{
+ grn_rc rc;
+ uint32_t ii_flags = builder->ii->header->flags;
+ grn_ii_builder_term *term;
+ rc = grn_ii_builder_get_term(ctx, builder, tid, &term);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (rid != term->rid || sid != term->sid) {
+ uint64_t rsid;
+ if (term->rid != GRN_ID_NIL) {
+ if (ii_flags & GRN_OBJ_WITH_POSITION) {
+ /* Append the end of positions. */
+ rc = grn_ii_builder_term_append(ctx, term, 0);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->n++;
+ } else {
+ /* Append a frequency if positions are not available. */
+ rc = grn_ii_builder_term_append(ctx, term, term->pos_or_freq);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->n++;
+ }
+ }
+ rsid = ((uint64_t)(rid - term->rid) << builder->sid_bits) | (sid - 1);
+ rc = grn_ii_builder_term_append(ctx, term, rsid);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->n++;
+ if (ii_flags & GRN_OBJ_WITH_WEIGHT) {
+ rc = grn_ii_builder_term_append(ctx, term, weight);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->n++;
+ }
+ term->rid = rid;
+ term->sid = sid;
+ term->pos_or_freq = 0;
+ }
+ if (ii_flags & GRN_OBJ_WITH_POSITION) {
+ rc = grn_ii_builder_term_append(ctx, term, pos - term->pos_or_freq);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->n++;
+ term->pos_or_freq = pos;
+ } else {
+ term->pos_or_freq++;
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ii_builder_append_value appends a value. Note that values must be
+ * appended in ascending rid and sid order.
+ */
+static grn_rc
+grn_ii_builder_append_value(grn_ctx *ctx, grn_ii_builder *builder,
+ grn_id rid, uint32_t sid, uint32_t weight,
+ const char *value, uint32_t value_size)
+{
+ uint32_t pos = 0;
+ grn_token_cursor *cursor;
+ if (rid != builder->rid) {
+ builder->rid = rid;
+ builder->sid = sid;
+ builder->pos = 1;
+ } else if (sid != builder->sid) {
+ builder->sid = sid;
+ builder->pos = 1;
+ } else {
+ /* Insert a space between values. */
+ builder->pos++;
+ }
+ if (value_size) {
+ if (!builder->tokenizer && !builder->normalizer) {
+ grn_id tid;
+ switch (builder->lexicon->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ tid = grn_pat_add(ctx, (grn_pat *)builder->lexicon,
+ value, value_size, NULL, NULL);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ tid = grn_dat_add(ctx, (grn_dat *)builder->lexicon,
+ value, value_size, NULL, NULL);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ tid = grn_hash_add(ctx, (grn_hash *)builder->lexicon,
+ value, value_size, NULL, NULL);
+ break;
+ case GRN_TABLE_NO_KEY :
+ tid = *(grn_id *)value;
+ break;
+ default :
+ tid = GRN_ID_NIL;
+ break;
+ }
+ if (tid != GRN_ID_NIL) {
+ grn_rc rc;
+ pos = builder->pos;
+ rc = grn_ii_builder_append_token(ctx, builder, rid, sid,
+ weight, tid, pos);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ } else {
+ cursor = grn_token_cursor_open(ctx, builder->lexicon, value, value_size,
+ GRN_TOKEN_ADD, 0);
+ if (!cursor) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR,
+ "grn_token_cursor_open failed: value = <%.*s>",
+ value_size, value);
+ }
+ return ctx->rc;
+ }
+ while (cursor->status == GRN_TOKEN_CURSOR_DOING) {
+ grn_id tid = grn_token_cursor_next(ctx, cursor);
+ if (tid != GRN_ID_NIL) {
+ grn_rc rc;
+ pos = builder->pos + cursor->pos;
+ rc = grn_ii_builder_append_token(ctx, builder, rid, sid,
+ weight, tid, pos);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ }
+ grn_token_cursor_close(ctx, cursor);
+ }
+ }
+ builder->pos = pos + 1;
+ return ctx->rc;
+}
+
+/* grn_ii_builder_append_obj appends a BULK, UVECTOR or VECTOR object. */
+static grn_rc
+grn_ii_builder_append_obj(grn_ctx *ctx, grn_ii_builder *builder,
+ grn_id rid, uint32_t sid, grn_obj *obj)
+{
+ switch (obj->header.type) {
+ case GRN_BULK :
+ return grn_ii_builder_append_value(ctx, builder, rid, sid, 0,
+ GRN_TEXT_VALUE(obj), GRN_TEXT_LEN(obj));
+ case GRN_UVECTOR :
+ {
+ const char *p = GRN_BULK_HEAD(obj);
+ uint32_t i, n_values = grn_uvector_size(ctx, obj);
+ uint32_t value_size = grn_uvector_element_size(ctx, obj);
+ for (i = 0; i < n_values; i++) {
+ grn_rc rc = grn_ii_builder_append_value(ctx, builder, rid, sid, 0,
+ p, value_size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ p += value_size;
+ }
+ }
+ return GRN_SUCCESS;
+ case GRN_VECTOR :
+ if (obj->u.v.body) {
+ /*
+ * Note that the following sections and n_sections don't correspond to
+ * source columns.
+ */
+ int i, n_secs = obj->u.v.n_sections;
+ grn_section *secs = obj->u.v.sections;
+ const char *head = GRN_BULK_HEAD(obj->u.v.body);
+ for (i = 0; i < n_secs; i++) {
+ grn_rc rc;
+ grn_section *sec = &secs[i];
+ if (sec->length == 0) {
+ continue;
+ }
+ if (builder->tokenizer) {
+ sid = i + 1;
+ }
+ rc = grn_ii_builder_append_value(ctx, builder, rid, sid, sec->weight,
+ head + sec->offset, sec->length);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "[index] invalid object assigned as value");
+ return ctx->rc;
+ }
+}
+
+/*
+ * grn_ii_builder_append_srcs reads values from source columns and appends the
+ * values.
+ */
+static grn_rc
+grn_ii_builder_append_srcs(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ size_t i;
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *objs;
+ grn_table_cursor *cursor;
+
+ /* Allocate memory for objects to store source values. */
+ objs = GRN_MALLOCN(grn_obj, builder->n_srcs);
+ if (!objs) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for objs: n_srcs = %u", builder->n_srcs);
+ return ctx->rc;
+ }
+
+ /* Create a cursor to get records in the ID order. */
+ cursor = grn_table_cursor_open(ctx, builder->src_table, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_OBJECT_CORRUPT, "[index] failed to open table cursor");
+ }
+ GRN_FREE(objs);
+ return ctx->rc;
+ }
+
+ /* Read source values and append it. */
+ for (i = 0; i < builder->n_srcs; i++) {
+ GRN_TEXT_INIT(&objs[i], 0);
+ }
+ while (rc == GRN_SUCCESS) {
+ grn_id rid = grn_table_cursor_next(ctx, cursor);
+ if (rid == GRN_ID_NIL) {
+ break;
+ }
+ for (i = 0; i < builder->n_srcs; i++) {
+ grn_obj *obj = &objs[i];
+ grn_obj *src = builder->srcs[i];
+ rc = grn_obj_reinit_for(ctx, obj, src);
+ if (rc == GRN_SUCCESS) {
+ if (GRN_OBJ_TABLEP(src)) {
+ int len = grn_table_get_key2(ctx, src, rid, obj);
+ if (len <= 0) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR, "failed to get key: rid = %u, len = %d",
+ rid, len);
+ }
+ rc = ctx->rc;
+ }
+ } else {
+ if (!grn_obj_get_value(ctx, src, rid, obj)) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR, "failed to get value: rid = %u", rid);
+ }
+ rc = ctx->rc;
+ }
+ }
+ if (rc == GRN_SUCCESS) {
+ uint32_t sid = (uint32_t)(i + 1);
+ rc = grn_ii_builder_append_obj(ctx, builder, rid, sid, obj);
+ }
+ }
+ }
+ if (rc == GRN_SUCCESS && builder->n >= builder->options.block_threshold) {
+ rc = grn_ii_builder_flush_block(ctx, builder);
+ }
+ }
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ii_builder_flush_block(ctx, builder);
+ }
+ for (i = 0; i < builder->n_srcs; i++) {
+ GRN_OBJ_FIN(ctx, &objs[i]);
+ }
+ grn_table_cursor_close(ctx, cursor);
+ GRN_FREE(objs);
+ return rc;
+}
+
+/* grn_ii_builder_set_src_table sets a source table. */
+static grn_rc
+grn_ii_builder_set_src_table(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ builder->src_table = grn_ctx_at(ctx, DB_OBJ(builder->ii)->range);
+ if (!builder->src_table) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_INVALID_ARGUMENT, "source table is null: range = %d",
+ DB_OBJ(builder->ii)->range);
+ }
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_set_sid_bits calculates sid_bits and sid_mask. */
+static grn_rc
+grn_ii_builder_set_sid_bits(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ /* Calculate the number of bits required to represent a section ID. */
+ if (builder->n_srcs == 1 && builder->tokenizer &&
+ (builder->srcs[0]->header.flags & GRN_OBJ_COLUMN_VECTOR) != 0) {
+ /* If the source column is a vector column and the index has a tokenizer, */
+ /* the maximum sid equals to the maximum number of elements. */
+ size_t max_elems = 0;
+ grn_table_cursor *cursor;
+ grn_obj obj;
+ cursor = grn_table_cursor_open(ctx, builder->src_table, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_OBJECT_CORRUPT, "[index] failed to open table cursor");
+ }
+ return ctx->rc;
+ }
+ GRN_TEXT_INIT(&obj, 0);
+ for (;;) {
+ grn_id rid = grn_table_cursor_next(ctx, cursor);
+ if (rid == GRN_ID_NIL) {
+ break;
+ }
+ if (!grn_obj_get_value(ctx, builder->srcs[0], rid, &obj)) {
+ continue;
+ }
+ if (obj.u.v.n_sections > (int) max_elems) {
+ max_elems = obj.u.v.n_sections;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &obj);
+ grn_table_cursor_close(ctx, cursor);
+ while (((uint32_t)1 << builder->sid_bits) < max_elems) {
+ builder->sid_bits++;
+ }
+ }
+ if (builder->sid_bits == 0) {
+ while (((uint32_t)1 << builder->sid_bits) < builder->n_srcs) {
+ builder->sid_bits++;
+ }
+ }
+ builder->sid_mask = ((uint64_t)1 << builder->sid_bits) - 1;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_set_srcs sets source columns. */
+static grn_rc
+grn_ii_builder_set_srcs(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ size_t i;
+ grn_id *source;
+ builder->n_srcs = builder->ii->obj.source_size / sizeof(grn_id);
+ source = (grn_id *)builder->ii->obj.source;
+ if (!source || !builder->n_srcs) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "source is not available: source = %p, source_size = %u",
+ builder->ii->obj.source, builder->ii->obj.source_size);
+ return ctx->rc;
+ }
+ builder->srcs = GRN_MALLOCN(grn_obj *, builder->n_srcs);
+ if (!builder->srcs) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ for (i = 0; i < builder->n_srcs; i++) {
+ builder->srcs[i] = grn_ctx_at(ctx, source[i]);
+ if (!builder->srcs[i]) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_OBJECT_CORRUPT, "source not found: id = %d", source[i]);
+ }
+ return ctx->rc;
+ }
+ }
+ return grn_ii_builder_set_sid_bits(ctx, builder);
+}
+
+/* grn_ii_builder_append_source appends values in source columns. */
+static grn_rc
+grn_ii_builder_append_source(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_rc rc = grn_ii_builder_set_src_table(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (grn_table_size(ctx, builder->src_table) == 0) {
+ /* Nothing to do because there are no values. */
+ return ctx->rc;
+ }
+ /* Create a block lexicon. */
+ rc = grn_ii_builder_create_lexicon(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ii_builder_set_srcs(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ii_builder_append_srcs(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ grn_ii_builder_fin_terms(ctx, builder);
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ii_builder_fill_block reads the next data from a temporary file and fill
+ * a block buffer.
+ */
+static grn_rc
+grn_ii_builder_fill_block(grn_ctx *ctx, grn_ii_builder *builder,
+ uint32_t block_id)
+{
+ ssize_t size;
+ uint32_t buf_rest;
+ uint64_t file_offset;
+ grn_ii_builder_block *block = &builder->blocks[block_id];
+ if (!block->rest) {
+ return GRN_END_OF_DATA;
+ }
+ if (!block->buf) {
+ block->buf = (uint8_t *)GRN_MALLOC(builder->options.block_buf_size);
+ if (!block->buf) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for buffered input: size = %u",
+ builder->options.block_buf_size);
+ return ctx->rc;
+ }
+ }
+
+ /* Move the remaining data to the head. */
+ buf_rest = block->end - block->cur;
+ if (buf_rest) {
+ grn_memmove(block->buf, block->cur, buf_rest);
+ }
+ block->cur = block->buf;
+ block->end = block->buf + buf_rest;
+
+ /* Read the next data. */
+ file_offset = grn_lseek(builder->fd, block->offset, SEEK_SET);
+ if (file_offset != block->offset) {
+ SERR("failed to seek file: expected = %" GRN_FMT_INT64U
+ ", actual = %" GRN_FMT_INT64D,
+ block->offset, file_offset);
+ return ctx->rc;
+ }
+ buf_rest = builder->options.block_buf_size - buf_rest;
+ if (block->rest < buf_rest) {
+ buf_rest = block->rest;
+ }
+ size = grn_read(builder->fd, block->end, buf_rest);
+ if (size <= 0) {
+ SERR("failed to read data: expected = %u, actual = %" GRN_FMT_INT64D,
+ buf_rest, (int64_t)size);
+ return ctx->rc;
+ }
+ block->offset += size;
+ block->rest -= size;
+ block->end += size;
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_read_from_block reads the next value from a block. */
+static grn_rc
+grn_ii_builder_read_from_block(grn_ctx *ctx, grn_ii_builder *builder,
+ uint32_t block_id, uint64_t *value)
+{
+ grn_ii_builder_block *block = &builder->blocks[block_id];
+ grn_rc rc = grn_ii_builder_block_next(ctx, block, value);
+ if (rc == GRN_SUCCESS) {
+ return GRN_SUCCESS;
+ } else if (rc == GRN_END_OF_DATA) {
+ rc = grn_ii_builder_fill_block(ctx, builder, block_id);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ return grn_ii_builder_block_next(ctx, block, value);
+ }
+ return rc;
+}
+
+/* grn_ii_builder_pack_chunk tries to pack a chunk. */
+static grn_rc
+grn_ii_builder_pack_chunk(grn_ctx *ctx, grn_ii_builder *builder,
+ grn_bool *packed)
+{
+ grn_id rid;
+ uint32_t sid, pos, *a;
+ grn_ii_builder_chunk *chunk = &builder->chunk;
+ *packed = GRN_FALSE;
+ if (chunk->offset != 1) { /* df != 1 */
+ return GRN_SUCCESS;
+ }
+ if (chunk->weight_buf && chunk->weight_buf[0]) { /* weight != 0 */
+ return GRN_SUCCESS;
+ }
+ if (chunk->freq_buf[0] != 0) { /* freq != 1 */
+ return GRN_SUCCESS;
+ }
+ rid = chunk->rid_buf[0];
+ if (chunk->sid_buf) {
+ if (rid >= 0x100000) {
+ return GRN_SUCCESS;
+ }
+ sid = chunk->sid_buf[0] + 1;
+ if (sid >= 0x800) {
+ return GRN_SUCCESS;
+ }
+ a = array_get(ctx, builder->ii, chunk->tid);
+ if (!a) {
+ DEFINE_NAME(builder->ii);
+ MERR("[ii][builder][chunk][pack] failed to allocate an array: "
+ "<%.*s>: "
+ "<%u>:<%u>:<%u>",
+ name_size, name,
+ rid, sid, chunk->tid);
+ return ctx->rc;
+ }
+ a[0] = ((rid << 12) + (sid << 1)) | 1;
+ } else {
+ a = array_get(ctx, builder->ii, chunk->tid);
+ if (!a) {
+ DEFINE_NAME(builder->ii);
+ MERR("[ii][builder][chunk][pack] failed to allocate an array: "
+ "<%.*s>: "
+ "<%u>:<%u>",
+ name_size, name,
+ rid, chunk->tid);
+ return ctx->rc;
+ }
+ a[0] = (rid << 1) | 1;
+ }
+ pos = 0;
+ if (chunk->pos_buf) {
+ pos = chunk->pos_buf[0];
+ }
+ a[1] = pos;
+ array_unref(builder->ii, chunk->tid);
+ *packed = GRN_TRUE;
+
+ grn_ii_builder_chunk_clear(ctx, chunk);
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_get_cinfo returns a new cinfo. */
+static grn_rc
+grn_ii_builder_get_cinfo(grn_ctx *ctx, grn_ii_builder *builder,
+ chunk_info **cinfo)
+{
+ if (builder->n_cinfos == builder->cinfos_size) {
+ uint32_t size = builder->cinfos_size ? (builder->cinfos_size * 2) : 1;
+ size_t n_bytes = size * sizeof(chunk_info);
+ chunk_info *cinfos = (chunk_info *)GRN_REALLOC(builder->cinfos, n_bytes);
+ if (!cinfos) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate memory for cinfos: n_bytes = %" GRN_FMT_SIZE,
+ n_bytes);
+ return ctx->rc;
+ }
+ builder->cinfos = cinfos;
+ builder->cinfos_size = size;
+ }
+ *cinfo = &builder->cinfos[builder->n_cinfos++];
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_flush_chunk flushes a chunk. */
+static grn_rc
+grn_ii_builder_flush_chunk(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_rc rc;
+ chunk_info *cinfo = NULL;
+ grn_ii_builder_chunk *chunk = &builder->chunk;
+ void *seg;
+ uint8_t *in;
+ uint32_t in_size, chunk_id, seg_id, seg_offset, seg_rest;
+
+ rc = grn_ii_builder_chunk_encode(ctx, chunk, NULL, 0);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ in = chunk->enc_buf;
+ in_size = chunk->enc_offset;
+
+ rc = chunk_new(ctx, builder->ii, &chunk_id, chunk->enc_offset);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ /* Copy to the first segment. */
+ seg_id = chunk_id >> GRN_II_N_CHUNK_VARIATION;
+ seg_offset = (chunk_id & ((1 << GRN_II_N_CHUNK_VARIATION) - 1)) <<
+ GRN_II_W_LEAST_CHUNK;
+ GRN_IO_SEG_REF(builder->ii->chunk, seg_id, seg);
+ if (!seg) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR,
+ "failed access chunk segment: chunk_id = %u, seg_id = %u",
+ chunk_id, seg_id);
+ }
+ return ctx->rc;
+ }
+ seg_rest = S_CHUNK - seg_offset;
+ if (in_size <= seg_rest) {
+ grn_memcpy((uint8_t *)seg + seg_offset, in, in_size);
+ in_size = 0;
+ } else {
+ grn_memcpy((uint8_t *)seg + seg_offset, in, seg_rest);
+ in += seg_rest;
+ in_size -= seg_rest;
+ }
+ GRN_IO_SEG_UNREF(builder->ii->chunk, seg_id);
+
+ /* Copy to the next segments. */
+ while (in_size) {
+ seg_id++;
+ GRN_IO_SEG_REF(builder->ii->chunk, seg_id, seg);
+ if (!seg) {
+ if (ctx->rc == GRN_SUCCESS) {
+ ERR(GRN_UNKNOWN_ERROR,
+ "failed access chunk segment: chunk_id = %u, seg_id = %u",
+ chunk_id, seg_id);
+ }
+ return ctx->rc;
+ }
+ if (in_size <= S_CHUNK) {
+ grn_memcpy(seg, in, in_size);
+ in_size = 0;
+ } else {
+ grn_memcpy(seg, in, S_CHUNK);
+ in += S_CHUNK;
+ in_size -= S_CHUNK;
+ }
+ GRN_IO_SEG_UNREF(builder->ii->chunk, seg_id);
+ }
+
+ /* Append a cinfo. */
+ rc = grn_ii_builder_get_cinfo(ctx, builder, &cinfo);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ cinfo->segno = chunk_id;
+ cinfo->size = chunk->enc_offset;
+ cinfo->dgap = chunk->rid_gap;
+
+ builder->buf.ii->header->total_chunk_size += chunk->enc_offset;
+ grn_ii_builder_chunk_clear(ctx, chunk);
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_read_to_chunk read values from a block to a chunk. */
+static grn_rc
+grn_ii_builder_read_to_chunk(grn_ctx *ctx, grn_ii_builder *builder,
+ uint32_t block_id)
+{
+ grn_rc rc;
+ uint64_t value;
+ uint32_t rid = GRN_ID_NIL, last_sid = 0;
+ uint32_t ii_flags = builder->ii->header->flags;
+ grn_ii_builder_chunk *chunk = &builder->chunk;
+
+ for (;;) {
+ uint32_t gap, freq;
+ uint64_t value;
+ rc = grn_ii_builder_read_from_block(ctx, builder, block_id, &value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (!value) {
+ break;
+ }
+ if (builder->chunk.offset == builder->chunk.size) {
+ rc = grn_ii_builder_chunk_extend_bufs(ctx, chunk, ii_flags);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+
+ /* Read record ID. */
+ gap = value >> builder->sid_bits; /* In-block gap */
+ if (gap) {
+ if (chunk->n >= builder->options.chunk_threshold) {
+ rc = grn_ii_builder_flush_chunk(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ last_sid = 0;
+ }
+ rid += gap;
+ gap = rid - chunk->rid; /* Global gap */
+ chunk->rid_buf[chunk->offset] = chunk->offset ? gap : rid;
+ chunk->n++;
+ chunk->rid = rid;
+ chunk->rid_gap += gap;
+ builder->df++;
+
+ /* Read section ID. */
+ if (ii_flags & GRN_OBJ_WITH_SECTION) {
+ uint32_t sid = (value & builder->sid_mask) + 1;
+ chunk->sid_buf[chunk->offset] = sid - last_sid - 1;
+ chunk->n++;
+ last_sid = sid;
+ }
+
+ /* Read weight. */
+ if (ii_flags & GRN_OBJ_WITH_WEIGHT) {
+ uint32_t weight;
+ rc = grn_ii_builder_read_from_block(ctx, builder, block_id, &value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ weight = value;
+ chunk->weight_buf[chunk->offset] = weight;
+ chunk->n++;
+ }
+
+ /* Read positions or a frequency. */
+ if (ii_flags & GRN_OBJ_WITH_POSITION) {
+ uint32_t pos = (uint32_t) -1;
+ freq = 0;
+ for (;;) {
+ rc = grn_ii_builder_read_from_block(ctx, builder, block_id, &value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (!value) {
+ break;
+ }
+ if (builder->chunk.pos_offset == builder->chunk.pos_size) {
+ rc = grn_ii_builder_chunk_extend_pos_buf(ctx, chunk);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (pos == (uint32_t) -1) {
+ chunk->pos_buf[chunk->pos_offset] = value - 1;
+ chunk->pos_sum += value - 1;
+ } else {
+ chunk->pos_buf[chunk->pos_offset] = value;
+ chunk->pos_sum += value;
+ }
+ chunk->n++;
+ pos += value;
+ chunk->pos_offset++;
+ freq++;
+ }
+ } else {
+ rc = grn_ii_builder_read_from_block(ctx, builder, block_id, &value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ freq = value;
+ }
+ chunk->freq_buf[chunk->offset] = freq - 1;
+ chunk->n++;
+ chunk->offset++;
+ }
+ rc = grn_ii_builder_read_from_block(ctx, builder, block_id, &value);
+ if (rc == GRN_SUCCESS) {
+ builder->blocks[block_id].tid = value;
+ } else if (rc == GRN_END_OF_DATA) {
+ builder->blocks[block_id].tid = GRN_ID_NIL;
+ } else {
+ return rc;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ii_builder_register_chunks registers chunks. */
+static grn_rc
+grn_ii_builder_register_chunks(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ grn_rc rc;
+ uint32_t buf_tid, *a;
+ buffer_term *buf_term;
+
+ rc = grn_ii_builder_chunk_encode(ctx, &builder->chunk, builder->cinfos,
+ builder->n_cinfos);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+
+ if (!grn_ii_builder_buffer_is_assigned(ctx, &builder->buf)) {
+ rc = grn_ii_builder_buffer_assign(ctx, &builder->buf,
+ builder->chunk.enc_offset);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ buf_tid = builder->buf.buf->header.nterms;
+ if (buf_tid >= builder->options.buffer_max_n_terms ||
+ builder->buf.chunk_size - builder->buf.chunk_offset <
+ builder->chunk.enc_offset) {
+ rc = grn_ii_builder_buffer_flush(ctx, &builder->buf);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ii_builder_buffer_assign(ctx, &builder->buf,
+ builder->chunk.enc_offset);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_tid = 0;
+ }
+ buf_term = &builder->buf.buf->terms[buf_tid];
+ buf_term->tid = builder->chunk.tid;
+ if (builder->n_cinfos) {
+ buf_term->tid |= CHUNK_SPLIT;
+ }
+ buf_term->size_in_buffer = 0;
+ buf_term->pos_in_buffer = 0;
+ buf_term->size_in_chunk = builder->chunk.enc_offset;
+ buf_term->pos_in_chunk = builder->buf.chunk_offset;
+
+ grn_memcpy(builder->buf.chunk + builder->buf.chunk_offset,
+ builder->chunk.enc_buf, builder->chunk.enc_offset);
+ builder->buf.chunk_offset += builder->chunk.enc_offset;
+
+ a = array_get(ctx, builder->ii, builder->chunk.tid);
+ if (!a) {
+ DEFINE_NAME(builder->ii);
+ MERR("[ii][builder][chunk][register] "
+ "failed to allocate an array in segment: "
+ "<%.*s>: "
+ "tid=<%u>: max_n_segments=<%u>",
+ name_size, name,
+ builder->chunk.tid,
+ builder->ii->seg->header->max_segment);
+ return ctx->rc;
+ }
+ a[0] = SEG2POS(builder->buf.buf_id,
+ sizeof(buffer_header) + buf_tid * sizeof(buffer_term));
+ a[1] = builder->df;
+ array_unref(builder->ii, builder->chunk.tid);
+
+ builder->buf.buf->header.nterms++;
+ builder->n_cinfos = 0;
+ grn_ii_builder_chunk_clear(ctx, &builder->chunk);
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_ii_builder_commit(grn_ctx *ctx, grn_ii_builder *builder)
+{
+ uint32_t i;
+ grn_rc rc;
+ grn_table_cursor *cursor;
+
+ for (i = 0; i < builder->n_blocks; i++) {
+ uint64_t value;
+ rc = grn_ii_builder_read_from_block(ctx, builder, i, &value);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->blocks[i].tid = value;
+ }
+
+ cursor = grn_table_cursor_open(ctx, builder->ii->lexicon,
+ NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_BY_KEY);
+ for (;;) {
+ grn_id tid = grn_table_cursor_next(ctx, cursor);
+ if (tid == GRN_ID_NIL) {
+ break;
+ }
+ builder->chunk.tid = tid;
+ builder->chunk.rid = GRN_ID_NIL;
+ builder->df = 0;
+ for (i = 0; i < builder->n_blocks; i++) {
+ if (tid == builder->blocks[i].tid) {
+ rc = grn_ii_builder_read_to_chunk(ctx, builder, i);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ if (!builder->chunk.n) {
+ /* This term does not appear. */
+ continue;
+ }
+ if (!builder->n_cinfos) {
+ grn_bool packed;
+ rc = grn_ii_builder_pack_chunk(ctx, builder, &packed);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (packed) {
+ continue;
+ }
+ }
+ rc = grn_ii_builder_register_chunks(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ if (grn_ii_builder_buffer_is_assigned(ctx, &builder->buf)) {
+ rc = grn_ii_builder_buffer_flush(ctx, &builder->buf);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ii_build2(grn_ctx *ctx, grn_ii *ii, const grn_ii_builder_options *options)
+{
+ grn_rc rc, rc_close;
+ grn_ii_builder *builder;
+ rc = grn_ii_builder_open(ctx, ii, options, &builder);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ii_builder_append_source(ctx, builder);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ii_builder_commit(ctx, builder);
+ }
+ rc_close = grn_ii_builder_close(ctx, builder);
+ if (rc == GRN_SUCCESS) {
+ rc = rc_close;
+ }
+ }
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/index_column.c b/storage/mroonga/vendor/groonga/lib/index_column.c
new file mode 100644
index 00000000..b5d4fde8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/index_column.c
@@ -0,0 +1,195 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_index_column.h"
+#include "grn_ii.h"
+#include "grn_hash.h"
+
+#include <string.h>
+
+static uint64_t grn_index_sparsity = 10;
+static grn_bool grn_index_chunk_split_enable = GRN_TRUE;
+
+void
+grn_index_column_init_from_env(void)
+{
+ {
+ char grn_index_sparsity_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_INDEX_SPARSITY",
+ grn_index_sparsity_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_index_sparsity_env[0]) {
+ uint64_t sparsity;
+ errno = 0;
+ sparsity = strtoull(grn_index_sparsity_env, NULL, 0);
+ if (errno == 0) {
+ grn_index_sparsity = sparsity;
+ }
+ }
+ }
+
+ {
+ char grn_index_chunk_split_enable_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_INDEX_CHUNK_SPLIT_ENABLE",
+ grn_index_chunk_split_enable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (strcmp(grn_index_chunk_split_enable_env, "no") == 0) {
+ grn_index_chunk_split_enable = GRN_FALSE;
+ } else {
+ grn_index_chunk_split_enable = GRN_TRUE;
+ }
+ }
+}
+
+inline static void
+grn_index_column_build_call_hook(grn_ctx *ctx, grn_obj *obj,
+ grn_id id, grn_obj *value, int flags)
+{
+ grn_hook *hooks = DB_OBJ(obj)->hooks[GRN_HOOK_SET];
+
+ if (hooks) {
+ grn_obj oldvalue;
+ /* todo : grn_proc_ctx_open() */
+ grn_obj id_, flags_;
+ grn_proc_ctx pctx = {{0}, hooks->proc, NULL, hooks, hooks, PROC_INIT, 4, 4,
+ {{0}}};
+ GRN_TEXT_INIT(&oldvalue, 0);
+ GRN_UINT32_INIT(&id_, 0);
+ GRN_UINT32_INIT(&flags_, 0);
+ GRN_UINT32_SET(ctx, &id_, id);
+ GRN_UINT32_SET(ctx, &flags_, flags);
+ while (hooks) {
+ grn_ctx_push(ctx, &id_);
+ grn_ctx_push(ctx, &oldvalue);
+ grn_ctx_push(ctx, value);
+ grn_ctx_push(ctx, &flags_);
+ pctx.caller = NULL;
+ pctx.currh = hooks;
+ if (hooks->proc) {
+ hooks->proc->funcs[PROC_INIT](ctx, 1, &obj, &pctx.user_data);
+ } else {
+ grn_obj_default_set_value_hook(ctx, 1, &obj, &pctx.user_data);
+ }
+ if (ctx->rc) {
+ grn_obj_close(ctx, &oldvalue);
+ return;
+ }
+ hooks = hooks->next;
+ pctx.offset++;
+ }
+ grn_obj_close(ctx, &oldvalue);
+ }
+}
+
+grn_rc
+grn_index_column_build(grn_ctx *ctx, grn_obj *index_column)
+{
+ grn_obj *src, **cp, **col, *target;
+ grn_id *s = DB_OBJ(index_column)->source;
+ if (!(DB_OBJ(index_column)->source_size) || !s) { return ctx->rc; }
+ if ((src = grn_ctx_at(ctx, *s))) {
+ target = GRN_OBJ_TABLEP(src) ? src : grn_ctx_at(ctx, src->header.domain);
+ if (target) {
+ int i, ncol = DB_OBJ(index_column)->source_size / sizeof(grn_id);
+ grn_table_flags flags;
+ grn_ii *ii = (grn_ii *)index_column;
+ grn_bool use_grn_ii_build;
+ grn_obj *tokenizer = NULL;
+ grn_table_get_info(ctx, ii->lexicon, &flags, NULL, &tokenizer, NULL, NULL);
+ switch (flags & GRN_OBJ_TABLE_TYPE_MASK) {
+ case GRN_OBJ_TABLE_PAT_KEY :
+ case GRN_OBJ_TABLE_DAT_KEY :
+ use_grn_ii_build = GRN_TRUE;
+ break;
+ default :
+ use_grn_ii_build = GRN_FALSE;
+ break;
+ }
+ if ((ii->header->flags & GRN_OBJ_WITH_WEIGHT)) {
+ use_grn_ii_build = GRN_FALSE;
+ }
+ if ((ii->header->flags & GRN_OBJ_WITH_POSITION) &&
+ (!tokenizer &&
+ !GRN_TYPE_IS_TEXT_FAMILY(ii->lexicon->header.domain))) {
+ /* TODO: Support offline index construction for WITH_POSITION
+ * index against UInt32 vector column. */
+ use_grn_ii_build = GRN_FALSE;
+ }
+ if ((col = GRN_MALLOC(ncol * sizeof(grn_obj *)))) {
+ for (cp = col, i = ncol; i; s++, cp++, i--) {
+ if (!(*cp = grn_ctx_at(ctx, *s))) {
+ ERR(GRN_INVALID_ARGUMENT, "source invalid, n=%d",i);
+ GRN_FREE(col);
+ return ctx->rc;
+ }
+ if (GRN_OBJ_TABLEP(grn_ctx_at(ctx, DB_OBJ(*cp)->range))) {
+ use_grn_ii_build = GRN_FALSE;
+ }
+ }
+ if (use_grn_ii_build) {
+ if (grn_index_chunk_split_enable) {
+ grn_ii_build2(ctx, ii, NULL);
+ } else {
+ grn_ii_build(ctx, ii, grn_index_sparsity);
+ }
+ } else {
+ grn_table_cursor *tc;
+ if ((tc = grn_table_cursor_open(ctx, target, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_BY_ID))) {
+ grn_id id;
+ grn_obj rv;
+ GRN_TEXT_INIT(&rv, 0);
+ while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ for (cp = col, i = ncol; i; i--, cp++) {
+ GRN_BULK_REWIND(&rv);
+ if (GRN_OBJ_TABLEP(*cp)) {
+ grn_table_get_key2(ctx, *cp, id, &rv);
+ } else {
+ grn_obj_get_value(ctx, *cp, id, &rv);
+ }
+ grn_index_column_build_call_hook(ctx, *cp, id, &rv, 0);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &rv);
+ grn_table_cursor_close(ctx, tc);
+ }
+ }
+ GRN_FREE(col);
+ grn_obj_touch(ctx, index_column, NULL);
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "invalid target");
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "invalid source");
+ }
+ return ctx->rc;
+}
+
+grn_rc
+grn_index_column_rebuild(grn_ctx *ctx, grn_obj *index_column)
+{
+ grn_ii *ii = (grn_ii *)index_column;
+
+ GRN_API_ENTER;
+
+ grn_ii_truncate(ctx, ii);
+ grn_index_column_build(ctx, index_column);
+
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/io.c b/storage/mroonga/vendor/groonga/lib/io.c
new file mode 100644
index 00000000..2f59b874
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/io.c
@@ -0,0 +1,2201 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include "grn_ctx.h"
+#include "grn_io.h"
+#include "grn_plugin.h"
+#include "grn_hash.h"
+#include "grn_ctx_impl.h"
+#include "grn_util.h"
+
+#ifdef WIN32
+# include <io.h>
+# include <share.h>
+#endif /* WIN32 */
+
+#define GRN_IO_IDSTR "GROONGA:IO:00001"
+#define GRN_IO_IDSTR_LEN (sizeof(GRN_IO_IDSTR) - 1)
+
+#define GRN_IO_VERSION_DEFAULT 1
+
+#define GRN_IO_FILE_SIZE_V1 1073741824UL
+
+#ifdef WIN32
+# define GRN_IO_FILE_SIZE_V0 134217728L
+#else /* WIN32 */
+# define GRN_IO_FILE_SIZE_V0 GRN_IO_FILE_SIZE_V1
+#endif /* WIN32 */
+
+typedef struct _grn_io_fileinfo {
+#ifdef WIN32
+ HANDLE fh;
+ HANDLE fmo;
+ grn_critical_section cs;
+#else /* WIN32 */
+ int fd;
+ dev_t dev;
+ ino_t inode;
+#endif /* WIN32 */
+} fileinfo;
+
+#define IO_HEADER_SIZE 64
+
+static uint32_t grn_io_version_default = GRN_IO_VERSION_DEFAULT;
+static grn_bool grn_io_use_sparse = GRN_FALSE;
+
+inline static grn_rc grn_fileinfo_open(grn_ctx *ctx, fileinfo *fi,
+ const char *path, int flags);
+inline static void grn_fileinfo_init(fileinfo *fis, int nfis);
+inline static int grn_fileinfo_opened(fileinfo *fi);
+inline static grn_rc grn_fileinfo_close(grn_ctx *ctx, fileinfo *fi);
+#ifdef WIN32
+inline static void * grn_mmap(grn_ctx *ctx, grn_ctx *owner_ctx,
+ grn_io *io, HANDLE *fmo, fileinfo *fi,
+ off_t offset, size_t length);
+inline static int grn_munmap(grn_ctx *ctx, grn_ctx *owner_ctx,
+ grn_io *io, HANDLE *fmo, fileinfo *fi,
+ void *start, size_t length);
+inline static int grn_msync(grn_ctx *ctx, HANDLE fh,
+ void *start, size_t length);
+# define GRN_MMAP(ctx,owner_ctx,io,fmo,fi,offset,length)\
+ (grn_mmap((ctx), (owner_ctx), (io), (fmo), (fi), (offset), (length)))
+# define GRN_MUNMAP(ctx,owner_ctx,io,fmo,fi,start,length)\
+ (grn_munmap((ctx), (owner_ctx), (io), (fmo), (fi), (start), (length)))
+# define GRN_MSYNC(ctx,fh,start,length) \
+ (grn_msync((ctx), (fh), (start), (length)))
+#else /* WIN32 */
+inline static void * grn_mmap(grn_ctx *ctx, grn_ctx *owner_ctx,
+ grn_io *io, fileinfo *fi,
+ off_t offset, size_t length);
+inline static int grn_munmap(grn_ctx *ctx, grn_ctx *owner_ctx,
+ grn_io *io, fileinfo *fi,
+ void *start, size_t length);
+inline static int grn_msync(grn_ctx *ctx, void *start, size_t length);
+# define GRN_MUNMAP(ctx,owner_ctx,io,fmo,fi,start,length) \
+ (grn_munmap((ctx), (owner_ctx), (io), (fi), (start), (length)))
+# define GRN_MSYNC(ctx,fh,start,length) \
+ (grn_msync((ctx), (start), (length)))
+# ifdef USE_FAIL_MALLOC
+inline static void * grn_fail_mmap(grn_ctx *ctx, grn_ctx *owner_ctx,
+ grn_io *io, fileinfo *fi,
+ off_t offset, size_t length,
+ const char* file, int line, const char *func);
+# define GRN_MMAP(ctx,owner_ctx,io,fmo,fi,offset,length)\
+ (grn_fail_mmap((ctx), (owner_ctx), (io), (fi), (offset), (length),\
+ __FILE__, __LINE__, __FUNCTION__))
+# else /* USE_FAIL_MALLOC */
+# define GRN_MMAP(ctx,owner_ctx,io,fmo,fi,offset,length)\
+ (grn_mmap((ctx), (owner_ctx), (io), (fi), (offset), (length)))
+# endif /* USE_FAIL_MALLOC */
+#endif /* WIN32 */
+inline static grn_rc grn_pread(grn_ctx *ctx, fileinfo *fi, void *buf,
+ size_t count, off_t offset);
+inline static grn_rc grn_pwrite(grn_ctx *ctx, fileinfo *fi, void *buf,
+ size_t count, off_t offset);
+
+void
+grn_io_init_from_env(void)
+{
+ {
+ char version_env[GRN_ENV_BUFFER_SIZE];
+
+ grn_getenv("GRN_IO_VERSION",
+ version_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (version_env[0]) {
+ grn_io_version_default = atoi(version_env);
+ }
+ }
+
+ {
+ char use_sparse_env[GRN_ENV_BUFFER_SIZE];
+
+ grn_getenv("GRN_IO_USE_SPARSE",
+ use_sparse_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (use_sparse_env[0] && strcmp(use_sparse_env, "yes") == 0) {
+ grn_io_use_sparse = GRN_TRUE;
+ }
+ }
+}
+
+static inline uint32_t
+grn_io_compute_base(uint32_t header_size)
+{
+ uint32_t total_header_size;
+ total_header_size = IO_HEADER_SIZE + header_size;
+ return (total_header_size + grn_pagesize - 1) & ~(grn_pagesize - 1);
+}
+
+static inline uint32_t
+grn_io_compute_base_segment(uint32_t base, uint32_t segment_size)
+{
+ return (base + segment_size - 1) / segment_size;
+}
+
+static uint32_t
+grn_io_compute_max_n_files(uint32_t segment_size, uint32_t max_segment,
+ unsigned int base_segument, unsigned long file_size)
+{
+ uint64_t last_segment_end;
+ last_segment_end = ((uint64_t)segment_size) * (max_segment + base_segument);
+ return (uint32_t)((last_segment_end + file_size - 1) / file_size);
+}
+
+static inline unsigned long
+grn_io_compute_file_size(uint32_t version)
+{
+ if (version == 0) {
+ return GRN_IO_FILE_SIZE_V0;
+ } else {
+ return GRN_IO_FILE_SIZE_V1;
+ }
+}
+
+static inline uint32_t
+grn_io_max_segment(grn_io *io)
+{
+ if (io->header->segment_tail) {
+ return io->header->segment_tail;
+ } else {
+ return io->header->max_segment;
+ }
+}
+
+static uint32_t
+grn_io_max_n_files(grn_io *io)
+{
+ unsigned long file_size;
+
+ file_size = grn_io_compute_file_size(io->header->version);
+ return grn_io_compute_max_n_files(io->header->segment_size,
+ grn_io_max_segment(io),
+ io->base_seg,
+ file_size);
+}
+
+static inline uint32_t
+grn_io_compute_nth_file_info(grn_io *io, uint32_t nth_segment)
+{
+ uint32_t segment_size;
+ unsigned long file_size;
+ uint32_t segments_per_file;
+ uint32_t resolved_nth_segment;
+
+ segment_size = io->header->segment_size;
+ file_size = grn_io_compute_file_size(io->header->version);
+ segments_per_file = file_size / segment_size;
+ resolved_nth_segment = nth_segment + io->base_seg;
+ return resolved_nth_segment / segments_per_file;
+}
+
+static grn_io *
+grn_io_create_tmp(grn_ctx *ctx, uint32_t header_size, uint32_t segment_size,
+ uint32_t max_segment, grn_io_mode mode, uint32_t flags)
+{
+ grn_io *io;
+ uint32_t b;
+ struct _grn_io_header *header;
+ b = grn_io_compute_base(header_size);
+ header = (struct _grn_io_header *)GRN_MMAP(ctx, &grn_gctx, NULL, NULL, NULL,
+ 0, b);
+ if (header) {
+ header->version = grn_io_version_default;
+ header->header_size = header_size;
+ header->segment_size = segment_size;
+ header->max_segment = max_segment;
+ header->n_arrays = 0;
+ header->flags = flags;
+ header->lock = 0;
+ grn_memcpy(header->idstr, GRN_IO_IDSTR, 16);
+ if ((io = GRN_MALLOCN(grn_io, 1))) {
+ grn_io_mapinfo *maps = NULL;
+ if ((maps = GRN_CALLOC(sizeof(grn_io_mapinfo) * max_segment))) {
+ io->header = header;
+ io->user_header = (((byte *) header) + IO_HEADER_SIZE);
+ io->maps = maps;
+ io->base = b;
+ io->base_seg = 0;
+ io->mode = mode;
+ io->header->curr_size = b;
+ io->fis = NULL;
+ io->ainfo = NULL;
+ io->max_map_seg = 0;
+ io->nmaps = 0;
+ io->count = 0;
+ io->flags = GRN_IO_TEMPORARY;
+ io->lock = &header->lock;
+ io->path[0] = '\0';
+ return io;
+ }
+ GRN_FREE(io);
+ }
+ GRN_MUNMAP(ctx, &grn_gctx, NULL, NULL, NULL, header, b);
+ }
+ return NULL;
+}
+
+static void
+grn_io_register(grn_ctx *ctx, grn_io *io)
+{
+ if (io->fis && (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {
+ grn_bool succeeded = GRN_FALSE;
+ CRITICAL_SECTION_ENTER(grn_glock);
+ if (grn_gctx.impl && grn_gctx.impl->ios &&
+ grn_hash_add(&grn_gctx, grn_gctx.impl->ios, io->path, strlen(io->path),
+ (void **)&io, NULL)) {
+ succeeded = GRN_TRUE;
+ }
+ CRITICAL_SECTION_LEAVE(grn_glock);
+ if (!succeeded) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "grn_io_register(%s) failed", io->path);
+ }
+ }
+}
+
+static void
+grn_io_unregister(grn_ctx *ctx, grn_io *io)
+{
+ if (io->fis && (io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {
+ grn_bool succeeded = GRN_FALSE;
+ CRITICAL_SECTION_ENTER(grn_glock);
+ if (grn_gctx.impl && grn_gctx.impl->ios) {
+ grn_hash_delete(&grn_gctx, grn_gctx.impl->ios,
+ io->path, strlen(io->path), NULL);
+ succeeded = GRN_TRUE;
+ }
+ CRITICAL_SECTION_LEAVE(grn_glock);
+ if (!succeeded) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "grn_io_unregister(%s) failed", io->path);
+ }
+ }
+}
+
+grn_io *
+grn_io_create(grn_ctx *ctx, const char *path, uint32_t header_size,
+ uint32_t segment_size, uint32_t max_segment, grn_io_mode mode,
+ uint32_t flags)
+{
+ grn_io *io;
+ fileinfo *fis;
+ uint32_t b, max_nfiles;
+ uint32_t bs;
+ struct _grn_io_header *header;
+ uint32_t version = grn_io_version_default;
+ unsigned long file_size;
+
+ if (!path) {
+ return grn_io_create_tmp(ctx, header_size, segment_size, max_segment,
+ mode, flags);
+ }
+ if (!*path || (strlen(path) > PATH_MAX - 4)) { return NULL; }
+ b = grn_io_compute_base(header_size);
+ bs = grn_io_compute_base_segment(b, segment_size);
+ file_size = grn_io_compute_file_size(version);
+ max_nfiles = grn_io_compute_max_n_files(segment_size, max_segment,
+ bs, file_size);
+ if ((fis = GRN_MALLOCN(fileinfo, max_nfiles))) {
+ grn_fileinfo_init(fis, max_nfiles);
+ if (!grn_fileinfo_open(ctx, fis, path, O_RDWR|O_CREAT|O_EXCL)) {
+ header = (struct _grn_io_header *)GRN_MMAP(ctx, &grn_gctx, NULL,
+ &fis->fmo, fis, 0, b);
+ if (header) {
+ header->version = version;
+ header->header_size = header_size;
+ header->segment_size = segment_size;
+ header->max_segment = max_segment;
+ header->n_arrays = 0;
+ header->flags = flags;
+ header->lock = 0;
+ grn_memcpy(header->idstr, GRN_IO_IDSTR, 16);
+ GRN_MSYNC(ctx, fis[0].fh, header, b);
+ if ((io = GRN_MALLOCN(grn_io, 1))) {
+ grn_io_mapinfo *maps = NULL;
+ if ((maps = GRN_CALLOC(sizeof(grn_io_mapinfo) * max_segment))) {
+ grn_strncpy(io->path, PATH_MAX-1, path, PATH_MAX-1);
+ io->header = header;
+ io->user_header = (((byte *) header) + IO_HEADER_SIZE);
+ io->maps = maps;
+ io->base = b;
+ io->base_seg = bs;
+ io->mode = mode;
+ io->header->curr_size = b;
+ io->fis = fis;
+ io->ainfo = NULL;
+ io->max_map_seg = 0;
+ io->nmaps = 0;
+ io->count = 0;
+ io->flags = flags;
+ io->lock = &header->lock;
+ grn_io_register(ctx, io);
+ return io;
+ }
+ GRN_FREE(io);
+ }
+ GRN_MUNMAP(ctx, &grn_gctx, NULL, &fis->fmo, fis, header, b);
+ }
+ grn_fileinfo_close(ctx, fis);
+ if (grn_unlink(path) == 0) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][create][error] removed path: <%s>", path);
+ } else {
+ ERRNO_ERR("[io][create][error] failed to remove path: <%s>", path);
+ }
+ }
+ GRN_FREE(fis);
+ }
+ return NULL;
+}
+
+static grn_rc
+array_init_(grn_ctx *ctx, grn_io *io, int n_arrays, size_t hsize, size_t msize)
+{
+ int i;
+ uint32_t ws;
+ byte *hp, *mp;
+ grn_io_array_spec *array_specs = (grn_io_array_spec *)io->user_header;
+ hp = io->user_header;
+ if (!(mp = GRN_CALLOC(msize))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ io->ainfo = (grn_io_array_info *)mp;
+ hp += sizeof(grn_io_array_spec) * n_arrays;
+ mp += sizeof(grn_io_array_info) * n_arrays;
+ for (ws = 0; (1 << ws) < io->header->segment_size; ws++);
+ for (i = 0; i < n_arrays; i++) {
+ uint32_t we = ws - array_specs[i].w_of_element;
+ io->ainfo[i].w_of_elm_in_a_segment = we;
+ io->ainfo[i].elm_mask_in_a_segment = (1 << we) - 1;
+ io->ainfo[i].max_n_segments = array_specs[i].max_n_segments;
+ io->ainfo[i].element_size = 1 << array_specs[i].w_of_element;
+ io->ainfo[i].segments = (uint32_t *)hp;
+ io->ainfo[i].addrs = (void **)mp;
+ hp += sizeof(uint32_t) * array_specs[i].max_n_segments;
+ mp += sizeof(void *) * array_specs[i].max_n_segments;
+ }
+ io->user_header += hsize;
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+array_init(grn_ctx *ctx, grn_io *io, int n_arrays)
+{
+ if (n_arrays) {
+ int i;
+ grn_io_array_spec *array_specs = (grn_io_array_spec *)io->user_header;
+ size_t hsize = sizeof(grn_io_array_spec) * n_arrays;
+ size_t msize = sizeof(grn_io_array_info) * n_arrays;
+ for (i = 0; i < n_arrays; i++) {
+ hsize += sizeof(uint32_t) * array_specs[i].max_n_segments;
+ msize += sizeof(void *) * array_specs[i].max_n_segments;
+ }
+ return array_init_(ctx, io, n_arrays, hsize, msize);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_io *
+grn_io_create_with_array(grn_ctx *ctx, const char *path,
+ uint32_t header_size, uint32_t segment_size,
+ grn_io_mode mode, int n_arrays,
+ grn_io_array_spec *array_specs)
+{
+ if (n_arrays) {
+ int i;
+ grn_io *io;
+ byte *hp;
+ uint32_t nsegs = 0;
+ size_t hsize = sizeof(grn_io_array_spec) * n_arrays;
+ size_t msize = sizeof(grn_io_array_info) * n_arrays;
+ for (i = 0; i < n_arrays; i++) {
+ nsegs += array_specs[i].max_n_segments;
+ hsize += sizeof(uint32_t) * array_specs[i].max_n_segments;
+ msize += sizeof(void *) * array_specs[i].max_n_segments;
+ }
+ if ((io = grn_io_create(ctx, path, header_size + hsize,
+ segment_size, nsegs, mode, GRN_IO_EXPIRE_GTICK))) {
+ grn_rc rc;
+ hp = io->user_header;
+ grn_memcpy(hp, array_specs, sizeof(grn_io_array_spec) * n_arrays);
+ io->header->n_arrays = n_arrays;
+ io->header->segment_tail = 1;
+ rc = array_init_(ctx, io, n_arrays, hsize, msize);
+ if (rc == GRN_SUCCESS) {
+ return io;
+ }
+ ERR(GRN_NO_MEMORY_AVAILABLE, "grn_io_create_with_array failed");
+ grn_io_close(ctx, io);
+ }
+ }
+ return NULL;
+}
+
+inline static uint32_t
+segment_alloc(grn_ctx *ctx, grn_io *io)
+{
+ uint32_t n, s;
+ grn_io_array_info *ai;
+ if (io->header->segment_tail) {
+ if (io->header->segment_tail > io->header->max_segment) {
+ s = 0;
+ } else {
+ s = io->header->segment_tail++;
+ }
+ } else {
+ char *used = GRN_CALLOC(io->header->max_segment + 1);
+ if (!used) { return 0; }
+ for (n = io->header->n_arrays, ai = io->ainfo; n; n--, ai++) {
+ for (s = 0; s < ai->max_n_segments; s++) {
+ used[ai->segments[s]] = 1;
+ }
+ }
+ for (s = 1; ; s++) {
+ if (s > io->header->max_segment) {
+ io->header->segment_tail = s;
+ s = 0;
+ break;
+ }
+ if (!used[s]) {
+ io->header->segment_tail = s + 1;
+ break;
+ }
+ }
+ GRN_FREE(used);
+ }
+ return s;
+}
+
+void
+grn_io_segment_alloc(grn_ctx *ctx, grn_io *io, grn_io_array_info *ai,
+ uint32_t lseg, int *flags, void **p)
+{
+ uint32_t *sp = &ai->segments[lseg];
+ if (!*sp) {
+ if ((*flags & GRN_TABLE_ADD)) {
+ if ((*sp = segment_alloc(ctx, io))) {
+ *flags |= GRN_TABLE_ADDED;
+ }
+ }
+ }
+ if (*sp) {
+ uint32_t pseg = *sp - 1;
+ GRN_IO_SEG_REF(io, pseg, *p);
+ if (*p) { GRN_IO_SEG_UNREF(io, pseg); };
+ }
+}
+
+void *
+grn_io_array_at(grn_ctx *ctx, grn_io *io, uint32_t array, off_t offset, int *flags)
+{
+ void *res;
+ GRN_IO_ARRAY_AT(io,array,offset,flags,res);
+ return res;
+}
+
+uint32_t
+grn_io_detect_type(grn_ctx *ctx, const char *path)
+{
+ struct _grn_io_header h;
+ uint32_t res = 0;
+ int fd;
+ grn_open(fd, path, O_RDONLY | GRN_OPEN_FLAG_BINARY);
+ if (fd != -1) {
+ struct stat s;
+ if (fstat(fd, &s) != -1 && (size_t) s.st_size >= sizeof(struct _grn_io_header)) {
+ if (grn_read(fd, &h, sizeof(struct _grn_io_header)) ==
+ sizeof(struct _grn_io_header)) {
+ if (!memcmp(h.idstr, GRN_IO_IDSTR, GRN_IO_IDSTR_LEN)) {
+ res = h.type;
+ } else {
+ ERR(GRN_INCOMPATIBLE_FILE_FORMAT,
+ "failed to detect type: format ID is different: <%s>: <%.*s>",
+ path,
+ (int)GRN_IO_IDSTR_LEN, GRN_IO_IDSTR);
+ }
+ } else {
+ SERR("failed to read enough data for detecting type: <%s>",
+ path);
+ }
+ } else {
+ ERR(GRN_INVALID_FORMAT, "grn_io_detect_type failed");
+ }
+ grn_close(fd);
+ } else {
+ ERRNO_ERR("failed to open path for detecting type: <%s>",
+ path);
+ }
+ return res;
+}
+
+grn_io *
+grn_io_open(grn_ctx *ctx, const char *path, grn_io_mode mode)
+{
+ size_t max_path_len = PATH_MAX - 4;
+ grn_io *io;
+ struct stat s;
+ fileinfo fi;
+ uint32_t flags = 0;
+ uint32_t b;
+ uint32_t header_size = 0, segment_size = 0, max_segment = 0, bs;
+ if (!path || !*path) {
+ ERR(GRN_INVALID_ARGUMENT, "[io][open] path is missing");
+ return NULL;
+ }
+ if ((strlen(path) > max_path_len)) {
+ int truncate_length = 10;
+ ERR(GRN_INVALID_ARGUMENT,
+ "[io][open] path is too long: "
+ "<%" GRN_FMT_SIZE ">(max: %" GRN_FMT_SIZE "): <%.*s...>",
+ strlen(path),
+ max_path_len,
+ truncate_length,
+ path);
+ return NULL;
+ }
+ {
+ struct _grn_io_header h;
+ int fd;
+ ssize_t read_bytes;
+ grn_open(fd, path, O_RDWR | GRN_OPEN_FLAG_BINARY);
+ if (fd == -1) {
+ ERRNO_ERR("failed to open path: <%s>",
+ path);
+ return NULL;
+ }
+ if (fstat(fd, &s) == -1) {
+ ERRNO_ERR("[io][open] failed to file status: <%s>",
+ path);
+ grn_close(fd);
+ return NULL;
+ }
+ if ((size_t) s.st_size < sizeof(struct _grn_io_header)) {
+ ERR(GRN_INCOMPATIBLE_FILE_FORMAT,
+ "[io][open] file size is too small: "
+ "<%" GRN_FMT_INT64D ">(required: >= %" GRN_FMT_SIZE "): <%s>",
+ (int64_t)(s.st_size),
+ sizeof(struct _grn_io_header),
+ path);
+ grn_close(fd);
+ return NULL;
+ }
+ read_bytes = grn_read(fd, &h, sizeof(struct _grn_io_header));
+ if (read_bytes != sizeof(struct _grn_io_header)) {
+ ERRNO_ERR("[io][open] failed to read header data: "
+ "<%" GRN_FMT_SSIZE ">(expected: %" GRN_FMT_SSIZE "): <%s>",
+ read_bytes,
+ sizeof(struct _grn_io_header),
+ path);
+ grn_close(fd);
+ return NULL;
+ }
+ if (memcmp(h.idstr, GRN_IO_IDSTR, GRN_IO_IDSTR_LEN) != 0) {
+ ERR(GRN_INCOMPATIBLE_FILE_FORMAT,
+ "failed to open: format ID is different: <%s>: <%.*s>",
+ path,
+ (int)GRN_IO_IDSTR_LEN, GRN_IO_IDSTR);
+ grn_close(fd);
+ return NULL;
+ }
+ header_size = h.header_size;
+ segment_size = h.segment_size;
+ max_segment = h.max_segment;
+ flags = h.flags;
+ grn_close(fd);
+ if (segment_size == 0) {
+ ERR(GRN_INCOMPATIBLE_FILE_FORMAT, "failed to open: segment size is 0");
+ return NULL;
+ }
+ }
+ b = grn_io_compute_base(header_size);
+ bs = grn_io_compute_base_segment(b, segment_size);
+ grn_fileinfo_init(&fi, 1);
+ if (!grn_fileinfo_open(ctx, &fi, path, O_RDWR)) {
+ struct _grn_io_header *header;
+ header = GRN_MMAP(ctx, &grn_gctx, NULL, &(fi.fmo), &fi, 0, b);
+ if (header) {
+ unsigned long file_size;
+ unsigned int max_nfiles;
+ fileinfo *fis;
+
+ file_size = grn_io_compute_file_size(header->version);
+ max_nfiles = grn_io_compute_max_n_files(segment_size, max_segment,
+ bs, file_size);
+ fis = GRN_MALLOCN(fileinfo, max_nfiles);
+ if (!fis) {
+ GRN_MUNMAP(ctx, &grn_gctx, NULL, &(fi.fmo), &fi, header, b);
+ grn_fileinfo_close(ctx, &fi);
+ return NULL;
+ }
+ grn_fileinfo_init(fis, max_nfiles);
+ grn_memcpy(fis, &fi, sizeof(fileinfo));
+ if ((io = GRN_MALLOC(sizeof(grn_io)))) {
+ grn_io_mapinfo *maps = NULL;
+ if ((maps = GRN_CALLOC(sizeof(grn_io_mapinfo) * max_segment))) {
+ grn_strncpy(io->path, PATH_MAX-1, path, PATH_MAX-1);
+ io->header = header;
+ io->user_header = (((byte *) header) + IO_HEADER_SIZE);
+ {
+ io->maps = maps;
+ io->base = b;
+ io->base_seg = bs;
+ io->mode = mode;
+ io->fis = fis;
+ io->ainfo = NULL;
+ io->max_map_seg = 0;
+ io->nmaps = 0;
+ io->count = 0;
+ io->flags = header->flags;
+ io->lock = &header->lock;
+ if (!array_init(ctx, io, io->header->n_arrays)) {
+ grn_io_register(ctx, io);
+ return io;
+ }
+ }
+ if (io->maps) { GRN_FREE(io->maps); }
+ }
+ GRN_FREE(io);
+ }
+ GRN_FREE(fis);
+ GRN_MUNMAP(ctx, &grn_gctx, NULL, &(fi.fmo), &fi, header, b);
+ }
+ grn_fileinfo_close(ctx, &fi);
+ }
+ return NULL;
+}
+
+grn_rc
+grn_io_close(grn_ctx *ctx, grn_io *io)
+{
+ uint32_t max_nfiles;
+
+ max_nfiles = grn_io_max_n_files(io);
+ grn_io_unregister(ctx, io);
+ if (io->ainfo) { GRN_FREE(io->ainfo); }
+ if (io->maps) {
+ int i;
+ uint32_t max_segment;
+ uint32_t segment_size;
+ unsigned long file_size;
+ uint32_t segments_per_file;
+
+ max_segment = grn_io_max_segment(io);
+ segment_size = io->header->segment_size;
+ file_size = grn_io_compute_file_size(io->header->version);
+ segments_per_file = file_size / segment_size;
+ for (i = 0; (uint) i < max_segment; i++) {
+ grn_io_mapinfo *mi;
+ mi = &(io->maps[i]);
+ if (mi->map) {
+ fileinfo *fi = NULL;
+ /* if (atomic_read(mi->nref)) { return STILL_IN_USE ; } */
+ if (io->fis) {
+ uint32_t bseg = i + io->base_seg;
+ uint32_t fno = bseg / segments_per_file;
+ fi = &io->fis[fno];
+ }
+ GRN_MUNMAP(ctx, &grn_gctx, io, &mi->fmo, fi, mi->map, segment_size);
+ }
+ }
+ GRN_FREE(io->maps);
+ }
+ GRN_MUNMAP(ctx, &grn_gctx, io, (io->fis ? &io->fis->fmo : NULL),
+ io->fis, io->header, io->base);
+ if (io->fis) {
+ uint i;
+ for (i = 0; i < max_nfiles; i++) {
+ fileinfo *fi = &(io->fis[i]);
+ grn_fileinfo_close(ctx, fi);
+ }
+ GRN_FREE(io->fis);
+ }
+ GRN_FREE(io);
+ return GRN_SUCCESS;
+}
+
+uint32_t
+grn_io_base_seg(grn_io *io)
+{
+ return io->base_seg;
+}
+
+const char *
+grn_io_path(grn_io *io)
+{
+ return io->path;
+}
+
+void *
+grn_io_header(grn_io *io)
+{
+ return io->user_header;
+}
+
+grn_rc
+grn_io_set_type(grn_io *io, uint32_t type)
+{
+ if (!io || !io->header) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ io->header->type = type;
+ return GRN_SUCCESS;
+}
+
+uint32_t
+grn_io_get_type(grn_io *io)
+{
+ if (!io || !io->header) { return GRN_VOID; }
+ return io->header->type;
+}
+
+inline static void
+gen_pathname(const char *path, char *buffer, int fno)
+{
+ size_t len = strlen(path);
+ grn_memcpy(buffer, path, len);
+ if (fno) {
+ buffer[len] = '.';
+ grn_itoh(fno, buffer + len + 1, 3);
+ buffer[len + 4] = '\0';
+ } else {
+ buffer[len] = '\0';
+ }
+}
+
+static uint32_t
+grn_io_n_files(grn_ctx *ctx, grn_io *io)
+{
+ unsigned long file_size;
+ file_size = grn_io_compute_file_size(io->header->version);
+ return ((io->header->curr_size + file_size - 1) / file_size);
+}
+
+grn_rc
+grn_io_size(grn_ctx *ctx, grn_io *io, uint64_t *size)
+{
+ uint32_t fno;
+ struct stat s;
+ uint64_t tsize = 0;
+ char buffer[PATH_MAX];
+ uint32_t n_files;
+
+ n_files = grn_io_n_files(ctx, io);
+ for (fno = 0; fno < n_files; fno++) {
+ gen_pathname(io->path, buffer, fno);
+ if (stat(buffer, &s)) {
+ SERR("failed to stat path to compute size: <%s>",
+ buffer);
+ } else {
+ tsize += s.st_size;
+ }
+ }
+ *size = tsize;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_io_remove_raw(grn_ctx *ctx, const char *path)
+{
+ grn_rc rc = GRN_SUCCESS;
+ int fno;
+ char buffer[PATH_MAX];
+
+ if (grn_unlink(path) != 0) {
+ ERRNO_ERR("[io][remove] failed to remove path: <%s>",
+ path);
+ return ctx->rc;
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO, "[io][remove] removed path: <%s>", path);
+
+ for (fno = 1; ; fno++) {
+ struct stat s;
+ gen_pathname(path, buffer, fno);
+ if (stat(buffer, &s) != 0) {
+ break;
+ }
+ if (grn_unlink(buffer) == 0) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][remove] removed numbered path: <%d>: <%s>", fno, buffer);
+ } else {
+ ERRNO_ERR("[io][remove] failed to remove numbered path: <%d>: <%s>",
+ fno, buffer);
+ rc = ctx->rc;
+ }
+ }
+ return rc;
+}
+
+grn_rc
+grn_io_remove(grn_ctx *ctx, const char *path)
+{
+ struct stat s;
+
+ if (stat(path, &s) != 0) {
+ SERR("failed to stat: <%s>", path);
+ return ctx->rc;
+ }
+
+ return grn_io_remove_raw(ctx, path);
+}
+
+grn_rc
+grn_io_remove_if_exist(grn_ctx *ctx, const char *path)
+{
+ struct stat s;
+ if (stat(path, &s) == 0) {
+ return grn_io_remove_raw(ctx, path);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_io_rename(grn_ctx *ctx, const char *old_name, const char *new_name)
+{
+ struct stat s;
+ if (stat(old_name, &s)) {
+ SERR("failed to stat path to be renamed: <%s>", old_name);
+ return ctx->rc;
+ } else if (rename(old_name, new_name)) {
+ SERR("failed to rename path: <%s> -> <%s>",
+ old_name, new_name);
+ return ctx->rc;
+ } else {
+ int fno;
+ char old_buffer[PATH_MAX];
+ char new_buffer[PATH_MAX];
+ for (fno = 1; ; fno++) {
+ gen_pathname(old_name, old_buffer, fno);
+ if (!stat(old_buffer, &s)) {
+ gen_pathname(new_name, new_buffer, fno);
+ if (rename(old_buffer, new_buffer)) {
+ SERR("failed to rename path: <%s> -> <%s>",
+ old_buffer, new_buffer);
+ }
+ } else {
+ SERR("failed to stat path to be renamed: <%s>",
+ old_buffer);
+ return ctx->rc;
+ }
+ }
+ return GRN_SUCCESS;
+ }
+}
+
+typedef struct {
+ grn_io_ja_ehead head;
+ char body[256];
+} ja_element;
+
+grn_rc
+grn_io_read_ja(grn_io *io, grn_ctx *ctx, grn_io_ja_einfo *einfo, uint32_t epos,
+ uint32_t key, uint32_t segment, uint32_t offset, void **value,
+ uint32_t *value_len)
+{
+ uint32_t rest = 0, size = *value_len + sizeof(grn_io_ja_ehead);
+ uint32_t segment_size = io->header->segment_size;
+ unsigned long file_size = grn_io_compute_file_size(io->header->version);
+ uint32_t segments_per_file = file_size / segment_size;
+ uint32_t bseg = segment + io->base_seg;
+ int fno = bseg / segments_per_file;
+ fileinfo *fi = &io->fis[fno];
+ off_t base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
+ off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
+ ja_element *v = GRN_MALLOC(size);
+ if (!v) {
+ *value = NULL;
+ *value_len = 0;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if ((unsigned long) (pos + size) > file_size) {
+ rest = pos + size - file_size;
+ size = file_size - pos;
+ }
+ if (!grn_fileinfo_opened(fi)) {
+ char path[PATH_MAX];
+ gen_pathname(io->path, path, fno);
+ if (grn_fileinfo_open(ctx, fi, path, O_RDWR|O_CREAT)) {
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return ctx->rc;
+ }
+ }
+ if (grn_pread(ctx, fi, v, size, pos)) {
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return ctx->rc;
+ }
+ if (einfo->pos != epos) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "einfo pos changed %x => %x", einfo->pos, epos);
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return GRN_FILE_CORRUPT;
+ }
+ if (einfo->size != *value_len) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "einfo size changed %d => %d", einfo->size, *value_len);
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return GRN_FILE_CORRUPT;
+ }
+ if (v->head.key != key) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "ehead key unmatch %x => %x", key, v->head.key);
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return GRN_INVALID_FORMAT;
+ }
+ if (v->head.size != *value_len) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "ehead size unmatch %d => %d", *value_len, v->head.size);
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return GRN_INVALID_FORMAT;
+ }
+ if (rest) {
+ byte *vr = (byte *)v + size;
+ do {
+ fi = &io->fis[++fno];
+ if (!grn_fileinfo_opened(fi)) {
+ char path[PATH_MAX];
+ gen_pathname(io->path, path, fno);
+ if (grn_fileinfo_open(ctx, fi, path, O_RDWR|O_CREAT)) {
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return ctx->rc;
+ }
+ }
+ size = rest > file_size ? file_size : rest;
+ if (grn_pread(ctx, fi, vr, size, 0)) {
+ *value = NULL;
+ *value_len = 0;
+ GRN_FREE(v);
+ return ctx->rc;
+ }
+ vr += size;
+ rest -= size;
+ } while (rest);
+ }
+ *value = v->body;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_io_write_ja(grn_io *io, grn_ctx *ctx, uint32_t key,
+ uint32_t segment, uint32_t offset, void *value,
+ uint32_t value_len)
+{
+ grn_rc rc;
+ uint32_t rest = 0, size = value_len + sizeof(grn_io_ja_ehead);
+ uint32_t segment_size = io->header->segment_size;
+ unsigned long file_size = grn_io_compute_file_size(io->header->version);
+ uint32_t segments_per_file = file_size / segment_size;
+ uint32_t bseg = segment + io->base_seg;
+ int fno = bseg / segments_per_file;
+ fileinfo *fi = &io->fis[fno];
+ off_t base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
+ off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
+ if ((unsigned long) (pos + size) > file_size) {
+ rest = pos + size - file_size;
+ size = file_size - pos;
+ }
+ if (!grn_fileinfo_opened(fi)) {
+ char path[PATH_MAX];
+ gen_pathname(io->path, path, fno);
+ if ((rc = grn_fileinfo_open(ctx, fi, path, O_RDWR|O_CREAT))) { return rc; }
+ }
+ if (value_len <= 256) {
+ ja_element je;
+ je.head.size = value_len;
+ je.head.key = key;
+ grn_memcpy(je.body, value, value_len);
+ rc = grn_pwrite(ctx, fi, &je, size, pos);
+ } else {
+ grn_io_ja_ehead eh;
+ eh.size = value_len;
+ eh.key = key;
+ if ((rc = grn_pwrite(ctx, fi, &eh, sizeof(grn_io_ja_ehead), pos))) {
+ return rc;
+ }
+ pos += sizeof(grn_io_ja_ehead);
+ rc = grn_pwrite(ctx, fi, value, size - sizeof(grn_io_ja_ehead), pos);
+ }
+ if (rc) { return rc; }
+ if (rest) {
+ byte *vr = (byte *)value + size - sizeof(grn_io_ja_ehead);
+ do {
+ fi = &io->fis[++fno];
+ if (!grn_fileinfo_opened(fi)) {
+ char path[PATH_MAX];
+ gen_pathname(io->path, path, fno);
+ if ((rc = grn_fileinfo_open(ctx, fi, path, O_RDWR|O_CREAT))) {
+ return rc;
+ }
+ }
+ size = rest > file_size ? file_size : rest;
+ if ((rc = grn_pwrite(ctx, fi, vr, size, 0))) { return rc; }
+ vr += size;
+ rest -= size;
+ } while (rest);
+ }
+ return rc;
+}
+
+grn_rc
+grn_io_write_ja_ehead(grn_io *io, grn_ctx *ctx, uint32_t key,
+ uint32_t segment, uint32_t offset, uint32_t value_len)
+{
+ grn_rc rc;
+ uint32_t segment_size = io->header->segment_size;
+ unsigned long file_size = grn_io_compute_file_size(io->header->version);
+ uint32_t segments_per_file = file_size / segment_size;
+ uint32_t bseg = segment + io->base_seg;
+ int fno = bseg / segments_per_file;
+ fileinfo *fi = &io->fis[fno];
+ off_t base = fno ? 0 : io->base - (uint64_t)segment_size + io->base_seg;
+ off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + offset + base;
+ if (!grn_fileinfo_opened(fi)) {
+ char path[PATH_MAX];
+ gen_pathname(io->path, path, fno);
+ if ((rc = grn_fileinfo_open(ctx, fi, path, O_RDWR|O_CREAT))) { return rc; }
+ }
+ {
+ grn_io_ja_ehead eh;
+ eh.size = value_len;
+ eh.key = key;
+ return grn_pwrite(ctx, fi, &eh, sizeof(grn_io_ja_ehead), pos);
+ }
+}
+
+void *
+grn_io_win_map(grn_io *io, grn_ctx *ctx, grn_io_win *iw, uint32_t segment,
+ uint32_t offset, uint32_t size, grn_io_rw_mode mode)
+{
+ uint32_t nseg, segment_size = io->header->segment_size;
+ if (offset >= segment_size) {
+ segment += offset / segment_size;
+ offset = offset % segment_size;
+ }
+ nseg = (offset + size + segment_size - 1) / segment_size;
+ if (!size || !ctx || segment + nseg > io->header->max_segment) {
+ return NULL;
+ }
+ iw->ctx = ctx;
+ iw->diff = 0;
+ iw->io = io;
+ iw->mode = mode;
+ iw->tiny_p = 0;
+ iw->segment = segment;
+ iw->offset = offset;
+ iw->nseg = nseg;
+ iw->size = size;
+ if (nseg == 1) {
+ byte *addr = NULL;
+ GRN_IO_SEG_REF(io, segment, addr);
+ if (!addr) { return NULL; }
+ iw->cached = 1;
+ iw->addr = addr + offset;
+ } else {
+ if (!(iw->addr = GRN_MALLOC(size))) { return NULL; }
+ iw->cached = 0;
+ switch (mode) {
+ case grn_io_rdonly:
+ case grn_io_rdwr:
+ {
+ byte *p, *q = NULL;
+ uint32_t s, r;
+ for (p = iw->addr, r = size; r; p += s, r -= s, segment++, offset = 0) {
+ GRN_IO_SEG_REF(io, segment, q);
+ if (!q) {
+ GRN_FREE(iw->addr);
+ return NULL;
+ }
+ s = (offset + r > segment_size) ? segment_size - offset : r;
+ grn_memcpy(p, q + offset, s);
+ GRN_IO_SEG_UNREF(io, segment);
+ }
+ }
+ break;
+ case grn_io_wronly:
+ break;
+ default :
+ return NULL;
+ }
+ }
+ return iw->addr;
+}
+
+grn_rc
+grn_io_win_unmap(grn_io_win *iw)
+{
+ if (!iw || !iw->io ||!iw->ctx) { return GRN_INVALID_ARGUMENT; }
+ if (iw->cached) {
+ if (!iw->tiny_p) { GRN_IO_SEG_UNREF(iw->io, iw->segment); }
+ return GRN_SUCCESS;
+ }
+ {
+ grn_io *io = iw->io;
+ grn_ctx *ctx = iw->ctx;
+ switch (iw->mode) {
+ case grn_io_rdonly:
+ if (!iw->addr) { return GRN_INVALID_ARGUMENT; }
+ GRN_FREE(iw->addr);
+ return GRN_SUCCESS;
+ case grn_io_rdwr:
+ case grn_io_wronly:
+ {
+ byte *p, *q = NULL;
+ uint32_t segment_size = io->header->segment_size;
+ uint32_t s, r, offset = iw->offset, segment = iw->segment;
+ for (p = iw->addr, r = iw->size; r;
+ p += s, r -= s, segment++, offset = 0) {
+ GRN_IO_SEG_REF(io, segment, q);
+ if (!q) { return GRN_NO_MEMORY_AVAILABLE; }
+ s = (offset + r > segment_size) ? segment_size - offset : r;
+ grn_memcpy(q + offset, p, s);
+ GRN_IO_SEG_UNREF(io, segment);
+ }
+ }
+ GRN_FREE(iw->addr);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+}
+
+#define DO_MAP(io,fmo,fi,pos,size,segno,res) do {\
+ (res) = GRN_MMAP(ctx, &grn_gctx, (io), (fmo), (fi), (pos), (size));\
+ if ((res)) {\
+ uint32_t nmaps;\
+ if (io->max_map_seg < segno) { io->max_map_seg = segno; }\
+ GRN_ATOMIC_ADD_EX(&io->nmaps, 1, nmaps);\
+ {\
+ uint64_t tail = io->base + (uint64_t)(size) * ((segno) + 1);\
+ if (tail > io->header->curr_size) { io->header->curr_size = tail; }\
+ }\
+ }\
+} while (0)
+
+void
+grn_io_seg_map_(grn_ctx *ctx, grn_io *io, uint32_t segno, grn_io_mapinfo *info)
+{
+ uint32_t segment_size = io->header->segment_size;
+ if ((io->flags & GRN_IO_TEMPORARY)) {
+ DO_MAP(io, &info->fmo, NULL, 0, segment_size, segno, info->map);
+ } else {
+ unsigned long file_size = grn_io_compute_file_size(io->header->version);
+ uint32_t segments_per_file = file_size / segment_size;
+ uint32_t bseg = segno + io->base_seg;
+ uint32_t fno = bseg / segments_per_file;
+ off_t base = fno ? 0 : io->base - (uint64_t)segment_size * io->base_seg;
+ off_t pos = (uint64_t)segment_size * (bseg % segments_per_file) + base;
+ fileinfo *fi = &io->fis[fno];
+ if (!grn_fileinfo_opened(fi)) {
+ char path[PATH_MAX];
+ grn_bool path_exist = GRN_TRUE;
+ gen_pathname(io->path, path, fno);
+ path_exist = grn_path_exist(path);
+ if (!grn_fileinfo_open(ctx, fi, path, O_RDWR|O_CREAT)) {
+ DO_MAP(io, &info->fmo, fi, pos, segment_size, segno, info->map);
+ if (!info->map && !path_exist) {
+ if (grn_unlink(path) == 0) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][map][error] memory mapping is failed and then "
+ "removed created map file: <%s>", path);
+ } else {
+ ERRNO_ERR("[io][map][error] memory mapping is failed and then "
+ "failed to remove created map file: <%s>", path);
+ }
+ }
+ }
+ } else {
+ DO_MAP(io, &info->fmo, fi, pos, segment_size, segno, info->map);
+ }
+ }
+}
+
+grn_rc
+grn_io_seg_expire(grn_ctx *ctx, grn_io *io, uint32_t segno, uint32_t nretry)
+{
+ uint32_t retry, *pnref;
+ grn_io_mapinfo *info;
+ if (!io->maps || segno >= io->header->max_segment) { return GRN_INVALID_ARGUMENT; }
+ info = &io->maps[segno];
+ if (!info->map) { return GRN_INVALID_ARGUMENT; }
+ pnref = &info->nref;
+ for (retry = 0;; retry++) {
+ uint32_t nref;
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);
+ if (nref) {
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);
+ if (retry >= GRN_IO_MAX_RETRY) {
+ GRN_LOG(ctx, GRN_LOG_CRIT,
+ "deadlock detected! in grn_io_seg_expire(%p, %u, %u)",
+ io, segno, nref);
+ return GRN_RESOURCE_DEADLOCK_AVOIDED;
+ }
+ } else {
+ GRN_ATOMIC_ADD_EX(pnref, GRN_IO_MAX_REF, nref);
+ if (nref > 1) {
+ GRN_ATOMIC_ADD_EX(pnref, -(GRN_IO_MAX_REF + 1), nref);
+ GRN_FUTEX_WAKE(pnref);
+ if (retry >= GRN_IO_MAX_RETRY) {
+ GRN_LOG(ctx, GRN_LOG_CRIT,
+ "deadlock detected!! in grn_io_seg_expire(%p, %u, %u)",
+ io, segno, nref);
+ return GRN_RESOURCE_DEADLOCK_AVOIDED;
+ }
+ } else {
+ uint32_t nmaps;
+ fileinfo *fi = &(io->fis[segno]);
+ GRN_MUNMAP(ctx, &grn_gctx, io, &info->fmo, fi,
+ info->map, io->header->segment_size);
+ info->map = NULL;
+ GRN_ATOMIC_ADD_EX(pnref, -(GRN_IO_MAX_REF + 1), nref);
+ GRN_ATOMIC_ADD_EX(&io->nmaps, -1, nmaps);
+ GRN_FUTEX_WAKE(pnref);
+ return GRN_SUCCESS;
+ }
+ }
+ if (retry >= nretry) { return GRN_RESOURCE_DEADLOCK_AVOIDED; }
+ GRN_FUTEX_WAIT(pnref);
+ }
+}
+
+uint32_t
+grn_io_expire(grn_ctx *ctx, grn_io *io, int count_thresh, uint32_t limit)
+{
+ uint32_t m, n = 0, ln = io->nmaps;
+ switch ((io->flags & (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT))) {
+ case GRN_IO_EXPIRE_GTICK :
+ {
+ uint32_t nref, nmaps, *pnref = &io->nref;
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);
+ if (!nref && grn_gtick - io->count > (uint) count_thresh) {
+ {
+ uint32_t i = io->header->n_arrays;
+ grn_io_array_spec *array_specs = (grn_io_array_spec *)io->user_header;
+ while (i--) {
+ memset(io->ainfo[i].addrs, 0,
+ sizeof(void *) * array_specs[i].max_n_segments);
+ }
+ }
+ {
+ uint32_t fno;
+ for (fno = 0; fno < io->max_map_seg; fno++) {
+ grn_io_mapinfo *info = &(io->maps[fno]);
+ if (info->map) {
+ fileinfo *fi = &(io->fis[fno]);
+ GRN_MUNMAP(ctx, &grn_gctx, io, &info->fmo, fi,
+ info->map, io->header->segment_size);
+ info->map = NULL;
+ info->nref = 0;
+ info->count = grn_gtick;
+ GRN_ATOMIC_ADD_EX(&io->nmaps, -1, nmaps);
+ n++;
+ }
+ }
+ }
+ }
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);
+ }
+ break;
+ case GRN_IO_EXPIRE_SEGMENT :
+ for (m = io->max_map_seg; n < limit && m; m--) {
+ if (!grn_io_seg_expire(ctx, io, m, 0)) { n++; }
+ }
+ break;
+ case (GRN_IO_EXPIRE_GTICK|GRN_IO_EXPIRE_SEGMENT) :
+ {
+ grn_io_mapinfo *info = io->maps;
+ for (m = io->max_map_seg; n < limit && m; info++, m--) {
+ if (info->map && (grn_gtick - info->count) > (uint) count_thresh) {
+ uint32_t nmaps, nref, *pnref = &info->nref;
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);
+ if (!nref && info->map && (grn_gtick - info->count) > (uint) count_thresh) {
+ GRN_MUNMAP(ctx, &grn_gctx, io, &info->fmo, NULL,
+ info->map, io->header->segment_size);
+ GRN_ATOMIC_ADD_EX(&io->nmaps, -1, nmaps);
+ info->map = NULL;
+ info->count = grn_gtick;
+ n++;
+ }
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);
+ }
+ }
+ }
+ break;
+ }
+ if (n) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "<%p:%x> expired i=%p max=%d (%d/%d)",
+ ctx, grn_gtick, io, io->max_map_seg, n, ln);
+ }
+ return n;
+}
+
+void *
+grn_io_anon_map(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length)
+{
+ return (mi->map = GRN_MMAP(ctx, ctx, NULL, &mi->fmo, NULL, 0, length));
+}
+
+void
+grn_io_anon_unmap(grn_ctx *ctx, grn_io_mapinfo *mi, size_t length)
+{
+ GRN_MUNMAP(ctx, ctx, NULL, &mi->fmo, NULL, mi->map, length);
+}
+
+grn_rc
+grn_io_lock(grn_ctx *ctx, grn_io *io, int timeout)
+{
+ static int _ncalls = 0, _ncolls = 0;
+ uint32_t count, count_log_border = 1000;
+ uint32_t rc_check_interval = 1000;
+ _ncalls++;
+ if (!io) { return GRN_INVALID_ARGUMENT; }
+ for (count = 0;; count++) {
+ uint32_t lock;
+ GRN_ATOMIC_ADD_EX(io->lock, 1, lock);
+ if (lock) {
+ GRN_ATOMIC_ADD_EX(io->lock, -1, lock);
+ if (count == count_log_border) {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "io(%s) collisions(%d/%d): lock failed %d times",
+ io->path, _ncolls, _ncalls, count_log_border);
+ }
+ if (!timeout || (timeout > 0 && timeout == (int) count)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[DB Locked] time out(%d): io(%s) collisions(%d/%d)",
+ timeout, io->path, _ncolls, _ncalls);
+ break;
+ }
+ if (!(++_ncolls % 1000000) && (_ncolls > _ncalls)) {
+ if (_ncolls < 0 || _ncalls < 0) {
+ _ncolls = 0; _ncalls = 0;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "io(%s) collisions(%d/%d)", io->path, _ncolls, _ncalls);
+ }
+ }
+ if ((count % rc_check_interval) == 0) {
+ if (ctx->rc != GRN_SUCCESS) {
+ return ctx->rc;
+ }
+ }
+ grn_nanosleep(GRN_LOCK_WAIT_TIME_NANOSECOND);
+ continue;
+ }
+ return GRN_SUCCESS;
+ }
+ ERR(GRN_RESOURCE_DEADLOCK_AVOIDED, "grn_io_lock failed");
+ return ctx->rc;
+}
+
+void
+grn_io_unlock(grn_io *io)
+{
+ if (io) {
+ uint32_t lock;
+ GRN_ATOMIC_ADD_EX(io->lock, -1, lock);
+ }
+}
+
+void
+grn_io_clear_lock(grn_io *io)
+{
+ if (io) { *io->lock = 0; }
+}
+
+uint32_t
+grn_io_is_locked(grn_io *io)
+{
+ return io ? *io->lock : 0;
+}
+
+grn_rc
+grn_io_flush(grn_ctx *ctx, grn_io *io)
+{
+ grn_rc rc = GRN_SUCCESS;
+ struct _grn_io_header *header;
+ uint32_t aligned_header_size;
+
+ if (io->path[0] == '\0') {
+ return GRN_SUCCESS;
+ }
+
+ header = io->header;
+ aligned_header_size = grn_io_compute_base(header->header_size);
+
+ if (GRN_MSYNC(ctx, io->fis[0].fh, header, aligned_header_size) != 0) {
+ return ctx->rc;
+ }
+
+ if (io->maps) {
+ uint32_t i;
+ uint32_t max_mapped_segment;
+ uint32_t segment_size;
+
+ max_mapped_segment = grn_io_max_segment(io);
+ segment_size = header->segment_size;
+ for (i = 0; i < max_mapped_segment; i++) {
+ grn_io_mapinfo *info = &(io->maps[i]);
+ uint32_t nth_file_info;
+ uint32_t *pnref;
+ uint32_t nref;
+ int msync_result;
+
+ if (!info) {
+ continue;
+ }
+
+ pnref = &info->nref;
+ GRN_ATOMIC_ADD_EX(pnref, 1, nref);
+ if (nref != 0) {
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);
+ continue;
+ }
+
+ if (!info->map) {
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);
+ GRN_FUTEX_WAKE(pnref);
+ continue;
+ }
+
+ nth_file_info = grn_io_compute_nth_file_info(io, i);
+ msync_result = GRN_MSYNC(ctx,
+ io->fis[nth_file_info].fh,
+ info->map,
+ segment_size);
+ GRN_ATOMIC_ADD_EX(pnref, -1, nref);
+ GRN_FUTEX_WAKE(pnref);
+
+ if (msync_result != 0) {
+ rc = ctx->rc;
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+grn_bool
+grn_io_is_corrupt(grn_ctx *ctx, grn_io *io)
+{
+ uint32_t i;
+ uint32_t n_files;
+
+ if (!io) {
+ return GRN_FALSE;
+ }
+
+ n_files = grn_io_n_files(ctx, io);
+ for (i = 0; i < n_files; i++) {
+ char path[PATH_MAX];
+ struct stat s;
+ gen_pathname(io->path, path, i);
+ if (stat(path, &s) != 0) {
+ SERR("[io][corrupt] used path doesn't exist: <%s>",
+ path);
+ return GRN_TRUE;
+ }
+ }
+
+ return GRN_FALSE;
+}
+
+size_t
+grn_io_get_disk_usage(grn_ctx *ctx, grn_io *io)
+{
+ size_t usage = 0;
+ uint32_t i;
+ uint32_t n_files;
+
+ if (!io) {
+ return usage;
+ }
+
+ n_files = grn_io_n_files(ctx, io);
+ for (i = 0; i < n_files; i++) {
+ char path[PATH_MAX];
+ struct stat s;
+ gen_pathname(io->path, path, i);
+ if (stat(path, &s) != 0) {
+ continue;
+ }
+ usage += s.st_size;
+ }
+
+ return usage;
+}
+
+/** mmap abstraction **/
+
+static size_t mmap_size = 0;
+
+#ifdef WIN32
+
+inline static grn_rc
+grn_fileinfo_open_v1(grn_ctx *ctx, fileinfo *fi, const char *path, int flags)
+{
+ CRITICAL_SECTION_INIT(fi->cs);
+ return GRN_SUCCESS;
+}
+
+inline static void *
+grn_mmap_v1(grn_ctx *ctx, grn_ctx *owner_ctx, HANDLE *fmo, fileinfo *fi,
+ off_t offset, size_t length)
+{
+ void *res;
+ if (!fi) {
+ if (fmo) {
+ *fmo = NULL;
+ }
+ /* TODO: Try to support VirtualAlloc() as anonymous mmap in POSIX.
+ * If VirtualAlloc() provides better performance rather than malloc(),
+ * we'll use it.
+ */
+ return GRN_CALLOC(length);
+ }
+ /* CRITICAL_SECTION_ENTER(fi->cs); */
+ /* try to create fmo */
+ *fmo = CreateFileMapping(fi->fh, NULL, PAGE_READWRITE, 0, offset + length, NULL);
+ if (!*fmo) {
+ SERR("CreateFileMapping(%lu + %" GRN_FMT_SIZE ") failed "
+ "<%" GRN_FMT_SIZE ">",
+ (DWORD)offset, length,
+ mmap_size);
+ return NULL;
+ }
+ res = MapViewOfFile(*fmo, FILE_MAP_WRITE, 0, (DWORD)offset, (SIZE_T)length);
+ if (!res) {
+ SERR("MapViewOfFile(%lu,%" GRN_FMT_SIZE ") failed <%" GRN_FMT_SIZE ">",
+ (DWORD)offset, length, mmap_size);
+ return NULL;
+ }
+ /* CRITICAL_SECTION_LEAVE(fi->cs); */
+ mmap_size += length;
+ return res;
+}
+
+inline static int
+grn_munmap_v1(grn_ctx *ctx, grn_ctx *owner_ctx, HANDLE *fmo, fileinfo *fi,
+ void *start, size_t length)
+{
+ int r = 0;
+
+ if (!fi) {
+ GRN_FREE(start);
+ return r;
+ }
+
+ if (!fmo) {
+ GRN_FREE(start);
+ return r;
+ }
+
+ if (*fmo) {
+ if (UnmapViewOfFile(start)) {
+ mmap_size -= length;
+ } else {
+ SERR("UnmapViewOfFile(%p,%" GRN_FMT_SIZE ") failed <%" GRN_FMT_SIZE ">",
+ start, length, mmap_size);
+ r = -1;
+ }
+ if (!CloseHandle(*fmo)) {
+ SERR("CloseHandle(%p,%" GRN_FMT_SIZE ") failed <%" GRN_FMT_SIZE ">",
+ start, length, mmap_size);
+ }
+ *fmo = NULL;
+ } else {
+ GRN_FREE(start);
+ }
+
+ return r;
+}
+
+inline static grn_rc
+grn_fileinfo_open_v0(grn_ctx *ctx, fileinfo *fi, const char *path, int flags)
+{
+ /* signature may be wrong.. */
+ fi->fmo = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, NULL);
+ /* open failed */
+ if (fi->fmo == NULL) {
+ // flock
+ /* retry to open */
+ fi->fmo = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, NULL);
+ /* failed again */
+ if (fi->fmo == NULL) {
+ /* try to create fmo */
+ fi->fmo = CreateFileMapping(fi->fh, NULL, PAGE_READWRITE, 0,
+ GRN_IO_FILE_SIZE_V0, NULL);
+ }
+ // funlock
+ }
+ if (fi->fmo != NULL) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS) {
+ CRITICAL_SECTION_INIT(fi->cs);
+ return GRN_SUCCESS;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "fmo object already exists! handle=%p", fi->fh);
+ CloseHandle(fi->fmo);
+ }
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "failed to get FileMappingObject #%lu", GetLastError());
+ }
+ CloseHandle(fi->fh);
+ SERR("OpenFileMapping");
+ return ctx->rc;
+}
+
+inline static void *
+grn_mmap_v0(grn_ctx *ctx, grn_ctx *owner_ctx, fileinfo *fi, off_t offset,
+ size_t length)
+{
+ void *res;
+ if (!fi) { return GRN_CALLOC(length); }
+ /* file must be exceeded to GRN_IO_FILE_SIZE_V0 when FileMappingObject created.
+ and, after fmo created, it's not allowed to expand the size of file.
+ DWORD tail = (DWORD)(offset + length);
+ DWORD filesize = GetFileSize(fi->fh, NULL);
+ if (filesize < tail) {
+ if (SetFilePointer(fi->fh, tail, NULL, FILE_BEGIN) != tail) {
+ grn_log("SetFilePointer failed");
+ return NULL;
+ }
+ if (!SetEndOfFile(fi->fh)) {
+ grn_log("SetEndOfFile failed");
+ return NULL;
+ }
+ filesize = tail;
+ }
+ */
+ res = MapViewOfFile(fi->fmo, FILE_MAP_WRITE, 0, (DWORD)offset, (SIZE_T)length);
+ if (!res) {
+ MERR("MapViewOfFile failed: <%" GRN_FMT_SIZE ">: %s",
+ mmap_size, grn_current_error_message());
+ return NULL;
+ }
+ mmap_size += length;
+ return res;
+}
+
+inline static int
+grn_munmap_v0(grn_ctx *ctx, grn_ctx *owner_ctx, fileinfo *fi, void *start,
+ size_t length)
+{
+ if (!fi) {
+ GRN_FREE(start);
+ return 0;
+ }
+
+ if (UnmapViewOfFile(start)) {
+ mmap_size -= length;
+ return 0;
+ } else {
+ SERR("UnmapViewOfFile(%p,%" GRN_FMT_SIZE ") failed <%" GRN_FMT_SIZE ">",
+ start, length, mmap_size);
+ return -1;
+ }
+}
+
+inline static grn_rc
+grn_fileinfo_open_common(grn_ctx *ctx, fileinfo *fi, const char *path, int flags)
+{
+ /* may be wrong if flags is just only O_RDWR */
+ if ((flags & O_CREAT)) {
+ DWORD dwCreationDisposition;
+ const char *flags_description;
+ if (flags & O_EXCL) {
+ dwCreationDisposition = CREATE_NEW;
+ flags_description = "O_RDWR|O_CREAT|O_EXCL";
+ } else {
+ dwCreationDisposition = OPEN_ALWAYS;
+ flags_description = "O_RDWR|O_CREAT";
+ }
+ fi->fh = CreateFile(path, GRN_IO_FILE_CREATE_MODE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ dwCreationDisposition, FILE_ATTRIBUTE_NORMAL, 0);
+ if (fi->fh == INVALID_HANDLE_VALUE) {
+ SERR("CreateFile(<%s>, <%s>) failed",
+ path, flags_description);
+ goto exit;
+ }
+
+ switch (dwCreationDisposition) {
+ case CREATE_NEW :
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][open] create new file: <%s>", path);
+ break;
+ case OPEN_ALWAYS :
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][open] open existing file because it exists: <%s>", path);
+ } else {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][open] create new file because it doesn't exist: <%s>",
+ path);
+ }
+ break;
+ default :
+ break;
+ }
+
+ if (grn_io_use_sparse) {
+ FILE_SET_SPARSE_BUFFER buffer;
+ buffer.SetSparse = TRUE;
+ DWORD returned_bytes;
+ if (!DeviceIoControl(fi->fh,
+ FSCTL_SET_SPARSE,
+ &buffer,
+ sizeof(FILE_SET_SPARSE_BUFFER),
+ NULL,
+ 0,
+ &returned_bytes,
+ NULL)) {
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "Tried to make file sparse but failed: "
+ "DeviceIoControl(FSCTL_SET_SPARSE): "
+ "<%s>: <%s>",
+ path, grn_current_error_message());
+ }
+ }
+
+ goto exit;
+ }
+
+ if ((flags & O_TRUNC)) {
+ CloseHandle(fi->fh);
+ /* unable to assign OPEN_ALWAYS and TRUNCATE_EXISTING at once */
+ fi->fh = CreateFile(path, GRN_IO_FILE_CREATE_MODE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (fi->fh == INVALID_HANDLE_VALUE) {
+ SERR("CreateFile(<%s>, <O_RDWR|O_TRUNC>) failed",
+ path);
+ goto exit;
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][open] truncated: <%s>", path);
+ goto exit;
+ }
+ /* O_RDWR only */
+ fi->fh = CreateFile(path, GRN_IO_FILE_CREATE_MODE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+ if (fi->fh == INVALID_HANDLE_VALUE) {
+ SERR("CreateFile(<%s>, <O_RDWR>) failed",
+ path);
+ goto exit;
+ }
+ GRN_LOG(ctx, GRN_LOG_INFO,
+ "[io][open] open existing file: <%s>", path);
+
+exit :
+ return ctx->rc;
+}
+
+inline static grn_rc
+grn_fileinfo_open(grn_ctx *ctx, fileinfo *fi, const char *path, int flags)
+{
+ grn_rc rc;
+ struct _grn_io_header io_header;
+ LARGE_INTEGER file_size;
+ int version = grn_io_version_default;
+
+ rc = grn_fileinfo_open_common(ctx, fi, path, flags);
+ if (rc != GRN_SUCCESS) {
+ if (fi->fh) {
+ CloseHandle(fi->fh);
+ fi->fh = INVALID_HANDLE_VALUE;
+ }
+ return rc;
+ }
+
+ if (GetFileSizeEx(fi->fh, &file_size) && file_size.QuadPart > 0) {
+ DWORD header_size;
+ DWORD read_bytes;
+ header_size = sizeof(struct _grn_io_header);
+ ReadFile(fi->fh, &io_header, header_size, &read_bytes, NULL);
+ if (read_bytes == header_size) {
+ version = io_header.version;
+ }
+ SetFilePointer(fi->fh, 0, NULL, FILE_BEGIN);
+ }
+
+ if (version == 0) {
+ return grn_fileinfo_open_v0(ctx, fi, path, flags);
+ } else {
+ return grn_fileinfo_open_v1(ctx, fi, path, flags);
+ }
+}
+
+inline static int
+grn_guess_io_version(grn_ctx *ctx, grn_io *io, fileinfo *fi)
+{
+ if (io) {
+ return io->header->version;
+ }
+
+ if (fi) {
+ if (fi->fmo) {
+ return 0;
+ } else {
+ return 1;
+ }
+ }
+
+ return grn_io_version_default;
+}
+
+inline static void *
+grn_mmap(grn_ctx *ctx, grn_ctx *owner_ctx, grn_io *io, HANDLE *fmo,
+ fileinfo *fi, off_t offset, size_t length)
+{
+ int version;
+
+ version = grn_guess_io_version(ctx, io, fi);
+
+ if (version == 0) {
+ return grn_mmap_v0(ctx, owner_ctx, fi, offset, length);
+ } else {
+ return grn_mmap_v1(ctx, owner_ctx, fmo, fi, offset, length);
+ }
+}
+
+inline static int
+grn_munmap(grn_ctx *ctx, grn_ctx *owner_ctx, grn_io *io,
+ HANDLE *fmo, fileinfo *fi, void *start, size_t length)
+{
+ int version;
+
+ version = grn_guess_io_version(ctx, io, fi);
+
+ if (version == 0) {
+ return grn_munmap_v0(ctx, owner_ctx, fi, start, length);
+ } else {
+ return grn_munmap_v1(ctx, owner_ctx, fmo, fi, start, length);
+ }
+}
+
+inline static grn_rc
+grn_fileinfo_close(grn_ctx *ctx, fileinfo *fi)
+{
+ if (fi->fmo != NULL) {
+ CloseHandle(fi->fmo);
+ fi->fmo = NULL;
+ }
+ if (fi->fh != INVALID_HANDLE_VALUE) {
+ CloseHandle(fi->fh);
+ CRITICAL_SECTION_FIN(fi->cs);
+ fi->fh = INVALID_HANDLE_VALUE;
+ }
+ return GRN_SUCCESS;
+}
+
+inline static void
+grn_fileinfo_init(fileinfo *fis, int nfis)
+{
+ for (; nfis--; fis++) {
+ fis->fh = INVALID_HANDLE_VALUE;
+ fis->fmo = NULL;
+ }
+}
+
+inline static int
+grn_fileinfo_opened(fileinfo *fi)
+{
+ return fi->fh != INVALID_HANDLE_VALUE;
+}
+
+inline static int
+grn_msync(grn_ctx *ctx, HANDLE handle, void *start, size_t length)
+{
+ BOOL succeeded;
+ SYSTEMTIME system_time;
+ FILETIME file_time;
+
+ succeeded = FlushViewOfFile(start, length);
+ if (!succeeded) {
+ SERR("FlushViewOfFile(<%p>, <%" GRN_FMT_SIZE ">) failed",
+ start, length);
+ return -1;
+ }
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ return 0;
+ }
+
+ GetSystemTime(&system_time);
+ succeeded = SystemTimeToFileTime(&system_time, &file_time);
+ if (!succeeded) {
+ SERR("SystemTimeToFileTime(<%04u-%02u-%02uT%02u:%02u:%02u.%03u>) failed",
+ system_time.wYear,
+ system_time.wMonth,
+ system_time.wDay,
+ system_time.wHour,
+ system_time.wMinute,
+ system_time.wSecond,
+ system_time.wMilliseconds);
+ return -1;
+ }
+
+ succeeded = SetFileTime(handle, NULL, NULL, &file_time);
+ if (!succeeded) {
+ SERR("SetFileTime(<%p>, <%p>, <%" GRN_FMT_SIZE ">) failed",
+ handle, start, length);
+ return -1;
+ }
+
+ return 0;
+}
+
+inline static grn_rc
+grn_pread(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
+{
+ DWORD r, len;
+ CRITICAL_SECTION_ENTER(fi->cs);
+ r = SetFilePointer(fi->fh, offset, NULL, FILE_BEGIN);
+ if (r == INVALID_SET_FILE_POINTER) {
+ SERR("SetFilePointer");
+ } else {
+ if (!ReadFile(fi->fh, buf, (DWORD)count, &len, NULL)) {
+ SERR("ReadFile");
+ } else if (len != count) {
+ /* todo : should retry ? */
+ ERR(GRN_INPUT_OUTPUT_ERROR,
+ "ReadFile %" GRN_FMT_SIZE " != %lu",
+ count, len);
+ }
+ }
+ CRITICAL_SECTION_LEAVE(fi->cs);
+ return ctx->rc;
+}
+
+inline static grn_rc
+grn_pwrite(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
+{
+ DWORD r, len;
+ CRITICAL_SECTION_ENTER(fi->cs);
+ r = SetFilePointer(fi->fh, offset, NULL, FILE_BEGIN);
+ if (r == INVALID_SET_FILE_POINTER) {
+ SERR("SetFilePointer");
+ } else {
+ if (!WriteFile(fi->fh, buf, (DWORD)count, &len, NULL)) {
+ SERR("WriteFile");
+ } else if (len != count) {
+ /* todo : should retry ? */
+ ERR(GRN_INPUT_OUTPUT_ERROR,
+ "WriteFile %" GRN_FMT_SIZE " != %lu",
+ count, len);
+ }
+ }
+ CRITICAL_SECTION_LEAVE(fi->cs);
+ return ctx->rc;
+}
+
+#else /* WIN32 */
+
+inline static grn_rc
+grn_fileinfo_open(grn_ctx *ctx, fileinfo *fi, const char *path, int flags)
+{
+ struct stat st;
+ grn_open(fi->fd, path, flags);
+ if (fi->fd == -1) {
+ ERRNO_ERR("failed to open file info path: <%s>",
+ path);
+ return ctx->rc;
+ }
+ if (fstat(fi->fd, &st) == -1) {
+ ERRNO_ERR("failed to stat file info path: <%s>",
+ path);
+ return ctx->rc;
+ }
+ fi->dev = st.st_dev;
+ fi->inode = st.st_ino;
+ return GRN_SUCCESS;
+}
+
+inline static void
+grn_fileinfo_init(fileinfo *fis, int nfis)
+{
+ for (; nfis--; fis++) { fis->fd = -1; }
+}
+
+inline static int
+grn_fileinfo_opened(fileinfo *fi)
+{
+ return fi->fd != -1;
+}
+
+inline static grn_rc
+grn_fileinfo_close(grn_ctx *ctx, fileinfo *fi)
+{
+ if (fi->fd != -1) {
+ if (grn_close(fi->fd) == -1) {
+ SERR("close");
+ return ctx->rc;
+ }
+ fi->fd = -1;
+ }
+ return GRN_SUCCESS;
+}
+
+#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+#include <sys/mman.h>
+
+inline static void *
+grn_mmap(grn_ctx *ctx, grn_ctx *owner_ctx, grn_io *io, fileinfo *fi,
+ off_t offset, size_t length)
+{
+ void *res;
+ int fd, flags;
+ if (fi) {
+ struct stat s;
+ off_t tail = offset + length;
+ fd = fi->fd;
+ if ((fstat(fd, &s) == -1) || (s.st_size < tail && ftruncate(fd, tail) == -1)) {
+ SERR("fstat");
+ return NULL;
+ }
+ flags = MAP_SHARED;
+ } else {
+ fd = -1;
+ flags = MAP_PRIVATE|MAP_ANONYMOUS;
+ }
+ res = mmap(NULL, length, PROT_READ|PROT_WRITE, flags, fd, offset);
+ if (MAP_FAILED == res) {
+ MERR("mmap(%" GRN_FMT_LLU ",%d,%" GRN_FMT_LLD ")=%s <%" GRN_FMT_LLU ">",
+ (unsigned long long int)length, fd, (long long int)offset,
+ strerror(errno), (unsigned long long int)mmap_size);
+ return NULL;
+ }
+ mmap_size += length;
+ return res;
+}
+
+#ifdef USE_FAIL_MALLOC
+inline static void *
+grn_fail_mmap(grn_ctx *ctx, grn_ctx *owner_ctx, grn_io *io, fileinfo *fi,
+ off_t offset, size_t length,
+ const char* file, int line, const char *func)
+{
+ if (grn_fail_malloc_check(length, file, line, func)) {
+ return grn_mmap(ctx, io, fi, offset, length);
+ } else {
+ MERR("fail_mmap(%" GRN_FMT_SIZE ",%d,%" GRN_FMT_LLU ") "
+ "(%s:%d@%s) <%" GRN_FMT_SIZE ">",
+ length,
+ fi ? fi->fd : 0,
+ (long long unsigned int)offset,
+ file,
+ line,
+ func,
+ mmap_size);
+ return NULL;
+ }
+}
+#endif /* USE_FAIL_MALLOC */
+
+inline static int
+grn_msync(grn_ctx *ctx, void *start, size_t length)
+{
+ int r = msync(start, length, MS_SYNC);
+ if (r == -1) { SERR("msync"); }
+ return r;
+}
+
+inline static int
+grn_munmap(grn_ctx *ctx, grn_ctx *owner_ctx, grn_io *io, fileinfo *fi,
+ void *start, size_t length)
+{
+ int res;
+ res = munmap(start, length);
+ if (res) {
+ SERR("munmap(%p,%" GRN_FMT_LLU ") failed <%" GRN_FMT_LLU ">",
+ start,
+ (unsigned long long int)length,
+ (unsigned long long int)mmap_size);
+ } else {
+ mmap_size -= length;
+ }
+ return res;
+}
+
+inline static grn_rc
+grn_pread(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
+{
+ ssize_t r = pread(fi->fd, buf, count, offset);
+ if (r != (ssize_t) count) {
+ if (r == -1) {
+ SERR("pread");
+ } else {
+ /* todo : should retry ? */
+ ERR(GRN_INPUT_OUTPUT_ERROR,
+ "pread returned %" GRN_FMT_LLD " != %" GRN_FMT_LLU,
+ (long long int)r, (unsigned long long int)count);
+ }
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_pwrite(grn_ctx *ctx, fileinfo *fi, void *buf, size_t count, off_t offset)
+{
+ ssize_t r = pwrite(fi->fd, buf, count, offset);
+ if (r != (ssize_t) count) {
+ if (r == -1) {
+ SERR("pwrite");
+ } else {
+ /* todo : should retry ? */
+ ERR(GRN_INPUT_OUTPUT_ERROR,
+ "pwrite returned %" GRN_FMT_LLD " != %" GRN_FMT_LLU,
+ (long long int)r, (unsigned long long int)count);
+ }
+ return ctx->rc;
+ }
+ return GRN_SUCCESS;
+}
+
+#endif /* WIN32 */
diff --git a/storage/mroonga/vendor/groonga/lib/load.c b/storage/mroonga/vendor/groonga/lib/load.c
new file mode 100644
index 00000000..eb77f2b3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/load.c
@@ -0,0 +1,1230 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_load.h"
+#include "grn_ctx_impl.h"
+#include "grn_db.h"
+#include "grn_util.h"
+
+static void
+grn_loader_save_error(grn_ctx *ctx, grn_loader *loader)
+{
+ loader->rc = ctx->rc;
+ grn_strcpy(loader->errbuf, GRN_CTX_MSGSIZE, ctx->errbuf);
+}
+
+static grn_obj *
+values_add(grn_ctx *ctx, grn_loader *loader)
+{
+ grn_obj *res;
+ uint32_t curr_size = loader->values_size * sizeof(grn_obj);
+ if (curr_size < GRN_TEXT_LEN(&loader->values)) {
+ res = (grn_obj *)(GRN_TEXT_VALUE(&loader->values) + curr_size);
+ res->header.domain = GRN_DB_TEXT;
+ GRN_BULK_REWIND(res);
+ } else {
+ if (grn_bulk_space(ctx, &loader->values, sizeof(grn_obj))) { return NULL; }
+ res = (grn_obj *)(GRN_TEXT_VALUE(&loader->values) + curr_size);
+ GRN_TEXT_INIT(res, 0);
+ }
+ loader->values_size++;
+ loader->last = res;
+ return res;
+}
+
+static grn_obj *
+values_next(grn_ctx *ctx, grn_obj *value)
+{
+ if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET ||
+ value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
+ value += GRN_UINT32_VALUE(value);
+ }
+ return value + 1;
+}
+
+static int
+values_len(grn_ctx *ctx, grn_obj *head, grn_obj *tail)
+{
+ int len;
+ for (len = 0; head < tail; head = values_next(ctx, head), len++) ;
+ return len;
+}
+
+static grn_id
+loader_add(grn_ctx *ctx, grn_obj *key)
+{
+ int added = 0;
+ grn_loader *loader = &ctx->impl->loader;
+ grn_id id = grn_table_add_by_key(ctx, loader->table, key, &added);
+ if (id == GRN_ID_NIL) {
+ grn_loader_save_error(ctx, loader);
+ return id;
+ }
+ if (!added && loader->ifexists) {
+ grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->ifexists, 0);
+ grn_obj *result;
+ GRN_RECORD_SET(ctx, v, id);
+ result = grn_expr_exec(ctx, loader->ifexists, 0);
+ if (!grn_obj_is_true(ctx, result)) {
+ id = 0;
+ }
+ }
+ return id;
+}
+
+static void
+add_weight_vector(grn_ctx *ctx,
+ grn_obj *column,
+ grn_obj *value,
+ grn_obj *vector)
+{
+ unsigned int i, n;
+ grn_obj weight_buffer;
+
+ n = GRN_UINT32_VALUE(value);
+ GRN_UINT32_INIT(&weight_buffer, 0);
+ for (i = 0; i < n; i += 2) {
+ grn_rc rc;
+ grn_obj *key, *weight;
+
+ key = value + 1 + i;
+ weight = key + 1;
+
+ GRN_BULK_REWIND(&weight_buffer);
+ rc = grn_obj_cast(ctx, weight, &weight_buffer, GRN_TRUE);
+ if (rc != GRN_SUCCESS) {
+ grn_obj *range;
+ range = grn_ctx_at(ctx, weight_buffer.header.domain);
+ ERR_CAST(column, range, weight);
+ grn_obj_unlink(ctx, range);
+ break;
+ }
+ grn_vector_add_element(ctx,
+ vector,
+ GRN_BULK_HEAD(key),
+ GRN_BULK_VSIZE(key),
+ GRN_UINT32_VALUE(&weight_buffer),
+ key->header.domain);
+ }
+ GRN_OBJ_FIN(ctx, &weight_buffer);
+}
+
+static void
+set_vector(grn_ctx *ctx, grn_obj *column, grn_id id, grn_obj *vector)
+{
+ int n = GRN_UINT32_VALUE(vector);
+ grn_obj buf, *v = vector + 1;
+ grn_id range_id;
+ grn_obj *range;
+
+ range_id = DB_OBJ(column)->range;
+ range = grn_ctx_at(ctx, range_id);
+ if (grn_obj_is_table(ctx, range)) {
+ GRN_RECORD_INIT(&buf, GRN_OBJ_VECTOR, range_id);
+ while (n--) {
+ grn_bool cast_failed = GRN_FALSE;
+ grn_obj record, *element = v;
+ if (range_id != element->header.domain) {
+ GRN_RECORD_INIT(&record, 0, range_id);
+ if (grn_obj_cast(ctx, element, &record, GRN_TRUE)) {
+ cast_failed = GRN_TRUE;
+ ERR_CAST(column, range, element);
+ }
+ element = &record;
+ }
+ if (!cast_failed) {
+ GRN_UINT32_PUT(ctx, &buf, GRN_RECORD_VALUE(element));
+ }
+ if (element == &record) { GRN_OBJ_FIN(ctx, element); }
+ v = values_next(ctx, v);
+ }
+ } else {
+ if (((struct _grn_type *)range)->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ GRN_TEXT_INIT(&buf, GRN_OBJ_VECTOR);
+ while (n--) {
+ switch (v->header.domain) {
+ case GRN_DB_TEXT :
+ {
+ grn_bool cast_failed = GRN_FALSE;
+ grn_obj casted_element, *element = v;
+ if (range_id != element->header.domain) {
+ GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
+ if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
+ cast_failed = GRN_TRUE;
+ ERR_CAST(column, range, element);
+ }
+ element = &casted_element;
+ }
+ if (!cast_failed) {
+ grn_vector_add_element(ctx, &buf,
+ GRN_TEXT_VALUE(element),
+ GRN_TEXT_LEN(element),
+ 0,
+ element->header.domain);
+ }
+ if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
+ break;
+ }
+ case GRN_JSON_LOAD_OPEN_BRACE :
+ add_weight_vector(ctx, column, v, &buf);
+ n -= GRN_UINT32_VALUE(v);
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "array must contain string or object");
+ break;
+ }
+ v = values_next(ctx, v);
+ }
+ } else {
+ grn_id value_size = ((grn_db_obj *)range)->range;
+ GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, range_id);
+ while (n--) {
+ grn_bool cast_failed = GRN_FALSE;
+ grn_obj casted_element, *element = v;
+ if (range_id != element->header.domain) {
+ GRN_OBJ_INIT(&casted_element, GRN_BULK, 0, range_id);
+ if (grn_obj_cast(ctx, element, &casted_element, GRN_TRUE)) {
+ cast_failed = GRN_TRUE;
+ ERR_CAST(column, range, element);
+ }
+ element = &casted_element;
+ }
+ if (!cast_failed) {
+ grn_bulk_write(ctx, &buf, GRN_TEXT_VALUE(element), value_size);
+ }
+ if (element == &casted_element) { GRN_OBJ_FIN(ctx, element); }
+ v = values_next(ctx, v);
+ }
+ }
+ }
+ grn_obj_set_value(ctx, column, id, &buf, GRN_OBJ_SET);
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static void
+set_weight_vector(grn_ctx *ctx, grn_obj *column, grn_id id, grn_obj *value)
+{
+ if (!grn_obj_is_weight_vector_column(ctx, column)) {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ column_name_size = grn_obj_name(ctx, column, column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_INVALID_ARGUMENT,
+ "<%.*s>: columns except weight vector column don't support object value",
+ column_name_size, column_name);
+ return;
+ }
+
+ {
+ grn_obj vector;
+
+ GRN_TEXT_INIT(&vector, GRN_OBJ_VECTOR);
+ add_weight_vector(ctx, column, value, &vector);
+ grn_obj_set_value(ctx, column, id, &vector, GRN_OBJ_SET);
+ GRN_OBJ_FIN(ctx, &vector);
+ }
+}
+
+static inline int
+name_equal(const char *p, unsigned int size, const char *name)
+{
+ if (strlen(name) != size) { return 0; }
+ if (*p != GRN_DB_PSEUDO_COLUMN_PREFIX) { return 0; }
+ return !memcmp(p + 1, name + 1, size - 1);
+}
+
+static void
+report_set_column_value_failure(grn_ctx *ctx,
+ grn_obj *key,
+ const char *column_name,
+ unsigned int column_name_size,
+ grn_obj *column_value)
+{
+ grn_obj key_inspected, column_value_inspected;
+
+ GRN_TEXT_INIT(&key_inspected, 0);
+ GRN_TEXT_INIT(&column_value_inspected, 0);
+ grn_inspect_limited(ctx, &key_inspected, key);
+ grn_inspect_limited(ctx, &column_value_inspected, column_value);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "[table][load] failed to set column value: %s: "
+ "key: <%.*s>, column: <%.*s>, value: <%.*s>",
+ ctx->errbuf,
+ (int)GRN_TEXT_LEN(&key_inspected),
+ GRN_TEXT_VALUE(&key_inspected),
+ column_name_size,
+ column_name,
+ (int)GRN_TEXT_LEN(&column_value_inspected),
+ GRN_TEXT_VALUE(&column_value_inspected));
+ GRN_OBJ_FIN(ctx, &key_inspected);
+ GRN_OBJ_FIN(ctx, &column_value_inspected);
+}
+
+static grn_id
+parse_id_value(grn_ctx *ctx, grn_obj *value)
+{
+ switch (value->header.type) {
+ case GRN_DB_UINT32 :
+ return GRN_UINT32_VALUE(value);
+ case GRN_DB_INT32 :
+ return GRN_INT32_VALUE(value);
+ default :
+ {
+ grn_id id = GRN_ID_NIL;
+ grn_obj casted_value;
+ GRN_UINT32_INIT(&casted_value, 0);
+ if (grn_obj_cast(ctx, value, &casted_value, GRN_FALSE) != GRN_SUCCESS) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, value);
+ ERR(GRN_INVALID_ARGUMENT,
+ "<%s>: failed to cast to <UInt32>: <%.*s>",
+ GRN_COLUMN_NAME_ID,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ } else {
+ id = GRN_UINT32_VALUE(&casted_value);
+ }
+ GRN_OBJ_FIN(ctx, &casted_value);
+ return id;
+ }
+ }
+}
+
+static void
+bracket_close(grn_ctx *ctx, grn_loader *loader)
+{
+ grn_id id = GRN_ID_NIL;
+ grn_obj *value, *value_end, *id_value = NULL, *key_value = NULL;
+ grn_obj *col, **cols; /* Columns except _id and _key. */
+ uint32_t i, begin;
+ uint32_t ncols; /* Number of columns except _id and _key. */
+ uint32_t nvalues; /* Number of values in brackets. */
+ uint32_t depth;
+ grn_bool is_record_load = GRN_FALSE;
+
+ cols = (grn_obj **)GRN_BULK_HEAD(&loader->columns);
+ ncols = GRN_BULK_VSIZE(&loader->columns) / sizeof(grn_obj *);
+ GRN_UINT32_POP(&loader->level, begin);
+ value = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
+ value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
+ GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET);
+ GRN_UINT32_SET(ctx, value, loader->values_size - begin - 1);
+ value++;
+ depth = GRN_BULK_VSIZE(&loader->level);
+ if (depth > sizeof(uint32_t) * loader->emit_level) {
+ return;
+ }
+ if (depth == 0 || !loader->table ||
+ loader->columns_status == GRN_LOADER_COLUMNS_BROKEN) {
+ goto exit;
+ }
+ nvalues = values_len(ctx, value, value_end);
+
+ if (loader->columns_status == GRN_LOADER_COLUMNS_UNSET) {
+ /*
+ * Target columns and _id or _key are not specified yet and values are
+ * handled as column names and "_id" or "_key".
+ */
+ for (i = 0; i < nvalues; i++) {
+ const char *col_name;
+ unsigned int col_name_size;
+ if (value->header.domain != GRN_DB_TEXT) {
+ grn_obj buffer;
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_inspect(ctx, &buffer, value);
+ ERR(GRN_INVALID_ARGUMENT,
+ "column name must be string: <%.*s>",
+ (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ grn_loader_save_error(ctx, loader);
+ GRN_OBJ_FIN(ctx, &buffer);
+ loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
+ goto exit;
+ }
+ col_name = GRN_TEXT_VALUE(value);
+ col_name_size = GRN_TEXT_LEN(value);
+ col = grn_obj_column(ctx, loader->table, col_name, col_name_size);
+ if (!col) {
+ ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>",
+ col_name_size, col_name);
+ grn_loader_save_error(ctx, loader);
+ loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
+ goto exit;
+ }
+ if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_ID)) {
+ grn_obj_unlink(ctx, col);
+ if (loader->id_offset != -1 || loader->key_offset != -1) {
+ /* _id and _key must not appear more than once. */
+ if (loader->id_offset != -1) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_ID, i,
+ GRN_COLUMN_NAME_ID, loader->id_offset);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_ID, i,
+ GRN_COLUMN_NAME_KEY, loader->key_offset);
+ }
+ grn_loader_save_error(ctx, loader);
+ loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
+ goto exit;
+ }
+ loader->id_offset = i;
+ } else if (name_equal(col_name, col_name_size, GRN_COLUMN_NAME_KEY)) {
+ grn_obj_unlink(ctx, col);
+ if (loader->id_offset != -1 || loader->key_offset != -1) {
+ /* _id and _key must not appear more than once. */
+ if (loader->id_offset != -1) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_KEY, i,
+ GRN_COLUMN_NAME_ID, loader->id_offset);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_KEY, i,
+ GRN_COLUMN_NAME_KEY, loader->key_offset);
+ }
+ grn_loader_save_error(ctx, loader);
+ loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
+ goto exit;
+ }
+ loader->key_offset = i;
+ } else {
+ GRN_PTR_PUT(ctx, &loader->columns, col);
+ }
+ value++;
+ }
+ switch (loader->table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ if (loader->id_offset == -1 && loader->key_offset == -1) {
+ ERR(GRN_INVALID_ARGUMENT, "missing id or key column");
+ grn_loader_save_error(ctx, loader);
+ loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
+ goto exit;
+ }
+ break;
+ }
+ loader->columns_status = GRN_LOADER_COLUMNS_SET;
+ goto exit;
+ }
+
+ is_record_load = GRN_TRUE;
+
+ /* Target columns and _id or _key are already specified. */
+ if (!nvalues) {
+ /*
+ * Accept empty arrays because a dump command may output a load command
+ * which contains empty arrays for a table with deleted records.
+ */
+ id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
+ } else {
+ uint32_t expected_nvalues = ncols;
+ if (loader->id_offset != -1 || loader->key_offset != -1) {
+ expected_nvalues++;
+ }
+ if (nvalues != expected_nvalues) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "unexpected #values: expected:%u, actual:%u",
+ expected_nvalues, nvalues);
+ grn_loader_save_error(ctx, loader);
+ goto exit;
+ }
+ if (loader->id_offset != -1) {
+ id_value = value + loader->id_offset;
+ id = parse_id_value(ctx, id_value);
+ if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
+ id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
+ }
+ } else if (loader->key_offset != -1) {
+ key_value = value + loader->key_offset;
+ id = loader_add(ctx, key_value);
+ } else {
+ id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
+ }
+ }
+ if (id == GRN_ID_NIL) {
+ /* Target record is not available. */
+ goto exit;
+ }
+
+ for (i = 0; i < nvalues; i++, value = values_next(ctx, value)) {
+ if ((uint) i == (uint) loader->id_offset ||
+ (uint) i == (uint) loader->key_offset) {
+ /* Skip _id and _key, because it's already used to get id. */
+ continue;
+ }
+ col = *cols;
+ if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
+ set_vector(ctx, col, id, value);
+ } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
+ set_weight_vector(ctx, col, id, value);
+ } else {
+ grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
+ }
+ if (ctx->rc != GRN_SUCCESS) {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int column_name_size;
+ grn_loader_save_error(ctx, loader);
+ column_name_size = grn_obj_name(ctx, col, column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ report_set_column_value_failure(ctx, key_value,
+ column_name, column_name_size,
+ value);
+ ERRCLR(ctx);
+ }
+ cols++;
+ }
+ if (loader->each) {
+ grn_obj *v = grn_expr_get_var_by_offset(ctx, loader->each, 0);
+ GRN_RECORD_SET(ctx, v, id);
+ grn_expr_exec(ctx, loader->each, 0);
+ }
+ loader->nrecords++;
+exit:
+ if (is_record_load) {
+ if (loader->output_ids) {
+ GRN_UINT32_PUT(ctx, &(loader->ids), id);
+ }
+ if (loader->output_errors) {
+ GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
+ grn_vector_add_element(ctx,
+ &(loader->error_messages),
+ ctx->errbuf,
+ strlen(ctx->errbuf),
+ 0,
+ GRN_DB_TEXT);
+ }
+ }
+ loader->values_size = begin;
+ ERRCLR(ctx);
+}
+
+static void
+brace_close(grn_ctx *ctx, grn_loader *loader)
+{
+ grn_id id = GRN_ID_NIL;
+ grn_obj *value, *value_begin, *value_end;
+ grn_obj *id_value = NULL, *key_value = NULL;
+ uint32_t begin;
+
+ GRN_UINT32_POP(&loader->level, begin);
+ value_begin = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + begin;
+ value_end = (grn_obj *)GRN_TEXT_VALUE(&loader->values) + loader->values_size;
+ GRN_ASSERT(value->header.domain == GRN_JSON_LOAD_OPEN_BRACE);
+ GRN_UINT32_SET(ctx, value_begin, loader->values_size - begin - 1);
+ value_begin++;
+ if ((size_t) GRN_BULK_VSIZE(&loader->level) > sizeof(uint32_t) * loader->emit_level) {
+ return;
+ }
+ if (!loader->table) {
+ goto exit;
+ }
+
+ /* Scan values to find _id or _key. */
+ for (value = value_begin; value + 1 < value_end;
+ value = values_next(ctx, value)) {
+ const char *name = GRN_TEXT_VALUE(value);
+ unsigned int name_size = GRN_TEXT_LEN(value);
+ if (value->header.domain != GRN_DB_TEXT) {
+ grn_obj buffer;
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_inspect(ctx, &buffer, value);
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "column name must be string: <%.*s>",
+ (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+ goto exit;
+ }
+ value++;
+ if (name_equal(name, name_size, GRN_COLUMN_NAME_ID)) {
+ if (id_value || key_value) {
+ if (loader->table->header.type == GRN_TABLE_NO_KEY) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "duplicated '_id' column");
+ goto exit;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "duplicated key columns: %s and %s",
+ id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_ID);
+ goto exit;
+ }
+ }
+ id_value = value;
+ } else if (name_equal(name, name_size, GRN_COLUMN_NAME_KEY)) {
+ if (id_value || key_value) {
+ GRN_LOG(ctx, GRN_LOG_ERROR,
+ "duplicated key columns: %s and %s",
+ id_value ? GRN_COLUMN_NAME_ID : GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY);
+ goto exit;
+ }
+ key_value = value;
+ }
+ }
+
+ switch (loader->table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ /* The target table requires _id or _key. */
+ if (!id_value && !key_value) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "neither _key nor _id is assigned");
+ goto exit;
+ }
+ break;
+ default :
+ /* The target table does not have _key. */
+ if (key_value) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "nonexistent key value");
+ goto exit;
+ }
+ break;
+ }
+
+ if (id_value) {
+ id = parse_id_value(ctx, id_value);
+ if (grn_table_at(ctx, loader->table, id) == GRN_ID_NIL) {
+ if (ctx->rc == GRN_SUCCESS) {
+ id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
+ }
+ }
+ } else if (key_value) {
+ id = loader_add(ctx, key_value);
+ } else {
+ id = grn_table_add(ctx, loader->table, NULL, 0, NULL);
+ }
+ if (id == GRN_ID_NIL) {
+ /* Target record is not available. */
+ goto exit;
+ }
+
+ for (value = value_begin; value + 1 < value_end;
+ value = values_next(ctx, value)) {
+ grn_obj *col;
+ const char *name = GRN_TEXT_VALUE(value);
+ unsigned int name_size = GRN_TEXT_LEN(value);
+ value++;
+ if (value == id_value || value == key_value) {
+ /* Skip _id and _key, because it's already used to get id. */
+ continue;
+ }
+ col = grn_obj_column(ctx, loader->table, name, name_size);
+ if (!col) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "invalid column('%.*s')",
+ (int)name_size, name);
+ /* Automatic column creation is disabled. */
+ /*
+ if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
+ grn_obj *v = value + 1;
+ col = grn_column_create(ctx, loader->table, name, name_size,
+ NULL, GRN_OBJ_PERSISTENT|GRN_OBJ_COLUMN_VECTOR,
+ grn_ctx_at(ctx, v->header.domain));
+ } else {
+ col = grn_column_create(ctx, loader->table, name, name_size,
+ NULL, GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx, value->header.domain));
+ }
+ */
+ } else {
+ if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACKET) {
+ set_vector(ctx, col, id, value);
+ } else if (value->header.domain == GRN_JSON_LOAD_OPEN_BRACE) {
+ set_weight_vector(ctx, col, id, value);
+ } else {
+ grn_obj_set_value(ctx, col, id, value, GRN_OBJ_SET);
+ }
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_loader_save_error(ctx, loader);
+ report_set_column_value_failure(ctx, key_value,
+ name, name_size, value);
+ ERRCLR(ctx);
+ }
+ grn_obj_unlink(ctx, col);
+ }
+ }
+ if (loader->each) {
+ value = grn_expr_get_var_by_offset(ctx, loader->each, 0);
+ GRN_RECORD_SET(ctx, value, id);
+ grn_expr_exec(ctx, loader->each, 0);
+ }
+ loader->nrecords++;
+exit:
+ if (loader->output_ids) {
+ GRN_UINT32_PUT(ctx, &(loader->ids), id);
+ }
+ if (loader->output_errors) {
+ GRN_INT32_PUT(ctx, &(loader->return_codes), ctx->rc);
+ grn_vector_add_element(ctx,
+ &(loader->error_messages),
+ ctx->errbuf,
+ strlen(ctx->errbuf),
+ 0,
+ GRN_DB_TEXT);
+ }
+ loader->values_size = begin;
+ ERRCLR(ctx);
+}
+
+#define JSON_READ_OPEN_BRACKET() do {\
+ GRN_UINT32_PUT(ctx, &loader->level, loader->values_size);\
+ values_add(ctx, loader);\
+ loader->last->header.domain = GRN_JSON_LOAD_OPEN_BRACKET;\
+ loader->stat = GRN_LOADER_TOKEN;\
+ str++;\
+} while (0)
+
+#define JSON_READ_OPEN_BRACE() do {\
+ GRN_UINT32_PUT(ctx, &loader->level, loader->values_size);\
+ values_add(ctx, loader);\
+ loader->last->header.domain = GRN_JSON_LOAD_OPEN_BRACE;\
+ loader->stat = GRN_LOADER_TOKEN;\
+ str++;\
+} while (0)
+
+static void
+json_read(grn_ctx *ctx, grn_loader *loader, const char *str, unsigned int str_len)
+{
+ const char *const beg = str;
+ char c;
+ int len;
+ const char *se = str + str_len;
+ while (str < se) {
+ c = *str;
+ switch (loader->stat) {
+ case GRN_LOADER_BEGIN :
+ if ((len = grn_isspace(str, ctx->encoding))) {
+ str += len;
+ continue;
+ }
+ switch (c) {
+ case '[' :
+ JSON_READ_OPEN_BRACKET();
+ break;
+ case '{' :
+ JSON_READ_OPEN_BRACE();
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT,
+ "JSON must start with '[' or '{': <%.*s>", str_len, beg);
+ loader->stat = GRN_LOADER_END;
+ break;
+ }
+ break;
+ case GRN_LOADER_TOKEN :
+ if ((len = grn_isspace(str, ctx->encoding))) {
+ str += len;
+ continue;
+ }
+ switch (c) {
+ case '"' :
+ loader->stat = GRN_LOADER_STRING;
+ values_add(ctx, loader);
+ str++;
+ break;
+ case '[' :
+ JSON_READ_OPEN_BRACKET();
+ break;
+ case '{' :
+ JSON_READ_OPEN_BRACE();
+ break;
+ case ':' :
+ str++;
+ break;
+ case ',' :
+ str++;
+ break;
+ case ']' :
+ bracket_close(ctx, loader);
+ loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
+ if (ctx->rc == GRN_CANCEL) {
+ loader->stat = GRN_LOADER_END;
+ }
+ str++;
+ break;
+ case '}' :
+ brace_close(ctx, loader);
+ loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
+ if (ctx->rc == GRN_CANCEL) {
+ loader->stat = GRN_LOADER_END;
+ }
+ str++;
+ break;
+ case '+' : case '-' : case '0' : case '1' : case '2' : case '3' :
+ case '4' : case '5' : case '6' : case '7' : case '8' : case '9' :
+ loader->stat = GRN_LOADER_NUMBER;
+ values_add(ctx, loader);
+ break;
+ default :
+ if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') || ('_' == c)) {
+ loader->stat = GRN_LOADER_SYMBOL;
+ values_add(ctx, loader);
+ } else {
+ if ((len = grn_charlen(ctx, str, se))) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char('%c') at", c);
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg) + len, beg);
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%*s", (int)(str - beg) + 1, "^");
+ str += len;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char(\\x%.2x) after", c);
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg), beg);
+ str = se;
+ }
+ }
+ break;
+ }
+ break;
+ case GRN_LOADER_SYMBOL :
+ if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
+ ('0' <= c && c <= '9') || ('_' == c)) {
+ GRN_TEXT_PUTC(ctx, loader->last, c);
+ str++;
+ } else {
+ char *v = GRN_TEXT_VALUE(loader->last);
+ switch (*v) {
+ case 'n' :
+ if (GRN_TEXT_LEN(loader->last) == 4 && !memcmp(v, "null", 4)) {
+ loader->last->header.domain = GRN_DB_VOID;
+ GRN_BULK_REWIND(loader->last);
+ }
+ break;
+ case 't' :
+ if (GRN_TEXT_LEN(loader->last) == 4 && !memcmp(v, "true", 4)) {
+ loader->last->header.domain = GRN_DB_BOOL;
+ GRN_BOOL_SET(ctx, loader->last, GRN_TRUE);
+ }
+ break;
+ case 'f' :
+ if (GRN_TEXT_LEN(loader->last) == 5 && !memcmp(v, "false", 5)) {
+ loader->last->header.domain = GRN_DB_BOOL;
+ GRN_BOOL_SET(ctx, loader->last, GRN_FALSE);
+ }
+ break;
+ default :
+ break;
+ }
+ loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
+ }
+ break;
+ case GRN_LOADER_NUMBER :
+ switch (c) {
+ case '+' : case '-' : case '.' : case 'e' : case 'E' :
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ GRN_TEXT_PUTC(ctx, loader->last, c);
+ str++;
+ break;
+ default :
+ {
+ const char *cur, *str = GRN_BULK_HEAD(loader->last);
+ const char *str_end = GRN_BULK_CURR(loader->last);
+ int64_t i = grn_atoll(str, str_end, &cur);
+ if (cur == str_end) {
+ loader->last->header.domain = GRN_DB_INT64;
+ GRN_INT64_SET(ctx, loader->last, i);
+ } else if (cur != str) {
+ uint64_t i = grn_atoull(str, str_end, &cur);
+ if (cur == str_end) {
+ loader->last->header.domain = GRN_DB_UINT64;
+ GRN_UINT64_SET(ctx, loader->last, i);
+ } else if (cur != str) {
+ double d;
+ char *end;
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUT(ctx, &buf, str, GRN_BULK_VSIZE(loader->last));
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ errno = 0;
+ d = strtod(GRN_TEXT_VALUE(&buf), &end);
+ if (!errno && end + 1 == GRN_BULK_CURR(&buf)) {
+ loader->last->header.domain = GRN_DB_FLOAT;
+ GRN_FLOAT_SET(ctx, loader->last, d);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+ }
+ }
+ }
+ loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
+ break;
+ }
+ break;
+ case GRN_LOADER_STRING :
+ switch (c) {
+ case '\\' :
+ loader->stat = GRN_LOADER_STRING_ESC;
+ str++;
+ break;
+ case '"' :
+ str++;
+ loader->stat = GRN_BULK_VSIZE(&loader->level) ? GRN_LOADER_TOKEN : GRN_LOADER_END;
+ /*
+ *(GRN_BULK_CURR(loader->last)) = '\0';
+ GRN_LOG(ctx, GRN_LOG_ALERT, "read str(%s)", GRN_TEXT_VALUE(loader->last));
+ */
+ break;
+ default :
+ if ((len = grn_charlen(ctx, str, se))) {
+ GRN_TEXT_PUT(ctx, loader->last, str, len);
+ str += len;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "ignored invalid char(\\x%.2x) after", c);
+ GRN_LOG(ctx, GRN_LOG_ERROR, "%.*s", (int)(str - beg), beg);
+ str = se;
+ }
+ break;
+ }
+ break;
+ case GRN_LOADER_STRING_ESC :
+ switch (c) {
+ case 'b' :
+ GRN_TEXT_PUTC(ctx, loader->last, '\b');
+ loader->stat = GRN_LOADER_STRING;
+ break;
+ case 'f' :
+ GRN_TEXT_PUTC(ctx, loader->last, '\f');
+ loader->stat = GRN_LOADER_STRING;
+ break;
+ case 'n' :
+ GRN_TEXT_PUTC(ctx, loader->last, '\n');
+ loader->stat = GRN_LOADER_STRING;
+ break;
+ case 'r' :
+ GRN_TEXT_PUTC(ctx, loader->last, '\r');
+ loader->stat = GRN_LOADER_STRING;
+ break;
+ case 't' :
+ GRN_TEXT_PUTC(ctx, loader->last, '\t');
+ loader->stat = GRN_LOADER_STRING;
+ break;
+ case 'u' :
+ loader->stat = GRN_LOADER_UNICODE0;
+ break;
+ default :
+ GRN_TEXT_PUTC(ctx, loader->last, c);
+ loader->stat = GRN_LOADER_STRING;
+ break;
+ }
+ str++;
+ break;
+ case GRN_LOADER_UNICODE0 :
+ switch (c) {
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ loader->unichar = (c - '0') * 0x1000;
+ break;
+ case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
+ loader->unichar = (c - 'a' + 10) * 0x1000;
+ break;
+ case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
+ loader->unichar = (c - 'A' + 10) * 0x1000;
+ break;
+ default :
+ ;// todo : error
+ }
+ loader->stat = GRN_LOADER_UNICODE1;
+ str++;
+ break;
+ case GRN_LOADER_UNICODE1 :
+ switch (c) {
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ loader->unichar += (c - '0') * 0x100;
+ break;
+ case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
+ loader->unichar += (c - 'a' + 10) * 0x100;
+ break;
+ case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
+ loader->unichar += (c - 'A' + 10) * 0x100;
+ break;
+ default :
+ ;// todo : error
+ }
+ loader->stat = GRN_LOADER_UNICODE2;
+ str++;
+ break;
+ case GRN_LOADER_UNICODE2 :
+ switch (c) {
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ loader->unichar += (c - '0') * 0x10;
+ break;
+ case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
+ loader->unichar += (c - 'a' + 10) * 0x10;
+ break;
+ case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
+ loader->unichar += (c - 'A' + 10) * 0x10;
+ break;
+ default :
+ ;// todo : error
+ }
+ loader->stat = GRN_LOADER_UNICODE3;
+ str++;
+ break;
+ case GRN_LOADER_UNICODE3 :
+ switch (c) {
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ loader->unichar += (c - '0');
+ break;
+ case 'a' : case 'b' : case 'c' : case 'd' : case 'e' : case 'f' :
+ loader->unichar += (c - 'a' + 10);
+ break;
+ case 'A' : case 'B' : case 'C' : case 'D' : case 'E' : case 'F' :
+ loader->unichar += (c - 'A' + 10);
+ break;
+ default :
+ ;// todo : error
+ }
+ {
+ uint32_t u = loader->unichar;
+ if (u < 0x80) {
+ GRN_TEXT_PUTC(ctx, loader->last, u);
+ } else {
+ if (u < 0x800) {
+ GRN_TEXT_PUTC(ctx, loader->last, ((u >> 6) & 0x1f) | 0xc0);
+ } else {
+ GRN_TEXT_PUTC(ctx, loader->last, (u >> 12) | 0xe0);
+ GRN_TEXT_PUTC(ctx, loader->last, ((u >> 6) & 0x3f) | 0x80);
+ }
+ GRN_TEXT_PUTC(ctx, loader->last, (u & 0x3f) | 0x80);
+ }
+ }
+ loader->stat = GRN_LOADER_STRING;
+ str++;
+ break;
+ case GRN_LOADER_END :
+ str = se;
+ break;
+ }
+ }
+}
+
+#undef JSON_READ_OPEN_BRACKET
+#undef JSON_READ_OPEN_BRACE
+
+/*
+ * grn_loader_parse_columns parses a columns parameter.
+ * Columns except _id and _key are appended to loader->columns.
+ * If it contains _id or _key, loader->id_offset or loader->key_offset is set.
+ */
+static grn_rc
+grn_loader_parse_columns(grn_ctx *ctx, grn_loader *loader,
+ const char *str, unsigned int str_size)
+{
+ const char *ptr = str, *ptr_end = ptr + str_size, *rest;
+ const char *tokens[256], *token_end;
+ while (ptr < ptr_end) {
+ int i, n = grn_tokenize(ptr, ptr_end - ptr, tokens, 256, &rest);
+ for (i = 0; i < n; i++) {
+ grn_obj *column;
+ token_end = tokens[i];
+ while (ptr < token_end && (' ' == *ptr || ',' == *ptr)) {
+ ptr++;
+ }
+ column = grn_obj_column(ctx, loader->table, ptr, token_end - ptr);
+ if (!column) {
+ ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s>",
+ (int)(token_end - ptr), ptr);
+ return ctx->rc;
+ }
+ if (name_equal(ptr, token_end - ptr, GRN_COLUMN_NAME_ID)) {
+ grn_obj_unlink(ctx, column);
+ if (loader->id_offset != -1 || loader->key_offset != -1) {
+ /* _id and _key must not appear more than once. */
+ if (loader->id_offset != -1) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_ID, i,
+ GRN_COLUMN_NAME_ID, loader->id_offset);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_ID, i,
+ GRN_COLUMN_NAME_KEY, loader->key_offset);
+ }
+ return ctx->rc;
+ }
+ loader->id_offset = i;
+ } else if (name_equal(ptr, token_end - ptr, GRN_COLUMN_NAME_KEY)) {
+ grn_obj_unlink(ctx, column);
+ if (loader->id_offset != -1 || loader->key_offset != -1) {
+ /* _id and _key must not appear more than once. */
+ if (loader->id_offset != -1) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_KEY, i,
+ GRN_COLUMN_NAME_ID, loader->id_offset);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "duplicated id and key columns: <%s> at %d and <%s> at %d",
+ GRN_COLUMN_NAME_KEY, i,
+ GRN_COLUMN_NAME_KEY, loader->key_offset);
+ }
+ return ctx->rc;
+ }
+ loader->key_offset = i;
+ } else {
+ GRN_PTR_PUT(ctx, &loader->columns, column);
+ }
+ ptr = token_end;
+ }
+ ptr = rest;
+ }
+ switch (loader->table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ if (loader->id_offset == -1 && loader->key_offset == -1) {
+ ERR(GRN_INVALID_ARGUMENT, "missing id or key column");
+ return ctx->rc;
+ }
+ break;
+ }
+ return ctx->rc;
+}
+
+static grn_com_addr *addr;
+
+void
+grn_load_internal(grn_ctx *ctx, grn_load_input *input)
+{
+ grn_loader *loader = &ctx->impl->loader;
+
+ loader->emit_level = input->emit_level;
+ if (ctx->impl->edge) {
+ grn_edge *edge = grn_edges_add_communicator(ctx, addr);
+ grn_obj *msg = grn_msg_open(ctx, edge->com, &ctx->impl->edge->send_old);
+ /* build msg */
+ grn_edge_dispatch(ctx, edge, msg);
+ }
+ if (input->table.length > 0) {
+ grn_ctx_loader_clear(ctx);
+ loader->input_type = input->type;
+ if (grn_db_check_name(ctx, input->table.value, input->table.length)) {
+ GRN_DB_CHECK_NAME_ERR("[table][load]",
+ input->table.value,
+ (int)(input->table.length));
+ loader->stat = GRN_LOADER_END;
+ return;
+ }
+ loader->table = grn_ctx_get(ctx, input->table.value, input->table.length);
+ if (!loader->table) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "nonexistent table: <%.*s>",
+ (int)(input->table.length),
+ input->table.value);
+ loader->stat = GRN_LOADER_END;
+ return;
+ }
+ if (input->columns.length > 0) {
+ grn_rc rc = grn_loader_parse_columns(ctx,
+ loader,
+ input->columns.value,
+ input->columns.length);
+ if (rc != GRN_SUCCESS) {
+ loader->columns_status = GRN_LOADER_COLUMNS_BROKEN;
+ loader->stat = GRN_LOADER_END;
+ return;
+ }
+ loader->columns_status = GRN_LOADER_COLUMNS_SET;
+ }
+ if (input->if_exists.length > 0) {
+ grn_obj *v;
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, loader->table, loader->ifexists, v);
+ if (loader->ifexists && v) {
+ grn_expr_parse(ctx,
+ loader->ifexists,
+ input->if_exists.value,
+ input->if_exists.length,
+ NULL, GRN_OP_EQUAL, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT|GRN_EXPR_ALLOW_UPDATE);
+ }
+ }
+ if (input->each.length > 0) {
+ grn_obj *v;
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, loader->table, loader->each, v);
+ if (loader->each && v) {
+ grn_expr_parse(ctx, loader->each,
+ input->each.value,
+ input->each.length,
+ NULL, GRN_OP_EQUAL, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT|GRN_EXPR_ALLOW_UPDATE);
+ }
+ }
+ loader->output_ids = input->output_ids;
+ loader->output_errors = input->output_errors;
+ } else {
+ if (!loader->table) {
+ ERR(GRN_INVALID_ARGUMENT, "mandatory \"table\" parameter is absent");
+ loader->stat = GRN_LOADER_END;
+ return;
+ }
+ }
+ switch (loader->input_type) {
+ case GRN_CONTENT_JSON :
+ json_read(ctx, loader, input->values.value, input->values.length);
+ break;
+ case GRN_CONTENT_NONE :
+ case GRN_CONTENT_TSV :
+ case GRN_CONTENT_XML :
+ case GRN_CONTENT_MSGPACK :
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "unsupported input_type");
+ loader->stat = GRN_LOADER_END;
+ // todo
+ break;
+ }
+}
+
+grn_rc
+grn_load(grn_ctx *ctx, grn_content_type input_type,
+ const char *table, unsigned int table_len,
+ const char *columns, unsigned int columns_len,
+ const char *values, unsigned int values_len,
+ const char *ifexists, unsigned int ifexists_len,
+ const char *each, unsigned int each_len)
+{
+ if (!ctx || !ctx->impl) {
+ ERR(GRN_INVALID_ARGUMENT, "db not initialized");
+ return ctx->rc;
+ }
+ GRN_API_ENTER;
+ {
+ grn_load_input input;
+ input.type = input_type;
+ input.table.value = table;
+ input.table.length = table_len;
+ input.columns.value = columns;
+ input.columns.length = columns_len;
+ input.values.value = values;
+ input.values.length = values_len;
+ input.if_exists.value = ifexists;
+ input.if_exists.length = ifexists_len;
+ input.each.value = each;
+ input.each.length = each_len;
+ input.output_ids = GRN_FALSE;
+ input.output_errors = GRN_FALSE;
+ input.emit_level = 1;
+ grn_load_internal(ctx, &input);
+ }
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/logger.c b/storage/mroonga/vendor/groonga/lib/logger.c
new file mode 100644
index 00000000..da3dd3e7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/logger.c
@@ -0,0 +1,810 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_logger.h"
+#include "grn_ctx.h"
+#include "grn_ctx_impl.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <share.h>
+#endif /* WIN32 */
+
+static const char *log_level_names[] = {
+ "none",
+ "emergency",
+ "alert",
+ "critical",
+ "error",
+ "warning",
+ "notice",
+ "info",
+ "debug",
+ "dump"
+};
+
+#define GRN_LOG_LAST GRN_LOG_DUMP
+
+const char *
+grn_log_level_to_string(grn_log_level level)
+{
+ if (level <= GRN_LOG_LAST) {
+ return log_level_names[level];
+ } else {
+ return "unknown";
+ }
+}
+
+grn_bool
+grn_log_level_parse(const char *string, grn_log_level *level)
+{
+ if (strcmp(string, " ") == 0 ||
+ grn_strcasecmp(string, "none") == 0) {
+ *level = GRN_LOG_NONE;
+ return GRN_TRUE;
+ } else if (strcmp(string, "E") == 0 ||
+ grn_strcasecmp(string, "emerg") == 0 ||
+ grn_strcasecmp(string, "emergency") == 0) {
+ *level = GRN_LOG_EMERG;
+ return GRN_TRUE;
+ } else if (strcmp(string, "A") == 0 ||
+ grn_strcasecmp(string, "alert") == 0) {
+ *level = GRN_LOG_ALERT;
+ return GRN_TRUE;
+ } else if (strcmp(string, "C") == 0 ||
+ grn_strcasecmp(string, "crit") == 0 ||
+ grn_strcasecmp(string, "critical") == 0) {
+ *level = GRN_LOG_CRIT;
+ return GRN_TRUE;
+ } else if (strcmp(string, "e") == 0 ||
+ grn_strcasecmp(string, "error") == 0) {
+ *level = GRN_LOG_ERROR;
+ return GRN_TRUE;
+ } else if (strcmp(string, "w") == 0 ||
+ grn_strcasecmp(string, "warn") == 0 ||
+ grn_strcasecmp(string, "warning") == 0) {
+ *level = GRN_LOG_WARNING;
+ return GRN_TRUE;
+ } else if (strcmp(string, "n") == 0 ||
+ grn_strcasecmp(string, "notice") == 0) {
+ *level = GRN_LOG_NOTICE;
+ return GRN_TRUE;
+ } else if (strcmp(string, "i") == 0 ||
+ grn_strcasecmp(string, "info") == 0) {
+ *level = GRN_LOG_INFO;
+ return GRN_TRUE;
+ } else if (strcmp(string, "d") == 0 ||
+ grn_strcasecmp(string, "debug") == 0) {
+ *level = GRN_LOG_DEBUG;
+ return GRN_TRUE;
+ } else if (strcmp(string, "-") == 0 ||
+ grn_strcasecmp(string, "dump") == 0) {
+ *level = GRN_LOG_DUMP;
+ return GRN_TRUE;
+ } else {
+ return GRN_FALSE;
+ }
+}
+
+static void
+rotate_log_file(grn_ctx *ctx, const char *current_path)
+{
+ char rotated_path[PATH_MAX];
+ grn_timeval now;
+ struct tm tm_buffer;
+ struct tm *tm;
+
+ grn_timeval_now(ctx, &now);
+ tm = grn_timeval2tm(ctx, &now, &tm_buffer);
+ grn_snprintf(rotated_path, PATH_MAX, PATH_MAX,
+ "%s.%04d-%02d-%02d-%02d-%02d-%02d-%06d",
+ current_path,
+ tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ (int)(GRN_TIME_NSEC_TO_USEC(now.tv_nsec)));
+ rename(current_path, rotated_path);
+}
+
+static grn_bool logger_inited = GRN_FALSE;
+static char *default_logger_path = NULL;
+static FILE *default_logger_file = NULL;
+static grn_critical_section default_logger_lock;
+static off_t default_logger_size = 0;
+static off_t default_logger_rotate_threshold_size = 0;
+
+#define LOGGER_NEED_ROTATE(size, threshold) \
+ ((threshold) > 0 && (size) >= (threshold))
+
+static void
+default_logger_log(grn_ctx *ctx, grn_log_level level,
+ const char *timestamp, const char *title,
+ const char *message, const char *location, void *user_data)
+{
+ const char slev[] = " EACewnid-";
+ if (default_logger_path) {
+ CRITICAL_SECTION_ENTER(default_logger_lock);
+ if (!default_logger_file) {
+ default_logger_file = grn_fopen(default_logger_path, "a");
+ default_logger_size = 0;
+ if (default_logger_file) {
+ struct stat stat;
+ if (fstat(grn_fileno(default_logger_file), &stat) != -1) {
+ default_logger_size = stat.st_size;
+ }
+ }
+ }
+ if (default_logger_file) {
+ char label = *(slev + level);
+ int written;
+ if (location && *location) {
+ if (title && *title) {
+ written = fprintf(default_logger_file, "%s|%c|%s: %s %s\n",
+ timestamp, label, location, title, message);
+ } else {
+ written = fprintf(default_logger_file, "%s|%c|%s: %s\n",
+ timestamp, label, location, message);
+ }
+ } else {
+ written = fprintf(default_logger_file, "%s|%c|%s %s\n",
+ timestamp, label, title, message);
+ }
+ if (written > 0) {
+ default_logger_size += written;
+ if (LOGGER_NEED_ROTATE(default_logger_size,
+ default_logger_rotate_threshold_size)) {
+ fclose(default_logger_file);
+ default_logger_file = NULL;
+ rotate_log_file(ctx, default_logger_path);
+ } else {
+ fflush(default_logger_file);
+ }
+ }
+ }
+ CRITICAL_SECTION_LEAVE(default_logger_lock);
+ }
+}
+
+static void
+default_logger_reopen(grn_ctx *ctx, void *user_data)
+{
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "log will be closed.");
+ CRITICAL_SECTION_ENTER(default_logger_lock);
+ if (default_logger_file) {
+ fclose(default_logger_file);
+ default_logger_file = NULL;
+ }
+ CRITICAL_SECTION_LEAVE(default_logger_lock);
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "log opened.");
+}
+
+static void
+default_logger_fin(grn_ctx *ctx, void *user_data)
+{
+ CRITICAL_SECTION_ENTER(default_logger_lock);
+ if (default_logger_file) {
+ fclose(default_logger_file);
+ default_logger_file = NULL;
+ }
+ CRITICAL_SECTION_LEAVE(default_logger_lock);
+}
+
+static grn_logger default_logger = {
+ GRN_LOG_DEFAULT_LEVEL,
+ GRN_LOG_TIME|GRN_LOG_MESSAGE,
+ NULL,
+ default_logger_log,
+ default_logger_reopen,
+ default_logger_fin
+};
+
+#define INITIAL_LOGGER { \
+ GRN_LOG_DEFAULT_LEVEL, \
+ GRN_LOG_TIME|GRN_LOG_MESSAGE, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL \
+}
+
+static grn_logger current_logger = INITIAL_LOGGER;
+
+void
+grn_default_logger_set_max_level(grn_log_level max_level)
+{
+ default_logger.max_level = max_level;
+ if (current_logger.log == default_logger_log) {
+ current_logger.max_level = max_level;
+ }
+}
+
+grn_log_level
+grn_default_logger_get_max_level(void)
+{
+ return default_logger.max_level;
+}
+
+void
+grn_default_logger_set_flags(int flags)
+{
+ default_logger.flags = flags;
+ if (current_logger.log == default_logger_log) {
+ current_logger.flags = flags;
+ }
+}
+
+int
+grn_default_logger_get_flags(void)
+{
+ return default_logger.flags;
+}
+
+void
+grn_default_logger_set_path(const char *path)
+{
+ if (logger_inited) {
+ CRITICAL_SECTION_ENTER(default_logger_lock);
+ }
+
+ if (default_logger_path) {
+ free(default_logger_path);
+ }
+
+ if (path) {
+ default_logger_path = grn_strdup_raw(path);
+ } else {
+ default_logger_path = NULL;
+ }
+
+ if (logger_inited) {
+ CRITICAL_SECTION_LEAVE(default_logger_lock);
+ }
+}
+
+const char *
+grn_default_logger_get_path(void)
+{
+ return default_logger_path;
+}
+
+void
+grn_default_logger_set_rotate_threshold_size(off_t threshold)
+{
+ default_logger_rotate_threshold_size = threshold;
+}
+
+off_t
+grn_default_logger_get_rotate_threshold_size(void)
+{
+ return default_logger_rotate_threshold_size;
+}
+
+void
+grn_logger_reopen(grn_ctx *ctx)
+{
+ if (current_logger.reopen) {
+ current_logger.reopen(ctx, current_logger.user_data);
+ }
+}
+
+static void
+current_logger_fin(grn_ctx *ctx)
+{
+ if (current_logger.fin) {
+ current_logger.fin(ctx, current_logger.user_data);
+ }
+ {
+ grn_logger initial_logger = INITIAL_LOGGER;
+ current_logger = initial_logger;
+ }
+}
+
+static void
+logger_info_func_wrapper(grn_ctx *ctx, grn_log_level level,
+ const char *timestamp, const char *title,
+ const char *message, const char *location,
+ void *user_data)
+{
+ grn_logger_info *info = user_data;
+ info->func(level, timestamp, title, message, location, info->func_arg);
+}
+
+/* Deprecated since 2.1.2. */
+grn_rc
+grn_logger_info_set(grn_ctx *ctx, const grn_logger_info *info)
+{
+ if (info) {
+ grn_logger logger;
+
+ memset(&logger, 0, sizeof(grn_logger));
+ logger.max_level = info->max_level;
+ logger.flags = info->flags;
+ if (info->func) {
+ logger.log = logger_info_func_wrapper;
+ logger.user_data = (grn_logger_info *)info;
+ } else {
+ logger.log = default_logger_log;
+ logger.reopen = default_logger_reopen;
+ logger.fin = default_logger_fin;
+ }
+ return grn_logger_set(ctx, &logger);
+ } else {
+ return grn_logger_set(ctx, NULL);
+ }
+}
+
+grn_rc
+grn_logger_set(grn_ctx *ctx, const grn_logger *logger)
+{
+ current_logger_fin(ctx);
+ if (logger) {
+ current_logger = *logger;
+ } else {
+ current_logger = default_logger;
+ }
+ return GRN_SUCCESS;
+}
+
+void
+grn_logger_set_max_level(grn_ctx *ctx, grn_log_level max_level)
+{
+ current_logger.max_level = max_level;
+}
+
+grn_log_level
+grn_logger_get_max_level(grn_ctx *ctx)
+{
+ return current_logger.max_level;
+}
+
+grn_bool
+grn_logger_pass(grn_ctx *ctx, grn_log_level level)
+{
+ return level <= current_logger.max_level;
+}
+
+#define TBUFSIZE GRN_TIMEVAL_STR_SIZE
+#define MBUFSIZE 0x1000
+#define LBUFSIZE 0x400
+
+void
+grn_logger_put(grn_ctx *ctx,
+ grn_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt,
+ ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ grn_logger_putv(ctx, level, file, line, func, fmt, ap);
+ va_end(ap);
+}
+
+void
+grn_logger_putv(grn_ctx *ctx,
+ grn_log_level level,
+ const char *file,
+ int line,
+ const char *func,
+ const char *fmt,
+ va_list ap)
+{
+ if (level <= current_logger.max_level && current_logger.log) {
+ char tbuf[TBUFSIZE];
+ char mbuf[MBUFSIZE];
+ char lbuf[LBUFSIZE];
+ tbuf[0] = '\0';
+ if (current_logger.flags & GRN_LOG_TIME) {
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ grn_timeval2str(ctx, &tv, tbuf, TBUFSIZE);
+ }
+ if (current_logger.flags & GRN_LOG_MESSAGE) {
+ grn_vsnprintf(mbuf, MBUFSIZE, fmt, ap);
+ } else {
+ mbuf[0] = '\0';
+ }
+ if (current_logger.flags & GRN_LOG_LOCATION) {
+ grn_snprintf(lbuf, LBUFSIZE, LBUFSIZE,
+ "%d %s:%d %s()", grn_getpid(), file, line, func);
+ } else if (current_logger.flags & GRN_LOG_PID) {
+ grn_snprintf(lbuf, LBUFSIZE, LBUFSIZE,
+ "%d", grn_getpid());
+ } else {
+ lbuf[0] = '\0';
+ }
+ current_logger.log(ctx, level, tbuf, "", mbuf, lbuf,
+ current_logger.user_data);
+ }
+}
+
+void
+grn_logger_init(void)
+{
+ CRITICAL_SECTION_INIT(default_logger_lock);
+ if (!current_logger.log) {
+ current_logger = default_logger;
+ }
+
+ logger_inited = GRN_TRUE;
+}
+
+void
+grn_logger_fin(grn_ctx *ctx)
+{
+ current_logger_fin(ctx);
+ if (default_logger_path) {
+ free(default_logger_path);
+ default_logger_path = NULL;
+ }
+ CRITICAL_SECTION_FIN(default_logger_lock);
+
+ logger_inited = GRN_FALSE;
+}
+
+
+static grn_bool query_logger_inited = GRN_FALSE;
+static char *default_query_logger_path = NULL;
+static FILE *default_query_logger_file = NULL;
+static grn_critical_section default_query_logger_lock;
+static off_t default_query_logger_size = 0;
+static off_t default_query_logger_rotate_threshold_size = 0;
+
+grn_bool
+grn_query_log_flags_parse(const char *string,
+ int string_size,
+ unsigned int *flags)
+{
+ const char *string_end;
+
+ *flags = GRN_QUERY_LOG_NONE;
+
+ if (!string) {
+ return GRN_TRUE;
+ }
+
+ if (string_size < 0) {
+ string_size = strlen(string);
+ }
+
+ string_end = string + string_size;
+
+ while (string < string_end) {
+ if (*string == '|' || *string == ' ') {
+ string += 1;
+ continue;
+ }
+
+#define CHECK_FLAG(name) \
+ if (((size_t) (string_end - string) >= (sizeof(#name) - 1)) && \
+ (memcmp(string, #name, sizeof(#name) - 1) == 0) && \
+ (((size_t)(string_end - string) == (sizeof(#name) - 1)) || \
+ (string[sizeof(#name) - 1] == '|') || \
+ (string[sizeof(#name) - 1] == ' '))) { \
+ *flags |= GRN_QUERY_LOG_ ## name; \
+ string += sizeof(#name) - 1; \
+ continue; \
+ }
+
+ CHECK_FLAG(NONE);
+ CHECK_FLAG(COMMAND);
+ CHECK_FLAG(RESULT_CODE);
+ CHECK_FLAG(DESTINATION);
+ CHECK_FLAG(CACHE);
+ CHECK_FLAG(SIZE);
+ CHECK_FLAG(SCORE);
+ CHECK_FLAG(ALL);
+ CHECK_FLAG(DEFAULT);
+
+#undef CHECK_FLAG
+
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+default_query_logger_log(grn_ctx *ctx, unsigned int flag,
+ const char *timestamp, const char *info,
+ const char *message, void *user_data)
+{
+ if (default_query_logger_path) {
+ CRITICAL_SECTION_ENTER(default_query_logger_lock);
+ if (!default_query_logger_file) {
+ default_query_logger_file = grn_fopen(default_query_logger_path, "a");
+ default_query_logger_size = 0;
+ if (default_query_logger_file) {
+ struct stat stat;
+ if (fstat(grn_fileno(default_query_logger_file), &stat) != -1) {
+ default_query_logger_size = stat.st_size;
+ }
+ }
+ }
+ if (default_query_logger_file) {
+ int written;
+ written = fprintf(default_query_logger_file, "%s|%s%s\n",
+ timestamp, info, message);
+ if (written > 0) {
+ default_query_logger_size += written;
+ if (LOGGER_NEED_ROTATE(default_query_logger_size,
+ default_query_logger_rotate_threshold_size)) {
+ fclose(default_query_logger_file);
+ default_query_logger_file = NULL;
+ rotate_log_file(ctx, default_query_logger_path);
+ } else {
+ fflush(default_query_logger_file);
+ }
+ }
+ }
+ CRITICAL_SECTION_LEAVE(default_query_logger_lock);
+ }
+}
+
+static void
+default_query_logger_close(grn_ctx *ctx, void *user_data)
+{
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_DESTINATION, " ",
+ "query log will be closed: <%s>", default_query_logger_path);
+ CRITICAL_SECTION_ENTER(default_query_logger_lock);
+ if (default_query_logger_file) {
+ fclose(default_query_logger_file);
+ default_query_logger_file = NULL;
+ }
+ CRITICAL_SECTION_LEAVE(default_query_logger_lock);
+}
+
+static void
+default_query_logger_reopen(grn_ctx *ctx, void *user_data)
+{
+ default_query_logger_close(ctx, user_data);
+ if (default_query_logger_path) {
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_DESTINATION, " ",
+ "query log is opened: <%s>", default_query_logger_path);
+ }
+}
+
+static void
+default_query_logger_fin(grn_ctx *ctx, void *user_data)
+{
+ if (default_query_logger_file) {
+ default_query_logger_close(ctx, user_data);
+ }
+}
+
+static grn_query_logger default_query_logger = {
+ GRN_QUERY_LOG_DEFAULT,
+ NULL,
+ default_query_logger_log,
+ default_query_logger_reopen,
+ default_query_logger_fin
+};
+
+#define INITIAL_QUERY_LOGGER { \
+ GRN_QUERY_LOG_DEFAULT, \
+ NULL, \
+ NULL, \
+ NULL, \
+ NULL \
+}
+
+static grn_query_logger current_query_logger = INITIAL_QUERY_LOGGER;
+
+void
+grn_default_query_logger_set_flags(unsigned int flags)
+{
+ default_query_logger.flags = flags;
+ if (current_query_logger.log == default_query_logger_log) {
+ current_query_logger.flags = flags;
+ }
+}
+
+unsigned int
+grn_default_query_logger_get_flags(void)
+{
+ return default_query_logger.flags;
+}
+
+void
+grn_default_query_logger_set_path(const char *path)
+{
+ if (query_logger_inited) {
+ CRITICAL_SECTION_ENTER(default_query_logger_lock);
+ }
+
+ if (default_query_logger_path) {
+ free(default_query_logger_path);
+ }
+
+ if (path) {
+ default_query_logger_path = grn_strdup_raw(path);
+ } else {
+ default_query_logger_path = NULL;
+ }
+
+ if (query_logger_inited) {
+ CRITICAL_SECTION_LEAVE(default_query_logger_lock);
+ }
+}
+
+const char *
+grn_default_query_logger_get_path(void)
+{
+ return default_query_logger_path;
+}
+
+void
+grn_default_query_logger_set_rotate_threshold_size(off_t threshold)
+{
+ default_query_logger_rotate_threshold_size = threshold;
+}
+
+off_t
+grn_default_query_logger_get_rotate_threshold_size(void)
+{
+ return default_query_logger_rotate_threshold_size;
+}
+
+void
+grn_query_logger_reopen(grn_ctx *ctx)
+{
+ if (current_query_logger.reopen) {
+ current_query_logger.reopen(ctx, current_query_logger.user_data);
+ }
+}
+
+static void
+current_query_logger_fin(grn_ctx *ctx)
+{
+ if (current_query_logger.fin) {
+ current_query_logger.fin(ctx, current_query_logger.user_data);
+ }
+ {
+ grn_query_logger initial_query_logger = INITIAL_QUERY_LOGGER;
+ current_query_logger = initial_query_logger;
+ }
+}
+
+grn_rc
+grn_query_logger_set(grn_ctx *ctx, const grn_query_logger *logger)
+{
+ current_query_logger_fin(ctx);
+ if (logger) {
+ current_query_logger = *logger;
+ } else {
+ current_query_logger = default_query_logger;
+ }
+ return GRN_SUCCESS;
+}
+
+void
+grn_query_logger_set_flags(grn_ctx *ctx, unsigned int flags)
+{
+ current_query_logger.flags = flags;
+}
+
+void
+grn_query_logger_add_flags(grn_ctx *ctx, unsigned int flags)
+{
+ current_query_logger.flags |= flags;
+}
+
+void
+grn_query_logger_remove_flags(grn_ctx *ctx, unsigned int flags)
+{
+ current_query_logger.flags &= ~flags;
+}
+
+unsigned int
+grn_query_logger_get_flags(grn_ctx *ctx)
+{
+ return current_query_logger.flags;
+}
+
+grn_bool
+grn_query_logger_pass(grn_ctx *ctx, unsigned int flag)
+{
+ return current_query_logger.flags & flag;
+}
+
+#define TIMESTAMP_BUFFER_SIZE TBUFSIZE
+/* 8+a(%p) + 1(|) + 1(mark) + 15(elapsed time) = 25+a */
+#define INFO_BUFFER_SIZE 40
+
+void
+grn_query_logger_put(grn_ctx *ctx, unsigned int flag, const char *mark,
+ const char *format, ...)
+{
+ char timestamp[TIMESTAMP_BUFFER_SIZE];
+ char info[INFO_BUFFER_SIZE];
+ grn_obj *message = &ctx->impl->query_log_buf;
+
+ if (!current_query_logger.log) {
+ return;
+ }
+
+ {
+ grn_timeval tv;
+ timestamp[0] = '\0';
+ grn_timeval_now(ctx, &tv);
+ grn_timeval2str(ctx, &tv, timestamp, TIMESTAMP_BUFFER_SIZE);
+ }
+
+ if (flag & (GRN_QUERY_LOG_COMMAND | GRN_QUERY_LOG_DESTINATION)) {
+ grn_snprintf(info, INFO_BUFFER_SIZE, INFO_BUFFER_SIZE,
+ "%p|%s", ctx, mark);
+ info[INFO_BUFFER_SIZE - 1] = '\0';
+ } else {
+ grn_timeval tv;
+ uint64_t elapsed_time;
+ grn_timeval_now(ctx, &tv);
+ elapsed_time =
+ (uint64_t)(tv.tv_sec - ctx->impl->tv.tv_sec) * GRN_TIME_NSEC_PER_SEC +
+ (tv.tv_nsec - ctx->impl->tv.tv_nsec);
+
+ grn_snprintf(info, INFO_BUFFER_SIZE, INFO_BUFFER_SIZE,
+ "%p|%s%015" GRN_FMT_INT64U " ", ctx, mark, elapsed_time);
+ info[INFO_BUFFER_SIZE - 1] = '\0';
+ }
+
+ {
+ va_list args;
+
+ va_start(args, format);
+ GRN_BULK_REWIND(message);
+ grn_text_vprintf(ctx, message, format, args);
+ va_end(args);
+ GRN_TEXT_PUTC(ctx, message, '\0');
+ }
+
+ current_query_logger.log(ctx, flag, timestamp, info, GRN_TEXT_VALUE(message),
+ current_query_logger.user_data);
+}
+
+void
+grn_query_logger_init(void)
+{
+ current_query_logger = default_query_logger;
+ CRITICAL_SECTION_INIT(default_query_logger_lock);
+
+ query_logger_inited = GRN_TRUE;
+}
+
+void
+grn_query_logger_fin(grn_ctx *ctx)
+{
+ current_query_logger_fin(ctx);
+ if (default_query_logger_path) {
+ free(default_query_logger_path);
+ default_query_logger_path = NULL;
+ }
+ CRITICAL_SECTION_FIN(default_query_logger_lock);
+
+ query_logger_inited = GRN_FALSE;
+}
+
+void
+grn_log_reopen(grn_ctx *ctx)
+{
+ grn_logger_reopen(ctx);
+ grn_query_logger_reopen(ctx);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/metadata.rc.in b/storage/mroonga/vendor/groonga/lib/metadata.rc.in
new file mode 100644
index 00000000..0c43cd7d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/metadata.rc.in
@@ -0,0 +1,28 @@
+#include <windows.h>
+
+#define LANG_CODE_US_ENGLISH 0x0409
+#define CHARSET_UNICODE 0x04b0
+#define US_ENGLISH_UNICODE "040904b0"
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 0,@GRN_VERSION_RC@
+PRODUCTVERSION 0,@GRN_VERSION_RC@
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK US_ENGLISH_UNICODE
+ BEGIN
+ VALUE "CompanyName", "Groonga project"
+ VALUE "FileDescription", "Full text search engine library"
+ VALUE "FileVersion", "@GRN_VERSION@"
+ VALUE "InternalName", "libgroonga"
+ VALUE "OriginalFilename", "@GRN_DLL_FILENAME@"
+ VALUE "ProductName", "libgroonga"
+ VALUE "ProductVersion", "@GRN_VERSION@"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", LANG_CODE_US_ENGLISH, CHARSET_UNICODE
+ END
+END
diff --git a/storage/mroonga/vendor/groonga/lib/mrb.c b/storage/mroonga/vendor/groonga/lib/mrb.c
new file mode 100644
index 00000000..f5bb49fb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb.c
@@ -0,0 +1,220 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_mrb.h"
+#include "grn_ctx_impl.h"
+#include "grn_util.h"
+
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+# include <mruby/proc.h>
+# include <mruby/compile.h>
+# include <mruby/string.h>
+#endif
+
+#include <ctype.h>
+
+#ifdef WIN32
+# include <share.h>
+#endif /* WIN32 */
+
+#define BUFFER_SIZE 2048
+#define E_LOAD_ERROR (mrb_class_get(mrb, "LoadError"))
+
+static char grn_mrb_ruby_scripts_dir[GRN_ENV_BUFFER_SIZE];
+static grn_bool grn_mrb_order_by_estimated_size_enable = GRN_FALSE;
+
+void
+grn_mrb_init_from_env(void)
+{
+ grn_getenv("GRN_RUBY_SCRIPTS_DIR",
+ grn_mrb_ruby_scripts_dir,
+ GRN_ENV_BUFFER_SIZE);
+ {
+ char grn_order_by_estimated_size_enable_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_ORDER_BY_ESTIMATED_SIZE_ENABLE",
+ grn_order_by_estimated_size_enable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (strcmp(grn_order_by_estimated_size_enable_env, "yes") == 0) {
+ grn_mrb_order_by_estimated_size_enable = GRN_TRUE;
+ } else {
+ grn_mrb_order_by_estimated_size_enable = GRN_FALSE;
+ }
+ }
+}
+
+grn_bool
+grn_mrb_is_order_by_estimated_size_enabled(void)
+{
+ return grn_mrb_order_by_estimated_size_enable;
+}
+
+#ifdef GRN_WITH_MRUBY
+# ifdef WIN32
+static char *windows_ruby_scripts_dir = NULL;
+static char windows_ruby_scripts_dir_buffer[PATH_MAX];
+static const char *
+grn_mrb_get_default_system_ruby_scripts_dir(void)
+{
+ if (!windows_ruby_scripts_dir) {
+ const char *base_dir;
+ const char *relative_path = GRN_RELATIVE_RUBY_SCRIPTS_DIR;
+ size_t base_dir_length;
+
+ base_dir = grn_windows_base_dir();
+ base_dir_length = strlen(base_dir);
+ grn_strcpy(windows_ruby_scripts_dir_buffer, PATH_MAX, base_dir);
+ grn_strcat(windows_ruby_scripts_dir_buffer, PATH_MAX, "/");
+ grn_strcat(windows_ruby_scripts_dir_buffer, PATH_MAX, relative_path);
+ windows_ruby_scripts_dir = windows_ruby_scripts_dir_buffer;
+ }
+ return windows_ruby_scripts_dir;
+}
+
+# else /* WIN32 */
+static const char *
+grn_mrb_get_default_system_ruby_scripts_dir(void)
+{
+ return GRN_RUBY_SCRIPTS_DIR;
+}
+# endif /* WIN32 */
+
+const char *
+grn_mrb_get_system_ruby_scripts_dir(grn_ctx *ctx)
+{
+ if (grn_mrb_ruby_scripts_dir[0]) {
+ return grn_mrb_ruby_scripts_dir;
+ } else {
+ return grn_mrb_get_default_system_ruby_scripts_dir();
+ }
+}
+
+static grn_bool
+grn_mrb_is_absolute_path(const char *path)
+{
+ if (path[0] == '/') {
+ return GRN_TRUE;
+ }
+
+ if (isalpha((unsigned char)path[0]) && path[1] == ':' && path[2] == '/') {
+ return GRN_TRUE;
+ }
+
+ return GRN_FALSE;
+}
+
+static grn_bool
+grn_mrb_expand_script_path(grn_ctx *ctx, const char *path,
+ char *expanded_path, size_t expanded_path_size)
+{
+ const char *ruby_scripts_dir;
+ char dir_last_char;
+ int path_length, max_path_length;
+
+ if (grn_mrb_is_absolute_path(path)) {
+ expanded_path[0] = '\0';
+ } else if (path[0] == '.' && path[1] == '/') {
+ grn_strcpy(expanded_path, expanded_path_size, ctx->impl->mrb.base_directory);
+ grn_strcat(expanded_path, expanded_path_size, "/");
+ } else {
+ ruby_scripts_dir = grn_mrb_get_system_ruby_scripts_dir(ctx);
+ grn_strcpy(expanded_path, expanded_path_size, ruby_scripts_dir);
+
+ dir_last_char = ruby_scripts_dir[strlen(expanded_path) - 1];
+ if (dir_last_char != '/') {
+ grn_strcat(expanded_path, expanded_path_size, "/");
+ }
+ }
+
+ path_length = strlen(path);
+ max_path_length = PATH_MAX - strlen(expanded_path) - 1;
+ if (path_length > max_path_length) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "script path is too long: %d (max: %d) <%s%s>",
+ path_length, max_path_length,
+ expanded_path, path);
+ return GRN_FALSE;
+ }
+
+ grn_strcat(expanded_path, expanded_path_size, path);
+
+ return GRN_TRUE;
+}
+
+mrb_value
+grn_mrb_load(grn_ctx *ctx, const char *path)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ char expanded_path[PATH_MAX];
+ FILE *file;
+ mrb_value result;
+ struct mrb_parser_state *parser;
+
+ if (!mrb) {
+ return mrb_nil_value();
+ }
+
+ if (!grn_mrb_expand_script_path(ctx, path, expanded_path, PATH_MAX)) {
+ return mrb_nil_value();
+ }
+
+ file = grn_fopen(expanded_path, "r");
+ if (!file) {
+ mrb_value exception;
+ SERR("fopen: failed to open mruby script file: <%s>",
+ expanded_path);
+ exception = mrb_exc_new(mrb, E_LOAD_ERROR,
+ ctx->errbuf, strlen(ctx->errbuf));
+ mrb->exc = mrb_obj_ptr(exception);
+ return mrb_nil_value();
+ }
+
+ {
+ char current_base_directory[PATH_MAX];
+ char *last_directory;
+
+ grn_strcpy(current_base_directory, PATH_MAX, data->base_directory);
+ grn_strcpy(data->base_directory, PATH_MAX, expanded_path);
+ last_directory = strrchr(data->base_directory, '/');
+ if (last_directory) {
+ last_directory[0] = '\0';
+ }
+
+ parser = mrb_parser_new(mrb);
+ mrb_parser_set_filename(parser, expanded_path);
+ parser->s = parser->send = NULL;
+ parser->f = file;
+ mrb_parser_parse(parser, NULL);
+ fclose(file);
+
+ {
+ struct RProc *proc;
+ proc = mrb_generate_code(mrb, parser);
+ proc->target_class = mrb->object_class;
+ result = mrb_toplevel_run(mrb, proc);
+ }
+ mrb_parser_free(parser);
+
+ grn_strcpy(data->base_directory, PATH_MAX, current_base_directory);
+ }
+
+ return result;
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/Makefile.am
new file mode 100644
index 00000000..0e4db634
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/Makefile.am
@@ -0,0 +1,21 @@
+SUBDIRS = \
+ scripts
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib \
+ $(MRUBY_CPPFLAGS)
+
+AM_CFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS) \
+ $(MRUBY_CFLAGS)
+
+noinst_LTLIBRARIES = libgrnmrb.la
+
+include sources.am
+
+CLEANFILES = *.gcno *.gcda
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.c
new file mode 100644
index 00000000..ef341d3a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.c
@@ -0,0 +1,121 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/variable.h>
+#include <mruby/data.h>
+
+#include "../grn_db.h"
+#include "mrb_ctx.h"
+#include "mrb_accessor.h"
+#include "mrb_converter.h"
+
+static struct mrb_data_type mrb_grn_accessor_type = {
+ "Groonga::Accessor",
+ NULL
+};
+
+static mrb_value
+mrb_grn_accessor_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_accessor_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_accessor_ptr);
+ DATA_TYPE(self) = &mrb_grn_accessor_type;
+ DATA_PTR(self) = mrb_cptr(mrb_accessor_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_accessor_next(mrb_state *mrb, mrb_value self)
+{
+ grn_accessor *accessor;
+
+ accessor = DATA_PTR(self);
+ return grn_mrb_value_from_grn_obj(mrb, (grn_obj *)(accessor->next));
+}
+
+static mrb_value
+mrb_grn_accessor_have_next_p(mrb_state *mrb, mrb_value self)
+{
+ grn_accessor *accessor;
+
+ accessor = DATA_PTR(self);
+ return mrb_bool_value(accessor->next != NULL);
+}
+
+static mrb_value
+mrb_grn_accessor_object(mrb_state *mrb, mrb_value self)
+{
+ grn_accessor *accessor;
+
+ accessor = DATA_PTR(self);
+ return grn_mrb_value_from_grn_obj(mrb, accessor->obj);
+}
+
+static mrb_value
+mrb_grn_accessor_name(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_rc rc;
+ grn_obj *accessor;
+ grn_obj name;
+ mrb_value mrb_name;
+
+ accessor = DATA_PTR(self);
+ GRN_TEXT_INIT(&name, 0);
+ rc = grn_column_name_(ctx, accessor, &name);
+ if (rc == GRN_SUCCESS) {
+ mrb_name = mrb_str_new(mrb, GRN_TEXT_VALUE(&name), GRN_TEXT_LEN(&name));
+ GRN_OBJ_FIN(ctx, &name);
+ } else {
+ mrb_name = mrb_nil_value();
+ GRN_OBJ_FIN(ctx, &name);
+ grn_mrb_ctx_check(mrb);
+ }
+
+ return mrb_name;
+}
+
+void
+grn_mrb_accessor_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Accessor", data->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_accessor_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "next",
+ mrb_grn_accessor_next, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "have_next?",
+ mrb_grn_accessor_have_next_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "object",
+ mrb_grn_accessor_object, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "name",
+ mrb_grn_accessor_name, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.h
new file mode 100644
index 00000000..4443f7d5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_accessor.h
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+#include "../grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_accessor_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_array.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_array.c
new file mode 100644
index 00000000..2d1e84cc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_array.c
@@ -0,0 +1,92 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_ctx.h"
+#include "mrb_array.h"
+
+static struct mrb_data_type mrb_grn_array_type = {
+ "Groonga::Array",
+ NULL
+};
+
+static mrb_value
+mrb_grn_array_class_create(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *name;
+ mrb_int name_length;
+ const char *path = NULL;
+ mrb_value mrb_value_type;
+ grn_obj *value_type = NULL;
+ grn_obj *array;
+
+ mrb_get_args(mrb, "so", &name, &name_length, &mrb_value_type);
+ if (!mrb_nil_p(mrb_value_type)) {
+ value_type = DATA_PTR(mrb_value_type);
+ }
+
+ array = grn_table_create(ctx,
+ name, name_length,
+ path,
+ GRN_TABLE_NO_KEY,
+ NULL,
+ value_type);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_funcall(mrb, klass, "new", 1, mrb_cptr_value(mrb, array));
+}
+
+static mrb_value
+mrb_grn_array_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_array_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_array_ptr);
+ DATA_TYPE(self) = &mrb_grn_array_type;
+ DATA_PTR(self) = mrb_cptr(mrb_array_ptr);
+ return self;
+}
+
+void
+grn_mrb_array_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *table_class;
+ struct RClass *klass;
+
+ table_class = mrb_class_get_under(mrb, module, "Table");
+ klass = mrb_define_class_under(mrb, module, "Array", table_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "create",
+ mrb_grn_array_class_create,
+ MRB_ARGS_REQ(2));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_array_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_array.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_array.h
new file mode 100644
index 00000000..77ef94d5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_array.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_array_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.c
new file mode 100644
index 00000000..b3c47795
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.c
@@ -0,0 +1,373 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/variable.h>
+#include <mruby/data.h>
+#include <mruby/numeric.h>
+#include <mruby/string.h>
+
+#include "../grn_db.h"
+#include "mrb_bulk.h"
+#include "mrb_object.h"
+
+static struct mrb_data_type mrb_grn_bulk_type = {
+ "Groonga::Bulk",
+ NULL
+};
+
+grn_obj *
+grn_mrb_value_to_bulk(mrb_state *mrb, mrb_value mrb_value_, grn_obj *bulk)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ switch (mrb_type(mrb_value_)) {
+ case MRB_TT_FALSE :
+ if (mrb_nil_p(mrb_value_)) {
+ grn_obj_reinit(ctx, bulk, GRN_DB_VOID, 0);
+ } else {
+ grn_obj_reinit(ctx, bulk, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, bulk, GRN_FALSE);
+ }
+ break;
+ case MRB_TT_TRUE :
+ grn_obj_reinit(ctx, bulk, GRN_DB_BOOL, 0);
+ GRN_BOOL_SET(ctx, bulk, GRN_TRUE);
+ break;
+ case MRB_TT_FIXNUM :
+ grn_obj_reinit(ctx, bulk, GRN_DB_INT64, 0);
+ GRN_INT64_SET(ctx, bulk, mrb_fixnum(mrb_value_));
+ break;
+ case MRB_TT_SYMBOL :
+ {
+ const char *name;
+ mrb_int name_length;
+
+ grn_obj_reinit(ctx, bulk, GRN_DB_TEXT, 0);
+ name = mrb_sym2name_len(mrb, mrb_symbol(mrb_value_), &name_length);
+ GRN_TEXT_SET(ctx, bulk, name, name_length);
+ }
+ break;
+ case MRB_TT_FLOAT :
+ grn_obj_reinit(ctx, bulk, GRN_DB_FLOAT, 0);
+ GRN_FLOAT_SET(ctx, bulk, mrb_float(mrb_value_));
+ break;
+ case MRB_TT_STRING :
+ grn_obj_reinit(ctx, bulk, GRN_DB_TEXT,
+ bulk->header.impl_flags & GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, bulk, RSTRING_PTR(mrb_value_), RSTRING_LEN(mrb_value_));
+ break;
+ default :
+ {
+ struct RClass *klass;
+
+ klass = mrb_class(mrb, mrb_value_);
+ if (klass == ctx->impl->mrb.builtin.time_class) {
+ mrb_value mrb_sec;
+ mrb_value mrb_usec;
+
+ mrb_sec = mrb_funcall(mrb, mrb_value_, "to_i", 0);
+ mrb_usec = mrb_funcall(mrb, mrb_value_, "usec", 0);
+ grn_obj_reinit(ctx, bulk, GRN_DB_TIME, 0);
+ GRN_TIME_SET(ctx, bulk,
+ GRN_TIME_PACK(mrb_fixnum(mrb_sec), mrb_fixnum(mrb_usec)));
+ } else {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "unsupported object to convert to bulk: %S",
+ mrb_value_);
+ }
+ }
+ break;
+ }
+
+ return bulk;
+}
+
+mrb_value
+grn_mrb_value_from_bulk(mrb_state *mrb, grn_obj *bulk)
+{
+ mrb_value mrb_value_;
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ if (!bulk) {
+ return mrb_nil_value();
+ }
+
+ switch (bulk->header.domain) {
+ case GRN_DB_BOOL :
+ {
+ grn_bool value;
+ value = GRN_BOOL_VALUE(bulk);
+ mrb_value_ = mrb_bool_value(value);
+ }
+ break;
+ case GRN_DB_INT8 :
+ {
+ int8_t value;
+ value = GRN_INT8_VALUE(bulk);
+ mrb_value_ = mrb_fixnum_value(value);
+ }
+ break;
+ case GRN_DB_UINT8 :
+ {
+ uint8_t value;
+ value = GRN_UINT8_VALUE(bulk);
+ mrb_value_ = mrb_fixnum_value(value);
+ }
+ break;
+ case GRN_DB_INT16 :
+ {
+ int16_t value;
+ value = GRN_INT16_VALUE(bulk);
+ mrb_value_ = mrb_fixnum_value(value);
+ }
+ break;
+ case GRN_DB_UINT16 :
+ {
+ uint16_t value;
+ value = GRN_UINT16_VALUE(bulk);
+ mrb_value_ = mrb_fixnum_value(value);
+ }
+ break;
+ case GRN_DB_INT32 :
+ {
+ int32_t value;
+ value = GRN_INT32_VALUE(bulk);
+ mrb_value_ = mrb_fixnum_value(value);
+ }
+ break;
+ case GRN_DB_UINT32 :
+ {
+ int64_t value;
+ value = GRN_UINT32_VALUE(bulk);
+ if (FIXABLE(value)) {
+ mrb_value_ = mrb_fixnum_value(value);
+ } else {
+ mrb_value_ = mrb_float_value(mrb, value);
+ }
+ }
+ break;
+ case GRN_DB_INT64 :
+ {
+ int64_t value;
+ value = GRN_INT64_VALUE(bulk);
+ if (FIXABLE(value)) {
+ mrb_value_ = mrb_fixnum_value(value);
+ } else {
+ mrb_value_ = mrb_float_value(mrb, value);
+ }
+ }
+ break;
+ case GRN_DB_UINT64 :
+ {
+ uint64_t value;
+ value = GRN_UINT64_VALUE(bulk);
+ if (FIXABLE(value)) {
+ mrb_value_ = mrb_fixnum_value(value);
+ } else {
+ mrb_value_ = mrb_float_value(mrb, value);
+ }
+ }
+ break;
+ case GRN_DB_FLOAT :
+ {
+ double value;
+ value = GRN_FLOAT_VALUE(bulk);
+ mrb_value_ = mrb_float_value(mrb, value);
+ }
+ break;
+ case GRN_DB_TIME :
+ {
+ int64_t value;
+ int64_t sec;
+ int32_t usec;
+ mrb_value mrb_sec;
+
+ value = GRN_TIME_VALUE(bulk);
+ GRN_TIME_UNPACK(value, sec, usec);
+ if (sec > MRB_INT_MAX) {
+ mrb_sec = mrb_float_value(mrb, sec);
+ } else {
+ mrb_sec = mrb_fixnum_value(sec);
+ }
+ mrb_value_ = mrb_funcall(mrb,
+ mrb_obj_value(ctx->impl->mrb.builtin.time_class),
+ "at",
+ 2,
+ mrb_sec,
+ mrb_fixnum_value(usec));
+ }
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ mrb_value_ = mrb_str_new(mrb,
+ GRN_TEXT_VALUE(bulk),
+ GRN_TEXT_LEN(bulk));
+ break;
+ default :
+ {
+ grn_obj *domain;
+ grn_bool is_record = GRN_FALSE;
+
+ domain = grn_ctx_at(ctx, bulk->header.domain);
+ if (domain) {
+ switch (domain->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ is_record = GRN_TRUE;
+ break;
+ default :
+ break;
+ }
+ }
+
+ if (is_record) {
+ mrb_value_ = mrb_fixnum_value(GRN_RECORD_VALUE(bulk));
+ grn_obj_unlink(ctx, domain);
+ } else {
+#define MESSAGE_SIZE 4096
+ char message[MESSAGE_SIZE];
+ char domain_name[GRN_TABLE_MAX_KEY_SIZE];
+ int domain_name_size;
+
+ if (domain) {
+ domain_name_size = grn_obj_name(ctx, domain,
+ domain_name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_obj_unlink(ctx, domain);
+ } else {
+ grn_strcpy(domain_name, GRN_TABLE_MAX_KEY_SIZE, "unknown");
+ domain_name_size = strlen(domain_name);
+ }
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "unsupported bulk value type: <%d>(%.*s)",
+ bulk->header.domain,
+ domain_name_size,
+ domain_name);
+ mrb_raise(mrb, E_RANGE_ERROR, message);
+ }
+#undef MESSAGE_SIZE
+ }
+ break;
+ }
+
+ return mrb_value_;
+}
+
+grn_bool
+grn_mrb_bulk_cast(mrb_state *mrb, grn_obj *from, grn_obj *to, grn_id domain_id)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_rc rc;
+
+ grn_obj_reinit(ctx, to, domain_id, 0);
+ rc = grn_obj_cast(ctx, from, to, GRN_FALSE);
+ return rc == GRN_SUCCESS;
+}
+
+static mrb_value
+mrb_grn_bulk_s_is_true(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_value_;
+ grn_obj bulk;
+ grn_bool is_true;
+
+ mrb_get_args(mrb, "o", &mrb_value_);
+
+ GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY);
+ grn_mrb_value_to_bulk(mrb, mrb_value_, &bulk);
+ is_true = grn_obj_is_true(ctx, &bulk);
+ GRN_OBJ_FIN(ctx, &bulk);
+
+ return mrb_bool_value(is_true);
+}
+
+static mrb_value
+mrb_grn_bulk_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_bulk_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_bulk_ptr);
+ DATA_TYPE(self) = &mrb_grn_bulk_type;
+ DATA_PTR(self) = mrb_cptr(mrb_bulk_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_bulk_get_domain(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *bulk;
+
+ bulk = DATA_PTR(self);
+ return mrb_fixnum_value(bulk->header.domain);
+}
+
+static mrb_value
+mrb_grn_bulk_get_value(mrb_state *mrb, mrb_value self)
+{
+ return grn_mrb_value_from_bulk(mrb, DATA_PTR(self));
+}
+
+static mrb_value
+mrb_grn_bulk_equal(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_other;
+
+ mrb_get_args(mrb, "o", &mrb_other);
+
+ if (!mrb_obj_is_kind_of(mrb, mrb_other, mrb_class(mrb, self))) {
+ return mrb_false_value();
+ }
+
+ return mrb_bool_value(DATA_PTR(self) == DATA_PTR(mrb_other));
+}
+
+void
+grn_mrb_bulk_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Bulk", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_singleton_method(mrb, (struct RObject *)klass, "true?",
+ mrb_grn_bulk_s_is_true, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_bulk_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "domain",
+ mrb_grn_bulk_get_domain, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "value",
+ mrb_grn_bulk_get_value, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "==",
+ mrb_grn_bulk_equal, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "inspect",
+ grn_mrb_object_inspect, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.h
new file mode 100644
index 00000000..f8f14b5f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_bulk.h
@@ -0,0 +1,41 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+#include "../grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_bulk_init(grn_ctx *ctx);
+
+mrb_value grn_mrb_value_from_bulk(mrb_state *mrb, grn_obj *bulk);
+grn_obj *grn_mrb_value_to_bulk(mrb_state *mrb,
+ mrb_value mrb_value_,
+ grn_obj *bulk);
+grn_bool grn_mrb_bulk_cast(mrb_state *mrb,
+ grn_obj *from,
+ grn_obj *to,
+ grn_id domain_id);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.c
new file mode 100644
index 00000000..843350f9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.c
@@ -0,0 +1,130 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "../grn_db.h"
+#include "../grn_cache.h"
+#include "mrb_bulk.h"
+#include "mrb_cache.h"
+
+static struct mrb_data_type mrb_grn_cache_type = {
+ "Groonga::Cache",
+ NULL
+};
+
+static mrb_value
+mrb_grn_cache_class_current(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_cache *cache;
+ mrb_value mrb_cache;
+
+ cache = grn_cache_current_get(ctx);
+ mrb_cache = mrb_funcall(mrb, klass, "new", 1, mrb_cptr_value(mrb, cache));
+
+ return mrb_cache;
+}
+
+static mrb_value
+mrb_grn_cache_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_cache_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_cache_ptr);
+ DATA_TYPE(self) = &mrb_grn_cache_type;
+ DATA_PTR(self) = mrb_cptr(mrb_cache_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_cache_fetch(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_cache *cache;
+ char *key;
+ mrb_int key_size;
+ grn_rc rc;
+ grn_obj cache_value;
+ mrb_value mrb_cache_value;
+
+ cache = DATA_PTR(self);
+ mrb_get_args(mrb, "s", &key, &key_size);
+
+ GRN_TEXT_INIT(&cache_value, 0);
+ rc = grn_cache_fetch(ctx, cache, key, key_size, &cache_value);
+ if (rc == GRN_SUCCESS) {
+ mrb_cache_value = grn_mrb_value_from_bulk(mrb, &cache_value);
+ } else {
+ mrb_cache_value = mrb_nil_value();
+ }
+ GRN_OBJ_FIN(ctx, &cache_value);
+
+ return mrb_cache_value;
+}
+
+static mrb_value
+mrb_grn_cache_update(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_cache *cache;
+ char *key;
+ mrb_int key_size;
+ char *value;
+ mrb_int value_size;
+ grn_obj value_buffer;
+
+ cache = DATA_PTR(self);
+ mrb_get_args(mrb, "ss", &key, &key_size, &value, &value_size);
+
+ GRN_TEXT_INIT(&value_buffer, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, &value_buffer, value, value_size);
+ grn_cache_update(ctx, cache, key, key_size, &value_buffer);
+ GRN_OBJ_FIN(ctx, &value_buffer);
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_cache_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Cache", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "current",
+ mrb_grn_cache_class_current, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_cache_initialize, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "fetch",
+ mrb_grn_cache_fetch, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "update",
+ mrb_grn_cache_update, MRB_ARGS_REQ(2));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.h
new file mode 100644
index 00000000..14628ba8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_cache.h
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+#include "../grn_db.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_cache_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_column.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_column.c
new file mode 100644
index 00000000..b36a42bf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_column.c
@@ -0,0 +1,173 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_proc.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_ctx.h"
+#include "mrb_column.h"
+#include "mrb_bulk.h"
+#include "mrb_converter.h"
+
+static mrb_value
+mrb_grn_column_class_parse_flags(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *error_message_tag;
+ char *flags_text;
+ mrb_int flags_text_size;
+ grn_column_flags flags;
+
+ mrb_get_args(mrb, "zs", &error_message_tag, &flags_text, &flags_text_size);
+
+ flags = grn_proc_column_parse_flags(ctx,
+ error_message_tag,
+ flags_text,
+ flags_text + flags_text_size);
+ return mrb_fixnum_value(flags);
+}
+
+static mrb_value
+mrb_grn_column_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *column;
+ mrb_int record_id;
+ grn_obj *column_value;
+
+ column = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &record_id);
+
+ column_value = grn_obj_get_value(ctx, column, record_id, NULL);
+ return grn_mrb_value_from_grn_obj(mrb, column_value);
+}
+
+static mrb_value
+mrb_grn_column_is_scalar(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *column;
+ grn_obj_flags column_type;
+
+ column = DATA_PTR(self);
+ column_type = (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK);
+
+ return mrb_bool_value(column_type == GRN_OBJ_COLUMN_SCALAR);
+}
+
+static mrb_value
+mrb_grn_column_is_vector(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *column;
+ grn_obj_flags column_type;
+
+ column = DATA_PTR(self);
+ column_type = (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK);
+
+ return mrb_bool_value(column_type == GRN_OBJ_COLUMN_VECTOR);
+}
+
+static mrb_value
+mrb_grn_column_is_index(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *column;
+ grn_obj_flags column_type;
+
+ column = DATA_PTR(self);
+ column_type = (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK);
+
+ return mrb_bool_value(column_type == GRN_OBJ_COLUMN_INDEX);
+}
+
+static mrb_value
+mrb_grn_column_is_locked(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ unsigned int is_locked;
+
+ is_locked = grn_obj_is_locked(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_bool_value(is_locked != 0);
+}
+
+static mrb_value
+mrb_grn_column_get_table(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+
+ table = grn_column_table(ctx, DATA_PTR(self));
+ if (!table) {
+ return mrb_nil_value();
+ }
+
+ return grn_mrb_value_from_grn_obj(mrb, table);
+}
+
+static mrb_value
+mrb_grn_column_truncate(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *column;
+
+ column = DATA_PTR(self);
+ grn_column_truncate(ctx, column);
+ grn_mrb_ctx_check(mrb);
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_column_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *object_class = data->object_class;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Column", object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "parse_flags",
+ mrb_grn_column_class_parse_flags, MRB_ARGS_REQ(2));
+
+ mrb_define_method(mrb, klass, "[]",
+ mrb_grn_column_array_reference, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "scalar?",
+ mrb_grn_column_is_scalar, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "vector?",
+ mrb_grn_column_is_vector, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "index?",
+ mrb_grn_column_is_index, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "locked?",
+ mrb_grn_column_is_locked, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "table",
+ mrb_grn_column_get_table, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "truncate",
+ mrb_grn_column_truncate, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_column.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_column.h
new file mode 100644
index 00000000..110b294c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_column.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_column_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_command.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command.c
new file mode 100644
index 00000000..0c9c7481
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command.c
@@ -0,0 +1,196 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include <groonga/command.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/value.h>
+#include <mruby/string.h>
+
+#include "mrb_ctx.h"
+#include "mrb_command.h"
+
+static struct mrb_data_type mrb_grn_command_type = {
+ "Groonga::Command",
+ NULL
+};
+
+mrb_value
+mrb_grn_command_instantiate(grn_ctx *ctx, grn_obj *command)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ mrb_value mrb_name;
+ struct RClass *command_class;
+ struct RClass *target_command_class;
+ mrb_value mrb_target_command_class;
+ mrb_value mrb_arguments[1];
+
+ name_size = grn_obj_name(ctx, command, name, GRN_TABLE_MAX_KEY_SIZE);
+ mrb_name = mrb_str_new(mrb, name, name_size);
+
+ command_class = mrb_class_get_under(mrb, module, "Command");
+ mrb_target_command_class = mrb_funcall(mrb,
+ mrb_obj_value(command_class),
+ "find_class", 1, mrb_name);
+ if (mrb_nil_p(mrb_target_command_class)) {
+ target_command_class = command_class;
+ } else {
+ target_command_class = mrb_class_ptr(mrb_target_command_class);
+ }
+ mrb_arguments[0] = mrb_cptr_value(mrb, command);
+ return mrb_obj_new(mrb, target_command_class, 1, mrb_arguments);
+}
+
+static void
+mrb_grn_command_run_wrapper(grn_ctx *ctx,
+ grn_obj *command,
+ grn_command_input *input,
+ void *user_data)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ int arena_index;
+ mrb_value mrb_command;
+ mrb_value mrb_input;
+
+ arena_index = mrb_gc_arena_save(mrb);
+ mrb_command = mrb_grn_command_instantiate(ctx, command);
+ {
+ struct RClass *command_input_class;
+ mrb_value mrb_arguments[1];
+ command_input_class = mrb_class_get_under(mrb, module, "CommandInput");
+ mrb_arguments[0] = mrb_cptr_value(mrb, input);
+ mrb_input = mrb_obj_new(mrb, command_input_class, 1, mrb_arguments);
+ }
+ mrb_funcall(mrb, mrb_command, "run_internal", 1, mrb_input);
+ if (ctx->rc == GRN_SUCCESS && mrb->exc) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_obj_name(ctx, command, name, GRN_TABLE_MAX_KEY_SIZE);
+ if (mrb->exc == mrb->nomem_err) {
+ MERR("failed to allocate memory in mruby: <%.*s>",
+ name_size, name);
+ } else {
+ mrb_value reason;
+ reason = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect", 0);
+ ERR(GRN_COMMAND_ERROR,
+ "failed to run command: <%*.s>: %.*s",
+ name_size, name,
+ (int)RSTRING_LEN(reason), RSTRING_PTR(reason));
+ }
+ }
+ mrb_gc_arena_restore(mrb, arena_index);
+}
+
+static mrb_value
+mrb_grn_command_class_register(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_name;
+ mrb_value *mrb_arguments;
+ mrb_int n_arguments;
+
+ mrb_get_args(mrb, "Sa", &mrb_name, &mrb_arguments, &n_arguments);
+
+ {
+ grn_expr_var *vars;
+ mrb_int i;
+
+ for (i = 0; i < n_arguments; i++) {
+ mrb_arguments[i] = mrb_convert_type(mrb, mrb_arguments[i],
+ MRB_TT_STRING, "String", "to_str");
+ }
+ vars = GRN_MALLOCN(grn_expr_var, n_arguments);
+ for (i = 0; i < n_arguments; i++) {
+ mrb_value mrb_argument = mrb_arguments[i];
+ grn_expr_var *var = &vars[i];
+ var->name = RSTRING_PTR(mrb_argument);
+ var->name_size = RSTRING_LEN(mrb_argument);
+ GRN_TEXT_INIT(&(var->value), 0);
+ }
+
+ grn_command_register(ctx,
+ RSTRING_PTR(mrb_name),
+ RSTRING_LEN(mrb_name),
+ mrb_grn_command_run_wrapper,
+ vars,
+ n_arguments,
+ NULL);
+
+ for (i = 0; i < n_arguments; i++) {
+ grn_expr_var *var = &vars[i];
+ GRN_OBJ_FIN(ctx, &(var->value));
+ }
+ GRN_FREE(vars);
+ }
+
+ grn_mrb_ctx_check(mrb);
+
+ {
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ struct RClass *command_class;
+ command_class = mrb_class_get_under(mrb, data->module, "Command");
+ mrb_funcall(mrb,
+ mrb_obj_value(command_class),
+ "register_class", 2, mrb_name, klass);
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_command_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_command_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_command_ptr);
+ DATA_TYPE(self) = &mrb_grn_command_type;
+ DATA_PTR(self) = mrb_cptr(mrb_command_ptr);
+ return self;
+}
+
+void
+grn_mrb_command_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *procedure_class;
+ struct RClass *klass;
+
+ procedure_class = mrb_class_get_under(mrb, module, "Procedure");
+ klass = mrb_define_class_under(mrb, module, "Command", procedure_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "register",
+ mrb_grn_command_class_register,
+ MRB_ARGS_REQ(2));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_command_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_command.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command.h
new file mode 100644
index 00000000..1872ca9f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command.h
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_command_init(grn_ctx *ctx);
+
+mrb_value grn_mrb_command_instantiate(grn_ctx *ctx, grn_obj *command);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.c
new file mode 100644
index 00000000..36570fd1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.c
@@ -0,0 +1,139 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include <groonga/command.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/value.h>
+#include <mruby/string.h>
+
+#include "mrb_ctx.h"
+#include "mrb_converter.h"
+#include "mrb_command_input.h"
+
+static struct mrb_data_type mrb_grn_command_input_type = {
+ "Groonga::CommandInput",
+ NULL
+};
+
+static mrb_value
+mrb_grn_command_input_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_command_input_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_command_input_ptr);
+ DATA_TYPE(self) = &mrb_grn_command_input_type;
+ DATA_PTR(self) = mrb_cptr(mrb_command_input_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_command_input_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_command_input *input;
+ mrb_value mrb_key_or_offset;
+ grn_obj *argument;
+
+ input = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_key_or_offset);
+
+ switch (mrb_type(mrb_key_or_offset)) {
+ case MRB_TT_FIXNUM :
+ {
+ mrb_int offset = mrb_fixnum(mrb_key_or_offset);
+ argument = grn_command_input_at(ctx, input, offset);
+ }
+ break;
+ case MRB_TT_SYMBOL :
+ {
+ mrb_sym mrb_key_symbol;
+ const char *key;
+ mrb_int key_length;
+
+ mrb_key_symbol = mrb_symbol(mrb_key_or_offset);
+ key = mrb_sym2name_len(mrb, mrb_key_symbol, &key_length);
+ argument = grn_command_input_get(ctx, input, key, key_length);
+ }
+ break;
+ case MRB_TT_STRING :
+ {
+ mrb_value mrb_key = mrb_key_or_offset;
+ argument = grn_command_input_get(ctx, input,
+ RSTRING_PTR(mrb_key),
+ RSTRING_LEN(mrb_key));
+ }
+ break;
+ default :
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "must be offset (as integer) or key (as symbol or string): %S",
+ mrb_key_or_offset);
+ break;
+ }
+
+ if (!argument) {
+ return mrb_nil_value();
+ }
+
+ if (GRN_TEXT_LEN(argument) == 0) {
+ return mrb_nil_value();
+ }
+
+ return mrb_str_new_static(mrb,
+ GRN_TEXT_VALUE(argument),
+ GRN_TEXT_LEN(argument));
+}
+
+static mrb_value
+mrb_grn_command_input_get_arguments(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_command_input *input;
+ grn_obj *arguments;
+
+ input = DATA_PTR(self);
+ arguments = grn_command_input_get_arguments(ctx, input);
+
+ return grn_mrb_value_from_grn_obj(mrb, arguments);
+}
+
+void
+grn_mrb_command_input_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "CommandInput", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_command_input_initialize, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "[]",
+ mrb_grn_command_input_array_reference, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "arguments",
+ mrb_grn_command_input_get_arguments, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.h
new file mode 100644
index 00000000..7766d819
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_input.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_command_input_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.c
new file mode 100644
index 00000000..8c7c0789
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.c
@@ -0,0 +1,41 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+
+#include "mrb_command_version.h"
+
+void
+grn_mrb_command_version_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *command_version_module;
+
+ command_version_module = mrb_define_module_under(mrb, module,
+ "CommandVersion");
+
+ mrb_define_const(mrb, command_version_module, "DEFAULT",
+ mrb_fixnum_value(GRN_COMMAND_VERSION_DEFAULT));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.h
new file mode 100644
index 00000000..167b7cb9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_command_version.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_command_version_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_config.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_config.c
new file mode 100644
index 00000000..52c722a4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_config.c
@@ -0,0 +1,90 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/string.h>
+
+#include "../grn_mrb.h"
+#include "mrb_config.h"
+#include "mrb_ctx.h"
+
+static mrb_value
+config_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *key;
+ mrb_int key_size;
+ const char *value;
+ uint32_t value_size;
+ grn_rc rc;
+
+ mrb_get_args(mrb, "s", &key, &key_size);
+
+ rc = grn_config_get(ctx, key, key_size, &value, &value_size);
+ if (rc != GRN_SUCCESS) {
+ grn_mrb_ctx_check(mrb);
+ }
+
+ if (!value) {
+ return mrb_nil_value();
+ } else {
+ return mrb_str_new(mrb, value, value_size);
+ }
+}
+
+static mrb_value
+config_array_set(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *key;
+ mrb_int key_size;
+ mrb_value mrb_value_;
+ grn_rc rc;
+
+ mrb_get_args(mrb, "sS", &key, &key_size, &mrb_value_);
+
+ rc = grn_config_set(ctx,
+ key, key_size,
+ RSTRING_PTR(mrb_value_), RSTRING_LEN(mrb_value_));
+ if (rc != GRN_SUCCESS) {
+ grn_mrb_ctx_check(mrb);
+ }
+
+ return mrb_value_;
+}
+
+void
+grn_mrb_config_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module;
+
+ module = mrb_define_module_under(mrb, data->module, "Config");
+
+ mrb_define_singleton_method(mrb, (struct RObject *)module,
+ "[]", config_array_reference,
+ MRB_ARGS_REQ(1));
+ mrb_define_singleton_method(mrb, (struct RObject *)module,
+ "[]=", config_array_set,
+ MRB_ARGS_REQ(2));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_config.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_config.h
new file mode 100644
index 00000000..a460db09
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_config.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_config_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.c
new file mode 100644
index 00000000..1010a429
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.c
@@ -0,0 +1,49 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+
+#include "mrb_ctx.h"
+#include "mrb_content_type.h"
+
+void
+grn_mrb_content_type_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module;
+
+ module = mrb_define_module_under(mrb, data->module, "ContentType");
+
+ mrb_define_const(mrb, module, "NONE",
+ mrb_fixnum_value(GRN_CONTENT_NONE));
+ mrb_define_const(mrb, module, "TSV",
+ mrb_fixnum_value(GRN_CONTENT_TSV));
+ mrb_define_const(mrb, module, "JSON",
+ mrb_fixnum_value(GRN_CONTENT_JSON));
+ mrb_define_const(mrb, module, "XML",
+ mrb_fixnum_value(GRN_CONTENT_XML));
+ mrb_define_const(mrb, module, "MSGPACK",
+ mrb_fixnum_value(GRN_CONTENT_MSGPACK));
+ mrb_define_const(mrb, module, "GROONGA_COMMAND_LIST",
+ mrb_fixnum_value(GRN_CONTENT_GROONGA_COMMAND_LIST));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.h
new file mode 100644
index 00000000..094f3df0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_content_type.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_content_type_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.c
new file mode 100644
index 00000000..147c47a3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.c
@@ -0,0 +1,350 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_db.h"
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/string.h>
+
+#include "mrb_converter.h"
+#include "mrb_bulk.h"
+
+void
+grn_mrb_value_to_raw_data_buffer_init(mrb_state *mrb,
+ grn_mrb_value_to_raw_data_buffer *buffer)
+{
+ GRN_VOID_INIT(&(buffer->from));
+ GRN_VOID_INIT(&(buffer->to));
+}
+
+void
+grn_mrb_value_to_raw_data_buffer_fin(mrb_state *mrb,
+ grn_mrb_value_to_raw_data_buffer *buffer)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ GRN_OBJ_FIN(ctx, &(buffer->from));
+ GRN_OBJ_FIN(ctx, &(buffer->to));
+}
+
+void
+grn_mrb_value_to_raw_data(mrb_state *mrb,
+ const char *context,
+ mrb_value mrb_value_,
+ grn_id domain_id,
+ grn_mrb_value_to_raw_data_buffer *buffer,
+ void **raw_value,
+ unsigned int *raw_value_size)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ enum mrb_vtype mrb_value_type;
+ grn_bool try_cast = GRN_FALSE;
+ grn_obj *from_bulk = NULL;
+
+ if (mrb_nil_p(mrb_value_)) {
+ *raw_value = NULL;
+ *raw_value_size = 0;
+ return;
+ }
+
+ mrb_value_type = mrb_type(mrb_value_);
+
+ switch (mrb_value_type) {
+ case MRB_TT_STRING :
+ switch (domain_id) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ *raw_value = RSTRING_PTR(mrb_value_);
+ *raw_value_size = RSTRING_LEN(mrb_value_);
+ break;
+ default :
+ try_cast = GRN_TRUE;
+ break;
+ }
+ break;
+ default :
+ {
+ struct RClass *klass;
+ grn_mrb_data *data = &(ctx->impl->mrb);
+
+ klass = mrb_class(mrb, mrb_value_);
+ if (domain_id == GRN_DB_TIME &&
+ klass == data->builtin.time_class) {
+ mrb_value mrb_sec;
+ mrb_value mrb_usec;
+
+ mrb_sec = mrb_funcall(mrb, mrb_value_, "to_i", 0);
+ mrb_usec = mrb_funcall(mrb, mrb_value_, "usec", 0);
+ buffer->value.time_value = GRN_TIME_PACK(mrb_fixnum(mrb_sec),
+ mrb_fixnum(mrb_usec));
+ *raw_value = &(buffer->value.time_value);
+ *raw_value_size = sizeof(buffer->value.time_value);
+ } else {
+ try_cast = GRN_TRUE;
+ if (mrb_value_type == MRB_TT_DATA &&
+ klass == mrb_class_get_under(mrb, data->module, "Bulk")) {
+ from_bulk = DATA_PTR(mrb_value_);
+ }
+ }
+ }
+ break;
+ }
+
+ if (!try_cast) {
+ return;
+ }
+
+ if (!from_bulk) {
+ from_bulk = &(buffer->from);
+ grn_mrb_value_to_bulk(mrb, mrb_value_, from_bulk);
+ }
+ if (!grn_mrb_bulk_cast(mrb, from_bulk, &(buffer->to), domain_id)) {
+ grn_obj *domain;
+ char domain_name[GRN_TABLE_MAX_KEY_SIZE];
+ int domain_name_size;
+
+ domain = grn_ctx_at(ctx, domain_id);
+ domain_name_size = grn_obj_name(ctx, domain, domain_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "%S: failed to convert to %S: %S",
+ mrb_str_new_static(mrb, context, strlen(context)),
+ mrb_str_new_static(mrb, domain_name, domain_name_size),
+ mrb_funcall(mrb, mrb_value_, "inspect", 0));
+ }
+ *raw_value = GRN_BULK_HEAD(&(buffer->to));
+ *raw_value_size = GRN_BULK_VSIZE(&(buffer->to));
+}
+
+mrb_value
+grn_mrb_value_from_raw_data(mrb_state *mrb,
+ grn_id domain,
+ void *raw_value,
+ unsigned int raw_value_size)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_value_;
+
+ switch (domain) {
+ case GRN_DB_INT32 :
+ if (raw_value_size == 0) {
+ mrb_value_ = mrb_fixnum_value(0);
+ } else {
+ int32_t value;
+ value = *((int32_t *)raw_value);
+ mrb_value_ = mrb_fixnum_value(value);
+ }
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ mrb_value_ = mrb_str_new(mrb,
+ raw_value,
+ raw_value_size);
+ break;
+ default :
+ {
+ grn_obj *domain_object;
+#define MESSAGE_SIZE 4096
+ char message[MESSAGE_SIZE];
+ char domain_name[GRN_TABLE_MAX_KEY_SIZE];
+ int domain_name_size;
+
+ domain_object = grn_ctx_at(ctx, domain);
+ if (domain_object) {
+ domain_name_size = grn_obj_name(ctx, domain_object,
+ domain_name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_obj_unlink(ctx, domain_object);
+ } else {
+ grn_strcpy(domain_name, GRN_TABLE_MAX_KEY_SIZE, "unknown");
+ domain_name_size = strlen(domain_name);
+ }
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "unsupported raw value type: <%d>(%.*s)",
+ domain,
+ domain_name_size,
+ domain_name);
+ mrb_raise(mrb, E_RANGE_ERROR, message);
+ }
+#undef MESSAGE_SIZE
+ break;
+ }
+
+ return mrb_value_;
+}
+
+struct RClass *
+grn_mrb_class_from_grn_obj(mrb_state *mrb, grn_obj *object)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_mrb_data *data;
+ struct RClass *klass = NULL;
+
+ data = &(ctx->impl->mrb);
+ switch (object->header.type) {
+ case GRN_BULK :
+ klass = mrb_class_get_under(mrb, data->module, "Bulk");
+ break;
+ case GRN_PTR :
+ klass = mrb_class_get_under(mrb, data->module, "Pointer");
+ break;
+ case GRN_ACCESSOR :
+ klass = mrb_class_get_under(mrb, data->module, "Accessor");
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ klass = mrb_class_get_under(mrb, data->module, "FixedSizeColumn");
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ klass = mrb_class_get_under(mrb, data->module, "VariableSizeColumn");
+ break;
+ case GRN_COLUMN_INDEX :
+ klass = mrb_class_get_under(mrb, data->module, "IndexColumn");
+ break;
+ case GRN_TYPE :
+ klass = mrb_class_get_under(mrb, data->module, "Type");
+ break;
+ case GRN_PROC :
+ klass = mrb_class_get_under(mrb, data->module, "Procedure");
+ break;
+ case GRN_EXPR :
+ klass = mrb_class_get_under(mrb, data->module, "Expression");
+ break;
+ case GRN_TABLE_NO_KEY :
+ klass = mrb_class_get_under(mrb, data->module, "Array");
+ break;
+ case GRN_TABLE_HASH_KEY :
+ klass = mrb_class_get_under(mrb, data->module, "HashTable");
+ break;
+ case GRN_TABLE_PAT_KEY :
+ klass = mrb_class_get_under(mrb, data->module, "PatriciaTrie");
+ break;
+ case GRN_TABLE_DAT_KEY :
+ klass = mrb_class_get_under(mrb, data->module, "DoubleArrayTrie");
+ break;
+ case GRN_DB :
+ klass = mrb_class_get_under(mrb, data->module, "Database");
+ break;
+ case GRN_VOID :
+ klass = mrb_class_get_under(mrb, data->module, "Void");
+ break;
+ default :
+ break;
+ }
+
+ if (!klass) {
+#define BUFFER_SIZE 1024
+ char buffer[BUFFER_SIZE];
+ grn_snprintf(buffer, BUFFER_SIZE, BUFFER_SIZE,
+ "can't find class for object type: %#x", object->header.type);
+ mrb_raise(mrb, E_ARGUMENT_ERROR, buffer);
+#undef BUFFER_SIZE
+ }
+
+ return klass;
+}
+
+mrb_value
+grn_mrb_value_from_grn_obj(mrb_state *mrb, grn_obj *object)
+{
+ struct RClass *mrb_class;
+ mrb_value mrb_new_arguments[1];
+ mrb_value mrb_object;
+
+ if (!object) {
+ return mrb_nil_value();
+ }
+
+ mrb_class = grn_mrb_class_from_grn_obj(mrb, object);
+ mrb_new_arguments[0] = mrb_cptr_value(mrb, object);
+ mrb_object = mrb_obj_new(mrb, mrb_class, 1, mrb_new_arguments);
+ return mrb_object;
+}
+
+grn_id
+grn_mrb_class_to_type(mrb_state *mrb, struct RClass *klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_id type = GRN_DB_VOID;
+
+ if (klass == mrb->nil_class) {
+ type = GRN_DB_VOID;
+ } else if (klass == mrb->true_class ||
+ klass == mrb->false_class) {
+ type = GRN_DB_BOOL;
+ } else if (klass == mrb->symbol_class) {
+ type = GRN_DB_TEXT;
+ } else if (klass == mrb->fixnum_class) {
+ type = GRN_DB_INT64;
+ } else if (klass == mrb->float_class) {
+ type = GRN_DB_FLOAT;
+ } else if (klass == mrb->string_class) {
+ type = GRN_DB_TEXT;
+ } else if (klass == ctx->impl->mrb.builtin.time_class) {
+ type = GRN_DB_TIME;
+ } else {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "unsupported class: %S", mrb_obj_value(klass));
+ }
+
+ return type;
+}
+
+static mrb_value
+mrb_grn_converter_class_convert(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *from = &(ctx->impl->mrb.buffer.from);
+ grn_obj *to = &(ctx->impl->mrb.buffer.to);
+ mrb_value mrb_from;
+ mrb_value mrb_to_class;
+ grn_id to_type;
+
+ mrb_get_args(mrb, "oC", &mrb_from, &mrb_to_class);
+
+ grn_mrb_value_to_bulk(mrb, mrb_from, from);
+ to_type = grn_mrb_class_to_type(mrb, mrb_class_ptr(mrb_to_class));
+ if (!grn_mrb_bulk_cast(mrb, from, to, to_type)) {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "failed to convert to %S: %S",
+ mrb_to_class,
+ mrb_from);
+ }
+
+ return grn_mrb_value_from_bulk(mrb, to);
+}
+
+void
+grn_mrb_converter_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module;
+
+ module = mrb_define_module_under(mrb, data->module, "Converter");
+
+ mrb_define_class_method(mrb, module, "convert",
+ mrb_grn_converter_class_convert,
+ MRB_ARGS_REQ(2));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.h
new file mode 100644
index 00000000..9b8546dd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_converter.h
@@ -0,0 +1,64 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GRN_MRB_DATA_PTR(mrb_object) \
+ (mrb_nil_p((mrb_object)) ? NULL : DATA_PTR((mrb_object)))
+
+void grn_mrb_converter_init(grn_ctx *ctx);
+
+typedef struct {
+ grn_obj from;
+ grn_obj to;
+ union {
+ int64_t time_value;
+ } value;
+} grn_mrb_value_to_raw_data_buffer;
+
+void grn_mrb_value_to_raw_data_buffer_init(mrb_state *mrb,
+ grn_mrb_value_to_raw_data_buffer *buffer);
+void grn_mrb_value_to_raw_data_buffer_fin(mrb_state *mrb,
+ grn_mrb_value_to_raw_data_buffer *buffer);
+void grn_mrb_value_to_raw_data(mrb_state *mrb,
+ const char *context,
+ mrb_value mrb_value_,
+ grn_id domain_id,
+ grn_mrb_value_to_raw_data_buffer *buffer,
+ void **raw_value,
+ unsigned int *raw_value_size);
+mrb_value grn_mrb_value_from_raw_data(mrb_state *mrb,
+ grn_id domain,
+ void *raw_value,
+ unsigned int raw_value_size);
+
+struct RClass *grn_mrb_class_from_grn_obj(mrb_state *mrb, grn_obj *object);
+mrb_value grn_mrb_value_from_grn_obj(mrb_state *mrb, grn_obj *object);
+
+grn_id grn_mrb_class_to_grn_type(mrb_state *mrb, struct RClass *klass);
+grn_id grn_mrb_value_to_grn_type(mrb_state *mrb, mrb_value value);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.c
new file mode 100644
index 00000000..e89df53e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.c
@@ -0,0 +1,838 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/variable.h>
+#include <mruby/string.h>
+
+#include "../grn_mrb.h"
+#include "mrb_ctx.h"
+#include "mrb_bulk.h"
+#include "mrb_converter.h"
+
+static mrb_value
+ctx_class_instance(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_ctx;
+ mrb_sym iv_name;
+
+ iv_name = mrb_intern_lit(mrb, "@instance");
+ mrb_ctx = mrb_iv_get(mrb, klass, iv_name);
+ if (mrb_nil_p(mrb_ctx)) {
+ struct RBasic *raw_mrb_ctx;
+ raw_mrb_ctx = mrb_obj_alloc(mrb, MRB_TT_DATA, mrb_class_ptr(klass));
+ mrb_ctx = mrb_obj_value(raw_mrb_ctx);
+ DATA_PTR(mrb_ctx) = ctx;
+ mrb_iv_set(mrb, klass, iv_name, mrb_ctx);
+ }
+
+ return mrb_ctx;
+}
+
+static mrb_value
+ctx_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_id_or_name;
+ grn_obj *object;
+
+ mrb_get_args(mrb, "o", &mrb_id_or_name);
+
+ if (mrb_nil_p(mrb_id_or_name)) {
+ return mrb_nil_value();
+ }
+
+ if (mrb_fixnum_p(mrb_id_or_name)) {
+ grn_id id = mrb_fixnum(mrb_id_or_name);
+ object = grn_ctx_at(ctx, id);
+ } else {
+ mrb_value mrb_name;
+ mrb_name = mrb_convert_type(mrb, mrb_id_or_name,
+ MRB_TT_STRING, "String", "to_str");
+ object = grn_ctx_get(ctx,
+ RSTRING_PTR(mrb_name),
+ RSTRING_LEN(mrb_name));
+ }
+
+ return grn_mrb_value_from_grn_obj(mrb, object);
+}
+
+static mrb_value
+ctx_get_rc(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_fixnum_value(ctx->rc);
+}
+
+static mrb_value
+ctx_set_rc(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int rc;
+
+ mrb_get_args(mrb, "i", &rc);
+ ctx->rc = rc;
+
+ return mrb_fixnum_value(ctx->rc);
+}
+
+static mrb_value
+ctx_get_error_level(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_fixnum_value(ctx->errlvl);
+}
+
+static mrb_value
+ctx_set_error_level(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int error_level;
+
+ mrb_get_args(mrb, "i", &error_level);
+ ctx->errlvl = error_level;
+
+ return mrb_fixnum_value(ctx->errlvl);
+}
+
+static mrb_value
+ctx_get_error_file(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_str_new_cstr(mrb, ctx->errfile);
+}
+
+static mrb_value
+ctx_set_error_file(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value error_file;
+
+ mrb_get_args(mrb, "S", &error_file);
+ mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@error_file"), error_file);
+ ctx->errfile = mrb_string_value_cstr(mrb, &error_file);
+
+ return error_file;
+}
+
+static mrb_value
+ctx_get_error_line(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_fixnum_value(ctx->errline);
+}
+
+static mrb_value
+ctx_set_error_line(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int error_line;
+
+ mrb_get_args(mrb, "i", &error_line);
+ ctx->errline = error_line;
+
+ return mrb_fixnum_value(ctx->errline);
+}
+
+static mrb_value
+ctx_get_error_method(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_str_new_cstr(mrb, ctx->errfunc);
+}
+
+static mrb_value
+ctx_set_error_method(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value error_method;
+
+ mrb_get_args(mrb, "S", &error_method);
+ mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@error_method"), error_method);
+ ctx->errfunc = mrb_string_value_cstr(mrb, &error_method);
+
+ return error_method;
+}
+
+static mrb_value
+ctx_get_error_message(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_str_new_cstr(mrb, ctx->errbuf);
+}
+
+static mrb_value
+ctx_set_error_message(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value error_message;
+
+ mrb_get_args(mrb, "S", &error_message);
+ grn_ctx_log(ctx, "%.*s",
+ (int)RSTRING_LEN(error_message),
+ RSTRING_PTR(error_message));
+
+ return error_message;
+}
+
+static mrb_value
+ctx_clear_error(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ ERRCLR(ctx);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+ctx_get_command_version(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return mrb_fixnum_value(grn_ctx_get_command_version(ctx));
+}
+
+static mrb_value
+ctx_set_command_version(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int command_version;
+
+ mrb_get_args(mrb, "i", &command_version);
+ grn_ctx_set_command_version(ctx, command_version);
+
+ return mrb_fixnum_value(command_version);
+}
+
+static mrb_value
+ctx_get_output(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return grn_mrb_value_from_bulk(mrb, ctx->impl->output.buf);
+}
+
+static mrb_value
+ctx_set_output(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_value_;
+
+ mrb_get_args(mrb, "S", &mrb_value_);
+ GRN_TEXT_SET(ctx, ctx->impl->output.buf,
+ RSTRING_PTR(mrb_value_),
+ RSTRING_LEN(mrb_value_));
+
+ return mrb_value_;
+}
+
+static mrb_value
+ctx_get_database(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ return grn_mrb_value_from_grn_obj(mrb, grn_ctx_db(ctx));
+}
+
+static mrb_value
+ctx_is_opened(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int mrb_id;
+
+ mrb_get_args(mrb, "i", &mrb_id);
+
+ return mrb_bool_value(grn_ctx_is_opened(ctx, mrb_id));
+}
+
+void
+grn_mrb_ctx_check(mrb_state *mrb)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ struct RClass *module = data->module;
+ struct RClass *error_class = NULL;
+#define MESSAGE_SIZE 4096
+ char message[MESSAGE_SIZE];
+
+ switch (ctx->rc) {
+ case GRN_SUCCESS:
+ return;
+ case GRN_END_OF_DATA:
+ error_class = mrb_class_get_under(mrb, module, "EndOfData");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "end of data: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_UNKNOWN_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "UnknownError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "unknown error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_OPERATION_NOT_PERMITTED:
+ error_class = mrb_class_get_under(mrb, module, "OperationNotPermitted");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "operation not permitted: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_SUCH_FILE_OR_DIRECTORY:
+ error_class = mrb_class_get_under(mrb, module, "NoSuchFileOrDirectory");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no such file or directory: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_SUCH_PROCESS:
+ error_class = mrb_class_get_under(mrb, module, "NoSuchProcess");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no such process: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INTERRUPTED_FUNCTION_CALL:
+ error_class = mrb_class_get_under(mrb, module, "InterruptedFunctionCall");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "interrupted function call: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INPUT_OUTPUT_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "InputOutputError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "input output error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_SUCH_DEVICE_OR_ADDRESS:
+ error_class = mrb_class_get_under(mrb, module, "NoSuchDeviceOrAddress");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no such device or address: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_ARG_LIST_TOO_LONG:
+ error_class = mrb_class_get_under(mrb, module, "ArgListTooLong");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "arg list too long: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_EXEC_FORMAT_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "ExecFormatError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "exec format error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_BAD_FILE_DESCRIPTOR:
+ error_class = mrb_class_get_under(mrb, module, "BadFileDescriptor");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "bad file descriptor: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_CHILD_PROCESSES:
+ error_class = mrb_class_get_under(mrb, module, "NoChildProcesses");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no child processes: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_RESOURCE_TEMPORARILY_UNAVAILABLE:
+ error_class = mrb_class_get_under(mrb, module,
+ "ResourceTemporarilyUnavailable");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "resource temporarily unavailable: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NOT_ENOUGH_SPACE:
+ error_class = mrb_class_get_under(mrb, module, "NotEnoughSpace");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "not enough space: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_PERMISSION_DENIED:
+ error_class = mrb_class_get_under(mrb, module, "PermissionDenied");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "permission denied: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_BAD_ADDRESS:
+ error_class = mrb_class_get_under(mrb, module, "BadAddress");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "bad address: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_RESOURCE_BUSY:
+ error_class = mrb_class_get_under(mrb, module, "ResourceBusy");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "resource busy: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_FILE_EXISTS:
+ error_class = mrb_class_get_under(mrb, module, "FileExists");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "file exists: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_IMPROPER_LINK:
+ error_class = mrb_class_get_under(mrb, module, "ImproperLink");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "improper link: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_SUCH_DEVICE:
+ error_class = mrb_class_get_under(mrb, module, "NoSuchDevice");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no such device: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NOT_A_DIRECTORY:
+ error_class = mrb_class_get_under(mrb, module, "NotDirectory");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "not directory: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_IS_A_DIRECTORY:
+ error_class = mrb_class_get_under(mrb, module, "IsDirectory");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "is directory: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INVALID_ARGUMENT:
+ error_class = mrb_class_get_under(mrb, module, "InvalidArgument");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "invalid argument: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_MANY_OPEN_FILES_IN_SYSTEM:
+ error_class = mrb_class_get_under(mrb, module, "TooManyOpenFilesInSystem");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too many open files in system: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_MANY_OPEN_FILES:
+ error_class = mrb_class_get_under(mrb, module, "TooManyOpenFiles");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too many open files: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INAPPROPRIATE_I_O_CONTROL_OPERATION:
+ error_class = mrb_class_get_under(mrb, module,
+ "InappropriateIOControlOperation");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "inappropriate IO control operation: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_FILE_TOO_LARGE:
+ error_class = mrb_class_get_under(mrb, module, "FileTooLarge");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "file too large: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_SPACE_LEFT_ON_DEVICE:
+ error_class = mrb_class_get_under(mrb, module, "NoSpaceLeftOnDevice");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no space left on device: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INVALID_SEEK:
+ error_class = mrb_class_get_under(mrb, module, "InvalidSeek");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "invalid seek: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_READ_ONLY_FILE_SYSTEM:
+ error_class = mrb_class_get_under(mrb, module, "ReadOnlyFileSystem");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "read only file system: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_MANY_LINKS:
+ error_class = mrb_class_get_under(mrb, module, "TooManyLinks");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too many links: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_BROKEN_PIPE:
+ error_class = mrb_class_get_under(mrb, module, "BrokenPipe");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "broken pipe: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_DOMAIN_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "DomainError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "domain error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_RESULT_TOO_LARGE:
+ error_class = mrb_class_get_under(mrb, module, "ResultTooLarge");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "result too large: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_RESOURCE_DEADLOCK_AVOIDED:
+ error_class = mrb_class_get_under(mrb, module, "ResourceDeadlockAvoided");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "resource deadlock avoided: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_MEMORY_AVAILABLE:
+ error_class = mrb_class_get_under(mrb, module, "NoMemoryAvailable");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no memory available: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_FILENAME_TOO_LONG:
+ error_class = mrb_class_get_under(mrb, module, "FilenameTooLong");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "filename too long: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_LOCKS_AVAILABLE:
+ error_class = mrb_class_get_under(mrb, module, "NoLocksAvailable");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no locks available: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_FUNCTION_NOT_IMPLEMENTED:
+ error_class = mrb_class_get_under(mrb, module, "FunctionNotImplemented");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "function not implemented: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_DIRECTORY_NOT_EMPTY:
+ error_class = mrb_class_get_under(mrb, module, "DirectoryNotEmpty");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "directory not empty: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_ILLEGAL_BYTE_SEQUENCE:
+ error_class = mrb_class_get_under(mrb, module, "IllegalByteSequence");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "illegal byte sequence: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_SOCKET_NOT_INITIALIZED:
+ error_class = mrb_class_get_under(mrb, module, "SocketNotInitialized");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "socket not initialized: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_OPERATION_WOULD_BLOCK:
+ error_class = mrb_class_get_under(mrb, module, "OperationWouldBlock");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "operation would block: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_ADDRESS_IS_NOT_AVAILABLE:
+ error_class = mrb_class_get_under(mrb, module, "AddressIsNotAvailable");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "address is not available: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NETWORK_IS_DOWN:
+ error_class = mrb_class_get_under(mrb, module, "NetworkIsDown");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "network is down: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NO_BUFFER:
+ error_class = mrb_class_get_under(mrb, module, "NoBuffer");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "no buffer: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_SOCKET_IS_ALREADY_CONNECTED:
+ error_class = mrb_class_get_under(mrb, module, "SocketIsAlreadyConnected");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "socket is already connected: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_SOCKET_IS_NOT_CONNECTED:
+ error_class = mrb_class_get_under(mrb, module, "SocketIsNotConnected");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "socket is not connected: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_SOCKET_IS_ALREADY_SHUTDOWNED:
+ error_class = mrb_class_get_under(mrb, module, "SocketIsAlreadyShutdowned");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "socket is already shutdowned: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_OPERATION_TIMEOUT:
+ error_class = mrb_class_get_under(mrb, module, "OperationTimeout");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "operation timeout: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_CONNECTION_REFUSED:
+ error_class = mrb_class_get_under(mrb, module, "ConnectionRefused");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "connection refused: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_RANGE_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "RangeError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "range error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOKENIZER_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "TokenizerError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "tokenizer error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_FILE_CORRUPT:
+ error_class = mrb_class_get_under(mrb, module, "FileCorrupt");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "file corrupt: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INVALID_FORMAT:
+ error_class = mrb_class_get_under(mrb, module, "InvalidFormat");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "invalid format: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_OBJECT_CORRUPT:
+ error_class = mrb_class_get_under(mrb, module, "ObjectCorrupt");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "object corrupt: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_MANY_SYMBOLIC_LINKS:
+ error_class = mrb_class_get_under(mrb, module, "TooManySymbolicLinks");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too many symbolic links: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NOT_SOCKET:
+ error_class = mrb_class_get_under(mrb, module, "NotSocket");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "not socket: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_OPERATION_NOT_SUPPORTED:
+ error_class = mrb_class_get_under(mrb, module, "OperationNotSupported");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "operation not supported: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_ADDRESS_IS_IN_USE:
+ error_class = mrb_class_get_under(mrb, module, "AddressIsInUse");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "address is in use: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_ZLIB_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "ZlibError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "zlib error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_LZ4_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "LZ4Error");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "LZ4 error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_STACK_OVER_FLOW:
+ error_class = mrb_class_get_under(mrb, module, "StackOverFlow");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "stack over flow: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_SYNTAX_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "SyntaxError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "syntax error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_RETRY_MAX:
+ error_class = mrb_class_get_under(mrb, module, "RetryMax");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "retry max: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_INCOMPATIBLE_FILE_FORMAT:
+ error_class = mrb_class_get_under(mrb, module, "IncompatibleFileFormat");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "incompatible file format: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_UPDATE_NOT_ALLOWED:
+ error_class = mrb_class_get_under(mrb, module, "UpdateNotAllowed");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "update not allowed: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_SMALL_OFFSET:
+ error_class = mrb_class_get_under(mrb, module, "TooSmallOffset");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too small offset: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_LARGE_OFFSET:
+ error_class = mrb_class_get_under(mrb, module, "TooLargeOffset");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too large offset: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOO_SMALL_LIMIT:
+ error_class = mrb_class_get_under(mrb, module, "TooSmallLimit");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "too small limit: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_CAS_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "CASError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "CAS error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_UNSUPPORTED_COMMAND_VERSION:
+ error_class = mrb_class_get_under(mrb, module, "UnsupportedCommandVersion");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "unsupported command version: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_NORMALIZER_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "NormalizerError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "normalizer error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_TOKEN_FILTER_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "TokenFilterError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "token filter error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_COMMAND_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "CommandError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "command error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_PLUGIN_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "PluginError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "plugin error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_SCORER_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "ScorerError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "scorer error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_CANCEL:
+ error_class = mrb_class_get_under(mrb, module, "Cancel");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "cancel: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_WINDOW_FUNCTION_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "WindowFunctionError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "window function error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ case GRN_ZSTD_ERROR:
+ error_class = mrb_class_get_under(mrb, module, "ZstdError");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "Zstandard error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ break;
+ }
+
+ if (!error_class) {
+ error_class = mrb_class_get_under(mrb, module, "Error");
+ grn_snprintf(message, MESSAGE_SIZE, MESSAGE_SIZE,
+ "unsupported error: <%s>(%d)",
+ ctx->errbuf, ctx->rc);
+ }
+#undef MESSAGE_SIZE
+
+ mrb_raise(mrb, error_class, message);
+}
+
+void
+grn_mrb_ctx_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Context", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "instance",
+ ctx_class_instance, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "[]", ctx_array_reference, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "rc", ctx_get_rc, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "rc=", ctx_set_rc, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "error_level", ctx_get_error_level,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "error_level=", ctx_set_error_level,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "error_file", ctx_get_error_file,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "error_file=", ctx_set_error_file,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "error_line", ctx_get_error_line,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "error_line=", ctx_set_error_line,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "error_method", ctx_get_error_method,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "error_method=", ctx_set_error_method,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "error_message", ctx_get_error_message,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "error_message=", ctx_set_error_message,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "clear_error", ctx_clear_error, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "command_version",
+ ctx_get_command_version, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "command_version=",
+ ctx_set_command_version, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "output",
+ ctx_get_output, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "output=",
+ ctx_set_output, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "database", ctx_get_database,
+ MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "opened?", ctx_is_opened,
+ MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.h
new file mode 100644
index 00000000..72519ae6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_ctx.h
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_ctx_init(grn_ctx *ctx);
+void grn_mrb_ctx_check(mrb_state *mrb);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_database.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_database.c
new file mode 100644
index 00000000..5ff2bdbe
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_database.c
@@ -0,0 +1,206 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_ctx.h"
+#include "mrb_database.h"
+#include "mrb_converter.h"
+
+static struct mrb_data_type mrb_grn_database_type = {
+ "Groonga::Database",
+ NULL
+};
+
+static mrb_value
+mrb_grn_database_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_database_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_database_ptr);
+ DATA_TYPE(self) = &mrb_grn_database_type;
+ DATA_PTR(self) = mrb_cptr(mrb_database_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_database_class_open(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *database;
+ char *path;
+
+ mrb_get_args(mrb, "z", &path);
+
+ database = grn_db_open(ctx, path);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_funcall(mrb, klass, "new", 1, mrb_cptr_value(mrb, database));
+}
+
+static mrb_value
+mrb_grn_database_class_create(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *database;
+ char *path;
+
+ mrb_get_args(mrb, "z", &path);
+
+ database = grn_db_create(ctx, path, NULL);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_funcall(mrb, klass, "new", 1, mrb_cptr_value(mrb, database));
+}
+
+static mrb_value
+mrb_grn_database_recover(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ grn_db_recover(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_database_is_locked(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ unsigned int is_locked;
+
+ is_locked = grn_obj_is_locked(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_bool_value(is_locked != 0);
+}
+
+static mrb_value
+mrb_grn_database_get_last_modified(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ uint32_t last_modified;
+ struct RClass *time_class;
+
+ last_modified = grn_db_get_last_modified(ctx, DATA_PTR(self));
+
+ time_class = mrb_class_get(mrb, "Time");
+ return mrb_funcall(mrb,
+ mrb_obj_value(time_class),
+ "at",
+ 1,
+ mrb_float_value(mrb, last_modified));
+}
+
+static mrb_value
+mrb_grn_database_is_dirty(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_bool is_dirty;
+
+ is_dirty = grn_db_is_dirty(ctx, DATA_PTR(self));
+
+ return mrb_bool_value(is_dirty);
+}
+
+static mrb_value
+mrb_grn_database_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *database;
+ mrb_value mrb_id_or_key;
+
+ mrb_get_args(mrb, "o", &mrb_id_or_key);
+
+ database = DATA_PTR(self);
+
+ if (mrb_fixnum_p(mrb_id_or_key)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ name_size = grn_table_get_key(ctx,
+ grn_ctx_db(ctx),
+ mrb_fixnum(mrb_id_or_key),
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ if (name_size == 0) {
+ return mrb_nil_value();
+ } else {
+ return mrb_str_new(mrb, name, name_size);
+ }
+ } else {
+ grn_id name_domain_id = GRN_DB_SHORT_TEXT;
+ grn_id id;
+ grn_mrb_value_to_raw_data_buffer buffer;
+ void *name;
+ unsigned int name_size;
+
+ grn_mrb_value_to_raw_data_buffer_init(mrb, &buffer);
+ grn_mrb_value_to_raw_data(mrb, "name", mrb_id_or_key,
+ name_domain_id, &buffer,
+ &name, &name_size);
+ id = grn_table_get(ctx, database, name, name_size);
+ grn_mrb_value_to_raw_data_buffer_fin(mrb, &buffer);
+
+ if (id == GRN_ID_NIL) {
+ return mrb_nil_value();
+ } else {
+ return mrb_fixnum_value(id);
+ }
+ }
+}
+
+void
+grn_mrb_database_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *object_class = data->object_class;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Database", object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "open",
+ mrb_grn_database_class_open,
+ MRB_ARGS_REQ(1));
+ mrb_define_class_method(mrb, klass, "create",
+ mrb_grn_database_class_create,
+ MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_database_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "recover",
+ mrb_grn_database_recover, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "locked?",
+ mrb_grn_database_is_locked, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "last_modified",
+ mrb_grn_database_get_last_modified, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "dirty?",
+ mrb_grn_database_is_dirty, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "[]",
+ mrb_grn_database_array_reference, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_database.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_database.h
new file mode 100644
index 00000000..512e33c9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_database.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_database_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.c
new file mode 100644
index 00000000..20007fef
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.c
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_double_array_trie.h"
+
+static struct mrb_data_type mrb_grn_double_array_trie_type = {
+ "Groonga::DoubleArrayTrie",
+ NULL
+};
+
+static mrb_value
+mrb_grn_double_array_trie_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_double_array_trie_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_double_array_trie_ptr);
+ DATA_TYPE(self) = &mrb_grn_double_array_trie_type;
+ DATA_PTR(self) = mrb_cptr(mrb_double_array_trie_ptr);
+ return self;
+}
+
+void
+grn_mrb_double_array_trie_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *table_class;
+ struct RClass *klass;
+
+ table_class = mrb_class_get_under(mrb, module, "Table");
+ klass = mrb_define_class_under(mrb, module, "DoubleArrayTrie", table_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_double_array_trie_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.h
new file mode 100644
index 00000000..4e7bd59d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_double_array_trie.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_double_array_trie_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_error.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_error.c
new file mode 100644
index 00000000..f162d499
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_error.c
@@ -0,0 +1,202 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+
+#include "../grn_mrb.h"
+#include "mrb_error.h"
+
+void
+grn_mrb_error_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *error_class;
+ struct RClass *groonga_error_class;
+
+ error_class = mrb_define_class_under(mrb, module, "Error",
+ mrb->eStandardError_class);
+ groonga_error_class = mrb_define_class_under(mrb, module, "GroongaError",
+ error_class);
+
+ mrb_define_class_under(mrb, module, "EndOfData",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "UnknownError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "OperationNotPermitted",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoSuchFileOrDirectory",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoSuchProcess",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "InterruptedFunctionCall",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "InputOutputError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoSuchDeviceOrAddress",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ArgListTooLong",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ExecFormatError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "BadFileDescriptor",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoChildProcesses",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ResourceTemporarilyUnavailable",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NotEnoughSpace",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "PermissionDenied",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "BadAddress",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ResourceBusy",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "FileExists",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ImproperLink",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoSuchDevice",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NotDirectory",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "IsDirectory",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "InvalidArgument",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooManyOpenFilesInSystem",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooManyOpenFiles",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "InappropriateIOControlOperation",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "FileTooLarge",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoSpaceLeftOnDevice",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "InvalidSeek",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ReadOnlyFileSystem",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooManyLinks",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "BrokenPipe",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "DomainError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ResultTooLarge",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ResourceDeadlockAvoided",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoMemoryAvailable",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "FilenameTooLong",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoLocksAvailable",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "FunctionNotImplemented",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "DirectoryNotEmpty",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "IllegalByteSequence",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "SocketNotInitialized",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "OperationWouldBlock",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "AddressIsNotAvailable",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NetworkIsDown",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NoBuffer",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "SocketIsAlreadyConnected",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "SocketIsNotConnected",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "SocketIsAlreadyShutdowned",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "OperationTimeout",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ConnectionRefused",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "RangeError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TokenizerError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "FileCorrupt",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "InvalidFormat",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ObjectCorrupt",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooManySymbolicLinks",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NotSocket",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "OperationNotSupported",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "AddressIsInUse",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ZlibError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "LZ4Error",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "StackOverFlow",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "SyntaxError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "RetryMax",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "IncompatibleFileFormat",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "UpdateNotAllowed",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooSmallOffset",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooLargeOffset",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TooSmallLimit",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "CASError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "UnsupportedCommandVersion",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "NormalizerError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "TokenFilterError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "CommandError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "PluginError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ScorerError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "Cancel",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "WindowFunctionError",
+ groonga_error_class);
+ mrb_define_class_under(mrb, module, "ZstdError",
+ groonga_error_class);
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_error.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_error.h
new file mode 100644
index 00000000..917bfec5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_error.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_error_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.c
new file mode 100644
index 00000000..fd5be59c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.c
@@ -0,0 +1,98 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/proc.h>
+#include <mruby/compile.h>
+#include <mruby/opcode.h>
+
+#include "../grn_mrb.h"
+#include "mrb_ctx.h"
+#include "mrb_eval_context.h"
+
+static mrb_value
+eval_context_compile(mrb_state *mrb, mrb_value self)
+{
+ char *script;
+ mrb_int script_length;
+ mrbc_context* compile_ctx;
+ struct mrb_parser_state *parser;
+ struct RProc *proc;
+
+ mrb_get_args(mrb, "s", &script, &script_length);
+
+ compile_ctx = mrbc_context_new(mrb);
+ if (!compile_ctx) {
+ mrb_raise(mrb, E_RUNTIME_ERROR,
+ "[mruby][eval][compile] failed to allocate context");
+ }
+ compile_ctx->capture_errors = TRUE;
+
+ parser = mrb_parse_nstring(mrb, script, script_length, compile_ctx);
+ if (!parser) {
+ mrbc_context_free(mrb, compile_ctx);
+ mrb_raise(mrb, E_RUNTIME_ERROR,
+ "[mruby][eval][compile] failed to allocate parser");
+ }
+ if (parser->nerr > 0) {
+ struct mrb_parser_message *error = &(parser->error_buffer[0]);
+ mrb_value new_args[1];
+ mrb_value exception;
+
+ new_args[0] = mrb_format(mrb,
+ "line %S:%S: %S",
+ mrb_fixnum_value(error->lineno),
+ mrb_fixnum_value(error->column),
+ mrb_str_new_cstr(mrb, error->message));
+ exception = mrb_obj_new(mrb, E_SYNTAX_ERROR, 1, new_args);
+ mrb_parser_free(parser);
+ mrbc_context_free(mrb, compile_ctx);
+
+ mrb_exc_raise(mrb, exception);
+ }
+
+ proc = mrb_generate_code(mrb, parser);
+ {
+ mrb_code *iseq = proc->body.irep->iseq;
+ while (GET_OPCODE(*iseq) != OP_STOP) {
+ iseq++;
+ }
+ *iseq = MKOP_AB(OP_RETURN, 1, OP_R_NORMAL);
+ }
+ mrb_parser_free(parser);
+ mrbc_context_free(mrb, compile_ctx);
+ return mrb_obj_value(proc);
+}
+
+void
+grn_mrb_eval_context_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "EvalContext", mrb->object_class);
+
+ mrb_define_method(mrb, klass, "compile", eval_context_compile,
+ MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.h
new file mode 100644
index 00000000..c277ed5e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_eval_context.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_eval_context_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.c
new file mode 100644
index 00000000..2b8f6a04
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.c
@@ -0,0 +1,1079 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/variable.h>
+#include <mruby/data.h>
+#include <mruby/string.h>
+#include <mruby/array.h>
+#include <mruby/hash.h>
+
+#include "../grn_expr.h"
+#include "../grn_proc.h"
+#include "../grn_util.h"
+#include "../grn_mrb.h"
+#include "mrb_accessor.h"
+#include "mrb_ctx.h"
+#include "mrb_expr.h"
+#include "mrb_operator.h"
+#include "mrb_converter.h"
+#include "mrb_options.h"
+
+static struct mrb_data_type mrb_grn_scan_info_type = {
+ "Groonga::ScanInfo",
+ NULL
+};
+static struct mrb_data_type mrb_grn_expr_code_type = {
+ "Groonga::ExpressionCode",
+ NULL
+};
+static struct mrb_data_type mrb_grn_expression_type = {
+ "Groonga::Expression",
+ NULL
+};
+
+static mrb_value
+mrb_grn_scan_info_new(mrb_state *mrb, scan_info *scan_info)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ struct RClass *module = ctx->impl->mrb.module;
+ struct RClass *klass;
+ mrb_value mrb_scan_info;
+
+ mrb_scan_info = mrb_cptr_value(mrb, scan_info);
+ klass = mrb_class_get_under(mrb, module, "ScanInfo");
+ return mrb_obj_new(mrb, klass, 1, &mrb_scan_info);
+}
+
+static mrb_value
+mrb_grn_expr_code_new(mrb_state *mrb, grn_expr_code *code)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ struct RClass *module = ctx->impl->mrb.module;
+ struct RClass *klass;
+ mrb_value mrb_code;
+
+ mrb_code = mrb_cptr_value(mrb, code);
+ klass = mrb_class_get_under(mrb, module, "ExpressionCode");
+ return mrb_obj_new(mrb, klass, 1, &mrb_code);
+}
+
+static mrb_value
+mrb_grn_scan_info_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_ptr);
+ DATA_TYPE(self) = &mrb_grn_scan_info_type;
+ DATA_PTR(self) = mrb_cptr(mrb_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_expr_code_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_code;
+
+ mrb_get_args(mrb, "o", &mrb_code);
+ DATA_TYPE(self) = &mrb_grn_expr_code_type;
+ DATA_PTR(self) = mrb_cptr(mrb_code);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_put_index(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ scan_info *si;
+ mrb_value mrb_index;
+ mrb_int sid;
+ mrb_int weight;
+ mrb_value mrb_scorer;
+ mrb_value mrb_scorer_args_expr;
+ mrb_int scorer_args_expr_offset;
+ grn_obj *index;
+ grn_obj *scorer = NULL;
+ grn_obj *scorer_args_expr = NULL;
+
+ mrb_get_args(mrb, "oiiooi",
+ &mrb_index, &sid, &weight,
+ &mrb_scorer,
+ &mrb_scorer_args_expr,
+ &scorer_args_expr_offset);
+ si = DATA_PTR(self);
+ index = DATA_PTR(mrb_index);
+ if (!mrb_nil_p(mrb_scorer)) {
+ scorer = DATA_PTR(mrb_scorer);
+ }
+ if (!mrb_nil_p(mrb_scorer_args_expr)) {
+ scorer_args_expr = DATA_PTR(mrb_scorer_args_expr);
+ }
+ grn_scan_info_put_index(ctx, si, index, sid, weight,
+ scorer,
+ scorer_args_expr,
+ scorer_args_expr_offset);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_get_op(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ grn_operator op;
+
+ si = DATA_PTR(self);
+ op = grn_scan_info_get_op(si);
+ return grn_mrb_value_from_operator(mrb, op);
+}
+
+static mrb_value
+mrb_grn_scan_info_set_op(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_value mrb_op;
+ grn_operator op;
+
+ mrb_get_args(mrb, "o", &mrb_op);
+ si = DATA_PTR(self);
+ op = grn_mrb_value_to_operator(mrb, mrb_op);
+ grn_scan_info_set_op(si, op);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_set_end(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_int end;
+
+ mrb_get_args(mrb, "i", &end);
+ si = DATA_PTR(self);
+ grn_scan_info_set_end(si, end);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_set_query(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_value mrb_query;
+
+ mrb_get_args(mrb, "o", &mrb_query);
+ si = DATA_PTR(self);
+ if (mrb_nil_p(mrb_query)) {
+ grn_scan_info_set_query(si, NULL);
+ } else {
+ grn_scan_info_set_query(si, DATA_PTR(mrb_query));
+ }
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_set_flags(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_int flags;
+
+ mrb_get_args(mrb, "i", &flags);
+ si = DATA_PTR(self);
+ grn_scan_info_set_flags(si, flags);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_get_flags(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ int flags;
+
+ si = DATA_PTR(self);
+ flags = grn_scan_info_get_flags(si);
+ return mrb_fixnum_value(flags);
+}
+
+static mrb_value
+mrb_grn_scan_info_set_logical_op(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_value mrb_logical_op;
+ grn_operator logical_op;
+
+ mrb_get_args(mrb, "o", &mrb_logical_op);
+ si = DATA_PTR(self);
+ logical_op = grn_mrb_value_to_operator(mrb, mrb_logical_op);
+ grn_scan_info_set_logical_op(si, logical_op);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_get_logical_op(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ grn_operator logical_op;
+
+ si = DATA_PTR(self);
+ logical_op = grn_scan_info_get_logical_op(si);
+ return grn_mrb_value_from_operator(mrb, logical_op);
+}
+
+static mrb_value
+mrb_grn_scan_info_set_max_interval(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_int max_interval;
+
+ mrb_get_args(mrb, "i", &max_interval);
+ si = DATA_PTR(self);
+ grn_scan_info_set_max_interval(si, max_interval);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_get_max_interval(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ int max_interval;
+
+ si = DATA_PTR(self);
+ max_interval = grn_scan_info_get_max_interval(si);
+ return mrb_fixnum_value(max_interval);
+}
+
+static mrb_value
+mrb_grn_scan_info_set_similarity_threshold(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_int similarity_threshold;
+
+ mrb_get_args(mrb, "i", &similarity_threshold);
+ si = DATA_PTR(self);
+ grn_scan_info_set_similarity_threshold(si, similarity_threshold);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_get_similarity_threshold(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ int similarity_threshold;
+
+ si = DATA_PTR(self);
+ similarity_threshold = grn_scan_info_get_similarity_threshold(si);
+ return mrb_fixnum_value(similarity_threshold);
+}
+
+static mrb_value
+mrb_grn_scan_info_get_arg(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ scan_info *si;
+ mrb_int index;
+ grn_obj *arg;
+
+ mrb_get_args(mrb, "i", &index);
+
+ si = DATA_PTR(self);
+ arg = grn_scan_info_get_arg(ctx, si, index);
+
+ return grn_mrb_value_from_grn_obj(mrb, arg);
+}
+
+static mrb_value
+mrb_grn_scan_info_push_arg(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_value mrb_arg;
+ grn_bool success;
+
+ mrb_get_args(mrb, "o", &mrb_arg);
+
+ si = DATA_PTR(self);
+ success = grn_scan_info_push_arg(si, DATA_PTR(mrb_arg));
+
+ return mrb_bool_value(success);
+}
+
+static mrb_value
+mrb_grn_scan_info_get_start_position(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ int start_position;
+
+ si = DATA_PTR(self);
+ start_position = grn_scan_info_get_start_position(si);
+ return mrb_fixnum_value(start_position);
+}
+
+static mrb_value
+mrb_grn_scan_info_set_start_position(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+ mrb_int start_position;
+
+ mrb_get_args(mrb, "i", &start_position);
+ si = DATA_PTR(self);
+ grn_scan_info_set_start_position(si, start_position);
+ return self;
+}
+
+static mrb_value
+mrb_grn_scan_info_reset_position(mrb_state *mrb, mrb_value self)
+{
+ scan_info *si;
+
+ si = DATA_PTR(self);
+ grn_scan_info_reset_position(si);
+ return self;
+}
+
+static mrb_value
+mrb_grn_expr_code_inspect(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_expr_code *code;
+ mrb_value inspected;
+
+ code = DATA_PTR(self);
+
+ inspected = mrb_str_buf_new(mrb, 48);
+
+ mrb_str_cat_lit(mrb, inspected, "#<");
+ mrb_str_cat_cstr(mrb, inspected, mrb_obj_classname(mrb, self));
+ mrb_str_cat_lit(mrb, inspected, ":");
+ mrb_str_concat(mrb, inspected, mrb_ptr_to_str(mrb, mrb_cptr(self)));
+
+ {
+ int32_t weight;
+ uint32_t offset;
+
+ weight = grn_expr_code_get_weight(ctx, DATA_PTR(self), &offset);
+
+ mrb_str_cat_lit(mrb, inspected, " weight=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ mrb_fixnum_value(weight),
+ "inspect",
+ 0));
+ mrb_str_cat_lit(mrb, inspected, ", offset=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ mrb_fixnum_value(offset),
+ "inspect",
+ 0));
+ }
+
+ mrb_str_cat_lit(mrb, inspected, ", n_args=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ mrb_fixnum_value(code->nargs),
+ "inspect",
+ 0));
+
+ mrb_str_cat_lit(mrb, inspected, ", modify=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ mrb_fixnum_value(code->modify),
+ "inspect",
+ 0));
+
+ mrb_str_cat_lit(mrb, inspected, ", op=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ grn_mrb_value_from_operator(mrb, code->op),
+ "inspect",
+ 0));
+
+ mrb_str_cat_lit(mrb, inspected, ", flags=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ mrb_fixnum_value(code->flags),
+ "inspect",
+ 0));
+
+ mrb_str_cat_lit(mrb, inspected, ", value=");
+ mrb_str_concat(mrb, inspected,
+ mrb_funcall(mrb,
+ grn_mrb_value_from_grn_obj(mrb, code->value),
+ "inspect",
+ 0));
+
+ mrb_str_cat_lit(mrb, inspected, ">");
+
+ return inspected;
+}
+
+static mrb_value
+mrb_grn_expr_code_get_weight(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ int32_t weight;
+ uint32_t offset;
+ mrb_value mrb_values[2];
+
+ weight = grn_expr_code_get_weight(ctx, DATA_PTR(self), &offset);
+ mrb_values[0] = mrb_fixnum_value(weight);
+ mrb_values[1] = mrb_fixnum_value(offset);
+ return mrb_ary_new_from_values(mrb, 2, mrb_values);
+}
+
+static mrb_value
+mrb_grn_expr_code_get_value(mrb_state *mrb, mrb_value self)
+{
+ grn_expr_code *expr_code;
+
+ expr_code = DATA_PTR(self);
+ return grn_mrb_value_from_grn_obj(mrb, expr_code->value);
+}
+
+static mrb_value
+mrb_grn_expr_code_get_n_args(mrb_state *mrb, mrb_value self)
+{
+ grn_expr_code *expr_code;
+
+ expr_code = DATA_PTR(self);
+ return mrb_fixnum_value(expr_code->nargs);
+}
+
+static mrb_value
+mrb_grn_expr_code_get_op(mrb_state *mrb, mrb_value self)
+{
+ grn_expr_code *expr_code;
+
+ expr_code = DATA_PTR(self);
+ return grn_mrb_value_from_operator(mrb, expr_code->op);
+}
+
+static mrb_value
+mrb_grn_expr_code_get_flags(mrb_state *mrb, mrb_value self)
+{
+ grn_expr_code *expr_code;
+
+ expr_code = DATA_PTR(self);
+ return mrb_fixnum_value(expr_code->flags);
+}
+
+static mrb_value
+mrb_grn_expr_code_get_modify(mrb_state *mrb, mrb_value self)
+{
+ grn_expr_code *expr_code;
+
+ expr_code = DATA_PTR(self);
+ return mrb_fixnum_value(expr_code->modify);
+}
+
+static mrb_value
+mrb_grn_expression_class_create(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_expr;
+ mrb_value mrb_table;
+ mrb_value mrb_new_arguments[1];
+ grn_obj *expr, *variable = NULL;
+
+ mrb_get_args(mrb, "o", &mrb_table);
+ if (mrb_nil_p(mrb_table)) {
+ expr = grn_expr_create(ctx, NULL, 0);
+ } else {
+ grn_obj *table = DATA_PTR(mrb_table);
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, expr, variable);
+ }
+
+ if (!expr) {
+ grn_mrb_ctx_check(mrb);
+ return mrb_nil_value();
+ }
+
+ mrb_new_arguments[0] = mrb_cptr_value(mrb, expr);
+ mrb_expr = mrb_obj_new(mrb, mrb_class_ptr(klass), 1, mrb_new_arguments);
+ {
+ mrb_value mrb_variable = mrb_nil_value();
+ if (variable) {
+ mrb_variable = grn_mrb_value_from_grn_obj(mrb, variable);
+ }
+ mrb_iv_set(mrb, mrb_expr, mrb_intern_lit(mrb, "@variable"), mrb_variable);
+ }
+
+ return mrb_expr;
+}
+
+static mrb_value
+mrb_grn_expression_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_expression_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_expression_ptr);
+ DATA_TYPE(self) = &mrb_grn_expression_type;
+ DATA_PTR(self) = mrb_cptr(mrb_expression_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_expression_is_empty(mrb_state *mrb, mrb_value self)
+{
+ grn_expr *expr;
+
+ expr = DATA_PTR(self);
+ return mrb_bool_value(expr->codes_curr == 0);
+}
+
+static mrb_value
+mrb_grn_expression_codes(mrb_state *mrb, mrb_value self)
+{
+ grn_expr *expr;
+ mrb_value mrb_codes;
+ int i;
+
+ expr = DATA_PTR(self);
+ mrb_codes = mrb_ary_new_capa(mrb, expr->codes_curr);
+ for (i = 0; i < expr->codes_curr; i++) {
+ grn_expr_code *code = expr->codes + i;
+ mrb_ary_push(mrb, mrb_codes, mrb_grn_expr_code_new(mrb, code));
+ }
+
+ return mrb_codes;
+}
+
+static mrb_value
+mrb_grn_expression_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_key;
+ grn_obj *var;
+
+ mrb_get_args(mrb, "o", &mrb_key);
+
+ expr = DATA_PTR(self);
+ switch (mrb_type(mrb_key)) {
+ case MRB_TT_SYMBOL :
+ {
+ const char *name;
+ mrb_int name_length;
+
+ name = mrb_sym2name_len(mrb, mrb_symbol(mrb_key), &name_length);
+ var = grn_expr_get_var(ctx, expr, name, name_length);
+ }
+ break;
+ case MRB_TT_STRING :
+ var = grn_expr_get_var(ctx, expr,
+ RSTRING_PTR(mrb_key), RSTRING_LEN(mrb_key));
+ break;
+ case MRB_TT_FIXNUM :
+ var = grn_expr_get_var_by_offset(ctx, expr, mrb_fixnum(mrb_key));
+ break;
+ default :
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "key must be Symbol, String or Fixnum: %S",
+ mrb_key);
+ break;
+ }
+
+ return grn_mrb_value_from_grn_obj(mrb, var);
+}
+
+static mrb_value
+mrb_grn_expression_set_condition(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_condition;
+ grn_obj *condition_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_condition);
+
+ expr = DATA_PTR(self);
+ condition_ptr = grn_expr_get_or_add_var(ctx,
+ expr,
+ GRN_SELECT_INTERNAL_VAR_CONDITION,
+ GRN_SELECT_INTERNAL_VAR_CONDITION_LEN);
+ GRN_OBJ_FIN(ctx, condition_ptr);
+ GRN_PTR_INIT(condition_ptr, 0, GRN_DB_OBJECT);
+ GRN_PTR_SET(ctx, condition_ptr, GRN_MRB_DATA_PTR(mrb_condition));
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_expression_take_object(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_object;
+ grn_obj *grn_object;
+
+ mrb_get_args(mrb, "o", &mrb_object);
+ expr = DATA_PTR(self);
+ grn_object = DATA_PTR(mrb_object);
+ grn_expr_take_obj(ctx, expr, grn_object);
+
+ return mrb_object;
+}
+
+static mrb_value
+mrb_grn_expression_allocate_constant(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_object;
+ grn_obj *grn_object;
+
+ mrb_get_args(mrb, "o", &mrb_object);
+ expr = DATA_PTR(self);
+
+ switch (mrb_type(mrb_object)) {
+ case MRB_TT_STRING:
+ grn_object = grn_expr_alloc_const(ctx, expr);
+ if (!grn_object) {
+ grn_mrb_ctx_check(mrb);
+ }
+ GRN_TEXT_INIT(grn_object, 0);
+ GRN_TEXT_SET(ctx, grn_object,
+ RSTRING_PTR(mrb_object), RSTRING_LEN(mrb_object));
+ break;
+ case MRB_TT_TRUE:
+ grn_object = grn_expr_alloc_const(ctx, expr);
+ if (!grn_object) {
+ grn_mrb_ctx_check(mrb);
+ }
+ GRN_BOOL_INIT(grn_object, 0);
+ GRN_BOOL_SET(ctx, grn_object, GRN_TRUE);
+ break;
+ default:
+ mrb_raisef(mrb, E_ARGUMENT_ERROR, "unsupported type: %S", mrb_object);
+ break;
+ }
+
+ return grn_mrb_value_from_grn_obj(mrb, grn_object);
+}
+
+static mrb_value
+mrb_grn_expression_parse(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ char *query;
+ mrb_int query_size;
+ grn_obj *default_column = NULL;
+ grn_operator default_mode = GRN_OP_MATCH;
+ grn_operator default_operator = GRN_OP_AND;
+ grn_expr_flags flags = GRN_EXPR_SYNTAX_SCRIPT;
+ mrb_value mrb_options = mrb_nil_value();
+
+ expr = DATA_PTR(self);
+ mrb_get_args(mrb, "s|H", &query, &query_size, &mrb_options);
+
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_default_column;
+ mrb_value mrb_flags;
+
+ mrb_default_column =
+ grn_mrb_options_get_lit(mrb, mrb_options, "default_column");
+ default_column = GRN_MRB_DATA_PTR(mrb_default_column);
+
+ mrb_flags = grn_mrb_options_get_lit(mrb, mrb_options, "flags");
+ if (!mrb_nil_p(mrb_flags)) {
+ flags = mrb_fixnum(mrb_flags);
+ }
+ }
+
+ grn_expr_parse(ctx, expr, query, query_size, default_column,
+ default_mode, default_operator, flags);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_expression_append_object(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_object;
+ grn_obj *object;
+ mrb_value mrb_op;
+ grn_operator op;
+ mrb_int n_args;
+
+ expr = DATA_PTR(self);
+ mrb_get_args(mrb, "ooi", &mrb_object, &mrb_op, &n_args);
+
+ object = DATA_PTR(mrb_object);
+ op = grn_mrb_value_to_operator(mrb, mrb_op);
+ grn_expr_append_obj(ctx, expr, object, op, n_args);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_expression_append_constant(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_constant;
+ mrb_value mrb_op;
+ grn_operator op;
+ mrb_int n_args;
+
+ expr = DATA_PTR(self);
+ mrb_get_args(mrb, "ooi", &mrb_constant, &mrb_op, &n_args);
+
+ op = grn_mrb_value_to_operator(mrb, mrb_op);
+ switch (mrb_type(mrb_constant)) {
+ case MRB_TT_FALSE :
+ if (mrb_nil_p(mrb_constant)) {
+ grn_obj constant;
+ GRN_VOID_INIT(&constant);
+ grn_expr_append_const(ctx, expr, &constant, op, n_args);
+ GRN_OBJ_FIN(ctx, &constant);
+ } else {
+ grn_obj constant;
+ GRN_BOOL_INIT(&constant, 0);
+ GRN_BOOL_SET(ctx, &constant, GRN_FALSE);
+ grn_expr_append_const(ctx, expr, &constant, op, n_args);
+ GRN_OBJ_FIN(ctx, &constant);
+ }
+ break;
+ case MRB_TT_TRUE :
+ {
+ grn_obj constant;
+ GRN_BOOL_INIT(&constant, 0);
+ GRN_BOOL_SET(ctx, &constant, GRN_TRUE);
+ grn_expr_append_const(ctx, expr, &constant, op, n_args);
+ GRN_OBJ_FIN(ctx, &constant);
+ }
+ break;
+ case MRB_TT_FIXNUM :
+ grn_expr_append_const_int(ctx, expr, mrb_fixnum(mrb_constant), op, n_args);
+ break;
+ case MRB_TT_SYMBOL :
+ {
+ const char *value;
+ mrb_int value_length;
+
+ value = mrb_sym2name_len(mrb, mrb_symbol(mrb_constant), &value_length);
+ grn_expr_append_const_str(ctx, expr, value, value_length, op, n_args);
+ }
+ break;
+ case MRB_TT_FLOAT :
+ {
+ grn_obj constant;
+ GRN_FLOAT_INIT(&constant, 0);
+ GRN_FLOAT_SET(ctx, &constant, mrb_float(mrb_constant));
+ grn_expr_append_const(ctx, expr, &constant, op, n_args);
+ GRN_OBJ_FIN(ctx, &constant);
+ }
+ break;
+ case MRB_TT_STRING :
+ grn_expr_append_const_str(ctx, expr,
+ RSTRING_PTR(mrb_constant),
+ RSTRING_LEN(mrb_constant),
+ op, n_args);
+ break;
+ default :
+ {
+ struct RClass *klass;
+
+ klass = mrb_class(mrb, mrb_constant);
+ if (klass == ctx->impl->mrb.builtin.time_class) {
+ grn_obj constant;
+ mrb_value mrb_sec;
+ mrb_value mrb_usec;
+
+ mrb_sec = mrb_funcall(mrb, mrb_constant, "to_i", 0);
+ mrb_usec = mrb_funcall(mrb, mrb_constant, "usec", 0);
+ GRN_TIME_INIT(&constant, 0);
+ GRN_TIME_SET(ctx, &constant,
+ GRN_TIME_PACK(mrb_fixnum(mrb_sec), mrb_fixnum(mrb_usec)));
+ grn_expr_append_const(ctx, expr, &constant, op, n_args);
+ GRN_OBJ_FIN(ctx, &constant);
+ } else {
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "unsupported constant to append to expression: %S",
+ mrb_constant);
+ }
+ }
+ break;
+ }
+
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_expression_append_operator(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *expr;
+ mrb_value mrb_op;
+ mrb_int n_args;
+ grn_operator op;
+
+ expr = DATA_PTR(self);
+ mrb_get_args(mrb, "oi", &mrb_op, &n_args);
+
+ op = grn_mrb_value_to_operator(mrb, mrb_op);
+ grn_expr_append_op(ctx, expr, op, n_args);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_expr_init(grn_ctx *ctx)
+{
+ mrb_state *mrb = ctx->impl->mrb.state;
+ struct RClass *module = ctx->impl->mrb.module;
+ struct RClass *object_class = ctx->impl->mrb.object_class;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "ScanInfo", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_scan_info_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "put_index",
+ mrb_grn_scan_info_put_index, MRB_ARGS_REQ(6));
+ mrb_define_method(mrb, klass, "op",
+ mrb_grn_scan_info_get_op, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "op=",
+ mrb_grn_scan_info_set_op, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "end=",
+ mrb_grn_scan_info_set_end, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "query=",
+ mrb_grn_scan_info_set_query, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "flags",
+ mrb_grn_scan_info_get_flags, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "flags=",
+ mrb_grn_scan_info_set_flags, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "logical_op",
+ mrb_grn_scan_info_get_logical_op, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "logical_op=",
+ mrb_grn_scan_info_set_logical_op, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "max_interval",
+ mrb_grn_scan_info_get_max_interval, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "max_interval=",
+ mrb_grn_scan_info_set_max_interval, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "similarity_threshold",
+ mrb_grn_scan_info_get_similarity_threshold, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "similarity_threshold=",
+ mrb_grn_scan_info_set_similarity_threshold, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "get_arg",
+ mrb_grn_scan_info_get_arg, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "push_arg",
+ mrb_grn_scan_info_push_arg, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "start_position",
+ mrb_grn_scan_info_get_start_position, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "start_position=",
+ mrb_grn_scan_info_set_start_position, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "reset_position",
+ mrb_grn_scan_info_reset_position, MRB_ARGS_NONE());
+
+ klass = mrb_define_class_under(mrb, module,
+ "ExpressionCode", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_expr_code_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "inspect",
+ mrb_grn_expr_code_inspect, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "weight",
+ mrb_grn_expr_code_get_weight, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "value",
+ mrb_grn_expr_code_get_value, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "n_args",
+ mrb_grn_expr_code_get_n_args, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "op",
+ mrb_grn_expr_code_get_op, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "flags",
+ mrb_grn_expr_code_get_flags, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "modify",
+ mrb_grn_expr_code_get_modify, MRB_ARGS_NONE());
+
+ {
+ struct RClass *expression_code_class = klass;
+ struct RClass *flags_module;
+ flags_module = mrb_define_module_under(mrb, expression_code_class, "Flags");
+ mrb_define_const(mrb, flags_module, "RELATIONAL_EXPRESSION",
+ mrb_fixnum_value(GRN_EXPR_CODE_RELATIONAL_EXPRESSION));
+ }
+
+ klass = mrb_define_class_under(mrb, module, "Expression", object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+#define DEFINE_FLAG(name) \
+ mrb_define_const(mrb, klass, \
+ #name, \
+ mrb_fixnum_value(GRN_EXPR_ ## name))
+
+ DEFINE_FLAG(SYNTAX_QUERY);
+ DEFINE_FLAG(SYNTAX_SCRIPT);
+ DEFINE_FLAG(SYNTAX_OUTPUT_COLUMNS);
+ DEFINE_FLAG(ALLOW_PRAGMA);
+ DEFINE_FLAG(ALLOW_COLUMN);
+ DEFINE_FLAG(ALLOW_UPDATE);
+ DEFINE_FLAG(ALLOW_LEADING_NOT);
+
+#undef DEFINE_FLAG
+
+ mrb_define_class_method(mrb, klass, "create",
+ mrb_grn_expression_class_create,
+ MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_expression_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "empty?",
+ mrb_grn_expression_is_empty, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "codes",
+ mrb_grn_expression_codes, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "[]",
+ mrb_grn_expression_array_reference, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "condition=",
+ mrb_grn_expression_set_condition, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "take_object",
+ mrb_grn_expression_take_object, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "allocate_constant",
+ mrb_grn_expression_allocate_constant, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "parse",
+ mrb_grn_expression_parse, MRB_ARGS_ARG(1, 1));
+
+ mrb_define_method(mrb, klass, "append_object",
+ mrb_grn_expression_append_object, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, klass, "append_constant",
+ mrb_grn_expression_append_constant, MRB_ARGS_REQ(3));
+ mrb_define_method(mrb, klass, "append_operator",
+ mrb_grn_expression_append_operator, MRB_ARGS_REQ(2));
+}
+
+grn_obj *
+grn_mrb_expr_rewrite(grn_ctx *ctx, grn_obj *expr)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ mrb_value mrb_expression;
+ mrb_value mrb_rewritten_expression;
+ grn_obj *rewritten_expression = NULL;
+ int arena_index;
+
+ arena_index = mrb_gc_arena_save(mrb);
+
+ mrb_expression = grn_mrb_value_from_grn_obj(mrb, expr);
+ mrb_rewritten_expression = mrb_funcall(mrb, mrb_expression, "rewrite", 0);
+ if (mrb_nil_p(mrb_rewritten_expression)) {
+ goto exit;
+ }
+
+ if (mrb_type(mrb_rewritten_expression) == MRB_TT_EXCEPTION) {
+ mrb->exc = mrb_obj_ptr(mrb_rewritten_expression);
+ mrb_print_error(mrb);
+ goto exit;
+ }
+
+ rewritten_expression = DATA_PTR(mrb_rewritten_expression);
+
+exit:
+ mrb_gc_arena_restore(mrb, arena_index);
+
+ return rewritten_expression;
+}
+
+scan_info **
+grn_mrb_scan_info_build(grn_ctx *ctx,
+ grn_obj *expr,
+ int *n,
+ grn_operator op,
+ grn_bool record_exist)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ mrb_value mrb_expression;
+ mrb_value mrb_sis;
+ scan_info **sis = NULL;
+ int i;
+ int arena_index;
+
+ arena_index = mrb_gc_arena_save(mrb);
+
+ mrb_expression = grn_mrb_value_from_grn_obj(mrb, expr);
+ mrb_sis = mrb_funcall(mrb, mrb_expression, "build_scan_info", 2,
+ grn_mrb_value_from_operator(mrb, op),
+ mrb_bool_value(record_exist));
+
+ if (mrb_nil_p(mrb_sis)) {
+ goto exit;
+ }
+
+ if (mrb_type(mrb_sis) == MRB_TT_EXCEPTION) {
+ mrb->exc = mrb_obj_ptr(mrb_sis);
+ mrb_print_error(mrb);
+ goto exit;
+ }
+
+ *n = RARRAY_LEN(mrb_sis);
+ sis = GRN_MALLOCN(scan_info *, *n);
+ for (i = 0; i < *n; i++) {
+ mrb_value mrb_si;
+ mrb_value mrb_si_data;
+ scan_info *si;
+ int start;
+
+ mrb_si_data = RARRAY_PTR(mrb_sis)[i];
+ start = mrb_fixnum(mrb_funcall(mrb, mrb_si_data, "start", 0));
+ si = grn_scan_info_open(ctx, start);
+ mrb_si = mrb_grn_scan_info_new(mrb, si);
+ mrb_funcall(mrb, mrb_si, "apply", 1, mrb_si_data);
+ sis[i] = si;
+ }
+
+exit:
+ mrb_gc_arena_restore(mrb, arena_index);
+
+ return sis;
+}
+
+unsigned int
+grn_mrb_expr_estimate_size(grn_ctx *ctx, grn_obj *expr, grn_obj *table)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ mrb_value mrb_expression;
+ mrb_value mrb_table;
+ mrb_value mrb_size;
+ unsigned int size;
+ int arena_index;
+
+ arena_index = mrb_gc_arena_save(mrb);
+
+ mrb_expression = grn_mrb_value_from_grn_obj(mrb, expr);
+ mrb_table = grn_mrb_value_from_grn_obj(mrb, table);
+ mrb_size = mrb_funcall(mrb, mrb_expression, "estimate_size", 1, mrb_table);
+ if (mrb->exc) {
+ size = grn_table_size(ctx, table);
+ } else {
+ size = mrb_fixnum(mrb_size);
+ }
+
+ mrb_gc_arena_restore(mrb, arena_index);
+
+ return size;
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.h
new file mode 100644
index 00000000..22b20220
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_expr.h
@@ -0,0 +1,43 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+#include "../grn_expr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_expr_init(grn_ctx *ctx);
+
+grn_obj *grn_mrb_expr_rewrite(grn_ctx *ctx, grn_obj *expr);
+scan_info **grn_mrb_scan_info_build(grn_ctx *ctx,
+ grn_obj *expr,
+ int *n,
+ grn_operator op,
+ grn_bool record_exist);
+unsigned int grn_mrb_expr_estimate_size(grn_ctx *ctx,
+ grn_obj *expr,
+ grn_obj *table);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.c
new file mode 100644
index 00000000..b1545dbc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.c
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_fixed_size_column.h"
+
+static struct mrb_data_type mrb_grn_fixed_size_column_type = {
+ "Groonga::FixedSizeColumn",
+ NULL
+};
+
+static mrb_value
+mrb_grn_fixed_size_column_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_fixed_size_column_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_fixed_size_column_ptr);
+ DATA_TYPE(self) = &mrb_grn_fixed_size_column_type;
+ DATA_PTR(self) = mrb_cptr(mrb_fixed_size_column_ptr);
+ return self;
+}
+
+void
+grn_mrb_fixed_size_column_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *column_class;
+ struct RClass *klass;
+
+ column_class = mrb_class_get_under(mrb, module, "Column");
+ klass = mrb_define_class_under(mrb, module, "FixedSizeColumn", column_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_fixed_size_column_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.h
new file mode 100644
index 00000000..9498d337
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_fixed_size_column.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_fixed_size_column_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.c
new file mode 100644
index 00000000..cf9a0d91
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.c
@@ -0,0 +1,117 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/string.h>
+
+#include "mrb_ctx.h"
+#include "mrb_hash_table.h"
+#include "mrb_options.h"
+
+static struct mrb_data_type mrb_grn_hash_table_type = {
+ "Groonga::HashTable",
+ NULL
+};
+
+static mrb_value
+mrb_grn_hash_table_class_create(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_options = mrb_nil_value();
+ const char *name = NULL;
+ unsigned int name_size = 0;
+ const char *path = NULL;
+ grn_obj_flags flags = GRN_OBJ_TABLE_HASH_KEY;
+ grn_obj *key_type = NULL;
+ grn_obj *value_type = NULL;
+ grn_obj *table;
+
+ mrb_get_args(mrb, "|H", &mrb_options);
+
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_name;
+ mrb_value mrb_flags;
+ mrb_value mrb_key_type;
+ mrb_value mrb_value_type;
+
+ mrb_name = grn_mrb_options_get_lit(mrb, mrb_options, "name");
+ if (!mrb_nil_p(mrb_name)) {
+ name = RSTRING_PTR(mrb_name);
+ name_size = RSTRING_LEN(mrb_name);
+ }
+
+ mrb_flags = grn_mrb_options_get_lit(mrb, mrb_options, "flags");
+ if (!mrb_nil_p(mrb_flags)) {
+ flags |= mrb_fixnum(mrb_flags);
+ }
+
+ mrb_key_type = grn_mrb_options_get_lit(mrb, mrb_options, "key_type");
+ if (!mrb_nil_p(mrb_key_type)) {
+ key_type = DATA_PTR(mrb_key_type);
+ }
+
+ mrb_value_type = grn_mrb_options_get_lit(mrb, mrb_options, "value_type");
+ if (!mrb_nil_p(mrb_value_type)) {
+ key_type = DATA_PTR(mrb_value_type);
+ }
+ }
+
+ table = grn_table_create(ctx, name, name_size, path, flags,
+ key_type, value_type);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_funcall(mrb, klass, "new", 1, mrb_cptr_value(mrb, table));
+}
+
+static mrb_value
+mrb_grn_hash_table_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_hash_table_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_hash_table_ptr);
+ DATA_TYPE(self) = &mrb_grn_hash_table_type;
+ DATA_PTR(self) = mrb_cptr(mrb_hash_table_ptr);
+ return self;
+}
+
+void
+grn_mrb_hash_table_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *table_class;
+ struct RClass *klass;
+
+ table_class = mrb_class_get_under(mrb, module, "Table");
+ klass = mrb_define_class_under(mrb, module, "HashTable", table_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "create",
+ mrb_grn_hash_table_class_create,
+ MRB_ARGS_OPT(1));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_hash_table_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.h
new file mode 100644
index 00000000..d6b747f0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_hash_table.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_hash_table_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_id.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_id.c
new file mode 100644
index 00000000..d5970fee
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_id.c
@@ -0,0 +1,79 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+
+#include "mrb_id.h"
+
+void
+grn_mrb_id_init(grn_ctx *ctx)
+{
+ mrb_state *mrb = ctx->impl->mrb.state;
+ struct RClass *module = ctx->impl->mrb.module;
+ struct RClass *id_module;
+
+ id_module = mrb_define_module_under(mrb, module, "ID");
+
+ mrb_define_const(mrb, id_module, "NIL",
+ mrb_fixnum_value(GRN_ID_NIL));
+ mrb_define_const(mrb, id_module, "MAX",
+ mrb_fixnum_value(GRN_ID_MAX));
+
+ mrb_define_const(mrb, id_module, "VOID",
+ mrb_fixnum_value(GRN_DB_VOID));
+ mrb_define_const(mrb, id_module, "DB",
+ mrb_fixnum_value(GRN_DB_DB));
+ mrb_define_const(mrb, id_module, "OBJECT",
+ mrb_fixnum_value(GRN_DB_OBJECT));
+ mrb_define_const(mrb, id_module, "BOOL",
+ mrb_fixnum_value(GRN_DB_BOOL));
+ mrb_define_const(mrb, id_module, "INT8",
+ mrb_fixnum_value(GRN_DB_INT8));
+ mrb_define_const(mrb, id_module, "UINT8",
+ mrb_fixnum_value(GRN_DB_UINT8));
+ mrb_define_const(mrb, id_module, "INT16",
+ mrb_fixnum_value(GRN_DB_INT16));
+ mrb_define_const(mrb, id_module, "UINT16",
+ mrb_fixnum_value(GRN_DB_UINT16));
+ mrb_define_const(mrb, id_module, "INT32",
+ mrb_fixnum_value(GRN_DB_INT32));
+ mrb_define_const(mrb, id_module, "UINT32",
+ mrb_fixnum_value(GRN_DB_UINT32));
+ mrb_define_const(mrb, id_module, "INT64",
+ mrb_fixnum_value(GRN_DB_INT64));
+ mrb_define_const(mrb, id_module, "UINT64",
+ mrb_fixnum_value(GRN_DB_UINT64));
+ mrb_define_const(mrb, id_module, "FLOAT",
+ mrb_fixnum_value(GRN_DB_FLOAT));
+ mrb_define_const(mrb, id_module, "TIME",
+ mrb_fixnum_value(GRN_DB_TIME));
+ mrb_define_const(mrb, id_module, "SHORT_TEXT",
+ mrb_fixnum_value(GRN_DB_SHORT_TEXT));
+ mrb_define_const(mrb, id_module, "TEXT",
+ mrb_fixnum_value(GRN_DB_TEXT));
+ mrb_define_const(mrb, id_module, "LONG_TEXT",
+ mrb_fixnum_value(GRN_DB_LONG_TEXT));
+ mrb_define_const(mrb, id_module, "TOKYO_GEO_POINT",
+ mrb_fixnum_value(GRN_DB_TOKYO_GEO_POINT));
+ mrb_define_const(mrb, id_module, "WGS84_GEO_POINT",
+ mrb_fixnum_value(GRN_DB_WGS84_GEO_POINT));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_id.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_id.h
new file mode 100644
index 00000000..b5418b73
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_id.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_id_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.c
new file mode 100644
index 00000000..02a3901b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.c
@@ -0,0 +1,199 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_ii.h"
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_ctx.h"
+#include "mrb_converter.h"
+#include "mrb_index_column.h"
+#include "mrb_operator.h"
+#include "mrb_options.h"
+
+static struct mrb_data_type mrb_grn_index_column_type = {
+ "Groonga::IndexColumn",
+ NULL
+};
+
+static mrb_value
+mrb_grn_index_column_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_index_column_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_index_column_ptr);
+ DATA_TYPE(self) = &mrb_grn_index_column_type;
+ DATA_PTR(self) = mrb_cptr(mrb_index_column_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_index_column_get_lexicon(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *index_column;
+ grn_obj *lexicon;
+
+ index_column = DATA_PTR(self);
+ lexicon = ((grn_ii *)index_column)->lexicon;
+
+ return grn_mrb_value_from_grn_obj(mrb, lexicon);
+}
+
+static mrb_value
+mrb_grn_index_column_get_source_ids(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *index_column;
+ grn_obj source_ids;
+ unsigned int i, n_ids;
+ mrb_value mrb_source_ids;
+
+ index_column = DATA_PTR(self);
+ GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_DB_VOID);
+ grn_obj_get_info(ctx, index_column, GRN_INFO_SOURCE, &source_ids);
+ n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+
+ mrb_source_ids = mrb_ary_new_capa(mrb, n_ids);
+ for (i = 0; i < n_ids; i++) {
+ grn_id source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
+ mrb_ary_push(mrb, mrb_source_ids, mrb_fixnum_value(source_id));
+ }
+
+ GRN_OBJ_FIN(ctx, &source_ids);
+
+ return mrb_source_ids;
+}
+
+static mrb_value
+mrb_grn_index_column_estimate_size_for_term_id(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *index_column;
+ mrb_int term_id;
+ unsigned int size;
+
+ index_column = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &term_id);
+
+ size = grn_ii_estimate_size(ctx, (grn_ii *)index_column, term_id);
+ return mrb_fixnum_value(size);
+}
+
+static mrb_value
+mrb_grn_index_column_estimate_size_for_query(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *index_column;
+ grn_obj *lexicon;
+ mrb_value mrb_query;
+ void *query;
+ unsigned int query_size;
+ grn_mrb_value_to_raw_data_buffer buffer;
+ mrb_value mrb_options = mrb_nil_value();
+ grn_search_optarg optarg;
+ unsigned int size;
+
+ index_column = DATA_PTR(self);
+ mrb_get_args(mrb, "o|H", &mrb_query, &mrb_options);
+
+ lexicon = grn_ctx_at(ctx, index_column->header.domain);
+ grn_mrb_value_to_raw_data_buffer_init(mrb, &buffer);
+ grn_mrb_value_to_raw_data(mrb, "query", mrb_query, lexicon->header.domain,
+ &buffer, &query, &query_size);
+
+ memset(&optarg, 0, sizeof(grn_search_optarg));
+ optarg.mode = GRN_OP_EXACT;
+
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_mode;
+
+ mrb_mode = grn_mrb_options_get_lit(mrb, mrb_options, "mode");
+ if (!mrb_nil_p(mrb_mode)) {
+ optarg.mode = grn_mrb_value_to_operator(mrb, mrb_mode);
+ }
+ }
+
+ size = grn_ii_estimate_size_for_query(ctx, (grn_ii *)index_column,
+ query, query_size, &optarg);
+ grn_mrb_value_to_raw_data_buffer_fin(mrb, &buffer);
+
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_fixnum_value(size);
+}
+
+static mrb_value
+mrb_grn_index_column_estimate_size_for_lexicon_cursor(mrb_state *mrb,
+ mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *index_column;
+ mrb_value mrb_lexicon_cursor;
+ grn_table_cursor *lexicon_cursor;
+ unsigned int size;
+
+ index_column = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_lexicon_cursor);
+
+ lexicon_cursor = DATA_PTR(mrb_lexicon_cursor);
+ size = grn_ii_estimate_size_for_lexicon_cursor(ctx,
+ (grn_ii *)index_column,
+ lexicon_cursor);
+ return mrb_fixnum_value(size);
+}
+
+void
+grn_mrb_index_column_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *column_class;
+ struct RClass *klass;
+
+ column_class = mrb_class_get_under(mrb, module, "Column");
+ klass = mrb_define_class_under(mrb, module, "IndexColumn", column_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_index_column_initialize, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "lexicon",
+ mrb_grn_index_column_get_lexicon,
+ MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "source_ids",
+ mrb_grn_index_column_get_source_ids,
+ MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "estimate_size_for_term_id",
+ mrb_grn_index_column_estimate_size_for_term_id,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "estimate_size_for_query",
+ mrb_grn_index_column_estimate_size_for_query,
+ MRB_ARGS_ARG(1, 1));
+ mrb_define_method(mrb, klass, "estimate_size_for_lexicon_cursor",
+ mrb_grn_index_column_estimate_size_for_lexicon_cursor,
+ MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.h
new file mode 100644
index 00000000..085a2d3a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_column.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_index_column_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.c
new file mode 100644
index 00000000..20f1e64f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.c
@@ -0,0 +1,245 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_ii.h"
+#include "../grn_db.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/string.h>
+#include <mruby/hash.h>
+#include <mruby/variable.h>
+
+#include "mrb_ctx.h"
+#include "mrb_index_cursor.h"
+#include "mrb_converter.h"
+#include "mrb_options.h"
+
+static struct mrb_data_type mrb_grn_index_cursor_type = {
+ "Groonga::IndexCursor",
+ NULL
+};
+
+static mrb_value
+mrb_grn_index_cursor_class_open_raw(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_table_cursor;
+ mrb_value mrb_index;
+ mrb_value mrb_options = mrb_nil_value();
+ grn_obj *index_cursor;
+ grn_table_cursor *table_cursor;
+ grn_obj *index;
+ grn_id rid_min = GRN_ID_NIL;
+ grn_id rid_max = GRN_ID_MAX;
+ int flags = 0;
+ mrb_value mrb_index_cursor;
+
+ mrb_get_args(mrb, "oo|H", &mrb_table_cursor, &mrb_index, &mrb_options);
+
+ table_cursor = DATA_PTR(mrb_table_cursor);
+ index = DATA_PTR(mrb_index);
+ if (!mrb_nil_p(mrb_options)) {
+ /* TODO */
+ }
+ index_cursor = grn_index_cursor_open(ctx, table_cursor, index,
+ rid_min, rid_max, flags);
+ grn_mrb_ctx_check(mrb);
+
+ mrb_index_cursor = mrb_funcall(mrb, klass, "new", 1,
+ mrb_cptr_value(mrb, index_cursor));
+ mrb_iv_set(mrb, mrb_index_cursor, mrb_intern_lit(mrb, "@index"), mrb_index);
+ return mrb_index_cursor;
+}
+
+static mrb_value
+mrb_grn_index_cursor_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_index_cursor_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_index_cursor_ptr);
+ DATA_TYPE(self) = &mrb_grn_index_cursor_type;
+ DATA_PTR(self) = mrb_cptr(mrb_index_cursor_ptr);
+
+ return self;
+}
+
+static mrb_value
+mrb_grn_index_cursor_close(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *index_cursor;
+
+ index_cursor = DATA_PTR(self);
+ if (index_cursor) {
+ DATA_PTR(self) = NULL;
+ grn_obj_close(ctx, index_cursor);
+ grn_mrb_ctx_check(mrb);
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_index_cursor_count(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_id term_id;
+ int n_records = 0;
+
+ while (grn_index_cursor_next(ctx, DATA_PTR(self), &term_id)) {
+ n_records++;
+ }
+
+ return mrb_fixnum_value(n_records);
+}
+
+static mrb_value
+mrb_grn_index_cursor_select(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_result_set;
+ mrb_value mrb_options;
+ grn_obj *index_cursor;
+ grn_obj *expr = NULL;
+ grn_obj *expr_variable = NULL;
+ int offset = 0;
+ int limit = 10;
+ int max_n_unmatched_records = -1;
+ int n_matched_records = 0;
+ int n_unmatched_records = 0;
+ mrb_value mrb_index;
+ grn_obj *index;
+ grn_obj *lexicon;
+ grn_obj *data_table;
+ grn_hash *result_set;
+ grn_posting *posting;
+ grn_id term_id;
+ grn_operator op = GRN_OP_OR;
+
+ mrb_get_args(mrb, "o|H", &mrb_result_set, &mrb_options);
+
+ index_cursor = DATA_PTR(self);
+ result_set = DATA_PTR(mrb_result_set);
+
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_expr;
+ mrb_value mrb_offset;
+ mrb_value mrb_limit;
+ mrb_value mrb_max_n_unmatched_records;
+
+ mrb_expr = grn_mrb_options_get_lit(mrb, mrb_options, "expression");
+ if (!mrb_nil_p(mrb_expr)) {
+ expr = DATA_PTR(mrb_expr);
+ expr_variable = grn_expr_get_var_by_offset(ctx, expr, 0);
+ }
+
+ mrb_offset = grn_mrb_options_get_lit(mrb, mrb_options, "offset");
+ if (!mrb_nil_p(mrb_offset)) {
+ offset = mrb_fixnum(mrb_offset);
+ }
+
+ mrb_limit = grn_mrb_options_get_lit(mrb, mrb_options, "limit");
+ if (!mrb_nil_p(mrb_limit)) {
+ limit = mrb_fixnum(mrb_limit);
+ }
+
+ mrb_max_n_unmatched_records =
+ grn_mrb_options_get_lit(mrb, mrb_options, "max_n_unmatched_records");
+ if (!mrb_nil_p(mrb_max_n_unmatched_records)) {
+ max_n_unmatched_records = mrb_fixnum(mrb_max_n_unmatched_records);
+ }
+ }
+
+ if (limit <= 0) {
+ return mrb_fixnum_value(n_matched_records);
+ }
+
+ mrb_index = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@index"));
+ index = DATA_PTR(mrb_index);
+ lexicon = ((grn_ii *)index)->lexicon;
+ data_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, index));
+
+ if (max_n_unmatched_records < 0) {
+ max_n_unmatched_records = INT32_MAX;
+ }
+ while ((posting = grn_index_cursor_next(ctx, index_cursor, &term_id))) {
+ if (expr) {
+ grn_bool matched_raw = GRN_FALSE;
+ grn_obj *matched;
+
+ GRN_RECORD_SET(ctx, expr_variable, posting->rid);
+ matched = grn_expr_exec(ctx, expr, 0);
+ if (matched) {
+ matched_raw = grn_obj_is_true(ctx, matched);
+ } else {
+ grn_mrb_ctx_check(mrb);
+ }
+
+ if (!matched_raw) {
+ n_unmatched_records++;
+ if (n_unmatched_records > max_n_unmatched_records) {
+ return mrb_fixnum_value(-1);
+ }
+ continue;
+ }
+ }
+ n_matched_records++;
+ if (offset > 0) {
+ offset--;
+ continue;
+ }
+ grn_ii_posting_add(ctx, posting, result_set, op);
+ limit--;
+ if (limit == 0) {
+ break;
+ }
+ }
+ grn_ii_resolve_sel_and(ctx, result_set, op);
+
+ return mrb_fixnum_value(n_matched_records);
+}
+
+void
+grn_mrb_index_cursor_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "IndexCursor", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "open_raw",
+ mrb_grn_index_cursor_class_open_raw,
+ MRB_ARGS_ARG(2, 1));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_index_cursor_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "close",
+ mrb_grn_index_cursor_close, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "count",
+ mrb_grn_index_cursor_count, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "select",
+ mrb_grn_index_cursor_select, MRB_ARGS_ARG(1, 1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.h
new file mode 100644
index 00000000..c1026002
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_index_cursor.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_index_cursor_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.c
new file mode 100644
index 00000000..cd8f44ae
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.c
@@ -0,0 +1,170 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_db.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/array.h>
+#include <mruby/data.h>
+
+#include "mrb_ctx.h"
+#include "mrb_indexable.h"
+#include "mrb_operator.h"
+#include "mrb_converter.h"
+
+static mrb_value
+indexable_find_index(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ mrb_value mrb_operator;
+ grn_operator operator;
+ grn_index_datum index_datum;
+ int n_index_data;
+
+ mrb_get_args(mrb, "o", &mrb_operator);
+ object = DATA_PTR(self);
+ operator = grn_mrb_value_to_operator(mrb, mrb_operator);
+ n_index_data = grn_column_find_index_data(ctx,
+ object,
+ operator,
+ &index_datum,
+ 1);
+ if (n_index_data == 0) {
+ return mrb_nil_value();
+ } else {
+ grn_mrb_data *data;
+ struct RClass *klass;
+ mrb_value args[2];
+
+ data = &(ctx->impl->mrb);
+ klass = mrb_class_get_under(mrb, data->module, "IndexInfo");
+ args[0] = grn_mrb_value_from_grn_obj(mrb, index_datum.index);
+ args[1] = mrb_fixnum_value(index_datum.section);
+ return mrb_obj_new(mrb, klass, 2, args);
+ }
+}
+
+static mrb_value
+indexable_indexes(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ grn_index_datum index_datum;
+ grn_index_datum *index_data;
+ int i, n_index_data;
+ mrb_value mrb_indexes;
+
+ object = DATA_PTR(self);
+ n_index_data = grn_column_get_all_index_data(ctx, object, &index_datum, 1);
+ if (n_index_data == 0) {
+ return mrb_ary_new(mrb);
+ }
+
+ if (n_index_data == 1) {
+ index_data = &index_datum;
+ } else {
+ index_data = GRN_MALLOCN(grn_index_datum, n_index_data);
+ n_index_data = grn_column_get_all_index_data(ctx,
+ object,
+ index_data,
+ n_index_data);
+ }
+
+ mrb_indexes = mrb_ary_new_capa(mrb, n_index_data);
+ for (i = 0; i < n_index_data; i++) {
+ grn_mrb_data *data;
+ struct RClass *klass;
+ mrb_value args[2];
+
+ data = &(ctx->impl->mrb);
+ klass = mrb_class_get_under(mrb, data->module, "IndexInfo");
+ args[0] = grn_mrb_value_from_grn_obj(mrb, index_data[i].index);
+ args[1] = mrb_fixnum_value(index_data[i].section);
+ mrb_ary_push(mrb, mrb_indexes, mrb_obj_new(mrb, klass, 2, args));
+ }
+
+ if (index_data != &index_datum) {
+ GRN_FREE(index_data);
+ }
+
+ return mrb_indexes;
+}
+
+static mrb_value
+indexable_index_ids(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ grn_hook_entry entry;
+ int i;
+ int n_indexes;
+ mrb_value mrb_index_ids;
+ grn_obj hook_data;
+
+ object = DATA_PTR(self);
+
+ if (grn_obj_is_key_accessor(ctx, object)) {
+ object = grn_ctx_at(ctx, object->header.domain);
+ }
+ if (grn_obj_is_table(ctx, object)) {
+ entry = GRN_HOOK_INSERT;
+ } else if (grn_obj_is_column(ctx, object)) {
+ entry = GRN_HOOK_SET;
+ } else {
+ return mrb_ary_new(mrb);
+ }
+ n_indexes = grn_obj_get_nhooks(ctx, object, entry);
+
+ mrb_index_ids = mrb_ary_new_capa(mrb, n_indexes);
+
+ GRN_TEXT_INIT(&hook_data, 0);
+ for (i = 0; i < n_indexes; i++) {
+ GRN_BULK_REWIND(&hook_data);
+ grn_obj_get_hook(ctx, object, entry, i, &hook_data);
+ if (GRN_BULK_VSIZE(&hook_data) ==
+ sizeof(grn_obj_default_set_value_hook_data)) {
+ grn_obj_default_set_value_hook_data *data;
+
+ data = (grn_obj_default_set_value_hook_data *)GRN_TEXT_VALUE(&hook_data);
+ mrb_ary_push(mrb, mrb_index_ids, mrb_fixnum_value(data->target));
+ }
+ }
+
+ return mrb_index_ids;
+}
+
+void
+grn_mrb_indexable_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module;
+
+ module = mrb_define_module_under(mrb, data->module, "Indexable");
+
+ mrb_define_method(mrb, module, "find_index",
+ indexable_find_index, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, module, "indexes",
+ indexable_indexes, MRB_ARGS_NONE());
+ mrb_define_method(mrb, module, "index_ids",
+ indexable_index_ids, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.h
new file mode 100644
index 00000000..3b191c72
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_indexable.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_indexable_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.c
new file mode 100644
index 00000000..d5ed72df
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.c
@@ -0,0 +1,99 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/variable.h>
+#include <mruby/string.h>
+
+#include "../grn_mrb.h"
+#include "mrb_logger.h"
+
+static mrb_value
+logger_s_get_default_path(mrb_state *mrb, mrb_value self)
+{
+ return mrb_str_new_cstr(mrb, grn_default_logger_get_path());
+}
+
+static mrb_value
+logger_s_get_default_level(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_level_class;
+ mrb_value mrb_level;
+
+ mrb_level_class = mrb_const_get(mrb, self, mrb_intern_lit(mrb, "Level"));
+ mrb_level = mrb_fixnum_value(grn_default_logger_get_max_level());
+ return mrb_funcall(mrb, mrb_level_class, "find", 1, mrb_level);
+}
+
+static mrb_value
+logger_need_log_p(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int level;
+
+ mrb_get_args(mrb, "i", &level);
+
+ return mrb_bool_value(grn_logger_pass(ctx, level));
+}
+
+static mrb_value
+logger_log(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int level;
+ char *file;
+ mrb_int line;
+ char *method;
+ char *message;
+ mrb_int message_size;
+
+ mrb_get_args(mrb, "izizs",
+ &level, &file, &line, &method, &message, &message_size);
+ grn_logger_put(ctx, level, file, line, method,
+ "%.*s", (int)message_size, message);
+
+ return self;
+}
+
+void
+grn_mrb_logger_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Logger", mrb->object_class);
+
+ mrb_define_singleton_method(mrb, (struct RObject *)klass, "default_path",
+ logger_s_get_default_path, MRB_ARGS_NONE());
+ mrb_define_singleton_method(mrb, (struct RObject *)klass, "default_level",
+ logger_s_get_default_level, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "need_log?", logger_need_log_p, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "log", logger_log, MRB_ARGS_REQ(5));
+
+ grn_mrb_load(ctx, "logger/level.rb");
+ grn_mrb_load(ctx, "logger.rb");
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.h
new file mode 100644
index 00000000..d23ddb19
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_logger.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_logger_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_object.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object.c
new file mode 100644
index 00000000..874d4add
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object.c
@@ -0,0 +1,346 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_util.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/string.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "../grn_mrb.h"
+#include "mrb_ctx.h"
+#include "mrb_object.h"
+#include "mrb_operator.h"
+#include "mrb_options.h"
+#include "mrb_converter.h"
+
+static mrb_value
+object_remove_force(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *name;
+ mrb_int name_size;
+
+ mrb_get_args(mrb, "s", &name, &name_size);
+ grn_obj_remove_force(ctx, name, name_size);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+mrb_value
+grn_mrb_object_inspect(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ mrb_value inspected;
+
+ object = DATA_PTR(self);
+ inspected = mrb_str_buf_new(mrb, 48);
+
+ mrb_str_cat_lit(mrb, inspected, "#<");
+ mrb_str_cat_cstr(mrb, inspected, mrb_obj_classname(mrb, self));
+ mrb_str_cat_lit(mrb, inspected, ":");
+ mrb_str_concat(mrb, inspected, mrb_ptr_to_str(mrb, mrb_cptr(self)));
+ if (object) {
+ grn_obj buffer;
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_inspect(ctx, &buffer, object);
+ mrb_str_cat_lit(mrb, inspected, " ");
+ mrb_str_cat(mrb, inspected, GRN_TEXT_VALUE(&buffer), GRN_TEXT_LEN(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+ } else {
+ mrb_str_cat_lit(mrb, inspected, " (closed)");
+ }
+ mrb_str_cat_lit(mrb, inspected, ">");
+
+ return inspected;
+}
+
+static mrb_value
+object_get_id(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_id id;
+
+ id = grn_obj_id(ctx, DATA_PTR(self));
+
+ return mrb_fixnum_value(id);
+}
+
+static mrb_value
+object_get_name(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_length;
+
+ object = DATA_PTR(self);
+ name_length = grn_obj_name(ctx, object, name, GRN_TABLE_MAX_KEY_SIZE);
+
+ if (name_length == 0) {
+ return mrb_nil_value();
+ } else {
+ return mrb_str_new(mrb, name, name_length);
+ }
+}
+
+static mrb_value
+object_get_path(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ const char *path;
+
+ object = DATA_PTR(self);
+ path = grn_obj_path(ctx, object);
+
+ if (path) {
+ return mrb_str_new_cstr(mrb, path);
+ } else {
+ return mrb_nil_value();
+ }
+}
+
+static mrb_value
+object_grn_inspect(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj buffer;
+ mrb_value inspected;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_inspect(ctx, &buffer, DATA_PTR(self));
+ inspected = mrb_str_new(mrb, GRN_TEXT_VALUE(&buffer), GRN_TEXT_LEN(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+
+ return inspected;
+}
+
+static mrb_value
+object_equal(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *object, *other_object;
+ mrb_value mrb_other;
+
+ mrb_get_args(mrb, "o", &mrb_other);
+ if (!mrb_obj_is_kind_of(mrb, mrb_other, mrb_obj_class(mrb, self))) {
+ return mrb_false_value();
+ }
+
+ object = DATA_PTR(self);
+ other_object = DATA_PTR(mrb_other);
+ return mrb_bool_value(object == other_object);
+}
+
+static mrb_value
+object_hash(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *object;
+
+ object = DATA_PTR(self);
+ return mrb_fixnum_value((mrb_int)((uint64_t)object));
+}
+
+static mrb_value
+object_close(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+
+ object = DATA_PTR(self);
+ if (!object) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "already closed object");
+ }
+
+ grn_obj_close(ctx, object);
+ DATA_PTR(self) = NULL;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+object_remove(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_options = mrb_nil_value();
+ grn_bool dependent = GRN_FALSE;
+ grn_obj *object;
+
+ mrb_get_args(mrb, "|H", &mrb_options);
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_dependent;
+ mrb_dependent = grn_mrb_options_get_lit(mrb, mrb_options, "dependent");
+ dependent = mrb_test(mrb_dependent);
+ }
+
+ object = DATA_PTR(self);
+ if (dependent) {
+ grn_obj_remove_dependent(ctx, object);
+ } else {
+ grn_obj_remove(ctx, object);
+ }
+ grn_mrb_ctx_check(mrb);
+
+ DATA_PTR(self) = NULL;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+object_is_closed(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *object;
+
+ object = DATA_PTR(self);
+ return mrb_bool_value(object == NULL);
+}
+
+static mrb_value
+object_get_domain_id(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *object;
+ grn_id domain_id;
+
+ object = DATA_PTR(self);
+ domain_id = object->header.domain;
+
+ if (domain_id == GRN_ID_NIL) {
+ return mrb_nil_value();
+ } else {
+ return mrb_fixnum_value(domain_id);
+ }
+}
+
+static mrb_value
+object_get_range_id(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ grn_id range_id;
+
+ object = DATA_PTR(self);
+ range_id = grn_obj_get_range(ctx, object);
+
+ if (range_id == GRN_ID_NIL) {
+ return mrb_nil_value();
+ } else {
+ return mrb_fixnum_value(range_id);
+ }
+}
+
+static mrb_value
+object_is_temporary(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *object;
+ grn_obj_flags flags;
+
+ object = DATA_PTR(self);
+ flags = object->header.flags;
+ return mrb_bool_value((flags & GRN_OBJ_PERSISTENT) != GRN_OBJ_PERSISTENT);
+}
+
+static mrb_value
+object_is_persistent(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *object;
+ grn_obj_flags flags;
+
+ object = DATA_PTR(self);
+ flags = object->header.flags;
+ return mrb_bool_value((flags & GRN_OBJ_PERSISTENT) == GRN_OBJ_PERSISTENT);
+}
+
+static mrb_value
+object_is_true(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+
+ object = DATA_PTR(self);
+ return mrb_bool_value(grn_obj_is_true(ctx, object));
+}
+
+static mrb_value
+object_check_corrupt(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *object;
+ grn_bool is_corrupt;
+
+ object = DATA_PTR(self);
+ is_corrupt = grn_obj_is_corrupt(ctx, object);
+ grn_mrb_ctx_check(mrb);
+ return mrb_bool_value(is_corrupt);
+}
+
+void
+grn_mrb_object_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Object", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ data->object_class = klass;
+
+ mrb_define_class_method(mrb,
+ klass,
+ "remove_force",
+ object_remove_force,
+ MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "inspect",
+ grn_mrb_object_inspect, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "id", object_get_id, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "name", object_get_name, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "path", object_get_path, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "grn_inspect",
+ object_grn_inspect, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "==", object_equal, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "eql?", object_equal, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "hash", object_hash, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "close", object_close, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "remove", object_remove, MRB_ARGS_OPT(1));
+ mrb_define_method(mrb, klass, "closed?", object_is_closed, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "domain_id", object_get_domain_id,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "range_id", object_get_range_id,
+ MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "temporary?", object_is_temporary,
+ MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "persistent?", object_is_persistent,
+ MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "true?", object_is_true, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "check_corrupt", object_check_corrupt,
+ MRB_ARGS_NONE());
+
+ grn_mrb_load(ctx, "index_info.rb");
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_object.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object.h
new file mode 100644
index 00000000..5650ba28
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object.h
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_object_init(grn_ctx *ctx);
+
+mrb_value grn_mrb_object_inspect(mrb_state *mrb, mrb_value self);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.c
new file mode 100644
index 00000000..1fb70299
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.c
@@ -0,0 +1,96 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+# include <mruby.h>
+# include <mruby/string.h>
+# include <mruby/class.h>
+# include <mruby/data.h>
+
+# include "../grn_mrb.h"
+# include "mrb_object.h"
+# include "mrb_operator.h"
+# include "mrb_converter.h"
+
+void
+grn_mrb_object_flags_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *flags_module;
+
+ flags_module = mrb_define_module_under(mrb, module, "ObjectFlags");
+
+#define MRB_DEFINE_FLAG(name) \
+ mrb_define_const(mrb, flags_module, #name, \
+ mrb_fixnum_value(GRN_OBJ_ ## name))
+
+ MRB_DEFINE_FLAG(TABLE_TYPE_MASK);
+ MRB_DEFINE_FLAG(TABLE_HASH_KEY);
+ MRB_DEFINE_FLAG(TABLE_PAT_KEY);
+ MRB_DEFINE_FLAG(TABLE_DAT_KEY);
+ MRB_DEFINE_FLAG(TABLE_NO_KEY);
+
+ MRB_DEFINE_FLAG(KEY_MASK);
+ MRB_DEFINE_FLAG(KEY_UINT);
+ MRB_DEFINE_FLAG(KEY_INT);
+ MRB_DEFINE_FLAG(KEY_FLOAT);
+ MRB_DEFINE_FLAG(KEY_GEO_POINT);
+
+ MRB_DEFINE_FLAG(KEY_WITH_SIS);
+ MRB_DEFINE_FLAG(KEY_NORMALIZE);
+
+ MRB_DEFINE_FLAG(COLUMN_TYPE_MASK);
+ MRB_DEFINE_FLAG(COLUMN_SCALAR);
+ MRB_DEFINE_FLAG(COLUMN_VECTOR);
+ MRB_DEFINE_FLAG(COLUMN_INDEX);
+
+ MRB_DEFINE_FLAG(COMPRESS_MASK);
+ MRB_DEFINE_FLAG(COMPRESS_NONE);
+ MRB_DEFINE_FLAG(COMPRESS_ZLIB);
+ MRB_DEFINE_FLAG(COMPRESS_LZ4);
+ MRB_DEFINE_FLAG(COMPRESS_ZSTD);
+
+ MRB_DEFINE_FLAG(WITH_SECTION);
+ MRB_DEFINE_FLAG(WITH_WEIGHT);
+ MRB_DEFINE_FLAG(WITH_POSITION);
+ MRB_DEFINE_FLAG(RING_BUFFER);
+
+ MRB_DEFINE_FLAG(UNIT_MASK);
+ MRB_DEFINE_FLAG(UNIT_DOCUMENT_NONE);
+ MRB_DEFINE_FLAG(UNIT_DOCUMENT_SECTION);
+ MRB_DEFINE_FLAG(UNIT_DOCUMENT_POSITION);
+ MRB_DEFINE_FLAG(UNIT_SECTION_NONE);
+ MRB_DEFINE_FLAG(UNIT_SECTION_POSITION);
+ MRB_DEFINE_FLAG(UNIT_POSITION_NONE);
+ MRB_DEFINE_FLAG(UNIT_USERDEF_DOCUMENT);
+ MRB_DEFINE_FLAG(UNIT_USERDEF_SECTION);
+ MRB_DEFINE_FLAG(UNIT_USERDEF_POSITION);
+
+ MRB_DEFINE_FLAG(NO_SUBREC);
+ MRB_DEFINE_FLAG(WITH_SUBREC);
+
+ MRB_DEFINE_FLAG(KEY_VAR_SIZE);
+
+ MRB_DEFINE_FLAG(TEMPORARY);
+ MRB_DEFINE_FLAG(PERSISTENT);
+}
+#endif /* GRN_WITH_MRUBY */
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.h
new file mode 100644
index 00000000..6f7bd7f7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_object_flags.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_object_flags_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.c
new file mode 100644
index 00000000..e0ef4727
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.c
@@ -0,0 +1,155 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+
+#include "mrb_operator.h"
+
+mrb_value
+grn_mrb_value_from_operator(mrb_state *mrb, grn_operator op)
+{
+ grn_ctx *ctx = (grn_ctx *)(mrb->ud);
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_value mrb_op_raw;
+ mrb_value mrb_op;
+
+ mrb_op_raw = mrb_fixnum_value(op);
+ mrb_op = mrb_funcall(mrb, mrb_obj_value(data->groonga.operator_class),
+ "find", 1, mrb_op_raw);
+ if (mrb_nil_p(mrb_op)) {
+ return mrb_op_raw;
+ } else {
+ return mrb_op;
+ }
+}
+
+grn_operator
+grn_mrb_value_to_operator(mrb_state *mrb, mrb_value mrb_op)
+{
+ if (!mrb_fixnum_p(mrb_op)) {
+ mrb_op = mrb_funcall(mrb, mrb_op, "value", 0);
+ }
+
+ return mrb_fixnum(mrb_op);
+}
+
+void
+grn_mrb_operator_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = ctx->impl->mrb.module;
+ struct RClass *klass;
+ mrb_value klass_obj;
+
+ klass = mrb_class_get_under(mrb, module, "Operator");
+ data->groonga.operator_class = klass;
+
+ klass_obj = mrb_obj_value(klass);
+#define DEFINE_OPERATOR(name) \
+ mrb_funcall(mrb, klass_obj, "register", 1, \
+ mrb_funcall(mrb, klass_obj, "new", 2, \
+ mrb_str_new_lit(mrb, #name), \
+ mrb_fixnum_value(GRN_OP_ ## name)))
+
+ DEFINE_OPERATOR(PUSH);
+ DEFINE_OPERATOR(POP);
+ DEFINE_OPERATOR(NOP);
+ DEFINE_OPERATOR(CALL);
+ DEFINE_OPERATOR(INTERN);
+ DEFINE_OPERATOR(GET_REF);
+ DEFINE_OPERATOR(GET_VALUE);
+ DEFINE_OPERATOR(AND);
+ DEFINE_OPERATOR(AND_NOT);
+ DEFINE_OPERATOR(OR);
+ DEFINE_OPERATOR(ASSIGN);
+ DEFINE_OPERATOR(STAR_ASSIGN);
+ DEFINE_OPERATOR(SLASH_ASSIGN);
+ DEFINE_OPERATOR(MOD_ASSIGN);
+ DEFINE_OPERATOR(PLUS_ASSIGN);
+ DEFINE_OPERATOR(MINUS_ASSIGN);
+ DEFINE_OPERATOR(SHIFTL_ASSIGN);
+ DEFINE_OPERATOR(SHIFTR_ASSIGN);
+ DEFINE_OPERATOR(SHIFTRR_ASSIGN);
+ DEFINE_OPERATOR(AND_ASSIGN);
+ DEFINE_OPERATOR(XOR_ASSIGN);
+ DEFINE_OPERATOR(OR_ASSIGN);
+ DEFINE_OPERATOR(JUMP);
+ DEFINE_OPERATOR(CJUMP);
+ DEFINE_OPERATOR(COMMA);
+ DEFINE_OPERATOR(BITWISE_OR);
+ DEFINE_OPERATOR(BITWISE_XOR);
+ DEFINE_OPERATOR(BITWISE_AND);
+ DEFINE_OPERATOR(BITWISE_NOT);
+ DEFINE_OPERATOR(EQUAL);
+ DEFINE_OPERATOR(NOT_EQUAL);
+ DEFINE_OPERATOR(LESS);
+ DEFINE_OPERATOR(GREATER);
+ DEFINE_OPERATOR(LESS_EQUAL);
+ DEFINE_OPERATOR(GREATER_EQUAL);
+ DEFINE_OPERATOR(IN);
+ DEFINE_OPERATOR(MATCH);
+ DEFINE_OPERATOR(NEAR);
+ DEFINE_OPERATOR(NEAR2);
+ DEFINE_OPERATOR(SIMILAR);
+ DEFINE_OPERATOR(TERM_EXTRACT);
+ DEFINE_OPERATOR(SHIFTL);
+ DEFINE_OPERATOR(SHIFTR);
+ DEFINE_OPERATOR(SHIFTRR);
+ DEFINE_OPERATOR(PLUS);
+ DEFINE_OPERATOR(MINUS);
+ DEFINE_OPERATOR(STAR);
+ DEFINE_OPERATOR(SLASH);
+ DEFINE_OPERATOR(MOD);
+ DEFINE_OPERATOR(DELETE);
+ DEFINE_OPERATOR(INCR);
+ DEFINE_OPERATOR(DECR);
+ DEFINE_OPERATOR(INCR_POST);
+ DEFINE_OPERATOR(DECR_POST);
+ DEFINE_OPERATOR(NOT);
+ DEFINE_OPERATOR(ADJUST);
+ DEFINE_OPERATOR(EXACT);
+ DEFINE_OPERATOR(LCP);
+ DEFINE_OPERATOR(PARTIAL);
+ DEFINE_OPERATOR(UNSPLIT);
+ DEFINE_OPERATOR(PREFIX);
+ DEFINE_OPERATOR(SUFFIX);
+ DEFINE_OPERATOR(GEO_DISTANCE1);
+ DEFINE_OPERATOR(GEO_DISTANCE2);
+ DEFINE_OPERATOR(GEO_DISTANCE3);
+ DEFINE_OPERATOR(GEO_DISTANCE4);
+ DEFINE_OPERATOR(GEO_WITHINP5);
+ DEFINE_OPERATOR(GEO_WITHINP6);
+ DEFINE_OPERATOR(GEO_WITHINP8);
+ DEFINE_OPERATOR(OBJ_SEARCH);
+ DEFINE_OPERATOR(EXPR_GET_VAR);
+ DEFINE_OPERATOR(TABLE_CREATE);
+ DEFINE_OPERATOR(TABLE_SELECT);
+ DEFINE_OPERATOR(TABLE_SORT);
+ DEFINE_OPERATOR(TABLE_GROUP);
+ DEFINE_OPERATOR(JSON_PUT);
+ DEFINE_OPERATOR(GET_MEMBER);
+ DEFINE_OPERATOR(REGEXP);
+ DEFINE_OPERATOR(FUZZY);
+
+#undef DEFINE_OPERATOR
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.h
new file mode 100644
index 00000000..6f27e137
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_operator.h
@@ -0,0 +1,34 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_operator_init(grn_ctx *ctx);
+mrb_value grn_mrb_value_from_operator(mrb_state *mrb, grn_operator op);
+grn_operator grn_mrb_value_to_operator(mrb_state *mrb, mrb_value mrb_op);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_options.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_options.c
new file mode 100644
index 00000000..445bcaf6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_options.c
@@ -0,0 +1,39 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include "../grn_db.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/hash.h>
+
+#include "mrb_options.h"
+
+mrb_value
+grn_mrb_options_get_static(mrb_state *mrb,
+ mrb_value mrb_options,
+ const char *key,
+ size_t key_size)
+{
+ mrb_sym mrb_key;
+
+ mrb_key = mrb_intern_static(mrb, key, key_size);
+ return mrb_hash_get(mrb, mrb_options, mrb_symbol_value(mrb_key));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_options.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_options.h
new file mode 100644
index 00000000..0cbd7bb7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_options.h
@@ -0,0 +1,38 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+mrb_value grn_mrb_options_get_static(mrb_state *mrb,
+ mrb_value mrb_options,
+ const char *key,
+ size_t key_size);
+#define grn_mrb_options_get_lit(mrb, mrb_options, literal) \
+ grn_mrb_options_get_static(mrb, mrb_options, \
+ (literal), mrb_strlen_lit(literal))
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.c
new file mode 100644
index 00000000..bd206b5c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.c
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_patricia_trie.h"
+
+static struct mrb_data_type mrb_grn_patricia_trie_type = {
+ "Groonga::PatriciaTrie",
+ NULL
+};
+
+static mrb_value
+mrb_grn_patricia_trie_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_patricia_trie_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_patricia_trie_ptr);
+ DATA_TYPE(self) = &mrb_grn_patricia_trie_type;
+ DATA_PTR(self) = mrb_cptr(mrb_patricia_trie_ptr);
+ return self;
+}
+
+void
+grn_mrb_patricia_trie_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *table_class;
+ struct RClass *klass;
+
+ table_class = mrb_class_get_under(mrb, module, "Table");
+ klass = mrb_define_class_under(mrb, module, "PatriciaTrie", table_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_patricia_trie_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.h
new file mode 100644
index 00000000..11da13a3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_patricia_trie.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_patricia_trie_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.c
new file mode 100644
index 00000000..b0d60f18
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.c
@@ -0,0 +1,77 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_pointer.h"
+#include "mrb_object.h"
+#include "mrb_converter.h"
+
+static struct mrb_data_type mrb_grn_pointer_type = {
+ "Groonga::Pointer",
+ NULL
+};
+
+static mrb_value
+mrb_grn_pointer_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_pointer_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_pointer_ptr);
+ DATA_TYPE(self) = &mrb_grn_pointer_type;
+ DATA_PTR(self) = mrb_cptr(mrb_pointer_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_pointer_get_value(mrb_state *mrb, mrb_value self)
+{
+ grn_obj *pointer;
+
+ pointer = DATA_PTR(self);
+ if (GRN_BULK_VSIZE(pointer) == 0) {
+ return mrb_nil_value();
+ }
+
+ return grn_mrb_value_from_grn_obj(mrb, GRN_PTR_VALUE(pointer));
+}
+
+void
+grn_mrb_pointer_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Pointer", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_pointer_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "value",
+ mrb_grn_pointer_get_value, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "inspect",
+ grn_mrb_object_inspect, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.h
new file mode 100644
index 00000000..5fe1dfb4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_pointer.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_pointer_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.c
new file mode 100644
index 00000000..f5045dc1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.c
@@ -0,0 +1,108 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_procedure.h"
+
+#include "mrb_operator.h"
+
+static struct mrb_data_type mrb_grn_procedure_type = {
+ "Groonga::Procedure",
+ NULL
+};
+
+static mrb_value
+mrb_grn_procedure_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_procedure_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_procedure_ptr);
+ DATA_TYPE(self) = &mrb_grn_procedure_type;
+ DATA_PTR(self) = mrb_cptr(mrb_procedure_ptr);
+ return self;
+}
+
+static mrb_value
+mrb_grn_procedure_selector_p(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *proc = DATA_PTR(self);
+
+ return mrb_bool_value(grn_obj_is_selector_proc(ctx, proc));
+}
+
+static mrb_value
+mrb_grn_procedure_selector_only_p(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *proc = DATA_PTR(self);
+
+ return mrb_bool_value(grn_obj_is_selector_only_proc(ctx, proc));
+}
+
+static mrb_value
+mrb_grn_procedure_scorer_p(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *proc = DATA_PTR(self);
+
+ return mrb_bool_value(grn_obj_is_scorer_proc(ctx, proc));
+}
+
+static mrb_value
+mrb_grn_procedure_get_selector_operator(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *proc = DATA_PTR(self);
+ grn_operator selector_op;
+
+ selector_op = grn_proc_get_selector_operator(ctx, proc);
+ return grn_mrb_value_from_operator(mrb, selector_op);
+}
+
+void
+grn_mrb_procedure_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *object_class = data->object_class;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Procedure", object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_procedure_initialize, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "selector?",
+ mrb_grn_procedure_selector_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "selector_only?",
+ mrb_grn_procedure_selector_only_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "scorer?",
+ mrb_grn_procedure_scorer_p, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "selector_operator",
+ mrb_grn_procedure_get_selector_operator, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.h
new file mode 100644
index 00000000..5d64fcd0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_procedure.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_procedure_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.c
new file mode 100644
index 00000000..d19ca780
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.c
@@ -0,0 +1,76 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/variable.h>
+#include <mruby/string.h>
+
+#include "../grn_mrb.h"
+#include "mrb_query_logger.h"
+
+static mrb_value
+query_logger_need_log_p(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int flag;
+
+ mrb_get_args(mrb, "i", &flag);
+
+ return mrb_bool_value(grn_query_logger_pass(ctx, flag));
+}
+
+static mrb_value
+query_logger_log_raw(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int flag;
+ char *mark;
+ char *message;
+ mrb_int message_size;
+
+ mrb_get_args(mrb, "izs", &flag, &mark, &message, &message_size);
+ grn_query_logger_put(ctx, flag, mark,
+ "%.*s", (int)message_size, message);
+
+ return self;
+}
+
+void
+grn_mrb_query_logger_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "QueryLogger", mrb->object_class);
+
+ mrb_define_method(mrb, klass, "need_log?", query_logger_need_log_p,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "log_raw", query_logger_log_raw,
+ MRB_ARGS_REQ(3));
+
+ grn_mrb_load(ctx, "query_logger/flag.rb");
+ grn_mrb_load(ctx, "query_logger.rb");
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.h
new file mode 100644
index 00000000..c0ea5eaf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_query_logger.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_query_logger_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_record.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_record.c
new file mode 100644
index 00000000..57411d27
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_record.c
@@ -0,0 +1,162 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/variable.h>
+#include <mruby/data.h>
+
+#include "../grn_db.h"
+#include "mrb_record.h"
+#include "mrb_bulk.h"
+
+typedef struct {
+ grn_obj *table;
+ grn_id id;
+ grn_obj key;
+} grn_mrb_record;
+
+static void
+mrb_grn_record_free(mrb_state *mrb, void *data)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_mrb_record *record = data;
+
+ if (!record) {
+ return;
+ }
+
+ GRN_OBJ_FIN(ctx, &(record->key));
+ mrb_free(mrb, record);
+}
+
+static struct mrb_data_type mrb_grn_record_type = {
+ "Groonga::Record",
+ mrb_grn_record_free
+};
+
+static mrb_value
+mrb_grn_record_initialize(mrb_state *mrb, mrb_value self)
+{
+ grn_mrb_record *record;
+ mrb_value mrb_table;
+ mrb_value mrb_id;
+
+ mrb_get_args(mrb, "oo", &mrb_table, &mrb_id);
+
+ DATA_TYPE(self) = &mrb_grn_record_type;
+
+ record = mrb_malloc(mrb, sizeof(grn_mrb_record));
+ record->table = DATA_PTR(mrb_table);
+ if (mrb_nil_p(mrb_id)) {
+ record->id = GRN_ID_NIL;
+ } else {
+ record->id = mrb_fixnum(mrb_id);
+ }
+
+ switch (record->table->header.domain) {
+ case GRN_ID_NIL :
+ case GRN_DB_SHORT_TEXT :
+ GRN_SHORT_TEXT_INIT(&(record->key), 0);
+ break;
+ default :
+ GRN_VALUE_FIX_SIZE_INIT(&(record->key), 0, record->table->header.domain);
+ break;
+ }
+
+ DATA_PTR(self) = record;
+
+ mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@table"), mrb_table);
+ mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@id"), mrb_id);
+
+ return self;
+}
+
+static mrb_value
+mrb_grn_record_set_id(mrb_state *mrb, mrb_value self)
+{
+ grn_mrb_record *record;
+ mrb_value mrb_id;
+
+ record = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_id);
+
+ if (mrb_nil_p(mrb_id)) {
+ record->id = GRN_ID_NIL;
+ } else {
+ record->id = mrb_fixnum(mrb_id);
+ }
+ mrb_iv_set(mrb, self, mrb_intern_lit(mrb, "@id"), mrb_id);
+
+ return mrb_id;
+}
+
+static mrb_value
+mrb_grn_record_key(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_mrb_record *record;
+ int key_size;
+
+ record = DATA_PTR(self);
+
+ if (record->id == GRN_ID_NIL) {
+ return mrb_nil_value();
+ }
+
+ if (record->table->header.type == GRN_TABLE_NO_KEY) {
+ return mrb_nil_value();
+ }
+
+ GRN_BULK_REWIND(&(record->key));
+ key_size = grn_table_get_key(ctx, record->table, record->id,
+ GRN_BULK_HEAD(&(record->key)),
+ GRN_BULK_VSIZE(&(record->key)));
+ if (key_size > GRN_BULK_VSIZE(&(record->key))) {
+ grn_bulk_space(ctx, &(record->key), key_size);
+ key_size = grn_table_get_key(ctx, record->table, record->id,
+ GRN_BULK_HEAD(&(record->key)),
+ GRN_BULK_VSIZE(&(record->key)));
+ }
+
+ return grn_mrb_value_from_bulk(mrb, &(record->key));
+}
+
+void
+grn_mrb_record_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Record", data->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_record_initialize, MRB_ARGS_REQ(2));
+
+ mrb_define_method(mrb, klass, "id=",
+ mrb_grn_record_set_id, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "key",
+ mrb_grn_record_key, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_record.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_record.h
new file mode 100644
index 00000000..9c0e6ece
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_record.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_record_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table.c
new file mode 100644
index 00000000..fecc6e3d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table.c
@@ -0,0 +1,493 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+#include <string.h>
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+
+#include "mrb_ctx.h"
+#include "mrb_table.h"
+#include "mrb_converter.h"
+#include "mrb_options.h"
+
+static mrb_value
+mrb_grn_table_array_reference(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ grn_id key_domain_id;
+ mrb_value mrb_key;
+ grn_id record_id;
+ grn_mrb_value_to_raw_data_buffer buffer;
+ void *key;
+ unsigned int key_size;
+
+ mrb_get_args(mrb, "o", &mrb_key);
+
+ table = DATA_PTR(self);
+ if (table->header.type == GRN_DB) {
+ key_domain_id = GRN_DB_SHORT_TEXT;
+ } else {
+ key_domain_id = table->header.domain;
+ }
+
+ grn_mrb_value_to_raw_data_buffer_init(mrb, &buffer);
+ grn_mrb_value_to_raw_data(mrb, "key", mrb_key, key_domain_id,
+ &buffer, &key, &key_size);
+ record_id = grn_table_get(ctx, table, key, key_size);
+ grn_mrb_value_to_raw_data_buffer_fin(mrb, &buffer);
+
+ if (record_id == GRN_ID_NIL) {
+ return mrb_nil_value();
+ } else {
+ return mrb_fixnum_value(record_id);
+ }
+}
+
+static mrb_value
+mrb_grn_table_is_id(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ mrb_int mrb_record_id;
+ grn_id record_id;
+ grn_id real_record_id;
+
+ mrb_get_args(mrb, "i", &mrb_record_id);
+
+ table = DATA_PTR(self);
+ record_id = (grn_id)mrb_record_id;
+ real_record_id = grn_table_at(ctx, table, record_id);
+ if (real_record_id == record_id) {
+ return mrb_true_value();
+ } else {
+ return mrb_false_value();
+ }
+}
+
+static mrb_value
+mrb_grn_table_find_column(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ mrb_value mrb_column_name;
+ grn_obj *column;
+
+ mrb_get_args(mrb, "o", &mrb_column_name);
+
+ table = DATA_PTR(self);
+ column = grn_obj_column(ctx, table,
+ RSTRING_PTR(mrb_column_name),
+ RSTRING_LEN(mrb_column_name));
+ grn_mrb_ctx_check(mrb);
+
+ return grn_mrb_value_from_grn_obj(mrb, column);
+}
+
+static mrb_value
+mrb_grn_table_get_column_ids(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ grn_hash *columns;
+ int n_columns;
+ mrb_value mrb_column_ids;
+
+ table = DATA_PTR(self);
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
+ if (!columns) {
+ grn_mrb_ctx_check(mrb);
+ return mrb_ary_new(mrb);
+ }
+
+ n_columns = grn_table_columns(ctx, table, "", 0, (grn_obj *)columns);
+ mrb_column_ids = mrb_ary_new_capa(mrb, n_columns);
+ {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
+ mrb_ary_push(mrb, mrb_column_ids, mrb_fixnum_value(*key));
+ });
+ }
+ grn_hash_close(ctx, columns);
+
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_column_ids;
+}
+
+static mrb_value
+mrb_grn_table_create_column(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ mrb_value mrb_name;
+ mrb_int flags;
+ mrb_value mrb_type;
+ grn_obj *type;
+ grn_obj *column;
+
+ mrb_get_args(mrb, "oio", &mrb_name, &flags, &mrb_type);
+
+ table = DATA_PTR(self);
+ type = DATA_PTR(mrb_type);
+ column = grn_column_create(ctx, table,
+ RSTRING_PTR(mrb_name),
+ RSTRING_LEN(mrb_name),
+ NULL,
+ flags,
+ type);
+ grn_mrb_ctx_check(mrb);
+
+ return grn_mrb_value_from_grn_obj(mrb, column);
+}
+
+static mrb_value
+mrb_grn_table_is_locked(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ unsigned int is_locked;
+
+ is_locked = grn_obj_is_locked(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_bool_value(is_locked != 0);
+}
+
+static mrb_value
+mrb_grn_table_get_size(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ unsigned int size;
+
+ size = grn_table_size(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_fixnum_value(size);
+}
+
+static mrb_value
+mrb_grn_table_is_empty(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ unsigned int size;
+
+ size = grn_table_size(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_bool_value(size == 0);
+}
+
+static mrb_value
+mrb_grn_table_select(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ grn_obj *expr;
+ grn_obj *result = NULL;
+ grn_operator operator = GRN_OP_OR;
+ mrb_value mrb_expr;
+ mrb_value mrb_options = mrb_nil_value();
+
+ table = DATA_PTR(self);
+ mrb_get_args(mrb, "o|H", &mrb_expr, &mrb_options);
+
+ expr = DATA_PTR(mrb_expr);
+
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_result;
+ mrb_value mrb_operator;
+
+ mrb_result = grn_mrb_options_get_lit(mrb, mrb_options, "result");
+ if (!mrb_nil_p(mrb_result)) {
+ result = DATA_PTR(mrb_result);
+ }
+
+ mrb_operator = grn_mrb_options_get_lit(mrb, mrb_options, "operator");
+ if (!mrb_nil_p(mrb_operator)) {
+ operator = mrb_fixnum(mrb_operator);
+ }
+ }
+
+ result = grn_table_select(ctx, table, expr, result, operator);
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_mrb_ctx_check(mrb);
+ }
+
+ return grn_mrb_value_from_grn_obj(mrb, result);
+}
+
+static mrb_value
+mrb_grn_table_sort_raw(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ mrb_value mrb_keys;
+ grn_table_sort_key *keys;
+ int i, n_keys;
+ mrb_int offset;
+ mrb_int limit;
+ mrb_value mrb_result;
+ grn_obj *result;
+
+ table = DATA_PTR(self);
+ mrb_get_args(mrb, "oiio", &mrb_keys, &offset, &limit, &mrb_result);
+
+ mrb_keys = mrb_convert_type(mrb, mrb_keys,
+ MRB_TT_ARRAY, "Array", "to_ary");
+
+ n_keys = RARRAY_LEN(mrb_keys);
+ keys = GRN_MALLOCN(grn_table_sort_key, n_keys);
+ for (i = 0; i < n_keys; i++) {
+ grn_memcpy(&(keys[i]),
+ DATA_PTR(RARRAY_PTR(mrb_keys)[i]),
+ sizeof(grn_table_sort_key));
+ }
+ result = DATA_PTR(mrb_result);
+ grn_table_sort(ctx, table, offset, limit, result, keys, n_keys);
+ GRN_FREE(keys);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_result;
+}
+
+static mrb_value
+mrb_grn_table_group_raw(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ mrb_value mrb_keys;
+ grn_table_sort_key *keys;
+ int i, n_keys;
+ mrb_value mrb_result;
+ grn_table_group_result *result;
+
+ table = DATA_PTR(self);
+ mrb_get_args(mrb, "oo", &mrb_keys, &mrb_result);
+
+ mrb_keys = mrb_convert_type(mrb, mrb_keys,
+ MRB_TT_ARRAY, "Array", "to_ary");
+
+ n_keys = RARRAY_LEN(mrb_keys);
+ keys = GRN_MALLOCN(grn_table_sort_key, n_keys);
+ for (i = 0; i < n_keys; i++) {
+ grn_memcpy(&(keys[i]),
+ DATA_PTR(RARRAY_PTR(mrb_keys)[i]),
+ sizeof(grn_table_sort_key));
+ }
+ result = DATA_PTR(mrb_result);
+ grn_table_group(ctx, table, keys, n_keys, result, 1);
+ GRN_FREE(keys);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_result;
+}
+
+static mrb_value
+mrb_grn_table_delete(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+ mrb_value mrb_options;
+ mrb_value mrb_id;
+ mrb_value mrb_key;
+ mrb_value mrb_expression;
+
+ table = DATA_PTR(self);
+ mrb_get_args(mrb, "H", &mrb_options);
+
+ mrb_id = grn_mrb_options_get_lit(mrb, mrb_options, "id");
+ if (!mrb_nil_p(mrb_id)) {
+ grn_table_delete_by_id(ctx, table, mrb_fixnum(mrb_id));
+ grn_mrb_ctx_check(mrb);
+ return mrb_nil_value();
+ }
+
+ mrb_key = grn_mrb_options_get_lit(mrb, mrb_options, "key");
+ if (!mrb_nil_p(mrb_key)) {
+ grn_id key_domain_id;
+ void *key;
+ unsigned int key_size;
+ grn_mrb_value_to_raw_data_buffer buffer;
+
+ key_domain_id = table->header.domain;
+ grn_mrb_value_to_raw_data_buffer_init(mrb, &buffer);
+ grn_mrb_value_to_raw_data(mrb, "key", mrb_key, key_domain_id,
+ &buffer, &key, &key_size);
+ grn_table_delete(ctx, table, key, key_size);
+ grn_mrb_value_to_raw_data_buffer_fin(mrb, &buffer);
+ grn_mrb_ctx_check(mrb);
+ return mrb_nil_value();
+ }
+
+ mrb_expression = grn_mrb_options_get_lit(mrb, mrb_options, "expression");
+ if (!mrb_nil_p(mrb_expression)) {
+ grn_obj *expression;
+ grn_obj *selected_records;
+ grn_table_cursor *cursor;
+
+ expression = DATA_PTR(mrb_expression);
+ selected_records = grn_table_select(ctx, table, expression, NULL, GRN_OP_OR);
+ grn_mrb_ctx_check(mrb);
+ cursor = grn_table_cursor_open(ctx, selected_records,
+ NULL, 0,
+ NULL, 0,
+ 0, -1, 0);
+ if (cursor) {
+ while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_id *id;
+ grn_table_cursor_get_key(ctx, cursor, (void **)&id);
+ grn_table_delete_by_id(ctx, table, *id);
+ }
+ grn_table_cursor_close(ctx, cursor);
+ }
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+ }
+
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "must have :id, :key or :expression: %S",
+ mrb_options);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_truncate(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_obj *table;
+
+ table = DATA_PTR(self);
+ grn_table_truncate(ctx, table);
+ grn_mrb_ctx_check(mrb);
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_apply_expression(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_output_column;
+ mrb_value mrb_expression;
+ grn_obj *table;
+ grn_obj *output_column = NULL;
+ grn_obj *expression = NULL;
+
+ mrb_get_args(mrb, "oo", &mrb_output_column, &mrb_expression);
+
+ table = DATA_PTR(self);
+ output_column = GRN_MRB_DATA_PTR(mrb_output_column);
+ expression = GRN_MRB_DATA_PTR(mrb_expression);
+ grn_table_apply_expr(ctx, table, output_column, expression);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_apply_window_function_raw(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_output_column;
+ mrb_value mrb_window_definition;
+ mrb_value mrb_window_function_call;
+ grn_obj *table;
+ grn_obj *output_column = NULL;
+ grn_window_definition *window_definition = NULL;
+ grn_obj *window_function_call = NULL;
+
+ mrb_get_args(mrb, "ooo",
+ &mrb_output_column,
+ &mrb_window_definition,
+ &mrb_window_function_call);
+
+ table = DATA_PTR(self);
+ output_column = GRN_MRB_DATA_PTR(mrb_output_column);
+ window_definition = GRN_MRB_DATA_PTR(mrb_window_definition);
+ window_function_call = GRN_MRB_DATA_PTR(mrb_window_function_call);
+ grn_table_apply_window_function(ctx,
+ table,
+ output_column,
+ window_definition,
+ window_function_call);
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_table_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *object_class = data->object_class;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Table", object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "[]",
+ mrb_grn_table_array_reference, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "id?",
+ mrb_grn_table_is_id, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "find_column",
+ mrb_grn_table_find_column, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "column_ids",
+ mrb_grn_table_get_column_ids, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "create_column",
+ mrb_grn_table_create_column, MRB_ARGS_REQ(3));
+
+ mrb_define_method(mrb, klass, "locked?",
+ mrb_grn_table_is_locked, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "size",
+ mrb_grn_table_get_size, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "empty?",
+ mrb_grn_table_is_empty, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "select",
+ mrb_grn_table_select, MRB_ARGS_ARG(1, 1));
+ mrb_define_method(mrb, klass, "sort_raw",
+ mrb_grn_table_sort_raw, MRB_ARGS_REQ(4));
+ mrb_define_method(mrb, klass, "group_raw",
+ mrb_grn_table_group_raw, MRB_ARGS_REQ(2));
+
+ mrb_define_method(mrb, klass, "delete",
+ mrb_grn_table_delete, MRB_ARGS_REQ(1));
+
+ mrb_define_method(mrb, klass, "truncate",
+ mrb_grn_table_truncate, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "apply_expression",
+ mrb_grn_table_apply_expression, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, klass, "apply_window_function_raw",
+ mrb_grn_table_apply_window_function_raw, MRB_ARGS_REQ(4));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table.h
new file mode 100644
index 00000000..fd06db56
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.c
new file mode 100644
index 00000000..a7748168
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.c
@@ -0,0 +1,208 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/string.h>
+#include <mruby/hash.h>
+#include <mruby/variable.h>
+
+#include "mrb_ctx.h"
+#include "mrb_bulk.h"
+#include "mrb_table_cursor.h"
+
+#include "mrb_converter.h"
+#include "mrb_options.h"
+
+static struct mrb_data_type mrb_grn_table_cursor_type = {
+ "Groonga::TableCursor",
+ NULL
+};
+
+static mrb_value
+mrb_grn_table_cursor_class_open_raw(mrb_state *mrb, mrb_value klass)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_table;
+ mrb_value mrb_options = mrb_nil_value();
+ grn_table_cursor *table_cursor;
+ grn_obj *table;
+ void *min = NULL;
+ unsigned int min_size = 0;
+ grn_mrb_value_to_raw_data_buffer min_buffer;
+ void *max = NULL;
+ unsigned int max_size = 0;
+ grn_mrb_value_to_raw_data_buffer max_buffer;
+ int offset = 0;
+ int limit = -1;
+ int flags = 0;
+
+ mrb_get_args(mrb, "o|H", &mrb_table, &mrb_options);
+
+ table = DATA_PTR(mrb_table);
+ grn_mrb_value_to_raw_data_buffer_init(mrb, &min_buffer);
+ grn_mrb_value_to_raw_data_buffer_init(mrb, &max_buffer);
+ if (!mrb_nil_p(mrb_options)) {
+ grn_id key_domain_id;
+ mrb_value mrb_min;
+ mrb_value mrb_max;
+ mrb_value mrb_flags;
+
+ if (table->header.type == GRN_DB) {
+ key_domain_id = GRN_DB_SHORT_TEXT;
+ } else {
+ key_domain_id = table->header.domain;
+ }
+
+ mrb_min = grn_mrb_options_get_lit(mrb, mrb_options, "min");
+ grn_mrb_value_to_raw_data(mrb, "min", mrb_min,
+ key_domain_id, &min_buffer, &min, &min_size);
+
+ mrb_max = grn_mrb_options_get_lit(mrb, mrb_options, "max");
+ grn_mrb_value_to_raw_data(mrb, "max", mrb_max,
+ key_domain_id, &max_buffer, &max, &max_size);
+
+ mrb_flags = grn_mrb_options_get_lit(mrb, mrb_options, "flags");
+ if (!mrb_nil_p(mrb_flags)) {
+ flags = mrb_fixnum(mrb_flags);
+ }
+ }
+ table_cursor = grn_table_cursor_open(ctx, table,
+ min, min_size,
+ max, max_size,
+ offset, limit, flags);
+ grn_mrb_value_to_raw_data_buffer_fin(mrb, &min_buffer);
+ grn_mrb_value_to_raw_data_buffer_fin(mrb, &max_buffer);
+ grn_mrb_ctx_check(mrb);
+
+ {
+ mrb_value mrb_table_cursor;
+ mrb_table_cursor = mrb_funcall(mrb, klass,
+ "new", 1, mrb_cptr_value(mrb, table_cursor));
+ mrb_iv_set(mrb, mrb_table_cursor, mrb_intern_lit(mrb, "@table"), mrb_table);
+ return mrb_table_cursor;
+ }
+}
+
+static mrb_value
+mrb_grn_table_cursor_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_table_cursor_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_table_cursor_ptr);
+ DATA_TYPE(self) = &mrb_grn_table_cursor_type;
+ DATA_PTR(self) = mrb_cptr(mrb_table_cursor_ptr);
+
+ return self;
+}
+
+static mrb_value
+mrb_grn_table_cursor_close(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_table_cursor *table_cursor;
+
+ table_cursor = DATA_PTR(self);
+ if (table_cursor) {
+ DATA_PTR(self) = NULL;
+ grn_table_cursor_close(ctx, table_cursor);
+ grn_mrb_ctx_check(mrb);
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_cursor_next(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_id id;
+
+ id = grn_table_cursor_next(ctx, DATA_PTR(self));
+ grn_mrb_ctx_check(mrb);
+
+ return mrb_fixnum_value(id);
+}
+
+static mrb_value
+mrb_grn_table_cursor_count(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ int n_records = 0;
+
+ while (grn_table_cursor_next(ctx, DATA_PTR(self)) != GRN_ID_NIL) {
+ n_records++;
+ }
+
+ return mrb_fixnum_value(n_records);
+}
+
+static mrb_value
+mrb_grn_table_cursor_get_key(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_table;
+ grn_obj *table;
+ grn_id domain;
+ void *key;
+ int key_size;
+
+ mrb_table = mrb_iv_get(mrb, self, mrb_intern_lit(mrb, "@table"));
+ table = DATA_PTR(mrb_table);
+ if (table->header.type == GRN_DB) {
+ domain = GRN_DB_SHORT_TEXT;
+ } else {
+ domain = table->header.domain;
+ }
+ key_size = grn_table_cursor_get_key(ctx, DATA_PTR(self), &key);
+
+ return grn_mrb_value_from_raw_data(mrb, domain, key, key_size);
+}
+
+void
+grn_mrb_table_cursor_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "TableCursor", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_class_method(mrb, klass, "open_raw",
+ mrb_grn_table_cursor_class_open_raw,
+ MRB_ARGS_ARG(1, 1));
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_table_cursor_initialize, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "close",
+ mrb_grn_table_cursor_close, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "next",
+ mrb_grn_table_cursor_next, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "count",
+ mrb_grn_table_cursor_count, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "key",
+ mrb_grn_table_cursor_get_key, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.h
new file mode 100644
index 00000000..6ffd51af
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_cursor_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.c
new file mode 100644
index 00000000..58a3137a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.c
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+
+#include "mrb_table_cursor_flags.h"
+
+void
+grn_mrb_table_cursor_flags_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *flags_module;
+
+ flags_module = mrb_define_module_under(mrb, module, "TableCursorFlags");
+
+ mrb_define_const(mrb, flags_module, "ASCENDING",
+ mrb_fixnum_value(GRN_CURSOR_ASCENDING));
+ mrb_define_const(mrb, flags_module, "DESCENDING",
+ mrb_fixnum_value(GRN_CURSOR_DESCENDING));
+ mrb_define_const(mrb, flags_module, "GE",
+ mrb_fixnum_value(GRN_CURSOR_GE));
+ mrb_define_const(mrb, flags_module, "GT",
+ mrb_fixnum_value(GRN_CURSOR_GT));
+ mrb_define_const(mrb, flags_module, "LE",
+ mrb_fixnum_value(GRN_CURSOR_LE));
+ mrb_define_const(mrb, flags_module, "LT",
+ mrb_fixnum_value(GRN_CURSOR_LT));
+ mrb_define_const(mrb, flags_module, "BY_KEY",
+ mrb_fixnum_value(GRN_CURSOR_BY_KEY));
+ mrb_define_const(mrb, flags_module, "BY_ID",
+ mrb_fixnum_value(GRN_CURSOR_BY_ID));
+ mrb_define_const(mrb, flags_module, "PREFIX",
+ mrb_fixnum_value(GRN_CURSOR_PREFIX));
+ mrb_define_const(mrb, flags_module, "SIZE_BY_BIT",
+ mrb_fixnum_value(GRN_CURSOR_SIZE_BY_BIT));
+ mrb_define_const(mrb, flags_module, "RK",
+ mrb_fixnum_value(GRN_CURSOR_RK));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.h
new file mode 100644
index 00000000..5db915a7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_cursor_flags.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_cursor_flags_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.c
new file mode 100644
index 00000000..8984ebef
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.c
@@ -0,0 +1,48 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+
+#include "mrb_table_group_flags.h"
+
+void
+grn_mrb_table_group_flags_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *flags_module;
+
+ flags_module = mrb_define_module_under(mrb, module, "TableGroupFlags");
+
+ mrb_define_const(mrb, flags_module, "CALC_COUNT",
+ mrb_fixnum_value(GRN_TABLE_GROUP_CALC_COUNT));
+ mrb_define_const(mrb, flags_module, "CALC_MAX",
+ mrb_fixnum_value(GRN_TABLE_GROUP_CALC_MAX));
+ mrb_define_const(mrb, flags_module, "CALC_MIN",
+ mrb_fixnum_value(GRN_TABLE_GROUP_CALC_MIN));
+ mrb_define_const(mrb, flags_module, "CALC_SUM",
+ mrb_fixnum_value(GRN_TABLE_GROUP_CALC_SUM));
+ mrb_define_const(mrb, flags_module, "CALC_AVG",
+ mrb_fixnum_value(GRN_TABLE_GROUP_CALC_AVG));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.h
new file mode 100644
index 00000000..4230a240
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_flags.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_group_flags_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.c
new file mode 100644
index 00000000..c4aaafa4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.c
@@ -0,0 +1,254 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+
+#include "mrb_ctx.h"
+#include "mrb_converter.h"
+#include "mrb_operator.h"
+#include "mrb_table_group_result.h"
+
+static void
+mrb_grn_table_group_result_free(mrb_state *mrb, void *data)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_table_group_result *result = data;
+
+ if (!result) {
+ return;
+ }
+
+ if (result->calc_target) {
+ grn_obj_unlink(ctx, result->calc_target);
+ }
+ if (result->table) {
+ grn_obj_unlink(ctx, result->table);
+ }
+ mrb_free(mrb, result);
+}
+
+static struct mrb_data_type mrb_grn_table_group_result_type = {
+ "Groonga::TableGroupResult",
+ mrb_grn_table_group_result_free
+};
+
+static mrb_value
+mrb_grn_table_group_result_initialize(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+
+ DATA_TYPE(self) = &mrb_grn_table_group_result_type;
+
+ result = mrb_calloc(mrb, 1, sizeof(grn_table_group_result));
+ DATA_PTR(self) = result;
+
+ return self;
+}
+
+
+static mrb_value
+mrb_grn_table_group_result_close(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+
+ result = DATA_PTR(self);
+ if (result) {
+ mrb_grn_table_group_result_free(mrb, result);
+ DATA_PTR(self) = NULL;
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_get_table(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+
+ result = DATA_PTR(self);
+
+ return grn_mrb_value_from_grn_obj(mrb, result->table);
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_table(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_value mrb_table;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_table);
+
+ if (mrb_nil_p(mrb_table)) {
+ result->table = NULL;
+ } else {
+ result->table = DATA_PTR(mrb_table);
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_key_begin(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_int key_begin;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &key_begin);
+
+ result->key_begin = key_begin;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_key_end(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_int key_end;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &key_end);
+
+ result->key_end = key_end;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_limit(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_int limit;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &limit);
+
+ result->limit = limit;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_flags(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_int flags;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &flags);
+
+ result->flags = flags;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_operator(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_value mrb_operator;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_operator);
+
+ result->op = grn_mrb_value_to_operator(mrb, mrb_operator);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_max_n_sub_records(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_int max_n_sub_records;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &max_n_sub_records);
+
+ result->max_n_subrecs = max_n_sub_records;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_group_result_set_calc_target(mrb_state *mrb, mrb_value self)
+{
+ grn_table_group_result *result;
+ mrb_value mrb_calc_target;
+
+ result = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_calc_target);
+
+ if (mrb_nil_p(mrb_calc_target)) {
+ result->calc_target = NULL;
+ } else {
+ result->calc_target = DATA_PTR(mrb_calc_target);
+ }
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_table_group_result_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "TableGroupResult",
+ mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_table_group_result_initialize, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "close",
+ mrb_grn_table_group_result_close, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "table",
+ mrb_grn_table_group_result_get_table, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "table=",
+ mrb_grn_table_group_result_set_table, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "key_begin=",
+ mrb_grn_table_group_result_set_key_begin, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "key_end=",
+ mrb_grn_table_group_result_set_key_end, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "limit=",
+ mrb_grn_table_group_result_set_limit, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "flags=",
+ mrb_grn_table_group_result_set_flags, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "operator=",
+ mrb_grn_table_group_result_set_operator, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "max_n_sub_records=",
+ mrb_grn_table_group_result_set_max_n_sub_records,
+ MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "calc_target=",
+ mrb_grn_table_group_result_set_calc_target, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.h
new file mode 100644
index 00000000..c3b17af2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_group_result.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_group_result_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.c
new file mode 100644
index 00000000..47f0169e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.c
@@ -0,0 +1,42 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+
+#include "mrb_table_sort_flags.h"
+
+void
+grn_mrb_table_sort_flags_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *flags_module;
+
+ flags_module = mrb_define_module_under(mrb, module, "TableSortFlags");
+
+ mrb_define_const(mrb, flags_module, "ASCENDING",
+ mrb_fixnum_value(GRN_TABLE_SORT_ASC));
+ mrb_define_const(mrb, flags_module, "DESCENDING",
+ mrb_fixnum_value(GRN_TABLE_SORT_DESC));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.h
new file mode 100644
index 00000000..7450399e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_flags.h
@@ -0,0 +1,31 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_sort_flags_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.c
new file mode 100644
index 00000000..f8692d48
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.c
@@ -0,0 +1,159 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/array.h>
+#include <mruby/string.h>
+
+#include "mrb_ctx.h"
+#include "mrb_table_sort_key.h"
+
+static void
+mrb_grn_table_sort_key_free(mrb_state *mrb, void *data)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_table_sort_key *sort_key = data;
+
+ if (!sort_key) {
+ return;
+ }
+
+ if (sort_key->key) {
+ if (sort_key->key->header.type == GRN_ACCESSOR) {
+ grn_obj_unlink(ctx, sort_key->key);
+ }
+ }
+ mrb_free(mrb, sort_key);
+}
+
+static struct mrb_data_type mrb_grn_table_sort_key_type = {
+ "Groonga::TableSortKey",
+ mrb_grn_table_sort_key_free
+};
+
+static mrb_value
+mrb_grn_table_sort_key_initialize(mrb_state *mrb, mrb_value self)
+{
+ grn_table_sort_key *result;
+
+ DATA_TYPE(self) = &mrb_grn_table_sort_key_type;
+
+ result = mrb_calloc(mrb, 1, sizeof(grn_table_sort_key));
+ DATA_PTR(self) = result;
+
+ return self;
+}
+
+
+static mrb_value
+mrb_grn_table_sort_key_close(mrb_state *mrb, mrb_value self)
+{
+ grn_table_sort_key *sort_key;
+
+ sort_key = DATA_PTR(self);
+ if (sort_key) {
+ mrb_grn_table_sort_key_free(mrb, sort_key);
+ DATA_PTR(self) = NULL;
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_sort_key_set_key(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ grn_table_sort_key *sort_key;
+ mrb_value mrb_key;
+
+ sort_key = DATA_PTR(self);
+ mrb_get_args(mrb, "o", &mrb_key);
+
+ if (sort_key->key) {
+ grn_obj_unlink(ctx, sort_key->key);
+ }
+
+ if (mrb_nil_p(mrb_key)) {
+ sort_key->key = NULL;
+ } else {
+ sort_key->key = DATA_PTR(mrb_key);
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_sort_key_set_flags(mrb_state *mrb, mrb_value self)
+{
+ grn_table_sort_key *sort_key;
+ mrb_int flags;
+
+ sort_key = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &flags);
+
+ sort_key->flags = flags;
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_table_sort_key_set_offset(mrb_state *mrb, mrb_value self)
+{
+ grn_table_sort_key *sort_key;
+ mrb_int offset;
+
+ sort_key = DATA_PTR(self);
+ mrb_get_args(mrb, "i", &offset);
+
+ sort_key->offset = offset;
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_table_sort_key_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "TableSortKey",
+ mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_table_sort_key_initialize, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "close",
+ mrb_grn_table_sort_key_close, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "key=",
+ mrb_grn_table_sort_key_set_key, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "flags=",
+ mrb_grn_table_sort_key_set_flags, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "offset=",
+ mrb_grn_table_sort_key_set_offset, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.h
new file mode 100644
index 00000000..9ca38bfc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_table_sort_key.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_table_sort_key_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.c
new file mode 100644
index 00000000..ba3a7e7b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.c
@@ -0,0 +1,46 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+
+#include "mrb_thread.h"
+
+static mrb_value
+thread_limit(mrb_state *mrb, mrb_value self)
+{
+ uint32_t limit;
+ limit = grn_thread_get_limit();
+ return mrb_fixnum_value(limit);
+}
+
+void
+grn_mrb_thread_init(grn_ctx *ctx)
+{
+ mrb_state *mrb = ctx->impl->mrb.state;
+ struct RClass *module = ctx->impl->mrb.module;
+ struct RClass *thread_module;
+
+ thread_module = mrb_define_module_under(mrb, module, "Thread");
+
+ mrb_define_class_method(mrb, thread_module,
+ "limit", thread_limit, MRB_ARGS_NONE());
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.h
new file mode 100644
index 00000000..030eafed
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_thread.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_thread_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_type.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_type.c
new file mode 100644
index 00000000..a288d60f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_type.c
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_ctx.h"
+#include "mrb_type.h"
+
+static struct mrb_data_type mrb_grn_type_type = {
+ "Groonga::Type",
+ NULL
+};
+
+static mrb_value
+mrb_grn_type_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_type_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_type_ptr);
+ DATA_TYPE(self) = &mrb_grn_type_type;
+ DATA_PTR(self) = mrb_cptr(mrb_type_ptr);
+ return self;
+}
+
+void
+grn_mrb_type_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *object_class = data->object_class;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Type", object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_type_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_type.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_type.h
new file mode 100644
index 00000000..8dc74b79
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_type.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_type_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.c
new file mode 100644
index 00000000..78f3de86
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.c
@@ -0,0 +1,60 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+
+#include "mrb_variable_size_column.h"
+
+static struct mrb_data_type mrb_grn_variable_size_column_type = {
+ "Groonga::VariableSizeColumn",
+ NULL
+};
+
+static mrb_value
+mrb_grn_variable_size_column_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_variable_size_column_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_variable_size_column_ptr);
+ DATA_TYPE(self) = &mrb_grn_variable_size_column_type;
+ DATA_PTR(self) = mrb_cptr(mrb_variable_size_column_ptr);
+ return self;
+}
+
+void
+grn_mrb_variable_size_column_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *column_class;
+ struct RClass *klass;
+
+ column_class = mrb_class_get_under(mrb, module, "Column");
+ klass = mrb_define_class_under(mrb, module,
+ "VariableSizeColumn", column_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_variable_size_column_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.h
new file mode 100644
index 00000000..1bac1238
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_variable_size_column.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_variable_size_column_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_void.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_void.c
new file mode 100644
index 00000000..33cdea6c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_void.c
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/variable.h>
+#include <mruby/data.h>
+
+#include "../grn_db.h"
+#include "mrb_void.h"
+
+static struct mrb_data_type mrb_grn_void_type = {
+ "Groonga::Void",
+ NULL
+};
+
+static mrb_value
+mrb_grn_void_initialize(mrb_state *mrb, mrb_value self)
+{
+ mrb_value mrb_void_ptr;
+
+ mrb_get_args(mrb, "o", &mrb_void_ptr);
+ DATA_TYPE(self) = &mrb_grn_void_type;
+ DATA_PTR(self) = mrb_cptr(mrb_void_ptr);
+ return self;
+}
+
+void
+grn_mrb_void_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Void", mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_void_initialize, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_void.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_void.h
new file mode 100644
index 00000000..dced2747
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_void.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_void_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.c
new file mode 100644
index 00000000..86ff372e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.c
@@ -0,0 +1,164 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/class.h>
+#include <mruby/data.h>
+#include <mruby/array.h>
+
+#include "mrb_ctx.h"
+#include "mrb_window_definition.h"
+
+static void
+mrb_grn_window_definition_free(mrb_state *mrb, void *data)
+{
+ grn_window_definition *definition = data;
+
+ if (!definition) {
+ return;
+ }
+
+ if (definition->sort_keys) {
+ mrb_free(mrb, definition->sort_keys);
+ }
+ if (definition->group_keys) {
+ mrb_free(mrb, definition->group_keys);
+ }
+ mrb_free(mrb, definition);
+}
+
+static struct mrb_data_type mrb_grn_window_definition_type = {
+ "Groonga::WindowDefinition",
+ mrb_grn_window_definition_free
+};
+
+static mrb_value
+mrb_grn_window_definition_initialize(mrb_state *mrb, mrb_value self)
+{
+ grn_window_definition *result;
+
+ DATA_TYPE(self) = &mrb_grn_window_definition_type;
+
+ result = mrb_calloc(mrb, 1, sizeof(grn_window_definition));
+ DATA_PTR(self) = result;
+
+ return self;
+}
+
+
+static mrb_value
+mrb_grn_window_definition_close(mrb_state *mrb, mrb_value self)
+{
+ grn_window_definition *definition;
+
+ definition = DATA_PTR(self);
+ if (definition) {
+ mrb_grn_window_definition_free(mrb, definition);
+ DATA_PTR(self) = NULL;
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_window_definition_set_sort_keys(mrb_state *mrb, mrb_value self)
+{
+ grn_window_definition *definition;
+ mrb_value mrb_keys;
+
+ definition = DATA_PTR(self);
+ mrb_get_args(mrb, "A!", &mrb_keys);
+
+ if (definition->sort_keys) {
+ mrb_free(mrb, definition->sort_keys);
+ }
+
+ if (mrb_nil_p(mrb_keys)) {
+ definition->sort_keys = NULL;
+ definition->n_sort_keys = 0;
+ } else {
+ mrb_int i, n;
+ n = RARRAY_LEN(mrb_keys);
+ definition->sort_keys = mrb_calloc(mrb, n, sizeof(grn_table_sort_key));
+ for (i = 0; i < n; i++) {
+ grn_table_sort_key *sort_key = DATA_PTR(RARRAY_PTR(mrb_keys)[i]);
+ definition->sort_keys[i] = *sort_key;
+ }
+ definition->n_sort_keys = n;
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+mrb_grn_window_definition_set_group_keys(mrb_state *mrb, mrb_value self)
+{
+ grn_window_definition *definition;
+ mrb_value mrb_keys;
+
+ definition = DATA_PTR(self);
+ mrb_get_args(mrb, "A!", &mrb_keys);
+
+ if (definition->group_keys) {
+ mrb_free(mrb, definition->group_keys);
+ }
+
+ if (mrb_nil_p(mrb_keys)) {
+ definition->group_keys = NULL;
+ definition->n_group_keys = 0;
+ } else {
+ mrb_int i, n;
+ n = RARRAY_LEN(mrb_keys);
+ definition->group_keys = mrb_calloc(mrb, n, sizeof(grn_table_sort_key));
+ for (i = 0; i < n; i++) {
+ grn_table_sort_key *group_key = DATA_PTR(RARRAY_PTR(mrb_keys)[i]);
+ definition->group_keys[i] = *group_key;
+ }
+ definition->n_group_keys = n;
+ }
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_window_definition_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "WindowDefinition",
+ mrb->object_class);
+ MRB_SET_INSTANCE_TT(klass, MRB_TT_DATA);
+
+ mrb_define_method(mrb, klass, "initialize",
+ mrb_grn_window_definition_initialize, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "close",
+ mrb_grn_window_definition_close, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "sort_keys=",
+ mrb_grn_window_definition_set_sort_keys, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "group_keys=",
+ mrb_grn_window_definition_set_group_keys, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.h
new file mode 100644
index 00000000..ea1b8ef6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_window_definition.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_window_definition_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.c b/storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.c
new file mode 100644
index 00000000..b2ca09f9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.c
@@ -0,0 +1,253 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_ctx_impl.h"
+
+#ifdef GRN_WITH_MRUBY
+#include <mruby.h>
+#include <mruby/data.h>
+#include <mruby/hash.h>
+#include <mruby/string.h>
+
+#include "../grn_mrb.h"
+#include "../grn_output.h"
+#include "mrb_ctx.h"
+#include "mrb_writer.h"
+#include "mrb_options.h"
+
+static mrb_value
+writer_write(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value target;
+
+ mrb_get_args(mrb, "o", &target);
+
+ switch (mrb_type(target)) {
+ case MRB_TT_FALSE :
+ if (mrb_nil_p(target)) {
+ GRN_OUTPUT_NULL();
+ } else {
+ GRN_OUTPUT_BOOL(GRN_FALSE);
+ }
+ break;
+ case MRB_TT_TRUE :
+ GRN_OUTPUT_BOOL(GRN_TRUE);
+ break;
+ case MRB_TT_FIXNUM :
+ GRN_OUTPUT_INT32(mrb_fixnum(target));
+ break;
+ case MRB_TT_FLOAT :
+ GRN_OUTPUT_FLOAT(mrb_float(target));
+ break;
+ case MRB_TT_SYMBOL :
+ {
+ const char *name;
+ mrb_int name_length;
+
+ name = mrb_sym2name_len(mrb, mrb_symbol(target), &name_length);
+ GRN_OUTPUT_STR(name, name_length);
+ }
+ break;
+ case MRB_TT_STRING :
+ GRN_OUTPUT_STR(RSTRING_PTR(target), RSTRING_LEN(target));
+ break;
+ default :
+ mrb_raisef(mrb, E_ARGUMENT_ERROR,
+ "must be nil, true, false, number, float, symbol or string: "
+ "%S",
+ target);
+ break;
+ }
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_open_array(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *name;
+ mrb_int n_elements;
+
+ mrb_get_args(mrb, "zi", &name, &n_elements);
+ GRN_OUTPUT_ARRAY_OPEN(name, n_elements);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_close_array(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ GRN_OUTPUT_ARRAY_CLOSE();
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_open_map(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ char *name;
+ mrb_int n_elements;
+
+ mrb_get_args(mrb, "zi", &name, &n_elements);
+ GRN_OUTPUT_MAP_OPEN(name, n_elements);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_close_map(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+
+ GRN_OUTPUT_MAP_CLOSE();
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_write_table_columns(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_table;
+ char *columns;
+ mrb_int columns_size;
+ grn_obj *table;
+ grn_obj_format format;
+ int n_hits = 0;
+ int offset = 0;
+ int limit = 0;
+ int hits_offset = 0;
+
+ mrb_get_args(mrb, "os", &mrb_table, &columns, &columns_size);
+
+ table = DATA_PTR(mrb_table);
+ GRN_OBJ_FORMAT_INIT(&format, n_hits, offset, limit, hits_offset);
+ format.flags |= GRN_OBJ_FORMAT_WITH_COLUMN_NAMES;
+ {
+ grn_rc rc;
+ rc = grn_output_format_set_columns(ctx, &format,
+ table, columns, columns_size);
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FORMAT_FIN(ctx, &format);
+ grn_mrb_ctx_check(mrb);
+ }
+ }
+ GRN_OUTPUT_TABLE_COLUMNS(table, &format);
+ GRN_OBJ_FORMAT_FIN(ctx, &format);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_write_table_records(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_value mrb_table;
+ mrb_value mrb_options = mrb_nil_value();
+ char *columns;
+ mrb_int columns_size;
+ grn_obj *table;
+ grn_obj_format format;
+ int n_hits = 0;
+ int offset = 0;
+ int limit = -1;
+ int hits_offset = 0;
+
+ mrb_get_args(mrb, "os|H", &mrb_table, &columns, &columns_size, &mrb_options);
+
+ table = DATA_PTR(mrb_table);
+ if (!mrb_nil_p(mrb_options)) {
+ mrb_value mrb_offset;
+ mrb_value mrb_limit;
+
+ mrb_offset = grn_mrb_options_get_lit(mrb, mrb_options, "offset");
+ if (!mrb_nil_p(mrb_offset)) {
+ offset = mrb_fixnum(mrb_offset);
+ }
+
+ mrb_limit = grn_mrb_options_get_lit(mrb, mrb_options, "limit");
+ if (!mrb_nil_p(mrb_limit)) {
+ limit = mrb_fixnum(mrb_limit);
+ }
+ }
+ if (limit < 0) {
+ limit = grn_table_size(ctx, table) + limit + 1;
+ }
+ GRN_OBJ_FORMAT_INIT(&format, n_hits, offset, limit, hits_offset);
+ {
+ grn_rc rc;
+ rc = grn_output_format_set_columns(ctx, &format,
+ table, columns, columns_size);
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FORMAT_FIN(ctx, &format);
+ grn_mrb_ctx_check(mrb);
+ }
+ }
+ GRN_OUTPUT_TABLE_RECORDS(table, &format);
+ GRN_OBJ_FORMAT_FIN(ctx, &format);
+
+ return mrb_nil_value();
+}
+
+static mrb_value
+writer_set_content_type(mrb_state *mrb, mrb_value self)
+{
+ grn_ctx *ctx = (grn_ctx *)mrb->ud;
+ mrb_int content_type;
+
+ mrb_get_args(mrb, "i", &content_type);
+
+ grn_ctx_set_output_type(ctx, content_type);
+
+ return mrb_nil_value();
+}
+
+void
+grn_mrb_writer_init(grn_ctx *ctx)
+{
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ struct RClass *module = data->module;
+ struct RClass *klass;
+
+ klass = mrb_define_class_under(mrb, module, "Writer", mrb->object_class);
+
+ mrb_define_method(mrb, klass, "write", writer_write, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, klass, "open_array",
+ writer_open_array, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, klass, "close_array",
+ writer_close_array, MRB_ARGS_NONE());
+ mrb_define_method(mrb, klass, "open_map",
+ writer_open_map, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, klass, "close_map",
+ writer_close_map, MRB_ARGS_NONE());
+
+ mrb_define_method(mrb, klass, "write_table_columns",
+ writer_write_table_columns, MRB_ARGS_REQ(2));
+ mrb_define_method(mrb, klass, "write_table_records",
+ writer_write_table_records, MRB_ARGS_ARG(2, 1));
+
+ mrb_define_method(mrb, klass, "content_type=",
+ writer_set_content_type, MRB_ARGS_REQ(1));
+}
+#endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.h b/storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.h
new file mode 100644
index 00000000..7b5b32d4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/mrb_writer.h
@@ -0,0 +1,32 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void grn_mrb_writer_init(grn_ctx *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/Makefile.am
new file mode 100644
index 00000000..835d881b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/Makefile.am
@@ -0,0 +1,16 @@
+SUBDIRS = \
+ command_line \
+ context \
+ expression_tree \
+ initialize \
+ logger \
+ query_logger
+
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/accessor.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/accessor.rb
new file mode 100644
index 00000000..3ae08fb6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/accessor.rb
@@ -0,0 +1,5 @@
+module Groonga
+ class Accessor
+ include Indexable
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/backtrace_entry.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/backtrace_entry.rb
new file mode 100644
index 00000000..34f95e96
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/backtrace_entry.rb
@@ -0,0 +1,28 @@
+module Groonga
+ class BacktraceEntry
+ class << self
+ def parse(entry)
+ match_data = /:(\d+):?/.match(entry)
+ file = match_data.pre_match
+ line = match_data[1].to_i
+ detail_match_data = /\A(in )?(\S+)\s*/.match(match_data.post_match)
+ if detail_match_data[1]
+ method = detail_match_data[2]
+ message = detail_match_data.post_match
+ else
+ method = ""
+ message = match_data.post_match
+ end
+ new(file, line, method, message)
+ end
+ end
+
+ attr_reader :file, :line, :method, :message
+ def initialize(file, line, method, message)
+ @file = file
+ @line = line
+ @method = method
+ @message = message
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/command.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command.rb
new file mode 100644
index 00000000..26dfe68c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command.rb
@@ -0,0 +1,64 @@
+module Groonga
+ class Command
+ @@classes = {}
+ class << self
+ def register_class(name, klass)
+ @@classes[name] = klass
+ end
+
+ def find_class(name)
+ @@classes[name]
+ end
+ end
+
+ private
+ def context
+ @context ||= Context.instance
+ end
+
+ def writer
+ @writer ||= context.writer
+ end
+
+ def query_logger
+ @query_logger ||= context.query_logger
+ end
+
+ def cache_key(input)
+ nil
+ end
+
+ def cache_output(key, options={})
+ if key.nil?
+ yield
+ else
+ cache = Cache.current
+ cached_value = cache.fetch(key)
+ if cached_value
+ context.output = cached_value
+ query_logger.log(:cache, ":", "cache(#{cached_value.bytesize})")
+ else
+ yield
+ cache.update(key, context.output) if options[:update]
+ end
+ end
+ end
+
+ def run_internal(input)
+ begin
+ options = {
+ :update => (input["cache"] != "no"),
+ }
+ cache_output(cache_key(input), options) do
+ run_body(input)
+ end
+ rescue GroongaError => groonga_error
+ context.set_groonga_error(groonga_error)
+ nil
+ rescue => error
+ context.record_error(:command_error, error)
+ nil
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_input.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_input.rb
new file mode 100644
index 00000000..779edb47
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_input.rb
@@ -0,0 +1,15 @@
+module Groonga
+ class CommandInput
+ include Enumerable
+
+ def each
+ args = arguments
+ arg = Record.new(args, nil)
+ args.each do |id|
+ arg.id = id
+ key = arg.key
+ yield(key, self[key])
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/Makefile.am
new file mode 100644
index 00000000..8d580810
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/Makefile.am
@@ -0,0 +1,9 @@
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_command_linedir = $(ruby_scriptsdir)/command_line
+ruby_scripts_command_line_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/grndb.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/grndb.rb
new file mode 100644
index 00000000..edd16d58
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/grndb.rb
@@ -0,0 +1,452 @@
+module Groonga
+ module CommandLine
+ class Grndb
+ def initialize(argv)
+ @program_path, *@arguments = argv
+ @succeeded = true
+ @database_path = nil
+ end
+
+ def run
+ command_line_parser = create_command_line_parser
+ options = nil
+ begin
+ options = command_line_parser.parse(@arguments)
+ rescue Slop::Error => error
+ $stderr.puts(error.message)
+ $stderr.puts
+ $stderr.puts(command_line_parser.help_message)
+ return false
+ end
+ @succeeded
+ end
+
+ private
+ def create_command_line_parser
+ program_name = File.basename(@program_path)
+ parser = CommandLineParser.new(program_name)
+
+ parser.add_command("check") do |command|
+ command.description = "Check database"
+
+ options = command.options
+ options.banner += " DB_PATH"
+ options.string("--target", "Check only the target object.")
+
+ command.add_action do |options|
+ open_database(command, options) do |database, rest_arguments|
+ check(database, options, rest_arguments)
+ end
+ end
+ end
+
+ parser.add_command("recover") do |command|
+ command.description = "Recover database"
+
+ options = command.options
+ options.banner += " DB_PATH"
+ options.boolean("--force-truncate", "Force to truncate corrupted objects.")
+
+ command.add_action do |options|
+ open_database(command, options) do |database, rest_arguments|
+ recover(database, options, rest_arguments)
+ end
+ end
+ end
+
+ parser
+ end
+
+ def open_database(command, options)
+ arguments = options.arguments
+ if arguments.empty?
+ $stderr.puts("Database path is missing")
+ $stderr.puts
+ $stderr.puts(command.help_message)
+ @succeesed = false
+ return
+ end
+
+ database = nil
+ @database_path, *rest_arguments = arguments
+ begin
+ database = Database.open(@database_path)
+ rescue Error => error
+ $stderr.puts("Failed to open database: <#{@database_path}>")
+ $stderr.puts(error.message)
+ @succeeded = false
+ return
+ end
+
+ begin
+ yield(database, rest_arguments)
+ ensure
+ database.close
+ end
+ end
+
+ def failed(*messages)
+ messages.each do |message|
+ $stderr.puts(message)
+ end
+ @succeeded = false
+ end
+
+ def recover(database, options, arguments)
+ recoverer = Recoverer.new
+ recoverer.database = database
+ recoverer.force_truncate = options[:force_truncate]
+ begin
+ recoverer.recover
+ rescue Error => error
+ failed("Failed to recover database: <#{@database_path}>",
+ error.message)
+ end
+ end
+
+ def check(database, options, arguments)
+ checker = Checker.new
+ checker.program_path = @program_path
+ checker.database_path = @database_path
+ checker.database = database
+ checker.on_failure = lambda do |message|
+ failed(message)
+ end
+
+ checker.check_database
+
+ target_name = options[:target]
+ if target_name
+ checker.check_one(target_name)
+ else
+ checker.check_all
+ end
+ end
+
+ class Checker
+ attr_writer :program_path
+ attr_writer :database_path
+ attr_writer :database
+ attr_writer :on_failure
+
+ def initialize
+ @context = Context.instance
+ @checked = {}
+ end
+
+ def check_database
+ check_database_orphan_inspect
+ check_database_locked
+ check_database_corrupt
+ check_database_dirty
+ end
+
+ def check_one(target_name)
+ target = @context[target_name]
+ if target.nil?
+ exist_p = open_database_cursor do |cursor|
+ cursor.any? do
+ cursor.key == target_name
+ end
+ end
+ if exist_p
+ failed_to_open(target_name)
+ else
+ message = "[#{target_name}] Not exist."
+ failed(message)
+ end
+ return
+ end
+
+ check_object_recursive(target)
+ end
+
+ def check_all
+ open_database_cursor do |cursor|
+ cursor.each do |id|
+ next if ID.builtin?(id)
+ next if builtin_object_name?(cursor.key)
+ next if @context[id]
+ failed_to_open(cursor.key)
+ end
+ end
+
+ @database.each do |object|
+ check_object(object)
+ end
+ end
+
+ private
+ def check_database_orphan_inspect
+ open_database_cursor do |cursor|
+ cursor.each do |id|
+ if cursor.key == "inspect" and @context[id].nil?
+ message =
+ "Database has orphan 'inspect' object. " +
+ "Remove it by '#{@program_path} recover #{@database_path}'."
+ failed(message)
+ break
+ end
+ end
+ end
+ end
+
+ def check_database_locked
+ return unless @database.locked?
+
+ message =
+ "Database is locked. " +
+ "It may be broken. " +
+ "Re-create the database."
+ failed(message)
+ end
+
+ def check_database_corrupt
+ return unless @database.corrupt?
+
+ message =
+ "Database is corrupt. " +
+ "Re-create the database."
+ failed(message)
+ end
+
+ def check_database_dirty
+ return unless @database.dirty?
+
+ last_modified = @database.last_modified
+ if File.stat(@database.path).mtime > last_modified
+ return
+ end
+
+ open_database_cursor do |cursor|
+ cursor.each do |id|
+ next if ID.builtin?(id)
+ path = "%s.%07x" % [@database.path, id]
+ next unless File.exist?(path)
+ return if File.stat(path).mtime > last_modified
+ end
+ end
+
+ message =
+ "Database wasn't closed successfully. " +
+ "It may be broken. " +
+ "Re-create the database."
+ failed(message)
+ end
+
+ def check_object(object)
+ return if @checked.key?(object.id)
+ @checked[object.id] = true
+
+ check_object_locked(object)
+ check_object_corrupt(object)
+ end
+
+ def check_object_locked(object)
+ case object
+ when IndexColumn
+ return unless object.locked?
+ message =
+ "[#{object.name}] Index column is locked. " +
+ "It may be broken. " +
+ "Re-create index by '#{@program_path} recover #{@database_path}'."
+ failed(message)
+ when Column
+ return unless object.locked?
+ name = object.name
+ message =
+ "[#{name}] Data column is locked. " +
+ "It may be broken. " +
+ "(1) Truncate the column (truncate #{name}) or " +
+ "clear lock of the column (lock_clear #{name}) " +
+ "and (2) load data again."
+ failed(message)
+ when Table
+ return unless object.locked?
+ name = object.name
+ message =
+ "[#{name}] Table is locked. " +
+ "It may be broken. " +
+ "(1) Truncate the table (truncate #{name}) or " +
+ "clear lock of the table (lock_clear #{name}) " +
+ "and (2) load data again."
+ failed(message)
+ end
+ end
+
+ def check_object_corrupt(object)
+ case object
+ when IndexColumn
+ return unless object.corrupt?
+ message =
+ "[#{object.name}] Index column is corrupt. " +
+ "Re-create index by '#{@program_path} recover #{@database_path}'."
+ failed(message)
+ when Column
+ return unless object.corrupt?
+ name = object.name
+ message =
+ "[#{name}] Data column is corrupt. " +
+ "(1) Truncate the column (truncate #{name} or " +
+ "'#{@program_path} recover --force-truncate #{@database_path}') " +
+ "and (2) load data again."
+ failed(message)
+ when Table
+ return unless object.corrupt?
+ name = object.name
+ message =
+ "[#{name}] Table is corrupt. " +
+ "(1) Truncate the table (truncate #{name} or " +
+ "'#{@program_path} recover --force-truncate #{@database_path}') " +
+ "and (2) load data again."
+ failed(message)
+ end
+ end
+
+ def check_object_recursive(target)
+ return if @checked.key?(target.id)
+
+ check_object(target)
+ case target
+ when Table
+ unless target.is_a?(Groonga::Array)
+ domain_id = target.domain_id
+ domain = @context[domain_id]
+ if domain.nil?
+ record = Record.new(@database, domain_id)
+ failed_to_open(record.key)
+ elsif domain.is_a?(Table)
+ check_object_recursive(domain)
+ end
+ end
+
+ target.column_ids.each do |column_id|
+ column = @context[column_id]
+ if column.nil?
+ record = Record.new(@database, column_id)
+ failed_to_open(record.key)
+ else
+ check_object_recursive(column)
+ end
+ end
+ when FixedSizeColumn, VariableSizeColumn
+ range_id = target.range_id
+ range = @context[range_id]
+ if range.nil?
+ record = Record.new(@database, range_id)
+ failed_to_open(record.key)
+ elsif range.is_a?(Table)
+ check_object_recursive(range)
+ end
+
+ lexicon_ids = []
+ target.indexes.each do |index_info|
+ index = index_info.index
+ lexicon_ids << index.domain_id
+ check_object(index)
+ end
+ lexicon_ids.uniq.each do |lexicon_id|
+ lexicon = @context[lexicon_id]
+ if lexicon.nil?
+ record = Record.new(@database, lexicon_id)
+ failed_to_open(record.key)
+ else
+ check_object(lexicon)
+ end
+ end
+ when IndexColumn
+ range_id = target.range_id
+ range = @context[range_id]
+ if range.nil?
+ record = Record.new(@database, range_id)
+ failed_to_open(record.key)
+ return
+ end
+ check_object(range)
+
+ target.source_ids.each do |source_id|
+ source = @context[source_id]
+ if source.nil?
+ record = Record.new(database, source_id)
+ failed_to_open(record.key)
+ elsif source.is_a?(Column)
+ check_object_recursive(source)
+ end
+ end
+ end
+ end
+
+ def open_database_cursor(&block)
+ flags =
+ TableCursorFlags::ASCENDING |
+ TableCursorFlags::BY_ID
+ TableCursor.open(@database, :flags => flags, &block)
+ end
+
+ def builtin_object_name?(name)
+ case name
+ when "inspect"
+ # Just for compatibility. It's needed for users who used
+ # Groonga master at between 2016-02-03 and 2016-02-26.
+ true
+ else
+ false
+ end
+ end
+
+ def failed(message)
+ @on_failure.call(message)
+ end
+
+ def failed_to_open(name)
+ message =
+ "[#{name}] Can't open object. " +
+ "It's broken. " +
+ "Re-create the object or the database."
+ failed(message)
+ end
+ end
+
+ class Recoverer
+ attr_writer :database
+ attr_writer :force_truncate
+
+ def initialize
+ @context = Context.instance
+ end
+
+ def recover
+ if @force_truncate
+ truncate_corrupt_objects
+ end
+ @database.recover
+ end
+
+ def truncate_corrupt_objects
+ @database.each do |object|
+ next unless object.corrupt?
+ logger = @context.logger
+ object_path = object.path
+ object_dirname = File.dirname(object_path)
+ object_basename = File.basename(object_path)
+ object.truncate
+ Dir.foreach(object_dirname) do |path|
+ if path.start_with?("#{object_basename}.")
+ begin
+ File.unlink("#{object_dirname}/#{path}")
+ message = "Corrupted <#{object_path}> related file is removed: <#{path}>"
+ $stdout.puts(message)
+ logger.log(Logger::Level::INFO.to_i, __FILE__, __LINE__, "truncate_corrupt_objects", message)
+ rescue Error => error
+ message = "Failed to remove file which is related to corrupted <#{object_path}>: <#{path}>"
+ $stderr.puts(message)
+ logger.log_error(message)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/sources.am
new file mode 100644
index 00000000..759948ee
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line/sources.am
@@ -0,0 +1,2 @@
+RUBY_SCRIPT_FILES = \
+ grndb.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line_parser.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line_parser.rb
new file mode 100644
index 00000000..7dad55a7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/command_line_parser.rb
@@ -0,0 +1,168 @@
+module Slop
+ class MissingCommand < Error
+ end
+
+ class UnknownCommand < Error
+ attr_reader :name
+
+ def initialize(msg, name)
+ super(msg)
+ @name = name
+ end
+ end
+end
+
+module Groonga
+ class CommandLineParser
+ def initialize(program_name=nil)
+ $0 ||= nil
+ @program_name = program_name || $0
+ @commands = []
+ @action_runner = ActionRunner.new
+ @options = Slop::Options.new
+ setup_options
+ end
+
+ def options
+ yield(@options) if block_given?
+ @options
+ end
+
+ def add_command(name)
+ command = Command.new(@program_name, name)
+ setup_common_options(command.options)
+ yield(command)
+ @commands << command
+ end
+
+ def add_action(&action)
+ @action_runner.add(&action)
+ end
+
+ def parse(command_line)
+ if @commands.empty?
+ result = @options.parse(command_line)
+ apply_actions(result)
+ return result
+ end
+
+ if command_line.empty?
+ message = "Command is missing"
+ raise Slop::MissingCommand.new(message)
+ end
+
+ first_argument = command_line.first
+ if first_argument.start_with?("-")
+ result = @options.parse(command_line)
+ apply_actions(result)
+ return result
+ end
+
+ command_name = first_argument
+ command = find_command(command_name)
+ if command.nil?
+ message = "Unknown command: <#{command_name}>"
+ raise Slop::UnknownCommand.new(message, command_name)
+ end
+
+ command.parse(command_line[1..-1])
+ end
+
+ def help_message
+ message = @options.to_s
+ @commands.each do |command|
+ message << "\n"
+ indent = " " * 4
+ message << "#{command.description}:\n" if command.description
+ message << "#{indent}#{command.options.banner}\n"
+ end
+ message
+ end
+
+ private
+ def setup_options
+ @options.banner = "Usage: #{@program_name} [OPTIONS]"
+ setup_common_options(@options)
+ @options.on("-h", "--help", "Display this help message.",
+ :tail => true) do
+ $stdout.puts(help_message)
+ end
+ end
+
+ def setup_common_options(options)
+ options.string("--log-path",
+ "Change log path (#{Logger.default_path})",
+ default: Logger.default_path)
+ default_log_level = Logger.default_level
+ options.string("--log-level",
+ "Change log level (#{default_log_level.name})",
+ default: default_log_level)
+ end
+
+ def find_command(name)
+ @commands.find do |command|
+ command.name == name
+ end
+ end
+
+ def apply_actions(result)
+ @action_runner.run(result) unless result.help?
+ end
+
+ class ActionRunner
+ def initialize
+ @actions = []
+ end
+
+ def add(&action)
+ @actions << action
+ end
+
+ def run(*args)
+ @actions.each do |action|
+ action.call(*args)
+ end
+ end
+ end
+
+ class Command
+ attr_reader :name
+ attr_reader :options
+ attr_accessor :description
+ def initialize(program_name, name)
+ @program_name = program_name
+ @name = name
+ @options = Slop::Options.new
+ setup_options
+ @description = nil
+ @action_runner = ActionRunner.new
+ end
+
+ def add_action(&action)
+ @action_runner.add(&action)
+ end
+
+ def parse(command_line)
+ result = @options.parse(command_line)
+ @action_runner.run(result) unless result.help?
+ result
+ end
+
+ def help_message
+ message = ""
+ message << "Description: #{@description}\n" if @description
+ message << @options.to_s
+ message
+ end
+
+ private
+ def setup_options
+ @options.banner = "Usage: #{@program_name} #{@name} [OPTIONS]"
+ @options.on("-h", "--help", "Display this help message.",
+ :tail => true) do
+ $stdout.puts(help_message)
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/context.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context.rb
new file mode 100644
index 00000000..b6f59dc3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context.rb
@@ -0,0 +1,85 @@
+require "context/error_level"
+require "context/rc"
+
+module Groonga
+ class Context
+ def guard(fallback=nil)
+ begin
+ yield
+ rescue => error
+ logger.log_error(error)
+ fallback
+ end
+ end
+
+ def logger
+ @logger ||= Logger.new
+ end
+
+ def query_logger
+ @query_logger ||= QueryLogger.new
+ end
+
+ def writer
+ @writer ||= Writer.new
+ end
+
+ def set_groonga_error(groonga_error)
+ set_error_raw(groonga_error.class.rc,
+ ErrorLevel::ERROR,
+ groonga_error.message,
+ groonga_error.backtrace)
+ end
+
+ def record_error(rc, error)
+ rc = RC.find(rc) if rc.is_a?(Symbol)
+ set_error_raw(rc, ErrorLevel::ERROR, error.message, error.backtrace)
+
+ logger.log_error(error)
+ end
+
+ def with_command_version(version)
+ old_version = command_version
+ begin
+ self.command_version = version
+ yield
+ ensure
+ self.command_version = old_version
+ end
+ end
+
+ def open_temporary(id)
+ if Thread.limit == 1
+ need_close = !opened?(id)
+ else
+ need_close = false
+ end
+ object = self[id]
+ begin
+ yield(object)
+ ensure
+ if need_close and object and !object.closed?
+ case object
+ when Table, Column
+ object.close
+ end
+ end
+ end
+ end
+
+ private
+ def set_error_raw(rc, error_level, message, backtrace)
+ self.rc = rc.to_i
+ self.error_level = error_level.to_i
+
+ self.error_message = message
+
+ if backtrace
+ entry = BacktraceEntry.parse(backtrace.first)
+ self.error_file = entry.file
+ self.error_line = entry.line
+ self.error_method = entry.method
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/Makefile.am
new file mode 100644
index 00000000..8d862082
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/Makefile.am
@@ -0,0 +1,9 @@
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_contextdir = $(ruby_scriptsdir)/context
+ruby_scripts_context_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/error_level.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/error_level.rb
new file mode 100644
index 00000000..c0685f16
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/error_level.rb
@@ -0,0 +1,30 @@
+module Groonga
+ class Context
+ class ErrorLevel
+ @@names = {}
+
+ class << self
+ def find(name)
+ @@names[name]
+ end
+ end
+
+ attr_reader :name
+ def initialize(name, level)
+ @@names[name] = self
+ @name = name
+ @level = level
+ end
+
+ def to_i
+ @level
+ end
+
+ EMERGENCY = new(:emergency, 1)
+ ALERT = new(:alert, 2)
+ CRITICAL = new(:critical, 3)
+ ERROR = new(:error, 4)
+ WARNING = new(:warning, 5)
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/rc.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/rc.rb
new file mode 100644
index 00000000..45187c22
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/rc.rb
@@ -0,0 +1,205 @@
+module Groonga
+ class Context
+ class RC
+ @@codes = {}
+ @@names = {}
+
+ class << self
+ def find(name_or_code)
+ if name_or_code.is_a?(Symbol)
+ @@names[name_or_code] || UNKNOWN_ERROR
+ else
+ @@codes[name_or_code] || UNKNOWN_ERROR
+ end
+ end
+
+ def register(name, code, error_class)
+ rc = new(name, code, error_class)
+ @@codes[code] = rc
+ @@names[name] = rc
+ error_class.rc = rc if error_class
+ rc
+ end
+ end
+
+ attr_reader :name
+ attr_reader :error_class
+ def initialize(name, code, error_class)
+ @name = name
+ @code = code
+ @error_class = error_class
+ end
+
+ def to_i
+ @code
+ end
+
+ SUCCESS =
+ register(:success, 0, nil)
+ END_OF_DATA =
+ register(:end_of_data, 1, EndOfData)
+ UNKNOWN_ERROR =
+ register(:unknown_error, -1, UnknownError)
+ OPERATION_NOT_PERMITTED =
+ register(:operation_not_permitted, -2, OperationNotPermitted)
+ NO_SUCH_FILE_OR_DIRECTORY =
+ register(:no_such_file_or_directory, -3, NoSuchFileOrDirectory)
+ NO_SUCH_PROCESS =
+ register(:no_such_process, -4, NoSuchProcess)
+ INTERRUPTED_FUNCTION_CALL =
+ register(:interrupted_function_call, -5, InterruptedFunctionCall)
+ INPUT_OUTPUT_ERROR =
+ register(:input_output_error, -6, InputOutputError)
+ NO_SUCH_DEVICE_OR_ADDRESS =
+ register(:no_such_device_or_address, -7, NoSuchDeviceOrAddress)
+ ARG_LIST_TOO_LONG =
+ register(:arg_list_too_long, -8, ArgListTooLong)
+ EXEC_FORMAT_ERROR =
+ register(:exec_format_error, -9, ExecFormatError)
+ BAD_FILE_DESCRIPTOR =
+ register(:bad_file_descriptor, -10, BadFileDescriptor)
+ NO_CHILD_PROCESSES =
+ register(:no_child_processes, -11, NoChildProcesses)
+ RESOURCE_TEMPORARILY_UNAVAILABLE =
+ register(:resource_temporarily_unavailable, -12,
+ ResourceTemporarilyUnavailable)
+ NOT_ENOUGH_SPACE =
+ register(:not_enough_space, -13, NotEnoughSpace)
+ PERMISSION_DENIED =
+ register(:permission_denied, -14, PermissionDenied)
+ BAD_ADDRESS =
+ register(:bad_address, -15, BadAddress)
+ RESOURCE_BUSY =
+ register(:resource_busy, -16, ResourceBusy)
+ FILE_EXISTS =
+ register(:file_exists, -17, FileExists)
+ IMPROPER_LINK =
+ register(:improper_link, -18, ImproperLink)
+ NO_SUCH_DEVICE =
+ register(:no_such_device, -19, NoSuchDevice)
+ NOT_DIRECTORY =
+ register(:not_directory, -20, NotDirectory)
+ IS_DIRECTORY =
+ register(:is_directory, -21, IsDirectory)
+ INVALID_ARGUMENT =
+ register(:invalid_argument, -22, InvalidArgument)
+ TOO_MANY_OPEN_FILES_IN_SYSTEM =
+ register(:too_many_open_files_in_system, -23, TooManyOpenFilesInSystem)
+ TOO_MANY_OPEN_FILES =
+ register(:too_many_open_files, -24, TooManyOpenFiles)
+ INAPPROPRIATE_IO_CONTROL_OPERATION =
+ register(:inappropriate_io_control_operation, -25,
+ InappropriateIOControlOperation)
+ FILE_TOO_LARGE =
+ register(:file_too_large, -26, FileTooLarge)
+ NO_SPACE_LEFT_ON_DEVICE =
+ register(:no_space_left_on_device, -27, NoSpaceLeftOnDevice)
+ INVALID_SEEK =
+ register(:invalid_seek, -28, InvalidSeek)
+ READ_ONLY_FILE_SYSTEM =
+ register(:read_only_file_system, -29, ReadOnlyFileSystem)
+ TOO_MANY_LINKS =
+ register(:too_many_links, -30, TooManyLinks)
+ BROKEN_PIPE =
+ register(:broken_pipe, -31, BrokenPipe)
+ DOMAIN_ERROR =
+ register(:domain_error, -32, DomainError)
+ RESULT_TOO_LARGE =
+ register(:result_too_large, -33, ResultTooLarge)
+ RESOURCE_DEADLOCK_AVOIDED =
+ register(:resource_deadlock_avoided, -34, ResourceDeadlockAvoided)
+ NO_MEMORY_AVAILABLE =
+ register(:no_memory_available, -35, NoMemoryAvailable)
+ FILENAME_TOO_LONG =
+ register(:filename_too_long, -36, FilenameTooLong)
+ NO_LOCKS_AVAILABLE =
+ register(:no_locks_available, -37, NoLocksAvailable)
+ FUNCTION_NOT_IMPLEMENTED =
+ register(:function_not_implemented, -38, FunctionNotImplemented)
+ DIRECTORY_NOT_EMPTY =
+ register(:directory_not_empty, -39, DirectoryNotEmpty)
+ ILLEGAL_BYTE_SEQUENCE =
+ register(:illegal_byte_sequence, -40, IllegalByteSequence)
+ SOCKET_NOT_INITIALIZED =
+ register(:socket_not_initialized, -41, SocketNotInitialized)
+ OPERATION_WOULD_BLOCK =
+ register(:operation_would_block, -42, OperationWouldBlock)
+ ADDRESS_IS_NOT_AVAILABLE =
+ register(:address_is_not_available, -43, AddressIsNotAvailable)
+ NETWORK_IS_DOWN =
+ register(:network_is_down, -44, NetworkIsDown)
+ NO_BUFFER =
+ register(:no_buffer, -45, NoBuffer)
+ SOCKET_IS_ALREADY_CONNECTED =
+ register(:socket_is_already_connected, -46, SocketIsAlreadyConnected)
+ SOCKET_IS_NOT_CONNECTED =
+ register(:socket_is_not_connected, -47, SocketIsNotConnected)
+ SOCKET_IS_ALREADY_SHUTDOWNED =
+ register(:socket_is_already_shutdowned, -48, SocketIsAlreadyShutdowned)
+ OPERATION_TIMEOUT =
+ register(:operation_timeout, -49, OperationTimeout)
+ CONNECTION_REFUSED =
+ register(:connection_refused, -50, ConnectionRefused)
+ RANGE_ERROR =
+ register(:range_error, -51, RangeError)
+ TOKENIZER_ERROR =
+ register(:tokenizer_error, -52, TokenizerError)
+ FILE_CORRUPT =
+ register(:file_corrupt, -53, FileCorrupt)
+ INVALID_FORMAT =
+ register(:invalid_format, -54, InvalidFormat)
+ OBJECT_CORRUPT =
+ register(:object_corrupt, -55, ObjectCorrupt)
+ TOO_MANY_SYMBOLIC_LINKS =
+ register(:too_many_symbolic_links, -56, TooManySymbolicLinks)
+ NOT_SOCKET =
+ register(:not_socket, -57, NotSocket)
+ OPERATION_NOT_SUPPORTED =
+ register(:operation_not_supported, -58, OperationNotSupported)
+ ADDRESS_IS_IN_USE =
+ register(:address_is_in_use, -59, AddressIsInUse)
+ ZLIB_ERROR =
+ register(:zlib_error, -60, ZlibError)
+ LZ4_ERROR =
+ register(:lz4_error, -61, LZ4Error)
+ STACK_OVER_FLOW =
+ register(:stack_over_flow, -62, StackOverFlow)
+ SYNTAX_ERROR =
+ register(:syntax_error, -63, SyntaxError)
+ RETRY_MAX =
+ register(:retry_max, -64, RetryMax)
+ INCOMPATIBLE_FILE_FORMAT =
+ register(:incompatible_file_format, -65, IncompatibleFileFormat)
+ UPDATE_NOT_ALLOWED =
+ register(:update_not_allowed, -66, UpdateNotAllowed)
+ TOO_SMALL_OFFSET =
+ register(:too_small_offset, -67, TooSmallOffset)
+ TOO_LARGE_OFFSET =
+ register(:too_large_offset, -68, TooLargeOffset)
+ TOO_SMALL_LIMIT =
+ register(:too_small_limit, -69, TooSmallLimit)
+ CAS_ERROR =
+ register(:cas_error, -70, CASError)
+ UNSUPPORTED_COMMAND_VERSION =
+ register(:unsupported_command_version, -71, UnsupportedCommandVersion)
+ NORMALIZER_ERROR =
+ register(:normalizer_error, -72, NormalizerError)
+ TOKEN_FILTER_ERROR =
+ register(:token_filter_error, -73, TokenFilterError)
+ COMMAND_ERROR =
+ register(:command_error, -74, CommandError)
+ PLUGIN_ERROR =
+ register(:plugin_error, -75, PluginError)
+ SCORER_ERROR =
+ register(:scorer_error, -76, ScorerError)
+ CANCEL =
+ register(:cancel, -77, Cancel)
+ WINDOW_FUNCTION_ERROR =
+ register(:window_function_error, -78, WindowFunctionError)
+ ZSTD_ERROR =
+ register(:zstd_error, -79, ZstdError)
+
+ GroongaError.rc = UNKNOWN_ERROR
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/sources.am
new file mode 100644
index 00000000..1f0d1624
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/context/sources.am
@@ -0,0 +1,3 @@
+RUBY_SCRIPT_FILES = \
+ error_level.rb \
+ rc.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/database.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/database.rb
new file mode 100644
index 00000000..e0c6b4a0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/database.rb
@@ -0,0 +1,65 @@
+module Groonga
+ class Database
+ def each_raw(options=nil)
+ return to_enum(__method__, options) unless block_given?
+
+ if options
+ min = options[:prefix]
+ order = options[:order]
+ order_by = options[:order_by]
+ else
+ min = nil
+ order = :ascending
+ order_by = :id
+ end
+ flags = 0
+
+ if order == :descending
+ flags |= TableCursorFlags::DESCENDING
+ else
+ flags |= TableCursorFlags::ASCENDING
+ end
+ if order_by == :id
+ flags |= TableCursorFlags::BY_ID
+ else
+ flags |= TableCursorFlags::BY_KEY
+ end
+ flags |= TableCursorFlags::PREFIX if min
+ TableCursor.open(self, :min => min, :flags => flags) do |cursor|
+ cursor.each do |id|
+ yield(id, cursor)
+ end
+ end
+ end
+
+ def each(options=nil)
+ return to_enum(__method__, options) unless block_given?
+
+ context = Context.instance
+ each_raw(options) do |id, cursor|
+ object = context[id]
+ yield(object) if object
+ end
+ end
+
+ def each_name(options=nil)
+ return to_enum(__method__, options) unless block_given?
+
+ each_raw(options) do |id, cursor|
+ name = cursor.key
+ yield(name)
+ end
+ end
+
+ def each_table(options={})
+ return to_enum(__method__, options) unless block_given?
+
+ context = Context.instance
+ each_name(options) do |name|
+ next if name.include?(".")
+ object = context[name]
+ yield(object) if object.is_a?(Table)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/error.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/error.rb
new file mode 100644
index 00000000..e39c9045
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/error.rb
@@ -0,0 +1,16 @@
+module Groonga
+ class GroongaError
+ class << self
+ def rc
+ @rc
+ end
+
+ def rc=(rc)
+ @rc = rc
+ end
+ end
+ end
+
+ class ErrorMessage < Error
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/eval_context.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/eval_context.rb
new file mode 100644
index 00000000..05c7ee8d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/eval_context.rb
@@ -0,0 +1,18 @@
+module Groonga
+ class EvalContext
+ def eval(script)
+ proc = compile(script)
+ instance_eval(&proc)
+ end
+
+ def method_missing(id, *args, &block)
+ return super unless args.empty?
+ return super if block_given?
+
+ object = Context.instance[id.to_s]
+ return super if object.nil?
+
+ object
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression.rb
new file mode 100644
index 00000000..27dadcb7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression.rb
@@ -0,0 +1,68 @@
+require "expression_rewriter"
+require "expression_rewriters"
+
+require "expression_tree_builder"
+
+require "scan_info"
+require "scan_info_builder"
+
+require "scan_info_data_size_estimator"
+require "expression_size_estimator"
+
+module Groonga
+ class Expression
+ def rewrite
+ rewritten = nil
+ begin
+ return nil unless ExpressionRewriters.enabled?
+ source = self
+ ExpressionRewriters.classes.each do |rewriter_class|
+ rewriter = rewriter_class.new(source)
+ new_rewritten = rewriter.rewrite
+ if new_rewritten
+ rewritten.close if rewritten
+ rewritten = new_rewritten
+ source = rewritten
+ end
+ end
+ rescue GroongaError => groonga_error
+ context.set_groonga_error(groonga_error)
+ rewritten.close if rewritten
+ rewritten = nil
+ rescue => error
+ context.record_error(:invalid_argument, error)
+ rewritten.close if rewritten
+ rewritten = nil
+ end
+ rewritten
+ end
+
+ def build_scan_info(op, record_exist)
+ begin
+ builder = ScanInfoBuilder.new(self, op, record_exist)
+ builder.build
+ rescue => error
+ context.record_error(:invalid_argument, error)
+ nil
+ end
+ end
+
+ def estimate_size(table)
+ begin
+ estimator = ExpressionSizeEstimator.new(self, table)
+ estimator.estimate
+ rescue GroongaError => groonga_error
+ context.set_groonga_error(groonga_error)
+ table.size
+ rescue => error
+ context.record_error(:unknown_error, error)
+ table.size
+ end
+ end
+
+ private
+ def context
+ @context ||= Context.instance
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriter.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriter.rb
new file mode 100644
index 00000000..8f56ca7c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriter.rb
@@ -0,0 +1,22 @@
+module Groonga
+ class ExpressionRewriter
+ class << self
+ def register(name)
+ ExpressionRewriters.register(name, self)
+ end
+ end
+
+ def initialize(expression)
+ @expression = expression
+ end
+
+ def rewrite
+ nil
+ end
+
+ private
+ def context
+ @context ||= Context.instance
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriters.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriters.rb
new file mode 100644
index 00000000..ae773541
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_rewriters.rb
@@ -0,0 +1,41 @@
+module Groonga
+ module ExpressionRewriters
+ @rewriters = {}
+
+ class << self
+ def register(name, rewriter_class)
+ @rewriters[name] = rewriter_class
+ end
+
+ def enabled?
+ rewriters_table_name =
+ Config["expression_rewriter.table"] || "expression_rewriters"
+ rewriters_table = Context.instance[rewriters_table_name]
+ return false if rewriters_table.nil?
+ return false if rewriters_table.empty?
+
+ true
+ end
+
+ def classes
+ rewriters_table_name =
+ Config["expression_rewriter.table"] || "expression_rewriters"
+ rewriters_table = Context.instance[rewriters_table_name]
+ return [] if rewriters_table.nil?
+
+ rewriters_table.collect do |id|
+ record = Record.new(rewriters_table, id)
+ name = record.key
+ rewriter = @rewriters[name]
+ if rewriter.nil?
+ plugin_name = record.plugin_name.value
+ require plugin_name
+ rewriter = @rewriters[name]
+ raise "unknown rewriter: <#{name}>:<#{plugin_name}>" if rewriter.nil?
+ end
+ rewriter
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb
new file mode 100644
index 00000000..597b56f9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_size_estimator.rb
@@ -0,0 +1,54 @@
+module Groonga
+ class ExpressionSizeEstimator
+ def initialize(expression, table)
+ @expression = expression
+ @table = table
+ @table_size = @table.size
+ end
+
+ def estimate
+ builder = ScanInfoBuilder.new(@expression, Operator::OR, false)
+ data_list = builder.build
+ return @table_size if data_list.nil?
+
+ current_size = 0
+ sizes = []
+ data_list.each do |data|
+ if (data.flags & ScanInfo::Flags::POP) != 0
+ size = sizes.pop
+ case data.logical_op
+ when Operator::AND, Operator::AND_NOT
+ current_size = size if size < current_size
+ when Operator::OR
+ current_size = size if size > current_size
+ else
+ message = "invalid logical operator: <#{data.logical_op.inspect}>"
+ raise InvalidArgument, message
+ end
+ else
+ if (data.flags & ScanInfo::Flags::PUSH) != 0
+ sizes.push(current_size)
+ current_size = 0
+ end
+
+ estimator = ScanInfoDataSizeEstimator.new(data, @table)
+ size = estimator.estimate
+ case data.logical_op
+ when Operator::AND
+ current_size = size if size < current_size
+ when Operator::AND_NOT
+ size = @table_size - size
+ size = 0 if size < 0
+ current_size = size if size < current_size
+ when Operator::OR
+ current_size = size if size > current_size
+ else
+ message = "invalid logical operator: <#{data.logical_op.inspect}>"
+ raise InvalidArgument, message
+ end
+ end
+ end
+ current_size
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree.rb
new file mode 100644
index 00000000..124ace0e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree.rb
@@ -0,0 +1,9 @@
+require "expression_tree/accessor"
+require "expression_tree/constant"
+require "expression_tree/binary_operation"
+require "expression_tree/function_call"
+require "expression_tree/index_column"
+require "expression_tree/logical_operation"
+require "expression_tree/options"
+require "expression_tree/procedure"
+require "expression_tree/variable"
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/Makefile.am
new file mode 100644
index 00000000..1235932f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/Makefile.am
@@ -0,0 +1,9 @@
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_expression_treedir = $(ruby_scriptsdir)/expression_tree
+ruby_scripts_expression_tree_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/accessor.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/accessor.rb
new file mode 100644
index 00000000..ac4b122f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/accessor.rb
@@ -0,0 +1,14 @@
+module Groonga
+ module ExpressionTree
+ class Accessor
+ attr_reader :object
+ def initialize(object)
+ @object = object
+ end
+
+ def build(expression)
+ expression.append_object(@object, Operator::PUSH, 1)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/binary_operation.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/binary_operation.rb
new file mode 100644
index 00000000..d59c65c7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/binary_operation.rb
@@ -0,0 +1,67 @@
+module Groonga
+ module ExpressionTree
+ class BinaryOperation
+ attr_reader :operator
+ attr_reader :left
+ attr_reader :right
+ def initialize(operator, left, right)
+ @operator = operator
+ @left = left
+ @right = right
+ end
+
+ def build(expression)
+ @left.build(expression)
+ @right.build(expression)
+ expression.append_operator(@operator, 2)
+ end
+
+ RANGE_OPERATORS = [
+ Operator::LESS,
+ Operator::GREATER,
+ Operator::LESS_EQUAL,
+ Operator::GREATER_EQUAL,
+ ]
+ def estimate_size(table)
+ case @operator
+ when *RANGE_OPERATORS
+ estimate_size_range(table)
+ else
+ table.size
+ end
+ end
+
+ private
+ def estimate_size_range(table)
+ return table.size unless @left.is_a?(Variable)
+ return table.size unless @right.is_a?(Constant)
+
+ column = @left.column
+ value = @right.value
+ index_info = column.find_index(@operator)
+ return table.size if index_info.nil?
+
+ index_column = index_info.index
+ lexicon = index_column.lexicon
+ options = {}
+ case @operator
+ when Operator::LESS
+ options[:max] = value
+ options[:flags] = TableCursorFlags::LT
+ when Operator::LESS_EQUAL
+ options[:max] = value
+ options[:flags] = TableCursorFlags::LE
+ when Operator::GREATER
+ options[:min] = value
+ options[:flags] = TableCursorFlags::GT
+ when Operator::GREATER_EQUAL
+ options[:min] = value
+ options[:flags] = TableCursorFlags::GE
+ end
+ TableCursor.open(lexicon, options) do |cursor|
+ index_column.estimate_size(:lexicon_cursor => cursor)
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/constant.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/constant.rb
new file mode 100644
index 00000000..228a1fc8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/constant.rb
@@ -0,0 +1,22 @@
+module Groonga
+ module ExpressionTree
+ class Constant
+ attr_reader :value
+ def initialize(value)
+ @value = value
+ end
+
+ def build(expression)
+ expression.append_constant(@value, Operator::PUSH, 1)
+ end
+
+ def estimate_size(table)
+ if Bulk.true?(@value)
+ table.size
+ else
+ 0
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/function_call.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/function_call.rb
new file mode 100644
index 00000000..0c7438d6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/function_call.rb
@@ -0,0 +1,66 @@
+module Groonga
+ module ExpressionTree
+ class FunctionCall
+ attr_reader :procedure
+ attr_reader :arguments
+ def initialize(procedure, arguments)
+ @procedure = procedure
+ @arguments = arguments
+ end
+
+ def build(expression)
+ @procedure.build(expression)
+ @arguments.each do |argument|
+ argument.build(expression)
+ end
+ expression.append_operator(Operator::CALL, @arguments.size)
+ end
+
+ def estimate_size(table)
+ return table.size unless @procedure.name == "between"
+
+ column, min, min_border, max, max_border = @arguments
+
+ if column.is_a?(Groonga::ExpressionTree::IndexColumn)
+ index_column = column.object
+ else
+ index_info = column.column.find_index(Operator::CALL)
+ return table.size if index_info.nil?
+ index_column = index_info.index
+ end
+
+ while index_column.is_a?(Groonga::Accessor)
+ if index_column.have_next?
+ index_column = index_column.next
+ else
+ index_column = index_column.object
+ index_info = index_column.find_index(Operator::CALL)
+ return table.size if index_info.nil?
+ index_column = index_info.index
+ end
+ end
+
+ lexicon = index_column.lexicon
+ options = {
+ :min => min.value,
+ :max => max.value,
+ :flags => 0,
+ }
+ if min_border.value == "include"
+ options[:flags] |= TableCursorFlags::LT
+ else
+ options[:flags] |= TableCursorFlags::LE
+ end
+ if max_border.value == "include"
+ options[:flags] |= TableCursorFlags::GT
+ else
+ options[:flags] |= TableCursorFlags::GE
+ end
+
+ TableCursor.open(lexicon, options) do |cursor|
+ index_column.estimate_size(:lexicon_cursor => cursor)
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/index_column.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/index_column.rb
new file mode 100644
index 00000000..c62a8d19
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/index_column.rb
@@ -0,0 +1,14 @@
+module Groonga
+ module ExpressionTree
+ class IndexColumn
+ attr_reader :object
+ def initialize(object)
+ @object = object
+ end
+
+ def build(expression)
+ expression.append_object(@object, Operator::PUSH, 1)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/logical_operation.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/logical_operation.rb
new file mode 100644
index 00000000..e8d494f8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/logical_operation.rb
@@ -0,0 +1,33 @@
+module Groonga
+ module ExpressionTree
+ class LogicalOperation
+ attr_reader :operator
+ attr_reader :nodes
+ def initialize(operator, nodes)
+ @operator = operator
+ @nodes = nodes
+ end
+
+ def build(expression)
+ @nodes.each_with_index do |node, i|
+ node.build(expression)
+ expression.append_operator(@operator, 2) if i > 0
+ end
+ end
+
+ def estimate_size(table)
+ estimated_sizes = @nodes.collect do |node|
+ node.estimate_size(table)
+ end
+ case @operator
+ when Operator::AND
+ estimated_sizes.min
+ when Operator::OR
+ estimated_sizes.max
+ else
+ estimated_sizes.first
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/options.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/options.rb
new file mode 100644
index 00000000..1504b57a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/options.rb
@@ -0,0 +1,14 @@
+module Groonga
+ module ExpressionTree
+ class Options
+ attr_reader :object
+ def initialize(object)
+ @object = object
+ end
+
+ def build(expression)
+ expression.append_object(@object, Operator::PUSH, 1)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/procedure.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/procedure.rb
new file mode 100644
index 00000000..1d63149c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/procedure.rb
@@ -0,0 +1,18 @@
+module Groonga
+ module ExpressionTree
+ class Procedure
+ attr_reader :object
+ def initialize(object)
+ @object = object
+ end
+
+ def name
+ @object.name
+ end
+
+ def build(expression)
+ expression.append_object(@object, Operator::PUSH, 1)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/sources.am
new file mode 100644
index 00000000..d8a776bf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/sources.am
@@ -0,0 +1,10 @@
+RUBY_SCRIPT_FILES = \
+ accessor.rb \
+ binary_operation.rb \
+ constant.rb \
+ function_call.rb \
+ index_column.rb \
+ logical_operation.rb \
+ options.rb \
+ procedure.rb \
+ variable.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/variable.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/variable.rb
new file mode 100644
index 00000000..e99ad9a8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree/variable.rb
@@ -0,0 +1,18 @@
+module Groonga
+ module ExpressionTree
+ class Variable
+ attr_reader :column
+ def initialize(column)
+ @column = column
+ end
+
+ def build(expression)
+ expression.append_object(@column, Operator::GET_VALUE, 1)
+ end
+
+ def estimate_size(table)
+ table.size
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree_builder.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree_builder.rb
new file mode 100644
index 00000000..f2cc297c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/expression_tree_builder.rb
@@ -0,0 +1,111 @@
+require "expression_tree"
+
+module Groonga
+ class ExpressionTreeBuilder
+ RELATION_OPERATORS = [
+ Operator::MATCH,
+ Operator::NEAR,
+ Operator::NEAR2,
+ Operator::SIMILAR,
+ Operator::PREFIX,
+ Operator::SUFFIX,
+ Operator::EQUAL,
+ Operator::NOT_EQUAL,
+ Operator::LESS,
+ Operator::GREATER,
+ Operator::LESS_EQUAL,
+ Operator::GREATER_EQUAL,
+ Operator::GEO_WITHINP5,
+ Operator::GEO_WITHINP6,
+ Operator::GEO_WITHINP8,
+ Operator::TERM_EXTRACT,
+ Operator::REGEXP,
+ Operator::FUZZY,
+ ]
+
+ ARITHMETIC_OPERATORS = [
+ Operator::BITWISE_OR,
+ Operator::BITWISE_XOR,
+ Operator::BITWISE_AND,
+ Operator::BITWISE_NOT,
+ Operator::SHIFTL,
+ Operator::SHIFTR,
+ Operator::SHIFTRR,
+ Operator::PLUS,
+ Operator::MINUS,
+ Operator::STAR,
+ Operator::MOD,
+ ]
+
+ LOGICAL_OPERATORS = [
+ Operator::AND,
+ Operator::OR,
+ Operator::AND_NOT,
+ Operator::ADJUST,
+ ]
+
+ def initialize(expression)
+ @expression = expression
+ end
+
+ def build
+ stack = []
+ codes = @expression.codes
+ codes.each do |code|
+ case code.op
+ when *LOGICAL_OPERATORS
+ right = stack.pop
+ left = stack.pop
+ nodes = []
+ add_logical_operation_node(code.op, nodes, left)
+ add_logical_operation_node(code.op, nodes, right)
+ node = ExpressionTree::LogicalOperation.new(code.op, nodes)
+ stack.push(node)
+ when *RELATION_OPERATORS, *ARITHMETIC_OPERATORS
+ right = stack.pop
+ left = stack.pop
+ node = ExpressionTree::BinaryOperation.new(code.op, left, right)
+ stack.push(node)
+ when Operator::GET_VALUE
+ node = ExpressionTree::Variable.new(code.value)
+ stack.push(node)
+ when Operator::PUSH
+ case code.value
+ when Procedure
+ node = ExpressionTree::Procedure.new(code.value)
+ when IndexColumn
+ node = ExpressionTree::IndexColumn.new(code.value)
+ when Accessor
+ node = ExpressionTree::Accessor.new(code.value)
+ when HashTable
+ node = ExpressionTree::Options.new(code.value)
+ else
+ node = ExpressionTree::Constant.new(code.value.value)
+ end
+ stack.push(node)
+ when Operator::CALL
+ arguments = []
+ (code.n_args - 1).times do
+ arguments.unshift(stack.pop)
+ end
+ procedure = stack.pop
+ node = ExpressionTree::FunctionCall.new(procedure, arguments)
+ stack.push(node)
+ else
+ raise "unknown operator: #{code.inspect}"
+ end
+ end
+ stack.pop
+ end
+
+ private
+ def add_logical_operation_node(operator, nodes, node)
+ if node.is_a?(ExpressionTree::LogicalOperation) and
+ node.operator == operator
+ nodes.concat(node.nodes)
+ else
+ nodes << node
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/fixed_size_column.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/fixed_size_column.rb
new file mode 100644
index 00000000..4fab9fb7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/fixed_size_column.rb
@@ -0,0 +1,5 @@
+module Groonga
+ class FixedSizeColumn
+ include Indexable
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/id.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/id.rb
new file mode 100644
index 00000000..a49e4fde
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/id.rb
@@ -0,0 +1,12 @@
+module Groonga
+ module ID
+ # TODO: Should we bind GRN_N_RESERVED_TYPES?
+ N_RESERVED_TYPES = 256
+
+ class << self
+ def builtin?(id)
+ id < N_RESERVED_TYPES
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_column.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_column.rb
new file mode 100644
index 00000000..25ebc149
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_column.rb
@@ -0,0 +1,39 @@
+module Groonga
+ class IndexColumn
+ private :estimate_size_for_term_id
+ private :estimate_size_for_query
+ private :estimate_size_for_lexicon_cursor
+
+ # Estimate the number of matched records for term ID or query.
+ #
+ # @overload estimate_size(:term_id => term_id)
+ # @return [Integer] the number of matched records for the term ID.
+ #
+ # @overload estimate_size(:query => query)
+ # @return [Integer] the number of matched records for the query.
+ #
+ # @overload estimate_size(:lexicon_cursor => lexicon_cursor)
+ # @return [Integer] the number of matched records for the lexicon cursor.
+ #
+ def estimate_size(parameters)
+ term_id = parameters[:term_id]
+ if term_id
+ return estimate_size_for_term_id(term_id)
+ end
+
+ query = parameters[:query]
+ if query
+ return estimate_size_for_query(query, parameters)
+ end
+
+ lexicon_cursor = parameters[:lexicon_cursor]
+ if lexicon_cursor
+ return estimate_size_for_lexicon_cursor(lexicon_cursor)
+ end
+
+ message =
+ "must specify :term_id, :query, :lexicon_cursor: #{parameters.inspect}"
+ raise InvalidArgument, message
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_cursor.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_cursor.rb
new file mode 100644
index 00000000..80440669
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_cursor.rb
@@ -0,0 +1,18 @@
+module Groonga
+ class IndexCursor
+ class << self
+ def open(*arguments)
+ cursor = open_raw(*arguments)
+ if block_given?
+ begin
+ yield(cursor)
+ ensure
+ cursor.close
+ end
+ else
+ cursor
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_info.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_info.rb
new file mode 100644
index 00000000..cf8336e5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/index_info.rb
@@ -0,0 +1,10 @@
+module Groonga
+ class IndexInfo
+ attr_reader :index
+ attr_reader :section_id
+ def initialize(index, section_id)
+ @index = index
+ @section_id = section_id
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/Makefile.am
new file mode 100644
index 00000000..e7531fdc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/Makefile.am
@@ -0,0 +1,9 @@
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_initializedir = $(ruby_scriptsdir)/initialize
+ruby_scripts_initialize_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/post.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/post.rb
new file mode 100644
index 00000000..c1215f3e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/post.rb
@@ -0,0 +1,28 @@
+require "error"
+
+require "context"
+
+require "writer"
+
+require "id"
+
+require "object"
+require "database"
+require "table"
+require "record"
+require "fixed_size_column"
+require "variable_size_column"
+require "index_column"
+require "accessor"
+require "command"
+require "command_input"
+require "table_cursor"
+require "index_cursor"
+
+require "expression"
+
+require "plugin_loader"
+
+require "eval_context"
+
+require "command_line_parser"
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/pre.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/pre.rb
new file mode 100644
index 00000000..99300d11
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/pre.rb
@@ -0,0 +1,3 @@
+require "backtrace_entry"
+
+require "operator"
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/sources.am
new file mode 100644
index 00000000..3c26e19b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/initialize/sources.am
@@ -0,0 +1,3 @@
+RUBY_SCRIPT_FILES = \
+ pre.rb \
+ post.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger.rb
new file mode 100644
index 00000000..95f86974
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger.rb
@@ -0,0 +1,34 @@
+module Groonga
+ class Logger
+ def log_error(error)
+ log_level = Level::ERROR.to_i
+
+ if error.is_a?(Error)
+ message = error.message
+ else
+ message = "#{error.class}: #{error.message}"
+ end
+ backtrace = error.backtrace
+ first_raw_entry = backtrace.first
+ if first_raw_entry
+ first_entry = BacktraceEntry.parse(first_raw_entry)
+ file = first_entry.file
+ line = first_entry.line
+ method = first_entry.method
+ # message = "#{file}:#{line}:#{method}: #{message}"
+ else
+ file = ""
+ line = 0
+ method = ""
+ end
+ log(log_level, file, line, method, message)
+
+ backtrace.each_with_index do |raw_entry, i|
+ entry = BacktraceEntry.parse(raw_entry)
+ message = entry.message
+ message = raw_entry if message.empty?
+ log(log_level, entry.file, entry.line, entry.method, raw_entry)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/Makefile.am
new file mode 100644
index 00000000..448e72ca
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/Makefile.am
@@ -0,0 +1,9 @@
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_loggerdir = $(ruby_scriptsdir)/logger
+ruby_scripts_logger_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/level.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/level.rb
new file mode 100644
index 00000000..4b8afa2c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/level.rb
@@ -0,0 +1,40 @@
+module Groonga
+ class Logger
+ class Level
+ @@names = {}
+ @@levels = {}
+ class << self
+ def find(name_or_level)
+ if name_or_level.is_a?(Integer)
+ @@levels[name_or_level]
+ else
+ @@names[name_or_level]
+ end
+ end
+ end
+
+ attr_reader :name
+ def initialize(name, level)
+ @@names[name] = self
+ @@levels[level] = self
+ @name = name
+ @level = level
+ end
+
+ def to_i
+ @level
+ end
+
+ NONE = new(:none, 0)
+ EMERG = new(:emerg, 1)
+ ALERT = new(:alert, 2)
+ CRIT = new(:crit, 3)
+ ERROR = new(:error, 4)
+ WARNING = new(:warning, 5)
+ NOTICE = new(:notice, 6)
+ INFO = new(:info, 7)
+ DEBUG = new(:debug, 8)
+ DUMP = new(:dump, 9)
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/sources.am
new file mode 100644
index 00000000..7231ee4e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/logger/sources.am
@@ -0,0 +1,2 @@
+RUBY_SCRIPT_FILES = \
+ level.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/object.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/object.rb
new file mode 100644
index 00000000..aa8e9e65
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/object.rb
@@ -0,0 +1,18 @@
+module Groonga
+ class Object
+ def domain
+ Context.instance[domain_id]
+ end
+
+ def range
+ Context.instance[range_id]
+ end
+
+ def corrupt?
+ check_corrupt
+ false
+ rescue
+ true
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/operator.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/operator.rb
new file mode 100644
index 00000000..349695e1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/operator.rb
@@ -0,0 +1,22 @@
+module Groonga
+ class Operator
+ @values = {}
+ class << self
+ def register(operator)
+ const_set(operator.name, operator)
+ @values[operator.value] = operator
+ end
+
+ def find(value)
+ @values[value]
+ end
+ end
+
+ attr_reader :name
+ attr_reader :value
+ def initialize(name, value)
+ @name = name
+ @value = value
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/plugin_loader.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/plugin_loader.rb
new file mode 100644
index 00000000..09b972f1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/plugin_loader.rb
@@ -0,0 +1,14 @@
+module Groonga
+ class PluginLoader
+ class << self
+ def load_file(path)
+ begin
+ load(path)
+ rescue => error
+ Context.instance.record_error(:plugin_error, error)
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger.rb
new file mode 100644
index 00000000..386ec0e2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger.rb
@@ -0,0 +1,9 @@
+module Groonga
+ class QueryLogger
+ def log(flag, mark, message)
+ flag = Flag.find(flag) if flag.is_a?(Symbol)
+ flag = flag.to_i if flag.is_a?(Flag)
+ log_raw(flag, mark, message)
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/Makefile.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/Makefile.am
new file mode 100644
index 00000000..14b4f61c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/Makefile.am
@@ -0,0 +1,9 @@
+include sources.am
+
+EXTRA_DIST = \
+ $(RUBY_SCRIPT_FILES)
+
+if WITH_MRUBY
+ruby_scripts_query_loggerdir = $(ruby_scriptsdir)/query_logger
+ruby_scripts_query_logger_DATA = $(RUBY_SCRIPT_FILES)
+endif
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/flag.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/flag.rb
new file mode 100644
index 00000000..659570f6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/flag.rb
@@ -0,0 +1,39 @@
+module Groonga
+ class QueryLogger
+ class Flag
+ @@names = {}
+ class << self
+ def find(name)
+ @@names[name]
+ end
+ end
+
+ attr_reader :name
+ def initialize(name, flag)
+ @@names[name] = self
+ @name = name
+ @flag = flag
+ end
+
+ def to_i
+ @flag
+ end
+
+ NONE = new(:none, 0x00)
+ COMMAND = new(:command, 0x01 << 0)
+ RESULT_CODE = new(:result_code, 0x01 << 1)
+ DESTINATION = new(:destination, 0x01 << 2)
+ CACHE = new(:cache, 0x01 << 3)
+ SIZE = new(:size, 0x01 << 4)
+ SCORE = new(:score, 0x01 << 5)
+
+ all_flags = COMMAND.to_i |
+ RESULT_CODE.to_i |
+ DESTINATION.to_i |
+ CACHE.to_i |
+ SIZE.to_i |
+ SCORE.to_i
+ ALL = new(:all, all_flags)
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/sources.am
new file mode 100644
index 00000000..44871a85
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/query_logger/sources.am
@@ -0,0 +1,2 @@
+RUBY_SCRIPT_FILES = \
+ flag.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/record.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/record.rb
new file mode 100644
index 00000000..cd7d1a4c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/record.rb
@@ -0,0 +1,38 @@
+module Groonga
+ class Record
+ attr_reader :table
+ attr_reader :id
+
+ def inspect
+ super.gsub(/>\z/) do
+ "@id=#{@id.inspect}, @table=#{@table.inspect}>"
+ end
+ end
+
+ def [](name)
+ column = find_column(name)
+ if column.nil?
+ raise InvalidArgument, "unknown column: <#{absolute_column_name(name)}>"
+ end
+ column[@id]
+ end
+
+ def method_missing(name, *args, &block)
+ return super unless args.empty?
+
+ column = find_column(name)
+ return super if column.nil?
+
+ column[@id]
+ end
+
+ private
+ def absolute_column_name(name)
+ "#{@table.name}.#{name}"
+ end
+
+ def find_column(name)
+ Context.instance[absolute_column_name(name)]
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/require.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/require.rb
new file mode 100644
index 00000000..1352b327
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/require.rb
@@ -0,0 +1,71 @@
+$" = [__FILE__]
+
+class ScriptLoader
+ @@loading_paths = {}
+
+ def initialize(path)
+ @base_path = path
+ end
+
+ def load_once
+ if absolute_path?(@base_path)
+ loaded = load_once_path(@base_path)
+ if loaded.nil?
+ raise LoadError, error_message
+ else
+ loaded
+ end
+ else
+ $LOAD_PATH.each do |load_path|
+ unless absolute_path?(load_path)
+ load_path = File.expand_path(load_path)
+ if File::ALT_SEPARATOR
+ load_path = load_path.gsub(File::ALT_SEPARATOR, "/")
+ end
+ end
+ loaded = load_once_path(File.join(load_path, @base_path))
+ return loaded unless loaded.nil?
+ end
+ raise LoadError, error_message
+ end
+ end
+
+ private
+ def error_message
+ "cannot load such file -- #{@base_path}"
+ end
+
+ def absolute_path?(path)
+ path.start_with?("/") or (/\A[a-z]:\\/i === path)
+ end
+
+ def load_once_path(path)
+ loaded = load_once_absolute_path(path)
+ return loaded unless loaded.nil?
+
+ return nil unless File.extname(path).empty?
+
+ load_once_absolute_path("#{path}.rb")
+ end
+
+ def load_once_absolute_path(path)
+ return false if $".include?(path)
+ return false if @@loading_paths.key?(path)
+
+ return nil unless File.file?(path)
+
+ @@loading_paths[path] = true
+ load(path)
+ $" << path
+ @@loading_paths.delete(path)
+
+ true
+ end
+end
+
+module Kernel
+ def require(path)
+ loader = ScriptLoader.new(path)
+ loader.load_once
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info.rb
new file mode 100644
index 00000000..acdb2eeb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info.rb
@@ -0,0 +1,38 @@
+module Groonga
+ class ScanInfo
+ module Flags
+ ACCESSOR = 0x01
+ PUSH = 0x02
+ POP = 0x04
+ PRE_CONST = 0x08
+ end
+
+ def apply(data)
+ self.op = data.op
+ self.logical_op = data.logical_op
+ self.end = data.end
+ self.query = data.query
+ self.flags = data.flags
+ if data.max_interval
+ self.max_interval = data.max_interval
+ end
+ if data.similarity_threshold
+ self.similarity_threshold = data.similarity_threshold
+ end
+ data.args.each do |arg|
+ push_arg(arg)
+ end
+ data.search_indexes.each do |search_index|
+ put_index(search_index.index_column,
+ search_index.section_id,
+ search_index.weight,
+ search_index.scorer,
+ search_index.scorer_args_expr,
+ search_index.scorer_args_expr_offset || 0)
+ end
+ if data.start_position
+ self.start_position = data.start_position
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_builder.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_builder.rb
new file mode 100644
index 00000000..66dad9ea
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_builder.rb
@@ -0,0 +1,577 @@
+require "scan_info_data"
+
+module Groonga
+ class ScanInfoBuilder
+ def initialize(expression, operator, record_exist)
+ @data_list = []
+ @expression = expression
+ @operator = operator
+ @record_exist = record_exist
+ @variable = @expression[0]
+ @table = Context.instance[@variable.domain]
+ end
+
+ RELATION_OPERATORS = [
+ Operator::MATCH,
+ Operator::NEAR,
+ Operator::NEAR2,
+ Operator::SIMILAR,
+ Operator::PREFIX,
+ Operator::SUFFIX,
+ Operator::EQUAL,
+ Operator::NOT_EQUAL,
+ Operator::LESS,
+ Operator::GREATER,
+ Operator::LESS_EQUAL,
+ Operator::GREATER_EQUAL,
+ Operator::GEO_WITHINP5,
+ Operator::GEO_WITHINP6,
+ Operator::GEO_WITHINP8,
+ Operator::TERM_EXTRACT,
+ Operator::REGEXP,
+ Operator::FUZZY,
+ ]
+
+ ARITHMETIC_OPERATORS = [
+ Operator::BITWISE_OR,
+ Operator::BITWISE_XOR,
+ Operator::BITWISE_AND,
+ Operator::BITWISE_NOT,
+ Operator::SHIFTL,
+ Operator::SHIFTR,
+ Operator::SHIFTRR,
+ Operator::PLUS,
+ Operator::MINUS,
+ Operator::STAR,
+ Operator::MOD,
+ ]
+
+ LOGICAL_OPERATORS = [
+ Operator::AND,
+ Operator::OR,
+ Operator::AND_NOT,
+ Operator::ADJUST,
+ ]
+ def build
+ return nil unless valid?
+
+ context = BuildContext.new(@expression)
+ codes = context.codes
+ while context.have_next?
+ code = context.code
+ code_op = context.code_op
+ i = context.i
+ context.next
+
+ case code_op
+ when *RELATION_OPERATORS
+ context.status = :start
+ data = context.data
+ data.op = code_op
+ data.end = i
+ data.weight = code.value.value if code.value
+ data.match_resolve_index
+ @data_list << data
+ context.data = nil
+ when *LOGICAL_OPERATORS
+ if context.status == :const
+ data = context.data
+ data.op = Operator::PUSH
+ data.end = data.start
+ @data_list << data
+ context.data = nil
+ end
+ put_logical_op(code_op, i)
+ # TODO: rescue and return nil
+ context.status = :start
+ when Operator::PUSH
+ context.data ||= ScanInfoData.new(i)
+ data = context.data
+ if code.value == @variable
+ context.status = :var
+ else
+ data.args << code.value
+ if context.status == :start
+ data.flags |= ScanInfo::Flags::PRE_CONST
+ end
+ context.status = :const
+ end
+ if code.modify > 0 and
+ LOGICAL_OPERATORS.include?(codes[i + code.modify].op)
+ data.op = Operator::PUSH
+ data.end = data.start
+ @data_list << data
+ context.data = nil
+ context.status = :start
+ end
+ when Operator::GET_VALUE
+ case context.status
+ when :start
+ context.data ||= ScanInfoData.new(i)
+ data = context.data
+ context.status = :column1
+ data.args << code.value
+ when :const, :var
+ context.status = :column1
+ data.args << code.value
+ when :column1
+ message = "invalid expression: can't use column as a value: "
+ message << "<#{code.value.name}>: <#{@expression.grn_inspect}>"
+ raise ErrorMessage, message
+ when :column2
+ # Do nothing
+ else
+ message = "internal expression parsing error: unknown status: "
+ message << "<#{context.status.inspect}>: "
+ message << "<#{@expression.grn_inspect}>"
+ raise ErrorMessage, message
+ end
+ when Operator::CALL
+ context.data ||= ScanInfoData.new(i)
+ data = context.data
+ if (code.flags & ExpressionCode::Flags::RELATIONAL_EXPRESSION) != 0 or
+ (not context.have_next?)
+ context.status = :start
+ data.op = code_op
+ data.end = i
+ data.call_relational_resolve_indexes
+ @data_list << data
+ context.data = nil
+ else
+ context.status = :column2
+ end
+ when Operator::GET_REF
+ context.data ||= ScanInfoData.new(i)
+ case context.status
+ when :start
+ data = context.data
+ context.status = :column1
+ data.args << code.value
+ end
+ when Operator::GET_MEMBER
+ data = context.data
+ index = data.args.pop
+ data.start_position = index.value
+ context.status = :column1
+ when Operator::NOT
+ success = build_not(context, code, i)
+ return nil unless success
+ end
+ end
+
+ if @operator == Operator::OR and !@record_exist
+ first_data = @data_list.first
+ if (first_data.flags & ScanInfo::Flags::PUSH) == 0 or
+ first_data.logical_op != @operator
+ raise ErrorMessage, "invalid expr"
+ else
+ first_data.flags &= ~ScanInfo::Flags::PUSH
+ first_data.logical_op = @operator
+ end
+ else
+ put_logical_op(@operator, context.n_codes)
+ end
+
+ optimize
+ end
+
+ private
+ def valid?
+ n_relation_expressions = 0
+ n_logical_expressions = 0
+ status = :start
+ codes = @expression.codes
+ codes.each_with_index do |code, i|
+ case code.op
+ when *RELATION_OPERATORS
+ if status == :start || status == :var
+ return false
+ end
+ status = :start
+ n_relation_expressions += 1
+ when *ARITHMETIC_OPERATORS
+ if status == :start || status == :var
+ return false
+ end
+ status = :start
+ return false if n_relation_expressions != (n_logical_expressions + 1)
+ when *LOGICAL_OPERATORS
+ case status
+ when :start
+ n_logical_expressions += 1
+ return false if n_logical_expressions >= n_relation_expressions
+ when :const
+ n_logical_expressions += 1
+ n_relation_expressions += 1
+ return false if n_logical_expressions >= n_relation_expressions
+ status = :start
+ else
+ return false
+ end
+ when Operator::PUSH
+ if code.modify > 0 and
+ LOGICAL_OPERATORS.include?(codes[i + code.modify].op)
+ n_relation_expressions += 1
+ status = :start
+ else
+ if code.value == @variable
+ status = :var
+ else
+ status = :const
+ end
+ end
+ when Operator::GET_VALUE
+ case status
+ when :start, :const, :var
+ status = :column1
+ when :column1
+ status = :column2
+ when :column2
+ # Do nothing
+ else
+ return false
+ end
+ when Operator::CALL
+ if (code.flags & ExpressionCode::Flags::RELATIONAL_EXPRESSION) != 0 or
+ code == codes.last
+ status = :start
+ n_relation_expressions += 1
+ else
+ status = :column2
+ end
+ when Operator::GET_REF
+ case status
+ when :start
+ status = :column1
+ else
+ return false
+ end
+ when Operator::GET_MEMBER
+ case status
+ when :const
+ return false unless codes[i - 1].value.value.is_a?(Integer)
+ status = :column1
+ else
+ return false
+ end
+ when Operator::NOT
+ # Do nothing
+ else
+ return false
+ end
+ end
+
+ return false if status != :start
+ return false if n_relation_expressions != (n_logical_expressions + 1)
+
+ true
+ end
+
+ def put_logical_op(operator, start)
+ n_parens = 1
+ n_dif_ops = 0
+ r = 0
+ j = @data_list.size
+ while j > 0
+ j -= 1
+ data = @data_list[j]
+ if (data.flags & ScanInfo::Flags::POP) != 0
+ n_dif_ops += 1
+ n_parens += 1
+ else
+ if (data.flags & ScanInfo::Flags::PUSH) != 0
+ n_parens -= 1
+ if n_parens == 0
+ if r == 0
+ if n_dif_ops > 0
+ if j > 0 and operator != Operator::AND_NOT
+ n_parens = 1
+ n_dif_ops = 0
+ r = j
+ else
+ new_data = ScanInfoData.new(start)
+ new_data.flags = ScanInfo::Flags::POP
+ new_data.logical_op = operator
+ @data_list << new_data
+ break
+ end
+ else
+ data.flags &= ~ScanInfo::Flags::PUSH
+ data.logical_op = operator
+ break
+ end
+ else
+ if n_dif_ops > 0
+ new_data = ScanInfoData.new(start)
+ new_data.flags = ScanInfo::Flags::POP
+ new_data.logical_op = operator
+ @data_list << new_data
+ else
+ data.flags &= ~ScanInfo::Flags::PUSH
+ data.logical_op = operator
+ @data_list =
+ @data_list[0...j] +
+ @data_list[r..-1] +
+ @data_list[j...r]
+ end
+ break
+ end
+ end
+ else
+ if operator == Operator::AND_NOT or operator != data.logical_op
+ n_dif_ops += 1
+ end
+ end
+ end
+
+ if j < 0
+ raise ErrorMessage, "unmatched nesting level"
+ end
+ end
+ end
+
+ def build_not(context, code, i)
+ last_data = @data_list.last
+ return false if last_data.nil?
+
+ case last_data.op
+ when Operator::LESS
+ last_data.op = Operator::GREATER_EQUAL
+ last_data.end += 1
+ when Operator::LESS_EQUAL
+ last_data.op = Operator::GREATER
+ last_data.end += 1
+ when Operator::GREATER
+ last_data.op = Operator::LESS_EQUAL
+ last_data.end += 1
+ when Operator::GREATER_EQUAL
+ last_data.op = Operator::LESS
+ last_data.end += 1
+ when Operator::NOT_EQUAL
+ last_data.op = Operator::EQUAL
+ last_data.end += 1
+ else
+ if @data_list.size == 1
+ if last_data.search_indexes.empty?
+ if last_data.op == Operator::EQUAL
+ last_data.op = Operator::NOT_EQUAL
+ last_data.end += 1
+ else
+ return false
+ end
+ else
+ last_data.logical_op = Operator::AND_NOT
+ last_data.flags &= ~ScanInfo::Flags::PUSH
+ @data_list.unshift(create_all_match_data)
+ end
+ else
+ next_code = context.code
+ return false if next_code.nil?
+
+ case next_code.op
+ when Operator::AND
+ context.code_op = Operator::AND_NOT
+ when Operator::AND_NOT
+ context.code_op = Operator::AND
+ when Operator::OR
+ @data_list[-1, 0] = create_all_match_data
+ put_logical_op(Operator::AND_NOT, i)
+ else
+ return false
+ end
+ end
+ end
+
+ true
+ end
+
+ def optimize
+ optimized_data_list = []
+ i = 0
+ n = @data_list.size
+ while i < n
+ data = @data_list[i]
+ next_data = @data_list[i + 1]
+ i += 1
+ if next_data.nil?
+ optimized_data_list << data
+ next
+ end
+ if range_operations?(data, next_data)
+ between_data = create_between_data(data, next_data)
+ optimized_data_list << between_data
+ i += 1
+ next
+ end
+ optimized_data_list << data
+ end
+
+ optimize_by_estimated_size(optimized_data_list)
+ end
+
+ def optimize_by_estimated_size(data_list)
+ return data_list unless Groonga::ORDER_BY_ESTIMATED_SIZE
+
+ start_index = nil
+ data_list.size.times do |i|
+ data = data_list[i]
+ if data.logical_op != Operator::AND
+ if start_index.nil?
+ start_index = i
+ else
+ sort_by_estimated_size!(data_list, start_index...i)
+ start_index = nil
+ end
+ end
+ end
+ unless start_index.nil?
+ sort_by_estimated_size!(data_list, start_index...data_list.size)
+ end
+ data_list
+ end
+
+ def sort_by_estimated_size!(data_list, range)
+ target_data_list = data_list[range]
+ return if target_data_list.size < 2
+
+ start_logical_op = target_data_list.first.logical_op
+ sorted_data_list = target_data_list.sort_by do |data|
+ estimator = ScanInfoDataSizeEstimator.new(data, @table)
+ estimator.estimate
+ end
+ sorted_data_list.each do |sorted_data|
+ sorted_data.logical_op = Operator::AND
+ end
+ sorted_data_list.first.logical_op = start_logical_op
+ data_list[range] = sorted_data_list
+ end
+
+ def range_operations?(data, next_data)
+ return false unless next_data.logical_op == Operator::AND
+
+ op, next_op = data.op, next_data.op
+ return false if !(lower_condition?(op) or lower_condition?(next_op))
+ return false if !(upper_condition?(op) or upper_condition?(next_op))
+
+ return false if data.args[0] != next_data.args[0]
+
+ data_search_indexes = data.search_indexes
+ return false if data_search_indexes.empty?
+
+ data_search_indexes == next_data.search_indexes
+ end
+
+ def lower_condition?(operator)
+ case operator
+ when Operator::GREATER, Operator::GREATER_EQUAL
+ true
+ else
+ false
+ end
+ end
+
+ def upper_condition?(operator)
+ case operator
+ when Operator::LESS, Operator::LESS_EQUAL
+ true
+ else
+ false
+ end
+ end
+
+ def create_all_match_data
+ data = ScanInfoData.new(0)
+ data.end = 0
+ data.flags = ScanInfo::Flags::PUSH
+ data.op = Operator::CALL
+ data.logical_op = Operator::OR
+ data.args = [Context.instance["all_records"]]
+ data.search_indexes = []
+ data
+ end
+
+ def create_between_data(data, next_data)
+ between_data = ScanInfoData.new(data.start)
+ between_data.end = next_data.end + 1
+ between_data.flags = data.flags
+ between_data.op = Operator::CALL
+ between_data.logical_op = data.logical_op
+ between_data.args = create_between_data_args(data, next_data)
+ between_data.search_indexes = data.search_indexes
+ between_data
+ end
+
+ def create_between_data_args(data, next_data)
+ between = Context.instance["between"]
+ @expression.take_object(between)
+ column = data.args[0]
+ op, next_op = data.op, next_data.op
+ if lower_condition?(op)
+ min = data.args[1]
+ min_operator = op
+ max = next_data.args[1]
+ max_operator = next_op
+ else
+ min = next_data.args[1]
+ min_operator = next_op
+ max = data.args[1]
+ max_operator = op
+ end
+ if min_operator == Operator::GREATER
+ min_border = "exclude"
+ else
+ min_border = "include"
+ end
+ if max_operator == Operator::LESS
+ max_border = "exclude"
+ else
+ max_border = "include"
+ end
+
+ [
+ between,
+ column,
+ min,
+ @expression.allocate_constant(min_border),
+ max,
+ @expression.allocate_constant(max_border),
+ ]
+ end
+
+ class BuildContext
+ attr_accessor :status
+ attr_reader :codes
+ attr_reader :n_codes
+ attr_reader :i
+ attr_writer :code_op
+ attr_accessor :data
+ def initialize(expression)
+ @expression = expression
+ @status = :start
+ @current_data = nil
+ @codes = @expression.codes
+ @n_codes = @codes.size
+ @i = 0
+ @code_op = nil
+ @data = nil
+ end
+
+ def have_next?
+ @i < @n_codes
+ end
+
+ def next
+ @i += 1
+ @code_op = nil
+ end
+
+ def code
+ @codes[@i]
+ end
+
+ def code_op
+ @code_op || code.op
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data.rb
new file mode 100644
index 00000000..342f7a7a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data.rb
@@ -0,0 +1,324 @@
+require "scan_info_search_index"
+
+module Groonga
+ class ScanInfoData
+ attr_accessor :start
+ attr_accessor :end
+ attr_accessor :op
+ attr_accessor :logical_op
+ attr_accessor :query
+ attr_accessor :args
+ attr_accessor :search_indexes
+ attr_accessor :flags
+ attr_accessor :max_interval
+ attr_accessor :similarity_threshold
+ attr_accessor :start_position
+ attr_accessor :weight
+ def initialize(start)
+ @start = start
+ @end = 0
+ @op = Operator::NOP
+ @logical_op = Operator::OR
+ @query = nil
+ @args = []
+ @search_indexes = []
+ @flags = ScanInfo::Flags::PUSH
+ @max_interval = nil
+ @similarity_threshold = nil
+ @start_position = nil
+ @weight = 0
+ end
+
+ def match_resolve_index
+ if near_search?
+ match_near_resolve_index
+ elsif similar_search?
+ match_similar_resolve_index
+ else
+ match_generic_resolve_index
+ end
+ end
+
+ def call_relational_resolve_indexes
+ procedure, *args = *@args
+ return unless procedure.selector?
+
+ selector_op = procedure.selector_operator
+ args.each do |arg|
+ call_relational_resolve_index(arg, selector_op)
+ end
+ end
+
+ private
+ def near_search?
+ (@op == Operator::NEAR or @op == Operator::NEAR2) and @args.size == 3
+ end
+
+ def match_near_resolve_index
+ arg = @args[0]
+ case arg
+ when Expression
+ match_resolve_index_expression(arg)
+ when Accessor
+ match_resolve_index_accessor(arg)
+ when Indexable
+ match_resolve_index_indexable(arg)
+ else
+ message =
+ "The first argument of NEAR/NEAR2 must be Expression, Accessor or Indexable: #{arg.class}"
+ raise ErrorMessage, message
+ end
+
+ self.query = @args[1]
+ self.max_interval = @args[2].value
+ end
+
+ def similar_search?
+ @op == Operator::SIMILAR and @args.size == 3
+ end
+
+ def match_similar_resolve_index
+ arg = @args[0]
+ case arg
+ when Expression
+ match_resolve_index_expression(arg)
+ when Accessor
+ match_resolve_index_accessor(arg)
+ when Indexable
+ match_resolve_index_indexable(arg)
+ else
+ message =
+ "The first argument of SIMILAR must be Expression, Accessor or Indexable: #{arg.class}"
+ raise ErrorMesesage, message
+ end
+
+ self.query = @args[1]
+ self.similarity_threshold = @args[2].value
+ end
+
+ def match_generic_resolve_index
+ @args.each do |arg|
+ case arg
+ when Expression
+ match_resolve_index_expression(arg)
+ when Accessor
+ match_resolve_index_accessor(arg)
+ when IndexColumn
+ match_resolve_index_index_column(arg)
+ when Indexable
+ match_resolve_index_indexable(arg)
+ when Procedure
+ break
+ else
+ self.query = arg
+ end
+ end
+ if @op == Operator::REGEXP and not index_searchable_regexp?(@query)
+ @search_indexes.clear
+ end
+ end
+
+ def index_searchable_regexp?(pattern)
+ return false if pattern.nil?
+
+ previous_char = nil
+ pattern.value.each_char do |char|
+ if previous_char == "\\"
+ case char
+ when "Z"
+ return false
+ when "b", "B"
+ return false
+ when "d", "D", "h", "H", "p", "s", "S", "w", "W"
+ return false
+ when "X"
+ return false
+ when "k", "g", "1", "2", "3", "4", "5", "6", "7", "8", "9"
+ return false
+ when "\\"
+ previous_char = nil
+ next
+ end
+ else
+ case char
+ when ".", "[", "]", "|", "?", "+", "*", "{", "}", "^", "$", "(", ")"
+ return false
+ end
+ end
+ previous_char = char
+ end
+ true
+ end
+
+ def match_resolve_index_expression(expression)
+ codes = expression.codes
+ n_codes = codes.size
+ i = 0
+ while i < n_codes
+ i = match_resolve_index_expression_codes(expression, codes, i, n_codes)
+ end
+ end
+
+ def match_resolve_index_expression_codes(expression, codes, i, n_codes)
+ code = codes[i]
+ value = code.value
+ return i + 1 if value.nil?
+
+ case value
+ when Accessor, Column
+ index_info, offset =
+ match_resolve_index_expression_find_index(expression,
+ codes, i, n_codes)
+ i += offset - 1
+ if index_info
+ if value.is_a?(Accessor)
+ self.flags |= ScanInfo::Flags::ACCESSOR
+ end
+ weight, offset = codes[i].weight
+ i += offset
+ put_search_index(index_info.index, index_info.section_id, weight)
+ end
+ when Procedure
+ unless value.scorer?
+ message = "procedure must be scorer: #{scorer.name}>"
+ raise ErrorMessage, message
+ end
+ scorer = value
+ i += 1
+ index_info, offset =
+ match_resolve_index_expression_find_index(expression,
+ codes, i, n_codes)
+ i += offset
+ if index_info
+ scorer_args_expr_offset = 0
+ if codes[i].op != Operator::CALL
+ scorer_args_expr_offset = i
+ end
+ while i < n_codes and codes[i].op != Operator::CALL
+ i += 1
+ end
+ weight, offset = codes[i].weight
+ i += offset
+ put_search_index(index_info.index,
+ index_info.section_id,
+ weight,
+ scorer,
+ expression,
+ scorer_args_expr_offset)
+ end
+ when Table
+ raise ErrorMessage, "invalid match target: <#{value.name}>"
+ end
+ i + 1
+ end
+
+ def match_resolve_index_expression_find_index(expression, codes, i, n_codes)
+ code = codes[i]
+ value = code.value
+ index_info = nil
+ offset = 1
+ case value
+ when Accessor
+ accessor = value
+ index_info = accessor.find_index(@op)
+ if index_info
+ if accessor.have_next? and index_info.index != accessor.object
+ index_info = IndexInfo.new(accessor, index_info.section_id)
+ end
+ end
+ when FixedSizeColumn, VariableSizeColumn
+ index_info = value.find_index(@op)
+ when IndexColumn
+ index = value
+ section_id = 0
+ rest_n_codes = n_codes - i
+ if rest_n_codes >= 2 and
+ codes[i + 1].value.is_a?(Bulk) and
+ (codes[i + 1].value.domain == ID::UINT32 or
+ codes[i + 1].value.domain == ID::INT32) and
+ codes[i + 2].op == Operator::GET_MEMBER
+ section_id = codes[i + 1].value.value + 1
+ offset += 2
+ end
+ index_info = IndexInfo.new(index, section_id)
+ end
+
+ [index_info, offset]
+ end
+
+ def match_resolve_index_expression_accessor(expr_code)
+ accessor = expr_code.value
+ self.flags |= ScanInfo::Flags::ACCESSOR
+ index_info = accessor.find_index(op)
+ return if index_info.nil?
+
+ section_id = index_info.section_id
+ weight = expr_code.weight
+ if accessor.next
+ put_search_index(accessor, section_id, weight)
+ else
+ put_search_index(index_info.index, section_id, weight)
+ end
+ end
+
+ def match_resolve_index_expression_data_column(expr_code)
+ column = expr_code.value
+ index_info = column.find_index(op)
+ return if index_info.nil?
+ put_search_index(index_info.index, index_info.section_id, expr_code.weight)
+ end
+
+ def match_resolve_index_index_column(index)
+ put_search_index(index, 0, 1)
+ end
+
+ def match_resolve_index_indexable(indexable)
+ index_info = indexable.find_index(op)
+ return if index_info.nil?
+ put_search_index(index_info.index, index_info.section_id, 1)
+ end
+
+ def match_resolve_index_accessor(accessor)
+ self.flags |= ScanInfo::Flags::ACCESSOR
+ index_info = accessor.find_index(op)
+ return if index_info.nil?
+ if accessor.next
+ put_search_index(accessor, index_info.section_id, 1)
+ else
+ put_search_index(index_info.index, index_info.section_id, 1)
+ end
+ end
+
+ def call_relational_resolve_index(object, selector_op)
+ case object
+ when Accessor
+ call_relational_resolve_index_accessor(object, selector_op)
+ when Bulk
+ self.query = object
+ when Indexable
+ call_relational_resolve_index_indexable(object, selector_op)
+ end
+ end
+
+ def call_relational_resolve_index_indexable(indexable, selector_op)
+ index_info = indexable.find_index(selector_op)
+ return if index_info.nil?
+ put_search_index(index_info.index, index_info.section_id, 1)
+ end
+
+ def call_relational_resolve_index_accessor(accessor, selector_op)
+ self.flags |= ScanInfo::Flags::ACCESSOR
+ index_info = accessor.find_index(selector_op)
+ return if index_info.nil?
+ put_search_index(index_info.index, index_info.section_id, 1)
+ end
+
+ def put_search_index(index, section_id, weight, *args)
+ search_index = ScanInfoSearchIndex.new(index,
+ section_id,
+ weight + @weight,
+ *args)
+ @search_indexes << search_index
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data_size_estimator.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data_size_estimator.rb
new file mode 100644
index 00000000..5d3dc4e0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_data_size_estimator.rb
@@ -0,0 +1,185 @@
+module Groonga
+ class ScanInfoDataSizeEstimator
+ def initialize(data, table)
+ @data = data
+ @table = table
+ @table_size = @table.size
+ end
+
+ def estimate
+ search_index = @data.search_indexes.first
+ return @table_size if search_index.nil?
+
+ index_column = resolve_index_column(search_index.index_column)
+ return @table_size if index_column.nil?
+
+ size = nil
+ case @data.op
+ when Operator::MATCH,
+ Operator::FUZZY
+ size = estimate_match(index_column)
+ when Operator::REGEXP
+ size = estimate_regexp(index_column)
+ when Operator::EQUAL
+ size = estimate_equal(index_column)
+ when Operator::LESS,
+ Operator::LESS_EQUAL,
+ Operator::GREATER,
+ Operator::GREATER_EQUAL
+ size = estimate_range(index_column)
+ when Operator::PREFIX
+ size = estimate_prefix(index_column)
+ when Operator::CALL
+ size = estimate_call(index_column)
+ end
+ size || @table_size
+ end
+
+ private
+ def resolve_index_column(index_column)
+ while index_column.is_a?(Accessor)
+ index_info = index_column.find_index(@data.op)
+ return nil if index_info.nil?
+ break if index_info.index == index_column
+ index_column = index_info.index
+ end
+
+ index_column
+ end
+
+ def sampling_cursor_limit(n_terms)
+ limit = n_terms * 0.01
+ if limit < 10
+ 10
+ elsif limit > 1000
+ 1000
+ else
+ limit.to_i
+ end
+ end
+
+ def estimate_match(index_column)
+ index_column.estimate_size(:query => @data.query.value)
+ end
+
+ def estimate_regexp(index_column)
+ index_column.estimate_size(:query => @data.query.value,
+ :mode => @data.op)
+ end
+
+ def estimate_equal(index_column)
+ query = @data.query
+ if index_column.is_a?(Accessor)
+ table = index_column.object
+ if index_column.name == "_id"
+ if table.id?(query.value)
+ 1
+ else
+ 0
+ end
+ else
+ if table[query.value]
+ 1
+ else
+ 0
+ end
+ end
+ else
+ lexicon = index_column.lexicon
+ if query.domain == lexicon.id
+ term_id = query.value
+ else
+ term_id = lexicon[query]
+ end
+ return 0 if term_id.nil?
+
+ index_column.estimate_size(:term_id => term_id)
+ end
+ end
+
+ def estimate_range(index_column)
+ if index_column.is_a?(Table)
+ is_table_search = true
+ lexicon = index_column
+ elsif index_column.is_a?(Groonga::Accessor)
+ is_table_search = true
+ lexicon = index_column.object
+ else
+ is_table_search = false
+ lexicon = index_column.lexicon
+ end
+ n_terms = lexicon.size
+ return 0 if n_terms.zero?
+
+ value = @data.query.value
+ options = {
+ :limit => sampling_cursor_limit(n_terms),
+ }
+ case @data.op
+ when Operator::LESS
+ options[:max] = value
+ options[:flags] = TableCursorFlags::LT
+ when Operator::LESS_EQUAL
+ options[:max] = value
+ options[:flags] = TableCursorFlags::LE
+ when Operator::GREATER
+ options[:min] = value
+ options[:flags] = TableCursorFlags::GT
+ when Operator::GREATER_EQUAL
+ options[:min] = value
+ options[:flags] = TableCursorFlags::GE
+ end
+ TableCursor.open(lexicon, options) do |cursor|
+ if is_table_search
+ size = 1
+ else
+ size = index_column.estimate_size(:lexicon_cursor => cursor)
+ end
+ size += 1 if cursor.next != ID::NIL
+ size
+ end
+ end
+
+ def estimate_prefix(index_column)
+ is_table_search =
+ (index_column.is_a?(Accessor) and
+ index_column.name == "_key")
+ if is_table_search
+ lexicon = index_column.object
+ else
+ lexicon = index_column.lexicon
+ end
+ n_terms = lexicon.size
+ return 0 if n_terms.zero?
+
+ value = @data.query.value
+ options = {
+ :min => value,
+ :limit => sampling_cursor_limit(n_terms),
+ :flags => TableCursorFlags::PREFIX,
+ }
+ TableCursor.open(lexicon, options) do |cursor|
+ if is_table_search
+ size = 1
+ else
+ size = index_column.estimate_size(:lexicon_cursor => cursor)
+ end
+ size += 1 if cursor.next != ID::NIL
+ size
+ end
+ end
+
+ def estimate_call(index_column)
+ procedure = @data.args[0]
+ arguments = @data.args[1..-1].collect do |arg|
+ if arg.is_a?(::Groonga::Object)
+ ExpressionTree::Variable.new(arg)
+ else
+ ExpressionTree::Constant.new(arg)
+ end
+ end
+ node = ExpressionTree::FunctionCall.new(procedure, arguments)
+ node.estimate_size(@table)
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_search_index.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_search_index.rb
new file mode 100644
index 00000000..a2818160
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/scan_info_search_index.rb
@@ -0,0 +1,9 @@
+module Groonga
+ class ScanInfoSearchIndex < Struct.new(:index_column,
+ :section_id,
+ :weight,
+ :scorer,
+ :scorer_args_expr,
+ :scorer_args_expr_offset)
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/scripts/sources.am
new file mode 100644
index 00000000..9a9e2bae
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/sources.am
@@ -0,0 +1,37 @@
+RUBY_SCRIPT_FILES = \
+ accessor.rb \
+ backtrace_entry.rb \
+ command.rb \
+ command_input.rb \
+ command_line_parser.rb \
+ context.rb \
+ database.rb \
+ error.rb \
+ eval_context.rb \
+ expression.rb \
+ expression_rewriter.rb \
+ expression_rewriters.rb \
+ expression_size_estimator.rb \
+ expression_tree.rb \
+ expression_tree_builder.rb \
+ fixed_size_column.rb \
+ id.rb \
+ index_column.rb \
+ index_cursor.rb \
+ index_info.rb \
+ logger.rb \
+ object.rb \
+ operator.rb \
+ plugin_loader.rb \
+ query_logger.rb \
+ record.rb \
+ require.rb \
+ scan_info.rb \
+ scan_info_builder.rb \
+ scan_info_data.rb \
+ scan_info_data_size_estimator.rb \
+ scan_info_search_index.rb \
+ table.rb \
+ table_cursor.rb \
+ variable_size_column.rb \
+ writer.rb
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/table.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/table.rb
new file mode 100644
index 00000000..75c91894
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/table.rb
@@ -0,0 +1,144 @@
+module Groonga
+ class Table
+ include Enumerable
+ include Indexable
+
+ def columns
+ context = Context.instance
+ column_ids.collect do |id|
+ context[id]
+ end
+ end
+
+ def each
+ flags =
+ TableCursorFlags::ASCENDING |
+ TableCursorFlags::BY_ID
+ TableCursor.open(self, :flags => flags) do |cursor|
+ cursor.each do |id|
+ yield(id)
+ end
+ end
+ end
+
+ def sort(keys, options={})
+ offset = options[:offset] || 0
+ limit = options[:limit] || -1
+ ensure_sort_keys(keys) do |sort_keys|
+ sorted = Array.create("", self)
+ begin
+ sort_raw(sort_keys, offset, limit, sorted)
+ rescue Exception
+ sorted.close
+ raise
+ end
+ sorted
+ end
+ end
+
+ def group(keys, result)
+ ensure_sort_keys(keys) do |sort_keys|
+ group_raw(sort_keys, result)
+ end
+ end
+
+ def apply_window_function(output_column,
+ window_function_call,
+ options={})
+ ensure_sort_keys_accept_nil(options[:sort_keys]) do |sort_keys|
+ ensure_sort_keys_accept_nil(options[:group_keys]) do |group_keys|
+ window_definition = WindowDefinition.new
+ begin
+ window_definition.sort_keys = sort_keys
+ window_definition.group_keys = group_keys
+ apply_window_function_raw(output_column,
+ window_definition,
+ window_function_call)
+ ensure
+ window_definition.close
+ end
+ end
+ end
+ end
+
+ private
+ def ensure_sort_keys_accept_nil(keys, &block)
+ return yield(nil) if keys.nil?
+
+ ensure_sort_keys(keys, &block)
+ end
+
+ def ensure_sort_keys(keys)
+ if keys.is_a?(::Array) and keys.all? {|key| key.is_a?(TableSortKey)}
+ return yield(keys)
+ end
+
+ converted_keys = []
+
+ begin
+ keys = [keys] unless keys.is_a?(::Array)
+ sort_keys = keys.collect do |key|
+ ensure_sort_key(key, converted_keys)
+ end
+ yield(sort_keys)
+ ensure
+ converted_keys.each do |converted_key|
+ converted_key.close
+ end
+ end
+ end
+
+ def ensure_sort_key(key, converted_keys)
+ return key if key.is_a?(TableSortKey)
+
+ sort_key = TableSortKey.new
+ converted_keys << sort_key
+
+ key_name = nil
+ order = :ascending
+ offset = 0
+ if key.is_a?(::Hash)
+ key_name = key[:key]
+ order = key[:order] || order
+ offset = key[:offset] || offset
+ else
+ key_name = key
+ end
+
+ case key_name
+ when String
+ # Do nothing
+ when Symbol
+ key_name = key_name.to_s
+ else
+ message = "sort key name must be String or Symbol: " +
+ "#{key_name.inspect}: #{key.inspect}"
+ raise ArgumentError, message
+ end
+
+ if key_name.start_with?("-")
+ key_name[0] = ""
+ order = :descending
+ elsif key_name.start_with?("+")
+ key_name[0] = ""
+ end
+
+ key = find_column(key_name)
+ if key.nil?
+ table_name = name || "(temporary)"
+ message = "unknown key: #{key_name.inspect}: "
+ message << "#{table_name}(#{size})"
+ raise ArgumentError, message
+ end
+
+ sort_key.key = key
+ if order == :ascending
+ sort_key.flags = Groonga::TableSortFlags::ASCENDING
+ else
+ sort_key.flags = Groonga::TableSortFlags::DESCENDING
+ end
+ sort_key.offset = offset
+ sort_key
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/table_cursor.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/table_cursor.rb
new file mode 100644
index 00000000..45949b71
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/table_cursor.rb
@@ -0,0 +1,28 @@
+module Groonga
+ class TableCursor
+ include Enumerable
+
+ class << self
+ def open(*arguments)
+ cursor = open_raw(*arguments)
+ if block_given?
+ begin
+ yield(cursor)
+ ensure
+ cursor.close
+ end
+ else
+ cursor
+ end
+ end
+ end
+
+ def each
+ loop do
+ id = self.next
+ return if id == Groonga::ID::NIL
+ yield(id)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/variable_size_column.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/variable_size_column.rb
new file mode 100644
index 00000000..3d75502f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/variable_size_column.rb
@@ -0,0 +1,5 @@
+module Groonga
+ class VariableSizeColumn
+ include Indexable
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/scripts/writer.rb b/storage/mroonga/vendor/groonga/lib/mrb/scripts/writer.rb
new file mode 100644
index 00000000..de2bc261
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/scripts/writer.rb
@@ -0,0 +1,21 @@
+module Groonga
+ class Writer
+ def array(name, n_elements)
+ open_array(name, n_elements)
+ begin
+ yield
+ ensure
+ close_array
+ end
+ end
+
+ def map(name, n_elements)
+ open_map(name, n_elements)
+ begin
+ yield
+ ensure
+ close_map
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/lib/mrb/sources.am b/storage/mroonga/vendor/groonga/lib/mrb/sources.am
new file mode 100644
index 00000000..9db16737
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/mrb/sources.am
@@ -0,0 +1,93 @@
+libgrnmrb_la_SOURCES = \
+ mrb_accessor.c \
+ mrb_accessor.h \
+ mrb_array.c \
+ mrb_array.h \
+ mrb_bulk.c \
+ mrb_bulk.h \
+ mrb_cache.c \
+ mrb_cache.h \
+ mrb_column.c \
+ mrb_column.h \
+ mrb_command.c \
+ mrb_command.h \
+ mrb_command_input.c \
+ mrb_command_input.h \
+ mrb_command_version.c \
+ mrb_command_version.h \
+ mrb_config.c \
+ mrb_config.h \
+ mrb_content_type.c \
+ mrb_content_type.h \
+ mrb_converter.c \
+ mrb_converter.h \
+ mrb_ctx.c \
+ mrb_ctx.h \
+ mrb_database.c \
+ mrb_database.h \
+ mrb_double_array_trie.c \
+ mrb_double_array_trie.h \
+ mrb_error.c \
+ mrb_error.h \
+ mrb_eval_context.c \
+ mrb_eval_context.h \
+ mrb_expr.c \
+ mrb_expr.h \
+ mrb_fixed_size_column.c \
+ mrb_fixed_size_column.h \
+ mrb_hash_table.c \
+ mrb_hash_table.h \
+ mrb_id.c \
+ mrb_id.h \
+ mrb_indexable.c \
+ mrb_indexable.h \
+ mrb_index_column.c \
+ mrb_index_column.h \
+ mrb_index_cursor.c \
+ mrb_index_cursor.h \
+ mrb_logger.c \
+ mrb_logger.h \
+ mrb_object.c \
+ mrb_object.h \
+ mrb_object_flags.c \
+ mrb_object_flags.h \
+ mrb_operator.c \
+ mrb_operator.h \
+ mrb_options.c \
+ mrb_options.h \
+ mrb_patricia_trie.c \
+ mrb_patricia_trie.h \
+ mrb_pointer.c \
+ mrb_pointer.h \
+ mrb_procedure.c \
+ mrb_procedure.h \
+ mrb_query_logger.c \
+ mrb_query_logger.h \
+ mrb_record.c \
+ mrb_record.h \
+ mrb_table.c \
+ mrb_table.h \
+ mrb_table_cursor.c \
+ mrb_table_cursor.h \
+ mrb_table_cursor_flags.c \
+ mrb_table_cursor_flags.h \
+ mrb_table_group_flags.c \
+ mrb_table_group_flags.h \
+ mrb_table_group_result.c \
+ mrb_table_group_result.h \
+ mrb_table_sort_flags.c \
+ mrb_table_sort_flags.h \
+ mrb_table_sort_key.c \
+ mrb_table_sort_key.h \
+ mrb_thread.c \
+ mrb_thread.h \
+ mrb_type.c \
+ mrb_type.h \
+ mrb_variable_size_column.c \
+ mrb_variable_size_column.h \
+ mrb_void.c \
+ mrb_void.h \
+ mrb_window_definition.c \
+ mrb_window_definition.h \
+ mrb_writer.c \
+ mrb_writer.h
diff --git a/storage/mroonga/vendor/groonga/lib/nfkc-custom-rules.txt b/storage/mroonga/vendor/groonga/lib/nfkc-custom-rules.txt
new file mode 100644
index 00000000..496751a5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/nfkc-custom-rules.txt
@@ -0,0 +1 @@
+〜 ~
diff --git a/storage/mroonga/vendor/groonga/lib/nfkc.c b/storage/mroonga/vendor/groonga/lib/nfkc.c
new file mode 100644
index 00000000..e83fe610
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/nfkc.c
@@ -0,0 +1,45 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_nfkc.h"
+#include <groonga/nfkc.h>
+
+#ifdef GRN_WITH_NFKC
+
+grn_char_type
+grn_nfkc_char_type(const unsigned char *utf8)
+{
+ return grn_nfkc50_char_type(utf8);
+}
+
+const char *
+grn_nfkc_decompose(const unsigned char *utf8)
+{
+ return grn_nfkc50_decompose(utf8);
+}
+
+const char *
+grn_nfkc_compose(const unsigned char *prefix_utf8,
+ const unsigned char *suffix_utf8)
+{
+ return grn_nfkc50_compose(prefix_utf8, suffix_utf8);
+}
+
+#endif /* GRN_WITH_NFKC */
+
diff --git a/storage/mroonga/vendor/groonga/lib/nfkc.rb b/storage/mroonga/vendor/groonga/lib/nfkc.rb
new file mode 100755
index 00000000..0c0e7fe7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/nfkc.rb
@@ -0,0 +1,897 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+#
+# Copyright(C) 2010-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+CUSTOM_RULE_PATH = 'nfkc-custom-rules.txt'
+
+class SwitchGenerator
+ def initialize(unicode_version, output)
+ @unicode_version = unicode_version
+ @output = output
+ end
+
+ def generate(bc, decompose_map, compose_map)
+ STDERR.puts('generating char type code..')
+ generate_blockcode_char_type(bc)
+ STDERR.puts('generating decompose code..')
+ generate_decompose(decompose_map)
+ STDERR.puts('generating compose code..')
+ generate_compose(compose_map)
+ end
+
+ private
+ def generate_blockcode_char_type(bc)
+ @output.puts(<<-HEADER)
+
+grn_char_type
+grn_nfkc#{@unicode_version}_char_type(const unsigned char *str)
+{
+ HEADER
+
+ @lv = 0
+ gen_bc(bc, 0)
+
+ @output.puts(<<-FOOTER)
+ return -1;
+}
+ FOOTER
+ end
+
+ def gen_bc(hash, level)
+ bl = ' ' * (level * 2)
+ h2 = {}
+ hash.each{|key,val|
+ key = key.dup
+ key.force_encoding("ASCII-8BIT")
+ head = key.bytes[0]
+ rest = key[1..-1]
+ if h2[head]
+ h2[head][rest] = val
+ else
+ h2[head] = {rest => val}
+ end
+ }
+ if h2.size < 3
+ h2.keys.sort.each{|k|
+ if (0x80 < k)
+ @output.printf("#{bl}if (str[#{level}] < 0x%02X) { return #{@lv}; }\n", k)
+ end
+ h = h2[k]
+ if h.keys.join =~ /^\x80*$/n
+ @lv, = h.values
+ else
+ @output.printf("#{bl}if (str[#{level}] == 0x%02X) {\n", k)
+ gen_bc(h, level + 1)
+ @output.puts bl + '}'
+ end
+ }
+ @output.puts bl + "return #{@lv};"
+ else
+ @output.puts bl + "switch (str[#{level}]) {"
+ lk = 0x80
+ br = true
+ h2.keys.sort.each{|k|
+ if (lk < k)
+ for j in lk..k-1
+ @output.printf("#{bl}case 0x%02X :\n", j)
+ end
+ br = false
+ end
+ unless br
+ @output.puts bl + " return #{@lv};"
+ @output.puts bl + ' break;'
+ end
+ h = h2[k]
+ @output.printf("#{bl}case 0x%02X :\n", k)
+ if h.keys.join =~ /^\x80*$/n
+ @lv, = h.values
+ br = false
+ else
+ gen_bc(h, level + 1)
+ @output.puts bl + ' break;'
+ br = true
+ end
+ lk = k + 1
+ }
+ @output.puts bl + 'default :'
+ @output.puts bl + " return #{@lv};"
+ @output.puts bl + ' break;'
+ @output.puts bl + '}'
+ end
+ end
+
+ def generate_decompose(hash)
+ @output.puts(<<-HEADER)
+
+const char *
+grn_nfkc#{@unicode_version}_decompose(const unsigned char *str)
+{
+ HEADER
+
+ gen_decompose(hash, 0)
+
+ @output.puts(<<-FOOTER)
+ return 0;
+}
+ FOOTER
+ end
+
+ def gen_decompose(hash, level)
+ bl = ' ' * ((level + 0) * 2)
+ if hash['']
+ dst = ''
+ hash[''].each_byte{|b| dst << format('\x%02X', b)}
+ @output.puts "#{bl}return \"#{dst}\";"
+ hash.delete('')
+ end
+ return if hash.empty?
+ h2 = {}
+ hash.each{|key,val|
+ key = key.dup
+ key.force_encoding("ASCII-8BIT")
+ head = key.bytes[0]
+ rest = key[1..-1]
+ if h2[head]
+ h2[head][rest] = val
+ else
+ h2[head] = {rest => val}
+ end
+ }
+ if h2.size == 1
+ h2.each{|key,val|
+ @output.printf("#{bl}if (str[#{level}] == 0x%02X) {\n", key)
+ gen_decompose(val, level + 1)
+ @output.puts bl + '}'
+ }
+ else
+ @output.puts "#{bl}switch (str[#{level}]) {"
+ h2.keys.sort.each{|k|
+ @output.printf("#{bl}case 0x%02X :\n", k)
+ gen_decompose(h2[k], level + 1)
+ @output.puts("#{bl} break;")
+ }
+ @output.puts bl + '}'
+ end
+ end
+
+ def generate_compose(compose_map)
+ @output.puts(<<-HEADER)
+
+const char *
+grn_nfkc#{@unicode_version}_compose(const unsigned char *prefix, const unsigned char *suffix)
+{
+ HEADER
+ suffix = {}
+ compose_map.each{|src,dst|
+ chars = src.chars
+ if chars.size != 2
+ STDERR.puts "caution: more than two chars in pattern #{chars.join('|')}"
+ end
+ s = chars.pop
+ if suffix[s]
+ suffix[s][chars.join] = dst
+ else
+ suffix[s] = {chars.join=>dst}
+ end
+ }
+ gen_compose_sub(suffix, 0)
+ @output.puts(<<-FOOTER)
+ return 0;
+}
+ FOOTER
+ end
+
+ def gen_compose_sub2(hash, level, indent)
+ bl = ' ' * ((level + indent + 0) * 2)
+ if hash['']
+ @output.print "#{bl}return \""
+ hash[''].each_byte{|b| @output.printf('\x%02X', b)}
+ @output.puts "\";"
+ hash.delete('')
+ end
+ return if hash.empty?
+
+ h2 = {}
+ hash.each{|key,val|
+ key = key.dup
+ key.force_encoding("ASCII-8BIT")
+ head = key.bytes[0]
+ rest = key[1..-1]
+ if h2[head]
+ h2[head][rest] = val
+ else
+ h2[head] = {rest => val}
+ end
+ }
+
+ if h2.size == 1
+ h2.each{|key,val|
+ @output.printf("#{bl}if (prefix[#{level}] == 0x%02X) {\n", key)
+ gen_compose_sub2(val, level + 1, indent)
+ @output.puts bl + '}'
+ }
+ else
+ @output.puts "#{bl}switch (prefix[#{level}]) {"
+ h2.keys.sort.each{|k|
+ @output.printf("#{bl}case 0x%02X :\n", k)
+ gen_compose_sub2(h2[k], level + 1, indent)
+ @output.puts("#{bl} break;")
+ }
+ @output.puts bl + '}'
+ end
+ end
+
+ def gen_compose_sub(hash, level)
+ bl = ' ' * ((level + 0) * 2)
+ if hash['']
+ gen_compose_sub2(hash[''], 0, level)
+ hash.delete('')
+ end
+ return if hash.empty?
+ h2 = {}
+ hash.each{|key,val|
+ key = key.dup
+ key.force_encoding("ASCII-8BIT")
+ head = key.bytes[0]
+ rest = key[1..-1]
+ if h2[head]
+ h2[head][rest] = val
+ else
+ h2[head] = {rest => val}
+ end
+ }
+ if h2.size == 1
+ h2.each{|key,val|
+ @output.printf("#{bl}if (suffix[#{level}] == 0x%02X) {\n", key)
+ gen_compose_sub(val, level + 1)
+ @output.puts bl + '}'
+ }
+ else
+ @output.puts "#{bl}switch (suffix[#{level}]) {"
+ h2.keys.sort.each{|k|
+ @output.printf("#{bl}case 0x%02X :\n", k)
+ gen_compose_sub(h2[k], level + 1)
+ @output.puts("#{bl} break;")
+ }
+ @output.puts bl + '}'
+ end
+ end
+end
+
+class TableGenerator < SwitchGenerator
+ private
+ def name_prefix
+ "grn_nfkc#{@unicode_version}_"
+ end
+
+ def table_name(type, common_bytes)
+ suffix = common_bytes.collect {|byte| "%02x" % byte}.join("")
+ "#{name_prefix}#{type}_table_#{suffix}"
+ end
+
+ def function_name(type)
+ "#{name_prefix}#{type}"
+ end
+
+ def generate_char_convert_tables(type, return_type, byte_size_groups)
+ if return_type.end_with?("*")
+ space = ""
+ else
+ space = " "
+ end
+ byte_size_groups.keys.sort.each do |common_bytes|
+ chars = byte_size_groups[common_bytes]
+ lines = []
+ all_values = []
+ last_bytes = chars.collect {|char| char.bytes.last}
+ last_bytes.min.step(last_bytes.max).each_slice(8) do |slice|
+ values = slice.collect do |last_byte|
+ char = (common_bytes + [last_byte]).pack("c*")
+ char.force_encoding("UTF-8")
+ yield(char)
+ end
+ all_values.concat(values)
+ lines << (" " + values.join(", "))
+ end
+
+ next if all_values.uniq.size == 1
+
+ @output.puts(<<-TABLE_HEADER)
+
+static #{return_type}#{space}#{table_name(type, common_bytes)}[] = {
+ TABLE_HEADER
+ @output.puts(lines.join(",\n"))
+ @output.puts(<<-TABLE_FOOTER)
+};
+ TABLE_FOOTER
+ end
+ end
+
+ def generate_char_convert_function(type,
+ argument_list,
+ char_variable,
+ default,
+ return_type,
+ byte_size_groups,
+ options={})
+ modifier = options[:internal] ? "static inline " : ""
+ @output.puts(<<-HEADER)
+
+#{modifier}#{return_type}
+#{function_name(type)}(#{argument_list})
+{
+ HEADER
+
+ prev_common_bytes = []
+ prev_n_common_bytes = 0
+ first_group = true
+ byte_size_groups.keys.sort.each do |common_bytes|
+ chars = byte_size_groups[common_bytes]
+ chars_bytes = chars.collect(&:bytes).sort
+ min = chars_bytes.first.last
+ max = chars_bytes.last.last
+ n_common_bytes = 0
+ if common_bytes.empty?
+ indent = " "
+ yield(:no_common_bytes, indent, chars, chars_bytes)
+ else
+ if first_group
+ @output.puts(<<-BODY)
+ {
+ BODY
+ end
+
+ found_different_byte = false
+ common_bytes.each_with_index do |common_byte, i|
+ unless found_different_byte
+ if prev_common_bytes[i] == common_byte
+ n_common_bytes += 1
+ next
+ end
+ found_different_byte = true
+ end
+ indent = " " * i
+ # p [i, prev_common_bytes.collect{|x| "%#04x" % x}, common_bytes.collect{|x| "%#04x" % x}, "%#04x" % common_byte, n_common_bytes, prev_n_common_bytes]
+ # TODO: The following code may be able to be simplified.
+ if prev_common_bytes[i].nil?
+ # p nil
+ @output.puts(<<-BODY)
+ #{indent}switch (#{char_variable}[#{i}]) {
+ BODY
+ elsif i < prev_n_common_bytes
+ # p :prev
+ @output.puts(<<-BODY)
+ #{indent} default :
+ #{indent} break;
+ #{indent} }
+ #{indent} break;
+ BODY
+ elsif n_common_bytes < prev_n_common_bytes
+ # p :common_prev
+ @output.puts(<<-BODY)
+ #{indent}switch (#{char_variable}[#{i}]) {
+ BODY
+ else
+ # p :else
+ prev_common_bytes.size.downto(common_bytes.size + 1) do |j|
+ sub_indent = " " * (j - 1)
+ @output.puts(<<-BODY)
+ #{indent}#{sub_indent}default :
+ #{indent}#{sub_indent} break;
+ #{indent}#{sub_indent}}
+ #{indent}#{sub_indent}break;
+ BODY
+ end
+ end
+ @output.puts(<<-BODY)
+ #{indent}case #{"%#04x" % common_byte} :
+ BODY
+ end
+
+ n = chars_bytes.first.size - 1
+ indent = " " + (" " * common_bytes.size)
+ yield(:have_common_bytes, indent, chars, chars_bytes, n, common_bytes)
+ end
+
+ prev_common_bytes = common_bytes
+ prev_n_common_bytes = n_common_bytes
+ first_group = false
+ end
+
+ # p [prev_common_bytes.collect{|x| "%#04x" % x}, prev_n_common_bytes]
+
+ (prev_common_bytes.size - 1).step(0, -1) do |i|
+ indent = " " * i
+ @output.puts(<<-BODY)
+ #{indent}default :
+ #{indent} break;
+ #{indent}}
+ BODY
+ if i > 0
+ @output.puts(<<-BODY)
+ #{indent}break;
+ BODY
+ end
+ end
+
+ @output.puts(<<-FOOTER)
+ }
+
+ return #{default};
+}
+ FOOTER
+ end
+
+ def generate_char_converter(type,
+ function_type,
+ char_map,
+ default,
+ return_type,
+ options={},
+ &converter)
+ byte_size_groups = char_map.keys.group_by do |from|
+ bytes = from.bytes
+ bytes[0..-2]
+ end
+
+ generate_char_convert_tables(type,
+ return_type,
+ byte_size_groups,
+ &converter)
+
+ char_variable = "utf8"
+ generate_char_convert_function(function_type,
+ "const unsigned char *#{char_variable}",
+ char_variable,
+ default,
+ return_type,
+ byte_size_groups,
+ options) do |state, *args|
+ case state
+ when :no_common_bytes
+ indent, chars, chars_bytes = args
+ if chars.size == 1
+ char = chars[0]
+ char_byte = chars_bytes.first.first
+ value = yield(char)
+ @output.puts(<<-BODY)
+#{indent}if (#{char_variable}[0] < 0x80) {
+#{indent} if (#{char_variable}[0] == #{"%#04x" % char_byte}) {
+#{indent} return #{value};
+#{indent} } else {
+#{indent} return #{default};
+#{indent} }
+#{indent}} else {
+ BODY
+ else
+ min = chars_bytes.first.first
+ max = chars_bytes.last.first
+ @output.puts(<<-BODY)
+#{indent}if (#{char_variable}[0] < 0x80) {
+#{indent} if (#{char_variable}[0] >= #{"%#04x" % min} &&
+#{indent} #{char_variable}[0] <= #{"%#04x" % max}) {
+#{indent} return #{table_name(type, [])}[#{char_variable}[0] - #{"%#04x" % min}];
+#{indent} } else {
+#{indent} return #{default};
+#{indent} }
+#{indent}} else {
+ BODY
+ end
+ when :have_common_bytes
+ indent, chars, chars_bytes, n, common_bytes = args
+ if chars.size == 1
+ char = chars[0]
+ char_byte = chars_bytes.first.last
+ value = yield(char)
+ @output.puts(<<-BODY)
+#{indent}if (#{char_variable}[#{n}] == #{"%#04x" % char_byte}) {
+#{indent} return #{value};
+#{indent}}
+#{indent}break;
+ BODY
+ else
+ sorted_chars = chars.sort
+ min = chars_bytes.first.last
+ max = chars_bytes.last.last
+ all_values = (min..max).collect do |last_byte|
+ char = (common_bytes + [last_byte]).pack("c*")
+ char.force_encoding("UTF-8")
+ yield(char)
+ end
+ if all_values.uniq.size == 1
+ value = all_values.first
+ else
+ value = "#{table_name(type, common_bytes)}[#{char_variable}[#{n}] - #{"%#04x" % min}]"
+ end
+ last_n_bits_for_char_in_utf8 = 6
+ max_n_chars_in_byte = 2 ** last_n_bits_for_char_in_utf8
+ if all_values.size == max_n_chars_in_byte
+ @output.puts(<<-BODY)
+#{indent}return #{value};
+ BODY
+ else
+ @output.puts(<<-BODY)
+#{indent}if (#{char_variable}[#{n}] >= #{"%#04x" % min} &&
+#{indent} #{char_variable}[#{n}] <= #{"%#04x" % max}) {
+#{indent} return #{value};
+#{indent}}
+#{indent}break;
+ BODY
+ end
+ end
+ end
+ end
+ end
+
+ def generate_blockcode_char_type(block_codes)
+ default = "GRN_CHAR_OTHERS"
+
+ char_types = {}
+ current_type = default
+ prev_char = nil
+ block_codes.keys.sort.each do |char|
+ type = block_codes[char]
+ if current_type != default
+ prev_code_point = prev_char.codepoints[0]
+ code_point = char.codepoints[0]
+ (prev_code_point...code_point).each do |target_code_point|
+ target_char = [target_code_point].pack("U*")
+ char_types[target_char] = current_type
+ end
+ end
+ current_type = type
+ prev_char = char
+ end
+ unless current_type == default
+ raise "TODO: Consider the max unicode character"
+ max_unicode_char = "\u{10ffff}"
+ (prev_char..max_unicode_char).each do |target_char|
+ char_types[target_char] = current_type
+ end
+ end
+
+ generate_char_converter("char_type",
+ "char_type",
+ char_types,
+ default,
+ "grn_char_type") do |char|
+ char_types[char] || default
+ end
+ end
+
+ def generate_decompose(decompose_map)
+ default = "NULL"
+ generate_char_converter("decompose",
+ "decompose",
+ decompose_map,
+ default,
+ "const char *") do |from|
+ to = decompose_map[from]
+ if to
+ escaped_value = to.bytes.collect {|char| "\\x%02x" % char}.join("")
+ "\"#{escaped_value}\""
+ else
+ default
+ end
+ end
+ end
+
+ def generate_compose(compose_map)
+ # require "pp"
+ # p compose_map.size
+ # pp compose_map.keys.group_by {|x| x.chars[1]}.size
+ # pp compose_map.keys.group_by {|x| x.chars[1]}.collect {|k, vs| [k, k.codepoints, vs.size, vs.group_by {|x| x.chars[0].bytesize}.collect {|k2, vs2| [k2, vs2.size]}]}
+ # pp compose_map.keys.group_by {|x| x.chars[0].bytesize}.collect {|k, vs| [k, vs.size]}
+ # pp compose_map
+
+ suffix_char_map = {}
+ compose_map.each do |source, destination|
+ chars = source.chars
+ if chars.size != 2
+ STDERR.puts "caution: more than two chars in pattern #{chars.join('|')}"
+ return
+ end
+ prefix, suffix = chars
+ suffix_char_map[suffix] ||= {}
+ suffix_char_map[suffix][prefix] = destination
+ end
+
+ suffix_char_map.each do |suffix, prefix_char_map|
+ suffix_bytes = suffix.bytes.collect {|byte| "%02x" % byte}.join("")
+ default = "NULL"
+ generate_char_converter("compose_prefix_#{suffix_bytes}",
+ "compose_prefix_#{suffix_bytes}",
+ prefix_char_map,
+ default,
+ "const char *",
+ :internal => true) do |prefix|
+ to = prefix_char_map[prefix]
+ if to
+ escaped_value = to.bytes.collect {|char| "\\x%02x" % char}.join("")
+ "\"#{escaped_value}\""
+ else
+ default
+ end
+ end
+ end
+
+
+ char_variable = "suffix_utf8"
+ argument_list =
+ "const unsigned char *prefix_utf8, " +
+ "const unsigned char *#{char_variable}"
+ default = "NULL"
+ byte_size_groups = suffix_char_map.keys.group_by do |from|
+ bytes = from.bytes
+ bytes[0..-2]
+ end
+ generate_char_convert_function("compose",
+ argument_list,
+ char_variable,
+ default,
+ "const char *",
+ byte_size_groups) do |type, *args|
+ case type
+ when :no_common_bytes
+ indent, chars, chars_bytes = args
+ @output.puts(<<-BODY)
+#{indent}switch (#{char_variable}[0]) {
+ BODY
+ chars.each do |char|
+ suffix_bytes = char.bytes.collect {|byte| "%02x" % byte}.join("")
+ type = "compose_prefix_#{suffix_bytes}"
+ @output.puts(<<-BODY)
+#{indent}case #{"%#04x" % char.bytes.last} :
+#{indent} return #{function_name(type)}(prefix_utf8);
+ BODY
+ end
+ @output.puts(<<-BODY)
+#{indent}default :
+#{indent} return #{default};
+#{indent}}
+#{indent}break;
+ BODY
+ when :have_common_bytes
+ indent, chars, chars_bytes, n, common_bytes = args
+ @output.puts(<<-BODY)
+#{indent}switch (#{char_variable}[#{n}]) {
+ BODY
+ chars.each do |char|
+ suffix_bytes = char.bytes.collect {|byte| "%02x" % byte}.join("")
+ type = "compose_prefix_#{suffix_bytes}"
+ @output.puts(<<-BODY)
+#{indent}case #{"%#04x" % char.bytes.last} :
+#{indent} return #{function_name(type)}(prefix_utf8);
+ BODY
+ end
+ @output.puts(<<-BODY)
+#{indent}default :
+#{indent} return #{default};
+#{indent}}
+#{indent}break;
+ BODY
+ end
+ end
+ end
+
+ def to_bytes_map(char_map)
+ bytes_map = {}
+ char_map.each_key do |from|
+ parent = bytes_map
+ from.bytes[0..-2].each do |byte|
+ parent[byte] ||= {}
+ parent = parent[byte]
+ end
+ parent[from.bytes.last] = char_map[from]
+ end
+ bytes_map
+ end
+end
+
+def create_bc(option)
+ bc = {}
+ open("|./icudump --#{option}").each{|l|
+ src,_,code = l.chomp.split("\t")
+ str = src.split(':').collect(&:hex).pack("c*")
+ str.force_encoding("UTF-8")
+ bc[str] = code
+ }
+ bc
+end
+
+def ccpush(hash, src, dst)
+ head = src.shift
+ hash[head] = {} unless hash[head]
+ if head
+ ccpush(hash[head], src, dst)
+ else
+ hash[head] = dst
+ end
+end
+
+def subst(hash, str)
+ cand = nil
+ src = str.chars
+ for i in 0..src.size-1
+ h = hash
+ for j in i..src.size-1
+ head = src[j]
+ h = h[head]
+ break unless h
+ if h[nil]
+ cand = src[0,i].join("") + h[nil] + src[j + 1..-1].join("")
+ end
+ end
+ return cand if cand
+ end
+ return str
+end
+
+def map_entry(decompose, cc, src, dst)
+ dst.downcase! unless $case_sensitive
+ loop {
+ dst2 = subst(cc, dst)
+ break if dst2 == dst
+ dst = dst2
+ }
+ unless $keep_space
+ dst = $1 if dst =~ /^ +([^ ].*)$/
+ end
+ decompose[src] = dst if src != dst
+end
+
+def create_decompose_map()
+ cc = {}
+ open('|./icudump --cc').each{|l|
+ _,src,dst = l.chomp.split("\t")
+ if cc[src]
+ STDERR.puts "caution: ambiguous mapping #{src}|#{cc[src]}|#{dst}" if cc[src] != dst
+ end
+ ccpush(cc, src.chars, dst)
+ }
+ decompose_map = {}
+ open('|./icudump --nfkd').each{|l|
+ n,src,dst = l.chomp.split("\t")
+ map_entry(decompose_map, cc, src, dst)
+ }
+ if File.readable?(CUSTOM_RULE_PATH)
+ open(CUSTOM_RULE_PATH).each{|l|
+ src,dst = l.chomp.split("\t")
+ map_entry(decompose_map, cc, src, dst)
+ }
+ end
+ unless $case_sensitive
+ for c in 'A'..'Z'
+ decompose_map[c] = c.downcase
+ end
+ end
+ return decompose_map
+end
+
+def create_compose_map(decompose_map)
+ cc = {}
+ open('|./icudump --cc').each{|l|
+ _,src,dst = l.chomp.split("\t")
+ src = src.chars.collect{|c| decompose_map[c] || c}.join
+ dst = decompose_map[dst] || dst
+ if cc[src] && cc[src] != dst
+ STDERR.puts("caution: inconsitent mapping '#{src}' => '#{cc[src]}'|'#{dst}'")
+ end
+ cc[src] = dst if src != dst
+ }
+ loop {
+ noccur = 0
+ cc2 = {}
+ cc.each {|src,dst|
+ src2 = src
+ chars = src.chars
+ l = chars.size - 1
+ for i in 0..l
+ for j in i..l
+ next if i == 0 && j == l
+ str = chars[i..j].join
+ if decompose_map[str]
+ STDERR.printf("caution: recursive mapping '%s'=>'%s'\n",
+ str, decompose_map[str])
+ end
+ if cc[str]
+ src2 = (i > 0 ? chars[0..i-1].join : '') + cc[str] + (j < l ? chars[j+1..l].join : '')
+ noccur += 1
+ end
+ end
+ end
+ cc2[src2] = dst if src2 != dst
+ }
+ cc = cc2
+ STDERR.puts("substituted #{noccur} patterns.")
+ break if noccur == 0
+ STDERR.puts('try again..')
+ }
+ return cc
+end
+
+######## main #######
+
+generator_class = SwitchGenerator
+ARGV.each{|arg|
+ case arg
+ when /-*c/i
+ $case_sensitive = true
+ when /-*s/i
+ $keep_space = true
+ when "--impl=switch"
+ generator_class = SwitchGenerator
+ when "--impl=table"
+ generator_class = TableGenerator
+ end
+}
+
+STDERR.puts('compiling icudump')
+system('cc -Wall -O3 -o icudump -I/tmp/local/include -L/tmp/local/lib icudump.c -licuuc -licui18n')
+
+STDERR.puts('getting Unicode version')
+unicode_version = `./icudump --version`.strip.gsub(".", "")
+
+STDERR.puts('creating bc..')
+bc = create_bc("gc")
+
+STDERR.puts('creating decompose map..')
+decompose_map = create_decompose_map()
+
+STDERR.puts('creating compose map..')
+compose_map = create_compose_map(decompose_map)
+
+File.open("nfkc#{unicode_version}.c", "w") do |output|
+ output.puts(<<-HEADER)
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Don't edit this file by hand. it generated automatically by nfkc.rb.
+*/
+
+#include "grn.h"
+#include "grn_nfkc.h"
+#include <groonga/nfkc.h>
+
+#ifdef GRN_WITH_NFKC
+ HEADER
+
+ generator = generator_class.new(unicode_version, output)
+ generator.generate(bc, decompose_map, compose_map)
+
+ output.puts(<<-FOOTER)
+
+#endif /* GRN_WITH_NFKC */
+
+ FOOTER
+end
diff --git a/storage/mroonga/vendor/groonga/lib/nfkc50.c b/storage/mroonga/vendor/groonga/lib/nfkc50.c
new file mode 100644
index 00000000..f734e832
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/nfkc50.c
@@ -0,0 +1,77784 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/*
+ Don't edit this file by hand. it generated automatically by nfkc.rb.
+*/
+
+#include "grn.h"
+#include "grn_nfkc.h"
+#include <groonga/nfkc.h>
+
+#ifdef GRN_WITH_NFKC
+
+static grn_char_type grn_nfkc50_char_type_table_[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_c2[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_c3[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_cb[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_cd[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_ce[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_cf[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d2[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d4[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d5[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d6[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d7[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d8[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_d9[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_db[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_dc[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_de[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_df[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0a4[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0a5[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0a6[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0a7[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0a8[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0a9[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0aa[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0ab[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0ac[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0ad[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0ae[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0af[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b0[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b1[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b2[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b3[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b4[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b5[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b6[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b7[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b8[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0b9[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0ba[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0bb[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0bc[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0bd[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0be[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e0bf[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e180[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e181[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e183[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e185[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e186[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e189[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e18a[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e18b[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e18c[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e18d[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e18e[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e199[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e19a[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e19b[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e19c[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e19d[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e19f[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1a0[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1a5[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1a7[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1a8[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1ad[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1ba[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1bc[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1bd[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1be[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e1bf[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e280[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e281[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e282[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e284[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e285[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e286[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e291[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e292[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e293[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e29a[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e29c[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e29d[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e29e[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e29f[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2ac[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b0[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b1[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b3[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b4[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b5[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b6[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b7[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2b8[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e2bf[] = {
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e382[] = {
+ GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA,
+ GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA,
+ GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA,
+ GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA, GRN_CHAR_HIRAGANA,
+ GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA,
+ GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA,
+ GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA,
+ GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_e387[] = {
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI, GRN_CHAR_KANJI,
+ GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA,
+ GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA, GRN_CHAR_KATAKANA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_ea9c[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_eaa0[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_eaa1[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efac[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efad[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efb4[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efb6[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efb7[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efb8[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efb9[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efbc[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efbd[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_efbf[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09080[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09081[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09084[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09085[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09086[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f0908c[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f0908d[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_DIGIT, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f0908e[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f0908f[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_SYMBOL, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09092[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f090a0[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f090a4[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f090a8[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f090a9[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09291[] = {
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d84[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d85[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d86[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d89[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_SYMBOL
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d8d[] = {
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL,
+ GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_SYMBOL, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d91[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d92[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d93[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d94[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d95[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS,
+ GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d9a[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d9b[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d9c[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d9d[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d9e[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA
+};
+
+static grn_char_type grn_nfkc50_char_type_table_f09d9f[] = {
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_SYMBOL, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA,
+ GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_ALPHA, GRN_CHAR_OTHERS, GRN_CHAR_OTHERS, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT,
+ GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT, GRN_CHAR_DIGIT
+};
+
+grn_char_type
+grn_nfkc50_char_type(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x21 &&
+ utf8[0] <= 0x7e) {
+ return grn_nfkc50_char_type_table_[utf8[0] - 0x21];
+ } else {
+ return GRN_CHAR_OTHERS;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc2 :
+ if (utf8[1] >= 0xa1 &&
+ utf8[1] <= 0xbf) {
+ return grn_nfkc50_char_type_table_c2[utf8[1] - 0xa1];
+ }
+ break;
+ case 0xc3 :
+ return grn_nfkc50_char_type_table_c3[utf8[1] - 0x80];
+ case 0xc4 :
+ return GRN_CHAR_ALPHA;
+ case 0xc5 :
+ return GRN_CHAR_ALPHA;
+ case 0xc6 :
+ return GRN_CHAR_ALPHA;
+ case 0xc7 :
+ return GRN_CHAR_ALPHA;
+ case 0xc8 :
+ return GRN_CHAR_ALPHA;
+ case 0xc9 :
+ return GRN_CHAR_ALPHA;
+ case 0xca :
+ return GRN_CHAR_ALPHA;
+ case 0xcb :
+ return grn_nfkc50_char_type_table_cb[utf8[1] - 0x80];
+ case 0xcd :
+ if (utf8[1] >= 0xb4 &&
+ utf8[1] <= 0xbe) {
+ return grn_nfkc50_char_type_table_cd[utf8[1] - 0xb4];
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x84 &&
+ utf8[1] <= 0xbf) {
+ return grn_nfkc50_char_type_table_ce[utf8[1] - 0x84];
+ }
+ break;
+ case 0xcf :
+ return grn_nfkc50_char_type_table_cf[utf8[1] - 0x80];
+ case 0xd0 :
+ return GRN_CHAR_ALPHA;
+ case 0xd1 :
+ return GRN_CHAR_ALPHA;
+ case 0xd2 :
+ return grn_nfkc50_char_type_table_d2[utf8[1] - 0x80];
+ case 0xd3 :
+ return GRN_CHAR_ALPHA;
+ case 0xd4 :
+ return grn_nfkc50_char_type_table_d4[utf8[1] - 0x80];
+ case 0xd5 :
+ return grn_nfkc50_char_type_table_d5[utf8[1] - 0x80];
+ case 0xd6 :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xbe) {
+ return grn_nfkc50_char_type_table_d6[utf8[1] - 0x80];
+ }
+ break;
+ case 0xd7 :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xb4) {
+ return grn_nfkc50_char_type_table_d7[utf8[1] - 0x80];
+ }
+ break;
+ case 0xd8 :
+ if (utf8[1] >= 0x8b &&
+ utf8[1] <= 0xba) {
+ return grn_nfkc50_char_type_table_d8[utf8[1] - 0x8b];
+ }
+ break;
+ case 0xd9 :
+ return grn_nfkc50_char_type_table_d9[utf8[1] - 0x80];
+ case 0xda :
+ return GRN_CHAR_ALPHA;
+ case 0xdb :
+ return grn_nfkc50_char_type_table_db[utf8[1] - 0x80];
+ case 0xdc :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xaf) {
+ return grn_nfkc50_char_type_table_dc[utf8[1] - 0x80];
+ }
+ break;
+ case 0xdd :
+ if (utf8[1] >= 0x8d &&
+ utf8[1] <= 0xad) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xde :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xb1) {
+ return grn_nfkc50_char_type_table_de[utf8[1] - 0x80];
+ }
+ break;
+ case 0xdf :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xba) {
+ return grn_nfkc50_char_type_table_df[utf8[1] - 0x80];
+ }
+ break;
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0a4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e0a5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0a6[utf8[2] - 0x85];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x8e &&
+ utf8[2] <= 0xba) {
+ return grn_nfkc50_char_type_table_e0a7[utf8[2] - 0x8e];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_char_type_table_e0a8[utf8[2] - 0x85];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x99 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_char_type_table_e0a9[utf8[2] - 0x99];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0aa[utf8[2] - 0x85];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xb1) {
+ return grn_nfkc50_char_type_table_e0ab[utf8[2] - 0x90];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0ac[utf8[2] - 0x85];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x9c &&
+ utf8[2] <= 0xb1) {
+ return grn_nfkc50_char_type_table_e0ad[utf8[2] - 0x9c];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x83 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_char_type_table_e0ae[utf8[2] - 0x83];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0xa6 &&
+ utf8[2] <= 0xba) {
+ return grn_nfkc50_char_type_table_e0af[utf8[2] - 0xa6];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_char_type_table_e0b0[utf8[2] - 0x85];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0xa0 &&
+ utf8[2] <= 0xaf) {
+ return grn_nfkc50_char_type_table_e0b1[utf8[2] - 0xa0];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0b2[utf8[2] - 0x85];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x9e &&
+ utf8[2] <= 0xb2) {
+ return grn_nfkc50_char_type_table_e0b3[utf8[2] - 0x9e];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_char_type_table_e0b4[utf8[2] - 0x85];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0xa0 &&
+ utf8[2] <= 0xaf) {
+ return grn_nfkc50_char_type_table_e0b5[utf8[2] - 0xa0];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0b6[utf8[2] - 0x85];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_char_type_table_e0b7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e0b8[utf8[2] - 0x81];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x9b) {
+ return grn_nfkc50_char_type_table_e0b9[utf8[2] - 0x80];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0ba[utf8[2] - 0x81];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x9d) {
+ return grn_nfkc50_char_type_table_e0bb[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e0bc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xaa) {
+ return grn_nfkc50_char_type_table_e0bd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e0be[utf8[2] - 0x85];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x91) {
+ return grn_nfkc50_char_type_table_e0bf[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xaa) {
+ return grn_nfkc50_char_type_table_e180[utf8[2] - 0x80];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x95) {
+ return grn_nfkc50_char_type_table_e181[utf8[2] - 0x80];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0xa0 &&
+ utf8[2] <= 0xbf) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_char_type_table_e183[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ return GRN_CHAR_ALPHA;
+ case 0x85 :
+ return grn_nfkc50_char_type_table_e185[utf8[2] - 0x80];
+ case 0x86 :
+ return grn_nfkc50_char_type_table_e186[utf8[2] - 0x80];
+ case 0x87 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb9) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x88 :
+ return GRN_CHAR_ALPHA;
+ case 0x89 :
+ return grn_nfkc50_char_type_table_e189[utf8[2] - 0x80];
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_char_type_table_e18a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ return grn_nfkc50_char_type_table_e18b[utf8[2] - 0x80];
+ case 0x8c :
+ return grn_nfkc50_char_type_table_e18c[utf8[2] - 0x80];
+ case 0x8d :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_char_type_table_e18d[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8e :
+ return grn_nfkc50_char_type_table_e18e[utf8[2] - 0x80];
+ case 0x8f :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb4) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x91 :
+ return GRN_CHAR_ALPHA;
+ case 0x92 :
+ return GRN_CHAR_ALPHA;
+ case 0x93 :
+ return GRN_CHAR_ALPHA;
+ case 0x94 :
+ return GRN_CHAR_ALPHA;
+ case 0x95 :
+ return GRN_CHAR_ALPHA;
+ case 0x96 :
+ return GRN_CHAR_ALPHA;
+ case 0x97 :
+ return GRN_CHAR_ALPHA;
+ case 0x98 :
+ return GRN_CHAR_ALPHA;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb6) {
+ return grn_nfkc50_char_type_table_e199[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e19a[utf8[2] - 0x81];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_char_type_table_e19b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb6) {
+ return grn_nfkc50_char_type_table_e19c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_char_type_table_e19d[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb3) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_char_type_table_e19f[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa0 :
+ return grn_nfkc50_char_type_table_e1a0[utf8[2] - 0x80];
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb7) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa8) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x9c) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_char_type_table_e1a5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa9) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e1a7[utf8[2] - 0x81];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x9f) {
+ return grn_nfkc50_char_type_table_e1a8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xb3) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_char_type_table_e1ad[utf8[2] - 0x85];
+ }
+ break;
+ case 0xb4 :
+ return GRN_CHAR_ALPHA;
+ case 0xb5 :
+ return GRN_CHAR_ALPHA;
+ case 0xb6 :
+ return GRN_CHAR_ALPHA;
+ case 0xb8 :
+ return GRN_CHAR_ALPHA;
+ case 0xb9 :
+ return GRN_CHAR_ALPHA;
+ case 0xba :
+ return grn_nfkc50_char_type_table_e1ba[utf8[2] - 0x80];
+ case 0xbb :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb9) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xbc :
+ return grn_nfkc50_char_type_table_e1bc[utf8[2] - 0x80];
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_e1bd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ return grn_nfkc50_char_type_table_e1be[utf8[2] - 0x80];
+ case 0xbf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_char_type_table_e1bf[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe2 :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e280[utf8[2] - 0x90];
+ }
+ break;
+ case 0x81 :
+ return grn_nfkc50_char_type_table_e281[utf8[2] - 0x80];
+ case 0x82 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb5) {
+ return grn_nfkc50_char_type_table_e282[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ return grn_nfkc50_char_type_table_e284[utf8[2] - 0x80];
+ case 0x85 :
+ return grn_nfkc50_char_type_table_e285[utf8[2] - 0x80];
+ case 0x86 :
+ return grn_nfkc50_char_type_table_e286[utf8[2] - 0x80];
+ case 0x87 :
+ return GRN_CHAR_SYMBOL;
+ case 0x88 :
+ return GRN_CHAR_SYMBOL;
+ case 0x89 :
+ return GRN_CHAR_SYMBOL;
+ case 0x8a :
+ return GRN_CHAR_SYMBOL;
+ case 0x8b :
+ return GRN_CHAR_SYMBOL;
+ case 0x8c :
+ return GRN_CHAR_SYMBOL;
+ case 0x8d :
+ return GRN_CHAR_SYMBOL;
+ case 0x8e :
+ return GRN_CHAR_SYMBOL;
+ case 0x8f :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa7) {
+ return GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa6) {
+ return GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 0x91 :
+ return grn_nfkc50_char_type_table_e291[utf8[2] - 0x80];
+ case 0x92 :
+ return grn_nfkc50_char_type_table_e292[utf8[2] - 0x80];
+ case 0x93 :
+ return grn_nfkc50_char_type_table_e293[utf8[2] - 0x80];
+ case 0x94 :
+ return GRN_CHAR_SYMBOL;
+ case 0x95 :
+ return GRN_CHAR_SYMBOL;
+ case 0x96 :
+ return GRN_CHAR_SYMBOL;
+ case 0x97 :
+ return GRN_CHAR_SYMBOL;
+ case 0x98 :
+ return GRN_CHAR_SYMBOL;
+ case 0x99 :
+ return GRN_CHAR_SYMBOL;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb2) {
+ return grn_nfkc50_char_type_table_e29a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_e29c[utf8[2] - 0x81];
+ }
+ break;
+ case 0x9d :
+ return grn_nfkc50_char_type_table_e29d[utf8[2] - 0x80];
+ case 0x9e :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_char_type_table_e29e[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9f :
+ return grn_nfkc50_char_type_table_e29f[utf8[2] - 0x80];
+ case 0xa0 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa1 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa2 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa3 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa4 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa5 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa6 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa7 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa8 :
+ return GRN_CHAR_SYMBOL;
+ case 0xa9 :
+ return GRN_CHAR_SYMBOL;
+ case 0xaa :
+ return GRN_CHAR_SYMBOL;
+ case 0xab :
+ return GRN_CHAR_SYMBOL;
+ case 0xac :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa3) {
+ return grn_nfkc50_char_type_table_e2ac[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ return grn_nfkc50_char_type_table_e2b0[utf8[2] - 0x80];
+ case 0xb1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb7) {
+ return grn_nfkc50_char_type_table_e2b1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb2 :
+ return GRN_CHAR_ALPHA;
+ case 0xb3 :
+ return grn_nfkc50_char_type_table_e2b3[utf8[2] - 0x80];
+ case 0xb4 :
+ return grn_nfkc50_char_type_table_e2b4[utf8[2] - 0x80];
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xaf) {
+ return grn_nfkc50_char_type_table_e2b5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_char_type_table_e2b6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x9e) {
+ return grn_nfkc50_char_type_table_e2b7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x97) {
+ return grn_nfkc50_char_type_table_e2b8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbb) {
+ return grn_nfkc50_char_type_table_e2bf[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe3 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_SYMBOL;
+ case 0x81 :
+ return GRN_CHAR_HIRAGANA;
+ case 0x82 :
+ return grn_nfkc50_char_type_table_e382[utf8[2] - 0x80];
+ case 0x83 :
+ return GRN_CHAR_KATAKANA;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return grn_nfkc50_char_type_table_e387[utf8[2] - 0x80];
+ case 0x88 :
+ return GRN_CHAR_SYMBOL;
+ case 0x89 :
+ return GRN_CHAR_SYMBOL;
+ case 0x8a :
+ return GRN_CHAR_SYMBOL;
+ case 0x8b :
+ return GRN_CHAR_SYMBOL;
+ case 0x8c :
+ return GRN_CHAR_SYMBOL;
+ case 0x8d :
+ return GRN_CHAR_SYMBOL;
+ case 0x8e :
+ return GRN_CHAR_SYMBOL;
+ case 0x8f :
+ return GRN_CHAR_SYMBOL;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xe4 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_SYMBOL;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xe5 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xe6 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xe7 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xe8 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xe9 :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xea :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x8f) {
+ return GRN_CHAR_KANJI;
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa1) {
+ return grn_nfkc50_char_type_table_ea9c[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xab) {
+ return grn_nfkc50_char_type_table_eaa0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb7) {
+ return grn_nfkc50_char_type_table_eaa1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xaf) {
+ return GRN_CHAR_KANJI;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xef :
+ switch (utf8[1]) {
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_char_type_table_efac[utf8[2] - 0x80];
+ }
+ break;
+ case 0xad :
+ return grn_nfkc50_char_type_table_efad[utf8[2] - 0x80];
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb1) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x93 &&
+ utf8[2] <= 0xbf) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xb0 :
+ return GRN_CHAR_ALPHA;
+ case 0xb1 :
+ return GRN_CHAR_ALPHA;
+ case 0xb2 :
+ return GRN_CHAR_ALPHA;
+ case 0xb3 :
+ return GRN_CHAR_ALPHA;
+ case 0xb4 :
+ return grn_nfkc50_char_type_table_efb4[utf8[2] - 0x80];
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xbf) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xb6 :
+ return grn_nfkc50_char_type_table_efb6[utf8[2] - 0x80];
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_char_type_table_efb7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_efb8[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb9 :
+ return grn_nfkc50_char_type_table_efb9[utf8[2] - 0x80];
+ case 0xba :
+ return GRN_CHAR_ALPHA;
+ case 0xbb :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbc) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_efbc[utf8[2] - 0x81];
+ }
+ break;
+ case 0xbd :
+ return grn_nfkc50_char_type_table_efbd[utf8[2] - 0x80];
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x82 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_char_type_table_efbf[utf8[2] - 0x82];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xf0 :
+ switch (utf8[1]) {
+ case 0x90 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return grn_nfkc50_char_type_table_f09080[utf8[3] - 0x80];
+ case 0x81 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x9d) {
+ return grn_nfkc50_char_type_table_f09081[utf8[3] - 0x80];
+ }
+ break;
+ case 0x82 :
+ return GRN_CHAR_ALPHA;
+ case 0x83 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xba) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x84 :
+ return grn_nfkc50_char_type_table_f09084[utf8[3] - 0x80];
+ case 0x85 :
+ return grn_nfkc50_char_type_table_f09085[utf8[3] - 0x80];
+ case 0x86 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x8a) {
+ return grn_nfkc50_char_type_table_f09086[utf8[3] - 0x80];
+ }
+ break;
+ case 0x8c :
+ return grn_nfkc50_char_type_table_f0908c[utf8[3] - 0x80];
+ case 0x8d :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x8a) {
+ return grn_nfkc50_char_type_table_f0908d[utf8[3] - 0x80];
+ }
+ break;
+ case 0x8e :
+ return grn_nfkc50_char_type_table_f0908e[utf8[3] - 0x80];
+ case 0x8f :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x95) {
+ return grn_nfkc50_char_type_table_f0908f[utf8[3] - 0x80];
+ }
+ break;
+ case 0x90 :
+ return GRN_CHAR_ALPHA;
+ case 0x91 :
+ return GRN_CHAR_ALPHA;
+ case 0x92 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xa9) {
+ return grn_nfkc50_char_type_table_f09092[utf8[3] - 0x80];
+ }
+ break;
+ case 0xa0 :
+ return grn_nfkc50_char_type_table_f090a0[utf8[3] - 0x80];
+ case 0xa4 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x9f) {
+ return grn_nfkc50_char_type_table_f090a4[utf8[3] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xb3) {
+ return grn_nfkc50_char_type_table_f090a8[utf8[3] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x98) {
+ return grn_nfkc50_char_type_table_f090a9[utf8[3] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0x92 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_ALPHA;
+ case 0x81 :
+ return GRN_CHAR_ALPHA;
+ case 0x82 :
+ return GRN_CHAR_ALPHA;
+ case 0x83 :
+ return GRN_CHAR_ALPHA;
+ case 0x84 :
+ return GRN_CHAR_ALPHA;
+ case 0x85 :
+ return GRN_CHAR_ALPHA;
+ case 0x86 :
+ return GRN_CHAR_ALPHA;
+ case 0x87 :
+ return GRN_CHAR_ALPHA;
+ case 0x88 :
+ return GRN_CHAR_ALPHA;
+ case 0x89 :
+ return GRN_CHAR_ALPHA;
+ case 0x8a :
+ return GRN_CHAR_ALPHA;
+ case 0x8b :
+ return GRN_CHAR_ALPHA;
+ case 0x8c :
+ return GRN_CHAR_ALPHA;
+ case 0x8d :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xae) {
+ return GRN_CHAR_ALPHA;
+ }
+ break;
+ case 0x90 :
+ return GRN_CHAR_DIGIT;
+ case 0x91 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xb3) {
+ return grn_nfkc50_char_type_table_f09291[utf8[3] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0x9d :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_SYMBOL;
+ case 0x81 :
+ return GRN_CHAR_SYMBOL;
+ case 0x82 :
+ return GRN_CHAR_SYMBOL;
+ case 0x83 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xb5) {
+ return GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 0x84 :
+ return grn_nfkc50_char_type_table_f09d84[utf8[3] - 0x80];
+ case 0x85 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xac) {
+ return grn_nfkc50_char_type_table_f09d85[utf8[3] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[3] >= 0x83 &&
+ utf8[3] <= 0xbf) {
+ return grn_nfkc50_char_type_table_f09d86[utf8[3] - 0x83];
+ }
+ break;
+ case 0x87 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x9d) {
+ return GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 0x88 :
+ return GRN_CHAR_SYMBOL;
+ case 0x89 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x85) {
+ return grn_nfkc50_char_type_table_f09d89[utf8[3] - 0x80];
+ }
+ break;
+ case 0x8c :
+ return GRN_CHAR_SYMBOL;
+ case 0x8d :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xb1) {
+ return grn_nfkc50_char_type_table_f09d8d[utf8[3] - 0x80];
+ }
+ break;
+ case 0x90 :
+ return GRN_CHAR_ALPHA;
+ case 0x91 :
+ return grn_nfkc50_char_type_table_f09d91[utf8[3] - 0x80];
+ case 0x92 :
+ return grn_nfkc50_char_type_table_f09d92[utf8[3] - 0x80];
+ case 0x93 :
+ return grn_nfkc50_char_type_table_f09d93[utf8[3] - 0x80];
+ case 0x94 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xbe) {
+ return grn_nfkc50_char_type_table_f09d94[utf8[3] - 0x80];
+ }
+ break;
+ case 0x95 :
+ return grn_nfkc50_char_type_table_f09d95[utf8[3] - 0x80];
+ case 0x96 :
+ return GRN_CHAR_ALPHA;
+ case 0x97 :
+ return GRN_CHAR_ALPHA;
+ case 0x98 :
+ return GRN_CHAR_ALPHA;
+ case 0x99 :
+ return GRN_CHAR_ALPHA;
+ case 0x9a :
+ return grn_nfkc50_char_type_table_f09d9a[utf8[3] - 0x80];
+ case 0x9b :
+ return grn_nfkc50_char_type_table_f09d9b[utf8[3] - 0x80];
+ case 0x9c :
+ return grn_nfkc50_char_type_table_f09d9c[utf8[3] - 0x80];
+ case 0x9d :
+ return grn_nfkc50_char_type_table_f09d9d[utf8[3] - 0x80];
+ case 0x9e :
+ return grn_nfkc50_char_type_table_f09d9e[utf8[3] - 0x80];
+ case 0x9f :
+ return grn_nfkc50_char_type_table_f09d9f[utf8[3] - 0x80];
+ default :
+ break;
+ }
+ break;
+ case 0xa0 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa1 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa2 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa3 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa4 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa5 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa6 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa7 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa8 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xa9 :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ return GRN_CHAR_KANJI;
+ case 0x9c :
+ return GRN_CHAR_KANJI;
+ case 0x9d :
+ return GRN_CHAR_KANJI;
+ case 0x9e :
+ return GRN_CHAR_KANJI;
+ case 0x9f :
+ return GRN_CHAR_KANJI;
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ return GRN_CHAR_KANJI;
+ case 0xa9 :
+ return GRN_CHAR_KANJI;
+ case 0xaa :
+ return GRN_CHAR_KANJI;
+ case 0xab :
+ return GRN_CHAR_KANJI;
+ case 0xac :
+ return GRN_CHAR_KANJI;
+ case 0xad :
+ return GRN_CHAR_KANJI;
+ case 0xae :
+ return GRN_CHAR_KANJI;
+ case 0xaf :
+ return GRN_CHAR_KANJI;
+ case 0xb0 :
+ return GRN_CHAR_KANJI;
+ case 0xb1 :
+ return GRN_CHAR_KANJI;
+ case 0xb2 :
+ return GRN_CHAR_KANJI;
+ case 0xb3 :
+ return GRN_CHAR_KANJI;
+ case 0xb4 :
+ return GRN_CHAR_KANJI;
+ case 0xb5 :
+ return GRN_CHAR_KANJI;
+ case 0xb6 :
+ return GRN_CHAR_KANJI;
+ case 0xb7 :
+ return GRN_CHAR_KANJI;
+ case 0xb8 :
+ return GRN_CHAR_KANJI;
+ case 0xb9 :
+ return GRN_CHAR_KANJI;
+ case 0xba :
+ return GRN_CHAR_KANJI;
+ case 0xbb :
+ return GRN_CHAR_KANJI;
+ case 0xbc :
+ return GRN_CHAR_KANJI;
+ case 0xbd :
+ return GRN_CHAR_KANJI;
+ case 0xbe :
+ return GRN_CHAR_KANJI;
+ case 0xbf :
+ return GRN_CHAR_KANJI;
+ default :
+ break;
+ }
+ break;
+ case 0xaa :
+ switch (utf8[2]) {
+ case 0x80 :
+ return GRN_CHAR_KANJI;
+ case 0x81 :
+ return GRN_CHAR_KANJI;
+ case 0x82 :
+ return GRN_CHAR_KANJI;
+ case 0x83 :
+ return GRN_CHAR_KANJI;
+ case 0x84 :
+ return GRN_CHAR_KANJI;
+ case 0x85 :
+ return GRN_CHAR_KANJI;
+ case 0x86 :
+ return GRN_CHAR_KANJI;
+ case 0x87 :
+ return GRN_CHAR_KANJI;
+ case 0x88 :
+ return GRN_CHAR_KANJI;
+ case 0x89 :
+ return GRN_CHAR_KANJI;
+ case 0x8a :
+ return GRN_CHAR_KANJI;
+ case 0x8b :
+ return GRN_CHAR_KANJI;
+ case 0x8c :
+ return GRN_CHAR_KANJI;
+ case 0x8d :
+ return GRN_CHAR_KANJI;
+ case 0x8e :
+ return GRN_CHAR_KANJI;
+ case 0x8f :
+ return GRN_CHAR_KANJI;
+ case 0x90 :
+ return GRN_CHAR_KANJI;
+ case 0x91 :
+ return GRN_CHAR_KANJI;
+ case 0x92 :
+ return GRN_CHAR_KANJI;
+ case 0x93 :
+ return GRN_CHAR_KANJI;
+ case 0x94 :
+ return GRN_CHAR_KANJI;
+ case 0x95 :
+ return GRN_CHAR_KANJI;
+ case 0x96 :
+ return GRN_CHAR_KANJI;
+ case 0x97 :
+ return GRN_CHAR_KANJI;
+ case 0x98 :
+ return GRN_CHAR_KANJI;
+ case 0x99 :
+ return GRN_CHAR_KANJI;
+ case 0x9a :
+ return GRN_CHAR_KANJI;
+ case 0x9b :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x9f) {
+ return GRN_CHAR_KANJI;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xaf :
+ switch (utf8[2]) {
+ case 0xa0 :
+ return GRN_CHAR_KANJI;
+ case 0xa1 :
+ return GRN_CHAR_KANJI;
+ case 0xa2 :
+ return GRN_CHAR_KANJI;
+ case 0xa3 :
+ return GRN_CHAR_KANJI;
+ case 0xa4 :
+ return GRN_CHAR_KANJI;
+ case 0xa5 :
+ return GRN_CHAR_KANJI;
+ case 0xa6 :
+ return GRN_CHAR_KANJI;
+ case 0xa7 :
+ return GRN_CHAR_KANJI;
+ case 0xa8 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x9f) {
+ return GRN_CHAR_KANJI;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return GRN_CHAR_OTHERS;
+}
+
+static const char *grn_nfkc50_decompose_table_[] = {
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a"
+};
+
+static const char *grn_nfkc50_decompose_table_c2[] = {
+ "\x20", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xcc\x88", NULL, "\x61", NULL, NULL, NULL, NULL, "\xcc\x84",
+ NULL, NULL, "\x32", "\x33", "\xcc\x81", "\xce\xbc", NULL, NULL,
+ "\xcc\xa7", "\x31", "\x6f", NULL, "\x31\xe2\x81\x84\x34", "\x31\xe2\x81\x84\x32", "\x33\xe2\x81\x84\x34"
+};
+
+static const char *grn_nfkc50_decompose_table_c3[] = {
+ "\xc3\xa0", "\xc3\xa1", "\xc3\xa2", "\xc3\xa3", "\xc3\xa4", "\xc3\xa5", NULL, "\xc3\xa7",
+ "\xc3\xa8", "\xc3\xa9", "\xc3\xaa", "\xc3\xab", "\xc3\xac", "\xc3\xad", "\xc3\xae", "\xc3\xaf",
+ NULL, "\xc3\xb1", "\xc3\xb2", "\xc3\xb3", "\xc3\xb4", "\xc3\xb5", "\xc3\xb6", NULL,
+ NULL, "\xc3\xb9", "\xc3\xba", "\xc3\xbb", "\xc3\xbc", "\xc3\xbd"
+};
+
+static const char *grn_nfkc50_decompose_table_c4[] = {
+ "\xc4\x81", NULL, "\xc4\x83", NULL, "\xc4\x85", NULL, "\xc4\x87", NULL,
+ "\xc4\x89", NULL, "\xc4\x8b", NULL, "\xc4\x8d", NULL, "\xc4\x8f", NULL,
+ NULL, NULL, "\xc4\x93", NULL, "\xc4\x95", NULL, "\xc4\x97", NULL,
+ "\xc4\x99", NULL, "\xc4\x9b", NULL, "\xc4\x9d", NULL, "\xc4\x9f", NULL,
+ "\xc4\xa1", NULL, "\xc4\xa3", NULL, "\xc4\xa5", NULL, NULL, NULL,
+ "\xc4\xa9", NULL, "\xc4\xab", NULL, "\xc4\xad", NULL, "\xc4\xaf", NULL,
+ "\x69\xcc\x87", NULL, "\x69\x6a", "\x69\x6a", "\xc4\xb5", NULL, "\xc4\xb7", NULL,
+ NULL, "\xc4\xba", NULL, "\xc4\xbc", NULL, "\xc4\xbe", NULL, "\x6c\xc2\xb7"
+};
+
+static const char *grn_nfkc50_decompose_table_c5[] = {
+ "\x6c\xc2\xb7", NULL, NULL, "\xc5\x84", NULL, "\xc5\x86", NULL, "\xc5\x88",
+ NULL, "\xca\xbc\x6e", NULL, NULL, "\xc5\x8d", NULL, "\xc5\x8f", NULL,
+ "\xc5\x91", NULL, NULL, NULL, "\xc5\x95", NULL, "\xc5\x97", NULL,
+ "\xc5\x99", NULL, "\xc5\x9b", NULL, "\xc5\x9d", NULL, "\xc5\x9f", NULL,
+ "\xc5\xa1", NULL, "\xc5\xa3", NULL, "\xc5\xa5", NULL, NULL, NULL,
+ "\xc5\xa9", NULL, "\xc5\xab", NULL, "\xc5\xad", NULL, "\xc5\xaf", NULL,
+ "\xc5\xb1", NULL, "\xc5\xb3", NULL, "\xc5\xb5", NULL, "\xc5\xb7", NULL,
+ "\xc3\xbf", "\xc5\xba", NULL, "\xc5\xbc", NULL, "\xc5\xbe", NULL, "\x73"
+};
+
+static const char *grn_nfkc50_decompose_table_c6[] = {
+ "\xc6\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xc6\xb0"
+};
+
+static const char *grn_nfkc50_decompose_table_c7[] = {
+ "\x64\xc5\xbe", "\x64\xc5\xbe", "\x64\xc5\xbe", "\x6c\x6a", "\x6c\x6a", "\x6c\x6a", "\x6e\x6a", "\x6e\x6a",
+ "\x6e\x6a", "\xc7\x8e", NULL, "\xc7\x90", NULL, "\xc7\x92", NULL, "\xc7\x94",
+ NULL, "\xc7\x96", NULL, "\xc7\x98", NULL, "\xc7\x9a", NULL, "\xc7\x9c",
+ NULL, NULL, "\xc7\x9f", NULL, "\xc7\xa1", NULL, NULL, NULL,
+ NULL, NULL, "\xc7\xa7", NULL, "\xc7\xa9", NULL, "\xc7\xab", NULL,
+ "\xc7\xad", NULL, NULL, NULL, NULL, "\x64\x7a", "\x64\x7a", "\x64\x7a",
+ "\xc7\xb5", NULL, NULL, NULL, "\xc7\xb9", NULL, "\xc7\xbb"
+};
+
+static const char *grn_nfkc50_decompose_table_c8[] = {
+ "\xc8\x81", NULL, "\xc8\x83", NULL, "\xc8\x85", NULL, "\xc8\x87", NULL,
+ "\xc8\x89", NULL, "\xc8\x8b", NULL, "\xc8\x8d", NULL, "\xc8\x8f", NULL,
+ "\xc8\x91", NULL, "\xc8\x93", NULL, "\xc8\x95", NULL, "\xc8\x97", NULL,
+ "\xc8\x99", NULL, "\xc8\x9b", NULL, NULL, NULL, "\xc8\x9f", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xc8\xa7", NULL,
+ "\xc8\xa9", NULL, "\xc8\xab", NULL, "\xc8\xad", NULL, "\xc8\xaf", NULL,
+ "\xc8\xb1", NULL, "\xc8\xb3"
+};
+
+static const char *grn_nfkc50_decompose_table_ca[] = {
+ "\x68", "\xc9\xa6", "\x6a", "\x72", "\xc9\xb9", "\xc9\xbb", "\xca\x81", "\x77",
+ "\x79"
+};
+
+static const char *grn_nfkc50_decompose_table_cb[] = {
+ "\xcc\x86", "\xcc\x87", "\xcc\x8a", "\xcc\xa8", "\xcc\x83", "\xcc\x8b", NULL, NULL,
+ "\xc9\xa3", "\x6c", "\x73", "\x78", "\xca\x95"
+};
+
+static const char *grn_nfkc50_decompose_table_cd[] = {
+ "\xcc\x80", "\xcc\x81", NULL, "\xcc\x93", "\xcc\x88\xcc\x81", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xca\xb9", NULL, NULL, NULL,
+ NULL, NULL, "\xcd\x85", NULL, NULL, NULL, "\x3b"
+};
+
+static const char *grn_nfkc50_decompose_table_ce[] = {
+ "\xcc\x81", "\xcc\x88\xcc\x81", NULL, "\xc2\xb7"
+};
+
+static const char *grn_nfkc50_decompose_table_cf[] = {
+ "\xce\xb2", "\xce\xb8", "\xce\xa5", "\xce\x8e", "\xce\xab", "\xcf\x86", "\xcf\x80", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xce\xba", "\xcf\x81", "\xcf\x82", NULL, "\xce\x98", "\xce\xb5", NULL, NULL,
+ NULL, "\xce\xa3"
+};
+
+static const char *grn_nfkc50_decompose_table_d9[] = {
+ "\xd8\xa7\xd9\xb4", "\xd9\x88\xd9\xb4", "\xdb\x87\xd9\xb4", "\xd9\x8a\xd9\xb4"
+};
+
+static const char *grn_nfkc50_decompose_table_e0a5[] = {
+ "\xe0\xa4\x95\xe0\xa4\xbc", "\xe0\xa4\x96\xe0\xa4\xbc", "\xe0\xa4\x97\xe0\xa4\xbc", "\xe0\xa4\x9c\xe0\xa4\xbc", "\xe0\xa4\xa1\xe0\xa4\xbc", "\xe0\xa4\xa2\xe0\xa4\xbc", "\xe0\xa4\xab\xe0\xa4\xbc", "\xe0\xa4\xaf\xe0\xa4\xbc"
+};
+
+static const char *grn_nfkc50_decompose_table_e0a7[] = {
+ "\xe0\xa6\xa1\xe0\xa6\xbc", "\xe0\xa6\xa2\xe0\xa6\xbc", NULL, "\xe0\xa6\xaf\xe0\xa6\xbc"
+};
+
+static const char *grn_nfkc50_decompose_table_e0a8[] = {
+ "\xe0\xa8\xb2\xe0\xa8\xbc", NULL, NULL, "\xe0\xa8\xb8\xe0\xa8\xbc"
+};
+
+static const char *grn_nfkc50_decompose_table_e0a9[] = {
+ "\xe0\xa8\x96\xe0\xa8\xbc", "\xe0\xa8\x97\xe0\xa8\xbc", "\xe0\xa8\x9c\xe0\xa8\xbc", NULL, NULL, "\xe0\xa8\xab\xe0\xa8\xbc"
+};
+
+static const char *grn_nfkc50_decompose_table_e0ad[] = {
+ "\xe0\xac\xa1\xe0\xac\xbc", "\xe0\xac\xa2\xe0\xac\xbc"
+};
+
+static const char *grn_nfkc50_decompose_table_e0bb[] = {
+ "\xe0\xba\xab\xe0\xba\x99", "\xe0\xba\xab\xe0\xba\xa1"
+};
+
+static const char *grn_nfkc50_decompose_table_e0bd[] = {
+ "\xe0\xbd\x82\xe0\xbe\xb7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xe0\xbd\x8c\xe0\xbe\xb7", NULL, NULL, NULL, NULL, "\xe0\xbd\x91\xe0\xbe\xb7",
+ NULL, NULL, NULL, NULL, "\xe0\xbd\x96\xe0\xbe\xb7", NULL, NULL, NULL,
+ NULL, "\xe0\xbd\x9b\xe0\xbe\xb7", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xe0\xbd\x80\xe0\xbe\xb5", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe0\xbd\xb1\xe0\xbd\xb2", NULL, "\xe0\xbd\xb1\xe0\xbd\xb4", "\xe0\xbe\xb2\xe0\xbe\x80", "\xe0\xbe\xb2\xe0\xbd\xb1\xe0\xbe\x80", "\xe0\xbe\xb3\xe0\xbe\x80", "\xe0\xbe\xb3\xe0\xbd\xb1\xe0\xbe\x80"
+};
+
+static const char *grn_nfkc50_decompose_table_e0be[] = {
+ "\xe0\xbd\xb1\xe0\xbe\x80", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xe0\xbe\x92\xe0\xbe\xb7", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe0\xbe\x9c\xe0\xbe\xb7", NULL, NULL, NULL,
+ NULL, "\xe0\xbe\xa1\xe0\xbe\xb7", NULL, NULL, NULL, NULL, "\xe0\xbe\xa6\xe0\xbe\xb7", NULL,
+ NULL, NULL, NULL, "\xe0\xbe\xab\xe0\xbe\xb7", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe0\xbe\x90\xe0\xbe\xb5"
+};
+
+static const char *grn_nfkc50_decompose_table_e1b4[] = {
+ "\x61", "\xc3\x86", "\x62", NULL, "\x64", "\x65", "\xc6\x8e", "\x67",
+ "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", NULL,
+ "\x6f", "\xc8\xa2", "\x70", "\x72"
+};
+
+static const char *grn_nfkc50_decompose_table_e1b5[] = {
+ "\x74", "\x75", "\x77", "\x61", "\xc9\x90", "\xc9\x91", "\xe1\xb4\x82", "\x62",
+ "\x64", "\x65", "\xc9\x99", "\xc9\x9b", "\xc9\x9c", "\x67", NULL, "\x6b",
+ "\x6d", "\xc5\x8b", "\x6f", "\xc9\x94", "\xe1\xb4\x96", "\xe1\xb4\x97", "\x70", "\x74",
+ "\x75", "\xe1\xb4\x9d", "\xc9\xaf", "\x76", "\xe1\xb4\xa5", "\xce\xb2", "\xce\xb3", "\xce\xb4",
+ "\xcf\x86", "\xcf\x87", "\x69", "\x72", "\x75", "\x76", "\xce\xb2", "\xce\xb3",
+ "\xcf\x81", "\xcf\x86", "\xcf\x87", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd0\xbd"
+};
+
+static const char *grn_nfkc50_decompose_table_e1b6[] = {
+ "\xc9\x92", "\x63", "\xc9\x95", "\xc3\xb0", "\xc9\x9c", "\x66", "\xc9\x9f", "\xc9\xa1",
+ "\xc9\xa5", "\xc9\xa8", "\xc9\xa9", "\xc9\xaa", "\xe1\xb5\xbb", "\xca\x9d", "\xc9\xad", "\xe1\xb6\x85",
+ "\xca\x9f", "\xc9\xb1", "\xc9\xb0", "\xc9\xb2", "\xc9\xb3", "\xc9\xb4", "\xc9\xb5", "\xc9\xb8",
+ "\xca\x82", "\xca\x83", "\xc6\xab", "\xca\x89", "\xca\x8a", "\xe1\xb4\x9c", "\xca\x8b", "\xca\x8c",
+ "\x7a", "\xca\x90", "\xca\x91", "\xca\x92", "\xce\xb8"
+};
+
+static const char *grn_nfkc50_decompose_table_e1b8[] = {
+ "\xe1\xb8\x81", NULL, "\xe1\xb8\x83", NULL, "\xe1\xb8\x85", NULL, "\xe1\xb8\x87", NULL,
+ "\xe1\xb8\x89", NULL, "\xe1\xb8\x8b", NULL, "\xe1\xb8\x8d", NULL, "\xe1\xb8\x8f", NULL,
+ "\xe1\xb8\x91", NULL, "\xe1\xb8\x93", NULL, "\xe1\xb8\x95", NULL, "\xe1\xb8\x97", NULL,
+ "\xe1\xb8\x99", NULL, "\xe1\xb8\x9b", NULL, "\xe1\xb8\x9d", NULL, "\xe1\xb8\x9f", NULL,
+ "\xe1\xb8\xa1", NULL, "\xe1\xb8\xa3", NULL, "\xe1\xb8\xa5", NULL, "\xe1\xb8\xa7", NULL,
+ "\xe1\xb8\xa9", NULL, "\xe1\xb8\xab", NULL, "\xe1\xb8\xad", NULL, "\xe1\xb8\xaf", NULL,
+ "\xe1\xb8\xb1", NULL, "\xe1\xb8\xb3", NULL, "\xe1\xb8\xb5", NULL, "\xe1\xb8\xb7", NULL,
+ "\xe1\xb8\xb9", NULL, "\xe1\xb8\xbb", NULL, "\xe1\xb8\xbd", NULL, "\xe1\xb8\xbf"
+};
+
+static const char *grn_nfkc50_decompose_table_e1b9[] = {
+ "\xe1\xb9\x81", NULL, "\xe1\xb9\x83", NULL, "\xe1\xb9\x85", NULL, "\xe1\xb9\x87", NULL,
+ "\xe1\xb9\x89", NULL, "\xe1\xb9\x8b", NULL, "\xe1\xb9\x8d", NULL, "\xe1\xb9\x8f", NULL,
+ "\xe1\xb9\x91", NULL, "\xe1\xb9\x93", NULL, "\xe1\xb9\x95", NULL, "\xe1\xb9\x97", NULL,
+ "\xe1\xb9\x99", NULL, "\xe1\xb9\x9b", NULL, "\xe1\xb9\x9d", NULL, "\xe1\xb9\x9f", NULL,
+ "\xe1\xb9\xa1", NULL, "\xe1\xb9\xa3", NULL, "\xe1\xb9\xa5", NULL, "\xe1\xb9\xa7", NULL,
+ "\xe1\xb9\xa9", NULL, "\xe1\xb9\xab", NULL, "\xe1\xb9\xad", NULL, "\xe1\xb9\xaf", NULL,
+ "\xe1\xb9\xb1", NULL, "\xe1\xb9\xb3", NULL, "\xe1\xb9\xb5", NULL, "\xe1\xb9\xb7", NULL,
+ "\xe1\xb9\xb9", NULL, "\xe1\xb9\xbb", NULL, "\xe1\xb9\xbd", NULL, "\xe1\xb9\xbf"
+};
+
+static const char *grn_nfkc50_decompose_table_e1ba[] = {
+ "\xe1\xba\x81", NULL, "\xe1\xba\x83", NULL, "\xe1\xba\x85", NULL, "\xe1\xba\x87", NULL,
+ "\xe1\xba\x89", NULL, "\xe1\xba\x8b", NULL, "\xe1\xba\x8d", NULL, "\xe1\xba\x8f", NULL,
+ "\xe1\xba\x91", NULL, "\xe1\xba\x93", NULL, "\xe1\xba\x95", NULL, NULL, NULL,
+ NULL, NULL, "\x61\xca\xbe", "\xe1\xb9\xa1", NULL, NULL, NULL, NULL,
+ "\xe1\xba\xa1", NULL, "\xe1\xba\xa3", NULL, "\xe1\xba\xa5", NULL, "\xe1\xba\xa7", NULL,
+ "\xe1\xba\xa9", NULL, "\xe1\xba\xab", NULL, "\xe1\xba\xad", NULL, "\xe1\xba\xaf", NULL,
+ "\xe1\xba\xb1", NULL, "\xe1\xba\xb3", NULL, "\xe1\xba\xb5", NULL, "\xe1\xba\xb7", NULL,
+ "\xe1\xba\xb9", NULL, "\xe1\xba\xbb", NULL, "\xe1\xba\xbd", NULL, "\xe1\xba\xbf"
+};
+
+static const char *grn_nfkc50_decompose_table_e1bb[] = {
+ "\xe1\xbb\x81", NULL, "\xe1\xbb\x83", NULL, "\xe1\xbb\x85", NULL, "\xe1\xbb\x87", NULL,
+ "\xe1\xbb\x89", NULL, "\xe1\xbb\x8b", NULL, "\xe1\xbb\x8d", NULL, "\xe1\xbb\x8f", NULL,
+ "\xe1\xbb\x91", NULL, "\xe1\xbb\x93", NULL, "\xe1\xbb\x95", NULL, "\xe1\xbb\x97", NULL,
+ "\xe1\xbb\x99", NULL, "\xe1\xbb\x9b", NULL, "\xe1\xbb\x9d", NULL, "\xe1\xbb\x9f", NULL,
+ "\xe1\xbb\xa1", NULL, "\xe1\xbb\xa3", NULL, "\xe1\xbb\xa5", NULL, "\xe1\xbb\xa7", NULL,
+ "\xe1\xbb\xa9", NULL, "\xe1\xbb\xab", NULL, "\xe1\xbb\xad", NULL, "\xe1\xbb\xaf", NULL,
+ "\xe1\xbb\xb1", NULL, "\xe1\xbb\xb3", NULL, "\xe1\xbb\xb5", NULL, "\xe1\xbb\xb7", NULL,
+ "\xe1\xbb\xb9"
+};
+
+static const char *grn_nfkc50_decompose_table_e1bd[] = {
+ "\xce\xac", NULL, "\xce\xad", NULL, "\xce\xae", NULL, "\xce\xaf", NULL,
+ "\xcf\x8c", NULL, "\xcf\x8d", NULL, "\xcf\x8e"
+};
+
+static const char *grn_nfkc50_decompose_table_e1be[] = {
+ "\xce\x86", NULL, "\xcc\x93", "\xce\xb9", "\xcc\x93"
+};
+
+static const char *grn_nfkc50_decompose_table_e1bf[] = {
+ "\xcd\x82", "\xcc\x88\xcd\x82", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xce\x88", NULL, "\xce\x89", NULL, "\xcc\x93\xcc\x80", "\xcc\x93\xcc\x81", "\xcc\x93\xcd\x82",
+ NULL, NULL, NULL, "\xce\x90", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\xce\x8a", NULL, "\xcc\x94\xcc\x80", "\xcc\x94\xcc\x81", "\xcc\x94\xcd\x82",
+ NULL, NULL, NULL, "\xce\xb0", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\xce\x8e", NULL, "\xcc\x88\xcc\x80", "\xcc\x88\xcc\x81", "\x60",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xce\x8c", NULL, "\xce\x8f", NULL, "\xcc\x81", "\xcc\x94"
+};
+
+static const char *grn_nfkc50_decompose_table_e280[] = {
+ "\x20", "\x20", "\x20", "\x20", "\x20", "\x20", "\x20", "\x20",
+ "\x20", "\x20", "\x20", NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe2\x80\x90", NULL, NULL, NULL, NULL, NULL, "\xcc\xb3",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\x2e", "\x2e\x2e", "\x2e\x2e\x2e", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\x20",
+ NULL, NULL, NULL, "\xe2\x80\xb2\xe2\x80\xb2", "\xe2\x80\xb2\xe2\x80\xb2\xe2\x80\xb2", NULL, "\xe2\x80\xb5\xe2\x80\xb5", "\xe2\x80\xb5\xe2\x80\xb5\xe2\x80\xb5",
+ NULL, NULL, NULL, NULL, "\x21\x21", NULL, "\xcc\x85"
+};
+
+static const char *grn_nfkc50_decompose_table_e281[] = {
+ "\x3f\x3f", "\x3f\x21", "\x21\x3f", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe2\x80\xb2\xe2\x80\xb2\xe2\x80\xb2\xe2\x80\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\x20", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\x30", "\x69", NULL, NULL, "\x34", "\x35", "\x36",
+ "\x37", "\x38", "\x39", "\x2b", "\xe2\x88\x92", "\x3d", "\x28", "\x29",
+ "\x6e"
+};
+
+static const char *grn_nfkc50_decompose_table_e282[] = {
+ "\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37",
+ "\x38", "\x39", "\x2b", "\xe2\x88\x92", "\x3d", "\x28", "\x29", NULL,
+ "\x61", "\x65", "\x6f", "\x78", "\xc9\x99", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\x72\x73"
+};
+
+static const char *grn_nfkc50_decompose_table_e284[] = {
+ "\x61\x2f\x63", "\x61\x2f\x73", "\x63", "\xc2\xb0\x63", NULL, "\x63\x2f\x6f", "\x63\x2f\x75", "\xc6\x90",
+ NULL, "\xc2\xb0\x66", "\x67", "\x68", "\x68", "\x68", "\x68", "\xc4\xa7",
+ "\x69", "\x69", "\x6c", "\x6c", NULL, "\x6e", "\x6e\x6f", NULL,
+ NULL, "\x70", "\x71", "\x72", "\x72", "\x72", NULL, NULL,
+ "\x73\x6d", "\x74\x65\x6c", "\x74\x6d", NULL, "\x7a", NULL, "\xce\xa9", NULL,
+ "\x7a", NULL, "\x6b", "\xc3\xa5", "\x62", "\x63", NULL, "\x65",
+ "\x65", "\x66", NULL, "\x6d", "\x6f", "\xd7\x90", "\xd7\x91", "\xd7\x92",
+ "\xd7\x93", "\x69", NULL, "\x66\x61\x78", "\xcf\x80", "\xce\xb3", "\xce\x93", "\xce\xa0"
+};
+
+static const char *grn_nfkc50_decompose_table_e285[] = {
+ "\xe2\x88\x91", NULL, NULL, NULL, NULL, "\x64", "\x64", "\x65",
+ "\x69", "\x6a", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\x31\xe2\x81\x84\x33", "\x32\xe2\x81\x84\x33", "\x31\xe2\x81\x84\x35", "\x32\xe2\x81\x84\x35", "\x33\xe2\x81\x84\x35",
+ "\x34\xe2\x81\x84\x35", "\x31\xe2\x81\x84\x36", "\x35\xe2\x81\x84\x36", "\x31\xe2\x81\x84\x38", "\x33\xe2\x81\x84\x38", "\x35\xe2\x81\x84\x38", "\x37\xe2\x81\x84\x38", "\x31\xe2\x81\x84",
+ "\x69", "\x69\x69", "\x69\x69\x69", "\x69\x76", "\x76", "\x76\x69", "\x76\x69\x69", "\x76\x69\x69\x69",
+ "\x69\x78", "\x78", "\x78\x69", "\x78\x69\x69", "\x6c", "\x63", "\x64", "\x6d",
+ "\x69", "\x69\x69", "\x69\x69\x69", "\x69\x76", "\x76", "\x76\x69", "\x76\x69\x69", "\x76\x69\x69\x69",
+ "\x69\x78", "\x78", "\x78\x69", "\x78\x69\x69", "\x6c", "\x63", "\x64", "\x6d"
+};
+
+static const char *grn_nfkc50_decompose_table_e288[] = {
+ "\xe2\x88\xab\xe2\x88\xab", "\xe2\x88\xab\xe2\x88\xab\xe2\x88\xab", NULL, "\xe2\x88\xae\xe2\x88\xae", "\xe2\x88\xae\xe2\x88\xae\xe2\x88\xae"
+};
+
+static const char *grn_nfkc50_decompose_table_e28c[] = {
+ "\xe3\x80\x88", "\xe3\x80\x89"
+};
+
+static const char *grn_nfkc50_decompose_table_e291[] = {
+ "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", "\x38",
+ "\x39", "\x31\x30", "\x31\x31", "\x31\x32", "\x31\x33", "\x31\x34", "\x31\x35", "\x31\x36",
+ "\x31\x37", "\x31\x38", "\x31\x39", "\x32\x30", "\x28\x31\x29", "\x28\x32\x29", "\x28\x33\x29", "\x28\x34\x29",
+ "\x28\x35\x29", "\x28\x36\x29", "\x28\x37\x29", "\x28\x38\x29", "\x28\x39\x29", "\x28\x31\x30\x29", "\x28\x31\x31\x29", "\x28\x31\x32\x29"
+};
+
+static const char *grn_nfkc50_decompose_table_e292[] = {
+ "\x28\x31\x33\x29", "\x28\x31\x34\x29", "\x28\x31\x35\x29", "\x28\x31\x36\x29", "\x28\x31\x37\x29", "\x28\x31\x38\x29", "\x28\x31\x39\x29", "\x28\x32\x30\x29",
+ "\x31\x2e", "\x32\x2e", "\x33\x2e", "\x34\x2e", "\x35\x2e", "\x36\x2e", "\x37\x2e", "\x38\x2e",
+ "\x39\x2e", "\x31\x30\x2e", "\x31\x31\x2e", "\x31\x32\x2e", "\x31\x33\x2e", "\x31\x34\x2e", "\x31\x35\x2e", "\x31\x36\x2e",
+ "\x31\x37\x2e", "\x31\x38\x2e", "\x31\x39\x2e", "\x32\x30\x2e", "\x28\x61\x29", "\x28\x62\x29", "\x28\x63\x29", "\x28\x64\x29",
+ "\x28\x65\x29", "\x28\x66\x29", "\x28\x67\x29", "\x28\x68\x29", "\x28\x69\x29", "\x28\x6a\x29", "\x28\x6b\x29", "\x28\x6c\x29",
+ "\x28\x6d\x29", "\x28\x6e\x29", "\x28\x6f\x29", "\x28\x70\x29", "\x28\x71\x29", "\x28\x72\x29", "\x28\x73\x29", "\x28\x74\x29",
+ "\x28\x75\x29", "\x28\x76\x29", "\x28\x77\x29", "\x28\x78\x29", "\x28\x79\x29", "\x28\x7a\x29", "\x61", "\x62",
+ "\x63", "\x64", "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a"
+};
+
+static const char *grn_nfkc50_decompose_table_e293[] = {
+ "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72",
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x30"
+};
+
+static const char *grn_nfkc50_decompose_table_e2a9[] = {
+ "\x3a\x3a\x3d", "\x3d\x3d", "\x3d\x3d\x3d"
+};
+
+static const char *grn_nfkc50_decompose_table_e2bc[] = {
+ "\xe4\xb8\x80", "\xe4\xb8\xa8", "\xe4\xb8\xb6", "\xe4\xb8\xbf", "\xe4\xb9\x99", "\xe4\xba\x85", "\xe4\xba\x8c", "\xe4\xba\xa0",
+ "\xe4\xba\xba", "\xe5\x84\xbf", "\xe5\x85\xa5", "\xe5\x85\xab", "\xe5\x86\x82", "\xe5\x86\x96", "\xe5\x86\xab", "\xe5\x87\xa0",
+ "\xe5\x87\xb5", "\xe5\x88\x80", "\xe5\x8a\x9b", "\xe5\x8b\xb9", "\xe5\x8c\x95", "\xe5\x8c\x9a", "\xe5\x8c\xb8", "\xe5\x8d\x81",
+ "\xe5\x8d\x9c", "\xe5\x8d\xa9", "\xe5\x8e\x82", "\xe5\x8e\xb6", "\xe5\x8f\x88", "\xe5\x8f\xa3", "\xe5\x9b\x97", "\xe5\x9c\x9f",
+ "\xe5\xa3\xab", "\xe5\xa4\x82", "\xe5\xa4\x8a", "\xe5\xa4\x95", "\xe5\xa4\xa7", "\xe5\xa5\xb3", "\xe5\xad\x90", "\xe5\xae\x80",
+ "\xe5\xaf\xb8", "\xe5\xb0\x8f", "\xe5\xb0\xa2", "\xe5\xb0\xb8", "\xe5\xb1\xae", "\xe5\xb1\xb1", "\xe5\xb7\x9b", "\xe5\xb7\xa5",
+ "\xe5\xb7\xb1", "\xe5\xb7\xbe", "\xe5\xb9\xb2", "\xe5\xb9\xba", "\xe5\xb9\xbf", "\xe5\xbb\xb4", "\xe5\xbb\xbe", "\xe5\xbc\x8b",
+ "\xe5\xbc\x93", "\xe5\xbd\x90", "\xe5\xbd\xa1", "\xe5\xbd\xb3", "\xe5\xbf\x83", "\xe6\x88\x88", "\xe6\x88\xb6", "\xe6\x89\x8b"
+};
+
+static const char *grn_nfkc50_decompose_table_e2bd[] = {
+ "\xe6\x94\xaf", "\xe6\x94\xb4", "\xe6\x96\x87", "\xe6\x96\x97", "\xe6\x96\xa4", "\xe6\x96\xb9", "\xe6\x97\xa0", "\xe6\x97\xa5",
+ "\xe6\x9b\xb0", "\xe6\x9c\x88", "\xe6\x9c\xa8", "\xe6\xac\xa0", "\xe6\xad\xa2", "\xe6\xad\xb9", "\xe6\xae\xb3", "\xe6\xaf\x8b",
+ "\xe6\xaf\x94", "\xe6\xaf\x9b", "\xe6\xb0\x8f", "\xe6\xb0\x94", "\xe6\xb0\xb4", "\xe7\x81\xab", "\xe7\x88\xaa", "\xe7\x88\xb6",
+ "\xe7\x88\xbb", "\xe7\x88\xbf", "\xe7\x89\x87", "\xe7\x89\x99", "\xe7\x89\x9b", "\xe7\x8a\xac", "\xe7\x8e\x84", "\xe7\x8e\x89",
+ "\xe7\x93\x9c", "\xe7\x93\xa6", "\xe7\x94\x98", "\xe7\x94\x9f", "\xe7\x94\xa8", "\xe7\x94\xb0", "\xe7\x96\x8b", "\xe7\x96\x92",
+ "\xe7\x99\xb6", "\xe7\x99\xbd", "\xe7\x9a\xae", "\xe7\x9a\xbf", "\xe7\x9b\xae", "\xe7\x9f\x9b", "\xe7\x9f\xa2", "\xe7\x9f\xb3",
+ "\xe7\xa4\xba", "\xe7\xa6\xb8", "\xe7\xa6\xbe", "\xe7\xa9\xb4", "\xe7\xab\x8b", "\xe7\xab\xb9", "\xe7\xb1\xb3", "\xe7\xb3\xb8",
+ "\xe7\xbc\xb6", "\xe7\xbd\x91", "\xe7\xbe\x8a", "\xe7\xbe\xbd", "\xe8\x80\x81", "\xe8\x80\x8c", "\xe8\x80\x92", "\xe8\x80\xb3"
+};
+
+static const char *grn_nfkc50_decompose_table_e2be[] = {
+ "\xe8\x81\xbf", "\xe8\x82\x89", "\xe8\x87\xa3", "\xe8\x87\xaa", "\xe8\x87\xb3", "\xe8\x87\xbc", "\xe8\x88\x8c", "\xe8\x88\x9b",
+ "\xe8\x88\x9f", "\xe8\x89\xae", "\xe8\x89\xb2", "\xe8\x89\xb8", "\xe8\x99\x8d", "\xe8\x99\xab", "\xe8\xa1\x80", "\xe8\xa1\x8c",
+ "\xe8\xa1\xa3", "\xe8\xa5\xbe", "\xe8\xa6\x8b", "\xe8\xa7\x92", "\xe8\xa8\x80", "\xe8\xb0\xb7", "\xe8\xb1\x86", "\xe8\xb1\x95",
+ "\xe8\xb1\xb8", "\xe8\xb2\x9d", "\xe8\xb5\xa4", "\xe8\xb5\xb0", "\xe8\xb6\xb3", "\xe8\xba\xab", "\xe8\xbb\x8a", "\xe8\xbe\x9b",
+ "\xe8\xbe\xb0", "\xe8\xbe\xb5", "\xe9\x82\x91", "\xe9\x85\x89", "\xe9\x87\x86", "\xe9\x87\x8c", "\xe9\x87\x91", "\xe9\x95\xb7",
+ "\xe9\x96\x80", "\xe9\x98\x9c", "\xe9\x9a\xb6", "\xe9\x9a\xb9", "\xe9\x9b\xa8", "\xe9\x9d\x91", "\xe9\x9d\x9e", "\xe9\x9d\xa2",
+ "\xe9\x9d\xa9", "\xe9\x9f\x8b", "\xe9\x9f\xad", "\xe9\x9f\xb3", "\xe9\xa0\x81", "\xe9\xa2\xa8", "\xe9\xa3\x9b", "\xe9\xa3\x9f",
+ "\xe9\xa6\x96", "\xe9\xa6\x99", "\xe9\xa6\xac", "\xe9\xaa\xa8", "\xe9\xab\x98", "\xe9\xab\x9f", "\xe9\xac\xa5", "\xe9\xac\xaf"
+};
+
+static const char *grn_nfkc50_decompose_table_e2bf[] = {
+ "\xe9\xac\xb2", "\xe9\xac\xbc", "\xe9\xad\x9a", "\xe9\xb3\xa5", "\xe9\xb9\xb5", "\xe9\xb9\xbf", "\xe9\xba\xa5", "\xe9\xba\xbb",
+ "\xe9\xbb\x83", "\xe9\xbb\x8d", "\xe9\xbb\x91", "\xe9\xbb\xb9", "\xe9\xbb\xbd", "\xe9\xbc\x8e", "\xe9\xbc\x93", "\xe9\xbc\xa0",
+ "\xe9\xbc\xbb", "\xe9\xbd\x8a", "\xe9\xbd\x92", "\xe9\xbe\x8d", "\xe9\xbe\x9c", "\xe9\xbe\xa0"
+};
+
+static const char *grn_nfkc50_decompose_table_e380[] = {
+ "\x20", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\x7e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xe3\x80\x92", NULL,
+ "\xe5\x8d\x81", "\xe5\x8d\x84", "\xe5\x8d\x85"
+};
+
+static const char *grn_nfkc50_decompose_table_e382[] = {
+ "\xe3\x82\x99", "\xe3\x82\x9a", NULL, NULL, "\xe3\x82\x88\xe3\x82\x8a"
+};
+
+static const char *grn_nfkc50_decompose_table_e384[] = {
+ "\xe1\x84\x80", "\xe1\x84\x81", "\xe1\x86\xaa", "\xe1\x84\x82", "\xe1\x86\xac", "\xe1\x86\xad", "\xe1\x84\x83", "\xe1\x84\x84",
+ "\xe1\x84\x85", "\xe1\x86\xb0", "\xe1\x86\xb1", "\xe1\x86\xb2", "\xe1\x86\xb3", "\xe1\x86\xb4", "\xe1\x86\xb5"
+};
+
+static const char *grn_nfkc50_decompose_table_e385[] = {
+ "\xe1\x84\x9a", "\xe1\x84\x86", "\xe1\x84\x87", "\xe1\x84\x88", "\xe1\x84\xa1", "\xe1\x84\x89", "\xe1\x84\x8a", "\xe1\x84\x8b",
+ "\xe1\x84\x8c", "\xe1\x84\x8d", "\xe1\x84\x8e", "\xe1\x84\x8f", "\xe1\x84\x90", "\xe1\x84\x91", "\xe1\x84\x92", "\xe1\x85\xa1",
+ "\xe1\x85\xa2", "\xe1\x85\xa3", "\xe1\x85\xa4", "\xe1\x85\xa5", "\xe1\x85\xa6", "\xe1\x85\xa7", "\xe1\x85\xa8", "\xe1\x85\xa9",
+ "\xe1\x85\xaa", "\xe1\x85\xab", "\xe1\x85\xac", "\xe1\x85\xad", "\xe1\x85\xae", "\xe1\x85\xaf", "\xe1\x85\xb0", "\xe1\x85\xb1",
+ "\xe1\x85\xb2", "\xe1\x85\xb3", "\xe1\x85\xb4", "\xe1\x85\xb5", "\xe1\x85\xa0", "\xe1\x84\x94", "\xe1\x84\x95", "\xe1\x87\x87",
+ "\xe1\x87\x88", "\xe1\x87\x8c", "\xe1\x87\x8e", "\xe1\x87\x93", "\xe1\x87\x97", "\xe1\x87\x99", "\xe1\x84\x9c", "\xe1\x87\x9d",
+ "\xe1\x87\x9f", "\xe1\x84\x9d", "\xe1\x84\x9e", "\xe1\x84\xa0", "\xe1\x84\xa2", "\xe1\x84\xa3", "\xe1\x84\xa7", "\xe1\x84\xa9",
+ "\xe1\x84\xab", "\xe1\x84\xac", "\xe1\x84\xad", "\xe1\x84\xae", "\xe1\x84\xaf", "\xe1\x84\xb2", "\xe1\x84\xb6", "\xe1\x85\x80"
+};
+
+static const char *grn_nfkc50_decompose_table_e386[] = {
+ "\xe1\x85\x87", "\xe1\x85\x8c", "\xe1\x87\xb1", "\xe1\x87\xb2", "\xe1\x85\x97", "\xe1\x85\x98", "\xe1\x85\x99", "\xe1\x86\x84",
+ "\xe1\x86\x85", "\xe1\x86\x88", "\xe1\x86\x91", "\xe1\x86\x92", "\xe1\x86\x94", "\xe1\x86\x9e", "\xe1\x86\xa1", NULL,
+ NULL, NULL, "\xe4\xb8\x80", "\xe4\xba\x8c", "\xe4\xb8\x89", "\xe5\x9b\x9b", "\xe4\xb8\x8a", "\xe4\xb8\xad",
+ "\xe4\xb8\x8b", "\xe7\x94\xb2", "\xe4\xb9\x99", "\xe4\xb8\x99", "\xe4\xb8\x81", "\xe5\xa4\xa9", "\xe5\x9c\xb0", "\xe4\xba\xba"
+};
+
+static const char *grn_nfkc50_decompose_table_e388[] = {
+ "\x28\xe1\x84\x80\x29", "\x28\xe1\x84\x82\x29", "\x28\xe1\x84\x83\x29", "\x28\xe1\x84\x85\x29", "\x28\xe1\x84\x86\x29", "\x28\xe1\x84\x87\x29", "\x28\xe1\x84\x89\x29", "\x28\xe1\x84\x8b\x29",
+ "\x28\xe1\x84\x8c\x29", "\x28\xe1\x84\x8e\x29", "\x28\xe1\x84\x8f\x29", "\x28\xe1\x84\x90\x29", "\x28\xe1\x84\x91\x29", "\x28\xe1\x84\x92\x29", "\x28\xea\xb0\x80\x29", "\x28\xeb\x82\x98\x29",
+ "\x28\xeb\x8b\xa4\x29", "\x28\xeb\x9d\xbc\x29", "\x28\xeb\xa7\x88\x29", "\x28\xeb\xb0\x94\x29", "\x28\xec\x82\xac\x29", "\x28\xec\x95\x84\x29", "\x28\xec\x9e\x90\x29", "\x28\xec\xb0\xa8\x29",
+ "\x28\xec\xb9\xb4\x29", "\x28\xed\x83\x80\x29", "\x28\xed\x8c\x8c\x29", "\x28\xed\x95\x98\x29", "\x28\xec\xa3\xbc\x29", "\x28\xec\x98\xa4\xec\xa0\x84\x29", "\x28\xec\x98\xa4\xed\x9b\x84\x29", NULL,
+ "\x28\xe4\xb8\x80\x29", "\x28\xe4\xba\x8c\x29", "\x28\xe4\xb8\x89\x29", "\x28\xe5\x9b\x9b\x29", "\x28\xe4\xba\x94\x29", "\x28\xe5\x85\xad\x29", "\x28\xe4\xb8\x83\x29", "\x28\xe5\x85\xab\x29",
+ "\x28\xe4\xb9\x9d\x29", "\x28\xe5\x8d\x81\x29", "\x28\xe6\x9c\x88\x29", "\x28\xe7\x81\xab\x29", "\x28\xe6\xb0\xb4\x29", "\x28\xe6\x9c\xa8\x29", "\x28\xe9\x87\x91\x29", "\x28\xe5\x9c\x9f\x29",
+ "\x28\xe6\x97\xa5\x29", "\x28\xe6\xa0\xaa\x29", "\x28\xe6\x9c\x89\x29", "\x28\xe7\xa4\xbe\x29", "\x28\xe5\x90\x8d\x29", "\x28\xe7\x89\xb9\x29", "\x28\xe8\xb2\xa1\x29", "\x28\xe7\xa5\x9d\x29",
+ "\x28\xe5\x8a\xb4\x29", "\x28\xe4\xbb\xa3\x29", "\x28\xe5\x91\xbc\x29", "\x28\xe5\xad\xa6\x29", "\x28\xe7\x9b\xa3\x29", "\x28\xe4\xbc\x81\x29", "\x28\xe8\xb3\x87\x29", "\x28\xe5\x8d\x94\x29"
+};
+
+static const char *grn_nfkc50_decompose_table_e389[] = {
+ "\x28\xe7\xa5\xad\x29", "\x28\xe4\xbc\x91\x29", "\x28\xe8\x87\xaa\x29", "\x28\xe8\x87\xb3\x29", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\x70\x74\x65", "\x32\x31", "\x32\x32", "\x32\x33", "\x32\x34", "\x32\x35", "\x32\x36", "\x32\x37",
+ "\x32\x38", "\x32\x39", "\x33\x30", "\x33\x31", "\x33\x32", "\x33\x33", "\x33\x34", "\x33\x35",
+ "\xe1\x84\x80", "\xe1\x84\x82", "\xe1\x84\x83", "\xe1\x84\x85", "\xe1\x84\x86", "\xe1\x84\x87", "\xe1\x84\x89", "\xe1\x84\x8b",
+ "\xe1\x84\x8c", "\xe1\x84\x8e", "\xe1\x84\x8f", "\xe1\x84\x90", "\xe1\x84\x91", "\xe1\x84\x92", "\xea\xb0\x80", "\xeb\x82\x98",
+ "\xeb\x8b\xa4", "\xeb\x9d\xbc", "\xeb\xa7\x88", "\xeb\xb0\x94", "\xec\x82\xac", "\xec\x95\x84", "\xec\x9e\x90", "\xec\xb0\xa8",
+ "\xec\xb9\xb4", "\xed\x83\x80", "\xed\x8c\x8c", "\xed\x95\x98", "\xec\xb0\xb8\xea\xb3\xa0", "\xec\xa3\xbc\xec\x9d\x98", "\xec\x9a\xb0"
+};
+
+static const char *grn_nfkc50_decompose_table_e38a[] = {
+ "\xe4\xb8\x80", "\xe4\xba\x8c", "\xe4\xb8\x89", "\xe5\x9b\x9b", "\xe4\xba\x94", "\xe5\x85\xad", "\xe4\xb8\x83", "\xe5\x85\xab",
+ "\xe4\xb9\x9d", "\xe5\x8d\x81", "\xe6\x9c\x88", "\xe7\x81\xab", "\xe6\xb0\xb4", "\xe6\x9c\xa8", "\xe9\x87\x91", "\xe5\x9c\x9f",
+ "\xe6\x97\xa5", "\xe6\xa0\xaa", "\xe6\x9c\x89", "\xe7\xa4\xbe", "\xe5\x90\x8d", "\xe7\x89\xb9", "\xe8\xb2\xa1", "\xe7\xa5\x9d",
+ "\xe5\x8a\xb4", "\xe7\xa7\x98", "\xe7\x94\xb7", "\xe5\xa5\xb3", "\xe9\x81\xa9", "\xe5\x84\xaa", "\xe5\x8d\xb0", "\xe6\xb3\xa8",
+ "\xe9\xa0\x85", "\xe4\xbc\x91", "\xe5\x86\x99", "\xe6\xad\xa3", "\xe4\xb8\x8a", "\xe4\xb8\xad", "\xe4\xb8\x8b", "\xe5\xb7\xa6",
+ "\xe5\x8f\xb3", "\xe5\x8c\xbb", "\xe5\xae\x97", "\xe5\xad\xa6", "\xe7\x9b\xa3", "\xe4\xbc\x81", "\xe8\xb3\x87", "\xe5\x8d\x94",
+ "\xe5\xa4\x9c", "\x33\x36", "\x33\x37", "\x33\x38", "\x33\x39", "\x34\x30", "\x34\x31", "\x34\x32",
+ "\x34\x33", "\x34\x34", "\x34\x35", "\x34\x36", "\x34\x37", "\x34\x38", "\x34\x39", "\x35\x30"
+};
+
+static const char *grn_nfkc50_decompose_table_e38b[] = {
+ "\x31\xe6\x9c\x88", "\x32\xe6\x9c\x88", "\x33\xe6\x9c\x88", "\x34\xe6\x9c\x88", "\x35\xe6\x9c\x88", "\x36\xe6\x9c\x88", "\x37\xe6\x9c\x88", "\x38\xe6\x9c\x88",
+ "\x39\xe6\x9c\x88", "\x31\x30\xe6\x9c\x88", "\x31\x31\xe6\x9c\x88", "\x31\x32\xe6\x9c\x88", "\x68\x67", "\x65\x72\x67", "\x65\x76", "\x6c\x74\x64",
+ "\xe3\x82\xa2", "\xe3\x82\xa4", "\xe3\x82\xa6", "\xe3\x82\xa8", "\xe3\x82\xaa", "\xe3\x82\xab", "\xe3\x82\xad", "\xe3\x82\xaf",
+ "\xe3\x82\xb1", "\xe3\x82\xb3", "\xe3\x82\xb5", "\xe3\x82\xb7", "\xe3\x82\xb9", "\xe3\x82\xbb", "\xe3\x82\xbd", "\xe3\x82\xbf",
+ "\xe3\x83\x81", "\xe3\x83\x84", "\xe3\x83\x86", "\xe3\x83\x88", "\xe3\x83\x8a", "\xe3\x83\x8b", "\xe3\x83\x8c", "\xe3\x83\x8d",
+ "\xe3\x83\x8e", "\xe3\x83\x8f", "\xe3\x83\x92", "\xe3\x83\x95", "\xe3\x83\x98", "\xe3\x83\x9b", "\xe3\x83\x9e", "\xe3\x83\x9f",
+ "\xe3\x83\xa0", "\xe3\x83\xa1", "\xe3\x83\xa2", "\xe3\x83\xa4", "\xe3\x83\xa6", "\xe3\x83\xa8", "\xe3\x83\xa9", "\xe3\x83\xaa",
+ "\xe3\x83\xab", "\xe3\x83\xac", "\xe3\x83\xad", "\xe3\x83\xaf", "\xe3\x83\xb0", "\xe3\x83\xb1", "\xe3\x83\xb2"
+};
+
+static const char *grn_nfkc50_decompose_table_e38c[] = {
+ "\xe3\x82\xa2\xe3\x83\x91\xe3\x83\xbc\xe3\x83\x88", "\xe3\x82\xa2\xe3\x83\xab\xe3\x83\x95\xe3\x82\xa1", "\xe3\x82\xa2\xe3\x83\xb3\xe3\x83\x9a\xe3\x82\xa2", "\xe3\x82\xa2\xe3\x83\xbc\xe3\x83\xab", "\xe3\x82\xa4\xe3\x83\x8b\xe3\x83\xb3\xe3\x82\xb0", "\xe3\x82\xa4\xe3\x83\xb3\xe3\x83\x81", "\xe3\x82\xa6\xe3\x82\xa9\xe3\x83\xb3", "\xe3\x82\xa8\xe3\x82\xb9\xe3\x82\xaf\xe3\x83\xbc\xe3\x83\x89",
+ "\xe3\x82\xa8\xe3\x83\xbc\xe3\x82\xab\xe3\x83\xbc", "\xe3\x82\xaa\xe3\x83\xb3\xe3\x82\xb9", "\xe3\x82\xaa\xe3\x83\xbc\xe3\x83\xa0", "\xe3\x82\xab\xe3\x82\xa4\xe3\x83\xaa", "\xe3\x82\xab\xe3\x83\xa9\xe3\x83\x83\xe3\x83\x88", "\xe3\x82\xab\xe3\x83\xad\xe3\x83\xaa\xe3\x83\xbc", "\xe3\x82\xac\xe3\x83\xad\xe3\x83\xb3", "\xe3\x82\xac\xe3\x83\xb3\xe3\x83\x9e",
+ "\xe3\x82\xae\xe3\x82\xac", "\xe3\x82\xae\xe3\x83\x8b\xe3\x83\xbc", "\xe3\x82\xad\xe3\x83\xa5\xe3\x83\xaa\xe3\x83\xbc", "\xe3\x82\xae\xe3\x83\xab\xe3\x83\x80\xe3\x83\xbc", "\xe3\x82\xad\xe3\x83\xad", "\xe3\x82\xad\xe3\x83\xad\xe3\x82\xb0\xe3\x83\xa9\xe3\x83\xa0", "\xe3\x82\xad\xe3\x83\xad\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\x88\xe3\x83\xab", "\xe3\x82\xad\xe3\x83\xad\xe3\x83\xaf\xe3\x83\x83\xe3\x83\x88",
+ "\xe3\x82\xb0\xe3\x83\xa9\xe3\x83\xa0", "\xe3\x82\xb0\xe3\x83\xa9\xe3\x83\xa0\xe3\x83\x88\xe3\x83\xb3", "\xe3\x82\xaf\xe3\x83\xab\xe3\x82\xbc\xe3\x82\xa4\xe3\x83\xad", "\xe3\x82\xaf\xe3\x83\xad\xe3\x83\xbc\xe3\x83\x8d", "\xe3\x82\xb1\xe3\x83\xbc\xe3\x82\xb9", "\xe3\x82\xb3\xe3\x83\xab\xe3\x83\x8a", "\xe3\x82\xb3\xe3\x83\xbc\xe3\x83\x9d", "\xe3\x82\xb5\xe3\x82\xa4\xe3\x82\xaf\xe3\x83\xab",
+ "\xe3\x82\xb5\xe3\x83\xb3\xe3\x83\x81\xe3\x83\xbc\xe3\x83\xa0", "\xe3\x82\xb7\xe3\x83\xaa\xe3\x83\xb3\xe3\x82\xb0", "\xe3\x82\xbb\xe3\x83\xb3\xe3\x83\x81", "\xe3\x82\xbb\xe3\x83\xb3\xe3\x83\x88", "\xe3\x83\x80\xe3\x83\xbc\xe3\x82\xb9", "\xe3\x83\x87\xe3\x82\xb7", "\xe3\x83\x89\xe3\x83\xab", "\xe3\x83\x88\xe3\x83\xb3",
+ "\xe3\x83\x8a\xe3\x83\x8e", "\xe3\x83\x8e\xe3\x83\x83\xe3\x83\x88", "\xe3\x83\x8f\xe3\x82\xa4\xe3\x83\x84", "\xe3\x83\x91\xe3\x83\xbc\xe3\x82\xbb\xe3\x83\xb3\xe3\x83\x88", "\xe3\x83\x91\xe3\x83\xbc\xe3\x83\x84", "\xe3\x83\x90\xe3\x83\xbc\xe3\x83\xac\xe3\x83\xab", "\xe3\x83\x94\xe3\x82\xa2\xe3\x82\xb9\xe3\x83\x88\xe3\x83\xab", "\xe3\x83\x94\xe3\x82\xaf\xe3\x83\xab",
+ "\xe3\x83\x94\xe3\x82\xb3", "\xe3\x83\x93\xe3\x83\xab", "\xe3\x83\x95\xe3\x82\xa1\xe3\x83\xa9\xe3\x83\x83\xe3\x83\x89", "\xe3\x83\x95\xe3\x82\xa3\xe3\x83\xbc\xe3\x83\x88", "\xe3\x83\x96\xe3\x83\x83\xe3\x82\xb7\xe3\x82\xa7\xe3\x83\xab", "\xe3\x83\x95\xe3\x83\xa9\xe3\x83\xb3", "\xe3\x83\x98\xe3\x82\xaf\xe3\x82\xbf\xe3\x83\xbc\xe3\x83\xab", "\xe3\x83\x9a\xe3\x82\xbd",
+ "\xe3\x83\x9a\xe3\x83\x8b\xe3\x83\x92", "\xe3\x83\x98\xe3\x83\xab\xe3\x83\x84", "\xe3\x83\x9a\xe3\x83\xb3\xe3\x82\xb9", "\xe3\x83\x9a\xe3\x83\xbc\xe3\x82\xb8", "\xe3\x83\x99\xe3\x83\xbc\xe3\x82\xbf", "\xe3\x83\x9d\xe3\x82\xa4\xe3\x83\xb3\xe3\x83\x88", "\xe3\x83\x9c\xe3\x83\xab\xe3\x83\x88", "\xe3\x83\x9b\xe3\x83\xb3"
+};
+
+static const char *grn_nfkc50_decompose_table_e38d[] = {
+ "\xe3\x83\x9d\xe3\x83\xb3\xe3\x83\x89", "\xe3\x83\x9b\xe3\x83\xbc\xe3\x83\xab", "\xe3\x83\x9b\xe3\x83\xbc\xe3\x83\xb3", "\xe3\x83\x9e\xe3\x82\xa4\xe3\x82\xaf\xe3\x83\xad", "\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xab", "\xe3\x83\x9e\xe3\x83\x83\xe3\x83\x8f", "\xe3\x83\x9e\xe3\x83\xab\xe3\x82\xaf", "\xe3\x83\x9e\xe3\x83\xb3\xe3\x82\xb7\xe3\x83\xa7\xe3\x83\xb3",
+ "\xe3\x83\x9f\xe3\x82\xaf\xe3\x83\xad\xe3\x83\xb3", "\xe3\x83\x9f\xe3\x83\xaa", "\xe3\x83\x9f\xe3\x83\xaa\xe3\x83\x90\xe3\x83\xbc\xe3\x83\xab", "\xe3\x83\xa1\xe3\x82\xac", "\xe3\x83\xa1\xe3\x82\xac\xe3\x83\x88\xe3\x83\xb3", "\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\x88\xe3\x83\xab", "\xe3\x83\xa4\xe3\x83\xbc\xe3\x83\x89", "\xe3\x83\xa4\xe3\x83\xbc\xe3\x83\xab",
+ "\xe3\x83\xa6\xe3\x82\xa2\xe3\x83\xb3", "\xe3\x83\xaa\xe3\x83\x83\xe3\x83\x88\xe3\x83\xab", "\xe3\x83\xaa\xe3\x83\xa9", "\xe3\x83\xab\xe3\x83\x94\xe3\x83\xbc", "\xe3\x83\xab\xe3\x83\xbc\xe3\x83\x96\xe3\x83\xab", "\xe3\x83\xac\xe3\x83\xa0", "\xe3\x83\xac\xe3\x83\xb3\xe3\x83\x88\xe3\x82\xb2\xe3\x83\xb3", "\xe3\x83\xaf\xe3\x83\x83\xe3\x83\x88",
+ "\x30\xe7\x82\xb9", "\x31\xe7\x82\xb9", "\x32\xe7\x82\xb9", "\x33\xe7\x82\xb9", "\x34\xe7\x82\xb9", "\x35\xe7\x82\xb9", "\x36\xe7\x82\xb9", "\x37\xe7\x82\xb9",
+ "\x38\xe7\x82\xb9", "\x39\xe7\x82\xb9", "\x31\x30\xe7\x82\xb9", "\x31\x31\xe7\x82\xb9", "\x31\x32\xe7\x82\xb9", "\x31\x33\xe7\x82\xb9", "\x31\x34\xe7\x82\xb9", "\x31\x35\xe7\x82\xb9",
+ "\x31\x36\xe7\x82\xb9", "\x31\x37\xe7\x82\xb9", "\x31\x38\xe7\x82\xb9", "\x31\x39\xe7\x82\xb9", "\x32\x30\xe7\x82\xb9", "\x32\x31\xe7\x82\xb9", "\x32\x32\xe7\x82\xb9", "\x32\x33\xe7\x82\xb9",
+ "\x32\x34\xe7\x82\xb9", "\x68\x70\x61", "\x64\x61", "\x61\x75", "\x62\x61\x72", "\x6f\x76", "\x70\x63", "\x64\x6d",
+ "\x64\x6d\x32", "\x64\x6d\x33", "\x69\x75", "\xe5\xb9\xb3\xe6\x88\x90", "\xe6\x98\xad\xe5\x92\x8c", "\xe5\xa4\xa7\xe6\xad\xa3", "\xe6\x98\x8e\xe6\xb2\xbb", "\xe6\xa0\xaa\xe5\xbc\x8f\xe4\xbc\x9a\xe7\xa4\xbe"
+};
+
+static const char *grn_nfkc50_decompose_table_e38e[] = {
+ "\x70\x61", "\x6e\x61", "\xce\xbc\x61", "\x6d\x61", "\x6b\x61", "\x6b\x62", "\x6d\x62", "\x67\x62",
+ "\x63\x61\x6c", "\x6b\x63\x61\x6c", "\x70\x66", "\x6e\x66", "\xce\xbc\x66", "\xce\xbc\x67", "\x6d\x67", "\x6b\x67",
+ "\x68\x7a", "\x6b\x68\x7a", "\x6d\x68\x7a", "\x67\x68\x7a", "\x74\x68\x7a", "\xce\xbc\x6c", "\x6d\x6c", "\x64\x6c",
+ "\x6b\x6c", "\x66\x6d", "\x6e\x6d", "\xce\xbc\x6d", "\x6d\x6d", "\x63\x6d", "\x6b\x6d", "\x6d\x6d\x32",
+ "\x63\x6d\x32", "\x6d\x32", "\x6b\x6d\x32", "\x6d\x6d\x33", "\x63\x6d\x33", "\x6d\x33", "\x6b\x6d\x33", "\x6d\xe2\x88\x95\x73",
+ "\x6d\xe2\x88\x95\x73\x32", "\x70\x61", "\x6b\x70\x61", "\x6d\x70\x61", "\x67\x70\x61", "\x72\x61\x64", "\x72\x61\x64\xe2\x88\x95\x73", "\x72\x61\x64\xe2\x88\x95\x73\x32",
+ "\x70\x73", "\x6e\x73", "\xce\xbc\x73", "\x6d\x73", "\x70\x76", "\x6e\x76", "\xce\xbc\x76", "\x6d\x76",
+ "\x6b\x76", "\x6d\x76", "\x70\x77", "\x6e\x77", "\xce\xbc\x77", "\x6d\x77", "\x6b\x77", "\x6d\x77"
+};
+
+static const char *grn_nfkc50_decompose_table_e38f[] = {
+ "\x6b\xce\xa9", "\x6d\xce\xa9", "\x61\x2e\x6d\x2e", "\x62\x71", "\x63\x63", "\x63\x64", "\x63\xe2\x88\x95\x6b\x67", "\x63\x6f\x2e",
+ "\x64\x62", "\x67\x79", "\x68\x61", "\x68\x70", "\x69\x6e", "\x6b\x6b", "\x6b\x6d", "\x6b\x74",
+ "\x6c\x6d", "\x6c\x6e", "\x6c\x6f\x67", "\x6c\x78", "\x6d\x62", "\x6d\x69\x6c", "\x6d\x6f\x6c", "\x70\x68",
+ "\x70\x2e\x6d\x2e", "\x70\x70\x6d", "\x70\x72", "\x73\x72", "\x73\x76", "\x77\x62", "\x76\xe2\x88\x95\x6d", "\x61\xe2\x88\x95\x6d",
+ "\x31\xe6\x97\xa5", "\x32\xe6\x97\xa5", "\x33\xe6\x97\xa5", "\x34\xe6\x97\xa5", "\x35\xe6\x97\xa5", "\x36\xe6\x97\xa5", "\x37\xe6\x97\xa5", "\x38\xe6\x97\xa5",
+ "\x39\xe6\x97\xa5", "\x31\x30\xe6\x97\xa5", "\x31\x31\xe6\x97\xa5", "\x31\x32\xe6\x97\xa5", "\x31\x33\xe6\x97\xa5", "\x31\x34\xe6\x97\xa5", "\x31\x35\xe6\x97\xa5", "\x31\x36\xe6\x97\xa5",
+ "\x31\x37\xe6\x97\xa5", "\x31\x38\xe6\x97\xa5", "\x31\x39\xe6\x97\xa5", "\x32\x30\xe6\x97\xa5", "\x32\x31\xe6\x97\xa5", "\x32\x32\xe6\x97\xa5", "\x32\x33\xe6\x97\xa5", "\x32\x34\xe6\x97\xa5",
+ "\x32\x35\xe6\x97\xa5", "\x32\x36\xe6\x97\xa5", "\x32\x37\xe6\x97\xa5", "\x32\x38\xe6\x97\xa5", "\x32\x39\xe6\x97\xa5", "\x33\x30\xe6\x97\xa5", "\x33\x31\xe6\x97\xa5", "\x67\x61\x6c"
+};
+
+static const char *grn_nfkc50_decompose_table_efa4[] = {
+ "\xe8\xb1\x88", "\xe6\x9b\xb4", "\xe8\xbb\x8a", "\xe8\xb3\x88", "\xe6\xbb\x91", "\xe4\xb8\xb2", "\xe5\x8f\xa5", "\xe9\xbe\x9c",
+ "\xe9\xbe\x9c", "\xe5\xa5\x91", "\xe9\x87\x91", "\xe5\x96\x87", "\xe5\xa5\x88", "\xe6\x87\xb6", "\xe7\x99\xa9", "\xe7\xbe\x85",
+ "\xe8\x98\xbf", "\xe8\x9e\xba", "\xe8\xa3\xb8", "\xe9\x82\x8f", "\xe6\xa8\x82", "\xe6\xb4\x9b", "\xe7\x83\x99", "\xe7\x8f\x9e",
+ "\xe8\x90\xbd", "\xe9\x85\xaa", "\xe9\xa7\xb1", "\xe4\xba\x82", "\xe5\x8d\xb5", "\xe6\xac\x84", "\xe7\x88\x9b", "\xe8\x98\xad",
+ "\xe9\xb8\x9e", "\xe5\xb5\x90", "\xe6\xbf\xab", "\xe8\x97\x8d", "\xe8\xa5\xa4", "\xe6\x8b\x89", "\xe8\x87\x98", "\xe8\xa0\x9f",
+ "\xe5\xbb\x8a", "\xe6\x9c\x97", "\xe6\xb5\xaa", "\xe7\x8b\xbc", "\xe9\x83\x8e", "\xe4\xbe\x86", "\xe5\x86\xb7", "\xe5\x8b\x9e",
+ "\xe6\x93\x84", "\xe6\xab\x93", "\xe7\x88\x90", "\xe7\x9b\xa7", "\xe8\x80\x81", "\xe8\x98\x86", "\xe8\x99\x9c", "\xe8\xb7\xaf",
+ "\xe9\x9c\xb2", "\xe9\xad\xaf", "\xe9\xb7\xba", "\xe7\xa2\x8c", "\xe7\xa5\xbf", "\xe7\xb6\xa0", "\xe8\x8f\x89", "\xe9\x8c\x84"
+};
+
+static const char *grn_nfkc50_decompose_table_efa5[] = {
+ "\xe9\xb9\xbf", "\xe8\xab\x96", "\xe5\xa3\x9f", "\xe5\xbc\x84", "\xe7\xb1\xa0", "\xe8\x81\xbe", "\xe7\x89\xa2", "\xe7\xa3\x8a",
+ "\xe8\xb3\x82", "\xe9\x9b\xb7", "\xe5\xa3\x98", "\xe5\xb1\xa2", "\xe6\xa8\x93", "\xe6\xb7\x9a", "\xe6\xbc\x8f", "\xe7\xb4\xaf",
+ "\xe7\xb8\xb7", "\xe9\x99\x8b", "\xe5\x8b\x92", "\xe8\x82\x8b", "\xe5\x87\x9c", "\xe5\x87\x8c", "\xe7\xa8\x9c", "\xe7\xb6\xbe",
+ "\xe8\x8f\xb1", "\xe9\x99\xb5", "\xe8\xae\x80", "\xe6\x8b\x8f", "\xe6\xa8\x82", "\xe8\xab\xbe", "\xe4\xb8\xb9", "\xe5\xaf\xa7",
+ "\xe6\x80\x92", "\xe7\x8e\x87", "\xe7\x95\xb0", "\xe5\x8c\x97", "\xe7\xa3\xbb", "\xe4\xbe\xbf", "\xe5\xbe\xa9", "\xe4\xb8\x8d",
+ "\xe6\xb3\x8c", "\xe6\x95\xb8", "\xe7\xb4\xa2", "\xe5\x8f\x83", "\xe5\xa1\x9e", "\xe7\x9c\x81", "\xe8\x91\x89", "\xe8\xaa\xaa",
+ "\xe6\xae\xba", "\xe8\xbe\xb0", "\xe6\xb2\x88", "\xe6\x8b\xbe", "\xe8\x8b\xa5", "\xe6\x8e\xa0", "\xe7\x95\xa5", "\xe4\xba\xae",
+ "\xe5\x85\xa9", "\xe5\x87\x89", "\xe6\xa2\x81", "\xe7\xb3\xa7", "\xe8\x89\xaf", "\xe8\xab\x92", "\xe9\x87\x8f", "\xe5\x8b\xb5"
+};
+
+static const char *grn_nfkc50_decompose_table_efa6[] = {
+ "\xe5\x91\x82", "\xe5\xa5\xb3", "\xe5\xbb\xac", "\xe6\x97\x85", "\xe6\xbf\xbe", "\xe7\xa4\xaa", "\xe9\x96\xad", "\xe9\xa9\xaa",
+ "\xe9\xba\x97", "\xe9\xbb\x8e", "\xe5\x8a\x9b", "\xe6\x9b\x86", "\xe6\xad\xb7", "\xe8\xbd\xa2", "\xe5\xb9\xb4", "\xe6\x86\x90",
+ "\xe6\x88\x80", "\xe6\x92\x9a", "\xe6\xbc\xa3", "\xe7\x85\x89", "\xe7\x92\x89", "\xe7\xa7\x8a", "\xe7\xb7\xb4", "\xe8\x81\xaf",
+ "\xe8\xbc\xa6", "\xe8\x93\xae", "\xe9\x80\xa3", "\xe9\x8d\x8a", "\xe5\x88\x97", "\xe5\x8a\xa3", "\xe5\x92\xbd", "\xe7\x83\x88",
+ "\xe8\xa3\x82", "\xe8\xaa\xaa", "\xe5\xbb\x89", "\xe5\xbf\xb5", "\xe6\x8d\xbb", "\xe6\xae\xae", "\xe7\xb0\xbe", "\xe7\x8d\xb5",
+ "\xe4\xbb\xa4", "\xe5\x9b\xb9", "\xe5\xaf\xa7", "\xe5\xb6\xba", "\xe6\x80\x9c", "\xe7\x8e\xb2", "\xe7\x91\xa9", "\xe7\xbe\x9a",
+ "\xe8\x81\x86", "\xe9\x88\xb4", "\xe9\x9b\xb6", "\xe9\x9d\x88", "\xe9\xa0\x98", "\xe4\xbe\x8b", "\xe7\xa6\xae", "\xe9\x86\xb4",
+ "\xe9\x9a\xb8", "\xe6\x83\xa1", "\xe4\xba\x86", "\xe5\x83\x9a", "\xe5\xaf\xae", "\xe5\xb0\xbf", "\xe6\x96\x99", "\xe6\xa8\x82"
+};
+
+static const char *grn_nfkc50_decompose_table_efa7[] = {
+ "\xe7\x87\x8e", "\xe7\x99\x82", "\xe8\x93\xbc", "\xe9\x81\xbc", "\xe9\xbe\x8d", "\xe6\x9a\x88", "\xe9\x98\xae", "\xe5\x8a\x89",
+ "\xe6\x9d\xbb", "\xe6\x9f\xb3", "\xe6\xb5\x81", "\xe6\xba\x9c", "\xe7\x90\x89", "\xe7\x95\x99", "\xe7\xa1\xab", "\xe7\xb4\x90",
+ "\xe9\xa1\x9e", "\xe5\x85\xad", "\xe6\x88\xae", "\xe9\x99\xb8", "\xe5\x80\xab", "\xe5\xb4\x99", "\xe6\xb7\xaa", "\xe8\xbc\xaa",
+ "\xe5\xbe\x8b", "\xe6\x85\x84", "\xe6\xa0\x97", "\xe7\x8e\x87", "\xe9\x9a\x86", "\xe5\x88\xa9", "\xe5\x90\x8f", "\xe5\xb1\xa5",
+ "\xe6\x98\x93", "\xe6\x9d\x8e", "\xe6\xa2\xa8", "\xe6\xb3\xa5", "\xe7\x90\x86", "\xe7\x97\xa2", "\xe7\xbd\xb9", "\xe8\xa3\x8f",
+ "\xe8\xa3\xa1", "\xe9\x87\x8c", "\xe9\x9b\xa2", "\xe5\x8c\xbf", "\xe6\xba\xba", "\xe5\x90\x9d", "\xe7\x87\x90", "\xe7\x92\x98",
+ "\xe8\x97\xba", "\xe9\x9a\xa3", "\xe9\xb1\x97", "\xe9\xba\x9f", "\xe6\x9e\x97", "\xe6\xb7\x8b", "\xe8\x87\xa8", "\xe7\xab\x8b",
+ "\xe7\xac\xa0", "\xe7\xb2\x92", "\xe7\x8b\x80", "\xe7\x82\x99", "\xe8\xad\x98", "\xe4\xbb\x80", "\xe8\x8c\xb6", "\xe5\x88\xba"
+};
+
+static const char *grn_nfkc50_decompose_table_efa8[] = {
+ "\xe5\x88\x87", "\xe5\xba\xa6", "\xe6\x8b\x93", "\xe7\xb3\x96", "\xe5\xae\x85", "\xe6\xb4\x9e", "\xe6\x9a\xb4", "\xe8\xbc\xbb",
+ "\xe8\xa1\x8c", "\xe9\x99\x8d", "\xe8\xa6\x8b", "\xe5\xbb\x93", "\xe5\x85\x80", "\xe5\x97\x80", NULL, NULL,
+ "\xe5\xa1\x9a", NULL, "\xe6\x99\xb4", NULL, NULL, "\xe5\x87\x9e", "\xe7\x8c\xaa", "\xe7\x9b\x8a",
+ "\xe7\xa4\xbc", "\xe7\xa5\x9e", "\xe7\xa5\xa5", "\xe7\xa6\x8f", "\xe9\x9d\x96", "\xe7\xb2\xbe", "\xe7\xbe\xbd", NULL,
+ "\xe8\x98\x92", NULL, "\xe8\xab\xb8", NULL, NULL, "\xe9\x80\xb8", "\xe9\x83\xbd", NULL,
+ NULL, NULL, "\xe9\xa3\xaf", "\xe9\xa3\xbc", "\xe9\xa4\xa8", "\xe9\xb6\xb4", NULL, NULL,
+ "\xe4\xbe\xae", "\xe5\x83\xa7", "\xe5\x85\x8d", "\xe5\x8b\x89", "\xe5\x8b\xa4", "\xe5\x8d\x91", "\xe5\x96\x9d", "\xe5\x98\x86",
+ "\xe5\x99\xa8", "\xe5\xa1\x80", "\xe5\xa2\xa8", "\xe5\xb1\xa4", "\xe5\xb1\xae", "\xe6\x82\x94", "\xe6\x85\xa8", "\xe6\x86\x8e"
+};
+
+static const char *grn_nfkc50_decompose_table_efa9[] = {
+ "\xe6\x87\xb2", "\xe6\x95\x8f", "\xe6\x97\xa2", "\xe6\x9a\x91", "\xe6\xa2\x85", "\xe6\xb5\xb7", "\xe6\xb8\x9a", "\xe6\xbc\xa2",
+ "\xe7\x85\xae", "\xe7\x88\xab", "\xe7\x90\xa2", "\xe7\xa2\x91", "\xe7\xa4\xbe", "\xe7\xa5\x89", "\xe7\xa5\x88", "\xe7\xa5\x90",
+ "\xe7\xa5\x96", "\xe7\xa5\x9d", "\xe7\xa6\x8d", "\xe7\xa6\x8e", "\xe7\xa9\x80", "\xe7\xaa\x81", "\xe7\xaf\x80", "\xe7\xb7\xb4",
+ "\xe7\xb8\x89", "\xe7\xb9\x81", "\xe7\xbd\xb2", "\xe8\x80\x85", "\xe8\x87\xad", "\xe8\x89\xb9", "\xe8\x89\xb9", "\xe8\x91\x97",
+ "\xe8\xa4\x90", "\xe8\xa6\x96", "\xe8\xac\x81", "\xe8\xac\xb9", "\xe8\xb3\x93", "\xe8\xb4\x88", "\xe8\xbe\xb6", "\xe9\x80\xb8",
+ "\xe9\x9b\xa3", "\xe9\x9f\xbf", "\xe9\xa0\xbb", NULL, NULL, NULL, NULL, NULL,
+ "\xe4\xb8\xa6", "\xe5\x86\xb5", "\xe5\x85\xa8", "\xe4\xbe\x80", "\xe5\x85\x85", "\xe5\x86\x80", "\xe5\x8b\x87", "\xe5\x8b\xba",
+ "\xe5\x96\x9d", "\xe5\x95\x95", "\xe5\x96\x99", "\xe5\x97\xa2", "\xe5\xa1\x9a", "\xe5\xa2\xb3", "\xe5\xa5\x84", "\xe5\xa5\x94"
+};
+
+static const char *grn_nfkc50_decompose_table_efaa[] = {
+ "\xe5\xa9\xa2", "\xe5\xac\xa8", "\xe5\xbb\x92", "\xe5\xbb\x99", "\xe5\xbd\xa9", "\xe5\xbe\xad", "\xe6\x83\x98", "\xe6\x85\x8e",
+ "\xe6\x84\x88", "\xe6\x86\x8e", "\xe6\x85\xa0", "\xe6\x87\xb2", "\xe6\x88\xb4", "\xe6\x8f\x84", "\xe6\x90\x9c", "\xe6\x91\x92",
+ "\xe6\x95\x96", "\xe6\x99\xb4", "\xe6\x9c\x97", "\xe6\x9c\x9b", "\xe6\x9d\x96", "\xe6\xad\xb9", "\xe6\xae\xba", "\xe6\xb5\x81",
+ "\xe6\xbb\x9b", "\xe6\xbb\x8b", "\xe6\xbc\xa2", "\xe7\x80\x9e", "\xe7\x85\xae", "\xe7\x9e\xa7", "\xe7\x88\xb5", "\xe7\x8a\xaf",
+ "\xe7\x8c\xaa", "\xe7\x91\xb1", "\xe7\x94\x86", "\xe7\x94\xbb", "\xe7\x98\x9d", "\xe7\x98\x9f", "\xe7\x9b\x8a", "\xe7\x9b\x9b",
+ "\xe7\x9b\xb4", "\xe7\x9d\x8a", "\xe7\x9d\x80", "\xe7\xa3\x8c", "\xe7\xaa\xb1", "\xe7\xaf\x80", "\xe7\xb1\xbb", "\xe7\xb5\x9b",
+ "\xe7\xb7\xb4", "\xe7\xbc\xbe", "\xe8\x80\x85", "\xe8\x8d\x92", "\xe8\x8f\xaf", "\xe8\x9d\xb9", "\xe8\xa5\x81", "\xe8\xa6\x86",
+ "\xe8\xa6\x96", "\xe8\xaa\xbf", "\xe8\xab\xb8", "\xe8\xab\x8b", "\xe8\xac\x81", "\xe8\xab\xbe", "\xe8\xab\xad", "\xe8\xac\xb9"
+};
+
+static const char *grn_nfkc50_decompose_table_efab[] = {
+ "\xe8\xae\x8a", "\xe8\xb4\x88", "\xe8\xbc\xb8", "\xe9\x81\xb2", "\xe9\x86\x99", "\xe9\x89\xb6", "\xe9\x99\xbc", "\xe9\x9b\xa3",
+ "\xe9\x9d\x96", "\xe9\x9f\x9b", "\xe9\x9f\xbf", "\xe9\xa0\x8b", "\xe9\xa0\xbb", "\xe9\xac\x92", "\xe9\xbe\x9c", "\xf0\xa2\xa1\x8a",
+ "\xf0\xa2\xa1\x84", "\xf0\xa3\x8f\x95", "\xe3\xae\x9d", "\xe4\x80\x98", "\xe4\x80\xb9", "\xf0\xa5\x89\x89", "\xf0\xa5\xb3\x90", "\xf0\xa7\xbb\x93",
+ "\xe9\xbd\x83", "\xe9\xbe\x8e"
+};
+
+static const char *grn_nfkc50_decompose_table_efac[] = {
+ "\x66\x66", "\x66\x69", "\x66\x6c", "\x66\x66\x69", "\x66\x66\x6c", "\x73\x74", "\x73\x74", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\xd5\xb4\xd5\xb6", "\xd5\xb4\xd5\xa5", "\xd5\xb4\xd5\xab", "\xd5\xbe\xd5\xb6", "\xd5\xb4\xd5\xad",
+ NULL, NULL, NULL, NULL, NULL, "\xd7\x99\xd6\xb4", NULL, "\xd7\xb2\xd6\xb7",
+ "\xd7\xa2", "\xd7\x90", "\xd7\x93", "\xd7\x94", "\xd7\x9b", "\xd7\x9c", "\xd7\x9d", "\xd7\xa8",
+ "\xd7\xaa", "\x2b", "\xd7\xa9\xd7\x81", "\xd7\xa9\xd7\x82", "\xd7\xa9\xd6\xbc\xd7\x81", "\xd7\xa9\xd6\xbc\xd7\x82", "\xd7\x90\xd6\xb7", "\xd7\x90\xd6\xb8",
+ "\xd7\x90\xd6\xbc", "\xd7\x91\xd6\xbc", "\xd7\x92\xd6\xbc", "\xd7\x93\xd6\xbc", "\xd7\x94\xd6\xbc", "\xd7\x95\xd6\xbc", "\xd7\x96\xd6\xbc", NULL,
+ "\xd7\x98\xd6\xbc", "\xd7\x99\xd6\xbc", "\xd7\x9a\xd6\xbc", "\xd7\x9b\xd6\xbc", "\xd7\x9c\xd6\xbc", NULL, "\xd7\x9e\xd6\xbc"
+};
+
+static const char *grn_nfkc50_decompose_table_efad[] = {
+ "\xd7\xa0\xd6\xbc", "\xd7\xa1\xd6\xbc", NULL, "\xd7\xa3\xd6\xbc", "\xd7\xa4\xd6\xbc", NULL, "\xd7\xa6\xd6\xbc", "\xd7\xa7\xd6\xbc",
+ "\xd7\xa8\xd6\xbc", "\xd7\xa9\xd6\xbc", "\xd7\xaa\xd6\xbc", "\xd7\x95\xd6\xb9", "\xd7\x91\xd6\xbf", "\xd7\x9b\xd6\xbf", "\xd7\xa4\xd6\xbf", "\xd7\x90\xd7\x9c",
+ "\xd9\xb1", "\xd9\xb1", "\xd9\xbb", "\xd9\xbb", "\xd9\xbb", "\xd9\xbb", "\xd9\xbe", "\xd9\xbe",
+ "\xd9\xbe", "\xd9\xbe", "\xda\x80", "\xda\x80", "\xda\x80", "\xda\x80", "\xd9\xba", "\xd9\xba",
+ "\xd9\xba", "\xd9\xba", "\xd9\xbf", "\xd9\xbf", "\xd9\xbf", "\xd9\xbf", "\xd9\xb9", "\xd9\xb9",
+ "\xd9\xb9", "\xd9\xb9", "\xda\xa4", "\xda\xa4", "\xda\xa4", "\xda\xa4", "\xda\xa6", "\xda\xa6",
+ "\xda\xa6", "\xda\xa6", "\xda\x84", "\xda\x84", "\xda\x84", "\xda\x84", "\xda\x83", "\xda\x83",
+ "\xda\x83", "\xda\x83", "\xda\x86", "\xda\x86", "\xda\x86", "\xda\x86", "\xda\x87", "\xda\x87"
+};
+
+static const char *grn_nfkc50_decompose_table_efae[] = {
+ "\xda\x87", "\xda\x87", "\xda\x8d", "\xda\x8d", "\xda\x8c", "\xda\x8c", "\xda\x8e", "\xda\x8e",
+ "\xda\x88", "\xda\x88", "\xda\x98", "\xda\x98", "\xda\x91", "\xda\x91", "\xda\xa9", "\xda\xa9",
+ "\xda\xa9", "\xda\xa9", "\xda\xaf", "\xda\xaf", "\xda\xaf", "\xda\xaf", "\xda\xb3", "\xda\xb3",
+ "\xda\xb3", "\xda\xb3", "\xda\xb1", "\xda\xb1", "\xda\xb1", "\xda\xb1", "\xda\xba", "\xda\xba",
+ "\xda\xbb", "\xda\xbb", "\xda\xbb", "\xda\xbb", "\xdb\x80", "\xdb\x80", "\xdb\x81", "\xdb\x81",
+ "\xdb\x81", "\xdb\x81", "\xda\xbe", "\xda\xbe", "\xda\xbe", "\xda\xbe", "\xdb\x92", "\xdb\x92",
+ "\xdb\x93", "\xdb\x93"
+};
+
+static const char *grn_nfkc50_decompose_table_efaf[] = {
+ "\xda\xad", "\xda\xad", "\xda\xad", "\xda\xad", "\xdb\x87", "\xdb\x87", "\xdb\x86", "\xdb\x86",
+ "\xdb\x88", "\xdb\x88", "\xdb\x87\xd9\xb4", "\xdb\x8b", "\xdb\x8b", "\xdb\x85", "\xdb\x85", "\xdb\x89",
+ "\xdb\x89", "\xdb\x90", "\xdb\x90", "\xdb\x90", "\xdb\x90", "\xd9\x89", "\xd9\x89", "\xd8\xa6\xd8\xa7",
+ "\xd8\xa6\xd8\xa7", "\xd8\xa6\xdb\x95", "\xd8\xa6\xdb\x95", "\xd8\xa6\xd9\x88", "\xd8\xa6\xd9\x88", "\xd8\xa6\xdb\x87", "\xd8\xa6\xdb\x87", "\xd8\xa6\xdb\x86",
+ "\xd8\xa6\xdb\x86", "\xd8\xa6\xdb\x88", "\xd8\xa6\xdb\x88", "\xd8\xa6\xdb\x90", "\xd8\xa6\xdb\x90", "\xd8\xa6\xdb\x90", "\xd8\xa6\xd9\x89", "\xd8\xa6\xd9\x89",
+ "\xd8\xa6\xd9\x89", "\xdb\x8c", "\xdb\x8c", "\xdb\x8c", "\xdb\x8c"
+};
+
+static const char *grn_nfkc50_decompose_table_efb0[] = {
+ "\xd8\xa6\xd8\xac", "\xd8\xa6\xd8\xad", "\xd8\xa6\xd9\x85", "\xd8\xa6\xd9\x89", "\xd8\xa6\xd9\x8a", "\xd8\xa8\xd8\xac", "\xd8\xa8\xd8\xad", "\xd8\xa8\xd8\xae",
+ "\xd8\xa8\xd9\x85", "\xd8\xa8\xd9\x89", "\xd8\xa8\xd9\x8a", "\xd8\xaa\xd8\xac", "\xd8\xaa\xd8\xad", "\xd8\xaa\xd8\xae", "\xd8\xaa\xd9\x85", "\xd8\xaa\xd9\x89",
+ "\xd8\xaa\xd9\x8a", "\xd8\xab\xd8\xac", "\xd8\xab\xd9\x85", "\xd8\xab\xd9\x89", "\xd8\xab\xd9\x8a", "\xd8\xac\xd8\xad", "\xd8\xac\xd9\x85", "\xd8\xad\xd8\xac",
+ "\xd8\xad\xd9\x85", "\xd8\xae\xd8\xac", "\xd8\xae\xd8\xad", "\xd8\xae\xd9\x85", "\xd8\xb3\xd8\xac", "\xd8\xb3\xd8\xad", "\xd8\xb3\xd8\xae", "\xd8\xb3\xd9\x85",
+ "\xd8\xb5\xd8\xad", "\xd8\xb5\xd9\x85", "\xd8\xb6\xd8\xac", "\xd8\xb6\xd8\xad", "\xd8\xb6\xd8\xae", "\xd8\xb6\xd9\x85", "\xd8\xb7\xd8\xad", "\xd8\xb7\xd9\x85",
+ "\xd8\xb8\xd9\x85", "\xd8\xb9\xd8\xac", "\xd8\xb9\xd9\x85", "\xd8\xba\xd8\xac", "\xd8\xba\xd9\x85", "\xd9\x81\xd8\xac", "\xd9\x81\xd8\xad", "\xd9\x81\xd8\xae",
+ "\xd9\x81\xd9\x85", "\xd9\x81\xd9\x89", "\xd9\x81\xd9\x8a", "\xd9\x82\xd8\xad", "\xd9\x82\xd9\x85", "\xd9\x82\xd9\x89", "\xd9\x82\xd9\x8a", "\xd9\x83\xd8\xa7",
+ "\xd9\x83\xd8\xac", "\xd9\x83\xd8\xad", "\xd9\x83\xd8\xae", "\xd9\x83\xd9\x84", "\xd9\x83\xd9\x85", "\xd9\x83\xd9\x89", "\xd9\x83\xd9\x8a", "\xd9\x84\xd8\xac"
+};
+
+static const char *grn_nfkc50_decompose_table_efb1[] = {
+ "\xd9\x84\xd8\xad", "\xd9\x84\xd8\xae", "\xd9\x84\xd9\x85", "\xd9\x84\xd9\x89", "\xd9\x84\xd9\x8a", "\xd9\x85\xd8\xac", "\xd9\x85\xd8\xad", "\xd9\x85\xd8\xae",
+ "\xd9\x85\xd9\x85", "\xd9\x85\xd9\x89", "\xd9\x85\xd9\x8a", "\xd9\x86\xd8\xac", "\xd9\x86\xd8\xad", "\xd9\x86\xd8\xae", "\xd9\x86\xd9\x85", "\xd9\x86\xd9\x89",
+ "\xd9\x86\xd9\x8a", "\xd9\x87\xd8\xac", "\xd9\x87\xd9\x85", "\xd9\x87\xd9\x89", "\xd9\x87\xd9\x8a", "\xd9\x8a\xd8\xac", "\xd9\x8a\xd8\xad", "\xd9\x8a\xd8\xae",
+ "\xd9\x8a\xd9\x85", "\xd9\x8a\xd9\x89", "\xd9\x8a\xd9\x8a", "\xd8\xb0\xd9\xb0", "\xd8\xb1\xd9\xb0", "\xd9\x89\xd9\xb0", "\xd9\x8c\xd9\x91", "\xd9\x8d\xd9\x91",
+ "\xd9\x8e\xd9\x91", "\xd9\x8f\xd9\x91", "\xd9\x90\xd9\x91", "\xd9\x91\xd9\xb0", "\xd8\xa6\xd8\xb1", "\xd8\xa6\xd8\xb2", "\xd8\xa6\xd9\x85", "\xd8\xa6\xd9\x86",
+ "\xd8\xa6\xd9\x89", "\xd8\xa6\xd9\x8a", "\xd8\xa8\xd8\xb1", "\xd8\xa8\xd8\xb2", "\xd8\xa8\xd9\x85", "\xd8\xa8\xd9\x86", "\xd8\xa8\xd9\x89", "\xd8\xa8\xd9\x8a",
+ "\xd8\xaa\xd8\xb1", "\xd8\xaa\xd8\xb2", "\xd8\xaa\xd9\x85", "\xd8\xaa\xd9\x86", "\xd8\xaa\xd9\x89", "\xd8\xaa\xd9\x8a", "\xd8\xab\xd8\xb1", "\xd8\xab\xd8\xb2",
+ "\xd8\xab\xd9\x85", "\xd8\xab\xd9\x86", "\xd8\xab\xd9\x89", "\xd8\xab\xd9\x8a", "\xd9\x81\xd9\x89", "\xd9\x81\xd9\x8a", "\xd9\x82\xd9\x89", "\xd9\x82\xd9\x8a"
+};
+
+static const char *grn_nfkc50_decompose_table_efb2[] = {
+ "\xd9\x83\xd8\xa7", "\xd9\x83\xd9\x84", "\xd9\x83\xd9\x85", "\xd9\x83\xd9\x89", "\xd9\x83\xd9\x8a", "\xd9\x84\xd9\x85", "\xd9\x84\xd9\x89", "\xd9\x84\xd9\x8a",
+ "\xd9\x85\xd8\xa7", "\xd9\x85\xd9\x85", "\xd9\x86\xd8\xb1", "\xd9\x86\xd8\xb2", "\xd9\x86\xd9\x85", "\xd9\x86\xd9\x86", "\xd9\x86\xd9\x89", "\xd9\x86\xd9\x8a",
+ "\xd9\x89\xd9\xb0", "\xd9\x8a\xd8\xb1", "\xd9\x8a\xd8\xb2", "\xd9\x8a\xd9\x85", "\xd9\x8a\xd9\x86", "\xd9\x8a\xd9\x89", "\xd9\x8a\xd9\x8a", "\xd8\xa6\xd8\xac",
+ "\xd8\xa6\xd8\xad", "\xd8\xa6\xd8\xae", "\xd8\xa6\xd9\x85", "\xd8\xa6\xd9\x87", "\xd8\xa8\xd8\xac", "\xd8\xa8\xd8\xad", "\xd8\xa8\xd8\xae", "\xd8\xa8\xd9\x85",
+ "\xd8\xa8\xd9\x87", "\xd8\xaa\xd8\xac", "\xd8\xaa\xd8\xad", "\xd8\xaa\xd8\xae", "\xd8\xaa\xd9\x85", "\xd8\xaa\xd9\x87", "\xd8\xab\xd9\x85", "\xd8\xac\xd8\xad",
+ "\xd8\xac\xd9\x85", "\xd8\xad\xd8\xac", "\xd8\xad\xd9\x85", "\xd8\xae\xd8\xac", "\xd8\xae\xd9\x85", "\xd8\xb3\xd8\xac", "\xd8\xb3\xd8\xad", "\xd8\xb3\xd8\xae",
+ "\xd8\xb3\xd9\x85", "\xd8\xb5\xd8\xad", "\xd8\xb5\xd8\xae", "\xd8\xb5\xd9\x85", "\xd8\xb6\xd8\xac", "\xd8\xb6\xd8\xad", "\xd8\xb6\xd8\xae", "\xd8\xb6\xd9\x85",
+ "\xd8\xb7\xd8\xad", "\xd8\xb8\xd9\x85", "\xd8\xb9\xd8\xac", "\xd8\xb9\xd9\x85", "\xd8\xba\xd8\xac", "\xd8\xba\xd9\x85", "\xd9\x81\xd8\xac", "\xd9\x81\xd8\xad"
+};
+
+static const char *grn_nfkc50_decompose_table_efb3[] = {
+ "\xd9\x81\xd8\xae", "\xd9\x81\xd9\x85", "\xd9\x82\xd8\xad", "\xd9\x82\xd9\x85", "\xd9\x83\xd8\xac", "\xd9\x83\xd8\xad", "\xd9\x83\xd8\xae", "\xd9\x83\xd9\x84",
+ "\xd9\x83\xd9\x85", "\xd9\x84\xd8\xac", "\xd9\x84\xd8\xad", "\xd9\x84\xd8\xae", "\xd9\x84\xd9\x85", "\xd9\x84\xd9\x87", "\xd9\x85\xd8\xac", "\xd9\x85\xd8\xad",
+ "\xd9\x85\xd8\xae", "\xd9\x85\xd9\x85", "\xd9\x86\xd8\xac", "\xd9\x86\xd8\xad", "\xd9\x86\xd8\xae", "\xd9\x86\xd9\x85", "\xd9\x86\xd9\x87", "\xd9\x87\xd8\xac",
+ "\xd9\x87\xd9\x85", "\xd9\x87\xd9\xb0", "\xd9\x8a\xd8\xac", "\xd9\x8a\xd8\xad", "\xd9\x8a\xd8\xae", "\xd9\x8a\xd9\x85", "\xd9\x8a\xd9\x87", "\xd8\xa6\xd9\x85",
+ "\xd8\xa6\xd9\x87", "\xd8\xa8\xd9\x85", "\xd8\xa8\xd9\x87", "\xd8\xaa\xd9\x85", "\xd8\xaa\xd9\x87", "\xd8\xab\xd9\x85", "\xd8\xab\xd9\x87", "\xd8\xb3\xd9\x85",
+ "\xd8\xb3\xd9\x87", "\xd8\xb4\xd9\x85", "\xd8\xb4\xd9\x87", "\xd9\x83\xd9\x84", "\xd9\x83\xd9\x85", "\xd9\x84\xd9\x85", "\xd9\x86\xd9\x85", "\xd9\x86\xd9\x87",
+ "\xd9\x8a\xd9\x85", "\xd9\x8a\xd9\x87", "\xd9\x80\xd9\x8e\xd9\x91", "\xd9\x80\xd9\x8f\xd9\x91", "\xd9\x80\xd9\x90\xd9\x91", "\xd8\xb7\xd9\x89", "\xd8\xb7\xd9\x8a", "\xd8\xb9\xd9\x89",
+ "\xd8\xb9\xd9\x8a", "\xd8\xba\xd9\x89", "\xd8\xba\xd9\x8a", "\xd8\xb3\xd9\x89", "\xd8\xb3\xd9\x8a", "\xd8\xb4\xd9\x89", "\xd8\xb4\xd9\x8a", "\xd8\xad\xd9\x89"
+};
+
+static const char *grn_nfkc50_decompose_table_efb4[] = {
+ "\xd8\xad\xd9\x8a", "\xd8\xac\xd9\x89", "\xd8\xac\xd9\x8a", "\xd8\xae\xd9\x89", "\xd8\xae\xd9\x8a", "\xd8\xb5\xd9\x89", "\xd8\xb5\xd9\x8a", "\xd8\xb6\xd9\x89",
+ "\xd8\xb6\xd9\x8a", "\xd8\xb4\xd8\xac", "\xd8\xb4\xd8\xad", "\xd8\xb4\xd8\xae", "\xd8\xb4\xd9\x85", "\xd8\xb4\xd8\xb1", "\xd8\xb3\xd8\xb1", "\xd8\xb5\xd8\xb1",
+ "\xd8\xb6\xd8\xb1", "\xd8\xb7\xd9\x89", "\xd8\xb7\xd9\x8a", "\xd8\xb9\xd9\x89", "\xd8\xb9\xd9\x8a", "\xd8\xba\xd9\x89", "\xd8\xba\xd9\x8a", "\xd8\xb3\xd9\x89",
+ "\xd8\xb3\xd9\x8a", "\xd8\xb4\xd9\x89", "\xd8\xb4\xd9\x8a", "\xd8\xad\xd9\x89", "\xd8\xad\xd9\x8a", "\xd8\xac\xd9\x89", "\xd8\xac\xd9\x8a", "\xd8\xae\xd9\x89",
+ "\xd8\xae\xd9\x8a", "\xd8\xb5\xd9\x89", "\xd8\xb5\xd9\x8a", "\xd8\xb6\xd9\x89", "\xd8\xb6\xd9\x8a", "\xd8\xb4\xd8\xac", "\xd8\xb4\xd8\xad", "\xd8\xb4\xd8\xae",
+ "\xd8\xb4\xd9\x85", "\xd8\xb4\xd8\xb1", "\xd8\xb3\xd8\xb1", "\xd8\xb5\xd8\xb1", "\xd8\xb6\xd8\xb1", "\xd8\xb4\xd8\xac", "\xd8\xb4\xd8\xad", "\xd8\xb4\xd8\xae",
+ "\xd8\xb4\xd9\x85", "\xd8\xb3\xd9\x87", "\xd8\xb4\xd9\x87", "\xd8\xb7\xd9\x85", "\xd8\xb3\xd8\xac", "\xd8\xb3\xd8\xad", "\xd8\xb3\xd8\xae", "\xd8\xb4\xd8\xac",
+ "\xd8\xb4\xd8\xad", "\xd8\xb4\xd8\xae", "\xd8\xb7\xd9\x85", "\xd8\xb8\xd9\x85", "\xd8\xa7\xd9\x8b", "\xd8\xa7\xd9\x8b"
+};
+
+static const char *grn_nfkc50_decompose_table_efb5[] = {
+ "\xd8\xaa\xd8\xac\xd9\x85", "\xd8\xaa\xd8\xad\xd8\xac", "\xd8\xaa\xd8\xad\xd8\xac", "\xd8\xaa\xd8\xad\xd9\x85", "\xd8\xaa\xd8\xae\xd9\x85", "\xd8\xaa\xd9\x85\xd8\xac", "\xd8\xaa\xd9\x85\xd8\xad", "\xd8\xaa\xd9\x85\xd8\xae",
+ "\xd8\xac\xd9\x85\xd8\xad", "\xd8\xac\xd9\x85\xd8\xad", "\xd8\xad\xd9\x85\xd9\x8a", "\xd8\xad\xd9\x85\xd9\x89", "\xd8\xb3\xd8\xad\xd8\xac", "\xd8\xb3\xd8\xac\xd8\xad", "\xd8\xb3\xd8\xac\xd9\x89", "\xd8\xb3\xd9\x85\xd8\xad",
+ "\xd8\xb3\xd9\x85\xd8\xad", "\xd8\xb3\xd9\x85\xd8\xac", "\xd8\xb3\xd9\x85\xd9\x85", "\xd8\xb3\xd9\x85\xd9\x85", "\xd8\xb5\xd8\xad\xd8\xad", "\xd8\xb5\xd8\xad\xd8\xad", "\xd8\xb5\xd9\x85\xd9\x85", "\xd8\xb4\xd8\xad\xd9\x85",
+ "\xd8\xb4\xd8\xad\xd9\x85", "\xd8\xb4\xd8\xac\xd9\x8a", "\xd8\xb4\xd9\x85\xd8\xae", "\xd8\xb4\xd9\x85\xd8\xae", "\xd8\xb4\xd9\x85\xd9\x85", "\xd8\xb4\xd9\x85\xd9\x85", "\xd8\xb6\xd8\xad\xd9\x89", "\xd8\xb6\xd8\xae\xd9\x85",
+ "\xd8\xb6\xd8\xae\xd9\x85", "\xd8\xb7\xd9\x85\xd8\xad", "\xd8\xb7\xd9\x85\xd8\xad", "\xd8\xb7\xd9\x85\xd9\x85", "\xd8\xb7\xd9\x85\xd9\x8a", "\xd8\xb9\xd8\xac\xd9\x85", "\xd8\xb9\xd9\x85\xd9\x85", "\xd8\xb9\xd9\x85\xd9\x85",
+ "\xd8\xb9\xd9\x85\xd9\x89", "\xd8\xba\xd9\x85\xd9\x85", "\xd8\xba\xd9\x85\xd9\x8a", "\xd8\xba\xd9\x85\xd9\x89", "\xd9\x81\xd8\xae\xd9\x85", "\xd9\x81\xd8\xae\xd9\x85", "\xd9\x82\xd9\x85\xd8\xad", "\xd9\x82\xd9\x85\xd9\x85"
+};
+
+static const char *grn_nfkc50_decompose_table_efb6[] = {
+ "\xd9\x84\xd8\xad\xd9\x85", "\xd9\x84\xd8\xad\xd9\x8a", "\xd9\x84\xd8\xad\xd9\x89", "\xd9\x84\xd8\xac\xd8\xac", "\xd9\x84\xd8\xac\xd8\xac", "\xd9\x84\xd8\xae\xd9\x85", "\xd9\x84\xd8\xae\xd9\x85", "\xd9\x84\xd9\x85\xd8\xad",
+ "\xd9\x84\xd9\x85\xd8\xad", "\xd9\x85\xd8\xad\xd8\xac", "\xd9\x85\xd8\xad\xd9\x85", "\xd9\x85\xd8\xad\xd9\x8a", "\xd9\x85\xd8\xac\xd8\xad", "\xd9\x85\xd8\xac\xd9\x85", "\xd9\x85\xd8\xae\xd8\xac", "\xd9\x85\xd8\xae\xd9\x85",
+ NULL, NULL, "\xd9\x85\xd8\xac\xd8\xae", "\xd9\x87\xd9\x85\xd8\xac", "\xd9\x87\xd9\x85\xd9\x85", "\xd9\x86\xd8\xad\xd9\x85", "\xd9\x86\xd8\xad\xd9\x89", "\xd9\x86\xd8\xac\xd9\x85",
+ "\xd9\x86\xd8\xac\xd9\x85", "\xd9\x86\xd8\xac\xd9\x89", "\xd9\x86\xd9\x85\xd9\x8a", "\xd9\x86\xd9\x85\xd9\x89", "\xd9\x8a\xd9\x85\xd9\x85", "\xd9\x8a\xd9\x85\xd9\x85", "\xd8\xa8\xd8\xae\xd9\x8a", "\xd8\xaa\xd8\xac\xd9\x8a",
+ "\xd8\xaa\xd8\xac\xd9\x89", "\xd8\xaa\xd8\xae\xd9\x8a", "\xd8\xaa\xd8\xae\xd9\x89", "\xd8\xaa\xd9\x85\xd9\x8a", "\xd8\xaa\xd9\x85\xd9\x89", "\xd8\xac\xd9\x85\xd9\x8a", "\xd8\xac\xd8\xad\xd9\x89", "\xd8\xac\xd9\x85\xd9\x89",
+ "\xd8\xb3\xd8\xae\xd9\x89", "\xd8\xb5\xd8\xad\xd9\x8a", "\xd8\xb4\xd8\xad\xd9\x8a", "\xd8\xb6\xd8\xad\xd9\x8a", "\xd9\x84\xd8\xac\xd9\x8a", "\xd9\x84\xd9\x85\xd9\x8a", "\xd9\x8a\xd8\xad\xd9\x8a", "\xd9\x8a\xd8\xac\xd9\x8a",
+ "\xd9\x8a\xd9\x85\xd9\x8a", "\xd9\x85\xd9\x85\xd9\x8a", "\xd9\x82\xd9\x85\xd9\x8a", "\xd9\x86\xd8\xad\xd9\x8a", "\xd9\x82\xd9\x85\xd8\xad", "\xd9\x84\xd8\xad\xd9\x85", "\xd8\xb9\xd9\x85\xd9\x8a", "\xd9\x83\xd9\x85\xd9\x8a",
+ "\xd9\x86\xd8\xac\xd8\xad", "\xd9\x85\xd8\xae\xd9\x8a", "\xd9\x84\xd8\xac\xd9\x85", "\xd9\x83\xd9\x85\xd9\x85", "\xd9\x84\xd8\xac\xd9\x85", "\xd9\x86\xd8\xac\xd8\xad", "\xd8\xac\xd8\xad\xd9\x8a", "\xd8\xad\xd8\xac\xd9\x8a"
+};
+
+static const char *grn_nfkc50_decompose_table_efb7[] = {
+ "\xd9\x85\xd8\xac\xd9\x8a", "\xd9\x81\xd9\x85\xd9\x8a", "\xd8\xa8\xd8\xad\xd9\x8a", "\xd9\x83\xd9\x85\xd9\x85", "\xd8\xb9\xd8\xac\xd9\x85", "\xd8\xb5\xd9\x85\xd9\x85", "\xd8\xb3\xd8\xae\xd9\x8a", "\xd9\x86\xd8\xac\xd9\x8a",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd8\xb5\xd9\x84\xdb\x92", "\xd9\x82\xd9\x84\xdb\x92", "\xd8\xa7\xd9\x84\xd9\x84\xd9\x87", "\xd8\xa7\xd9\x83\xd8\xa8\xd8\xb1", "\xd9\x85\xd8\xad\xd9\x85\xd8\xaf", "\xd8\xb5\xd9\x84\xd8\xb9\xd9\x85", "\xd8\xb1\xd8\xb3\xd9\x88\xd9\x84", "\xd8\xb9\xd9\x84\xd9\x8a\xd9\x87",
+ "\xd9\x88\xd8\xb3\xd9\x84\xd9\x85", "\xd8\xb5\xd9\x84\xd9\x89", "\xd8\xb5\xd9\x84\xd9\x89\x20\xd8\xa7\xd9\x84\xd9\x84\xd9\x87\x20\xd8\xb9\xd9\x84\xd9\x8a\xd9\x87\x20\xd9\x88\xd8\xb3\xd9\x84\xd9\x85", "\xd8\xac\xd9\x84\x20\xd8\xac\xd9\x84\xd8\xa7\xd9\x84\xd9\x87", "\xd8\xb1\xdb\x8c\xd8\xa7\xd9\x84"
+};
+
+static const char *grn_nfkc50_decompose_table_efb8[] = {
+ "\x2c", "\xe3\x80\x81", "\xe3\x80\x82", "\x3a", "\x3b", "\x21", "\x3f", "\xe3\x80\x96",
+ "\xe3\x80\x97", "\x2e\x2e\x2e", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\x2e\x2e", "\xe2\x80\x94", "\xe2\x80\x93", "\x5f", "\x5f", "\x28", "\x29", "\x7b",
+ "\x7d", "\xe3\x80\x94", "\xe3\x80\x95", "\xe3\x80\x90", "\xe3\x80\x91", "\xe3\x80\x8a", "\xe3\x80\x8b", "\xe3\x80\x88"
+};
+
+static const char *grn_nfkc50_decompose_table_efb9[] = {
+ "\xe3\x80\x89", "\xe3\x80\x8c", "\xe3\x80\x8d", "\xe3\x80\x8e", "\xe3\x80\x8f", NULL, NULL, "\x5b",
+ "\x5d", "\xcc\x85", "\xcc\x85", "\xcc\x85", "\xcc\x85", "\x5f", "\x5f", "\x5f",
+ "\x2c", "\xe3\x80\x81", "\x2e", NULL, "\x3b", "\x3a", "\x3f", "\x21",
+ "\xe2\x80\x94", "\x28", "\x29", "\x7b", "\x7d", "\xe3\x80\x94", "\xe3\x80\x95", "\x23",
+ "\x26", "\x2a", "\x2b", "\x2d", "\x3c", "\x3e", "\x3d", NULL,
+ "\x5c", "\x24", "\x25", "\x40", NULL, NULL, NULL, NULL,
+ "\xd9\x8b", "\xd9\x80\xd9\x8b", "\xd9\x8c", NULL, "\xd9\x8d", NULL, "\xd9\x8e", "\xd9\x80\xd9\x8e",
+ "\xd9\x8f", "\xd9\x80\xd9\x8f", "\xd9\x90", "\xd9\x80\xd9\x90", "\xd9\x91", "\xd9\x80\xd9\x91", "\xd9\x92", "\xd9\x80\xd9\x92"
+};
+
+static const char *grn_nfkc50_decompose_table_efba[] = {
+ "\xd8\xa1", "\xd8\xa2", "\xd8\xa2", "\xd8\xa3", "\xd8\xa3", "\xd8\xa4", "\xd8\xa4", "\xd8\xa5",
+ "\xd8\xa5", "\xd8\xa6", "\xd8\xa6", "\xd8\xa6", "\xd8\xa6", "\xd8\xa7", "\xd8\xa7", "\xd8\xa8",
+ "\xd8\xa8", "\xd8\xa8", "\xd8\xa8", "\xd8\xa9", "\xd8\xa9", "\xd8\xaa", "\xd8\xaa", "\xd8\xaa",
+ "\xd8\xaa", "\xd8\xab", "\xd8\xab", "\xd8\xab", "\xd8\xab", "\xd8\xac", "\xd8\xac", "\xd8\xac",
+ "\xd8\xac", "\xd8\xad", "\xd8\xad", "\xd8\xad", "\xd8\xad", "\xd8\xae", "\xd8\xae", "\xd8\xae",
+ "\xd8\xae", "\xd8\xaf", "\xd8\xaf", "\xd8\xb0", "\xd8\xb0", "\xd8\xb1", "\xd8\xb1", "\xd8\xb2",
+ "\xd8\xb2", "\xd8\xb3", "\xd8\xb3", "\xd8\xb3", "\xd8\xb3", "\xd8\xb4", "\xd8\xb4", "\xd8\xb4",
+ "\xd8\xb4", "\xd8\xb5", "\xd8\xb5", "\xd8\xb5", "\xd8\xb5", "\xd8\xb6", "\xd8\xb6", "\xd8\xb6"
+};
+
+static const char *grn_nfkc50_decompose_table_efbb[] = {
+ "\xd8\xb6", "\xd8\xb7", "\xd8\xb7", "\xd8\xb7", "\xd8\xb7", "\xd8\xb8", "\xd8\xb8", "\xd8\xb8",
+ "\xd8\xb8", "\xd8\xb9", "\xd8\xb9", "\xd8\xb9", "\xd8\xb9", "\xd8\xba", "\xd8\xba", "\xd8\xba",
+ "\xd8\xba", "\xd9\x81", "\xd9\x81", "\xd9\x81", "\xd9\x81", "\xd9\x82", "\xd9\x82", "\xd9\x82",
+ "\xd9\x82", "\xd9\x83", "\xd9\x83", "\xd9\x83", "\xd9\x83", "\xd9\x84", "\xd9\x84", "\xd9\x84",
+ "\xd9\x84", "\xd9\x85", "\xd9\x85", "\xd9\x85", "\xd9\x85", "\xd9\x86", "\xd9\x86", "\xd9\x86",
+ "\xd9\x86", "\xd9\x87", "\xd9\x87", "\xd9\x87", "\xd9\x87", "\xd9\x88", "\xd9\x88", "\xd9\x89",
+ "\xd9\x89", "\xd9\x8a", "\xd9\x8a", "\xd9\x8a", "\xd9\x8a", "\xd9\x84\xd8\xa2", "\xd9\x84\xd8\xa2", "\xd9\x84\xd8\xa3",
+ "\xd9\x84\xd8\xa3", "\xd9\x84\xd8\xa5", "\xd9\x84\xd8\xa5", "\xd9\x84\xd8\xa7", "\xd9\x84\xd8\xa7"
+};
+
+static const char *grn_nfkc50_decompose_table_efbc[] = {
+ "\x21", "\x22", "\x23", "\x24", "\x25", "\x26", "\x27", "\x28",
+ "\x29", "\x2a", "\x2b", "\x2c", "\x2d", "\x2e", "\x2f", "\x30",
+ "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", "\x38",
+ "\x39", "\x3a", "\x3b", "\x3c", "\x3d", "\x3e", "\x3f", "\x40",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x5b", "\x5c", "\x5d", "\x5e", "\x5f"
+};
+
+static const char *grn_nfkc50_decompose_table_efbd[] = {
+ "\x60", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67",
+ "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f",
+ "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77",
+ "\x78", "\x79", "\x7a", "\x7b", "\x7c", "\x7d", "\x7e", "\xe2\xa6\x85",
+ "\xe2\xa6\x86", "\xe3\x80\x82", "\xe3\x80\x8c", "\xe3\x80\x8d", "\xe3\x80\x81", "\xe3\x83\xbb", "\xe3\x83\xb2", "\xe3\x82\xa1",
+ "\xe3\x82\xa3", "\xe3\x82\xa5", "\xe3\x82\xa7", "\xe3\x82\xa9", "\xe3\x83\xa3", "\xe3\x83\xa5", "\xe3\x83\xa7", "\xe3\x83\x83",
+ "\xe3\x83\xbc", "\xe3\x82\xa2", "\xe3\x82\xa4", "\xe3\x82\xa6", "\xe3\x82\xa8", "\xe3\x82\xaa", "\xe3\x82\xab", "\xe3\x82\xad",
+ "\xe3\x82\xaf", "\xe3\x82\xb1", "\xe3\x82\xb3", "\xe3\x82\xb5", "\xe3\x82\xb7", "\xe3\x82\xb9", "\xe3\x82\xbb", "\xe3\x82\xbd"
+};
+
+static const char *grn_nfkc50_decompose_table_efbe[] = {
+ "\xe3\x82\xbf", "\xe3\x83\x81", "\xe3\x83\x84", "\xe3\x83\x86", "\xe3\x83\x88", "\xe3\x83\x8a", "\xe3\x83\x8b", "\xe3\x83\x8c",
+ "\xe3\x83\x8d", "\xe3\x83\x8e", "\xe3\x83\x8f", "\xe3\x83\x92", "\xe3\x83\x95", "\xe3\x83\x98", "\xe3\x83\x9b", "\xe3\x83\x9e",
+ "\xe3\x83\x9f", "\xe3\x83\xa0", "\xe3\x83\xa1", "\xe3\x83\xa2", "\xe3\x83\xa4", "\xe3\x83\xa6", "\xe3\x83\xa8", "\xe3\x83\xa9",
+ "\xe3\x83\xaa", "\xe3\x83\xab", "\xe3\x83\xac", "\xe3\x83\xad", "\xe3\x83\xaf", "\xe3\x83\xb3", "\xe3\x82\x99", "\xe3\x82\x9a",
+ "\xe1\x85\xa0", "\xe1\x84\x80", "\xe1\x84\x81", "\xe1\x86\xaa", "\xe1\x84\x82", "\xe1\x86\xac", "\xe1\x86\xad", "\xe1\x84\x83",
+ "\xe1\x84\x84", "\xe1\x84\x85", "\xe1\x86\xb0", "\xe1\x86\xb1", "\xe1\x86\xb2", "\xe1\x86\xb3", "\xe1\x86\xb4", "\xe1\x86\xb5",
+ "\xe1\x84\x9a", "\xe1\x84\x86", "\xe1\x84\x87", "\xe1\x84\x88", "\xe1\x84\xa1", "\xe1\x84\x89", "\xe1\x84\x8a", "\xe1\x84\x8b",
+ "\xe1\x84\x8c", "\xe1\x84\x8d", "\xe1\x84\x8e", "\xe1\x84\x8f", "\xe1\x84\x90", "\xe1\x84\x91", "\xe1\x84\x92"
+};
+
+static const char *grn_nfkc50_decompose_table_efbf[] = {
+ "\xe1\x85\xa1", "\xe1\x85\xa2", "\xe1\x85\xa3", "\xe1\x85\xa4", "\xe1\x85\xa5", "\xe1\x85\xa6", NULL, NULL,
+ "\xe1\x85\xa7", "\xe1\x85\xa8", "\xe1\x85\xa9", "\xe1\x85\xaa", "\xe1\x85\xab", "\xe1\x85\xac", NULL, NULL,
+ "\xe1\x85\xad", "\xe1\x85\xae", "\xe1\x85\xaf", "\xe1\x85\xb0", "\xe1\x85\xb1", "\xe1\x85\xb2", NULL, NULL,
+ "\xe1\x85\xb3", "\xe1\x85\xb4", "\xe1\x85\xb5", NULL, NULL, NULL, "\xc2\xa2", "\xc2\xa3",
+ "\xc2\xac", "\xcc\x84", "\xc2\xa6", "\xc2\xa5", "\xe2\x82\xa9", NULL, "\xe2\x94\x82", "\xe2\x86\x90",
+ "\xe2\x86\x91", "\xe2\x86\x92", "\xe2\x86\x93", "\xe2\x96\xa0", "\xe2\x97\x8b"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d85[] = {
+ "\xf0\x9d\x85\x97\xf0\x9d\x85\xa5", "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5", "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xae", "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xaf", "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xb0", "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xb1", "\xf0\x9d\x85\x98\xf0\x9d\x85\xa5\xf0\x9d\x85\xb2"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d86[] = {
+ "\xf0\x9d\x86\xb9\xf0\x9d\x85\xa5", "\xf0\x9d\x86\xba\xf0\x9d\x85\xa5", "\xf0\x9d\x86\xb9\xf0\x9d\x85\xa5\xf0\x9d\x85\xae", "\xf0\x9d\x86\xba\xf0\x9d\x85\xa5\xf0\x9d\x85\xae", "\xf0\x9d\x86\xb9\xf0\x9d\x85\xa5\xf0\x9d\x85\xaf"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d90[] = {
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66",
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76",
+ "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64",
+ "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d91[] = {
+ "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74",
+ "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62",
+ "\x63", "\x64", "\x65", "\x66", "\x67", NULL, "\x69", "\x6a",
+ "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72",
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d92[] = {
+ "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66",
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76",
+ "\x77", "\x78", "\x79", "\x7a", "\x61", NULL, "\x63", "\x64",
+ NULL, NULL, "\x67", NULL, NULL, "\x6a", "\x6b", NULL,
+ NULL, "\x6e", "\x6f", "\x70", "\x71", NULL, "\x73", "\x74",
+ "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62",
+ "\x63", "\x64", NULL, "\x66", NULL, "\x68", "\x69", "\x6a"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d93[] = {
+ "\x6b", "\x6c", "\x6d", "\x6e", NULL, "\x70", "\x71", "\x72",
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66",
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d94[] = {
+ "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62", NULL, "\x64",
+ "\x65", "\x66", "\x67", NULL, NULL, "\x6a", "\x6b", "\x6c",
+ "\x6d", "\x6e", "\x6f", "\x70", "\x71", NULL, "\x73", "\x74",
+ "\x75", "\x76", "\x77", "\x78", "\x79", NULL, "\x61", "\x62",
+ "\x63", "\x64", "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a",
+ "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72",
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", NULL, "\x64", "\x65", "\x66", "\x67"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d95[] = {
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", NULL, "\x6f", NULL,
+ NULL, NULL, "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", NULL, "\x61", "\x62", "\x63", "\x64", "\x65", "\x66",
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76",
+ "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64",
+ "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c",
+ "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d96[] = {
+ "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62",
+ "\x63", "\x64", "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a",
+ "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72",
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d97[] = {
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76",
+ "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64",
+ "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c",
+ "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74",
+ "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62",
+ "\x63", "\x64", "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a",
+ "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d98[] = {
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70",
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66",
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76",
+ "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d99[] = {
+ "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c",
+ "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74",
+ "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a", "\x61", "\x62",
+ "\x63", "\x64", "\x65", "\x66", "\x67", "\x68", "\x69", "\x6a",
+ "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70", "\x71", "\x72",
+ "\x73", "\x74", "\x75", "\x76", "\x77", "\x78", "\x79", "\x7a",
+ "\x61", "\x62", "\x63", "\x64", "\x65", "\x66", "\x67", "\x68",
+ "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e", "\x6f", "\x70"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d9a[] = {
+ "\x71", "\x72", "\x73", "\x74", "\x75", "\x76", "\x77", "\x78",
+ "\x79", "\x7a", "\x61", "\x62", "\x63", "\x64", "\x65", "\x66",
+ "\x67", "\x68", "\x69", "\x6a", "\x6b", "\x6c", "\x6d", "\x6e",
+ "\x6f", "\x70", "\x71", "\x72", "\x73", "\x74", "\x75", "\x76",
+ "\x77", "\x78", "\x79", "\x7a", "\xc4\xb1", "\xc8\xb7", NULL, NULL,
+ "\xce\x91", "\xce\x92", "\xce\x93", "\xce\x94", "\xce\x95", "\xce\x96", "\xce\x97", "\xce\x98",
+ "\xce\x99", "\xce\x9a", "\xce\x9b", "\xce\x9c", "\xce\x9d", "\xce\x9e", "\xce\x9f", "\xce\xa0",
+ "\xce\xa1", "\xce\x98", "\xce\xa3", "\xce\xa4", "\xce\xa5", "\xce\xa6", "\xce\xa7", "\xce\xa8"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d9b[] = {
+ "\xce\xa9", "\xe2\x88\x87", "\xce\xb1", "\xce\xb2", "\xce\xb3", "\xce\xb4", "\xce\xb5", "\xce\xb6",
+ "\xce\xb7", "\xce\xb8", "\xce\xb9", "\xce\xba", "\xce\xbb", "\xce\xbc", "\xce\xbd", "\xce\xbe",
+ "\xce\xbf", "\xcf\x80", "\xcf\x81", "\xcf\x82", "\xcf\x83", "\xcf\x84", "\xcf\x85", "\xcf\x86",
+ "\xcf\x87", "\xcf\x88", "\xcf\x89", "\xe2\x88\x82", "\xce\xb5", "\xce\xb8", "\xce\xba", "\xcf\x86",
+ "\xcf\x81", "\xcf\x80", "\xce\x91", "\xce\x92", "\xce\x93", "\xce\x94", "\xce\x95", "\xce\x96",
+ "\xce\x97", "\xce\x98", "\xce\x99", "\xce\x9a", "\xce\x9b", "\xce\x9c", "\xce\x9d", "\xce\x9e",
+ "\xce\x9f", "\xce\xa0", "\xce\xa1", "\xce\x98", "\xce\xa3", "\xce\xa4", "\xce\xa5", "\xce\xa6",
+ "\xce\xa7", "\xce\xa8", "\xce\xa9", "\xe2\x88\x87", "\xce\xb1", "\xce\xb2", "\xce\xb3", "\xce\xb4"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d9c[] = {
+ "\xce\xb5", "\xce\xb6", "\xce\xb7", "\xce\xb8", "\xce\xb9", "\xce\xba", "\xce\xbb", "\xce\xbc",
+ "\xce\xbd", "\xce\xbe", "\xce\xbf", "\xcf\x80", "\xcf\x81", "\xcf\x82", "\xcf\x83", "\xcf\x84",
+ "\xcf\x85", "\xcf\x86", "\xcf\x87", "\xcf\x88", "\xcf\x89", "\xe2\x88\x82", "\xce\xb5", "\xce\xb8",
+ "\xce\xba", "\xcf\x86", "\xcf\x81", "\xcf\x80", "\xce\x91", "\xce\x92", "\xce\x93", "\xce\x94",
+ "\xce\x95", "\xce\x96", "\xce\x97", "\xce\x98", "\xce\x99", "\xce\x9a", "\xce\x9b", "\xce\x9c",
+ "\xce\x9d", "\xce\x9e", "\xce\x9f", "\xce\xa0", "\xce\xa1", "\xce\x98", "\xce\xa3", "\xce\xa4",
+ "\xce\xa5", "\xce\xa6", "\xce\xa7", "\xce\xa8", "\xce\xa9", "\xe2\x88\x87", "\xce\xb1", "\xce\xb2",
+ "\xce\xb3", "\xce\xb4", "\xce\xb5", "\xce\xb6", "\xce\xb7", "\xce\xb8", "\xce\xb9", "\xce\xba"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d9d[] = {
+ "\xce\xbb", "\xce\xbc", "\xce\xbd", "\xce\xbe", "\xce\xbf", "\xcf\x80", "\xcf\x81", "\xcf\x82",
+ "\xcf\x83", "\xcf\x84", "\xcf\x85", "\xcf\x86", "\xcf\x87", "\xcf\x88", "\xcf\x89", "\xe2\x88\x82",
+ "\xce\xb5", "\xce\xb8", "\xce\xba", "\xcf\x86", "\xcf\x81", "\xcf\x80", "\xce\x91", "\xce\x92",
+ "\xce\x93", "\xce\x94", "\xce\x95", "\xce\x96", "\xce\x97", "\xce\x98", "\xce\x99", "\xce\x9a",
+ "\xce\x9b", "\xce\x9c", "\xce\x9d", "\xce\x9e", "\xce\x9f", "\xce\xa0", "\xce\xa1", "\xce\x98",
+ "\xce\xa3", "\xce\xa4", "\xce\xa5", "\xce\xa6", "\xce\xa7", "\xce\xa8", "\xce\xa9", "\xe2\x88\x87",
+ "\xce\xb1", "\xce\xb2", "\xce\xb3", "\xce\xb4", "\xce\xb5", "\xce\xb6", "\xce\xb7", "\xce\xb8",
+ "\xce\xb9", "\xce\xba", "\xce\xbb", "\xce\xbc", "\xce\xbd", "\xce\xbe", "\xce\xbf", "\xcf\x80"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d9e[] = {
+ "\xcf\x81", "\xcf\x82", "\xcf\x83", "\xcf\x84", "\xcf\x85", "\xcf\x86", "\xcf\x87", "\xcf\x88",
+ "\xcf\x89", "\xe2\x88\x82", "\xce\xb5", "\xce\xb8", "\xce\xba", "\xcf\x86", "\xcf\x81", "\xcf\x80",
+ "\xce\x91", "\xce\x92", "\xce\x93", "\xce\x94", "\xce\x95", "\xce\x96", "\xce\x97", "\xce\x98",
+ "\xce\x99", "\xce\x9a", "\xce\x9b", "\xce\x9c", "\xce\x9d", "\xce\x9e", "\xce\x9f", "\xce\xa0",
+ "\xce\xa1", "\xce\x98", "\xce\xa3", "\xce\xa4", "\xce\xa5", "\xce\xa6", "\xce\xa7", "\xce\xa8",
+ "\xce\xa9", "\xe2\x88\x87", "\xce\xb1", "\xce\xb2", "\xce\xb3", "\xce\xb4", "\xce\xb5", "\xce\xb6",
+ "\xce\xb7", "\xce\xb8", "\xce\xb9", "\xce\xba", "\xce\xbb", "\xce\xbc", "\xce\xbd", "\xce\xbe",
+ "\xce\xbf", "\xcf\x80", "\xcf\x81", "\xcf\x82", "\xcf\x83", "\xcf\x84", "\xcf\x85", "\xcf\x86"
+};
+
+static const char *grn_nfkc50_decompose_table_f09d9f[] = {
+ "\xcf\x87", "\xcf\x88", "\xcf\x89", "\xe2\x88\x82", "\xce\xb5", "\xce\xb8", "\xce\xba", "\xcf\x86",
+ "\xcf\x81", "\xcf\x80", "\xcf\x9c", "\xcf\x9d", NULL, NULL, "\x30", "\x31",
+ "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", "\x38", "\x39",
+ "\x30", "\x31", "\x32", "\x33", "\x34", "\x35", "\x36", "\x37",
+ "\x38", "\x39", "\x30", "\x31", "\x32", "\x33", "\x34", "\x35",
+ "\x36", "\x37", "\x38", "\x39", "\x30", "\x31", "\x32", "\x33",
+ "\x34", "\x35", "\x36", "\x37", "\x38", "\x39", "\x30", "\x31",
+ "\x32", "\x33", "\x34", "\x35", "\x36", "\x37", "\x38", "\x39"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa0[] = {
+ "\xe4\xb8\xbd", "\xe4\xb8\xb8", "\xe4\xb9\x81", "\xf0\xa0\x84\xa2", "\xe4\xbd\xa0", "\xe4\xbe\xae", "\xe4\xbe\xbb", "\xe5\x80\x82",
+ "\xe5\x81\xba", "\xe5\x82\x99", "\xe5\x83\xa7", "\xe5\x83\x8f", "\xe3\x92\x9e", "\xf0\xa0\x98\xba", "\xe5\x85\x8d", "\xe5\x85\x94",
+ "\xe5\x85\xa4", "\xe5\x85\xb7", "\xf0\xa0\x94\x9c", "\xe3\x92\xb9", "\xe5\x85\xa7", "\xe5\x86\x8d", "\xf0\xa0\x95\x8b", "\xe5\x86\x97",
+ "\xe5\x86\xa4", "\xe4\xbb\x8c", "\xe5\x86\xac", "\xe5\x86\xb5", "\xf0\xa9\x87\x9f", "\xe5\x87\xb5", "\xe5\x88\x83", "\xe3\x93\x9f",
+ "\xe5\x88\xbb", "\xe5\x89\x86", "\xe5\x89\xb2", "\xe5\x89\xb7", "\xe3\x94\x95", "\xe5\x8b\x87", "\xe5\x8b\x89", "\xe5\x8b\xa4",
+ "\xe5\x8b\xba", "\xe5\x8c\x85", "\xe5\x8c\x86", "\xe5\x8c\x97", "\xe5\x8d\x89", "\xe5\x8d\x91", "\xe5\x8d\x9a", "\xe5\x8d\xb3",
+ "\xe5\x8d\xbd", "\xe5\x8d\xbf", "\xe5\x8d\xbf", "\xe5\x8d\xbf", "\xf0\xa0\xa8\xac", "\xe7\x81\xb0", "\xe5\x8f\x8a", "\xe5\x8f\x9f",
+ "\xf0\xa0\xad\xa3", "\xe5\x8f\xab", "\xe5\x8f\xb1", "\xe5\x90\x86", "\xe5\x92\x9e", "\xe5\x90\xb8", "\xe5\x91\x88", "\xe5\x91\xa8"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa1[] = {
+ "\xe5\x92\xa2", "\xe5\x93\xb6", "\xe5\x94\x90", "\xe5\x95\x93", "\xe5\x95\xa3", "\xe5\x96\x84", "\xe5\x96\x84", "\xe5\x96\x99",
+ "\xe5\x96\xab", "\xe5\x96\xb3", "\xe5\x97\x82", "\xe5\x9c\x96", "\xe5\x98\x86", "\xe5\x9c\x97", "\xe5\x99\x91", "\xe5\x99\xb4",
+ "\xe5\x88\x87", "\xe5\xa3\xae", "\xe5\x9f\x8e", "\xe5\x9f\xb4", "\xe5\xa0\x8d", "\xe5\x9e\x8b", "\xe5\xa0\xb2", "\xe5\xa0\xb1",
+ "\xe5\xa2\xac", "\xf0\xa1\x93\xa4", "\xe5\xa3\xb2", "\xe5\xa3\xb7", "\xe5\xa4\x86", "\xe5\xa4\x9a", "\xe5\xa4\xa2", "\xe5\xa5\xa2",
+ "\xf0\xa1\x9a\xa8", "\xf0\xa1\x9b\xaa", "\xe5\xa7\xac", "\xe5\xa8\x9b", "\xe5\xa8\xa7", "\xe5\xa7\x98", "\xe5\xa9\xa6", "\xe3\x9b\xae",
+ "\xe3\x9b\xbc", "\xe5\xac\x88", "\xe5\xac\xbe", "\xe5\xac\xbe", "\xf0\xa1\xa7\x88", "\xe5\xaf\x83", "\xe5\xaf\x98", "\xe5\xaf\xa7",
+ "\xe5\xaf\xb3", "\xf0\xa1\xac\x98", "\xe5\xaf\xbf", "\xe5\xb0\x86", "\xe5\xbd\x93", "\xe5\xb0\xa2", "\xe3\x9e\x81", "\xe5\xb1\xa0",
+ "\xe5\xb1\xae", "\xe5\xb3\x80", "\xe5\xb2\x8d", "\xf0\xa1\xb7\xa4", "\xe5\xb5\x83", "\xf0\xa1\xb7\xa6", "\xe5\xb5\xae", "\xe5\xb5\xab"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa2[] = {
+ "\xe5\xb5\xbc", "\xe5\xb7\xa1", "\xe5\xb7\xa2", "\xe3\xa0\xaf", "\xe5\xb7\xbd", "\xe5\xb8\xa8", "\xe5\xb8\xbd", "\xe5\xb9\xa9",
+ "\xe3\xa1\xa2", "\xf0\xa2\x86\x83", "\xe3\xa1\xbc", "\xe5\xba\xb0", "\xe5\xba\xb3", "\xe5\xba\xb6", "\xe5\xbb\x8a", "\xf0\xaa\x8e\x92",
+ "\xe5\xbb\xbe", "\xf0\xa2\x8c\xb1", "\xf0\xa2\x8c\xb1", "\xe8\x88\x81", "\xe5\xbc\xa2", "\xe5\xbc\xa2", "\xe3\xa3\x87", "\xf0\xa3\x8a\xb8",
+ "\xf0\xa6\x87\x9a", "\xe5\xbd\xa2", "\xe5\xbd\xab", "\xe3\xa3\xa3", "\xe5\xbe\x9a", "\xe5\xbf\x8d", "\xe5\xbf\x97", "\xe5\xbf\xb9",
+ "\xe6\x82\x81", "\xe3\xa4\xba", "\xe3\xa4\x9c", "\xe6\x82\x94", "\xf0\xa2\x9b\x94", "\xe6\x83\x87", "\xe6\x85\x88", "\xe6\x85\x8c",
+ "\xe6\x85\x8e", "\xe6\x85\x8c", "\xe6\x85\xba", "\xe6\x86\x8e", "\xe6\x86\xb2", "\xe6\x86\xa4", "\xe6\x86\xaf", "\xe6\x87\x9e",
+ "\xe6\x87\xb2", "\xe6\x87\xb6", "\xe6\x88\x90", "\xe6\x88\x9b", "\xe6\x89\x9d", "\xe6\x8a\xb1", "\xe6\x8b\x94", "\xe6\x8d\x90",
+ "\xf0\xa2\xac\x8c", "\xe6\x8c\xbd", "\xe6\x8b\xbc", "\xe6\x8d\xa8", "\xe6\x8e\x83", "\xe6\x8f\xa4", "\xf0\xa2\xaf\xb1", "\xe6\x90\xa2"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa3[] = {
+ "\xe6\x8f\x85", "\xe6\x8e\xa9", "\xe3\xa8\xae", "\xe6\x91\xa9", "\xe6\x91\xbe", "\xe6\x92\x9d", "\xe6\x91\xb7", "\xe3\xa9\xac",
+ "\xe6\x95\x8f", "\xe6\x95\xac", "\xf0\xa3\x80\x8a", "\xe6\x97\xa3", "\xe6\x9b\xb8", "\xe6\x99\x89", "\xe3\xac\x99", "\xe6\x9a\x91",
+ "\xe3\xac\x88", "\xe3\xab\xa4", "\xe5\x86\x92", "\xe5\x86\x95", "\xe6\x9c\x80", "\xe6\x9a\x9c", "\xe8\x82\xad", "\xe4\x8f\x99",
+ "\xe6\x9c\x97", "\xe6\x9c\x9b", "\xe6\x9c\xa1", "\xe6\x9d\x9e", "\xe6\x9d\x93", "\xf0\xa3\x8f\x83", "\xe3\xad\x89", "\xe6\x9f\xba",
+ "\xe6\x9e\x85", "\xe6\xa1\x92", "\xe6\xa2\x85", "\xf0\xa3\x91\xad", "\xe6\xa2\x8e", "\xe6\xa0\x9f", "\xe6\xa4\x94", "\xe3\xae\x9d",
+ "\xe6\xa5\x82", "\xe6\xa6\xa3", "\xe6\xa7\xaa", "\xe6\xaa\xa8", "\xf0\xa3\x9a\xa3", "\xe6\xab\x9b", "\xe3\xb0\x98", "\xe6\xac\xa1",
+ "\xf0\xa3\xa2\xa7", "\xe6\xad\x94", "\xe3\xb1\x8e", "\xe6\xad\xb2", "\xe6\xae\x9f", "\xe6\xae\xba", "\xe6\xae\xbb", "\xf0\xa3\xaa\x8d",
+ "\xf0\xa1\xb4\x8b", "\xf0\xa3\xab\xba", "\xe6\xb1\x8e", "\xf0\xa3\xb2\xbc", "\xe6\xb2\xbf", "\xe6\xb3\x8d", "\xe6\xb1\xa7", "\xe6\xb4\x96"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa4[] = {
+ "\xe6\xb4\xbe", "\xe6\xb5\xb7", "\xe6\xb5\x81", "\xe6\xb5\xa9", "\xe6\xb5\xb8", "\xe6\xb6\x85", "\xf0\xa3\xb4\x9e", "\xe6\xb4\xb4",
+ "\xe6\xb8\xaf", "\xe6\xb9\xae", "\xe3\xb4\xb3", "\xe6\xbb\x8b", "\xe6\xbb\x87", "\xf0\xa3\xbb\x91", "\xe6\xb7\xb9", "\xe6\xbd\xae",
+ "\xf0\xa3\xbd\x9e", "\xf0\xa3\xbe\x8e", "\xe6\xbf\x86", "\xe7\x80\xb9", "\xe7\x80\x9e", "\xe7\x80\x9b", "\xe3\xb6\x96", "\xe7\x81\x8a",
+ "\xe7\x81\xbd", "\xe7\x81\xb7", "\xe7\x82\xad", "\xf0\xa0\x94\xa5", "\xe7\x85\x85", "\xf0\xa4\x89\xa3", "\xe7\x86\x9c", "\xf0\xa4\x8e\xab",
+ "\xe7\x88\xa8", "\xe7\x88\xb5", "\xe7\x89\x90", "\xf0\xa4\x98\x88", "\xe7\x8a\x80", "\xe7\x8a\x95", "\xf0\xa4\x9c\xb5", "\xf0\xa4\xa0\x94",
+ "\xe7\x8d\xba", "\xe7\x8e\x8b", "\xe3\xba\xac", "\xe7\x8e\xa5", "\xe3\xba\xb8", "\xe3\xba\xb8", "\xe7\x91\x87", "\xe7\x91\x9c",
+ "\xe7\x91\xb1", "\xe7\x92\x85", "\xe7\x93\x8a", "\xe3\xbc\x9b", "\xe7\x94\xa4", "\xf0\xa4\xb0\xb6", "\xe7\x94\xbe", "\xf0\xa4\xb2\x92",
+ "\xe7\x95\xb0", "\xf0\xa2\x86\x9f", "\xe7\x98\x90", "\xf0\xa4\xbe\xa1", "\xf0\xa4\xbe\xb8", "\xf0\xa5\x81\x84", "\xe3\xbf\xbc", "\xe4\x80\x88"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa5[] = {
+ "\xe7\x9b\xb4", "\xf0\xa5\x83\xb3", "\xf0\xa5\x83\xb2", "\xf0\xa5\x84\x99", "\xf0\xa5\x84\xb3", "\xe7\x9c\x9e", "\xe7\x9c\x9f", "\xe7\x9c\x9f",
+ "\xe7\x9d\x8a", "\xe4\x80\xb9", "\xe7\x9e\x8b", "\xe4\x81\x86", "\xe4\x82\x96", "\xf0\xa5\x90\x9d", "\xe7\xa1\x8e", "\xe7\xa2\x8c",
+ "\xe7\xa3\x8c", "\xe4\x83\xa3", "\xf0\xa5\x98\xa6", "\xe7\xa5\x96", "\xf0\xa5\x9a\x9a", "\xf0\xa5\x9b\x85", "\xe7\xa6\x8f", "\xe7\xa7\xab",
+ "\xe4\x84\xaf", "\xe7\xa9\x80", "\xe7\xa9\x8a", "\xe7\xa9\x8f", "\xf0\xa5\xa5\xbc", "\xf0\xa5\xaa\xa7", "\xf0\xa5\xaa\xa7", "\xe7\xab\xae",
+ "\xe4\x88\x82", "\xf0\xa5\xae\xab", "\xe7\xaf\x86", "\xe7\xaf\x89", "\xe4\x88\xa7", "\xf0\xa5\xb2\x80", "\xe7\xb3\x92", "\xe4\x8a\xa0",
+ "\xe7\xb3\xa8", "\xe7\xb3\xa3", "\xe7\xb4\x80", "\xf0\xa5\xbe\x86", "\xe7\xb5\xa3", "\xe4\x8c\x81", "\xe7\xb7\x87", "\xe7\xb8\x82",
+ "\xe7\xb9\x85", "\xe4\x8c\xb4", "\xf0\xa6\x88\xa8", "\xf0\xa6\x89\x87", "\xe4\x8d\x99", "\xf0\xa6\x8b\x99", "\xe7\xbd\xba", "\xf0\xa6\x8c\xbe",
+ "\xe7\xbe\x95", "\xe7\xbf\xba", "\xe8\x80\x85", "\xf0\xa6\x93\x9a", "\xf0\xa6\x94\xa3", "\xe8\x81\xa0", "\xf0\xa6\x96\xa8", "\xe8\x81\xb0"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa6[] = {
+ "\xf0\xa3\x8d\x9f", "\xe4\x8f\x95", "\xe8\x82\xb2", "\xe8\x84\x83", "\xe4\x90\x8b", "\xe8\x84\xbe", "\xe5\xaa\xb5", "\xf0\xa6\x9e\xa7",
+ "\xf0\xa6\x9e\xb5", "\xf0\xa3\x8e\x93", "\xf0\xa3\x8e\x9c", "\xe8\x88\x81", "\xe8\x88\x84", "\xe8\xbe\x9e", "\xe4\x91\xab", "\xe8\x8a\x91",
+ "\xe8\x8a\x8b", "\xe8\x8a\x9d", "\xe5\x8a\xb3", "\xe8\x8a\xb1", "\xe8\x8a\xb3", "\xe8\x8a\xbd", "\xe8\x8b\xa6", "\xf0\xa6\xac\xbc",
+ "\xe8\x8b\xa5", "\xe8\x8c\x9d", "\xe8\x8d\xa3", "\xe8\x8e\xad", "\xe8\x8c\xa3", "\xe8\x8e\xbd", "\xe8\x8f\xa7", "\xe8\x91\x97",
+ "\xe8\x8d\x93", "\xe8\x8f\x8a", "\xe8\x8f\x8c", "\xe8\x8f\x9c", "\xf0\xa6\xb0\xb6", "\xf0\xa6\xb5\xab", "\xf0\xa6\xb3\x95", "\xe4\x94\xab",
+ "\xe8\x93\xb1", "\xe8\x93\xb3", "\xe8\x94\x96", "\xf0\xa7\x8f\x8a", "\xe8\x95\xa4", "\xf0\xa6\xbc\xac", "\xe4\x95\x9d", "\xe4\x95\xa1",
+ "\xf0\xa6\xbe\xb1", "\xf0\xa7\x83\x92", "\xe4\x95\xab", "\xe8\x99\x90", "\xe8\x99\x9c", "\xe8\x99\xa7", "\xe8\x99\xa9", "\xe8\x9a\xa9",
+ "\xe8\x9a\x88", "\xe8\x9c\x8e", "\xe8\x9b\xa2", "\xe8\x9d\xb9", "\xe8\x9c\xa8", "\xe8\x9d\xab", "\xe8\x9e\x86", "\xe4\x97\x97"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa7[] = {
+ "\xe8\x9f\xa1", "\xe8\xa0\x81", "\xe4\x97\xb9", "\xe8\xa1\xa0", "\xe8\xa1\xa3", "\xf0\xa7\x99\xa7", "\xe8\xa3\x97", "\xe8\xa3\x9e",
+ "\xe4\x98\xb5", "\xe8\xa3\xba", "\xe3\x92\xbb", "\xf0\xa7\xa2\xae", "\xf0\xa7\xa5\xa6", "\xe4\x9a\xbe", "\xe4\x9b\x87", "\xe8\xaa\xa0",
+ "\xe8\xab\xad", "\xe8\xae\x8a", "\xe8\xb1\x95", "\xf0\xa7\xb2\xa8", "\xe8\xb2\xab", "\xe8\xb3\x81", "\xe8\xb4\x9b", "\xe8\xb5\xb7",
+ "\xf0\xa7\xbc\xaf", "\xf0\xa0\xa0\x84", "\xe8\xb7\x8b", "\xe8\xb6\xbc", "\xe8\xb7\xb0", "\xf0\xa0\xa3\x9e", "\xe8\xbb\x94", "\xe8\xbc\xb8",
+ "\xf0\xa8\x97\x92", "\xf0\xa8\x97\xad", "\xe9\x82\x94", "\xe9\x83\xb1", "\xe9\x84\x91", "\xf0\xa8\x9c\xae", "\xe9\x84\x9b", "\xe9\x88\xb8",
+ "\xe9\x8b\x97", "\xe9\x8b\x98", "\xe9\x89\xbc", "\xe9\x8f\xb9", "\xe9\x90\x95", "\xf0\xa8\xaf\xba", "\xe9\x96\x8b", "\xe4\xa6\x95",
+ "\xe9\x96\xb7", "\xf0\xa8\xb5\xb7", "\xe4\xa7\xa6", "\xe9\x9b\x83", "\xe5\xb6\xb2", "\xe9\x9c\xa3", "\xf0\xa9\x85\x85", "\xf0\xa9\x88\x9a",
+ "\xe4\xa9\xae", "\xe4\xa9\xb6", "\xe9\x9f\xa0", "\xf0\xa9\x90\x8a", "\xe4\xaa\xb2", "\xf0\xa9\x92\x96", "\xe9\xa0\x8b", "\xe9\xa0\x8b"
+};
+
+static const char *grn_nfkc50_decompose_table_f0afa8[] = {
+ "\xe9\xa0\xa9", "\xf0\xa9\x96\xb6", "\xe9\xa3\xa2", "\xe4\xac\xb3", "\xe9\xa4\xa9", "\xe9\xa6\xa7", "\xe9\xa7\x82", "\xe9\xa7\xbe",
+ "\xe4\xaf\x8e", "\xf0\xa9\xac\xb0", "\xe9\xac\x92", "\xe9\xb1\x80", "\xe9\xb3\xbd", "\xe4\xb3\x8e", "\xe4\xb3\xad", "\xe9\xb5\xa7",
+ "\xf0\xaa\x83\x8e", "\xe4\xb3\xb8", "\xf0\xaa\x84\x85", "\xf0\xaa\x88\x8e", "\xf0\xaa\x8a\x91", "\xe9\xba\xbb", "\xe4\xb5\x96", "\xe9\xbb\xb9",
+ "\xe9\xbb\xbe", "\xe9\xbc\x85", "\xe9\xbc\x8f", "\xe9\xbc\x96", "\xe9\xbc\xbb", "\xf0\xaa\x98\x80"
+};
+
+const char *
+grn_nfkc50_decompose(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x41 &&
+ utf8[0] <= 0x5a) {
+ return grn_nfkc50_decompose_table_[utf8[0] - 0x41];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc2 :
+ if (utf8[1] >= 0xa0 &&
+ utf8[1] <= 0xbe) {
+ return grn_nfkc50_decompose_table_c2[utf8[1] - 0xa0];
+ }
+ break;
+ case 0xc3 :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0x9d) {
+ return grn_nfkc50_decompose_table_c3[utf8[1] - 0x80];
+ }
+ break;
+ case 0xc4 :
+ return grn_nfkc50_decompose_table_c4[utf8[1] - 0x80];
+ case 0xc5 :
+ return grn_nfkc50_decompose_table_c5[utf8[1] - 0x80];
+ case 0xc6 :
+ if (utf8[1] >= 0xa0 &&
+ utf8[1] <= 0xaf) {
+ return grn_nfkc50_decompose_table_c6[utf8[1] - 0xa0];
+ }
+ break;
+ case 0xc7 :
+ if (utf8[1] >= 0x84 &&
+ utf8[1] <= 0xba) {
+ return grn_nfkc50_decompose_table_c7[utf8[1] - 0x84];
+ }
+ break;
+ case 0xc8 :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xb2) {
+ return grn_nfkc50_decompose_table_c8[utf8[1] - 0x80];
+ }
+ break;
+ case 0xca :
+ if (utf8[1] >= 0xb0 &&
+ utf8[1] <= 0xb8) {
+ return grn_nfkc50_decompose_table_ca[utf8[1] - 0xb0];
+ }
+ break;
+ case 0xcb :
+ if (utf8[1] >= 0x98 &&
+ utf8[1] <= 0xa4) {
+ return grn_nfkc50_decompose_table_cb[utf8[1] - 0x98];
+ }
+ break;
+ case 0xcd :
+ if (utf8[1] >= 0x80 &&
+ utf8[1] <= 0xbe) {
+ return grn_nfkc50_decompose_table_cd[utf8[1] - 0x80];
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x84 &&
+ utf8[1] <= 0x87) {
+ return grn_nfkc50_decompose_table_ce[utf8[1] - 0x84];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x90 &&
+ utf8[1] <= 0xb9) {
+ return grn_nfkc50_decompose_table_cf[utf8[1] - 0x90];
+ }
+ break;
+ case 0xd6 :
+ if (utf8[1] == 0x87) {
+ return "\xd5\xa5\xd6\x82";
+ }
+ break;
+ case 0xd9 :
+ if (utf8[1] >= 0xb5 &&
+ utf8[1] <= 0xb8) {
+ return grn_nfkc50_decompose_table_d9[utf8[1] - 0xb5];
+ }
+ break;
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0x9f) {
+ return grn_nfkc50_decompose_table_e0a5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x9c &&
+ utf8[2] <= 0x9f) {
+ return grn_nfkc50_decompose_table_e0a7[utf8[2] - 0x9c];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0xb3 &&
+ utf8[2] <= 0xb6) {
+ return grn_nfkc50_decompose_table_e0a8[utf8[2] - 0xb3];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x99 &&
+ utf8[2] <= 0x9e) {
+ return grn_nfkc50_decompose_table_e0a9[utf8[2] - 0x99];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x9c &&
+ utf8[2] <= 0x9d) {
+ return grn_nfkc50_decompose_table_e0ad[utf8[2] - 0x9c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] == 0xb3) {
+ return "\xe0\xb9\x8d\xe0\xb8\xb2";
+ }
+ break;
+ case 0xba :
+ if (utf8[2] == 0xb3) {
+ return "\xe0\xbb\x8d\xe0\xba\xb2";
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x9c &&
+ utf8[2] <= 0x9d) {
+ return grn_nfkc50_decompose_table_e0bb[utf8[2] - 0x9c];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] == 0x8c) {
+ return "\xe0\xbc\x8b";
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x83 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_decompose_table_e0bd[utf8[2] - 0x83];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_decompose_table_e0be[utf8[2] - 0x81];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x83 :
+ if (utf8[2] == 0xbc) {
+ return "\xe1\x83\x9c";
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0xac &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_e1b4[utf8[2] - 0xac];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_decompose_table_e1b5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x9b &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_e1b6[utf8[2] - 0x9b];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e1b8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e1b9[utf8[2] - 0x80];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e1ba[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_decompose_table_e1bb[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0xb1 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_decompose_table_e1bd[utf8[2] - 0xb1];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0xbb &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_e1be[utf8[2] - 0xbb];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e1bf[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe2 :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e280[utf8[2] - 0x80];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x87 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_e281[utf8[2] - 0x87];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_decompose_table_e282[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ return grn_nfkc50_decompose_table_e284[utf8[2] - 0x80];
+ case 0x85 :
+ return grn_nfkc50_decompose_table_e285[utf8[2] - 0x80];
+ case 0x88 :
+ if (utf8[2] >= 0xac &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_decompose_table_e288[utf8[2] - 0xac];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0xa9 &&
+ utf8[2] <= 0xaa) {
+ return grn_nfkc50_decompose_table_e28c[utf8[2] - 0xa9];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0xa0 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_e291[utf8[2] - 0xa0];
+ }
+ break;
+ case 0x92 :
+ return grn_nfkc50_decompose_table_e292[utf8[2] - 0x80];
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xaa) {
+ return grn_nfkc50_decompose_table_e293[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] == 0x8c) {
+ return "\xe2\x88\xab\xe2\x88\xab\xe2\x88\xab\xe2\x88\xab";
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0xb4 &&
+ utf8[2] <= 0xb6) {
+ return grn_nfkc50_decompose_table_e2a9[utf8[2] - 0xb4];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] == 0x9c) {
+ return "\xe2\xab\x9d\xcc\xb8";
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] == 0xaf) {
+ return "\xe2\xb5\xa1";
+ }
+ break;
+ case 0xba :
+ if (utf8[2] == 0x9f) {
+ return "\xe6\xaf\x8d";
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] == 0xb3) {
+ return "\xe9\xbe\x9f";
+ }
+ break;
+ case 0xbc :
+ return grn_nfkc50_decompose_table_e2bc[utf8[2] - 0x80];
+ case 0xbd :
+ return grn_nfkc50_decompose_table_e2bd[utf8[2] - 0x80];
+ case 0xbe :
+ return grn_nfkc50_decompose_table_e2be[utf8[2] - 0x80];
+ case 0xbf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x95) {
+ return grn_nfkc50_decompose_table_e2bf[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe3 :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xba) {
+ return grn_nfkc50_decompose_table_e380[utf8[2] - 0x80];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x9b &&
+ utf8[2] <= 0x9f) {
+ return grn_nfkc50_decompose_table_e382[utf8[2] - 0x9b];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] == 0xbf) {
+ return "\xe3\x82\xb3\xe3\x83\x88";
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0xb1 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_e384[utf8[2] - 0xb1];
+ }
+ break;
+ case 0x85 :
+ return grn_nfkc50_decompose_table_e385[utf8[2] - 0x80];
+ case 0x86 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x9f) {
+ return grn_nfkc50_decompose_table_e386[utf8[2] - 0x80];
+ }
+ break;
+ case 0x88 :
+ return grn_nfkc50_decompose_table_e388[utf8[2] - 0x80];
+ case 0x89 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e389[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8a :
+ return grn_nfkc50_decompose_table_e38a[utf8[2] - 0x80];
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_e38b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ return grn_nfkc50_decompose_table_e38c[utf8[2] - 0x80];
+ case 0x8d :
+ return grn_nfkc50_decompose_table_e38d[utf8[2] - 0x80];
+ case 0x8e :
+ return grn_nfkc50_decompose_table_e38e[utf8[2] - 0x80];
+ case 0x8f :
+ return grn_nfkc50_decompose_table_e38f[utf8[2] - 0x80];
+ default :
+ break;
+ }
+ break;
+ case 0xef :
+ switch (utf8[1]) {
+ case 0xa4 :
+ return grn_nfkc50_decompose_table_efa4[utf8[2] - 0x80];
+ case 0xa5 :
+ return grn_nfkc50_decompose_table_efa5[utf8[2] - 0x80];
+ case 0xa6 :
+ return grn_nfkc50_decompose_table_efa6[utf8[2] - 0x80];
+ case 0xa7 :
+ return grn_nfkc50_decompose_table_efa7[utf8[2] - 0x80];
+ case 0xa8 :
+ return grn_nfkc50_decompose_table_efa8[utf8[2] - 0x80];
+ case 0xa9 :
+ return grn_nfkc50_decompose_table_efa9[utf8[2] - 0x80];
+ case 0xaa :
+ return grn_nfkc50_decompose_table_efaa[utf8[2] - 0x80];
+ case 0xab :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x99) {
+ return grn_nfkc50_decompose_table_efab[utf8[2] - 0x80];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_efac[utf8[2] - 0x80];
+ }
+ break;
+ case 0xad :
+ return grn_nfkc50_decompose_table_efad[utf8[2] - 0x80];
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb1) {
+ return grn_nfkc50_decompose_table_efae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x93 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_efaf[utf8[2] - 0x93];
+ }
+ break;
+ case 0xb0 :
+ return grn_nfkc50_decompose_table_efb0[utf8[2] - 0x80];
+ case 0xb1 :
+ return grn_nfkc50_decompose_table_efb1[utf8[2] - 0x80];
+ case 0xb2 :
+ return grn_nfkc50_decompose_table_efb2[utf8[2] - 0x80];
+ case 0xb3 :
+ return grn_nfkc50_decompose_table_efb3[utf8[2] - 0x80];
+ case 0xb4 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_decompose_table_efb4[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_efb5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ return grn_nfkc50_decompose_table_efb6[utf8[2] - 0x80];
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_decompose_table_efb7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_efb8[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb9 :
+ return grn_nfkc50_decompose_table_efb9[utf8[2] - 0x80];
+ case 0xba :
+ return grn_nfkc50_decompose_table_efba[utf8[2] - 0x80];
+ case 0xbb :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_decompose_table_efbb[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_decompose_table_efbc[utf8[2] - 0x81];
+ }
+ break;
+ case 0xbd :
+ return grn_nfkc50_decompose_table_efbd[utf8[2] - 0x80];
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xbe) {
+ return grn_nfkc50_decompose_table_efbe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x82 &&
+ utf8[2] <= 0xae) {
+ return grn_nfkc50_decompose_table_efbf[utf8[2] - 0x82];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xf0 :
+ switch (utf8[1]) {
+ case 0x9d :
+ switch (utf8[2]) {
+ case 0x85 :
+ if (utf8[3] >= 0x9e &&
+ utf8[3] <= 0xa4) {
+ return grn_nfkc50_decompose_table_f09d85[utf8[3] - 0x9e];
+ }
+ break;
+ case 0x86 :
+ if (utf8[3] >= 0xbb &&
+ utf8[3] <= 0xbf) {
+ return grn_nfkc50_decompose_table_f09d86[utf8[3] - 0xbb];
+ }
+ break;
+ case 0x87 :
+ if (utf8[3] == 0x80) {
+ return "\xf0\x9d\x86\xba\xf0\x9d\x85\xa5\xf0\x9d\x85\xaf";
+ }
+ break;
+ case 0x90 :
+ return grn_nfkc50_decompose_table_f09d90[utf8[3] - 0x80];
+ case 0x91 :
+ return grn_nfkc50_decompose_table_f09d91[utf8[3] - 0x80];
+ case 0x92 :
+ return grn_nfkc50_decompose_table_f09d92[utf8[3] - 0x80];
+ case 0x93 :
+ return grn_nfkc50_decompose_table_f09d93[utf8[3] - 0x80];
+ case 0x94 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0xbe) {
+ return grn_nfkc50_decompose_table_f09d94[utf8[3] - 0x80];
+ }
+ break;
+ case 0x95 :
+ return grn_nfkc50_decompose_table_f09d95[utf8[3] - 0x80];
+ case 0x96 :
+ return grn_nfkc50_decompose_table_f09d96[utf8[3] - 0x80];
+ case 0x97 :
+ return grn_nfkc50_decompose_table_f09d97[utf8[3] - 0x80];
+ case 0x98 :
+ return grn_nfkc50_decompose_table_f09d98[utf8[3] - 0x80];
+ case 0x99 :
+ return grn_nfkc50_decompose_table_f09d99[utf8[3] - 0x80];
+ case 0x9a :
+ return grn_nfkc50_decompose_table_f09d9a[utf8[3] - 0x80];
+ case 0x9b :
+ return grn_nfkc50_decompose_table_f09d9b[utf8[3] - 0x80];
+ case 0x9c :
+ return grn_nfkc50_decompose_table_f09d9c[utf8[3] - 0x80];
+ case 0x9d :
+ return grn_nfkc50_decompose_table_f09d9d[utf8[3] - 0x80];
+ case 0x9e :
+ return grn_nfkc50_decompose_table_f09d9e[utf8[3] - 0x80];
+ case 0x9f :
+ return grn_nfkc50_decompose_table_f09d9f[utf8[3] - 0x80];
+ default :
+ break;
+ }
+ break;
+ case 0xaf :
+ switch (utf8[2]) {
+ case 0xa0 :
+ return grn_nfkc50_decompose_table_f0afa0[utf8[3] - 0x80];
+ case 0xa1 :
+ return grn_nfkc50_decompose_table_f0afa1[utf8[3] - 0x80];
+ case 0xa2 :
+ return grn_nfkc50_decompose_table_f0afa2[utf8[3] - 0x80];
+ case 0xa3 :
+ return grn_nfkc50_decompose_table_f0afa3[utf8[3] - 0x80];
+ case 0xa4 :
+ return grn_nfkc50_decompose_table_f0afa4[utf8[3] - 0x80];
+ case 0xa5 :
+ return grn_nfkc50_decompose_table_f0afa5[utf8[3] - 0x80];
+ case 0xa6 :
+ return grn_nfkc50_decompose_table_f0afa6[utf8[3] - 0x80];
+ case 0xa7 :
+ return grn_nfkc50_decompose_table_f0afa7[utf8[3] - 0x80];
+ case 0xa8 :
+ if (utf8[3] >= 0x80 &&
+ utf8[3] <= 0x9d) {
+ return grn_nfkc50_decompose_table_f0afa8[utf8[3] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_[] = {
+ "\xc3\xa0", NULL, NULL, NULL, "\xc3\xa8", NULL, NULL, NULL,
+ "\xc3\xac", NULL, NULL, NULL, NULL, "\xc7\xb9", "\xc3\xb2", NULL,
+ NULL, NULL, NULL, NULL, "\xc3\xb9", NULL, "\xe1\xba\x81", NULL,
+ "\xe1\xbb\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_c3[] = {
+ "\xe1\xba\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbb\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xe1\xbb\x93", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xc7\x9c"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_c4[] = {
+ "\xe1\xba\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xb8\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_c6[] = {
+ "\xe1\xbb\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe1\xbb\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_ce[] = {
+ "\xe1\xbe\xba", NULL, NULL, NULL, "\xe1\xbf\x88", NULL, "\xe1\xbf\x8a", NULL,
+ "\xe1\xbf\x9a", NULL, NULL, NULL, NULL, NULL, "\xe1\xbf\xb8", NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xbf\xaa", NULL, NULL, NULL,
+ "\xe1\xbf\xba", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xb0", NULL, NULL, NULL, "\xe1\xbd\xb2", NULL, "\xe1\xbd\xb4", NULL,
+ "\xe1\xbd\xb6", NULL, NULL, NULL, NULL, NULL, "\xe1\xbd\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_cf[] = {
+ "\xe1\xbd\xba", NULL, NULL, NULL, "\xe1\xbd\xbc", "\xe1\xbf\x92", "\xe1\xbf\xa2"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_d0[] = {
+ "\xd0\x80", NULL, NULL, "\xd0\x8d", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd1\x90", NULL, NULL, "\xd1\x9d"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_e1bc[] = {
+ "\xe1\xbc\x82", "\xe1\xbc\x83", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x8a", "\xe1\xbc\x8b", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x92", "\xe1\xbc\x93", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x9a", "\xe1\xbc\x9b", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xa2", "\xe1\xbc\xa3", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xaa", "\xe1\xbc\xab", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xb2", "\xe1\xbc\xb3", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xba", "\xe1\xbc\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc80_table_e1bd[] = {
+ "\xe1\xbd\x82", "\xe1\xbd\x83", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\x8a", "\xe1\xbd\x8b", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\x92", "\xe1\xbd\x93", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe1\xbd\x9b", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xa2", "\xe1\xbd\xa3", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xaa", "\xe1\xbd\xab"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc80(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x79) {
+ return grn_nfkc50_compose_prefix_cc80_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] >= 0xa2 &&
+ utf8[1] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_cc80_table_c3[utf8[1] - 0xa2];
+ }
+ break;
+ case 0xc4 :
+ if (utf8[1] >= 0x83 &&
+ utf8[1] <= 0x93) {
+ return grn_nfkc50_compose_prefix_cc80_table_c4[utf8[1] - 0x83];
+ }
+ break;
+ case 0xc5 :
+ if (utf8[1] == 0x8d) {
+ return "\xe1\xb9\x91";
+ }
+ break;
+ case 0xc6 :
+ if (utf8[1] >= 0xa1 &&
+ utf8[1] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_cc80_table_c6[utf8[1] - 0xa1];
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xbf) {
+ return grn_nfkc50_compose_prefix_cc80_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x85 &&
+ utf8[1] <= 0x8b) {
+ return grn_nfkc50_compose_prefix_cc80_table_cf[utf8[1] - 0x85];
+ }
+ break;
+ case 0xd0 :
+ if (utf8[1] >= 0x95 &&
+ utf8[1] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_cc80_table_d0[utf8[1] - 0x95];
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cc80_table_e1bc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa9) {
+ return grn_nfkc50_compose_prefix_cc80_table_e1bd[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_[] = {
+ "\xc3\xa1", NULL, "\xc4\x87", NULL, "\xc3\xa9", NULL, "\xc7\xb5", NULL,
+ "\xc3\xad", NULL, "\xe1\xb8\xb1", "\xc4\xba", "\xe1\xb8\xbf", "\xc5\x84", "\xc3\xb3", "\xe1\xb9\x95",
+ NULL, "\xc5\x95", "\xc5\x9b", NULL, "\xc3\xba", NULL, "\xe1\xba\x83", NULL,
+ "\xc3\xbd", "\xc5\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_c3[] = {
+ "\xc7\xbc", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xc7\xbe", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xba\xa5", NULL, NULL, "\xc7\xbb",
+ "\xc7\xbd", "\xe1\xb8\x89", NULL, NULL, "\xe1\xba\xbf", NULL, NULL, NULL,
+ NULL, "\xe1\xb8\xaf", NULL, NULL, NULL, NULL, "\xe1\xbb\x91", "\xe1\xb9\x8d",
+ NULL, NULL, "\xc7\xbf", NULL, NULL, NULL, "\xc7\x98"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_c4[] = {
+ "\xe1\xba\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xb8\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_c5[] = {
+ "\xe1\xb9\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xb9\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_c6[] = {
+ "\xe1\xbb\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe1\xbb\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_ce[] = {
+ "\xce\x86", NULL, NULL, NULL, "\xce\x88", NULL, "\xce\x89", NULL,
+ "\xce\x8a", NULL, NULL, NULL, NULL, NULL, "\xce\x8c", NULL,
+ NULL, NULL, NULL, NULL, "\xce\x8e", NULL, NULL, NULL,
+ "\xce\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xce\xac", NULL, NULL, NULL, "\xce\xad", NULL, "\xce\xae", NULL,
+ "\xce\xaf", NULL, NULL, NULL, NULL, NULL, "\xcf\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_cf[] = {
+ "\xcf\x8d", NULL, NULL, NULL, "\xcf\x8e", "\xce\x90", "\xce\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_d0[] = {
+ "\xd0\x83", NULL, NULL, NULL, NULL, NULL, NULL, "\xd0\x8c",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd1\x93", NULL, NULL, NULL, NULL, NULL, NULL, "\xd1\x9c"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_e1bc[] = {
+ "\xe1\xbc\x84", "\xe1\xbc\x85", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x8c", "\xe1\xbc\x8d", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x94", "\xe1\xbc\x95", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x9c", "\xe1\xbc\x9d", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xa4", "\xe1\xbc\xa5", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xac", "\xe1\xbc\xad", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xb4", "\xe1\xbc\xb5", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xbc", "\xe1\xbc\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc81_table_e1bd[] = {
+ "\xe1\xbd\x84", "\xe1\xbd\x85", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\x8c", "\xe1\xbd\x8d", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\x94", "\xe1\xbd\x95", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe1\xbd\x9d", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xa4", "\xe1\xbd\xa5", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xac", "\xe1\xbd\xad"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc81(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x7a) {
+ return grn_nfkc50_compose_prefix_cc81_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] >= 0x86 &&
+ utf8[1] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_cc81_table_c3[utf8[1] - 0x86];
+ }
+ break;
+ case 0xc4 :
+ if (utf8[1] >= 0x83 &&
+ utf8[1] <= 0x93) {
+ return grn_nfkc50_compose_prefix_cc81_table_c4[utf8[1] - 0x83];
+ }
+ break;
+ case 0xc5 :
+ if (utf8[1] >= 0x8d &&
+ utf8[1] <= 0xa9) {
+ return grn_nfkc50_compose_prefix_cc81_table_c5[utf8[1] - 0x8d];
+ }
+ break;
+ case 0xc6 :
+ if (utf8[1] >= 0xa1 &&
+ utf8[1] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_cc81_table_c6[utf8[1] - 0xa1];
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xbf) {
+ return grn_nfkc50_compose_prefix_cc81_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x85 &&
+ utf8[1] <= 0x8b) {
+ return grn_nfkc50_compose_prefix_cc81_table_cf[utf8[1] - 0x85];
+ }
+ break;
+ case 0xd0 :
+ if (utf8[1] >= 0x93 &&
+ utf8[1] <= 0xba) {
+ return grn_nfkc50_compose_prefix_cc81_table_d0[utf8[1] - 0x93];
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cc81_table_e1bc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xa9) {
+ return grn_nfkc50_compose_prefix_cc81_table_e1bd[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc82_table_[] = {
+ "\xc3\xa2", NULL, "\xc4\x89", NULL, "\xc3\xaa", NULL, "\xc4\x9d", "\xc4\xa5",
+ "\xc3\xae", "\xc4\xb5", NULL, NULL, NULL, NULL, "\xc3\xb4", NULL,
+ NULL, NULL, "\xc5\x9d", NULL, "\xc3\xbb", NULL, "\xc5\xb5", NULL,
+ "\xc5\xb7", "\xe1\xba\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc82_table_e1ba[] = {
+ "\xe1\xba\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbb\x87"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc82(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x7a) {
+ return grn_nfkc50_compose_prefix_cc82_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xba :
+ if (utf8[2] >= 0xa1 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cc82_table_e1ba[utf8[2] - 0xa1];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] == 0x8d) {
+ return "\xe1\xbb\x99";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc83_table_[] = {
+ "\xc3\xa3", NULL, NULL, NULL, "\xe1\xba\xbd", NULL, NULL, NULL,
+ "\xc4\xa9", NULL, NULL, NULL, NULL, "\xc3\xb1", "\xc3\xb5", NULL,
+ NULL, NULL, NULL, NULL, "\xc5\xa9", "\xe1\xb9\xbd", NULL, NULL,
+ "\xe1\xbb\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc83_table_c3[] = {
+ "\xe1\xba\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbb\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xe1\xbb\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc83_table_c6[] = {
+ "\xe1\xbb\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe1\xbb\xaf"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc83(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x79) {
+ return grn_nfkc50_compose_prefix_cc83_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] >= 0xa2 &&
+ utf8[1] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_cc83_table_c3[utf8[1] - 0xa2];
+ }
+ break;
+ case 0xc4 :
+ if (utf8[1] == 0x83) {
+ return "\xe1\xba\xb5";
+ }
+ break;
+ case 0xc6 :
+ if (utf8[1] >= 0xa1 &&
+ utf8[1] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_cc83_table_c6[utf8[1] - 0xa1];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc88_table_[] = {
+ "\xc3\xa4", NULL, NULL, NULL, "\xc3\xab", NULL, NULL, "\xe1\xb8\xa7",
+ "\xc3\xaf", NULL, NULL, NULL, NULL, NULL, "\xc3\xb6", NULL,
+ NULL, NULL, NULL, "\xe1\xba\x97", "\xc3\xbc", NULL, "\xe1\xba\x85", "\xe1\xba\x8d",
+ "\xc3\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc88_table_ce[] = {
+ "\xce\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xce\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xcf\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc88_table_d0[] = {
+ "\xd0\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xd3\x92", NULL, NULL, NULL, NULL, "\xd0\x81",
+ "\xd3\x9c", "\xd3\x9e", "\xd3\xa4", NULL, NULL, NULL, NULL, NULL,
+ "\xd3\xa6", NULL, NULL, NULL, NULL, "\xd3\xb0", NULL, NULL,
+ NULL, "\xd3\xb4", NULL, NULL, NULL, "\xd3\xb8", NULL, "\xd3\xac",
+ NULL, NULL, "\xd3\x93", NULL, NULL, NULL, NULL, "\xd1\x91",
+ "\xd3\x9d", "\xd3\x9f", "\xd3\xa5", NULL, NULL, NULL, NULL, NULL,
+ "\xd3\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc88_table_d1[] = {
+ "\xd3\xb1", NULL, NULL, NULL, "\xd3\xb5", NULL, NULL, NULL,
+ "\xd3\xb9", NULL, "\xd3\xad", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\xd1\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc88_table_d3[] = {
+ "\xd3\x9a", "\xd3\x9b", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd3\xaa", "\xd3\xab"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc88(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x79) {
+ return grn_nfkc50_compose_prefix_cc88_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] == 0xb5) {
+ return "\xe1\xb9\x8f";
+ }
+ break;
+ case 0xc5 :
+ if (utf8[1] == 0xab) {
+ return "\xe1\xb9\xbb";
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x99 &&
+ utf8[1] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cc88_table_ce[utf8[1] - 0x99];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] == 0x85) {
+ return "\xcf\x8b";
+ }
+ break;
+ case 0xd0 :
+ if (utf8[1] >= 0x86 &&
+ utf8[1] <= 0xbe) {
+ return grn_nfkc50_compose_prefix_cc88_table_d0[utf8[1] - 0x86];
+ }
+ break;
+ case 0xd1 :
+ if (utf8[1] >= 0x83 &&
+ utf8[1] <= 0x96) {
+ return grn_nfkc50_compose_prefix_cc88_table_d1[utf8[1] - 0x83];
+ }
+ break;
+ case 0xd3 :
+ if (utf8[1] >= 0x98 &&
+ utf8[1] <= 0xa9) {
+ return grn_nfkc50_compose_prefix_cc88_table_d3[utf8[1] - 0x98];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc8a_table_[] = {
+ "\xc3\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xc5\xaf", NULL, "\xe1\xba\x98", NULL,
+ "\xe1\xba\x99"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc8a(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x79) {
+ return grn_nfkc50_compose_prefix_cc8a_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cca7_table_[] = {
+ "\xc3\xa7", "\xe1\xb8\x91", "\xc8\xa9", NULL, "\xc4\xa3", "\xe1\xb8\xa9", NULL, NULL,
+ "\xc4\xb7", "\xc4\xbc", NULL, "\xc5\x86", NULL, NULL, NULL, "\xc5\x97",
+ "\xc5\x9f", "\xc5\xa3"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cca7(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x63 &&
+ utf8[0] <= 0x74) {
+ return grn_nfkc50_compose_prefix_cca7_table_[utf8[0] - 0x63];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc84_table_[] = {
+ "\xc4\x81", NULL, NULL, NULL, "\xc4\x93", NULL, "\xe1\xb8\xa1", NULL,
+ "\xc4\xab", NULL, NULL, NULL, NULL, NULL, "\xc5\x8d", NULL,
+ NULL, NULL, NULL, NULL, "\xc5\xab", NULL, NULL, NULL,
+ "\xc8\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc84_table_c3[] = {
+ "\xc7\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xc7\x9f", NULL,
+ "\xc7\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xc8\xad",
+ "\xc8\xab", NULL, NULL, NULL, NULL, NULL, "\xc7\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc84_table_c8[] = {
+ "\xc7\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xc8\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc84_table_ce[] = {
+ "\xe1\xbe\xb9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbf\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xbf\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbe\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbf\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc84_table_d0[] = {
+ "\xd3\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\xd3\xae", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd3\xa3"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc84(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x79) {
+ return grn_nfkc50_compose_prefix_cc84_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] >= 0x86 &&
+ utf8[1] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_cc84_table_c3[utf8[1] - 0x86];
+ }
+ break;
+ case 0xc7 :
+ if (utf8[1] == 0xab) {
+ return "\xc7\xad";
+ }
+ break;
+ case 0xc8 :
+ if (utf8[1] >= 0xa7 &&
+ utf8[1] <= 0xaf) {
+ return grn_nfkc50_compose_prefix_cc84_table_c8[utf8[1] - 0xa7];
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cc84_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] == 0x85) {
+ return "\xe1\xbf\xa1";
+ }
+ break;
+ case 0xd0 :
+ if (utf8[1] >= 0x98 &&
+ utf8[1] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_cc84_table_d0[utf8[1] - 0x98];
+ }
+ break;
+ case 0xd1 :
+ if (utf8[1] == 0x83) {
+ return "\xd3\xaf";
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xb8 :
+ if (utf8[2] == 0xb7) {
+ return "\xe1\xb8\xb9";
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] == 0x9b) {
+ return "\xe1\xb9\x9d";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc86_table_[] = {
+ "\xc4\x83", NULL, NULL, NULL, "\xc4\x95", NULL, "\xc4\x9f", NULL,
+ "\xc4\xad", NULL, NULL, NULL, NULL, NULL, "\xc5\x8f", NULL,
+ NULL, NULL, NULL, NULL, "\xc5\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc86_table_ce[] = {
+ "\xe1\xbe\xb8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbf\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xbf\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbe\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbf\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc86_table_d0[] = {
+ "\xd3\x90", NULL, NULL, NULL, NULL, "\xd3\x96", "\xd3\x81", NULL,
+ "\xd0\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, "\xd0\x8e", NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xd3\x91", NULL, NULL, NULL, NULL, "\xd3\x97", "\xd3\x82", NULL,
+ "\xd0\xb9"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc86(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_cc86_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc8 :
+ if (utf8[1] == 0xa9) {
+ return "\xe1\xb8\x9d";
+ }
+ break;
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cc86_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] == 0x85) {
+ return "\xe1\xbf\xa0";
+ }
+ break;
+ case 0xd0 :
+ if (utf8[1] >= 0x90 &&
+ utf8[1] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_cc86_table_d0[utf8[1] - 0x90];
+ }
+ break;
+ case 0xd1 :
+ if (utf8[1] == 0x83) {
+ return "\xd1\x9e";
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xba :
+ if (utf8[2] == 0xa1) {
+ return "\xe1\xba\xb7";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cca8_table_[] = {
+ "\xc4\x85", NULL, NULL, NULL, "\xc4\x99", NULL, NULL, NULL,
+ "\xc4\xaf", NULL, NULL, NULL, NULL, NULL, "\xc7\xab", NULL,
+ NULL, NULL, NULL, NULL, "\xc5\xb3"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cca8(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_cca8_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc87_table_[] = {
+ "\xc8\xa7", "\xe1\xb8\x83", "\xc4\x8b", "\xe1\xb8\x8b", "\xc4\x97", "\xe1\xb8\x9f", "\xc4\xa1", "\xe1\xb8\xa3",
+ NULL, NULL, NULL, NULL, "\xe1\xb9\x81", "\xe1\xb9\x85", "\xc8\xaf", "\xe1\xb9\x97",
+ NULL, "\xe1\xb9\x99", "\xe1\xb9\xa1", "\xe1\xb9\xab", NULL, NULL, "\xe1\xba\x87", "\xe1\xba\x8b",
+ "\xe1\xba\x8f", "\xc5\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc87_table_c5[] = {
+ "\xe1\xb9\xa5", NULL, NULL, NULL, NULL, NULL, "\xe1\xb9\xa7"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc87(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x7a) {
+ return grn_nfkc50_compose_prefix_cc87_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc5 :
+ if (utf8[1] >= 0x9b &&
+ utf8[1] <= 0xa1) {
+ return grn_nfkc50_compose_prefix_cc87_table_c5[utf8[1] - 0x9b];
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xb9 :
+ if (utf8[2] == 0xa3) {
+ return "\xe1\xb9\xa9";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc8c_table_[] = {
+ "\xc7\x8e", NULL, "\xc4\x8d", "\xc4\x8f", "\xc4\x9b", NULL, "\xc7\xa7", "\xc8\x9f",
+ "\xc7\x90", "\xc7\xb0", "\xc7\xa9", "\xc4\xbe", NULL, "\xc5\x88", "\xc7\x92", NULL,
+ NULL, "\xc5\x99", "\xc5\xa1", "\xc5\xa5", "\xc7\x94", NULL, NULL, NULL,
+ NULL, "\xc5\xbe"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc8c(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x7a) {
+ return grn_nfkc50_compose_prefix_cc8c_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] == 0xbc) {
+ return "\xc7\x9a";
+ }
+ break;
+ case 0xc6 :
+ if (utf8[1] == 0xb7) {
+ return "\xc7\xae";
+ }
+ break;
+ case 0xca :
+ if (utf8[1] == 0x92) {
+ return "\xc7\xaf";
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc8b_table_[] = {
+ "\xc5\x91", NULL, NULL, NULL, NULL, NULL, "\xc5\xb1"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc8b(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x6f &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_cc8b_table_[utf8[0] - 0x6f];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xd0 :
+ if (utf8[1] == 0xa3) {
+ return "\xd3\xb2";
+ }
+ break;
+ case 0xd1 :
+ if (utf8[1] == 0x83) {
+ return "\xd3\xb3";
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc9b_table_[] = {
+ "\xc6\xa1", NULL, NULL, NULL, NULL, NULL, "\xc6\xb0"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc9b(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x6f &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_cc9b_table_[utf8[0] - 0x6f];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc8f_table_[] = {
+ "\xc8\x81", NULL, NULL, NULL, "\xc8\x85", NULL, NULL, NULL,
+ "\xc8\x89", NULL, NULL, NULL, NULL, NULL, "\xc8\x8d", NULL,
+ NULL, "\xc8\x91", NULL, NULL, "\xc8\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc8f_table_d1[] = {
+ "\xd1\xb6", "\xd1\xb7"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc8f(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_cc8f_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xd1 :
+ if (utf8[1] >= 0xb4 &&
+ utf8[1] <= 0xb5) {
+ return grn_nfkc50_compose_prefix_cc8f_table_d1[utf8[1] - 0xb4];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc91_table_[] = {
+ "\xc8\x83", NULL, NULL, NULL, "\xc8\x87", NULL, NULL, NULL,
+ "\xc8\x8b", NULL, NULL, NULL, NULL, NULL, "\xc8\x8f", NULL,
+ NULL, "\xc8\x93", NULL, NULL, "\xc8\x97"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc91(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_cc91_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cca6_table_[] = {
+ "\xc8\x99", "\xc8\x9b"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cca6(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x73 &&
+ utf8[0] <= 0x74) {
+ return grn_nfkc50_compose_prefix_cca6_table_[utf8[0] - 0x73];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_d993(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xd8 :
+ if (utf8[1] == 0xa7) {
+ return "\xd8\xa2";
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_d994_table_d9[] = {
+ "\xd8\xa4", NULL, "\xd8\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_d994_table_db[] = {
+ "\xdb\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xdb\x93", NULL, NULL, "\xdb\x80"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_d994(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xd8 :
+ if (utf8[1] == 0xa7) {
+ return "\xd8\xa3";
+ }
+ break;
+ case 0xd9 :
+ if (utf8[1] >= 0x88 &&
+ utf8[1] <= 0x8a) {
+ return grn_nfkc50_compose_prefix_d994_table_d9[utf8[1] - 0x88];
+ }
+ break;
+ case 0xdb :
+ if (utf8[1] >= 0x81 &&
+ utf8[1] <= 0x95) {
+ return grn_nfkc50_compose_prefix_d994_table_db[utf8[1] - 0x81];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_d995(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xd8 :
+ if (utf8[1] == 0xa7) {
+ return "\xd8\xa5";
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e0a4bc_table_e0a4[] = {
+ "\xe0\xa4\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe0\xa4\xb1", NULL, NULL, "\xe0\xa4\xb4"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0a4bc(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xa4 :
+ if (utf8[2] >= 0xa8 &&
+ utf8[2] <= 0xb3) {
+ return grn_nfkc50_compose_prefix_e0a4bc_table_e0a4[utf8[2] - 0xa8];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0a6be(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xa7 :
+ if (utf8[2] == 0x87) {
+ return "\xe0\xa7\x8b";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0a797(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xa7 :
+ if (utf8[2] == 0x87) {
+ return "\xe0\xa7\x8c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0ad96(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xad :
+ if (utf8[2] == 0x87) {
+ return "\xe0\xad\x88";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0acbe(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xad :
+ if (utf8[2] == 0x87) {
+ return "\xe0\xad\x8b";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0ad97(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xad :
+ if (utf8[2] == 0x87) {
+ return "\xe0\xad\x8c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0af97(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xae :
+ if (utf8[2] == 0x92) {
+ return "\xe0\xae\x94";
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] == 0x86) {
+ return "\xe0\xaf\x8c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e0aebe_table_e0af[] = {
+ "\xe0\xaf\x8a", "\xe0\xaf\x8b"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0aebe(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xaf :
+ if (utf8[2] >= 0x86 &&
+ utf8[2] <= 0x87) {
+ return grn_nfkc50_compose_prefix_e0aebe_table_e0af[utf8[2] - 0x86];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b196(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb1 :
+ if (utf8[2] == 0x86) {
+ return "\xe0\xb1\x88";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e0b395_table_e0b3[] = {
+ "\xe0\xb3\x87", NULL, NULL, NULL, "\xe0\xb3\x8b"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b395(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb2 :
+ if (utf8[2] == 0xbf) {
+ return "\xe0\xb3\x80";
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x86 &&
+ utf8[2] <= 0x8a) {
+ return grn_nfkc50_compose_prefix_e0b395_table_e0b3[utf8[2] - 0x86];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b396(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb3 :
+ if (utf8[2] == 0x86) {
+ return "\xe0\xb3\x88";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b382(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb3 :
+ if (utf8[2] == 0x86) {
+ return "\xe0\xb3\x8a";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e0b4be_table_e0b5[] = {
+ "\xe0\xb5\x8a", "\xe0\xb5\x8b"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b4be(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb5 :
+ if (utf8[2] >= 0x86 &&
+ utf8[2] <= 0x87) {
+ return grn_nfkc50_compose_prefix_e0b4be_table_e0b5[utf8[2] - 0x86];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b597(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb5 :
+ if (utf8[2] == 0x86) {
+ return "\xe0\xb5\x8c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e0b78a_table_e0b7[] = {
+ "\xe0\xb7\x9a", NULL, NULL, "\xe0\xb7\x9d"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b78a(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb7 :
+ if (utf8[2] >= 0x99 &&
+ utf8[2] <= 0x9c) {
+ return grn_nfkc50_compose_prefix_e0b78a_table_e0b7[utf8[2] - 0x99];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b78f(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb7 :
+ if (utf8[2] == 0x99) {
+ return "\xe0\xb7\x9c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e0b79f(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe0 :
+ switch (utf8[1]) {
+ case 0xb7 :
+ if (utf8[2] == 0x99) {
+ return "\xe0\xb7\x9e";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_e180ae(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] == 0xa5) {
+ return "\xe1\x80\xa6";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e1acb5_table_e1ac[] = {
+ "\xe1\xac\x86", NULL, "\xe1\xac\x88", NULL, "\xe1\xac\x8a", NULL, "\xe1\xac\x8c", NULL,
+ "\xe1\xac\x8e", NULL, NULL, NULL, "\xe1\xac\x92", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, "\xe1\xac\xbb", NULL, "\xe1\xac\xbd",
+ NULL, "\xe1\xad\x80", "\xe1\xad\x81"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e1acb5(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xac :
+ if (utf8[2] >= 0x85 &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_compose_prefix_e1acb5_table_e1ac[utf8[2] - 0x85];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] == 0x82) {
+ return "\xe1\xad\x83";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_cca5(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] == 0x61) {
+ return "\xe1\xb8\x81";
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cca3_table_[] = {
+ "\xe1\xba\xa1", "\xe1\xb8\x85", NULL, "\xe1\xb8\x8d", "\xe1\xba\xb9", NULL, NULL, "\xe1\xb8\xa5",
+ "\xe1\xbb\x8b", NULL, "\xe1\xb8\xb3", "\xe1\xb8\xb7", "\xe1\xb9\x83", "\xe1\xb9\x87", "\xe1\xbb\x8d", NULL,
+ NULL, "\xe1\xb9\x9b", "\xe1\xb9\xa3", "\xe1\xb9\xad", "\xe1\xbb\xa5", "\xe1\xb9\xbf", "\xe1\xba\x89", NULL,
+ "\xe1\xbb\xb5", "\xe1\xba\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_cca3_table_c6[] = {
+ "\xe1\xbb\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe1\xbb\xb1"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cca3(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x7a) {
+ return grn_nfkc50_compose_prefix_cca3_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc6 :
+ if (utf8[1] >= 0xa1 &&
+ utf8[1] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_cca3_table_c6[utf8[1] - 0xa1];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_ccb1_table_[] = {
+ "\xe1\xb8\x87", NULL, "\xe1\xb8\x8f", NULL, NULL, NULL, "\xe1\xba\x96", NULL,
+ NULL, "\xe1\xb8\xb5", "\xe1\xb8\xbb", NULL, "\xe1\xb9\x89", NULL, NULL, NULL,
+ "\xe1\xb9\x9f", NULL, "\xe1\xb9\xaf", NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xba\x95"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_ccb1(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x62 &&
+ utf8[0] <= 0x7a) {
+ return grn_nfkc50_compose_prefix_ccb1_table_[utf8[0] - 0x62];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_ccad_table_[] = {
+ "\xe1\xb8\x93", "\xe1\xb8\x99", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xb8\xbd", NULL, "\xe1\xb9\x8b", NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xb9\xb1", "\xe1\xb9\xb7"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_ccad(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x64 &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_ccad_table_[utf8[0] - 0x64];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_ccb0_table_[] = {
+ "\xe1\xb8\x9b", NULL, NULL, NULL, "\xe1\xb8\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xb9\xb5"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_ccb0(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x65 &&
+ utf8[0] <= 0x75) {
+ return grn_nfkc50_compose_prefix_ccb0_table_[utf8[0] - 0x65];
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_ccae(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] == 0x68) {
+ return "\xe1\xb8\xab";
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static inline const char *
+grn_nfkc50_compose_prefix_cca4(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] == 0x75) {
+ return "\xe1\xb9\xb3";
+ } else {
+ return NULL;
+ }
+ } else {
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc89_table_[] = {
+ "\xe1\xba\xa3", NULL, NULL, NULL, "\xe1\xba\xbb", NULL, NULL, NULL,
+ "\xe1\xbb\x89", NULL, NULL, NULL, NULL, NULL, "\xe1\xbb\x8f", NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xbb\xa7", NULL, NULL, NULL,
+ "\xe1\xbb\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc89_table_c3[] = {
+ "\xe1\xba\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbb\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, "\xe1\xbb\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc89_table_c6[] = {
+ "\xe1\xbb\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe1\xbb\xad"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc89(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x61 &&
+ utf8[0] <= 0x79) {
+ return grn_nfkc50_compose_prefix_cc89_table_[utf8[0] - 0x61];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xc3 :
+ if (utf8[1] >= 0xa2 &&
+ utf8[1] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_cc89_table_c3[utf8[1] - 0xa2];
+ }
+ break;
+ case 0xc4 :
+ if (utf8[1] == 0x83) {
+ return "\xe1\xba\xb3";
+ }
+ break;
+ case 0xc6 :
+ if (utf8[1] >= 0xa1 &&
+ utf8[1] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_cc89_table_c6[utf8[1] - 0xa1];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc93_table_ce[] = {
+ "\xe1\xbc\x88", NULL, NULL, NULL, "\xe1\xbc\x98", NULL, "\xe1\xbc\xa8", NULL,
+ "\xe1\xbc\xb8", NULL, NULL, NULL, NULL, NULL, "\xe1\xbd\x88", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x80", NULL, NULL, NULL, "\xe1\xbc\x90", NULL, "\xe1\xbc\xa0", NULL,
+ "\xe1\xbc\xb0", NULL, NULL, NULL, NULL, NULL, "\xe1\xbd\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc93_table_cf[] = {
+ "\xe1\xbf\xa4", NULL, NULL, NULL, "\xe1\xbd\x90", NULL, NULL, NULL,
+ "\xe1\xbd\xa0"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc93(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xbf) {
+ return grn_nfkc50_compose_prefix_cc93_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x81 &&
+ utf8[1] <= 0x89) {
+ return grn_nfkc50_compose_prefix_cc93_table_cf[utf8[1] - 0x81];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cc94_table_ce[] = {
+ "\xe1\xbc\x89", NULL, NULL, NULL, "\xe1\xbc\x99", NULL, "\xe1\xbc\xa9", NULL,
+ "\xe1\xbc\xb9", NULL, NULL, NULL, NULL, NULL, "\xe1\xbd\x89", NULL,
+ "\xe1\xbf\xac", NULL, NULL, NULL, "\xe1\xbd\x99", NULL, NULL, NULL,
+ "\xe1\xbd\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x81", NULL, NULL, NULL, "\xe1\xbc\x91", NULL, "\xe1\xbc\xa1", NULL,
+ "\xe1\xbc\xb1", NULL, NULL, NULL, NULL, NULL, "\xe1\xbd\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_cc94_table_cf[] = {
+ "\xe1\xbf\xa5", NULL, NULL, NULL, "\xe1\xbd\x91", NULL, NULL, NULL,
+ "\xe1\xbd\xa1"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cc94(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xbf) {
+ return grn_nfkc50_compose_prefix_cc94_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x81 &&
+ utf8[1] <= 0x89) {
+ return grn_nfkc50_compose_prefix_cc94_table_cf[utf8[1] - 0x81];
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cd82_table_ce[] = {
+ "\xe1\xbe\xb6", NULL, NULL, NULL, NULL, NULL, "\xe1\xbf\x86", NULL,
+ "\xe1\xbf\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd82_table_cf[] = {
+ "\xe1\xbf\xa6", NULL, NULL, NULL, "\xe1\xbf\xb6", "\xe1\xbf\x97", "\xe1\xbf\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd82_table_e1bc[] = {
+ "\xe1\xbc\x86", "\xe1\xbc\x87", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\x8e", "\xe1\xbc\x8f", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xa6", "\xe1\xbc\xa7", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xae", "\xe1\xbc\xaf", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xb6", "\xe1\xbc\xb7", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbc\xbe", "\xe1\xbc\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd82_table_e1bd[] = {
+ "\xe1\xbd\x96", "\xe1\xbd\x97", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe1\xbd\x9f", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xa6", "\xe1\xbd\xa7", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbd\xae", "\xe1\xbd\xaf"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cd82(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xce :
+ if (utf8[1] >= 0xb1 &&
+ utf8[1] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cd82_table_ce[utf8[1] - 0xb1];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x85 &&
+ utf8[1] <= 0x8b) {
+ return grn_nfkc50_compose_prefix_cd82_table_cf[utf8[1] - 0x85];
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb9) {
+ return grn_nfkc50_compose_prefix_cd82_table_e1bc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xa9) {
+ return grn_nfkc50_compose_prefix_cd82_table_e1bd[utf8[2] - 0x90];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_cd85_table_ce[] = {
+ "\xe1\xbe\xbc", NULL, NULL, NULL, NULL, NULL, "\xe1\xbf\x8c", NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbf\xbc", NULL, NULL, "\xe1\xbe\xb4", NULL, "\xe1\xbf\x84", NULL, NULL,
+ "\xe1\xbe\xb3", NULL, NULL, NULL, NULL, NULL, "\xe1\xbf\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd85_table_cf[] = {
+ "\xe1\xbf\xb3", NULL, NULL, NULL, NULL, "\xe1\xbf\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd85_table_e1bc[] = {
+ "\xe1\xbe\x80", "\xe1\xbe\x81", "\xe1\xbe\x82", "\xe1\xbe\x83", "\xe1\xbe\x84", "\xe1\xbe\x85", "\xe1\xbe\x86", "\xe1\xbe\x87",
+ "\xe1\xbe\x88", "\xe1\xbe\x89", "\xe1\xbe\x8a", "\xe1\xbe\x8b", "\xe1\xbe\x8c", "\xe1\xbe\x8d", "\xe1\xbe\x8e", "\xe1\xbe\x8f",
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbe\x90", "\xe1\xbe\x91", "\xe1\xbe\x92", "\xe1\xbe\x93", "\xe1\xbe\x94", "\xe1\xbe\x95", "\xe1\xbe\x96", "\xe1\xbe\x97",
+ "\xe1\xbe\x98", "\xe1\xbe\x99", "\xe1\xbe\x9a", "\xe1\xbe\x9b", "\xe1\xbe\x9c", "\xe1\xbe\x9d", "\xe1\xbe\x9e", "\xe1\xbe\x9f"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd85_table_e1bd[] = {
+ "\xe1\xbe\xa0", "\xe1\xbe\xa1", "\xe1\xbe\xa2", "\xe1\xbe\xa3", "\xe1\xbe\xa4", "\xe1\xbe\xa5", "\xe1\xbe\xa6", "\xe1\xbe\xa7",
+ "\xe1\xbe\xa8", "\xe1\xbe\xa9", "\xe1\xbe\xaa", "\xe1\xbe\xab", "\xe1\xbe\xac", "\xe1\xbe\xad", "\xe1\xbe\xae", "\xe1\xbe\xaf",
+ "\xe1\xbe\xb2", NULL, NULL, NULL, "\xe1\xbf\x82", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe1\xbf\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_cd85_table_e1bf[] = {
+ "\xe1\xbf\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe1\xbf\xb7"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_cd85(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xce :
+ if (utf8[1] >= 0x91 &&
+ utf8[1] <= 0xb7) {
+ return grn_nfkc50_compose_prefix_cd85_table_ce[utf8[1] - 0x91];
+ }
+ break;
+ case 0xcf :
+ if (utf8[1] >= 0x89 &&
+ utf8[1] <= 0x8e) {
+ return grn_nfkc50_compose_prefix_cd85_table_cf[utf8[1] - 0x89];
+ }
+ break;
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xaf) {
+ return grn_nfkc50_compose_prefix_cd85_table_e1bc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0xa0 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_cd85_table_e1bd[utf8[2] - 0xa0];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] == 0xb6) {
+ return "\xe1\xbe\xb7";
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x86 &&
+ utf8[2] <= 0xb6) {
+ return grn_nfkc50_compose_prefix_cd85_table_e1bf[utf8[2] - 0x86];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_ccb8_table_[] = {
+ "\xe2\x89\xae", "\xe2\x89\xa0", "\xe2\x89\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_ccb8_table_e286[] = {
+ "\xe2\x86\x9a", NULL, "\xe2\x86\x9b", NULL, "\xe2\x86\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_ccb8_table_e287[] = {
+ "\xe2\x87\x8d", NULL, "\xe2\x87\x8f", NULL, "\xe2\x87\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_ccb8_table_e288[] = {
+ "\xe2\x88\x84", NULL, NULL, NULL, NULL, "\xe2\x88\x89", NULL, NULL,
+ "\xe2\x88\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe2\x88\xa4", NULL, "\xe2\x88\xa6", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe2\x89\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_ccb8_table_e289[] = {
+ "\xe2\x89\x84", NULL, "\xe2\x89\x87", NULL, NULL, "\xe2\x89\x89", NULL, NULL,
+ NULL, NULL, "\xe2\x89\xad", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xe2\x89\xa2", NULL,
+ NULL, "\xe2\x89\xb0", "\xe2\x89\xb1", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe2\x89\xb4",
+ "\xe2\x89\xb5", NULL, NULL, "\xe2\x89\xb8", "\xe2\x89\xb9", NULL, NULL, "\xe2\x8a\x80",
+ "\xe2\x8a\x81", "\xe2\x8b\xa0", "\xe2\x8b\xa1"
+};
+
+static const char *grn_nfkc50_compose_prefix_ccb8_table_e28a[] = {
+ "\xe2\x8a\x84", "\xe2\x8a\x85", NULL, NULL, "\xe2\x8a\x88", "\xe2\x8a\x89", NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\xe2\x8b\xa2",
+ "\xe2\x8b\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe2\x8a\xac", NULL, NULL, NULL, NULL, NULL, "\xe2\x8a\xad", "\xe2\x8a\xae",
+ NULL, "\xe2\x8a\xaf", NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xe2\x8b\xaa", "\xe2\x8b\xab", "\xe2\x8b\xac", "\xe2\x8b\xad"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_ccb8(const unsigned char *utf8)
+{
+ if (utf8[0] < 0x80) {
+ if (utf8[0] >= 0x3c &&
+ utf8[0] <= 0x3e) {
+ return grn_nfkc50_compose_prefix_ccb8_table_[utf8[0] - 0x3c];
+ } else {
+ return NULL;
+ }
+ } else {
+ switch (utf8[0]) {
+ case 0xe2 :
+ switch (utf8[1]) {
+ case 0x86 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0x94) {
+ return grn_nfkc50_compose_prefix_ccb8_table_e286[utf8[2] - 0x90];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0x94) {
+ return grn_nfkc50_compose_prefix_ccb8_table_e287[utf8[2] - 0x90];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x83 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_ccb8_table_e288[utf8[2] - 0x83];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x83 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_compose_prefix_ccb8_table_e289[utf8[2] - 0x83];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x82 &&
+ utf8[2] <= 0xb5) {
+ return grn_nfkc50_compose_prefix_ccb8_table_e28a[utf8[2] - 0x82];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e38299_table_e381[] = {
+ "\xe3\x82\x94", NULL, NULL, NULL, NULL, "\xe3\x81\x8c", NULL, "\xe3\x81\x8e",
+ NULL, "\xe3\x81\x90", NULL, "\xe3\x81\x92", NULL, "\xe3\x81\x94", NULL, "\xe3\x81\x96",
+ NULL, "\xe3\x81\x98", NULL, "\xe3\x81\x9a", NULL, "\xe3\x81\x9c", NULL, "\xe3\x81\x9e",
+ NULL, "\xe3\x81\xa0", NULL, "\xe3\x81\xa2", NULL, NULL, "\xe3\x81\xa5", NULL,
+ "\xe3\x81\xa7", NULL, "\xe3\x81\xa9", NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe3\x81\xb0", NULL, NULL, "\xe3\x81\xb3", NULL, NULL, "\xe3\x81\xb6",
+ NULL, NULL, "\xe3\x81\xb9", NULL, NULL, "\xe3\x81\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e38299_table_e382[] = {
+ "\xe3\x82\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, "\xe3\x83\xb4", NULL, NULL, NULL, NULL, "\xe3\x82\xac", NULL,
+ "\xe3\x82\xae", NULL, "\xe3\x82\xb0", NULL, "\xe3\x82\xb2", NULL, "\xe3\x82\xb4", NULL,
+ "\xe3\x82\xb6", NULL, "\xe3\x82\xb8", NULL, "\xe3\x82\xba", NULL, "\xe3\x82\xbc", NULL,
+ "\xe3\x82\xbe", NULL, "\xe3\x83\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e38299_table_e383[] = {
+ "\xe3\x83\x82", NULL, NULL, "\xe3\x83\x85", NULL, "\xe3\x83\x87", NULL, "\xe3\x83\x89",
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xe3\x83\x90", NULL,
+ NULL, "\xe3\x83\x93", NULL, NULL, "\xe3\x83\x96", NULL, NULL, "\xe3\x83\x99",
+ NULL, NULL, "\xe3\x83\x9c", NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, "\xe3\x83\xb7", "\xe3\x83\xb8",
+ "\xe3\x83\xb9", "\xe3\x83\xba", NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xe3\x83\xbe"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e38299(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe3 :
+ switch (utf8[1]) {
+ case 0x81 :
+ if (utf8[2] >= 0x86 &&
+ utf8[2] <= 0xbb) {
+ return grn_nfkc50_compose_prefix_e38299_table_e381[utf8[2] - 0x86];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x9d &&
+ utf8[2] <= 0xbf) {
+ return grn_nfkc50_compose_prefix_e38299_table_e382[utf8[2] - 0x9d];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x81 &&
+ utf8[2] <= 0xbd) {
+ return grn_nfkc50_compose_prefix_e38299_table_e383[utf8[2] - 0x81];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e3829a_table_e381[] = {
+ "\xe3\x81\xb1", NULL, NULL, "\xe3\x81\xb4", NULL, NULL, "\xe3\x81\xb7", NULL,
+ NULL, "\xe3\x81\xba", NULL, NULL, "\xe3\x81\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e3829a_table_e383[] = {
+ "\xe3\x83\x91", NULL, NULL, "\xe3\x83\x94", NULL, NULL, "\xe3\x83\x97", NULL,
+ NULL, "\xe3\x83\x9a", NULL, NULL, "\xe3\x83\x9d"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e3829a(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe3 :
+ switch (utf8[1]) {
+ case 0x81 :
+ if (utf8[2] >= 0xaf &&
+ utf8[2] <= 0xbb) {
+ return grn_nfkc50_compose_prefix_e3829a_table_e381[utf8[2] - 0xaf];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x8f &&
+ utf8[2] <= 0x9b) {
+ return grn_nfkc50_compose_prefix_e3829a_table_e383[utf8[2] - 0x8f];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a1_table_e184[] = {
+ "\xea\xb0\x80", "\xea\xb9\x8c", "\xeb\x82\x98", "\xeb\x8b\xa4", "\xeb\x94\xb0", "\xeb\x9d\xbc", "\xeb\xa7\x88", "\xeb\xb0\x94",
+ "\xeb\xb9\xa0", "\xec\x82\xac", "\xec\x8b\xb8", "\xec\x95\x84", "\xec\x9e\x90", "\xec\xa7\x9c", "\xec\xb0\xa8", "\xec\xb9\xb4",
+ "\xed\x83\x80", "\xed\x8c\x8c", "\xed\x95\x98"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a1(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a1_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab0[] = {
+ "\xea\xb0\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab1[] = {
+ "\xea\xb1\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab2[] = {
+ "\xea\xb2\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab3[] = {
+ "\xea\xb3\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb3\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab4[] = {
+ "\xea\xb4\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab5[] = {
+ "\xea\xb5\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab6[] = {
+ "\xea\xb6\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab7[] = {
+ "\xea\xb7\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab8[] = {
+ "\xea\xb8\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eab9[] = {
+ "\xea\xb9\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eaba[] = {
+ "\xea\xba\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xba\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eabb[] = {
+ "\xea\xbb\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eabc[] = {
+ "\xea\xbc\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eabd[] = {
+ "\xea\xbd\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eabe[] = {
+ "\xea\xbe\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eabf[] = {
+ "\xea\xbf\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb80[] = {
+ "\xeb\x80\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb81[] = {
+ "\xeb\x81\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x81\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb82[] = {
+ "\xeb\x82\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb83[] = {
+ "\xeb\x83\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb84[] = {
+ "\xeb\x84\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb85[] = {
+ "\xeb\x85\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb86[] = {
+ "\xeb\x86\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb87[] = {
+ "\xeb\x87\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb88[] = {
+ "\xeb\x88\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x88\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb89[] = {
+ "\xeb\x89\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb8a[] = {
+ "\xeb\x8a\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb8b[] = {
+ "\xeb\x8b\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb8c[] = {
+ "\xeb\x8c\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb8d[] = {
+ "\xeb\x8d\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb8e[] = {
+ "\xeb\x8e\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb8f[] = {
+ "\xeb\x8f\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8f\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb90[] = {
+ "\xeb\x90\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb91[] = {
+ "\xeb\x91\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb92[] = {
+ "\xeb\x92\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb93[] = {
+ "\xeb\x93\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb94[] = {
+ "\xeb\x94\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb95[] = {
+ "\xeb\x95\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb96[] = {
+ "\xeb\x96\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x96\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb97[] = {
+ "\xeb\x97\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb98[] = {
+ "\xeb\x98\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb99[] = {
+ "\xeb\x99\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb9a[] = {
+ "\xeb\x9a\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb9b[] = {
+ "\xeb\x9b\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb9c[] = {
+ "\xeb\x9c\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb9d[] = {
+ "\xeb\x9d\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9d\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb9e[] = {
+ "\xeb\x9e\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eb9f[] = {
+ "\xeb\x9f\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba0[] = {
+ "\xeb\xa0\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba1[] = {
+ "\xeb\xa1\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba2[] = {
+ "\xeb\xa2\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba3[] = {
+ "\xeb\xa3\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba4[] = {
+ "\xeb\xa4\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa4\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba5[] = {
+ "\xeb\xa5\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba6[] = {
+ "\xeb\xa6\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba7[] = {
+ "\xeb\xa7\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba8[] = {
+ "\xeb\xa8\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eba9[] = {
+ "\xeb\xa9\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebaa[] = {
+ "\xeb\xaa\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebab[] = {
+ "\xeb\xab\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xab\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebac[] = {
+ "\xeb\xac\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebad[] = {
+ "\xeb\xad\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebae[] = {
+ "\xeb\xae\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebaf[] = {
+ "\xeb\xaf\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb0[] = {
+ "\xeb\xb0\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb1[] = {
+ "\xeb\xb1\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb2[] = {
+ "\xeb\xb2\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb2\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb3[] = {
+ "\xeb\xb3\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb4[] = {
+ "\xeb\xb4\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb5[] = {
+ "\xeb\xb5\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb6[] = {
+ "\xeb\xb6\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb7[] = {
+ "\xeb\xb7\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb8[] = {
+ "\xeb\xb8\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebb9[] = {
+ "\xeb\xb9\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb9\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebba[] = {
+ "\xeb\xba\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebbb[] = {
+ "\xeb\xbb\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebbc[] = {
+ "\xeb\xbc\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebbd[] = {
+ "\xeb\xbd\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebbe[] = {
+ "\xeb\xbe\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ebbf[] = {
+ "\xeb\xbf\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec80[] = {
+ "\xec\x80\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x80\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec81[] = {
+ "\xec\x81\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec82[] = {
+ "\xec\x82\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec83[] = {
+ "\xec\x83\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec84[] = {
+ "\xec\x84\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec85[] = {
+ "\xec\x85\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec86[] = {
+ "\xec\x86\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec87[] = {
+ "\xec\x87\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x87\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec88[] = {
+ "\xec\x88\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec89[] = {
+ "\xec\x89\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec8a[] = {
+ "\xec\x8a\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec8b[] = {
+ "\xec\x8b\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec8c[] = {
+ "\xec\x8c\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec8d[] = {
+ "\xec\x8d\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec8e[] = {
+ "\xec\x8e\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8e\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec8f[] = {
+ "\xec\x8f\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec90[] = {
+ "\xec\x90\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec91[] = {
+ "\xec\x91\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec92[] = {
+ "\xec\x92\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec93[] = {
+ "\xec\x93\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec94[] = {
+ "\xec\x94\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec95[] = {
+ "\xec\x95\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x95\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec96[] = {
+ "\xec\x96\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec97[] = {
+ "\xec\x97\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec98[] = {
+ "\xec\x98\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec99[] = {
+ "\xec\x99\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec9a[] = {
+ "\xec\x9a\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec9b[] = {
+ "\xec\x9b\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec9c[] = {
+ "\xec\x9c\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9c\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec9d[] = {
+ "\xec\x9d\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec9e[] = {
+ "\xec\x9e\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ec9f[] = {
+ "\xec\x9f\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca0[] = {
+ "\xec\xa0\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca1[] = {
+ "\xec\xa1\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca2[] = {
+ "\xec\xa2\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca3[] = {
+ "\xec\xa3\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa3\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca4[] = {
+ "\xec\xa4\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca5[] = {
+ "\xec\xa5\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca6[] = {
+ "\xec\xa6\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca7[] = {
+ "\xec\xa7\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca8[] = {
+ "\xec\xa8\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_eca9[] = {
+ "\xec\xa9\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecaa[] = {
+ "\xec\xaa\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaa\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecab[] = {
+ "\xec\xab\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecac[] = {
+ "\xec\xac\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecad[] = {
+ "\xec\xad\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecae[] = {
+ "\xec\xae\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecaf[] = {
+ "\xec\xaf\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb0[] = {
+ "\xec\xb0\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb1[] = {
+ "\xec\xb1\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb1\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb2[] = {
+ "\xec\xb2\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb3[] = {
+ "\xec\xb3\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb4[] = {
+ "\xec\xb4\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb5[] = {
+ "\xec\xb5\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb6[] = {
+ "\xec\xb6\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb7[] = {
+ "\xec\xb7\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb8[] = {
+ "\xec\xb8\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb8\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecb9[] = {
+ "\xec\xb9\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecba[] = {
+ "\xec\xba\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecbb[] = {
+ "\xec\xbb\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecbc[] = {
+ "\xec\xbc\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecbd[] = {
+ "\xec\xbd\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecbe[] = {
+ "\xec\xbe\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ecbf[] = {
+ "\xec\xbf\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbf\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed80[] = {
+ "\xed\x80\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed81[] = {
+ "\xed\x81\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed82[] = {
+ "\xed\x82\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed83[] = {
+ "\xed\x83\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed84[] = {
+ "\xed\x84\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed85[] = {
+ "\xed\x85\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed86[] = {
+ "\xed\x86\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x86\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed87[] = {
+ "\xed\x87\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed88[] = {
+ "\xed\x88\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed89[] = {
+ "\xed\x89\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed8a[] = {
+ "\xed\x8a\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed8b[] = {
+ "\xed\x8b\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed8c[] = {
+ "\xed\x8c\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed8d[] = {
+ "\xed\x8d\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8d\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed8e[] = {
+ "\xed\x8e\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed8f[] = {
+ "\xed\x8f\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed90[] = {
+ "\xed\x90\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed91[] = {
+ "\xed\x91\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed92[] = {
+ "\xed\x92\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed93[] = {
+ "\xed\x93\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed94[] = {
+ "\xed\x94\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x94\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed95[] = {
+ "\xed\x95\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed96[] = {
+ "\xed\x96\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed97[] = {
+ "\xed\x97\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xa5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed98[] = {
+ "\xed\x98\x81", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\x9d", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed99[] = {
+ "\xed\x99\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed9a[] = {
+ "\xed\x9a\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed9b[] = {
+ "\xed\x9b\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9b\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed9c[] = {
+ "\xed\x9c\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a8_table_ed9d[] = {
+ "\xed\x9d\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xad"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186a8(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a8_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x89";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab0[] = {
+ "\xea\xb0\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab1[] = {
+ "\xea\xb1\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab2[] = {
+ "\xea\xb2\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab3[] = {
+ "\xea\xb3\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb3\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab4[] = {
+ "\xea\xb4\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab5[] = {
+ "\xea\xb5\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab6[] = {
+ "\xea\xb6\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab7[] = {
+ "\xea\xb7\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab8[] = {
+ "\xea\xb8\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eab9[] = {
+ "\xea\xb9\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eaba[] = {
+ "\xea\xba\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xba\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eabb[] = {
+ "\xea\xbb\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eabc[] = {
+ "\xea\xbc\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eabd[] = {
+ "\xea\xbd\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eabe[] = {
+ "\xea\xbe\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eabf[] = {
+ "\xea\xbf\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb80[] = {
+ "\xeb\x80\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb81[] = {
+ "\xeb\x81\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x81\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb82[] = {
+ "\xeb\x82\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb83[] = {
+ "\xeb\x83\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb84[] = {
+ "\xeb\x84\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb85[] = {
+ "\xeb\x85\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb86[] = {
+ "\xeb\x86\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb87[] = {
+ "\xeb\x87\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb88[] = {
+ "\xeb\x88\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x88\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb89[] = {
+ "\xeb\x89\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb8a[] = {
+ "\xeb\x8a\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb8b[] = {
+ "\xeb\x8b\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb8c[] = {
+ "\xeb\x8c\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb8d[] = {
+ "\xeb\x8d\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb8e[] = {
+ "\xeb\x8e\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb8f[] = {
+ "\xeb\x8f\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8f\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb90[] = {
+ "\xeb\x90\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb91[] = {
+ "\xeb\x91\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb92[] = {
+ "\xeb\x92\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb93[] = {
+ "\xeb\x93\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb94[] = {
+ "\xeb\x94\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb95[] = {
+ "\xeb\x95\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb96[] = {
+ "\xeb\x96\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x96\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb97[] = {
+ "\xeb\x97\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb98[] = {
+ "\xeb\x98\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb99[] = {
+ "\xeb\x99\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb9a[] = {
+ "\xeb\x9a\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb9b[] = {
+ "\xeb\x9b\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb9c[] = {
+ "\xeb\x9c\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb9d[] = {
+ "\xeb\x9d\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9d\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb9e[] = {
+ "\xeb\x9e\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eb9f[] = {
+ "\xeb\x9f\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba0[] = {
+ "\xeb\xa0\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba1[] = {
+ "\xeb\xa1\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba2[] = {
+ "\xeb\xa2\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba3[] = {
+ "\xeb\xa3\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba4[] = {
+ "\xeb\xa4\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa4\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba5[] = {
+ "\xeb\xa5\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba6[] = {
+ "\xeb\xa6\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba7[] = {
+ "\xeb\xa7\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba8[] = {
+ "\xeb\xa8\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eba9[] = {
+ "\xeb\xa9\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebaa[] = {
+ "\xeb\xaa\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebab[] = {
+ "\xeb\xab\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xab\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebac[] = {
+ "\xeb\xac\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebad[] = {
+ "\xeb\xad\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebae[] = {
+ "\xeb\xae\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebaf[] = {
+ "\xeb\xaf\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb0[] = {
+ "\xeb\xb0\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb1[] = {
+ "\xeb\xb1\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb2[] = {
+ "\xeb\xb2\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb2\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb3[] = {
+ "\xeb\xb3\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb4[] = {
+ "\xeb\xb4\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb5[] = {
+ "\xeb\xb5\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb6[] = {
+ "\xeb\xb6\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb7[] = {
+ "\xeb\xb7\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb8[] = {
+ "\xeb\xb8\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebb9[] = {
+ "\xeb\xb9\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb9\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebba[] = {
+ "\xeb\xba\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebbb[] = {
+ "\xeb\xbb\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebbc[] = {
+ "\xeb\xbc\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebbd[] = {
+ "\xeb\xbd\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebbe[] = {
+ "\xeb\xbe\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ebbf[] = {
+ "\xeb\xbf\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec80[] = {
+ "\xec\x80\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x80\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec81[] = {
+ "\xec\x81\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec82[] = {
+ "\xec\x82\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec83[] = {
+ "\xec\x83\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec84[] = {
+ "\xec\x84\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec85[] = {
+ "\xec\x85\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec86[] = {
+ "\xec\x86\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec87[] = {
+ "\xec\x87\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x87\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec88[] = {
+ "\xec\x88\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec89[] = {
+ "\xec\x89\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec8a[] = {
+ "\xec\x8a\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec8b[] = {
+ "\xec\x8b\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec8c[] = {
+ "\xec\x8c\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec8d[] = {
+ "\xec\x8d\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec8e[] = {
+ "\xec\x8e\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8e\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec8f[] = {
+ "\xec\x8f\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec90[] = {
+ "\xec\x90\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec91[] = {
+ "\xec\x91\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec92[] = {
+ "\xec\x92\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec93[] = {
+ "\xec\x93\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec94[] = {
+ "\xec\x94\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec95[] = {
+ "\xec\x95\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x95\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec96[] = {
+ "\xec\x96\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec97[] = {
+ "\xec\x97\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec98[] = {
+ "\xec\x98\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec99[] = {
+ "\xec\x99\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec9a[] = {
+ "\xec\x9a\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec9b[] = {
+ "\xec\x9b\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec9c[] = {
+ "\xec\x9c\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9c\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec9d[] = {
+ "\xec\x9d\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec9e[] = {
+ "\xec\x9e\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ec9f[] = {
+ "\xec\x9f\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca0[] = {
+ "\xec\xa0\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca1[] = {
+ "\xec\xa1\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca2[] = {
+ "\xec\xa2\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca3[] = {
+ "\xec\xa3\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa3\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca4[] = {
+ "\xec\xa4\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca5[] = {
+ "\xec\xa5\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca6[] = {
+ "\xec\xa6\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca7[] = {
+ "\xec\xa7\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca8[] = {
+ "\xec\xa8\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_eca9[] = {
+ "\xec\xa9\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecaa[] = {
+ "\xec\xaa\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaa\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecab[] = {
+ "\xec\xab\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecac[] = {
+ "\xec\xac\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecad[] = {
+ "\xec\xad\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecae[] = {
+ "\xec\xae\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecaf[] = {
+ "\xec\xaf\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb0[] = {
+ "\xec\xb0\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb1[] = {
+ "\xec\xb1\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb1\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb2[] = {
+ "\xec\xb2\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb3[] = {
+ "\xec\xb3\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb4[] = {
+ "\xec\xb4\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb5[] = {
+ "\xec\xb5\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb6[] = {
+ "\xec\xb6\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb7[] = {
+ "\xec\xb7\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb8[] = {
+ "\xec\xb8\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb8\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecb9[] = {
+ "\xec\xb9\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecba[] = {
+ "\xec\xba\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecbb[] = {
+ "\xec\xbb\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecbc[] = {
+ "\xec\xbc\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecbd[] = {
+ "\xec\xbd\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecbe[] = {
+ "\xec\xbe\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ecbf[] = {
+ "\xec\xbf\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbf\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed80[] = {
+ "\xed\x80\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed81[] = {
+ "\xed\x81\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed82[] = {
+ "\xed\x82\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed83[] = {
+ "\xed\x83\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed84[] = {
+ "\xed\x84\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed85[] = {
+ "\xed\x85\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed86[] = {
+ "\xed\x86\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x86\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed87[] = {
+ "\xed\x87\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed88[] = {
+ "\xed\x88\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed89[] = {
+ "\xed\x89\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed8a[] = {
+ "\xed\x8a\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed8b[] = {
+ "\xed\x8b\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed8c[] = {
+ "\xed\x8c\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed8d[] = {
+ "\xed\x8d\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8d\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed8e[] = {
+ "\xed\x8e\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed8f[] = {
+ "\xed\x8f\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed90[] = {
+ "\xed\x90\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed91[] = {
+ "\xed\x91\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed92[] = {
+ "\xed\x92\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed93[] = {
+ "\xed\x93\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed94[] = {
+ "\xed\x94\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x94\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed95[] = {
+ "\xed\x95\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed96[] = {
+ "\xed\x96\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed97[] = {
+ "\xed\x97\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xa6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed98[] = {
+ "\xed\x98\x82", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\x9e", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed99[] = {
+ "\xed\x99\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed9a[] = {
+ "\xed\x9a\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed9b[] = {
+ "\xed\x9b\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9b\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed9c[] = {
+ "\xed\x9c\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186a9_table_ed9d[] = {
+ "\xed\x9d\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xae"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186a9(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186a9_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x8a";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab0[] = {
+ "\xea\xb0\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab1[] = {
+ "\xea\xb1\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab2[] = {
+ "\xea\xb2\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab3[] = {
+ "\xea\xb3\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb3\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab4[] = {
+ "\xea\xb4\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab5[] = {
+ "\xea\xb5\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab6[] = {
+ "\xea\xb6\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab7[] = {
+ "\xea\xb7\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab8[] = {
+ "\xea\xb8\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eab9[] = {
+ "\xea\xb9\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eaba[] = {
+ "\xea\xba\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xba\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eabb[] = {
+ "\xea\xbb\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eabc[] = {
+ "\xea\xbc\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eabd[] = {
+ "\xea\xbd\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eabe[] = {
+ "\xea\xbe\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eabf[] = {
+ "\xea\xbf\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb80[] = {
+ "\xeb\x80\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb81[] = {
+ "\xeb\x81\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x81\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb82[] = {
+ "\xeb\x82\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb83[] = {
+ "\xeb\x83\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb84[] = {
+ "\xeb\x84\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb85[] = {
+ "\xeb\x85\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb86[] = {
+ "\xeb\x86\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb87[] = {
+ "\xeb\x87\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb88[] = {
+ "\xeb\x88\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x88\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb89[] = {
+ "\xeb\x89\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb8a[] = {
+ "\xeb\x8a\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb8b[] = {
+ "\xeb\x8b\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb8c[] = {
+ "\xeb\x8c\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb8d[] = {
+ "\xeb\x8d\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb8e[] = {
+ "\xeb\x8e\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb8f[] = {
+ "\xeb\x8f\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8f\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb90[] = {
+ "\xeb\x90\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb91[] = {
+ "\xeb\x91\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb92[] = {
+ "\xeb\x92\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb93[] = {
+ "\xeb\x93\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb94[] = {
+ "\xeb\x94\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb95[] = {
+ "\xeb\x95\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb96[] = {
+ "\xeb\x96\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x96\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb97[] = {
+ "\xeb\x97\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb98[] = {
+ "\xeb\x98\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb99[] = {
+ "\xeb\x99\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb9a[] = {
+ "\xeb\x9a\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb9b[] = {
+ "\xeb\x9b\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb9c[] = {
+ "\xeb\x9c\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb9d[] = {
+ "\xeb\x9d\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9d\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb9e[] = {
+ "\xeb\x9e\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eb9f[] = {
+ "\xeb\x9f\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba0[] = {
+ "\xeb\xa0\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba1[] = {
+ "\xeb\xa1\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba2[] = {
+ "\xeb\xa2\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba3[] = {
+ "\xeb\xa3\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba4[] = {
+ "\xeb\xa4\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa4\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba5[] = {
+ "\xeb\xa5\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba6[] = {
+ "\xeb\xa6\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba7[] = {
+ "\xeb\xa7\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba8[] = {
+ "\xeb\xa8\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eba9[] = {
+ "\xeb\xa9\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebaa[] = {
+ "\xeb\xaa\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebab[] = {
+ "\xeb\xab\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xab\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebac[] = {
+ "\xeb\xac\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebad[] = {
+ "\xeb\xad\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebae[] = {
+ "\xeb\xae\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebaf[] = {
+ "\xeb\xaf\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb0[] = {
+ "\xeb\xb0\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb1[] = {
+ "\xeb\xb1\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb2[] = {
+ "\xeb\xb2\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb2\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb3[] = {
+ "\xeb\xb3\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb4[] = {
+ "\xeb\xb4\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb5[] = {
+ "\xeb\xb5\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb6[] = {
+ "\xeb\xb6\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb7[] = {
+ "\xeb\xb7\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb8[] = {
+ "\xeb\xb8\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebb9[] = {
+ "\xeb\xb9\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb9\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebba[] = {
+ "\xeb\xba\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebbb[] = {
+ "\xeb\xbb\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebbc[] = {
+ "\xeb\xbc\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebbd[] = {
+ "\xeb\xbd\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebbe[] = {
+ "\xeb\xbe\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ebbf[] = {
+ "\xeb\xbf\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec80[] = {
+ "\xec\x80\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x80\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec81[] = {
+ "\xec\x81\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec82[] = {
+ "\xec\x82\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec83[] = {
+ "\xec\x83\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec84[] = {
+ "\xec\x84\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec85[] = {
+ "\xec\x85\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec86[] = {
+ "\xec\x86\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec87[] = {
+ "\xec\x87\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x87\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec88[] = {
+ "\xec\x88\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec89[] = {
+ "\xec\x89\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec8a[] = {
+ "\xec\x8a\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec8b[] = {
+ "\xec\x8b\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec8c[] = {
+ "\xec\x8c\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec8d[] = {
+ "\xec\x8d\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec8e[] = {
+ "\xec\x8e\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8e\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec8f[] = {
+ "\xec\x8f\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec90[] = {
+ "\xec\x90\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec91[] = {
+ "\xec\x91\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec92[] = {
+ "\xec\x92\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec93[] = {
+ "\xec\x93\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec94[] = {
+ "\xec\x94\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec95[] = {
+ "\xec\x95\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x95\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec96[] = {
+ "\xec\x96\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec97[] = {
+ "\xec\x97\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec98[] = {
+ "\xec\x98\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec99[] = {
+ "\xec\x99\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec9a[] = {
+ "\xec\x9a\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec9b[] = {
+ "\xec\x9b\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec9c[] = {
+ "\xec\x9c\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9c\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec9d[] = {
+ "\xec\x9d\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec9e[] = {
+ "\xec\x9e\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ec9f[] = {
+ "\xec\x9f\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca0[] = {
+ "\xec\xa0\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca1[] = {
+ "\xec\xa1\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca2[] = {
+ "\xec\xa2\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca3[] = {
+ "\xec\xa3\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa3\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca4[] = {
+ "\xec\xa4\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca5[] = {
+ "\xec\xa5\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca6[] = {
+ "\xec\xa6\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca7[] = {
+ "\xec\xa7\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca8[] = {
+ "\xec\xa8\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_eca9[] = {
+ "\xec\xa9\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecaa[] = {
+ "\xec\xaa\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaa\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecab[] = {
+ "\xec\xab\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecac[] = {
+ "\xec\xac\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecad[] = {
+ "\xec\xad\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecae[] = {
+ "\xec\xae\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecaf[] = {
+ "\xec\xaf\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb0[] = {
+ "\xec\xb0\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb1[] = {
+ "\xec\xb1\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb1\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb2[] = {
+ "\xec\xb2\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb3[] = {
+ "\xec\xb3\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb4[] = {
+ "\xec\xb4\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb5[] = {
+ "\xec\xb5\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb6[] = {
+ "\xec\xb6\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb7[] = {
+ "\xec\xb7\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb8[] = {
+ "\xec\xb8\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb8\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecb9[] = {
+ "\xec\xb9\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecba[] = {
+ "\xec\xba\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecbb[] = {
+ "\xec\xbb\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecbc[] = {
+ "\xec\xbc\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecbd[] = {
+ "\xec\xbd\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecbe[] = {
+ "\xec\xbe\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ecbf[] = {
+ "\xec\xbf\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbf\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed80[] = {
+ "\xed\x80\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed81[] = {
+ "\xed\x81\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed82[] = {
+ "\xed\x82\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed83[] = {
+ "\xed\x83\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed84[] = {
+ "\xed\x84\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed85[] = {
+ "\xed\x85\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed86[] = {
+ "\xed\x86\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x86\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed87[] = {
+ "\xed\x87\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed88[] = {
+ "\xed\x88\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed89[] = {
+ "\xed\x89\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed8a[] = {
+ "\xed\x8a\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed8b[] = {
+ "\xed\x8b\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed8c[] = {
+ "\xed\x8c\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed8d[] = {
+ "\xed\x8d\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8d\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed8e[] = {
+ "\xed\x8e\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed8f[] = {
+ "\xed\x8f\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed90[] = {
+ "\xed\x90\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed91[] = {
+ "\xed\x91\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed92[] = {
+ "\xed\x92\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed93[] = {
+ "\xed\x93\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed94[] = {
+ "\xed\x94\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x94\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed95[] = {
+ "\xed\x95\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed96[] = {
+ "\xed\x96\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed97[] = {
+ "\xed\x97\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xa7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed98[] = {
+ "\xed\x98\x83", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\x9f", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed99[] = {
+ "\xed\x99\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed9a[] = {
+ "\xed\x9a\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed9b[] = {
+ "\xed\x9b\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9b\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed9c[] = {
+ "\xed\x9c\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186aa_table_ed9d[] = {
+ "\xed\x9d\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xaf"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186aa(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186aa_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x8b";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab0[] = {
+ "\xea\xb0\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab1[] = {
+ "\xea\xb1\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab2[] = {
+ "\xea\xb2\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab3[] = {
+ "\xea\xb3\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab4[] = {
+ "\xea\xb4\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab5[] = {
+ "\xea\xb5\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab6[] = {
+ "\xea\xb6\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab7[] = {
+ "\xea\xb7\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab8[] = {
+ "\xea\xb8\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eab9[] = {
+ "\xea\xb9\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eaba[] = {
+ "\xea\xba\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eabb[] = {
+ "\xea\xbb\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eabc[] = {
+ "\xea\xbc\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eabd[] = {
+ "\xea\xbd\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eabe[] = {
+ "\xea\xbe\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eabf[] = {
+ "\xea\xbf\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb80[] = {
+ "\xeb\x80\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb81[] = {
+ "\xeb\x81\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb82[] = {
+ "\xeb\x82\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb83[] = {
+ "\xeb\x83\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb84[] = {
+ "\xeb\x84\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb85[] = {
+ "\xeb\x85\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb86[] = {
+ "\xeb\x86\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb87[] = {
+ "\xeb\x87\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb88[] = {
+ "\xeb\x88\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb89[] = {
+ "\xeb\x89\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb8a[] = {
+ "\xeb\x8a\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb8b[] = {
+ "\xeb\x8b\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb8c[] = {
+ "\xeb\x8c\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb8d[] = {
+ "\xeb\x8d\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb8e[] = {
+ "\xeb\x8e\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb8f[] = {
+ "\xeb\x8f\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb90[] = {
+ "\xeb\x90\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb91[] = {
+ "\xeb\x91\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb92[] = {
+ "\xeb\x92\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb93[] = {
+ "\xeb\x93\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb94[] = {
+ "\xeb\x94\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb95[] = {
+ "\xeb\x95\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb96[] = {
+ "\xeb\x96\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb97[] = {
+ "\xeb\x97\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb98[] = {
+ "\xeb\x98\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb99[] = {
+ "\xeb\x99\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb9a[] = {
+ "\xeb\x9a\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb9b[] = {
+ "\xeb\x9b\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb9c[] = {
+ "\xeb\x9c\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb9d[] = {
+ "\xeb\x9d\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb9e[] = {
+ "\xeb\x9e\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eb9f[] = {
+ "\xeb\x9f\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba0[] = {
+ "\xeb\xa0\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba1[] = {
+ "\xeb\xa1\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba2[] = {
+ "\xeb\xa2\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba3[] = {
+ "\xeb\xa3\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba4[] = {
+ "\xeb\xa4\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba5[] = {
+ "\xeb\xa5\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba6[] = {
+ "\xeb\xa6\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba7[] = {
+ "\xeb\xa7\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba8[] = {
+ "\xeb\xa8\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eba9[] = {
+ "\xeb\xa9\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebaa[] = {
+ "\xeb\xaa\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebab[] = {
+ "\xeb\xab\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebac[] = {
+ "\xeb\xac\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebad[] = {
+ "\xeb\xad\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebae[] = {
+ "\xeb\xae\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebaf[] = {
+ "\xeb\xaf\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb0[] = {
+ "\xeb\xb0\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb1[] = {
+ "\xeb\xb1\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb2[] = {
+ "\xeb\xb2\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb3[] = {
+ "\xeb\xb3\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb4[] = {
+ "\xeb\xb4\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb5[] = {
+ "\xeb\xb5\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb6[] = {
+ "\xeb\xb6\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb7[] = {
+ "\xeb\xb7\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb8[] = {
+ "\xeb\xb8\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebb9[] = {
+ "\xeb\xb9\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebba[] = {
+ "\xeb\xba\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebbb[] = {
+ "\xeb\xbb\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebbc[] = {
+ "\xeb\xbc\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebbd[] = {
+ "\xeb\xbd\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebbe[] = {
+ "\xeb\xbe\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ebbf[] = {
+ "\xeb\xbf\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec80[] = {
+ "\xec\x80\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec81[] = {
+ "\xec\x81\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec82[] = {
+ "\xec\x82\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec83[] = {
+ "\xec\x83\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec84[] = {
+ "\xec\x84\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec85[] = {
+ "\xec\x85\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec86[] = {
+ "\xec\x86\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec87[] = {
+ "\xec\x87\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec88[] = {
+ "\xec\x88\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec89[] = {
+ "\xec\x89\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec8a[] = {
+ "\xec\x8a\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec8b[] = {
+ "\xec\x8b\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec8c[] = {
+ "\xec\x8c\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec8d[] = {
+ "\xec\x8d\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec8e[] = {
+ "\xec\x8e\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec8f[] = {
+ "\xec\x8f\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec90[] = {
+ "\xec\x90\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec91[] = {
+ "\xec\x91\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec92[] = {
+ "\xec\x92\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec93[] = {
+ "\xec\x93\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec94[] = {
+ "\xec\x94\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec95[] = {
+ "\xec\x95\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec96[] = {
+ "\xec\x96\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec97[] = {
+ "\xec\x97\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec98[] = {
+ "\xec\x98\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec99[] = {
+ "\xec\x99\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec9a[] = {
+ "\xec\x9a\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec9b[] = {
+ "\xec\x9b\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec9c[] = {
+ "\xec\x9c\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec9d[] = {
+ "\xec\x9d\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec9e[] = {
+ "\xec\x9e\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ec9f[] = {
+ "\xec\x9f\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca0[] = {
+ "\xec\xa0\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca1[] = {
+ "\xec\xa1\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca2[] = {
+ "\xec\xa2\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca3[] = {
+ "\xec\xa3\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca4[] = {
+ "\xec\xa4\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca5[] = {
+ "\xec\xa5\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca6[] = {
+ "\xec\xa6\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca7[] = {
+ "\xec\xa7\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca8[] = {
+ "\xec\xa8\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_eca9[] = {
+ "\xec\xa9\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecaa[] = {
+ "\xec\xaa\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecab[] = {
+ "\xec\xab\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecac[] = {
+ "\xec\xac\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecad[] = {
+ "\xec\xad\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecae[] = {
+ "\xec\xae\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecaf[] = {
+ "\xec\xaf\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb0[] = {
+ "\xec\xb0\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb1[] = {
+ "\xec\xb1\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb2[] = {
+ "\xec\xb2\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb3[] = {
+ "\xec\xb3\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb4[] = {
+ "\xec\xb4\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb5[] = {
+ "\xec\xb5\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb6[] = {
+ "\xec\xb6\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb7[] = {
+ "\xec\xb7\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb8[] = {
+ "\xec\xb8\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecb9[] = {
+ "\xec\xb9\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecba[] = {
+ "\xec\xba\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecbb[] = {
+ "\xec\xbb\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecbc[] = {
+ "\xec\xbc\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecbd[] = {
+ "\xec\xbd\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecbe[] = {
+ "\xec\xbe\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ecbf[] = {
+ "\xec\xbf\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed80[] = {
+ "\xed\x80\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed81[] = {
+ "\xed\x81\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed82[] = {
+ "\xed\x82\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed83[] = {
+ "\xed\x83\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed84[] = {
+ "\xed\x84\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed85[] = {
+ "\xed\x85\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed86[] = {
+ "\xed\x86\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed87[] = {
+ "\xed\x87\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed88[] = {
+ "\xed\x88\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed89[] = {
+ "\xed\x89\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed8a[] = {
+ "\xed\x8a\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed8b[] = {
+ "\xed\x8b\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed8c[] = {
+ "\xed\x8c\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed8d[] = {
+ "\xed\x8d\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed8e[] = {
+ "\xed\x8e\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed8f[] = {
+ "\xed\x8f\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed90[] = {
+ "\xed\x90\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed91[] = {
+ "\xed\x91\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed92[] = {
+ "\xed\x92\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed93[] = {
+ "\xed\x93\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed94[] = {
+ "\xed\x94\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed95[] = {
+ "\xed\x95\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed96[] = {
+ "\xed\x96\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed97[] = {
+ "\xed\x97\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xa8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed98[] = {
+ "\xed\x98\x84", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed99[] = {
+ "\xed\x99\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed9a[] = {
+ "\xed\x9a\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed9b[] = {
+ "\xed\x9b\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed9c[] = {
+ "\xed\x9c\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ab_table_ed9d[] = {
+ "\xed\x9d\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb0"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186ab(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ab_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x8c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab0[] = {
+ "\xea\xb0\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab1[] = {
+ "\xea\xb1\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab2[] = {
+ "\xea\xb2\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab3[] = {
+ "\xea\xb3\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab4[] = {
+ "\xea\xb4\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab5[] = {
+ "\xea\xb5\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab6[] = {
+ "\xea\xb6\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab7[] = {
+ "\xea\xb7\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab8[] = {
+ "\xea\xb8\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eab9[] = {
+ "\xea\xb9\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eaba[] = {
+ "\xea\xba\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eabb[] = {
+ "\xea\xbb\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eabc[] = {
+ "\xea\xbc\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eabd[] = {
+ "\xea\xbd\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eabe[] = {
+ "\xea\xbe\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eabf[] = {
+ "\xea\xbf\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb80[] = {
+ "\xeb\x80\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb81[] = {
+ "\xeb\x81\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb82[] = {
+ "\xeb\x82\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb83[] = {
+ "\xeb\x83\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb84[] = {
+ "\xeb\x84\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb85[] = {
+ "\xeb\x85\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb86[] = {
+ "\xeb\x86\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb87[] = {
+ "\xeb\x87\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb88[] = {
+ "\xeb\x88\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb89[] = {
+ "\xeb\x89\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb8a[] = {
+ "\xeb\x8a\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb8b[] = {
+ "\xeb\x8b\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb8c[] = {
+ "\xeb\x8c\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb8d[] = {
+ "\xeb\x8d\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb8e[] = {
+ "\xeb\x8e\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb8f[] = {
+ "\xeb\x8f\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb90[] = {
+ "\xeb\x90\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb91[] = {
+ "\xeb\x91\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb92[] = {
+ "\xeb\x92\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb93[] = {
+ "\xeb\x93\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb94[] = {
+ "\xeb\x94\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb95[] = {
+ "\xeb\x95\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb96[] = {
+ "\xeb\x96\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb97[] = {
+ "\xeb\x97\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb98[] = {
+ "\xeb\x98\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb99[] = {
+ "\xeb\x99\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb9a[] = {
+ "\xeb\x9a\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb9b[] = {
+ "\xeb\x9b\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb9c[] = {
+ "\xeb\x9c\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb9d[] = {
+ "\xeb\x9d\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb9e[] = {
+ "\xeb\x9e\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eb9f[] = {
+ "\xeb\x9f\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba0[] = {
+ "\xeb\xa0\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba1[] = {
+ "\xeb\xa1\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba2[] = {
+ "\xeb\xa2\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba3[] = {
+ "\xeb\xa3\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba4[] = {
+ "\xeb\xa4\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba5[] = {
+ "\xeb\xa5\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba6[] = {
+ "\xeb\xa6\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba7[] = {
+ "\xeb\xa7\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba8[] = {
+ "\xeb\xa8\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eba9[] = {
+ "\xeb\xa9\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebaa[] = {
+ "\xeb\xaa\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebab[] = {
+ "\xeb\xab\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebac[] = {
+ "\xeb\xac\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebad[] = {
+ "\xeb\xad\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebae[] = {
+ "\xeb\xae\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebaf[] = {
+ "\xeb\xaf\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb0[] = {
+ "\xeb\xb0\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb1[] = {
+ "\xeb\xb1\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb2[] = {
+ "\xeb\xb2\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb3[] = {
+ "\xeb\xb3\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb4[] = {
+ "\xeb\xb4\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb5[] = {
+ "\xeb\xb5\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb6[] = {
+ "\xeb\xb6\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb7[] = {
+ "\xeb\xb7\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb8[] = {
+ "\xeb\xb8\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebb9[] = {
+ "\xeb\xb9\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebba[] = {
+ "\xeb\xba\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebbb[] = {
+ "\xeb\xbb\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebbc[] = {
+ "\xeb\xbc\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebbd[] = {
+ "\xeb\xbd\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebbe[] = {
+ "\xeb\xbe\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ebbf[] = {
+ "\xeb\xbf\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec80[] = {
+ "\xec\x80\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec81[] = {
+ "\xec\x81\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec82[] = {
+ "\xec\x82\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec83[] = {
+ "\xec\x83\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec84[] = {
+ "\xec\x84\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec85[] = {
+ "\xec\x85\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec86[] = {
+ "\xec\x86\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec87[] = {
+ "\xec\x87\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec88[] = {
+ "\xec\x88\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec89[] = {
+ "\xec\x89\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec8a[] = {
+ "\xec\x8a\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec8b[] = {
+ "\xec\x8b\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec8c[] = {
+ "\xec\x8c\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec8d[] = {
+ "\xec\x8d\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec8e[] = {
+ "\xec\x8e\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec8f[] = {
+ "\xec\x8f\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec90[] = {
+ "\xec\x90\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec91[] = {
+ "\xec\x91\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec92[] = {
+ "\xec\x92\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec93[] = {
+ "\xec\x93\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec94[] = {
+ "\xec\x94\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec95[] = {
+ "\xec\x95\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec96[] = {
+ "\xec\x96\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec97[] = {
+ "\xec\x97\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec98[] = {
+ "\xec\x98\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec99[] = {
+ "\xec\x99\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec9a[] = {
+ "\xec\x9a\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec9b[] = {
+ "\xec\x9b\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec9c[] = {
+ "\xec\x9c\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec9d[] = {
+ "\xec\x9d\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec9e[] = {
+ "\xec\x9e\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ec9f[] = {
+ "\xec\x9f\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca0[] = {
+ "\xec\xa0\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca1[] = {
+ "\xec\xa1\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca2[] = {
+ "\xec\xa2\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca3[] = {
+ "\xec\xa3\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca4[] = {
+ "\xec\xa4\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca5[] = {
+ "\xec\xa5\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca6[] = {
+ "\xec\xa6\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca7[] = {
+ "\xec\xa7\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca8[] = {
+ "\xec\xa8\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_eca9[] = {
+ "\xec\xa9\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecaa[] = {
+ "\xec\xaa\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecab[] = {
+ "\xec\xab\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecac[] = {
+ "\xec\xac\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecad[] = {
+ "\xec\xad\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecae[] = {
+ "\xec\xae\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecaf[] = {
+ "\xec\xaf\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb0[] = {
+ "\xec\xb0\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb1[] = {
+ "\xec\xb1\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb2[] = {
+ "\xec\xb2\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb3[] = {
+ "\xec\xb3\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb4[] = {
+ "\xec\xb4\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb5[] = {
+ "\xec\xb5\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb6[] = {
+ "\xec\xb6\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb7[] = {
+ "\xec\xb7\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb8[] = {
+ "\xec\xb8\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecb9[] = {
+ "\xec\xb9\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecba[] = {
+ "\xec\xba\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecbb[] = {
+ "\xec\xbb\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecbc[] = {
+ "\xec\xbc\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecbd[] = {
+ "\xec\xbd\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecbe[] = {
+ "\xec\xbe\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ecbf[] = {
+ "\xec\xbf\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed80[] = {
+ "\xed\x80\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed81[] = {
+ "\xed\x81\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed82[] = {
+ "\xed\x82\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed83[] = {
+ "\xed\x83\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed84[] = {
+ "\xed\x84\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed85[] = {
+ "\xed\x85\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed86[] = {
+ "\xed\x86\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed87[] = {
+ "\xed\x87\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed88[] = {
+ "\xed\x88\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed89[] = {
+ "\xed\x89\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed8a[] = {
+ "\xed\x8a\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed8b[] = {
+ "\xed\x8b\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed8c[] = {
+ "\xed\x8c\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed8d[] = {
+ "\xed\x8d\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed8e[] = {
+ "\xed\x8e\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed8f[] = {
+ "\xed\x8f\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed90[] = {
+ "\xed\x90\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed91[] = {
+ "\xed\x91\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed92[] = {
+ "\xed\x92\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed93[] = {
+ "\xed\x93\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed94[] = {
+ "\xed\x94\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed95[] = {
+ "\xed\x95\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed96[] = {
+ "\xed\x96\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed97[] = {
+ "\xed\x97\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xa9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed98[] = {
+ "\xed\x98\x85", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed99[] = {
+ "\xed\x99\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed9a[] = {
+ "\xed\x9a\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed9b[] = {
+ "\xed\x9b\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed9c[] = {
+ "\xed\x9c\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ac_table_ed9d[] = {
+ "\xed\x9d\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb1"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186ac(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ac_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x8d";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab0[] = {
+ "\xea\xb0\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab1[] = {
+ "\xea\xb1\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab2[] = {
+ "\xea\xb2\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab3[] = {
+ "\xea\xb3\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab4[] = {
+ "\xea\xb4\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab5[] = {
+ "\xea\xb5\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab6[] = {
+ "\xea\xb6\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab7[] = {
+ "\xea\xb7\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab8[] = {
+ "\xea\xb8\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eab9[] = {
+ "\xea\xb9\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eaba[] = {
+ "\xea\xba\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eabb[] = {
+ "\xea\xbb\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eabc[] = {
+ "\xea\xbc\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eabd[] = {
+ "\xea\xbd\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eabe[] = {
+ "\xea\xbe\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eabf[] = {
+ "\xea\xbf\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb80[] = {
+ "\xeb\x80\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb81[] = {
+ "\xeb\x81\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb82[] = {
+ "\xeb\x82\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb83[] = {
+ "\xeb\x83\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb84[] = {
+ "\xeb\x84\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb85[] = {
+ "\xeb\x85\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb86[] = {
+ "\xeb\x86\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb87[] = {
+ "\xeb\x87\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb88[] = {
+ "\xeb\x88\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb89[] = {
+ "\xeb\x89\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb8a[] = {
+ "\xeb\x8a\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb8b[] = {
+ "\xeb\x8b\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb8c[] = {
+ "\xeb\x8c\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb8d[] = {
+ "\xeb\x8d\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb8e[] = {
+ "\xeb\x8e\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb8f[] = {
+ "\xeb\x8f\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb90[] = {
+ "\xeb\x90\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb91[] = {
+ "\xeb\x91\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb92[] = {
+ "\xeb\x92\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb93[] = {
+ "\xeb\x93\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb94[] = {
+ "\xeb\x94\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb95[] = {
+ "\xeb\x95\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb96[] = {
+ "\xeb\x96\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb97[] = {
+ "\xeb\x97\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb98[] = {
+ "\xeb\x98\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb99[] = {
+ "\xeb\x99\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb9a[] = {
+ "\xeb\x9a\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb9b[] = {
+ "\xeb\x9b\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb9c[] = {
+ "\xeb\x9c\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb9d[] = {
+ "\xeb\x9d\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb9e[] = {
+ "\xeb\x9e\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eb9f[] = {
+ "\xeb\x9f\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba0[] = {
+ "\xeb\xa0\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba1[] = {
+ "\xeb\xa1\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba2[] = {
+ "\xeb\xa2\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba3[] = {
+ "\xeb\xa3\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba4[] = {
+ "\xeb\xa4\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba5[] = {
+ "\xeb\xa5\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba6[] = {
+ "\xeb\xa6\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba7[] = {
+ "\xeb\xa7\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba8[] = {
+ "\xeb\xa8\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eba9[] = {
+ "\xeb\xa9\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebaa[] = {
+ "\xeb\xaa\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebab[] = {
+ "\xeb\xab\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebac[] = {
+ "\xeb\xac\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebad[] = {
+ "\xeb\xad\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebae[] = {
+ "\xeb\xae\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebaf[] = {
+ "\xeb\xaf\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb0[] = {
+ "\xeb\xb0\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb1[] = {
+ "\xeb\xb1\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb2[] = {
+ "\xeb\xb2\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb3[] = {
+ "\xeb\xb3\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb4[] = {
+ "\xeb\xb4\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb5[] = {
+ "\xeb\xb5\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb6[] = {
+ "\xeb\xb6\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb7[] = {
+ "\xeb\xb7\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb8[] = {
+ "\xeb\xb8\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebb9[] = {
+ "\xeb\xb9\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebba[] = {
+ "\xeb\xba\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebbb[] = {
+ "\xeb\xbb\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebbc[] = {
+ "\xeb\xbc\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebbd[] = {
+ "\xeb\xbd\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebbe[] = {
+ "\xeb\xbe\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ebbf[] = {
+ "\xeb\xbf\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec80[] = {
+ "\xec\x80\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec81[] = {
+ "\xec\x81\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec82[] = {
+ "\xec\x82\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec83[] = {
+ "\xec\x83\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec84[] = {
+ "\xec\x84\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec85[] = {
+ "\xec\x85\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec86[] = {
+ "\xec\x86\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec87[] = {
+ "\xec\x87\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec88[] = {
+ "\xec\x88\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec89[] = {
+ "\xec\x89\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec8a[] = {
+ "\xec\x8a\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec8b[] = {
+ "\xec\x8b\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec8c[] = {
+ "\xec\x8c\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec8d[] = {
+ "\xec\x8d\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec8e[] = {
+ "\xec\x8e\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec8f[] = {
+ "\xec\x8f\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec90[] = {
+ "\xec\x90\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec91[] = {
+ "\xec\x91\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec92[] = {
+ "\xec\x92\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec93[] = {
+ "\xec\x93\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec94[] = {
+ "\xec\x94\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec95[] = {
+ "\xec\x95\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec96[] = {
+ "\xec\x96\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec97[] = {
+ "\xec\x97\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec98[] = {
+ "\xec\x98\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec99[] = {
+ "\xec\x99\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec9a[] = {
+ "\xec\x9a\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec9b[] = {
+ "\xec\x9b\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec9c[] = {
+ "\xec\x9c\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec9d[] = {
+ "\xec\x9d\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec9e[] = {
+ "\xec\x9e\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ec9f[] = {
+ "\xec\x9f\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca0[] = {
+ "\xec\xa0\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca1[] = {
+ "\xec\xa1\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca2[] = {
+ "\xec\xa2\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca3[] = {
+ "\xec\xa3\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca4[] = {
+ "\xec\xa4\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca5[] = {
+ "\xec\xa5\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca6[] = {
+ "\xec\xa6\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca7[] = {
+ "\xec\xa7\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca8[] = {
+ "\xec\xa8\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_eca9[] = {
+ "\xec\xa9\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecaa[] = {
+ "\xec\xaa\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecab[] = {
+ "\xec\xab\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecac[] = {
+ "\xec\xac\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecad[] = {
+ "\xec\xad\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecae[] = {
+ "\xec\xae\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecaf[] = {
+ "\xec\xaf\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb0[] = {
+ "\xec\xb0\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb1[] = {
+ "\xec\xb1\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb2[] = {
+ "\xec\xb2\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb3[] = {
+ "\xec\xb3\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb4[] = {
+ "\xec\xb4\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb5[] = {
+ "\xec\xb5\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb6[] = {
+ "\xec\xb6\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb7[] = {
+ "\xec\xb7\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb8[] = {
+ "\xec\xb8\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecb9[] = {
+ "\xec\xb9\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecba[] = {
+ "\xec\xba\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecbb[] = {
+ "\xec\xbb\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecbc[] = {
+ "\xec\xbc\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecbd[] = {
+ "\xec\xbd\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecbe[] = {
+ "\xec\xbe\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ecbf[] = {
+ "\xec\xbf\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed80[] = {
+ "\xed\x80\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed81[] = {
+ "\xed\x81\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed82[] = {
+ "\xed\x82\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed83[] = {
+ "\xed\x83\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed84[] = {
+ "\xed\x84\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed85[] = {
+ "\xed\x85\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed86[] = {
+ "\xed\x86\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed87[] = {
+ "\xed\x87\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed88[] = {
+ "\xed\x88\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed89[] = {
+ "\xed\x89\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed8a[] = {
+ "\xed\x8a\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed8b[] = {
+ "\xed\x8b\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed8c[] = {
+ "\xed\x8c\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed8d[] = {
+ "\xed\x8d\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed8e[] = {
+ "\xed\x8e\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed8f[] = {
+ "\xed\x8f\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed90[] = {
+ "\xed\x90\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed91[] = {
+ "\xed\x91\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed92[] = {
+ "\xed\x92\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed93[] = {
+ "\xed\x93\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed94[] = {
+ "\xed\x94\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed95[] = {
+ "\xed\x95\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed96[] = {
+ "\xed\x96\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed97[] = {
+ "\xed\x97\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xaa"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed98[] = {
+ "\xed\x98\x86", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed99[] = {
+ "\xed\x99\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed9a[] = {
+ "\xed\x9a\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed9b[] = {
+ "\xed\x9b\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed9c[] = {
+ "\xed\x9c\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ad_table_ed9d[] = {
+ "\xed\x9d\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb2"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186ad(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ad_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x8e";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab0[] = {
+ "\xea\xb0\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb0\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab1[] = {
+ "\xea\xb1\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab2[] = {
+ "\xea\xb2\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab3[] = {
+ "\xea\xb3\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab4[] = {
+ "\xea\xb4\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab5[] = {
+ "\xea\xb5\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab6[] = {
+ "\xea\xb6\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab7[] = {
+ "\xea\xb7\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb7\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab8[] = {
+ "\xea\xb8\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eab9[] = {
+ "\xea\xb9\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eaba[] = {
+ "\xea\xba\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eabb[] = {
+ "\xea\xbb\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eabc[] = {
+ "\xea\xbc\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eabd[] = {
+ "\xea\xbd\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eabe[] = {
+ "\xea\xbe\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbe\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eabf[] = {
+ "\xea\xbf\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb80[] = {
+ "\xeb\x80\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb81[] = {
+ "\xeb\x81\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb82[] = {
+ "\xeb\x82\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb83[] = {
+ "\xeb\x83\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb84[] = {
+ "\xeb\x84\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb85[] = {
+ "\xeb\x85\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x85\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb86[] = {
+ "\xeb\x86\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb87[] = {
+ "\xeb\x87\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb88[] = {
+ "\xeb\x88\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb89[] = {
+ "\xeb\x89\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb8a[] = {
+ "\xeb\x8a\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb8b[] = {
+ "\xeb\x8b\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb8c[] = {
+ "\xeb\x8c\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8c\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb8d[] = {
+ "\xeb\x8d\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb8e[] = {
+ "\xeb\x8e\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb8f[] = {
+ "\xeb\x8f\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb90[] = {
+ "\xeb\x90\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb91[] = {
+ "\xeb\x91\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb92[] = {
+ "\xeb\x92\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb93[] = {
+ "\xeb\x93\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x93\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb94[] = {
+ "\xeb\x94\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb95[] = {
+ "\xeb\x95\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb96[] = {
+ "\xeb\x96\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb97[] = {
+ "\xeb\x97\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb98[] = {
+ "\xeb\x98\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb99[] = {
+ "\xeb\x99\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb9a[] = {
+ "\xeb\x9a\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9a\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb9b[] = {
+ "\xeb\x9b\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb9c[] = {
+ "\xeb\x9c\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb9d[] = {
+ "\xeb\x9d\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb9e[] = {
+ "\xeb\x9e\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eb9f[] = {
+ "\xeb\x9f\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba0[] = {
+ "\xeb\xa0\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba1[] = {
+ "\xeb\xa1\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa1\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba2[] = {
+ "\xeb\xa2\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba3[] = {
+ "\xeb\xa3\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba4[] = {
+ "\xeb\xa4\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba5[] = {
+ "\xeb\xa5\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba6[] = {
+ "\xeb\xa6\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba7[] = {
+ "\xeb\xa7\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba8[] = {
+ "\xeb\xa8\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa8\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eba9[] = {
+ "\xeb\xa9\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebaa[] = {
+ "\xeb\xaa\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebab[] = {
+ "\xeb\xab\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebac[] = {
+ "\xeb\xac\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebad[] = {
+ "\xeb\xad\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebae[] = {
+ "\xeb\xae\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebaf[] = {
+ "\xeb\xaf\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xaf\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb0[] = {
+ "\xeb\xb0\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb1[] = {
+ "\xeb\xb1\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb2[] = {
+ "\xeb\xb2\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb3[] = {
+ "\xeb\xb3\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb4[] = {
+ "\xeb\xb4\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb5[] = {
+ "\xeb\xb5\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb6[] = {
+ "\xeb\xb6\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb6\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb7[] = {
+ "\xeb\xb7\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb8[] = {
+ "\xeb\xb8\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebb9[] = {
+ "\xeb\xb9\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebba[] = {
+ "\xeb\xba\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebbb[] = {
+ "\xeb\xbb\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebbc[] = {
+ "\xeb\xbc\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebbd[] = {
+ "\xeb\xbd\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbd\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebbe[] = {
+ "\xeb\xbe\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ebbf[] = {
+ "\xeb\xbf\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec80[] = {
+ "\xec\x80\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec81[] = {
+ "\xec\x81\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec82[] = {
+ "\xec\x82\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec83[] = {
+ "\xec\x83\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec84[] = {
+ "\xec\x84\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x84\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec85[] = {
+ "\xec\x85\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec86[] = {
+ "\xec\x86\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec87[] = {
+ "\xec\x87\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec88[] = {
+ "\xec\x88\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec89[] = {
+ "\xec\x89\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec8a[] = {
+ "\xec\x8a\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec8b[] = {
+ "\xec\x8b\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8b\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec8c[] = {
+ "\xec\x8c\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec8d[] = {
+ "\xec\x8d\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec8e[] = {
+ "\xec\x8e\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec8f[] = {
+ "\xec\x8f\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec90[] = {
+ "\xec\x90\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec91[] = {
+ "\xec\x91\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec92[] = {
+ "\xec\x92\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x92\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec93[] = {
+ "\xec\x93\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec94[] = {
+ "\xec\x94\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec95[] = {
+ "\xec\x95\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec96[] = {
+ "\xec\x96\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec97[] = {
+ "\xec\x97\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec98[] = {
+ "\xec\x98\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec99[] = {
+ "\xec\x99\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x99\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec9a[] = {
+ "\xec\x9a\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec9b[] = {
+ "\xec\x9b\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec9c[] = {
+ "\xec\x9c\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec9d[] = {
+ "\xec\x9d\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec9e[] = {
+ "\xec\x9e\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ec9f[] = {
+ "\xec\x9f\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca0[] = {
+ "\xec\xa0\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa0\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca1[] = {
+ "\xec\xa1\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca2[] = {
+ "\xec\xa2\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca3[] = {
+ "\xec\xa3\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca4[] = {
+ "\xec\xa4\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca5[] = {
+ "\xec\xa5\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca6[] = {
+ "\xec\xa6\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca7[] = {
+ "\xec\xa7\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa7\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca8[] = {
+ "\xec\xa8\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_eca9[] = {
+ "\xec\xa9\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecaa[] = {
+ "\xec\xaa\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecab[] = {
+ "\xec\xab\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecac[] = {
+ "\xec\xac\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecad[] = {
+ "\xec\xad\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecae[] = {
+ "\xec\xae\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xae\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecaf[] = {
+ "\xec\xaf\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb0[] = {
+ "\xec\xb0\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb1[] = {
+ "\xec\xb1\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb2[] = {
+ "\xec\xb2\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb3[] = {
+ "\xec\xb3\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb4[] = {
+ "\xec\xb4\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb5[] = {
+ "\xec\xb5\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb5\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb6[] = {
+ "\xec\xb6\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb7[] = {
+ "\xec\xb7\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb8[] = {
+ "\xec\xb8\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecb9[] = {
+ "\xec\xb9\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecba[] = {
+ "\xec\xba\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecbb[] = {
+ "\xec\xbb\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecbc[] = {
+ "\xec\xbc\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbc\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecbd[] = {
+ "\xec\xbd\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecbe[] = {
+ "\xec\xbe\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ecbf[] = {
+ "\xec\xbf\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed80[] = {
+ "\xed\x80\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed81[] = {
+ "\xed\x81\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed82[] = {
+ "\xed\x82\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed83[] = {
+ "\xed\x83\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x83\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed84[] = {
+ "\xed\x84\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed85[] = {
+ "\xed\x85\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed86[] = {
+ "\xed\x86\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed87[] = {
+ "\xed\x87\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed88[] = {
+ "\xed\x88\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed89[] = {
+ "\xed\x89\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed8a[] = {
+ "\xed\x8a\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8a\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed8b[] = {
+ "\xed\x8b\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed8c[] = {
+ "\xed\x8c\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed8d[] = {
+ "\xed\x8d\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed8e[] = {
+ "\xed\x8e\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed8f[] = {
+ "\xed\x8f\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed90[] = {
+ "\xed\x90\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed91[] = {
+ "\xed\x91\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x91\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed92[] = {
+ "\xed\x92\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed93[] = {
+ "\xed\x93\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed94[] = {
+ "\xed\x94\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed95[] = {
+ "\xed\x95\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed96[] = {
+ "\xed\x96\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed97[] = {
+ "\xed\x97\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xab"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed98[] = {
+ "\xed\x98\x87", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x98\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed99[] = {
+ "\xed\x99\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed9a[] = {
+ "\xed\x9a\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed9b[] = {
+ "\xed\x9b\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed9c[] = {
+ "\xed\x9c\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ae_table_ed9d[] = {
+ "\xed\x9d\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb3"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186ae(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ae_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x8f";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab0[] = {
+ "\xea\xb0\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab1[] = {
+ "\xea\xb1\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab2[] = {
+ "\xea\xb2\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab3[] = {
+ "\xea\xb3\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab4[] = {
+ "\xea\xb4\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab5[] = {
+ "\xea\xb5\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab6[] = {
+ "\xea\xb6\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab7[] = {
+ "\xea\xb7\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab8[] = {
+ "\xea\xb8\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eab9[] = {
+ "\xea\xb9\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eaba[] = {
+ "\xea\xba\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eabb[] = {
+ "\xea\xbb\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eabc[] = {
+ "\xea\xbc\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eabd[] = {
+ "\xea\xbd\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eabe[] = {
+ "\xea\xbe\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eabf[] = {
+ "\xea\xbf\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb80[] = {
+ "\xeb\x80\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb81[] = {
+ "\xeb\x81\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb82[] = {
+ "\xeb\x82\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb83[] = {
+ "\xeb\x83\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb84[] = {
+ "\xeb\x84\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb85[] = {
+ "\xeb\x85\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb86[] = {
+ "\xeb\x86\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb87[] = {
+ "\xeb\x87\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb88[] = {
+ "\xeb\x88\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb89[] = {
+ "\xeb\x89\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb8a[] = {
+ "\xeb\x8a\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb8b[] = {
+ "\xeb\x8b\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb8c[] = {
+ "\xeb\x8c\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb8d[] = {
+ "\xeb\x8d\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb8e[] = {
+ "\xeb\x8e\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb8f[] = {
+ "\xeb\x8f\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb90[] = {
+ "\xeb\x90\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb91[] = {
+ "\xeb\x91\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb92[] = {
+ "\xeb\x92\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb93[] = {
+ "\xeb\x93\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb94[] = {
+ "\xeb\x94\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb95[] = {
+ "\xeb\x95\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb96[] = {
+ "\xeb\x96\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb97[] = {
+ "\xeb\x97\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb98[] = {
+ "\xeb\x98\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb99[] = {
+ "\xeb\x99\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb9a[] = {
+ "\xeb\x9a\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb9b[] = {
+ "\xeb\x9b\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb9c[] = {
+ "\xeb\x9c\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb9d[] = {
+ "\xeb\x9d\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb9e[] = {
+ "\xeb\x9e\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eb9f[] = {
+ "\xeb\x9f\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba0[] = {
+ "\xeb\xa0\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba1[] = {
+ "\xeb\xa1\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba2[] = {
+ "\xeb\xa2\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba3[] = {
+ "\xeb\xa3\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba4[] = {
+ "\xeb\xa4\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba5[] = {
+ "\xeb\xa5\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba6[] = {
+ "\xeb\xa6\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba7[] = {
+ "\xeb\xa7\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba8[] = {
+ "\xeb\xa8\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eba9[] = {
+ "\xeb\xa9\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebaa[] = {
+ "\xeb\xaa\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebab[] = {
+ "\xeb\xab\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebac[] = {
+ "\xeb\xac\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebad[] = {
+ "\xeb\xad\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebae[] = {
+ "\xeb\xae\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebaf[] = {
+ "\xeb\xaf\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb0[] = {
+ "\xeb\xb0\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb1[] = {
+ "\xeb\xb1\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb2[] = {
+ "\xeb\xb2\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb3[] = {
+ "\xeb\xb3\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb4[] = {
+ "\xeb\xb4\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb5[] = {
+ "\xeb\xb5\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb6[] = {
+ "\xeb\xb6\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb7[] = {
+ "\xeb\xb7\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb8[] = {
+ "\xeb\xb8\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebb9[] = {
+ "\xeb\xb9\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebba[] = {
+ "\xeb\xba\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebbb[] = {
+ "\xeb\xbb\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebbc[] = {
+ "\xeb\xbc\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebbd[] = {
+ "\xeb\xbd\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebbe[] = {
+ "\xeb\xbe\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ebbf[] = {
+ "\xeb\xbf\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec80[] = {
+ "\xec\x80\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec81[] = {
+ "\xec\x81\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec82[] = {
+ "\xec\x82\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec83[] = {
+ "\xec\x83\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec84[] = {
+ "\xec\x84\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec85[] = {
+ "\xec\x85\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec86[] = {
+ "\xec\x86\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec87[] = {
+ "\xec\x87\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec88[] = {
+ "\xec\x88\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec89[] = {
+ "\xec\x89\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec8a[] = {
+ "\xec\x8a\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec8b[] = {
+ "\xec\x8b\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec8c[] = {
+ "\xec\x8c\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec8d[] = {
+ "\xec\x8d\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec8e[] = {
+ "\xec\x8e\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec8f[] = {
+ "\xec\x8f\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec90[] = {
+ "\xec\x90\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec91[] = {
+ "\xec\x91\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec92[] = {
+ "\xec\x92\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec93[] = {
+ "\xec\x93\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec94[] = {
+ "\xec\x94\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec95[] = {
+ "\xec\x95\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec96[] = {
+ "\xec\x96\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec97[] = {
+ "\xec\x97\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec98[] = {
+ "\xec\x98\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec99[] = {
+ "\xec\x99\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec9a[] = {
+ "\xec\x9a\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec9b[] = {
+ "\xec\x9b\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec9c[] = {
+ "\xec\x9c\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec9d[] = {
+ "\xec\x9d\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec9e[] = {
+ "\xec\x9e\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ec9f[] = {
+ "\xec\x9f\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca0[] = {
+ "\xec\xa0\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca1[] = {
+ "\xec\xa1\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca2[] = {
+ "\xec\xa2\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca3[] = {
+ "\xec\xa3\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca4[] = {
+ "\xec\xa4\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca5[] = {
+ "\xec\xa5\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca6[] = {
+ "\xec\xa6\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca7[] = {
+ "\xec\xa7\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca8[] = {
+ "\xec\xa8\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_eca9[] = {
+ "\xec\xa9\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecaa[] = {
+ "\xec\xaa\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecab[] = {
+ "\xec\xab\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecac[] = {
+ "\xec\xac\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecad[] = {
+ "\xec\xad\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecae[] = {
+ "\xec\xae\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecaf[] = {
+ "\xec\xaf\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb0[] = {
+ "\xec\xb0\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb1[] = {
+ "\xec\xb1\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb2[] = {
+ "\xec\xb2\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb3[] = {
+ "\xec\xb3\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb4[] = {
+ "\xec\xb4\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb5[] = {
+ "\xec\xb5\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb6[] = {
+ "\xec\xb6\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb7[] = {
+ "\xec\xb7\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb8[] = {
+ "\xec\xb8\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecb9[] = {
+ "\xec\xb9\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecba[] = {
+ "\xec\xba\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecbb[] = {
+ "\xec\xbb\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecbc[] = {
+ "\xec\xbc\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecbd[] = {
+ "\xec\xbd\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecbe[] = {
+ "\xec\xbe\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ecbf[] = {
+ "\xec\xbf\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed80[] = {
+ "\xed\x80\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed81[] = {
+ "\xed\x81\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed82[] = {
+ "\xed\x82\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed83[] = {
+ "\xed\x83\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed84[] = {
+ "\xed\x84\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed85[] = {
+ "\xed\x85\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed86[] = {
+ "\xed\x86\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed87[] = {
+ "\xed\x87\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed88[] = {
+ "\xed\x88\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed89[] = {
+ "\xed\x89\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed8a[] = {
+ "\xed\x8a\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed8b[] = {
+ "\xed\x8b\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed8c[] = {
+ "\xed\x8c\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed8d[] = {
+ "\xed\x8d\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed8e[] = {
+ "\xed\x8e\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed8f[] = {
+ "\xed\x8f\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed90[] = {
+ "\xed\x90\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed91[] = {
+ "\xed\x91\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed92[] = {
+ "\xed\x92\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed93[] = {
+ "\xed\x93\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed94[] = {
+ "\xed\x94\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed95[] = {
+ "\xed\x95\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed96[] = {
+ "\xed\x96\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed97[] = {
+ "\xed\x97\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xac"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed98[] = {
+ "\xed\x98\x88", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed99[] = {
+ "\xed\x99\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed9a[] = {
+ "\xed\x9a\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed9b[] = {
+ "\xed\x9b\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed9c[] = {
+ "\xed\x9c\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186af_table_ed9d[] = {
+ "\xed\x9d\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb4"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186af(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186af_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x90";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab0[] = {
+ "\xea\xb0\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab1[] = {
+ "\xea\xb1\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab2[] = {
+ "\xea\xb2\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab3[] = {
+ "\xea\xb3\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab4[] = {
+ "\xea\xb4\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab5[] = {
+ "\xea\xb5\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab6[] = {
+ "\xea\xb6\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab7[] = {
+ "\xea\xb7\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab8[] = {
+ "\xea\xb8\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eab9[] = {
+ "\xea\xb9\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eaba[] = {
+ "\xea\xba\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eabb[] = {
+ "\xea\xbb\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eabc[] = {
+ "\xea\xbc\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eabd[] = {
+ "\xea\xbd\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eabe[] = {
+ "\xea\xbe\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eabf[] = {
+ "\xea\xbf\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb80[] = {
+ "\xeb\x80\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb81[] = {
+ "\xeb\x81\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb82[] = {
+ "\xeb\x82\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb83[] = {
+ "\xeb\x83\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb84[] = {
+ "\xeb\x84\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb85[] = {
+ "\xeb\x85\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb86[] = {
+ "\xeb\x86\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb87[] = {
+ "\xeb\x87\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb88[] = {
+ "\xeb\x88\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb89[] = {
+ "\xeb\x89\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb8a[] = {
+ "\xeb\x8a\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb8b[] = {
+ "\xeb\x8b\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb8c[] = {
+ "\xeb\x8c\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb8d[] = {
+ "\xeb\x8d\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb8e[] = {
+ "\xeb\x8e\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb8f[] = {
+ "\xeb\x8f\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb90[] = {
+ "\xeb\x90\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb91[] = {
+ "\xeb\x91\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb92[] = {
+ "\xeb\x92\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb93[] = {
+ "\xeb\x93\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb94[] = {
+ "\xeb\x94\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb95[] = {
+ "\xeb\x95\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb96[] = {
+ "\xeb\x96\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb97[] = {
+ "\xeb\x97\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb98[] = {
+ "\xeb\x98\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb99[] = {
+ "\xeb\x99\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb9a[] = {
+ "\xeb\x9a\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb9b[] = {
+ "\xeb\x9b\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb9c[] = {
+ "\xeb\x9c\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb9d[] = {
+ "\xeb\x9d\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb9e[] = {
+ "\xeb\x9e\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eb9f[] = {
+ "\xeb\x9f\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba0[] = {
+ "\xeb\xa0\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba1[] = {
+ "\xeb\xa1\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba2[] = {
+ "\xeb\xa2\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba3[] = {
+ "\xeb\xa3\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba4[] = {
+ "\xeb\xa4\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba5[] = {
+ "\xeb\xa5\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba6[] = {
+ "\xeb\xa6\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba7[] = {
+ "\xeb\xa7\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba8[] = {
+ "\xeb\xa8\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eba9[] = {
+ "\xeb\xa9\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebaa[] = {
+ "\xeb\xaa\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebab[] = {
+ "\xeb\xab\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebac[] = {
+ "\xeb\xac\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebad[] = {
+ "\xeb\xad\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebae[] = {
+ "\xeb\xae\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebaf[] = {
+ "\xeb\xaf\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb0[] = {
+ "\xeb\xb0\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb1[] = {
+ "\xeb\xb1\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb2[] = {
+ "\xeb\xb2\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb3[] = {
+ "\xeb\xb3\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb4[] = {
+ "\xeb\xb4\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb5[] = {
+ "\xeb\xb5\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb6[] = {
+ "\xeb\xb6\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb7[] = {
+ "\xeb\xb7\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb8[] = {
+ "\xeb\xb8\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebb9[] = {
+ "\xeb\xb9\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebba[] = {
+ "\xeb\xba\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebbb[] = {
+ "\xeb\xbb\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebbc[] = {
+ "\xeb\xbc\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebbd[] = {
+ "\xeb\xbd\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebbe[] = {
+ "\xeb\xbe\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ebbf[] = {
+ "\xeb\xbf\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec80[] = {
+ "\xec\x80\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec81[] = {
+ "\xec\x81\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec82[] = {
+ "\xec\x82\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec83[] = {
+ "\xec\x83\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec84[] = {
+ "\xec\x84\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec85[] = {
+ "\xec\x85\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec86[] = {
+ "\xec\x86\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec87[] = {
+ "\xec\x87\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec88[] = {
+ "\xec\x88\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec89[] = {
+ "\xec\x89\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec8a[] = {
+ "\xec\x8a\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec8b[] = {
+ "\xec\x8b\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec8c[] = {
+ "\xec\x8c\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec8d[] = {
+ "\xec\x8d\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec8e[] = {
+ "\xec\x8e\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec8f[] = {
+ "\xec\x8f\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec90[] = {
+ "\xec\x90\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec91[] = {
+ "\xec\x91\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec92[] = {
+ "\xec\x92\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec93[] = {
+ "\xec\x93\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec94[] = {
+ "\xec\x94\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec95[] = {
+ "\xec\x95\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec96[] = {
+ "\xec\x96\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec97[] = {
+ "\xec\x97\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec98[] = {
+ "\xec\x98\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec99[] = {
+ "\xec\x99\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec9a[] = {
+ "\xec\x9a\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec9b[] = {
+ "\xec\x9b\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec9c[] = {
+ "\xec\x9c\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec9d[] = {
+ "\xec\x9d\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec9e[] = {
+ "\xec\x9e\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ec9f[] = {
+ "\xec\x9f\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca0[] = {
+ "\xec\xa0\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca1[] = {
+ "\xec\xa1\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca2[] = {
+ "\xec\xa2\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca3[] = {
+ "\xec\xa3\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca4[] = {
+ "\xec\xa4\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca5[] = {
+ "\xec\xa5\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca6[] = {
+ "\xec\xa6\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca7[] = {
+ "\xec\xa7\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca8[] = {
+ "\xec\xa8\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_eca9[] = {
+ "\xec\xa9\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecaa[] = {
+ "\xec\xaa\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecab[] = {
+ "\xec\xab\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecac[] = {
+ "\xec\xac\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecad[] = {
+ "\xec\xad\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecae[] = {
+ "\xec\xae\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecaf[] = {
+ "\xec\xaf\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb0[] = {
+ "\xec\xb0\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb1[] = {
+ "\xec\xb1\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb2[] = {
+ "\xec\xb2\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb3[] = {
+ "\xec\xb3\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb4[] = {
+ "\xec\xb4\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb5[] = {
+ "\xec\xb5\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb6[] = {
+ "\xec\xb6\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb7[] = {
+ "\xec\xb7\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb8[] = {
+ "\xec\xb8\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecb9[] = {
+ "\xec\xb9\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecba[] = {
+ "\xec\xba\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecbb[] = {
+ "\xec\xbb\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecbc[] = {
+ "\xec\xbc\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecbd[] = {
+ "\xec\xbd\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecbe[] = {
+ "\xec\xbe\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ecbf[] = {
+ "\xec\xbf\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed80[] = {
+ "\xed\x80\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed81[] = {
+ "\xed\x81\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed82[] = {
+ "\xed\x82\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed83[] = {
+ "\xed\x83\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed84[] = {
+ "\xed\x84\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed85[] = {
+ "\xed\x85\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed86[] = {
+ "\xed\x86\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed87[] = {
+ "\xed\x87\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed88[] = {
+ "\xed\x88\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed89[] = {
+ "\xed\x89\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed8a[] = {
+ "\xed\x8a\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed8b[] = {
+ "\xed\x8b\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed8c[] = {
+ "\xed\x8c\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed8d[] = {
+ "\xed\x8d\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed8e[] = {
+ "\xed\x8e\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed8f[] = {
+ "\xed\x8f\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed90[] = {
+ "\xed\x90\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed91[] = {
+ "\xed\x91\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed92[] = {
+ "\xed\x92\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed93[] = {
+ "\xed\x93\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed94[] = {
+ "\xed\x94\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed95[] = {
+ "\xed\x95\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed96[] = {
+ "\xed\x96\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed97[] = {
+ "\xed\x97\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xad"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed98[] = {
+ "\xed\x98\x89", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed99[] = {
+ "\xed\x99\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed9a[] = {
+ "\xed\x9a\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed9b[] = {
+ "\xed\x9b\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed9c[] = {
+ "\xed\x9c\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b0_table_ed9d[] = {
+ "\xed\x9d\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb5"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b0(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b0_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x91";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab0[] = {
+ "\xea\xb0\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab1[] = {
+ "\xea\xb1\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab2[] = {
+ "\xea\xb2\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab3[] = {
+ "\xea\xb3\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab4[] = {
+ "\xea\xb4\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab5[] = {
+ "\xea\xb5\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab6[] = {
+ "\xea\xb6\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab7[] = {
+ "\xea\xb7\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab8[] = {
+ "\xea\xb8\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eab9[] = {
+ "\xea\xb9\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eaba[] = {
+ "\xea\xba\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eabb[] = {
+ "\xea\xbb\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eabc[] = {
+ "\xea\xbc\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eabd[] = {
+ "\xea\xbd\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eabe[] = {
+ "\xea\xbe\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eabf[] = {
+ "\xea\xbf\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb80[] = {
+ "\xeb\x80\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb81[] = {
+ "\xeb\x81\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb82[] = {
+ "\xeb\x82\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb83[] = {
+ "\xeb\x83\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb84[] = {
+ "\xeb\x84\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb85[] = {
+ "\xeb\x85\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb86[] = {
+ "\xeb\x86\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb87[] = {
+ "\xeb\x87\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb88[] = {
+ "\xeb\x88\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb89[] = {
+ "\xeb\x89\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb8a[] = {
+ "\xeb\x8a\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb8b[] = {
+ "\xeb\x8b\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb8c[] = {
+ "\xeb\x8c\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb8d[] = {
+ "\xeb\x8d\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb8e[] = {
+ "\xeb\x8e\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb8f[] = {
+ "\xeb\x8f\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb90[] = {
+ "\xeb\x90\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb91[] = {
+ "\xeb\x91\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb92[] = {
+ "\xeb\x92\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb93[] = {
+ "\xeb\x93\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb94[] = {
+ "\xeb\x94\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb95[] = {
+ "\xeb\x95\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb96[] = {
+ "\xeb\x96\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb97[] = {
+ "\xeb\x97\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb98[] = {
+ "\xeb\x98\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb99[] = {
+ "\xeb\x99\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb9a[] = {
+ "\xeb\x9a\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb9b[] = {
+ "\xeb\x9b\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb9c[] = {
+ "\xeb\x9c\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb9d[] = {
+ "\xeb\x9d\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb9e[] = {
+ "\xeb\x9e\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eb9f[] = {
+ "\xeb\x9f\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba0[] = {
+ "\xeb\xa0\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba1[] = {
+ "\xeb\xa1\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba2[] = {
+ "\xeb\xa2\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba3[] = {
+ "\xeb\xa3\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba4[] = {
+ "\xeb\xa4\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba5[] = {
+ "\xeb\xa5\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba6[] = {
+ "\xeb\xa6\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba7[] = {
+ "\xeb\xa7\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba8[] = {
+ "\xeb\xa8\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eba9[] = {
+ "\xeb\xa9\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebaa[] = {
+ "\xeb\xaa\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebab[] = {
+ "\xeb\xab\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebac[] = {
+ "\xeb\xac\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebad[] = {
+ "\xeb\xad\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebae[] = {
+ "\xeb\xae\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebaf[] = {
+ "\xeb\xaf\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb0[] = {
+ "\xeb\xb0\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb1[] = {
+ "\xeb\xb1\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb2[] = {
+ "\xeb\xb2\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb3[] = {
+ "\xeb\xb3\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb4[] = {
+ "\xeb\xb4\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb5[] = {
+ "\xeb\xb5\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb6[] = {
+ "\xeb\xb6\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb7[] = {
+ "\xeb\xb7\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb8[] = {
+ "\xeb\xb8\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebb9[] = {
+ "\xeb\xb9\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebba[] = {
+ "\xeb\xba\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebbb[] = {
+ "\xeb\xbb\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebbc[] = {
+ "\xeb\xbc\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebbd[] = {
+ "\xeb\xbd\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebbe[] = {
+ "\xeb\xbe\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ebbf[] = {
+ "\xeb\xbf\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec80[] = {
+ "\xec\x80\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec81[] = {
+ "\xec\x81\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec82[] = {
+ "\xec\x82\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec83[] = {
+ "\xec\x83\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec84[] = {
+ "\xec\x84\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec85[] = {
+ "\xec\x85\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec86[] = {
+ "\xec\x86\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec87[] = {
+ "\xec\x87\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec88[] = {
+ "\xec\x88\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec89[] = {
+ "\xec\x89\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec8a[] = {
+ "\xec\x8a\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec8b[] = {
+ "\xec\x8b\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec8c[] = {
+ "\xec\x8c\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec8d[] = {
+ "\xec\x8d\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec8e[] = {
+ "\xec\x8e\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec8f[] = {
+ "\xec\x8f\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec90[] = {
+ "\xec\x90\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec91[] = {
+ "\xec\x91\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec92[] = {
+ "\xec\x92\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec93[] = {
+ "\xec\x93\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec94[] = {
+ "\xec\x94\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec95[] = {
+ "\xec\x95\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec96[] = {
+ "\xec\x96\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec97[] = {
+ "\xec\x97\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec98[] = {
+ "\xec\x98\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec99[] = {
+ "\xec\x99\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec9a[] = {
+ "\xec\x9a\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec9b[] = {
+ "\xec\x9b\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec9c[] = {
+ "\xec\x9c\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec9d[] = {
+ "\xec\x9d\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec9e[] = {
+ "\xec\x9e\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ec9f[] = {
+ "\xec\x9f\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca0[] = {
+ "\xec\xa0\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca1[] = {
+ "\xec\xa1\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca2[] = {
+ "\xec\xa2\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca3[] = {
+ "\xec\xa3\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca4[] = {
+ "\xec\xa4\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca5[] = {
+ "\xec\xa5\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca6[] = {
+ "\xec\xa6\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca7[] = {
+ "\xec\xa7\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca8[] = {
+ "\xec\xa8\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_eca9[] = {
+ "\xec\xa9\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecaa[] = {
+ "\xec\xaa\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecab[] = {
+ "\xec\xab\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecac[] = {
+ "\xec\xac\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecad[] = {
+ "\xec\xad\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecae[] = {
+ "\xec\xae\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecaf[] = {
+ "\xec\xaf\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb0[] = {
+ "\xec\xb0\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb1[] = {
+ "\xec\xb1\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb2[] = {
+ "\xec\xb2\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb3[] = {
+ "\xec\xb3\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb4[] = {
+ "\xec\xb4\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb5[] = {
+ "\xec\xb5\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb6[] = {
+ "\xec\xb6\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb7[] = {
+ "\xec\xb7\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb8[] = {
+ "\xec\xb8\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecb9[] = {
+ "\xec\xb9\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecba[] = {
+ "\xec\xba\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecbb[] = {
+ "\xec\xbb\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecbc[] = {
+ "\xec\xbc\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecbd[] = {
+ "\xec\xbd\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecbe[] = {
+ "\xec\xbe\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ecbf[] = {
+ "\xec\xbf\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed80[] = {
+ "\xed\x80\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed81[] = {
+ "\xed\x81\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed82[] = {
+ "\xed\x82\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed83[] = {
+ "\xed\x83\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed84[] = {
+ "\xed\x84\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed85[] = {
+ "\xed\x85\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed86[] = {
+ "\xed\x86\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed87[] = {
+ "\xed\x87\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed88[] = {
+ "\xed\x88\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed89[] = {
+ "\xed\x89\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed8a[] = {
+ "\xed\x8a\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed8b[] = {
+ "\xed\x8b\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed8c[] = {
+ "\xed\x8c\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed8d[] = {
+ "\xed\x8d\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed8e[] = {
+ "\xed\x8e\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed8f[] = {
+ "\xed\x8f\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed90[] = {
+ "\xed\x90\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed91[] = {
+ "\xed\x91\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed92[] = {
+ "\xed\x92\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed93[] = {
+ "\xed\x93\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed94[] = {
+ "\xed\x94\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed95[] = {
+ "\xed\x95\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed96[] = {
+ "\xed\x96\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed97[] = {
+ "\xed\x97\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xae"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed98[] = {
+ "\xed\x98\x8a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed99[] = {
+ "\xed\x99\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed9a[] = {
+ "\xed\x9a\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed9b[] = {
+ "\xed\x9b\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed9c[] = {
+ "\xed\x9c\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b1_table_ed9d[] = {
+ "\xed\x9d\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb6"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b1(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b1_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x92";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab0[] = {
+ "\xea\xb0\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab1[] = {
+ "\xea\xb1\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab2[] = {
+ "\xea\xb2\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab3[] = {
+ "\xea\xb3\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab4[] = {
+ "\xea\xb4\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb4\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab5[] = {
+ "\xea\xb5\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab6[] = {
+ "\xea\xb6\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab7[] = {
+ "\xea\xb7\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab8[] = {
+ "\xea\xb8\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eab9[] = {
+ "\xea\xb9\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eaba[] = {
+ "\xea\xba\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eabb[] = {
+ "\xea\xbb\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbb\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eabc[] = {
+ "\xea\xbc\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eabd[] = {
+ "\xea\xbd\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eabe[] = {
+ "\xea\xbe\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eabf[] = {
+ "\xea\xbf\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb80[] = {
+ "\xeb\x80\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb81[] = {
+ "\xeb\x81\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb82[] = {
+ "\xeb\x82\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x82\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb83[] = {
+ "\xeb\x83\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb84[] = {
+ "\xeb\x84\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb85[] = {
+ "\xeb\x85\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb86[] = {
+ "\xeb\x86\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb87[] = {
+ "\xeb\x87\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb88[] = {
+ "\xeb\x88\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb89[] = {
+ "\xeb\x89\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x89\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb8a[] = {
+ "\xeb\x8a\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb8b[] = {
+ "\xeb\x8b\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb8c[] = {
+ "\xeb\x8c\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb8d[] = {
+ "\xeb\x8d\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb8e[] = {
+ "\xeb\x8e\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb8f[] = {
+ "\xeb\x8f\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb90[] = {
+ "\xeb\x90\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x90\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb91[] = {
+ "\xeb\x91\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb92[] = {
+ "\xeb\x92\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb93[] = {
+ "\xeb\x93\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb94[] = {
+ "\xeb\x94\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb95[] = {
+ "\xeb\x95\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb96[] = {
+ "\xeb\x96\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb97[] = {
+ "\xeb\x97\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x97\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb98[] = {
+ "\xeb\x98\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb99[] = {
+ "\xeb\x99\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb9a[] = {
+ "\xeb\x9a\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb9b[] = {
+ "\xeb\x9b\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb9c[] = {
+ "\xeb\x9c\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb9d[] = {
+ "\xeb\x9d\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb9e[] = {
+ "\xeb\x9e\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9e\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eb9f[] = {
+ "\xeb\x9f\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba0[] = {
+ "\xeb\xa0\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba1[] = {
+ "\xeb\xa1\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba2[] = {
+ "\xeb\xa2\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba3[] = {
+ "\xeb\xa3\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba4[] = {
+ "\xeb\xa4\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba5[] = {
+ "\xeb\xa5\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa5\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba6[] = {
+ "\xeb\xa6\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba7[] = {
+ "\xeb\xa7\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba8[] = {
+ "\xeb\xa8\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eba9[] = {
+ "\xeb\xa9\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebaa[] = {
+ "\xeb\xaa\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebab[] = {
+ "\xeb\xab\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebac[] = {
+ "\xeb\xac\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xac\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebad[] = {
+ "\xeb\xad\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebae[] = {
+ "\xeb\xae\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebaf[] = {
+ "\xeb\xaf\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb0[] = {
+ "\xeb\xb0\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb1[] = {
+ "\xeb\xb1\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb2[] = {
+ "\xeb\xb2\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb3[] = {
+ "\xeb\xb3\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb3\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb4[] = {
+ "\xeb\xb4\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb5[] = {
+ "\xeb\xb5\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb6[] = {
+ "\xeb\xb6\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb7[] = {
+ "\xeb\xb7\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb8[] = {
+ "\xeb\xb8\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebb9[] = {
+ "\xeb\xb9\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebba[] = {
+ "\xeb\xba\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xba\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebbb[] = {
+ "\xeb\xbb\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebbc[] = {
+ "\xeb\xbc\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebbd[] = {
+ "\xeb\xbd\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebbe[] = {
+ "\xeb\xbe\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ebbf[] = {
+ "\xeb\xbf\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec80[] = {
+ "\xec\x80\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec81[] = {
+ "\xec\x81\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x81\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec82[] = {
+ "\xec\x82\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec83[] = {
+ "\xec\x83\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec84[] = {
+ "\xec\x84\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec85[] = {
+ "\xec\x85\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec86[] = {
+ "\xec\x86\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec87[] = {
+ "\xec\x87\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec88[] = {
+ "\xec\x88\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x88\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec89[] = {
+ "\xec\x89\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec8a[] = {
+ "\xec\x8a\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec8b[] = {
+ "\xec\x8b\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec8c[] = {
+ "\xec\x8c\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec8d[] = {
+ "\xec\x8d\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec8e[] = {
+ "\xec\x8e\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec8f[] = {
+ "\xec\x8f\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8f\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec90[] = {
+ "\xec\x90\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec91[] = {
+ "\xec\x91\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec92[] = {
+ "\xec\x92\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec93[] = {
+ "\xec\x93\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec94[] = {
+ "\xec\x94\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec95[] = {
+ "\xec\x95\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec96[] = {
+ "\xec\x96\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x96\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec97[] = {
+ "\xec\x97\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec98[] = {
+ "\xec\x98\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec99[] = {
+ "\xec\x99\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec9a[] = {
+ "\xec\x9a\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec9b[] = {
+ "\xec\x9b\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec9c[] = {
+ "\xec\x9c\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec9d[] = {
+ "\xec\x9d\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9d\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec9e[] = {
+ "\xec\x9e\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ec9f[] = {
+ "\xec\x9f\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca0[] = {
+ "\xec\xa0\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca1[] = {
+ "\xec\xa1\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca2[] = {
+ "\xec\xa2\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca3[] = {
+ "\xec\xa3\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca4[] = {
+ "\xec\xa4\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa4\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca5[] = {
+ "\xec\xa5\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca6[] = {
+ "\xec\xa6\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca7[] = {
+ "\xec\xa7\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca8[] = {
+ "\xec\xa8\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_eca9[] = {
+ "\xec\xa9\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecaa[] = {
+ "\xec\xaa\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecab[] = {
+ "\xec\xab\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xab\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecac[] = {
+ "\xec\xac\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecad[] = {
+ "\xec\xad\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecae[] = {
+ "\xec\xae\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecaf[] = {
+ "\xec\xaf\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb0[] = {
+ "\xec\xb0\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb1[] = {
+ "\xec\xb1\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb2[] = {
+ "\xec\xb2\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb2\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb3[] = {
+ "\xec\xb3\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb4[] = {
+ "\xec\xb4\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb5[] = {
+ "\xec\xb5\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb6[] = {
+ "\xec\xb6\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb7[] = {
+ "\xec\xb7\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb8[] = {
+ "\xec\xb8\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecb9[] = {
+ "\xec\xb9\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb9\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecba[] = {
+ "\xec\xba\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecbb[] = {
+ "\xec\xbb\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecbc[] = {
+ "\xec\xbc\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecbd[] = {
+ "\xec\xbd\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecbe[] = {
+ "\xec\xbe\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ecbf[] = {
+ "\xec\xbf\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed80[] = {
+ "\xed\x80\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x80\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed81[] = {
+ "\xed\x81\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed82[] = {
+ "\xed\x82\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed83[] = {
+ "\xed\x83\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed84[] = {
+ "\xed\x84\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed85[] = {
+ "\xed\x85\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed86[] = {
+ "\xed\x86\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed87[] = {
+ "\xed\x87\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x87\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed88[] = {
+ "\xed\x88\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed89[] = {
+ "\xed\x89\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed8a[] = {
+ "\xed\x8a\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed8b[] = {
+ "\xed\x8b\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed8c[] = {
+ "\xed\x8c\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed8d[] = {
+ "\xed\x8d\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed8e[] = {
+ "\xed\x8e\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8e\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed8f[] = {
+ "\xed\x8f\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed90[] = {
+ "\xed\x90\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed91[] = {
+ "\xed\x91\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed92[] = {
+ "\xed\x92\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed93[] = {
+ "\xed\x93\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed94[] = {
+ "\xed\x94\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed95[] = {
+ "\xed\x95\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x95\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed96[] = {
+ "\xed\x96\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed97[] = {
+ "\xed\x97\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xaf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed98[] = {
+ "\xed\x98\x8b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed99[] = {
+ "\xed\x99\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed9a[] = {
+ "\xed\x9a\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed9b[] = {
+ "\xed\x9b\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed9c[] = {
+ "\xed\x9c\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9c\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b2_table_ed9d[] = {
+ "\xed\x9d\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb7"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b2(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b2_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x93";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab0[] = {
+ "\xea\xb0\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab1[] = {
+ "\xea\xb1\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab2[] = {
+ "\xea\xb2\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab3[] = {
+ "\xea\xb3\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab4[] = {
+ "\xea\xb4\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab5[] = {
+ "\xea\xb5\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab6[] = {
+ "\xea\xb6\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab7[] = {
+ "\xea\xb7\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab8[] = {
+ "\xea\xb8\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eab9[] = {
+ "\xea\xb9\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eaba[] = {
+ "\xea\xba\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eabb[] = {
+ "\xea\xbb\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eabc[] = {
+ "\xea\xbc\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eabd[] = {
+ "\xea\xbd\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eabe[] = {
+ "\xea\xbe\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eabf[] = {
+ "\xea\xbf\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb80[] = {
+ "\xeb\x80\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb81[] = {
+ "\xeb\x81\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb82[] = {
+ "\xeb\x82\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb83[] = {
+ "\xeb\x83\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb84[] = {
+ "\xeb\x84\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb85[] = {
+ "\xeb\x85\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb86[] = {
+ "\xeb\x86\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb87[] = {
+ "\xeb\x87\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb88[] = {
+ "\xeb\x88\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb89[] = {
+ "\xeb\x89\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb8a[] = {
+ "\xeb\x8a\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb8b[] = {
+ "\xeb\x8b\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb8c[] = {
+ "\xeb\x8c\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb8d[] = {
+ "\xeb\x8d\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb8e[] = {
+ "\xeb\x8e\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb8f[] = {
+ "\xeb\x8f\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb90[] = {
+ "\xeb\x90\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb91[] = {
+ "\xeb\x91\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb92[] = {
+ "\xeb\x92\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb93[] = {
+ "\xeb\x93\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb94[] = {
+ "\xeb\x94\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb95[] = {
+ "\xeb\x95\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb96[] = {
+ "\xeb\x96\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb97[] = {
+ "\xeb\x97\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb98[] = {
+ "\xeb\x98\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb99[] = {
+ "\xeb\x99\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb9a[] = {
+ "\xeb\x9a\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb9b[] = {
+ "\xeb\x9b\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb9c[] = {
+ "\xeb\x9c\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb9d[] = {
+ "\xeb\x9d\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb9e[] = {
+ "\xeb\x9e\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eb9f[] = {
+ "\xeb\x9f\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba0[] = {
+ "\xeb\xa0\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba1[] = {
+ "\xeb\xa1\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba2[] = {
+ "\xeb\xa2\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba3[] = {
+ "\xeb\xa3\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba4[] = {
+ "\xeb\xa4\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba5[] = {
+ "\xeb\xa5\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba6[] = {
+ "\xeb\xa6\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba7[] = {
+ "\xeb\xa7\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba8[] = {
+ "\xeb\xa8\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eba9[] = {
+ "\xeb\xa9\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebaa[] = {
+ "\xeb\xaa\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebab[] = {
+ "\xeb\xab\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebac[] = {
+ "\xeb\xac\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebad[] = {
+ "\xeb\xad\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebae[] = {
+ "\xeb\xae\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebaf[] = {
+ "\xeb\xaf\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb0[] = {
+ "\xeb\xb0\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb1[] = {
+ "\xeb\xb1\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb2[] = {
+ "\xeb\xb2\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb3[] = {
+ "\xeb\xb3\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb4[] = {
+ "\xeb\xb4\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb5[] = {
+ "\xeb\xb5\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb6[] = {
+ "\xeb\xb6\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb7[] = {
+ "\xeb\xb7\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb8[] = {
+ "\xeb\xb8\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebb9[] = {
+ "\xeb\xb9\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebba[] = {
+ "\xeb\xba\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebbb[] = {
+ "\xeb\xbb\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebbc[] = {
+ "\xeb\xbc\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebbd[] = {
+ "\xeb\xbd\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebbe[] = {
+ "\xeb\xbe\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ebbf[] = {
+ "\xeb\xbf\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec80[] = {
+ "\xec\x80\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec81[] = {
+ "\xec\x81\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec82[] = {
+ "\xec\x82\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec83[] = {
+ "\xec\x83\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec84[] = {
+ "\xec\x84\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec85[] = {
+ "\xec\x85\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec86[] = {
+ "\xec\x86\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec87[] = {
+ "\xec\x87\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec88[] = {
+ "\xec\x88\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec89[] = {
+ "\xec\x89\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec8a[] = {
+ "\xec\x8a\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec8b[] = {
+ "\xec\x8b\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec8c[] = {
+ "\xec\x8c\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec8d[] = {
+ "\xec\x8d\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec8e[] = {
+ "\xec\x8e\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec8f[] = {
+ "\xec\x8f\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec90[] = {
+ "\xec\x90\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec91[] = {
+ "\xec\x91\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec92[] = {
+ "\xec\x92\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec93[] = {
+ "\xec\x93\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec94[] = {
+ "\xec\x94\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec95[] = {
+ "\xec\x95\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec96[] = {
+ "\xec\x96\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec97[] = {
+ "\xec\x97\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec98[] = {
+ "\xec\x98\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec99[] = {
+ "\xec\x99\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec9a[] = {
+ "\xec\x9a\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec9b[] = {
+ "\xec\x9b\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec9c[] = {
+ "\xec\x9c\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec9d[] = {
+ "\xec\x9d\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec9e[] = {
+ "\xec\x9e\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ec9f[] = {
+ "\xec\x9f\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca0[] = {
+ "\xec\xa0\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca1[] = {
+ "\xec\xa1\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca2[] = {
+ "\xec\xa2\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca3[] = {
+ "\xec\xa3\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca4[] = {
+ "\xec\xa4\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca5[] = {
+ "\xec\xa5\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca6[] = {
+ "\xec\xa6\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca7[] = {
+ "\xec\xa7\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca8[] = {
+ "\xec\xa8\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_eca9[] = {
+ "\xec\xa9\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecaa[] = {
+ "\xec\xaa\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecab[] = {
+ "\xec\xab\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecac[] = {
+ "\xec\xac\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecad[] = {
+ "\xec\xad\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecae[] = {
+ "\xec\xae\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecaf[] = {
+ "\xec\xaf\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb0[] = {
+ "\xec\xb0\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb1[] = {
+ "\xec\xb1\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb2[] = {
+ "\xec\xb2\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb3[] = {
+ "\xec\xb3\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb4[] = {
+ "\xec\xb4\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb5[] = {
+ "\xec\xb5\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb6[] = {
+ "\xec\xb6\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb7[] = {
+ "\xec\xb7\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb8[] = {
+ "\xec\xb8\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecb9[] = {
+ "\xec\xb9\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecba[] = {
+ "\xec\xba\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecbb[] = {
+ "\xec\xbb\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecbc[] = {
+ "\xec\xbc\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecbd[] = {
+ "\xec\xbd\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecbe[] = {
+ "\xec\xbe\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ecbf[] = {
+ "\xec\xbf\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed80[] = {
+ "\xed\x80\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed81[] = {
+ "\xed\x81\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed82[] = {
+ "\xed\x82\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed83[] = {
+ "\xed\x83\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed84[] = {
+ "\xed\x84\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed85[] = {
+ "\xed\x85\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed86[] = {
+ "\xed\x86\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed87[] = {
+ "\xed\x87\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed88[] = {
+ "\xed\x88\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed89[] = {
+ "\xed\x89\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed8a[] = {
+ "\xed\x8a\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed8b[] = {
+ "\xed\x8b\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed8c[] = {
+ "\xed\x8c\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed8d[] = {
+ "\xed\x8d\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed8e[] = {
+ "\xed\x8e\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed8f[] = {
+ "\xed\x8f\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed90[] = {
+ "\xed\x90\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed91[] = {
+ "\xed\x91\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed92[] = {
+ "\xed\x92\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed93[] = {
+ "\xed\x93\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed94[] = {
+ "\xed\x94\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed95[] = {
+ "\xed\x95\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed96[] = {
+ "\xed\x96\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed97[] = {
+ "\xed\x97\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb0"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed98[] = {
+ "\xed\x98\x8c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed99[] = {
+ "\xed\x99\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed9a[] = {
+ "\xed\x9a\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed9b[] = {
+ "\xed\x9b\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed9c[] = {
+ "\xed\x9c\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b3_table_ed9d[] = {
+ "\xed\x9d\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb8"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b3(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b3_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x94";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab0[] = {
+ "\xea\xb0\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab1[] = {
+ "\xea\xb1\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab2[] = {
+ "\xea\xb2\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab3[] = {
+ "\xea\xb3\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab4[] = {
+ "\xea\xb4\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab5[] = {
+ "\xea\xb5\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab6[] = {
+ "\xea\xb6\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab7[] = {
+ "\xea\xb7\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab8[] = {
+ "\xea\xb8\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eab9[] = {
+ "\xea\xb9\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eaba[] = {
+ "\xea\xba\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eabb[] = {
+ "\xea\xbb\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eabc[] = {
+ "\xea\xbc\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eabd[] = {
+ "\xea\xbd\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eabe[] = {
+ "\xea\xbe\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eabf[] = {
+ "\xea\xbf\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb80[] = {
+ "\xeb\x80\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb81[] = {
+ "\xeb\x81\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb82[] = {
+ "\xeb\x82\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb83[] = {
+ "\xeb\x83\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb84[] = {
+ "\xeb\x84\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb85[] = {
+ "\xeb\x85\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb86[] = {
+ "\xeb\x86\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb87[] = {
+ "\xeb\x87\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb88[] = {
+ "\xeb\x88\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb89[] = {
+ "\xeb\x89\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb8a[] = {
+ "\xeb\x8a\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb8b[] = {
+ "\xeb\x8b\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb8c[] = {
+ "\xeb\x8c\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb8d[] = {
+ "\xeb\x8d\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb8e[] = {
+ "\xeb\x8e\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb8f[] = {
+ "\xeb\x8f\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb90[] = {
+ "\xeb\x90\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb91[] = {
+ "\xeb\x91\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb92[] = {
+ "\xeb\x92\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb93[] = {
+ "\xeb\x93\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb94[] = {
+ "\xeb\x94\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb95[] = {
+ "\xeb\x95\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb96[] = {
+ "\xeb\x96\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb97[] = {
+ "\xeb\x97\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb98[] = {
+ "\xeb\x98\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb99[] = {
+ "\xeb\x99\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb9a[] = {
+ "\xeb\x9a\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb9b[] = {
+ "\xeb\x9b\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb9c[] = {
+ "\xeb\x9c\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb9d[] = {
+ "\xeb\x9d\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb9e[] = {
+ "\xeb\x9e\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eb9f[] = {
+ "\xeb\x9f\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba0[] = {
+ "\xeb\xa0\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba1[] = {
+ "\xeb\xa1\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba2[] = {
+ "\xeb\xa2\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba3[] = {
+ "\xeb\xa3\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba4[] = {
+ "\xeb\xa4\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba5[] = {
+ "\xeb\xa5\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba6[] = {
+ "\xeb\xa6\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba7[] = {
+ "\xeb\xa7\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba8[] = {
+ "\xeb\xa8\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eba9[] = {
+ "\xeb\xa9\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebaa[] = {
+ "\xeb\xaa\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebab[] = {
+ "\xeb\xab\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebac[] = {
+ "\xeb\xac\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebad[] = {
+ "\xeb\xad\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebae[] = {
+ "\xeb\xae\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebaf[] = {
+ "\xeb\xaf\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb0[] = {
+ "\xeb\xb0\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb1[] = {
+ "\xeb\xb1\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb2[] = {
+ "\xeb\xb2\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb3[] = {
+ "\xeb\xb3\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb4[] = {
+ "\xeb\xb4\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb5[] = {
+ "\xeb\xb5\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb6[] = {
+ "\xeb\xb6\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb7[] = {
+ "\xeb\xb7\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb8[] = {
+ "\xeb\xb8\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebb9[] = {
+ "\xeb\xb9\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebba[] = {
+ "\xeb\xba\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebbb[] = {
+ "\xeb\xbb\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebbc[] = {
+ "\xeb\xbc\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebbd[] = {
+ "\xeb\xbd\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebbe[] = {
+ "\xeb\xbe\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ebbf[] = {
+ "\xeb\xbf\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec80[] = {
+ "\xec\x80\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec81[] = {
+ "\xec\x81\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec82[] = {
+ "\xec\x82\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec83[] = {
+ "\xec\x83\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec84[] = {
+ "\xec\x84\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec85[] = {
+ "\xec\x85\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec86[] = {
+ "\xec\x86\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec87[] = {
+ "\xec\x87\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec88[] = {
+ "\xec\x88\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec89[] = {
+ "\xec\x89\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec8a[] = {
+ "\xec\x8a\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec8b[] = {
+ "\xec\x8b\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec8c[] = {
+ "\xec\x8c\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec8d[] = {
+ "\xec\x8d\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec8e[] = {
+ "\xec\x8e\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec8f[] = {
+ "\xec\x8f\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec90[] = {
+ "\xec\x90\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec91[] = {
+ "\xec\x91\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec92[] = {
+ "\xec\x92\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec93[] = {
+ "\xec\x93\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec94[] = {
+ "\xec\x94\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec95[] = {
+ "\xec\x95\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec96[] = {
+ "\xec\x96\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec97[] = {
+ "\xec\x97\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec98[] = {
+ "\xec\x98\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec99[] = {
+ "\xec\x99\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec9a[] = {
+ "\xec\x9a\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec9b[] = {
+ "\xec\x9b\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec9c[] = {
+ "\xec\x9c\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec9d[] = {
+ "\xec\x9d\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec9e[] = {
+ "\xec\x9e\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ec9f[] = {
+ "\xec\x9f\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca0[] = {
+ "\xec\xa0\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca1[] = {
+ "\xec\xa1\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca2[] = {
+ "\xec\xa2\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca3[] = {
+ "\xec\xa3\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca4[] = {
+ "\xec\xa4\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca5[] = {
+ "\xec\xa5\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca6[] = {
+ "\xec\xa6\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca7[] = {
+ "\xec\xa7\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca8[] = {
+ "\xec\xa8\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_eca9[] = {
+ "\xec\xa9\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecaa[] = {
+ "\xec\xaa\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecab[] = {
+ "\xec\xab\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecac[] = {
+ "\xec\xac\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecad[] = {
+ "\xec\xad\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecae[] = {
+ "\xec\xae\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecaf[] = {
+ "\xec\xaf\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb0[] = {
+ "\xec\xb0\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb1[] = {
+ "\xec\xb1\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb2[] = {
+ "\xec\xb2\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb3[] = {
+ "\xec\xb3\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb4[] = {
+ "\xec\xb4\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb5[] = {
+ "\xec\xb5\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb6[] = {
+ "\xec\xb6\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb7[] = {
+ "\xec\xb7\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb8[] = {
+ "\xec\xb8\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecb9[] = {
+ "\xec\xb9\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecba[] = {
+ "\xec\xba\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecbb[] = {
+ "\xec\xbb\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecbc[] = {
+ "\xec\xbc\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecbd[] = {
+ "\xec\xbd\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecbe[] = {
+ "\xec\xbe\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ecbf[] = {
+ "\xec\xbf\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed80[] = {
+ "\xed\x80\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed81[] = {
+ "\xed\x81\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed82[] = {
+ "\xed\x82\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed83[] = {
+ "\xed\x83\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed84[] = {
+ "\xed\x84\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed85[] = {
+ "\xed\x85\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed86[] = {
+ "\xed\x86\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed87[] = {
+ "\xed\x87\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed88[] = {
+ "\xed\x88\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed89[] = {
+ "\xed\x89\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed8a[] = {
+ "\xed\x8a\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed8b[] = {
+ "\xed\x8b\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed8c[] = {
+ "\xed\x8c\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed8d[] = {
+ "\xed\x8d\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed8e[] = {
+ "\xed\x8e\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed8f[] = {
+ "\xed\x8f\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed90[] = {
+ "\xed\x90\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed91[] = {
+ "\xed\x91\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed92[] = {
+ "\xed\x92\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed93[] = {
+ "\xed\x93\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed94[] = {
+ "\xed\x94\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed95[] = {
+ "\xed\x95\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed96[] = {
+ "\xed\x96\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed97[] = {
+ "\xed\x97\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb1"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed98[] = {
+ "\xed\x98\x8d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xa9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed99[] = {
+ "\xed\x99\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed9a[] = {
+ "\xed\x9a\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed9b[] = {
+ "\xed\x9b\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed9c[] = {
+ "\xed\x9c\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b4_table_ed9d[] = {
+ "\xed\x9d\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xb9"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b4(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b4_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x95";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab0[] = {
+ "\xea\xb0\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab1[] = {
+ "\xea\xb1\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab2[] = {
+ "\xea\xb2\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab3[] = {
+ "\xea\xb3\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab4[] = {
+ "\xea\xb4\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab5[] = {
+ "\xea\xb5\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab6[] = {
+ "\xea\xb6\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab7[] = {
+ "\xea\xb7\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab8[] = {
+ "\xea\xb8\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eab9[] = {
+ "\xea\xb9\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eaba[] = {
+ "\xea\xba\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eabb[] = {
+ "\xea\xbb\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eabc[] = {
+ "\xea\xbc\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eabd[] = {
+ "\xea\xbd\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eabe[] = {
+ "\xea\xbe\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eabf[] = {
+ "\xea\xbf\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb80[] = {
+ "\xeb\x80\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb81[] = {
+ "\xeb\x81\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb82[] = {
+ "\xeb\x82\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb83[] = {
+ "\xeb\x83\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb84[] = {
+ "\xeb\x84\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb85[] = {
+ "\xeb\x85\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb86[] = {
+ "\xeb\x86\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb87[] = {
+ "\xeb\x87\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb88[] = {
+ "\xeb\x88\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb89[] = {
+ "\xeb\x89\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb8a[] = {
+ "\xeb\x8a\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb8b[] = {
+ "\xeb\x8b\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb8c[] = {
+ "\xeb\x8c\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb8d[] = {
+ "\xeb\x8d\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb8e[] = {
+ "\xeb\x8e\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb8f[] = {
+ "\xeb\x8f\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb90[] = {
+ "\xeb\x90\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb91[] = {
+ "\xeb\x91\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb92[] = {
+ "\xeb\x92\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb93[] = {
+ "\xeb\x93\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb94[] = {
+ "\xeb\x94\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb95[] = {
+ "\xeb\x95\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb96[] = {
+ "\xeb\x96\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb97[] = {
+ "\xeb\x97\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb98[] = {
+ "\xeb\x98\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb99[] = {
+ "\xeb\x99\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb9a[] = {
+ "\xeb\x9a\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb9b[] = {
+ "\xeb\x9b\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb9c[] = {
+ "\xeb\x9c\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb9d[] = {
+ "\xeb\x9d\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb9e[] = {
+ "\xeb\x9e\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eb9f[] = {
+ "\xeb\x9f\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba0[] = {
+ "\xeb\xa0\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba1[] = {
+ "\xeb\xa1\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba2[] = {
+ "\xeb\xa2\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba3[] = {
+ "\xeb\xa3\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba4[] = {
+ "\xeb\xa4\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba5[] = {
+ "\xeb\xa5\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba6[] = {
+ "\xeb\xa6\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba7[] = {
+ "\xeb\xa7\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba8[] = {
+ "\xeb\xa8\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eba9[] = {
+ "\xeb\xa9\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebaa[] = {
+ "\xeb\xaa\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebab[] = {
+ "\xeb\xab\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebac[] = {
+ "\xeb\xac\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebad[] = {
+ "\xeb\xad\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebae[] = {
+ "\xeb\xae\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebaf[] = {
+ "\xeb\xaf\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb0[] = {
+ "\xeb\xb0\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb1[] = {
+ "\xeb\xb1\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb2[] = {
+ "\xeb\xb2\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb3[] = {
+ "\xeb\xb3\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb4[] = {
+ "\xeb\xb4\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb5[] = {
+ "\xeb\xb5\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb6[] = {
+ "\xeb\xb6\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb7[] = {
+ "\xeb\xb7\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb8[] = {
+ "\xeb\xb8\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebb9[] = {
+ "\xeb\xb9\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebba[] = {
+ "\xeb\xba\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebbb[] = {
+ "\xeb\xbb\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebbc[] = {
+ "\xeb\xbc\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebbd[] = {
+ "\xeb\xbd\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebbe[] = {
+ "\xeb\xbe\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ebbf[] = {
+ "\xeb\xbf\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec80[] = {
+ "\xec\x80\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec81[] = {
+ "\xec\x81\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec82[] = {
+ "\xec\x82\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec83[] = {
+ "\xec\x83\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec84[] = {
+ "\xec\x84\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec85[] = {
+ "\xec\x85\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec86[] = {
+ "\xec\x86\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec87[] = {
+ "\xec\x87\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec88[] = {
+ "\xec\x88\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec89[] = {
+ "\xec\x89\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec8a[] = {
+ "\xec\x8a\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec8b[] = {
+ "\xec\x8b\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec8c[] = {
+ "\xec\x8c\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec8d[] = {
+ "\xec\x8d\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec8e[] = {
+ "\xec\x8e\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec8f[] = {
+ "\xec\x8f\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec90[] = {
+ "\xec\x90\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec91[] = {
+ "\xec\x91\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec92[] = {
+ "\xec\x92\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec93[] = {
+ "\xec\x93\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec94[] = {
+ "\xec\x94\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec95[] = {
+ "\xec\x95\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec96[] = {
+ "\xec\x96\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec97[] = {
+ "\xec\x97\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec98[] = {
+ "\xec\x98\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec99[] = {
+ "\xec\x99\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec9a[] = {
+ "\xec\x9a\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec9b[] = {
+ "\xec\x9b\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec9c[] = {
+ "\xec\x9c\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec9d[] = {
+ "\xec\x9d\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec9e[] = {
+ "\xec\x9e\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ec9f[] = {
+ "\xec\x9f\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca0[] = {
+ "\xec\xa0\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca1[] = {
+ "\xec\xa1\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca2[] = {
+ "\xec\xa2\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca3[] = {
+ "\xec\xa3\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca4[] = {
+ "\xec\xa4\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca5[] = {
+ "\xec\xa5\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca6[] = {
+ "\xec\xa6\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca7[] = {
+ "\xec\xa7\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca8[] = {
+ "\xec\xa8\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_eca9[] = {
+ "\xec\xa9\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecaa[] = {
+ "\xec\xaa\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecab[] = {
+ "\xec\xab\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecac[] = {
+ "\xec\xac\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecad[] = {
+ "\xec\xad\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecae[] = {
+ "\xec\xae\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecaf[] = {
+ "\xec\xaf\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb0[] = {
+ "\xec\xb0\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb1[] = {
+ "\xec\xb1\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb2[] = {
+ "\xec\xb2\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb3[] = {
+ "\xec\xb3\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb4[] = {
+ "\xec\xb4\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb5[] = {
+ "\xec\xb5\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb6[] = {
+ "\xec\xb6\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb7[] = {
+ "\xec\xb7\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb8[] = {
+ "\xec\xb8\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecb9[] = {
+ "\xec\xb9\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecba[] = {
+ "\xec\xba\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecbb[] = {
+ "\xec\xbb\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecbc[] = {
+ "\xec\xbc\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecbd[] = {
+ "\xec\xbd\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecbe[] = {
+ "\xec\xbe\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ecbf[] = {
+ "\xec\xbf\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed80[] = {
+ "\xed\x80\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed81[] = {
+ "\xed\x81\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed82[] = {
+ "\xed\x82\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed83[] = {
+ "\xed\x83\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed84[] = {
+ "\xed\x84\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed85[] = {
+ "\xed\x85\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed86[] = {
+ "\xed\x86\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed87[] = {
+ "\xed\x87\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed88[] = {
+ "\xed\x88\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed89[] = {
+ "\xed\x89\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed8a[] = {
+ "\xed\x8a\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed8b[] = {
+ "\xed\x8b\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed8c[] = {
+ "\xed\x8c\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed8d[] = {
+ "\xed\x8d\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed8e[] = {
+ "\xed\x8e\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed8f[] = {
+ "\xed\x8f\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed90[] = {
+ "\xed\x90\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed91[] = {
+ "\xed\x91\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed92[] = {
+ "\xed\x92\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed93[] = {
+ "\xed\x93\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed94[] = {
+ "\xed\x94\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed95[] = {
+ "\xed\x95\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed96[] = {
+ "\xed\x96\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed97[] = {
+ "\xed\x97\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb2"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed98[] = {
+ "\xed\x98\x8e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xaa", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed99[] = {
+ "\xed\x99\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed9a[] = {
+ "\xed\x9a\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed9b[] = {
+ "\xed\x9b\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed9c[] = {
+ "\xed\x9c\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b5_table_ed9d[] = {
+ "\xed\x9d\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xba"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b5(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b5_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x96";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab0[] = {
+ "\xea\xb0\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab1[] = {
+ "\xea\xb1\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb1\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab2[] = {
+ "\xea\xb2\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab3[] = {
+ "\xea\xb3\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab4[] = {
+ "\xea\xb4\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab5[] = {
+ "\xea\xb5\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab6[] = {
+ "\xea\xb6\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab7[] = {
+ "\xea\xb7\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab8[] = {
+ "\xea\xb8\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb8\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eab9[] = {
+ "\xea\xb9\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eaba[] = {
+ "\xea\xba\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eabb[] = {
+ "\xea\xbb\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eabc[] = {
+ "\xea\xbc\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eabd[] = {
+ "\xea\xbd\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eabe[] = {
+ "\xea\xbe\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eabf[] = {
+ "\xea\xbf\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbf\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb80[] = {
+ "\xeb\x80\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb81[] = {
+ "\xeb\x81\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb82[] = {
+ "\xeb\x82\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb83[] = {
+ "\xeb\x83\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb84[] = {
+ "\xeb\x84\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb85[] = {
+ "\xeb\x85\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb86[] = {
+ "\xeb\x86\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x86\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb87[] = {
+ "\xeb\x87\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb88[] = {
+ "\xeb\x88\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb89[] = {
+ "\xeb\x89\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb8a[] = {
+ "\xeb\x8a\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb8b[] = {
+ "\xeb\x8b\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb8c[] = {
+ "\xeb\x8c\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb8d[] = {
+ "\xeb\x8d\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8d\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb8e[] = {
+ "\xeb\x8e\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb8f[] = {
+ "\xeb\x8f\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb90[] = {
+ "\xeb\x90\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb91[] = {
+ "\xeb\x91\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb92[] = {
+ "\xeb\x92\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb93[] = {
+ "\xeb\x93\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb94[] = {
+ "\xeb\x94\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x94\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb95[] = {
+ "\xeb\x95\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb96[] = {
+ "\xeb\x96\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb97[] = {
+ "\xeb\x97\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb98[] = {
+ "\xeb\x98\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb99[] = {
+ "\xeb\x99\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb9a[] = {
+ "\xeb\x9a\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb9b[] = {
+ "\xeb\x9b\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9b\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb9c[] = {
+ "\xeb\x9c\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb9d[] = {
+ "\xeb\x9d\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb9e[] = {
+ "\xeb\x9e\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eb9f[] = {
+ "\xeb\x9f\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba0[] = {
+ "\xeb\xa0\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba1[] = {
+ "\xeb\xa1\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba2[] = {
+ "\xeb\xa2\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa2\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba3[] = {
+ "\xeb\xa3\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba4[] = {
+ "\xeb\xa4\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba5[] = {
+ "\xeb\xa5\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba6[] = {
+ "\xeb\xa6\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba7[] = {
+ "\xeb\xa7\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba8[] = {
+ "\xeb\xa8\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eba9[] = {
+ "\xeb\xa9\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa9\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebaa[] = {
+ "\xeb\xaa\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebab[] = {
+ "\xeb\xab\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebac[] = {
+ "\xeb\xac\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebad[] = {
+ "\xeb\xad\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebae[] = {
+ "\xeb\xae\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebaf[] = {
+ "\xeb\xaf\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb0[] = {
+ "\xeb\xb0\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb0\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb1[] = {
+ "\xeb\xb1\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb2[] = {
+ "\xeb\xb2\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb3[] = {
+ "\xeb\xb3\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb4[] = {
+ "\xeb\xb4\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb5[] = {
+ "\xeb\xb5\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb6[] = {
+ "\xeb\xb6\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb7[] = {
+ "\xeb\xb7\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb7\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb8[] = {
+ "\xeb\xb8\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebb9[] = {
+ "\xeb\xb9\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebba[] = {
+ "\xeb\xba\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebbb[] = {
+ "\xeb\xbb\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebbc[] = {
+ "\xeb\xbc\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebbd[] = {
+ "\xeb\xbd\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebbe[] = {
+ "\xeb\xbe\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbe\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ebbf[] = {
+ "\xeb\xbf\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec80[] = {
+ "\xec\x80\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec81[] = {
+ "\xec\x81\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec82[] = {
+ "\xec\x82\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec83[] = {
+ "\xec\x83\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec84[] = {
+ "\xec\x84\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec85[] = {
+ "\xec\x85\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x85\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec86[] = {
+ "\xec\x86\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec87[] = {
+ "\xec\x87\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec88[] = {
+ "\xec\x88\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec89[] = {
+ "\xec\x89\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec8a[] = {
+ "\xec\x8a\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec8b[] = {
+ "\xec\x8b\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec8c[] = {
+ "\xec\x8c\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8c\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec8d[] = {
+ "\xec\x8d\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec8e[] = {
+ "\xec\x8e\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec8f[] = {
+ "\xec\x8f\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec90[] = {
+ "\xec\x90\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec91[] = {
+ "\xec\x91\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec92[] = {
+ "\xec\x92\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec93[] = {
+ "\xec\x93\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x93\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec94[] = {
+ "\xec\x94\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec95[] = {
+ "\xec\x95\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec96[] = {
+ "\xec\x96\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec97[] = {
+ "\xec\x97\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec98[] = {
+ "\xec\x98\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec99[] = {
+ "\xec\x99\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec9a[] = {
+ "\xec\x9a\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9a\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec9b[] = {
+ "\xec\x9b\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec9c[] = {
+ "\xec\x9c\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec9d[] = {
+ "\xec\x9d\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec9e[] = {
+ "\xec\x9e\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ec9f[] = {
+ "\xec\x9f\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca0[] = {
+ "\xec\xa0\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca1[] = {
+ "\xec\xa1\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa1\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca2[] = {
+ "\xec\xa2\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca3[] = {
+ "\xec\xa3\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca4[] = {
+ "\xec\xa4\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca5[] = {
+ "\xec\xa5\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca6[] = {
+ "\xec\xa6\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca7[] = {
+ "\xec\xa7\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca8[] = {
+ "\xec\xa8\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa8\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_eca9[] = {
+ "\xec\xa9\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecaa[] = {
+ "\xec\xaa\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecab[] = {
+ "\xec\xab\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecac[] = {
+ "\xec\xac\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecad[] = {
+ "\xec\xad\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecae[] = {
+ "\xec\xae\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecaf[] = {
+ "\xec\xaf\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaf\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb0[] = {
+ "\xec\xb0\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb1[] = {
+ "\xec\xb1\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb2[] = {
+ "\xec\xb2\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb3[] = {
+ "\xec\xb3\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb4[] = {
+ "\xec\xb4\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb5[] = {
+ "\xec\xb5\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb6[] = {
+ "\xec\xb6\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb6\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb7[] = {
+ "\xec\xb7\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb8[] = {
+ "\xec\xb8\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecb9[] = {
+ "\xec\xb9\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecba[] = {
+ "\xec\xba\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecbb[] = {
+ "\xec\xbb\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecbc[] = {
+ "\xec\xbc\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecbd[] = {
+ "\xec\xbd\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbd\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecbe[] = {
+ "\xec\xbe\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ecbf[] = {
+ "\xec\xbf\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed80[] = {
+ "\xed\x80\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed81[] = {
+ "\xed\x81\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed82[] = {
+ "\xed\x82\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed83[] = {
+ "\xed\x83\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed84[] = {
+ "\xed\x84\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x84\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed85[] = {
+ "\xed\x85\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed86[] = {
+ "\xed\x86\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed87[] = {
+ "\xed\x87\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed88[] = {
+ "\xed\x88\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed89[] = {
+ "\xed\x89\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed8a[] = {
+ "\xed\x8a\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed8b[] = {
+ "\xed\x8b\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8b\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed8c[] = {
+ "\xed\x8c\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed8d[] = {
+ "\xed\x8d\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed8e[] = {
+ "\xed\x8e\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed8f[] = {
+ "\xed\x8f\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed90[] = {
+ "\xed\x90\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed91[] = {
+ "\xed\x91\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed92[] = {
+ "\xed\x92\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x92\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed93[] = {
+ "\xed\x93\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed94[] = {
+ "\xed\x94\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed95[] = {
+ "\xed\x95\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed96[] = {
+ "\xed\x96\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed97[] = {
+ "\xed\x97\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb3"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed98[] = {
+ "\xed\x98\x8f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xab", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed99[] = {
+ "\xed\x99\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x99\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed9a[] = {
+ "\xed\x9a\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed9b[] = {
+ "\xed\x9b\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed9c[] = {
+ "\xed\x9c\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b6_table_ed9d[] = {
+ "\xed\x9d\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xbb"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b6(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b6_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x97";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab0[] = {
+ "\xea\xb0\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab1[] = {
+ "\xea\xb1\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab2[] = {
+ "\xea\xb2\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab3[] = {
+ "\xea\xb3\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab4[] = {
+ "\xea\xb4\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab5[] = {
+ "\xea\xb5\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab6[] = {
+ "\xea\xb6\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab7[] = {
+ "\xea\xb7\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab8[] = {
+ "\xea\xb8\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eab9[] = {
+ "\xea\xb9\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eaba[] = {
+ "\xea\xba\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eabb[] = {
+ "\xea\xbb\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eabc[] = {
+ "\xea\xbc\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eabd[] = {
+ "\xea\xbd\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eabe[] = {
+ "\xea\xbe\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eabf[] = {
+ "\xea\xbf\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb80[] = {
+ "\xeb\x80\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb81[] = {
+ "\xeb\x81\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb82[] = {
+ "\xeb\x82\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb83[] = {
+ "\xeb\x83\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb84[] = {
+ "\xeb\x84\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb85[] = {
+ "\xeb\x85\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb86[] = {
+ "\xeb\x86\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb87[] = {
+ "\xeb\x87\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb88[] = {
+ "\xeb\x88\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb89[] = {
+ "\xeb\x89\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb8a[] = {
+ "\xeb\x8a\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb8b[] = {
+ "\xeb\x8b\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb8c[] = {
+ "\xeb\x8c\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb8d[] = {
+ "\xeb\x8d\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb8e[] = {
+ "\xeb\x8e\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb8f[] = {
+ "\xeb\x8f\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb90[] = {
+ "\xeb\x90\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb91[] = {
+ "\xeb\x91\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb92[] = {
+ "\xeb\x92\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb93[] = {
+ "\xeb\x93\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb94[] = {
+ "\xeb\x94\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb95[] = {
+ "\xeb\x95\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb96[] = {
+ "\xeb\x96\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb97[] = {
+ "\xeb\x97\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb98[] = {
+ "\xeb\x98\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb99[] = {
+ "\xeb\x99\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb9a[] = {
+ "\xeb\x9a\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb9b[] = {
+ "\xeb\x9b\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb9c[] = {
+ "\xeb\x9c\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb9d[] = {
+ "\xeb\x9d\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb9e[] = {
+ "\xeb\x9e\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eb9f[] = {
+ "\xeb\x9f\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba0[] = {
+ "\xeb\xa0\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba1[] = {
+ "\xeb\xa1\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba2[] = {
+ "\xeb\xa2\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba3[] = {
+ "\xeb\xa3\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba4[] = {
+ "\xeb\xa4\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba5[] = {
+ "\xeb\xa5\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba6[] = {
+ "\xeb\xa6\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba7[] = {
+ "\xeb\xa7\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba8[] = {
+ "\xeb\xa8\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eba9[] = {
+ "\xeb\xa9\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebaa[] = {
+ "\xeb\xaa\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebab[] = {
+ "\xeb\xab\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebac[] = {
+ "\xeb\xac\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebad[] = {
+ "\xeb\xad\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebae[] = {
+ "\xeb\xae\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebaf[] = {
+ "\xeb\xaf\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb0[] = {
+ "\xeb\xb0\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb1[] = {
+ "\xeb\xb1\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb2[] = {
+ "\xeb\xb2\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb3[] = {
+ "\xeb\xb3\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb4[] = {
+ "\xeb\xb4\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb5[] = {
+ "\xeb\xb5\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb6[] = {
+ "\xeb\xb6\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb7[] = {
+ "\xeb\xb7\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb8[] = {
+ "\xeb\xb8\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebb9[] = {
+ "\xeb\xb9\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebba[] = {
+ "\xeb\xba\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebbb[] = {
+ "\xeb\xbb\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebbc[] = {
+ "\xeb\xbc\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebbd[] = {
+ "\xeb\xbd\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebbe[] = {
+ "\xeb\xbe\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ebbf[] = {
+ "\xeb\xbf\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec80[] = {
+ "\xec\x80\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec81[] = {
+ "\xec\x81\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec82[] = {
+ "\xec\x82\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec83[] = {
+ "\xec\x83\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec84[] = {
+ "\xec\x84\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec85[] = {
+ "\xec\x85\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec86[] = {
+ "\xec\x86\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec87[] = {
+ "\xec\x87\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec88[] = {
+ "\xec\x88\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec89[] = {
+ "\xec\x89\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec8a[] = {
+ "\xec\x8a\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec8b[] = {
+ "\xec\x8b\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec8c[] = {
+ "\xec\x8c\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec8d[] = {
+ "\xec\x8d\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec8e[] = {
+ "\xec\x8e\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec8f[] = {
+ "\xec\x8f\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec90[] = {
+ "\xec\x90\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec91[] = {
+ "\xec\x91\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec92[] = {
+ "\xec\x92\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec93[] = {
+ "\xec\x93\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec94[] = {
+ "\xec\x94\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec95[] = {
+ "\xec\x95\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec96[] = {
+ "\xec\x96\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec97[] = {
+ "\xec\x97\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec98[] = {
+ "\xec\x98\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec99[] = {
+ "\xec\x99\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec9a[] = {
+ "\xec\x9a\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec9b[] = {
+ "\xec\x9b\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec9c[] = {
+ "\xec\x9c\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec9d[] = {
+ "\xec\x9d\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec9e[] = {
+ "\xec\x9e\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ec9f[] = {
+ "\xec\x9f\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca0[] = {
+ "\xec\xa0\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca1[] = {
+ "\xec\xa1\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca2[] = {
+ "\xec\xa2\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca3[] = {
+ "\xec\xa3\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca4[] = {
+ "\xec\xa4\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca5[] = {
+ "\xec\xa5\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca6[] = {
+ "\xec\xa6\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca7[] = {
+ "\xec\xa7\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca8[] = {
+ "\xec\xa8\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_eca9[] = {
+ "\xec\xa9\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecaa[] = {
+ "\xec\xaa\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecab[] = {
+ "\xec\xab\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecac[] = {
+ "\xec\xac\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecad[] = {
+ "\xec\xad\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecae[] = {
+ "\xec\xae\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecaf[] = {
+ "\xec\xaf\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb0[] = {
+ "\xec\xb0\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb1[] = {
+ "\xec\xb1\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb2[] = {
+ "\xec\xb2\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb3[] = {
+ "\xec\xb3\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb4[] = {
+ "\xec\xb4\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb5[] = {
+ "\xec\xb5\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb6[] = {
+ "\xec\xb6\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb7[] = {
+ "\xec\xb7\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb8[] = {
+ "\xec\xb8\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecb9[] = {
+ "\xec\xb9\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecba[] = {
+ "\xec\xba\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecbb[] = {
+ "\xec\xbb\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecbc[] = {
+ "\xec\xbc\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecbd[] = {
+ "\xec\xbd\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecbe[] = {
+ "\xec\xbe\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ecbf[] = {
+ "\xec\xbf\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed80[] = {
+ "\xed\x80\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed81[] = {
+ "\xed\x81\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed82[] = {
+ "\xed\x82\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed83[] = {
+ "\xed\x83\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed84[] = {
+ "\xed\x84\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed85[] = {
+ "\xed\x85\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed86[] = {
+ "\xed\x86\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed87[] = {
+ "\xed\x87\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed88[] = {
+ "\xed\x88\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed89[] = {
+ "\xed\x89\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed8a[] = {
+ "\xed\x8a\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed8b[] = {
+ "\xed\x8b\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed8c[] = {
+ "\xed\x8c\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed8d[] = {
+ "\xed\x8d\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed8e[] = {
+ "\xed\x8e\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed8f[] = {
+ "\xed\x8f\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed90[] = {
+ "\xed\x90\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed91[] = {
+ "\xed\x91\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed92[] = {
+ "\xed\x92\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed93[] = {
+ "\xed\x93\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed94[] = {
+ "\xed\x94\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed95[] = {
+ "\xed\x95\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed96[] = {
+ "\xed\x96\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed97[] = {
+ "\xed\x97\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb4"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed98[] = {
+ "\xed\x98\x90", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xac", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed99[] = {
+ "\xed\x99\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed9a[] = {
+ "\xed\x9a\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed9b[] = {
+ "\xed\x9b\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed9c[] = {
+ "\xed\x9c\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b7_table_ed9d[] = {
+ "\xed\x9d\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xbc"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b7(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b7_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x98";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab0[] = {
+ "\xea\xb0\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab1[] = {
+ "\xea\xb1\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab2[] = {
+ "\xea\xb2\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab3[] = {
+ "\xea\xb3\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab4[] = {
+ "\xea\xb4\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab5[] = {
+ "\xea\xb5\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab6[] = {
+ "\xea\xb6\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab7[] = {
+ "\xea\xb7\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab8[] = {
+ "\xea\xb8\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eab9[] = {
+ "\xea\xb9\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eaba[] = {
+ "\xea\xba\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eabb[] = {
+ "\xea\xbb\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eabc[] = {
+ "\xea\xbc\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eabd[] = {
+ "\xea\xbd\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eabe[] = {
+ "\xea\xbe\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eabf[] = {
+ "\xea\xbf\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb80[] = {
+ "\xeb\x80\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb81[] = {
+ "\xeb\x81\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb82[] = {
+ "\xeb\x82\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb83[] = {
+ "\xeb\x83\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb84[] = {
+ "\xeb\x84\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb85[] = {
+ "\xeb\x85\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb86[] = {
+ "\xeb\x86\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb87[] = {
+ "\xeb\x87\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb88[] = {
+ "\xeb\x88\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb89[] = {
+ "\xeb\x89\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb8a[] = {
+ "\xeb\x8a\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb8b[] = {
+ "\xeb\x8b\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb8c[] = {
+ "\xeb\x8c\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb8d[] = {
+ "\xeb\x8d\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb8e[] = {
+ "\xeb\x8e\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb8f[] = {
+ "\xeb\x8f\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb90[] = {
+ "\xeb\x90\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb91[] = {
+ "\xeb\x91\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb92[] = {
+ "\xeb\x92\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb93[] = {
+ "\xeb\x93\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb94[] = {
+ "\xeb\x94\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb95[] = {
+ "\xeb\x95\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb96[] = {
+ "\xeb\x96\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb97[] = {
+ "\xeb\x97\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb98[] = {
+ "\xeb\x98\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb99[] = {
+ "\xeb\x99\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb9a[] = {
+ "\xeb\x9a\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb9b[] = {
+ "\xeb\x9b\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb9c[] = {
+ "\xeb\x9c\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb9d[] = {
+ "\xeb\x9d\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb9e[] = {
+ "\xeb\x9e\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eb9f[] = {
+ "\xeb\x9f\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba0[] = {
+ "\xeb\xa0\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba1[] = {
+ "\xeb\xa1\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba2[] = {
+ "\xeb\xa2\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba3[] = {
+ "\xeb\xa3\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba4[] = {
+ "\xeb\xa4\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba5[] = {
+ "\xeb\xa5\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba6[] = {
+ "\xeb\xa6\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba7[] = {
+ "\xeb\xa7\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba8[] = {
+ "\xeb\xa8\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eba9[] = {
+ "\xeb\xa9\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebaa[] = {
+ "\xeb\xaa\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebab[] = {
+ "\xeb\xab\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebac[] = {
+ "\xeb\xac\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebad[] = {
+ "\xeb\xad\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebae[] = {
+ "\xeb\xae\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebaf[] = {
+ "\xeb\xaf\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb0[] = {
+ "\xeb\xb0\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb1[] = {
+ "\xeb\xb1\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb2[] = {
+ "\xeb\xb2\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb3[] = {
+ "\xeb\xb3\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb4[] = {
+ "\xeb\xb4\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb5[] = {
+ "\xeb\xb5\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb6[] = {
+ "\xeb\xb6\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb7[] = {
+ "\xeb\xb7\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb8[] = {
+ "\xeb\xb8\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebb9[] = {
+ "\xeb\xb9\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebba[] = {
+ "\xeb\xba\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebbb[] = {
+ "\xeb\xbb\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebbc[] = {
+ "\xeb\xbc\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebbd[] = {
+ "\xeb\xbd\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebbe[] = {
+ "\xeb\xbe\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ebbf[] = {
+ "\xeb\xbf\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec80[] = {
+ "\xec\x80\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec81[] = {
+ "\xec\x81\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec82[] = {
+ "\xec\x82\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec83[] = {
+ "\xec\x83\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec84[] = {
+ "\xec\x84\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec85[] = {
+ "\xec\x85\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec86[] = {
+ "\xec\x86\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec87[] = {
+ "\xec\x87\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec88[] = {
+ "\xec\x88\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec89[] = {
+ "\xec\x89\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec8a[] = {
+ "\xec\x8a\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec8b[] = {
+ "\xec\x8b\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec8c[] = {
+ "\xec\x8c\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec8d[] = {
+ "\xec\x8d\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec8e[] = {
+ "\xec\x8e\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec8f[] = {
+ "\xec\x8f\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec90[] = {
+ "\xec\x90\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec91[] = {
+ "\xec\x91\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec92[] = {
+ "\xec\x92\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec93[] = {
+ "\xec\x93\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec94[] = {
+ "\xec\x94\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec95[] = {
+ "\xec\x95\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec96[] = {
+ "\xec\x96\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec97[] = {
+ "\xec\x97\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec98[] = {
+ "\xec\x98\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec99[] = {
+ "\xec\x99\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec9a[] = {
+ "\xec\x9a\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec9b[] = {
+ "\xec\x9b\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec9c[] = {
+ "\xec\x9c\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec9d[] = {
+ "\xec\x9d\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec9e[] = {
+ "\xec\x9e\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ec9f[] = {
+ "\xec\x9f\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca0[] = {
+ "\xec\xa0\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca1[] = {
+ "\xec\xa1\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca2[] = {
+ "\xec\xa2\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca3[] = {
+ "\xec\xa3\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca4[] = {
+ "\xec\xa4\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca5[] = {
+ "\xec\xa5\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca6[] = {
+ "\xec\xa6\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca7[] = {
+ "\xec\xa7\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca8[] = {
+ "\xec\xa8\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_eca9[] = {
+ "\xec\xa9\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecaa[] = {
+ "\xec\xaa\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecab[] = {
+ "\xec\xab\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecac[] = {
+ "\xec\xac\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecad[] = {
+ "\xec\xad\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecae[] = {
+ "\xec\xae\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecaf[] = {
+ "\xec\xaf\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb0[] = {
+ "\xec\xb0\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb1[] = {
+ "\xec\xb1\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb2[] = {
+ "\xec\xb2\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb3[] = {
+ "\xec\xb3\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb4[] = {
+ "\xec\xb4\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb5[] = {
+ "\xec\xb5\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb6[] = {
+ "\xec\xb6\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb7[] = {
+ "\xec\xb7\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb8[] = {
+ "\xec\xb8\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecb9[] = {
+ "\xec\xb9\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecba[] = {
+ "\xec\xba\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecbb[] = {
+ "\xec\xbb\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecbc[] = {
+ "\xec\xbc\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecbd[] = {
+ "\xec\xbd\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecbe[] = {
+ "\xec\xbe\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ecbf[] = {
+ "\xec\xbf\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed80[] = {
+ "\xed\x80\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed81[] = {
+ "\xed\x81\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed82[] = {
+ "\xed\x82\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed83[] = {
+ "\xed\x83\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed84[] = {
+ "\xed\x84\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed85[] = {
+ "\xed\x85\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed86[] = {
+ "\xed\x86\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed87[] = {
+ "\xed\x87\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed88[] = {
+ "\xed\x88\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed89[] = {
+ "\xed\x89\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed8a[] = {
+ "\xed\x8a\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed8b[] = {
+ "\xed\x8b\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed8c[] = {
+ "\xed\x8c\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed8d[] = {
+ "\xed\x8d\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed8e[] = {
+ "\xed\x8e\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed8f[] = {
+ "\xed\x8f\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed90[] = {
+ "\xed\x90\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed91[] = {
+ "\xed\x91\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed92[] = {
+ "\xed\x92\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed93[] = {
+ "\xed\x93\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed94[] = {
+ "\xed\x94\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed95[] = {
+ "\xed\x95\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed96[] = {
+ "\xed\x96\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed97[] = {
+ "\xed\x97\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb5"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed98[] = {
+ "\xed\x98\x91", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xad", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed99[] = {
+ "\xed\x99\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed9a[] = {
+ "\xed\x9a\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed9b[] = {
+ "\xed\x9b\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed9c[] = {
+ "\xed\x9c\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b8_table_ed9d[] = {
+ "\xed\x9d\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xbd"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b8(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b8_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x99";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab0[] = {
+ "\xea\xb0\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab1[] = {
+ "\xea\xb1\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab2[] = {
+ "\xea\xb2\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab3[] = {
+ "\xea\xb3\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab4[] = {
+ "\xea\xb4\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab5[] = {
+ "\xea\xb5\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab6[] = {
+ "\xea\xb6\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab7[] = {
+ "\xea\xb7\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab8[] = {
+ "\xea\xb8\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eab9[] = {
+ "\xea\xb9\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eaba[] = {
+ "\xea\xba\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eabb[] = {
+ "\xea\xbb\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eabc[] = {
+ "\xea\xbc\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eabd[] = {
+ "\xea\xbd\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eabe[] = {
+ "\xea\xbe\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eabf[] = {
+ "\xea\xbf\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb80[] = {
+ "\xeb\x80\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb81[] = {
+ "\xeb\x81\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb82[] = {
+ "\xeb\x82\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb83[] = {
+ "\xeb\x83\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb84[] = {
+ "\xeb\x84\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb85[] = {
+ "\xeb\x85\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb86[] = {
+ "\xeb\x86\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb87[] = {
+ "\xeb\x87\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb88[] = {
+ "\xeb\x88\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb89[] = {
+ "\xeb\x89\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb8a[] = {
+ "\xeb\x8a\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb8b[] = {
+ "\xeb\x8b\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb8c[] = {
+ "\xeb\x8c\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb8d[] = {
+ "\xeb\x8d\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb8e[] = {
+ "\xeb\x8e\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb8f[] = {
+ "\xeb\x8f\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb90[] = {
+ "\xeb\x90\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb91[] = {
+ "\xeb\x91\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb92[] = {
+ "\xeb\x92\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb93[] = {
+ "\xeb\x93\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb94[] = {
+ "\xeb\x94\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb95[] = {
+ "\xeb\x95\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb96[] = {
+ "\xeb\x96\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb97[] = {
+ "\xeb\x97\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb98[] = {
+ "\xeb\x98\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb99[] = {
+ "\xeb\x99\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb9a[] = {
+ "\xeb\x9a\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb9b[] = {
+ "\xeb\x9b\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb9c[] = {
+ "\xeb\x9c\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb9d[] = {
+ "\xeb\x9d\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb9e[] = {
+ "\xeb\x9e\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eb9f[] = {
+ "\xeb\x9f\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba0[] = {
+ "\xeb\xa0\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba1[] = {
+ "\xeb\xa1\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba2[] = {
+ "\xeb\xa2\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba3[] = {
+ "\xeb\xa3\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba4[] = {
+ "\xeb\xa4\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba5[] = {
+ "\xeb\xa5\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba6[] = {
+ "\xeb\xa6\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba7[] = {
+ "\xeb\xa7\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba8[] = {
+ "\xeb\xa8\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eba9[] = {
+ "\xeb\xa9\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebaa[] = {
+ "\xeb\xaa\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebab[] = {
+ "\xeb\xab\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebac[] = {
+ "\xeb\xac\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebad[] = {
+ "\xeb\xad\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebae[] = {
+ "\xeb\xae\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebaf[] = {
+ "\xeb\xaf\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb0[] = {
+ "\xeb\xb0\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb1[] = {
+ "\xeb\xb1\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb2[] = {
+ "\xeb\xb2\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb3[] = {
+ "\xeb\xb3\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb4[] = {
+ "\xeb\xb4\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb5[] = {
+ "\xeb\xb5\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb6[] = {
+ "\xeb\xb6\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb7[] = {
+ "\xeb\xb7\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb8[] = {
+ "\xeb\xb8\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebb9[] = {
+ "\xeb\xb9\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebba[] = {
+ "\xeb\xba\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebbb[] = {
+ "\xeb\xbb\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebbc[] = {
+ "\xeb\xbc\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebbd[] = {
+ "\xeb\xbd\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebbe[] = {
+ "\xeb\xbe\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ebbf[] = {
+ "\xeb\xbf\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec80[] = {
+ "\xec\x80\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec81[] = {
+ "\xec\x81\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec82[] = {
+ "\xec\x82\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec83[] = {
+ "\xec\x83\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec84[] = {
+ "\xec\x84\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec85[] = {
+ "\xec\x85\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec86[] = {
+ "\xec\x86\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec87[] = {
+ "\xec\x87\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec88[] = {
+ "\xec\x88\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec89[] = {
+ "\xec\x89\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec8a[] = {
+ "\xec\x8a\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec8b[] = {
+ "\xec\x8b\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec8c[] = {
+ "\xec\x8c\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec8d[] = {
+ "\xec\x8d\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec8e[] = {
+ "\xec\x8e\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec8f[] = {
+ "\xec\x8f\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec90[] = {
+ "\xec\x90\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec91[] = {
+ "\xec\x91\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec92[] = {
+ "\xec\x92\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec93[] = {
+ "\xec\x93\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec94[] = {
+ "\xec\x94\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec95[] = {
+ "\xec\x95\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec96[] = {
+ "\xec\x96\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec97[] = {
+ "\xec\x97\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec98[] = {
+ "\xec\x98\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec99[] = {
+ "\xec\x99\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec9a[] = {
+ "\xec\x9a\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec9b[] = {
+ "\xec\x9b\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec9c[] = {
+ "\xec\x9c\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec9d[] = {
+ "\xec\x9d\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec9e[] = {
+ "\xec\x9e\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ec9f[] = {
+ "\xec\x9f\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca0[] = {
+ "\xec\xa0\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca1[] = {
+ "\xec\xa1\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca2[] = {
+ "\xec\xa2\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca3[] = {
+ "\xec\xa3\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca4[] = {
+ "\xec\xa4\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca5[] = {
+ "\xec\xa5\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca6[] = {
+ "\xec\xa6\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca7[] = {
+ "\xec\xa7\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca8[] = {
+ "\xec\xa8\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_eca9[] = {
+ "\xec\xa9\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecaa[] = {
+ "\xec\xaa\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecab[] = {
+ "\xec\xab\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecac[] = {
+ "\xec\xac\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecad[] = {
+ "\xec\xad\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecae[] = {
+ "\xec\xae\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecaf[] = {
+ "\xec\xaf\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb0[] = {
+ "\xec\xb0\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb1[] = {
+ "\xec\xb1\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb2[] = {
+ "\xec\xb2\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb3[] = {
+ "\xec\xb3\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb4[] = {
+ "\xec\xb4\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb5[] = {
+ "\xec\xb5\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb6[] = {
+ "\xec\xb6\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb7[] = {
+ "\xec\xb7\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb8[] = {
+ "\xec\xb8\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecb9[] = {
+ "\xec\xb9\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecba[] = {
+ "\xec\xba\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecbb[] = {
+ "\xec\xbb\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecbc[] = {
+ "\xec\xbc\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecbd[] = {
+ "\xec\xbd\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecbe[] = {
+ "\xec\xbe\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ecbf[] = {
+ "\xec\xbf\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed80[] = {
+ "\xed\x80\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed81[] = {
+ "\xed\x81\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed82[] = {
+ "\xed\x82\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed83[] = {
+ "\xed\x83\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed84[] = {
+ "\xed\x84\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed85[] = {
+ "\xed\x85\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed86[] = {
+ "\xed\x86\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed87[] = {
+ "\xed\x87\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed88[] = {
+ "\xed\x88\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed89[] = {
+ "\xed\x89\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed8a[] = {
+ "\xed\x8a\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed8b[] = {
+ "\xed\x8b\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed8c[] = {
+ "\xed\x8c\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed8d[] = {
+ "\xed\x8d\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed8e[] = {
+ "\xed\x8e\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed8f[] = {
+ "\xed\x8f\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed90[] = {
+ "\xed\x90\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed91[] = {
+ "\xed\x91\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed92[] = {
+ "\xed\x92\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed93[] = {
+ "\xed\x93\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed94[] = {
+ "\xed\x94\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed95[] = {
+ "\xed\x95\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed96[] = {
+ "\xed\x96\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed97[] = {
+ "\xed\x97\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb6"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed98[] = {
+ "\xed\x98\x92", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xae", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed99[] = {
+ "\xed\x99\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed9a[] = {
+ "\xed\x9a\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed9b[] = {
+ "\xed\x9b\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed9c[] = {
+ "\xed\x9c\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186b9_table_ed9d[] = {
+ "\xed\x9d\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xbe"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186b9(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186b9_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x9a";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab0[] = {
+ "\xea\xb0\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab1[] = {
+ "\xea\xb1\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab2[] = {
+ "\xea\xb2\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab3[] = {
+ "\xea\xb3\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab4[] = {
+ "\xea\xb4\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab5[] = {
+ "\xea\xb5\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab6[] = {
+ "\xea\xb6\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab7[] = {
+ "\xea\xb7\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab8[] = {
+ "\xea\xb8\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eab9[] = {
+ "\xea\xb9\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eaba[] = {
+ "\xea\xba\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eabb[] = {
+ "\xea\xbb\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eabc[] = {
+ "\xea\xbc\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eabd[] = {
+ "\xea\xbd\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eabe[] = {
+ "\xea\xbe\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eabf[] = {
+ "\xea\xbf\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb80[] = {
+ "\xeb\x80\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb81[] = {
+ "\xeb\x81\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb82[] = {
+ "\xeb\x82\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb83[] = {
+ "\xeb\x83\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb84[] = {
+ "\xeb\x84\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb85[] = {
+ "\xeb\x85\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb86[] = {
+ "\xeb\x86\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb87[] = {
+ "\xeb\x87\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb88[] = {
+ "\xeb\x88\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb89[] = {
+ "\xeb\x89\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb8a[] = {
+ "\xeb\x8a\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb8b[] = {
+ "\xeb\x8b\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb8c[] = {
+ "\xeb\x8c\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb8d[] = {
+ "\xeb\x8d\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb8e[] = {
+ "\xeb\x8e\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb8f[] = {
+ "\xeb\x8f\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb90[] = {
+ "\xeb\x90\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb91[] = {
+ "\xeb\x91\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb92[] = {
+ "\xeb\x92\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb93[] = {
+ "\xeb\x93\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb94[] = {
+ "\xeb\x94\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb95[] = {
+ "\xeb\x95\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb96[] = {
+ "\xeb\x96\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb97[] = {
+ "\xeb\x97\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb98[] = {
+ "\xeb\x98\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb99[] = {
+ "\xeb\x99\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb9a[] = {
+ "\xeb\x9a\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb9b[] = {
+ "\xeb\x9b\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb9c[] = {
+ "\xeb\x9c\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb9d[] = {
+ "\xeb\x9d\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb9e[] = {
+ "\xeb\x9e\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eb9f[] = {
+ "\xeb\x9f\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba0[] = {
+ "\xeb\xa0\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba1[] = {
+ "\xeb\xa1\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba2[] = {
+ "\xeb\xa2\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba3[] = {
+ "\xeb\xa3\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba4[] = {
+ "\xeb\xa4\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba5[] = {
+ "\xeb\xa5\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba6[] = {
+ "\xeb\xa6\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba7[] = {
+ "\xeb\xa7\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba8[] = {
+ "\xeb\xa8\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eba9[] = {
+ "\xeb\xa9\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebaa[] = {
+ "\xeb\xaa\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebab[] = {
+ "\xeb\xab\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebac[] = {
+ "\xeb\xac\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebad[] = {
+ "\xeb\xad\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebae[] = {
+ "\xeb\xae\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebaf[] = {
+ "\xeb\xaf\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb0[] = {
+ "\xeb\xb0\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb1[] = {
+ "\xeb\xb1\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb2[] = {
+ "\xeb\xb2\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb3[] = {
+ "\xeb\xb3\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb4[] = {
+ "\xeb\xb4\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb5[] = {
+ "\xeb\xb5\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb6[] = {
+ "\xeb\xb6\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb7[] = {
+ "\xeb\xb7\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb8[] = {
+ "\xeb\xb8\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebb9[] = {
+ "\xeb\xb9\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebba[] = {
+ "\xeb\xba\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebbb[] = {
+ "\xeb\xbb\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebbc[] = {
+ "\xeb\xbc\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebbd[] = {
+ "\xeb\xbd\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebbe[] = {
+ "\xeb\xbe\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ebbf[] = {
+ "\xeb\xbf\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec80[] = {
+ "\xec\x80\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec81[] = {
+ "\xec\x81\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec82[] = {
+ "\xec\x82\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec83[] = {
+ "\xec\x83\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec84[] = {
+ "\xec\x84\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec85[] = {
+ "\xec\x85\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec86[] = {
+ "\xec\x86\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec87[] = {
+ "\xec\x87\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec88[] = {
+ "\xec\x88\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec89[] = {
+ "\xec\x89\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec8a[] = {
+ "\xec\x8a\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec8b[] = {
+ "\xec\x8b\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec8c[] = {
+ "\xec\x8c\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec8d[] = {
+ "\xec\x8d\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec8e[] = {
+ "\xec\x8e\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec8f[] = {
+ "\xec\x8f\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec90[] = {
+ "\xec\x90\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec91[] = {
+ "\xec\x91\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec92[] = {
+ "\xec\x92\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec93[] = {
+ "\xec\x93\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec94[] = {
+ "\xec\x94\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec95[] = {
+ "\xec\x95\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec96[] = {
+ "\xec\x96\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec97[] = {
+ "\xec\x97\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec98[] = {
+ "\xec\x98\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec99[] = {
+ "\xec\x99\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec9a[] = {
+ "\xec\x9a\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec9b[] = {
+ "\xec\x9b\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec9c[] = {
+ "\xec\x9c\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec9d[] = {
+ "\xec\x9d\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec9e[] = {
+ "\xec\x9e\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ec9f[] = {
+ "\xec\x9f\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca0[] = {
+ "\xec\xa0\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca1[] = {
+ "\xec\xa1\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca2[] = {
+ "\xec\xa2\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca3[] = {
+ "\xec\xa3\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca4[] = {
+ "\xec\xa4\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca5[] = {
+ "\xec\xa5\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca6[] = {
+ "\xec\xa6\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca7[] = {
+ "\xec\xa7\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca8[] = {
+ "\xec\xa8\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_eca9[] = {
+ "\xec\xa9\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecaa[] = {
+ "\xec\xaa\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecab[] = {
+ "\xec\xab\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecac[] = {
+ "\xec\xac\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecad[] = {
+ "\xec\xad\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecae[] = {
+ "\xec\xae\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecaf[] = {
+ "\xec\xaf\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb0[] = {
+ "\xec\xb0\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb1[] = {
+ "\xec\xb1\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb2[] = {
+ "\xec\xb2\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb3[] = {
+ "\xec\xb3\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb4[] = {
+ "\xec\xb4\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb5[] = {
+ "\xec\xb5\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb6[] = {
+ "\xec\xb6\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb7[] = {
+ "\xec\xb7\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb8[] = {
+ "\xec\xb8\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecb9[] = {
+ "\xec\xb9\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecba[] = {
+ "\xec\xba\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecbb[] = {
+ "\xec\xbb\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecbc[] = {
+ "\xec\xbc\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecbd[] = {
+ "\xec\xbd\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecbe[] = {
+ "\xec\xbe\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ecbf[] = {
+ "\xec\xbf\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed80[] = {
+ "\xed\x80\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed81[] = {
+ "\xed\x81\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed82[] = {
+ "\xed\x82\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed83[] = {
+ "\xed\x83\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed84[] = {
+ "\xed\x84\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed85[] = {
+ "\xed\x85\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed86[] = {
+ "\xed\x86\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed87[] = {
+ "\xed\x87\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed88[] = {
+ "\xed\x88\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed89[] = {
+ "\xed\x89\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed8a[] = {
+ "\xed\x8a\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed8b[] = {
+ "\xed\x8b\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed8c[] = {
+ "\xed\x8c\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed8d[] = {
+ "\xed\x8d\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed8e[] = {
+ "\xed\x8e\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed8f[] = {
+ "\xed\x8f\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed90[] = {
+ "\xed\x90\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed91[] = {
+ "\xed\x91\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed92[] = {
+ "\xed\x92\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed93[] = {
+ "\xed\x93\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed94[] = {
+ "\xed\x94\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed95[] = {
+ "\xed\x95\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed96[] = {
+ "\xed\x96\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed97[] = {
+ "\xed\x97\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb7"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed98[] = {
+ "\xed\x98\x93", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xaf", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed99[] = {
+ "\xed\x99\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed9a[] = {
+ "\xed\x9a\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed9b[] = {
+ "\xed\x9b\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed9c[] = {
+ "\xed\x9c\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186ba_table_ed9d[] = {
+ "\xed\x9d\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\xbf"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186ba(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186ba_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x9b";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab0[] = {
+ "\xea\xb0\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab1[] = {
+ "\xea\xb1\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab2[] = {
+ "\xea\xb2\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab3[] = {
+ "\xea\xb3\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab4[] = {
+ "\xea\xb4\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab5[] = {
+ "\xea\xb5\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab6[] = {
+ "\xea\xb6\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab7[] = {
+ "\xea\xb7\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab8[] = {
+ "\xea\xb8\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eab9[] = {
+ "\xea\xb9\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eaba[] = {
+ "\xea\xba\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eabb[] = {
+ "\xea\xbb\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eabc[] = {
+ "\xea\xbc\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eabd[] = {
+ "\xea\xbd\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eabe[] = {
+ "\xea\xbe\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eabf[] = {
+ "\xea\xbf\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb80[] = {
+ "\xeb\x80\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb81[] = {
+ "\xeb\x81\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb82[] = {
+ "\xeb\x82\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb83[] = {
+ "\xeb\x83\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb84[] = {
+ "\xeb\x84\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb85[] = {
+ "\xeb\x85\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb86[] = {
+ "\xeb\x86\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb87[] = {
+ "\xeb\x87\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb88[] = {
+ "\xeb\x88\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb89[] = {
+ "\xeb\x89\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb8a[] = {
+ "\xeb\x8a\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb8b[] = {
+ "\xeb\x8b\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb8c[] = {
+ "\xeb\x8c\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb8d[] = {
+ "\xeb\x8d\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb8e[] = {
+ "\xeb\x8e\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb8f[] = {
+ "\xeb\x8f\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb90[] = {
+ "\xeb\x90\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb91[] = {
+ "\xeb\x91\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb92[] = {
+ "\xeb\x92\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb93[] = {
+ "\xeb\x93\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb94[] = {
+ "\xeb\x94\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb95[] = {
+ "\xeb\x95\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb96[] = {
+ "\xeb\x96\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb97[] = {
+ "\xeb\x97\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb98[] = {
+ "\xeb\x98\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb99[] = {
+ "\xeb\x99\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb9a[] = {
+ "\xeb\x9a\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb9b[] = {
+ "\xeb\x9b\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb9c[] = {
+ "\xeb\x9c\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb9d[] = {
+ "\xeb\x9d\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb9e[] = {
+ "\xeb\x9e\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eb9f[] = {
+ "\xeb\x9f\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba0[] = {
+ "\xeb\xa0\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba1[] = {
+ "\xeb\xa1\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba2[] = {
+ "\xeb\xa2\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba3[] = {
+ "\xeb\xa3\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba4[] = {
+ "\xeb\xa4\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba5[] = {
+ "\xeb\xa5\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba6[] = {
+ "\xeb\xa6\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba7[] = {
+ "\xeb\xa7\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba8[] = {
+ "\xeb\xa8\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eba9[] = {
+ "\xeb\xa9\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebaa[] = {
+ "\xeb\xaa\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebab[] = {
+ "\xeb\xab\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebac[] = {
+ "\xeb\xac\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebad[] = {
+ "\xeb\xad\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebae[] = {
+ "\xeb\xae\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebaf[] = {
+ "\xeb\xaf\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb0[] = {
+ "\xeb\xb0\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb1[] = {
+ "\xeb\xb1\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb2[] = {
+ "\xeb\xb2\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb3[] = {
+ "\xeb\xb3\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb4[] = {
+ "\xeb\xb4\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb5[] = {
+ "\xeb\xb5\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb6[] = {
+ "\xeb\xb6\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb7[] = {
+ "\xeb\xb7\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb8[] = {
+ "\xeb\xb8\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebb9[] = {
+ "\xeb\xb9\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebba[] = {
+ "\xeb\xba\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebbb[] = {
+ "\xeb\xbb\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebbc[] = {
+ "\xeb\xbc\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebbd[] = {
+ "\xeb\xbd\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebbe[] = {
+ "\xeb\xbe\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ebbf[] = {
+ "\xeb\xbf\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec80[] = {
+ "\xec\x80\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec81[] = {
+ "\xec\x81\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec82[] = {
+ "\xec\x82\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec83[] = {
+ "\xec\x83\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec84[] = {
+ "\xec\x84\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec85[] = {
+ "\xec\x85\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec86[] = {
+ "\xec\x86\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec87[] = {
+ "\xec\x87\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec88[] = {
+ "\xec\x88\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec89[] = {
+ "\xec\x89\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec8a[] = {
+ "\xec\x8a\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec8b[] = {
+ "\xec\x8b\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec8c[] = {
+ "\xec\x8c\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec8d[] = {
+ "\xec\x8d\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec8e[] = {
+ "\xec\x8e\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec8f[] = {
+ "\xec\x8f\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec90[] = {
+ "\xec\x90\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec91[] = {
+ "\xec\x91\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec92[] = {
+ "\xec\x92\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec93[] = {
+ "\xec\x93\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec94[] = {
+ "\xec\x94\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec95[] = {
+ "\xec\x95\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec96[] = {
+ "\xec\x96\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec97[] = {
+ "\xec\x97\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec98[] = {
+ "\xec\x98\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec99[] = {
+ "\xec\x99\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec9a[] = {
+ "\xec\x9a\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec9b[] = {
+ "\xec\x9b\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec9c[] = {
+ "\xec\x9c\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec9d[] = {
+ "\xec\x9d\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec9e[] = {
+ "\xec\x9e\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ec9f[] = {
+ "\xec\x9f\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca0[] = {
+ "\xec\xa0\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca1[] = {
+ "\xec\xa1\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca2[] = {
+ "\xec\xa2\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca3[] = {
+ "\xec\xa3\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca4[] = {
+ "\xec\xa4\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca5[] = {
+ "\xec\xa5\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca6[] = {
+ "\xec\xa6\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca7[] = {
+ "\xec\xa7\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca8[] = {
+ "\xec\xa8\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_eca9[] = {
+ "\xec\xa9\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecaa[] = {
+ "\xec\xaa\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecab[] = {
+ "\xec\xab\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecac[] = {
+ "\xec\xac\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecad[] = {
+ "\xec\xad\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecae[] = {
+ "\xec\xae\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecaf[] = {
+ "\xec\xaf\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb0[] = {
+ "\xec\xb0\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb1[] = {
+ "\xec\xb1\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb2[] = {
+ "\xec\xb2\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb3[] = {
+ "\xec\xb3\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb4[] = {
+ "\xec\xb4\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb5[] = {
+ "\xec\xb5\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb6[] = {
+ "\xec\xb6\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb7[] = {
+ "\xec\xb7\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb8[] = {
+ "\xec\xb8\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecb9[] = {
+ "\xec\xb9\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecba[] = {
+ "\xec\xba\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecbb[] = {
+ "\xec\xbb\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecbc[] = {
+ "\xec\xbc\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecbd[] = {
+ "\xec\xbd\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecbe[] = {
+ "\xec\xbe\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ecbf[] = {
+ "\xec\xbf\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed80[] = {
+ "\xed\x80\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed81[] = {
+ "\xed\x81\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed82[] = {
+ "\xed\x82\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed83[] = {
+ "\xed\x83\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed84[] = {
+ "\xed\x84\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed85[] = {
+ "\xed\x85\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed86[] = {
+ "\xed\x86\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed87[] = {
+ "\xed\x87\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed88[] = {
+ "\xed\x88\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed89[] = {
+ "\xed\x89\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed8a[] = {
+ "\xed\x8a\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed8b[] = {
+ "\xed\x8b\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed8c[] = {
+ "\xed\x8c\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed8d[] = {
+ "\xed\x8d\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed8e[] = {
+ "\xed\x8e\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed8f[] = {
+ "\xed\x8f\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed90[] = {
+ "\xed\x90\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed91[] = {
+ "\xed\x91\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed92[] = {
+ "\xed\x92\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed93[] = {
+ "\xed\x93\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed94[] = {
+ "\xed\x94\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed95[] = {
+ "\xed\x95\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed96[] = {
+ "\xed\x96\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed97[] = {
+ "\xed\x97\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb8"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed98[] = {
+ "\xed\x98\x94", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb0", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed99[] = {
+ "\xed\x99\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed9a[] = {
+ "\xed\x9a\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed9b[] = {
+ "\xed\x9b\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed9c[] = {
+ "\xed\x9c\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bb_table_ed9d[] = {
+ "\xed\x9d\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x80"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186bb(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bb_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x9c";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab0[] = {
+ "\xea\xb0\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab1[] = {
+ "\xea\xb1\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab2[] = {
+ "\xea\xb2\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab3[] = {
+ "\xea\xb3\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab4[] = {
+ "\xea\xb4\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab5[] = {
+ "\xea\xb5\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab6[] = {
+ "\xea\xb6\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab7[] = {
+ "\xea\xb7\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab8[] = {
+ "\xea\xb8\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eab9[] = {
+ "\xea\xb9\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eaba[] = {
+ "\xea\xba\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eabb[] = {
+ "\xea\xbb\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eabc[] = {
+ "\xea\xbc\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eabd[] = {
+ "\xea\xbd\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eabe[] = {
+ "\xea\xbe\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eabf[] = {
+ "\xea\xbf\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb80[] = {
+ "\xeb\x80\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb81[] = {
+ "\xeb\x81\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb82[] = {
+ "\xeb\x82\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb83[] = {
+ "\xeb\x83\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb84[] = {
+ "\xeb\x84\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb85[] = {
+ "\xeb\x85\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb86[] = {
+ "\xeb\x86\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb87[] = {
+ "\xeb\x87\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb88[] = {
+ "\xeb\x88\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb89[] = {
+ "\xeb\x89\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb8a[] = {
+ "\xeb\x8a\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb8b[] = {
+ "\xeb\x8b\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb8c[] = {
+ "\xeb\x8c\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb8d[] = {
+ "\xeb\x8d\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb8e[] = {
+ "\xeb\x8e\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb8f[] = {
+ "\xeb\x8f\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb90[] = {
+ "\xeb\x90\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb91[] = {
+ "\xeb\x91\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb92[] = {
+ "\xeb\x92\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb93[] = {
+ "\xeb\x93\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb94[] = {
+ "\xeb\x94\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb95[] = {
+ "\xeb\x95\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb96[] = {
+ "\xeb\x96\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb97[] = {
+ "\xeb\x97\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb98[] = {
+ "\xeb\x98\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb99[] = {
+ "\xeb\x99\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb9a[] = {
+ "\xeb\x9a\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb9b[] = {
+ "\xeb\x9b\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb9c[] = {
+ "\xeb\x9c\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb9d[] = {
+ "\xeb\x9d\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb9e[] = {
+ "\xeb\x9e\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eb9f[] = {
+ "\xeb\x9f\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba0[] = {
+ "\xeb\xa0\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba1[] = {
+ "\xeb\xa1\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba2[] = {
+ "\xeb\xa2\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba3[] = {
+ "\xeb\xa3\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba4[] = {
+ "\xeb\xa4\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba5[] = {
+ "\xeb\xa5\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba6[] = {
+ "\xeb\xa6\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba7[] = {
+ "\xeb\xa7\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba8[] = {
+ "\xeb\xa8\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eba9[] = {
+ "\xeb\xa9\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebaa[] = {
+ "\xeb\xaa\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebab[] = {
+ "\xeb\xab\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebac[] = {
+ "\xeb\xac\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebad[] = {
+ "\xeb\xad\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebae[] = {
+ "\xeb\xae\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebaf[] = {
+ "\xeb\xaf\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb0[] = {
+ "\xeb\xb0\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb1[] = {
+ "\xeb\xb1\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb2[] = {
+ "\xeb\xb2\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb3[] = {
+ "\xeb\xb3\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb4[] = {
+ "\xeb\xb4\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb5[] = {
+ "\xeb\xb5\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb6[] = {
+ "\xeb\xb6\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb7[] = {
+ "\xeb\xb7\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb8[] = {
+ "\xeb\xb8\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebb9[] = {
+ "\xeb\xb9\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebba[] = {
+ "\xeb\xba\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebbb[] = {
+ "\xeb\xbb\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebbc[] = {
+ "\xeb\xbc\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebbd[] = {
+ "\xeb\xbd\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebbe[] = {
+ "\xeb\xbe\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ebbf[] = {
+ "\xeb\xbf\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec80[] = {
+ "\xec\x80\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec81[] = {
+ "\xec\x81\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec82[] = {
+ "\xec\x82\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec83[] = {
+ "\xec\x83\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec84[] = {
+ "\xec\x84\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec85[] = {
+ "\xec\x85\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec86[] = {
+ "\xec\x86\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec87[] = {
+ "\xec\x87\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec88[] = {
+ "\xec\x88\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec89[] = {
+ "\xec\x89\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec8a[] = {
+ "\xec\x8a\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec8b[] = {
+ "\xec\x8b\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec8c[] = {
+ "\xec\x8c\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec8d[] = {
+ "\xec\x8d\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec8e[] = {
+ "\xec\x8e\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec8f[] = {
+ "\xec\x8f\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec90[] = {
+ "\xec\x90\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec91[] = {
+ "\xec\x91\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec92[] = {
+ "\xec\x92\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec93[] = {
+ "\xec\x93\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec94[] = {
+ "\xec\x94\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec95[] = {
+ "\xec\x95\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec96[] = {
+ "\xec\x96\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec97[] = {
+ "\xec\x97\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec98[] = {
+ "\xec\x98\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec99[] = {
+ "\xec\x99\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec9a[] = {
+ "\xec\x9a\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec9b[] = {
+ "\xec\x9b\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec9c[] = {
+ "\xec\x9c\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec9d[] = {
+ "\xec\x9d\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec9e[] = {
+ "\xec\x9e\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ec9f[] = {
+ "\xec\x9f\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca0[] = {
+ "\xec\xa0\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca1[] = {
+ "\xec\xa1\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca2[] = {
+ "\xec\xa2\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca3[] = {
+ "\xec\xa3\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca4[] = {
+ "\xec\xa4\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca5[] = {
+ "\xec\xa5\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca6[] = {
+ "\xec\xa6\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca7[] = {
+ "\xec\xa7\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca8[] = {
+ "\xec\xa8\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_eca9[] = {
+ "\xec\xa9\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecaa[] = {
+ "\xec\xaa\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecab[] = {
+ "\xec\xab\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecac[] = {
+ "\xec\xac\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecad[] = {
+ "\xec\xad\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecae[] = {
+ "\xec\xae\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecaf[] = {
+ "\xec\xaf\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb0[] = {
+ "\xec\xb0\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb1[] = {
+ "\xec\xb1\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb2[] = {
+ "\xec\xb2\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb3[] = {
+ "\xec\xb3\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb4[] = {
+ "\xec\xb4\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb5[] = {
+ "\xec\xb5\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb6[] = {
+ "\xec\xb6\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb7[] = {
+ "\xec\xb7\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb8[] = {
+ "\xec\xb8\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecb9[] = {
+ "\xec\xb9\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecba[] = {
+ "\xec\xba\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecbb[] = {
+ "\xec\xbb\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecbc[] = {
+ "\xec\xbc\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecbd[] = {
+ "\xec\xbd\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecbe[] = {
+ "\xec\xbe\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ecbf[] = {
+ "\xec\xbf\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed80[] = {
+ "\xed\x80\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed81[] = {
+ "\xed\x81\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed82[] = {
+ "\xed\x82\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed83[] = {
+ "\xed\x83\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed84[] = {
+ "\xed\x84\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed85[] = {
+ "\xed\x85\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed86[] = {
+ "\xed\x86\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed87[] = {
+ "\xed\x87\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed88[] = {
+ "\xed\x88\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed89[] = {
+ "\xed\x89\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed8a[] = {
+ "\xed\x8a\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed8b[] = {
+ "\xed\x8b\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed8c[] = {
+ "\xed\x8c\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed8d[] = {
+ "\xed\x8d\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed8e[] = {
+ "\xed\x8e\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed8f[] = {
+ "\xed\x8f\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed90[] = {
+ "\xed\x90\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed91[] = {
+ "\xed\x91\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed92[] = {
+ "\xed\x92\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed93[] = {
+ "\xed\x93\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed94[] = {
+ "\xed\x94\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed95[] = {
+ "\xed\x95\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed96[] = {
+ "\xed\x96\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed97[] = {
+ "\xed\x97\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xb9"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed98[] = {
+ "\xed\x98\x95", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb1", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed99[] = {
+ "\xed\x99\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed9a[] = {
+ "\xed\x9a\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed9b[] = {
+ "\xed\x9b\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed9c[] = {
+ "\xed\x9c\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bc_table_ed9d[] = {
+ "\xed\x9d\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x81"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186bc(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bc_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x9d";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab0[] = {
+ "\xea\xb0\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab1[] = {
+ "\xea\xb1\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab2[] = {
+ "\xea\xb2\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab3[] = {
+ "\xea\xb3\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab4[] = {
+ "\xea\xb4\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab5[] = {
+ "\xea\xb5\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab6[] = {
+ "\xea\xb6\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab7[] = {
+ "\xea\xb7\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab8[] = {
+ "\xea\xb8\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eab9[] = {
+ "\xea\xb9\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eaba[] = {
+ "\xea\xba\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eabb[] = {
+ "\xea\xbb\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eabc[] = {
+ "\xea\xbc\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eabd[] = {
+ "\xea\xbd\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eabe[] = {
+ "\xea\xbe\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eabf[] = {
+ "\xea\xbf\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb80[] = {
+ "\xeb\x80\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb81[] = {
+ "\xeb\x81\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb82[] = {
+ "\xeb\x82\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb83[] = {
+ "\xeb\x83\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb84[] = {
+ "\xeb\x84\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb85[] = {
+ "\xeb\x85\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb86[] = {
+ "\xeb\x86\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb87[] = {
+ "\xeb\x87\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb88[] = {
+ "\xeb\x88\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb89[] = {
+ "\xeb\x89\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb8a[] = {
+ "\xeb\x8a\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb8b[] = {
+ "\xeb\x8b\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb8c[] = {
+ "\xeb\x8c\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb8d[] = {
+ "\xeb\x8d\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb8e[] = {
+ "\xeb\x8e\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb8f[] = {
+ "\xeb\x8f\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb90[] = {
+ "\xeb\x90\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb91[] = {
+ "\xeb\x91\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb92[] = {
+ "\xeb\x92\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb93[] = {
+ "\xeb\x93\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb94[] = {
+ "\xeb\x94\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb95[] = {
+ "\xeb\x95\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb96[] = {
+ "\xeb\x96\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb97[] = {
+ "\xeb\x97\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb98[] = {
+ "\xeb\x98\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb99[] = {
+ "\xeb\x99\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb9a[] = {
+ "\xeb\x9a\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb9b[] = {
+ "\xeb\x9b\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb9c[] = {
+ "\xeb\x9c\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb9d[] = {
+ "\xeb\x9d\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb9e[] = {
+ "\xeb\x9e\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eb9f[] = {
+ "\xeb\x9f\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba0[] = {
+ "\xeb\xa0\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba1[] = {
+ "\xeb\xa1\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba2[] = {
+ "\xeb\xa2\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba3[] = {
+ "\xeb\xa3\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba4[] = {
+ "\xeb\xa4\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba5[] = {
+ "\xeb\xa5\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba6[] = {
+ "\xeb\xa6\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba7[] = {
+ "\xeb\xa7\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba8[] = {
+ "\xeb\xa8\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eba9[] = {
+ "\xeb\xa9\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebaa[] = {
+ "\xeb\xaa\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebab[] = {
+ "\xeb\xab\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebac[] = {
+ "\xeb\xac\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebad[] = {
+ "\xeb\xad\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebae[] = {
+ "\xeb\xae\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebaf[] = {
+ "\xeb\xaf\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb0[] = {
+ "\xeb\xb0\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb1[] = {
+ "\xeb\xb1\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb2[] = {
+ "\xeb\xb2\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb3[] = {
+ "\xeb\xb3\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb4[] = {
+ "\xeb\xb4\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb5[] = {
+ "\xeb\xb5\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb6[] = {
+ "\xeb\xb6\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb7[] = {
+ "\xeb\xb7\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb8[] = {
+ "\xeb\xb8\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebb9[] = {
+ "\xeb\xb9\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebba[] = {
+ "\xeb\xba\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebbb[] = {
+ "\xeb\xbb\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebbc[] = {
+ "\xeb\xbc\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebbd[] = {
+ "\xeb\xbd\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebbe[] = {
+ "\xeb\xbe\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ebbf[] = {
+ "\xeb\xbf\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec80[] = {
+ "\xec\x80\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec81[] = {
+ "\xec\x81\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec82[] = {
+ "\xec\x82\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec83[] = {
+ "\xec\x83\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec84[] = {
+ "\xec\x84\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec85[] = {
+ "\xec\x85\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec86[] = {
+ "\xec\x86\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec87[] = {
+ "\xec\x87\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec88[] = {
+ "\xec\x88\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec89[] = {
+ "\xec\x89\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec8a[] = {
+ "\xec\x8a\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec8b[] = {
+ "\xec\x8b\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec8c[] = {
+ "\xec\x8c\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec8d[] = {
+ "\xec\x8d\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec8e[] = {
+ "\xec\x8e\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec8f[] = {
+ "\xec\x8f\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec90[] = {
+ "\xec\x90\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec91[] = {
+ "\xec\x91\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec92[] = {
+ "\xec\x92\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec93[] = {
+ "\xec\x93\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec94[] = {
+ "\xec\x94\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec95[] = {
+ "\xec\x95\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec96[] = {
+ "\xec\x96\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec97[] = {
+ "\xec\x97\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec98[] = {
+ "\xec\x98\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec99[] = {
+ "\xec\x99\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec9a[] = {
+ "\xec\x9a\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec9b[] = {
+ "\xec\x9b\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec9c[] = {
+ "\xec\x9c\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec9d[] = {
+ "\xec\x9d\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec9e[] = {
+ "\xec\x9e\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ec9f[] = {
+ "\xec\x9f\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca0[] = {
+ "\xec\xa0\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca1[] = {
+ "\xec\xa1\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca2[] = {
+ "\xec\xa2\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca3[] = {
+ "\xec\xa3\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca4[] = {
+ "\xec\xa4\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca5[] = {
+ "\xec\xa5\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca6[] = {
+ "\xec\xa6\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca7[] = {
+ "\xec\xa7\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca8[] = {
+ "\xec\xa8\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_eca9[] = {
+ "\xec\xa9\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecaa[] = {
+ "\xec\xaa\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecab[] = {
+ "\xec\xab\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecac[] = {
+ "\xec\xac\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecad[] = {
+ "\xec\xad\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecae[] = {
+ "\xec\xae\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecaf[] = {
+ "\xec\xaf\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb0[] = {
+ "\xec\xb0\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb1[] = {
+ "\xec\xb1\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb2[] = {
+ "\xec\xb2\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb3[] = {
+ "\xec\xb3\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb4[] = {
+ "\xec\xb4\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb5[] = {
+ "\xec\xb5\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb6[] = {
+ "\xec\xb6\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb7[] = {
+ "\xec\xb7\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb8[] = {
+ "\xec\xb8\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecb9[] = {
+ "\xec\xb9\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecba[] = {
+ "\xec\xba\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecbb[] = {
+ "\xec\xbb\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecbc[] = {
+ "\xec\xbc\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecbd[] = {
+ "\xec\xbd\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecbe[] = {
+ "\xec\xbe\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ecbf[] = {
+ "\xec\xbf\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed80[] = {
+ "\xed\x80\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed81[] = {
+ "\xed\x81\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed82[] = {
+ "\xed\x82\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed83[] = {
+ "\xed\x83\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed84[] = {
+ "\xed\x84\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed85[] = {
+ "\xed\x85\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed86[] = {
+ "\xed\x86\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed87[] = {
+ "\xed\x87\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed88[] = {
+ "\xed\x88\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed89[] = {
+ "\xed\x89\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed8a[] = {
+ "\xed\x8a\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed8b[] = {
+ "\xed\x8b\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed8c[] = {
+ "\xed\x8c\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed8d[] = {
+ "\xed\x8d\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed8e[] = {
+ "\xed\x8e\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed8f[] = {
+ "\xed\x8f\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed90[] = {
+ "\xed\x90\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed91[] = {
+ "\xed\x91\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed92[] = {
+ "\xed\x92\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed93[] = {
+ "\xed\x93\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed94[] = {
+ "\xed\x94\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed95[] = {
+ "\xed\x95\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed96[] = {
+ "\xed\x96\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed97[] = {
+ "\xed\x97\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xba"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed98[] = {
+ "\xed\x98\x96", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb2", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed99[] = {
+ "\xed\x99\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed9a[] = {
+ "\xed\x9a\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed9b[] = {
+ "\xed\x9b\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed9c[] = {
+ "\xed\x9c\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bd_table_ed9d[] = {
+ "\xed\x9d\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x82"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186bd(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bd_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x9e";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab0[] = {
+ "\xea\xb0\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab1[] = {
+ "\xea\xb1\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab2[] = {
+ "\xea\xb2\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab3[] = {
+ "\xea\xb3\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab4[] = {
+ "\xea\xb4\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab5[] = {
+ "\xea\xb5\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab6[] = {
+ "\xea\xb6\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab7[] = {
+ "\xea\xb7\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab8[] = {
+ "\xea\xb8\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eab9[] = {
+ "\xea\xb9\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eaba[] = {
+ "\xea\xba\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eabb[] = {
+ "\xea\xbb\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eabc[] = {
+ "\xea\xbc\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eabd[] = {
+ "\xea\xbd\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eabe[] = {
+ "\xea\xbe\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eabf[] = {
+ "\xea\xbf\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb80[] = {
+ "\xeb\x80\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb81[] = {
+ "\xeb\x81\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb82[] = {
+ "\xeb\x82\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb83[] = {
+ "\xeb\x83\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb84[] = {
+ "\xeb\x84\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb85[] = {
+ "\xeb\x85\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb86[] = {
+ "\xeb\x86\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb87[] = {
+ "\xeb\x87\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb88[] = {
+ "\xeb\x88\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb89[] = {
+ "\xeb\x89\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb8a[] = {
+ "\xeb\x8a\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb8b[] = {
+ "\xeb\x8b\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb8c[] = {
+ "\xeb\x8c\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb8d[] = {
+ "\xeb\x8d\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb8e[] = {
+ "\xeb\x8e\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb8f[] = {
+ "\xeb\x8f\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb90[] = {
+ "\xeb\x90\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb91[] = {
+ "\xeb\x91\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb92[] = {
+ "\xeb\x92\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb93[] = {
+ "\xeb\x93\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb94[] = {
+ "\xeb\x94\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb95[] = {
+ "\xeb\x95\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb96[] = {
+ "\xeb\x96\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb97[] = {
+ "\xeb\x97\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb98[] = {
+ "\xeb\x98\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb99[] = {
+ "\xeb\x99\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb9a[] = {
+ "\xeb\x9a\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb9b[] = {
+ "\xeb\x9b\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb9c[] = {
+ "\xeb\x9c\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb9d[] = {
+ "\xeb\x9d\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb9e[] = {
+ "\xeb\x9e\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eb9f[] = {
+ "\xeb\x9f\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba0[] = {
+ "\xeb\xa0\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba1[] = {
+ "\xeb\xa1\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba2[] = {
+ "\xeb\xa2\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba3[] = {
+ "\xeb\xa3\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba4[] = {
+ "\xeb\xa4\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba5[] = {
+ "\xeb\xa5\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba6[] = {
+ "\xeb\xa6\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba7[] = {
+ "\xeb\xa7\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba8[] = {
+ "\xeb\xa8\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eba9[] = {
+ "\xeb\xa9\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebaa[] = {
+ "\xeb\xaa\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebab[] = {
+ "\xeb\xab\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebac[] = {
+ "\xeb\xac\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebad[] = {
+ "\xeb\xad\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebae[] = {
+ "\xeb\xae\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebaf[] = {
+ "\xeb\xaf\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb0[] = {
+ "\xeb\xb0\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb1[] = {
+ "\xeb\xb1\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb2[] = {
+ "\xeb\xb2\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb3[] = {
+ "\xeb\xb3\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb4[] = {
+ "\xeb\xb4\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb5[] = {
+ "\xeb\xb5\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb6[] = {
+ "\xeb\xb6\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb7[] = {
+ "\xeb\xb7\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb8[] = {
+ "\xeb\xb8\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebb9[] = {
+ "\xeb\xb9\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebba[] = {
+ "\xeb\xba\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebbb[] = {
+ "\xeb\xbb\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebbc[] = {
+ "\xeb\xbc\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebbd[] = {
+ "\xeb\xbd\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebbe[] = {
+ "\xeb\xbe\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ebbf[] = {
+ "\xeb\xbf\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec80[] = {
+ "\xec\x80\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec81[] = {
+ "\xec\x81\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec82[] = {
+ "\xec\x82\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec83[] = {
+ "\xec\x83\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec84[] = {
+ "\xec\x84\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec85[] = {
+ "\xec\x85\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec86[] = {
+ "\xec\x86\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec87[] = {
+ "\xec\x87\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec88[] = {
+ "\xec\x88\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec89[] = {
+ "\xec\x89\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec8a[] = {
+ "\xec\x8a\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec8b[] = {
+ "\xec\x8b\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec8c[] = {
+ "\xec\x8c\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec8d[] = {
+ "\xec\x8d\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec8e[] = {
+ "\xec\x8e\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec8f[] = {
+ "\xec\x8f\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec90[] = {
+ "\xec\x90\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec91[] = {
+ "\xec\x91\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec92[] = {
+ "\xec\x92\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec93[] = {
+ "\xec\x93\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec94[] = {
+ "\xec\x94\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec95[] = {
+ "\xec\x95\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec96[] = {
+ "\xec\x96\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec97[] = {
+ "\xec\x97\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec98[] = {
+ "\xec\x98\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec99[] = {
+ "\xec\x99\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec9a[] = {
+ "\xec\x9a\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec9b[] = {
+ "\xec\x9b\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec9c[] = {
+ "\xec\x9c\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec9d[] = {
+ "\xec\x9d\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec9e[] = {
+ "\xec\x9e\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ec9f[] = {
+ "\xec\x9f\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca0[] = {
+ "\xec\xa0\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca1[] = {
+ "\xec\xa1\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca2[] = {
+ "\xec\xa2\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca3[] = {
+ "\xec\xa3\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca4[] = {
+ "\xec\xa4\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca5[] = {
+ "\xec\xa5\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca6[] = {
+ "\xec\xa6\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca7[] = {
+ "\xec\xa7\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca8[] = {
+ "\xec\xa8\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_eca9[] = {
+ "\xec\xa9\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecaa[] = {
+ "\xec\xaa\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecab[] = {
+ "\xec\xab\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecac[] = {
+ "\xec\xac\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecad[] = {
+ "\xec\xad\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecae[] = {
+ "\xec\xae\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecaf[] = {
+ "\xec\xaf\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb0[] = {
+ "\xec\xb0\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb1[] = {
+ "\xec\xb1\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb2[] = {
+ "\xec\xb2\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb3[] = {
+ "\xec\xb3\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb4[] = {
+ "\xec\xb4\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb5[] = {
+ "\xec\xb5\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb6[] = {
+ "\xec\xb6\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb7[] = {
+ "\xec\xb7\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb8[] = {
+ "\xec\xb8\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecb9[] = {
+ "\xec\xb9\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecba[] = {
+ "\xec\xba\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecbb[] = {
+ "\xec\xbb\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecbc[] = {
+ "\xec\xbc\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecbd[] = {
+ "\xec\xbd\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecbe[] = {
+ "\xec\xbe\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ecbf[] = {
+ "\xec\xbf\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed80[] = {
+ "\xed\x80\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed81[] = {
+ "\xed\x81\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed82[] = {
+ "\xed\x82\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed83[] = {
+ "\xed\x83\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed84[] = {
+ "\xed\x84\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed85[] = {
+ "\xed\x85\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed86[] = {
+ "\xed\x86\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed87[] = {
+ "\xed\x87\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed88[] = {
+ "\xed\x88\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed89[] = {
+ "\xed\x89\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed8a[] = {
+ "\xed\x8a\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed8b[] = {
+ "\xed\x8b\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed8c[] = {
+ "\xed\x8c\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed8d[] = {
+ "\xed\x8d\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed8e[] = {
+ "\xed\x8e\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed8f[] = {
+ "\xed\x8f\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed90[] = {
+ "\xed\x90\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed91[] = {
+ "\xed\x91\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed92[] = {
+ "\xed\x92\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed93[] = {
+ "\xed\x93\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed94[] = {
+ "\xed\x94\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed95[] = {
+ "\xed\x95\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed96[] = {
+ "\xed\x96\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed97[] = {
+ "\xed\x97\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xbb"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed98[] = {
+ "\xed\x98\x97", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb3", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed99[] = {
+ "\xed\x99\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed9a[] = {
+ "\xed\x9a\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed9b[] = {
+ "\xed\x9b\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed9c[] = {
+ "\xed\x9c\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186be_table_ed9d[] = {
+ "\xed\x9d\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x83"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186be(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186be_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\x9f";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab0[] = {
+ "\xea\xb0\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab1[] = {
+ "\xea\xb1\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab2[] = {
+ "\xea\xb2\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab3[] = {
+ "\xea\xb3\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab4[] = {
+ "\xea\xb4\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab5[] = {
+ "\xea\xb5\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab6[] = {
+ "\xea\xb6\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab7[] = {
+ "\xea\xb7\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab8[] = {
+ "\xea\xb8\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eab9[] = {
+ "\xea\xb9\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eaba[] = {
+ "\xea\xba\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eabb[] = {
+ "\xea\xbb\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eabc[] = {
+ "\xea\xbc\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eabd[] = {
+ "\xea\xbd\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eabe[] = {
+ "\xea\xbe\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eabf[] = {
+ "\xea\xbf\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb80[] = {
+ "\xeb\x80\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb81[] = {
+ "\xeb\x81\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb82[] = {
+ "\xeb\x82\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb83[] = {
+ "\xeb\x83\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb84[] = {
+ "\xeb\x84\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb85[] = {
+ "\xeb\x85\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb86[] = {
+ "\xeb\x86\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb87[] = {
+ "\xeb\x87\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb88[] = {
+ "\xeb\x88\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb89[] = {
+ "\xeb\x89\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb8a[] = {
+ "\xeb\x8a\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb8b[] = {
+ "\xeb\x8b\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb8c[] = {
+ "\xeb\x8c\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb8d[] = {
+ "\xeb\x8d\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb8e[] = {
+ "\xeb\x8e\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb8f[] = {
+ "\xeb\x8f\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb90[] = {
+ "\xeb\x90\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb91[] = {
+ "\xeb\x91\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb92[] = {
+ "\xeb\x92\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb93[] = {
+ "\xeb\x93\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb94[] = {
+ "\xeb\x94\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb95[] = {
+ "\xeb\x95\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb96[] = {
+ "\xeb\x96\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb97[] = {
+ "\xeb\x97\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb98[] = {
+ "\xeb\x98\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb99[] = {
+ "\xeb\x99\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb9a[] = {
+ "\xeb\x9a\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb9b[] = {
+ "\xeb\x9b\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb9c[] = {
+ "\xeb\x9c\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb9d[] = {
+ "\xeb\x9d\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb9e[] = {
+ "\xeb\x9e\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eb9f[] = {
+ "\xeb\x9f\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba0[] = {
+ "\xeb\xa0\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba1[] = {
+ "\xeb\xa1\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba2[] = {
+ "\xeb\xa2\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba3[] = {
+ "\xeb\xa3\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba4[] = {
+ "\xeb\xa4\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba5[] = {
+ "\xeb\xa5\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba6[] = {
+ "\xeb\xa6\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba7[] = {
+ "\xeb\xa7\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba8[] = {
+ "\xeb\xa8\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eba9[] = {
+ "\xeb\xa9\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebaa[] = {
+ "\xeb\xaa\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebab[] = {
+ "\xeb\xab\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebac[] = {
+ "\xeb\xac\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebad[] = {
+ "\xeb\xad\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebae[] = {
+ "\xeb\xae\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebaf[] = {
+ "\xeb\xaf\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb0[] = {
+ "\xeb\xb0\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb1[] = {
+ "\xeb\xb1\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb2[] = {
+ "\xeb\xb2\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb3[] = {
+ "\xeb\xb3\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb4[] = {
+ "\xeb\xb4\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb5[] = {
+ "\xeb\xb5\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb6[] = {
+ "\xeb\xb6\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb7[] = {
+ "\xeb\xb7\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb8[] = {
+ "\xeb\xb8\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebb9[] = {
+ "\xeb\xb9\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebba[] = {
+ "\xeb\xba\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebbb[] = {
+ "\xeb\xbb\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebbc[] = {
+ "\xeb\xbc\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebbd[] = {
+ "\xeb\xbd\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebbe[] = {
+ "\xeb\xbe\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ebbf[] = {
+ "\xeb\xbf\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec80[] = {
+ "\xec\x80\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec81[] = {
+ "\xec\x81\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec82[] = {
+ "\xec\x82\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec83[] = {
+ "\xec\x83\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec84[] = {
+ "\xec\x84\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec85[] = {
+ "\xec\x85\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec86[] = {
+ "\xec\x86\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec87[] = {
+ "\xec\x87\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec88[] = {
+ "\xec\x88\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec89[] = {
+ "\xec\x89\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec8a[] = {
+ "\xec\x8a\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec8b[] = {
+ "\xec\x8b\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec8c[] = {
+ "\xec\x8c\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec8d[] = {
+ "\xec\x8d\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec8e[] = {
+ "\xec\x8e\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec8f[] = {
+ "\xec\x8f\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec90[] = {
+ "\xec\x90\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec91[] = {
+ "\xec\x91\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec92[] = {
+ "\xec\x92\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec93[] = {
+ "\xec\x93\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec94[] = {
+ "\xec\x94\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec95[] = {
+ "\xec\x95\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec96[] = {
+ "\xec\x96\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec97[] = {
+ "\xec\x97\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec98[] = {
+ "\xec\x98\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec99[] = {
+ "\xec\x99\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec9a[] = {
+ "\xec\x9a\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec9b[] = {
+ "\xec\x9b\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec9c[] = {
+ "\xec\x9c\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec9d[] = {
+ "\xec\x9d\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec9e[] = {
+ "\xec\x9e\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ec9f[] = {
+ "\xec\x9f\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca0[] = {
+ "\xec\xa0\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca1[] = {
+ "\xec\xa1\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca2[] = {
+ "\xec\xa2\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca3[] = {
+ "\xec\xa3\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca4[] = {
+ "\xec\xa4\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca5[] = {
+ "\xec\xa5\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca6[] = {
+ "\xec\xa6\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca7[] = {
+ "\xec\xa7\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca8[] = {
+ "\xec\xa8\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_eca9[] = {
+ "\xec\xa9\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecaa[] = {
+ "\xec\xaa\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecab[] = {
+ "\xec\xab\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecac[] = {
+ "\xec\xac\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecad[] = {
+ "\xec\xad\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecae[] = {
+ "\xec\xae\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecaf[] = {
+ "\xec\xaf\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb0[] = {
+ "\xec\xb0\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb1[] = {
+ "\xec\xb1\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb2[] = {
+ "\xec\xb2\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb3[] = {
+ "\xec\xb3\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb4[] = {
+ "\xec\xb4\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb5[] = {
+ "\xec\xb5\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb6[] = {
+ "\xec\xb6\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb7[] = {
+ "\xec\xb7\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb8[] = {
+ "\xec\xb8\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecb9[] = {
+ "\xec\xb9\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecba[] = {
+ "\xec\xba\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecbb[] = {
+ "\xec\xbb\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecbc[] = {
+ "\xec\xbc\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecbd[] = {
+ "\xec\xbd\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecbe[] = {
+ "\xec\xbe\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ecbf[] = {
+ "\xec\xbf\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed80[] = {
+ "\xed\x80\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed81[] = {
+ "\xed\x81\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed82[] = {
+ "\xed\x82\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed83[] = {
+ "\xed\x83\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed84[] = {
+ "\xed\x84\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed85[] = {
+ "\xed\x85\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed86[] = {
+ "\xed\x86\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed87[] = {
+ "\xed\x87\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed88[] = {
+ "\xed\x88\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed89[] = {
+ "\xed\x89\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed8a[] = {
+ "\xed\x8a\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed8b[] = {
+ "\xed\x8b\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed8c[] = {
+ "\xed\x8c\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed8d[] = {
+ "\xed\x8d\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed8e[] = {
+ "\xed\x8e\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed8f[] = {
+ "\xed\x8f\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed90[] = {
+ "\xed\x90\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed91[] = {
+ "\xed\x91\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed92[] = {
+ "\xed\x92\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed93[] = {
+ "\xed\x93\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed94[] = {
+ "\xed\x94\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed95[] = {
+ "\xed\x95\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed96[] = {
+ "\xed\x96\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x84"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed97[] = {
+ "\xed\x97\xa0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xbc"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed98[] = {
+ "\xed\x98\x98", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb4", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x90"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed99[] = {
+ "\xed\x99\xac", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x88"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed9a[] = {
+ "\xed\x9a\xa4", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\x80"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed9b[] = {
+ "\xed\x9b\x9c", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb8", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x94"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed9c[] = {
+ "\xed\x9c\xb0", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x8c"
+};
+
+static const char *grn_nfkc50_compose_prefix_e186bf_table_ed9d[] = {
+ "\xed\x9d\xa8", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x84"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e186bf(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e186bf_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\xa0";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab0[] = {
+ "\xea\xb0\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab1[] = {
+ "\xea\xb1\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab2[] = {
+ "\xea\xb2\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab3[] = {
+ "\xea\xb3\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab4[] = {
+ "\xea\xb4\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab5[] = {
+ "\xea\xb5\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab6[] = {
+ "\xea\xb6\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab7[] = {
+ "\xea\xb7\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab8[] = {
+ "\xea\xb8\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eab9[] = {
+ "\xea\xb9\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eaba[] = {
+ "\xea\xba\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eabb[] = {
+ "\xea\xbb\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eabc[] = {
+ "\xea\xbc\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eabd[] = {
+ "\xea\xbd\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eabe[] = {
+ "\xea\xbe\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eabf[] = {
+ "\xea\xbf\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb80[] = {
+ "\xeb\x80\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb81[] = {
+ "\xeb\x81\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb82[] = {
+ "\xeb\x82\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb83[] = {
+ "\xeb\x83\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb84[] = {
+ "\xeb\x84\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb85[] = {
+ "\xeb\x85\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb86[] = {
+ "\xeb\x86\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb87[] = {
+ "\xeb\x87\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb88[] = {
+ "\xeb\x88\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb89[] = {
+ "\xeb\x89\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb8a[] = {
+ "\xeb\x8a\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb8b[] = {
+ "\xeb\x8b\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb8c[] = {
+ "\xeb\x8c\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb8d[] = {
+ "\xeb\x8d\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb8e[] = {
+ "\xeb\x8e\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb8f[] = {
+ "\xeb\x8f\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb90[] = {
+ "\xeb\x90\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb91[] = {
+ "\xeb\x91\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb92[] = {
+ "\xeb\x92\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb93[] = {
+ "\xeb\x93\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb94[] = {
+ "\xeb\x94\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb95[] = {
+ "\xeb\x95\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb96[] = {
+ "\xeb\x96\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb97[] = {
+ "\xeb\x97\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb98[] = {
+ "\xeb\x98\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb99[] = {
+ "\xeb\x99\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb9a[] = {
+ "\xeb\x9a\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb9b[] = {
+ "\xeb\x9b\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb9c[] = {
+ "\xeb\x9c\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb9d[] = {
+ "\xeb\x9d\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb9e[] = {
+ "\xeb\x9e\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eb9f[] = {
+ "\xeb\x9f\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba0[] = {
+ "\xeb\xa0\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba1[] = {
+ "\xeb\xa1\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba2[] = {
+ "\xeb\xa2\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba3[] = {
+ "\xeb\xa3\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba4[] = {
+ "\xeb\xa4\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba5[] = {
+ "\xeb\xa5\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba6[] = {
+ "\xeb\xa6\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba7[] = {
+ "\xeb\xa7\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba8[] = {
+ "\xeb\xa8\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eba9[] = {
+ "\xeb\xa9\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebaa[] = {
+ "\xeb\xaa\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebab[] = {
+ "\xeb\xab\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebac[] = {
+ "\xeb\xac\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebad[] = {
+ "\xeb\xad\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebae[] = {
+ "\xeb\xae\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebaf[] = {
+ "\xeb\xaf\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb0[] = {
+ "\xeb\xb0\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb1[] = {
+ "\xeb\xb1\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb2[] = {
+ "\xeb\xb2\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb3[] = {
+ "\xeb\xb3\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb4[] = {
+ "\xeb\xb4\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb5[] = {
+ "\xeb\xb5\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb6[] = {
+ "\xeb\xb6\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb7[] = {
+ "\xeb\xb7\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb8[] = {
+ "\xeb\xb8\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebb9[] = {
+ "\xeb\xb9\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebba[] = {
+ "\xeb\xba\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebbb[] = {
+ "\xeb\xbb\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebbc[] = {
+ "\xeb\xbc\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebbd[] = {
+ "\xeb\xbd\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebbe[] = {
+ "\xeb\xbe\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ebbf[] = {
+ "\xeb\xbf\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec80[] = {
+ "\xec\x80\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec81[] = {
+ "\xec\x81\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec82[] = {
+ "\xec\x82\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec83[] = {
+ "\xec\x83\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec84[] = {
+ "\xec\x84\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec85[] = {
+ "\xec\x85\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec86[] = {
+ "\xec\x86\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec87[] = {
+ "\xec\x87\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec88[] = {
+ "\xec\x88\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec89[] = {
+ "\xec\x89\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec8a[] = {
+ "\xec\x8a\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec8b[] = {
+ "\xec\x8b\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec8c[] = {
+ "\xec\x8c\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec8d[] = {
+ "\xec\x8d\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec8e[] = {
+ "\xec\x8e\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec8f[] = {
+ "\xec\x8f\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec90[] = {
+ "\xec\x90\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec91[] = {
+ "\xec\x91\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec92[] = {
+ "\xec\x92\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec93[] = {
+ "\xec\x93\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec94[] = {
+ "\xec\x94\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec95[] = {
+ "\xec\x95\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec96[] = {
+ "\xec\x96\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec97[] = {
+ "\xec\x97\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec98[] = {
+ "\xec\x98\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec99[] = {
+ "\xec\x99\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec9a[] = {
+ "\xec\x9a\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec9b[] = {
+ "\xec\x9b\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec9c[] = {
+ "\xec\x9c\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec9d[] = {
+ "\xec\x9d\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec9e[] = {
+ "\xec\x9e\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ec9f[] = {
+ "\xec\x9f\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca0[] = {
+ "\xec\xa0\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca1[] = {
+ "\xec\xa1\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca2[] = {
+ "\xec\xa2\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca3[] = {
+ "\xec\xa3\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca4[] = {
+ "\xec\xa4\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca5[] = {
+ "\xec\xa5\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca6[] = {
+ "\xec\xa6\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca7[] = {
+ "\xec\xa7\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca8[] = {
+ "\xec\xa8\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_eca9[] = {
+ "\xec\xa9\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecaa[] = {
+ "\xec\xaa\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecab[] = {
+ "\xec\xab\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecac[] = {
+ "\xec\xac\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecad[] = {
+ "\xec\xad\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecae[] = {
+ "\xec\xae\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecaf[] = {
+ "\xec\xaf\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb0[] = {
+ "\xec\xb0\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb1[] = {
+ "\xec\xb1\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb2[] = {
+ "\xec\xb2\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb3[] = {
+ "\xec\xb3\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb4[] = {
+ "\xec\xb4\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb5[] = {
+ "\xec\xb5\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb6[] = {
+ "\xec\xb6\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb7[] = {
+ "\xec\xb7\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb8[] = {
+ "\xec\xb8\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecb9[] = {
+ "\xec\xb9\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecba[] = {
+ "\xec\xba\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecbb[] = {
+ "\xec\xbb\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecbc[] = {
+ "\xec\xbc\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecbd[] = {
+ "\xec\xbd\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecbe[] = {
+ "\xec\xbe\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ecbf[] = {
+ "\xec\xbf\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed80[] = {
+ "\xed\x80\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed81[] = {
+ "\xed\x81\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed82[] = {
+ "\xed\x82\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed83[] = {
+ "\xed\x83\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed84[] = {
+ "\xed\x84\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed85[] = {
+ "\xed\x85\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed86[] = {
+ "\xed\x86\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed87[] = {
+ "\xed\x87\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed88[] = {
+ "\xed\x88\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed89[] = {
+ "\xed\x89\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed8a[] = {
+ "\xed\x8a\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed8b[] = {
+ "\xed\x8b\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed8c[] = {
+ "\xed\x8c\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed8d[] = {
+ "\xed\x8d\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed8e[] = {
+ "\xed\x8e\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed8f[] = {
+ "\xed\x8f\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed90[] = {
+ "\xed\x90\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed91[] = {
+ "\xed\x91\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed92[] = {
+ "\xed\x92\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed93[] = {
+ "\xed\x93\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed94[] = {
+ "\xed\x94\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed95[] = {
+ "\xed\x95\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed96[] = {
+ "\xed\x96\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x85"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed97[] = {
+ "\xed\x97\xa1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xbd"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed98[] = {
+ "\xed\x98\x99", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb5", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x91"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed99[] = {
+ "\xed\x99\xad", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x89"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed9a[] = {
+ "\xed\x9a\xa5", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\x81"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed9b[] = {
+ "\xed\x9b\x9d", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xb9", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x95"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed9c[] = {
+ "\xed\x9c\xb1", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x8d"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18780_table_ed9d[] = {
+ "\xed\x9d\xa9", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x85"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e18780(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18780_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\xa1";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab0[] = {
+ "\xea\xb0\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab1[] = {
+ "\xea\xb1\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab2[] = {
+ "\xea\xb2\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab3[] = {
+ "\xea\xb3\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab4[] = {
+ "\xea\xb4\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab5[] = {
+ "\xea\xb5\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab6[] = {
+ "\xea\xb6\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab7[] = {
+ "\xea\xb7\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab8[] = {
+ "\xea\xb8\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eab9[] = {
+ "\xea\xb9\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eaba[] = {
+ "\xea\xba\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eabb[] = {
+ "\xea\xbb\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eabc[] = {
+ "\xea\xbc\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eabd[] = {
+ "\xea\xbd\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eabe[] = {
+ "\xea\xbe\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eabf[] = {
+ "\xea\xbf\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb80[] = {
+ "\xeb\x80\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb81[] = {
+ "\xeb\x81\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb82[] = {
+ "\xeb\x82\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb83[] = {
+ "\xeb\x83\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb84[] = {
+ "\xeb\x84\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb85[] = {
+ "\xeb\x85\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb86[] = {
+ "\xeb\x86\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb87[] = {
+ "\xeb\x87\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb88[] = {
+ "\xeb\x88\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb89[] = {
+ "\xeb\x89\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb8a[] = {
+ "\xeb\x8a\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb8b[] = {
+ "\xeb\x8b\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb8c[] = {
+ "\xeb\x8c\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb8d[] = {
+ "\xeb\x8d\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb8e[] = {
+ "\xeb\x8e\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb8f[] = {
+ "\xeb\x8f\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb90[] = {
+ "\xeb\x90\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb91[] = {
+ "\xeb\x91\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb92[] = {
+ "\xeb\x92\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb93[] = {
+ "\xeb\x93\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb94[] = {
+ "\xeb\x94\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb95[] = {
+ "\xeb\x95\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb96[] = {
+ "\xeb\x96\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb97[] = {
+ "\xeb\x97\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb98[] = {
+ "\xeb\x98\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb99[] = {
+ "\xeb\x99\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb9a[] = {
+ "\xeb\x9a\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb9b[] = {
+ "\xeb\x9b\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb9c[] = {
+ "\xeb\x9c\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb9d[] = {
+ "\xeb\x9d\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb9e[] = {
+ "\xeb\x9e\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eb9f[] = {
+ "\xeb\x9f\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba0[] = {
+ "\xeb\xa0\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba1[] = {
+ "\xeb\xa1\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba2[] = {
+ "\xeb\xa2\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba3[] = {
+ "\xeb\xa3\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba4[] = {
+ "\xeb\xa4\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba5[] = {
+ "\xeb\xa5\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba6[] = {
+ "\xeb\xa6\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba7[] = {
+ "\xeb\xa7\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba8[] = {
+ "\xeb\xa8\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eba9[] = {
+ "\xeb\xa9\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebaa[] = {
+ "\xeb\xaa\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebab[] = {
+ "\xeb\xab\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebac[] = {
+ "\xeb\xac\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebad[] = {
+ "\xeb\xad\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebae[] = {
+ "\xeb\xae\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebaf[] = {
+ "\xeb\xaf\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb0[] = {
+ "\xeb\xb0\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb1[] = {
+ "\xeb\xb1\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb2[] = {
+ "\xeb\xb2\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb3[] = {
+ "\xeb\xb3\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb4[] = {
+ "\xeb\xb4\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb5[] = {
+ "\xeb\xb5\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb6[] = {
+ "\xeb\xb6\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb7[] = {
+ "\xeb\xb7\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb8[] = {
+ "\xeb\xb8\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebb9[] = {
+ "\xeb\xb9\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebba[] = {
+ "\xeb\xba\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebbb[] = {
+ "\xeb\xbb\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebbc[] = {
+ "\xeb\xbc\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebbd[] = {
+ "\xeb\xbd\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebbe[] = {
+ "\xeb\xbe\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ebbf[] = {
+ "\xeb\xbf\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec80[] = {
+ "\xec\x80\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec81[] = {
+ "\xec\x81\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec82[] = {
+ "\xec\x82\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec83[] = {
+ "\xec\x83\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec84[] = {
+ "\xec\x84\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec85[] = {
+ "\xec\x85\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec86[] = {
+ "\xec\x86\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec87[] = {
+ "\xec\x87\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec88[] = {
+ "\xec\x88\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec89[] = {
+ "\xec\x89\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec8a[] = {
+ "\xec\x8a\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec8b[] = {
+ "\xec\x8b\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec8c[] = {
+ "\xec\x8c\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec8d[] = {
+ "\xec\x8d\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec8e[] = {
+ "\xec\x8e\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec8f[] = {
+ "\xec\x8f\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec90[] = {
+ "\xec\x90\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec91[] = {
+ "\xec\x91\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec92[] = {
+ "\xec\x92\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec93[] = {
+ "\xec\x93\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec94[] = {
+ "\xec\x94\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec95[] = {
+ "\xec\x95\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec96[] = {
+ "\xec\x96\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec97[] = {
+ "\xec\x97\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec98[] = {
+ "\xec\x98\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec99[] = {
+ "\xec\x99\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec9a[] = {
+ "\xec\x9a\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec9b[] = {
+ "\xec\x9b\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec9c[] = {
+ "\xec\x9c\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec9d[] = {
+ "\xec\x9d\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec9e[] = {
+ "\xec\x9e\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ec9f[] = {
+ "\xec\x9f\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca0[] = {
+ "\xec\xa0\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca1[] = {
+ "\xec\xa1\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca2[] = {
+ "\xec\xa2\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca3[] = {
+ "\xec\xa3\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca4[] = {
+ "\xec\xa4\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca5[] = {
+ "\xec\xa5\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca6[] = {
+ "\xec\xa6\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca7[] = {
+ "\xec\xa7\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca8[] = {
+ "\xec\xa8\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_eca9[] = {
+ "\xec\xa9\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecaa[] = {
+ "\xec\xaa\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecab[] = {
+ "\xec\xab\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecac[] = {
+ "\xec\xac\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecad[] = {
+ "\xec\xad\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecae[] = {
+ "\xec\xae\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecaf[] = {
+ "\xec\xaf\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb0[] = {
+ "\xec\xb0\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb1[] = {
+ "\xec\xb1\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb2[] = {
+ "\xec\xb2\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb3[] = {
+ "\xec\xb3\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb4[] = {
+ "\xec\xb4\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb5[] = {
+ "\xec\xb5\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb6[] = {
+ "\xec\xb6\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb7[] = {
+ "\xec\xb7\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb8[] = {
+ "\xec\xb8\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecb9[] = {
+ "\xec\xb9\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecba[] = {
+ "\xec\xba\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecbb[] = {
+ "\xec\xbb\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecbc[] = {
+ "\xec\xbc\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecbd[] = {
+ "\xec\xbd\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecbe[] = {
+ "\xec\xbe\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ecbf[] = {
+ "\xec\xbf\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed80[] = {
+ "\xed\x80\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed81[] = {
+ "\xed\x81\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed82[] = {
+ "\xed\x82\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed83[] = {
+ "\xed\x83\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed84[] = {
+ "\xed\x84\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed85[] = {
+ "\xed\x85\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed86[] = {
+ "\xed\x86\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed87[] = {
+ "\xed\x87\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed88[] = {
+ "\xed\x88\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed89[] = {
+ "\xed\x89\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed8a[] = {
+ "\xed\x8a\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed8b[] = {
+ "\xed\x8b\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed8c[] = {
+ "\xed\x8c\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed8d[] = {
+ "\xed\x8d\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed8e[] = {
+ "\xed\x8e\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed8f[] = {
+ "\xed\x8f\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed90[] = {
+ "\xed\x90\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed91[] = {
+ "\xed\x91\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed92[] = {
+ "\xed\x92\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed93[] = {
+ "\xed\x93\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed94[] = {
+ "\xed\x94\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed95[] = {
+ "\xed\x95\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed96[] = {
+ "\xed\x96\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x86"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed97[] = {
+ "\xed\x97\xa2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xbe"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed98[] = {
+ "\xed\x98\x9a", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb6", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x92"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed99[] = {
+ "\xed\x99\xae", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x8a"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed9a[] = {
+ "\xed\x9a\xa6", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\x82"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed9b[] = {
+ "\xed\x9b\x9e", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xba", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x96"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed9c[] = {
+ "\xed\x9c\xb2", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x8e"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18781_table_ed9d[] = {
+ "\xed\x9d\xaa", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x86"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e18781(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18781_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\xa2";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab0[] = {
+ "\xea\xb0\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb0\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb1\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab1[] = {
+ "\xea\xb1\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb2\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab2[] = {
+ "\xea\xb2\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab3[] = {
+ "\xea\xb3\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb3\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb4\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab4[] = {
+ "\xea\xb4\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb5\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab5[] = {
+ "\xea\xb5\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab6[] = {
+ "\xea\xb6\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb6\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab7[] = {
+ "\xea\xb7\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb7\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xb8\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab8[] = {
+ "\xea\xb8\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xb9\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eab9[] = {
+ "\xea\xb9\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eaba[] = {
+ "\xea\xba\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xba\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbb\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eabb[] = {
+ "\xea\xbb\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbc\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eabc[] = {
+ "\xea\xbc\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eabd[] = {
+ "\xea\xbd\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbd\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eabe[] = {
+ "\xea\xbe\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xea\xbe\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xea\xbf\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eabf[] = {
+ "\xea\xbf\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x80\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb80[] = {
+ "\xeb\x80\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb81[] = {
+ "\xeb\x81\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x81\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x82\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb82[] = {
+ "\xeb\x82\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x83\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb83[] = {
+ "\xeb\x83\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb84[] = {
+ "\xeb\x84\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x84\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb85[] = {
+ "\xeb\x85\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x85\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x86\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb86[] = {
+ "\xeb\x86\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x87\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb87[] = {
+ "\xeb\x87\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb88[] = {
+ "\xeb\x88\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x88\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x89\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb89[] = {
+ "\xeb\x89\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8a\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb8a[] = {
+ "\xeb\x8a\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb8b[] = {
+ "\xeb\x8b\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8b\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb8c[] = {
+ "\xeb\x8c\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8c\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x8d\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb8d[] = {
+ "\xeb\x8d\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8e\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb8e[] = {
+ "\xeb\x8e\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb8f[] = {
+ "\xeb\x8f\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x8f\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x90\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb90[] = {
+ "\xeb\x90\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x91\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb91[] = {
+ "\xeb\x91\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb92[] = {
+ "\xeb\x92\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x92\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb93[] = {
+ "\xeb\x93\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x93\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x94\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb94[] = {
+ "\xeb\x94\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x95\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb95[] = {
+ "\xeb\x95\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb96[] = {
+ "\xeb\x96\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x96\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x97\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb97[] = {
+ "\xeb\x97\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x98\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb98[] = {
+ "\xeb\x98\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb99[] = {
+ "\xeb\x99\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x99\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb9a[] = {
+ "\xeb\x9a\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9a\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9b\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb9b[] = {
+ "\xeb\x9b\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9c\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb9c[] = {
+ "\xeb\x9c\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb9d[] = {
+ "\xeb\x9d\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9d\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\x9e\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb9e[] = {
+ "\xeb\x9e\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\x9f\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eb9f[] = {
+ "\xeb\x9f\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba0[] = {
+ "\xeb\xa0\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa0\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba1[] = {
+ "\xeb\xa1\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa1\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa2\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba2[] = {
+ "\xeb\xa2\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa3\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba3[] = {
+ "\xeb\xa3\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba4[] = {
+ "\xeb\xa4\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa4\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa5\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba5[] = {
+ "\xeb\xa5\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa6\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba6[] = {
+ "\xeb\xa6\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba7[] = {
+ "\xeb\xa7\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa7\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba8[] = {
+ "\xeb\xa8\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xa8\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xa9\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eba9[] = {
+ "\xeb\xa9\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaa\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebaa[] = {
+ "\xeb\xaa\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebab[] = {
+ "\xeb\xab\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xab\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xac\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebac[] = {
+ "\xeb\xac\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xad\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebad[] = {
+ "\xeb\xad\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebae[] = {
+ "\xeb\xae\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xae\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebaf[] = {
+ "\xeb\xaf\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xaf\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb0\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb0[] = {
+ "\xeb\xb0\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb1\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb1[] = {
+ "\xeb\xb1\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb2[] = {
+ "\xeb\xb2\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb2\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb3\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb3[] = {
+ "\xeb\xb3\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb4\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb4[] = {
+ "\xeb\xb4\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb5[] = {
+ "\xeb\xb5\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb5\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb6[] = {
+ "\xeb\xb6\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb6\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xb7\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb7[] = {
+ "\xeb\xb7\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb8\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb8[] = {
+ "\xeb\xb8\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebb9[] = {
+ "\xeb\xb9\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xb9\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xba\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebba[] = {
+ "\xeb\xba\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbb\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebbb[] = {
+ "\xeb\xbb\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebbc[] = {
+ "\xeb\xbc\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbc\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebbd[] = {
+ "\xeb\xbd\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbd\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xeb\xbe\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebbe[] = {
+ "\xeb\xbe\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xeb\xbf\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ebbf[] = {
+ "\xeb\xbf\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec80[] = {
+ "\xec\x80\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x80\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x81\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec81[] = {
+ "\xec\x81\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x82\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec82[] = {
+ "\xec\x82\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec83[] = {
+ "\xec\x83\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x83\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec84[] = {
+ "\xec\x84\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x84\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x85\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec85[] = {
+ "\xec\x85\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x86\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec86[] = {
+ "\xec\x86\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec87[] = {
+ "\xec\x87\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x87\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x88\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec88[] = {
+ "\xec\x88\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x89\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec89[] = {
+ "\xec\x89\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec8a[] = {
+ "\xec\x8a\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8a\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec8b[] = {
+ "\xec\x8b\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8b\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8c\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec8c[] = {
+ "\xec\x8c\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8d\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec8d[] = {
+ "\xec\x8d\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec8e[] = {
+ "\xec\x8e\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x8e\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x8f\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec8f[] = {
+ "\xec\x8f\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x90\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec90[] = {
+ "\xec\x90\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec91[] = {
+ "\xec\x91\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x91\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec92[] = {
+ "\xec\x92\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x92\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x93\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec93[] = {
+ "\xec\x93\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x94\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec94[] = {
+ "\xec\x94\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec95[] = {
+ "\xec\x95\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x95\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x96\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec96[] = {
+ "\xec\x96\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x97\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec97[] = {
+ "\xec\x97\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec98[] = {
+ "\xec\x98\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x98\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec99[] = {
+ "\xec\x99\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x99\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9a\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec9a[] = {
+ "\xec\x9a\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9b\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec9b[] = {
+ "\xec\x9b\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec9c[] = {
+ "\xec\x9c\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9c\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\x9d\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec9d[] = {
+ "\xec\x9d\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9e\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec9e[] = {
+ "\xec\x9e\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ec9f[] = {
+ "\xec\x9f\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\x9f\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca0[] = {
+ "\xec\xa0\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa0\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa1\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca1[] = {
+ "\xec\xa1\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa2\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca2[] = {
+ "\xec\xa2\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca3[] = {
+ "\xec\xa3\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa3\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa4\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca4[] = {
+ "\xec\xa4\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa5\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca5[] = {
+ "\xec\xa5\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca6[] = {
+ "\xec\xa6\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa6\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca7[] = {
+ "\xec\xa7\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa7\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xa8\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca8[] = {
+ "\xec\xa8\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xa9\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_eca9[] = {
+ "\xec\xa9\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecaa[] = {
+ "\xec\xaa\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xaa\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xab\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecab[] = {
+ "\xec\xab\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xac\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecac[] = {
+ "\xec\xac\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecad[] = {
+ "\xec\xad\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xad\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecae[] = {
+ "\xec\xae\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xae\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xaf\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecaf[] = {
+ "\xec\xaf\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb0\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb0[] = {
+ "\xec\xb0\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb1[] = {
+ "\xec\xb1\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb1\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb2\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb2[] = {
+ "\xec\xb2\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb3\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb3[] = {
+ "\xec\xb3\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb4[] = {
+ "\xec\xb4\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb4\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb5[] = {
+ "\xec\xb5\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb5\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb6\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb6[] = {
+ "\xec\xb6\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb7\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb7[] = {
+ "\xec\xb7\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb8[] = {
+ "\xec\xb8\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xb8\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xb9\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecb9[] = {
+ "\xec\xb9\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xba\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecba[] = {
+ "\xec\xba\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecbb[] = {
+ "\xec\xbb\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbb\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecbc[] = {
+ "\xec\xbc\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbc\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xec\xbd\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecbd[] = {
+ "\xec\xbd\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbe\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecbe[] = {
+ "\xec\xbe\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ecbf[] = {
+ "\xec\xbf\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xec\xbf\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x80\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed80[] = {
+ "\xed\x80\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x81\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed81[] = {
+ "\xed\x81\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed82[] = {
+ "\xed\x82\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x82\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed83[] = {
+ "\xed\x83\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x83\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x84\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed84[] = {
+ "\xed\x84\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x85\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed85[] = {
+ "\xed\x85\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed86[] = {
+ "\xed\x86\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x86\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x87\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed87[] = {
+ "\xed\x87\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x88\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed88[] = {
+ "\xed\x88\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed89[] = {
+ "\xed\x89\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x89\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed8a[] = {
+ "\xed\x8a\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8a\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8b\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed8b[] = {
+ "\xed\x8b\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8c\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed8c[] = {
+ "\xed\x8c\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed8d[] = {
+ "\xed\x8d\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8d\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x8e\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed8e[] = {
+ "\xed\x8e\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x8f\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed8f[] = {
+ "\xed\x8f\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed90[] = {
+ "\xed\x90\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x90\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed91[] = {
+ "\xed\x91\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x91\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x92\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed92[] = {
+ "\xed\x92\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x93\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed93[] = {
+ "\xed\x93\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed94[] = {
+ "\xed\x94\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x94\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x95\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed95[] = {
+ "\xed\x95\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x96\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed96[] = {
+ "\xed\x96\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\x87"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed97[] = {
+ "\xed\x97\xa3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x97\xbf"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed98[] = {
+ "\xed\x98\x9b", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x98\xb7", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x99\x93"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed99[] = {
+ "\xed\x99\xaf", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9a\x8b"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed9a[] = {
+ "\xed\x9a\xa7", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\x83"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed9b[] = {
+ "\xed\x9b\x9f", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9b\xbb", NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ "\xed\x9c\x97"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed9c[] = {
+ "\xed\x9c\xb3", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9d\x8f"
+};
+
+static const char *grn_nfkc50_compose_prefix_e18782_table_ed9d[] = {
+ "\xed\x9d\xab", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, "\xed\x9e\x87"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e18782(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xea :
+ switch (utf8[1]) {
+ case 0xb0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eab9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eaba[utf8[2] - 0x84];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eabb[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eabc[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eabd[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eabe[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eabf[utf8[2] - 0x94];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xeb :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb80[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb81[utf8[2] - 0x84];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb82[utf8[2] - 0x98];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb83[utf8[2] - 0x90];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb84[utf8[2] - 0x88];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb85[utf8[2] - 0x80];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb86[utf8[2] - 0x94];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb87[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb88[utf8[2] - 0x84];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb89[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb8a[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb8b[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb8c[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb8d[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb8e[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb8f[utf8[2] - 0x84];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb90[utf8[2] - 0x98];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb91[utf8[2] - 0x90];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb92[utf8[2] - 0x88];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb93[utf8[2] - 0x80];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb94[utf8[2] - 0x94];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb95[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb96[utf8[2] - 0x84];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb97[utf8[2] - 0x98];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb98[utf8[2] - 0x90];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb99[utf8[2] - 0x88];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb9a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb9b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb9c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb9d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb9e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eb9f[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba0[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba1[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba2[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba3[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba4[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba5[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba6[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba7[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba8[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eba9[utf8[2] - 0x94];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebaa[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebab[utf8[2] - 0x84];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebac[utf8[2] - 0x98];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebad[utf8[2] - 0x90];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebae[utf8[2] - 0x88];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebaf[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb0[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb1[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb2[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb3[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb4[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb5[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb6[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb7[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb8[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebb9[utf8[2] - 0x84];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebba[utf8[2] - 0x98];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebbb[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebbc[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebbd[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebbe[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ebbf[utf8[2] - 0x8c];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xec :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec80[utf8[2] - 0x84];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec81[utf8[2] - 0x98];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec82[utf8[2] - 0x90];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec83[utf8[2] - 0x88];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec84[utf8[2] - 0x80];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec85[utf8[2] - 0x94];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec86[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec87[utf8[2] - 0x84];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec88[utf8[2] - 0x98];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec89[utf8[2] - 0x90];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec8a[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec8b[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec8c[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec8d[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec8e[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec8f[utf8[2] - 0x98];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec90[utf8[2] - 0x90];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec91[utf8[2] - 0x88];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec92[utf8[2] - 0x80];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec93[utf8[2] - 0x94];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec94[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec95[utf8[2] - 0x84];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec96[utf8[2] - 0x98];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec97[utf8[2] - 0x90];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec98[utf8[2] - 0x88];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec99[utf8[2] - 0x80];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec9a[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec9b[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec9c[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec9d[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec9e[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9f :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ec9f[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa0 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca0[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa1 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca1[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa2 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca2[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xa3 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca3[utf8[2] - 0x84];
+ }
+ break;
+ case 0xa4 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca4[utf8[2] - 0x98];
+ }
+ break;
+ case 0xa5 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca5[utf8[2] - 0x90];
+ }
+ break;
+ case 0xa6 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca6[utf8[2] - 0x88];
+ }
+ break;
+ case 0xa7 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca7[utf8[2] - 0x80];
+ }
+ break;
+ case 0xa8 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca8[utf8[2] - 0x94];
+ }
+ break;
+ case 0xa9 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_eca9[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xaa :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecaa[utf8[2] - 0x84];
+ }
+ break;
+ case 0xab :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecab[utf8[2] - 0x98];
+ }
+ break;
+ case 0xac :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecac[utf8[2] - 0x90];
+ }
+ break;
+ case 0xad :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecad[utf8[2] - 0x88];
+ }
+ break;
+ case 0xae :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecae[utf8[2] - 0x80];
+ }
+ break;
+ case 0xaf :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecaf[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb0 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb0[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb1 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb1[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb2 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb2[utf8[2] - 0x98];
+ }
+ break;
+ case 0xb3 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb3[utf8[2] - 0x90];
+ }
+ break;
+ case 0xb4 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb4[utf8[2] - 0x88];
+ }
+ break;
+ case 0xb5 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb5[utf8[2] - 0x80];
+ }
+ break;
+ case 0xb6 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb6[utf8[2] - 0x94];
+ }
+ break;
+ case 0xb7 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb7[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xb8 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb8[utf8[2] - 0x84];
+ }
+ break;
+ case 0xb9 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecb9[utf8[2] - 0x98];
+ }
+ break;
+ case 0xba :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecba[utf8[2] - 0x90];
+ }
+ break;
+ case 0xbb :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecbb[utf8[2] - 0x88];
+ }
+ break;
+ case 0xbc :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecbc[utf8[2] - 0x80];
+ }
+ break;
+ case 0xbd :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecbd[utf8[2] - 0x94];
+ }
+ break;
+ case 0xbe :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecbe[utf8[2] - 0x8c];
+ }
+ break;
+ case 0xbf :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ecbf[utf8[2] - 0x84];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xed :
+ switch (utf8[1]) {
+ case 0x80 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed80[utf8[2] - 0x98];
+ }
+ break;
+ case 0x81 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed81[utf8[2] - 0x90];
+ }
+ break;
+ case 0x82 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed82[utf8[2] - 0x88];
+ }
+ break;
+ case 0x83 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed83[utf8[2] - 0x80];
+ }
+ break;
+ case 0x84 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed84[utf8[2] - 0x94];
+ }
+ break;
+ case 0x85 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed85[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x86 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed86[utf8[2] - 0x84];
+ }
+ break;
+ case 0x87 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed87[utf8[2] - 0x98];
+ }
+ break;
+ case 0x88 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed88[utf8[2] - 0x90];
+ }
+ break;
+ case 0x89 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed89[utf8[2] - 0x88];
+ }
+ break;
+ case 0x8a :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed8a[utf8[2] - 0x80];
+ }
+ break;
+ case 0x8b :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed8b[utf8[2] - 0x94];
+ }
+ break;
+ case 0x8c :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed8c[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x8d :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed8d[utf8[2] - 0x84];
+ }
+ break;
+ case 0x8e :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed8e[utf8[2] - 0x98];
+ }
+ break;
+ case 0x8f :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed8f[utf8[2] - 0x90];
+ }
+ break;
+ case 0x90 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed90[utf8[2] - 0x88];
+ }
+ break;
+ case 0x91 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed91[utf8[2] - 0x80];
+ }
+ break;
+ case 0x92 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed92[utf8[2] - 0x94];
+ }
+ break;
+ case 0x93 :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed93[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x94 :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed94[utf8[2] - 0x84];
+ }
+ break;
+ case 0x95 :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed95[utf8[2] - 0x98];
+ }
+ break;
+ case 0x96 :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed96[utf8[2] - 0x90];
+ }
+ break;
+ case 0x97 :
+ if (utf8[2] >= 0x88 &&
+ utf8[2] <= 0xa4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed97[utf8[2] - 0x88];
+ }
+ break;
+ case 0x98 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0xb8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed98[utf8[2] - 0x80];
+ }
+ break;
+ case 0x99 :
+ if (utf8[2] >= 0x94 &&
+ utf8[2] <= 0xb0) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed99[utf8[2] - 0x94];
+ }
+ break;
+ case 0x9a :
+ if (utf8[2] >= 0x8c &&
+ utf8[2] <= 0xa8) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed9a[utf8[2] - 0x8c];
+ }
+ break;
+ case 0x9b :
+ if (utf8[2] >= 0x84 &&
+ utf8[2] <= 0xbc) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed9b[utf8[2] - 0x84];
+ }
+ break;
+ case 0x9c :
+ if (utf8[2] >= 0x98 &&
+ utf8[2] <= 0xb4) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed9c[utf8[2] - 0x98];
+ }
+ break;
+ case 0x9d :
+ if (utf8[2] >= 0x90 &&
+ utf8[2] <= 0xac) {
+ return grn_nfkc50_compose_prefix_e18782_table_ed9d[utf8[2] - 0x90];
+ }
+ break;
+ case 0x9e :
+ if (utf8[2] == 0x88) {
+ return "\xed\x9e\xa3";
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a2_table_e184[] = {
+ "\xea\xb0\x9c", "\xea\xb9\xa8", "\xeb\x82\xb4", "\xeb\x8c\x80", "\xeb\x95\x8c", "\xeb\x9e\x98", "\xeb\xa7\xa4", "\xeb\xb0\xb0",
+ "\xeb\xb9\xbc", "\xec\x83\x88", "\xec\x8c\x94", "\xec\x95\xa0", "\xec\x9e\xac", "\xec\xa7\xb8", "\xec\xb1\x84", "\xec\xba\x90",
+ "\xed\x83\x9c", "\xed\x8c\xa8", "\xed\x95\xb4"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a2(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a2_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a3_table_e184[] = {
+ "\xea\xb0\xb8", "\xea\xba\x84", "\xeb\x83\x90", "\xeb\x8c\x9c", "\xeb\x95\xa8", "\xeb\x9e\xb4", "\xeb\xa8\x80", "\xeb\xb1\x8c",
+ "\xeb\xba\x98", "\xec\x83\xa4", "\xec\x8c\xb0", "\xec\x95\xbc", "\xec\x9f\x88", "\xec\xa8\x94", "\xec\xb1\xa0", "\xec\xba\xac",
+ "\xed\x83\xb8", "\xed\x8d\x84", "\xed\x96\x90"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a3(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a3_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a4_table_e184[] = {
+ "\xea\xb1\x94", "\xea\xba\xa0", "\xeb\x83\xac", "\xeb\x8c\xb8", "\xeb\x96\x84", "\xeb\x9f\x90", "\xeb\xa8\x9c", "\xeb\xb1\xa8",
+ "\xeb\xba\xb4", "\xec\x84\x80", "\xec\x8d\x8c", "\xec\x96\x98", "\xec\x9f\xa4", "\xec\xa8\xb0", "\xec\xb1\xbc", "\xec\xbb\x88",
+ "\xed\x84\x94", "\xed\x8d\xa0", "\xed\x96\xac"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a4(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a4_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a5_table_e184[] = {
+ "\xea\xb1\xb0", "\xea\xba\xbc", "\xeb\x84\x88", "\xeb\x8d\x94", "\xeb\x96\xa0", "\xeb\x9f\xac", "\xeb\xa8\xb8", "\xeb\xb2\x84",
+ "\xeb\xbb\x90", "\xec\x84\x9c", "\xec\x8d\xa8", "\xec\x96\xb4", "\xec\xa0\x80", "\xec\xa9\x8c", "\xec\xb2\x98", "\xec\xbb\xa4",
+ "\xed\x84\xb0", "\xed\x8d\xbc", "\xed\x97\x88"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a5(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a5_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a6_table_e184[] = {
+ "\xea\xb2\x8c", "\xea\xbb\x98", "\xeb\x84\xa4", "\xeb\x8d\xb0", "\xeb\x96\xbc", "\xeb\xa0\x88", "\xeb\xa9\x94", "\xeb\xb2\xa0",
+ "\xeb\xbb\xac", "\xec\x84\xb8", "\xec\x8e\x84", "\xec\x97\x90", "\xec\xa0\x9c", "\xec\xa9\xa8", "\xec\xb2\xb4", "\xec\xbc\x80",
+ "\xed\x85\x8c", "\xed\x8e\x98", "\xed\x97\xa4"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a6(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a6_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a7_table_e184[] = {
+ "\xea\xb2\xa8", "\xea\xbb\xb4", "\xeb\x85\x80", "\xeb\x8e\x8c", "\xeb\x97\x98", "\xeb\xa0\xa4", "\xeb\xa9\xb0", "\xeb\xb2\xbc",
+ "\xeb\xbc\x88", "\xec\x85\x94", "\xec\x8e\xa0", "\xec\x97\xac", "\xec\xa0\xb8", "\xec\xaa\x84", "\xec\xb3\x90", "\xec\xbc\x9c",
+ "\xed\x85\xa8", "\xed\x8e\xb4", "\xed\x98\x80"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a7(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a7_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a8_table_e184[] = {
+ "\xea\xb3\x84", "\xea\xbc\x90", "\xeb\x85\x9c", "\xeb\x8e\xa8", "\xeb\x97\xb4", "\xeb\xa1\x80", "\xeb\xaa\x8c", "\xeb\xb3\x98",
+ "\xeb\xbc\xa4", "\xec\x85\xb0", "\xec\x8e\xbc", "\xec\x98\x88", "\xec\xa1\x94", "\xec\xaa\xa0", "\xec\xb3\xac", "\xec\xbc\xb8",
+ "\xed\x86\x84", "\xed\x8f\x90", "\xed\x98\x9c"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a8(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a8_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185a9_table_e184[] = {
+ "\xea\xb3\xa0", "\xea\xbc\xac", "\xeb\x85\xb8", "\xeb\x8f\x84", "\xeb\x98\x90", "\xeb\xa1\x9c", "\xeb\xaa\xa8", "\xeb\xb3\xb4",
+ "\xeb\xbd\x80", "\xec\x86\x8c", "\xec\x8f\x98", "\xec\x98\xa4", "\xec\xa1\xb0", "\xec\xaa\xbc", "\xec\xb4\x88", "\xec\xbd\x94",
+ "\xed\x86\xa0", "\xed\x8f\xac", "\xed\x98\xb8"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185a9(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185a9_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185aa_table_e184[] = {
+ "\xea\xb3\xbc", "\xea\xbd\x88", "\xeb\x86\x94", "\xeb\x8f\xa0", "\xeb\x98\xac", "\xeb\xa1\xb8", "\xeb\xab\x84", "\xeb\xb4\x90",
+ "\xeb\xbd\x9c", "\xec\x86\xa8", "\xec\x8f\xb4", "\xec\x99\x80", "\xec\xa2\x8c", "\xec\xab\x98", "\xec\xb4\xa4", "\xec\xbd\xb0",
+ "\xed\x86\xbc", "\xed\x90\x88", "\xed\x99\x94"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185aa(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185aa_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185ab_table_e184[] = {
+ "\xea\xb4\x98", "\xea\xbd\xa4", "\xeb\x86\xb0", "\xeb\x8f\xbc", "\xeb\x99\x88", "\xeb\xa2\x94", "\xeb\xab\xa0", "\xeb\xb4\xac",
+ "\xeb\xbd\xb8", "\xec\x87\x84", "\xec\x90\x90", "\xec\x99\x9c", "\xec\xa2\xa8", "\xec\xab\xb4", "\xec\xb5\x80", "\xec\xbe\x8c",
+ "\xed\x87\x98", "\xed\x90\xa4", "\xed\x99\xb0"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185ab(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185ab_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185ac_table_e184[] = {
+ "\xea\xb4\xb4", "\xea\xbe\x80", "\xeb\x87\x8c", "\xeb\x90\x98", "\xeb\x99\xa4", "\xeb\xa2\xb0", "\xeb\xab\xbc", "\xeb\xb5\x88",
+ "\xeb\xbe\x94", "\xec\x87\xa0", "\xec\x90\xac", "\xec\x99\xb8", "\xec\xa3\x84", "\xec\xac\x90", "\xec\xb5\x9c", "\xec\xbe\xa8",
+ "\xed\x87\xb4", "\xed\x91\x80", "\xed\x9a\x8c"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185ac(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185ac_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185ad_table_e184[] = {
+ "\xea\xb5\x90", "\xea\xbe\x9c", "\xeb\x87\xa8", "\xeb\x90\xb4", "\xeb\x9a\x80", "\xeb\xa3\x8c", "\xeb\xac\x98", "\xeb\xb5\xa4",
+ "\xeb\xbe\xb0", "\xec\x87\xbc", "\xec\x91\x88", "\xec\x9a\x94", "\xec\xa3\xa0", "\xec\xac\xac", "\xec\xb5\xb8", "\xec\xbf\x84",
+ "\xed\x88\x90", "\xed\x91\x9c", "\xed\x9a\xa8"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185ad(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185ad_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185ae_table_e184[] = {
+ "\xea\xb5\xac", "\xea\xbe\xb8", "\xeb\x88\x84", "\xeb\x91\x90", "\xeb\x9a\x9c", "\xeb\xa3\xa8", "\xeb\xac\xb4", "\xeb\xb6\x80",
+ "\xeb\xbf\x8c", "\xec\x88\x98", "\xec\x91\xa4", "\xec\x9a\xb0", "\xec\xa3\xbc", "\xec\xad\x88", "\xec\xb6\x94", "\xec\xbf\xa0",
+ "\xed\x88\xac", "\xed\x91\xb8", "\xed\x9b\x84"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185ae(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185ae_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185af_table_e184[] = {
+ "\xea\xb6\x88", "\xea\xbf\x94", "\xeb\x88\xa0", "\xeb\x91\xac", "\xeb\x9a\xb8", "\xeb\xa4\x84", "\xeb\xad\x90", "\xeb\xb6\x9c",
+ "\xeb\xbf\xa8", "\xec\x88\xb4", "\xec\x92\x80", "\xec\x9b\x8c", "\xec\xa4\x98", "\xec\xad\xa4", "\xec\xb6\xb0", "\xec\xbf\xbc",
+ "\xed\x89\x88", "\xed\x92\x94", "\xed\x9b\xa0"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185af(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185af_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185b0_table_e184[] = {
+ "\xea\xb6\xa4", "\xea\xbf\xb0", "\xeb\x88\xbc", "\xeb\x92\x88", "\xeb\x9b\x94", "\xeb\xa4\xa0", "\xeb\xad\xac", "\xeb\xb6\xb8",
+ "\xec\x80\x84", "\xec\x89\x90", "\xec\x92\x9c", "\xec\x9b\xa8", "\xec\xa4\xb4", "\xec\xae\x80", "\xec\xb7\x8c", "\xed\x80\x98",
+ "\xed\x89\xa4", "\xed\x92\xb0", "\xed\x9b\xbc"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185b0(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185b0_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185b1_table_e184[] = {
+ "\xea\xb7\x80", "\xeb\x80\x8c", "\xeb\x89\x98", "\xeb\x92\xa4", "\xeb\x9b\xb0", "\xeb\xa4\xbc", "\xeb\xae\x88", "\xeb\xb7\x94",
+ "\xec\x80\xa0", "\xec\x89\xac", "\xec\x92\xb8", "\xec\x9c\x84", "\xec\xa5\x90", "\xec\xae\x9c", "\xec\xb7\xa8", "\xed\x80\xb4",
+ "\xed\x8a\x80", "\xed\x93\x8c", "\xed\x9c\x98"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185b1(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185b1_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185b2_table_e184[] = {
+ "\xea\xb7\x9c", "\xeb\x80\xa8", "\xeb\x89\xb4", "\xeb\x93\x80", "\xeb\x9c\x8c", "\xeb\xa5\x98", "\xeb\xae\xa4", "\xeb\xb7\xb0",
+ "\xec\x80\xbc", "\xec\x8a\x88", "\xec\x93\x94", "\xec\x9c\xa0", "\xec\xa5\xac", "\xec\xae\xb8", "\xec\xb8\x84", "\xed\x81\x90",
+ "\xed\x8a\x9c", "\xed\x93\xa8", "\xed\x9c\xb4"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185b2(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185b2_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185b3_table_e184[] = {
+ "\xea\xb7\xb8", "\xeb\x81\x84", "\xeb\x8a\x90", "\xeb\x93\x9c", "\xeb\x9c\xa8", "\xeb\xa5\xb4", "\xeb\xaf\x80", "\xeb\xb8\x8c",
+ "\xec\x81\x98", "\xec\x8a\xa4", "\xec\x93\xb0", "\xec\x9c\xbc", "\xec\xa6\x88", "\xec\xaf\x94", "\xec\xb8\xa0", "\xed\x81\xac",
+ "\xed\x8a\xb8", "\xed\x94\x84", "\xed\x9d\x90"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185b3(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185b3_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185b4_table_e184[] = {
+ "\xea\xb8\x94", "\xeb\x81\xa0", "\xeb\x8a\xac", "\xeb\x93\xb8", "\xeb\x9d\x84", "\xeb\xa6\x90", "\xeb\xaf\x9c", "\xeb\xb8\xa8",
+ "\xec\x81\xb4", "\xec\x8b\x80", "\xec\x94\x8c", "\xec\x9d\x98", "\xec\xa6\xa4", "\xec\xaf\xb0", "\xec\xb8\xbc", "\xed\x82\x88",
+ "\xed\x8b\x94", "\xed\x94\xa0", "\xed\x9d\xac"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185b4(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185b4_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static const char *grn_nfkc50_compose_prefix_e185b5_table_e184[] = {
+ "\xea\xb8\xb0", "\xeb\x81\xbc", "\xeb\x8b\x88", "\xeb\x94\x94", "\xeb\x9d\xa0", "\xeb\xa6\xac", "\xeb\xaf\xb8", "\xeb\xb9\x84",
+ "\xec\x82\x90", "\xec\x8b\x9c", "\xec\x94\xa8", "\xec\x9d\xb4", "\xec\xa7\x80", "\xec\xb0\x8c", "\xec\xb9\x98", "\xed\x82\xa4",
+ "\xed\x8b\xb0", "\xed\x94\xbc", "\xed\x9e\x88"
+};
+
+static inline const char *
+grn_nfkc50_compose_prefix_e185b5(const unsigned char *utf8)
+{
+ {
+ switch (utf8[0]) {
+ case 0xe1 :
+ switch (utf8[1]) {
+ case 0x84 :
+ if (utf8[2] >= 0x80 &&
+ utf8[2] <= 0x92) {
+ return grn_nfkc50_compose_prefix_e185b5_table_e184[utf8[2] - 0x80];
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+const char *
+grn_nfkc50_compose(const unsigned char *prefix_utf8, const unsigned char *suffix_utf8)
+{
+ {
+ switch (suffix_utf8[0]) {
+ case 0xcc :
+ switch (suffix_utf8[1]) {
+ case 0x80 :
+ return grn_nfkc50_compose_prefix_cc80(prefix_utf8);
+ case 0x81 :
+ return grn_nfkc50_compose_prefix_cc81(prefix_utf8);
+ case 0x82 :
+ return grn_nfkc50_compose_prefix_cc82(prefix_utf8);
+ case 0x83 :
+ return grn_nfkc50_compose_prefix_cc83(prefix_utf8);
+ case 0x88 :
+ return grn_nfkc50_compose_prefix_cc88(prefix_utf8);
+ case 0x8a :
+ return grn_nfkc50_compose_prefix_cc8a(prefix_utf8);
+ case 0xa7 :
+ return grn_nfkc50_compose_prefix_cca7(prefix_utf8);
+ case 0x84 :
+ return grn_nfkc50_compose_prefix_cc84(prefix_utf8);
+ case 0x86 :
+ return grn_nfkc50_compose_prefix_cc86(prefix_utf8);
+ case 0xa8 :
+ return grn_nfkc50_compose_prefix_cca8(prefix_utf8);
+ case 0x87 :
+ return grn_nfkc50_compose_prefix_cc87(prefix_utf8);
+ case 0x8c :
+ return grn_nfkc50_compose_prefix_cc8c(prefix_utf8);
+ case 0x8b :
+ return grn_nfkc50_compose_prefix_cc8b(prefix_utf8);
+ case 0x9b :
+ return grn_nfkc50_compose_prefix_cc9b(prefix_utf8);
+ case 0x8f :
+ return grn_nfkc50_compose_prefix_cc8f(prefix_utf8);
+ case 0x91 :
+ return grn_nfkc50_compose_prefix_cc91(prefix_utf8);
+ case 0xa6 :
+ return grn_nfkc50_compose_prefix_cca6(prefix_utf8);
+ case 0xa5 :
+ return grn_nfkc50_compose_prefix_cca5(prefix_utf8);
+ case 0xa3 :
+ return grn_nfkc50_compose_prefix_cca3(prefix_utf8);
+ case 0xb1 :
+ return grn_nfkc50_compose_prefix_ccb1(prefix_utf8);
+ case 0xad :
+ return grn_nfkc50_compose_prefix_ccad(prefix_utf8);
+ case 0xb0 :
+ return grn_nfkc50_compose_prefix_ccb0(prefix_utf8);
+ case 0xae :
+ return grn_nfkc50_compose_prefix_ccae(prefix_utf8);
+ case 0xa4 :
+ return grn_nfkc50_compose_prefix_cca4(prefix_utf8);
+ case 0x89 :
+ return grn_nfkc50_compose_prefix_cc89(prefix_utf8);
+ case 0x93 :
+ return grn_nfkc50_compose_prefix_cc93(prefix_utf8);
+ case 0x94 :
+ return grn_nfkc50_compose_prefix_cc94(prefix_utf8);
+ case 0xb8 :
+ return grn_nfkc50_compose_prefix_ccb8(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xcd :
+ switch (suffix_utf8[1]) {
+ case 0x82 :
+ return grn_nfkc50_compose_prefix_cd82(prefix_utf8);
+ case 0x85 :
+ return grn_nfkc50_compose_prefix_cd85(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xd9 :
+ switch (suffix_utf8[1]) {
+ case 0x93 :
+ return grn_nfkc50_compose_prefix_d993(prefix_utf8);
+ case 0x94 :
+ return grn_nfkc50_compose_prefix_d994(prefix_utf8);
+ case 0x95 :
+ return grn_nfkc50_compose_prefix_d995(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xe0 :
+ switch (suffix_utf8[1]) {
+ case 0xa4 :
+ switch (suffix_utf8[2]) {
+ case 0xbc :
+ return grn_nfkc50_compose_prefix_e0a4bc(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xa6 :
+ switch (suffix_utf8[2]) {
+ case 0xbe :
+ return grn_nfkc50_compose_prefix_e0a6be(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xa7 :
+ switch (suffix_utf8[2]) {
+ case 0x97 :
+ return grn_nfkc50_compose_prefix_e0a797(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xac :
+ switch (suffix_utf8[2]) {
+ case 0xbe :
+ return grn_nfkc50_compose_prefix_e0acbe(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xad :
+ switch (suffix_utf8[2]) {
+ case 0x96 :
+ return grn_nfkc50_compose_prefix_e0ad96(prefix_utf8);
+ case 0x97 :
+ return grn_nfkc50_compose_prefix_e0ad97(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xae :
+ switch (suffix_utf8[2]) {
+ case 0xbe :
+ return grn_nfkc50_compose_prefix_e0aebe(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xaf :
+ switch (suffix_utf8[2]) {
+ case 0x97 :
+ return grn_nfkc50_compose_prefix_e0af97(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xb1 :
+ switch (suffix_utf8[2]) {
+ case 0x96 :
+ return grn_nfkc50_compose_prefix_e0b196(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xb3 :
+ switch (suffix_utf8[2]) {
+ case 0x95 :
+ return grn_nfkc50_compose_prefix_e0b395(prefix_utf8);
+ case 0x96 :
+ return grn_nfkc50_compose_prefix_e0b396(prefix_utf8);
+ case 0x82 :
+ return grn_nfkc50_compose_prefix_e0b382(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xb4 :
+ switch (suffix_utf8[2]) {
+ case 0xbe :
+ return grn_nfkc50_compose_prefix_e0b4be(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xb5 :
+ switch (suffix_utf8[2]) {
+ case 0x97 :
+ return grn_nfkc50_compose_prefix_e0b597(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xb7 :
+ switch (suffix_utf8[2]) {
+ case 0x8a :
+ return grn_nfkc50_compose_prefix_e0b78a(prefix_utf8);
+ case 0x8f :
+ return grn_nfkc50_compose_prefix_e0b78f(prefix_utf8);
+ case 0x9f :
+ return grn_nfkc50_compose_prefix_e0b79f(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe1 :
+ switch (suffix_utf8[1]) {
+ case 0x80 :
+ switch (suffix_utf8[2]) {
+ case 0xae :
+ return grn_nfkc50_compose_prefix_e180ae(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0x85 :
+ switch (suffix_utf8[2]) {
+ case 0xa1 :
+ return grn_nfkc50_compose_prefix_e185a1(prefix_utf8);
+ case 0xa2 :
+ return grn_nfkc50_compose_prefix_e185a2(prefix_utf8);
+ case 0xa3 :
+ return grn_nfkc50_compose_prefix_e185a3(prefix_utf8);
+ case 0xa4 :
+ return grn_nfkc50_compose_prefix_e185a4(prefix_utf8);
+ case 0xa5 :
+ return grn_nfkc50_compose_prefix_e185a5(prefix_utf8);
+ case 0xa6 :
+ return grn_nfkc50_compose_prefix_e185a6(prefix_utf8);
+ case 0xa7 :
+ return grn_nfkc50_compose_prefix_e185a7(prefix_utf8);
+ case 0xa8 :
+ return grn_nfkc50_compose_prefix_e185a8(prefix_utf8);
+ case 0xa9 :
+ return grn_nfkc50_compose_prefix_e185a9(prefix_utf8);
+ case 0xaa :
+ return grn_nfkc50_compose_prefix_e185aa(prefix_utf8);
+ case 0xab :
+ return grn_nfkc50_compose_prefix_e185ab(prefix_utf8);
+ case 0xac :
+ return grn_nfkc50_compose_prefix_e185ac(prefix_utf8);
+ case 0xad :
+ return grn_nfkc50_compose_prefix_e185ad(prefix_utf8);
+ case 0xae :
+ return grn_nfkc50_compose_prefix_e185ae(prefix_utf8);
+ case 0xaf :
+ return grn_nfkc50_compose_prefix_e185af(prefix_utf8);
+ case 0xb0 :
+ return grn_nfkc50_compose_prefix_e185b0(prefix_utf8);
+ case 0xb1 :
+ return grn_nfkc50_compose_prefix_e185b1(prefix_utf8);
+ case 0xb2 :
+ return grn_nfkc50_compose_prefix_e185b2(prefix_utf8);
+ case 0xb3 :
+ return grn_nfkc50_compose_prefix_e185b3(prefix_utf8);
+ case 0xb4 :
+ return grn_nfkc50_compose_prefix_e185b4(prefix_utf8);
+ case 0xb5 :
+ return grn_nfkc50_compose_prefix_e185b5(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0x86 :
+ switch (suffix_utf8[2]) {
+ case 0xa8 :
+ return grn_nfkc50_compose_prefix_e186a8(prefix_utf8);
+ case 0xa9 :
+ return grn_nfkc50_compose_prefix_e186a9(prefix_utf8);
+ case 0xaa :
+ return grn_nfkc50_compose_prefix_e186aa(prefix_utf8);
+ case 0xab :
+ return grn_nfkc50_compose_prefix_e186ab(prefix_utf8);
+ case 0xac :
+ return grn_nfkc50_compose_prefix_e186ac(prefix_utf8);
+ case 0xad :
+ return grn_nfkc50_compose_prefix_e186ad(prefix_utf8);
+ case 0xae :
+ return grn_nfkc50_compose_prefix_e186ae(prefix_utf8);
+ case 0xaf :
+ return grn_nfkc50_compose_prefix_e186af(prefix_utf8);
+ case 0xb0 :
+ return grn_nfkc50_compose_prefix_e186b0(prefix_utf8);
+ case 0xb1 :
+ return grn_nfkc50_compose_prefix_e186b1(prefix_utf8);
+ case 0xb2 :
+ return grn_nfkc50_compose_prefix_e186b2(prefix_utf8);
+ case 0xb3 :
+ return grn_nfkc50_compose_prefix_e186b3(prefix_utf8);
+ case 0xb4 :
+ return grn_nfkc50_compose_prefix_e186b4(prefix_utf8);
+ case 0xb5 :
+ return grn_nfkc50_compose_prefix_e186b5(prefix_utf8);
+ case 0xb6 :
+ return grn_nfkc50_compose_prefix_e186b6(prefix_utf8);
+ case 0xb7 :
+ return grn_nfkc50_compose_prefix_e186b7(prefix_utf8);
+ case 0xb8 :
+ return grn_nfkc50_compose_prefix_e186b8(prefix_utf8);
+ case 0xb9 :
+ return grn_nfkc50_compose_prefix_e186b9(prefix_utf8);
+ case 0xba :
+ return grn_nfkc50_compose_prefix_e186ba(prefix_utf8);
+ case 0xbb :
+ return grn_nfkc50_compose_prefix_e186bb(prefix_utf8);
+ case 0xbc :
+ return grn_nfkc50_compose_prefix_e186bc(prefix_utf8);
+ case 0xbd :
+ return grn_nfkc50_compose_prefix_e186bd(prefix_utf8);
+ case 0xbe :
+ return grn_nfkc50_compose_prefix_e186be(prefix_utf8);
+ case 0xbf :
+ return grn_nfkc50_compose_prefix_e186bf(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0x87 :
+ switch (suffix_utf8[2]) {
+ case 0x80 :
+ return grn_nfkc50_compose_prefix_e18780(prefix_utf8);
+ case 0x81 :
+ return grn_nfkc50_compose_prefix_e18781(prefix_utf8);
+ case 0x82 :
+ return grn_nfkc50_compose_prefix_e18782(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ case 0xac :
+ switch (suffix_utf8[2]) {
+ case 0xb5 :
+ return grn_nfkc50_compose_prefix_e1acb5(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ case 0xe3 :
+ switch (suffix_utf8[1]) {
+ case 0x82 :
+ switch (suffix_utf8[2]) {
+ case 0x99 :
+ return grn_nfkc50_compose_prefix_e38299(prefix_utf8);
+ case 0x9a :
+ return grn_nfkc50_compose_prefix_e3829a(prefix_utf8);
+ default :
+ return NULL;
+ }
+ break;
+ default :
+ break;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+#endif /* GRN_WITH_NFKC */
+
diff --git a/storage/mroonga/vendor/groonga/lib/normalizer.c b/storage/mroonga/vendor/groonga/lib/normalizer.c
new file mode 100644
index 00000000..86e72e13
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/normalizer.c
@@ -0,0 +1,1194 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+
+#include "grn_normalizer.h"
+#include "grn_string.h"
+#include "grn_nfkc.h"
+#include <groonga/normalizer.h>
+#include <groonga/tokenizer.h>
+
+grn_rc
+grn_normalizer_register(grn_ctx *ctx,
+ const char *name_ptr,
+ int name_length,
+ grn_proc_func *init,
+ grn_proc_func *next,
+ grn_proc_func *fin)
+{
+ grn_expr_var vars[1];
+ vars[0].name= 0;
+ vars[0].name_size= 0;
+
+ GRN_PTR_INIT(&vars[0].value, 0, GRN_ID_NIL);
+
+ if (name_length < 0) {
+ name_length = strlen(name_ptr);
+ }
+
+ {
+ grn_obj * const normalizer = grn_proc_create(ctx,
+ name_ptr, name_length,
+ GRN_PROC_NORMALIZER,
+ init, next, fin,
+ sizeof(*vars) / sizeof(vars),
+ vars);
+ if (!normalizer) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NORMALIZER_ERROR,
+ "[normalizer] failed to register normalizer: <%.*s>",
+ name_length, name_ptr);
+ return ctx->rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_normalizer_init(void)
+{
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_normalizer_fin(void)
+{
+ return GRN_SUCCESS;
+}
+
+static unsigned char symbol[] = {
+ ',', '.', 0, ':', ';', '?', '!', 0, 0, 0, '`', 0, '^', '~', '_', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, '-', '-', '/', '\\', 0, 0, '|', 0, 0, 0, '\'', 0,
+ '"', '(', ')', 0, 0, '[', ']', '{', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ '+', '-', 0, 0, 0, '=', 0, '<', '>', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ '$', 0, 0, '%', '#', '&', '*', '@', 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+inline static grn_obj *
+eucjp_normalize(grn_ctx *ctx, grn_string *nstr)
+{
+ static uint16_t hankana[] = {
+ 0xa1a1, 0xa1a3, 0xa1d6, 0xa1d7, 0xa1a2, 0xa1a6, 0xa5f2, 0xa5a1, 0xa5a3,
+ 0xa5a5, 0xa5a7, 0xa5a9, 0xa5e3, 0xa5e5, 0xa5e7, 0xa5c3, 0xa1bc, 0xa5a2,
+ 0xa5a4, 0xa5a6, 0xa5a8, 0xa5aa, 0xa5ab, 0xa5ad, 0xa5af, 0xa5b1, 0xa5b3,
+ 0xa5b5, 0xa5b7, 0xa5b9, 0xa5bb, 0xa5bd, 0xa5bf, 0xa5c1, 0xa5c4, 0xa5c6,
+ 0xa5c8, 0xa5ca, 0xa5cb, 0xa5cc, 0xa5cd, 0xa5ce, 0xa5cf, 0xa5d2, 0xa5d5,
+ 0xa5d8, 0xa5db, 0xa5de, 0xa5df, 0xa5e0, 0xa5e1, 0xa5e2, 0xa5e4, 0xa5e6,
+ 0xa5e8, 0xa5e9, 0xa5ea, 0xa5eb, 0xa5ec, 0xa5ed, 0xa5ef, 0xa5f3, 0xa1ab,
+ 0xa1eb
+ };
+ static unsigned char dakuten[] = {
+ 0xf4, 0, 0, 0, 0, 0xac, 0, 0xae, 0, 0xb0, 0, 0xb2, 0, 0xb4, 0, 0xb6, 0,
+ 0xb8, 0, 0xba, 0, 0xbc, 0, 0xbe, 0, 0xc0, 0, 0xc2, 0, 0, 0xc5, 0, 0xc7,
+ 0, 0xc9, 0, 0, 0, 0, 0, 0, 0xd0, 0, 0, 0xd3, 0, 0, 0xd6, 0, 0, 0xd9, 0,
+ 0, 0xdc
+ };
+ static unsigned char handaku[] = {
+ 0xd1, 0, 0, 0xd4, 0, 0, 0xd7, 0, 0, 0xda, 0, 0, 0xdd
+ };
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_, b;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->original_length_in_bytes, length = 0;
+ int removeblankp = nstr->flags & GRN_STRING_REMOVE_BLANK;
+ if (!(nstr->normalized = GRN_MALLOC(size * 2 + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][eucjp] failed to allocate normalized text space");
+ return NULL;
+ }
+ d0 = (unsigned char *) nstr->normalized;
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->normalized);
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][eucjp] failed to allocate checks space");
+ return NULL;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STRING_WITH_TYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->normalized);
+ nstr->checks = NULL;
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][eucjp] failed to allocate character types space");
+ return NULL;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->original + size;
+ for (s = s_ = (unsigned char *) nstr->original, d = d_ = d0; s < e; s++) {
+ if ((*s & 0x80)) {
+ if (((s + 1) < e) && (*(s + 1) & 0x80)) {
+ unsigned char c1 = *s++, c2 = *s, c3 = 0;
+ switch (c1 >> 4) {
+ case 0x08 :
+ if (c1 == 0x8e && 0xa0 <= c2 && c2 <= 0xdf) {
+ uint16_t c = hankana[c2 - 0xa0];
+ switch (c) {
+ case 0xa1ab :
+ if (d > d0 + 1 && d[-2] == 0xa5
+ && 0xa6 <= d[-1] && d[-1] <= 0xdb && (b = dakuten[d[-1] - 0xa6])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1] += 2; s_ += 2; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ case 0xa1eb :
+ if (d > d0 + 1 && d[-2] == 0xa5
+ && 0xcf <= d[-1] && d[-1] <= 0xdb && (b = handaku[d[-1] - 0xcf])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1] += 2; s_ += 2; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ default :
+ *d++ = c >> 8; *d = c & 0xff;
+ break;
+ }
+ ctype = GRN_CHAR_KATAKANA;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ case 0x09 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ case 0x0a :
+ switch (c1 & 0x0f) {
+ case 1 :
+ switch (c2) {
+ case 0xbc :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ break;
+ case 0xb9 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ break;
+ case 0xa1 :
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ break;
+ default :
+ if (c2 >= 0xa4 && (c3 = symbol[c2 - 0xa4])) {
+ *d = c3;
+ ctype = GRN_CHAR_SYMBOL;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ }
+ break;
+ case 2 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ break;
+ case 3 :
+ c3 = c2 - 0x80;
+ if ('a' <= c3 && c3 <= 'z') {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c3;
+ } else if ('A' <= c3 && c3 <= 'Z') {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c3 + 0x20;
+ } else if ('0' <= c3 && c3 <= '9') {
+ ctype = GRN_CHAR_DIGIT;
+ *d = c3;
+ } else {
+ ctype = GRN_CHAR_OTHERS;
+ *d++ = c1; *d = c2;
+ }
+ break;
+ case 4 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_HIRAGANA;
+ break;
+ case 5 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ break;
+ case 6 :
+ case 7 :
+ case 8 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ break;
+ default :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ break;
+ default :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ break;
+ }
+ } else {
+ /* skip invalid character */
+ continue;
+ }
+ } else {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->n_characters = length;
+ nstr->normalized_length_in_bytes = (size_t)(d - (unsigned char *)nstr->normalized);
+ return NULL;
+}
+
+inline static grn_obj *
+sjis_normalize(grn_ctx *ctx, grn_string *nstr)
+{
+ static uint16_t hankana[] = {
+ 0x8140, 0x8142, 0x8175, 0x8176, 0x8141, 0x8145, 0x8392, 0x8340, 0x8342,
+ 0x8344, 0x8346, 0x8348, 0x8383, 0x8385, 0x8387, 0x8362, 0x815b, 0x8341,
+ 0x8343, 0x8345, 0x8347, 0x8349, 0x834a, 0x834c, 0x834e, 0x8350, 0x8352,
+ 0x8354, 0x8356, 0x8358, 0x835a, 0x835c, 0x835e, 0x8360, 0x8363, 0x8365,
+ 0x8367, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d, 0x836e, 0x8371, 0x8374,
+ 0x8377, 0x837a, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8384, 0x8386,
+ 0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838f, 0x8393, 0x814a,
+ 0x814b
+ };
+ static unsigned char dakuten[] = {
+ 0x94, 0, 0, 0, 0, 0x4b, 0, 0x4d, 0, 0x4f, 0, 0x51, 0, 0x53, 0, 0x55, 0,
+ 0x57, 0, 0x59, 0, 0x5b, 0, 0x5d, 0, 0x5f, 0, 0x61, 0, 0, 0x64, 0, 0x66,
+ 0, 0x68, 0, 0, 0, 0, 0, 0, 0x6f, 0, 0, 0x72, 0, 0, 0x75, 0, 0, 0x78, 0,
+ 0, 0x7b
+ };
+ static unsigned char handaku[] = {
+ 0x70, 0, 0, 0x73, 0, 0, 0x76, 0, 0, 0x79, 0, 0, 0x7c
+ };
+ int16_t *ch;
+ const unsigned char *s, *s_;
+ unsigned char *d, *d0, *d_, b, *e;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->original_length_in_bytes, length = 0;
+ int removeblankp = nstr->flags & GRN_STRING_REMOVE_BLANK;
+ if (!(nstr->normalized = GRN_MALLOC(size * 2 + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][sjis] failed to allocate normalized text space");
+ return NULL;
+ }
+ d0 = (unsigned char *) nstr->normalized;
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->normalized);
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][sjis] failed to allocate checks space");
+ return NULL;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STRING_WITH_TYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->normalized);
+ nstr->checks = NULL;
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][sjis] failed to allocate character types space");
+ return NULL;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->original + size;
+ for (s = s_ = (unsigned char *) nstr->original, d = d_ = d0; s < e; s++) {
+ if ((*s & 0x80)) {
+ if (0xa0 <= *s && *s <= 0xdf) {
+ uint16_t c = hankana[*s - 0xa0];
+ switch (c) {
+ case 0x814a :
+ if (d > d0 + 1 && d[-2] == 0x83
+ && 0x45 <= d[-1] && d[-1] <= 0x7a && (b = dakuten[d[-1] - 0x45])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1]++; s_++; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ case 0x814b :
+ if (d > d0 + 1 && d[-2] == 0x83
+ && 0x6e <= d[-1] && d[-1] <= 0x7a && (b = handaku[d[-1] - 0x6e])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1]++; s_++; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ default :
+ *d++ = c >> 8; *d = c & 0xff;
+ break;
+ }
+ ctype = GRN_CHAR_KATAKANA;
+ } else {
+ if ((s + 1) < e && 0x40 <= *(s + 1) && *(s + 1) <= 0xfc) {
+ unsigned char c1 = *s++, c2 = *s, c3 = 0;
+ if (0x81 <= c1 && c1 <= 0x87) {
+ switch (c1 & 0x0f) {
+ case 1 :
+ switch (c2) {
+ case 0x5b :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ break;
+ case 0x58 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ break;
+ case 0x40 :
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ break;
+ default :
+ if (0x43 <= c2 && c2 <= 0x7e && (c3 = symbol[c2 - 0x43])) {
+ *d = c3;
+ ctype = GRN_CHAR_SYMBOL;
+ } else if (0x7f <= c2 && c2 <= 0x97 && (c3 = symbol[c2 - 0x44])) {
+ *d = c3;
+ ctype = GRN_CHAR_SYMBOL;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ }
+ break;
+ case 2 :
+ c3 = c2 - 0x1f;
+ if (0x4f <= c2 && c2 <= 0x58) {
+ ctype = GRN_CHAR_DIGIT;
+ *d = c2 - 0x1f;
+ } else if (0x60 <= c2 && c2 <= 0x79) {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c2 + 0x01;
+ } else if (0x81 <= c2 && c2 <= 0x9a) {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c2 - 0x20;
+ } else if (0x9f <= c2 && c2 <= 0xf1) {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_HIRAGANA;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ case 3 :
+ if (0x40 <= c2 && c2 <= 0x96) {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 4 :
+ case 7 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ break;
+ default :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ }
+ } else {
+ /* skip invalid character */
+ continue;
+ }
+ }
+ } else {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->n_characters = length;
+ nstr->normalized_length_in_bytes = (size_t)(d - (unsigned char *)nstr->normalized);
+ return NULL;
+}
+
+#ifdef GRN_WITH_NFKC
+static inline int
+grn_str_charlen_utf8(grn_ctx *ctx, const unsigned char *str, const unsigned char *end)
+{
+ /* MEMO: This function allows non-null-terminated string as str. */
+ /* But requires the end of string. */
+ const unsigned char *p = str;
+ if (end <= p || !*p) { return 0; }
+ if (*p & 0x80) {
+ int b, w;
+ int size;
+ int i;
+ for (b = 0x40, w = 0; b && (*p & b); b >>= 1, w++);
+ if (!w) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "invalid utf8 string: the first bit is 0x80: <%.*s>: <%.*s>",
+ (int)(end - p), p,
+ (int)(end - str), str);
+ return 0;
+ }
+ size = w + 1;
+ for (i = 1; i < size; i++) {
+ if (++p >= end) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "invalid utf8 string: too short: "
+ "%d byte is required but %d byte is given: <%.*s>",
+ size, i,
+ (int)(end - str), str);
+ return 0;
+ }
+ if (!*p) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "invalid utf8 string: NULL character is found: <%.*s>",
+ (int)(end - str), str);
+ return 0;
+ }
+ if ((*p & 0xc0) != 0x80) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "invalid utf8 string: 0x80 is not allowed: <%.*s>: <%.*s>",
+ (int)(end - p), p,
+ (int)(end - str), str);
+ return 0;
+ }
+ }
+ return size;
+ } else {
+ return 1;
+ }
+ return 0;
+}
+
+inline static grn_obj *
+utf8_normalize(grn_ctx *ctx, grn_string *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *s__ = NULL, *p, *p2, *pe, *e;
+ unsigned char *d, *d_, *de;
+ uint_least8_t *cp;
+ size_t length = 0, ls, lp, size = nstr->original_length_in_bytes, ds = size * 3;
+ int removeblankp = nstr->flags & GRN_STRING_REMOVE_BLANK;
+ grn_bool remove_tokenized_delimiter_p =
+ nstr->flags & GRN_STRING_REMOVE_TOKENIZED_DELIMITER;
+ if (!(nstr->normalized = GRN_MALLOC(ds + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][utf8] failed to allocate normalized text space");
+ return NULL;
+ }
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(ds * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->normalized);
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][utf8] failed to allocate checks space");
+ return NULL;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STRING_WITH_TYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(ds + 1))) {
+ if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
+ GRN_FREE(nstr->normalized); nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][utf8] failed to allocate character types space");
+ return NULL;
+ }
+ }
+ cp = nstr->ctypes;
+ d = (unsigned char *)nstr->normalized;
+ de = d + ds;
+ d_ = NULL;
+ e = (unsigned char *)nstr->original + size;
+ for (s = s_ = (unsigned char *)nstr->original; ; s += ls) {
+ if (!(ls = grn_str_charlen_utf8(ctx, s, e))) {
+ break;
+ }
+ if (remove_tokenized_delimiter_p &&
+ grn_tokenizer_is_tokenized_delimiter(ctx, (const char *)s, ls,
+ GRN_ENC_UTF8)) {
+ continue;
+ }
+ if ((p = (unsigned char *)grn_nfkc_decompose(s))) {
+ pe = p + strlen((char *)p);
+ } else {
+ p = s;
+ pe = p + ls;
+ }
+ if (d_ && (p2 = (unsigned char *)grn_nfkc_compose(d_, p))) {
+ p = p2;
+ pe = p + strlen((char *)p);
+ if (cp) { cp--; }
+ if (ch) {
+ ch -= (d - d_);
+ if (ch[0] >= 0) {
+ s_ = s__;
+ }
+ }
+ d = d_;
+ length--;
+ }
+ for (; ; p += lp) {
+ if (!(lp = grn_str_charlen_utf8(ctx, p, pe))) {
+ break;
+ }
+ if ((*p == ' ' && removeblankp) || *p < 0x20 /* skip unprintable ascii */ ) {
+ if (cp > nstr->ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ } else {
+ if (de <= d + lp) {
+ unsigned char *normalized;
+ ds += (ds >> 1) + lp;
+ if (!(normalized = GRN_REALLOC(nstr->normalized, ds + 1))) {
+ if (nstr->ctypes) { GRN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
+ if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
+ GRN_FREE(nstr->normalized); nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][utf8] failed to expand normalized text space");
+ return NULL;
+ }
+ de = normalized + ds;
+ d = normalized + (d - (unsigned char *)nstr->normalized);
+ nstr->normalized = (char *)normalized;
+ if (ch) {
+ int16_t *checks;
+ if (!(checks = GRN_REALLOC(nstr->checks, ds * sizeof(int16_t) + 1))) {
+ if (nstr->ctypes) { GRN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
+ GRN_FREE(nstr->checks); nstr->checks = NULL;
+ GRN_FREE(nstr->normalized); nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][utf8] failed to expand checks space");
+ return NULL;
+ }
+ ch = checks + (ch - nstr->checks);
+ nstr->checks = checks;
+ }
+ if (cp) {
+ uint_least8_t *ctypes;
+ if (!(ctypes = GRN_REALLOC(nstr->ctypes, ds + 1))) {
+ GRN_FREE(nstr->ctypes); nstr->ctypes = NULL;
+ if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
+ GRN_FREE(nstr->normalized); nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][utf8] failed to expand character types space");
+ return NULL;
+ }
+ cp = ctypes + (cp - nstr->ctypes);
+ nstr->ctypes = ctypes;
+ }
+ }
+ grn_memcpy(d, p, lp);
+ d_ = d;
+ d += lp;
+ length++;
+ if (cp) { *cp++ = grn_nfkc_char_type(p); }
+ if (ch) {
+ size_t i;
+ if (s_ == s + ls) {
+ *ch++ = -1;
+ } else {
+ *ch++ = (int16_t)(s + ls - s_);
+ s__ = s_;
+ s_ = s + ls;
+ }
+ for (i = lp; i > 1; i--) { *ch++ = 0; }
+ }
+ }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->n_characters = length;
+ nstr->normalized_length_in_bytes = (size_t)(d - (unsigned char *)nstr->normalized);
+ return NULL;
+}
+#endif /* GRN_WITH_NFKC */
+
+inline static grn_obj *
+ascii_normalize(grn_ctx *ctx, grn_string *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->original_length_in_bytes, length = 0;
+ int removeblankp = nstr->flags & GRN_STRING_REMOVE_BLANK;
+ if (!(nstr->normalized = GRN_MALLOC(size + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][ascii] failed to allocate normalized text space");
+ return NULL;
+ }
+ d0 = (unsigned char *) nstr->normalized;
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->normalized);
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][ascii] failed to allocate checks space");
+ return NULL;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STRING_WITH_TYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->normalized);
+ nstr->checks = NULL;
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][ascii] failed to allocate character types space");
+ return NULL;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->original + size;
+ for (s = s_ = (unsigned char *) nstr->original, d = d_ = d0; s < e; s++) {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->n_characters = length;
+ nstr->normalized_length_in_bytes = (size_t)(d - (unsigned char *)nstr->normalized);
+ return NULL;
+}
+
+/* use cp1252 as latin1 */
+inline static grn_obj *
+latin1_normalize(grn_ctx *ctx, grn_string *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->original_length_in_bytes, length = 0;
+ int removeblankp = nstr->flags & GRN_STRING_REMOVE_BLANK;
+ if (!(nstr->normalized = GRN_MALLOC(size + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][latin1] failed to allocate normalized text space");
+ return NULL;
+ }
+ d0 = (unsigned char *) nstr->normalized;
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->normalized);
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][latin1] failed to allocate checks space");
+ return NULL;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STRING_WITH_TYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->normalized);
+ nstr->checks = NULL;
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[normalizer][latin1] failed to allocate character types space");
+ return NULL;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->original + size;
+ for (s = s_ = (unsigned char *) nstr->original, d = d_ = d0; s < e; s++) {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ case 8 :
+ if (c == 0x8a || c == 0x8c || c == 0x8e) {
+ *d = c + 0x10;
+ ctype = GRN_CHAR_ALPHA;
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 9 :
+ if (c == 0x9a || c == 0x9c || c == 0x9e || c == 0x9f) {
+ *d = (c == 0x9f) ? c + 0x60 : c;
+ ctype = GRN_CHAR_ALPHA;
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 0x0c :
+ *d = c + 0x20;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ case 0x0d :
+ *d = (c == 0xd7 || c == 0xdf) ? c : c + 0x20;
+ ctype = (c == 0xd7) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 0x0e :
+ *d = c;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ case 0x0f :
+ *d = c;
+ ctype = (c == 0xf7) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->n_characters = length;
+ nstr->normalized_length_in_bytes = (size_t)(d - (unsigned char *)nstr->normalized);
+ return NULL;
+}
+
+inline static grn_obj *
+koi8r_normalize(grn_ctx *ctx, grn_string *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->original_length_in_bytes, length = 0;
+ int removeblankp = nstr->flags & GRN_STRING_REMOVE_BLANK;
+ if (!(nstr->normalized = GRN_MALLOC(size + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][koi8r] failed to allocate normalized text space");
+ return NULL;
+ }
+ d0 = (unsigned char *) nstr->normalized;
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->normalized);
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][koi8r] failed to allocate checks space");
+ return NULL;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STRING_WITH_TYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->normalized);
+ nstr->checks = NULL;
+ nstr->normalized = NULL;
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[string][koi8r] failed to allocate character types space");
+ return NULL;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->original + size;
+ for (s = s_ = (unsigned char *) nstr->original, d = d_ = d0; s < e; s++) {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_CHAR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_CHAR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ case 0x0a :
+ *d = c;
+ ctype = (c == 0xa3) ? GRN_CHAR_ALPHA : GRN_CHAR_OTHERS;
+ break;
+ case 0x0b :
+ if (c == 0xb3) {
+ *d = c - 0x10;
+ ctype = GRN_CHAR_ALPHA;
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ case 0x0c :
+ case 0x0d :
+ *d = c;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ case 0x0e :
+ case 0x0f :
+ *d = c - 0x20;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->n_characters = length;
+ nstr->normalized_length_in_bytes = (size_t)(d - (unsigned char *)nstr->normalized);
+ return NULL;
+}
+
+static grn_obj *
+auto_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_string *string = (grn_string *)(args[0]);
+ switch (string->encoding) {
+ case GRN_ENC_EUC_JP :
+ eucjp_normalize(ctx, string);
+ break;
+ case GRN_ENC_UTF8 :
+#ifdef GRN_WITH_NFKC
+ utf8_normalize(ctx, string);
+#else /* GRN_WITH_NFKC */
+ ascii_normalize(ctx, string);
+#endif /* GRN_WITH_NFKC */
+ break;
+ case GRN_ENC_SJIS :
+ sjis_normalize(ctx, string);
+ break;
+ case GRN_ENC_LATIN1 :
+ latin1_normalize(ctx, string);
+ break;
+ case GRN_ENC_KOI8R :
+ koi8r_normalize(ctx, string);
+ break;
+ default :
+ ascii_normalize(ctx, string);
+ break;
+ }
+ return NULL;
+}
+
+#ifdef GRN_WITH_NFKC
+static grn_obj *
+nfkc51_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_string *string = (grn_string *)(args[0]);
+ utf8_normalize(ctx, string);
+ return NULL;
+}
+#endif /* GRN_WITH_NFKC */
+
+grn_rc
+grn_normalizer_normalize(grn_ctx *ctx, grn_obj *normalizer, grn_obj *string)
+{
+ grn_rc rc;
+ int nargs = 0;
+
+ grn_ctx_push(ctx, string);
+ nargs++;
+ rc = grn_proc_call(ctx, normalizer, nargs, NULL);
+ grn_ctx_pop(ctx);
+
+ return rc;
+}
+
+grn_rc
+grn_db_init_builtin_normalizers(grn_ctx *ctx)
+{
+ const char *normalizer_nfkc51_name = "NormalizerNFKC51";
+
+ grn_normalizer_register(ctx, GRN_NORMALIZER_AUTO_NAME, -1,
+ NULL, auto_next, NULL);
+
+#ifdef GRN_WITH_NFKC
+ grn_normalizer_register(ctx, normalizer_nfkc51_name, -1,
+ NULL, nfkc51_next, NULL);
+#else /* GRN_WITH_NFKC */
+ grn_normalizer_register(ctx, normalizer_nfkc51_name, -1,
+ NULL, NULL, NULL);
+#endif /* GRN_WITH_NFKC */
+/*
+ grn_normalizer_register(ctx, "NormalizerUCA", -1,
+ NULL, uca_next, NULL);
+*/
+
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/obj.c b/storage/mroonga/vendor/groonga/lib/obj.c
new file mode 100644
index 00000000..8160daf5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/obj.c
@@ -0,0 +1,689 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_index_column.h"
+#include "grn_pat.h"
+#include "grn_dat.h"
+#include "grn_ii.h"
+
+grn_bool
+grn_obj_is_true(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ switch (obj->header.type) {
+ case GRN_BULK :
+ switch (obj->header.domain) {
+ case GRN_DB_BOOL :
+ return GRN_BOOL_VALUE(obj);
+ break;
+ case GRN_DB_INT32 :
+ return GRN_INT32_VALUE(obj) != 0;
+ break;
+ case GRN_DB_UINT32 :
+ return GRN_UINT32_VALUE(obj) != 0;
+ break;
+ case GRN_DB_FLOAT : {
+ double float_value;
+ float_value = GRN_FLOAT_VALUE(obj);
+ return (float_value < -DBL_EPSILON ||
+ DBL_EPSILON < float_value);
+ break;
+ }
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ return GRN_TEXT_LEN(obj) != 0;
+ break;
+ default :
+ return GRN_FALSE;
+ break;
+ }
+ break;
+ case GRN_VECTOR :
+ return GRN_TRUE;
+ break;
+ default :
+ return GRN_FALSE;
+ break;
+ }
+}
+
+grn_bool
+grn_obj_is_builtin(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_id id;
+
+ if (!obj) { return GRN_FALSE; }
+
+ id = grn_obj_id(ctx, obj);
+ return grn_id_is_builtin(ctx, id);
+}
+
+grn_bool
+grn_obj_is_bulk(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_BULK;
+}
+
+grn_bool
+grn_obj_is_text_family_bulk(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_bulk(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TYPE_IS_TEXT_FAMILY(obj->header.domain);
+}
+
+grn_bool
+grn_obj_is_table(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_bool is_table = GRN_FALSE;
+
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ switch (obj->header.type) {
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ is_table = GRN_TRUE;
+ default :
+ break;
+ }
+
+ return is_table;
+}
+
+grn_bool
+grn_obj_is_column(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_bool is_column = GRN_FALSE;
+
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ switch (obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ is_column = GRN_TRUE;
+ default :
+ break;
+ }
+
+ return is_column;
+}
+
+grn_bool
+grn_obj_is_scalar_column(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_column(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_SCALAR;
+}
+
+grn_bool
+grn_obj_is_vector_column(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_column(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return ((obj->header.type == GRN_COLUMN_VAR_SIZE) &&
+ ((obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) ==
+ GRN_OBJ_COLUMN_VECTOR));
+}
+
+grn_bool
+grn_obj_is_weight_vector_column(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_vector_column(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return (obj->header.flags & GRN_OBJ_WITH_WEIGHT) == GRN_OBJ_WITH_WEIGHT;
+}
+
+grn_bool
+grn_obj_is_reference_column(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_obj *range;
+
+ if (!grn_obj_is_column(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ range = grn_ctx_at(ctx, grn_obj_get_range(ctx, obj));
+ if (!range) {
+ return GRN_FALSE;
+ }
+
+ switch (range->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ return GRN_TRUE;
+ default:
+ return GRN_FALSE;
+ }
+}
+
+grn_bool
+grn_obj_is_data_column(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_column(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_COLUMN_FIX_SIZE ||
+ obj->header.type == GRN_COLUMN_VAR_SIZE;
+}
+
+grn_bool
+grn_obj_is_index_column(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_column(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_COLUMN_INDEX;
+}
+
+grn_bool
+grn_obj_is_accessor(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_ACCESSOR;
+}
+
+grn_bool
+grn_obj_is_key_accessor(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_accessor *accessor;
+
+ if (!grn_obj_is_accessor(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ accessor = (grn_accessor *)obj;
+ if (accessor->next) {
+ return GRN_FALSE;
+ }
+
+ return accessor->action == GRN_ACCESSOR_GET_KEY;
+}
+
+grn_bool
+grn_obj_is_type(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_TYPE;
+}
+
+grn_bool
+grn_obj_is_text_family_type(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!grn_obj_is_type(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TYPE_IS_TEXT_FAMILY(grn_obj_id(ctx, obj));
+}
+
+grn_bool
+grn_obj_is_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_PROC;
+}
+
+grn_bool
+grn_obj_is_tokenizer_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->type == GRN_PROC_TOKENIZER;
+}
+
+grn_bool
+grn_obj_is_function_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->type == GRN_PROC_FUNCTION;
+}
+
+grn_bool
+grn_obj_is_selector_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_function_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->callbacks.function.selector != NULL;
+}
+
+grn_bool
+grn_obj_is_selector_only_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_selector_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->funcs[PROC_INIT] == NULL;
+}
+
+grn_bool
+grn_obj_is_normalizer_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->type == GRN_PROC_NORMALIZER;
+}
+
+grn_bool
+grn_obj_is_token_filter_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->type == GRN_PROC_TOKEN_FILTER;
+}
+
+grn_bool
+grn_obj_is_scorer_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->type == GRN_PROC_SCORER;
+}
+
+grn_bool
+grn_obj_is_window_function_proc(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_proc *proc;
+
+ if (!grn_obj_is_proc(ctx, obj)) {
+ return GRN_FALSE;
+ }
+
+ proc = (grn_proc *)obj;
+ return proc->type == GRN_PROC_WINDOW_FUNCTION;
+}
+
+grn_bool
+grn_obj_is_expr(grn_ctx *ctx, grn_obj *obj)
+{
+ if (!obj) {
+ return GRN_FALSE;
+ }
+
+ return obj->header.type == GRN_EXPR;
+}
+
+static void
+grn_db_reindex(grn_ctx *ctx, grn_obj *db)
+{
+ grn_table_cursor *cursor;
+ grn_id id;
+
+ cursor = grn_table_cursor_open(ctx, db,
+ NULL, 0, NULL, 0,
+ 0, -1,
+ GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ return;
+ }
+
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *object;
+
+ object = grn_ctx_at(ctx, id);
+ if (!object) {
+ ERRCLR(ctx);
+ continue;
+ }
+
+ switch (object->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ grn_obj_reindex(ctx, object);
+ break;
+ default:
+ break;
+ }
+
+ grn_obj_unlink(ctx, object);
+
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+}
+
+static void
+grn_table_reindex(grn_ctx *ctx, grn_obj *table)
+{
+ grn_hash *columns;
+
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
+ if (!columns) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[table][reindex] failed to create a table to store columns");
+ return;
+ }
+
+ if (grn_table_columns(ctx, table, "", 0, (grn_obj *)columns) > 0) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
+ grn_obj *column = grn_ctx_at(ctx, *key);
+ if (column && column->header.type == GRN_COLUMN_INDEX) {
+ grn_obj_reindex(ctx, column);
+ }
+ });
+ }
+ grn_hash_close(ctx, columns);
+}
+
+static void
+grn_data_column_reindex(grn_ctx *ctx, grn_obj *data_column)
+{
+ grn_hook *hooks;
+
+ for (hooks = DB_OBJ(data_column)->hooks[GRN_HOOK_SET];
+ hooks;
+ hooks = hooks->next) {
+ grn_obj_default_set_value_hook_data *data = (void *)GRN_NEXT_ADDR(hooks);
+ grn_obj *target = grn_ctx_at(ctx, data->target);
+ if (target->header.type != GRN_COLUMN_INDEX) {
+ continue;
+ }
+ grn_obj_reindex(ctx, target);
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+}
+
+grn_rc
+grn_obj_reindex(grn_ctx *ctx, grn_obj *obj)
+{
+ GRN_API_ENTER;
+
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT, "[object][reindex] object must not be NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ switch (obj->header.type) {
+ case GRN_DB :
+ grn_db_reindex(ctx, obj);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ grn_table_reindex(ctx, obj);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ grn_data_column_reindex(ctx, obj);
+ break;
+ case GRN_COLUMN_INDEX :
+ grn_index_column_rebuild(ctx, obj);
+ break;
+ default :
+ {
+ grn_obj type_name;
+ GRN_TEXT_INIT(&type_name, 0);
+ grn_inspect_type(ctx, &type_name, obj->header.type);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[object][reindex] object must be TABLE_HASH_KEY, "
+ "TABLE_PAT_KEY, TABLE_DAT_KEY or COLUMN_INDEX: <%.*s>",
+ (int)GRN_TEXT_LEN(&type_name),
+ GRN_TEXT_VALUE(&type_name));
+ GRN_OBJ_FIN(ctx, &type_name);
+ GRN_API_RETURN(ctx->rc);
+ }
+ break;
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+const char *
+grn_obj_type_to_string(uint8_t type)
+{
+ switch (type) {
+ case GRN_VOID :
+ return "void";
+ case GRN_BULK :
+ return "bulk";
+ case GRN_PTR :
+ return "ptr";
+ case GRN_UVECTOR :
+ return "uvector";
+ case GRN_PVECTOR :
+ return "pvector";
+ case GRN_VECTOR :
+ return "vector";
+ case GRN_MSG :
+ return "msg";
+ case GRN_QUERY :
+ return "query";
+ case GRN_ACCESSOR :
+ return "accessor";
+ case GRN_SNIP :
+ return "snip";
+ case GRN_PATSNIP :
+ return "patsnip";
+ case GRN_STRING :
+ return "string";
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ return "cursor:table:hash_key";
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ return "cursor:table:pat_key";
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ return "cursor:table:dat_key";
+ case GRN_CURSOR_TABLE_NO_KEY :
+ return "cursor:table:no_key";
+ case GRN_CURSOR_COLUMN_INDEX :
+ return "cursor:column:index";
+ case GRN_CURSOR_COLUMN_GEO_INDEX :
+ return "cursor:column:geo_index";
+ case GRN_CURSOR_CONFIG :
+ return "cursor:config";
+ case GRN_TYPE :
+ return "type";
+ case GRN_PROC :
+ return "proc";
+ case GRN_EXPR :
+ return "expr";
+ case GRN_TABLE_HASH_KEY :
+ return "table:hash_key";
+ case GRN_TABLE_PAT_KEY :
+ return "table:pat_key";
+ case GRN_TABLE_DAT_KEY :
+ return "table:dat_key";
+ case GRN_TABLE_NO_KEY :
+ return "table:no_key";
+ case GRN_DB :
+ return "db";
+ case GRN_COLUMN_FIX_SIZE :
+ return "column:fix_size";
+ case GRN_COLUMN_VAR_SIZE :
+ return "column:var_size";
+ case GRN_COLUMN_INDEX :
+ return "column:index";
+ default :
+ return "unknown";
+ }
+}
+
+grn_bool
+grn_obj_name_is_column(grn_ctx *ctx, const char *name, int name_len)
+{
+ if (!name) {
+ return GRN_FALSE;
+ }
+
+ if (name_len < 0) {
+ name_len = strlen(name);
+ }
+
+ return memchr(name, GRN_DB_DELIMITER, name_len) != NULL;
+}
+
+grn_io *
+grn_obj_get_io(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_io *io = NULL;
+
+ if (!obj) {
+ return NULL;
+ }
+
+ if (obj->header.type == GRN_DB) {
+ obj = ((grn_db *)obj)->keys;
+ }
+
+ switch (obj->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ io = ((grn_pat *)obj)->io;
+ break;
+ case GRN_TABLE_DAT_KEY :
+ io = ((grn_dat *)obj)->io;
+ break;
+ case GRN_TABLE_HASH_KEY :
+ io = ((grn_hash *)obj)->io;
+ break;
+ case GRN_TABLE_NO_KEY :
+ io = ((grn_array *)obj)->io;
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ io = ((grn_ja *)obj)->io;
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ io = ((grn_ra *)obj)->io;
+ break;
+ case GRN_COLUMN_INDEX :
+ io = ((grn_ii *)obj)->seg;
+ break;
+ }
+
+ return io;
+}
+
+size_t
+grn_obj_get_disk_usage(grn_ctx *ctx, grn_obj *obj)
+{
+ size_t usage = 0;
+
+ GRN_API_ENTER;
+
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT, "[object][disk-usage] object must not be NULL");
+ GRN_API_RETURN(0);
+ }
+
+ switch (obj->header.type) {
+ case GRN_DB :
+ {
+ grn_db *db = (grn_db *)obj;
+ usage = grn_obj_get_disk_usage(ctx, db->keys);
+ if (db->specs) {
+ usage += grn_obj_get_disk_usage(ctx, (grn_obj *)(db->specs));
+ }
+ usage += grn_obj_get_disk_usage(ctx, (grn_obj *)(db->config));
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ usage = grn_dat_get_disk_usage(ctx, (grn_dat *)obj);
+ break;
+ case GRN_COLUMN_INDEX :
+ usage = grn_ii_get_disk_usage(ctx, (grn_ii *)obj);
+ break;
+ default :
+ {
+ grn_io *io;
+ io = grn_obj_get_io(ctx, obj);
+ if (io) {
+ usage = grn_io_get_disk_usage(ctx, io);
+ }
+ }
+ break;
+ }
+
+ GRN_API_RETURN(usage);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/operator.c b/storage/mroonga/vendor/groonga/lib/operator.c
new file mode 100644
index 00000000..1e1f2cf7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/operator.c
@@ -0,0 +1,1362 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_db.h"
+#include "grn_str.h"
+#include "grn_normalizer.h"
+
+#include <string.h>
+
+#ifdef GRN_WITH_ONIGMO
+# define GRN_SUPPORT_REGEXP
+#endif
+
+#ifdef GRN_SUPPORT_REGEXP
+# include <onigmo.h>
+#endif
+
+static const char *operator_names[] = {
+ "push",
+ "pop",
+ "nop",
+ "call",
+ "intern",
+ "get_ref",
+ "get_value",
+ "and",
+ "and_not",
+ "or",
+ "assign",
+ "star_assign",
+ "slash_assign",
+ "mod_assign",
+ "plus_assign",
+ "minus_assign",
+ "shiftl_assign",
+ "shiftr_assign",
+ "shiftrr_assign",
+ "and_assign",
+ "xor_assign",
+ "or_assign",
+ "jump",
+ "cjump",
+ "comma",
+ "bitwise_or",
+ "bitwise_xor",
+ "bitwise_and",
+ "bitwise_not",
+ "equal",
+ "not_equal",
+ "less",
+ "greater",
+ "less_equal",
+ "greater_equal",
+ "in",
+ "match",
+ "near",
+ "near2",
+ "similar",
+ "term_extract",
+ "shiftl",
+ "shiftr",
+ "shiftrr",
+ "plus",
+ "minus",
+ "star",
+ "slash",
+ "mod",
+ "delete",
+ "incr",
+ "decr",
+ "incr_post",
+ "decr_post",
+ "not",
+ "adjust",
+ "exact",
+ "lcp",
+ "partial",
+ "unsplit",
+ "prefix",
+ "suffix",
+ "geo_distance1",
+ "geo_distance2",
+ "geo_distance3",
+ "geo_distance4",
+ "geo_withinp5",
+ "geo_withinp6",
+ "geo_withinp8",
+ "obj_search",
+ "expr_get_var",
+ "table_create",
+ "table_select",
+ "table_sort",
+ "table_group",
+ "json_put",
+ "get_member",
+ "regexp",
+ "fuzzy"
+};
+
+#define GRN_OP_LAST GRN_OP_FUZZY
+
+const char *
+grn_operator_to_string(grn_operator op)
+{
+ if (op <= GRN_OP_LAST) {
+ return operator_names[op];
+ } else {
+ return "unknown";
+ }
+}
+
+grn_operator_exec_func *
+grn_operator_to_exec_func(grn_operator op)
+{
+ grn_operator_exec_func *func = NULL;
+
+ switch (op) {
+ case GRN_OP_EQUAL :
+ func = grn_operator_exec_equal;
+ break;
+ case GRN_OP_NOT_EQUAL :
+ func = grn_operator_exec_not_equal;
+ break;
+ case GRN_OP_LESS :
+ func = grn_operator_exec_less;
+ break;
+ case GRN_OP_GREATER :
+ func = grn_operator_exec_greater;
+ break;
+ case GRN_OP_LESS_EQUAL :
+ func = grn_operator_exec_less_equal;
+ break;
+ case GRN_OP_GREATER_EQUAL :
+ func = grn_operator_exec_greater_equal;
+ break;
+ case GRN_OP_MATCH :
+ func = grn_operator_exec_match;
+ break;
+ case GRN_OP_PREFIX :
+ func = grn_operator_exec_prefix;
+ break;
+ case GRN_OP_REGEXP :
+ func = grn_operator_exec_regexp;
+ break;
+ default :
+ break;
+ }
+
+ return func;
+}
+
+#define DO_EQ_SUB do {\
+ switch (y->header.domain) {\
+ case GRN_DB_INT8 :\
+ r = ((unsigned char) x_ == (unsigned char) GRN_INT8_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT8 :\
+ r = (x_ == GRN_UINT8_VALUE(y));\
+ break;\
+ case GRN_DB_INT16 :\
+ r = ((int) x_ == (int) GRN_INT16_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT16 :\
+ r = (x_ == GRN_UINT16_VALUE(y));\
+ break;\
+ case GRN_DB_INT32 :\
+ r = ((int) x_ == (int) GRN_INT32_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT32 :\
+ r = ((uint) x_ == GRN_UINT32_VALUE(y)); \
+ break;\
+ case GRN_DB_INT64 :\
+ r = ((long long) x_ == GRN_INT64_VALUE(y)); \
+ break;\
+ case GRN_DB_TIME :\
+ r = (GRN_TIME_PACK(x_,0) == GRN_INT64_VALUE(y));\
+ break;\
+ case GRN_DB_UINT64 :\
+ r = ((unsigned long long) x_ == GRN_UINT64_VALUE(y)); \
+ break;\
+ case GRN_DB_FLOAT :\
+ r = ((x_ <= GRN_FLOAT_VALUE(y)) && (x_ >= GRN_FLOAT_VALUE(y)));\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ {\
+ const char *p_ = GRN_TEXT_VALUE(y);\
+ int i_ = grn_atoi(p_, p_ + GRN_TEXT_LEN(y), NULL);\
+ r = ((int) x_ == i_); \
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+} while (0)
+
+#define DO_EQ(x,y,r) do {\
+ switch (x->header.domain) {\
+ case GRN_DB_VOID :\
+ r = GRN_FALSE;\
+ break;\
+ case GRN_DB_INT8 :\
+ {\
+ int8_t x_ = GRN_INT8_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_UINT8 :\
+ {\
+ uint8_t x_ = GRN_UINT8_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_INT16 :\
+ {\
+ int16_t x_ = GRN_INT16_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_UINT16 :\
+ {\
+ uint16_t x_ = GRN_UINT16_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_INT32 :\
+ {\
+ int32_t x_ = GRN_INT32_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_UINT32 :\
+ {\
+ uint32_t x_ = GRN_UINT32_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_INT64 :\
+ {\
+ int64_t x_ = GRN_INT64_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_TIME :\
+ {\
+ int64_t x_ = GRN_INT64_VALUE(x);\
+ switch (y->header.domain) {\
+ case GRN_DB_INT32 :\
+ r = (x_ == GRN_TIME_PACK(GRN_INT32_VALUE(y), 0));\
+ break;\
+ case GRN_DB_UINT32 :\
+ r = (x_ == GRN_TIME_PACK(GRN_UINT32_VALUE(y), 0));\
+ break;\
+ case GRN_DB_INT64 :\
+ case GRN_DB_TIME :\
+ r = ((long long) x_ == GRN_INT64_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT64 :\
+ r = ((unsigned long long) x_ == GRN_UINT64_VALUE(y)); \
+ break;\
+ case GRN_DB_FLOAT :\
+ r = (x_ == GRN_TIME_PACK(GRN_FLOAT_VALUE(y), 0));\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ {\
+ grn_obj time_value_;\
+ GRN_TIME_INIT(&time_value_, 0);\
+ if (grn_obj_cast(ctx, y, &time_value_, GRN_FALSE) == GRN_SUCCESS) {\
+ r = (x_ == GRN_TIME_VALUE(&time_value_));\
+ } else {\
+ r = GRN_FALSE;\
+ }\
+ GRN_OBJ_FIN(ctx, &time_value_);\
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+ }\
+ break;\
+ case GRN_DB_UINT64 :\
+ {\
+ uint64_t x_ = GRN_UINT64_VALUE(x);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ case GRN_DB_FLOAT :\
+ {\
+ double x_ = GRN_FLOAT_VALUE(x);\
+ switch (y->header.domain) {\
+ case GRN_DB_INT32 :\
+ r = ((x_ <= GRN_INT32_VALUE(y)) && (x_ >= GRN_INT32_VALUE(y)));\
+ break;\
+ case GRN_DB_UINT32 :\
+ r = ((x_ <= GRN_UINT32_VALUE(y)) && (x_ >= GRN_UINT32_VALUE(y)));\
+ break;\
+ case GRN_DB_INT64 :\
+ case GRN_DB_TIME :\
+ r = ((x_ <= GRN_INT64_VALUE(y)) && (x_ >= GRN_INT64_VALUE(y)));\
+ break;\
+ case GRN_DB_UINT64 :\
+ r = ((x_ <= GRN_UINT64_VALUE(y)) && (x_ >= GRN_UINT64_VALUE(y)));\
+ break;\
+ case GRN_DB_FLOAT :\
+ r = ((x_ <= GRN_FLOAT_VALUE(y)) && (x_ >= GRN_FLOAT_VALUE(y)));\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ {\
+ const char *p_ = GRN_TEXT_VALUE(y);\
+ int i_ = grn_atoi(p_, p_ + GRN_TEXT_LEN(y), NULL);\
+ r = (x_ <= i_ && x_ >= i_);\
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+ }\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ if (GRN_DB_SHORT_TEXT <= y->header.domain && y->header.domain <= GRN_DB_LONG_TEXT) {\
+ uint32_t la = GRN_TEXT_LEN(x), lb = GRN_TEXT_LEN(y);\
+ r = (la == lb && !memcmp(GRN_TEXT_VALUE(x), GRN_TEXT_VALUE(y), lb));\
+ } else {\
+ const char *q_ = GRN_TEXT_VALUE(x);\
+ int x_ = grn_atoi(q_, q_ + GRN_TEXT_LEN(x), NULL);\
+ DO_EQ_SUB;\
+ }\
+ break;\
+ default :\
+ if ((x->header.domain == y->header.domain)) {\
+ r = (GRN_BULK_VSIZE(x) == GRN_BULK_VSIZE(y) &&\
+ !(memcmp(GRN_BULK_HEAD(x), GRN_BULK_HEAD(y), GRN_BULK_VSIZE(x))));\
+ } else {\
+ grn_obj dest;\
+ if (x->header.domain < y->header.domain) {\
+ GRN_OBJ_INIT(&dest, GRN_BULK, 0, y->header.domain);\
+ if (!grn_obj_cast(ctx, x, &dest, GRN_FALSE)) {\
+ r = (GRN_BULK_VSIZE(&dest) == GRN_BULK_VSIZE(y) &&\
+ !memcmp(GRN_BULK_HEAD(&dest), GRN_BULK_HEAD(y), GRN_BULK_VSIZE(y))); \
+ } else {\
+ r = GRN_FALSE;\
+ }\
+ } else {\
+ GRN_OBJ_INIT(&dest, GRN_BULK, 0, x->header.domain);\
+ if (!grn_obj_cast(ctx, y, &dest, GRN_FALSE)) {\
+ r = (GRN_BULK_VSIZE(&dest) == GRN_BULK_VSIZE(x) &&\
+ !memcmp(GRN_BULK_HEAD(&dest), GRN_BULK_HEAD(x), GRN_BULK_VSIZE(x))); \
+ } else {\
+ r = GRN_FALSE;\
+ }\
+ }\
+ GRN_OBJ_FIN(ctx, &dest);\
+ }\
+ break;\
+ }\
+} while (0)
+
+grn_bool
+grn_operator_exec_equal(grn_ctx *ctx, grn_obj *x, grn_obj *y)
+{
+ grn_bool r = GRN_FALSE;
+ GRN_API_ENTER;
+ DO_EQ(x, y, r);
+ GRN_API_RETURN(r);
+}
+
+grn_bool
+grn_operator_exec_not_equal(grn_ctx *ctx, grn_obj *x, grn_obj *y)
+{
+ grn_bool r = GRN_FALSE;
+ GRN_API_ENTER;
+ DO_EQ(x, y, r);
+ GRN_API_RETURN(!r);
+}
+
+#define DO_COMPARE_SCALAR_SUB_NUMERIC(y,op) do {\
+ switch ((y)->header.domain) {\
+ case GRN_DB_BOOL :\
+ r = (x_ op (uint8_t)(GRN_BOOL_VALUE(y) ? 1 : 0));\
+ break;\
+ case GRN_DB_INT8 :\
+ r = ((signed char) x_ op GRN_INT8_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT8 :\
+ r = ((unsigned char) x_ op GRN_UINT8_VALUE(y)); \
+ break;\
+ case GRN_DB_INT16 :\
+ r = ((short) x_ op GRN_INT16_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT16 :\
+ r = ((unsigned short) x_ op GRN_UINT16_VALUE(y)); \
+ break;\
+ case GRN_DB_INT32 :\
+ r = ((int) x_ op GRN_INT32_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT32 :\
+ r = ((uint) x_ op GRN_UINT32_VALUE(y)); \
+ break;\
+ case GRN_DB_INT64 :\
+ r = ((long long) x_ op GRN_INT64_VALUE(y)); \
+ break;\
+ case GRN_DB_TIME :\
+ r = (GRN_TIME_PACK(x_,0) op GRN_INT64_VALUE(y));\
+ break;\
+ case GRN_DB_UINT64 :\
+ r = ((unsigned long long) x_ op GRN_UINT64_VALUE(y)); \
+ break;\
+ case GRN_DB_FLOAT :\
+ r = (x_ op GRN_FLOAT_VALUE(y));\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+} while (0)
+
+#define DO_COMPARE_SCALAR_SUB_BUILTIN(op) do {\
+ switch (y->header.domain) {\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ {\
+ grn_obj y_;\
+ GRN_OBJ_INIT(&y_, GRN_BULK, 0, x->header.domain);\
+ if (grn_obj_cast(ctx, y, &y_, GRN_FALSE)) {\
+ r = GRN_FALSE;\
+ } else {\
+ DO_COMPARE_SCALAR_SUB_NUMERIC(&y_, op);\
+ }\
+ GRN_OBJ_FIN(ctx, &y_);\
+ }\
+ break;\
+ default :\
+ DO_COMPARE_SCALAR_SUB_NUMERIC(y,op);\
+ break;\
+ }\
+} while (0)
+
+#define DO_COMPARE_SCALAR_SUB(op) do {\
+ if (y->header.domain >= GRN_N_RESERVED_TYPES) {\
+ grn_obj *y_table;\
+ y_table = grn_ctx_at(ctx, y->header.domain);\
+ switch (y_table->header.type) {\
+ case GRN_TABLE_HASH_KEY :\
+ case GRN_TABLE_PAT_KEY :\
+ case GRN_TABLE_DAT_KEY :\
+ {\
+ grn_obj y_key;\
+ int length;\
+ GRN_OBJ_INIT(&y_key, GRN_BULK, 0, y_table->header.domain);\
+ length = grn_table_get_key2(ctx, y_table, GRN_RECORD_VALUE(y), &y_key);\
+ if (length > 0) {\
+ grn_obj *y_original = y;\
+ y = &y_key;\
+ DO_COMPARE_SCALAR_SUB_BUILTIN(op);\
+ y = y_original;\
+ } else {\
+ r = GRN_FALSE;\
+ }\
+ GRN_OBJ_FIN(ctx, &y_key);\
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+ grn_obj_unlink(ctx, y_table);\
+ } else {\
+ DO_COMPARE_SCALAR_SUB_BUILTIN(op);\
+ }\
+} while (0)
+
+#define DO_COMPARE_SCALAR_BUILTIN(x,y,r,op) do {\
+ switch (x->header.domain) {\
+ case GRN_DB_BOOL :\
+ {\
+ uint8_t x_ = GRN_BOOL_VALUE(x) ? 1 : 0;\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_INT8 :\
+ {\
+ int8_t x_ = GRN_INT8_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_UINT8 :\
+ {\
+ uint8_t x_ = GRN_UINT8_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_INT16 :\
+ {\
+ int16_t x_ = GRN_INT16_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_UINT16 :\
+ {\
+ uint16_t x_ = GRN_UINT16_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_INT32 :\
+ {\
+ int32_t x_ = GRN_INT32_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_UINT32 :\
+ {\
+ uint32_t x_ = GRN_UINT32_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_TIME :\
+ {\
+ int64_t x_ = GRN_INT64_VALUE(x);\
+ switch (y->header.domain) {\
+ case GRN_DB_INT32 :\
+ r = (x_ op GRN_TIME_PACK(GRN_INT32_VALUE(y), 0));\
+ break;\
+ case GRN_DB_UINT32 :\
+ r = (x_ op GRN_TIME_PACK(GRN_UINT32_VALUE(y), 0));\
+ break;\
+ case GRN_DB_INT64 :\
+ case GRN_DB_TIME :\
+ r = ((long long) x_ op GRN_INT64_VALUE(y)); \
+ break;\
+ case GRN_DB_UINT64 :\
+ r = ((unsigned long long) x_ op GRN_UINT64_VALUE(y)); \
+ break;\
+ case GRN_DB_FLOAT :\
+ r = (x_ op GRN_TIME_PACK(GRN_FLOAT_VALUE(y), 0));\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ {\
+ grn_obj time_value_;\
+ GRN_TIME_INIT(&time_value_, 0);\
+ if (grn_obj_cast(ctx, y, &time_value_, GRN_FALSE) == GRN_SUCCESS) {\
+ r = (x_ op GRN_TIME_VALUE(&time_value_));\
+ } else {\
+ r = GRN_FALSE;\
+ }\
+ GRN_OBJ_FIN(ctx, &time_value_);\
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+ }\
+ break;\
+ case GRN_DB_INT64 :\
+ {\
+ int64_t x_ = GRN_INT64_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_UINT64 :\
+ {\
+ uint64_t x_ = GRN_UINT64_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_FLOAT :\
+ {\
+ double x_ = GRN_FLOAT_VALUE(x);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ case GRN_DB_SHORT_TEXT :\
+ case GRN_DB_TEXT :\
+ case GRN_DB_LONG_TEXT :\
+ if (GRN_DB_SHORT_TEXT <= y->header.domain && y->header.domain <= GRN_DB_LONG_TEXT) {\
+ int r_;\
+ uint32_t la = GRN_TEXT_LEN(x), lb = GRN_TEXT_LEN(y);\
+ if (la > lb) {\
+ if (!(r_ = memcmp(GRN_TEXT_VALUE(x), GRN_TEXT_VALUE(y), lb))) {\
+ r_ = 1;\
+ }\
+ } else {\
+ if (!(r_ = memcmp(GRN_TEXT_VALUE(x), GRN_TEXT_VALUE(y), la))) {\
+ r_ = la == lb ? 0 : -1;\
+ }\
+ }\
+ r = (r_ op 0);\
+ } else {\
+ const char *q_ = GRN_TEXT_VALUE(x);\
+ int x_ = grn_atoi(q_, q_ + GRN_TEXT_LEN(x), NULL);\
+ DO_COMPARE_SCALAR_SUB(op);\
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+} while (0)
+
+#define DO_COMPARE_SCALAR(x, y, r, op) do {\
+ if (x->header.domain >= GRN_N_RESERVED_TYPES) {\
+ grn_obj *x_table;\
+ x_table = grn_ctx_at(ctx, x->header.domain);\
+ switch (x_table->header.type) {\
+ case GRN_TABLE_HASH_KEY :\
+ case GRN_TABLE_PAT_KEY :\
+ case GRN_TABLE_DAT_KEY :\
+ {\
+ grn_obj x_key;\
+ int length;\
+ GRN_OBJ_INIT(&x_key, GRN_BULK, 0, x_table->header.domain);\
+ length = grn_table_get_key2(ctx, x_table, GRN_RECORD_VALUE(x), &x_key);\
+ if (length > 0) {\
+ grn_obj *x_original = x;\
+ x = &x_key;\
+ DO_COMPARE_SCALAR_BUILTIN((&x_key), y, r, op);\
+ x = x_original;\
+ } else {\
+ r = GRN_FALSE;\
+ }\
+ GRN_OBJ_FIN(ctx, &x_key);\
+ }\
+ break;\
+ default :\
+ r = GRN_FALSE;\
+ break;\
+ }\
+ grn_obj_unlink(ctx, x_table);\
+ } else {\
+ DO_COMPARE_SCALAR_BUILTIN(x, y, r, op);\
+ }\
+} while (0)
+
+#define DO_COMPARE(x, y, r, op) do {\
+ if (x->header.type == GRN_UVECTOR) {\
+ grn_obj element_buffer;\
+ unsigned int i, n;\
+ unsigned int element_size;\
+ GRN_VALUE_FIX_SIZE_INIT(&element_buffer, 0, x->header.domain);\
+ n = grn_uvector_size(ctx, x);\
+ element_size = grn_uvector_element_size(ctx, x);\
+ for (i = 0; i < n; i++) {\
+ grn_obj *element = &element_buffer;\
+ GRN_BULK_REWIND(element);\
+ grn_bulk_write(ctx, element,\
+ ((uint8_t *)GRN_BULK_HEAD(x)) + (element_size * i),\
+ element_size);\
+ DO_COMPARE_SCALAR(element, y, r, op);\
+ if (r) {\
+ break;\
+ }\
+ }\
+ GRN_OBJ_FIN(ctx, &element_buffer);\
+ } else {\
+ if (GRN_BULK_VSIZE(x) == 0 || GRN_BULK_VSIZE(y) == 0) {\
+ r = GRN_FALSE;\
+ } else {\
+ DO_COMPARE_SCALAR(x, y, r, op);\
+ }\
+ }\
+} while (0)
+
+grn_bool
+grn_operator_exec_less(grn_ctx *ctx, grn_obj *x, grn_obj *y)
+{
+ grn_bool r = GRN_FALSE;
+ GRN_API_ENTER;
+ DO_COMPARE(x, y, r, <);
+ GRN_API_RETURN(r);
+}
+
+grn_bool
+grn_operator_exec_greater(grn_ctx *ctx, grn_obj *x, grn_obj *y)
+{
+ grn_bool r = GRN_FALSE;
+ GRN_API_ENTER;
+ DO_COMPARE(x, y, r, >);
+ GRN_API_RETURN(r);
+}
+
+grn_bool
+grn_operator_exec_less_equal(grn_ctx *ctx, grn_obj *x, grn_obj *y)
+{
+ grn_bool r = GRN_FALSE;
+ GRN_API_ENTER;
+ DO_COMPARE(x, y, r, <=);
+ GRN_API_RETURN(r);
+}
+
+grn_bool
+grn_operator_exec_greater_equal(grn_ctx *ctx, grn_obj *x, grn_obj *y)
+{
+ grn_bool r = GRN_FALSE;
+ GRN_API_ENTER;
+ DO_COMPARE(x, y, r, >=);
+ GRN_API_RETURN(r);
+}
+
+static grn_bool
+exec_match_uvector_bulk(grn_ctx *ctx, grn_obj *uvector, grn_obj *query)
+{
+ grn_bool matched = GRN_FALSE;
+ unsigned int i, size;
+ grn_obj element;
+ unsigned int element_size;
+
+ size = grn_uvector_size(ctx, uvector);
+ element_size = grn_uvector_element_size(ctx, uvector);
+ GRN_VALUE_FIX_SIZE_INIT(&element, 0, uvector->header.domain);
+ for (i = 0; i < size; i++) {
+ GRN_BULK_REWIND(&element);
+ grn_bulk_write(ctx, &element,
+ GRN_BULK_HEAD(uvector) + (element_size * i),
+ element_size);
+ if (grn_operator_exec_equal(ctx, &element, query)) {
+ matched = GRN_TRUE;
+ break;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &element);
+
+ return matched;
+}
+
+static grn_bool
+exec_match_vector_bulk(grn_ctx *ctx, grn_obj *vector, grn_obj *query)
+{
+ grn_bool matched = GRN_FALSE;
+ unsigned int i, size;
+ grn_obj element;
+
+ size = grn_vector_size(ctx, vector);
+ GRN_VOID_INIT(&element);
+ for (i = 0; i < size; i++) {
+ const char *content;
+ unsigned int content_size;
+ grn_id domain_id;
+
+ content_size = grn_vector_get_element(ctx, vector, i,
+ &content, NULL, &domain_id);
+ grn_obj_reinit(ctx, &element, domain_id, 0);
+ grn_bulk_write(ctx, &element, content, content_size);
+ if (grn_operator_exec_equal(ctx, &element, query)) {
+ matched = GRN_TRUE;
+ break;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &element);
+
+ return matched;
+}
+
+#ifdef GRN_SUPPORT_REGEXP
+static OnigRegex
+regexp_compile(grn_ctx *ctx,
+ const char *pattern,
+ unsigned int pattern_len,
+ const OnigSyntaxType *syntax)
+{
+ OnigRegex regex;
+ OnigEncoding onig_encoding;
+ int onig_result;
+ OnigErrorInfo onig_error_info;
+
+ if (ctx->encoding == GRN_ENC_NONE) {
+ return NULL;
+ }
+
+ switch (ctx->encoding) {
+ case GRN_ENC_EUC_JP :
+ onig_encoding = ONIG_ENCODING_EUC_JP;
+ break;
+ case GRN_ENC_UTF8 :
+ onig_encoding = ONIG_ENCODING_UTF8;
+ break;
+ case GRN_ENC_SJIS :
+ onig_encoding = ONIG_ENCODING_CP932;
+ break;
+ case GRN_ENC_LATIN1 :
+ onig_encoding = ONIG_ENCODING_ISO_8859_1;
+ break;
+ case GRN_ENC_KOI8R :
+ onig_encoding = ONIG_ENCODING_KOI8_R;
+ break;
+ default :
+ return NULL;
+ }
+
+ onig_result = onig_new(&regex,
+ pattern,
+ pattern + pattern_len,
+ ONIG_OPTION_ASCII_RANGE |
+ ONIG_OPTION_MULTILINE,
+ onig_encoding,
+ syntax,
+ &onig_error_info);
+ if (onig_result != ONIG_NORMAL) {
+ char message[ONIG_MAX_ERROR_MESSAGE_LEN];
+ onig_error_code_to_str(message, onig_result, onig_error_info);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[operator][regexp] "
+ "failed to create regular expression object: <%.*s>: %s",
+ pattern_len, pattern,
+ message);
+ return NULL;
+ }
+
+ return regex;
+}
+
+static grn_bool
+regexp_is_match(grn_ctx *ctx, OnigRegex regex,
+ const char *target, unsigned int target_len)
+{
+ OnigPosition position;
+
+ position = onig_search(regex,
+ target,
+ target + target_len,
+ target,
+ target + target_len,
+ NULL,
+ ONIG_OPTION_NONE);
+ return position != ONIG_MISMATCH;
+}
+#endif /* GRN_SUPPORT_REGEXP */
+
+static grn_bool
+string_have_sub_text(grn_ctx *ctx,
+ const char *text, unsigned int text_len,
+ const char *sub_text, unsigned int sub_text_len)
+{
+ if (sub_text_len == 0) {
+ return GRN_FALSE;
+ }
+
+ if (sub_text_len > text_len) {
+ return GRN_FALSE;
+ }
+
+#ifdef GRN_SUPPORT_REGEXP
+ {
+ OnigRegex regex;
+ grn_bool matched;
+
+ regex = regexp_compile(ctx, sub_text, sub_text_len, ONIG_SYNTAX_ASIS);
+ if (!regex) {
+ return GRN_FALSE;
+ }
+
+ matched = regexp_is_match(ctx, regex, text, text_len);
+ onig_free(regex);
+ return matched;
+ }
+#else /* GRN_SUPPORT_REGEXP */
+ {
+ const char *text_current = text;
+ const char *text_end = text + text_len;
+ const char *sub_text_current = sub_text;
+ const char *sub_text_end = sub_text + sub_text_len;
+ int sub_text_start_char_len;
+ int sub_text_char_len;
+
+ sub_text_start_char_len = grn_charlen(ctx, sub_text, sub_text_end);
+ if (sub_text_start_char_len == 0) {
+ return GRN_FALSE;
+ }
+ sub_text_char_len = sub_text_start_char_len;
+
+ while (text_current < text_end) {
+ int text_char_len;
+
+ text_char_len = grn_charlen(ctx, text_current, text_end);
+ if (text_char_len == 0) {
+ return GRN_FALSE;
+ }
+
+ if (text_char_len == sub_text_char_len &&
+ memcmp(text_current, sub_text_current, text_char_len) == 0) {
+ sub_text_current += sub_text_char_len;
+ if (sub_text_current == sub_text_end) {
+ return GRN_TRUE;
+ }
+
+ sub_text_char_len = grn_charlen(ctx, sub_text_current, sub_text_end);
+ if (sub_text_char_len == 0) {
+ return GRN_FALSE;
+ }
+ } else {
+ if (sub_text_current != sub_text) {
+ sub_text_current = sub_text;
+ sub_text_char_len = sub_text_start_char_len;
+ continue;
+ }
+ }
+
+ text_current += text_char_len;
+ }
+
+ return GRN_FALSE;
+ }
+#endif /* GRN_SUPPORT_REGEXP */
+}
+
+static grn_bool
+string_have_prefix(grn_ctx *ctx,
+ const char *target, unsigned int target_len,
+ const char *prefix, unsigned int prefix_len)
+{
+ return (target_len >= prefix_len &&
+ strncmp(target, prefix, prefix_len) == 0);
+}
+
+static grn_bool
+string_match_regexp(grn_ctx *ctx,
+ const char *target, unsigned int target_len,
+ const char *pattern, unsigned int pattern_len)
+{
+#ifdef GRN_SUPPORT_REGEXP
+ OnigRegex regex;
+ grn_bool matched;
+
+ regex = regexp_compile(ctx, pattern, pattern_len, ONIG_SYNTAX_RUBY);
+ if (!regex) {
+ return GRN_FALSE;
+ }
+
+ matched = regexp_is_match(ctx, regex, target, target_len);
+ onig_free(regex);
+ return matched;
+#else /* GRN_SUPPORT_REGEXP */
+ return GRN_FALSE;
+#endif /* GRN_SUPPORT_REGEXP */
+}
+
+static grn_bool
+exec_text_operator(grn_ctx *ctx,
+ grn_operator op,
+ const char *target,
+ unsigned int target_len,
+ const char *query,
+ unsigned int query_len)
+{
+ grn_bool matched = GRN_FALSE;
+
+ if (target_len == 0 || query_len == 0) {
+ return GRN_FALSE;
+ }
+
+ switch (op) {
+ case GRN_OP_MATCH :
+ matched = string_have_sub_text(ctx, target, target_len, query, query_len);
+ break;
+ case GRN_OP_PREFIX :
+ matched = string_have_prefix(ctx, target, target_len, query, query_len);
+ break;
+ case GRN_OP_REGEXP :
+ matched = string_match_regexp(ctx, target, target_len, query, query_len);
+ break;
+ default :
+ matched = GRN_FALSE;
+ break;
+ }
+
+ return matched;
+}
+
+static grn_bool
+exec_text_operator_raw_text_raw_text(grn_ctx *ctx,
+ grn_operator op,
+ const char *target,
+ unsigned int target_len,
+ const char *query,
+ unsigned int query_len)
+{
+ grn_obj *normalizer;
+ grn_obj *norm_target;
+ grn_obj *norm_query;
+ const char *norm_target_raw;
+ const char *norm_query_raw;
+ unsigned int norm_target_raw_length_in_bytes;
+ unsigned int norm_query_raw_length_in_bytes;
+ grn_bool matched = GRN_FALSE;
+
+ if (target_len == 0 || query_len == 0) {
+ return GRN_FALSE;
+ }
+
+ normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ norm_target = grn_string_open(ctx, target, target_len, normalizer, 0);
+ grn_string_get_normalized(ctx, norm_target,
+ &norm_target_raw,
+ &norm_target_raw_length_in_bytes,
+ NULL);
+
+ if (op == GRN_OP_REGEXP) {
+ norm_query = NULL;
+ norm_query_raw = query;
+ norm_query_raw_length_in_bytes = query_len;
+ } else {
+ norm_query = grn_string_open(ctx, query, query_len, normalizer, 0);
+ grn_string_get_normalized(ctx, norm_query,
+ &norm_query_raw,
+ &norm_query_raw_length_in_bytes,
+ NULL);
+ }
+
+ matched = exec_text_operator(ctx, op,
+ norm_target_raw,
+ norm_target_raw_length_in_bytes,
+ norm_query_raw,
+ norm_query_raw_length_in_bytes);
+
+ grn_obj_close(ctx, norm_target);
+ if (norm_query) {
+ grn_obj_close(ctx, norm_query);
+ }
+ grn_obj_unlink(ctx, normalizer);
+
+ return matched;
+}
+
+static grn_bool
+exec_text_operator_record_text(grn_ctx *ctx,
+ grn_operator op,
+ grn_obj *record, grn_obj *table,
+ grn_obj *query)
+{
+ grn_obj *normalizer;
+ char record_key[GRN_TABLE_MAX_KEY_SIZE];
+ int record_key_len;
+ grn_bool matched = GRN_FALSE;
+
+ if (table->header.domain != GRN_DB_SHORT_TEXT) {
+ return GRN_FALSE;
+ }
+
+ if (GRN_TEXT_LEN(query) == 0) {
+ return GRN_FALSE;
+ }
+
+ record_key_len = grn_table_get_key(ctx, table, GRN_RECORD_VALUE(record),
+ record_key, GRN_TABLE_MAX_KEY_SIZE);
+ grn_table_get_info(ctx, table, NULL, NULL, NULL, &normalizer, NULL);
+ if (normalizer) {
+ grn_obj *norm_query;
+ const char *norm_query_raw;
+ unsigned int norm_query_raw_length_in_bytes;
+
+ if (op == GRN_OP_REGEXP) {
+ norm_query = NULL;
+ norm_query_raw = GRN_TEXT_VALUE(query);
+ norm_query_raw_length_in_bytes = GRN_TEXT_LEN(query);
+ } else {
+ norm_query = grn_string_open(ctx,
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query),
+ normalizer,
+ 0);
+ grn_string_get_normalized(ctx, norm_query,
+ &norm_query_raw,
+ &norm_query_raw_length_in_bytes,
+ NULL);
+ }
+ matched = exec_text_operator(ctx,
+ op,
+ record_key,
+ record_key_len,
+ norm_query_raw,
+ norm_query_raw_length_in_bytes);
+ if (norm_query) {
+ grn_obj_close(ctx, norm_query);
+ }
+ } else {
+ matched = exec_text_operator_raw_text_raw_text(ctx,
+ op,
+ record_key,
+ record_key_len,
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query));
+ }
+
+ return matched;
+}
+
+static grn_bool
+exec_text_operator_text_text(grn_ctx *ctx,
+ grn_operator op,
+ grn_obj *target,
+ grn_obj *query)
+{
+ return exec_text_operator_raw_text_raw_text(ctx,
+ op,
+ GRN_TEXT_VALUE(target),
+ GRN_TEXT_LEN(target),
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query));
+}
+
+static grn_bool
+exec_text_operator_bulk_bulk(grn_ctx *ctx,
+ grn_operator op,
+ grn_obj *target,
+ grn_obj *query)
+{
+ switch (target->header.domain) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ switch (query->header.domain) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ return exec_text_operator_text_text(ctx, op, target, query);
+ default :
+ break;
+ }
+ return GRN_FALSE;
+ default:
+ {
+ grn_obj *domain;
+ domain = grn_ctx_at(ctx, target->header.domain);
+ if (GRN_OBJ_TABLEP(domain)) {
+ switch (query->header.domain) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ return exec_text_operator_record_text(ctx, op, target, domain, query);
+ default :
+ break;
+ }
+ }
+ }
+ return GRN_FALSE;
+ }
+}
+
+grn_bool
+grn_operator_exec_match(grn_ctx *ctx, grn_obj *target, grn_obj *sub_text)
+{
+ grn_bool matched;
+ GRN_API_ENTER;
+ switch (target->header.type) {
+ case GRN_UVECTOR :
+ matched = exec_match_uvector_bulk(ctx, target, sub_text);
+ break;
+ case GRN_VECTOR :
+ matched = exec_match_vector_bulk(ctx, target, sub_text);
+ break;
+ default :
+ matched = exec_text_operator_bulk_bulk(ctx, GRN_OP_MATCH, target, sub_text);
+ break;
+ }
+ GRN_API_RETURN(matched);
+}
+
+grn_bool
+grn_operator_exec_prefix(grn_ctx *ctx, grn_obj *target, grn_obj *prefix)
+{
+ grn_bool matched;
+ GRN_API_ENTER;
+ matched = exec_text_operator_bulk_bulk(ctx, GRN_OP_PREFIX, target, prefix);
+ GRN_API_RETURN(matched);
+}
+
+static grn_bool
+exec_regexp_uvector_bulk(grn_ctx *ctx, grn_obj *uvector, grn_obj *pattern)
+{
+#ifdef GRN_SUPPORT_REGEXP
+ grn_bool matched = GRN_FALSE;
+ unsigned int i, size;
+ OnigRegex regex;
+ grn_obj *domain;
+ grn_obj *normalizer;
+ grn_obj *normalizer_auto = NULL;
+
+ size = grn_uvector_size(ctx, uvector);
+ if (size == 0) {
+ return GRN_FALSE;
+ }
+
+ regex = regexp_compile(ctx,
+ GRN_TEXT_VALUE(pattern),
+ GRN_TEXT_LEN(pattern),
+ ONIG_SYNTAX_RUBY);
+ if (!regex) {
+ return GRN_FALSE;
+ }
+
+ domain = grn_ctx_at(ctx, uvector->header.domain);
+ if (!domain) {
+ onig_free(regex);
+ return GRN_FALSE;
+ }
+
+ grn_table_get_info(ctx, domain, NULL, NULL, NULL, &normalizer, NULL);
+ if (!normalizer) {
+ normalizer_auto = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ }
+
+ for (i = 0; i < size; i++) {
+ grn_id record_id;
+ char key[GRN_TABLE_MAX_KEY_SIZE];
+ int key_size;
+
+ record_id = grn_uvector_get_element(ctx, uvector, i, NULL);
+ key_size = grn_table_get_key(ctx, domain, record_id,
+ key, GRN_TABLE_MAX_KEY_SIZE);
+ if (key_size == 0) {
+ continue;
+ }
+
+ if (normalizer) {
+ matched = regexp_is_match(ctx, regex, key, key_size);
+ } else {
+ grn_obj *norm_key;
+ const char *norm_key_raw;
+ unsigned int norm_key_raw_length_in_bytes;
+
+ norm_key = grn_string_open(ctx, key, key_size, normalizer_auto, 0);
+ grn_string_get_normalized(ctx, norm_key,
+ &norm_key_raw,
+ &norm_key_raw_length_in_bytes,
+ NULL);
+ matched = regexp_is_match(ctx, regex,
+ norm_key_raw,
+ norm_key_raw_length_in_bytes);
+ grn_obj_unlink(ctx, norm_key);
+ }
+
+ if (matched) {
+ break;
+ }
+ }
+
+ if (normalizer_auto) {
+ grn_obj_unlink(ctx, normalizer_auto);
+ }
+
+ grn_obj_unlink(ctx, domain);
+
+ onig_free(regex);
+
+ return matched;
+#else /* GRN_SUPPORT_REGEXP */
+ return GRN_FALSE;
+#endif /* GRN_SUPPORT_REGEXP */
+}
+
+static grn_bool
+exec_regexp_vector_bulk(grn_ctx *ctx, grn_obj *vector, grn_obj *pattern)
+{
+#ifdef GRN_SUPPORT_REGEXP
+ grn_obj *normalizer = NULL;
+ grn_bool matched = GRN_FALSE;
+ unsigned int i, size;
+ OnigRegex regex;
+
+ size = grn_vector_size(ctx, vector);
+ if (size == 0) {
+ return GRN_FALSE;
+ }
+
+ regex = regexp_compile(ctx,
+ GRN_TEXT_VALUE(pattern),
+ GRN_TEXT_LEN(pattern),
+ ONIG_SYNTAX_RUBY);
+ if (!regex) {
+ return GRN_FALSE;
+ }
+
+ normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ for (i = 0; i < size; i++) {
+ const char *content;
+ unsigned int content_size;
+ grn_id domain_id;
+ grn_obj *norm_content;
+ const char *norm_content_raw;
+ unsigned int norm_content_raw_length_in_bytes;
+
+ content_size = grn_vector_get_element(ctx, vector, i,
+ &content, NULL, &domain_id);
+ if (content_size == 0) {
+ continue;
+ }
+
+ norm_content = grn_string_open(ctx, content, content_size, normalizer, 0);
+ grn_string_get_normalized(ctx, norm_content,
+ &norm_content_raw,
+ &norm_content_raw_length_in_bytes,
+ NULL);
+
+ matched = regexp_is_match(ctx, regex,
+ norm_content_raw,
+ norm_content_raw_length_in_bytes);
+
+ grn_obj_unlink(ctx, norm_content);
+
+ if (matched) {
+ break;
+ }
+ }
+ grn_obj_unlink(ctx, normalizer);
+
+ onig_free(regex);
+
+ return matched;
+#else /* GRN_SUPPORT_REGEXP */
+ return GRN_FALSE;
+#endif /* GRN_SUPPORT_REGEXP */
+}
+
+grn_bool
+grn_operator_exec_regexp(grn_ctx *ctx, grn_obj *target, grn_obj *pattern)
+{
+ grn_bool matched = GRN_FALSE;
+ GRN_API_ENTER;
+ switch (target->header.type) {
+ case GRN_UVECTOR :
+ matched = exec_regexp_uvector_bulk(ctx, target, pattern);
+ break;
+ case GRN_VECTOR :
+ matched = exec_regexp_vector_bulk(ctx, target, pattern);
+ break;
+ case GRN_BULK :
+ matched = exec_text_operator_bulk_bulk(ctx, GRN_OP_REGEXP, target, pattern);
+ break;
+ default :
+ matched = GRN_FALSE;
+ break;
+ }
+ GRN_API_RETURN(matched);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/output.c b/storage/mroonga/vendor/groonga/lib/output.c
new file mode 100644
index 00000000..76b9845a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/output.c
@@ -0,0 +1,2880 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2009-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+
+#include <string.h>
+#include "grn_str.h"
+#include "grn_db.h"
+#include "grn_expr_code.h"
+#include "grn_util.h"
+#include "grn_output.h"
+
+#define LEVELS (&ctx->impl->output.levels)
+#define DEPTH (GRN_BULK_VSIZE(LEVELS)>>2)
+#define CURR_LEVEL (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1))) : 0)
+#define INCR_DEPTH(i) GRN_UINT32_PUT(ctx, LEVELS, i)
+#define DECR_DEPTH (DEPTH ? grn_bulk_truncate(ctx, LEVELS, GRN_BULK_VSIZE(LEVELS) - sizeof(uint32_t)) : 0)
+#define INCR_LENGTH (DEPTH ? (GRN_UINT32_VALUE_AT(LEVELS, (DEPTH - 1)) += 2) : 0)
+
+static void
+indent(grn_ctx *ctx, grn_obj *outbuf, size_t level)
+{
+ size_t i;
+ for (i = 0; i < level; i++) {
+ GRN_TEXT_PUTS(ctx, outbuf, " ");
+ }
+}
+
+static void
+json_array_open(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
+{
+ GRN_TEXT_PUTC(ctx, outbuf, '[');
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ (*indent_level)++;
+ indent(ctx, outbuf, *indent_level);
+ }
+}
+
+static void
+json_array_close(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
+{
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ (*indent_level)--;
+ indent(ctx, outbuf, *indent_level);
+ }
+ GRN_TEXT_PUTC(ctx, outbuf, ']');
+}
+
+static void
+json_element_end(grn_ctx *ctx, grn_obj *outbuf, size_t indent_level)
+{
+ GRN_TEXT_PUTC(ctx, outbuf, ',');
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ indent(ctx, outbuf, indent_level);
+ }
+}
+
+static void
+json_map_open(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
+{
+ GRN_TEXT_PUTC(ctx, outbuf, '{');
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ (*indent_level)++;
+ indent(ctx, outbuf, *indent_level);
+ }
+}
+
+static void
+json_map_close(grn_ctx *ctx, grn_obj *outbuf, size_t *indent_level)
+{
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ (*indent_level)--;
+ indent(ctx, outbuf, *indent_level);
+ }
+ GRN_TEXT_PUTC(ctx, outbuf, '}');
+}
+
+static void
+json_key_end(grn_ctx *ctx, grn_obj *outbuf)
+{
+ GRN_TEXT_PUTC(ctx, outbuf, ':');
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, ' ');
+ }
+}
+
+static void
+json_key(grn_ctx *ctx, grn_obj *outbuf, const char *key)
+{
+ grn_text_esc(ctx, outbuf, key, strlen(key));
+ json_key_end(ctx, outbuf);
+}
+
+static void
+json_value_end(grn_ctx *ctx, grn_obj *outbuf, size_t indent_level)
+{
+ GRN_TEXT_PUTC(ctx, outbuf, ',');
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ indent(ctx, outbuf, indent_level);
+ }
+}
+
+static void
+put_delimiter(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
+{
+ uint32_t level = CURR_LEVEL;
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ if (level < 2) {
+ if (DEPTH > 0 && ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ indent(ctx, outbuf, DEPTH + 1);
+ }
+ return;
+ }
+ if ((level & 3) == 3) {
+ GRN_TEXT_PUTC(ctx, outbuf, ':');
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, ' ');
+ }
+ } else {
+ json_element_end(ctx, outbuf, DEPTH + 1);
+ }
+ // if (DEPTH == 1 && ((level & 3) != 3)) { GRN_TEXT_PUTC(ctx, outbuf, '\n'); }
+ break;
+ case GRN_CONTENT_XML:
+ if (!DEPTH) { return; }
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ break;
+ case GRN_CONTENT_TSV:
+ if (level < 2) { return; }
+ if (DEPTH <= 2) {
+ GRN_TEXT_PUTC(ctx, outbuf, ((level & 3) == 3) ? '\t' : '\n');
+ } else {
+ GRN_TEXT_PUTC(ctx, outbuf, '\t');
+ }
+ case GRN_CONTENT_MSGPACK :
+ // do nothing
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+}
+
+void
+grn_output_array_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *name, int nelements)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ GRN_TEXT_PUTC(ctx, outbuf, '[');
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTC(ctx, outbuf, '<');
+ GRN_TEXT_PUTS(ctx, outbuf, name);
+ GRN_TEXT_PUTC(ctx, outbuf, '>');
+ grn_vector_add_element(ctx,
+ &ctx->impl->output.names,
+ name, strlen(name),
+ 0, GRN_DB_SHORT_TEXT);
+ break;
+ case GRN_CONTENT_TSV:
+ if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "[\t"); }
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ if (nelements < 0) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "grn_output_array_open nelements (%d) for <%s>",
+ nelements,
+ name);
+ }
+ msgpack_pack_array(&ctx->impl->output.msgpacker, nelements);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_DEPTH(0);
+}
+
+void
+grn_output_array_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
+{
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ indent(ctx, outbuf, DEPTH);
+ }
+ GRN_TEXT_PUTC(ctx, outbuf, ']');
+ break;
+ case GRN_CONTENT_TSV:
+ if (DEPTH > 3) {
+ if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
+ GRN_TEXT_PUTC(ctx, outbuf, ']');
+ }
+ break;
+ case GRN_CONTENT_XML:
+ {
+ const char *name;
+ unsigned int name_len;
+ name_len = grn_vector_pop_element(ctx,
+ &ctx->impl->output.names,
+ &name, NULL, NULL);
+ GRN_TEXT_PUTS(ctx, outbuf, "</");
+ GRN_TEXT_PUT(ctx, outbuf, name, name_len);
+ GRN_TEXT_PUTC(ctx, outbuf, '>');
+ }
+ break;
+ case GRN_CONTENT_MSGPACK :
+ // do nothing
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ DECR_DEPTH;
+ INCR_LENGTH;
+}
+
+void
+grn_output_map_open(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *name, int nelements)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ GRN_TEXT_PUTS(ctx, outbuf, "{");
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTC(ctx, outbuf, '<');
+ GRN_TEXT_PUTS(ctx, outbuf, name);
+ GRN_TEXT_PUTC(ctx, outbuf, '>');
+ grn_vector_add_element(ctx,
+ &ctx->impl->output.names,
+ name, strlen(name), 0, GRN_DB_SHORT_TEXT);
+ break;
+ case GRN_CONTENT_TSV:
+ if (DEPTH > 2) { GRN_TEXT_PUTS(ctx, outbuf, "{\t"); }
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ if (nelements < 0) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG,
+ "grn_output_map_open nelements (%d) for <%s>",
+ nelements,
+ name);
+ }
+ msgpack_pack_map(&ctx->impl->output.msgpacker, nelements);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_DEPTH(1);
+}
+
+void
+grn_output_map_close(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
+{
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ if (ctx->impl->output.is_pretty) {
+ GRN_TEXT_PUTC(ctx, outbuf, '\n');
+ indent(ctx, outbuf, DEPTH);
+ }
+ GRN_TEXT_PUTS(ctx, outbuf, "}");
+ break;
+ case GRN_CONTENT_TSV:
+ if (DEPTH > 3) {
+ if (CURR_LEVEL >= 2) { GRN_TEXT_PUTC(ctx, outbuf, '\t'); }
+ GRN_TEXT_PUTC(ctx, outbuf, '}');
+ }
+ break;
+ case GRN_CONTENT_XML:
+ {
+ const char *name;
+ unsigned int name_len;
+ name_len = grn_vector_pop_element(ctx,
+ &ctx->impl->output.names,
+ &name, NULL, NULL);
+ GRN_TEXT_PUTS(ctx, outbuf, "</");
+ GRN_TEXT_PUT(ctx, outbuf, name, name_len);
+ GRN_TEXT_PUTC(ctx, outbuf, '>');
+ }
+ break;
+ case GRN_CONTENT_MSGPACK :
+ // do nothing
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ DECR_DEPTH;
+ INCR_LENGTH;
+}
+
+void
+grn_output_int32(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int value)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ grn_text_itoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_itoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
+ grn_text_itoa(ctx, outbuf, value);
+ GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_int32(&ctx->impl->output.msgpacker, value);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ grn_text_itoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_int64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ grn_text_lltoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_lltoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
+ grn_text_lltoa(ctx, outbuf, value);
+ GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_int64(&ctx->impl->output.msgpacker, value);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ grn_text_lltoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_uint64(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, uint64_t value)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ grn_text_ulltoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_ulltoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<INT>");
+ grn_text_ulltoa(ctx, outbuf, value);
+ GRN_TEXT_PUTS(ctx, outbuf, "</INT>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_uint64(&ctx->impl->output.msgpacker, value);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ grn_text_ulltoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_float(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, double value)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ grn_text_ftoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_ftoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<FLOAT>");
+ grn_text_ftoa(ctx, outbuf, value);
+ GRN_TEXT_PUTS(ctx, outbuf, "</FLOAT>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_double(&ctx->impl->output.msgpacker, value);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ grn_text_ftoa(ctx, outbuf, value);
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_str(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *value, size_t value_len)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ grn_text_esc(ctx, outbuf, value, value_len);
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_esc(ctx, outbuf, value, value_len);
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<TEXT>");
+ grn_text_escape_xml(ctx, outbuf, value, value_len);
+ GRN_TEXT_PUTS(ctx, outbuf, "</TEXT>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_str(&ctx->impl->output.msgpacker, value_len);
+ msgpack_pack_str_body(&ctx->impl->output.msgpacker, value, value_len);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ GRN_TEXT_PUT(ctx, outbuf, value, value_len);
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_cstr(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *value)
+{
+ grn_output_str(ctx, outbuf, output_type, value, strlen(value));
+}
+
+void
+grn_output_bool(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, grn_bool value)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
+ break;
+ case GRN_CONTENT_TSV:
+ GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<BOOL>");
+ GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
+ GRN_TEXT_PUTS(ctx, outbuf, "</BOOL>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ if (value) {
+ msgpack_pack_true(&ctx->impl->output.msgpacker);
+ } else {
+ msgpack_pack_false(&ctx->impl->output.msgpacker);
+ }
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ GRN_TEXT_PUTS(ctx, outbuf, value ? "true" : "false");
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_null(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ GRN_TEXT_PUTS(ctx, outbuf, "null");
+ break;
+ case GRN_CONTENT_TSV:
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<NULL/>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_nil(&ctx->impl->output.msgpacker);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+static inline void
+grn_output_bulk_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ const char *value, size_t value_len)
+{
+ if (value_len == sizeof(grn_id) && *(grn_id *)value == GRN_ID_NIL) {
+ grn_output_null(ctx, outbuf, output_type);
+ } else {
+ grn_output_str(ctx, outbuf, output_type, value, value_len);
+ }
+}
+
+void
+grn_output_time(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type, int64_t value)
+{
+ double dv = value;
+ dv /= 1000000.0;
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ grn_text_ftoa(ctx, outbuf, dv);
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_ftoa(ctx, outbuf, dv);
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<DATE>");
+ grn_text_ftoa(ctx, outbuf, dv);
+ GRN_TEXT_PUTS(ctx, outbuf, "</DATE>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ msgpack_pack_double(&ctx->impl->output.msgpacker, dv);
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ grn_text_ftoa(ctx, outbuf, dv);
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+void
+grn_output_geo_point(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_geo_point *value)
+{
+ put_delimiter(ctx, outbuf, output_type);
+ switch (output_type) {
+ case GRN_CONTENT_JSON:
+ if (value) {
+ GRN_TEXT_PUTC(ctx, outbuf, '"');
+ grn_text_itoa(ctx, outbuf, value->latitude);
+ GRN_TEXT_PUTC(ctx, outbuf, 'x');
+ grn_text_itoa(ctx, outbuf, value->longitude);
+ GRN_TEXT_PUTC(ctx, outbuf, '"');
+ } else {
+ GRN_TEXT_PUTS(ctx, outbuf, "null");
+ }
+ break;
+ case GRN_CONTENT_TSV:
+ if (value) {
+ GRN_TEXT_PUTC(ctx, outbuf, '"');
+ grn_text_itoa(ctx, outbuf, value->latitude);
+ GRN_TEXT_PUTC(ctx, outbuf, 'x');
+ grn_text_itoa(ctx, outbuf, value->longitude);
+ GRN_TEXT_PUTC(ctx, outbuf, '"');
+ } else {
+ GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
+ }
+ break;
+ case GRN_CONTENT_XML:
+ GRN_TEXT_PUTS(ctx, outbuf, "<GEO_POINT>");
+ if (value) {
+ grn_text_itoa(ctx, outbuf, value->latitude);
+ GRN_TEXT_PUTC(ctx, outbuf, 'x');
+ grn_text_itoa(ctx, outbuf, value->longitude);
+ }
+ GRN_TEXT_PUTS(ctx, outbuf, "</GEO_POINT>");
+ break;
+ case GRN_CONTENT_MSGPACK :
+#ifdef GRN_WITH_MESSAGE_PACK
+ if (value) {
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ grn_text_itoa(ctx, &buf, value->latitude);
+ GRN_TEXT_PUTC(ctx, &buf, 'x');
+ grn_text_itoa(ctx, &buf, value->longitude);
+ msgpack_pack_str(&ctx->impl->output.msgpacker, GRN_TEXT_LEN(&buf));
+ msgpack_pack_str_body(&ctx->impl->output.msgpacker,
+ GRN_TEXT_VALUE(&buf),
+ GRN_TEXT_LEN(&buf));
+ grn_obj_close(ctx, &buf);
+ } else {
+ msgpack_pack_nil(&ctx->impl->output.msgpacker);
+ }
+#endif
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ if (value) {
+ GRN_TEXT_PUTC(ctx, outbuf, '"');
+ grn_text_itoa(ctx, outbuf, value->latitude);
+ GRN_TEXT_PUTC(ctx, outbuf, 'x');
+ grn_text_itoa(ctx, outbuf, value->longitude);
+ GRN_TEXT_PUTC(ctx, outbuf, '"');
+ } else {
+ GRN_TEXT_PUTS(ctx, outbuf, "\"\"");
+ }
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+ INCR_LENGTH;
+}
+
+static void
+grn_text_atoj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *obj, grn_id id)
+{
+ uint32_t vs;
+ grn_obj buf;
+ if (obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a = (grn_accessor *)obj;
+ GRN_TEXT_INIT(&buf, 0);
+ for (;;) {
+ buf.header.domain = grn_obj_get_range(ctx, obj);
+ GRN_BULK_REWIND(&buf);
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ GRN_UINT32_PUT(ctx, &buf, id);
+ buf.header.domain = GRN_DB_UINT32;
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ grn_table_get_key2(ctx, a->obj, id, &buf);
+ buf.header.domain = DB_OBJ(a->obj)->header.domain;
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ buf.header.domain = DB_OBJ(a->obj)->range;
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ {
+ grn_rset_recinfo *ri =
+ (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
+ int32_t int32_score = ri->score;
+ GRN_INT32_PUT(ctx, &buf, int32_score);
+ buf.header.domain = GRN_DB_INT32;
+ } else {
+ double float_score = ri->score;
+ GRN_FLOAT_PUT(ctx, &buf, float_score);
+ buf.header.domain = GRN_DB_FLOAT;
+ }
+ }
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ GRN_INT32_PUT(ctx, &buf, ri->n_subrecs);
+ }
+ buf.header.domain = GRN_DB_INT32;
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int64_t max;
+ max = grn_rset_recinfo_get_max(ctx, ri, a->obj);
+ GRN_INT64_PUT(ctx, &buf, max);
+ }
+ buf.header.domain = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int64_t min;
+ min = grn_rset_recinfo_get_min(ctx, ri, a->obj);
+ GRN_INT64_PUT(ctx, &buf, min);
+ }
+ buf.header.domain = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int64_t sum;
+ sum = grn_rset_recinfo_get_sum(ctx, ri, a->obj);
+ GRN_INT64_PUT(ctx, &buf, sum);
+ }
+ buf.header.domain = GRN_DB_INT64;
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ double avg;
+ avg = grn_rset_recinfo_get_avg(ctx, ri, a->obj);
+ GRN_FLOAT_PUT(ctx, &buf, avg);
+ }
+ buf.header.domain = GRN_DB_FLOAT;
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ if ((a->obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
+ if (a->next) {
+ grn_id *idp;
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ idp = (grn_id *)GRN_BULK_HEAD(&buf);
+ vs = GRN_BULK_VSIZE(&buf) / sizeof(grn_id);
+ grn_output_array_open(ctx, outbuf, output_type, "VECTOR", vs);
+ for (; vs--; idp++) {
+ grn_text_atoj(ctx, outbuf, output_type, (grn_obj *)a->next, *idp);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ } else {
+ grn_text_atoj(ctx, outbuf, output_type, a->obj, id);
+ }
+ goto exit;
+ } else {
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ }
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ /* todo */
+ break;
+ }
+ if (a->next) {
+ a = a->next;
+ if ((size_t) GRN_BULK_VSIZE(&buf) >= sizeof(grn_id)) {
+ id = *((grn_id *)GRN_BULK_HEAD(&buf));
+ } else {
+ id = GRN_ID_NIL;
+ }
+ } else {
+ break;
+ }
+ }
+ grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
+ } else {
+ grn_obj_format *format_argument = NULL;
+ grn_obj_format format;
+ GRN_OBJ_FORMAT_INIT(&format, 0, 0, 0, 0);
+ switch (obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ GRN_VALUE_FIX_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ if ((obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
+ grn_obj *range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
+ if (GRN_OBJ_TABLEP(range) ||
+ (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) == 0) {
+ GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
+ } else {
+ GRN_VALUE_VAR_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
+ }
+ if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ format.flags |= GRN_OBJ_FORMAT_WITH_WEIGHT;
+ format_argument = &format;
+ }
+ } else {
+ GRN_VALUE_VAR_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ GRN_UINT32_INIT(&buf, 0);
+ break;
+ default:
+ GRN_TEXT_INIT(&buf, 0);
+ break;
+ }
+ grn_obj_get_value(ctx, obj, id, &buf);
+ grn_output_obj(ctx, outbuf, output_type, &buf, format_argument);
+ }
+exit :
+ grn_obj_close(ctx, &buf);
+}
+
+static inline void
+grn_output_void(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *bulk, grn_obj_format *format)
+{
+ grn_output_null(ctx, outbuf, output_type);
+}
+
+static inline void
+grn_output_bulk(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *bulk, grn_obj_format *format)
+{
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ switch (bulk->header.domain) {
+ case GRN_DB_VOID :
+ grn_output_bulk_void(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
+ break;
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ grn_output_str(ctx, outbuf, output_type, GRN_BULK_HEAD(bulk), GRN_BULK_VSIZE(bulk));
+ break;
+ case GRN_DB_BOOL :
+ grn_output_bool(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_INT8 :
+ grn_output_int32(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_INT8_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_UINT8 :
+ grn_output_int32(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_UINT8_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_INT16 :
+ grn_output_int32(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_INT16_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_UINT16 :
+ grn_output_int32(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_UINT16_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_INT32 :
+ grn_output_int32(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_INT32_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_UINT32 :
+ grn_output_int64(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_UINT32_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_INT64 :
+ grn_output_int64(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_UINT64 :
+ grn_output_uint64(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_UINT64_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_FLOAT :
+ grn_output_float(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_FLOAT_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_TIME :
+ grn_output_time(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? GRN_INT64_VALUE(bulk) : 0);
+ break;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ grn_output_geo_point(ctx, outbuf, output_type,
+ GRN_BULK_VSIZE(bulk) ? (grn_geo_point *)GRN_BULK_HEAD(bulk) : NULL);
+ break;
+ default :
+ if (format) {
+ int j;
+ int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
+ grn_id id = GRN_RECORD_VALUE(bulk);
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", ncolumns);
+ for (j = 0; j < ncolumns; j++) {
+ grn_id range_id;
+ grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
+ GRN_BULK_REWIND(&buf);
+ grn_column_name_(ctx, columns[j], &buf);
+ grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
+ /* column range */
+ range_id = grn_obj_get_range(ctx, columns[j]);
+ if (range_id == GRN_ID_NIL) {
+ GRN_TEXT_PUTS(ctx, outbuf, "null");
+ } else {
+ int name_len;
+ grn_obj *range_obj;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+
+ range_obj = grn_ctx_at(ctx, range_id);
+ name_len = grn_obj_name(ctx, range_obj, name_buf,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_BULK_REWIND(&buf);
+ GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
+ grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+ grn_output_array_open(ctx, outbuf, output_type, "HIT", ncolumns);
+ for (j = 0; j < ncolumns; j++) {
+ grn_text_atoj(ctx, outbuf, output_type, columns[j], id);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ } else {
+ grn_obj *table = grn_ctx_at(ctx, bulk->header.domain);
+ grn_id id = GRN_RECORD_VALUE(bulk);
+ if (table && table->header.type != GRN_TABLE_NO_KEY) {
+ grn_obj *accessor = grn_obj_column(ctx, table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ if (accessor) {
+ if (id == GRN_ID_NIL) {
+ grn_obj_reinit_for(ctx, &buf, accessor);
+ } else {
+ grn_obj_get_value(ctx, accessor, id, &buf);
+ }
+ grn_obj_unlink(ctx, accessor);
+ }
+ grn_output_obj(ctx, outbuf, output_type, &buf, format);
+ } else {
+ grn_output_int64(ctx, outbuf, output_type, id);
+ }
+ }
+ break;
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static void
+grn_output_uvector_result_set(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *uvector,
+ grn_obj_format *format)
+{
+ unsigned int i_hit, n_hits;
+ unsigned int i_column, n_columns;
+ unsigned int n_elements;
+ grn_obj **columns;
+ grn_obj buf;
+ grn_bool with_column_names = GRN_FALSE;
+
+ n_hits = grn_vector_size(ctx, uvector);
+
+ n_columns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
+ columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+
+ GRN_TEXT_INIT(&buf, 0);
+
+ if (n_hits > 0 && format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ with_column_names = GRN_TRUE;
+ }
+
+ n_elements = 1; /* for NHITS */
+ if (with_column_names) {
+ n_elements += 1; /* for COLUMNS */
+ }
+ n_elements += n_hits; /* for HITS */
+ grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", n_elements);
+
+ grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
+ grn_text_itoa(ctx, outbuf, n_hits);
+ grn_output_array_close(ctx, outbuf, output_type);
+
+ if (with_column_names) {
+ grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_columns);
+ for (i_column = 0; i_column < n_columns; i_column++) {
+ grn_id range_id;
+ grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
+
+ /* name */
+ GRN_BULK_REWIND(&buf);
+ grn_column_name_(ctx, columns[i_column], &buf);
+ grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
+
+ /* type */
+ range_id = grn_obj_get_range(ctx, columns[i_column]);
+ if (range_id == GRN_ID_NIL) {
+ GRN_TEXT_PUTS(ctx, outbuf, "null");
+ } else {
+ int name_len;
+ grn_obj *range_obj;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+
+ range_obj = grn_ctx_at(ctx, range_id);
+ name_len = grn_obj_name(ctx, range_obj, name_buf,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_BULK_REWIND(&buf);
+ GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
+ grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
+ }
+
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+
+ for (i_hit = 0; i_hit < n_hits++; i_hit++) {
+ grn_id id;
+
+ id = grn_uvector_get_element(ctx, uvector, i_hit, NULL);
+ grn_output_array_open(ctx, outbuf, output_type, "HITS", n_columns);
+ for (i_column = 0; i_column < n_columns; i_column++) {
+ GRN_BULK_REWIND(&buf);
+ grn_obj_get_value(ctx, columns[i_column], id, &buf);
+ grn_output_obj(ctx, outbuf, output_type, &buf, NULL);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+
+ grn_output_array_close(ctx, outbuf, output_type);
+
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static inline void
+grn_output_uvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *uvector, grn_obj_format *format)
+{
+ grn_bool output_result_set = GRN_FALSE;
+ grn_bool with_weight = GRN_FALSE;
+ grn_obj *range;
+ grn_bool range_is_type;
+
+ if (format) {
+ if (GRN_BULK_VSIZE(&(format->columns)) > 0) {
+ output_result_set = GRN_TRUE;
+ }
+ if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
+ with_weight = GRN_TRUE;
+ }
+ }
+
+ if (output_result_set) {
+ grn_output_uvector_result_set(ctx, outbuf, output_type, uvector, format);
+ return;
+ }
+
+ range = grn_ctx_at(ctx, uvector->header.domain);
+ range_is_type = (range->header.type == GRN_TYPE);
+ if (range_is_type) {
+ unsigned int i, n;
+ char *raw_elements;
+ unsigned int element_size;
+ grn_obj element;
+
+ raw_elements = GRN_BULK_HEAD(uvector);
+ element_size = GRN_TYPE_SIZE(DB_OBJ(range));
+ n = GRN_BULK_VSIZE(uvector) / element_size;
+
+ grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
+ GRN_OBJ_INIT(&element, GRN_BULK, 0, uvector->header.domain);
+ for (i = 0; i < n; i++) {
+ GRN_BULK_REWIND(&element);
+ grn_bulk_write_from(ctx, &element, raw_elements + (element_size * i),
+ 0, element_size);
+ grn_output_obj(ctx, outbuf, output_type, &element, NULL);
+ }
+ GRN_OBJ_FIN(ctx, &element);
+ grn_output_array_close(ctx, outbuf, output_type);
+ } else {
+ unsigned int i, n;
+ grn_obj id_value;
+ grn_obj key_value;
+
+ GRN_UINT32_INIT(&id_value, 0);
+ GRN_OBJ_INIT(&key_value, GRN_BULK, 0, range->header.domain);
+
+ n = grn_vector_size(ctx, uvector);
+ if (with_weight) {
+ grn_output_map_open(ctx, outbuf, output_type, "WEIGHT_VECTOR", n);
+ } else {
+ grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
+ }
+
+ for (i = 0; i < n; i++) {
+ grn_id id;
+ unsigned int weight;
+
+ id = grn_uvector_get_element(ctx, uvector, i, &weight);
+ if (range->header.type == GRN_TABLE_NO_KEY) {
+ GRN_UINT32_SET(ctx, &id_value, id);
+ grn_output_obj(ctx, outbuf, output_type, &id_value, NULL);
+ } else {
+ GRN_BULK_REWIND(&key_value);
+ grn_table_get_key2(ctx, range, id, &key_value);
+ grn_output_obj(ctx, outbuf, output_type, &key_value, NULL);
+ }
+
+ if (with_weight) {
+ grn_output_uint64(ctx, outbuf, output_type, weight);
+ }
+ }
+
+ if (with_weight) {
+ grn_output_map_close(ctx, outbuf, output_type);
+ } else {
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+
+ GRN_OBJ_FIN(ctx, &id_value);
+ GRN_OBJ_FIN(ctx, &key_value);
+ }
+ grn_obj_unlink(ctx, range);
+}
+
+static inline void
+grn_output_vector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *vector, grn_obj_format *format)
+{
+ grn_bool with_weight = GRN_FALSE;
+
+ if (vector->header.domain == GRN_DB_VOID) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
+ return;
+ }
+
+ if (format) {
+ if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
+ with_weight = GRN_TRUE;
+ }
+ }
+
+ if (with_weight) {
+ unsigned int i, n;
+ grn_obj value;
+
+ GRN_VOID_INIT(&value);
+ n = grn_vector_size(ctx, vector);
+ grn_output_map_open(ctx, outbuf, output_type, "WEIGHT_VECTOR", n);
+ for (i = 0; i < n; i++) {
+ const char *_value;
+ unsigned int weight, length;
+ grn_id domain;
+
+ length = grn_vector_get_element(ctx, vector, i,
+ &_value, &weight, &domain);
+ if (domain != GRN_DB_VOID) {
+ grn_obj_reinit(ctx, &value, domain, 0);
+ } else {
+ grn_obj_reinit(ctx, &value, vector->header.domain, 0);
+ }
+ grn_bulk_write(ctx, &value, _value, length);
+ grn_output_obj(ctx, outbuf, output_type, &value, NULL);
+ grn_output_uint64(ctx, outbuf, output_type, weight);
+ }
+ grn_output_map_close(ctx, outbuf, output_type);
+ GRN_OBJ_FIN(ctx, &value);
+ } else {
+ unsigned int i, n;
+ grn_obj value;
+ GRN_VOID_INIT(&value);
+ n = grn_vector_size(ctx, vector);
+ grn_output_array_open(ctx, outbuf, output_type, "VECTOR", n);
+ for (i = 0; i < n; i++) {
+ const char *_value;
+ unsigned int weight, length;
+ grn_id domain;
+
+ length = grn_vector_get_element(ctx, vector, i,
+ &_value, &weight, &domain);
+ if (domain != GRN_DB_VOID) {
+ grn_obj_reinit(ctx, &value, domain, 0);
+ } else {
+ grn_obj_reinit(ctx, &value, vector->header.domain, 0);
+ }
+ grn_bulk_write(ctx, &value, _value, length);
+ grn_output_obj(ctx, outbuf, output_type, &value, NULL);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ GRN_OBJ_FIN(ctx, &value);
+ }
+}
+
+static inline void
+grn_output_pvector(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *pvector, grn_obj_format *format)
+{
+ if (format) {
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "cannot print GRN_PVECTOR using grn_obj_format");
+ } else {
+ unsigned int i, n;
+ grn_output_array_open(ctx, outbuf, output_type, "VECTOR", -1);
+ n = GRN_BULK_VSIZE(pvector) / sizeof(grn_obj *);
+ for (i = 0; i < n; i++) {
+ grn_obj *value;
+
+ value = GRN_PTR_VALUE_AT(pvector, i);
+ grn_output_obj(ctx, outbuf, output_type, value, NULL);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+}
+
+static inline void
+grn_output_result_set_n_hits_v1(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj_format *format)
+{
+ grn_output_array_open(ctx, outbuf, output_type, "NHITS", 1);
+ if (output_type == GRN_CONTENT_XML) {
+ grn_text_itoa(ctx, outbuf, format->nhits);
+ } else {
+ grn_output_int32(ctx, outbuf, output_type, format->nhits);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+}
+
+static inline void
+grn_output_result_set_n_hits_v3(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj_format *format)
+{
+ grn_output_cstr(ctx, outbuf, output_type, "n_hits");
+ grn_output_int32(ctx, outbuf, output_type, format->nhits);
+}
+
+static inline void
+grn_output_result_set_n_hits(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj_format *format)
+{
+ if (format->nhits == -1) {
+ return;
+ }
+
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_result_set_n_hits_v1(ctx, outbuf, output_type, format);
+ } else {
+ grn_output_result_set_n_hits_v3(ctx, outbuf, output_type, format);
+ }
+}
+
+static inline void
+grn_output_table_column_info(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ const char *name,
+ const char *type)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_array_open(ctx, outbuf, output_type, "COLUMN", 2);
+ if (name) {
+ grn_output_cstr(ctx, outbuf, output_type, name);
+ } else {
+ grn_output_null(ctx, outbuf, output_type);
+ }
+ if (type) {
+ grn_output_cstr(ctx, outbuf, output_type, type);
+ } else {
+ grn_output_null(ctx, outbuf, output_type);
+ }
+ grn_output_array_close(ctx, outbuf, output_type);
+ } else {
+ grn_output_map_open(ctx, outbuf, output_type, "column", 2);
+ grn_output_cstr(ctx, outbuf, output_type, "name");
+ if (name) {
+ grn_output_cstr(ctx, outbuf, output_type, name);
+ } else {
+ grn_output_null(ctx, outbuf, output_type);
+ }
+ grn_output_cstr(ctx, outbuf, output_type, "type");
+ if (type) {
+ grn_output_cstr(ctx, outbuf, output_type, type);
+ } else {
+ grn_output_null(ctx, outbuf, output_type);
+ }
+ grn_output_map_close(ctx, outbuf, output_type);
+ }
+}
+
+static inline int
+count_n_elements_in_expression(grn_ctx *ctx, grn_obj *expression)
+{
+ int n_elements = 0;
+ grn_bool is_first_comma = GRN_TRUE;
+ grn_expr *expr = (grn_expr *)expression;
+ grn_expr_code *code;
+ grn_expr_code *code_end = expr->codes + expr->codes_curr;
+
+ for (code = expr->codes; code < code_end; code++) {
+ if (code->op == GRN_OP_COMMA) {
+ n_elements++;
+ if (is_first_comma) {
+ n_elements++;
+ is_first_comma = GRN_FALSE;
+ }
+ }
+ }
+
+ return n_elements;
+}
+
+static grn_bool
+is_score_accessor(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_accessor *a;
+
+ if (obj->header.type != GRN_ACCESSOR) {
+ return GRN_FALSE;
+ }
+
+ for (a = (grn_accessor *)obj; a->next; a = a->next) {
+ }
+ return a->action == GRN_ACCESSOR_GET_SCORE;
+}
+
+static inline void
+grn_output_table_column(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *column, grn_obj *buf)
+{
+ grn_id range_id = GRN_ID_NIL;
+
+ if (!column) {
+ grn_output_table_column_info(ctx, outbuf, output_type, NULL, NULL);
+ return;
+ }
+
+ GRN_BULK_REWIND(buf);
+ grn_column_name_(ctx, column, buf);
+ GRN_TEXT_PUTC(ctx, buf, '\0');
+
+ if (column->header.type == GRN_COLUMN_INDEX) {
+ range_id = GRN_DB_UINT32;
+ } else if (is_score_accessor(ctx, column)) {
+ if (grn_ctx_get_command_version(ctx) == GRN_COMMAND_VERSION_1) {
+ range_id = GRN_DB_INT32;
+ } else {
+ range_id = GRN_DB_FLOAT;
+ }
+ }
+ if (range_id == GRN_ID_NIL) {
+ range_id = grn_obj_get_range(ctx, column);
+ }
+ if (range_id == GRN_ID_NIL) {
+ grn_output_table_column_info(ctx,
+ outbuf,
+ output_type,
+ GRN_TEXT_VALUE(buf),
+ NULL);
+ } else {
+ grn_obj *range_obj;
+ char type_name[GRN_TABLE_MAX_KEY_SIZE];
+ int type_name_len;
+
+ range_obj = grn_ctx_at(ctx, range_id);
+ type_name_len = grn_obj_name(ctx,
+ range_obj,
+ type_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ type_name[type_name_len] = '\0';
+ grn_output_table_column_info(ctx,
+ outbuf,
+ output_type,
+ GRN_TEXT_VALUE(buf),
+ type_name);
+ }
+}
+
+static inline void
+grn_output_table_column_by_expression(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_expr_code *code,
+ grn_expr_code *code_end,
+ grn_obj *buf)
+{
+ if (code_end <= code) {
+ grn_output_table_column_info(ctx,
+ outbuf,
+ output_type,
+ NULL,
+ NULL);
+ return;
+ }
+
+ switch (code_end[-1].op) {
+ case GRN_OP_GET_MEMBER :
+ if ((code_end - code) == 3) {
+ GRN_BULK_REWIND(buf);
+ grn_column_name_(ctx, code[0].value, buf);
+ GRN_TEXT_PUTC(ctx, buf, '[');
+ grn_inspect(ctx, buf, code[1].value);
+ GRN_TEXT_PUTC(ctx, buf, ']');
+ GRN_TEXT_PUTC(ctx, buf, '\0');
+
+ grn_output_table_column_info(ctx,
+ outbuf,
+ output_type,
+ GRN_TEXT_VALUE(buf),
+ NULL);
+ } else {
+ grn_output_table_column(ctx, outbuf, output_type, code->value, buf);
+ }
+ break;
+ default :
+ grn_output_table_column(ctx, outbuf, output_type, code->value, buf);
+ break;
+ }
+}
+
+static inline void
+grn_output_table_columns_open(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ int n_columns)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_array_open(ctx, outbuf, output_type, "COLUMNS", n_columns);
+ } else {
+ grn_output_cstr(ctx, outbuf, output_type, "columns");
+ grn_output_array_open(ctx, outbuf, output_type, "columns", n_columns);
+ }
+}
+
+static inline void
+grn_output_table_columns_close(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_array_close(ctx, outbuf, output_type);
+ } else {
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+}
+
+static inline void
+grn_output_table_columns_by_expression(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table, grn_obj_format *format,
+ grn_obj *buf)
+{
+ int n_elements;
+ int previous_comma_offset = -1;
+ grn_bool is_first_comma = GRN_TRUE;
+ grn_bool have_comma = GRN_FALSE;
+ grn_expr *expr = (grn_expr *)format->expression;
+ grn_expr_code *code;
+ grn_expr_code *code_end = expr->codes + expr->codes_curr;
+
+ n_elements = count_n_elements_in_expression(ctx, format->expression);
+
+ grn_output_table_columns_open(ctx, outbuf, output_type, n_elements);
+
+ for (code = expr->codes; code < code_end; code++) {
+ int code_start_offset;
+
+ if (code->op != GRN_OP_COMMA) {
+ continue;
+ }
+
+ have_comma = GRN_TRUE;
+ if (is_first_comma) {
+ unsigned int n_used_codes;
+ int code_end_offset;
+
+ n_used_codes = grn_expr_code_n_used_codes(ctx, expr->codes, code - 1);
+ code_end_offset = code - expr->codes - n_used_codes;
+
+ grn_output_table_column_by_expression(ctx, outbuf, output_type,
+ expr->codes,
+ expr->codes + code_end_offset,
+ buf);
+ code_start_offset = code_end_offset;
+ is_first_comma = GRN_FALSE;
+ } else {
+ code_start_offset = previous_comma_offset + 1;
+ }
+
+ grn_output_table_column_by_expression(ctx, outbuf, output_type,
+ expr->codes + code_start_offset,
+ code,
+ buf);
+ previous_comma_offset = code - expr->codes;
+ }
+
+ if (!have_comma && expr->codes_curr > 0) {
+ grn_output_table_column_by_expression(ctx, outbuf, output_type,
+ expr->codes,
+ code_end,
+ buf);
+ }
+
+ grn_output_table_columns_close(ctx, outbuf, output_type);
+}
+
+static inline void
+grn_output_table_columns_by_columns(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table, grn_obj_format *format,
+ grn_obj *buf)
+{
+ int i;
+ int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+
+ grn_output_table_columns_open(ctx, outbuf, output_type, ncolumns);
+ for (i = 0; i < ncolumns; i++) {
+ grn_output_table_column(ctx, outbuf, output_type, columns[i], buf);
+ }
+ grn_output_table_columns_close(ctx, outbuf, output_type);
+}
+
+void
+grn_output_table_columns(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table, grn_obj_format *format)
+{
+ grn_obj buf;
+
+ GRN_TEXT_INIT(&buf, 0);
+ if (format->expression) {
+ grn_output_table_columns_by_expression(ctx, outbuf, output_type,
+ table, format, &buf);
+ } else {
+ grn_output_table_columns_by_columns(ctx, outbuf, output_type,
+ table, format, &buf);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static inline void
+grn_output_table_record_open(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ int n_columns)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_array_open(ctx, outbuf, output_type, "HIT", n_columns);
+ } else {
+ grn_output_array_open(ctx, outbuf, output_type, "record", n_columns);
+ }
+}
+
+static inline void
+grn_output_table_record_close(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_array_close(ctx, outbuf, output_type);
+ } else {
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+}
+
+static inline void
+grn_output_table_record_by_column(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *column,
+ grn_id id)
+{
+ grn_text_atoj(ctx, outbuf, output_type, column, id);
+}
+
+static inline void
+grn_output_table_record_by_expression(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *expression,
+ grn_obj *record)
+{
+ grn_expr *expr = (grn_expr *)expression;
+
+ if (expr->codes_curr == 1 && expr->codes[0].op == GRN_OP_GET_VALUE) {
+ grn_obj *column = expr->codes[0].value;
+ grn_output_table_record_by_column(ctx,
+ outbuf,
+ output_type,
+ column,
+ GRN_RECORD_VALUE(record));
+ } else {
+ grn_obj *result;
+ result = grn_expr_exec(ctx, expression, 0);
+ if (result) {
+ grn_output_obj(ctx, outbuf, output_type, result, NULL);
+ } else {
+ grn_output_cstr(ctx, outbuf, output_type, ctx->errbuf);
+ }
+ }
+}
+
+static inline void
+grn_output_table_records_by_expression(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_table_cursor *tc,
+ grn_obj_format *format)
+{
+ int n_elements = 0;
+ grn_id id;
+ grn_obj *record;
+ grn_expr *expr = (grn_expr *)format->expression;
+ grn_expr_code *code;
+ grn_expr_code *code_end = expr->codes + expr->codes_curr;
+
+ n_elements = count_n_elements_in_expression(ctx, format->expression);
+ record = grn_expr_get_var_by_offset(ctx, format->expression, 0);
+ while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ int previous_comma_offset = -1;
+ grn_bool is_first_comma = GRN_TRUE;
+ grn_bool have_comma = GRN_FALSE;
+ GRN_RECORD_SET(ctx, record, id);
+ grn_output_table_record_open(ctx, outbuf, output_type, n_elements);
+ for (code = expr->codes; code < code_end; code++) {
+ if (code->op == GRN_OP_COMMA) {
+ int code_start_offset = previous_comma_offset + 1;
+ int code_end_offset;
+ int original_codes_curr = expr->codes_curr;
+
+ have_comma = GRN_TRUE;
+ if (is_first_comma) {
+ int second_code_offset;
+ unsigned int second_code_n_used_codes;
+ second_code_offset = code - expr->codes - 1;
+ second_code_n_used_codes =
+ grn_expr_code_n_used_codes(ctx,
+ expr->codes,
+ expr->codes + second_code_offset);
+ expr->codes_curr = second_code_offset - second_code_n_used_codes + 1;
+ grn_output_table_record_by_expression(ctx,
+ outbuf,
+ output_type,
+ format->expression,
+ record);
+ code_start_offset = expr->codes_curr;
+ is_first_comma = GRN_FALSE;
+ }
+ code_end_offset = code - expr->codes - code_start_offset;
+ expr->codes += code_start_offset;
+ expr->codes_curr = code_end_offset;
+ grn_output_table_record_by_expression(ctx,
+ outbuf,
+ output_type,
+ format->expression,
+ record);
+ expr->codes -= code_start_offset;
+ expr->codes_curr = original_codes_curr;
+ previous_comma_offset = code - expr->codes;
+ }
+ }
+
+ if (!have_comma && expr->codes_curr > 0) {
+ grn_output_table_record_by_expression(ctx,
+ outbuf,
+ output_type,
+ format->expression,
+ record);
+ }
+
+ grn_output_table_record_close(ctx, outbuf, output_type);
+ }
+}
+
+static inline void
+grn_output_table_records_by_columns(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_table_cursor *tc,
+ grn_obj_format *format)
+{
+ int i;
+ grn_id id;
+ int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+ while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ grn_output_table_record_open(ctx, outbuf, output_type, ncolumns);
+ for (i = 0; i < ncolumns; i++) {
+ grn_output_table_record_by_column(ctx,
+ outbuf,
+ output_type,
+ columns[i],
+ id);
+ }
+ grn_output_table_record_close(ctx, outbuf, output_type);
+ }
+}
+
+static inline void
+grn_output_table_records_open(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ int n_records)
+{
+ if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
+ grn_output_cstr(ctx, outbuf, output_type, "records");
+ grn_output_array_open(ctx, outbuf, output_type, "records", n_records);
+ }
+}
+
+static inline void
+grn_output_table_records_close(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type)
+{
+ if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
+ grn_output_array_close(ctx, outbuf, output_type);
+ }
+}
+
+void
+grn_output_table_records(grn_ctx *ctx, grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table, grn_obj_format *format)
+{
+ grn_table_cursor *tc;
+
+ grn_output_table_records_open(ctx, outbuf, output_type, format->limit);
+ tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
+ format->offset, format->limit,
+ GRN_CURSOR_ASCENDING);
+ if (tc) {
+ if (format->expression) {
+ grn_output_table_records_by_expression(ctx, outbuf, output_type,
+ tc, format);
+ } else {
+ grn_output_table_records_by_columns(ctx, outbuf, output_type,
+ tc, format);
+ }
+ grn_table_cursor_close(ctx, tc);
+ } else {
+ ERRCLR(ctx);
+ }
+ grn_output_table_records_close(ctx, outbuf, output_type);
+}
+
+static void
+grn_output_result_set_open_v1(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table,
+ grn_obj_format *format,
+ uint32_t n_additional_elements)
+{
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ if (format) {
+ int resultset_size = 1;
+ /* resultset: [NHITS, (COLUMNS), (HITS)] */
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ resultset_size++;
+ }
+ resultset_size += format->limit;
+ resultset_size += n_additional_elements;
+ grn_output_array_open(ctx, outbuf, output_type, "RESULTSET", resultset_size);
+ grn_output_result_set_n_hits(ctx, outbuf, output_type, format);
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ grn_output_table_columns(ctx, outbuf, output_type, table, format);
+ }
+ grn_output_table_records(ctx, outbuf, output_type, table, format);
+ } else {
+ int i;
+ grn_obj *column = grn_obj_column(ctx, table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ grn_table_cursor *tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_ASCENDING);
+ grn_output_array_open(ctx, outbuf, output_type, "HIT", -1);
+ if (tc) {
+ grn_id id;
+ for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
+ GRN_BULK_REWIND(&buf);
+ grn_obj_get_value(ctx, column, id, &buf);
+ grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ grn_obj_unlink(ctx, column);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static void
+grn_output_result_set_close_v1(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *table,
+ grn_obj_format *format)
+{
+ grn_output_array_close(ctx, outbuf, output_type);
+}
+
+static void
+grn_output_result_set_open_v3(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format,
+ uint32_t n_additional_elements)
+{
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ if (format) {
+ int n_elements = 2;
+ /* result_set: {"n_hits": N, ("columns": COLUMNS,) "records": records} */
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ n_elements++;
+ }
+ n_elements += n_additional_elements;
+ grn_output_map_open(ctx, outbuf, output_type, "result_set", n_elements);
+ grn_output_result_set_n_hits(ctx, outbuf, output_type, format);
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ grn_output_table_columns(ctx, outbuf, output_type, result_set, format);
+ }
+ grn_output_table_records(ctx, outbuf, output_type, result_set, format);
+ } else {
+ grn_obj *column;
+ int n_records;
+ int n_elements = 1;
+
+ column = grn_obj_column(ctx,
+ result_set,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ n_elements += n_additional_elements;
+ grn_output_map_open(ctx, outbuf, output_type, "result_set", n_elements);
+ n_records = grn_table_size(ctx, result_set);
+ grn_output_cstr(ctx, outbuf, output_type, "keys");
+ grn_output_array_open(ctx, outbuf, output_type, "keys", n_records);
+ GRN_TABLE_EACH_BEGIN(ctx, result_set, cursor, id) {
+ GRN_BULK_REWIND(&buf);
+ grn_obj_get_value(ctx, column, id, &buf);
+ grn_text_esc(ctx, outbuf, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_output_array_close(ctx, outbuf, output_type);
+ grn_obj_unlink(ctx, column);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static void
+grn_output_result_set_close_v3(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format)
+{
+ grn_output_map_close(ctx, outbuf, output_type);
+}
+
+void
+grn_output_result_set_open(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format,
+ uint32_t n_additional_elements)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_result_set_open_v1(ctx,
+ outbuf,
+ output_type,
+ result_set,
+ format,
+ n_additional_elements);
+ } else {
+ grn_output_result_set_open_v3(ctx,
+ outbuf,
+ output_type,
+ result_set,
+ format,
+ n_additional_elements);
+ }
+}
+
+void
+grn_output_result_set_close(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format)
+{
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ grn_output_result_set_close_v1(ctx, outbuf, output_type, result_set, format);
+ } else {
+ grn_output_result_set_close_v3(ctx, outbuf, output_type, result_set, format);
+ }
+}
+
+void
+grn_output_result_set(grn_ctx *ctx,
+ grn_obj *outbuf,
+ grn_content_type output_type,
+ grn_obj *result_set,
+ grn_obj_format *format)
+{
+ uint32_t n_additional_elements = 0;
+
+ grn_output_result_set_open(ctx,
+ outbuf,
+ output_type,
+ result_set,
+ format,
+ n_additional_elements);
+ grn_output_result_set_close(ctx, outbuf, output_type, result_set, format);
+}
+
+void
+grn_output_obj(grn_ctx *ctx, grn_obj *outbuf, grn_content_type output_type,
+ grn_obj *obj, grn_obj_format *format)
+{
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ switch (obj->header.type) {
+ case GRN_VOID :
+ grn_output_void(ctx, outbuf, output_type, obj, format);
+ break;
+ case GRN_BULK :
+ grn_output_bulk(ctx, outbuf, output_type, obj, format);
+ break;
+ case GRN_UVECTOR :
+ grn_output_uvector(ctx, outbuf, output_type, obj, format);
+ break;
+ case GRN_VECTOR :
+ grn_output_vector(ctx, outbuf, output_type, obj, format);
+ break;
+ case GRN_PVECTOR :
+ grn_output_pvector(ctx, outbuf, output_type, obj, format);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ /* Deprecated. Use grn_output_result_set() directly. */
+ grn_output_result_set(ctx, outbuf, output_type, obj, format);
+ break;
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+typedef enum {
+ XML_START,
+ XML_START_ELEMENT,
+ XML_END_ELEMENT,
+ XML_TEXT
+} xml_status;
+
+typedef enum {
+ XML_PLACE_NONE,
+ XML_PLACE_COLUMN,
+ XML_PLACE_HIT
+} xml_place;
+
+static char *
+transform_xml_next_column(grn_obj *columns, int n)
+{
+ char *column = GRN_TEXT_VALUE(columns);
+ while (n--) {
+ while (*column) {
+ column++;
+ }
+ column++;
+ }
+ return column;
+}
+
+static void
+transform_xml(grn_ctx *ctx, grn_obj *output, grn_obj *transformed)
+{
+ char *s, *e;
+ xml_status status = XML_START;
+ xml_place place = XML_PLACE_NONE;
+ grn_obj buf, name, columns, *expr;
+ unsigned int len;
+ int offset = 0, limit = 0, record_n = 0;
+ int column_n = 0, column_text_n = 0, result_set_n = -1;
+ grn_bool in_vector = GRN_FALSE;
+ unsigned int vector_element_n = 0;
+ grn_bool in_weight_vector = GRN_FALSE;
+ unsigned int weight_vector_item_n = 0;
+
+ s = GRN_TEXT_VALUE(output);
+ e = GRN_BULK_CURR(output);
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_INIT(&name, 0);
+ GRN_TEXT_INIT(&columns, 0);
+
+ expr = ctx->impl->curr_expr;
+
+#define EQUAL_NAME_P(_name) \
+ (GRN_TEXT_LEN(&name) == strlen(_name) && \
+ !memcmp(GRN_TEXT_VALUE(&name), _name, strlen(_name)))
+
+ while (s < e) {
+ switch (*s) {
+ case '<' :
+ s++;
+ switch (*s) {
+ case '/' :
+ status = XML_END_ELEMENT;
+ s++;
+ break;
+ default :
+ status = XML_START_ELEMENT;
+ break;
+ }
+ GRN_BULK_REWIND(&name);
+ break;
+ case '>' :
+ switch (status) {
+ case XML_START_ELEMENT :
+ if (EQUAL_NAME_P("COLUMN")) {
+ place = XML_PLACE_COLUMN;
+ column_text_n = 0;
+ } else if (EQUAL_NAME_P("HIT")) {
+ place = XML_PLACE_HIT;
+ column_n = 0;
+ if (result_set_n == 0) {
+ GRN_TEXT_PUTS(ctx, transformed, "<HIT NO=\"");
+ grn_text_itoa(ctx, transformed, record_n++);
+ GRN_TEXT_PUTS(ctx, transformed, "\">\n");
+ } else {
+ GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONELEMENT ");
+ }
+ } else if (EQUAL_NAME_P("RESULTSET")) {
+ GRN_BULK_REWIND(&columns);
+ result_set_n++;
+ if (result_set_n == 0) {
+ } else {
+ GRN_TEXT_PUTS(ctx, transformed, "<NAVIGATIONENTRY>\n");
+ }
+ } else if (EQUAL_NAME_P("VECTOR")) {
+ char *c = transform_xml_next_column(&columns, column_n++);
+ in_vector = GRN_TRUE;
+ vector_element_n = 0;
+ GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
+ GRN_TEXT_PUTS(ctx, transformed, c);
+ GRN_TEXT_PUTS(ctx, transformed, "\">");
+ } else if (EQUAL_NAME_P("WEIGHT_VECTOR")) {
+ char *c = transform_xml_next_column(&columns, column_n++);
+ in_weight_vector = GRN_TRUE;
+ weight_vector_item_n = 0;
+ GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
+ GRN_TEXT_PUTS(ctx, transformed, c);
+ GRN_TEXT_PUTS(ctx, transformed, "\">");
+ }
+ break;
+ case XML_END_ELEMENT :
+ if (EQUAL_NAME_P("HIT")) {
+ place = XML_PLACE_NONE;
+ if (result_set_n == 0) {
+ GRN_TEXT_PUTS(ctx, transformed, "</HIT>\n");
+ } else {
+ GRN_TEXT_PUTS(ctx, transformed, "/>\n");
+ }
+ } else if (EQUAL_NAME_P("RESULTSET")) {
+ place = XML_PLACE_NONE;
+ if (result_set_n == 0) {
+ GRN_TEXT_PUTS(ctx, transformed, "</RESULTSET>\n");
+ } else {
+ GRN_TEXT_PUTS(ctx, transformed,
+ "</NAVIGATIONELEMENTS>\n"
+ "</NAVIGATIONENTRY>\n");
+ }
+ } else if (EQUAL_NAME_P("RESULT")) {
+ GRN_TEXT_PUTS(ctx, transformed,
+ "</RESULTPAGE>\n"
+ "</SEGMENT>\n"
+ "</SEGMENTS>\n");
+ } else if (EQUAL_NAME_P("VECTOR")) {
+ in_vector = GRN_FALSE;
+ GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
+ } else if (EQUAL_NAME_P("WEIGHT_VECTOR")) {
+ in_weight_vector = GRN_FALSE;
+ GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
+ } else {
+ switch (place) {
+ case XML_PLACE_HIT :
+ if (result_set_n == 0) {
+ if (in_vector) {
+ if (vector_element_n > 0) {
+ GRN_TEXT_PUTS(ctx, transformed, ", ");
+ }
+ GRN_TEXT_PUT(ctx, transformed,
+ GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ vector_element_n++;
+ } else if (in_weight_vector) {
+ grn_bool is_key;
+ is_key = ((weight_vector_item_n % 2) == 0);
+ if (is_key) {
+ unsigned int weight_vector_key_n;
+ weight_vector_key_n = weight_vector_item_n / 2;
+ if (weight_vector_key_n > 0) {
+ GRN_TEXT_PUTS(ctx, transformed, ", ");
+ }
+ } else {
+ GRN_TEXT_PUTS(ctx, transformed, ":");
+ }
+ GRN_TEXT_PUT(ctx, transformed,
+ GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ weight_vector_item_n++;
+ } else {
+ char *c = transform_xml_next_column(&columns, column_n++);
+ GRN_TEXT_PUTS(ctx, transformed, "<FIELD NAME=\"");
+ GRN_TEXT_PUTS(ctx, transformed, c);
+ GRN_TEXT_PUTS(ctx, transformed, "\">");
+ GRN_TEXT_PUT(ctx, transformed,
+ GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ GRN_TEXT_PUTS(ctx, transformed, "</FIELD>\n");
+ }
+ } else {
+ char *c = transform_xml_next_column(&columns, column_n++);
+ GRN_TEXT_PUTS(ctx, transformed, c);
+ GRN_TEXT_PUTS(ctx, transformed, "=\"");
+ GRN_TEXT_PUT(ctx, transformed,
+ GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ GRN_TEXT_PUTS(ctx, transformed, "\" ");
+ }
+ break;
+ default :
+ if (EQUAL_NAME_P("NHITS")) {
+ if (result_set_n == 0) {
+ uint32_t nhits;
+ grn_obj *offset_value, *limit_value;
+
+ nhits = grn_atoui(GRN_TEXT_VALUE(&buf), GRN_BULK_CURR(&buf),
+ NULL);
+ offset_value = grn_expr_get_var(ctx, expr,
+ "offset", strlen("offset"));
+ limit_value = grn_expr_get_var(ctx, expr,
+ "limit", strlen("limit"));
+ if (GRN_TEXT_LEN(offset_value)) {
+ offset = grn_atoi(GRN_TEXT_VALUE(offset_value),
+ GRN_BULK_CURR(offset_value),
+ NULL);
+ } else {
+ offset = 0;
+ }
+ if (GRN_TEXT_LEN(limit_value)) {
+ limit = grn_atoi(GRN_TEXT_VALUE(limit_value),
+ GRN_BULK_CURR(limit_value),
+ NULL);
+ } else {
+#define DEFAULT_LIMIT 10
+ limit = DEFAULT_LIMIT;
+#undef DEFAULT_LIMIT
+ }
+ grn_normalize_offset_and_limit(ctx, nhits, &offset, &limit);
+ record_n = offset + 1;
+ GRN_TEXT_PUTS(ctx, transformed,
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<SEGMENTS>\n"
+ "<SEGMENT>\n"
+ "<RESULTPAGE>\n"
+ "<RESULTSET OFFSET=\"");
+ grn_text_lltoa(ctx, transformed, offset);
+ GRN_TEXT_PUTS(ctx, transformed, "\" LIMIT=\"");
+ grn_text_lltoa(ctx, transformed, limit);
+ GRN_TEXT_PUTS(ctx, transformed, "\" NHITS=\"");
+ grn_text_lltoa(ctx, transformed, nhits);
+ GRN_TEXT_PUTS(ctx, transformed, "\">\n");
+ } else {
+ GRN_TEXT_PUTS(ctx, transformed,
+ "<NAVIGATIONELEMENTS COUNT=\"");
+ GRN_TEXT_PUT(ctx, transformed,
+ GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ GRN_TEXT_PUTS(ctx, transformed,
+ "\">\n");
+ }
+ } else if (EQUAL_NAME_P("TEXT")) {
+ switch (place) {
+ case XML_PLACE_COLUMN :
+ if (column_text_n == 0) {
+ GRN_TEXT_PUT(ctx, &columns,
+ GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ GRN_TEXT_PUTC(ctx, &columns, '\0');
+ }
+ column_text_n++;
+ break;
+ default :
+ break;
+ }
+ }
+ }
+ }
+ default :
+ break;
+ }
+ s++;
+ GRN_BULK_REWIND(&buf);
+ status = XML_TEXT;
+ break;
+ default :
+ len = grn_charlen(ctx, s, e);
+ switch (status) {
+ case XML_START_ELEMENT :
+ case XML_END_ELEMENT :
+ GRN_TEXT_PUT(ctx, &name, s, len);
+ break;
+ default :
+ GRN_TEXT_PUT(ctx, &buf, s, len);
+ break;
+ }
+ s += len;
+ break;
+ }
+ }
+#undef EQUAL_NAME_P
+
+ GRN_OBJ_FIN(ctx, &buf);
+ GRN_OBJ_FIN(ctx, &name);
+ GRN_OBJ_FIN(ctx, &columns);
+}
+
+#ifdef GRN_WITH_MESSAGE_PACK
+typedef struct {
+ grn_ctx *ctx;
+ grn_obj *buffer;
+} msgpack_writer_ctx;
+
+static inline int
+msgpack_buffer_writer(void* data, const char* buf, msgpack_size_t len)
+{
+ msgpack_writer_ctx *writer_ctx = (msgpack_writer_ctx *)data;
+ return grn_bulk_write(writer_ctx->ctx, writer_ctx->buffer, buf, len);
+}
+#endif
+
+#define JSON_CALLBACK_PARAM "callback"
+
+static void
+grn_output_envelope_json_v1(grn_ctx *ctx,
+ grn_rc rc,
+ grn_obj *head,
+ grn_obj *body,
+ grn_obj *foot,
+ double started,
+ double elapsed,
+ const char *file,
+ int line)
+{
+ size_t indent_level = 0;
+
+ json_array_open(ctx, head, &indent_level);
+ {
+ json_array_open(ctx, head, &indent_level);
+ {
+ grn_text_itoa(ctx, head, rc);
+
+ json_element_end(ctx, head, indent_level);
+ grn_text_ftoa(ctx, head, started);
+
+ json_element_end(ctx, head, indent_level);
+ grn_text_ftoa(ctx, head, elapsed);
+
+ if (rc != GRN_SUCCESS) {
+ json_element_end(ctx, head, indent_level);
+ grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
+
+ if (ctx->errfunc && ctx->errfile) {
+ grn_obj *command;
+
+ json_element_end(ctx, head, indent_level);
+ json_array_open(ctx, head, &indent_level);
+ {
+ json_array_open(ctx, head, &indent_level);
+ {
+ grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
+
+ json_element_end(ctx, head, indent_level);
+ grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
+
+ json_element_end(ctx, head, indent_level);
+ grn_text_itoa(ctx, head, ctx->errline);
+ }
+ json_array_close(ctx, head, &indent_level);
+
+ if (file && (command = GRN_CTX_USER_DATA(ctx)->ptr)) {
+ json_element_end(ctx, head, indent_level);
+ json_array_open(ctx, head, &indent_level);
+ {
+ grn_text_esc(ctx, head, file, strlen(file));
+
+ json_element_end(ctx, head, indent_level);
+ grn_text_itoa(ctx, head, line);
+
+ json_element_end(ctx, head, indent_level);
+ grn_text_esc(ctx, head,
+ GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
+ }
+ json_array_close(ctx, head, &indent_level);
+ }
+ }
+ json_array_close(ctx, head, &indent_level);
+ }
+ }
+ }
+ json_array_close(ctx, head, &indent_level);
+ }
+
+ if (GRN_TEXT_LEN(body)) {
+ json_element_end(ctx, head, indent_level);
+ }
+
+ json_array_close(ctx, foot, &indent_level);
+}
+
+static void
+grn_output_envelope_json(grn_ctx *ctx,
+ grn_rc rc,
+ grn_obj *head,
+ grn_obj *body,
+ grn_obj *foot,
+ double started,
+ double elapsed,
+ const char *file,
+ int line)
+{
+ size_t indent_level = 0;
+
+ json_map_open(ctx, head, &indent_level);
+ {
+ json_key(ctx, head, "header");
+ json_map_open(ctx, head, &indent_level);
+ {
+ json_key(ctx, head, "return_code");
+ grn_text_itoa(ctx, head, rc);
+
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "start_time");
+ grn_text_ftoa(ctx, head, started);
+
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "elapsed_time");
+ grn_text_ftoa(ctx, head, elapsed);
+
+ if (rc != GRN_SUCCESS) {
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "error");
+ json_map_open(ctx, head, &indent_level);
+ {
+ json_key(ctx, head, "message");
+ grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
+
+ if (ctx->errfunc && ctx->errfile) {
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "function");
+ grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
+
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "file");
+ grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
+
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "line");
+ grn_text_itoa(ctx, head, ctx->errline);
+ }
+
+ if (file) {
+ grn_obj *command;
+
+ command = GRN_CTX_USER_DATA(ctx)->ptr;
+ if (command) {
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "input");
+ json_map_open(ctx, head, &indent_level);
+ {
+ json_key(ctx, head, "file");
+ grn_text_esc(ctx, head, file, strlen(file));
+
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "line");
+ grn_text_itoa(ctx, head, line);
+
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "command");
+ grn_text_esc(ctx, head,
+ GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
+ }
+ json_map_close(ctx, head, &indent_level);
+ }
+ }
+ }
+ json_map_close(ctx, head, &indent_level);
+ }
+ }
+ json_map_close(ctx, head, &indent_level);
+
+ if (GRN_TEXT_LEN(body)) {
+ json_value_end(ctx, head, indent_level);
+ json_key(ctx, head, "body");
+ }
+
+ json_map_close(ctx, foot, &indent_level);
+ }
+}
+
+#ifdef GRN_WITH_MESSAGE_PACK
+static void
+msgpack_pack_cstr(msgpack_packer *packer,
+ const char *string)
+{
+ size_t size;
+
+ size = strlen(string);
+ msgpack_pack_str(packer, size);
+ msgpack_pack_str_body(packer, string, size);
+}
+
+static void
+grn_output_envelope_msgpack_v1(grn_ctx *ctx,
+ grn_rc rc,
+ grn_obj *head,
+ grn_obj *body,
+ grn_obj *foot,
+ double started,
+ double elapsed,
+ const char *file,
+ int line)
+{
+ msgpack_writer_ctx head_writer_ctx;
+ msgpack_packer header_packer;
+ int header_size;
+
+ head_writer_ctx.ctx = ctx;
+ head_writer_ctx.buffer = head;
+ msgpack_packer_init(&header_packer, &head_writer_ctx, msgpack_buffer_writer);
+
+ /* [HEADER, (BODY)] */
+ if (GRN_TEXT_LEN(body) > 0) {
+ msgpack_pack_array(&header_packer, 2);
+ } else {
+ msgpack_pack_array(&header_packer, 1);
+ }
+
+ /* HEADER := [rc, started, elapsed, (error, (ERROR DETAIL))] */
+ header_size = 3;
+ if (rc != GRN_SUCCESS) {
+ header_size++;
+ if (ctx->errfunc && ctx->errfile) {
+ header_size++;
+ }
+ }
+ msgpack_pack_array(&header_packer, header_size);
+ msgpack_pack_int(&header_packer, rc);
+
+ msgpack_pack_double(&header_packer, started);
+ msgpack_pack_double(&header_packer, elapsed);
+
+ if (rc != GRN_SUCCESS) {
+ msgpack_pack_str(&header_packer, strlen(ctx->errbuf));
+ msgpack_pack_str_body(&header_packer, ctx->errbuf, strlen(ctx->errbuf));
+ if (ctx->errfunc && ctx->errfile) {
+ grn_obj *command = GRN_CTX_USER_DATA(ctx)->ptr;
+ int error_detail_size;
+
+ /* ERROR DETAIL : = [[errfunc, errfile, errline,
+ (file, line, command)]] */
+ /* TODO: output backtrace */
+ msgpack_pack_array(&header_packer, 1);
+ error_detail_size = 3;
+ if (command) {
+ error_detail_size += 3;
+ }
+ msgpack_pack_array(&header_packer, error_detail_size);
+
+ msgpack_pack_str(&header_packer, strlen(ctx->errfunc));
+ msgpack_pack_str_body(&header_packer, ctx->errfunc, strlen(ctx->errfunc));
+
+ msgpack_pack_str(&header_packer, strlen(ctx->errfile));
+ msgpack_pack_str_body(&header_packer, ctx->errfile, strlen(ctx->errfile));
+
+ msgpack_pack_int(&header_packer, ctx->errline);
+
+ if (command) {
+ if (file) {
+ msgpack_pack_str(&header_packer, strlen(file));
+ msgpack_pack_str_body(&header_packer, file, strlen(file));
+ } else {
+ msgpack_pack_str(&header_packer, 7);
+ msgpack_pack_str_body(&header_packer, "(stdin)", 7);
+ }
+
+ msgpack_pack_int(&header_packer, line);
+
+ msgpack_pack_str(&header_packer, GRN_TEXT_LEN(command));
+ msgpack_pack_str_body(&header_packer, GRN_TEXT_VALUE(command), GRN_TEXT_LEN(command));
+ }
+ }
+ }
+}
+
+static void
+grn_output_envelope_msgpack(grn_ctx *ctx,
+ grn_rc rc,
+ grn_obj *head,
+ grn_obj *body,
+ grn_obj *foot,
+ double started,
+ double elapsed,
+ const char *file,
+ int line)
+{
+ msgpack_writer_ctx writer_ctx;
+ msgpack_packer packer;
+ int n_elements;
+
+ writer_ctx.ctx = ctx;
+ writer_ctx.buffer = head;
+ msgpack_packer_init(&packer, &writer_ctx, msgpack_buffer_writer);
+
+ /*
+ * ENVELOPE := {
+ * "header": HEADER,
+ * "body": BODY (optional)
+ * }
+ */
+ if (GRN_TEXT_LEN(body) > 0) {
+ n_elements = 2;
+ } else {
+ n_elements = 1;
+ }
+
+ msgpack_pack_map(&packer, n_elements);
+ {
+ int n_header_elements = 3;
+
+ /*
+ * HEADER := {
+ * "return_code": rc,
+ * "start_time": started,
+ * "elapsed_time": elapsed,
+ " "error": { (optional)
+ * "message": errbuf,
+ * "function": errfunc,
+ * "file": errfile,
+ * "line": errline,
+ * "input": { (optional)
+ * "file": input_file,
+ * "line": line,
+ * "command": command
+ * }
+ * }
+ * }
+ */
+
+ if (rc != GRN_SUCCESS) {
+ n_header_elements++;
+ }
+
+ msgpack_pack_cstr(&packer, "header");
+ msgpack_pack_map(&packer, n_header_elements);
+ {
+ msgpack_pack_cstr(&packer, "return_code");
+ msgpack_pack_int(&packer, rc);
+
+ msgpack_pack_cstr(&packer, "start_time");
+ msgpack_pack_double(&packer, started);
+
+ msgpack_pack_cstr(&packer, "elapsed_time");
+ msgpack_pack_double(&packer, elapsed);
+
+ if (rc != GRN_SUCCESS) {
+ int n_error_elements = 1;
+ grn_obj *command;
+
+ if (ctx->errfunc) {
+ n_error_elements++;
+ }
+ if (ctx->errfile) {
+ n_error_elements += 2;
+ }
+
+ command = GRN_CTX_USER_DATA(ctx)->ptr;
+ if (file || command) {
+ n_error_elements++;
+ }
+
+ msgpack_pack_cstr(&packer, "error");
+ msgpack_pack_map(&packer, n_error_elements);
+ {
+ msgpack_pack_cstr(&packer, "message");
+ msgpack_pack_cstr(&packer, ctx->errbuf);
+
+ if (ctx->errfunc) {
+ msgpack_pack_cstr(&packer, "function");
+ msgpack_pack_cstr(&packer, ctx->errfunc);
+ }
+
+ if (ctx->errfile) {
+ msgpack_pack_cstr(&packer, "file");
+ msgpack_pack_cstr(&packer, ctx->errfile);
+
+ msgpack_pack_cstr(&packer, "line");
+ msgpack_pack_int(&packer, ctx->errline);
+ }
+
+ if (file || command) {
+ int n_input_elements = 0;
+
+ if (file) {
+ n_input_elements += 2;
+ }
+ if (command) {
+ n_input_elements++;
+ }
+
+ msgpack_pack_cstr(&packer, "input");
+ msgpack_pack_map(&packer, n_input_elements);
+
+ if (file) {
+ msgpack_pack_cstr(&packer, "file");
+ msgpack_pack_cstr(&packer, file);
+
+ msgpack_pack_cstr(&packer, "line");
+ msgpack_pack_int(&packer, line);
+ }
+
+ if (command) {
+ msgpack_pack_cstr(&packer, "command");
+ msgpack_pack_str(&packer, GRN_TEXT_LEN(command));
+ msgpack_pack_str_body(&packer,
+ GRN_TEXT_VALUE(command),
+ GRN_TEXT_LEN(command));
+ }
+ }
+ }
+ }
+ }
+
+ if (GRN_TEXT_LEN(body) > 0) {
+ msgpack_pack_cstr(&packer, "body");
+ }
+ }
+}
+#endif /* GRN_WITH_MESSAGE_PACK */
+
+void
+grn_output_envelope(grn_ctx *ctx,
+ grn_rc rc,
+ grn_obj *head,
+ grn_obj *body,
+ grn_obj *foot,
+ const char *file,
+ int line)
+{
+ double started, finished, elapsed;
+
+ grn_timeval tv_now;
+ grn_timeval_now(ctx, &tv_now);
+ started = ctx->impl->tv.tv_sec;
+ started += ctx->impl->tv.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
+ finished = tv_now.tv_sec;
+ finished += tv_now.tv_nsec / GRN_TIME_NSEC_PER_SEC_F;
+ elapsed = finished - started;
+
+ switch (ctx->impl->output.type) {
+ case GRN_CONTENT_JSON:
+ {
+ grn_obj *expr;
+ grn_obj *jsonp_func = NULL;
+
+ expr = ctx->impl->curr_expr;
+ if (expr) {
+ jsonp_func = grn_expr_get_var(ctx, expr, JSON_CALLBACK_PARAM,
+ strlen(JSON_CALLBACK_PARAM));
+ }
+ if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
+ GRN_TEXT_PUT(ctx, head,
+ GRN_TEXT_VALUE(jsonp_func), GRN_TEXT_LEN(jsonp_func));
+ GRN_TEXT_PUTC(ctx, head, '(');
+ }
+
+ if (grn_ctx_get_command_version(ctx) <= GRN_COMMAND_VERSION_2) {
+ grn_output_envelope_json_v1(ctx, rc,
+ head, body, foot,
+ started, elapsed,
+ file, line);
+ } else {
+ grn_output_envelope_json(ctx, rc,
+ head, body, foot,
+ started, elapsed,
+ file, line);
+ }
+
+ if (jsonp_func && GRN_TEXT_LEN(jsonp_func)) {
+ GRN_TEXT_PUTS(ctx, foot, ");");
+ }
+ }
+ break;
+ case GRN_CONTENT_TSV:
+ grn_text_itoa(ctx, head, rc);
+ GRN_TEXT_PUTC(ctx, head, '\t');
+ grn_text_ftoa(ctx, head, started);
+ GRN_TEXT_PUTC(ctx, head, '\t');
+ grn_text_ftoa(ctx, head, elapsed);
+ if (rc != GRN_SUCCESS) {
+ GRN_TEXT_PUTC(ctx, head, '\t');
+ grn_text_esc(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
+ if (ctx->errfunc && ctx->errfile) {
+ /* TODO: output backtrace */
+ GRN_TEXT_PUTC(ctx, head, '\t');
+ grn_text_esc(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
+ GRN_TEXT_PUTC(ctx, head, '\t');
+ grn_text_esc(ctx, head, ctx->errfile, strlen(ctx->errfile));
+ GRN_TEXT_PUTC(ctx, head, '\t');
+ grn_text_itoa(ctx, head, ctx->errline);
+ }
+ }
+ GRN_TEXT_PUTS(ctx, head, "\n");
+ GRN_TEXT_PUTS(ctx, foot, "\nEND");
+ break;
+ case GRN_CONTENT_XML:
+ {
+ char buf[GRN_TABLE_MAX_KEY_SIZE];
+ int is_select = 0;
+ if (!rc && ctx->impl->curr_expr) {
+ int len = grn_obj_name(ctx, ctx->impl->curr_expr,
+ buf, GRN_TABLE_MAX_KEY_SIZE);
+ buf[len] = '\0';
+ is_select = strcmp(buf, "select") == 0;
+ }
+ if (is_select) {
+ grn_obj transformed;
+ GRN_TEXT_INIT(&transformed, 0);
+ transform_xml(ctx, body, &transformed);
+ GRN_TEXT_SET(ctx, body,
+ GRN_TEXT_VALUE(&transformed), GRN_TEXT_LEN(&transformed));
+ GRN_OBJ_FIN(ctx, &transformed);
+ } else {
+ GRN_TEXT_PUTS(ctx, head, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RESULT CODE=\"");
+ grn_text_itoa(ctx, head, rc);
+ GRN_TEXT_PUTS(ctx, head, "\" UP=\"");
+ grn_text_ftoa(ctx, head, started);
+ GRN_TEXT_PUTS(ctx, head, "\" ELAPSED=\"");
+ grn_text_ftoa(ctx, head, elapsed);
+ GRN_TEXT_PUTS(ctx, head, "\">\n");
+ if (rc != GRN_SUCCESS) {
+ GRN_TEXT_PUTS(ctx, head, "<ERROR>");
+ grn_text_escape_xml(ctx, head, ctx->errbuf, strlen(ctx->errbuf));
+ if (ctx->errfunc && ctx->errfile) {
+ /* TODO: output backtrace */
+ GRN_TEXT_PUTS(ctx, head, "<INFO FUNC=\"");
+ grn_text_escape_xml(ctx, head, ctx->errfunc, strlen(ctx->errfunc));
+ GRN_TEXT_PUTS(ctx, head, "\" FILE=\"");
+ grn_text_escape_xml(ctx, head, ctx->errfile, strlen(ctx->errfile));
+ GRN_TEXT_PUTS(ctx, head, "\" LINE=\"");
+ grn_text_itoa(ctx, head, ctx->errline);
+ GRN_TEXT_PUTS(ctx, head, "\"/>");
+ }
+ GRN_TEXT_PUTS(ctx, head, "</ERROR>");
+ }
+ GRN_TEXT_PUTS(ctx, foot, "\n</RESULT>");
+ }
+ }
+ break;
+ case GRN_CONTENT_MSGPACK:
+#ifdef GRN_WITH_MESSAGE_PACK
+ if (grn_ctx_get_command_version(ctx) <= GRN_COMMAND_VERSION_2) {
+ grn_output_envelope_msgpack_v1(ctx, rc,
+ head, body, foot,
+ started, elapsed,
+ file, line);
+ } else {
+ grn_output_envelope_msgpack(ctx, rc,
+ head, body, foot,
+ started, elapsed,
+ file, line);
+ }
+#endif /* GRN_WITH_MESSAGE_PACK */
+ break;
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ break;
+ case GRN_CONTENT_NONE:
+ break;
+ }
+}
+
+static inline grn_bool
+is_output_columns_format_v1(grn_ctx *ctx,
+ const char *output_columns,
+ unsigned int output_columns_len)
+{
+ const char *current;
+ const char *end;
+ grn_bool in_identifier = GRN_FALSE;
+
+ current = output_columns;
+ end = current + output_columns_len;
+ while (current < end) {
+ int char_length;
+
+ char_length = grn_charlen(ctx, current, end);
+ if (char_length != 1) {
+ return GRN_FALSE;
+ }
+
+ switch (current[0]) {
+ case ' ' :
+ case ',' :
+ in_identifier = GRN_FALSE;
+ break;
+ case '_' :
+ in_identifier = GRN_TRUE;
+ break;
+ case '.' :
+ case '-' :
+ case '#' :
+ case '@' :
+ if (!in_identifier) {
+ return GRN_FALSE;
+ }
+ break;
+ default :
+ if ('a' <= current[0] && current[0] <= 'z') {
+ in_identifier = GRN_TRUE;
+ break;
+ } else if ('A' <= current[0] && current[0] <= 'Z') {
+ in_identifier = GRN_TRUE;
+ break;
+ } else if ('0' <= current[0] && current[0] <= '9') {
+ in_identifier = GRN_TRUE;
+ break;
+ } else {
+ return GRN_FALSE;
+ }
+ }
+
+ current += char_length;
+ }
+
+ return GRN_TRUE;
+}
+
+grn_rc
+grn_output_format_set_columns(grn_ctx *ctx, grn_obj_format *format,
+ grn_obj *table,
+ const char *columns, int columns_len)
+{
+ grn_rc rc;
+
+ if (is_output_columns_format_v1(ctx, columns, columns_len)) {
+ rc = grn_obj_columns(ctx, table, columns, columns_len, &(format->columns));
+ } else {
+ grn_obj *variable;
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, format->expression, variable);
+ rc = grn_expr_parse(ctx, format->expression,
+ columns, columns_len, NULL,
+ GRN_OP_MATCH, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_OUTPUT_COLUMNS);
+ }
+
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/pat.c b/storage/mroonga/vendor/groonga/lib/pat.c
new file mode 100644
index 00000000..5d3c5ff3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/pat.c
@@ -0,0 +1,3674 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include <string.h>
+#include <limits.h>
+#include "grn_pat.h"
+#include "grn_output.h"
+#include "grn_util.h"
+#include "grn_normalizer.h"
+
+#define GRN_PAT_DELETED (GRN_ID_MAX + 1)
+
+#define GRN_PAT_SEGMENT_SIZE 0x400000
+#define W_OF_KEY_IN_A_SEGMENT 22
+#define W_OF_PAT_IN_A_SEGMENT 18
+#define W_OF_SIS_IN_A_SEGMENT 19
+#define KEY_MASK_IN_A_SEGMENT 0x3fffff
+#define PAT_MASK_IN_A_SEGMENT 0x3ffff
+#define SIS_MASK_IN_A_SEGMENT 0x7ffff
+#define SEG_NOT_ASSIGNED 0xffff
+#define GRN_PAT_MAX_SEGMENT 0x1000
+#define GRN_PAT_MDELINFOS (GRN_PAT_NDELINFOS - 1)
+
+#define GRN_PAT_BIN_KEY 0x70000
+
+typedef struct {
+ grn_id lr[2];
+ /*
+ lr[0]: the left node.
+ lr[1]: the right node.
+
+ The left node has 0 at the nth bit at the nth byte.
+ The right node has 1 at the nth bit at the nth byte.
+ 'check' value indicate 'at the nth bit at the nth byte'.
+
+ The both available nodes has larger check value rather
+ than the current node.
+
+ The first node (PAT_AT(pat, GRN_ID_NIL, node)) has only
+ the right node and the node is the start point.
+ */
+ uint32_t key;
+ /*
+ PAT_IMD(node) == 0: key bytes offset in memory map.
+ PAT_IMD(node) == 1: the key bytes.
+ */
+ uint16_t check;
+ /*
+ nth byte: 12, nth bit: 3, terminated: 1
+
+ nth byte is different in key bytes: (check >> 4): max == 4095
+ the left most byte is the 0th byte and the right most byte is the 11th byte.
+
+ nth bit is different in nth byte: ((check >> 1) & 0b111)
+ the left most bit is the 0th bit and the right most bit is the 7th bit.
+
+ terminated: (check & 0b1)
+ terminated == 1: key is terminated.
+ */
+ uint16_t bits;
+ /* length: 13, immediate: 1, deleting: 1 */
+} pat_node;
+
+#define PAT_DELETING (1<<1)
+#define PAT_IMMEDIATE (1<<2)
+
+#define PAT_DEL(x) ((x)->bits & PAT_DELETING)
+#define PAT_IMD(x) ((x)->bits & PAT_IMMEDIATE)
+#define PAT_LEN(x) (((x)->bits >> 3) + 1)
+#define PAT_CHK(x) ((x)->check)
+#define PAT_DEL_ON(x) ((x)->bits |= PAT_DELETING)
+#define PAT_IMD_ON(x) ((x)->bits |= PAT_IMMEDIATE)
+#define PAT_DEL_OFF(x) ((x)->bits &= ~PAT_DELETING)
+#define PAT_IMD_OFF(x) ((x)->bits &= ~PAT_IMMEDIATE)
+#define PAT_LEN_SET(x,v) ((x)->bits = ((x)->bits & ((1<<3) - 1))|(((v) - 1) << 3))
+#define PAT_CHK_SET(x,v) ((x)->check = (v))
+
+typedef struct {
+ grn_id children;
+ grn_id sibling;
+} sis_node;
+
+enum {
+ segment_key = 0,
+ segment_pat = 1,
+ segment_sis = 2
+};
+
+void grn_p_pat_node(grn_ctx *ctx, grn_pat *pat, pat_node *node);
+
+/* error utilities */
+inline static int
+grn_pat_name(grn_ctx *ctx, grn_pat *pat, char *buffer, int buffer_size)
+{
+ int name_size;
+
+ if (DB_OBJ(pat)->id == GRN_ID_NIL) {
+ grn_strcpy(buffer, buffer_size, "(anonymous)");
+ name_size = strlen(buffer);
+ } else {
+ name_size = grn_obj_name(ctx, (grn_obj *)pat, buffer, buffer_size);
+ }
+
+ return name_size;
+}
+
+/* bit operation */
+
+#define nth_bit(key,n,l) ((((key)[(n)>>4]) >> (7 - (((n)>>1) & 7))) & 1)
+
+/* segment operation */
+
+/* patricia array operation */
+
+#define PAT_AT(pat,id,n) do {\
+ int flags = 0;\
+ GRN_IO_ARRAY_AT(pat->io, segment_pat, id, &flags, n);\
+} while (0)
+
+inline static pat_node *
+pat_get(grn_ctx *ctx, grn_pat *pat, grn_id id)
+{
+ pat_node *res;
+ int flags = GRN_TABLE_ADD;
+ if (id > GRN_ID_MAX) { return NULL; }
+ GRN_IO_ARRAY_AT(pat->io, segment_pat, id, &flags, res);
+ return res;
+}
+
+/* sis operation */
+
+inline static sis_node *
+sis_at(grn_ctx *ctx, grn_pat *pat, grn_id id)
+{
+ sis_node *res;
+ int flags = 0;
+ if (id > GRN_ID_MAX) { return NULL; }
+ GRN_IO_ARRAY_AT(pat->io, segment_sis, id, &flags, res);
+ return res;
+}
+
+inline static sis_node *
+sis_get(grn_ctx *ctx, grn_pat *pat, grn_id id)
+{
+ sis_node *res;
+ int flags = GRN_TABLE_ADD;
+ if (id > GRN_ID_MAX) { return NULL; }
+ GRN_IO_ARRAY_AT(pat->io, segment_sis, id, &flags, res);
+ return res;
+}
+
+#define MAX_LEVEL 16
+
+static void
+sis_collect(grn_ctx *ctx, grn_pat *pat, grn_hash *h, grn_id id, uint32_t level)
+{
+ uint32_t *offset;
+ sis_node *sl = sis_at(ctx, pat, id);
+ if (sl) {
+ grn_id sid = sl->children;
+ while (sid && sid != id) {
+ if (grn_hash_add(ctx, h, &sid, sizeof(grn_id), (void **) &offset, NULL)) {
+ *offset = level;
+ if (level < MAX_LEVEL) { sis_collect(ctx, pat, h, sid, level + 1); }
+ if (!(sl = sis_at(ctx, pat, sid))) { break; }
+ sid = sl->sibling;
+ } else {
+ /* todo : must be handled */
+ }
+ }
+ }
+}
+
+/* key operation */
+
+#define KEY_AT(pat,pos,ptr,addp) do {\
+ int flags = addp;\
+ GRN_IO_ARRAY_AT(pat->io, segment_key, pos, &flags, ptr);\
+} while (0)
+
+inline static uint32_t
+key_put(grn_ctx *ctx, grn_pat *pat, const uint8_t *key, uint32_t len)
+{
+ uint32_t res, ts;
+// if (len >= GRN_PAT_SEGMENT_SIZE) { return 0; /* error */ }
+ res = pat->header->curr_key;
+ if (res < GRN_PAT_MAX_TOTAL_KEY_SIZE &&
+ len > GRN_PAT_MAX_TOTAL_KEY_SIZE - res) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_pat_name(ctx, pat, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_NOT_ENOUGH_SPACE,
+ "[pat][key][put] total key size is over: <%.*s>: "
+ "max=%u: current=%u: new key size=%u",
+ name_size, name,
+ GRN_PAT_MAX_TOTAL_KEY_SIZE,
+ res,
+ len);
+ return 0;
+ }
+
+ ts = (res + len) >> W_OF_KEY_IN_A_SEGMENT;
+ if (res >> W_OF_KEY_IN_A_SEGMENT != ts) {
+ res = pat->header->curr_key = ts << W_OF_KEY_IN_A_SEGMENT;
+ }
+ {
+ uint8_t *dest;
+ KEY_AT(pat, res, dest, GRN_TABLE_ADD);
+ if (!dest) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+ name_size = grn_pat_name(ctx, pat, name, GRN_TABLE_MAX_KEY_SIZE);
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[pat][key][put] failed to allocate memory for new key: <%.*s>: "
+ "new offset:%u key size:%u",
+ name_size, name,
+ res,
+ len);
+ return 0;
+ }
+ grn_memcpy(dest, key, len);
+ }
+ pat->header->curr_key += len;
+ return res;
+}
+
+inline static uint8_t *
+pat_node_get_key(grn_ctx *ctx, grn_pat *pat, pat_node *n)
+{
+ if (PAT_IMD(n)) {
+ return (uint8_t *) &n->key;
+ } else {
+ uint8_t *res;
+ KEY_AT(pat, n->key, res, 0);
+ return res;
+ }
+}
+
+inline static grn_rc
+pat_node_set_key(grn_ctx *ctx, grn_pat *pat, pat_node *n, const uint8_t *key, uint32_t len)
+{
+ grn_rc rc;
+ if (!key || !len) { return GRN_INVALID_ARGUMENT; }
+ PAT_LEN_SET(n, len);
+ if (len <= sizeof(uint32_t)) {
+ PAT_IMD_ON(n);
+ grn_memcpy(&n->key, key, len);
+ rc = GRN_SUCCESS;
+ } else {
+ PAT_IMD_OFF(n);
+ n->key = key_put(ctx, pat, key, len);
+ rc = ctx->rc;
+ }
+ return rc;
+}
+
+/* delinfo operation */
+
+enum {
+ /* The delinfo is currently not used. */
+ DL_EMPTY = 0,
+ /*
+ * stat->d refers to a deleting node (in a tree).
+ * The deletion requires an additional operation.
+ */
+ DL_PHASE1,
+ /*
+ * stat->d refers to a deleted node (not in a tree).
+ * The node is pending for safety.
+ */
+ DL_PHASE2
+};
+
+inline static grn_pat_delinfo *
+delinfo_search(grn_pat *pat, grn_id id)
+{
+ int i;
+ grn_pat_delinfo *di;
+ for (i = (pat->header->curr_del2) & GRN_PAT_MDELINFOS;
+ i != pat->header->curr_del;
+ i = (i + 1) & GRN_PAT_MDELINFOS) {
+ di = &pat->header->delinfos[i];
+ if (di->stat != DL_PHASE1) { continue; }
+ if (di->ld == id) { return di; }
+ if (di->d == id) { return di; }
+ }
+ return NULL;
+}
+
+inline static grn_rc
+delinfo_turn_2(grn_ctx *ctx, grn_pat *pat, grn_pat_delinfo *di)
+{
+ grn_id d, *p = NULL;
+ pat_node *ln, *dn;
+ // grn_log("delinfo_turn_2> di->d=%d di->ld=%d stat=%d", di->d, di->ld, di->stat);
+ if (di->stat != DL_PHASE1) {
+ return GRN_SUCCESS;
+ }
+ PAT_AT(pat, di->ld, ln);
+ if (!ln) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ d = di->d;
+ if (!d) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ PAT_AT(pat, d, dn);
+ if (!dn) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ PAT_DEL_OFF(ln);
+ PAT_DEL_OFF(dn);
+ {
+ grn_id *p0;
+ pat_node *rn;
+ int c0 = -1, c;
+ uint32_t len = PAT_LEN(dn) * 16;
+ const uint8_t *key = pat_node_get_key(ctx, pat, dn);
+ if (!key) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ PAT_AT(pat, 0, rn);
+ p0 = &rn->lr[1];
+ for (;;) {
+ grn_id r = *p0;
+ if (!r) {
+ break;
+ }
+ if (r == d) {
+ p = p0;
+ break;
+ }
+ PAT_AT(pat, r, rn);
+ if (!rn) {
+ return GRN_FILE_CORRUPT;
+ }
+ c = PAT_CHK(rn);
+ if ((int) c <= (int) c0 || (int) len <= (int) c) {
+ break;
+ }
+ if (c & 1) {
+ p0 = (c + 1 < (int) len) ? &rn->lr[1] : &rn->lr[0];
+ } else {
+ p0 = &rn->lr[nth_bit((uint8_t *)key, c, len)];
+ }
+ c0 = c;
+ }
+ }
+ if (p) {
+ PAT_CHK_SET(ln, PAT_CHK(dn));
+ ln->lr[1] = dn->lr[1];
+ ln->lr[0] = dn->lr[0];
+ *p = di->ld;
+ } else {
+ /* debug */
+ int j;
+ grn_id dd;
+ grn_pat_delinfo *ddi;
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "failed to find d=%d", d);
+ for (j = (pat->header->curr_del2 + 1) & GRN_PAT_MDELINFOS;
+ j != pat->header->curr_del;
+ j = (j + 1) & GRN_PAT_MDELINFOS) {
+ ddi = &pat->header->delinfos[j];
+ if (ddi->stat != DL_PHASE1) { continue; }
+ PAT_AT(pat, ddi->ld, ln);
+ if (!ln) { continue; }
+ if (!(dd = ddi->d)) { continue; }
+ if (d == ddi->ld) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "found!!!, d(%d) become ld of (%d)", d, dd);
+ }
+ }
+ /* debug */
+ }
+ di->stat = DL_PHASE2;
+ di->d = d;
+ // grn_log("delinfo_turn_2< di->d=%d di->ld=%d", di->d, di->ld);
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+delinfo_turn_3(grn_ctx *ctx, grn_pat *pat, grn_pat_delinfo *di)
+{
+ pat_node *dn;
+ uint32_t size;
+ if (di->stat != DL_PHASE2) { return GRN_SUCCESS; }
+ PAT_AT(pat, di->d, dn);
+ if (!dn) { return GRN_INVALID_ARGUMENT; }
+ if (di->shared) {
+ PAT_IMD_ON(dn);
+ size = 0;
+ } else {
+ if (PAT_IMD(dn)) {
+ size = 0;
+ } else {
+ size = PAT_LEN(dn);
+ }
+ }
+ di->stat = DL_EMPTY;
+ // dn->lr[1] = GRN_PAT_DELETED;
+ dn->lr[0] = pat->header->garbages[size];
+ pat->header->garbages[size] = di->d;
+ return GRN_SUCCESS;
+}
+
+inline static grn_pat_delinfo *
+delinfo_new(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_pat_delinfo *res = &pat->header->delinfos[pat->header->curr_del];
+ uint32_t n = (pat->header->curr_del + 1) & GRN_PAT_MDELINFOS;
+ int gap = ((n + GRN_PAT_NDELINFOS - pat->header->curr_del2) & GRN_PAT_MDELINFOS)
+ - (GRN_PAT_NDELINFOS / 2);
+ while (gap-- > 0) {
+ if (delinfo_turn_2(ctx, pat, &pat->header->delinfos[pat->header->curr_del2])) {
+ GRN_LOG(ctx, GRN_LOG_CRIT, "d2 failed: %d", pat->header->delinfos[pat->header->curr_del2].ld);
+ }
+ pat->header->curr_del2 = (pat->header->curr_del2 + 1) & GRN_PAT_MDELINFOS;
+ }
+ if ((int) n == (int) pat->header->curr_del3) {
+ if (delinfo_turn_3(ctx, pat, &pat->header->delinfos[pat->header->curr_del3])) {
+ GRN_LOG(ctx, GRN_LOG_CRIT, "d3 failed: %d", pat->header->delinfos[pat->header->curr_del3].ld);
+ }
+ pat->header->curr_del3 = (pat->header->curr_del3 + 1) & GRN_PAT_MDELINFOS;
+ }
+ pat->header->curr_del = n;
+ return res;
+}
+
+/* pat operation */
+
+inline static grn_pat *
+_grn_pat_create(grn_ctx *ctx, grn_pat *pat,
+ const char *path, uint32_t key_size,
+ uint32_t value_size, uint32_t flags) {
+ grn_io *io;
+ pat_node *node0;
+ struct grn_pat_header *header;
+ uint32_t entry_size, w_of_element;
+ grn_encoding encoding = ctx->encoding;
+ if (flags & GRN_OBJ_KEY_WITH_SIS) {
+ entry_size = sizeof(sis_node) + value_size;
+ } else {
+ entry_size = value_size;
+ }
+ for (w_of_element = 0; (1 << w_of_element) < entry_size; w_of_element++) {
+ /* nop */
+ }
+ {
+ grn_io_array_spec array_spec[3];
+ array_spec[segment_key].w_of_element = 0;
+ array_spec[segment_key].max_n_segments = 0x400;
+ array_spec[segment_pat].w_of_element = 4;
+ array_spec[segment_pat].max_n_segments = 1 << (30 - (22 - 4));
+ array_spec[segment_sis].w_of_element = w_of_element;
+ array_spec[segment_sis].max_n_segments = 1 << (30 - (22 - w_of_element));
+ io = grn_io_create_with_array(ctx, path, sizeof(struct grn_pat_header),
+ GRN_PAT_SEGMENT_SIZE, grn_io_auto, 3, array_spec);
+ }
+ if (!io) { return NULL; }
+ if (encoding == GRN_ENC_DEFAULT) { encoding = grn_gctx.encoding; }
+ header = grn_io_header(io);
+ grn_io_set_type(io, GRN_TABLE_PAT_KEY);
+ header->flags = flags;
+ header->encoding = encoding;
+ header->key_size = key_size;
+ header->value_size = value_size;
+ header->n_entries = 0;
+ header->curr_rec = 0;
+ header->curr_key = 0;
+ header->curr_del = 0;
+ header->curr_del2 = 0;
+ header->curr_del3 = 0;
+ header->n_garbages = 0;
+ header->tokenizer = GRN_ID_NIL;
+ if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
+ header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
+ pat->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ header->normalizer = grn_obj_id(ctx, pat->normalizer);
+ } else {
+ pat->normalizer = NULL;
+ header->normalizer = GRN_ID_NIL;
+ }
+ header->truncated = GRN_FALSE;
+ GRN_PTR_INIT(&(pat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ pat->io = io;
+ pat->header = header;
+ pat->key_size = key_size;
+ pat->value_size = value_size;
+ pat->tokenizer = NULL;
+ pat->encoding = encoding;
+ pat->obj.header.flags = header->flags;
+ if (!(node0 = pat_get(ctx, pat, 0))) {
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ node0->lr[1] = 0;
+ node0->lr[0] = 0;
+ node0->key = 0;
+ return pat;
+}
+
+grn_pat *
+grn_pat_create(grn_ctx *ctx, const char *path, uint32_t key_size,
+ uint32_t value_size, uint32_t flags)
+{
+ grn_pat *pat;
+ if (!(pat = GRN_CALLOC(sizeof(grn_pat)))) {
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(pat, GRN_TABLE_PAT_KEY);
+ if (!_grn_pat_create(ctx, pat, path, key_size, value_size, flags)) {
+ GRN_FREE(pat);
+ return NULL;
+ }
+ pat->cache = NULL;
+ pat->cache_size = 0;
+ pat->is_dirty = GRN_FALSE;
+ CRITICAL_SECTION_INIT(pat->lock);
+ return pat;
+}
+
+/*
+ grn_pat_cache_enable() and grn_pat_cache_disable() are not thread-safe.
+ So far, they can be used only from single threaded programs.
+ */
+
+grn_rc
+grn_pat_cache_enable(grn_ctx *ctx, grn_pat *pat, uint32_t cache_size)
+{
+ if (pat->cache || pat->cache_size) {
+ ERR(GRN_INVALID_ARGUMENT, "cache is already enabled");
+ return ctx->rc;
+ }
+ if (cache_size & (cache_size - 1)) {
+ ERR(GRN_INVALID_ARGUMENT, "cache_size(%u) must be a power of two", cache_size);
+ return ctx->rc;
+ }
+ if (!(pat->cache = GRN_CALLOC(cache_size * sizeof(grn_id)))) {
+ return ctx->rc;
+ }
+ pat->cache_size = cache_size;
+ return GRN_SUCCESS;
+}
+
+void
+grn_pat_cache_disable(grn_ctx *ctx, grn_pat *pat)
+{
+ if (pat->cache) {
+ GRN_FREE(pat->cache);
+ pat->cache_size = 0;
+ pat->cache = NULL;
+ }
+}
+
+grn_pat *
+grn_pat_open(grn_ctx *ctx, const char *path)
+{
+ grn_io *io;
+ grn_pat *pat;
+ pat_node *node0;
+ struct grn_pat_header *header;
+ uint32_t io_type;
+ io = grn_io_open(ctx, path, grn_io_auto);
+ if (!io) { return NULL; }
+ header = grn_io_header(io);
+ io_type = grn_io_get_type(io);
+ if (io_type != GRN_TABLE_PAT_KEY) {
+ ERR(GRN_INVALID_FORMAT, "[table][pat] file type must be %#04x: <%#04x>",
+ GRN_TABLE_PAT_KEY, io_type);
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ if (!(pat = GRN_MALLOC(sizeof(grn_pat)))) {
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(pat, GRN_TABLE_PAT_KEY);
+ pat->io = io;
+ pat->header = header;
+ pat->key_size = header->key_size;
+ pat->value_size = header->value_size;
+ pat->encoding = header->encoding;
+ pat->tokenizer = grn_ctx_at(ctx, header->tokenizer);
+ if (header->flags & GRN_OBJ_KEY_NORMALIZE) {
+ header->flags &= ~GRN_OBJ_KEY_NORMALIZE;
+ pat->normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ header->normalizer = grn_obj_id(ctx, pat->normalizer);
+ } else {
+ pat->normalizer = grn_ctx_at(ctx, header->normalizer);
+ }
+ GRN_PTR_INIT(&(pat->token_filters), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ pat->obj.header.flags = header->flags;
+ PAT_AT(pat, 0, node0);
+ if (!node0) {
+ grn_io_close(ctx, io);
+ GRN_FREE(pat);
+ return NULL;
+ }
+ pat->cache = NULL;
+ pat->cache_size = 0;
+ pat->is_dirty = GRN_FALSE;
+ CRITICAL_SECTION_INIT(pat->lock);
+ return pat;
+}
+
+/*
+ * grn_pat_error_if_truncated() logs an error and returns its error code if
+ * a pat is truncated by another process.
+ * Otherwise, this function returns GRN_SUCCESS.
+ * Note that `ctx` and `pat` must be valid.
+ *
+ * FIXME: A pat should be reopened if possible.
+ */
+static grn_rc
+grn_pat_error_if_truncated(grn_ctx *ctx, grn_pat *pat)
+{
+ if (pat->header->truncated) {
+ ERR(GRN_FILE_CORRUPT,
+ "pat is truncated, please unmap or reopen the database");
+ return GRN_FILE_CORRUPT;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_pat_close(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_rc rc;
+
+ CRITICAL_SECTION_FIN(pat->lock);
+
+ if (pat->is_dirty) {
+ uint32_t n_dirty_opens;
+ GRN_ATOMIC_ADD_EX(&(pat->header->n_dirty_opens), -1, n_dirty_opens);
+ }
+
+ if ((rc = grn_io_close(ctx, pat->io))) {
+ ERR(rc, "grn_io_close failed");
+ } else {
+ grn_pvector_fin(ctx, &pat->token_filters);
+ if (pat->cache) { grn_pat_cache_disable(ctx, pat); }
+ GRN_FREE(pat);
+ }
+
+ return rc;
+}
+
+grn_rc
+grn_pat_remove(grn_ctx *ctx, const char *path)
+{
+ if (!path) {
+ ERR(GRN_INVALID_ARGUMENT, "path is null");
+ return GRN_INVALID_ARGUMENT;
+ }
+ return grn_io_remove(ctx, path);
+}
+
+grn_rc
+grn_pat_truncate(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_rc rc;
+ const char *io_path;
+ char *path;
+ uint32_t key_size, value_size, flags;
+
+ rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if ((io_path = grn_io_path(pat->io)) && *io_path != '\0') {
+ if (!(path = GRN_STRDUP(io_path))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ } else {
+ path = NULL;
+ }
+ key_size = pat->key_size;
+ value_size = pat->value_size;
+ flags = pat->obj.header.flags;
+ if (path) {
+ pat->header->truncated = GRN_TRUE;
+ }
+ if ((rc = grn_io_close(ctx, pat->io))) { goto exit; }
+ grn_pvector_fin(ctx, &pat->token_filters);
+ pat->io = NULL;
+ if (path && (rc = grn_io_remove(ctx, path))) { goto exit; }
+ if (!_grn_pat_create(ctx, pat, path, key_size, value_size, flags)) {
+ rc = GRN_UNKNOWN_ERROR;
+ }
+ if (pat->cache && pat->cache_size) {
+ memset(pat->cache, 0, pat->cache_size * sizeof(grn_id));
+ }
+exit:
+ if (path) { GRN_FREE(path); }
+ return rc;
+}
+
+inline static grn_id
+_grn_pat_add(grn_ctx *ctx, grn_pat *pat, const uint8_t *key, uint32_t size, uint32_t *new, uint32_t *lkey)
+{
+ grn_id r, r0, *p0, *p1 = NULL;
+ pat_node *rn, *rn0;
+ int c, c0 = -1, c1 = -1, len;
+ uint32_t cache_id = 0;
+
+ *new = 0;
+ if (pat->cache) {
+ const uint8_t *p = key;
+ uint32_t length = size;
+ for (cache_id = 0; length--; p++) { cache_id = (cache_id * 37) + *p; }
+ cache_id &= (pat->cache_size - 1);
+ if (pat->cache[cache_id]) {
+ PAT_AT(pat, pat->cache[cache_id], rn);
+ if (rn) {
+ const uint8_t *k = pat_node_get_key(ctx, pat, rn);
+ if (k && size == PAT_LEN(rn) && !memcmp(k, key, size)) {
+ return pat->cache[cache_id];
+ }
+ }
+ }
+ }
+
+ len = (int)size * 16;
+ PAT_AT(pat, 0, rn0);
+ p0 = &rn0->lr[1];
+ if (*p0) {
+ uint32_t size2;
+ int xor, mask;
+ const uint8_t *s, *d;
+ for (;;) {
+ if (!(r0 = *p0)) {
+ if (!(s = pat_node_get_key(ctx, pat, rn0))) { return GRN_ID_NIL; }
+ size2 = PAT_LEN(rn0);
+ break;
+ }
+ PAT_AT(pat, r0, rn0);
+ if (!rn0) { return GRN_ID_NIL; }
+ if (c0 < rn0->check && rn0->check < len) {
+ c1 = c0; c0 = rn0->check;
+ p1 = p0;
+ if (c0 & 1) {
+ p0 = (c0 + 1 < len) ? &rn0->lr[1] : &rn0->lr[0];
+ } else {
+ p0 = &rn0->lr[nth_bit(key, c0, len)];
+ }
+ } else {
+ if (!(s = pat_node_get_key(ctx, pat, rn0))) { return GRN_ID_NIL; }
+ size2 = PAT_LEN(rn0);
+ if (size == size2 && !memcmp(s, key, size)) {
+ if (pat->cache) { pat->cache[cache_id] = r0; }
+ return r0;
+ }
+ break;
+ }
+ }
+ {
+ uint32_t min = size > size2 ? size2 : size;
+ for (c = 0, d = key; min && *s == *d; c += 16, s++, d++, min--);
+ if (min) {
+ for (xor = *s ^ *d, mask = 0x80; !(xor & mask); mask >>= 1, c += 2);
+ } else {
+ c--;
+ }
+ }
+ if (c == c0 && !*p0) {
+ if (c < len - 2) { c += 2; }
+ } else {
+ if (c < c0) {
+ if (c > c1) {
+ p0 = p1;
+ } else {
+ PAT_AT(pat, 0, rn0);
+ p0 = &rn0->lr[1];
+ while ((r0 = *p0)) {
+ PAT_AT(pat, r0, rn0);
+ if (!rn0) { return GRN_ID_NIL; }
+ c0 = PAT_CHK(rn0);
+ if (c < c0) { break; }
+ if (c0 & 1) {
+ p0 = (c0 + 1 < len) ? &rn0->lr[1] : &rn0->lr[0];
+ } else {
+ p0 = &rn0->lr[nth_bit(key, c0, len)];
+ }
+ }
+ }
+ }
+ }
+ if (c >= len) { return GRN_ID_NIL; }
+ } else {
+ c = len - 2;
+ }
+ {
+ uint32_t size2 = size > sizeof(uint32_t) ? size : 0;
+ if (*lkey && size2) {
+ if (pat->header->garbages[0]) {
+ r = pat->header->garbages[0];
+ PAT_AT(pat, r, rn);
+ if (!rn) { return GRN_ID_NIL; }
+ pat->header->n_entries++;
+ pat->header->n_garbages--;
+ pat->header->garbages[0] = rn->lr[0];
+ } else {
+ r = pat->header->curr_rec + 1;
+ rn = pat_get(ctx, pat, r);
+ if (!rn) { return GRN_ID_NIL; }
+ pat->header->curr_rec = r;
+ pat->header->n_entries++;
+ }
+ PAT_IMD_OFF(rn);
+ PAT_LEN_SET(rn, size);
+ rn->key = *lkey;
+ } else {
+ if (pat->header->garbages[size2]) {
+ uint8_t *keybuf;
+ r = pat->header->garbages[size2];
+ PAT_AT(pat, r, rn);
+ if (!rn) { return GRN_ID_NIL; }
+ if (!(keybuf = pat_node_get_key(ctx, pat, rn))) { return GRN_ID_NIL; }
+ pat->header->n_entries++;
+ pat->header->n_garbages--;
+ pat->header->garbages[size2] = rn->lr[0];
+ PAT_LEN_SET(rn, size);
+ grn_memcpy(keybuf, key, size);
+ } else {
+ r = pat->header->curr_rec + 1;
+ rn = pat_get(ctx, pat, r);
+ if (!rn) { return GRN_ID_NIL; }
+ if (pat_node_set_key(ctx, pat, rn, key, size)) { return GRN_ID_NIL; }
+ pat->header->curr_rec = r;
+ pat->header->n_entries++;
+ }
+ *lkey = rn->key;
+ }
+ }
+ PAT_CHK_SET(rn, c);
+ PAT_DEL_OFF(rn);
+ if ((c & 1) ? (c + 1 < len) : nth_bit(key, c, len)) {
+ rn->lr[1] = r;
+ rn->lr[0] = *p0;
+ } else {
+ rn->lr[1] = *p0;
+ rn->lr[0] = r;
+ }
+ // smp_wmb();
+ *p0 = r;
+ *new = 1;
+ if (pat->cache) { pat->cache[cache_id] = r; }
+ return r;
+}
+
+inline static grn_bool
+chop(grn_ctx *ctx, grn_pat *pat, const char **key, const char *end, uint32_t *lkey)
+{
+ size_t len = grn_charlen(ctx, *key, end);
+ if (len) {
+ *lkey += len;
+ *key += len;
+ return (end - *key) > 0;
+ } else {
+ return GRN_FALSE;
+ }
+}
+
+#define MAX_FIXED_KEY_SIZE (sizeof(int64_t))
+
+#define KEY_NEEDS_CONVERT(pat,size) \
+ (!((pat)->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE) && (size_t) (size) <= MAX_FIXED_KEY_SIZE)
+
+#define KEY_ENC(pat,keybuf,key,size) do {\
+ switch ((pat)->obj.header.flags & GRN_OBJ_KEY_MASK) {\
+ case GRN_OBJ_KEY_UINT :\
+ if (((pat)->obj.header.domain != GRN_DB_TOKYO_GEO_POINT) &&\
+ ((pat)->obj.header.domain != GRN_DB_WGS84_GEO_POINT)) {\
+ grn_hton((keybuf), (key), (size));\
+ break;\
+ }\
+ case GRN_OBJ_KEY_GEO_POINT :\
+ grn_gton((keybuf), (key), (size));\
+ break;\
+ case GRN_OBJ_KEY_INT :\
+ grn_hton((keybuf), (key), (size));\
+ *((uint8_t *)(keybuf)) ^= 0x80;\
+ break;\
+ case GRN_OBJ_KEY_FLOAT :\
+ if ((size) == sizeof(int64_t)) {\
+ int64_t v = *(int64_t *)(key);\
+ v ^= ((v >> 63)|(1ULL << 63));\
+ grn_hton((keybuf), &v, (size));\
+ }\
+ break;\
+ }\
+} while (0)
+
+#define KEY_DEC(pat,keybuf,key,size) do {\
+ switch ((pat)->obj.header.flags & GRN_OBJ_KEY_MASK) {\
+ case GRN_OBJ_KEY_UINT :\
+ if (((pat)->obj.header.domain != GRN_DB_TOKYO_GEO_POINT) &&\
+ ((pat)->obj.header.domain != GRN_DB_WGS84_GEO_POINT)) {\
+ grn_ntoh((keybuf), (key), (size));\
+ break;\
+ }\
+ case GRN_OBJ_KEY_GEO_POINT :\
+ grn_ntog((keybuf), (key), (size));\
+ break;\
+ case GRN_OBJ_KEY_INT :\
+ grn_ntohi((keybuf), (key), (size));\
+ break;\
+ case GRN_OBJ_KEY_FLOAT :\
+ if ((size) == sizeof(int64_t)) {\
+ int64_t v;\
+ grn_hton(&v, (key), (size));\
+ *((int64_t *)(keybuf)) = v ^ ((((int64_t)(v^(1ULL<<63)))>> 63)|(1ULL<<63)); \
+ }\
+ break;\
+ }\
+} while (0)
+
+#define KEY_ENCODE(pat,keybuf,key,size) do {\
+ if (KEY_NEEDS_CONVERT(pat,size)) {\
+ KEY_ENC((pat), (keybuf), (key), (size));\
+ (key) = (keybuf);\
+ }\
+} while (0)
+
+grn_id
+grn_pat_add(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size,
+ void **value, int *added)
+{
+ uint32_t new, lkey = 0;
+ grn_id r0;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (!key || !key_size) { return GRN_ID_NIL; }
+ if (key_size > GRN_TABLE_MAX_KEY_SIZE) {
+ ERR(GRN_INVALID_ARGUMENT, "too long key: (%u)", key_size);
+ return GRN_ID_NIL;
+ }
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ r0 = _grn_pat_add(ctx, pat, (uint8_t *)key, key_size, &new, &lkey);
+ if (r0 == GRN_ID_NIL) { return GRN_ID_NIL; }
+ if (added) { *added = new; }
+ if (r0 && (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) &&
+ (*((uint8_t *)key) & 0x80)) { // todo: refine!!
+ sis_node *sl, *sr;
+ grn_id l = r0, r;
+ if (new && (sl = sis_get(ctx, pat, l))) {
+ const char *sis = key, *end = sis + key_size;
+ sl->children = l;
+ sl->sibling = 0;
+ while (chop(ctx, pat, &sis, end, &lkey)) {
+ if (!(*sis & 0x80)) { break; }
+ if (!(r = _grn_pat_add(ctx, pat, (uint8_t *)sis, end - sis, &new, &lkey))) {
+ break;
+ }
+ if (!(sr = sis_get(ctx, pat, r))) { break; }
+ if (new) {
+ sl->sibling = r;
+ sr->children = l;
+ sr->sibling = 0;
+ } else {
+ sl->sibling = sr->children;
+ sr->children = l;
+ break;
+ }
+ l = r;
+ sl = sr;
+ }
+ }
+ }
+ if (r0 && value) {
+ byte *v = (byte *)sis_get(ctx, pat, r0);
+ if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ *value = v + sizeof(sis_node);
+ } else {
+ *value = v;
+ }
+ }
+ return r0;
+}
+
+inline static grn_id
+_grn_pat_get(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size, void **value)
+{
+ grn_id r;
+ pat_node *rn;
+ int c0 = -1, c;
+ uint32_t len = key_size * 16;
+ PAT_AT(pat, 0, rn);
+ for (r = rn->lr[1]; r;) {
+ PAT_AT(pat, r, rn);
+ if (!rn) { break; /* corrupt? */ }
+ c = PAT_CHK(rn);
+ if ((int) len <= c) { break; }
+ if (c <= c0) {
+ const uint8_t *k = pat_node_get_key(ctx, pat, rn);
+ if (k && key_size == PAT_LEN(rn) && !memcmp(k, key, key_size)) {
+ if (value) {
+ byte *v = (byte *)sis_get(ctx, pat, r);
+ if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ *value = v + sizeof(sis_node);
+ } else {
+ *value = v;
+ }
+ }
+ return r;
+ }
+ break;
+ }
+ if (c & 1) {
+ r = (c + 1 < (int) len) ? rn->lr[1] : rn->lr[0];
+ } else {
+ r = rn->lr[nth_bit((uint8_t *)key, c, len)];
+ }
+ c0 = c;
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_pat_get(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size, void **value)
+{
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ return _grn_pat_get(ctx, pat, key, key_size, value);
+}
+
+grn_id
+grn_pat_nextid(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
+{
+ grn_id r = GRN_ID_NIL;
+ if (pat && key) {
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (!(r = pat->header->garbages[key_size > sizeof(uint32_t) ? key_size : 0])) {
+ r = pat->header->curr_rec + 1;
+ }
+ }
+ return r;
+}
+
+static void
+get_tc(grn_ctx *ctx, grn_pat *pat, grn_hash *h, pat_node *rn)
+{
+ grn_id id;
+ pat_node *node;
+ id = rn->lr[1];
+ if (id) {
+ PAT_AT(pat, id, node);
+ if (node) {
+ if (PAT_CHK(node) > PAT_CHK(rn)) {
+ get_tc(ctx, pat, h, node);
+ } else {
+ grn_hash_add(ctx, h, &id, sizeof(grn_id), NULL, NULL);
+ }
+ }
+ }
+ id = rn->lr[0];
+ if (id) {
+ PAT_AT(pat, id, node);
+ if (node) {
+ if (PAT_CHK(node) > PAT_CHK(rn)) {
+ get_tc(ctx, pat, h, node);
+ } else {
+ grn_hash_add(ctx, h, &id, sizeof(grn_id), NULL, NULL);
+ }
+ }
+ }
+}
+
+grn_rc
+grn_pat_prefix_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, uint32_t key_size, grn_hash *h)
+{
+ int c0 = -1, c;
+ const uint8_t *k;
+ uint32_t len = key_size * 16;
+ grn_id r;
+ pat_node *rn;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ grn_rc rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ PAT_AT(pat, 0, rn);
+ r = rn->lr[1];
+ while (r) {
+ PAT_AT(pat, r, rn);
+ if (!rn) { return GRN_FILE_CORRUPT; }
+ c = PAT_CHK(rn);
+ if (c0 < c && c < (int) len - 1) {
+ if (c & 1) {
+ r = (c + 1 < (int) len) ? rn->lr[1] : rn->lr[0];
+ } else {
+ r = rn->lr[nth_bit((uint8_t *)key, c, len)];
+ }
+ c0 = c;
+ continue;
+ }
+ if (!(k = pat_node_get_key(ctx, pat, rn))) { break; }
+ if (PAT_LEN(rn) < key_size) { break; }
+ if (!memcmp(k, key, key_size)) {
+ if (c >= (int) len - 1) {
+ get_tc(ctx, pat, h, rn);
+ } else {
+ grn_hash_add(ctx, h, &r, sizeof(grn_id), NULL, NULL);
+ }
+ return GRN_SUCCESS;
+ }
+ break;
+ }
+ return GRN_END_OF_DATA;
+}
+
+grn_hash *
+grn_pat_prefix_search2(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
+{
+ grn_hash *h;
+ if (!pat || !key) { return NULL; }
+ if ((h = grn_hash_create(ctx, NULL, sizeof(grn_id), 0, 0))) {
+ if (grn_pat_prefix_search(ctx, pat, key, key_size, h)) {
+ grn_hash_close(ctx, h);
+ h = NULL;
+ }
+ }
+ return h;
+}
+
+grn_rc
+grn_pat_suffix_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, uint32_t key_size, grn_hash *h)
+{
+ grn_id r;
+ if ((r = grn_pat_get(ctx, pat, key, key_size, NULL))) {
+ uint32_t *offset;
+ if (grn_hash_add(ctx, h, &r, sizeof(grn_id), (void **) &offset, NULL)) {
+ *offset = 0;
+ if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) { sis_collect(ctx, pat, h, r, 1); }
+ return GRN_SUCCESS;
+ }
+ }
+ return GRN_END_OF_DATA;
+}
+
+grn_hash *
+grn_pat_suffix_search2(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
+{
+ grn_hash *h;
+ if (!pat || !key) { return NULL; }
+ if ((h = grn_hash_create(ctx, NULL, sizeof(grn_id), sizeof(uint32_t), 0))) {
+ if (grn_pat_suffix_search(ctx, pat, key, key_size, h)) {
+ grn_hash_close(ctx, h);
+ h = NULL;
+ }
+ }
+ return h;
+}
+
+grn_id
+grn_pat_lcp_search(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
+{
+ pat_node *rn;
+ grn_id r, r2 = GRN_ID_NIL;
+ uint32_t len = key_size * 16;
+ int c0 = -1, c;
+ if (!pat || !key) {
+ return GRN_ID_NIL;
+ }
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ if (!(pat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)) { return GRN_ID_NIL; }
+ PAT_AT(pat, 0, rn);
+ for (r = rn->lr[1]; r;) {
+ PAT_AT(pat, r, rn);
+ if (!rn) { break; /* corrupt? */ }
+ c = PAT_CHK(rn);
+ if (c <= c0) {
+ if (PAT_LEN(rn) <= key_size) {
+ uint8_t *p = pat_node_get_key(ctx, pat, rn);
+ if (!p) { break; }
+ if (!memcmp(p, key, PAT_LEN(rn))) { return r; }
+ }
+ break;
+ }
+ if ((int) len <= c) { break; }
+ if (c & 1) {
+ uint8_t *p;
+ pat_node *rn0;
+ grn_id r0 = rn->lr[0];
+ PAT_AT(pat, r0, rn0);
+ if (!rn0) { break; /* corrupt? */ }
+ p = pat_node_get_key(ctx, pat, rn0);
+ if (!p) { break; }
+ if (PAT_LEN(rn0) <= key_size && !memcmp(p, key, PAT_LEN(rn0))) { r2 = r0; }
+ r = (c + 1 < (int) len) ? rn->lr[1] : rn->lr[0];
+ } else {
+ r = rn->lr[nth_bit((uint8_t *)key, c, len)];
+ }
+ c0 = c;
+ }
+ return r2;
+}
+
+static grn_id
+common_prefix_pat_node_get(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size)
+{
+ int c0 = -1, c;
+ const uint8_t *k;
+ uint32_t len = key_size * 16;
+ grn_id r;
+ pat_node *rn;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ PAT_AT(pat, 0, rn);
+ r = rn->lr[1];
+ while (r) {
+ PAT_AT(pat, r, rn);
+ if (!rn) { return GRN_ID_NIL; }
+ c = PAT_CHK(rn);
+ if (c0 < c && c < (int) len - 1) {
+ if (c & 1) {
+ r = (c + 1 < (int) len) ? rn->lr[1] : rn->lr[0];
+ } else {
+ r = rn->lr[nth_bit((uint8_t *)key, c, len)];
+ }
+ c0 = c;
+ continue;
+ }
+ if (!(k = pat_node_get_key(ctx, pat, rn))) { break; }
+ if (PAT_LEN(rn) < key_size) { break; }
+ if (!memcmp(k, key, key_size)) {
+ return r;
+ }
+ break;
+ }
+ return GRN_ID_NIL;
+}
+
+typedef struct {
+ grn_id id;
+ uint16_t distance;
+} fuzzy_heap_node;
+
+typedef struct {
+ int n_entries;
+ int limit;
+ fuzzy_heap_node *nodes;
+} fuzzy_heap;
+
+static inline fuzzy_heap *
+fuzzy_heap_open(grn_ctx *ctx, int max)
+{
+ fuzzy_heap *h = GRN_MALLOC(sizeof(fuzzy_heap));
+ if (!h) { return NULL; }
+ h->nodes = GRN_MALLOC(sizeof(fuzzy_heap_node) * max);
+ if (!h->nodes) {
+ GRN_FREE(h);
+ return NULL;
+ }
+ h->n_entries = 0;
+ h->limit = max;
+ return h;
+}
+
+static inline grn_bool
+fuzzy_heap_push(grn_ctx *ctx, fuzzy_heap *h, grn_id id, uint16_t distance)
+{
+ int n, n2;
+ fuzzy_heap_node node = {id, distance};
+ fuzzy_heap_node node2;
+ if (h->n_entries >= h->limit) {
+ int max = h->limit * 2;
+ fuzzy_heap_node *nodes = GRN_REALLOC(h->nodes, sizeof(fuzzy_heap) * max);
+ if (!h) {
+ return GRN_FALSE;
+ }
+ h->limit = max;
+ h->nodes = nodes;
+ }
+ h->nodes[h->n_entries] = node;
+ n = h->n_entries++;
+ while (n) {
+ n2 = (n - 1) >> 1;
+ if (h->nodes[n2].distance <= h->nodes[n].distance) { break; }
+ node2 = h->nodes[n];
+ h->nodes[n] = h->nodes[n2];
+ h->nodes[n2] = node2;
+ n = n2;
+ }
+ return GRN_TRUE;
+}
+
+static inline void
+fuzzy_heap_close(grn_ctx *ctx, fuzzy_heap *h)
+{
+ GRN_FREE(h->nodes);
+ GRN_FREE(h);
+}
+
+#define DIST(ox,oy) (dists[((lx + 1) * (oy)) + (ox)])
+
+inline static uint16_t
+calc_edit_distance_by_offset(grn_ctx *ctx,
+ const char *sx, const char *ex,
+ const char *sy, const char *ey,
+ uint16_t *dists, uint32_t lx,
+ uint32_t offset, uint32_t max_distance,
+ grn_bool *can_transition, int flags)
+{
+ uint32_t cx, cy, x, y;
+ const char *px, *py;
+
+ /* Skip already calculated rows */
+ for (py = sy, y = 1; py < ey && (cy = grn_charlen(ctx, py, ey)); py += cy, y++) {
+ if (py - sy >= offset) {
+ break;
+ }
+ }
+ for (; py < ey && (cy = grn_charlen(ctx, py, ey)); py += cy, y++) {
+ /* children nodes will be no longer smaller than max distance
+ * with only insertion costs.
+ * This is end of row on allocated memory. */
+ if (y > lx + max_distance) {
+ *can_transition = GRN_FALSE;
+ return max_distance + 1;
+ }
+
+ for (px = sx, x = 1; px < ex && (cx = grn_charlen(ctx, px, ex)); px += cx, x++) {
+ if (cx == cy && !memcmp(px, py, cx)) {
+ DIST(x, y) = DIST(x - 1, y - 1);
+ } else {
+ uint32_t a, b, c;
+ a = DIST(x - 1, y) + 1;
+ b = DIST(x, y - 1) + 1;
+ c = DIST(x - 1, y - 1) + 1;
+ DIST(x, y) = ((a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c));
+ if (flags & GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION &&
+ x > 1 && y > 1 &&
+ cx == cy &&
+ memcmp(px, py - cy, cx) == 0 &&
+ memcmp(px - cx, py, cx) == 0) {
+ uint32_t t = DIST(x - 2, y - 2) + 1;
+ DIST(x, y) = ((DIST(x, y) < t) ? DIST(x, y) : t);
+ }
+ }
+ }
+ }
+ if (lx) {
+ /* If there is no cell which is smaller than equal to max distance on end of row,
+ * children nodes will be no longer smaller than max distance */
+ *can_transition = GRN_FALSE;
+ for (x = 1; x <= lx; x++) {
+ if (DIST(x, y - 1) <= max_distance) {
+ *can_transition = GRN_TRUE;
+ break;
+ }
+ }
+ }
+ return DIST(lx, y - 1);
+}
+
+typedef struct {
+ const char *key;
+ int key_length;
+ grn_bool can_transition;
+} fuzzy_node;
+
+inline static void
+_grn_pat_fuzzy_search(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ const char *key, uint32_t key_size,
+ uint16_t *dists, uint32_t lx,
+ int last_check, fuzzy_node *last_node,
+ uint32_t max_distance, int flags, fuzzy_heap *heap)
+{
+ pat_node *node = NULL;
+ int check, len;
+ const char *k;
+ uint32_t offset = 0;
+
+ PAT_AT(pat, id, node);
+ if (!node) {
+ return;
+ }
+ check = PAT_CHK(node);
+ len = PAT_LEN(node);
+ k = pat_node_get_key(ctx, pat, node);
+
+ if (check > last_check) {
+ if (len >= last_node->key_length &&
+ !memcmp(k, last_node->key, last_node->key_length)) {
+ if (last_node->can_transition == GRN_FALSE) {
+ return;
+ }
+ }
+ _grn_pat_fuzzy_search(ctx, pat, node->lr[0],
+ key, key_size, dists, lx,
+ check, last_node,
+ max_distance, flags, heap);
+
+ _grn_pat_fuzzy_search(ctx, pat, node->lr[1],
+ key, key_size, dists, lx,
+ check, last_node,
+ max_distance, flags, heap);
+ } else {
+ if (id) {
+ /* Set already calculated common prefix length */
+ if (len >= last_node->key_length &&
+ !memcmp(k, last_node->key, last_node->key_length)) {
+ if (last_node->can_transition == GRN_FALSE) {
+ return;
+ }
+ offset = last_node->key_length;
+ } else {
+ if (last_node->can_transition == GRN_FALSE) {
+ last_node->can_transition = GRN_TRUE;
+ }
+ if (last_node->key_length) {
+ const char *kp = k;
+ const char *ke = k + len;
+ const char *p = last_node->key;
+ const char *e = last_node->key + last_node->key_length;
+ int lp;
+ for (;p < e && kp < ke && (lp = grn_charlen(ctx, p, e));
+ p += lp, kp += lp) {
+ if (p + lp <= e && kp + lp <= ke && memcmp(p, kp, lp)) {
+ break;
+ }
+ }
+ offset = kp - k;
+ }
+ }
+ if (len - offset) {
+ uint16_t distance;
+ distance =
+ calc_edit_distance_by_offset(ctx,
+ key, key + key_size,
+ k, k + len,
+ dists, lx,
+ offset, max_distance,
+ &(last_node->can_transition), flags);
+ if (distance <= max_distance) {
+ fuzzy_heap_push(ctx, heap, id, distance);
+ }
+ }
+ last_node->key = k;
+ last_node->key_length = len;
+ }
+ }
+ return;
+}
+
+#define HEAP_SIZE 256
+
+grn_rc
+grn_pat_fuzzy_search(grn_ctx *ctx, grn_pat *pat,
+ const void *key, uint32_t key_size,
+ grn_fuzzy_search_optarg *args, grn_hash *h)
+{
+ pat_node *node;
+ grn_id id;
+ uint16_t *dists;
+ uint32_t lx, len, x, y, i;
+ const char *s = key;
+ const char *e = (const char *)key + key_size;
+ fuzzy_node last_node;
+ fuzzy_heap *heap;
+ uint32_t max_distance = 1;
+ uint32_t max_expansion = 0;
+ uint32_t prefix_match_size = 0;
+ int flags = 0;
+ grn_rc rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (args) {
+ max_distance = args->max_distance;
+ max_expansion = args->max_expansion;
+ prefix_match_size = args->prefix_match_size;
+ flags = args->flags;
+ }
+ if (key_size > GRN_TABLE_MAX_KEY_SIZE ||
+ max_distance > GRN_TABLE_MAX_KEY_SIZE ||
+ prefix_match_size > key_size) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ heap = fuzzy_heap_open(ctx, HEAP_SIZE);
+ if (!heap) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+
+ PAT_AT(pat, GRN_ID_NIL, node);
+ id = node->lr[1];
+
+ if (prefix_match_size) {
+ grn_id tid;
+ tid = common_prefix_pat_node_get(ctx, pat, key, prefix_match_size);
+ if (tid != GRN_ID_NIL) {
+ id = tid;
+ } else {
+ return GRN_END_OF_DATA;
+ }
+ }
+ for (lx = 0; s < e && (len = grn_charlen(ctx, s, e)); s += len) {
+ lx++;
+ }
+ dists = GRN_MALLOC((lx + 1) * (lx + max_distance + 1) * sizeof(uint16_t));
+ if (!dists) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+
+ for (x = 0; x <= lx; x++) { DIST(x, 0) = x; }
+ for (y = 0; y <= lx + max_distance ; y++) { DIST(0, y) = y; }
+
+ last_node.key = NULL;
+ last_node.key_length = 0;
+ last_node.can_transition = GRN_TRUE;
+ _grn_pat_fuzzy_search(ctx, pat, id,
+ key, key_size, dists, lx,
+ -1, &last_node, max_distance, flags, heap);
+ GRN_FREE(dists);
+ for (i = 0; i < (uint32_t) heap->n_entries; i++) {
+ if (max_expansion > 0 && i >= max_expansion) {
+ break;
+ }
+ if (DB_OBJ(h)->header.flags & GRN_OBJ_WITH_SUBREC) {
+ grn_rset_recinfo *ri;
+ if (grn_hash_add(ctx, h, &(heap->nodes[i].id), sizeof(grn_id), (void **)&ri, NULL)) {
+ ri->score = max_distance - heap->nodes[i].distance + 1;
+ }
+ } else {
+ grn_hash_add(ctx, h, &(heap->nodes[i].id), sizeof(grn_id), NULL, NULL);
+ }
+ }
+ fuzzy_heap_close(ctx, heap);
+ if (grn_hash_size(ctx, h)) {
+ return GRN_SUCCESS;
+ } else {
+ return GRN_END_OF_DATA;
+ }
+}
+
+inline static grn_rc
+_grn_pat_del(grn_ctx *ctx, grn_pat *pat, const char *key, uint32_t key_size, int shared,
+ grn_table_delete_optarg *optarg)
+{
+ grn_pat_delinfo *di;
+ pat_node *rn, *rn0 = NULL, *rno = NULL;
+ int c = -1, c0 = -1, ch;
+ uint32_t len = key_size * 16;
+ grn_id r, otherside, *proot, *p, *p0 = NULL;
+
+ /* delinfo_new() must be called before searching for rn. */
+ di = delinfo_new(ctx, pat);
+ di->shared = shared;
+
+ /*
+ * Search a patricia tree for a given key.
+ * If the key exists, get its output node.
+ *
+ * rn, rn0: the output node and its previous node.
+ * rno: the other side of rn (the other destination of rn0).
+ * c, c0: checks of rn0 and its previous node.
+ * p, p0: pointers to transitions (IDs) that refer to rn and rn0.
+ */
+ PAT_AT(pat, 0, rn);
+ proot = p = &rn->lr[1];
+ for (;;) {
+ r = *p;
+ if (!r) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ PAT_AT(pat, r, rn);
+ if (!rn) {
+ return GRN_FILE_CORRUPT;
+ }
+ ch = PAT_CHK(rn);
+ if ((int) len <= ch) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (c >= ch) {
+ /* Output node found. */
+ const uint8_t *k = pat_node_get_key(ctx, pat, rn);
+ if (!k) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (key_size != PAT_LEN(rn) || memcmp(k, key, key_size)) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ /* Given key found. */
+ break;
+ }
+ c0 = c;
+ p0 = p;
+ c = ch;
+ if (c & 1) {
+ p = (c + 1 < (int) len) ? &rn->lr[1] : &rn->lr[0];
+ } else {
+ p = &rn->lr[nth_bit((uint8_t *)key, c, len)];
+ }
+ rn0 = rn;
+ }
+ if (optarg && optarg->func &&
+ !optarg->func(ctx, (grn_obj *)pat, r, optarg->func_arg)) {
+ return GRN_SUCCESS;
+ }
+ if (rn0->lr[0] == rn0->lr[1]) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "*p0 (%d), rn0->lr[0] == rn0->lr[1] (%d)",
+ *p0, rn0->lr[0]);
+ return GRN_FILE_CORRUPT;
+ }
+ otherside = (rn0->lr[1] == r) ? rn0->lr[0] : rn0->lr[1];
+ if (otherside) {
+ PAT_AT(pat, otherside, rno);
+ if (!rno) {
+ return GRN_FILE_CORRUPT;
+ }
+ }
+
+ if (rn == rn0) {
+ /* The last transition (p) is a self-loop. */
+ di->stat = DL_PHASE2;
+ di->d = r;
+ if (otherside) {
+ if (c0 < PAT_CHK(rno) && PAT_CHK(rno) <= c) {
+ /* To keep rno as an output node, its check is set to zero. */
+ if (!delinfo_search(pat, otherside)) {
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "no delinfo found %d", otherside);
+ }
+ PAT_CHK_SET(rno, 0);
+ }
+ if (proot == p0 && !rno->check) {
+ /*
+ * Update rno->lr because the first node, rno becomes the new first
+ * node, is not an output node even if its check is zero.
+ */
+ const uint8_t *k = pat_node_get_key(ctx, pat, rno);
+ int direction = k ? (*k >> 7) : 1;
+ rno->lr[direction] = otherside;
+ rno->lr[!direction] = 0;
+ }
+ }
+ *p0 = otherside;
+ } else if ((!rn->lr[0] && rn->lr[1] == r) ||
+ (!rn->lr[1] && rn->lr[0] == r)) {
+ /* The output node has only a disabled self-loop. */
+ di->stat = DL_PHASE2;
+ di->d = r;
+ *p = 0;
+ } else {
+ /* The last transition (p) is not a self-loop. */
+ grn_pat_delinfo *ldi = NULL, *ddi = NULL;
+ if (PAT_DEL(rn)) {
+ ldi = delinfo_search(pat, r);
+ }
+ if (PAT_DEL(rn0)) {
+ ddi = delinfo_search(pat, *p0);
+ }
+ if (ldi) {
+ PAT_DEL_OFF(rn);
+ di->stat = DL_PHASE2;
+ if (ddi) {
+ PAT_DEL_OFF(rn0);
+ ddi->stat = DL_PHASE2;
+ if (ddi == ldi) {
+ if (r != ddi->ld) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "r(%d) != ddi->ld(%d)", r, ddi->ld);
+ }
+ di->d = r;
+ } else {
+ ldi->ld = ddi->ld;
+ di->d = r;
+ }
+ } else {
+ PAT_DEL_ON(rn0);
+ ldi->ld = *p0;
+ di->d = r;
+ }
+ } else {
+ PAT_DEL_ON(rn);
+ if (ddi) {
+ if (ddi->d != *p0) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "ddi->d(%d) != *p0(%d)", ddi->d, *p0);
+ }
+ PAT_DEL_OFF(rn0);
+ ddi->stat = DL_PHASE2;
+ di->stat = DL_PHASE1;
+ di->ld = ddi->ld;
+ di->d = r;
+ /*
+ PAT_DEL_OFF(rn0);
+ ddi->d = r;
+ di->stat = DL_PHASE2;
+ di->d = *p0;
+ */
+ } else {
+ PAT_DEL_ON(rn0);
+ di->stat = DL_PHASE1;
+ di->ld = *p0;
+ di->d = r;
+ // grn_log("pat_del d=%d ld=%d stat=%d", r, *p0, DL_PHASE1);
+ }
+ }
+ if (*p0 == otherside) {
+ /* The previous node (*p0) has a self-loop (rn0 == rno). */
+ PAT_CHK_SET(rno, 0);
+ if (proot == p0) {
+ /*
+ * Update rno->lr because the first node, rno becomes the new first
+ * node, is not an output node even if its check is zero.
+ */
+ const uint8_t *k = pat_node_get_key(ctx, pat, rno);
+ int direction = k ? (*k >> 7) : 1;
+ rno->lr[direction] = otherside;
+ rno->lr[!direction] = 0;
+ }
+ } else {
+ if (otherside) {
+ if (c0 < PAT_CHK(rno) && PAT_CHK(rno) <= c) {
+ /* To keep rno as an output node, its check is set to zero. */
+ if (!delinfo_search(pat, otherside)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "no delinfo found %d", otherside);
+ }
+ PAT_CHK_SET(rno, 0);
+ }
+ if (proot == p0 && !rno->check) {
+ /*
+ * Update rno->lr because the first node, rno becomes the new first
+ * node, is not an output node even if its check is zero.
+ */
+ const uint8_t *k = pat_node_get_key(ctx, pat, rno);
+ int direction = k ? (*k >> 7) : 1;
+ rno->lr[direction] = otherside;
+ rno->lr[!direction] = 0;
+ }
+ }
+ *p0 = otherside;
+ }
+ }
+ pat->header->n_entries--;
+ pat->header->n_garbages++;
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+_grn_pat_delete(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size,
+ grn_table_delete_optarg *optarg)
+{
+ if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ grn_id id = grn_pat_get(ctx, pat, key, key_size, NULL);
+ if (id && grn_pat_delete_with_sis(ctx, pat, id, optarg)) {
+ return GRN_SUCCESS;
+ }
+ return GRN_INVALID_ARGUMENT;
+ }
+ return _grn_pat_del(ctx, pat, key, key_size, 0, optarg);
+}
+
+grn_rc
+grn_pat_delete(grn_ctx *ctx, grn_pat *pat, const void *key, uint32_t key_size,
+ grn_table_delete_optarg *optarg)
+{
+ grn_rc rc;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ if (!pat || !key || !key_size) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ return _grn_pat_delete(ctx, pat, key, key_size, optarg);
+}
+
+uint32_t
+grn_pat_size(grn_ctx *ctx, grn_pat *pat)
+{
+ if (!pat) { return GRN_INVALID_ARGUMENT; }
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return 0;
+ }
+ return pat->header->n_entries;
+}
+
+const char *
+_grn_pat_key(grn_ctx *ctx, grn_pat *pat, grn_id id, uint32_t *key_size)
+{
+ pat_node *node;
+ uint8_t *key;
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ *key_size = 0;
+ return NULL;
+ }
+ PAT_AT(pat, id, node);
+ if (!node) {
+ *key_size = 0;
+ return NULL;
+ }
+ key = pat_node_get_key(ctx, pat, node);
+ if (key) {
+ *key_size = PAT_LEN(node);
+ } else {
+ *key_size = 0;
+ }
+ return (const char *)key;
+}
+
+grn_rc
+grn_pat_delete_by_id(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ grn_table_delete_optarg *optarg)
+{
+ grn_rc rc;
+ if (!pat || !id) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ {
+ uint32_t key_size;
+ const char *key = _grn_pat_key(ctx, pat, id, &key_size);
+ return _grn_pat_delete(ctx, pat, key, key_size, optarg);
+ }
+}
+
+int
+grn_pat_get_key(grn_ctx *ctx, grn_pat *pat, grn_id id, void *keybuf, int bufsize)
+{
+ int len;
+ uint8_t *key;
+ pat_node *node;
+ if (!pat) { return 0; }
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return 0;
+ }
+ if (!id) { return 0; }
+ PAT_AT(pat, id, node);
+ if (!node) { return 0; }
+ if (!(key = pat_node_get_key(ctx, pat, node))) { return 0; }
+ len = PAT_LEN(node);
+ if (keybuf && bufsize >= len) {
+ if (KEY_NEEDS_CONVERT(pat, len)) {
+ KEY_DEC(pat, keybuf, key, len);
+ } else {
+ grn_memcpy(keybuf, key, len);
+ }
+ }
+ return len;
+}
+
+int
+grn_pat_get_key2(grn_ctx *ctx, grn_pat *pat, grn_id id, grn_obj *bulk)
+{
+ uint32_t len;
+ uint8_t *key;
+ pat_node *node;
+ if (!pat) { return GRN_INVALID_ARGUMENT; }
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return 0;
+ }
+ if (!id) { return 0; }
+ PAT_AT(pat, id, node);
+ if (!node) { return 0; }
+ if (!(key = pat_node_get_key(ctx, pat, node))) { return 0; }
+ len = PAT_LEN(node);
+ if (KEY_NEEDS_CONVERT(pat, len)) {
+ if (bulk->header.impl_flags & GRN_OBJ_REFER) {
+ GRN_TEXT_INIT(bulk, 0);
+ }
+ if (!grn_bulk_reserve(ctx, bulk, len)) {
+ char *curr = GRN_BULK_CURR(bulk);
+ KEY_DEC(pat, curr, key, len);
+ grn_bulk_truncate(ctx, bulk, GRN_BULK_VSIZE(bulk) + len);
+ }
+ } else {
+ if (bulk->header.impl_flags & GRN_OBJ_REFER) {
+ bulk->u.b.head = (char *)key;
+ bulk->u.b.curr = (char *)key + len;
+ } else {
+ grn_bulk_write(ctx, bulk, (char *)key, len);
+ }
+ }
+ return len;
+}
+
+int
+grn_pat_get_value(grn_ctx *ctx, grn_pat *pat, grn_id id, void *valuebuf)
+{
+ int value_size;
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return 0;
+ }
+ value_size = (int)pat->value_size;
+ if (value_size) {
+ byte *v = (byte *)sis_at(ctx, pat, id);
+ if (v) {
+ if (valuebuf) {
+ if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ grn_memcpy(valuebuf, v + sizeof(sis_node), value_size);
+ } else {
+ grn_memcpy(valuebuf, v, value_size);
+ }
+ }
+ return value_size;
+ }
+ }
+ return 0;
+}
+
+const char *
+grn_pat_get_value_(grn_ctx *ctx, grn_pat *pat, grn_id id, uint32_t *size)
+{
+ const char *value = NULL;
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return NULL;
+ }
+ if ((*size = pat->value_size)) {
+ if ((value = (const char *)sis_at(ctx, pat, id))
+ && (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS)) {
+ value += sizeof(sis_node);
+ }
+ }
+ return value;
+}
+
+grn_rc
+grn_pat_set_value(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ const void *value, int flags)
+{
+ grn_rc rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (value) {
+ uint32_t value_size = pat->value_size;
+ if (value_size) {
+ byte *v = (byte *)sis_get(ctx, pat, id);
+ if (v) {
+ if (pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) { v += sizeof(sis_node); }
+ switch ((flags & GRN_OBJ_SET_MASK)) {
+ case GRN_OBJ_SET :
+ grn_memcpy(v, value, value_size);
+ return GRN_SUCCESS;
+ case GRN_OBJ_INCR :
+ switch (value_size) {
+ case sizeof(int32_t) :
+ *((int32_t *)v) += *((int32_t *)value);
+ return GRN_SUCCESS;
+ case sizeof(int64_t) :
+ *((int64_t *)v) += *((int64_t *)value);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ break;
+ case GRN_OBJ_DECR :
+ switch (value_size) {
+ case sizeof(int32_t) :
+ *((int32_t *)v) -= *((int32_t *)value);
+ return GRN_SUCCESS;
+ case sizeof(int64_t) :
+ *((int64_t *)v) -= *((int64_t *)value);
+ return GRN_SUCCESS;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+ break;
+ default :
+ // todo : support other types.
+ return GRN_INVALID_ARGUMENT;
+ }
+ } else {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ }
+ return GRN_INVALID_ARGUMENT;
+}
+
+grn_rc
+grn_pat_info(grn_ctx *ctx, grn_pat *pat, int *key_size, unsigned int *flags,
+ grn_encoding *encoding, unsigned int *n_entries, unsigned int *file_size)
+{
+ grn_rc rc;
+ ERRCLR(NULL);
+ if (!pat) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_pat_error_if_truncated(ctx, pat);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (key_size) { *key_size = pat->key_size; }
+ if (flags) { *flags = pat->obj.header.flags; }
+ if (encoding) { *encoding = pat->encoding; }
+ if (n_entries) { *n_entries = pat->header->n_entries; }
+ if (file_size) {
+ uint64_t tmp = 0;
+ if ((rc = grn_io_size(ctx, pat->io, &tmp))) {
+ return rc;
+ }
+ *file_size = (unsigned int) tmp; /* FIXME: inappropriate cast */
+ }
+ return GRN_SUCCESS;
+}
+
+int
+grn_pat_delete_with_sis(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ grn_table_delete_optarg *optarg)
+{
+ int level = 0, shared;
+ const char *key = NULL, *_key;
+ sis_node *sp, *ss = NULL, *si;
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return 0;
+ }
+ si = sis_at(ctx, pat, id);
+ while (id) {
+ pat_node *rn;
+ uint32_t key_size;
+ if ((si && si->children && si->children != id) ||
+ (optarg && optarg->func &&
+ !optarg->func(ctx, (grn_obj *)pat, id, optarg->func_arg))) {
+ break;
+ }
+ PAT_AT(pat, id, rn);
+ if (!(_key = (char *)pat_node_get_key(ctx, pat, rn))) { return 0; }
+ if (_key == key) {
+ shared = 1;
+ } else {
+ key = _key;
+ shared = 0;
+ }
+ key_size = PAT_LEN(rn);
+ if (key && key_size) { _grn_pat_del(ctx, pat, key, key_size, shared, NULL); }
+ if (si) {
+ grn_id *p, sid;
+ uint32_t lkey = 0;
+ if ((*key & 0x80) && chop(ctx, pat, &key, key + key_size, &lkey)) {
+ if ((sid = grn_pat_get(ctx, pat, key, key_size - lkey, NULL)) &&
+ (ss = sis_at(ctx, pat, sid))) {
+ for (p = &ss->children; *p && *p != sid; p = &sp->sibling) {
+ if (*p == id) {
+ *p = si->sibling;
+ break;
+ }
+ if (!(sp = sis_at(ctx, pat, *p))) { break; }
+ }
+ }
+ } else {
+ sid = GRN_ID_NIL;
+ }
+ si->sibling = 0;
+ si->children = 0;
+ id = sid;
+ si = ss;
+ } else {
+ id = GRN_ID_NIL;
+ }
+ level++;
+ }
+ if (level) {
+ uint32_t lkey = 0;
+ while (id && key) {
+ uint32_t key_size;
+ if (_grn_pat_key(ctx, pat, id, &key_size) != key) { break; }
+ {
+ pat_node *rn;
+ PAT_AT(pat, id, rn);
+ if (!rn) { break; }
+ if (lkey) {
+ rn->key = lkey;
+ } else {
+ pat_node_set_key(ctx, pat, rn, (uint8_t *)key, key_size);
+ lkey = rn->key;
+ }
+ }
+ {
+ const char *end = key + key_size;
+ if (!((*key & 0x80) && chop(ctx, pat, &key, end, &lkey))) { break; }
+ id = grn_pat_get(ctx, pat, key, end - key, NULL);
+ }
+ }
+ }
+ return level;
+}
+
+grn_id
+grn_pat_next(grn_ctx *ctx, grn_pat *pat, grn_id id)
+{
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ while (++id <= pat->header->curr_rec) {
+ uint32_t key_size;
+ const char *key = _grn_pat_key(ctx, pat, id, &key_size);
+ if (id == grn_pat_get(ctx, pat, key, key_size, NULL)) {
+ return id;
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_pat_at(grn_ctx *ctx, grn_pat *pat, grn_id id)
+{
+ uint32_t key_size;
+ const char *key = _grn_pat_key(ctx, pat, id, &key_size);
+ if (key && (id == _grn_pat_get(ctx, pat, key, key_size, NULL))) { return id; }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_pat_curr_id(grn_ctx *ctx, grn_pat *pat)
+{
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+ return pat->header->curr_rec;
+}
+
+int
+grn_pat_scan(grn_ctx *ctx, grn_pat *pat, const char *str, unsigned int str_len,
+ grn_pat_scan_hit *sh, unsigned int sh_size, const char **rest)
+{
+ int n = 0;
+ grn_id tid;
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return 0;
+ }
+ if (pat->normalizer) {
+ int flags =
+ GRN_STRING_REMOVE_BLANK |
+ GRN_STRING_WITH_TYPES |
+ GRN_STRING_WITH_CHECKS;
+ grn_obj *nstr = grn_string_open(ctx, str, str_len,
+ pat->normalizer, flags);
+ if (nstr) {
+ const short *cp = grn_string_get_checks(ctx, nstr);
+ const unsigned char *tp = grn_string_get_types(ctx, nstr);
+ unsigned int offset = 0, offset0 = 0;
+ unsigned int normalized_length_in_bytes;
+ const char *sp, *se;
+ grn_string_get_normalized(ctx, nstr, &sp, &normalized_length_in_bytes,
+ NULL);
+ se = sp + normalized_length_in_bytes;
+ while (n < (int) sh_size) {
+ if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
+ const char *key;
+ uint32_t len;
+ int first_key_char_len;
+ key = _grn_pat_key(ctx, pat, tid, &len);
+ sh[n].id = tid;
+ sh[n].offset = (*cp > 0) ? offset : offset0;
+ first_key_char_len = grn_charlen(ctx, key, key + len);
+ if (sh[n].offset > 0 &&
+ GRN_CHAR_IS_BLANK(tp[-1]) &&
+ ((first_key_char_len == 1 && key[0] != ' ') ||
+ first_key_char_len > 1)){
+ /* Remove leading spaces. */
+ const char *original_str = str + sh[n].offset;
+ while (grn_charlen(ctx, original_str, str + str_len) == 1 &&
+ original_str[0] == ' ') {
+ original_str++;
+ sh[n].offset++;
+ }
+ }
+ {
+ grn_bool blank_in_alnum = GRN_FALSE;
+ const unsigned char *start_tp = tp;
+ const unsigned char *blank_in_alnum_check_tp;
+ while (len--) {
+ if (*cp > 0) { offset0 = offset; offset += *cp; tp++; }
+ sp++; cp++;
+ }
+ sh[n].length = offset - sh[n].offset;
+ for (blank_in_alnum_check_tp = start_tp + 1;
+ blank_in_alnum_check_tp < tp;
+ blank_in_alnum_check_tp++) {
+#define GRN_CHAR_IS_ALNUM(char_type) \
+ (GRN_CHAR_TYPE(char_type) == GRN_CHAR_ALPHA || \
+ GRN_CHAR_TYPE(char_type) == GRN_CHAR_DIGIT)
+ if (GRN_CHAR_IS_BLANK(blank_in_alnum_check_tp[0]) &&
+ GRN_CHAR_IS_ALNUM(blank_in_alnum_check_tp[-1]) &&
+ (blank_in_alnum_check_tp + 1) < tp &&
+ GRN_CHAR_IS_ALNUM(blank_in_alnum_check_tp[1])) {
+ blank_in_alnum = GRN_TRUE;
+ }
+#undef GRN_CHAR_IS_ALNUM
+ }
+ if (!blank_in_alnum) {
+ n++;
+ }
+ }
+ } else {
+ if (*cp > 0) { offset0 = offset; offset += *cp; tp++; }
+ do {
+ sp++; cp++;
+ } while (sp < se && !*cp);
+ }
+ if (se <= sp) { offset = str_len; break; }
+ }
+ if (rest) {
+ grn_string_get_original(ctx, nstr, rest, NULL);
+ *rest += offset;
+ }
+ grn_obj_close(ctx, nstr);
+ } else {
+ n = -1;
+ if (rest) { *rest = str; }
+ }
+ } else {
+ uint32_t len;
+ const char *sp, *se = str + str_len;
+ for (sp = str; sp < se && n < (int) sh_size; sp += len) {
+ if ((tid = grn_pat_lcp_search(ctx, pat, sp, se - sp))) {
+ _grn_pat_key(ctx, pat, tid, &len);
+ sh[n].id = tid;
+ sh[n].offset = sp - str;
+ sh[n].length = len;
+ n++;
+ } else {
+ len = grn_charlen(ctx, sp, se);
+ }
+ if (!len) { break; }
+ }
+ if (rest) { *rest = sp; }
+ }
+ return n;
+}
+
+#define INITIAL_SIZE 512
+
+inline static void
+push(grn_pat_cursor *c, grn_id id, uint16_t check)
+{
+ grn_ctx *ctx = c->ctx;
+ grn_pat_cursor_entry *se;
+ if (c->size <= c->sp) {
+ if (c->ss) {
+ uint32_t size = c->size * 4;
+ grn_pat_cursor_entry *ss = GRN_REALLOC(c->ss, size);
+ if (!ss) { return; /* give up */ }
+ c->ss = ss;
+ c->size = size;
+ } else {
+ if (!(c->ss = GRN_MALLOC(sizeof(grn_pat_cursor_entry) * INITIAL_SIZE))) {
+ return; /* give up */
+ }
+ c->size = INITIAL_SIZE;
+ }
+ }
+ se = &c->ss[c->sp++];
+ se->id = id;
+ se->check = check;
+}
+
+inline static grn_pat_cursor_entry *
+pop(grn_pat_cursor *c)
+{
+ return c->sp ? &c->ss[--c->sp] : NULL;
+}
+
+static grn_id
+grn_pat_cursor_next_by_id(grn_ctx *ctx, grn_pat_cursor *c)
+{
+ grn_pat *pat = c->pat;
+ int dir = (c->obj.header.flags & GRN_CURSOR_DESCENDING) ? -1 : 1;
+ while (c->curr_rec != c->tail) {
+ c->curr_rec += dir;
+ if (pat->header->n_garbages) {
+ uint32_t key_size;
+ const void *key = _grn_pat_key(ctx, pat, c->curr_rec, &key_size);
+ if (_grn_pat_get(ctx, pat, key, key_size, NULL) != c->curr_rec) {
+ continue;
+ }
+ }
+ c->rest--;
+ return c->curr_rec;
+ }
+ return GRN_ID_NIL;
+}
+
+grn_id
+grn_pat_cursor_next(grn_ctx *ctx, grn_pat_cursor *c)
+{
+ pat_node *node;
+ grn_pat_cursor_entry *se;
+ if (!c->rest) { return GRN_ID_NIL; }
+ if ((c->obj.header.flags & GRN_CURSOR_BY_ID)) {
+ return grn_pat_cursor_next_by_id(ctx, c);
+ }
+ while ((se = pop(c))) {
+ grn_id id = se->id;
+ int check = se->check, ch;
+ while (id) {
+ PAT_AT(c->pat, id, node);
+ if (!node) {
+ break;
+ }
+ ch = PAT_CHK(node);
+ if (ch > check) {
+ if (c->obj.header.flags & GRN_CURSOR_DESCENDING) {
+ push(c, node->lr[0], ch);
+ id = node->lr[1];
+ } else {
+ push(c, node->lr[1], ch);
+ id = node->lr[0];
+ }
+ check = ch;
+ continue;
+ } else {
+ if (id == c->tail) {
+ c->sp = 0;
+ } else {
+ if (!c->curr_rec && c->tail) {
+ uint32_t lmin, lmax;
+ pat_node *nmin, *nmax;
+ const uint8_t *kmin, *kmax;
+ if (c->obj.header.flags & GRN_CURSOR_DESCENDING) {
+ PAT_AT(c->pat, c->tail, nmin);
+ PAT_AT(c->pat, id, nmax);
+ } else {
+ PAT_AT(c->pat, id, nmin);
+ PAT_AT(c->pat, c->tail, nmax);
+ }
+ lmin = PAT_LEN(nmin);
+ lmax = PAT_LEN(nmax);
+ kmin = pat_node_get_key(ctx, c->pat, nmin);
+ kmax = pat_node_get_key(ctx, c->pat, nmax);
+ if ((lmin < lmax) ?
+ (memcmp(kmin, kmax, lmin) > 0) :
+ (memcmp(kmin, kmax, lmax) >= 0)) {
+ c->sp = 0;
+ break;
+ }
+ }
+ }
+ c->curr_rec = id;
+ c->rest--;
+ return id;
+ }
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+void
+grn_pat_cursor_close(grn_ctx *ctx, grn_pat_cursor *c)
+{
+ GRN_ASSERT(c->ctx == ctx);
+ if (c->ss) { GRN_FREE(c->ss); }
+ GRN_FREE(c);
+}
+
+inline static int
+bitcmp(const void *s1, const void *s2, int offset, int length)
+{
+ int r, rest = length + (offset & 7) - 8, bl = offset >> 3, mask = 0xff >> (offset & 7);
+ unsigned char *a = (unsigned char *)s1 + bl, *b = (unsigned char *)s2 + bl;
+ if (rest <= 0) {
+ mask &= 0xff << -rest;
+ return (*a & mask) - (*b & mask);
+ }
+ if ((r = (*a & mask) - (*b & mask))) { return r; }
+ a++; b++;
+ if ((bl = rest >> 3)) {
+ if ((r = memcmp(a, b, bl))) { return r; }
+ a += bl; b += bl;
+ }
+ mask = 0xff << (8 - (rest & 7));
+ return (*a & mask) - (*b & mask);
+}
+
+inline static grn_rc
+set_cursor_prefix(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ const void *key, uint32_t key_size, int flags)
+{
+ int c0 = -1, ch;
+ const uint8_t *k;
+ uint32_t len, byte_len;
+ grn_id id;
+ pat_node *node;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ if (flags & GRN_CURSOR_SIZE_BY_BIT) {
+ len = key_size * 2;
+ byte_len = key_size >> 3;
+ } else {
+ len = key_size * 16;
+ byte_len = key_size;
+ }
+ KEY_ENCODE(pat, keybuf, key, byte_len);
+ PAT_AT(pat, 0, node);
+ id = node->lr[1];
+ while (id) {
+ PAT_AT(pat, id, node);
+ if (!node) { return GRN_FILE_CORRUPT; }
+ ch = PAT_CHK(node);
+ if (c0 < ch && ch < (int) len - 1) {
+ if (ch & 1) {
+ id = (ch + 1 < (int) len) ? node->lr[1] : node->lr[0];
+ } else {
+ id = node->lr[nth_bit((uint8_t *)key, ch, len)];
+ }
+ c0 = ch;
+ continue;
+ }
+ if (!(k = pat_node_get_key(ctx, pat, node))) { break; }
+ if (PAT_LEN(node) < byte_len) { break; }
+ if ((flags & GRN_CURSOR_SIZE_BY_BIT)
+ ? !bitcmp(k, key, 0, key_size)
+ : !memcmp(k, key, key_size)) {
+ if (c0 < ch) {
+ if (flags & GRN_CURSOR_DESCENDING) {
+ if ((ch > (int) len - 1) || !(flags & GRN_CURSOR_GT)) {
+ push(c, node->lr[0], ch);
+ }
+ push(c, node->lr[1], ch);
+ } else {
+ push(c, node->lr[1], ch);
+ if ((ch > (int) len - 1) || !(flags & GRN_CURSOR_GT)) {
+ push(c, node->lr[0], ch);
+ }
+ }
+ } else {
+ if (PAT_LEN(node) * 16 > len || !(flags & GRN_CURSOR_GT)) {
+ push(c, id, ch);
+ }
+ }
+ }
+ break;
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+set_cursor_near(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ uint32_t min_size, const void *key, int flags)
+{
+ grn_id id;
+ pat_node *node;
+ const uint8_t *k;
+ int r, check = -1, ch;
+ uint32_t min = min_size * 16;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ KEY_ENCODE(pat, keybuf, key, pat->key_size);
+ PAT_AT(pat, 0, node);
+ for (id = node->lr[1]; id;) {
+ PAT_AT(pat, id, node);
+ if (!node) { return GRN_FILE_CORRUPT; }
+ ch = PAT_CHK(node);
+ if (ch <= check) {
+ if (check >= (int) min) { push(c, id, check); }
+ break;
+ }
+ if ((check += 2) < ch) {
+ if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
+ if ((r = bitcmp(key, k, check >> 1, (ch - check) >> 1))) {
+ if (ch >= (int) min) {
+ push(c, node->lr[1], ch);
+ push(c, node->lr[0], ch);
+ }
+ break;
+ }
+ }
+ check = ch;
+ if (nth_bit((uint8_t *)key, check, pat->key_size)) {
+ if (check >= (int) min) { push(c, node->lr[0], check); }
+ id = node->lr[1];
+ } else {
+ if (check >= (int) min) { push(c, node->lr[1], check); }
+ id = node->lr[0];
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+set_cursor_common_prefix(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ uint32_t min_size, const void *key, uint32_t key_size, int flags)
+{
+ grn_id id;
+ pat_node *node;
+ const uint8_t *k;
+ int check = -1, ch;
+ uint32_t len = key_size * 16;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ PAT_AT(pat, 0, node);
+ for (id = node->lr[1]; id;) {
+ PAT_AT(pat, id, node);
+ if (!node) { return GRN_FILE_CORRUPT; }
+ ch = PAT_CHK(node);
+ if (ch <= check) {
+ if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
+ {
+ uint32_t l = PAT_LEN(node);
+ if (min_size <= l && l <= key_size) {
+ if (!memcmp(key, k, l)) { push(c, id, check); }
+ }
+ }
+ break;
+ }
+ check = ch;
+ if ((int) len <= check) { break; }
+ if (check & 1) {
+ grn_id id0 = node->lr[0];
+ pat_node *node0;
+ PAT_AT(pat, id0, node0);
+ if (!node0) { return GRN_FILE_CORRUPT; }
+ if (!(k = pat_node_get_key(ctx, pat, node0))) { return GRN_FILE_CORRUPT; }
+ {
+ uint32_t l = PAT_LEN(node0);
+ if (memcmp(key, k, l)) { break; }
+ if (min_size <= l) {
+ push(c, id0, check);
+ }
+ }
+ id = node->lr[1];
+ } else {
+ id = node->lr[nth_bit((uint8_t *)key, check, len)];
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+set_cursor_ascend(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ const void *key, uint32_t key_size, int flags)
+{
+ grn_id id;
+ pat_node *node;
+ const uint8_t *k;
+ int r, check = -1, ch, c2;
+ uint32_t len = key_size * 16;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ PAT_AT(pat, 0, node);
+ for (id = node->lr[1]; id;) {
+ PAT_AT(pat, id, node);
+ if (!node) { return GRN_FILE_CORRUPT; }
+ ch = PAT_CHK(node);
+ if (ch <= check) {
+ if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
+ {
+ uint32_t l = PAT_LEN(node);
+ if (l == key_size) {
+ if (flags & GRN_CURSOR_GT) {
+ if (memcmp(key, k, l) < 0) { push(c, id, check); }
+ } else {
+ if (memcmp(key, k, l) <= 0) { push(c, id, check); }
+ }
+ } else if (l < key_size) {
+ if (memcmp(key, k, l) < 0) { push(c, id, check); }
+ } else {
+ if (memcmp(key, k, key_size) <= 0) { push(c, id, check); }
+ }
+ }
+ break;
+ }
+ c2 = (int) len < ch ? (int) len : ch;
+ if ((check += 2) < c2) {
+ if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
+ if ((r = bitcmp(key, k, check >> 1, ((c2 + 1) >> 1) - (check >> 1)))) {
+ if (r < 0) {
+ push(c, node->lr[1], ch);
+ push(c, node->lr[0], ch);
+ }
+ break;
+ }
+ }
+ check = ch;
+ if ((int) len <= check) {
+ push(c, node->lr[1], ch);
+ push(c, node->lr[0], ch);
+ break;
+ }
+ if (check & 1) {
+ if (check + 1 < (int) len) {
+ id = node->lr[1];
+ } else {
+ push(c, node->lr[1], check);
+ id = node->lr[0];
+ }
+ } else {
+ if (nth_bit((uint8_t *)key, check, len)) {
+ id = node->lr[1];
+ } else {
+ push(c, node->lr[1], check);
+ id = node->lr[0];
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+set_cursor_descend(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ const void *key, uint32_t key_size, int flags)
+{
+ grn_id id;
+ pat_node *node;
+ const uint8_t *k;
+ int r, check = -1, ch, c2;
+ uint32_t len = key_size * 16;
+ uint8_t keybuf[MAX_FIXED_KEY_SIZE];
+ KEY_ENCODE(pat, keybuf, key, key_size);
+ PAT_AT(pat, 0, node);
+ for (id = node->lr[1]; id;) {
+ PAT_AT(pat, id, node);
+ if (!node) { return GRN_FILE_CORRUPT; }
+ ch = PAT_CHK(node);
+ if (ch <= check) {
+ if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
+ {
+ uint32_t l = PAT_LEN(node);
+ if (l <= key_size) {
+ if ((flags & GRN_CURSOR_LT) && l == key_size) {
+ if (memcmp(key, k, l) > 0) { push(c, id, check); }
+ } else {
+ if (memcmp(key, k, l) >= 0) { push(c, id, check); }
+ }
+ } else {
+ if (memcmp(key, k, key_size) > 0) { push(c, id, check); }
+ }
+ }
+ break;
+ }
+ c2 = (int) len < ch ? (int) len : ch;
+ if ((check += 2) < c2) {
+ if (!(k = pat_node_get_key(ctx, pat, node))) { return GRN_FILE_CORRUPT; }
+ if ((r = bitcmp(key, k, check >> 1, ((c2 + 1) >> 1) - (check >> 1)))) {
+ if (r >= 0) {
+ push(c, node->lr[0], ch);
+ push(c, node->lr[1], ch);
+ }
+ break;
+ }
+ }
+ check = ch;
+ if ((int) len <= check) { break; }
+ if (check & 1) {
+ if (check + 1 < (int) len) {
+ push(c, node->lr[0], check);
+ id = node->lr[1];
+ } else {
+ id = node->lr[0];
+ }
+ } else {
+ if (nth_bit((uint8_t *)key, check, len)) {
+ push(c, node->lr[0], check);
+ id = node->lr[1];
+ } else {
+ id = node->lr[0];
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_pat_cursor *
+grn_pat_cursor_open_by_id(grn_ctx *ctx, grn_pat *pat,
+ const void *min, uint32_t min_size,
+ const void *max, uint32_t max_size,
+ int offset, int limit, int flags)
+{
+ int dir;
+ grn_pat_cursor *c;
+ if (!pat || !ctx) { return NULL; }
+ if (!(c = GRN_MALLOCN(grn_pat_cursor, 1))) { return NULL; }
+ GRN_DB_OBJ_SET_TYPE(c, GRN_CURSOR_TABLE_PAT_KEY);
+ c->pat = pat;
+ c->ctx = ctx;
+ c->obj.header.flags = flags;
+ c->obj.header.domain = GRN_ID_NIL;
+ c->size = 0;
+ c->sp = 0;
+ c->ss = NULL;
+ c->tail = 0;
+ if (flags & GRN_CURSOR_DESCENDING) {
+ dir = -1;
+ if (max) {
+ if (!(c->curr_rec = grn_pat_get(ctx, pat, max, max_size, NULL))) {
+ c->tail = GRN_ID_NIL;
+ goto exit;
+ }
+ if (!(flags & GRN_CURSOR_LT)) { c->curr_rec++; }
+ } else {
+ c->curr_rec = pat->header->curr_rec + 1;
+ }
+ if (min) {
+ if (!(c->tail = grn_pat_get(ctx, pat, min, min_size, NULL))) {
+ c->curr_rec = GRN_ID_NIL;
+ goto exit;
+ }
+ if ((flags & GRN_CURSOR_GT)) { c->tail++; }
+ } else {
+ c->tail = GRN_ID_NIL + 1;
+ }
+ if (c->curr_rec < c->tail) { c->tail = c->curr_rec; }
+ } else {
+ dir = 1;
+ if (min) {
+ if (!(c->curr_rec = grn_pat_get(ctx, pat, min, min_size, NULL))) {
+ c->tail = GRN_ID_NIL;
+ goto exit;
+ }
+ if (!(flags & GRN_CURSOR_GT)) { c->curr_rec--; }
+ } else {
+ c->curr_rec = GRN_ID_NIL;
+ }
+ if (max) {
+ if (!(c->tail = grn_pat_get(ctx, pat, max, max_size, NULL))) {
+ c->curr_rec = GRN_ID_NIL;
+ goto exit;
+ }
+ if ((flags & GRN_CURSOR_LT)) { c->tail--; }
+ } else {
+ c->tail = pat->header->curr_rec;
+ }
+ if (c->tail < c->curr_rec) { c->tail = c->curr_rec; }
+ }
+ if (pat->header->n_garbages) {
+ while (offset && c->curr_rec != c->tail) {
+ uint32_t key_size;
+ const void *key;
+ c->curr_rec += dir;
+ key = _grn_pat_key(ctx, pat, c->curr_rec, &key_size);
+ if (_grn_pat_get(ctx, pat, key, key_size, NULL) == c->curr_rec) {
+ offset--;
+ }
+ }
+ } else {
+ if ((int) (dir * (c->tail - c->curr_rec)) < offset) {
+ c->curr_rec = c->tail;
+ } else {
+ c->curr_rec += dir * offset;
+ }
+ }
+ c->rest = (limit < 0) ? GRN_ID_MAX : limit;
+exit :
+ return c;
+}
+
+static grn_rc set_cursor_rk(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ const void *key, uint32_t key_size, int flags);
+
+grn_pat_cursor *
+grn_pat_cursor_open(grn_ctx *ctx, grn_pat *pat,
+ const void *min, uint32_t min_size,
+ const void *max, uint32_t max_size,
+ int offset, int limit, int flags)
+{
+ grn_id id;
+ pat_node *node;
+ grn_pat_cursor *c;
+ if (!pat || !ctx) { return NULL; }
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return NULL;
+ }
+ if ((flags & GRN_CURSOR_BY_ID)) {
+ return grn_pat_cursor_open_by_id(ctx, pat, min, min_size, max, max_size,
+ offset, limit, flags);
+ }
+ if (!(c = GRN_MALLOCN(grn_pat_cursor, 1))) { return NULL; }
+ GRN_DB_OBJ_SET_TYPE(c, GRN_CURSOR_TABLE_PAT_KEY);
+ c->pat = pat;
+ c->ctx = ctx;
+ c->size = 0;
+ c->sp = 0;
+ c->ss = NULL;
+ c->tail = 0;
+ c->rest = GRN_ID_MAX;
+ c->curr_rec = GRN_ID_NIL;
+ c->obj.header.domain = GRN_ID_NIL;
+ if (flags & GRN_CURSOR_PREFIX) {
+ if (max && max_size) {
+ if ((pat->obj.header.flags & GRN_OBJ_KEY_VAR_SIZE)) {
+ set_cursor_common_prefix(ctx, pat, c, min_size, max, max_size, flags);
+ } else {
+ set_cursor_near(ctx, pat, c, min_size, max, flags);
+ }
+ goto exit;
+ } else {
+ if (min && min_size) {
+ if (flags & GRN_CURSOR_RK) {
+ set_cursor_rk(ctx, pat, c, min, min_size, flags);
+ } else {
+ set_cursor_prefix(ctx, pat, c, min, min_size, flags);
+ }
+ goto exit;
+ }
+ }
+ }
+ if (flags & GRN_CURSOR_DESCENDING) {
+ if (min && min_size) {
+ set_cursor_ascend(ctx, pat, c, min, min_size, flags);
+ c->obj.header.flags = GRN_CURSOR_ASCENDING;
+ c->tail = grn_pat_cursor_next(ctx, c);
+ c->sp = 0;
+ if (!c->tail) { goto exit; }
+ }
+ if (max && max_size) {
+ set_cursor_descend(ctx, pat, c, max, max_size, flags);
+ } else {
+ PAT_AT(pat, 0, node);
+ if (!node) {
+ grn_pat_cursor_close(ctx, c);
+ return NULL;
+ }
+ if ((id = node->lr[1])) {
+ PAT_AT(pat, id, node);
+ if (node) {
+ int ch = PAT_CHK(node);
+ push(c, node->lr[0], ch);
+ push(c, node->lr[1], ch);
+ }
+ }
+ }
+ } else {
+ if (max && max_size) {
+ set_cursor_descend(ctx, pat, c, max, max_size, flags);
+ c->obj.header.flags = GRN_CURSOR_DESCENDING;
+ c->tail = grn_pat_cursor_next(ctx, c);
+ c->sp = 0;
+ if (!c->tail) { goto exit; }
+ }
+ if (min && min_size) {
+ set_cursor_ascend(ctx, pat, c, min, min_size, flags);
+ } else {
+ PAT_AT(pat, 0, node);
+ if (!node) {
+ grn_pat_cursor_close(ctx, c);
+ return NULL;
+ }
+ if ((id = node->lr[1])) {
+ PAT_AT(pat, id, node);
+ if (node) {
+ int ch = PAT_CHK(node);
+ push(c, node->lr[1], ch);
+ push(c, node->lr[0], ch);
+ }
+ }
+ }
+ }
+exit :
+ c->obj.header.flags = flags;
+ c->curr_rec = GRN_ID_NIL;
+ while (offset--) { grn_pat_cursor_next(ctx, c); }
+ c->rest = (limit < 0) ? GRN_ID_MAX : limit;
+ return c;
+}
+
+int
+grn_pat_cursor_get_key(grn_ctx *ctx, grn_pat_cursor *c, void **key)
+{
+ *key = c->curr_key;
+ return grn_pat_get_key(ctx, c->pat, c->curr_rec, *key, GRN_TABLE_MAX_KEY_SIZE);
+}
+
+int
+grn_pat_cursor_get_value(grn_ctx *ctx, grn_pat_cursor *c, void **value)
+{
+ int value_size = (int)c->pat->value_size;
+ if (value_size) {
+ byte *v = (byte *)sis_at(ctx, c->pat, c->curr_rec);
+ if (v) {
+ if (c->pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ *value = v + sizeof(sis_node);
+ } else {
+ *value = v;
+ }
+ } else {
+ *value = NULL;
+ }
+ }
+ return value_size;
+}
+
+int
+grn_pat_cursor_get_key_value(grn_ctx *ctx, grn_pat_cursor *c,
+ void **key, uint32_t *key_size, void **value)
+{
+ int value_size = (int)c->pat->value_size;
+ if (key_size) {
+ *key_size = (uint32_t) grn_pat_get_key(ctx, c->pat, c->curr_rec, c->curr_key,
+ GRN_TABLE_MAX_KEY_SIZE);
+ if (key) { *key = c->curr_key; }
+ }
+ if (value && value_size) {
+ byte *v = (byte *)sis_at(ctx, c->pat, c->curr_rec);
+ if (v) {
+ if (c->pat->obj.header.flags & GRN_OBJ_KEY_WITH_SIS) {
+ *value = v + sizeof(sis_node);
+ } else {
+ *value = v;
+ }
+ } else {
+ *value = NULL;
+ }
+ }
+ return value_size;
+}
+
+grn_rc
+grn_pat_cursor_set_value(grn_ctx *ctx, grn_pat_cursor *c,
+ const void *value, int flags)
+{
+ return grn_pat_set_value(ctx, c->pat, c->curr_rec, value, flags);
+}
+
+grn_rc
+grn_pat_cursor_delete(grn_ctx *ctx, grn_pat_cursor *c,
+ grn_table_delete_optarg *optarg)
+{
+ return grn_pat_delete_by_id(ctx, c->pat, c->curr_rec, optarg);
+}
+
+void
+grn_pat_check(grn_ctx *ctx, grn_pat *pat)
+{
+ char buf[8];
+ struct grn_pat_header *h = pat->header;
+ if (grn_pat_error_if_truncated(ctx, pat) != GRN_SUCCESS) {
+ return;
+ }
+ GRN_OUTPUT_ARRAY_OPEN("RESULT", 1);
+ GRN_OUTPUT_MAP_OPEN("SUMMARY", 23);
+ GRN_OUTPUT_CSTR("flags");
+ grn_itoh(h->flags, buf, 8);
+ GRN_OUTPUT_STR(buf, 8);
+ GRN_OUTPUT_CSTR("key size");
+ GRN_OUTPUT_INT64(h->key_size);
+ GRN_OUTPUT_CSTR("value_size");
+ GRN_OUTPUT_INT64(h->value_size);
+ GRN_OUTPUT_CSTR("tokenizer");
+ GRN_OUTPUT_INT64(h->tokenizer);
+ GRN_OUTPUT_CSTR("normalizer");
+ GRN_OUTPUT_INT64(h->normalizer);
+ GRN_OUTPUT_CSTR("n_entries");
+ GRN_OUTPUT_INT64(h->n_entries);
+ GRN_OUTPUT_CSTR("curr_rec");
+ GRN_OUTPUT_INT64(h->curr_rec);
+ GRN_OUTPUT_CSTR("curr_key");
+ GRN_OUTPUT_INT64(h->curr_key);
+ GRN_OUTPUT_CSTR("curr_del");
+ GRN_OUTPUT_INT64(h->curr_del);
+ GRN_OUTPUT_CSTR("curr_del2");
+ GRN_OUTPUT_INT64(h->curr_del2);
+ GRN_OUTPUT_CSTR("curr_del3");
+ GRN_OUTPUT_INT64(h->curr_del3);
+ GRN_OUTPUT_CSTR("n_garbages");
+ GRN_OUTPUT_INT64(h->n_garbages);
+ GRN_OUTPUT_MAP_CLOSE();
+ GRN_OUTPUT_ARRAY_CLOSE();
+}
+
+/* utilities */
+void
+grn_p_pat_node(grn_ctx *ctx, grn_pat *pat, pat_node *node)
+{
+ uint8_t *key = NULL;
+
+ if (!node) {
+ printf("#<pat_node:(null)>\n");
+ return;
+ }
+
+ if (PAT_IMD(node)) {
+ key = (uint8_t *)&(node->key);
+ } else {
+ KEY_AT(pat, node->key, key, 0);
+ }
+
+ printf("#<pat_node:%p "
+ "left:%u "
+ "right:%u "
+ "deleting:%s "
+ "immediate:%s "
+ "length:%u "
+ "nth-byte:%u "
+ "nth-bit:%u "
+ "terminated:%s "
+ "key:<%.*s>"
+ ">\n",
+ node,
+ node->lr[0],
+ node->lr[1],
+ PAT_DEL(node) ? "true" : "false",
+ PAT_IMD(node) ? "true" : "false",
+ PAT_LEN(node),
+ PAT_CHK(node) >> 4,
+ (PAT_CHK(node) >> 1) & 0x7,
+ (PAT_CHK(node) & 0x1) ? "true" : "false",
+ PAT_LEN(node),
+ (char *)key);
+}
+
+static void
+grn_pat_inspect_check(grn_ctx *ctx, grn_obj *buf, int check)
+{
+ GRN_TEXT_PUTS(ctx, buf, "{");
+ grn_text_lltoa(ctx, buf, check >> 4);
+ GRN_TEXT_PUTS(ctx, buf, ",");
+ grn_text_lltoa(ctx, buf, (check >> 1) & 7);
+ GRN_TEXT_PUTS(ctx, buf, ",");
+ grn_text_lltoa(ctx, buf, check & 1);
+ GRN_TEXT_PUTS(ctx, buf, "}");
+}
+
+static void
+grn_pat_inspect_node(grn_ctx *ctx, grn_pat *pat, grn_id id, int check,
+ grn_obj *key_buf, int indent, const char *prefix,
+ grn_obj *buf)
+{
+ pat_node *node = NULL;
+ int i, c;
+
+ PAT_AT(pat, id, node);
+ c = PAT_CHK(node);
+
+ for (i = 0; i < indent; i++) {
+ GRN_TEXT_PUTC(ctx, buf, ' ');
+ }
+ GRN_TEXT_PUTS(ctx, buf, prefix);
+ grn_text_lltoa(ctx, buf, id);
+ grn_pat_inspect_check(ctx, buf, c);
+
+ if (c > check) {
+ GRN_TEXT_PUTS(ctx, buf, "\n");
+ grn_pat_inspect_node(ctx, pat, node->lr[0], c, key_buf,
+ indent + 2, "L:", buf);
+ GRN_TEXT_PUTS(ctx, buf, "\n");
+ grn_pat_inspect_node(ctx, pat, node->lr[1], c, key_buf,
+ indent + 2, "R:", buf);
+ } else if (id) {
+ int key_size;
+ uint8_t *key;
+
+ key_size = PAT_LEN(node);
+ GRN_BULK_REWIND(key_buf);
+ grn_bulk_space(ctx, key_buf, key_size);
+ grn_pat_get_key(ctx, pat, id, GRN_BULK_HEAD(key_buf), key_size);
+ GRN_TEXT_PUTS(ctx, buf, "(");
+ grn_inspect(ctx, buf, key_buf);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ key = pat_node_get_key(ctx, pat, node);
+ for (i = 0; i < key_size; i++) {
+ int j;
+ uint8_t byte = key[i];
+ if (i != 0) {
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ }
+ for (j = 0; j < 8; j++) {
+ grn_text_lltoa(ctx, buf, (byte >> (7 - j)) & 1);
+ }
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+ }
+}
+
+void
+grn_pat_inspect_nodes(grn_ctx *ctx, grn_pat *pat, grn_obj *buf)
+{
+ pat_node *node;
+ grn_obj key_buf;
+
+ GRN_TEXT_PUTS(ctx, buf, "{");
+ PAT_AT(pat, GRN_ID_NIL, node);
+ if (node->lr[1]) {
+ GRN_TEXT_PUTS(ctx, buf, "\n");
+ GRN_OBJ_INIT(&key_buf, GRN_BULK, 0, pat->obj.header.domain);
+ grn_pat_inspect_node(ctx, pat, node->lr[1], -1, &key_buf, 0, "", buf);
+ GRN_OBJ_FIN(ctx, &key_buf);
+ GRN_TEXT_PUTS(ctx, buf, "\n");
+ }
+ GRN_TEXT_PUTS(ctx, buf, "}");
+}
+
+static void
+grn_pat_cursor_inspect_entries(grn_ctx *ctx, grn_pat_cursor *c, grn_obj *buf)
+{
+ uint i;
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ for (i = 0; i < c->sp; i++) {
+ grn_pat_cursor_entry *e = c->ss + i;
+ if (i != 0) {
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ }
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ grn_text_lltoa(ctx, buf, e->id);
+ GRN_TEXT_PUTS(ctx, buf, ",");
+ grn_pat_inspect_check(ctx, buf, e->check);
+ GRN_TEXT_PUTS(ctx, buf, "]");
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+}
+
+void
+grn_pat_cursor_inspect(grn_ctx *ctx, grn_pat_cursor *c, grn_obj *buf)
+{
+ GRN_TEXT_PUTS(ctx, buf, "#<cursor:pat:");
+ grn_inspect_name(ctx, buf, (grn_obj *)(c->pat));
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ GRN_TEXT_PUTS(ctx, buf, "current:");
+ grn_text_lltoa(ctx, buf, c->curr_rec);
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ GRN_TEXT_PUTS(ctx, buf, "tail:");
+ grn_text_lltoa(ctx, buf, c->tail);
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ GRN_TEXT_PUTS(ctx, buf, "flags:");
+ if (c->obj.header.flags & GRN_CURSOR_PREFIX) {
+ GRN_TEXT_PUTS(ctx, buf, "prefix");
+ } else {
+ if (c->obj.header.flags & GRN_CURSOR_DESCENDING) {
+ GRN_TEXT_PUTS(ctx, buf, "descending");
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "ascending");
+ }
+ GRN_TEXT_PUTS(ctx, buf, "|");
+ if (c->obj.header.flags & GRN_CURSOR_GT) {
+ GRN_TEXT_PUTS(ctx, buf, "greater-than");
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "greater");
+ }
+ GRN_TEXT_PUTS(ctx, buf, "|");
+ if (c->obj.header.flags & GRN_CURSOR_LT) {
+ GRN_TEXT_PUTS(ctx, buf, "less-than");
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "less");
+ }
+ if (c->obj.header.flags & GRN_CURSOR_BY_ID) {
+ GRN_TEXT_PUTS(ctx, buf, "|by-id");
+ }
+ if (c->obj.header.flags & GRN_CURSOR_BY_KEY) {
+ GRN_TEXT_PUTS(ctx, buf, "|by-key");
+ }
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ GRN_TEXT_PUTS(ctx, buf, "rest:");
+ grn_text_lltoa(ctx, buf, c->rest);
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ GRN_TEXT_PUTS(ctx, buf, "entries:");
+ grn_pat_cursor_inspect_entries(ctx, c, buf);
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+}
+
+typedef struct {
+ uint8_t code;
+ uint8_t next;
+ uint8_t emit;
+ uint8_t attr;
+} rk_tree_node;
+
+static uint16_t rk_str_idx[] = {
+ 0x0003, 0x0006, 0x0009, 0x000c, 0x0012, 0x0015, 0x0018, 0x001e, 0x0024, 0x002a,
+ 0x0030, 0x0036, 0x003c, 0x0042, 0x0048, 0x004e, 0x0054, 0x005a, 0x0060, 0x0066,
+ 0x006c, 0x0072, 0x0078, 0x007e, 0x0084, 0x008a, 0x0090, 0x0096, 0x009c, 0x00a2,
+ 0x00a8, 0x00ae, 0x00b4, 0x00ba, 0x00c0, 0x00c3, 0x00c6, 0x00c9, 0x00cc, 0x00cf,
+ 0x00d2, 0x00d5, 0x00db, 0x00e1, 0x00e7, 0x00ea, 0x00f0, 0x00f6, 0x00fc, 0x00ff,
+ 0x0105, 0x0108, 0x010e, 0x0111, 0x0114, 0x0117, 0x011a, 0x011d, 0x0120, 0x0123,
+ 0x0129, 0x012f, 0x0135, 0x013b, 0x013e, 0x0144, 0x014a, 0x0150, 0x0156, 0x0159,
+ 0x015c, 0x015f, 0x0162, 0x0165, 0x0168, 0x016b, 0x016e, 0x0171, 0x0177, 0x017d,
+ 0x0183, 0x0189, 0x018c, 0x0192, 0x0198, 0x019e, 0x01a1, 0x01a4, 0x01aa, 0x01b0,
+ 0x01b6, 0x01bc, 0x01bf, 0x01c2, 0x01c8, 0x01ce, 0x01d1, 0x01d7, 0x01dd, 0x01e0,
+ 0x01e6, 0x01e9, 0x01ef, 0x01f2, 0x01f5, 0x01fb, 0x0201, 0x0207, 0x020d, 0x0213,
+ 0x0216, 0x0219, 0x021c, 0x021f, 0x0222, 0x0225, 0x0228, 0x022e, 0x0234, 0x023a,
+ 0x023d, 0x0243, 0x0249, 0x024f, 0x0252, 0x0258, 0x025e, 0x0264, 0x0267, 0x026d,
+ 0x0273, 0x0279, 0x027f, 0x0285, 0x0288, 0x028b, 0x028e, 0x0291, 0x0294, 0x0297,
+ 0x029a, 0x029d, 0x02a0, 0x02a3, 0x02a9, 0x02af, 0x02b5, 0x02b8, 0x02bb, 0x02be,
+ 0x02c1, 0x02c4, 0x02c7, 0x02ca, 0x02cd, 0x02d0, 0x02d3, 0x02d6, 0x02dc, 0x02e2,
+ 0x02e8, 0x02eb, 0x02ee, 0x02f1, 0x02f4, 0x02f7, 0x02fa, 0x02fd, 0x0300, 0x0303,
+ 0x0309, 0x030c, 0x0312, 0x0318, 0x031e, 0x0324, 0x0327, 0x032a, 0x032d
+};
+static char rk_str[] = {
+ 0xe3, 0x82, 0xa1, 0xe3, 0x82, 0xa2, 0xe3, 0x82, 0xa3, 0xe3, 0x82, 0xa4, 0xe3,
+ 0x82, 0xa4, 0xe3, 0x82, 0xa7, 0xe3, 0x82, 0xa5, 0xe3, 0x82, 0xa6, 0xe3, 0x82,
+ 0xa6, 0xe3, 0x82, 0xa2, 0xe3, 0x82, 0xa6, 0xe3, 0x82, 0xa3, 0xe3, 0x82, 0xa6,
+ 0xe3, 0x82, 0xa4, 0xe3, 0x82, 0xa6, 0xe3, 0x82, 0xa6, 0xe3, 0x82, 0xa6, 0xe3,
+ 0x82, 0xa7, 0xe3, 0x82, 0xa6, 0xe3, 0x82, 0xa8, 0xe3, 0x82, 0xa6, 0xe3, 0x82,
+ 0xaa, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa0, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa1,
+ 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa2, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa3, 0xe3,
+ 0x82, 0xa6, 0xe3, 0x83, 0xa4, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa5, 0xe3, 0x82,
+ 0xa6, 0xe3, 0x83, 0xa6, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa7, 0xe3, 0x82, 0xa6,
+ 0xe3, 0x83, 0xa8, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xa9, 0xe3, 0x82, 0xa6, 0xe3,
+ 0x83, 0xaa, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xab, 0xe3, 0x82, 0xa6, 0xe3, 0x83,
+ 0xac, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xad, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xae,
+ 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xaf, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xb0, 0xe3,
+ 0x82, 0xa6, 0xe3, 0x83, 0xb1, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xb2, 0xe3, 0x82,
+ 0xa6, 0xe3, 0x83, 0xb3, 0xe3, 0x82, 0xa6, 0xe3, 0x83, 0xbc, 0xe3, 0x82, 0xa7,
+ 0xe3, 0x82, 0xa8, 0xe3, 0x82, 0xa9, 0xe3, 0x82, 0xaa, 0xe3, 0x82, 0xab, 0xe3,
+ 0x82, 0xac, 0xe3, 0x82, 0xad, 0xe3, 0x82, 0xad, 0xe3, 0x83, 0xa3, 0xe3, 0x82,
+ 0xad, 0xe3, 0x83, 0xa5, 0xe3, 0x82, 0xad, 0xe3, 0x83, 0xa7, 0xe3, 0x82, 0xae,
+ 0xe3, 0x82, 0xae, 0xe3, 0x83, 0xa3, 0xe3, 0x82, 0xae, 0xe3, 0x83, 0xa5, 0xe3,
+ 0x82, 0xae, 0xe3, 0x83, 0xa7, 0xe3, 0x82, 0xaf, 0xe3, 0x82, 0xaf, 0xe3, 0x82,
+ 0xa1, 0xe3, 0x82, 0xb0, 0xe3, 0x82, 0xb0, 0xe3, 0x82, 0xa1, 0xe3, 0x82, 0xb1,
+ 0xe3, 0x82, 0xb2, 0xe3, 0x82, 0xb3, 0xe3, 0x82, 0xb4, 0xe3, 0x82, 0xb5, 0xe3,
+ 0x82, 0xb6, 0xe3, 0x82, 0xb7, 0xe3, 0x82, 0xb7, 0xe3, 0x82, 0xa7, 0xe3, 0x82,
+ 0xb7, 0xe3, 0x83, 0xa3, 0xe3, 0x82, 0xb7, 0xe3, 0x83, 0xa5, 0xe3, 0x82, 0xb7,
+ 0xe3, 0x83, 0xa7, 0xe3, 0x82, 0xb8, 0xe3, 0x82, 0xb8, 0xe3, 0x82, 0xa7, 0xe3,
+ 0x82, 0xb8, 0xe3, 0x83, 0xa3, 0xe3, 0x82, 0xb8, 0xe3, 0x83, 0xa5, 0xe3, 0x82,
+ 0xb8, 0xe3, 0x83, 0xa7, 0xe3, 0x82, 0xb9, 0xe3, 0x82, 0xba, 0xe3, 0x82, 0xbb,
+ 0xe3, 0x82, 0xbc, 0xe3, 0x82, 0xbd, 0xe3, 0x82, 0xbe, 0xe3, 0x82, 0xbf, 0xe3,
+ 0x83, 0x80, 0xe3, 0x83, 0x81, 0xe3, 0x83, 0x81, 0xe3, 0x82, 0xa7, 0xe3, 0x83,
+ 0x81, 0xe3, 0x83, 0xa3, 0xe3, 0x83, 0x81, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x81,
+ 0xe3, 0x83, 0xa7, 0xe3, 0x83, 0x82, 0xe3, 0x83, 0x82, 0xe3, 0x83, 0xa3, 0xe3,
+ 0x83, 0x82, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x82, 0xe3, 0x83, 0xa7, 0xe3, 0x83,
+ 0x83, 0xe3, 0x83, 0x84, 0xe3, 0x83, 0x84, 0xe3, 0x82, 0xa1, 0xe3, 0x83, 0x84,
+ 0xe3, 0x82, 0xa3, 0xe3, 0x83, 0x84, 0xe3, 0x82, 0xa7, 0xe3, 0x83, 0x84, 0xe3,
+ 0x82, 0xa9, 0xe3, 0x83, 0x85, 0xe3, 0x83, 0x86, 0xe3, 0x83, 0x86, 0xe3, 0x82,
+ 0xa3, 0xe3, 0x83, 0x86, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x87, 0xe3, 0x83, 0x87,
+ 0xe3, 0x82, 0xa3, 0xe3, 0x83, 0x87, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x88, 0xe3,
+ 0x83, 0x88, 0xe3, 0x82, 0xa5, 0xe3, 0x83, 0x89, 0xe3, 0x83, 0x89, 0xe3, 0x82,
+ 0xa5, 0xe3, 0x83, 0x8a, 0xe3, 0x83, 0x8b, 0xe3, 0x83, 0x8b, 0xe3, 0x82, 0xa3,
+ 0xe3, 0x83, 0x8b, 0xe3, 0x82, 0xa7, 0xe3, 0x83, 0x8b, 0xe3, 0x83, 0xa3, 0xe3,
+ 0x83, 0x8b, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x8b, 0xe3, 0x83, 0xa7, 0xe3, 0x83,
+ 0x8c, 0xe3, 0x83, 0x8d, 0xe3, 0x83, 0x8e, 0xe3, 0x83, 0x8f, 0xe3, 0x83, 0x90,
+ 0xe3, 0x83, 0x91, 0xe3, 0x83, 0x92, 0xe3, 0x83, 0x92, 0xe3, 0x83, 0xa3, 0xe3,
+ 0x83, 0x92, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x92, 0xe3, 0x83, 0xa7, 0xe3, 0x83,
+ 0x93, 0xe3, 0x83, 0x93, 0xe3, 0x83, 0xa3, 0xe3, 0x83, 0x93, 0xe3, 0x83, 0xa5,
+ 0xe3, 0x83, 0x93, 0xe3, 0x83, 0xa7, 0xe3, 0x83, 0x94, 0xe3, 0x83, 0x94, 0xe3,
+ 0x83, 0xa3, 0xe3, 0x83, 0x94, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x94, 0xe3, 0x83,
+ 0xa7, 0xe3, 0x83, 0x95, 0xe3, 0x83, 0x95, 0xe3, 0x82, 0xa1, 0xe3, 0x83, 0x95,
+ 0xe3, 0x82, 0xa3, 0xe3, 0x83, 0x95, 0xe3, 0x82, 0xa7, 0xe3, 0x83, 0x95, 0xe3,
+ 0x82, 0xa9, 0xe3, 0x83, 0x95, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0x96, 0xe3, 0x83,
+ 0x97, 0xe3, 0x83, 0x98, 0xe3, 0x83, 0x99, 0xe3, 0x83, 0x9a, 0xe3, 0x83, 0x9b,
+ 0xe3, 0x83, 0x9c, 0xe3, 0x83, 0x9d, 0xe3, 0x83, 0x9e, 0xe3, 0x83, 0x9f, 0xe3,
+ 0x83, 0x9f, 0xe3, 0x83, 0xa3, 0xe3, 0x83, 0x9f, 0xe3, 0x83, 0xa5, 0xe3, 0x83,
+ 0x9f, 0xe3, 0x83, 0xa7, 0xe3, 0x83, 0xa0, 0xe3, 0x83, 0xa1, 0xe3, 0x83, 0xa2,
+ 0xe3, 0x83, 0xa3, 0xe3, 0x83, 0xa4, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0xa6, 0xe3,
+ 0x83, 0xa7, 0xe3, 0x83, 0xa8, 0xe3, 0x83, 0xa9, 0xe3, 0x83, 0xaa, 0xe3, 0x83,
+ 0xaa, 0xe3, 0x83, 0xa3, 0xe3, 0x83, 0xaa, 0xe3, 0x83, 0xa5, 0xe3, 0x83, 0xaa,
+ 0xe3, 0x83, 0xa7, 0xe3, 0x83, 0xab, 0xe3, 0x83, 0xac, 0xe3, 0x83, 0xad, 0xe3,
+ 0x83, 0xae, 0xe3, 0x83, 0xaf, 0xe3, 0x83, 0xb0, 0xe3, 0x83, 0xb1, 0xe3, 0x83,
+ 0xb2, 0xe3, 0x83, 0xb3, 0xe3, 0x83, 0xb3, 0xe3, 0x83, 0xbc, 0xe3, 0x83, 0xb4,
+ 0xe3, 0x83, 0xb4, 0xe3, 0x82, 0xa1, 0xe3, 0x83, 0xb4, 0xe3, 0x82, 0xa3, 0xe3,
+ 0x83, 0xb4, 0xe3, 0x82, 0xa7, 0xe3, 0x83, 0xb4, 0xe3, 0x82, 0xa9, 0xe3, 0x83,
+ 0xb5, 0xe3, 0x83, 0xb6, 0xe3, 0x83, 0xbc
+};
+static uint16_t rk_tree_idx[] = {
+ 0x001b, 0x0022, 0x0025, 0x0028, 0x002d, 0x0030, 0x0039, 0x003b, 0x003c, 0x003f,
+ 0x0046, 0x0047, 0x004f, 0x0050, 0x0053, 0x005a, 0x005d, 0x0064, 0x0067, 0x006f,
+ 0x0070, 0x0073, 0x007d, 0x007f, 0x0081, 0x0082, 0x0083, 0x0088, 0x008f, 0x0092,
+ 0x00af, 0x00b5, 0x00bc, 0x00bf, 0x00c6, 0x00c9, 0x00d1, 0x00d6, 0x00da, 0x00e4,
+ 0x00e6, 0x00eb, 0x00ec, 0x00f0, 0x00f6, 0x00fc, 0x00fe, 0x0108, 0x010a, 0x010c,
+ 0x010d, 0x010e, 0x0113, 0x0118, 0x011f, 0x0123, 0x0125, 0x0164, 0x0180, 0x0183,
+ 0x0199, 0x01ad
+};
+static rk_tree_node rk_tree[] = {
+ {0x2d, 0x00, 0xb2, 0x01}, {0x61, 0x00, 0x01, 0x01}, {0x62, 0x01, 0xff, 0x01},
+ {0x63, 0x03, 0xff, 0x01}, {0x64, 0x06, 0xff, 0x01}, {0x65, 0x00, 0x24, 0x01},
+ {0x66, 0x0a, 0xff, 0x01}, {0x67, 0x0c, 0xff, 0x01}, {0x68, 0x0f, 0xff, 0x01},
+ {0x69, 0x00, 0x03, 0x01}, {0x6a, 0x11, 0xff, 0x01}, {0x6b, 0x13, 0xff, 0x01},
+ {0x6c, 0x16, 0xff, 0x01}, {0x6d, 0x1c, 0xff, 0x01}, {0x6e, 0x1e, 0xff, 0x01},
+ {0x6f, 0x00, 0x26, 0x01}, {0x70, 0x20, 0xff, 0x01}, {0x72, 0x22, 0xff, 0x01},
+ {0x73, 0x24, 0xff, 0x01}, {0x74, 0x27, 0xff, 0x01}, {0x75, 0x00, 0x06, 0x01},
+ {0x76, 0x2c, 0xff, 0x01}, {0x77, 0x2d, 0xff, 0x01}, {0x78, 0x2f, 0xff, 0x01},
+ {0x79, 0x35, 0xff, 0x01}, {0x7a, 0x36, 0xff, 0x01}, {0xe3, 0x38, 0xff, 0x01},
+ {0x61, 0x00, 0x72, 0x01}, {0x62, 0x01, 0x56, 0x01}, {0x65, 0x00, 0x89, 0x01},
+ {0x69, 0x00, 0x78, 0x01}, {0x6f, 0x00, 0x8c, 0x01}, {0x75, 0x00, 0x86, 0x01},
+ {0x79, 0x02, 0xff, 0x00}, {0x61, 0x00, 0x79, 0x01}, {0x6f, 0x00, 0x7b, 0x01},
+ {0x75, 0x00, 0x7a, 0x01}, {0x63, 0x03, 0x56, 0x01}, {0x68, 0x04, 0xff, 0x01},
+ {0x79, 0x05, 0xff, 0x01}, {0x61, 0x00, 0x4f, 0x00}, {0x65, 0x00, 0x4e, 0x00},
+ {0x69, 0x00, 0x4d, 0x01}, {0x6f, 0x00, 0x51, 0x00}, {0x75, 0x00, 0x50, 0x00},
+ {0x61, 0x00, 0x4f, 0x01}, {0x6f, 0x00, 0x51, 0x01}, {0x75, 0x00, 0x50, 0x01},
+ {0x61, 0x00, 0x4c, 0x01}, {0x64, 0x06, 0x56, 0x01}, {0x65, 0x00, 0x60, 0x01},
+ {0x68, 0x07, 0xff, 0x00}, {0x69, 0x00, 0x61, 0x00}, {0x6f, 0x00, 0x65, 0x01},
+ {0x75, 0x00, 0x5c, 0x01}, {0x77, 0x08, 0xff, 0x00}, {0x79, 0x09, 0xff, 0x01},
+ {0x69, 0x00, 0x61, 0x01}, {0x75, 0x00, 0x62, 0x01}, {0x75, 0x00, 0x66, 0x01},
+ {0x61, 0x00, 0x53, 0x01}, {0x6f, 0x00, 0x55, 0x01}, {0x75, 0x00, 0x54, 0x01},
+ {0x61, 0x00, 0x81, 0x00}, {0x65, 0x00, 0x83, 0x00}, {0x66, 0x0a, 0x56, 0x01},
+ {0x69, 0x00, 0x82, 0x00}, {0x6f, 0x00, 0x84, 0x00}, {0x75, 0x00, 0x80, 0x01},
+ {0x79, 0x0b, 0xff, 0x00}, {0x75, 0x00, 0x85, 0x01}, {0x61, 0x00, 0x28, 0x01},
+ {0x65, 0x00, 0x36, 0x01}, {0x67, 0x0c, 0x56, 0x01}, {0x69, 0x00, 0x2d, 0x01},
+ {0x6f, 0x00, 0x38, 0x01}, {0x75, 0x00, 0x33, 0x01}, {0x77, 0x0d, 0xff, 0x00},
+ {0x79, 0x0e, 0xff, 0x00}, {0x61, 0x00, 0x34, 0x01}, {0x61, 0x00, 0x2e, 0x01},
+ {0x6f, 0x00, 0x30, 0x01}, {0x75, 0x00, 0x2f, 0x01}, {0x61, 0x00, 0x71, 0x01},
+ {0x65, 0x00, 0x88, 0x01}, {0x68, 0x0f, 0x56, 0x01}, {0x69, 0x00, 0x74, 0x01},
+ {0x6f, 0x00, 0x8b, 0x01}, {0x75, 0x00, 0x80, 0x01}, {0x79, 0x10, 0xff, 0x00},
+ {0x61, 0x00, 0x75, 0x01}, {0x6f, 0x00, 0x77, 0x01}, {0x75, 0x00, 0x76, 0x01},
+ {0x61, 0x00, 0x42, 0x00}, {0x65, 0x00, 0x41, 0x00}, {0x69, 0x00, 0x40, 0x01},
+ {0x6a, 0x11, 0x56, 0x01}, {0x6f, 0x00, 0x44, 0x00}, {0x75, 0x00, 0x43, 0x00},
+ {0x79, 0x12, 0xff, 0x00}, {0x61, 0x00, 0x42, 0x01}, {0x6f, 0x00, 0x44, 0x01},
+ {0x75, 0x00, 0x43, 0x01}, {0x61, 0x00, 0x27, 0x01}, {0x65, 0x00, 0x35, 0x01},
+ {0x69, 0x00, 0x29, 0x01}, {0x6b, 0x13, 0x56, 0x01}, {0x6f, 0x00, 0x37, 0x01},
+ {0x75, 0x00, 0x31, 0x01}, {0x77, 0x14, 0xff, 0x00}, {0x79, 0x15, 0xff, 0x00},
+ {0x61, 0x00, 0x32, 0x01}, {0x61, 0x00, 0x2a, 0x01}, {0x6f, 0x00, 0x2c, 0x01},
+ {0x75, 0x00, 0x2b, 0x01}, {0x61, 0x00, 0x00, 0x01}, {0x65, 0x00, 0x23, 0x01},
+ {0x69, 0x00, 0x02, 0x01}, {0x6b, 0x17, 0xff, 0x01}, {0x6c, 0x16, 0x56, 0x01},
+ {0x6f, 0x00, 0x25, 0x01}, {0x74, 0x18, 0xff, 0x01}, {0x75, 0x00, 0x05, 0x01},
+ {0x77, 0x1a, 0xff, 0x01}, {0x79, 0x1b, 0xff, 0x01}, {0x61, 0x00, 0xb0, 0x01},
+ {0x65, 0x00, 0xb1, 0x01}, {0x73, 0x19, 0xff, 0x00}, {0x75, 0x00, 0x56, 0x01},
+ {0x75, 0x00, 0x56, 0x01}, {0x61, 0x00, 0xa4, 0x01}, {0x61, 0x00, 0x96, 0x01},
+ {0x65, 0x00, 0x23, 0x01}, {0x69, 0x00, 0x02, 0x01}, {0x6f, 0x00, 0x9a, 0x01},
+ {0x75, 0x00, 0x98, 0x01}, {0x61, 0x00, 0x8e, 0x01}, {0x65, 0x00, 0x94, 0x01},
+ {0x69, 0x00, 0x8f, 0x01}, {0x6d, 0x1c, 0x56, 0x01}, {0x6f, 0x00, 0x95, 0x01},
+ {0x75, 0x00, 0x93, 0x01}, {0x79, 0x1d, 0xff, 0x00}, {0x61, 0x00, 0x90, 0x01},
+ {0x6f, 0x00, 0x92, 0x01}, {0x75, 0x00, 0x91, 0x01}, {0x00, 0x00, 0xa9, 0x01},
+ {0x27, 0x00, 0xa9, 0x00}, {0x2d, 0x00, 0xaa, 0x00}, {0x61, 0x00, 0x67, 0x01},
+ {0x62, 0x01, 0xa9, 0x00}, {0x63, 0x03, 0xa9, 0x00}, {0x64, 0x06, 0xa9, 0x00},
+ {0x65, 0x00, 0x6f, 0x01}, {0x66, 0x0a, 0xa9, 0x00}, {0x67, 0x0c, 0xa9, 0x00},
+ {0x68, 0x0f, 0xa9, 0x00}, {0x69, 0x00, 0x68, 0x01}, {0x6a, 0x11, 0xa9, 0x00},
+ {0x6b, 0x13, 0xa9, 0x00}, {0x6c, 0x16, 0xa9, 0x00}, {0x6d, 0x1c, 0xa9, 0x00},
+ {0x6e, 0x00, 0xa9, 0x00}, {0x6f, 0x00, 0x70, 0x01}, {0x70, 0x20, 0xa9, 0x00},
+ {0x72, 0x22, 0xa9, 0x00}, {0x73, 0x24, 0xa9, 0x00}, {0x74, 0x27, 0xa9, 0x00},
+ {0x75, 0x00, 0x6e, 0x01}, {0x76, 0x2c, 0xa9, 0x00}, {0x77, 0x2d, 0xa9, 0x00},
+ {0x78, 0x2f, 0xa9, 0x00}, {0x79, 0x1f, 0xff, 0x00}, {0x7a, 0x36, 0xa9, 0x00},
+ {0xe3, 0x38, 0xa9, 0x00}, {0x00, 0x00, 0xa9, 0x01}, {0x61, 0x00, 0x6b, 0x01},
+ {0x65, 0x00, 0x6a, 0x01}, {0x69, 0x00, 0x69, 0x01}, {0x6f, 0x00, 0x6d, 0x01},
+ {0x75, 0x00, 0x6c, 0x01}, {0x61, 0x00, 0x73, 0x01}, {0x65, 0x00, 0x8a, 0x01},
+ {0x69, 0x00, 0x7c, 0x01}, {0x6f, 0x00, 0x8d, 0x01}, {0x70, 0x20, 0x56, 0x01},
+ {0x75, 0x00, 0x87, 0x01}, {0x79, 0x21, 0xff, 0x00}, {0x61, 0x00, 0x7d, 0x01},
+ {0x6f, 0x00, 0x7f, 0x01}, {0x75, 0x00, 0x7e, 0x01}, {0x61, 0x00, 0x9c, 0x01},
+ {0x65, 0x00, 0xa2, 0x01}, {0x69, 0x00, 0x9d, 0x01}, {0x6f, 0x00, 0xa3, 0x01},
+ {0x72, 0x22, 0x56, 0x01}, {0x75, 0x00, 0xa1, 0x01}, {0x79, 0x23, 0xff, 0x00},
+ {0x61, 0x00, 0x9e, 0x01}, {0x6f, 0x00, 0xa0, 0x01}, {0x75, 0x00, 0x9f, 0x01},
+ {0x61, 0x00, 0x39, 0x01}, {0x65, 0x00, 0x47, 0x01}, {0x68, 0x25, 0xff, 0x00},
+ {0x69, 0x00, 0x3b, 0x01}, {0x6f, 0x00, 0x49, 0x01}, {0x73, 0x24, 0x56, 0x01},
+ {0x75, 0x00, 0x45, 0x01}, {0x79, 0x26, 0xff, 0x00}, {0x61, 0x00, 0x3d, 0x00},
+ {0x65, 0x00, 0x3c, 0x00}, {0x69, 0x00, 0x3b, 0x01}, {0x6f, 0x00, 0x3f, 0x00},
+ {0x75, 0x00, 0x3e, 0x00}, {0x61, 0x00, 0x3d, 0x01}, {0x65, 0x00, 0x3c, 0x01},
+ {0x6f, 0x00, 0x3f, 0x01}, {0x75, 0x00, 0x3e, 0x01}, {0x61, 0x00, 0x4b, 0x01},
+ {0x65, 0x00, 0x5d, 0x01}, {0x68, 0x28, 0xff, 0x00}, {0x69, 0x00, 0x4d, 0x01},
+ {0x6f, 0x00, 0x63, 0x01}, {0x73, 0x29, 0xff, 0x00}, {0x74, 0x27, 0x56, 0x01},
+ {0x75, 0x00, 0x57, 0x01}, {0x77, 0x2a, 0xff, 0x00}, {0x79, 0x2b, 0xff, 0x00},
+ {0x69, 0x00, 0x5e, 0x01}, {0x75, 0x00, 0x5f, 0x01}, {0x61, 0x00, 0x58, 0x00},
+ {0x65, 0x00, 0x5a, 0x00}, {0x69, 0x00, 0x59, 0x00}, {0x6f, 0x00, 0x5b, 0x00},
+ {0x75, 0x00, 0x57, 0x01}, {0x75, 0x00, 0x64, 0x01}, {0x61, 0x00, 0x4f, 0x01},
+ {0x65, 0x00, 0x4e, 0x01}, {0x6f, 0x00, 0x51, 0x01}, {0x75, 0x00, 0x50, 0x01},
+ {0x61, 0x00, 0xac, 0x00}, {0x65, 0x00, 0xae, 0x00}, {0x69, 0x00, 0xad, 0x00},
+ {0x6f, 0x00, 0xaf, 0x00}, {0x75, 0x00, 0xab, 0x01}, {0x76, 0x2c, 0x56, 0x01},
+ {0x61, 0x00, 0xa5, 0x01}, {0x65, 0x00, 0x0b, 0x01}, {0x69, 0x00, 0x08, 0x01},
+ {0x6f, 0x00, 0xa8, 0x01}, {0x77, 0x2d, 0x56, 0x01}, {0x79, 0x2e, 0xff, 0x01},
+ {0x65, 0x00, 0xa7, 0x01}, {0x69, 0x00, 0xa6, 0x01}, {0x61, 0x00, 0x00, 0x01},
+ {0x65, 0x00, 0x23, 0x01}, {0x69, 0x00, 0x02, 0x01}, {0x6b, 0x30, 0xff, 0x01},
+ {0x6f, 0x00, 0x25, 0x01}, {0x74, 0x31, 0xff, 0x01}, {0x75, 0x00, 0x05, 0x01},
+ {0x77, 0x33, 0xff, 0x01}, {0x78, 0x2f, 0x56, 0x01}, {0x79, 0x34, 0xff, 0x01},
+ {0x61, 0x00, 0xb0, 0x01}, {0x65, 0x00, 0xb1, 0x01}, {0x73, 0x32, 0xff, 0x00},
+ {0x75, 0x00, 0x56, 0x01}, {0x75, 0x00, 0x56, 0x01}, {0x61, 0x00, 0xa4, 0x01},
+ {0x61, 0x00, 0x96, 0x01}, {0x65, 0x00, 0x23, 0x01}, {0x69, 0x00, 0x02, 0x01},
+ {0x6f, 0x00, 0x9a, 0x01}, {0x75, 0x00, 0x98, 0x01}, {0x61, 0x00, 0x97, 0x01},
+ {0x65, 0x00, 0x04, 0x01}, {0x6f, 0x00, 0x9b, 0x01}, {0x75, 0x00, 0x99, 0x01},
+ {0x79, 0x35, 0x56, 0x01}, {0x61, 0x00, 0x3a, 0x01}, {0x65, 0x00, 0x48, 0x01},
+ {0x69, 0x00, 0x40, 0x01}, {0x6f, 0x00, 0x4a, 0x01}, {0x75, 0x00, 0x46, 0x01},
+ {0x79, 0x37, 0xff, 0x00}, {0x7a, 0x36, 0x56, 0x01}, {0x61, 0x00, 0x42, 0x01},
+ {0x65, 0x00, 0x41, 0x01}, {0x6f, 0x00, 0x44, 0x01}, {0x75, 0x00, 0x43, 0x01},
+ {0x81, 0x39, 0xff, 0x01}, {0x82, 0x3d, 0xff, 0x01}, {0x81, 0x00, 0x00, 0x01},
+ {0x82, 0x00, 0x01, 0x01}, {0x83, 0x00, 0x02, 0x01}, {0x84, 0x00, 0x03, 0x01},
+ {0x85, 0x00, 0x05, 0x01}, {0x86, 0x3a, 0xff, 0x01}, {0x87, 0x00, 0x23, 0x01},
+ {0x88, 0x00, 0x24, 0x01}, {0x89, 0x00, 0x25, 0x01}, {0x8a, 0x00, 0x26, 0x01},
+ {0x8b, 0x00, 0x27, 0x01}, {0x8c, 0x00, 0x28, 0x01}, {0x8d, 0x00, 0x29, 0x01},
+ {0x8e, 0x00, 0x2d, 0x01}, {0x8f, 0x00, 0x31, 0x01}, {0x90, 0x00, 0x33, 0x01},
+ {0x91, 0x00, 0x35, 0x01}, {0x92, 0x00, 0x36, 0x01}, {0x93, 0x00, 0x37, 0x01},
+ {0x94, 0x00, 0x38, 0x01}, {0x95, 0x00, 0x39, 0x01}, {0x96, 0x00, 0x3a, 0x01},
+ {0x97, 0x00, 0x3b, 0x01}, {0x98, 0x00, 0x40, 0x01}, {0x99, 0x00, 0x45, 0x01},
+ {0x9a, 0x00, 0x46, 0x01}, {0x9b, 0x00, 0x47, 0x01}, {0x9c, 0x00, 0x48, 0x01},
+ {0x9d, 0x00, 0x49, 0x01}, {0x9e, 0x00, 0x4a, 0x01}, {0x9f, 0x00, 0x4b, 0x01},
+ {0xa0, 0x00, 0x4c, 0x01}, {0xa1, 0x00, 0x4d, 0x01}, {0xa2, 0x00, 0x52, 0x01},
+ {0xa3, 0x00, 0x56, 0x01}, {0xa4, 0x00, 0x57, 0x01}, {0xa5, 0x00, 0x5c, 0x01},
+ {0xa6, 0x00, 0x5d, 0x01}, {0xa7, 0x00, 0x60, 0x01}, {0xa8, 0x00, 0x63, 0x01},
+ {0xa9, 0x00, 0x65, 0x01}, {0xaa, 0x00, 0x67, 0x01}, {0xab, 0x00, 0x68, 0x01},
+ {0xac, 0x00, 0x6e, 0x01}, {0xad, 0x00, 0x6f, 0x01}, {0xae, 0x00, 0x70, 0x01},
+ {0xaf, 0x00, 0x71, 0x01}, {0xb0, 0x00, 0x72, 0x01}, {0xb1, 0x00, 0x73, 0x01},
+ {0xb2, 0x00, 0x74, 0x01}, {0xb3, 0x00, 0x78, 0x01}, {0xb4, 0x00, 0x7c, 0x01},
+ {0xb5, 0x00, 0x80, 0x01}, {0xb6, 0x00, 0x86, 0x01}, {0xb7, 0x00, 0x87, 0x01},
+ {0xb8, 0x00, 0x88, 0x01}, {0xb9, 0x00, 0x89, 0x01}, {0xba, 0x00, 0x8a, 0x01},
+ {0xbb, 0x00, 0x8b, 0x01}, {0xbc, 0x00, 0x8c, 0x01}, {0xbd, 0x00, 0x8d, 0x01},
+ {0xbe, 0x00, 0x8e, 0x01}, {0xbf, 0x00, 0x8f, 0x01}, {0x00, 0x00, 0x06, 0x00},
+ {0x2d, 0x00, 0x22, 0x00}, {0x61, 0x00, 0x07, 0x00}, {0x62, 0x01, 0x06, 0x00},
+ {0x63, 0x03, 0x06, 0x00}, {0x64, 0x06, 0x06, 0x00}, {0x65, 0x00, 0x0c, 0x00},
+ {0x66, 0x0a, 0x06, 0x00}, {0x67, 0x0c, 0x06, 0x00}, {0x68, 0x0f, 0x06, 0x00},
+ {0x69, 0x00, 0x09, 0x00}, {0x6a, 0x11, 0x06, 0x00}, {0x6b, 0x13, 0x06, 0x00},
+ {0x6c, 0x16, 0x06, 0x00}, {0x6d, 0x1c, 0x06, 0x00}, {0x6e, 0x1e, 0x06, 0x00},
+ {0x6f, 0x00, 0x0d, 0x00}, {0x70, 0x20, 0x06, 0x00}, {0x72, 0x22, 0x06, 0x00},
+ {0x73, 0x24, 0x06, 0x00}, {0x74, 0x27, 0x06, 0x00}, {0x75, 0x00, 0x0a, 0x00},
+ {0x76, 0x2c, 0x06, 0x00}, {0x77, 0x2d, 0x06, 0x00}, {0x78, 0x2f, 0x06, 0x00},
+ {0x79, 0x35, 0x06, 0x00}, {0x7a, 0x36, 0x06, 0x00}, {0xe3, 0x3b, 0xff, 0x01},
+ {0x00, 0x00, 0x06, 0x00}, {0x81, 0x39, 0x06, 0x00}, {0x82, 0x3c, 0xff, 0x01},
+ {0x00, 0x00, 0x06, 0x01}, {0x80, 0x00, 0x0e, 0x00}, {0x81, 0x00, 0x0f, 0x00},
+ {0x82, 0x00, 0x10, 0x00}, {0x83, 0x00, 0x11, 0x00}, {0x84, 0x00, 0x12, 0x00},
+ {0x85, 0x00, 0x13, 0x00}, {0x86, 0x00, 0x14, 0x00}, {0x87, 0x00, 0x15, 0x00},
+ {0x88, 0x00, 0x16, 0x00}, {0x89, 0x00, 0x17, 0x00}, {0x8a, 0x00, 0x18, 0x00},
+ {0x8b, 0x00, 0x19, 0x00}, {0x8c, 0x00, 0x1a, 0x00}, {0x8d, 0x00, 0x1b, 0x00},
+ {0x8e, 0x00, 0x1c, 0x00}, {0x8f, 0x00, 0x1d, 0x00}, {0x90, 0x00, 0x1e, 0x00},
+ {0x91, 0x00, 0x1f, 0x00}, {0x92, 0x00, 0x20, 0x00}, {0x93, 0x00, 0x21, 0x00},
+ {0x9b, 0x00, 0xab, 0x01}, {0x80, 0x00, 0x93, 0x01}, {0x81, 0x00, 0x94, 0x01},
+ {0x82, 0x00, 0x95, 0x01}, {0x83, 0x00, 0x96, 0x01}, {0x84, 0x00, 0x97, 0x01},
+ {0x85, 0x00, 0x98, 0x01}, {0x86, 0x00, 0x99, 0x01}, {0x87, 0x00, 0x9a, 0x01},
+ {0x88, 0x00, 0x9b, 0x01}, {0x89, 0x00, 0x9c, 0x01}, {0x8a, 0x00, 0x9d, 0x01},
+ {0x8b, 0x00, 0xa1, 0x01}, {0x8c, 0x00, 0xa2, 0x01}, {0x8d, 0x00, 0xa3, 0x01},
+ {0x8e, 0x00, 0xa4, 0x01}, {0x8f, 0x00, 0xa5, 0x01}, {0x90, 0x00, 0xa6, 0x01},
+ {0x91, 0x00, 0xa7, 0x01}, {0x92, 0x00, 0xa8, 0x01}, {0x93, 0x00, 0xa9, 0x01}
+};
+
+static rk_tree_node *
+rk_lookup(uint8_t state, uint8_t code)
+{
+ if (state < sizeof(rk_tree_idx)/sizeof(uint16_t)) {
+ uint16_t ns = state ? rk_tree_idx[state - 1] : 0;
+ uint16_t ne = rk_tree_idx[state];
+ while (ns < ne) {
+ uint16_t m = (ns + ne)>>1;
+ rk_tree_node *rn = &rk_tree[m];
+ if (rn->code == code) { return rn; }
+ if (rn->code < code) {
+ ns = m + 1;
+ } else {
+ ne = m;
+ }
+ }
+ }
+ return NULL;
+}
+
+static uint32_t
+rk_emit(rk_tree_node *rn, char **str)
+{
+ if (rn && rn->emit != 0xff) {
+ uint16_t pos = rn->emit ? rk_str_idx[rn->emit - 1] : 0;
+ *str = &rk_str[pos];
+ return (uint32_t)(rk_str_idx[rn->emit] - pos);
+ } else {
+ *str = NULL;
+ return 0;
+ }
+}
+
+#define RK_OUTPUT(e,l) do {\
+ if (oc < oe) {\
+ uint32_t l_ = (oc + (l) < oe) ? (l) : (oe - oc);\
+ grn_memcpy(oc, (e), l_);\
+ oc += l_;\
+ ic_ = ic;\
+ }\
+} while (0)
+
+static uint32_t
+rk_conv(const char *str, uint32_t str_len, uint8_t *buf, uint32_t buf_size, uint8_t *statep)
+{
+ uint32_t l;
+ uint8_t state = 0;
+ rk_tree_node *rn;
+ char *e;
+ uint8_t *oc = buf, *oe = oc + buf_size;
+ const uint8_t *ic = (uint8_t *)str, *ic_ = ic, *ie = ic + str_len;
+ while (ic < ie) {
+ if ((rn = rk_lookup(state, *ic))) {
+ ic++;
+ if ((l = rk_emit(rn, &e))) { RK_OUTPUT(e, l); }
+ state = rn->next;
+ } else {
+ if (!state) { ic++; }
+ if (ic_ < ic) { RK_OUTPUT(ic_, ic - ic_); }
+ state = 0;
+ }
+ }
+#ifdef FLUSH_UNRESOLVED_INPUT
+ if ((rn = rk_lookup(state, 0))) {
+ if ((l = rk_emit(rn, &e))) { RK_OUTPUT(e, l); }
+ state = rn->next;
+ } else {
+ if (ic_ < ic) { RK_OUTPUT(ic_, ic - ic_); }
+ }
+#endif /* FLUSH_UNRESOLVED_INPUT */
+ *statep = state;
+ return oc - buf;
+}
+
+static grn_id
+sub_search(grn_ctx *ctx, grn_pat *pat, grn_id id,
+ int *c0, uint8_t *key, uint32_t key_len)
+{
+ pat_node *pn;
+ uint32_t len = key_len * 16;
+ if (!key_len) { return id; }
+ PAT_AT(pat, id, pn);
+ while (pn) {
+ int ch;
+ ch = PAT_CHK(pn);
+ if (*c0 < ch && ch < (int) len - 1) {
+ if (ch & 1) {
+ id = (ch + 1 < (int) len) ? pn->lr[1] : pn->lr[0];
+ } else {
+ id = pn->lr[nth_bit(key, ch, len)];
+ }
+ *c0 = ch;
+ PAT_AT(pat, id, pn);
+ } else {
+ const uint8_t *k = pat_node_get_key(ctx, pat, pn);
+ return (k && key_len <= PAT_LEN(pn) && !memcmp(k, key, key_len)) ? id : GRN_ID_NIL;
+ }
+ }
+ return GRN_ID_NIL;
+}
+
+static void
+search_push(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ uint8_t *key, uint32_t key_len, uint8_t state, grn_id id, int c0, int flags)
+{
+ if (state) {
+ int step;
+ uint16_t ns, ne;
+ if (flags & GRN_CURSOR_DESCENDING) {
+ ns = rk_tree_idx[state - 1];
+ ne = rk_tree_idx[state];
+ step = 1;
+ } else {
+ ns = rk_tree_idx[state] - 1;
+ ne = rk_tree_idx[state - 1] - 1;
+ step = -1;
+ }
+ for (; ns != ne; ns += step) {
+ rk_tree_node *rn = &rk_tree[ns];
+ if (rn->attr) {
+ char *e;
+ uint32_t l = rk_emit(rn, &e);
+ if (l) {
+ if (l + key_len <= GRN_TABLE_MAX_KEY_SIZE) {
+ int ch = c0;
+ grn_id i;
+ grn_memcpy(key + key_len, e, l);
+ if ((i = sub_search(ctx, pat, id, &ch, key, key_len + l))) {
+ search_push(ctx, pat, c, key, key_len + l, rn->next, i, ch, flags);
+ }
+ }
+ } else {
+ search_push(ctx, pat, c, key, key_len, rn->next, id, c0, flags);
+ }
+ }
+ }
+ } else {
+ pat_node *pn;
+ PAT_AT(pat, id, pn);
+ if (pn) {
+ int ch = PAT_CHK(pn);
+ uint32_t len = key_len * 16;
+ if (c0 < ch) {
+ if (flags & GRN_CURSOR_DESCENDING) {
+ if ((ch > (int) len - 1) || !(flags & GRN_CURSOR_GT)) { push(c, pn->lr[0], ch); }
+ push(c, pn->lr[1], ch);
+ } else {
+ push(c, pn->lr[1], ch);
+ if ((ch > (int) len - 1) || !(flags & GRN_CURSOR_GT)) { push(c, pn->lr[0], ch); }
+ }
+ } else {
+ if (PAT_LEN(pn) * 16 > len || !(flags & GRN_CURSOR_GT)) { push(c, id, ch); }
+ }
+ }
+ }
+}
+
+static grn_rc
+set_cursor_rk(grn_ctx *ctx, grn_pat *pat, grn_pat_cursor *c,
+ const void *key, uint32_t key_len, int flags)
+{
+ grn_id id;
+ uint8_t state;
+ pat_node *pn;
+ int c0 = -1;
+ uint32_t len, byte_len;
+ uint8_t keybuf[GRN_TABLE_MAX_KEY_SIZE];
+ if (flags & GRN_CURSOR_SIZE_BY_BIT) { return GRN_OPERATION_NOT_SUPPORTED; }
+ byte_len = rk_conv(key, key_len, keybuf, GRN_TABLE_MAX_KEY_SIZE, &state);
+ len = byte_len * 16;
+ PAT_AT(pat, 0, pn);
+ id = pn->lr[1];
+ if ((id = sub_search(ctx, pat, id, &c0, keybuf, byte_len))) {
+ search_push(ctx, pat, c, keybuf, byte_len, state, id, c0, flags);
+ }
+ return ctx->rc;
+}
+
+uint32_t
+grn_pat_total_key_size(grn_ctx *ctx, grn_pat *pat)
+{
+ return pat->header->curr_key;
+}
+
+grn_bool
+grn_pat_is_key_encoded(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_obj *domain;
+ uint32_t key_size;
+
+ domain = grn_ctx_at(ctx, pat->obj.header.domain);
+ if (grn_obj_is_type(ctx, domain)) {
+ key_size = grn_type_size(ctx, domain);
+ } else {
+ key_size = sizeof(grn_id);
+ }
+
+ return KEY_NEEDS_CONVERT(pat, key_size);
+}
+
+grn_rc
+grn_pat_dirty(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ CRITICAL_SECTION_ENTER(pat->lock);
+ if (!pat->is_dirty) {
+ uint32_t n_dirty_opens;
+ pat->is_dirty = GRN_TRUE;
+ GRN_ATOMIC_ADD_EX(&(pat->header->n_dirty_opens), 1, n_dirty_opens);
+ rc = grn_io_flush(ctx, pat->io);
+ }
+ CRITICAL_SECTION_LEAVE(pat->lock);
+
+ return rc;
+}
+
+grn_bool
+grn_pat_is_dirty(grn_ctx *ctx, grn_pat *pat)
+{
+ return pat->header->n_dirty_opens > 0;
+}
+
+grn_rc
+grn_pat_clean(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ CRITICAL_SECTION_ENTER(pat->lock);
+ if (pat->is_dirty) {
+ uint32_t n_dirty_opens;
+ pat->is_dirty = GRN_FALSE;
+ GRN_ATOMIC_ADD_EX(&(pat->header->n_dirty_opens), -1, n_dirty_opens);
+ rc = grn_io_flush(ctx, pat->io);
+ }
+ CRITICAL_SECTION_LEAVE(pat->lock);
+
+ return rc;
+}
+
+grn_rc
+grn_pat_clear_dirty(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ CRITICAL_SECTION_ENTER(pat->lock);
+ pat->is_dirty = GRN_FALSE;
+ pat->header->n_dirty_opens = 0;
+ rc = grn_io_flush(ctx, pat->io);
+ CRITICAL_SECTION_LEAVE(pat->lock);
+
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/plugin.c b/storage/mroonga/vendor/groonga/lib/plugin.c
new file mode 100644
index 00000000..ce4e3347
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/plugin.c
@@ -0,0 +1,1396 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include "grn_ctx_impl_mrb.h"
+#include "grn_proc.h"
+#include <groonga/plugin.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/stat.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif /* HAVE_DIRENT_H */
+
+#ifndef S_ISREG
+# ifdef _S_IFREG
+# define S_ISREG(mode) (mode & _S_IFREG)
+# endif /* _S_IFREG */
+#endif /* !S_ISREG */
+
+#include "grn_db.h"
+#include "grn_plugin.h"
+#include "grn_ctx_impl.h"
+#include "grn_util.h"
+
+#ifdef GRN_WITH_MRUBY
+# include <mruby.h>
+#endif /* GRN_WITH_MRUBY */
+
+static grn_hash *grn_plugins = NULL;
+static grn_critical_section grn_plugins_lock;
+static grn_ctx grn_plugins_ctx;
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+# define grn_dl_open(filename) dlopen(filename, RTLD_LAZY | RTLD_LOCAL)
+# define grn_dl_open_error_label() dlerror()
+# define grn_dl_close(dl) (dlclose(dl) == 0)
+# define grn_dl_close_error_label() dlerror()
+# define grn_dl_sym(dl, symbol) dlsym(dl, symbol)
+# define grn_dl_sym_error_label() dlerror()
+# define grn_dl_clear_error() dlerror()
+#else
+# define grn_dl_open(filename) LoadLibrary(filename)
+# define grn_dl_open_error_label() "LoadLibrary"
+# define grn_dl_close(dl) (FreeLibrary(dl) != 0)
+# define grn_dl_close_error_label() "FreeLibrary"
+# define grn_dl_sym(dl, symbol) ((void *)GetProcAddress(dl, symbol))
+# define grn_dl_sym_error_label() "GetProcAddress"
+# define grn_dl_clear_error()
+#endif
+
+#define GRN_PLUGIN_KEY_SIZE(filename) (strlen((filename)) + 1)
+
+static char grn_plugins_dir[GRN_ENV_BUFFER_SIZE];
+
+void
+grn_plugin_init_from_env(void)
+{
+ grn_getenv("GRN_PLUGINS_DIR",
+ grn_plugins_dir,
+ GRN_ENV_BUFFER_SIZE);
+}
+
+static int
+compute_name_size(const char *name, int name_size)
+{
+ if (name_size < 0) {
+ if (name) {
+ name_size = strlen(name);
+ } else {
+ name_size = 0;
+ }
+ }
+ return name_size;
+}
+
+grn_id
+grn_plugin_reference(grn_ctx *ctx, const char *filename)
+{
+ grn_id id;
+ grn_plugin **plugin = NULL;
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ id = grn_hash_get(&grn_plugins_ctx, grn_plugins,
+ filename, GRN_PLUGIN_KEY_SIZE(filename),
+ (void **)&plugin);
+ if (plugin) {
+ (*plugin)->refcount++;
+ }
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ return id;
+}
+
+const char *
+grn_plugin_path(grn_ctx *ctx, grn_id id)
+{
+ const char *path;
+ grn_plugin *plugin;
+ int value_size;
+ const char *system_plugins_dir;
+ size_t system_plugins_dir_size;
+
+ if (id == GRN_ID_NIL) {
+ return NULL;
+ }
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ value_size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ if (!plugin) {
+ return NULL;
+ }
+
+ path = plugin->path;
+ system_plugins_dir = grn_plugin_get_system_plugins_dir();
+ system_plugins_dir_size = strlen(system_plugins_dir);
+ if (strncmp(system_plugins_dir, path, system_plugins_dir_size) == 0) {
+ const char *plugin_name = path + system_plugins_dir_size;
+ while (plugin_name[0] == '/') {
+ plugin_name++;
+ }
+ /* TODO: remove suffix too? */
+ return plugin_name;
+ } else {
+ return path;
+ }
+}
+
+#define GRN_PLUGIN_FUNC_PREFIX "grn_plugin_impl_"
+
+static grn_rc
+grn_plugin_call_init(grn_ctx *ctx, grn_id id)
+{
+ grn_plugin *plugin;
+ int size;
+
+ size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
+ if (size == 0) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (plugin->init_func) {
+ return plugin->init_func(ctx);
+ }
+
+ return GRN_SUCCESS;
+}
+
+#ifdef GRN_WITH_MRUBY
+static grn_rc
+grn_plugin_call_register_mrb(grn_ctx *ctx, grn_id id, grn_plugin *plugin)
+{
+ grn_mrb_data *data;
+ mrb_state *mrb;
+ struct RClass *module;
+ struct RClass *plugin_loader_class;
+ int arena_index;
+
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ return ctx->rc;
+ }
+
+ data = &(ctx->impl->mrb);
+ mrb = data->state;
+ module = data->module;
+
+ {
+ int added;
+ grn_hash_add(ctx, ctx->impl->mrb.registered_plugins,
+ &id, sizeof(grn_id), NULL, &added);
+ if (!added) {
+ return ctx->rc;
+ }
+ }
+
+ arena_index = mrb_gc_arena_save(mrb);
+ plugin_loader_class = mrb_class_get_under(mrb, module, "PluginLoader");
+ mrb_funcall(mrb, mrb_obj_value(plugin_loader_class),
+ "load_file", 1, mrb_str_new_cstr(mrb, ctx->impl->plugin_path));
+ mrb_gc_arena_restore(mrb, arena_index);
+ return ctx->rc;
+}
+#endif /*GRN_WITH_MRUBY */
+
+static grn_rc
+grn_plugin_call_register(grn_ctx *ctx, grn_id id)
+{
+ grn_plugin *plugin;
+ int size;
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ if (size == 0) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+#ifdef GRN_WITH_MRUBY
+ if (!plugin->dl) {
+ return grn_plugin_call_register_mrb(ctx, id, plugin);
+ }
+#endif /* GRN_WITH_MRUBY */
+
+ if (plugin->register_func) {
+ return plugin->register_func(ctx);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_plugin_call_fin(grn_ctx *ctx, grn_id id)
+{
+ grn_plugin *plugin;
+ int size;
+
+ size = grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin);
+ if (size == 0) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (plugin->fin_func) {
+ return plugin->fin_func(ctx);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_plugin_initialize(grn_ctx *ctx, grn_plugin *plugin,
+ grn_dl dl, grn_id id, const char *path)
+{
+ plugin->dl = dl;
+
+#define GET_SYMBOL(type) do { \
+ grn_dl_clear_error(); \
+ plugin->type ## _func = grn_dl_sym(dl, GRN_PLUGIN_FUNC_PREFIX #type); \
+ if (!plugin->type ## _func) { \
+ const char *label; \
+ label = grn_dl_sym_error_label(); \
+ SERR("%s", label); \
+ } \
+} while (0)
+
+ GET_SYMBOL(init);
+ GET_SYMBOL(register);
+ GET_SYMBOL(fin);
+
+#undef GET_SYMBOL
+
+ if (!plugin->init_func || !plugin->register_func || !plugin->fin_func) {
+ ERR(GRN_INVALID_FORMAT,
+ "init func (%s) %sfound, "
+ "register func (%s) %sfound and "
+ "fin func (%s) %sfound",
+ GRN_PLUGIN_FUNC_PREFIX "init", plugin->init_func ? "" : "not ",
+ GRN_PLUGIN_FUNC_PREFIX "register", plugin->register_func ? "" : "not ",
+ GRN_PLUGIN_FUNC_PREFIX "fin", plugin->fin_func ? "" : "not ");
+ }
+
+ if (!ctx->rc) {
+ ctx->impl->plugin_path = path;
+ grn_plugin_call_init(ctx, id);
+ ctx->impl->plugin_path = NULL;
+ }
+
+ return ctx->rc;
+}
+
+#ifdef GRN_WITH_MRUBY
+static grn_id
+grn_plugin_open_mrb(grn_ctx *ctx, const char *filename, size_t filename_size)
+{
+ grn_ctx *plugins_ctx = &grn_plugins_ctx;
+ grn_id id = GRN_ID_NIL;
+ grn_plugin **plugin = NULL;
+
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_ID_NIL;
+ }
+
+ if (!ctx->impl->mrb.state) {
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED, "mruby support isn't enabled");
+ return GRN_ID_NIL;
+ }
+
+ id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size,
+ (void **)&plugin, NULL);
+ if (!id) {
+ return id;
+ }
+
+ {
+ grn_ctx *ctx = plugins_ctx;
+ *plugin = GRN_MALLOCN(grn_plugin, 1);
+ }
+ if (!*plugin) {
+ grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
+ return GRN_ID_NIL;
+ }
+
+ grn_memcpy((*plugin)->path, filename, filename_size);
+ (*plugin)->dl = NULL;
+ (*plugin)->init_func = NULL;
+ (*plugin)->register_func = NULL;
+ (*plugin)->fin_func = NULL;
+ (*plugin)->refcount = 1;
+
+ return id;
+}
+#endif /* GRN_WITH_MRUBY */
+
+grn_id
+grn_plugin_open(grn_ctx *ctx, const char *filename)
+{
+ grn_ctx *plugins_ctx = &grn_plugins_ctx;
+ grn_id id = GRN_ID_NIL;
+ grn_dl dl;
+ grn_plugin **plugin = NULL;
+ size_t filename_size;
+
+ filename_size = GRN_PLUGIN_KEY_SIZE(filename);
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ if ((id = grn_hash_get(plugins_ctx, grn_plugins, filename, filename_size,
+ (void **)&plugin))) {
+ (*plugin)->refcount++;
+ goto exit;
+ }
+
+#ifdef GRN_WITH_MRUBY
+ {
+ const char *mrb_suffix;
+ mrb_suffix = grn_plugin_get_ruby_suffix();
+ if (filename_size > strlen(mrb_suffix) &&
+ strcmp(filename + (strlen(filename) - strlen(mrb_suffix)),
+ mrb_suffix) == 0) {
+ id = grn_plugin_open_mrb(ctx, filename, filename_size);
+ goto exit;
+ }
+ }
+#endif /* GRN_WITH_MRUBY */
+
+ if ((dl = grn_dl_open(filename))) {
+ if ((id = grn_hash_add(plugins_ctx, grn_plugins, filename, filename_size,
+ (void **)&plugin, NULL))) {
+ {
+ grn_ctx *ctx = plugins_ctx;
+ *plugin = GRN_MALLOCN(grn_plugin, 1);
+ }
+ if (*plugin) {
+ grn_memcpy((*plugin)->path, filename, filename_size);
+ if (grn_plugin_initialize(ctx, *plugin, dl, id, filename)) {
+ {
+ grn_ctx *ctx = plugins_ctx;
+ GRN_FREE(*plugin);
+ }
+ *plugin = NULL;
+ }
+ }
+ if (!*plugin) {
+ grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
+ if (grn_dl_close(dl)) {
+ /* Now, __FILE__ set in plugin is invalid. */
+ ctx->errline = 0;
+ ctx->errfile = NULL;
+ } else {
+ const char *label;
+ label = grn_dl_close_error_label();
+ SERR("%s", label);
+ }
+ id = GRN_ID_NIL;
+ } else {
+ (*plugin)->refcount = 1;
+ }
+ } else {
+ if (!grn_dl_close(dl)) {
+ const char *label;
+ label = grn_dl_close_error_label();
+ SERR("%s", label);
+ }
+ }
+ } else {
+ const char *label;
+ label = grn_dl_open_error_label();
+ SERR("%s", label);
+ }
+
+exit:
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ return id;
+}
+
+grn_rc
+grn_plugin_close(grn_ctx *ctx, grn_id id)
+{
+ grn_ctx *plugins_ctx = &grn_plugins_ctx;
+ grn_rc rc;
+ grn_plugin *plugin;
+
+ if (id == GRN_ID_NIL) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ if (!grn_hash_get_value(plugins_ctx, grn_plugins, id, &plugin)) {
+ rc = GRN_INVALID_ARGUMENT;
+ goto exit;
+ }
+ if (--plugin->refcount) {
+ rc = GRN_SUCCESS;
+ goto exit;
+ }
+ if (plugin->dl) {
+ grn_plugin_call_fin(ctx, id);
+ if (!grn_dl_close(plugin->dl)) {
+ const char *label;
+ label = grn_dl_close_error_label();
+ SERR("%s", label);
+ }
+ }
+ {
+ grn_ctx *ctx = plugins_ctx;
+ GRN_FREE(plugin);
+ }
+ rc = grn_hash_delete_by_id(plugins_ctx, grn_plugins, id, NULL);
+
+exit:
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ return rc;
+}
+
+void *
+grn_plugin_sym(grn_ctx *ctx, grn_id id, const char *symbol)
+{
+ grn_plugin *plugin;
+ grn_dl_symbol func;
+
+ if (id == GRN_ID_NIL) {
+ return NULL;
+ }
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ if (!grn_hash_get_value(&grn_plugins_ctx, grn_plugins, id, &plugin)) {
+ func = NULL;
+ goto exit;
+ }
+ grn_dl_clear_error();
+ if (!(func = grn_dl_sym(plugin->dl, symbol))) {
+ const char *label;
+ label = grn_dl_sym_error_label();
+ SERR("%s", label);
+ }
+
+exit:
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ return func;
+}
+
+grn_rc
+grn_plugins_init(void)
+{
+ CRITICAL_SECTION_INIT(grn_plugins_lock);
+ grn_ctx_init(&grn_plugins_ctx, 0);
+ grn_plugins = grn_hash_create(&grn_plugins_ctx, NULL,
+ PATH_MAX, sizeof(grn_plugin *),
+ GRN_OBJ_KEY_VAR_SIZE);
+ if (!grn_plugins) {
+ grn_ctx_fin(&grn_plugins_ctx);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_plugins_fin(void)
+{
+ grn_rc rc;
+ if (!grn_plugins) { return GRN_INVALID_ARGUMENT; }
+ GRN_HASH_EACH(&grn_plugins_ctx, grn_plugins, id, NULL, NULL, NULL, {
+ grn_plugin_close(&grn_plugins_ctx, id);
+ });
+ rc = grn_hash_close(&grn_plugins_ctx, grn_plugins);
+ grn_ctx_fin(&grn_plugins_ctx);
+ CRITICAL_SECTION_FIN(grn_plugins_lock);
+ return rc;
+}
+
+const char *
+grn_plugin_get_suffix(void)
+{
+ return GRN_PLUGIN_SUFFIX;
+}
+
+const char *
+grn_plugin_get_ruby_suffix(void)
+{
+ return ".rb";
+}
+
+grn_rc
+grn_plugin_register_by_path(grn_ctx *ctx, const char *path)
+{
+ grn_obj *db;
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "db not initialized");
+ return ctx->rc;
+ }
+ GRN_API_ENTER;
+ if (GRN_DB_P(db)) {
+ grn_id id;
+ id = grn_plugin_open(ctx, path);
+ if (id) {
+ ctx->impl->plugin_path = path;
+ ctx->rc = grn_plugin_call_register(ctx, id);
+ ctx->impl->plugin_path = NULL;
+ grn_plugin_close(ctx, id);
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
+ }
+ GRN_API_RETURN(ctx->rc);
+}
+
+#ifdef WIN32
+static char *windows_plugins_dir = NULL;
+static char windows_plugins_dir_buffer[PATH_MAX];
+static const char *
+grn_plugin_get_default_system_plugins_dir(void)
+{
+ if (!windows_plugins_dir) {
+ const char *base_dir;
+ const char *relative_path = GRN_RELATIVE_PLUGINS_DIR;
+ size_t base_dir_length;
+
+ base_dir = grn_windows_base_dir();
+ base_dir_length = strlen(base_dir);
+ grn_strcpy(windows_plugins_dir_buffer, PATH_MAX, base_dir);
+ grn_strcat(windows_plugins_dir_buffer, PATH_MAX, "/");
+ grn_strcat(windows_plugins_dir_buffer, PATH_MAX, relative_path);
+ windows_plugins_dir = windows_plugins_dir_buffer;
+ }
+ return windows_plugins_dir;
+}
+
+#else /* WIN32 */
+static const char *
+grn_plugin_get_default_system_plugins_dir(void)
+{
+ return GRN_PLUGINS_DIR;
+}
+#endif /* WIN32 */
+
+const char *
+grn_plugin_get_system_plugins_dir(void)
+{
+ if (grn_plugins_dir[0]) {
+ return grn_plugins_dir;
+ } else {
+ return grn_plugin_get_default_system_plugins_dir();
+ }
+}
+
+static char *
+grn_plugin_find_path_raw(grn_ctx *ctx, const char *path)
+{
+ struct stat path_stat;
+
+ if (stat(path, &path_stat) != 0) {
+ return NULL;
+ }
+
+ if (!S_ISREG(path_stat.st_mode)) {
+ return NULL;
+ }
+
+ return GRN_STRDUP(path);
+}
+
+#ifdef GRN_WITH_MRUBY
+static char *
+grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len)
+{
+ char mrb_path[PATH_MAX];
+ const char *mrb_suffix;
+ size_t mrb_path_len;
+
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ return NULL;
+ }
+
+ if (!ctx->impl->mrb.state) {
+ return NULL;
+ }
+
+ mrb_suffix = grn_plugin_get_ruby_suffix();
+ mrb_path_len = path_len + strlen(mrb_suffix);
+ if (mrb_path_len >= PATH_MAX) {
+ ERR(GRN_FILENAME_TOO_LONG,
+ "too long plugin path: <%s%s>",
+ path, mrb_suffix);
+ return NULL;
+ }
+
+ grn_strcpy(mrb_path, PATH_MAX, path);
+ grn_strcat(mrb_path, PATH_MAX, mrb_suffix);
+ return grn_plugin_find_path_raw(ctx, mrb_path);
+}
+#else /* GRN_WITH_MRUBY */
+static char *
+grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len)
+{
+ return NULL;
+}
+#endif /* GRN_WITH_MRUBY */
+
+static char *
+grn_plugin_find_path_so(grn_ctx *ctx, const char *path, size_t path_len)
+{
+ char so_path[PATH_MAX];
+ const char *so_suffix;
+ size_t so_path_len;
+
+ so_suffix = grn_plugin_get_suffix();
+ so_path_len = path_len + strlen(so_suffix);
+ if (so_path_len >= PATH_MAX) {
+ ERR(GRN_FILENAME_TOO_LONG,
+ "too long plugin path: <%s%s>",
+ path, so_suffix);
+ return NULL;
+ }
+
+ grn_strcpy(so_path, PATH_MAX, path);
+ grn_strcat(so_path, PATH_MAX, so_suffix);
+ return grn_plugin_find_path_raw(ctx, so_path);
+}
+
+static char *
+grn_plugin_find_path_libs_so(grn_ctx *ctx, const char *path, size_t path_len)
+{
+ char libs_so_path[PATH_MAX];
+ const char *base_name;
+ const char *so_suffix;
+ const char *libs_path = "/.libs";
+ size_t libs_so_path_len;
+
+ base_name = strrchr(path, '/');
+ if (!base_name) {
+ return NULL;
+ }
+
+ so_suffix = grn_plugin_get_suffix();
+ libs_so_path_len =
+ base_name - path +
+ strlen(libs_path) +
+ strlen(base_name) +
+ strlen(so_suffix);
+ if (libs_so_path_len >= PATH_MAX) {
+ ERR(GRN_FILENAME_TOO_LONG,
+ "too long plugin path: <%.*s/.libs%s%s>",
+ (int)(base_name - path), path, base_name, so_suffix);
+ return NULL;
+ }
+
+ libs_so_path[0] = '\0';
+ grn_strncat(libs_so_path, PATH_MAX, path, base_name - path);
+ grn_strcat(libs_so_path, PATH_MAX, libs_path);
+ grn_strcat(libs_so_path, PATH_MAX, base_name);
+ grn_strcat(libs_so_path, PATH_MAX, so_suffix);
+ return grn_plugin_find_path_raw(ctx, libs_so_path);
+}
+
+char *
+grn_plugin_find_path(grn_ctx *ctx, const char *name)
+{
+ const char *plugins_dir;
+ char dir_last_char;
+ char path[PATH_MAX];
+ int name_length, max_name_length;
+ char *found_path = NULL;
+ size_t path_len;
+
+ GRN_API_ENTER;
+ if (name[0] == '/') {
+ path[0] = '\0';
+ } else {
+ plugins_dir = grn_plugin_get_system_plugins_dir();
+ grn_strcpy(path, PATH_MAX, plugins_dir);
+
+ dir_last_char = plugins_dir[strlen(path) - 1];
+ if (dir_last_char != '/') {
+ grn_strcat(path, PATH_MAX, "/");
+ }
+ }
+
+ name_length = strlen(name);
+ max_name_length = PATH_MAX - strlen(path) - 1;
+ if (name_length > max_name_length) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "plugin name is too long: %d (max: %d) <%s%s>",
+ name_length, max_name_length,
+ path, name);
+ goto exit;
+ }
+ grn_strcat(path, PATH_MAX, name);
+
+ found_path = grn_plugin_find_path_raw(ctx, path);
+ if (found_path) {
+ goto exit;
+ }
+
+ path_len = strlen(path);
+
+ found_path = grn_plugin_find_path_so(ctx, path, path_len);
+ if (found_path) {
+ goto exit;
+ }
+ if (ctx->rc) {
+ goto exit;
+ }
+
+ found_path = grn_plugin_find_path_libs_so(ctx, path, path_len);
+ if (found_path) {
+ goto exit;
+ }
+ if (ctx->rc) {
+ goto exit;
+ }
+
+ found_path = grn_plugin_find_path_mrb(ctx, path, path_len);
+ if (found_path) {
+ goto exit;
+ }
+ if (ctx->rc) {
+ goto exit;
+ }
+
+exit :
+ GRN_API_RETURN(found_path);
+}
+
+static void
+grn_plugin_set_name_resolve_error(grn_ctx *ctx, const char *name,
+ const char *tag)
+{
+ const char *prefix, *prefix_separator, *suffix;
+
+ if (name[0] == '/') {
+ prefix = "";
+ prefix_separator = "";
+ suffix = "";
+ } else {
+ prefix = grn_plugin_get_system_plugins_dir();
+ if (prefix[strlen(prefix) - 1] != '/') {
+ prefix_separator = "/";
+ } else {
+ prefix_separator = "";
+ }
+ suffix = grn_plugin_get_suffix();
+ }
+ ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY,
+ "%s cannot find plugin file: <%s%s%s%s>",
+ tag, prefix, prefix_separator, name, suffix);
+}
+
+grn_rc
+grn_plugin_register(grn_ctx *ctx, const char *name)
+{
+ grn_rc rc;
+ char *path;
+
+ GRN_API_ENTER;
+ path = grn_plugin_find_path(ctx, name);
+ if (path) {
+ rc = grn_plugin_register_by_path(ctx, path);
+ GRN_FREE(path);
+ } else {
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_plugin_set_name_resolve_error(ctx, name, "[plugin][register]");
+ }
+ rc = ctx->rc;
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_plugin_unregister_by_path(grn_ctx *ctx, const char *path)
+{
+ grn_obj *db;
+ grn_id plugin_id;
+
+ if (!ctx || !ctx->impl) {
+ ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] ctx isn't initialized");
+ return ctx->rc;
+ }
+
+ db = ctx->impl->db;
+ if (!db) {
+ ERR(GRN_INVALID_ARGUMENT, "[plugin][unregister] DB isn't initialized");
+ return ctx->rc;
+ }
+
+ GRN_API_ENTER;
+
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ plugin_id = grn_hash_get(&grn_plugins_ctx, grn_plugins,
+ path, GRN_PLUGIN_KEY_SIZE(path),
+ NULL);
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ if (plugin_id == GRN_ID_NIL) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ {
+ grn_table_cursor *cursor;
+ grn_id id;
+
+ cursor = grn_table_cursor_open(ctx, db,
+ NULL, 0,
+ NULL, 0,
+ 0, -1, GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ while ((id = grn_table_cursor_next(ctx, cursor))) {
+ grn_obj *obj;
+ obj = grn_ctx_at(ctx, id);
+ if (!obj) {
+ continue;
+ }
+ if (obj->header.type == GRN_PROC && DB_OBJ(obj)->range == plugin_id) {
+ grn_obj_remove(ctx, obj);
+ } else {
+ grn_obj_unlink(ctx, obj);
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_plugin_unregister(grn_ctx *ctx, const char *name)
+{
+ grn_rc rc;
+ char *path;
+
+ GRN_API_ENTER;
+ path = grn_plugin_find_path(ctx, name);
+ if (path) {
+ rc = grn_plugin_unregister_by_path(ctx, path);
+ GRN_FREE(path);
+ } else {
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_plugin_set_name_resolve_error(ctx, name, "[plugin][unregister]");
+ }
+ rc = ctx->rc;
+ }
+ GRN_API_RETURN(rc);
+}
+
+void
+grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc)
+{
+#ifdef GRN_WITH_MRUBY
+ grn_id plugin_id;
+ grn_plugin *plugin = NULL;
+
+ if (!(proc->header.flags & GRN_OBJ_CUSTOM_NAME)) {
+ return;
+ }
+
+ plugin_id = DB_OBJ(proc)->range;
+ CRITICAL_SECTION_ENTER(grn_plugins_lock);
+ {
+ const char *value;
+ value = grn_hash_get_value_(&grn_plugins_ctx, grn_plugins, plugin_id, NULL);
+ if (value) {
+ plugin = *((grn_plugin **)value);
+ }
+ }
+ CRITICAL_SECTION_LEAVE(grn_plugins_lock);
+
+ if (!plugin) {
+ return;
+ }
+
+ if (plugin->dl) {
+ return;
+ }
+
+ grn_ctx_impl_mrb_ensure_init(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ return;
+ }
+
+ if (!ctx->impl->mrb.state) {
+ return;
+ }
+
+ {
+ grn_id id;
+ int added;
+ id = DB_OBJ(proc)->id;
+ grn_hash_add(ctx, ctx->impl->mrb.checked_procs,
+ &id, sizeof(grn_id), NULL, &added);
+ if (!added) {
+ return;
+ }
+ }
+
+ ctx->impl->plugin_path = plugin->path;
+ grn_plugin_call_register_mrb(ctx, plugin_id, plugin);
+ ctx->impl->plugin_path = NULL;
+#endif /* GRN_WITH_MRUBY */
+}
+
+grn_rc
+grn_plugin_get_names(grn_ctx *ctx, grn_obj *names)
+{
+ grn_hash *processed_paths;
+ const char *system_plugins_dir;
+ const char *native_plugin_suffix;
+ const char *ruby_plugin_suffix;
+ grn_bool is_close_opened_object_mode = GRN_FALSE;
+
+ GRN_API_ENTER;
+
+ if (ctx->rc) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (grn_thread_get_limit() == 1) {
+ is_close_opened_object_mode = GRN_TRUE;
+ }
+
+ processed_paths = grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE, 0,
+ GRN_OBJ_TABLE_HASH_KEY |
+ GRN_OBJ_KEY_VAR_SIZE);
+ if (!processed_paths) {
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ system_plugins_dir = grn_plugin_get_system_plugins_dir();
+ native_plugin_suffix = grn_plugin_get_suffix();
+ ruby_plugin_suffix = grn_plugin_get_ruby_suffix();
+
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, grn_ctx_db(ctx), cursor, id,
+ GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+ const char *path;
+ grn_id processed_path_id;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (!object) {
+ ERRCLR(ctx);
+ goto next_loop;
+ }
+
+ if (!grn_obj_is_proc(ctx, object)) {
+ goto next_loop;
+ }
+
+ path = grn_obj_path(ctx, object);
+ if (!path) {
+ goto next_loop;
+ }
+
+ processed_path_id = grn_hash_get(ctx, processed_paths,
+ path, strlen(path),
+ NULL);
+ if (processed_path_id != GRN_ID_NIL) {
+ goto next_loop;
+ }
+
+ grn_hash_add(ctx, processed_paths,
+ path, strlen(path),
+ NULL, NULL);
+
+ {
+ const char *relative_path;
+ const char *libs_path = "/.libs/";
+ const char *start_libs;
+ char name[PATH_MAX];
+
+ name[0] = '\0';
+ if (strncmp(path, system_plugins_dir, strlen(system_plugins_dir)) == 0) {
+ relative_path = path + strlen(system_plugins_dir);
+ } else {
+ relative_path = path;
+ }
+ start_libs = strstr(relative_path, libs_path);
+ if (start_libs) {
+ grn_strncat(name, PATH_MAX, relative_path, start_libs - relative_path);
+ grn_strcat(name, PATH_MAX, "/");
+ grn_strcat(name, PATH_MAX, start_libs + strlen(libs_path));
+ } else {
+ grn_strcat(name, PATH_MAX, relative_path);
+ }
+ if (strlen(name) > strlen(native_plugin_suffix) &&
+ strcmp(name + strlen(name) - strlen(native_plugin_suffix),
+ native_plugin_suffix) == 0) {
+ name[strlen(name) - strlen(native_plugin_suffix)] = '\0';
+ } else if (strlen(name) > strlen(ruby_plugin_suffix) &&
+ strcmp(name + strlen(name) - strlen(ruby_plugin_suffix),
+ ruby_plugin_suffix) == 0) {
+ name[strlen(name) - strlen(ruby_plugin_suffix)] = '\0';
+ }
+ grn_vector_add_element(ctx, names,
+ name, strlen(name),
+ 0, GRN_DB_TEXT);
+ }
+
+ next_loop :
+ if (is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+
+ grn_hash_close(ctx, processed_paths);
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+void *
+grn_plugin_malloc(grn_ctx *ctx, size_t size, const char *file, int line,
+ const char *func)
+{
+ return grn_malloc(ctx, size, file, line, func);
+}
+
+void *
+grn_plugin_calloc(grn_ctx *ctx, size_t size, const char *file, int line,
+ const char *func)
+{
+ return grn_calloc(ctx, size, file, line, func);
+}
+
+void *
+grn_plugin_realloc(grn_ctx *ctx, void *ptr, size_t size,
+ const char *file, int line, const char *func)
+{
+ return grn_realloc(ctx, ptr, size, file, line, func);
+}
+
+void
+grn_plugin_free(grn_ctx *ctx, void *ptr, const char *file, int line,
+ const char *func)
+{
+ grn_free(ctx, ptr, file, line, func);
+}
+
+void
+grn_plugin_set_error(grn_ctx *ctx, grn_log_level level, grn_rc error_code,
+ const char *file, int line, const char *func,
+ const char *format, ...)
+{
+ char old_error_message[GRN_CTX_MSGSIZE];
+
+ ctx->errlvl = level;
+ ctx->rc = error_code;
+ ctx->errfile = file;
+ ctx->errline = line;
+ ctx->errfunc = func;
+
+ grn_strcpy(old_error_message, GRN_CTX_MSGSIZE, ctx->errbuf);
+
+ {
+ va_list ap;
+ va_start(ap, format);
+ grn_ctx_logv(ctx, format, ap);
+ va_end(ap);
+ }
+
+ if (grn_ctx_impl_should_log(ctx)) {
+ grn_ctx_impl_set_current_error_message(ctx);
+ if (grn_logger_pass(ctx, level)) {
+ char new_error_message[GRN_CTX_MSGSIZE];
+ grn_strcpy(new_error_message, GRN_CTX_MSGSIZE, ctx->errbuf);
+ grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, old_error_message);
+ {
+ va_list ap;
+ va_start(ap, format);
+ grn_logger_putv(ctx, level, file, line, func, format, ap);
+ va_end(ap);
+ }
+ grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, new_error_message);
+ }
+ if (level <= GRN_LOG_ERROR) {
+ grn_plugin_logtrace(ctx, level);
+ }
+ }
+}
+
+void
+grn_plugin_clear_error(grn_ctx *ctx)
+{
+ ERRCLR(ctx);
+}
+
+void
+grn_plugin_backtrace(grn_ctx *ctx)
+{
+ BACKTRACE(ctx);
+}
+
+void
+grn_plugin_logtrace(grn_ctx *ctx, grn_log_level level)
+{
+ if (level <= GRN_LOG_ERROR) {
+ grn_plugin_backtrace(ctx);
+ LOGTRACE(ctx, level);
+ }
+}
+
+struct _grn_plugin_mutex {
+ grn_critical_section critical_section;
+};
+
+grn_plugin_mutex *
+grn_plugin_mutex_open(grn_ctx *ctx)
+{
+ grn_plugin_mutex * const mutex =
+ GRN_PLUGIN_MALLOC(ctx, sizeof(grn_plugin_mutex));
+ if (mutex != NULL) {
+ CRITICAL_SECTION_INIT(mutex->critical_section);
+ }
+ return mutex;
+}
+
+grn_plugin_mutex *
+grn_plugin_mutex_create(grn_ctx *ctx)
+{
+ return grn_plugin_mutex_open(ctx);
+}
+
+void
+grn_plugin_mutex_close(grn_ctx *ctx, grn_plugin_mutex *mutex)
+{
+ if (mutex != NULL) {
+ CRITICAL_SECTION_FIN(mutex->critical_section);
+ GRN_PLUGIN_FREE(ctx, mutex);
+ }
+}
+
+void
+grn_plugin_mutex_destroy(grn_ctx *ctx, grn_plugin_mutex *mutex)
+{
+ grn_plugin_mutex_close(ctx, mutex);
+}
+
+void
+grn_plugin_mutex_lock(grn_ctx *ctx, grn_plugin_mutex *mutex)
+{
+ if (mutex != NULL) {
+ CRITICAL_SECTION_ENTER(mutex->critical_section);
+ }
+}
+
+void
+grn_plugin_mutex_unlock(grn_ctx *ctx, grn_plugin_mutex *mutex)
+{
+ if (mutex != NULL) {
+ CRITICAL_SECTION_LEAVE(mutex->critical_section);
+ }
+}
+
+grn_obj *
+grn_plugin_proc_alloc(grn_ctx *ctx, grn_user_data *user_data,
+ grn_id domain, unsigned char flags)
+{
+ return grn_proc_alloc(ctx, user_data, domain, flags);
+}
+
+grn_obj *
+grn_plugin_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data)
+{
+ return grn_proc_get_vars(ctx, user_data);
+}
+
+grn_obj *
+grn_plugin_proc_get_var(grn_ctx *ctx, grn_user_data *user_data,
+ const char *name, int name_size)
+{
+ name_size = compute_name_size(name, name_size);
+ return grn_proc_get_var(ctx, user_data, name, name_size);
+}
+
+grn_bool
+grn_plugin_proc_get_var_bool(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ grn_bool default_value)
+{
+ grn_obj *var;
+
+ var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
+ return grn_proc_option_value_bool(ctx, var, default_value);
+}
+
+int32_t
+grn_plugin_proc_get_var_int32(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ int32_t default_value)
+{
+ grn_obj *var;
+
+ var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
+ return grn_proc_option_value_int32(ctx, var, default_value);
+}
+
+const char *
+grn_plugin_proc_get_var_string(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ size_t *size)
+{
+ grn_obj *var;
+
+ var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
+ return grn_proc_option_value_string(ctx, var, size);
+}
+
+grn_content_type
+grn_plugin_proc_get_var_content_type(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *name,
+ int name_size,
+ grn_content_type default_value)
+{
+ grn_obj *var;
+
+ var = grn_plugin_proc_get_var(ctx, user_data, name, name_size);
+ return grn_proc_option_value_content_type(ctx, var, default_value);
+}
+
+grn_obj *
+grn_plugin_proc_get_var_by_offset(grn_ctx *ctx, grn_user_data *user_data,
+ unsigned int offset)
+{
+ return grn_proc_get_var_by_offset(ctx, user_data, offset);
+}
+
+grn_obj *
+grn_plugin_proc_get_caller(grn_ctx *ctx, grn_user_data *user_data)
+{
+ grn_obj *caller = NULL;
+ GRN_API_ENTER;
+ grn_proc_get_info(ctx, user_data, NULL, NULL, &caller);
+ GRN_API_RETURN(caller);
+}
+
+const char *
+grn_plugin_win32_base_dir(void)
+{
+ return grn_plugin_windows_base_dir();
+}
+
+const char *
+grn_plugin_windows_base_dir(void)
+{
+#ifdef WIN32
+ return grn_windows_base_dir();
+#else /* WIN32 */
+ return NULL;
+#endif /* WIN32 */
+}
+
+/*
+ grn_plugin_charlen() takes the length of a string, unlike grn_charlen_().
+ */
+int
+grn_plugin_charlen(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding)
+{
+ return grn_charlen_(ctx, str_ptr, str_ptr + str_length, encoding);
+}
+
+/*
+ grn_plugin_isspace() takes the length of a string, unlike grn_isspace().
+ */
+int
+grn_plugin_isspace(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding)
+{
+ if ((str_ptr == NULL) || (str_length == 0)) {
+ return 0;
+ }
+ switch ((unsigned char)str_ptr[0]) {
+ case ' ' :
+ case '\f' :
+ case '\n' :
+ case '\r' :
+ case '\t' :
+ case '\v' :
+ return 1;
+ case 0x81 :
+ if ((encoding == GRN_ENC_SJIS) && (str_length >= 2) &&
+ ((unsigned char)str_ptr[1] == 0x40)) {
+ return 2;
+ }
+ break;
+ case 0xA1 :
+ if ((encoding == GRN_ENC_EUC_JP) && (str_length >= 2) &&
+ ((unsigned char)str_ptr[1] == 0xA1)) {
+ return 2;
+ }
+ break;
+ case 0xE3 :
+ if ((encoding == GRN_ENC_UTF8) && (str_length >= 3) &&
+ ((unsigned char)str_ptr[1] == 0x80) &&
+ ((unsigned char)str_ptr[2] == 0x80)) {
+ return 3;
+ }
+ break;
+ default :
+ break;
+ }
+ return 0;
+}
+
+grn_rc
+grn_plugin_expr_var_init(grn_ctx *ctx,
+ grn_expr_var *var,
+ const char *name,
+ int name_size)
+{
+ var->name = name;
+ var->name_size = compute_name_size(name, name_size);
+ GRN_TEXT_INIT(&var->value, 0);
+ return GRN_SUCCESS;
+}
+
+grn_obj *
+grn_plugin_command_create(grn_ctx *ctx,
+ const char *name,
+ int name_size,
+ grn_proc_func func,
+ unsigned int n_vars,
+ grn_expr_var *vars)
+{
+ grn_obj *proc;
+ name_size = compute_name_size(name, name_size);
+ proc = grn_proc_create(ctx, name, name_size, GRN_PROC_COMMAND,
+ func, NULL, NULL, n_vars, vars);
+ return proc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc.c b/storage/mroonga/vendor/groonga/lib/proc.c
new file mode 100644
index 00000000..8ed39961
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc.c
@@ -0,0 +1,4211 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_proc.h"
+#include "grn_ctx.h"
+#include "grn_ii.h"
+#include "grn_db.h"
+#include "grn_util.h"
+#include "grn_output.h"
+#include "grn_pat.h"
+#include "grn_geo.h"
+#include "grn_expr.h"
+#include "grn_cache.h"
+#include "grn_load.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <io.h>
+# include <share.h>
+#endif /* WIN32 */
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
+#endif
+
+/**** globals for procs ****/
+const char *grn_document_root = NULL;
+
+#define VAR GRN_PROC_GET_VAR_BY_OFFSET
+
+static double grn_between_too_many_index_match_ratio = 0.01;
+static double grn_in_values_too_many_index_match_ratio = 0.01;
+
+void
+grn_proc_init_from_env(void)
+{
+ {
+ char grn_between_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_BETWEEN_TOO_MANY_INDEX_MATCH_RATIO",
+ grn_between_too_many_index_match_ratio_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_between_too_many_index_match_ratio_env[0]) {
+ grn_between_too_many_index_match_ratio =
+ atof(grn_between_too_many_index_match_ratio_env);
+ }
+ }
+
+ {
+ char grn_in_values_too_many_index_match_ratio_env[GRN_ENV_BUFFER_SIZE];
+ grn_getenv("GRN_IN_VALUES_TOO_MANY_INDEX_MATCH_RATIO",
+ grn_in_values_too_many_index_match_ratio_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_in_values_too_many_index_match_ratio_env[0]) {
+ grn_in_values_too_many_index_match_ratio =
+ atof(grn_in_values_too_many_index_match_ratio_env);
+ }
+ }
+}
+
+/* bulk must be initialized grn_bulk or grn_msg */
+static int
+grn_bulk_put_from_file(grn_ctx *ctx, grn_obj *bulk, const char *path)
+{
+ /* FIXME: implement more smartly with grn_bulk */
+ int fd, ret = 0;
+ struct stat stat;
+ grn_open(fd, path, O_RDONLY|O_NOFOLLOW|GRN_OPEN_FLAG_BINARY);
+ if (fd == -1) {
+ switch (errno) {
+ case EACCES :
+ ERR(GRN_OPERATION_NOT_PERMITTED, "request is not allowed: <%s>", path);
+ break;
+ case ENOENT :
+ ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY, "no such file: <%s>", path);
+ break;
+#ifndef WIN32
+ case ELOOP :
+ ERR(GRN_NO_SUCH_FILE_OR_DIRECTORY,
+ "symbolic link is not allowed: <%s>", path);
+ break;
+#endif /* WIN32 */
+ default :
+ ERRNO_ERR("failed to open file: <%s>", path);
+ break;
+ }
+ return 0;
+ }
+ if (fstat(fd, &stat) != -1) {
+ char *buf, *bp;
+ off_t rest = stat.st_size;
+ if ((buf = GRN_MALLOC(rest))) {
+ ssize_t ss;
+ for (bp = buf; rest; rest -= ss, bp += ss) {
+ if ((ss = grn_read(fd, bp, rest)) == -1) { goto exit; }
+ }
+ GRN_TEXT_PUT(ctx, bulk, buf, stat.st_size);
+ ret = 1;
+ }
+ GRN_FREE(buf);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "cannot stat file: <%s>", path);
+ }
+exit :
+ grn_close(fd);
+ return ret;
+}
+
+#ifdef stat
+# undef stat
+#endif /* stat */
+
+/**** procs ****/
+
+static grn_obj *
+proc_load(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_load_input input;
+
+ input.type = grn_plugin_proc_get_var_content_type(ctx,
+ user_data,
+ "input_type",
+ -1,
+ GRN_CONTENT_JSON);
+#define INIT_STRING_ARGUMENT(member_name, arg_name) \
+ input.member_name.value = \
+ grn_plugin_proc_get_var_string(ctx, \
+ user_data, \
+ arg_name, \
+ -1, \
+ &(input.member_name.length))
+
+ INIT_STRING_ARGUMENT(table, "table");
+ INIT_STRING_ARGUMENT(columns, "columns");
+ INIT_STRING_ARGUMENT(values, "values");
+ INIT_STRING_ARGUMENT(if_exists, "ifexists");
+ INIT_STRING_ARGUMENT(each, "each");
+
+#undef INIT_STRING_ARGUMENT
+
+ input.output_ids = grn_plugin_proc_get_var_bool(ctx,
+ user_data,
+ "output_ids", -1,
+ GRN_FALSE);
+ input.output_errors = grn_plugin_proc_get_var_bool(ctx,
+ user_data,
+ "output_errors", -1,
+ GRN_FALSE);
+ input.emit_level = 1;
+
+ grn_load_internal(ctx, &input);
+ if (ctx->rc == GRN_CANCEL) {
+ ctx->impl->loader.stat = GRN_LOADER_END;
+ ctx->impl->loader.rc = GRN_SUCCESS;
+ }
+ if (ctx->impl->loader.stat != GRN_LOADER_END &&
+ !(ctx->impl->command.flags & GRN_CTX_TAIL)) {
+ grn_obj *command = grn_proc_get_info(ctx, user_data, NULL, NULL, NULL);
+ grn_ctx_set_keep_command(ctx, command);
+ } else {
+ if (ctx->impl->loader.rc != GRN_SUCCESS) {
+ ctx->rc = ctx->impl->loader.rc;
+ grn_strcpy(ctx->errbuf, GRN_CTX_MSGSIZE, ctx->impl->loader.errbuf);
+ }
+ if (grn_ctx_get_command_version(ctx) >= GRN_COMMAND_VERSION_3) {
+ int n_elements = 1;
+ if (ctx->impl->loader.output_ids) {
+ n_elements++;
+ }
+ if (ctx->impl->loader.output_errors) {
+ n_elements++;
+ }
+ GRN_OUTPUT_MAP_OPEN("result", n_elements);
+ GRN_OUTPUT_CSTR("n_loaded_records");
+ GRN_OUTPUT_INT64(ctx->impl->loader.nrecords);
+ if (ctx->impl->loader.output_ids) {
+ grn_obj *ids = &(ctx->impl->loader.ids);
+ int i, n_ids;
+
+ GRN_OUTPUT_CSTR("loaded_ids");
+ n_ids = GRN_BULK_VSIZE(ids) / sizeof(uint32_t);
+ GRN_OUTPUT_ARRAY_OPEN("loaded_ids", n_ids);
+ for (i = 0; i < n_ids; i++) {
+ GRN_OUTPUT_UINT64(GRN_UINT32_VALUE_AT(ids, i));
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+ if (ctx->impl->loader.output_errors) {
+ grn_obj *return_codes = &(ctx->impl->loader.return_codes);
+ grn_obj *error_messages = &(ctx->impl->loader.error_messages);
+ int i, n;
+
+ GRN_OUTPUT_CSTR("errors");
+ n = GRN_BULK_VSIZE(return_codes) / sizeof(int32_t);
+ GRN_OUTPUT_ARRAY_OPEN("errors", n);
+ for (i = 0; i < n; i++) {
+ const char *message;
+ unsigned int message_size;
+
+ message_size = grn_vector_get_element(ctx,
+ error_messages,
+ i,
+ &message,
+ NULL,
+ NULL);
+
+ GRN_OUTPUT_MAP_OPEN("error", 2);
+ GRN_OUTPUT_CSTR("return_code");
+ GRN_OUTPUT_INT64(GRN_INT32_VALUE_AT(return_codes, i));
+ GRN_OUTPUT_CSTR("message");
+ if (message_size == 0) {
+ GRN_OUTPUT_NULL();
+ } else {
+ GRN_OUTPUT_STR(message, message_size);
+ }
+ GRN_OUTPUT_MAP_CLOSE();
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+ GRN_OUTPUT_MAP_CLOSE();
+ } else {
+ GRN_OUTPUT_INT64(ctx->impl->loader.nrecords);
+ }
+ if (ctx->impl->loader.table) {
+ grn_db_touch(ctx, DB_OBJ(ctx->impl->loader.table)->db);
+ }
+ grn_ctx_loader_clear(ctx);
+ }
+ return NULL;
+}
+
+static grn_obj *
+proc_status(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_timeval now;
+ grn_cache *cache;
+ grn_cache_statistics statistics;
+
+ grn_timeval_now(ctx, &now);
+ cache = grn_cache_current_get(ctx);
+ grn_cache_get_statistics(ctx, cache, &statistics);
+ GRN_OUTPUT_MAP_OPEN("RESULT", 10);
+ GRN_OUTPUT_CSTR("alloc_count");
+ GRN_OUTPUT_INT32(grn_alloc_count());
+ GRN_OUTPUT_CSTR("starttime");
+ GRN_OUTPUT_INT32(grn_starttime.tv_sec);
+ GRN_OUTPUT_CSTR("start_time");
+ GRN_OUTPUT_INT32(grn_starttime.tv_sec);
+ GRN_OUTPUT_CSTR("uptime");
+ GRN_OUTPUT_INT32(now.tv_sec - grn_starttime.tv_sec);
+ GRN_OUTPUT_CSTR("version");
+ GRN_OUTPUT_CSTR(grn_get_version());
+ GRN_OUTPUT_CSTR("n_queries");
+ GRN_OUTPUT_INT64(statistics.nfetches);
+ GRN_OUTPUT_CSTR("cache_hit_rate");
+ if (statistics.nfetches == 0) {
+ GRN_OUTPUT_FLOAT(0.0);
+ } else {
+ double cache_hit_rate;
+ cache_hit_rate = (double)statistics.nhits / (double)statistics.nfetches;
+ GRN_OUTPUT_FLOAT(cache_hit_rate * 100.0);
+ }
+ GRN_OUTPUT_CSTR("command_version");
+ GRN_OUTPUT_INT32(grn_ctx_get_command_version(ctx));
+ GRN_OUTPUT_CSTR("default_command_version");
+ GRN_OUTPUT_INT32(grn_get_default_command_version());
+ GRN_OUTPUT_CSTR("max_command_version");
+ GRN_OUTPUT_INT32(GRN_COMMAND_VERSION_MAX);
+ GRN_OUTPUT_MAP_CLOSE();
+
+#ifdef USE_MEMORY_DEBUG
+ grn_alloc_info_dump(&grn_gctx);
+#endif /* USE_MEMORY_DEBUG */
+
+ return NULL;
+}
+
+#define GRN_STRLEN(s) ((s) ? strlen(s) : 0)
+
+void
+grn_proc_output_object_name(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_obj bulk;
+ int name_len;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+
+ if (obj) {
+ GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY);
+ name_len = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_SET(ctx, &bulk, name, name_len);
+ } else {
+ GRN_VOID_INIT(&bulk);
+ }
+
+ GRN_OUTPUT_OBJ(&bulk, NULL);
+ GRN_OBJ_FIN(ctx, &bulk);
+}
+
+void
+grn_proc_output_object_id_name(grn_ctx *ctx, grn_id id)
+{
+ grn_obj *obj = NULL;
+
+ if (id != GRN_ID_NIL) {
+ obj = grn_ctx_at(ctx, id);
+ }
+
+ grn_proc_output_object_name(ctx, obj);
+}
+
+static grn_obj *
+proc_missing(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ uint32_t plen;
+ grn_obj *outbuf = ctx->impl->output.buf;
+ static int grn_document_root_len = -1;
+ if (!grn_document_root) { return NULL; }
+ if (grn_document_root_len < 0) {
+ size_t l;
+ if ((l = strlen(grn_document_root)) > PATH_MAX) {
+ return NULL;
+ }
+ grn_document_root_len = (int)l;
+ if (l > 0 && grn_document_root[l - 1] == '/') { grn_document_root_len--; }
+ }
+ if ((plen = GRN_TEXT_LEN(VAR(0))) + grn_document_root_len < PATH_MAX) {
+ char path[PATH_MAX];
+ grn_memcpy(path, grn_document_root, grn_document_root_len);
+ path[grn_document_root_len] = '/';
+ grn_str_url_path_normalize(ctx,
+ GRN_TEXT_VALUE(VAR(0)),
+ GRN_TEXT_LEN(VAR(0)),
+ path + grn_document_root_len + 1,
+ PATH_MAX - grn_document_root_len - 1);
+ grn_bulk_put_from_file(ctx, outbuf, path);
+ } else {
+ uint32_t abbrlen = 32;
+ ERR(GRN_INVALID_ARGUMENT,
+ "too long path name: <%s/%.*s...> %u(%u)",
+ grn_document_root,
+ abbrlen < plen ? abbrlen : plen, GRN_TEXT_VALUE(VAR(0)),
+ plen + grn_document_root_len, PATH_MAX);
+ }
+ return NULL;
+}
+
+static grn_obj *
+proc_quit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ ctx->stat = GRN_CTX_QUITTING;
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_obj *
+proc_shutdown(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ const char *mode;
+ size_t mode_size;
+
+ mode = grn_plugin_proc_get_var_string(ctx, user_data, "mode", -1, &mode_size);
+#define MODE_EQUAL(name) \
+ (mode_size == strlen(name) && memcmp(mode, name, mode_size) == 0)
+ if (mode_size == 0 || MODE_EQUAL("graceful")) {
+ /* Do nothing. This is the default. */
+ } else if (MODE_EQUAL("immediate")) {
+ grn_request_canceler_cancel_all();
+ if (ctx->rc == GRN_INTERRUPTED_FUNCTION_CALL) {
+ ctx->rc = GRN_SUCCESS;
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[shutdown] mode must be <graceful> or <immediate>: <%.*s>",
+ (int)mode_size, mode);
+ }
+#undef MODE_EQUAL
+
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_gctx.stat = GRN_CTX_QUIT;
+ ctx->stat = GRN_CTX_QUITTING;
+ }
+
+ GRN_OUTPUT_BOOL(!ctx->rc);
+
+ return NULL;
+}
+
+static grn_obj *
+proc_defrag(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ int olen, threshold;
+ olen = GRN_TEXT_LEN(VAR(0));
+
+ if (olen) {
+ obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), olen);
+ } else {
+ obj = ctx->impl->db;
+ }
+
+ threshold = GRN_TEXT_LEN(VAR(1))
+ ? grn_atoi(GRN_TEXT_VALUE(VAR(1)), GRN_BULK_CURR(VAR(1)), NULL)
+ : 0;
+
+ if (obj) {
+ grn_obj_defrag(ctx, obj, threshold);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "defrag object not found");
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_obj *
+proc_log_level(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *level_name = VAR(0);
+ if (GRN_TEXT_LEN(level_name) > 0) {
+ grn_log_level max_level;
+ GRN_TEXT_PUTC(ctx, level_name, '\0');
+ if (grn_log_level_parse(GRN_TEXT_VALUE(level_name), &max_level)) {
+ grn_logger_set_max_level(ctx, max_level);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "invalid log level: <%s>", GRN_TEXT_VALUE(level_name));
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "log level is missing");
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_obj *
+proc_log_put(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *level_name = VAR(0);
+ grn_obj *message = VAR(1);
+ if (GRN_TEXT_LEN(level_name) > 0) {
+ grn_log_level level;
+ GRN_TEXT_PUTC(ctx, level_name, '\0');
+ if (grn_log_level_parse(GRN_TEXT_VALUE(level_name), &level)) {
+ GRN_LOG(ctx, level, "%.*s",
+ (int)GRN_TEXT_LEN(message),
+ GRN_TEXT_VALUE(message));
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "invalid log level: <%s>", GRN_TEXT_VALUE(level_name));
+ }
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "log level is missing");
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_obj *
+proc_log_reopen(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_log_reopen(ctx);
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_rc
+proc_delete_validate_selector(grn_ctx *ctx, grn_obj *table, grn_obj *table_name,
+ grn_obj *key, grn_obj *id, grn_obj *filter)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ if (!table) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] table doesn't exist: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
+ return rc;
+ }
+
+ if (GRN_TEXT_LEN(key) == 0 &&
+ GRN_TEXT_LEN(id) == 0 &&
+ GRN_TEXT_LEN(filter) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] either key, id or filter must be specified: "
+ "table: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
+ return rc;
+ }
+
+ if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] "
+ "record selector must be one of key, id and filter: "
+ "table: <%.*s>, key: <%.*s>, id: <%.*s>, filter: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
+ (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
+ (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
+ return rc;
+ }
+
+ if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] "
+ "can't use both key and id: table: <%.*s>, key: <%.*s>, id: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
+ (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id));
+ return rc;
+ }
+
+ if (GRN_TEXT_LEN(key) && GRN_TEXT_LEN(id) == 0 && GRN_TEXT_LEN(filter)) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] "
+ "can't use both key and filter: "
+ "table: <%.*s>, key: <%.*s>, filter: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key),
+ (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
+ return rc;
+ }
+
+ if (GRN_TEXT_LEN(key) == 0 && GRN_TEXT_LEN(id) && GRN_TEXT_LEN(filter)) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] "
+ "can't use both id and filter: "
+ "table: <%.*s>, id: <%.*s>, filter: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
+ (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter));
+ return rc;
+ }
+
+ return rc;
+}
+
+static grn_obj *
+proc_delete(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ grn_obj *table_name = VAR(0);
+ grn_obj *key = VAR(1);
+ grn_obj *id = VAR(2);
+ grn_obj *filter = VAR(3);
+ grn_obj *table = NULL;
+
+ if (GRN_TEXT_LEN(table_name) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc, "[table][record][delete] table name isn't specified");
+ goto exit;
+ }
+
+ table = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(table_name),
+ GRN_TEXT_LEN(table_name));
+ rc = proc_delete_validate_selector(ctx, table, table_name, key, id, filter);
+ if (rc != GRN_SUCCESS) { goto exit; }
+
+ if (GRN_TEXT_LEN(key)) {
+ grn_obj casted_key;
+ if (key->header.domain != table->header.domain) {
+ GRN_OBJ_INIT(&casted_key, GRN_BULK, 0, table->header.domain);
+ grn_obj_cast(ctx, key, &casted_key, GRN_FALSE);
+ key = &casted_key;
+ }
+ if (ctx->rc) {
+ rc = ctx->rc;
+ } else {
+ rc = grn_table_delete(ctx, table, GRN_BULK_HEAD(key), GRN_BULK_VSIZE(key));
+ if (key == &casted_key) {
+ GRN_OBJ_FIN(ctx, &casted_key);
+ }
+ }
+ } else if (GRN_TEXT_LEN(id)) {
+ const char *end;
+ grn_id parsed_id = grn_atoui(GRN_TEXT_VALUE(id), GRN_BULK_CURR(id), &end);
+ if (end == GRN_BULK_CURR(id)) {
+ rc = grn_table_delete_by_id(ctx, table, parsed_id);
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ ERR(rc,
+ "[table][record][delete] id should be number: "
+ "table: <%.*s>, id: <%.*s>, detail: <%.*s|%c|%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(id), GRN_TEXT_VALUE(id),
+ (int)(end - GRN_TEXT_VALUE(id)), GRN_TEXT_VALUE(id),
+ end[0],
+ (int)(GRN_TEXT_VALUE(id) - end - 1), end + 1);
+ }
+ } else if (GRN_TEXT_LEN(filter)) {
+ grn_obj *cond, *v;
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, cond, v);
+ grn_expr_parse(ctx, cond,
+ GRN_TEXT_VALUE(filter),
+ GRN_TEXT_LEN(filter),
+ NULL, GRN_OP_MATCH, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc) {
+ rc = ctx->rc;
+ ERR(rc,
+ "[table][record][delete] failed to parse filter: "
+ "table: <%.*s>, filter: <%.*s>, detail: <%s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(filter), GRN_TEXT_VALUE(filter),
+ ctx->errbuf);
+ } else {
+ grn_obj *records;
+
+ records = grn_table_select(ctx, table, cond, NULL, GRN_OP_OR);
+ if (records) {
+ GRN_TABLE_EACH_BEGIN(ctx, records, cursor, result_id) {
+ void *key;
+ grn_id id;
+ grn_rc sub_rc;
+
+ if (grn_table_cursor_get_key(ctx, cursor, &key) == 0) {
+ continue;
+ }
+
+ id = *(grn_id *)key;
+ sub_rc = grn_table_delete_by_id(ctx, table, id);
+ if (rc == GRN_SUCCESS) {
+ rc = sub_rc;
+ }
+ if (ctx->rc == GRN_CANCEL) {
+ break;
+ }
+ if (ctx->rc != GRN_SUCCESS) {
+ ERRCLR(ctx);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_obj_unlink(ctx, records);
+ }
+ }
+ grn_obj_unlink(ctx, cond);
+ }
+
+exit :
+ if (table) {
+ grn_obj_unlink(ctx, table);
+ }
+ GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
+ return NULL;
+}
+
+grn_bool
+grn_proc_option_value_bool(grn_ctx *ctx,
+ grn_obj *option,
+ grn_bool default_value)
+{
+ const char *value;
+ size_t value_length;
+
+ if (!option) {
+ return default_value;
+ }
+
+ value = GRN_TEXT_VALUE(option);
+ value_length = GRN_TEXT_LEN(option);
+
+ if (value_length == 0) {
+ return default_value;
+ }
+
+ if (value_length == strlen("yes") &&
+ strncmp(value, "yes", value_length) == 0) {
+ return GRN_TRUE;
+ } else if (value_length == strlen("no") &&
+ strncmp(value, "no", value_length) == 0) {
+ return GRN_FALSE;
+ } else {
+ return default_value;
+ }
+}
+
+int32_t
+grn_proc_option_value_int32(grn_ctx *ctx,
+ grn_obj *option,
+ int32_t default_value)
+{
+ const char *value;
+ size_t value_length;
+ int32_t int32_value;
+ const char *rest;
+
+ if (!option) {
+ return default_value;
+ }
+
+ value = GRN_TEXT_VALUE(option);
+ value_length = GRN_TEXT_LEN(option);
+
+ if (value_length == 0) {
+ return default_value;
+ }
+
+ int32_value = grn_atoi(value, value + value_length, &rest);
+ if (rest == value + value_length) {
+ return int32_value;
+ } else {
+ return default_value;
+ }
+}
+
+const char *
+grn_proc_option_value_string(grn_ctx *ctx,
+ grn_obj *option,
+ size_t *size)
+{
+ const char *value;
+ size_t value_length;
+
+ if (!option) {
+ if (size) {
+ *size = 0;
+ }
+ return NULL;
+ }
+
+ value = GRN_TEXT_VALUE(option);
+ value_length = GRN_TEXT_LEN(option);
+
+ if (size) {
+ *size = value_length;
+ }
+
+ if (value_length == 0) {
+ return NULL;
+ } else {
+ return value;
+ }
+}
+
+grn_content_type
+grn_proc_option_value_content_type(grn_ctx *ctx,
+ grn_obj *option,
+ grn_content_type default_value)
+{
+ if (!option) {
+ return default_value;
+ }
+
+ return grn_content_type_parse(ctx, option, default_value);
+}
+
+static grn_obj *
+proc_cache_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_cache *cache;
+ unsigned int current_max_n_entries;
+
+ cache = grn_cache_current_get(ctx);
+ current_max_n_entries = grn_cache_get_max_n_entries(ctx, cache);
+ if (GRN_TEXT_LEN(VAR(0))) {
+ const char *rest;
+ uint32_t max = grn_atoui(GRN_TEXT_VALUE(VAR(0)),
+ GRN_BULK_CURR(VAR(0)), &rest);
+ if (GRN_BULK_CURR(VAR(0)) == rest) {
+ grn_cache_set_max_n_entries(ctx, cache, max);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "max value is invalid unsigned integer format: <%.*s>",
+ (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
+ }
+ }
+ if (ctx->rc == GRN_SUCCESS) {
+ GRN_OUTPUT_INT64(current_max_n_entries);
+ }
+ return NULL;
+}
+
+static grn_obj *
+proc_register(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ if (GRN_TEXT_LEN(VAR(0))) {
+ const char *name;
+ GRN_TEXT_PUTC(ctx, VAR(0), '\0');
+ name = GRN_TEXT_VALUE(VAR(0));
+ grn_plugin_register(ctx, name);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "path is required");
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+void grn_ii_buffer_check(grn_ctx *ctx, grn_ii *ii, uint32_t seg);
+
+static grn_obj *
+proc_check(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(VAR(0)), GRN_TEXT_LEN(VAR(0)));
+ if (!obj) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "no such object: <%.*s>", (int)GRN_TEXT_LEN(VAR(0)), GRN_TEXT_VALUE(VAR(0)));
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ } else {
+ switch (obj->header.type) {
+ case GRN_DB :
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ grn_pat_check(ctx, (grn_pat *)obj);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ grn_hash_check(ctx, (grn_hash *)obj);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ case GRN_COLUMN_FIX_SIZE :
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ grn_ja_check(ctx, (grn_ja *)obj);
+ break;
+ case GRN_COLUMN_INDEX :
+ {
+ grn_ii *ii = (grn_ii *)obj;
+ struct grn_ii_header *h = ii->header;
+ char buf[8];
+ GRN_OUTPUT_ARRAY_OPEN("RESULT", 8);
+ {
+ uint32_t i, j, g =0, a = 0, b = 0;
+ uint32_t max = 0;
+ for (i = h->bgqtail; i != h->bgqhead; i = ((i + 1) & (GRN_II_BGQSIZE - 1))) {
+ j = h->bgqbody[i];
+ g++;
+ if (j > max) { max = j; }
+ }
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ j = h->binfo[i];
+ if (j != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (j > max) { max = j; }
+ b++;
+ }
+ }
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ j = h->ainfo[i];
+ if (j != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (j > max) { max = j; }
+ a++;
+ }
+ }
+ GRN_OUTPUT_MAP_OPEN("SUMMARY", 12);
+ GRN_OUTPUT_CSTR("flags");
+ grn_itoh(h->flags, buf, 8);
+ GRN_OUTPUT_STR(buf, 8);
+ GRN_OUTPUT_CSTR("max sid");
+ GRN_OUTPUT_INT64(h->smax);
+ GRN_OUTPUT_CSTR("number of garbage segments");
+ GRN_OUTPUT_INT64(g);
+ GRN_OUTPUT_CSTR("number of array segments");
+ GRN_OUTPUT_INT64(a);
+ GRN_OUTPUT_CSTR("max id of array segment");
+ GRN_OUTPUT_INT64(h->amax);
+ GRN_OUTPUT_CSTR("number of buffer segments");
+ GRN_OUTPUT_INT64(b);
+ GRN_OUTPUT_CSTR("max id of buffer segment");
+ GRN_OUTPUT_INT64(h->bmax);
+ GRN_OUTPUT_CSTR("max id of physical segment in use");
+ GRN_OUTPUT_INT64(max);
+ GRN_OUTPUT_CSTR("number of unmanaged segments");
+ GRN_OUTPUT_INT64(h->pnext - a - b - g);
+ GRN_OUTPUT_CSTR("total chunk size");
+ GRN_OUTPUT_INT64(h->total_chunk_size);
+ for (max = 0, i = 0; i < (GRN_II_MAX_CHUNK >> 3); i++) {
+ if ((j = h->chunks[i])) {
+ int k;
+ for (k = 0; k < 8; k++) {
+ if ((j & (1 << k))) { max = (i << 3) + j; }
+ }
+ }
+ }
+ GRN_OUTPUT_CSTR("max id of chunk segments in use");
+ GRN_OUTPUT_INT64(max);
+ GRN_OUTPUT_CSTR("number of garbage chunk");
+ GRN_OUTPUT_ARRAY_OPEN("NGARBAGES", GRN_II_N_CHUNK_VARIATION);
+ for (i = 0; i <= GRN_II_N_CHUNK_VARIATION; i++) {
+ GRN_OUTPUT_INT64(h->ngarbages[i]);
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ GRN_OUTPUT_MAP_CLOSE();
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ if (h->binfo[i] < 0x20000) { grn_ii_buffer_check(ctx, ii, i); }
+ }
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+ break;
+ }
+ }
+ return NULL;
+}
+
+static grn_obj *
+proc_truncate(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ const char *target_name;
+ int target_name_len;
+
+ target_name_len = GRN_TEXT_LEN(VAR(0));
+ if (target_name_len > 0) {
+ target_name = GRN_TEXT_VALUE(VAR(0));
+ } else {
+ target_name_len = GRN_TEXT_LEN(VAR(1));
+ if (target_name_len == 0) {
+ ERR(GRN_INVALID_ARGUMENT, "[truncate] table name is missing");
+ goto exit;
+ }
+ target_name = GRN_TEXT_VALUE(VAR(1));
+ }
+
+ {
+ grn_obj *target = grn_ctx_get(ctx, target_name, target_name_len);
+ if (!target) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[truncate] no such target: <%.*s>", target_name_len, target_name);
+ goto exit;
+ }
+
+ switch (target->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ grn_table_truncate(ctx, target);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ grn_column_truncate(ctx, target);
+ break;
+ default:
+ {
+ grn_obj buffer;
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_inspect(ctx, &buffer, target);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[truncate] not a table nor column object: <%.*s>",
+ (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+ }
+ break;
+ }
+ }
+
+exit :
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static int
+parse_normalize_flags(grn_ctx *ctx, grn_obj *flag_names)
+{
+ int flags = 0;
+ const char *names, *names_end;
+ int length;
+
+ names = GRN_TEXT_VALUE(flag_names);
+ length = GRN_TEXT_LEN(flag_names);
+ names_end = names + length;
+ while (names < names_end) {
+ if (*names == '|' || *names == ' ') {
+ names += 1;
+ continue;
+ }
+
+#define CHECK_FLAG(name)\
+ if (((unsigned long) (names_end - names) >= (unsigned long) (sizeof(#name) - 1)) && \
+ (!memcmp(names, #name, sizeof(#name) - 1))) {\
+ flags |= GRN_STRING_ ## name;\
+ names += sizeof(#name) - 1;\
+ continue;\
+ }
+
+ CHECK_FLAG(REMOVE_BLANK);
+ CHECK_FLAG(WITH_TYPES);
+ CHECK_FLAG(WITH_CHECKS);
+ CHECK_FLAG(REMOVE_TOKENIZED_DELIMITER);
+
+#define GRN_STRING_NONE 0
+ CHECK_FLAG(NONE);
+#undef GRN_STRING_NONE
+
+ ERR(GRN_INVALID_ARGUMENT, "[normalize] invalid flag: <%.*s>",
+ (int)(names_end - names), names);
+ return 0;
+#undef CHECK_FLAG
+ }
+
+ return flags;
+}
+
+static grn_bool
+is_normalizer(grn_ctx *ctx, grn_obj *object)
+{
+ if (object->header.type != GRN_PROC) {
+ return GRN_FALSE;
+ }
+
+ if (grn_proc_get_type(ctx, object) != GRN_PROC_NORMALIZER) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static const char *
+char_type_name(grn_char_type type)
+{
+ const char *name = "unknown";
+
+#define CHAR_TYPE_NAME_WITH_BLANK(type_name) do { \
+ if (GRN_CHAR_IS_BLANK(type)) { \
+ name = type_name "|blank"; \
+ } else { \
+ name = type_name; \
+ } \
+ } while (GRN_FALSE)
+
+ switch (GRN_CHAR_TYPE(type)) {
+ case GRN_CHAR_NULL :
+ CHAR_TYPE_NAME_WITH_BLANK("null");
+ break;
+ case GRN_CHAR_ALPHA :
+ CHAR_TYPE_NAME_WITH_BLANK("alpha");
+ break;
+ case GRN_CHAR_DIGIT :
+ CHAR_TYPE_NAME_WITH_BLANK("digit");
+ break;
+ case GRN_CHAR_SYMBOL :
+ CHAR_TYPE_NAME_WITH_BLANK("symbol");
+ break;
+ case GRN_CHAR_HIRAGANA :
+ CHAR_TYPE_NAME_WITH_BLANK("hiragana");
+ break;
+ case GRN_CHAR_KATAKANA :
+ CHAR_TYPE_NAME_WITH_BLANK("katakana");
+ break;
+ case GRN_CHAR_KANJI :
+ CHAR_TYPE_NAME_WITH_BLANK("kanji");
+ break;
+ case GRN_CHAR_OTHERS :
+ CHAR_TYPE_NAME_WITH_BLANK("others");
+ break;
+ default :
+ CHAR_TYPE_NAME_WITH_BLANK("unknown");
+ break;
+ }
+
+#undef CHAR_TYPE_NAME_WITH_BLANK
+
+ return name;
+}
+
+static grn_obj *
+proc_normalize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *normalizer_name;
+ grn_obj *string;
+ grn_obj *flag_names;
+
+ normalizer_name = VAR(0);
+ string = VAR(1);
+ flag_names = VAR(2);
+ if (GRN_TEXT_LEN(normalizer_name) == 0) {
+ ERR(GRN_INVALID_ARGUMENT, "normalizer name is missing");
+ return NULL;
+ }
+
+ {
+ grn_obj *normalizer;
+ grn_obj *grn_string;
+ int flags;
+ unsigned int normalized_length_in_bytes;
+ unsigned int normalized_n_characters;
+
+ flags = parse_normalize_flags(ctx, flag_names);
+ normalizer = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(normalizer_name),
+ GRN_TEXT_LEN(normalizer_name));
+ if (!normalizer) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[normalize] nonexistent normalizer: <%.*s>",
+ (int)GRN_TEXT_LEN(normalizer_name),
+ GRN_TEXT_VALUE(normalizer_name));
+ return NULL;
+ }
+
+ if (!is_normalizer(ctx, normalizer)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, normalizer);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[normalize] not normalizer: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ grn_obj_unlink(ctx, normalizer);
+ return NULL;
+ }
+
+ grn_string = grn_string_open(ctx,
+ GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
+ normalizer, flags);
+ grn_obj_unlink(ctx, normalizer);
+
+ GRN_OUTPUT_MAP_OPEN("RESULT", 3);
+ {
+ const char *normalized;
+
+ grn_string_get_normalized(ctx, grn_string,
+ &normalized,
+ &normalized_length_in_bytes,
+ &normalized_n_characters);
+ GRN_OUTPUT_CSTR("normalized");
+ GRN_OUTPUT_STR(normalized, normalized_length_in_bytes);
+ }
+ {
+ const unsigned char *types;
+
+ types = grn_string_get_types(ctx, grn_string);
+ GRN_OUTPUT_CSTR("types");
+ if (types) {
+ unsigned int i;
+ GRN_OUTPUT_ARRAY_OPEN("types", normalized_n_characters);
+ for (i = 0; i < normalized_n_characters; i++) {
+ GRN_OUTPUT_CSTR(char_type_name(types[i]));
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ } else {
+ GRN_OUTPUT_ARRAY_OPEN("types", 0);
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+ }
+ {
+ const short *checks;
+
+ checks = grn_string_get_checks(ctx, grn_string);
+ GRN_OUTPUT_CSTR("checks");
+ if (checks) {
+ unsigned int i;
+ GRN_OUTPUT_ARRAY_OPEN("checks", normalized_length_in_bytes);
+ for (i = 0; i < normalized_length_in_bytes; i++) {
+ GRN_OUTPUT_INT32(checks[i]);
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ } else {
+ GRN_OUTPUT_ARRAY_OPEN("checks", 0);
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+ }
+ GRN_OUTPUT_MAP_CLOSE();
+
+ grn_obj_unlink(ctx, grn_string);
+ }
+
+ return NULL;
+}
+
+static void
+list_proc(grn_ctx *ctx, grn_proc_type target_proc_type,
+ const char *name, const char *plural_name)
+{
+ grn_obj *db;
+ grn_table_cursor *cursor;
+ grn_obj target_procs;
+
+ db = grn_ctx_db(ctx);
+ cursor = grn_table_cursor_open(ctx, db, NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_BY_ID);
+ if (!cursor) {
+ return;
+ }
+
+ GRN_PTR_INIT(&target_procs, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ {
+ grn_id id;
+
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *obj;
+ grn_proc_type proc_type;
+
+ obj = grn_ctx_at(ctx, id);
+ if (!obj) {
+ continue;
+ }
+
+ if (obj->header.type != GRN_PROC) {
+ grn_obj_unlink(ctx, obj);
+ continue;
+ }
+
+ proc_type = grn_proc_get_type(ctx, obj);
+ if (proc_type != target_proc_type) {
+ grn_obj_unlink(ctx, obj);
+ continue;
+ }
+
+ GRN_PTR_PUT(ctx, &target_procs, obj);
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ {
+ int i, n_procs;
+
+ n_procs = GRN_BULK_VSIZE(&target_procs) / sizeof(grn_obj *);
+ GRN_OUTPUT_ARRAY_OPEN(plural_name, n_procs);
+ for (i = 0; i < n_procs; i++) {
+ grn_obj *proc;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ proc = GRN_PTR_VALUE_AT(&target_procs, i);
+ name_size = grn_obj_name(ctx, proc, name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_OUTPUT_MAP_OPEN(name, 1);
+ GRN_OUTPUT_CSTR("name");
+ GRN_OUTPUT_STR(name, name_size);
+ GRN_OUTPUT_MAP_CLOSE();
+
+ grn_obj_unlink(ctx, proc);
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+
+ grn_obj_unlink(ctx, &target_procs);
+ }
+}
+
+static grn_obj *
+proc_tokenizer_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ list_proc(ctx, GRN_PROC_TOKENIZER, "tokenizer", "tokenizers");
+ return NULL;
+}
+
+static grn_obj *
+proc_normalizer_list(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ list_proc(ctx, GRN_PROC_NORMALIZER, "normalizer", "normalizers");
+ return NULL;
+}
+
+static grn_obj *
+func_rand(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ int val;
+ grn_obj *obj;
+ if (nargs > 0) {
+ int max = GRN_INT32_VALUE(args[0]);
+ val = (int) (1.0 * max * rand() / (RAND_MAX + 1.0));
+ } else {
+ val = rand();
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_INT32, 0))) {
+ GRN_INT32_SET(ctx, obj, val);
+ }
+ return obj;
+}
+
+static grn_obj *
+func_now(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_TIME, 0))) {
+ GRN_TIME_NOW(ctx, obj);
+ }
+ return obj;
+}
+
+static inline grn_bool
+is_comparable_number_type(grn_id type)
+{
+ return GRN_DB_INT8 <= type && type <= GRN_DB_TIME;
+}
+
+static inline grn_id
+larger_number_type(grn_id type1, grn_id type2)
+{
+ if (type1 == type2) {
+ return type1;
+ }
+
+ switch (type1) {
+ case GRN_DB_FLOAT :
+ return type1;
+ case GRN_DB_TIME :
+ if (type2 == GRN_DB_FLOAT) {
+ return type2;
+ } else {
+ return type1;
+ }
+ default :
+ if (type2 > type1) {
+ return type2;
+ } else {
+ return type1;
+ }
+ }
+}
+
+static inline grn_id
+smaller_number_type(grn_id type1, grn_id type2)
+{
+ if (type1 == type2) {
+ return type1;
+ }
+
+ switch (type1) {
+ case GRN_DB_FLOAT :
+ return type1;
+ case GRN_DB_TIME :
+ if (type2 == GRN_DB_FLOAT) {
+ return type2;
+ } else {
+ return type1;
+ }
+ default :
+ {
+ grn_id smaller_number_type;
+ if (type2 > type1) {
+ smaller_number_type = type2;
+ } else {
+ smaller_number_type = type1;
+ }
+ switch (smaller_number_type) {
+ case GRN_DB_UINT8 :
+ return GRN_DB_INT8;
+ case GRN_DB_UINT16 :
+ return GRN_DB_INT16;
+ case GRN_DB_UINT32 :
+ return GRN_DB_INT32;
+ case GRN_DB_UINT64 :
+ return GRN_DB_INT64;
+ default :
+ return smaller_number_type;
+ }
+ }
+ }
+}
+
+static inline grn_bool
+is_negative_value(grn_obj *number)
+{
+ switch (number->header.domain) {
+ case GRN_DB_INT8 :
+ return GRN_INT8_VALUE(number) < 0;
+ case GRN_DB_INT16 :
+ return GRN_INT16_VALUE(number) < 0;
+ case GRN_DB_INT32 :
+ return GRN_INT32_VALUE(number) < 0;
+ case GRN_DB_INT64 :
+ return GRN_INT64_VALUE(number) < 0;
+ case GRN_DB_TIME :
+ return GRN_TIME_VALUE(number) < 0;
+ case GRN_DB_FLOAT :
+ return GRN_FLOAT_VALUE(number) < 0;
+ default :
+ return GRN_FALSE;
+ }
+}
+
+static inline grn_bool
+number_safe_cast(grn_ctx *ctx, grn_obj *src, grn_obj *dest, grn_id type)
+{
+ grn_obj_reinit(ctx, dest, type, 0);
+ if (src->header.domain == type) {
+ GRN_TEXT_SET(ctx, dest, GRN_TEXT_VALUE(src), GRN_TEXT_LEN(src));
+ return GRN_TRUE;
+ }
+
+ switch (type) {
+ case GRN_DB_UINT8 :
+ if (is_negative_value(src)) {
+ GRN_UINT8_SET(ctx, dest, 0);
+ return GRN_TRUE;
+ }
+ break;
+ case GRN_DB_UINT16 :
+ if (is_negative_value(src)) {
+ GRN_UINT16_SET(ctx, dest, 0);
+ return GRN_TRUE;
+ }
+ break;
+ case GRN_DB_UINT32 :
+ if (is_negative_value(src)) {
+ GRN_UINT32_SET(ctx, dest, 0);
+ return GRN_TRUE;
+ }
+ break;
+ case GRN_DB_UINT64 :
+ if (is_negative_value(src)) {
+ GRN_UINT64_SET(ctx, dest, 0);
+ return GRN_TRUE;
+ }
+ break;
+ }
+ return grn_obj_cast(ctx, src, dest, GRN_FALSE) == GRN_SUCCESS;
+}
+
+static inline int
+compare_number(grn_ctx *ctx, grn_obj *number1, grn_obj *number2, grn_id type)
+{
+#define COMPARE_AND_RETURN(type, value1, value2)\
+ {\
+ type computed_value1 = value1;\
+ type computed_value2 = value2;\
+ if (computed_value1 > computed_value2) {\
+ return 1;\
+ } else if (computed_value1 < computed_value2) {\
+ return -1;\
+ } else {\
+ return 0;\
+ }\
+ }
+
+ switch (type) {
+ case GRN_DB_INT8 :
+ COMPARE_AND_RETURN(int8_t,
+ GRN_INT8_VALUE(number1),
+ GRN_INT8_VALUE(number2));
+ case GRN_DB_UINT8 :
+ COMPARE_AND_RETURN(uint8_t,
+ GRN_UINT8_VALUE(number1),
+ GRN_UINT8_VALUE(number2));
+ case GRN_DB_INT16 :
+ COMPARE_AND_RETURN(int16_t,
+ GRN_INT16_VALUE(number1),
+ GRN_INT16_VALUE(number2));
+ case GRN_DB_UINT16 :
+ COMPARE_AND_RETURN(uint16_t,
+ GRN_UINT16_VALUE(number1),
+ GRN_UINT16_VALUE(number2));
+ case GRN_DB_INT32 :
+ COMPARE_AND_RETURN(int32_t,
+ GRN_INT32_VALUE(number1),
+ GRN_INT32_VALUE(number2));
+ case GRN_DB_UINT32 :
+ COMPARE_AND_RETURN(uint32_t,
+ GRN_UINT32_VALUE(number1),
+ GRN_UINT32_VALUE(number2));
+ case GRN_DB_INT64 :
+ COMPARE_AND_RETURN(int64_t,
+ GRN_INT64_VALUE(number1),
+ GRN_INT64_VALUE(number2));
+ case GRN_DB_UINT64 :
+ COMPARE_AND_RETURN(uint64_t,
+ GRN_UINT64_VALUE(number1),
+ GRN_UINT64_VALUE(number2));
+ case GRN_DB_FLOAT :
+ COMPARE_AND_RETURN(double,
+ GRN_FLOAT_VALUE(number1),
+ GRN_FLOAT_VALUE(number2));
+ case GRN_DB_TIME :
+ COMPARE_AND_RETURN(int64_t,
+ GRN_TIME_VALUE(number1),
+ GRN_TIME_VALUE(number2));
+ default :
+ return 0;
+ }
+
+#undef COMPARE_AND_RETURN
+}
+
+inline static void
+get_number_in_grn_uvector(grn_ctx *ctx, grn_obj *uvector, unsigned int offset,
+ grn_obj *buf)
+{
+#define GET_UVECTOR_ELEMENT_AS(type) do { \
+ GRN_ ## type ## _SET(ctx, \
+ buf, \
+ GRN_ ## type ## _VALUE_AT(uvector, offset)); \
+ } while (GRN_FALSE)
+ switch (uvector->header.domain) {
+ case GRN_DB_BOOL :
+ GET_UVECTOR_ELEMENT_AS(BOOL);
+ break;
+ case GRN_DB_INT8 :
+ GET_UVECTOR_ELEMENT_AS(INT8);
+ break;
+ case GRN_DB_UINT8 :
+ GET_UVECTOR_ELEMENT_AS(UINT8);
+ break;
+ case GRN_DB_INT16 :
+ GET_UVECTOR_ELEMENT_AS(INT16);
+ break;
+ case GRN_DB_UINT16 :
+ GET_UVECTOR_ELEMENT_AS(UINT16);
+ break;
+ case GRN_DB_INT32 :
+ GET_UVECTOR_ELEMENT_AS(INT32);
+ break;
+ case GRN_DB_UINT32 :
+ GET_UVECTOR_ELEMENT_AS(UINT32);
+ break;
+ case GRN_DB_INT64 :
+ GET_UVECTOR_ELEMENT_AS(INT64);
+ break;
+ case GRN_DB_UINT64 :
+ GET_UVECTOR_ELEMENT_AS(UINT64);
+ break;
+ case GRN_DB_FLOAT :
+ GET_UVECTOR_ELEMENT_AS(FLOAT);
+ break;
+ case GRN_DB_TIME :
+ GET_UVECTOR_ELEMENT_AS(TIME);
+ break;
+ default :
+ GET_UVECTOR_ELEMENT_AS(RECORD);
+ break;
+ }
+#undef GET_UVECTOR_ELEMENT_AS
+}
+
+inline static void
+apply_max(grn_ctx *ctx, grn_obj *number, grn_obj *max,
+ grn_obj *casted_number, grn_obj *casted_max, grn_id cast_type)
+{
+ grn_id domain = number->header.domain;
+ if (!is_comparable_number_type(domain)) {
+ return;
+ }
+ cast_type = larger_number_type(cast_type, domain);
+ if (!number_safe_cast(ctx, number, casted_number, cast_type)) {
+ return;
+ }
+ if (max->header.domain == GRN_DB_VOID) {
+ grn_obj_reinit(ctx, max, cast_type, 0);
+ GRN_TEXT_SET(ctx, max,
+ GRN_TEXT_VALUE(casted_number),
+ GRN_TEXT_LEN(casted_number));
+ return;
+ }
+
+ if (max->header.domain != cast_type) {
+ if (!number_safe_cast(ctx, max, casted_max, cast_type)) {
+ return;
+ }
+ grn_obj_reinit(ctx, max, cast_type, 0);
+ GRN_TEXT_SET(ctx, max,
+ GRN_TEXT_VALUE(casted_max),
+ GRN_TEXT_LEN(casted_max));
+ }
+ if (compare_number(ctx, casted_number, max, cast_type) > 0) {
+ grn_obj_reinit(ctx, max, cast_type, 0);
+ GRN_TEXT_SET(ctx, max,
+ GRN_TEXT_VALUE(casted_number),
+ GRN_TEXT_LEN(casted_number));
+ }
+}
+
+static grn_obj *
+func_max(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *max;
+ grn_id cast_type = GRN_DB_INT8;
+ grn_obj casted_max, casted_number;
+ int i;
+
+ max = GRN_PROC_ALLOC(GRN_DB_VOID, 0);
+ if (!max) {
+ return max;
+ }
+
+ GRN_VOID_INIT(&casted_max);
+ GRN_VOID_INIT(&casted_number);
+
+ for (i = 0; i < nargs; i++) {
+ switch (args[i]->header.type) {
+ case GRN_BULK :
+ apply_max(ctx, args[i], max, &casted_number, &casted_max, cast_type);
+ break;
+ case GRN_UVECTOR :
+ {
+ unsigned int j;
+ unsigned int n_elements;
+ grn_obj number_in_uvector;
+ grn_obj *domain;
+
+ domain = grn_ctx_at(ctx, args[i]->header.domain);
+ GRN_OBJ_INIT(&number_in_uvector, GRN_BULK, 0, args[i]->header.domain);
+ n_elements = grn_uvector_size(ctx, args[i]);
+ for (j = 0; j < n_elements; j++) {
+ get_number_in_grn_uvector(ctx, args[i], j, &number_in_uvector);
+ if (grn_obj_is_table(ctx, domain)) {
+ grn_obj_reinit(ctx, &number_in_uvector, domain->header.domain, 0);
+ grn_table_get_key2(ctx, domain,
+ GRN_RECORD_VALUE(&number_in_uvector),
+ &number_in_uvector);
+ }
+ apply_max(ctx, &number_in_uvector, max, &casted_number, &casted_max, cast_type);
+ }
+ GRN_OBJ_FIN(ctx, &number_in_uvector);
+ }
+ break;
+ default :
+ continue;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &casted_max);
+ GRN_OBJ_FIN(ctx, &casted_number);
+
+ return max;
+}
+
+static void
+apply_min(grn_ctx *ctx, grn_obj *number, grn_obj *min,
+ grn_obj *casted_number, grn_obj *casted_min, grn_id cast_type)
+{
+ grn_id domain = number->header.domain;
+ if (!is_comparable_number_type(domain)) {
+ return;
+ }
+ cast_type = smaller_number_type(cast_type, domain);
+ if (!number_safe_cast(ctx, number, casted_number, cast_type)) {
+ return;
+ }
+ if (min->header.domain == GRN_DB_VOID) {
+ grn_obj_reinit(ctx, min, cast_type, 0);
+ GRN_TEXT_SET(ctx, min,
+ GRN_TEXT_VALUE(casted_number),
+ GRN_TEXT_LEN(casted_number));
+ return;
+ }
+
+ if (min->header.domain != cast_type) {
+ if (!number_safe_cast(ctx, min, casted_min, cast_type)) {
+ return;
+ }
+ grn_obj_reinit(ctx, min, cast_type, 0);
+ GRN_TEXT_SET(ctx, min,
+ GRN_TEXT_VALUE(casted_min),
+ GRN_TEXT_LEN(casted_min));
+ }
+ if (compare_number(ctx, casted_number, min, cast_type) < 0) {
+ grn_obj_reinit(ctx, min, cast_type, 0);
+ GRN_TEXT_SET(ctx, min,
+ GRN_TEXT_VALUE(casted_number),
+ GRN_TEXT_LEN(casted_number));
+ }
+}
+
+static grn_obj *
+func_min(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *min;
+ grn_id cast_type = GRN_DB_INT8;
+ grn_obj casted_min, casted_number;
+ int i;
+
+ min = GRN_PROC_ALLOC(GRN_DB_VOID, 0);
+ if (!min) {
+ return min;
+ }
+
+ GRN_VOID_INIT(&casted_min);
+ GRN_VOID_INIT(&casted_number);
+ for (i = 0; i < nargs; i++) {
+ switch (args[i]->header.type) {
+ case GRN_BULK :
+ apply_min(ctx, args[i], min, &casted_number, &casted_min, cast_type);
+ break;
+ case GRN_UVECTOR :
+ {
+ unsigned int j;
+ unsigned int n_elements;
+ grn_obj number_in_uvector;
+ grn_obj *domain;
+
+ domain = grn_ctx_at(ctx, args[i]->header.domain);
+ GRN_OBJ_INIT(&number_in_uvector, GRN_BULK, 0, args[i]->header.domain);
+ n_elements = grn_uvector_size(ctx, args[i]);
+ for (j = 0; j < n_elements; j++) {
+ get_number_in_grn_uvector(ctx, args[i], j, &number_in_uvector);
+ if (grn_obj_is_table(ctx, domain)) {
+ grn_obj_reinit(ctx, &number_in_uvector, domain->header.domain, 0);
+ grn_table_get_key2(ctx, domain,
+ GRN_RECORD_VALUE(&number_in_uvector),
+ &number_in_uvector);
+ }
+ apply_min(ctx, &number_in_uvector, min, &casted_number, &casted_min, cast_type);
+ }
+ GRN_OBJ_FIN(ctx, &number_in_uvector);
+ }
+ break;
+ default :
+ continue;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &casted_min);
+ GRN_OBJ_FIN(ctx, &casted_number);
+
+ return min;
+}
+
+static grn_obj *
+func_geo_in_circle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ grn_bool r = GRN_FALSE;
+ grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
+ switch (nargs) {
+ case 4 :
+ if (grn_geo_resolve_approximate_type(ctx, args[3], &type) != GRN_SUCCESS) {
+ break;
+ }
+ /* fallthru */
+ case 3 :
+ r = grn_geo_in_circle(ctx, args[0], args[1], args[2], type);
+ break;
+ default :
+ break;
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
+ GRN_BOOL_SET(ctx, obj, r);
+ }
+ return obj;
+}
+
+static grn_obj *
+func_geo_in_rectangle(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ grn_bool r = GRN_FALSE;
+ if (nargs == 3) {
+ r = grn_geo_in_rectangle(ctx, args[0], args[1], args[2]);
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
+ GRN_BOOL_SET(ctx, obj, r);
+ }
+ return obj;
+}
+
+static grn_obj *
+func_geo_distance(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ double d = 0.0;
+ grn_geo_approximate_type type = GRN_GEO_APPROXIMATE_RECTANGLE;
+ switch (nargs) {
+ case 3 :
+ if (grn_geo_resolve_approximate_type(ctx, args[2], &type) != GRN_SUCCESS) {
+ break;
+ }
+ /* fallthru */
+ case 2 :
+ d = grn_geo_distance(ctx, args[0], args[1], type);
+ break;
+ default:
+ break;
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
+ GRN_FLOAT_SET(ctx, obj, d);
+ }
+ return obj;
+}
+
+/* deprecated. */
+static grn_obj *
+func_geo_distance2(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ double d = 0;
+ if (nargs == 2) {
+ d = grn_geo_distance_sphere(ctx, args[0], args[1]);
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
+ GRN_FLOAT_SET(ctx, obj, d);
+ }
+ return obj;
+}
+
+/* deprecated. */
+static grn_obj *
+func_geo_distance3(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *obj;
+ double d = 0;
+ if (nargs == 2) {
+ d = grn_geo_distance_ellipsoid(ctx, args[0], args[1]);
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_FLOAT, 0))) {
+ GRN_FLOAT_SET(ctx, obj, d);
+ }
+ return obj;
+}
+
+static grn_obj *
+func_all_records(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *true_value;
+ if ((true_value = GRN_PROC_ALLOC(GRN_DB_BOOL, 0))) {
+ GRN_BOOL_SET(ctx, true_value, GRN_TRUE);
+ }
+ return true_value;
+}
+
+static grn_rc
+selector_all_records(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ grn_posting posting;
+
+ memset(&posting, 0, sizeof(grn_posting));
+ GRN_TABLE_EACH(ctx, table, 0, 0, id, NULL, NULL, NULL, {
+ posting.rid = id;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, GRN_OP_OR);
+ });
+
+ return ctx->rc;
+}
+
+typedef struct {
+ grn_obj *found;
+ grn_obj *table;
+ grn_obj *records;
+} selector_to_function_data;
+
+static grn_bool
+selector_to_function_data_init(grn_ctx *ctx,
+ selector_to_function_data *data,
+ grn_user_data *user_data)
+{
+ grn_obj *condition = NULL;
+ grn_obj *variable;
+
+ data->table = NULL;
+ data->records = NULL;
+
+ data->found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
+ if (!data->found) {
+ return GRN_FALSE;
+ }
+ GRN_BOOL_SET(ctx, data->found, GRN_FALSE);
+
+ grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
+ if (!condition) {
+ return GRN_FALSE;
+ }
+
+ variable = grn_expr_get_var_by_offset(ctx, condition, 0);
+ if (!variable) {
+ return GRN_FALSE;
+ }
+
+ data->table = grn_ctx_at(ctx, variable->header.domain);
+ if (!data->table) {
+ return GRN_FALSE;
+ }
+
+ data->records = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ data->table, NULL);
+ if (!data->records) {
+ return GRN_FALSE;
+ }
+
+ {
+ grn_rset_posinfo pi;
+ unsigned int key_size;
+ memset(&pi, 0, sizeof(grn_rset_posinfo));
+ pi.rid = GRN_RECORD_VALUE(variable);
+ key_size = ((grn_hash *)(data->records))->key_size;
+ if (grn_table_add(ctx, data->records, &pi, key_size, NULL) == GRN_ID_NIL) {
+ return GRN_FALSE;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+selector_to_function_data_selected(grn_ctx *ctx,
+ selector_to_function_data *data)
+{
+ GRN_BOOL_SET(ctx, data->found, grn_table_size(ctx, data->records) > 0);
+}
+
+static void
+selector_to_function_data_fin(grn_ctx *ctx,
+ selector_to_function_data *data)
+{
+ if (data->records) {
+ grn_obj_unlink(ctx, data->records);
+ }
+}
+
+grn_operator
+grn_proc_option_value_mode(grn_ctx *ctx,
+ grn_obj *option,
+ grn_operator default_mode,
+ const char *context)
+{
+ if (option->header.domain != GRN_DB_TEXT) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, option);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s: mode must be text: <%.*s>",
+ context,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return GRN_OP_NOP;
+ }
+
+ if (GRN_TEXT_LEN(option) == 0) {
+ return default_mode;
+ }
+
+#define EQUAL_MODE(name) \
+ (GRN_TEXT_LEN(option) == strlen(name) && \
+ memcmp(GRN_TEXT_VALUE(option), name, strlen(name)) == 0)
+
+ if (EQUAL_MODE("==") || EQUAL_MODE("EQUAL")) {
+ return GRN_OP_EQUAL;
+ } else if (EQUAL_MODE("!=") || EQUAL_MODE("NOT_EQUAL")) {
+ return GRN_OP_NOT_EQUAL;
+ } else if (EQUAL_MODE("<") || EQUAL_MODE("LESS")) {
+ return GRN_OP_LESS;
+ } else if (EQUAL_MODE(">") || EQUAL_MODE("GREATER")) {
+ return GRN_OP_GREATER;
+ } else if (EQUAL_MODE("<=") || EQUAL_MODE("LESS_EQUAL")) {
+ return GRN_OP_LESS_EQUAL;
+ } else if (EQUAL_MODE(">=") || EQUAL_MODE("GREATER_EQUAL")) {
+ return GRN_OP_GREATER_EQUAL;
+ } else if (EQUAL_MODE("@") || EQUAL_MODE("MATCH")) {
+ return GRN_OP_MATCH;
+ } else if (EQUAL_MODE("*N") || EQUAL_MODE("NEAR")) {
+ return GRN_OP_NEAR;
+ } else if (EQUAL_MODE("*S") || EQUAL_MODE("SIMILAR")) {
+ return GRN_OP_SIMILAR;
+ } else if (EQUAL_MODE("^") || EQUAL_MODE("@^") || EQUAL_MODE("PREFIX")) {
+ return GRN_OP_PREFIX;
+ } else if (EQUAL_MODE("$") || EQUAL_MODE("@$") || EQUAL_MODE("SUFFIX")) {
+ return GRN_OP_SUFFIX;
+ } else if (EQUAL_MODE("~") || EQUAL_MODE("@~") || EQUAL_MODE("REGEXP")) {
+ return GRN_OP_REGEXP;
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s: mode must be one of them: "
+ "["
+ "\"==\", \"EQUAL\", "
+ "\"!=\", \"NOT_EQUAL\", "
+ "\"<\", \"LESS\", "
+ "\">\", \"GREATER\", "
+ "\"<=\", \"LESS_EQUAL\", "
+ "\">=\", \"GREATER_EQUAL\", "
+ "\"@\", \"MATCH\", "
+ "\"*N\", \"NEAR\", "
+ "\"*S\", \"SIMILAR\", "
+ "\"^\", \"@^\", \"PREFIX\", "
+ "\"$\", \"@$\", \"SUFFIX\", "
+ "\"~\", \"@~\", \"REGEXP\""
+ "]: <%.*s>",
+ context,
+ (int)GRN_TEXT_LEN(option),
+ GRN_TEXT_VALUE(option));
+ return GRN_OP_NOP;
+ }
+
+#undef EQUAL_MODE
+}
+
+static grn_rc
+run_query(grn_ctx *ctx, grn_obj *table,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *match_columns_string;
+ grn_obj *query;
+ grn_obj *query_expander_name = NULL;
+ grn_operator default_mode = GRN_OP_MATCH;
+ grn_expr_flags flags = GRN_EXPR_SYNTAX_QUERY;
+ grn_bool flags_specified = GRN_FALSE;
+ grn_obj *match_columns = NULL;
+ grn_obj *condition = NULL;
+ grn_obj *dummy_variable;
+
+ if (!(2 <= nargs && nargs <= 3)) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "query(): wrong number of arguments (%d for 2..3)", nargs);
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ match_columns_string = args[0];
+ query = args[1];
+ if (nargs > 2) {
+ grn_obj *options = args[2];
+
+ switch (options->header.type) {
+ case GRN_BULK :
+ query_expander_name = options;
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_hash_cursor *cursor;
+ void *key;
+ grn_obj *value;
+ int key_size;
+ cursor = grn_hash_cursor_open(ctx, (grn_hash *)options,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "query(): failed to open cursor for options");
+ rc = ctx->rc;
+ goto exit;
+ }
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_hash_cursor_get_key_value(ctx, cursor, &key, &key_size,
+ (void **)&value);
+
+#define KEY_EQUAL(name) \
+ (key_size == strlen(name) && memcmp(key, name, strlen(name)) == 0)
+ if (KEY_EQUAL("expander")) {
+ query_expander_name = value;
+ } else if (KEY_EQUAL("default_mode")) {
+ default_mode = grn_proc_option_value_mode(ctx,
+ value,
+ GRN_OP_MATCH,
+ "query()");
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_hash_cursor_close(ctx, cursor);
+ rc = ctx->rc;
+ goto exit;
+ }
+ } else if (KEY_EQUAL("flags")) {
+ flags_specified = GRN_TRUE;
+ flags |= grn_proc_expr_query_flags_parse(ctx,
+ GRN_TEXT_VALUE(value),
+ GRN_TEXT_LEN(value),
+ "query()");
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_hash_cursor_close(ctx, cursor);
+ rc = ctx->rc;
+ goto exit;
+ }
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "query(): unknown option name: <%.*s>",
+ key_size, (char *)key);
+ grn_hash_cursor_close(ctx, cursor);
+ rc = ctx->rc;
+ goto exit;
+ }
+#undef KEY_EQUAL
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ break;
+ default :
+ {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, options);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "query(): "
+ "3rd argument must be string or object literal: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ }
+ rc = ctx->rc;
+ goto exit;
+ }
+ }
+
+ if (!flags_specified) {
+ flags |= GRN_EXPR_ALLOW_PRAGMA | GRN_EXPR_ALLOW_COLUMN;
+ }
+
+ if (match_columns_string->header.domain == GRN_DB_TEXT &&
+ GRN_TEXT_LEN(match_columns_string) > 0) {
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, match_columns, dummy_variable);
+ if (!match_columns) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ grn_expr_parse(ctx, match_columns,
+ GRN_TEXT_VALUE(match_columns_string),
+ GRN_TEXT_LEN(match_columns_string),
+ NULL, GRN_OP_MATCH, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ rc = ctx->rc;
+ goto exit;
+ }
+ }
+
+ if (query->header.domain == GRN_DB_TEXT && GRN_TEXT_LEN(query) > 0) {
+ const char *query_string;
+ unsigned int query_string_len;
+ grn_obj expanded_query;
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, condition, dummy_variable);
+ if (!condition) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ query_string = GRN_TEXT_VALUE(query);
+ query_string_len = GRN_TEXT_LEN(query);
+
+ GRN_TEXT_INIT(&expanded_query, 0);
+ if (query_expander_name &&
+ query_expander_name->header.domain == GRN_DB_TEXT &&
+ GRN_TEXT_LEN(query_expander_name) > 0) {
+ rc = grn_proc_syntax_expand_query(ctx,
+ query_string, query_string_len,
+ flags,
+ GRN_TEXT_VALUE(query_expander_name),
+ GRN_TEXT_LEN(query_expander_name),
+ NULL, 0,
+ NULL, 0,
+ &expanded_query,
+ "[query]");
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FIN(ctx, &expanded_query);
+ goto exit;
+ }
+ query_string = GRN_TEXT_VALUE(&expanded_query);
+ query_string_len = GRN_TEXT_LEN(&expanded_query);
+ }
+ grn_expr_parse(ctx, condition,
+ query_string,
+ query_string_len,
+ match_columns, default_mode, GRN_OP_AND, flags);
+ rc = ctx->rc;
+ GRN_OBJ_FIN(ctx, &expanded_query);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ grn_table_select(ctx, table, condition, res, op);
+ rc = ctx->rc;
+ }
+
+exit :
+ if (match_columns) {
+ grn_obj_unlink(ctx, match_columns);
+ }
+ if (condition) {
+ grn_obj_unlink(ctx, condition);
+ }
+
+ return rc;
+}
+
+static grn_obj *
+func_query(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ selector_to_function_data data;
+
+ if (selector_to_function_data_init(ctx, &data, user_data)) {
+ grn_rc rc;
+ rc = run_query(ctx, data.table, nargs, args, data.records, GRN_OP_AND);
+ if (rc == GRN_SUCCESS) {
+ selector_to_function_data_selected(ctx, &data);
+ }
+ }
+ selector_to_function_data_fin(ctx, &data);
+
+ return data.found;
+}
+
+static grn_rc
+selector_query(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ return run_query(ctx, table, nargs - 1, args + 1, res, op);
+}
+
+static grn_rc
+run_sub_filter(grn_ctx *ctx, grn_obj *table,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *scope;
+ grn_obj *sub_filter_string;
+ grn_obj *scope_domain = NULL;
+ grn_obj *sub_filter = NULL;
+ grn_obj *dummy_variable = NULL;
+
+ if (nargs != 2) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "sub_filter(): wrong number of arguments (%d for 2)", nargs);
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ scope = args[0];
+ sub_filter_string = args[1];
+
+ switch (scope->header.type) {
+ case GRN_ACCESSOR :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ break;
+ default :
+ /* TODO: put inspected the 1st argument to message */
+ ERR(GRN_INVALID_ARGUMENT,
+ "sub_filter(): the 1st argument must be column or accessor");
+ rc = ctx->rc;
+ goto exit;
+ break;
+ }
+
+ scope_domain = grn_ctx_at(ctx, grn_obj_get_range(ctx, scope));
+
+ if (sub_filter_string->header.domain != GRN_DB_TEXT) {
+ /* TODO: put inspected the 2nd argument to message */
+ ERR(GRN_INVALID_ARGUMENT,
+ "sub_filter(): the 2nd argument must be String");
+ rc = ctx->rc;
+ goto exit;
+ }
+ if (GRN_TEXT_LEN(sub_filter_string) == 0) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "sub_filter(): the 2nd argument must not be empty String");
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, scope_domain, sub_filter, dummy_variable);
+ if (!sub_filter) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ grn_expr_parse(ctx, sub_filter,
+ GRN_TEXT_VALUE(sub_filter_string),
+ GRN_TEXT_LEN(sub_filter_string),
+ NULL, GRN_OP_MATCH, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ {
+ grn_obj *base_res = NULL;
+
+ base_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ scope_domain, NULL);
+ grn_table_select(ctx, scope_domain, sub_filter, base_res, GRN_OP_OR);
+ if (scope->header.type == GRN_ACCESSOR) {
+ rc = grn_accessor_resolve(ctx, scope, -1, base_res, res, op);
+ } else {
+ grn_accessor accessor;
+ accessor.header.type = GRN_ACCESSOR;
+ accessor.obj = scope;
+ accessor.action = GRN_ACCESSOR_GET_COLUMN_VALUE;
+ accessor.next = NULL;
+ rc = grn_accessor_resolve(ctx, (grn_obj *)&accessor, -1, base_res,
+ res, op);
+ }
+ grn_obj_unlink(ctx, base_res);
+ }
+
+exit :
+ if (scope_domain) {
+ grn_obj_unlink(ctx, scope_domain);
+ }
+ if (sub_filter) {
+ grn_obj_unlink(ctx, sub_filter);
+ }
+
+ return rc;
+}
+
+static grn_rc
+selector_sub_filter(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ return run_sub_filter(ctx, table, nargs - 1, args + 1, res, op);
+}
+
+static grn_obj *
+func_html_untag(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *html_arg;
+ int html_arg_domain;
+ grn_obj html;
+ grn_obj *text;
+ const char *html_raw;
+ int i, length;
+ grn_bool in_tag = GRN_FALSE;
+
+ if (nargs != 1) {
+ ERR(GRN_INVALID_ARGUMENT, "HTML is missing");
+ return NULL;
+ }
+
+ html_arg = args[0];
+ html_arg_domain = html_arg->header.domain;
+ switch (html_arg_domain) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ GRN_VALUE_VAR_SIZE_INIT(&html, GRN_OBJ_DO_SHALLOW_COPY, html_arg_domain);
+ GRN_TEXT_SET(ctx, &html, GRN_TEXT_VALUE(html_arg), GRN_TEXT_LEN(html_arg));
+ break;
+ default :
+ GRN_TEXT_INIT(&html, 0);
+ if (grn_obj_cast(ctx, html_arg, &html, GRN_FALSE)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, html_arg);
+ ERR(GRN_INVALID_ARGUMENT, "failed to cast to text: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected), GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_OBJ_FIN(ctx, &html);
+ return NULL;
+ }
+ break;
+ }
+
+ text = GRN_PROC_ALLOC(html.header.domain, 0);
+ if (!text) {
+ GRN_OBJ_FIN(ctx, &html);
+ return NULL;
+ }
+
+ html_raw = GRN_TEXT_VALUE(&html);
+ length = GRN_TEXT_LEN(&html);
+ for (i = 0; i < length; i++) {
+ switch (html_raw[i]) {
+ case '<' :
+ in_tag = GRN_TRUE;
+ break;
+ case '>' :
+ if (in_tag) {
+ in_tag = GRN_FALSE;
+ } else {
+ GRN_TEXT_PUTC(ctx, text, html_raw[i]);
+ }
+ break;
+ default :
+ if (!in_tag) {
+ GRN_TEXT_PUTC(ctx, text, html_raw[i]);
+ }
+ break;
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &html);
+
+ return text;
+}
+
+static grn_bool
+grn_text_equal_cstr(grn_ctx *ctx, grn_obj *text, const char *cstr)
+{
+ int cstr_len;
+
+ cstr_len = strlen(cstr);
+ return (GRN_TEXT_LEN(text) == cstr_len &&
+ strncmp(GRN_TEXT_VALUE(text), cstr, cstr_len) == 0);
+}
+
+typedef enum {
+ BETWEEN_BORDER_INVALID,
+ BETWEEN_BORDER_INCLUDE,
+ BETWEEN_BORDER_EXCLUDE
+} between_border_type;
+
+typedef struct {
+ grn_obj *value;
+ grn_obj *min;
+ grn_obj casted_min;
+ between_border_type min_border_type;
+ grn_obj *max;
+ grn_obj casted_max;
+ between_border_type max_border_type;
+} between_data;
+
+static void
+between_data_init(grn_ctx *ctx, between_data *data)
+{
+ GRN_VOID_INIT(&(data->casted_min));
+ GRN_VOID_INIT(&(data->casted_max));
+}
+
+static void
+between_data_fin(grn_ctx *ctx, between_data *data)
+{
+ GRN_OBJ_FIN(ctx, &(data->casted_min));
+ GRN_OBJ_FIN(ctx, &(data->casted_max));
+}
+
+static between_border_type
+between_parse_border(grn_ctx *ctx, grn_obj *border,
+ const char *argument_description)
+{
+ grn_obj inspected;
+
+ /* TODO: support other text types */
+ if (border->header.domain == GRN_DB_TEXT) {
+ if (grn_text_equal_cstr(ctx, border, "include")) {
+ return BETWEEN_BORDER_INCLUDE;
+ } else if (grn_text_equal_cstr(ctx, border, "exclude")) {
+ return BETWEEN_BORDER_EXCLUDE;
+ }
+ }
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, border);
+ ERR(GRN_INVALID_ARGUMENT,
+ "between(): %s must be \"include\" or \"exclude\": <%.*s>",
+ argument_description,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ grn_obj_unlink(ctx, &inspected);
+
+ return BETWEEN_BORDER_INVALID;
+}
+
+static grn_rc
+between_cast(grn_ctx *ctx, grn_obj *source, grn_obj *destination, grn_id domain,
+ const char *target_argument_name)
+{
+ grn_rc rc;
+
+ GRN_OBJ_INIT(destination, GRN_BULK, 0, domain);
+ rc = grn_obj_cast(ctx, source, destination, GRN_FALSE);
+ if (rc != GRN_SUCCESS) {
+ grn_obj inspected_source;
+ grn_obj *domain_object;
+ char domain_name[GRN_TABLE_MAX_KEY_SIZE];
+ int domain_name_length;
+
+ GRN_TEXT_INIT(&inspected_source, 0);
+ grn_inspect(ctx, &inspected_source, source);
+
+ domain_object = grn_ctx_at(ctx, domain);
+ domain_name_length =
+ grn_obj_name(ctx, domain_object, domain_name, GRN_TABLE_MAX_KEY_SIZE);
+
+ ERR(rc, "between(): failed to cast %s: <%.*s> -> <%.*s>",
+ target_argument_name,
+ (int)GRN_TEXT_LEN(&inspected_source),
+ GRN_TEXT_VALUE(&inspected_source),
+ domain_name_length,
+ domain_name);
+
+ grn_obj_unlink(ctx, &inspected_source);
+ grn_obj_unlink(ctx, domain_object);
+ }
+
+ return rc;
+}
+
+static grn_rc
+between_parse_args(grn_ctx *ctx, int nargs, grn_obj **args, between_data *data)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *min_border;
+ grn_obj *max_border;
+
+ if (nargs != 5) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "between(): wrong number of arguments (%d for 5)", nargs);
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ data->value = args[0];
+ data->min = args[1];
+ min_border = args[2];
+ data->max = args[3];
+ max_border = args[4];
+
+ data->min_border_type =
+ between_parse_border(ctx, min_border, "the 3rd argument (min_border)");
+ if (data->min_border_type == BETWEEN_BORDER_INVALID) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ data->max_border_type =
+ between_parse_border(ctx, max_border, "the 5th argument (max_border)");
+ if (data->max_border_type == BETWEEN_BORDER_INVALID) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ {
+ grn_id value_type;
+ switch (data->value->header.type) {
+ case GRN_BULK :
+ value_type = data->value->header.domain;
+ break;
+ case GRN_COLUMN_INDEX :
+ {
+ grn_obj *domain_object;
+ domain_object = grn_ctx_at(ctx, data->value->header.domain);
+ value_type = domain_object->header.domain;
+ }
+ break;
+ default :
+ value_type = grn_obj_get_range(ctx, data->value);
+ break;
+ }
+ if (value_type != data->min->header.domain) {
+ rc = between_cast(ctx, data->min, &data->casted_min, value_type, "min");
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ data->min = &(data->casted_min);
+ }
+
+ if (value_type != data->max->header.domain) {
+ rc = between_cast(ctx, data->max, &data->casted_max, value_type, "max");
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ data->max = &(data->casted_max);
+ }
+ }
+
+exit :
+ return rc;
+}
+
+static grn_bool
+between_create_expr(grn_ctx *ctx, grn_obj *table, between_data *data,
+ grn_obj **expr, grn_obj **variable)
+{
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, *expr, *variable);
+ if (!*expr) {
+ return GRN_FALSE;
+ }
+
+ if (data->value->header.type == GRN_BULK) {
+ grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_PUSH, 1);
+ } else {
+ grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_GET_VALUE, 1);
+ }
+ grn_expr_append_obj(ctx, *expr, data->min, GRN_OP_PUSH, 1);
+ if (data->min_border_type == BETWEEN_BORDER_INCLUDE) {
+ grn_expr_append_op(ctx, *expr, GRN_OP_GREATER_EQUAL, 2);
+ } else {
+ grn_expr_append_op(ctx, *expr, GRN_OP_GREATER, 2);
+ }
+
+ if (data->value->header.type == GRN_BULK) {
+ grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_PUSH, 1);
+ } else {
+ grn_expr_append_obj(ctx, *expr, data->value, GRN_OP_GET_VALUE, 1);
+ }
+ grn_expr_append_obj(ctx, *expr, data->max, GRN_OP_PUSH, 1);
+ if (data->max_border_type == BETWEEN_BORDER_INCLUDE) {
+ grn_expr_append_op(ctx, *expr, GRN_OP_LESS_EQUAL, 2);
+ } else {
+ grn_expr_append_op(ctx, *expr, GRN_OP_LESS, 2);
+ }
+
+ grn_expr_append_op(ctx, *expr, GRN_OP_AND, 2);
+
+ return GRN_TRUE;
+}
+
+static grn_obj *
+func_between(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *found;
+ between_data data;
+ grn_obj *condition = NULL;
+ grn_obj *variable;
+ grn_obj *table = NULL;
+ grn_obj *between_expr;
+ grn_obj *between_variable;
+ grn_obj *result;
+
+ found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
+ if (!found) {
+ return NULL;
+ }
+ GRN_BOOL_SET(ctx, found, GRN_FALSE);
+
+ grn_proc_get_info(ctx, user_data, NULL, NULL, &condition);
+ if (!condition) {
+ return found;
+ }
+
+ variable = grn_expr_get_var_by_offset(ctx, condition, 0);
+ if (!variable) {
+ return found;
+ }
+
+ between_data_init(ctx, &data);
+ rc = between_parse_args(ctx, nargs, args, &data);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ table = grn_ctx_at(ctx, variable->header.domain);
+ if (!table) {
+ goto exit;
+ }
+ if (!between_create_expr(ctx, table, &data, &between_expr, &between_variable)) {
+ goto exit;
+ }
+
+ GRN_RECORD_SET(ctx, between_variable, GRN_RECORD_VALUE(variable));
+ result = grn_expr_exec(ctx, between_expr, 0);
+ if (grn_obj_is_true(ctx, result)) {
+ GRN_BOOL_SET(ctx, found, GRN_TRUE);
+ }
+
+ grn_obj_unlink(ctx, between_expr);
+ grn_obj_unlink(ctx, table);
+
+exit :
+ between_data_fin(ctx, &data);
+ if (table) {
+ grn_obj_unlink(ctx, table);
+ }
+
+ return found;
+}
+
+static grn_bool
+selector_between_sequential_search_should_use(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ grn_obj *index_table,
+ between_data *data,
+ grn_obj *res,
+ grn_operator op,
+ double too_many_index_match_ratio)
+{
+ int n_index_keys;
+
+ if (too_many_index_match_ratio < 0.0) {
+ return GRN_FALSE;
+ }
+
+ if (op != GRN_OP_AND) {
+ return GRN_FALSE;
+ }
+
+ if (!index) {
+ return GRN_FALSE;
+ }
+
+ if (index->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ return GRN_FALSE;
+ }
+
+ if (data->value->header.type == GRN_COLUMN_INDEX) {
+ return GRN_FALSE;
+ }
+
+ n_index_keys = grn_table_size(ctx, index_table);
+ if (n_index_keys == 0) {
+ return GRN_FALSE;
+ }
+
+ switch (index_table->header.domain) {
+ /* TODO: */
+ /* case GRN_DB_INT8 : */
+ /* case GRN_DB_UINT8 : */
+ /* case GRN_DB_INT16 : */
+ /* case GRN_DB_UINT16 : */
+ /* case GRN_DB_INT32 : */
+ /* case GRN_DB_UINT32 : */
+ /* case GRN_DB_INT64 : */
+ /* case GRN_DB_UINT64 : */
+ /* case GRN_DB_FLOAT : */
+ case GRN_DB_TIME :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+
+ {
+ grn_table_cursor *cursor;
+ long long int all_min;
+ long long int all_max;
+ cursor = grn_table_cursor_open(ctx, index_table,
+ NULL, -1,
+ NULL, -1,
+ 0, 1,
+ GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+ if (grn_table_cursor_next(ctx, cursor) == GRN_ID_NIL) {
+ grn_table_cursor_close(ctx, cursor);
+ return GRN_FALSE;
+ }
+ {
+ long long int *key;
+ grn_table_cursor_get_key(ctx, cursor, (void **)&key);
+ all_min = *key;
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ cursor = grn_table_cursor_open(ctx, index_table,
+ NULL, 0, NULL, 0,
+ 0, 1,
+ GRN_CURSOR_BY_KEY | GRN_CURSOR_DESCENDING);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+ if (grn_table_cursor_next(ctx, cursor) == GRN_ID_NIL) {
+ grn_table_cursor_close(ctx, cursor);
+ return GRN_FALSE;
+ }
+ {
+ long long int *key;
+ grn_table_cursor_get_key(ctx, cursor, (void **)&key);
+ all_max = *key;
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ /*
+ * We assume the following:
+ * * homogeneous index key distribution.
+ * * each index key matches only 1 record.
+ * TODO: Improve me.
+ */
+ {
+ int n_existing_records;
+ int n_indexed_records;
+ long long int all_difference;
+ long long int argument_difference;
+
+ n_existing_records = grn_table_size(ctx, res);
+
+ all_difference = all_max - all_min;
+ if (all_difference <= 0) {
+ return GRN_FALSE;
+ }
+ argument_difference =
+ GRN_TIME_VALUE(data->max) - GRN_TIME_VALUE(data->min);
+ if (argument_difference <= 0) {
+ return GRN_FALSE;
+ }
+ n_indexed_records =
+ n_index_keys * ((double)argument_difference / (double)all_difference);
+
+ /*
+ * Same as:
+ * ((n_existing_record / n_indexed_records) > too_many_index_match_ratio)
+ */
+ if (n_existing_records > (n_indexed_records * too_many_index_match_ratio)) {
+ return GRN_FALSE;
+ }
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_rc
+selector_between_sequential_search(grn_ctx *ctx,
+ grn_obj *table,
+ between_data *data,
+ grn_obj *res,
+ grn_operator op)
+{
+ {
+ int offset = 0;
+ int limit = -1;
+ int flags = 0;
+ grn_obj *target_table;
+ grn_obj *target_column;
+ grn_operator_exec_func *greater;
+ grn_operator_exec_func *less;
+ grn_table_cursor *cursor;
+ grn_id id;
+ grn_obj value;
+
+ if (op == GRN_OP_AND) {
+ target_table = res;
+ } else {
+ target_table = table;
+ }
+ cursor = grn_table_cursor_open(ctx, target_table,
+ NULL, 0,
+ NULL, 0,
+ offset, limit, flags);
+ if (!cursor) {
+ return ctx->rc;
+ }
+
+ if (data->value->header.type == GRN_BULK) {
+ target_column = grn_obj_column(ctx,
+ table,
+ GRN_TEXT_VALUE(data->value),
+ GRN_TEXT_LEN(data->value));
+ } else {
+ target_column = data->value;
+ }
+ if (data->min_border_type == BETWEEN_BORDER_INCLUDE) {
+ greater = grn_operator_exec_greater_equal;
+ } else {
+ greater = grn_operator_exec_greater;
+ }
+ if (data->max_border_type == BETWEEN_BORDER_INCLUDE) {
+ less = grn_operator_exec_less_equal;
+ } else {
+ less = grn_operator_exec_less;
+ }
+
+ GRN_VOID_INIT(&value);
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_id record_id;
+
+ if (target_table == res) {
+ grn_id *key;
+ grn_table_cursor_get_key(ctx, cursor, (void **)&key);
+ record_id = *key;
+ } else {
+ record_id = id;
+ }
+
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, target_column, record_id, &value);
+ if (greater(ctx, &value, data->min) && less(ctx, &value, data->max)) {
+ grn_posting posting;
+ posting.rid = record_id;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &value);
+
+ if (target_column != data->value &&
+ target_column->header.type == GRN_ACCESSOR) {
+ grn_obj_unlink(ctx, target_column);
+ }
+
+ grn_table_cursor_close(ctx, cursor);
+
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+selector_between(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ int nargs,
+ grn_obj **args,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ int offset = 0;
+ int limit = -1;
+ int flags = GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_KEY;
+ between_data data;
+ grn_bool use_sequential_search;
+ grn_obj *index_table = NULL;
+ grn_table_cursor *cursor;
+ grn_id id;
+
+ between_data_init(ctx, &data);
+ rc = between_parse_args(ctx, nargs - 1, args + 1, &data);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ if (data.min_border_type == BETWEEN_BORDER_EXCLUDE) {
+ flags |= GRN_CURSOR_GT;
+ }
+ if (data.max_border_type == BETWEEN_BORDER_EXCLUDE) {
+ flags |= GRN_CURSOR_LT;
+ }
+
+ if (data.value->header.type == GRN_COLUMN_INDEX) {
+ index = data.value;
+ }
+
+ if (index) {
+ switch (index->header.type) {
+ case GRN_TABLE_NO_KEY :
+ case GRN_TABLE_HASH_KEY :
+ break;
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ index_table = index;
+ index = NULL;
+ break;
+ default :
+ index_table = grn_ctx_at(ctx, index->header.domain);
+ break;
+ }
+ }
+
+ if (index_table) {
+ double ratio = grn_between_too_many_index_match_ratio;
+ use_sequential_search =
+ selector_between_sequential_search_should_use(ctx,
+ table,
+ index,
+ index_table,
+ &data,
+ res,
+ op,
+ ratio);
+ } else {
+ use_sequential_search = GRN_TRUE;
+ }
+ if (use_sequential_search) {
+ rc = selector_between_sequential_search(ctx, table, &data, res, op);
+ goto exit;
+ }
+
+ cursor = grn_table_cursor_open(ctx, index_table,
+ GRN_BULK_HEAD(data.min),
+ GRN_BULK_VSIZE(data.min),
+ GRN_BULK_HEAD(data.max),
+ GRN_BULK_VSIZE(data.max),
+ offset, limit, flags);
+ if (!cursor) {
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ if (index) {
+ while ((id = grn_table_cursor_next(ctx, cursor))) {
+ grn_ii_at(ctx, (grn_ii *)index, id, (grn_hash *)res, op);
+ }
+ } else {
+ grn_posting posting;
+ memset(&posting, 0, sizeof(grn_posting));
+ posting.sid = 1;
+ posting.pos = 0;
+ while ((id = grn_table_cursor_next(ctx, cursor))) {
+ posting.rid = id;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ grn_table_cursor_close(ctx, cursor);
+
+exit :
+ between_data_fin(ctx, &data);
+
+ return rc;
+}
+
+static grn_obj *
+func_in_values(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *found;
+ grn_obj *target_value;
+ int i;
+
+ found = GRN_PROC_ALLOC(GRN_DB_BOOL, 0);
+ if (!found) {
+ return NULL;
+ }
+ GRN_BOOL_SET(ctx, found, GRN_FALSE);
+
+ if (nargs < 1) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "in_values(): wrong number of arguments (%d for 1..)", nargs);
+ return found;
+ }
+
+ target_value = args[0];
+ for (i = 1; i < nargs; i++) {
+ grn_obj *value = args[i];
+ grn_bool result;
+
+ result = grn_operator_exec_equal(ctx, target_value, value);
+ if (ctx->rc) {
+ break;
+ }
+
+ if (result) {
+ GRN_BOOL_SET(ctx, found, GRN_TRUE);
+ break;
+ }
+ }
+
+ return found;
+}
+
+static grn_bool
+is_reference_type_column(grn_ctx *ctx, grn_obj *column)
+{
+ grn_bool is_reference_type;
+ grn_obj *range;
+
+ range = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
+ switch (range->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ is_reference_type = GRN_TRUE;
+ break;
+ default :
+ is_reference_type = GRN_FALSE;
+ break;
+ }
+ grn_obj_unlink(ctx, range);
+
+ return is_reference_type;
+}
+
+static grn_obj *
+selector_in_values_find_source(grn_ctx *ctx, grn_obj *index, grn_obj *res)
+{
+ grn_id source_id = GRN_ID_NIL;
+ grn_obj source_ids;
+ unsigned int n_source_ids;
+
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+ grn_obj_get_info(ctx, index, GRN_INFO_SOURCE, &source_ids);
+ n_source_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+ if (n_source_ids == 1) {
+ source_id = GRN_UINT32_VALUE_AT(&source_ids, 0);
+ }
+ GRN_OBJ_FIN(ctx, &source_ids);
+
+ if (source_id == GRN_ID_NIL) {
+ return NULL;
+ } else {
+ return grn_ctx_at(ctx, source_id);
+ }
+}
+
+static grn_bool
+selector_in_values_sequential_search(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ int n_values,
+ grn_obj **values,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_obj *source;
+ int n_existing_records;
+
+ if (grn_in_values_too_many_index_match_ratio < 0.0) {
+ return GRN_FALSE;
+ }
+
+ if (op != GRN_OP_AND) {
+ return GRN_FALSE;
+ }
+
+ if (index->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ return GRN_FALSE;
+ }
+
+ n_existing_records = grn_table_size(ctx, res);
+ if (n_existing_records == 0) {
+ return GRN_TRUE;
+ }
+
+ source = selector_in_values_find_source(ctx, index, res);
+ if (!source) {
+ return GRN_FALSE;
+ }
+
+ if (!is_reference_type_column(ctx, source)) {
+ grn_obj_unlink(ctx, source);
+ return GRN_FALSE;
+ }
+
+ {
+ grn_obj value_ids;
+ int i, n_value_ids;
+ int n_indexed_records = 0;
+
+ {
+ grn_id range_id;
+ grn_obj *range;
+
+ range_id = grn_obj_get_range(ctx, source);
+ range = grn_ctx_at(ctx, range_id);
+ if (!range) {
+ grn_obj_unlink(ctx, source);
+ return GRN_FALSE;
+ }
+
+ GRN_RECORD_INIT(&value_ids, GRN_OBJ_VECTOR, range_id);
+ for (i = 0; i < n_values; i++) {
+ grn_obj *value = values[i];
+ grn_id value_id;
+
+ value_id = grn_table_get(ctx, range,
+ GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
+ if (value_id == GRN_ID_NIL) {
+ continue;
+ }
+ GRN_RECORD_PUT(ctx, &value_ids, value_id);
+ }
+ grn_obj_unlink(ctx, range);
+ }
+
+ n_value_ids = GRN_BULK_VSIZE(&value_ids) / sizeof(grn_id);
+ for (i = 0; i < n_value_ids; i++) {
+ grn_id value_id = GRN_RECORD_VALUE_AT(&value_ids, i);
+ n_indexed_records += grn_ii_estimate_size(ctx, (grn_ii *)index, value_id);
+ }
+
+ /*
+ * Same as:
+ * ((n_existing_record / n_indexed_records) >
+ * grn_in_values_too_many_index_match_ratio)
+ */
+ if (n_existing_records >
+ (n_indexed_records * grn_in_values_too_many_index_match_ratio)) {
+ grn_obj_unlink(ctx, &value_ids);
+ grn_obj_unlink(ctx, source);
+ return GRN_FALSE;
+ }
+
+ {
+ grn_obj *accessor;
+ char local_source_name[GRN_TABLE_MAX_KEY_SIZE];
+ int local_source_name_length;
+
+ local_source_name_length = grn_column_name(ctx, source,
+ local_source_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ grn_obj_unlink(ctx, source);
+ accessor = grn_obj_column(ctx, res,
+ local_source_name,
+ local_source_name_length);
+ {
+ grn_table_cursor *cursor;
+ grn_id id;
+ grn_obj record_value;
+
+ GRN_VOID_INIT(&record_value);
+ cursor = grn_table_cursor_open(ctx, res,
+ NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_ASCENDING);
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_id *record_id;
+ grn_table_cursor_get_key(ctx, cursor, (void **)&record_id);
+ GRN_BULK_REWIND(&record_value);
+ grn_obj_get_value(ctx, accessor, id, &record_value);
+ for (i = 0; i < n_value_ids; i++) {
+ grn_id value_id = GRN_RECORD_VALUE_AT(&value_ids, i);
+ switch (record_value.header.type) {
+ case GRN_BULK :
+ if (value_id == GRN_RECORD_VALUE(&record_value)) {
+ grn_posting posting;
+ posting.rid = *record_id;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ break;
+ case GRN_UVECTOR :
+ {
+ int j, n_elements;
+ n_elements = GRN_BULK_VSIZE(&record_value) / sizeof(grn_id);
+ for (j = 0; j < n_elements; j++) {
+ if (value_id == GRN_RECORD_VALUE_AT(&record_value, j)) {
+ grn_posting posting;
+ posting.rid = *record_id;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ }
+ }
+ break;
+ default :
+ break;
+ }
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ GRN_OBJ_FIN(ctx, &record_value);
+ }
+ grn_obj_unlink(ctx, accessor);
+ }
+ grn_obj_unlink(ctx, &value_ids);
+ }
+ grn_obj_unlink(ctx, source);
+
+ return GRN_TRUE;
+}
+
+static grn_rc
+selector_in_values(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ int i, n_values;
+ grn_obj **values;
+
+ if (!index) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ if (nargs < 2) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "in_values(): wrong number of arguments (%d for 1..)", nargs);
+ return ctx->rc;
+ }
+
+ n_values = nargs - 2;
+ values = args + 2;
+
+ if (n_values == 0) {
+ return rc;
+ }
+
+ if (selector_in_values_sequential_search(ctx, table, index,
+ n_values, values,
+ res, op)) {
+ return ctx->rc;
+ }
+
+ ctx->flags |= GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
+ for (i = 0; i < n_values; i++) {
+ grn_obj *value = values[i];
+ grn_search_optarg search_options;
+ memset(&search_options, 0, sizeof(grn_search_optarg));
+ search_options.mode = GRN_OP_EXACT;
+ search_options.similarity_threshold = 0;
+ search_options.max_interval = 0;
+ search_options.weight_vector = NULL;
+ search_options.vector_size = 0;
+ search_options.proc = NULL;
+ search_options.max_size = 0;
+ search_options.scorer = NULL;
+ if (i == n_values - 1) {
+ ctx->flags &= ~GRN_CTX_TEMPORARY_DISABLE_II_RESOLVE_SEL_AND;
+ }
+ rc = grn_obj_search(ctx, index, value, res, op, &search_options);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+
+ return rc;
+}
+
+static grn_obj *
+proc_range_filter(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *table_name = VAR(0);
+ grn_obj *column_name = VAR(1);
+ grn_obj *min = VAR(2);
+ grn_obj *min_border = VAR(3);
+ grn_obj *max = VAR(4);
+ grn_obj *max_border = VAR(5);
+ grn_obj *offset = VAR(6);
+ grn_obj *limit = VAR(7);
+ grn_obj *filter = VAR(8);
+ grn_obj *output_columns = VAR(9);
+ grn_obj *table;
+ grn_obj *res = NULL;
+ grn_obj *filter_expr = NULL;
+ grn_obj *filter_variable = NULL;
+ int real_offset;
+ int real_limit;
+
+ table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_name), GRN_TEXT_LEN(table_name));
+ if (!table) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] nonexistent table <%.*s>",
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name));
+ return NULL;
+ }
+
+ if (GRN_TEXT_LEN(filter) > 0) {
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, filter_expr, filter_variable);
+ if (!filter_expr) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] failed to create expression");
+ goto exit;
+ }
+
+ grn_expr_parse(ctx, filter_expr,
+ GRN_TEXT_VALUE(filter), GRN_TEXT_LEN(filter),
+ NULL, GRN_OP_MATCH, GRN_OP_AND, GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ }
+
+ res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ table, NULL);
+ if (!res) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] failed to result table");
+ goto exit;
+ }
+
+ {
+ grn_obj int32_value;
+
+ GRN_INT32_INIT(&int32_value, 0);
+
+ if (GRN_TEXT_LEN(offset) > 0) {
+ if (grn_obj_cast(ctx, offset, &int32_value, GRN_FALSE) != GRN_SUCCESS) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] invalid offset format: <%.*s>",
+ (int)GRN_TEXT_LEN(offset), GRN_TEXT_VALUE(offset));
+ GRN_OBJ_FIN(ctx, &int32_value);
+ goto exit;
+ }
+ real_offset = GRN_INT32_VALUE(&int32_value);
+ } else {
+ real_offset = 0;
+ }
+
+ GRN_BULK_REWIND(&int32_value);
+
+ if (GRN_TEXT_LEN(limit) > 0) {
+ if (grn_obj_cast(ctx, limit, &int32_value, GRN_FALSE) != GRN_SUCCESS) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] invalid limit format: <%.*s>",
+ (int)GRN_TEXT_LEN(limit), GRN_TEXT_VALUE(limit));
+ GRN_OBJ_FIN(ctx, &int32_value);
+ goto exit;
+ }
+ real_limit = GRN_INT32_VALUE(&int32_value);
+ } else {
+ real_limit = GRN_SELECT_DEFAULT_LIMIT;
+ }
+
+ GRN_OBJ_FIN(ctx, &int32_value);
+ }
+ {
+ grn_rc rc;
+ int original_offset = real_offset;
+ int original_limit = real_limit;
+ rc = grn_normalize_offset_and_limit(ctx, grn_table_size(ctx, table),
+ &real_offset, &real_limit);
+ switch (rc) {
+ case GRN_TOO_SMALL_OFFSET :
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] too small offset: <%d>", original_offset);
+ goto exit;
+ case GRN_TOO_LARGE_OFFSET :
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] too large offset: <%d>", original_offset);
+ goto exit;
+ case GRN_TOO_SMALL_LIMIT :
+ ERR(GRN_INVALID_ARGUMENT,
+ "[range_filter] too small limit: <%d>", original_limit);
+ goto exit;
+ default :
+ break;
+ }
+ }
+
+ if (real_limit != 0) {
+ grn_table_sort_key *sort_keys;
+ unsigned int n_sort_keys;
+ sort_keys = grn_table_sort_key_from_str(ctx,
+ GRN_TEXT_VALUE(column_name),
+ GRN_TEXT_LEN(column_name),
+ table,
+ &n_sort_keys);
+ if (n_sort_keys == 1) {
+ grn_table_sort_key *sort_key;
+ grn_obj *index;
+ int n_indexes;
+ grn_operator op = GRN_OP_OR;
+
+ sort_key = &(sort_keys[0]);
+ n_indexes = grn_column_index(ctx, sort_key->key, GRN_OP_LESS,
+ &index, 1, NULL);
+ if (n_indexes > 0) {
+ grn_obj *lexicon;
+ grn_table_cursor *table_cursor;
+ int table_cursor_flags = 0;
+ between_border_type min_border_type;
+ between_border_type max_border_type;
+ grn_obj real_min;
+ grn_obj real_max;
+ int n_records = 0;
+ grn_obj *index_cursor;
+ int index_cursor_flags = 0;
+ grn_posting *posting;
+
+ lexicon = grn_ctx_at(ctx, index->header.domain);
+ if (sort_key->flags & GRN_TABLE_SORT_DESC) {
+ table_cursor_flags |= GRN_CURSOR_DESCENDING;
+ } else {
+ table_cursor_flags |= GRN_CURSOR_ASCENDING;
+ }
+ if (GRN_TEXT_LEN(min_border) > 0) {
+ min_border_type = between_parse_border(ctx, min_border, "min_border");
+ } else {
+ min_border_type = BETWEEN_BORDER_INCLUDE;
+ }
+ if (GRN_TEXT_LEN(max_border) > 0) {
+ max_border_type = between_parse_border(ctx, max_border, "max_border");
+ } else {
+ max_border_type = BETWEEN_BORDER_INCLUDE;
+ }
+ if (min_border_type == BETWEEN_BORDER_EXCLUDE) {
+ table_cursor_flags |= GRN_CURSOR_GT;
+ }
+ if (max_border_type == BETWEEN_BORDER_EXCLUDE) {
+ table_cursor_flags |= GRN_CURSOR_LT;
+ }
+ GRN_OBJ_INIT(&real_min, GRN_BULK, 0, lexicon->header.domain);
+ GRN_OBJ_INIT(&real_max, GRN_BULK, 0, lexicon->header.domain);
+ if (GRN_TEXT_LEN(min) > 0) {
+ grn_obj_cast(ctx, min, &real_min, GRN_FALSE);
+ }
+ if (GRN_TEXT_LEN(max) > 0) {
+ grn_obj_cast(ctx, max, &real_max, GRN_FALSE);
+ }
+ table_cursor = grn_table_cursor_open(ctx, lexicon,
+ GRN_BULK_HEAD(&real_min),
+ GRN_BULK_VSIZE(&real_min),
+ GRN_BULK_HEAD(&real_max),
+ GRN_BULK_VSIZE(&real_max),
+ 0, -1, table_cursor_flags);
+ index_cursor = grn_index_cursor_open(ctx, table_cursor,
+ index, GRN_ID_NIL, GRN_ID_NIL,
+ index_cursor_flags);
+ while ((posting = grn_index_cursor_next(ctx, index_cursor, NULL))) {
+ grn_bool result_boolean = GRN_FALSE;
+
+ if (filter_expr) {
+ grn_obj *result;
+ GRN_RECORD_SET(ctx, filter_variable, posting->rid);
+ result = grn_expr_exec(ctx, filter_expr, 0);
+ if (ctx->rc) {
+ break;
+ }
+ result_boolean = grn_obj_is_true(ctx, result);
+ } else {
+ result_boolean = GRN_TRUE;
+ }
+
+ if (result_boolean) {
+ if (n_records >= real_offset) {
+ grn_ii_posting_add(ctx, posting, (grn_hash *)res, op);
+ }
+ n_records++;
+ if (n_records == real_limit) {
+ break;
+ }
+ }
+ }
+ grn_obj_unlink(ctx, index_cursor);
+ grn_table_cursor_close(ctx, table_cursor);
+
+ GRN_OBJ_FIN(ctx, &real_min);
+ GRN_OBJ_FIN(ctx, &real_max);
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ }
+ grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
+ }
+
+ if (ctx->rc == GRN_SUCCESS) {
+ const char *raw_output_columns;
+ int raw_output_columns_len;
+
+ raw_output_columns = GRN_TEXT_VALUE(output_columns);
+ raw_output_columns_len = GRN_TEXT_LEN(output_columns);
+ if (raw_output_columns_len == 0) {
+ raw_output_columns = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
+ raw_output_columns_len = strlen(raw_output_columns);
+ }
+ grn_proc_select_output_columns(ctx, res, -1, real_offset, real_limit,
+ raw_output_columns,
+ raw_output_columns_len,
+ filter_expr);
+ }
+
+exit :
+ if (filter_expr) {
+ grn_obj_unlink(ctx, filter_expr);
+ }
+ if (res) {
+ grn_obj_unlink(ctx, res);
+ }
+
+ return NULL;
+}
+
+static grn_obj *
+proc_request_cancel(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *id = VAR(0);
+ grn_bool canceled;
+
+ if (GRN_TEXT_LEN(id) == 0) {
+ ERR(GRN_INVALID_ARGUMENT, "[request_cancel] ID is missing");
+ return NULL;
+ }
+
+ canceled = grn_request_canceler_cancel(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id));
+
+ GRN_OUTPUT_MAP_OPEN("result", 2);
+ GRN_OUTPUT_CSTR("id");
+ GRN_OUTPUT_STR(GRN_TEXT_VALUE(id), GRN_TEXT_LEN(id));
+ GRN_OUTPUT_CSTR("canceled");
+ GRN_OUTPUT_BOOL(canceled);
+ GRN_OUTPUT_MAP_CLOSE();
+
+ return NULL;
+}
+
+static grn_obj *
+proc_plugin_register(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ if (GRN_TEXT_LEN(VAR(0))) {
+ const char *name;
+ GRN_TEXT_PUTC(ctx, VAR(0), '\0');
+ name = GRN_TEXT_VALUE(VAR(0));
+ grn_plugin_register(ctx, name);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "[plugin_register] name is missing");
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_obj *
+proc_plugin_unregister(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ if (GRN_TEXT_LEN(VAR(0))) {
+ const char *name;
+ GRN_TEXT_PUTC(ctx, VAR(0), '\0');
+ name = GRN_TEXT_VALUE(VAR(0));
+ grn_plugin_unregister(ctx, name);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "[plugin_unregister] name is missing");
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+ return NULL;
+}
+
+static grn_obj *
+proc_io_flush(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *target_name;
+ grn_obj *recursive;
+ grn_obj *only_opened;
+ grn_obj *target;
+ grn_bool is_recursive;
+ grn_bool is_only_opened;
+
+ target_name = VAR(0);
+ recursive = VAR(1);
+ only_opened = VAR(2);
+
+ if (GRN_TEXT_LEN(target_name) > 0) {
+ target = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(target_name),
+ GRN_TEXT_LEN(target_name));
+ if (!target) {
+ ERR(GRN_INVALID_ARGUMENT, "[io_flush] unknown target: <%.*s>",
+ (int)GRN_TEXT_LEN(target_name),
+ GRN_TEXT_VALUE(target_name));
+ GRN_OUTPUT_BOOL(GRN_FALSE);
+ return NULL;
+ }
+ } else {
+ target = grn_ctx_db(ctx);
+ }
+
+ is_recursive = grn_proc_option_value_bool(ctx, recursive, GRN_TRUE);
+ is_only_opened = grn_proc_option_value_bool(ctx, only_opened, GRN_FALSE);
+ {
+ grn_rc rc;
+ if (target->header.type == GRN_DB && is_only_opened) {
+ rc = grn_obj_flush(ctx, target);
+ if (rc == GRN_SUCCESS) {
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, target, cursor, id, GRN_CURSOR_BY_ID) {
+ grn_obj *sub_target;
+
+ if (id < GRN_N_RESERVED_TYPES) {
+ continue;
+ }
+
+ if (!grn_ctx_is_opened(ctx, id)) {
+ continue;
+ }
+
+ sub_target = grn_ctx_at(ctx, id);
+ rc = grn_obj_flush(ctx, sub_target);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ }
+ } else {
+ if (is_recursive) {
+ rc = grn_obj_flush_recursive(ctx, target);
+ } else {
+ rc = grn_obj_flush(ctx, target);
+ }
+ }
+ GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
+ }
+
+
+ return NULL;
+}
+
+static grn_obj *
+proc_thread_limit(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *max_bulk;
+ uint32_t current_limit;
+
+ current_limit = grn_thread_get_limit();
+ GRN_OUTPUT_INT64(current_limit);
+
+ max_bulk = VAR(0);
+ if (GRN_TEXT_LEN(max_bulk) > 0) {
+ uint32_t max;
+ const char *max_text = GRN_TEXT_VALUE(max_bulk);
+ const char *max_text_end;
+ const char *max_text_rest;
+
+ max_text_end = max_text + GRN_TEXT_LEN(max_bulk);
+ max = grn_atoui(max_text, max_text_end, &max_text_rest);
+ if (max_text_rest != max_text_end) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[thread_limit] max must be unsigned integer value: <%.*s>",
+ (int)GRN_TEXT_LEN(max_bulk),
+ max_text);
+ return NULL;
+ }
+ if (max == 0) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[thread_limit] max must be 1 or larger: <%.*s>",
+ (int)GRN_TEXT_LEN(max_bulk),
+ max_text);
+ return NULL;
+ }
+ grn_thread_set_limit(max);
+ }
+
+ return NULL;
+}
+
+static grn_obj *
+proc_database_unmap(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_rc rc;
+ uint32_t current_limit;
+
+ current_limit = grn_thread_get_limit();
+ if (current_limit != 1) {
+ ERR(GRN_OPERATION_NOT_PERMITTED,
+ "[database_unmap] the max number of threads must be 1: <%u>",
+ current_limit);
+ GRN_OUTPUT_BOOL(GRN_FALSE);
+ return NULL;
+ }
+
+ rc = grn_db_unmap(ctx, grn_ctx_db(ctx));
+ GRN_OUTPUT_BOOL(rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+static grn_obj *
+proc_reindex(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *target_name;
+ grn_obj *target;
+
+ target_name = VAR(0);
+ if (GRN_TEXT_LEN(target_name) == 0) {
+ target = grn_ctx_db(ctx);
+ } else {
+ target = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(target_name),
+ GRN_TEXT_LEN(target_name));
+ if (!target) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[reindex] nonexistent target: <%.*s>",
+ (int)GRN_TEXT_LEN(target_name),
+ GRN_TEXT_VALUE(target_name));
+ GRN_OUTPUT_BOOL(GRN_FALSE);
+ return NULL;
+ }
+ }
+
+ grn_obj_reindex(ctx, target);
+
+ GRN_OUTPUT_BOOL(ctx->rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+static grn_rc
+selector_prefix_rk_search_key(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *column,
+ grn_obj *query,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ if (!grn_obj_is_key_accessor(ctx, column)) {
+ grn_obj inspected_column;
+ GRN_TEXT_INIT(&inspected_column, 0);
+ grn_inspect(ctx, &inspected_column, column);
+ ERR(GRN_INVALID_ARGUMENT,
+ "prefix_rk_serach(): column must be _key: %.*s",
+ (int)GRN_TEXT_LEN(&inspected_column),
+ GRN_TEXT_VALUE(&inspected_column));
+ rc = ctx->rc;
+ GRN_OBJ_FIN(ctx, &inspected_column);
+ goto exit;
+ }
+
+ if (table->header.type != GRN_TABLE_PAT_KEY) {
+ grn_obj inspected_table;
+ GRN_TEXT_INIT(&inspected_table, 0);
+ grn_inspect(ctx, &inspected_table, table);
+ ERR(GRN_INVALID_ARGUMENT,
+ "prefix_rk_serach(): table of _key must TABLE_PAT_KEY: %.*s",
+ (int)GRN_TEXT_LEN(&inspected_table),
+ GRN_TEXT_VALUE(&inspected_table));
+ rc = ctx->rc;
+ GRN_OBJ_FIN(ctx, &inspected_table);
+ goto exit;
+ }
+
+ GRN_TABLE_EACH_BEGIN_MIN(ctx,
+ table,
+ cursor,
+ id,
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query),
+ GRN_CURSOR_PREFIX | GRN_CURSOR_RK) {
+ grn_posting posting;
+ posting.rid = id;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = 0;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+
+exit :
+ return rc;
+}
+
+static grn_rc
+selector_prefix_rk_search_index(grn_ctx *ctx,
+ grn_obj *index,
+ grn_obj *query,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *table;
+
+ table = grn_column_table(ctx, index);
+
+ GRN_TABLE_EACH_BEGIN_MIN(ctx,
+ table,
+ cursor,
+ id,
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query),
+ GRN_CURSOR_PREFIX | GRN_CURSOR_RK) {
+ grn_ii_at(ctx, (grn_ii *)index, id, (grn_hash *)res, op);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+
+ return rc;
+}
+
+static grn_rc
+selector_prefix_rk_search(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ int nargs,
+ grn_obj **args,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *column;
+ grn_obj *query;
+
+ if ((nargs - 1) != 2) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "prefix_rk_serach(): wrong number of arguments (%d for 2)", nargs - 1);
+ return ctx->rc;
+ }
+
+ column = args[1];
+ query = args[2];
+
+ if (index) {
+ rc = selector_prefix_rk_search_index(ctx, index, query, res, op);
+ } else if (grn_obj_is_accessor(ctx, column) &&
+ ((grn_accessor *)column)->next) {
+ grn_obj *accessor = column;
+ unsigned int accessor_deep = 0;
+ grn_obj *base_table = NULL;
+ grn_obj *base_column = NULL;
+ grn_obj *base_index = NULL;
+ grn_obj *base_res = NULL;
+ grn_accessor *a;
+
+ for (a = (grn_accessor *)accessor; a; a = a->next) {
+ if (a->next) {
+ accessor_deep++;
+ } else {
+ if (grn_obj_is_data_column(ctx, a->obj)) {
+ grn_operator selector_op;
+ grn_index_datum index_data;
+ unsigned int n_index_datum;
+
+ selector_op = grn_proc_get_selector_operator(ctx, args[0]);
+ base_column = a->obj;
+ base_table = grn_column_table(ctx, a->obj);
+ n_index_datum = grn_column_find_index_data(ctx,
+ base_column,
+ selector_op,
+ &index_data,
+ 1);
+ if (n_index_datum > 0) {
+ base_index = index_data.index;
+ }
+ } else {
+ base_column = (grn_obj *)a;
+ base_table = a->obj;
+ }
+ base_res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ base_table, NULL);
+ }
+ }
+ if (base_index) {
+ rc = selector_prefix_rk_search_index(ctx,
+ base_index,
+ query,
+ base_res,
+ GRN_OP_OR);
+ } else {
+ rc = selector_prefix_rk_search_key(ctx,
+ base_table,
+ base_column,
+ query,
+ base_res,
+ GRN_OP_OR);
+ }
+ if (rc == GRN_SUCCESS) {
+ grn_accessor_resolve(ctx,
+ accessor,
+ accessor_deep,
+ base_res,
+ res,
+ op);
+ }
+ grn_obj_close(ctx, base_res);
+ } else {
+ rc = selector_prefix_rk_search_key(ctx,
+ table,
+ column,
+ query,
+ res,
+ op);
+ }
+ return rc;
+}
+
+#define DEF_VAR(v,name_str) do {\
+ (v).name = (name_str);\
+ (v).name_size = GRN_STRLEN(name_str);\
+ GRN_TEXT_INIT(&(v).value, 0);\
+} while (0)
+
+#define DEF_COMMAND(name, func, nvars, vars)\
+ (grn_proc_create(ctx, (name), (sizeof(name) - 1),\
+ GRN_PROC_COMMAND, (func), NULL, NULL, (nvars), (vars)))
+
+void
+grn_db_init_builtin_commands(grn_ctx *ctx)
+{
+ grn_expr_var vars[10];
+
+ grn_proc_init_define_selector(ctx);
+ grn_proc_init_select(ctx);
+
+ DEF_VAR(vars[0], "values");
+ DEF_VAR(vars[1], "table");
+ DEF_VAR(vars[2], "columns");
+ DEF_VAR(vars[3], "ifexists");
+ DEF_VAR(vars[4], "input_type");
+ DEF_VAR(vars[5], "each");
+ DEF_VAR(vars[6], "output_ids");
+ DEF_VAR(vars[7], "output_errors");
+ DEF_COMMAND("load", proc_load, 8, vars);
+
+ DEF_COMMAND("status", proc_status, 0, vars);
+
+ grn_proc_init_table_list(ctx);
+
+ grn_proc_init_column_list(ctx);
+
+ grn_proc_init_table_create(ctx);
+
+ grn_proc_init_table_remove(ctx);
+
+ grn_proc_init_table_rename(ctx);
+
+ grn_proc_init_column_create(ctx);
+
+ grn_proc_init_column_remove(ctx);
+
+ grn_proc_init_column_rename(ctx);
+
+ DEF_VAR(vars[0], "path");
+ DEF_COMMAND(GRN_EXPR_MISSING_NAME, proc_missing, 1, vars);
+
+ DEF_COMMAND("quit", proc_quit, 0, vars);
+
+ DEF_VAR(vars[0], "mode");
+ DEF_COMMAND("shutdown", proc_shutdown, 1, vars);
+
+ grn_proc_init_clearlock(ctx);
+ grn_proc_init_lock_clear(ctx);
+
+ DEF_VAR(vars[0], "target_name");
+ DEF_VAR(vars[1], "threshold");
+ DEF_COMMAND("defrag", proc_defrag, 2, vars);
+
+ DEF_VAR(vars[0], "level");
+ DEF_COMMAND("log_level", proc_log_level, 1, vars);
+
+ DEF_VAR(vars[0], "level");
+ DEF_VAR(vars[1], "message");
+ DEF_COMMAND("log_put", proc_log_put, 2, vars);
+
+ DEF_COMMAND("log_reopen", proc_log_reopen, 0, vars);
+
+ DEF_VAR(vars[0], "table");
+ DEF_VAR(vars[1], "key");
+ DEF_VAR(vars[2], "id");
+ DEF_VAR(vars[3], "filter");
+ DEF_COMMAND("delete", proc_delete, 4, vars);
+
+ DEF_VAR(vars[0], "max");
+ DEF_COMMAND("cache_limit", proc_cache_limit, 1, vars);
+
+ grn_proc_init_dump(ctx);
+
+ /* Deprecated. Use "plugin_register" instead. */
+ DEF_VAR(vars[0], "path");
+ DEF_COMMAND("register", proc_register, 1, vars);
+
+ DEF_VAR(vars[0], "obj");
+ DEF_COMMAND("check", proc_check, 1, vars);
+
+ DEF_VAR(vars[0], "target_name");
+ DEF_VAR(vars[1], "table");
+ DEF_COMMAND("truncate", proc_truncate, 2, vars);
+
+ DEF_VAR(vars[0], "normalizer");
+ DEF_VAR(vars[1], "string");
+ DEF_VAR(vars[2], "flags");
+ DEF_COMMAND("normalize", proc_normalize, 3, vars);
+
+ grn_proc_init_tokenize(ctx);
+ grn_proc_init_table_tokenize(ctx);
+
+ DEF_COMMAND("tokenizer_list", proc_tokenizer_list, 0, vars);
+
+ DEF_COMMAND("normalizer_list", proc_normalizer_list, 0, vars);
+
+ {
+ grn_obj *proc;
+ proc = grn_proc_create(ctx, "rand", -1, GRN_PROC_FUNCTION, func_rand,
+ NULL, NULL, 0, NULL);
+ grn_proc_set_is_stable(ctx, proc, GRN_FALSE);
+ }
+
+ {
+ grn_obj *proc;
+ proc = grn_proc_create(ctx, "now", -1, GRN_PROC_FUNCTION, func_now,
+ NULL, NULL, 0, NULL);
+ grn_proc_set_is_stable(ctx, proc, GRN_FALSE);
+ }
+
+ grn_proc_create(ctx, "max", -1, GRN_PROC_FUNCTION, func_max,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx, "min", -1, GRN_PROC_FUNCTION, func_min,
+ NULL, NULL, 0, NULL);
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "geo_in_circle", -1, GRN_PROC_FUNCTION,
+ func_geo_in_circle, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, grn_selector_geo_in_circle);
+ /* We may need GRN_OP_GEO_IN_CIRCLE. */
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_MATCH);
+
+ selector_proc = grn_proc_create(ctx, "geo_in_rectangle", -1,
+ GRN_PROC_FUNCTION,
+ func_geo_in_rectangle, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, grn_selector_geo_in_rectangle);
+ /* We may need GRN_OP_GEO_IN_RECTANGLE. */
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_MATCH);
+ }
+
+ grn_proc_create(ctx, "geo_distance", -1, GRN_PROC_FUNCTION,
+ func_geo_distance, NULL, NULL, 0, NULL);
+
+ /* deprecated. */
+ grn_proc_create(ctx, "geo_distance2", -1, GRN_PROC_FUNCTION,
+ func_geo_distance2, NULL, NULL, 0, NULL);
+
+ /* deprecated. */
+ grn_proc_create(ctx, "geo_distance3", -1, GRN_PROC_FUNCTION,
+ func_geo_distance3, NULL, NULL, 0, NULL);
+
+ grn_proc_init_edit_distance(ctx);
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "all_records", -1, GRN_PROC_FUNCTION,
+ func_all_records, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_all_records);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
+ }
+
+ /* experimental */
+ grn_proc_init_snippet_html(ctx);
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "query", -1, GRN_PROC_FUNCTION,
+ func_query, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_query);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
+ }
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "sub_filter", -1, GRN_PROC_FUNCTION,
+ NULL, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_sub_filter);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
+ }
+
+ grn_proc_create(ctx, "html_untag", -1, GRN_PROC_FUNCTION,
+ func_html_untag, NULL, NULL, 0, NULL);
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "between", -1, GRN_PROC_FUNCTION,
+ func_between, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_between);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_LESS);
+ }
+
+ grn_proc_init_highlight_html(ctx);
+ grn_proc_init_highlight_full(ctx);
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "in_values", -1, GRN_PROC_FUNCTION,
+ func_in_values, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_in_values);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_EQUAL);
+ }
+
+ DEF_VAR(vars[0], "table");
+ DEF_VAR(vars[1], "column");
+ DEF_VAR(vars[2], "min");
+ DEF_VAR(vars[3], "min_border");
+ DEF_VAR(vars[4], "max");
+ DEF_VAR(vars[5], "max_border");
+ DEF_VAR(vars[6], "offset");
+ DEF_VAR(vars[7], "limit");
+ DEF_VAR(vars[8], "filter");
+ DEF_VAR(vars[9], "output_columns");
+ DEF_COMMAND("range_filter", proc_range_filter, 10, vars);
+
+ DEF_VAR(vars[0], "id");
+ DEF_COMMAND("request_cancel", proc_request_cancel, 1, vars);
+
+ DEF_VAR(vars[0], "name");
+ DEF_COMMAND("plugin_register", proc_plugin_register, 1, vars);
+
+ DEF_VAR(vars[0], "name");
+ DEF_COMMAND("plugin_unregister", proc_plugin_unregister, 1, vars);
+
+ DEF_VAR(vars[0], "target_name");
+ DEF_VAR(vars[1], "recursive");
+ DEF_VAR(vars[2], "only_opened");
+ DEF_COMMAND("io_flush", proc_io_flush, 3, vars);
+
+ grn_proc_init_object_exist(ctx);
+
+ DEF_VAR(vars[0], "max");
+ DEF_COMMAND("thread_limit", proc_thread_limit, 1, vars);
+
+ DEF_COMMAND("database_unmap", proc_database_unmap, 0, vars);
+
+ grn_proc_init_column_copy(ctx);
+
+ grn_proc_init_schema(ctx);
+
+ DEF_VAR(vars[0], "target_name");
+ DEF_COMMAND("reindex", proc_reindex, 1, vars);
+
+ {
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "prefix_rk_search", -1,
+ GRN_PROC_FUNCTION,
+ NULL, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_prefix_rk_search);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_PREFIX);
+ }
+
+ grn_proc_init_config_get(ctx);
+ grn_proc_init_config_set(ctx);
+ grn_proc_init_config_delete(ctx);
+
+ grn_proc_init_lock_acquire(ctx);
+ grn_proc_init_lock_release(ctx);
+
+ grn_proc_init_object_inspect(ctx);
+
+ grn_proc_init_fuzzy_search(ctx);
+
+ grn_proc_init_object_remove(ctx);
+
+ grn_proc_init_snippet(ctx);
+ grn_proc_init_highlight(ctx);
+
+ grn_proc_init_query_expand(ctx);
+
+ grn_proc_init_object_list(ctx);
+
+ grn_proc_init_table_copy(ctx);
+
+ grn_proc_init_in_records(ctx);
+
+ grn_proc_init_query_log_flags_get(ctx);
+ grn_proc_init_query_log_flags_set(ctx);
+ grn_proc_init_query_log_flags_add(ctx);
+ grn_proc_init_query_log_flags_remove(ctx);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/Makefile.am b/storage/mroonga/vendor/groonga/lib/proc/Makefile.am
new file mode 100644
index 00000000..e4284dc2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_CFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS) \
+ $(MRUBY_CFLAGS)
+
+noinst_LTLIBRARIES = libgrnproc.la
+
+include sources.am
+
+CLEANFILES = *.gcno *.gcda
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_column.c b/storage/mroonga/vendor/groonga/lib/proc/proc_column.c
new file mode 100644
index 00000000..ecf527c3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_column.c
@@ -0,0 +1,1025 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include "../grn_ctx.h"
+#include "../grn_db.h"
+#include "../grn_str.h"
+
+#include <groonga/plugin.h>
+
+grn_column_flags
+grn_proc_column_parse_flags(grn_ctx *ctx,
+ const char *error_message_tag,
+ const char *text,
+ const char *end)
+{
+ grn_column_flags flags = 0;
+ while (text < end) {
+ size_t name_size;
+
+ if (*text == '|' || *text == ' ') {
+ text += 1;
+ continue;
+ }
+
+#define CHECK_FLAG(name) \
+ name_size = strlen(#name); \
+ if ((unsigned long) (end - text) >= (unsigned long) name_size && \
+ memcmp(text, #name, name_size) == 0) { \
+ flags |= GRN_OBJ_ ## name; \
+ text += name_size; \
+ continue; \
+ }
+
+ CHECK_FLAG(COLUMN_SCALAR);
+ CHECK_FLAG(COLUMN_VECTOR);
+ CHECK_FLAG(COLUMN_INDEX);
+ CHECK_FLAG(COMPRESS_ZLIB);
+ CHECK_FLAG(COMPRESS_LZ4);
+ CHECK_FLAG(COMPRESS_ZSTD);
+ CHECK_FLAG(WITH_SECTION);
+ CHECK_FLAG(WITH_WEIGHT);
+ CHECK_FLAG(WITH_POSITION);
+ CHECK_FLAG(RING_BUFFER);
+ CHECK_FLAG(INDEX_SMALL);
+ CHECK_FLAG(INDEX_MEDIUM);
+
+#undef CHECK_FLAG
+
+ ERR(GRN_INVALID_ARGUMENT,
+ "%s unknown flag: <%.*s>",
+ error_message_tag,
+ (int)(end - text), text);
+ return 0;
+ }
+ return flags;
+}
+
+static grn_rc
+command_column_create_resolve_source_name(grn_ctx *ctx,
+ grn_obj *table,
+ const char *source_name,
+ int source_name_length,
+ grn_obj *source_ids)
+{
+ grn_obj *column;
+
+ column = grn_obj_column(ctx, table, source_name, source_name_length);
+ if (!column) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][create] nonexistent source: <%.*s>",
+ source_name_length, source_name);
+ return ctx->rc;
+ }
+
+ if (column->header.type == GRN_ACCESSOR) {
+ if (strncmp(source_name, "_key", source_name_length) == 0) {
+ grn_id source_id = grn_obj_id(ctx, table);
+ GRN_UINT32_PUT(ctx, source_ids, source_id);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][create] pseudo column except <_key> is invalid: <%.*s>",
+ source_name_length, source_name);
+ }
+ } else {
+ grn_id source_id = grn_obj_id(ctx, column);
+ GRN_UINT32_PUT(ctx, source_ids, source_id);
+ }
+ grn_obj_unlink(ctx, column);
+
+ return ctx->rc;
+}
+
+static grn_rc
+command_column_create_resolve_source_names(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *source_names,
+ grn_obj *source_ids)
+{
+ int i, names_length;
+ int start, source_name_length;
+ const char *names;
+
+ names = GRN_TEXT_VALUE(source_names);
+ start = 0;
+ source_name_length = 0;
+ names_length = GRN_TEXT_LEN(source_names);
+ for (i = 0; i < names_length; i++) {
+ switch (names[i]) {
+ case ' ' :
+ if (source_name_length == 0) {
+ start++;
+ }
+ break;
+ case ',' :
+ {
+ grn_rc rc;
+ const char *source_name = names + start;
+ rc = command_column_create_resolve_source_name(ctx,
+ table,
+ source_name,
+ source_name_length,
+ source_ids);
+ if (rc) {
+ return rc;
+ }
+ start = i + 1;
+ source_name_length = 0;
+ }
+ break;
+ default :
+ source_name_length++;
+ break;
+ }
+ }
+
+ if (source_name_length > 0) {
+ grn_rc rc;
+ const char *source_name = names + start;
+ rc = command_column_create_resolve_source_name(ctx,
+ table,
+ source_name,
+ source_name_length,
+ source_ids);
+ if (rc) {
+ return rc;
+ }
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_obj *
+command_column_create(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_bool succeeded = GRN_TRUE;
+ grn_obj *table;
+ grn_obj *column;
+ grn_obj *table_raw;
+ grn_obj *name;
+ grn_obj *flags_raw;
+ grn_obj *type_raw;
+ grn_obj *source_raw;
+ grn_column_flags flags;
+ grn_obj *type = NULL;
+
+ table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ flags_raw = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ type_raw = grn_plugin_proc_get_var(ctx, user_data, "type", -1);
+ source_raw = grn_plugin_proc_get_var(ctx, user_data, "source", -1);
+
+ table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_raw), GRN_TEXT_LEN(table_raw));
+ if (!table) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][create] table doesn't exist: <%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw));
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+
+ {
+ const char *rest;
+ flags = grn_atoi(GRN_TEXT_VALUE(flags_raw),
+ GRN_BULK_CURR(flags_raw),
+ &rest);
+ if (GRN_TEXT_VALUE(flags_raw) == rest) {
+ flags = grn_proc_column_parse_flags(ctx,
+ "[column][create][flags]",
+ GRN_TEXT_VALUE(flags_raw),
+ GRN_BULK_CURR(flags_raw));
+ if (ctx->rc) {
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+ }
+ }
+
+ type = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(type_raw),
+ GRN_TEXT_LEN(type_raw));
+ if (!type) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][create] type doesn't exist: <%.*s>",
+ (int)GRN_TEXT_LEN(type_raw),
+ GRN_TEXT_VALUE(type_raw));
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+
+ if (GRN_TEXT_LEN(name) == 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][create] name is missing");
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+ flags |= GRN_OBJ_PERSISTENT;
+
+ column = grn_column_create(ctx, table,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name),
+ NULL, flags, type);
+ if (!column) {
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+
+ if (GRN_TEXT_LEN(source_raw) > 0) {
+ grn_rc rc;
+ grn_obj source_ids;
+ GRN_UINT32_INIT(&source_ids, GRN_OBJ_VECTOR);
+ rc = command_column_create_resolve_source_names(ctx,
+ type,
+ source_raw,
+ &source_ids);
+ if (rc == GRN_SUCCESS && GRN_BULK_VSIZE(&source_ids) > 0) {
+ grn_obj_set_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
+ rc = ctx->rc;
+ }
+ GRN_OBJ_FIN(ctx, &source_ids);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_remove(ctx, column);
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+ }
+
+ grn_obj_unlink(ctx, column);
+
+exit :
+ grn_ctx_output_bool(ctx, succeeded);
+ if (table) { grn_obj_unlink(ctx, table); }
+ if (type) { grn_obj_unlink(ctx, type); }
+
+ return NULL;
+}
+
+void
+grn_proc_init_column_create(grn_ctx *ctx)
+{
+ grn_expr_var vars[5];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "flags", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "type", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "source", -1);
+ grn_plugin_command_create(ctx,
+ "column_create", -1,
+ command_column_create,
+ 5,
+ vars);
+}
+
+static grn_obj *
+command_column_remove(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *table_raw;
+ grn_obj *name;
+ grn_obj *table;
+ grn_obj *column;
+ char fullname[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int fullname_len;
+
+ table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+
+ table = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(table_raw),
+ GRN_TEXT_LEN(table_raw));
+
+ fullname_len = grn_obj_name(ctx, table, fullname, GRN_TABLE_MAX_KEY_SIZE);
+ if (fullname_len == 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][remove] table isn't found: <%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw));
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+
+ fullname[fullname_len] = GRN_DB_DELIMITER;
+ fullname_len++;
+ if (fullname_len + GRN_TEXT_LEN(name) > GRN_TABLE_MAX_KEY_SIZE) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][remove] column name is too long: <%d> > <%u>: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TABLE_MAX_KEY_SIZE - fullname_len,
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+ grn_memcpy(fullname + fullname_len,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ fullname_len += GRN_TEXT_LEN(name);
+ column = grn_ctx_get(ctx, fullname, fullname_len);
+ if (!column) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][remove] column isn't found: <%.*s%c%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+
+ grn_obj_remove(ctx, column);
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+ return NULL;
+}
+
+void
+grn_proc_init_column_remove(grn_ctx *ctx)
+{
+ grn_expr_var vars[2];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1);
+ grn_plugin_command_create(ctx,
+ "column_remove", -1,
+ command_column_remove,
+ 2,
+ vars);
+}
+
+static grn_obj *
+command_column_rename(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *table_raw;
+ grn_obj *name;
+ grn_obj *new_name;
+ grn_obj *table = NULL;
+ grn_obj *column = NULL;
+
+ table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ new_name = grn_plugin_proc_get_var(ctx, user_data, "new_name", -1);
+
+ if (GRN_TEXT_LEN(table_raw) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][rename] table name isn't specified");
+ goto exit;
+ }
+
+ table = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_raw), GRN_TEXT_LEN(table_raw));
+ if (!table) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][rename] table isn't found: <%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw));
+ goto exit;
+ }
+
+ if (GRN_TEXT_LEN(name) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][rename] column name isn't specified: <%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw));
+ goto exit;
+ }
+
+ column = grn_obj_column(ctx, table,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ if (!column) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][rename] column isn't found: <%.*s%c%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ goto exit;
+ }
+
+ if (GRN_TEXT_LEN(new_name) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][rename] new column name isn't specified: "
+ "<%.*s%c%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ goto exit;
+ }
+
+ rc = grn_column_rename(ctx, column,
+ GRN_TEXT_VALUE(new_name),
+ GRN_TEXT_LEN(new_name));
+ if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) {
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][rename] failed to rename: "
+ "<%.*s%c%.*s> -> <%.*s%c%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(new_name),
+ GRN_TEXT_VALUE(new_name));
+ goto exit;
+ }
+
+exit :
+ grn_ctx_output_bool(ctx, rc == GRN_SUCCESS);
+ if (column) { grn_obj_unlink(ctx, column); }
+ if (table) { grn_obj_unlink(ctx, table); }
+ return NULL;
+}
+
+void
+grn_proc_init_column_rename(grn_ctx *ctx)
+{
+ grn_expr_var vars[3];
+ vars[0].name= NULL;
+ vars[0].name_size= 0;
+ vars[1].name= NULL;
+ vars[1].name_size= 0;
+ vars[2].name= NULL;
+ vars[2].name_size= 0;
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "new_name", -1);
+ grn_plugin_command_create(ctx,
+ "column_rename", -1,
+ command_column_rename,
+ 3,
+ vars);
+}
+
+static void
+output_column_name(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj bulk;
+ int name_len;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+
+ GRN_TEXT_INIT(&bulk, GRN_OBJ_DO_SHALLOW_COPY);
+ name_len = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_SET(ctx, &bulk, name, name_len);
+
+ grn_ctx_output_obj(ctx, &bulk, NULL);
+ GRN_OBJ_FIN(ctx, &bulk);
+}
+
+static int
+output_column_info(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj o;
+ grn_id id;
+ const char *type;
+ const char *path;
+
+ switch (column->header.type) {
+ case GRN_COLUMN_FIX_SIZE:
+ type = "fix";
+ break;
+ case GRN_COLUMN_VAR_SIZE:
+ type = "var";
+ break;
+ case GRN_COLUMN_INDEX:
+ type = "index";
+ break;
+ default:
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid header type %d\n", column->header.type);
+ return 0;
+ }
+ id = grn_obj_id(ctx, column);
+ path = grn_obj_path(ctx, column);
+ GRN_TEXT_INIT(&o, 0);
+ grn_ctx_output_array_open(ctx, "COLUMN", 8);
+ grn_ctx_output_int64(ctx, id);
+ output_column_name(ctx, column);
+ grn_ctx_output_cstr(ctx, path);
+ grn_ctx_output_cstr(ctx, type);
+ grn_dump_column_create_flags(ctx, grn_column_get_flags(ctx, column), &o);
+ grn_ctx_output_obj(ctx, &o, NULL);
+ grn_proc_output_object_id_name(ctx, column->header.domain);
+ grn_proc_output_object_id_name(ctx, grn_obj_get_range(ctx, column));
+ {
+ grn_db_obj *obj = (grn_db_obj *)column;
+ grn_id *s = obj->source;
+ int i = 0, n = obj->source_size / sizeof(grn_id);
+ grn_ctx_output_array_open(ctx, "SOURCES", n);
+ for (i = 0; i < n; i++, s++) {
+ grn_proc_output_object_id_name(ctx, *s);
+ }
+ grn_ctx_output_array_close(ctx);
+
+ }
+ /* output_obj_source(ctx, (grn_db_obj *)column); */
+ grn_ctx_output_array_close(ctx);
+ GRN_OBJ_FIN(ctx, &o);
+ return 1;
+}
+
+static grn_obj *
+command_column_list(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *table_raw;
+ grn_obj *table;
+ grn_hash *cols;
+ grn_obj *col;
+ int column_list_size = -1;
+
+ table_raw = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
+
+ table = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(table_raw),
+ GRN_TEXT_LEN(table_raw));
+ if (!table) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][list] table doesn't exist: <%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw));
+ return NULL;
+ }
+
+ if (!grn_obj_is_table(ctx, table)) {
+ const char *type_name;
+ type_name = grn_obj_type_to_string(table->header.type);
+ grn_obj_unlink(ctx, table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][list] not table: <%.*s>: <%s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw),
+ type_name);
+ return NULL;
+ }
+
+ column_list_size = 1; /* [header, (key), (COLUMNS)] */
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ column_list_size++;
+ }
+ cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (!cols) {
+ grn_obj_unlink(ctx, table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[column][list] "
+ "failed to create temporary table to list columns: <%.*s>",
+ (int)GRN_TEXT_LEN(table_raw),
+ GRN_TEXT_VALUE(table_raw));
+ return NULL;
+ }
+
+ column_list_size += grn_table_columns(ctx, table, NULL, 0, (grn_obj *)cols);
+
+ grn_ctx_output_array_open(ctx, "COLUMN_LIST", column_list_size);
+ grn_ctx_output_array_open(ctx, "HEADER", 8);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_cstr(ctx, "UInt32");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "path");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "type");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "flags");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "domain");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "range");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "source");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_close(ctx);
+
+ if ((col = grn_obj_column(ctx, table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN))) {
+ int name_len;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+ grn_id id;
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ grn_ctx_output_array_open(ctx, "COLUMN", 8);
+ id = grn_obj_id(ctx, table);
+ grn_ctx_output_int64(ctx, id);
+ grn_ctx_output_cstr(ctx, GRN_COLUMN_NAME_KEY);
+ grn_ctx_output_cstr(ctx, "");
+ grn_ctx_output_cstr(ctx, "");
+ grn_dump_column_create_flags(ctx, 0, &buf);
+ grn_ctx_output_obj(ctx, &buf, NULL);
+ name_len = grn_obj_name(ctx, table, name_buf, GRN_TABLE_MAX_KEY_SIZE);
+ grn_ctx_output_str(ctx, name_buf, name_len);
+ grn_proc_output_object_id_name(ctx, table->header.domain);
+ grn_ctx_output_array_open(ctx, "SOURCES", 0);
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_close(ctx);
+ GRN_OBJ_FIN(ctx, &buf);
+ grn_obj_unlink(ctx, col);
+ }
+ {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ if ((col = grn_ctx_at(ctx, *key))) {
+ output_column_info(ctx, col);
+ grn_obj_unlink(ctx, col);
+ }
+ });
+ }
+ grn_ctx_output_array_close(ctx);
+ grn_hash_close(ctx, cols);
+ grn_obj_unlink(ctx, table);
+
+ return NULL;
+}
+
+void
+grn_proc_init_column_list(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
+ grn_plugin_command_create(ctx,
+ "column_list", -1,
+ command_column_list,
+ 1,
+ vars);
+}
+
+static grn_rc
+command_column_copy_resolve_target(grn_ctx *ctx,
+ const char *label,
+ grn_obj *table_name,
+ grn_obj *column_name,
+ grn_obj **table,
+ grn_obj **column)
+{
+ if (GRN_TEXT_LEN(table_name) == 0) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][copy] %s table name isn't specified",
+ label);
+ return ctx->rc;
+ }
+ *table = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(table_name),
+ GRN_TEXT_LEN(table_name));
+ if (!*table) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][copy] %s table isn't found: <%.*s>",
+ label,
+ (int)GRN_TEXT_LEN(table_name),
+ GRN_TEXT_VALUE(table_name));
+ return ctx->rc;
+ }
+
+ if (GRN_TEXT_LEN(column_name) == 0) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][copy] %s column name isn't specified: <%.*s>",
+ label,
+ (int)GRN_TEXT_LEN(table_name),
+ GRN_TEXT_VALUE(table_name));
+ return ctx->rc;
+ }
+ *column = grn_obj_column(ctx, *table,
+ GRN_TEXT_VALUE(column_name),
+ GRN_TEXT_LEN(column_name));
+ if (!*column) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[column][copy] %s column isn't found: <%.*s.%.*s>",
+ label,
+ (int)GRN_TEXT_LEN(table_name), GRN_TEXT_VALUE(table_name),
+ (int)GRN_TEXT_LEN(column_name), GRN_TEXT_VALUE(column_name));
+ return ctx->rc;
+ }
+
+ return ctx->rc;
+}
+
+static void
+command_column_copy_same_table(grn_ctx *ctx, grn_obj *table,
+ grn_obj *from_column, grn_obj *to_column)
+{
+ grn_table_cursor *cursor;
+ grn_id id;
+ grn_obj value;
+
+ cursor = grn_table_cursor_open(ctx, table,
+ NULL, 0,
+ NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ return;
+ }
+
+ GRN_VOID_INIT(&value);
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, from_column, id, &value);
+ grn_obj_set_value(ctx, to_column, id, &value, GRN_OBJ_SET);
+ }
+ GRN_OBJ_FIN(ctx, &value);
+ grn_table_cursor_close(ctx, cursor);
+}
+
+static void
+command_column_copy_same_key_type(grn_ctx *ctx,
+ grn_obj *from_table,
+ grn_obj *from_column,
+ grn_obj *to_table,
+ grn_obj *to_column)
+{
+ grn_table_cursor *cursor;
+ grn_id from_id;
+ grn_obj value;
+
+ cursor = grn_table_cursor_open(ctx, from_table,
+ NULL, 0,
+ NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ return;
+ }
+
+ GRN_VOID_INIT(&value);
+ while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ void *key;
+ int key_size;
+ grn_id to_id;
+
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ to_id = grn_table_add(ctx, to_table, key, key_size, NULL);
+ if (to_id == GRN_ID_NIL) {
+ continue;
+ }
+
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, from_column, from_id, &value);
+ grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET);
+ }
+ GRN_OBJ_FIN(ctx, &value);
+ grn_table_cursor_close(ctx, cursor);
+}
+
+static void
+command_column_copy_different(grn_ctx *ctx,
+ grn_obj *from_table,
+ grn_obj *from_column,
+ grn_obj *to_table,
+ grn_obj *to_column,
+ grn_obj *from_table_name,
+ grn_obj *from_column_name,
+ grn_obj *to_table_name,
+ grn_obj *to_column_name)
+{
+ grn_table_cursor *cursor;
+ grn_id from_id;
+ grn_obj from_key_buffer;
+ grn_obj to_key_buffer;
+ grn_obj value;
+
+ cursor = grn_table_cursor_open(ctx, from_table,
+ NULL, 0,
+ NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ return;
+ }
+
+ if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
+ GRN_SHORT_TEXT_INIT(&from_key_buffer, 0);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&from_key_buffer, 0, from_table->header.domain);
+ }
+ if (to_table->header.domain == GRN_DB_SHORT_TEXT) {
+ GRN_SHORT_TEXT_INIT(&to_key_buffer, 0);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&to_key_buffer, 0, to_table->header.domain);
+ }
+ GRN_VOID_INIT(&value);
+ while ((from_id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ void *key;
+ int key_size;
+ grn_rc cast_rc;
+ grn_id to_id;
+
+ GRN_BULK_REWIND(&from_key_buffer);
+ GRN_BULK_REWIND(&to_key_buffer);
+
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ grn_bulk_write(ctx, &from_key_buffer, key, key_size);
+ cast_rc = grn_obj_cast(ctx, &from_key_buffer, &to_key_buffer, GRN_FALSE);
+ if (cast_rc != GRN_SUCCESS) {
+ grn_obj *to_key_type;
+ grn_obj inspected_key;
+ grn_obj inspected_to_key_type;
+
+ to_key_type = grn_ctx_at(ctx, to_table->header.domain);
+ GRN_TEXT_INIT(&inspected_key, 0);
+ GRN_TEXT_INIT(&inspected_to_key_type, 0);
+ grn_inspect(ctx, &inspected_key, &from_key_buffer);
+ grn_inspect(ctx, &inspected_to_key_type, to_key_type);
+ ERR(cast_rc,
+ "[column][copy] failed to cast key: <%.*s> -> %.*s: "
+ "<%.*s.%.*s> -> <%.*s.%.*s>",
+ (int)GRN_TEXT_LEN(&inspected_key),
+ GRN_TEXT_VALUE(&inspected_key),
+ (int)GRN_TEXT_LEN(&inspected_to_key_type),
+ GRN_TEXT_VALUE(&inspected_to_key_type),
+ (int)GRN_TEXT_LEN(from_table_name),
+ GRN_TEXT_VALUE(from_table_name),
+ (int)GRN_TEXT_LEN(from_column_name),
+ GRN_TEXT_VALUE(from_column_name),
+ (int)GRN_TEXT_LEN(to_table_name),
+ GRN_TEXT_VALUE(to_table_name),
+ (int)GRN_TEXT_LEN(to_column_name),
+ GRN_TEXT_VALUE(to_column_name));
+ GRN_OBJ_FIN(ctx, &inspected_key);
+ GRN_OBJ_FIN(ctx, &inspected_to_key_type);
+ break;
+ }
+ to_id = grn_table_add(ctx, to_table,
+ GRN_BULK_HEAD(&to_key_buffer),
+ GRN_BULK_VSIZE(&to_key_buffer),
+ NULL);
+ if (to_id == GRN_ID_NIL) {
+ continue;
+ }
+
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, from_column, from_id, &value);
+ grn_obj_set_value(ctx, to_column, to_id, &value, GRN_OBJ_SET);
+ }
+ GRN_OBJ_FIN(ctx, &from_key_buffer);
+ GRN_OBJ_FIN(ctx, &to_key_buffer);
+ GRN_OBJ_FIN(ctx, &value);
+
+ grn_table_cursor_close(ctx, cursor);
+}
+
+static grn_obj *
+command_column_copy(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *from_table = NULL;
+ grn_obj *from_column = NULL;
+ grn_obj *to_table = NULL;
+ grn_obj *to_column = NULL;
+ grn_obj *from_table_name;
+ grn_obj *from_column_name;
+ grn_obj *to_table_name;
+ grn_obj *to_column_name;
+
+ from_table_name = grn_plugin_proc_get_var(ctx, user_data, "from_table", -1);
+ from_column_name = grn_plugin_proc_get_var(ctx, user_data, "from_name", -1);
+ to_table_name = grn_plugin_proc_get_var(ctx, user_data, "to_table", -1);
+ to_column_name = grn_plugin_proc_get_var(ctx, user_data, "to_name", -1);
+
+ rc = command_column_copy_resolve_target(ctx, "from",
+ from_table_name, from_column_name,
+ &from_table, &from_column);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ rc = command_column_copy_resolve_target(ctx, "to",
+ to_table_name, to_column_name,
+ &to_table, &to_column);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ if ((from_table->header.type == GRN_TABLE_NO_KEY ||
+ to_table->header.type == GRN_TABLE_NO_KEY) &&
+ from_table != to_table) {
+ rc = GRN_OPERATION_NOT_SUPPORTED;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[column][copy] copy from/to TABLE_NO_KEY isn't supported: "
+ "<%.*s%c%.*s> -> <%.*s%c%.*s>",
+ (int)GRN_TEXT_LEN(from_table_name),
+ GRN_TEXT_VALUE(from_table_name),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(from_column_name),
+ GRN_TEXT_VALUE(from_column_name),
+ (int)GRN_TEXT_LEN(to_table_name),
+ GRN_TEXT_VALUE(to_table_name),
+ GRN_DB_DELIMITER,
+ (int)GRN_TEXT_LEN(to_column_name),
+ GRN_TEXT_VALUE(to_column_name));
+ goto exit;
+ }
+
+ if (from_table == to_table) {
+ command_column_copy_same_table(ctx, from_table, from_column, to_column);
+ } else if (from_table->header.domain == to_table->header.domain) {
+ command_column_copy_same_key_type(ctx,
+ from_table, from_column,
+ to_table, to_column);
+ } else {
+ command_column_copy_different(ctx,
+ from_table,
+ from_column,
+ to_table,
+ to_column,
+ from_table_name,
+ from_column_name,
+ to_table_name,
+ to_column_name);
+ }
+
+exit :
+ grn_ctx_output_bool(ctx, rc == GRN_SUCCESS);
+
+ if (to_column) {
+ grn_obj_unlink(ctx, to_column);
+ }
+ if (to_table) {
+ grn_obj_unlink(ctx, to_table);
+ }
+ if (from_column) {
+ grn_obj_unlink(ctx, from_column);
+ }
+ if (from_table) {
+ grn_obj_unlink(ctx, from_table);
+ }
+
+ return NULL;
+}
+
+void
+grn_proc_init_column_copy(grn_ctx *ctx)
+{
+ grn_expr_var vars[4];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "from_table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "from_name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "to_table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "to_name", -1);
+ grn_plugin_command_create(ctx,
+ "column_copy", -1,
+ command_column_copy,
+ 4,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_config.c b/storage/mroonga/vendor/groonga/lib/proc/proc_config.c
new file mode 100644
index 00000000..61a1c5a8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_config.c
@@ -0,0 +1,139 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include <groonga/plugin.h>
+
+static grn_obj *
+command_config_get(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *key;
+ const char *value;
+ uint32_t value_size;
+
+ key = grn_plugin_proc_get_var(ctx, user_data, "key", -1);
+ if (GRN_TEXT_LEN(key) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[config][get] key is missing");
+ return NULL;
+ }
+
+ grn_config_get(ctx,
+ GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key),
+ &value, &value_size);
+ if (ctx->rc) {
+ return NULL;
+ }
+
+ grn_ctx_output_str(ctx, value, value_size);
+
+ return NULL;
+}
+
+static grn_obj *
+command_config_set(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *key;
+ grn_obj *value;
+
+ key = grn_plugin_proc_get_var(ctx, user_data, "key", -1);
+ if (GRN_TEXT_LEN(key) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[config][set] key is missing");
+ return NULL;
+ }
+
+ value = grn_plugin_proc_get_var(ctx, user_data, "value", -1);
+ grn_config_set(ctx,
+ GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key),
+ GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
+
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+static grn_obj *
+command_config_delete(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *key;
+
+ key = grn_plugin_proc_get_var(ctx, user_data, "key", -1);
+ if (GRN_TEXT_LEN(key) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[config][delete] key is missing");
+ return NULL;
+ }
+
+ grn_config_delete(ctx,
+ GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key));
+
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+void
+grn_proc_init_config_get(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "key", -1);
+ grn_plugin_command_create(ctx,
+ "config_get", -1,
+ command_config_get,
+ 1,
+ vars);
+}
+
+void
+grn_proc_init_config_set(grn_ctx *ctx)
+{
+ grn_expr_var vars[2];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "key", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "value", -1);
+ grn_plugin_command_create(ctx,
+ "config_set", -1,
+ command_config_set,
+ 2,
+ vars);
+}
+
+void
+grn_proc_init_config_delete(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "key", -1);
+ grn_plugin_command_create(ctx,
+ "config_delete", -1,
+ command_config_delete,
+ 1,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_dump.c b/storage/mroonga/vendor/groonga/lib/proc/proc_dump.c
new file mode 100644
index 00000000..391925d8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_dump.c
@@ -0,0 +1,1138 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_ctx_impl.h"
+#include "../grn_db.h"
+#include "../grn_str.h"
+
+#include <groonga/plugin.h>
+
+static const size_t DUMP_FLUSH_THRESHOLD_SIZE = 256 * 1024;
+
+typedef struct {
+ grn_obj *output;
+ grn_bool is_close_opened_object_mode;
+ grn_bool have_reference_column;
+ grn_bool have_index_column;
+ grn_bool is_sort_hash_table;
+ grn_obj column_name_buffer;
+} grn_dumper;
+
+static void
+dumper_collect_statistics_table(grn_ctx *ctx,
+ grn_dumper *dumper,
+ grn_obj *table)
+{
+ grn_hash *columns;
+
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (!columns) {
+ return;
+ }
+
+ grn_table_columns(ctx, table, NULL, 0, (grn_obj *)columns);
+ GRN_HASH_EACH_BEGIN(ctx, columns, cursor, id) {
+ void *key;
+ grn_id column_id;
+ grn_obj *column;
+
+ grn_hash_cursor_get_key(ctx, cursor, &key);
+ column_id = *((grn_id *)key);
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ column = grn_ctx_at(ctx, column_id);
+ if (!column) {
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ goto next_loop;
+ }
+
+ if (grn_obj_is_index_column(ctx, column)) {
+ dumper->have_index_column = GRN_TRUE;
+ } else if (grn_obj_is_reference_column(ctx, column)) {
+ dumper->have_reference_column = GRN_TRUE;
+ }
+
+ next_loop :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+ grn_hash_close(ctx, columns);
+}
+
+static void
+dumper_collect_statistics(grn_ctx *ctx, grn_dumper *dumper)
+{
+ GRN_DB_EACH_BEGIN_BY_ID(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (!object) {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ goto next_loop;
+ }
+
+ if (!grn_obj_is_table(ctx, object)) {
+ goto next_loop;
+ }
+
+ dumper_collect_statistics_table(ctx, dumper, object);
+
+next_loop :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+}
+
+static void
+dump_value_raw(grn_ctx *ctx, grn_obj *output, const char *value, int value_len)
+{
+ grn_obj escaped_value;
+ GRN_TEXT_INIT(&escaped_value, 0);
+ grn_text_esc(ctx, &escaped_value, value, value_len);
+ /* is no character escaped? */
+ /* TODO false positive with spaces inside values */
+ if (GRN_TEXT_LEN(&escaped_value) == value_len + 2) {
+ GRN_TEXT_PUT(ctx, output, value, value_len);
+ } else {
+ GRN_TEXT_PUT(ctx, output,
+ GRN_TEXT_VALUE(&escaped_value), GRN_TEXT_LEN(&escaped_value));
+ }
+ grn_obj_close(ctx, &escaped_value);
+}
+
+static void
+dump_value(grn_ctx *ctx, grn_dumper *dumper, const char *value, int value_len)
+{
+ dump_value_raw(ctx, dumper->output, value, value_len);
+}
+
+static void
+dump_configs(grn_ctx *ctx, grn_dumper *dumper)
+{
+ grn_obj *config_cursor;
+
+ config_cursor = grn_config_cursor_open(ctx);
+ if (!config_cursor)
+ return;
+
+ while (grn_config_cursor_next(ctx, config_cursor)) {
+ const char *key;
+ uint32_t key_size;
+ const char *value;
+ uint32_t value_size;
+
+ key_size = grn_config_cursor_get_key(ctx, config_cursor, &key);
+ value_size = grn_config_cursor_get_value(ctx, config_cursor, &value);
+
+ GRN_TEXT_PUTS(ctx, dumper->output, "config_set ");
+ dump_value(ctx, dumper, key, key_size);
+ GRN_TEXT_PUTS(ctx, dumper->output, " ");
+ dump_value(ctx, dumper, value, value_size);
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+ }
+ grn_obj_close(ctx, config_cursor);
+}
+
+static void
+dump_plugins(grn_ctx *ctx, grn_dumper *dumper)
+{
+ grn_obj plugin_names;
+ unsigned int i, n;
+
+ GRN_TEXT_INIT(&plugin_names, GRN_OBJ_VECTOR);
+
+ grn_plugin_get_names(ctx, &plugin_names);
+
+ n = grn_vector_size(ctx, &plugin_names);
+ if (n == 0) {
+ GRN_OBJ_FIN(ctx, &plugin_names);
+ return;
+ }
+
+ if (GRN_TEXT_LEN(dumper->output) > 0) {
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+ grn_ctx_output_flush(ctx, 0);
+ }
+ for (i = 0; i < n; i++) {
+ const char *name;
+ unsigned int name_size;
+
+ name_size = grn_vector_get_element(ctx, &plugin_names, i, &name, NULL, NULL);
+ grn_text_printf(ctx, dumper->output, "plugin_register %.*s\n",
+ (int)name_size, name);
+ }
+
+ GRN_OBJ_FIN(ctx, &plugin_names);
+}
+
+static void
+dump_obj_name_raw(grn_ctx *ctx, grn_obj *output, grn_obj *obj)
+{
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_len;
+ name_len = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
+ dump_value_raw(ctx, output, name, name_len);
+}
+
+static void
+dump_obj_name(grn_ctx *ctx, grn_dumper *dumper, grn_obj *obj)
+{
+ dump_obj_name_raw(ctx, dumper->output, obj);
+}
+
+static void
+dump_column_name(grn_ctx *ctx, grn_dumper *dumper, grn_obj *column)
+{
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_len;
+ name_len = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
+ dump_value(ctx, dumper, name, name_len);
+}
+
+static void
+dump_index_column_sources(grn_ctx *ctx, grn_dumper *dumper, grn_obj *column)
+{
+ grn_obj sources;
+ grn_id *source_ids;
+ int i, n;
+
+ GRN_OBJ_INIT(&sources, GRN_BULK, 0, GRN_ID_NIL);
+ grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &sources);
+
+ n = GRN_BULK_VSIZE(&sources) / sizeof(grn_id);
+ source_ids = (grn_id *)GRN_BULK_HEAD(&sources);
+ if (n > 0) {
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ }
+ for (i = 0; i < n; i++) {
+ grn_id source_id;
+ grn_obj *source;
+
+ source_id = *source_ids;
+ source_ids++;
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ source = grn_ctx_at(ctx, source_id);
+ if (!source) {
+ goto next_loop;
+ }
+
+ if (i) { GRN_TEXT_PUTC(ctx, dumper->output, ','); }
+ switch (source->header.type) {
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_HASH_KEY:
+ GRN_TEXT_PUT(ctx,
+ dumper->output,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ break;
+ default:
+ dump_column_name(ctx, dumper, source);
+ break;
+ }
+
+ next_loop :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ }
+ grn_obj_close(ctx, &sources);
+}
+
+static void
+dump_column(grn_ctx *ctx, grn_dumper *dumper, grn_obj *table, grn_obj *column)
+{
+ grn_id type_id;
+ grn_obj *type;
+ grn_column_flags flags;
+ grn_column_flags default_flags = GRN_OBJ_PERSISTENT;
+
+ type_id = grn_obj_get_range(ctx, column);
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+ type = grn_ctx_at(ctx, type_id);
+ if (!type) {
+ /* ERR(GRN_RANGE_ERROR, "couldn't get column's type object"); */
+ goto exit;
+ }
+
+ GRN_TEXT_PUTS(ctx, dumper->output, "column_create ");
+ dump_obj_name(ctx, dumper, table);
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ dump_column_name(ctx, dumper, column);
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ if (type->header.type == GRN_TYPE) {
+ default_flags |= type->header.flags;
+ }
+ flags = grn_column_get_flags(ctx, column);
+ grn_dump_column_create_flags(ctx,
+ flags & ~default_flags,
+ dumper->output);
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ dump_obj_name(ctx, dumper, type);
+ if (column->header.flags & GRN_OBJ_COLUMN_INDEX) {
+ dump_index_column_sources(ctx, dumper, column);
+ }
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+
+exit :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+}
+
+static void
+dump_columns(grn_ctx *ctx, grn_dumper *dumper, grn_obj *table,
+ grn_bool dump_data_column,
+ grn_bool dump_reference_column,
+ grn_bool dump_index_column)
+{
+ grn_hash *columns;
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ if (!columns) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_NO_MEMORY_AVAILABLE,
+ "couldn't create a hash to hold columns");
+ return;
+ }
+
+ if (grn_table_columns(ctx, table, NULL, 0, (grn_obj *)columns) >= 0) {
+ GRN_HASH_EACH_BEGIN(ctx, columns, cursor, id) {
+ void *key;
+ grn_id column_id;
+ grn_obj *column;
+
+ grn_hash_cursor_get_key(ctx, cursor, &key);
+ column_id = *((grn_id *)key);
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ column = grn_ctx_at(ctx, column_id);
+ if (!column) {
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ goto next_loop;
+ }
+
+ if (grn_obj_is_index_column(ctx, column)) {
+ if (dump_index_column) {
+ dump_column(ctx, dumper, table, column);
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+ } else if (grn_obj_is_reference_column(ctx, column)) {
+ if (dump_reference_column) {
+ dump_column(ctx, dumper, table, column);
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+ } else {
+ if (dump_data_column) {
+ dump_column(ctx, dumper, table, column);
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+ }
+
+ next_loop :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+ grn_hash_close(ctx, columns);
+}
+
+static void
+dump_record_column_vector(grn_ctx *ctx, grn_dumper *dumper, grn_id id,
+ grn_obj *column, grn_id range_id, grn_obj *buf)
+{
+ grn_obj *range;
+ grn_obj_format *format_argument = NULL;
+ grn_obj_format format;
+
+ range = grn_ctx_at(ctx, range_id);
+ if (column->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ format.flags = GRN_OBJ_FORMAT_WITH_WEIGHT;
+ format_argument = &format;
+ }
+
+ if (grn_obj_is_table(ctx, range) ||
+ (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) == 0) {
+ GRN_OBJ_INIT(buf, GRN_UVECTOR, 0, range_id);
+ grn_obj_get_value(ctx, column, id, buf);
+ grn_text_otoj(ctx, dumper->output, buf, format_argument);
+ } else {
+ GRN_OBJ_INIT(buf, GRN_VECTOR, 0, range_id);
+ grn_obj_get_value(ctx, column, id, buf);
+ grn_text_otoj(ctx, dumper->output, buf, format_argument);
+ }
+
+ grn_obj_unlink(ctx, range);
+ grn_obj_unlink(ctx, buf);
+}
+
+static void
+dump_record(grn_ctx *ctx, grn_dumper *dumper,
+ grn_obj *table,
+ grn_id id,
+ grn_obj *columns, int n_columns)
+{
+ int j;
+ grn_obj buf;
+ grn_obj *column_name = &(dumper->column_name_buffer);
+
+ GRN_TEXT_PUTC(ctx, dumper->output, '[');
+ for (j = 0; j < n_columns; j++) {
+ grn_bool is_value_column;
+ grn_id range;
+ grn_obj *column;
+ column = GRN_PTR_VALUE_AT(columns, j);
+ /* TODO: use grn_obj_is_value_accessor() */
+ GRN_BULK_REWIND(column_name);
+ grn_column_name_(ctx, column, column_name);
+ if (GRN_TEXT_LEN(column_name) == GRN_COLUMN_NAME_VALUE_LEN &&
+ !memcmp(GRN_TEXT_VALUE(column_name),
+ GRN_COLUMN_NAME_VALUE,
+ GRN_COLUMN_NAME_VALUE_LEN)) {
+ is_value_column = GRN_TRUE;
+ } else {
+ is_value_column = GRN_FALSE;
+ }
+ range = grn_obj_get_range(ctx, column);
+
+ if (j) { GRN_TEXT_PUTC(ctx, dumper->output, ','); }
+ switch (column->header.type) {
+ case GRN_COLUMN_VAR_SIZE:
+ case GRN_COLUMN_FIX_SIZE:
+ switch (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_VECTOR:
+ dump_record_column_vector(ctx, dumper, id, column, range, &buf);
+ break;
+ case GRN_OBJ_COLUMN_SCALAR:
+ {
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ grn_obj_get_value(ctx, column, id, &buf);
+ grn_text_otoj(ctx, dumper->output, &buf, NULL);
+ grn_obj_unlink(ctx, &buf);
+ }
+ break;
+ default:
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_OPERATION_NOT_SUPPORTED,
+ "unsupported column type: %#x",
+ column->header.type);
+ break;
+ }
+ break;
+ case GRN_COLUMN_INDEX:
+ break;
+ case GRN_ACCESSOR:
+ {
+ GRN_OBJ_INIT(&buf, GRN_BULK, 0, range);
+ grn_obj_get_value(ctx, column, id, &buf);
+ /* XXX maybe, grn_obj_get_range() should not unconditionally return
+ GRN_DB_INT32 when column is GRN_ACCESSOR and
+ GRN_ACCESSOR_GET_VALUE */
+ if (is_value_column) {
+ buf.header.domain = grn_obj_get_range(ctx, table);
+ }
+ grn_text_otoj(ctx, dumper->output, &buf, NULL);
+ grn_obj_unlink(ctx, &buf);
+ }
+ break;
+ default:
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_OPERATION_NOT_SUPPORTED,
+ "unsupported header type %#x",
+ column->header.type);
+ break;
+ }
+ }
+ GRN_TEXT_PUTC(ctx, dumper->output, ']');
+ if ((size_t) GRN_TEXT_LEN(dumper->output) >= DUMP_FLUSH_THRESHOLD_SIZE) {
+ grn_ctx_output_flush(ctx, 0);
+ }
+}
+
+static void
+dump_records(grn_ctx *ctx, grn_dumper *dumper, grn_obj *table)
+{
+ grn_table_cursor *cursor;
+ int i, n_columns;
+ grn_obj columns;
+ grn_bool have_index_column = GRN_FALSE;
+ grn_bool have_data_column = GRN_FALSE;
+
+ if (grn_table_size(ctx, table) == 0) {
+ return;
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ GRN_PTR_INIT(&columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
+
+ if (table->header.type == GRN_TABLE_NO_KEY) {
+ grn_obj *id_accessor;
+ id_accessor = grn_obj_column(ctx,
+ table,
+ GRN_COLUMN_NAME_ID,
+ GRN_COLUMN_NAME_ID_LEN);
+ GRN_PTR_PUT(ctx, &columns, id_accessor);
+ } else if (table->header.domain != GRN_ID_NIL) {
+ grn_obj *key_accessor;
+ key_accessor = grn_obj_column(ctx,
+ table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ GRN_PTR_PUT(ctx, &columns, key_accessor);
+ }
+
+ if (grn_obj_get_range(ctx, table) != GRN_ID_NIL) {
+ grn_obj *value_accessor;
+ value_accessor = grn_obj_column(ctx,
+ table,
+ GRN_COLUMN_NAME_VALUE,
+ GRN_COLUMN_NAME_VALUE_LEN);
+ GRN_PTR_PUT(ctx, &columns, value_accessor);
+ }
+
+ {
+ grn_hash *real_columns;
+
+ real_columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ grn_table_columns(ctx, table, NULL, 0, (grn_obj *)real_columns);
+ GRN_HASH_EACH_BEGIN(ctx, real_columns, cursor, id) {
+ void *key;
+ grn_id column_id;
+ grn_obj *column;
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ grn_hash_cursor_get_key(ctx, cursor, &key);
+ column_id = *((grn_id *)key);
+
+ column = grn_ctx_at(ctx, column_id);
+ if (column) {
+ if (grn_obj_is_index_column(ctx, column)) {
+ have_index_column = GRN_TRUE;
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } else {
+ have_data_column = GRN_TRUE;
+ GRN_PTR_PUT(ctx, &columns, column);
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_merge_temporary_open_space(ctx);
+ }
+ }
+ } else {
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+ grn_hash_close(ctx, real_columns);
+ }
+
+ n_columns = GRN_BULK_VSIZE(&columns) / sizeof(grn_obj *);
+
+ if (have_index_column && !have_data_column) {
+ goto exit;
+ }
+
+ if (GRN_TEXT_LEN(dumper->output) > 0) {
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+ }
+
+ GRN_TEXT_PUTS(ctx, dumper->output, "load --table ");
+ dump_obj_name(ctx, dumper, table);
+ GRN_TEXT_PUTS(ctx, dumper->output, "\n[\n");
+
+ GRN_TEXT_PUTC(ctx, dumper->output, '[');
+ for (i = 0; i < n_columns; i++) {
+ grn_obj *column;
+ grn_obj *column_name = &(dumper->column_name_buffer);
+
+ column = GRN_PTR_VALUE_AT(&columns, i);
+ if (i) { GRN_TEXT_PUTC(ctx, dumper->output, ','); }
+ GRN_BULK_REWIND(column_name);
+ grn_column_name_(ctx, column, column_name);
+ grn_text_otoj(ctx, dumper->output, column_name, NULL);
+ }
+ GRN_TEXT_PUTS(ctx, dumper->output, "],\n");
+
+ if (table->header.type == GRN_TABLE_HASH_KEY && dumper->is_sort_hash_table) {
+ grn_obj *sorted;
+ grn_table_sort_key sort_keys[1];
+ uint32_t n_sort_keys = 1;
+ grn_bool is_first_record = GRN_TRUE;
+
+ sort_keys[0].key = grn_obj_column(ctx, table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ sort_keys[0].flags = GRN_TABLE_SORT_ASC;
+ sort_keys[0].offset = 0;
+ sorted = grn_table_create(ctx,
+ NULL, 0, NULL,
+ GRN_TABLE_NO_KEY,
+ NULL,
+ table);
+ grn_table_sort(ctx,
+ table, 0, -1,
+ sorted,
+ sort_keys, n_sort_keys);
+ cursor = grn_table_cursor_open(ctx,
+ sorted,
+ NULL, 0, NULL, 0,
+ 0, -1,
+ 0);
+ while (grn_table_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ void *value_raw;
+ grn_id id;
+
+ grn_table_cursor_get_value(ctx, cursor, &value_raw);
+ id = *((grn_id *)value_raw);
+
+ if (is_first_record) {
+ is_first_record = GRN_FALSE;
+ } else {
+ GRN_TEXT_PUTS(ctx, dumper->output, ",\n");
+ }
+ dump_record(ctx, dumper, table, id, &columns, n_columns);
+ }
+ GRN_TEXT_PUTS(ctx, dumper->output, "\n]\n");
+ grn_obj_close(ctx, sorted);
+ grn_obj_unlink(ctx, sort_keys[0].key);
+ } else {
+ grn_obj delete_commands;
+ grn_id old_id = GRN_ID_NIL;
+ grn_id id;
+
+ GRN_TEXT_INIT(&delete_commands, 0);
+ cursor = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_BY_KEY);
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ if (old_id != GRN_ID_NIL) { GRN_TEXT_PUTS(ctx, dumper->output, ",\n"); }
+ if (table->header.type == GRN_TABLE_NO_KEY && old_id + 1 < id) {
+ grn_id current_id;
+ for (current_id = old_id + 1; current_id < id; current_id++) {
+ GRN_TEXT_PUTS(ctx, dumper->output, "[],\n");
+ GRN_TEXT_PUTS(ctx, &delete_commands, "delete --table ");
+ dump_obj_name_raw(ctx, &delete_commands, table);
+ GRN_TEXT_PUTS(ctx, &delete_commands, " --id ");
+ grn_text_lltoa(ctx, &delete_commands, current_id);
+ GRN_TEXT_PUTC(ctx, &delete_commands, '\n');
+ }
+ }
+ dump_record(ctx, dumper, table, id, &columns, n_columns);
+
+ old_id = id;
+ }
+ grn_table_cursor_close(ctx, cursor);
+ GRN_TEXT_PUTS(ctx, dumper->output, "\n]\n");
+ GRN_TEXT_PUT(ctx, dumper->output,
+ GRN_TEXT_VALUE(&delete_commands),
+ GRN_TEXT_LEN(&delete_commands));
+ GRN_OBJ_FIN(ctx, &delete_commands);
+ }
+exit :
+ for (i = 0; i < n_columns; i++) {
+ grn_obj *column;
+
+ column = GRN_PTR_VALUE_AT(&columns, i);
+ if (column->header.type == GRN_ACCESSOR) {
+ grn_obj_close(ctx, column);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &columns);
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+}
+
+static void
+dump_table(grn_ctx *ctx, grn_dumper *dumper, grn_obj *table)
+{
+ grn_obj *domain = NULL;
+ grn_id range_id;
+ grn_obj *range = NULL;
+ grn_table_flags flags;
+ grn_table_flags default_flags = GRN_OBJ_PERSISTENT;
+ grn_obj *default_tokenizer;
+ grn_obj *normalizer;
+ grn_obj *token_filters;
+
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ domain = grn_ctx_at(ctx, table->header.domain);
+ break;
+ default:
+ break;
+ }
+
+ if (GRN_TEXT_LEN(dumper->output) > 0) {
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+ grn_ctx_output_flush(ctx, 0);
+ }
+
+ grn_table_get_info(ctx, table,
+ &flags,
+ NULL,
+ &default_tokenizer,
+ &normalizer,
+ &token_filters);
+
+ GRN_TEXT_PUTS(ctx, dumper->output, "table_create ");
+ dump_obj_name(ctx, dumper, table);
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ grn_dump_table_create_flags(ctx,
+ flags & ~default_flags,
+ dumper->output);
+ if (domain) {
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ dump_obj_name(ctx, dumper, domain);
+ }
+ range_id = grn_obj_get_range(ctx, table);
+ if (range_id != GRN_ID_NIL) {
+ range = grn_ctx_at(ctx, range_id);
+ if (!range) {
+ // ERR(GRN_RANGE_ERROR, "couldn't get table's value_type object");
+ return;
+ }
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ GRN_TEXT_PUTC(ctx, dumper->output, ' ');
+ } else {
+ GRN_TEXT_PUTS(ctx, dumper->output, " --value_type ");
+ }
+ dump_obj_name(ctx, dumper, range);
+ grn_obj_unlink(ctx, range);
+ }
+ if (default_tokenizer) {
+ GRN_TEXT_PUTS(ctx, dumper->output, " --default_tokenizer ");
+ dump_obj_name(ctx, dumper, default_tokenizer);
+ }
+ if (normalizer) {
+ GRN_TEXT_PUTS(ctx, dumper->output, " --normalizer ");
+ dump_obj_name(ctx, dumper, normalizer);
+ }
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ int n_token_filters;
+
+ n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
+ if (n_token_filters > 0) {
+ int i;
+ GRN_TEXT_PUTS(ctx, dumper->output, " --token_filters ");
+ for (i = 0; i < n_token_filters; i++) {
+ grn_obj *token_filter = GRN_PTR_VALUE_AT(token_filters, i);
+ if (i > 0) {
+ GRN_TEXT_PUTC(ctx, dumper->output, ',');
+ }
+ dump_obj_name(ctx, dumper, token_filter);
+ }
+ }
+ }
+
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+
+ dump_columns(ctx, dumper, table, GRN_TRUE, GRN_FALSE, GRN_FALSE);
+}
+
+static void
+dump_schema(grn_ctx *ctx, grn_dumper *dumper)
+{
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ if ((object = grn_ctx_at(ctx, id))) {
+ switch (object->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ dump_table(ctx, dumper, object);
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+
+ if (!dumper->have_reference_column) {
+ return;
+ }
+
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+ grn_ctx_output_flush(ctx, 0);
+
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ if ((object = grn_ctx_at(ctx, id))) {
+ switch (object->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY:
+ case GRN_TABLE_NO_KEY:
+ dump_columns(ctx, dumper, object, GRN_FALSE, GRN_TRUE, GRN_FALSE);
+ break;
+ default:
+ break;
+ }
+ } else {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+}
+
+static void
+dump_selected_tables_records(grn_ctx *ctx, grn_dumper *dumper, grn_obj *tables)
+{
+ const char *p, *e;
+
+ p = GRN_TEXT_VALUE(tables);
+ e = p + GRN_TEXT_LEN(tables);
+ while (p < e) {
+ int len;
+ grn_obj *table;
+ const char *token, *token_e;
+
+ if ((len = grn_isspace(p, ctx->encoding))) {
+ p += len;
+ continue;
+ }
+
+ token = p;
+ if (!(('a' <= *p && *p <= 'z') ||
+ ('A' <= *p && *p <= 'Z') ||
+ (*p == '_'))) {
+ while (p < e && !grn_isspace(p, ctx->encoding)) {
+ p++;
+ }
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid table name is ignored: <%.*s>\n",
+ (int)(p - token), token);
+ continue;
+ }
+ while (p < e &&
+ (('a' <= *p && *p <= 'z') ||
+ ('A' <= *p && *p <= 'Z') ||
+ ('0' <= *p && *p <= '9') ||
+ (*p == '_'))) {
+ p++;
+ }
+ token_e = p;
+ while (p < e && (len = grn_isspace(p, ctx->encoding))) {
+ p += len;
+ continue;
+ }
+ if (p < e && *p == ',') {
+ p++;
+ }
+
+ table = grn_ctx_get(ctx, token, token_e - token);
+ if (!table) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "nonexistent table name is ignored: <%.*s>\n",
+ (int)(token_e - token), token);
+ continue;
+ }
+
+ if (grn_obj_is_table(ctx, table)) {
+ dump_records(ctx, dumper, table);
+ }
+ grn_obj_unlink(ctx, table);
+ }
+}
+
+static void
+dump_all_records(grn_ctx *ctx, grn_dumper *dumper)
+{
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *table;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ table = grn_ctx_at(ctx, id);
+ if (!table) {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ goto next_loop;
+ }
+
+ if (grn_obj_is_table(ctx, table)) {
+ dump_records(ctx, dumper, table);
+ }
+
+ next_loop :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+}
+
+static void
+dump_indexes(grn_ctx *ctx, grn_dumper *dumper)
+{
+ if (!dumper->have_index_column) {
+ return;
+ }
+
+ if (GRN_TEXT_LEN(dumper->output) > 0) {
+ GRN_TEXT_PUTC(ctx, dumper->output, '\n');
+ }
+
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (!object) {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ goto next_loop;
+ }
+
+ if (grn_obj_is_table(ctx, object)) {
+ dump_columns(ctx, dumper, object, GRN_FALSE, GRN_FALSE, GRN_TRUE);
+ }
+
+ next_loop :
+ if (dumper->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+}
+
+static grn_obj *
+command_dump(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_dumper dumper;
+ grn_obj *tables;
+ grn_bool is_dump_plugins;
+ grn_bool is_dump_schema;
+ grn_bool is_dump_records;
+ grn_bool is_dump_indexes;
+ grn_bool is_dump_configs;
+
+ dumper.output = ctx->impl->output.buf;
+ if (grn_thread_get_limit() == 1) {
+ dumper.is_close_opened_object_mode = GRN_TRUE;
+ } else {
+ dumper.is_close_opened_object_mode = GRN_FALSE;
+ }
+ dumper.have_reference_column = GRN_FALSE;
+ dumper.have_index_column = GRN_FALSE;
+
+ tables = grn_plugin_proc_get_var(ctx, user_data, "tables", -1);
+ is_dump_plugins = grn_plugin_proc_get_var_bool(ctx, user_data,
+ "dump_plugins", -1,
+ GRN_TRUE);
+ is_dump_schema = grn_plugin_proc_get_var_bool(ctx, user_data,
+ "dump_schema", -1,
+ GRN_TRUE);
+ is_dump_records = grn_plugin_proc_get_var_bool(ctx, user_data,
+ "dump_records", -1,
+ GRN_TRUE);
+ is_dump_indexes = grn_plugin_proc_get_var_bool(ctx, user_data,
+ "dump_indexes", -1,
+ GRN_TRUE);
+ is_dump_configs = grn_plugin_proc_get_var_bool(ctx, user_data,
+ "dump_configs", -1,
+ GRN_TRUE);
+ dumper.is_sort_hash_table =
+ grn_plugin_proc_get_var_bool(ctx, user_data,
+ "sort_hash_table", -1,
+ GRN_FALSE);
+ GRN_TEXT_INIT(&(dumper.column_name_buffer), 0);
+
+ grn_ctx_set_output_type(ctx, GRN_CONTENT_GROONGA_COMMAND_LIST);
+
+ dumper_collect_statistics(ctx, &dumper);
+
+ if (is_dump_configs) {
+ dump_configs(ctx, &dumper);
+ }
+ if (is_dump_plugins) {
+ dump_plugins(ctx, &dumper);
+ }
+ if (is_dump_schema) {
+ dump_schema(ctx, &dumper);
+ }
+ if (is_dump_records) {
+ /* To update index columns correctly, we first create the whole schema, then
+ load non-derivative records, while skipping records of index columns. That
+ way, Groonga will silently do the job of updating index columns for us. */
+ if (GRN_TEXT_LEN(tables) > 0) {
+ dump_selected_tables_records(ctx, &dumper, tables);
+ } else {
+ dump_all_records(ctx, &dumper);
+ }
+ }
+ if (is_dump_indexes) {
+ dump_indexes(ctx, &dumper);
+ }
+ /* remove the last newline because another one will be added by the caller.
+ maybe, the caller of proc functions currently doesn't consider the
+ possibility of multiple-line output from proc functions. */
+ if (GRN_BULK_VSIZE(dumper.output) > 0) {
+ grn_bulk_truncate(ctx, dumper.output, GRN_BULK_VSIZE(dumper.output) - 1);
+ }
+
+ GRN_OBJ_FIN(ctx, &(dumper.column_name_buffer));
+
+ return NULL;
+}
+
+void
+grn_proc_init_dump(grn_ctx *ctx)
+{
+ grn_expr_var vars[7];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "tables", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "dump_plugins", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "dump_schema", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "dump_records", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "dump_indexes", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[5]), "dump_configs", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[6]), "sort_hash_table", -1);
+ grn_plugin_command_create(ctx,
+ "dump", -1,
+ command_dump,
+ sizeof(vars) / sizeof(vars[0]),
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_fuzzy_search.c b/storage/mroonga/vendor/groonga/lib/proc/proc_fuzzy_search.c
new file mode 100644
index 00000000..952fdbb1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_fuzzy_search.c
@@ -0,0 +1,467 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_rset.h"
+#include "../grn_ii.h"
+
+#include <groonga/plugin.h>
+
+#include <string.h>
+
+#define DIST(ox,oy) (dists[((lx + 1) * (oy)) + (ox)])
+
+static uint32_t
+calc_edit_distance(grn_ctx *ctx, char *sx, char *ex, char *sy, char *ey, int flags)
+{
+ int d = 0;
+ uint32_t cx, lx, cy, ly, *dists;
+ char *px, *py;
+ for (px = sx, lx = 0; px < ex && (cx = grn_charlen(ctx, px, ex)); px += cx, lx++);
+ for (py = sy, ly = 0; py < ey && (cy = grn_charlen(ctx, py, ey)); py += cy, ly++);
+ if ((dists = GRN_PLUGIN_MALLOC(ctx, (lx + 1) * (ly + 1) * sizeof(uint32_t)))) {
+ uint32_t x, y;
+ for (x = 0; x <= lx; x++) { DIST(x, 0) = x; }
+ for (y = 0; y <= ly; y++) { DIST(0, y) = y; }
+ for (x = 1, px = sx; x <= lx; x++, px += cx) {
+ cx = grn_charlen(ctx, px, ex);
+ for (y = 1, py = sy; y <= ly; y++, py += cy) {
+ cy = grn_charlen(ctx, py, ey);
+ if (cx == cy && !memcmp(px, py, cx)) {
+ DIST(x, y) = DIST(x - 1, y - 1);
+ } else {
+ uint32_t a = DIST(x - 1, y) + 1;
+ uint32_t b = DIST(x, y - 1) + 1;
+ uint32_t c = DIST(x - 1, y - 1) + 1;
+ DIST(x, y) = ((a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c));
+ if (flags & GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION &&
+ x > 1 && y > 1 && cx == cy &&
+ memcmp(px, py - cy, cx) == 0 &&
+ memcmp(px - cx, py, cx) == 0) {
+ uint32_t t = DIST(x - 2, y - 2) + 1;
+ DIST(x, y) = ((DIST(x, y) < t) ? DIST(x, y) : t);
+ }
+ }
+ }
+ }
+ d = DIST(lx, ly);
+ GRN_PLUGIN_FREE(ctx, dists);
+ }
+ return d;
+}
+
+static grn_obj *
+func_edit_distance(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+#define N_REQUIRED_ARGS 2
+#define MAX_ARGS 3
+ int d = 0;
+ int flags = 0;
+ grn_obj *obj;
+ if (nargs >= N_REQUIRED_ARGS && nargs <= MAX_ARGS) {
+ if (nargs == MAX_ARGS && GRN_BOOL_VALUE(args[2])) {
+ flags |= GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION;
+ }
+ d = calc_edit_distance(ctx, GRN_TEXT_VALUE(args[0]), GRN_BULK_CURR(args[0]),
+ GRN_TEXT_VALUE(args[1]), GRN_BULK_CURR(args[1]), flags);
+ }
+ if ((obj = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_UINT32, 0))) {
+ GRN_UINT32_SET(ctx, obj, d);
+ }
+ return obj;
+#undef N_REQUIRED_ARGS
+#undef MAX_ARGS
+}
+
+void
+grn_proc_init_edit_distance(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "edit_distance", -1, GRN_PROC_FUNCTION,
+ func_edit_distance, NULL, NULL, 0, NULL);
+}
+
+#define SCORE_HEAP_SIZE 256
+
+typedef struct {
+ grn_id id;
+ uint32_t score;
+} score_heap_node;
+
+typedef struct {
+ int n_entries;
+ int limit;
+ score_heap_node *nodes;
+} score_heap;
+
+static inline score_heap *
+score_heap_open(grn_ctx *ctx, int max)
+{
+ score_heap *h = GRN_PLUGIN_MALLOC(ctx, sizeof(score_heap));
+ if (!h) { return NULL; }
+ h->nodes = GRN_PLUGIN_MALLOC(ctx, sizeof(score_heap_node) * max);
+ if (!h->nodes) {
+ GRN_PLUGIN_FREE(ctx, h);
+ return NULL;
+ }
+ h->n_entries = 0;
+ h->limit = max;
+ return h;
+}
+
+static inline grn_bool
+score_heap_push(grn_ctx *ctx, score_heap *h, grn_id id, uint32_t score)
+{
+ int n, n2;
+ score_heap_node node = {id, score};
+ score_heap_node node2;
+ if (h->n_entries >= h->limit) {
+ int max = h->limit * 2;
+ score_heap_node *nodes;
+ nodes = GRN_PLUGIN_REALLOC(ctx, h->nodes, sizeof(score_heap) * max);
+ if (!nodes) {
+ return GRN_FALSE;
+ }
+ h->limit = max;
+ h->nodes = nodes;
+ }
+ h->nodes[h->n_entries] = node;
+ n = h->n_entries++;
+ while (n) {
+ n2 = (n - 1) >> 1;
+ if (h->nodes[n2].score <= h->nodes[n].score) { break; }
+ node2 = h->nodes[n];
+ h->nodes[n] = h->nodes[n2];
+ h->nodes[n2] = node2;
+ n = n2;
+ }
+ return GRN_TRUE;
+}
+
+static inline void
+score_heap_close(grn_ctx *ctx, score_heap *h)
+{
+ GRN_PLUGIN_FREE(ctx, h->nodes);
+ GRN_PLUGIN_FREE(ctx, h);
+}
+
+static grn_rc
+sequential_fuzzy_search(grn_ctx *ctx, grn_obj *table, grn_obj *column, grn_obj *query,
+ uint32_t max_distance, uint32_t prefix_match_size,
+ uint32_t max_expansion, int flags, grn_obj *res, grn_operator op)
+{
+ grn_table_cursor *tc;
+ char *sx = GRN_TEXT_VALUE(query);
+ char *ex = GRN_BULK_CURR(query);
+
+ if (op == GRN_OP_AND) {
+ tc = grn_table_cursor_open(ctx, res, NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_BY_ID);
+ } else {
+ tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1, GRN_CURSOR_BY_ID);
+ }
+ if (tc) {
+ grn_id id;
+ grn_obj value;
+ score_heap *heap;
+ int i, n;
+ GRN_TEXT_INIT(&value, 0);
+
+ heap = score_heap_open(ctx, SCORE_HEAP_SIZE);
+ if (!heap) {
+ grn_table_cursor_close(ctx, tc);
+ grn_obj_unlink(ctx, &value);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+
+ while ((id = grn_table_cursor_next(ctx, tc))) {
+ unsigned int distance = 0;
+ grn_obj *domain;
+ grn_id record_id;
+
+ if (op == GRN_OP_AND) {
+ grn_id *key;
+ grn_table_cursor_get_key(ctx, tc, (void **)&key);
+ record_id = *key;
+ } else {
+ record_id = id;
+ }
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, column, record_id, &value);
+ domain = grn_ctx_at(ctx, ((&value))->header.domain);
+ if ((&(value))->header.type == GRN_VECTOR) {
+ n = grn_vector_size(ctx, &value);
+ for (i = 0; i < n; i++) {
+ unsigned int length;
+ const char *vector_value = NULL;
+ length = grn_vector_get_element(ctx, &value, i, &vector_value, NULL, NULL);
+
+ if (!prefix_match_size ||
+ (prefix_match_size > 0 && length >= prefix_match_size &&
+ !memcmp(sx, vector_value, prefix_match_size))) {
+ distance = calc_edit_distance(ctx, sx, ex,
+ (char *)vector_value,
+ (char *)vector_value + length, flags);
+ if (distance <= max_distance) {
+ score_heap_push(ctx, heap, record_id, distance);
+ break;
+ }
+ }
+ }
+ } else if ((&(value))->header.type == GRN_UVECTOR &&
+ grn_obj_is_table(ctx, domain)) {
+ n = grn_vector_size(ctx, &value);
+ for (i = 0; i < n; i++) {
+ grn_id rid;
+ char key_name[GRN_TABLE_MAX_KEY_SIZE];
+ int key_length;
+ rid = grn_uvector_get_element(ctx, &value, i, NULL);
+ key_length = grn_table_get_key(ctx, domain, rid, key_name, GRN_TABLE_MAX_KEY_SIZE);
+
+ if (!prefix_match_size ||
+ (prefix_match_size > 0 && key_length >= (int) prefix_match_size &&
+ !memcmp(sx, key_name, prefix_match_size))) {
+ distance = calc_edit_distance(ctx, sx, ex,
+ key_name, key_name + key_length, flags);
+ if (distance <= max_distance) {
+ score_heap_push(ctx, heap, record_id, distance);
+ break;
+ }
+ }
+ }
+ } else {
+ if (grn_obj_is_reference_column(ctx, column)) {
+ grn_id rid;
+ char key_name[GRN_TABLE_MAX_KEY_SIZE];
+ int key_length;
+ rid = GRN_RECORD_VALUE(&value);
+ key_length = grn_table_get_key(ctx, domain, rid, key_name, GRN_TABLE_MAX_KEY_SIZE);
+ if (!prefix_match_size ||
+ (prefix_match_size > 0 && key_length >= (int) prefix_match_size &&
+ !memcmp(sx, key_name, prefix_match_size))) {
+ distance = calc_edit_distance(ctx, sx, ex,
+ key_name, key_name + key_length, flags);
+ if (distance <= max_distance) {
+ score_heap_push(ctx, heap, record_id, distance);
+ }
+ }
+ } else {
+ if (!prefix_match_size ||
+ (prefix_match_size > 0 && GRN_TEXT_LEN(&value) >= prefix_match_size &&
+ !memcmp(sx, GRN_TEXT_VALUE(&value), prefix_match_size))) {
+ distance = calc_edit_distance(ctx, sx, ex,
+ GRN_TEXT_VALUE(&value),
+ GRN_BULK_CURR(&value), flags);
+ if (distance <= max_distance) {
+ score_heap_push(ctx, heap, record_id, distance);
+ }
+ }
+ }
+ }
+ grn_obj_unlink(ctx, domain);
+ }
+ grn_table_cursor_close(ctx, tc);
+ grn_obj_unlink(ctx, &value);
+
+ for (i = 0; i < heap->n_entries; i++) {
+ if (max_expansion > 0 && (uint32_t) i >= max_expansion) {
+ break;
+ }
+ {
+ grn_posting posting;
+ posting.rid = heap->nodes[i].id;
+ posting.sid = 1;
+ posting.pos = 0;
+ posting.weight = max_distance - heap->nodes[i].score;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ }
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ score_heap_close(ctx, heap);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+selector_fuzzy_search(grn_ctx *ctx, grn_obj *table, grn_obj *index,
+ int nargs, grn_obj **args,
+ grn_obj *res, grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *target = NULL;
+ grn_obj *obj;
+ grn_obj *query;
+ uint32_t max_distance = 1;
+ uint32_t prefix_length = 0;
+ uint32_t prefix_match_size = 0;
+ uint32_t max_expansion = 0;
+ int flags = 0;
+ grn_bool use_sequential_search = GRN_FALSE;
+
+ if ((nargs - 1) < 2) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "fuzzy_search(): wrong number of arguments (%d ...)",
+ nargs - 1);
+ rc = ctx->rc;
+ goto exit;
+ }
+ obj = args[1];
+ query = args[2];
+
+ if (nargs == 4) {
+ grn_obj *options = args[3];
+
+ switch (options->header.type) {
+ case GRN_BULK :
+ max_distance = GRN_UINT32_VALUE(options);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ {
+ grn_hash_cursor *cursor;
+ void *key;
+ grn_obj *value;
+ int key_size;
+ cursor = grn_hash_cursor_open(ctx, (grn_hash *)options,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "fuzzy_search(): couldn't open cursor");
+ goto exit;
+ }
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_hash_cursor_get_key_value(ctx, cursor, &key, &key_size,
+ (void **)&value);
+
+ if (key_size == 12 && !memcmp(key, "max_distance", 12)) {
+ max_distance = GRN_UINT32_VALUE(value);
+ } else if (key_size == 13 && !memcmp(key, "prefix_length", 13)) {
+ prefix_length = GRN_UINT32_VALUE(value);
+ } else if (key_size == 13 && !memcmp(key, "max_expansion", 13)) {
+ max_expansion = GRN_UINT32_VALUE(value);
+ } else if (key_size == 18 && !memcmp(key, "with_transposition", 18)) {
+ if (GRN_BOOL_VALUE(value)) {
+ flags |= GRN_TABLE_FUZZY_SEARCH_WITH_TRANSPOSITION;
+ }
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "invalid option name: <%.*s>",
+ key_size, (char *)key);
+ grn_hash_cursor_close(ctx, cursor);
+ goto exit;
+ }
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ break;
+ default :
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "fuzzy_search(): "
+ "3rd argument must be integer or object literal: <%.*s>",
+ (int)GRN_TEXT_LEN(options),
+ GRN_TEXT_VALUE(options));
+ goto exit;
+ }
+ }
+
+ if (index) {
+ target = index;
+ } else {
+ if (obj->header.type == GRN_COLUMN_INDEX) {
+ target = obj;
+ } else {
+ grn_column_index(ctx, obj, GRN_OP_FUZZY, &target, 1, NULL);
+ }
+ }
+
+ if (target) {
+ grn_obj *lexicon;
+ use_sequential_search = GRN_TRUE;
+ lexicon = grn_ctx_at(ctx, target->header.domain);
+ if (lexicon) {
+ if (lexicon->header.type == GRN_TABLE_PAT_KEY) {
+ use_sequential_search = GRN_FALSE;
+ }
+ grn_obj_unlink(ctx, lexicon);
+ }
+ } else {
+ if (grn_obj_is_key_accessor(ctx, obj) &&
+ table->header.type == GRN_TABLE_PAT_KEY) {
+ target = table;
+ } else {
+ use_sequential_search = GRN_TRUE;
+ }
+ }
+
+ if (prefix_length) {
+ const char *s = GRN_TEXT_VALUE(query);
+ const char *e = GRN_BULK_CURR(query);
+ const char *p;
+ unsigned int cl = 0;
+ unsigned int length = 0;
+ for (p = s; p < e && (cl = grn_charlen(ctx, p, e)); p += cl) {
+ length++;
+ if (length > prefix_length) {
+ break;
+ }
+ }
+ prefix_match_size = p - s;
+ }
+
+ if (use_sequential_search) {
+ rc = sequential_fuzzy_search(ctx, table, obj, query,
+ max_distance, prefix_match_size,
+ max_expansion, flags, res, op);
+ goto exit;
+ }
+
+ if (!target) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, target);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "fuzzy_search(): "
+ "column must be COLUMN_INDEX or TABLE_PAT_KEY: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ rc = ctx->rc;
+ GRN_OBJ_FIN(ctx, &inspected);
+ } else {
+ grn_search_optarg options = {0};
+ options.mode = GRN_OP_FUZZY;
+ options.fuzzy.prefix_match_size = prefix_match_size;
+ options.fuzzy.max_distance = max_distance;
+ options.fuzzy.max_expansion = max_expansion;
+ options.fuzzy.flags = flags;
+ grn_obj_search(ctx, target, query, res, op, &options);
+ }
+
+exit :
+ return rc;
+}
+
+void
+grn_proc_init_fuzzy_search(grn_ctx *ctx)
+{
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "fuzzy_search", -1,
+ GRN_PROC_FUNCTION,
+ NULL, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_fuzzy_search);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_FUZZY);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_highlight.c b/storage/mroonga/vendor/groonga/lib/proc/proc_highlight.c
new file mode 100644
index 00000000..80551a10
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_highlight.c
@@ -0,0 +1,503 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_expr.h"
+
+#include <groonga/plugin.h>
+#include <string.h>
+
+#define GRN_FUNC_HIGHLIGHT_HTML_CACHE_NAME "$highlight_html"
+
+static void
+grn_pat_tag_keys_put_original_text(grn_ctx *ctx, grn_obj *output,
+ const char *text, unsigned int length,
+ grn_bool use_html_escape)
+{
+ if (use_html_escape) {
+ grn_text_escape_xml(ctx, output, text, length);
+ } else {
+ GRN_TEXT_PUT(ctx, output, text, length);
+ }
+}
+
+static grn_rc
+grn_pat_tag_keys(grn_ctx *ctx, grn_obj *keywords,
+ const char *string, unsigned int string_length,
+ const char **open_tags, unsigned int *open_tag_lengths,
+ const char **close_tags, unsigned int *close_tag_lengths,
+ unsigned int n_tags,
+ grn_obj *highlighted,
+ grn_bool use_html_escape)
+{
+ while (string_length > 0) {
+#define MAX_N_HITS 16
+ grn_pat_scan_hit hits[MAX_N_HITS];
+ const char *rest;
+ unsigned int i, n_hits;
+ unsigned int previous = 0;
+ size_t chunk_length;
+
+ n_hits = grn_pat_scan(ctx, (grn_pat *)keywords,
+ string, string_length,
+ hits, MAX_N_HITS, &rest);
+ for (i = 0; i < n_hits; i++) {
+ unsigned int nth_tag;
+ if (hits[i].offset - previous > 0) {
+ grn_pat_tag_keys_put_original_text(ctx,
+ highlighted,
+ string + previous,
+ hits[i].offset - previous,
+ use_html_escape);
+ }
+ nth_tag = ((hits[i].id - 1) % n_tags);
+ GRN_TEXT_PUT(ctx, highlighted,
+ open_tags[nth_tag], open_tag_lengths[nth_tag]);
+ grn_pat_tag_keys_put_original_text(ctx,
+ highlighted,
+ string + hits[i].offset,
+ hits[i].length,
+ use_html_escape);
+ GRN_TEXT_PUT(ctx, highlighted,
+ close_tags[nth_tag], close_tag_lengths[nth_tag]);
+ previous = hits[i].offset + hits[i].length;
+ }
+
+ chunk_length = rest - string;
+ if (chunk_length - previous > 0) {
+ grn_pat_tag_keys_put_original_text(ctx,
+ highlighted,
+ string + previous,
+ string_length - previous,
+ use_html_escape);
+ }
+ string_length -= chunk_length;
+ string = rest;
+#undef MAX_N_HITS
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_obj *
+func_highlight_create_keywords_table(grn_ctx *ctx,
+ grn_user_data *user_data,
+ const char *normalizer_name,
+ unsigned int normalizer_name_length)
+{
+ grn_obj *keywords;
+
+ keywords = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_PAT_KEY,
+ grn_ctx_at(ctx, GRN_DB_SHORT_TEXT),
+ NULL);
+
+ if (normalizer_name_length > 0) {
+ grn_obj *normalizer;
+ normalizer = grn_ctx_get(ctx,
+ normalizer_name,
+ normalizer_name_length);
+ if (!grn_obj_is_normalizer_proc(ctx, normalizer)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, normalizer);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "highlight_full() not normalizer: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ grn_obj_unlink(ctx, normalizer);
+ grn_obj_unlink(ctx, keywords);
+ return NULL;
+ }
+ grn_obj_set_info(ctx, keywords, GRN_INFO_NORMALIZER, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+
+ return keywords;
+}
+
+static grn_obj *
+highlight_keyword_sets(grn_ctx *ctx, grn_user_data *user_data,
+ grn_obj **keyword_set_args, unsigned int n_keyword_args,
+ grn_obj *string, grn_obj *keywords,
+ grn_bool use_html_escape)
+{
+ grn_obj *highlighted = NULL;
+#define KEYWORD_SET_SIZE 3
+ {
+ unsigned int i;
+ unsigned int n_keyword_sets;
+ grn_obj open_tags;
+ grn_obj open_tag_lengths;
+ grn_obj close_tags;
+ grn_obj close_tag_lengths;
+
+ n_keyword_sets = n_keyword_args / KEYWORD_SET_SIZE;
+
+ GRN_OBJ_INIT(&open_tags, GRN_BULK, 0, GRN_DB_VOID);
+ GRN_OBJ_INIT(&open_tag_lengths, GRN_BULK, 0, GRN_DB_VOID);
+ GRN_OBJ_INIT(&close_tags, GRN_BULK, 0, GRN_DB_VOID);
+ GRN_OBJ_INIT(&close_tag_lengths, GRN_BULK, 0, GRN_DB_VOID);
+
+ for (i = 0; i < n_keyword_sets; i++) {
+ grn_obj *keyword = keyword_set_args[i * KEYWORD_SET_SIZE + 0];
+ grn_obj *open_tag = keyword_set_args[i * KEYWORD_SET_SIZE + 1];
+ grn_obj *close_tag = keyword_set_args[i * KEYWORD_SET_SIZE + 2];
+
+ grn_table_add(ctx, keywords,
+ GRN_TEXT_VALUE(keyword),
+ GRN_TEXT_LEN(keyword),
+ NULL);
+ {
+ const char *open_tag_content = GRN_TEXT_VALUE(open_tag);
+ grn_bulk_write(ctx, &open_tags,
+ (const char *)(&open_tag_content),
+ sizeof(char *));
+ }
+ {
+ unsigned int open_tag_length = GRN_TEXT_LEN(open_tag);
+ grn_bulk_write(ctx, &open_tag_lengths,
+ (const char *)(&open_tag_length),
+ sizeof(unsigned int));
+ }
+ {
+ const char *close_tag_content = GRN_TEXT_VALUE(close_tag);
+ grn_bulk_write(ctx, &close_tags,
+ (const char *)(&close_tag_content),
+ sizeof(char *));
+ }
+ {
+ unsigned int close_tag_length = GRN_TEXT_LEN(close_tag);
+ grn_bulk_write(ctx, &close_tag_lengths,
+ (const char *)(&close_tag_length),
+ sizeof(unsigned int));
+ }
+ }
+
+ highlighted = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_TEXT, 0);
+ grn_pat_tag_keys(ctx, keywords,
+ GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
+ (const char **)GRN_BULK_HEAD(&open_tags),
+ (unsigned int *)GRN_BULK_HEAD(&open_tag_lengths),
+ (const char **)GRN_BULK_HEAD(&close_tags),
+ (unsigned int *)GRN_BULK_HEAD(&close_tag_lengths),
+ n_keyword_sets,
+ highlighted,
+ use_html_escape);
+ grn_obj_unlink(ctx, &open_tags);
+ grn_obj_unlink(ctx, &open_tag_lengths);
+ grn_obj_unlink(ctx, &close_tags);
+ grn_obj_unlink(ctx, &close_tag_lengths);
+ }
+#undef KEYWORD_SET_SIZE
+ return highlighted;
+}
+
+static grn_obj *
+highlight_keywords(grn_ctx *ctx, grn_user_data *user_data,
+ grn_obj *string, grn_obj *keywords, grn_bool use_html_escape,
+ const char *default_open_tag, unsigned int default_open_tag_length,
+ const char *default_close_tag, unsigned int default_close_tag_length)
+{
+ grn_obj *highlighted = NULL;
+ const char *open_tags[1];
+ unsigned int open_tag_lengths[1];
+ const char *close_tags[1];
+ unsigned int close_tag_lengths[1];
+ unsigned int n_keyword_sets = 1;
+
+ open_tags[0] = default_open_tag;
+ open_tag_lengths[0] = default_open_tag_length;
+ close_tags[0] = default_close_tag;
+ close_tag_lengths[0] = default_close_tag_length;
+
+ highlighted = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_TEXT, 0);
+ grn_pat_tag_keys(ctx, keywords,
+ GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
+ open_tags,
+ open_tag_lengths,
+ close_tags,
+ close_tag_lengths,
+ n_keyword_sets,
+ highlighted,
+ use_html_escape);
+
+ return highlighted;
+}
+
+static grn_obj *
+func_highlight(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *highlighted = NULL;
+
+#define N_REQUIRED_ARGS 1
+ if (nargs > N_REQUIRED_ARGS) {
+ grn_obj *string = args[0];
+ grn_bool use_html_escape = GRN_FALSE;
+ grn_obj *keywords;
+ const char *normalizer_name = "NormalizerAuto";
+ unsigned int normalizer_name_length = 14;
+ const char *default_open_tag = NULL;
+ unsigned int default_open_tag_length = 0;
+ const char *default_close_tag = NULL;
+ unsigned int default_close_tag_length = 0;
+ grn_obj *end_arg = args[nargs - 1];
+ int n_args_without_option = nargs;
+
+ if (end_arg->header.type == GRN_TABLE_HASH_KEY) {
+ grn_obj *options = end_arg;
+ grn_hash_cursor *cursor;
+ void *key;
+ grn_obj *value;
+ int key_size;
+
+ n_args_without_option--;
+ cursor = grn_hash_cursor_open(ctx, (grn_hash *)options,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "highlight(): couldn't open cursor");
+ goto exit;
+ }
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_hash_cursor_get_key_value(ctx, cursor, &key, &key_size,
+ (void **)&value);
+ if (key_size == 10 && !memcmp(key, "normalizer", 10)) {
+ normalizer_name = GRN_TEXT_VALUE(value);
+ normalizer_name_length = GRN_TEXT_LEN(value);
+ } else if (key_size == 11 && !memcmp(key, "html_escape", 11)) {
+ if (GRN_BOOL_VALUE(value)) {
+ use_html_escape = GRN_TRUE;
+ }
+ } else if (key_size == 16 && !memcmp(key, "default_open_tag", 16)) {
+ default_open_tag = GRN_TEXT_VALUE(value);
+ default_open_tag_length = GRN_TEXT_LEN(value);
+ } else if (key_size == 17 && !memcmp(key, "default_close_tag", 17)) {
+ default_close_tag = GRN_TEXT_VALUE(value);
+ default_close_tag_length = GRN_TEXT_LEN(value);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "invalid option name: <%.*s>",
+ key_size, (char *)key);
+ grn_hash_cursor_close(ctx, cursor);
+ goto exit;
+ }
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+
+ keywords =
+ func_highlight_create_keywords_table(ctx, user_data,
+ normalizer_name,
+ normalizer_name_length);
+
+ if (keywords) {
+ grn_obj **keyword_args = args + N_REQUIRED_ARGS;
+ unsigned int n_keyword_args = n_args_without_option - N_REQUIRED_ARGS;
+ if (default_open_tag_length == 0 && default_close_tag_length == 0) {
+ highlighted = highlight_keyword_sets(ctx, user_data,
+ keyword_args, n_keyword_args,
+ string, keywords, use_html_escape);
+ } else {
+ unsigned int i;
+ for (i = 0; i < n_keyword_args; i++) {
+ grn_table_add(ctx, keywords,
+ GRN_TEXT_VALUE(keyword_args[i]),
+ GRN_TEXT_LEN(keyword_args[i]),
+ NULL);
+ }
+ highlighted = highlight_keywords(ctx, user_data,
+ string, keywords, use_html_escape,
+ default_open_tag, default_open_tag_length,
+ default_close_tag, default_close_tag_length);
+ }
+ }
+ }
+#undef N_REQUIRED_ARGS
+
+exit :
+ if (!highlighted) {
+ highlighted = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
+ }
+
+ return highlighted;
+}
+
+void
+grn_proc_init_highlight(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "highlight", -1, GRN_PROC_FUNCTION,
+ func_highlight, NULL, NULL, 0, NULL);
+}
+
+static grn_obj *
+func_highlight_full(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *highlighted = NULL;
+
+#define N_REQUIRED_ARGS 3
+#define KEYWORD_SET_SIZE 3
+ if ((nargs >= (N_REQUIRED_ARGS + KEYWORD_SET_SIZE) &&
+ (nargs - N_REQUIRED_ARGS) % KEYWORD_SET_SIZE == 0)) {
+ grn_obj *string = args[0];
+ grn_obj *keywords;
+ const char *normalizer_name = GRN_TEXT_VALUE(args[1]);
+ unsigned int normalizer_name_length = GRN_TEXT_LEN(args[1]);
+ grn_bool use_html_escape = GRN_BOOL_VALUE(args[2]);
+
+ keywords =
+ func_highlight_create_keywords_table(ctx, user_data,
+ normalizer_name,
+ normalizer_name_length);
+ if (keywords) {
+ highlighted = highlight_keyword_sets(ctx, user_data,
+ args + N_REQUIRED_ARGS,
+ nargs - N_REQUIRED_ARGS,
+ string, keywords,
+ use_html_escape);
+ }
+ }
+
+ if (!highlighted) {
+ highlighted = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
+ }
+#undef KEYWORD_SET_SIZE
+#undef N_REQUIRED_ARGS
+
+ return highlighted;
+}
+
+void
+grn_proc_init_highlight_full(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "highlight_full", -1, GRN_PROC_FUNCTION,
+ func_highlight_full, NULL, NULL, 0, NULL);
+}
+
+static grn_obj *
+func_highlight_html_create_keywords_table(grn_ctx *ctx, grn_obj *expression)
+{
+ grn_obj *keywords;
+ grn_obj *condition_ptr = NULL;
+ grn_obj *condition = NULL;
+
+ keywords = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_PAT_KEY,
+ grn_ctx_at(ctx, GRN_DB_SHORT_TEXT),
+ NULL);
+
+ {
+ grn_obj *normalizer;
+ normalizer = grn_ctx_get(ctx, "NormalizerAuto", -1);
+ grn_obj_set_info(ctx, keywords, GRN_INFO_NORMALIZER, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+
+ condition_ptr = grn_expr_get_var(ctx, expression,
+ GRN_SELECT_INTERNAL_VAR_CONDITION,
+ strlen(GRN_SELECT_INTERNAL_VAR_CONDITION));
+ if (condition_ptr) {
+ condition = GRN_PTR_VALUE(condition_ptr);
+ }
+
+ if (condition) {
+ size_t i, n_keywords;
+ grn_obj current_keywords;
+ GRN_TEXT_INIT(&current_keywords, GRN_OBJ_VECTOR);
+ grn_expr_get_keywords(ctx, condition, &current_keywords);
+
+ n_keywords = grn_vector_size(ctx, &current_keywords);
+ for (i = 0; i < n_keywords; i++) {
+ const char *keyword;
+ unsigned int keyword_size;
+ keyword_size = grn_vector_get_element(ctx,
+ &current_keywords,
+ i,
+ &keyword,
+ NULL,
+ NULL);
+ grn_table_add(ctx,
+ keywords,
+ keyword,
+ keyword_size,
+ NULL);
+ }
+ GRN_OBJ_FIN(ctx, &current_keywords);
+ }
+
+ return keywords;
+}
+
+static grn_obj *
+func_highlight_html(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *highlighted = NULL;
+
+#define N_REQUIRED_ARGS 1
+ if (nargs == N_REQUIRED_ARGS) {
+ grn_obj *string = args[0];
+ grn_obj *expression = NULL;
+ grn_obj *keywords;
+ grn_obj *keywords_ptr;
+ grn_bool use_html_escape = GRN_TRUE;
+
+ grn_proc_get_info(ctx, user_data, NULL, NULL, &expression);
+
+ keywords_ptr = grn_expr_get_var(ctx, expression,
+ GRN_FUNC_HIGHLIGHT_HTML_CACHE_NAME,
+ strlen(GRN_FUNC_HIGHLIGHT_HTML_CACHE_NAME));
+ if (keywords_ptr) {
+ keywords = GRN_PTR_VALUE(keywords_ptr);
+ } else {
+ keywords_ptr =
+ grn_expr_get_or_add_var(ctx, expression,
+ GRN_FUNC_HIGHLIGHT_HTML_CACHE_NAME,
+ strlen(GRN_FUNC_HIGHLIGHT_HTML_CACHE_NAME));
+ GRN_OBJ_FIN(ctx, keywords_ptr);
+ GRN_PTR_INIT(keywords_ptr, GRN_OBJ_OWN, GRN_DB_OBJECT);
+
+ keywords = func_highlight_html_create_keywords_table(ctx, expression);
+ GRN_PTR_SET(ctx, keywords_ptr, keywords);
+ }
+
+ highlighted = highlight_keywords(ctx, user_data,
+ string, keywords, use_html_escape,
+ "<span class=\"keyword\">",
+ strlen("<span class=\"keyword\">"),
+ "</span>",
+ strlen("</span>"));
+ }
+#undef N_REQUIRED_ARGS
+
+ if (!highlighted) {
+ highlighted = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
+ }
+
+ return highlighted;
+}
+
+void
+grn_proc_init_highlight_html(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "highlight_html", -1, GRN_PROC_FUNCTION,
+ func_highlight_html, NULL, NULL, 0, NULL);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_in_records.c b/storage/mroonga/vendor/groonga/lib/proc/proc_in_records.c
new file mode 100644
index 00000000..e3b8a7e3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_in_records.c
@@ -0,0 +1,519 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_db.h"
+#include "../grn_store.h"
+
+#include <groonga/plugin.h>
+
+typedef struct {
+ int n_conditions;
+ grn_obj *condition_table;
+ grn_obj condition_columns;
+ grn_operator *condition_modes;
+ grn_obj *search_result;
+} grn_in_records_data;
+
+static void
+grn_in_records_data_free(grn_ctx *ctx, grn_in_records_data *data)
+{
+ int i;
+ int n_condition_columns;
+
+ if (!data) {
+ return;
+ }
+
+ GRN_PLUGIN_FREE(ctx, data->condition_modes);
+
+ n_condition_columns =
+ GRN_BULK_VSIZE(&(data->condition_columns)) / sizeof(grn_obj *);
+ for (i = 0; i < n_condition_columns; i++) {
+ grn_obj *condition_column;
+ condition_column = GRN_PTR_VALUE_AT(&(data->condition_columns), i);
+ if (condition_column && condition_column->header.type == GRN_ACCESSOR) {
+ grn_obj_unlink(ctx, condition_column);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &(data->condition_columns));
+
+ if (data->search_result) {
+ grn_obj_close(ctx, data->search_result);
+ }
+
+ GRN_PLUGIN_FREE(ctx, data);
+}
+
+static grn_obj *
+func_in_records_init(grn_ctx *ctx,
+ int n_args,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_in_records_data *data;
+ grn_obj *condition_table;
+ grn_expr_code *codes;
+ int n_arg_codes;
+ int n_logical_args;
+ int n_conditions;
+ int i;
+ int nth;
+
+ {
+ grn_obj *caller;
+ grn_expr *expr;
+ grn_expr_code *call_code;
+
+ caller = grn_plugin_proc_get_caller(ctx, user_data);
+ expr = (grn_expr *)caller;
+ call_code = expr->codes + expr->codes_curr - 1;
+ n_logical_args = call_code->nargs - 1;
+ codes = expr->codes + 1;
+ n_arg_codes = expr->codes_curr - 2;
+ }
+
+ if (n_logical_args < 4) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): wrong number of arguments (%d for 4..)",
+ n_logical_args);
+ return NULL;
+ }
+
+ if ((n_logical_args % 3) != 1) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): the number of arguments must be 1 + 3n (%d)",
+ n_logical_args);
+ return NULL;
+ }
+
+ n_conditions = (n_logical_args - 1) / 3;
+
+ condition_table = codes[0].value;
+ if (!grn_obj_is_table(ctx, condition_table)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, condition_table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): the first argument must be a table: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ data = GRN_PLUGIN_CALLOC(ctx, sizeof(grn_in_records_data));
+ if (!data) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): failed to allocate internal data");
+ return NULL;
+ }
+ user_data->ptr = data;
+
+ data->n_conditions = n_conditions;
+ data->condition_table = condition_table;
+ GRN_PTR_INIT(&(data->condition_columns), GRN_OBJ_VECTOR, GRN_ID_NIL);
+ data->condition_modes = GRN_PLUGIN_MALLOCN(ctx, grn_operator, n_conditions);
+ if (!data->condition_modes) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): "
+ "failed to allocate internal data for condition modes");
+ goto exit;
+ }
+
+ for (i = 1, nth = 0; i < n_arg_codes; nth++) {
+ int value_i = i;
+ int mode_name_i;
+ grn_obj *mode_name;
+ int column_name_i;
+ grn_obj *column_name;
+ grn_obj *condition_column;
+
+ value_i += codes[value_i].modify;
+
+ mode_name_i = value_i + 1;
+ mode_name = codes[mode_name_i].value;
+ data->condition_modes[nth] = grn_proc_option_value_mode(ctx,
+ mode_name,
+ GRN_OP_EQUAL,
+ "in_records()");
+ if (ctx->rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ column_name_i = mode_name_i + 1;
+ column_name = codes[column_name_i].value;
+ if (!grn_obj_is_text_family_bulk(ctx, column_name)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, condition_table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): "
+ "the %dth argument must be column name as string: "
+ "<%.*s>",
+ column_name_i,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ goto exit;
+ }
+
+ condition_column = grn_obj_column(ctx, condition_table,
+ GRN_TEXT_VALUE(column_name),
+ GRN_TEXT_LEN(column_name));
+ if (!condition_column) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, condition_table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): "
+ "the %dth argument must be existing column name: "
+ "<%.*s>: <%.*s>",
+ column_name_i,
+ (int)GRN_TEXT_LEN(column_name),
+ GRN_TEXT_VALUE(column_name),
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ goto exit;
+ }
+ GRN_PTR_PUT(ctx, &(data->condition_columns), condition_column);
+
+ i = column_name_i + 1;
+ }
+
+ return NULL;
+
+exit :
+ grn_in_records_data_free(ctx, data);
+
+ return NULL;
+}
+
+static grn_obj *
+func_in_records_next(grn_ctx *ctx,
+ int n_args,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_in_records_data *data = user_data->ptr;
+ grn_obj *found;
+ grn_obj *condition;
+ grn_obj *variable;
+ int i;
+
+ found = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_BOOL, 0);
+ if (!found) {
+ return NULL;
+ }
+ GRN_BOOL_SET(ctx, found, GRN_FALSE);
+
+ if (!data) {
+ return found;
+ }
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx,
+ data->condition_table,
+ condition,
+ variable);
+ if (!condition) {
+ grn_rc rc = ctx->rc;
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "in_records(): "
+ "failed to create internal expression: %s",
+ ctx->errbuf);
+ return found;
+ }
+
+ for (i = 1; i < n_args; i += 3) {
+ int nth = (i - 1) / 3;
+ grn_obj *value = args[i];
+ grn_obj *condition_column;
+ grn_operator condition_mode;
+
+ condition_column = GRN_PTR_VALUE_AT(&(data->condition_columns), nth);
+ condition_mode = data->condition_modes[nth];
+
+ switch (condition_mode) {
+ case GRN_OP_EQUAL :
+ case GRN_OP_NOT_EQUAL :
+ grn_expr_append_obj(ctx, condition, condition_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, condition, value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, condition, condition_mode, 2);
+ break;
+ case GRN_OP_LESS :
+ grn_expr_append_obj(ctx, condition, condition_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, condition, value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, condition, GRN_OP_GREATER_EQUAL, 2);
+ break;
+ case GRN_OP_GREATER :
+ grn_expr_append_obj(ctx, condition, condition_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, condition, value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, condition, GRN_OP_LESS_EQUAL, 2);
+ break;
+ case GRN_OP_LESS_EQUAL :
+ grn_expr_append_obj(ctx, condition, condition_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, condition, value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, condition, GRN_OP_GREATER, 2);
+ break;
+ case GRN_OP_GREATER_EQUAL :
+ grn_expr_append_obj(ctx, condition, condition_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, condition, value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, condition, GRN_OP_LESS, 2);
+ break;
+ default :
+ grn_expr_append_obj(ctx, condition, value, GRN_OP_PUSH, 1);
+ grn_expr_append_obj(ctx, condition, condition_column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_op(ctx, condition, condition_mode, 2);
+ break;
+ }
+
+ if (nth > 0) {
+ grn_expr_append_op(ctx, condition, GRN_OP_AND, 2);
+ }
+ }
+
+ data->search_result = grn_table_select(ctx,
+ data->condition_table,
+ condition,
+ data->search_result,
+ GRN_OP_OR);
+ if (grn_table_size(ctx, data->search_result) > 0) {
+ GRN_BOOL_SET(ctx, found, GRN_TRUE);
+
+ GRN_TABLE_EACH_BEGIN(ctx, data->search_result, cursor, id) {
+ grn_table_cursor_delete(ctx, cursor);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ }
+
+ grn_obj_close(ctx, condition);
+
+ return found;
+}
+
+static grn_obj *
+func_in_records_fin(grn_ctx *ctx,
+ int n_args,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_in_records_data *data = user_data->ptr;
+
+ grn_in_records_data_free(ctx, data);
+
+ return NULL;
+}
+
+static grn_rc
+selector_in_records(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ int n_args,
+ grn_obj **args,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_obj *condition_table;
+ grn_operator *condition_modes = NULL;
+ grn_obj condition_columns;
+ int i, nth;
+
+ /* TODO: Enable me when function call is supported. */
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+
+ if (n_args < 5) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): wrong number of arguments (%d for 4..)",
+ n_args - 1);
+ return ctx->rc;
+ }
+
+ condition_table = args[1];
+ if (!grn_obj_is_table(ctx, condition_table)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, condition_table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): the first argument must be a table: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+
+ condition_modes = GRN_PLUGIN_MALLOCN(ctx, grn_operator, (n_args - 2) / 3);
+ GRN_PTR_INIT(&condition_columns, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ for (i = 2, nth = 0; i < n_args; i += 3, nth++) {
+ int mode_name_i = i + 1;
+ int column_name_i = i + 2;
+ grn_obj *mode_name;
+ grn_operator mode;
+ grn_obj *column_name;
+ grn_obj *condition_column;
+
+ mode_name = args[mode_name_i];
+ mode = grn_proc_option_value_mode(ctx,
+ mode_name,
+ GRN_OP_EQUAL,
+ "in_records()");
+ if (ctx->rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ condition_modes[nth] = mode;
+
+ column_name = args[column_name_i];
+ if (!grn_obj_is_text_family_bulk(ctx, column_name)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, condition_table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): "
+ "the %dth argument must be column name as string: "
+ "<%.*s>",
+ column_name_i,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ goto exit;
+ }
+
+ condition_column = grn_obj_column(ctx, condition_table,
+ GRN_TEXT_VALUE(column_name),
+ GRN_TEXT_LEN(column_name));
+ if (!condition_column) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, condition_table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): "
+ "the %dth argument must be existing column name: "
+ "<%.*s>: <%.*s>",
+ column_name_i,
+ (int)GRN_TEXT_LEN(column_name),
+ GRN_TEXT_VALUE(column_name),
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ goto exit;
+ }
+ GRN_PTR_PUT(ctx, &condition_columns, condition_column);
+ }
+
+ {
+ grn_obj condition_column_value;
+
+ GRN_VOID_INIT(&condition_column_value);
+ GRN_TABLE_EACH_BEGIN(ctx, condition_table, cursor, id) {
+ grn_obj *sub_res = NULL;
+
+ for (i = 2; i < n_args; i += 3) {
+ int nth = (i - 2) / 3;
+ grn_operator sub_op;
+ grn_obj *condition_column;
+ grn_operator condition_mode;
+ grn_obj *column = args[i];
+ grn_obj *expr;
+ grn_obj *variable;
+
+ if (nth == 0) {
+ sub_op = GRN_OP_OR;
+ } else {
+ sub_op = GRN_OP_AND;
+ }
+
+ condition_column = GRN_PTR_VALUE_AT(&condition_columns, nth);
+ condition_mode = condition_modes[nth];
+
+ GRN_BULK_REWIND(&condition_column_value);
+ grn_obj_get_value(ctx,
+ condition_column,
+ id,
+ &condition_column_value);
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, expr, variable);
+ if (!expr) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "in_records(): failed to create expression");
+ GRN_OBJ_FIN(ctx, &condition_column_value);
+ if (sub_res) {
+ grn_obj_close(ctx, sub_res);
+ }
+ goto exit;
+ }
+ grn_expr_append_obj(ctx, expr, column, GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, expr, &condition_column_value, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, expr, condition_mode, 2);
+ sub_res = grn_table_select(ctx, table, expr, sub_res, sub_op);
+ grn_obj_close(ctx, expr);
+ }
+
+ if (sub_res) {
+ grn_table_setoperation(ctx, res, sub_res, res, op);
+ grn_obj_close(ctx, sub_res);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ GRN_OBJ_FIN(ctx, &condition_column_value);
+ }
+
+exit :
+ GRN_PLUGIN_FREE(ctx, condition_modes);
+
+ for (i = 2; i < n_args; i += 3) {
+ int nth = (i - 2) / 3;
+ grn_obj *condition_column;
+ condition_column = GRN_PTR_VALUE_AT(&condition_columns, nth);
+ if (condition_column && condition_column->header.type == GRN_ACCESSOR) {
+ grn_obj_unlink(ctx, condition_column);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &condition_columns);
+
+ return ctx->rc;
+}
+
+void
+grn_proc_init_in_records(grn_ctx *ctx)
+{
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "in_records", -1, GRN_PROC_FUNCTION,
+ func_in_records_init,
+ func_in_records_next,
+ func_in_records_fin,
+ 0,
+ NULL);
+ grn_proc_set_selector(ctx, selector_proc, selector_in_records);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_lock.c b/storage/mroonga/vendor/groonga/lib/proc/proc_lock.c
new file mode 100644
index 00000000..9eaf808a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_lock.c
@@ -0,0 +1,172 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include "../grn_ctx.h"
+
+#include <groonga/plugin.h>
+
+static grn_obj *
+command_lock_clear(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ int target_name_len;
+ grn_obj *target_name;
+ grn_obj *obj;
+
+ target_name = grn_plugin_proc_get_var(ctx, user_data, "target_name", -1);
+ target_name_len = GRN_TEXT_LEN(target_name);
+
+ if (target_name_len) {
+ obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(target_name), target_name_len);
+ } else {
+ obj = grn_ctx_db(ctx);
+ }
+
+ if (obj) {
+ grn_obj_clear_lock(ctx, obj);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[lock][clear] target object not found: <%.*s>",
+ target_name_len, GRN_TEXT_VALUE(target_name));
+ }
+
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+void
+grn_proc_init_clearlock(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ /* Deprecated. Use "lock_clear" instead. */
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "target_name", -1);
+ grn_plugin_command_create(ctx,
+ "clearlock", -1,
+ command_lock_clear,
+ 1,
+ vars);
+}
+
+void
+grn_proc_init_lock_clear(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "target_name", -1);
+ grn_plugin_command_create(ctx,
+ "lock_clear", -1,
+ command_lock_clear,
+ 1,
+ vars);
+}
+
+static grn_obj *
+command_lock_acquire(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ int target_name_len;
+ grn_obj *target_name;
+ grn_obj *obj;
+
+ target_name = grn_plugin_proc_get_var(ctx, user_data, "target_name", -1);
+ target_name_len = GRN_TEXT_LEN(target_name);
+
+ if (target_name_len) {
+ obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(target_name), target_name_len);
+ } else {
+ obj = grn_ctx_db(ctx);
+ }
+
+ if (obj) {
+ grn_obj_lock(ctx, obj, GRN_ID_NIL, grn_lock_timeout);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[lock][acquire] target object not found: <%.*s>",
+ target_name_len, GRN_TEXT_VALUE(target_name));
+ }
+
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+void
+grn_proc_init_lock_acquire(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "target_name", -1);
+ grn_plugin_command_create(ctx,
+ "lock_acquire", -1,
+ command_lock_acquire,
+ 1,
+ vars);
+}
+
+static grn_obj *
+command_lock_release(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ int target_name_len;
+ grn_obj *target_name;
+ grn_obj *obj;
+
+ target_name = grn_plugin_proc_get_var(ctx, user_data, "target_name", -1);
+ target_name_len = GRN_TEXT_LEN(target_name);
+
+ if (target_name_len) {
+ obj = grn_ctx_get(ctx, GRN_TEXT_VALUE(target_name), target_name_len);
+ } else {
+ obj = grn_ctx_db(ctx);
+ }
+
+ if (obj) {
+ grn_obj_unlock(ctx, obj, GRN_ID_NIL);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[lock][release] target object not found: <%.*s>",
+ target_name_len, GRN_TEXT_VALUE(target_name));
+ }
+
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+
+ return NULL;
+}
+
+void
+grn_proc_init_lock_release(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "target_name", -1);
+ grn_plugin_command_create(ctx,
+ "lock_release", -1,
+ command_lock_release,
+ 1,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_object.c b/storage/mroonga/vendor/groonga/lib/proc/proc_object.c
new file mode 100644
index 00000000..380e6553
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_object.c
@@ -0,0 +1,138 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_io.h"
+
+#include <groonga/plugin.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+static grn_obj *
+command_object_exist(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *db;
+ grn_obj *name;
+ grn_id id;
+
+ db = grn_ctx_db(ctx);
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ if (GRN_TEXT_LEN(name) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[object][exist] name is missing");
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+
+ id = grn_table_get(ctx, db,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ grn_ctx_output_bool(ctx, id != GRN_ID_NIL);
+ return NULL;
+}
+
+void
+grn_proc_init_object_exist(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_command_create(ctx,
+ "object_exist", -1,
+ command_object_exist,
+ 1,
+ vars);
+}
+
+static grn_obj *
+command_object_remove(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *db;
+ grn_obj *name;
+ grn_bool force;
+ grn_obj *target;
+ grn_bool failed_to_open;
+
+ db = grn_ctx_db(ctx);
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ force = grn_plugin_proc_get_var_bool(ctx, user_data, "force", -1, GRN_FALSE);
+
+ if (GRN_TEXT_LEN(name) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[object][remove] name is missing");
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+
+ target = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ if (target) {
+ grn_obj_remove(ctx, target);
+ if (!force || ctx->rc == GRN_SUCCESS) {
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+ return NULL;
+ }
+ grn_obj_close(ctx, target);
+ failed_to_open = GRN_TRUE;
+ } else {
+ failed_to_open = (ctx->rc != GRN_SUCCESS);
+ }
+
+ if (force) {
+ grn_obj_remove_force(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name));
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+ } else {
+ if (failed_to_open) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[object][remove] "
+ "failed to open the target object: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[object][remove] target object doesn't exist: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ }
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ }
+
+ return NULL;
+}
+
+void
+grn_proc_init_object_remove(grn_ctx *ctx)
+{
+ grn_expr_var vars[2];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "force", -1);
+ grn_plugin_command_create(ctx,
+ "object_remove", -1,
+ command_object_remove,
+ 2,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_object_inspect.c b/storage/mroonga/vendor/groonga/lib/proc/proc_object_inspect.c
new file mode 100644
index 00000000..eaa6ec4b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_object_inspect.c
@@ -0,0 +1,614 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_pat.h"
+#include "../grn_dat.h"
+#include "../grn_ii.h"
+
+#include "../grn_proc.h"
+
+#include <groonga/plugin.h>
+
+static void command_object_inspect_dispatch(grn_ctx *ctx, grn_obj *obj);
+
+static void
+command_object_inspect_obj_name(grn_ctx *ctx, grn_obj *obj)
+{
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ name_size = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_ctx_output_str(ctx, name, name_size);
+}
+
+static void
+command_object_inspect_obj_type(grn_ctx *ctx, uint8_t type)
+{
+ grn_ctx_output_map_open(ctx, "type", 2);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, type);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_cstr(ctx, grn_obj_type_to_string(type));
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_type(grn_ctx *ctx, grn_obj *type)
+{
+ if (!type) {
+ grn_ctx_output_null(ctx);
+ return;
+ }
+
+ grn_ctx_output_map_open(ctx, "type", 4);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, grn_obj_id(ctx, type));
+ grn_ctx_output_cstr(ctx, "name");
+ command_object_inspect_obj_name(ctx, type);
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_obj_type(ctx, type->header.type);
+ grn_ctx_output_cstr(ctx, "size");
+ if (type->header.type == GRN_TYPE) {
+ grn_ctx_output_uint64(ctx, grn_type_size(ctx, type));
+ } else {
+ grn_ctx_output_uint64(ctx, sizeof(grn_id));
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_disk_usage(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_ctx_output_uint64(ctx, grn_obj_get_disk_usage(ctx, obj));
+}
+
+static void
+command_object_inspect_table_hash_key_key(grn_ctx *ctx, grn_hash *hash)
+{
+ grn_ctx_output_map_open(ctx, "key", 3);
+ {
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_type(ctx, grn_ctx_at(ctx, hash->obj.header.domain));
+ grn_ctx_output_cstr(ctx, "total_size");
+ grn_ctx_output_uint64(ctx, grn_hash_total_key_size(ctx, hash));
+ grn_ctx_output_cstr(ctx, "max_total_size");
+ grn_ctx_output_uint64(ctx, grn_hash_max_total_key_size(ctx, hash));
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_table_pat_key_key(grn_ctx *ctx, grn_pat *pat)
+{
+ grn_ctx_output_map_open(ctx, "key", 3);
+ {
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_type(ctx, grn_ctx_at(ctx, pat->obj.header.domain));
+ grn_ctx_output_cstr(ctx, "total_size");
+ grn_ctx_output_uint64(ctx, grn_pat_total_key_size(ctx, pat));
+ grn_ctx_output_cstr(ctx, "max_total_size");
+ grn_ctx_output_uint64(ctx, GRN_PAT_MAX_TOTAL_KEY_SIZE);
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_table_dat_key_key(grn_ctx *ctx, grn_dat *dat)
+{
+ grn_ctx_output_map_open(ctx, "key", 1);
+ {
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_type(ctx, grn_ctx_at(ctx, dat->obj.header.domain));
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_table_key(grn_ctx *ctx, grn_obj *table)
+{
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ command_object_inspect_table_hash_key_key(ctx, (grn_hash *)table);
+ break;
+ case GRN_TABLE_PAT_KEY :
+ command_object_inspect_table_pat_key_key(ctx, (grn_pat *)table);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ command_object_inspect_table_dat_key_key(ctx, (grn_dat *)table);
+ break;
+ case GRN_TABLE_NO_KEY :
+ grn_ctx_output_null(ctx);
+ break;
+ default :
+ break;
+ }
+}
+
+static void
+command_object_inspect_table_value(grn_ctx *ctx, grn_obj *table)
+{
+ if (table->header.type == GRN_TABLE_DAT_KEY) {
+ grn_ctx_output_null(ctx);
+ } else {
+ grn_ctx_output_map_open(ctx, "value", 1);
+ {
+ grn_id range_id = grn_obj_get_range(ctx, table);
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_type(ctx, grn_ctx_at(ctx, range_id));
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+}
+
+static void
+command_object_inspect_table(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_ctx_output_map_open(ctx, "table", 7);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, grn_obj_id(ctx, obj));
+ grn_ctx_output_cstr(ctx, "name");
+ command_object_inspect_obj_name(ctx, obj);
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_obj_type(ctx, obj->header.type);
+ grn_ctx_output_cstr(ctx, "key");
+ command_object_inspect_table_key(ctx, obj);
+ grn_ctx_output_cstr(ctx, "value");
+ command_object_inspect_table_value(ctx, obj);
+ grn_ctx_output_cstr(ctx, "n_records");
+ grn_ctx_output_uint64(ctx, grn_table_size(ctx, obj));
+ grn_ctx_output_cstr(ctx, "disk_usage");
+ command_object_inspect_disk_usage(ctx, obj);
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_column_name(grn_ctx *ctx, grn_obj *column)
+{
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ name_size = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
+ name[name_size] = '\0';
+ grn_ctx_output_str(ctx, name, name_size);
+}
+
+static void
+command_object_inspect_column_type_name(grn_ctx *ctx, grn_obj *column)
+{
+ switch (column->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ switch (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_SCALAR :
+ grn_ctx_output_cstr(ctx, "scalar");
+ break;
+ case GRN_OBJ_COLUMN_VECTOR :
+ grn_ctx_output_cstr(ctx, "vector");
+ break;
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ grn_ctx_output_cstr(ctx, "index");
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+command_object_inspect_column_type(grn_ctx *ctx, grn_obj *column)
+{
+ grn_ctx_output_map_open(ctx, "type", 2);
+ {
+ grn_ctx_output_cstr(ctx, "name");
+ command_object_inspect_column_type_name(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "raw");
+ grn_ctx_output_map_open(ctx, "raw", 2);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, column->header.type);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_cstr(ctx, grn_obj_type_to_string(column->header.type));
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_column_index_value_statistics(grn_ctx *ctx,
+ grn_ii *ii)
+{
+ grn_ctx_output_map_open(ctx, "statistics", 11);
+ {
+ struct grn_ii_header *h = ii->header;
+
+ grn_ctx_output_cstr(ctx, "max_section_id");
+ grn_ctx_output_uint64(ctx, grn_ii_max_section(ii));
+
+ {
+ uint32_t max_id = 0;
+ uint32_t n_garbage_segments = 0;
+ uint32_t n_array_segments = 0;
+ uint32_t n_buffer_segments = 0;
+
+ grn_ctx_output_cstr(ctx, "n_garbage_segments");
+ {
+ uint32_t i;
+
+ for (i = h->bgqtail;
+ i != h->bgqhead;
+ i = ((i + 1) & (GRN_II_BGQSIZE - 1))) {
+ uint32_t id = h->bgqbody[i];
+ n_garbage_segments++;
+ if (id > max_id) { max_id = id; }
+ }
+ grn_ctx_output_uint64(ctx, n_garbage_segments);
+ }
+
+ grn_ctx_output_cstr(ctx, "max_array_segment_id");
+ grn_ctx_output_uint64(ctx, h->amax);
+ grn_ctx_output_cstr(ctx, "n_array_segments");
+ {
+ uint32_t i;
+
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ uint32_t id = h->ainfo[i];
+ if (id != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (id > max_id) { max_id = id; }
+ n_array_segments++;
+ }
+ }
+ grn_ctx_output_uint64(ctx, n_array_segments);
+ }
+
+ grn_ctx_output_cstr(ctx, "max_buffer_segment_id");
+ grn_ctx_output_uint64(ctx, h->bmax);
+ grn_ctx_output_cstr(ctx, "n_buffer_segments");
+ {
+ uint32_t i;
+
+ for (i = 0; i < GRN_II_MAX_LSEG; i++) {
+ uint32_t id = h->binfo[i];
+ if (id != GRN_II_PSEG_NOT_ASSIGNED) {
+ if (id > max_id) { max_id = id; }
+ n_buffer_segments++;
+ }
+ }
+ grn_ctx_output_uint64(ctx, n_buffer_segments);
+ }
+
+ grn_ctx_output_cstr(ctx, "max_in_use_physical_segment_id");
+ grn_ctx_output_uint64(ctx, max_id);
+
+ grn_ctx_output_cstr(ctx, "n_unmanaged_segments");
+ grn_ctx_output_uint64(ctx,
+ h->pnext -
+ n_array_segments -
+ n_buffer_segments -
+ n_garbage_segments);
+ }
+
+ {
+ grn_ctx_output_cstr(ctx, "total_chunk_size");
+ grn_ctx_output_uint64(ctx, h->total_chunk_size);
+ grn_ctx_output_cstr(ctx, "max_in_use_chunk_id");
+ {
+ uint32_t i;
+ uint32_t max_id;
+
+ for (max_id = 0, i = 0; i < (GRN_II_MAX_CHUNK >> 3); i++) {
+ uint8_t sub_chunk_info = h->chunks[i];
+ uint8_t bit;
+
+ if (sub_chunk_info == 0) {
+ continue;
+ }
+ for (bit = 0; bit < 8; bit++) {
+ if (sub_chunk_info & (1 << bit)) {
+ max_id = (i << 3) + sub_chunk_info;
+ }
+ }
+ }
+ grn_ctx_output_uint64(ctx, max_id);
+ }
+ grn_ctx_output_cstr(ctx, "n_garbage_chunks");
+ grn_ctx_output_array_open(ctx,
+ "n_garbage_chunks",
+ GRN_II_N_CHUNK_VARIATION);
+ {
+ uint32_t i;
+ for (i = 0; i <= GRN_II_N_CHUNK_VARIATION; i++) {
+ grn_ctx_output_uint64(ctx, h->ngarbages[i]);
+ }
+ }
+ grn_ctx_output_array_close(ctx);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_column_data_value_compress(grn_ctx *ctx, grn_obj *column)
+{
+ const char *compress = NULL;
+ grn_column_flags column_flags;
+
+ column_flags = grn_column_get_flags(ctx, column);
+ switch (column_flags & GRN_OBJ_COMPRESS_MASK) {
+ case GRN_OBJ_COMPRESS_ZLIB :
+ compress = "zlib";
+ break;
+ case GRN_OBJ_COMPRESS_LZ4 :
+ compress = "lz4";
+ break;
+ case GRN_OBJ_COMPRESS_ZSTD :
+ compress = "zstd";
+ break;
+ default :
+ break;
+ }
+
+ if (compress) {
+ grn_ctx_output_cstr(ctx, compress);
+ } else {
+ grn_ctx_output_null(ctx);
+ }
+}
+
+static void
+command_object_inspect_column_value(grn_ctx *ctx, grn_obj *column)
+{
+ int n_elements = 1;
+ grn_bool is_index = (column->header.type == GRN_COLUMN_INDEX);
+
+ if (is_index) {
+ n_elements += 5;
+ } else {
+ n_elements += 1;
+ }
+ grn_ctx_output_map_open(ctx, "value", n_elements);
+ {
+ grn_id range_id;
+ grn_column_flags column_flags;
+
+ range_id = grn_obj_get_range(ctx, column);
+ column_flags = grn_column_get_flags(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_type(ctx, grn_ctx_at(ctx, range_id));
+ if (is_index) {
+ grn_ctx_output_cstr(ctx, "section");
+ grn_ctx_output_bool(ctx, (column_flags & GRN_OBJ_WITH_SECTION) != 0);
+ grn_ctx_output_cstr(ctx, "weight");
+ grn_ctx_output_bool(ctx, (column_flags & GRN_OBJ_WITH_WEIGHT) != 0);
+ grn_ctx_output_cstr(ctx, "position");
+ grn_ctx_output_bool(ctx, (column_flags & GRN_OBJ_WITH_POSITION) != 0);
+ grn_ctx_output_cstr(ctx, "size");
+ if ((column_flags & GRN_OBJ_INDEX_SMALL) != 0) {
+ grn_ctx_output_cstr(ctx, "small");
+ } else if ((column_flags & GRN_OBJ_INDEX_MEDIUM) != 0) {
+ grn_ctx_output_cstr(ctx, "medium");
+ } else {
+ grn_ctx_output_cstr(ctx, "normal");
+ }
+ grn_ctx_output_cstr(ctx, "statistics");
+ command_object_inspect_column_index_value_statistics(ctx,
+ (grn_ii *)column);
+ } else {
+ grn_ctx_output_cstr(ctx, "compress");
+ command_object_inspect_column_data_value_compress(ctx, column);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_column_index_sources(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj *source_table;
+ grn_obj source_ids;
+ unsigned int i, n_ids;
+
+ source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
+
+ GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
+
+ n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+ grn_ctx_output_array_open(ctx, "sources", n_ids);
+ for (i = 0; i < n_ids; i++) {
+ grn_id source_id;
+ grn_obj *source;
+
+ source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
+ source = grn_ctx_at(ctx, source_id);
+
+ grn_ctx_output_map_open(ctx, "source", 4);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ if (grn_obj_is_table(ctx, source)) {
+ grn_ctx_output_null(ctx);
+ } else {
+ grn_ctx_output_uint64(ctx, source_id);
+ }
+
+ grn_ctx_output_cstr(ctx, "name");
+ if (grn_obj_is_table(ctx, source)) {
+ grn_ctx_output_cstr(ctx, "_key");
+ } else {
+ command_object_inspect_column_name(ctx, source);
+ }
+
+ grn_ctx_output_cstr(ctx, "table");
+ command_object_inspect_table(ctx, source_table);
+
+ grn_ctx_output_cstr(ctx, "full_name");
+ if (grn_obj_is_table(ctx, source)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+ name_size = grn_obj_name(ctx, source, name, GRN_TABLE_MAX_KEY_SIZE);
+ name[name_size] = '\0';
+ grn_strcat(name, GRN_TABLE_MAX_KEY_SIZE, "._key");
+ grn_ctx_output_cstr(ctx, name);
+ } else {
+ command_object_inspect_obj_name(ctx, source);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_array_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &source_ids);
+}
+
+static void
+command_object_inspect_column(grn_ctx *ctx, grn_obj *column)
+{
+ int n_elements = 7;
+ grn_bool is_index = (column->header.type == GRN_COLUMN_INDEX);
+
+ if (is_index) {
+ n_elements += 1;
+ }
+ grn_ctx_output_map_open(ctx, "column", n_elements);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, grn_obj_id(ctx, column));
+ grn_ctx_output_cstr(ctx, "name");
+ command_object_inspect_column_name(ctx, column);
+ grn_ctx_output_cstr(ctx, "table");
+ command_object_inspect_table(ctx, grn_ctx_at(ctx, column->header.domain));
+ grn_ctx_output_cstr(ctx, "full_name");
+ command_object_inspect_obj_name(ctx, column);
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_column_type(ctx, column);
+ grn_ctx_output_cstr(ctx, "value");
+ command_object_inspect_column_value(ctx, column);
+ if (is_index) {
+ grn_ctx_output_cstr(ctx, "sources");
+ command_object_inspect_column_index_sources(ctx, column);
+ }
+ grn_ctx_output_cstr(ctx, "disk_usage");
+ command_object_inspect_disk_usage(ctx, column);
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_db(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_db *db = (grn_db *)obj;
+
+ grn_ctx_output_map_open(ctx, "database", 3);
+ {
+ grn_ctx_output_cstr(ctx, "type");
+ command_object_inspect_obj_type(ctx, obj->header.type);
+ grn_ctx_output_cstr(ctx, "name_table");
+ command_object_inspect_dispatch(ctx, db->keys);
+ grn_ctx_output_cstr(ctx, "disk_usage");
+ command_object_inspect_disk_usage(ctx, obj);
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_object_inspect_dispatch(grn_ctx *ctx, grn_obj *obj)
+{
+ switch (obj->header.type) {
+ case GRN_TYPE :
+ command_object_inspect_type(ctx, obj);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ command_object_inspect_table(ctx, obj);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ command_object_inspect_column(ctx, obj);
+ break;
+ case GRN_DB :
+ command_object_inspect_db(ctx, obj);
+ break;
+ default :
+ {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[object][inspect] unsupported type: <%s>(%#x)",
+ grn_obj_type_to_string(obj->header.type),
+ obj->header.type);
+ grn_ctx_output_null(ctx);
+ break;
+ }
+ }
+}
+
+static grn_obj *
+command_object_inspect(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *name;
+ grn_obj *target;
+
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ if (GRN_TEXT_LEN(name) == 0) {
+ target = grn_ctx_db(ctx);
+ } else {
+ target = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ if (!target) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[object][inspect] nonexistent target: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ grn_ctx_output_null(ctx);
+ return NULL;
+ }
+ }
+
+ command_object_inspect_dispatch(ctx, target);
+
+ return NULL;
+}
+
+void
+grn_proc_init_object_inspect(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_command_create(ctx,
+ "object_inspect", -1,
+ command_object_inspect,
+ 1,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_object_list.c b/storage/mroonga/vendor/groonga/lib/proc/proc_object_list.c
new file mode 100644
index 00000000..adb4c91b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_object_list.c
@@ -0,0 +1,413 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_db.h"
+
+#include <groonga/plugin.h>
+
+static void
+command_object_list_dump_flags(grn_ctx *ctx, grn_obj_spec *spec)
+{
+ grn_obj flags;
+
+ GRN_TEXT_INIT(&flags, 0);
+
+ switch (spec->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ grn_dump_table_create_flags(ctx, spec->header.flags, &flags);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_INDEX :
+ grn_dump_column_create_flags(ctx, spec->header.flags, &flags);
+ break;
+ case GRN_TYPE :
+ if (spec->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ GRN_TEXT_PUTS(ctx, &flags, "KEY_VAR_SIZE");
+ } else {
+ switch (spec->header.flags & GRN_OBJ_KEY_MASK) {
+ case GRN_OBJ_KEY_UINT :
+ GRN_TEXT_PUTS(ctx, &flags, "KEY_UINT");
+ break;
+ case GRN_OBJ_KEY_INT :
+ GRN_TEXT_PUTS(ctx, &flags, "KEY_INT");
+ break;
+ case GRN_OBJ_KEY_FLOAT :
+ GRN_TEXT_PUTS(ctx, &flags, "KEY_FLOAT");
+ break;
+ case GRN_OBJ_KEY_GEO_POINT :
+ GRN_TEXT_PUTS(ctx, &flags, "KEY_GEO_POINT");
+ break;
+ }
+ }
+ break;
+ }
+ if (spec->header.flags & GRN_OBJ_CUSTOM_NAME) {
+ if (GRN_TEXT_LEN(&flags) > 0) {
+ GRN_TEXT_PUTS(ctx, &flags, "|");
+ }
+ GRN_TEXT_PUTS(ctx, &flags, "CUSTOM_NAME");
+ }
+
+ grn_ctx_output_str(ctx, GRN_TEXT_VALUE(&flags), GRN_TEXT_LEN(&flags));
+
+ GRN_OBJ_FIN(ctx, &flags);
+}
+
+static grn_obj *
+command_object_list(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_db *db;
+ uint32_t n_objects = 0;
+ grn_obj vector;
+
+ db = (grn_db *)grn_ctx_db(ctx);
+ if (!db->specs) {
+ grn_ctx_output_map_open(ctx, "objects", n_objects);
+ grn_ctx_output_map_close(ctx);
+ return NULL;
+ }
+
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, (grn_obj *)db, cursor, id,
+ GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING) {
+ grn_io_win jw;
+ uint32_t value_len;
+ char *value;
+
+ value = grn_ja_ref(ctx, db->specs, id, &jw, &value_len);
+ if (value) {
+ n_objects++;
+ grn_ja_unref(ctx, &jw);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+
+ GRN_OBJ_INIT(&vector, GRN_VECTOR, 0, GRN_DB_TEXT);
+
+ grn_ctx_output_map_open(ctx, "objects", n_objects);
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, (grn_obj *)db, cursor, id,
+ GRN_CURSOR_BY_ID | GRN_CURSOR_ASCENDING) {
+ void *name;
+ int name_size;
+ grn_io_win jw;
+ uint32_t value_len;
+ char *value;
+ unsigned int n_elements;
+
+ value = grn_ja_ref(ctx, db->specs, id, &jw, &value_len);
+ if (!value) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+
+ grn_ctx_output_str(ctx, name, name_size);
+
+ GRN_BULK_REWIND(&vector);
+ if (grn_vector_decode(ctx, &vector, value, value_len) != GRN_SUCCESS) {
+ grn_ctx_output_map_open(ctx, "object", 4);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_int64(ctx, id);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_str(ctx, name, name_size);
+ grn_ctx_output_cstr(ctx, "opened");
+ grn_ctx_output_bool(ctx, grn_ctx_is_opened(ctx, id));
+ grn_ctx_output_cstr(ctx, "value_size");
+ grn_ctx_output_uint64(ctx, value_len);
+ }
+ grn_ctx_output_map_close(ctx);
+ goto next;
+ }
+
+ n_elements = grn_vector_size(ctx, &vector);
+
+ {
+ uint32_t element_size;
+ grn_obj_spec *spec;
+ uint32_t n_properties = 8;
+ grn_bool need_sources = GRN_FALSE;
+ grn_bool need_token_filters = GRN_FALSE;
+
+ element_size = grn_vector_get_element(ctx,
+ &vector,
+ GRN_SERIALIZED_SPEC_INDEX_SPEC,
+ (const char **)&spec,
+ NULL,
+ NULL);
+ if (element_size == 0) {
+ grn_ctx_output_map_open(ctx, "object", 4);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_int64(ctx, id);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_str(ctx, name, name_size);
+ grn_ctx_output_cstr(ctx, "opened");
+ grn_ctx_output_bool(ctx, grn_ctx_is_opened(ctx, id));
+ grn_ctx_output_cstr(ctx, "n_elements");
+ grn_ctx_output_uint64(ctx, n_elements);
+ }
+ grn_ctx_output_map_close(ctx);
+ goto next;
+ }
+
+ switch (spec->header.type) {
+ case GRN_COLUMN_INDEX :
+ need_sources = GRN_TRUE;
+ n_properties++;
+ break;
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_NO_KEY :
+ need_token_filters = GRN_TRUE;
+ n_properties++;
+ break;
+ }
+ grn_ctx_output_map_open(ctx, "object", n_properties);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, id);
+
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_str(ctx, name, name_size);
+
+ grn_ctx_output_cstr(ctx, "opened");
+ grn_ctx_output_bool(ctx, grn_ctx_is_opened(ctx, id));
+
+ grn_ctx_output_cstr(ctx, "n_elements");
+ grn_ctx_output_uint64(ctx, n_elements);
+
+ grn_ctx_output_cstr(ctx, "type");
+ grn_ctx_output_map_open(ctx, "type", 2);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, spec->header.type);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_cstr(ctx, grn_obj_type_to_string(spec->header.type));
+ }
+ grn_ctx_output_map_close(ctx);
+
+ grn_ctx_output_cstr(ctx, "flags");
+ grn_ctx_output_map_open(ctx, "flags", 2);
+ {
+ grn_ctx_output_cstr(ctx, "value");
+ grn_ctx_output_uint64(ctx, spec->header.flags);
+ grn_ctx_output_cstr(ctx, "names");
+ command_object_list_dump_flags(ctx, spec);
+ }
+ grn_ctx_output_map_close(ctx);
+
+ grn_ctx_output_cstr(ctx, "path");
+ if (spec->header.flags & GRN_OBJ_CUSTOM_NAME) {
+ const char *path;
+ uint32_t path_size;
+ path_size = grn_vector_get_element(ctx,
+ &vector,
+ GRN_SERIALIZED_SPEC_INDEX_PATH,
+ &path,
+ NULL,
+ NULL);
+ grn_ctx_output_str(ctx, path, path_size);
+ } else {
+ switch (spec->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_INDEX :
+ {
+ char path[PATH_MAX];
+ grn_db_generate_pathname(ctx, (grn_obj *)db, id, path);
+ grn_ctx_output_cstr(ctx, path);
+ }
+ break;
+ default :
+ grn_ctx_output_null(ctx);
+ break;
+ }
+ }
+
+ switch (spec->header.type) {
+ case GRN_TYPE :
+ grn_ctx_output_cstr(ctx, "size");
+ grn_ctx_output_uint64(ctx, spec->range);
+ break;
+ case GRN_PROC :
+ grn_ctx_output_cstr(ctx, "plugin_id");
+ grn_ctx_output_uint64(ctx, spec->range);
+ break;
+ default :
+ grn_ctx_output_cstr(ctx, "range");
+ grn_ctx_output_map_open(ctx, "range", 2);
+ {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ name_size = grn_table_get_key(ctx,
+ (grn_obj *)db,
+ spec->range,
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, spec->range);
+
+ grn_ctx_output_cstr(ctx, "name");
+ if (name_size == 0) {
+ grn_ctx_output_null(ctx);
+ } else {
+ grn_ctx_output_str(ctx, name, name_size);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+ break;
+ }
+
+ if (need_sources) {
+ const grn_id *source_ids;
+ uint32_t n_source_ids;
+ uint32_t i;
+
+ if (n_elements > GRN_SERIALIZED_SPEC_INDEX_SOURCE) {
+ uint32_t element_size;
+
+ element_size = grn_vector_get_element(ctx,
+ &vector,
+ GRN_SERIALIZED_SPEC_INDEX_SOURCE,
+ (const char **)&source_ids,
+ NULL,
+ NULL);
+ n_source_ids = element_size / sizeof(grn_id);
+ } else {
+ source_ids = NULL;
+ n_source_ids = 0;
+ }
+
+ grn_ctx_output_cstr(ctx, "sources");
+ grn_ctx_output_array_open(ctx, "sources", n_source_ids);
+ for (i = 0; i < n_source_ids; i++) {
+ grn_id source_id;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ source_id = source_ids[i];
+ name_size = grn_table_get_key(ctx,
+ (grn_obj *)db,
+ source_id,
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+
+ grn_ctx_output_map_open(ctx, "source", 2);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, source_id);
+
+ grn_ctx_output_cstr(ctx, "name");
+ if (name_size == 0) {
+ grn_ctx_output_null(ctx);
+ } else {
+ grn_ctx_output_str(ctx, name, name_size);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_array_close(ctx);
+ }
+
+ if (need_token_filters) {
+ const grn_id *token_filter_ids;
+ uint32_t n_token_filter_ids;
+ uint32_t i;
+
+ if (n_elements > GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS) {
+ uint32_t element_size;
+
+ element_size = grn_vector_get_element(ctx,
+ &vector,
+ GRN_SERIALIZED_SPEC_INDEX_TOKEN_FILTERS,
+ (const char **)&token_filter_ids,
+ NULL,
+ NULL);
+ n_token_filter_ids = element_size / sizeof(grn_id);
+ } else {
+ token_filter_ids = NULL;
+ n_token_filter_ids = 0;
+ }
+
+ grn_ctx_output_cstr(ctx, "token_filters");
+ grn_ctx_output_array_open(ctx, "token_filters", n_token_filter_ids);
+ for (i = 0; i < n_token_filter_ids; i++) {
+ grn_id token_filter_id;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ token_filter_id = token_filter_ids[i];
+ name_size = grn_table_get_key(ctx,
+ (grn_obj *)db,
+ token_filter_id,
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+
+ grn_ctx_output_map_open(ctx, "token_filter", 2);
+ {
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_uint64(ctx, token_filter_id);
+
+ grn_ctx_output_cstr(ctx, "name");
+ if (name_size == 0) {
+ grn_ctx_output_null(ctx);
+ } else {
+ grn_ctx_output_str(ctx, name, name_size);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_array_close(ctx);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+
+ next :
+ grn_ja_unref(ctx, &jw);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &vector);
+
+ return NULL;
+}
+
+void
+grn_proc_init_object_list(grn_ctx *ctx)
+{
+ grn_plugin_command_create(ctx,
+ "object_list", -1,
+ command_object_list,
+ 0,
+ NULL);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_query.c b/storage/mroonga/vendor/groonga/lib/proc/proc_query.c
new file mode 100644
index 00000000..6dcf63e1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_query.c
@@ -0,0 +1,118 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include <groonga/plugin.h>
+
+static grn_obj *
+command_query_expand(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ const char *expander;
+ size_t expander_size;
+ const char *query;
+ size_t query_size;
+ const char *flags_raw;
+ size_t flags_raw_size;
+ grn_expr_flags flags = GRN_EXPR_SYNTAX_QUERY;
+ const char *term_column;
+ size_t term_column_size;
+ const char *expanded_term_column;
+ size_t expanded_term_column_size;
+ grn_obj expanded_query;
+
+ expander = grn_plugin_proc_get_var_string(ctx,
+ user_data,
+ "expander",
+ -1,
+ &expander_size);
+ query = grn_plugin_proc_get_var_string(ctx,
+ user_data,
+ "query",
+ -1,
+ &query_size);
+ flags_raw = grn_plugin_proc_get_var_string(ctx,
+ user_data,
+ "flags",
+ -1,
+ &flags_raw_size);
+ term_column = grn_plugin_proc_get_var_string(ctx,
+ user_data,
+ "term_column",
+ -1,
+ &term_column_size);
+ expanded_term_column =
+ grn_plugin_proc_get_var_string(ctx,
+ user_data,
+ "expanded_term_column",
+ -1,
+ &expanded_term_column_size);
+
+ if (flags_raw_size > 0) {
+ flags |= grn_proc_expr_query_flags_parse(ctx,
+ flags_raw,
+ flags_raw_size,
+ "[query][expand]");
+ } else {
+ flags |= GRN_EXPR_ALLOW_PRAGMA | GRN_EXPR_ALLOW_COLUMN;
+ }
+
+ if (ctx->rc != GRN_SUCCESS) {
+ return NULL;
+ }
+
+ GRN_TEXT_INIT(&expanded_query, 0);
+ grn_proc_syntax_expand_query(ctx,
+ query,
+ query_size,
+ flags,
+ expander,
+ expander_size,
+ term_column,
+ term_column_size,
+ expanded_term_column,
+ expanded_term_column_size,
+ &expanded_query,
+ "[query][expand]");
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_ctx_output_str(ctx,
+ GRN_TEXT_VALUE(&expanded_query),
+ GRN_TEXT_LEN(&expanded_query));
+ }
+ GRN_OBJ_FIN(ctx, &expanded_query);
+
+ return NULL;
+}
+
+void
+grn_proc_init_query_expand(grn_ctx *ctx)
+{
+ grn_expr_var vars[5];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "expander", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "query", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "flags", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "term_column", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "expanded_term_column", -1);
+ grn_plugin_command_create(ctx,
+ "query_expand", -1,
+ command_query_expand,
+ 5,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_query_log_flags.c b/storage/mroonga/vendor/groonga/lib/proc/proc_query_log_flags.c
new file mode 100644
index 00000000..b05d1abf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_query_log_flags.c
@@ -0,0 +1,220 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include <groonga/plugin.h>
+
+static grn_obj *
+command_query_log_flags_get(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ unsigned int current_flags;
+ grn_obj inspected_flags;
+
+ current_flags = grn_query_logger_get_flags(ctx);
+ GRN_TEXT_INIT(&inspected_flags, 0);
+
+ grn_inspect_query_log_flags(ctx, &inspected_flags,current_flags);
+ grn_ctx_output_str(ctx,
+ GRN_TEXT_VALUE(&inspected_flags),
+ GRN_TEXT_LEN(&inspected_flags));
+
+ GRN_OBJ_FIN(ctx, &inspected_flags);
+
+ return NULL;
+}
+
+void
+grn_proc_init_query_log_flags_get(grn_ctx *ctx)
+{
+ grn_plugin_command_create(ctx,
+ "query_log_flags_get", -1,
+ command_query_log_flags_get,
+ 0,
+ NULL);
+}
+
+typedef enum {
+ UPDATE_SET,
+ UPDATE_ADD,
+ UPDATE_REMOVE
+} grn_query_log_flags_update_mode;
+
+static void
+grn_query_log_flags_update(grn_ctx *ctx,
+ grn_obj *flags_text,
+ grn_query_log_flags_update_mode mode,
+ const char *error_message_tag)
+{
+ unsigned int previous_flags;
+ unsigned int flags = 0;
+
+ previous_flags = grn_query_logger_get_flags(ctx);
+ if (GRN_TEXT_LEN(flags_text) == 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s no query log flags",
+ error_message_tag);
+ grn_ctx_output_null(ctx);
+ return;
+ }
+
+ if (!grn_query_log_flags_parse(GRN_TEXT_VALUE(flags_text),
+ GRN_TEXT_LEN(flags_text),
+ &flags)) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s invalid query log flags: <%.*s>",
+ error_message_tag,
+ (int)GRN_TEXT_LEN(flags_text),
+ GRN_TEXT_VALUE(flags_text));
+ grn_ctx_output_null(ctx);
+ return;
+ }
+
+ switch (mode) {
+ case UPDATE_SET :
+ grn_query_logger_set_flags(ctx, flags);
+ break;
+ case UPDATE_ADD :
+ grn_query_logger_add_flags(ctx, flags);
+ break;
+ case UPDATE_REMOVE :
+ grn_query_logger_remove_flags(ctx, flags);
+ break;
+ }
+
+ {
+ unsigned int current_flags;
+ grn_obj inspected_flags;
+
+ current_flags = grn_query_logger_get_flags(ctx);
+ GRN_TEXT_INIT(&inspected_flags, 0);
+
+ grn_ctx_output_map_open(ctx, "query_log_flags", 2);
+
+ grn_inspect_query_log_flags(ctx, &inspected_flags, previous_flags);
+ grn_ctx_output_cstr(ctx, "previous");
+ grn_ctx_output_str(ctx,
+ GRN_TEXT_VALUE(&inspected_flags),
+ GRN_TEXT_LEN(&inspected_flags));
+
+ GRN_BULK_REWIND(&inspected_flags);
+ grn_inspect_query_log_flags(ctx, &inspected_flags, current_flags);
+ grn_ctx_output_cstr(ctx, "current");
+ grn_ctx_output_str(ctx,
+ GRN_TEXT_VALUE(&inspected_flags),
+ GRN_TEXT_LEN(&inspected_flags));
+
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &inspected_flags);
+ }
+
+ return;
+}
+
+static grn_obj *
+command_query_log_flags_set(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *flags_text;
+
+ flags_text = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ grn_query_log_flags_update(ctx,
+ flags_text,
+ UPDATE_SET,
+ "[query-log][flags][set]");
+ return NULL;
+}
+
+void
+grn_proc_init_query_log_flags_set(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "flags", -1);
+ grn_plugin_command_create(ctx,
+ "query_log_flags_set", -1,
+ command_query_log_flags_set,
+ 1,
+ vars);
+}
+
+static grn_obj *
+command_query_log_flags_add(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *flags_text;
+
+ flags_text = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ grn_query_log_flags_update(ctx,
+ flags_text,
+ UPDATE_ADD,
+ "[query-log][flags][add]");
+ return NULL;
+}
+
+void
+grn_proc_init_query_log_flags_add(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "flags", -1);
+ grn_plugin_command_create(ctx,
+ "query_log_flags_add", -1,
+ command_query_log_flags_add,
+ 1,
+ vars);
+}
+
+static grn_obj *
+command_query_log_flags_remove(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *flags_text;
+
+ flags_text = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ grn_query_log_flags_update(ctx,
+ flags_text,
+ UPDATE_REMOVE,
+ "[query-log][flags][remove]");
+ return NULL;
+}
+
+void
+grn_proc_init_query_log_flags_remove(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "flags", -1);
+ grn_plugin_command_create(ctx,
+ "query_log_flags_remove", -1,
+ command_query_log_flags_remove,
+ 1,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_schema.c b/storage/mroonga/vendor/groonga/lib/proc/proc_schema.c
new file mode 100644
index 00000000..061c145a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_schema.c
@@ -0,0 +1,1226 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include "../grn_db.h"
+
+#include <groonga/plugin.h>
+
+typedef struct {
+ grn_bool is_close_opened_object_mode;
+} grn_schema_data;
+
+static void
+command_schema_output_id(grn_ctx *ctx, grn_obj *obj)
+{
+ if (obj) {
+ grn_id id;
+ id = grn_obj_id(ctx, obj);
+ grn_ctx_output_uint64(ctx, id);
+ } else {
+ grn_ctx_output_null(ctx);
+ }
+}
+
+static void
+command_schema_output_name(grn_ctx *ctx, grn_obj *obj)
+{
+ if (obj) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+ name_size = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_ctx_output_str(ctx, name, name_size);
+ } else {
+ grn_ctx_output_null(ctx);
+ }
+}
+
+static void
+command_schema_output_column_name(grn_ctx *ctx, grn_obj *column)
+{
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+ name_size = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
+ grn_ctx_output_str(ctx, name, name_size);
+}
+
+static void
+command_schema_output_type(grn_ctx *ctx, const char *type_label, grn_obj *type)
+{
+ if (!type) {
+ grn_ctx_output_null(ctx);
+ return;
+ }
+
+ grn_ctx_output_map_open(ctx, type_label, 3);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, type);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, type);
+
+ grn_ctx_output_cstr(ctx, "type");
+ if (grn_obj_is_table(ctx, type)) {
+ grn_ctx_output_cstr(ctx, "reference");
+ } else {
+ grn_ctx_output_cstr(ctx, "type");
+ }
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_output_key_type(grn_ctx *ctx, grn_obj *key_type)
+{
+ command_schema_output_type(ctx, "key_type", key_type);
+}
+
+static void
+command_schema_output_value_type(grn_ctx *ctx, grn_obj *value_type)
+{
+ command_schema_output_type(ctx, "value_type", value_type);
+}
+
+static void
+command_schema_output_command(grn_ctx *ctx,
+ const char *command_name,
+ grn_obj *arguments)
+{
+ grn_ctx_output_map_open(ctx, "command", 3);
+
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_cstr(ctx, command_name);
+
+ grn_ctx_output_cstr(ctx, "arguments");
+ {
+ int i, n;
+
+ n = grn_vector_size(ctx, arguments);
+ grn_ctx_output_map_open(ctx, "arguments", n / 2);
+ for (i = 0; i < n; i += 2) {
+ const char *name;
+ unsigned int name_size;
+ const char *value;
+ unsigned int value_size;
+
+ name_size = grn_vector_get_element(ctx, arguments, i, &name,
+ NULL, NULL);
+ value_size = grn_vector_get_element(ctx, arguments, i + 1, &value,
+ NULL, NULL);
+ grn_ctx_output_str(ctx, name, name_size);
+ grn_ctx_output_str(ctx, value, value_size);
+ }
+ grn_ctx_output_map_close(ctx);
+ }
+
+ grn_ctx_output_cstr(ctx, "command_line");
+ {
+ int i, n;
+ grn_obj command_line;
+
+ GRN_TEXT_INIT(&command_line, 0);
+ GRN_TEXT_PUTS(ctx, &command_line, command_name);
+ n = grn_vector_size(ctx, arguments);
+ for (i = 0; i < n; i += 2) {
+ const char *name;
+ unsigned int name_size;
+ const char *value;
+ unsigned int value_size;
+
+ name_size = grn_vector_get_element(ctx, arguments, i, &name,
+ NULL, NULL);
+ value_size = grn_vector_get_element(ctx, arguments, i + 1, &value,
+ NULL, NULL);
+ grn_text_printf(ctx, &command_line,
+ " --%.*s %.*s",
+ name_size, name,
+ value_size, value);
+ }
+ grn_ctx_output_str(ctx,
+ GRN_TEXT_VALUE(&command_line),
+ GRN_TEXT_LEN(&command_line));
+ GRN_OBJ_FIN(ctx, &command_line);
+ }
+
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_output_plugins(grn_ctx *ctx)
+{
+ grn_obj plugin_names;
+ unsigned int i, n;
+
+ GRN_TEXT_INIT(&plugin_names, GRN_OBJ_VECTOR);
+
+ grn_plugin_get_names(ctx, &plugin_names);
+
+ grn_ctx_output_cstr(ctx, "plugins");
+
+ n = grn_vector_size(ctx, &plugin_names);
+ grn_ctx_output_map_open(ctx, "plugins", n);
+ for (i = 0; i < n; i++) {
+ const char *name;
+ unsigned int name_size;
+
+ name_size = grn_vector_get_element(ctx, &plugin_names, i, &name, NULL, NULL);
+ grn_ctx_output_str(ctx, name, name_size);
+
+ grn_ctx_output_map_open(ctx, "plugin", 1);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_str(ctx, name, name_size);
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &plugin_names);
+}
+
+static void
+command_schema_output_types(grn_ctx *ctx)
+{
+ unsigned int n_types;
+
+ n_types = 0;
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ if (grn_id_is_builtin_type(ctx, id)) {
+ n_types++;
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+
+ grn_ctx_output_cstr(ctx, "types");
+
+ grn_ctx_output_map_open(ctx, "types", n_types);
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ grn_obj *type;
+
+ if (!grn_id_is_builtin_type(ctx, id)) {
+ continue;
+ }
+
+ type = grn_ctx_at(ctx, id);
+
+ command_schema_output_name(ctx, type);
+
+ grn_ctx_output_map_open(ctx, "type", 5);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, type);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, type);
+
+ grn_ctx_output_cstr(ctx, "size");
+ grn_ctx_output_int64(ctx, grn_type_size(ctx, type));
+
+ grn_ctx_output_cstr(ctx, "can_be_key_type");
+ grn_ctx_output_bool(ctx, grn_type_size(ctx, type) <= GRN_TABLE_MAX_KEY_SIZE);
+
+ grn_ctx_output_cstr(ctx, "can_be_value_type");
+ grn_ctx_output_bool(ctx, !(type->header.flags & GRN_OBJ_KEY_VAR_SIZE));
+
+ grn_ctx_output_map_close(ctx);
+ } GRN_DB_EACH_END(ctx, cursor);
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_output_tokenizers(grn_ctx *ctx, grn_schema_data *data)
+{
+ grn_obj tokenizer_ids;
+ unsigned int i, n;
+
+ GRN_RECORD_INIT(&tokenizer_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (object) {
+ if (grn_obj_is_tokenizer_proc(ctx, object)) {
+ GRN_RECORD_PUT(ctx, &tokenizer_ids, id);
+ }
+ } else {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+
+ grn_ctx_output_cstr(ctx, "tokenizers");
+
+ n = GRN_BULK_VSIZE(&tokenizer_ids) / sizeof(grn_id);
+ grn_ctx_output_map_open(ctx, "tokenizers", n);
+ for (i = 0; i < n; i++) {
+ grn_id tokenizer_id;
+ grn_obj *tokenizer;
+
+ tokenizer_id = GRN_RECORD_VALUE_AT(&tokenizer_ids, i);
+ tokenizer = grn_ctx_at(ctx, tokenizer_id);
+
+ command_schema_output_name(ctx, tokenizer);
+
+ grn_ctx_output_map_open(ctx, "tokenizer", 2);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, tokenizer);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, tokenizer);
+
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &tokenizer_ids);
+}
+
+static void
+command_schema_output_normalizers(grn_ctx *ctx, grn_schema_data *data)
+{
+ grn_obj normalizer_ids;
+ unsigned int i, n;
+
+ GRN_RECORD_INIT(&normalizer_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (object) {
+ if (grn_obj_is_normalizer_proc(ctx, object)) {
+ GRN_RECORD_PUT(ctx, &normalizer_ids, id);
+ }
+ } else {
+ /* XXX: this clause is executed when MeCab normalizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+
+ grn_ctx_output_cstr(ctx, "normalizers");
+
+ n = GRN_BULK_VSIZE(&normalizer_ids) / sizeof(grn_id);
+ grn_ctx_output_map_open(ctx, "normalizers", n);
+ for (i = 0; i < n; i++) {
+ grn_id normalizer_id;
+ grn_obj *normalizer;
+
+ normalizer_id = GRN_RECORD_VALUE_AT(&normalizer_ids, i);
+ normalizer = grn_ctx_at(ctx, normalizer_id);
+
+ command_schema_output_name(ctx, normalizer);
+
+ grn_ctx_output_map_open(ctx, "normalizer", 2);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, normalizer);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, normalizer);
+
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &normalizer_ids);
+}
+
+static void
+command_schema_output_token_filters(grn_ctx *ctx, grn_schema_data *data)
+{
+ grn_obj token_filter_ids;
+ unsigned int i, n;
+
+ GRN_RECORD_INIT(&token_filter_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (object) {
+ if (grn_obj_is_token_filter_proc(ctx, object)) {
+ GRN_RECORD_PUT(ctx, &token_filter_ids, id);
+ }
+ } else {
+ /* XXX: this clause is executed when MeCab normalizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_DB_EACH_END(ctx, cursor);
+
+ grn_ctx_output_cstr(ctx, "token_filters");
+
+ n = GRN_BULK_VSIZE(&token_filter_ids) / sizeof(grn_id);
+ grn_ctx_output_map_open(ctx, "token_filters", n);
+ for (i = 0; i < n; i++) {
+ grn_id token_filter_id;
+ grn_obj *token_filter;
+
+ token_filter_id = GRN_RECORD_VALUE_AT(&token_filter_ids, i);
+ token_filter = grn_ctx_at(ctx, token_filter_id);
+
+ command_schema_output_name(ctx, token_filter);
+
+ grn_ctx_output_map_open(ctx, "token_filter", 2);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, token_filter);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, token_filter);
+
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &token_filter_ids);
+}
+
+static const char *
+command_schema_table_type_name(grn_ctx *ctx, grn_obj *table)
+{
+ const char *name = "unknown";
+
+ switch (table->header.type) {
+ case GRN_TABLE_NO_KEY :
+ name = "array";
+ break;
+ case GRN_TABLE_HASH_KEY :
+ name = "hash table";
+ break;
+ case GRN_TABLE_PAT_KEY :
+ name = "patricia trie";
+ break;
+ case GRN_TABLE_DAT_KEY :
+ name = "double array trie";
+ break;
+ default :
+ break;
+ }
+
+ return name;
+}
+
+static void
+command_schema_table_output_key_type(grn_ctx *ctx, grn_obj *table)
+{
+ grn_obj *key_type = NULL;
+
+ if (table->header.type != GRN_TABLE_NO_KEY &&
+ table->header.domain != GRN_ID_NIL) {
+ key_type = grn_ctx_at(ctx, table->header.domain);
+ }
+
+ command_schema_output_key_type(ctx, key_type);
+}
+
+static void
+command_schema_table_output_value_type(grn_ctx *ctx, grn_obj *table)
+{
+ grn_obj *value_type = NULL;
+ grn_id range = GRN_ID_NIL;
+
+ if (table->header.type != GRN_TABLE_DAT_KEY) {
+ range = grn_obj_get_range(ctx, table);
+ }
+ if (range != GRN_ID_NIL) {
+ value_type = grn_ctx_at(ctx, range);
+ }
+
+ command_schema_output_value_type(ctx, value_type);
+}
+
+static void
+command_schema_table_output_tokenizer(grn_ctx *ctx, grn_obj *table)
+{
+ grn_obj *tokenizer;
+
+ tokenizer = grn_obj_get_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, NULL);
+ if (!tokenizer) {
+ grn_ctx_output_null(ctx);
+ return;
+ }
+
+ grn_ctx_output_map_open(ctx, "tokenizer", 2);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, tokenizer);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, tokenizer);
+
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_table_output_normalizer(grn_ctx *ctx, grn_obj *table)
+{
+ grn_obj *normalizer;
+
+ normalizer = grn_obj_get_info(ctx, table, GRN_INFO_NORMALIZER, NULL);
+ if (!normalizer) {
+ grn_ctx_output_null(ctx);
+ return;
+ }
+
+ grn_ctx_output_map_open(ctx, "normalizer", 2);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, normalizer);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, normalizer);
+
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_table_output_token_filters(grn_ctx *ctx, grn_obj *table)
+{
+ grn_obj token_filters;
+ int i, n;
+
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_DB_OBJECT);
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
+ }
+
+ n = GRN_BULK_VSIZE(&token_filters) / sizeof(grn_obj *);
+ grn_ctx_output_array_open(ctx, "token_filters", n);
+ for (i = 0; i < n; i++) {
+ grn_obj *token_filter;
+
+ token_filter = GRN_PTR_VALUE_AT(&token_filters, i);
+
+ grn_ctx_output_map_open(ctx, "token_filter", 2);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, token_filter);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, token_filter);
+
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_array_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &token_filters);
+}
+
+static void
+command_schema_table_command_collect_arguments(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *arguments)
+{
+#define ADD(name_, value_) \
+ grn_vector_add_element(ctx, arguments, \
+ name_, strlen(name_), \
+ 0, GRN_DB_TEXT); \
+ grn_vector_add_element(ctx, arguments, \
+ value_, strlen(value_), \
+ 0, GRN_DB_TEXT)
+
+#define ADD_OBJECT_NAME(name_, object_) do { \
+ char object_name[GRN_TABLE_MAX_KEY_SIZE]; \
+ unsigned int object_name_size; \
+ object_name_size = grn_obj_name(ctx, object_, \
+ object_name, \
+ GRN_TABLE_MAX_KEY_SIZE); \
+ object_name[object_name_size] = '\0'; \
+ ADD(name_, object_name); \
+ } while (GRN_FALSE)
+
+ ADD_OBJECT_NAME("name", table);
+
+ {
+ grn_obj flags;
+ grn_table_flags table_flags;
+ grn_table_flags ignored_flags = GRN_OBJ_KEY_NORMALIZE | GRN_OBJ_PERSISTENT;
+ GRN_TEXT_INIT(&flags, 0);
+ grn_table_get_info(ctx, table, &table_flags, NULL, NULL, NULL, NULL);
+ grn_dump_table_create_flags(ctx,
+ table_flags & ~ignored_flags,
+ &flags);
+ GRN_TEXT_PUTC(ctx, &flags, '\0');
+ ADD("flags", GRN_TEXT_VALUE(&flags));
+ GRN_OBJ_FIN(ctx, &flags);
+ }
+
+ {
+ grn_obj *key_type = NULL;
+
+ if (table->header.type != GRN_TABLE_NO_KEY &&
+ table->header.domain != GRN_ID_NIL) {
+ key_type = grn_ctx_at(ctx, table->header.domain);
+ }
+ if (key_type) {
+ ADD_OBJECT_NAME("key_type", key_type);
+ }
+ }
+
+ {
+ grn_obj *value_type = NULL;
+ grn_id range = GRN_ID_NIL;
+
+ if (table->header.type != GRN_TABLE_DAT_KEY) {
+ range = grn_obj_get_range(ctx, table);
+ }
+ if (range != GRN_ID_NIL) {
+ value_type = grn_ctx_at(ctx, range);
+ }
+ if (value_type) {
+ ADD_OBJECT_NAME("value_type", value_type);
+ }
+ }
+
+ {
+ grn_obj *tokenizer;
+ tokenizer = grn_obj_get_info(ctx, table, GRN_INFO_DEFAULT_TOKENIZER, NULL);
+ if (tokenizer) {
+ ADD_OBJECT_NAME("default_tokenizer", tokenizer);
+ }
+ }
+
+ {
+ grn_obj *normalizer;
+ normalizer = grn_obj_get_info(ctx, table, GRN_INFO_NORMALIZER, NULL);
+ if (!normalizer && (table->header.flags & GRN_OBJ_KEY_NORMALIZE)) {
+ normalizer = grn_ctx_get(ctx, "NormalizerAuto", -1);
+ }
+ if (normalizer) {
+ ADD_OBJECT_NAME("normalizer", normalizer);
+ }
+ }
+
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ grn_obj token_filters;
+ int n;
+
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, GRN_DB_OBJECT);
+ grn_obj_get_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
+ n = GRN_BULK_VSIZE(&token_filters) / sizeof(grn_obj *);
+ if (n > 0) {
+ grn_obj token_filter_names;
+ int i;
+
+ GRN_TEXT_INIT(&token_filter_names, 0);
+ for (i = 0; i < n; i++) {
+ grn_obj *token_filter;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ token_filter = GRN_PTR_VALUE_AT(&token_filters, i);
+ name_size = grn_obj_name(ctx, token_filter,
+ name, GRN_TABLE_MAX_KEY_SIZE);
+ if (i > 0) {
+ GRN_TEXT_PUTC(ctx, &token_filter_names, ',');
+ }
+ GRN_TEXT_PUT(ctx, &token_filter_names, name, name_size);
+ }
+ GRN_TEXT_PUTC(ctx, &token_filter_names, '\0');
+ ADD("token_filters", GRN_TEXT_VALUE(&token_filter_names));
+ GRN_OBJ_FIN(ctx, &token_filter_names);
+ }
+ GRN_OBJ_FIN(ctx, &token_filters);
+ }
+
+#undef ADD_OBJECT_NAME
+#undef ADD
+}
+
+static void
+command_schema_table_output_command(grn_ctx *ctx, grn_obj *table)
+{
+ grn_obj arguments;
+
+ GRN_TEXT_INIT(&arguments, GRN_OBJ_VECTOR);
+ command_schema_table_command_collect_arguments(ctx, table, &arguments);
+
+ command_schema_output_command(ctx, "table_create", &arguments);
+
+ GRN_OBJ_FIN(ctx, &arguments);
+}
+
+static void
+command_schema_column_output_type(grn_ctx *ctx, grn_obj *column)
+{
+ switch (column->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ switch (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_SCALAR :
+ grn_ctx_output_cstr(ctx, "scalar");
+ break;
+ case GRN_OBJ_COLUMN_VECTOR :
+ grn_ctx_output_cstr(ctx, "vector");
+ break;
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ grn_ctx_output_cstr(ctx, "index");
+ break;
+ }
+}
+
+static void
+command_schema_column_output_value_type(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj *value_type;
+ value_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
+ command_schema_output_value_type(ctx, value_type);
+}
+
+static void
+command_schema_column_output_compress(grn_ctx *ctx, grn_obj *column)
+{
+ const char *compress = NULL;
+
+ if (column->header.type != GRN_COLUMN_INDEX) {
+ switch (column->header.flags & GRN_OBJ_COMPRESS_MASK) {
+ case GRN_OBJ_COMPRESS_ZLIB :
+ compress = "zlib";
+ break;
+ case GRN_OBJ_COMPRESS_LZ4 :
+ compress = "lz4";
+ break;
+ case GRN_OBJ_COMPRESS_ZSTD :
+ compress = "zstd";
+ break;
+ default :
+ break;
+ }
+ }
+
+ if (compress) {
+ grn_ctx_output_cstr(ctx, compress);
+ } else {
+ grn_ctx_output_null(ctx);
+ }
+}
+
+static void
+command_schema_column_output_sources(grn_ctx *ctx, grn_obj *column)
+{
+ grn_obj *source_table;
+ grn_obj source_ids;
+ unsigned int i, n_ids;
+
+ source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
+
+ GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+
+ if (column->header.type == GRN_COLUMN_INDEX) {
+ grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
+ }
+
+ n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+ grn_ctx_output_array_open(ctx, "sources", n_ids);
+ for (i = 0; i < n_ids; i++) {
+ grn_id source_id;
+ grn_obj *source;
+
+ source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
+ source = grn_ctx_at(ctx, source_id);
+
+ grn_ctx_output_map_open(ctx, "source", 4);
+
+ grn_ctx_output_cstr(ctx, "id");
+ if (grn_obj_is_table(ctx, source)) {
+ command_schema_output_id(ctx, NULL);
+ } else {
+ command_schema_output_id(ctx, source);
+ }
+
+ grn_ctx_output_cstr(ctx, "name");
+ if (grn_obj_is_table(ctx, source)) {
+ grn_ctx_output_cstr(ctx, "_key");
+ } else {
+ command_schema_output_column_name(ctx, source);
+ }
+
+ grn_ctx_output_cstr(ctx, "table");
+ command_schema_output_name(ctx, source_table);
+
+ grn_ctx_output_cstr(ctx, "full_name");
+ if (grn_obj_is_table(ctx, source)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+ name_size = grn_obj_name(ctx, source, name, GRN_TABLE_MAX_KEY_SIZE);
+ name[name_size] = '\0';
+ grn_strcat(name, GRN_TABLE_MAX_KEY_SIZE, "._key");
+ grn_ctx_output_cstr(ctx, name);
+ } else {
+ command_schema_output_name(ctx, source);
+ }
+
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_array_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &source_ids);
+}
+
+static void
+command_schema_output_indexes(grn_ctx *ctx, grn_obj *object)
+{
+ uint32_t i;
+ grn_index_datum *index_data = NULL;
+ uint32_t n_index_data = 0;
+
+ n_index_data = grn_column_get_all_index_data(ctx, object, NULL, 0);
+ if (n_index_data > 0) {
+ index_data = GRN_PLUGIN_MALLOC(ctx,
+ sizeof(grn_index_datum) * n_index_data);
+ if (!index_data) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[schema] failed to allocate memory for indexes");
+ return;
+ }
+ grn_column_get_all_index_data(ctx, object, index_data, n_index_data);
+ }
+
+ grn_ctx_output_array_open(ctx, "indexes", n_index_data);
+ for (i = 0; i < n_index_data; i++) {
+ grn_obj *lexicon;
+
+ grn_ctx_output_map_open(ctx, "index", 5);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, index_data[i].index);
+
+ grn_ctx_output_cstr(ctx, "full_name");
+ command_schema_output_name(ctx, index_data[i].index);
+
+ grn_ctx_output_cstr(ctx, "table");
+ lexicon = grn_ctx_at(ctx, index_data[i].index->header.domain);
+ command_schema_output_name(ctx, lexicon);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_column_name(ctx, index_data[i].index);
+
+ grn_ctx_output_cstr(ctx, "section");
+ grn_ctx_output_uint64(ctx, index_data[i].section);
+
+ grn_ctx_output_map_close(ctx);
+ }
+ grn_ctx_output_array_close(ctx);
+
+ if (index_data) {
+ GRN_PLUGIN_FREE(ctx, index_data);
+ }
+}
+
+static void
+command_schema_column_command_collect_arguments(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *column,
+ grn_obj *arguments)
+{
+#define ADD(name_, value_) \
+ grn_vector_add_element(ctx, arguments, \
+ name_, strlen(name_), \
+ 0, GRN_DB_TEXT); \
+ grn_vector_add_element(ctx, arguments, \
+ value_, strlen(value_), \
+ 0, GRN_DB_TEXT)
+
+#define ADD_OBJECT_NAME(name_, object_) do { \
+ char object_name[GRN_TABLE_MAX_KEY_SIZE]; \
+ unsigned int object_name_size; \
+ object_name_size = grn_obj_name(ctx, object_, \
+ object_name, \
+ GRN_TABLE_MAX_KEY_SIZE); \
+ object_name[object_name_size] = '\0'; \
+ ADD(name_, object_name); \
+ } while (GRN_FALSE)
+
+ ADD_OBJECT_NAME("table", table);
+ {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int column_name_size;
+ column_name_size = grn_column_name(ctx, column,
+ column_name, GRN_TABLE_MAX_KEY_SIZE);
+ column_name[column_name_size] = '\0';
+ ADD("name", column_name);
+ }
+
+ {
+ grn_obj flags;
+ grn_column_flags column_flags;
+
+ GRN_TEXT_INIT(&flags, 0);
+ column_flags = grn_column_get_flags(ctx, column);
+ grn_dump_column_create_flags(ctx,
+ column_flags & ~GRN_OBJ_PERSISTENT,
+ &flags);
+ GRN_TEXT_PUTC(ctx, &flags, '\0');
+ ADD("flags", GRN_TEXT_VALUE(&flags));
+ GRN_OBJ_FIN(ctx, &flags);
+ }
+
+ {
+ grn_obj *value_type;
+
+ value_type = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
+ ADD_OBJECT_NAME("type", value_type);
+ }
+
+ if (column->header.type == GRN_COLUMN_INDEX) {
+ grn_obj source_ids;
+ unsigned int n_ids;
+
+ GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
+
+ n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
+ if (n_ids > 0) {
+ grn_obj sources;
+ unsigned int i;
+
+ GRN_TEXT_INIT(&sources, 0);
+ for (i = 0; i < n_ids; i++) {
+ grn_id source_id;
+ grn_obj *source;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int name_size;
+
+ source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
+ source = grn_ctx_at(ctx, source_id);
+
+ if (grn_obj_is_table(ctx, source)) {
+ grn_strcpy(name, GRN_TABLE_MAX_KEY_SIZE, "_key");
+ name_size = strlen(name);
+ } else {
+ name_size = grn_column_name(ctx, source, name, GRN_TABLE_MAX_KEY_SIZE);
+ }
+ if (i > 0) {
+ GRN_TEXT_PUTC(ctx, &sources, ',');
+ }
+ GRN_TEXT_PUT(ctx, &sources, name, name_size);
+ }
+ GRN_TEXT_PUTC(ctx, &sources, '\0');
+ ADD("source", GRN_TEXT_VALUE(&sources));
+ GRN_OBJ_FIN(ctx, &sources);
+ }
+ GRN_OBJ_FIN(ctx, &source_ids);
+ }
+
+#undef ADD_OBJECT_NAME
+#undef ADD
+}
+
+static void
+command_schema_column_output_command(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *column)
+{
+ grn_obj arguments;
+
+ GRN_TEXT_INIT(&arguments, GRN_OBJ_VECTOR);
+ command_schema_column_command_collect_arguments(ctx, table, column, &arguments);
+
+ command_schema_output_command(ctx, "column_create", &arguments);
+
+ GRN_OBJ_FIN(ctx, &arguments);
+}
+
+static void
+command_schema_column_output(grn_ctx *ctx, grn_obj *table, grn_obj *column)
+{
+ if (!column) {
+ return;
+ }
+
+ command_schema_output_column_name(ctx, column);
+
+ grn_ctx_output_map_open(ctx, "column", 13);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_column_name(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "table");
+ command_schema_output_name(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "full_name");
+ command_schema_output_name(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "type");
+ command_schema_column_output_type(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "value_type");
+ command_schema_column_output_value_type(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "compress");
+ command_schema_column_output_compress(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "section");
+ grn_ctx_output_bool(ctx, (column->header.flags & GRN_OBJ_WITH_SECTION) != 0);
+
+ grn_ctx_output_cstr(ctx, "weight");
+ grn_ctx_output_bool(ctx, (column->header.flags & GRN_OBJ_WITH_WEIGHT) != 0);
+
+ grn_ctx_output_cstr(ctx, "position");
+ grn_ctx_output_bool(ctx, (column->header.flags & GRN_OBJ_WITH_POSITION) != 0);
+
+ grn_ctx_output_cstr(ctx, "sources");
+ command_schema_column_output_sources(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "indexes");
+ command_schema_output_indexes(ctx, column);
+
+ grn_ctx_output_cstr(ctx, "command");
+ command_schema_column_output_command(ctx, table, column);
+
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_table_output_columns(grn_ctx *ctx,
+ grn_obj *table,
+ grn_schema_data *data)
+{
+ grn_hash *columns;
+
+ columns = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
+ if (!columns) {
+ grn_ctx_output_map_open(ctx, "columns", 0);
+ grn_ctx_output_map_close(ctx);
+ return;
+ }
+
+ grn_table_columns(ctx, table, "", 0, (grn_obj *)columns);
+ grn_ctx_output_map_open(ctx, "columns", grn_hash_size(ctx, columns));
+ {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, columns, id, &key, NULL, NULL, {
+ grn_obj *column;
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ column = grn_ctx_at(ctx, *key);
+ command_schema_column_output(ctx, table, column);
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ });
+ }
+ grn_ctx_output_map_close(ctx);
+ grn_hash_close(ctx, columns);
+}
+
+static void
+command_schema_output_table(grn_ctx *ctx,
+ grn_schema_data *data,
+ grn_obj *table)
+{
+ command_schema_output_name(ctx, table);
+
+ grn_ctx_output_map_open(ctx, "table", 11);
+
+ grn_ctx_output_cstr(ctx, "id");
+ command_schema_output_id(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "name");
+ command_schema_output_name(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "type");
+ grn_ctx_output_cstr(ctx, command_schema_table_type_name(ctx, table));
+
+ grn_ctx_output_cstr(ctx, "key_type");
+ command_schema_table_output_key_type(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "value_type");
+ command_schema_table_output_value_type(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "tokenizer");
+ command_schema_table_output_tokenizer(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "normalizer");
+ command_schema_table_output_normalizer(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "token_filters");
+ command_schema_table_output_token_filters(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "indexes");
+ command_schema_output_indexes(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "command");
+ command_schema_table_output_command(ctx, table);
+
+ grn_ctx_output_cstr(ctx, "columns");
+ command_schema_table_output_columns(ctx, table, data);
+
+ grn_ctx_output_map_close(ctx);
+}
+
+static void
+command_schema_output_tables(grn_ctx *ctx, grn_schema_data *data)
+{
+ grn_obj table_ids;
+ unsigned int i, n;
+
+ GRN_RECORD_INIT(&table_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ GRN_DB_EACH_BEGIN_BY_KEY(ctx, cursor, id) {
+ void *name;
+ int name_size;
+ grn_obj *object;
+
+ if (grn_id_is_builtin(ctx, id)) {
+ continue;
+ }
+
+ name_size = grn_table_cursor_get_key(ctx, cursor, &name);
+ if (grn_obj_name_is_column(ctx, name, name_size)) {
+ continue;
+ }
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (!object) {
+ /* XXX: this clause is executed when MeCab tokenizer is enabled in
+ database but the groonga isn't supported MeCab.
+ We should return error mesage about it and error exit status
+ but it's too difficult for this architecture. :< */
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ goto next_loop;
+ }
+
+ if (grn_obj_is_table(ctx, object)) {
+ GRN_RECORD_PUT(ctx, &table_ids, id);
+ }
+
+ next_loop :
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+
+ n = GRN_BULK_VSIZE(&table_ids) / sizeof(grn_id);
+
+ grn_ctx_output_cstr(ctx, "tables");
+ grn_ctx_output_map_open(ctx, "tables", n);
+ for (i = 0; i < n; i++) {
+ grn_id table_id;
+ grn_obj *table;
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_push_temporary_open_space(ctx);
+ }
+
+ table_id = GRN_RECORD_VALUE_AT(&table_ids, i);
+ table = grn_ctx_at(ctx, table_id);
+
+ command_schema_output_table(ctx, data, table);
+
+ if (data->is_close_opened_object_mode) {
+ grn_ctx_pop_temporary_open_space(ctx);
+ }
+ }
+ grn_ctx_output_map_close(ctx);
+
+ GRN_OBJ_FIN(ctx, &table_ids);
+}
+
+static grn_obj *
+command_schema(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_schema_data data;
+
+ data.is_close_opened_object_mode = (grn_thread_get_limit() == 1);
+
+ grn_ctx_output_map_open(ctx, "schema", 6);
+ command_schema_output_plugins(ctx);
+ command_schema_output_types(ctx);
+ command_schema_output_tokenizers(ctx, &data);
+ command_schema_output_normalizers(ctx, &data);
+ command_schema_output_token_filters(ctx, &data);
+ command_schema_output_tables(ctx, &data);
+ grn_ctx_output_map_close(ctx);
+
+ return NULL;
+}
+
+void
+grn_proc_init_schema(grn_ctx *ctx)
+{
+ grn_plugin_command_create(ctx,
+ "schema", -1,
+ command_schema,
+ 0,
+ NULL);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_select.c b/storage/mroonga/vendor/groonga/lib/proc/proc_select.c
new file mode 100644
index 00000000..a665b1cc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_select.c
@@ -0,0 +1,3809 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_raw_string.h"
+#include "../grn_expr.h"
+#include "../grn_str.h"
+#include "../grn_output.h"
+#include "../grn_util.h"
+#include "../grn_cache.h"
+#include "../grn_ii.h"
+
+#include "../grn_ts.h"
+
+#include <groonga/plugin.h>
+
+#define GRN_SELECT_INTERNAL_VAR_MATCH_COLUMNS "$match_columns"
+
+#define DEFAULT_DRILLDOWN_LIMIT 10
+#define DEFAULT_DRILLDOWN_OUTPUT_COLUMNS "_key, _nsubrecs"
+
+typedef enum {
+ GRN_COLUMN_STAGE_INITIAL,
+ GRN_COLUMN_STAGE_FILTERED,
+ GRN_COLUMN_STAGE_OUTPUT
+} grn_column_stage;
+
+typedef struct {
+ grn_raw_string label;
+ grn_column_stage stage;
+ grn_obj *type;
+ grn_obj_flags flags;
+ grn_raw_string value;
+ struct {
+ grn_raw_string sort_keys;
+ grn_raw_string group_keys;
+ } window;
+} grn_column_data;
+
+typedef struct {
+ grn_hash *initial;
+ grn_hash *filtered;
+ grn_hash *output;
+} grn_columns;
+
+typedef struct {
+ grn_raw_string match_columns;
+ grn_raw_string query;
+ grn_raw_string query_expander;
+ grn_raw_string query_flags;
+ grn_raw_string filter;
+ struct {
+ grn_obj *match_columns;
+ grn_obj *expression;
+ } condition;
+ grn_obj *filtered;
+} grn_filter_data;
+
+typedef struct {
+ grn_raw_string label;
+ grn_filter_data filter;
+ grn_raw_string sort_keys;
+ grn_raw_string output_columns;
+ int offset;
+ int limit;
+ grn_obj *table;
+} grn_slice_data;
+
+typedef struct {
+ grn_raw_string label;
+ grn_raw_string keys;
+ grn_table_sort_key *parsed_keys;
+ int n_parsed_keys;
+ grn_raw_string sort_keys;
+ grn_raw_string output_columns;
+ int offset;
+ int limit;
+ grn_table_group_flags calc_types;
+ grn_raw_string calc_target_name;
+ grn_raw_string filter;
+ grn_raw_string table_name;
+ grn_columns columns;
+ grn_table_group_result result;
+ grn_obj *filtered_result;
+} grn_drilldown_data;
+
+typedef struct _grn_select_output_formatter grn_select_output_formatter;
+
+typedef struct {
+ /* inputs */
+ grn_raw_string table;
+ grn_filter_data filter;
+ grn_raw_string scorer;
+ grn_raw_string sort_keys;
+ grn_raw_string output_columns;
+ int offset;
+ int limit;
+ grn_hash *slices;
+ grn_drilldown_data drilldown;
+ grn_hash *drilldowns;
+ grn_raw_string cache;
+ grn_raw_string match_escalation_threshold;
+ grn_raw_string adjuster;
+ grn_columns columns;
+
+ /* for processing */
+ struct {
+ grn_obj *target;
+ grn_obj *initial;
+ grn_obj *result;
+ grn_obj *sorted;
+ grn_obj *output;
+ } tables;
+ uint16_t cacheable;
+ uint16_t taintable;
+ struct {
+ int n_elements;
+ grn_select_output_formatter *formatter;
+ } output;
+} grn_select_data;
+
+typedef void grn_select_output_slices_label_func(grn_ctx *ctx,
+ grn_select_data *data);
+typedef void grn_select_output_slices_open_func(grn_ctx *ctx,
+ grn_select_data *data,
+ unsigned int n_result_sets);
+typedef void grn_select_output_slices_close_func(grn_ctx *ctx,
+ grn_select_data *data);
+typedef void grn_select_output_slice_label_func(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_slice_data *slice);
+typedef void grn_select_output_drilldowns_label_func(grn_ctx *ctx,
+ grn_select_data *data);
+typedef void grn_select_output_drilldowns_open_func(grn_ctx *ctx,
+ grn_select_data *data,
+ unsigned int n_result_sets);
+typedef void grn_select_output_drilldowns_close_func(grn_ctx *ctx,
+ grn_select_data *data);
+typedef void grn_select_output_drilldown_label_func(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_drilldown_data *drilldown);
+
+struct _grn_select_output_formatter {
+ grn_select_output_slices_label_func *slices_label;
+ grn_select_output_slices_open_func *slices_open;
+ grn_select_output_slices_close_func *slices_close;
+ grn_select_output_slice_label_func *slice_label;
+ grn_select_output_drilldowns_label_func *drilldowns_label;
+ grn_select_output_drilldowns_open_func *drilldowns_open;
+ grn_select_output_drilldowns_close_func *drilldowns_close;
+ grn_select_output_drilldown_label_func *drilldown_label;
+};
+
+grn_rc
+grn_proc_syntax_expand_query(grn_ctx *ctx,
+ const char *query,
+ unsigned int query_len,
+ grn_expr_flags flags,
+ const char *query_expander_name,
+ unsigned int query_expander_name_len,
+ const char *term_column_name,
+ unsigned int term_column_name_len,
+ const char *expanded_term_column_name,
+ unsigned int expanded_term_column_name_len,
+ grn_obj *expanded_query,
+ const char *error_message_tag)
+{
+ grn_obj *query_expander;
+
+ query_expander = grn_ctx_get(ctx,
+ query_expander_name,
+ query_expander_name_len);
+ if (!query_expander) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s nonexistent query expander: <%.*s>",
+ error_message_tag,
+ (int)query_expander_name_len,
+ query_expander_name);
+ return ctx->rc;
+ }
+
+ if (expanded_term_column_name_len == 0) {
+ return grn_expr_syntax_expand_query(ctx, query, query_len, flags,
+ query_expander, expanded_query);
+ }
+
+ if (!grn_obj_is_table(ctx, query_expander)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, query_expander);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s query expander with expanded term column "
+ "must be table: <%.*s>",
+ error_message_tag,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+
+ {
+ grn_obj *term_column = NULL;
+ grn_obj *expanded_term_column;
+
+ expanded_term_column = grn_obj_column(ctx,
+ query_expander,
+ expanded_term_column_name,
+ expanded_term_column_name_len);
+ if (!expanded_term_column) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, query_expander);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s nonexistent expanded term column: <%.*s>: "
+ "query expander: <%.*s>",
+ error_message_tag,
+ (int)expanded_term_column_name_len,
+ expanded_term_column_name,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+
+ if (term_column_name_len > 0) {
+ term_column = grn_obj_column(ctx,
+ query_expander,
+ term_column_name,
+ term_column_name_len);
+ if (!term_column) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, query_expander);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s nonexistent term column: <%.*s>: "
+ "query expander: <%.*s>",
+ error_message_tag,
+ (int)term_column_name_len,
+ term_column_name,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ if (grn_obj_is_accessor(ctx, expanded_term_column)) {
+ grn_obj_unlink(ctx, expanded_term_column);
+ }
+ return ctx->rc;
+ }
+ }
+
+ grn_expr_syntax_expand_query_by_table(ctx,
+ query, query_len,
+ flags,
+ term_column,
+ expanded_term_column,
+ expanded_query);
+ if (grn_obj_is_accessor(ctx, term_column)) {
+ grn_obj_unlink(ctx, term_column);
+ }
+ if (grn_obj_is_accessor(ctx, expanded_term_column)) {
+ grn_obj_unlink(ctx, expanded_term_column);
+ }
+ return ctx->rc;
+ }
+}
+
+static grn_table_group_flags
+grn_parse_table_group_calc_types(grn_ctx *ctx,
+ const char *calc_types,
+ unsigned int calc_types_len)
+{
+ grn_table_group_flags flags = 0;
+ const char *calc_types_end = calc_types + calc_types_len;
+
+ while (calc_types < calc_types_end) {
+ if (*calc_types == ',' || *calc_types == ' ') {
+ calc_types += 1;
+ continue;
+ }
+
+#define CHECK_TABLE_GROUP_CALC_TYPE(name)\
+ if (((unsigned long) (calc_types_end - calc_types) >= (unsigned long) (sizeof(#name) - 1)) && \
+ (!memcmp(calc_types, #name, sizeof(#name) - 1))) {\
+ flags |= GRN_TABLE_GROUP_CALC_ ## name;\
+ calc_types += sizeof(#name) - 1;\
+ continue;\
+ }
+
+ CHECK_TABLE_GROUP_CALC_TYPE(COUNT);
+ CHECK_TABLE_GROUP_CALC_TYPE(MAX);
+ CHECK_TABLE_GROUP_CALC_TYPE(MIN);
+ CHECK_TABLE_GROUP_CALC_TYPE(SUM);
+ CHECK_TABLE_GROUP_CALC_TYPE(AVG);
+
+#define GRN_TABLE_GROUP_CALC_NONE 0
+ CHECK_TABLE_GROUP_CALC_TYPE(NONE);
+#undef GRN_TABLE_GROUP_CALC_NONE
+
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "invalid table group calc type: <%.*s>",
+ (int)(calc_types_end - calc_types),
+ calc_types);
+ return 0;
+#undef CHECK_TABLE_GROUP_CALC_TYPE
+ }
+
+ return flags;
+}
+
+static const char *
+grn_column_stage_name(grn_column_stage stage)
+{
+ switch (stage) {
+ case GRN_COLUMN_STAGE_INITIAL :
+ return "initial";
+ case GRN_COLUMN_STAGE_FILTERED :
+ return "filtered";
+ case GRN_COLUMN_STAGE_OUTPUT :
+ return "output";
+ default :
+ return "unknown";
+ }
+}
+
+static grn_bool
+grn_column_data_init(grn_ctx *ctx,
+ const char *label,
+ size_t label_len,
+ grn_column_stage stage,
+ grn_hash **columns)
+{
+ void *column_raw;
+ grn_column_data *column;
+ int added;
+
+ if (!*columns) {
+ *columns = grn_hash_create(ctx,
+ NULL,
+ GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_column_data),
+ GRN_OBJ_TABLE_HASH_KEY |
+ GRN_OBJ_KEY_VAR_SIZE |
+ GRN_HASH_TINY);
+ }
+ if (!*columns) {
+ return GRN_FALSE;
+ }
+
+ grn_hash_add(ctx,
+ *columns,
+ label,
+ label_len,
+ &column_raw,
+ &added);
+ if (!added) {
+ return GRN_TRUE;
+ }
+
+ column = column_raw;
+ column->label.value = label;
+ column->label.length = label_len;
+ column->stage = stage;
+ column->type = grn_ctx_at(ctx, GRN_DB_TEXT);
+ column->flags = GRN_OBJ_COLUMN_SCALAR;
+ GRN_RAW_STRING_INIT(column->value);
+ GRN_RAW_STRING_INIT(column->window.sort_keys);
+ GRN_RAW_STRING_INIT(column->window.group_keys);
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_column_data_fill(grn_ctx *ctx,
+ grn_column_data *column,
+ grn_obj *type_raw,
+ grn_obj *flags,
+ grn_obj *value,
+ grn_obj *window_sort_keys,
+ grn_obj *window_group_keys)
+{
+ if (type_raw && GRN_TEXT_LEN(type_raw) > 0) {
+ grn_obj *type;
+
+ type = grn_ctx_get(ctx, GRN_TEXT_VALUE(type_raw), GRN_TEXT_LEN(type_raw));
+ if (!type) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][columns][%s][%.*s] unknown type: <%.*s>",
+ grn_column_stage_name(column->stage),
+ (int)(column->label.length),
+ column->label.value,
+ (int)(GRN_TEXT_LEN(type_raw)),
+ GRN_TEXT_VALUE(type_raw));
+ return GRN_FALSE;
+ }
+ if (!(grn_obj_is_type(ctx, type) || grn_obj_is_table(ctx, type))) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, type);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][columns][%s][%.*s] invalid type: %.*s",
+ grn_column_stage_name(column->stage),
+ (int)(column->label.length),
+ column->label.value,
+ (int)(GRN_TEXT_LEN(&inspected)),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ grn_obj_unlink(ctx, type);
+ return GRN_FALSE;
+ }
+ column->type = type;
+ }
+
+ if (flags && GRN_TEXT_LEN(flags) > 0) {
+ char error_message_tag[GRN_TABLE_MAX_KEY_SIZE];
+
+ grn_snprintf(error_message_tag,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "[select][columns][%s][%.*s]",
+ grn_column_stage_name(column->stage),
+ (int)(column->label.length),
+ column->label.value);
+ column->flags =
+ grn_proc_column_parse_flags(ctx,
+ error_message_tag,
+ GRN_TEXT_VALUE(flags),
+ GRN_TEXT_VALUE(flags) + GRN_TEXT_LEN(flags));
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ }
+
+ GRN_RAW_STRING_FILL(column->value, value);
+ GRN_RAW_STRING_FILL(column->window.sort_keys, window_sort_keys);
+ GRN_RAW_STRING_FILL(column->window.group_keys, window_group_keys);
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_column_data_collect(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_hash *columns,
+ const char *prefix_label,
+ size_t prefix_label_len)
+{
+ grn_hash_cursor *cursor = NULL;
+
+ cursor = grn_hash_cursor_open(ctx, columns,
+ NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+
+ while (grn_hash_cursor_next(ctx, cursor)) {
+ grn_column_data *column;
+ char key_name[GRN_TABLE_MAX_KEY_SIZE];
+ grn_obj *type = NULL;
+ grn_obj *flags = NULL;
+ grn_obj *value = NULL;
+ struct {
+ grn_obj *sort_keys;
+ grn_obj *group_keys;
+ } window;
+
+ window.sort_keys = NULL;
+ window.group_keys = NULL;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&column);
+
+#define GET_VAR_RAW(parameter_key, name) \
+ if (!name) { \
+ grn_snprintf(key_name, \
+ GRN_TABLE_MAX_KEY_SIZE, \
+ GRN_TABLE_MAX_KEY_SIZE, \
+ "%.*s%s[%.*s]." # name, \
+ (int)prefix_label_len, \
+ prefix_label, \
+ parameter_key, \
+ (int)(column->label.length), \
+ column->label.value); \
+ name = grn_plugin_proc_get_var(ctx, user_data, key_name, -1); \
+ }
+
+#define GET_VAR(name) do { \
+ GET_VAR_RAW("columns", name); \
+ /* For backward compatibility */ \
+ GET_VAR_RAW("column", name); \
+ } while (GRN_FALSE)
+
+ GET_VAR(type);
+ GET_VAR(flags);
+ GET_VAR(value);
+ GET_VAR(window.sort_keys);
+ GET_VAR(window.group_keys);
+
+#undef GET_VAR
+
+#undef GET_VAR_RAW
+
+ grn_column_data_fill(ctx, column,
+ type, flags, value,
+ window.sort_keys,
+ window.group_keys);
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ return GRN_TRUE;
+}
+
+static void
+grn_columns_init(grn_ctx *ctx, grn_columns *columns)
+{
+ columns->initial = NULL;
+ columns->filtered = NULL;
+ columns->output = NULL;
+}
+
+static void
+grn_columns_fin(grn_ctx *ctx, grn_columns *columns)
+{
+ if (columns->initial) {
+ grn_hash_close(ctx, columns->initial);
+ }
+
+ if (columns->filtered) {
+ grn_hash_close(ctx, columns->filtered);
+ }
+
+ if (columns->output) {
+ grn_hash_close(ctx, columns->output);
+ }
+}
+
+static grn_bool
+grn_columns_collect(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_columns *columns,
+ const char *prefix,
+ const char *base_prefix,
+ size_t base_prefix_len)
+{
+ grn_obj *vars;
+ grn_table_cursor *cursor;
+ size_t prefix_len;
+ const char *suffix = "].stage";
+ size_t suffix_len;
+
+ vars = grn_plugin_proc_get_vars(ctx, user_data);
+ cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+
+ prefix_len = strlen(prefix);
+ suffix_len = strlen(suffix);
+ while (grn_table_cursor_next(ctx, cursor)) {
+ void *key;
+ char *variable_name;
+ unsigned int variable_name_len;
+ char *column_name;
+ size_t column_name_len;
+ void *value_raw;
+ grn_obj *value;
+ grn_column_stage stage;
+ grn_hash **target_columns;
+
+ variable_name_len = grn_table_cursor_get_key(ctx, cursor, &key);
+ variable_name = key;
+ if (variable_name_len < base_prefix_len + prefix_len + suffix_len + 1) {
+ continue;
+ }
+
+ if (base_prefix_len > 0) {
+ if (memcmp(base_prefix, variable_name, base_prefix_len) != 0) {
+ continue;
+ }
+ }
+
+ if (memcmp(prefix, variable_name + base_prefix_len, prefix_len) != 0) {
+ continue;
+ }
+
+ if (memcmp(suffix,
+ variable_name + (variable_name_len - suffix_len),
+ suffix_len) != 0) {
+ continue;
+ }
+
+ grn_table_cursor_get_value(ctx, cursor, &value_raw);
+ value = value_raw;
+ if (GRN_TEXT_EQUAL_CSTRING(value, "initial")) {
+ stage = GRN_COLUMN_STAGE_INITIAL;
+ target_columns = &(columns->initial);
+ } else if (GRN_TEXT_EQUAL_CSTRING(value, "filtered")) {
+ stage = GRN_COLUMN_STAGE_FILTERED;
+ target_columns = &(columns->filtered);
+ } else if (GRN_TEXT_EQUAL_CSTRING(value, "output")) {
+ stage = GRN_COLUMN_STAGE_OUTPUT;
+ target_columns = &(columns->output);
+ } else {
+ continue;
+ }
+
+ column_name = variable_name + base_prefix_len + prefix_len;
+ column_name_len =
+ variable_name_len - base_prefix_len - prefix_len - suffix_len;
+ if (!grn_column_data_init(ctx,
+ column_name,
+ column_name_len,
+ stage,
+ target_columns)) {
+ grn_table_cursor_close(ctx, cursor);
+ return GRN_FALSE;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_columns_fill(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_columns *columns,
+ const char *prefix,
+ size_t prefix_length)
+{
+ if (!grn_columns_collect(ctx, user_data, columns,
+ "columns[", prefix, prefix_length)) {
+ return GRN_FALSE;
+ }
+
+ /* For backward compatibility */
+ if (!grn_columns_collect(ctx, user_data, columns,
+ "column[", prefix, prefix_length)) {
+ return GRN_FALSE;
+ }
+
+ if (columns->initial) {
+ if (!grn_column_data_collect(ctx,
+ user_data,
+ columns->initial,
+ prefix,
+ prefix_length)) {
+ return GRN_FALSE;
+ }
+ }
+
+ if (columns->filtered) {
+ if (!grn_column_data_collect(ctx,
+ user_data,
+ columns->filtered,
+ prefix,
+ prefix_length)) {
+ return GRN_FALSE;
+ }
+ }
+
+ if (columns->output) {
+ if (!grn_column_data_collect(ctx,
+ user_data,
+ columns->output,
+ prefix,
+ prefix_length)) {
+ return GRN_FALSE;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+grn_filter_data_init(grn_ctx *ctx, grn_filter_data *data)
+{
+ GRN_RAW_STRING_INIT(data->match_columns);
+ GRN_RAW_STRING_INIT(data->query);
+ GRN_RAW_STRING_INIT(data->query_expander);
+ GRN_RAW_STRING_INIT(data->query_flags);
+ GRN_RAW_STRING_INIT(data->filter);
+ data->condition.match_columns = NULL;
+ data->condition.expression = NULL;
+ data->filtered = NULL;
+}
+
+static void
+grn_filter_data_fin(grn_ctx *ctx, grn_filter_data *data)
+{
+ if (data->filtered) {
+ grn_obj_unlink(ctx, data->filtered);
+ }
+ if (data->condition.expression) {
+ grn_obj_close(ctx, data->condition.expression);
+ }
+ if (data->condition.match_columns) {
+ grn_obj_close(ctx, data->condition.match_columns);
+ }
+}
+
+static void
+grn_filter_data_fill(grn_ctx *ctx,
+ grn_filter_data *data,
+ grn_obj *match_columns,
+ grn_obj *query,
+ grn_obj *query_expander,
+ grn_obj *query_flags,
+ grn_obj *filter)
+{
+ GRN_RAW_STRING_FILL(data->match_columns, match_columns);
+ GRN_RAW_STRING_FILL(data->query, query);
+ GRN_RAW_STRING_FILL(data->query_expander, query_expander);
+ GRN_RAW_STRING_FILL(data->query_flags, query_flags);
+ GRN_RAW_STRING_FILL(data->filter, filter);
+}
+
+static grn_bool
+grn_filter_data_execute(grn_ctx *ctx,
+ grn_filter_data *data,
+ grn_obj *table,
+ const char *tag)
+{
+ grn_obj *variable;
+
+ if (data->query.length == 0 && data->filter.length == 0) {
+ return GRN_TRUE;
+ }
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx,
+ table,
+ data->condition.expression,
+ variable);
+ if (!data->condition.expression) {
+ grn_rc rc = ctx->rc;
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "%s[condition] "
+ "failed to create expression for condition: %s",
+ tag,
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ if (data->query.length > 0) {
+ if (data->match_columns.length > 0) {
+ GRN_EXPR_CREATE_FOR_QUERY(ctx,
+ table,
+ data->condition.match_columns,
+ variable);
+ if (!data->condition.match_columns) {
+ grn_rc rc = ctx->rc;
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "%s[match_columns] "
+ "failed to create expression for match columns: "
+ "<%.*s>: %s",
+ tag,
+ (int)(data->match_columns.length),
+ data->match_columns.value,
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ grn_expr_parse(ctx,
+ data->condition.match_columns,
+ data->match_columns.value,
+ data->match_columns.length,
+ NULL, GRN_OP_MATCH, GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ }
+
+ {
+ grn_expr_flags flags;
+ grn_obj query_expander_buf;
+ const char *query = data->query.value;
+ unsigned int query_len = data->query.length;
+
+ flags = GRN_EXPR_SYNTAX_QUERY;
+ if (data->query_flags.length) {
+ flags |= grn_proc_expr_query_flags_parse(ctx,
+ data->query_flags.value,
+ data->query_flags.length,
+ tag);
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ } else {
+ flags |= GRN_EXPR_ALLOW_PRAGMA|GRN_EXPR_ALLOW_COLUMN;
+ }
+
+ GRN_TEXT_INIT(&query_expander_buf, 0);
+ if (data->query_expander.length > 0) {
+ grn_rc rc;
+ rc = grn_proc_syntax_expand_query(ctx,
+ data->query.value,
+ data->query.length,
+ flags,
+ data->query_expander.value,
+ data->query_expander.length,
+ NULL, 0,
+ NULL, 0,
+ &query_expander_buf,
+ tag);
+ if (rc == GRN_SUCCESS) {
+ query = GRN_TEXT_VALUE(&query_expander_buf);
+ query_len = GRN_TEXT_LEN(&query_expander_buf);
+ } else {
+ GRN_OBJ_FIN(ctx, &query_expander_buf);
+ return GRN_FALSE;
+ }
+ }
+
+ grn_expr_parse(ctx,
+ data->condition.expression,
+ query,
+ query_len,
+ data->condition.match_columns,
+ GRN_OP_MATCH,
+ GRN_OP_AND,
+ flags);
+ GRN_OBJ_FIN(ctx, &query_expander_buf);
+
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ }
+ }
+
+ if (data->filter.length > 0) {
+ grn_expr_parse(ctx,
+ data->condition.expression,
+ data->filter.value,
+ data->filter.length,
+ data->condition.match_columns,
+ GRN_OP_MATCH,
+ GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+
+ if (data->query.length > 0) {
+ grn_expr_append_op(ctx, data->condition.expression, GRN_OP_AND, 2);
+ }
+
+ if (ctx->rc != GRN_SUCCESS) {
+ return GRN_FALSE;
+ }
+ }
+
+ data->filtered = grn_table_select(ctx,
+ table,
+ data->condition.expression,
+ NULL,
+ GRN_OP_OR);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+static void
+grn_slice_data_init(grn_ctx *ctx,
+ grn_slice_data *slice,
+ const char *label,
+ size_t label_len)
+{
+ slice->label.value = label;
+ slice->label.length = label_len;
+ grn_filter_data_init(ctx, &(slice->filter));
+ GRN_RAW_STRING_INIT(slice->sort_keys);
+ GRN_RAW_STRING_INIT(slice->output_columns);
+ slice->offset = 0;
+ slice->limit = GRN_SELECT_DEFAULT_LIMIT;
+ slice->table = NULL;
+}
+
+static void
+grn_slice_data_fin(grn_ctx *ctx, grn_slice_data *slice)
+{
+ grn_filter_data_fin(ctx, &(slice->filter));
+}
+
+static void
+grn_slice_data_fill(grn_ctx *ctx,
+ grn_slice_data *slice,
+ grn_obj *match_columns,
+ grn_obj *query,
+ grn_obj *query_expander,
+ grn_obj *query_flags,
+ grn_obj *filter,
+ grn_obj *sort_keys,
+ grn_obj *output_columns,
+ grn_obj *offset,
+ grn_obj *limit)
+{
+ grn_filter_data_fill(ctx,
+ &(slice->filter),
+ match_columns,
+ query,
+ query_expander,
+ query_flags,
+ filter);
+
+ GRN_RAW_STRING_FILL(slice->sort_keys, sort_keys);
+
+ GRN_RAW_STRING_FILL(slice->output_columns, output_columns);
+ if (slice->output_columns.length == 0) {
+ slice->output_columns.value = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
+ slice->output_columns.length = strlen(GRN_SELECT_DEFAULT_OUTPUT_COLUMNS);
+ }
+
+ slice->offset = grn_proc_option_value_int32(ctx, offset, 0);
+ slice->limit = grn_proc_option_value_int32(ctx,
+ limit,
+ GRN_SELECT_DEFAULT_LIMIT);
+}
+
+static void
+grn_drilldown_data_init(grn_ctx *ctx,
+ grn_drilldown_data *drilldown,
+ const char *label,
+ size_t label_len)
+{
+ drilldown->label.value = label;
+ drilldown->label.length = label_len;
+ GRN_RAW_STRING_INIT(drilldown->keys);
+ drilldown->parsed_keys = NULL;
+ drilldown->n_parsed_keys = 0;
+ GRN_RAW_STRING_INIT(drilldown->sort_keys);
+ GRN_RAW_STRING_INIT(drilldown->output_columns);
+ drilldown->offset = 0;
+ drilldown->limit = DEFAULT_DRILLDOWN_LIMIT;
+ drilldown->calc_types = 0;
+ GRN_RAW_STRING_INIT(drilldown->calc_target_name);
+ GRN_RAW_STRING_INIT(drilldown->filter);
+ GRN_RAW_STRING_INIT(drilldown->table_name);
+ grn_columns_init(ctx, &(drilldown->columns));
+ drilldown->result.table = NULL;
+ drilldown->filtered_result = NULL;
+}
+
+static void
+grn_drilldown_data_fin(grn_ctx *ctx, grn_drilldown_data *drilldown)
+{
+ grn_table_group_result *result;
+
+ grn_columns_fin(ctx, &(drilldown->columns));
+
+ if (drilldown->filtered_result) {
+ grn_obj_close(ctx, drilldown->filtered_result);
+ }
+
+ result = &(drilldown->result);
+ if (result->table) {
+ if (result->calc_target) {
+ grn_obj_unlink(ctx, result->calc_target);
+ }
+ if (result->table) {
+ grn_obj_close(ctx, result->table);
+ }
+ }
+}
+
+static void
+grn_drilldown_data_fill(grn_ctx *ctx,
+ grn_drilldown_data *drilldown,
+ grn_obj *keys,
+ grn_obj *sort_keys,
+ grn_obj *output_columns,
+ grn_obj *offset,
+ grn_obj *limit,
+ grn_obj *calc_types,
+ grn_obj *calc_target,
+ grn_obj *filter,
+ grn_obj *table)
+{
+ GRN_RAW_STRING_FILL(drilldown->keys, keys);
+
+ GRN_RAW_STRING_FILL(drilldown->sort_keys, sort_keys);
+
+ GRN_RAW_STRING_FILL(drilldown->output_columns, output_columns);
+ if (drilldown->output_columns.length == 0) {
+ drilldown->output_columns.value = DEFAULT_DRILLDOWN_OUTPUT_COLUMNS;
+ drilldown->output_columns.length = strlen(DEFAULT_DRILLDOWN_OUTPUT_COLUMNS);
+ }
+
+ if (offset && GRN_TEXT_LEN(offset)) {
+ drilldown->offset =
+ grn_atoi(GRN_TEXT_VALUE(offset), GRN_BULK_CURR(offset), NULL);
+ } else {
+ drilldown->offset = 0;
+ }
+
+ if (limit && GRN_TEXT_LEN(limit)) {
+ drilldown->limit =
+ grn_atoi(GRN_TEXT_VALUE(limit), GRN_BULK_CURR(limit), NULL);
+ } else {
+ drilldown->limit = DEFAULT_DRILLDOWN_LIMIT;
+ }
+
+ if (calc_types && GRN_TEXT_LEN(calc_types)) {
+ drilldown->calc_types =
+ grn_parse_table_group_calc_types(ctx,
+ GRN_TEXT_VALUE(calc_types),
+ GRN_TEXT_LEN(calc_types));
+ } else {
+ drilldown->calc_types = 0;
+ }
+
+ GRN_RAW_STRING_FILL(drilldown->calc_target_name, calc_target);
+
+ GRN_RAW_STRING_FILL(drilldown->filter, filter);
+
+ GRN_RAW_STRING_FILL(drilldown->table_name, table);
+}
+
+grn_expr_flags
+grn_proc_expr_query_flags_parse(grn_ctx *ctx,
+ const char *query_flags,
+ size_t query_flags_size,
+ const char *error_message_tag)
+{
+ grn_expr_flags flags = 0;
+ const char *query_flags_end = query_flags + query_flags_size;
+
+ while (query_flags < query_flags_end) {
+ if (*query_flags == '|' || *query_flags == ' ') {
+ query_flags += 1;
+ continue;
+ }
+
+#define CHECK_EXPR_FLAG(name) \
+ if (((unsigned long) (query_flags_end - query_flags) >= (unsigned long) (sizeof(#name) - 1)) && \
+ (memcmp(query_flags, #name, sizeof(#name) - 1) == 0) && \
+ (((query_flags_end - query_flags) == (sizeof(#name) - 1)) || \
+ (query_flags[sizeof(#name) - 1] == '|') || \
+ (query_flags[sizeof(#name) - 1] == ' '))) { \
+ flags |= GRN_EXPR_ ## name; \
+ query_flags += sizeof(#name) - 1; \
+ continue; \
+ }
+
+ CHECK_EXPR_FLAG(ALLOW_PRAGMA);
+ CHECK_EXPR_FLAG(ALLOW_COLUMN);
+ CHECK_EXPR_FLAG(ALLOW_UPDATE);
+ CHECK_EXPR_FLAG(ALLOW_LEADING_NOT);
+ CHECK_EXPR_FLAG(QUERY_NO_SYNTAX_ERROR);
+
+#define GRN_EXPR_NONE 0
+ CHECK_EXPR_FLAG(NONE);
+#undef GNR_EXPR_NONE
+
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s invalid query flag: <%.*s>",
+ error_message_tag,
+ (int)(query_flags_end - query_flags),
+ query_flags);
+ return 0;
+#undef CHECK_EXPR_FLAG
+ }
+
+ return flags;
+}
+
+static void
+grn_select_expression_set_condition(grn_ctx *ctx,
+ grn_obj *expression,
+ grn_obj *condition)
+{
+ grn_obj *condition_ptr;
+
+ if (!expression) {
+ return;
+ }
+
+ condition_ptr =
+ grn_expr_get_or_add_var(ctx, expression,
+ GRN_SELECT_INTERNAL_VAR_CONDITION,
+ GRN_SELECT_INTERNAL_VAR_CONDITION_LEN);
+ GRN_PTR_INIT(condition_ptr, 0, GRN_DB_OBJECT);
+ GRN_PTR_SET(ctx, condition_ptr, condition);
+}
+
+grn_bool
+grn_proc_select_format_init(grn_ctx *ctx,
+ grn_obj_format *format,
+ grn_obj *result_set,
+ int n_hits,
+ int offset,
+ int limit,
+ const char *columns,
+ int columns_len,
+ grn_obj *condition)
+{
+ grn_rc rc;
+
+ GRN_OBJ_FORMAT_INIT(format, n_hits, offset, limit, offset);
+ format->flags =
+ GRN_OBJ_FORMAT_WITH_COLUMN_NAMES|
+ GRN_OBJ_FORMAT_XML_ELEMENT_RESULTSET;
+ rc = grn_output_format_set_columns(ctx,
+ format,
+ result_set,
+ columns,
+ columns_len);
+ if (rc != GRN_SUCCESS) {
+ GRN_OBJ_FORMAT_FIN(ctx, format);
+ return GRN_FALSE;
+ }
+
+ grn_select_expression_set_condition(ctx, format->expression, condition);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+grn_bool
+grn_proc_select_format_fin(grn_ctx *ctx, grn_obj_format *format)
+{
+ GRN_OBJ_FORMAT_FIN(ctx, format);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+grn_bool
+grn_proc_select_output_columns_open(grn_ctx *ctx,
+ grn_obj_format *format,
+ grn_obj *res,
+ int n_hits,
+ int offset,
+ int limit,
+ const char *columns,
+ int columns_len,
+ grn_obj *condition,
+ uint32_t n_additional_elements)
+{
+ grn_bool succeeded;
+
+ if (!grn_proc_select_format_init(ctx,
+ format,
+ res,
+ n_hits,
+ offset,
+ limit,
+ columns,
+ columns_len,
+ condition)) {
+ return GRN_FALSE;
+ }
+
+ GRN_OUTPUT_RESULT_SET_OPEN(res, format, n_additional_elements);
+ succeeded = (ctx->rc == GRN_SUCCESS);
+ if (!succeeded) {
+ GRN_OUTPUT_RESULT_SET_CLOSE(res, format);
+ }
+
+ return succeeded;
+}
+
+grn_bool
+grn_proc_select_output_columns_close(grn_ctx *ctx,
+ grn_obj_format *format,
+ grn_obj *result_set)
+{
+ GRN_OUTPUT_RESULT_SET_CLOSE(result_set, format);
+
+ return grn_proc_select_format_fin(ctx, format);
+}
+
+grn_bool
+grn_proc_select_output_columns(grn_ctx *ctx,
+ grn_obj *res,
+ int n_hits,
+ int offset,
+ int limit,
+ const char *columns,
+ int columns_len,
+ grn_obj *condition)
+{
+ grn_obj_format format;
+ uint32_t n_additional_elements = 0;
+
+ if (!grn_proc_select_output_columns_open(ctx,
+ &format,
+ res,
+ n_hits,
+ offset,
+ limit,
+ columns,
+ columns_len,
+ condition,
+ n_additional_elements)) {
+ return GRN_FALSE;
+ }
+
+ return grn_proc_select_output_columns_close(ctx, &format, res);
+}
+
+static grn_obj *
+grn_select_create_all_selected_result_table(grn_ctx *ctx,
+ grn_obj *table)
+{
+ grn_obj *result;
+ grn_posting posting;
+
+ result = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC,
+ table, NULL);
+ if (!result) {
+ return NULL;
+ }
+
+ memset(&posting, 0, sizeof(grn_posting));
+ GRN_TABLE_EACH_BEGIN(ctx, table, cursor, id) {
+ posting.rid = id;
+ grn_ii_posting_add(ctx,
+ &posting,
+ (grn_hash *)(result),
+ GRN_OP_OR);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+
+ return result;
+}
+
+static grn_obj *
+grn_select_create_no_sort_keys_sorted_table(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj *table)
+{
+ grn_obj *sorted;
+ grn_table_cursor *cursor;
+
+ sorted = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_NO_KEY,
+ NULL,
+ table);
+
+ if (!sorted) {
+ return NULL;
+ }
+
+ cursor = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0,
+ data->offset,
+ data->limit,
+ GRN_CURSOR_ASCENDING);
+ if (cursor) {
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, cursor))) {
+ grn_id *value;
+ if (grn_array_add(ctx, (grn_array *)sorted, (void **)&value)) {
+ *value = id;
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ }
+
+ return sorted;
+}
+
+
+static void
+grn_select_apply_columns(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj *table,
+ grn_hash *columns)
+{
+ grn_hash_cursor *columns_cursor;
+
+ columns_cursor = grn_hash_cursor_open(ctx, columns,
+ NULL, 0, NULL, 0, 0, -1, 0);
+ if (!columns_cursor) {
+ return;
+ }
+
+ while (grn_hash_cursor_next(ctx, columns_cursor) != GRN_ID_NIL) {
+ grn_column_data *column_data;
+ grn_obj *column;
+ grn_obj *expression;
+ grn_obj *record;
+
+ grn_hash_cursor_get_value(ctx, columns_cursor, (void **)&column_data);
+
+ column = grn_column_create(ctx,
+ table,
+ column_data->label.value,
+ column_data->label.length,
+ NULL,
+ column_data->flags,
+ column_data->type);
+ if (!column) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][column][%s][%.*s] failed to create column: %s",
+ grn_column_stage_name(column_data->stage),
+ (int)(column_data->label.length),
+ column_data->label.value,
+ ctx->errbuf);
+ break;
+ }
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, table, expression, record);
+ if (!expression) {
+ grn_obj_close(ctx, column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][column][%s][%.*s] "
+ "failed to create expression to compute value: %s",
+ grn_column_stage_name(column_data->stage),
+ (int)(column_data->label.length),
+ column_data->label.value,
+ ctx->errbuf);
+ break;
+ }
+ grn_expr_parse(ctx,
+ expression,
+ column_data->value.value,
+ column_data->value.length,
+ NULL,
+ GRN_OP_MATCH,
+ GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, expression);
+ grn_obj_close(ctx, column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][column][%s][%.*s] "
+ "failed to parse value: <%.*s>: %s",
+ grn_column_stage_name(column_data->stage),
+ (int)(column_data->label.length),
+ column_data->label.value,
+ (int)(column_data->value.length),
+ column_data->value.value,
+ ctx->errbuf);
+ break;
+ }
+ grn_select_expression_set_condition(ctx,
+ expression,
+ data->filter.condition.expression);
+
+ if (column_data->window.sort_keys.length > 0 ||
+ column_data->window.group_keys.length > 0) {
+ grn_window_definition definition;
+ grn_rc rc;
+
+ if (column_data->window.sort_keys.length > 0) {
+ int n_sort_keys;
+ definition.sort_keys =
+ grn_table_sort_key_from_str(ctx,
+ column_data->window.sort_keys.value,
+ column_data->window.sort_keys.length,
+ table, &n_sort_keys);
+ definition.n_sort_keys = n_sort_keys;
+ if (!definition.sort_keys) {
+ grn_obj_close(ctx, expression);
+ grn_obj_close(ctx, column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][column][%s][%.*s] "
+ "failed to parse sort keys: %s",
+ grn_column_stage_name(column_data->stage),
+ (int)(column_data->label.length),
+ column_data->label.value,
+ ctx->errbuf);
+ break;
+ }
+ } else {
+ definition.sort_keys = NULL;
+ definition.n_sort_keys = 0;
+ }
+
+ if (column_data->window.group_keys.length > 0) {
+ int n_group_keys;
+ definition.group_keys =
+ grn_table_sort_key_from_str(ctx,
+ column_data->window.group_keys.value,
+ column_data->window.group_keys.length,
+ table, &n_group_keys);
+ definition.n_group_keys = n_group_keys;
+ if (!definition.group_keys) {
+ grn_obj_close(ctx, expression);
+ grn_obj_close(ctx, column);
+ if (definition.sort_keys) {
+ grn_table_sort_key_close(ctx,
+ definition.sort_keys,
+ definition.n_sort_keys);
+ }
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][column][%s][%.*s] "
+ "failed to parse group keys: %s",
+ grn_column_stage_name(column_data->stage),
+ (int)(column_data->label.length),
+ column_data->label.value,
+ ctx->errbuf);
+ break;
+ }
+ } else {
+ definition.group_keys = NULL;
+ definition.n_group_keys = 0;
+ }
+
+ rc = grn_table_apply_window_function(ctx,
+ table,
+ column,
+ &definition,
+ expression);
+ if (definition.sort_keys) {
+ grn_table_sort_key_close(ctx,
+ definition.sort_keys,
+ definition.n_sort_keys);
+ }
+ if (definition.group_keys) {
+ grn_table_sort_key_close(ctx,
+ definition.group_keys,
+ definition.n_group_keys);
+ }
+ if (rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, expression);
+ grn_obj_close(ctx, column);
+ break;
+ }
+ } else {
+ grn_rc rc;
+ rc = grn_table_apply_expr(ctx, table, column, expression);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, expression);
+ grn_obj_close(ctx, column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][column][%s][%.*s] "
+ "failed to apply expression to generate column values: "
+ "%s",
+ grn_column_stage_name(column_data->stage),
+ (int)(column_data->label.length),
+ column_data->label.value,
+ ctx->errbuf);
+ break;
+ }
+ }
+
+ grn_obj_close(ctx, expression);
+
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "columns[%.*s](%d)",
+ (int)(column_data->label.length),
+ column_data->label.value,
+ grn_table_size(ctx, table));
+ }
+
+ grn_hash_cursor_close(ctx, columns_cursor);
+}
+
+static grn_bool
+grn_select_apply_initial_columns(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ if (!data->columns.initial) {
+ return GRN_TRUE;
+ }
+
+ data->tables.initial =
+ grn_select_create_all_selected_result_table(ctx, data->tables.target);
+ if (!data->tables.initial) {
+ return GRN_FALSE;
+ }
+
+ grn_select_apply_columns(ctx,
+ data,
+ data->tables.initial,
+ data->columns.initial);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+static grn_bool
+grn_select_filter(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ if (!grn_filter_data_execute(ctx,
+ &(data->filter),
+ data->tables.initial,
+ "[select]")) {
+ return GRN_FALSE;
+ }
+
+ data->tables.result = data->filter.filtered;
+ if (!data->tables.result) {
+ data->tables.result = data->tables.initial;
+ }
+
+ {
+ grn_expr *expression;
+ expression = (grn_expr *)(data->filter.condition.expression);
+ if (expression) {
+ data->cacheable *= expression->cacheable;
+ data->taintable += expression->taintable;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_apply_filtered_columns(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ if (!data->columns.filtered) {
+ return GRN_TRUE;
+ }
+
+ if (data->tables.result == data->tables.initial) {
+ data->tables.result =
+ grn_select_create_all_selected_result_table(ctx, data->tables.initial);
+ if (!data->tables.result) {
+ return GRN_FALSE;
+ }
+ }
+
+ grn_select_apply_columns(ctx,
+ data,
+ data->tables.result,
+ data->columns.filtered);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+static int
+grn_select_apply_adjuster_execute_ensure_factor(grn_ctx *ctx,
+ grn_obj *factor_object)
+{
+ if (!factor_object) {
+ return 1;
+ } else if (factor_object->header.domain == GRN_DB_INT32) {
+ return GRN_INT32_VALUE(factor_object);
+ } else {
+ grn_rc rc;
+ grn_obj int32_object;
+ int factor;
+ GRN_INT32_INIT(&int32_object, 0);
+ rc = grn_obj_cast(ctx, factor_object, &int32_object, GRN_FALSE);
+ if (rc == GRN_SUCCESS) {
+ factor = GRN_INT32_VALUE(&int32_object);
+ } else {
+ /* TODO: Log or return error? */
+ factor = 1;
+ }
+ GRN_OBJ_FIN(ctx, &int32_object);
+ return factor;
+ }
+}
+
+static void
+grn_select_apply_adjuster_execute_adjust(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *column,
+ grn_obj *value,
+ grn_obj *factor)
+{
+ grn_obj *index;
+ unsigned int n_indexes;
+ int factor_value;
+
+ n_indexes = grn_column_index(ctx, column, GRN_OP_MATCH, &index, 1, NULL);
+ if (n_indexes == 0) {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int column_name_size;
+ column_name_size = grn_obj_name(ctx, column,
+ column_name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "adjuster requires index column for the target column: "
+ "<%.*s>",
+ column_name_size,
+ column_name);
+ return;
+ }
+
+ factor_value = grn_select_apply_adjuster_execute_ensure_factor(ctx, factor);
+
+ {
+ grn_search_optarg options;
+ memset(&options, 0, sizeof(grn_search_optarg));
+
+ options.mode = GRN_OP_EXACT;
+ options.similarity_threshold = 0;
+ options.max_interval = 0;
+ options.weight_vector = NULL;
+ options.vector_size = factor_value;
+ options.proc = NULL;
+ options.max_size = 0;
+ options.scorer = NULL;
+
+ grn_obj_search(ctx, index, value, table, GRN_OP_ADJUST, &options);
+ }
+}
+
+static void
+grn_select_apply_adjuster_execute(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *adjuster)
+{
+ grn_expr *expr = (grn_expr *)adjuster;
+ grn_expr_code *code, *code_end;
+
+ code = expr->codes;
+ code_end = expr->codes + expr->codes_curr;
+ while (code < code_end) {
+ grn_obj *column, *value, *factor;
+
+ if (code->op == GRN_OP_PLUS) {
+ code++;
+ continue;
+ }
+
+ column = code->value;
+ code++;
+ value = code->value;
+ code++;
+ code++; /* op == GRN_OP_MATCH */
+ if ((code_end - code) >= 2 && code[1].op == GRN_OP_STAR) {
+ factor = code->value;
+ code++;
+ code++; /* op == GRN_OP_STAR */
+ } else {
+ factor = NULL;
+ }
+ grn_select_apply_adjuster_execute_adjust(ctx, table, column, value, factor);
+ }
+}
+
+static grn_bool
+grn_select_apply_adjuster(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ grn_obj *adjuster;
+ grn_obj *record;
+ grn_rc rc;
+
+ if (data->adjuster.length == 0) {
+ return GRN_TRUE;
+ }
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, data->tables.target, adjuster, record);
+ if (!adjuster) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][adjuster] "
+ "failed to create expression: %s",
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ rc = grn_expr_parse(ctx, adjuster,
+ data->adjuster.value,
+ data->adjuster.length,
+ NULL,
+ GRN_OP_MATCH, GRN_OP_ADJUST,
+ GRN_EXPR_SYNTAX_ADJUSTER);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, adjuster);
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[select][adjuster] "
+ "failed to parse: %s",
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ data->cacheable *= ((grn_expr *)adjuster)->cacheable;
+ data->taintable += ((grn_expr *)adjuster)->taintable;
+ grn_select_apply_adjuster_execute(ctx, data->tables.result, adjuster);
+ grn_obj_unlink(ctx, adjuster);
+
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "adjust(%d)", grn_table_size(ctx, data->tables.result));
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_apply_scorer(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ grn_obj *scorer;
+ grn_obj *record;
+ grn_rc rc = GRN_SUCCESS;
+
+ if (data->scorer.length == 0) {
+ return GRN_TRUE;
+ }
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, data->tables.result, scorer, record);
+ if (!scorer) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][scorer] "
+ "failed to create expression: %s",
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ rc = grn_expr_parse(ctx,
+ scorer,
+ data->scorer.value,
+ data->scorer.length,
+ NULL,
+ GRN_OP_MATCH,
+ GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT|GRN_EXPR_ALLOW_UPDATE);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, scorer);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][scorer] "
+ "failed to parse: %s",
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ data->cacheable *= ((grn_expr *)scorer)->cacheable;
+ data->taintable += ((grn_expr *)scorer)->taintable;
+ GRN_TABLE_EACH_BEGIN(ctx, data->tables.result, cursor, id) {
+ GRN_RECORD_SET(ctx, record, id);
+ grn_expr_exec(ctx, scorer, 0);
+ if (ctx->rc) {
+ rc = ctx->rc;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[select][scorer] "
+ "failed to execute: <%.*s>: %s",
+ (int)(data->scorer.length),
+ data->scorer.value,
+ ctx->errbuf);
+ break;
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_obj_unlink(ctx, scorer);
+
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "score(%d)", grn_table_size(ctx, data->tables.result));
+
+ return rc == GRN_SUCCESS;
+}
+
+static grn_bool
+grn_select_sort(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ grn_table_sort_key *keys;
+ uint32_t n_keys;
+
+ if (data->sort_keys.length == 0) {
+ return GRN_TRUE;
+ }
+
+ keys = grn_table_sort_key_from_str(ctx,
+ data->sort_keys.value,
+ data->sort_keys.length,
+ data->tables.result,
+ &n_keys);
+ if (!keys) {
+ if (ctx->rc == GRN_SUCCESS) {
+ return GRN_TRUE;
+ } else {
+ GRN_PLUGIN_ERROR(ctx,
+ ctx->rc,
+ "[select][sort] "
+ "failed to parse: <%.*s>: %s",
+ (int)(data->sort_keys.length),
+ data->sort_keys.value,
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+ }
+
+ data->tables.sorted = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_OBJ_TABLE_NO_KEY,
+ NULL,
+ data->tables.result);
+ if (!data->tables.sorted) {
+ GRN_PLUGIN_ERROR(ctx,
+ ctx->rc,
+ "[select][sort] "
+ "failed to create table to store sorted record: "
+ "<%.*s>: %s",
+ (int)(data->sort_keys.length),
+ data->sort_keys.value,
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+
+ grn_table_sort(ctx,
+ data->tables.result,
+ data->offset,
+ data->limit,
+ data->tables.sorted,
+ keys,
+ n_keys);
+
+ grn_table_sort_key_close(ctx, keys, n_keys);
+
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "sort(%d)", data->limit);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+static grn_bool
+grn_select_apply_output_columns(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ if (!data->columns.output) {
+ return GRN_TRUE;
+ }
+
+ if (!data->tables.sorted) {
+ data->tables.sorted =
+ grn_select_create_no_sort_keys_sorted_table(ctx,
+ data,
+ data->tables.result);
+ if (!data->tables.sorted) {
+ return GRN_FALSE;
+ }
+ }
+
+ grn_select_apply_columns(ctx,
+ data,
+ data->tables.sorted,
+ data->columns.output);
+
+ return ctx->rc == GRN_SUCCESS;
+}
+
+static grn_bool
+grn_select_output_match_open(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj_format *format,
+ uint32_t n_additional_elements)
+{
+ grn_bool succeeded = GRN_TRUE;
+ int offset;
+ grn_obj *output_table;
+
+ if (data->tables.sorted) {
+ offset = 0;
+ output_table = data->tables.sorted;
+ } else {
+ offset = data->offset;
+ output_table = data->tables.result;
+ }
+ succeeded =
+ grn_proc_select_output_columns_open(ctx,
+ format,
+ output_table,
+ grn_table_size(ctx, data->tables.result),
+ offset,
+ data->limit,
+ data->output_columns.value,
+ data->output_columns.length,
+ data->filter.condition.expression,
+ n_additional_elements);
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "output(%d)", data->limit);
+
+ return succeeded;
+}
+
+static grn_bool
+grn_select_output_match_close(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj_format *format)
+{
+ grn_obj *output_table;
+
+ if (data->tables.sorted) {
+ output_table = data->tables.sorted;
+ } else {
+ output_table = data->tables.result;
+ }
+
+ return grn_proc_select_output_columns_close(ctx, format, output_table);
+}
+
+static grn_bool
+grn_select_output_match(grn_ctx *ctx, grn_select_data *data)
+{
+ grn_obj_format format;
+ uint32_t n_additional_elements = 0;
+
+ if (!grn_select_output_match_open(ctx, data, &format, n_additional_elements)) {
+ return GRN_FALSE;
+ }
+
+ return grn_select_output_match_close(ctx, data, &format);
+}
+
+static grn_bool
+grn_select_slice_execute(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj *table,
+ grn_slice_data *slice)
+{
+ char tag[GRN_TABLE_MAX_KEY_SIZE];
+ grn_filter_data *filter;
+
+ grn_snprintf(tag, GRN_TABLE_MAX_KEY_SIZE, GRN_TABLE_MAX_KEY_SIZE,
+ "[select][slices][%.*s]",
+ (int)(slice->label.length),
+ slice->label.value);
+ filter = &(slice->filter);
+ if (filter->query.length == 0 && filter->filter.length == 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "%s slice requires query or filter",
+ tag);
+ return GRN_FALSE;
+ }
+
+ if (!grn_filter_data_execute(ctx, filter, table, tag)) {
+ return GRN_FALSE;
+ }
+
+ slice->table = filter->filtered;
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_slices_execute(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj *table,
+ grn_hash *slices)
+{
+ grn_bool succeeded = GRN_TRUE;
+
+ GRN_HASH_EACH_BEGIN(ctx, slices, cursor, id) {
+ grn_slice_data *slice;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+ if (!grn_select_slice_execute(ctx, data, table, slice)) {
+ succeeded = GRN_FALSE;
+ break;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ return succeeded;
+}
+
+static grn_bool
+grn_select_prepare_slices(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ if (!data->slices) {
+ return GRN_TRUE;
+ }
+
+ if (!grn_select_slices_execute(ctx, data, data->tables.result, data->slices)) {
+ return GRN_FALSE;
+ }
+
+ data->output.n_elements += 1;
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_output_slices(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ grn_bool succeeded = GRN_TRUE;
+ unsigned int n_available_results = 0;
+
+ if (!data->slices) {
+ return GRN_TRUE;
+ }
+
+ data->output.formatter->slices_label(ctx, data);
+
+ GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
+ grn_slice_data *slice;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+ if (slice->table) {
+ n_available_results++;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ data->output.formatter->slices_open(ctx, data, n_available_results);
+
+ GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
+ grn_slice_data *slice;
+ uint32_t n_hits;
+ int offset;
+ int limit;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+ if (!slice->table) {
+ continue;
+ }
+
+ n_hits = grn_table_size(ctx, slice->table);
+
+ offset = slice->offset;
+ limit = slice->limit;
+ grn_normalize_offset_and_limit(ctx, n_hits, &offset, &limit);
+
+ if (slice->sort_keys.length > 0) {
+ grn_table_sort_key *sort_keys;
+ uint32_t n_sort_keys;
+ sort_keys = grn_table_sort_key_from_str(ctx,
+ slice->sort_keys.value,
+ slice->sort_keys.length,
+ slice->table, &n_sort_keys);
+ if (sort_keys) {
+ grn_obj *sorted;
+ sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY,
+ NULL, slice->table);
+ if (sorted) {
+ grn_table_sort(ctx, slice->table, offset, limit,
+ sorted, sort_keys, n_sort_keys);
+ data->output.formatter->slice_label(ctx, data, slice);
+ if (!grn_proc_select_output_columns(ctx,
+ sorted,
+ n_hits,
+ 0,
+ limit,
+ slice->output_columns.value,
+ slice->output_columns.length,
+ slice->filter.condition.expression)) {
+ succeeded = GRN_FALSE;
+ }
+ grn_obj_unlink(ctx, sorted);
+ }
+ grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
+ } else {
+ succeeded = GRN_FALSE;
+ }
+ } else {
+ data->output.formatter->slice_label(ctx, data, slice);
+ if (!grn_proc_select_output_columns(ctx,
+ slice->table,
+ n_hits,
+ offset,
+ limit,
+ slice->output_columns.value,
+ slice->output_columns.length,
+ slice->filter.condition.expression)) {
+ succeeded = GRN_FALSE;
+ }
+ }
+
+ if (!succeeded) {
+ break;
+ }
+
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "slice(%d)[%.*s]",
+ n_hits,
+ (int)(slice->label.length),
+ slice->label.value);
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ data->output.formatter->slices_close(ctx, data);
+
+ return succeeded;
+}
+
+static grn_bool
+grn_select_drilldown_execute(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_obj *table,
+ grn_hash *drilldowns,
+ grn_id id)
+{
+ grn_table_sort_key *keys = NULL;
+ unsigned int n_keys = 0;
+ grn_obj *target_table = table;
+ grn_drilldown_data *drilldown;
+ grn_table_group_result *result;
+
+ drilldown =
+ (grn_drilldown_data *)grn_hash_get_value_(ctx, drilldowns, id, NULL);
+ result = &(drilldown->result);
+
+ result->limit = 1;
+ result->flags = GRN_TABLE_GROUP_CALC_COUNT;
+ result->op = 0;
+ result->max_n_subrecs = 0;
+ result->key_begin = 0;
+ result->key_end = 0;
+ if (result->calc_target) {
+ grn_obj_unlink(ctx, result->calc_target);
+ }
+ result->calc_target = NULL;
+
+ if (drilldown->table_name.length > 0) {
+ grn_id dependent_id;
+ dependent_id = grn_hash_get(ctx,
+ drilldowns,
+ drilldown->table_name.value,
+ drilldown->table_name.length,
+ NULL);
+ if (dependent_id == GRN_ID_NIL) {
+ if (data->slices) {
+ grn_slice_data *slice;
+ dependent_id = grn_hash_get(ctx,
+ data->slices,
+ drilldown->table_name.value,
+ drilldown->table_name.length,
+ NULL);
+ if (dependent_id) {
+ slice =
+ (grn_slice_data *)grn_hash_get_value_(ctx, data->slices,
+ dependent_id, NULL);
+ target_table = slice->table;
+ }
+ }
+ if (dependent_id == GRN_ID_NIL) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[select][drilldowns][%.*s][table] "
+ "nonexistent label: <%.*s>",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ (int)(drilldown->table_name.length),
+ drilldown->table_name.value);
+ return GRN_FALSE;
+ }
+ } else {
+ grn_drilldown_data *dependent_drilldown;
+ grn_table_group_result *dependent_result;
+
+ dependent_drilldown =
+ (grn_drilldown_data *)grn_hash_get_value_(ctx,
+ drilldowns,
+ dependent_id,
+ NULL);
+ dependent_result = &(dependent_drilldown->result);
+ target_table = dependent_result->table;
+ }
+ }
+
+ if (drilldown->parsed_keys) {
+ result->key_end = drilldown->n_parsed_keys;
+ } else if (drilldown->keys.length > 0) {
+ keys = grn_table_sort_key_from_str(ctx,
+ drilldown->keys.value,
+ drilldown->keys.length,
+ target_table, &n_keys);
+ if (!keys) {
+ GRN_PLUGIN_CLEAR_ERROR(ctx);
+ return GRN_FALSE;
+ }
+
+ result->key_end = n_keys - 1;
+ if (n_keys > 1) {
+ result->max_n_subrecs = 1;
+ }
+ }
+
+ if (drilldown->calc_target_name.length > 0) {
+ result->calc_target = grn_obj_column(ctx, target_table,
+ drilldown->calc_target_name.value,
+ drilldown->calc_target_name.length);
+ }
+ if (result->calc_target) {
+ result->flags |= drilldown->calc_types;
+ }
+
+ if (drilldown->parsed_keys) {
+ grn_table_group(ctx,
+ target_table,
+ drilldown->parsed_keys,
+ drilldown->n_parsed_keys,
+ result,
+ 1);
+ } else {
+ grn_table_group(ctx, target_table, keys, n_keys, result, 1);
+ }
+
+ if (keys) {
+ grn_table_sort_key_close(ctx, keys, n_keys);
+ }
+
+ if (!result->table) {
+ return GRN_FALSE;
+ }
+
+ if (drilldown->columns.initial) {
+ grn_select_apply_columns(ctx,
+ data,
+ result->table,
+ drilldown->columns.initial);
+ }
+
+ if (drilldown->filter.length > 0) {
+ grn_obj *expression;
+ grn_obj *record;
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, result->table, expression, record);
+ if (!expression) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][drilldowns]%s%.*s%s[filter] "
+ "failed to create expression for filter: %s",
+ drilldown->label.length > 0 ? "[" : "",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ drilldown->label.length > 0 ? "]" : "",
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+ grn_expr_parse(ctx,
+ expression,
+ drilldown->filter.value,
+ drilldown->filter.length,
+ NULL,
+ GRN_OP_MATCH,
+ GRN_OP_AND,
+ GRN_EXPR_SYNTAX_SCRIPT);
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, expression);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][drilldowns]%s%.*s%s[filter] "
+ "failed to parse filter: <%.*s>: %s",
+ drilldown->label.length > 0 ? "[" : "",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ drilldown->label.length > 0 ? "]" : "",
+ (int)(drilldown->filter.length),
+ drilldown->filter.value,
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+ drilldown->filtered_result = grn_table_select(ctx,
+ result->table,
+ expression,
+ NULL,
+ GRN_OP_OR);
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, expression);
+ if (drilldown->filtered_result) {
+ grn_obj_close(ctx, drilldown->filtered_result);
+ drilldown->filtered_result = NULL;
+ }
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][drilldowns]%s%.*s%s[filter] "
+ "failed to execute filter: <%.*s>: %s",
+ drilldown->label.length > 0 ? "[" : "",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ drilldown->label.length > 0 ? "]" : "",
+ (int)(drilldown->filter.length),
+ drilldown->filter.value,
+ ctx->errbuf);
+ return GRN_FALSE;
+ }
+ grn_obj_close(ctx, expression);
+ }
+
+ {
+ unsigned int n_hits;
+
+ if (drilldown->filtered_result) {
+ n_hits = grn_table_size(ctx, drilldown->filtered_result);
+ } else {
+ n_hits = grn_table_size(ctx, result->table);
+ }
+ if (data->drilldown.keys.length == 0) {
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "drilldowns[%.*s](%u)",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ n_hits);
+ } else {
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "drilldown(%u)",
+ n_hits);
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+typedef enum {
+ TSORT_STATUS_NOT_VISITED,
+ TSORT_STATUS_VISITING,
+ TSORT_STATUS_VISITED
+} tsort_status;
+
+static grn_bool
+drilldown_tsort_visit(grn_ctx *ctx,
+ grn_hash *drilldowns,
+ tsort_status *statuses,
+ grn_obj *ids,
+ grn_id id)
+{
+ grn_bool cycled = GRN_TRUE;
+ uint32_t index = id - 1;
+
+ switch (statuses[index]) {
+ case TSORT_STATUS_VISITING :
+ cycled = GRN_TRUE;
+ break;
+ case TSORT_STATUS_VISITED :
+ cycled = GRN_FALSE;
+ break;
+ case TSORT_STATUS_NOT_VISITED :
+ cycled = GRN_FALSE;
+ statuses[index] = TSORT_STATUS_VISITING;
+ {
+ grn_drilldown_data *drilldown;
+ drilldown =
+ (grn_drilldown_data *)grn_hash_get_value_(ctx, drilldowns, id, NULL);
+ if (drilldown->table_name.length > 0) {
+ grn_id dependent_id;
+ dependent_id = grn_hash_get(ctx, drilldowns,
+ drilldown->table_name.value,
+ drilldown->table_name.length,
+ NULL);
+ if (dependent_id != GRN_ID_NIL) {
+ cycled = drilldown_tsort_visit(ctx,
+ drilldowns,
+ statuses,
+ ids,
+ dependent_id);
+ if (cycled) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[select][drilldowns][%.*s][table] "
+ "cycled dependency: <%.*s>",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ (int)(drilldown->table_name.length),
+ drilldown->table_name.value);
+ }
+ }
+ }
+ }
+ if (!cycled) {
+ statuses[index] = TSORT_STATUS_VISITED;
+ GRN_RECORD_PUT(ctx, ids, id);
+ }
+ break;
+ }
+
+ return cycled;
+}
+
+static grn_bool
+drilldown_tsort_body(grn_ctx *ctx,
+ grn_hash *drilldowns,
+ tsort_status *statuses,
+ grn_obj *ids)
+{
+ grn_bool succeeded = GRN_TRUE;
+
+ GRN_HASH_EACH_BEGIN(ctx, drilldowns, cursor, id) {
+ if (drilldown_tsort_visit(ctx, drilldowns, statuses, ids, id)) {
+ succeeded = GRN_FALSE;
+ break;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ return succeeded;
+}
+
+static void
+drilldown_tsort_init(grn_ctx *ctx,
+ tsort_status *statuses,
+ size_t n_statuses)
+{
+ size_t i;
+ for (i = 0; i < n_statuses; i++) {
+ statuses[i] = TSORT_STATUS_NOT_VISITED;
+ }
+}
+
+static grn_bool
+drilldown_tsort(grn_ctx *ctx,
+ grn_hash *drilldowns,
+ grn_obj *ids)
+{
+ tsort_status *statuses;
+ size_t n_statuses;
+ grn_bool succeeded;
+
+ n_statuses = grn_hash_size(ctx, drilldowns);
+ statuses = GRN_PLUGIN_MALLOCN(ctx, tsort_status, n_statuses);
+ if (!statuses) {
+ return GRN_FALSE;
+ }
+
+ drilldown_tsort_init(ctx, statuses, n_statuses);
+ succeeded = drilldown_tsort_body(ctx, drilldowns, statuses, ids);
+ GRN_PLUGIN_FREE(ctx, statuses);
+ return succeeded;
+}
+
+static grn_bool
+grn_select_drilldowns_execute(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ grn_bool succeeded = GRN_TRUE;
+ grn_obj tsorted_ids;
+ size_t i;
+ size_t n_drilldowns;
+
+ GRN_RECORD_INIT(&tsorted_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ if (!drilldown_tsort(ctx, data->drilldowns, &tsorted_ids)) {
+ succeeded = GRN_FALSE;
+ goto exit;
+ }
+
+ n_drilldowns = GRN_BULK_VSIZE(&tsorted_ids) / sizeof(grn_id);
+ for (i = 0; i < n_drilldowns; i++) {
+ grn_id id;
+
+ id = GRN_RECORD_VALUE_AT(&tsorted_ids, i);
+ if (!grn_select_drilldown_execute(ctx,
+ data,
+ data->tables.result,
+ data->drilldowns,
+ id)) {
+ if (ctx->rc != GRN_SUCCESS) {
+ succeeded = GRN_FALSE;
+ break;
+ }
+ }
+ }
+
+exit :
+ GRN_OBJ_FIN(ctx, &tsorted_ids);
+
+ return succeeded;
+}
+
+static grn_drilldown_data *
+grn_select_data_drilldowns_add(grn_ctx *ctx,
+ grn_select_data *data,
+ const char *label,
+ size_t label_len)
+{
+ grn_drilldown_data *drilldown = NULL;
+ int added;
+
+ if (!data->drilldowns) {
+ data->drilldowns = grn_hash_create(ctx,
+ NULL,
+ GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_drilldown_data),
+ GRN_OBJ_TABLE_HASH_KEY |
+ GRN_OBJ_KEY_VAR_SIZE |
+ GRN_HASH_TINY);
+ if (!data->drilldowns) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][drilldowns] "
+ "failed to allocate drilldowns data: %s",
+ ctx->errbuf);
+ return NULL;
+ }
+ }
+
+ grn_hash_add(ctx,
+ data->drilldowns,
+ label,
+ label_len,
+ (void **)&drilldown,
+ &added);
+ if (added) {
+ grn_drilldown_data_init(ctx, drilldown, label, label_len);
+ }
+
+ return drilldown;
+}
+
+static grn_bool
+grn_select_prepare_drilldowns(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ if (data->drilldown.keys.length > 0) {
+ data->drilldown.parsed_keys =
+ grn_table_sort_key_from_str(ctx,
+ data->drilldown.keys.value,
+ data->drilldown.keys.length,
+ data->tables.result,
+ &(data->drilldown.n_parsed_keys));
+ if (data->drilldown.parsed_keys) {
+ int i;
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ for (i = 0; i < data->drilldown.n_parsed_keys; i++) {
+ grn_drilldown_data *drilldown;
+
+ GRN_BULK_REWIND(&buffer);
+ grn_text_printf(ctx, &buffer, "drilldown%d", i);
+ drilldown = grn_select_data_drilldowns_add(ctx,
+ data,
+ GRN_TEXT_VALUE(&buffer),
+ GRN_TEXT_LEN(&buffer));
+ if (!drilldown) {
+ continue;
+ }
+
+ drilldown->parsed_keys = data->drilldown.parsed_keys + i;
+ drilldown->n_parsed_keys = 1;
+
+#define COPY(field) \
+ drilldown->field = data->drilldown.field
+
+ COPY(sort_keys);
+ COPY(output_columns);
+ COPY(offset);
+ COPY(limit);
+ COPY(calc_types);
+ COPY(calc_target_name);
+ COPY(filter);
+
+#undef COPY
+ }
+ }
+ }
+
+ if (!data->drilldowns) {
+ return GRN_TRUE;
+ }
+
+ if (!grn_select_drilldowns_execute(ctx, data)) {
+ return GRN_FALSE;
+ }
+
+ {
+ unsigned int n_available_results = 0;
+
+ GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_table_group_result *result;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+ result = &(drilldown->result);
+ if (result->table) {
+ n_available_results++;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ if (data->drilldown.keys.length > 0) {
+ data->output.n_elements += n_available_results;
+ } else {
+ if (n_available_results > 0) {
+ data->output.n_elements += 1;
+ }
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_output_drilldowns(grn_ctx *ctx,
+ grn_select_data *data)
+{
+ grn_bool succeeded = GRN_TRUE;
+ unsigned int n_available_results = 0;
+ grn_bool is_labeled;
+
+ if (!data->drilldowns) {
+ return GRN_TRUE;
+ }
+
+ data->output.formatter->drilldowns_label(ctx, data);
+
+ GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_table_group_result *result;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+ result = &(drilldown->result);
+ if (result->table) {
+ n_available_results++;
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ is_labeled = (data->drilldown.keys.length == 0);
+
+ data->output.formatter->drilldowns_open(ctx, data, n_available_results);
+
+ GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_table_group_result *result;
+ grn_obj *target_table;
+ uint32_t n_hits;
+ int offset;
+ int limit;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+ result = &(drilldown->result);
+
+ if (!result->table) {
+ continue;
+ }
+
+ if (drilldown->filtered_result) {
+ target_table = drilldown->filtered_result;
+ } else {
+ target_table = result->table;
+ }
+
+ n_hits = grn_table_size(ctx, target_table);
+
+ offset = drilldown->offset;
+ limit = drilldown->limit;
+ grn_normalize_offset_and_limit(ctx, n_hits, &offset, &limit);
+
+ if (drilldown->sort_keys.length > 0) {
+ grn_table_sort_key *sort_keys;
+ uint32_t n_sort_keys;
+ sort_keys = grn_table_sort_key_from_str(ctx,
+ drilldown->sort_keys.value,
+ drilldown->sort_keys.length,
+ target_table, &n_sort_keys);
+ if (sort_keys) {
+ grn_obj *sorted;
+ sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY,
+ NULL, target_table);
+ if (sorted) {
+ grn_table_sort(ctx, target_table, offset, limit,
+ sorted, sort_keys, n_sort_keys);
+ data->output.formatter->drilldown_label(ctx, data, drilldown);
+ if (!grn_proc_select_output_columns(ctx,
+ sorted,
+ n_hits,
+ 0,
+ limit,
+ drilldown->output_columns.value,
+ drilldown->output_columns.length,
+ data->filter.condition.expression)) {
+ succeeded = GRN_FALSE;
+ }
+ grn_obj_unlink(ctx, sorted);
+ }
+ grn_table_sort_key_close(ctx, sort_keys, n_sort_keys);
+ } else {
+ succeeded = GRN_FALSE;
+ }
+ } else {
+ data->output.formatter->drilldown_label(ctx, data, drilldown);
+ if (!grn_proc_select_output_columns(ctx,
+ target_table,
+ n_hits,
+ offset,
+ limit,
+ drilldown->output_columns.value,
+ drilldown->output_columns.length,
+ data->filter.condition.expression)) {
+ succeeded = GRN_FALSE;
+ }
+ }
+
+ if (!succeeded) {
+ break;
+ }
+
+ if (is_labeled) {
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "output.drilldowns[%.*s](%d)",
+ (int)(drilldown->label.length),
+ drilldown->label.value,
+ n_hits);
+ } else {
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "output.drilldown(%d)", n_hits);
+ }
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ data->output.formatter->drilldowns_close(ctx, data);
+
+ return succeeded;
+}
+
+static grn_bool
+grn_select_output(grn_ctx *ctx, grn_select_data *data)
+{
+ grn_bool succeeded = GRN_TRUE;
+
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ GRN_OUTPUT_ARRAY_OPEN("RESULT", data->output.n_elements);
+ succeeded = grn_select_output_match(ctx, data);
+ if (succeeded) {
+ succeeded = grn_select_output_slices(ctx, data);
+ }
+ if (succeeded) {
+ succeeded = grn_select_output_drilldowns(ctx, data);
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ } else {
+ grn_obj_format format;
+ uint32_t n_additional_elements = 0;
+
+ if (data->slices) {
+ n_additional_elements++;
+ }
+ if (data->drilldowns) {
+ n_additional_elements++;
+ }
+
+ succeeded = grn_select_output_match_open(ctx,
+ data,
+ &format,
+ n_additional_elements);
+ if (succeeded) {
+ succeeded = grn_select_output_slices(ctx, data);
+ if (succeeded) {
+ succeeded = grn_select_output_drilldowns(ctx, data);
+ }
+ if (!grn_select_output_match_close(ctx, data, &format)) {
+ succeeded = GRN_FALSE;
+ }
+ }
+ }
+
+ return succeeded;
+}
+
+static void
+grn_select_output_slices_label_v1(grn_ctx *ctx, grn_select_data *data)
+{
+}
+
+static void
+grn_select_output_slices_open_v1(grn_ctx *ctx,
+ grn_select_data *data,
+ unsigned int n_result_sets)
+{
+ GRN_OUTPUT_MAP_OPEN("SLICES", n_result_sets);
+}
+
+static void
+grn_select_output_slices_close_v1(grn_ctx *ctx, grn_select_data *data)
+{
+ GRN_OUTPUT_MAP_CLOSE();
+}
+
+static void
+grn_select_output_slice_label_v1(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_slice_data *slice)
+{
+ GRN_OUTPUT_STR(slice->label.value, slice->label.length);
+}
+
+static void
+grn_select_output_drilldowns_label_v1(grn_ctx *ctx, grn_select_data *data)
+{
+}
+
+static void
+grn_select_output_drilldowns_open_v1(grn_ctx *ctx,
+ grn_select_data *data,
+ unsigned int n_result_sets)
+{
+ if (data->drilldown.keys.length == 0) {
+ GRN_OUTPUT_MAP_OPEN("DRILLDOWNS", n_result_sets);
+ }
+}
+
+static void
+grn_select_output_drilldowns_close_v1(grn_ctx *ctx, grn_select_data *data)
+{
+ if (data->drilldown.keys.length == 0) {
+ GRN_OUTPUT_MAP_CLOSE();
+ }
+}
+
+static void
+grn_select_output_drilldown_label_v1(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_drilldown_data *drilldown)
+{
+ if (data->drilldown.keys.length == 0) {
+ GRN_OUTPUT_STR(drilldown->label.value, drilldown->label.length);
+ }
+}
+
+static grn_select_output_formatter grn_select_output_formatter_v1 = {
+ grn_select_output_slices_label_v1,
+ grn_select_output_slices_open_v1,
+ grn_select_output_slices_close_v1,
+ grn_select_output_slice_label_v1,
+ grn_select_output_drilldowns_label_v1,
+ grn_select_output_drilldowns_open_v1,
+ grn_select_output_drilldowns_close_v1,
+ grn_select_output_drilldown_label_v1
+};
+
+static void
+grn_select_output_slices_label_v3(grn_ctx *ctx, grn_select_data *data)
+{
+ GRN_OUTPUT_CSTR("slices");
+}
+
+static void
+grn_select_output_slices_open_v3(grn_ctx *ctx,
+ grn_select_data *data,
+ unsigned int n_result_sets)
+{
+ GRN_OUTPUT_MAP_OPEN("slices", n_result_sets);
+}
+
+static void
+grn_select_output_slices_close_v3(grn_ctx *ctx, grn_select_data *data)
+{
+ GRN_OUTPUT_MAP_CLOSE();
+}
+
+static void
+grn_select_output_slice_label_v3(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_slice_data *slice)
+{
+ GRN_OUTPUT_STR(slice->label.value, slice->label.length);
+}
+
+static void
+grn_select_output_drilldowns_label_v3(grn_ctx *ctx, grn_select_data *data)
+{
+ GRN_OUTPUT_CSTR("drilldowns");
+}
+
+static void
+grn_select_output_drilldowns_open_v3(grn_ctx *ctx,
+ grn_select_data *data,
+ unsigned int n_result_sets)
+{
+ GRN_OUTPUT_MAP_OPEN("drilldowns", n_result_sets);
+}
+
+static void
+grn_select_output_drilldowns_close_v3(grn_ctx *ctx, grn_select_data *data)
+{
+ GRN_OUTPUT_MAP_CLOSE();
+}
+
+static void
+grn_select_output_drilldown_label_v3(grn_ctx *ctx,
+ grn_select_data *data,
+ grn_drilldown_data *drilldown)
+{
+ if (data->drilldown.keys.length == 0) {
+ GRN_OUTPUT_STR(drilldown->label.value, drilldown->label.length);
+ } else {
+ grn_obj *key;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_len;
+
+ key = drilldown->parsed_keys[0].key;
+ switch (key->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_INDEX :
+ name_len = grn_column_name(ctx, key, name, GRN_TABLE_MAX_KEY_SIZE);
+ break;
+ default :
+ name_len = grn_obj_name(ctx, key, name, GRN_TABLE_MAX_KEY_SIZE);
+ break;
+ }
+ GRN_OUTPUT_STR(name, name_len);
+ }
+}
+
+static grn_select_output_formatter grn_select_output_formatter_v3 = {
+ grn_select_output_slices_label_v3,
+ grn_select_output_slices_open_v3,
+ grn_select_output_slices_close_v3,
+ grn_select_output_slice_label_v3,
+ grn_select_output_drilldowns_label_v3,
+ grn_select_output_drilldowns_open_v3,
+ grn_select_output_drilldowns_close_v3,
+ grn_select_output_drilldown_label_v3
+};
+
+static grn_rc
+grn_select(grn_ctx *ctx, grn_select_data *data)
+{
+ uint32_t nhits;
+ grn_obj *outbuf = ctx->impl->output.buf;
+ grn_content_type output_type = ctx->impl->output.type;
+ char cache_key[GRN_CACHE_MAX_KEY_SIZE];
+ uint32_t cache_key_size;
+ long long int threshold, original_threshold = 0;
+ grn_cache *cache_obj = grn_cache_current_get(ctx);
+
+ if (grn_ctx_get_command_version(ctx) < GRN_COMMAND_VERSION_3) {
+ data->output.formatter = &grn_select_output_formatter_v1;
+ } else {
+ data->output.formatter = &grn_select_output_formatter_v3;
+ }
+
+ data->cacheable = 1;
+ data->taintable = 0;
+
+ data->output.n_elements = 0;
+
+ grn_raw_string_lstrip(ctx, &(data->filter.query));
+
+ cache_key_size =
+ data->table.length + 1 +
+ data->filter.match_columns.length + 1 +
+ data->filter.query.length + 1 +
+ data->filter.filter.length + 1 +
+ data->scorer.length + 1 +
+ data->sort_keys.length + 1 +
+ data->output_columns.length + 1 +
+ data->match_escalation_threshold.length + 1 +
+ data->filter.query_expander.length + 1 +
+ data->filter.query_flags.length + 1 +
+ data->adjuster.length + 1 +
+ sizeof(grn_content_type) +
+ sizeof(int) * 2 +
+ sizeof(grn_command_version) +
+ sizeof(grn_bool);
+ if (data->slices) {
+ GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
+ grn_slice_data *slice;
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+ grn_raw_string_lstrip(ctx, &(slice->filter.query));
+ cache_key_size +=
+ slice->filter.match_columns.length + 1 +
+ slice->filter.query.length + 1 +
+ slice->filter.query_expander.length + 1 +
+ slice->filter.query_flags.length + 1 +
+ slice->filter.filter.length + 1 +
+ slice->sort_keys.length + 1 +
+ slice->output_columns.length + 1 +
+ slice->label.length + 1 +
+ sizeof(int) * 2;
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+#define DRILLDOWN_CACHE_SIZE(drilldown) \
+ drilldown->keys.length + 1 + \
+ drilldown->sort_keys.length + 1 + \
+ drilldown->output_columns.length + 1 + \
+ drilldown->label.length + 1 + \
+ drilldown->calc_target_name.length + 1 + \
+ drilldown->filter.length + 1 + \
+ drilldown->table_name.length + 1 + \
+ sizeof(int) * 2 + \
+ sizeof(grn_table_group_flags)
+ if (data->drilldown.keys.length > 0) {
+ grn_drilldown_data *drilldown = &(data->drilldown);
+ cache_key_size += DRILLDOWN_CACHE_SIZE(drilldown);
+ }
+ if (data->drilldowns) {
+ GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+ cache_key_size += DRILLDOWN_CACHE_SIZE(drilldown);
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+#undef DRILLDOWN_CACHE_SIZE
+ if (cache_key_size <= GRN_CACHE_MAX_KEY_SIZE) {
+ char *cp = cache_key;
+
+#define PUT_CACHE_KEY(string) \
+ if ((string).value) \
+ grn_memcpy(cp, (string).value, (string).length); \
+ cp += (string).length; \
+ *cp++ = '\0'
+
+ PUT_CACHE_KEY(data->table);
+ PUT_CACHE_KEY(data->filter.match_columns);
+ PUT_CACHE_KEY(data->filter.query);
+ PUT_CACHE_KEY(data->filter.filter);
+ PUT_CACHE_KEY(data->scorer);
+ PUT_CACHE_KEY(data->sort_keys);
+ PUT_CACHE_KEY(data->output_columns);
+ if (data->slices) {
+ GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
+ grn_slice_data *slice;
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+ PUT_CACHE_KEY(slice->filter.match_columns);
+ PUT_CACHE_KEY(slice->filter.query);
+ PUT_CACHE_KEY(slice->filter.query_expander);
+ PUT_CACHE_KEY(slice->filter.query_flags);
+ PUT_CACHE_KEY(slice->filter.filter);
+ PUT_CACHE_KEY(slice->sort_keys);
+ PUT_CACHE_KEY(slice->output_columns);
+ PUT_CACHE_KEY(slice->label);
+ grn_memcpy(cp, &(slice->offset), sizeof(int));
+ cp += sizeof(int);
+ grn_memcpy(cp, &(slice->limit), sizeof(int));
+ cp += sizeof(int);
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+#define PUT_CACHE_KEY_DRILLDOWN(drilldown) do { \
+ PUT_CACHE_KEY(drilldown->keys); \
+ PUT_CACHE_KEY(drilldown->sort_keys); \
+ PUT_CACHE_KEY(drilldown->output_columns); \
+ PUT_CACHE_KEY(drilldown->label); \
+ PUT_CACHE_KEY(drilldown->calc_target_name); \
+ PUT_CACHE_KEY(drilldown->filter); \
+ PUT_CACHE_KEY(drilldown->table_name); \
+ grn_memcpy(cp, &(drilldown->offset), sizeof(int)); \
+ cp += sizeof(int); \
+ grn_memcpy(cp, &(drilldown->limit), sizeof(int)); \
+ cp += sizeof(int); \
+ grn_memcpy(cp, \
+ &(drilldown->calc_types), \
+ sizeof(grn_table_group_flags)); \
+ cp += sizeof(grn_table_group_flags); \
+ } while (GRN_FALSE)
+ if (data->drilldown.keys.length > 0) {
+ grn_drilldown_data *drilldown = &(data->drilldown);
+ PUT_CACHE_KEY_DRILLDOWN(drilldown);
+ }
+ if (data->drilldowns) {
+ GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+ PUT_CACHE_KEY_DRILLDOWN(drilldown);
+ } GRN_HASH_EACH_END(ctx, cursor);
+ }
+#undef PUT_CACHE_KEY_DRILLDOWN
+ PUT_CACHE_KEY(data->match_escalation_threshold);
+ PUT_CACHE_KEY(data->filter.query_expander);
+ PUT_CACHE_KEY(data->filter.query_flags);
+ PUT_CACHE_KEY(data->adjuster);
+ grn_memcpy(cp, &output_type, sizeof(grn_content_type));
+ cp += sizeof(grn_content_type);
+ grn_memcpy(cp, &(data->offset), sizeof(int));
+ cp += sizeof(int);
+ grn_memcpy(cp, &(data->limit), sizeof(int));
+ cp += sizeof(int);
+ grn_memcpy(cp, &(ctx->impl->command.version), sizeof(grn_command_version));
+ cp += sizeof(grn_command_version);
+ grn_memcpy(cp, &(ctx->impl->output.is_pretty), sizeof(grn_bool));
+ cp += sizeof(grn_bool);
+#undef PUT_CACHE_KEY
+
+ {
+ grn_rc rc;
+ rc = grn_cache_fetch(ctx, cache_obj, cache_key, cache_key_size, outbuf);
+ if (rc == GRN_SUCCESS) {
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_CACHE,
+ ":", "cache(%" GRN_FMT_LLD ")",
+ (long long int)GRN_TEXT_LEN(outbuf));
+ return ctx->rc;
+ }
+ }
+ }
+ if (data->match_escalation_threshold.length) {
+ const char *end, *rest;
+ original_threshold = grn_ctx_get_match_escalation_threshold(ctx);
+ end =
+ data->match_escalation_threshold.value +
+ data->match_escalation_threshold.length;
+ threshold = grn_atoll(data->match_escalation_threshold.value, end, &rest);
+ if (end == rest) {
+ grn_ctx_set_match_escalation_threshold(ctx, threshold);
+ }
+ }
+
+ data->tables.target = grn_ctx_get(ctx, data->table.value, data->table.length);
+ if (!data->tables.target) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][table] invalid name: <%.*s>",
+ (int)(data->table.length),
+ data->table.value);
+ goto exit;
+ }
+
+ {
+ if (data->filter.filter.length > 0 &&
+ (data->filter.filter.value[0] == '?') &&
+ (ctx->impl->output.type == GRN_CONTENT_JSON)) {
+ ctx->rc = grn_ts_select(ctx, data->tables.target,
+ data->filter.filter.value + 1,
+ data->filter.filter.length - 1,
+ data->scorer.value,
+ data->scorer.length,
+ data->sort_keys.value,
+ data->sort_keys.length,
+ data->output_columns.value,
+ data->output_columns.length,
+ data->offset,
+ data->limit);
+ if (!ctx->rc &&
+ data->cacheable > 0 &&
+ cache_key_size <= GRN_CACHE_MAX_KEY_SIZE &&
+ (!data->cache.value ||
+ data->cache.length != 2 ||
+ data->cache.value[0] != 'n' ||
+ data->cache.value[1] != 'o')) {
+ grn_cache_update(ctx, cache_obj, cache_key, cache_key_size, outbuf);
+ }
+ goto exit;
+ }
+
+ data->tables.initial = data->tables.target;
+ if (!grn_select_apply_initial_columns(ctx, data)) {
+ goto exit;
+ }
+
+ if (!grn_select_filter(ctx, data)) {
+ goto exit;
+ }
+
+ nhits = grn_table_size(ctx, data->tables.result);
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "select(%d)", nhits);
+
+ if (!grn_select_apply_filtered_columns(ctx, data)) {
+ goto exit;
+ }
+
+ {
+ grn_bool succeeded;
+
+ /* For select results */
+ data->output.n_elements = 1;
+
+ if (!grn_select_apply_adjuster(ctx, data)) {
+ goto exit;
+ }
+
+ if (!grn_select_apply_scorer(ctx, data)) {
+ goto exit;
+ }
+
+ grn_normalize_offset_and_limit(ctx, nhits,
+ &(data->offset), &(data->limit));
+
+ if (!grn_select_sort(ctx, data)) {
+ goto exit;
+ }
+
+ if (!grn_select_apply_output_columns(ctx, data)) {
+ goto exit;
+ }
+
+ if (!grn_select_prepare_slices(ctx, data)) {
+ goto exit;
+ }
+
+ if (!grn_select_prepare_drilldowns(ctx, data)) {
+ goto exit;
+ }
+
+ succeeded = grn_select_output(ctx, data);
+ if (!succeeded) {
+ goto exit;
+ }
+ }
+ if (!ctx->rc &&
+ data->cacheable &&
+ cache_key_size <= GRN_CACHE_MAX_KEY_SIZE &&
+ (!data->cache.value ||
+ data->cache.length != 2 ||
+ data->cache.value[0] != 'n' ||
+ data->cache.value[1] != 'o')) {
+ grn_cache_update(ctx, cache_obj, cache_key, cache_key_size, outbuf);
+ }
+ if (data->taintable > 0) {
+ grn_db_touch(ctx, DB_OBJ(data->tables.target)->db);
+ }
+ }
+
+exit :
+ if (data->match_escalation_threshold.length > 0) {
+ grn_ctx_set_match_escalation_threshold(ctx, original_threshold);
+ }
+
+ /* GRN_LOG(ctx, GRN_LOG_NONE, "%d", ctx->seqno); */
+
+ return ctx->rc;
+}
+
+static grn_slice_data *
+grn_select_data_slices_add(grn_ctx *ctx,
+ grn_select_data *data,
+ const char *label,
+ size_t label_len)
+{
+ grn_slice_data *slice = NULL;
+ int added;
+
+ if (!data->slices) {
+ data->slices = grn_hash_create(ctx,
+ NULL,
+ GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_slice_data),
+ GRN_OBJ_TABLE_HASH_KEY |
+ GRN_OBJ_KEY_VAR_SIZE |
+ GRN_HASH_TINY);
+ if (!data->slices) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[select][slices] "
+ "failed to allocate slices data: %s",
+ ctx->errbuf);
+ return NULL;
+ }
+ }
+
+ grn_hash_add(ctx,
+ data->slices,
+ label,
+ label_len,
+ (void **)&slice,
+ &added);
+ if (added) {
+ grn_slice_data_init(ctx, slice, label, label_len);
+ }
+
+ return slice;
+}
+
+static grn_bool
+grn_select_data_fill_slice_labels(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_select_data *data)
+{
+ grn_obj *vars;
+ grn_table_cursor *cursor;
+ const char *prefix = "slices[";
+ int prefix_len;
+
+ vars = grn_plugin_proc_get_vars(ctx, user_data);
+
+ cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+
+ prefix_len = strlen(prefix);
+ while (grn_table_cursor_next(ctx, cursor)) {
+ void *key;
+ char *name;
+ int name_len;
+ name_len = grn_table_cursor_get_key(ctx, cursor, &key);
+ name = key;
+ if (name_len > prefix_len + 1 &&
+ strncmp(prefix, name, prefix_len) == 0) {
+ const char *label_end;
+ size_t label_len;
+ label_end = memchr(name + prefix_len + 1,
+ ']',
+ name_len - prefix_len - 1);
+ if (!label_end) {
+ continue;
+ }
+ label_len = (label_end - name) - prefix_len;
+ grn_select_data_slices_add(ctx,
+ data,
+ name + prefix_len,
+ label_len);
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_data_fill_slices(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_select_data *data)
+{
+ if (!grn_select_data_fill_slice_labels(ctx, user_data, data)) {
+ return GRN_FALSE;
+ }
+
+ GRN_HASH_EACH_BEGIN(ctx, data->slices, cursor, id) {
+ grn_slice_data *slice;
+ char slice_label[GRN_TABLE_MAX_KEY_SIZE];
+ char key_name[GRN_TABLE_MAX_KEY_SIZE];
+ grn_obj *match_columns;
+ grn_obj *query;
+ grn_obj *query_expander;
+ grn_obj *query_flags;
+ grn_obj *filter;
+ grn_obj *sort_keys;
+ grn_obj *output_columns;
+ grn_obj *offset;
+ grn_obj *limit;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+
+ grn_snprintf(slice_label,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "slices[%.*s].",
+ (int)(slice->label.length),
+ slice->label.value);
+
+#define GET_VAR(name) \
+ grn_snprintf(key_name, \
+ GRN_TABLE_MAX_KEY_SIZE, \
+ GRN_TABLE_MAX_KEY_SIZE, \
+ "%s%s", slice_label, #name); \
+ name = grn_plugin_proc_get_var(ctx, user_data, key_name, -1);
+
+ GET_VAR(match_columns);
+ GET_VAR(query);
+ GET_VAR(query_expander);
+ GET_VAR(query_flags);
+ GET_VAR(filter);
+ GET_VAR(sort_keys);
+ GET_VAR(output_columns);
+ GET_VAR(offset);
+ GET_VAR(limit);
+
+#undef GET_VAR
+
+ grn_slice_data_fill(ctx,
+ slice,
+ match_columns,
+ query,
+ query_expander,
+ query_flags,
+ filter,
+ sort_keys,
+ output_columns,
+ offset,
+ limit);
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_data_fill_drilldown_labels(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_select_data *data,
+ const char *prefix)
+{
+ grn_obj *vars;
+ grn_table_cursor *cursor;
+ int prefix_len;
+
+ vars = grn_plugin_proc_get_vars(ctx, user_data);
+
+ cursor = grn_table_cursor_open(ctx, vars, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+
+ prefix_len = strlen(prefix);
+ while (grn_table_cursor_next(ctx, cursor)) {
+ void *key;
+ char *name;
+ int name_len;
+ name_len = grn_table_cursor_get_key(ctx, cursor, &key);
+ name = key;
+ if (name_len > prefix_len + 1 &&
+ strncmp(prefix, name, prefix_len) == 0) {
+ const char *label_end;
+ size_t label_len;
+ label_end = memchr(name + prefix_len + 1,
+ ']',
+ name_len - prefix_len - 1);
+ if (!label_end) {
+ continue;
+ }
+ label_len = (label_end - name) - prefix_len;
+ grn_select_data_drilldowns_add(ctx,
+ data,
+ name + prefix_len,
+ label_len);
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+grn_select_data_fill_drilldown_columns(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_drilldown_data *drilldown,
+ const char *parameter_key)
+{
+ char prefix[GRN_TABLE_MAX_KEY_SIZE];
+
+ grn_snprintf(prefix,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "%s[%.*s].",
+ parameter_key,
+ (int)(drilldown->label.length),
+ drilldown->label.value);
+ return grn_columns_fill(ctx,
+ user_data,
+ &(drilldown->columns),
+ prefix,
+ strlen(prefix));
+}
+
+static grn_bool
+grn_select_data_fill_drilldowns(grn_ctx *ctx,
+ grn_user_data *user_data,
+ grn_select_data *data)
+{
+ grn_obj *drilldown;
+
+ drilldown = grn_plugin_proc_get_var(ctx, user_data, "drilldown", -1);
+ if (GRN_TEXT_LEN(drilldown) > 0) {
+ grn_obj *sort_keys;
+
+ sort_keys = grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_sort_keys", -1);
+ if (GRN_TEXT_LEN(sort_keys) == 0) {
+ /* For backward compatibility */
+ sort_keys = grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_sortby", -1);
+ }
+ grn_drilldown_data_fill(ctx,
+ &(data->drilldown),
+ drilldown,
+ sort_keys,
+ grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_output_columns",
+ -1),
+ grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_offset", -1),
+ grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_limit", -1),
+ grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_calc_types", -1),
+ grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_calc_target", -1),
+ grn_plugin_proc_get_var(ctx, user_data,
+ "drilldown_filter", -1),
+ NULL);
+ return GRN_TRUE;
+ } else {
+ grn_bool succeeded = GRN_TRUE;
+
+ if (!grn_select_data_fill_drilldown_labels(ctx, user_data, data,
+ "drilldowns[")) {
+ return GRN_FALSE;
+ }
+
+ /* For backward compatibility */
+ if (!grn_select_data_fill_drilldown_labels(ctx, user_data, data,
+ "drilldown[")) {
+ return GRN_FALSE;
+ }
+
+ GRN_HASH_EACH_BEGIN(ctx, data->drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_obj *keys = NULL;
+ grn_obj *sort_keys = NULL;
+ grn_obj *output_columns = NULL;
+ grn_obj *offset = NULL;
+ grn_obj *limit = NULL;
+ grn_obj *calc_types = NULL;
+ grn_obj *calc_target = NULL;
+ grn_obj *filter = NULL;
+ grn_obj *table = NULL;
+
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+
+ succeeded = grn_select_data_fill_drilldown_columns(ctx,
+ user_data,
+ drilldown,
+ "drilldowns");
+ if (!succeeded) {
+ break;
+ }
+
+ /* For backward compatibility */
+ succeeded = grn_select_data_fill_drilldown_columns(ctx,
+ user_data,
+ drilldown,
+ "drilldown");
+ if (!succeeded) {
+ break;
+ }
+
+#define GET_VAR_RAW(parameter_key, name) do { \
+ if (!name) { \
+ char key_name[GRN_TABLE_MAX_KEY_SIZE]; \
+ grn_snprintf(key_name, \
+ GRN_TABLE_MAX_KEY_SIZE, \
+ GRN_TABLE_MAX_KEY_SIZE, \
+ "%s[%.*s].%s", \
+ (parameter_key), \
+ (int)(drilldown->label.length), \
+ drilldown->label.value, \
+ #name); \
+ name = grn_plugin_proc_get_var(ctx, user_data, key_name, -1); \
+ } \
+ } while (GRN_FALSE)
+
+#define GET_VAR(name) do { \
+ GET_VAR_RAW("drilldowns", name); \
+ /* For backward compatibility */ \
+ GET_VAR_RAW("drilldown", name); \
+ } while (GRN_FALSE)
+
+ GET_VAR(keys);
+ GET_VAR(sort_keys);
+ if (!sort_keys) {
+ grn_obj *sortby = NULL;
+ GET_VAR(sortby);
+ sort_keys = sortby;
+ }
+ GET_VAR(output_columns);
+ GET_VAR(offset);
+ GET_VAR(limit);
+ GET_VAR(calc_types);
+ GET_VAR(calc_target);
+ GET_VAR(filter);
+ GET_VAR(table);
+
+#undef GET_VAR
+
+#undef GET_VAR_RAW
+
+ grn_drilldown_data_fill(ctx,
+ drilldown,
+ keys,
+ sort_keys,
+ output_columns,
+ offset,
+ limit,
+ calc_types,
+ calc_target,
+ filter,
+ table);
+ } GRN_HASH_EACH_END(ctx, cursor);
+
+ return succeeded;
+ }
+}
+
+static grn_obj *
+command_select(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_select_data data;
+
+ grn_columns_init(ctx, &(data.columns));
+ grn_filter_data_init(ctx, &(data.filter));
+
+ data.tables.target = NULL;
+ data.tables.initial = NULL;
+ data.tables.result = NULL;
+ data.tables.sorted = NULL;
+
+ data.slices = NULL;
+ grn_drilldown_data_init(ctx, &(data.drilldown), NULL, 0);
+ data.drilldowns = NULL;
+
+ data.table.value = grn_plugin_proc_get_var_string(ctx, user_data,
+ "table", -1,
+ &(data.table.length));
+#define GET_VAR(name) \
+ grn_plugin_proc_get_var(ctx, user_data, name, strlen(name))
+
+ {
+ grn_obj *query_expander;
+
+ query_expander = GET_VAR("query_expander");
+ if (GRN_TEXT_LEN(query_expander) == 0) {
+ query_expander = GET_VAR("query_expansion");
+ }
+
+ grn_filter_data_fill(ctx,
+ &(data.filter),
+ GET_VAR("match_columns"),
+ GET_VAR("query"),
+ query_expander,
+ GET_VAR("query_flags"),
+ GET_VAR("filter"));
+ }
+#undef GET_VAR
+
+ data.scorer.value =
+ grn_plugin_proc_get_var_string(ctx, user_data,
+ "scorer", -1,
+ &(data.scorer.length));
+ data.sort_keys.value =
+ grn_plugin_proc_get_var_string(ctx, user_data,
+ "sort_keys", -1,
+ &(data.sort_keys.length));
+ if (data.sort_keys.length == 0) {
+ /* For backward compatibility */
+ data.sort_keys.value =
+ grn_plugin_proc_get_var_string(ctx, user_data,
+ "sortby", -1,
+ &(data.sort_keys.length));
+ }
+ data.output_columns.value =
+ grn_plugin_proc_get_var_string(ctx, user_data,
+ "output_columns", -1,
+ &(data.output_columns.length));
+ if (!data.output_columns.value) {
+ data.output_columns.value = GRN_SELECT_DEFAULT_OUTPUT_COLUMNS;
+ data.output_columns.length = strlen(GRN_SELECT_DEFAULT_OUTPUT_COLUMNS);
+ }
+ data.offset = grn_plugin_proc_get_var_int32(ctx, user_data,
+ "offset", -1,
+ 0);
+ data.limit = grn_plugin_proc_get_var_int32(ctx, user_data,
+ "limit", -1,
+ GRN_SELECT_DEFAULT_LIMIT);
+
+ data.cache.value = grn_plugin_proc_get_var_string(ctx, user_data,
+ "cache", -1,
+ &(data.cache.length));
+ data.match_escalation_threshold.value =
+ grn_plugin_proc_get_var_string(ctx, user_data,
+ "match_escalation_threshold", -1,
+ &(data.match_escalation_threshold.length));
+
+ data.adjuster.value =
+ grn_plugin_proc_get_var_string(ctx, user_data,
+ "adjuster", -1,
+ &(data.adjuster.length));
+
+ if (!grn_select_data_fill_slices(ctx, user_data, &data)) {
+ goto exit;
+ }
+
+ if (!grn_select_data_fill_drilldowns(ctx, user_data, &data)) {
+ goto exit;
+ }
+
+ if (!grn_columns_fill(ctx, user_data, &(data.columns), NULL, 0)) {
+ goto exit;
+ }
+
+ grn_select(ctx, &data);
+
+exit :
+ if (data.drilldowns) {
+ GRN_HASH_EACH_BEGIN(ctx, data.drilldowns, cursor, id) {
+ grn_drilldown_data *drilldown;
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&drilldown);
+ grn_drilldown_data_fin(ctx, drilldown);
+ } GRN_HASH_EACH_END(ctx, cursor);
+ grn_hash_close(ctx, data.drilldowns);
+ }
+
+ if (data.drilldown.parsed_keys) {
+ grn_table_sort_key_close(ctx,
+ data.drilldown.parsed_keys,
+ data.drilldown.n_parsed_keys);
+ }
+ grn_drilldown_data_fin(ctx, &(data.drilldown));
+
+ if (data.slices) {
+ GRN_HASH_EACH_BEGIN(ctx, data.slices, cursor, id) {
+ grn_slice_data *slice;
+ grn_hash_cursor_get_value(ctx, cursor, (void **)&slice);
+ grn_slice_data_fin(ctx, slice);
+ } GRN_HASH_EACH_END(ctx, cursor);
+ grn_hash_close(ctx, data.slices);
+ }
+
+ if (data.tables.sorted) {
+ grn_obj_unlink(ctx, data.tables.sorted);
+ }
+
+ if (data.tables.result == data.filter.filtered) {
+ data.tables.result = NULL;
+ }
+ grn_filter_data_fin(ctx, &(data.filter));
+
+ if (data.tables.result &&
+ data.tables.result != data.tables.initial &&
+ data.tables.result != data.tables.target) {
+ grn_obj_unlink(ctx, data.tables.result);
+ }
+
+ if (data.tables.initial && data.tables.initial != data.tables.target) {
+ grn_obj_unlink(ctx, data.tables.initial);
+ }
+
+ if (data.tables.target) {
+ grn_obj_unlink(ctx, data.tables.target);
+ }
+
+ grn_columns_fin(ctx, &(data.columns));
+
+ return NULL;
+}
+
+#define N_VARS 26
+#define DEFINE_VARS grn_expr_var vars[N_VARS]
+
+static void
+init_vars(grn_ctx *ctx, grn_expr_var *vars)
+{
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "match_columns", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "query", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "filter", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[5]), "scorer", -1);
+ /* Deprecated since 6.0.3. Use sort_keys instead. */
+ grn_plugin_expr_var_init(ctx, &(vars[6]), "sortby", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[7]), "output_columns", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[8]), "offset", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[9]), "limit", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[10]), "drilldown", -1);
+ /* Deprecated since 6.0.3. Use drilldown_sort_keys instead. */
+ grn_plugin_expr_var_init(ctx, &(vars[11]), "drilldown_sortby", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[12]), "drilldown_output_columns", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[13]), "drilldown_offset", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[14]), "drilldown_limit", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[15]), "cache", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[16]), "match_escalation_threshold", -1);
+ /* Deprecated. Use query_expander instead. */
+ grn_plugin_expr_var_init(ctx, &(vars[17]), "query_expansion", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[18]), "query_flags", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[19]), "query_expander", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[20]), "adjuster", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[21]), "drilldown_calc_types", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[22]), "drilldown_calc_target", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[23]), "drilldown_filter", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[24]), "sort_keys", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[25]), "drilldown_sort_keys", -1);
+}
+
+void
+grn_proc_init_select(grn_ctx *ctx)
+{
+ DEFINE_VARS;
+
+ init_vars(ctx, vars);
+ grn_plugin_command_create(ctx,
+ "select", -1,
+ command_select,
+ N_VARS - 1,
+ vars + 1);
+}
+
+static grn_obj *
+command_define_selector(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ uint32_t i, nvars;
+ grn_expr_var *vars;
+
+ grn_proc_get_info(ctx, user_data, &vars, &nvars, NULL);
+ for (i = 1; i < nvars; i++) {
+ grn_obj *var;
+ var = grn_plugin_proc_get_var_by_offset(ctx, user_data, i);
+ GRN_TEXT_SET(ctx, &((vars + i)->value),
+ GRN_TEXT_VALUE(var),
+ GRN_TEXT_LEN(var));
+ }
+ {
+ grn_obj *name;
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ grn_plugin_command_create(ctx,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name),
+ command_select,
+ nvars - 1,
+ vars + 1);
+ }
+ GRN_OUTPUT_BOOL(!ctx->rc);
+
+ return NULL;
+}
+
+void
+grn_proc_init_define_selector(grn_ctx *ctx)
+{
+ DEFINE_VARS;
+
+ init_vars(ctx, vars);
+ grn_plugin_command_create(ctx,
+ "define_selector", -1,
+ command_define_selector,
+ N_VARS,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_snippet.c b/storage/mroonga/vendor/groonga/lib/proc/proc_snippet.c
new file mode 100644
index 00000000..0c6ea681
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_snippet.c
@@ -0,0 +1,319 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_expr.h"
+
+#include <groonga/plugin.h>
+#include <string.h>
+
+#define GRN_FUNC_SNIPPET_HTML_CACHE_NAME "$snippet_html"
+
+static grn_obj *
+snippet_exec(grn_ctx *ctx, grn_obj *snip, grn_obj *text,
+ grn_user_data *user_data,
+ const char *prefix, int prefix_length,
+ const char *suffix, int suffix_length)
+{
+ grn_rc rc;
+ unsigned int i, n_results, max_tagged_length;
+ grn_obj snippet_buffer;
+ grn_obj *snippets;
+
+ if (GRN_TEXT_LEN(text) == 0) {
+ return NULL;
+ }
+
+ rc = grn_snip_exec(ctx, snip,
+ GRN_TEXT_VALUE(text), GRN_TEXT_LEN(text),
+ &n_results, &max_tagged_length);
+ if (rc != GRN_SUCCESS) {
+ return NULL;
+ }
+
+ if (n_results == 0) {
+ return grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
+ }
+
+ snippets = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_SHORT_TEXT, GRN_OBJ_VECTOR);
+ if (!snippets) {
+ return NULL;
+ }
+
+ GRN_TEXT_INIT(&snippet_buffer, 0);
+ grn_bulk_space(ctx, &snippet_buffer,
+ prefix_length + max_tagged_length + suffix_length);
+ for (i = 0; i < n_results; i++) {
+ unsigned int snippet_length;
+
+ GRN_BULK_REWIND(&snippet_buffer);
+ if (prefix_length) {
+ GRN_TEXT_PUT(ctx, &snippet_buffer, prefix, prefix_length);
+ }
+ rc = grn_snip_get_result(ctx, snip, i,
+ GRN_TEXT_VALUE(&snippet_buffer) + prefix_length,
+ &snippet_length);
+ if (rc == GRN_SUCCESS) {
+ grn_strncat(GRN_TEXT_VALUE(&snippet_buffer),
+ GRN_BULK_WSIZE(&snippet_buffer),
+ suffix,
+ suffix_length);
+ grn_vector_add_element(ctx, snippets,
+ GRN_TEXT_VALUE(&snippet_buffer),
+ prefix_length + snippet_length + suffix_length,
+ 0, GRN_DB_SHORT_TEXT);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &snippet_buffer);
+
+ return snippets;
+}
+
+/* TODO: support caching for the same parameter. */
+static grn_obj *
+func_snippet(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *snippets = NULL;
+
+#define N_REQUIRED_ARGS 1
+#define KEYWORD_SET_SIZE 3
+ if (nargs > N_REQUIRED_ARGS) {
+ grn_obj *text = args[0];
+ grn_obj *end_arg = args[nargs - 1];
+ grn_obj *snip = NULL;
+ unsigned int width = 200;
+ unsigned int max_n_results = 3;
+ grn_snip_mapping *mapping = NULL;
+ int flags = GRN_SNIP_SKIP_LEADING_SPACES;
+ const char *prefix = NULL;
+ int prefix_length = 0;
+ const char *suffix = NULL;
+ int suffix_length = 0;
+ const char *normalizer_name = NULL;
+ int normalizer_name_length = 0;
+ const char *default_open_tag = NULL;
+ int default_open_tag_length = 0;
+ const char *default_close_tag = NULL;
+ int default_close_tag_length = 0;
+ int n_args_without_option = nargs;
+
+ if (end_arg->header.type == GRN_TABLE_HASH_KEY) {
+ grn_obj *options = end_arg;
+ grn_hash_cursor *cursor;
+ void *key;
+ int key_size;
+ grn_obj *value;
+
+ n_args_without_option--;
+ cursor = grn_hash_cursor_open(ctx, (grn_hash *)options,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (!cursor) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "snippet(): couldn't open cursor");
+ goto exit;
+ }
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ grn_hash_cursor_get_key_value(ctx, cursor,
+ &key, &key_size,
+ (void **)&value);
+ if (key_size == 5 && !memcmp(key, "width", 5)) {
+ width = GRN_UINT32_VALUE(value);
+ } else if (key_size == 13 && !memcmp(key, "max_n_results", 13)) {
+ max_n_results = GRN_UINT32_VALUE(value);
+ } else if (key_size == 19 && !memcmp(key, "skip_leading_spaces", 19)) {
+ if (GRN_BOOL_VALUE(value) == GRN_FALSE) {
+ flags &= ~GRN_SNIP_SKIP_LEADING_SPACES;
+ }
+ } else if (key_size == 11 && !memcmp(key, "html_escape", 11)) {
+ if (GRN_BOOL_VALUE(value)) {
+ mapping = GRN_SNIP_MAPPING_HTML_ESCAPE;
+ }
+ } else if (key_size == 6 && !memcmp(key, "prefix", 6)) {
+ prefix = GRN_TEXT_VALUE(value);
+ prefix_length = GRN_TEXT_LEN(value);
+ } else if (key_size == 6 && !memcmp(key, "suffix", 6)) {
+ suffix = GRN_TEXT_VALUE(value);
+ suffix_length = GRN_TEXT_LEN(value);
+ } else if (key_size == 10 && !memcmp(key, "normalizer", 10)) {
+ normalizer_name = GRN_TEXT_VALUE(value);
+ normalizer_name_length = GRN_TEXT_LEN(value);
+ } else if (key_size == 16 && !memcmp(key, "default_open_tag", 16)) {
+ default_open_tag = GRN_TEXT_VALUE(value);
+ default_open_tag_length = GRN_TEXT_LEN(value);
+ } else if (key_size == 17 && !memcmp(key, "default_close_tag", 17)) {
+ default_close_tag = GRN_TEXT_VALUE(value);
+ default_close_tag_length = GRN_TEXT_LEN(value);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "invalid option name: <%.*s>",
+ key_size, (char *)key);
+ grn_hash_cursor_close(ctx, cursor);
+ goto exit;
+ }
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+
+ snip = grn_snip_open(ctx, flags, width, max_n_results,
+ default_open_tag, default_open_tag_length,
+ default_close_tag, default_close_tag_length, mapping);
+ if (snip) {
+ grn_rc rc;
+ unsigned int i;
+ if (!normalizer_name) {
+ grn_snip_set_normalizer(ctx, snip, GRN_NORMALIZER_AUTO);
+ } else if (normalizer_name_length > 0) {
+ grn_obj *normalizer;
+ normalizer = grn_ctx_get(ctx, normalizer_name, normalizer_name_length);
+ if (!grn_obj_is_normalizer_proc(ctx, normalizer)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, normalizer);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "snippet(): not normalizer: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ grn_obj_unlink(ctx, normalizer);
+ goto exit;
+ }
+ grn_snip_set_normalizer(ctx, snip, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+ if (default_open_tag_length == 0 && default_close_tag_length == 0) {
+ unsigned int n_keyword_sets =
+ (n_args_without_option - N_REQUIRED_ARGS) / KEYWORD_SET_SIZE;
+ grn_obj **keyword_set_args = args + N_REQUIRED_ARGS;
+ for (i = 0; i < n_keyword_sets; i++) {
+ rc = grn_snip_add_cond(ctx, snip,
+ GRN_TEXT_VALUE(keyword_set_args[i * KEYWORD_SET_SIZE]),
+ GRN_TEXT_LEN(keyword_set_args[i * KEYWORD_SET_SIZE]),
+ GRN_TEXT_VALUE(keyword_set_args[i * KEYWORD_SET_SIZE + 1]),
+ GRN_TEXT_LEN(keyword_set_args[i * KEYWORD_SET_SIZE + 1]),
+ GRN_TEXT_VALUE(keyword_set_args[i * KEYWORD_SET_SIZE + 2]),
+ GRN_TEXT_LEN(keyword_set_args[i * KEYWORD_SET_SIZE + 2]));
+ }
+ } else {
+ unsigned int n_keywords = n_args_without_option - N_REQUIRED_ARGS;
+ grn_obj **keyword_args = args + N_REQUIRED_ARGS;
+ for (i = 0; i < n_keywords; i++) {
+ rc = grn_snip_add_cond(ctx, snip,
+ GRN_TEXT_VALUE(keyword_args[i]),
+ GRN_TEXT_LEN(keyword_args[i]),
+ NULL, 0,
+ NULL, 0);
+ }
+ }
+ snippets = snippet_exec(ctx, snip, text, user_data,
+ prefix, prefix_length,
+ suffix, suffix_length);
+ }
+ }
+#undef KEYWORD_SET_SIZE
+#undef N_REQUIRED_ARGS
+
+exit :
+ if (!snippets) {
+ snippets = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
+ }
+
+ return snippets;
+}
+
+void
+grn_proc_init_snippet(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "snippet", -1, GRN_PROC_FUNCTION,
+ func_snippet, NULL, NULL, 0, NULL);
+}
+
+static grn_obj *
+func_snippet_html(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *snippets = NULL;
+
+ /* TODO: support parameters */
+ if (nargs == 1) {
+ grn_obj *text = args[0];
+ grn_obj *expression = NULL;
+ grn_obj *condition_ptr = NULL;
+ grn_obj *condition = NULL;
+ grn_obj *snip = NULL;
+ int flags = GRN_SNIP_SKIP_LEADING_SPACES;
+ unsigned int width = 200;
+ unsigned int max_n_results = 3;
+ const char *open_tag = "<span class=\"keyword\">";
+ const char *close_tag = "</span>";
+ grn_snip_mapping *mapping = GRN_SNIP_MAPPING_HTML_ESCAPE;
+
+ grn_proc_get_info(ctx, user_data, NULL, NULL, &expression);
+ condition_ptr = grn_expr_get_var(ctx, expression,
+ GRN_SELECT_INTERNAL_VAR_CONDITION,
+ strlen(GRN_SELECT_INTERNAL_VAR_CONDITION));
+ if (condition_ptr) {
+ condition = GRN_PTR_VALUE(condition_ptr);
+ }
+
+ if (condition) {
+ grn_obj *snip_ptr;
+ snip_ptr = grn_expr_get_var(ctx, expression,
+ GRN_FUNC_SNIPPET_HTML_CACHE_NAME,
+ strlen(GRN_FUNC_SNIPPET_HTML_CACHE_NAME));
+ if (snip_ptr) {
+ snip = GRN_PTR_VALUE(snip_ptr);
+ } else {
+ snip_ptr =
+ grn_expr_get_or_add_var(ctx, expression,
+ GRN_FUNC_SNIPPET_HTML_CACHE_NAME,
+ strlen(GRN_FUNC_SNIPPET_HTML_CACHE_NAME));
+ GRN_OBJ_FIN(ctx, snip_ptr);
+ GRN_PTR_INIT(snip_ptr, GRN_OBJ_OWN, GRN_DB_OBJECT);
+
+ snip = grn_snip_open(ctx, flags, width, max_n_results,
+ open_tag, strlen(open_tag),
+ close_tag, strlen(close_tag),
+ mapping);
+ if (snip) {
+ grn_snip_set_normalizer(ctx, snip, GRN_NORMALIZER_AUTO);
+ grn_expr_snip_add_conditions(ctx, condition, snip,
+ 0, NULL, NULL, NULL, NULL);
+ GRN_PTR_SET(ctx, snip_ptr, snip);
+ }
+ }
+ }
+
+ if (snip) {
+ snippets = snippet_exec(ctx, snip, text, user_data, NULL, 0, NULL, 0);
+ }
+ }
+
+ if (!snippets) {
+ snippets = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_VOID, 0);
+ }
+
+ return snippets;
+}
+
+void
+grn_proc_init_snippet_html(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "snippet_html", -1, GRN_PROC_FUNCTION,
+ func_snippet_html, NULL, NULL, 0, NULL);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_table.c b/storage/mroonga/vendor/groonga/lib/proc/proc_table.c
new file mode 100644
index 00000000..3c40992d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_table.c
@@ -0,0 +1,910 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+
+#include "../grn_ctx.h"
+#include "../grn_str.h"
+#include "../grn_db.h"
+
+#include <groonga/plugin.h>
+
+static grn_table_flags
+command_table_create_parse_flags(grn_ctx *ctx,
+ const char *nptr,
+ const char *end)
+{
+ grn_table_flags flags = 0;
+ while (nptr < end) {
+ size_t name_size;
+
+ if (*nptr == '|' || *nptr == ' ') {
+ nptr += 1;
+ continue;
+ }
+
+#define CHECK_FLAG(name) \
+ name_size = strlen(#name); \
+ if ((unsigned long) (end - nptr) >= (unsigned long) name_size && \
+ memcmp(nptr, #name, name_size) == 0) { \
+ flags |= GRN_OBJ_ ## name; \
+ nptr += name_size; \
+ continue; \
+ }
+
+ CHECK_FLAG(TABLE_HASH_KEY);
+ CHECK_FLAG(TABLE_PAT_KEY);
+ CHECK_FLAG(TABLE_DAT_KEY);
+ CHECK_FLAG(TABLE_NO_KEY);
+ CHECK_FLAG(KEY_NORMALIZE);
+ CHECK_FLAG(KEY_WITH_SIS);
+ CHECK_FLAG(KEY_LARGE);
+
+#undef CHECK_FLAG
+
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create][flags] unknown flag: <%.*s>",
+ (int)(end - nptr), nptr);
+ return 0;
+ }
+ return flags;
+}
+
+static grn_bool
+grn_proc_table_set_token_filters_put(grn_ctx *ctx,
+ grn_obj *token_filters,
+ const char *token_filter_name,
+ int token_filter_name_length)
+{
+ grn_obj *token_filter;
+
+ token_filter = grn_ctx_get(ctx,
+ token_filter_name,
+ token_filter_name_length);
+ if (token_filter) {
+ GRN_PTR_PUT(ctx, token_filters, token_filter);
+ return GRN_TRUE;
+ } else {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create][token-filter] "
+ "nonexistent token filter: <%.*s>",
+ token_filter_name_length, token_filter_name);
+ return GRN_FALSE;
+ }
+}
+
+static grn_bool
+grn_proc_table_set_token_filters_fill(grn_ctx *ctx,
+ grn_obj *token_filters,
+ grn_obj *token_filter_names)
+{
+ const char *start, *current, *end;
+ const char *name_start, *name_end;
+ const char *last_name_end;
+
+ start = GRN_TEXT_VALUE(token_filter_names);
+ end = start + GRN_TEXT_LEN(token_filter_names);
+ current = start;
+ name_start = NULL;
+ name_end = NULL;
+ last_name_end = start;
+ while (current < end) {
+ switch (current[0]) {
+ case ' ' :
+ if (name_start && !name_end) {
+ name_end = current;
+ }
+ break;
+ case ',' :
+ if (!name_start) {
+ goto break_loop;
+ }
+ if (!name_end) {
+ name_end = current;
+ }
+ if (!grn_proc_table_set_token_filters_put(ctx,
+ token_filters,
+ name_start,
+ name_end - name_start)) {
+ return GRN_FALSE;
+ }
+ last_name_end = name_end + 1;
+ name_start = NULL;
+ name_end = NULL;
+ break;
+ default :
+ if (!name_start) {
+ name_start = current;
+ }
+ break;
+ }
+ current++;
+ }
+
+break_loop:
+ if (!name_start) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create][token-filter] empty token filter name: "
+ "<%.*s|%.*s|%.*s>",
+ (int)(last_name_end - start), start,
+ (int)(current - last_name_end), last_name_end,
+ (int)(end - current), current);
+ return GRN_FALSE;
+ }
+
+ if (!name_end) {
+ name_end = current;
+ }
+ grn_proc_table_set_token_filters_put(ctx,
+ token_filters,
+ name_start,
+ name_end - name_start);
+
+ return GRN_TRUE;
+}
+
+grn_bool
+grn_proc_table_set_token_filters(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *token_filter_names)
+{
+ grn_bool succeeded = GRN_FALSE;
+ grn_obj token_filters;
+
+ if (GRN_TEXT_LEN(token_filter_names) == 0) {
+ return GRN_TRUE;
+ }
+
+ GRN_PTR_INIT(&token_filters, GRN_OBJ_VECTOR, 0);
+ succeeded = grn_proc_table_set_token_filters_fill(ctx,
+ &token_filters,
+ token_filter_names);
+ if (succeeded) {
+ grn_obj_set_info(ctx, table, GRN_INFO_TOKEN_FILTERS, &token_filters);
+ }
+ grn_obj_unlink(ctx, &token_filters);
+
+ return succeeded;
+}
+
+static grn_obj *
+command_table_create(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *name;
+ grn_obj *flags_raw;
+ grn_obj *key_type_name;
+ grn_obj *value_type_name;
+ grn_obj *default_tokenizer_name;
+ grn_obj *normalizer_name;
+ grn_obj *token_filters_name;
+ grn_obj *table;
+ const char *rest;
+ grn_table_flags flags;
+
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ flags_raw = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ key_type_name = grn_plugin_proc_get_var(ctx, user_data, "key_type", -1);
+ value_type_name = grn_plugin_proc_get_var(ctx, user_data, "value_type", -1);
+ default_tokenizer_name =
+ grn_plugin_proc_get_var(ctx, user_data, "default_tokenizer", -1);
+ normalizer_name =
+ grn_plugin_proc_get_var(ctx, user_data, "normalizer", -1);
+ token_filters_name =
+ grn_plugin_proc_get_var(ctx, user_data, "token_filters", -1);
+
+ flags = grn_atoi(GRN_TEXT_VALUE(flags_raw),
+ GRN_BULK_CURR(flags_raw),
+ &rest);
+
+ if (GRN_TEXT_VALUE(flags_raw) == rest) {
+ flags = command_table_create_parse_flags(ctx,
+ GRN_TEXT_VALUE(flags_raw),
+ GRN_BULK_CURR(flags_raw));
+ if (ctx->rc) { goto exit; }
+ }
+
+ if (GRN_TEXT_LEN(name) == 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create] should not create anonymous table");
+ goto exit;
+ }
+
+ {
+ grn_obj *key_type = NULL;
+ grn_obj *value_type = NULL;
+
+ if (GRN_TEXT_LEN(key_type_name) > 0) {
+ key_type = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(key_type_name),
+ GRN_TEXT_LEN(key_type_name));
+ if (!key_type) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "key type doesn't exist: <%.*s> (%.*s)",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ (int)GRN_TEXT_LEN(key_type_name),
+ GRN_TEXT_VALUE(key_type_name));
+ goto exit;
+ }
+ }
+
+ if (GRN_TEXT_LEN(value_type_name) > 0) {
+ value_type = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(value_type_name),
+ GRN_TEXT_LEN(value_type_name));
+ if (!value_type) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create] "
+ "value type doesn't exist: <%.*s> (%.*s)",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ (int)GRN_TEXT_LEN(value_type_name),
+ GRN_TEXT_VALUE(value_type_name));
+ goto exit;
+ }
+ }
+
+ flags |= GRN_OBJ_PERSISTENT;
+ table = grn_table_create(ctx,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name),
+ NULL, flags,
+ key_type,
+ value_type);
+ if (!table) {
+ goto exit;
+ }
+
+ if (GRN_TEXT_LEN(default_tokenizer_name) > 0) {
+ grn_obj *default_tokenizer;
+
+ default_tokenizer =
+ grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(default_tokenizer_name),
+ GRN_TEXT_LEN(default_tokenizer_name));
+ if (!default_tokenizer) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create][%.*s] unknown tokenizer: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ (int)GRN_TEXT_LEN(default_tokenizer_name),
+ GRN_TEXT_VALUE(default_tokenizer_name));
+ grn_obj_remove(ctx, table);
+ goto exit;
+ }
+ grn_obj_set_info(ctx, table,
+ GRN_INFO_DEFAULT_TOKENIZER,
+ default_tokenizer);
+ }
+
+ if (GRN_TEXT_LEN(normalizer_name) > 0) {
+ grn_obj *normalizer;
+
+ normalizer =
+ grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(normalizer_name),
+ GRN_TEXT_LEN(normalizer_name));
+ if (!normalizer) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][create][%.*s] unknown normalizer: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ (int)GRN_TEXT_LEN(normalizer_name),
+ GRN_TEXT_VALUE(normalizer_name));
+ grn_obj_remove(ctx, table);
+ goto exit;
+ }
+ grn_obj_set_info(ctx, table, GRN_INFO_NORMALIZER, normalizer);
+ }
+
+ if (!grn_proc_table_set_token_filters(ctx, table, token_filters_name)) {
+ grn_obj_remove(ctx, table);
+ goto exit;
+ }
+
+ grn_obj_unlink(ctx, table);
+ }
+
+exit :
+ grn_ctx_output_bool(ctx, ctx->rc == GRN_SUCCESS);
+ return NULL;
+}
+
+void
+grn_proc_init_table_create(grn_ctx *ctx)
+{
+ grn_expr_var vars[7];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "flags", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "key_type", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "value_type", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "default_tokenizer", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[5]), "normalizer", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[6]), "token_filters", -1);
+ grn_plugin_command_create(ctx,
+ "table_create", -1,
+ command_table_create,
+ 7,
+ vars);
+}
+
+static int
+output_table_info(grn_ctx *ctx, grn_obj *table)
+{
+ grn_id id;
+ grn_obj o;
+ const char *path;
+ grn_table_flags flags;
+ grn_obj *default_tokenizer;
+ grn_obj *normalizer;
+ grn_obj *token_filters;
+
+ id = grn_obj_id(ctx, table);
+ path = grn_obj_path(ctx, table);
+ GRN_TEXT_INIT(&o, 0);
+ grn_ctx_output_array_open(ctx, "TABLE", 8);
+ grn_ctx_output_int64(ctx, id);
+ grn_proc_output_object_id_name(ctx, id);
+ grn_ctx_output_cstr(ctx, path);
+ GRN_BULK_REWIND(&o);
+
+ grn_table_get_info(ctx, table,
+ &flags,
+ NULL,
+ &default_tokenizer,
+ &normalizer,
+ &token_filters);
+ grn_dump_table_create_flags(ctx, flags, &o);
+ grn_ctx_output_obj(ctx, &o, NULL);
+ grn_proc_output_object_id_name(ctx, table->header.domain);
+ grn_proc_output_object_id_name(ctx, grn_obj_get_range(ctx, table));
+ grn_proc_output_object_name(ctx, default_tokenizer);
+ grn_proc_output_object_name(ctx, normalizer);
+ grn_ctx_output_array_close(ctx);
+ GRN_OBJ_FIN(ctx, &o);
+ return 1;
+}
+
+static grn_obj *
+command_table_list(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *db;
+ grn_obj tables;
+ int n_top_level_elements;
+ int n_elements_for_header = 1;
+ int n_tables;
+ int i;
+
+ db = grn_ctx_db(ctx);
+
+ {
+ grn_table_cursor *cursor;
+ grn_id id;
+ grn_obj *prefix;
+ const void *min = NULL;
+ unsigned int min_size = 0;
+ int flags = 0;
+
+ prefix = grn_plugin_proc_get_var(ctx, user_data, "prefix", -1);
+ if (GRN_TEXT_LEN(prefix) > 0) {
+ min = GRN_TEXT_VALUE(prefix);
+ min_size = GRN_TEXT_LEN(prefix);
+ flags |= GRN_CURSOR_PREFIX;
+ }
+ cursor = grn_table_cursor_open(ctx, db,
+ min, min_size,
+ NULL, 0,
+ 0, -1, flags);
+ if (!cursor) {
+ return NULL;
+ }
+
+ GRN_PTR_INIT(&tables, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ while ((id = grn_table_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ grn_obj *object;
+ const char *name;
+ void *key;
+ int i, key_size;
+ grn_bool have_period = GRN_FALSE;
+
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ name = key;
+ for (i = 0; i < key_size; i++) {
+ if (name[i] == '.') {
+ have_period = GRN_TRUE;
+ break;
+ }
+ }
+ if (have_period) {
+ continue;
+ }
+
+ object = grn_ctx_at(ctx, id);
+ if (object) {
+ if (grn_obj_is_table(ctx, object)) {
+ GRN_PTR_PUT(ctx, &tables, object);
+ } else {
+ grn_obj_unlink(ctx, object);
+ }
+ } else {
+ if (ctx->rc != GRN_SUCCESS) {
+ ERRCLR(ctx);
+ }
+ }
+ }
+ grn_table_cursor_close(ctx, cursor);
+ }
+ n_tables = GRN_BULK_VSIZE(&tables) / sizeof(grn_obj *);
+ n_top_level_elements = n_elements_for_header + n_tables;
+ grn_ctx_output_array_open(ctx, "TABLE_LIST", n_top_level_elements);
+
+ grn_ctx_output_array_open(ctx, "HEADER", 8);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "id");
+ grn_ctx_output_cstr(ctx, "UInt32");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "name");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "path");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "flags");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "domain");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "range");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "default_tokenizer");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_open(ctx, "PROPERTY", 2);
+ grn_ctx_output_cstr(ctx, "normalizer");
+ grn_ctx_output_cstr(ctx, "ShortText");
+ grn_ctx_output_array_close(ctx);
+ grn_ctx_output_array_close(ctx);
+
+ for (i = 0; i < n_tables; i++) {
+ grn_obj *table = GRN_PTR_VALUE_AT(&tables, i);
+ output_table_info(ctx, table);
+ grn_obj_unlink(ctx, table);
+ }
+ GRN_OBJ_FIN(ctx, &tables);
+
+ grn_ctx_output_array_close(ctx);
+
+ return NULL;
+}
+
+void
+grn_proc_init_table_list(grn_ctx *ctx)
+{
+ grn_expr_var vars[1];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "prefix", -1);
+ grn_plugin_command_create(ctx,
+ "table_list", -1,
+ command_table_list,
+ 1,
+ vars);
+}
+
+static grn_obj *
+command_table_remove(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *name;
+ grn_obj *table;
+ grn_bool dependent;
+
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ dependent = grn_plugin_proc_get_var_bool(ctx, user_data, "dependent", -1,
+ GRN_FALSE);
+ table = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ if (!table) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][remove] table isn't found: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+
+ if (!grn_obj_is_table(ctx, table)) {
+ const char *type_name;
+ type_name = grn_obj_type_to_string(table->header.type);
+ grn_obj_unlink(ctx, table);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][remove] not table: <%.*s>: <%s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ type_name);
+ grn_ctx_output_bool(ctx, GRN_FALSE);
+ return NULL;
+ }
+
+ if (dependent) {
+ grn_obj_remove_dependent(ctx, table);
+ } else {
+ grn_obj_remove(ctx, table);
+ }
+ grn_ctx_output_bool(ctx, !ctx->rc);
+ return NULL;
+}
+
+void
+grn_proc_init_table_remove(grn_ctx *ctx)
+{
+ grn_expr_var vars[2];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "dependent", -1);
+ grn_plugin_command_create(ctx,
+ "table_remove", -1,
+ command_table_remove,
+ 2,
+ vars);
+}
+
+static grn_obj *
+command_table_rename(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *name;
+ grn_obj *new_name;
+ grn_obj *table = NULL;
+
+ name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
+ new_name = grn_plugin_proc_get_var(ctx, user_data, "new_name", -1);
+ if (GRN_TEXT_LEN(name) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx, rc, "[table][rename] table name isn't specified");
+ goto exit;
+ }
+ table = grn_ctx_get(ctx, GRN_TEXT_VALUE(name), GRN_TEXT_LEN(name));
+ if (!table) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[table][rename] table isn't found: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ goto exit;
+ }
+ if (GRN_TEXT_LEN(new_name) == 0) {
+ rc = GRN_INVALID_ARGUMENT;
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[table][rename] new table name isn't specified: <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ goto exit;
+ }
+ rc = grn_table_rename(ctx, table,
+ GRN_TEXT_VALUE(new_name),
+ GRN_TEXT_LEN(new_name));
+ if (rc != GRN_SUCCESS && ctx->rc == GRN_SUCCESS) {
+ GRN_PLUGIN_ERROR(ctx,
+ rc,
+ "[table][rename] failed to rename: <%.*s> -> <%.*s>",
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name),
+ (int)GRN_TEXT_LEN(new_name),
+ GRN_TEXT_VALUE(new_name));
+ }
+exit :
+ grn_ctx_output_bool(ctx, !rc);
+ if (table) { grn_obj_unlink(ctx, table); }
+ return NULL;
+}
+
+void
+grn_proc_init_table_rename(grn_ctx *ctx)
+{
+ grn_expr_var vars[2];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "new_name", -1);
+ grn_plugin_command_create(ctx,
+ "table_rename", -1,
+ command_table_rename,
+ 2,
+ vars);
+}
+
+static grn_rc
+command_table_copy_resolve_target(grn_ctx *ctx,
+ const char *label,
+ grn_obj *name,
+ grn_obj **table)
+{
+ if (GRN_TEXT_LEN(name) == 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][copy] %s name isn't specified",
+ label);
+ return ctx->rc;
+ }
+ *table = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(name),
+ GRN_TEXT_LEN(name));
+ if (!*table) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][copy] %s table isn't found: <%.*s>",
+ label,
+ (int)GRN_TEXT_LEN(name),
+ GRN_TEXT_VALUE(name));
+ return ctx->rc;
+ }
+
+ return ctx->rc;
+}
+
+static void
+command_table_copy_same_key_type(grn_ctx *ctx,
+ grn_obj *from_table,
+ grn_obj *to_table,
+ grn_obj *from_name,
+ grn_obj *to_name)
+{
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, from_table, cursor, from_id,
+ GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING) {
+ void *key;
+ int key_size;
+ grn_id to_id;
+
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ to_id = grn_table_add(ctx, to_table, key, key_size, NULL);
+ if (to_id == GRN_ID_NIL) {
+ grn_obj key_buffer;
+ grn_obj inspected_key;
+ if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
+ GRN_SHORT_TEXT_INIT(&key_buffer, 0);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&key_buffer, 0, from_table->header.domain);
+ }
+ grn_bulk_write(ctx, &key_buffer, key, key_size);
+ GRN_TEXT_INIT(&inspected_key, 0);
+ grn_inspect(ctx, &inspected_key, &key_buffer);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][copy] failed to copy key: <%.*s>: "
+ "<%.*s> -> <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected_key),
+ GRN_TEXT_VALUE(&inspected_key),
+ (int)GRN_TEXT_LEN(from_name),
+ GRN_TEXT_VALUE(from_name),
+ (int)GRN_TEXT_LEN(to_name),
+ GRN_TEXT_VALUE(to_name));
+ GRN_OBJ_FIN(ctx, &inspected_key);
+ GRN_OBJ_FIN(ctx, &key_buffer);
+ break;
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+}
+
+static void
+command_table_copy_different(grn_ctx *ctx,
+ grn_obj *from_table,
+ grn_obj *to_table,
+ grn_obj *from_name,
+ grn_obj *to_name)
+{
+ grn_obj from_key_buffer;
+ grn_obj to_key_buffer;
+
+ if (from_table->header.domain == GRN_DB_SHORT_TEXT) {
+ GRN_SHORT_TEXT_INIT(&from_key_buffer, 0);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&from_key_buffer, 0, from_table->header.domain);
+ }
+ if (to_table->header.domain == GRN_DB_SHORT_TEXT) {
+ GRN_SHORT_TEXT_INIT(&to_key_buffer, 0);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&to_key_buffer, 0, to_table->header.domain);
+ }
+
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, from_table, cursor, from_id,
+ GRN_CURSOR_BY_KEY | GRN_CURSOR_ASCENDING) {
+ void *key;
+ int key_size;
+ grn_rc cast_rc;
+ grn_id to_id;
+
+ GRN_BULK_REWIND(&from_key_buffer);
+ GRN_BULK_REWIND(&to_key_buffer);
+
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ grn_bulk_write(ctx, &from_key_buffer, key, key_size);
+ cast_rc = grn_obj_cast(ctx, &from_key_buffer, &to_key_buffer, GRN_FALSE);
+ if (cast_rc != GRN_SUCCESS) {
+ grn_obj *to_key_type;
+ grn_obj inspected_key;
+ grn_obj inspected_to_key_type;
+
+ to_key_type = grn_ctx_at(ctx, to_table->header.domain);
+ GRN_TEXT_INIT(&inspected_key, 0);
+ GRN_TEXT_INIT(&inspected_to_key_type, 0);
+ grn_inspect(ctx, &inspected_key, &from_key_buffer);
+ grn_inspect(ctx, &inspected_to_key_type, to_key_type);
+ ERR(cast_rc,
+ "[table][copy] failed to cast key: <%.*s> -> %.*s: "
+ "<%.*s> -> <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected_key),
+ GRN_TEXT_VALUE(&inspected_key),
+ (int)GRN_TEXT_LEN(&inspected_to_key_type),
+ GRN_TEXT_VALUE(&inspected_to_key_type),
+ (int)GRN_TEXT_LEN(from_name),
+ GRN_TEXT_VALUE(from_name),
+ (int)GRN_TEXT_LEN(to_name),
+ GRN_TEXT_VALUE(to_name));
+ GRN_OBJ_FIN(ctx, &inspected_key);
+ GRN_OBJ_FIN(ctx, &inspected_to_key_type);
+ break;
+ }
+
+ to_id = grn_table_add(ctx, to_table,
+ GRN_BULK_HEAD(&to_key_buffer),
+ GRN_BULK_VSIZE(&to_key_buffer),
+ NULL);
+ if (to_id == GRN_ID_NIL) {
+ grn_obj inspected_from_key;
+ grn_obj inspected_to_key;
+ GRN_TEXT_INIT(&inspected_from_key, 0);
+ GRN_TEXT_INIT(&inspected_to_key, 0);
+ grn_inspect(ctx, &inspected_from_key, &from_key_buffer);
+ grn_inspect(ctx, &inspected_to_key, &to_key_buffer);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "[table][copy] failed to copy key: <%.*s> -> <%.*s>: "
+ "<%.*s> -> <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected_from_key),
+ GRN_TEXT_VALUE(&inspected_from_key),
+ (int)GRN_TEXT_LEN(&inspected_to_key),
+ GRN_TEXT_VALUE(&inspected_to_key),
+ (int)GRN_TEXT_LEN(from_name),
+ GRN_TEXT_VALUE(from_name),
+ (int)GRN_TEXT_LEN(to_name),
+ GRN_TEXT_VALUE(to_name));
+ GRN_OBJ_FIN(ctx, &inspected_from_key);
+ GRN_OBJ_FIN(ctx, &inspected_to_key);
+ break;
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ GRN_OBJ_FIN(ctx, &from_key_buffer);
+ GRN_OBJ_FIN(ctx, &to_key_buffer);
+}
+
+static grn_obj *
+command_table_copy(grn_ctx *ctx,
+ int nargs,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *from_table = NULL;
+ grn_obj *to_table = NULL;
+ grn_obj *from_name;
+ grn_obj *to_name;
+
+ from_name = grn_plugin_proc_get_var(ctx, user_data, "from_name", -1);
+ to_name = grn_plugin_proc_get_var(ctx, user_data, "to_name", -1);
+
+ rc = command_table_copy_resolve_target(ctx, "from", from_name, &from_table);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+ rc = command_table_copy_resolve_target(ctx, "to", to_name, &to_table);
+ if (rc != GRN_SUCCESS) {
+ goto exit;
+ }
+
+ if (from_table->header.type == GRN_TABLE_NO_KEY ||
+ to_table->header.type == GRN_TABLE_NO_KEY) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_OPERATION_NOT_SUPPORTED,
+ "[table][copy] copy from/to TABLE_NO_KEY isn't supported: "
+ "<%.*s> -> <%.*s>",
+ (int)GRN_TEXT_LEN(from_name),
+ GRN_TEXT_VALUE(from_name),
+ (int)GRN_TEXT_LEN(to_name),
+ GRN_TEXT_VALUE(to_name));
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ if (from_table == to_table) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_OPERATION_NOT_SUPPORTED,
+ "[table][copy] from table and to table is the same: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(from_name),
+ GRN_TEXT_VALUE(from_name));
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ if (from_table->header.domain == to_table->header.domain) {
+ command_table_copy_same_key_type(ctx,
+ from_table, to_table,
+ from_name, to_name);
+ } else {
+ command_table_copy_different(ctx,
+ from_table, to_table,
+ from_name, to_name);
+ }
+
+exit :
+ grn_ctx_output_bool(ctx, rc == GRN_SUCCESS);
+
+ if (to_table) {
+ grn_obj_unlink(ctx, to_table);
+ }
+ if (from_table) {
+ grn_obj_unlink(ctx, from_table);
+ }
+
+ return NULL;
+}
+
+void
+grn_proc_init_table_copy(grn_ctx *ctx)
+{
+ grn_expr_var vars[2];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "from_name", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "to_name", -1);
+ grn_plugin_command_create(ctx,
+ "table_copy", -1,
+ command_table_copy,
+ 2,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/proc_tokenize.c b/storage/mroonga/vendor/groonga/lib/proc/proc_tokenize.c
new file mode 100644
index 00000000..206ebf58
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/proc_tokenize.c
@@ -0,0 +1,433 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "../grn_proc.h"
+#include "../grn_ctx.h"
+#include "../grn_token_cursor.h"
+
+#include <groonga/plugin.h>
+
+static unsigned int
+parse_tokenize_flags(grn_ctx *ctx, grn_obj *flag_names)
+{
+ unsigned int flags = 0;
+ const char *names, *names_end;
+ int length;
+
+ names = GRN_TEXT_VALUE(flag_names);
+ length = GRN_TEXT_LEN(flag_names);
+ names_end = names + length;
+ while (names < names_end) {
+ if (*names == '|' || *names == ' ') {
+ names += 1;
+ continue;
+ }
+
+#define CHECK_FLAG(name)\
+ if (((unsigned long) (names_end - names) >= (unsigned long) (sizeof(#name) - 1)) &&\
+ (!memcmp(names, #name, sizeof(#name) - 1))) {\
+ flags |= GRN_TOKEN_CURSOR_ ## name;\
+ names += sizeof(#name) - 1;\
+ continue;\
+ }
+
+ CHECK_FLAG(ENABLE_TOKENIZED_DELIMITER);
+
+#define GRN_TOKEN_CURSOR_NONE 0
+ CHECK_FLAG(NONE);
+#undef GRN_TOKEN_CURSOR_NONE
+
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[tokenize] invalid flag: <%.*s>",
+ (int)(names_end - names), names);
+ return 0;
+#undef CHECK_FLAG
+ }
+
+ return flags;
+}
+
+typedef struct {
+ grn_id id;
+ int32_t position;
+ grn_bool force_prefix;
+} tokenize_token;
+
+static void
+output_tokens(grn_ctx *ctx, grn_obj *tokens, grn_obj *lexicon, grn_obj *index_column)
+{
+ int i, n_tokens, n_elements;
+ grn_obj estimated_size;
+
+ n_tokens = GRN_BULK_VSIZE(tokens) / sizeof(tokenize_token);
+ n_elements = 3;
+ if (index_column) {
+ n_elements++;
+ GRN_UINT32_INIT(&estimated_size, 0);
+ }
+
+ grn_ctx_output_array_open(ctx, "TOKENS", n_tokens);
+ for (i = 0; i < n_tokens; i++) {
+ tokenize_token *token;
+ char value[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int value_size;
+
+ token = ((tokenize_token *)(GRN_BULK_HEAD(tokens))) + i;
+
+ grn_ctx_output_map_open(ctx, "TOKEN", n_elements);
+
+ grn_ctx_output_cstr(ctx, "value");
+ value_size = grn_table_get_key(ctx, lexicon, token->id,
+ value, GRN_TABLE_MAX_KEY_SIZE);
+ grn_ctx_output_str(ctx, value, value_size);
+
+ grn_ctx_output_cstr(ctx, "position");
+ grn_ctx_output_int32(ctx, token->position);
+
+ grn_ctx_output_cstr(ctx, "force_prefix");
+ grn_ctx_output_bool(ctx, token->force_prefix);
+
+ if (index_column) {
+ GRN_BULK_REWIND(&estimated_size);
+ grn_obj_get_value(ctx, index_column, token->id, &estimated_size);
+ grn_ctx_output_cstr(ctx, "estimated_size");
+ grn_ctx_output_int64(ctx, GRN_UINT32_VALUE(&estimated_size));
+ }
+
+ grn_ctx_output_map_close(ctx);
+ }
+
+ if (index_column) {
+ GRN_OBJ_FIN(ctx, &estimated_size);
+ }
+
+ grn_ctx_output_array_close(ctx);
+}
+
+static grn_obj *
+create_lexicon_for_tokenize(grn_ctx *ctx,
+ grn_obj *tokenizer_name,
+ grn_obj *normalizer_name,
+ grn_obj *token_filter_names)
+{
+ grn_obj *lexicon;
+ grn_obj *tokenizer;
+ grn_obj *normalizer = NULL;
+
+ tokenizer = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(tokenizer_name),
+ GRN_TEXT_LEN(tokenizer_name));
+ if (!tokenizer) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[tokenize] nonexistent tokenizer: <%.*s>",
+ (int)GRN_TEXT_LEN(tokenizer_name),
+ GRN_TEXT_VALUE(tokenizer_name));
+ return NULL;
+ }
+
+ if (!grn_obj_is_tokenizer_proc(ctx, tokenizer)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, tokenizer);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[tokenize] not tokenizer: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ grn_obj_unlink(ctx, tokenizer);
+ return NULL;
+ }
+
+ if (GRN_TEXT_LEN(normalizer_name) > 0) {
+ normalizer = grn_ctx_get(ctx,
+ GRN_TEXT_VALUE(normalizer_name),
+ GRN_TEXT_LEN(normalizer_name));
+ if (!normalizer) {
+ grn_obj_unlink(ctx, tokenizer);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[tokenize] nonexistent normalizer: <%.*s>",
+ (int)GRN_TEXT_LEN(normalizer_name),
+ GRN_TEXT_VALUE(normalizer_name));
+ return NULL;
+ }
+
+ if (!grn_obj_is_normalizer_proc(ctx, normalizer)) {
+ grn_obj inspected;
+ grn_obj_unlink(ctx, tokenizer);
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, normalizer);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[tokenize] not normalizer: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ grn_obj_unlink(ctx, normalizer);
+ return NULL;
+ }
+ }
+
+ lexicon = grn_table_create(ctx, NULL, 0,
+ NULL,
+ GRN_OBJ_TABLE_HASH_KEY,
+ grn_ctx_at(ctx, GRN_DB_SHORT_TEXT),
+ NULL);
+ grn_obj_set_info(ctx, lexicon,
+ GRN_INFO_DEFAULT_TOKENIZER, tokenizer);
+ grn_obj_unlink(ctx, tokenizer);
+ if (normalizer) {
+ grn_obj_set_info(ctx, lexicon,
+ GRN_INFO_NORMALIZER, normalizer);
+ grn_obj_unlink(ctx, normalizer);
+ }
+ grn_proc_table_set_token_filters(ctx, lexicon, token_filter_names);
+
+ return lexicon;
+}
+
+static void
+tokenize(grn_ctx *ctx, grn_obj *lexicon, grn_obj *string, grn_tokenize_mode mode,
+ unsigned int flags, grn_obj *tokens)
+{
+ grn_token_cursor *token_cursor;
+
+ token_cursor =
+ grn_token_cursor_open(ctx, lexicon,
+ GRN_TEXT_VALUE(string), GRN_TEXT_LEN(string),
+ mode, flags);
+ if (!token_cursor) {
+ return;
+ }
+
+ while (token_cursor->status == GRN_TOKEN_CURSOR_DOING) {
+ grn_id token_id = grn_token_cursor_next(ctx, token_cursor);
+ tokenize_token *current_token;
+ if (token_id == GRN_ID_NIL) {
+ continue;
+ }
+ grn_bulk_space(ctx, tokens, sizeof(tokenize_token));
+ current_token = ((tokenize_token *)(GRN_BULK_CURR(tokens))) - 1;
+ current_token->id = token_id;
+ current_token->position = token_cursor->pos;
+ current_token->force_prefix = token_cursor->force_prefix;
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+}
+
+static grn_obj *
+command_table_tokenize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *table_name;
+ grn_obj *string;
+ grn_obj *flag_names;
+ grn_obj *mode_name;
+ grn_obj *index_column_name;
+
+ table_name = grn_plugin_proc_get_var(ctx, user_data, "table", -1);
+ string = grn_plugin_proc_get_var(ctx, user_data, "string", -1);
+ flag_names = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ mode_name = grn_plugin_proc_get_var(ctx, user_data, "mode", -1);
+ index_column_name = grn_plugin_proc_get_var(ctx, user_data, "index_column", -1);
+
+ if (GRN_TEXT_LEN(table_name) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "[table_tokenize] table name is missing");
+ return NULL;
+ }
+
+ if (GRN_TEXT_LEN(string) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "[table_tokenize] string is missing");
+ return NULL;
+ }
+
+ {
+ unsigned int flags;
+ grn_obj *lexicon;
+ grn_obj *index_column = NULL;
+
+ flags = parse_tokenize_flags(ctx, flag_names);
+ if (ctx->rc != GRN_SUCCESS) {
+ return NULL;
+ }
+
+ lexicon = grn_ctx_get(ctx, GRN_TEXT_VALUE(table_name), GRN_TEXT_LEN(table_name));
+ if (!lexicon) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[table_tokenize] nonexistent lexicon: <%.*s>",
+ (int)GRN_TEXT_LEN(table_name),
+ GRN_TEXT_VALUE(table_name));
+ return NULL;
+ }
+
+#define MODE_NAME_EQUAL(name)\
+ (GRN_TEXT_LEN(mode_name) == strlen(name) &&\
+ memcmp(GRN_TEXT_VALUE(mode_name), name, strlen(name)) == 0)
+
+ if (GRN_TEXT_LEN(index_column_name) > 0) {
+ index_column = grn_obj_column(ctx, lexicon,
+ GRN_TEXT_VALUE(index_column_name),
+ GRN_TEXT_LEN(index_column_name));
+ if (!index_column) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[table_tokenize] nonexistent index column: <%.*s>",
+ (int)GRN_TEXT_LEN(index_column_name),
+ GRN_TEXT_VALUE(index_column_name));
+ goto exit;
+ }
+ if (index_column->header.type != GRN_COLUMN_INDEX) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[table_tokenize] index column must be COLUMN_INDEX: <%.*s>",
+ (int)GRN_TEXT_LEN(index_column_name),
+ GRN_TEXT_VALUE(index_column_name));
+ goto exit;
+ }
+ }
+
+ {
+ grn_obj tokens;
+ GRN_VALUE_FIX_SIZE_INIT(&tokens, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ if (GRN_TEXT_LEN(mode_name) == 0 || MODE_NAME_EQUAL("GET")) {
+ tokenize(ctx, lexicon, string, GRN_TOKEN_GET, flags, &tokens);
+ output_tokens(ctx, &tokens, lexicon, index_column);
+ } else if (MODE_NAME_EQUAL("ADD")) {
+ tokenize(ctx, lexicon, string, GRN_TOKEN_ADD, flags, &tokens);
+ output_tokens(ctx, &tokens, lexicon, index_column);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[table_tokenize] invalid mode: <%.*s>",
+ (int)GRN_TEXT_LEN(mode_name), GRN_TEXT_VALUE(mode_name));
+ }
+ GRN_OBJ_FIN(ctx, &tokens);
+ }
+#undef MODE_NAME_EQUAL
+
+exit:
+ grn_obj_unlink(ctx, lexicon);
+ if (index_column) {
+ grn_obj_unlink(ctx, index_column);
+ }
+ }
+
+ return NULL;
+}
+
+void
+grn_proc_init_table_tokenize(grn_ctx *ctx)
+{
+ grn_expr_var vars[5];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "table", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "string", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "flags", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "mode", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "index_column", -1);
+ grn_plugin_command_create(ctx,
+ "table_tokenize", -1,
+ command_table_tokenize,
+ 5,
+ vars);
+}
+
+static grn_obj *
+command_tokenize(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *tokenizer_name;
+ grn_obj *string;
+ grn_obj *normalizer_name;
+ grn_obj *flag_names;
+ grn_obj *mode_name;
+ grn_obj *token_filter_names;
+
+ tokenizer_name = grn_plugin_proc_get_var(ctx, user_data, "tokenizer", -1);
+ string = grn_plugin_proc_get_var(ctx, user_data, "string", -1);
+ normalizer_name = grn_plugin_proc_get_var(ctx, user_data, "normalizer", -1);
+ flag_names = grn_plugin_proc_get_var(ctx, user_data, "flags", -1);
+ mode_name = grn_plugin_proc_get_var(ctx, user_data, "mode", -1);
+ token_filter_names = grn_plugin_proc_get_var(ctx, user_data, "token_filters", -1);
+
+ if (GRN_TEXT_LEN(tokenizer_name) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "[tokenize] tokenizer name is missing");
+ return NULL;
+ }
+
+ if (GRN_TEXT_LEN(string) == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "[tokenize] string is missing");
+ return NULL;
+ }
+
+ {
+ unsigned int flags;
+ grn_obj *lexicon;
+
+ flags = parse_tokenize_flags(ctx, flag_names);
+ if (ctx->rc != GRN_SUCCESS) {
+ return NULL;
+ }
+
+ lexicon = create_lexicon_for_tokenize(ctx,
+ tokenizer_name,
+ normalizer_name,
+ token_filter_names);
+ if (!lexicon) {
+ return NULL;
+ }
+#define MODE_NAME_EQUAL(name)\
+ (GRN_TEXT_LEN(mode_name) == strlen(name) &&\
+ memcmp(GRN_TEXT_VALUE(mode_name), name, strlen(name)) == 0)
+
+ {
+ grn_obj tokens;
+ GRN_VALUE_FIX_SIZE_INIT(&tokens, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ if (GRN_TEXT_LEN(mode_name) == 0 || MODE_NAME_EQUAL("ADD")) {
+ tokenize(ctx, lexicon, string, GRN_TOKEN_ADD, flags, &tokens);
+ output_tokens(ctx, &tokens, lexicon, NULL);
+ } else if (MODE_NAME_EQUAL("GET")) {
+ tokenize(ctx, lexicon, string, GRN_TOKEN_ADD, flags, &tokens);
+ GRN_BULK_REWIND(&tokens);
+ tokenize(ctx, lexicon, string, GRN_TOKEN_GET, flags, &tokens);
+ output_tokens(ctx, &tokens, lexicon, NULL);
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[tokenize] invalid mode: <%.*s>",
+ (int)GRN_TEXT_LEN(mode_name), GRN_TEXT_VALUE(mode_name));
+ }
+ GRN_OBJ_FIN(ctx, &tokens);
+ }
+#undef MODE_NAME_EQUAL
+
+ grn_obj_unlink(ctx, lexicon);
+ }
+
+ return NULL;
+}
+
+void
+grn_proc_init_tokenize(grn_ctx *ctx)
+{
+ grn_expr_var vars[6];
+
+ grn_plugin_expr_var_init(ctx, &(vars[0]), "tokenizer", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[1]), "string", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[2]), "normalizer", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[3]), "flags", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[4]), "mode", -1);
+ grn_plugin_expr_var_init(ctx, &(vars[5]), "token_filters", -1);
+ grn_plugin_command_create(ctx,
+ "tokenize", -1,
+ command_tokenize,
+ 6,
+ vars);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/proc/sources.am b/storage/mroonga/vendor/groonga/lib/proc/sources.am
new file mode 100644
index 00000000..a945320f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/proc/sources.am
@@ -0,0 +1,18 @@
+libgrnproc_la_SOURCES = \
+ proc_column.c \
+ proc_config.c \
+ proc_dump.c \
+ proc_fuzzy_search.c \
+ proc_highlight.c \
+ proc_in_records.c \
+ proc_lock.c \
+ proc_object.c \
+ proc_object_inspect.c \
+ proc_object_list.c \
+ proc_query.c \
+ proc_query_log_flags.c \
+ proc_schema.c \
+ proc_select.c \
+ proc_snippet.c \
+ proc_table.c \
+ proc_tokenize.c
diff --git a/storage/mroonga/vendor/groonga/lib/raw_string.c b/storage/mroonga/vendor/groonga/lib/raw_string.c
new file mode 100644
index 00000000..794450f8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/raw_string.c
@@ -0,0 +1,38 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_raw_string.h"
+#include "grn_str.h"
+
+void
+grn_raw_string_lstrip(grn_ctx *ctx,
+ grn_raw_string *string)
+{
+ const char *end;
+ int space_len;
+
+ end = string->value + string->length;
+ while (string->value < end) {
+ space_len = grn_isspace(string->value, ctx->encoding);
+ if (space_len == 0) {
+ break;
+ }
+ string->value += space_len;
+ string->length -= space_len;
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/report.c b/storage/mroonga/vendor/groonga/lib/report.c
new file mode 100644
index 00000000..c16e6e68
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/report.c
@@ -0,0 +1,98 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_report.h"
+
+const grn_log_level GRN_REPORT_INDEX_LOG_LEVEL = GRN_LOG_INFO;
+
+void
+grn_report_index(grn_ctx *ctx,
+ const char *action,
+ const char *tag,
+ grn_obj *index)
+{
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+
+ if (!grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ return;
+ }
+
+ index_name_size = grn_obj_name(ctx, index, index_name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_LOG(ctx, GRN_REPORT_INDEX_LOG_LEVEL,
+ "%s[index]%s <%.*s>",
+ action, tag, index_name_size, index_name);
+}
+
+void
+grn_report_index_not_used(grn_ctx *ctx,
+ const char *action,
+ const char *tag,
+ grn_obj *index,
+ const char *reason)
+{
+ char index_name[GRN_TABLE_MAX_KEY_SIZE];
+ int index_name_size;
+
+ if (!grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ return;
+ }
+
+ index_name_size = grn_obj_name(ctx, index, index_name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_LOG(ctx, GRN_REPORT_INDEX_LOG_LEVEL,
+ "%s[index-not-used]%s <%.*s>: %s",
+ action, tag, index_name_size, index_name, reason);
+}
+
+void
+grn_report_table(grn_ctx *ctx,
+ const char *action,
+ const char *tag,
+ grn_obj *table)
+{
+ grn_obj description;
+ grn_obj *target;
+
+ if (!grn_logger_pass(ctx, GRN_REPORT_INDEX_LOG_LEVEL)) {
+ return;
+ }
+
+ GRN_TEXT_INIT(&description, 0);
+ for (target = table; target; target = grn_ctx_at(ctx, target->header.domain)) {
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ name_size = grn_obj_name(ctx, target, name, GRN_TABLE_MAX_KEY_SIZE);
+ if (GRN_TEXT_LEN(&description) > 0) {
+ GRN_TEXT_PUTS(ctx, &description, " -> ");
+ }
+ if (name_size == 0) {
+ GRN_TEXT_PUTS(ctx, &description, "(temporary)");
+ } else {
+ GRN_TEXT_PUTS(ctx, &description, "<");
+ GRN_TEXT_PUT(ctx, &description, name, name_size);
+ GRN_TEXT_PUTS(ctx, &description, ">");
+ }
+ }
+ GRN_LOG(ctx, GRN_REPORT_INDEX_LOG_LEVEL,
+ "%s[table]%s %.*s",
+ action, tag,
+ (int)GRN_TEXT_LEN(&description),
+ GRN_TEXT_VALUE(&description));
+ GRN_OBJ_FIN(ctx, &description);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/request_canceler.c b/storage/mroonga/vendor/groonga/lib/request_canceler.c
new file mode 100644
index 00000000..c5aedf3e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/request_canceler.c
@@ -0,0 +1,176 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx.h"
+#include "grn_ctx_impl.h"
+#include "grn_request_canceler.h"
+
+typedef struct _grn_request_canceler grn_request_canceler;
+struct _grn_request_canceler {
+ grn_hash *entries;
+ grn_mutex mutex;
+};
+
+typedef struct _grn_request_canceler_entry grn_request_canceler_entry;
+struct _grn_request_canceler_entry {
+ grn_ctx *ctx;
+};
+
+static grn_ctx grn_the_request_canceler_ctx;
+static grn_request_canceler *grn_the_request_canceler = NULL;
+
+grn_bool
+grn_request_canceler_init(void)
+{
+ grn_ctx *ctx = &grn_the_request_canceler_ctx;
+
+ grn_ctx_init(ctx, 0);
+
+ grn_the_request_canceler = GRN_MALLOC(sizeof(grn_request_canceler));
+ if (!grn_the_request_canceler) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[request-canceler] failed to allocate the global request canceler");
+ return GRN_FALSE;
+ }
+
+ grn_the_request_canceler->entries =
+ grn_hash_create(ctx, NULL, GRN_TABLE_MAX_KEY_SIZE,
+ sizeof(grn_request_canceler_entry), GRN_OBJ_KEY_VAR_SIZE);
+ if (!grn_the_request_canceler->entries) {
+ return GRN_FALSE;
+ }
+ MUTEX_INIT(grn_the_request_canceler->mutex);
+
+ return GRN_TRUE;
+}
+
+void
+grn_request_canceler_register(grn_ctx *ctx,
+ const char *request_id, unsigned int size)
+{
+ MUTEX_LOCK(grn_the_request_canceler->mutex);
+ {
+ grn_hash *entries = grn_the_request_canceler->entries;
+ grn_id id;
+ void *value;
+ id = grn_hash_add(&grn_the_request_canceler_ctx,
+ entries, request_id, size, &value, NULL);
+ if (id) {
+ grn_request_canceler_entry *entry = value;
+ entry->ctx = ctx;
+ }
+ }
+ MUTEX_UNLOCK(grn_the_request_canceler->mutex);
+}
+
+void
+grn_request_canceler_unregister(grn_ctx *ctx,
+ const char *request_id, unsigned int size)
+{
+ MUTEX_LOCK(grn_the_request_canceler->mutex);
+ {
+ grn_hash *entries = grn_the_request_canceler->entries;
+ grn_hash_delete(&grn_the_request_canceler_ctx,
+ entries, request_id, size, NULL);
+ }
+ MUTEX_UNLOCK(grn_the_request_canceler->mutex);
+
+ if (ctx->rc == GRN_CANCEL) {
+ ERRSET(ctx, GRN_LOG_NOTICE, ctx->rc,
+ "[request-canceler] a request is canceled: <%.*s>",
+ size, request_id);
+ }
+}
+
+static grn_bool
+grn_request_canceler_cancel_entry(grn_request_canceler_entry *entry)
+{
+ if (entry->ctx->rc == GRN_SUCCESS) {
+ entry->ctx->rc = GRN_CANCEL;
+ if (entry->ctx->impl->current_request_timer_id) {
+ void *timer_id = entry->ctx->impl->current_request_timer_id;
+ entry->ctx->impl->current_request_timer_id = NULL;
+ grn_request_timer_unregister(timer_id);
+ }
+ return GRN_TRUE;
+ } else {
+ return GRN_FALSE;
+ }
+}
+
+grn_bool
+grn_request_canceler_cancel(const char *request_id, unsigned int size)
+{
+ grn_bool canceled = GRN_FALSE;
+ MUTEX_LOCK(grn_the_request_canceler->mutex);
+ {
+ grn_ctx *ctx = &grn_the_request_canceler_ctx;
+ grn_hash *entries = grn_the_request_canceler->entries;
+ void *value;
+ if (grn_hash_get(ctx, entries, request_id, size, &value)) {
+ grn_request_canceler_entry *entry = value;
+ if (grn_request_canceler_cancel_entry(entry)) {
+ canceled = GRN_TRUE;
+ }
+ }
+ }
+ MUTEX_UNLOCK(grn_the_request_canceler->mutex);
+ return canceled;
+}
+
+grn_bool
+grn_request_canceler_cancel_all(void)
+{
+ grn_bool canceled = GRN_FALSE;
+ MUTEX_LOCK(grn_the_request_canceler->mutex);
+ {
+ grn_ctx *ctx = &grn_the_request_canceler_ctx;
+ grn_hash *entries = grn_the_request_canceler->entries;
+ grn_hash_cursor *cursor;
+
+ cursor = grn_hash_cursor_open(ctx, entries,
+ NULL, 0, NULL, 0,
+ 0, -1, 0);
+ if (cursor) {
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ void *value;
+ if (grn_hash_cursor_get_value(ctx, cursor, &value) > 0) {
+ grn_request_canceler_entry *entry = value;
+ if (grn_request_canceler_cancel_entry(entry)) {
+ canceled = GRN_TRUE;
+ }
+ }
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ }
+ MUTEX_UNLOCK(grn_the_request_canceler->mutex);
+ return canceled;
+}
+
+void
+grn_request_canceler_fin(void)
+{
+ grn_ctx *ctx = &grn_the_request_canceler_ctx;
+
+ grn_hash_close(ctx, grn_the_request_canceler->entries);
+ MUTEX_FIN(grn_the_request_canceler->mutex);
+ GRN_FREE(grn_the_request_canceler);
+ grn_the_request_canceler = NULL;
+ grn_ctx_fin(ctx);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/request_timer.c b/storage/mroonga/vendor/groonga/lib/request_timer.c
new file mode 100644
index 00000000..23a0c644
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/request_timer.c
@@ -0,0 +1,88 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx.h"
+#include "grn_request_timer.h"
+
+static grn_request_timer grn_current_request_timer = { 0 };
+static double grn_request_timer_default_timeout = 0.0;
+
+grn_bool
+grn_request_timer_init(void)
+{
+ return GRN_TRUE;
+}
+
+void *
+grn_request_timer_register(const char *request_id,
+ unsigned int request_id_size,
+ double timeout)
+{
+ void *timer_id = NULL;
+
+ if (grn_current_request_timer.register_func) {
+ void *user_data = grn_current_request_timer.user_data;
+ timer_id = grn_current_request_timer.register_func(request_id,
+ request_id_size,
+ timeout,
+ user_data);
+ }
+
+ return timer_id;
+}
+
+void
+grn_request_timer_unregister(void *timer_id)
+{
+ if (grn_current_request_timer.unregister_func) {
+ void *user_data = grn_current_request_timer.user_data;
+ grn_current_request_timer.unregister_func(timer_id, user_data);
+ }
+}
+
+void
+grn_request_timer_set(grn_request_timer *timer)
+{
+ if (grn_current_request_timer.fin_func) {
+ void *user_data = grn_current_request_timer.user_data;
+ grn_current_request_timer.fin_func(user_data);
+ }
+ if (timer) {
+ grn_current_request_timer = *timer;
+ } else {
+ memset(&grn_current_request_timer, 0, sizeof(grn_request_timer));
+ }
+}
+
+double
+grn_get_default_request_timeout(void)
+{
+ return grn_request_timer_default_timeout;
+}
+
+void
+grn_set_default_request_timeout(double timeout)
+{
+ grn_request_timer_default_timeout = timeout;
+}
+
+void
+grn_request_timer_fin(void)
+{
+ grn_request_timer_set(NULL);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/rset.c b/storage/mroonga/vendor/groonga/lib/rset.c
new file mode 100644
index 00000000..f7b50039
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/rset.c
@@ -0,0 +1,324 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2009-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn_db.h"
+
+uint32_t
+grn_rset_recinfo_calc_values_size(grn_ctx *ctx, grn_table_group_flags flags)
+{
+ uint32_t size = 0;
+
+ if (flags & GRN_TABLE_GROUP_CALC_MAX) {
+ size += GRN_RSET_MAX_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_MIN) {
+ size += GRN_RSET_MIN_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_SUM) {
+ size += GRN_RSET_SUM_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_AVG) {
+ size += GRN_RSET_AVG_SIZE;
+ }
+
+ return size;
+}
+
+void
+grn_rset_recinfo_update_calc_values(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ grn_obj *value)
+{
+ grn_table_group_flags flags;
+ byte *values;
+ grn_obj value_int64;
+ grn_obj value_float;
+
+ flags = DB_OBJ(table)->flags.group;
+
+ values = (((byte *)ri->subrecs) +
+ GRN_RSET_SUBRECS_SIZE(DB_OBJ(table)->subrec_size,
+ DB_OBJ(table)->max_n_subrecs));
+
+ GRN_INT64_INIT(&value_int64, 0);
+ GRN_FLOAT_INIT(&value_float, 0);
+
+ if (flags & (GRN_TABLE_GROUP_CALC_MAX |
+ GRN_TABLE_GROUP_CALC_MIN |
+ GRN_TABLE_GROUP_CALC_SUM)) {
+ grn_obj_cast(ctx, value, &value_int64, GRN_FALSE);
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_AVG) {
+ grn_obj_cast(ctx, value, &value_float, GRN_FALSE);
+ }
+
+ if (flags & GRN_TABLE_GROUP_CALC_MAX) {
+ int64_t current_max = *((int64_t *)values);
+ int64_t value_raw = GRN_INT64_VALUE(&value_int64);
+ if (ri->n_subrecs == 1 || value_raw > current_max) {
+ *((int64_t *)values) = value_raw;
+ }
+ values += GRN_RSET_MAX_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_MIN) {
+ int64_t current_min = *((int64_t *)values);
+ int64_t value_raw = GRN_INT64_VALUE(&value_int64);
+ if (ri->n_subrecs == 1 || value_raw < current_min) {
+ *((int64_t *)values) = value_raw;
+ }
+ values += GRN_RSET_MIN_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_SUM) {
+ int64_t value_raw = GRN_INT64_VALUE(&value_int64);
+ *((int64_t *)values) += value_raw;
+ values += GRN_RSET_SUM_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_AVG) {
+ double current_average = *((double *)values);
+ double value_raw = GRN_FLOAT_VALUE(&value_float);
+ *((double *)values) += (value_raw - current_average) / ri->n_subrecs;
+ values += GRN_RSET_AVG_SIZE;
+ }
+
+ GRN_OBJ_FIN(ctx, &value_float);
+ GRN_OBJ_FIN(ctx, &value_int64);
+}
+
+int64_t *
+grn_rset_recinfo_get_max_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ grn_table_group_flags flags;
+ byte *values;
+
+ flags = DB_OBJ(table)->flags.group;
+ if (!(flags & GRN_TABLE_GROUP_CALC_MAX)) {
+ return NULL;
+ }
+
+ values = (((byte *)ri->subrecs) +
+ GRN_RSET_SUBRECS_SIZE(DB_OBJ(table)->subrec_size,
+ DB_OBJ(table)->max_n_subrecs));
+
+ return (int64_t *)values;
+}
+
+int64_t
+grn_rset_recinfo_get_max(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ int64_t *max_address;
+
+ max_address = grn_rset_recinfo_get_max_(ctx, ri, table);
+ if (max_address) {
+ return *max_address;
+ } else {
+ return 0;
+ }
+}
+
+void
+grn_rset_recinfo_set_max(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ int64_t max)
+{
+ int64_t *max_address;
+
+ max_address = grn_rset_recinfo_get_max_(ctx, ri, table);
+ if (!max_address) {
+ return;
+ }
+
+ *max_address = max;
+}
+
+int64_t *
+grn_rset_recinfo_get_min_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ grn_table_group_flags flags;
+ byte *values;
+
+ flags = DB_OBJ(table)->flags.group;
+ if (!(flags & GRN_TABLE_GROUP_CALC_MIN)) {
+ return NULL;
+ }
+
+ values = (((byte *)ri->subrecs) +
+ GRN_RSET_SUBRECS_SIZE(DB_OBJ(table)->subrec_size,
+ DB_OBJ(table)->max_n_subrecs));
+
+ if (flags & GRN_TABLE_GROUP_CALC_MAX) {
+ values += GRN_RSET_MAX_SIZE;
+ }
+
+ return (int64_t *)values;
+}
+
+int64_t
+grn_rset_recinfo_get_min(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ int64_t *min_address;
+
+ min_address = grn_rset_recinfo_get_min_(ctx, ri, table);
+ if (min_address) {
+ return *min_address;
+ } else {
+ return 0;
+ }
+}
+
+void
+grn_rset_recinfo_set_min(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ int64_t min)
+{
+ int64_t *min_address;
+
+ min_address = grn_rset_recinfo_get_min_(ctx, ri, table);
+ if (!min_address) {
+ return;
+ }
+
+ *min_address = min;
+}
+
+int64_t *
+grn_rset_recinfo_get_sum_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ grn_table_group_flags flags;
+ byte *values;
+
+ flags = DB_OBJ(table)->flags.group;
+ if (!(flags & GRN_TABLE_GROUP_CALC_SUM)) {
+ return NULL;
+ }
+
+ values = (((byte *)ri->subrecs) +
+ GRN_RSET_SUBRECS_SIZE(DB_OBJ(table)->subrec_size,
+ DB_OBJ(table)->max_n_subrecs));
+
+ if (flags & GRN_TABLE_GROUP_CALC_MAX) {
+ values += GRN_RSET_MAX_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_MIN) {
+ values += GRN_RSET_MIN_SIZE;
+ }
+
+ return (int64_t *)values;
+}
+
+int64_t
+grn_rset_recinfo_get_sum(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ int64_t *sum_address;
+
+ sum_address = grn_rset_recinfo_get_sum_(ctx, ri, table);
+ if (sum_address) {
+ return *sum_address;
+ } else {
+ return 0;
+ }
+}
+
+void
+grn_rset_recinfo_set_sum(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ int64_t sum)
+{
+ int64_t *sum_address;
+
+ sum_address = grn_rset_recinfo_get_sum_(ctx, ri, table);
+ if (!sum_address) {
+ return;
+ }
+
+ *sum_address = sum;
+}
+
+double *
+grn_rset_recinfo_get_avg_(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ grn_table_group_flags flags;
+ byte *values;
+
+ flags = DB_OBJ(table)->flags.group;
+ if (!(flags & GRN_TABLE_GROUP_CALC_AVG)) {
+ return NULL;
+ }
+
+ values = (((byte *)ri->subrecs) +
+ GRN_RSET_SUBRECS_SIZE(DB_OBJ(table)->subrec_size,
+ DB_OBJ(table)->max_n_subrecs));
+
+ if (flags & GRN_TABLE_GROUP_CALC_MAX) {
+ values += GRN_RSET_MAX_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_MIN) {
+ values += GRN_RSET_MIN_SIZE;
+ }
+ if (flags & GRN_TABLE_GROUP_CALC_SUM) {
+ values += GRN_RSET_SUM_SIZE;
+ }
+
+ return (double *)values;
+}
+
+double
+grn_rset_recinfo_get_avg(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table)
+{
+ double *avg_address;
+
+ avg_address = grn_rset_recinfo_get_avg_(ctx, ri, table);
+ if (avg_address) {
+ return *avg_address;
+ } else {
+ return 0;
+ }
+}
+
+void
+grn_rset_recinfo_set_avg(grn_ctx *ctx,
+ grn_rset_recinfo *ri,
+ grn_obj *table,
+ double avg)
+{
+ double *avg_address;
+
+ avg_address = grn_rset_recinfo_get_avg_(ctx, ri, table);
+ if (!avg_address) {
+ return;
+ }
+
+ *avg_address = avg;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/scanner.c b/storage/mroonga/vendor/groonga/lib/scanner.c
new file mode 100644
index 00000000..fa562fa1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/scanner.c
@@ -0,0 +1,73 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_scanner.h"
+
+grn_scanner *
+grn_scanner_open(grn_ctx *ctx,
+ grn_obj *expr,
+ grn_operator op,
+ grn_bool record_exist)
+{
+ grn_scanner *scanner;
+
+ scanner = GRN_MALLOC(sizeof(grn_scanner));
+ if (!scanner) {
+ return NULL;
+ }
+
+ scanner->source_expr = expr;
+ scanner->expr = grn_expr_rewrite(ctx, expr);
+ if (!scanner->expr) {
+ scanner->expr = expr;
+ }
+
+ scanner->sis = grn_scan_info_build(ctx,
+ scanner->expr,
+ &(scanner->n_sis),
+ op,
+ record_exist);
+ if (!scanner->sis) {
+ grn_scanner_close(ctx, scanner);
+ return NULL;
+ }
+
+ return scanner;
+}
+
+void
+grn_scanner_close(grn_ctx *ctx, grn_scanner *scanner)
+{
+ if (!scanner) {
+ return;
+ }
+
+ if (scanner->sis) {
+ uint i;
+ for (i = 0; i < scanner->n_sis; i++) {
+ grn_scan_info_close(ctx, scanner->sis[i]);
+ }
+ GRN_FREE(scanner->sis);
+ }
+
+ if (scanner->expr != scanner->source_expr) {
+ grn_obj_close(ctx, scanner->expr);
+ }
+
+ GRN_FREE(scanner);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/scorer.c b/storage/mroonga/vendor/groonga/lib/scorer.c
new file mode 100644
index 00000000..5791ad35
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/scorer.c
@@ -0,0 +1,189 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+
+#include "grn.h"
+#include "grn_db.h"
+#include "grn_scorer.h"
+#include <groonga/scorer.h>
+
+grn_obj *
+grn_scorer_matched_record_get_table(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->table;
+}
+
+grn_obj *
+grn_scorer_matched_record_get_lexicon(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->lexicon;
+}
+
+grn_id
+grn_scorer_matched_record_get_id(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->id;
+}
+
+grn_obj *
+grn_scorer_matched_record_get_terms(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return &(record->terms);
+}
+
+grn_obj *
+grn_scorer_matched_record_get_term_weights(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return &(record->term_weights);
+}
+
+unsigned int
+grn_scorer_matched_record_get_total_term_weights(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->total_term_weights;
+}
+
+long long unsigned int
+grn_scorer_matched_record_get_n_documents(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->n_documents;
+}
+
+unsigned int
+grn_scorer_matched_record_get_n_occurrences(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->n_occurrences;
+}
+
+long long unsigned int
+grn_scorer_matched_record_get_n_candidates(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->n_candidates;
+}
+
+unsigned int
+grn_scorer_matched_record_get_n_tokens(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->n_tokens;
+}
+
+int
+grn_scorer_matched_record_get_weight(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ return record->weight;
+}
+
+grn_obj *
+grn_scorer_matched_record_get_arg(grn_ctx *ctx,
+ grn_scorer_matched_record *record,
+ unsigned int i)
+{
+ grn_expr *expr;
+ grn_expr_code *codes_original;
+ uint32_t codes_curr_original;
+ grn_obj *arg;
+
+ if (!record->args_expr) {
+ return NULL;
+ }
+
+ expr = (grn_expr *)(record->args_expr);
+ /* TODO: support getting column value */
+ codes_original = expr->codes;
+ codes_curr_original = expr->codes_curr;
+ expr->codes += record->args_expr_offset;
+ expr->codes_curr = 1; /* TODO: support 1 or more codes */
+ arg = grn_expr_exec(ctx, (grn_obj *)expr, 0);
+ expr->codes_curr = codes_curr_original;
+ expr->codes = codes_original;
+
+ return arg;
+}
+
+unsigned int
+grn_scorer_matched_record_get_n_args(grn_ctx *ctx,
+ grn_scorer_matched_record *record)
+{
+ grn_expr *expr;
+ grn_expr_code *codes;
+ unsigned int n_args = 0;
+
+ if (!record->args_expr) {
+ return 0;
+ }
+
+ expr = (grn_expr *)(record->args_expr);
+ codes = expr->codes + record->args_expr_offset;
+ if (codes[0].op == GRN_OP_CALL) {
+ return 0;
+ }
+
+ n_args++;
+ for (; codes[0].op != GRN_OP_CALL; codes++) {
+ if (codes[0].op == GRN_OP_COMMA) {
+ n_args++;
+ }
+ }
+
+ return n_args;
+}
+
+grn_rc
+grn_scorer_register(grn_ctx *ctx,
+ const char *scorer_name_ptr,
+ int scorer_name_length,
+ grn_scorer_score_func *score)
+{
+ if (scorer_name_length == -1) {
+ scorer_name_length = strlen(scorer_name_ptr);
+ }
+
+ {
+ grn_obj *scorer_object = grn_proc_create(ctx,
+ scorer_name_ptr,
+ scorer_name_length,
+ GRN_PROC_SCORER,
+ NULL, NULL, NULL, 0, NULL);
+ if (scorer_object == NULL) {
+ GRN_PLUGIN_ERROR(ctx, GRN_SCORER_ERROR,
+ "[scorer][%.*s] failed to grn_proc_create()",
+ scorer_name_length, scorer_name_ptr);
+ return ctx->rc;
+ }
+
+ {
+ grn_proc *scorer = (grn_proc *)scorer_object;
+ scorer->callbacks.scorer.score = score;
+ }
+ }
+
+ return GRN_SUCCESS;
+}
+
diff --git a/storage/mroonga/vendor/groonga/lib/scorers.c b/storage/mroonga/vendor/groonga/lib/scorers.c
new file mode 100644
index 00000000..44a3e9b4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/scorers.c
@@ -0,0 +1,96 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_db.h"
+
+#include <groonga/scorer.h>
+
+#include <math.h>
+
+static double
+scorer_tf_idf(grn_ctx *ctx, grn_scorer_matched_record *record)
+{
+ double min_score = 1.0;
+ double tf;
+ double n_all_documents;
+ double n_candidates;
+ double n_tokens;
+ double n_estimated_match_documents;
+
+ tf = grn_scorer_matched_record_get_n_occurrences(ctx, record) +
+ grn_scorer_matched_record_get_total_term_weights(ctx, record);
+ n_all_documents = grn_scorer_matched_record_get_n_documents(ctx, record);
+ n_candidates = grn_scorer_matched_record_get_n_candidates(ctx, record);
+ n_tokens = grn_scorer_matched_record_get_n_tokens(ctx, record);
+ n_estimated_match_documents = n_candidates / n_tokens;
+
+ if (n_estimated_match_documents >= n_all_documents) {
+ return min_score;
+ } else {
+ double idf;
+ double tf_idf;
+
+ idf = log(n_all_documents / n_estimated_match_documents);
+ tf_idf = tf * idf;
+ return fmax(tf_idf, min_score);
+ }
+}
+
+static double
+scorer_tf_at_most(grn_ctx *ctx, grn_scorer_matched_record *record)
+{
+ double tf;
+ double max;
+ grn_obj *max_raw;
+
+ tf = grn_scorer_matched_record_get_n_occurrences(ctx, record) +
+ grn_scorer_matched_record_get_total_term_weights(ctx, record);
+ max_raw = grn_scorer_matched_record_get_arg(ctx, record, 0);
+
+ if (!max_raw) {
+ return tf;
+ }
+
+ if (max_raw->header.type != GRN_BULK) {
+ return tf;
+ }
+
+ if (max_raw->header.domain == GRN_DB_FLOAT) {
+ max = GRN_FLOAT_VALUE(max_raw);
+ } else {
+ grn_obj casted_max_raw;
+ GRN_FLOAT_INIT(&casted_max_raw, 0);
+ if (grn_obj_cast(ctx, max_raw, &casted_max_raw, GRN_FALSE) != GRN_SUCCESS) {
+ GRN_OBJ_FIN(ctx, &casted_max_raw);
+ return tf;
+ } else {
+ max = GRN_FLOAT_VALUE(&casted_max_raw);
+ }
+ GRN_OBJ_FIN(ctx, &casted_max_raw);
+ }
+
+ return fmin(tf, max);
+}
+
+grn_rc
+grn_db_init_builtin_scorers(grn_ctx *ctx)
+{
+ grn_scorer_register(ctx, "scorer_tf_idf", -1, scorer_tf_idf);
+ grn_scorer_register(ctx, "scorer_tf_at_most", -1, scorer_tf_at_most);
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/snip.c b/storage/mroonga/vendor/groonga/lib/snip.c
new file mode 100644
index 00000000..4693dc2b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/snip.c
@@ -0,0 +1,841 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2009-2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include <string.h>
+#include <stddef.h>
+#include "grn_snip.h"
+#include "grn_ctx.h"
+
+#if !defined MAX
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#if !defined MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+static int
+grn_bm_check_euc(const unsigned char *x, const size_t y)
+{
+ const unsigned char *p;
+ for (p = x + y - 1; p >= x && *p >= 0x80U; p--);
+ return (int) ((x + y - p) & 1);
+}
+
+static int
+grn_bm_check_sjis(const unsigned char *x, const size_t y)
+{
+ const unsigned char *p;
+ for (p = x + y - 1; p >= x; p--)
+ if ((*p < 0x81U) || (*p > 0x9fU && *p < 0xe0U) || (*p > 0xfcU))
+ break;
+ return (int) ((x + y - p) & 1);
+}
+
+/*
+static void
+grn_bm_suffixes(const unsigned char *x, size_t m, size_t *suff)
+{
+ size_t f, g;
+ intptr_t i;
+ f = 0;
+ suff[m - 1] = m;
+ g = m - 1;
+ for (i = m - 2; i >= 0; --i) {
+ if (i > (intptr_t) g && suff[i + m - 1 - f] < i - g)
+ suff[i] = suff[i + m - 1 - f];
+ else {
+ if (i < (intptr_t) g)
+ g = i;
+ f = i;
+ while (g > 0 && x[g] == x[g + m - 1 - f])
+ --g;
+ suff[i] = f - g;
+ }
+ }
+}
+*/
+
+static void
+grn_bm_preBmBc(const unsigned char *x, size_t m, size_t *bmBc)
+{
+ size_t i;
+ for (i = 0; i < ASIZE; ++i) {
+ bmBc[i] = m;
+ }
+ for (i = 0; i < m - 1; ++i) {
+ bmBc[(unsigned int) x[i]] = m - (i + 1);
+ }
+}
+
+#define GRN_BM_COMPARE do { \
+ if (string_checks[found]) { \
+ size_t offset = cond->last_offset, found_alpha_head = cond->found_alpha_head; \
+ /* calc real offset */\
+ for (i = cond->last_found; i < found; i++) { \
+ if (string_checks[i] > 0) { \
+ found_alpha_head = i; \
+ offset += string_checks[i]; \
+ } \
+ } \
+ /* if real offset is in a character, move it the head of the character */ \
+ if (string_checks[found] < 0) { \
+ offset -= string_checks[found_alpha_head]; \
+ cond->last_found = found_alpha_head; \
+ } else { \
+ cond->last_found = found; \
+ } \
+ cond->start_offset = cond->last_offset = offset; \
+ if (flags & GRN_SNIP_SKIP_LEADING_SPACES) { \
+ while (cond->start_offset < string_original_length_in_bytes && \
+ (i = grn_isspace(string_original + cond->start_offset, \
+ string_encoding))) { cond->start_offset += i; } \
+ } \
+ for (i = cond->last_found; i < found + m; i++) { \
+ if (string_checks[i] > 0) { \
+ offset += string_checks[i]; \
+ } \
+ } \
+ cond->end_offset = offset; \
+ cond->found = found + shift; \
+ cond->found_alpha_head = found_alpha_head; \
+ /* printf("bm: cond:%p found:%zd last_found:%zd st_off:%zd ed_off:%zd\n", cond, cond->found,cond->last_found,cond->start_offset,cond->end_offset); */ \
+ return; \
+ } \
+} while (0)
+
+#define GRN_BM_BM_COMPARE do { \
+ if (p[-2] == ck) { \
+ for (i = 3; i <= m && p[-(intptr_t)i] == cp[-(intptr_t)i]; ++i) { \
+ } \
+ if (i > m) { \
+ found = p - y - m; \
+ GRN_BM_COMPARE; \
+ } \
+ } \
+} while (0)
+
+void
+grn_bm_tunedbm(grn_ctx *ctx, snip_cond *cond, grn_obj *string, int flags)
+{
+ register unsigned char *limit, ck;
+ register const unsigned char *p, *cp;
+ register size_t *bmBc, delta1, i;
+
+ const unsigned char *x;
+ unsigned char *y;
+ size_t shift, found;
+
+ const char *string_original;
+ unsigned int string_original_length_in_bytes;
+ const short *string_checks;
+ grn_encoding string_encoding;
+ const char *string_norm, *keyword_norm;
+ unsigned int n, m;
+
+ grn_string_get_original(ctx, string,
+ &string_original, &string_original_length_in_bytes);
+ string_checks = grn_string_get_checks(ctx, string);
+ string_encoding = grn_string_get_encoding(ctx, string);
+ grn_string_get_normalized(ctx, string, &string_norm, &n, NULL);
+ grn_string_get_normalized(ctx, cond->keyword, &keyword_norm, &m, NULL);
+
+ y = (unsigned char *)string_norm;
+ if (m == 1) {
+ if (n > cond->found) {
+ shift = 1;
+ p = memchr(y + cond->found, keyword_norm[0], n - cond->found);
+ if (p != NULL) {
+ found = p - y;
+ GRN_BM_COMPARE;
+ }
+ }
+ cond->stopflag = SNIPCOND_STOP;
+ return;
+ }
+
+ x = (unsigned char *)keyword_norm;
+ bmBc = cond->bmBc;
+ shift = cond->shift;
+
+ /* Restart */
+ p = y + m + cond->found;
+ cp = x + m;
+ ck = cp[-2];
+
+ /* 12 means 1(initial offset) + 10 (in loop) + 1 (shift) */
+ if (n - cond->found > 12 * m) {
+ limit = y + n - 11 * m;
+ while (p <= limit) {
+ p += bmBc[p[-1]];
+ if(!(delta1 = bmBc[p[-1]])) {
+ goto check;
+ }
+ p += delta1;
+ p += bmBc[p[-1]];
+ p += bmBc[p[-1]];
+ if(!(delta1 = bmBc[p[-1]])) {
+ goto check;
+ }
+ p += delta1;
+ p += bmBc[p[-1]];
+ p += bmBc[p[-1]];
+ if(!(delta1 = bmBc[p[-1]])) {
+ goto check;
+ }
+ p += delta1;
+ p += bmBc[p[-1]];
+ p += bmBc[p[-1]];
+ continue;
+ check:
+ GRN_BM_BM_COMPARE;
+ p += shift;
+ }
+ }
+ /* limit check + search */
+ limit = y + n;
+ while(p <= limit) {
+ if (!(delta1 = bmBc[p[-1]])) {
+ GRN_BM_BM_COMPARE;
+ p += shift;
+ }
+ p += delta1;
+ }
+ cond->stopflag = SNIPCOND_STOP;
+}
+
+static size_t
+count_mapped_chars(const char *str, const char *end)
+{
+ const char *p;
+ size_t dl;
+
+ dl = 0;
+ for (p = str; p != end; p++) {
+ switch (*p) {
+ case '<':
+ case '>':
+ dl += 4; /* &lt; or &gt; */
+ break;
+ case '&':
+ dl += 5; /* &amp; */
+ break;
+ case '"':
+ dl += 6; /* &quot; */
+ break;
+ default:
+ dl++;
+ break;
+ }
+ }
+ return dl;
+}
+
+grn_rc
+grn_snip_cond_close(grn_ctx *ctx, snip_cond *cond)
+{
+ if (!cond) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (cond->keyword) {
+ grn_obj_close(ctx, cond->keyword);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_snip_cond_init(grn_ctx *ctx, snip_cond *sc, const char *keyword, unsigned int keyword_len,
+ grn_encoding enc, grn_obj *normalizer, int flags)
+{
+ const char *norm;
+ unsigned int norm_blen;
+ int f = GRN_STR_REMOVEBLANK;
+ memset(sc, 0, sizeof(snip_cond));
+ if (!(sc->keyword = grn_string_open(ctx, keyword, keyword_len,
+ normalizer, f))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "grn_string_open on snip_cond_init failed!");
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ grn_string_get_normalized(ctx, sc->keyword, &norm, &norm_blen, NULL);
+ if (!norm_blen) {
+ grn_snip_cond_close(ctx, sc);
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (norm_blen != 1) {
+ grn_bm_preBmBc((unsigned char *)norm, norm_blen, sc->bmBc);
+ sc->shift = sc->bmBc[(unsigned char)norm[norm_blen - 1]];
+ sc->bmBc[(unsigned char)norm[norm_blen - 1]] = 0;
+ }
+ return GRN_SUCCESS;
+}
+
+void
+grn_snip_cond_reinit(snip_cond *cond)
+{
+ cond->found = 0;
+ cond->last_found = 0;
+ cond->last_offset = 0;
+ cond->start_offset = 0;
+ cond->end_offset = 0;
+
+ cond->count = 0;
+ cond->stopflag = SNIPCOND_NONSTOP;
+}
+
+inline static char *
+grn_snip_strndup(grn_ctx *ctx, const char *string, unsigned int string_len)
+{
+ char *copied_string;
+
+ copied_string = GRN_MALLOC(string_len + 1);
+ if (!copied_string) {
+ return NULL;
+ }
+ grn_memcpy(copied_string, string, string_len);
+ copied_string[string_len]= '\0'; /* not required, but for ql use */
+ return copied_string;
+}
+
+inline static grn_rc
+grn_snip_cond_set_tag(grn_ctx *ctx,
+ const char **dest_tag, size_t *dest_tag_len,
+ const char *tag, unsigned int tag_len,
+ const char *default_tag, unsigned int default_tag_len,
+ int copy_tag)
+{
+ if (tag) {
+ if (copy_tag) {
+ char *copied_tag;
+ copied_tag = grn_snip_strndup(ctx, tag, tag_len);
+ if (!copied_tag) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ *dest_tag = copied_tag;
+ } else {
+ *dest_tag = tag;
+ }
+ *dest_tag_len = tag_len;
+ } else {
+ *dest_tag = default_tag;
+ *dest_tag_len = default_tag_len;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_snip_set_normalizer(grn_ctx *ctx, grn_obj *snip,
+ grn_obj *normalizer)
+{
+ grn_snip *snip_;
+ if (!snip) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ snip_ = (grn_snip *)snip;
+ snip_->normalizer = normalizer;
+ return GRN_SUCCESS;
+}
+
+grn_obj *
+grn_snip_get_normalizer(grn_ctx *ctx, grn_obj *snip)
+{
+ grn_snip *snip_;
+
+ if (!snip) {
+ return NULL;
+ }
+
+ snip_ = (grn_snip *)snip;
+ return snip_->normalizer;
+}
+
+grn_rc
+grn_snip_add_cond(grn_ctx *ctx, grn_obj *snip,
+ const char *keyword, unsigned int keyword_len,
+ const char *opentag, unsigned int opentag_len,
+ const char *closetag, unsigned int closetag_len)
+{
+ grn_rc rc;
+ int copy_tag;
+ snip_cond *cond;
+ unsigned int norm_blen;
+ grn_snip *snip_;
+
+ snip_ = (grn_snip *)snip;
+ if (!snip_ || !keyword || !keyword_len || snip_->cond_len >= MAX_SNIP_COND_COUNT) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ cond = snip_->cond + snip_->cond_len;
+ if ((rc = grn_snip_cond_init(ctx, cond, keyword, keyword_len,
+ snip_->encoding, snip_->normalizer, snip_->flags))) {
+ return rc;
+ }
+ grn_string_get_normalized(ctx, cond->keyword, NULL, &norm_blen, NULL);
+ if (norm_blen > snip_->width) {
+ grn_snip_cond_close(ctx, cond);
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ copy_tag = snip_->flags & GRN_SNIP_COPY_TAG;
+ rc = grn_snip_cond_set_tag(ctx,
+ &(cond->opentag), &(cond->opentag_len),
+ opentag, opentag_len,
+ snip_->defaultopentag, snip_->defaultopentag_len,
+ copy_tag);
+ if (rc) {
+ grn_snip_cond_close(ctx, cond);
+ return rc;
+ }
+
+ rc = grn_snip_cond_set_tag(ctx,
+ &(cond->closetag), &(cond->closetag_len),
+ closetag, closetag_len,
+ snip_->defaultclosetag, snip_->defaultclosetag_len,
+ copy_tag);
+ if (rc) {
+ if (opentag && copy_tag) {
+ GRN_FREE((void *)cond->opentag);
+ }
+ grn_snip_cond_close(ctx, cond);
+ return rc;
+ }
+
+ snip_->cond_len++;
+ return GRN_SUCCESS;
+}
+
+static size_t
+grn_snip_find_firstbyte(const char *string, grn_encoding encoding, size_t offset,
+ size_t doffset)
+{
+ switch (encoding) {
+ case GRN_ENC_EUC_JP:
+ while (!(grn_bm_check_euc((unsigned char *) string, offset)))
+ offset += doffset;
+ break;
+ case GRN_ENC_SJIS:
+ if (!(grn_bm_check_sjis((unsigned char *) string, offset)))
+ offset += doffset;
+ break;
+ case GRN_ENC_UTF8:
+ while ((signed char)string[offset] <= (signed char)0xc0)
+ offset += doffset;
+ break;
+ default:
+ break;
+ }
+ return offset;
+}
+
+inline static grn_rc
+grn_snip_set_default_tag(grn_ctx *ctx,
+ const char **dest_tag, size_t *dest_tag_len,
+ const char *tag, unsigned int tag_len,
+ int copy_tag)
+{
+ if (copy_tag && tag) {
+ char *copied_tag;
+ copied_tag = grn_snip_strndup(ctx, tag, tag_len);
+ if (!copied_tag) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ *dest_tag = copied_tag;
+ } else {
+ *dest_tag = tag;
+ }
+ *dest_tag_len = tag_len;
+ return GRN_SUCCESS;
+}
+
+grn_obj *
+grn_snip_open(grn_ctx *ctx, int flags, unsigned int width,
+ unsigned int max_results,
+ const char *defaultopentag, unsigned int defaultopentag_len,
+ const char *defaultclosetag, unsigned int defaultclosetag_len,
+ grn_snip_mapping *mapping)
+{
+ int copy_tag;
+ grn_snip *ret = NULL;
+ if (!(ret = GRN_MALLOC(sizeof(grn_snip)))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_snip allocation failed on grn_snip_open");
+ return NULL;
+ }
+ if (max_results > MAX_SNIP_RESULT_COUNT || max_results == 0) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "max_results is invalid on grn_snip_open");
+ GRN_FREE(ret);
+ return NULL;
+ }
+ GRN_API_ENTER;
+ ret->encoding = ctx->encoding;
+ ret->flags = flags;
+ ret->width = width;
+ ret->max_results = max_results;
+ ret->defaultopentag = NULL;
+ ret->defaultclosetag = NULL;
+
+ copy_tag = flags & GRN_SNIP_COPY_TAG;
+ if (grn_snip_set_default_tag(ctx,
+ &(ret->defaultopentag),
+ &(ret->defaultopentag_len),
+ defaultopentag, defaultopentag_len,
+ copy_tag)) {
+ GRN_FREE(ret);
+ GRN_API_RETURN(NULL);
+ }
+
+ if (grn_snip_set_default_tag(ctx,
+ &(ret->defaultclosetag),
+ &(ret->defaultclosetag_len),
+ defaultclosetag, defaultclosetag_len,
+ copy_tag)) {
+ if (copy_tag && ret->defaultopentag) {
+ GRN_FREE((void *)ret->defaultopentag);
+ }
+ GRN_FREE(ret);
+ GRN_API_RETURN(NULL);
+ }
+
+ ret->cond_len = 0;
+ ret->mapping = mapping;
+ ret->nstr = NULL;
+ ret->tag_count = 0;
+ ret->snip_count = 0;
+ if (ret->flags & GRN_SNIP_NORMALIZE) {
+ ret->normalizer = GRN_NORMALIZER_AUTO;
+ } else {
+ ret->normalizer = NULL;
+ }
+
+ GRN_DB_OBJ_SET_TYPE(ret, GRN_SNIP);
+ {
+ grn_obj *db;
+ grn_id id;
+ db = grn_ctx_db(ctx);
+ id = grn_obj_register(ctx, db, NULL, 0);
+ DB_OBJ(ret)->header.domain = GRN_ID_NIL;
+ DB_OBJ(ret)->range = GRN_ID_NIL;
+ grn_db_obj_init(ctx, db, id, DB_OBJ(ret));
+ }
+
+ GRN_API_RETURN((grn_obj *)ret);
+}
+
+static grn_rc
+exec_clean(grn_ctx *ctx, grn_snip *snip)
+{
+ snip_cond *cond, *cond_end;
+ if (snip->nstr) {
+ grn_obj_close(ctx, snip->nstr);
+ snip->nstr = NULL;
+ }
+ snip->tag_count = 0;
+ snip->snip_count = 0;
+ for (cond = snip->cond, cond_end = cond + snip->cond_len;
+ cond < cond_end; cond++) {
+ grn_snip_cond_reinit(cond);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_snip_close(grn_ctx *ctx, grn_snip *snip)
+{
+ snip_cond *cond, *cond_end;
+ if (!snip) { return GRN_INVALID_ARGUMENT; }
+ GRN_API_ENTER;
+ if (snip->flags & GRN_SNIP_COPY_TAG) {
+ int i;
+ snip_cond *sc;
+ const char *dot = snip->defaultopentag, *dct = snip->defaultclosetag;
+ for (i = snip->cond_len, sc = snip->cond; i; i--, sc++) {
+ if (sc->opentag != dot) { GRN_FREE((void *)sc->opentag); }
+ if (sc->closetag != dct) { GRN_FREE((void *)sc->closetag); }
+ }
+ if (dot) { GRN_FREE((void *)dot); }
+ if (dct) { GRN_FREE((void *)dct); }
+ }
+ if (snip->nstr) {
+ grn_obj_close(ctx, snip->nstr);
+ }
+ for (cond = snip->cond, cond_end = cond + snip->cond_len;
+ cond < cond_end; cond++) {
+ grn_snip_cond_close(ctx, cond);
+ }
+ GRN_FREE(snip);
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_rc
+grn_snip_exec(grn_ctx *ctx, grn_obj *snip, const char *string, unsigned int string_len,
+ unsigned int *nresults, unsigned int *max_tagged_len)
+{
+ size_t i;
+ grn_snip *snip_;
+ int f = GRN_STR_WITH_CHECKS|GRN_STR_REMOVEBLANK;
+ if (!snip || !string || !nresults || !max_tagged_len) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_ENTER;
+ snip_ = (grn_snip *)snip;
+ exec_clean(ctx, snip_);
+ *nresults = 0;
+ snip_->nstr = grn_string_open(ctx, string, string_len, snip_->normalizer, f);
+ if (!snip_->nstr) {
+ exec_clean(ctx, snip_);
+ GRN_LOG(ctx, GRN_LOG_ALERT, "grn_string_open on grn_snip_exec failed !");
+ GRN_API_RETURN(ctx->rc);
+ }
+ for (i = 0; i < snip_->cond_len; i++) {
+ grn_bm_tunedbm(ctx, snip_->cond + i, snip_->nstr, snip_->flags);
+ }
+
+ {
+ _snip_tag_result *tag_result = snip_->tag_result;
+ _snip_result *snip_result = snip_->snip_result;
+ size_t last_end_offset = 0, last_last_end_offset = 0;
+ unsigned int unfound_cond_count = snip_->cond_len;
+
+ *max_tagged_len = 0;
+ while (1) {
+ size_t tagged_len = 0, last_tag_end = 0;
+ int_least8_t all_stop = 1, found_cond = 0;
+ snip_result->tag_count = 0;
+
+ while (1) {
+ size_t min_start_offset = (size_t) -1;
+ size_t max_end_offset = 0;
+ snip_cond *cond = NULL;
+
+ /* get condition which have minimum offset and is not stopped */
+ for (i = 0; i < snip_->cond_len; i++) {
+ if (snip_->cond[i].stopflag == SNIPCOND_NONSTOP &&
+ (min_start_offset > snip_->cond[i].start_offset ||
+ (min_start_offset == snip_->cond[i].start_offset &&
+ max_end_offset < snip_->cond[i].end_offset))) {
+ min_start_offset = snip_->cond[i].start_offset;
+ max_end_offset = snip_->cond[i].end_offset;
+ cond = &snip_->cond[i];
+ }
+ }
+ if (!cond) {
+ break;
+ }
+ /* check whether condtion is the first condition in snippet */
+ if (snip_result->tag_count == 0) {
+ /* skip condition if the number of rest snippet field is smaller than */
+ /* the number of unfound keywords. */
+ if (snip_->max_results - *nresults <= unfound_cond_count && cond->count > 0) {
+ int_least8_t exclude_other_cond = 1;
+ for (i = 0; i < snip_->cond_len; i++) {
+ if ((snip_->cond + i) != cond
+ && snip_->cond[i].end_offset <= cond->start_offset + snip_->width
+ && snip_->cond[i].count == 0) {
+ exclude_other_cond = 0;
+ }
+ }
+ if (exclude_other_cond) {
+ grn_bm_tunedbm(ctx, cond, snip_->nstr, snip_->flags);
+ continue;
+ }
+ }
+ snip_result->start_offset = cond->start_offset;
+ snip_result->first_tag_result_idx = snip_->tag_count;
+ } else {
+ if (cond->start_offset >= snip_result->start_offset + snip_->width) {
+ break;
+ }
+ /* check nesting to make valid HTML */
+ /* ToDo: allow <test><te>te</te><st>st</st></test> */
+ if (cond->start_offset < last_tag_end) {
+ grn_bm_tunedbm(ctx, cond, snip_->nstr, snip_->flags);
+ continue;
+ }
+ }
+ if (cond->end_offset > snip_result->start_offset + snip_->width) {
+ /* If a keyword gets across a snippet, */
+ /* it was skipped and never to be tagged. */
+ cond->stopflag = SNIPCOND_ACROSS;
+ grn_bm_tunedbm(ctx, cond, snip_->nstr, snip_->flags);
+ } else {
+ found_cond = 1;
+ if (cond->count == 0) {
+ unfound_cond_count--;
+ }
+ cond->count++;
+ last_end_offset = cond->end_offset;
+
+ tag_result->cond = cond;
+ tag_result->start_offset = cond->start_offset;
+ tag_result->end_offset = last_tag_end = cond->end_offset;
+
+ snip_result->tag_count++;
+ tag_result++;
+ tagged_len += cond->opentag_len + cond->closetag_len;
+ if (++snip_->tag_count >= MAX_SNIP_TAG_COUNT) {
+ break;
+ }
+ grn_bm_tunedbm(ctx, cond, snip_->nstr, snip_->flags);
+ }
+ }
+ if (!found_cond) {
+ break;
+ }
+ if (snip_result->start_offset + last_end_offset < snip_->width) {
+ snip_result->start_offset = 0;
+ } else {
+ snip_result->start_offset =
+ MAX(MIN
+ ((snip_result->start_offset + last_end_offset - snip_->width) / 2,
+ string_len - snip_->width), last_last_end_offset);
+ }
+ snip_result->start_offset =
+ grn_snip_find_firstbyte(string, snip_->encoding, snip_result->start_offset, 1);
+
+ snip_result->end_offset = snip_result->start_offset + snip_->width;
+ if (snip_result->end_offset < string_len) {
+ snip_result->end_offset =
+ grn_snip_find_firstbyte(string, snip_->encoding, snip_result->end_offset, -1);
+ } else {
+ snip_result->end_offset = string_len;
+ }
+ last_last_end_offset = snip_result->end_offset;
+
+ if (snip_->mapping == (grn_snip_mapping *) -1) {
+ tagged_len +=
+ count_mapped_chars(&string[snip_result->start_offset],
+ &string[snip_result->end_offset]) + 1;
+ } else {
+ tagged_len += snip_result->end_offset - snip_result->start_offset + 1;
+ }
+
+ *max_tagged_len = MAX(*max_tagged_len, tagged_len);
+
+ snip_result->last_tag_result_idx = snip_->tag_count - 1;
+ (*nresults)++;
+ snip_result++;
+
+ if (*nresults == snip_->max_results || snip_->tag_count == MAX_SNIP_TAG_COUNT) {
+ break;
+ }
+ for (i = 0; i < snip_->cond_len; i++) {
+ if (snip_->cond[i].stopflag != SNIPCOND_STOP) {
+ all_stop = 0;
+ snip_->cond[i].stopflag = SNIPCOND_NONSTOP;
+ }
+ }
+ if (all_stop) {
+ break;
+ }
+ }
+ }
+ snip_->snip_count = *nresults;
+ snip_->string = string;
+
+ snip_->max_tagged_len = *max_tagged_len;
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_rc
+grn_snip_get_result(grn_ctx *ctx, grn_obj *snip, const unsigned int index, char *result, unsigned int *result_len)
+{
+ char *p;
+ size_t i, j, k;
+ _snip_result *sres;
+ grn_snip *snip_;
+
+ snip_ = (grn_snip *)snip;
+ if (snip_->snip_count <= index || !snip_->nstr) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ GRN_ASSERT(snip_->snip_count != 0 && snip_->tag_count != 0);
+
+ GRN_API_ENTER;
+ sres = &snip_->snip_result[index];
+ j = sres->first_tag_result_idx;
+ for (p = result, i = sres->start_offset; i < sres->end_offset; i++) {
+ for (; j <= sres->last_tag_result_idx && snip_->tag_result[j].start_offset == i; j++) {
+ if (snip_->tag_result[j].end_offset > sres->end_offset) {
+ continue;
+ }
+ grn_memcpy(p,
+ snip_->tag_result[j].cond->opentag,
+ snip_->tag_result[j].cond->opentag_len);
+ p += snip_->tag_result[j].cond->opentag_len;
+ }
+
+ if (snip_->mapping == GRN_SNIP_MAPPING_HTML_ESCAPE) {
+ switch (snip_->string[i]) {
+ case '<':
+ *p++ = '&';
+ *p++ = 'l';
+ *p++ = 't';
+ *p++ = ';';
+ break;
+ case '>':
+ *p++ = '&';
+ *p++ = 'g';
+ *p++ = 't';
+ *p++ = ';';
+ break;
+ case '&':
+ *p++ = '&';
+ *p++ = 'a';
+ *p++ = 'm';
+ *p++ = 'p';
+ *p++ = ';';
+ break;
+ case '"':
+ *p++ = '&';
+ *p++ = 'q';
+ *p++ = 'u';
+ *p++ = 'o';
+ *p++ = 't';
+ *p++ = ';';
+ break;
+ default:
+ *p++ = snip_->string[i];
+ break;
+ }
+ } else {
+ *p++ = snip_->string[i];
+ }
+
+ for (k = sres->last_tag_result_idx;
+ snip_->tag_result[k].end_offset <= sres->end_offset; k--) {
+ /* TODO: avoid all loop */
+ if (snip_->tag_result[k].end_offset == i + 1) {
+ grn_memcpy(p,
+ snip_->tag_result[k].cond->closetag,
+ snip_->tag_result[k].cond->closetag_len);
+ p += snip_->tag_result[k].cond->closetag_len;
+ }
+ if (k <= sres->first_tag_result_idx) {
+ break;
+ }
+ };
+ }
+ *p = '\0';
+
+ if(result_len) { *result_len = (unsigned int)(p - result); }
+ GRN_ASSERT((unsigned int)(p - result) <= snip_->max_tagged_len);
+
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/store.c b/storage/mroonga/vendor/groonga/lib/store.c
new file mode 100644
index 00000000..efa400fa
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/store.c
@@ -0,0 +1,2864 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include "grn_str.h"
+#include "grn_store.h"
+#include "grn_ctx_impl.h"
+#include "grn_output.h"
+#include <string.h>
+
+/* rectangular arrays */
+
+#define GRN_RA_W_SEGMENT 22
+#define GRN_RA_SEGMENT_SIZE (1 << GRN_RA_W_SEGMENT)
+
+static grn_ra *
+_grn_ra_create(grn_ctx *ctx, grn_ra *ra, const char *path, unsigned int element_size)
+{
+ grn_io *io;
+ int max_segments, n_elm, w_elm;
+ struct grn_ra_header *header;
+ unsigned int actual_size;
+ if (element_size > GRN_RA_SEGMENT_SIZE) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "element_size too large (%d)", element_size);
+ return NULL;
+ }
+ for (actual_size = 1; actual_size < element_size; actual_size *= 2) ;
+ max_segments = ((GRN_ID_MAX + 1) / GRN_RA_SEGMENT_SIZE) * actual_size;
+ io = grn_io_create(ctx, path, sizeof(struct grn_ra_header),
+ GRN_RA_SEGMENT_SIZE, max_segments, grn_io_auto,
+ GRN_IO_EXPIRE_SEGMENT);
+ if (!io) { return NULL; }
+ header = grn_io_header(io);
+ grn_io_set_type(io, GRN_COLUMN_FIX_SIZE);
+ header->element_size = actual_size;
+ n_elm = GRN_RA_SEGMENT_SIZE / header->element_size;
+ for (w_elm = GRN_RA_W_SEGMENT; (1 << w_elm) > n_elm; w_elm--);
+ ra->io = io;
+ ra->header = header;
+ ra->element_mask = n_elm - 1;
+ ra->element_width = w_elm;
+ return ra;
+}
+
+grn_ra *
+grn_ra_create(grn_ctx *ctx, const char *path, unsigned int element_size)
+{
+ grn_ra *ra = (grn_ra *)GRN_CALLOC(sizeof(grn_ra));
+ if (!ra) {
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(ra, GRN_COLUMN_FIX_SIZE);
+ if (!_grn_ra_create(ctx, ra, path, element_size)) {
+ GRN_FREE(ra);
+ return NULL;
+ }
+ return ra;
+}
+
+grn_ra *
+grn_ra_open(grn_ctx *ctx, const char *path)
+{
+ grn_io *io;
+ int n_elm, w_elm;
+ grn_ra *ra = NULL;
+ struct grn_ra_header *header;
+ uint32_t io_type;
+ io = grn_io_open(ctx, path, grn_io_auto);
+ if (!io) { return NULL; }
+ header = grn_io_header(io);
+ io_type = grn_io_get_type(io);
+ if (io_type != GRN_COLUMN_FIX_SIZE) {
+ ERR(GRN_INVALID_FORMAT,
+ "[column][fix-size] file type must be %#04x: <%#04x>",
+ GRN_COLUMN_FIX_SIZE, io_type);
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ ra = GRN_MALLOCN(grn_ra, 1);
+ if (!ra) {
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ n_elm = GRN_RA_SEGMENT_SIZE / header->element_size;
+ for (w_elm = GRN_RA_W_SEGMENT; (1 << w_elm) > n_elm; w_elm--);
+ GRN_DB_OBJ_SET_TYPE(ra, GRN_COLUMN_FIX_SIZE);
+ ra->io = io;
+ ra->header = header;
+ ra->element_mask = n_elm - 1;
+ ra->element_width = w_elm;
+ return ra;
+}
+
+grn_rc
+grn_ra_info(grn_ctx *ctx, grn_ra *ra, unsigned int *element_size)
+{
+ if (!ra) { return GRN_INVALID_ARGUMENT; }
+ if (element_size) { *element_size = ra->header->element_size; }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ra_close(grn_ctx *ctx, grn_ra *ra)
+{
+ grn_rc rc;
+ if (!ra) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_io_close(ctx, ra->io);
+ GRN_FREE(ra);
+ return rc;
+}
+
+grn_rc
+grn_ra_remove(grn_ctx *ctx, const char *path)
+{
+ if (!path) { return GRN_INVALID_ARGUMENT; }
+ return grn_io_remove(ctx, path);
+}
+
+grn_rc
+grn_ra_truncate(grn_ctx *ctx, grn_ra *ra)
+{
+ grn_rc rc;
+ const char *io_path;
+ char *path;
+ unsigned int element_size;
+ if ((io_path = grn_io_path(ra->io)) && *io_path != '\0') {
+ if (!(path = GRN_STRDUP(io_path))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ } else {
+ path = NULL;
+ }
+ element_size = ra->header->element_size;
+ if ((rc = grn_io_close(ctx, ra->io))) { goto exit; }
+ ra->io = NULL;
+ if (path && (rc = grn_io_remove(ctx, path))) { goto exit; }
+ if (!_grn_ra_create(ctx, ra, path, element_size)) {
+ rc = GRN_UNKNOWN_ERROR;
+ }
+exit:
+ if (path) { GRN_FREE(path); }
+ return rc;
+}
+
+void *
+grn_ra_ref(grn_ctx *ctx, grn_ra *ra, grn_id id)
+{
+ void *p = NULL;
+ uint16_t seg;
+ if (id > GRN_ID_MAX) { return NULL; }
+ seg = id >> ra->element_width;
+ GRN_IO_SEG_REF(ra->io, seg, p);
+ if (!p) { return NULL; }
+ return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
+}
+
+grn_rc
+grn_ra_unref(grn_ctx *ctx, grn_ra *ra, grn_id id)
+{
+ uint16_t seg;
+ if (id > GRN_ID_MAX) { return GRN_INVALID_ARGUMENT; }
+ seg = id >> ra->element_width;
+ GRN_IO_SEG_UNREF(ra->io, seg);
+ return GRN_SUCCESS;
+}
+
+void *
+grn_ra_ref_cache(grn_ctx *ctx, grn_ra *ra, grn_id id, grn_ra_cache *cache)
+{
+ void *p = NULL;
+ uint16_t seg;
+ if (id > GRN_ID_MAX) { return NULL; }
+ seg = id >> ra->element_width;
+ if (seg == cache->seg) {
+ p = cache->p;
+ } else {
+ if (cache->seg != -1) { GRN_IO_SEG_UNREF(ra->io, cache->seg); }
+ GRN_IO_SEG_REF(ra->io, seg, p);
+ cache->seg = seg;
+ cache->p = p;
+ }
+ if (!p) { return NULL; }
+ return (void *)(((byte *)p) + ((id & ra->element_mask) * ra->header->element_size));
+}
+
+grn_rc
+grn_ra_cache_fin(grn_ctx *ctx, grn_ra *ra, grn_id id)
+{
+ uint16_t seg;
+ if (id > GRN_ID_MAX) { return GRN_INVALID_ARGUMENT; }
+ seg = id >> ra->element_width;
+ GRN_IO_SEG_UNREF(ra->io, seg);
+ return GRN_SUCCESS;
+}
+
+/**** jagged arrays ****/
+
+#define GRN_JA_W_SEGREGATE_THRESH_V1 7
+#define GRN_JA_W_SEGREGATE_THRESH_V2 16
+#define GRN_JA_W_CAPACITY 38
+#define GRN_JA_W_SEGMENT 22
+
+#define JA_ESEG_VOID (0xffffffffU)
+#define JA_SEGMENT_SIZE (1U << GRN_JA_W_SEGMENT)
+#define JA_W_EINFO 3
+#define JA_W_SEGMENTS_MAX (GRN_JA_W_CAPACITY - GRN_JA_W_SEGMENT)
+#define JA_W_EINFO_IN_A_SEGMENT (GRN_JA_W_SEGMENT - JA_W_EINFO)
+#define JA_N_EINFO_IN_A_SEGMENT (1U << JA_W_EINFO_IN_A_SEGMENT)
+#define JA_M_EINFO_IN_A_SEGMENT (JA_N_EINFO_IN_A_SEGMENT - 1)
+#define JA_N_GARBAGES_IN_A_SEGMENT ((1U << (GRN_JA_W_SEGMENT - 3)) - 2)
+#define JA_N_ELEMENT_VARIATION_V1 (GRN_JA_W_SEGREGATE_THRESH_V1 - JA_W_EINFO + 1)
+#define JA_N_ELEMENT_VARIATION_V2 (GRN_JA_W_SEGREGATE_THRESH_V2 - JA_W_EINFO + 1)
+#define JA_N_DSEGMENTS (1U << JA_W_SEGMENTS_MAX)
+#define JA_N_ESEGMENTS (1U << (GRN_ID_WIDTH - JA_W_EINFO_IN_A_SEGMENT))
+
+typedef struct _grn_ja_einfo grn_ja_einfo;
+
+struct _grn_ja_einfo {
+ union {
+ struct {
+ uint16_t seg;
+ uint16_t pos;
+ uint16_t size;
+ uint8_t c1;
+ uint8_t c2;
+ } n;
+ struct {
+ uint32_t size;
+ uint16_t seg;
+ uint8_t c1;
+ uint8_t c2;
+ } h;
+ uint8_t c[8];
+ } u;
+};
+
+#define ETINY (0x80)
+#define EHUGE (0x40)
+#define ETINY_P(e) ((e)->u.c[7] & ETINY)
+#define ETINY_ENC(e,_size) ((e)->u.c[7] = (_size) + ETINY)
+#define ETINY_DEC(e,_size) ((_size) = (e)->u.c[7] & ~(ETINY|EHUGE))
+#define EHUGE_P(e) ((e)->u.c[7] & EHUGE)
+#define EHUGE_ENC(e,_seg,_size) do {\
+ (e)->u.h.c1 = 0;\
+ (e)->u.h.c2 = EHUGE;\
+ (e)->u.h.seg = (_seg);\
+ (e)->u.h.size = (_size);\
+} while (0)
+#define EHUGE_DEC(e,_seg,_size) do {\
+ (_seg) = (e)->u.h.seg;\
+ (_size) = (e)->u.h.size;\
+} while (0)
+#define EINFO_ENC(e,_seg,_pos,_size) do {\
+ (e)->u.n.c1 = (_pos) >> 16;\
+ (e)->u.n.c2 = ((_size) >> 16);\
+ (e)->u.n.seg = (_seg);\
+ (e)->u.n.pos = (_pos);\
+ (e)->u.n.size = (_size);\
+} while (0)
+#define EINFO_DEC(e,_seg,_pos,_size) do {\
+ (_seg) = (e)->u.n.seg;\
+ (_pos) = ((e)->u.n.c1 << 16) + (e)->u.n.pos;\
+ (_size) = ((e)->u.n.c2 << 16) + (e)->u.n.size;\
+} while (0)
+
+typedef struct {
+ uint32_t seg;
+ uint32_t pos;
+} ja_pos;
+
+typedef struct {
+ uint32_t head;
+ uint32_t tail;
+ uint32_t nrecs;
+ uint32_t next;
+ ja_pos recs[JA_N_GARBAGES_IN_A_SEGMENT];
+} grn_ja_ginfo;
+
+struct grn_ja_header_v1 {
+ uint32_t flags;
+ uint32_t curr_seg;
+ uint32_t curr_pos;
+ uint32_t max_element_size;
+ ja_pos free_elements[JA_N_ELEMENT_VARIATION_V1];
+ uint32_t garbages[JA_N_ELEMENT_VARIATION_V1];
+ uint32_t ngarbages[JA_N_ELEMENT_VARIATION_V1];
+ uint32_t dsegs[JA_N_DSEGMENTS];
+ uint32_t esegs[JA_N_ESEGMENTS];
+};
+
+struct grn_ja_header_v2 {
+ uint32_t flags;
+ uint32_t curr_seg;
+ uint32_t curr_pos;
+ uint32_t max_element_size;
+ ja_pos free_elements[JA_N_ELEMENT_VARIATION_V2];
+ uint32_t garbages[JA_N_ELEMENT_VARIATION_V2];
+ uint32_t ngarbages[JA_N_ELEMENT_VARIATION_V2];
+ uint32_t dsegs[JA_N_DSEGMENTS];
+ uint32_t esegs[JA_N_ESEGMENTS];
+ uint8_t segregate_threshold;
+ uint8_t n_element_variation;
+};
+
+struct grn_ja_header {
+ uint32_t flags;
+ uint32_t *curr_seg;
+ uint32_t *curr_pos;
+ uint32_t max_element_size;
+ ja_pos *free_elements;
+ uint32_t *garbages;
+ uint32_t *ngarbages;
+ uint32_t *dsegs;
+ uint32_t *esegs;
+ uint8_t segregate_threshold;
+ uint8_t n_element_variation;
+};
+
+#define SEG_SEQ (0x10000000U)
+#define SEG_HUGE (0x20000000U)
+#define SEG_EINFO (0x30000000U)
+#define SEG_GINFO (0x40000000U)
+#define SEG_MASK (0xf0000000U)
+
+#define SEGMENTS_AT(ja,seg) ((ja)->header->dsegs[seg])
+#define SEGMENTS_SEGRE_ON(ja,seg,width) (SEGMENTS_AT(ja,seg) = width)
+#define SEGMENTS_SEQ_ON(ja,seg) (SEGMENTS_AT(ja,seg) = SEG_SEQ)
+#define SEGMENTS_HUGE_ON(ja,seg) (SEGMENTS_AT(ja,seg) = SEG_HUGE)
+#define SEGMENTS_EINFO_ON(ja,seg,lseg) (SEGMENTS_AT(ja,seg) = SEG_EINFO|(lseg))
+#define SEGMENTS_GINFO_ON(ja,seg,width) (SEGMENTS_AT(ja,seg) = SEG_GINFO|(width))
+#define SEGMENTS_OFF(ja,seg) (SEGMENTS_AT(ja,seg) = 0)
+
+static grn_ja *
+_grn_ja_create(grn_ctx *ctx, grn_ja *ja, const char *path,
+ unsigned int max_element_size, uint32_t flags)
+{
+ unsigned int i;
+ grn_io *io;
+ struct grn_ja_header *header;
+ struct grn_ja_header_v2 *header_v2;
+ io = grn_io_create(ctx, path, sizeof(struct grn_ja_header_v2),
+ JA_SEGMENT_SIZE, JA_N_DSEGMENTS, grn_io_auto,
+ GRN_IO_EXPIRE_SEGMENT);
+ if (!io) { return NULL; }
+ grn_io_set_type(io, GRN_COLUMN_VAR_SIZE);
+
+ header_v2 = grn_io_header(io);
+ header_v2->flags = flags;
+ header_v2->curr_seg = 0;
+ header_v2->curr_pos = JA_SEGMENT_SIZE;
+ header_v2->max_element_size = max_element_size;
+ for (i = 0; i < JA_N_ESEGMENTS; i++) { header_v2->esegs[i] = JA_ESEG_VOID; }
+ header_v2->segregate_threshold = GRN_JA_W_SEGREGATE_THRESH_V2;
+ header_v2->n_element_variation = JA_N_ELEMENT_VARIATION_V2;
+
+ header = GRN_MALLOCN(struct grn_ja_header, 1);
+ if (!header) {
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ header->flags = header_v2->flags;
+ header->curr_seg = &(header_v2->curr_seg);
+ header->curr_pos = &(header_v2->curr_pos);
+ header->max_element_size = header_v2->max_element_size;
+ header->free_elements = header_v2->free_elements;
+ header->garbages = header_v2->garbages;
+ header->ngarbages = header_v2->ngarbages;
+ header->dsegs = header_v2->dsegs;
+ header->esegs = header_v2->esegs;
+ header->segregate_threshold = header_v2->segregate_threshold;
+ header->n_element_variation = header_v2->n_element_variation;
+
+ ja->io = io;
+ ja->header = header;
+ SEGMENTS_EINFO_ON(ja, 0, 0);
+ header->esegs[0] = 0;
+ return ja;
+}
+
+grn_ja *
+grn_ja_create(grn_ctx *ctx, const char *path, unsigned int max_element_size, uint32_t flags)
+{
+ grn_ja *ja = NULL;
+ ja = (grn_ja *)GRN_CALLOC(sizeof(grn_ja));
+ if (!ja) {
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(ja, GRN_COLUMN_VAR_SIZE);
+ if (!_grn_ja_create(ctx, ja, path, max_element_size, flags)) {
+ GRN_FREE(ja);
+ return NULL;
+ }
+ return ja;
+}
+
+grn_ja *
+grn_ja_open(grn_ctx *ctx, const char *path)
+{
+ grn_io *io;
+ grn_ja *ja = NULL;
+ struct grn_ja_header *header;
+ struct grn_ja_header_v2 *header_v2;
+ uint32_t io_type;
+ io = grn_io_open(ctx, path, grn_io_auto);
+ if (!io) { return NULL; }
+ header_v2 = grn_io_header(io);
+ io_type = grn_io_get_type(io);
+ if (io_type != GRN_COLUMN_VAR_SIZE) {
+ ERR(GRN_INVALID_FORMAT,
+ "[column][var-size] file type must be %#04x: <%#04x>",
+ GRN_COLUMN_VAR_SIZE, io_type);
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ if (header_v2->segregate_threshold == 0) {
+ header_v2->segregate_threshold = GRN_JA_W_SEGREGATE_THRESH_V1;
+ }
+ if (header_v2->n_element_variation == 0) {
+ header_v2->n_element_variation = JA_N_ELEMENT_VARIATION_V1;
+ }
+ ja = GRN_MALLOCN(grn_ja, 1);
+ if (!ja) {
+ grn_io_close(ctx, io);
+ return NULL;
+ }
+ GRN_DB_OBJ_SET_TYPE(ja, GRN_COLUMN_VAR_SIZE);
+ header = GRN_MALLOCN(struct grn_ja_header, 1);
+ if (!header) {
+ grn_io_close(ctx, io);
+ GRN_FREE(ja);
+ return NULL;
+ }
+
+ header->flags = header_v2->flags;
+ header->curr_seg = &(header_v2->curr_seg);
+ header->curr_pos = &(header_v2->curr_pos);
+ header->max_element_size = header_v2->max_element_size;
+ header->segregate_threshold = header_v2->segregate_threshold;
+ header->n_element_variation = header_v2->n_element_variation;
+ if (header->segregate_threshold == GRN_JA_W_SEGREGATE_THRESH_V1) {
+ struct grn_ja_header_v1 *header_v1 = (struct grn_ja_header_v1 *)header_v2;
+ header->free_elements = header_v1->free_elements;
+ header->garbages = header_v1->garbages;
+ header->ngarbages = header_v1->ngarbages;
+ header->dsegs = header_v1->dsegs;
+ header->esegs = header_v1->esegs;
+ } else {
+ header->free_elements = header_v2->free_elements;
+ header->garbages = header_v2->garbages;
+ header->ngarbages = header_v2->ngarbages;
+ header->dsegs = header_v2->dsegs;
+ header->esegs = header_v2->esegs;
+ }
+
+ ja->io = io;
+ ja->header = header;
+
+ return ja;
+}
+
+grn_rc
+grn_ja_info(grn_ctx *ctx, grn_ja *ja, unsigned int *max_element_size)
+{
+ if (!ja) { return GRN_INVALID_ARGUMENT; }
+ if (max_element_size) { *max_element_size = ja->header->max_element_size; }
+ return GRN_SUCCESS;
+}
+
+grn_column_flags
+grn_ja_get_flags(grn_ctx *ctx, grn_ja *ja)
+{
+ if (!ja) {
+ return 0;
+ }
+
+ return ja->header->flags;
+}
+
+grn_rc
+grn_ja_close(grn_ctx *ctx, grn_ja *ja)
+{
+ grn_rc rc;
+ if (!ja) { return GRN_INVALID_ARGUMENT; }
+ rc = grn_io_close(ctx, ja->io);
+ GRN_FREE(ja->header);
+ GRN_FREE(ja);
+ return rc;
+}
+
+grn_rc
+grn_ja_remove(grn_ctx *ctx, const char *path)
+{
+ if (!path) { return GRN_INVALID_ARGUMENT; }
+ return grn_io_remove(ctx, path);
+}
+
+grn_rc
+grn_ja_truncate(grn_ctx *ctx, grn_ja *ja)
+{
+ grn_rc rc;
+ const char *io_path;
+ char *path;
+ unsigned int max_element_size;
+ uint32_t flags;
+ if ((io_path = grn_io_path(ja->io)) && *io_path != '\0') {
+ if (!(path = GRN_STRDUP(io_path))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE, "cannot duplicate path: <%s>", io_path);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ } else {
+ path = NULL;
+ }
+ max_element_size = ja->header->max_element_size;
+ flags = ja->header->flags;
+ if ((rc = grn_io_close(ctx, ja->io))) { goto exit; }
+ ja->io = NULL;
+ if (path && (rc = grn_io_remove(ctx, path))) { goto exit; }
+ GRN_FREE(ja->header);
+ if (!_grn_ja_create(ctx, ja, path, max_element_size, flags)) {
+ rc = GRN_UNKNOWN_ERROR;
+ }
+exit:
+ if (path) { GRN_FREE(path); }
+ return rc;
+}
+
+static void *
+grn_ja_ref_raw(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
+{
+ uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
+ iw->size = 0;
+ iw->addr = NULL;
+ iw->pseg = pseg;
+ iw->uncompressed_value = NULL;
+ if (pseg != JA_ESEG_VOID) {
+ grn_ja_einfo *einfo = NULL;
+ GRN_IO_SEG_REF(ja->io, pseg, einfo);
+ if (einfo) {
+ grn_ja_einfo *ei = &einfo[id & JA_M_EINFO_IN_A_SEGMENT];
+ if (ETINY_P(ei)) {
+ iw->tiny_p = 1;
+ ETINY_DEC(ei, iw->size);
+ iw->io = ja->io;
+ iw->ctx = ctx;
+ iw->addr = (void *)ei;
+ } else {
+ uint32_t jag, vpos, vsize;
+ iw->tiny_p = 0;
+ if (EHUGE_P(ei)) {
+ EHUGE_DEC(ei, jag, vsize);
+ vpos = 0;
+ } else {
+ EINFO_DEC(ei, jag, vpos, vsize);
+ }
+ grn_io_win_map(ja->io, ctx, iw, jag, vpos, vsize, grn_io_rdonly);
+ }
+ if (!iw->addr) { GRN_IO_SEG_UNREF(ja->io, pseg); }
+ }
+ }
+ *value_len = iw->size;
+ return iw->addr;
+}
+
+grn_rc
+grn_ja_unref(grn_ctx *ctx, grn_io_win *iw)
+{
+ if (iw->uncompressed_value) {
+ GRN_FREE(iw->uncompressed_value);
+ iw->uncompressed_value = NULL;
+ }
+ if (!iw->addr) { return GRN_INVALID_ARGUMENT; }
+ GRN_IO_SEG_UNREF(iw->io, iw->pseg);
+ if (!iw->tiny_p) { grn_io_win_unmap(iw); }
+ return GRN_SUCCESS;
+}
+
+#define DELETED 0x80000000
+
+static grn_rc
+grn_ja_free(grn_ctx *ctx, grn_ja *ja, grn_ja_einfo *einfo)
+{
+ grn_ja_ginfo *ginfo = NULL;
+ uint32_t seg, pos, element_size, aligned_size, m, *gseg;
+ if (ETINY_P(einfo)) { return GRN_SUCCESS; }
+ if (EHUGE_P(einfo)) {
+ uint32_t n;
+ EHUGE_DEC(einfo, seg, element_size);
+ n = ((element_size + JA_SEGMENT_SIZE - 1) >> GRN_JA_W_SEGMENT);
+ for (; n--; seg++) { SEGMENTS_OFF(ja, seg); }
+ return GRN_SUCCESS;
+ }
+ EINFO_DEC(einfo, seg, pos, element_size);
+ if (!element_size) { return GRN_SUCCESS; }
+ {
+ int es = element_size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ }
+ if (m > ja->header->segregate_threshold) {
+ byte *addr = NULL;
+ GRN_IO_SEG_REF(ja->io, seg, addr);
+ if (!addr) { return GRN_NO_MEMORY_AVAILABLE; }
+ aligned_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
+ *(uint32_t *)(addr + pos - sizeof(grn_id)) = DELETED|aligned_size;
+ if (SEGMENTS_AT(ja, seg) < (aligned_size + sizeof(grn_id)) + SEG_SEQ) {
+ GRN_LOG(ctx, GRN_WARN, "inconsistent ja entry detected (%d > %d)",
+ element_size, SEGMENTS_AT(ja, seg) - SEG_SEQ);
+ }
+ SEGMENTS_AT(ja, seg) -= (aligned_size + sizeof(grn_id));
+ if (SEGMENTS_AT(ja, seg) == SEG_SEQ) {
+ /* reuse the segment */
+ SEGMENTS_OFF(ja, seg);
+ if (seg == *(ja->header->curr_seg)) {
+ *(ja->header->curr_pos) = JA_SEGMENT_SIZE;
+ }
+ }
+ GRN_IO_SEG_UNREF(ja->io, seg);
+ } else {
+ uint32_t lseg = 0, lseg_;
+ gseg = &ja->header->garbages[m - JA_W_EINFO];
+ while ((lseg_ = *gseg)) {
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
+ if (!ginfo) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ lseg = lseg_;
+ if (ginfo->nrecs < JA_N_GARBAGES_IN_A_SEGMENT) { break; }
+ gseg = &ginfo->next;
+ }
+ if (!lseg_) {
+ uint32_t i = 0;
+ while (SEGMENTS_AT(ja, i)) {
+ if (++i >= JA_N_DSEGMENTS) {
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ SEGMENTS_GINFO_ON(ja, i, m - JA_W_EINFO);
+ *gseg = i;
+ lseg_ = *gseg;
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
+ lseg = lseg_;
+ if (!ginfo) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ ginfo->head = 0;
+ ginfo->tail = 0;
+ ginfo->nrecs = 0;
+ ginfo->next = 0;
+ }
+ ginfo->recs[ginfo->head].seg = seg;
+ ginfo->recs[ginfo->head].pos = pos;
+ if (++ginfo->head == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->head = 0; }
+ ginfo->nrecs++;
+ ja->header->ngarbages[m - JA_W_EINFO]++;
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_replace(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ grn_ja_einfo *ei, uint64_t *cas)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint32_t lseg, *pseg, pos;
+ grn_ja_einfo *einfo = NULL, eback;
+ lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
+ pos = id & JA_M_EINFO_IN_A_SEGMENT;
+ pseg = &ja->header->esegs[lseg];
+ if (grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
+ return ctx->rc;
+ }
+ if (*pseg == JA_ESEG_VOID) {
+ unsigned int i = 0;
+ while (SEGMENTS_AT(ja, i)) {
+ if (++i >= JA_N_DSEGMENTS) {
+ ERR(GRN_NOT_ENOUGH_SPACE, "grn_ja file (%s) is full", ja->io->path);
+ rc = GRN_NOT_ENOUGH_SPACE;
+ goto exit;
+ }
+ }
+ SEGMENTS_EINFO_ON(ja, i, lseg);
+ GRN_IO_SEG_REF(ja->io, i, einfo);
+ if (einfo) {
+ *pseg = i;
+ memset(einfo, 0, JA_SEGMENT_SIZE);
+ }
+ } else {
+ GRN_IO_SEG_REF(ja->io, *pseg, einfo);
+ }
+ if (!einfo) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ goto exit;
+ }
+ eback = einfo[pos];
+ if (cas && *cas != *((uint64_t *)&eback)) {
+ ERR(GRN_CAS_ERROR, "cas failed (%d)", id);
+ GRN_IO_SEG_UNREF(ja->io, *pseg);
+ rc = GRN_CAS_ERROR;
+ goto exit;
+ }
+ // smb_wmb();
+ {
+ uint64_t *location = (uint64_t *)(einfo + pos);
+ uint64_t value = *((uint64_t *)ei);
+ GRN_SET_64BIT(location, value);
+ }
+ GRN_IO_SEG_UNREF(ja->io, *pseg);
+ grn_ja_free(ctx, ja, &eback);
+exit :
+ grn_io_unlock(ja->io);
+ return rc;
+}
+
+#define JA_N_GARBAGES_TH 10
+
+// todo : grn_io_win_map cause verbose copy when nseg > 1, it should be copied directly.
+static grn_rc
+grn_ja_alloc(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ uint32_t element_size, grn_ja_einfo *einfo, grn_io_win *iw)
+{
+ byte *addr = NULL;
+ iw->io = ja->io;
+ iw->ctx = ctx;
+ iw->cached = 1;
+ if (element_size < 8) {
+ ETINY_ENC(einfo, element_size);
+ iw->tiny_p = 1;
+ iw->addr = (void *)einfo;
+ return GRN_SUCCESS;
+ }
+ iw->tiny_p = 0;
+ if (grn_io_lock(ctx, ja->io, grn_lock_timeout)) { return ctx->rc; }
+ if (element_size + sizeof(grn_id) > JA_SEGMENT_SIZE) {
+ uint i;
+ int j, n = (element_size + JA_SEGMENT_SIZE - 1) >> GRN_JA_W_SEGMENT;
+ for (i = 0, j = -1; i < JA_N_DSEGMENTS; i++) {
+ if (SEGMENTS_AT(ja, i)) {
+ j = i;
+ } else {
+ if (i == (uint) (j + n)) {
+ j++;
+ addr = grn_io_win_map(ja->io, ctx, iw, j, 0, element_size, grn_io_wronly);
+ if (!addr) {
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ EHUGE_ENC(einfo, j, element_size);
+ for (; j <= (int) i; j++) { SEGMENTS_HUGE_ON(ja, j); }
+ grn_io_unlock(ja->io);
+ return GRN_SUCCESS;
+ }
+ }
+ }
+ GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. requested element_size=%d.", element_size);
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ } else {
+ ja_pos *vp;
+ int m, aligned_size, es = element_size - 1;
+ GRN_BIT_SCAN_REV(es, m);
+ m++;
+ if (m > ja->header->segregate_threshold) {
+ uint32_t seg = *(ja->header->curr_seg);
+ uint32_t pos = *(ja->header->curr_pos);
+ if (pos + element_size + sizeof(grn_id) > JA_SEGMENT_SIZE) {
+ seg = 0;
+ while (SEGMENTS_AT(ja, seg)) {
+ if (++seg >= JA_N_DSEGMENTS) {
+ grn_io_unlock(ja->io);
+ GRN_LOG(ctx, GRN_LOG_CRIT, "ja full. seg=%d.", seg);
+ return GRN_NOT_ENOUGH_SPACE;
+ }
+ }
+ SEGMENTS_SEQ_ON(ja, seg);
+ *(ja->header->curr_seg) = seg;
+ pos = 0;
+ }
+ GRN_IO_SEG_REF(ja->io, seg, addr);
+ if (!addr) {
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ *(grn_id *)(addr + pos) = id;
+ aligned_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
+ if (pos + aligned_size < JA_SEGMENT_SIZE) {
+ *(grn_id *)(addr + pos + aligned_size) = GRN_ID_NIL;
+ }
+ SEGMENTS_AT(ja, seg) += aligned_size + sizeof(grn_id);
+ pos += sizeof(grn_id);
+ EINFO_ENC(einfo, seg, pos, element_size);
+ iw->segment = seg;
+ iw->addr = addr + pos;
+ *(ja->header->curr_pos) = pos + aligned_size;
+ grn_io_unlock(ja->io);
+ return GRN_SUCCESS;
+ } else {
+ uint32_t lseg = 0, lseg_;
+ aligned_size = 1 << m;
+ if (ja->header->ngarbages[m - JA_W_EINFO] > JA_N_GARBAGES_TH) {
+ grn_ja_ginfo *ginfo = NULL;
+ uint32_t seg, pos, *gseg;
+ gseg = &ja->header->garbages[m - JA_W_EINFO];
+ while ((lseg_ = *gseg)) {
+ GRN_IO_SEG_REF(ja->io, lseg_, ginfo);
+ if (!ginfo) {
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (ginfo->next || ginfo->nrecs > JA_N_GARBAGES_TH) {
+ seg = ginfo->recs[ginfo->tail].seg;
+ pos = ginfo->recs[ginfo->tail].pos;
+ GRN_IO_SEG_REF(ja->io, seg, addr);
+ if (!addr) {
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ GRN_IO_SEG_UNREF(ja->io, lseg_);
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ EINFO_ENC(einfo, seg, pos, element_size);
+ iw->segment = seg;
+ iw->addr = addr + pos;
+ if (++ginfo->tail == JA_N_GARBAGES_IN_A_SEGMENT) { ginfo->tail = 0; }
+ ginfo->nrecs--;
+ ja->header->ngarbages[m - JA_W_EINFO]--;
+ if (!ginfo->nrecs) {
+ SEGMENTS_OFF(ja, *gseg);
+ *gseg = ginfo->next;
+ }
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ GRN_IO_SEG_UNREF(ja->io, lseg_);
+ grn_io_unlock(ja->io);
+ return GRN_SUCCESS;
+ }
+ if (lseg) { GRN_IO_SEG_UNREF(ja->io, lseg); }
+ if (!ginfo->next) {
+ GRN_IO_SEG_UNREF(ja->io, lseg_);
+ break;
+ }
+ lseg = lseg_;
+ gseg = &ginfo->next;
+ }
+ }
+ vp = &ja->header->free_elements[m - JA_W_EINFO];
+ if (!vp->seg) {
+ uint i = 0;
+ while (SEGMENTS_AT(ja, i)) {
+ if (++i >= JA_N_DSEGMENTS) {
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ SEGMENTS_SEGRE_ON(ja, i, m);
+ vp->seg = i;
+ vp->pos = 0;
+ }
+ }
+ EINFO_ENC(einfo, vp->seg, vp->pos, element_size);
+ GRN_IO_SEG_REF(ja->io, vp->seg, addr);
+ if (!addr) {
+ grn_io_unlock(ja->io);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ iw->segment = vp->seg;
+ iw->addr = addr + vp->pos;
+ if ((vp->pos += aligned_size) == JA_SEGMENT_SIZE) {
+ vp->seg = 0;
+ vp->pos = 0;
+ }
+ iw->uncompressed_value = NULL;
+ grn_io_unlock(ja->io);
+ return GRN_SUCCESS;
+ }
+}
+
+static grn_rc
+set_value(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
+ grn_ja_einfo *einfo)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_io_win iw;
+ if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
+ value_len >= ja->header->max_element_size) {
+ if ((rc = grn_ja_alloc(ctx, ja, id, value_len + sizeof(uint32_t), einfo, &iw))) {
+ return rc;
+ }
+ grn_memcpy(iw.addr, value, value_len);
+ memset((byte *)iw.addr + value_len, 0, sizeof(uint32_t));
+ grn_io_win_unmap(&iw);
+ } else {
+ if ((rc = grn_ja_alloc(ctx, ja, id, value_len, einfo, &iw))) { return rc; }
+ grn_memcpy(iw.addr, value, value_len);
+ grn_io_win_unmap(&iw);
+ }
+ return rc;
+}
+
+static grn_rc
+grn_ja_put_raw(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ void *value, uint32_t value_len, int flags, uint64_t *cas)
+{
+ int rc;
+ int64_t buf;
+ grn_io_win iw;
+ grn_ja_einfo einfo;
+
+ if ((flags & GRN_OBJ_SET_MASK) == GRN_OBJ_SET &&
+ value_len > 0) {
+ grn_io_win jw;
+ uint32_t old_len;
+ void *old_value;
+ grn_bool same_value = GRN_FALSE;
+
+ old_value = grn_ja_ref(ctx, ja, id, &jw, &old_len);
+ if (value_len == old_len && memcmp(value, old_value, value_len) == 0) {
+ same_value = GRN_TRUE;
+ }
+ grn_ja_unref(ctx, &jw);
+ if (same_value) {
+ return GRN_SUCCESS;
+ }
+ }
+
+ switch (flags & GRN_OBJ_SET_MASK) {
+ case GRN_OBJ_APPEND :
+ if (value_len) {
+ grn_io_win jw;
+ uint32_t old_len;
+ void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
+ if (oldvalue) {
+ if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
+ old_len + value_len >= ja->header->max_element_size) {
+ if (old_len >= ja->header->max_element_size) {
+ byte *b = oldvalue;
+ uint32_t el = old_len - sizeof(uint32_t);
+ uint32_t pos = *((uint32_t *)(b + el));
+ GRN_ASSERT(pos < el);
+ if (el <= pos + value_len) {
+ uint32_t rest = el - pos;
+ grn_memcpy(b + pos, value, rest);
+ grn_memcpy(b, (byte *)value + rest, value_len - rest);
+ *((uint32_t *)(b + el)) = value_len - rest;
+ } else {
+ grn_memcpy(b + pos, value, value_len);
+ *((uint32_t *)(b + el)) = pos + value_len;
+ }
+ return GRN_SUCCESS;
+ } else {
+ if ((rc = grn_ja_alloc(ctx, ja, id,
+ value_len + old_len + sizeof(uint32_t),
+ &einfo, &iw))) {
+ grn_ja_unref(ctx, &jw);
+ return rc;
+ }
+ grn_memcpy(iw.addr, oldvalue, old_len);
+ grn_memcpy((byte *)iw.addr + old_len, value, value_len);
+ memset((byte *)iw.addr + old_len + value_len, 0, sizeof(uint32_t));
+ grn_io_win_unmap(&iw);
+ }
+ } else {
+ if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
+ grn_ja_unref(ctx, &jw);
+ return rc;
+ }
+ grn_memcpy(iw.addr, oldvalue, old_len);
+ grn_memcpy((byte *)iw.addr + old_len, value, value_len);
+ grn_io_win_unmap(&iw);
+ }
+ grn_ja_unref(ctx, &jw);
+ } else {
+ set_value(ctx, ja, id, value, value_len, &einfo);
+ }
+ }
+ break;
+ case GRN_OBJ_PREPEND :
+ if (value_len) {
+ grn_io_win jw;
+ uint32_t old_len;
+ void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
+ if (oldvalue) {
+ if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
+ old_len + value_len >= ja->header->max_element_size) {
+ if (old_len >= ja->header->max_element_size) {
+ byte *b = oldvalue;
+ uint32_t el = old_len - sizeof(uint32_t);
+ uint32_t pos = *((uint32_t *)(b + el));
+ GRN_ASSERT(pos < el);
+ if (pos < value_len) {
+ uint32_t rest = value_len - pos;
+ grn_memcpy(b, (byte *)value + rest, pos);
+ grn_memcpy(b + el - rest, value, rest);
+ *((uint32_t *)(b + el)) = el - rest;
+ } else {
+ grn_memcpy(b + pos - value_len, value, value_len);
+ *((uint32_t *)(b + el)) = pos - value_len;
+ }
+ return GRN_SUCCESS;
+ } else {
+ if ((rc = grn_ja_alloc(ctx, ja, id,
+ value_len + old_len + sizeof(uint32_t),
+ &einfo, &iw))) {
+ grn_ja_unref(ctx, &jw);
+ return rc;
+ }
+ grn_memcpy(iw.addr, value, value_len);
+ grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
+ memset((byte *)iw.addr + value_len + old_len, 0, sizeof(uint32_t));
+ grn_io_win_unmap(&iw);
+ }
+ } else {
+ if ((rc = grn_ja_alloc(ctx, ja, id, value_len + old_len, &einfo, &iw))) {
+ grn_ja_unref(ctx, &jw);
+ return rc;
+ }
+ grn_memcpy(iw.addr, value, value_len);
+ grn_memcpy((byte *)iw.addr + value_len, oldvalue, old_len);
+ grn_io_win_unmap(&iw);
+ }
+ grn_ja_unref(ctx, &jw);
+ } else {
+ set_value(ctx, ja, id, value, value_len, &einfo);
+ }
+ }
+ break;
+ case GRN_OBJ_DECR :
+ if (value_len == sizeof(int64_t)) {
+ int64_t *v = (int64_t *)&buf;
+ *v = -(*(int64_t *)value);
+ value = v;
+ } else if (value_len == sizeof(int32_t)) {
+ int32_t *v = (int32_t *)&buf;
+ *v = -(*(int32_t *)value);
+ value = v;
+ } else {
+ return GRN_INVALID_ARGUMENT;
+ }
+ /* fallthru */
+ case GRN_OBJ_INCR :
+ {
+ grn_io_win jw;
+ uint32_t old_len;
+ void *oldvalue = grn_ja_ref(ctx, ja, id, &jw, &old_len);
+ if (oldvalue && old_len) {
+ grn_rc rc = GRN_INVALID_ARGUMENT;
+ if (old_len == sizeof(int64_t) && value_len == sizeof(int64_t)) {
+ (*(int64_t *)oldvalue) += (*(int64_t *)value);
+ rc = GRN_SUCCESS;
+ } else if (old_len == sizeof(int32_t) && value_len == sizeof(int32_t)) {
+ (*(int32_t *)oldvalue) += (*(int32_t *)value);
+ rc = GRN_SUCCESS;
+ }
+ grn_ja_unref(ctx, &jw);
+ return rc;
+ }
+ }
+ /* fallthru */
+ case GRN_OBJ_SET :
+ if (value_len) {
+ set_value(ctx, ja, id, value, value_len, &einfo);
+ } else {
+ memset(&einfo, 0, sizeof(grn_ja_einfo));
+ }
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT, "grn_ja_put_raw called with illegal flags value");
+ return GRN_INVALID_ARGUMENT;
+ }
+ if ((rc = grn_ja_replace(ctx, ja, id, &einfo, cas))) {
+ if (!grn_io_lock(ctx, ja->io, grn_lock_timeout)) {
+ grn_ja_free(ctx, ja, &einfo);
+ grn_io_unlock(ja->io);
+ }
+ }
+ return rc;
+}
+
+grn_rc
+grn_ja_putv(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *vector, int flags)
+{
+ grn_obj header, footer;
+ grn_rc rc = GRN_SUCCESS;
+ grn_section *vp;
+ int i, f = 0, n = grn_vector_size(ctx, vector);
+ GRN_TEXT_INIT(&header, 0);
+ GRN_TEXT_INIT(&footer, 0);
+ grn_text_benc(ctx, &header, n);
+ for (i = 0, vp = vector->u.v.sections; i < n; i++, vp++) {
+ grn_text_benc(ctx, &header, vp->length);
+ if (vp->weight || vp->domain) { f = 1; }
+ }
+ if (f) {
+ for (i = 0, vp = vector->u.v.sections; i < n; i++, vp++) {
+ grn_text_benc(ctx, &footer, vp->weight);
+ grn_text_benc(ctx, &footer, vp->domain);
+ }
+ }
+ {
+ grn_io_win iw;
+ grn_ja_einfo einfo;
+ grn_obj *body = vector->u.v.body;
+ size_t sizeh = GRN_BULK_VSIZE(&header);
+ size_t sizev = body ? GRN_BULK_VSIZE(body) : 0;
+ size_t sizef = GRN_BULK_VSIZE(&footer);
+ if ((rc = grn_ja_alloc(ctx, ja, id, sizeh + sizev + sizef, &einfo, &iw))) { goto exit; }
+ grn_memcpy(iw.addr, GRN_BULK_HEAD(&header), sizeh);
+ if (body) {
+ grn_memcpy((char *)iw.addr + sizeh, GRN_BULK_HEAD(body), sizev);
+ }
+ if (f) {
+ grn_memcpy((char *)iw.addr + sizeh + sizev, GRN_BULK_HEAD(&footer), sizef);
+ }
+ grn_io_win_unmap(&iw);
+ rc = grn_ja_replace(ctx, ja, id, &einfo, NULL);
+ }
+exit :
+ GRN_OBJ_FIN(ctx, &footer);
+ GRN_OBJ_FIN(ctx, &header);
+ return rc;
+}
+
+uint32_t
+grn_ja_size(grn_ctx *ctx, grn_ja *ja, grn_id id)
+{
+ grn_ja_einfo *einfo = NULL, *ei;
+ uint32_t lseg, *pseg, pos, size;
+ lseg = id >> JA_W_EINFO_IN_A_SEGMENT;
+ pos = id & JA_M_EINFO_IN_A_SEGMENT;
+ pseg = &ja->header->esegs[lseg];
+ if (*pseg == JA_ESEG_VOID) {
+ ctx->rc = GRN_INVALID_ARGUMENT;
+ return 0;
+ }
+ GRN_IO_SEG_REF(ja->io, *pseg, einfo);
+ if (!einfo) {
+ ctx->rc = GRN_NO_MEMORY_AVAILABLE;
+ return 0;
+ }
+ ei = &einfo[pos];
+ if (ETINY_P(ei)) {
+ ETINY_DEC(ei, size);
+ } else {
+ if (EHUGE_P(ei)) {
+ size = ei->u.h.size;
+ } else {
+ size = (ei->u.n.c2 << 16) + ei->u.n.size;
+ }
+ }
+ GRN_IO_SEG_UNREF(ja->io, *pseg);
+ return size;
+}
+
+grn_rc
+grn_ja_element_info(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ uint64_t *cas, uint32_t *pos, uint32_t *size)
+{
+ uint32_t pseg = ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
+ if (pseg == JA_ESEG_VOID) {
+ return GRN_INVALID_ARGUMENT;
+ } else {
+ grn_ja_einfo *einfo = NULL;
+ GRN_IO_SEG_REF(ja->io, pseg, einfo);
+ if (einfo) {
+ grn_ja_einfo *ei;
+ *cas = *((uint64_t *)&einfo[id & JA_M_EINFO_IN_A_SEGMENT]);
+ ei = (grn_ja_einfo *)cas;
+ if (ETINY_P(ei)) {
+ ETINY_DEC(ei, *size);
+ *pos = 0;
+ } else {
+ uint32_t jag;
+ if (EHUGE_P(ei)) {
+ EHUGE_DEC(ei, jag, *size);
+ *pos = 0;
+ } else {
+ EINFO_DEC(ei, jag, *pos, *size);
+ }
+ }
+ GRN_IO_SEG_UNREF(ja->io, pseg);
+ } else {
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+#define COMPRESSED_VALUE_META_FLAG(meta) ((meta) & 0xf000000000000000)
+#define COMPRESSED_VALUE_META_FLAG_RAW 0x1000000000000000
+#define COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(meta) \
+ ((meta) & 0x0fffffffffffffff)
+
+#define COMPRESS_THRESHOLD_BYTE 256
+#define COMPRESS_PACKED_VALUE_SIZE_MAX 257
+ /* COMPRESS_THRESHOLD_BYTE - 1 + sizeof(uint64_t) = 257 */
+
+#if defined(GRN_WITH_ZLIB) || defined(GRN_WITH_LZ4) || defined(GRN_WITH_ZSTD)
+# define GRN_WITH_COMPRESSED
+#endif
+
+#ifdef GRN_WITH_COMPRESSED
+static void *
+grn_ja_ref_packed(grn_ctx *ctx,
+ grn_io_win *iw,
+ uint32_t *value_len,
+ void *raw_value,
+ uint32_t raw_value_len,
+ void **compressed_value,
+ uint32_t *compressed_value_len,
+ uint32_t *uncompressed_value_len)
+{
+ uint64_t compressed_value_meta;
+
+ compressed_value_meta = *((uint64_t *)raw_value);
+ *compressed_value = (void *)(((uint64_t *)raw_value) + 1);
+ *compressed_value_len = raw_value_len - sizeof(uint64_t);
+
+ *uncompressed_value_len =
+ COMPRESSED_VALUE_META_UNCOMPRESSED_LEN(compressed_value_meta);
+ switch (COMPRESSED_VALUE_META_FLAG(compressed_value_meta)) {
+ case COMPRESSED_VALUE_META_FLAG_RAW :
+ iw->uncompressed_value = NULL;
+ *value_len = *uncompressed_value_len;
+ return *compressed_value;
+ default :
+ return NULL;
+ }
+}
+
+static grn_rc
+grn_ja_put_packed(grn_ctx *ctx,
+ grn_ja *ja,
+ grn_id id,
+ void *value,
+ uint32_t value_len,
+ int flags,
+ uint64_t *cas)
+{
+ char *packed_value[COMPRESS_PACKED_VALUE_SIZE_MAX];
+ uint32_t packed_value_len;
+ uint64_t packed_value_meta;
+
+ packed_value_len = value_len + sizeof(uint64_t);
+ packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
+ *((uint64_t *)packed_value) = packed_value_meta;
+ memcpy(((uint64_t *)packed_value) + 1,
+ value,
+ value_len);
+ return grn_ja_put_raw(ctx,
+ ja,
+ id,
+ packed_value,
+ packed_value_len,
+ flags,
+ cas);
+}
+
+static void
+grn_ja_compress_error(grn_ctx *ctx,
+ grn_ja *ja,
+ grn_id id,
+ grn_rc rc,
+ const char *message,
+ const char *detail)
+{
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_len;
+
+ if (ja->obj.id == GRN_ID_NIL) {
+ name[0] = '\0';
+ name_len = 0;
+ } else {
+ name_len = grn_obj_name(ctx, (grn_obj *)ja, name, GRN_TABLE_MAX_KEY_SIZE);
+ }
+ ERR(GRN_ZSTD_ERROR,
+ "[ja]%s: %s%.*s%s<%u>%s%s%s",
+ message,
+ name_len == 0 ? "" : "<",
+ name_len,
+ name,
+ name_len == 0 ? "" : ">: ",
+ id,
+ detail ? " :<" : "",
+ detail ? detail : "",
+ detail ? ">" : "");
+}
+#endif /* GRN_WITH_COMPRESSED */
+
+#ifdef GRN_WITH_ZLIB
+#include <zlib.h>
+
+static const char *
+grn_zrc_to_string(int zrc)
+{
+ switch (zrc) {
+ case Z_OK :
+ return "OK";
+ case Z_STREAM_END :
+ return "Stream is end";
+ case Z_NEED_DICT :
+ return "Need dictionary";
+ case Z_ERRNO :
+ return "See errno";
+ case Z_STREAM_ERROR :
+ return "Stream error";
+ case Z_DATA_ERROR :
+ return "Data error";
+ case Z_MEM_ERROR :
+ return "Memory error";
+ case Z_BUF_ERROR :
+ return "Buffer error";
+ case Z_VERSION_ERROR :
+ return "Version error";
+ default :
+ return "Unknown";
+ }
+}
+
+static void *
+grn_ja_ref_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
+{
+ z_stream zstream;
+ void *raw_value;
+ uint32_t raw_value_len;
+ void *zvalue;
+ uint32_t zvalue_len;
+ void *unpacked_value;
+ uint32_t uncompressed_value_len;
+ int zrc;
+
+ if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ return NULL;
+ }
+
+ unpacked_value = grn_ja_ref_packed(ctx,
+ iw, value_len,
+ raw_value, raw_value_len,
+ &zvalue, &zvalue_len,
+ &uncompressed_value_len);
+ if (unpacked_value) {
+ return unpacked_value;
+ }
+
+ zstream.next_in = (Bytef *)zvalue;
+ zstream.avail_in = zvalue_len;
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zrc = inflateInit2(&zstream, 15 /* windowBits */);
+ if (zrc != Z_OK) {
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to decompress: initialize",
+ grn_zrc_to_string(zrc));
+ return NULL;
+ }
+ if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
+ inflateEnd(&zstream);
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to decompress: allocate buffer",
+ NULL);
+ return NULL;
+ }
+ zstream.next_out = (Bytef *)iw->uncompressed_value;
+ zstream.avail_out = uncompressed_value_len;
+ zrc = inflate(&zstream, Z_FINISH);
+ if (zrc != Z_STREAM_END) {
+ inflateEnd(&zstream);
+ GRN_FREE(iw->uncompressed_value);
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to decompress: finish",
+ grn_zrc_to_string(zrc));
+ return NULL;
+ }
+ *value_len = zstream.total_out;
+ zrc = inflateEnd(&zstream);
+ if (zrc != Z_OK) {
+ GRN_FREE(iw->uncompressed_value);
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to decompress: end",
+ grn_zrc_to_string(zrc));
+ return NULL;
+ }
+ return iw->uncompressed_value;
+}
+#endif /* GRN_WITH_ZLIB */
+
+#ifdef GRN_WITH_LZ4
+#include <lz4.h>
+
+# if (LZ4_VERSION_MAJOR == 1 && LZ4_VERSION_MINOR < 6)
+# define LZ4_compress_default(source, dest, source_size, max_dest_size) \
+ LZ4_compress((source), (dest), (source_size))
+# endif
+
+static void *
+grn_ja_ref_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
+{
+ void *raw_value;
+ uint32_t raw_value_len;
+ void *lz4_value;
+ uint32_t lz4_value_len;
+ void *unpacked_value;
+ uint32_t uncompressed_value_len;
+
+ if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ return NULL;
+ }
+
+ unpacked_value = grn_ja_ref_packed(ctx,
+ iw, value_len,
+ raw_value, raw_value_len,
+ &lz4_value, &lz4_value_len,
+ &uncompressed_value_len);
+ if (unpacked_value) {
+ return unpacked_value;
+ }
+
+ if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ return NULL;
+ }
+ if (LZ4_decompress_safe((const char *)(lz4_value),
+ (char *)(iw->uncompressed_value),
+ lz4_value_len,
+ uncompressed_value_len) < 0) {
+ GRN_FREE(iw->uncompressed_value);
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_LZ4_ERROR,
+ "[lz4] failed to decompress",
+ NULL);
+ return NULL;
+ }
+ *value_len = uncompressed_value_len;
+ return iw->uncompressed_value;
+}
+#endif /* GRN_WITH_LZ4 */
+
+#ifdef GRN_WITH_ZSTD
+#include <zstd.h>
+
+static void *
+grn_ja_ref_zstd(grn_ctx *ctx,
+ grn_ja *ja,
+ grn_id id,
+ grn_io_win *iw,
+ uint32_t *value_len)
+{
+ void *raw_value;
+ uint32_t raw_value_len;
+ void *zstd_value;
+ uint32_t zstd_value_len;
+ void *unpacked_value;
+ uint32_t uncompressed_value_len;
+ size_t written_len;
+
+ if (!(raw_value = grn_ja_ref_raw(ctx, ja, id, iw, &raw_value_len))) {
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ return NULL;
+ }
+
+ unpacked_value = grn_ja_ref_packed(ctx,
+ iw, value_len,
+ raw_value, raw_value_len,
+ &zstd_value, &zstd_value_len,
+ &uncompressed_value_len);
+ if (unpacked_value) {
+ return unpacked_value;
+ }
+
+ if (!(iw->uncompressed_value = GRN_MALLOC(uncompressed_value_len))) {
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ return NULL;
+ }
+
+ written_len = ZSTD_decompress((char *)(iw->uncompressed_value),
+ uncompressed_value_len,
+ zstd_value,
+ zstd_value_len);
+ if (ZSTD_isError(written_len)) {
+ GRN_FREE(iw->uncompressed_value);
+ iw->uncompressed_value = NULL;
+ *value_len = 0;
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZSTD_ERROR,
+ "[zstd] failed to decompress",
+ ZSTD_getErrorName(written_len));
+ return NULL;
+ }
+ *value_len = uncompressed_value_len;
+ return iw->uncompressed_value;
+}
+#endif /* GRN_WITH_ZSTD */
+
+void *
+grn_ja_ref(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_io_win *iw, uint32_t *value_len)
+{
+ switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
+#ifdef GRN_WITH_ZLIB
+ case GRN_OBJ_COMPRESS_ZLIB :
+ return grn_ja_ref_zlib(ctx, ja, id, iw, value_len);
+#endif /* GRN_WITH_ZLIB */
+#ifdef GRN_WITH_LZ4
+ case GRN_OBJ_COMPRESS_LZ4 :
+ return grn_ja_ref_lz4(ctx, ja, id, iw, value_len);
+#endif /* GRN_WITH_LZ4 */
+#ifdef GRN_WITH_ZSTD
+ case GRN_OBJ_COMPRESS_ZSTD :
+ return grn_ja_ref_zstd(ctx, ja, id, iw, value_len);
+#endif /* GRN_WITH_ZSTD */
+ default :
+ return grn_ja_ref_raw(ctx, ja, id, iw, value_len);
+ }
+}
+
+grn_obj *
+grn_ja_get_value(grn_ctx *ctx, grn_ja *ja, grn_id id, grn_obj *value)
+{
+ void *v;
+ uint32_t len;
+ grn_io_win iw;
+ if (!value) {
+ if (!(value = grn_obj_open(ctx, GRN_BULK, 0, 0))) {
+ ERR(GRN_INVALID_ARGUMENT, "grn_obj_get_value failed");
+ goto exit;
+ }
+ }
+ if ((v = grn_ja_ref(ctx, ja, id, &iw, &len))) {
+ if ((ja->header->flags & GRN_OBJ_RING_BUFFER) &&
+ len > ja->header->max_element_size) {
+ byte *b = v;
+ uint32_t el = len - sizeof(uint32_t);
+ uint32_t pos = *((uint32_t *)(b + el));
+ GRN_ASSERT(pos < el);
+ grn_bulk_write(ctx, value, (char *)(b + pos), el - pos);
+ grn_bulk_write(ctx, value, (char *)(b), pos);
+ } else {
+ grn_bulk_write(ctx, value, v, len);
+ }
+ grn_ja_unref(ctx, &iw);
+ }
+exit :
+ return value;
+}
+
+#ifdef GRN_WITH_ZLIB
+inline static grn_rc
+grn_ja_put_zlib(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ void *value, uint32_t value_len, int flags, uint64_t *cas)
+{
+ grn_rc rc;
+ z_stream zstream;
+ void *zvalue;
+ int zvalue_len;
+ int zrc;
+
+ if (value_len == 0) {
+ return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
+ }
+
+ if (value_len < COMPRESS_THRESHOLD_BYTE) {
+ return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
+ }
+
+ zstream.next_in = value;
+ zstream.avail_in = value_len;
+ zstream.zalloc = Z_NULL;
+ zstream.zfree = Z_NULL;
+ zrc = deflateInit2(&zstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
+ 15 /* windowBits */,
+ 8 /* memLevel */,
+ Z_DEFAULT_STRATEGY);
+ if (zrc != Z_OK) {
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to compress: initialize",
+ grn_zrc_to_string(zrc));
+ return ctx->rc;
+ }
+ zvalue_len = deflateBound(&zstream, value_len);
+ if (!(zvalue = GRN_MALLOC(zvalue_len + sizeof(uint64_t)))) {
+ deflateEnd(&zstream);
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to allocate compress buffer",
+ NULL);
+ return ctx->rc;
+ }
+ zstream.next_out = (Bytef *)(((uint64_t *)zvalue) + 1);
+ zstream.avail_out = zvalue_len;
+ zrc = deflate(&zstream, Z_FINISH);
+ if (zrc != Z_STREAM_END) {
+ deflateEnd(&zstream);
+ GRN_FREE(zvalue);
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to compress: finish",
+ grn_zrc_to_string(zrc));
+ return ctx->rc;
+ }
+ zvalue_len = zstream.total_out;
+ zrc = deflateEnd(&zstream);
+ if (zrc != Z_OK) {
+ GRN_FREE(zvalue);
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZLIB_ERROR,
+ "[zlib] failed to compress: end",
+ grn_zrc_to_string(zrc));
+ return ctx->rc;
+ }
+ *(uint64_t *)zvalue = value_len;
+ rc = grn_ja_put_raw(ctx, ja, id, zvalue, zvalue_len + sizeof(uint64_t), flags, cas);
+ GRN_FREE(zvalue);
+ return rc;
+}
+#endif /* GRN_WITH_ZLIB */
+
+#ifdef GRN_WITH_LZ4
+inline static grn_rc
+grn_ja_put_lz4(grn_ctx *ctx, grn_ja *ja, grn_id id,
+ void *value, uint32_t value_len, int flags, uint64_t *cas)
+{
+ grn_rc rc;
+ void *packed_value;
+ int packed_value_len_max;
+ int packed_value_len_real;
+ char *lz4_value;
+ int lz4_value_len_max;
+ int lz4_value_len_real;
+
+ if (value_len == 0) {
+ return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
+ }
+
+ if (value_len < COMPRESS_THRESHOLD_BYTE) {
+ return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
+ }
+
+ if (value_len > (uint32_t)LZ4_MAX_INPUT_SIZE) {
+ uint64_t packed_value_meta;
+
+ packed_value_len_real = value_len + sizeof(uint64_t);
+ packed_value = GRN_MALLOC(packed_value_len_real);
+ if (!packed_value) {
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_LZ4_ERROR,
+ "[lz4] failed to allocate packed buffer",
+ NULL);
+ return ctx->rc;
+ }
+ packed_value_meta = value_len | COMPRESSED_VALUE_META_FLAG_RAW;
+ *((uint64_t *)packed_value) = packed_value_meta;
+ memcpy(((uint64_t *)packed_value) + 1,
+ value,
+ value_len);
+ rc = grn_ja_put_raw(ctx,
+ ja,
+ id,
+ packed_value,
+ packed_value_len_real,
+ flags,
+ cas);
+ GRN_FREE(packed_value);
+ return rc;
+ }
+
+ lz4_value_len_max = LZ4_compressBound(value_len);
+ packed_value_len_max = lz4_value_len_max + sizeof(uint64_t);
+ if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_LZ4_ERROR,
+ "[lz4] failed to allocate compress buffer",
+ NULL);
+ return ctx->rc;
+ }
+ lz4_value = (char *)((uint64_t *)packed_value + 1);
+ lz4_value_len_real = LZ4_compress_default((const char *)value,
+ lz4_value,
+ value_len,
+ lz4_value_len_max);
+ if (lz4_value_len_real <= 0) {
+ GRN_FREE(packed_value);
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_LZ4_ERROR,
+ "[lz4] failed to compress",
+ NULL);
+ return ctx->rc;
+ }
+ *(uint64_t *)packed_value = value_len;
+ packed_value_len_real = lz4_value_len_real + sizeof(uint64_t);
+ rc = grn_ja_put_raw(ctx,
+ ja,
+ id,
+ packed_value,
+ packed_value_len_real,
+ flags,
+ cas);
+ GRN_FREE(packed_value);
+ return rc;
+}
+#endif /* GRN_WITH_LZ4 */
+
+#ifdef GRN_WITH_ZSTD
+inline static grn_rc
+grn_ja_put_zstd(grn_ctx *ctx,
+ grn_ja *ja,
+ grn_id id,
+ void *value,
+ uint32_t value_len,
+ int flags,
+ uint64_t *cas)
+{
+ grn_rc rc;
+ void *packed_value;
+ int packed_value_len_max;
+ int packed_value_len_real;
+ void *zstd_value;
+ int zstd_value_len_max;
+ int zstd_value_len_real;
+ int zstd_compression_level = 3;
+
+ if (value_len == 0) {
+ return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
+ }
+
+ if (value_len < COMPRESS_THRESHOLD_BYTE) {
+ return grn_ja_put_packed(ctx, ja, id, value, value_len, flags, cas);
+ }
+
+ zstd_value_len_max = ZSTD_compressBound(value_len);
+ packed_value_len_max = zstd_value_len_max + sizeof(uint64_t);
+ if (!(packed_value = GRN_MALLOC(packed_value_len_max))) {
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZSTD_ERROR,
+ "[zstd] failed to allocate compress buffer",
+ NULL);
+ return ctx->rc;
+ }
+ zstd_value = ((uint64_t *)packed_value) + 1;
+ zstd_value_len_real = ZSTD_compress(zstd_value, zstd_value_len_max,
+ value, value_len,
+ zstd_compression_level);
+ if (ZSTD_isError(zstd_value_len_real)) {
+ grn_ja_compress_error(ctx,
+ ja,
+ id,
+ GRN_ZSTD_ERROR,
+ "[zstd] failed to compress",
+ ZSTD_getErrorName(zstd_value_len_real));
+ return ctx->rc;
+ }
+ *(uint64_t *)packed_value = value_len;
+ packed_value_len_real = zstd_value_len_real + sizeof(uint64_t);
+ rc = grn_ja_put_raw(ctx,
+ ja,
+ id,
+ packed_value,
+ packed_value_len_real,
+ flags,
+ cas);
+ GRN_FREE(packed_value);
+ return rc;
+}
+#endif /* GRN_WITH_ZSTD */
+
+grn_rc
+grn_ja_put(grn_ctx *ctx, grn_ja *ja, grn_id id, void *value, uint32_t value_len,
+ int flags, uint64_t *cas)
+{
+ switch (ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
+#ifdef GRN_WITH_ZLIB
+ case GRN_OBJ_COMPRESS_ZLIB :
+ return grn_ja_put_zlib(ctx, ja, id, value, value_len, flags, cas);
+#endif /* GRN_WITH_ZLIB */
+#ifdef GRN_WITH_LZ4
+ case GRN_OBJ_COMPRESS_LZ4 :
+ return grn_ja_put_lz4(ctx, ja, id, value, value_len, flags, cas);
+#endif /* GRN_WITH_LZ4 */
+#ifdef GRN_WITH_ZSTD
+ case GRN_OBJ_COMPRESS_ZSTD :
+ return grn_ja_put_zstd(ctx, ja, id, value, value_len, flags, cas);
+#endif /* GRN_WITH_ZSTD */
+ default :
+ return grn_ja_put_raw(ctx, ja, id, value, value_len, flags, cas);
+ }
+}
+
+static grn_rc
+grn_ja_defrag_seg(grn_ctx *ctx, grn_ja *ja, uint32_t seg)
+{
+ byte *v = NULL, *ve;
+ uint32_t element_size, cum = 0, *seginfo = &SEGMENTS_AT(ja,seg), sum;
+ sum = (*seginfo & ~SEG_MASK);
+ GRN_IO_SEG_REF(ja->io, seg, v);
+ if (!v) { return GRN_NO_MEMORY_AVAILABLE; }
+ ve = v + JA_SEGMENT_SIZE;
+ while (v < ve && cum < sum) {
+ grn_id id = *((grn_id *)v);
+ if (!id) { break; }
+ if (id & DELETED) {
+ element_size = (id & ~DELETED);
+ } else {
+ uint64_t cas;
+ uint32_t pos;
+ if (grn_ja_element_info(ctx, ja, id, &cas, &pos, &element_size)) { break; }
+ if (v + sizeof(uint32_t) != ve - JA_SEGMENT_SIZE + pos) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "dseges[%d] = pos unmatch (%d != %" GRN_FMT_LLD ")",
+ seg, pos, (long long int)(v + sizeof(uint32_t) + JA_SEGMENT_SIZE - ve));
+ break;
+ }
+ if (grn_ja_put(ctx, ja, id, v + sizeof(uint32_t), element_size, GRN_OBJ_SET, &cas)) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "dseges[%d] = put failed (%d)", seg, id);
+ break;
+ }
+ element_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
+ cum += sizeof(uint32_t) + element_size;
+ }
+ v += sizeof(uint32_t) + element_size;
+ }
+ if (*seginfo) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "dseges[%d] = %d after defrag", seg, (*seginfo & ~SEG_MASK));
+ }
+ GRN_IO_SEG_UNREF(ja->io, seg);
+ return GRN_SUCCESS;
+}
+
+int
+grn_ja_defrag(grn_ctx *ctx, grn_ja *ja, int threshold)
+{
+ int nsegs = 0;
+ uint32_t seg, ts = 1U << (GRN_JA_W_SEGMENT - threshold);
+ for (seg = 0; seg < JA_N_DSEGMENTS; seg++) {
+ if (seg == *(ja->header->curr_seg)) { continue; }
+ if (((SEGMENTS_AT(ja, seg) & SEG_MASK) == SEG_SEQ) &&
+ ((SEGMENTS_AT(ja, seg) & ~SEG_MASK) < ts)) {
+ if (!grn_ja_defrag_seg(ctx, ja, seg)) { nsegs++; }
+ }
+ }
+ return nsegs;
+}
+
+void
+grn_ja_check(grn_ctx *ctx, grn_ja *ja)
+{
+ char buf[8];
+ uint32_t seg;
+ struct grn_ja_header *h = ja->header;
+ GRN_OUTPUT_ARRAY_OPEN("RESULT", 8);
+ GRN_OUTPUT_MAP_OPEN("SUMMARY", 8);
+ GRN_OUTPUT_CSTR("flags");
+ grn_itoh(h->flags, buf, 8);
+ GRN_OUTPUT_STR(buf, 8);
+ GRN_OUTPUT_CSTR("curr seg");
+ GRN_OUTPUT_INT64(*(h->curr_seg));
+ GRN_OUTPUT_CSTR("curr pos");
+ GRN_OUTPUT_INT64(*(h->curr_pos));
+ GRN_OUTPUT_CSTR("max_element_size");
+ GRN_OUTPUT_INT64(h->max_element_size);
+ GRN_OUTPUT_CSTR("segregate_threshold");
+ GRN_OUTPUT_INT64(h->segregate_threshold);
+ GRN_OUTPUT_CSTR("n_element_variation");
+ GRN_OUTPUT_INT64(h->n_element_variation);
+ GRN_OUTPUT_MAP_CLOSE();
+ GRN_OUTPUT_ARRAY_OPEN("DETAIL", -1);
+ for (seg = 0; seg < JA_N_DSEGMENTS; seg++) {
+ int dseg = SEGMENTS_AT(ja, seg);
+ if (dseg) {
+ GRN_OUTPUT_MAP_OPEN("SEG", -1);
+ GRN_OUTPUT_CSTR("seg id");
+ GRN_OUTPUT_INT64(seg);
+ GRN_OUTPUT_CSTR("seg type");
+ GRN_OUTPUT_INT64((dseg & SEG_MASK)>>28);
+ GRN_OUTPUT_CSTR("seg value");
+ GRN_OUTPUT_INT64(dseg & ~SEG_MASK);
+ if ((dseg & SEG_MASK) == SEG_SEQ) {
+ byte *v = NULL, *ve;
+ uint32_t element_size, cum = 0, sum = dseg & ~SEG_MASK;
+ uint32_t n_del_elements = 0, n_elements = 0, s_del_elements = 0, s_elements = 0;
+ GRN_IO_SEG_REF(ja->io, seg, v);
+ if (v) {
+ /*
+ GRN_OUTPUT_CSTR("seg seq");
+ GRN_OUTPUT_ARRAY_OPEN("SEQ", -1);
+ */
+ ve = v + JA_SEGMENT_SIZE;
+ while (v < ve && cum < sum) {
+ grn_id id = *((grn_id *)v);
+ /*
+ GRN_OUTPUT_MAP_OPEN("ENTRY", -1);
+ GRN_OUTPUT_CSTR("id");
+ GRN_OUTPUT_INT64(id);
+ */
+ if (!id) { break; }
+ if (id & DELETED) {
+ element_size = (id & ~DELETED);
+ n_del_elements++;
+ s_del_elements += element_size;
+ } else {
+ element_size = grn_ja_size(ctx, ja, id);
+ element_size = (element_size + sizeof(grn_id) - 1) & ~(sizeof(grn_id) - 1);
+ cum += sizeof(uint32_t) + element_size;
+ n_elements++;
+ s_elements += sizeof(uint32_t) + element_size;
+ }
+ v += sizeof(uint32_t) + element_size;
+ /*
+ GRN_OUTPUT_CSTR("size");
+ GRN_OUTPUT_INT64(element_size);
+ GRN_OUTPUT_CSTR("cum");
+ GRN_OUTPUT_INT64(cum);
+ GRN_OUTPUT_MAP_CLOSE();
+ */
+ }
+ GRN_IO_SEG_UNREF(ja->io, seg);
+ /*
+ GRN_OUTPUT_ARRAY_CLOSE();
+ */
+ GRN_OUTPUT_CSTR("n_elements");
+ GRN_OUTPUT_INT64(n_elements);
+ GRN_OUTPUT_CSTR("s_elements");
+ GRN_OUTPUT_INT64(s_elements);
+ GRN_OUTPUT_CSTR("n_del_elements");
+ GRN_OUTPUT_INT64(n_del_elements);
+ GRN_OUTPUT_CSTR("s_del_elements");
+ GRN_OUTPUT_INT64(s_del_elements);
+ if (cum != sum) {
+ GRN_OUTPUT_CSTR("cum gap");
+ GRN_OUTPUT_INT64(cum - sum);
+ }
+ }
+ }
+ GRN_OUTPUT_MAP_CLOSE();
+ }
+ }
+ GRN_OUTPUT_ARRAY_CLOSE();
+ GRN_OUTPUT_ARRAY_CLOSE();
+}
+
+/* grn_ja_reader */
+
+grn_rc
+grn_ja_reader_init(grn_ctx *ctx, grn_ja_reader *reader, grn_ja *ja)
+{
+ reader->ja = ja;
+ reader->einfo_seg_id = JA_ESEG_VOID;
+ reader->ref_avail = GRN_FALSE;
+ reader->ref_seg_id = JA_ESEG_VOID;
+ reader->ref_seg_ids = NULL;
+ reader->nref_seg_ids = 0;
+ reader->ref_seg_ids_size = 0;
+ reader->body_seg_id = JA_ESEG_VOID;
+ reader->body_seg_addr = NULL;
+ reader->packed_buf = NULL;
+ reader->packed_buf_size = 0;
+#ifdef GRN_WITH_ZLIB
+ if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
+ z_stream *new_stream = GRN_MALLOCN(z_stream, 1);
+ if (!new_stream) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ new_stream->zalloc = NULL;
+ new_stream->zfree = NULL;
+ new_stream->opaque = NULL;
+ if (inflateInit2(new_stream, 15) != Z_OK) {
+ GRN_FREE(new_stream);
+ return GRN_ZLIB_ERROR;
+ }
+ reader->stream = new_stream;
+ }
+#endif /* GRN_WITH_ZLIB */
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_reader_fin(grn_ctx *ctx, grn_ja_reader *reader)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (reader->einfo_seg_id != JA_ESEG_VOID) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
+ }
+ if (reader->ref_seg_ids) {
+ grn_ja_reader_unref(ctx, reader);
+ GRN_FREE(reader->ref_seg_ids);
+ }
+ if (reader->body_seg_addr) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
+ }
+ if (reader->packed_buf) {
+ GRN_FREE(reader->packed_buf);
+ }
+#ifdef GRN_WITH_ZLIB
+ if (reader->ja->header->flags & GRN_OBJ_COMPRESS_ZLIB) {
+ if (reader->stream) {
+ if (inflateEnd((z_stream *)reader->stream) != Z_OK) {
+ rc = GRN_UNKNOWN_ERROR;
+ }
+ GRN_FREE(reader->stream);
+ }
+ }
+#endif /* GRN_WITH_ZLIB */
+ return rc;
+}
+
+grn_rc
+grn_ja_reader_open(grn_ctx *ctx, grn_ja *ja, grn_ja_reader **reader)
+{
+ grn_rc rc;
+ grn_ja_reader *new_reader = GRN_MALLOCN(grn_ja_reader, 1);
+ if (!new_reader) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ rc = grn_ja_reader_init(ctx, new_reader, ja);
+ if (rc != GRN_SUCCESS) {
+ GRN_FREE(new_reader);
+ return rc;
+ }
+ *reader = new_reader;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_reader_close(grn_ctx *ctx, grn_ja_reader *reader)
+{
+ grn_rc rc = grn_ja_reader_fin(ctx, reader);
+ GRN_FREE(reader);
+ return rc;
+}
+
+#ifdef GRN_WITH_COMPRESSED
+/* grn_ja_reader_seek_compressed() prepares to access a compressed value. */
+static grn_rc
+grn_ja_reader_seek_compressed(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
+{
+ grn_ja_einfo *einfo;
+ void *seg_addr;
+ uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
+ if (seg_id == JA_ESEG_VOID) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (seg_id != reader->einfo_seg_id) {
+ GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ if (reader->einfo_seg_id != JA_ESEG_VOID) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
+ }
+ reader->einfo_seg_id = seg_id;
+ reader->einfo_seg_addr = seg_addr;
+ }
+ einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
+ einfo += id & JA_M_EINFO_IN_A_SEGMENT;
+ reader->einfo = einfo;
+ /* ETINY_P(einfo) is always false because the original size needs 8 bytes. */
+ if (EHUGE_P(einfo)) {
+ EHUGE_DEC(einfo, seg_id, reader->packed_size);
+ reader->body_seg_offset = 0;
+ } else {
+ EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->packed_size);
+ }
+ if (seg_id != reader->body_seg_id) {
+ GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ if (reader->body_seg_addr) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
+ }
+ reader->body_seg_id = seg_id;
+ reader->body_seg_addr = seg_addr;
+ }
+ seg_addr = (char *)reader->body_seg_addr + reader->body_seg_offset;
+ reader->value_size = (uint32_t)*(uint64_t *)seg_addr;
+ return GRN_SUCCESS;
+}
+#endif /* GRN_WITH_COMPRESSED */
+
+/* grn_ja_reader_seek_raw() prepares to access a value. */
+static grn_rc
+grn_ja_reader_seek_raw(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
+{
+ grn_ja_einfo *einfo;
+ void *seg_addr;
+ uint32_t seg_id = reader->ja->header->esegs[id >> JA_W_EINFO_IN_A_SEGMENT];
+ if (seg_id == JA_ESEG_VOID) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (seg_id != reader->einfo_seg_id) {
+ GRN_IO_SEG_REF(reader->ja->io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ if (reader->einfo_seg_id != JA_ESEG_VOID) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->einfo_seg_id);
+ }
+ reader->einfo_seg_id = seg_id;
+ reader->einfo_seg_addr = seg_addr;
+ }
+ einfo = (grn_ja_einfo *)reader->einfo_seg_addr;
+ einfo += id & JA_M_EINFO_IN_A_SEGMENT;
+ reader->einfo = einfo;
+ if (ETINY_P(einfo)) {
+ ETINY_DEC(einfo, reader->value_size);
+ reader->ref_avail = GRN_FALSE;
+ } else {
+ if (EHUGE_P(einfo)) {
+ EHUGE_DEC(einfo, seg_id, reader->value_size);
+ reader->ref_avail = GRN_FALSE;
+ } else {
+ EINFO_DEC(einfo, seg_id, reader->body_seg_offset, reader->value_size);
+ reader->ref_avail = GRN_TRUE;
+ }
+ if (reader->body_seg_addr) {
+ if (seg_id != reader->body_seg_id) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->body_seg_id);
+ reader->body_seg_addr = NULL;
+ }
+ }
+ reader->body_seg_id = seg_id;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_reader_seek(grn_ctx *ctx, grn_ja_reader *reader, grn_id id)
+{
+ switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
+#ifdef GRN_WITH_ZLIB
+ case GRN_OBJ_COMPRESS_ZLIB :
+ return grn_ja_reader_seek_compressed(ctx, reader, id);
+#endif /* GRN_WITH_ZLIB */
+#ifdef GRN_WITH_LZ4
+ case GRN_OBJ_COMPRESS_LZ4 :
+ return grn_ja_reader_seek_compressed(ctx, reader, id);
+#endif /* GRN_WITH_LZ4 */
+#ifdef GRN_WITH_ZSTD
+ case GRN_OBJ_COMPRESS_ZSTD :
+ return grn_ja_reader_seek_compressed(ctx, reader, id);
+#endif /* GRN_WITH_ZSTD */
+ default :
+ return grn_ja_reader_seek_raw(ctx, reader, id);
+ }
+}
+
+grn_rc
+grn_ja_reader_ref(grn_ctx *ctx, grn_ja_reader *reader, void **addr)
+{
+ if (!reader->ref_avail) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (reader->body_seg_id != reader->ref_seg_id) {
+ void *seg_addr;
+ if (reader->nref_seg_ids == reader->ref_seg_ids_size) {
+ size_t n_bytes;
+ uint32_t new_size, *new_seg_ids;
+ if (reader->ref_seg_ids_size == 0) {
+ new_size = GRN_JA_READER_INITIAL_REF_SEG_IDS_SIZE;
+ } else {
+ new_size = reader->ref_seg_ids_size * 2;
+ }
+ n_bytes = sizeof(uint32_t) * new_size;
+ new_seg_ids = (uint32_t *)GRN_REALLOC(reader->ref_seg_ids, n_bytes);
+ if (!new_seg_ids) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ reader->ref_seg_ids = new_seg_ids;
+ reader->ref_seg_ids_size = new_size;
+ }
+ GRN_IO_SEG_REF(reader->ja->io, reader->body_seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ reader->ref_seg_id = reader->body_seg_id;
+ reader->ref_seg_addr = seg_addr;
+ reader->ref_seg_ids[reader->nref_seg_ids++] = reader->body_seg_id;
+ }
+ *addr = (char *)reader->ref_seg_addr + reader->body_seg_offset;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_reader_unref(grn_ctx *ctx, grn_ja_reader *reader)
+{
+ uint32_t i;
+ for (i = 0; i < reader->nref_seg_ids; i++) {
+ GRN_IO_SEG_UNREF(reader->ja->io, reader->ref_seg_ids[i]);
+ }
+ reader->ref_seg_id = JA_ESEG_VOID;
+ reader->nref_seg_ids = 0;
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+
+#ifdef GRN_WITH_ZLIB
+/* grn_ja_reader_read_zlib() reads a value compressed with zlib. */
+static grn_rc
+grn_ja_reader_read_zlib(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
+{
+ uLong dest_size = reader->value_size;
+ z_stream *stream = (z_stream *)reader->stream;
+ grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
+ if (EHUGE_P(einfo)) {
+ /* TODO: Use z_stream to avoid copy. */
+ grn_io *io = reader->ja->io;
+ void *seg_addr;
+ char *packed_ptr;
+ uint32_t size, seg_id;
+ if (reader->packed_size > reader->packed_buf_size) {
+ void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
+ if (!new_buf) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ reader->packed_buf = new_buf;
+ reader->packed_buf_size = reader->packed_size;
+ }
+ packed_ptr = (char *)reader->packed_buf;
+ grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
+ io->header->segment_size - sizeof(uint64_t));
+ packed_ptr += io->header->segment_size - sizeof(uint64_t);
+ size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
+ seg_id = reader->body_seg_id + 1;
+ while (size > io->header->segment_size) {
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ size -= io->header->segment_size;
+ packed_ptr += io->header->segment_size;
+ }
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(packed_ptr, seg_addr, size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ if (uncompress((Bytef *)buf, &dest_size, (Bytef *)reader->packed_buf,
+ reader->packed_size - sizeof(uint64_t)) != Z_OK) {
+ return GRN_ZLIB_ERROR;
+ }
+ if (dest_size != reader->value_size) {
+ return GRN_ZLIB_ERROR;
+ }
+ } else {
+ char *packed_addr = (char *)reader->body_seg_addr;
+ packed_addr += reader->body_seg_offset + sizeof(uint64_t);
+ if (inflateReset(stream) != Z_OK) {
+ return GRN_ZLIB_ERROR;
+ }
+ stream->next_in = (Bytef *)packed_addr;
+ stream->avail_in = reader->packed_size - sizeof(uint64_t);
+ stream->next_out = (Bytef *)buf;
+ stream->avail_out = dest_size;
+ if ((inflate(stream, Z_FINISH) != Z_STREAM_END) || stream->avail_out) {
+ return GRN_ZLIB_ERROR;
+ }
+ }
+ return GRN_SUCCESS;
+}
+#endif /* GRN_WITH_ZLIB */
+
+#ifdef GRN_WITH_LZ4
+/* grn_ja_reader_read_lz4() reads a value compressed with LZ4. */
+static grn_rc
+grn_ja_reader_read_lz4(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
+{
+ int src_size, dest_size;
+ grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
+ if (EHUGE_P(einfo)) {
+ grn_io *io = reader->ja->io;
+ void *seg_addr;
+ char *packed_ptr;
+ uint32_t size, seg_id;
+ if (reader->packed_size > reader->packed_buf_size) {
+ void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
+ if (!new_buf) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ reader->packed_buf = new_buf;
+ reader->packed_buf_size = reader->packed_size;
+ }
+ packed_ptr = (char *)reader->packed_buf;
+ grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
+ io->header->segment_size - sizeof(uint64_t));
+ packed_ptr += io->header->segment_size - sizeof(uint64_t);
+ size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
+ seg_id = reader->body_seg_id + 1;
+ while (size > io->header->segment_size) {
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ size -= io->header->segment_size;
+ packed_ptr += io->header->segment_size;
+ }
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(packed_ptr, seg_addr, size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ src_size = (int)(reader->packed_size - sizeof(uint64_t));
+ dest_size = LZ4_decompress_safe(reader->packed_buf, buf, src_size,
+ (int)reader->value_size);
+ } else {
+ char *packed_addr = (char *)reader->body_seg_addr;
+ packed_addr += reader->body_seg_offset + sizeof(uint64_t);
+ src_size = (int)(reader->packed_size - sizeof(uint64_t));
+ dest_size = LZ4_decompress_safe(packed_addr, buf, src_size,
+ (int)reader->value_size);
+ }
+ if ((uint32_t)dest_size != reader->value_size) {
+ return GRN_LZ4_ERROR;
+ }
+ return GRN_SUCCESS;
+}
+#endif /* GRN_WITH_LZ4 */
+
+#ifdef GRN_WITH_ZSTD
+/* grn_ja_reader_read_zstd() reads a value compressed with Zstandard. */
+static grn_rc
+grn_ja_reader_read_zstd(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
+{
+ int src_size, dest_size;
+ grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
+ if (EHUGE_P(einfo)) {
+ grn_io *io = reader->ja->io;
+ void *seg_addr;
+ char *packed_ptr;
+ uint32_t size, seg_id;
+ if (reader->packed_size > reader->packed_buf_size) {
+ void *new_buf = GRN_REALLOC(reader->packed_buf, reader->packed_size);
+ if (!new_buf) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ reader->packed_buf = new_buf;
+ reader->packed_buf_size = reader->packed_size;
+ }
+ packed_ptr = (char *)reader->packed_buf;
+ grn_memcpy(packed_ptr, (char *)reader->body_seg_addr + sizeof(uint64_t),
+ io->header->segment_size - sizeof(uint64_t));
+ packed_ptr += io->header->segment_size - sizeof(uint64_t);
+ size = reader->packed_size - (io->header->segment_size - sizeof(uint64_t));
+ seg_id = reader->body_seg_id + 1;
+ while (size > io->header->segment_size) {
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(packed_ptr, seg_addr, io->header->segment_size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ size -= io->header->segment_size;
+ packed_ptr += io->header->segment_size;
+ }
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(packed_ptr, seg_addr, size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ src_size = (int)(reader->packed_size - sizeof(uint64_t));
+ dest_size = ZSTD_decompress(reader->packed_buf, reader->value_size,
+ buf, src_size);
+ } else {
+ char *packed_addr = (char *)reader->body_seg_addr;
+ packed_addr += reader->body_seg_offset + sizeof(uint64_t);
+ src_size = (int)(reader->packed_size - sizeof(uint64_t));
+ dest_size = ZSTD_decompress(packed_addr, reader->value_size,
+ buf, src_size);
+ }
+ if ((uint32_t)dest_size != reader->value_size) {
+ return GRN_ZSTD_ERROR;
+ }
+ return GRN_SUCCESS;
+}
+#endif /* GRN_WITH_ZSTD */
+
+/* grn_ja_reader_read_raw() reads a value. */
+static grn_rc
+grn_ja_reader_read_raw(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
+{
+ grn_io *io = reader->ja->io;
+ grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
+ if (ETINY_P(einfo)) {
+ grn_memcpy(buf, einfo, reader->value_size);
+ } else if (EHUGE_P(einfo)) {
+ char *buf_ptr = (char *)buf;
+ void *seg_addr;
+ uint32_t seg_id = reader->body_seg_id;
+ uint32_t size = reader->value_size;
+ while (size > io->header->segment_size) {
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(buf_ptr, seg_addr, io->header->segment_size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ size -= io->header->segment_size;
+ buf_ptr += io->header->segment_size;
+ }
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(buf_ptr, seg_addr, size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ } else {
+ if (!reader->body_seg_addr) {
+ GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
+ if (!reader->body_seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ }
+ grn_memcpy(buf, (char *)reader->body_seg_addr + reader->body_seg_offset,
+ reader->value_size);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_reader_read(grn_ctx *ctx, grn_ja_reader *reader, void *buf)
+{
+ switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
+#ifdef GRN_WITH_ZLIB
+ case GRN_OBJ_COMPRESS_ZLIB :
+ return grn_ja_reader_read_zlib(ctx, reader, buf);
+#endif /* GRN_WITH_ZLIB */
+#ifdef GRN_WITH_LZ4
+ case GRN_OBJ_COMPRESS_LZ4 :
+ return grn_ja_reader_read_lz4(ctx, reader, buf);
+#endif /* GRN_WITH_LZ4 */
+#ifdef GRN_WITH_ZSTD
+ case GRN_OBJ_COMPRESS_ZSTD :
+ return grn_ja_reader_read_zstd(ctx, reader, buf);
+#endif /* GRN_WITH_ZSTD */
+ default :
+ return grn_ja_reader_read_raw(ctx, reader, buf);
+ }
+}
+
+#ifdef GRN_WITH_ZLIB
+/* grn_ja_reader_pread_zlib() reads a part of a value compressed with zlib. */
+static grn_rc
+grn_ja_reader_pread_zlib(grn_ctx *ctx, grn_ja_reader *reader,
+ size_t offset, size_t size, void *buf)
+{
+ /* TODO: To be supported? */
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+#endif /* GRN_WITH_ZLIB */
+
+#ifdef GRN_WITH_LZ4
+/* grn_ja_reader_pread_lz4() reads a part of a value compressed with LZ4. */
+static grn_rc
+grn_ja_reader_pread_lz4(grn_ctx *ctx, grn_ja_reader *reader,
+ size_t offset, size_t size, void *buf)
+{
+ /* TODO: To be supported? */
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+#endif /* GRN_WITH_LZ4 */
+
+#ifdef GRN_WITH_ZSTD
+/* grn_ja_reader_pread_zstd() reads a part of a value compressed with ZSTD. */
+static grn_rc
+grn_ja_reader_pread_zstd(grn_ctx *ctx, grn_ja_reader *reader,
+ size_t offset, size_t size, void *buf)
+{
+ /* TODO: To be supported? */
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+#endif /* GRN_WITH_ZSTD */
+
+/* grn_ja_reader_pread_raw() reads a part of a value. */
+static grn_rc
+grn_ja_reader_pread_raw(grn_ctx *ctx, grn_ja_reader *reader,
+ size_t offset, size_t size, void *buf)
+{
+ grn_io *io = reader->ja->io;
+ grn_ja_einfo *einfo = (grn_ja_einfo *)reader->einfo;
+ if ((offset >= reader->value_size) || !size) {
+ return GRN_SUCCESS;
+ }
+ if (size > (reader->value_size - offset)) {
+ size = reader->value_size - offset;
+ }
+ if (ETINY_P(einfo)) {
+ grn_memcpy(buf, (char *)einfo + offset, size);
+ } else if (EHUGE_P(einfo)) {
+ char *buf_ptr = (char *)buf;
+ void *seg_addr;
+ uint32_t seg_id = reader->body_seg_id;
+ if (offset >= io->header->segment_size) {
+ seg_id += offset / io->header->segment_size;
+ offset %= io->header->segment_size;
+ }
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(buf_ptr, (char *)seg_addr + offset,
+ io->header->segment_size - offset);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ size -= io->header->segment_size - offset;
+ buf_ptr += io->header->segment_size - offset;
+ while (size > io->header->segment_size) {
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(buf_ptr, (char *)seg_addr, io->header->segment_size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ seg_id++;
+ size -= io->header->segment_size;
+ buf_ptr += io->header->segment_size;
+ }
+ GRN_IO_SEG_REF(io, seg_id, seg_addr);
+ if (!seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ grn_memcpy(buf_ptr, seg_addr, size);
+ GRN_IO_SEG_UNREF(io, seg_id);
+ } else {
+ if (!reader->body_seg_addr) {
+ GRN_IO_SEG_REF(io, reader->body_seg_id, reader->body_seg_addr);
+ if (!reader->body_seg_addr) {
+ return GRN_UNKNOWN_ERROR;
+ }
+ }
+ offset += reader->body_seg_offset;
+ grn_memcpy(buf, (char *)reader->body_seg_addr + offset, size);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ja_reader_pread(grn_ctx *ctx, grn_ja_reader *reader,
+ size_t offset, size_t size, void *buf)
+{
+ switch (reader->ja->header->flags & GRN_OBJ_COMPRESS_MASK) {
+#ifdef GRN_WITH_ZLIB
+ case GRN_OBJ_COMPRESS_ZLIB :
+ return grn_ja_reader_pread_zlib(ctx, reader, offset, size, buf);
+#endif /* GRN_WITH_ZLIB */
+#ifdef GRN_WITH_LZ4
+ case GRN_OBJ_COMPRESS_LZ4 :
+ return grn_ja_reader_pread_lz4(ctx, reader, offset, size, buf);
+#endif /* GRN_WITH_LZ4 */
+#ifdef GRN_WITH_ZSTD
+ case GRN_OBJ_COMPRESS_ZSTD :
+ return grn_ja_reader_pread_zstd(ctx, reader, offset, size, buf);
+#endif /* GRN_WITH_ZSTD */
+ default :
+ return grn_ja_reader_pread_raw(ctx, reader, offset, size, buf);
+ }
+}
+
+/**** vgram ****/
+
+/*
+
+static int len_sum = 0;
+static int img_sum = 0;
+static int simple_sum = 0;
+static int skip_sum = 0;
+
+grn_vgram *
+grn_vgram_create(const char *path)
+{
+ grn_vgram *s;
+ if (!(s = GRN_MALLOCN(grn_vgram, 1))) { return NULL; }
+ s->vgram = grn_sym_create(path, sizeof(grn_id) * 2, 0, GRN_ENC_NONE);
+ if (!s->vgram) {
+ GRN_FREE(s);
+ return NULL;
+ }
+ return s;
+}
+
+grn_vgram *
+grn_vgram_open(const char *path)
+{
+ grn_vgram *s;
+ if (!(s = GRN_MALLOCN(grn_vgram, 1))) { return NULL; }
+ s->vgram = grn_sym_open(path);
+ if (!s->vgram) {
+ GRN_FREE(s);
+ return NULL;
+ }
+ return s;
+}
+
+grn_vgram_buf *
+grn_vgram_buf_open(size_t len)
+{
+ grn_vgram_buf *b;
+ if (!(b = GRN_MALLOCN(grn_vgram_buf, 1))) { return NULL; }
+ b->len = len;
+ b->tvs = b->tvp = GRN_MALLOCN(grn_id, len);
+ if (!b->tvp) { GRN_FREE(b); return NULL; }
+ b->tve = b->tvs + len;
+ b->vps = b->vpp = GRN_MALLOCN(grn_vgram_vnode, len * 2);
+ if (!b->vpp) { GRN_FREE(b->tvp); GRN_FREE(b); return NULL; }
+ b->vpe = b->vps + len;
+ return b;
+}
+
+grn_rc
+grn_vgram_buf_add(grn_vgram_buf *b, grn_id tid)
+{
+ uint8_t dummybuf[8], *dummyp;
+ if (b->tvp < b->tve) { *b->tvp++ = tid; }
+ dummyp = dummybuf;
+ GRN_B_ENC(tid, dummyp);
+ simple_sum += dummyp - dummybuf;
+ return GRN_SUCCESS;
+}
+
+typedef struct {
+ grn_id vid;
+ grn_id tid;
+} vgram_key;
+
+grn_rc
+grn_vgram_update(grn_vgram *vgram, grn_id rid, grn_vgram_buf *b, grn_hash *terms)
+{
+ grn_inv_updspec **u;
+ if (b && b->tvs < b->tvp) {
+ grn_id *t0, *tn;
+ for (t0 = b->tvs; t0 < b->tvp - 1; t0++) {
+ grn_vgram_vnode *v, **vp;
+ if (grn_set_at(terms, t0, (void **) &u)) {
+ vp = &(*u)->vnodes;
+ for (tn = t0 + 1; tn < b->tvp; tn++) {
+ for (v = *vp; v && v->tid != *tn; v = v->cdr) ;
+ if (!v) {
+ if (b->vpp < b->vpe) {
+ v = b->vpp++;
+ } else {
+ // todo;
+ break;
+ }
+ v->car = NULL;
+ v->cdr = *vp;
+ *vp = v;
+ v->tid = *tn;
+ v->vid = 0;
+ v->freq = 0;
+ v->len = tn - t0;
+ }
+ v->freq++;
+ if (v->vid) {
+ vp = &v->car;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ {
+ grn_set *th = grn_set_open(sizeof(grn_id), sizeof(int), 0);
+ if (!th) { return GRN_NO_MEMORY_AVAILABLE; }
+ if (t0 == b->tvp) { GRN_LOG(ctx, GRN_LOG_DEBUG, "t0 == tvp"); }
+ for (t0 = b->tvs; t0 < b->tvp; t0++) {
+ grn_id vid, vid0 = *t0, vid1 = 0;
+ grn_vgram_vnode *v, *v2 = NULL, **vp;
+ if (grn_set_at(terms, t0, (void **) &u)) {
+ vp = &(*u)->vnodes;
+ for (tn = t0 + 1; tn < b->tvp; tn++) {
+ for (v = *vp; v; v = v->cdr) {
+ if (!v->vid && (v->freq < 2 || v->freq * v->len < 4)) {
+ *vp = v->cdr;
+ v->freq = 0;
+ }
+ if (v->tid == *tn) { break; }
+ vp = &v->cdr;
+ }
+ if (v) {
+ if (v->freq) {
+ v2 = v;
+ vid1 = vid0;
+ vid0 = v->vid;
+ }
+ if (v->vid) {
+ vp = &v->car;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ if (v2) {
+ if (!v2->vid) {
+ vgram_key key;
+ key.vid = vid1;
+ key.tid = v2->tid;
+ if (!(v2->vid = grn_sym_get(vgram->vgram, (char *)&key))) {
+ grn_set_close(th);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ vid = *t0 = v2->vid * 2 + 1;
+ memset(t0 + 1, 0, sizeof(grn_id) * v2->len);
+ t0 += v2->len;
+ } else {
+ vid = *t0 *= 2;
+ }
+ {
+ int *tf;
+ if (!grn_set_get(th, &vid, (void **) &tf)) {
+ grn_set_close(th);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ (*tf)++;
+ }
+ }
+ if (!th->n_entries) { GRN_LOG(ctx, GRN_LOG_DEBUG, "th->n_entries == 0"); }
+ {
+ int j = 0;
+ int skip = 0;
+ grn_set_eh *ehs, *ehp, *ehe;
+ grn_set_sort_optarg arg;
+ uint8_t *ps = GRN_MALLOC(b->len * 2), *pp, *pe;
+ if (!ps) {
+ grn_set_close(th);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ pp = ps;
+ pe = ps + b->len * 2;
+ arg.mode = grn_sort_descending;
+ arg.compar = NULL;
+ arg.compar_arg = (void *)(intptr_t)sizeof(grn_id);
+ ehs = grn_set_sort(th, 0, &arg);
+ if (!ehs) {
+ GRN_FREE(ps);
+ grn_set_close(th);
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ GRN_B_ENC(th->n_entries, pp);
+ for (ehp = ehs, ehe = ehs + th->n_entries; ehp < ehe; ehp++, j++) {
+ int *id = (int *)GRN_SET_INTVAL(*ehp);
+ GRN_B_ENC(*GRN_SET_INTKEY(*ehp), pp);
+ *id = j;
+ }
+ for (t0 = b->tvs; t0 < b->tvp; t0++) {
+ if (*t0) {
+ int *id;
+ if (!grn_set_at(th, t0, (void **) &id)) {
+ GRN_LOG(ctx, GRN_LOG_ERROR, "lookup error (%d)", *t0);
+ }
+ GRN_B_ENC(*id, pp);
+ } else {
+ skip++;
+ }
+ }
+ len_sum += b->len;
+ img_sum += pp - ps;
+ skip_sum += skip;
+ GRN_FREE(ehs);
+ GRN_FREE(ps);
+ }
+ grn_set_close(th);
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_vgram_buf_close(grn_vgram_buf *b)
+{
+ if (!b) { return GRN_INVALID_ARGUMENT; }
+ if (b->tvs) { GRN_FREE(b->tvs); }
+ if (b->vps) { GRN_FREE(b->vps); }
+ GRN_FREE(b);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_vgram_close(grn_vgram *vgram)
+{
+ if (!vgram) { return GRN_INVALID_ARGUMENT; }
+ GRN_LOG(ctx, GRN_LOG_DEBUG, "len=%d img=%d skip=%d simple=%d", len_sum, img_sum, skip_sum, simple_sum);
+ grn_sym_close(vgram->vgram);
+ GRN_FREE(vgram);
+ return GRN_SUCCESS;
+}
+*/
diff --git a/storage/mroonga/vendor/groonga/lib/str.c b/storage/mroonga/vendor/groonga/lib/str.c
new file mode 100644
index 00000000..4f0a3a98
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/str.c
@@ -0,0 +1,3276 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include <limits.h>
+#include <stdarg.h>
+#include <string.h>
+#include "grn_db.h"
+#include "grn_str.h"
+#include "grn_nfkc.h"
+
+#ifndef _ISOC99_SOURCE
+#define _ISOC99_SOURCE
+#endif /* _ISOC99_SOURCE */
+#include <math.h>
+
+#if defined(HAVE__GMTIME64_S) && defined(__GNUC__)
+# ifdef _WIN64
+# define gmtime_s(tm, time) _gmtime64_s(tm, time)
+# else /* _WIN64 */
+# define gmtime_s(tm, time) _gmtime32_s(tm, time)
+# endif /* _WIN64 */
+#endif /* defined(HAVE__GMTIME64_S) && defined(__GNUC__) */
+
+inline static int
+grn_str_charlen_utf8(grn_ctx *ctx, const unsigned char *str, const unsigned char *end)
+{
+ /* MEMO: This function allows non-null-terminated string as str. */
+ /* But requires the end of string. */
+ if (end <= str || !*str) {
+ return 0;
+ }
+ if (*str & 0x80) {
+ int i;
+ int len;
+ GRN_BIT_SCAN_REV(~(((uint) *str) << 24), len);
+ len = 31 - len;
+ if ((unsigned int)(len - 2) >= 3) { /* (len == 1 || len >= 5) */
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "grn_str_charlen_utf8(): first byte is invalid");
+ return 0;
+ }
+ if (str + len > end) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "grn_str_charlen_utf8(): incomplete character");
+ return 0;
+ }
+ for (i = 1; i < len; ++i) {
+ if ((str[i] & 0xc0) != 0x80) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "grn_str_charlen_utf8(): <%d>th byte is invalid",
+ i + 1);
+ return 0;
+ }
+ }
+ return len;
+ } else {
+ return 1;
+ }
+}
+
+unsigned int
+grn_str_charlen(grn_ctx *ctx, const char *str, grn_encoding encoding)
+{
+ /* MEMO: This function requires null-terminated string as str.*/
+ unsigned char *p = (unsigned char *) str;
+ if (!*p) { return 0; }
+ switch (encoding) {
+ case GRN_ENC_EUC_JP :
+ if (*p & 0x80) {
+ if (*(p + 1)) {
+ return 2;
+ } else {
+ /* This is invalid character */
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid euc-jp string end on grn_str_charlen");
+ return 0;
+ }
+ }
+ return 1;
+ case GRN_ENC_UTF8 :
+ if (*p & 0x80) {
+ int b, w;
+ size_t size;
+ for (b = 0x40, w = 0; b && (*p & b); b >>= 1, w++);
+ if (!w) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid utf8 string(1) on grn_str_charlen");
+ return 0;
+ }
+ for (size = 1; w--; size++) {
+ if (!*++p || (*p & 0xc0) != 0x80) {
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid utf8 string(2) on grn_str_charlen");
+ return 0;
+ }
+ }
+ return size;
+ } else {
+ return 1;
+ }
+ case GRN_ENC_SJIS :
+ if (*p & 0x80) {
+ /* we regard 0xa0 as JIS X 0201 KANA. adjusted to other tools. */
+ if (0xa0 <= *p && *p <= 0xdf) {
+ /* hankaku-kana */
+ return 1;
+ } else if (!(*(p + 1))) {
+ /* This is invalid character */
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid sjis string end on grn_str_charlen");
+ return 0;
+ } else {
+ return 2;
+ }
+ } else {
+ return 1;
+ }
+ default :
+ return 1;
+ }
+ return 0;
+}
+
+int
+grn_charlen_(grn_ctx *ctx, const char *str, const char *end, grn_encoding encoding)
+{
+ /* MEMO: This function allows non-null-terminated string as str. */
+ /* But requires the end of string. */
+ unsigned char *p = (unsigned char *) str;
+ if (p >= (unsigned char *)end) { return 0; }
+ switch (encoding) {
+ case GRN_ENC_EUC_JP :
+ if (*p & 0x80) {
+ if ((p + 1) < (unsigned char *)end) {
+ return 2;
+ } else {
+ /* This is invalid character */
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid euc-jp string end on grn_charlen");
+ return 0;
+ }
+ }
+ return 1;
+ case GRN_ENC_UTF8 :
+ return grn_str_charlen_utf8(ctx, p, (unsigned char *)end);
+ case GRN_ENC_SJIS :
+ if (*p & 0x80) {
+ /* we regard 0xa0 as JIS X 0201 KANA. adjusted to other tools. */
+ if (0xa0 <= *p && *p <= 0xdf) {
+ /* hankaku-kana */
+ return 1;
+ } else if (++p >= (unsigned char *)end) {
+ /* This is invalid character */
+ GRN_LOG(ctx, GRN_LOG_WARNING, "invalid sjis string end on grn_charlen");
+ return 0;
+ } else {
+ return 2;
+ }
+ } else {
+ return 1;
+ }
+ default :
+ return 1;
+ }
+ return 0;
+}
+
+int
+grn_charlen(grn_ctx *ctx, const char *str, const char *end)
+{
+ return grn_charlen_(ctx, str, end, ctx->encoding);
+}
+
+static unsigned char symbol[] = {
+ ',', '.', 0, ':', ';', '?', '!', 0, 0, 0, '`', 0, '^', '~', '_', 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, '-', '-', '/', '\\', 0, 0, '|', 0, 0, 0, '\'', 0,
+ '"', '(', ')', 0, 0, '[', ']', '{', '}', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ '+', '-', 0, 0, 0, '=', 0, '<', '>', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ '$', 0, 0, '%', '#', '&', '*', '@', 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+inline static grn_rc
+normalize_euc(grn_ctx *ctx, grn_str *nstr)
+{
+ static uint16_t hankana[] = {
+ 0xa1a1, 0xa1a3, 0xa1d6, 0xa1d7, 0xa1a2, 0xa1a6, 0xa5f2, 0xa5a1, 0xa5a3,
+ 0xa5a5, 0xa5a7, 0xa5a9, 0xa5e3, 0xa5e5, 0xa5e7, 0xa5c3, 0xa1bc, 0xa5a2,
+ 0xa5a4, 0xa5a6, 0xa5a8, 0xa5aa, 0xa5ab, 0xa5ad, 0xa5af, 0xa5b1, 0xa5b3,
+ 0xa5b5, 0xa5b7, 0xa5b9, 0xa5bb, 0xa5bd, 0xa5bf, 0xa5c1, 0xa5c4, 0xa5c6,
+ 0xa5c8, 0xa5ca, 0xa5cb, 0xa5cc, 0xa5cd, 0xa5ce, 0xa5cf, 0xa5d2, 0xa5d5,
+ 0xa5d8, 0xa5db, 0xa5de, 0xa5df, 0xa5e0, 0xa5e1, 0xa5e2, 0xa5e4, 0xa5e6,
+ 0xa5e8, 0xa5e9, 0xa5ea, 0xa5eb, 0xa5ec, 0xa5ed, 0xa5ef, 0xa5f3, 0xa1ab,
+ 0xa1eb
+ };
+ static unsigned char dakuten[] = {
+ 0xf4, 0, 0, 0, 0, 0xac, 0, 0xae, 0, 0xb0, 0, 0xb2, 0, 0xb4, 0, 0xb6, 0,
+ 0xb8, 0, 0xba, 0, 0xbc, 0, 0xbe, 0, 0xc0, 0, 0xc2, 0, 0, 0xc5, 0, 0xc7,
+ 0, 0xc9, 0, 0, 0, 0, 0, 0, 0xd0, 0, 0, 0xd3, 0, 0, 0xd6, 0, 0, 0xd9, 0,
+ 0, 0xdc
+ };
+ static unsigned char handaku[] = {
+ 0xd1, 0, 0, 0xd4, 0, 0, 0xd7, 0, 0, 0xda, 0, 0, 0xdd
+ };
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_, b;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->orig_blen, length = 0;
+ int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
+ if (!(nstr->norm = GRN_MALLOC(size * 2 + 1))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ d0 = (unsigned char *) nstr->norm;
+ if (nstr->flags & GRN_STR_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->norm);
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STR_WITH_CTYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->norm);
+ nstr->checks = NULL;
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->orig + size;
+ for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
+ if ((*s & 0x80)) {
+ if (((s + 1) < e) && (*(s + 1) & 0x80)) {
+ unsigned char c1 = *s++, c2 = *s, c3 = 0;
+ switch (c1 >> 4) {
+ case 0x08 :
+ if (c1 == 0x8e && 0xa0 <= c2 && c2 <= 0xdf) {
+ uint16_t c = hankana[c2 - 0xa0];
+ switch (c) {
+ case 0xa1ab :
+ if (d > d0 + 1 && d[-2] == 0xa5
+ && 0xa6 <= d[-1] && d[-1] <= 0xdb && (b = dakuten[d[-1] - 0xa6])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1] += 2; s_ += 2; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ case 0xa1eb :
+ if (d > d0 + 1 && d[-2] == 0xa5
+ && 0xcf <= d[-1] && d[-1] <= 0xdb && (b = handaku[d[-1] - 0xcf])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1] += 2; s_ += 2; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ default :
+ *d++ = c >> 8; *d = c & 0xff;
+ break;
+ }
+ ctype = GRN_CHAR_KATAKANA;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ case 0x09 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ case 0x0a :
+ switch (c1 & 0x0f) {
+ case 1 :
+ switch (c2) {
+ case 0xbc :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ break;
+ case 0xb9 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ break;
+ case 0xa1 :
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ break;
+ default :
+ if (c2 >= 0xa4 && (c3 = symbol[c2 - 0xa4])) {
+ *d = c3;
+ ctype = GRN_CHAR_SYMBOL;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ }
+ break;
+ case 2 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ break;
+ case 3 :
+ c3 = c2 - 0x80;
+ if ('a' <= c3 && c3 <= 'z') {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c3;
+ } else if ('A' <= c3 && c3 <= 'Z') {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c3 + 0x20;
+ } else if ('0' <= c3 && c3 <= '9') {
+ ctype = GRN_CHAR_DIGIT;
+ *d = c3;
+ } else {
+ ctype = GRN_CHAR_OTHERS;
+ *d++ = c1; *d = c2;
+ }
+ break;
+ case 4 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_HIRAGANA;
+ break;
+ case 5 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ break;
+ case 6 :
+ case 7 :
+ case 8 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ break;
+ default :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ break;
+ default :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ break;
+ }
+ } else {
+ /* skip invalid character */
+ continue;
+ }
+ } else {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->length = length;
+ nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
+ return GRN_SUCCESS;
+}
+
+#ifdef GRN_WITH_NFKC
+inline static grn_rc
+normalize_utf8(grn_ctx *ctx, grn_str *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *s__ = NULL, *p, *p2, *pe, *e;
+ unsigned char *d, *d_, *de;
+ uint_least8_t *cp;
+ size_t length = 0, ls, lp, size = nstr->orig_blen, ds = size * 3;
+ int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
+ if (!(nstr->norm = GRN_MALLOC(ds + 1))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ if (nstr->flags & GRN_STR_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(ds * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->norm); nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STR_WITH_CTYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(ds + 1))) {
+ if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
+ GRN_FREE(nstr->norm); nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ cp = nstr->ctypes;
+ d = (unsigned char *)nstr->norm;
+ de = d + ds;
+ d_ = NULL;
+ e = (unsigned char *)nstr->orig + size;
+ for (s = s_ = (unsigned char *)nstr->orig; ; s += ls) {
+ if (!(ls = grn_str_charlen_utf8(ctx, s, e))) {
+ break;
+ }
+ if ((p = (unsigned char *)grn_nfkc_decompose(s))) {
+ pe = p + strlen((char *)p);
+ } else {
+ p = s;
+ pe = p + ls;
+ }
+ if (d_ && (p2 = (unsigned char *)grn_nfkc_compose(d_, p))) {
+ p = p2;
+ pe = p + strlen((char *)p);
+ if (cp) { cp--; }
+ if (ch) {
+ ch -= (d - d_);
+ s_ = s__;
+ }
+ d = d_;
+ length--;
+ }
+ for (; ; p += lp) {
+ if (!(lp = grn_str_charlen_utf8(ctx, p, pe))) {
+ break;
+ }
+ if ((*p == ' ' && removeblankp) || *p < 0x20 /* skip unprintable ascii */ ) {
+ if (cp > nstr->ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ } else {
+ if (de <= d + lp) {
+ unsigned char *norm;
+ ds += (ds >> 1) + lp;
+ if (!(norm = GRN_REALLOC(nstr->norm, ds + 1))) {
+ if (nstr->ctypes) { GRN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
+ if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
+ GRN_FREE(nstr->norm); nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ de = norm + ds;
+ d = norm + (d - (unsigned char *)nstr->norm);
+ nstr->norm = (char *)norm;
+ if (ch) {
+ int16_t *checks;
+ if (!(checks = GRN_REALLOC(nstr->checks, ds * sizeof(int16_t)+ 1))) {
+ if (nstr->ctypes) { GRN_FREE(nstr->ctypes); nstr->ctypes = NULL; }
+ GRN_FREE(nstr->checks); nstr->checks = NULL;
+ GRN_FREE(nstr->norm); nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ ch = checks + (ch - nstr->checks);
+ nstr->checks = checks;
+ }
+ if (cp) {
+ uint_least8_t *ctypes;
+ if (!(ctypes = GRN_REALLOC(nstr->ctypes, ds + 1))) {
+ GRN_FREE(nstr->ctypes); nstr->ctypes = NULL;
+ if (nstr->checks) { GRN_FREE(nstr->checks); nstr->checks = NULL; }
+ GRN_FREE(nstr->norm); nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ cp = ctypes + (cp - nstr->ctypes);
+ nstr->ctypes = ctypes;
+ }
+ }
+ grn_memcpy(d, p, lp);
+ d_ = d;
+ d += lp;
+ length++;
+ if (cp) { *cp++ = grn_nfkc_char_type(p); }
+ if (ch) {
+ size_t i;
+ if (s_ == s + ls) {
+ *ch++ = -1;
+ } else {
+ *ch++ = (int16_t)(s + ls - s_);
+ s__ = s_;
+ s_ = s + ls;
+ }
+ for (i = lp; i > 1; i--) { *ch++ = 0; }
+ }
+ }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->length = length;
+ nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
+ return GRN_SUCCESS;
+}
+#endif /* GRN_WITH_NFKC */
+
+inline static grn_rc
+normalize_sjis(grn_ctx *ctx, grn_str *nstr)
+{
+ static uint16_t hankana[] = {
+ 0x8140, 0x8142, 0x8175, 0x8176, 0x8141, 0x8145, 0x8392, 0x8340, 0x8342,
+ 0x8344, 0x8346, 0x8348, 0x8383, 0x8385, 0x8387, 0x8362, 0x815b, 0x8341,
+ 0x8343, 0x8345, 0x8347, 0x8349, 0x834a, 0x834c, 0x834e, 0x8350, 0x8352,
+ 0x8354, 0x8356, 0x8358, 0x835a, 0x835c, 0x835e, 0x8360, 0x8363, 0x8365,
+ 0x8367, 0x8369, 0x836a, 0x836b, 0x836c, 0x836d, 0x836e, 0x8371, 0x8374,
+ 0x8377, 0x837a, 0x837d, 0x837e, 0x8380, 0x8381, 0x8382, 0x8384, 0x8386,
+ 0x8388, 0x8389, 0x838a, 0x838b, 0x838c, 0x838d, 0x838f, 0x8393, 0x814a,
+ 0x814b
+ };
+ static unsigned char dakuten[] = {
+ 0x94, 0, 0, 0, 0, 0x4b, 0, 0x4d, 0, 0x4f, 0, 0x51, 0, 0x53, 0, 0x55, 0,
+ 0x57, 0, 0x59, 0, 0x5b, 0, 0x5d, 0, 0x5f, 0, 0x61, 0, 0, 0x64, 0, 0x66,
+ 0, 0x68, 0, 0, 0, 0, 0, 0, 0x6f, 0, 0, 0x72, 0, 0, 0x75, 0, 0, 0x78, 0,
+ 0, 0x7b
+ };
+ static unsigned char handaku[] = {
+ 0x70, 0, 0, 0x73, 0, 0, 0x76, 0, 0, 0x79, 0, 0, 0x7c
+ };
+ int16_t *ch;
+ const unsigned char *s, *s_;
+ unsigned char *d, *d0, *d_, b, *e;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->orig_blen, length = 0;
+ int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
+ if (!(nstr->norm = GRN_MALLOC(size * 2 + 1))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ d0 = (unsigned char *) nstr->norm;
+ if (nstr->flags & GRN_STR_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * 2 * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->norm);
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STR_WITH_CTYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->norm);
+ nstr->checks = NULL;
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->orig + size;
+ for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
+ if ((*s & 0x80)) {
+ if (0xa0 <= *s && *s <= 0xdf) {
+ uint16_t c = hankana[*s - 0xa0];
+ switch (c) {
+ case 0x814a :
+ if (d > d0 + 1 && d[-2] == 0x83
+ && 0x45 <= d[-1] && d[-1] <= 0x7a && (b = dakuten[d[-1] - 0x45])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1]++; s_++; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ case 0x814b :
+ if (d > d0 + 1 && d[-2] == 0x83
+ && 0x6e <= d[-1] && d[-1] <= 0x7a && (b = handaku[d[-1] - 0x6e])) {
+ *(d - 1) = b;
+ if (ch) { ch[-1]++; s_++; }
+ continue;
+ } else {
+ *d++ = c >> 8; *d = c & 0xff;
+ }
+ break;
+ default :
+ *d++ = c >> 8; *d = c & 0xff;
+ break;
+ }
+ ctype = GRN_CHAR_KATAKANA;
+ } else {
+ if ((s + 1) < e && 0x40 <= *(s + 1) && *(s + 1) <= 0xfc) {
+ unsigned char c1 = *s++, c2 = *s, c3 = 0;
+ if (0x81 <= c1 && c1 <= 0x87) {
+ switch (c1 & 0x0f) {
+ case 1 :
+ switch (c2) {
+ case 0x5b :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ break;
+ case 0x58 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ break;
+ case 0x40 :
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ break;
+ default :
+ if (0x43 <= c2 && c2 <= 0x7e && (c3 = symbol[c2 - 0x43])) {
+ *d = c3;
+ ctype = GRN_CHAR_SYMBOL;
+ } else if (0x7f <= c2 && c2 <= 0x97 && (c3 = symbol[c2 - 0x44])) {
+ *d = c3;
+ ctype = GRN_CHAR_SYMBOL;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ }
+ break;
+ case 2 :
+ c3 = c2 - 0x1f;
+ if (0x4f <= c2 && c2 <= 0x58) {
+ ctype = GRN_CHAR_DIGIT;
+ *d = c2 - 0x1f;
+ } else if (0x60 <= c2 && c2 <= 0x79) {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c2 + 0x01;
+ } else if (0x81 <= c2 && c2 <= 0x9a) {
+ ctype = GRN_CHAR_ALPHA;
+ *d = c2 - 0x20;
+ } else if (0x9f <= c2 && c2 <= 0xf1) {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_HIRAGANA;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ case 3 :
+ if (0x40 <= c2 && c2 <= 0x96) {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KATAKANA;
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 4 :
+ case 7 :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_SYMBOL;
+ break;
+ default :
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ } else {
+ *d++ = c1; *d = c2;
+ ctype = GRN_CHAR_KANJI;
+ }
+ } else {
+ /* skip invalid character */
+ continue;
+ }
+ }
+ } else {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->length = length;
+ nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+normalize_none(grn_ctx *ctx, grn_str *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->orig_blen, length = 0;
+ int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
+ if (!(nstr->norm = GRN_MALLOC(size + 1))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ d0 = (unsigned char *) nstr->norm;
+ if (nstr->flags & GRN_STR_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->norm);
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STR_WITH_CTYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->norm);
+ nstr->checks = NULL;
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->orig + size;
+ for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->length = length;
+ nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
+ return GRN_SUCCESS;
+}
+
+/* use cp1252 as latin1 */
+inline static grn_rc
+normalize_latin1(grn_ctx *ctx, grn_str *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = nstr->orig_blen, length = 0;
+ int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
+ if (!(nstr->norm = GRN_MALLOC(size + 1))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ d0 = (unsigned char *) nstr->norm;
+ if (nstr->flags & GRN_STR_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->norm);
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STR_WITH_CTYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->norm);
+ nstr->checks = NULL;
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->orig + size;
+ for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ case 8 :
+ if (c == 0x8a || c == 0x8c || c == 0x8e) {
+ *d = c + 0x10;
+ ctype = GRN_CHAR_ALPHA;
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 9 :
+ if (c == 0x9a || c == 0x9c || c == 0x9e || c == 0x9f) {
+ *d = (c == 0x9f) ? c + 0x60 : c;
+ ctype = GRN_CHAR_ALPHA;
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 0x0c :
+ *d = c + 0x20;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ case 0x0d :
+ *d = (c == 0xd7 || c == 0xdf) ? c : c + 0x20;
+ ctype = (c == 0xd7) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 0x0e :
+ *d = c;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ case 0x0f :
+ *d = c;
+ ctype = (c == 0xf7) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->length = length;
+ nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+normalize_koi8r(grn_ctx *ctx, grn_str *nstr)
+{
+ int16_t *ch;
+ const unsigned char *s, *s_, *e;
+ unsigned char *d, *d0, *d_;
+ uint_least8_t *cp, *ctypes, ctype;
+ size_t size = strlen(nstr->orig), length = 0;
+ int removeblankp = nstr->flags & GRN_STR_REMOVEBLANK;
+ if (!(nstr->norm = GRN_MALLOC(size + 1))) {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ d0 = (unsigned char *) nstr->norm;
+ if (nstr->flags & GRN_STR_WITH_CHECKS) {
+ if (!(nstr->checks = GRN_MALLOC(size * sizeof(int16_t) + 1))) {
+ GRN_FREE(nstr->norm);
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ ch = nstr->checks;
+ if (nstr->flags & GRN_STR_WITH_CTYPES) {
+ if (!(nstr->ctypes = GRN_MALLOC(size + 1))) {
+ GRN_FREE(nstr->checks);
+ GRN_FREE(nstr->norm);
+ nstr->checks = NULL;
+ nstr->norm = NULL;
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+ cp = ctypes = nstr->ctypes;
+ e = (unsigned char *)nstr->orig + size;
+ for (s = s_ = (unsigned char *) nstr->orig, d = d_ = d0; s < e; s++) {
+ unsigned char c = *s;
+ switch (c >> 4) {
+ case 0 :
+ case 1 :
+ /* skip unprintable ascii */
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ case 2 :
+ if (c == 0x20) {
+ if (removeblankp) {
+ if (cp > ctypes) { *(cp - 1) |= GRN_STR_BLANK; }
+ continue;
+ } else {
+ *d = ' ';
+ ctype = GRN_STR_BLANK|GRN_CHAR_SYMBOL;
+ }
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_SYMBOL;
+ }
+ break;
+ case 3 :
+ *d = c;
+ ctype = (c <= 0x39) ? GRN_CHAR_DIGIT : GRN_CHAR_SYMBOL;
+ break;
+ case 4 :
+ *d = ('A' <= c) ? c + 0x20 : c;
+ ctype = (c == 0x40) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 5 :
+ *d = (c <= 'Z') ? c + 0x20 : c;
+ ctype = (c <= 0x5a) ? GRN_CHAR_ALPHA : GRN_CHAR_SYMBOL;
+ break;
+ case 6 :
+ *d = c;
+ ctype = (c == 0x60) ? GRN_CHAR_SYMBOL : GRN_CHAR_ALPHA;
+ break;
+ case 7 :
+ *d = c;
+ ctype = (c <= 0x7a) ? GRN_CHAR_ALPHA : (c == 0x7f ? GRN_CHAR_OTHERS : GRN_CHAR_SYMBOL);
+ break;
+ case 0x0a :
+ *d = c;
+ ctype = (c == 0xa3) ? GRN_CHAR_ALPHA : GRN_CHAR_OTHERS;
+ break;
+ case 0x0b :
+ if (c == 0xb3) {
+ *d = c - 0x10;
+ ctype = GRN_CHAR_ALPHA;
+ } else {
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ }
+ break;
+ case 0x0c :
+ case 0x0d :
+ *d = c;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ case 0x0e :
+ case 0x0f :
+ *d = c - 0x20;
+ ctype = GRN_CHAR_ALPHA;
+ break;
+ default :
+ *d = c;
+ ctype = GRN_CHAR_OTHERS;
+ break;
+ }
+ d++;
+ length++;
+ if (cp) { *cp++ = ctype; }
+ if (ch) {
+ *ch++ = (int16_t)(s + 1 - s_);
+ s_ = s + 1;
+ while (++d_ < d) { *ch++ = 0; }
+ }
+ }
+ if (cp) { *cp = GRN_CHAR_NULL; }
+ *d = '\0';
+ nstr->length = length;
+ nstr->norm_blen = (size_t)(d - (unsigned char *)nstr->norm);
+ return GRN_SUCCESS;
+}
+
+static grn_str *
+grn_fakenstr_open(grn_ctx *ctx, const char *str, size_t str_len, grn_encoding encoding, int flags)
+{
+ /* TODO: support GRN_STR_REMOVEBLANK flag and ctypes */
+ grn_str *nstr;
+ if (!(nstr = GRN_MALLOC(sizeof(grn_str)))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "memory allocation on grn_fakenstr_open failed !");
+ return NULL;
+ }
+ if (!(nstr->norm = GRN_MALLOC(str_len + 1))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "memory allocation for keyword on grn_snip_add_cond failed !");
+ GRN_FREE(nstr);
+ return NULL;
+ }
+ nstr->orig = str;
+ nstr->orig_blen = str_len;
+ grn_memcpy(nstr->norm, str, str_len);
+ nstr->norm[str_len] = '\0';
+ nstr->norm_blen = str_len;
+ nstr->ctypes = NULL;
+ nstr->flags = flags;
+
+ if (flags & GRN_STR_WITH_CHECKS) {
+ int16_t f = 0;
+ unsigned char c;
+ size_t i;
+ if (!(nstr->checks = (int16_t *) GRN_MALLOC(sizeof(int16_t) * str_len))) {
+ GRN_FREE(nstr->norm);
+ GRN_FREE(nstr);
+ return NULL;
+ }
+ switch (encoding) {
+ case GRN_ENC_EUC_JP:
+ for (i = 0; i < str_len; i++) {
+ if (!f) {
+ c = (unsigned char) str[i];
+ f = ((c >= 0xa1U && c <= 0xfeU) || c == 0x8eU ? 2 : (c == 0x8fU ? 3 : 1)
+ );
+ nstr->checks[i] = f;
+ } else {
+ nstr->checks[i] = 0;
+ }
+ f--;
+ }
+ break;
+ case GRN_ENC_SJIS:
+ for (i = 0; i < str_len; i++) {
+ if (!f) {
+ c = (unsigned char) str[i];
+ f = (c >= 0x81U && ((c <= 0x9fU) || (c >= 0xe0U && c <= 0xfcU)) ? 2 : 1);
+ nstr->checks[i] = f;
+ } else {
+ nstr->checks[i] = 0;
+ }
+ f--;
+ }
+ break;
+ case GRN_ENC_UTF8:
+ for (i = 0; i < str_len; i++) {
+ if (!f) {
+ c = (unsigned char) str[i];
+ f = (c & 0x80U ? (c & 0x20U ? (c & 0x10U ? 4 : 3)
+ : 2)
+ : 1);
+ nstr->checks[i] = f;
+ } else {
+ nstr->checks[i] = 0;
+ }
+ f--;
+ }
+ break;
+ default:
+ for (i = 0; i < str_len; i++) {
+ nstr->checks[i] = 1;
+ }
+ break;
+ }
+ } else {
+ nstr->checks = NULL;
+ }
+ return nstr;
+}
+
+grn_str *
+grn_str_open_(grn_ctx *ctx, const char *str, unsigned int str_len, int flags, grn_encoding encoding)
+{
+ grn_rc rc;
+ grn_str *nstr;
+ if (!str || !str_len) { return NULL; }
+
+ if (!(flags & GRN_STR_NORMALIZE)) {
+ return grn_fakenstr_open(ctx, str, str_len, encoding, flags);
+ }
+
+ if (!(nstr = GRN_MALLOC(sizeof(grn_str)))) {
+ GRN_LOG(ctx, GRN_LOG_ALERT, "memory allocation on grn_str_open failed !");
+ return NULL;
+ }
+ nstr->orig = str;
+ nstr->orig_blen = str_len;
+ nstr->norm = NULL;
+ nstr->norm_blen = 0;
+ nstr->checks = NULL;
+ nstr->ctypes = NULL;
+ nstr->encoding = encoding;
+ nstr->flags = flags;
+ switch (encoding) {
+ case GRN_ENC_EUC_JP :
+ rc = normalize_euc(ctx, nstr);
+ break;
+ case GRN_ENC_UTF8 :
+#ifdef GRN_WITH_NFKC
+ rc = normalize_utf8(ctx, nstr);
+#else /* GRN_WITH_NFKC */
+ rc = normalize_none(ctx, nstr);
+#endif /* GRN_WITH_NFKC */
+ break;
+ case GRN_ENC_SJIS :
+ rc = normalize_sjis(ctx, nstr);
+ break;
+ case GRN_ENC_LATIN1 :
+ rc = normalize_latin1(ctx, nstr);
+ break;
+ case GRN_ENC_KOI8R :
+ rc = normalize_koi8r(ctx, nstr);
+ break;
+ default :
+ rc = normalize_none(ctx, nstr);
+ break;
+ }
+ if (rc) {
+ grn_str_close(ctx, nstr);
+ return NULL;
+ }
+ return nstr;
+}
+
+grn_str *
+grn_str_open(grn_ctx *ctx, const char *str, unsigned int str_len, int flags)
+{
+ return grn_str_open_(ctx, str, str_len, flags, ctx->encoding);
+}
+
+grn_rc
+grn_str_close(grn_ctx *ctx, grn_str *nstr)
+{
+ if (nstr) {
+ if (nstr->norm) { GRN_FREE(nstr->norm); }
+ if (nstr->ctypes) { GRN_FREE(nstr->ctypes); }
+ if (nstr->checks) { GRN_FREE(nstr->checks); }
+ GRN_FREE(nstr);
+ return GRN_SUCCESS;
+ } else {
+ return GRN_INVALID_ARGUMENT;
+ }
+}
+
+static const char *grn_enc_string[] = {
+ "default",
+ "none",
+ "euc_jp",
+ "utf8",
+ "sjis",
+ "latin1",
+ "koi8r"
+};
+
+const char *
+grn_encoding_to_string(grn_encoding enc)
+{
+ if (enc < (sizeof(grn_enc_string) / sizeof(char *))) {
+ return grn_enc_string[enc];
+ } else {
+ return "unknown";
+ }
+}
+
+grn_encoding
+grn_encoding_parse(const char *str)
+{
+ grn_encoding e = GRN_ENC_UTF8;
+ int i = sizeof(grn_enc_string) / sizeof(grn_enc_string[0]);
+ while (i--) {
+ if (!strcmp(str, grn_enc_string[i])) {
+ e = (grn_encoding)i;
+ }
+ }
+ return e;
+}
+
+size_t
+grn_str_len(grn_ctx *ctx, const char *str, grn_encoding encoding, const char **last)
+{
+ size_t len, tlen;
+ const char *p = NULL;
+ for (len = 0; ; len++) {
+ p = str;
+ if (!(tlen = grn_str_charlen(ctx, str, encoding))) {
+ break;
+ }
+ str += tlen;
+ }
+ if (last) { *last = p; }
+ return len;
+}
+
+int
+grn_isspace(const char *str, grn_encoding encoding)
+{
+ const unsigned char *s = (const unsigned char *) str;
+ if (!s) { return 0; }
+ switch (s[0]) {
+ case ' ' :
+ case '\f' :
+ case '\n' :
+ case '\r' :
+ case '\t' :
+ case '\v' :
+ return 1;
+ case 0x81 :
+ if (encoding == GRN_ENC_SJIS && s[1] == 0x40) { return 2; }
+ break;
+ case 0xA1 :
+ if (encoding == GRN_ENC_EUC_JP && s[1] == 0xA1) { return 2; }
+ break;
+ case 0xE3 :
+ if (encoding == GRN_ENC_UTF8 && s[1] == 0x80 && s[2] == 0x80) { return 3; }
+ break;
+ default :
+ break;
+ }
+ return 0;
+}
+
+int8_t
+grn_atoi8(const char *nptr, const char *end, const char **rest)
+{
+ const char *p = nptr;
+ int8_t v = 0, t, n = 0, o = 0;
+ if (p < end && *p == '-') {
+ p++;
+ n = 1;
+ o = 1;
+ }
+ while (p < end && *p >= '0' && *p <= '9') {
+ t = v * 10 - (*p - '0');
+ if (t > v || (!n && t == INT8_MIN)) { v = 0; break; }
+ v = t;
+ o = 0;
+ p++;
+ }
+ if (rest) { *rest = o ? nptr : p; }
+ return n ? v : -v;
+}
+
+uint8_t
+grn_atoui8(const char *nptr, const char *end, const char **rest)
+{
+ uint8_t v = 0, t;
+ while (nptr < end && *nptr >= '0' && *nptr <= '9') {
+ t = v * 10 + (*nptr - '0');
+ if (t < v) { v = 0; break; }
+ v = t;
+ nptr++;
+ }
+ if (rest) { *rest = nptr; }
+ return v;
+}
+
+int16_t
+grn_atoi16(const char *nptr, const char *end, const char **rest)
+{
+ const char *p = nptr;
+ int16_t v = 0, t, n = 0, o = 0;
+ if (p < end && *p == '-') {
+ p++;
+ n = 1;
+ o = 1;
+ }
+ while (p < end && *p >= '0' && *p <= '9') {
+ t = v * 10 - (*p - '0');
+ if (t > v || (!n && t == INT16_MIN)) { v = 0; break; }
+ v = t;
+ o = 0;
+ p++;
+ }
+ if (rest) { *rest = o ? nptr : p; }
+ return n ? v : -v;
+}
+
+uint16_t
+grn_atoui16(const char *nptr, const char *end, const char **rest)
+{
+ uint16_t v = 0, t;
+ while (nptr < end && *nptr >= '0' && *nptr <= '9') {
+ t = v * 10 + (*nptr - '0');
+ if (t < v) { v = 0; break; }
+ v = t;
+ nptr++;
+ }
+ if (rest) { *rest = nptr; }
+ return v;
+}
+
+int
+grn_atoi(const char *nptr, const char *end, const char **rest)
+{
+ const char *p = nptr;
+ int v = 0, t, n = 0, o = 0;
+ if (p < end && *p == '-') {
+ p++;
+ n = 1;
+ o = 1;
+ }
+ while (p < end && *p >= '0' && *p <= '9') {
+ t = v * 10 - (*p - '0');
+ if (t > v || (!n && t == INT32_MIN)) { v = 0; break; }
+ v = t;
+ o = 0;
+ p++;
+ }
+ if (rest) { *rest = o ? nptr : p; }
+ return n ? v : -v;
+}
+
+unsigned int
+grn_atoui(const char *nptr, const char *end, const char **rest)
+{
+ unsigned int v = 0, t;
+ while (nptr < end && *nptr >= '0' && *nptr <= '9') {
+ t = v * 10 + (*nptr - '0');
+ if (t < v) { v = 0; break; }
+ v = t;
+ nptr++;
+ }
+ if (rest) { *rest = nptr; }
+ return v;
+}
+
+int64_t
+grn_atoll(const char *nptr, const char *end, const char **rest)
+{
+ const char *p = nptr;
+ int o = 0;
+ int64_t v = 0;
+ if (p < end && *p == '-') {
+ p++;
+ o = 1;
+ while (p < end && *p >= '0' && *p <= '9') {
+ int64_t t = v * 10 - (*p - '0');
+ if (t > v) { v = 0; break; }
+ v = t;
+ o = 0;
+ p++;
+ }
+ } else {
+ while (p < end && *p >= '0' && *p <= '9') {
+ int64_t t = v * 10 + (*p - '0');
+ if (t < v) { v = 0; break; }
+ v = t;
+ p++;
+ }
+ }
+ if (rest) { *rest = o ? nptr : p; }
+ return v;
+}
+
+uint64_t
+grn_atoull(const char *nptr, const char *end, const char **rest)
+{
+ uint64_t v = 0, t;
+ while (nptr < end && *nptr >= '0' && *nptr <= '9') {
+ t = v * 10 + (*nptr - '0');
+ if (t < v) { v = 0; break; }
+ v = t;
+ nptr++;
+ }
+ if (rest) { *rest = nptr; }
+ return v;
+}
+
+unsigned int
+grn_htoui(const char *nptr, const char *end, const char **rest)
+{
+ unsigned int v = 0, t;
+ while (nptr < end) {
+ switch (*nptr) {
+ case '0' :
+ case '1' :
+ case '2' :
+ case '3' :
+ case '4' :
+ case '5' :
+ case '6' :
+ case '7' :
+ case '8' :
+ case '9' :
+ t = v * 16 + (*nptr++ - '0');
+ break;
+ case 'a' :
+ case 'b' :
+ case 'c' :
+ case 'd' :
+ case 'e' :
+ case 'f' :
+ t = v * 16 + (*nptr++ - 'a') + 10;
+ break;
+ case 'A' :
+ case 'B' :
+ case 'C' :
+ case 'D' :
+ case 'E' :
+ case 'F' :
+ t = v * 16 + (*nptr++ - 'A') + 10;
+ break;
+ default :
+ v = 0; goto exit;
+ }
+ if (t < v) { v = 0; goto exit; }
+ v = t;
+ }
+exit :
+ if (rest) { *rest = nptr; }
+ return v;
+}
+
+void
+grn_itoh(unsigned int i, char *p, unsigned int len)
+{
+ static const char *hex = "0123456789ABCDEF";
+ p += len - 1;
+ while (len--) {
+ *p-- = hex[i & 0xf];
+ i >>= 4;
+ }
+}
+
+grn_rc
+grn_itoa(int i, char *p, char *end, char **rest)
+{
+ char *q;
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ q = p;
+ if (i < 0) {
+ *p++ = '-';
+ q = p;
+ if (i == INT_MIN) {
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ *p++ = (-(i % 10)) + '0';
+ i /= 10;
+ }
+ i = -i;
+ }
+ do {
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ *p++ = i % 10 + '0';
+ } while ((i /= 10) > 0);
+ if (rest) { *rest = p; }
+ for (p--; q < p; q++, p--) {
+ char t = *q;
+ *q = *p;
+ *p = t;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_itoa_padded(int i, char *p, char *end, char ch)
+{
+ char *q;
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ if (i < 0) {
+ *p++ = '-';
+ if (i == INT_MIN) {
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ *p++ = (-(i % 10)) + '0';
+ i /= 10;
+ }
+ i = -i;
+ }
+ q = end - 1;
+ do {
+ if (q < p) { return GRN_INVALID_ARGUMENT; }
+ *q-- = i % 10 + '0';
+ } while ((i /= 10) > 0);
+ while (q >= p) {
+ *q-- = ch;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_lltoa(int64_t i, char *p, char *end, char **rest)
+{
+ char *q;
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ q = p;
+ if (i < 0) {
+ *p++ = '-';
+ q = p;
+ if (i == INT64_MIN) {
+ *p++ = (-(i % 10)) + '0';
+ i /= 10;
+ }
+ i = -i;
+ }
+ do {
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ *p++ = i % 10 + '0';
+ } while ((i /= 10) > 0);
+ if (rest) { *rest = p; }
+ for (p--; q < p; q++, p--) {
+ char t = *q;
+ *q = *p;
+ *p = t;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ulltoa(uint64_t i, char *p, char *end, char **rest)
+{
+ char *q;
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ q = p;
+ do {
+ if (p >= end) { return GRN_INVALID_ARGUMENT; }
+ *p++ = i % 10 + '0';
+ } while ((i /= 10) > 0);
+ if (rest) { *rest = p; }
+ for (p--; q < p; q++, p--) {
+ char t = *q;
+ *q = *p;
+ *p = t;
+ }
+ return GRN_SUCCESS;
+}
+
+#define I2B(i) \
+ ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(i) & 0x3f])
+
+#define B2I(b) \
+ (((b) < '+' || 'z' < (b)) ? 0xff : "\x3e\xff\xff\xff\x3f\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\xff\xff\xff\xff\xff\xff\xff\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\xff\xff\xff\xff\xff\xff\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33"[(b) - '+'])
+
+#define MASK 0x34d34d34
+
+char *
+grn_itob(grn_id id, char *p)
+{
+ id ^= MASK;
+ *p++ = I2B(id >> 24);
+ *p++ = I2B(id >> 18);
+ *p++ = I2B(id >> 12);
+ *p++ = I2B(id >> 6);
+ *p++ = I2B(id);
+ return p;
+}
+
+grn_id
+grn_btoi(char *b)
+{
+ uint8_t i;
+ grn_id id = 0;
+ int len = 5;
+ while (len--) {
+ char c = *b++;
+ if ((i = B2I(c)) == 0xff) { return 0; }
+ id = (id << 6) + i;
+ }
+ return id ^ MASK;
+}
+
+#define I2B32H(i) ("0123456789ABCDEFGHIJKLMNOPQRSTUV"[(i) & 0x1f])
+
+char *
+grn_lltob32h(int64_t i, char *p)
+{
+ uint64_t u = (uint64_t)i + 0x8000000000000000ULL;
+ *p++ = I2B32H(u >> 60);
+ *p++ = I2B32H(u >> 55);
+ *p++ = I2B32H(u >> 50);
+ *p++ = I2B32H(u >> 45);
+ *p++ = I2B32H(u >> 40);
+ *p++ = I2B32H(u >> 35);
+ *p++ = I2B32H(u >> 30);
+ *p++ = I2B32H(u >> 25);
+ *p++ = I2B32H(u >> 20);
+ *p++ = I2B32H(u >> 15);
+ *p++ = I2B32H(u >> 10);
+ *p++ = I2B32H(u >> 5);
+ *p++ = I2B32H(u);
+ return p;
+}
+
+char *
+grn_ulltob32h(uint64_t i, char *p)
+{
+ char lb = (i >> 59) & 0x10;
+ i += 0x8000000000000000ULL;
+ *p++ = lb + I2B32H(i >> 60);
+ *p++ = I2B32H(i >> 55);
+ *p++ = I2B32H(i >> 50);
+ *p++ = I2B32H(i >> 45);
+ *p++ = I2B32H(i >> 40);
+ *p++ = I2B32H(i >> 35);
+ *p++ = I2B32H(i >> 30);
+ *p++ = I2B32H(i >> 25);
+ *p++ = I2B32H(i >> 20);
+ *p++ = I2B32H(i >> 15);
+ *p++ = I2B32H(i >> 10);
+ *p++ = I2B32H(i >> 5);
+ *p++ = I2B32H(i);
+ return p;
+}
+
+grn_rc
+grn_aton(grn_ctx *ctx, const char *p, const char *end, const char **rest,
+ grn_obj *res)
+{
+ if (*p == '+') {
+ p++;
+ }
+
+ switch (*p) {
+ case '-' :
+ case '0' : case '1' : case '2' : case '3' : case '4' :
+ case '5' : case '6' : case '7' : case '8' : case '9' :
+ {
+ int64_t int64;
+ char rest_char;
+ int64 = grn_atoll(p, end, rest);
+ rest_char = **rest;
+ if (end == *rest) {
+ if ((int64_t)INT32_MIN <= int64 && int64 <= (int64_t)INT32_MAX) {
+ grn_obj_reinit(ctx, res, GRN_DB_INT32, 0);
+ GRN_INT32_SET(ctx, res, int64);
+ } else if ((int64_t)INT32_MAX < int64 && int64 <= (int64_t)UINT32_MAX) {
+ grn_obj_reinit(ctx, res, GRN_DB_UINT32, 0);
+ GRN_UINT32_SET(ctx, res, int64);
+ } else {
+ grn_obj_reinit(ctx, res, GRN_DB_INT64, 0);
+ GRN_INT64_SET(ctx, res, int64);
+ }
+ } else {
+ if (*p != '-' && rest_char >= '0' && rest_char <= '9') {
+ uint64_t uint64 = grn_atoull(p, end, rest);
+ if (end == *rest) {
+ grn_obj_reinit(ctx, res, GRN_DB_UINT64, 0);
+ GRN_UINT64_SET(ctx, res, uint64);
+ }
+ }
+ if (end != *rest) {
+ if (rest_char == '.' || rest_char == 'e' || rest_char == 'E' ||
+ (rest_char >= '0' && rest_char <= '9')) {
+ char *rest_float;
+ double d;
+ errno = 0;
+ d = strtod(p, &rest_float);
+ if (!errno && rest_float == end) {
+ grn_obj_reinit(ctx, res, GRN_DB_FLOAT, 0);
+ GRN_FLOAT_SET(ctx, res, d);
+ *rest = rest_float;
+ } else {
+ return GRN_INVALID_ARGUMENT;
+ }
+ }
+ }
+ }
+ }
+ break;
+ default :
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ return GRN_SUCCESS;
+}
+
+int
+grn_str_tok(const char *str, size_t str_len, char delim, const char **tokbuf, int buf_size, const char **rest)
+{
+ const char **tok = tokbuf, **tok_end = tokbuf + buf_size;
+ if (buf_size > 0) {
+ const char *str_end = str + str_len;
+ for (;;str++) {
+ if (str == str_end) {
+ *tok++ = str;
+ break;
+ }
+ if (delim == *str) {
+ // *str = '\0';
+ *tok++ = str;
+ if (tok == tok_end) { break; }
+ }
+ }
+ }
+ if (rest) { *rest = str; }
+ return tok - tokbuf;
+}
+
+inline static int
+op_getopt_flag(int *flags, const grn_str_getopt_opt *o,
+ int argc, char * const argv[], int i, const char *optvalue)
+{
+ switch (o->op) {
+ case GETOPT_OP_NONE:
+ break;
+ case GETOPT_OP_ON:
+ *flags |= o->flag;
+ break;
+ case GETOPT_OP_OFF:
+ *flags &= ~o->flag;
+ break;
+ case GETOPT_OP_UPDATE:
+ *flags = o->flag;
+ break;
+ default:
+ return i;
+ }
+ if (o->arg) {
+ if (optvalue) {
+ *o->arg = (char *)optvalue;
+ } else if (++i < argc) {
+ *o->arg = argv[i];
+ } else {
+ return -1;
+ }
+ }
+ return i;
+}
+
+int
+grn_str_getopt(int argc, char * const argv[], const grn_str_getopt_opt *opts,
+ int *flags)
+{
+ int i;
+ for (i = 1; i < argc; i++) {
+ const char * v = argv[i];
+ if (*v == '-') {
+ const grn_str_getopt_opt *o;
+ int found;
+ if (*++v == '-') {
+ const char *eq;
+ size_t len;
+ found = 0;
+ v++;
+ for (eq = v; *eq != '\0' && *eq != '='; eq++) {}
+ len = eq - v;
+ for (o = opts; o->opt != '\0' || o->longopt != NULL; o++) {
+ if (o->longopt && strlen(o->longopt) == len &&
+ !memcmp(v, o->longopt, len)) {
+ i = op_getopt_flag(flags, o, argc, argv, i,
+ (*eq == '\0' ? NULL : eq + 1));
+ if (i < 0) {
+ fprintf(stderr, "%s: option '--%s' needs argument.\n", argv[0], o->longopt);
+ return -1;
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found) { goto exit; }
+ } else {
+ const char *p;
+ for (p = v; *p; p++) {
+ found = 0;
+ for (o = opts; o->opt != '\0' || o->longopt != NULL; o++) {
+ if (o->opt && *p == o->opt) {
+ i = op_getopt_flag(flags, o, argc, argv, i, NULL);
+ if (i < 0) {
+ fprintf(stderr, "%s: option '-%c' needs argument.\n", argv[0], *p);
+ return -1;
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found) { goto exit; }
+ }
+ }
+ } else {
+ break;
+ }
+ }
+ return i;
+exit:
+ fprintf(stderr, "%s: cannot recognize option '%s'.\n", argv[0], argv[i]);
+ return -1;
+}
+
+#define UNIT_SIZE (1 << 12)
+#define UNIT_MASK (UNIT_SIZE - 1)
+
+int grn_bulk_margin_size = 0;
+
+grn_rc
+grn_bulk_resize(grn_ctx *ctx, grn_obj *buf, unsigned int newsize)
+{
+ char *head;
+ unsigned int rounded_newsize;
+ newsize += grn_bulk_margin_size + 1;
+ if (GRN_BULK_OUTP(buf)) {
+ rounded_newsize = (newsize + (UNIT_MASK)) & ~UNIT_MASK;
+ if (rounded_newsize < newsize) { return GRN_NOT_ENOUGH_SPACE; }
+ newsize = rounded_newsize;
+ head = buf->u.b.head - (buf->u.b.head ? grn_bulk_margin_size : 0);
+ if (!(head = GRN_REALLOC(head, newsize))) { return GRN_NO_MEMORY_AVAILABLE; }
+ buf->u.b.curr = head + grn_bulk_margin_size + GRN_BULK_VSIZE(buf);
+ buf->u.b.head = head + grn_bulk_margin_size;
+ buf->u.b.tail = head + newsize;
+ } else {
+ if (newsize > GRN_BULK_BUFSIZE) {
+ rounded_newsize = (newsize + (UNIT_MASK)) & ~UNIT_MASK;
+ if (rounded_newsize < newsize) { return GRN_NOT_ENOUGH_SPACE; }
+ newsize = rounded_newsize;
+ if (!(head = GRN_MALLOC(newsize))) { return GRN_NO_MEMORY_AVAILABLE; }
+ grn_memcpy(head, GRN_BULK_HEAD(buf), GRN_BULK_VSIZE(buf));
+ buf->u.b.curr = head + grn_bulk_margin_size + GRN_BULK_VSIZE(buf);
+ buf->u.b.head = head + grn_bulk_margin_size;
+ buf->u.b.tail = head + newsize;
+ buf->header.impl_flags |= GRN_OBJ_OUTPLACE;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_bulk_reinit(grn_ctx *ctx, grn_obj *buf, unsigned int size)
+{
+ GRN_BULK_REWIND(buf);
+ return grn_bulk_resize(ctx, buf, size);
+}
+
+grn_rc
+grn_bulk_write(grn_ctx *ctx, grn_obj *buf, const char *str, unsigned int len)
+{
+ grn_rc rc = GRN_SUCCESS;
+ char *curr;
+ if (GRN_BULK_REST(buf) < len) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
+ }
+ curr = GRN_BULK_CURR(buf);
+ if (str)
+ grn_memcpy(curr, str, len);
+ GRN_BULK_INCR_LEN(buf, len);
+ return rc;
+}
+
+grn_rc
+grn_bulk_write_from(grn_ctx *ctx, grn_obj *bulk,
+ const char *str, unsigned int from, unsigned int len)
+{
+ grn_rc rc = grn_bulk_truncate(ctx, bulk, from);
+ if (!rc) { rc = grn_bulk_write(ctx, bulk, str, len); }
+ return rc;
+}
+
+grn_rc
+grn_bulk_reserve(grn_ctx *ctx, grn_obj *buf, unsigned int len)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (GRN_BULK_REST(buf) < len) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
+ }
+ return rc;
+}
+
+grn_rc
+grn_bulk_space(grn_ctx *ctx, grn_obj *buf, unsigned int len)
+{
+ grn_rc rc = grn_bulk_reserve(ctx, buf, len);
+ if (!rc) {
+ GRN_BULK_INCR_LEN(buf, len);
+ }
+ return rc;
+}
+
+static grn_rc
+grn_bulk_space_clear(grn_ctx *ctx, grn_obj *buf, unsigned int len)
+{
+ grn_rc rc = grn_bulk_reserve(ctx, buf, len);
+ if (!rc) {
+ memset(GRN_BULK_CURR(buf), 0, len);
+ GRN_BULK_INCR_LEN(buf, len);
+ }
+ return rc;
+}
+
+grn_rc
+grn_bulk_truncate(grn_ctx *ctx, grn_obj *bulk, unsigned int len)
+{
+ if (GRN_BULK_OUTP(bulk)) {
+ if ((bulk->u.b.tail - bulk->u.b.head) < len) {
+ return grn_bulk_space_clear(ctx, bulk, len);
+ } else {
+ bulk->u.b.curr = bulk->u.b.head + len;
+ }
+ } else {
+ if (GRN_BULK_BUFSIZE < len) {
+ return grn_bulk_space_clear(ctx, bulk, len);
+ } else {
+ bulk->header.flags &= ~GRN_BULK_BUFSIZE_MAX;
+ bulk->header.flags += len;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_text_itoa(grn_ctx *ctx, grn_obj *buf, int i)
+{
+ grn_rc rc = GRN_SUCCESS;
+ for (;;) {
+ char *curr = GRN_BULK_CURR(buf);
+ char *tail = GRN_BULK_TAIL(buf);
+ if (grn_itoa(i, curr, tail, &curr)) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_WSIZE(buf) + UNIT_SIZE))) { return rc; }
+ } else {
+ GRN_BULK_SET_CURR(buf, curr);
+ break;
+ }
+ }
+ return rc;
+}
+
+grn_rc
+grn_text_itoa_padded(grn_ctx *ctx, grn_obj *buf, int i, char ch, unsigned int len)
+{
+ grn_rc rc = GRN_SUCCESS;
+ char *curr;
+ if ((rc = grn_bulk_reserve(ctx, buf, len))) { return rc; }
+ curr = GRN_BULK_CURR(buf);
+ if (!grn_itoa_padded(i, curr, curr + len, ch)) {
+ GRN_BULK_SET_CURR(buf, curr + len);
+ }
+ return rc;
+}
+
+grn_rc
+grn_text_lltoa(grn_ctx *ctx, grn_obj *buf, long long int i)
+{
+ grn_rc rc = GRN_SUCCESS;
+ for (;;) {
+ char *curr = GRN_BULK_CURR(buf);
+ char *tail = GRN_BULK_TAIL(buf);
+ if (grn_lltoa(i, curr, tail, &curr)) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_WSIZE(buf) + UNIT_SIZE))) { return rc; }
+ } else {
+ GRN_BULK_SET_CURR(buf, curr);
+ break;
+ }
+ }
+ return rc;
+}
+
+grn_rc
+grn_text_ulltoa(grn_ctx *ctx, grn_obj *buf, unsigned long long int i)
+{
+ grn_rc rc = GRN_SUCCESS;
+ for (;;) {
+ char *curr = GRN_BULK_CURR(buf);
+ char *tail = GRN_BULK_TAIL(buf);
+ if (grn_ulltoa(i, curr, tail, &curr)) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_WSIZE(buf) + UNIT_SIZE))) { return rc; }
+ } else {
+ GRN_BULK_SET_CURR(buf, curr);
+ break;
+ }
+ }
+ return rc;
+}
+
+inline static void
+ftoa_(grn_ctx *ctx, grn_obj *buf, double d)
+{
+ char *start;
+ size_t before_size;
+ size_t len;
+#define DIGIT_NUMBER 16
+#define FIRST_BUFFER_SIZE (DIGIT_NUMBER + 4)
+ before_size = GRN_BULK_VSIZE(buf);
+ grn_bulk_reserve(ctx, buf, FIRST_BUFFER_SIZE);
+ grn_text_printf(ctx, buf, "%#.*g", DIGIT_NUMBER, d);
+ len = GRN_BULK_VSIZE(buf) - before_size;
+ start = GRN_BULK_CURR(buf) - len;
+#undef FIRST_BUFFER_SIZE
+#undef DIGIT_NUMBER
+ if (start[len - 1] == '.') {
+ GRN_TEXT_PUTC(ctx, buf, '0');
+ } else {
+ char *p, *q;
+ start[len] = '\0';
+ if ((p = strchr(start, 'e'))) {
+ for (q = p; *(q - 2) != '.' && *(q - 1) == '0'; q--) { len--; }
+ grn_memmove(q, p, start + len - q);
+ } else {
+ for (q = start + len; *(q - 2) != '.' && *(q - 1) == '0'; q--) { len--; }
+ }
+ grn_bulk_truncate(ctx, buf, before_size + len);
+ }
+}
+
+grn_rc
+grn_text_ftoa(grn_ctx *ctx, grn_obj *buf, double d)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (GRN_BULK_REST(buf) < 32) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + 32))) { return rc; }
+ }
+#ifdef HAVE_FPCLASSIFY
+ switch (fpclassify(d)) {
+ case FP_NAN :
+ GRN_TEXT_PUTS(ctx, buf, "#<nan>");
+ break;
+ case FP_INFINITE :
+ GRN_TEXT_PUTS(ctx, buf, d > 0 ? "#i1/0" : "#i-1/0");
+ break;
+ default :
+ ftoa_(ctx, buf, d);
+ break;
+ }
+#else /* HAVE_FPCLASSIFY */
+ if (d == d) {
+ if (d != 0 && ((d / 2.0) == d)) {
+ GRN_TEXT_PUTS(ctx, buf, d > 0 ? "#i1/0" : "#i-1/0");
+ } else {
+ ftoa_(ctx, buf, d);
+ }
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "#<nan>");
+ }
+#endif /* HAVE_FPCLASSIFY */
+ return rc;
+}
+
+grn_rc
+grn_text_itoh(grn_ctx *ctx, grn_obj *buf, int i, unsigned int len)
+{
+ grn_rc rc = GRN_SUCCESS;
+ if (GRN_BULK_REST(buf) < len) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
+ }
+ grn_itoh(i, GRN_BULK_CURR(buf), len);
+ GRN_BULK_INCR_LEN(buf, len);
+ return rc;
+}
+
+grn_rc
+grn_text_itob(grn_ctx *ctx, grn_obj *buf, grn_id id)
+{
+ size_t len = 5;
+ grn_rc rc = GRN_SUCCESS;
+ if (GRN_BULK_REST(buf) < len) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
+ }
+ grn_itob(id, GRN_BULK_CURR(buf));
+ GRN_BULK_INCR_LEN(buf, len);
+ return rc;
+}
+
+grn_rc
+grn_text_lltob32h(grn_ctx *ctx, grn_obj *buf, long long int i)
+{
+ size_t len = 13;
+ grn_rc rc = GRN_SUCCESS;
+ if (GRN_BULK_REST(buf) < len) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + len))) { return rc; }
+ }
+ grn_lltob32h(i, GRN_BULK_CURR(buf));
+ GRN_BULK_INCR_LEN(buf, len);
+ return rc;
+}
+
+grn_rc
+grn_text_esc(grn_ctx *ctx, grn_obj *buf, const char *s, unsigned int len)
+{
+ const char *e;
+ unsigned int l;
+ grn_rc rc = GRN_SUCCESS;
+
+ GRN_TEXT_PUTC(ctx, buf, '"');
+ for (e = s + len; s < e; s += l) {
+ if (!(l = grn_charlen(ctx, s, e))) { break; }
+ if (l == 1) {
+ switch (*s) {
+ case '"' :
+ grn_bulk_write(ctx, buf, "\\\"", 2);
+ break;
+ case '\\' :
+ grn_bulk_write(ctx, buf, "\\\\", 2);
+ break;
+ case '\b' :
+ grn_bulk_write(ctx, buf, "\\b", 2);
+ break;
+ case '\f' :
+ grn_bulk_write(ctx, buf, "\\f", 2);
+ break;
+ case '\n' :
+ grn_bulk_write(ctx, buf, "\\n", 2);
+ break;
+ case '\r' :
+ grn_bulk_write(ctx, buf, "\\r", 2);
+ break;
+ case '\t' :
+ grn_bulk_write(ctx, buf, "\\t", 2);
+ break;
+ case '\x00': case '\x01': case '\x02': case '\x03': case '\x04': case '\x05':
+ case '\x06': case '\x07': case '\x0b': case '\x0e': case '\x0f': case '\x10':
+ case '\x11': case '\x12': case '\x13': case '\x14': case '\x15': case '\x16':
+ case '\x17': case '\x18': case '\x19': case '\x1a': case '\x1b': case '\x1c':
+ case '\x1d': case '\x1e': case '\x1f': case '\x7f':
+ if (!(rc = grn_bulk_write(ctx, buf, "\\u", 2))) {
+ if ((rc = grn_text_itoh(ctx, buf, *s, 4))) {
+ GRN_BULK_INCR_LEN(buf, -2);
+ return rc;
+ }
+ } else {
+ return rc;
+ }
+ break;
+ default :
+ GRN_TEXT_PUTC(ctx, buf, *s);
+ }
+ } else if (l == 3) {
+ if (*s == '\xe2' && *(s + 1) == '\x80') {
+ switch (*(s + 2)) {
+ case '\xa8': /* \u2028 */
+ grn_bulk_write(ctx, buf, "\\u2028", 6);
+ break;
+ case '\xa9': /* \u2029 */
+ grn_bulk_write(ctx, buf, "\\u2029", 6);
+ break;
+ default:
+ grn_bulk_write(ctx, buf, s, l);
+ }
+ } else {
+ grn_bulk_write(ctx, buf, s, l);
+ }
+ } else {
+ grn_bulk_write(ctx, buf, s, l);
+ }
+ }
+ GRN_TEXT_PUTC(ctx, buf, '"');
+ return rc;
+}
+
+grn_rc
+grn_text_escape_xml(grn_ctx *ctx, grn_obj *buf, const char *s, unsigned int len)
+{
+ const char *e;
+ unsigned int l;
+ grn_rc rc = GRN_SUCCESS;
+
+ for (e = s + len; s < e; s += l) {
+ if (!(l = grn_charlen(ctx, s, e))) { break; }
+ if (l == 1) {
+ switch (*s) {
+ case '"' :
+ grn_bulk_write(ctx, buf, "&quot;", 6);
+ break;
+ case '<' :
+ grn_bulk_write(ctx, buf, "&lt;", 4);
+ break;
+ case '>' :
+ grn_bulk_write(ctx, buf, "&gt;", 4);
+ break;
+ case '&' :
+ grn_bulk_write(ctx, buf, "&amp;", 5);
+ break;
+ default :
+ GRN_TEXT_PUTC(ctx, buf, *s);
+ }
+ } else {
+ grn_bulk_write(ctx, buf, s, l);
+ }
+ }
+ return rc;
+}
+
+#define TOK_ESC (0x80)
+
+const char *
+grn_text_unesc_tok(grn_ctx *ctx, grn_obj *buf, const char *s, const char *e, char *tok_type)
+{
+ const char *p;
+ unsigned int len;
+ uint8_t stat = GRN_TOK_VOID;
+ for (p = s; p < e; p += len) {
+ if (!(len = grn_charlen(ctx, p, e))) {
+ p = e;
+ stat &= ~TOK_ESC;
+ goto exit;
+ }
+ switch (stat) {
+ case GRN_TOK_VOID :
+ if (*p == ' ') { continue; }
+ switch (*p) {
+ case '"' :
+ stat = GRN_TOK_STRING;
+ break;
+ case '\'' :
+ stat = GRN_TOK_QUOTE;
+ break;
+ case ')' :
+ case '(' :
+ GRN_TEXT_PUT(ctx, buf, p, len);
+ p += len;
+ stat = GRN_TOK_SYMBOL;
+ goto exit;
+ case '\\' :
+ stat = GRN_TOK_SYMBOL|TOK_ESC;
+ break;
+ default :
+ stat = GRN_TOK_SYMBOL;
+ GRN_TEXT_PUT(ctx, buf, p, len);
+ break;
+ }
+ break;
+ case GRN_TOK_SYMBOL :
+ if (*p == ' ') { goto exit; }
+ switch (*p) {
+ case '\'' :
+ case '"' :
+ case ')' :
+ case '(' :
+ goto exit;
+ case '\\' :
+ stat |= TOK_ESC;
+ break;
+ default :
+ GRN_TEXT_PUT(ctx, buf, p, len);
+ break;
+ }
+ break;
+ case GRN_TOK_STRING :
+ switch (*p) {
+ case '"' :
+ p += len;
+ goto exit;
+ case '\\' :
+ stat |= TOK_ESC;
+ break;
+ default :
+ GRN_TEXT_PUT(ctx, buf, p, len);
+ break;
+ }
+ break;
+ case GRN_TOK_QUOTE :
+ switch (*p) {
+ case '\'' :
+ p += len;
+ goto exit;
+ case '\\' :
+ stat |= TOK_ESC;
+ break;
+ default :
+ GRN_TEXT_PUT(ctx, buf, p, len);
+ break;
+ }
+ break;
+ case GRN_TOK_SYMBOL|TOK_ESC :
+ case GRN_TOK_STRING|TOK_ESC :
+ case GRN_TOK_QUOTE|TOK_ESC :
+ switch (*p) {
+ case 'b' :
+ GRN_TEXT_PUTC(ctx, buf, '\b');
+ break;
+ case 'f' :
+ GRN_TEXT_PUTC(ctx, buf, '\f');
+ break;
+ case 'n' :
+ GRN_TEXT_PUTC(ctx, buf, '\n');
+ break;
+ case 'r' :
+ GRN_TEXT_PUTC(ctx, buf, '\r');
+ break;
+ case 't' :
+ GRN_TEXT_PUTC(ctx, buf, '\t');
+ break;
+ default :
+ GRN_TEXT_PUT(ctx, buf, p, len);
+ break;
+ }
+ stat &= ~TOK_ESC;
+ break;
+ }
+ }
+exit :
+ *tok_type = stat;
+ return p;
+}
+
+grn_rc
+grn_text_benc(grn_ctx *ctx, grn_obj *buf, unsigned int v)
+{
+ grn_rc rc = GRN_SUCCESS;
+ uint8_t *p;
+ if (GRN_BULK_REST(buf) < 5) {
+ if ((rc = grn_bulk_resize(ctx, buf, GRN_BULK_VSIZE(buf) + 5))) { return rc; }
+ }
+ p = (uint8_t *)GRN_BULK_CURR(buf);
+ GRN_B_ENC(v, p);
+ GRN_BULK_SET_CURR(buf, (char *)p);
+ return rc;
+}
+
+/* 0x00 - 0x7f */
+static const int_least8_t urlenc_tbl[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+grn_rc
+grn_text_urlenc(grn_ctx *ctx, grn_obj *buf, const char *s, unsigned int len)
+{
+ const char *e, c = '%';
+ for (e = s + len; s < e; s++) {
+ if ((signed char)*s < 0 || urlenc_tbl[(int)*s]) {
+ if (!grn_bulk_write(ctx, buf, &c, 1)) {
+ if (grn_text_itoh(ctx, buf, *s, 2)) {
+ GRN_BULK_INCR_LEN(buf, -1);
+ }
+ }
+ } else {
+ GRN_TEXT_PUTC(ctx, buf, *s);
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+static const char *weekdays[7] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+static const char *months[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+grn_rc
+grn_text_time2rfc1123(grn_ctx *ctx, grn_obj *bulk, int sec)
+{
+ time_t tsec;
+ struct tm *t;
+#ifdef HAVE__GMTIME64_S
+ struct tm tm;
+ tsec = (time_t)sec;
+ t = (gmtime_s(&tm, &tsec) == 0) ? &tm : NULL;
+#else /* HAVE__GMTIME64_S */
+# ifdef HAVE_GMTIME_R
+ struct tm tm;
+ tsec = (time_t)sec;
+ t = gmtime_r(&tsec, &tm);
+# else /* HAVE_GMTIME_R */
+ tsec = (time_t)sec;
+ t = gmtime(&tsec);
+# endif /* HAVE_GMTIME_R */
+#endif /* HAVE__GMTIME64_S */
+ if (t) {
+ GRN_TEXT_SET(ctx, bulk, weekdays[t->tm_wday], 3);
+ GRN_TEXT_PUTS(ctx, bulk, ", ");
+ grn_text_itoa_padded(ctx, bulk, t->tm_mday, '0', 2);
+ GRN_TEXT_PUTS(ctx, bulk, " ");
+ GRN_TEXT_PUT(ctx, bulk, months[t->tm_mon], 3);
+ GRN_TEXT_PUTS(ctx, bulk, " ");
+ grn_text_itoa(ctx, bulk, t->tm_year + 1900);
+ GRN_TEXT_PUTS(ctx, bulk, " ");
+ grn_text_itoa_padded(ctx, bulk, t->tm_hour, '0', 2);
+ GRN_TEXT_PUTS(ctx, bulk, ":");
+ grn_text_itoa_padded(ctx, bulk, t->tm_min, '0', 2);
+ GRN_TEXT_PUTS(ctx, bulk, ":");
+ grn_text_itoa_padded(ctx, bulk, t->tm_sec, '0', 2);
+ GRN_TEXT_PUTS(ctx, bulk, " GMT");
+ } else {
+ GRN_TEXT_SETS(ctx, bulk, "Mon, 16 Mar 1980 20:40:00 GMT");
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_text_printf(grn_ctx *ctx, grn_obj *bulk, const char *format, ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ grn_text_vprintf(ctx, bulk, format, args);
+ va_end(args);
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_text_vprintf(grn_ctx *ctx, grn_obj *bulk, const char *format, va_list args)
+{
+ grn_bool is_written = GRN_FALSE;
+ int written_size;
+
+ {
+ int rest_size;
+ va_list copied_args;
+
+ rest_size = GRN_BULK_REST(bulk);
+ va_copy(copied_args, args);
+ written_size = vsnprintf(GRN_BULK_CURR(bulk), rest_size,
+ format, copied_args);
+ va_end(copied_args);
+
+ if (0 <= written_size && written_size < rest_size) {
+ is_written = GRN_TRUE;
+ }
+ }
+
+ if (!is_written) {
+#ifdef WIN32
+# define N_NEW_SIZES 3
+ int i;
+ int new_sizes[N_NEW_SIZES];
+
+ new_sizes[0] = GRN_BULK_REST(bulk) + strlen(format) * 2;
+ new_sizes[1] = new_sizes[0] + 4096;
+ new_sizes[2] = new_sizes[0] + 65536;
+
+ for (i = 0; i < N_NEW_SIZES; i++) {
+ grn_rc rc;
+ int new_size = new_sizes[i];
+ va_list copied_args;
+
+ rc = grn_bulk_reserve(ctx, bulk, GRN_BULK_VSIZE(bulk) + new_size);
+ if (rc) {
+ return rc;
+ }
+ va_copy(copied_args, args);
+ written_size = vsnprintf(GRN_BULK_CURR(bulk), new_size,
+ format, copied_args);
+ va_end(copied_args);
+ if (written_size != -1) {
+ break;
+ }
+ }
+# undef N_NEW_SIZES
+#else /* WIN32 */
+ grn_rc rc;
+ int required_size = written_size + 1; /* "+ 1" for terminate '\0'. */
+
+ rc = grn_bulk_reserve(ctx, bulk, GRN_BULK_VSIZE(bulk) + required_size);
+ if (rc) {
+ return rc;
+ }
+ written_size = vsnprintf(GRN_BULK_CURR(bulk), required_size,
+ format, args);
+#endif /* WIN32 */
+ }
+
+ if (written_size < 0) {
+ return GRN_INVALID_ARGUMENT;
+ }
+
+ GRN_BULK_INCR_LEN(bulk, written_size);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_bulk_fin(grn_ctx *ctx, grn_obj *buf)
+{
+ if (!(buf->header.impl_flags & GRN_OBJ_REFER)) {
+ if (GRN_BULK_OUTP(buf) && buf->u.b.head) {
+ GRN_REALLOC(buf->u.b.head - grn_bulk_margin_size, 0);
+ }
+ }
+ buf->header.flags = 0;
+ buf->header.impl_flags &= ~GRN_OBJ_DO_SHALLOW_COPY;
+ buf->u.b.head = NULL;
+ buf->u.b.curr = NULL;
+ buf->u.b.tail = NULL;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_substring(grn_ctx *ctx, char **str, char **str_end, int start, int end, grn_encoding encoding)
+{
+ int i;
+ size_t l;
+ char *s = *str, *e = *str_end;
+ for (i = 0; s < e; i++, s += l) {
+ if (i == start) { *str = s; }
+ if (!(l = grn_charlen(ctx, s, e))) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (i == end) {
+ *str_end = s;
+ break;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+static void
+grn_text_atoj(grn_ctx *ctx, grn_obj *bulk, grn_obj *obj, grn_id id)
+{
+ uint32_t vs;
+ grn_obj buf;
+ if (obj->header.type == GRN_ACCESSOR) {
+ grn_accessor *a = (grn_accessor *)obj;
+ GRN_TEXT_INIT(&buf, 0);
+ for (;;) {
+ GRN_BULK_REWIND(&buf);
+ switch (a->action) {
+ case GRN_ACCESSOR_GET_ID :
+ GRN_UINT32_PUT(ctx, &buf, id);
+ buf.header.domain = GRN_DB_UINT32;
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ grn_table_get_key2(ctx, a->obj, id, &buf);
+ buf.header.domain = DB_OBJ(a->obj)->header.domain;
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ buf.header.domain = GRN_DB_INT32; /* fix me */
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ int32_t int32_score = ri->score;
+ GRN_INT32_PUT(ctx, &buf, int32_score);
+ }
+ buf.header.domain = GRN_DB_INT32;
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ {
+ grn_rset_recinfo *ri = (grn_rset_recinfo *)grn_obj_get_value_(ctx, a->obj, id, &vs);
+ GRN_INT32_PUT(ctx, &buf, ri->n_subrecs);
+ }
+ buf.header.domain = GRN_DB_INT32;
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ if ((a->obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
+ if (a->next) {
+ grn_id *idp;
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ idp = (grn_id *)GRN_BULK_HEAD(&buf);
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ for (vs = GRN_BULK_VSIZE(&buf) / sizeof(grn_id); vs--; idp++) {
+ grn_text_atoj(ctx, bulk, (grn_obj *)a->next, *idp);
+ if (vs) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ } else {
+ grn_text_atoj(ctx, bulk, a->obj, id);
+ }
+ goto exit;
+ } else {
+ grn_obj_get_value(ctx, a->obj, id, &buf);
+ }
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ /* todo */
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ /* todo */
+ break;
+ }
+ if (a->next) {
+ a = a->next;
+ id = *((grn_id *)GRN_BULK_HEAD(&buf));
+ } else {
+ break;
+ }
+ }
+ } else {
+ switch (obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE :
+ GRN_VALUE_FIX_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ if ((obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) {
+ grn_obj *range = grn_ctx_at(ctx, DB_OBJ(obj)->range);
+ if (range->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ GRN_VALUE_VAR_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
+ } else {
+ GRN_VALUE_FIX_SIZE_INIT(&buf, GRN_OBJ_VECTOR, DB_OBJ(obj)->range);
+ }
+ } else {
+ GRN_VALUE_VAR_SIZE_INIT(&buf, 0, DB_OBJ(obj)->range);
+ }
+ break;
+ case GRN_COLUMN_INDEX :
+ GRN_UINT32_INIT(&buf, 0);
+ break;
+ default:
+ GRN_TEXT_INIT(&buf, 0);
+ break;
+ }
+ grn_obj_get_value(ctx, obj, id, &buf);
+ }
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+exit :
+ grn_obj_close(ctx, &buf);
+}
+
+grn_rc
+grn_text_otoj(grn_ctx *ctx, grn_obj *bulk, grn_obj *obj, grn_obj_format *format)
+{
+ grn_obj buf;
+ GRN_TEXT_INIT(&buf, 0);
+ switch (obj->header.type) {
+ case GRN_BULK :
+ switch (obj->header.domain) {
+ case GRN_DB_VOID :
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ grn_text_esc(ctx, bulk, GRN_BULK_HEAD(obj), GRN_BULK_VSIZE(obj));
+ break;
+ case GRN_DB_BOOL :
+ if (*((unsigned char *)GRN_BULK_HEAD(obj))) {
+ GRN_TEXT_PUTS(ctx, bulk, "true");
+ } else {
+ GRN_TEXT_PUTS(ctx, bulk, "false");
+ }
+ break;
+ case GRN_DB_INT8 :
+ grn_text_itoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT8_VALUE(obj) : 0);
+ break;
+ case GRN_DB_UINT8 :
+ grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT8_VALUE(obj) : 0);
+ break;
+ case GRN_DB_INT16 :
+ grn_text_itoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT16_VALUE(obj) : 0);
+ break;
+ case GRN_DB_UINT16 :
+ grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT16_VALUE(obj) : 0);
+ break;
+ case GRN_DB_INT32 :
+ grn_text_itoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT32_VALUE(obj) : 0);
+ break;
+ case GRN_DB_UINT32 :
+ grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT32_VALUE(obj) : 0);
+ break;
+ case GRN_DB_INT64 :
+ grn_text_lltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_INT64_VALUE(obj) : 0);
+ break;
+ case GRN_DB_UINT64 :
+ grn_text_ulltoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_UINT64_VALUE(obj) : 0);
+ break;
+ case GRN_DB_FLOAT :
+ grn_text_ftoa(ctx, bulk, GRN_BULK_VSIZE(obj) ? GRN_FLOAT_VALUE(obj) : 0);
+ break;
+ case GRN_DB_TIME :
+ {
+ double dv = *((int64_t *)GRN_BULK_HEAD(obj));
+ dv /= 1000000.0;
+ grn_text_ftoa(ctx, bulk, dv);
+ }
+ break;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ if (GRN_BULK_VSIZE(obj) == sizeof(grn_geo_point)) {
+ grn_geo_point *gp = (grn_geo_point *)GRN_BULK_HEAD(obj);
+ GRN_TEXT_PUTC(ctx, bulk, '"');
+ grn_text_itoa(ctx, bulk, gp->latitude);
+ GRN_TEXT_PUTC(ctx, bulk, 'x');
+ grn_text_itoa(ctx, bulk, gp->longitude);
+ GRN_TEXT_PUTC(ctx, bulk, '"');
+ } else {
+ GRN_TEXT_PUTS(ctx, bulk, "\"\"");
+ }
+ break;
+ default :
+ if (format) {
+ int j;
+ int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
+ grn_id id = GRN_RECORD_VALUE(obj);
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ GRN_TEXT_PUTS(ctx, bulk, "[");
+ for (j = 0; j < ncolumns; j++) {
+ grn_id range_id;
+ if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ GRN_TEXT_PUTS(ctx, bulk, "[");
+ GRN_BULK_REWIND(&buf);
+ grn_column_name_(ctx, columns[j], &buf);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ /* column range */
+ range_id = grn_obj_get_range(ctx, columns[j]);
+ if (range_id == GRN_ID_NIL) {
+ GRN_TEXT_PUTS(ctx, bulk, "null");
+ } else {
+ int name_len;
+ grn_obj *range_obj;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+
+ range_obj = grn_ctx_at(ctx, range_id);
+ name_len = grn_obj_name(ctx, range_obj, name_buf,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_BULK_REWIND(&buf);
+ GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ }
+ GRN_TEXT_PUTS(ctx, bulk, "]");
+ }
+ GRN_TEXT_PUTS(ctx, bulk, "],");
+ }
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ for (j = 0; j < ncolumns; j++) {
+ if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ grn_text_atoj(ctx, bulk, columns[j], id);
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ } else {
+ if (GRN_BULK_VSIZE(obj) == 0) {
+ GRN_TEXT_PUTS(ctx, bulk, "null");
+ } else {
+ grn_obj *table = grn_ctx_at(ctx, obj->header.domain);
+ grn_id id = GRN_RECORD_VALUE(obj);
+ if (table && table->header.type != GRN_TABLE_NO_KEY) {
+ /* todo : temporal patch. grn_table_at() is kinda costful... */
+ if (grn_table_at(ctx, table, id)) {
+ grn_obj *accessor = grn_obj_column(ctx, table,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ if (accessor) {
+ grn_obj_get_value(ctx, accessor, id, &buf);
+ grn_obj_unlink(ctx, accessor);
+ }
+ }
+ grn_text_otoj(ctx, bulk, &buf, format);
+ } else {
+ grn_text_lltoa(ctx, bulk, id);
+ }
+ }
+ }
+ }
+ break;
+ case GRN_UVECTOR :
+ if (format) {
+ if (format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT) {
+ int i, n;
+ grn_obj *domain;
+
+ n = grn_uvector_size(ctx, obj);
+ domain = grn_ctx_at(ctx, obj->header.domain);
+ GRN_TEXT_PUTS(ctx, bulk, "{");
+ for (i = 0; i < n; i++) {
+ grn_id id;
+ unsigned int weight;
+
+ if (i > 0) {
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ }
+ id = grn_uvector_get_element(ctx, obj, i, &weight);
+ if (domain) {
+ if (domain->header.type == GRN_TABLE_NO_KEY) {
+ GRN_TEXT_PUTC(ctx, bulk, '"');
+ grn_text_ulltoa(ctx, bulk, id);
+ GRN_TEXT_PUTC(ctx, bulk, '"');
+ } else {
+ GRN_BULK_REWIND(&buf);
+ grn_table_get_key2(ctx, domain, id, &buf);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ }
+ } else {
+ GRN_TEXT_PUTC(ctx, bulk, '"');
+ grn_text_ulltoa(ctx, bulk, id);
+ GRN_TEXT_PUTC(ctx, bulk, '"');
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ':');
+ grn_text_ulltoa(ctx, bulk, weight);
+ }
+ GRN_TEXT_PUTS(ctx, bulk, "}");
+ } else {
+ /* TODO: Does we still need this code? If we don't need this, we should
+ remove this. */
+ int i, j;
+ grn_id *v = (grn_id *)GRN_BULK_HEAD(obj), *ve = (grn_id *)GRN_BULK_CURR(obj);
+ int ncolumns = GRN_BULK_VSIZE(&format->columns) / sizeof(grn_obj *);
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+ GRN_TEXT_PUTS(ctx, bulk, "[[");
+ grn_text_itoa(ctx, bulk, ve - v);
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ if (v < ve) {
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ GRN_TEXT_PUTS(ctx, bulk, ",[");
+ for (j = 0; j < ncolumns; j++) {
+ grn_id range_id;
+ if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ GRN_TEXT_PUTS(ctx, bulk, "[");
+ GRN_BULK_REWIND(&buf);
+ grn_column_name_(ctx, columns[j], &buf);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ /* column range */
+ range_id = grn_obj_get_range(ctx, columns[j]);
+ if (range_id == GRN_ID_NIL) {
+ GRN_TEXT_PUTS(ctx, bulk, "null");
+ } else {
+ int name_len;
+ grn_obj *range_obj;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+
+ range_obj = grn_ctx_at(ctx, range_id);
+ name_len = grn_obj_name(ctx, range_obj, name_buf,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_BULK_REWIND(&buf);
+ GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ }
+ GRN_TEXT_PUTS(ctx, bulk, "]");
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ for (i = 0;; i++) {
+ GRN_TEXT_PUTS(ctx, bulk, ",[");
+ for (j = 0; j < ncolumns; j++) {
+ if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ GRN_BULK_REWIND(&buf);
+ grn_obj_get_value(ctx, columns[j], *v, &buf);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ v++;
+ if (v < ve) {
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ } else {
+ break;
+ }
+ }
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ } else {
+ grn_obj *range = grn_ctx_at(ctx, obj->header.domain);
+ if (range && range->header.type == GRN_TYPE) {
+ grn_id value_size = ((struct _grn_type *)range)->obj.range;
+ char *v = (char *)GRN_BULK_HEAD(obj),
+ *ve = (char *)GRN_BULK_CURR(obj);
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ if (v < ve) {
+ for (;;) {
+ grn_obj value;
+ GRN_OBJ_INIT(&value, GRN_BULK, 0, obj->header.domain);
+ grn_bulk_write_from(ctx, &value, v, 0, value_size);
+ grn_text_otoj(ctx, bulk, &value, NULL);
+
+ v += value_size;
+ if (v < ve) {
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ } else {
+ break;
+ }
+ }
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ } else {
+ grn_id *v = (grn_id *)GRN_BULK_HEAD(obj),
+ *ve = (grn_id *)GRN_BULK_CURR(obj);
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ if (v < ve) {
+ for (;;) {
+ if (range->header.type != GRN_TABLE_NO_KEY) {
+ grn_obj key;
+ GRN_OBJ_INIT(&key, GRN_BULK, 0, range->header.domain);
+ grn_table_get_key2(ctx, range, *v, &key);
+ grn_text_otoj(ctx, bulk, &key, NULL);
+ GRN_OBJ_FIN(ctx, &key);
+ } else {
+ grn_text_lltoa(ctx, bulk, *v);
+ }
+ v++;
+ if (v < ve) {
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ } else {
+ break;
+ }
+ }
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ }
+ break;
+ case GRN_VECTOR :
+ if (obj->header.domain == GRN_DB_VOID) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid obj->header.domain");
+ } else {
+ unsigned int i, n;
+ grn_obj value;
+ grn_obj weight;
+ grn_bool with_weight;
+
+ GRN_VOID_INIT(&value);
+ GRN_UINT32_INIT(&weight, 0);
+ with_weight = (format && format->flags & GRN_OBJ_FORMAT_WITH_WEIGHT);
+ n = grn_vector_size(ctx, obj);
+ if (with_weight) {
+ GRN_TEXT_PUTC(ctx, bulk, '{');
+ } else {
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ }
+ for (i = 0; i < n; i++) {
+ const char *_value;
+ unsigned int _weight, length;
+ grn_id domain;
+ if (i) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+
+ length = grn_vector_get_element(ctx, obj, i,
+ &_value, &_weight, &domain);
+ if (domain != GRN_DB_VOID) {
+ grn_obj_reinit(ctx, &value, domain, 0);
+ } else {
+ grn_obj_reinit(ctx, &value, obj->header.domain, 0);
+ }
+ grn_bulk_write(ctx, &value, _value, length);
+ grn_text_otoj(ctx, bulk, &value, NULL);
+ if (with_weight) {
+ GRN_TEXT_PUTC(ctx, bulk, ':');
+ GRN_UINT32_SET(ctx, &weight, _weight);
+ grn_text_otoj(ctx, bulk, &weight, NULL);
+ }
+ }
+ if (with_weight) {
+ GRN_TEXT_PUTC(ctx, bulk, '}');
+ } else {
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ GRN_OBJ_FIN(ctx, &value);
+ GRN_OBJ_FIN(ctx, &weight);
+ }
+ break;
+ case GRN_PVECTOR :
+ if (format) {
+ ERR(GRN_FUNCTION_NOT_IMPLEMENTED,
+ "cannot print GRN_PVECTOR using grn_obj_format");
+ } else {
+ unsigned int i, n;
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ n = GRN_BULK_VSIZE(obj) / sizeof(grn_obj *);
+ for (i = 0; i < n; i++) {
+ grn_obj *value;
+
+ if (i) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ value = GRN_PTR_VALUE_AT(obj, i);
+ grn_text_otoj(ctx, bulk, value, NULL);
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ if (format) {
+ int i, j;
+ int ncolumns = GRN_BULK_VSIZE(&format->columns)/sizeof(grn_obj *);
+ grn_obj **columns = (grn_obj **)GRN_BULK_HEAD(&format->columns);
+ grn_table_cursor *tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
+ format->offset, format->limit,
+ GRN_CURSOR_ASCENDING);
+ if (!tc) { ERRCLR(ctx); }
+ GRN_TEXT_PUTS(ctx, bulk, "[[");
+ grn_text_itoa(ctx, bulk, format->nhits);
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ if (format->flags & GRN_OBJ_FORMAT_WITH_COLUMN_NAMES) {
+ GRN_TEXT_PUTS(ctx, bulk, ",[");
+ for (j = 0; j < ncolumns; j++) {
+ grn_id range_id;
+ if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ GRN_TEXT_PUTS(ctx, bulk, "[");
+ GRN_BULK_REWIND(&buf);
+ grn_column_name_(ctx, columns[j], &buf);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ GRN_TEXT_PUTC(ctx, bulk, ',');
+ /* column range */
+ range_id = grn_obj_get_range(ctx, columns[j]);
+ if (range_id == GRN_ID_NIL) {
+ GRN_TEXT_PUTS(ctx, bulk, "null");
+ } else {
+ int name_len;
+ grn_obj *range_obj;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+
+ range_obj = grn_ctx_at(ctx, range_id);
+ name_len = grn_obj_name(ctx, range_obj, name_buf,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_BULK_REWIND(&buf);
+ GRN_TEXT_PUT(ctx, &buf, name_buf, name_len);
+ grn_text_otoj(ctx, bulk, &buf, NULL);
+ }
+ GRN_TEXT_PUTS(ctx, bulk, "]");
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ if (tc) {
+ grn_id id;
+ for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
+ GRN_TEXT_PUTS(ctx, bulk, ",[");
+ for (j = 0; j < ncolumns; j++) {
+ if (j) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ grn_text_atoj(ctx, bulk, columns[j], id);
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ } else {
+ int i;
+ grn_id id;
+ grn_obj *column = grn_obj_column(ctx, obj,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ grn_table_cursor *tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_ASCENDING);
+ GRN_TEXT_PUTC(ctx, bulk, '[');
+ if (tc) {
+ for (i = 0; (id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL; i++) {
+ if (i) { GRN_TEXT_PUTC(ctx, bulk, ','); }
+ GRN_BULK_REWIND(&buf);
+ grn_obj_get_value(ctx, column, id, &buf);
+ grn_text_esc(ctx, bulk, GRN_BULK_HEAD(&buf), GRN_BULK_VSIZE(&buf));
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_TEXT_PUTC(ctx, bulk, ']');
+ grn_obj_unlink(ctx, column);
+ }
+ break;
+ }
+ grn_obj_close(ctx, &buf);
+ return GRN_SUCCESS;
+}
+
+const char *
+grn_text_urldec(grn_ctx *ctx, grn_obj *buf, const char *p, const char *e, char d)
+{
+ while (p < e) {
+ if (*p == d) {
+ p++; break;
+ } else if (*p == '%' && p + 3 <= e) {
+ const char *r;
+ unsigned int c = grn_htoui(p + 1, p + 3, &r);
+ if (p + 3 == r) {
+ GRN_TEXT_PUTC(ctx, buf, c);
+ p += 3;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid %% sequence (%c%c)", p[1], p[2]);
+ GRN_TEXT_PUTC(ctx, buf, '%');
+ p += 1;
+ }
+ } else {
+ GRN_TEXT_PUTC(ctx, buf, *p);
+ p++;
+ }
+ }
+ return p;
+}
+
+const char *
+grn_text_cgidec(grn_ctx *ctx, grn_obj *buf, const char *p, const char *e,
+ const char *delimiters)
+{
+ while (p < e) {
+ grn_bool found_delimiter = GRN_FALSE;
+ const char *delimiter;
+ for (delimiter = delimiters; *delimiter; delimiter++) {
+ if (*p == *delimiter) {
+ found_delimiter = GRN_TRUE;
+ break;
+ }
+ }
+ if (found_delimiter) {
+ p++;
+ break;
+ }
+
+ if (*p == '+') {
+ GRN_TEXT_PUTC(ctx, buf, ' ');
+ p++;
+ } else if (*p == '%' && p + 3 <= e) {
+ const char *r;
+ unsigned int c = grn_htoui(p + 1, p + 3, &r);
+ if (p + 3 == r) {
+ GRN_TEXT_PUTC(ctx, buf, c);
+ p += 3;
+ } else {
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "invalid %% sequence (%c%c)", p[1], p[2]);
+ GRN_TEXT_PUTC(ctx, buf, '%');
+ p += 1;
+ }
+ } else {
+ GRN_TEXT_PUTC(ctx, buf, *p);
+ p++;
+ }
+ }
+ return p;
+}
+
+void
+grn_str_url_path_normalize(grn_ctx *ctx, const char *path, size_t path_len,
+ char *buf, size_t buf_len)
+{
+ char *b = buf, *be = buf + buf_len - 1;
+ const char *p = path, *pe = path + path_len, *pc;
+
+ if (buf_len < 2) { return; }
+
+ while (p < pe) {
+ for (pc = p; pc < pe && *pc != '/'; pc++) {}
+ if (*p == '.') {
+ if (pc == p + 2 && *(p + 1) == '.') {
+ /* '..' */
+ if (b - buf >= 2) {
+ for (b -= 2; *b != '/' && b >= buf; b--) {}
+ }
+ if (*b == '/') {
+ b++;
+ ERR(GRN_INVALID_ARGUMENT, "parent path doesn't exist.");
+ }
+ p = pc + 1;
+ continue;
+ } else if (pc == p + 1) {
+ /* '.' */
+ p = pc + 1;
+ continue;
+ }
+ }
+ if (be - b >= pc - p) {
+ grn_memcpy(b, p, (pc - p));
+ b += pc - p;
+ p = pc;
+ if (p < pe && *pc == '/' && be > b) {
+ *b++ = '/';
+ p++;
+ }
+ }
+ }
+ *b = '\0';
+}
+
+grn_bool
+grn_bulk_is_zero(grn_ctx *ctx, grn_obj *obj)
+{
+ const char *v = GRN_BULK_HEAD(obj);
+ unsigned int s = GRN_BULK_VSIZE(obj);
+ for (; s; s--, v++) {
+ if (*v) { return GRN_FALSE; }
+ }
+ return GRN_TRUE;
+}
+
diff --git a/storage/mroonga/vendor/groonga/lib/string.c b/storage/mroonga/vendor/groonga/lib/string.c
new file mode 100644
index 00000000..8e591100
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/string.c
@@ -0,0 +1,416 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2012 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include <string.h>
+#include "grn_string.h"
+#include "grn_normalizer.h"
+#include "grn_str.h"
+#include "grn_util.h"
+
+#include <groonga/tokenizer.h>
+
+static grn_string *
+grn_fake_string_open(grn_ctx *ctx, grn_string *string)
+{
+ /* TODO: support GRN_STRING_REMOVE_BLANK flag and ctypes */
+ grn_string *nstr = string;
+ const char *str;
+ unsigned int str_len;
+
+ str = nstr->original;
+ str_len = nstr->original_length_in_bytes;
+
+ if (!(nstr->normalized = GRN_MALLOC(str_len + 1))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[strinig][fake] failed to allocate normalized text space");
+ grn_string_close(ctx, (grn_obj *)nstr);
+ return NULL;
+ }
+
+ if (nstr->flags & GRN_STRING_REMOVE_TOKENIZED_DELIMITER &&
+ ctx->encoding == GRN_ENC_UTF8) {
+ int char_length;
+ const char *source_current = str;
+ const char *source_end = str + str_len;
+ char *destination = nstr->normalized;
+ unsigned int destination_length = 0;
+ while ((char_length = grn_charlen(ctx, source_current, source_end)) > 0) {
+ if (!grn_tokenizer_is_tokenized_delimiter(ctx,
+ source_current, char_length,
+ ctx->encoding)) {
+ grn_memcpy(destination, source_current, char_length);
+ destination += char_length;
+ destination_length += char_length;
+ }
+ source_current += char_length;
+ }
+ nstr->normalized[destination_length] = '\0';
+ nstr->normalized_length_in_bytes = destination_length;
+ } else {
+ grn_memcpy(nstr->normalized, str, str_len);
+ nstr->normalized[str_len] = '\0';
+ nstr->normalized_length_in_bytes = str_len;
+ }
+
+ if (nstr->flags & GRN_STRING_WITH_CHECKS) {
+ int16_t f = 0;
+ unsigned char c;
+ size_t i;
+ if (!(nstr->checks = (int16_t *) GRN_MALLOC(sizeof(int16_t) * str_len))) {
+ grn_string_close(ctx, (grn_obj *)nstr);
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[strinig][fake] failed to allocate checks space");
+ return NULL;
+ }
+ switch (nstr->encoding) {
+ case GRN_ENC_EUC_JP:
+ for (i = 0; i < str_len; i++) {
+ if (!f) {
+ c = (unsigned char) str[i];
+ f = ((c >= 0xa1U && c <= 0xfeU) || c == 0x8eU ? 2 : (c == 0x8fU ? 3 : 1)
+ );
+ nstr->checks[i] = f;
+ } else {
+ nstr->checks[i] = 0;
+ }
+ f--;
+ }
+ break;
+ case GRN_ENC_SJIS:
+ for (i = 0; i < str_len; i++) {
+ if (!f) {
+ c = (unsigned char) str[i];
+ f = (c >= 0x81U && ((c <= 0x9fU) || (c >= 0xe0U && c <= 0xfcU)) ? 2 : 1);
+ nstr->checks[i] = f;
+ } else {
+ nstr->checks[i] = 0;
+ }
+ f--;
+ }
+ break;
+ case GRN_ENC_UTF8:
+ for (i = 0; i < str_len; i++) {
+ if (!f) {
+ c = (unsigned char) str[i];
+ f = (c & 0x80U ? (c & 0x20U ? (c & 0x10U ? 4 : 3)
+ : 2)
+ : 1);
+ nstr->checks[i] = f;
+ } else {
+ nstr->checks[i] = 0;
+ }
+ f--;
+ }
+ break;
+ default:
+ for (i = 0; i < str_len; i++) {
+ nstr->checks[i] = 1;
+ }
+ break;
+ }
+ }
+ return nstr;
+}
+
+grn_obj *
+grn_string_open_(grn_ctx *ctx, const char *str, unsigned int str_len,
+ grn_obj *normalizer, int flags, grn_encoding encoding)
+{
+ grn_string *string;
+ grn_obj *obj;
+ grn_bool is_normalizer_auto;
+
+ if (!str || !str_len) {
+ return NULL;
+ }
+
+ is_normalizer_auto = (normalizer == GRN_NORMALIZER_AUTO);
+ if (is_normalizer_auto) {
+ normalizer = grn_ctx_get(ctx, GRN_NORMALIZER_AUTO_NAME, -1);
+ if (!normalizer) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[string][open] NormalizerAuto normalizer isn't available");
+ return NULL;
+ }
+ }
+
+ string = GRN_MALLOCN(grn_string, 1);
+ if (!string) {
+ if (is_normalizer_auto) {
+ grn_obj_unlink(ctx, normalizer);
+ }
+ GRN_LOG(ctx, GRN_LOG_ALERT,
+ "[string][open] failed to allocate memory");
+ return NULL;
+ }
+
+ obj = (grn_obj *)string;
+ GRN_OBJ_INIT(obj, GRN_STRING, GRN_OBJ_ALLOCATED, GRN_ID_NIL);
+ string->original = str;
+ string->original_length_in_bytes = str_len;
+ string->normalized = NULL;
+ string->normalized_length_in_bytes = 0;
+ string->n_characters = 0;
+ string->checks = NULL;
+ string->ctypes = NULL;
+ string->encoding = encoding;
+ string->flags = flags;
+
+ if (!normalizer) {
+ return (grn_obj *)grn_fake_string_open(ctx, string);
+ }
+
+ grn_normalizer_normalize(ctx, normalizer, (grn_obj *)string);
+ if (ctx->rc) {
+ grn_obj_close(ctx, obj);
+ obj = NULL;
+ }
+
+ if (is_normalizer_auto) {
+ grn_obj_unlink(ctx, normalizer);
+ }
+
+ return obj;
+}
+
+grn_obj *
+grn_string_open(grn_ctx *ctx, const char *str, unsigned int str_len,
+ grn_obj *normalizer, int flags)
+{
+ return grn_string_open_(ctx, str, str_len, normalizer, flags, ctx->encoding);
+}
+
+grn_rc
+grn_string_get_original(grn_ctx *ctx, grn_obj *string,
+ const char **original,
+ unsigned int *length_in_bytes)
+{
+ grn_rc rc;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ if (original) { *original = string_->original; }
+ if (length_in_bytes) {
+ *length_in_bytes = string_->original_length_in_bytes;
+ }
+ rc = GRN_SUCCESS;
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_RETURN(rc);
+}
+
+int
+grn_string_get_flags(grn_ctx *ctx, grn_obj *string)
+{
+ int flags = 0;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ flags = string_->flags;
+ }
+ GRN_API_RETURN(flags);
+}
+
+grn_rc
+grn_string_get_normalized(grn_ctx *ctx, grn_obj *string,
+ const char **normalized,
+ unsigned int *length_in_bytes,
+ unsigned int *n_characters)
+{
+ grn_rc rc;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ if (normalized) { *normalized = string_->normalized; }
+ if (length_in_bytes) {
+ *length_in_bytes = string_->normalized_length_in_bytes;
+ }
+ if (n_characters) { *n_characters = string_->n_characters; }
+ rc = GRN_SUCCESS;
+ } else {
+ if (normalized) { *normalized = NULL; }
+ if (length_in_bytes) { *length_in_bytes = 0; }
+ if (n_characters) { *n_characters = 0; }
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_rc
+grn_string_set_normalized(grn_ctx *ctx, grn_obj *string,
+ char *normalized, unsigned int length_in_bytes,
+ unsigned int n_characters)
+{
+ grn_rc rc;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ if (string_->normalized) { GRN_FREE(string_->normalized); }
+ string_->normalized = normalized;
+ string_->normalized_length_in_bytes = length_in_bytes;
+ string_->n_characters = n_characters;
+ rc = GRN_SUCCESS;
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_RETURN(rc);
+}
+
+const short *
+grn_string_get_checks(grn_ctx *ctx, grn_obj *string)
+{
+ int16_t *checks = NULL;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ checks = string_->checks;
+ } else {
+ checks = NULL;
+ }
+ GRN_API_RETURN(checks);
+}
+
+grn_rc
+grn_string_set_checks(grn_ctx *ctx, grn_obj *string, short *checks)
+{
+ grn_rc rc;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ if (string_->checks) { GRN_FREE(string_->checks); }
+ string_->checks = checks;
+ rc = GRN_SUCCESS;
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_RETURN(rc);
+}
+
+const unsigned char *
+grn_string_get_types(grn_ctx *ctx, grn_obj *string)
+{
+ unsigned char *types = NULL;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ types = string_->ctypes;
+ } else {
+ types = NULL;
+ }
+ GRN_API_RETURN(types);
+}
+
+grn_rc
+grn_string_set_types(grn_ctx *ctx, grn_obj *string, unsigned char *types)
+{
+ grn_rc rc;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ if (string_->ctypes) { GRN_FREE(string_->ctypes); }
+ string_->ctypes = types;
+ rc = GRN_SUCCESS;
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ GRN_API_RETURN(rc);
+}
+
+grn_encoding
+grn_string_get_encoding(grn_ctx *ctx, grn_obj *string)
+{
+ grn_encoding encoding = GRN_ENC_NONE;
+ grn_string *string_ = (grn_string *)string;
+ GRN_API_ENTER;
+ if (string_) {
+ encoding = string_->encoding;
+ }
+ GRN_API_RETURN(encoding);
+}
+
+grn_rc
+grn_string_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *string)
+{
+ grn_string *string_ = (grn_string *)string;
+
+ GRN_TEXT_PUTS(ctx, buffer, "#<string:");
+
+ GRN_TEXT_PUTS(ctx, buffer, " original:<");
+ GRN_TEXT_PUT(ctx, buffer,
+ string_->original,
+ string_->original_length_in_bytes);
+ GRN_TEXT_PUTS(ctx, buffer, ">");
+ GRN_TEXT_PUTS(ctx, buffer, "(");
+ grn_text_itoa(ctx, buffer, string_->original_length_in_bytes);
+ GRN_TEXT_PUTS(ctx, buffer, ")");
+
+ GRN_TEXT_PUTS(ctx, buffer, " normalized:<");
+ GRN_TEXT_PUT(ctx, buffer,
+ string_->normalized,
+ string_->normalized_length_in_bytes);
+ GRN_TEXT_PUTS(ctx, buffer, ">");
+ GRN_TEXT_PUTS(ctx, buffer, "(");
+ grn_text_itoa(ctx, buffer, string_->normalized_length_in_bytes);
+ GRN_TEXT_PUTS(ctx, buffer, ")");
+
+ GRN_TEXT_PUTS(ctx, buffer, " n_characters:");
+ grn_text_itoa(ctx, buffer, string_->n_characters);
+
+ GRN_TEXT_PUTS(ctx, buffer, " encoding:");
+ grn_inspect_encoding(ctx, buffer, string_->encoding);
+
+ GRN_TEXT_PUTS(ctx, buffer, " flags:");
+ if (string_->flags & GRN_STRING_REMOVE_BLANK) {
+ GRN_TEXT_PUTS(ctx, buffer, "REMOVE_BLANK|");
+ }
+ if (string_->flags & GRN_STRING_WITH_TYPES) {
+ GRN_TEXT_PUTS(ctx, buffer, "WITH_TYPES|");
+ }
+ if (string_->flags & GRN_STRING_WITH_CHECKS) {
+ GRN_TEXT_PUTS(ctx, buffer, "WITH_CHECKS|");
+ }
+ if (string_->flags & GRN_STRING_REMOVE_TOKENIZED_DELIMITER) {
+ GRN_TEXT_PUTS(ctx, buffer, "REMOVE_TOKENIZED_DELIMITER|");
+ }
+ if (GRN_TEXT_VALUE(buffer)[GRN_TEXT_LEN(buffer) - 1] == '|') {
+ grn_bulk_truncate(ctx, buffer, GRN_TEXT_LEN(buffer) - 1);
+ }
+
+ GRN_TEXT_PUTS(ctx, buffer, ">");
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_string_close(grn_ctx *ctx, grn_obj *string)
+{
+ grn_rc rc;
+ grn_string *string_ = (grn_string *)string;
+ if (string_) {
+ if (string_->normalized) { GRN_FREE(string_->normalized); }
+ if (string_->ctypes) { GRN_FREE(string_->ctypes); }
+ if (string_->checks) { GRN_FREE(string_->checks); }
+ GRN_FREE(string);
+ rc = GRN_SUCCESS;
+ } else {
+ rc = GRN_INVALID_ARGUMENT;
+ }
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/table.c b/storage/mroonga/vendor/groonga/lib/table.c
new file mode 100644
index 00000000..0047c787
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/table.c
@@ -0,0 +1,122 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_ctx.h"
+#include "grn_expr_executor.h"
+
+grn_rc
+grn_table_apply_expr(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *output_column,
+ grn_obj *expr)
+{
+ grn_expr_executor *executor;
+
+ GRN_API_ENTER;
+
+ if (!grn_obj_is_data_column(ctx, output_column)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, output_column);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][apply-expr] output column isn't data column: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (!grn_obj_is_expr(ctx, expr)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, expr);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][apply-expr] expr is invalid: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ executor = grn_expr_executor_open(ctx, expr);
+ if (!executor) {
+ GRN_API_RETURN(ctx->rc);
+ }
+ GRN_TABLE_EACH_BEGIN_FLAGS(ctx, table, cursor, id, GRN_CURSOR_BY_ID) {
+ grn_obj *value;
+ value = grn_expr_executor_exec(ctx, executor, id);
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ if (value) {
+ grn_obj_set_value(ctx, output_column, id, value, GRN_OBJ_SET);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_expr_executor_close(ctx, executor);
+
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_id
+grn_table_find_reference_object(grn_ctx *ctx, grn_obj *table)
+{
+ grn_id table_id;
+ grn_id reference_object_id = GRN_ID_NIL;
+
+ GRN_API_ENTER;
+
+ if (!grn_obj_is_table(ctx, table)) {
+ GRN_API_RETURN(GRN_ID_NIL);
+ }
+
+ table_id = DB_OBJ(table)->id;
+
+ GRN_DB_SPEC_EACH_BEGIN(ctx, cursor, id, spec) {
+ if (id == table_id) {
+ continue;
+ }
+
+ switch (spec->header.type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ if (spec->header.domain == table_id) {
+ reference_object_id = id;
+ }
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ case GRN_COLUMN_FIX_SIZE :
+ if (spec->header.domain == table_id) {
+ break;
+ }
+ if (spec->range == table_id) {
+ reference_object_id = id;
+ }
+ break;
+ default :
+ break;
+ }
+
+ if (reference_object_id != GRN_ID_NIL) {
+ break;
+ }
+ } GRN_DB_SPEC_EACH_END(ctx, cursor);
+
+ GRN_API_RETURN(reference_object_id);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/thread.c b/storage/mroonga/vendor/groonga/lib/thread.c
new file mode 100644
index 00000000..7e823ab3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/thread.c
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx.h"
+
+static grn_thread_get_limit_func get_limit_func = NULL;
+static void *get_limit_func_data = NULL;
+static grn_thread_set_limit_func set_limit_func = NULL;
+static void *set_limit_func_data = NULL;
+
+uint32_t
+grn_thread_get_limit(void)
+{
+ if (get_limit_func) {
+ return get_limit_func(get_limit_func_data);
+ } else {
+ return 0;
+ }
+}
+
+void
+grn_thread_set_limit(uint32_t new_limit)
+{
+ if (!set_limit_func) {
+ return;
+ }
+
+ set_limit_func(new_limit, set_limit_func_data);
+}
+
+void
+grn_thread_set_get_limit_func(grn_thread_get_limit_func func,
+ void *data)
+{
+ get_limit_func = func;
+ get_limit_func_data = data;
+}
+
+void
+grn_thread_set_set_limit_func(grn_thread_set_limit_func func, void *data)
+{
+ set_limit_func = func;
+ set_limit_func_data = data;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/time.c b/storage/mroonga/vendor/groonga/lib/time.c
new file mode 100644
index 00000000..b11bc7a0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/time.c
@@ -0,0 +1,245 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_time.h"
+#include "grn_ctx.h"
+#include "grn_str.h"
+
+#include <stdio.h>
+#include <time.h>
+
+#if defined(HAVE__LOCALTIME64_S) && defined(__GNUC__)
+# ifdef _WIN64
+# define localtime_s(tm, time) _localtime64_s(tm, time)
+# else /* _WIN64 */
+# define localtime_s(tm, time) _localtime32_s(tm, time)
+# endif /* _WIN64 */
+#endif /* defined(HAVE__LOCALTIME64_S) && defined(__GNUC__) */
+
+/* fixme by 2038 */
+
+grn_rc
+grn_timeval_now(grn_ctx *ctx, grn_timeval *tv)
+{
+#ifdef HAVE_CLOCK_GETTIME
+ struct timespec t;
+ if (clock_gettime(CLOCK_REALTIME, &t)) {
+ SERR("clock_gettime");
+ } else {
+ tv->tv_sec = t.tv_sec;
+ tv->tv_nsec = t.tv_nsec;
+ }
+ return ctx->rc;
+#else /* HAVE_CLOCK_GETTIME */
+# ifdef WIN32
+ time_t t;
+ struct _timeb tb;
+ time(&t);
+ _ftime(&tb);
+ tv->tv_sec = t;
+ tv->tv_nsec = tb.millitm * (GRN_TIME_NSEC_PER_SEC / 1000);
+ return GRN_SUCCESS;
+# else /* WIN32 */
+ struct timeval t;
+ if (gettimeofday(&t, NULL)) {
+ SERR("gettimeofday");
+ } else {
+ tv->tv_sec = t.tv_sec;
+ tv->tv_nsec = GRN_TIME_USEC_TO_NSEC(t.tv_usec);
+ }
+ return ctx->rc;
+# endif /* WIN32 */
+#endif /* HAVE_CLOCK_GETTIME */
+}
+
+void
+grn_time_now(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ GRN_TIME_SET(ctx, obj, GRN_TIME_PACK(tv.tv_sec,
+ GRN_TIME_NSEC_TO_USEC(tv.tv_nsec)));
+}
+
+static grn_bool
+grn_time_t_to_tm(grn_ctx *ctx, const time_t time, struct tm *tm)
+{
+ grn_bool success;
+ const char *function_name;
+#ifdef HAVE__LOCALTIME64_S
+ function_name = "localtime_s";
+ success = (localtime_s(tm, &time) == 0);
+#else /* HAVE__LOCALTIME64_S */
+# ifdef HAVE_LOCALTIME_R
+ function_name = "localtime_r";
+ success = (localtime_r(&time, tm) != NULL);
+# else /* HAVE_LOCALTIME_R */
+ function_name = "localtime";
+ {
+ struct tm *local_tm;
+ local_tm = localtime(&time);
+ if (local_tm) {
+ success = GRN_TRUE;
+ memcpy(tm, local_tm, sizeof(struct tm));
+ } else {
+ success = GRN_FALSE;
+ }
+ }
+# endif /* HAVE_LOCALTIME_R */
+#endif /* HAVE__LOCALTIME64_S */
+ if (!success) {
+ SERR("%s: failed to convert time_t to struct tm: <%" GRN_FMT_INT64D ">",
+ function_name,
+ (int64_t)time);
+ }
+ return success;
+}
+
+struct tm *
+grn_timeval2tm(grn_ctx *ctx, grn_timeval *tv, struct tm *tm)
+{
+ if (grn_time_t_to_tm(ctx, tv->tv_sec, tm)) {
+ return tm;
+ } else {
+ return NULL;
+ }
+}
+
+grn_bool
+grn_time_to_tm(grn_ctx *ctx, int64_t time, struct tm *tm)
+{
+ int64_t sec;
+ int32_t usec;
+
+ GRN_TIME_UNPACK(time, sec, usec);
+ return grn_time_t_to_tm(ctx, sec, tm);
+}
+
+static grn_bool
+grn_time_t_from_tm(grn_ctx *ctx, time_t *time, struct tm *tm)
+{
+ grn_bool success;
+
+ tm->tm_yday = -1;
+ *time = mktime(tm);
+ success = (tm->tm_yday != -1);
+ if (!success) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "mktime: failed to convert struct tm to time_t: "
+ "<%04d-%02d-%02dT%02d:%02d:%02d>(%d)",
+ 1900 + tm->tm_year,
+ tm->tm_mon + 1,
+ tm->tm_mday,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec,
+ tm->tm_isdst);
+ }
+ return success;
+}
+
+grn_bool
+grn_time_from_tm(grn_ctx *ctx, int64_t *time, struct tm *tm)
+{
+ time_t sec_time_t;
+ int64_t sec;
+ int32_t usec = 0;
+
+ if (!grn_time_t_from_tm(ctx, &sec_time_t, tm)) {
+ return GRN_FALSE;
+ }
+
+ sec = sec_time_t;
+ *time = GRN_TIME_PACK(sec, usec);
+ return GRN_TRUE;
+}
+
+grn_rc
+grn_timeval2str(grn_ctx *ctx, grn_timeval *tv, char *buf, size_t buf_size)
+{
+ struct tm tm;
+ struct tm *ltm;
+ ltm = grn_timeval2tm(ctx, tv, &tm);
+ grn_snprintf(buf, buf_size, GRN_TIMEVAL_STR_SIZE,
+ GRN_TIMEVAL_STR_FORMAT,
+ ltm->tm_year + 1900, ltm->tm_mon + 1, ltm->tm_mday,
+ ltm->tm_hour, ltm->tm_min, ltm->tm_sec,
+ (int)(GRN_TIME_NSEC_TO_USEC(tv->tv_nsec)));
+ if (buf_size > GRN_TIMEVAL_STR_SIZE) {
+ buf[GRN_TIMEVAL_STR_SIZE - 1] = '\0';
+ } else {
+ buf[buf_size - 1] = '\0';
+ }
+ return ctx->rc;
+}
+
+grn_rc
+grn_str2timeval(const char *str, uint32_t str_len, grn_timeval *tv)
+{
+ struct tm tm;
+ const char *r1, *r2, *rend = str + str_len;
+ uint32_t uv;
+ memset(&tm, 0, sizeof(struct tm));
+
+ tm.tm_year = (int)grn_atoui(str, rend, &r1) - 1900;
+ if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-')) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ r1++;
+ tm.tm_mon = (int)grn_atoui(r1, rend, &r1) - 1;
+ if ((r1 + 1) >= rend || (*r1 != '/' && *r1 != '-') ||
+ tm.tm_mon < 0 || tm.tm_mon >= 12) { return GRN_INVALID_ARGUMENT; }
+ r1++;
+ tm.tm_mday = (int)grn_atoui(r1, rend, &r1);
+ if ((r1 + 1) >= rend || *r1 != ' ' ||
+ tm.tm_mday < 1 || tm.tm_mday > 31) { return GRN_INVALID_ARGUMENT; }
+
+ tm.tm_hour = (int)grn_atoui(++r1, rend, &r2);
+ if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
+ tm.tm_hour < 0 || tm.tm_hour >= 24) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ r1 = r2 + 1;
+ tm.tm_min = (int)grn_atoui(r1, rend, &r2);
+ if ((r2 + 1) >= rend || r1 == r2 || *r2 != ':' ||
+ tm.tm_min < 0 || tm.tm_min >= 60) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ r1 = r2 + 1;
+ tm.tm_sec = (int)grn_atoui(r1, rend, &r2);
+ if (r1 == r2 ||
+ tm.tm_sec < 0 || tm.tm_sec > 61 /* leap 2sec */) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ r1 = r2;
+ tm.tm_yday = -1;
+ tm.tm_isdst = -1;
+
+ /* tm_yday is set appropriately (0-365) on successful completion. */
+ tv->tv_sec = mktime(&tm);
+ if (tm.tm_yday == -1) { return GRN_INVALID_ARGUMENT; }
+ if ((r1 + 1) < rend && *r1 == '.') { r1++; }
+ uv = grn_atoi(r1, rend, &r2);
+ while (r2 < r1 + 6) {
+ uv *= 10;
+ r2++;
+ }
+ if (uv >= GRN_TIME_USEC_PER_SEC) { return GRN_INVALID_ARGUMENT; }
+ tv->tv_nsec = GRN_TIME_USEC_TO_NSEC(uv);
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/token_cursor.c b/storage/mroonga/vendor/groonga/lib/token_cursor.c
new file mode 100644
index 00000000..179d0f31
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/token_cursor.c
@@ -0,0 +1,386 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn_token_cursor.h"
+#include "grn_string.h"
+#include "grn_pat.h"
+#include "grn_dat.h"
+
+static void
+grn_token_cursor_open_initialize_token_filters(grn_ctx *ctx,
+ grn_token_cursor *token_cursor)
+{
+ grn_obj *token_filters = token_cursor->token_filter.objects;
+ unsigned int i, n_token_filters;
+
+ token_cursor->token_filter.data = NULL;
+
+ if (token_filters) {
+ n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
+ } else {
+ n_token_filters = 0;
+ }
+
+ if (n_token_filters == 0) {
+ return;
+ }
+
+ token_cursor->token_filter.data = GRN_CALLOC(sizeof(void *) * n_token_filters);
+ if (!token_cursor->token_filter.data) {
+ return;
+ }
+
+ for (i = 0; i < n_token_filters; i++) {
+ grn_obj *token_filter_object = GRN_PTR_VALUE_AT(token_filters, i);
+ grn_proc *token_filter = (grn_proc *)token_filter_object;
+
+ token_cursor->token_filter.data[i] =
+ token_filter->callbacks.token_filter.init(ctx,
+ token_cursor->table,
+ token_cursor->mode);
+ }
+}
+
+grn_token_cursor *
+grn_token_cursor_open(grn_ctx *ctx, grn_obj *table,
+ const char *str, size_t str_len,
+ grn_tokenize_mode mode, unsigned int flags)
+{
+ grn_token_cursor *token_cursor;
+ grn_encoding encoding;
+ grn_obj *tokenizer;
+ grn_obj *normalizer;
+ grn_obj *token_filters;
+ grn_table_flags table_flags;
+ if (grn_table_get_info(ctx, table, &table_flags, &encoding, &tokenizer,
+ &normalizer, &token_filters)) {
+ return NULL;
+ }
+ if (!(token_cursor = GRN_MALLOC(sizeof(grn_token_cursor)))) { return NULL; }
+ token_cursor->table = table;
+ token_cursor->mode = mode;
+ token_cursor->encoding = encoding;
+ token_cursor->tokenizer = tokenizer;
+ token_cursor->token_filter.objects = token_filters;
+ token_cursor->token_filter.data = NULL;
+ token_cursor->orig = (const unsigned char *)str;
+ token_cursor->orig_blen = str_len;
+ token_cursor->curr = NULL;
+ token_cursor->nstr = NULL;
+ token_cursor->curr_size = 0;
+ token_cursor->pos = -1;
+ token_cursor->status = GRN_TOKEN_CURSOR_DOING;
+ token_cursor->force_prefix = GRN_FALSE;
+ if (tokenizer) {
+ grn_obj str_, flags_, mode_;
+ GRN_TEXT_INIT(&str_, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&str_, str, str_len);
+ GRN_UINT32_INIT(&flags_, 0);
+ GRN_UINT32_SET(ctx, &flags_, flags);
+ GRN_UINT32_INIT(&mode_, 0);
+ GRN_UINT32_SET(ctx, &mode_, mode);
+ token_cursor->pctx.caller = NULL;
+ token_cursor->pctx.user_data.ptr = NULL;
+ token_cursor->pctx.proc = (grn_proc *)tokenizer;
+ token_cursor->pctx.hooks = NULL;
+ token_cursor->pctx.currh = NULL;
+ token_cursor->pctx.phase = PROC_INIT;
+ grn_ctx_push(ctx, &mode_);
+ grn_ctx_push(ctx, &str_);
+ grn_ctx_push(ctx, &flags_);
+ ((grn_proc *)tokenizer)->funcs[PROC_INIT](ctx, 1, &table, &token_cursor->pctx.user_data);
+ grn_obj_close(ctx, &flags_);
+ grn_obj_close(ctx, &str_);
+ grn_obj_close(ctx, &mode_);
+ } else {
+ int nflags = 0;
+ token_cursor->nstr = grn_string_open_(ctx, str, str_len,
+ normalizer,
+ nflags,
+ token_cursor->encoding);
+ if (token_cursor->nstr) {
+ const char *normalized;
+ grn_string_get_normalized(ctx, token_cursor->nstr,
+ &normalized, &(token_cursor->curr_size), NULL);
+ token_cursor->curr = (const unsigned char *)normalized;
+ } else {
+ ERR(GRN_TOKENIZER_ERROR,
+ "[token-cursor][open] failed to grn_string_open()");
+ }
+ }
+
+ if (ctx->rc == GRN_SUCCESS) {
+ grn_token_cursor_open_initialize_token_filters(ctx, token_cursor);
+ }
+
+ if (ctx->rc) {
+ grn_token_cursor_close(ctx, token_cursor);
+ token_cursor = NULL;
+ }
+ return token_cursor;
+}
+
+static int
+grn_token_cursor_next_apply_token_filters(grn_ctx *ctx,
+ grn_token_cursor *token_cursor,
+ grn_obj *current_token_data,
+ grn_obj *status)
+{
+ grn_obj *token_filters = token_cursor->token_filter.objects;
+ unsigned int i, n_token_filters;
+ grn_token current_token;
+ grn_token next_token;
+
+ if (token_filters) {
+ n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
+ } else {
+ n_token_filters = 0;
+ }
+
+ GRN_TEXT_INIT(&(current_token.data), GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, &(current_token.data),
+ GRN_TEXT_VALUE(current_token_data),
+ GRN_TEXT_LEN(current_token_data));
+ current_token.status = GRN_INT32_VALUE(status);
+ GRN_TEXT_INIT(&(next_token.data), GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET(ctx, &(next_token.data),
+ GRN_TEXT_VALUE(&(current_token.data)),
+ GRN_TEXT_LEN(&(current_token.data)));
+ next_token.status = current_token.status;
+
+ for (i = 0; i < n_token_filters; i++) {
+ grn_obj *token_filter_object = GRN_PTR_VALUE_AT(token_filters, i);
+ grn_proc *token_filter = (grn_proc *)token_filter_object;
+ void *data = token_cursor->token_filter.data[i];
+
+#define SKIP_FLAGS\
+ (GRN_TOKEN_SKIP |\
+ GRN_TOKEN_SKIP_WITH_POSITION)
+ if (current_token.status & SKIP_FLAGS) {
+ break;
+ }
+#undef SKIP_FLAGS
+
+ token_filter->callbacks.token_filter.filter(ctx,
+ &current_token,
+ &next_token,
+ data);
+ GRN_TEXT_SET(ctx, &(current_token.data),
+ GRN_TEXT_VALUE(&(next_token.data)),
+ GRN_TEXT_LEN(&(next_token.data)));
+ current_token.status = next_token.status;
+ }
+
+ token_cursor->curr =
+ (const unsigned char *)GRN_TEXT_VALUE(&(current_token.data));
+ token_cursor->curr_size = GRN_TEXT_LEN(&(current_token.data));
+
+ return current_token.status;
+}
+
+grn_id
+grn_token_cursor_next(grn_ctx *ctx, grn_token_cursor *token_cursor)
+{
+ int status;
+ grn_id tid = GRN_ID_NIL;
+ grn_obj *table = token_cursor->table;
+ grn_obj *tokenizer = token_cursor->tokenizer;
+ while (token_cursor->status != GRN_TOKEN_CURSOR_DONE) {
+ if (tokenizer) {
+ grn_obj *curr_, *stat_;
+ ((grn_proc *)tokenizer)->funcs[PROC_NEXT](ctx, 1, &table, &token_cursor->pctx.user_data);
+ stat_ = grn_ctx_pop(ctx);
+ curr_ = grn_ctx_pop(ctx);
+ status = grn_token_cursor_next_apply_token_filters(ctx, token_cursor,
+ curr_, stat_);
+ token_cursor->status =
+ ((status & GRN_TOKEN_LAST) ||
+ (token_cursor->mode == GRN_TOKENIZE_GET &&
+ (status & GRN_TOKEN_REACH_END)))
+ ? GRN_TOKEN_CURSOR_DONE : GRN_TOKEN_CURSOR_DOING;
+ token_cursor->force_prefix = GRN_FALSE;
+#define SKIP_FLAGS \
+ (GRN_TOKEN_SKIP | GRN_TOKEN_SKIP_WITH_POSITION)
+ if (status & SKIP_FLAGS) {
+ if (status & GRN_TOKEN_SKIP) {
+ token_cursor->pos++;
+ }
+ if (token_cursor->status == GRN_TOKEN_CURSOR_DONE && tid == GRN_ID_NIL) {
+ token_cursor->status = GRN_TOKEN_CURSOR_DONE_SKIP;
+ break;
+ } else {
+ continue;
+ }
+ }
+#undef SKIP_FLAGS
+ if (status & GRN_TOKEN_FORCE_PREFIX) {
+ token_cursor->force_prefix = GRN_TRUE;
+ }
+ if (token_cursor->curr_size == 0) {
+ if (token_cursor->status != GRN_TOKEN_CURSOR_DONE) {
+ char tokenizer_name[GRN_TABLE_MAX_KEY_SIZE];
+ int tokenizer_name_length;
+ tokenizer_name_length =
+ grn_obj_name(ctx, token_cursor->tokenizer,
+ tokenizer_name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_LOG(ctx, GRN_WARN,
+ "[token_next] ignore an empty token: <%.*s>: <%.*s>",
+ tokenizer_name_length, tokenizer_name,
+ token_cursor->orig_blen, token_cursor->orig);
+ }
+ continue;
+ }
+ if (token_cursor->curr_size > GRN_TABLE_MAX_KEY_SIZE) {
+ GRN_LOG(ctx, GRN_WARN,
+ "[token_next] ignore too long token. "
+ "Token must be less than or equal to %d: <%d>(<%.*s>)",
+ GRN_TABLE_MAX_KEY_SIZE,
+ token_cursor->curr_size,
+ token_cursor->curr_size, token_cursor->curr);
+ continue;
+ }
+ if (status & GRN_TOKEN_UNMATURED) {
+ if (status & GRN_TOKEN_OVERLAP) {
+ if (token_cursor->mode == GRN_TOKENIZE_GET) {
+ token_cursor->pos++;
+ continue;
+ }
+ } else {
+ if (status & GRN_TOKEN_REACH_END) {
+ token_cursor->force_prefix = GRN_TRUE;
+ }
+ }
+ }
+ } else {
+ token_cursor->status = GRN_TOKEN_CURSOR_DONE;
+ }
+ if (token_cursor->mode == GRN_TOKENIZE_ADD) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ if (grn_io_lock(ctx, ((grn_pat *)table)->io, grn_lock_timeout)) {
+ tid = GRN_ID_NIL;
+ } else {
+ tid = grn_pat_add(ctx, (grn_pat *)table, token_cursor->curr, token_cursor->curr_size,
+ NULL, NULL);
+ grn_io_unlock(((grn_pat *)table)->io);
+ }
+ break;
+ case GRN_TABLE_DAT_KEY :
+ if (grn_io_lock(ctx, ((grn_dat *)table)->io, grn_lock_timeout)) {
+ tid = GRN_ID_NIL;
+ } else {
+ tid = grn_dat_add(ctx, (grn_dat *)table, token_cursor->curr, token_cursor->curr_size,
+ NULL, NULL);
+ grn_io_unlock(((grn_dat *)table)->io);
+ }
+ break;
+ case GRN_TABLE_HASH_KEY :
+ if (grn_io_lock(ctx, ((grn_hash *)table)->io, grn_lock_timeout)) {
+ tid = GRN_ID_NIL;
+ } else {
+ tid = grn_hash_add(ctx, (grn_hash *)table, token_cursor->curr, token_cursor->curr_size,
+ NULL, NULL);
+ grn_io_unlock(((grn_hash *)table)->io);
+ }
+ break;
+ case GRN_TABLE_NO_KEY :
+ if (token_cursor->curr_size == sizeof(grn_id)) {
+ tid = *((grn_id *)token_cursor->curr);
+ } else {
+ tid = GRN_ID_NIL;
+ }
+ break;
+ }
+ } else if (token_cursor->mode != GRN_TOKENIZE_ONLY) {
+ switch (table->header.type) {
+ case GRN_TABLE_PAT_KEY :
+ tid = grn_pat_get(ctx, (grn_pat *)table, token_cursor->curr, token_cursor->curr_size, NULL);
+ break;
+ case GRN_TABLE_DAT_KEY :
+ tid = grn_dat_get(ctx, (grn_dat *)table, token_cursor->curr, token_cursor->curr_size, NULL);
+ break;
+ case GRN_TABLE_HASH_KEY :
+ tid = grn_hash_get(ctx, (grn_hash *)table, token_cursor->curr, token_cursor->curr_size, NULL);
+ break;
+ case GRN_TABLE_NO_KEY :
+ if (token_cursor->curr_size == sizeof(grn_id)) {
+ tid = *((grn_id *)token_cursor->curr);
+ } else {
+ tid = GRN_ID_NIL;
+ }
+ break;
+ }
+ }
+ if (token_cursor->mode != GRN_TOKENIZE_ONLY &&
+ tid == GRN_ID_NIL && token_cursor->status != GRN_TOKEN_CURSOR_DONE) {
+ token_cursor->status = GRN_TOKEN_CURSOR_NOT_FOUND;
+ }
+ token_cursor->pos++;
+ break;
+ }
+ return tid;
+}
+
+static void
+grn_token_cursor_close_token_filters(grn_ctx *ctx,
+ grn_token_cursor *token_cursor)
+{
+ grn_obj *token_filters = token_cursor->token_filter.objects;
+ unsigned int i, n_token_filters;
+
+ if (!token_cursor->token_filter.data) {
+ return;
+ }
+
+ if (token_filters) {
+ n_token_filters = GRN_BULK_VSIZE(token_filters) / sizeof(grn_obj *);
+ } else {
+ n_token_filters = 0;
+ }
+
+ if (n_token_filters == 0) {
+ return;
+ }
+
+ for (i = 0; i < n_token_filters; i++) {
+ grn_obj *token_filter_object = GRN_PTR_VALUE_AT(token_filters, i);
+ grn_proc *token_filter = (grn_proc *)token_filter_object;
+ void *data = token_cursor->token_filter.data[i];
+
+ token_filter->callbacks.token_filter.fin(ctx, data);
+ }
+ GRN_FREE(token_cursor->token_filter.data);
+}
+
+grn_rc
+grn_token_cursor_close(grn_ctx *ctx, grn_token_cursor *token_cursor)
+{
+ if (token_cursor) {
+ if (token_cursor->tokenizer) {
+ ((grn_proc *)token_cursor->tokenizer)->funcs[PROC_FIN](ctx, 1, &token_cursor->table,
+ &token_cursor->pctx.user_data);
+ }
+ grn_token_cursor_close_token_filters(ctx, token_cursor);
+ if (token_cursor->nstr) {
+ grn_obj_close(ctx, token_cursor->nstr);
+ }
+ GRN_FREE(token_cursor);
+ return GRN_SUCCESS;
+ } else {
+ return GRN_INVALID_ARGUMENT;
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/token_filter.c b/storage/mroonga/vendor/groonga/lib/token_filter.c
new file mode 100644
index 00000000..55367762
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/token_filter.c
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+
+#include "grn.h"
+#include "grn_db.h"
+#include <groonga/token_filter.h>
+
+grn_rc
+grn_token_filter_register(grn_ctx *ctx,
+ const char *plugin_name_ptr,
+ int plugin_name_length,
+ grn_token_filter_init_func *init,
+ grn_token_filter_filter_func *filter,
+ grn_token_filter_fin_func *fin)
+{
+ if (plugin_name_length == -1) {
+ plugin_name_length = strlen(plugin_name_ptr);
+ }
+
+ {
+ grn_obj *token_filter_object = grn_proc_create(ctx,
+ plugin_name_ptr,
+ plugin_name_length,
+ GRN_PROC_TOKEN_FILTER,
+ NULL, NULL, NULL, 0, NULL);
+ if (token_filter_object == NULL) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKEN_FILTER_ERROR,
+ "[token-filter][%.*s] failed to grn_proc_create()",
+ plugin_name_length, plugin_name_ptr);
+ return ctx->rc;
+ }
+
+ {
+ grn_proc *token_filter = (grn_proc *)token_filter_object;
+ token_filter->callbacks.token_filter.init = init;
+ token_filter->callbacks.token_filter.filter = filter;
+ token_filter->callbacks.token_filter.fin = fin;
+ }
+ }
+
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/tokenizer.c b/storage/mroonga/vendor/groonga/lib/tokenizer.c
new file mode 100644
index 00000000..67cc8744
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/tokenizer.c
@@ -0,0 +1,377 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include "grn.h"
+#include <groonga/tokenizer.h>
+
+#include <string.h>
+
+#include "grn_ctx.h"
+#include "grn_db.h"
+#include "grn_str.h"
+#include "grn_string.h"
+#include "grn_token_cursor.h"
+
+/*
+ Just for backward compatibility. See grn_plugin_charlen() instead.
+ */
+int
+grn_tokenizer_charlen(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding)
+{
+ return grn_plugin_charlen(ctx, str_ptr, str_length, encoding);
+}
+
+/*
+ Just for backward compatibility. See grn_plugin_isspace() instead.
+ */
+int
+grn_tokenizer_isspace(grn_ctx *ctx, const char *str_ptr,
+ unsigned int str_length, grn_encoding encoding)
+{
+ return grn_plugin_isspace(ctx, str_ptr, str_length, encoding);
+}
+
+grn_bool
+grn_tokenizer_is_tokenized_delimiter(grn_ctx *ctx,
+ const char *str_ptr,
+ unsigned int str_length,
+ grn_encoding encoding)
+{
+ if (encoding != GRN_ENC_UTF8) {
+ return GRN_FALSE;
+ }
+
+ if (str_length != GRN_TOKENIZER_TOKENIZED_DELIMITER_UTF8_LEN) {
+ return GRN_FALSE;
+ }
+
+ return memcmp(str_ptr,
+ GRN_TOKENIZER_TOKENIZED_DELIMITER_UTF8,
+ GRN_TOKENIZER_TOKENIZED_DELIMITER_UTF8_LEN) == 0;
+}
+
+grn_bool
+grn_tokenizer_have_tokenized_delimiter(grn_ctx *ctx,
+ const char *str_ptr,
+ unsigned int str_length,
+ grn_encoding encoding)
+{
+ int char_length;
+ const char *current = str_ptr;
+ const char *end = str_ptr + str_length;
+
+ if (encoding != GRN_ENC_UTF8) {
+ return GRN_FALSE;
+ }
+
+ if (str_length == 0) {
+ return GRN_FALSE;
+ }
+
+ while ((char_length = grn_charlen_(ctx, current, end, encoding)) > 0) {
+ if (grn_tokenizer_is_tokenized_delimiter(ctx,
+ current, char_length,
+ encoding)) {
+ return GRN_TRUE;
+ }
+ current += char_length;
+ }
+ return GRN_FALSE;
+}
+
+grn_tokenizer_query *
+grn_tokenizer_query_open(grn_ctx *ctx, int num_args, grn_obj **args,
+ unsigned int normalize_flags)
+{
+ grn_obj *flags = grn_ctx_pop(ctx);
+ grn_obj *query_str = grn_ctx_pop(ctx);
+ grn_obj *tokenize_mode = grn_ctx_pop(ctx);
+
+ if (query_str == NULL) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "missing argument");
+ return NULL;
+ }
+
+ if ((num_args < 1) || (args == NULL) || (args[0] == NULL)) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT, "invalid NULL pointer");
+ return NULL;
+ }
+
+ {
+ grn_tokenizer_query * const query =
+ GRN_PLUGIN_MALLOC(ctx, sizeof(grn_tokenizer_query));
+ if (query == NULL) {
+ return NULL;
+ }
+ query->normalized_query = NULL;
+ query->query_buf = NULL;
+ if (flags) {
+ query->flags = GRN_UINT32_VALUE(flags);
+ } else {
+ query->flags = 0;
+ }
+ if (tokenize_mode) {
+ query->tokenize_mode = GRN_UINT32_VALUE(tokenize_mode);
+ } else {
+ query->tokenize_mode = GRN_TOKENIZE_ADD;
+ }
+ query->token_mode = query->tokenize_mode;
+
+ {
+ grn_obj * const table = args[0];
+ grn_table_flags table_flags;
+ grn_encoding table_encoding;
+ unsigned int query_length = GRN_TEXT_LEN(query_str);
+ char *query_buf = (char *)GRN_PLUGIN_MALLOC(ctx, query_length + 1);
+ grn_obj *normalizer = NULL;
+
+ if (query_buf == NULL) {
+ GRN_PLUGIN_FREE(ctx, query);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer] failed to duplicate query");
+ return NULL;
+ }
+ grn_table_get_info(ctx, table, &table_flags, &table_encoding, NULL,
+ &normalizer, NULL);
+ {
+ grn_obj *normalized_query;
+ if (table_flags & GRN_OBJ_KEY_NORMALIZE) {
+ normalizer = GRN_NORMALIZER_AUTO;
+ }
+ normalized_query = grn_string_open_(ctx,
+ GRN_TEXT_VALUE(query_str),
+ GRN_TEXT_LEN(query_str),
+ normalizer,
+ normalize_flags,
+ table_encoding);
+ if (!normalized_query) {
+ GRN_PLUGIN_FREE(ctx, query_buf);
+ GRN_PLUGIN_FREE(ctx, query);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer] failed to open normalized string");
+ return NULL;
+ }
+ query->normalized_query = normalized_query;
+ grn_memcpy(query_buf, GRN_TEXT_VALUE(query_str), query_length);
+ query_buf[query_length] = '\0';
+ query->query_buf = query_buf;
+ query->ptr = query_buf;
+ query->length = query_length;
+ }
+ query->encoding = table_encoding;
+
+ if (query->flags & GRN_TOKEN_CURSOR_ENABLE_TOKENIZED_DELIMITER) {
+ const char *normalized_string;
+ unsigned int normalized_string_length;
+
+ grn_string_get_normalized(ctx,
+ query->normalized_query,
+ &normalized_string,
+ &normalized_string_length,
+ NULL);
+ query->have_tokenized_delimiter =
+ grn_tokenizer_have_tokenized_delimiter(ctx,
+ normalized_string,
+ normalized_string_length,
+ query->encoding);
+ } else {
+ query->have_tokenized_delimiter = GRN_FALSE;
+ }
+ }
+ return query;
+ }
+}
+
+grn_tokenizer_query *
+grn_tokenizer_query_create(grn_ctx *ctx, int num_args, grn_obj **args)
+{
+ return grn_tokenizer_query_open(ctx, num_args, args, 0);
+}
+
+void
+grn_tokenizer_query_close(grn_ctx *ctx, grn_tokenizer_query *query)
+{
+ if (query != NULL) {
+ if (query->normalized_query != NULL) {
+ grn_obj_unlink(ctx, query->normalized_query);
+ }
+ if (query->query_buf != NULL) {
+ GRN_PLUGIN_FREE(ctx, query->query_buf);
+ }
+ GRN_PLUGIN_FREE(ctx, query);
+ }
+}
+
+void
+grn_tokenizer_query_destroy(grn_ctx *ctx, grn_tokenizer_query *query)
+{
+ grn_tokenizer_query_close(ctx, query);
+}
+
+void
+grn_tokenizer_token_init(grn_ctx *ctx, grn_tokenizer_token *token)
+{
+ GRN_TEXT_INIT(&token->str, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_UINT32_INIT(&token->status, 0);
+}
+
+void
+grn_tokenizer_token_fin(grn_ctx *ctx, grn_tokenizer_token *token)
+{
+ GRN_OBJ_FIN(ctx, &(token->str));
+ GRN_OBJ_FIN(ctx, &(token->status));
+}
+
+void
+grn_tokenizer_token_push(grn_ctx *ctx, grn_tokenizer_token *token,
+ const char *str_ptr, unsigned int str_length,
+ grn_token_status status)
+{
+ GRN_TEXT_SET_REF(&token->str, str_ptr, str_length);
+ GRN_UINT32_SET(ctx, &token->status, status);
+ grn_ctx_push(ctx, &token->str);
+ grn_ctx_push(ctx, &token->status);
+}
+
+const char *
+grn_tokenizer_tokenized_delimiter_next(grn_ctx *ctx,
+ grn_tokenizer_token *token,
+ const char *str_ptr,
+ unsigned int str_length,
+ grn_encoding encoding)
+{
+ size_t char_length = 0;
+ const char *start = str_ptr;
+ const char *current;
+ const char *end = str_ptr + str_length;
+ const char *next_start = NULL;
+ unsigned int token_length;
+ grn_token_status status;
+
+ for (current = start; current < end; current += char_length) {
+ char_length = grn_charlen_(ctx, current, end, encoding);
+ if (char_length == 0) {
+ break;
+ }
+ if (grn_tokenizer_is_tokenized_delimiter(ctx, current, char_length,
+ encoding)) {
+ next_start = str_ptr + (current - start + char_length);
+ break;
+ }
+ }
+
+ token_length = current - start;
+ if (current == end) {
+ status = GRN_TOKENIZER_LAST;
+ } else {
+ status = GRN_TOKENIZER_CONTINUE;
+ }
+ grn_tokenizer_token_push(ctx, token, start, token_length, status);
+
+ return next_start;
+}
+
+grn_rc
+grn_tokenizer_register(grn_ctx *ctx, const char *plugin_name_ptr,
+ unsigned int plugin_name_length,
+ grn_proc_func *init, grn_proc_func *next,
+ grn_proc_func *fin)
+{
+ grn_expr_var vars[3];
+ vars[0].name= NULL;
+ vars[0].name_size= 0;
+ vars[1].name= NULL;
+ vars[1].name_size= 0;
+ vars[2].name= NULL;
+ vars[2].name_size= 0;
+ GRN_TEXT_INIT(&vars[0].value, 0);
+ GRN_TEXT_INIT(&vars[1].value, 0);
+ GRN_UINT32_INIT(&vars[2].value, 0);
+
+ {
+ /*
+ grn_proc_create() registers a plugin to the database which is associated
+ with `ctx'. A returned object must not be finalized here.
+ */
+ grn_obj * const obj = grn_proc_create(ctx, plugin_name_ptr,
+ plugin_name_length,
+ GRN_PROC_TOKENIZER,
+ init, next, fin, 3, vars);
+ if (obj == NULL) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR, "grn_proc_create() failed");
+ return ctx->rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_obj *
+grn_token_get_data(grn_ctx *ctx, grn_token *token)
+{
+ GRN_API_ENTER;
+ if (!token) {
+ ERR(GRN_INVALID_ARGUMENT, "token must not be NULL");
+ GRN_API_RETURN(NULL);
+ }
+ GRN_API_RETURN(&(token->data));
+}
+
+grn_rc
+grn_token_set_data(grn_ctx *ctx,
+ grn_token *token,
+ const char *str_ptr,
+ int str_length)
+{
+ GRN_API_ENTER;
+ if (!token) {
+ ERR(GRN_INVALID_ARGUMENT, "token must not be NULL");
+ goto exit;
+ }
+ if (str_length == -1) {
+ str_length = strlen(str_ptr);
+ }
+ GRN_TEXT_SET(ctx, &(token->data), str_ptr, str_length);
+exit:
+ GRN_API_RETURN(ctx->rc);
+}
+
+grn_token_status
+grn_token_get_status(grn_ctx *ctx, grn_token *token)
+{
+ GRN_API_ENTER;
+ if (!token) {
+ ERR(GRN_INVALID_ARGUMENT, "token must not be NULL");
+ GRN_API_RETURN(GRN_TOKEN_CONTINUE);
+ }
+ GRN_API_RETURN(token->status);
+}
+
+grn_rc
+grn_token_set_status(grn_ctx *ctx,
+ grn_token *token,
+ grn_token_status status)
+{
+ GRN_API_ENTER;
+ if (!token) {
+ ERR(GRN_INVALID_ARGUMENT, "token must not be NULL");
+ goto exit;
+ }
+ token->status = status;
+exit:
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/tokenizers.c b/storage/mroonga/vendor/groonga/lib/tokenizers.c
new file mode 100644
index 00000000..e86ad343
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/tokenizers.c
@@ -0,0 +1,893 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include <string.h>
+#include "grn_token_cursor.h"
+#include "grn_string.h"
+#include "grn_plugin.h"
+#include <groonga/tokenizer.h>
+
+grn_obj *grn_tokenizer_uvector = NULL;
+
+typedef struct {
+ grn_tokenizer_token token;
+ byte *curr;
+ byte *tail;
+ uint32_t unit;
+} grn_uvector_tokenizer;
+
+static grn_obj *
+uvector_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *str, *flags, *mode;
+ grn_uvector_tokenizer *tokenizer;
+ if (!(flags = grn_ctx_pop(ctx))) {
+ ERR(GRN_INVALID_ARGUMENT, "[tokenizer][uvector] missing argument: flags");
+ return NULL;
+ }
+ if (!(str = grn_ctx_pop(ctx))) {
+ ERR(GRN_INVALID_ARGUMENT, "[tokenizer][uvector] missing argument: string");
+ return NULL;
+ }
+ if (!(mode = grn_ctx_pop(ctx))) {
+ ERR(GRN_INVALID_ARGUMENT, "[tokenizer][uvector] missing argument: mode");
+ return NULL;
+ }
+ if (!(tokenizer = GRN_MALLOC(sizeof(grn_uvector_tokenizer)))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][uvector] "
+ "memory allocation to grn_uvector_tokenizer failed");
+ return NULL;
+ }
+ user_data->ptr = tokenizer;
+
+ grn_tokenizer_token_init(ctx, &(tokenizer->token));
+ tokenizer->curr = (byte *)GRN_TEXT_VALUE(str);
+ tokenizer->tail = tokenizer->curr + GRN_TEXT_LEN(str);
+ tokenizer->unit = sizeof(grn_id);
+ return NULL;
+}
+
+static grn_obj *
+uvector_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_uvector_tokenizer *tokenizer = user_data->ptr;
+ byte *p = tokenizer->curr + tokenizer->unit;
+ if (tokenizer->tail < p) {
+ grn_tokenizer_token_push(ctx, &(tokenizer->token),
+ (const char *)tokenizer->curr, 0,
+ GRN_TOKEN_LAST);
+ } else {
+ grn_token_status status;
+ if (tokenizer->tail == p) {
+ status = GRN_TOKEN_LAST;
+ } else {
+ status = GRN_TOKEN_CONTINUE;
+ }
+ grn_tokenizer_token_push(ctx, &(tokenizer->token),
+ (const char *)tokenizer->curr, tokenizer->unit,
+ status);
+ tokenizer->curr = p;
+ }
+ return NULL;
+}
+
+static grn_obj *
+uvector_fin(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_uvector_tokenizer *tokenizer = user_data->ptr;
+ if (!tokenizer) {
+ return NULL;
+ }
+ grn_tokenizer_token_fin(ctx, &(tokenizer->token));
+ GRN_FREE(tokenizer);
+ return NULL;
+}
+
+typedef struct {
+ const uint8_t *delimiter;
+ uint32_t delimiter_len;
+ const unsigned char *next;
+ const unsigned char *end;
+ grn_tokenizer_token token;
+ grn_tokenizer_query *query;
+ grn_bool have_tokenized_delimiter;
+} grn_delimited_tokenizer;
+
+static grn_obj *
+delimited_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data,
+ const uint8_t *delimiter, uint32_t delimiter_len)
+{
+ grn_tokenizer_query *query;
+ unsigned int normalize_flags = 0;
+ const char *normalized;
+ unsigned int normalized_length_in_bytes;
+ grn_delimited_tokenizer *tokenizer;
+
+ query = grn_tokenizer_query_open(ctx, nargs, args, normalize_flags);
+ if (!query) {
+ return NULL;
+ }
+
+ if (!(tokenizer = GRN_MALLOC(sizeof(grn_delimited_tokenizer)))) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][delimit] "
+ "memory allocation to grn_delimited_tokenizer failed");
+ grn_tokenizer_query_close(ctx, query);
+ return NULL;
+ }
+ user_data->ptr = tokenizer;
+
+ tokenizer->query = query;
+
+ tokenizer->have_tokenized_delimiter =
+ grn_tokenizer_have_tokenized_delimiter(ctx,
+ tokenizer->query->ptr,
+ tokenizer->query->length,
+ tokenizer->query->encoding);
+ tokenizer->delimiter = delimiter;
+ tokenizer->delimiter_len = delimiter_len;
+ grn_string_get_normalized(ctx, tokenizer->query->normalized_query,
+ &normalized, &normalized_length_in_bytes,
+ NULL);
+ tokenizer->next = (const unsigned char *)normalized;
+ tokenizer->end = tokenizer->next + normalized_length_in_bytes;
+
+ grn_tokenizer_token_init(ctx, &(tokenizer->token));
+
+ return NULL;
+}
+
+static grn_obj *
+delimited_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_delimited_tokenizer *tokenizer = user_data->ptr;
+
+ if (tokenizer->have_tokenized_delimiter) {
+ unsigned int rest_length;
+ rest_length = tokenizer->end - tokenizer->next;
+ tokenizer->next =
+ (unsigned char *)grn_tokenizer_tokenized_delimiter_next(
+ ctx,
+ &(tokenizer->token),
+ (const char *)tokenizer->next,
+ rest_length,
+ tokenizer->query->encoding);
+ } else {
+ size_t cl;
+ const unsigned char *p = tokenizer->next, *r;
+ const unsigned char *e = tokenizer->end;
+ grn_token_status status;
+ for (r = p; r < e; r += cl) {
+ if (!(cl = grn_charlen_(ctx, (char *)r, (char *)e,
+ tokenizer->query->encoding))) {
+ tokenizer->next = (unsigned char *)e;
+ break;
+ }
+ {
+ grn_bool found_delimiter = GRN_FALSE;
+ const unsigned char *current_end = r;
+ while (current_end + tokenizer->delimiter_len <= e &&
+ !memcmp(current_end,
+ tokenizer->delimiter, tokenizer->delimiter_len)) {
+ current_end += tokenizer->delimiter_len;
+ tokenizer->next = current_end;
+ found_delimiter = GRN_TRUE;
+ }
+ if (found_delimiter) {
+ break;
+ }
+ }
+ }
+ if (r == e) {
+ status = GRN_TOKEN_LAST;
+ } else {
+ status = GRN_TOKEN_CONTINUE;
+ }
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ (const char *)p,
+ r - p,
+ status);
+ }
+
+ return NULL;
+}
+
+static grn_obj *
+delimited_fin(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_delimited_tokenizer *tokenizer = user_data->ptr;
+ if (!tokenizer) {
+ return NULL;
+ }
+ grn_tokenizer_query_close(ctx, tokenizer->query);
+ grn_tokenizer_token_fin(ctx, &(tokenizer->token));
+ GRN_FREE(tokenizer);
+ return NULL;
+}
+
+static grn_obj *
+delimit_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ static const uint8_t delimiter[1] = {' '};
+ return delimited_init(ctx, nargs, args, user_data, delimiter, 1);
+}
+
+static grn_obj *
+delimit_null_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ static const uint8_t delimiter[1] = {'\0'};
+ return delimited_init(ctx, nargs, args, user_data, delimiter, 1);
+}
+
+/* ngram tokenizer */
+
+static grn_bool grn_ngram_tokenizer_remove_blank_disable = GRN_FALSE;
+
+typedef struct {
+ grn_tokenizer_token token;
+ grn_tokenizer_query *query;
+ uint8_t uni_alpha;
+ uint8_t uni_digit;
+ uint8_t uni_symbol;
+ uint8_t ngram_unit;
+ uint8_t ignore_blank;
+ uint8_t overlap;
+ int32_t pos;
+ uint32_t skip;
+ const unsigned char *next;
+ const unsigned char *end;
+ const uint_least8_t *ctypes;
+ uint32_t len;
+ uint32_t tail;
+} grn_ngram_tokenizer;
+
+static grn_obj *
+ngram_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data, uint8_t ngram_unit,
+ uint8_t uni_alpha, uint8_t uni_digit, uint8_t uni_symbol, uint8_t ignore_blank)
+{
+ unsigned int normalize_flags =
+ GRN_STRING_REMOVE_BLANK |
+ GRN_STRING_WITH_TYPES |
+ GRN_STRING_REMOVE_TOKENIZED_DELIMITER;
+ grn_tokenizer_query *query;
+ const char *normalized;
+ unsigned int normalized_length_in_bytes;
+ grn_ngram_tokenizer *tokenizer;
+
+ if (grn_ngram_tokenizer_remove_blank_disable) {
+ normalize_flags &= ~GRN_STRING_REMOVE_BLANK;
+ }
+ query = grn_tokenizer_query_open(ctx, nargs, args, normalize_flags);
+ if (!query) {
+ return NULL;
+ }
+
+ if (!(tokenizer = GRN_MALLOC(sizeof(grn_ngram_tokenizer)))) {
+ grn_tokenizer_query_close(ctx, query);
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][ngram] "
+ "memory allocation to grn_ngram_tokenizer failed");
+ return NULL;
+ }
+ user_data->ptr = tokenizer;
+
+ grn_tokenizer_token_init(ctx, &(tokenizer->token));
+ tokenizer->query = query;
+
+ tokenizer->uni_alpha = uni_alpha;
+ tokenizer->uni_digit = uni_digit;
+ tokenizer->uni_symbol = uni_symbol;
+ tokenizer->ngram_unit = ngram_unit;
+ tokenizer->ignore_blank = ignore_blank;
+ tokenizer->overlap = 0;
+ tokenizer->pos = 0;
+ tokenizer->skip = 0;
+
+ grn_string_get_normalized(ctx, tokenizer->query->normalized_query,
+ &normalized, &normalized_length_in_bytes,
+ &(tokenizer->len));
+ tokenizer->next = (const unsigned char *)normalized;
+ tokenizer->end = tokenizer->next + normalized_length_in_bytes;
+ tokenizer->ctypes =
+ grn_string_get_types(ctx, tokenizer->query->normalized_query);
+ return NULL;
+}
+
+static grn_obj *
+unigram_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 1, 1, 1, 1, 0); }
+
+static grn_obj *
+bigram_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 1, 1, 1, 0); }
+
+static grn_obj *
+trigram_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 3, 1, 1, 1, 0); }
+
+static grn_obj *
+bigrams_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 1, 1, 0, 0); }
+
+static grn_obj *
+bigramsa_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 0, 1, 0, 0); }
+
+static grn_obj *
+bigramsad_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 0, 0, 0, 0); }
+
+static grn_obj *
+bigrami_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 1, 1, 1, 1); }
+
+static grn_obj *
+bigramis_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 1, 1, 0, 1); }
+
+static grn_obj *
+bigramisa_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 0, 1, 0, 1); }
+
+static grn_obj *
+bigramisad_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{ return ngram_init(ctx, nargs, args, user_data, 2, 0, 0, 0, 1); }
+
+static grn_obj *
+ngram_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ size_t cl;
+ grn_ngram_tokenizer *tokenizer = user_data->ptr;
+ const unsigned char *p = tokenizer->next, *r = p, *e = tokenizer->end;
+ int32_t len = 0, pos = tokenizer->pos + tokenizer->skip;
+ grn_token_status status = 0;
+ const uint_least8_t *cp = tokenizer->ctypes ? tokenizer->ctypes + pos : NULL;
+ if (cp && tokenizer->uni_alpha && GRN_STR_CTYPE(*cp) == GRN_CHAR_ALPHA) {
+ while ((cl = grn_charlen_(ctx, (char *)r, (char *)e,
+ tokenizer->query->encoding))) {
+ len++;
+ r += cl;
+ if (/* !tokenizer->ignore_blank && */ GRN_STR_ISBLANK(*cp)) { break; }
+ if (GRN_STR_CTYPE(*++cp) != GRN_CHAR_ALPHA) { break; }
+ }
+ tokenizer->next = r;
+ tokenizer->overlap = 0;
+ } else if (cp &&
+ tokenizer->uni_digit &&
+ GRN_STR_CTYPE(*cp) == GRN_CHAR_DIGIT) {
+ while ((cl = grn_charlen_(ctx, (char *)r, (char *)e,
+ tokenizer->query->encoding))) {
+ len++;
+ r += cl;
+ if (/* !tokenizer->ignore_blank && */ GRN_STR_ISBLANK(*cp)) { break; }
+ if (GRN_STR_CTYPE(*++cp) != GRN_CHAR_DIGIT) { break; }
+ }
+ tokenizer->next = r;
+ tokenizer->overlap = 0;
+ } else if (cp &&
+ tokenizer->uni_symbol &&
+ GRN_STR_CTYPE(*cp) == GRN_CHAR_SYMBOL) {
+ while ((cl = grn_charlen_(ctx, (char *)r, (char *)e,
+ tokenizer->query->encoding))) {
+ len++;
+ r += cl;
+ if (!tokenizer->ignore_blank && GRN_STR_ISBLANK(*cp)) { break; }
+ if (GRN_STR_CTYPE(*++cp) != GRN_CHAR_SYMBOL) { break; }
+ }
+ tokenizer->next = r;
+ tokenizer->overlap = 0;
+ } else {
+#ifdef PRE_DEFINED_UNSPLIT_WORDS
+ const unsigned char *key = NULL;
+ // todo : grn_pat_lcp_search
+ if ((tid = grn_sym_common_prefix_search(sym, p))) {
+ if (!(key = _grn_sym_key(sym, tid))) {
+ tokenizer->status = GRN_TOKEN_CURSOR_NOT_FOUND;
+ return NULL;
+ }
+ len = grn_str_len(key, tokenizer->query->encoding, NULL);
+ }
+ r = p + grn_charlen_(ctx, p, e, tokenizer->query->encoding);
+ if (tid && (len > 1 || r == p)) {
+ if (r != p && pos + len - 1 <= tokenizer->tail) { continue; }
+ p += strlen(key);
+ if (!*p && tokenizer->mode == GRN_TOKEN_GET) {
+ tokenizer->status = GRN_TOKEN_CURSOR_DONE;
+ }
+ }
+#endif /* PRE_DEFINED_UNSPLIT_WORDS */
+ if ((cl = grn_charlen_(ctx, (char *)r, (char *)e,
+ tokenizer->query->encoding))) {
+ len++;
+ r += cl;
+ tokenizer->next = r;
+ while (len < tokenizer->ngram_unit &&
+ (cl = grn_charlen_(ctx, (char *)r, (char *)e,
+ tokenizer->query->encoding))) {
+ if (cp) {
+ if (!tokenizer->ignore_blank && GRN_STR_ISBLANK(*cp)) { break; }
+ cp++;
+ if ((tokenizer->uni_alpha && GRN_STR_CTYPE(*cp) == GRN_CHAR_ALPHA) ||
+ (tokenizer->uni_digit && GRN_STR_CTYPE(*cp) == GRN_CHAR_DIGIT) ||
+ (tokenizer->uni_symbol && GRN_STR_CTYPE(*cp) == GRN_CHAR_SYMBOL)) {
+ break;
+ }
+ }
+ len++;
+ r += cl;
+ }
+ if (tokenizer->overlap) {
+ status |= GRN_TOKEN_OVERLAP;
+ }
+ if (len < tokenizer->ngram_unit) {
+ status |= GRN_TOKEN_UNMATURED;
+ }
+ tokenizer->overlap = (len > 1) ? 1 : 0;
+ }
+ }
+ tokenizer->pos = pos;
+ tokenizer->len = len;
+ tokenizer->tail = pos + len - 1;
+ if (p == r || tokenizer->next == e) {
+ tokenizer->skip = 0;
+ status |= GRN_TOKEN_LAST;
+ } else {
+ tokenizer->skip = tokenizer->overlap ? 1 : len;
+ }
+ if (r == e) { status |= GRN_TOKEN_REACH_END; }
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ (const char *)p,
+ r - p,
+ status);
+ return NULL;
+}
+
+static grn_obj *
+ngram_fin(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_ngram_tokenizer *tokenizer = user_data->ptr;
+ if (!tokenizer) {
+ return NULL;
+ }
+ grn_tokenizer_token_fin(ctx, &(tokenizer->token));
+ grn_tokenizer_query_close(ctx, tokenizer->query);
+ GRN_FREE(tokenizer);
+ return NULL;
+}
+
+/* regexp tokenizer */
+
+typedef struct {
+ grn_tokenizer_token token;
+ grn_tokenizer_query *query;
+ struct {
+ int32_t n_skip_tokens;
+ } get;
+ grn_bool is_begin;
+ grn_bool is_end;
+ grn_bool is_start_token;
+ grn_bool is_overlapping;
+ const char *next;
+ const char *end;
+ unsigned int nth_char;
+ const uint_least8_t *char_types;
+ grn_obj buffer;
+} grn_regexp_tokenizer;
+
+static grn_obj *
+regexp_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ unsigned int normalize_flags = GRN_STRING_WITH_TYPES;
+ grn_tokenizer_query *query;
+ const char *normalized;
+ unsigned int normalized_length_in_bytes;
+ grn_regexp_tokenizer *tokenizer;
+
+ query = grn_tokenizer_query_open(ctx, nargs, args, normalize_flags);
+ if (!query) {
+ return NULL;
+ }
+
+ tokenizer = GRN_MALLOC(sizeof(grn_regexp_tokenizer));
+ if (!tokenizer) {
+ grn_tokenizer_query_close(ctx, query);
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][regexp] failed to allocate memory");
+ return NULL;
+ }
+ user_data->ptr = tokenizer;
+
+ grn_tokenizer_token_init(ctx, &(tokenizer->token));
+ tokenizer->query = query;
+
+ tokenizer->get.n_skip_tokens = 0;
+
+ tokenizer->is_begin = GRN_TRUE;
+ tokenizer->is_end = GRN_FALSE;
+ tokenizer->is_start_token = GRN_TRUE;
+ tokenizer->is_overlapping = GRN_FALSE;
+
+ grn_string_get_normalized(ctx, tokenizer->query->normalized_query,
+ &normalized, &normalized_length_in_bytes,
+ NULL);
+ tokenizer->next = normalized;
+ tokenizer->end = tokenizer->next + normalized_length_in_bytes;
+ tokenizer->nth_char = 0;
+ tokenizer->char_types =
+ grn_string_get_types(ctx, tokenizer->query->normalized_query);
+
+ GRN_TEXT_INIT(&(tokenizer->buffer), 0);
+
+ return NULL;
+}
+
+static grn_obj *
+regexp_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ int char_len;
+ grn_token_status status = 0;
+ grn_regexp_tokenizer *tokenizer = user_data->ptr;
+ unsigned int n_characters = 0;
+ int ngram_unit = 2;
+ grn_obj *buffer = &(tokenizer->buffer);
+ const char *current = tokenizer->next;
+ const char *end = tokenizer->end;
+ const uint_least8_t *char_types = tokenizer->char_types;
+ grn_tokenize_mode mode = tokenizer->query->tokenize_mode;
+ grn_bool is_begin = tokenizer->is_begin;
+ grn_bool is_start_token = tokenizer->is_start_token;
+ grn_bool break_by_blank = GRN_FALSE;
+ grn_bool break_by_end_mark = GRN_FALSE;
+
+ GRN_BULK_REWIND(buffer);
+ tokenizer->is_begin = GRN_FALSE;
+ tokenizer->is_start_token = GRN_FALSE;
+
+ if (char_types) {
+ char_types += tokenizer->nth_char;
+ }
+
+ if (mode != GRN_TOKEN_GET) {
+ if (is_begin) {
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ GRN_TOKENIZER_BEGIN_MARK_UTF8,
+ GRN_TOKENIZER_BEGIN_MARK_UTF8_LEN,
+ status);
+ return NULL;
+ }
+
+ if (tokenizer->is_end) {
+ status |= GRN_TOKEN_LAST | GRN_TOKEN_REACH_END;
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ GRN_TOKENIZER_END_MARK_UTF8,
+ GRN_TOKENIZER_END_MARK_UTF8_LEN,
+ status);
+ return NULL;
+ }
+ if (is_start_token) {
+ if (char_types && GRN_STR_ISBLANK(char_types[-1])) {
+ status |= GRN_TOKEN_SKIP;
+ grn_tokenizer_token_push(ctx, &(tokenizer->token), "", 0, status);
+ return NULL;
+ }
+ }
+ }
+
+ char_len = grn_charlen_(ctx, current, end, tokenizer->query->encoding);
+ if (char_len == 0) {
+ status |= GRN_TOKEN_LAST | GRN_TOKEN_REACH_END;
+ grn_tokenizer_token_push(ctx, &(tokenizer->token), "", 0, status);
+ return NULL;
+ }
+
+ if (mode == GRN_TOKEN_GET) {
+ if (is_begin &&
+ char_len == GRN_TOKENIZER_BEGIN_MARK_UTF8_LEN &&
+ memcmp(current, GRN_TOKENIZER_BEGIN_MARK_UTF8, char_len) == 0) {
+ tokenizer->is_start_token = GRN_TRUE;
+ n_characters++;
+ GRN_TEXT_PUT(ctx, buffer, current, char_len);
+ current += char_len;
+ tokenizer->next = current;
+ tokenizer->nth_char++;
+ if (current == end) {
+ status |= GRN_TOKEN_LAST | GRN_TOKEN_REACH_END;
+ }
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ GRN_TOKENIZER_BEGIN_MARK_UTF8,
+ GRN_TOKENIZER_BEGIN_MARK_UTF8_LEN,
+ status);
+ return NULL;
+ }
+
+ if (current + char_len == end &&
+ char_len == GRN_TOKENIZER_END_MARK_UTF8_LEN &&
+ memcmp(current, GRN_TOKENIZER_END_MARK_UTF8, char_len) == 0) {
+ status |= GRN_TOKEN_LAST | GRN_TOKEN_REACH_END;
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ GRN_TOKENIZER_END_MARK_UTF8,
+ GRN_TOKENIZER_END_MARK_UTF8_LEN,
+ status);
+ return NULL;
+ }
+ }
+
+ while (GRN_TRUE) {
+ n_characters++;
+ GRN_TEXT_PUT(ctx, buffer, current, char_len);
+ current += char_len;
+ if (n_characters == 1) {
+ tokenizer->next = current;
+ tokenizer->nth_char++;
+ }
+
+ if (char_types) {
+ uint_least8_t char_type;
+ char_type = char_types[0];
+ char_types++;
+ if (GRN_STR_ISBLANK(char_type)) {
+ break_by_blank = GRN_TRUE;
+ }
+ }
+
+ char_len = grn_charlen_(ctx, (const char *)current, (const char *)end,
+ tokenizer->query->encoding);
+ if (char_len == 0) {
+ break;
+ }
+
+ if (mode == GRN_TOKEN_GET &&
+ current + char_len == end &&
+ char_len == GRN_TOKENIZER_END_MARK_UTF8_LEN &&
+ memcmp(current, GRN_TOKENIZER_END_MARK_UTF8, char_len) == 0) {
+ break_by_end_mark = GRN_TRUE;
+ }
+
+ if (break_by_blank || break_by_end_mark) {
+ break;
+ }
+
+ if (n_characters == (uint) ngram_unit) {
+ break;
+ }
+ }
+
+ if (tokenizer->is_overlapping) {
+ status |= GRN_TOKEN_OVERLAP;
+ }
+ if (n_characters < (uint) ngram_unit) {
+ status |= GRN_TOKEN_UNMATURED;
+ }
+ tokenizer->is_overlapping = (n_characters > 1);
+
+ if (mode == GRN_TOKEN_GET) {
+ if (current == end) {
+ tokenizer->is_end = GRN_TRUE;
+ status |= GRN_TOKEN_LAST | GRN_TOKEN_REACH_END;
+ if (status & GRN_TOKEN_UNMATURED) {
+ status |= GRN_TOKEN_FORCE_PREFIX;
+ }
+ } else {
+ if (break_by_blank) {
+ tokenizer->get.n_skip_tokens = 0;
+ tokenizer->is_start_token = GRN_TRUE;
+ } else if (break_by_end_mark) {
+ if (!is_start_token && (status & GRN_TOKEN_UNMATURED)) {
+ status |= GRN_TOKEN_SKIP;
+ }
+ } else if (tokenizer->get.n_skip_tokens > 0) {
+ tokenizer->get.n_skip_tokens--;
+ status |= GRN_TOKEN_SKIP;
+ } else {
+ tokenizer->get.n_skip_tokens = ngram_unit - 1;
+ }
+ }
+ } else {
+ if (tokenizer->next == end) {
+ tokenizer->is_end = GRN_TRUE;
+ }
+ if (break_by_blank) {
+ tokenizer->is_start_token = GRN_TRUE;
+ }
+ }
+
+ grn_tokenizer_token_push(ctx,
+ &(tokenizer->token),
+ GRN_TEXT_VALUE(buffer),
+ GRN_TEXT_LEN(buffer),
+ status);
+
+ return NULL;
+}
+
+static grn_obj *
+regexp_fin(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_regexp_tokenizer *tokenizer = user_data->ptr;
+ if (!tokenizer) {
+ return NULL;
+ }
+ grn_tokenizer_token_fin(ctx, &(tokenizer->token));
+ grn_tokenizer_query_close(ctx, tokenizer->query);
+ GRN_OBJ_FIN(ctx, &(tokenizer->buffer));
+ GRN_FREE(tokenizer);
+ return NULL;
+}
+
+/* external */
+
+grn_rc
+grn_tokenizers_init(void)
+{
+ static grn_proc _grn_tokenizer_uvector;
+ _grn_tokenizer_uvector.obj.db = NULL;
+ _grn_tokenizer_uvector.obj.id = GRN_ID_NIL;
+ _grn_tokenizer_uvector.obj.header.domain = GRN_ID_NIL;
+ _grn_tokenizer_uvector.obj.range = GRN_ID_NIL;
+ _grn_tokenizer_uvector.funcs[PROC_INIT] = uvector_init;
+ _grn_tokenizer_uvector.funcs[PROC_NEXT] = uvector_next;
+ _grn_tokenizer_uvector.funcs[PROC_FIN] = uvector_fin;
+ grn_tokenizer_uvector = (grn_obj *)&_grn_tokenizer_uvector;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_tokenizers_fin(void)
+{
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_db_init_mecab_tokenizer(grn_ctx *ctx)
+{
+ switch (GRN_CTX_GET_ENCODING(ctx)) {
+ case GRN_ENC_EUC_JP :
+ case GRN_ENC_UTF8 :
+ case GRN_ENC_SJIS :
+#if defined(GRN_EMBEDDED) && defined(GRN_WITH_MECAB)
+ {
+ GRN_PLUGIN_DECLARE_FUNCTIONS(tokenizers_mecab);
+ grn_rc rc;
+ rc = GRN_PLUGIN_IMPL_NAME_TAGGED(init, tokenizers_mecab)(ctx);
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_PLUGIN_IMPL_NAME_TAGGED(register, tokenizers_mecab)(ctx);
+ if (rc != GRN_SUCCESS) {
+ GRN_PLUGIN_IMPL_NAME_TAGGED(fin, tokenizers_mecab)(ctx);
+ }
+ }
+ return rc;
+ }
+#else /* defined(GRN_EMBEDDED) && defined(GRN_WITH_MECAB) */
+ {
+ const char *mecab_plugin_name = "tokenizers/mecab";
+ char *path;
+ path = grn_plugin_find_path(ctx, mecab_plugin_name);
+ if (path) {
+ GRN_FREE(path);
+ return grn_plugin_register(ctx, mecab_plugin_name);
+ } else {
+ return GRN_NO_SUCH_FILE_OR_DIRECTORY;
+ }
+ }
+#endif /* defined(GRN_EMBEDDED) && defined(GRN_WITH_MECAB) */
+ break;
+ default :
+ return GRN_OPERATION_NOT_SUPPORTED;
+ }
+}
+
+void
+grn_db_fin_mecab_tokenizer(grn_ctx *ctx)
+{
+ switch (GRN_CTX_GET_ENCODING(ctx)) {
+ case GRN_ENC_EUC_JP :
+ case GRN_ENC_UTF8 :
+ case GRN_ENC_SJIS :
+#if defined(GRN_EMBEDDED) && defined(GRN_WITH_MECAB)
+ {
+ GRN_PLUGIN_DECLARE_FUNCTIONS(tokenizers_mecab);
+ GRN_PLUGIN_IMPL_NAME_TAGGED(fin, tokenizers_mecab)(ctx);
+ }
+#else /* defined(GRN_EMBEDDED) && defined(GRN_WITH_MECAB) */
+ {
+ const char *mecab_plugin_name = "tokenizers/mecab";
+ char *path;
+ path = grn_plugin_find_path(ctx, mecab_plugin_name);
+ if (path) {
+ GRN_FREE(path);
+ grn_plugin_unregister(ctx, mecab_plugin_name);
+ }
+ }
+#endif /* defined(GRN_EMBEDDED) && defined(GRN_WITH_MECAB) */
+ break;
+ default :
+ break;
+ }
+ return;
+}
+
+#define DEF_TOKENIZER(name, init, next, fin, vars)\
+ (grn_proc_create(ctx, (name), (sizeof(name) - 1),\
+ GRN_PROC_TOKENIZER, (init), (next), (fin), 3, (vars)))
+
+grn_rc
+grn_db_init_builtin_tokenizers(grn_ctx *ctx)
+{
+ grn_obj *obj;
+ grn_expr_var vars[3];
+ vars[0].name= NULL;
+ vars[0].name_size= 0;
+ vars[1].name= NULL;
+ vars[1].name_size= 0;
+ vars[2].name= NULL;
+ vars[2].name_size= 0;
+
+ GRN_TEXT_INIT(&vars[0].value, 0);
+ GRN_TEXT_INIT(&vars[1].value, 0);
+ GRN_UINT32_INIT(&vars[2].value, 0);
+
+ {
+ char grn_ngram_tokenizer_remove_blank_disable_env[GRN_ENV_BUFFER_SIZE];
+
+ grn_getenv("GRN_NGRAM_TOKENIZER_REMOVE_BLANK_DISABLE",
+ grn_ngram_tokenizer_remove_blank_disable_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (grn_ngram_tokenizer_remove_blank_disable_env[0]) {
+ grn_ngram_tokenizer_remove_blank_disable = GRN_TRUE;
+ }
+ }
+
+ obj = DEF_TOKENIZER("TokenDelimit",
+ delimit_init, delimited_next, delimited_fin, vars);
+ if (!obj || ((grn_db_obj *)obj)->id != GRN_DB_DELIMIT) { return GRN_FILE_CORRUPT; }
+ obj = DEF_TOKENIZER("TokenUnigram",
+ unigram_init, ngram_next, ngram_fin, vars);
+ if (!obj || ((grn_db_obj *)obj)->id != GRN_DB_UNIGRAM) { return GRN_FILE_CORRUPT; }
+ obj = DEF_TOKENIZER("TokenBigram",
+ bigram_init, ngram_next, ngram_fin, vars);
+ if (!obj || ((grn_db_obj *)obj)->id != GRN_DB_BIGRAM) { return GRN_FILE_CORRUPT; }
+ obj = DEF_TOKENIZER("TokenTrigram",
+ trigram_init, ngram_next, ngram_fin, vars);
+ if (!obj || ((grn_db_obj *)obj)->id != GRN_DB_TRIGRAM) { return GRN_FILE_CORRUPT; }
+
+ DEF_TOKENIZER("TokenBigramSplitSymbol",
+ bigrams_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenBigramSplitSymbolAlpha",
+ bigramsa_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenBigramSplitSymbolAlphaDigit",
+ bigramsad_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenBigramIgnoreBlank",
+ bigrami_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenBigramIgnoreBlankSplitSymbol",
+ bigramis_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenBigramIgnoreBlankSplitSymbolAlpha",
+ bigramisa_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenBigramIgnoreBlankSplitSymbolAlphaDigit",
+ bigramisad_init, ngram_next, ngram_fin, vars);
+ DEF_TOKENIZER("TokenDelimitNull",
+ delimit_null_init, delimited_next, delimited_fin, vars);
+ DEF_TOKENIZER("TokenRegexp",
+ regexp_init, regexp_next, regexp_fin, vars);
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts.c b/storage/mroonga/vendor/groonga/lib/ts.c
new file mode 100644
index 00000000..909f4864
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts.c
@@ -0,0 +1,906 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/* TS is an acronym for "Turbo Selector". */
+
+#include "grn_ts.h"
+
+#include "grn_output.h"
+#include "grn_str.h"
+
+#include "ts/ts_buf.h"
+#include "ts/ts_cursor.h"
+#include "ts/ts_expr.h"
+#include "ts/ts_expr_parser.h"
+#include "ts/ts_log.h"
+#include "ts/ts_sorter.h"
+#include "ts/ts_str.h"
+#include "ts/ts_types.h"
+#include "ts/ts_util.h"
+
+#include <string.h>
+
+/*-------------------------------------------------------------
+ * Miscellaneous.
+ */
+
+enum { GRN_TS_BATCH_SIZE = 1024 };
+
+/* grn_ts_bool_output() outputs a value. */
+static grn_rc
+grn_ts_bool_output(grn_ctx *ctx, grn_ts_bool value)
+{
+ if (value) {
+ return grn_bulk_write(ctx, ctx->impl->output.buf, "true", 4);
+ } else {
+ return grn_bulk_write(ctx, ctx->impl->output.buf, "false", 5);
+ }
+}
+
+/* grn_ts_int_output() outputs a value. */
+static grn_rc
+grn_ts_int_output(grn_ctx *ctx, grn_ts_int value)
+{
+ return grn_text_lltoa(ctx, ctx->impl->output.buf, value);
+}
+
+/* grn_ts_float_output() outputs a value. */
+static grn_rc
+grn_ts_float_output(grn_ctx *ctx, grn_ts_float value)
+{
+ return grn_text_ftoa(ctx, ctx->impl->output.buf, value);
+}
+
+/* grn_ts_time_output() outputs a value. */
+static grn_rc
+grn_ts_time_output(grn_ctx *ctx, grn_ts_time value)
+{
+ return grn_text_ftoa(ctx, ctx->impl->output.buf, value * 0.000001);
+}
+
+/* grn_ts_text_output() outputs a value. */
+static grn_rc
+grn_ts_text_output(grn_ctx *ctx, grn_ts_text value)
+{
+ return grn_text_esc(ctx, ctx->impl->output.buf, value.ptr, value.size);
+}
+
+/* grn_ts_geo_output() outputs a value. */
+static grn_rc
+grn_ts_geo_output(grn_ctx *ctx, grn_ts_geo value)
+{
+ grn_rc rc = grn_bulk_write(ctx, ctx->impl->output.buf, "\"", 1);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_text_itoa(ctx, ctx->impl->output.buf, value.latitude);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_bulk_write(ctx, ctx->impl->output.buf, "x", 1);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_text_itoa(ctx, ctx->impl->output.buf, value.longitude);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ return grn_bulk_write(ctx, ctx->impl->output.buf, "\"", 1);
+}
+
+#define GRN_TS_VECTOR_OUTPUT(kind)\
+ size_t i;\
+ grn_rc rc = grn_bulk_write(ctx, ctx->impl->output.buf, "[", 1);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ for (i = 0; i < value.size; ++i) {\
+ if (i) {\
+ rc = grn_bulk_write(ctx, ctx->impl->output.buf, ",", 1);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ rc = grn_ts_ ## kind ## _output(ctx, value.ptr[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ return grn_bulk_write(ctx, ctx->impl->output.buf, "]", 1);
+/* grn_ts_bool_vector_output() outputs a value. */
+static grn_rc
+grn_ts_bool_vector_output(grn_ctx *ctx, grn_ts_bool_vector value)
+{
+ GRN_TS_VECTOR_OUTPUT(bool)
+}
+
+/* grn_ts_int_vector_output() outputs a value. */
+static grn_rc
+grn_ts_int_vector_output(grn_ctx *ctx, grn_ts_int_vector value)
+{
+ GRN_TS_VECTOR_OUTPUT(int)
+}
+
+/* grn_ts_float_vector_output() outputs a value. */
+static grn_rc
+grn_ts_float_vector_output(grn_ctx *ctx, grn_ts_float_vector value)
+{
+ GRN_TS_VECTOR_OUTPUT(float)
+}
+
+/* grn_ts_time_vector_output() outputs a value. */
+static grn_rc
+grn_ts_time_vector_output(grn_ctx *ctx, grn_ts_time_vector value)
+{
+ GRN_TS_VECTOR_OUTPUT(time)
+}
+
+/* grn_ts_text_vector_output() outputs a value. */
+static grn_rc
+grn_ts_text_vector_output(grn_ctx *ctx, grn_ts_text_vector value)
+{
+ GRN_TS_VECTOR_OUTPUT(text)
+}
+
+/* grn_ts_geo_vector_output() outputs a value. */
+static grn_rc
+grn_ts_geo_vector_output(grn_ctx *ctx, grn_ts_geo_vector value)
+{
+ GRN_TS_VECTOR_OUTPUT(geo)
+}
+#undef GRN_TS_VECTOR_OUTPUT
+
+/*-------------------------------------------------------------
+ * grn_ts_writer.
+ */
+
+typedef struct {
+ grn_ts_expr_parser *parser;
+ grn_ts_expr **exprs;
+ size_t n_exprs;
+ size_t max_n_exprs;
+ grn_obj name_buf;
+ grn_ts_str *names;
+ grn_ts_buf *bufs;
+} grn_ts_writer;
+
+/* grn_ts_writer_init() initializes a writer. */
+static void
+grn_ts_writer_init(grn_ctx *ctx, grn_ts_writer *writer)
+{
+ memset(writer, 0, sizeof(*writer));
+ writer->parser = NULL;
+ writer->exprs = NULL;
+ GRN_TEXT_INIT(&writer->name_buf, GRN_OBJ_VECTOR);
+ writer->names = NULL;
+ writer->bufs = NULL;
+}
+
+/* grn_ts_writer_fin() finalizes a writer. */
+static void
+grn_ts_writer_fin(grn_ctx *ctx, grn_ts_writer *writer)
+{
+ size_t i;
+ if (writer->bufs) {
+ for (i = 0; i < writer->n_exprs; i++) {
+ grn_ts_buf_fin(ctx, &writer->bufs[i]);
+ }
+ GRN_FREE(writer->bufs);
+ }
+ if (writer->names) {
+ GRN_FREE(writer->names);
+ }
+ GRN_OBJ_FIN(ctx, &writer->name_buf);
+ if (writer->exprs) {
+ for (i = 0; i < writer->n_exprs; i++) {
+ grn_ts_expr_close(ctx, writer->exprs[i]);
+ }
+ GRN_FREE(writer->exprs);
+ }
+ if (writer->parser) {
+ grn_ts_expr_parser_close(ctx, writer->parser);
+ }
+}
+
+/* grn_ts_writer_expand() expands a wildcard. */
+static grn_rc
+grn_ts_writer_expand(grn_ctx *ctx, grn_ts_writer *writer,
+ grn_obj *table, grn_ts_str str)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_hash_cursor *cursor;
+ grn_hash *hash = grn_hash_create(ctx, NULL, sizeof(grn_ts_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_HASH_TINY);
+ if (!hash) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ grn_table_columns(ctx, table, str.ptr, str.size - 1, (grn_obj *)hash);
+ if (ctx->rc != GRN_SUCCESS) {
+ return ctx->rc;
+ }
+ cursor = grn_hash_cursor_open(ctx, hash, NULL, 0, NULL, 0, 0, -1, 0);
+ if (!cursor) {
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ while (grn_hash_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+ size_t name_size;
+ grn_obj *column;
+ grn_ts_id *column_id;
+ if (!grn_hash_cursor_get_key(ctx, cursor, (void **)&column_id)) {
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ }
+ column = grn_ctx_at(ctx, *column_id);
+ if (!column) {
+ rc = GRN_INVALID_ARGUMENT;
+ break;
+ }
+ name_size = grn_column_name(ctx, column, name_buf, sizeof(name_buf));
+ grn_obj_unlink(ctx, column);
+ rc = grn_vector_add_element(ctx, &writer->name_buf,
+ name_buf, name_size, 0, GRN_DB_TEXT);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ grn_hash_cursor_close(ctx, cursor);
+ }
+ grn_hash_close(ctx, hash);
+ return rc;
+}
+
+/* grn_ts_writer_parse() parses output expressions. */
+static grn_rc
+grn_ts_writer_parse(grn_ctx *ctx, grn_ts_writer *writer,
+ grn_obj *table, grn_ts_str str)
+{
+ grn_rc rc;
+ grn_ts_str rest = str;
+ rc = grn_ts_expr_parser_open(ctx, table, &writer->parser);
+ for ( ; ; ) {
+ grn_ts_str first = { NULL, 0 };
+ rc = grn_ts_expr_parser_split(ctx, writer->parser, rest, &first, &rest);
+ if (rc != GRN_SUCCESS) {
+ return (rc == GRN_END_OF_DATA) ? GRN_SUCCESS : rc;
+ }
+ if ((first.ptr[first.size - 1] == '*') &&
+ grn_ts_str_is_name_prefix((grn_ts_str){ first.ptr, first.size - 1 })) {
+ rc = grn_ts_writer_expand(ctx, writer, table, first);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ } else if (grn_ts_str_is_key_name(first) &&
+ !grn_ts_table_has_key(ctx, table)) {
+ /*
+ * Skip _key if the table has no _key, because the default output_columns
+ * option contains _key.
+ */
+ GRN_TS_DEBUG("skip \"_key\" because the table has no _key");
+ } else {
+ rc = grn_vector_add_element(ctx, &writer->name_buf,
+ first.ptr, first.size, 0, GRN_DB_TEXT);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_writer_build() builds output expresions. */
+static grn_rc
+grn_ts_writer_build(grn_ctx *ctx, grn_ts_writer *writer, grn_obj *table)
+{
+ size_t i, n_names = grn_vector_size(ctx, &writer->name_buf);
+ if (!n_names) {
+ return GRN_SUCCESS;
+ }
+ writer->names = GRN_MALLOCN(grn_ts_str, n_names);
+ if (!writer->names) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
+ sizeof(grn_ts_str), n_names);
+ }
+ writer->exprs = GRN_MALLOCN(grn_ts_expr *, n_names);
+ if (!writer->exprs) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
+ sizeof(grn_ts_expr *), n_names);
+ }
+ for (i = 0; i < n_names; i++) {
+ grn_rc rc;
+ grn_ts_expr *new_expr;
+ const char *name_ptr;
+ size_t name_size = grn_vector_get_element(ctx, &writer->name_buf, i,
+ &name_ptr, NULL, NULL);
+ rc = grn_ts_expr_parser_parse(ctx, writer->parser,
+ (grn_ts_str){ name_ptr, name_size },
+ &new_expr);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ writer->names[i].ptr = name_ptr;
+ writer->names[i].size = name_size;
+ writer->exprs[i] = new_expr;
+ writer->n_exprs++;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_writer_open() creates a writer. */
+static grn_rc
+grn_ts_writer_open(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
+ grn_ts_writer **writer)
+{
+ grn_rc rc;
+ grn_ts_writer *new_writer = GRN_MALLOCN(grn_ts_writer, 1);
+ if (!new_writer) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_writer));
+ }
+ grn_ts_writer_init(ctx, new_writer);
+ rc = grn_ts_writer_parse(ctx, new_writer, table, str);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_writer_build(ctx, new_writer, table);
+ }
+ if (rc != GRN_SUCCESS) {
+ grn_ts_writer_fin(ctx, new_writer);
+ GRN_FREE(new_writer);
+ return rc;
+ }
+ *writer = new_writer;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_writer_close() destroys a writer. */
+static void
+grn_ts_writer_close(grn_ctx *ctx, grn_ts_writer *writer)
+{
+ grn_ts_writer_fin(ctx, writer);
+ GRN_FREE(writer);
+}
+
+/* TODO: Errors of output macros, such as GRN_TEXT_*(), are ignored. */
+
+#define GRN_TS_WRITER_OUTPUT_HEADER_CASE(TYPE, name)\
+ case GRN_DB_ ## TYPE: {\
+ GRN_TEXT_PUTS(ctx, ctx->impl->output.buf, name);\
+ break;\
+ }
+/* grn_ts_writer_output_header() outputs names and data types. */
+static grn_rc
+grn_ts_writer_output_header(grn_ctx *ctx, grn_ts_writer *writer)
+{
+ grn_rc rc;
+ GRN_OUTPUT_ARRAY_OPEN("COLUMNS", writer->n_exprs);
+ for (size_t i = 0; i < writer->n_exprs; ++i) {
+ GRN_OUTPUT_ARRAY_OPEN("COLUMN", 2);
+ rc = grn_text_esc(ctx, ctx->impl->output.buf,
+ writer->names[i].ptr, writer->names[i].size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ GRN_TEXT_PUT(ctx, ctx->impl->output.buf, ",\"", 2);
+ switch (writer->exprs[i]->data_type) {
+ case GRN_DB_VOID: {
+ if (writer->exprs[i]->data_kind == GRN_TS_GEO) {
+ GRN_TEXT_PUTS(ctx, ctx->impl->output.buf, "GeoPoint");
+ } else {
+ GRN_TEXT_PUTS(ctx, ctx->impl->output.buf, "Void");
+ }
+ break;
+ }
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(BOOL, "Bool")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT8, "Int8")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT16, "Int16")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT32, "Int32")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(INT64, "Int64")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT8, "UInt8")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT16, "UInt16")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT32, "UInt32")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(UINT64, "UInt64")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(FLOAT, "Float")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(TIME, "Time")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(SHORT_TEXT, "ShortText")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(TEXT, "Text")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(LONG_TEXT, "LongText")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(TOKYO_GEO_POINT, "TokyoGeoPoint")
+ GRN_TS_WRITER_OUTPUT_HEADER_CASE(WGS84_GEO_POINT, "WGS84GeoPoint")
+ default: {
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+ size_t name_size;
+ grn_obj *obj = grn_ctx_at(ctx, writer->exprs[i]->data_type);
+ if (!obj) {
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d",
+ writer->exprs[i]->data_type);
+ }
+ if (!grn_ts_obj_is_table(ctx, obj)) {
+ grn_obj_unlink(ctx, obj);
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d",
+ writer->exprs[i]->data_type);
+ }
+ name_size = grn_obj_name(ctx, obj, name_buf, sizeof(name_buf));
+ GRN_TEXT_PUT(ctx, ctx->impl->output.buf, name_buf, name_size);
+ grn_obj_unlink(ctx, obj);
+ break;
+ }
+ }
+ GRN_TEXT_PUTC(ctx, ctx->impl->output.buf, '"');
+ GRN_OUTPUT_ARRAY_CLOSE();
+ }
+ GRN_OUTPUT_ARRAY_CLOSE(); /* COLUMNS. */
+ return GRN_SUCCESS;
+}
+#undef GRN_TS_WRITER_OUTPUT_HEADER_CASE
+
+#define GRN_TS_WRITER_OUTPUT_BODY_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *value = (grn_ts_ ## kind *)writer->bufs[j].ptr;\
+ grn_ts_ ## kind ## _output(ctx, value[i]);\
+ break;\
+ }
+#define GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(KIND, kind)\
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(KIND ## _VECTOR, kind ## _vector)
+/*
+ * grn_ts_writer_output_body() evaluates expressions and outputs the results.
+ */
+static grn_rc
+grn_ts_writer_output_body(grn_ctx *ctx, grn_ts_writer *writer,
+ const grn_ts_record *in, size_t n_in)
+{
+ size_t i, j, count = 0;
+ writer->bufs = GRN_MALLOCN(grn_ts_buf, writer->n_exprs);
+ if (!writer->bufs) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
+ sizeof(grn_ts_buf), writer->n_exprs);
+ }
+ for (i = 0; i < writer->n_exprs; i++) {
+ grn_ts_buf_init(ctx, &writer->bufs[i]);
+ }
+ while (count < n_in) {
+ size_t batch_size = GRN_TS_BATCH_SIZE;
+ if (batch_size > (n_in - count)) {
+ batch_size = n_in - count;
+ }
+ for (i = 0; i < writer->n_exprs; ++i) {
+ grn_rc rc = grn_ts_expr_evaluate_to_buf(ctx, writer->exprs[i], in + count,
+ batch_size, &writer->bufs[i]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ for (i = 0; i < batch_size; ++i) {
+ GRN_OUTPUT_ARRAY_OPEN("HIT", writer->n_exprs);
+ for (j = 0; j < writer->n_exprs; ++j) {
+ if (j) {
+ GRN_TEXT_PUTC(ctx, ctx->impl->output.buf, ',');
+ }
+ switch (writer->exprs[j]->data_kind) {
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(BOOL, bool);
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(INT, int);
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(FLOAT, float);
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(TIME, time);
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(TEXT, text);
+ GRN_TS_WRITER_OUTPUT_BODY_CASE(GEO, geo);
+ GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(BOOL, bool);
+ GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(INT, int);
+ GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(FLOAT, float);
+ GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TIME, time);
+ GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(TEXT, text);
+ GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE(GEO, geo);
+ default: {
+ break;
+ }
+ }
+ }
+ GRN_OUTPUT_ARRAY_CLOSE(); /* HITS. */
+ }
+ count += batch_size;
+ }
+ return GRN_SUCCESS;
+}
+#undef GRN_TS_WRITER_OUTPUT_BODY_VECTOR_CASE
+#undef GRN_TS_WRITER_OUTPUT_BODY_CASE
+
+/* grn_ts_writer_output() outputs search results into the output buffer. */
+static grn_rc
+grn_ts_writer_output(grn_ctx *ctx, grn_ts_writer *writer,
+ const grn_ts_record *in, size_t n_in, size_t n_hits)
+{
+ grn_rc rc;
+ GRN_OUTPUT_ARRAY_OPEN("RESULT", 1);
+ GRN_OUTPUT_ARRAY_OPEN("RESULTSET", 2 + n_in);
+ GRN_OUTPUT_ARRAY_OPEN("NHITS", 1);
+ rc = grn_text_ulltoa(ctx, ctx->impl->output.buf, n_hits);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ GRN_OUTPUT_ARRAY_CLOSE(); /* NHITS. */
+ rc = grn_ts_writer_output_header(ctx, writer);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_writer_output_body(ctx, writer, in, n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ GRN_OUTPUT_ARRAY_CLOSE(); /* RESULTSET. */
+ GRN_OUTPUT_ARRAY_CLOSE(); /* RESET. */
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_select_filter() applies a filter to all the records of a table. */
+static grn_rc
+grn_ts_select_filter(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
+ size_t offset, size_t limit,
+ grn_ts_record **out, size_t *n_out, size_t *n_hits)
+{
+ grn_rc rc;
+ grn_table_cursor *cursor_obj;
+ grn_ts_cursor *cursor;
+ grn_ts_expr *expr = NULL;
+ grn_ts_record *buf = NULL;
+ size_t buf_size = 0;
+
+ *out = NULL;
+ *n_out = 0;
+ *n_hits = 0;
+
+ cursor_obj = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_ID);
+ if (!cursor_obj) {
+ return (ctx->rc != GRN_SUCCESS) ? ctx->rc : GRN_UNKNOWN_ERROR;
+ }
+ rc = grn_ts_obj_cursor_open(ctx, cursor_obj, &cursor);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, cursor_obj);
+ return rc;
+ }
+
+ if (str.size) {
+ rc = grn_ts_expr_parse(ctx, table, str, &expr);
+ }
+ if (rc == GRN_SUCCESS) {
+ for ( ; ; ) {
+ size_t batch_size;
+ grn_ts_record *batch;
+
+ /* Extend the record buffer. */
+ if (buf_size < (*n_out + GRN_TS_BATCH_SIZE)) {
+ size_t new_size = buf_size ? (buf_size * 2) : GRN_TS_BATCH_SIZE;
+ size_t n_bytes = sizeof(grn_ts_record) * new_size;
+ grn_ts_record *new_buf = (grn_ts_record *)GRN_REALLOC(buf, n_bytes);
+ if (!new_buf) {
+ GRN_TS_ERR(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ n_bytes);
+ rc = ctx->rc;
+ break;
+ }
+ buf = new_buf;
+ buf_size = new_size;
+ }
+
+ /* Read records from the cursor. */
+ batch = buf + *n_out;
+ rc = grn_ts_cursor_read(ctx, cursor, batch, GRN_TS_BATCH_SIZE,
+ &batch_size);
+ if ((rc != GRN_SUCCESS) || !batch_size) {
+ break;
+ }
+
+ /* Apply the filter. */
+ if (expr) {
+ rc = grn_ts_expr_filter(ctx, expr, batch, batch_size,
+ batch, &batch_size);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ *n_hits += batch_size;
+
+ /* Apply the offset and the limit. */
+ if (offset) {
+ if (batch_size <= offset) {
+ offset -= batch_size;
+ batch_size = 0;
+ } else {
+ size_t n_bytes = sizeof(grn_ts_record) * (batch_size - offset);
+ grn_memmove(batch, batch + offset, n_bytes);
+ batch_size -= offset;
+ offset = 0;
+ }
+ }
+ if (batch_size <= limit) {
+ limit -= batch_size;
+ } else {
+ batch_size = limit;
+ limit = 0;
+ }
+ *n_out += batch_size;
+ }
+ /* Ignore a failure of destruction. */
+ if (expr) {
+ grn_ts_expr_close(ctx, expr);
+ }
+ }
+ /* Ignore a failure of destruction. */
+ grn_ts_cursor_close(ctx, cursor);
+
+ if (rc != GRN_SUCCESS) {
+ if (buf) {
+ GRN_FREE(buf);
+ }
+ *n_out = 0;
+ *n_hits = 0;
+ return rc;
+ }
+ *out = buf;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_select_scorer() adjust scores. */
+static grn_rc
+grn_ts_select_scorer(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
+ grn_ts_record *records, size_t n_records)
+{
+ grn_rc rc;
+ grn_ts_str rest;
+ grn_ts_expr *expr;
+ rest = grn_ts_str_trim_score_assignment(str);
+ if (!rest.size) {
+ return GRN_SUCCESS;
+ }
+ rc = grn_ts_expr_parse(ctx, table, rest, &expr);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_adjust(ctx, expr, records, n_records);
+ grn_ts_expr_close(ctx, expr);
+ return rc;
+}
+
+/* grn_ts_select_output() outputs the results. */
+static grn_rc
+grn_ts_select_output(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
+ const grn_ts_record *in, size_t n_in, size_t n_hits)
+{
+ grn_ts_writer *writer= 0;
+ grn_rc rc = grn_ts_writer_open(ctx, table, str, &writer);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_writer_output(ctx, writer, in, n_in, n_hits);
+ grn_ts_writer_close(ctx, writer);
+ return rc;
+}
+
+/* grn_ts_select_with_sortby() executes a select command with --sortby. */
+static grn_rc
+grn_ts_select_with_sortby(grn_ctx *ctx, grn_obj *table,
+ grn_ts_str filter, grn_ts_str scorer,
+ grn_ts_str sortby, grn_ts_str output_columns,
+ size_t offset, size_t limit)
+{
+ grn_rc rc;
+ grn_ts_record *recs = NULL;
+ size_t n_recs = 0, max_n_recs = 0, n_hits = 0;
+ grn_table_cursor *cursor_obj;
+ grn_ts_cursor *cursor = NULL;
+ grn_ts_expr *filter_expr = NULL;
+ grn_ts_expr *scorer_expr = NULL;
+ grn_ts_sorter *sorter = NULL;
+ cursor_obj = grn_table_cursor_open(ctx, table, NULL, 0, NULL, 0, 0, -1,
+ GRN_CURSOR_ASCENDING | GRN_CURSOR_BY_ID);
+ if (!cursor_obj) {
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_table_cursor_open failed");
+ }
+ rc = grn_ts_obj_cursor_open(ctx, cursor_obj, &cursor);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_close(ctx, cursor_obj);
+ return rc;
+ }
+ if (filter.size) {
+ rc = grn_ts_expr_parse(ctx, table, filter, &filter_expr);
+ }
+ if (rc == GRN_SUCCESS) {
+ scorer = grn_ts_str_trim_score_assignment(scorer);
+ if (scorer.size) {
+ rc = grn_ts_expr_parse(ctx, table, scorer, &scorer_expr);
+ }
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_sorter_parse(ctx, table, sortby, offset, limit, &sorter);
+ }
+ }
+ if (rc == GRN_SUCCESS) {
+ size_t n_pending_recs = 0;
+ for ( ; ; ) {
+ size_t batch_size;
+ grn_ts_record *batch;
+ /* Extend a buffer for records. */
+ if (max_n_recs < (n_recs + GRN_TS_BATCH_SIZE)) {
+ size_t n_bytes, new_max_n_recs = max_n_recs * 2;
+ grn_ts_record *new_recs;
+ if (!new_max_n_recs) {
+ new_max_n_recs = GRN_TS_BATCH_SIZE;
+ }
+ n_bytes = sizeof(grn_ts_record) * new_max_n_recs;
+ new_recs = (grn_ts_record *)GRN_REALLOC(recs, n_bytes);
+ if (!new_recs) {
+ GRN_TS_ERR(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ n_bytes);
+ rc = ctx->rc;
+ break;
+ }
+ recs = new_recs;
+ max_n_recs = new_max_n_recs;
+ }
+ /* Read records from a cursor. */
+ batch = recs + n_recs;
+ rc = grn_ts_cursor_read(ctx, cursor, batch, GRN_TS_BATCH_SIZE,
+ &batch_size);
+ if (rc != GRN_SUCCESS) {
+ break;
+ } else if (!batch_size) {
+ /* Apply a scorer and complete sorting. */
+ if (scorer_expr) {
+ rc = grn_ts_expr_adjust(ctx, scorer_expr,
+ recs + n_recs - n_pending_recs,
+ n_pending_recs);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ if (n_pending_recs) {
+ rc = grn_ts_sorter_progress(ctx, sorter, recs, n_recs, &n_recs);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ rc = grn_ts_sorter_complete(ctx, sorter, recs, n_recs, &n_recs);
+ break;
+ }
+ /* Apply a filter. */
+ if (filter_expr) {
+ rc = grn_ts_expr_filter(ctx, filter_expr, batch, batch_size,
+ batch, &batch_size);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ n_hits += batch_size;
+ n_recs += batch_size;
+ n_pending_recs += batch_size;
+ /*
+ * Apply a scorer and progress sorting if there are enough pending
+ * records.
+ */
+ if (n_pending_recs >= GRN_TS_BATCH_SIZE) {
+ if (scorer_expr) {
+ rc = grn_ts_expr_adjust(ctx, scorer_expr,
+ recs + n_recs - n_pending_recs,
+ n_pending_recs);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ rc = grn_ts_sorter_progress(ctx, sorter, recs, n_recs, &n_recs);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ n_pending_recs = 0;
+ }
+ }
+ }
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_select_output(ctx, table, output_columns,
+ recs, n_recs, n_hits);
+ }
+ if (cursor) {
+ grn_ts_cursor_close(ctx, cursor);
+ }
+ if (recs) {
+ GRN_FREE(recs);
+ }
+ if (sorter) {
+ grn_ts_sorter_close(ctx, sorter);
+ }
+ if (scorer_expr) {
+ grn_ts_expr_close(ctx, scorer_expr);
+ }
+ if (filter_expr) {
+ grn_ts_expr_close(ctx, filter_expr);
+ }
+ return rc;
+}
+
+/*
+ * grn_ts_select_without_sortby() executes a select command without --sortby.
+ */
+static grn_rc
+grn_ts_select_without_sortby(grn_ctx *ctx, grn_obj *table,
+ grn_ts_str filter, grn_ts_str scorer,
+ grn_ts_str output_columns,
+ size_t offset, size_t limit)
+{
+ grn_rc rc;
+ grn_ts_record *records = NULL;
+ size_t n_records, n_hits;
+ rc = grn_ts_select_filter(ctx, table, filter, offset, limit,
+ &records, &n_records, &n_hits);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_select_scorer(ctx, table, scorer, records, n_records);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_select_output(ctx, table, output_columns,
+ records, n_records, n_hits);
+ }
+ }
+ if (records) {
+ GRN_FREE(records);
+ }
+ return rc;
+}
+
+/*-------------------------------------------------------------
+ * API.
+ */
+
+grn_rc
+grn_ts_select(grn_ctx *ctx, grn_obj *table,
+ const char *filter_ptr, size_t filter_len,
+ const char *scorer_ptr, size_t scorer_len,
+ const char *sortby_ptr, size_t sortby_len,
+ const char *output_columns_ptr, size_t output_columns_len,
+ size_t offset, size_t limit)
+{
+ grn_rc rc;
+ grn_ts_str filter = { filter_ptr, filter_len };
+ grn_ts_str scorer = { scorer_ptr, scorer_len };
+ grn_ts_str sortby = { sortby_ptr, sortby_len };
+ grn_ts_str output_columns = { output_columns_ptr, output_columns_len };
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) ||
+ (!filter_ptr && filter_len) || (!scorer_ptr && scorer_len) ||
+ (!sortby_ptr && sortby_len) ||
+ (!output_columns_ptr && output_columns_len)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ filter = grn_ts_str_trim_left(filter);
+ if (sortby_len) {
+ rc = grn_ts_select_with_sortby(ctx, table, filter, scorer, sortby,
+ output_columns, offset, limit);
+ } else {
+ rc = grn_ts_select_without_sortby(ctx, table, filter, scorer,
+ output_columns, offset, limit);
+ }
+ if (rc != GRN_SUCCESS) {
+ GRN_BULK_REWIND(ctx->impl->output.buf);
+ if ((ctx->rc == GRN_SUCCESS) || !ctx->errbuf[0]) {
+ ERR(rc, "error message is missing");
+ } else if (ctx->errlvl < GRN_LOG_ERROR) {
+ ctx->errlvl = GRN_LOG_ERROR;
+ }
+ }
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/Makefile.am b/storage/mroonga/vendor/groonga/lib/ts/Makefile.am
new file mode 100644
index 00000000..f1f21df4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/Makefile.am
@@ -0,0 +1,20 @@
+BUNDLED_LIBRARIES_CFLAGS = \
+ $(MRUBY_CFLAGS) \
+ $(ONIGMO_CFLAGS)
+
+DEFAULT_INCLUDES = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ $(BUNDLED_LIBRARIES_CFLAGS)
+
+AM_CFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS)
+
+noinst_LTLIBRARIES = libgrnts.la
+
+include sources.am
+
+CLEANFILES = *.gcno *.gcda
diff --git a/storage/mroonga/vendor/groonga/lib/ts/sources.am b/storage/mroonga/vendor/groonga/lib/ts/sources.am
new file mode 100644
index 00000000..5d89b059
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/sources.am
@@ -0,0 +1,25 @@
+libgrnts_la_SOURCES = \
+ ts_buf.c \
+ ts_buf.h \
+ ts_cursor.c \
+ ts_cursor.h \
+ ts_expr.c \
+ ts_expr.h \
+ ts_expr_builder.c \
+ ts_expr_builder.h \
+ ts_expr_node.c \
+ ts_expr_node.h \
+ ts_expr_parser.c \
+ ts_expr_parser.h \
+ ts_log.h \
+ ts_op.c \
+ ts_op.h \
+ ts_plan.c \
+ ts_plan.h \
+ ts_sorter.c \
+ ts_sorter.h \
+ ts_str.c \
+ ts_str.h \
+ ts_types.h \
+ ts_util.c \
+ ts_util.h
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_buf.c b/storage/mroonga/vendor/groonga/lib/ts/ts_buf.c
new file mode 100644
index 00000000..65521d71
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_buf.c
@@ -0,0 +1,244 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_buf.h"
+
+#include "../grn_ctx.h"
+
+#include "ts_log.h"
+
+#include <string.h>
+
+/*-------------------------------------------------------------
+ * grn_ts_buf
+ */
+
+void
+grn_ts_buf_init(grn_ctx *ctx, grn_ts_buf *buf)
+{
+ buf->ptr = NULL;
+ buf->size = 0;
+ buf->pos = 0;
+}
+
+/*
+grn_rc
+grn_ts_buf_open(grn_ctx *ctx, grn_ts_buf **buf)
+{
+ grn_ts_buf *new_buf = GRN_MALLOCN(grn_ts_buf, 1);
+ if (!new_buf) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_buf));
+ }
+ grn_ts_buf_init(ctx, new_buf);
+ *buf = new_buf;
+ return GRN_SUCCESS;
+}
+*/
+
+void
+grn_ts_buf_fin(grn_ctx *ctx, grn_ts_buf *buf)
+{
+ if (buf->ptr) {
+ GRN_FREE(buf->ptr);
+ }
+}
+
+/*
+void
+grn_ts_buf_close(grn_ctx *ctx, grn_ts_buf *buf)
+{
+ if (buf) {
+ grn_ts_buf_fin(ctx, buf);
+ }
+}
+*/
+
+grn_rc
+grn_ts_buf_reserve(grn_ctx *ctx, grn_ts_buf *buf, size_t min_size)
+{
+ void *new_ptr;
+ size_t enough_size;
+ if (min_size <= buf->size) {
+ return GRN_SUCCESS;
+ }
+ enough_size = buf->size ? (buf->size << 1) : 1;
+ while (enough_size < min_size) {
+ if ((enough_size << 1) < enough_size) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "size overflow: %" GRN_FMT_SIZE,
+ min_size);
+ }
+ enough_size <<= 1;
+ }
+ new_ptr = GRN_REALLOC(buf->ptr, enough_size);
+ if (!new_ptr) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ enough_size);
+ }
+ buf->ptr = new_ptr;
+ buf->size = enough_size;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_buf_resize(grn_ctx *ctx, grn_ts_buf *buf, size_t new_size)
+{
+ void *new_ptr;
+ if (new_size == buf->size) {
+ return GRN_SUCCESS;
+ }
+ if (!new_size) {
+ if (buf->ptr) {
+ GRN_FREE(buf->ptr);
+ buf->ptr = NULL;
+ buf->size = new_size;
+ }
+ return GRN_SUCCESS;
+ }
+ new_ptr = GRN_REALLOC(buf->ptr, new_size);
+ if (!new_ptr) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ new_size);
+ }
+ buf->ptr = new_ptr;
+ buf->size = new_size;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_buf_write(grn_ctx *ctx, grn_ts_buf *buf, const void *ptr, size_t size)
+{
+ size_t new_pos = buf->pos + size;
+ if (new_pos < buf->pos) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "size overflow: %" GRN_FMT_SIZE " + %" GRN_FMT_SIZE,
+ buf->pos, size);
+ }
+ if (new_pos > buf->size) {
+ grn_rc rc = grn_ts_buf_reserve(ctx, buf, new_pos);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ grn_memcpy((char *)buf->ptr + buf->pos, ptr, size);
+ buf->pos += size;
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_rbuf
+ */
+
+void
+grn_ts_rbuf_init(grn_ctx *ctx, grn_ts_rbuf *rbuf)
+{
+ rbuf->recs = NULL;
+ rbuf->n_recs = 0;
+ rbuf->max_n_recs = 0;
+}
+
+void
+grn_ts_rbuf_fin(grn_ctx *ctx, grn_ts_rbuf *rbuf)
+{
+ if (rbuf->recs) {
+ GRN_FREE(rbuf->recs);
+ }
+}
+
+grn_rc
+grn_ts_rbuf_open(grn_ctx *ctx, grn_ts_rbuf **rbuf)
+{
+ grn_ts_rbuf *new_rbuf = GRN_MALLOCN(grn_ts_rbuf, 1);
+ if (!new_rbuf) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_rbuf));
+ }
+ grn_ts_rbuf_init(ctx, new_rbuf);
+ *rbuf = new_rbuf;
+ return GRN_SUCCESS;
+}
+
+void
+grn_ts_rbuf_close(grn_ctx *ctx, grn_ts_rbuf *rbuf)
+{
+ if (rbuf) {
+ grn_ts_rbuf_fin(ctx, rbuf);
+ }
+}
+
+grn_rc
+grn_ts_rbuf_reserve(grn_ctx *ctx, grn_ts_rbuf *rbuf, size_t min_max_n_recs)
+{
+ size_t n_bytes, enough_max_n_recs;
+ grn_ts_record *new_recs;
+ if (min_max_n_recs <= rbuf->max_n_recs) {
+ return GRN_SUCCESS;
+ }
+ enough_max_n_recs = rbuf->max_n_recs ? (rbuf->max_n_recs << 1) : 1;
+ while (enough_max_n_recs < min_max_n_recs) {
+ if ((enough_max_n_recs << 1) < enough_max_n_recs) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "size overflow: %" GRN_FMT_SIZE,
+ min_max_n_recs);
+ }
+ enough_max_n_recs <<= 1;
+ }
+ n_bytes = sizeof(grn_ts_record) * enough_max_n_recs;
+ new_recs = GRN_REALLOC(rbuf->recs, n_bytes);
+ if (!new_recs) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ n_bytes);
+ }
+ rbuf->recs = new_recs;
+ rbuf->max_n_recs = enough_max_n_recs;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_rbuf_resize(grn_ctx *ctx, grn_ts_rbuf *rbuf, size_t new_max_n_recs)
+{
+ size_t n_bytes;
+ grn_ts_record *new_recs;
+ if (new_max_n_recs == rbuf->max_n_recs) {
+ return GRN_SUCCESS;
+ }
+ if (!new_max_n_recs) {
+ if (rbuf->recs) {
+ GRN_FREE(rbuf->recs);
+ rbuf->recs = NULL;
+ rbuf->max_n_recs = new_max_n_recs;
+ }
+ return GRN_SUCCESS;
+ }
+ n_bytes = sizeof(grn_ts_record) * new_max_n_recs;
+ new_recs = GRN_REALLOC(rbuf->recs, n_bytes);
+ if (!new_recs) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ new_max_n_recs);
+ }
+ rbuf->recs = new_recs;
+ rbuf->max_n_recs = new_max_n_recs;
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_buf.h b/storage/mroonga/vendor/groonga/lib/ts/ts_buf.h
new file mode 100644
index 00000000..f8077f0f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_buf.h
@@ -0,0 +1,111 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------
+ * grn_ts_buf
+ */
+
+/* grn_ts_buf works as a buffer for arbitrary data. */
+
+typedef struct {
+ void *ptr; /* The starting address. */
+ size_t size; /* The size in bytes. */
+ size_t pos; /* The current position for grn_ts_buf_write(). */
+} grn_ts_buf;
+
+/* grn_ts_buf_init() initializes a buffer. */
+void grn_ts_buf_init(grn_ctx *ctx, grn_ts_buf *buf);
+
+/* grn_ts_buf_fin() finalizes a buffer. */
+void grn_ts_buf_fin(grn_ctx *ctx, grn_ts_buf *buf);
+
+#if 0
+/* grn_ts_buf_open() creates a buffer. */
+grn_rc grn_ts_buf_open(grn_ctx *ctx, grn_ts_buf **buf);
+
+/* grn_ts_buf_close() destroys a buffer. */
+void grn_ts_buf_close(grn_ctx *ctx, grn_ts_buf *buf);
+#endif
+
+/*
+ * grn_ts_buf_reserve() reserves enough memory to store `min_size` bytes.
+ * Note that this function never shrinks a buffer and does nothing if
+ * `min_size` is not greater than `buf->size`.
+ */
+grn_rc grn_ts_buf_reserve(grn_ctx *ctx, grn_ts_buf *buf, size_t min_size);
+
+/* grn_ts_buf_resize() resizes a buffer. */
+grn_rc grn_ts_buf_resize(grn_ctx *ctx, grn_ts_buf *buf, size_t new_size);
+
+/*
+ * grn_ts_buf_write() writes data into a buffer. `buf->pos` specifies the
+ * position and it will be modified on success.
+ * Note that this function resizes a buffer if required.
+ */
+grn_rc grn_ts_buf_write(grn_ctx *ctx, grn_ts_buf *buf,
+ const void *ptr, size_t size);
+
+/*-------------------------------------------------------------
+ * grn_ts_rbuf
+ */
+
+/* grn_ts_rbuf works as a buffer for records. */
+
+typedef struct {
+ grn_ts_record *recs; /* Pointer to records. */
+ size_t n_recs; /* The number of records. */
+ size_t max_n_recs; /* The maximum number of records. */
+} grn_ts_rbuf;
+
+/* grn_ts_rbuf_init() initializes a buffer. */
+void grn_ts_rbuf_init(grn_ctx *ctx, grn_ts_rbuf *rbuf);
+
+/* grn_ts_rbuf_fin() finalizes a buffer. */
+void grn_ts_rbuf_fin(grn_ctx *ctx, grn_ts_rbuf *rbuf);
+
+/* grn_ts_rbuf_open() creates a buffer. */
+/*grn_rc grn_ts_rbuf_open(grn_ctx *ctx, grn_ts_rbuf **rbuf);*/
+
+/* grn_ts_rbuf_close() destroys a buffer. */
+/*void grn_ts_rbuf_close(grn_ctx *ctx, grn_ts_rbuf *rbuf);*/
+
+/*
+ * grn_ts_rbuf_reserve() reserves enough memory to store `n_recs` records.
+ * Note that this function never shrinks a buffer and does nothing if `n_recs`
+ * is not greater than the `rbuf->max_n_recs`.
+ */
+grn_rc grn_ts_rbuf_reserve(grn_ctx *ctx, grn_ts_rbuf *rbuf, size_t n_recs);
+
+/* grn_ts_rbuf_resize() resizes a buffer. */
+grn_rc grn_ts_rbuf_resize(grn_ctx *ctx, grn_ts_rbuf *rbuf,
+ size_t new_max_n_recs);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_cursor.c b/storage/mroonga/vendor/groonga/lib/ts/ts_cursor.c
new file mode 100644
index 00000000..779e4cae
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_cursor.c
@@ -0,0 +1,163 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_cursor.h"
+
+#include "../grn_ctx.h"
+#include "../grn_dat.h"
+#include "../grn_hash.h"
+#include "../grn_pat.h"
+
+#include "ts_log.h"
+#include "ts_util.h"
+
+/*-------------------------------------------------------------
+ * grn_ts_obj_cursor.
+ */
+
+typedef struct {
+ GRN_TS_CURSOR_COMMON_MEMBERS
+ grn_obj *obj; /* Wrapped cursor object. */
+} grn_ts_obj_cursor;
+
+grn_rc
+grn_ts_obj_cursor_open(grn_ctx *ctx, grn_obj *obj, grn_ts_cursor **cursor)
+{
+ grn_ts_obj_cursor *new_cursor;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!obj || !cursor) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ switch (obj->header.type) {
+ case GRN_CURSOR_TABLE_HASH_KEY:
+ case GRN_CURSOR_TABLE_PAT_KEY:
+ case GRN_CURSOR_TABLE_DAT_KEY:
+ case GRN_CURSOR_TABLE_NO_KEY: {
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ }
+ new_cursor = GRN_MALLOCN(grn_ts_obj_cursor, 1);
+ if (!new_cursor) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_obj_cursor));
+ }
+ new_cursor->type = GRN_TS_OBJ_CURSOR;
+ new_cursor->obj = obj;
+ *cursor = (grn_ts_cursor *)new_cursor;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_obj_cursor_close() destroys a wrapper cursor. */
+static grn_rc
+grn_ts_obj_cursor_close(grn_ctx *ctx, grn_ts_obj_cursor *cursor)
+{
+ if (cursor->obj) {
+ grn_obj_close(ctx, cursor->obj);
+ }
+ GRN_FREE(cursor);
+ return GRN_SUCCESS;
+}
+
+#define GRN_TS_OBJ_CURSOR_READ(type)\
+ size_t i;\
+ grn_ ## type ## _cursor *obj = (grn_ ## type ## _cursor *)cursor->obj;\
+ for (i = 0; i < max_n_recs; i++) {\
+ recs[i].id = grn_ ## type ## _cursor_next(ctx, obj);\
+ if (!recs[i].id) {\
+ break;\
+ }\
+ recs[i].score = 0;\
+ }\
+ *n_recs = i;\
+ return GRN_SUCCESS;
+/* grn_ts_obj_cursor_read() reads records from a wrapper cursor. */
+static grn_rc
+grn_ts_obj_cursor_read(grn_ctx *ctx, grn_ts_obj_cursor *cursor,
+ grn_ts_record *recs, size_t max_n_recs, size_t *n_recs)
+{
+ switch (cursor->obj->header.type) {
+ case GRN_CURSOR_TABLE_HASH_KEY: {
+ GRN_TS_OBJ_CURSOR_READ(hash)
+ }
+ case GRN_CURSOR_TABLE_PAT_KEY: {
+ GRN_TS_OBJ_CURSOR_READ(pat)
+ }
+ case GRN_CURSOR_TABLE_DAT_KEY: {
+ GRN_TS_OBJ_CURSOR_READ(dat)
+ }
+ case GRN_CURSOR_TABLE_NO_KEY: {
+ GRN_TS_OBJ_CURSOR_READ(array)
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_cursor.
+ */
+
+grn_rc
+grn_ts_cursor_close(grn_ctx *ctx, grn_ts_cursor *cursor)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!cursor) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ switch (cursor->type) {
+ case GRN_TS_OBJ_CURSOR: {
+ return grn_ts_obj_cursor_close(ctx, (grn_ts_obj_cursor *)cursor);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid cursor type: %d",
+ cursor->type);
+ }
+ }
+}
+
+grn_rc
+grn_ts_cursor_read(grn_ctx *ctx, grn_ts_cursor *cursor,
+ grn_ts_record *out, size_t max_n_out, size_t *n_out)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!cursor || (!out && max_n_out) || !n_out) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ switch (cursor->type) {
+ case GRN_TS_OBJ_CURSOR: {
+ return grn_ts_obj_cursor_read(ctx, (grn_ts_obj_cursor *)cursor,
+ out, max_n_out, n_out);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid cursor type: %d",
+ cursor->type);
+ }
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_cursor.h b/storage/mroonga/vendor/groonga/lib/ts/ts_cursor.h
new file mode 100644
index 00000000..f12034f7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_cursor.h
@@ -0,0 +1,59 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ GRN_TS_OBJ_CURSOR /* Wrapper cursor. */
+} grn_ts_cursor_type;
+
+#define GRN_TS_CURSOR_COMMON_MEMBERS\
+ grn_ts_cursor_type type; /* Cursor type. */
+
+typedef struct {
+ GRN_TS_CURSOR_COMMON_MEMBERS
+} grn_ts_cursor;
+
+/*
+ * grn_ts_obj_cursor_open() creates a wrapper cursor.
+ * The new cursor will be a wrapper for a Groonga cursor specified by `obj`.
+ * On success, `obj` will be closed in grn_ts_cursor_close().
+ * On failure, `obj` is left as is.
+ */
+grn_rc grn_ts_obj_cursor_open(grn_ctx *ctx, grn_obj *obj,
+ grn_ts_cursor **cursor);
+
+/* grn_ts_cursor_close() destroys a cursor. */
+grn_rc grn_ts_cursor_close(grn_ctx *ctx, grn_ts_cursor *cursor);
+
+/* grn_ts_cursor_read() reads records from a cursor. */
+grn_rc grn_ts_cursor_read(grn_ctx *ctx, grn_ts_cursor *cursor,
+ grn_ts_record *out, size_t max_n_out, size_t *n_out);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr.c b/storage/mroonga/vendor/groonga/lib/ts/ts_expr.c
new file mode 100644
index 00000000..16576fbc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr.c
@@ -0,0 +1,219 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_expr.h"
+
+#include <string.h>
+
+#include "../grn_ctx.h"
+
+#include "ts_log.h"
+#include "ts_str.h"
+#include "ts_util.h"
+#include "ts_expr_parser.h"
+
+/* grn_ts_expr_init() initializes an expression. */
+static void
+grn_ts_expr_init(grn_ctx *ctx, grn_ts_expr *expr)
+{
+ memset(expr, 0, sizeof(*expr));
+ expr->table = NULL;
+ expr->root = NULL;
+}
+
+/* grn_ts_expr_fin() finalizes an expression. */
+static void
+grn_ts_expr_fin(grn_ctx *ctx, grn_ts_expr *expr)
+{
+ if (expr->root) {
+ grn_ts_expr_node_close(ctx, expr->root);
+ }
+ if (expr->table) {
+ grn_obj_unlink(ctx, expr->table);
+ }
+}
+
+grn_rc
+grn_ts_expr_open(grn_ctx *ctx, grn_obj *table, grn_ts_expr_node *root,
+ grn_ts_expr **expr)
+{
+ grn_rc rc;
+ grn_ts_expr *new_expr;
+ grn_ts_expr_type type;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) || !root || !expr) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ switch (root->type) {
+ case GRN_TS_EXPR_ID_NODE: {
+ type = GRN_TS_EXPR_ID;
+ break;
+ }
+ case GRN_TS_EXPR_SCORE_NODE: {
+ type = GRN_TS_EXPR_SCORE;
+ break;
+ }
+ case GRN_TS_EXPR_KEY_NODE:
+ case GRN_TS_EXPR_VALUE_NODE: {
+ type = GRN_TS_EXPR_VARIABLE;
+ break;
+ }
+ case GRN_TS_EXPR_CONST_NODE: {
+ type = GRN_TS_EXPR_CONST;
+ break;
+ }
+ case GRN_TS_EXPR_COLUMN_NODE:
+ case GRN_TS_EXPR_OP_NODE:
+ case GRN_TS_EXPR_BRIDGE_NODE: {
+ type = GRN_TS_EXPR_VARIABLE;
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ }
+ new_expr = GRN_MALLOCN(grn_ts_expr, 1);
+ if (!new_expr) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE,
+ sizeof(grn_ts_expr));
+ }
+ rc = grn_ts_obj_increment_ref_count(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ GRN_FREE(new_expr);
+ return rc;
+ }
+ grn_ts_expr_init(ctx, new_expr);
+ new_expr->table = table;
+ new_expr->type = type;
+ new_expr->data_kind = root->data_kind;
+ new_expr->data_type = root->data_type;
+ new_expr->root = root;
+ *expr = new_expr;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_parse(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
+ grn_ts_expr **expr)
+{
+ grn_rc rc;
+ grn_ts_expr *new_expr;
+ grn_ts_expr_parser *parser;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) ||
+ (!str.ptr && str.size) || !expr) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_parser_open(ctx, table, &parser);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_parser_parse(ctx, parser, str, &new_expr);
+ grn_ts_expr_parser_close(ctx, parser);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *expr = new_expr;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_close(grn_ctx *ctx, grn_ts_expr *expr)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!expr) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ grn_ts_expr_fin(ctx, expr);
+ GRN_FREE(expr);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr *expr,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_buf *out)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!expr || (!in && n_in) || !out) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (!n_in) {
+ return GRN_SUCCESS;
+ }
+ return grn_ts_expr_node_evaluate_to_buf(ctx, expr->root, in, n_in, out);
+}
+
+grn_rc
+grn_ts_expr_evaluate(grn_ctx *ctx, grn_ts_expr *expr,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!expr || (!in && n_in) || (n_in && !out)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (!n_in) {
+ return GRN_SUCCESS;
+ }
+ return grn_ts_expr_node_evaluate(ctx, expr->root, in, n_in, out);
+}
+
+grn_rc
+grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!expr || (!in && n_in) || !out || !n_out) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (!n_in) {
+ *n_out = 0;
+ return GRN_SUCCESS;
+ }
+ return grn_ts_expr_node_filter(ctx, expr->root, in, n_in, out, n_out);
+}
+
+grn_rc
+grn_ts_expr_adjust(grn_ctx *ctx, grn_ts_expr *expr,
+ grn_ts_record *io, size_t n_io)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!expr || (!io && n_io)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (!n_io) {
+ return GRN_SUCCESS;
+ }
+ return grn_ts_expr_node_adjust(ctx, expr->root, io, n_io);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr.h b/storage/mroonga/vendor/groonga/lib/ts/ts_expr.h
new file mode 100644
index 00000000..b50e886d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr.h
@@ -0,0 +1,87 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_buf.h"
+#include "ts_expr_node.h"
+#include "ts_str.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------
+ * Enumeration types.
+ */
+
+typedef enum {
+ GRN_TS_EXPR_ID, /* IDs (_id). */
+ GRN_TS_EXPR_SCORE, /* Scores (_score). */
+ GRN_TS_EXPR_CONST, /* A const. */
+ GRN_TS_EXPR_VARIABLE /* An expression that contains a variable. */
+} grn_ts_expr_type;
+
+/*-------------------------------------------------------------
+ * Expression components.
+ */
+
+typedef struct {
+ grn_obj *table; /* Associated table. */
+ grn_ts_expr_type type; /* Expression type. */
+ grn_ts_data_kind data_kind; /* Abstract data type. */
+ grn_ts_data_type data_type; /* Detailed data type. */
+ grn_ts_expr_node *root; /* Root node. */
+} grn_ts_expr;
+
+/* grn_ts_expr_open() creates an expression. */
+grn_rc grn_ts_expr_open(grn_ctx *ctx, grn_obj *table, grn_ts_expr_node *root,
+ grn_ts_expr **expr);
+
+/* grn_ts_expr_parse() parses a string and creates an expression. */
+grn_rc grn_ts_expr_parse(grn_ctx *ctx, grn_obj *table, grn_ts_str str,
+ grn_ts_expr **expr);
+
+/* grn_ts_expr_close() destroys an expression. */
+grn_rc grn_ts_expr_close(grn_ctx *ctx, grn_ts_expr *expr);
+
+/* grn_ts_expr_evaluate() evaluates an expression. */
+grn_rc grn_ts_expr_evaluate(grn_ctx *ctx, grn_ts_expr *expr,
+ const grn_ts_record *in, size_t n_in, void *out);
+
+/* grn_ts_expr_evaluate_to_buf() evaluates an expression. */
+grn_rc grn_ts_expr_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr *expr,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_buf *out);
+
+/* grn_ts_expr_filter() filters records. */
+grn_rc grn_ts_expr_filter(grn_ctx *ctx, grn_ts_expr *expr,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out);
+
+/* grn_ts_expr_adjust() updates scores. */
+grn_rc grn_ts_expr_adjust(grn_ctx *ctx, grn_ts_expr *expr,
+ grn_ts_record *io, size_t n_io);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.c b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.c
new file mode 100644
index 00000000..a742e062
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.c
@@ -0,0 +1,757 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_expr_builder.h"
+
+#include <string.h>
+
+#include "../grn_ctx.h"
+#include "../grn_db.h"
+
+#include "ts_log.h"
+#include "ts_util.h"
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_bridge.
+ */
+
+/* grn_ts_expr_bridge_init() initializes a bridge. */
+static void
+grn_ts_expr_bridge_init(grn_ctx *ctx, grn_ts_expr_bridge *bridge)
+{
+ memset(bridge, 0, sizeof(*bridge));
+ bridge->src_table = NULL;
+ bridge->dest_table = NULL;
+}
+
+/* grn_ts_expr_bridge_fin() finalizes a bridge. */
+static void
+grn_ts_expr_bridge_fin(grn_ctx *ctx, grn_ts_expr_bridge *bridge)
+{
+ if (bridge->dest_table) {
+ grn_obj_unlink(ctx, bridge->dest_table);
+ }
+ /* Note: bridge->src_table does not increment a reference count. */
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_builder.
+ */
+
+/* grn_ts_expr_builder_init() initializes an expression builder. */
+static void
+grn_ts_expr_builder_init(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ memset(builder, 0, sizeof(*builder));
+ builder->table = NULL;
+ builder->curr_table = NULL;
+ builder->nodes = NULL;
+ builder->bridges = NULL;
+}
+
+/* grn_ts_expr_builder_fin() finalizes an expression builder. */
+static void
+grn_ts_expr_builder_fin(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ size_t i;
+ if (builder->bridges) {
+ for (i = 0; i < builder->n_bridges; i++) {
+ grn_ts_expr_bridge_fin(ctx, &builder->bridges[i]);
+ }
+ GRN_FREE(builder->bridges);
+ }
+ if (builder->nodes) {
+ for (i = 0; i < builder->n_nodes; i++) {
+ if (builder->nodes[i]) {
+ grn_ts_expr_node_close(ctx, builder->nodes[i]);
+ }
+ }
+ GRN_FREE(builder->nodes);
+ }
+ /* Note: builder->curr_table does not increment a reference count. */
+ if (builder->table) {
+ grn_obj_unlink(ctx, builder->table);
+ }
+}
+
+grn_rc
+grn_ts_expr_builder_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_builder **builder)
+{
+ grn_rc rc;
+ grn_ts_expr_builder *new_builder;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) || !builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ new_builder = GRN_MALLOCN(grn_ts_expr_builder, 1);
+ if (!new_builder) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE,
+ sizeof(grn_ts_expr_builder));
+ }
+ rc = grn_ts_obj_increment_ref_count(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ GRN_FREE(new_builder);
+ return rc;
+ }
+ grn_ts_expr_builder_init(ctx, new_builder);
+ new_builder->table = table;
+ new_builder->curr_table = table;
+ *builder = new_builder;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_builder_close(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ grn_ts_expr_builder_fin(ctx, builder);
+ GRN_FREE(builder);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_builder_complete(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_expr **expr)
+{
+ grn_rc rc;
+ grn_ts_expr *new_expr;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder || (builder->n_nodes != 1) || builder->n_bridges || !expr) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_node_deref(ctx, &builder->nodes[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_open(ctx, builder->table, builder->nodes[0], &new_expr);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->n_nodes = 0;
+ *expr = new_expr;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_builder_clear(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ size_t i;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (builder->bridges) {
+ for (i = 0; i < builder->n_bridges; i++) {
+ grn_ts_expr_bridge_fin(ctx, &builder->bridges[i]);
+ }
+ builder->n_bridges = 0;
+ }
+ if (builder->nodes) {
+ for (i = 0; i < builder->n_nodes; i++) {
+ if (builder->nodes[i]) {
+ grn_ts_expr_node_close(ctx, builder->nodes[i]);
+ }
+ }
+ builder->n_nodes = 0;
+ }
+ builder->curr_table = builder->table;
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ts_expr_builder_push_node() pushes a node.
+ * The given node will be closed on failure.
+ */
+static grn_rc
+grn_ts_expr_builder_push_node(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_expr_node *node)
+{
+ if (builder->n_nodes == builder->max_n_nodes) {
+ size_t n_bytes, new_max_n_nodes;
+ grn_ts_expr_node **new_nodes;
+ new_max_n_nodes = builder->n_nodes ? (builder->n_nodes * 2) : 1;
+ n_bytes = sizeof(grn_ts_expr_node *) * new_max_n_nodes;
+ new_nodes = (grn_ts_expr_node **)GRN_REALLOC(builder->nodes, n_bytes);
+ if (!new_nodes) {
+ grn_ts_expr_node_close(ctx, node);
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes);
+ }
+ builder->nodes = new_nodes;
+ builder->max_n_nodes = new_max_n_nodes;
+ }
+ builder->nodes[builder->n_nodes++] = node;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_builder_push_name(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_str name)
+{
+ grn_obj *column;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder || !grn_ts_str_is_name(name)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (grn_ts_str_is_id_name(name)) {
+ return grn_ts_expr_builder_push_id(ctx, builder);
+ }
+ if (grn_ts_str_is_score_name(name)) {
+ return grn_ts_expr_builder_push_score(ctx, builder);
+ }
+ if (grn_ts_str_is_key_name(name)) {
+ return grn_ts_expr_builder_push_key(ctx, builder);
+ }
+ if (grn_ts_str_is_value_name(name)) {
+ return grn_ts_expr_builder_push_value(ctx, builder);
+ }
+ /* grn_obj_column() returns a column or accessor. */
+ column = grn_obj_column(ctx, builder->curr_table, name.ptr, name.size);
+ if (!column) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "object not found: \"%.*s\"",
+ (int)name.size, name.ptr);
+ }
+ return grn_ts_expr_builder_push_obj(ctx, builder, column);
+}
+
+#define GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(TYPE, KIND, kind)\
+ case GRN_DB_ ## TYPE: {\
+ value.as_ ## kind = (grn_ts_ ## kind)GRN_ ## TYPE ## _VALUE(obj);\
+ return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\
+ obj->header.domain, value);\
+ }
+/* grn_ts_expr_push_builder_bulk() pushes a scalar const. */
+static grn_rc
+grn_ts_expr_builder_push_bulk(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_obj *obj)
+{
+ grn_ts_any value;
+ switch (obj->header.domain) {
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(BOOL, BOOL, bool)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT8, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT16, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT32, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(INT64, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT8, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT16, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT32, INT, int)
+ /* The behavior is undefined if a value is greater than 2^63 - 1. */
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(UINT64, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(FLOAT, FLOAT, float)
+ GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE(TIME, TIME, time)
+ case GRN_DB_SHORT_TEXT:
+ case GRN_DB_TEXT:
+ case GRN_DB_LONG_TEXT: {
+ value.as_text.ptr = GRN_TEXT_VALUE(obj);
+ value.as_text.size = GRN_TEXT_LEN(obj);
+ return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_TEXT,
+ obj->header.domain, value);
+ }
+ case GRN_DB_TOKYO_GEO_POINT:
+ case GRN_DB_WGS84_GEO_POINT: {
+ GRN_GEO_POINT_VALUE(obj, value.as_geo.latitude, value.as_geo.longitude);
+ return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_GEO,
+ obj->header.domain, value);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "not bulk");
+ }
+ }
+}
+#undef GRN_TS_EXPR_BUILDER_PUSH_BULK_CASE
+
+#define GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(TYPE, KIND, kind)\
+ case GRN_DB_ ## TYPE: {\
+ value.as_ ## kind ## _vector.ptr = (grn_ts_ ## kind *)GRN_BULK_HEAD(obj);\
+ value.as_ ## kind ## _vector.size = grn_uvector_size(ctx, obj);\
+ return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\
+ obj->header.domain, value);\
+ }
+#define GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(TYPE, KIND, kind)\
+ case GRN_DB_ ## TYPE: {\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_ ## kind *buf;\
+ grn_ts_ ## kind ## _vector vector = { NULL, grn_uvector_size(ctx, obj) };\
+ if (!vector.size) {\
+ value.as_ ## kind ## _vector = vector;\
+ return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\
+ obj->header.domain, value);\
+ }\
+ buf = GRN_MALLOCN(grn_ts_ ## kind, vector.size);\
+ if (!buf) {\
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,\
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",\
+ sizeof(grn_ts_ ## kind));\
+ }\
+ for (i = 0; i < vector.size; i++) {\
+ buf[i] = GRN_ ## TYPE ##_VALUE_AT(obj, i);\
+ }\
+ vector.ptr = buf;\
+ value.as_ ## kind ## _vector = vector;\
+ rc = grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_ ## KIND,\
+ obj->header.domain, value);\
+ GRN_FREE(buf);\
+ return rc;\
+ }
+/* grn_ts_expr_builder_push_uvector() pushes an array of fixed-size values. */
+static grn_rc
+grn_ts_expr_builder_push_uvector(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_obj *obj)
+{
+ grn_ts_any value;
+ switch (obj->header.domain) {
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(BOOL, BOOL, bool)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT8, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT16, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(INT32, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(INT64, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT8, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT16, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST(UINT32, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(UINT64, INT, int)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(TIME, TIME, time)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(TOKYO_GEO_POINT, GEO, geo)
+ GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE(WGS84_GEO_POINT, GEO, geo)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data type: %d",
+ obj->header.domain);
+ }
+ }
+}
+#undef GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE_WITH_TYPECAST
+#undef GRN_TS_EXPR_BUILDER_PUSH_UVECTOR_CASE
+
+/* grn_ts_expr_builder_push_vector() pushes a Text vector. */
+static grn_rc
+grn_ts_expr_builder_push_vector(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_obj *obj)
+{
+ switch (obj->header.domain) {
+ case GRN_DB_SHORT_TEXT:
+ case GRN_DB_TEXT:
+ case GRN_DB_LONG_TEXT: {
+ size_t i;
+ grn_rc rc;
+ grn_ts_any value;
+ grn_ts_text *buf;
+ grn_ts_text_vector vector = { NULL, grn_vector_size(ctx, obj) };
+ if (!vector.size) {
+ value.as_text_vector = vector;
+ return grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_TEXT_VECTOR,
+ obj->header.domain, value);
+ }
+ buf = GRN_MALLOCN(grn_ts_text, vector.size);
+ if (!buf) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: "
+ "%" GRN_FMT_SIZE " x %" GRN_FMT_SIZE,
+ sizeof(grn_ts_text), vector.size);
+ }
+ for (i = 0; i < vector.size; i++) {
+ buf[i].size = grn_vector_get_element(ctx, obj, i, &buf[i].ptr,
+ NULL, NULL);
+ }
+ vector.ptr = buf;
+ value.as_text_vector = vector;
+ rc = grn_ts_expr_builder_push_const(ctx, builder, GRN_TS_TEXT_VECTOR,
+ obj->header.domain, value);
+ GRN_FREE(buf);
+ return rc;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data type: %d",
+ obj->header.domain);
+ }
+ }
+}
+
+static grn_rc
+grn_ts_expr_builder_push_single_accessor(grn_ctx *ctx,
+ grn_ts_expr_builder *builder,
+ grn_accessor *accessor)
+{
+ switch (accessor->action) {
+ case GRN_ACCESSOR_GET_ID: {
+ return grn_ts_expr_builder_push_id(ctx, builder);
+ }
+ case GRN_ACCESSOR_GET_SCORE: {
+ return grn_ts_expr_builder_push_score(ctx, builder);
+ }
+ case GRN_ACCESSOR_GET_KEY: {
+ if (accessor->obj != builder->curr_table) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table conflict");
+ }
+ return grn_ts_expr_builder_push_key(ctx, builder);
+ }
+ case GRN_ACCESSOR_GET_VALUE: {
+ if (accessor->obj != builder->curr_table) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table conflict");
+ }
+ return grn_ts_expr_builder_push_value(ctx, builder);
+ }
+ case GRN_ACCESSOR_GET_COLUMN_VALUE: {
+ return grn_ts_expr_builder_push_column(ctx, builder, accessor->obj);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid accessor action: %d",
+ accessor->action);
+ }
+ }
+}
+
+static grn_rc
+grn_ts_expr_builder_push_accessor(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_accessor *accessor)
+{
+ grn_rc rc = grn_ts_expr_builder_push_single_accessor(ctx, builder, accessor);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ for (accessor = accessor->next; accessor; accessor = accessor->next) {
+ rc = grn_ts_expr_builder_begin_subexpr(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_builder_push_single_accessor(ctx, builder, accessor);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_builder_end_subexpr(ctx, builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_builder_push_obj(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_obj *obj)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder || !obj) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ switch (obj->header.type) {
+ case GRN_BULK: {
+ return grn_ts_expr_builder_push_bulk(ctx, builder, obj);
+ }
+ case GRN_UVECTOR: {
+ return grn_ts_expr_builder_push_uvector(ctx, builder, obj);
+ }
+ case GRN_VECTOR: {
+ return grn_ts_expr_builder_push_vector(ctx, builder, obj);
+ }
+ case GRN_ACCESSOR: {
+ return grn_ts_expr_builder_push_accessor(ctx, builder,
+ (grn_accessor *)obj);
+ }
+ case GRN_COLUMN_FIX_SIZE:
+ case GRN_COLUMN_VAR_SIZE: {
+ return grn_ts_expr_builder_push_column(ctx, builder, obj);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid object type: %d",
+ obj->header.type);
+ }
+ }
+}
+
+grn_rc
+grn_ts_expr_builder_push_id(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_rc rc;
+ grn_ts_expr_node *node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_id_node_open(ctx, &node);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_expr_builder_push_node(ctx, builder, node);
+ }
+ return rc;
+}
+
+grn_rc
+grn_ts_expr_builder_push_score(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_rc rc;
+ grn_ts_expr_node *node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_score_node_open(ctx, &node);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_expr_builder_push_node(ctx, builder, node);
+ }
+ return rc;
+}
+
+grn_rc
+grn_ts_expr_builder_push_key(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_rc rc;
+ grn_ts_expr_node *node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_key_node_open(ctx, builder->curr_table, &node);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_expr_builder_push_node(ctx, builder, node);
+ }
+ return rc;
+}
+
+grn_rc
+grn_ts_expr_builder_push_value(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_rc rc;
+ grn_ts_expr_node *node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_value_node_open(ctx, builder->curr_table, &node);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_expr_builder_push_node(ctx, builder, node);
+ }
+ return rc;
+}
+
+grn_rc
+grn_ts_expr_builder_push_const(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_data_kind kind, grn_ts_data_type type,
+ grn_ts_any value)
+{
+ grn_rc rc;
+ grn_ts_expr_node *node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_const_node_open(ctx, kind, type, value, &node);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_expr_builder_push_node(ctx, builder, node);
+ }
+ return rc;
+}
+
+grn_rc
+grn_ts_expr_builder_push_column(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_obj *column)
+{
+ grn_rc rc;
+ grn_ts_expr_node *node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder || !column || !grn_ts_obj_is_column(ctx, column) ||
+ (DB_OBJ(builder->curr_table)->id != column->header.domain)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_column_node_open(ctx, column, &node);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_expr_builder_push_node(ctx, builder, node);
+ }
+ return rc;
+}
+
+/*
+ * grn_ts_expr_builder_get_max_n_args() returns the number of nodes in the
+ * current subexpression.
+ */
+static size_t
+grn_ts_expr_builder_get_max_n_args(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ size_t max_n_args = builder->n_nodes;
+ if (builder->n_bridges) {
+ max_n_args -= builder->bridges[builder->n_bridges - 1].n_nodes;
+ }
+ return max_n_args;
+}
+
+grn_rc
+grn_ts_expr_builder_push_op(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_op_type op_type)
+{
+ grn_rc rc;
+ grn_ts_expr_node **args, *node;
+ size_t n_args, max_n_args;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ n_args = grn_ts_op_get_n_args(op_type);
+ if (!n_args) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "invalid #arguments: %" GRN_FMT_SIZE,
+ n_args);
+ }
+ max_n_args = grn_ts_expr_builder_get_max_n_args(ctx, builder);
+ if (n_args > max_n_args) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "invalid #arguments: %" GRN_FMT_SIZE ", %" GRN_FMT_SIZE,
+ n_args, builder->n_nodes);
+ }
+ /* Arguments are the top n_args nodes in the stack. */
+ args = &builder->nodes[builder->n_nodes - n_args];
+ builder->n_nodes -= n_args;
+ rc = grn_ts_expr_op_node_open(ctx, op_type, args, n_args, &node);
+ if (rc == GRN_SUCCESS) {
+ builder->nodes[builder->n_nodes++] = node;
+ }
+ return rc;
+}
+
+/* grn_ts_expr_builder_push_bridge() pushes a bridge. */
+static grn_rc
+grn_ts_expr_builder_push_bridge(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_expr_bridge *bridge)
+{
+ if (builder->n_bridges == builder->max_n_bridges) {
+ size_t n_bytes, new_max_n_bridges;
+ grn_ts_expr_bridge *new_bridges;
+ new_max_n_bridges = builder->n_bridges ? (builder->n_bridges * 2) : 1;
+ n_bytes = sizeof(grn_ts_expr_bridge) * new_max_n_bridges;
+ new_bridges = (grn_ts_expr_bridge *)GRN_REALLOC(builder->bridges, n_bytes);
+ if (!new_bridges) {
+ grn_ts_expr_bridge_fin(ctx, bridge);
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes);
+ }
+ builder->bridges = new_bridges;
+ builder->max_n_bridges = new_max_n_bridges;
+ }
+ builder->bridges[builder->n_bridges++] = *bridge;
+ builder->curr_table = bridge->dest_table;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_builder_pop_bridge() pops a bridge. */
+static void
+grn_ts_expr_builder_pop_bridge(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_ts_expr_bridge *bridge = &builder->bridges[builder->n_bridges - 1];
+ builder->curr_table = bridge->src_table;
+ grn_ts_expr_bridge_fin(ctx, bridge);
+ builder->n_bridges--;
+}
+
+grn_rc
+grn_ts_expr_builder_begin_subexpr(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_rc rc;
+ size_t max_n_args;
+ grn_obj *obj;
+ grn_ts_expr_node *node;
+ grn_ts_expr_bridge bridge;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ max_n_args = grn_ts_expr_builder_get_max_n_args(ctx, builder);
+ if (!max_n_args) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ /* Check whehter or not the latest node refers to a table. */
+ node = builder->nodes[builder->n_nodes - 1];
+ if ((node->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ obj = grn_ctx_at(ctx, node->data_type);
+ if (!obj) {
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d",
+ node->data_type);
+ }
+ if (!grn_ts_obj_is_table(ctx, obj)) {
+ grn_obj_unlink(ctx, obj);
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d", node->data_type);
+ }
+ /* Creates a bridge to a subexpression. */
+ grn_ts_expr_bridge_init(ctx, &bridge);
+ bridge.src_table = builder->curr_table;
+ bridge.dest_table = obj;
+ bridge.n_nodes = builder->n_nodes;
+ rc = grn_ts_expr_builder_push_bridge(ctx, builder, &bridge);
+ if (rc != GRN_SUCCESS) {
+ grn_obj_unlink(ctx, obj);
+ return rc;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_builder_end_subexpr(grn_ctx *ctx, grn_ts_expr_builder *builder)
+{
+ grn_rc rc;
+ grn_ts_expr_node **args, *node;
+ if (!ctx || !builder || (builder->n_nodes < 2) || !builder->n_bridges) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ /* Check whehter or not the subexpression is complete.*/
+ if (grn_ts_expr_builder_get_max_n_args(ctx, builder) != 1) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ /* Creates a bridge node. */
+ args = &builder->nodes[builder->n_nodes - 2];
+ rc = grn_ts_expr_bridge_node_open(ctx, args[0], args[1], &node);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ /* Note: The following grn_ts_expr_push_node() must not fail. */
+ builder->n_nodes -= 2;
+ grn_ts_expr_builder_push_node(ctx, builder, node);
+ grn_ts_expr_builder_pop_bridge(ctx, builder);
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.h b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.h
new file mode 100644
index 00000000..f9795ed1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_builder.h
@@ -0,0 +1,128 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_buf.h"
+#include "ts_expr.h"
+#include "ts_expr_node.h"
+#include "ts_op.h"
+#include "ts_str.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ grn_obj *src_table; /* The source table of a bridge (no ref. count). */
+ grn_obj *dest_table; /* The destination table of a bridge. */
+ size_t n_nodes; /* The stack depth (position) of a bridge. */
+} grn_ts_expr_bridge;
+
+typedef struct {
+ grn_obj *table; /* Associated table. */
+ grn_obj *curr_table; /* Current table (no ref. count). */
+ grn_ts_expr_node **nodes; /* Node stack. */
+ size_t n_nodes; /* Number of nodes (stack depth). */
+ size_t max_n_nodes; /* Maximum number of nodes (stack capacity). */
+ grn_ts_expr_bridge *bridges; /* Bridges to subexpressions. */
+ size_t n_bridges; /* Number of bridges (subexpression depth). */
+ size_t max_n_bridges; /* Max. number (capacity) of bridges. */
+} grn_ts_expr_builder;
+
+/* grn_ts_expr_builder_open() creates an expression builder. */
+grn_rc grn_ts_expr_builder_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_builder **builder);
+
+/* grn_ts_expr_builder_close() destroys an expression builder. */
+grn_rc grn_ts_expr_builder_close(grn_ctx *ctx, grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_complete() completes an expression. */
+grn_rc grn_ts_expr_builder_complete(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_expr **expr);
+
+/* grn_ts_expr_builder_clear() clears the internal states. */
+grn_rc grn_ts_expr_builder_clear(grn_ctx *ctx, grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_push_name() pushes a named object. */
+grn_rc grn_ts_expr_builder_push_name(grn_ctx *ctx,
+ grn_ts_expr_builder *builder,
+ grn_ts_str name);
+
+/*
+ * grn_ts_expr_builder_push_obj() pushes an object.
+ *
+ * Acceptable objects are as follows:
+ * - Consts
+ * - GRN_BULK: GRN_DB_*.
+ * - GRN_UVECTOR: GRN_DB_* except GRN_DB_[SHORT/LONG_]TEXT.
+ * - GRN_VECTOR: GRN_DB_[SHORT/LONG_]TEXT.
+ * - Columns
+ * - GRN_ACCESSOR: _id, _score, _key, _value, and columns.
+ * - GRN_COLUMN_FIX_SIZE: GRN_DB_* except GRN_DB_[SHORT/LONG_]TEXT.
+ * - GRN_COLUMN_VAR_SIZE: GRN_DB_[SHORT/LONG_]TEXT.
+ */
+grn_rc grn_ts_expr_builder_push_obj(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_obj *obj);
+
+/* grn_ts_expr_builder_push_id() pushes "_id". */
+grn_rc grn_ts_expr_builder_push_id(grn_ctx *ctx, grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_push_score() pushes "_score". */
+grn_rc grn_ts_expr_builder_push_score(grn_ctx *ctx,
+ grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_push_key() pushes "_key". */
+grn_rc grn_ts_expr_builder_push_key(grn_ctx *ctx,
+ grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_push_value() pushes "_value". */
+grn_rc grn_ts_expr_builder_push_value(grn_ctx *ctx,
+ grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_push_const() pushes a const. */
+grn_rc grn_ts_expr_builder_push_const(grn_ctx *ctx,
+ grn_ts_expr_builder *builder,
+ grn_ts_data_kind kind,
+ grn_ts_data_type type,
+ grn_ts_any value);
+
+/* grn_ts_expr_builder_push_column() pushes a column. */
+grn_rc grn_ts_expr_builder_push_column(grn_ctx *ctx,
+ grn_ts_expr_builder *builder,
+ grn_obj *column);
+
+/* grn_ts_expr_builder_push_op() pushes an operator. */
+grn_rc grn_ts_expr_builder_push_op(grn_ctx *ctx, grn_ts_expr_builder *builder,
+ grn_ts_op_type op_type);
+
+/* grn_ts_expr_builder_begin_subexpr() begins a subexpression. */
+grn_rc grn_ts_expr_builder_begin_subexpr(grn_ctx *ctx,
+ grn_ts_expr_builder *builder);
+
+/* grn_ts_expr_builder_end_subexpr() ends a subexpression. */
+grn_rc grn_ts_expr_builder_end_subexpr(grn_ctx *ctx,
+ grn_ts_expr_builder *builder);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c
new file mode 100644
index 00000000..c38d9709
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.c
@@ -0,0 +1,5325 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_expr_node.h"
+
+#include <math.h>
+#include <string.h>
+
+#include "../grn_ctx.h"
+#include "../grn_dat.h"
+#include "../grn_db.h"
+#include "../grn_geo.h"
+#include "../grn_hash.h"
+#include "../grn_pat.h"
+#include "../grn_store.h"
+
+#include "ts_log.h"
+#include "ts_str.h"
+#include "ts_util.h"
+
+/*-------------------------------------------------------------
+ * Built-in data kinds.
+ */
+
+/* grn_ts_bool_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_bool_is_valid(grn_ts_bool value)
+{
+ return GRN_TRUE;
+}
+
+/* grn_ts_int_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_int_is_valid(grn_ts_int value)
+{
+ return GRN_TRUE;
+}
+
+/* grn_ts_float_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_float_is_valid(grn_ts_float value)
+{
+ return isfinite(value);
+}
+
+/* grn_ts_time_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_time_is_valid(grn_ts_time value)
+{
+ return GRN_TRUE;
+}
+
+/* grn_ts_text_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_text_is_valid(grn_ts_text value)
+{
+ return value.ptr || !value.size;
+}
+
+/* grn_ts_geo_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_geo_is_valid(grn_ts_geo value)
+{
+ return ((value.latitude >= GRN_GEO_MIN_LATITUDE) &&
+ (value.latitude <= GRN_GEO_MAX_LATITUDE)) &&
+ ((value.longitude >= GRN_GEO_MIN_LONGITUDE) &&
+ (value.longitude <= GRN_GEO_MAX_LONGITUDE));
+}
+
+#define GRN_TS_VECTOR_IS_VALID(type)\
+ if (value.size) {\
+ size_t i;\
+ if (!value.ptr) {\
+ return GRN_FALSE;\
+ }\
+ for (i = 0; i < value.size; i++) {\
+ if (!grn_ts_ ## type ## _is_valid(value.ptr[i])) {\
+ return GRN_FALSE;\
+ }\
+ }\
+ }\
+ return GRN_TRUE;
+/* grn_ts_bool_vector_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_bool_vector_is_valid(grn_ts_bool_vector value)
+{
+ GRN_TS_VECTOR_IS_VALID(bool)
+}
+
+/* grn_ts_int_vector_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_int_vector_is_valid(grn_ts_int_vector value)
+{
+ GRN_TS_VECTOR_IS_VALID(int)
+}
+
+/* grn_ts_float_vector_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_float_vector_is_valid(grn_ts_float_vector value)
+{
+ GRN_TS_VECTOR_IS_VALID(float)
+}
+
+/* grn_ts_time_vector_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_time_vector_is_valid(grn_ts_time_vector value)
+{
+ GRN_TS_VECTOR_IS_VALID(time)
+}
+
+/* grn_ts_text_vector_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_text_vector_is_valid(grn_ts_text_vector value)
+{
+ GRN_TS_VECTOR_IS_VALID(text)
+}
+
+/* grn_ts_geo_vector_is_valid() returns whether a value is valid or not. */
+inline static grn_ts_bool
+grn_ts_geo_vector_is_valid(grn_ts_geo_vector value)
+{
+ GRN_TS_VECTOR_IS_VALID(geo)
+}
+#undef GRN_TS_VECTOR_IS_VALID
+
+/* grn_ts_bool_zero() returns a zero. */
+inline static grn_ts_bool
+grn_ts_bool_zero(void)
+{
+ return GRN_FALSE;
+}
+
+/* grn_ts_int_zero() returns a zero. */
+inline static grn_ts_int
+grn_ts_int_zero(void)
+{
+ return 0;
+}
+
+/* grn_ts_float_zero() returns a zero. */
+inline static grn_ts_float
+grn_ts_float_zero(void)
+{
+ return 0.0;
+}
+
+/* grn_ts_time_zero() returns a zero. */
+inline static grn_ts_time
+grn_ts_time_zero(void)
+{
+ return 0;
+}
+
+/* grn_ts_text_zero() returns a zero. */
+inline static grn_ts_text
+grn_ts_text_zero(void)
+{
+ return (grn_ts_text){ NULL, 0 };
+}
+
+/* grn_ts_geo_zero() returns a zero. */
+inline static grn_ts_geo
+grn_ts_geo_zero(void)
+{
+ return (grn_ts_geo){ 0, 0 };
+}
+
+/* grn_ts_ref_zero() returns a zero. */
+inline static grn_ts_ref
+grn_ts_ref_zero(void)
+{
+ return (grn_ts_ref){ 0, 0.0 };
+}
+
+/* grn_ts_data_type_to_kind() returns a kind associated with a type. */
+static grn_ts_data_kind
+grn_ts_data_type_to_kind(grn_ts_data_type type)
+{
+ switch (type) {
+ case GRN_DB_VOID: {
+ return GRN_TS_VOID;
+ }
+ case GRN_DB_BOOL: {
+ return GRN_TS_BOOL;
+ }
+ case GRN_DB_INT8:
+ case GRN_DB_INT16:
+ case GRN_DB_INT32:
+ case GRN_DB_INT64:
+ case GRN_DB_UINT8:
+ case GRN_DB_UINT16:
+ case GRN_DB_UINT32:
+ case GRN_DB_UINT64: {
+ return GRN_TS_INT;
+ }
+ case GRN_DB_FLOAT: {
+ return GRN_TS_FLOAT;
+ }
+ case GRN_DB_TIME: {
+ return GRN_TS_TIME;
+ }
+ case GRN_DB_SHORT_TEXT:
+ case GRN_DB_TEXT:
+ case GRN_DB_LONG_TEXT: {
+ return GRN_TS_TEXT;
+ }
+ case GRN_DB_TOKYO_GEO_POINT:
+ case GRN_DB_WGS84_GEO_POINT: {
+ return GRN_TS_GEO;
+ }
+ default: {
+ return GRN_TS_REF;
+ }
+ }
+}
+
+/* grn_ts_data_kind_to_type() returns a type associated with a kind. */
+static grn_ts_data_type
+grn_ts_data_kind_to_type(grn_ts_data_kind kind)
+{
+ switch (kind & ~GRN_TS_VECTOR_FLAG) {
+ case GRN_TS_BOOL: {
+ return GRN_DB_BOOL;
+ }
+ case GRN_TS_INT: {
+ return GRN_DB_INT64;
+ }
+ case GRN_TS_FLOAT: {
+ return GRN_DB_FLOAT;
+ }
+ case GRN_TS_TIME: {
+ return GRN_DB_TIME;
+ }
+ case GRN_TS_TEXT: {
+ return GRN_DB_TEXT;
+ }
+ case GRN_TS_GEO: {
+ /* GRN_DB_TOKYO_GEO_POINT or GRN_DB_WGS84_GEO_POINT. */
+ return GRN_DB_VOID;
+ }
+ case GRN_TS_REF: {
+ /*
+ * grn_ts_data_kind does not have enough information to get a correct
+ * table ID.
+ */
+ return GRN_DB_VOID;
+ }
+ default: {
+ return GRN_DB_VOID;
+ }
+ }
+}
+
+/*-------------------------------------------------------------
+ * Operators.
+ */
+
+/* grn_ts_op_logical_not_bool() returns !arg. */
+inline static grn_ts_bool
+grn_ts_op_logical_not_bool(grn_ts_bool arg)
+{
+ return !arg;
+}
+
+/* grn_ts_op_bitwise_not_bool() returns ~arg. */
+inline static grn_ts_bool
+grn_ts_op_bitwise_not_bool(grn_ts_bool arg)
+{
+ return !arg;
+}
+
+/* grn_ts_op_bitwise_not_int() returns ~arg. */
+inline static grn_ts_int
+grn_ts_op_bitwise_not_int(grn_ts_int arg)
+{
+ return ~arg;
+}
+
+/* grn_ts_op_positive_int() returns +arg. */
+inline static grn_ts_int
+grn_ts_op_positive_int(grn_ts_int arg)
+{
+ return arg;
+}
+
+/* grn_ts_op_positive_float() returns +arg. */
+inline static grn_ts_float
+grn_ts_op_positive_float(grn_ts_float arg)
+{
+ return arg;
+}
+
+/* grn_ts_op_negative_int() returns -arg. */
+inline static grn_ts_int
+grn_ts_op_negative_int(grn_ts_int arg)
+{
+ return -arg;
+}
+
+/* grn_ts_op_negative_float() returns -arg. */
+inline static grn_ts_float
+grn_ts_op_negative_float(grn_ts_float arg)
+{
+ return -arg;
+}
+
+/* grn_ts_op_float() returns (Float)arg. */
+static grn_rc
+grn_ts_op_float(grn_ctx *ctx, grn_ts_int arg, grn_ts_float *out)
+{
+ *out = (grn_ts_float)arg;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_time() returns (Time)arg. */
+static grn_rc
+grn_ts_op_time(grn_ctx *ctx, grn_ts_text arg, grn_ts_time *out)
+{
+ grn_timeval value;
+ grn_rc rc = grn_str2timeval(arg.ptr, arg.size, &value);
+ if (rc != GRN_SUCCESS) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "grn_str2timeval failed");
+ }
+ *out = (grn_ts_time)((value.tv_sec * 1000000) + (value.tv_nsec / 1000));
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_bitwise_and_bool() returns lhs & rhs. */
+inline static grn_ts_bool
+grn_ts_op_bitwise_and_bool(grn_ts_bool lhs, grn_ts_bool rhs)
+{
+ return lhs & rhs;
+}
+
+/* grn_ts_op_bitwise_and_int() returns lhs & rhs. */
+inline static grn_ts_int
+grn_ts_op_bitwise_and_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs & rhs;
+}
+
+/* grn_ts_op_bitwise_or_bool() returns lhs | rhs. */
+inline static grn_ts_bool
+grn_ts_op_bitwise_or_bool(grn_ts_bool lhs, grn_ts_bool rhs)
+{
+ return lhs | rhs;
+}
+
+/* grn_ts_op_bitwise_or_int() returns lhs | rhs. */
+inline static grn_ts_int
+grn_ts_op_bitwise_or_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs | rhs;
+}
+
+/* grn_ts_op_bitwise_xor_bool() returns lhs ^ rhs. */
+inline static grn_ts_bool
+grn_ts_op_bitwise_xor_bool(grn_ts_bool lhs, grn_ts_bool rhs)
+{
+ return lhs ^ rhs;
+}
+
+/* grn_ts_op_bitwise_xor_int() returns lhs ^ rhs. */
+inline static grn_ts_int
+grn_ts_op_bitwise_xor_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs ^ rhs;
+}
+
+/* grn_ts_op_equal_bool() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_bool(grn_ts_bool lhs, grn_ts_bool rhs)
+{
+ return lhs == rhs;
+}
+
+/* grn_ts_op_equal_int() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs == rhs;
+}
+
+/* grn_ts_op_equal_float() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_float(grn_ts_float lhs, grn_ts_float rhs)
+{
+ /* To suppress warnings, "lhs == rhs" is not used. */
+ return (lhs <= rhs) && (lhs >= rhs);
+}
+
+/* grn_ts_op_equal_time() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_time(grn_ts_time lhs, grn_ts_time rhs)
+{
+ return lhs == rhs;
+}
+
+/* grn_ts_op_equal_text() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_text(grn_ts_text lhs, grn_ts_text rhs)
+{
+ return (lhs.size == rhs.size) && !memcmp(lhs.ptr, rhs.ptr, lhs.size);
+}
+
+/* grn_ts_op_equal_geo() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_geo(grn_ts_geo lhs, grn_ts_geo rhs)
+{
+ return (lhs.latitude == rhs.latitude) && (lhs.longitude == rhs.longitude);
+}
+
+/* grn_ts_op_equal_ref() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_ref(grn_ts_ref lhs, grn_ts_ref rhs)
+{
+ /* Ignore scores. */
+ return lhs.id == rhs.id;
+}
+
+#define GRN_TS_OP_EQUAL_VECTOR(kind)\
+ size_t i;\
+ if (lhs.size != rhs.size) {\
+ return GRN_FALSE;\
+ }\
+ for (i = 0; i < lhs.size; i++) {\
+ if (!grn_ts_op_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ return GRN_FALSE;\
+ }\
+ }\
+ return GRN_TRUE;
+/* grn_ts_op_equal_bool_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_bool_vector(grn_ts_bool_vector lhs, grn_ts_bool_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(bool)
+}
+
+/* grn_ts_op_equal_int_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(int)
+}
+
+/* grn_ts_op_equal_float_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_float_vector(grn_ts_float_vector lhs, grn_ts_float_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(float)
+}
+
+/* grn_ts_op_equal_time_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(time)
+}
+
+/* grn_ts_op_equal_text_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(text)
+}
+
+/* grn_ts_op_equal_geo_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_geo_vector(grn_ts_geo_vector lhs, grn_ts_geo_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(geo)
+}
+
+/* grn_ts_op_equal_ref_vector() returns lhs == rhs. */
+inline static grn_ts_bool
+grn_ts_op_equal_ref_vector(grn_ts_ref_vector lhs, grn_ts_ref_vector rhs)
+{
+ GRN_TS_OP_EQUAL_VECTOR(ref)
+}
+#undef GRN_TS_OP_EQUAL_VECTOR
+
+/* grn_ts_op_not_equal_bool() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_bool(grn_ts_bool lhs, grn_ts_bool rhs)
+{
+ return lhs != rhs;
+}
+
+/* grn_ts_op_not_equal_int() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs != rhs;
+}
+
+/* grn_ts_op_not_equal_float() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_float(grn_ts_float lhs, grn_ts_float rhs)
+{
+ /* To suppress warnings, "lhs != rhs" is not used. */
+ return !grn_ts_op_equal_float(lhs, rhs);
+}
+
+/* grn_ts_op_not_equal_time() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_time(grn_ts_time lhs, grn_ts_time rhs)
+{
+ return lhs != rhs;
+}
+
+/* grn_ts_op_not_equal_text() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_text(grn_ts_text lhs, grn_ts_text rhs)
+{
+ return (lhs.size != rhs.size) || memcmp(lhs.ptr, rhs.ptr, lhs.size);
+}
+
+/* grn_ts_op_not_equal_geo() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_geo(grn_ts_geo lhs, grn_ts_geo rhs)
+{
+ return (lhs.latitude != rhs.latitude) || (lhs.longitude != rhs.longitude);
+}
+
+/* grn_ts_op_not_equal_ref() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_ref(grn_ts_ref lhs, grn_ts_ref rhs)
+{
+ /* Ignore scores. */
+ return lhs.id != rhs.id;
+}
+
+#define GRN_TS_OP_NOT_EQUAL_VECTOR(kind)\
+ size_t i;\
+ if (lhs.size != rhs.size) {\
+ return GRN_TRUE;\
+ }\
+ for (i = 0; i < lhs.size; i++) {\
+ if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ return GRN_TRUE;\
+ }\
+ }\
+ return GRN_FALSE;
+/* grn_ts_op_not_equal_bool_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_bool_vector(grn_ts_bool_vector lhs, grn_ts_bool_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(bool)
+}
+
+/* grn_ts_op_not_equal_int_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(int)
+}
+
+/* grn_ts_op_not_equal_float_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_float_vector(grn_ts_float_vector lhs,
+ grn_ts_float_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(float)
+}
+
+/* grn_ts_op_not_equal_time_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(time)
+}
+
+/* grn_ts_op_not_equal_text_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(text)
+}
+
+/* grn_ts_op_not_equal_geo_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_geo_vector(grn_ts_geo_vector lhs, grn_ts_geo_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(geo)
+}
+
+/* grn_ts_op_not_equal_ref_vector() returns lhs != rhs. */
+inline static grn_ts_bool
+grn_ts_op_not_equal_ref_vector(grn_ts_ref_vector lhs, grn_ts_ref_vector rhs)
+{
+ GRN_TS_OP_NOT_EQUAL_VECTOR(ref)
+}
+#undef GRN_TS_OP_NOT_EQUAL_VECTOR
+
+/* grn_ts_op_less_int() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs < rhs;
+}
+
+/* grn_ts_op_less_float() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_float(grn_ts_float lhs, grn_ts_float rhs)
+{
+ return lhs < rhs;
+}
+
+/* grn_ts_op_less_time() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_time(grn_ts_time lhs, grn_ts_time rhs)
+{
+ return lhs < rhs;
+}
+
+/* grn_ts_op_less_text() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_text(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
+ int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
+ return cmp ? (cmp < 0) : (lhs.size < rhs.size);
+}
+
+#define GRN_TS_OP_LESS_VECTOR(kind)\
+ size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
+ for (i = 0; i < min_size; i++) {\
+ if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ if (grn_ts_op_less_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ return GRN_TRUE;\
+ }\
+ }\
+ }\
+ return lhs.size < rhs.size;
+/* grn_ts_op_less_int_vector() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs)
+{
+ GRN_TS_OP_LESS_VECTOR(int)
+}
+
+/* grn_ts_op_less_float_vector() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_float_vector(grn_ts_float_vector lhs, grn_ts_float_vector rhs)
+{
+ GRN_TS_OP_LESS_VECTOR(float)
+}
+
+/* grn_ts_op_less_time_vector() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs)
+{
+ GRN_TS_OP_LESS_VECTOR(time)
+}
+
+/* grn_ts_op_less_text_vector() returns lhs < rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs)
+{
+ GRN_TS_OP_LESS_VECTOR(text)
+}
+#undef GRN_TS_OP_LESS_VECTOR
+
+/* grn_ts_op_less_equal_int() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs <= rhs;
+}
+
+/* grn_ts_op_less_equal_float() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_float(grn_ts_float lhs, grn_ts_float rhs)
+{
+ return lhs <= rhs;
+}
+
+/* grn_ts_op_less_equal_time() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_time(grn_ts_time lhs, grn_ts_time rhs)
+{
+ return lhs <= rhs;
+}
+
+/* grn_ts_op_less_equal_text() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_text(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
+ int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
+ return cmp ? (cmp < 0) : (lhs.size <= rhs.size);
+}
+
+#define GRN_TS_OP_LESS_EQUAL_VECTOR(kind)\
+ size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
+ for (i = 0; i < min_size; i++) {\
+ if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ if (grn_ts_op_less_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ return GRN_TRUE;\
+ }\
+ }\
+ }\
+ return lhs.size <= rhs.size;
+/* grn_ts_op_less_equal_int_vector() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs)
+{
+ GRN_TS_OP_LESS_EQUAL_VECTOR(int)
+}
+
+/* grn_ts_op_less_equal_float_vector() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_float_vector(grn_ts_float_vector lhs,
+ grn_ts_float_vector rhs)
+{
+ GRN_TS_OP_LESS_EQUAL_VECTOR(float)
+}
+
+/* grn_ts_op_less_equal_time_vector() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_time_vector(grn_ts_time_vector lhs,
+ grn_ts_time_vector rhs)
+{
+ GRN_TS_OP_LESS_EQUAL_VECTOR(time)
+}
+
+/* grn_ts_op_less_equal_text_vector() returns lhs <= rhs. */
+inline static grn_ts_bool
+grn_ts_op_less_equal_text_vector(grn_ts_text_vector lhs,
+ grn_ts_text_vector rhs)
+{
+ GRN_TS_OP_LESS_EQUAL_VECTOR(text)
+}
+#undef GRN_TS_OP_LESS_EQUAL_VECTOR
+
+/* grn_ts_op_greater_int() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs > rhs;
+}
+
+/* grn_ts_op_greater_float() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_float(grn_ts_float lhs, grn_ts_float rhs)
+{
+ return lhs > rhs;
+}
+
+/* grn_ts_op_greater_time() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_time(grn_ts_time lhs, grn_ts_time rhs)
+{
+ return lhs > rhs;
+}
+
+/* grn_ts_op_greater_text() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_text(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
+ int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
+ return cmp ? (cmp > 0) : (lhs.size > rhs.size);
+}
+
+#define GRN_TS_OP_GREATER_VECTOR(kind)\
+ size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
+ for (i = 0; i < min_size; i++) {\
+ if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ if (grn_ts_op_greater_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ return GRN_TRUE;\
+ }\
+ }\
+ }\
+ return lhs.size > rhs.size;
+/* grn_ts_op_greater_int_vector() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_int_vector(grn_ts_int_vector lhs, grn_ts_int_vector rhs)
+{
+ GRN_TS_OP_GREATER_VECTOR(int)
+}
+
+/* grn_ts_op_greater_float_vector() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_float_vector(grn_ts_float_vector lhs,
+ grn_ts_float_vector rhs)
+{
+ GRN_TS_OP_GREATER_VECTOR(float)
+}
+
+/* grn_ts_op_greater_time_vector() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_time_vector(grn_ts_time_vector lhs, grn_ts_time_vector rhs)
+{
+ GRN_TS_OP_GREATER_VECTOR(time)
+}
+
+/* grn_ts_op_greater_text_vector() returns lhs > rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_text_vector(grn_ts_text_vector lhs, grn_ts_text_vector rhs)
+{
+ GRN_TS_OP_GREATER_VECTOR(text)
+}
+#undef GRN_TS_OP_GREATER_VECTOR
+
+/* grn_ts_op_greater_equal_int() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_int(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs >= rhs;
+}
+
+/* grn_ts_op_greater_equal_float() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_float(grn_ts_float lhs, grn_ts_float rhs)
+{
+ return lhs >= rhs;
+}
+
+/* grn_ts_op_greater_equal_time() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_time(grn_ts_time lhs, grn_ts_time rhs)
+{
+ return lhs >= rhs;
+}
+
+/* grn_ts_op_greater_equal_text() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_text(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
+ int cmp = memcmp(lhs.ptr, rhs.ptr, min_size);
+ return cmp ? (cmp > 0) : (lhs.size >= rhs.size);
+}
+
+#define GRN_TS_OP_GREATER_EQUAL_VECTOR(kind)\
+ size_t i, min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;\
+ for (i = 0; i < min_size; i++) {\
+ if (grn_ts_op_not_equal_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ if (grn_ts_op_greater_ ## kind(lhs.ptr[i], rhs.ptr[i])) {\
+ return GRN_TRUE;\
+ }\
+ }\
+ }\
+ return lhs.size >= rhs.size;
+/* grn_ts_op_greater_equal_int_vector() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_int_vector(grn_ts_int_vector lhs,
+ grn_ts_int_vector rhs)
+{
+ GRN_TS_OP_GREATER_EQUAL_VECTOR(int)
+}
+
+/* grn_ts_op_greater_equal_float_vector() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_float_vector(grn_ts_float_vector lhs,
+ grn_ts_float_vector rhs)
+{
+ GRN_TS_OP_GREATER_EQUAL_VECTOR(float)
+}
+
+/* grn_ts_op_greater_equal_time_vector() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_time_vector(grn_ts_time_vector lhs,
+ grn_ts_time_vector rhs)
+{
+ GRN_TS_OP_GREATER_EQUAL_VECTOR(time)
+}
+
+/* grn_ts_op_greater_equal_text_vector() returns lhs >= rhs. */
+inline static grn_ts_bool
+grn_ts_op_greater_equal_text_vector(grn_ts_text_vector lhs,
+ grn_ts_text_vector rhs)
+{
+ GRN_TS_OP_GREATER_EQUAL_VECTOR(text)
+}
+#undef GRN_TS_OP_GREATER_EQUAL_VECTOR
+
+/* grn_ts_op_shift_arithmetic_left() returns lhs << rhs. */
+inline static grn_ts_int
+grn_ts_op_shift_arithmetic_left(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs << rhs;
+}
+
+/* grn_ts_op_shift_arithmetic_right() returns lhs << rhs. */
+inline static grn_ts_int
+grn_ts_op_shift_arithmetic_right(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs >> rhs;
+}
+
+/* grn_ts_op_shift_logical_left() returns lhs << rhs. */
+inline static grn_ts_int
+grn_ts_op_shift_logical_left(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return lhs << rhs;
+}
+
+/* grn_ts_op_shift_logical_right() returns lhs << rhs. */
+inline static grn_ts_int
+grn_ts_op_shift_logical_right(grn_ts_int lhs, grn_ts_int rhs)
+{
+ return (uint64_t)lhs >> rhs;
+}
+
+inline static grn_rc
+grn_ts_op_plus_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs,
+ grn_ts_int *out)
+{
+ *out = lhs + rhs;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_plus_float_float(grn_ctx *ctx, grn_ts_float lhs, grn_ts_float rhs,
+ grn_ts_float *out)
+{
+ *out = lhs + rhs;
+ if (!grn_ts_float_is_valid(*out)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g + %g = %g", lhs, rhs, *out);
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_plus_time_int(grn_ctx *ctx, grn_ts_time lhs, grn_ts_int rhs,
+ grn_ts_time *out)
+{
+ *out = lhs + (rhs * 1000000);
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_plus_time_float(grn_ctx *ctx, grn_ts_time lhs, grn_ts_float rhs,
+ grn_ts_time *out)
+{
+ *out = (grn_ts_time)(lhs + (rhs * 1000000.0));
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_minus_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs,
+ grn_ts_int *out)
+{
+ *out = lhs - rhs;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_minus_float_float(grn_ctx *ctx, grn_ts_float lhs, grn_ts_float rhs,
+ grn_ts_float *out)
+{
+ *out = lhs - rhs;
+ if (!grn_ts_float_is_valid(*out)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g - %g = %g", lhs, rhs, *out);
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_minus_time_time(grn_ctx *ctx, grn_ts_time lhs, grn_ts_time rhs,
+ grn_ts_float *out)
+{
+ *out = (lhs - rhs) * 0.000001;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_minus_time_int(grn_ctx *ctx, grn_ts_time lhs, grn_ts_int rhs,
+ grn_ts_time *out)
+{
+ *out = lhs - (rhs * 1000000);
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_minus_time_float(grn_ctx *ctx, grn_ts_time lhs, grn_ts_float rhs,
+ grn_ts_time *out)
+{
+ *out = lhs - (grn_ts_int)(rhs * 1000000.0);
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_multiplication_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs,
+ grn_ts_int *out)
+{
+ *out = lhs * rhs;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_multiplication_float_float(grn_ctx *ctx, grn_ts_float lhs,
+ grn_ts_float rhs, grn_ts_float *out)
+{
+ *out = lhs * rhs;
+ if (!grn_ts_float_is_valid(*out)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g * %g = %g", lhs, rhs, *out);
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_division_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs,
+ grn_ts_int *out)
+{
+ if (!rhs) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "%" GRN_FMT_INT64D " / %" GRN_FMT_INT64D
+ " causes division by zero",
+ lhs, rhs);
+ }
+ *out = (rhs != -1) ? (lhs / rhs) : -lhs;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_division_float_float(grn_ctx *ctx, grn_ts_float lhs,
+ grn_ts_float rhs, grn_ts_float *out)
+{
+ *out = lhs / rhs;
+ if (!grn_ts_float_is_valid(*out)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g / %g = %g", lhs, rhs, *out);
+ }
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_modulus_int_int(grn_ctx *ctx, grn_ts_int lhs, grn_ts_int rhs,
+ grn_ts_int *out)
+{
+ if (!rhs) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "%" GRN_FMT_INT64D " %% %" GRN_FMT_INT64D
+ " causes division by zero",
+ lhs, rhs);
+ }
+ *out = (rhs != -1) ? (lhs % rhs) : -lhs;
+ return GRN_SUCCESS;
+}
+
+inline static grn_rc
+grn_ts_op_modulus_float_float(grn_ctx *ctx, grn_ts_float lhs, grn_ts_float rhs,
+ grn_ts_float *out)
+{
+ *out = fmod(lhs, rhs);
+ if (!grn_ts_float_is_valid(*out)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "%g %% %g = %g", lhs, rhs, *out);
+ }
+ return GRN_SUCCESS;
+}
+
+static grn_ts_bool
+grn_ts_op_match(grn_ts_text lhs, grn_ts_text rhs)
+{
+ const char *lhs_ptr, *lhs_ptr_last;
+ if (lhs.size < rhs.size) {
+ return GRN_FALSE;
+ }
+ lhs_ptr_last = lhs.ptr + lhs.size - rhs.size;
+ for (lhs_ptr = lhs.ptr; lhs_ptr <= lhs_ptr_last; lhs_ptr++) {
+ size_t i;
+ for (i = 0; i < rhs.size; i++) {
+ if (lhs_ptr[i] != rhs.ptr[i]) {
+ break;
+ }
+ }
+ if (i == rhs.size) {
+ return GRN_TRUE;
+ }
+ }
+ return GRN_FALSE;
+}
+
+static grn_ts_bool
+grn_ts_op_prefix_match(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t i;
+ if (lhs.size < rhs.size) {
+ return GRN_FALSE;
+ }
+ for (i = 0; i < rhs.size; i++) {
+ if (lhs.ptr[i] != rhs.ptr[i]) {
+ return GRN_FALSE;
+ }
+ }
+ return GRN_TRUE;
+}
+
+static grn_ts_bool
+grn_ts_op_suffix_match(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t i;
+ const char *lhs_ptr;
+ if (lhs.size < rhs.size) {
+ return GRN_FALSE;
+ }
+ lhs_ptr = lhs.ptr + lhs.size - rhs.size;
+ for (i = 0; i < rhs.size; i++) {
+ if (lhs_ptr[i] != rhs.ptr[i]) {
+ return GRN_FALSE;
+ }
+ }
+ return GRN_TRUE;
+}
+
+/*-------------------------------------------------------------
+ * Groonga objects.
+ */
+
+#define GRN_TS_TABLE_GET_KEY(type)\
+ uint32_t key_size;\
+ const void *key_ptr = _grn_ ## type ## _key(ctx, type, id, &key_size);\
+ if (!key_ptr) {\
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "_grn_" #type "_key failed: %u", id);\
+ }\
+/* grn_ts_hash_get_bool_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_bool_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_bool *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const grn_ts_bool *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_int8_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_int8_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const int8_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_int16_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_int16_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const int16_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_int32_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_int32_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const int32_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_int64_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_int64_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const int64_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_uint8_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_uint8_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const uint8_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_uint16_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_uint16_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const uint16_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_uint32_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_uint32_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const uint32_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_uint64_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_uint64_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = (grn_ts_int)*(const uint64_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_float_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_float_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_float *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const grn_ts_float *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_time_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_time_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_time *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const grn_ts_time *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_geo_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_geo_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_geo *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ *key = *(const grn_ts_geo *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_text_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_text_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_text *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ key->ptr = key_ptr;
+ key->size = key_size;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_hash_get_ref_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_hash_get_ref_key(grn_ctx *ctx, grn_hash *hash, grn_ts_id id,
+ grn_ts_ref *key)
+{
+ GRN_TS_TABLE_GET_KEY(hash)
+ key->id = *(const grn_ts_id *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_bool_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_bool_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_bool *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ *key = *(const grn_ts_bool *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_int8_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_int8_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ int8_t tmp;
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntohi(&tmp, key_ptr, sizeof(tmp));
+ *key = tmp;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_int16_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_int16_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ int16_t tmp;
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntohi(&tmp, key_ptr, sizeof(tmp));
+ *key = tmp;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_int32_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_int32_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ int32_t tmp;
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntohi(&tmp, key_ptr, sizeof(tmp));
+ *key = tmp;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_int64_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_int64_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntohi(key, key_ptr, sizeof(grn_ts_int));
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_uint8_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_uint8_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ *key = *(const uint8_t *)key_ptr;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_uint16_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_uint16_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ uint16_t tmp;
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntoh(&tmp, key_ptr, sizeof(tmp));
+ *key = tmp;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_uint32_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_uint32_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ uint32_t tmp;
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntoh(&tmp, key_ptr, sizeof(tmp));
+ *key = tmp;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_uint64_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_uint64_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_int *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntoh(key, key_ptr, sizeof(grn_ts_int));
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_float_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_float_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_float *key)
+{
+ int64_t tmp;
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntoh(&tmp, key_ptr, sizeof(tmp));
+ tmp ^= (((tmp ^ ((int64_t)1 << 63)) >> 63) | ((int64_t)1 << 63));
+ *(int64_t *)key = tmp;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_time_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_time_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_time *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntohi(key, key_ptr, sizeof(grn_ts_time));
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_geo_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_geo_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_geo *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntog(key, key_ptr, sizeof(grn_ts_geo));
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_text_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_text_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_text *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ key->ptr = key_ptr;
+ key->size = key_size;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_pat_get_ref_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_pat_get_ref_key(grn_ctx *ctx, grn_pat *pat, grn_ts_id id,
+ grn_ts_ref *key)
+{
+ GRN_TS_TABLE_GET_KEY(pat)
+ grn_ntoh(&key->id, key_ptr, sizeof(key->id));
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_dat_get_text_key() gets a reference to a key (_key). */
+static grn_rc
+grn_ts_dat_get_text_key(grn_ctx *ctx, grn_dat *dat, grn_ts_id id,
+ grn_ts_text *key)
+{
+ GRN_TS_TABLE_GET_KEY(dat)
+ key->ptr = key_ptr;
+ key->size = key_size;
+ return GRN_SUCCESS;
+}
+#undef GRN_TS_TABLE_GET_KEY
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_id_node.
+ */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+} grn_ts_expr_id_node;
+
+/* grn_ts_expr_id_node_init() initializes a node. */
+static void
+grn_ts_expr_id_node_init(grn_ctx *ctx, grn_ts_expr_id_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_ID_NODE;
+ node->data_kind = GRN_TS_INT;
+ node->data_type = GRN_DB_UINT32;
+}
+
+/* grn_ts_expr_id_node_fin() finalizes a node. */
+static void
+grn_ts_expr_id_node_fin(grn_ctx *ctx, grn_ts_expr_id_node *node)
+{
+ /* Nothing to do. */
+}
+
+grn_rc
+grn_ts_expr_id_node_open(grn_ctx *ctx, grn_ts_expr_node **node)
+{
+ grn_ts_expr_id_node *new_node = GRN_MALLOCN(grn_ts_expr_id_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_id_node));
+ }
+ grn_ts_expr_id_node_init(ctx, new_node);
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_id_node_close() destroys a node. */
+static void
+grn_ts_expr_id_node_close(grn_ctx *ctx, grn_ts_expr_id_node *node)
+{
+ grn_ts_expr_id_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+/* grn_ts_expr_id_node_evaluate() outputs IDs. */
+static grn_rc
+grn_ts_expr_id_node_evaluate(grn_ctx *ctx, grn_ts_expr_id_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i;
+ grn_ts_int *out_ptr = (grn_ts_int *)out;
+ for (i = 0; i < n_in; i++) {
+ out_ptr[i] = (grn_ts_int)in[i].id;
+ }
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_score_node.
+ */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+} grn_ts_expr_score_node;
+
+/* grn_ts_expr_score_node_init() initializes a node. */
+static void
+grn_ts_expr_score_node_init(grn_ctx *ctx, grn_ts_expr_score_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_SCORE_NODE;
+ node->data_kind = GRN_TS_FLOAT;
+ node->data_type = GRN_DB_FLOAT;
+}
+
+/* grn_ts_expr_score_node_fin() finalizes a node. */
+static void
+grn_ts_expr_score_node_fin(grn_ctx *ctx, grn_ts_expr_score_node *node)
+{
+ /* Nothing to do. */
+}
+
+grn_rc
+grn_ts_expr_score_node_open(grn_ctx *ctx, grn_ts_expr_node **node)
+{
+ grn_ts_expr_score_node *new_node = GRN_MALLOCN(grn_ts_expr_score_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_score_node));
+ }
+ grn_ts_expr_score_node_init(ctx, new_node);
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_score_node_close() destroys a node. */
+static void
+grn_ts_expr_score_node_close(grn_ctx *ctx, grn_ts_expr_score_node *node)
+{
+ grn_ts_expr_score_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+/* grn_ts_expr_score_node_evaluate() outputs scores. */
+static grn_rc
+grn_ts_expr_score_node_evaluate(grn_ctx *ctx, grn_ts_expr_score_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ size_t i;
+ grn_ts_float *out_ptr = (grn_ts_float *)out;
+ for (i = 0; i < n_in; i++) {
+ out_ptr[i] = (grn_ts_float)in[i].score;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_score_node_adjust() does nothing. */
+static grn_rc
+grn_ts_expr_score_node_adjust(grn_ctx *ctx, grn_ts_expr_score_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ /* Nothing to do. */
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_key_node.
+ */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+ grn_obj *table;
+ grn_ts_buf buf;
+} grn_ts_expr_key_node;
+
+/* grn_ts_expr_key_node_init() initializes a node. */
+static void
+grn_ts_expr_key_node_init(grn_ctx *ctx, grn_ts_expr_key_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_KEY_NODE;
+ node->table = NULL;
+ grn_ts_buf_init(ctx, &node->buf);
+}
+
+/* grn_ts_expr_key_node_fin() finalizes a node. */
+static void
+grn_ts_expr_key_node_fin(grn_ctx *ctx, grn_ts_expr_key_node *node)
+{
+ grn_ts_buf_fin(ctx, &node->buf);
+ if (node->table) {
+ grn_obj_unlink(ctx, node->table);
+ }
+}
+
+grn_rc
+grn_ts_expr_key_node_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_node **node)
+{
+ grn_rc rc;
+ grn_ts_expr_key_node *new_node;
+ if (!grn_ts_table_has_key(ctx, table)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "the table has no _key");
+ }
+ new_node = GRN_MALLOCN(grn_ts_expr_key_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_key_node));
+ }
+ grn_ts_expr_key_node_init(ctx, new_node);
+ rc = grn_ts_obj_increment_ref_count(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_key_node_fin(ctx, new_node);
+ GRN_FREE(new_node);
+ return rc;
+ }
+ new_node->data_kind = grn_ts_data_type_to_kind(table->header.domain);
+ new_node->data_type = table->header.domain;
+ new_node->table = table;
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_key_node_close() destroys a node. */
+static void
+grn_ts_expr_key_node_close(grn_ctx *ctx, grn_ts_expr_key_node *node)
+{
+ grn_ts_expr_key_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+#define GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(table, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ for (i = 0; i < n_in; i++) {\
+ rc = grn_ts_ ## table ## _get_ ## kind ## _key(ctx, table, in[i].id,\
+ &out_ptr[i]);\
+ if (rc != GRN_SUCCESS) {\
+ out_ptr[i] = grn_ts_ ## kind ## _zero();\
+ }\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(table, TYPE, type)\
+ case GRN_DB_ ## TYPE: {\
+ grn_ts_int *out_ptr = (grn_ts_int *)out;\
+ for (i = 0; i < n_in; i++) {\
+ rc = grn_ts_ ## table ## _get_ ## type ## _key(ctx, table, in[i].id,\
+ &out_ptr[i]);\
+ if (rc != GRN_SUCCESS) {\
+ out_ptr[i] = grn_ts_int_zero();\
+ }\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(table)\
+ case GRN_TS_TEXT: {\
+ char *buf_ptr;\
+ grn_ts_text *out_ptr = (grn_ts_text *)out;\
+ node->buf.pos = 0;\
+ for (i = 0; i < n_in; i++) {\
+ grn_ts_text key;\
+ rc = grn_ts_ ## table ## _get_text_key(ctx, table, in[i].id, &key);\
+ if (rc != GRN_SUCCESS) {\
+ key = grn_ts_text_zero();\
+ }\
+ rc = grn_ts_buf_write(ctx, &node->buf, key.ptr, key.size);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ out_ptr[i].size = key.size;\
+ }\
+ buf_ptr = (char *)node->buf.ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i].ptr = buf_ptr;\
+ buf_ptr += out_ptr[i].size;\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(table)\
+ case GRN_TS_REF: {\
+ grn_ts_ref *out_ptr = (grn_ts_ref *)out;\
+ for (i = 0; i < n_in; i++) {\
+ rc = grn_ts_ ## table ## _get_ref_key(ctx, table, in[i].id,\
+ &out_ptr[i]);\
+ if (rc != GRN_SUCCESS) {\
+ out_ptr[i] = grn_ts_ref_zero();\
+ }\
+ out_ptr[i].score = in[i].score;\
+ }\
+ return GRN_SUCCESS;\
+ }
+/* grn_ts_expr_key_node_evaluate() outputs keys. */
+static grn_rc
+grn_ts_expr_key_node_evaluate(grn_ctx *ctx, grn_ts_expr_key_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i;
+ grn_rc rc;
+ switch (node->table->header.type) {
+ case GRN_TABLE_HASH_KEY: {
+ grn_hash *hash = (grn_hash *)node->table;
+ switch (node->data_kind) {
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, BOOL, bool)
+ case GRN_TS_INT: {
+ switch (node->data_type) {
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT8, int8)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT16, int16)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT32, int32)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, INT64, int64)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT8, uint8)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT16, uint16)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT32, uint32)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(hash, UINT64, uint64)
+ }
+ }
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, FLOAT, float)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, TIME, time)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(hash)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(hash, GEO, geo)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(hash)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+ }
+ case GRN_TABLE_PAT_KEY: {
+ grn_pat *pat = (grn_pat *)node->table;
+ switch (node->data_kind) {
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, BOOL, bool)
+ case GRN_TS_INT: {
+ switch (node->data_type) {
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT8, int8)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT16, int16)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT32, int32)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, INT64, int64)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT8, uint8)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT16, uint16)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT32, uint32)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE(pat, UINT64, uint64)
+ }
+ }
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, FLOAT, float)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, TIME, time)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(pat)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE(pat, GEO, geo)
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE(pat)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+ }
+ case GRN_TABLE_DAT_KEY: {
+ grn_dat *dat = (grn_dat *)node->table;
+ switch (node->data_kind) {
+ GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE(dat)
+ /* GRN_TABLE_DAT_KEY supports only Text. */
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+ }
+ /* GRN_TABLE_NO_KEY doesn't support _key. */
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d",
+ node->table->header.type);
+ }
+ }
+}
+#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_REF_CASE
+#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_TEXT_CASE
+#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_INT_CASE
+#undef GRN_TS_EXPR_KEY_NODE_EVALUATE_CASE
+
+/* grn_ts_expr_key_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_key_node_filter(grn_ctx *ctx, grn_ts_expr_key_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, count;
+ grn_ts_bool key= 0;
+ switch (node->table->header.type) {
+ case GRN_TABLE_HASH_KEY: {
+ grn_hash *hash = (grn_hash *)node->table;
+ for (i = 0, count = 0; i < n_in; i++) {
+ grn_rc rc = grn_ts_hash_get_bool_key(ctx, hash, in[i].id, &key);
+ if (rc != GRN_SUCCESS) {
+ key = grn_ts_bool_zero();
+ }
+ if (key) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+ }
+ case GRN_TABLE_PAT_KEY: {
+ grn_pat *pat = (grn_pat *)node->table;
+ for (i = 0, count = 0; i < n_in; i++) {
+ grn_rc rc = grn_ts_pat_get_bool_key(ctx, pat, in[i].id, &key);
+ if (rc != GRN_SUCCESS) {
+ key = grn_ts_bool_zero();
+ }
+ if (key) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+ }
+ /* GRN_TABLE_DAT_KEY and GRN_TABLE_NO_KEY don't support a Bool key. */
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d",
+ node->table->header.type);
+ }
+ }
+}
+
+/* grn_ts_expr_key_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_key_node_adjust(grn_ctx *ctx, grn_ts_expr_key_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ size_t i;
+ grn_ts_float key= 0;
+ switch (node->table->header.type) {
+ case GRN_TABLE_HASH_KEY: {
+ grn_hash *hash = (grn_hash *)node->table;
+ for (i = 0; i < n_io; i++) {
+ grn_rc rc = grn_ts_hash_get_float_key(ctx, hash, io[i].id, &key);
+ if (rc != GRN_SUCCESS) {
+ key = grn_ts_float_zero();
+ }
+ io[i].score = (grn_ts_score)key;
+ }
+ return GRN_SUCCESS;
+ }
+ case GRN_TABLE_PAT_KEY: {
+ grn_pat *pat = (grn_pat *)node->table;
+ for (i = 0; i < n_io; i++) {
+ grn_rc rc = grn_ts_pat_get_float_key(ctx, pat, io[i].id, &key);
+ if (rc != GRN_SUCCESS) {
+ key = grn_ts_float_zero();
+ }
+ io[i].score = (grn_ts_score)key;
+ }
+ return GRN_SUCCESS;
+ }
+ /* GRN_TABLE_DAT_KEY and GRN_TABLE_NO_KEY don't support a Float key. */
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid table type: %d",
+ node->table->header.type);
+ }
+ }
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_value_node.
+ */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+ grn_obj *table;
+} grn_ts_expr_value_node;
+
+/* grn_ts_expr_value_node_init() initializes a node. */
+static void
+grn_ts_expr_value_node_init(grn_ctx *ctx, grn_ts_expr_value_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_VALUE_NODE;
+ node->table = NULL;
+}
+
+/* grn_ts_expr_value_node_fin() finalizes a node. */
+static void
+grn_ts_expr_value_node_fin(grn_ctx *ctx, grn_ts_expr_value_node *node)
+{
+ if (node->table) {
+ grn_obj_unlink(ctx, node->table);
+ }
+}
+
+grn_rc
+grn_ts_expr_value_node_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_node **node)
+{
+ grn_rc rc;
+ grn_ts_expr_value_node *new_node;
+ if (!grn_ts_table_has_value(ctx, table)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "table has no _value");
+ }
+ new_node = GRN_MALLOCN(grn_ts_expr_value_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_value_node));
+ }
+ grn_ts_expr_value_node_init(ctx, new_node);
+ rc = grn_ts_obj_increment_ref_count(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ GRN_FREE(new_node);
+ return rc;
+ }
+ new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(table)->range);
+ new_node->data_type = DB_OBJ(table)->range;
+ new_node->table = table;
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_value_node_close() destroys a node. */
+static void
+grn_ts_expr_value_node_close(grn_ctx *ctx, grn_ts_expr_value_node *node)
+{
+ grn_ts_expr_value_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ size_t i;\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ for (i = 0; i < n_in; i++) {\
+ const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);\
+ if (ptr) {\
+ out_ptr[i] = *(const grn_ts_ ## kind *)ptr;\
+ } else {\
+ out_ptr[i] = grn_ts_ ## kind ## _zero();\
+ }\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(TYPE, type)\
+ case GRN_DB_ ## TYPE: {\
+ size_t i;\
+ grn_ts_int *out_ptr = (grn_ts_int *)out;\
+ for (i = 0; i < n_in; i++) {\
+ const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);\
+ if (ptr) {\
+ out_ptr[i] = (grn_ts_int)*(const type ## _t *)ptr;\
+ } else {\
+ out_ptr[i] = grn_ts_int_zero();\
+ }\
+ }\
+ return GRN_SUCCESS;\
+ }
+/* grn_ts_expr_value_node_evaluate() outputs values. */
+static grn_rc
+grn_ts_expr_value_node_evaluate(grn_ctx *ctx, grn_ts_expr_value_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(BOOL, bool)
+ case GRN_TS_INT: {
+ switch (node->data_type) {
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT8, int8)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT16, int16)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT32, int32)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(INT64, int64)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT8, uint8)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT16, uint16)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT32, uint32)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE(UINT64, uint64)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
+ node->data_type);
+ }
+ }
+ }
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(FLOAT, float)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(TIME, time)
+ GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE(GEO, geo)
+ case GRN_TS_REF: {
+ size_t i;
+ grn_ts_ref *out_ptr = (grn_ts_ref *)out;
+ for (i = 0; i < n_in; i++) {
+ const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);
+ if (ptr) {
+ out_ptr[i].id = *(const grn_ts_id *)ptr;
+ out_ptr[i].score = in[i].score;
+ } else {
+ out_ptr[i] = grn_ts_ref_zero();
+ }
+ }
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_INT_CASE
+#undef GRN_TS_EXPR_VALUE_NODE_EVALUATE_CASE
+
+/* grn_ts_expr_value_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_value_node_filter(grn_ctx *ctx, grn_ts_expr_value_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, count = 0;
+ for (i = 0; i < n_in; i++) {
+ const void *ptr = grn_ts_table_get_value(ctx, node->table, in[i].id);
+ if (ptr && *(const grn_ts_bool *)ptr) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_value_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_value_node_adjust(grn_ctx *ctx, grn_ts_expr_value_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ size_t i;
+ for (i = 0; i < n_io; i++) {
+ const void *ptr = grn_ts_table_get_value(ctx, node->table, io[i].id);
+ if (ptr) {
+ io[i].score = (grn_ts_score)*(const grn_ts_float *)ptr;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_const_node.
+ */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+ grn_ts_any content;
+ grn_ts_buf text_buf;
+ grn_ts_buf vector_buf;
+} grn_ts_expr_const_node;
+
+/* grn_ts_expr_const_node_init() initializes a node. */
+static void
+grn_ts_expr_const_node_init(grn_ctx *ctx, grn_ts_expr_const_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_CONST_NODE;
+ grn_ts_buf_init(ctx, &node->text_buf);
+ grn_ts_buf_init(ctx, &node->vector_buf);
+}
+
+/* grn_ts_expr_const_node_fin() finalizes a node. */
+static void
+grn_ts_expr_const_node_fin(grn_ctx *ctx, grn_ts_expr_const_node *node)
+{
+ grn_ts_buf_fin(ctx, &node->vector_buf);
+ grn_ts_buf_fin(ctx, &node->text_buf);
+}
+
+#define GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ node->content.as_ ## kind = value.as_ ## kind;\
+ return GRN_SUCCESS;\
+ }
+/* grn_ts_expr_const_node_set_scalar() sets a scalar value. */
+static grn_rc
+grn_ts_expr_const_node_set_scalar(grn_ctx *ctx, grn_ts_expr_const_node *node,
+ grn_ts_any value)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(BOOL, bool)
+ GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(INT, int)
+ GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(FLOAT, float)
+ GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(TIME, time)
+ case GRN_TS_TEXT: {
+ grn_rc rc = grn_ts_buf_write(ctx, &node->text_buf,
+ value.as_text.ptr, value.as_text.size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ node->content.as_text.ptr = (const char *)node->text_buf.ptr;
+ node->content.as_text.size = value.as_text.size;
+ return GRN_SUCCESS;
+ }
+ GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE(GEO, geo)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_CONST_NODE_SET_SCALAR_CASE
+
+#define GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND ## _VECTOR: {\
+ grn_rc rc;\
+ size_t n_bytes;\
+ const grn_ts_ ## kind *buf_ptr;\
+ grn_ts_ ## kind ## _vector vector;\
+ vector = value.as_ ## kind ## _vector;\
+ n_bytes = sizeof(grn_ts_ ## kind) * vector.size;\
+ rc = grn_ts_buf_write(ctx, &node->vector_buf, vector.ptr, n_bytes);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ buf_ptr = (const grn_ts_ ## kind *)node->vector_buf.ptr;\
+ node->content.as_ ## kind ## _vector.ptr = buf_ptr;\
+ node->content.as_ ## kind ## _vector.size = vector.size;\
+ return GRN_SUCCESS;\
+ }
+/* grn_ts_expr_const_node_set_vector() sets a vector value. */
+static grn_rc
+grn_ts_expr_const_node_set_vector(grn_ctx *ctx, grn_ts_expr_const_node *node,
+ grn_ts_any value)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(BOOL, bool)
+ GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(INT, int)
+ GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(FLOAT, float)
+ GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(TIME, time)
+ case GRN_TS_TEXT_VECTOR: {
+ grn_rc rc;
+ size_t i, n_bytes, offset, total_size;
+ grn_ts_text_vector vector = value.as_text_vector;
+ grn_ts_text *vector_buf;
+ char *text_buf;
+ n_bytes = sizeof(grn_ts_text) * vector.size;
+ rc = grn_ts_buf_resize(ctx, &node->vector_buf, n_bytes);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ vector_buf = (grn_ts_text *)node->vector_buf.ptr;
+ total_size = 0;
+ for (i = 0; i < vector.size; i++) {
+ total_size += vector.ptr[i].size;
+ }
+ rc = grn_ts_buf_resize(ctx, &node->text_buf, total_size);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ text_buf = (char *)node->text_buf.ptr;
+ offset = 0;
+ for (i = 0; i < vector.size; i++) {
+ grn_memcpy(text_buf + offset, vector.ptr[i].ptr, vector.ptr[i].size);
+ vector_buf[i].ptr = text_buf + offset;
+ vector_buf[i].size = vector.ptr[i].size;
+ offset += vector.ptr[i].size;
+ }
+ node->content.as_text_vector.ptr = vector_buf;
+ node->content.as_text_vector.size = vector.size;
+ return GRN_SUCCESS;
+ }
+ GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE(GEO, geo)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_CONST_NODE_SET_VECTOR_CASE
+
+#define GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ if (!grn_ts_ ## kind ## _is_valid(value.as_ ## kind)) {\
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");\
+ }\
+ return GRN_SUCCESS;\
+ }
+static grn_rc
+grn_ts_expr_const_node_check_value(grn_ctx *ctx, grn_ts_data_kind kind,
+ grn_ts_any value)
+{
+ switch (kind) {
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(BOOL, bool)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(INT, int)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(FLOAT, float)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TIME, time)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TEXT, text)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(GEO, geo)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(BOOL_VECTOR, bool_vector)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(INT_VECTOR, int_vector)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(FLOAT_VECTOR, float_vector)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TIME_VECTOR, time_vector)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(TEXT_VECTOR, text_vector)
+ GRN_TS_EXPR_CONST_NODE_CHECK_VALUE(GEO_VECTOR, geo_vector)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ }
+}
+#undef GRN_TS_EXPR_CONST_NODE_CHECK_VALUE
+
+grn_rc
+grn_ts_expr_const_node_open(grn_ctx *ctx, grn_ts_data_kind data_kind,
+ grn_ts_data_type data_type,
+ grn_ts_any value, grn_ts_expr_node **node)
+{
+ grn_rc rc = grn_ts_expr_const_node_check_value(ctx, data_kind, value);
+ grn_ts_expr_const_node *new_node;
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ new_node = GRN_MALLOCN(grn_ts_expr_const_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_const_node));
+ }
+ grn_ts_expr_const_node_init(ctx, new_node);
+ new_node->data_kind = data_kind;
+ if (data_type != GRN_DB_VOID) {
+ new_node->data_type = data_type;
+ } else {
+ new_node->data_type = grn_ts_data_kind_to_type(data_kind);
+ }
+ if (data_kind & GRN_TS_VECTOR_FLAG) {
+ rc = grn_ts_expr_const_node_set_vector(ctx, new_node, value);
+ } else {
+ rc = grn_ts_expr_const_node_set_scalar(ctx, new_node, value);
+ }
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_const_node_fin(ctx, new_node);
+ GRN_FREE(new_node);
+ return rc;
+ }
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_const_node_close() destroys a node. */
+static void
+grn_ts_expr_const_node_close(grn_ctx *ctx, grn_ts_expr_const_node *node)
+{
+ grn_ts_expr_const_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+#define GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ size_t i;\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = node->content.as_ ## kind;\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(KIND, kind)\
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(KIND ## _VECTOR, kind ## _vector)
+/* grn_ts_expr_const_node_evaluate() outputs the stored const. */
+static grn_rc
+grn_ts_expr_const_node_evaluate(grn_ctx *ctx, grn_ts_expr_const_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(BOOL, bool)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(INT, int)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(FLOAT, float)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(TIME, time)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(TEXT, text)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE(GEO, geo)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(BOOL, bool)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(INT, int)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(FLOAT, float)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(TIME, time)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(TEXT, text)
+ GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE(GEO, geo)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_VECTOR_CASE
+#undef GRN_TS_EXPR_CONST_NODE_EVALUATE_CASE
+
+/* grn_ts_expr_const_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_const_node_filter(grn_ctx *ctx, grn_ts_expr_const_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ if (node->content.as_bool) {
+ /* All the records pass through the filter. */
+ if (in != out) {
+ size_t i;
+ for (i = 0; i < n_in; i++) {
+ out[i] = in[i];
+ }
+ }
+ *n_out = n_in;
+ } else {
+ /* All the records are discarded. */
+ *n_out = 0;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_const_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_const_node_adjust(grn_ctx *ctx, grn_ts_expr_const_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ size_t i;
+ grn_ts_score score = (grn_ts_score)node->content.as_float;
+ for (i = 0; i < n_io; i++) {
+ io[i].score = score;
+ }
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_column_node.
+ */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+ grn_obj *column;
+ grn_ts_buf buf;
+ grn_ts_buf body_buf;
+ grn_ja_reader *reader;
+} grn_ts_expr_column_node;
+
+/* grn_ts_expr_column_node_init() initializes a node. */
+static void
+grn_ts_expr_column_node_init(grn_ctx *ctx, grn_ts_expr_column_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_COLUMN_NODE;
+ node->column = NULL;
+ grn_ts_buf_init(ctx, &node->buf);
+ grn_ts_buf_init(ctx, &node->body_buf);
+ node->reader = NULL;
+}
+
+/* grn_ts_expr_column_node_fin() finalizes a node. */
+static void
+grn_ts_expr_column_node_fin(grn_ctx *ctx, grn_ts_expr_column_node *node)
+{
+ if (node->reader) {
+ grn_ja_reader_close(ctx, node->reader);
+ }
+ grn_ts_buf_fin(ctx, &node->body_buf);
+ grn_ts_buf_fin(ctx, &node->buf);
+ if (node->column) {
+ grn_obj_unlink(ctx, node->column);
+ }
+}
+
+#define GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE(TYPE)\
+ case GRN_DB_ ## TYPE: {\
+ GRN_ ## TYPE ## _INIT(&new_node->buf, GRN_OBJ_VECTOR);\
+ break;\
+ }
+grn_rc
+grn_ts_expr_column_node_open(grn_ctx *ctx, grn_obj *column,
+ grn_ts_expr_node **node)
+{
+ grn_rc rc;
+ grn_ts_expr_column_node *new_node = GRN_MALLOCN(grn_ts_expr_column_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_column_node));
+ }
+ grn_ts_expr_column_node_init(ctx, new_node);
+ new_node->data_kind = grn_ts_data_type_to_kind(DB_OBJ(column)->range);
+ if (column->header.type == GRN_COLUMN_VAR_SIZE) {
+ grn_obj_flags type = column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK;
+ if (type == GRN_OBJ_COLUMN_VECTOR) {
+ new_node->data_kind |= GRN_TS_VECTOR_FLAG;
+ }
+ }
+ new_node->data_type = DB_OBJ(column)->range;
+ rc = grn_ts_obj_increment_ref_count(ctx, column);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_column_node_fin(ctx, new_node);
+ GRN_FREE(new_node);
+ return rc;
+ }
+ new_node->column = column;
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+#undef GRN_TS_EXPR_COLUMN_NODE_OPEN_CASE
+
+/* grn_ts_expr_column_node_close() destroys a node. */
+static void
+grn_ts_expr_column_node_close(grn_ctx *ctx, grn_ts_expr_column_node *node)
+{
+ grn_ts_expr_column_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ size_t i;\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ grn_ra *ra = (grn_ra *)node->column;\
+ grn_ra_cache cache;\
+ GRN_RA_CACHE_INIT(ra, &cache);\
+ for (i = 0; i < n_in; i++) {\
+ grn_ts_ ## kind *ptr = NULL;\
+ if (in[i].id) {\
+ ptr = (grn_ts_ ## kind *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);\
+ }\
+ out_ptr[i] = ptr ? *ptr : grn_ts_ ## kind ## _zero();\
+ }\
+ GRN_RA_CACHE_FIN(ra, &cache);\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(TYPE, type)\
+ case GRN_DB_ ## TYPE: {\
+ size_t i;\
+ grn_ts_int *out_ptr = (grn_ts_int *)out;\
+ grn_ra *ra = (grn_ra *)node->column;\
+ grn_ra_cache cache;\
+ GRN_RA_CACHE_INIT(ra, &cache);\
+ for (i = 0; i < n_in; i++) {\
+ type ## _t *ptr = NULL;\
+ if (in[i].id) {\
+ ptr = (type ## _t *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);\
+ }\
+ out_ptr[i] = ptr ? (grn_ts_int)*ptr : grn_ts_int_zero();\
+ }\
+ GRN_RA_CACHE_FIN(ra, &cache);\
+ return GRN_SUCCESS;\
+ }
+/* grn_ts_expr_column_node_evaluate_scalar() outputs scalar column values. */
+static grn_rc
+grn_ts_expr_column_node_evaluate_scalar(grn_ctx *ctx,
+ grn_ts_expr_column_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(BOOL, bool)
+ case GRN_TS_INT: {
+ switch (node->data_type) {
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT8, int8)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT16, int16)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT32, int32)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(INT64, int64)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT8, uint8)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT16, uint16)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT32, uint32)
+ /* The behavior is undefined if a value is greater than 2^63 - 1. */
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE(UINT64, uint64)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
+ node->data_type);
+ }
+ }
+ }
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(FLOAT, float)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(TIME, time)
+ case GRN_TS_TEXT: {
+ size_t i;
+ char *buf_ptr;
+ grn_rc rc;
+ grn_ts_text *out_ptr = (grn_ts_text *)out;
+ if (!node->reader) {
+ rc = grn_ja_reader_open(ctx, (grn_ja *)node->column, &node->reader);
+ if (rc != GRN_SUCCESS) {
+ GRN_TS_ERR_RETURN(rc, "grn_ja_reader_open failed");
+ }
+ } else {
+ grn_ja_reader_unref(ctx, node->reader);
+ }
+ node->buf.pos = 0;
+ for (i = 0; i < n_in; i++) {
+ rc = grn_ja_reader_seek(ctx, node->reader, in[i].id);
+ if (rc == GRN_SUCCESS) {
+ if (node->reader->ref_avail) {
+ void *addr;
+ rc = grn_ja_reader_ref(ctx, node->reader, &addr);
+ if (rc == GRN_SUCCESS) {
+ out_ptr[i].ptr = (char *)addr;
+ }
+ } else {
+ rc = grn_ts_buf_reserve(ctx, &node->buf,
+ node->buf.pos + node->reader->value_size);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ja_reader_read(ctx, node->reader,
+ (char *)node->buf.ptr + node->buf.pos);
+ if (rc == GRN_SUCCESS) {
+ out_ptr[i].ptr = NULL;
+ node->buf.pos += node->reader->value_size;
+ }
+ }
+ }
+ }
+ if (rc == GRN_SUCCESS) {
+ out_ptr[i].size = node->reader->value_size;
+ } else {
+ out_ptr[i].ptr = NULL;
+ out_ptr[i].size = 0;
+ }
+ }
+ buf_ptr = (char *)node->buf.ptr;
+ for (i = 0; i < n_in; i++) {
+ if (!out_ptr[i].ptr) {
+ out_ptr[i].ptr = buf_ptr;
+ buf_ptr += out_ptr[i].size;
+ }
+ }
+ return GRN_SUCCESS;
+ }
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE(GEO, geo)
+ case GRN_TS_REF: {
+ size_t i;
+ grn_ts_ref *out_ptr = (grn_ts_ref *)out;
+ grn_ra *ra = (grn_ra *)node->column;
+ grn_ra_cache cache;
+ GRN_RA_CACHE_INIT(ra, &cache);
+ for (i = 0; i < n_in; i++) {
+ grn_ts_id *ptr = NULL;
+ if (in[i].id) {
+ ptr = (grn_ts_id *)grn_ra_ref_cache(ctx, ra, in[i].id, &cache);
+ }
+ out_ptr[i].id = ptr ? *ptr : GRN_ID_NIL;
+ out_ptr[i].score = in[i].score;
+ }
+ GRN_RA_CACHE_FIN(ra, &cache);
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_INT_CASE
+#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_SCALAR_CASE
+
+/*
+ * grn_ts_expr_column_node_evaluate_text_vector() outputs text vector column
+ * values.
+ */
+static grn_rc
+grn_ts_expr_column_node_evaluate_text_vector(grn_ctx *ctx,
+ grn_ts_expr_column_node *node,
+ const grn_ts_record *in,
+ size_t n_in, void *out)
+{
+ grn_rc rc;
+ char *buf_ptr;
+ size_t i, j, n_bytes, n_values, total_n_bytes = 0, total_n_values = 0;
+ grn_ts_text *text_ptr;
+ grn_ts_text_vector *out_ptr = (grn_ts_text_vector *)out;
+ /* Read encoded values into node->body_buf and get the size of each value. */
+ node->body_buf.pos = 0;
+ for (i = 0; i < n_in; i++) {
+ char *ptr;
+ rc = grn_ts_ja_get_value(ctx, node->column, in[i].id,
+ &node->body_buf, &n_bytes);
+ if (rc == GRN_SUCCESS) {
+ ptr = (char *)node->body_buf.ptr + total_n_bytes;
+ GRN_B_DEC(n_values, ptr);
+ } else {
+ n_bytes = 0;
+ n_values = 0;
+ }
+ grn_memcpy(&out_ptr[i].ptr, &n_bytes, sizeof(n_bytes));
+ out_ptr[i].size = n_values;
+ total_n_bytes += n_bytes;
+ total_n_values += n_values;
+ }
+ /* Resize node->buf. */
+ n_bytes = sizeof(grn_ts_text) * total_n_values;
+ rc = grn_ts_buf_reserve(ctx, &node->buf, n_bytes);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ /* Decode values and compose the result. */
+ buf_ptr = (char *)node->body_buf.ptr;
+ text_ptr = (grn_ts_text *)node->buf.ptr;
+ for (i = 0; i < n_in; i++) {
+ char *ptr = buf_ptr;
+ grn_memcpy(&n_bytes, &out_ptr[i].ptr, sizeof(n_bytes));
+ buf_ptr += n_bytes;
+ GRN_B_DEC(n_values, ptr);
+ out_ptr[i].ptr = text_ptr;
+ for (j = 0; j < out_ptr[i].size; j++) {
+ GRN_B_DEC(text_ptr[j].size, ptr);
+ }
+ for (j = 0; j < out_ptr[i].size; j++) {
+ text_ptr[j].ptr = ptr;
+ ptr += text_ptr[j].size;
+ }
+ text_ptr += out_ptr[i].size;
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ts_expr_column_node_evaluate_ref_vector() outputs ref vector column
+ * values.
+ */
+static grn_rc
+grn_ts_expr_column_node_evaluate_ref_vector(grn_ctx *ctx,
+ grn_ts_expr_column_node *node,
+ const grn_ts_record *in,
+ size_t n_in, void *out)
+{
+ grn_rc rc;
+ size_t i, j, n_bytes, offset = 0;
+ grn_ts_id *buf_ptr;
+ grn_ts_ref *ref_ptr;
+ grn_ts_ref_vector *out_ptr = (grn_ts_ref_vector *)out;
+ /* Read column values into node->body_buf and get the size of each value. */
+ node->body_buf.pos = 0;
+ for (i = 0; i < n_in; i++) {
+ size_t size;
+ rc = grn_ts_ja_get_value(ctx, node->column, in[i].id,
+ &node->body_buf, &size);
+ if (rc == GRN_SUCCESS) {
+ out_ptr[i].size = size / sizeof(grn_ts_id);
+ offset += out_ptr[i].size;
+ } else {
+ out_ptr[i].size = 0;
+ }
+ }
+ /* Resize node->buf. */
+ n_bytes = sizeof(grn_ts_ref) * offset;
+ rc = grn_ts_buf_reserve(ctx, &node->buf, n_bytes);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ /* Compose the result. */
+ buf_ptr = (grn_ts_id *)node->body_buf.ptr;
+ ref_ptr = (grn_ts_ref *)node->buf.ptr;
+ for (i = 0; i < n_in; i++) {
+ out_ptr[i].ptr = ref_ptr;
+ for (j = 0; j < out_ptr[i].size; j++, buf_ptr++, ref_ptr++) {
+ ref_ptr->id = *buf_ptr;
+ ref_ptr->score = in[i].score;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND ## _VECTOR: {\
+ size_t i;\
+ grn_ts_ ## kind *buf_ptr;\
+ grn_ts_ ## kind ## _vector *out_ptr = (grn_ts_ ## kind ## _vector *)out;\
+ /* Read column values into node->buf and save the size of each value. */\
+ node->buf.pos = 0;\
+ for (i = 0; i < n_in; i++) {\
+ size_t n_bytes;\
+ grn_rc rc = grn_ts_ja_get_value(ctx, node->column, in[i].id,\
+ &node->buf, &n_bytes);\
+ if (rc == GRN_SUCCESS) {\
+ out_ptr[i].size = n_bytes / sizeof(grn_ts_ ## kind);\
+ } else {\
+ out_ptr[i].size = 0;\
+ }\
+ }\
+ buf_ptr = (grn_ts_ ## kind *)node->buf.ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i].ptr = buf_ptr;\
+ buf_ptr += out_ptr[i].size;\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(TYPE, type)\
+ case GRN_DB_ ## TYPE: {\
+ size_t i, j;\
+ grn_ts_int *buf_ptr;\
+ grn_ts_int_vector *out_ptr = (grn_ts_int_vector *)out;\
+ /*
+ * Read column values into body_buf and typecast the values to grn_ts_int.
+ * Then, store the grn_ts_int values into node->buf and save the size of
+ * each value.
+ */\
+ node->buf.pos = 0;\
+ for (i = 0; i < n_in; i++) {\
+ grn_rc rc;\
+ size_t n_bytes, new_n_bytes;\
+ node->body_buf.pos = 0;\
+ rc = grn_ts_ja_get_value(ctx, node->column, in[i].id,\
+ &node->body_buf, &n_bytes);\
+ if (rc == GRN_SUCCESS) {\
+ out_ptr[i].size = n_bytes / sizeof(type ## _t);\
+ } else {\
+ out_ptr[i].size = 0;\
+ }\
+ new_n_bytes = node->buf.pos + (sizeof(grn_ts_int) * out_ptr[i].size);\
+ rc = grn_ts_buf_reserve(ctx, &node->buf, new_n_bytes);\
+ if (rc == GRN_SUCCESS) {\
+ type ## _t *src_ptr = (type ## _t *)node->body_buf.ptr;\
+ grn_ts_int *dest_ptr;\
+ dest_ptr = (grn_ts_int *)((char *)node->buf.ptr + node->buf.pos);\
+ for (j = 0; j < out_ptr[i].size; j++) {\
+ dest_ptr[j] = (grn_ts_int)src_ptr[j];\
+ }\
+ node->buf.pos = new_n_bytes;\
+ } else {\
+ out_ptr[i].size = 0;\
+ }\
+ }\
+ buf_ptr = (grn_ts_int *)node->buf.ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i].ptr = buf_ptr;\
+ buf_ptr += out_ptr[i].size;\
+ }\
+ return GRN_SUCCESS;\
+ }
+/* grn_ts_expr_column_node_evaluate_vector() outputs vector column values. */
+static grn_rc
+grn_ts_expr_column_node_evaluate_vector(grn_ctx *ctx,
+ grn_ts_expr_column_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(BOOL, bool)
+ case GRN_TS_INT_VECTOR: {
+ switch (node->data_type) {
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT8, int8)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT16, int16)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT32, int32)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(INT64, int64)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT8, uint8)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT16, uint16)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT32, uint32)
+ /* The behavior is undefined if a value is greater than 2^63 - 1. */
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE(UINT64, uint64)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
+ node->data_type);
+ }
+ }
+ }
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(FLOAT, float)
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(TIME, time)
+ case GRN_TS_TEXT_VECTOR: {
+ return grn_ts_expr_column_node_evaluate_text_vector(ctx, node, in, n_in,
+ out);
+ }
+ GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE(GEO, geo)
+ case GRN_TS_REF_VECTOR: {
+ return grn_ts_expr_column_node_evaluate_ref_vector(ctx, node, in, n_in,
+ out);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_INT_CASE
+#undef GRN_TS_EXPR_COLUMN_NODE_EVALUATE_VECTOR_CASE
+
+/* grn_ts_expr_column_node_evaluate() outputs column values. */
+static grn_rc
+grn_ts_expr_column_node_evaluate(grn_ctx *ctx, grn_ts_expr_column_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ if (node->data_kind & GRN_TS_VECTOR_FLAG) {
+ return grn_ts_expr_column_node_evaluate_vector(ctx, node, in, n_in, out);
+ } else {
+ return grn_ts_expr_column_node_evaluate_scalar(ctx, node, in, n_in, out);
+ }
+}
+
+/* grn_ts_expr_column_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_column_node_filter(grn_ctx *ctx, grn_ts_expr_column_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, count = 0;
+ grn_ra *ra = (grn_ra *)node->column;
+ grn_ra_cache cache;
+ GRN_RA_CACHE_INIT(ra, &cache);
+ for (i = 0; i < n_in; i++) {
+ grn_ts_bool *ptr = NULL;
+ if (in[i].id) {
+ ptr = grn_ra_ref_cache(ctx, ra, in[i].id, &cache);
+ }
+ if (ptr && *ptr) {
+ out[count++] = in[i];
+ }
+ }
+ GRN_RA_CACHE_FIN(ra, &cache);
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_column_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_column_node_adjust(grn_ctx *ctx, grn_ts_expr_column_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ size_t i;
+ grn_ra *ra = (grn_ra *)node->column;
+ grn_ra_cache cache;
+ GRN_RA_CACHE_INIT(ra, &cache);
+ for (i = 0; i < n_io; i++) {
+ grn_ts_float *ptr = NULL;
+ if (io[i].id) {
+ ptr = grn_ra_ref_cache(ctx, ra, io[i].id, &cache);
+ }
+ if (ptr) {
+ io[i].score = (grn_ts_score)*ptr;
+ }
+ }
+ GRN_RA_CACHE_FIN(ra, &cache);
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_op_node.
+ */
+
+enum {
+ GRN_TS_EXPR_OP_NODE_MAX_N_ARGS = 3,
+ GRN_TS_EXPR_OP_NODE_N_BUFS = 3
+};
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+ grn_ts_op_type op_type;
+ grn_ts_expr_node *args[GRN_TS_EXPR_OP_NODE_MAX_N_ARGS];
+ size_t n_args;
+ grn_ts_buf bufs[GRN_TS_EXPR_OP_NODE_N_BUFS];
+} grn_ts_expr_op_node;
+
+/* grn_ts_expr_op_node_init() initializes a node. */
+static void
+grn_ts_expr_op_node_init(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ size_t i;
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_OP_NODE;
+ for (i = 0; i < GRN_TS_EXPR_OP_NODE_MAX_N_ARGS; i++) {
+ node->args[i] = NULL;
+ }
+ for (i = 0; i < GRN_TS_EXPR_OP_NODE_N_BUFS; i++) {
+ grn_ts_buf_init(ctx, &node->bufs[i]);
+ }
+}
+
+/* grn_ts_expr_op_node_fin() finalizes a node. */
+static void
+grn_ts_expr_op_node_fin(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ size_t i;
+ for (i = 0; i < GRN_TS_EXPR_OP_NODE_N_BUFS; i++) {
+ grn_ts_buf_fin(ctx, &node->bufs[i]);
+ }
+ for (i = 0; i < GRN_TS_EXPR_OP_NODE_MAX_N_ARGS; i++) {
+ if (node->args[i]) {
+ grn_ts_expr_node_close(ctx, node->args[i]);
+ }
+ }
+}
+
+/*
+ * grn_ts_expr_op_node_deref_args_for_equal() resolves references if required.
+ */
+static grn_rc
+grn_ts_expr_op_node_deref_args_for_equal(grn_ctx *ctx,
+ grn_ts_expr_op_node *node)
+{
+ grn_rc rc;
+ if (node->n_args != 2) {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid #args: %" GRN_FMT_SIZE,
+ node->n_args);
+ }
+ if ((node->args[0]->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) {
+ return grn_ts_expr_node_deref(ctx, &node->args[1]);
+ }
+ if ((node->args[1]->data_kind & ~GRN_TS_VECTOR_FLAG) != GRN_TS_REF) {
+ return grn_ts_expr_node_deref(ctx, &node->args[0]);
+ }
+
+ /* FIXME: Arguments should be compared as references if possible. */
+ rc = grn_ts_expr_node_deref(ctx, &node->args[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_node_deref(ctx, &node->args[1]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_op_node_deref_args() resolves references if required. */
+static grn_rc
+grn_ts_expr_op_node_deref_args(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ switch (node->op_type) {
+ case GRN_TS_OP_EQUAL:
+ case GRN_TS_OP_NOT_EQUAL: {
+ return grn_ts_expr_op_node_deref_args_for_equal(ctx, node);
+ }
+ /* TODO: Add a ternary operator. */
+ default: {
+ size_t i;
+ for (i = 0; i < node->n_args; i++) {
+ grn_rc rc = grn_ts_expr_node_deref(ctx, &node->args[i]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+ }
+ }
+}
+
+/*
+ * grn_ts_op_plus_check_args() checks arguments. Note that arguments are
+ * rearranged in some cases.
+ */
+static grn_rc
+grn_ts_op_plus_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ grn_rc rc;
+ if ((node->args[0]->data_kind == GRN_TS_INT) &&
+ (node->args[1]->data_kind == GRN_TS_FLOAT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0],
+ 1, &node->args[0]);
+ if (rc != GRN_SUCCESS) {
+ node->args[0] = NULL;
+ return rc;
+ }
+ } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) &&
+ (node->args[1]->data_kind == GRN_TS_INT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1],
+ 1, &node->args[1]);
+ if (rc != GRN_SUCCESS) {
+ node->args[1] = NULL;
+ return rc;
+ }
+ }
+
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_INT: {
+ switch (node->args[1]->data_kind) {
+ case GRN_TS_INT: {
+ /* Int + Int = Int. */
+ node->data_kind = GRN_TS_INT;
+ node->data_type = GRN_DB_INT64;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_TIME: {
+ /* Int + Time = Time + Int = Time. */
+ grn_ts_expr_node *tmp = node->args[0];
+ node->args[0] = node->args[1];
+ node->args[1] = tmp;
+ node->data_kind = GRN_TS_TIME;
+ node->data_type = GRN_DB_TIME;
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[1]->data_kind);
+ }
+ }
+ }
+ case GRN_TS_FLOAT: {
+ switch (node->args[1]->data_kind) {
+ case GRN_TS_FLOAT: {
+ /* Float + Float = Float. */
+ node->data_kind = GRN_TS_FLOAT;
+ node->data_type = GRN_DB_FLOAT;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_TIME: {
+ /* Float + Time = Time + Float = Time. */
+ grn_ts_expr_node *tmp = node->args[0];
+ node->args[0] = node->args[1];
+ node->args[1] = tmp;
+ node->data_kind = GRN_TS_TIME;
+ node->data_type = GRN_DB_TIME;
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[1]->data_kind);
+ }
+ }
+ }
+ case GRN_TS_TIME: {
+ switch (node->args[1]->data_kind) {
+ case GRN_TS_INT:
+ case GRN_TS_FLOAT: {
+ /* Time + Int or Float = Time. */
+ node->data_kind = GRN_TS_TIME;
+ node->data_type = GRN_DB_TIME;
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[1]->data_kind);
+ }
+ }
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+
+/* grn_ts_op_minus_check_args() checks arguments. */
+static grn_rc
+grn_ts_op_minus_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ grn_rc rc;
+ if ((node->args[0]->data_kind == GRN_TS_INT) &&
+ (node->args[1]->data_kind == GRN_TS_FLOAT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0],
+ 1, &node->args[0]);
+ if (rc != GRN_SUCCESS) {
+ node->args[0] = NULL;
+ return rc;
+ }
+ } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) &&
+ (node->args[1]->data_kind == GRN_TS_INT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1],
+ 1, &node->args[1]);
+ if (rc != GRN_SUCCESS) {
+ node->args[1] = NULL;
+ return rc;
+ }
+ }
+
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_INT: {
+ if (node->args[1]->data_kind != GRN_TS_INT) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[1]->data_kind);
+ }
+ /* Int - Int = Int. */
+ node->data_kind = GRN_TS_INT;
+ node->data_type = GRN_DB_INT64;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_FLOAT: {
+ if (node->args[1]->data_kind != GRN_TS_FLOAT) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[1]->data_kind);
+ }
+ /* Float - Float = Float. */
+ node->data_kind = GRN_TS_FLOAT;
+ node->data_type = GRN_DB_FLOAT;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_TIME: {
+ switch (node->args[1]->data_kind) {
+ case GRN_TS_INT:
+ case GRN_TS_FLOAT: {
+ /* Time - Int or Float = Time. */
+ node->data_kind = GRN_TS_TIME;
+ node->data_type = GRN_DB_TIME;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_TIME: {
+ /* Time - Time = Float. */
+ node->data_kind = GRN_TS_FLOAT;
+ node->data_type = GRN_DB_FLOAT;
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[1]->data_kind);
+ }
+ }
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+
+/*
+ * grn_ts_expr_op_node_typecast_args_for_cmp() inserts a typecast operator for
+ * comparison.
+ */
+static grn_rc
+grn_ts_expr_op_node_typecast_args_for_cmp(grn_ctx *ctx,
+ grn_ts_expr_op_node *node)
+{
+ grn_rc rc;
+ if ((node->args[0]->data_kind == GRN_TS_INT) &&
+ (node->args[1]->data_kind == GRN_TS_FLOAT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0],
+ 1, &node->args[0]);
+ if (rc != GRN_SUCCESS) {
+ node->args[0] = NULL;
+ return rc;
+ }
+ } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) &&
+ (node->args[1]->data_kind == GRN_TS_INT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1],
+ 1, &node->args[1]);
+ if (rc != GRN_SUCCESS) {
+ node->args[1] = NULL;
+ return rc;
+ }
+ } else if ((node->args[0]->data_kind == GRN_TS_TIME) &&
+ (node->args[1]->data_kind == GRN_TS_TEXT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_TIME, &node->args[1],
+ 1, &node->args[1]);
+ if (rc != GRN_SUCCESS) {
+ node->args[1] = NULL;
+ return rc;
+ }
+ } else if ((node->args[0]->data_kind == GRN_TS_TEXT) &&
+ (node->args[1]->data_kind == GRN_TS_TIME)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_TIME, &node->args[0],
+ 1, &node->args[0]);
+ if (rc != GRN_SUCCESS) {
+ node->args[0] = NULL;
+ return rc;
+ }
+ } else {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "data kind conflict: %d != %d",
+ node->args[0]->data_kind,
+ node->args[1]->data_kind);
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ts_expr_op_node_check_args() checks the combination of an operator and
+ * its arguments.
+ */
+static grn_rc
+grn_ts_expr_op_node_check_args(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ switch (node->op_type) {
+ case GRN_TS_OP_LOGICAL_NOT: {
+ if (node->args[0]->data_kind != GRN_TS_BOOL) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ node->data_kind = GRN_TS_BOOL;
+ node->data_type = GRN_DB_BOOL;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_BITWISE_NOT: {
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_BOOL:
+ case GRN_TS_INT: {
+ node->data_kind = node->args[0]->data_kind;
+ node->data_type = grn_ts_data_kind_to_type(node->data_kind);
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+ }
+ case GRN_TS_OP_POSITIVE:
+ case GRN_TS_OP_NEGATIVE: {
+ if ((node->args[0]->data_kind != GRN_TS_INT) &&
+ (node->args[0]->data_kind != GRN_TS_FLOAT)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ node->data_kind = node->args[0]->data_kind;
+ node->data_type = grn_ts_data_kind_to_type(node->data_kind);
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_FLOAT: {
+ if (node->args[0]->data_kind != GRN_TS_INT) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ node->data_kind = GRN_TS_FLOAT;
+ node->data_type = GRN_DB_FLOAT;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_TIME: {
+ if (node->args[0]->data_kind != GRN_TS_TEXT) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ node->data_kind = GRN_TS_TIME;
+ node->data_type = GRN_DB_TIME;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_LOGICAL_AND:
+ case GRN_TS_OP_LOGICAL_OR:
+ case GRN_TS_OP_LOGICAL_SUB: {
+ if ((node->args[0]->data_kind != GRN_TS_BOOL) ||
+ (node->args[1]->data_kind != GRN_TS_BOOL)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d",
+ node->args[0]->data_kind, node->args[1]->data_kind);
+ }
+ node->data_kind = GRN_TS_BOOL;
+ node->data_type = GRN_DB_BOOL;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_BITWISE_AND:
+ case GRN_TS_OP_BITWISE_OR:
+ case GRN_TS_OP_BITWISE_XOR: {
+ if (node->args[0]->data_kind != node->args[1]->data_kind) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data kind conflict: %d != %d",
+ node->args[0]->data_kind, node->args[1]->data_kind);
+ }
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_BOOL:
+ case GRN_TS_INT: {
+ node->data_kind = node->args[0]->data_kind;
+ node->data_type = grn_ts_data_kind_to_type(node->data_kind);
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+ node->data_kind = GRN_TS_BOOL;
+ node->data_type = GRN_DB_BOOL;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_EQUAL:
+ case GRN_TS_OP_NOT_EQUAL: {
+ grn_ts_data_kind scalar_data_kind;
+ if (node->args[0]->data_kind != node->args[1]->data_kind) {
+ grn_rc rc = grn_ts_expr_op_node_typecast_args_for_cmp(ctx, node);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ scalar_data_kind = node->args[0]->data_kind & ~GRN_TS_VECTOR_FLAG;
+ if (((scalar_data_kind == GRN_TS_REF) ||
+ (scalar_data_kind == GRN_TS_GEO)) &&
+ (node->args[0]->data_type != node->args[1]->data_type)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "data type conflict: %d != %d",
+ node->args[0]->data_type, node->args[1]->data_type);
+ }
+ node->data_kind = GRN_TS_BOOL;
+ node->data_type = GRN_DB_BOOL;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_LESS:
+ case GRN_TS_OP_LESS_EQUAL:
+ case GRN_TS_OP_GREATER:
+ case GRN_TS_OP_GREATER_EQUAL: {
+ if (node->args[0]->data_kind != node->args[1]->data_kind) {
+ grn_rc rc = grn_ts_expr_op_node_typecast_args_for_cmp(ctx, node);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_INT:
+ case GRN_TS_FLOAT:
+ case GRN_TS_TIME:
+ case GRN_TS_TEXT:
+ case GRN_TS_INT_VECTOR:
+ case GRN_TS_FLOAT_VECTOR:
+ case GRN_TS_TIME_VECTOR:
+ case GRN_TS_TEXT_VECTOR: {
+ node->data_kind = GRN_TS_BOOL;
+ node->data_type = GRN_DB_BOOL;
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+ case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT:
+ case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT:
+ case GRN_TS_OP_SHIFT_LOGICAL_LEFT:
+ case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: {
+ if ((node->args[0]->data_kind != GRN_TS_INT) ||
+ (node->args[1]->data_kind != GRN_TS_INT)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d",
+ node->args[0]->data_kind,
+ node->args[1]->data_kind);
+ }
+ node->data_kind = GRN_TS_INT;
+ node->data_type = GRN_DB_INT64;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_OP_PLUS: {
+ return grn_ts_op_plus_check_args(ctx, node);
+ }
+ case GRN_TS_OP_MINUS: {
+ return grn_ts_op_minus_check_args(ctx, node);
+ }
+ case GRN_TS_OP_MULTIPLICATION:
+ case GRN_TS_OP_DIVISION:
+ case GRN_TS_OP_MODULUS: {
+ if (node->args[0]->data_kind != node->args[1]->data_kind) {
+ grn_rc rc;
+ if ((node->args[0]->data_kind == GRN_TS_INT) &&
+ (node->args[1]->data_kind == GRN_TS_FLOAT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[0],
+ 1, &node->args[0]);
+ if (rc != GRN_SUCCESS) {
+ node->args[0] = NULL;
+ return rc;
+ }
+ } else if ((node->args[0]->data_kind == GRN_TS_FLOAT) &&
+ (node->args[1]->data_kind == GRN_TS_INT)) {
+ rc = grn_ts_expr_op_node_open(ctx, GRN_TS_OP_FLOAT, &node->args[1],
+ 1, &node->args[1]);
+ if (rc != GRN_SUCCESS) {
+ node->args[1] = NULL;
+ return rc;
+ }
+ } else {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "data kind conflict: %d != %d",
+ node->args[0]->data_kind,
+ node->args[1]->data_kind);
+ }
+ }
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_INT:
+ case GRN_TS_FLOAT: {
+ node->data_kind = node->args[0]->data_kind;
+ node->data_type = grn_ts_data_kind_to_type(node->data_kind);
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+ }
+ }
+ case GRN_TS_OP_MATCH:
+ case GRN_TS_OP_PREFIX_MATCH:
+ case GRN_TS_OP_SUFFIX_MATCH: {
+ if ((node->args[0]->data_kind != GRN_TS_TEXT) ||
+ (node->args[1]->data_kind != GRN_TS_TEXT)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d, %d",
+ node->args[0]->data_kind,
+ node->args[1]->data_kind);
+ }
+ node->data_kind = GRN_TS_BOOL;
+ node->data_type = GRN_DB_BOOL;
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid operator: %d",
+ node->op_type);
+ }
+ }
+}
+
+/* grn_ts_expr_op_node_setup() sets up an operator node. */
+static grn_rc
+grn_ts_expr_op_node_setup(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ grn_rc rc = grn_ts_expr_op_node_deref_args(ctx, node);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_op_node_check_args(ctx, node);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (node->data_kind == GRN_TS_VOID) {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ GRN_TS_VOID);
+ } else if (node->data_type == GRN_DB_VOID) {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data type: %d",
+ GRN_DB_VOID);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_op_node_open(grn_ctx *ctx, grn_ts_op_type op_type,
+ grn_ts_expr_node **args, size_t n_args,
+ grn_ts_expr_node **node)
+{
+ size_t i;
+ grn_rc rc;
+ grn_ts_expr_op_node *new_node = GRN_MALLOCN(grn_ts_expr_op_node, 1);
+ if (!new_node) {
+ for (i = 0; i < n_args; i++) {
+ grn_ts_expr_node_close(ctx, args[i]);
+ }
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_op_node));
+ }
+ grn_ts_expr_op_node_init(ctx, new_node);
+ new_node->op_type = op_type;
+ for (i = 0; i < n_args; i++) {
+ new_node->args[i] = args[i];
+ }
+ new_node->n_args = n_args;
+ rc = grn_ts_expr_op_node_setup(ctx, new_node);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_op_node_fin(ctx, new_node);
+ GRN_FREE(new_node);
+ return rc;
+ }
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_op_node_close() destroys a node. */
+static void
+grn_ts_expr_op_node_close(grn_ctx *ctx, grn_ts_expr_op_node *node)
+{
+ grn_ts_expr_op_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+/* grn_ts_op_logical_not_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_logical_not_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i;
+ grn_ts_bool *out_ptr = (grn_ts_bool *)out;
+ grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ for (i = 0; i < n_in; i++) {
+ out_ptr[i] = grn_ts_op_logical_not_bool(out_ptr[i]);
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_bitwise_not_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_bitwise_not_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i;
+ grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ switch (node->data_kind) {
+ case GRN_TS_BOOL: {
+ grn_ts_bool *out_ptr = (grn_ts_bool *)out;
+ for (i = 0; i < n_in; i++) {
+ out_ptr[i] = grn_ts_op_bitwise_not_bool(out_ptr[i]);
+ }
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_INT: {
+ grn_ts_int *out_ptr = (grn_ts_int *)out;
+ for (i = 0; i < n_in; i++) {
+ out_ptr[i] = grn_ts_op_bitwise_not_int(out_ptr[i]);
+ }
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+
+#define GRN_TS_OP_SIGN_EVALUATE_CASE(type, KIND, kind) \
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(out_ptr[i]);\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_OP_SIGN_EVALUATE(type) \
+ size_t i;\
+ grn_rc rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ switch (node->data_kind) {\
+ GRN_TS_OP_SIGN_EVALUATE_CASE(type, INT, int)\
+ GRN_TS_OP_SIGN_EVALUATE_CASE(type, FLOAT, float)\
+ default: {\
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
+ node->data_kind);\
+ }\
+ }
+/* grn_ts_op_positive_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_positive_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_SIGN_EVALUATE(positive)
+}
+
+/* grn_ts_op_negative_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_negative_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_SIGN_EVALUATE(negative)
+}
+#undef GRN_TS_OP_SIGN_EVALUATE
+#undef GRN_TS_OP_SIGN_EVALUATE_CASE
+
+/* grn_ts_op_float_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_float_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i;
+ grn_ts_int *buf_ptr;
+ grn_ts_float *out_ptr = (grn_ts_float *)out;
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptr = (grn_ts_int *)node->bufs[0].ptr;
+ for (i = 0; i < n_in; i++) {
+ rc = grn_ts_op_float(ctx, buf_ptr[i], &out_ptr[i]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_time_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_time_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i;
+ grn_ts_text *buf_ptr;
+ grn_ts_time *out_ptr = (grn_ts_time *)out;
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptr = (grn_ts_text *)node->bufs[0].ptr;
+ for (i = 0; i < n_in; i++) {
+ rc = grn_ts_op_time(ctx, buf_ptr[i], &out_ptr[i]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_logical_and_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_logical_and_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i, j, count;
+ grn_rc rc;
+ grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out;
+ grn_ts_buf *tmp_in_buf = &node->bufs[2];
+ grn_ts_record *tmp_in;
+
+ /* Evaluate the 1st argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
+
+ /* Create a list of true records. */
+ rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
+ count = 0;
+ for (i = 0; i < n_in; i++) {
+ if (buf_ptrs[0][i]) {
+ tmp_in[count++] = in[i];
+ }
+ }
+
+ /* Evaluate the 2nd argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
+ &node->bufs[1]);
+ buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
+
+ /* Merge the results. */
+ count = 0;
+ for (i = 0, j = 0; i < n_in; i++) {
+ out_ptr[count++] = buf_ptrs[0][i] && buf_ptrs[1][j++];
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_logical_or_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_logical_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i, j, count;
+ grn_rc rc;
+ grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out;
+ grn_ts_buf *tmp_in_buf = &node->bufs[2];
+ grn_ts_record *tmp_in;
+
+ /* Evaluate the 1st argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
+
+ /* Create a list of false records. */
+ rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
+ count = 0;
+ for (i = 0; i < n_in; i++) {
+ if (!buf_ptrs[0][i]) {
+ tmp_in[count++] = in[i];
+ }
+ }
+
+ /* Evaluate the 2nd argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
+ &node->bufs[1]);
+ buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
+
+ /* Merge the results. */
+ count = 0;
+ for (i = 0, j = 0; i < n_in; i++) {
+ out_ptr[count++] = buf_ptrs[0][i] || buf_ptrs[1][j++];
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_logical_sub_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_logical_sub_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ size_t i, j, count;
+ grn_rc rc;
+ grn_ts_bool *buf_ptrs[2], *out_ptr = (grn_ts_bool *)out;
+ grn_ts_buf *tmp_in_buf = &node->bufs[2];
+ grn_ts_record *tmp_in;
+
+ /* Evaluate the 1st argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
+
+ /* Create a list of true records. */
+ rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
+ count = 0;
+ for (i = 0; i < n_in; i++) {
+ if (buf_ptrs[0][i]) {
+ tmp_in[count++] = in[i];
+ }
+ }
+
+ /* Evaluate the 2nd argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
+ &node->bufs[1]);
+ buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
+
+ /* Merge the results. */
+ count = 0;
+ for (i = 0, j = 0; i < n_in; i++) {
+ out_ptr[count++] = buf_ptrs[0][i] &&
+ grn_ts_op_logical_not_bool(buf_ptrs[1][j++]);
+ }
+ return GRN_SUCCESS;
+}
+
+#define GRN_TS_OP_BITWISE_EVALUATE_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ /*
+ * Use the output buffer to put evaluation results of the 1st argument,
+ * because the data kind is same.
+ */\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc == GRN_SUCCESS) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
+ in, n_in, &node->bufs[0]);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_ ## kind *buf_ptr = (grn_ts_ ## kind *)node->bufs[0].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_bitwise_ ## type ## _ ## kind(out_ptr[i],\
+ buf_ptr[i]);\
+ }\
+ }\
+ }\
+ return rc;\
+ }
+/* grn_ts_op_bitwise_and_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_bitwise_and_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->args[0]->data_kind) {
+ GRN_TS_OP_BITWISE_EVALUATE_CASE(and, BOOL, bool)
+ GRN_TS_OP_BITWISE_EVALUATE_CASE(and, INT, int)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+
+/* grn_ts_op_bitwise_or_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_bitwise_or_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->args[0]->data_kind) {
+ GRN_TS_OP_BITWISE_EVALUATE_CASE(or, BOOL, bool)
+ GRN_TS_OP_BITWISE_EVALUATE_CASE(or, INT, int)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+
+/* grn_ts_op_bitwise_xor_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_bitwise_xor_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->args[0]->data_kind) {
+ GRN_TS_OP_BITWISE_EVALUATE_CASE(xor, BOOL, bool)
+ GRN_TS_OP_BITWISE_EVALUATE_CASE(xor, INT, int)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+#undef GRN_TS_OP_BITWISE_EVALUATE_CASE
+
+#define GRN_TS_OP_CHK_EVALUATE_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *buf_ptrs[] = {\
+ (grn_ts_ ## kind *)node->bufs[0].ptr,\
+ (grn_ts_ ## kind *)node->bufs[1].ptr\
+ };\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i],\
+ buf_ptrs[1][i]);\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, KIND, kind)\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, KIND ## _VECTOR, kind ## _vector)
+#define GRN_TS_OP_CHK_EVALUATE(type)\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_bool *out_ptr = (grn_ts_bool *)out;\
+ if (node->args[0]->data_kind == GRN_TS_BOOL) {\
+ /*
+ * Use the output buffer to put evaluation results of the 1st argument,
+ * because the data kind is same.
+ */\
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_buf *buf = &node->bufs[0];\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
+ in, n_in, buf);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_bool *buf_ptr = (grn_ts_bool *)buf->ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type ## _bool(out_ptr[i], buf_ptr[i]);\
+ }\
+ }\
+ }\
+ return rc;\
+ }\
+ for (i = 0; i < 2; i++) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ switch (node->args[0]->data_kind) {\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, INT, int)\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, TIME, time)\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, TEXT, text)\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, GEO, geo)\
+ GRN_TS_OP_CHK_EVALUATE_CASE(type, REF, ref)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, BOOL, bool)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, INT, int)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, TIME, time)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, TEXT, text)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, GEO, geo)\
+ GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE(type, REF, ref)\
+ default: {\
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
+ node->args[0]->data_kind);\
+ }\
+ }
+/* grn_ts_op_equal_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_CHK_EVALUATE(equal)
+}
+
+/* grn_ts_op_not_equal_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_not_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_CHK_EVALUATE(not_equal)
+}
+#undef GRN_TS_OP_CHK_EVALUATE
+#undef GRN_TS_OP_CHK_EVALUATE_VECTOR_CASE
+#undef GRN_TS_OP_CHK_EVALUATE_CASE
+
+#define GRN_TS_OP_CMP_EVALUATE_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *buf_ptrs[] = {\
+ (grn_ts_ ## kind *)node->bufs[0].ptr,\
+ (grn_ts_ ## kind *)node->bufs[1].ptr\
+ };\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i],\
+ buf_ptrs[1][i]);\
+ }\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, KIND, kind)\
+ GRN_TS_OP_CMP_EVALUATE_CASE(type, KIND ## _VECTOR, kind ## _vector)
+#define GRN_TS_OP_CMP_EVALUATE(type)\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_bool *out_ptr = (grn_ts_bool *)out;\
+ for (i = 0; i < 2; i++) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ switch (node->args[0]->data_kind) {\
+ GRN_TS_OP_CMP_EVALUATE_CASE(type, INT, int)\
+ GRN_TS_OP_CMP_EVALUATE_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CMP_EVALUATE_CASE(type, TIME, time)\
+ GRN_TS_OP_CMP_EVALUATE_CASE(type, TEXT, text)\
+ GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, INT, int)\
+ GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, TIME, time)\
+ GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE(type, TEXT, text)\
+ default: {\
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
+ node->args[0]->data_kind);\
+ }\
+ }
+/* grn_ts_op_less_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_less_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_CMP_EVALUATE(less)
+}
+
+/* grn_ts_op_less_equal_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_less_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_CMP_EVALUATE(less_equal)
+}
+
+/* grn_ts_op_greater_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_greater_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_CMP_EVALUATE(greater)
+}
+
+/* grn_ts_op_greater_equal_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_greater_equal_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_CMP_EVALUATE(greater_equal)
+}
+#undef GRN_TS_OP_CMP_EVALUATE
+#undef GRN_TS_OP_CMP_EVALUATE_VECTOR_CASE
+#undef GRN_TS_OP_CMP_EVALUATE_CASE
+
+#define GRN_TS_OP_SHIFT_EVALUATE(type)\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_int *out_ptr = (grn_ts_int *)out;\
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc == GRN_SUCCESS) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
+ in, n_in, &node->bufs[0]);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_int *buf_ptr = (grn_ts_int *)node->bufs[0].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_shift_ ## type(out_ptr[i], buf_ptr[i]);\
+ }\
+ }\
+ }\
+ return rc;
+/* grn_ts_op_shift_arithmetic_left_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_shift_arithmetic_left_evaluate(grn_ctx *ctx,
+ grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_SHIFT_EVALUATE(arithmetic_left)
+}
+
+/* grn_ts_op_shift_arithmetic_right_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_shift_arithmetic_right_evaluate(grn_ctx *ctx,
+ grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_SHIFT_EVALUATE(arithmetic_right)
+}
+
+/* grn_ts_op_shift_logical_left_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_shift_logical_left_evaluate(grn_ctx *ctx,
+ grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_SHIFT_EVALUATE(logical_left)
+}
+
+/* grn_ts_op_shift_logical_right_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_shift_logical_right_evaluate(grn_ctx *ctx,
+ grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_SHIFT_EVALUATE(logical_right)
+}
+#undef GRN_TS_OP_SHIFT_EVALUATE
+
+#define GRN_TS_OP_ARITH_EVALUATE(type, lhs_kind, rhs_kind)\
+ /*
+ * Use the output buffer to put evaluation results of the 1st argument,
+ * because the data kind is same.
+ */\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_ ## lhs_kind *out_ptr = (grn_ts_ ## lhs_kind *)out;\
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc == GRN_SUCCESS) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
+ in, n_in, &node->bufs[0]);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_ ## rhs_kind *buf_ptr = (grn_ts_ ## rhs_kind *)node->bufs[0].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ rc = grn_ts_op_ ## type ## _ ## lhs_kind ## _ ## rhs_kind(\
+ ctx, out_ptr[i], buf_ptr[i], &out_ptr[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ }\
+ }\
+ return rc;
+
+#define GRN_TS_OP_ARITH_EVALUATE_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ /*
+ * Use the output buffer to put evaluation results of the 1st argument,
+ * because the data kind is same.
+ */\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_ ## kind *out_ptr = (grn_ts_ ## kind *)out;\
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc == GRN_SUCCESS) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
+ in, n_in, &node->bufs[0]);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_ ## kind *buf_ptr = (grn_ts_ ## kind *)node->bufs[0].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type ## _ ## kind(out_ptr[i],\
+ buf_ptr[i]);\
+ }\
+ }\
+ }\
+ return rc;\
+ }
+#define GRN_TS_OP_ARITH_EVALUATE_TIME_CASE(type, KIND, lhs, rhs)\
+ case GRN_TS_ ## KIND: {\
+ /*
+ * Use the output buffer to put evaluation results of the 1st argument,
+ * because the data kind is same.
+ */\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_ ## lhs *out_ptr = (grn_ts_ ## lhs *)out;\
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, out);\
+ if (rc == GRN_SUCCESS) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1],\
+ in, n_in, &node->bufs[0]);\
+ if (rc == GRN_SUCCESS) {\
+ grn_ts_ ## rhs *buf_ptr = (grn_ts_ ## rhs *)node->bufs[0].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type ## _ ## lhs ## _ ## rhs(out_ptr[i],\
+ buf_ptr[i]);\
+ }\
+ }\
+ }\
+ return rc;\
+ }
+/* grn_ts_op_plus_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_plus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(plus, int, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(plus, float, float)
+ }
+ case GRN_TS_TIME: {
+ switch (node->args[1]->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(plus, time, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(plus, time, float)
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "data kind conflict: %d, %d",
+ node->args[0]->data_kind,
+ node->args[1]->data_kind);
+ }
+ }
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+
+/* grn_ts_op_minus_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_minus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->args[0]->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(minus, int, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(minus, float, float)
+ }
+ case GRN_TS_TIME: {
+ switch (node->args[1]->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(minus, time, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(minus, time, float)
+ }
+ case GRN_TS_TIME: {
+ size_t i;
+ grn_rc rc;
+ grn_ts_float *out_ptr = (grn_ts_float *)out;
+ grn_ts_time *buf_ptrs[2];
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], in, n_in,
+ &node->bufs[1]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptrs[0] = (grn_ts_time *)node->bufs[0].ptr;
+ buf_ptrs[1] = (grn_ts_time *)node->bufs[1].ptr;
+ for (i = 0; i < n_in; i++) {
+ rc = grn_ts_op_minus_time_time(ctx, buf_ptrs[0][i], buf_ptrs[1][i],
+ &out_ptr[i]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "data kind conflict: %d, %d",
+ node->args[0]->data_kind,
+ node->args[1]->data_kind);
+ }
+ }
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->args[0]->data_kind);
+ }
+ }
+}
+#undef GRN_TS_OP_ARITH_EVALUATE_TIME_CASE
+
+/* grn_ts_op_multiplication_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_multiplication_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ switch (node->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(multiplication, int, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(multiplication, float, float)
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+
+/* grn_ts_op_division_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_division_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(division, int, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(division, float, float)
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+
+/* grn_ts_op_modulus_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_modulus_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->data_kind) {
+ case GRN_TS_INT: {
+ GRN_TS_OP_ARITH_EVALUATE(modulus, int, int)
+ }
+ case GRN_TS_FLOAT: {
+ GRN_TS_OP_ARITH_EVALUATE(modulus, float, float)
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",
+ node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_OP_ARITH_EVALUATE_CASE
+
+#define GRN_TS_OP_MATCH_EVALUATE(type)\
+ size_t i;\
+ grn_rc rc;\
+ grn_ts_bool *out_ptr = (grn_ts_bool *)out;\
+ grn_ts_text *buf_ptrs[2];\
+ for (i = 0; i < 2; i++) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ buf_ptrs[0] = (grn_ts_text *)node->bufs[0].ptr;\
+ buf_ptrs[1] = (grn_ts_text *)node->bufs[1].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ out_ptr[i] = grn_ts_op_ ## type(buf_ptrs[0][i], buf_ptrs[1][i]);\
+ }\
+ return GRN_SUCCESS;\
+/* grn_ts_op_match_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_match_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ GRN_TS_OP_MATCH_EVALUATE(match)
+}
+
+/* grn_ts_op_prefix_match_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_prefix_match_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_MATCH_EVALUATE(prefix_match)
+}
+
+/* grn_ts_op_suffix_match_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_op_suffix_match_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ GRN_TS_OP_MATCH_EVALUATE(suffix_match)
+}
+#undef GRN_TS_OP_MATCH_EVALUATE
+
+/* grn_ts_expr_op_node_evaluate() evaluates an operator. */
+static grn_rc
+grn_ts_expr_op_node_evaluate(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->op_type) {
+ case GRN_TS_OP_LOGICAL_NOT: {
+ return grn_ts_op_logical_not_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_BITWISE_NOT: {
+ return grn_ts_op_bitwise_not_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_POSITIVE: {
+ return grn_ts_op_positive_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_NEGATIVE: {
+ return grn_ts_op_negative_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_FLOAT: {
+ return grn_ts_op_float_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_TIME: {
+ return grn_ts_op_time_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_LOGICAL_AND: {
+ return grn_ts_op_logical_and_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_LOGICAL_OR: {
+ return grn_ts_op_logical_or_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_LOGICAL_SUB: {
+ return grn_ts_op_logical_sub_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_BITWISE_AND: {
+ return grn_ts_op_bitwise_and_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_BITWISE_OR: {
+ return grn_ts_op_bitwise_or_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_BITWISE_XOR: {
+ return grn_ts_op_bitwise_xor_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_EQUAL: {
+ return grn_ts_op_equal_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_NOT_EQUAL: {
+ return grn_ts_op_not_equal_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_LESS: {
+ return grn_ts_op_less_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_LESS_EQUAL: {
+ return grn_ts_op_less_equal_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_GREATER: {
+ return grn_ts_op_greater_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_GREATER_EQUAL: {
+ return grn_ts_op_greater_equal_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT: {
+ return grn_ts_op_shift_arithmetic_left_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT: {
+ return grn_ts_op_shift_arithmetic_right_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_SHIFT_LOGICAL_LEFT: {
+ return grn_ts_op_shift_logical_left_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: {
+ return grn_ts_op_shift_logical_right_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_PLUS: {
+ return grn_ts_op_plus_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_MINUS: {
+ return grn_ts_op_minus_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_MULTIPLICATION: {
+ return grn_ts_op_multiplication_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_DIVISION: {
+ return grn_ts_op_division_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_MODULUS: {
+ return grn_ts_op_modulus_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_MATCH: {
+ return grn_ts_op_match_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_PREFIX_MATCH: {
+ return grn_ts_op_prefix_match_evaluate(ctx, node, in, n_in, out);
+ }
+ case GRN_TS_OP_SUFFIX_MATCH: {
+ return grn_ts_op_suffix_match_evaluate(ctx, node, in, n_in, out);
+ }
+ // TODO: Add operators.
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "operator not supported: %d", node->op_type);
+ }
+ }
+}
+
+/* grn_ts_op_logical_not_filter() filters records. */
+static grn_rc
+grn_ts_op_logical_not_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, count;
+ grn_rc rc;
+ grn_ts_bool *buf_ptr;
+ rc = grn_ts_buf_reserve(ctx, &node->bufs[0], sizeof(grn_ts_bool) * n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptr = (grn_ts_bool *)node->bufs[0].ptr;
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, buf_ptr);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ for (i = 0, count = 0; i < n_in; i++) {
+ if (grn_ts_op_logical_not_bool(buf_ptr[i])) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_bitwise_not_filter() filters records. */
+static grn_rc
+grn_ts_op_bitwise_not_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, count;
+ grn_rc rc;
+ grn_ts_bool *buf_ptr;
+ rc = grn_ts_buf_reserve(ctx, &node->bufs[0], sizeof(grn_ts_bool) * n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptr = (grn_ts_bool *)node->bufs[0].ptr;
+ rc = grn_ts_expr_node_evaluate(ctx, node->args[0], in, n_in, buf_ptr);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ for (i = 0, count = 0; i < n_in; i++) {
+ if (grn_ts_op_bitwise_not_bool(buf_ptr[i])) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_logical_and_filter() filters records. */
+static grn_rc
+grn_ts_op_logical_and_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ grn_rc rc = grn_ts_expr_node_filter(ctx, node->args[0], in, n_in,
+ out, n_out);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ return grn_ts_expr_node_filter(ctx, node->args[1], out, *n_out, out, n_out);
+}
+
+/* grn_ts_op_logical_or_filter() filters records. */
+static grn_rc
+grn_ts_op_logical_or_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, j, count;
+ grn_rc rc;
+ grn_ts_bool *buf_ptrs[2];
+ grn_ts_buf *tmp_in_buf = &node->bufs[2];
+ grn_ts_record *tmp_in;
+
+ /* Evaluate the 1st argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptrs[0] = (grn_ts_bool *)node->bufs[0].ptr;
+
+ /* Create a list of false records. */
+ rc = grn_ts_buf_reserve(ctx, tmp_in_buf, sizeof(grn_ts_record) * n_in);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp_in = (grn_ts_record *)tmp_in_buf->ptr;
+ count = 0;
+ for (i = 0; i < n_in; i++) {
+ if (!buf_ptrs[0][i]) {
+ tmp_in[count++] = in[i];
+ }
+ }
+
+ /* Evaluate the 2nd argument. */
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], tmp_in, count,
+ &node->bufs[1]);
+ buf_ptrs[1] = (grn_ts_bool *)node->bufs[1].ptr;
+
+ /* Merge the results. */
+ count = 0;
+ for (i = 0, j = 0; i < n_in; i++) {
+ if (buf_ptrs[0][i] || buf_ptrs[1][j++]) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_op_logical_sub_filter() filters records. */
+static grn_rc
+grn_ts_op_logical_sub_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, n, count;
+ grn_ts_bool *buf_ptr;
+ grn_rc rc = grn_ts_expr_node_filter(ctx, node->args[0], in, n_in, out, &n);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[1], out, n,
+ &node->bufs[0]);
+ buf_ptr = (grn_ts_bool *)node->bufs[0].ptr;
+ for (i = 0, count = 0; i < n; i++) {
+ if (grn_ts_op_logical_not_bool(buf_ptr[i])) {
+ out[count++] = out[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+#define GRN_TS_OP_BITWISE_FILTER(type)\
+ size_t i, count = 0;\
+ grn_ts_bool *buf_ptrs[2];\
+ for (i = 0; i < 2; i++) {\
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ buf_ptrs[i] = (grn_ts_bool *)node->bufs[i].ptr;\
+ }\
+ for (i = 0; i < n_in; i++) {\
+ if (grn_ts_op_bitwise_ ## type ## _bool(buf_ptrs[0][i], buf_ptrs[1][i])) {\
+ out[count++] = in[i];\
+ }\
+ }\
+ *n_out = count;\
+ return GRN_SUCCESS;\
+/* grn_ts_op_bitwise_and_filter() filters records. */
+static grn_rc
+grn_ts_op_bitwise_and_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_BITWISE_FILTER(and);
+}
+
+/* grn_ts_op_bitwise_or_filter() filters records. */
+static grn_rc
+grn_ts_op_bitwise_or_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_BITWISE_FILTER(or);
+}
+
+/* grn_ts_op_bitwise_xor_filter() filters records. */
+static grn_rc
+grn_ts_op_bitwise_xor_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_BITWISE_FILTER(xor);
+}
+#undef GRN_TS_OP_BITWISE_FILTER_CASE
+
+#define GRN_TS_OP_CHK_FILTER_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *buf_ptrs[] = {\
+ (grn_ts_ ## kind *)node->bufs[0].ptr,\
+ (grn_ts_ ## kind *)node->bufs[1].ptr\
+ };\
+ for (i = 0; i < n_in; i++) {\
+ if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\
+ out[count++] = in[i];\
+ }\
+ }\
+ *n_out = count;\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, KIND, kind)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, KIND ## _VECTOR, kind ## _vector)
+#define GRN_TS_OP_CHK_FILTER(type)\
+ size_t i, count = 0;\
+ for (i = 0; i < 2; i++) {\
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ switch (node->args[0]->data_kind) {\
+ GRN_TS_OP_CHK_FILTER_CASE(type, BOOL, bool)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, INT, int)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, TIME, time)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, TEXT, text)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, GEO, geo)\
+ GRN_TS_OP_CHK_FILTER_CASE(type, REF, ref)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, BOOL, bool)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, INT, int)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, TIME, time)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, TEXT, text)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, GEO, geo)\
+ GRN_TS_OP_CHK_FILTER_VECTOR_CASE(type, REF, ref)\
+ default: {\
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
+ node->args[0]->data_kind);\
+ }\
+ }
+/* grn_ts_op_equal_filter() filters records. */
+static grn_rc
+grn_ts_op_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_CHK_FILTER(equal)
+}
+
+/* grn_ts_op_not_equal_filter() filters records. */
+static grn_rc
+grn_ts_op_not_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_CHK_FILTER(not_equal)
+}
+#undef GRN_TS_OP_CHK_FILTER
+#undef GRN_TS_OP_CHK_FILTER_VECTOR_CASE
+#undef GRN_TS_OP_CHK_FILTER_CASE
+
+#define GRN_TS_OP_CMP_FILTER_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *buf_ptrs[] = {\
+ (grn_ts_ ## kind *)node->bufs[0].ptr,\
+ (grn_ts_ ## kind *)node->bufs[1].ptr\
+ };\
+ for (i = 0; i < n_in; i++) {\
+ if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\
+ out[count++] = in[i];\
+ }\
+ }\
+ *n_out = count;\
+ return GRN_SUCCESS;\
+ }
+#define GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, KIND, kind)\
+ GRN_TS_OP_CMP_FILTER_CASE(type, KIND ## _VECTOR, kind ## _vector)
+#define GRN_TS_OP_CMP_FILTER(type)\
+ size_t i, count = 0;\
+ for (i = 0; i < 2; i++) {\
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ switch (node->args[0]->data_kind) {\
+ GRN_TS_OP_CMP_FILTER_CASE(type, INT, int)\
+ GRN_TS_OP_CMP_FILTER_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CMP_FILTER_CASE(type, TIME, time)\
+ GRN_TS_OP_CMP_FILTER_CASE(type, TEXT, text)\
+ GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, INT, int)\
+ GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, FLOAT, float)\
+ GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, TIME, time)\
+ GRN_TS_OP_CMP_FILTER_VECTOR_CASE(type, TEXT, text)\
+ default: {\
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid data kind: %d",\
+ node->args[0]->data_kind);\
+ }\
+ }
+/* grn_ts_op_less_filter() filters records. */
+static grn_rc
+grn_ts_op_less_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_CMP_FILTER(less)
+}
+
+/* grn_ts_op_less_equal_filter() filters records. */
+static grn_rc
+grn_ts_op_less_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_CMP_FILTER(less_equal)
+}
+
+/* grn_ts_op_greater_filter() filters records. */
+static grn_rc
+grn_ts_op_greater_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_CMP_FILTER(greater)
+}
+
+/* grn_ts_op_greater_equal_filter() filters records. */
+static grn_rc
+grn_ts_op_greater_equal_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_CMP_FILTER(greater_equal)
+}
+#undef GRN_TS_OP_CMP_FILTER
+#undef GRN_TS_OP_CMP_FILTER_VECTOR_CASE
+#undef GRN_TS_OP_CMP_FILTER_CASE
+
+#define GRN_TS_OP_MATCH_FILTER_CASE(type, KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_ts_ ## kind *buf_ptrs[] = {\
+ (grn_ts_ ## kind *)node->bufs[0].ptr,\
+ (grn_ts_ ## kind *)node->bufs[1].ptr\
+ };\
+ for (i = 0; i < n_in; i++) {\
+ if (grn_ts_op_ ## type ## _ ## kind(buf_ptrs[0][i], buf_ptrs[1][i])) {\
+ out[count++] = in[i];\
+ }\
+ }\
+ *n_out = count;\
+ return GRN_SUCCESS;\
+ }
+
+#define GRN_TS_OP_MATCH_FILTER(type)\
+ size_t i, count = 0;\
+ grn_ts_text *buf_ptrs[2];\
+ for (i = 0; i < 2; i++) {\
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], in, n_in,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ buf_ptrs[0] = (grn_ts_text *)node->bufs[0].ptr;\
+ buf_ptrs[1] = (grn_ts_text *)node->bufs[1].ptr;\
+ for (i = 0; i < n_in; i++) {\
+ if (grn_ts_op_ ## type(buf_ptrs[0][i], buf_ptrs[1][i])) {\
+ out[count++] = in[i];\
+ }\
+ }\
+ *n_out = count;\
+ return GRN_SUCCESS;\
+/* grn_ts_op_match_filter() filters records. */
+static grn_rc
+grn_ts_op_match_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_MATCH_FILTER(match)
+}
+
+/* grn_ts_op_prefix_match_filter() filters records. */
+static grn_rc
+grn_ts_op_prefix_match_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_MATCH_FILTER(prefix_match)
+}
+
+/* grn_ts_op_suffix_match_filter() filters records. */
+static grn_rc
+grn_ts_op_suffix_match_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ GRN_TS_OP_MATCH_FILTER(suffix_match)
+}
+#undef GRN_TS_OP_MATCH_FILTER
+
+/* grn_ts_expr_op_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_op_node_filter(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ switch (node->op_type) {
+ case GRN_TS_OP_LOGICAL_NOT: {
+ return grn_ts_op_logical_not_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_BITWISE_NOT: {
+ return grn_ts_op_bitwise_not_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_LOGICAL_AND: {
+ return grn_ts_op_logical_and_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_LOGICAL_OR: {
+ return grn_ts_op_logical_or_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_LOGICAL_SUB: {
+ return grn_ts_op_logical_sub_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_BITWISE_AND: {
+ return grn_ts_op_bitwise_and_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_BITWISE_OR: {
+ return grn_ts_op_bitwise_or_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_BITWISE_XOR: {
+ return grn_ts_op_bitwise_xor_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_EQUAL: {
+ return grn_ts_op_equal_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_NOT_EQUAL: {
+ return grn_ts_op_not_equal_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_LESS: {
+ return grn_ts_op_less_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_LESS_EQUAL: {
+ return grn_ts_op_less_equal_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_GREATER: {
+ return grn_ts_op_greater_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_GREATER_EQUAL: {
+ return grn_ts_op_greater_equal_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_MATCH: {
+ return grn_ts_op_match_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_PREFIX_MATCH: {
+ return grn_ts_op_prefix_match_filter(ctx, node, in, n_in, out, n_out);
+ }
+ case GRN_TS_OP_SUFFIX_MATCH: {
+ return grn_ts_op_suffix_match_filter(ctx, node, in, n_in, out, n_out);
+ }
+ // TODO: Add operators.
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "operator not supported: %d", node->op_type);
+ }
+ }
+}
+
+#define GRN_TS_OP_SIGN_ADJUST(type)\
+ size_t i;\
+ grn_ts_float *buf_ptr;\
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], io, n_io,\
+ &node->bufs[0]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ buf_ptr = (grn_ts_float *)node->bufs[0].ptr;\
+ for (i = 0; i < n_io; i++) {\
+ grn_ts_float result = grn_ts_op_ ## type ## _float(buf_ptr[i]);\
+ io[i].score = (grn_ts_score)result;\
+ if (!isfinite(io[i].score)) {\
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid score: %g", result);\
+ }\
+ }\
+ return GRN_SUCCESS;
+/* grn_ts_op_positive_adjust() updates scores. */
+static grn_rc
+grn_ts_op_positive_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_SIGN_ADJUST(positive)
+}
+
+/* grn_ts_op_negative_adjust() updates scores. */
+static grn_rc
+grn_ts_op_negative_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_SIGN_ADJUST(negative)
+}
+#undef GRN_TS_OP_SIGN_ADJUST
+
+/* grn_ts_op_float_adjust() updates scores. */
+static grn_rc
+grn_ts_op_float_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ size_t i;
+ grn_ts_int *buf_ptr;
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[0], io, n_io,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ buf_ptr = (grn_ts_int *)node->bufs[0].ptr;
+ for (i = 0; i < n_io; i++) {
+ grn_ts_float result;
+ rc = grn_ts_op_float(ctx, buf_ptr[i], &result);
+ io[i].score = (grn_ts_score)result;
+ if (!isfinite(io[i].score)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid score: %g", result);
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+#define GRN_TS_OP_ARITH_ADJUST(type)\
+ grn_rc rc;\
+ size_t i;\
+ grn_ts_float *buf_ptrs[2];\
+ for (i = 0; i < 2; i++) {\
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->args[i], io, n_io,\
+ &node->bufs[i]);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ }\
+ buf_ptrs[0] = (grn_ts_float *)node->bufs[0].ptr;\
+ buf_ptrs[1] = (grn_ts_float *)node->bufs[1].ptr;\
+ for (i = 0; i < n_io; i++) {\
+ grn_ts_float result;\
+ rc = grn_ts_op_ ## type ## _float_float(ctx, buf_ptrs[0][i],\
+ buf_ptrs[1][i], &result);\
+ io[i].score = (grn_ts_score)result;\
+ if (!isfinite(io[i].score)) {\
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid score: %g", result);\
+ }\
+ }\
+ return GRN_SUCCESS;
+/* grn_ts_op_plus_adjust() updates scores. */
+static grn_rc
+grn_ts_op_plus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_ARITH_ADJUST(plus)
+}
+
+/* grn_ts_op_minus_adjust() updates scores. */
+static grn_rc
+grn_ts_op_minus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_ARITH_ADJUST(minus)
+}
+
+/* grn_ts_op_multiplication_adjust() updates scores. */
+static grn_rc
+grn_ts_op_multiplication_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_ARITH_ADJUST(multiplication)
+}
+
+/* grn_ts_op_division_adjust() updates scores. */
+static grn_rc
+grn_ts_op_division_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_ARITH_ADJUST(division)
+}
+
+/* grn_ts_op_modulus_adjust() updates scores. */
+static grn_rc
+grn_ts_op_modulus_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ GRN_TS_OP_ARITH_ADJUST(modulus)
+}
+#undef GRN_TS_OP_ARITH_ADJUST
+
+/* grn_ts_expr_op_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_op_node_adjust(grn_ctx *ctx, grn_ts_expr_op_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ switch (node->op_type) {
+ case GRN_TS_OP_POSITIVE: {
+ return grn_ts_op_positive_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_NEGATIVE: {
+ return grn_ts_op_negative_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_FLOAT: {
+ return grn_ts_op_float_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_PLUS: {
+ return grn_ts_op_plus_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_MINUS: {
+ return grn_ts_op_minus_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_MULTIPLICATION: {
+ return grn_ts_op_multiplication_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_DIVISION: {
+ return grn_ts_op_division_adjust(ctx, node, io, n_io);
+ }
+ case GRN_TS_OP_MODULUS: {
+ return grn_ts_op_modulus_adjust(ctx, node, io, n_io);
+ }
+ // TODO: Add operators.
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "operator not supported: %d", node->op_type);
+ }
+ }
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_bridge_node.
+ */
+
+enum { GRN_TS_EXPR_BRIDGE_NODE_N_BUFS = 2 };
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+ grn_ts_expr_node *src;
+ grn_ts_expr_node *dest;
+ grn_ts_buf bufs[GRN_TS_EXPR_BRIDGE_NODE_N_BUFS];
+} grn_ts_expr_bridge_node;
+
+/* grn_ts_expr_bridge_node_init() initializes a node. */
+static void
+grn_ts_expr_bridge_node_init(grn_ctx *ctx, grn_ts_expr_bridge_node *node)
+{
+ size_t i;
+ memset(node, 0, sizeof(*node));
+ node->type = GRN_TS_EXPR_BRIDGE_NODE;
+ node->src = NULL;
+ node->dest = NULL;
+ for (i = 0; i < GRN_TS_EXPR_BRIDGE_NODE_N_BUFS; i++) {
+ grn_ts_buf_init(ctx, &node->bufs[i]);
+ }
+}
+
+/* grn_ts_expr_bridge_node_fin() finalizes a node. */
+static void
+grn_ts_expr_bridge_node_fin(grn_ctx *ctx, grn_ts_expr_bridge_node *node)
+{
+ size_t i;
+ for (i = 0; i < GRN_TS_EXPR_BRIDGE_NODE_N_BUFS; i++) {
+ grn_ts_buf_fin(ctx, &node->bufs[i]);
+ }
+ if (node->dest) {
+ grn_ts_expr_node_close(ctx, node->dest);
+ }
+ if (node->src) {
+ grn_ts_expr_node_close(ctx, node->src);
+ }
+}
+
+grn_rc
+grn_ts_expr_bridge_node_open(grn_ctx *ctx, grn_ts_expr_node *src,
+ grn_ts_expr_node *dest, grn_ts_expr_node **node)
+{
+ grn_ts_expr_bridge_node *new_node = GRN_MALLOCN(grn_ts_expr_bridge_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_bridge_node));
+ }
+ grn_ts_expr_bridge_node_init(ctx, new_node);
+ new_node->data_kind = dest->data_kind;
+ new_node->data_type = dest->data_type;
+ new_node->src = src;
+ new_node->dest = dest;
+ *node = (grn_ts_expr_node *)new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_bridge_node_close() destroys a node. */
+static void
+grn_ts_expr_bridge_node_close(grn_ctx *ctx, grn_ts_expr_bridge_node *node)
+{
+ grn_ts_expr_bridge_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+/* grn_ts_expr_bridge_node_evaluate() evaluates a bridge. */
+static grn_rc
+grn_ts_expr_bridge_node_evaluate(grn_ctx *ctx, grn_ts_expr_bridge_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out)
+{
+ grn_ts_record *tmp;
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp = (grn_ts_record *)node->bufs[0].ptr;
+ return grn_ts_expr_node_evaluate(ctx, node->dest, tmp, n_in, out);
+}
+
+/* grn_ts_expr_bridge_node_filter() filters records. */
+static grn_rc
+grn_ts_expr_bridge_node_filter(grn_ctx *ctx, grn_ts_expr_bridge_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ size_t i, count;
+ grn_ts_bool *values;
+ grn_ts_record *tmp;
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, in, n_in,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp = (grn_ts_record *)node->bufs[0].ptr;
+ rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->dest, in, n_in,
+ &node->bufs[1]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ values = (grn_ts_bool *)&node->bufs[1].ptr;
+ for (i = 0, count = 0; i < n_in; i++) {
+ if (values[i]) {
+ out[count++] = in[i];
+ }
+ }
+ *n_out = count;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_bridge_node_adjust() updates scores. */
+static grn_rc
+grn_ts_expr_bridge_node_adjust(grn_ctx *ctx, grn_ts_expr_bridge_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ size_t i;
+ grn_ts_record *tmp;
+ grn_rc rc = grn_ts_expr_node_evaluate_to_buf(ctx, node->src, io, n_io,
+ &node->bufs[0]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ tmp = (grn_ts_record *)node->bufs[0].ptr;
+ rc = grn_ts_expr_node_adjust(ctx, node->dest, tmp, n_io);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ for (i = 0; i < n_io; i++) {
+ io[i].score = tmp[i].score;
+ }
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_node.
+ */
+
+#define GRN_TS_EXPR_NODE_CLOSE_CASE(TYPE, type)\
+ case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
+ grn_ts_expr_ ## type ## _node *type ## _node;\
+ type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
+ grn_ts_expr_ ## type ## _node_close(ctx, type ## _node);\
+ return;\
+ }
+void
+grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node)
+{
+ switch (node->type) {
+ GRN_TS_EXPR_NODE_CLOSE_CASE(ID, id)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(SCORE, score)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(KEY, key)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(VALUE, value)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(CONST, const)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(COLUMN, column)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(OP, op)
+ GRN_TS_EXPR_NODE_CLOSE_CASE(BRIDGE, bridge)
+ }
+}
+#undef GRN_TS_EXPR_NODE_CLOSE_CASE
+
+/* grn_ts_expr_node_deref_once() resolves a reference. */
+static grn_rc
+grn_ts_expr_node_deref_once(grn_ctx *ctx, grn_ts_expr_node *in,
+ grn_ts_expr_node **out)
+{
+ grn_rc rc;
+ grn_id table_id = in->data_type;
+ grn_ts_expr_node *key_node, *bridge_node;
+ grn_obj *table = grn_ctx_at(ctx, table_id);
+ if (!table) {
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d", table_id);
+ }
+ if (!grn_ts_obj_is_table(ctx, table)) {
+ grn_obj_unlink(ctx, table);
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "not table: %d", table_id);
+ }
+ rc = grn_ts_expr_key_node_open(ctx, table, &key_node);
+ grn_obj_unlink(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_bridge_node_open(ctx, in, key_node, &bridge_node);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_node_close(ctx, key_node);
+ return rc;
+ }
+ *out = bridge_node;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_node_deref(grn_ctx *ctx, grn_ts_expr_node **node_ptr)
+{
+ grn_ts_expr_node *node = *node_ptr, **in_ptr = NULL;
+ while ((node->data_kind & ~GRN_TS_VECTOR_FLAG) == GRN_TS_REF) {
+ grn_ts_expr_node *new_node= 0;
+ grn_rc rc = grn_ts_expr_node_deref_once(ctx, node, &new_node);
+ if (rc != GRN_SUCCESS) {
+ if (in_ptr) {
+ *in_ptr = NULL;
+ grn_ts_expr_node_close(ctx, node);
+ }
+ return rc;
+ }
+ if (node == *node_ptr) {
+ grn_ts_expr_bridge_node *bridge_node;
+ bridge_node = (grn_ts_expr_bridge_node *)new_node;
+ if (bridge_node->src != node) {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "broken bridge node");
+ }
+ in_ptr = &bridge_node->src;
+ }
+ node = new_node;
+ }
+ *node_ptr = node;
+ return GRN_SUCCESS;
+}
+
+#define GRN_TS_EXPR_NODE_EVALUATE_CASE(TYPE, type)\
+ case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
+ grn_ts_expr_ ## type ## _node *type ## _node;\
+ type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
+ return grn_ts_expr_ ## type ## _node_evaluate(ctx, type ## _node,\
+ in, n_in, out);\
+ }
+grn_rc
+grn_ts_expr_node_evaluate(grn_ctx *ctx, grn_ts_expr_node *node,
+ const grn_ts_record *in, size_t n_in, void *out)
+{
+ switch (node->type) {
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(ID, id)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(SCORE, score)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(KEY, key)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(VALUE, value)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(CONST, const)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(COLUMN, column)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(OP, op)
+ GRN_TS_EXPR_NODE_EVALUATE_CASE(BRIDGE, bridge)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT,
+ "invalid node type: %d", node->type);
+ }
+ }
+}
+#undef GRN_TS_EXPR_NODE_EVALUATE_CASE
+
+#define GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(KIND, kind)\
+ case GRN_TS_ ## KIND: {\
+ grn_rc rc = grn_ts_buf_reserve(ctx, out, sizeof(grn_ts_ ## kind) * n_in);\
+ if (rc != GRN_SUCCESS) {\
+ return rc;\
+ }\
+ return grn_ts_expr_node_evaluate(ctx, node, in, n_in, out->ptr);\
+ }
+#define GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(KIND, kind)\
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(KIND ## _VECTOR, kind ## _vector)
+grn_rc
+grn_ts_expr_node_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_buf *out)
+{
+ switch (node->data_kind) {
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(BOOL, bool)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(INT, int)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(FLOAT, float)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(TIME, time)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(TEXT, text)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(GEO, geo)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE(REF, ref)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(BOOL, bool)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(INT, int)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(FLOAT, float)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(TIME, time)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(TEXT, text)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(GEO, geo)
+ GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE(REF, ref)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT,
+ "invalid data kind: %d", node->data_kind);
+ }
+ }
+}
+#undef GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_VECTOR_CASE
+#undef GRN_TS_EXPR_NODE_EVALUATE_TO_BUF_CASE
+
+#define GRN_TS_EXPR_NODE_FILTER_CASE(TYPE, type)\
+ case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
+ grn_ts_expr_ ## type ## _node *type ## _node;\
+ type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
+ return grn_ts_expr_ ## type ## _node_filter(ctx, type ## _node,\
+ in, n_in, out, n_out);\
+ }
+grn_rc
+grn_ts_expr_node_filter(grn_ctx *ctx, grn_ts_expr_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out)
+{
+ if (node->data_kind != GRN_TS_BOOL) {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "invalid data kind: %d", node->data_kind);
+ }
+ switch (node->type) {
+ GRN_TS_EXPR_NODE_FILTER_CASE(KEY, key)
+ GRN_TS_EXPR_NODE_FILTER_CASE(VALUE, value)
+ GRN_TS_EXPR_NODE_FILTER_CASE(CONST, const)
+ GRN_TS_EXPR_NODE_FILTER_CASE(COLUMN, column)
+ GRN_TS_EXPR_NODE_FILTER_CASE(OP, op)
+ GRN_TS_EXPR_NODE_FILTER_CASE(BRIDGE, bridge)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "invalid node type: %d", node->type);
+ }
+ }
+}
+#undef GRN_TS_EXPR_NODE_FILTER_CASE
+
+#define GRN_TS_EXPR_NODE_ADJUST_CASE(TYPE, type)\
+ case GRN_TS_EXPR_ ## TYPE ## _NODE: {\
+ grn_ts_expr_ ## type ## _node *type ## _node;\
+ type ## _node = (grn_ts_expr_ ## type ## _node *)node;\
+ return grn_ts_expr_ ## type ## _node_adjust(ctx, type ## _node, io, n_io);\
+ }
+grn_rc
+grn_ts_expr_node_adjust(grn_ctx *ctx, grn_ts_expr_node *node,
+ grn_ts_record *io, size_t n_io)
+{
+ if (node->data_kind != GRN_TS_FLOAT) {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "invalid data kind: %d", node->data_kind);
+ }
+ switch (node->type) {
+ GRN_TS_EXPR_NODE_ADJUST_CASE(SCORE, score)
+ GRN_TS_EXPR_NODE_ADJUST_CASE(KEY, key)
+ GRN_TS_EXPR_NODE_ADJUST_CASE(VALUE, value)
+ GRN_TS_EXPR_NODE_ADJUST_CASE(CONST, const)
+ GRN_TS_EXPR_NODE_ADJUST_CASE(COLUMN, column)
+ GRN_TS_EXPR_NODE_ADJUST_CASE(OP, op)
+ GRN_TS_EXPR_NODE_ADJUST_CASE(BRIDGE, bridge)
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "invalid node type: %d", node->type);
+ }
+ }
+}
+#undef GRN_TS_EXPR_NODE_ADJUST_CASE
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.h b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.h
new file mode 100644
index 00000000..bcc9f371
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_node.h
@@ -0,0 +1,128 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_buf.h"
+#include "ts_op.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ GRN_TS_EXPR_ID_NODE, /* ID (_id). */
+ GRN_TS_EXPR_SCORE_NODE, /* Score (_score). */
+ GRN_TS_EXPR_KEY_NODE, /* Key (_key). */
+ GRN_TS_EXPR_VALUE_NODE, /* Embedded value (_value). */
+ GRN_TS_EXPR_CONST_NODE, /* Const. */
+ GRN_TS_EXPR_COLUMN_NODE, /* Column. */
+ GRN_TS_EXPR_OP_NODE, /* Operator. */
+ GRN_TS_EXPR_BRIDGE_NODE /* Bridge to a subexpression. */
+} grn_ts_expr_node_type;
+
+#define GRN_TS_EXPR_NODE_COMMON_MEMBERS\
+ grn_ts_expr_node_type type; /* Node type. */\
+ grn_ts_data_kind data_kind; /* Abstract data type. */\
+ grn_ts_data_type data_type; /* Detailed data type. */
+
+typedef struct {
+ GRN_TS_EXPR_NODE_COMMON_MEMBERS
+} grn_ts_expr_node;
+
+/* grn_ts_expr_id_node_open() creates a node associated with IDs (_id). */
+grn_rc grn_ts_expr_id_node_open(grn_ctx *ctx, grn_ts_expr_node **node);
+
+/*
+ * grn_ts_expr_score_node_open() creates a node associated with scores
+ * (_score).
+ */
+grn_rc grn_ts_expr_score_node_open(grn_ctx *ctx, grn_ts_expr_node **node);
+
+/* grn_ts_expr_key_node_open() creates a node associated with keys (_key). */
+grn_rc grn_ts_expr_key_node_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_node **node);
+
+/*
+ * grn_ts_expr_value_node_open() creates a node associated with values
+ * (_value).
+ */
+grn_rc grn_ts_expr_value_node_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_node **node);
+
+/* grn_ts_expr_const_node_open() creates a node associated with a const. */
+grn_rc grn_ts_expr_const_node_open(grn_ctx *ctx, grn_ts_data_kind data_kind,
+ grn_ts_data_type data_type,
+ grn_ts_any value, grn_ts_expr_node **node);
+
+/* grn_ts_expr_column_node_open() creates a node associated with a column. */
+grn_rc grn_ts_expr_column_node_open(grn_ctx *ctx, grn_obj *column,
+ grn_ts_expr_node **node);
+
+/*
+ * grn_ts_expr_op_node_open() creates a node associated with an operator.
+ * Note that argument nodes are destroyed on failure.
+ */
+grn_rc grn_ts_expr_op_node_open(grn_ctx *ctx, grn_ts_op_type op_type,
+ grn_ts_expr_node **args, size_t n_args,
+ grn_ts_expr_node **node);
+
+/* grn_ts_expr_bridge_node_open() creates a node associated with a bridge. */
+grn_rc grn_ts_expr_bridge_node_open(grn_ctx *ctx, grn_ts_expr_node *src,
+ grn_ts_expr_node *dest,
+ grn_ts_expr_node **node);
+
+/* grn_ts_expr_node_close() destroys a node. */
+void grn_ts_expr_node_close(grn_ctx *ctx, grn_ts_expr_node *node);
+
+/*
+ * grn_ts_expr_node_deref() resolves references.
+ *
+ * If *node_ptr refers to a reference node, grn_ts_expr_node_deref() creates a
+ * key node associated with the destination table and creates a bridge node
+ * from *node_ptr to the key node. If the data kind of the bridge node is
+ * GRN_TS_REF, references are recursively resolved.
+ */
+grn_rc grn_ts_expr_node_deref(grn_ctx *ctx, grn_ts_expr_node **node_ptr);
+
+/* grn_ts_expr_node_evaluate() evaluates a subtree. */
+grn_rc grn_ts_expr_node_evaluate(grn_ctx *ctx, grn_ts_expr_node *node,
+ const grn_ts_record *in, size_t n_in,
+ void *out);
+
+/* grn_ts_expr_node_evaluate_to_buf() evaluates a subtree. */
+grn_rc grn_ts_expr_node_evaluate_to_buf(grn_ctx *ctx, grn_ts_expr_node *node,
+ const grn_ts_record *in, size_t n_in,
+ grn_ts_buf *out);
+
+/* grn_ts_expr_node_filter() filters records. */
+grn_rc grn_ts_expr_node_filter(grn_ctx *ctx, grn_ts_expr_node *node,
+ grn_ts_record *in, size_t n_in,
+ grn_ts_record *out, size_t *n_out);
+
+/* grn_ts_expr_node_adjust() updates scores. */
+grn_rc grn_ts_expr_node_adjust(grn_ctx *ctx, grn_ts_expr_node *node,
+ grn_ts_record *io, size_t n_io);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.c b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.c
new file mode 100644
index 00000000..7786c046
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.c
@@ -0,0 +1,1329 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_expr_parser.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../grn_ctx.h"
+
+#include "ts_log.h"
+#include "ts_str.h"
+#include "ts_util.h"
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_token.
+ */
+
+#define GRN_TS_EXPR_TOKEN_INIT(TYPE)\
+ memset(token, 0, sizeof(*token));\
+ token->type = GRN_TS_EXPR_ ## TYPE ## _TOKEN;\
+ token->src = src;
+/* grn_ts_expr_dummy_token_init() initializes a token. */
+static void
+grn_ts_expr_dummy_token_init(grn_ctx *ctx, grn_ts_expr_dummy_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(DUMMY)
+}
+
+/* grn_ts_expr_start_token_init() initializes a token. */
+static void
+grn_ts_expr_start_token_init(grn_ctx *ctx, grn_ts_expr_start_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(START)
+}
+
+/* grn_ts_expr_end_token_init() initializes a token. */
+static void
+grn_ts_expr_end_token_init(grn_ctx *ctx, grn_ts_expr_end_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(END)
+}
+
+/* grn_ts_expr_const_token_init() initializes a token. */
+static void
+grn_ts_expr_const_token_init(grn_ctx *ctx, grn_ts_expr_const_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(CONST);
+ grn_ts_buf_init(ctx, &token->buf);
+}
+
+/* grn_ts_expr_name_token_init() initializes a token. */
+static void
+grn_ts_expr_name_token_init(grn_ctx *ctx, grn_ts_expr_name_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(NAME);
+}
+
+/* grn_ts_expr_op_token_init() initializes a token. */
+static void
+grn_ts_expr_op_token_init(grn_ctx *ctx, grn_ts_expr_op_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(OP);
+}
+
+/* grn_ts_expr_bridge_token_init() initializes a token. */
+static void
+grn_ts_expr_bridge_token_init(grn_ctx *ctx, grn_ts_expr_bridge_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(BRIDGE)
+}
+
+/* grn_ts_expr_bracket_token_init() initializes a token. */
+static void
+grn_ts_expr_bracket_token_init(grn_ctx *ctx, grn_ts_expr_bracket_token *token,
+ grn_ts_str src)
+{
+ GRN_TS_EXPR_TOKEN_INIT(BRACKET)
+}
+#undef GRN_TS_EXPR_TOKEN_INIT
+
+/* grn_ts_expr_dummy_token_fin() finalizes a token. */
+static void
+grn_ts_expr_dummy_token_fin(grn_ctx *ctx, grn_ts_expr_dummy_token *token)
+{
+ /* Nothing to do. */
+}
+
+/* grn_ts_expr_start_token_fin() finalizes a token. */
+static void
+grn_ts_expr_start_token_fin(grn_ctx *ctx, grn_ts_expr_start_token *token)
+{
+ /* Nothing to do. */
+}
+
+/* grn_ts_expr_end_token_fin() finalizes a token. */
+static void
+grn_ts_expr_end_token_fin(grn_ctx *ctx, grn_ts_expr_end_token *token)
+{
+ /* Nothing to do. */
+}
+
+/* grn_ts_expr_const_token_fin() finalizes a token. */
+static void
+grn_ts_expr_const_token_fin(grn_ctx *ctx, grn_ts_expr_const_token *token)
+{
+ grn_ts_buf_fin(ctx, &token->buf);
+}
+
+/* grn_ts_expr_name_token_fin() finalizes a token. */
+static void
+grn_ts_expr_name_token_fin(grn_ctx *ctx, grn_ts_expr_name_token *token)
+{
+ /* Nothing to do. */
+}
+
+/* grn_ts_expr_op_token_fin() finalizes a token. */
+static void
+grn_ts_expr_op_token_fin(grn_ctx *ctx, grn_ts_expr_op_token *token)
+{
+ /* Nothing to do. */
+}
+
+/* grn_ts_expr_bridge_token_fin() finalizes a token. */
+static void
+grn_ts_expr_bridge_token_fin(grn_ctx *ctx, grn_ts_expr_bridge_token *token)
+{
+ /* Nothing to do. */
+}
+
+/* grn_ts_expr_bracket_token_fin() finalizes a token. */
+static void
+grn_ts_expr_bracket_token_fin(grn_ctx *ctx, grn_ts_expr_bracket_token *token)
+{
+ /* Nothing to do. */
+}
+
+#define GRN_TS_EXPR_TOKEN_OPEN(TYPE, type)\
+ grn_ts_expr_ ## type ## _token *new_token;\
+ new_token = GRN_MALLOCN(grn_ts_expr_ ## type ## _token, 1);\
+ if (!new_token) {\
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,\
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",\
+ sizeof(grn_ts_expr_ ## type ## _token));\
+ }\
+ grn_ts_expr_ ## type ## _token_init(ctx, new_token, src);\
+ *token = new_token;
+/* grn_ts_expr_dummy_token_open() creates a token. */
+/*
+static grn_rc
+grn_ts_expr_dummy_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_dummy_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(DUMMY, dummy)
+ return GRN_SUCCESS;
+}
+*/
+
+/* grn_ts_expr_start_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_start_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_start_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(START, start)
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_end_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_end_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_end_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(END, end)
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_const_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_const_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_const_token **token)
+ {
+ GRN_TS_EXPR_TOKEN_OPEN(CONST, const)
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_name_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_name_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_name_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(NAME, name)
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_op_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_op_token_open(grn_ctx *ctx, grn_ts_str src, grn_ts_op_type op_type,
+ grn_ts_expr_op_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(OP, op)
+ new_token->op_type = op_type;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_bridge_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_bridge_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_bridge_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(BRIDGE, bridge)
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_bracket_token_open() creates a token. */
+static grn_rc
+grn_ts_expr_bracket_token_open(grn_ctx *ctx, grn_ts_str src,
+ grn_ts_expr_bracket_token **token)
+{
+ GRN_TS_EXPR_TOKEN_OPEN(BRACKET, bracket)
+ return GRN_SUCCESS;
+}
+#undef GRN_TS_EXPR_TOKEN_OPEN
+
+#define GRN_TS_EXPR_TOKEN_CLOSE_CASE(TYPE, type)\
+ case GRN_TS_EXPR_ ## TYPE ## _TOKEN: {\
+ grn_ts_expr_ ## type ## _token *type ## _token;\
+ type ## _token = (grn_ts_expr_ ## type ## _token *)token;\
+ grn_ts_expr_ ## type ## _token_fin(ctx, type ## _token);\
+ break;\
+ }
+/* grn_ts_expr_token_close() destroys a token. */
+static void
+grn_ts_expr_token_close(grn_ctx *ctx, grn_ts_expr_token *token)
+{
+ switch (token->type) {
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(DUMMY, dummy)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(START, start)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(END, end)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(CONST, const)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(NAME, name)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(OP, op)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(BRACKET, bracket)
+ GRN_TS_EXPR_TOKEN_CLOSE_CASE(BRIDGE, bridge)
+ }
+ GRN_FREE(token);
+}
+#undef GRN_TS_EXPR_TOKEN_CLOSE_CASE
+
+/*-------------------------------------------------------------
+ * grn_ts_expr_parser.
+ */
+
+/* grn_ts_expr_parser_init() initializes a parser. */
+static void
+grn_ts_expr_parser_init(grn_ctx *ctx, grn_ts_expr_parser *parser)
+{
+ memset(parser, 0, sizeof(*parser));
+ parser->builder = NULL;
+ grn_ts_buf_init(ctx, &parser->str_buf);
+ parser->tokens = NULL;
+ parser->dummy_tokens = NULL;
+ parser->stack = NULL;
+}
+
+/* grn_ts_expr_parser_fin() finalizes a parser. */
+static void
+grn_ts_expr_parser_fin(grn_ctx *ctx, grn_ts_expr_parser *parser)
+{
+ if (parser->stack) {
+ GRN_FREE(parser->stack);
+ }
+ if (parser->dummy_tokens) {
+ size_t i;
+ for (i = 0; i < parser->n_dummy_tokens; i++) {
+ grn_ts_expr_dummy_token_fin(ctx, &parser->dummy_tokens[i]);
+ }
+ GRN_FREE(parser->dummy_tokens);
+ }
+ if (parser->tokens) {
+ size_t i;
+ for (i = 0; i < parser->n_tokens; i++) {
+ grn_ts_expr_token_close(ctx, parser->tokens[i]);
+ }
+ GRN_FREE(parser->tokens);
+ }
+ grn_ts_buf_fin(ctx, &parser->str_buf);
+ if (parser->builder) {
+ grn_ts_expr_builder_close(ctx, parser->builder);
+ }
+}
+
+grn_rc
+grn_ts_expr_parser_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_parser **parser)
+{
+ grn_rc rc;
+ grn_ts_expr_parser *new_parser;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) || !parser) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ new_parser = GRN_MALLOCN(grn_ts_expr_parser, 1);
+ if (!new_parser) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_expr_parser));
+ }
+ grn_ts_expr_parser_init(ctx, new_parser);
+ rc = grn_ts_expr_builder_open(ctx, table, &new_parser->builder);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_parser_fin(ctx, new_parser);
+ GRN_FREE(new_parser);
+ return rc;
+ }
+ *parser = new_parser;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_expr_parser_close(grn_ctx *ctx, grn_ts_expr_parser *parser)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!parser) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ grn_ts_expr_parser_fin(ctx, parser);
+ GRN_FREE(parser);
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_start() creates the start token. */
+static grn_rc
+grn_ts_expr_parser_tokenize_start(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ grn_ts_str token_str = { str.ptr, 0 };
+ grn_ts_expr_start_token *new_token= 0;
+ grn_rc rc = grn_ts_expr_start_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_end() creates the end token. */
+static grn_rc
+grn_ts_expr_parser_tokenize_end(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ grn_ts_str token_str = { str.ptr, 0 };
+ grn_ts_expr_end_token *new_token= 0;
+ grn_rc rc = grn_ts_expr_end_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_number() tokenizes an Int or Float literal. */
+static grn_rc
+grn_ts_expr_parser_tokenize_number(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ char *end;
+ grn_rc rc;
+ grn_ts_int int_value;
+ grn_ts_str token_str;
+ grn_ts_expr_const_token *new_token= 0;
+
+ int_value = strtol(str.ptr, &end, 0);
+ if ((end != str.ptr) && (*end != '.') && (*end != 'e')) {
+ if (grn_ts_byte_is_name_char(*end)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
+ "unterminated Int literal: \"%.*s\"",
+ (int)str.size, str.ptr);
+ }
+ token_str.ptr = str.ptr;
+ token_str.size = end - str.ptr;
+ rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ new_token->data_kind = GRN_TS_INT;
+ new_token->content.as_int = int_value;
+ } else {
+ grn_ts_float float_value = strtod(str.ptr, &end);
+ if (end == str.ptr) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid number literal: \"%.*s\"",
+ (int)str.size, str.ptr);
+ }
+ if (grn_ts_byte_is_name_char(*end)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
+ "unterminated Float literal: \"%.*s\"",
+ (int)str.size, str.ptr);
+ }
+ token_str.ptr = str.ptr;
+ token_str.size = end - str.ptr;
+ rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ new_token->data_kind = GRN_TS_FLOAT;
+ new_token->content.as_float = float_value;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_text() tokenizes a Text literal. */
+static grn_rc
+grn_ts_expr_parser_tokenize_text(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ size_t i, n_escapes = 0;
+ grn_rc rc;
+ grn_ts_str token_str;
+ grn_ts_expr_const_token *new_token= 0;
+ for (i = 1; i < str.size; i++) {
+ if (str.ptr[i] == '\\') {
+ i++;
+ n_escapes++;
+ } else if (str.ptr[i] == '"') {
+ break;
+ }
+ }
+ if (i >= str.size) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "no closing double quote: \"%.*s\"",
+ (int)str.size, str.ptr);
+ }
+ token_str.ptr = str.ptr;
+ token_str.size = i + 1;
+ rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ new_token->data_kind = GRN_TS_TEXT;
+ if (n_escapes) {
+ char *buf_ptr;
+ const char *str_ptr = str.ptr + 1;
+ size_t size = token_str.size - 2 - n_escapes;
+ rc = grn_ts_buf_resize(ctx, &new_token->buf, size);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_token_close(ctx, (grn_ts_expr_token *)new_token);
+ return rc;
+ }
+ buf_ptr = (char *)new_token->buf.ptr;
+ for (i = 0; i < size; i++) {
+ if (str_ptr[i] == '\\') {
+ str_ptr++;
+ }
+ buf_ptr[i] = str_ptr[i];
+ }
+ new_token->content.as_text.ptr = buf_ptr;
+ new_token->content.as_text.size = size;
+ } else {
+ new_token->content.as_text.ptr = token_str.ptr + 1;
+ new_token->content.as_text.size = token_str.size - 2;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_name() tokenizes a Bool literal or a name. */
+static grn_rc
+grn_ts_expr_parser_tokenize_name(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ size_t i;
+ grn_ts_str token_str;
+ for (i = 1; i < str.size; i++) {
+ if (!grn_ts_byte_is_name_char(str.ptr[i])) {
+ break;
+ }
+ }
+ token_str.ptr = str.ptr;
+ token_str.size = i;
+
+ if (grn_ts_str_is_bool(token_str)) {
+ grn_ts_expr_const_token *new_token= 0;
+ grn_rc rc = grn_ts_expr_const_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ new_token->data_kind = GRN_TS_BOOL;
+ if (token_str.ptr[0] == 't') {
+ new_token->content.as_bool = GRN_TRUE;
+ } else {
+ new_token->content.as_bool = GRN_FALSE;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+ }
+ return grn_ts_expr_name_token_open(ctx, token_str, token);
+}
+
+/* grn_ts_expr_parser_tokenize_bridge() tokenizes a bridge. */
+static grn_rc
+grn_ts_expr_parser_tokenize_bridge(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ grn_ts_str token_str = { str.ptr, 1 };
+ grn_ts_expr_bridge_token *new_token= 0;
+ grn_rc rc = grn_ts_expr_bridge_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_bracket() tokenizes a bracket. */
+static grn_rc
+grn_ts_expr_parser_tokenize_bracket(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str,
+ grn_ts_expr_token **token)
+{
+ grn_ts_str token_str = { str.ptr, 1 };
+ grn_ts_expr_bracket_token *new_token= 0;
+ grn_rc rc = grn_ts_expr_bracket_token_open(ctx, token_str, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ts_expr_parsre_tokenize_sign() tokenizes an operator '+' or '-'.
+ * Note that '+' and '-' have two roles each.
+ * '+' is GRN_TS_OP_POSITIVE or GRN_TS_OP_PLUS.
+ * '-' is GRN_TS_OP_NEGATIVE or GRN_TS_OP_MINUS.
+ */
+static grn_rc
+grn_ts_expr_parser_tokenize_sign(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ size_t n_args;
+ grn_rc rc;
+ grn_ts_op_type op_type;
+ grn_ts_str token_str = { str.ptr, 1 };
+ grn_ts_expr_token *prev_token = parser->tokens[parser->n_tokens - 1];
+ grn_ts_expr_op_token *new_token= 0;
+ switch (prev_token->type) {
+ case GRN_TS_EXPR_START_TOKEN:
+ case GRN_TS_EXPR_OP_TOKEN: {
+ n_args = 1;
+ break;
+ }
+ case GRN_TS_EXPR_CONST_TOKEN:
+ case GRN_TS_EXPR_NAME_TOKEN: {
+ n_args = 2;
+ break;
+ }
+ case GRN_TS_EXPR_BRACKET_TOKEN: {
+ grn_ts_str bracket;
+ const grn_ts_expr_bracket_token *bracket_token;
+ bracket_token = (const grn_ts_expr_bracket_token *)prev_token;
+ bracket = bracket_token->src;
+ switch (bracket.ptr[0]) {
+ case '(': case '[': {
+ n_args = 1;
+ break;
+ }
+ case ')': case ']': {
+ n_args = 2;
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "undefined bracket: \"%.*s\"",
+ (int)bracket.size, bracket.ptr);
+ }
+ }
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence: %d",
+ prev_token->type);
+ }
+ }
+ if (token_str.ptr[0] == '+') {
+ op_type = (n_args == 1) ? GRN_TS_OP_POSITIVE : GRN_TS_OP_PLUS;
+ } else {
+ op_type = (n_args == 1) ? GRN_TS_OP_NEGATIVE : GRN_TS_OP_MINUS;
+ }
+ rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_op() tokenizes an operator. */
+static grn_rc
+grn_ts_expr_parser_tokenize_op(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_ts_str token_str = str;
+ grn_ts_op_type op_type;
+ grn_ts_expr_op_token *new_token= 0;
+ switch (str.ptr[0]) {
+ case '+': case '-': {
+ return grn_ts_expr_parser_tokenize_sign(ctx, parser, str, token);
+ }
+ case '!': {
+ if ((str.size >= 2) && (str.ptr[1] == '=')) {
+ token_str.size = 2;
+ op_type = GRN_TS_OP_NOT_EQUAL;
+ } else {
+ token_str.size = 1;
+ op_type = GRN_TS_OP_LOGICAL_NOT;
+ }
+ rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
+ break;
+ }
+#define GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE(label, TYPE_1, TYPE_2, TYPE_3,\
+ TYPE_EQUAL)\
+ case label: {\
+ if ((str.size >= 2) && (str.ptr[1] == '=')) {\
+ token_str.size = 2;\
+ op_type = GRN_TS_OP_ ## TYPE_EQUAL;\
+ } else if ((str.size >= 2) && (str.ptr[1] == label)) {\
+ if ((str.size >= 3) && (str.ptr[2] == label)) {\
+ token_str.size = 3;\
+ op_type = GRN_TS_OP_ ## TYPE_3;\
+ } else {\
+ token_str.size = 2;\
+ op_type = GRN_TS_OP_ ## TYPE_2;\
+ }\
+ } else {\
+ token_str.size = 1;\
+ op_type = GRN_TS_OP_ ## TYPE_1;\
+ }\
+ rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);\
+ break;\
+ }
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('<', LESS, SHIFT_ARITHMETIC_LEFT,
+ SHIFT_LOGICAL_LEFT, LESS_EQUAL)
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('>', GREATER, SHIFT_ARITHMETIC_RIGHT,
+ SHIFT_LOGICAL_RIGHT, GREATER_EQUAL)
+#undef GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE
+ case '&': {
+ if ((str.size >= 2) && (str.ptr[1] == '&')) {
+ token_str.size = 2;
+ op_type = GRN_TS_OP_LOGICAL_AND;
+ } else if ((str.size >= 2) && (str.ptr[1] == '&')) {
+ token_str.size = 2;
+ op_type = GRN_TS_OP_LOGICAL_SUB;
+ } else {
+ token_str.size = 1;
+ op_type = GRN_TS_OP_BITWISE_AND;
+ }
+ rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
+ break;
+ }
+ case '|': {
+ if ((str.size >= 2) && (str.ptr[1] == '|')) {
+ token_str.size = 2;
+ op_type = GRN_TS_OP_LOGICAL_OR;
+ } else {
+ token_str.size = 1;
+ op_type = GRN_TS_OP_BITWISE_OR;
+ }
+ rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
+ break;
+ }
+ case '=': {
+ if ((str.size < 2) || (str.ptr[1] != '=')) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
+ "single equal not available: =\"%.*s\"",
+ (int)str.size, str.ptr);
+ }
+ token_str.size = 2;
+ rc = grn_ts_expr_op_token_open(ctx, token_str, GRN_TS_OP_EQUAL,
+ &new_token);
+ break;
+ }
+#define GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE(label, TYPE)\
+ case label: {\
+ token_str.size = 1;\
+ rc = grn_ts_expr_op_token_open(ctx, token_str, GRN_TS_OP_ ## TYPE,\
+ &new_token);\
+ break;\
+ }
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('~', BITWISE_NOT)
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('^', BITWISE_XOR)
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('*', MULTIPLICATION)
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('/', DIVISION)
+ GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE('%', MODULUS)
+#undef GRN_TS_EXPR_PARSER_TOKENIZE_OP_CASE
+ case '@': {
+ if ((str.size >= 2) && (str.ptr[1] == '^')) {
+ token_str.size = 2;
+ op_type = GRN_TS_OP_PREFIX_MATCH;
+ } else if ((str.size >= 2) && (str.ptr[1] == '$')) {
+ token_str.size = 2;
+ op_type = GRN_TS_OP_SUFFIX_MATCH;
+ } else {
+ token_str.size = 1;
+ op_type = GRN_TS_OP_MATCH;
+ }
+ rc = grn_ts_expr_op_token_open(ctx, token_str, op_type, &new_token);
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid character: \"%.*s\"",
+ (int)str.size, str.ptr);
+ }
+ }
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *token = (grn_ts_expr_token *)new_token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize_next() extracts the next token. */
+static grn_rc
+grn_ts_expr_parser_tokenize_next(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr_token **token)
+{
+ grn_ts_str rest;
+ if (!parser->n_tokens) {
+ return grn_ts_expr_parser_tokenize_start(ctx, parser, str, token);
+ }
+ rest = grn_ts_str_trim_left(str);
+ if (!rest.size) {
+ return grn_ts_expr_parser_tokenize_end(ctx, parser, rest, token);
+ }
+ if (grn_ts_str_has_number_prefix(rest)) {
+ grn_ts_expr_token *prev_token;
+ if ((rest.ptr[0] != '+') && (rest.ptr[0] != '-')) {
+ return grn_ts_expr_parser_tokenize_number(ctx, parser, rest, token);
+ }
+ prev_token = parser->tokens[parser->n_tokens - 1];
+ switch (prev_token->type) {
+ case GRN_TS_EXPR_START_TOKEN:
+ case GRN_TS_EXPR_OP_TOKEN: {
+ return grn_ts_expr_parser_tokenize_number(ctx, parser, rest, token);
+ }
+ case GRN_TS_EXPR_BRACKET_TOKEN: {
+ if ((prev_token->src.ptr[0] == '(') ||
+ (prev_token->src.ptr[0] == '[')) {
+ return grn_ts_expr_parser_tokenize_number(ctx, parser, rest, token);
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ if (rest.ptr[0] == '"') {
+ return grn_ts_expr_parser_tokenize_text(ctx, parser, rest, token);
+ }
+ if (grn_ts_byte_is_name_char(rest.ptr[0])) {
+ return grn_ts_expr_parser_tokenize_name(ctx, parser, rest, token);
+ }
+ switch (rest.ptr[0]) {
+ case '(': case ')': case '[': case ']': {
+ return grn_ts_expr_parser_tokenize_bracket(ctx, parser, rest, token);
+ }
+ case '.': {
+ return grn_ts_expr_parser_tokenize_bridge(ctx, parser, rest, token);
+ }
+ default: {
+ return grn_ts_expr_parser_tokenize_op(ctx, parser, rest, token);
+ }
+ }
+}
+
+/*
+ * grn_ts_expr_parser_reserve_tokens() extends a token buffer for a new token.
+ */
+static grn_rc
+grn_ts_expr_parser_reserve_tokens(grn_ctx *ctx, grn_ts_expr_parser *parser)
+{
+ size_t i, n_bytes, new_max_n_tokens;
+ grn_ts_expr_token **new_tokens;
+ if (parser->n_tokens < parser->max_n_tokens) {
+ return GRN_SUCCESS;
+ }
+ new_max_n_tokens = parser->n_tokens * 2;
+ if (!new_max_n_tokens) {
+ new_max_n_tokens = 1;
+ }
+ n_bytes = sizeof(grn_ts_expr_token *) * new_max_n_tokens;
+ new_tokens = (grn_ts_expr_token **)GRN_REALLOC(parser->tokens, n_bytes);
+ if (!new_tokens) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE,
+ n_bytes);
+ }
+ for (i = parser->n_tokens; i < new_max_n_tokens; i++) {
+ new_tokens[i] = NULL;
+ }
+ parser->tokens = new_tokens;
+ parser->max_n_tokens = new_max_n_tokens;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_tokenize() tokenizes a string. */
+static grn_rc
+grn_ts_expr_parser_tokenize(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str)
+{
+ grn_ts_str rest = str;
+ const char *end = str.ptr + str.size;
+ grn_ts_expr_token *token = NULL;
+ GRN_TS_DEBUG("str = \"%.*s\"", (int)str.size, str.ptr);
+ do {
+ grn_rc rc = grn_ts_expr_parser_reserve_tokens(ctx, parser);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_parser_tokenize_next(ctx, parser, rest, &token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if ((token->type != GRN_TS_EXPR_START_TOKEN) &&
+ (token->type != GRN_TS_EXPR_END_TOKEN)) {
+ GRN_TS_DEBUG("token = \"%.*s\"", (int)token->src.size, token->src.ptr);
+ }
+ parser->tokens[parser->n_tokens++] = token;
+ rest.ptr = token->src.ptr + token->src.size;
+ rest.size = end - rest.ptr;
+ } while (token->type != GRN_TS_EXPR_END_TOKEN);
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_push_const() pushes a token to an expression. */
+static grn_rc
+grn_ts_expr_parser_push_const(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_const_token *token)
+{
+ return grn_ts_expr_builder_push_const(ctx, parser->builder, token->data_kind,
+ GRN_DB_VOID, token->content);
+}
+
+/* grn_ts_expr_parser_push_name() pushes a token to an expression. */
+static grn_rc
+grn_ts_expr_parser_push_name(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_name_token *token)
+{
+ return grn_ts_expr_builder_push_name(ctx, parser->builder, token->src);
+}
+
+/* grn_ts_expr_parser_push_op() pushes a token to an expression. */
+static grn_rc
+grn_ts_expr_parser_push_op(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_op_token *token)
+{
+ return grn_ts_expr_builder_push_op(ctx, parser->builder, token->op_type);
+}
+
+/*
+ * grn_ts_expr_parser_apply_one() applies a bridge or prior operator.
+ * If there is no target, this function returns GRN_END_OF_DATA.
+ */
+// FIXME: Support a ternary operator.
+static grn_rc
+grn_ts_expr_parser_apply_one(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_op_precedence precedence_threshold)
+{
+ grn_rc rc;
+ grn_ts_str src;
+ grn_ts_expr_token **stack = parser->stack;
+ grn_ts_expr_dummy_token *dummy_token;
+ size_t n_args, depth = parser->stack_depth;
+ if (depth < 2) {
+ return GRN_END_OF_DATA;
+ }
+ if (stack[depth - 1]->type != GRN_TS_EXPR_DUMMY_TOKEN) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "argument must be dummy token");
+ }
+
+ /* Check the number of arguments. */
+ switch (stack[depth - 2]->type) {
+ case GRN_TS_EXPR_BRIDGE_TOKEN: {
+ rc = grn_ts_expr_builder_end_subexpr(ctx, parser->builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ n_args = 2;
+ break;
+ }
+ case GRN_TS_EXPR_OP_TOKEN: {
+ grn_ts_expr_op_token *op_token;
+ grn_ts_op_precedence precedence;
+ op_token = (grn_ts_expr_op_token *)stack[depth - 2];
+ precedence = grn_ts_op_get_precedence(op_token->op_type);
+ if (precedence < precedence_threshold) {
+ return GRN_END_OF_DATA;
+ }
+ rc = grn_ts_expr_parser_push_op(ctx, parser, op_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ n_args = grn_ts_op_get_n_args(op_token->op_type);
+ break;
+ }
+ default: {
+ return GRN_END_OF_DATA;
+ }
+ }
+
+ /* Concatenate the source strings. */
+ switch (n_args) {
+ case 1: {
+ grn_ts_expr_token *arg = stack[depth - 1];
+ src.ptr = stack[depth - 2]->src.ptr;
+ src.size = (arg->src.ptr + arg->src.size) - src.ptr;
+ break;
+ }
+ case 2: {
+ grn_ts_expr_token *args[2] = { stack[depth - 3], stack[depth - 1] };
+ src.ptr = args[0]->src.ptr;
+ src.size = (args[1]->src.ptr + args[1]->src.size) - src.ptr;
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED,
+ "invalid #arguments: %" GRN_FMT_SIZE,
+ n_args);
+ }
+ }
+
+ /* Replace the operator and argument tokens with a dummy token. */
+ dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
+ GRN_TS_DEBUG("dummy token: \"%.*s\"", (int)src.size, src.ptr);
+ grn_ts_expr_dummy_token_init(ctx, dummy_token, src);
+ depth -= n_args + 1;
+ stack[depth++] = dummy_token;
+ parser->stack_depth = depth;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_apply() applies bridges and prior operators. */
+static grn_rc
+grn_ts_expr_parser_apply(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_op_precedence precedence_threshold)
+{
+ for ( ; ; ) {
+ grn_rc rc = grn_ts_expr_parser_apply_one(ctx, parser,
+ precedence_threshold);
+ if (rc == GRN_END_OF_DATA) {
+ return GRN_SUCCESS;
+ } else if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+}
+
+/* grn_ts_expr_parser_analyze_op() analyzes a token. */
+static grn_rc
+grn_ts_expr_parser_analyze_op(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_op_token *token)
+{
+ size_t n_args = grn_ts_op_get_n_args(token->op_type);
+ grn_ts_expr_token *ex_token = parser->stack[parser->stack_depth - 1];
+ if (n_args == 1) {
+ if (ex_token->type == GRN_TS_EXPR_DUMMY_TOKEN) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ } else if (n_args == 2) {
+ grn_ts_op_precedence precedence = grn_ts_op_get_precedence(token->op_type);
+ grn_rc rc = grn_ts_expr_parser_apply(ctx, parser, precedence);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_analyze_bridge() analyzes a token. */
+static grn_rc
+grn_ts_expr_parser_analyze_bridge(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_bridge_token *token)
+{
+ grn_rc rc = grn_ts_expr_builder_begin_subexpr(ctx, parser->builder);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_expr_parser_analyze_bracket() analyzes a token. */
+static grn_rc
+grn_ts_expr_parser_analyze_bracket(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_bracket_token *token)
+{
+ grn_ts_expr_token *ex_token = parser->stack[parser->stack_depth - 1];
+ switch (token->src.ptr[0]) {
+ case '(': {
+ if (ex_token->type == GRN_TS_EXPR_DUMMY_TOKEN) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
+ return GRN_SUCCESS;
+ }
+ case '[': {
+ if (ex_token->type != GRN_TS_EXPR_DUMMY_TOKEN) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ parser->stack[parser->stack_depth++] = (grn_ts_expr_token *)token;
+ return GRN_SUCCESS;
+ }
+ case ')': case ']': {
+ grn_ts_expr_token *ex_ex_token;
+ grn_rc rc = grn_ts_expr_parser_apply(ctx, parser, 0);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (parser->stack_depth < 2) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ ex_ex_token = parser->stack[parser->stack_depth - 2];
+ if (ex_ex_token->type != GRN_TS_EXPR_BRACKET_TOKEN) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ if (token->src.ptr[0] == ')') {
+ size_t depth = parser->stack_depth;
+ grn_ts_str src;
+ grn_ts_expr_dummy_token *dummy_token;
+ if (ex_ex_token->src.ptr[0] != '(') {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ src.ptr = ex_ex_token->src.ptr;
+ src.size = (token->src.ptr + token->src.size) - src.ptr;
+ dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
+ GRN_TS_DEBUG("dummy token: \"%.*s\"", (int)src.size, src.ptr);
+ grn_ts_expr_dummy_token_init(ctx, dummy_token, src);
+ parser->stack[depth - 2] = dummy_token;
+ parser->stack_depth--;
+ // TODO: Apply a function.
+ } else if (token->src.ptr[0] == ']') {
+ size_t depth = parser->stack_depth;
+ if (ex_ex_token->src.ptr[0] != '[') {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "invalid token sequence");
+ }
+ parser->stack[depth - 2] = parser->stack[depth - 1];
+ parser->stack_depth--;
+ // TODO: Push a subscript operator.
+ }
+ return GRN_SUCCESS;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT, "undefined bracket: \"%.*s\"",
+ (int)token->src.size, token->src.ptr);
+ }
+ }
+}
+
+/* grn_ts_expr_parser_analyze_token() analyzes a token. */
+static grn_rc
+grn_ts_expr_parser_analyze_token(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_expr_token *token)
+{
+ switch (token->type) {
+ case GRN_TS_EXPR_START_TOKEN: {
+ parser->stack[parser->stack_depth++] = token;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_EXPR_END_TOKEN: {
+ return grn_ts_expr_parser_apply(ctx, parser, 0);
+ }
+ case GRN_TS_EXPR_CONST_TOKEN: {
+ grn_ts_expr_const_token *const_token = (grn_ts_expr_const_token *)token;
+ grn_ts_expr_dummy_token *dummy_token;
+ grn_rc rc = grn_ts_expr_parser_push_const(ctx, parser, const_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
+ grn_ts_expr_dummy_token_init(ctx, dummy_token, token->src);
+ parser->stack[parser->stack_depth++] = dummy_token;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_EXPR_NAME_TOKEN: {
+ grn_ts_expr_name_token *name_token = (grn_ts_expr_name_token *)token;
+ grn_ts_expr_dummy_token *dummy_token;
+ grn_rc rc = grn_ts_expr_parser_push_name(ctx, parser, name_token);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ dummy_token = &parser->dummy_tokens[parser->n_dummy_tokens++];
+ grn_ts_expr_dummy_token_init(ctx, dummy_token, token->src);
+ parser->stack[parser->stack_depth++] = dummy_token;
+ return GRN_SUCCESS;
+ }
+ case GRN_TS_EXPR_OP_TOKEN: {
+ grn_ts_expr_op_token *op_token = (grn_ts_expr_op_token *)token;
+ return grn_ts_expr_parser_analyze_op(ctx, parser, op_token);
+ }
+ case GRN_TS_EXPR_BRIDGE_TOKEN: {
+ grn_ts_expr_bridge_token *bridge_token;
+ bridge_token = (grn_ts_expr_bridge_token *)token;
+ return grn_ts_expr_parser_analyze_bridge(ctx, parser, bridge_token);
+ }
+ case GRN_TS_EXPR_BRACKET_TOKEN: {
+ grn_ts_expr_bracket_token *bracket_token;
+ bracket_token = (grn_ts_expr_bracket_token *)token;
+ return grn_ts_expr_parser_analyze_bracket(ctx, parser, bracket_token);
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid token type: %d",
+ token->type);
+ }
+ }
+}
+
+/* grn_ts_expr_parser_analyze() analyzes tokens. */
+static grn_rc
+grn_ts_expr_parser_analyze(grn_ctx *ctx, grn_ts_expr_parser *parser)
+{
+ size_t i;
+
+ /* Reserve temporary work spaces. */
+ if (parser->n_tokens > parser->max_n_dummy_tokens) {
+ size_t n_bytes = sizeof(grn_ts_expr_dummy_token) * parser->n_tokens;
+ grn_ts_expr_dummy_token *dummy_tokens = parser->dummy_tokens;
+ grn_ts_expr_dummy_token *new_dummy_tokens;
+ new_dummy_tokens = (grn_ts_expr_dummy_token *)GRN_REALLOC(dummy_tokens,
+ n_bytes);
+ if (!new_dummy_tokens) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes);
+ }
+ parser->dummy_tokens = new_dummy_tokens;
+ parser->max_n_dummy_tokens = parser->n_tokens;
+ }
+ if (parser->n_tokens > parser->stack_size) {
+ size_t n_bytes = sizeof(grn_ts_expr_token *) * parser->n_tokens;
+ grn_ts_expr_token **new_stack;
+ new_stack = (grn_ts_expr_token **)GRN_REALLOC(parser->stack, n_bytes);
+ if (!new_stack) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_REALLOC failed: %" GRN_FMT_SIZE, n_bytes);
+ }
+ parser->stack = new_stack;
+ parser->stack_size = parser->n_tokens;
+ }
+
+ /* Analyze tokens. */
+ for (i = 0; i < parser->n_tokens; i++) {
+ grn_rc rc;
+ rc = grn_ts_expr_parser_analyze_token(ctx, parser, parser->tokens[i]);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (parser->stack_depth != 2) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_FORMAT,
+ "tokens left in stack: %" GRN_FMT_SIZE,
+ parser->stack_depth);
+ }
+ return GRN_SUCCESS;
+}
+
+/*
+ * grn_ts_expr_parser_clear() clears the internal states for parsing the next
+ * string.
+ */
+static void
+grn_ts_expr_parser_clear(grn_ctx *ctx, grn_ts_expr_parser *parser)
+{
+ parser->stack_depth = 0;
+ if (parser->dummy_tokens) {
+ size_t i;
+ for (i = 0; i < parser->n_dummy_tokens; i++) {
+ grn_ts_expr_dummy_token_fin(ctx, &parser->dummy_tokens[i]);
+ }
+ parser->n_dummy_tokens = 0;
+ }
+ if (parser->tokens) {
+ size_t i;
+ for (i = 0; i < parser->n_tokens; i++) {
+ grn_ts_expr_token_close(ctx, parser->tokens[i]);
+ }
+ parser->n_tokens = 0;
+ }
+ grn_ts_expr_builder_clear(ctx, parser->builder);
+}
+
+grn_rc
+grn_ts_expr_parser_parse(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr **expr)
+{
+ grn_rc rc;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!parser || (!str.ptr && str.size)) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ grn_ts_expr_parser_clear(ctx, parser);
+ rc = grn_ts_buf_reserve(ctx, &parser->str_buf, str.size + 1);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ grn_memcpy(parser->str_buf.ptr, str.ptr, str.size);
+ ((char *)parser->str_buf.ptr)[str.size] = '\0';
+ str.ptr = (const char *)parser->str_buf.ptr;
+ rc = grn_ts_expr_parser_tokenize(ctx, parser, str);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ rc = grn_ts_expr_parser_analyze(ctx, parser);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ return grn_ts_expr_builder_complete(ctx, parser->builder, expr);
+}
+
+grn_rc
+grn_ts_expr_parser_split(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_str *first, grn_ts_str *rest)
+{
+ size_t i;
+ char stack_top;
+ grn_rc rc = GRN_SUCCESS;
+ grn_ts_buf stack;
+
+ // FIXME: `stack` should be a member of `parser`.
+ grn_ts_buf_init(ctx, &stack);
+ for ( ; ; ) {
+ str = grn_ts_str_trim_left(str);
+ if (!str.size) {
+ rc = GRN_END_OF_DATA;
+ break;
+ }
+ for (i = 0; i < str.size; i++) {
+ if (stack.pos) {
+ if (str.ptr[i] == stack_top) {
+ if (--stack.pos) {
+ stack_top = ((char *)stack.ptr)[stack.pos - 1];
+ }
+ continue;
+ }
+ if (stack_top == '"') {
+ /* Skip the next byte of an escape character. */
+ if ((str.ptr[i] == '\\') && (i < (str.size - 1))) {
+ i++;
+ }
+ continue;
+ }
+ } else if (str.ptr[i] == ',') {
+ /* An expression delimiter. */
+ break;
+ }
+ switch (str.ptr[i]) {
+ case '(': {
+ stack_top = ')';
+ rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
+ break;
+ }
+ case '[': {
+ stack_top = ']';
+ rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
+ break;
+ }
+ case '{': {
+ stack_top = '}';
+ rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
+ break;
+ }
+ case '"': {
+ stack_top = '"';
+ rc = grn_ts_buf_write(ctx, &stack, &stack_top, 1);
+ break;
+ }
+ }
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ if (i) {
+ /* Set the result. */
+ first->ptr = str.ptr;
+ first->size = i;
+ if (first->size == str.size) {
+ rest->ptr = str.ptr + str.size;
+ rest->size = 0;
+ } else {
+ rest->ptr = str.ptr + first->size + 1;
+ rest->size = str.size - first->size - 1;
+ }
+ break;
+ }
+ str.ptr++;
+ str.size--;
+ }
+ grn_ts_buf_fin(ctx, &stack);
+ return rc;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.h b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.h
new file mode 100644
index 00000000..77205983
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_expr_parser.h
@@ -0,0 +1,107 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "ts_expr.h"
+#include "ts_expr_builder.h"
+#include "ts_str.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ GRN_TS_EXPR_DUMMY_TOKEN, /* No extra data. */
+ GRN_TS_EXPR_START_TOKEN, /* No extra data. */
+ GRN_TS_EXPR_END_TOKEN, /* No extra data. */
+ GRN_TS_EXPR_CONST_TOKEN, /* +data_kind, content and buf. */
+ GRN_TS_EXPR_NAME_TOKEN, /* +name. */
+ GRN_TS_EXPR_OP_TOKEN, /* +op_type. */
+ GRN_TS_EXPR_BRIDGE_TOKEN, /* No extra data. */
+ GRN_TS_EXPR_BRACKET_TOKEN /* No extra data. */
+} grn_ts_expr_token_type;
+
+#define GRN_TS_EXPR_TOKEN_COMMON_MEMBERS\
+ grn_ts_str src; /* Source string. */\
+ grn_ts_expr_token_type type; /* Token type. */
+
+typedef struct {
+ GRN_TS_EXPR_TOKEN_COMMON_MEMBERS
+} grn_ts_expr_token;
+
+typedef grn_ts_expr_token grn_ts_expr_dummy_token;
+typedef grn_ts_expr_token grn_ts_expr_start_token;
+typedef grn_ts_expr_token grn_ts_expr_end_token;
+
+typedef struct {
+ GRN_TS_EXPR_TOKEN_COMMON_MEMBERS
+ grn_ts_data_kind data_kind; /* The data kind of the const. */
+ grn_ts_any content; /* The const. */
+ grn_ts_buf buf; /* Buffer for content.as_text. */
+} grn_ts_expr_const_token;
+
+typedef grn_ts_expr_token grn_ts_expr_name_token;
+
+typedef struct {
+ GRN_TS_EXPR_TOKEN_COMMON_MEMBERS
+ grn_ts_op_type op_type; /* Operator type. */
+} grn_ts_expr_op_token;
+
+typedef grn_ts_expr_token grn_ts_expr_bridge_token;
+typedef grn_ts_expr_token grn_ts_expr_bracket_token;
+
+typedef struct {
+ grn_ts_expr_builder *builder; /* Builder. */
+ grn_ts_buf str_buf; /* Buffer for a source string. */
+ grn_ts_expr_token **tokens; /* Tokens. */
+ size_t n_tokens; /* Number of tokens. */
+ size_t max_n_tokens; /* Maximum number of tokens. */
+ grn_ts_expr_dummy_token *dummy_tokens; /* Dummy tokens. */
+ size_t n_dummy_tokens; /* Number of dummy tokens. */
+ size_t max_n_dummy_tokens; /* Maximum number of dummy tokens. */
+ grn_ts_expr_token **stack; /* Token stack. */
+ size_t stack_depth; /* Token stack's current depth. */
+ size_t stack_size; /* Token stack's capacity. */
+} grn_ts_expr_parser;
+
+/* grn_ts_expr_parser_open() creates a parser. */
+grn_rc grn_ts_expr_parser_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_expr_parser **parser);
+
+/* grn_ts_expr_parser_close() destroys a parser. */
+grn_rc grn_ts_expr_parser_close(grn_ctx *ctx, grn_ts_expr_parser *parser);
+
+/* grn_ts_expr_parser_parse() parses a string and creates an expression. */
+grn_rc grn_ts_expr_parser_parse(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_expr **expr);
+
+/*
+ * grn_ts_expr_parser_split() splits comma-separated strings into the first
+ * expression and the rest.
+ * Note that if `str` is empty, this function returns GRN_END_OF_DATA.
+ */
+grn_rc grn_ts_expr_parser_split(grn_ctx *ctx, grn_ts_expr_parser *parser,
+ grn_ts_str str, grn_ts_str *first,
+ grn_ts_str *rest);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_log.h b/storage/mroonga/vendor/groonga/lib/ts/ts_log.h
new file mode 100644
index 00000000..844a0ee6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_log.h
@@ -0,0 +1,46 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+#include "../grn_ctx.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GRN_TS_DEBUG() logs a message that is useful for debug. */
+#define GRN_TS_DEBUG(...) GRN_LOG(ctx, GRN_LOG_DEBUG, __VA_ARGS__)
+
+/* GRN_TS_WARN() logs a warning. */
+#define GRN_TS_WARN(rc, ...) WARN(rc, __VA_ARGS__)
+
+/* GRN_TS_ERR() reports an error. */
+#define GRN_TS_ERR(rc, ...) ERR(rc, __VA_ARGS__)
+
+/* GRN_TS_ERR_RETURN() reports an error and returns its error code. */
+#define GRN_TS_ERR_RETURN(rc, ...) do {\
+ GRN_TS_ERR(rc, __VA_ARGS__);\
+ return rc;\
+} while (GRN_FALSE)
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_op.c b/storage/mroonga/vendor/groonga/lib/ts/ts_op.c
new file mode 100644
index 00000000..64262b77
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_op.c
@@ -0,0 +1,131 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_op.h"
+
+size_t
+grn_ts_op_get_n_args(grn_ts_op_type op_type)
+{
+ switch (op_type) {
+ case GRN_TS_OP_LOGICAL_NOT: /* !X */
+ case GRN_TS_OP_BITWISE_NOT: /* ~X */
+ case GRN_TS_OP_POSITIVE: /* +X */
+ case GRN_TS_OP_NEGATIVE: /* -X */
+ case GRN_TS_OP_FLOAT:
+ case GRN_TS_OP_TIME: {
+ return 1;
+ }
+ case GRN_TS_OP_LOGICAL_AND: /* X && Y */
+ case GRN_TS_OP_LOGICAL_OR: /* X || Y */
+ case GRN_TS_OP_LOGICAL_SUB: /* X &! Y */
+ case GRN_TS_OP_BITWISE_AND: /* X & Y */
+ case GRN_TS_OP_BITWISE_OR: /* X | Y */
+ case GRN_TS_OP_BITWISE_XOR: /* X ^ Y */
+ case GRN_TS_OP_EQUAL: /* X == Y */
+ case GRN_TS_OP_NOT_EQUAL: /* X != Y */
+ case GRN_TS_OP_LESS: /* X < Y */
+ case GRN_TS_OP_LESS_EQUAL: /* X <= Y */
+ case GRN_TS_OP_GREATER: /* X > Y */
+ case GRN_TS_OP_GREATER_EQUAL: /* X >= Y */
+ case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT: /* X << Y */
+ case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT: /* X >> Y */
+ case GRN_TS_OP_SHIFT_LOGICAL_LEFT: /* X <<< Y */
+ case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: /* X >>> Y */
+ case GRN_TS_OP_PLUS: /* X + Y */
+ case GRN_TS_OP_MINUS: /* X - Y */
+ case GRN_TS_OP_MULTIPLICATION: /* X * Y */
+ case GRN_TS_OP_DIVISION: /* X / Y */
+ case GRN_TS_OP_MODULUS: /* X % Y */
+ case GRN_TS_OP_MATCH: /* X @ Y */
+ case GRN_TS_OP_PREFIX_MATCH: /* X @^ Y */
+ case GRN_TS_OP_SUFFIX_MATCH: { /* X @$ Y */
+ return 2;
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
+grn_ts_op_precedence
+grn_ts_op_get_precedence(grn_ts_op_type op_type)
+{
+ switch (op_type) {
+ case GRN_TS_OP_LOGICAL_NOT:
+ case GRN_TS_OP_BITWISE_NOT:
+ case GRN_TS_OP_POSITIVE:
+ case GRN_TS_OP_NEGATIVE: {
+ return 15;
+ }
+ case GRN_TS_OP_FLOAT:
+ case GRN_TS_OP_TIME: {
+ return 16;
+ }
+ case GRN_TS_OP_LOGICAL_AND: {
+ return 5;
+ }
+ case GRN_TS_OP_LOGICAL_OR: {
+ return 3;
+ }
+ case GRN_TS_OP_LOGICAL_SUB: {
+ return 4;
+ }
+ case GRN_TS_OP_BITWISE_AND: {
+ return 8;
+ }
+ case GRN_TS_OP_BITWISE_OR: {
+ return 6;
+ }
+ case GRN_TS_OP_BITWISE_XOR: {
+ return 7;
+ }
+ case GRN_TS_OP_EQUAL:
+ case GRN_TS_OP_NOT_EQUAL: {
+ return 9;
+ }
+ case GRN_TS_OP_LESS:
+ case GRN_TS_OP_LESS_EQUAL:
+ case GRN_TS_OP_GREATER:
+ case GRN_TS_OP_GREATER_EQUAL: {
+ return 10;
+ }
+ case GRN_TS_OP_SHIFT_ARITHMETIC_LEFT:
+ case GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT:
+ case GRN_TS_OP_SHIFT_LOGICAL_LEFT:
+ case GRN_TS_OP_SHIFT_LOGICAL_RIGHT: {
+ return 11;
+ }
+ case GRN_TS_OP_PLUS:
+ case GRN_TS_OP_MINUS: {
+ return 12;
+ }
+ case GRN_TS_OP_MULTIPLICATION:
+ case GRN_TS_OP_DIVISION:
+ case GRN_TS_OP_MODULUS: {
+ return 13;
+ }
+ case GRN_TS_OP_MATCH:
+ case GRN_TS_OP_PREFIX_MATCH:
+ case GRN_TS_OP_SUFFIX_MATCH: {
+ return 14;
+ }
+ default: {
+ return 0;
+ }
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_op.h b/storage/mroonga/vendor/groonga/lib/ts/ts_op.h
new file mode 100644
index 00000000..7c34de96
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_op.h
@@ -0,0 +1,87 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------
+ * Operator types.
+ */
+
+typedef enum {
+ /* Invalid operator. */
+ GRN_TS_OP_NOP,
+
+ /* Unary operators. */
+ GRN_TS_OP_LOGICAL_NOT, /* !X */
+ GRN_TS_OP_BITWISE_NOT, /* ~X */
+ GRN_TS_OP_POSITIVE, /* +X */
+ GRN_TS_OP_NEGATIVE, /* -X */
+
+ /* Typecast operators. */
+ GRN_TS_OP_FLOAT,
+ GRN_TS_OP_TIME,
+
+ /* Binary operators. */
+ GRN_TS_OP_LOGICAL_AND, /* X && Y */
+ GRN_TS_OP_LOGICAL_OR, /* X || Y */
+ GRN_TS_OP_LOGICAL_SUB, /* X &! Y */
+ GRN_TS_OP_BITWISE_AND, /* X & Y */
+ GRN_TS_OP_BITWISE_OR, /* X | Y */
+ GRN_TS_OP_BITWISE_XOR, /* X ^ Y */
+ GRN_TS_OP_EQUAL, /* X == Y */
+ GRN_TS_OP_NOT_EQUAL, /* X != Y */
+ GRN_TS_OP_LESS, /* X < Y */
+ GRN_TS_OP_LESS_EQUAL, /* X <= Y */
+ GRN_TS_OP_GREATER, /* X > Y */
+ GRN_TS_OP_GREATER_EQUAL, /* X >= Y */
+ GRN_TS_OP_SHIFT_ARITHMETIC_LEFT, /* X << Y */
+ GRN_TS_OP_SHIFT_ARITHMETIC_RIGHT, /* X >> Y */
+ GRN_TS_OP_SHIFT_LOGICAL_LEFT, /* X <<< Y */
+ GRN_TS_OP_SHIFT_LOGICAL_RIGHT, /* X >>> Y */
+ GRN_TS_OP_PLUS, /* X + Y */
+ GRN_TS_OP_MINUS, /* X - Y */
+ GRN_TS_OP_MULTIPLICATION, /* X * Y */
+ GRN_TS_OP_DIVISION, /* X / Y */
+ GRN_TS_OP_MODULUS, /* X % Y */
+ GRN_TS_OP_MATCH, /* X @ Y */
+ GRN_TS_OP_PREFIX_MATCH, /* X @^ Y */
+ GRN_TS_OP_SUFFIX_MATCH /* X @$ Y */
+} grn_ts_op_type;
+
+/* Operator precedence. */
+typedef int grn_ts_op_precedence;
+
+/* grn_ts_op_get_n_args() returns the number of arguments. */
+size_t grn_ts_op_get_n_args(grn_ts_op_type op_type);
+
+/*
+ * grn_ts_op_get_precedence() returns the precedence.
+ * A prior operator has a higher precedence.
+ */
+grn_ts_op_precedence grn_ts_op_get_precedence(grn_ts_op_type op_type);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_plan.c b/storage/mroonga/vendor/groonga/lib/ts/ts_plan.c
new file mode 100644
index 00000000..3a8c9c0f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_plan.c
@@ -0,0 +1,21 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_plan.h"
+
+// TODO
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_plan.h b/storage/mroonga/vendor/groonga/lib/ts/ts_plan.h
new file mode 100644
index 00000000..462bccfa
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_plan.h
@@ -0,0 +1,87 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_buf.h"
+#include "ts_cursor.h"
+#include "ts_expr.h"
+#include "ts_sorter.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int REMOVE_ME;
+} grn_ts_plan_node;
+
+typedef struct {
+ grn_obj *table;
+ grn_ts_plan_node *root;
+} grn_ts_plan;
+
+/* grn_ts_plan_open() creates a plan. */
+grn_rc grn_ts_plan_open(grn_ctx *ctx, grn_obj *table, grn_ts_plan_node *root,
+ grn_ts_plan **plan);
+
+/* grn_ts_plan_close() destroys a plan. */
+grn_rc grn_ts_plan_close(grn_ctx *ctx, grn_ts_plan *plan);
+
+/* grn_ts_plan_exec() executes a plan. */
+grn_rc grn_ts_plan_exec(grn_ctx *ctx, grn_ts_plan *plan,
+ grn_ts_rbuf *rbuf, size_t *n_hits);
+
+typedef struct {
+ grn_obj *table;
+} grn_ts_planner;
+
+/* grn_ts_planner_open() creates a planner. */
+grn_rc grn_ts_planner_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_planner **planner);
+
+/* grn_ts_planner_close() destroys a planner. */
+grn_rc grn_ts_planner_close(grn_ctx *ctx, grn_ts_planner *planner);
+
+/* grn_ts_planner_complete() completes a planner. */
+grn_rc grn_ts_planner_complete(grn_ctx *ctx, grn_ts_planner *planner,
+ grn_ts_plan **plan);
+
+/* grn_ts_planner_push_cursor() pushes a cursor. */
+grn_rc grn_ts_planner_push_cursor(grn_ctx *ctx, grn_ts_planner *planner,
+ grn_ts_cursor *cursor);
+
+/* grn_ts_planner_push_filter() pushes a filter. */
+grn_rc grn_ts_planner_push_filter(grn_ctx *ctx, grn_ts_planner *planner,
+ grn_ts_expr *expr);
+
+/* grn_ts_planner_push_scorer() pushes a scorer. */
+grn_rc grn_ts_planner_push_scorer(grn_ctx *ctx, grn_ts_planner *planner,
+ grn_ts_expr *expr);
+
+/* grn_ts_planner_push_sorter() pushes a sorter. */
+grn_rc grn_ts_planner_push_sorter(grn_ctx *ctx, grn_ts_planner *planner,
+ grn_ts_sorter *sorter);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_sorter.c b/storage/mroonga/vendor/groonga/lib/ts/ts_sorter.c
new file mode 100644
index 00000000..6a614663
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_sorter.c
@@ -0,0 +1,2174 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_sorter.h"
+
+#include <string.h>
+
+#include "ts_expr_parser.h"
+#include "ts_log.h"
+#include "ts_util.h"
+
+/*-------------------------------------------------------------
+ * grn_ts_sorter_node.
+ */
+
+/* grn_ts_sorter_node_init() initializes a sorter node. */
+static void
+grn_ts_sorter_node_init(grn_ctx *ctx, grn_ts_sorter_node *node)
+{
+ memset(node, 0, sizeof(*node));
+ node->expr = NULL;
+ grn_ts_buf_init(ctx, &node->buf);
+ node->next = NULL;
+}
+
+/* grn_ts_sorter_node_fin() finalizes a sorter node. */
+static void
+grn_ts_sorter_node_fin(grn_ctx *ctx, grn_ts_sorter_node *node)
+{
+ grn_ts_buf_fin(ctx, &node->buf);
+ if (node->expr) {
+ grn_ts_expr_close(ctx, node->expr);
+ }
+}
+
+/* grn_ts_sorter_node_open() creates a sorter nodes. */
+static grn_rc
+grn_ts_sorter_node_open(grn_ctx *ctx, grn_ts_expr *expr, grn_ts_bool reverse,
+ grn_ts_sorter_node **node)
+{
+ grn_ts_sorter_node *new_node;
+ new_node = GRN_MALLOCN(grn_ts_sorter_node, 1);
+ if (!new_node) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_sorter_node));
+ }
+ grn_ts_sorter_node_init(ctx, new_node);
+ new_node->expr = expr;
+ new_node->reverse = reverse;
+ *node = new_node;
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_sorter_node_close() destroys a sorter node. */
+static void
+grn_ts_sorter_node_close(grn_ctx *ctx, grn_ts_sorter_node *node)
+{
+ grn_ts_sorter_node_fin(ctx, node);
+ GRN_FREE(node);
+}
+
+/* grn_ts_sorter_node_list_close() destroys a linked list of sorter nodes. */
+static void
+grn_ts_sorter_node_list_close(grn_ctx *ctx, grn_ts_sorter_node *head)
+{
+ grn_ts_sorter_node *node = head;
+ while (node) {
+ grn_ts_sorter_node *next = node->next;
+ grn_ts_sorter_node_close(ctx, node);
+ node = next;
+ }
+}
+
+/* grn_ts_sorter_node_progress() progresses sorting. */
+static grn_rc
+grn_ts_sorter_node_progress(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs, size_t *n_rest)
+{
+ // TODO
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+
+/* grn_ts_sorter_node_complete() completes sorting. */
+static grn_rc
+grn_ts_sorter_node_complete(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs, size_t *n_rest)
+{
+ // TODO
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+
+/* Forward declarations. */
+static grn_rc
+grn_ts_sorter_node_sort(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs);
+
+/* grn_ts_rec_swap() swaps records. */
+inline static void
+grn_ts_rec_swap(grn_ts_record *lhs, grn_ts_record *rhs)
+{
+ grn_ts_record tmp = *lhs;
+ *lhs = *rhs;
+ *rhs = tmp;
+}
+
+/* grn_ts_int_swap() swaps Int values. */
+inline static void
+grn_ts_int_swap(grn_ts_int *lhs, grn_ts_int *rhs)
+{
+ grn_ts_int tmp = *lhs;
+ *lhs = *rhs;
+ *rhs = tmp;
+}
+
+/* FIXME: Sorting by _id does not assume ID duplicates. */
+
+/* grn_ts_move_pivot_by_id_asc() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_id_asc(grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (recs[first].id < recs[middle].id) {
+ /* first < middle. */
+ if (recs[middle].id < recs[last].id) {
+ /* first < middle < last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[first].id < recs[last].id) {
+ /* first < last < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else {
+ /* last < first < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+ } else if (recs[last].id < recs[middle].id) {
+ /* last < middle < first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[last].id < recs[first].id) {
+ /* middle < last < first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else {
+ /* middle < first < last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+}
+
+/* grn_ts_isort_by_id_asc() sorts records. */
+static grn_rc
+grn_ts_isort_by_id_asc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (recs[j].id < recs[j - 1].id) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_id_asc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_id_asc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_record pivot;
+ size_t left, right;
+ grn_ts_move_pivot_by_id_asc(recs, n_recs);
+ pivot = recs[0];
+ left = 1;
+ right = n_recs;
+ for ( ; ; ) {
+ /* Move prior records to left. */
+ while (left < right) {
+ if (pivot.id < recs[left].id) {
+ break;
+ }
+ ++left;
+ }
+ while (left < right) {
+ --right;
+ if (recs[right].id < pivot.id) {
+ break;
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ ++left;
+ }
+ /* Move the pivot to the boundary. */
+ --left;
+ grn_ts_rec_swap(&recs[0], &recs[left]);
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_id_asc(ctx, node, offset, next_limit, recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_id_asc(ctx, node, next_offset, next_limit,
+ recs + right, n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ return grn_ts_isort_by_id_asc(ctx, node, offset, limit, recs, n_recs);
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_move_pivot_by_id_desc() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_id_desc(grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (recs[first].id > recs[middle].id) {
+ /* first > middle. */
+ if (recs[middle].id > recs[last].id) {
+ /* first > middle > last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[first].id > recs[last].id) {
+ /* first > last > middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else {
+ /* last > first > middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+ } else if (recs[last].id > recs[middle].id) {
+ /* last > middle > first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[last].id > recs[first].id) {
+ /* middle > last > first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else {
+ /* middle > first > last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+}
+
+/* grn_ts_isort_by_id_desc() sorts records. */
+static grn_rc
+grn_ts_isort_by_id_desc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (recs[j].id > recs[j - 1].id) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_id_desc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_id_desc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_record pivot;
+ size_t left, right;
+ grn_ts_move_pivot_by_id_desc(recs, n_recs);
+ pivot = recs[0];
+ left = 1;
+ right = n_recs;
+ for ( ; ; ) {
+ /* Move prior records to left. */
+ while (left < right) {
+ if (pivot.id > recs[left].id) {
+ break;
+ }
+ ++left;
+ }
+ while (left < right) {
+ --right;
+ if (recs[right].id > pivot.id) {
+ break;
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ ++left;
+ }
+ /* Move the pivot to the boundary. */
+ --left;
+ grn_ts_rec_swap(&recs[0], &recs[left]);
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_id_desc(ctx, node, offset, next_limit,
+ recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_id_desc(ctx, node, next_offset, next_limit,
+ recs + right, n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ return grn_ts_isort_by_id_desc(ctx, node, offset, limit, recs, n_recs);
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_sorter_node_sort_by_id() sorts records by _id. */
+static grn_rc
+grn_ts_sorter_node_sort_by_id(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ if (node->reverse) {
+ return grn_ts_qsort_by_id_desc(ctx, node, offset, limit, recs, n_recs);
+ } else {
+ return grn_ts_qsort_by_id_asc(ctx, node, offset, limit, recs, n_recs);
+ }
+}
+
+/* grn_ts_move_pivot_by_score_asc() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_score_asc(grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (recs[first].score < recs[middle].score) {
+ /* first < middle. */
+ if (recs[middle].score < recs[last].score) {
+ /* first < middle < last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[first].score < recs[last].score) {
+ /* first < last < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else { /* last < first < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+ } else if (recs[last].score < recs[middle].score) {
+ /* last < middle < first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[last].score < recs[first].score) {
+ /* middle < last < first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else { /* middle < first < last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+}
+
+/* grn_ts_isort_by_score_asc() sorts records. */
+static grn_rc
+grn_ts_isort_by_score_asc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (recs[j].score < recs[j - 1].score) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ /* Apply the next sorting if there are score duplicates. */
+ if (node->next) {
+ grn_rc rc;
+ size_t begin = 0;
+ for (size_t i = 1; i < n_recs; ++i) {
+ if ((recs[i].score < recs[begin].score) ||
+ (recs[i].score > recs[begin].score)) {
+ if ((i - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, i - begin,
+ recs + begin, i - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ begin = i;
+ }
+ }
+ if ((n_recs - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, n_recs - begin,
+ recs + begin, n_recs - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_score_asc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_score_asc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_record pivot;
+ size_t left, right;
+ size_t pivot_left, pivot_right;
+ grn_ts_move_pivot_by_score_asc(recs, n_recs);
+ pivot = recs[0];
+ left = 1;
+ right = n_recs;
+ pivot_left = 1;
+ pivot_right = n_recs;
+ for ( ; ; ) {
+ /*
+ * Prior entries are moved to left. Less prior entries are moved to
+ * right. Entries which equal to the pivot are moved to the edges.
+ */
+ while (left < right) {
+ if (pivot.score < recs[left].score) {
+ break;
+ } else if ((pivot.score <= recs[left].score) &&
+ (pivot.score >= recs[left].score)) {
+ grn_ts_rec_swap(&recs[left], &recs[pivot_left]);
+ ++pivot_left;
+ }
+ ++left;
+ }
+ while (left < right) {
+ --right;
+ if (recs[right].score < pivot.score) {
+ break;
+ } else if ((recs[right].score <= pivot.score) &&
+ (recs[right].score >= pivot.score)) {
+ --pivot_right;
+ grn_ts_rec_swap(&recs[right], &recs[pivot_right]);
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ ++left;
+ }
+ /* Move left pivot-equivalent entries to the left of the boundary. */
+ while (pivot_left > 0) {
+ --pivot_left;
+ --left;
+ grn_ts_rec_swap(&recs[pivot_left], &recs[left]);
+ }
+ /* Move right pivot-equivalent entries to the right of the boundary. */
+ while (pivot_right < n_recs) {
+ grn_ts_rec_swap(&recs[pivot_right], &recs[right]);
+ ++pivot_right;
+ ++right;
+ }
+ /* Apply the next sort condition to the pivot-equivalent recs. */
+ if (node->next) {
+ if (((right - left) >= 2) && (offset < right) && (limit > left)) {
+ size_t next_offset = (offset < left) ? 0 : (offset - left);
+ size_t next_limit = ((limit > right) ? right : limit) - left;
+ rc = grn_ts_sorter_node_sort(ctx, node->next, next_offset, next_limit,
+ recs + left, right - left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_score_asc(ctx, node, offset, next_limit,
+ recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_score_asc(ctx, node, next_offset, next_limit,
+ recs + right, n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ rc = grn_ts_isort_by_score_asc(ctx, node, offset, limit, recs, n_recs);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_move_pivot_by_score_desc() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_score_desc(grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (recs[first].score > recs[middle].score) {
+ /* first > middle. */
+ if (recs[middle].score > recs[last].score) {
+ /* first > middle > last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[first].score > recs[last].score) {
+ /* first > last > middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else { /* last > first > middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+ } else if (recs[last].score > recs[middle].score) {
+ /* last > middle > first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ } else if (recs[last].score > recs[first].score) {
+ /* middle > last > first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ } else { /* middle > first > last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ }
+}
+
+/* grn_ts_isort_by_score_desc() sorts records. */
+static grn_rc
+grn_ts_isort_by_score_desc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (recs[j].score > recs[j - 1].score) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ /* Apply the next sorting if there are score duplicates. */
+ if (node->next) {
+ grn_rc rc;
+ size_t begin = 0;
+ for (size_t i = 1; i < n_recs; ++i) {
+ if ((recs[i].score < recs[begin].score) ||
+ (recs[i].score > recs[begin].score)) {
+ if ((i - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, i - begin,
+ recs + begin, i - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ begin = i;
+ }
+ }
+ if ((n_recs - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, n_recs - begin,
+ recs + begin, n_recs - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_score_desc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_score_desc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_record pivot;
+ size_t left = 1, right = n_recs;
+ size_t pivot_left = 1, pivot_right = n_recs;
+ grn_ts_move_pivot_by_score_desc(recs, n_recs);
+ pivot = recs[0];
+ for ( ; ; ) {
+ /*
+ * Prior entries are moved to left. Less prior entries are moved to
+ * right. Entries which equal to the pivot are moved to the edges.
+ */
+ while (left < right) {
+ if (pivot.score > recs[left].score) {
+ break;
+ } else if ((pivot.score <= recs[left].score) &&
+ (pivot.score >= recs[left].score)) {
+ grn_ts_rec_swap(&recs[left], &recs[pivot_left]);
+ ++pivot_left;
+ }
+ ++left;
+ }
+ while (left < right) {
+ --right;
+ if (recs[right].score > pivot.score) {
+ break;
+ } else if ((recs[right].score <= pivot.score) &&
+ (recs[right].score >= pivot.score)) {
+ --pivot_right;
+ grn_ts_rec_swap(&recs[right], &recs[pivot_right]);
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ ++left;
+ }
+ /* Move left pivot-equivalent entries to the left of the boundary. */
+ while (pivot_left > 0) {
+ --pivot_left;
+ --left;
+ grn_ts_rec_swap(&recs[pivot_left], &recs[left]);
+ }
+ /* Move right pivot-equivalent entries to the right of the boundary. */
+ while (pivot_right < n_recs) {
+ grn_ts_rec_swap(&recs[pivot_right], &recs[right]);
+ ++pivot_right;
+ ++right;
+ }
+ /* Apply the next sort condition to the pivot-equivalent recs. */
+ if (node->next) {
+ if (((right - left) >= 2) && (offset < right) && (limit > left)) {
+ size_t next_offset = (offset < left) ? 0 : (offset - left);
+ size_t next_limit = ((limit > right) ? right : limit) - left;
+ rc = grn_ts_sorter_node_sort(ctx, node->next, next_offset, next_limit,
+ recs + left, right - left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_score_desc(ctx, node, offset, next_limit,
+ recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_score_desc(ctx, node, next_offset, next_limit,
+ recs + right, n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ rc = grn_ts_isort_by_score_desc(ctx, node, offset, limit, recs, n_recs);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_sorter_node_sort_by_score() sorts records by _score. */
+static grn_rc
+grn_ts_sorter_node_sort_by_score(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ if (node->reverse) {
+ return grn_ts_qsort_by_score_desc(ctx, node, offset, limit, recs, n_recs);
+ } else {
+ return grn_ts_qsort_by_score_asc(ctx, node, offset, limit, recs, n_recs);
+ }
+}
+
+/* grn_ts_move_pivot_by_int() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_int(grn_ts_sorter_node *node, grn_ts_int *vals,
+ grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (vals[first] < vals[middle]) {
+ /* first < middle. */
+ if (vals[middle] < vals[last]) {
+ /* first < middle < last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_int_swap(&vals[0], &vals[middle]);
+ } else if (vals[first] < vals[last]) {
+ /* first < last < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_int_swap(&vals[0], &vals[last]);
+ } else { /* last < first < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_int_swap(&vals[0], &vals[first]);
+ }
+ } else if (vals[last] < vals[middle]) {
+ /* last < middle < first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_int_swap(&vals[0], &vals[middle]);
+ } else if (vals[last] < vals[first]) {
+ /* middle < last < first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_int_swap(&vals[0], &vals[last]);
+ } else { /* middle < first < last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_int_swap(&vals[0], &vals[first]);
+ }
+}
+
+/* grn_ts_isort_by_int() sorts records. */
+static grn_rc
+grn_ts_isort_by_int(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_int *vals, grn_ts_record *recs, size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (vals[j] < vals[j - 1]) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ grn_ts_int_swap(&vals[j], &vals[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ /* Apply the next sorting if there are score duplicates. */
+ if (node->next) {
+ grn_rc rc;
+ size_t begin = 0;
+ for (size_t i = 1; i < n_recs; ++i) {
+ if (vals[i] != vals[begin]) {
+ if ((i - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, i - begin,
+ recs + begin, i - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ begin = i;
+ }
+ }
+ if ((n_recs - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, n_recs - begin,
+ recs + begin, n_recs - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_int() sorts records. */
+static grn_rc
+grn_ts_qsort_by_int(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_int *vals, grn_ts_record *recs, size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_int pivot;
+ size_t left, right;
+ size_t pivot_left, pivot_right;
+ grn_ts_move_pivot_by_int(node, vals, recs, n_recs);
+ pivot = vals[0];
+ left = 1;
+ right = n_recs;
+ pivot_left = 1;
+ pivot_right = n_recs;
+ for ( ; ; ) {
+ /*
+ * Prior entries are moved to left. Less prior entries are moved to
+ * right. Entries which equal to the pivot are moved to the edges.
+ */
+ while (left < right) {
+ if (pivot < vals[left]) {
+ break;
+ } else if (pivot == vals[left]) {
+ grn_ts_rec_swap(&recs[left], &recs[pivot_left]);
+ grn_ts_int_swap(&vals[left], &vals[pivot_left]);
+ ++pivot_left;
+ }
+ ++left;
+ }
+ while (left < right) {
+ --right;
+ if (vals[right] < pivot) {
+ break;
+ } else if (vals[right] == pivot) {
+ --pivot_right;
+ grn_ts_rec_swap(&recs[right], &recs[pivot_right]);
+ grn_ts_int_swap(&vals[right], &vals[pivot_right]);
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ grn_ts_int_swap(&vals[left], &vals[right]);
+ ++left;
+ }
+ /* Move left pivot-equivalent entries to the left of the boundary. */
+ while (pivot_left > 0) {
+ --pivot_left;
+ --left;
+ grn_ts_rec_swap(&recs[pivot_left], &recs[left]);
+ grn_ts_int_swap(&vals[pivot_left], &vals[left]);
+ }
+ /* Move right pivot-equivalent entries to the right of the boundary. */
+ while (pivot_right < n_recs) {
+ grn_ts_rec_swap(&recs[pivot_right], &recs[right]);
+ grn_ts_int_swap(&vals[pivot_right], &vals[right]);
+ ++pivot_right;
+ ++right;
+ }
+ /* Apply the next sort condition to the pivot-equivalent recs. */
+ if (node->next) {
+ if (((right - left) >= 2) && (offset < right) && (limit > left)) {
+ size_t next_offset = (offset < left) ? 0 : (offset - left);
+ size_t next_limit = ((limit > right) ? right : limit) - left;
+ rc = grn_ts_sorter_node_sort(ctx, node->next, next_offset, next_limit,
+ recs + left, right - left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_int(ctx, node, offset, next_limit,
+ vals, recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ vals += right;
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_int(ctx, node, next_offset, next_limit,
+ vals + right, recs + right, n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ rc = grn_ts_isort_by_int(ctx, node, offset, limit, vals, recs, n_recs);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_text_cmp() compares Text values. */
+inline static int
+grn_ts_text_cmp(grn_ts_text lhs, grn_ts_text rhs)
+{
+ size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
+ int result = memcmp(lhs.ptr, rhs.ptr, min_size);
+ if (result != 0) {
+ return result;
+ }
+ if (lhs.size == rhs.size) {
+ return 0;
+ }
+ return (lhs.size < rhs.size) ? -1 : 1;
+}
+
+/* grn_ts_text_swap() swaps Text values. */
+inline static void
+grn_ts_text_swap(grn_ts_text *lhs, grn_ts_text *rhs)
+{
+ grn_ts_text tmp = *lhs;
+ *lhs = *rhs;
+ *rhs = tmp;
+}
+
+#if 0
+/* grn_ts_move_pivot_by_text_asc() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_text_asc(grn_ts_sorter_node *node, grn_ts_text *vals,
+ grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (grn_ts_text_cmp(vals[first], vals[middle]) < 0) {
+ /* first < middle. */
+ if (grn_ts_text_cmp(vals[middle], vals[last]) < 0) {
+ /* first < middle < last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_text_swap(&vals[0], &vals[middle]);
+ } else if (grn_ts_text_cmp(vals[first], vals[last]) < 0) {
+ /* first < last < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_text_swap(&vals[0], &vals[last]);
+ } else { /* last < first < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_text_swap(&vals[0], &vals[first]);
+ }
+ } else if (grn_ts_text_cmp(vals[last], vals[middle]) < 0) {
+ /* last < middle < first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_text_swap(&vals[0], &vals[middle]);
+ } else if (grn_ts_text_cmp(vals[last], vals[first]) < 0) {
+ /* middle < last < first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_text_swap(&vals[0], &vals[last]);
+ } else { /* middle < first < last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_text_swap(&vals[0], &vals[first]);
+ }
+}
+
+/* grn_ts_isort_by_text_asc() sorts records. */
+static grn_rc
+grn_ts_isort_by_text_asc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_text *vals, grn_ts_record *recs, size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (grn_ts_text_cmp(vals[j], vals[j - 1]) < 0) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ grn_ts_text_swap(&vals[j], &vals[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ /* Apply the next sorting if there are score duplicates. */
+ if (node->next) {
+ grn_rc rc;
+ size_t begin = 0;
+ for (size_t i = 1; i < n_recs; ++i) {
+ if (grn_ts_text_cmp(vals[i], vals[begin]) != 0) {
+ if ((i - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, i - begin,
+ recs + begin, i - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ begin = i;
+ }
+ }
+ if ((n_recs - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, n_recs - begin,
+ recs + begin, n_recs - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_text_asc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_text_asc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_text *vals, grn_ts_record *recs, size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_move_pivot_by_text_asc(node, vals, recs, n_recs);
+ grn_ts_text pivot = vals[0];
+ size_t left = 1, right = n_recs;
+ size_t pivot_left = 1, pivot_right = n_recs;
+ for ( ; ; ) {
+ /*
+ * Prior entries are moved to left. Less prior entries are moved to
+ * right. Entries which equal to the pivot are moved to the edges.
+ */
+ while (left < right) {
+ int result = grn_ts_text_cmp(pivot, vals[left]);
+ if (result < 0) {
+ break;
+ } else if (result == 0) {
+ grn_ts_rec_swap(&recs[left], &recs[pivot_left]);
+ grn_ts_text_swap(&vals[left], &vals[pivot_left]);
+ ++pivot_left;
+ }
+ ++left;
+ }
+ while (left < right) {
+ int result;
+ --right;
+ result = grn_ts_text_cmp(vals[right], pivot);
+ if (result < 0) {
+ break;
+ } else if (result == 0) {
+ --pivot_right;
+ grn_ts_rec_swap(&recs[right], &recs[pivot_right]);
+ grn_ts_text_swap(&vals[right], &vals[pivot_right]);
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ grn_ts_text_swap(&vals[left], &vals[right]);
+ ++left;
+ }
+ /* Move left pivot-equivalent entries to the left of the boundary. */
+ while (pivot_left > 0) {
+ --pivot_left;
+ --left;
+ grn_ts_rec_swap(&recs[pivot_left], &recs[left]);
+ grn_ts_text_swap(&vals[pivot_left], &vals[left]);
+ }
+ /* Move right pivot-equivalent entries to the right of the boundary. */
+ while (pivot_right < n_recs) {
+ grn_ts_rec_swap(&recs[pivot_right], &recs[right]);
+ grn_ts_text_swap(&vals[pivot_right], &vals[right]);
+ ++pivot_right;
+ ++right;
+ }
+ /* Apply the next sort condition to the pivot-equivalent recs. */
+ if (node->next) {
+ if (((right - left) >= 2) && (offset < right) && (limit > left)) {
+ size_t next_offset = (offset < left) ? 0 : (offset - left);
+ size_t next_limit = ((limit > right) ? right : limit) - left;
+ rc = grn_ts_sorter_node_sort(ctx, node->next, next_offset, next_limit,
+ recs + left, right - left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_text_asc(ctx, node, offset, next_limit,
+ vals, recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ vals += right;
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_text_asc(ctx, node, next_offset, next_limit,
+ vals + right, recs + right,
+ n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ rc = grn_ts_isort_by_text_asc(ctx, node, offset, limit,
+ vals, recs, n_recs);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+#endif
+
+/* grn_ts_move_pivot_by_text_desc() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_text_desc(grn_ts_sorter_node *node, grn_ts_text *vals,
+ grn_ts_record *recs, size_t n_recs)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ if (grn_ts_text_cmp(vals[first], vals[middle]) > 0) {
+ /* first < middle. */
+ if (grn_ts_text_cmp(vals[middle], vals[last]) > 0) {
+ /* first < middle < last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_text_swap(&vals[0], &vals[middle]);
+ } else if (grn_ts_text_cmp(vals[first], vals[last]) > 0) {
+ /* first < last < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_text_swap(&vals[0], &vals[last]);
+ } else { /* last < first < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_text_swap(&vals[0], &vals[first]);
+ }
+ } else if (grn_ts_text_cmp(vals[last], vals[middle]) > 0) {
+ /* last < middle < first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_text_swap(&vals[0], &vals[middle]);
+ } else if (grn_ts_text_cmp(vals[last], vals[first]) > 0) {
+ /* middle < last < first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_text_swap(&vals[0], &vals[last]);
+ } else { /* middle < first < last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_text_swap(&vals[0], &vals[first]);
+ }
+}
+
+/* grn_ts_isort_by_text_desc() sorts records. */
+static grn_rc
+grn_ts_isort_by_text_desc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_text *vals, grn_ts_record *recs,
+ size_t n_recs)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (grn_ts_text_cmp(vals[j], vals[j - 1]) > 0) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ grn_ts_text_swap(&vals[j], &vals[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ /* Apply the next sorting if there are score duplicates. */
+ if (node->next) {
+ grn_rc rc;
+ size_t begin = 0;
+ for (size_t i = 1; i < n_recs; ++i) {
+ if (grn_ts_text_cmp(vals[i], vals[begin]) != 0) {
+ if ((i - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, i - begin,
+ recs + begin, i - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ begin = i;
+ }
+ }
+ if ((n_recs - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, n_recs - begin,
+ recs + begin, n_recs - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_text_desc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_text_desc(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_text *vals, grn_ts_record *recs,
+ size_t n_recs)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ grn_ts_text pivot;
+ size_t left, right;
+ size_t pivot_left, pivot_right;
+ grn_ts_move_pivot_by_text_desc(node, vals, recs, n_recs);
+ pivot = vals[0];
+ left = 1;
+ right = n_recs;
+ pivot_left = 1;
+ pivot_right = n_recs;
+ for ( ; ; ) {
+ /*
+ * Prior entries are moved to left. Less prior entries are moved to
+ * right. Entries which equal to the pivot are moved to the edges.
+ */
+ while (left < right) {
+ int result = grn_ts_text_cmp(pivot, vals[left]);
+ if (result > 0) {
+ break;
+ } else if (result == 0) {
+ grn_ts_rec_swap(&recs[left], &recs[pivot_left]);
+ grn_ts_text_swap(&vals[left], &vals[pivot_left]);
+ ++pivot_left;
+ }
+ ++left;
+ }
+ while (left < right) {
+ int result;
+ --right;
+ result = grn_ts_text_cmp(vals[right], pivot);
+ if (result > 0) {
+ break;
+ } else if (result == 0) {
+ --pivot_right;
+ grn_ts_rec_swap(&recs[right], &recs[pivot_right]);
+ grn_ts_text_swap(&vals[right], &vals[pivot_right]);
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ grn_ts_text_swap(&vals[left], &vals[right]);
+ ++left;
+ }
+ /* Move left pivot-equivalent entries to the left of the boundary. */
+ while (pivot_left > 0) {
+ --pivot_left;
+ --left;
+ grn_ts_rec_swap(&recs[pivot_left], &recs[left]);
+ grn_ts_text_swap(&vals[pivot_left], &vals[left]);
+ }
+ /* Move right pivot-equivalent entries to the right of the boundary. */
+ while (pivot_right < n_recs) {
+ grn_ts_rec_swap(&recs[pivot_right], &recs[right]);
+ grn_ts_text_swap(&vals[pivot_right], &vals[right]);
+ ++pivot_right;
+ ++right;
+ }
+ /* Apply the next sort condition to the pivot-equivalent recs. */
+ if (node->next) {
+ if (((right - left) >= 2) && (offset < right) && (limit > left)) {
+ size_t next_offset = (offset < left) ? 0 : (offset - left);
+ size_t next_limit = ((limit > right) ? right : limit) - left;
+ rc = grn_ts_sorter_node_sort(ctx, node->next, next_offset, next_limit,
+ recs + left, right - left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_text_desc(ctx, node, offset, next_limit,
+ vals, recs, left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ vals += right;
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_text_desc(ctx, node, next_offset, next_limit,
+ vals + right, recs + right,
+ n_recs - right);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ rc = grn_ts_isort_by_text_desc(ctx, node, offset, limit,
+ vals, recs, n_recs);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_text_get_label() returns a label. */
+inline static int
+grn_ts_text_get_label(grn_ts_text val, size_t depth)
+{
+ return (depth < val.size) ? (uint8_t)val.ptr[depth] : -1;
+}
+
+/* grn_ts_text_cmp2() compares Text values. */
+inline static int
+grn_ts_text_cmp2(grn_ts_text lhs, grn_ts_text rhs, size_t depth)
+{
+ size_t min_size = (lhs.size < rhs.size) ? lhs.size : rhs.size;
+ int result = memcmp(lhs.ptr + depth, rhs.ptr + depth, min_size - depth);
+ if (result != 0) {
+ return result;
+ }
+ if (lhs.size == rhs.size) {
+ return 0;
+ }
+ return (lhs.size < rhs.size) ? -1 : 1;
+}
+
+/* grn_ts_move_pivot_by_text_asc2() moves the pivot to the front. */
+static void
+grn_ts_move_pivot_by_text_asc2(grn_ts_sorter_node *node, grn_ts_text *vals,
+ grn_ts_record *recs, size_t n_recs, size_t depth)
+{
+ /* Choose the median from recs[1], recs[n_recs / 2], and recs[n_recs - 2]. */
+ size_t first = 1;
+ size_t middle = n_recs / 2;
+ size_t last = n_recs - 2;
+ int first_label = grn_ts_text_get_label(vals[first], depth);
+ int middle_label = grn_ts_text_get_label(vals[middle], depth);
+ int last_label = grn_ts_text_get_label(vals[last], depth);
+ if (first_label < middle_label) {
+ /* first < middle. */
+ if (middle_label < last_label) {
+ /* first < middle < last */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_text_swap(&vals[0], &vals[middle]);
+ } else if (first_label < last_label) {
+ /* first < last < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_text_swap(&vals[0], &vals[last]);
+ } else { /* last < first < middle. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_text_swap(&vals[0], &vals[first]);
+ }
+ } else if (last_label < middle_label) {
+ /* last < middle < first. */
+ grn_ts_rec_swap(&recs[0], &recs[middle]);
+ grn_ts_text_swap(&vals[0], &vals[middle]);
+ } else if (last_label < first_label) {
+ /* middle < last < first. */
+ grn_ts_rec_swap(&recs[0], &recs[last]);
+ grn_ts_text_swap(&vals[0], &vals[last]);
+ } else { /* middle < first < last. */
+ grn_ts_rec_swap(&recs[0], &recs[first]);
+ grn_ts_text_swap(&vals[0], &vals[first]);
+ }
+}
+
+/* grn_ts_isort_by_text_asc2() sorts records. */
+static grn_rc
+grn_ts_isort_by_text_asc2(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit, grn_ts_text *vals,
+ grn_ts_record *recs, size_t n_recs, size_t depth)
+{
+ for (size_t i = 1; i < n_recs; ++i) {
+ for (size_t j = i; j > 0; --j) {
+ if (grn_ts_text_cmp2(vals[j], vals[j - 1], depth) < 0) {
+ grn_ts_rec_swap(&recs[j], &recs[j - 1]);
+ grn_ts_text_swap(&vals[j], &vals[j - 1]);
+ } else {
+ break;
+ }
+ }
+ }
+ /* Apply the next sorting if there are score duplicates. */
+ if (node->next) {
+ grn_rc rc;
+ size_t begin = 0;
+ for (size_t i = 1; i < n_recs; ++i) {
+ if (grn_ts_text_cmp2(vals[i], vals[begin], depth) != 0) {
+ if ((i - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, i - begin,
+ recs + begin, i - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ begin = i;
+ }
+ }
+ if ((n_recs - begin) >= 2) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, 0, n_recs - begin,
+ recs + begin, n_recs - begin);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_qsort_by_text_asc() sorts records. */
+static grn_rc
+grn_ts_qsort_by_text_asc2(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit, grn_ts_text *vals,
+ grn_ts_record *recs, size_t n_recs, size_t depth)
+{
+ grn_rc rc;
+ /*
+ * FIXME: Currently, the threshold is 16.
+ * This value should be optimized and replaced with a named constant.
+ */
+ while (n_recs >= 16) {
+ int pivot;
+ size_t left, right;
+ size_t pivot_left, pivot_right;
+ grn_ts_move_pivot_by_text_asc2(node, vals, recs, n_recs, depth);
+ pivot = grn_ts_text_get_label(vals[0], depth);
+ left = 1;
+ right = n_recs;
+ pivot_left = 1;
+ pivot_right = n_recs;
+ for ( ; ; ) {
+ /*
+ * Prior entries are moved to left. Less prior entries are moved to
+ * right. Entries which equal to the pivot are moved to the edges.
+ */
+ while (left < right) {
+ int label = grn_ts_text_get_label(vals[left], depth);
+ if (label > pivot) {
+ break;
+ } else if (label == pivot) {
+ grn_ts_rec_swap(&recs[left], &recs[pivot_left]);
+ grn_ts_text_swap(&vals[left], &vals[pivot_left]);
+ ++pivot_left;
+ }
+ ++left;
+ }
+ while (left < right) {
+ int label;
+ --right;
+ label = grn_ts_text_get_label(vals[right], depth);
+ if (label < pivot) {
+ break;
+ } else if (label == pivot) {
+ --pivot_right;
+ grn_ts_rec_swap(&recs[right], &recs[pivot_right]);
+ grn_ts_text_swap(&vals[right], &vals[pivot_right]);
+ }
+ }
+ if (left >= right) {
+ break;
+ }
+ grn_ts_rec_swap(&recs[left], &recs[right]);
+ grn_ts_text_swap(&vals[left], &vals[right]);
+ ++left;
+ }
+ /* Move left pivot-equivalent entries to the left of the boundary. */
+ while (pivot_left > 0) {
+ --pivot_left;
+ --left;
+ grn_ts_rec_swap(&recs[pivot_left], &recs[left]);
+ grn_ts_text_swap(&vals[pivot_left], &vals[left]);
+ }
+ /* Move right pivot-equivalent entries to the right of the boundary. */
+ while (pivot_right < n_recs) {
+ grn_ts_rec_swap(&recs[pivot_right], &recs[right]);
+ grn_ts_text_swap(&vals[pivot_right], &vals[right]);
+ ++pivot_right;
+ ++right;
+ }
+ /* Apply the next sort condition to the pivot-equivalent recs. */
+ if (((right - left) >= 2) && (offset < right) && (limit > left)) {
+ size_t next_offset = (offset < left) ? 0 : (offset - left);
+ size_t next_limit = ((limit > right) ? right : limit) - left;
+ if (pivot != -1) {
+ rc = grn_ts_qsort_by_text_asc2(ctx, node, next_offset, next_limit,
+ vals, recs + left, right - left,
+ depth + 1);
+ } else if (node->next) {
+ rc = grn_ts_sorter_node_sort(ctx, node->next, next_offset, next_limit,
+ recs + left, right - left);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ }
+ /*
+ * Use a recursive call to sort the smaller group so that the recursion
+ * depth is less than log_2(n_recs).
+ */
+ if (left < (n_recs - right)) {
+ if ((offset < left) && (left >= 2)) {
+ size_t next_limit = (limit < left) ? limit : left;
+ rc = grn_ts_qsort_by_text_asc2(ctx, node, offset, next_limit,
+ vals, recs, left, depth);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (limit <= right) {
+ return GRN_SUCCESS;
+ }
+ vals += right;
+ recs += right;
+ n_recs -= right;
+ offset = (offset < right) ? 0 : (offset - right);
+ limit -= right;
+ } else {
+ if ((limit > right) && ((n_recs - right) >= 2)) {
+ size_t next_offset = (offset < right) ? 0 : (offset - right);
+ size_t next_limit = limit - right;
+ rc = grn_ts_qsort_by_text_asc2(ctx, node, next_offset, next_limit,
+ vals + right, recs + right,
+ n_recs - right, depth);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ if (offset >= left) {
+ return GRN_SUCCESS;
+ }
+ n_recs = left;
+ if (limit > left) {
+ limit = left;
+ }
+ }
+ }
+ if (n_recs >= 2) {
+ rc = grn_ts_isort_by_text_asc2(ctx, node, offset, limit,
+ vals, recs, n_recs, depth);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ }
+ return GRN_SUCCESS;
+}
+
+/* grn_ts_sorter_node_sort_by_var() sorts records. */
+static grn_rc
+grn_ts_sorter_node_sort_by_var(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ size_t i;
+ grn_rc rc;
+ switch (node->expr->data_kind) {
+ case GRN_TS_INT: {
+ grn_ts_int *vals;
+ rc = grn_ts_expr_evaluate_to_buf(ctx, node->expr, recs, n_recs,
+ &node->buf);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ vals = (grn_ts_int *)node->buf.ptr;
+ if (node->reverse) {
+ for (i = 0; i < n_recs; i++) {
+ vals[i] = -1 - vals[i];
+ }
+ }
+ return grn_ts_qsort_by_int(ctx, node, offset, limit, vals, recs, n_recs);
+ }
+ case GRN_TS_FLOAT: {
+ grn_ts_int *vals;
+ rc = grn_ts_expr_evaluate_to_buf(ctx, node->expr, recs, n_recs,
+ &node->buf);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ vals = (grn_ts_int *)node->buf.ptr;
+ if (node->reverse) {
+ for (i = 0; i < n_recs; i++) {
+ if (vals[i] < 0) {
+ vals[i] = (vals[i] ^ INT64_MAX) + 1;
+ }
+ vals[i] = -1 - vals[i];
+ }
+ } else {
+ for (i = 0; i < n_recs; i++) {
+ if (vals[i] < 0) {
+ vals[i] = (vals[i] ^ INT64_MAX) + 1;
+ }
+ }
+ }
+ return grn_ts_qsort_by_int(ctx, node, offset, limit, vals, recs, n_recs);
+ }
+ case GRN_TS_TIME: {
+ grn_ts_int *vals;
+ rc = grn_ts_expr_evaluate_to_buf(ctx, node->expr, recs, n_recs,
+ &node->buf);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ vals = (grn_ts_int *)node->buf.ptr;
+ if (node->reverse) {
+ for (i = 0; i < n_recs; i++) {
+ vals[i] = -1 - vals[i];
+ }
+ }
+ return grn_ts_qsort_by_int(ctx, node, offset, limit, vals, recs, n_recs);
+ }
+ case GRN_TS_TEXT: {
+ grn_ts_text *vals;
+ rc = grn_ts_expr_evaluate_to_buf(ctx, node->expr, recs, n_recs,
+ &node->buf);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ vals = (grn_ts_text *)node->buf.ptr;
+ if (node->reverse) {
+ return grn_ts_qsort_by_text_desc(ctx, node, offset, limit,
+ vals, recs, n_recs);
+ } else {
+ return grn_ts_qsort_by_text_asc2(ctx, node, offset, limit,
+ vals, recs, n_recs, 0);
+ }
+ }
+ case GRN_TS_INT_VECTOR:
+ case GRN_TS_FLOAT_VECTOR:
+ case GRN_TS_TIME_VECTOR:
+ case GRN_TS_TEXT_VECTOR: {
+ // TODO
+ GRN_TS_ERR_RETURN(GRN_OPERATION_NOT_SUPPORTED, "not supported yet");
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid data kind: %d",
+ node->expr->data_kind);
+ }
+ }
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+}
+
+/* grn_ts_sorter_node_sort() sorts records. */
+static grn_rc
+grn_ts_sorter_node_sort(grn_ctx *ctx, grn_ts_sorter_node *node,
+ size_t offset, size_t limit,
+ grn_ts_record *recs, size_t n_recs)
+{
+ switch (node->expr->type) {
+ case GRN_TS_EXPR_ID: {
+ return grn_ts_sorter_node_sort_by_id(ctx, node, offset, limit,
+ recs, n_recs);
+ }
+ case GRN_TS_EXPR_SCORE: {
+ return grn_ts_sorter_node_sort_by_score(ctx, node, offset, limit,
+ recs, n_recs);
+ }
+ case GRN_TS_EXPR_CONST: {
+ if (!node->next) {
+ return GRN_SUCCESS;
+ }
+ return grn_ts_sorter_node_sort(ctx, node->next, offset, limit, recs,
+ n_recs);
+ }
+ case GRN_TS_EXPR_VARIABLE: {
+ return grn_ts_sorter_node_sort_by_var(ctx, node, offset, limit,
+ recs, n_recs);
+ break;
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_OBJECT_CORRUPT, "invalid expr type: %d",
+ node->expr->type);
+ }
+ }
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_sorter.
+ */
+
+static void
+grn_ts_sorter_init(grn_ctx *ctx, grn_ts_sorter *sorter)
+{
+ memset(sorter, 0, sizeof(*sorter));
+ sorter->table = NULL;
+ sorter->head = NULL;
+}
+
+static void
+grn_ts_sorter_fin(grn_ctx *ctx, grn_ts_sorter *sorter)
+{
+ if (sorter->head) {
+ grn_ts_sorter_node_list_close(ctx, sorter->head);
+ }
+ if (sorter->table) {
+ grn_obj_unlink(ctx, sorter->table);
+ }
+}
+
+grn_rc
+grn_ts_sorter_open(grn_ctx *ctx, grn_obj *table, grn_ts_sorter_node *head,
+ size_t offset, size_t limit, grn_ts_sorter **sorter)
+{
+ grn_rc rc;
+ grn_ts_sorter *new_sorter;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) || !head || !sorter) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ new_sorter = GRN_MALLOCN(grn_ts_sorter, 1);
+ if (!new_sorter) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_sorter));
+ }
+ rc = grn_ts_obj_increment_ref_count(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ GRN_FREE(new_sorter);
+ return rc;
+ }
+ grn_ts_sorter_init(ctx, new_sorter);
+ new_sorter->table = table;
+ new_sorter->head = head;
+ new_sorter->offset = offset;
+ new_sorter->limit = limit;
+ /* FIXME: Enable partial sorting. */
+/* new_sorter->partial = (offset + limit) < 1000;*/
+ *sorter = new_sorter;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_parse(grn_ctx *ctx, grn_obj *table,
+ grn_ts_str str, size_t offset,
+ size_t limit, grn_ts_sorter **sorter)
+{
+ grn_rc rc;
+ grn_ts_sorter *new_sorter = NULL;
+ grn_ts_expr_parser *parser;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) || !str.size || !sorter) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_expr_parser_open(ctx, table, &parser);
+ if (rc == GRN_SUCCESS) {
+ grn_ts_sorter_builder *builder;
+ rc = grn_ts_sorter_builder_open(ctx, table, &builder);
+ if (rc == GRN_SUCCESS) {
+ grn_ts_str first, rest = str;
+ for ( ; ; ) {
+ grn_ts_expr *expr;
+ grn_ts_bool reverse = GRN_FALSE;
+ rc = grn_ts_expr_parser_split(ctx, parser, rest, &first, &rest);
+ if (rc == GRN_END_OF_DATA) {
+ rc = grn_ts_sorter_builder_complete(ctx, builder, offset, limit,
+ &new_sorter);
+ break;
+ } else if (rc != GRN_SUCCESS) {
+ break;
+ }
+ if (first.ptr[0] == '-') {
+ reverse = GRN_TRUE;
+ first.ptr++;
+ first.size--;
+ }
+ rc = grn_ts_expr_parser_parse(ctx, parser, first, &expr);
+ if (rc != GRN_SUCCESS) {
+ break;
+ }
+ rc = grn_ts_sorter_builder_push(ctx, builder, expr, reverse);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_expr_close(ctx, expr);
+ break;
+ }
+ }
+ grn_ts_sorter_builder_close(ctx, builder);
+ }
+ grn_ts_expr_parser_close(ctx, parser);
+ }
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ *sorter = new_sorter;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_close(grn_ctx *ctx, grn_ts_sorter *sorter)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!sorter) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ grn_ts_sorter_fin(ctx, sorter);
+ GRN_FREE(sorter);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_progress(grn_ctx *ctx, grn_ts_sorter *sorter,
+ grn_ts_record *recs, size_t n_recs, size_t *n_rest)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!sorter || (!recs && n_recs) || !n_rest) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (sorter->partial) {
+ return grn_ts_sorter_node_progress(ctx, sorter->head, sorter->offset,
+ sorter->limit, recs, n_recs, n_rest);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_complete(grn_ctx *ctx, grn_ts_sorter *sorter,
+ grn_ts_record *recs, size_t n_recs, size_t *n_rest)
+{
+ grn_rc rc;
+ size_t i, limit;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!sorter || (!recs && n_recs) || !n_rest) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ if (sorter->offset >= n_recs) {
+ return GRN_SUCCESS;
+ }
+ limit = sorter->limit;
+ if (limit > (n_recs - sorter->offset)) {
+ limit = n_recs;
+ } else {
+ limit += sorter->offset;
+ }
+ if (sorter->partial) {
+ // FIXME: If there was no input. Partial sorting is not required.
+ rc = grn_ts_sorter_node_progress(ctx, sorter->head, sorter->offset,
+ limit, recs, n_recs, n_rest);
+ if (rc == GRN_SUCCESS) {
+ rc = grn_ts_sorter_node_complete(ctx, sorter->head, sorter->offset,
+ limit, recs, n_recs, n_rest);
+ }
+ } else {
+ rc = grn_ts_sorter_node_sort(ctx, sorter->head, sorter->offset,
+ limit, recs, n_recs);
+ }
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (sorter->offset) {
+ for (i = 0; i < limit; i++) {
+ recs[i] = recs[sorter->offset + i];
+ }
+ }
+ *n_rest = limit;
+ return GRN_SUCCESS;
+}
+
+/*-------------------------------------------------------------
+ * grn_ts_sorter_builder.
+ */
+
+/* grn_ts_sorter_builder_init() initializes a sorter builder. */
+static void
+grn_ts_sorter_builder_init(grn_ctx *ctx, grn_ts_sorter_builder *builder)
+{
+ memset(builder, 0, sizeof(*builder));
+ builder->table = NULL;
+ builder->head = NULL;
+ builder->tail = NULL;
+}
+
+/* grn_ts_sorter_builder_fin() finalizes a sorter builder. */
+static void
+grn_ts_sorter_builder_fin(grn_ctx *ctx, grn_ts_sorter_builder *builder)
+{
+ if (builder->head) {
+ grn_ts_sorter_node_list_close(ctx, builder->head);
+ }
+ if (builder->table) {
+ grn_obj_unlink(ctx, builder->table);
+ }
+}
+
+grn_rc
+grn_ts_sorter_builder_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_sorter_builder **builder)
+{
+ grn_rc rc;
+ grn_ts_sorter_builder *new_builder;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!table || !grn_ts_obj_is_table(ctx, table) || !builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ new_builder = GRN_MALLOCN(grn_ts_sorter_builder, 1);
+ if (!new_builder) {
+ GRN_TS_ERR_RETURN(GRN_NO_MEMORY_AVAILABLE,
+ "GRN_MALLOCN failed: %" GRN_FMT_SIZE " x 1",
+ sizeof(grn_ts_sorter_builder));
+ }
+ grn_ts_sorter_builder_init(ctx, new_builder);
+ rc = grn_ts_obj_increment_ref_count(ctx, table);
+ if (rc != GRN_SUCCESS) {
+ grn_ts_sorter_builder_fin(ctx, new_builder);
+ GRN_FREE(new_builder);
+ return rc;
+ }
+ new_builder->table = table;
+ *builder = new_builder;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_builder_close(grn_ctx *ctx, grn_ts_sorter_builder *builder)
+{
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ grn_ts_sorter_builder_fin(ctx, builder);
+ GRN_FREE(builder);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_builder_complete(grn_ctx *ctx, grn_ts_sorter_builder *builder,
+ size_t offset, size_t limit,
+ grn_ts_sorter **sorter)
+{
+ grn_rc rc;
+ grn_ts_sorter *new_sorter;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder || !builder->head || !sorter) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ rc = grn_ts_sorter_open(ctx, builder->table, builder->head,
+ offset, limit, &new_sorter);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ builder->head = NULL;
+ builder->tail = NULL;
+ *sorter = new_sorter;
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_ts_sorter_builder_push(grn_ctx *ctx, grn_ts_sorter_builder *builder,
+ grn_ts_expr *expr, grn_ts_bool reverse)
+{
+ grn_rc rc;
+ grn_ts_sorter_node *new_node;
+ if (!ctx) {
+ return GRN_INVALID_ARGUMENT;
+ }
+ if (!builder || !expr || expr->table != builder->table) {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ switch (expr->data_kind) {
+ case GRN_TS_INT:
+ case GRN_TS_FLOAT:
+ case GRN_TS_TIME:
+ case GRN_TS_TEXT: {
+ break;
+ }
+ case GRN_TS_INT_VECTOR:
+ case GRN_TS_FLOAT_VECTOR:
+ case GRN_TS_TIME_VECTOR:
+ case GRN_TS_TEXT_VECTOR: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "not supported yet");
+ }
+ default: {
+ GRN_TS_ERR_RETURN(GRN_INVALID_ARGUMENT, "invalid argument");
+ }
+ }
+ rc = grn_ts_sorter_node_open(ctx, expr, reverse, &new_node);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (builder->tail) {
+ builder->tail->next = new_node;
+ } else {
+ builder->head = new_node;
+ }
+ builder->tail = new_node;
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_sorter.h b/storage/mroonga/vendor/groonga/lib/ts/ts_sorter.h
new file mode 100644
index 00000000..d80479e1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_sorter.h
@@ -0,0 +1,98 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_expr.h"
+#include "ts_str.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* TODO: Sorting should take into account the order of input records. */
+
+typedef struct grn_ts_sorter_node {
+ grn_ts_expr *expr; /* Expression. */
+ grn_ts_bool reverse; /* Reverse order or not. */
+ grn_ts_buf buf; /* Buffer for values. */
+ struct grn_ts_sorter_node *next; /* Next node. */
+} grn_ts_sorter_node;
+
+typedef struct {
+ grn_obj *table; /* Table. */
+ grn_ts_sorter_node *head; /* First node. */
+ size_t offset; /* Top `offset` records will be discarded. */
+ size_t limit; /* At most `limit` records will be left. */
+ grn_ts_bool partial; /* Partial sorting or not. */
+} grn_ts_sorter;
+
+/* grn_ts_sorter_open() creates a sorter. */
+grn_rc grn_ts_sorter_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_sorter_node *head, size_t offset,
+ size_t limit, grn_ts_sorter **sorter);
+
+/* grn_ts_sorter_parse() parses a string and creates a sorter. */
+grn_rc grn_ts_sorter_parse(grn_ctx *ctx, grn_obj *table,
+ grn_ts_str str, size_t offset,
+ size_t limit, grn_ts_sorter **sorter);
+
+/* grn_ts_sorter_close() destroys a sorter. */
+grn_rc grn_ts_sorter_close(grn_ctx *ctx, grn_ts_sorter *sorter);
+
+/* grn_ts_sorter_progress() progresses sorting. */
+grn_rc grn_ts_sorter_progress(grn_ctx *ctx, grn_ts_sorter *sorter,
+ grn_ts_record *recs, size_t n_recs,
+ size_t *n_rest);
+
+/* grn_ts_sorter_complete() completes sorting. */
+grn_rc grn_ts_sorter_complete(grn_ctx *ctx, grn_ts_sorter *sorter,
+ grn_ts_record *recs, size_t n_recs,
+ size_t *n_rest);
+
+typedef struct {
+ grn_obj *table; /* Table. */
+ grn_ts_sorter_node *head; /* First node. */
+ grn_ts_sorter_node *tail; /* Last node. */
+} grn_ts_sorter_builder;
+
+/* grn_ts_sorter_builder_open() creates a sorter builder. */
+grn_rc grn_ts_sorter_builder_open(grn_ctx *ctx, grn_obj *table,
+ grn_ts_sorter_builder **builder);
+
+/* grn_ts_sorter_builder_close() destroys a sorter builder. */
+grn_rc grn_ts_sorter_builder_close(grn_ctx *ctx,
+ grn_ts_sorter_builder *builder);
+
+/* grn_ts_sorter_builder_complete() completes a sorter. */
+grn_rc grn_ts_sorter_builder_complete(grn_ctx *ctx,
+ grn_ts_sorter_builder *builder,
+ size_t offset, size_t limit,
+ grn_ts_sorter **sorter);
+
+/* grn_ts_sorter_builder_push() pushes a node. */
+grn_rc grn_ts_sorter_builder_push(grn_ctx *ctx, grn_ts_sorter_builder *builder,
+ grn_ts_expr *expr, grn_ts_bool reverse);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_str.c b/storage/mroonga/vendor/groonga/lib/ts/ts_str.c
new file mode 100644
index 00000000..9f200fa3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_str.c
@@ -0,0 +1,191 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_str.h"
+
+#include <ctype.h>
+#include <string.h>
+
+/*-------------------------------------------------------------
+ * Byte.
+ */
+
+grn_ts_bool
+grn_ts_byte_is_decimal(uint8_t byte)
+{
+ return (byte >= '0') && (byte <= '9');
+}
+
+grn_ts_bool
+grn_ts_byte_is_name_char(uint8_t byte)
+{
+ /*
+ * Note: A table name allows '#', '@' and '-'.
+ * http://groonga.org/docs/reference/commands/table_create.html#name
+ */
+ if (((byte >= '0') && (byte <= '9')) || ((byte >= 'A') && (byte <= 'Z')) ||
+ ((byte >= 'a') && (byte <= 'z')) || (byte == '_')) {
+ return GRN_TRUE;
+ }
+ return GRN_FALSE;
+}
+
+/*-------------------------------------------------------------
+ * String.
+ */
+
+grn_ts_bool
+grn_ts_str_starts_with(grn_ts_str str, grn_ts_str prefix)
+{
+ if (str.size < prefix.size) {
+ return GRN_FALSE;
+ }
+ return !memcmp(str.ptr, prefix.ptr, prefix.size);
+}
+
+grn_ts_str
+grn_ts_str_trim_left(grn_ts_str str)
+{
+ size_t i;
+ for (i = 0; i < str.size; i++) {
+ if (!isspace((uint8_t)str.ptr[i])) {
+ break;
+ }
+ }
+ str.ptr += i;
+ str.size -= i;
+ return str;
+}
+
+grn_ts_str
+grn_ts_str_trim_score_assignment(grn_ts_str str)
+{
+ grn_ts_str rest;
+ str = grn_ts_str_trim_left(str);
+ if (!grn_ts_str_starts_with(str, (grn_ts_str){ "_score", 6 })) {
+ return str;
+ }
+ rest.ptr = str.ptr + 6;
+ rest.size = str.size - 6;
+ rest = grn_ts_str_trim_left(rest);
+ if (!rest.size || (rest.ptr[0] != '=') ||
+ ((rest.size >= 2) && (rest.ptr[1] == '='))) {
+ return str;
+ }
+ rest.ptr++;
+ rest.size--;
+ return grn_ts_str_trim_left(rest);
+}
+
+grn_ts_bool
+grn_ts_str_has_number_prefix(grn_ts_str str)
+{
+ if (!str.size) {
+ return GRN_FALSE;
+ }
+ if (grn_ts_byte_is_decimal(str.ptr[0])) {
+ return GRN_TRUE;
+ }
+ if (str.size == 1) {
+ return GRN_FALSE;
+ }
+ switch (str.ptr[0]) {
+ case '+': case '-': {
+ if (grn_ts_byte_is_decimal(str.ptr[1])) {
+ return GRN_TRUE;
+ }
+ if (str.size == 2) {
+ return GRN_FALSE;
+ }
+ return (str.ptr[1] == '.') && grn_ts_byte_is_decimal(str.ptr[2]);
+ }
+ case '.': {
+ return grn_ts_byte_is_decimal(str.ptr[1]);
+ }
+ default: {
+ return GRN_FALSE;
+ }
+ }
+}
+
+grn_ts_bool
+grn_ts_str_is_name_prefix(grn_ts_str str)
+{
+ size_t i;
+ for (i = 0; i < str.size; i++) {
+ if (!grn_ts_byte_is_name_char(str.ptr[i])) {
+ return GRN_FALSE;
+ }
+ }
+ return GRN_TRUE;
+}
+
+grn_ts_bool
+grn_ts_str_is_name(grn_ts_str str)
+{
+ if (!str.size) {
+ return GRN_FALSE;
+ }
+ return grn_ts_str_is_name_prefix(str);
+}
+
+grn_ts_bool
+grn_ts_str_is_true(grn_ts_str str)
+{
+ return (str.size == 4) && !memcmp(str.ptr, "true", 4);
+}
+
+grn_ts_bool
+grn_ts_str_is_false(grn_ts_str str)
+{
+ return (str.size == 5) && !memcmp(str.ptr, "false", 5);
+}
+
+grn_ts_bool
+grn_ts_str_is_bool(grn_ts_str str)
+{
+ return grn_ts_str_is_true(str) || grn_ts_str_is_false(str);
+}
+
+grn_ts_bool
+grn_ts_str_is_id_name(grn_ts_str str)
+{
+ return (str.size == GRN_COLUMN_NAME_ID_LEN) &&
+ !memcmp(str.ptr, GRN_COLUMN_NAME_ID, GRN_COLUMN_NAME_ID_LEN);
+}
+
+grn_ts_bool
+grn_ts_str_is_score_name(grn_ts_str str)
+{
+ return (str.size == GRN_COLUMN_NAME_SCORE_LEN) &&
+ !memcmp(str.ptr, GRN_COLUMN_NAME_SCORE, GRN_COLUMN_NAME_SCORE_LEN);
+}
+
+grn_ts_bool
+grn_ts_str_is_key_name(grn_ts_str str)
+{
+ return (str.size == GRN_COLUMN_NAME_KEY_LEN) &&
+ !memcmp(str.ptr, GRN_COLUMN_NAME_KEY, GRN_COLUMN_NAME_KEY_LEN);
+}
+
+grn_ts_bool
+grn_ts_str_is_value_name(grn_ts_str str)
+{
+ return (str.size == GRN_COLUMN_NAME_VALUE_LEN) &&
+ !memcmp(str.ptr, GRN_COLUMN_NAME_VALUE, GRN_COLUMN_NAME_VALUE_LEN);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_str.h b/storage/mroonga/vendor/groonga/lib/ts/ts_str.h
new file mode 100644
index 00000000..11371233
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_str.h
@@ -0,0 +1,106 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------
+ * Byte.
+ */
+
+/* grn_ts_byte_is_decimal() returns whether or not a byte is decimal. */
+grn_ts_bool grn_ts_byte_is_decimal(uint8_t byte);
+
+/*
+ * grn_ts_byte_is_name_char() returns whether or not a byte is allowed as a
+ * part of a name.
+ */
+grn_ts_bool grn_ts_byte_is_name_char(uint8_t byte);
+
+/*-------------------------------------------------------------
+ * String.
+ */
+
+typedef struct {
+ const char *ptr; /* The starting address. */
+ size_t size; /* The size in bytes. */
+} grn_ts_str;
+
+/* grn_ts_str_has_prefix() returns whether or not str starts with prefix. */
+grn_ts_bool grn_ts_str_starts_with(grn_ts_str str, grn_ts_str prefix);
+
+/* grn_ts_str_trim_left() returns a string without leading white-spaces. */
+grn_ts_str grn_ts_str_trim_left(grn_ts_str str);
+
+/*
+ * grn_ts_str_trim_score_assignment() returns a string without leading
+ * white-spaces and an assignment to _score. If `str` does not start with
+ * an assignment, this function returns `grn_ts_str_trim_left(str)`.
+ */
+grn_ts_str grn_ts_str_trim_score_assignment(grn_ts_str str);
+
+/*
+ * grn_ts_str_has_number_prefix() returns whether or not a string starts with a
+ * number or not.
+ */
+grn_ts_bool grn_ts_str_has_number_prefix(grn_ts_str str);
+
+/*
+ * grn_ts_str_is_name_prefix() returns whether or not a string is valid as a
+ * name prefix. Note that an empty string is a name prefix.
+ */
+grn_ts_bool grn_ts_str_is_name_prefix(grn_ts_str str);
+
+/*
+ * grn_ts_str_is_name() returns whether or not a string is valid as a name.
+ * Note that an empty string is invalid as a name.
+ */
+grn_ts_bool grn_ts_str_is_name(grn_ts_str str);
+
+/* grn_ts_str_is_true() returns str == "true". */
+grn_ts_bool grn_ts_str_is_true(grn_ts_str str);
+
+/* grn_ts_str_is_false() returns str == "false". */
+grn_ts_bool grn_ts_str_is_false(grn_ts_str str);
+
+/* grn_ts_str_is_bool() returns (str == "true") || (str == "false"). */
+grn_ts_bool grn_ts_str_is_bool(grn_ts_str str);
+
+/* grn_ts_str_is_id_name() returns str == "_id". */
+grn_ts_bool grn_ts_str_is_id_name(grn_ts_str str);
+
+/* grn_ts_str_is_score_name() returns str == "_score". */
+grn_ts_bool grn_ts_str_is_score_name(grn_ts_str str);
+
+/* grn_ts_str_is_key_name() returns str == "_key". */
+grn_ts_bool grn_ts_str_is_key_name(grn_ts_str str);
+
+/* grn_ts_str_is_value_name() returns str == "_value". */
+grn_ts_bool grn_ts_str_is_value_name(grn_ts_str str);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_types.h b/storage/mroonga/vendor/groonga/lib/ts/ts_types.h
new file mode 100644
index 00000000..389eec42
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_types.h
@@ -0,0 +1,168 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-------------------------------------------------------------
+ * Built-in data types.
+ */
+
+/* grn_builtin_type or table ID. */
+typedef grn_id grn_ts_data_type;
+
+/* ID (_id). */
+typedef grn_id grn_ts_id;
+
+/* Score (_score). */
+typedef float grn_ts_score;
+
+/* Record (_id, _score). */
+typedef struct {
+ grn_ts_id id;
+ grn_ts_score score;
+} grn_ts_record;
+
+/*-------------------------------------------------------------
+ * Built-in scalar data kinds.
+ */
+
+/* Bool. */
+typedef grn_bool grn_ts_bool;
+
+/* Int. */
+typedef int64_t grn_ts_int;
+
+/* Float. */
+typedef double grn_ts_float;
+
+/* Time. */
+typedef int64_t grn_ts_time;
+
+/* Text. */
+typedef struct {
+ const char *ptr;
+ size_t size;
+} grn_ts_text;
+
+/* Geo. */
+typedef grn_geo_point grn_ts_geo;
+typedef grn_geo_point grn_ts_tokyo_geo;
+typedef grn_geo_point grn_ts_wgs84_geo;
+
+/* Ref. */
+typedef grn_ts_record grn_ts_ref;
+
+/*-------------------------------------------------------------
+ * Built-in vector data kinds.
+ */
+
+/* BoolVector. */
+typedef struct {
+ const grn_ts_bool *ptr;
+ size_t size;
+} grn_ts_bool_vector;
+
+/* IntVector. */
+typedef struct {
+ const grn_ts_int *ptr;
+ size_t size;
+} grn_ts_int_vector;
+
+/* FloatVector. */
+typedef struct {
+ const grn_ts_float *ptr;
+ size_t size;
+} grn_ts_float_vector;
+
+/* TimeVector. */
+typedef struct {
+ const grn_ts_time *ptr;
+ size_t size;
+} grn_ts_time_vector;
+
+/* TextVector. */
+typedef struct {
+ const grn_ts_text *ptr;
+ size_t size;
+} grn_ts_text_vector;
+
+/* GeoVector. */
+typedef struct {
+ const grn_ts_geo *ptr;
+ size_t size;
+} grn_ts_geo_vector;
+typedef grn_ts_geo_vector grn_ts_tokyo_geo_vector;
+typedef grn_ts_geo_vector grn_ts_wgs84_geo_vector;
+
+/* RefVector. */
+typedef struct {
+ const grn_ts_ref *ptr;
+ size_t size;
+} grn_ts_ref_vector;
+
+/*-------------------------------------------------------------
+ * Built-in data kinds.
+ */
+
+enum { GRN_TS_VECTOR_FLAG = 1 << 7 };
+
+typedef enum {
+ GRN_TS_VOID = 0, /* GRN_DB_VOID */
+ GRN_TS_BOOL = 1, /* GRN_DB_BOOL */
+ GRN_TS_INT = 2, /* GRN_DB_[U]INT(8/16/32/64) */
+ GRN_TS_FLOAT = 3, /* GRN_DB_FLOAT */
+ GRN_TS_TIME = 4, /* GRN_DB_TIME */
+ GRN_TS_TEXT = 5, /* GRN_DB_[SHORT_/LONG_]TEST */
+ GRN_TS_GEO = 6, /* GRN_DB_(TOKYO/WGS84)_GEO_POINT */
+ GRN_TS_REF = 7, /* Table reference. */
+ GRN_TS_BOOL_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_BOOL,
+ GRN_TS_INT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_INT,
+ GRN_TS_FLOAT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_FLOAT,
+ GRN_TS_TIME_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_TIME,
+ GRN_TS_TEXT_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_TEXT,
+ GRN_TS_GEO_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_GEO,
+ GRN_TS_REF_VECTOR = GRN_TS_VECTOR_FLAG | GRN_TS_REF
+} grn_ts_data_kind;
+
+typedef union {
+ grn_ts_bool as_bool;
+ grn_ts_int as_int;
+ grn_ts_float as_float;
+ grn_ts_time as_time;
+ grn_ts_text as_text;
+ grn_ts_geo as_geo;
+ grn_ts_ref as_ref;
+ grn_ts_bool_vector as_bool_vector;
+ grn_ts_int_vector as_int_vector;
+ grn_ts_float_vector as_float_vector;
+ grn_ts_time_vector as_time_vector;
+ grn_ts_text_vector as_text_vector;
+ grn_ts_geo_vector as_geo_vector;
+ grn_ts_ref_vector as_ref_vector;
+} grn_ts_any;
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_util.c b/storage/mroonga/vendor/groonga/lib/ts/ts_util.c
new file mode 100644
index 00000000..18e66060
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_util.c
@@ -0,0 +1,129 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "ts_util.h"
+
+#include "../grn_dat.h"
+#include "../grn_hash.h"
+#include "../grn_pat.h"
+
+#include "ts_log.h"
+
+grn_rc
+grn_ts_obj_increment_ref_count(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_id id = grn_obj_id(ctx, obj);
+ grn_obj *obj_clone = grn_ctx_at(ctx, id);
+ if (!obj_clone) {
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "grn_ctx_at failed: %d", id);
+ }
+ if (obj_clone != obj) {
+ grn_obj_unlink(ctx, obj_clone);
+ GRN_TS_ERR_RETURN(GRN_UNKNOWN_ERROR, "wrong object: %p != %p",
+ obj, obj_clone);
+ }
+ return GRN_SUCCESS;
+}
+
+grn_ts_bool
+grn_ts_obj_is_table(grn_ctx *ctx, grn_obj *obj)
+{
+ return grn_obj_is_table(ctx, obj);
+}
+
+grn_ts_bool
+grn_ts_obj_is_column(grn_ctx *ctx, grn_obj *obj)
+{
+ switch (obj->header.type) {
+ case GRN_COLUMN_FIX_SIZE:
+ case GRN_COLUMN_VAR_SIZE: {
+ return GRN_TRUE;
+ }
+ /* GRN_COLUMN_INDEX is not supported. */
+ default: {
+ return GRN_FALSE;
+ }
+ }
+}
+
+grn_rc
+grn_ts_ja_get_value(grn_ctx *ctx, grn_obj *ja, grn_ts_id id,
+ grn_ts_buf *buf, size_t *value_size)
+{
+ grn_rc rc;
+ uint32_t size;
+ grn_io_win iw;
+ char *ptr = (char *)grn_ja_ref(ctx, (grn_ja *)ja, id, &iw, &size);
+ if (!ptr) {
+ if (value_size) {
+ *value_size = 0;
+ }
+ return GRN_SUCCESS;
+ }
+ rc = grn_ts_buf_write(ctx, buf, ptr, size);
+ grn_ja_unref(ctx, &iw);
+ if (rc != GRN_SUCCESS) {
+ return rc;
+ }
+ if (value_size) {
+ *value_size = size;
+ }
+ return GRN_SUCCESS;
+}
+
+grn_ts_bool
+grn_ts_table_has_key(grn_ctx *ctx, grn_obj *table)
+{
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ case GRN_TABLE_PAT_KEY:
+ case GRN_TABLE_DAT_KEY: {
+ return GRN_TRUE;
+ }
+ default: {
+ return GRN_FALSE;
+ }
+ }
+}
+
+grn_ts_bool
+grn_ts_table_has_value(grn_ctx *ctx, grn_obj *table)
+{
+ return DB_OBJ(table)->range != GRN_DB_VOID;
+}
+
+const void *
+grn_ts_table_get_value(grn_ctx *ctx, grn_obj *table, grn_ts_id id)
+{
+ switch (table->header.type) {
+ case GRN_TABLE_HASH_KEY: {
+ return grn_hash_get_value_(ctx, (grn_hash *)table, id, NULL);
+ }
+ case GRN_TABLE_PAT_KEY: {
+ uint32_t size;
+ return grn_pat_get_value_(ctx, (grn_pat *)table, id, &size);
+ }
+ /* GRN_TABLE_DAT_KEY does not support _value. */
+ case GRN_TABLE_NO_KEY: {
+ return _grn_array_get_value(ctx, (grn_array *)table, id);
+ }
+ default: {
+ return NULL;
+ }
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/lib/ts/ts_util.h b/storage/mroonga/vendor/groonga/lib/ts/ts_util.h
new file mode 100644
index 00000000..24a6a507
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/ts/ts_util.h
@@ -0,0 +1,61 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#pragma once
+
+#include "../grn.h"
+
+#include "ts_buf.h"
+#include "ts_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* grn_ts_obj_increment_ref_count() increments an object reference count. */
+grn_rc grn_ts_obj_increment_ref_count(grn_ctx *ctx, grn_obj *obj);
+
+/* grn_ts_obj_is_table() returns whether or not an object is a table. */
+grn_ts_bool grn_ts_obj_is_table(grn_ctx *ctx, grn_obj *obj);
+
+/* grn_ts_obj_is_column() returns whether or not an object is a column. */
+grn_ts_bool grn_ts_obj_is_column(grn_ctx *ctx, grn_obj *obj);
+
+/*
+ * grn_ts_ja_get_value() gets a value from ja and writes it to buf. Note that
+ * the value is appended to the end of buf.
+ */
+grn_rc grn_ts_ja_get_value(grn_ctx *ctx, grn_obj *ja, grn_ts_id id,
+ grn_ts_buf *buf, size_t *value_size);
+
+/* grn_ts_table_has_key() returns whether or not a table has _key. */
+grn_ts_bool grn_ts_table_has_key(grn_ctx *ctx, grn_obj *table);
+
+/* grn_ts_table_has_value() returns whether or not a table has _value. */
+grn_ts_bool grn_ts_table_has_value(grn_ctx *ctx, grn_obj *table);
+
+/*
+ * grn_ts_table_get_value() gets a reference to a value (_value). On failure,
+ * this function returns NULL.
+ */
+const void *grn_ts_table_get_value(grn_ctx *ctx, grn_obj *table, grn_ts_id id);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/storage/mroonga/vendor/groonga/lib/type.c b/storage/mroonga/vendor/groonga/lib/type.c
new file mode 100644
index 00000000..6696444a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/type.c
@@ -0,0 +1,87 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx_impl.h"
+#include "grn_db.h"
+
+grn_bool
+grn_type_id_is_builtin(grn_ctx *ctx, grn_id id)
+{
+ return id >= GRN_DB_OBJECT && id <= GRN_DB_WGS84_GEO_POINT;
+}
+
+grn_bool
+grn_type_id_is_number_family(grn_ctx *ctx, grn_id id)
+{
+ return GRN_DB_INT8 <= id && id <= GRN_DB_FLOAT;
+}
+
+grn_bool
+grn_type_id_is_text_family(grn_ctx *ctx, grn_id id)
+{
+ return GRN_DB_SHORT_TEXT <= id && id <= GRN_DB_LONG_TEXT;
+}
+
+grn_obj *
+grn_type_create(grn_ctx *ctx, const char *name, unsigned int name_size,
+ grn_obj_flags flags, unsigned int size)
+{
+ grn_id id;
+ struct _grn_type *res = NULL;
+ grn_obj *db;
+ if (!ctx || !ctx->impl || !(db = ctx->impl->db)) {
+ ERR(GRN_INVALID_ARGUMENT, "db not initialized");
+ return NULL;
+ }
+ GRN_API_ENTER;
+ if (grn_db_check_name(ctx, name, name_size)) {
+ GRN_DB_CHECK_NAME_ERR("[type][create]", name, name_size);
+ GRN_API_RETURN(NULL);
+ }
+ if (!GRN_DB_P(db)) {
+ ERR(GRN_INVALID_ARGUMENT, "invalid db assigned");
+ GRN_API_RETURN(NULL);
+ }
+ id = grn_obj_register(ctx, db, name, name_size);
+ if (id && (res = GRN_MALLOC(sizeof(grn_db_obj)))) {
+ GRN_DB_OBJ_SET_TYPE(res, GRN_TYPE);
+ res->obj.header.flags = flags;
+ res->obj.header.domain = GRN_ID_NIL;
+ GRN_TYPE_SIZE(&res->obj) = size;
+ if (grn_db_obj_init(ctx, db, id, DB_OBJ(res))) {
+ // grn_obj_delete(ctx, db, id);
+ GRN_FREE(res);
+ GRN_API_RETURN(NULL);
+ }
+ }
+ GRN_API_RETURN((grn_obj *)res);
+}
+
+uint32_t
+grn_type_size(grn_ctx *ctx, grn_obj *type)
+{
+ uint32_t size;
+
+ GRN_API_ENTER;
+ if (!type) {
+ ERR(GRN_INVALID_ARGUMENT, "[type][size] type is NULL");
+ GRN_API_RETURN(0);
+ }
+ size = GRN_TYPE_SIZE(DB_OBJ(type));
+ GRN_API_RETURN(size);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/util.c b/storage/mroonga/vendor/groonga/lib/util.c
new file mode 100644
index 00000000..2b2c24be
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/util.c
@@ -0,0 +1,1643 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_db.h"
+#include "grn_pat.h"
+#include "grn_ii.h"
+#include "grn_util.h"
+#include "grn_string.h"
+#include "grn_expr.h"
+#include "grn_load.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef WIN32
+# include <io.h>
+# include <share.h>
+#endif /* WIN32 */
+
+grn_rc
+grn_normalize_offset_and_limit(grn_ctx *ctx, int size, int *p_offset, int *p_limit)
+{
+ int end;
+ int offset = *p_offset;
+ int limit = *p_limit;
+
+ if (offset < 0) {
+ offset += size;
+ if (offset < 0) {
+ *p_offset = 0;
+ *p_limit = 0;
+ return GRN_TOO_SMALL_OFFSET;
+ }
+ } else if (offset != 0 && offset >= size) {
+ *p_offset = 0;
+ *p_limit = 0;
+ return GRN_TOO_LARGE_OFFSET;
+ }
+
+ if (limit < 0) {
+ limit += size + 1;
+ if (limit < 0) {
+ *p_offset = 0;
+ *p_limit = 0;
+ return GRN_TOO_SMALL_LIMIT;
+ }
+ } else if (limit > size) {
+ limit = size;
+ }
+
+ /* At this point, offset and limit must be zero or positive. */
+ end = offset + limit;
+ if (end > size) {
+ limit -= end - size;
+ }
+ *p_offset = offset;
+ *p_limit = limit;
+ return GRN_SUCCESS;
+}
+
+grn_obj *
+grn_inspect_name(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ int name_size;
+
+ name_size = grn_obj_name(ctx, obj, NULL, 0);
+ if (name_size > 0) {
+ grn_bulk_space(ctx, buf, name_size);
+ grn_obj_name(ctx, obj, GRN_BULK_CURR(buf) - name_size, name_size);
+ } else {
+ grn_id id;
+
+ id = grn_obj_id(ctx, obj);
+ if (id == GRN_ID_NIL) {
+ GRN_TEXT_PUTS(ctx, buf, "(nil)");
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(anonymous:");
+ grn_text_lltoa(ctx, buf, id);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+ }
+ }
+
+ return buf;
+}
+
+grn_obj *
+grn_inspect_encoding(grn_ctx *ctx, grn_obj *buf, grn_encoding encoding)
+{
+ switch (encoding) {
+ case GRN_ENC_DEFAULT :
+ GRN_TEXT_PUTS(ctx, buf, "default(");
+ grn_inspect_encoding(ctx, buf, grn_get_default_encoding());
+ GRN_TEXT_PUTS(ctx, buf, ")");
+ break;
+ case GRN_ENC_NONE :
+ GRN_TEXT_PUTS(ctx, buf, "none");
+ break;
+ case GRN_ENC_EUC_JP :
+ GRN_TEXT_PUTS(ctx, buf, "EUC-JP");
+ break;
+ case GRN_ENC_UTF8 :
+ GRN_TEXT_PUTS(ctx, buf, "UTF-8");
+ break;
+ case GRN_ENC_SJIS :
+ GRN_TEXT_PUTS(ctx, buf, "Shift_JIS");
+ break;
+ case GRN_ENC_LATIN1 :
+ GRN_TEXT_PUTS(ctx, buf, "Latin-1");
+ break;
+ case GRN_ENC_KOI8R :
+ GRN_TEXT_PUTS(ctx, buf, "KOI8-R");
+ break;
+ default :
+ GRN_TEXT_PUTS(ctx, buf, "unknown(");
+ grn_text_itoa(ctx, buf, encoding);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+ break;
+ }
+
+ return buf;
+}
+
+grn_obj *
+grn_inspect_type(grn_ctx *ctx, grn_obj *buf, unsigned char type)
+{
+ switch (type) {
+ case GRN_VOID :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_VOID");
+ break;
+ case GRN_BULK :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_BULK");
+ break;
+ case GRN_PTR :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_PTR");
+ break;
+ case GRN_UVECTOR :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_UVECTOR");
+ break;
+ case GRN_PVECTOR :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_PVECTOR");
+ break;
+ case GRN_VECTOR :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_VECTOR");
+ break;
+ case GRN_MSG :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_MSG");
+ break;
+ case GRN_QUERY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_QUERY");
+ break;
+ case GRN_ACCESSOR :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_ACCESSOR");
+ break;
+ case GRN_SNIP :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_SNIP");
+ break;
+ case GRN_PATSNIP :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_PATSNIP");
+ break;
+ case GRN_STRING :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_STRING");
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_CURSOR_TABLE_HASH_KEY");
+ break;
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_CURSOR_TABLE_PAT_KEY");
+ break;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_CURSOR_TABLE_DAT_KEY");
+ break;
+ case GRN_CURSOR_TABLE_NO_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_CURSOR_TABLE_NO_KEY");
+ break;
+ case GRN_CURSOR_COLUMN_INDEX :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_CURSOR_COLUMN_INDEX");
+ break;
+ case GRN_CURSOR_COLUMN_GEO_INDEX :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_CURSOR_COLUMN_GEO_INDEX");
+ break;
+ case GRN_TYPE :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_TYPE");
+ break;
+ case GRN_PROC :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_PROC");
+ break;
+ case GRN_EXPR :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_EXPR");
+ break;
+ case GRN_TABLE_HASH_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_TABLE_HASH_KEY");
+ break;
+ case GRN_TABLE_PAT_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_TABLE_PAT_KEY");
+ break;
+ case GRN_TABLE_DAT_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_TABLE_DAT_KEY");
+ break;
+ case GRN_TABLE_NO_KEY :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_TABLE_NO_KEY");
+ break;
+ case GRN_DB :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_DB");
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_COLUMN_FIX_SIZE");
+ break;
+ case GRN_COLUMN_VAR_SIZE :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_COLUMN_VAR_SIZE");
+ break;
+ case GRN_COLUMN_INDEX :
+ GRN_TEXT_PUTS(ctx, buf, "GRN_COLUMN_INDEX");
+ break;
+ default:
+ {
+#define TYPE_IN_HEX_SIZE 5 /* "0xXX" */
+ char type_in_hex[TYPE_IN_HEX_SIZE];
+ grn_snprintf(type_in_hex,
+ TYPE_IN_HEX_SIZE,
+ TYPE_IN_HEX_SIZE,
+ "%#02x", type);
+#undef TYPE_IN_HEX_SIZE
+ GRN_TEXT_PUTS(ctx, buf, "(unknown: ");
+ GRN_TEXT_PUTS(ctx, buf, type_in_hex);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+ }
+ break;
+ }
+
+ return buf;
+}
+
+
+grn_obj *
+grn_inspect_query_log_flags(grn_ctx *ctx, grn_obj *buffer, unsigned int flags)
+{
+ grn_bool have_content = GRN_FALSE;
+
+ if (flags == GRN_QUERY_LOG_NONE) {
+ GRN_TEXT_PUTS(ctx, buffer, "NONE");
+ return buffer;
+ }
+
+#define CHECK_FLAG(NAME) do { \
+ if (flags & GRN_QUERY_LOG_ ## NAME) { \
+ if (have_content) { \
+ GRN_TEXT_PUTS(ctx, buffer, "|"); \
+ } \
+ GRN_TEXT_PUTS(ctx, buffer, #NAME); \
+ have_content = GRN_TRUE; \
+ } \
+ } while (GRN_FALSE)
+
+ CHECK_FLAG(COMMAND);
+ CHECK_FLAG(RESULT_CODE);
+ CHECK_FLAG(DESTINATION);
+ CHECK_FLAG(CACHE);
+ CHECK_FLAG(SIZE);
+ CHECK_FLAG(SCORE);
+
+#undef CHECK_FALG
+
+ return buffer;
+}
+
+static grn_rc
+grn_proc_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_proc *proc = (grn_proc *)obj;
+ uint32_t i;
+
+ GRN_TEXT_PUTS(ctx, buf, "#<proc:");
+ switch (proc->type) {
+ case GRN_PROC_INVALID :
+ GRN_TEXT_PUTS(ctx, buf, "invalid");
+ GRN_TEXT_PUTS(ctx, buf, ">");
+ return GRN_SUCCESS;
+ break;
+ case GRN_PROC_TOKENIZER :
+ GRN_TEXT_PUTS(ctx, buf, "tokenizer");
+ break;
+ case GRN_PROC_COMMAND :
+ GRN_TEXT_PUTS(ctx, buf, "command");
+ break;
+ case GRN_PROC_FUNCTION :
+ GRN_TEXT_PUTS(ctx, buf, "function");
+ break;
+ case GRN_PROC_HOOK :
+ GRN_TEXT_PUTS(ctx, buf, "hook");
+ break;
+ case GRN_PROC_NORMALIZER :
+ GRN_TEXT_PUTS(ctx, buf, "normalizer");
+ break;
+ case GRN_PROC_TOKEN_FILTER :
+ GRN_TEXT_PUTS(ctx, buf, "token-filter");
+ break;
+ case GRN_PROC_SCORER :
+ GRN_TEXT_PUTS(ctx, buf, "scorer");
+ break;
+ case GRN_PROC_WINDOW_FUNCTION :
+ GRN_TEXT_PUTS(ctx, buf, "window-function");
+ break;
+ }
+ GRN_TEXT_PUTS(ctx, buf, " ");
+
+ grn_inspect_name(ctx, buf, obj);
+ GRN_TEXT_PUTS(ctx, buf, " ");
+
+ GRN_TEXT_PUTS(ctx, buf, "arguments:[");
+ for (i = 0; i < proc->nvars; i++) {
+ grn_expr_var *var = proc->vars + i;
+ if (i != 0) {
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ }
+ GRN_TEXT_PUT(ctx, buf, var->name, var->name_size);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_expr_code_inspect_indented(grn_ctx *ctx,
+ grn_obj *buffer,
+ grn_expr_code *code,
+ const char *indent)
+{
+ if (!code) {
+ GRN_TEXT_PUTS(ctx, buffer, "(NULL)");
+ return GRN_SUCCESS;
+ }
+
+ GRN_TEXT_PUTS(ctx, buffer, "<");
+ GRN_TEXT_PUTS(ctx, buffer, grn_operator_to_string(code->op));
+ GRN_TEXT_PUTS(ctx, buffer, " ");
+ GRN_TEXT_PUTS(ctx, buffer, "n_args:");
+ grn_text_itoa(ctx, buffer, code->nargs);
+ GRN_TEXT_PUTS(ctx, buffer, ", ");
+ GRN_TEXT_PUTS(ctx, buffer, "flags:");
+ grn_text_itoh(ctx, buffer, code->flags, 1);
+ GRN_TEXT_PUTS(ctx, buffer, ", ");
+ GRN_TEXT_PUTS(ctx, buffer, "modify:");
+ grn_text_itoa(ctx, buffer, code->modify);
+ GRN_TEXT_PUTS(ctx, buffer, ", ");
+ GRN_TEXT_PUTS(ctx, buffer, "value:");
+ grn_inspect_indented(ctx, buffer, code->value, " ");
+ GRN_TEXT_PUTS(ctx, buffer, ">");
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_expr_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *expr)
+{
+ grn_expr *e = (grn_expr *)expr;
+
+ GRN_TEXT_PUTS(ctx, buffer, "#<expr\n");
+ {
+ int i = 0;
+ grn_obj *value;
+ const char *name;
+ uint32_t name_len;
+ unsigned int n_vars;
+ grn_hash *vars = grn_expr_get_vars(ctx, expr, &n_vars);
+ GRN_TEXT_PUTS(ctx, buffer, " vars:{");
+ GRN_HASH_EACH(ctx, vars, id, &name, &name_len, &value, {
+ if (i++) {
+ GRN_TEXT_PUTC(ctx, buffer, ',');
+ }
+ GRN_TEXT_PUTS(ctx, buffer, "\n ");
+ GRN_TEXT_PUT(ctx, buffer, name, name_len);
+ GRN_TEXT_PUTC(ctx, buffer, ':');
+ grn_inspect_indented(ctx, buffer, value, " ");
+ });
+ GRN_TEXT_PUTS(ctx, buffer, "\n },");
+ }
+
+ {
+ uint32_t i;
+ grn_expr_code *code;
+ GRN_TEXT_PUTS(ctx, buffer, "\n codes:{");
+ for (i = 0, code = e->codes; i < e->codes_curr; i++, code++) {
+ if (i) { GRN_TEXT_PUTC(ctx, buffer, ','); }
+ GRN_TEXT_PUTS(ctx, buffer, "\n ");
+ grn_text_itoa(ctx, buffer, i);
+ GRN_TEXT_PUTS(ctx, buffer, ":");
+ grn_expr_code_inspect_indented(ctx, buffer, code, " ");
+ }
+ GRN_TEXT_PUTS(ctx, buffer, "\n }");
+ }
+
+ GRN_TEXT_PUTS(ctx, buffer, "\n>");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_ptr_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *ptr)
+{
+ size_t size;
+
+ GRN_TEXT_PUTS(ctx, buffer, "#<ptr:");
+
+ size = GRN_BULK_VSIZE(ptr);
+ if (size == 0) {
+ GRN_TEXT_PUTS(ctx, buffer, "(empty)");
+ } else if (size >= sizeof(grn_obj *)) {
+ grn_obj *content = GRN_PTR_VALUE(ptr);
+ grn_inspect(ctx, buffer, content);
+ if (size > sizeof(grn_obj *)) {
+ grn_text_printf(ctx, buffer,
+ " (and more data: %" GRN_FMT_SIZE ")",
+ size - sizeof(grn_obj *));
+ }
+ }
+ GRN_TEXT_PUTS(ctx, buffer, ">");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_pvector_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *pvector)
+{
+ int i, n;
+
+ GRN_TEXT_PUTS(ctx, buffer, "[");
+ n = GRN_BULK_VSIZE(pvector) / sizeof(grn_obj *);
+ for (i = 0; i < n; i++) {
+ grn_obj *element = GRN_PTR_VALUE_AT(pvector, i);
+
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buffer, ", ");
+ }
+
+ grn_inspect(ctx, buffer, element);
+ }
+ GRN_TEXT_PUTS(ctx, buffer, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_vector_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *vector)
+{
+ int i;
+ grn_obj *body = vector->u.v.body;
+
+ GRN_TEXT_PUTS(ctx, buffer, "[");
+ for (i = 0; i < vector->u.v.n_sections; i++) {
+ grn_section *section = &(vector->u.v.sections[i]);
+ const char *value_raw;
+
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buffer, ", ");
+ }
+
+ value_raw = GRN_BULK_HEAD(body) + section->offset;
+ GRN_TEXT_PUTS(ctx, buffer, "{");
+ GRN_TEXT_PUTS(ctx, buffer, "\"value\":");
+ {
+ grn_obj value_object;
+ GRN_OBJ_INIT(&value_object, GRN_BULK, GRN_OBJ_DO_SHALLOW_COPY,
+ section->domain);
+ GRN_TEXT_SET(ctx, &value_object, value_raw, section->length);
+ grn_inspect(ctx, buffer, &value_object);
+ GRN_OBJ_FIN(ctx, &value_object);
+ }
+ GRN_TEXT_PUTS(ctx, buffer, ", \"weight\":");
+ grn_text_itoa(ctx, buffer, section->weight);
+ GRN_TEXT_PUTS(ctx, buffer, "}");
+ }
+ GRN_TEXT_PUTS(ctx, buffer, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_accessor_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_accessor *accessor = (grn_accessor *)obj;
+
+ GRN_TEXT_PUTS(ctx, buf, "#<accessor ");
+ for (; accessor; accessor = accessor->next) {
+ grn_bool show_obj_name = GRN_FALSE;
+ grn_bool show_obj_domain_name = GRN_FALSE;
+
+ if (accessor != (grn_accessor *)obj) {
+ GRN_TEXT_PUTS(ctx, buf, ".");
+ }
+ switch (accessor->action) {
+ case GRN_ACCESSOR_GET_ID :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_ID,
+ GRN_COLUMN_NAME_ID_LEN);
+ show_obj_name = GRN_TRUE;
+ break;
+ case GRN_ACCESSOR_GET_KEY :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ show_obj_name = GRN_TRUE;
+ break;
+ case GRN_ACCESSOR_GET_VALUE :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_VALUE,
+ GRN_COLUMN_NAME_VALUE_LEN);
+ show_obj_name = GRN_TRUE;
+ break;
+ case GRN_ACCESSOR_GET_SCORE :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_SCORE,
+ GRN_COLUMN_NAME_SCORE_LEN);
+ break;
+ case GRN_ACCESSOR_GET_NSUBRECS :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_NSUBRECS,
+ GRN_COLUMN_NAME_NSUBRECS_LEN);
+ break;
+ case GRN_ACCESSOR_GET_MAX :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_MAX,
+ GRN_COLUMN_NAME_MAX_LEN);
+ break;
+ case GRN_ACCESSOR_GET_MIN :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_MIN,
+ GRN_COLUMN_NAME_MIN_LEN);
+ break;
+ case GRN_ACCESSOR_GET_SUM :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_SUM,
+ GRN_COLUMN_NAME_SUM_LEN);
+ break;
+ case GRN_ACCESSOR_GET_AVG :
+ GRN_TEXT_PUT(ctx,
+ buf,
+ GRN_COLUMN_NAME_AVG,
+ GRN_COLUMN_NAME_AVG_LEN);
+ break;
+ case GRN_ACCESSOR_GET_COLUMN_VALUE :
+ grn_column_name_(ctx, accessor->obj, buf);
+ show_obj_domain_name = GRN_TRUE;
+ break;
+ case GRN_ACCESSOR_GET_DB_OBJ :
+ grn_text_printf(ctx, buf, "(_db)");
+ break;
+ case GRN_ACCESSOR_LOOKUP :
+ grn_text_printf(ctx, buf, "(_lookup)");
+ break;
+ case GRN_ACCESSOR_FUNCALL :
+ grn_text_printf(ctx, buf, "(_funcall)");
+ break;
+ default :
+ grn_text_printf(ctx, buf, "(unknown:%u)", accessor->action);
+ break;
+ }
+
+ if (show_obj_name || show_obj_domain_name) {
+ grn_obj *target = accessor->obj;
+ char name[GRN_TABLE_MAX_KEY_SIZE];
+ int name_size;
+
+ if (show_obj_domain_name) {
+ target = grn_ctx_at(ctx, target->header.domain);
+ }
+
+ name_size = grn_obj_name(ctx,
+ target,
+ name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_PUTS(ctx, buf, "(");
+ if (name_size == 0) {
+ GRN_TEXT_PUTS(ctx, buf, "anonymous");
+ } else {
+ GRN_TEXT_PUT(ctx, buf, name, name_size);
+ }
+ GRN_TEXT_PUTS(ctx, buf, ")");
+ }
+ }
+ GRN_TEXT_PUTS(ctx, buf, ">");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_type_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_id range_id;
+
+ GRN_TEXT_PUTS(ctx, buf, "#<type ");
+ grn_inspect_name(ctx, buf, obj);
+
+ range_id = grn_obj_get_range(ctx, obj);
+ GRN_TEXT_PUTS(ctx, buf, " size:");
+ grn_text_lltoa(ctx, buf, range_id);
+
+ GRN_TEXT_PUTS(ctx, buf, " type:");
+ if (obj->header.flags & GRN_OBJ_KEY_VAR_SIZE) {
+ GRN_TEXT_PUTS(ctx, buf, "var_size");
+ } else {
+ switch (obj->header.flags & GRN_OBJ_KEY_MASK) {
+ case GRN_OBJ_KEY_UINT :
+ GRN_TEXT_PUTS(ctx, buf, "uint");
+ break;
+ case GRN_OBJ_KEY_INT :
+ GRN_TEXT_PUTS(ctx, buf, "int");
+ break;
+ case GRN_OBJ_KEY_FLOAT :
+ GRN_TEXT_PUTS(ctx, buf, "float");
+ break;
+ case GRN_OBJ_KEY_GEO_POINT :
+ GRN_TEXT_PUTS(ctx, buf, "geo_point");
+ break;
+ default :
+ break;
+ }
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_column_inspect_common(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_id range_id;
+
+ grn_inspect_name(ctx, buf, obj);
+
+ range_id = grn_obj_get_range(ctx, obj);
+ if (range_id) {
+ grn_obj *range = grn_ctx_at(ctx, range_id);
+ GRN_TEXT_PUTS(ctx, buf, " range:");
+ if (range) {
+ grn_inspect_name(ctx, buf, range);
+ } else {
+ grn_text_lltoa(ctx, buf, range_id);
+ }
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_store_inspect_body(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_column_inspect_common(ctx, buf, obj);
+ GRN_TEXT_PUTS(ctx, buf, " type:");
+ switch (obj->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
+ case GRN_OBJ_COLUMN_VECTOR :
+ GRN_TEXT_PUTS(ctx, buf, "vector");
+ break;
+ case GRN_OBJ_COLUMN_SCALAR :
+ GRN_TEXT_PUTS(ctx, buf, "scalar");
+ break;
+ default:
+ break;
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, " compress:");
+ switch (obj->header.flags & GRN_OBJ_COMPRESS_MASK) {
+ case GRN_OBJ_COMPRESS_NONE :
+ GRN_TEXT_PUTS(ctx, buf, "none");
+ break;
+ case GRN_OBJ_COMPRESS_ZLIB :
+ GRN_TEXT_PUTS(ctx, buf, "zlib");
+ break;
+ case GRN_OBJ_COMPRESS_LZ4 :
+ GRN_TEXT_PUTS(ctx, buf, "lz4");
+ break;
+ case GRN_OBJ_COMPRESS_ZSTD :
+ GRN_TEXT_PUTS(ctx, buf, "zstd");
+ break;
+ default:
+ break;
+ }
+
+ if (obj->header.flags & GRN_OBJ_RING_BUFFER) {
+ GRN_TEXT_PUTS(ctx, buf, " ring_buffer:true");
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_ra_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ GRN_TEXT_PUTS(ctx, buf, "#<column:fix_size ");
+ grn_store_inspect_body(ctx, buf, obj);
+ GRN_TEXT_PUTS(ctx, buf, ">");
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_ja_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ GRN_TEXT_PUTS(ctx, buf, "#<column:var_size ");
+ grn_store_inspect_body(ctx, buf, obj);
+ GRN_TEXT_PUTS(ctx, buf, ">");
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_ii_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_obj sources;
+ int i, n, have_flags = 0;
+ grn_id *source_ids;
+
+ GRN_TEXT_PUTS(ctx, buf, "#<column:index ");
+ grn_column_inspect_common(ctx, buf, obj);
+
+ GRN_TEXT_INIT(&sources, 0);
+ grn_obj_get_info(ctx, obj, GRN_INFO_SOURCE, &sources);
+ source_ids = (grn_id *)GRN_BULK_HEAD(&sources);
+ n = GRN_BULK_VSIZE(&sources) / sizeof(grn_id);
+ GRN_TEXT_PUTS(ctx, buf, " sources:[");
+ for (i = 0; i < n; i++) {
+ grn_id source_id;
+ grn_obj *source;
+ if (i) { GRN_TEXT_PUTS(ctx, buf, ", "); }
+ source_id = source_ids[i];
+ source = grn_ctx_at(ctx, source_id);
+ if (source) {
+ grn_inspect_name(ctx, buf, source);
+ } else {
+ grn_text_lltoa(ctx, buf, source_id);
+ }
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+ GRN_OBJ_FIN(ctx, &sources);
+
+ GRN_TEXT_PUTS(ctx, buf, " flags:");
+ if (obj->header.flags & GRN_OBJ_WITH_SECTION) {
+ GRN_TEXT_PUTS(ctx, buf, "SECTION");
+ have_flags = 1;
+ }
+ if (obj->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ if (have_flags) { GRN_TEXT_PUTS(ctx, buf, "|"); }
+ GRN_TEXT_PUTS(ctx, buf, "WEIGHT");
+ have_flags = 1;
+ }
+ if (obj->header.flags & GRN_OBJ_WITH_POSITION) {
+ if (have_flags) { GRN_TEXT_PUTS(ctx, buf, "|"); }
+ GRN_TEXT_PUTS(ctx, buf, "POSITION");
+ have_flags = 1;
+ }
+ if (!have_flags) {
+ GRN_TEXT_PUTS(ctx, buf, "NONE");
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_type_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ switch (obj->header.type) {
+ case GRN_TABLE_HASH_KEY:
+ GRN_TEXT_PUTS(ctx, buf, "hash");
+ break;
+ case GRN_TABLE_PAT_KEY:
+ GRN_TEXT_PUTS(ctx, buf, "pat");
+ break;
+ case GRN_TABLE_DAT_KEY:
+ GRN_TEXT_PUTS(ctx, buf, "dat");
+ break;
+ case GRN_TABLE_NO_KEY:
+ GRN_TEXT_PUTS(ctx, buf, "no_key");
+ break;
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_key_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_obj *domain;
+ grn_id domain_id;
+
+ GRN_TEXT_PUTS(ctx, buf, "key:");
+ domain_id = obj->header.domain;
+ domain = grn_ctx_at(ctx, domain_id);
+ if (domain) {
+ grn_inspect_name(ctx, buf, domain);
+ } else if (domain_id) {
+ grn_text_lltoa(ctx, buf, domain_id);
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(nil)");
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_columns_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_hash *cols;
+
+ GRN_TEXT_PUTS(ctx, buf, "columns:[");
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, obj, "", 0, (grn_obj *)cols)) {
+ int i = 0;
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) {
+ if (i++ > 0) { GRN_TEXT_PUTS(ctx, buf, ", "); }
+ grn_column_name_(ctx, col, buf);
+ }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_ids_and_values_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ int i = 0;
+ grn_obj value;
+
+ GRN_VALUE_FIX_SIZE_INIT(&value, 0, grn_obj_get_range(ctx, obj));
+
+ GRN_TEXT_PUTS(ctx, buf, "ids&values:[");
+ GRN_TABLE_EACH_BEGIN(ctx, obj, cursor, id) {
+ void *value_buffer;
+ int value_size;
+
+ if (i++ > 0) {
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, "\n ");
+ grn_text_lltoa(ctx, buf, id);
+ GRN_TEXT_PUTS(ctx, buf, ":");
+ value_size = grn_table_cursor_get_value(ctx, cursor, &value_buffer);
+ grn_bulk_write_from(ctx, &value, value_buffer, 0, value_size);
+ grn_inspect(ctx, buf, &value);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ GRN_TEXT_PUTS(ctx, buf, "\n]");
+
+ GRN_OBJ_FIN(ctx, &value);
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_ids_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_table_cursor *tc;
+
+ GRN_TEXT_PUTS(ctx, buf, "ids:[");
+ tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_ASCENDING);
+ if (tc) {
+ int i = 0;
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, tc))) {
+ if (i++ > 0) { GRN_TEXT_PUTS(ctx, buf, ", "); }
+ grn_text_lltoa(ctx, buf, id);
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_default_tokenizer_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_obj *default_tokenizer;
+
+ GRN_TEXT_PUTS(ctx, buf, "default_tokenizer:");
+ default_tokenizer = grn_obj_get_info(ctx, obj,
+ GRN_INFO_DEFAULT_TOKENIZER, NULL);
+ if (default_tokenizer) {
+ grn_inspect_name(ctx, buf, default_tokenizer);
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(nil)");
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_normalizer_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_obj *normalizer;
+
+ GRN_TEXT_PUTS(ctx, buf, "normalizer:");
+ normalizer = grn_obj_get_info(ctx, obj, GRN_INFO_NORMALIZER, NULL);
+ if (normalizer) {
+ grn_inspect_name(ctx, buf, normalizer);
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(nil)");
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_keys_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_table_cursor *tc;
+ int max_n_keys = 10;
+
+ /* TODO */
+ /* max_n_keys = grn_atoi(grn_getenv("GRN_INSPECT_TABLE_MAX_N_KEYS")); */
+
+ GRN_TEXT_PUTS(ctx, buf, "keys:[");
+ tc = grn_table_cursor_open(ctx, obj, NULL, 0, NULL, 0,
+ 0, -1, GRN_CURSOR_ASCENDING);
+ if (tc) {
+ int i = 0;
+ grn_id id;
+ grn_obj key;
+ GRN_OBJ_INIT(&key, GRN_BULK, 0, obj->header.domain);
+ while ((id = grn_table_cursor_next(ctx, tc))) {
+ if (max_n_keys > 0 && i >= max_n_keys) {
+ GRN_TEXT_PUTS(ctx, buf, ", ...");
+ break;
+ }
+ if (i++ > 0) { GRN_TEXT_PUTS(ctx, buf, ", "); }
+ grn_table_get_key2(ctx, obj, id, &key);
+ grn_inspect(ctx, buf, &key);
+ GRN_BULK_REWIND(&key);
+ }
+ GRN_OBJ_FIN(ctx, &key);
+ grn_table_cursor_close(ctx, tc);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_subrec_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ GRN_TEXT_PUTS(ctx, buf, "subrec:");
+ if (obj->header.flags & GRN_OBJ_WITH_SUBREC) {
+ switch (obj->header.flags & GRN_OBJ_UNIT_MASK) {
+ case GRN_OBJ_UNIT_DOCUMENT_NONE :
+ GRN_TEXT_PUTS(ctx, buf, "document:none");
+ break;
+ case GRN_OBJ_UNIT_DOCUMENT_SECTION :
+ GRN_TEXT_PUTS(ctx, buf, "document:section");
+ break;
+ case GRN_OBJ_UNIT_DOCUMENT_POSITION :
+ GRN_TEXT_PUTS(ctx, buf, "document:position");
+ break;
+ case GRN_OBJ_UNIT_SECTION_NONE :
+ GRN_TEXT_PUTS(ctx, buf, "section:none");
+ break;
+ case GRN_OBJ_UNIT_SECTION_POSITION :
+ GRN_TEXT_PUTS(ctx, buf, "section:popsition");
+ break;
+ case GRN_OBJ_UNIT_POSITION_NONE :
+ GRN_TEXT_PUTS(ctx, buf, "section:none");
+ break;
+ case GRN_OBJ_UNIT_USERDEF_DOCUMENT :
+ GRN_TEXT_PUTS(ctx, buf, "userdef:document");
+ break;
+ case GRN_OBJ_UNIT_USERDEF_SECTION :
+ GRN_TEXT_PUTS(ctx, buf, "userdef:section");
+ break;
+ case GRN_OBJ_UNIT_USERDEF_POSITION :
+ GRN_TEXT_PUTS(ctx, buf, "userdef:position");
+ break;
+ }
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "none");
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_table_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_id range_id;
+ grn_obj *range;
+
+ GRN_TEXT_PUTS(ctx, buf, "#<table:");
+ grn_table_type_inspect(ctx, buf, obj);
+ GRN_TEXT_PUTS(ctx, buf, " ");
+
+ grn_inspect_name(ctx, buf, obj);
+
+ if (obj->header.type != GRN_TABLE_NO_KEY) {
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_table_key_inspect(ctx, buf, obj);
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, " value:");
+ range_id = grn_obj_get_range(ctx, obj);
+ range = grn_ctx_at(ctx, range_id);
+ if (range) {
+ grn_inspect_name(ctx, buf, range);
+ } else if (range_id) {
+ grn_text_lltoa(ctx, buf, range_id);
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(nil)");
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, " size:");
+ grn_text_lltoa(ctx, buf, grn_table_size(ctx, obj));
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_table_columns_inspect(ctx, buf, obj);
+
+ if (obj->header.type == GRN_TABLE_NO_KEY) {
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ if (range) {
+ grn_table_ids_and_values_inspect(ctx, buf, obj);
+ } else {
+ grn_table_ids_inspect(ctx, buf, obj);
+ }
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_table_default_tokenizer_inspect(ctx, buf, obj);
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_table_normalizer_inspect(ctx, buf, obj);
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_table_keys_inspect(ctx, buf, obj);
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_table_subrec_inspect(ctx, buf, obj);
+
+ if (obj->header.type == GRN_TABLE_PAT_KEY) {
+ GRN_TEXT_PUTS(ctx, buf, " nodes:");
+ grn_pat_inspect_nodes(ctx, (grn_pat *)obj, buf);
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_db_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_db *db = (grn_db *)obj;
+
+ GRN_TEXT_PUTS(ctx, buf, "#<db");
+
+ GRN_TEXT_PUTS(ctx, buf, " key_type:");
+ grn_table_type_inspect(ctx, buf, db->keys);
+
+ GRN_TEXT_PUTS(ctx, buf, " size:");
+ grn_text_lltoa(ctx, buf, grn_table_size(ctx, obj));
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_time_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *obj)
+{
+ int64_t time_raw;
+ int64_t sec;
+ int32_t usec;
+
+ time_raw = GRN_TIME_VALUE(obj);
+ GRN_TIME_UNPACK(time_raw, sec, usec);
+ grn_text_printf(ctx, buffer,
+ "%" GRN_FMT_INT64D ".%d",
+ sec, usec);
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_geo_point_inspect_point(grn_ctx *ctx, grn_obj *buf, int point)
+{
+ GRN_TEXT_PUTS(ctx, buf, "(");
+ grn_text_itoa(ctx, buf, point / 1000 / 3600 % 3600);
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ grn_text_itoa(ctx, buf, point / 1000 / 60 % 60);
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ grn_text_itoa(ctx, buf, point / 1000 % 60);
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ grn_text_itoa(ctx, buf, point % 1000);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_geo_point_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ int latitude, longitude;
+
+ GRN_GEO_POINT_VALUE(obj, latitude, longitude);
+
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ GRN_TEXT_PUTS(ctx, buf, "(");
+ grn_text_itoa(ctx, buf, latitude);
+ GRN_TEXT_PUTS(ctx, buf, ",");
+ grn_text_itoa(ctx, buf, longitude);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+
+ GRN_TEXT_PUTS(ctx, buf, " (");
+ grn_geo_point_inspect_point(ctx, buf, latitude);
+ GRN_TEXT_PUTS(ctx, buf, ",");
+ grn_geo_point_inspect_point(ctx, buf, longitude);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+
+ {
+ int i, j;
+ grn_geo_point point;
+ uint8_t encoded[sizeof(grn_geo_point)];
+
+ GRN_TEXT_PUTS(ctx, buf, " [");
+ point.latitude = latitude;
+ point.longitude = longitude;
+ grn_gton(encoded, &point, sizeof(grn_geo_point));
+ for (i = 0; (uint) i < sizeof(grn_geo_point); i++) {
+ if (i != 0) {
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ }
+ for (j = 0; j < 8; j++) {
+ grn_text_itoa(ctx, buf, (encoded[i] >> (7 - j)) & 1);
+ }
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_json_load_open_bracket_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ uint32_t i, n;
+
+ n = GRN_UINT32_VALUE(obj);
+
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ for (i = 0; i < n; i++) {
+ grn_obj *value;
+ value = obj + 1 + i;
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ }
+ grn_inspect(ctx, buf, value);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_json_load_open_brace_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ uint32_t i, n;
+
+ n = GRN_UINT32_VALUE(obj);
+
+ GRN_TEXT_PUTS(ctx, buf, "{");
+ for (i = 0; i < n; i += 2) {
+ grn_obj *key, *value;
+ key = obj + 1 + i;
+ value = key + 1;
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ }
+ grn_inspect(ctx, buf, key);
+ GRN_TEXT_PUTS(ctx, buf, ": ");
+ grn_inspect(ctx, buf, value);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "}");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_record_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ grn_obj *table;
+ grn_hash *cols;
+
+ table = grn_ctx_at(ctx, obj->header.domain);
+ GRN_TEXT_PUTS(ctx, buf, "#<record:");
+ if (table) {
+ grn_table_type_inspect(ctx, buf, table);
+ GRN_TEXT_PUTS(ctx, buf, ":");
+ grn_inspect_name(ctx, buf, table);
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(anonymous table:");
+ grn_text_lltoa(ctx, buf, obj->header.domain);
+ GRN_TEXT_PUTS(ctx, buf, ")");
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, " id:");
+ if (GRN_BULK_VSIZE(obj) == 0) {
+ GRN_TEXT_PUTS(ctx, buf, "(no value)");
+ } else {
+ grn_id id;
+
+ id = GRN_RECORD_VALUE(obj);
+ grn_text_lltoa(ctx, buf, id);
+
+ if (table && grn_table_at(ctx, table, id)) {
+ if (table->header.type != GRN_TABLE_NO_KEY) {
+ grn_obj key;
+ GRN_TEXT_PUTS(ctx, buf, " key:");
+ GRN_OBJ_INIT(&key, GRN_BULK, 0, table->header.domain);
+ grn_table_get_key2(ctx, table, id, &key);
+ grn_inspect(ctx, buf, &key);
+ GRN_OBJ_FIN(ctx, &key);
+ }
+ if ((cols = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY))) {
+ if (grn_table_columns(ctx, table, "", 0, (grn_obj *)cols)) {
+ grn_id *key;
+ GRN_HASH_EACH(ctx, cols, column_id, &key, NULL, NULL, {
+ grn_obj *col = grn_ctx_at(ctx, *key);
+ if (col) {
+ grn_obj value;
+ GRN_TEXT_INIT(&value, 0);
+ GRN_TEXT_PUTS(ctx, buf, " ");
+ grn_column_name_(ctx, col, buf);
+ GRN_TEXT_PUTS(ctx, buf, ":");
+ grn_obj_get_value(ctx, col, id, &value);
+ grn_inspect(ctx, buf, &value);
+ GRN_OBJ_FIN(ctx, &value);
+ }
+ });
+ }
+ grn_hash_close(ctx, cols);
+ }
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "(nonexistent)");
+ }
+ }
+
+ GRN_TEXT_PUTS(ctx, buf, ">");
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+grn_uvector_record_inspect(grn_ctx *ctx, grn_obj *buf, grn_obj *obj)
+{
+ unsigned int i, n = 0;
+ grn_obj record;
+
+ GRN_RECORD_INIT(&record, 0, obj->header.domain);
+ GRN_TEXT_PUTS(ctx, buf, "[");
+ n = grn_vector_size(ctx, obj);
+ for (i = 0; i < n; i++) {
+ grn_id id;
+ unsigned int weight;
+
+ if (i > 0) {
+ GRN_TEXT_PUTS(ctx, buf, ", ");
+ }
+
+ id = grn_uvector_get_element(ctx, obj, i, &weight);
+ GRN_TEXT_PUTS(ctx, buf, "#<element record:");
+ GRN_RECORD_SET(ctx, &record, id);
+ grn_inspect(ctx, buf, &record);
+ grn_text_printf(ctx, buf, ", weight:%u>", weight);
+ }
+ GRN_TEXT_PUTS(ctx, buf, "]");
+ GRN_OBJ_FIN(ctx, &record);
+
+ return GRN_SUCCESS;
+}
+
+grn_obj *
+grn_inspect(grn_ctx *ctx, grn_obj *buffer, grn_obj *obj)
+{
+ grn_obj *domain;
+
+ if (!buffer) {
+ buffer = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT);
+ }
+
+ if (!obj) {
+ GRN_TEXT_PUTS(ctx, buffer, "(NULL)");
+ return buffer;
+ }
+
+ switch (obj->header.type) {
+ case GRN_VOID :
+ /* TODO */
+ break;
+ case GRN_BULK :
+ switch (obj->header.domain) {
+ case GRN_DB_TIME :
+ grn_time_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_DB_TOKYO_GEO_POINT :
+ case GRN_DB_WGS84_GEO_POINT :
+ grn_geo_point_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_JSON_LOAD_OPEN_BRACKET :
+ grn_json_load_open_bracket_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_JSON_LOAD_OPEN_BRACE :
+ grn_json_load_open_brace_inspect(ctx, buffer, obj);
+ return buffer;
+ default :
+ domain = grn_ctx_at(ctx, obj->header.domain);
+ if (domain) {
+ grn_id type = domain->header.type;
+ switch (type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ grn_record_inspect(ctx, buffer, obj);
+ return buffer;
+ default :
+ break;
+ }
+ }
+ }
+ break;
+ case GRN_PTR :
+ grn_ptr_inspect(ctx, buffer, obj);
+ break;
+ case GRN_UVECTOR :
+ domain = grn_ctx_at(ctx, obj->header.domain);
+ if (domain) {
+ grn_id type = domain->header.type;
+ switch (type) {
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ grn_uvector_record_inspect(ctx, buffer, obj);
+ return buffer;
+ default :
+ break;
+ }
+ }
+ break;
+ case GRN_PVECTOR :
+ grn_pvector_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_VECTOR :
+ grn_vector_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_MSG :
+ /* TODO */
+ break;
+ case GRN_ACCESSOR :
+ grn_accessor_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_SNIP :
+ case GRN_PATSNIP :
+ /* TODO */
+ break;
+ case GRN_STRING :
+ grn_string_inspect(ctx, buffer, obj);
+ break;
+ case GRN_CURSOR_TABLE_HASH_KEY :
+ /* TODO */
+ break;
+ case GRN_CURSOR_TABLE_PAT_KEY :
+ grn_pat_cursor_inspect(ctx, (grn_pat_cursor *)obj, buffer);
+ return buffer;
+ case GRN_CURSOR_TABLE_DAT_KEY :
+ case GRN_CURSOR_TABLE_NO_KEY :
+ case GRN_CURSOR_COLUMN_INDEX :
+ case GRN_CURSOR_COLUMN_GEO_INDEX :
+ /* TODO */
+ break;
+ case GRN_TYPE :
+ grn_type_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_PROC :
+ grn_proc_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_EXPR :
+ grn_expr_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_TABLE_HASH_KEY :
+ case GRN_TABLE_PAT_KEY :
+ case GRN_TABLE_DAT_KEY :
+ case GRN_TABLE_NO_KEY :
+ grn_table_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_DB :
+ grn_db_inspect(ctx, buffer, obj);
+ break;
+ case GRN_COLUMN_FIX_SIZE :
+ grn_ra_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_COLUMN_VAR_SIZE :
+ grn_ja_inspect(ctx, buffer, obj);
+ return buffer;
+ case GRN_COLUMN_INDEX :
+ grn_ii_inspect(ctx, buffer, obj);
+ return buffer;
+ default :
+ break;
+ }
+
+ grn_text_otoj(ctx, buffer, obj, NULL);
+ return buffer;
+}
+
+grn_obj *
+grn_inspect_indented(grn_ctx *ctx, grn_obj *buffer, grn_obj *obj,
+ const char *indent)
+{
+ grn_obj sub_buffer;
+
+ GRN_TEXT_INIT(&sub_buffer, 0);
+ grn_inspect(ctx, &sub_buffer, obj);
+ {
+ const char *inspected = GRN_TEXT_VALUE(&sub_buffer);
+ size_t inspected_size = GRN_TEXT_LEN(&sub_buffer);
+ size_t i, line_start;
+
+ if (!buffer) {
+ buffer = grn_obj_open(ctx, GRN_BULK, 0, GRN_DB_TEXT);
+ }
+
+ line_start = 0;
+ for (i = 0; i < inspected_size; i++) {
+ if (inspected[i] == '\n') {
+ if (line_start != 0) {
+ GRN_TEXT_PUTS(ctx, buffer, indent);
+ }
+ GRN_TEXT_PUT(ctx, buffer, inspected + line_start, i + 1 - line_start);
+ line_start = i + 1;
+ }
+ }
+ if (line_start != 0) {
+ GRN_TEXT_PUTS(ctx, buffer, indent);
+ }
+ GRN_TEXT_PUT(ctx, buffer,
+ inspected + line_start,
+ inspected_size - line_start);
+ }
+ GRN_OBJ_FIN(ctx, &sub_buffer);
+
+ return buffer;
+}
+
+grn_obj *
+grn_inspect_limited(grn_ctx *ctx, grn_obj *buffer, grn_obj *obj)
+{
+ grn_obj sub_buffer;
+ unsigned int max_size = GRN_CTX_MSGSIZE / 2;
+
+ GRN_TEXT_INIT(&sub_buffer, 0);
+ grn_inspect(ctx, &sub_buffer, obj);
+ if (GRN_TEXT_LEN(&sub_buffer) > max_size) {
+ GRN_TEXT_PUT(ctx, buffer, GRN_TEXT_VALUE(&sub_buffer), max_size);
+ GRN_TEXT_PUTS(ctx, buffer, "...(");
+ grn_text_lltoa(ctx, buffer, GRN_TEXT_LEN(&sub_buffer));
+ GRN_TEXT_PUTS(ctx, buffer, ")");
+ } else {
+ GRN_TEXT_PUT(ctx,
+ buffer,
+ GRN_TEXT_VALUE(&sub_buffer),
+ GRN_TEXT_LEN(&sub_buffer));
+ }
+ GRN_OBJ_FIN(ctx, &sub_buffer);
+
+ return buffer;
+}
+
+void
+grn_p(grn_ctx *ctx, grn_obj *obj)
+{
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_inspect(ctx, &buffer, obj);
+ printf("%.*s\n", (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+}
+
+void
+grn_p_geo_point(grn_ctx *ctx, grn_geo_point *point)
+{
+ grn_obj obj;
+
+ GRN_WGS84_GEO_POINT_INIT(&obj, 0);
+ GRN_GEO_POINT_SET(ctx, &obj, point->latitude, point->longitude);
+ grn_p(ctx, &obj);
+ GRN_OBJ_FIN(ctx, &obj);
+}
+
+void
+grn_p_ii_values(grn_ctx *ctx, grn_obj *ii)
+{
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_ii_inspect_values(ctx, (grn_ii *)ii, &buffer);
+ printf("%.*s\n", (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+}
+
+void
+grn_p_expr_code(grn_ctx *ctx, grn_expr_code *code)
+{
+ grn_obj buffer;
+
+ GRN_TEXT_INIT(&buffer, 0);
+ grn_expr_code_inspect_indented(ctx, &buffer, code, "");
+ printf("%.*s\n", (int)GRN_TEXT_LEN(&buffer), GRN_TEXT_VALUE(&buffer));
+ GRN_OBJ_FIN(ctx, &buffer);
+}
+
+void
+grn_p_record(grn_ctx *ctx, grn_obj *table, grn_id id)
+{
+ grn_obj record;
+
+ GRN_RECORD_INIT(&record, 0, grn_obj_id(ctx, table));
+ GRN_RECORD_SET(ctx, &record, id);
+ grn_p(ctx, &record);
+ GRN_OBJ_FIN(ctx, &record);
+}
+
+#ifdef WIN32
+int
+grn_mkstemp(char *path_template)
+{
+ errno_t error;
+ size_t path_template_size;
+ int fd;
+
+ path_template_size = strlen(path_template) + 1;
+ error = _mktemp_s(path_template, path_template_size);
+ if (error != 0) {
+ return -1;
+ }
+
+ error = _sopen_s(&fd,
+ path_template,
+ _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
+ _SH_DENYNO,
+ _S_IREAD | _S_IWRITE);
+ if (error != 0) {
+ return -1;
+ }
+
+ return fd;
+}
+#else /* WIN32 */
+int
+grn_mkstemp(char *path_template)
+{
+# ifdef HAVE_MKSTEMP
+ return mkstemp(path_template);
+# else /* HAVE_MKSTEMP */
+ mktemp(path_template);
+ return open(path_template, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
+# endif /* HAVE_MKSTEMP */
+}
+#endif /* WIN32 */
+
+grn_bool
+grn_path_exist(const char *path)
+{
+ struct stat status;
+ return stat(path, &status) == 0;
+}
+
+/* todo : refine */
+/*
+ * grn_tokenize splits a string into at most buf_size tokens and
+ * returns the number of tokens. The ending address of each token is
+ * written into tokbuf. Delimiters are ' ' and ','.
+ * Then, the address to the remaining is set to rest.
+ */
+int
+grn_tokenize(const char *str, size_t str_len,
+ const char **tokbuf, int buf_size,
+ const char **rest)
+{
+ const char **tok = tokbuf, **tok_end = tokbuf + buf_size;
+ if (buf_size > 0) {
+ const char *str_end = str + str_len;
+ while (str < str_end && (' ' == *str || ',' == *str)) { str++; }
+ for (;;) {
+ if (str == str_end) {
+ *tok++ = str;
+ break;
+ }
+ if (' ' == *str || ',' == *str) {
+ /* *str = '\0'; */
+ *tok++ = str;
+ if (tok == tok_end) { break; }
+ do { str++; } while (str < str_end && (' ' == *str || ',' == *str));
+ } else {
+ str++;
+ }
+ }
+ }
+ if (rest) { *rest = str; }
+ return tok - tokbuf;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/window_function.c b/storage/mroonga/vendor/groonga/lib/window_function.c
new file mode 100644
index 00000000..81aba8da
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/window_function.c
@@ -0,0 +1,464 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_ctx.h"
+#include "grn_db.h"
+#include "grn_expr.h"
+#include "grn_window_function.h"
+
+#include <string.h>
+
+grn_rc
+grn_window_init(grn_ctx *ctx,
+ grn_window *window,
+ grn_obj *table,
+ grn_bool is_sorted)
+{
+ GRN_API_ENTER;
+
+ window->table = table;
+ GRN_RECORD_INIT(&(window->ids), GRN_OBJ_VECTOR, grn_obj_id(ctx, table));
+ window->n_ids = 0;
+ window->current_index = 0;
+ window->direction = GRN_WINDOW_DIRECTION_ASCENDING;
+ window->is_sorted = is_sorted;
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_rc
+grn_window_fin(grn_ctx *ctx, grn_window *window)
+{
+ GRN_API_ENTER;
+
+ GRN_OBJ_FIN(ctx, &(window->ids));
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_id
+grn_window_next(grn_ctx *ctx, grn_window *window)
+{
+ grn_id next_id;
+
+ GRN_API_ENTER;
+
+ if (!window) {
+ GRN_API_RETURN(GRN_ID_NIL);
+ }
+
+ if (window->direction == GRN_WINDOW_DIRECTION_ASCENDING) {
+ if ((unsigned long) window->current_index >= window->n_ids) {
+ GRN_API_RETURN(GRN_ID_NIL);
+ }
+ } else {
+ if (window->current_index < 0) {
+ GRN_API_RETURN(GRN_ID_NIL);
+ }
+ }
+
+ next_id = GRN_RECORD_VALUE_AT(&(window->ids), window->current_index);
+ if (window->direction == GRN_WINDOW_DIRECTION_ASCENDING) {
+ window->current_index++;
+ } else {
+ window->current_index--;
+ }
+
+ GRN_API_RETURN(next_id);
+}
+
+grn_rc
+grn_window_rewind(grn_ctx *ctx, grn_window *window)
+{
+ GRN_API_ENTER;
+
+ if (!window) {
+ ERR(GRN_INVALID_ARGUMENT, "[window][rewind] window is NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (window->direction == GRN_WINDOW_DIRECTION_ASCENDING) {
+ window->current_index = 0;
+ } else {
+ window->current_index = window->n_ids - 1;
+ }
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+grn_obj *
+grn_window_get_table(grn_ctx *ctx, grn_window *window)
+{
+ GRN_API_ENTER;
+
+ if (!window) {
+ ERR(GRN_INVALID_ARGUMENT, "[window][rewind] window is NULL");
+ GRN_API_RETURN(NULL);
+ }
+
+ GRN_API_RETURN(window->table);
+}
+
+grn_rc
+grn_window_set_direction(grn_ctx *ctx,
+ grn_window *window,
+ grn_window_direction direction)
+{
+ GRN_API_ENTER;
+
+ if (!window) {
+ ERR(GRN_INVALID_ARGUMENT, "[window][set][direction] window is NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ switch (direction) {
+ case GRN_WINDOW_DIRECTION_ASCENDING :
+ window->direction = direction;
+ window->current_index = 0;
+ break;
+ case GRN_WINDOW_DIRECTION_DESCENDING :
+ window->direction = direction;
+ window->current_index = window->n_ids - 1;
+ break;
+ default :
+ ERR(GRN_INVALID_ARGUMENT,
+ "[window][set][direction] direction must be "
+ "GRN_WINDOW_DIRECTION_ASCENDING(%d) or "
+ "GRN_WINDOW_DIRECTION_DESCENDING(%d): %d",
+ GRN_WINDOW_DIRECTION_ASCENDING,
+ GRN_WINDOW_DIRECTION_DESCENDING,
+ direction);
+ GRN_API_RETURN(ctx->rc);
+ break;
+ }
+
+ GRN_API_RETURN(GRN_SUCCESS);
+}
+
+static inline void
+grn_window_reset(grn_ctx *ctx,
+ grn_window *window)
+{
+ GRN_BULK_REWIND(&(window->ids));
+}
+
+static inline void
+grn_window_add_record(grn_ctx *ctx,
+ grn_window *window,
+ grn_id record_id)
+{
+ GRN_RECORD_PUT(ctx, &(window->ids), record_id);
+}
+
+static inline grn_bool
+grn_window_is_empty(grn_ctx *ctx,
+ grn_window *window)
+{
+ return GRN_BULK_VSIZE(&(window->ids)) == 0;
+}
+
+grn_bool
+grn_window_is_sorted(grn_ctx *ctx, grn_window *window)
+{
+ GRN_API_ENTER;
+
+ if (!window) {
+ ERR(GRN_INVALID_ARGUMENT, "[window][is-sorted] window is NULL");
+ GRN_API_RETURN(GRN_FALSE);
+ }
+
+ GRN_API_RETURN(window->is_sorted);
+}
+
+size_t
+grn_window_get_size(grn_ctx *ctx,
+ grn_window *window)
+{
+ GRN_API_ENTER;
+
+ GRN_API_RETURN(window->n_ids);
+}
+
+grn_obj *
+grn_window_function_create(grn_ctx *ctx,
+ const char *name,
+ int name_size,
+ grn_window_function_func func)
+{
+ grn_obj *window_function = NULL;
+
+ GRN_API_ENTER;
+
+ if (name_size == -1) {
+ name_size = strlen(name);
+ }
+
+ window_function = grn_proc_create(ctx,
+ name,
+ name_size,
+ GRN_PROC_WINDOW_FUNCTION,
+ NULL, NULL, NULL, 0, NULL);
+ if (!window_function) {
+ ERR(GRN_WINDOW_FUNCTION_ERROR,
+ "[window-function][%.*s] failed to create proc: %s",
+ name_size, name,
+ ctx->errbuf);
+ GRN_API_RETURN(NULL);
+ }
+
+ {
+ grn_proc *proc = (grn_proc *)window_function;
+ proc->callbacks.window_function = func;
+ }
+
+ GRN_API_RETURN(window_function);
+}
+
+static grn_bool
+grn_expr_is_window_function_call(grn_ctx *ctx,
+ grn_obj *window_function_call)
+{
+ grn_expr *expr = (grn_expr *)window_function_call;
+ grn_expr_code *func;
+ grn_expr_code *call;
+
+ func = &(expr->codes[0]);
+ call = &(expr->codes[expr->codes_curr - 1]);
+
+ if (func->op != GRN_OP_PUSH) {
+ return GRN_FALSE;
+ }
+ if (!grn_obj_is_window_function_proc(ctx, func->value)) {
+ return GRN_FALSE;
+ }
+
+ if (call->op != GRN_OP_CALL) {
+ return GRN_FALSE;
+ }
+ if ((unsigned int) call->nargs != (expr->codes_curr - 1)) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_rc
+grn_expr_call_window_function(grn_ctx *ctx,
+ grn_obj *output_column,
+ grn_window *window,
+ grn_obj *window_function_call)
+{
+ grn_rc rc;
+ grn_expr *expr = (grn_expr *)window_function_call;
+ grn_proc *proc;
+ int32_t i, n;
+ grn_obj args;
+
+ proc = (grn_proc *)(expr->codes[0].value);
+
+ GRN_PTR_INIT(&args, GRN_OBJ_VECTOR, GRN_ID_NIL);
+ n = expr->codes_curr - 1;
+ for (i = 1; i < n; i++) {
+ /* TODO: Check op. */
+ GRN_PTR_PUT(ctx, &args, expr->codes[i].value);
+ }
+ window->n_ids = GRN_BULK_VSIZE(&(window->ids)) / sizeof(grn_id);
+ if (window->direction == GRN_WINDOW_DIRECTION_ASCENDING) {
+ window->current_index = 0;
+ } else {
+ window->current_index = window->n_ids - 1;
+ }
+ rc = proc->callbacks.window_function(ctx,
+ output_column,
+ window,
+ (grn_obj **)GRN_BULK_HEAD(&args),
+ GRN_BULK_VSIZE(&args) / sizeof(grn_obj *));
+ GRN_OBJ_FIN(ctx, &args);
+
+ return rc;
+}
+
+grn_rc
+grn_table_apply_window_function(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *output_column,
+ grn_window_definition *definition,
+ grn_obj *window_function_call)
+{
+ GRN_API_ENTER;
+
+ if (!table) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][apply][window-function] table is NULL");
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ if (!grn_expr_is_window_function_call(ctx, window_function_call)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, window_function_call);
+ ERR(GRN_INVALID_ARGUMENT,
+ "[table][apply][window-function] must be window function call: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ GRN_API_RETURN(ctx->rc);
+ }
+
+ {
+ size_t n_sort_keys;
+ grn_table_sort_key *sort_keys;
+ grn_obj *sorted;
+ grn_window window;
+
+ n_sort_keys = definition->n_group_keys + definition->n_sort_keys;
+ sort_keys = GRN_MALLOCN(grn_table_sort_key, n_sort_keys);
+ if (!sort_keys) {
+ grn_rc rc = ctx->rc;
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+ ERR(rc,
+ "[table][apply][window-function] "
+ "failed to allocate internal sort keys: %s",
+ ctx->errbuf);
+ GRN_API_RETURN(ctx->rc);
+ }
+ {
+ size_t i;
+ for (i = 0; i < definition->n_group_keys; i++) {
+ sort_keys[i] = definition->group_keys[i];
+ }
+ for (i = 0; i < definition->n_sort_keys; i++) {
+ sort_keys[i + definition->n_group_keys] = definition->sort_keys[i];
+ }
+ }
+ sorted = grn_table_create(ctx,
+ NULL, 0, NULL,
+ GRN_OBJ_TABLE_NO_KEY,
+ NULL,
+ table);
+ if (!sorted) {
+ grn_rc rc = ctx->rc;
+ if (rc == GRN_SUCCESS) {
+ rc = GRN_NO_MEMORY_AVAILABLE;
+ }
+ GRN_FREE(sort_keys);
+ ERR(rc,
+ "[table][apply][window-function] "
+ "failed to allocate table to store sorted result: %s",
+ ctx->errbuf);
+ GRN_API_RETURN(ctx->rc);
+ }
+ grn_table_sort(ctx,
+ table,
+ 0, -1,
+ sorted,
+ sort_keys, n_sort_keys);
+
+ grn_window_init(ctx, &window, table, definition->n_sort_keys > 0);
+ if (definition->n_group_keys > 0) {
+ grn_obj *previous_values;
+ grn_obj *current_values;
+ size_t i, n;
+
+ previous_values = GRN_MALLOCN(grn_obj, definition->n_group_keys);
+ current_values = GRN_MALLOCN(grn_obj, definition->n_group_keys);
+ n = definition->n_group_keys;
+
+ for (i = 0; i < n; i++) {
+ GRN_VOID_INIT(&(previous_values[i]));
+ GRN_VOID_INIT(&(current_values[i]));
+ }
+
+ GRN_TABLE_EACH_BEGIN(ctx, sorted, cursor, id) {
+ void *value;
+ grn_id record_id;
+ grn_bool is_group_key_changed = GRN_FALSE;
+
+ grn_table_cursor_get_value(ctx, cursor, &value);
+ record_id = *((grn_id *)value);
+
+ for (i = 0; i < n; i++) {
+ size_t reverse_i = n - i - 1;
+ grn_obj *previous_value = &(previous_values[reverse_i]);
+ grn_obj *current_value = &(current_values[reverse_i]);
+ grn_obj *group_key = definition->group_keys[reverse_i].key;
+
+ if (is_group_key_changed) {
+ GRN_BULK_REWIND(previous_value);
+ grn_obj_get_value(ctx, group_key, record_id, previous_value);
+ } else {
+ GRN_BULK_REWIND(current_value);
+ grn_obj_get_value(ctx, group_key, record_id, current_value);
+ if ((GRN_BULK_VSIZE(current_value) !=
+ GRN_BULK_VSIZE(previous_value)) ||
+ (memcmp(GRN_BULK_HEAD(current_value),
+ GRN_BULK_HEAD(previous_value),
+ GRN_BULK_VSIZE(current_value)) != 0)) {
+ is_group_key_changed = GRN_TRUE;
+ grn_bulk_write_from(ctx,
+ previous_value,
+ GRN_BULK_HEAD(current_value),
+ 0,
+ GRN_BULK_VSIZE(current_value));
+ }
+ }
+ }
+
+ if (is_group_key_changed && !grn_window_is_empty(ctx, &window)) {
+ grn_expr_call_window_function(ctx,
+ output_column,
+ &window,
+ window_function_call);
+ grn_window_reset(ctx, &window);
+ }
+ grn_window_add_record(ctx, &window, record_id);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_expr_call_window_function(ctx,
+ output_column,
+ &window,
+ window_function_call);
+
+ for (i = 0; i < definition->n_group_keys; i++) {
+ GRN_OBJ_FIN(ctx, &(previous_values[i]));
+ GRN_OBJ_FIN(ctx, &(current_values[i]));
+ }
+ GRN_FREE(previous_values);
+ GRN_FREE(current_values);
+ } else {
+ GRN_TABLE_EACH_BEGIN(ctx, sorted, cursor, id) {
+ void *value;
+ grn_id record_id;
+
+ grn_table_cursor_get_value(ctx, cursor, &value);
+ record_id = *((grn_id *)value);
+ grn_window_add_record(ctx, &window, record_id);
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_expr_call_window_function(ctx,
+ output_column,
+ &window,
+ window_function_call);
+ }
+ grn_window_fin(ctx, &window);
+
+ GRN_FREE(sort_keys);
+ }
+
+ GRN_API_RETURN(ctx->rc);
+}
diff --git a/storage/mroonga/vendor/groonga/lib/window_functions.c b/storage/mroonga/vendor/groonga/lib/window_functions.c
new file mode 100644
index 00000000..7a177cd8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/window_functions.c
@@ -0,0 +1,405 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_db.h"
+#include "grn_window_functions.h"
+
+static grn_rc
+window_record_number(grn_ctx *ctx,
+ grn_obj *output_column,
+ grn_window *window,
+ grn_obj **args,
+ int n_args)
+{
+ grn_id id;
+ uint32_t nth_record = 1;
+ grn_obj value;
+
+ GRN_UINT32_INIT(&value, 0);
+ while ((id = grn_window_next(ctx, window))) {
+ GRN_UINT32_SET(ctx, &value, nth_record);
+ grn_obj_set_value(ctx, output_column, id, &value, GRN_OBJ_SET);
+ nth_record++;
+ }
+ GRN_OBJ_FIN(ctx, &value);
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+window_sum(grn_ctx *ctx,
+ grn_obj *output_column,
+ grn_window *window,
+ grn_obj **args,
+ int n_args)
+{
+ grn_id id;
+ grn_obj *target;
+
+ if (n_args != 1) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "window_sum(): wrong number of arguments (%d for 1)",
+ n_args);
+ return ctx->rc;
+ }
+
+ target = args[0];
+ if (target->header.type != GRN_ACCESSOR) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, target);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "window_sum(): "
+ "the target column must be accessor: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+
+ {
+ const grn_id output_column_range_id = grn_obj_get_range(ctx, output_column);
+ const grn_id target_range_id = grn_obj_get_range(ctx, target);
+ grn_obj sum;
+ grn_obj value;
+
+ switch (target_range_id) {
+ case GRN_DB_INT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_INT64 :
+ case GRN_DB_UINT8 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ case GRN_DB_FLOAT :
+ break;
+ default :
+ {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, target);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "window_sum(): "
+ "the target column must be number column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+ break;
+ }
+
+ switch (output_column_range_id) {
+ case GRN_DB_INT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_INT64 :
+ GRN_INT64_INIT(&sum, 0);
+ break;
+ case GRN_DB_UINT8 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ GRN_UINT64_INIT(&sum, 0);
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_INIT(&sum, 0);
+ break;
+ default :
+ {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, output_column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "window_sum(): "
+ "the output column must be number column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+ break;
+ }
+ GRN_VOID_INIT(&value);
+
+ if (grn_window_is_sorted(ctx, window)) {
+ while ((id = grn_window_next(ctx, window))) {
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, target, id, &value);
+ switch (target_range_id) {
+ case GRN_DB_INT8 :
+ GRN_INT64_SET(ctx,
+ &sum,
+ GRN_INT64_VALUE(&sum) + GRN_INT8_VALUE(&value));
+ break;
+ case GRN_DB_INT16 :
+ GRN_INT64_SET(ctx,
+ &sum,
+ GRN_INT64_VALUE(&sum) + GRN_INT16_VALUE(&value));
+ break;
+ case GRN_DB_INT32 :
+ GRN_INT64_SET(ctx,
+ &sum,
+ GRN_INT64_VALUE(&sum) + GRN_INT32_VALUE(&value));
+ break;
+ case GRN_DB_INT64 :
+ GRN_INT64_SET(ctx,
+ &sum,
+ GRN_INT64_VALUE(&sum) + GRN_INT64_VALUE(&value));
+ break;
+ case GRN_DB_UINT8 :
+ GRN_UINT64_SET(ctx,
+ &sum,
+ GRN_UINT64_VALUE(&sum) + GRN_UINT8_VALUE(&value));
+ break;
+ case GRN_DB_UINT16 :
+ GRN_UINT64_SET(ctx,
+ &sum,
+ GRN_UINT64_VALUE(&sum) + GRN_UINT16_VALUE(&value));
+ break;
+ case GRN_DB_UINT32 :
+ GRN_UINT64_SET(ctx,
+ &sum,
+ GRN_UINT64_VALUE(&sum) + GRN_UINT32_VALUE(&value));
+ break;
+ case GRN_DB_UINT64 :
+ GRN_UINT64_SET(ctx,
+ &sum,
+ GRN_UINT64_VALUE(&sum) + GRN_UINT64_VALUE(&value));
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_SET(ctx,
+ &sum,
+ GRN_FLOAT_VALUE(&sum) + GRN_FLOAT_VALUE(&value));
+ break;
+ default :
+ break;
+ }
+ grn_obj_set_value(ctx, output_column, id, &sum, GRN_OBJ_SET);
+ }
+ } else {
+ int64_t sum_raw_int64 = 0;
+ uint64_t sum_raw_uint64 = 0;
+ double sum_raw_double = 0.0;
+
+ while ((id = grn_window_next(ctx, window))) {
+ GRN_BULK_REWIND(&value);
+ grn_obj_get_value(ctx, target, id, &value);
+ switch (target_range_id) {
+ case GRN_DB_INT8 :
+ sum_raw_int64 += GRN_INT8_VALUE(&value);
+ break;
+ case GRN_DB_INT16 :
+ sum_raw_int64 += GRN_INT16_VALUE(&value);
+ break;
+ case GRN_DB_INT32 :
+ sum_raw_int64 += GRN_INT32_VALUE(&value);
+ break;
+ case GRN_DB_INT64 :
+ sum_raw_int64 += GRN_INT64_VALUE(&value);
+ break;
+ case GRN_DB_UINT8 :
+ sum_raw_uint64 += GRN_UINT8_VALUE(&value);
+ break;
+ case GRN_DB_UINT16 :
+ sum_raw_uint64 += GRN_UINT16_VALUE(&value);
+ break;
+ case GRN_DB_UINT32 :
+ sum_raw_uint64 += GRN_UINT32_VALUE(&value);
+ break;
+ case GRN_DB_UINT64 :
+ sum_raw_uint64 += GRN_UINT64_VALUE(&value);
+ break;
+ case GRN_DB_FLOAT :
+ sum_raw_double += GRN_FLOAT_VALUE(&value);
+ break;
+ default :
+ break;
+ }
+ }
+
+ switch (output_column_range_id) {
+ case GRN_DB_INT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_INT64 :
+ GRN_INT64_SET(ctx, &sum, sum_raw_int64);
+ break;
+ case GRN_DB_UINT8 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ GRN_UINT64_SET(ctx, &sum, sum_raw_uint64);
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_SET(ctx, &sum, sum_raw_double);
+ break;
+ }
+
+ grn_window_rewind(ctx, window);
+ while ((id = grn_window_next(ctx, window))) {
+ grn_obj_set_value(ctx, output_column, id, &sum, GRN_OBJ_SET);
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &value);
+ GRN_OBJ_FIN(ctx, &sum);
+ }
+
+ return GRN_SUCCESS;
+}
+
+static grn_rc
+window_count(grn_ctx *ctx,
+ grn_obj *output_column,
+ grn_window *window,
+ grn_obj **args,
+ int n_args)
+{
+ grn_id id;
+ grn_id output_column_range_id;
+ grn_obj n_records;
+ uint32_t n_records_raw = 0;
+
+
+ if (n_args != 0) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "window_count(): wrong number of arguments (%d for 0)",
+ n_args);
+ return ctx->rc;
+ }
+
+ output_column_range_id = grn_obj_get_range(ctx, output_column);
+ switch (output_column_range_id) {
+ case GRN_DB_INT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_INT64 :
+ GRN_INT64_INIT(&n_records, 0);
+ break;
+ case GRN_DB_UINT8 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ GRN_UINT64_INIT(&n_records, 0);
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_INIT(&n_records, 0);
+ break;
+ default :
+ {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, output_column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "window_count(): "
+ "the output column must be number column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return ctx->rc;
+ }
+ break;
+ }
+
+ if (grn_window_is_sorted(ctx, window)) {
+ while ((id = grn_window_next(ctx, window))) {
+ n_records_raw++;
+ switch (output_column_range_id) {
+ case GRN_DB_INT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_INT64 :
+ GRN_INT64_SET(ctx, &n_records, n_records_raw);
+ break;
+ case GRN_DB_UINT8 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ GRN_UINT64_SET(ctx, &n_records, n_records_raw);
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_SET(ctx, &n_records, n_records_raw);
+ break;
+ default :
+ break;
+ }
+ grn_obj_set_value(ctx, output_column, id, &n_records, GRN_OBJ_SET);
+ }
+ } else {
+ while ((id = grn_window_next(ctx, window))) {
+ n_records_raw++;
+ }
+
+ switch (output_column_range_id) {
+ case GRN_DB_INT8 :
+ case GRN_DB_INT16 :
+ case GRN_DB_INT32 :
+ case GRN_DB_INT64 :
+ GRN_INT64_SET(ctx, &n_records, n_records_raw);
+ break;
+ case GRN_DB_UINT8 :
+ case GRN_DB_UINT16 :
+ case GRN_DB_UINT32 :
+ case GRN_DB_UINT64 :
+ GRN_UINT64_SET(ctx, &n_records, n_records_raw);
+ break;
+ case GRN_DB_FLOAT :
+ GRN_FLOAT_SET(ctx, &n_records, n_records_raw);
+ break;
+ }
+
+ grn_window_rewind(ctx, window);
+ while ((id = grn_window_next(ctx, window))) {
+ grn_obj_set_value(ctx, output_column, id, &n_records, GRN_OBJ_SET);
+ }
+ }
+
+ GRN_OBJ_FIN(ctx, &n_records);
+
+ return GRN_SUCCESS;
+}
+
+grn_rc
+grn_db_init_builtin_window_functions(grn_ctx *ctx)
+{
+ /* For backward compatibility. */
+ grn_window_function_create(ctx,
+ "record_number", -1,
+ window_record_number);
+ grn_window_function_create(ctx,
+ "window_record_number", -1,
+ window_record_number);
+
+ grn_window_function_create(ctx,
+ "window_sum", -1,
+ window_sum);
+
+ grn_window_function_create(ctx,
+ "window_count", -1,
+ window_count);
+
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/lib/windows.c b/storage/mroonga/vendor/groonga/lib/windows.c
new file mode 100644
index 00000000..a363d711
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/windows.c
@@ -0,0 +1,104 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn.h"
+#include "grn_windows.h"
+
+#ifdef WIN32
+static char *windows_base_dir = NULL;
+const char *
+grn_windows_base_dir(void)
+{
+ if (!windows_base_dir) {
+ HMODULE dll;
+ const wchar_t *dll_filename = GRN_DLL_FILENAME;
+ wchar_t absolute_dll_filename[MAX_PATH];
+ DWORD absolute_dll_filename_size;
+ dll = GetModuleHandleW(dll_filename);
+ absolute_dll_filename_size = GetModuleFileNameW(dll,
+ absolute_dll_filename,
+ MAX_PATH);
+ if (absolute_dll_filename_size == 0) {
+ windows_base_dir = grn_strdup_raw(".");
+ } else {
+ DWORD ansi_dll_filename_size;
+ ansi_dll_filename_size =
+ WideCharToMultiByte(CP_ACP, 0,
+ absolute_dll_filename, absolute_dll_filename_size,
+ NULL, 0, NULL, NULL);
+ if (ansi_dll_filename_size == 0) {
+ windows_base_dir = grn_strdup_raw(".");
+ } else {
+ char *path;
+ windows_base_dir = malloc(ansi_dll_filename_size + 1);
+ WideCharToMultiByte(CP_ACP, 0,
+ absolute_dll_filename, absolute_dll_filename_size,
+ windows_base_dir, ansi_dll_filename_size,
+ NULL, NULL);
+ windows_base_dir[ansi_dll_filename_size] = '\0';
+ if ((path = strrchr(windows_base_dir, '\\'))) {
+ *path = '\0';
+ }
+ path = strrchr(windows_base_dir, '\\');
+ if (path && (grn_strcasecmp(path + 1, "bin") == 0 ||
+ grn_strcasecmp(path + 1, "lib") == 0)) {
+ *path = '\0';
+ } else {
+ path = windows_base_dir + strlen(windows_base_dir);
+ *path = '\0';
+ }
+ for (path = windows_base_dir; *path; path++) {
+ if (*path == '\\') {
+ *path = '/';
+ }
+ }
+ }
+ }
+ }
+ return windows_base_dir;
+}
+
+UINT
+grn_windows_encoding_to_code_page(grn_encoding encoding)
+{
+ UINT code_page;
+
+ switch (encoding) {
+ case GRN_ENC_EUC_JP :
+ code_page = 20932;
+ break;
+ case GRN_ENC_UTF8 :
+ code_page = CP_UTF8;
+ break;
+ case GRN_ENC_SJIS :
+ code_page = 932;
+ break;
+ case GRN_ENC_LATIN1 :
+ code_page = 1252;
+ break;
+ case GRN_ENC_KOI8R :
+ code_page = 20866;
+ break;
+ default :
+ code_page = CP_ACP;
+ break;
+ }
+
+ return code_page;
+}
+#endif /* WIN32 */
diff --git a/storage/mroonga/vendor/groonga/lib/windows_event_logger.c b/storage/mroonga/vendor/groonga/lib/windows_event_logger.c
new file mode 100644
index 00000000..fb8229ad
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/lib/windows_event_logger.c
@@ -0,0 +1,203 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include "grn_logger.h"
+#include "grn_ctx.h"
+#include "grn_windows.h"
+
+#include <string.h>
+
+#ifdef WIN32
+
+typedef struct _grn_windows_event_logger_data {
+ char *event_source_name;
+ HANDLE event_source;
+} grn_windows_event_logger_data;
+
+static void
+windows_event_logger_log(grn_ctx *ctx, grn_log_level level,
+ const char *timestamp, const char *title,
+ const char *message, const char *location,
+ void *user_data)
+{
+ grn_windows_event_logger_data *data = user_data;
+ WORD type;
+ WORD category = 0;
+ DWORD event_id = 0;
+ PSID user_sid = NULL;
+ WORD n_strings = 1;
+ DWORD event_data_size = 0;
+ const WCHAR *strings[1];
+ LPVOID event_data = NULL;
+ const char level_marks[] = " EACewnid-";
+ grn_obj formatted_buffer;
+ UINT code_page;
+ DWORD convert_flags = 0;
+ int n_converted_chars;
+
+ switch (level) {
+ case GRN_LOG_NONE :
+ return;
+ break;
+ case GRN_LOG_EMERG :
+ case GRN_LOG_ALERT :
+ case GRN_LOG_CRIT :
+ case GRN_LOG_ERROR :
+ type = EVENTLOG_ERROR_TYPE;
+ break;
+ case GRN_LOG_WARNING :
+ type = EVENTLOG_WARNING_TYPE;
+ break;
+ case GRN_LOG_NOTICE :
+ case GRN_LOG_INFO :
+ case GRN_LOG_DEBUG :
+ case GRN_LOG_DUMP :
+ type = EVENTLOG_INFORMATION_TYPE;
+ break;
+ default :
+ type = EVENTLOG_ERROR_TYPE;
+ break;
+ }
+
+ if (data->event_source == INVALID_HANDLE_VALUE) {
+ data->event_source = RegisterEventSourceA(NULL, data->event_source_name);
+ if (data->event_source == INVALID_HANDLE_VALUE) {
+ return;
+ }
+ }
+
+ GRN_TEXT_INIT(&formatted_buffer, 0);
+ if (location && location[0]) {
+ grn_text_printf(ctx, &formatted_buffer, "%s|%c|%s %s %s",
+ timestamp, level_marks[level], title, message, location);
+ } else {
+ grn_text_printf(ctx, &formatted_buffer, "%s|%c|%s %s",
+ timestamp, level_marks[level], title, message);
+ }
+
+ code_page = grn_windows_encoding_to_code_page(ctx->encoding);
+
+ n_converted_chars = MultiByteToWideChar(code_page,
+ convert_flags,
+ GRN_TEXT_VALUE(&formatted_buffer),
+ GRN_TEXT_LEN(&formatted_buffer),
+ NULL,
+ 0);
+#define CONVERTED_BUFFER_SIZE 512
+ if (n_converted_chars < CONVERTED_BUFFER_SIZE) {
+ WCHAR converted_buffer[CONVERTED_BUFFER_SIZE];
+ n_converted_chars = MultiByteToWideChar(code_page,
+ convert_flags,
+ GRN_TEXT_VALUE(&formatted_buffer),
+ GRN_TEXT_LEN(&formatted_buffer),
+ converted_buffer,
+ CONVERTED_BUFFER_SIZE);
+ converted_buffer[n_converted_chars] = L'\0';
+ strings[0] = converted_buffer;
+ ReportEventW(data->event_source, type, category, event_id, user_sid,
+ n_strings, event_data_size,
+ strings, event_data);
+#undef CONVERTED_BUFFER_SIZE
+ } else {
+ WCHAR *converted;
+ converted = GRN_MALLOCN(WCHAR, n_converted_chars);
+ n_converted_chars = MultiByteToWideChar(code_page,
+ convert_flags,
+ GRN_TEXT_VALUE(&formatted_buffer),
+ GRN_TEXT_LEN(&formatted_buffer),
+ converted,
+ n_converted_chars);
+ converted[n_converted_chars] = L'\0';
+ strings[0] = converted;
+ ReportEventW(data->event_source, type, category, event_id, user_sid,
+ n_strings, event_data_size,
+ strings, event_data);
+ GRN_FREE(converted);
+ }
+ GRN_OBJ_FIN(ctx, &formatted_buffer);
+}
+
+static void
+windows_event_logger_reopen(grn_ctx *ctx, void *user_data)
+{
+}
+
+static void
+windows_event_logger_fin(grn_ctx *ctx, void *user_data)
+{
+ grn_windows_event_logger_data *data = user_data;
+
+ free(data->event_source_name);
+ if (data->event_source != INVALID_HANDLE_VALUE) {
+ DeregisterEventSource(data->event_source);
+ }
+ free(data);
+}
+#endif /* WIN32 */
+
+grn_rc
+grn_windows_event_logger_set(grn_ctx *ctx, const char *event_source_name)
+{
+#ifdef WIN32
+ grn_rc rc;
+ grn_logger windows_event_logger;
+ grn_windows_event_logger_data *data;
+
+ if (ctx) {
+ GRN_API_ENTER;
+ }
+
+ data = malloc(sizeof(grn_windows_event_logger_data));
+ if (!data) {
+ if (ctx) {
+ ERR(GRN_NO_MEMORY_AVAILABLE,
+ "failed to allocate user data for Windows event logger");
+ GRN_API_RETURN(ctx->rc);
+ } else {
+ return GRN_NO_MEMORY_AVAILABLE;
+ }
+ }
+
+ if (event_source_name) {
+ data->event_source_name = grn_strdup_raw(event_source_name);
+ } else {
+ data->event_source_name = grn_strdup_raw("libgroonga");
+ }
+ data->event_source = INVALID_HANDLE_VALUE;
+
+ windows_event_logger.max_level = GRN_LOG_DEFAULT_LEVEL;
+ windows_event_logger.flags = GRN_LOG_TIME | GRN_LOG_MESSAGE;
+ windows_event_logger.user_data = data;
+ windows_event_logger.log = windows_event_logger_log;
+ windows_event_logger.reopen = windows_event_logger_reopen;
+ windows_event_logger.fin = windows_event_logger_fin;
+
+ rc = grn_logger_set(ctx, &windows_event_logger);
+ if (rc != GRN_SUCCESS) {
+ windows_event_logger.fin(ctx, windows_event_logger.user_data);
+ }
+
+ if (ctx) {
+ GRN_API_RETURN(rc);
+ } else {
+ return rc;
+ }
+#else /* WIN32 */
+ return GRN_FUNCTION_NOT_IMPLEMENTED;
+#endif /* WIN32 */
+}
diff --git a/storage/mroonga/vendor/groonga/nginx_version b/storage/mroonga/vendor/groonga/nginx_version
new file mode 100644
index 00000000..43ded906
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/nginx_version
@@ -0,0 +1 @@
+1.13.5
diff --git a/storage/mroonga/vendor/groonga/plugins/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/CMakeLists.txt
new file mode 100644
index 00000000..d7a5f22e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/CMakeLists.txt
@@ -0,0 +1,30 @@
+# Copyright(C) 2012-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+add_subdirectory(suggest)
+add_subdirectory(tokenizers)
+add_subdirectory(query_expanders)
+add_subdirectory(ruby)
+add_subdirectory(token_filters)
+add_subdirectory(sharding)
+add_subdirectory(functions)
+
+if(NOT GRN_EMBED)
+ if(GRN_WITH_MRUBY)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/ruby_scripts.am RUBY_SCRIPTS)
+ install(FILES ${RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_PLUGINS_DIR}")
+ endif()
+endif()
diff --git a/storage/mroonga/vendor/groonga/plugins/Makefile.am b/storage/mroonga/vendor/groonga/plugins/Makefile.am
new file mode 100644
index 00000000..6c98a0cc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/Makefile.am
@@ -0,0 +1,19 @@
+SUBDIRS = \
+ tokenizers \
+ suggest \
+ query_expanders \
+ ruby \
+ token_filters \
+ sharding \
+ functions \
+ expression_rewriters
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+if WITH_MRUBY
+dist_plugins_DATA = \
+ $(ruby_scripts)
+endif
+
+include ruby_scripts.am
diff --git a/storage/mroonga/vendor/groonga/plugins/expression_rewriters/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/CMakeLists.txt
new file mode 100644
index 00000000..aabec442
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/CMakeLists.txt
@@ -0,0 +1,26 @@
+# Copyright(C) 2015 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+if(NOT GRN_EMBED)
+ if(GRN_WITH_MRUBY)
+ set(GRN_RELATIVE_EXPRESSION_REWRITER_PLUGINS_DIR
+ "${GRN_RELATIVE_PLUGINS_DIR}/expression_rewriters")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/sources.am
+ EXPRESSION_REWRITERS)
+ install(FILES ${EXPRESSION_REWRITERS}
+ DESTINATION "${GRN_RELATIVE_SEXPRESSION_REWRITER_PLUGINS_DIR}")
+ endif()
+endif()
diff --git a/storage/mroonga/vendor/groonga/plugins/expression_rewriters/Makefile.am b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/Makefile.am
new file mode 100644
index 00000000..60a032ac
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/Makefile.am
@@ -0,0 +1,9 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+if WITH_MRUBY
+dist_expression_rewriter_plugins_DATA = \
+ $(expression_rewriters)
+endif
+
+include sources.am
diff --git a/storage/mroonga/vendor/groonga/plugins/expression_rewriters/optimizer.rb b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/optimizer.rb
new file mode 100644
index 00000000..3dfee681
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/optimizer.rb
@@ -0,0 +1,147 @@
+module Groonga
+ module ExpressionRewriters
+ class Optimizer < ExpressionRewriter
+ register "optimizer"
+
+ def rewrite
+ builder = ExpressionTreeBuilder.new(@expression)
+ root_node = builder.build
+
+ variable = @expression[0]
+ table = context[variable.domain]
+ optimized_root_node = optimize_node(table, root_node)
+
+ rewritten = Expression.create(table)
+ optimized_root_node.build(rewritten)
+ rewritten
+ end
+
+ private
+ def optimize_node(table, node)
+ case node
+ when ExpressionTree::LogicalOperation
+ optimized_sub_nodes = node.nodes.collect do |sub_node|
+ optimize_node(table, sub_node)
+ end
+ case node.operator
+ when Operator::AND
+ optimized_sub_nodes =
+ optimize_and_sub_nodes(table, optimized_sub_nodes)
+ end
+ ExpressionTree::LogicalOperation.new(node.operator,
+ optimized_sub_nodes)
+ when ExpressionTree::BinaryOperation
+ optimized_left = optimize_node(table, node.left)
+ optimized_right = optimize_node(table, node.right)
+ if optimized_left.is_a?(ExpressionTree::Constant) and
+ optimized_right.is_a?(ExpressionTree::Variable)
+ ExpressionTree::BinaryOperation.new(node.operator,
+ optimized_right,
+ optimized_left)
+ elsif node.left == optimized_left and node.right == optimized_right
+ node
+ else
+ ExpressionTree::BinaryOperation.new(node.operator,
+ optimized_left,
+ optimized_right)
+ end
+ else
+ node
+ end
+ end
+
+ def optimize_and_sub_nodes(table, sub_nodes)
+ grouped_sub_nodes = sub_nodes.group_by do |sub_node|
+ case sub_node
+ when ExpressionTree::BinaryOperation
+ if sub_node.left.is_a?(ExpressionTree::Variable)
+ sub_node.left.column
+ else
+ nil
+ end
+ else
+ nil
+ end
+ end
+
+ optimized_nodes = []
+ grouped_sub_nodes.each do |column, grouped_nodes|
+ if column
+ grouped_nodes = optimize_grouped_nodes(column, grouped_nodes)
+ end
+ optimized_nodes.concat(grouped_nodes)
+ end
+
+ optimized_nodes.sort_by do |node|
+ node.estimate_size(table)
+ end
+ end
+
+ COMPARISON_OPERATORS = [
+ Operator::EQUAL,
+ Operator::NOT_EQUAL,
+ Operator::LESS,
+ Operator::GREATER,
+ Operator::LESS_EQUAL,
+ Operator::GREATER_EQUAL,
+ ]
+ def optimize_grouped_nodes(column, grouped_nodes)
+ target_nodes, done_nodes = grouped_nodes.partition do |node|
+ node.is_a?(ExpressionTree::BinaryOperation) and
+ COMPARISON_OPERATORS.include?(node.operator) and
+ node.right.is_a?(ExpressionTree::Constant)
+ end
+
+ # TODO: target_nodes = remove_needless_nodes(target_nodes)
+ # e.g.: x < 1 && x < 3 -> x < 1: (x < 3) is meaningless
+
+ if target_nodes.size == 2
+ between_node = try_optimize_between(column, target_nodes)
+ if between_node
+ done_nodes << between_node
+ else
+ done_nodes.concat(target_nodes)
+ end
+ else
+ done_nodes.concat(target_nodes)
+ end
+
+ done_nodes
+ end
+
+ def try_optimize_between(column, target_nodes)
+ greater_node = nil
+ less_node = nil
+ target_nodes.each do |node|
+ case node.operator
+ when Operator::GREATER, Operator::GREATER_EQUAL
+ greater_node = node
+ when Operator::LESS, Operator::LESS_EQUAL
+ less_node = node
+ end
+ end
+ return nil if greater_node.nil? or less_node.nil?
+
+ between = ExpressionTree::Procedure.new(context["between"])
+ if greater_node.operator == Operator::GREATER
+ greater_border = "exclude"
+ else
+ greater_border = "include"
+ end
+ if less_node.operator == Operator::LESS
+ less_border = "exclude"
+ else
+ less_border = "include"
+ end
+ arguments = [
+ ExpressionTree::Variable.new(column),
+ greater_node.right,
+ ExpressionTree::Constant.new(greater_border),
+ less_node.right,
+ ExpressionTree::Constant.new(less_border),
+ ]
+ ExpressionTree::FunctionCall.new(between, arguments)
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/expression_rewriters/sources.am b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/sources.am
new file mode 100644
index 00000000..7670bed6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/expression_rewriters/sources.am
@@ -0,0 +1,2 @@
+expression_rewriters = \
+ optimizer.rb
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/functions/CMakeLists.txt
new file mode 100644
index 00000000..65a6d2c3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/CMakeLists.txt
@@ -0,0 +1,141 @@
+# Copyright(C) 2015-2017 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib
+ )
+
+set(GRN_FUNCTIONS_PLUGIN_DIR "${GRN_RELATIVE_PLUGINS_DIR}/functions")
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/vector_sources.am
+ VECTOR_SOURCES)
+set_source_files_properties(${VECTOR_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(vector_functions STATIC ${VECTOR_SOURCES})
+ set_target_properties(
+ vector_functions
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(vector_functions MODULE ${VECTOR_SOURCES})
+ set_target_properties(vector_functions PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "vector")
+ install(TARGETS vector_functions DESTINATION "${GRN_FUNCTIONS_PLUGIN_DIR}")
+endif()
+target_link_libraries(vector_functions libgroonga)
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/string_sources.am
+ STRING_SOURCES)
+set_source_files_properties(${STRING_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(string_functions STATIC ${STRING_SOURCES})
+ set_target_properties(
+ string_functions
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(string_functions MODULE ${STRING_SOURCES})
+ set_target_properties(string_functions PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "string")
+ install(TARGETS string_functions DESTINATION "${GRN_FUNCTIONS_PLUGIN_DIR}")
+endif()
+target_link_libraries(string_functions libgroonga)
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/number_sources.am
+ NUMBER_SOURCES)
+set_source_files_properties(${NUMBER_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(number_functions STATIC ${NUMBER_SOURCES})
+ set_target_properties(
+ number_functions
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(number_functions MODULE ${NUMBER_SOURCES})
+ set_target_properties(number_functions PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "number")
+ install(TARGETS number_functions DESTINATION "${GRN_FUNCTIONS_PLUGIN_DIR}")
+endif()
+target_link_libraries(number_functions libgroonga "${M_LIBS}")
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/time_sources.am
+ TIME_SOURCES)
+set_source_files_properties(${TIME_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(time_functions STATIC ${TIME_SOURCES})
+ set_target_properties(
+ time_functions
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(time_functions MODULE ${TIME_SOURCES})
+ set_target_properties(time_functions PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "time")
+ install(TARGETS time_functions DESTINATION "${GRN_FUNCTIONS_PLUGIN_DIR}")
+endif()
+target_link_libraries(time_functions libgroonga)
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/index_column_sources.am
+ INDEX_COLUMN_SOURCES)
+set_source_files_properties(${INDEX_COLUMN_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(index_column_functions STATIC ${INDEX_COLUMN_SOURCES})
+ set_target_properties(
+ index_column_functions
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(index_column_functions MODULE ${INDEX_COLUMN_SOURCES})
+ set_target_properties(index_column_functions PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "index_column")
+ install(TARGETS index_column_functions
+ DESTINATION "${GRN_FUNCTIONS_PLUGIN_DIR}")
+endif()
+target_link_libraries(index_column_functions libgroonga)
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/math_sources.am
+ MATH_SOURCES)
+set_source_files_properties(${MATH_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(math_functions STATIC ${MATH_SOURCES})
+ set_target_properties(
+ math_functions
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(math_functions MODULE ${MATH_SOURCES})
+ set_target_properties(math_functions PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "math")
+ install(TARGETS math_functions DESTINATION "${GRN_FUNCTIONS_PLUGIN_DIR}")
+endif()
+target_link_libraries(math_functions libgroonga)
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/Makefile.am b/storage/mroonga/vendor/groonga/plugins/functions/Makefile.am
new file mode 100644
index 00000000..f57ee031
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/Makefile.am
@@ -0,0 +1,33 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -no-undefined
+
+LIBS = \
+ $(top_builddir)/lib/libgroonga.la
+
+function_plugins_LTLIBRARIES =
+function_plugins_LTLIBRARIES += vector.la
+function_plugins_LTLIBRARIES += string.la
+function_plugins_LTLIBRARIES += number.la
+function_plugins_LTLIBRARIES += time.la
+function_plugins_LTLIBRARIES += index_column.la
+function_plugins_LTLIBRARIES += math.la
+
+include vector_sources.am
+include string_sources.am
+include number_sources.am
+include time_sources.am
+include index_column_sources.am
+include math_sources.am
+
+number_la_LIBADD = -lm
+math_la_LIBADD = -lm
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/index_column.c b/storage/mroonga/vendor/groonga/plugins/functions/index_column.c
new file mode 100644
index 00000000..05010074
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/index_column.c
@@ -0,0 +1,266 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG functions_time
+#endif
+
+#include <groonga/plugin.h>
+
+static grn_rc
+selector_index_column_df_ratio_between(grn_ctx *ctx,
+ grn_obj *table,
+ grn_obj *index,
+ int n_args,
+ grn_obj **args,
+ grn_obj *res,
+ grn_operator op)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_obj *index_column;
+ grn_ii *ii;
+ double min;
+ double max;
+ grn_obj *source_table;
+ unsigned int n_documents;
+ grn_posting posting;
+
+ if ((n_args - 1) != 3) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio_between(): "
+ "wrong number of arguments (%d for 3)", n_args - 1);
+ rc = ctx->rc;
+ goto exit;
+ }
+
+ index_column = args[1];
+ ii = (grn_ii *)index_column;
+ min = GRN_FLOAT_VALUE(args[2]);
+ max = GRN_FLOAT_VALUE(args[3]);
+
+ source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, index_column));
+ n_documents = grn_table_size(ctx, source_table);
+ memset(&posting, 0, sizeof(grn_posting));
+ posting.sid = 1;
+
+ if (op == GRN_OP_AND) {
+ GRN_TABLE_EACH_BEGIN(ctx, res, cursor, record_id) {
+ void *key;
+ grn_id term_id;
+ uint32_t n_match_documents;
+ double df_ratio;
+
+ grn_table_cursor_get_key(ctx, cursor, &key);
+ term_id = *(grn_id *)key;
+ n_match_documents = grn_ii_estimate_size(ctx, ii, term_id);
+ if (n_match_documents > n_documents) {
+ n_match_documents = n_documents;
+ }
+ df_ratio = (double)n_match_documents / (double)n_documents;
+ if (min <= df_ratio && df_ratio <= max) {
+ posting.rid = term_id;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ grn_ii_resolve_sel_and(ctx, (grn_hash *)res, op);
+ } else {
+ GRN_TABLE_EACH_BEGIN(ctx, table, cursor, term_id) {
+ uint32_t n_match_documents;
+ double df_ratio;
+
+ n_match_documents = grn_ii_estimate_size(ctx, ii, term_id);
+ if (n_match_documents > n_documents) {
+ n_match_documents = n_documents;
+ }
+ df_ratio = (double)n_match_documents / (double)n_documents;
+ {
+ void *key;
+ int key_size;
+ key_size = grn_table_cursor_get_key(ctx, cursor, &key);
+ }
+ if (min <= df_ratio && df_ratio <= max) {
+ posting.rid = term_id;
+ grn_ii_posting_add(ctx, &posting, (grn_hash *)res, op);
+ }
+ } GRN_TABLE_EACH_END(ctx, cursor);
+ }
+
+exit :
+ return rc;
+}
+
+static grn_obj *
+func_index_column_df_ratio(grn_ctx *ctx,
+ int n_args,
+ grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *term_table;
+ grn_obj *index_column_name;
+ grn_obj *index_column;
+ grn_ii *ii;
+ grn_id term_id;
+
+ if (n_args != 1) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio(): "
+ "wrong number of arguments (%d for 1)", n_args - 1);
+ return NULL;
+ }
+
+ {
+ grn_obj *expr;
+ grn_obj *variable;
+
+ expr = grn_plugin_proc_get_caller(ctx, user_data);
+ if (!expr) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio(): "
+ "called directly");
+ return NULL;
+ }
+
+ variable = grn_expr_get_var_by_offset(ctx, expr, 0);
+ if (!variable) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio(): "
+ "caller expression must have target record information");
+ return NULL;
+ }
+
+ term_table = grn_ctx_at(ctx, variable->header.domain);
+ term_id = GRN_RECORD_VALUE(variable);
+ while (GRN_TRUE) {
+ grn_obj *key_type;
+
+ key_type = grn_ctx_at(ctx, term_table->header.domain);
+ if (!grn_obj_is_table(ctx, key_type)) {
+ break;
+ }
+
+ grn_table_get_key(ctx, term_table, term_id, &term_id, sizeof(grn_id));
+ term_table = key_type;
+ }
+ }
+
+ index_column_name = args[0];
+ if (!grn_obj_is_text_family_bulk(ctx, index_column_name)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, index_column_name);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio(): "
+ "the first argument must be index column name: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ index_column = grn_obj_column(ctx,
+ term_table,
+ GRN_TEXT_VALUE(index_column_name),
+ GRN_TEXT_LEN(index_column_name));
+ if (!index_column) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio(): "
+ "nonexistent object: <%.*s>",
+ (int)GRN_TEXT_LEN(index_column_name),
+ GRN_TEXT_VALUE(index_column_name));
+ return NULL;
+ }
+
+ if (!grn_obj_is_index_column(ctx, index_column)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, index_column);
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_INVALID_ARGUMENT,
+ "index_column_df_ratio(): "
+ "the first argument must be index column: %.*s",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ if (grn_obj_is_accessor(ctx, index_column)) {
+ grn_obj_unlink(ctx, index_column);
+ }
+ return NULL;
+ }
+
+ ii = (grn_ii *)index_column;
+
+ {
+ grn_obj *source_table;
+ unsigned int n_documents;
+ uint32_t n_match_documents;
+ double df_ratio;
+ grn_obj *df_ratio_value;
+
+ source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, index_column));
+ n_documents = grn_table_size(ctx, source_table);
+ n_match_documents = grn_ii_estimate_size(ctx, ii, term_id);
+ if (n_match_documents > n_documents) {
+ n_match_documents = n_documents;
+ }
+ df_ratio = (double)n_match_documents / (double)n_documents;
+
+ df_ratio_value = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_FLOAT, 0);
+ if (!df_ratio_value) {
+ return NULL;
+ }
+ GRN_FLOAT_SET(ctx, df_ratio_value, df_ratio);
+ return df_ratio_value;
+ }
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_obj *selector_proc;
+
+ selector_proc = grn_proc_create(ctx, "index_column_df_ratio_between", -1,
+ GRN_PROC_FUNCTION,
+ NULL, NULL, NULL, 0, NULL);
+ grn_proc_set_selector(ctx, selector_proc,
+ selector_index_column_df_ratio_between);
+ grn_proc_set_selector_operator(ctx, selector_proc, GRN_OP_NOP);
+
+ grn_proc_create(ctx, "index_column_df_ratio", -1,
+ GRN_PROC_FUNCTION,
+ func_index_column_df_ratio, NULL, NULL, 0, NULL);
+
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/index_column_sources.am b/storage/mroonga/vendor/groonga/plugins/functions/index_column_sources.am
new file mode 100644
index 00000000..261907bc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/index_column_sources.am
@@ -0,0 +1,2 @@
+index_column_la_SOURCES = \
+ index_column.c
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/math.c b/storage/mroonga/vendor/groonga/plugins/functions/math.c
new file mode 100644
index 00000000..a6a9e260
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/math.c
@@ -0,0 +1,142 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG functions_math
+#endif
+
+#include <groonga/plugin.h>
+
+#include <math.h>
+#include <stdlib.h>
+
+static grn_obj *
+func_math_abs(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *number;
+ grn_obj *grn_abs_number = NULL;
+
+ if (n_args != 1) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "math_abs(): wrong number of arguments (%d for 1)",
+ n_args);
+ return NULL;
+ }
+
+ number = args[0];
+ if (!(number->header.type == GRN_BULK &&
+ grn_type_id_is_number_family(ctx, number->header.domain))) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, number);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "math_abs(): the first argument must be a number: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+#define ABS_AS_IS(return_type, to_type, getter, setter) { \
+ grn_abs_number = grn_plugin_proc_alloc(ctx, \
+ user_data, \
+ (return_type), \
+ 0); \
+ if (!grn_abs_number) { \
+ return NULL; \
+ } \
+ setter(ctx, grn_abs_number, getter(number)); \
+ }
+#define ABS_CONVERT_TYPE(func, return_type, to_type, getter, setter) { \
+ grn_abs_number = grn_plugin_proc_alloc(ctx, \
+ user_data, \
+ (return_type), \
+ 0); \
+ if (!grn_abs_number) { \
+ return NULL; \
+ } else { \
+ to_type abs_number_raw = (to_type)(func)(getter(number)); \
+ setter(ctx, grn_abs_number, abs_number_raw); \
+ } \
+ }
+
+ switch (number->header.domain) {
+ case GRN_DB_INT8:
+ ABS_CONVERT_TYPE(abs, GRN_DB_UINT8, uint8_t, GRN_INT8_VALUE, GRN_UINT8_SET);
+ break;
+ case GRN_DB_UINT8:
+ ABS_AS_IS(GRN_DB_UINT8, uint8_t, GRN_UINT8_VALUE, GRN_UINT8_SET);
+ break;
+ case GRN_DB_INT16:
+ ABS_CONVERT_TYPE(abs, GRN_DB_UINT16, uint16_t, GRN_INT16_VALUE, GRN_UINT16_SET);
+ break;
+ case GRN_DB_UINT16:
+ ABS_AS_IS(GRN_DB_UINT16, uint16_t, GRN_UINT16_VALUE, GRN_UINT16_SET);
+ break;
+ case GRN_DB_INT32:
+ ABS_CONVERT_TYPE(labs, GRN_DB_UINT32, uint32_t, GRN_INT32_VALUE, GRN_UINT32_SET);
+ break;
+ case GRN_DB_UINT32:
+ ABS_AS_IS(GRN_DB_UINT32, uint32_t, GRN_UINT32_VALUE, GRN_UINT32_SET);
+ break;
+ case GRN_DB_INT64:
+ ABS_CONVERT_TYPE(llabs, GRN_DB_UINT64, uint64_t, GRN_INT64_VALUE, GRN_UINT64_SET);
+ break;
+ case GRN_DB_UINT64:
+ ABS_AS_IS(GRN_DB_UINT64, uint64_t, GRN_UINT64_VALUE, GRN_UINT64_SET);
+ break;
+ case GRN_DB_FLOAT:
+ ABS_CONVERT_TYPE(fabs, GRN_DB_FLOAT, double, GRN_FLOAT_VALUE, GRN_FLOAT_SET);
+ break;
+ default :
+ break;
+ }
+#undef ABS_CONVERT_TYPE
+#undef ABS_AS_IS
+
+ return grn_abs_number;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ grn_proc_create(ctx,
+ "math_abs", -1,
+ GRN_PROC_FUNCTION,
+ func_math_abs,
+ NULL, NULL, 0, NULL);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/math_sources.am b/storage/mroonga/vendor/groonga/plugins/functions/math_sources.am
new file mode 100644
index 00000000..8c14ca74
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/math_sources.am
@@ -0,0 +1,2 @@
+math_la_SOURCES = \
+ math.c
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/number.c b/storage/mroonga/vendor/groonga/plugins/functions/number.c
new file mode 100644
index 00000000..7cdfc0e1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/number.c
@@ -0,0 +1,187 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG functions_number
+#endif
+
+#include <groonga/plugin.h>
+
+#include <math.h>
+
+static grn_obj *
+func_number_classify(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *number;
+ grn_obj *interval;
+ grn_obj casted_interval;
+ grn_obj *classed_number;
+
+ if (n_args != 2) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "number_classify(): wrong number of arguments (%d for 2)",
+ n_args);
+ return NULL;
+ }
+
+ number = args[0];
+ if (!(number->header.type == GRN_BULK &&
+ grn_type_id_is_number_family(ctx, number->header.domain))) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, number);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "number_classify(): the first argument must be a number: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ interval = args[1];
+ if (!(interval->header.type == GRN_BULK &&
+ grn_type_id_is_number_family(ctx, interval->header.domain))) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, interval);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "number_classify(): the second argument must be a number: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ classed_number = grn_plugin_proc_alloc(ctx,
+ user_data,
+ number->header.domain,
+ 0);
+ if (!classed_number) {
+ return NULL;
+ }
+
+ GRN_VALUE_FIX_SIZE_INIT(&casted_interval, 0, number->header.domain);
+ grn_obj_cast(ctx, interval, &casted_interval, GRN_FALSE);
+
+#define CLASSIFY_RAW(type, getter, setter, classifier) { \
+ type number_raw; \
+ type interval_raw; \
+ type class_raw; \
+ type classed_number_raw; \
+ \
+ number_raw = getter(number); \
+ interval_raw = getter(&casted_interval); \
+ class_raw = classifier(number_raw, interval_raw); \
+ classed_number_raw = class_raw * interval_raw; \
+ setter(ctx, classed_number, classed_number_raw); \
+ }
+
+#define CLASSIFIER_INT(number_raw, interval_raw) \
+ (number_raw) < 0 ? \
+ ((((number_raw) + 1) / (interval_raw)) - 1) : \
+ (((number_raw) / (interval_raw)))
+
+#define CLASSIFY_INT(type, getter, setter) \
+ CLASSIFY_RAW(type, getter, setter, CLASSIFIER_INT)
+
+#define CLASSIFIER_UINT(number_raw, interval_raw) \
+ ((number_raw) / (interval_raw))
+
+#define CLASSIFY_UINT(type, getter, setter) \
+ CLASSIFY_RAW(type, getter, setter, CLASSIFIER_UINT)
+
+#define CLASSIFIER_FLOAT(number_raw, interval_raw) \
+ floor((number_raw) / (interval_raw))
+
+#define CLASSIFY_FLOAT(getter, setter) \
+ CLASSIFY_RAW(double, getter, setter, CLASSIFIER_FLOAT)
+
+ switch (number->header.domain) {
+ case GRN_DB_INT8 :
+ CLASSIFY_INT(int8_t, GRN_INT8_VALUE, GRN_INT8_SET);
+ break;
+ case GRN_DB_UINT8 :
+ CLASSIFY_UINT(uint8_t, GRN_UINT8_VALUE, GRN_UINT8_SET);
+ break;
+ case GRN_DB_INT16 :
+ CLASSIFY_INT(int16_t, GRN_INT16_VALUE, GRN_INT16_SET);
+ break;
+ case GRN_DB_UINT16 :
+ CLASSIFY_UINT(uint16_t, GRN_UINT16_VALUE, GRN_UINT16_SET);
+ break;
+ case GRN_DB_INT32 :
+ CLASSIFY_INT(int32_t, GRN_INT32_VALUE, GRN_INT32_SET);
+ break;
+ case GRN_DB_UINT32 :
+ CLASSIFY_UINT(uint32_t, GRN_UINT32_VALUE, GRN_UINT32_SET);
+ break;
+ case GRN_DB_INT64 :
+ CLASSIFY_INT(int64_t, GRN_INT64_VALUE, GRN_INT64_SET);
+ break;
+ case GRN_DB_UINT64 :
+ CLASSIFY_UINT(uint64_t, GRN_UINT64_VALUE, GRN_UINT64_SET);
+ break;
+ case GRN_DB_FLOAT :
+ CLASSIFY_FLOAT(GRN_FLOAT_VALUE, GRN_FLOAT_SET);
+ break;
+ default :
+ break;
+ }
+#undef CLASSIFY_FLOAT
+#undef CLASSIFIER_FLAOT
+#undef CLASSIFY_UINT
+#undef CLASSIFIER_UINT
+#undef CLASSIFY_INT
+#undef CLASSIFIER_INT
+#undef CLASSIFY_RAW
+
+ GRN_OBJ_FIN(ctx, &casted_interval);
+
+ return classed_number;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ grn_proc_create(ctx,
+ "number_classify", -1,
+ GRN_PROC_FUNCTION,
+ func_number_classify,
+ NULL, NULL, 0, NULL);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/number_sources.am b/storage/mroonga/vendor/groonga/plugins/functions/number_sources.am
new file mode 100644
index 00000000..b3d9483b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/number_sources.am
@@ -0,0 +1,2 @@
+number_la_SOURCES = \
+ number.c
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/string.c b/storage/mroonga/vendor/groonga/plugins/functions/string.c
new file mode 100644
index 00000000..0af2d6ab
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/string.c
@@ -0,0 +1,299 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG functions_string
+#endif
+
+#include <groonga/plugin.h>
+
+/*
+ * func_string_length() returns the number of characters in a string.
+ * If the string contains an invalid byte sequence, this function returns the
+ * number of characters before the invalid byte sequence.
+ */
+static grn_obj *
+func_string_length(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *target;
+ unsigned int length = 0;
+ grn_obj *grn_length;
+
+ if (n_args != 1) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "string_length(): wrong number of arguments (%d for 1)",
+ n_args);
+ return NULL;
+ }
+
+ target = args[0];
+ if (!(target->header.type == GRN_BULK &&
+ ((target->header.domain == GRN_DB_SHORT_TEXT) ||
+ (target->header.domain == GRN_DB_TEXT) ||
+ (target->header.domain == GRN_DB_LONG_TEXT)))) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, target);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "string_length(): target object must be a text bulk: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ {
+ const char *s = GRN_TEXT_VALUE(target);
+ const char *e = GRN_TEXT_VALUE(target) + GRN_TEXT_LEN(target);
+ const char *p;
+ unsigned int cl = 0;
+ for (p = s; p < e && (cl = grn_charlen(ctx, p, e)); p += cl) {
+ length++;
+ }
+ }
+
+ grn_length = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_UINT32, 0);
+ if (!grn_length) {
+ return NULL;
+ }
+
+ GRN_UINT32_SET(ctx, grn_length, length);
+
+ return grn_length;
+}
+
+static grn_obj *
+func_string_substring(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *target;
+ grn_obj *from_raw;
+ grn_obj *length_raw = NULL;
+ int64_t from = 0;
+ int64_t length = -1;
+ const char *start = NULL;
+ const char *end = NULL;
+ grn_obj *substring;
+
+ if (n_args < 2) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "string_substring(): wrong number of arguments (%d for 2..3)",
+ n_args);
+ return NULL;
+ }
+
+ target = args[0];
+ from_raw = args[1];
+ if (n_args == 3) {
+ length_raw = args[2];
+ }
+
+ if (!(target->header.type == GRN_BULK &&
+ grn_type_id_is_text_family(ctx, target->header.domain))) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, target);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "string_substring(): target object must be a text bulk: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ /* TODO: extract as grn_func_arg_int64() */
+ if (!grn_type_id_is_number_family(ctx, from_raw->header.domain)) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, from_raw);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "string_substring(): from must be a number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ if (from_raw->header.domain == GRN_DB_INT32) {
+ from = GRN_INT32_VALUE(from_raw);
+ } else if (from_raw->header.domain == GRN_DB_INT64) {
+ from = GRN_INT64_VALUE(from_raw);
+ } else {
+ grn_obj buffer;
+ grn_rc rc;
+
+ GRN_INT64_INIT(&buffer, 0);
+ rc = grn_obj_cast(ctx, from_raw, &buffer, GRN_FALSE);
+ if (rc == GRN_SUCCESS) {
+ from = GRN_INT64_VALUE(&buffer);
+ }
+ GRN_OBJ_FIN(ctx, &buffer);
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, from_raw);
+ GRN_PLUGIN_ERROR(ctx, rc,
+ "string_substring(): "
+ "failed to cast from value to number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ }
+
+ if (length_raw) {
+ /* TODO: extract as grn_func_arg_int64() */
+ if (!grn_type_id_is_number_family(ctx, length_raw->header.domain)) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, length_raw);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "string_substring(): length must be a number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ if (length_raw->header.domain == GRN_DB_INT32) {
+ length = GRN_INT32_VALUE(length_raw);
+ } else if (length_raw->header.domain == GRN_DB_INT64) {
+ length = GRN_INT64_VALUE(length_raw);
+ } else {
+ grn_obj buffer;
+ grn_rc rc;
+
+ GRN_INT64_INIT(&buffer, 0);
+ rc = grn_obj_cast(ctx, length_raw, &buffer, GRN_FALSE);
+ if (rc == GRN_SUCCESS) {
+ length = GRN_INT64_VALUE(&buffer);
+ }
+ GRN_OBJ_FIN(ctx, &buffer);
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, length_raw);
+ GRN_PLUGIN_ERROR(ctx, rc,
+ "string_substring(): "
+ "failed to cast length value to number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ }
+ }
+
+ substring = grn_plugin_proc_alloc(ctx, user_data, target->header.domain, 0);
+ if (!substring) {
+ return NULL;
+ }
+
+ GRN_BULK_REWIND(substring);
+
+ if (GRN_TEXT_LEN(target) == 0) {
+ return substring;
+ }
+ if (length == 0) {
+ return substring;
+ }
+
+ while (from < 0) {
+ from += GRN_TEXT_LEN(target);
+ }
+
+ {
+ const char *p;
+
+ start = NULL;
+ p = GRN_TEXT_VALUE(target);
+ end = p + GRN_TEXT_LEN(target);
+
+ if (from == 0) {
+ start = p;
+ } else {
+ unsigned int char_length = 0;
+ int64_t n_chars = 0;
+
+ for (;
+ p < end && (char_length = grn_charlen(ctx, p, end));
+ p += char_length, n_chars++) {
+ if (n_chars == from) {
+ start = p;
+ break;
+ }
+ }
+ }
+
+ if (start && length > 0) {
+ unsigned int char_length = 0;
+ int64_t n_chars = 0;
+
+ for (;
+ p < end && (char_length = grn_charlen(ctx, p, end));
+ p += char_length, n_chars++) {
+ if (n_chars == length) {
+ end = p;
+ break;
+ }
+ }
+ }
+ }
+
+ if (start) {
+ GRN_TEXT_SET(ctx, substring, start, end - start);
+ }
+
+ return substring;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ grn_proc_create(ctx, "string_length", -1, GRN_PROC_FUNCTION, func_string_length,
+ NULL, NULL, 0, NULL);
+
+ grn_proc_create(ctx, "string_substring", -1, GRN_PROC_FUNCTION, func_string_substring,
+ NULL, NULL, 0, NULL);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/string_sources.am b/storage/mroonga/vendor/groonga/plugins/functions/string_sources.am
new file mode 100644
index 00000000..3477e58a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/string_sources.am
@@ -0,0 +1,2 @@
+string_la_SOURCES = \
+ string.c
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/time.c b/storage/mroonga/vendor/groonga/plugins/functions/time.c
new file mode 100644
index 00000000..f82ea872
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/time.c
@@ -0,0 +1,376 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG functions_time
+#endif
+
+#include <groonga/plugin.h>
+
+#include <math.h>
+
+typedef enum {
+ GRN_TIME_CLASSIFY_UNIT_SECOND,
+ GRN_TIME_CLASSIFY_UNIT_MINUTE,
+ GRN_TIME_CLASSIFY_UNIT_HOUR,
+ GRN_TIME_CLASSIFY_UNIT_DAY,
+ GRN_TIME_CLASSIFY_UNIT_WEEK,
+ GRN_TIME_CLASSIFY_UNIT_MONTH,
+ GRN_TIME_CLASSIFY_UNIT_YEAR
+} grn_time_classify_unit;
+
+static grn_obj *
+func_time_classify_raw(grn_ctx *ctx,
+ int n_args,
+ grn_obj **args,
+ grn_user_data *user_data,
+ const char *function_name,
+ grn_time_classify_unit unit)
+{
+ grn_obj *time;
+ uint32_t interval_raw = 1;
+ grn_obj *classed_time;
+ grn_bool accept_interval = GRN_TRUE;
+
+ switch (unit) {
+ case GRN_TIME_CLASSIFY_UNIT_SECOND :
+ case GRN_TIME_CLASSIFY_UNIT_MINUTE :
+ case GRN_TIME_CLASSIFY_UNIT_HOUR :
+ accept_interval = GRN_TRUE;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_DAY :
+ case GRN_TIME_CLASSIFY_UNIT_WEEK :
+ accept_interval = GRN_FALSE;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_MONTH :
+ case GRN_TIME_CLASSIFY_UNIT_YEAR :
+ accept_interval = GRN_TRUE;
+ break;
+ }
+
+ if (accept_interval) {
+ if (!(n_args == 1 || n_args == 2)) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s(): "
+ "wrong number of arguments (%d for 1..2)",
+ function_name,
+ n_args);
+ return NULL;
+ }
+ } else {
+ if (n_args != 1) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s(): "
+ "wrong number of arguments (%d for 1)",
+ function_name,
+ n_args);
+ return NULL;
+ }
+ }
+
+ time = args[0];
+ if (!(time->header.type == GRN_BULK &&
+ time->header.domain == GRN_DB_TIME)) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, time);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s(): "
+ "the first argument must be a time: "
+ "<%.*s>",
+ function_name,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ if (n_args == 2) {
+ grn_obj *interval;
+ grn_obj casted_interval;
+
+ interval = args[1];
+ if (!(interval->header.type == GRN_BULK &&
+ grn_type_id_is_number_family(ctx, interval->header.domain))) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, interval);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s(): "
+ "the second argument must be a number: "
+ "<%.*s>",
+ function_name,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+
+ GRN_VALUE_FIX_SIZE_INIT(&casted_interval, 0, GRN_DB_UINT32);
+ grn_obj_cast(ctx, interval, &casted_interval, GRN_FALSE);
+ interval_raw = GRN_UINT32_VALUE(&casted_interval);
+ GRN_OBJ_FIN(ctx, &casted_interval);
+
+ if (interval_raw == 0) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, interval);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "%s(): "
+ "the second argument must not be zero: "
+ "<%.*s>",
+ function_name,
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ }
+
+ {
+ int64_t time_raw;
+ struct tm tm;
+ int64_t classed_time_raw;
+
+ time_raw = GRN_TIME_VALUE(time);
+ if (!grn_time_to_tm(ctx, time_raw, &tm)) {
+ return NULL;
+ }
+
+ switch (unit) {
+ case GRN_TIME_CLASSIFY_UNIT_SECOND :
+ tm.tm_sec = (tm.tm_sec / interval_raw) * interval_raw;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_MINUTE :
+ tm.tm_min = (tm.tm_min / interval_raw) * interval_raw;
+ tm.tm_sec = 0;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_HOUR :
+ tm.tm_hour = (tm.tm_hour / interval_raw) * interval_raw;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_DAY :
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_WEEK :
+ if ((tm.tm_mday - tm.tm_wday) >= 0) {
+ tm.tm_mday -= tm.tm_wday;
+ } else {
+ int n_underflowed_mday = -(tm.tm_mday - tm.tm_wday);
+ int mday;
+ int max_mday = 31;
+
+ if (tm.tm_mon == 0) {
+ tm.tm_year--;
+ tm.tm_mon = 11;
+ } else {
+ tm.tm_mon--;
+ }
+
+ for (mday = max_mday; mday > n_underflowed_mday; mday--) {
+ int64_t unused;
+ tm.tm_mday = mday;
+ if (grn_time_from_tm(ctx, &unused, &tm)) {
+ break;
+ }
+ }
+ tm.tm_mday -= n_underflowed_mday;
+ }
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_MONTH :
+ tm.tm_mon = (tm.tm_mon / interval_raw) * interval_raw;
+ tm.tm_mday = 1;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ break;
+ case GRN_TIME_CLASSIFY_UNIT_YEAR :
+ tm.tm_year = (((1900 + tm.tm_year) / interval_raw) * interval_raw) - 1900;
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ break;
+ }
+
+ if (!grn_time_from_tm(ctx, &classed_time_raw, &tm)) {
+ return NULL;
+ }
+
+ classed_time = grn_plugin_proc_alloc(ctx,
+ user_data,
+ time->header.domain,
+ 0);
+ if (!classed_time) {
+ return NULL;
+ }
+ GRN_TIME_SET(ctx, classed_time, classed_time_raw);
+
+ return classed_time;
+ }
+}
+
+static grn_obj *
+func_time_classify_second(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_second",
+ GRN_TIME_CLASSIFY_UNIT_SECOND);
+}
+
+static grn_obj *
+func_time_classify_minute(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_minute",
+ GRN_TIME_CLASSIFY_UNIT_MINUTE);
+}
+
+static grn_obj *
+func_time_classify_hour(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_hour",
+ GRN_TIME_CLASSIFY_UNIT_HOUR);
+}
+
+static grn_obj *
+func_time_classify_day(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_day",
+ GRN_TIME_CLASSIFY_UNIT_DAY);
+}
+
+static grn_obj *
+func_time_classify_week(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_week",
+ GRN_TIME_CLASSIFY_UNIT_WEEK);
+}
+
+static grn_obj *
+func_time_classify_month(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_month",
+ GRN_TIME_CLASSIFY_UNIT_MONTH);
+}
+
+static grn_obj *
+func_time_classify_year(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ return func_time_classify_raw(ctx,
+ n_args,
+ args,
+ user_data,
+ "time_classify_year",
+ GRN_TIME_CLASSIFY_UNIT_YEAR);
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ grn_proc_create(ctx,
+ "time_classify_second", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_second,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx,
+ "time_classify_minute", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_minute,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx,
+ "time_classify_hour", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_hour,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx,
+ "time_classify_day", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_day,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx,
+ "time_classify_week", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_week,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx,
+ "time_classify_month", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_month,
+ NULL, NULL, 0, NULL);
+ grn_proc_create(ctx,
+ "time_classify_year", -1,
+ GRN_PROC_FUNCTION,
+ func_time_classify_year,
+ NULL, NULL, 0, NULL);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/time_sources.am b/storage/mroonga/vendor/groonga/plugins/functions/time_sources.am
new file mode 100644
index 00000000..2c55a570
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/time_sources.am
@@ -0,0 +1,2 @@
+time_la_SOURCES = \
+ time.c
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/vector.c b/storage/mroonga/vendor/groonga/plugins/functions/vector.c
new file mode 100644
index 00000000..1104b313
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/vector.c
@@ -0,0 +1,401 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2015-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG functions_vector
+#endif
+
+#include <groonga/plugin.h>
+
+static grn_obj *
+func_vector_size(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *target;
+ unsigned int size;
+ grn_obj *grn_size;
+
+ if (n_args != 1) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "vector_size(): wrong number of arguments (%d for 1)",
+ n_args);
+ return NULL;
+ }
+
+ target = args[0];
+ switch (target->header.type) {
+ case GRN_VECTOR :
+ case GRN_PVECTOR :
+ case GRN_UVECTOR :
+ size = grn_vector_size(ctx, target);
+ break;
+ default :
+ {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, target, &inspected);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "vector_size(): target object must be vector: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ break;
+ }
+
+ grn_size = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_UINT32, 0);
+ if (!grn_size) {
+ return NULL;
+ }
+
+ GRN_UINT32_SET(ctx, grn_size, size);
+
+ return grn_size;
+}
+
+static grn_obj *
+func_vector_slice(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *target;
+ grn_obj *from_raw = NULL;
+ grn_obj *length_raw = NULL;
+ int64_t from = 0;
+ int64_t length = -1;
+ uint32_t to = 0;
+ uint32_t size = 0;
+ grn_obj *slice;
+
+ if (n_args < 2 || n_args > 3) {
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "vector_slice(): wrong number of arguments (%d for 2..3)",
+ n_args);
+ return NULL;
+ }
+
+ target = args[0];
+ from_raw = args[1];
+ if (n_args == 3) {
+ length_raw = args[2];
+ }
+ switch (target->header.type) {
+ case GRN_VECTOR :
+ case GRN_PVECTOR :
+ case GRN_UVECTOR :
+ size = grn_vector_size(ctx, target);
+ break;
+ default :
+ {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, target, &inspected);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "vector_slice(): target object must be vector: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ break;
+ }
+
+ if (!grn_type_id_is_number_family(ctx, from_raw->header.domain)) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, from_raw);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "vector_slice(): from must be a number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ if (from_raw->header.domain == GRN_DB_INT32) {
+ from = GRN_INT32_VALUE(from_raw);
+ } else if (from_raw->header.domain == GRN_DB_INT64) {
+ from = GRN_INT64_VALUE(from_raw);
+ } else {
+ grn_obj buffer;
+ grn_rc rc;
+
+ GRN_INT64_INIT(&buffer, 0);
+ rc = grn_obj_cast(ctx, from_raw, &buffer, GRN_FALSE);
+ if (rc == GRN_SUCCESS) {
+ from = GRN_INT64_VALUE(&buffer);
+ }
+ GRN_OBJ_FIN(ctx, &buffer);
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, from_raw);
+ GRN_PLUGIN_ERROR(ctx, rc,
+ "vector_slice(): "
+ "failed to cast from value to number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ }
+
+ if (length_raw) {
+ if (!grn_type_id_is_number_family(ctx, length_raw->header.domain)) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, length_raw);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "vector_slice(): length must be a number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ if (length_raw->header.domain == GRN_DB_INT32) {
+ length = GRN_INT32_VALUE(length_raw);
+ } else if (length_raw->header.domain == GRN_DB_INT64) {
+ length = GRN_INT64_VALUE(length_raw);
+ } else {
+ grn_obj buffer;
+ grn_rc rc;
+
+ GRN_INT64_INIT(&buffer, 0);
+ rc = grn_obj_cast(ctx, length_raw, &buffer, GRN_FALSE);
+ if (rc == GRN_SUCCESS) {
+ length = GRN_INT64_VALUE(&buffer);
+ }
+ GRN_OBJ_FIN(ctx, &buffer);
+
+ if (rc != GRN_SUCCESS) {
+ grn_obj inspected;
+
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, length_raw);
+ GRN_PLUGIN_ERROR(ctx, rc,
+ "vector_slice(): "
+ "failed to cast length value to number: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return NULL;
+ }
+ }
+ }
+
+ slice = grn_plugin_proc_alloc(ctx, user_data, target->header.domain, GRN_OBJ_VECTOR);
+ if (!slice) {
+ return NULL;
+ }
+
+ if (target->header.flags & GRN_OBJ_WITH_WEIGHT) {
+ slice->header.flags |= GRN_OBJ_WITH_WEIGHT;
+ }
+
+ if (length < 0) {
+ length = size + length + 1;
+ }
+
+ if (length > size) {
+ length = size;
+ }
+
+ if (length <= 0) {
+ return slice;
+ }
+
+ while (from < 0) {
+ from += size;
+ }
+
+ to = from + length;
+ if (to > size) {
+ to = size;
+ }
+
+ switch (target->header.type) {
+ case GRN_VECTOR :
+ {
+ unsigned int i;
+ for (i = from; i < to; i++) {
+ const char *content;
+ unsigned int content_length;
+ unsigned int weight;
+ grn_id domain;
+ content_length = grn_vector_get_element(ctx, target, i,
+ &content, &weight, &domain);
+ grn_vector_add_element(ctx, slice,
+ content, content_length, weight, domain);
+ }
+ }
+ break;
+ case GRN_PVECTOR :
+ {
+ unsigned int i;
+ for (i = from; i < to; i++) {
+ grn_obj *element = GRN_PTR_VALUE_AT(target, i);
+ GRN_PTR_PUT(ctx, slice, element);
+ }
+ }
+ break;
+ case GRN_UVECTOR :
+ {
+ grn_obj *domain;
+
+ domain = grn_ctx_at(ctx, target->header.domain);
+ if (grn_obj_is_table(ctx, domain)) {
+ unsigned int i;
+ for (i = from; i < to; i++) {
+ grn_id id;
+ unsigned int weight;
+ id = grn_uvector_get_element(ctx, target, i, &weight);
+ grn_uvector_add_element(ctx, slice, id, weight);
+ }
+ } else {
+#define PUT_SLICE_VALUES(type) do { \
+ unsigned int i; \
+ for (i = from; i < to; i++) { \
+ GRN_ ## type ## _PUT(ctx, \
+ slice, \
+ GRN_ ## type ## _VALUE_AT(target, i)); \
+ } \
+ } while (GRN_FALSE)
+ switch (target->header.domain) {
+ case GRN_DB_BOOL :
+ PUT_SLICE_VALUES(BOOL);
+ break;
+ case GRN_DB_INT8 :
+ PUT_SLICE_VALUES(INT8);
+ break;
+ case GRN_DB_UINT8 :
+ PUT_SLICE_VALUES(UINT8);
+ break;
+ case GRN_DB_INT16 :
+ PUT_SLICE_VALUES(INT16);
+ break;
+ case GRN_DB_UINT16 :
+ PUT_SLICE_VALUES(UINT16);
+ break;
+ case GRN_DB_INT32 :
+ PUT_SLICE_VALUES(INT32);
+ break;
+ case GRN_DB_UINT32 :
+ PUT_SLICE_VALUES(UINT32);
+ break;
+ case GRN_DB_INT64 :
+ PUT_SLICE_VALUES(INT64);
+ break;
+ case GRN_DB_UINT64 :
+ PUT_SLICE_VALUES(UINT64);
+ break;
+ case GRN_DB_FLOAT :
+ PUT_SLICE_VALUES(FLOAT);
+ break;
+ case GRN_DB_TIME :
+ PUT_SLICE_VALUES(TIME);
+ break;
+ }
+ }
+ }
+ break;
+#undef PUT_SLICE_VALUES
+ }
+
+ return slice;
+}
+
+static grn_obj *
+func_vector_new(grn_ctx *ctx, int n_args, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_obj *vector = NULL;
+ int i;
+
+ if (n_args == 0) {
+ return grn_plugin_proc_alloc(ctx, user_data, GRN_DB_UINT32, GRN_OBJ_VECTOR);
+ }
+
+ vector = grn_plugin_proc_alloc(ctx,
+ user_data,
+ args[0]->header.domain,
+ GRN_OBJ_VECTOR);
+ if (!vector) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_args; i++) {
+ grn_obj *element = args[i];
+ switch (vector->header.type) {
+ case GRN_VECTOR :
+ grn_vector_add_element(ctx,
+ vector,
+ GRN_BULK_HEAD(element),
+ GRN_BULK_VSIZE(element),
+ 0,
+ element->header.domain);
+ break;
+ case GRN_UVECTOR :
+ grn_bulk_write(ctx,
+ vector,
+ GRN_BULK_HEAD(element),
+ GRN_BULK_VSIZE(element));
+ break;
+ case GRN_PVECTOR :
+ GRN_PTR_PUT(ctx, vector, element);
+ break;
+ default :
+ break;
+ }
+ }
+
+ return vector;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc = GRN_SUCCESS;
+
+ grn_proc_create(ctx, "vector_size", -1, GRN_PROC_FUNCTION, func_vector_size,
+ NULL, NULL, 0, NULL);
+
+ grn_proc_create(ctx, "vector_slice", -1, GRN_PROC_FUNCTION, func_vector_slice,
+ NULL, NULL, 0, NULL);
+
+ grn_proc_create(ctx, "vector_new", -1, GRN_PROC_FUNCTION, func_vector_new,
+ NULL, NULL, 0, NULL);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/functions/vector_sources.am b/storage/mroonga/vendor/groonga/plugins/functions/vector_sources.am
new file mode 100644
index 00000000..1d98e651
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/functions/vector_sources.am
@@ -0,0 +1,2 @@
+vector_la_SOURCES = \
+ vector.c
diff --git a/storage/mroonga/vendor/groonga/plugins/query_expanders/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/query_expanders/CMakeLists.txt
new file mode 100644
index 00000000..c2f04cb8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/query_expanders/CMakeLists.txt
@@ -0,0 +1,38 @@
+# Copyright(C) 2012-2013 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib
+ )
+
+set(QUERY_EXPANDERS_DIR "${GRN_RELATIVE_PLUGINS_DIR}/query_expanders")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/tsv_sources.am TSV_SOURCES)
+set_source_files_properties(${TSV_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(tsv_query_expander STATIC ${TSV_SOURCES})
+ set_target_properties(
+ tsv_query_expander
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(tsv_query_expander MODULE ${TSV_SOURCES})
+ set_target_properties(tsv_query_expander PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "tsv")
+ install(TARGETS tsv_query_expander DESTINATION "${QUERY_EXPANDERS_DIR}")
+endif()
+target_link_libraries(tsv_query_expander libgroonga)
diff --git a/storage/mroonga/vendor/groonga/plugins/query_expanders/Makefile.am b/storage/mroonga/vendor/groonga/plugins/query_expanders/Makefile.am
new file mode 100644
index 00000000..96c0911a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/query_expanders/Makefile.am
@@ -0,0 +1,20 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -no-undefined
+
+LIBS = \
+ $(top_builddir)/lib/libgroonga.la
+
+query_expander_plugins_LTLIBRARIES =
+query_expander_plugins_LTLIBRARIES += tsv.la
+
+include tsv_sources.am
diff --git a/storage/mroonga/vendor/groonga/plugins/query_expanders/tsv.c b/storage/mroonga/vendor/groonga/plugins/query_expanders/tsv.c
new file mode 100644
index 00000000..5d5deec6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/query_expanders/tsv.c
@@ -0,0 +1,314 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2012-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG query_expanders_tsv
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <groonga/plugin.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <windows.h>
+# include <share.h>
+#endif /* WIN32 */
+
+#define MAX_SYNONYM_BYTES 4096
+
+static grn_hash *synonyms = NULL;
+
+#ifdef WIN32
+static char win32_synonyms_file[MAX_PATH] = "";
+const char *
+get_system_synonyms_file(void)
+{
+ if (win32_synonyms_file[0] == '\0') {
+ const char *base_dir;
+ const char *relative_path = GRN_QUERY_EXPANDER_TSV_RELATIVE_SYNONYMS_FILE;
+ size_t base_dir_length;
+
+ base_dir = grn_plugin_windows_base_dir();
+ base_dir_length = strlen(base_dir);
+ grn_strcpy(win32_synonyms_file, MAX_PATH, base_dir);
+ grn_strcat(win32_synonyms_file, MAX_PATH, "/");
+ grn_strcat(win32_synonyms_file, MAX_PATH, relative_path);
+ }
+ return win32_synonyms_file;
+}
+
+#else /* WIN32 */
+const char *
+get_system_synonyms_file(void)
+{
+ return GRN_QUERY_EXPANDER_TSV_SYNONYMS_FILE;
+}
+#endif /* WIN32 */
+
+static grn_bool
+is_comment_mark(char character)
+{
+ return character == '#';
+}
+
+static grn_encoding
+detect_coding_part(grn_ctx *ctx, const char *line, size_t line_length)
+{
+ grn_encoding encoding = GRN_ENC_NONE;
+ grn_obj null_terminated_line_buffer;
+ const char *c_line;
+ const char *coding_part_keyword = "coding: ";
+ const char *coding_part;
+ const char *encoding_name;
+
+ GRN_TEXT_INIT(&null_terminated_line_buffer, 0);
+ GRN_TEXT_PUT(ctx, &null_terminated_line_buffer, line, line_length);
+ GRN_TEXT_PUTC(ctx, &null_terminated_line_buffer, '\0');
+
+ c_line = GRN_TEXT_VALUE(&null_terminated_line_buffer);
+ coding_part = strstr(c_line, coding_part_keyword);
+ if (coding_part) {
+ encoding_name = coding_part + strlen(coding_part_keyword);
+ if (grn_strncasecmp(encoding_name, "utf-8", strlen("utf-8")) == 0 ||
+ grn_strncasecmp(encoding_name, "utf8", strlen("utf8")) == 0) {
+ encoding = GRN_ENC_UTF8;
+ } else if (grn_strncasecmp(encoding_name, "sjis", strlen("sjis")) == 0 ||
+ grn_strncasecmp(encoding_name, "Shift_JIS", strlen("Shift_JIS")) == 0) {
+ encoding = GRN_ENC_SJIS;
+ } else if (grn_strncasecmp(encoding_name, "EUC-JP", strlen("EUC-JP")) == 0 ||
+ grn_strncasecmp(encoding_name, "euc_jp", strlen("euc_jp")) == 0) {
+ encoding = GRN_ENC_EUC_JP;
+ } else if (grn_strncasecmp(encoding_name, "latin1", strlen("latin1")) == 0) {
+ encoding = GRN_ENC_LATIN1;
+ } else if (grn_strncasecmp(encoding_name, "KOI8-R", strlen("KOI8-R")) == 0 ||
+ grn_strncasecmp(encoding_name, "koi8r", strlen("koi8r")) == 0) {
+ encoding = GRN_ENC_KOI8R;
+ }
+ } else {
+ encoding = ctx->encoding;
+ }
+ GRN_OBJ_FIN(ctx, &null_terminated_line_buffer);
+
+ return encoding;
+}
+
+static grn_encoding
+guess_encoding(grn_ctx *ctx, const char **line, size_t *line_length)
+{
+ const char bom[] = {0xef, 0xbb, 0xbf};
+ size_t bom_length = sizeof(bom);
+
+ if (*line_length >= bom_length && memcmp(*line, bom, bom_length) == 0) {
+ *line += bom_length;
+ *line_length -= bom_length;
+ return GRN_ENC_UTF8;
+ }
+
+ if (!is_comment_mark((*line)[0])) {
+ return ctx->encoding;
+ }
+
+ return detect_coding_part(ctx, (*line) + 1, (*line_length) - 1);
+}
+
+static void
+parse_synonyms_file_line(grn_ctx *ctx, const char *line, size_t line_length,
+ grn_obj *key, grn_obj *value)
+{
+ size_t i = 0;
+
+ if (is_comment_mark(line[i])) {
+ return;
+ }
+
+ while (i < line_length) {
+ char character = line[i];
+ i++;
+ if (character == '\t') {
+ break;
+ }
+ GRN_TEXT_PUTC(ctx, key, character);
+ }
+
+ if (i == line_length) {
+ return;
+ }
+
+ GRN_TEXT_PUTS(ctx, value, "((");
+ while (i < line_length) {
+ char character = line[i];
+ i++;
+ if (character == '\t') {
+ GRN_TEXT_PUTS(ctx, value, ") OR (");
+ } else {
+ GRN_TEXT_PUTC(ctx, value, character);
+ }
+ }
+ GRN_TEXT_PUTS(ctx, value, "))");
+
+ {
+ grn_id id;
+ void *value_location = NULL;
+
+ id = grn_hash_add(ctx, synonyms, GRN_TEXT_VALUE(key), GRN_TEXT_LEN(key),
+ &value_location, NULL);
+ if (id == GRN_ID_NIL) {
+ GRN_PLUGIN_LOG(ctx, GRN_LOG_WARNING,
+ "[plugin][query-expander][tsv] "
+ "failed to register key: <%.*s>",
+ (int)GRN_TEXT_LEN(key), GRN_TEXT_VALUE(key));
+ return;
+ }
+
+ if (GRN_TEXT_LEN(value) <= MAX_SYNONYM_BYTES - 1) {
+ GRN_TEXT_PUTC(ctx, value, '\0');
+ } else {
+ grn_bulk_truncate(ctx, value, MAX_SYNONYM_BYTES - 1);
+ GRN_TEXT_PUTC(ctx, value, '\0');
+ }
+ grn_memcpy(value_location, GRN_TEXT_VALUE(value), GRN_TEXT_LEN(value));
+ }
+}
+
+static void
+load_synonyms(grn_ctx *ctx)
+{
+ static char path_env[GRN_ENV_BUFFER_SIZE];
+ const char *path;
+ grn_file_reader *file_reader;
+ int number_of_lines;
+ grn_encoding encoding;
+ grn_obj line, key, value;
+
+ grn_getenv("GRN_QUERY_EXPANDER_TSV_SYNONYMS_FILE",
+ path_env,
+ GRN_ENV_BUFFER_SIZE);
+ if (path_env[0]) {
+ path = path_env;
+ } else {
+ path = get_system_synonyms_file();
+ }
+ file_reader = grn_file_reader_open(ctx, path);
+ if (!file_reader) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[plugin][query-expander][tsv] "
+ "synonyms file doesn't exist: <%s>",
+ path);
+ return;
+ }
+
+ GRN_TEXT_INIT(&line, 0);
+ GRN_TEXT_INIT(&key, 0);
+ GRN_TEXT_INIT(&value, 0);
+ grn_bulk_reserve(ctx, &value, MAX_SYNONYM_BYTES);
+ number_of_lines = 0;
+ while (grn_file_reader_read_line(ctx, file_reader, &line) == GRN_SUCCESS) {
+ const char *line_value = GRN_TEXT_VALUE(&line);
+ size_t line_length = GRN_TEXT_LEN(&line);
+
+ if (line_length > 0 && line_value[line_length - 1] == '\n') {
+ if (line_length > 1 && line_value[line_length - 2] == '\r') {
+ line_length -= 2;
+ } else {
+ line_length -= 1;
+ }
+ }
+ number_of_lines++;
+ if (number_of_lines == 1) {
+ encoding = guess_encoding(ctx, &line_value, &line_length);
+ }
+ GRN_BULK_REWIND(&key);
+ GRN_BULK_REWIND(&value);
+ parse_synonyms_file_line(ctx, line_value, line_length, &key, &value);
+ GRN_BULK_REWIND(&line);
+ }
+ GRN_OBJ_FIN(ctx, &line);
+ GRN_OBJ_FIN(ctx, &key);
+ GRN_OBJ_FIN(ctx, &value);
+
+ grn_file_reader_close(ctx, file_reader);
+}
+
+static grn_obj *
+func_query_expander_tsv(grn_ctx *ctx, int nargs, grn_obj **args,
+ grn_user_data *user_data)
+{
+ grn_rc rc = GRN_END_OF_DATA;
+ grn_id id;
+ grn_obj *term, *expanded_term;
+ void *value;
+ grn_obj *rc_object;
+
+ term = args[0];
+ expanded_term = args[1];
+ id = grn_hash_get(ctx, synonyms,
+ GRN_TEXT_VALUE(term), GRN_TEXT_LEN(term),
+ &value);
+ if (id != GRN_ID_NIL) {
+ const char *query = value;
+ GRN_TEXT_PUTS(ctx, expanded_term, query);
+ rc = GRN_SUCCESS;
+ }
+
+ rc_object = grn_plugin_proc_alloc(ctx, user_data, GRN_DB_INT32, 0);
+ if (rc_object) {
+ GRN_INT32_SET(ctx, rc_object, rc);
+ }
+
+ return rc_object;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ if (!synonyms) {
+ synonyms = grn_hash_create(ctx, NULL,
+ GRN_TABLE_MAX_KEY_SIZE,
+ MAX_SYNONYM_BYTES,
+ GRN_OBJ_TABLE_HASH_KEY | GRN_OBJ_KEY_VAR_SIZE);
+ if (!synonyms) {
+ return ctx->rc;
+ }
+ load_synonyms(ctx);
+ }
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_proc_create(ctx, "QueryExpanderTSV", strlen("QueryExpanderTSV"),
+ GRN_PROC_FUNCTION,
+ func_query_expander_tsv, NULL, NULL,
+ 0, NULL);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ if (synonyms) {
+ grn_hash_close(ctx, synonyms);
+ synonyms = NULL;
+ }
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/query_expanders/tsv_sources.am b/storage/mroonga/vendor/groonga/plugins/query_expanders/tsv_sources.am
new file mode 100644
index 00000000..f1bdabed
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/query_expanders/tsv_sources.am
@@ -0,0 +1,2 @@
+tsv_la_SOURCES = \
+ tsv.c
diff --git a/storage/mroonga/vendor/groonga/plugins/ruby/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/ruby/CMakeLists.txt
new file mode 100644
index 00000000..a2bcccd1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/ruby/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright(C) 2013-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+if(NOT GRN_EMBED)
+ if(GRN_WITH_MRUBY)
+ set(GRN_RELATIVE_RUBY_PLUGINS_DIR "${GRN_RELATIVE_PLUGINS_DIR}/ruby")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/sources.am RUBY_SCRIPTS)
+ install(FILES ${RUBY_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_RUBY_PLUGINS_DIR}")
+ endif()
+endif()
diff --git a/storage/mroonga/vendor/groonga/plugins/ruby/Makefile.am b/storage/mroonga/vendor/groonga/plugins/ruby/Makefile.am
new file mode 100644
index 00000000..a4949727
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/ruby/Makefile.am
@@ -0,0 +1,9 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+if WITH_MRUBY
+dist_ruby_plugins_DATA = \
+ $(ruby_scripts)
+endif
+
+include sources.am
diff --git a/storage/mroonga/vendor/groonga/plugins/ruby/eval.rb b/storage/mroonga/vendor/groonga/plugins/ruby/eval.rb
new file mode 100644
index 00000000..e7619cf2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/ruby/eval.rb
@@ -0,0 +1,36 @@
+module Groonga
+ module Ruby
+ class EvalCommand < Command
+ register("ruby_eval",
+ [
+ "script",
+ ])
+
+ def run_body(input)
+ script = input[:script]
+ unless script.is_a?(String)
+ message = "script must be a string: <#{script.inspect}>"
+ raise Groonga::InvalidArgument, message
+ end
+
+ eval_context = EvalContext.new
+ begin
+ result = eval_context.eval(script)
+ rescue Exception => error
+ writer.map("result", 1) do
+ writer.write("exception")
+ writer.map("exception", 1) do
+ writer.write("message")
+ writer.write(error.message)
+ end
+ end
+ else
+ writer.map("result", 1) do
+ writer.write("value")
+ writer.write(result)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/ruby/sources.am b/storage/mroonga/vendor/groonga/plugins/ruby/sources.am
new file mode 100644
index 00000000..f8938291
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/ruby/sources.am
@@ -0,0 +1,2 @@
+ruby_scripts = \
+ eval.rb
diff --git a/storage/mroonga/vendor/groonga/plugins/ruby_scripts.am b/storage/mroonga/vendor/groonga/plugins/ruby_scripts.am
new file mode 100644
index 00000000..0262dbb9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/ruby_scripts.am
@@ -0,0 +1,2 @@
+ruby_scripts = \
+ sharding.rb
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding.rb b/storage/mroonga/vendor/groonga/plugins/sharding.rb
new file mode 100644
index 00000000..86401c1f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding.rb
@@ -0,0 +1,11 @@
+require "sharding/parameters"
+require "sharding/range_expression_builder"
+require "sharding/logical_enumerator"
+
+require "sharding/logical_parameters"
+
+require "sharding/logical_count"
+require "sharding/logical_range_filter"
+require "sharding/logical_select"
+require "sharding/logical_shard_list"
+require "sharding/logical_table_remove"
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/sharding/CMakeLists.txt
new file mode 100644
index 00000000..1131520f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/CMakeLists.txt
@@ -0,0 +1,24 @@
+# Copyright(C) 2015 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+if(NOT GRN_EMBED)
+ if(GRN_WITH_MRUBY)
+ set(GRN_RELATIVE_SHARDING_PLUGINS_DIR "${GRN_RELATIVE_PLUGINS_DIR}/sharding")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/sources.am SHARDING_SCRIPTS)
+ install(FILES ${SHARDING_SCRIPTS}
+ DESTINATION "${GRN_RELATIVE_SHARDING_PLUGINS_DIR}")
+ endif()
+endif()
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/Makefile.am b/storage/mroonga/vendor/groonga/plugins/sharding/Makefile.am
new file mode 100644
index 00000000..8104ab6d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/Makefile.am
@@ -0,0 +1,9 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+if WITH_MRUBY
+dist_sharding_plugins_DATA = \
+ $(sharding_scripts)
+endif
+
+include sources.am
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_count.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_count.rb
new file mode 100644
index 00000000..8bdd77ef
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_count.rb
@@ -0,0 +1,169 @@
+module Groonga
+ module Sharding
+ class LogicalCountCommand < Command
+ register("logical_count",
+ [
+ "logical_table",
+ "shard_key",
+ "min",
+ "min_border",
+ "max",
+ "max_border",
+ "filter",
+ ])
+
+ def run_body(input)
+ enumerator = LogicalEnumerator.new("logical_count", input)
+ filter = input[:filter]
+
+ total = 0
+ enumerator.each do |shard, shard_range|
+ total += count_n_records(filter, shard, shard_range,
+ enumerator.target_range)
+ end
+ writer.write(total)
+ end
+
+ private
+ def cache_key(input)
+ key = "logical_count\0"
+ key << "#{input[:logical_table]}\0"
+ key << "#{input[:shard_key]}\0"
+ key << "#{input[:min]}\0"
+ key << "#{input[:min_border]}\0"
+ key << "#{input[:max]}\0"
+ key << "#{input[:max_border]}\0"
+ key << "#{input[:filter]}\0"
+ key
+ end
+
+ def log_use_range_index(use, table_name, line, method)
+ message = "[logical_count]"
+ if use
+ message << "[range-index]"
+ else
+ message << "[select]"
+ end
+ message << " <#{table_name}>"
+ Context.instance.logger.log(Logger::Level::DEBUG,
+ __FILE__,
+ line,
+ method.to_s,
+ message)
+ end
+
+ def count_n_records(filter, shard, shard_range, target_range)
+ cover_type = target_range.cover_type(shard_range)
+ return 0 if cover_type == :none
+
+ shard_key = shard.key
+ if shard_key.nil?
+ message = "[logical_count] shard_key doesn't exist: " +
+ "<#{shard.key_name}>"
+ raise InvalidArgument, message
+ end
+ table = shard.table
+ table_name = shard.table_name
+
+ expression_builder = RangeExpressionBuilder.new(shard_key,
+ target_range)
+ expression_builder.filter = filter
+ if cover_type == :all
+ log_use_range_index(false, table_name, __LINE__, __method__)
+ if filter.nil?
+ return table.size
+ else
+ return filtered_count_n_records(table) do |expression|
+ expression_builder.build_all(expression)
+ end
+ end
+ end
+
+ range_index = nil
+ if filter.nil?
+ index_info = shard_key.find_index(Operator::LESS)
+ if index_info
+ range_index = index_info.index
+ end
+ end
+
+ use_range_index = (!range_index.nil?)
+ log_use_range_index(use_range_index, table_name, __LINE__, __method__)
+
+ case cover_type
+ when :partial_min
+ if range_index
+ count_n_records_in_range(range_index,
+ target_range.min, target_range.min_border,
+ nil, nil)
+ else
+ filtered_count_n_records(table) do |expression|
+ expression_builder.build_partial_min(expression)
+ end
+ end
+ when :partial_max
+ if range_index
+ count_n_records_in_range(range_index,
+ nil, nil,
+ target_range.max, target_range.max_border)
+ else
+ filtered_count_n_records(table) do |expression|
+ expression_builder.build_partial_max(expression)
+ end
+ end
+ when :partial_min_and_max
+ if range_index
+ count_n_records_in_range(range_index,
+ target_range.min, target_range.min_border,
+ target_range.max, target_range.max_border)
+ else
+ filtered_count_n_records(table) do |expression|
+ expression_builder.build_partial_min_and_max(expression)
+ end
+ end
+ end
+ end
+
+ def filtered_count_n_records(table)
+ expression = nil
+ filtered_table = nil
+
+ begin
+ expression = Expression.create(table)
+ yield(expression)
+ filtered_table = table.select(expression)
+ filtered_table.size
+ ensure
+ filtered_table.close if filtered_table
+ expression.close if expression
+ end
+ end
+
+ def count_n_records_in_range(range_index,
+ min, min_border, max, max_border)
+ flags = TableCursorFlags::BY_KEY
+ case min_border
+ when :include
+ flags |= TableCursorFlags::GE
+ when :exclude
+ flags |= TableCursorFlags::GT
+ end
+ case max_border
+ when :include
+ flags |= TableCursorFlags::LE
+ when :exclude
+ flags |= TableCursorFlags::LT
+ end
+
+ TableCursor.open(range_index.table,
+ :min => min,
+ :max => max,
+ :flags => flags) do |table_cursor|
+ IndexCursor.open(table_cursor, range_index) do |index_cursor|
+ index_cursor.count
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_enumerator.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_enumerator.rb
new file mode 100644
index 00000000..d05a220f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_enumerator.rb
@@ -0,0 +1,317 @@
+module Groonga
+ module Sharding
+ class LogicalEnumerator
+ include Enumerable
+
+ attr_reader :target_range
+ attr_reader :logical_table
+ attr_reader :shard_key_name
+ def initialize(command_name, input, options={})
+ @command_name = command_name
+ @input = input
+ @options = options
+ initialize_parameters
+ end
+
+ def each(&block)
+ each_internal(:ascending, &block)
+ end
+
+ def reverse_each(&block)
+ each_internal(:descending, &block)
+ end
+
+ private
+ def each_internal(order)
+ context = Context.instance
+ each_shard_with_around(order) do |prev_shard, current_shard, next_shard|
+ shard_range_data = current_shard.range_data
+ shard_range = nil
+
+ if shard_range_data.day.nil?
+ if order == :ascending
+ if next_shard
+ next_shard_range_data = next_shard.range_data
+ else
+ next_shard_range_data = nil
+ end
+ else
+ if prev_shard
+ next_shard_range_data = prev_shard.range_data
+ else
+ next_shard_range_data = nil
+ end
+ end
+ max_day = compute_month_shard_max_day(shard_range_data.year,
+ shard_range_data.month,
+ next_shard_range_data)
+ shard_range = MonthShardRange.new(shard_range_data.year,
+ shard_range_data.month,
+ max_day)
+ else
+ shard_range = DayShardRange.new(shard_range_data.year,
+ shard_range_data.month,
+ shard_range_data.day)
+ end
+
+ yield(current_shard, shard_range)
+ end
+ end
+
+ def each_shard_with_around(order)
+ context = Context.instance
+ prefix = "#{@logical_table}_"
+
+ shards = [nil]
+ context.database.each_name(:prefix => prefix,
+ :order_by => :key,
+ :order => order) do |name|
+ shard_range_raw = name[prefix.size..-1]
+
+ case shard_range_raw
+ when /\A(\d{4})(\d{2})\z/
+ shard_range_data = ShardRangeData.new($1.to_i, $2.to_i, nil)
+ when /\A(\d{4})(\d{2})(\d{2})\z/
+ shard_range_data = ShardRangeData.new($1.to_i, $2.to_i, $3.to_i)
+ else
+ next
+ end
+
+ shards << Shard.new(name, @shard_key_name, shard_range_data)
+ next if shards.size < 3
+ yield(*shards)
+ shards.shift
+ end
+
+ if shards.size == 2
+ yield(shards[0], shards[1], nil)
+ end
+ end
+
+ private
+ def initialize_parameters
+ @logical_table = @input[:logical_table]
+ if @logical_table.nil?
+ raise InvalidArgument, "[#{@command_name}] logical_table is missing"
+ end
+
+ @shard_key_name = @input[:shard_key]
+ if @shard_key_name.nil?
+ require_shard_key = @options[:require_shard_key]
+ require_shard_key = true if require_shard_key.nil?
+ if require_shard_key
+ raise InvalidArgument, "[#{@command_name}] shard_key is missing"
+ end
+ end
+
+ @target_range = TargetRange.new(@command_name, @input)
+ end
+
+ def compute_month_shard_max_day(year, month, next_shard_range)
+ return nil if next_shard_range.nil?
+
+ return nil if month != next_shard_range.month
+
+ next_shard_range.day
+ end
+
+ class Shard
+ attr_reader :table_name, :key_name, :range_data
+ def initialize(table_name, key_name, range_data)
+ @table_name = table_name
+ @key_name = key_name
+ @range_data = range_data
+ end
+
+ def table
+ @table ||= Context.instance[@table_name]
+ end
+
+ def full_key_name
+ "#{@table_name}.#{@key_name}"
+ end
+
+ def key
+ @key ||= Context.instance[full_key_name]
+ end
+ end
+
+ class ShardRangeData
+ attr_reader :year, :month, :day
+ def initialize(year, month, day)
+ @year = year
+ @month = month
+ @day = day
+ end
+
+ def to_suffix
+ if @day.nil?
+ "_%04d%02d" % [@year, @month]
+ else
+ "_%04d%02d%02d" % [@year, @month, @day]
+ end
+ end
+ end
+
+ class DayShardRange
+ attr_reader :year, :month, :day
+ def initialize(year, month, day)
+ @year = year
+ @month = month
+ @day = day
+ end
+
+ def least_over_time
+ next_day = Time.local(@year, @month, @day) + (60 * 60 * 24)
+ while next_day.day == @day # For leap second
+ next_day += 1
+ end
+ next_day
+ end
+
+ def min_time
+ Time.local(@year, @month, @day)
+ end
+
+ def include?(time)
+ @year == time.year and
+ @month == time.month and
+ @day == time.day
+ end
+ end
+
+ class MonthShardRange
+ attr_reader :year, :month, :max_day
+ def initialize(year, month, max_day)
+ @year = year
+ @month = month
+ @max_day = max_day
+ end
+
+ def least_over_time
+ if @max_day.nil?
+ if @month == 12
+ Time.local(@year + 1, 1, 1)
+ else
+ Time.local(@year, @month + 1, 1)
+ end
+ else
+ Time.local(@year, @month, @max_day)
+ end
+ end
+
+ def min_time
+ Time.local(@year, @month, 1)
+ end
+
+ def include?(time)
+ return false unless @year == time.year
+ return false unless @month == time.month
+
+ if @max_day.nil?
+ true
+ else
+ time.day <= @max_day
+ end
+ end
+ end
+
+ class TargetRange
+ attr_reader :min, :min_border
+ attr_reader :max, :max_border
+ def initialize(command_name, input)
+ @command_name = command_name
+ @input = input
+ @min = parse_value(:min)
+ @min_border = parse_border(:min_border)
+ @max = parse_value(:max)
+ @max_border = parse_border(:max_border)
+ end
+
+ def cover_type(shard_range)
+ return :all if @min.nil? and @max.nil?
+
+ if @min and @max
+ return :none unless in_min?(shard_range)
+ return :none unless in_max?(shard_range)
+ min_partial_p = in_min_partial?(shard_range)
+ max_partial_p = in_max_partial?(shard_range)
+ if min_partial_p and max_partial_p
+ :partial_min_and_max
+ elsif min_partial_p
+ :partial_min
+ elsif max_partial_p
+ :partial_max
+ else
+ :all
+ end
+ elsif @min
+ return :none unless in_min?(shard_range)
+ if in_min_partial?(shard_range)
+ :partial_min
+ else
+ :all
+ end
+ else
+ return :none unless in_max?(shard_range)
+ if in_max_partial?(shard_range)
+ :partial_max
+ else
+ :all
+ end
+ end
+ end
+
+ private
+ def parse_value(name)
+ value = @input[name]
+ return nil if value.nil?
+
+ Converter.convert(value, Time)
+ end
+
+ def parse_border(name)
+ border = @input[name]
+ return :include if border.nil?
+
+ case border
+ when "include"
+ :include
+ when "exclude"
+ :exclude
+ else
+ message =
+ "[#{@command_name}] #{name} must be \"include\" or \"exclude\": " +
+ "<#{border}>"
+ raise InvalidArgument, message
+ end
+ end
+
+ def in_min?(shard_range)
+ @min < shard_range.least_over_time
+ end
+
+ def in_min_partial?(shard_range)
+ return false unless shard_range.include?(@min)
+
+ return true if @min_border == :exclude
+
+ shard_range.min_time != @min
+ end
+
+ def in_max?(shard_range)
+ max_base_time = shard_range.min_time
+ if @max_border == :include
+ @max >= max_base_time
+ else
+ @max > max_base_time
+ end
+ end
+
+ def in_max_partial?(shard_range)
+ shard_range.include?(@max)
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_parameters.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_parameters.rb
new file mode 100644
index 00000000..75ff569b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_parameters.rb
@@ -0,0 +1,44 @@
+module Groonga
+ module Sharding
+ class LogicalParametersCommand < Command
+ register("logical_parameters",
+ [
+ "range_index",
+ ])
+
+ def run_body(input)
+ range_index = parse_range_index(input[:range_index])
+
+ parameters = [
+ :range_index,
+ ]
+ writer.map("parameters", parameters.size) do
+ parameters.each do |name|
+ writer.write(name.to_s)
+ writer.write(Parameters.__send__(name))
+ end
+ end
+
+ Parameters.range_index = range_index if range_index
+ end
+
+ private
+ def parse_range_index(value)
+ case value
+ when nil
+ nil
+ when "auto"
+ :auto
+ when "always"
+ :always
+ when "never"
+ :never
+ else
+ message = "[logical_parameters][range_index] "
+ message << "must be auto, always or never: <#{value}>"
+ raise InvalidArgument, message
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_range_filter.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_range_filter.rb
new file mode 100644
index 00000000..1c8f8644
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_range_filter.rb
@@ -0,0 +1,642 @@
+module Groonga
+ module Sharding
+ class LogicalRangeFilterCommand < Command
+ register("logical_range_filter",
+ [
+ "logical_table",
+ "shard_key",
+ "min",
+ "min_border",
+ "max",
+ "max_border",
+ "order",
+ "filter",
+ "offset",
+ "limit",
+ "output_columns",
+ "use_range_index",
+ ])
+
+ def run_body(input)
+ output_columns = input[:output_columns] || "_key, *"
+
+ context = ExecuteContext.new(input)
+ begin
+ executor = Executor.new(context)
+ executor.execute
+
+ result_sets = context.result_sets
+ n_elements = 1 # for columns
+ result_sets.each do |result_set|
+ n_elements += result_set.size
+ end
+
+ writer.array("RESULTSET", n_elements) do
+ first_result_set = result_sets.first
+ if first_result_set
+ writer.write_table_columns(first_result_set, output_columns)
+ end
+ limit = context.limit
+ if limit < 0
+ n_records = result_sets.inject(0) do |n, result_set|
+ n + result_set.size
+ end
+ limit = n_records + limit + 1
+ end
+ options = {}
+ result_sets.each do |result_set|
+ options[:limit] = limit
+ writer.write_table_records(result_set, output_columns, options)
+ limit -= result_set.size
+ break if limit <= 0
+ end
+ end
+ ensure
+ context.close
+ end
+ end
+
+ private
+ def cache_key(input)
+ key = "logical_range_filter\0"
+ key << "#{input[:logical_table]}\0"
+ key << "#{input[:shard_key]}\0"
+ key << "#{input[:min]}\0"
+ key << "#{input[:min_border]}\0"
+ key << "#{input[:max]}\0"
+ key << "#{input[:max_border]}\0"
+ key << "#{input[:order]}\0"
+ key << "#{input[:filter]}\0"
+ key << "#{input[:offset]}\0"
+ key << "#{input[:limit]}\0"
+ key << "#{input[:output_columns]}\0"
+ key << "#{input[:use_range_index]}\0"
+ key
+ end
+
+ class ExecuteContext
+ attr_reader :use_range_index
+ attr_reader :enumerator
+ attr_reader :order
+ attr_reader :filter
+ attr_reader :offset
+ attr_reader :limit
+ attr_accessor :current_offset
+ attr_accessor :current_limit
+ attr_reader :result_sets
+ attr_reader :unsorted_result_sets
+ attr_reader :threshold
+ def initialize(input)
+ @input = input
+ @use_range_index = parse_use_range_index(@input[:use_range_index])
+ @enumerator = LogicalEnumerator.new("logical_range_filter", @input)
+ @order = parse_order(@input, :order)
+ @filter = @input[:filter]
+ @offset = (@input[:offset] || 0).to_i
+ @limit = (@input[:limit] || 10).to_i
+
+ @current_offset = @offset
+ @current_limit = @limit
+
+ @result_sets = []
+ @unsorted_result_sets = []
+
+ @threshold = compute_threshold
+ end
+
+ def close
+ @unsorted_result_sets.each do |result_set|
+ result_set.close if result_set.temporary?
+ end
+ @result_sets.each do |result_set|
+ result_set.close if result_set.temporary?
+ end
+ end
+
+ private
+ def parse_use_range_index(use_range_index)
+ case use_range_index
+ when "yes"
+ true
+ when "no"
+ false
+ else
+ nil
+ end
+ end
+
+ def parse_order(input, name)
+ order = input[name]
+ return :ascending if order.nil?
+
+ case order
+ when "ascending"
+ :ascending
+ when "descending"
+ :descending
+ else
+ message =
+ "[logical_range_filter] #{name} must be " +
+ "\"ascending\" or \"descending\": <#{order}>"
+ raise InvalidArgument, message
+ end
+ end
+
+ def compute_threshold
+ threshold_env = ENV["GRN_LOGICAL_RANGE_FILTER_THRESHOLD"]
+ default_threshold = 0.2
+ (threshold_env || default_threshold).to_f
+ end
+ end
+
+ class Executor
+ def initialize(context)
+ @context = context
+ end
+
+ def execute
+ first_shard = nil
+ enumerator = @context.enumerator
+ target_range = enumerator.target_range
+ if @context.order == :descending
+ each_method = :reverse_each
+ else
+ each_method = :each
+ end
+ enumerator.send(each_method) do |shard, shard_range|
+ first_shard ||= shard
+ shard_executor = ShardExecutor.new(@context, shard, shard_range)
+ shard_executor.execute
+ break if @context.current_limit == 0
+ end
+ if first_shard.nil?
+ message =
+ "[logical_range_filter] no shard exists: " +
+ "logical_table: <#{enumerator.logical_table}>: " +
+ "shard_key: <#{enumerator.shard_key_name}>"
+ raise InvalidArgument, message
+ end
+ if @context.result_sets.empty?
+ result_set = HashTable.create(:flags => ObjectFlags::WITH_SUBREC,
+ :key_type => first_shard.table)
+ @context.result_sets << result_set
+ end
+ end
+ end
+
+ class ShardExecutor
+ def initialize(context, shard, shard_range)
+ @context = context
+ @shard = shard
+ @shard_range = shard_range
+
+ @filter = @context.filter
+ @result_sets = @context.result_sets
+ @unsorted_result_sets = @context.unsorted_result_sets
+
+ @target_range = @context.enumerator.target_range
+
+ @cover_type = @target_range.cover_type(@shard_range)
+ end
+
+ def execute
+ return if @cover_type == :none
+ return if @shard.table.empty?
+
+ shard_key = @shard.key
+ if shard_key.nil?
+ message = "[logical_range_filter] shard_key doesn't exist: " +
+ "<#{@shard.key_name}>"
+ raise InvalidArgument, message
+ end
+
+ expression_builder = RangeExpressionBuilder.new(shard_key,
+ @target_range)
+ expression_builder.filter = @filter
+
+ index_info = shard_key.find_index(Operator::LESS)
+ if index_info
+ range_index = index_info.index
+ unless use_range_index?(range_index, expression_builder)
+ range_index = nil
+ end
+ else
+ range_index = nil
+ end
+
+ execute_filter(range_index, expression_builder)
+ end
+
+ private
+ def decide_use_range_index(use, reason, line, method)
+ message = "[logical_range_filter]"
+ if use
+ message << "[range-index] "
+ else
+ message << "[select] "
+ end
+ message << "<#{@shard.table_name}>: "
+ message << reason
+ Context.instance.logger.log(Logger::Level::DEBUG,
+ __FILE__,
+ line,
+ method.to_s,
+ message)
+
+ use
+ end
+
+ def use_range_index?(range_index, expression_builder)
+ use_range_index_parameter_message =
+ "force by use_range_index parameter"
+ case @context.use_range_index
+ when true
+ return decide_use_range_index(true,
+ use_range_index_parameter_message,
+ __LINE__, __method__)
+ when false
+ return decide_use_range_index(false,
+ use_range_index_parameter_message,
+ __LINE__, __method__)
+ end
+
+ range_index_logical_parameter_message =
+ "force by range_index logical parameter"
+ case Parameters.range_index
+ when :always
+ return decide_use_range_index(true,
+ range_index_logical_parameter_message,
+ __LINE__, __method__)
+ when :never
+ return decide_use_range_index(false,
+ range_index_logical_parameter_message,
+ __LINE__, __method__)
+ end
+
+ current_limit = @context.current_limit
+ if current_limit < 0
+ reason = "limit is negative: <#{current_limit}>"
+ return decide_use_range_index(false, reason,
+ __LINE__, __method__)
+ end
+
+ required_n_records = @context.current_offset + current_limit
+ max_n_records = @shard.table.size
+ if max_n_records <= required_n_records
+ reason = "the number of required records (#{required_n_records}) "
+ reason << ">= "
+ reason << "the number of records in shard (#{max_n_records})"
+ return decide_use_range_index(false, reason,
+ __LINE__, __method__)
+ end
+
+ threshold = @context.threshold
+ if threshold <= 0.0
+ reason = "threshold is negative: <#{threshold}>"
+ return decide_use_range_index(true, reason,
+ __LINE__, __method__)
+ end
+ if threshold >= 1.0
+ reason = "threshold (#{threshold}) >= 1.0"
+ return decide_use_range_index(false, reason,
+ __LINE__, __method__)
+ end
+
+ table = @shard.table
+ estimated_n_records = 0
+ case @cover_type
+ when :all
+ if @filter
+ create_expression(table) do |expression|
+ expression_builder.build_all(expression)
+ unless range_index_available_expression?(expression,
+ __LINE__, __method__)
+ return false
+ end
+ estimated_n_records = expression.estimate_size(table)
+ end
+ else
+ estimated_n_records = max_n_records
+ end
+ when :partial_min
+ create_expression(table) do |expression|
+ expression_builder.build_partial_min(expression)
+ unless range_index_available_expression?(expression,
+ __LINE__, __method__)
+ return false
+ end
+ estimated_n_records = expression.estimate_size(table)
+ end
+ when :partial_max
+ create_expression(table) do |expression|
+ expression_builder.build_partial_max(expression)
+ unless range_index_available_expression?(expression,
+ __LINE__, __method__)
+ return false
+ end
+ estimated_n_records = expression.estimate_size(table)
+ end
+ when :partial_min_and_max
+ create_expression(table) do |expression|
+ expression_builder.build_partial_min_and_max(expression)
+ unless range_index_available_expression?(expression,
+ __LINE__, __method__)
+ return false
+ end
+ estimated_n_records = expression.estimate_size(table)
+ end
+ end
+
+ if estimated_n_records <= required_n_records
+ reason = "the number of required records (#{required_n_records}) "
+ reason << ">= "
+ reason << "the number of estimated records (#{estimated_n_records})"
+ return decide_use_range_index(false, reason,
+ __LINE__, __method__)
+ end
+
+ hit_ratio = estimated_n_records / max_n_records.to_f
+ use_range_index_by_hit_ratio = (hit_ratio >= threshold)
+ if use_range_index_by_hit_ratio
+ relation = ">="
+ else
+ relation = "<"
+ end
+ reason = "hit ratio "
+ reason << "(#{hit_ratio}=#{estimated_n_records}/#{max_n_records}) "
+ reason << "#{relation} threshold (#{threshold})"
+ decide_use_range_index(use_range_index_by_hit_ratio, reason,
+ __LINE__, __method__)
+ end
+
+ def range_index_available_expression?(expression, line, method_name)
+ nested_reference_vector_column_accessor =
+ find_nested_reference_vector_column_accessor(expression)
+ if nested_reference_vector_column_accessor
+ reason = "nested reference vector column accessor can't be used: "
+ reason << "<#{nested_reference_vector_column_accessor.name}>"
+ return decide_use_range_index(false, reason, line, method_name)
+ end
+
+ selector_only_procedure = find_selector_only_procedure(expression)
+ if selector_only_procedure
+ reason = "selector only procedure can't be used: "
+ reason << "<#{selector_only_procedure.name}>"
+ return decide_use_range_index(false, reason, line, method_name)
+ end
+
+ true
+ end
+
+ def find_nested_reference_vector_column_accessor(expression)
+ expression.codes.each do |code|
+ value = code.value
+ next unless value.is_a?(Accessor)
+
+ sub_accessor = value
+ while sub_accessor.have_next?
+ object = sub_accessor.object
+ return value if object.is_a?(Column) and object.vector?
+ sub_accessor = sub_accessor.next
+ end
+ end
+ nil
+ end
+
+ def find_selector_only_procedure(expression)
+ expression.codes.each do |code|
+ value = code.value
+ return value if value.is_a?(Procedure) and value.selector_only?
+ end
+ nil
+ end
+
+ def execute_filter(range_index, expression_builder)
+ case @cover_type
+ when :all
+ filter_shard_all(range_index, expression_builder)
+ when :partial_min
+ if range_index
+ filter_by_range(range_index, expression_builder,
+ @target_range.min, @target_range.min_border,
+ nil, nil)
+ else
+ filter_table do |expression|
+ expression_builder.build_partial_min(expression)
+ end
+ end
+ when :partial_max
+ if range_index
+ filter_by_range(range_index, expression_builder,
+ nil, nil,
+ @target_range.max, @target_range.max_border)
+ else
+ filter_table do |expression|
+ expression_builder.build_partial_max(expression)
+ end
+ end
+ when :partial_min_and_max
+ if range_index
+ filter_by_range(range_index, expression_builder,
+ @target_range.min, @target_range.min_border,
+ @target_range.max, @target_range.max_border)
+ else
+ filter_table do |expression|
+ expression_builder.build_partial_min_and_max(expression)
+ end
+ end
+ end
+ end
+
+ def filter_shard_all(range_index, expression_builder)
+ table = @shard.table
+ if @filter.nil?
+ if table.size <= @context.current_offset
+ @context.current_offset -= table.size
+ return
+ end
+ if range_index
+ filter_by_range(range_index, expression_builder,
+ nil, nil,
+ nil, nil)
+ else
+ sort_result_set(table)
+ end
+ else
+ if range_index
+ filter_by_range(range_index, expression_builder,
+ nil, nil,
+ nil, nil)
+ else
+ filter_table do |expression|
+ expression_builder.build_all(expression)
+ end
+ end
+ end
+ end
+
+ def create_expression(table)
+ expression = Expression.create(table)
+ begin
+ yield(expression)
+ ensure
+ expression.close
+ end
+ end
+
+ def filter_by_range(range_index, expression_builder,
+ min, min_border, max, max_border)
+ lexicon = range_index.domain
+ data_table = range_index.range
+ flags = build_range_search_flags(min_border, max_border)
+
+ result_set = HashTable.create(:flags => ObjectFlags::WITH_SUBREC,
+ :key_type => data_table)
+ n_matched_records = 0
+ begin
+ TableCursor.open(lexicon,
+ :min => min,
+ :max => max,
+ :flags => flags) do |table_cursor|
+ options = {
+ :offset => @context.current_offset,
+ }
+ current_limit = @context.current_limit
+ if current_limit < 0
+ options[:limit] = data_table.size
+ else
+ options[:limit] = current_limit
+ end
+ max_n_unmatched_records =
+ compute_max_n_unmatched_records(data_table.size,
+ options[:limit])
+ options[:max_n_unmatched_records] = max_n_unmatched_records
+ if @filter
+ create_expression(data_table) do |expression|
+ expression.parse(@filter)
+ options[:expression] = expression
+ IndexCursor.open(table_cursor, range_index) do |index_cursor|
+ n_matched_records = index_cursor.select(result_set, options)
+ end
+ end
+ else
+ IndexCursor.open(table_cursor, range_index) do |index_cursor|
+ n_matched_records = index_cursor.select(result_set, options)
+ end
+ end
+ if n_matched_records == -1
+ result_set.close
+ fallback_message =
+ "fallback because there are too much unmatched records: "
+ fallback_message << "<#{max_n_unmatched_records}>"
+ decide_use_range_index(false,
+ fallback_message,
+ __LINE__, __method__)
+ execute_filter(nil, expression_builder)
+ return
+ end
+ end
+ rescue
+ result_set.close
+ raise
+ end
+
+ if n_matched_records <= @context.current_offset
+ @context.current_offset -= n_matched_records
+ result_set.close
+ return
+ end
+
+ if @context.current_offset > 0
+ @context.current_offset = 0
+ end
+ if @context.current_limit > 0
+ @context.current_limit -= result_set.size
+ end
+ @result_sets << result_set
+ end
+
+ def build_range_search_flags(min_border, max_border)
+ flags = TableCursorFlags::BY_KEY
+ case @context.order
+ when :ascending
+ flags |= TableCursorFlags::ASCENDING
+ when :descending
+ flags |= TableCursorFlags::DESCENDING
+ end
+ case min_border
+ when :include
+ flags |= TableCursorFlags::GE
+ when :exclude
+ flags |= TableCursorFlags::GT
+ end
+ case max_border
+ when :include
+ flags |= TableCursorFlags::LE
+ when :exclude
+ flags |= TableCursorFlags::LT
+ end
+ flags
+ end
+
+ def compute_max_n_unmatched_records(data_table_size, limit)
+ max_n_unmatched_records = limit * 100
+ max_n_sample_records = data_table_size
+ if max_n_sample_records > 10000
+ sample_ratio = 1 / (Math.log(data_table_size) ** 2)
+ max_n_sample_records = (max_n_sample_records * sample_ratio).ceil
+ end
+ if max_n_unmatched_records > max_n_sample_records
+ max_n_unmatched_records = max_n_sample_records
+ end
+ max_n_unmatched_records
+ end
+
+ def filter_table
+ table = @shard.table
+ create_expression(table) do |expression|
+ yield(expression)
+ result_set = table.select(expression)
+ sort_result_set(result_set)
+ end
+ end
+
+ def sort_result_set(result_set)
+ if result_set.empty?
+ result_set.close if result_set.temporary?
+ return
+ end
+
+ if result_set.size <= @context.current_offset
+ @context.current_offset -= result_set.size
+ result_set.close if result_set.temporary?
+ return
+ end
+
+ @unsorted_result_sets << result_set if result_set.temporary?
+ sort_keys = [
+ {
+ :key => @context.enumerator.shard_key_name,
+ :order => @context.order,
+ },
+ ]
+ if @context.current_limit > 0
+ limit = @context.current_limit
+ else
+ limit = result_set.size
+ end
+ sorted_result_set = result_set.sort(sort_keys,
+ :offset => @context.current_offset,
+ :limit => limit)
+ @result_sets << sorted_result_set
+ if @context.current_offset > 0
+ @context.current_offset = 0
+ end
+ if @context.current_limit > 0
+ @context.current_limit -= sorted_result_set.size
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_select.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_select.rb
new file mode 100644
index 00000000..07ebf9e8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_select.rb
@@ -0,0 +1,975 @@
+module Groonga
+ module Sharding
+ class LogicalSelectCommand < Command
+ register("logical_select",
+ [
+ "logical_table",
+ "shard_key",
+ "min",
+ "min_border",
+ "max",
+ "max_border",
+ "filter",
+ # Deprecated since 6.1.5. Use sort_keys instead.
+ "sortby",
+ "output_columns",
+ "offset",
+ "limit",
+ "drilldown",
+ # Deprecated since 6.1.5. Use drilldown_sort_keys instead.
+ "drilldown_sortby",
+ "drilldown_output_columns",
+ "drilldown_offset",
+ "drilldown_limit",
+ "drilldown_calc_types",
+ "drilldown_calc_target",
+ "sort_keys",
+ "drilldown_sort_keys",
+ "match_columns",
+ "query",
+ "drilldown_filter",
+ ])
+
+ def run_body(input)
+ context = ExecuteContext.new(input)
+ begin
+ executor = Executor.new(context)
+ executor.execute
+
+ n_results = 1
+ n_plain_drilldowns = context.plain_drilldown.n_result_sets
+ n_labeled_drilldowns = context.labeled_drilldowns.n_result_sets
+ if n_plain_drilldowns > 0
+ n_results += n_plain_drilldowns
+ elsif
+ if n_labeled_drilldowns > 0
+ n_results += 1
+ end
+ end
+
+ writer.array("RESULT", n_results) do
+ write_records(writer, context)
+ if n_plain_drilldowns > 0
+ write_plain_drilldowns(writer, context)
+ elsif n_labeled_drilldowns > 0
+ write_labeled_drilldowns(writer, context)
+ end
+ end
+ ensure
+ context.close
+ end
+ end
+
+ private
+ def cache_key(input)
+ sort_keys = input[:sort_keys] || input[:sortby]
+ drilldown_sort_keys =
+ input[:drilldown_sort_keys] || input[:drilldown_sortby]
+ key = "logical_select\0"
+ key << "#{input[:logical_table]}\0"
+ key << "#{input[:shard_key]}\0"
+ key << "#{input[:min]}\0"
+ key << "#{input[:min_border]}\0"
+ key << "#{input[:max]}\0"
+ key << "#{input[:max_border]}\0"
+ key << "#{input[:filter]}\0"
+ key << "#{sort_keys}\0"
+ key << "#{input[:output_columns]}\0"
+ key << "#{input[:offset]}\0"
+ key << "#{input[:limit]}\0"
+ key << "#{input[:drilldown]}\0"
+ key << "#{drilldown_sort_keys}\0"
+ key << "#{input[:match_columns]}\0"
+ key << "#{input[:query]}\0"
+ key << "#{input[:drilldown_output_columns]}\0"
+ key << "#{input[:drilldown_offset]}\0"
+ key << "#{input[:drilldown_limit]}\0"
+ key << "#{input[:drilldown_calc_types]}\0"
+ key << "#{input[:drilldown_calc_target]}\0"
+ key << "#{input[:drilldown_filter]}\0"
+ labeled_drilldowns = LabeledDrilldowns.parse(input).sort_by(&:label)
+ labeled_drilldowns.each do |drilldown|
+ key << "#{drilldown.label}\0"
+ key << "#{drilldown.keys.join(',')}\0"
+ key << "#{drilldown.output_columns}\0"
+ key << "#{drilldown.offset}\0"
+ key << "#{drilldown.limit}\0"
+ key << "#{drilldown.calc_types}\0"
+ key << "#{drilldown.calc_target_name}\0"
+ key << "#{drilldown.filter}\0"
+ cache_key_dynamic_columns(key, drilldown.dynamic_columns)
+ end
+ dynamic_columns = DynamicColumns.parse(input)
+ cache_key_dynamic_columns(key, dynamic_columns)
+ key
+ end
+
+ def cache_key_dynamic_columns(key, dynamic_columns)
+ [
+ :initial,
+ :filtered,
+ :output
+ ].each do |stage|
+ target_dynamic_columns = dynamic_columns.__send__("each_#{stage}").to_a
+ target_dynamic_columns.sort_by(&:label).each do |dynamic_column|
+ key << "#{dynamic_column.label}\0"
+ key << "#{dynamic_column.stage}\0"
+ key << "#{dynamic_column.type}\0"
+ key << "#{dynamic_column.flags}\0"
+ key << "#{dynamic_column.value}\0"
+ key << "#{dynamic_column.window_sort_keys.join(',')}\0"
+ key << "#{dynamic_column.window_group_keys.join(',')}\0"
+ end
+ end
+ end
+
+ def write_records(writer, context)
+ result_sets = context.result_sets
+
+ n_hits = 0
+ n_elements = 2 # for N hits and columns
+ result_sets.each do |result_set|
+ n_hits += result_set.size
+ n_elements += result_set.size
+ end
+
+ output_columns = context.output_columns
+
+ writer.array("RESULTSET", n_elements) do
+ writer.array("NHITS", 1) do
+ writer.write(n_hits)
+ end
+ first_result_set = result_sets.first
+ if first_result_set
+ writer.write_table_columns(first_result_set, output_columns)
+ end
+
+ current_offset = context.offset
+ current_offset += n_hits if current_offset < 0
+ current_limit = context.limit
+ current_limit += n_hits + 1 if current_limit < 0
+ options = {
+ :offset => current_offset,
+ :limit => current_limit,
+ }
+ result_sets.each do |result_set|
+ if result_set.size > current_offset
+ writer.write_table_records(result_set, output_columns, options)
+ current_limit -= result_set.size
+ end
+ if current_offset > 0
+ current_offset = [current_offset - result_set.size, 0].max
+ end
+ break if current_limit <= 0
+ options[:offset] = current_offset
+ options[:limit] = current_limit
+ end
+ end
+ end
+
+ def write_plain_drilldowns(writer, execute_context)
+ plain_drilldown = execute_context.plain_drilldown
+
+ drilldowns = plain_drilldown.result_sets
+ output_columns = plain_drilldown.output_columns
+ options = {
+ :offset => plain_drilldown.offset,
+ :limit => plain_drilldown.limit,
+ }
+
+ drilldowns.each do |drilldown|
+ n_elements = 2 # for N hits and columns
+ n_elements += drilldown.size
+ writer.array("RESULTSET", n_elements) do
+ writer.array("NHITS", 1) do
+ writer.write(drilldown.size)
+ end
+ writer.write_table_columns(drilldown, output_columns)
+ writer.write_table_records(drilldown, output_columns,
+ options)
+ end
+ end
+ end
+
+ def write_labeled_drilldowns(writer, execute_context)
+ labeled_drilldowns = execute_context.labeled_drilldowns
+ is_command_version1 = (context.command_version == 1)
+
+ writer.map("DRILLDOWNS", labeled_drilldowns.n_result_sets) do
+ labeled_drilldowns.each do |drilldown|
+ writer.write(drilldown.label)
+
+ result_set = drilldown.result_set
+ n_elements = 2 # for N hits and columns
+ n_elements += result_set.size
+ output_columns = drilldown.output_columns
+ options = {
+ :offset => drilldown.offset,
+ :limit => drilldown.limit,
+ }
+
+ writer.array("RESULTSET", n_elements) do
+ writer.array("NHITS", 1) do
+ writer.write(result_set.size)
+ end
+ writer.write_table_columns(result_set, output_columns)
+ if is_command_version1 and drilldown.need_command_version2?
+ context.with_command_version(2) do
+ writer.write_table_records(result_set,
+ drilldown.output_columns_v2,
+ options)
+ end
+ else
+ writer.write_table_records(result_set, output_columns, options)
+ end
+ end
+ end
+ end
+ end
+
+ class LabeledArgumentParser
+ def initialize(parameters)
+ @parameters = parameters
+ end
+
+ def parse(prefix_pattern)
+ pattern = /\A#{prefix_pattern}\[(.+?)\]\.(.+)\z/
+ labeled_arguments = {}
+ @parameters.each do |key, value|
+ match_data = pattern.match(key)
+ next if match_data.nil?
+ labeled_argument = (labeled_arguments[match_data[1]] ||= {})
+ labeled_argument[match_data[2]] = value
+ end
+ labeled_arguments
+ end
+ end
+
+ module KeysParsable
+ private
+ def parse_keys(raw_keys)
+ return [] if raw_keys.nil?
+
+ raw_keys.strip.split(/ *, */)
+ end
+ end
+
+ module Calculatable
+ def calc_target(table)
+ return nil if @calc_target_name.nil?
+ table.find_column(@calc_target_name)
+ end
+
+ private
+ def parse_calc_types(raw_types)
+ return TableGroupFlags::CALC_COUNT if raw_types.nil?
+
+ types = 0
+ raw_types.strip.split(/ *, */).each do |name|
+ case name
+ when "COUNT"
+ types |= TableGroupFlags::CALC_COUNT
+ when "MAX"
+ types |= TableGroupFlags::CALC_MAX
+ when "MIN"
+ types |= TableGroupFlags::CALC_MIN
+ when "SUM"
+ types |= TableGroupFlags::CALC_SUM
+ when "AVG"
+ types |= TableGroupFlags::CALC_AVG
+ when "NONE"
+ # Do nothing
+ else
+ raise InvalidArgument, "invalid drilldown calc type: <#{name}>"
+ end
+ end
+ types
+ end
+ end
+
+ class ExecuteContext
+ include KeysParsable
+
+ attr_reader :enumerator
+ attr_reader :match_columns
+ attr_reader :query
+ attr_reader :filter
+ attr_reader :offset
+ attr_reader :limit
+ attr_reader :sort_keys
+ attr_reader :output_columns
+ attr_reader :dynamic_columns
+ attr_reader :result_sets
+ attr_reader :unsorted_result_sets
+ attr_reader :plain_drilldown
+ attr_reader :labeled_drilldowns
+ attr_reader :temporary_tables
+ attr_reader :expressions
+ def initialize(input)
+ @input = input
+ @enumerator = LogicalEnumerator.new("logical_select", @input)
+ @match_columns = @input[:match_columns]
+ @query = @input[:query]
+ @filter = @input[:filter]
+ @offset = (@input[:offset] || 0).to_i
+ @limit = (@input[:limit] || 10).to_i
+ @sort_keys = parse_keys(@input[:sort_keys] || @input[:sortby])
+ @output_columns = @input[:output_columns] || "_id, _key, *"
+
+ @dynamic_columns = DynamicColumns.parse(@input)
+
+ @result_sets = []
+ @unsorted_result_sets = []
+
+ @plain_drilldown = PlainDrilldownExecuteContext.new(@input)
+ @labeled_drilldowns = LabeledDrilldowns.parse(@input)
+
+ @temporary_tables = []
+
+ @expressions = []
+ end
+
+ def close
+ @result_sets.each do |result_set|
+ result_set.close if result_set.temporary?
+ end
+ @unsorted_result_sets.each do |result_set|
+ result_set.close if result_set.temporary?
+ end
+
+ @plain_drilldown.close
+ @labeled_drilldowns.close
+
+ @dynamic_columns.close
+
+ @temporary_tables.each do |table|
+ table.close
+ end
+
+ @expressions.each do |expression|
+ expression.close
+ end
+ end
+ end
+
+ class DynamicColumns
+ class << self
+ def parse(input)
+ parser = LabeledArgumentParser.new(input)
+ columns = parser.parse(/columns?/)
+
+ initial_contexts = []
+ filtered_contexts = []
+ output_contexts = []
+ columns.each do |label, parameters|
+ contexts = nil
+ case parameters["stage"]
+ when "initial"
+ contexts = initial_contexts
+ when "filtered"
+ contexts = filtered_contexts
+ when "output"
+ contexts = output_contexts
+ else
+ next
+ end
+ contexts << DynamicColumnExecuteContext.new(label, parameters)
+ end
+
+ new(initial_contexts,
+ filtered_contexts,
+ output_contexts)
+ end
+ end
+
+ def initialize(initial_contexts,
+ filtered_contexts,
+ output_contexts)
+ @initial_contexts = initial_contexts
+ @filtered_contexts = filtered_contexts
+ @output_contexts = output_contexts
+ end
+
+ def each_initial(&block)
+ @initial_contexts.each(&block)
+ end
+
+ def each_filtered(&block)
+ @filtered_contexts.each(&block)
+ end
+
+ def each_output(&block)
+ @output_contexts.each(&block)
+ end
+
+ def close
+ @initial_contexts.each do |context|
+ context.close
+ end
+ @filtered_contexts.each do |context|
+ context.close
+ end
+ @output_contexts.each do |context|
+ context.close
+ end
+ end
+ end
+
+ class DynamicColumnExecuteContext
+ include KeysParsable
+
+ attr_reader :label
+ attr_reader :stage
+ attr_reader :type
+ attr_reader :flags
+ attr_reader :value
+ attr_reader :window_sort_keys
+ attr_reader :window_group_keys
+ def initialize(label, parameters)
+ @label = label
+ @stage = parameters["stage"]
+ @type = parse_type(parameters["type"])
+ @flags = parse_flags(parameters["flags"] || "COLUMN_SCALAR")
+ @value = parameters["value"]
+ @window_sort_keys = parse_keys(parameters["window.sort_keys"])
+ @window_group_keys = parse_keys(parameters["window.group_keys"])
+ end
+
+ def close
+ end
+
+ def apply(table, condition=nil)
+ column = table.create_column(@label, @flags, @type)
+ return if table.empty?
+
+ expression = Expression.create(table)
+ begin
+ expression.parse(@value)
+ if @window_sort_keys.empty? and @window_group_keys.empty?
+ expression.condition = condition if condition
+ table.apply_expression(column, expression)
+ else
+ table.apply_window_function(column, expression,
+ :sort_keys => @window_sort_keys,
+ :group_keys => @window_group_keys)
+ end
+ ensure
+ expression.close
+ end
+ end
+
+ private
+ def parse_type(type_raw)
+ return nil if type_raw.nil?
+
+ type = Context.instance[type_raw]
+ if type.nil?
+ message = "#{error_message_tag} unknown type: <#{type_raw}>"
+ raise InvalidArgument, message
+ end
+
+ case type
+ when Type, Table
+ type
+ else
+ message = "#{error_message_tag} invalid type: #{type.grn_inspect}"
+ raise InvalidArgument, message
+ end
+ end
+
+ def parse_flags(flags_raw)
+ Column.parse_flags(error_message_tag, flags_raw)
+ end
+
+ def error_message_tag
+ "[logical_select][columns][#{@stage}][#{@label}]"
+ end
+ end
+
+ class PlainDrilldownExecuteContext
+ include KeysParsable
+ include Calculatable
+
+ attr_reader :keys
+ attr_reader :offset
+ attr_reader :limit
+ attr_reader :sort_keys
+ attr_reader :output_columns
+ attr_reader :calc_target_name
+ attr_reader :calc_types
+ attr_reader :filter
+ attr_reader :result_sets
+ attr_reader :unsorted_result_sets
+ attr_reader :temporary_tables
+ attr_reader :expressions
+ def initialize(input)
+ @input = input
+ @keys = parse_keys(@input[:drilldown])
+ @offset = (@input[:drilldown_offset] || 0).to_i
+ @limit = (@input[:drilldown_limit] || 10).to_i
+ @sort_keys = parse_keys(@input[:drilldown_sort_keys] ||
+ @input[:drilldown_sortby])
+ @output_columns = @input[:drilldown_output_columns]
+ @output_columns ||= "_key, _nsubrecs"
+ @calc_target_name = @input[:drilldown_calc_target]
+ @calc_types = parse_calc_types(@input[:drilldown_calc_types])
+ @filter = @input[:drilldown_filter]
+
+ @result_sets = []
+ @unsorted_result_sets = []
+
+ @temporary_tables = []
+
+ @expressions = []
+ end
+
+ def close
+ @result_sets.each do |result_set|
+ result_set.close
+ end
+ @unsorted_result_sets.each do |result_set|
+ result_set.close
+ end
+
+ @temporary_tables.each do |table|
+ table.close
+ end
+
+ @expressions.each do |expression|
+ expression.close
+ end
+ end
+
+ def have_keys?
+ @keys.size > 0
+ end
+
+ def n_result_sets
+ @result_sets.size
+ end
+ end
+
+ class LabeledDrilldowns
+ include Enumerable
+ include TSort
+
+ class << self
+ def parse(input)
+ parser = LabeledArgumentParser.new(input)
+ drilldowns = parser.parse(/drilldowns?/)
+
+ contexts = {}
+ drilldowns.each do |label, parameters|
+ next if parameters["keys"].nil?
+ context = LabeledDrilldownExecuteContext.new(label, parameters)
+ contexts[label] = context
+ end
+
+ new(contexts)
+ end
+ end
+
+ def initialize(contexts)
+ @contexts = contexts
+ @dependencies = {}
+ @contexts.each do |label, context|
+ if context.table
+ depended_context = @contexts[context.table]
+ if depended_context.nil?
+ raise "Unknown drilldown: <#{context.table}>"
+ end
+ @dependencies[label] = [depended_context]
+ else
+ @dependencies[label] = []
+ end
+ end
+ end
+
+ def close
+ @contexts.each_value do |context|
+ context.close
+ end
+ end
+
+ def [](label)
+ @contexts[label]
+ end
+
+ def have_keys?
+ not @contexts.empty?
+ end
+
+ def n_result_sets
+ @contexts.size
+ end
+
+ def each(&block)
+ @contexts.each_value(&block)
+ end
+
+ def tsort_each_node(&block)
+ @contexts.each_value(&block)
+ end
+
+ def tsort_each_child(context, &block)
+ @dependencies[context.label].each(&block)
+ end
+ end
+
+ class LabeledDrilldownExecuteContext
+ include KeysParsable
+ include Calculatable
+
+ attr_reader :label
+ attr_reader :keys
+ attr_reader :offset
+ attr_reader :limit
+ attr_reader :sort_keys
+ attr_reader :output_columns
+ attr_reader :calc_target_name
+ attr_reader :calc_types
+ attr_reader :filter
+ attr_reader :table
+ attr_reader :dynamic_columns
+ attr_accessor :result_set
+ attr_accessor :unsorted_result_set
+ attr_reader :temporary_tables
+ attr_reader :expressions
+ def initialize(label, parameters)
+ @label = label
+ @keys = parse_keys(parameters["keys"])
+ @offset = (parameters["offset"] || 0).to_i
+ @limit = (parameters["limit"] || 10).to_i
+ @sort_keys = parse_keys(parameters["sort_keys"] ||
+ parameters["sortby"])
+ @output_columns = parameters["output_columns"]
+ @output_columns ||= "_key, _nsubrecs"
+ @calc_target_name = parameters["calc_target"]
+ @calc_types = parse_calc_types(parameters["calc_types"])
+ @filter = parameters["filter"]
+ @table = parameters["table"]
+
+ @dynamic_columns = DynamicColumns.parse(parameters)
+
+ @result_set = nil
+ @unsorted_result_set = nil
+
+ @temporary_tables = []
+
+ @expressions = []
+ end
+
+ def close
+ @result_set.close if @result_set
+ @unsorted_result_set.close if @unsorted_result_set
+
+ @dynamic_columns.close
+
+ @temporary_tables.each do |table|
+ table.close
+ end
+
+ @expressions.each do |expression|
+ expression.close
+ end
+ end
+
+ def need_command_version2?
+ /[.\[]/ === @output_columns
+ end
+
+ def output_columns_v2
+ columns = @output_columns.strip.split(/ *, */)
+ converted_columns = columns.collect do |column|
+ match_data = /\A_value\.(.+)\z/.match(column)
+ if match_data.nil?
+ column
+ else
+ nth_key = keys.index(match_data[1])
+ if nth_key
+ "_key[#{nth_key}]"
+ else
+ column
+ end
+ end
+ end
+ converted_columns.join(",")
+ end
+ end
+
+ class Executor
+ def initialize(context)
+ @context = context
+ end
+
+ def execute
+ execute_search
+ if @context.plain_drilldown.have_keys?
+ execute_plain_drilldown
+ elsif @context.labeled_drilldowns.have_keys?
+ execute_labeled_drilldowns
+ end
+ end
+
+ private
+ def execute_search
+ first_shard = nil
+ enumerator = @context.enumerator
+ enumerator.each do |shard, shard_range|
+ first_shard ||= shard
+ shard_executor = ShardExecutor.new(@context, shard, shard_range)
+ shard_executor.execute
+ end
+ if first_shard.nil?
+ message =
+ "[logical_select] no shard exists: " +
+ "logical_table: <#{enumerator.logical_table}>: " +
+ "shard_key: <#{enumerator.shard_key_name}>"
+ raise InvalidArgument, message
+ end
+ if @context.result_sets.empty?
+ result_set = HashTable.create(:flags => ObjectFlags::WITH_SUBREC,
+ :key_type => first_shard.table)
+ @context.dynamic_columns.each_initial do |dynamic_column|
+ dynamic_column.apply(result_set)
+ end
+ @context.dynamic_columns.each_filtered do |dynamic_column|
+ dynamic_column.apply(result_set)
+ end
+ @context.result_sets << result_set
+ end
+ end
+
+ def execute_plain_drilldown
+ drilldown = @context.plain_drilldown
+ group_result = TableGroupResult.new
+ begin
+ group_result.key_begin = 0
+ group_result.key_end = 0
+ group_result.limit = 1
+ group_result.flags = drilldown.calc_types
+ drilldown.keys.each do |key|
+ @context.result_sets.each do |result_set|
+ with_calc_target(group_result,
+ drilldown.calc_target(result_set)) do
+ result_set.group([key], group_result)
+ end
+ end
+ result_set = group_result.table
+ result_set = apply_drilldown_filter(drilldown, result_set)
+ if drilldown.sort_keys.empty?
+ drilldown.result_sets << result_set
+ else
+ drilldown.result_sets << result_set.sort(drilldown.sort_keys)
+ drilldown.unsorted_result_sets << result_set
+ end
+ group_result.table = nil
+ end
+ ensure
+ group_result.close
+ end
+ end
+
+ def execute_labeled_drilldowns
+ drilldowns = @context.labeled_drilldowns
+
+ drilldowns.tsort_each do |drilldown|
+ group_result = TableGroupResult.new
+ keys = drilldown.keys
+ begin
+ group_result.key_begin = 0
+ group_result.key_end = keys.size - 1
+ if keys.size > 1
+ group_result.max_n_sub_records = 1
+ end
+ group_result.limit = 1
+ group_result.flags = drilldown.calc_types
+ if drilldown.table
+ target_table = drilldowns[drilldown.table].result_set
+ with_calc_target(group_result,
+ drilldown.calc_target(target_table)) do
+ target_table.group(keys, group_result)
+ end
+ else
+ @context.result_sets.each do |result_set|
+ with_calc_target(group_result,
+ drilldown.calc_target(result_set)) do
+ result_set.group(keys, group_result)
+ end
+ end
+ end
+ result_set = group_result.table
+ drilldown.dynamic_columns.each_initial do |dynamic_column|
+ dynamic_column.apply(result_set)
+ end
+ result_set = apply_drilldown_filter(drilldown, result_set)
+ if drilldown.sort_keys.empty?
+ drilldown.result_set = result_set
+ else
+ drilldown.result_set = result_set.sort(drilldown.sort_keys)
+ drilldown.unsorted_result_set = result_set
+ end
+ group_result.table = nil
+ ensure
+ group_result.close
+ end
+ end
+ end
+
+ def with_calc_target(group_result, calc_target)
+ group_result.calc_target = calc_target
+ begin
+ yield
+ ensure
+ calc_target.close if calc_target
+ group_result.calc_target = nil
+ end
+ end
+
+ def apply_drilldown_filter(drilldown, result_set)
+ filter = drilldown.filter
+ return result_set if filter.nil?
+
+ expression = Expression.create(result_set)
+ drilldown.expressions << expression
+ expression.parse(filter)
+ filtered_result_set = result_set.select(expression)
+ drilldown.temporary_tables << result_set
+ filtered_result_set
+ end
+ end
+
+ class ShardExecutor
+ def initialize(context, shard, shard_range)
+ @context = context
+ @shard = shard
+ @shard_range = shard_range
+
+ @target_table = @shard.table
+
+ @match_columns = @context.match_columns
+ @query = @context.query
+ @filter = @context.filter
+ @sort_keys = @context.sort_keys
+ @result_sets = @context.result_sets
+ @unsorted_result_sets = @context.unsorted_result_sets
+
+ @target_range = @context.enumerator.target_range
+
+ @cover_type = @target_range.cover_type(@shard_range)
+ end
+
+ def execute
+ return if @cover_type == :none
+ return if @target_table.empty?
+
+ shard_key = @shard.key
+ if shard_key.nil?
+ message = "[logical_select] shard_key doesn't exist: " +
+ "<#{@shard.key_name}>"
+ raise InvalidArgument, message
+ end
+
+ @context.dynamic_columns.each_initial do |dynamic_column|
+ if @target_table == @shard.table
+ @target_table = create_all_match_table(@target_table)
+ @context.temporary_tables << @target_table
+ end
+ dynamic_column.apply(@target_table)
+ end
+
+ create_expression_builder(shard_key) do |expression_builder|
+ case @cover_type
+ when :all
+ filter_shard_all(expression_builder)
+ when :partial_min
+ filter_table do |expression|
+ expression_builder.build_partial_min(expression)
+ end
+ when :partial_max
+ filter_table do |expression|
+ expression_builder.build_partial_max(expression)
+ end
+ when :partial_min_and_max
+ filter_table do |expression|
+ expression_builder.build_partial_min_and_max(expression)
+ end
+ end
+ end
+ end
+
+ private
+ def filter_shard_all(expression_builder)
+ if @query.nil? and @filter.nil?
+ add_result_set(@target_table, nil)
+ @context.temporary_tables.delete(@target_table)
+ else
+ filter_table do |expression|
+ expression_builder.build_all(expression)
+ end
+ end
+ end
+
+ def create_expression(table)
+ expression = Expression.create(table)
+ @context.expressions << expression
+ expression
+ end
+
+ def create_expression_builder(shard_key)
+ expression_builder = RangeExpressionBuilder.new(shard_key,
+ @target_range)
+ expression_builder.match_columns = @match_columns
+ expression_builder.query = @query
+ expression_builder.filter = @filter
+ begin
+ yield(expression_builder)
+ ensure
+ expression = expression_builder.match_columns_expression
+ @context.expressions << expression if expression
+ end
+ end
+
+ def filter_table
+ table = @target_table
+ expression = create_expression(table)
+ yield(expression)
+ add_result_set(table.select(expression), expression)
+ end
+
+ def add_result_set(result_set, condition)
+ if result_set.empty?
+ result_set.close
+ return
+ end
+
+ @context.dynamic_columns.each_filtered do |dynamic_column|
+ if result_set == @shard.table
+ @context.temporary_tables << result_set
+ result_set = create_all_match_table(result_set)
+ end
+ dynamic_column.apply(result_set, condition)
+ end
+
+ if @sort_keys.empty?
+ @result_sets << result_set
+ else
+ @unsorted_result_sets << result_set
+ sorted_result_set = result_set.sort(@sort_keys)
+ @result_sets << sorted_result_set
+ end
+ end
+
+ def create_all_match_table(table)
+ expression = Expression.create(table)
+ begin
+ expression.append_constant(true, Operator::PUSH, 1)
+ table.select(expression)
+ ensure
+ expression.close
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_shard_list.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_shard_list.rb
new file mode 100644
index 00000000..b8ef3f76
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_shard_list.rb
@@ -0,0 +1,28 @@
+module Groonga
+ module Sharding
+ class LogicalShardListCommand < Command
+ register("logical_shard_list",
+ [
+ "logical_table",
+ ])
+
+ def run_body(input)
+ enumerator = LogicalEnumerator.new("logical_shard_list",
+ input,
+ :require_shard_key => false)
+ shard_names = enumerator.collect do |current_shard, shard_range|
+ current_shard.table_name
+ end
+
+ writer.array("shards", shard_names.size) do
+ shard_names.each do |shard_name|
+ writer.map("shard", 1) do
+ writer.write("name")
+ writer.write(shard_name)
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/logical_table_remove.rb b/storage/mroonga/vendor/groonga/plugins/sharding/logical_table_remove.rb
new file mode 100644
index 00000000..3353d6c3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/logical_table_remove.rb
@@ -0,0 +1,345 @@
+module Groonga
+ module Sharding
+ class LogicalTableRemoveCommand < Command
+ register("logical_table_remove",
+ [
+ "logical_table",
+ "shard_key",
+ "min",
+ "min_border",
+ "max",
+ "max_border",
+ "dependent",
+ "force",
+ ])
+
+ def run_body(input)
+ @dependent = (input[:dependent] == "yes")
+ @force = (input[:force] == "yes")
+
+ enumerator = LogicalEnumerator.new("logical_table_remove", input)
+
+ success = true
+ enumerator.each do |shard, shard_range|
+ remove_shard(shard, shard_range, enumerator.target_range)
+ end
+ writer.write(success)
+ end
+
+ private
+ def remove_shard(shard, shard_range, target_range)
+ cover_type = target_range.cover_type(shard_range)
+ return if cover_type == :none
+
+ shard_key = shard.key
+ if shard_key.nil?
+ if @force
+ context.clear_error
+ else
+ message =
+ "[logical_table_remove] shard_key doesn't exist: " +
+ "<#{shard.key_name}>"
+ raise InvalidArgument, message
+ end
+ end
+ table = shard.table
+
+ if cover_type == :all or ((table.nil? or shard_key.nil?) and @force)
+ remove_table(shard, table)
+ return
+ end
+
+ expression_builder = RangeExpressionBuilder.new(shard_key,
+ target_range)
+ case cover_type
+ when :partial_min
+ remove_records(table) do |expression|
+ expression_builder.build_partial_min(expression)
+ end
+ remove_table(shard, table) if table.empty?
+ when :partial_max
+ remove_records(table) do |expression|
+ expression_builder.build_partial_max(expression)
+ end
+ remove_table(shard, table) if table.empty?
+ when :partial_min_and_max
+ remove_records(table) do |expression|
+ expression_builder.build_partial_min_and_max(expression)
+ end
+ remove_table(shard, table) if table.empty?
+ end
+ end
+
+ def collect_referenced_table_ids_from_index_ids(index_ids,
+ referenced_table_ids)
+ database = context.database
+ index_ids.each do |index_id|
+ index = context[index_id]
+ if index.nil?
+ context.clear_error
+ index_name = database[index_id]
+ lexicon_name = index_name.split(".", 2)[0]
+ lexicon_id = database[lexicon_name]
+ referenced_table_ids << lexicon_id if lexicon_id
+ else
+ referenced_table_ids << index.domain_id
+ end
+ end
+ end
+
+ def collect_referenced_table_ids_from_column_name(column_name,
+ referenced_table_ids)
+ database = context.database
+ column_id = database[column_name]
+ database.each_raw do |id, cursor|
+ next if ID.builtin?(id)
+ next if id == column_id
+
+ context.open_temporary(id) do |object|
+ if object.nil?
+ context.clear_error
+ next
+ end
+
+ case object
+ when IndexColumn
+ if object.source_ids.include?(column_id)
+ collect_referenced_table_ids_from_index_ids([id],
+ referenced_table_ids)
+ end
+ end
+ end
+ end
+ end
+
+ def collect_referenced_table_ids_from_column(column,
+ referenced_table_ids)
+ range = column.range
+ case range
+ when nil
+ context.clear_error
+ when Table
+ referenced_table_ids << range.id
+ collect_referenced_table_ids_from_index_ids(range.index_ids,
+ referenced_table_ids)
+ end
+ collect_referenced_table_ids_from_index_ids(column.index_ids,
+ referenced_table_ids)
+ end
+
+ def collect_referenced_table_ids_from_column_names(column_names)
+ referenced_table_ids = []
+ column_names.each do |column_name|
+ column = context[column_name]
+ if column.nil?
+ context.clear_error
+ collect_referenced_table_ids_from_column_name(column_name,
+ referenced_table_ids)
+ else
+ collect_referenced_table_ids_from_column(column,
+ referenced_table_ids)
+ end
+ end
+ referenced_table_ids
+ end
+
+ def collect_referenced_table_ids(shard, table)
+ return [] unless @dependent
+
+ column_names = nil
+ if table
+ begin
+ column_names = table.columns.collect(&:name)
+ rescue
+ context.clear_error
+ end
+ end
+ if column_names.nil?
+ prefix = "#{shard.table_name}."
+ column_names = []
+ context.database.each_name(:prefix => prefix) do |column_name|
+ column_names << column_name
+ end
+ end
+
+ collect_referenced_table_ids_from_column_names(column_names)
+ end
+
+ def remove_table(shard, table)
+ if table.nil?
+ unless @force
+ if context.rc == Context::RC::SUCCESS.to_i
+ error_class = InvalidArgument
+ else
+ rc = Context::RC.find(context.rc)
+ error_class = rc.error_class
+ end
+ message = "[logical_table_remove] table is broken: " +
+ "<#{shard.table_name}>: #{context.error_message}"
+ raise error_class, message
+ end
+ context.clear_error
+ end
+
+ referenced_table_ids = collect_referenced_table_ids(shard, table)
+
+ if table.nil?
+ remove_table_force(shard.table_name)
+ else
+ options = {:dependent => @dependent}
+ if @force
+ begin
+ table.remove(options)
+ rescue
+ context.clear_error
+ table.close
+ remove_table_force(shard.table_name)
+ end
+ else
+ table.remove(options)
+ end
+ end
+
+ remove_referenced_tables(shard, referenced_table_ids)
+ end
+
+ def remove_table_force(table_name)
+ database = context.database
+
+ prefix = "#{table_name}."
+ database.each_raw(:prefix => prefix) do |id, cursor|
+ column = context[id]
+ if column.nil?
+ context.clear_error
+ column_name = cursor.key
+ remove_column_force(column_name)
+ table = context[table_name]
+ if table.nil?
+ context.clear_error
+ else
+ table.close
+ end
+ else
+ remove_column(column)
+ end
+ end
+
+ table_id = database[table_name]
+ return if table_id.nil?
+
+ database.each_raw do |id, cursor|
+ next if ID.builtin?(id)
+ next if id == table_id
+
+ context.open_temporary(id) do |object|
+ if object.nil?
+ context.clear_error
+ next
+ end
+
+ case object
+ when Table
+ if object.domain_id == table_id
+ begin
+ object.remove(:dependent => @dependent)
+ rescue
+ context.clear_error
+ reference_table_name = object.name
+ object.close
+ remove_table_force(reference_table_name)
+ end
+ end
+ when Column
+ if object.range_id == table_id
+ remove_column(object)
+ end
+ end
+ end
+ end
+
+ Object.remove_force(table_name)
+ end
+
+ def remove_column(column)
+ begin
+ column.remove(:dependent => @dependent)
+ rescue
+ context.clear_error
+ column_name = column.name
+ column.close
+ remove_column_force(column_name)
+ end
+ end
+
+ def remove_column_force(column_name)
+ database = context.database
+
+ column_id = database[column_name]
+
+ column = context[column_id]
+ if column.nil?
+ context.clear_error
+ else
+ column.index_ids.each do |id|
+ index_column = context[id]
+ if index_column.nil?
+ context.clear_error
+ index_column_name = database[id]
+ remove_column_force(index_column_name)
+ else
+ remove_column(index_column)
+ end
+ end
+ column.close
+ end
+
+ Object.remove_force(column_name)
+ end
+
+ def remove_referenced_tables(shard, referenced_table_ids)
+ return if referenced_table_ids.empty?
+
+ database = context.database
+ shard_suffix = shard.range_data.to_suffix
+ referenced_table_ids.uniq.each do |referenced_table_id|
+ referenced_table_name = database[referenced_table_id]
+ next if referenced_table_name.nil?
+ next unless referenced_table_name.end_with?(shard_suffix)
+
+ referenced_table = context[referenced_table_id]
+ if referenced_table.nil?
+ context.clear_error
+ if @force
+ Object.remove_force(referenced_table_name)
+ end
+ next
+ end
+
+ if @force
+ begin
+ referenced_table.remove(:dependent => @dependent)
+ rescue
+ context.clear_error
+ referenced_table.close
+ remove_table_force(referenced_table_name)
+ end
+ else
+ referenced_table.remove(:dependent => @dependent)
+ end
+ end
+ end
+
+ def remove_records(table)
+ expression = nil
+
+ begin
+ expression = Expression.create(table)
+ yield(expression)
+ table.delete(:expression => expression)
+ ensure
+ expression.close if expression
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/parameters.rb b/storage/mroonga/vendor/groonga/plugins/sharding/parameters.rb
new file mode 100644
index 00000000..b09a9d6c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/parameters.rb
@@ -0,0 +1,10 @@
+module Groonga
+ module Sharding
+ module Parameters
+ @range_index = :auto
+ class << self
+ attr_accessor :range_index
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/range_expression_builder.rb b/storage/mroonga/vendor/groonga/plugins/sharding/range_expression_builder.rb
new file mode 100644
index 00000000..cc80735d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/range_expression_builder.rb
@@ -0,0 +1,88 @@
+module Groonga
+ module Sharding
+ class RangeExpressionBuilder
+ attr_reader :match_columns_expression
+
+ attr_writer :match_columns
+ attr_writer :query
+ attr_writer :filter
+
+ def initialize(key, target_range)
+ @key = key
+ @target_range = target_range
+ @match_columns_expression = nil
+ @match_columns = nil
+ @query = nil
+ @filter = nil
+ end
+
+ def build_all(expression)
+ build_condition(expression)
+ end
+
+ def build_partial_min(expression)
+ expression.append_object(@key, Operator::PUSH, 1)
+ expression.append_operator(Operator::GET_VALUE, 1)
+ expression.append_constant(@target_range.min, Operator::PUSH, 1)
+ if @target_range.min_border == :include
+ expression.append_operator(Operator::GREATER_EQUAL, 2)
+ else
+ expression.append_operator(Operator::GREATER, 2)
+ end
+ build_condition(expression)
+ end
+
+ def build_partial_max(expression)
+ expression.append_object(@key, Operator::PUSH, 1)
+ expression.append_operator(Operator::GET_VALUE, 1)
+ expression.append_constant(@target_range.max, Operator::PUSH, 1)
+ if @target_range.max_border == :include
+ expression.append_operator(Operator::LESS_EQUAL, 2)
+ else
+ expression.append_operator(Operator::LESS, 2)
+ end
+ build_condition(expression)
+ end
+
+ def build_partial_min_and_max(expression)
+ between = Groonga::Context.instance["between"]
+ expression.append_object(between, Operator::PUSH, 1)
+ expression.append_object(@key, Operator::PUSH, 1)
+ expression.append_operator(Operator::GET_VALUE, 1)
+ expression.append_constant(@target_range.min, Operator::PUSH, 1)
+ expression.append_constant(@target_range.min_border,
+ Operator::PUSH, 1)
+ expression.append_constant(@target_range.max, Operator::PUSH, 1)
+ expression.append_constant(@target_range.max_border,
+ Operator::PUSH, 1)
+ expression.append_operator(Operator::CALL, 5)
+ build_condition(expression)
+ end
+
+ private
+ def build_condition(expression)
+ if @query
+ is_empty = expression.empty?
+ if @match_columns
+ table = Context.instance[expression[0].domain]
+ @match_columns_expression = Expression.create(table)
+ @match_columns_expression.parse(@match_columns)
+ end
+ flags = Expression::SYNTAX_QUERY |
+ Expression::ALLOW_PRAGMA |
+ Expression::ALLOW_COLUMN
+ expression.parse(@query,
+ default_column: @match_columns_expression,
+ flags: flags)
+ expression.append_operator(Operator::AND, 2) unless is_empty
+ end
+
+ if @filter
+ is_empty = expression.empty?
+ expression.parse(@filter)
+ expression.append_operator(Operator::AND, 2) unless is_empty
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/plugins/sharding/sources.am b/storage/mroonga/vendor/groonga/plugins/sharding/sources.am
new file mode 100644
index 00000000..df2b6d02
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/sharding/sources.am
@@ -0,0 +1,10 @@
+sharding_scripts = \
+ logical_count.rb \
+ logical_enumerator.rb \
+ logical_parameters.rb \
+ logical_range_filter.rb \
+ logical_select.rb \
+ logical_shard_list.rb \
+ logical_table_remove.rb \
+ parameters.rb \
+ range_expression_builder.rb
diff --git a/storage/mroonga/vendor/groonga/plugins/suggest/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/suggest/CMakeLists.txt
new file mode 100644
index 00000000..8b287e65
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/suggest/CMakeLists.txt
@@ -0,0 +1,36 @@
+# Copyright(C) 2012-2013 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib
+ ${MRUBY_INCLUDE_DIRS}
+ ${MESSAGE_PACK_INCLUDE_DIRS})
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/sources.am SUGGEST_SOURCES)
+set_source_files_properties(${SUGGEST_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(suggest STATIC ${SUGGEST_SOURCES})
+ set_target_properties(
+ suggest
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(suggest MODULE ${SUGGEST_SOURCES})
+ set_target_properties(suggest PROPERTIES PREFIX "")
+ install(TARGETS suggest DESTINATION "${GRN_RELATIVE_PLUGINS_DIR}/suggest")
+endif()
+target_link_libraries(suggest libgroonga)
diff --git a/storage/mroonga/vendor/groonga/plugins/suggest/Makefile.am b/storage/mroonga/vendor/groonga/plugins/suggest/Makefile.am
new file mode 100644
index 00000000..7f321b6c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/suggest/Makefile.am
@@ -0,0 +1,24 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CFLAGS = \
+ $(MESSAGE_PACK_CFLAGS) \
+ $(MRUBY_CFLAGS)
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -no-undefined
+
+LIBS = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(MESSAGE_PACK_LIBS)
+
+suggest_plugins_LTLIBRARIES = suggest.la
+
+include sources.am
diff --git a/storage/mroonga/vendor/groonga/plugins/suggest/sources.am b/storage/mroonga/vendor/groonga/plugins/suggest/sources.am
new file mode 100644
index 00000000..798a431a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/suggest/sources.am
@@ -0,0 +1,2 @@
+suggest_la_SOURCES = \
+ suggest.c
diff --git a/storage/mroonga/vendor/groonga/plugins/suggest/suggest.c b/storage/mroonga/vendor/groonga/plugins/suggest/suggest.c
new file mode 100644
index 00000000..7f64f3c1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/suggest/suggest.c
@@ -0,0 +1,1035 @@
+/* -*- c-basic-offset: 2; indent-tabs-mode: nil -*- */
+/* Copyright(C) 2010-2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG suggest_suggest
+#endif
+
+#include <string.h>
+
+#include "grn_ctx.h"
+#include "grn_db.h"
+#include "grn_ii.h"
+#include "grn_token_cursor.h"
+#include "grn_output.h"
+#include <groonga/plugin.h>
+
+#define VAR GRN_PROC_GET_VAR_BY_OFFSET
+#define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
+#define TEXT_VALUE_LEN(x) GRN_TEXT_VALUE(x), GRN_TEXT_LEN(x)
+
+#define MIN_LEARN_DISTANCE (60 * GRN_TIME_USEC_PER_SEC)
+
+#define COMPLETE 1
+#define CORRECT 2
+#define SUGGEST 4
+
+typedef enum {
+ GRN_SUGGEST_SEARCH_YES,
+ GRN_SUGGEST_SEARCH_NO,
+ GRN_SUGGEST_SEARCH_AUTO
+} grn_suggest_search_mode;
+
+typedef struct {
+ grn_obj *post_event;
+ grn_obj *post_type;
+ grn_obj *post_item;
+ grn_obj *seq;
+ grn_obj *post_time;
+ grn_obj *pairs;
+
+ int learn_distance_in_seconds;
+
+ grn_id post_event_id;
+ grn_id post_type_id;
+ grn_id post_item_id;
+ grn_id seq_id;
+ int64_t post_time_value;
+
+ grn_obj *seqs;
+ grn_obj *seqs_events;
+ grn_obj *events;
+ grn_obj *events_item;
+ grn_obj *events_type;
+ grn_obj *events_time;
+ grn_obj *event_types;
+ grn_obj *items;
+ grn_obj *items_freq;
+ grn_obj *items_freq2;
+ grn_obj *items_last;
+ grn_obj *pairs_pre;
+ grn_obj *pairs_post;
+ grn_obj *pairs_freq0;
+ grn_obj *pairs_freq1;
+ grn_obj *pairs_freq2;
+
+ grn_obj dataset_name;
+
+ grn_obj *configuration;
+
+ grn_obj weight;
+ grn_obj pre_events;
+
+ uint64_t key_prefix;
+ grn_obj pre_item;
+} grn_suggest_learner;
+
+static int
+grn_parse_suggest_types(grn_obj *text)
+{
+ const char *nptr = GRN_TEXT_VALUE(text);
+ const char *end = GRN_BULK_CURR(text);
+ int types = 0;
+ while (nptr < end) {
+ if (*nptr == '|') {
+ nptr += 1;
+ continue;
+ }
+ {
+ const char string[] = "complete";
+ size_t length = sizeof(string) - 1;
+ if (nptr + length <= end && memcmp(nptr, string, length) == 0) {
+ types |= COMPLETE;
+ nptr += length;
+ continue;
+ }
+ }
+ {
+ const char string[] = "correct";
+ size_t length = sizeof(string) - 1;
+ if (nptr + length <= end && memcmp(nptr, string, length) == 0) {
+ types |= CORRECT;
+ nptr += length;
+ continue;
+ }
+ }
+ {
+ const char string[] = "suggest";
+ size_t length = sizeof(string) - 1;
+ if (nptr + length <= end && memcmp(nptr, string, length) == 0) {
+ types |= SUGGEST;
+ nptr += length;
+ continue;
+ }
+ }
+ break;
+ }
+ return types;
+}
+
+static double
+cooccurrence_search(grn_ctx *ctx, grn_obj *items, grn_obj *items_boost, grn_id id,
+ grn_obj *res, int query_type, int frequency_threshold,
+ double conditional_probability_threshold)
+{
+ double max_score = 0.0;
+ if (id) {
+ grn_ii_cursor *c;
+ grn_obj *co = grn_obj_column(ctx, items, CONST_STR_LEN("co"));
+ grn_obj *pairs = grn_ctx_at(ctx, grn_obj_get_range(ctx, co));
+ grn_obj *items_freq = grn_obj_column(ctx, items, CONST_STR_LEN("freq"));
+ grn_obj *items_freq2 = grn_obj_column(ctx, items, CONST_STR_LEN("freq2"));
+ grn_obj *pairs_freq, *pairs_post = grn_obj_column(ctx, pairs, CONST_STR_LEN("post"));
+ switch (query_type) {
+ case COMPLETE :
+ pairs_freq = grn_obj_column(ctx, pairs, CONST_STR_LEN("freq0"));
+ break;
+ case CORRECT :
+ pairs_freq = grn_obj_column(ctx, pairs, CONST_STR_LEN("freq1"));
+ break;
+ case SUGGEST :
+ pairs_freq = grn_obj_column(ctx, pairs, CONST_STR_LEN("freq2"));
+ break;
+ default :
+ return max_score;
+ }
+ if ((c = grn_ii_cursor_open(ctx, (grn_ii *)co, id, GRN_ID_NIL, GRN_ID_MAX,
+ ((grn_ii *)co)->n_elements - 1, 0))) {
+ grn_posting *p;
+ grn_obj post, pair_freq, item_freq, item_freq2, item_boost;
+ GRN_RECORD_INIT(&post, 0, grn_obj_id(ctx, items));
+ GRN_INT32_INIT(&pair_freq, 0);
+ GRN_INT32_INIT(&item_freq, 0);
+ GRN_INT32_INIT(&item_freq2, 0);
+ GRN_INT32_INIT(&item_boost, 0);
+ while ((p = grn_ii_cursor_next(ctx, c))) {
+ grn_id post_id;
+ int pfreq, ifreq, ifreq2, boost;
+ double conditional_probability;
+ GRN_BULK_REWIND(&post);
+ GRN_BULK_REWIND(&pair_freq);
+ GRN_BULK_REWIND(&item_freq);
+ GRN_BULK_REWIND(&item_freq2);
+ GRN_BULK_REWIND(&item_boost);
+ grn_obj_get_value(ctx, pairs_post, p->rid, &post);
+ grn_obj_get_value(ctx, pairs_freq, p->rid, &pair_freq);
+ post_id = GRN_RECORD_VALUE(&post);
+ grn_obj_get_value(ctx, items_freq, post_id, &item_freq);
+ grn_obj_get_value(ctx, items_freq2, post_id, &item_freq2);
+ grn_obj_get_value(ctx, items_boost, post_id, &item_boost);
+ pfreq = GRN_INT32_VALUE(&pair_freq);
+ ifreq = GRN_INT32_VALUE(&item_freq);
+ ifreq2 = GRN_INT32_VALUE(&item_freq2);
+ if (ifreq2 > 0) {
+ conditional_probability = (double)pfreq / (double)ifreq2;
+ } else {
+ conditional_probability = 0.0;
+ }
+ boost = GRN_INT32_VALUE(&item_boost);
+ if (pfreq >= frequency_threshold && ifreq >= frequency_threshold &&
+ conditional_probability >= conditional_probability_threshold &&
+ boost >= 0) {
+ grn_rset_recinfo *ri;
+ void *value;
+ double score = pfreq;
+ int added;
+ if (max_score < score + boost) { max_score = score + boost; }
+ /* put any formula if desired */
+ if (grn_hash_add(ctx, (grn_hash *)res,
+ &post_id, sizeof(grn_id), &value, &added)) {
+ ri = value;
+ ri->score += score;
+ if (added) {
+ ri->score += boost;
+ }
+ }
+ }
+ }
+ GRN_OBJ_FIN(ctx, &post);
+ GRN_OBJ_FIN(ctx, &pair_freq);
+ GRN_OBJ_FIN(ctx, &item_freq);
+ GRN_OBJ_FIN(ctx, &item_freq2);
+ GRN_OBJ_FIN(ctx, &item_boost);
+ grn_ii_cursor_close(ctx, c);
+ }
+ }
+ return max_score;
+}
+
+#define DEFAULT_LIMIT 10
+#define DEFAULT_SORTBY "-_score"
+#define DEFAULT_OUTPUT_COLUMNS "_key,_score"
+#define DEFAULT_FREQUENCY_THRESHOLD 100
+#define DEFAULT_CONDITIONAL_PROBABILITY_THRESHOLD 0.2
+
+static void
+output(grn_ctx *ctx, grn_obj *table, grn_obj *res, grn_id tid,
+ grn_obj *sortby, grn_obj *output_columns, int offset, int limit)
+{
+ grn_obj *sorted;
+ if ((sorted = grn_table_create(ctx, NULL, 0, NULL, GRN_OBJ_TABLE_NO_KEY, NULL, res))) {
+ uint32_t nkeys;
+ grn_obj_format format;
+ grn_table_sort_key *keys;
+ const char *sortby_val = GRN_TEXT_VALUE(sortby);
+ unsigned int sortby_len = GRN_TEXT_LEN(sortby);
+ const char *oc_val = GRN_TEXT_VALUE(output_columns);
+ unsigned int oc_len = GRN_TEXT_LEN(output_columns);
+ if (!sortby_val || !sortby_len) {
+ sortby_val = DEFAULT_SORTBY;
+ sortby_len = sizeof(DEFAULT_SORTBY) - 1;
+ }
+ if (!oc_val || !oc_len) {
+ oc_val = DEFAULT_OUTPUT_COLUMNS;
+ oc_len = sizeof(DEFAULT_OUTPUT_COLUMNS) - 1;
+ }
+ if ((keys = grn_table_sort_key_from_str(ctx, sortby_val, sortby_len, res, &nkeys))) {
+ grn_table_sort(ctx, res, offset, limit, sorted, keys, nkeys);
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "sort(%d)", limit);
+ GRN_OBJ_FORMAT_INIT(&format, grn_table_size(ctx, res), 0, limit, offset);
+ format.flags =
+ GRN_OBJ_FORMAT_WITH_COLUMN_NAMES|
+ GRN_OBJ_FORMAT_XML_ELEMENT_RESULTSET;
+ grn_obj_columns(ctx, sorted, oc_val, oc_len, &format.columns);
+ GRN_OUTPUT_OBJ(sorted, &format);
+ GRN_OBJ_FORMAT_FIN(ctx, &format);
+ grn_table_sort_key_close(ctx, keys, nkeys);
+ }
+ grn_obj_unlink(ctx, sorted);
+ } else {
+ ERR(GRN_UNKNOWN_ERROR, "cannot create temporary sort table.");
+ }
+}
+
+static inline void
+complete_add_item(grn_ctx *ctx, grn_id id, grn_obj *res, int frequency_threshold,
+ grn_obj *items_freq, grn_obj *items_boost,
+ grn_obj *item_freq, grn_obj *item_boost)
+{
+ GRN_BULK_REWIND(item_freq);
+ GRN_BULK_REWIND(item_boost);
+ grn_obj_get_value(ctx, items_freq, id, item_freq);
+ grn_obj_get_value(ctx, items_boost, id, item_boost);
+ if (GRN_INT32_VALUE(item_boost) >= 0) {
+ double score;
+ score = 1 +
+ GRN_INT32_VALUE(item_freq) +
+ GRN_INT32_VALUE(item_boost);
+ if (score >= frequency_threshold) {
+ void *value;
+ if (grn_hash_add(ctx, (grn_hash *)res, &id, sizeof(grn_id),
+ &value, NULL)) {
+ grn_rset_recinfo *ri;
+ ri = value;
+ ri->score += score;
+ }
+ }
+ }
+}
+
+static void
+complete(grn_ctx *ctx, grn_obj *items, grn_obj *items_boost, grn_obj *col,
+ grn_obj *query, grn_obj *sortby,
+ grn_obj *output_columns, int offset, int limit,
+ int frequency_threshold, double conditional_probability_threshold,
+ grn_suggest_search_mode prefix_search_mode)
+{
+ grn_obj *res;
+ grn_obj *items_freq = grn_obj_column(ctx, items, CONST_STR_LEN("freq"));
+ grn_obj item_freq, item_boost;
+ GRN_INT32_INIT(&item_freq, 0);
+ GRN_INT32_INIT(&item_boost, 0);
+ if ((res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, items, NULL))) {
+ grn_id tid = grn_table_get(ctx, items, TEXT_VALUE_LEN(query));
+ if (GRN_TEXT_LEN(query)) {
+ grn_table_cursor *cur;
+ /* RK search + prefix search */
+ grn_obj *index;
+ /* FIXME: support index selection */
+ if (grn_column_index(ctx, col, GRN_OP_PREFIX, &index, 1, NULL)) {
+ if ((cur = grn_table_cursor_open(ctx, grn_ctx_at(ctx, index->header.domain),
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query),
+ NULL, 0, 0, -1,
+ GRN_CURSOR_PREFIX|GRN_CURSOR_RK))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, cur))) {
+ grn_ii_cursor *icur;
+ if ((icur = grn_ii_cursor_open(ctx, (grn_ii *)index, id,
+ GRN_ID_NIL, GRN_ID_MAX, 1, 0))) {
+ grn_posting *p;
+ while ((p = grn_ii_cursor_next(ctx, icur))) {
+ complete_add_item(ctx, p->rid, res, frequency_threshold,
+ items_freq, items_boost,
+ &item_freq, &item_boost);
+ }
+ grn_ii_cursor_close(ctx, icur);
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ } else {
+ ERR(GRN_UNKNOWN_ERROR, "cannot open cursor for prefix RK search.");
+ }
+ } else {
+ ERR(GRN_UNKNOWN_ERROR, "cannot find index for prefix RK search.");
+ }
+ cooccurrence_search(ctx, items, items_boost, tid, res, COMPLETE,
+ frequency_threshold,
+ conditional_probability_threshold);
+ if (((prefix_search_mode == GRN_SUGGEST_SEARCH_YES) ||
+ (prefix_search_mode == GRN_SUGGEST_SEARCH_AUTO &&
+ !grn_table_size(ctx, res))) &&
+ (cur = grn_table_cursor_open(ctx, items,
+ GRN_TEXT_VALUE(query),
+ GRN_TEXT_LEN(query),
+ NULL, 0, 0, -1, GRN_CURSOR_PREFIX))) {
+ grn_id id;
+ while ((id = grn_table_cursor_next(ctx, cur))) {
+ complete_add_item(ctx, id, res, frequency_threshold,
+ items_freq, items_boost, &item_freq, &item_boost);
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+ }
+ output(ctx, items, res, tid, sortby, output_columns, offset, limit);
+ grn_obj_close(ctx, res);
+ } else {
+ ERR(GRN_UNKNOWN_ERROR, "cannot create temporary table.");
+ }
+ GRN_OBJ_FIN(ctx, &item_boost);
+ GRN_OBJ_FIN(ctx, &item_freq);
+}
+
+static void
+correct(grn_ctx *ctx, grn_obj *items, grn_obj *items_boost,
+ grn_obj *query, grn_obj *sortby,
+ grn_obj *output_columns, int offset, int limit,
+ int frequency_threshold, double conditional_probability_threshold,
+ grn_suggest_search_mode similar_search_mode)
+{
+ grn_obj *res;
+ grn_obj *items_freq2 = grn_obj_column(ctx, items, CONST_STR_LEN("freq2"));
+ grn_obj item_freq2, item_boost;
+ GRN_INT32_INIT(&item_freq2, 0);
+ GRN_INT32_INIT(&item_boost, 0);
+ if ((res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, items, NULL))) {
+ grn_id tid = grn_table_get(ctx, items, TEXT_VALUE_LEN(query));
+ double max_score;
+ max_score = cooccurrence_search(ctx, items, items_boost, tid, res, CORRECT,
+ frequency_threshold,
+ conditional_probability_threshold);
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SCORE,
+ ":", "cooccur(%f)", max_score);
+ if (GRN_TEXT_LEN(query) &&
+ ((similar_search_mode == GRN_SUGGEST_SEARCH_YES) ||
+ (similar_search_mode == GRN_SUGGEST_SEARCH_AUTO &&
+ max_score < frequency_threshold))) {
+ grn_obj *key, *index;
+ if ((key = grn_obj_column(ctx, items,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN))) {
+ if (grn_column_index(ctx, key, GRN_OP_MATCH, &index, 1, NULL)) {
+ grn_select_optarg optarg;
+ memset(&optarg, 0, sizeof(grn_select_optarg));
+ optarg.mode = GRN_OP_SIMILAR;
+ optarg.similarity_threshold = 0;
+ optarg.max_size = 2;
+ grn_ii_select(ctx, (grn_ii *)index, TEXT_VALUE_LEN(query),
+ (grn_hash *)res, GRN_OP_OR, &optarg);
+ grn_obj_unlink(ctx, index);
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "similar(%d)", grn_table_size(ctx, res));
+ {
+ grn_hash_cursor *hc = grn_hash_cursor_open(ctx, (grn_hash *)res, NULL,
+ 0, NULL, 0, 0, -1, 0);
+ if (hc) {
+ while (grn_hash_cursor_next(ctx, hc)) {
+ void *key, *value;
+ if (grn_hash_cursor_get_key_value(ctx, hc, &key, NULL, &value)) {
+ grn_id *rp;
+ rp = key;
+ GRN_BULK_REWIND(&item_freq2);
+ GRN_BULK_REWIND(&item_boost);
+ grn_obj_get_value(ctx, items_freq2, *rp, &item_freq2);
+ grn_obj_get_value(ctx, items_boost, *rp, &item_boost);
+ if (GRN_INT32_VALUE(&item_boost) >= 0) {
+ double score;
+ grn_rset_recinfo *ri;
+ score = 1 +
+ (GRN_INT32_VALUE(&item_freq2) >> 4) +
+ GRN_INT32_VALUE(&item_boost);
+ ri = value;
+ ri->score += score;
+ if (score >= frequency_threshold) { continue; }
+ }
+ /* score < frequency_threshold || item_boost < 0 */
+ grn_hash_cursor_delete(ctx, hc, NULL);
+ }
+ }
+ grn_hash_cursor_close(ctx, hc);
+ }
+ }
+ GRN_QUERY_LOG(ctx, GRN_QUERY_LOG_SIZE,
+ ":", "filter(%d)", grn_table_size(ctx, res));
+ {
+ /* exec _score -= edit_distance(_key, "query string") for all records */
+ grn_obj *var;
+ grn_obj *expr;
+
+ GRN_EXPR_CREATE_FOR_QUERY(ctx, res, expr, var);
+ if (expr) {
+ grn_table_cursor *tc;
+ grn_obj *score = grn_obj_column(ctx, res,
+ GRN_COLUMN_NAME_SCORE,
+ GRN_COLUMN_NAME_SCORE_LEN);
+ grn_obj *key = grn_obj_column(ctx, res,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ grn_expr_append_obj(ctx, expr,
+ score,
+ GRN_OP_GET_VALUE, 1);
+ grn_expr_append_obj(ctx, expr,
+ grn_ctx_get(ctx, CONST_STR_LEN("edit_distance")),
+ GRN_OP_PUSH, 1);
+ grn_expr_append_obj(ctx, expr,
+ key,
+ GRN_OP_GET_VALUE, 1);
+ grn_expr_append_const(ctx, expr, query, GRN_OP_PUSH, 1);
+ grn_expr_append_op(ctx, expr, GRN_OP_CALL, 2);
+ grn_expr_append_op(ctx, expr, GRN_OP_MINUS_ASSIGN, 2);
+
+ if ((tc = grn_table_cursor_open(ctx, res, NULL, 0, NULL, 0, 0, -1, 0))) {
+ grn_id id;
+ grn_obj score_value;
+ GRN_FLOAT_INIT(&score_value, 0);
+ while ((id = grn_table_cursor_next(ctx, tc)) != GRN_ID_NIL) {
+ GRN_RECORD_SET(ctx, var, id);
+ grn_expr_exec(ctx, expr, 0);
+ GRN_BULK_REWIND(&score_value);
+ grn_obj_get_value(ctx, score, id, &score_value);
+ if (GRN_FLOAT_VALUE(&score_value) < frequency_threshold) {
+ grn_table_cursor_delete(ctx, tc);
+ }
+ }
+ grn_obj_unlink(ctx, &score_value);
+ grn_table_cursor_close(ctx, tc);
+ }
+ grn_obj_unlink(ctx, score);
+ grn_obj_unlink(ctx, key);
+ grn_obj_unlink(ctx, expr);
+ } else {
+ ERR(GRN_UNKNOWN_ERROR,
+ "error on building expr. for calicurating edit distance");
+ }
+ }
+ }
+ grn_obj_unlink(ctx, key);
+ }
+ }
+ output(ctx, items, res, tid, sortby, output_columns, offset, limit);
+ grn_obj_close(ctx, res);
+ } else {
+ ERR(GRN_UNKNOWN_ERROR, "cannot create temporary table.");
+ }
+ GRN_OBJ_FIN(ctx, &item_boost);
+ GRN_OBJ_FIN(ctx, &item_freq2);
+}
+
+static void
+suggest(grn_ctx *ctx, grn_obj *items, grn_obj *items_boost,
+ grn_obj *query, grn_obj *sortby,
+ grn_obj *output_columns, int offset, int limit,
+ int frequency_threshold, double conditional_probability_threshold)
+{
+ grn_obj *res;
+ if ((res = grn_table_create(ctx, NULL, 0, NULL,
+ GRN_TABLE_HASH_KEY|GRN_OBJ_WITH_SUBREC, items, NULL))) {
+ grn_id tid = grn_table_get(ctx, items, TEXT_VALUE_LEN(query));
+ cooccurrence_search(ctx, items, items_boost, tid, res, SUGGEST,
+ frequency_threshold, conditional_probability_threshold);
+ output(ctx, items, res, tid, sortby, output_columns, offset, limit);
+ grn_obj_close(ctx, res);
+ } else {
+ ERR(GRN_UNKNOWN_ERROR, "cannot create temporary table.");
+ }
+}
+
+static grn_suggest_search_mode
+parse_search_mode(grn_ctx *ctx, grn_obj *mode_text)
+{
+ grn_suggest_search_mode mode;
+ int mode_length;
+
+ mode_length = GRN_TEXT_LEN(mode_text);
+ if (mode_length == 3 &&
+ grn_strncasecmp("yes", GRN_TEXT_VALUE(mode_text), 3) == 0) {
+ mode = GRN_SUGGEST_SEARCH_YES;
+ } else if (mode_length == 2 &&
+ grn_strncasecmp("no", GRN_TEXT_VALUE(mode_text), 2) == 0) {
+ mode = GRN_SUGGEST_SEARCH_NO;
+ } else {
+ mode = GRN_SUGGEST_SEARCH_AUTO;
+ }
+
+ return mode;
+}
+
+static grn_obj *
+command_suggest(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_obj *items, *col, *items_boost;
+ int types;
+ int offset = 0;
+ int limit = DEFAULT_LIMIT;
+ int frequency_threshold = DEFAULT_FREQUENCY_THRESHOLD;
+ double conditional_probability_threshold =
+ DEFAULT_CONDITIONAL_PROBABILITY_THRESHOLD;
+ grn_suggest_search_mode prefix_search_mode;
+ grn_suggest_search_mode similar_search_mode;
+
+ types = grn_parse_suggest_types(VAR(0));
+ if (GRN_TEXT_LEN(VAR(6)) > 0) {
+ offset = grn_atoi(GRN_TEXT_VALUE(VAR(6)), GRN_BULK_CURR(VAR(6)), NULL);
+ }
+ if (GRN_TEXT_LEN(VAR(7)) > 0) {
+ limit = grn_atoi(GRN_TEXT_VALUE(VAR(7)), GRN_BULK_CURR(VAR(7)), NULL);
+ }
+ if (GRN_TEXT_LEN(VAR(8)) > 0) {
+ frequency_threshold = grn_atoi(GRN_TEXT_VALUE(VAR(8)), GRN_BULK_CURR(VAR(8)), NULL);
+ }
+ if (GRN_TEXT_LEN(VAR(9)) > 0) {
+ GRN_TEXT_PUTC(ctx, VAR(9), '\0');
+ conditional_probability_threshold = strtod(GRN_TEXT_VALUE(VAR(9)), NULL);
+ }
+
+ prefix_search_mode = parse_search_mode(ctx, VAR(10));
+ similar_search_mode = parse_search_mode(ctx, VAR(11));
+
+ if ((items = grn_ctx_get(ctx, TEXT_VALUE_LEN(VAR(1))))) {
+ if ((items_boost = grn_obj_column(ctx, items, CONST_STR_LEN("boost")))) {
+ int n_outputs = 0;
+ if (types & COMPLETE) {
+ n_outputs++;
+ }
+ if (types & CORRECT) {
+ n_outputs++;
+ }
+ if (types & SUGGEST) {
+ n_outputs++;
+ }
+ GRN_OUTPUT_MAP_OPEN("RESULT_SET", n_outputs);
+
+ if (types & COMPLETE) {
+ if ((col = grn_obj_column(ctx, items, TEXT_VALUE_LEN(VAR(2))))) {
+ GRN_OUTPUT_CSTR("complete");
+ complete(ctx, items, items_boost, col, VAR(3), VAR(4),
+ VAR(5), offset, limit,
+ frequency_threshold, conditional_probability_threshold,
+ prefix_search_mode);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "invalid column.");
+ }
+ }
+ if (types & CORRECT) {
+ GRN_OUTPUT_CSTR("correct");
+ correct(ctx, items, items_boost, VAR(3), VAR(4),
+ VAR(5), offset, limit,
+ frequency_threshold, conditional_probability_threshold,
+ similar_search_mode);
+ }
+ if (types & SUGGEST) {
+ GRN_OUTPUT_CSTR("suggest");
+ suggest(ctx, items, items_boost, VAR(3), VAR(4),
+ VAR(5), offset, limit,
+ frequency_threshold, conditional_probability_threshold);
+ }
+ GRN_OUTPUT_MAP_CLOSE();
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "nonexistent column: <%.*s.boost>",
+ (int)GRN_TEXT_LEN(VAR(1)), GRN_TEXT_VALUE(VAR(1)));
+ }
+ grn_obj_unlink(ctx, items);
+ } else {
+ ERR(GRN_INVALID_ARGUMENT, "nonexistent table: <%.*s>",
+ (int)GRN_TEXT_LEN(VAR(1)), GRN_TEXT_VALUE(VAR(1)));
+ }
+ return NULL;
+}
+
+static void
+learner_init_values(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ learner->post_event_id = GRN_RECORD_VALUE(learner->post_event);
+ learner->post_type_id = GRN_RECORD_VALUE(learner->post_type);
+ learner->post_item_id = GRN_RECORD_VALUE(learner->post_item);
+ learner->seq_id = GRN_RECORD_VALUE(learner->seq);
+ learner->post_time_value = GRN_TIME_VALUE(learner->post_time);
+}
+
+static void
+learner_init(grn_ctx *ctx, grn_suggest_learner *learner,
+ grn_obj *post_event, grn_obj *post_type, grn_obj *post_item,
+ grn_obj *seq, grn_obj *post_time, grn_obj *pairs)
+{
+ learner->post_event = post_event;
+ learner->post_type = post_type;
+ learner->post_item = post_item;
+ learner->seq = seq;
+ learner->post_time = post_time;
+ learner->pairs = pairs;
+
+ learner->learn_distance_in_seconds = 0;
+
+ learner_init_values(ctx, learner);
+}
+
+static void
+learner_init_columns(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_id events_id, event_types_id;
+ grn_obj *seqs, *events, *post_item, *items, *pairs;
+
+ learner->seqs = seqs = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(learner->seq));
+ learner->seqs_events = grn_obj_column(ctx, seqs, CONST_STR_LEN("events"));
+
+ events_id = grn_obj_get_range(ctx, learner->seqs_events);
+ learner->events = events = grn_ctx_at(ctx, events_id);
+ learner->events_item = grn_obj_column(ctx, events, CONST_STR_LEN("item"));
+ learner->events_type = grn_obj_column(ctx, events, CONST_STR_LEN("type"));
+ learner->events_time = grn_obj_column(ctx, events, CONST_STR_LEN("time"));
+
+ event_types_id = grn_obj_get_range(ctx, learner->events_type);
+ learner->event_types = grn_obj_column(ctx, events, CONST_STR_LEN("time"));
+
+ post_item = learner->post_item;
+ learner->items = items = grn_ctx_at(ctx, GRN_OBJ_GET_DOMAIN(post_item));
+ learner->items_freq = grn_obj_column(ctx, items, CONST_STR_LEN("freq"));
+ learner->items_freq2 = grn_obj_column(ctx, items, CONST_STR_LEN("freq2"));
+ learner->items_last = grn_obj_column(ctx, items, CONST_STR_LEN("last"));
+
+ pairs = learner->pairs;
+ learner->pairs_pre = grn_obj_column(ctx, pairs, CONST_STR_LEN("pre"));
+ learner->pairs_post = grn_obj_column(ctx, pairs, CONST_STR_LEN("post"));
+ learner->pairs_freq0 = grn_obj_column(ctx, pairs, CONST_STR_LEN("freq0"));
+ learner->pairs_freq1 = grn_obj_column(ctx, pairs, CONST_STR_LEN("freq1"));
+ learner->pairs_freq2 = grn_obj_column(ctx, pairs, CONST_STR_LEN("freq2"));
+}
+
+static void
+learner_fin_columns(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_obj_unlink(ctx, learner->seqs);
+ grn_obj_unlink(ctx, learner->seqs_events);
+
+ grn_obj_unlink(ctx, learner->events);
+ grn_obj_unlink(ctx, learner->events_item);
+ grn_obj_unlink(ctx, learner->events_type);
+ grn_obj_unlink(ctx, learner->events_time);
+
+ grn_obj_unlink(ctx, learner->event_types);
+
+ grn_obj_unlink(ctx, learner->items);
+ grn_obj_unlink(ctx, learner->items_freq);
+ grn_obj_unlink(ctx, learner->items_freq2);
+ grn_obj_unlink(ctx, learner->items_last);
+
+ grn_obj_unlink(ctx, learner->pairs_pre);
+ grn_obj_unlink(ctx, learner->pairs_post);
+ grn_obj_unlink(ctx, learner->pairs_freq0);
+ grn_obj_unlink(ctx, learner->pairs_freq1);
+ grn_obj_unlink(ctx, learner->pairs_freq2);
+}
+
+static void
+learner_init_weight(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_obj *weight_column = NULL;
+ unsigned int weight = 1;
+
+ if (learner->configuration) {
+ weight_column = grn_obj_column(ctx,
+ learner->configuration,
+ CONST_STR_LEN("weight"));
+ }
+ if (weight_column) {
+ grn_id id;
+ id = grn_table_get(ctx, learner->configuration,
+ GRN_TEXT_VALUE(&(learner->dataset_name)),
+ GRN_TEXT_LEN(&(learner->dataset_name)));
+ if (id != GRN_ID_NIL) {
+ grn_obj weight_value;
+ GRN_UINT32_INIT(&weight_value, 0);
+ grn_obj_get_value(ctx, weight_column, id, &weight_value);
+ weight = GRN_UINT32_VALUE(&weight_value);
+ GRN_OBJ_FIN(ctx, &weight_value);
+ }
+ grn_obj_unlink(ctx, weight_column);
+ }
+
+ GRN_UINT32_INIT(&(learner->weight), 0);
+ GRN_UINT32_SET(ctx, &(learner->weight), weight);
+}
+
+static void
+learner_init_dataset_name(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ char events_name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int events_name_size;
+ unsigned int events_name_prefix_size;
+
+ events_name_size = grn_obj_name(ctx, learner->events,
+ events_name, GRN_TABLE_MAX_KEY_SIZE);
+ GRN_TEXT_INIT(&(learner->dataset_name), 0);
+ events_name_prefix_size = strlen("event_");
+ if (events_name_size > events_name_prefix_size) {
+ GRN_TEXT_PUT(ctx,
+ &(learner->dataset_name),
+ events_name + events_name_prefix_size,
+ events_name_size - events_name_prefix_size);
+ }
+}
+
+static void
+learner_fin_dataset_name(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ GRN_OBJ_FIN(ctx, &(learner->dataset_name));
+}
+
+static void
+learner_init_configuration(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ learner->configuration = grn_ctx_get(ctx, "configuration", -1);
+}
+
+static void
+learner_fin_configuration(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ if (learner->configuration) {
+ grn_obj_unlink(ctx, learner->configuration);
+ }
+}
+
+static void
+learner_init_buffers(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ learner_init_weight(ctx, learner);
+ GRN_RECORD_INIT(&(learner->pre_events), 0, grn_obj_id(ctx, learner->events));
+}
+
+static void
+learner_fin_buffers(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_obj_unlink(ctx, &(learner->weight));
+ grn_obj_unlink(ctx, &(learner->pre_events));
+}
+
+static void
+learner_init_submit_learn(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_id items_id;
+
+ learner->key_prefix = ((uint64_t)learner->post_item_id) << 32;
+
+ items_id = grn_obj_get_range(ctx, learner->events_item);
+ GRN_RECORD_INIT(&(learner->pre_item), 0, items_id);
+
+ grn_obj_get_value(ctx, learner->seqs_events, learner->seq_id,
+ &(learner->pre_events));
+}
+
+static void
+learner_fin_submit_learn(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_obj_unlink(ctx, &(learner->pre_item));
+ GRN_BULK_REWIND(&(learner->pre_events));
+}
+
+static grn_bool
+learner_is_valid_input(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ return learner->post_event_id && learner->post_item_id && learner->seq_id;
+}
+
+static void
+learner_increment(grn_ctx *ctx, grn_suggest_learner *learner,
+ grn_obj *column, grn_id record_id)
+{
+ grn_obj_set_value(ctx, column, record_id, &(learner->weight), GRN_OBJ_INCR);
+}
+
+static void
+learner_increment_item_freq(grn_ctx *ctx, grn_suggest_learner *learner,
+ grn_obj *column)
+{
+ learner_increment(ctx, learner, column, learner->post_item_id);
+}
+
+static void
+learner_set_last_post_time(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ grn_obj_set_value(ctx, learner->items_last, learner->post_item_id,
+ learner->post_time, GRN_OBJ_SET);
+}
+
+static void
+learner_learn_for_complete_and_correcnt(grn_ctx *ctx,
+ grn_suggest_learner *learner)
+{
+ grn_obj *pre_item, *post_item, *pre_events;
+ grn_obj pre_type, pre_time;
+ grn_id *ep, *es;
+ uint64_t key;
+ int64_t post_time_value;
+
+ pre_item = &(learner->pre_item);
+ post_item = learner->post_item;
+ pre_events = &(learner->pre_events);
+ post_time_value = learner->post_time_value;
+ GRN_RECORD_INIT(&pre_type, 0, grn_obj_get_range(ctx, learner->events_type));
+ GRN_TIME_INIT(&pre_time, 0);
+ ep = (grn_id *)GRN_BULK_CURR(pre_events);
+ es = (grn_id *)GRN_BULK_HEAD(pre_events);
+ while (es < ep--) {
+ grn_id pair_id;
+ int added;
+ int64_t learn_distance;
+
+ GRN_BULK_REWIND(&pre_type);
+ GRN_BULK_REWIND(&pre_time);
+ GRN_BULK_REWIND(pre_item);
+ grn_obj_get_value(ctx, learner->events_type, *ep, &pre_type);
+ grn_obj_get_value(ctx, learner->events_time, *ep, &pre_time);
+ grn_obj_get_value(ctx, learner->events_item, *ep, pre_item);
+ learn_distance = post_time_value - GRN_TIME_VALUE(&pre_time);
+ if (learn_distance >= MIN_LEARN_DISTANCE) {
+ learner->learn_distance_in_seconds =
+ (int)(learn_distance / GRN_TIME_USEC_PER_SEC);
+ break;
+ }
+ key = learner->key_prefix + GRN_RECORD_VALUE(pre_item);
+ pair_id = grn_table_add(ctx, learner->pairs, &key, sizeof(uint64_t),
+ &added);
+ if (added) {
+ grn_obj_set_value(ctx, learner->pairs_pre, pair_id, pre_item,
+ GRN_OBJ_SET);
+ grn_obj_set_value(ctx, learner->pairs_post, pair_id, post_item,
+ GRN_OBJ_SET);
+ }
+ if (GRN_RECORD_VALUE(&pre_type)) {
+ learner_increment(ctx, learner, learner->pairs_freq1, pair_id);
+ break;
+ } else {
+ learner_increment(ctx, learner, learner->pairs_freq0, pair_id);
+ }
+ }
+ GRN_OBJ_FIN(ctx, &pre_type);
+ GRN_OBJ_FIN(ctx, &pre_time);
+}
+
+static void
+learner_learn_for_suggest(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ char keybuf[GRN_TABLE_MAX_KEY_SIZE];
+ int keylen = grn_table_get_key(ctx, learner->items, learner->post_item_id,
+ keybuf, GRN_TABLE_MAX_KEY_SIZE);
+ unsigned int token_flags = 0;
+ grn_token_cursor *token_cursor =
+ grn_token_cursor_open(ctx, learner->items, keybuf, keylen,
+ GRN_TOKEN_ADD, token_flags);
+ if (token_cursor) {
+ grn_id tid;
+ grn_obj *pre_item = &(learner->pre_item);
+ grn_obj *post_item = learner->post_item;
+ grn_hash *token_ids = NULL;
+ while ((tid = grn_token_cursor_next(ctx, token_cursor)) && tid != learner->post_item_id) {
+ uint64_t key;
+ int added;
+ grn_id pair_id;
+ key = learner->key_prefix + tid;
+ pair_id = grn_table_add(ctx, learner->pairs, &key, sizeof(uint64_t),
+ &added);
+ if (added) {
+ GRN_RECORD_SET(ctx, pre_item, tid);
+ grn_obj_set_value(ctx, learner->pairs_pre, pair_id,
+ pre_item, GRN_OBJ_SET);
+ grn_obj_set_value(ctx, learner->pairs_post, pair_id,
+ post_item, GRN_OBJ_SET);
+ }
+ if (!token_ids) {
+ token_ids = grn_hash_create(ctx, NULL, sizeof(grn_id), 0,
+ GRN_OBJ_TABLE_HASH_KEY|GRN_HASH_TINY);
+ }
+ if (token_ids) {
+ int token_added;
+ grn_hash_add(ctx, token_ids, &tid, sizeof(grn_id), NULL, &token_added);
+ if (token_added) {
+ learner_increment(ctx, learner, learner->pairs_freq2, pair_id);
+ }
+ }
+ }
+ if (token_ids) {
+ grn_hash_close(ctx, token_ids);
+ }
+ grn_token_cursor_close(ctx, token_cursor);
+ }
+}
+
+static void
+learner_append_post_event(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ GRN_RECORD_SET(ctx, &(learner->pre_events), learner->post_event_id);
+ grn_obj_set_value(ctx, learner->seqs_events, learner->seq_id,
+ &(learner->pre_events), GRN_OBJ_APPEND);
+}
+
+static void
+learner_learn(grn_ctx *ctx, grn_suggest_learner *learner)
+{
+ if (learner_is_valid_input(ctx, learner)) {
+ learner_init_columns(ctx, learner);
+ learner_init_dataset_name(ctx, learner);
+ learner_init_configuration(ctx, learner);
+ learner_init_buffers(ctx, learner);
+ learner_increment_item_freq(ctx, learner, learner->items_freq);
+ learner_set_last_post_time(ctx, learner);
+ if (learner->post_type_id) {
+ learner_init_submit_learn(ctx, learner);
+ learner_increment_item_freq(ctx, learner, learner->items_freq2);
+ learner_learn_for_complete_and_correcnt(ctx, learner);
+ learner_learn_for_suggest(ctx, learner);
+ learner_fin_submit_learn(ctx, learner);
+ }
+ learner_append_post_event(ctx, learner);
+ learner_fin_buffers(ctx, learner);
+ learner_fin_configuration(ctx, learner);
+ learner_fin_dataset_name(ctx, learner);
+ learner_fin_columns(ctx, learner);
+ }
+}
+
+static grn_obj *
+func_suggest_preparer(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ int learn_distance_in_seconds = 0;
+ grn_obj *obj;
+ if (nargs == 6) {
+ grn_obj *post_event = args[0];
+ grn_obj *post_type = args[1];
+ grn_obj *post_item = args[2];
+ grn_obj *seq = args[3];
+ grn_obj *post_time = args[4];
+ grn_obj *pairs = args[5];
+ grn_suggest_learner learner;
+ learner_init(ctx, &learner,
+ post_event, post_type, post_item, seq, post_time, pairs);
+ learner_learn(ctx, &learner);
+ learn_distance_in_seconds = learner.learn_distance_in_seconds;
+ }
+ if ((obj = GRN_PROC_ALLOC(GRN_DB_UINT32, 0))) {
+ GRN_UINT32_SET(ctx, obj, learn_distance_in_seconds);
+ }
+ return obj;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_expr_var vars[12];
+
+ grn_plugin_expr_var_init(ctx, &vars[0], "types", -1);
+ grn_plugin_expr_var_init(ctx, &vars[1], "table", -1);
+ grn_plugin_expr_var_init(ctx, &vars[2], "column", -1);
+ grn_plugin_expr_var_init(ctx, &vars[3], "query", -1);
+ grn_plugin_expr_var_init(ctx, &vars[4], "sortby", -1);
+ grn_plugin_expr_var_init(ctx, &vars[5], "output_columns", -1);
+ grn_plugin_expr_var_init(ctx, &vars[6], "offset", -1);
+ grn_plugin_expr_var_init(ctx, &vars[7], "limit", -1);
+ grn_plugin_expr_var_init(ctx, &vars[8], "frequency_threshold", -1);
+ grn_plugin_expr_var_init(ctx, &vars[9], "conditional_probability_threshold", -1);
+ grn_plugin_expr_var_init(ctx, &vars[10], "prefix_search", -1);
+ grn_plugin_expr_var_init(ctx, &vars[11], "similar_search", -1);
+ grn_plugin_command_create(ctx, "suggest", -1, command_suggest, 12, vars);
+
+ grn_proc_create(ctx, CONST_STR_LEN("suggest_preparer"), GRN_PROC_FUNCTION,
+ func_suggest_preparer, NULL, NULL, 0, NULL);
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/token_filters/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/token_filters/CMakeLists.txt
new file mode 100644
index 00000000..4aa7d09b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/token_filters/CMakeLists.txt
@@ -0,0 +1,63 @@
+# Copyright(C) 2014 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib
+ )
+
+set(TOKEN_FILTERS_DIR "${GRN_RELATIVE_PLUGINS_DIR}/token_filters")
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/stop_word_sources.am
+ STOP_WORD_SOURCES)
+set_source_files_properties(${STOP_WORD_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+if(GRN_EMBED)
+ add_library(stop_word_token_filter STATIC ${STOP_WORD_SOURCES})
+ set_target_properties(
+ stop_word_token_filter
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+else()
+ add_library(stop_word_token_filter MODULE ${STOP_WORD_SOURCES})
+ set_target_properties(stop_word_token_filter PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "stop_word")
+ install(TARGETS stop_word_token_filter DESTINATION "${TOKEN_FILTERS_DIR}")
+endif()
+target_link_libraries(stop_word_token_filter libgroonga)
+
+if(GRN_WITH_LIBSTEMMER)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/stem_sources.am STEM_SOURCES)
+ include_directories(${LIBSTEMMER_INCLUDE_DIRS})
+ link_directories(${LIBSTEMMER_LIBRARY_DIRS})
+ set_source_files_properties(${STEM_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ if(GRN_EMBED)
+ add_library(stem_token_filter STATIC ${STEM_SOURCES})
+ set_target_properties(
+ stem_token_filter
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+ else()
+ add_library(stem_token_filter MODULE ${STEM_SOURCES})
+ set_target_properties(stem_token_filter PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "stem")
+ install(TARGETS stem_token_filter DESTINATION "${TOKEN_FILTERS_DIR}")
+ endif()
+ target_link_libraries(stem_token_filter libgroonga ${LIBSTEMMER_LIBRARIES})
+endif()
diff --git a/storage/mroonga/vendor/groonga/plugins/token_filters/Makefile.am b/storage/mroonga/vendor/groonga/plugins/token_filters/Makefile.am
new file mode 100644
index 00000000..c63bef7a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/token_filters/Makefile.am
@@ -0,0 +1,28 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -no-undefined
+
+LIBS = \
+ $(top_builddir)/lib/libgroonga.la
+
+token_filter_plugins_LTLIBRARIES =
+token_filter_plugins_LTLIBRARIES += stop_word.la
+if WITH_LIBSTEMMER
+token_filter_plugins_LTLIBRARIES += stem.la
+endif
+
+include stop_word_sources.am
+
+include stem_sources.am
+stem_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBSTEMMER_CFLAGS)
+stem_la_LIBADD = $(LIBS) $(LIBSTEMMER_LIBS)
+stem_la_LDFLAGS = $(AM_LDFLAGS) $(LIBSTEMMER_LDFLAGS)
diff --git a/storage/mroonga/vendor/groonga/plugins/token_filters/stem.c b/storage/mroonga/vendor/groonga/plugins/token_filters/stem.c
new file mode 100644
index 00000000..2144eb09
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/token_filters/stem.c
@@ -0,0 +1,279 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG token_filters_stem
+#endif
+
+#include <grn_str.h>
+
+#include <groonga.h>
+#include <groonga/token_filter.h>
+
+#include <ctype.h>
+#include <string.h>
+
+#include <libstemmer.h>
+
+typedef struct {
+ struct sb_stemmer *stemmer;
+ grn_tokenizer_token token;
+ grn_obj buffer;
+} grn_stem_token_filter;
+
+static void *
+stem_init(grn_ctx *ctx, grn_obj *table, grn_token_mode mode)
+{
+ grn_stem_token_filter *token_filter;
+
+ token_filter = GRN_PLUGIN_MALLOC(ctx, sizeof(grn_stem_token_filter));
+ if (!token_filter) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[token-filter][stem] "
+ "failed to allocate grn_stem_token_filter");
+ return NULL;
+ }
+
+ {
+ /* TODO: Support other languages. */
+ const char *algorithm = "english";
+ const char *encoding = "UTF_8";
+ token_filter->stemmer = sb_stemmer_new(algorithm, encoding);
+ if (!token_filter->stemmer) {
+ GRN_PLUGIN_FREE(ctx, token_filter);
+ GRN_PLUGIN_ERROR(ctx, GRN_INVALID_ARGUMENT,
+ "[token-filter][stem] "
+ "failed to create stemmer: "
+ "algorithm=<%s>, encoding=<%s>",
+ algorithm, encoding);
+ return NULL;
+ }
+ }
+ grn_tokenizer_token_init(ctx, &(token_filter->token));
+ GRN_TEXT_INIT(&(token_filter->buffer), 0);
+
+ return token_filter;
+}
+
+static grn_bool
+is_stemmable(grn_obj *data, grn_bool *is_all_upper)
+{
+ const char *current, *end;
+ grn_bool have_lower = GRN_FALSE;
+ grn_bool have_upper = GRN_FALSE;
+
+ *is_all_upper = GRN_FALSE;
+
+ switch (data->header.domain) {
+ case GRN_DB_SHORT_TEXT :
+ case GRN_DB_TEXT :
+ case GRN_DB_LONG_TEXT :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+
+ current = GRN_TEXT_VALUE(data);
+ end = current + GRN_TEXT_LEN(data);
+
+ for (; current < end; current++) {
+ if (islower((unsigned char)*current)) {
+ have_lower = GRN_TRUE;
+ continue;
+ }
+ if (isupper((unsigned char)*current)) {
+ have_upper = GRN_TRUE;
+ continue;
+ }
+ if (isdigit((unsigned char)*current)) {
+ continue;
+ }
+ switch (*current) {
+ case '-' :
+ case '\'' :
+ break;
+ default :
+ return GRN_FALSE;
+ }
+ }
+
+ if (!have_lower && have_upper) {
+ *is_all_upper = GRN_TRUE;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+normalize(grn_ctx *ctx,
+ const char *string, unsigned int length,
+ grn_obj *normalized)
+{
+ const char *current, *end;
+ const char *unwritten;
+
+ current = unwritten = string;
+ end = current + length;
+
+ for (; current < end; current++) {
+ if (isupper((unsigned char)*current)) {
+ if (current > unwritten) {
+ GRN_TEXT_PUT(ctx, normalized, unwritten, current - unwritten);
+ }
+ GRN_TEXT_PUTC(ctx, normalized, tolower((unsigned char)*current));
+ unwritten = current + 1;
+ }
+ }
+
+ if (current != unwritten) {
+ GRN_TEXT_PUT(ctx, normalized, unwritten, current - unwritten);
+ }
+}
+
+static void
+unnormalize(grn_ctx *ctx,
+ const char *string, unsigned int length,
+ grn_obj *normalized)
+{
+ const char *current, *end;
+ const char *unwritten;
+
+ current = unwritten = string;
+ end = current + length;
+
+ for (; current < end; current++) {
+ if (islower((unsigned char)*current)) {
+ if (current > unwritten) {
+ GRN_TEXT_PUT(ctx, normalized, unwritten, current - unwritten);
+ }
+ GRN_TEXT_PUTC(ctx, normalized, toupper((unsigned char)*current));
+ unwritten = current + 1;
+ }
+ }
+
+ if (current != unwritten) {
+ GRN_TEXT_PUT(ctx, normalized, unwritten, current - unwritten);
+ }
+}
+
+static void
+stem_filter(grn_ctx *ctx,
+ grn_token *current_token,
+ grn_token *next_token,
+ void *user_data)
+{
+ grn_stem_token_filter *token_filter = user_data;
+ grn_obj *data;
+ grn_bool is_all_upper = GRN_FALSE;
+
+ if (GRN_CTX_GET_ENCODING(ctx) != GRN_ENC_UTF8) {
+ return;
+ }
+
+ data = grn_token_get_data(ctx, current_token);
+ if (!is_stemmable(data, &is_all_upper)) {
+ return;
+ }
+
+ {
+ const sb_symbol *stemmed;
+
+ if (is_all_upper) {
+ grn_obj *buffer;
+ buffer = &(token_filter->buffer);
+ GRN_BULK_REWIND(buffer);
+ normalize(ctx,
+ GRN_TEXT_VALUE(data),
+ GRN_TEXT_LEN(data),
+ buffer);
+ stemmed = sb_stemmer_stem(token_filter->stemmer,
+ GRN_TEXT_VALUE(buffer), GRN_TEXT_LEN(buffer));
+ if (stemmed) {
+ GRN_BULK_REWIND(buffer);
+ unnormalize(ctx,
+ stemmed,
+ sb_stemmer_length(token_filter->stemmer),
+ buffer);
+ grn_token_set_data(ctx, next_token,
+ GRN_TEXT_VALUE(buffer), GRN_TEXT_LEN(buffer));
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[token-filter][stem] "
+ "failed to allocate memory for stemmed word: <%.*s> "
+ "(normalized: <%.*s>)",
+ (int)GRN_TEXT_LEN(data), GRN_TEXT_VALUE(data),
+ (int)GRN_TEXT_LEN(buffer), GRN_TEXT_VALUE(buffer));
+ }
+ } else {
+ stemmed = sb_stemmer_stem(token_filter->stemmer,
+ GRN_TEXT_VALUE(data), GRN_TEXT_LEN(data));
+ if (stemmed) {
+ grn_token_set_data(ctx, next_token,
+ stemmed,
+ sb_stemmer_length(token_filter->stemmer));
+ } else {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[token-filter][stem] "
+ "failed to allocate memory for stemmed word: <%.*s>",
+ (int)GRN_TEXT_LEN(data), GRN_TEXT_VALUE(data));
+ }
+ }
+ }
+}
+
+static void
+stem_fin(grn_ctx *ctx, void *user_data)
+{
+ grn_stem_token_filter *token_filter = user_data;
+ if (!token_filter) {
+ return;
+ }
+
+ grn_tokenizer_token_fin(ctx, &(token_filter->token));
+ if (token_filter->stemmer) {
+ sb_stemmer_delete(token_filter->stemmer);
+ }
+ GRN_OBJ_FIN(ctx, &(token_filter->buffer));
+ GRN_PLUGIN_FREE(ctx, token_filter);
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc;
+
+ rc = grn_token_filter_register(ctx,
+ "TokenFilterStem", -1,
+ stem_init,
+ stem_filter,
+ stem_fin);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/token_filters/stem_sources.am b/storage/mroonga/vendor/groonga/plugins/token_filters/stem_sources.am
new file mode 100644
index 00000000..d02a3952
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/token_filters/stem_sources.am
@@ -0,0 +1,2 @@
+stem_la_SOURCES = \
+ stem.c
diff --git a/storage/mroonga/vendor/groonga/plugins/token_filters/stop_word.c b/storage/mroonga/vendor/groonga/plugins/token_filters/stop_word.c
new file mode 100644
index 00000000..a06d772f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/token_filters/stop_word.c
@@ -0,0 +1,159 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG token_filters_stop_word
+#endif
+
+#include <grn_str.h>
+
+#include <groonga.h>
+#include <groonga/token_filter.h>
+
+#include <string.h>
+
+#define COLUMN_NAME "is_stop_word"
+
+typedef struct {
+ grn_obj *table;
+ grn_token_mode mode;
+ grn_obj *column;
+ grn_obj value;
+ grn_tokenizer_token token;
+} grn_stop_word_token_filter;
+
+static void *
+stop_word_init(grn_ctx *ctx, grn_obj *table, grn_token_mode mode)
+{
+ grn_stop_word_token_filter *token_filter;
+
+ if (mode != GRN_TOKEN_GET) {
+ return NULL;
+ }
+
+ token_filter = GRN_PLUGIN_MALLOC(ctx, sizeof(grn_stop_word_token_filter));
+ if (!token_filter) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[token-filter][stop-word] "
+ "failed to allocate grn_stop_word_token_filter");
+ return NULL;
+ }
+
+ token_filter->table = table;
+ token_filter->mode = mode;
+ token_filter->column = grn_obj_column(ctx,
+ token_filter->table,
+ COLUMN_NAME,
+ strlen(COLUMN_NAME));
+ if (!token_filter->column) {
+ char table_name[GRN_TABLE_MAX_KEY_SIZE];
+ unsigned int table_name_size;
+
+ table_name_size = grn_obj_name(ctx,
+ token_filter->table,
+ table_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKEN_FILTER_ERROR,
+ "[token-filter][stop-word] "
+ "column for judging stop word doesn't exit: <%.*s.%s>",
+ table_name_size,
+ table_name,
+ COLUMN_NAME);
+ GRN_PLUGIN_FREE(ctx, token_filter);
+ return NULL;
+ }
+
+ GRN_BOOL_INIT(&(token_filter->value), 0);
+ grn_tokenizer_token_init(ctx, &(token_filter->token));
+
+ return token_filter;
+}
+
+static void
+stop_word_filter(grn_ctx *ctx,
+ grn_token *current_token,
+ grn_token *next_token,
+ void *user_data)
+{
+ grn_stop_word_token_filter *token_filter = user_data;
+ grn_id id;
+ grn_obj *data;
+
+ if (!token_filter) {
+ return;
+ }
+
+ data = grn_token_get_data(ctx, current_token);
+ id = grn_table_get(ctx,
+ token_filter->table,
+ GRN_TEXT_VALUE(data),
+ GRN_TEXT_LEN(data));
+ if (id != GRN_ID_NIL) {
+ GRN_BULK_REWIND(&(token_filter->value));
+ grn_obj_get_value(ctx,
+ token_filter->column,
+ id,
+ &(token_filter->value));
+ if (GRN_BOOL_VALUE(&(token_filter->value))) {
+ grn_tokenizer_status status;
+ status = grn_token_get_status(ctx, current_token);
+ status |= GRN_TOKEN_SKIP;
+ grn_token_set_status(ctx, next_token, status);
+ }
+ }
+}
+
+static void
+stop_word_fin(grn_ctx *ctx, void *user_data)
+{
+ grn_stop_word_token_filter *token_filter = user_data;
+ if (!token_filter) {
+ return;
+ }
+
+ grn_tokenizer_token_fin(ctx, &(token_filter->token));
+ grn_obj_unlink(ctx, token_filter->column);
+ grn_obj_unlink(ctx, &(token_filter->value));
+ GRN_PLUGIN_FREE(ctx, token_filter);
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc;
+
+ rc = grn_token_filter_register(ctx,
+ "TokenFilterStopWord", -1,
+ stop_word_init,
+ stop_word_filter,
+ stop_word_fin);
+
+ return rc;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/token_filters/stop_word_sources.am b/storage/mroonga/vendor/groonga/plugins/token_filters/stop_word_sources.am
new file mode 100644
index 00000000..bab89551
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/token_filters/stop_word_sources.am
@@ -0,0 +1,2 @@
+stop_word_la_SOURCES = \
+ stop_word.c
diff --git a/storage/mroonga/vendor/groonga/plugins/tokenizers/CMakeLists.txt b/storage/mroonga/vendor/groonga/plugins/tokenizers/CMakeLists.txt
new file mode 100644
index 00000000..26aadc4e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/tokenizers/CMakeLists.txt
@@ -0,0 +1,76 @@
+# Copyright(C) 2012-2013 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib
+ )
+
+set(TOKENIZERS_DIR "${GRN_RELATIVE_PLUGINS_DIR}/tokenizers")
+if(GRN_WITH_MECAB)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mecab_sources.am MECAB_SOURCES)
+ include_directories(${MECAB_INCLUDE_DIRS})
+ link_directories(${MECAB_LIBRARY_DIRS})
+ if(GRN_WITH_BUNDLED_MECAB)
+ set(GRN_BUNDLED_MECAB_RELATIVE_RC_PATH "${CONFIG_DIR}/mecabrc")
+ set(MECAB_COMPILE_DEFINITIONS
+ "GRN_WITH_BUNDLED_MECAB"
+ "GRN_BUNDLED_MECAB_RELATIVE_RC_PATH=\"${GRN_BUNDLED_MECAB_RELATIVE_RC_PATH}\""
+ "GRN_BUNDLED_MECAB_RC_PATH=\"${CMAKE_INSTALL_PREFIX}/${GRN_BUNDLED_MECAB_RELATIVE_RC_PATH}\"")
+ set_source_files_properties(${MECAB_SOURCES}
+ PROPERTIES
+ COMPILE_DEFINITIONS
+ "${MECAB_COMPILE_DEFINITIONS}")
+ endif()
+ set_source_files_properties(${MECAB_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ if(GRN_EMBED)
+ add_library(mecab_tokenizer STATIC ${MECAB_SOURCES})
+ set_target_properties(
+ mecab_tokenizer
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+ else()
+ add_library(mecab_tokenizer MODULE ${MECAB_SOURCES})
+ set_target_properties(mecab_tokenizer PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "mecab")
+ install(TARGETS mecab_tokenizer DESTINATION "${TOKENIZERS_DIR}")
+ endif()
+ target_link_libraries(mecab_tokenizer libgroonga ${MECAB_LIBRARIES})
+endif()
+
+if(GRN_WITH_KYTEA)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/kytea_sources.am KYTEA_SOURCES)
+ include_directories(${KYTEA_INCLUDE_DIRS})
+ link_directories(${KYTEA_LIBRARY_DIRS})
+ set_source_files_properties(${KYTEA_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS}")
+ if(GRN_EMBED)
+ add_library(kytea_tokenizer STATIC ${KYTEA_SOURCES})
+ set_target_properties(
+ kytea_tokenizer
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+ else()
+ add_library(kytea_tokenizer MODULE ${KYTEA_SOURCES})
+ set_target_properties(kytea_tokenizer PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "kytea")
+ install(TARGETS kytea_tokenizer DESTINATION "${TOKENIZERS_DIR}")
+ endif()
+ target_link_libraries(kytea_tokenizer libgroonga ${KYTEA_LIBRARIES})
+endif()
diff --git a/storage/mroonga/vendor/groonga/plugins/tokenizers/Makefile.am b/storage/mroonga/vendor/groonga/plugins/tokenizers/Makefile.am
new file mode 100644
index 00000000..9e10612b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/tokenizers/Makefile.am
@@ -0,0 +1,33 @@
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CPPFLAGS = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -no-undefined
+
+LIBS = \
+ $(top_builddir)/lib/libgroonga.la
+
+tokenizer_plugins_LTLIBRARIES =
+if WITH_MECAB
+tokenizer_plugins_LTLIBRARIES += mecab.la
+endif
+if WITH_KYTEA
+tokenizer_plugins_LTLIBRARIES += kytea.la
+endif
+
+include mecab_sources.am
+mecab_la_CPPFLAGS = $(AM_CPPFLAGS) $(MECAB_CPPFLAGS)
+mecab_la_LIBADD = $(LIBS) $(MECAB_LIBS)
+mecab_la_LDFLAGS = $(AM_LDFLAGS) $(MECAB_LDFLAGS)
+
+include kytea_sources.am
+kytea_la_CPPFLAGS = $(AM_CPPFLAGS) $(KYTEA_CFLAGS)
+kytea_la_LIBADD = $(LIBS) $(KYTEA_LIBS)
+kytea_la_LDFLAGS = $(AM_LDFLAGS) $(KYTEA_LDFLAGS)
diff --git a/storage/mroonga/vendor/groonga/plugins/tokenizers/kytea.cpp b/storage/mroonga/vendor/groonga/plugins/tokenizers/kytea.cpp
new file mode 100644
index 00000000..76d827c0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/tokenizers/kytea.cpp
@@ -0,0 +1,358 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2012 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG tokenizers_kytea
+#endif
+
+#include <groonga/tokenizer.h>
+
+#include <kytea/kytea.h>
+#include <kytea/string-util.h>
+
+#include <string.h>
+
+#include <string>
+#include <vector>
+
+namespace {
+
+grn_plugin_mutex *kytea_mutex = NULL;
+kytea::KyteaConfig *kytea_config = NULL;
+kytea::Kytea *kytea_tagger = NULL;
+kytea::StringUtil *kytea_util = NULL;
+
+void kytea_init(grn_ctx *ctx);
+void kytea_fin(grn_ctx *ctx);
+
+void kytea_init(grn_ctx *ctx) {
+ if (kytea_mutex || kytea_config || kytea_tagger || kytea_util) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "TokenKytea is already initialized");
+ return;
+ }
+
+ kytea_mutex = grn_plugin_mutex_open(ctx);
+ if (!kytea_mutex) {
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][kytea] "
+ "grn_plugin_mutex_open() failed");
+ return;
+ }
+
+ kytea::KyteaConfig * const config = static_cast<kytea::KyteaConfig *>(
+ GRN_PLUGIN_MALLOC(ctx, sizeof(kytea::KyteaConfig)));
+ if (!config) {
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][kytea] "
+ "memory allocation to kytea::KyteaConfig failed");
+ return;
+ }
+
+ try {
+ new (config) kytea::KyteaConfig;
+ kytea_config = config;
+ try {
+ kytea_config->setDebug(0);
+ kytea_config->setOnTraining(false);
+ kytea_config->parseRunCommandLine(0, NULL);
+ } catch (...) {
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "kytea::KyteaConfig settings failed");
+ return;
+ }
+ } catch (...) {
+ GRN_PLUGIN_FREE(ctx, config);
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "kytea::KyteaConfig initialization failed");
+ return;
+ }
+
+ kytea::Kytea * const tagger = static_cast<kytea::Kytea *>(
+ GRN_PLUGIN_MALLOC(ctx, sizeof(kytea::Kytea)));
+ if (!tagger) {
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][kytea] "
+ "memory allocation to kytea::Kytea failed");
+ return;
+ }
+
+ try {
+ new (tagger) kytea::Kytea;
+ kytea_tagger = tagger;
+ try {
+ kytea_tagger->readModel(kytea_config->getModelFile().c_str());
+ } catch (...) {
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "kytea::Kytea::readModel() failed");
+ return;
+ }
+ } catch (...) {
+ GRN_PLUGIN_FREE(ctx, tagger);
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "kytea::Kytea initialization failed");
+ return;
+ }
+
+ try {
+ kytea_util = kytea_tagger->getStringUtil();
+ } catch (...) {
+ kytea_fin(ctx);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "kytea::Kytea::getStringUtil() failed");
+ return;
+ }
+}
+
+void kytea_fin(grn_ctx *ctx) {
+ kytea_util = NULL;
+
+ if (kytea_tagger) {
+ kytea_tagger->~Kytea();
+ GRN_PLUGIN_FREE(ctx, kytea_tagger);
+ kytea_tagger = NULL;
+ }
+
+ if (kytea_config) {
+ kytea_config->~KyteaConfig();
+ GRN_PLUGIN_FREE(ctx, kytea_config);
+ kytea_config = NULL;
+ }
+
+ if (kytea_mutex) {
+ grn_plugin_mutex_close(ctx, kytea_mutex);
+ kytea_mutex = NULL;
+ }
+}
+
+struct grn_tokenizer_kytea {
+ grn_tokenizer_query *query;
+ kytea::KyteaSentence sentence;
+ std::vector<std::string> tokens;
+ std::size_t id;
+ grn_tokenizer_token token;
+ const char *rest_query_string;
+ unsigned int rest_query_string_length;
+
+ grn_tokenizer_kytea() :
+ query(NULL),
+ sentence(),
+ tokens(),
+ id(0),
+ token(),
+ rest_query_string(NULL)
+ {
+ }
+ ~grn_tokenizer_kytea() {}
+};
+
+void grn_tokenizer_kytea_init(grn_ctx *ctx, grn_tokenizer_kytea *tokenizer) {
+ new (tokenizer) grn_tokenizer_kytea;
+ grn_tokenizer_token_init(ctx, &tokenizer->token);
+}
+
+void grn_tokenizer_kytea_fin(grn_ctx *ctx, grn_tokenizer_kytea *tokenizer) {
+ grn_tokenizer_token_fin(ctx, &tokenizer->token);
+ if (tokenizer->query) {
+ grn_tokenizer_query_close(ctx, tokenizer->query);
+ }
+ tokenizer->~grn_tokenizer_kytea();
+}
+
+grn_obj *grn_kytea_init(grn_ctx *ctx, int num_args, grn_obj **args,
+ grn_user_data *user_data) {
+ unsigned int normalizer_flags = 0;
+ grn_tokenizer_query * const query =
+ grn_tokenizer_query_open(ctx, num_args, args, normalizer_flags);
+ if (!query) {
+ return NULL;
+ }
+
+ grn_tokenizer_kytea * const tokenizer = static_cast<grn_tokenizer_kytea *>(
+ GRN_PLUGIN_MALLOC(ctx, sizeof(grn_tokenizer_kytea)));
+ if (!tokenizer) {
+ grn_tokenizer_query_close(ctx, query);
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][kytea] "
+ "memory allocation to grn_tokenizer_kytea failed");
+ return NULL;
+ }
+
+ try {
+ grn_tokenizer_kytea_init(ctx, tokenizer);
+ } catch (...) {
+ grn_tokenizer_query_close(ctx, query);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "tokenizer initialization failed");
+ return NULL;
+ }
+
+ tokenizer->query = query;
+
+ grn_obj *normalized_query = query->normalized_query;
+ const char *normalized_string;
+ unsigned int normalized_string_length;
+ grn_string_get_normalized(ctx,
+ normalized_query,
+ &normalized_string,
+ &normalized_string_length,
+ NULL);
+ if (tokenizer->query->have_tokenized_delimiter) {
+ tokenizer->rest_query_string = normalized_string;
+ tokenizer->rest_query_string_length = normalized_string_length;
+ } else {
+ grn_plugin_mutex_lock(ctx, kytea_mutex);
+ try {
+ const std::string str(normalized_string, normalized_string_length);
+ const kytea::KyteaString &surface_str = kytea_util->mapString(str);
+ const kytea::KyteaString &normalized_str = kytea_util->normalize(surface_str);
+ tokenizer->sentence = kytea::KyteaSentence(surface_str, normalized_str);
+ kytea_tagger->calculateWS(tokenizer->sentence);
+ } catch (...) {
+ grn_plugin_mutex_unlock(ctx, kytea_mutex);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "tokenization failed");
+ return NULL;
+ }
+ grn_plugin_mutex_unlock(ctx, kytea_mutex);
+
+ try {
+ for (std::size_t i = 0; i < tokenizer->sentence.words.size(); ++i) {
+ const std::string &token =
+ kytea_util->showString(tokenizer->sentence.words[i].surface);
+ const char *ptr = token.c_str();
+ unsigned int left = static_cast<unsigned int>(token.length());
+ while (left > 0) {
+ const int char_length =
+ grn_tokenizer_charlen(ctx, ptr, left, query->encoding);
+ if ((char_length == 0) ||
+ (grn_tokenizer_isspace(ctx, ptr, left, query->encoding) != 0)) {
+ break;
+ }
+ ptr += char_length;
+ left -= char_length;
+ }
+ if (left == 0) {
+ tokenizer->tokens.push_back(token);
+ }
+ }
+ } catch (...) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][kytea] "
+ "adjustment failed");
+ return NULL;
+ }
+ }
+
+ user_data->ptr = tokenizer;
+ return NULL;
+}
+
+grn_obj *grn_kytea_next(grn_ctx *ctx, int num_args, grn_obj **args,
+ grn_user_data *user_data) {
+ grn_tokenizer_kytea * const tokenizer =
+ static_cast<grn_tokenizer_kytea *>(user_data->ptr);
+
+ if (tokenizer->query->have_tokenized_delimiter) {
+ unsigned int rest_query_string_length =
+ tokenizer->rest_query_string_length;
+ const char *rest_query_string =
+ grn_tokenizer_tokenized_delimiter_next(ctx,
+ &(tokenizer->token),
+ tokenizer->rest_query_string,
+ rest_query_string_length,
+ tokenizer->query->encoding);
+ if (rest_query_string) {
+ tokenizer->rest_query_string_length -=
+ rest_query_string - tokenizer->rest_query_string;
+ }
+ tokenizer->rest_query_string = rest_query_string;
+ } else {
+ const grn_tokenizer_status status =
+ ((tokenizer->id + 1) < tokenizer->tokens.size()) ?
+ GRN_TOKENIZER_CONTINUE : GRN_TOKENIZER_LAST;
+ if (tokenizer->id < tokenizer->tokens.size()) {
+ const std::string &token = tokenizer->tokens[tokenizer->id++];
+ grn_tokenizer_token_push(ctx, &tokenizer->token,
+ token.c_str(), token.length(), status);
+ } else {
+ grn_tokenizer_token_push(ctx, &tokenizer->token, "", 0, status);
+ }
+ }
+
+ return NULL;
+}
+
+grn_obj *grn_kytea_fin(grn_ctx *ctx, int num_args, grn_obj **args,
+ grn_user_data *user_data) {
+ grn_tokenizer_kytea * const tokenizer =
+ static_cast<grn_tokenizer_kytea *>(user_data->ptr);
+ if (tokenizer) {
+ grn_tokenizer_kytea_fin(ctx, tokenizer);
+ GRN_PLUGIN_FREE(ctx, tokenizer);
+ }
+ return NULL;
+}
+
+} // namespace
+
+extern "C" {
+
+/*
+ GRN_PLUGIN_INIT() is called to initialize this plugin. Note that an error
+ code must be set in `ctx->rc' on failure.
+ */
+grn_rc GRN_PLUGIN_INIT(grn_ctx *ctx) {
+ kytea_init(ctx);
+ return ctx->rc;
+}
+
+/*
+ GRN_PLUGIN_REGISTER() registers this plugin to the database associated with
+ `ctx'. The registration requires the plugin name and the functions to be
+ called for tokenization.
+ */
+grn_rc GRN_PLUGIN_REGISTER(grn_ctx *ctx) {
+ return grn_tokenizer_register(ctx, "TokenKytea", 10, grn_kytea_init,
+ grn_kytea_next, grn_kytea_fin);
+}
+
+/*
+ GRN_PLUGIN_FIN() is called to finalize the plugin that was initialized by
+ GRN_PLUGIN_INIT().
+ */
+grn_rc GRN_PLUGIN_FIN(grn_ctx *ctx) {
+ kytea_fin(ctx);
+ return GRN_SUCCESS;
+}
+
+} // extern "C"
diff --git a/storage/mroonga/vendor/groonga/plugins/tokenizers/kytea_sources.am b/storage/mroonga/vendor/groonga/plugins/tokenizers/kytea_sources.am
new file mode 100644
index 00000000..182f3857
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/tokenizers/kytea_sources.am
@@ -0,0 +1,2 @@
+kytea_la_SOURCES = \
+ kytea.cpp
diff --git a/storage/mroonga/vendor/groonga/plugins/tokenizers/mecab.c b/storage/mroonga/vendor/groonga/plugins/tokenizers/mecab.c
new file mode 100644
index 00000000..cabf2c94
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/tokenizers/mecab.c
@@ -0,0 +1,660 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef GRN_EMBEDDED
+# define GRN_PLUGIN_FUNCTION_TAG tokenizers_mecab
+#endif
+
+#include <grn_str.h>
+
+#include <groonga.h>
+#include <groonga/tokenizer.h>
+
+#include <mecab.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+static unsigned int sole_mecab_init_counter = 0;
+static mecab_t *sole_mecab = NULL;
+static grn_plugin_mutex *sole_mecab_mutex = NULL;
+static grn_encoding sole_mecab_encoding = GRN_ENC_NONE;
+
+static grn_bool grn_mecab_chunked_tokenize_enabled = GRN_FALSE;
+static int grn_mecab_chunk_size_threshold = 8192;
+
+typedef struct {
+ mecab_t *mecab;
+ grn_obj buf;
+ const char *next;
+ const char *end;
+ grn_tokenizer_query *query;
+ grn_tokenizer_token token;
+} grn_mecab_tokenizer;
+
+static const char *
+mecab_global_error_message(void)
+{
+ double version;
+
+ version = atof(mecab_version());
+ /* MeCab <= 0.993 doesn't support mecab_strerror(NULL). */
+ if (version <= 0.993) {
+ return "Unknown";
+ }
+
+ return mecab_strerror(NULL);
+}
+
+
+static grn_encoding
+translate_mecab_charset_to_grn_encoding(const char *charset)
+{
+ if (grn_strcasecmp(charset, "euc-jp") == 0) {
+ return GRN_ENC_EUC_JP;
+ } else if (grn_strcasecmp(charset, "utf-8") == 0 ||
+ grn_strcasecmp(charset, "utf8") == 0) {
+ return GRN_ENC_UTF8;
+ } else if (grn_strcasecmp(charset, "shift_jis") == 0 ||
+ grn_strcasecmp(charset, "shift-jis") == 0 ||
+ grn_strcasecmp(charset, "sjis") == 0) {
+ return GRN_ENC_SJIS;
+ }
+ return GRN_ENC_NONE;
+}
+
+static grn_encoding
+get_mecab_encoding(mecab_t *mecab)
+{
+ grn_encoding encoding = GRN_ENC_NONE;
+ const mecab_dictionary_info_t *dictionary_info;
+ dictionary_info = mecab_dictionary_info(mecab);
+ if (dictionary_info) {
+ const char *charset = dictionary_info->charset;
+ encoding = translate_mecab_charset_to_grn_encoding(charset);
+ }
+ return encoding;
+}
+
+static inline grn_bool
+is_delimiter_character(grn_ctx *ctx, const char *character, int character_bytes)
+{
+ switch (character_bytes) {
+ case 1 :
+ switch (character[0]) {
+ case ',' :
+ case '.' :
+ case '!' :
+ case '?' :
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+ case 3 :
+ switch ((unsigned char)(character[0])) {
+ case 0xE3 :
+ switch ((unsigned char)(character[1])) {
+ case 0x80 :
+ switch ((unsigned char)(character[2])) {
+ case 0x81 : /* U+3001 (0xE3 0x80 0x81 in UTF-8) IDEOGRAPHIC COMMA */
+ case 0x82 : /* U+3002 (0xE3 0x80 0x82 in UTF-8) IDEOGRAPHIC FULL STOP */
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+ default :
+ return GRN_FALSE;
+ }
+ return GRN_FALSE;
+ case 0xEF :
+ switch ((unsigned char)(character[1])) {
+ case 0xBC :
+ switch ((unsigned char)(character[2])) {
+ case 0x81 :
+ /* U+FF01 (0xEF 0xBC 0x81 in UTF-8) FULLWIDTH EXCLAMATION MARK */
+ case 0x9F :
+ /* U+FF1F (0xEF 0xBC 0x9F in UTF-8) FULLWIDTH QUESTION MARK */
+ return GRN_TRUE;
+ default :
+ return GRN_FALSE;
+ }
+ default :
+ return GRN_FALSE;
+ }
+ return GRN_FALSE;
+ default :
+ return GRN_FALSE;
+ }
+ default :
+ return GRN_FALSE;
+ }
+}
+
+static grn_bool
+chunked_tokenize_utf8_chunk(grn_ctx *ctx,
+ grn_mecab_tokenizer *tokenizer,
+ const char *chunk,
+ unsigned int chunk_bytes)
+{
+ const char *tokenized_chunk;
+ size_t tokenized_chunk_length;
+
+ tokenized_chunk = mecab_sparse_tostr2(tokenizer->mecab, chunk, chunk_bytes);
+ if (!tokenized_chunk) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab][chunk] "
+ "mecab_sparse_tostr2() failed len=%d err=%s",
+ chunk_bytes,
+ mecab_strerror(tokenizer->mecab));
+ return GRN_FALSE;
+ }
+
+ if (GRN_TEXT_LEN(&(tokenizer->buf)) > 0) {
+ GRN_TEXT_PUTS(ctx, &(tokenizer->buf), " ");
+ }
+
+ tokenized_chunk_length = strlen(tokenized_chunk);
+ if (tokenized_chunk_length >= 1 &&
+ isspace((unsigned char)tokenized_chunk[tokenized_chunk_length - 1])) {
+ GRN_TEXT_PUT(ctx, &(tokenizer->buf),
+ tokenized_chunk, tokenized_chunk_length - 1);
+ } else {
+ GRN_TEXT_PUT(ctx, &(tokenizer->buf),
+ tokenized_chunk, tokenized_chunk_length);
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+chunked_tokenize_utf8(grn_ctx *ctx,
+ grn_mecab_tokenizer *tokenizer,
+ const char *string,
+ unsigned int string_bytes)
+{
+ const char *chunk_start;
+ const char *current;
+ const char *last_delimiter;
+ const char *string_end = string + string_bytes;
+ grn_encoding encoding = tokenizer->query->encoding;
+
+ if (string_bytes < grn_mecab_chunk_size_threshold) {
+ return chunked_tokenize_utf8_chunk(ctx,
+ tokenizer,
+ string,
+ string_bytes);
+ }
+
+ chunk_start = current = string;
+ last_delimiter = NULL;
+ while (current < string_end) {
+ int space_bytes;
+ int character_bytes;
+ const char *current_character;
+
+ space_bytes = grn_isspace(current, encoding);
+ if (space_bytes > 0) {
+ if (chunk_start != current) {
+ grn_bool succeeded;
+ succeeded = chunked_tokenize_utf8_chunk(ctx,
+ tokenizer,
+ chunk_start,
+ current - chunk_start);
+ if (!succeeded) {
+ return succeeded;
+ }
+ }
+ current += space_bytes;
+ chunk_start = current;
+ last_delimiter = NULL;
+ continue;
+ }
+
+ character_bytes = grn_charlen_(ctx, current, string_end, encoding);
+ if (character_bytes == 0) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab][chunk] "
+ "invalid byte sequence: position=%d",
+ (int)(current - string));
+ return GRN_FALSE;
+ }
+
+ current_character = current;
+ current += character_bytes;
+ if (is_delimiter_character(ctx, current_character, character_bytes)) {
+ last_delimiter = current;
+ }
+
+ if ((current - chunk_start) >= grn_mecab_chunk_size_threshold) {
+ grn_bool succeeded;
+ if (last_delimiter) {
+ succeeded = chunked_tokenize_utf8_chunk(ctx,
+ tokenizer,
+ chunk_start,
+ last_delimiter - chunk_start);
+ chunk_start = last_delimiter;
+ } else {
+ succeeded = chunked_tokenize_utf8_chunk(ctx,
+ tokenizer,
+ chunk_start,
+ current - chunk_start);
+ chunk_start = current;
+ }
+ if (!succeeded) {
+ return succeeded;
+ }
+ last_delimiter = NULL;
+ }
+ }
+
+ if (current == chunk_start) {
+ return GRN_TRUE;
+ } else {
+ return chunked_tokenize_utf8_chunk(ctx,
+ tokenizer,
+ chunk_start,
+ current - chunk_start);
+ }
+}
+
+static mecab_t *
+mecab_create(grn_ctx *ctx)
+{
+ mecab_t *mecab;
+ int argc = 0;
+ const char *argv[4];
+
+ argv[argc++] = "Groonga";
+ argv[argc++] = "-Owakati";
+#ifdef GRN_WITH_BUNDLED_MECAB
+ argv[argc++] = "--rcfile";
+# ifdef WIN32
+ {
+ static char windows_mecab_rc_file[PATH_MAX];
+
+ grn_strcpy(windows_mecab_rc_file,
+ PATH_MAX,
+ grn_plugin_windows_base_dir());
+ grn_strcat(windows_mecab_rc_file,
+ PATH_MAX,
+ "/");
+ grn_strcat(windows_mecab_rc_file,
+ PATH_MAX,
+ GRN_BUNDLED_MECAB_RELATIVE_RC_PATH);
+ {
+ char *c;
+ for (c = windows_mecab_rc_file; *c != '\0'; c++) {
+ if (*c == '/') {
+ *c = '\\';
+ }
+ }
+ }
+ argv[argc++] = windows_mecab_rc_file;
+ }
+# else /* WIN32 */
+ argv[argc++] = GRN_BUNDLED_MECAB_RC_PATH;
+# endif /* WIN32 */
+#endif /* GRN_WITH_BUNDLED_MECAB */
+ mecab = mecab_new(argc, (char **)argv);
+
+ if (!mecab) {
+#ifdef GRN_WITH_BUNDLED_MECAB
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab] failed to create mecab_t: %s: "
+ "mecab_new(\"%s\", \"%s\", \"%s\", \"%s\")",
+ mecab_global_error_message(),
+ argv[0], argv[1], argv[2], argv[3]);
+#else /* GRN_WITH_BUNDLED_MECAB */
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab] failed to create mecab_t: %s: "
+ "mecab_new(\"%s\", \"%s\")",
+ mecab_global_error_message(),
+ argv[0], argv[1]);
+#endif /* GRN_WITH_BUNDLED_MECAB */
+ }
+
+ return mecab;
+}
+
+/*
+ This function is called for a full text search query or a document to be
+ indexed. This means that both short/long strings are given.
+ The return value of this function is ignored. When an error occurs in this
+ function, `ctx->rc' is overwritten with an error code (not GRN_SUCCESS).
+ */
+static grn_obj *
+mecab_init(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_mecab_tokenizer *tokenizer;
+ unsigned int normalizer_flags = 0;
+ grn_tokenizer_query *query;
+ grn_obj *normalized_query;
+ const char *normalized_string;
+ unsigned int normalized_string_length;
+
+ query = grn_tokenizer_query_open(ctx, nargs, args, normalizer_flags);
+ if (!query) {
+ return NULL;
+ }
+ if (!sole_mecab) {
+ grn_plugin_mutex_lock(ctx, sole_mecab_mutex);
+ if (!sole_mecab) {
+ sole_mecab = mecab_create(ctx);
+ if (sole_mecab) {
+ sole_mecab_encoding = get_mecab_encoding(sole_mecab);
+ }
+ }
+ grn_plugin_mutex_unlock(ctx, sole_mecab_mutex);
+ }
+ if (!sole_mecab) {
+ grn_tokenizer_query_close(ctx, query);
+ return NULL;
+ }
+
+ if (query->encoding != sole_mecab_encoding) {
+ grn_tokenizer_query_close(ctx, query);
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab] "
+ "MeCab dictionary charset (%s) does not match "
+ "the table encoding: <%s>",
+ grn_encoding_to_string(sole_mecab_encoding),
+ grn_encoding_to_string(query->encoding));
+ return NULL;
+ }
+
+ if (!(tokenizer = GRN_PLUGIN_MALLOC(ctx, sizeof(grn_mecab_tokenizer)))) {
+ grn_tokenizer_query_close(ctx, query);
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][mecab] "
+ "memory allocation to grn_mecab_tokenizer failed");
+ return NULL;
+ }
+ tokenizer->mecab = sole_mecab;
+ tokenizer->query = query;
+
+ normalized_query = query->normalized_query;
+ grn_string_get_normalized(ctx,
+ normalized_query,
+ &normalized_string,
+ &normalized_string_length,
+ NULL);
+ GRN_TEXT_INIT(&(tokenizer->buf), 0);
+ if (query->have_tokenized_delimiter) {
+ tokenizer->next = normalized_string;
+ tokenizer->end = tokenizer->next + normalized_string_length;
+ } else if (normalized_string_length == 0) {
+ tokenizer->next = "";
+ tokenizer->end = tokenizer->next;
+ } else {
+ grn_bool succeeded;
+ grn_plugin_mutex_lock(ctx, sole_mecab_mutex);
+ if (grn_mecab_chunked_tokenize_enabled &&
+ ctx->encoding == GRN_ENC_UTF8) {
+ succeeded = chunked_tokenize_utf8(ctx,
+ tokenizer,
+ normalized_string,
+ normalized_string_length);
+ } else {
+ const char *s;
+ s = mecab_sparse_tostr2(tokenizer->mecab,
+ normalized_string,
+ normalized_string_length);
+ if (!s) {
+ succeeded = GRN_FALSE;
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab] "
+ "mecab_sparse_tostr() failed len=%d err=%s",
+ normalized_string_length,
+ mecab_strerror(tokenizer->mecab));
+ } else {
+ succeeded = GRN_TRUE;
+ GRN_TEXT_PUTS(ctx, &(tokenizer->buf), s);
+ }
+ }
+ grn_plugin_mutex_unlock(ctx, sole_mecab_mutex);
+ if (!succeeded) {
+ grn_tokenizer_query_close(ctx, tokenizer->query);
+ GRN_PLUGIN_FREE(ctx, tokenizer);
+ return NULL;
+ }
+ {
+ char *buf, *p;
+ unsigned int bufsize;
+
+ buf = GRN_TEXT_VALUE(&(tokenizer->buf));
+ bufsize = GRN_TEXT_LEN(&(tokenizer->buf));
+ /* A certain version of mecab returns trailing lf or spaces. */
+ for (p = buf + bufsize - 2;
+ buf <= p && isspace(*(unsigned char *)p);
+ p--) { *p = '\0'; }
+ tokenizer->next = buf;
+ tokenizer->end = p + 1;
+ }
+ }
+ user_data->ptr = tokenizer;
+
+ grn_tokenizer_token_init(ctx, &(tokenizer->token));
+
+ return NULL;
+}
+
+/*
+ This function returns tokens one by one.
+ */
+static grn_obj *
+mecab_next(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ /* grn_obj *table = args[0]; */
+ grn_mecab_tokenizer *tokenizer = user_data->ptr;
+ grn_encoding encoding = tokenizer->query->encoding;
+
+ if (tokenizer->query->have_tokenized_delimiter) {
+ tokenizer->next =
+ grn_tokenizer_tokenized_delimiter_next(ctx,
+ &(tokenizer->token),
+ tokenizer->next,
+ tokenizer->end - tokenizer->next,
+ encoding);
+ } else {
+ size_t cl;
+ const char *p = tokenizer->next, *r;
+ const char *e = tokenizer->end;
+ grn_tokenizer_status status;
+
+ for (r = p; r < e; r += cl) {
+ int space_len;
+
+ space_len = grn_isspace(r, encoding);
+ if (space_len > 0 && r == p) {
+ cl = space_len;
+ p = r + cl;
+ continue;
+ }
+
+ if (!(cl = grn_charlen_(ctx, r, e, encoding))) {
+ tokenizer->next = e;
+ break;
+ }
+
+ if (space_len > 0) {
+ const char *q = r + space_len;
+ while (q < e && (space_len = grn_isspace(q, encoding))) {
+ q += space_len;
+ }
+ tokenizer->next = q;
+ break;
+ }
+ }
+
+ if (r == e || tokenizer->next == e) {
+ status = GRN_TOKENIZER_LAST;
+ } else {
+ status = GRN_TOKENIZER_CONTINUE;
+ }
+ grn_tokenizer_token_push(ctx, &(tokenizer->token), p, r - p, status);
+ }
+
+ return NULL;
+}
+
+/*
+ This function finalizes a tokenization.
+ */
+static grn_obj *
+mecab_fin(grn_ctx *ctx, int nargs, grn_obj **args, grn_user_data *user_data)
+{
+ grn_mecab_tokenizer *tokenizer = user_data->ptr;
+ if (!tokenizer) {
+ return NULL;
+ }
+ grn_tokenizer_token_fin(ctx, &(tokenizer->token));
+ grn_tokenizer_query_close(ctx, tokenizer->query);
+ grn_obj_unlink(ctx, &(tokenizer->buf));
+ GRN_PLUGIN_FREE(ctx, tokenizer);
+ return NULL;
+}
+
+static void
+check_mecab_dictionary_encoding(grn_ctx *ctx)
+{
+#ifdef HAVE_MECAB_DICTIONARY_INFO_T
+ mecab_t *mecab;
+ grn_encoding encoding;
+ grn_bool have_same_encoding_dictionary;
+
+ mecab = mecab_create(ctx);
+ if (!mecab) {
+ return;
+ }
+
+ encoding = GRN_CTX_GET_ENCODING(ctx);
+ have_same_encoding_dictionary = (encoding == get_mecab_encoding(mecab));
+ mecab_destroy(mecab);
+
+ if (!have_same_encoding_dictionary) {
+ GRN_PLUGIN_ERROR(ctx, GRN_TOKENIZER_ERROR,
+ "[tokenizer][mecab] "
+ "MeCab has no dictionary that uses the context encoding"
+ ": <%s>",
+ grn_encoding_to_string(encoding));
+ }
+#endif
+}
+
+/*
+ This function initializes a plugin. This function fails if there is no
+ dictionary that uses the context encoding of groonga.
+ */
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ ++sole_mecab_init_counter;
+ if (sole_mecab_init_counter > 1)
+ {
+ return GRN_SUCCESS;
+ }
+ {
+ char env[GRN_ENV_BUFFER_SIZE];
+
+ grn_getenv("GRN_MECAB_CHUNKED_TOKENIZE_ENABLED",
+ env,
+ GRN_ENV_BUFFER_SIZE);
+ grn_mecab_chunked_tokenize_enabled = (env[0] && strcmp(env, "yes") == 0);
+ }
+
+ {
+ char env[GRN_ENV_BUFFER_SIZE];
+
+ grn_getenv("GRN_MECAB_CHUNK_SIZE_THRESHOLD",
+ env,
+ GRN_ENV_BUFFER_SIZE);
+ if (env[0]) {
+ int threshold = -1;
+ const char *end;
+ const char *rest;
+
+ end = env + strlen(env);
+ threshold = grn_atoi(env, end, &rest);
+ if (end > env && end == rest) {
+ grn_mecab_chunk_size_threshold = threshold;
+ }
+ }
+ }
+
+ sole_mecab = NULL;
+ sole_mecab_mutex = grn_plugin_mutex_open(ctx);
+ if (!sole_mecab_mutex) {
+ GRN_PLUGIN_ERROR(ctx, GRN_NO_MEMORY_AVAILABLE,
+ "[tokenizer][mecab] grn_plugin_mutex_open() failed");
+ return ctx->rc;
+ }
+
+ check_mecab_dictionary_encoding(ctx);
+ if (ctx->rc != GRN_SUCCESS) {
+ grn_plugin_mutex_close(ctx, sole_mecab_mutex);
+ sole_mecab_mutex = NULL;
+ }
+
+ return ctx->rc;
+}
+
+/*
+ This function registers a plugin to a database.
+ */
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_rc rc;
+
+ rc = grn_tokenizer_register(ctx, "TokenMecab", 10,
+ mecab_init, mecab_next, mecab_fin);
+ if (rc == GRN_SUCCESS) {
+ grn_obj *token_mecab;
+ token_mecab = grn_ctx_get(ctx, "TokenMecab", 10);
+ /* Just for backward compatibility. TokenMecab was built-in not plugin. */
+ if (token_mecab && grn_obj_id(ctx, token_mecab) != GRN_DB_MECAB) {
+ rc = GRN_FILE_CORRUPT;
+ }
+ }
+
+ return rc;
+}
+
+/*
+ This function finalizes a plugin.
+ */
+grn_rc
+GRN_PLUGIN_FIN(grn_ctx *ctx)
+{
+ --sole_mecab_init_counter;
+ if (sole_mecab_init_counter > 0)
+ {
+ return GRN_SUCCESS;
+ }
+ if (sole_mecab) {
+ mecab_destroy(sole_mecab);
+ sole_mecab = NULL;
+ }
+ if (sole_mecab_mutex) {
+ grn_plugin_mutex_close(ctx, sole_mecab_mutex);
+ sole_mecab_mutex = NULL;
+ }
+
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/plugins/tokenizers/mecab_sources.am b/storage/mroonga/vendor/groonga/plugins/tokenizers/mecab_sources.am
new file mode 100644
index 00000000..56912727
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/plugins/tokenizers/mecab_sources.am
@@ -0,0 +1,2 @@
+mecab_la_SOURCES = \
+ mecab.c
diff --git a/storage/mroonga/vendor/groonga/src/.gitignore b/storage/mroonga/vendor/groonga/src/.gitignore
new file mode 100644
index 00000000..a8278d75
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/.gitignore
@@ -0,0 +1,2 @@
+/grntest
+/*.exe
diff --git a/storage/mroonga/vendor/groonga/src/CMakeLists.txt b/storage/mroonga/vendor/groonga/src/CMakeLists.txt
new file mode 100644
index 00000000..17ef3a41
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/CMakeLists.txt
@@ -0,0 +1,62 @@
+# Copyright(C) 2012-2013 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${MRUBY_INCLUDE_DIRS}
+ ${MESSAGE_PACK_INCLUDE_DIRS}
+ )
+
+add_subdirectory(suggest)
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/groonga_sources.am GROONGA_SOURCES)
+add_executable(groonga ${GROONGA_SOURCES})
+set_source_files_properties(${GROONGA_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+target_link_libraries(groonga libgroonga)
+install(TARGETS groonga DESTINATION ${BIN_DIR})
+
+if(GRN_WITH_MRUBY)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/grndb_sources.am GRNDB_SOURCES)
+ add_executable(grndb ${GRNDB_SOURCES})
+ set_source_files_properties(${GRNDB_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ set_source_files_properties(${GRNDB_SOURCES}
+ PROPERTIES
+ COMPILE_DEFINITIONS "${MRUBY_DEFINITIONS}")
+ target_link_libraries(grndb libgroonga)
+ install(TARGETS grndb DESTINATION ${BIN_DIR})
+endif()
+
+if(NOT WIN32)
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/grnslap_sources.am GRNSLAP_SOURCES)
+ add_executable(grnslap ${GRNSLAP_SOURCES})
+ set_source_files_properties(${GRNSLAP_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ target_link_libraries(grnslap libgroonga)
+ install(TARGETS grnslap DESTINATION ${BIN_DIR})
+endif()
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/groonga_benchmark_sources.am
+ GROONGA_BENCHMARK_SOURCES)
+add_executable(groonga-benchmark ${GROONGA_BENCHMARK_SOURCES})
+set_source_files_properties(${GROONGA_BENCHMARK_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+target_link_libraries(groonga-benchmark libgroonga)
+install(TARGETS groonga-benchmark DESTINATION ${BIN_DIR})
+
diff --git a/storage/mroonga/vendor/groonga/src/Makefile.am b/storage/mroonga/vendor/groonga/src/Makefile.am
new file mode 100644
index 00000000..2ee68723
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/Makefile.am
@@ -0,0 +1,67 @@
+SUBDIRS = \
+ suggest \
+ httpd
+
+NONEXISTENT_CXX_SOURCE = nonexistent.cpp
+
+bin_PROGRAMS = groonga groonga-benchmark
+noinst_PROGRAMS = grnslap
+if WITH_MRUBY
+bin_PROGRAMS += grndb
+noinst_PROGRAMS += groonga-mruby
+endif
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS) \
+ $(MRUBY_CFLAGS)
+
+AM_CPPFLAGS = \
+ $(MRUBY_CPPFLAGS)
+
+DEFS += $(GRN_DEFS)
+
+AM_LDFLAGS = -no-undefined
+
+DEFAULT_INCLUDES = \
+ -I$(top_builddir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib \
+ $(GROONGA_INCLUDEDIR)
+
+include groonga_sources.am
+nodist_EXTRA_groonga_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+groonga_CFLAGS = $(AM_CFLAGS) $(LIBEDIT_CFLAGS)
+groonga_LDADD = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(LIBEDIT_LIBS) \
+ $(MESSAGE_PACK_LIBS)
+
+include grnslap_sources.am
+nodist_EXTRA_grnslap_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+grnslap_LDADD = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(MESSAGE_PACK_LIBS)
+
+include groonga_benchmark_sources.am
+nodist_EXTRA_groonga_benchmark_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+groonga_benchmark_LDADD = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(MESSAGE_PACK_LIBS)
+
+include grndb_sources.am
+nodist_EXTRA_grndb_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+grndb_LDADD = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(MESSAGE_PACK_LIBS)
+
+include groonga_mruby_sources.am
+nodist_EXTRA_groonga_mruby_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+groonga_mruby_LDADD = \
+ $(top_builddir)/lib/libgroonga.la \
+ $(MESSAGE_PACK_LIBS)
diff --git a/storage/mroonga/vendor/groonga/src/grndb.c b/storage/mroonga/vendor/groonga/src/grndb.c
new file mode 100644
index 00000000..11f3ff5a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/grndb.c
@@ -0,0 +1,197 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014-2016 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef WIN32
+# define GROONGA_MAIN
+#endif /* WIN32 */
+
+#include <stdio.h>
+
+#include <grn_mrb.h>
+#include <grn_ctx_impl.h>
+#include <grn_ctx_impl_mrb.h>
+
+#include <mruby/variable.h>
+#include <mruby/array.h>
+
+static int
+run_command(grn_ctx *ctx, int argc, char **argv)
+{
+ int exit_code = EXIT_SUCCESS;
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+ mrb_value mrb_command_line_module;
+ mrb_value mrb_grndb_class;
+
+ mrb_command_line_module = mrb_const_get(mrb,
+ mrb_obj_value(data->module),
+ mrb_intern_cstr(mrb, "CommandLine"));
+ if (mrb->exc) {
+ goto exit;
+ }
+
+ mrb_grndb_class = mrb_const_get(mrb,
+ mrb_command_line_module,
+ mrb_intern_cstr(mrb, "Grndb"));
+ if (mrb->exc) {
+ goto exit;
+ }
+
+ {
+ int i;
+ mrb_value mrb_argv;
+ mrb_value mrb_grndb;
+ mrb_value mrb_result;
+
+ mrb_argv = mrb_ary_new_capa(mrb, argc);
+ for (i = 0; i < argc; i++) {
+ mrb_ary_push(mrb, mrb_argv, mrb_str_new_cstr(mrb, argv[i]));
+ }
+ mrb_grndb = mrb_funcall(mrb, mrb_grndb_class, "new", 1, mrb_argv);
+ if (mrb->exc) {
+ goto exit;
+ }
+
+ mrb_result = mrb_funcall(mrb, mrb_grndb, "run", 0);
+ if (mrb->exc) {
+ goto exit;
+ }
+
+ if (!mrb_bool(mrb_result)) {
+ exit_code = EXIT_FAILURE;
+ }
+ }
+
+exit :
+ if (mrb->exc) {
+ mrb_print_error(mrb);
+ exit_code = EXIT_FAILURE;
+ }
+
+ return exit_code;
+}
+
+static int
+run(grn_ctx *ctx, int argc, char **argv)
+{
+ int exit_code = EXIT_SUCCESS;
+ const char *grndb_rb = "command_line/grndb.rb";
+ grn_mrb_data *data = &(ctx->impl->mrb);
+ mrb_state *mrb = data->state;
+
+ mrb_gv_set(mrb, mrb_intern_lit(mrb, "$0"), mrb_str_new_cstr(mrb, argv[0]));
+
+ grn_mrb_load(ctx, grndb_rb);
+ if (ctx->rc != GRN_SUCCESS) {
+ fprintf(stderr, "Failed to load Ruby script: <%s>: %s",
+ grndb_rb, ctx->errbuf);
+ goto exit;
+ }
+
+ {
+ int arena_index;
+
+ arena_index = mrb_gc_arena_save(mrb);
+ exit_code = run_command(ctx, argc, argv);
+ mrb_gc_arena_restore(mrb, arena_index);
+ }
+
+exit :
+ if (ctx->rc != GRN_SUCCESS) {
+ exit_code = EXIT_FAILURE;
+ }
+ return exit_code;
+}
+
+int
+main(int argc, char **argv)
+{
+ int exit_code = EXIT_SUCCESS;
+ const char *log_path = GRN_LOG_PATH;
+ const char *log_level_name = NULL;
+
+ {
+ int i;
+ for (i = 1; i < argc; i++) {
+ const char *arg = argv[i];
+
+ if (arg[0] != '-') {
+ continue;
+ }
+
+ if (arg[1] == '-' && arg[2] == '\0') {
+ break;
+ }
+
+#define log_path_prefix "--log-path"
+#define log_level_prefix "--log-level"
+ if (strcmp(arg, log_path_prefix) == 0) {
+ if (i + 1 < argc) {
+ log_path = argv[i + 1];
+ i++;
+ }
+ } else if (strncmp(arg,
+ log_path_prefix "=",
+ strlen(log_path_prefix "=")) == 0) {
+ log_path = arg + strlen(log_path_prefix "=");
+ } else if (strcmp(arg, log_level_prefix) == 0) {
+ if (i + 1 < argc) {
+ log_level_name = argv[i + 1];
+ i++;
+ }
+ } else if (strncmp(arg,
+ log_level_prefix "=",
+ strlen(log_level_prefix "=")) == 0) {
+ log_level_name = arg + strlen(log_level_prefix "=");
+ }
+#undef log_path_equal_prefix
+#undef log_level_equal_prefix
+ }
+ }
+
+ grn_default_logger_set_path(log_path);
+ if (log_level_name) {
+ grn_log_level log_level = GRN_LOG_DEFAULT_LEVEL;
+ if (!grn_log_level_parse(log_level_name, &log_level)) {
+ fprintf(stderr, "%s: failed to parse log level: <%s>\n",
+ argv[0], log_level_name);
+ return EXIT_FAILURE;
+ }
+ grn_default_logger_set_max_level(log_level);
+ }
+
+ if (grn_init() != GRN_SUCCESS) {
+ return EXIT_FAILURE;
+ }
+
+ {
+ grn_ctx ctx;
+ grn_ctx_init(&ctx, 0);
+ grn_ctx_impl_mrb_ensure_init(&ctx);
+ if (ctx.rc == GRN_SUCCESS) {
+ exit_code = run(&ctx, argc, argv);
+ } else {
+ exit_code = EXIT_FAILURE;
+ }
+ grn_ctx_fin(&ctx);
+ }
+
+ grn_fin();
+
+ return exit_code;
+}
diff --git a/storage/mroonga/vendor/groonga/src/grndb_sources.am b/storage/mroonga/vendor/groonga/src/grndb_sources.am
new file mode 100644
index 00000000..ce2e2bb3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/grndb_sources.am
@@ -0,0 +1,2 @@
+grndb_SOURCES = \
+ grndb.c
diff --git a/storage/mroonga/vendor/groonga/src/grnslap.c b/storage/mroonga/vendor/groonga/src/grnslap.c
new file mode 100644
index 00000000..cdd51853
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/grnslap.c
@@ -0,0 +1,375 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2012 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <grn_com.h>
+#include <grn_ctx_impl.h>
+#include <string.h>
+#include <stdio.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif /* HAVE_SYS_WAIT_H */
+#ifndef WIN32
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#define DEFAULT_PORT 10041
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_MAX_CONCURRENCY 10
+#define DEFAULT_MAX_THROUGHPUT 10000
+#define MAX_DEST 256
+
+typedef struct {
+ const char *host;
+ uint16_t port;
+} grn_slap_dest;
+
+static int proto = 'g';
+static int verbose = 0;
+static int dest_cnt = 0;
+static grn_slap_dest dests[MAX_DEST];
+static int max_con = DEFAULT_MAX_CONCURRENCY;
+static int max_tp = DEFAULT_MAX_THROUGHPUT;
+
+#include <stdarg.h>
+static void
+lprint(grn_ctx *ctx, const char *fmt, ...)
+{
+ char buf[1024];
+ grn_timeval tv;
+ int len;
+ va_list argp;
+ grn_timeval_now(ctx, &tv);
+ grn_timeval2str(ctx, &tv, buf, 1024);
+ len = strlen(buf);
+ buf[len++] = '|';
+ va_start(argp, fmt);
+ vsnprintf(buf + len, 1023 - len, fmt, argp);
+ va_end(argp);
+ buf[1023] = '\0';
+ puts(buf);
+}
+
+static void
+parse_dest(char *deststr, grn_slap_dest *dest)
+{
+ int p;
+ char *d;
+ if ((d = strchr(deststr, ':'))) {
+ if ((p = atoi(d + 1))) {
+ *d = '\0';
+ dest->host = deststr;
+ dest->port = p;
+ return;
+ }
+ }
+ dest->host = NULL;
+ dest->port = 0;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "Usage: grnslap [options...] [dest...]\n"
+ "options:\n"
+ " -P <protocol>: http or gqtp (default: gqtp)\n"
+ " -m <max concurrency>: number of max concurrency (default: %d)\n"
+ "dest: hostname:port number (default: \"%s:%d\")\n",
+ DEFAULT_MAX_CONCURRENCY, DEFAULT_HOST, DEFAULT_PORT);
+}
+
+#define BUFSIZE 0x1000000
+
+typedef struct _session session;
+
+struct _session {
+ grn_com_queue_entry eq;
+ grn_com *com;
+ struct timeval tv;
+ grn_id id;
+ int stat;
+ int query_id;
+ int n_query;
+ int n_sessions;
+};
+
+static grn_com_event ev;
+static grn_com_queue fsessions;
+static grn_hash *sessions;
+static int done = 0;
+static int nsent = 0;
+static int nrecv = 0;
+static int etime_min = INT32_MAX;
+static int etime_max = 0;
+static int64_t etime_amount = 0;
+
+static session *
+session_open(grn_ctx *ctx, grn_slap_dest *dest)
+{
+ grn_id id;
+ session *s;
+ grn_com *com;
+ if (!(com = grn_com_copen(ctx, &ev, dest->host, dest->port))) { return NULL; }
+ id = grn_hash_add(ctx, sessions, &com->fd, sizeof(grn_sock), (void **)&s, NULL);
+ com->opaque = s;
+ s->com = com;
+ s->id = id;
+ s->stat = 1;
+ return s;
+}
+
+static void
+session_close(grn_ctx *ctx, session *s)
+{
+ if (!s->stat) { return; }
+ grn_com_close(ctx, s->com);
+ s->stat = 0;
+ grn_hash_delete_by_id(ctx, sessions, s->id, NULL);
+}
+
+static session *
+session_alloc(grn_ctx *ctx, grn_slap_dest *dest)
+{
+ session *s;
+ while ((s = (session *)grn_com_queue_deque(ctx, &fsessions))) {
+ if (s->n_query < 1000000 && !s->com->closed) { return s; }
+ //session_close(ctx, s);
+ }
+ return session_open(ctx, dest);
+}
+
+static void
+msg_handler(grn_ctx *ctx, grn_obj *msg)
+{
+ uint32_t etime;
+ struct timeval tv;
+ grn_msg *m = (grn_msg *)msg;
+ grn_com *com = ((grn_msg *)msg)->u.peer;
+ session *s = com->opaque;
+ s->stat = 3;
+ gettimeofday(&tv, NULL);
+ etime = (tv.tv_sec - s->tv.tv_sec) * 1000000 + (tv.tv_usec - s->tv.tv_usec);
+ if (etime > etime_max) { etime_max = etime; }
+ if (etime < etime_min) { etime_min = etime; }
+ if (ctx->rc) { m->header.proto = 0; }
+ switch (m->header.proto) {
+ case GRN_COM_PROTO_GQTP :
+ if (GRN_BULK_VSIZE(msg) == 2) {
+ etime_amount += etime;
+ } else {
+ if (verbose) {
+ GRN_TEXT_PUTC(ctx, msg, '\0');
+ lprint(ctx, "%8d(%4d) %8d : %s", s->query_id, s->n_sessions, etime, GRN_BULK_HEAD(msg));
+ }
+ }
+ if ((m->header.flags & GRN_CTX_TAIL)) {
+ grn_com_queue_enque(ctx, &fsessions, (grn_com_queue_entry *)s);
+ nrecv++;
+ }
+ break;
+ case GRN_COM_PROTO_HTTP :
+ nrecv++;
+ /* lprint(ctx, "recv: %d, %d", (int)GRN_BULK_VSIZE(msg), nrecv); */
+ grn_com_close_(ctx, com);
+ grn_com_queue_enque(ctx, &fsessions, (grn_com_queue_entry *)s);
+ break;
+ default :
+ grn_com_close_(ctx, com);
+ grn_com_queue_enque(ctx, &fsessions, (grn_com_queue_entry *)s);
+ break;
+ }
+ grn_msg_close(ctx, msg);
+}
+
+static grn_thread_func_result CALLBACK
+receiver(void *arg)
+{
+ grn_ctx ctx_, *ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ while (!grn_com_event_poll(ctx, &ev, 100)) {
+ if (nsent == nrecv && done) { break; }
+ /*
+ {
+ session *s;
+ GRN_HASH_EACH(ctx, sessions, id, NULL, NULL, &s, {
+ printf("id=%d: fd=%d stat=%d q=%d n=%d\n", s->id, s->com->fd, s->stat, s->query_id, s->n_query);
+ });
+ }
+ */
+ }
+ grn_ctx_fin(ctx);
+ return GRN_THREAD_FUNC_RETURN_VALUE;
+}
+
+static int
+do_client()
+{
+ int rc = -1;
+ grn_obj text;
+ grn_thread thread;
+ struct timeval tvb, tve;
+ grn_com_header sheader;
+ grn_ctx ctx_, *ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ GRN_COM_QUEUE_INIT(&fsessions);
+ sessions = grn_hash_create(ctx, NULL, sizeof(grn_sock), sizeof(session), 0);
+ sheader.proto = GRN_COM_PROTO_GQTP;
+ sheader.qtype = 0;
+ sheader.keylen = 0;
+ sheader.level = 0;
+ sheader.flags = 0;
+ sheader.status = 0;
+ sheader.opaque = 0;
+ sheader.cas = 0;
+ GRN_TEXT_INIT(&text, 0);
+ rc = grn_bulk_reserve(ctx, &text, BUFSIZE);
+ if (!rc) {
+ char *buf = GRN_TEXT_VALUE(&text);
+ if (!grn_com_event_init(ctx, &ev, 1000, sizeof(grn_com))) {
+ ev.msg_handler = msg_handler;
+ if (!THREAD_CREATE(thread, receiver, NULL)) {
+ int cnt = 0;
+ gettimeofday(&tvb, NULL);
+ lprint(ctx, "begin: procotol=%c max_concurrency=%d max_tp=%d", proto, max_con, max_tp);
+ while (fgets(buf, BUFSIZE, stdin)) {
+ uint32_t size = strlen(buf) - 1;
+ session *s = session_alloc(ctx, dests + (cnt++ % dest_cnt));
+ if (s) {
+ gettimeofday(&s->tv, NULL);
+ s->n_query++;
+ s->query_id = ++nsent;
+ s->n_sessions = (nsent - nrecv);
+ switch (proto) {
+ case 'H' :
+ case 'h' :
+ if (grn_com_send_http(ctx, s->com, buf, size, 0)) {
+ fprintf(stderr, "grn_com_send_http failed\n");
+ }
+ s->stat = 2;
+ /*
+ lprint(ctx, "sent %04d %04d %d",
+ s->n_query, s->query_id, s->com->fd);
+ */
+ break;
+ default :
+ if (grn_com_send(ctx, s->com, &sheader, buf, size, 0)) {
+ fprintf(stderr, "grn_com_send failed\n");
+ }
+ break;
+ }
+ } else {
+ fprintf(stderr, "grn_com_copen failed\n");
+ }
+ for (;;) {
+ gettimeofday(&tve, NULL);
+ if ((nrecv < max_tp * (tve.tv_sec - tvb.tv_sec)) &&
+ (nsent - nrecv) < max_con) { break; }
+ /* lprint(ctx, "s:%d r:%d", nsent, nrecv); */
+ grn_nanosleep(1000000);
+ }
+ if (!(nsent % 1000)) { lprint(ctx, " : %d", nsent); }
+ }
+ done = 1;
+ if (THREAD_JOIN(thread)) {
+ fprintf(stderr, "THREAD_JOIN failed\n");
+ }
+ gettimeofday(&tve, NULL);
+ {
+ double qps;
+ uint64_t etime = (tve.tv_sec - tvb.tv_sec);
+ etime *= 1000000;
+ etime += (tve.tv_usec - tvb.tv_usec);
+ qps = (double)nsent * 1000000 / etime;
+ lprint(ctx, "end : n=%d min=%d max=%d avg=%d qps=%f etime=%d.%06d", nsent, etime_min, etime_max, (int)(etime_amount / nsent), qps, etime / 1000000, etime % 1000000);
+ }
+ {
+ session *s;
+ GRN_HASH_EACH(ctx, sessions, id, NULL, NULL, &s, {
+ session_close(ctx, s);
+ });
+ }
+ rc = 0;
+ } else {
+ fprintf(stderr, "THREAD_CREATE failed\n");
+ }
+ grn_com_event_fin(ctx, &ev);
+ } else {
+ fprintf(stderr, "grn_com_event_init failed\n");
+ }
+ }
+ grn_obj_unlink(ctx, &text);
+ grn_hash_close(ctx, sessions);
+ grn_ctx_fin(ctx);
+ return rc;
+}
+
+enum {
+ flag_usage = 1,
+ flag_verbose = 2
+};
+
+int
+main(int argc, char **argv)
+{
+ const char *protostr = NULL, *maxconstr = NULL, *maxtpstr = NULL;
+ int r, i, flags = 0;
+ static grn_str_getopt_opt opts[] = {
+ {'P', NULL, NULL, 0, GETOPT_OP_NONE},
+ {'m', NULL, NULL, 0, GETOPT_OP_NONE},
+ {'t', NULL, NULL, 0, GETOPT_OP_NONE},
+ {'h', NULL, NULL, flag_usage, GETOPT_OP_ON},
+ {'v', NULL, NULL, flag_verbose, GETOPT_OP_ON},
+ {'\0', NULL, NULL, 0, 0}
+ };
+ opts[0].arg = &protostr;
+ opts[1].arg = &maxconstr;
+ opts[2].arg = &maxtpstr;
+ i = grn_str_getopt(argc, argv, opts, &flags);
+ if (protostr) { proto = *protostr; }
+ if (maxconstr) { max_con = atoi(maxconstr); }
+ if (maxtpstr) { max_tp = atoi(maxtpstr); }
+ if (flags & flag_verbose) { verbose = 1; }
+
+ if (argc <= i) {
+ dests[0].host = DEFAULT_HOST;
+ dests[0].port = DEFAULT_PORT;
+ dest_cnt = 1;
+ } else if (i > 0 && argc <= (i + MAX_DEST)){
+ for (dest_cnt = 0; i < argc; i++) {
+ parse_dest(argv[i], &dests[dest_cnt]);
+ if (dests[dest_cnt].host) {
+ dest_cnt++;
+ }
+ }
+ if (!dest_cnt) { flags |= flag_usage; }
+ } else {
+ /* too much dests */
+ flags |= flag_usage;
+ }
+
+ grn_default_logger_set_path(GRN_LOG_PATH);
+
+ if (grn_init()) { return -1; }
+ if (flags & flag_usage) {
+ usage(); r = -1;
+ } else {
+ r = do_client();
+ }
+ grn_fin();
+ return r;
+}
diff --git a/storage/mroonga/vendor/groonga/src/grnslap_sources.am b/storage/mroonga/vendor/groonga/src/grnslap_sources.am
new file mode 100644
index 00000000..244f5bfc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/grnslap_sources.am
@@ -0,0 +1,2 @@
+grnslap_SOURCES = \
+ grnslap.c
diff --git a/storage/mroonga/vendor/groonga/src/groonga.c b/storage/mroonga/vendor/groonga/src/groonga.c
new file mode 100644
index 00000000..a7f15d13
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/groonga.c
@@ -0,0 +1,3763 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2009-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifdef WIN32
+# define GROONGA_MAIN
+#endif /* WIN32 */
+#include <grn.h>
+
+#include <grn_com.h>
+#include <grn_ctx_impl.h>
+#include <grn_proc.h>
+#include <grn_db.h>
+#include <grn_util.h>
+#include <grn_error.h>
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif /* HAVE_SYS_WAIT_H */
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif /* HAVE_SYS_SOCKET_H */
+#ifndef WIN32
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#ifdef HAVE_SYS_RESOURCE_H
+# include <sys/resource.h>
+#endif /* HAVE_SYS_RESOURCE_H */
+
+#ifdef HAVE_SYS_SYSCTL_H
+# include <sys/sysctl.h>
+#endif /* HAVE_SYS_SYSCTL_H */
+
+#ifdef WIN32
+# include <io.h>
+# include <direct.h>
+#else /* WIN32 */
+# include <sys/uio.h>
+#endif /* WIN32 */
+
+#ifndef USE_MSG_NOSIGNAL
+# ifdef MSG_NOSIGNAL
+# undef MSG_NOSIGNAL
+# endif
+# define MSG_NOSIGNAL 0
+#endif /* USE_MSG_NOSIGNAL */
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif /* STDIN_FILENO */
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif /* STDOUT_FILENO */
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif /* STDERR_FILENO */
+
+#define DEFAULT_HTTP_PORT 10041
+#define DEFAULT_GQTP_PORT 10043
+#define DEFAULT_DEST "localhost"
+#define DEFAULT_MAX_N_FLOATING_THREADS 8
+#define MAX_CON 0x10000
+
+#define RLIMIT_NOFILE_MINIMUM 4096
+
+static char bind_address[HOST_NAME_MAX + 1];
+static char hostname[HOST_NAME_MAX + 1];
+static int port = DEFAULT_GQTP_PORT;
+static int batchmode;
+static int number_of_lines = 0;
+static int newdb;
+static grn_bool is_daemon_mode = GRN_FALSE;
+static int (*do_client)(int argc, char **argv);
+static int (*do_server)(char *path);
+static const char *pid_file_path = NULL;
+static const char *input_path = NULL;
+static grn_file_reader *input_reader = NULL;
+static FILE *output = NULL;
+static grn_bool is_memcached_mode = GRN_FALSE;
+static const char *memcached_column_name = NULL;
+
+static int ready_notify_pipe[2];
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+
+static grn_encoding encoding;
+static const char *windows_event_source_name = "Groonga";
+static grn_bool use_windows_event_log = GRN_FALSE;
+static grn_obj http_response_server_line;
+
+static int
+grn_rc_to_exit_code(grn_rc rc)
+{
+ if (rc == GRN_SUCCESS) {
+ return EXIT_SUCCESS;
+ } else {
+ return EXIT_FAILURE;
+ }
+}
+
+static void
+break_accept_event_loop(grn_ctx *ctx)
+{
+ grn_com *client;
+ const char *address;
+
+ if (strcmp(bind_address, "0.0.0.0") == 0) {
+ address = "127.0.0.1";
+ } else if (strcmp(bind_address, "::") == 0) {
+ address = "::1";
+ } else {
+ address = bind_address;
+ }
+ client = grn_com_copen(ctx, NULL, address, port);
+ if (client) {
+ grn_com_close(ctx, client);
+ }
+}
+
+#ifdef GRN_WITH_LIBEDIT
+#include <locale.h>
+#include <histedit.h>
+static EditLine *line_editor = NULL;
+static HistoryW *line_editor_history = NULL;
+static HistEventW line_editor_history_event;
+static char line_editor_history_path[PATH_MAX] = "";
+
+static const wchar_t *
+line_editor_prompt(EditLine *e __attribute__((unused)))
+{
+ return L"> ";
+}
+static const wchar_t * const line_editor_editor = L"emacs";
+
+static void
+line_editor_init(int argc __attribute__((unused)), char *argv[])
+{
+ const char * const HOME_PATH = getenv("HOME");
+ const char * const HISTORY_PATH = "/.groonga-history";
+
+ setlocale(LC_ALL, "");
+
+ if (strlen(HOME_PATH) + strlen(HISTORY_PATH) < PATH_MAX) {
+ grn_strcpy(line_editor_history_path, PATH_MAX, HOME_PATH);
+ grn_strcat(line_editor_history_path, PATH_MAX, HISTORY_PATH);
+ } else {
+ line_editor_history_path[0] = '\0';
+ }
+
+ line_editor_history = history_winit();
+ history_w(line_editor_history, &line_editor_history_event, H_SETSIZE, 200);
+ if (line_editor_history_path[0]) {
+ history_w(line_editor_history, &line_editor_history_event,
+ H_LOAD, line_editor_history_path);
+ }
+
+ line_editor = el_init(argv[0], stdin, stdout, stderr);
+ el_wset(line_editor, EL_PROMPT, &line_editor_prompt);
+ el_wset(line_editor, EL_EDITOR, line_editor_editor);
+ el_wset(line_editor, EL_HIST, history_w, line_editor_history);
+ el_source(line_editor, NULL);
+}
+
+static void
+line_editor_fin(void)
+{
+ if (line_editor) {
+ el_end(line_editor);
+ if (line_editor_history) {
+ if (line_editor_history_path[0]) {
+ history_w(line_editor_history, &line_editor_history_event,
+ H_SAVE, line_editor_history_path);
+ }
+ history_wend(line_editor_history);
+ }
+ }
+}
+
+static grn_rc
+line_editor_fgets(grn_ctx *ctx, grn_obj *buf)
+{
+ grn_rc rc = GRN_SUCCESS;
+ const wchar_t *line;
+ int nchar;
+ line = el_wgets(line_editor, &nchar);
+ if (nchar > 0) {
+ int i;
+ char multibyte_buf[MB_CUR_MAX];
+ size_t multibyte_len;
+ mbstate_t ps;
+ history_w(line_editor_history, &line_editor_history_event, H_ENTER, line);
+ memset(&ps, 0, sizeof(ps));
+ wcrtomb(NULL, L'\0', &ps);
+ for (i = 0; i < nchar; i++) {
+ multibyte_len = wcrtomb(multibyte_buf, line[i], &ps);
+ if (multibyte_len == (size_t)-1) {
+ GRN_LOG(ctx, GRN_LOG_WARNING,
+ "[prompt][libedit] failed to read input: %s", strerror(errno));
+ rc = GRN_INVALID_ARGUMENT;
+ } else {
+ GRN_TEXT_PUT(ctx, buf, multibyte_buf, multibyte_len);
+ }
+ }
+ } else {
+ rc = GRN_END_OF_DATA;
+ }
+ return rc;
+}
+#endif /* GRN_WITH_LIBEDIT */
+
+inline static grn_rc
+read_next_line(grn_ctx *ctx, grn_obj *buf)
+{
+ static int the_first_read = GRN_TRUE;
+ grn_rc rc = GRN_SUCCESS;
+ if (!batchmode) {
+#ifdef GRN_WITH_LIBEDIT
+ rc = line_editor_fgets(ctx, buf);
+#else
+ fprintf(stderr, "> ");
+ fflush(stderr);
+ rc = grn_file_reader_read_line(ctx, input_reader, buf);
+#endif
+ } else {
+ rc = grn_file_reader_read_line(ctx, input_reader, buf);
+ if (rc != GRN_END_OF_DATA) {
+ number_of_lines++;
+ }
+ }
+ if (the_first_read && GRN_TEXT_LEN(buf) > 0) {
+ const char bom[] = {0xef, 0xbb, 0xbf};
+ if (GRN_CTX_GET_ENCODING(ctx) == GRN_ENC_UTF8 &&
+ GRN_TEXT_LEN(buf) > 3 && !memcmp(GRN_TEXT_VALUE(buf), bom, 3)) {
+ grn_obj buf_without_bom;
+ GRN_TEXT_INIT(&buf_without_bom, 0);
+ GRN_TEXT_PUT(ctx, &buf_without_bom,
+ GRN_TEXT_VALUE(buf) + 3, GRN_TEXT_LEN(buf) - 3);
+ GRN_TEXT_SET(ctx, buf,
+ GRN_TEXT_VALUE(&buf_without_bom),
+ GRN_TEXT_LEN(&buf_without_bom));
+ grn_obj_unlink(ctx, &buf_without_bom);
+ }
+ the_first_read = GRN_FALSE;
+ }
+ if (GRN_TEXT_LEN(buf) > 0 &&
+ GRN_TEXT_VALUE(buf)[GRN_TEXT_LEN(buf) - 1] == '\n') {
+ grn_bulk_truncate(ctx, buf, GRN_TEXT_LEN(buf) - 1);
+ }
+ if (GRN_TEXT_LEN(buf) > 0 &&
+ GRN_TEXT_VALUE(buf)[GRN_TEXT_LEN(buf) - 1] == '\r') {
+ grn_bulk_truncate(ctx, buf, GRN_TEXT_LEN(buf) - 1);
+ }
+ return rc;
+}
+
+inline static grn_rc
+prompt(grn_ctx *ctx, grn_obj *buf)
+{
+ grn_rc rc = GRN_SUCCESS;
+ grn_bool need_next_line = GRN_TRUE;
+ GRN_BULK_REWIND(buf);
+ while (need_next_line) {
+ rc = read_next_line(ctx, buf);
+ if (rc == GRN_SUCCESS &&
+ GRN_TEXT_LEN(buf) > 0 &&
+ GRN_TEXT_VALUE(buf)[GRN_TEXT_LEN(buf) - 1] == '\\') {
+ grn_bulk_truncate(ctx, buf, GRN_TEXT_LEN(buf) - 1);
+ need_next_line = GRN_TRUE;
+ } else {
+ need_next_line = GRN_FALSE;
+ }
+ }
+ return rc;
+}
+
+static void
+output_envelope(grn_ctx *ctx, grn_rc rc, grn_obj *head, grn_obj *body, grn_obj *foot)
+{
+ grn_output_envelope(ctx, rc, head, body, foot, input_path, number_of_lines);
+}
+
+static void
+s_output_raw(grn_ctx *ctx, int flags, FILE *stream)
+{
+ char *chunk = NULL;
+ unsigned int chunk_size = 0;
+ int recv_flags;
+
+ grn_ctx_recv(ctx, &chunk, &chunk_size, &recv_flags);
+ if (chunk_size > 0) {
+ fwrite(chunk, 1, chunk_size, stream);
+ }
+
+ if (flags & GRN_CTX_TAIL) {
+ grn_obj *command;
+
+ if (grn_ctx_get_output_type(ctx) == GRN_CONTENT_GROONGA_COMMAND_LIST &&
+ chunk_size > 0 &&
+ chunk[chunk_size - 1] != '\n') {
+ fwrite("\n", 1, 1, stream);
+ }
+ fflush(stream);
+
+ command = GRN_CTX_USER_DATA(ctx)->ptr;
+ GRN_BULK_REWIND(command);
+ }
+}
+
+static void
+s_output_typed(grn_ctx *ctx, int flags, FILE *stream)
+{
+ if (ctx && ctx->impl && (flags & GRN_CTX_TAIL)) {
+ char *chunk = NULL;
+ unsigned int chunk_size = 0;
+ int recv_flags;
+ grn_obj body;
+ grn_obj *command;
+
+ GRN_TEXT_INIT(&body, 0);
+ grn_ctx_recv(ctx, &chunk, &chunk_size, &recv_flags);
+ GRN_TEXT_SET(ctx, &body, chunk, chunk_size);
+
+ if (GRN_TEXT_LEN(&body) || ctx->rc) {
+ grn_obj head, foot;
+ GRN_TEXT_INIT(&head, 0);
+ GRN_TEXT_INIT(&foot, 0);
+ output_envelope(ctx, ctx->rc, &head, &body, &foot);
+ fwrite(GRN_TEXT_VALUE(&head), 1, GRN_TEXT_LEN(&head), stream);
+ fwrite(GRN_TEXT_VALUE(&body), 1, GRN_TEXT_LEN(&body), stream);
+ fwrite(GRN_TEXT_VALUE(&foot), 1, GRN_TEXT_LEN(&foot), stream);
+ fputc('\n', stream);
+ fflush(stream);
+ GRN_OBJ_FIN(ctx, &head);
+ GRN_OBJ_FIN(ctx, &foot);
+ }
+ GRN_OBJ_FIN(ctx, &body);
+
+ command = GRN_CTX_USER_DATA(ctx)->ptr;
+ GRN_BULK_REWIND(command);
+ }
+}
+
+static void
+s_output(grn_ctx *ctx, int flags, void *arg)
+{
+ FILE *stream = (FILE *)arg;
+
+ switch (grn_ctx_get_output_type(ctx)) {
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ case GRN_CONTENT_NONE :
+ s_output_raw(ctx, flags, stream);
+ break;
+ default :
+ s_output_typed(ctx, flags, stream);
+ break;
+ }
+}
+
+static int
+do_alone(int argc, char **argv)
+{
+ int exit_code = EXIT_FAILURE;
+ char *path = NULL;
+ grn_obj *db;
+ grn_ctx ctx_, *ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ if (argc > 0 && argv) { path = *argv++; argc--; }
+ db = (newdb || !path) ? grn_db_create(ctx, path, NULL) : grn_db_open(ctx, path);
+ if (db) {
+ grn_obj command;
+ GRN_TEXT_INIT(&command, 0);
+ GRN_CTX_USER_DATA(ctx)->ptr = &command;
+ grn_ctx_recv_handler_set(ctx, s_output, output);
+ if (!argc) {
+ grn_obj text;
+ GRN_TEXT_INIT(&text, 0);
+ while (prompt(ctx, &text) != GRN_END_OF_DATA) {
+ GRN_TEXT_PUT(ctx, &command, GRN_TEXT_VALUE(&text), GRN_TEXT_LEN(&text));
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(&text), GRN_TEXT_LEN(&text), 0);
+ if (ctx->stat == GRN_CTX_QUIT) { break; }
+ }
+ exit_code = grn_rc_to_exit_code(ctx->rc);
+ grn_obj_unlink(ctx, &text);
+ } else {
+ grn_rc rc;
+ rc = grn_ctx_sendv(ctx, argc, argv, 0);
+ exit_code = grn_rc_to_exit_code(rc);
+ }
+ grn_obj_unlink(ctx, &command);
+ grn_obj_close(ctx, db);
+ } else {
+ fprintf(stderr, "db open failed (%s): %s\n", path, ctx->errbuf);
+ }
+ grn_ctx_fin(ctx);
+ return exit_code;
+}
+
+static int
+c_output(grn_ctx *ctx)
+{
+ int flags;
+ char *str;
+ unsigned int str_len;
+ do {
+ grn_ctx_recv(ctx, &str, &str_len, &flags);
+ /*
+ if (ctx->rc) {
+ fprintf(stderr, "grn_ctx_recv failed\n");
+ return -1;
+ }
+ */
+ if (str_len || ctx->rc) {
+ grn_obj head, body, foot;
+ GRN_TEXT_INIT(&head, 0);
+ GRN_TEXT_INIT(&body, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_INIT(&foot, 0);
+ if (ctx->rc == GRN_SUCCESS) {
+ GRN_TEXT_SET(ctx, &body, str, str_len);
+ } else {
+ ERR(ctx->rc, "%.*s", str_len, str);
+ }
+ output_envelope(ctx, ctx->rc, &head, &body, &foot);
+ fwrite(GRN_TEXT_VALUE(&head), 1, GRN_TEXT_LEN(&head), output);
+ fwrite(GRN_TEXT_VALUE(&body), 1, GRN_TEXT_LEN(&body), output);
+ fwrite(GRN_TEXT_VALUE(&foot), 1, GRN_TEXT_LEN(&foot), output);
+ fputc('\n', output);
+ fflush(output);
+ GRN_OBJ_FIN(ctx, &head);
+ GRN_OBJ_FIN(ctx, &body);
+ GRN_OBJ_FIN(ctx, &foot);
+ }
+ } while ((flags & GRN_CTX_MORE));
+ return 0;
+}
+
+static int
+g_client(int argc, char **argv)
+{
+ int exit_code = EXIT_FAILURE;
+ grn_ctx ctx_, *ctx = &ctx_;
+ const char *hostname = DEFAULT_DEST;
+ if (argc > 0 && argv) { hostname = *argv++; argc--; }
+ grn_ctx_init(ctx, 0);
+ if (!grn_ctx_connect(ctx, hostname, port, 0)) {
+ if (!argc) {
+ grn_obj text;
+ GRN_TEXT_INIT(&text, 0);
+ while (prompt(ctx, &text) != GRN_END_OF_DATA) {
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(&text), GRN_TEXT_LEN(&text), 0);
+ exit_code = grn_rc_to_exit_code(ctx->rc);
+ if (ctx->rc != GRN_SUCCESS) { break; }
+ if (c_output(ctx)) { goto exit; }
+ if (ctx->stat == GRN_CTX_QUIT) { break; }
+ }
+ grn_obj_unlink(ctx, &text);
+ } else {
+ grn_rc rc;
+ rc = grn_ctx_sendv(ctx, argc, argv, 0);
+ exit_code = grn_rc_to_exit_code(rc);
+ if (c_output(ctx)) { goto exit; }
+ }
+ } else {
+ fprintf(stderr, "grn_ctx_connect failed (%s:%d)\n", hostname, port);
+ }
+exit :
+ grn_ctx_fin(ctx);
+ return exit_code;
+}
+
+/* server */
+
+typedef void (*grn_edge_dispatcher_func)(grn_ctx *ctx, grn_edge *edge);
+typedef void (*grn_handler_func)(grn_ctx *ctx, grn_obj *msg);
+
+static grn_com_queue ctx_new;
+static grn_com_queue ctx_old;
+static grn_mutex q_mutex;
+static grn_cond q_cond;
+static uint32_t n_running_threads = 0;
+static uint32_t n_floating_threads = 0;
+static uint32_t max_n_floating_threads;
+
+static uint32_t
+groonga_get_thread_limit(void *data)
+{
+ return max_n_floating_threads;
+}
+
+static void
+groonga_set_thread_limit(uint32_t new_limit, void *data)
+{
+ uint32_t i;
+ uint32_t current_n_floating_threads;
+ static uint32_t n_changing_threads = 0;
+ uint32_t prev_n_changing_threads;
+
+ GRN_ATOMIC_ADD_EX(&n_changing_threads, 1, prev_n_changing_threads);
+
+ MUTEX_LOCK_ENSURE(&grn_gctx, q_mutex);
+ current_n_floating_threads = n_floating_threads;
+ max_n_floating_threads = new_limit;
+ MUTEX_UNLOCK(q_mutex);
+
+ if (prev_n_changing_threads > 0) {
+ GRN_ATOMIC_ADD_EX(&n_changing_threads, -1, prev_n_changing_threads);
+ return;
+ }
+
+ if (current_n_floating_threads > new_limit) {
+ for (i = 0; i < current_n_floating_threads; i++) {
+ MUTEX_LOCK_ENSURE(&grn_gctx, q_mutex);
+ COND_SIGNAL(q_cond);
+ MUTEX_UNLOCK(q_mutex);
+ }
+ }
+
+ while (GRN_TRUE) {
+ grn_bool is_reduced;
+ MUTEX_LOCK_ENSURE(&grn_gctx, q_mutex);
+ is_reduced = (n_running_threads <= max_n_floating_threads);
+ if (!is_reduced && n_floating_threads > 0) {
+ COND_SIGNAL(q_cond);
+ }
+ MUTEX_UNLOCK(q_mutex);
+ if (is_reduced) {
+ break;
+ }
+ grn_nanosleep(1000000);
+ }
+
+ GRN_ATOMIC_ADD_EX(&n_changing_threads, -1, prev_n_changing_threads);
+}
+
+typedef struct {
+ grn_mutex mutex;
+ grn_ctx ctx;
+ grn_pat *entries;
+ uint64_t earliest_unix_time_msec;
+} request_timer_data;
+static request_timer_data the_request_timer_data;
+
+static void *
+request_timer_register(const char *request_id,
+ unsigned int request_id_size,
+ double timeout,
+ void *user_data)
+{
+ request_timer_data *data = user_data;
+ grn_id id = GRN_ID_NIL;
+
+ {
+ grn_ctx *ctx = &(data->ctx);
+ grn_bool is_first_timer;
+ grn_timeval tv;
+ uint64_t timeout_unix_time_msec;
+ void *value;
+
+ MUTEX_LOCK(data->mutex);
+ is_first_timer = (grn_pat_size(ctx, data->entries) == 0);
+ grn_timeval_now(ctx, &tv);
+ timeout_unix_time_msec = GRN_TIMEVAL_TO_MSEC(&tv) + (timeout * 1000);
+ while (GRN_TRUE) {
+ int added;
+ id = grn_pat_add(ctx, data->entries,
+ &timeout_unix_time_msec, sizeof(uint64_t),
+ &value, &added);
+ if (added != 0) {
+ break;
+ }
+ timeout_unix_time_msec++;
+ }
+ grn_memcpy(value, &request_id_size, sizeof(unsigned int));
+ grn_memcpy(((uint8_t *)value) + sizeof(unsigned int),
+ request_id, request_id_size);
+ if (data->earliest_unix_time_msec == 0 ||
+ data->earliest_unix_time_msec > timeout_unix_time_msec) {
+ data->earliest_unix_time_msec = timeout_unix_time_msec;
+ }
+ if (is_first_timer) {
+ break_accept_event_loop(ctx);
+ }
+ MUTEX_UNLOCK(data->mutex);
+ }
+
+ return (void *)(uint64_t)id;
+}
+
+static void
+request_timer_unregister(void *timer_id,
+ void *user_data)
+{
+ request_timer_data *data = user_data;
+ grn_id id = (grn_id)(uint64_t)timer_id;
+
+ {
+ grn_ctx *ctx = &(data->ctx);
+ uint64_t timeout_unix_time_msec;
+ int key_size;
+
+ MUTEX_LOCK(data->mutex);
+ key_size = grn_pat_get_key(ctx,
+ data->entries,
+ id,
+ &timeout_unix_time_msec,
+ sizeof(uint64_t));
+ if (key_size > 0) {
+ grn_pat_delete_by_id(ctx, data->entries, id, NULL);
+ if (data->earliest_unix_time_msec >= timeout_unix_time_msec) {
+ data->earliest_unix_time_msec = 0;
+ }
+ }
+ MUTEX_UNLOCK(data->mutex);
+ }
+}
+
+static void
+request_timer_fin(void *user_data)
+{
+ request_timer_data *data = user_data;
+
+ {
+ grn_ctx *ctx = &(data->ctx);
+ grn_pat_close(ctx, data->entries);
+ grn_ctx_fin(ctx);
+ MUTEX_FIN(data->mutex);
+ }
+}
+
+static void
+request_timer_init(void)
+{
+ static grn_request_timer timer;
+ request_timer_data *data = &the_request_timer_data;
+ grn_ctx *ctx;
+
+ MUTEX_INIT(data->mutex);
+ ctx = &(data->ctx);
+ grn_ctx_init(ctx, 0);
+ data->entries = grn_pat_create(ctx,
+ NULL,
+ sizeof(uint64_t),
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_OBJ_KEY_UINT);
+ data->earliest_unix_time_msec = 0;
+
+ timer.user_data = data;
+ timer.register_func = request_timer_register;
+ timer.unregister_func = request_timer_unregister;
+ timer.fin_func = request_timer_fin;
+
+ grn_request_timer_set(&timer);
+}
+
+static grn_bool
+request_timer_ensure_earliest_unix_time_msec(void)
+{
+ request_timer_data *data = &the_request_timer_data;
+ grn_ctx *ctx;
+ grn_pat_cursor *cursor;
+
+ if (data->earliest_unix_time_msec > 0) {
+ return GRN_TRUE;
+ }
+
+ ctx = &(data->ctx);
+ cursor = grn_pat_cursor_open(ctx, data->entries,
+ NULL, 0,
+ NULL, 0,
+ 0, 1, GRN_CURSOR_ASCENDING);
+ if (!cursor) {
+ return GRN_FALSE;
+ }
+ while (grn_pat_cursor_next(ctx, cursor) != GRN_ID_NIL) {
+ void *key;
+ uint64_t timeout_unix_time_msec;
+
+ grn_pat_cursor_get_key(ctx, cursor, &key);
+ timeout_unix_time_msec = *(uint64_t *)key;
+ data->earliest_unix_time_msec = timeout_unix_time_msec;
+ break;
+ }
+ grn_pat_cursor_close(ctx, cursor);
+
+ return data->earliest_unix_time_msec > 0;
+}
+
+static int
+request_timer_get_poll_timeout(void)
+{
+ request_timer_data *data = &the_request_timer_data;
+ int timeout = 1000;
+ grn_ctx *ctx;
+ grn_timeval tv;
+
+ MUTEX_LOCK(data->mutex);
+ ctx = &(data->ctx);
+ if (grn_pat_size(ctx, data->entries) == 0) {
+ goto exit;
+ }
+
+ if (!request_timer_ensure_earliest_unix_time_msec()) {
+ goto exit;
+ }
+
+ grn_timeval_now(ctx, &tv);
+ timeout = data->earliest_unix_time_msec - GRN_TIMEVAL_TO_MSEC(&tv);
+ if (timeout < 0) {
+ timeout = 0;
+ } else if (timeout > 1000) {
+ timeout = 1000;
+ }
+
+exit :
+ MUTEX_UNLOCK(data->mutex);
+
+ return timeout;
+}
+
+static void
+request_timer_process_timeout(void)
+{
+ request_timer_data *data = &the_request_timer_data;
+ grn_ctx *ctx;
+ grn_timeval tv;
+ uint64_t max;
+ grn_pat_cursor *cursor;
+
+ ctx = &(data->ctx);
+ if (grn_pat_size(ctx, data->entries) == 0) {
+ return;
+ }
+
+ grn_timeval_now(ctx, &tv);
+ max = GRN_TIMEVAL_TO_MSEC(&tv);
+ cursor = grn_pat_cursor_open(ctx, data->entries,
+ NULL, 0,
+ &max, sizeof(uint64_t),
+ 0, -1, GRN_CURSOR_ASCENDING);
+ if (!cursor) {
+ return;
+ }
+
+ grn_id id;
+ while ((id = grn_pat_cursor_next(ctx, cursor)) != GRN_ID_NIL) {
+ void *value;
+ const char *request_id;
+ unsigned int request_id_size;
+
+ grn_pat_cursor_get_value(ctx, cursor, &value);
+ request_id_size = *((unsigned int *)value);
+ request_id = (const char *)(((uint8_t *)value) + sizeof(unsigned int));
+ grn_request_canceler_cancel(request_id, request_id_size);
+ }
+ grn_pat_cursor_close(ctx, cursor);
+}
+
+static void
+reset_ready_notify_pipe(void)
+{
+ ready_notify_pipe[PIPE_READ] = 0;
+ ready_notify_pipe[PIPE_WRITE] = 0;
+}
+
+static void
+close_ready_notify_pipe(void)
+{
+ if (ready_notify_pipe[PIPE_READ] > 0) {
+ close(ready_notify_pipe[PIPE_READ]);
+ }
+ if (ready_notify_pipe[PIPE_WRITE] > 0) {
+ close(ready_notify_pipe[PIPE_WRITE]);
+ }
+ reset_ready_notify_pipe();
+}
+
+static void
+send_ready_notify(void)
+{
+ if (ready_notify_pipe[PIPE_WRITE] > 0) {
+ const char *ready_notify_message = "ready";
+ write(ready_notify_pipe[PIPE_WRITE],
+ ready_notify_message,
+ strlen(ready_notify_message));
+ }
+ close_ready_notify_pipe();
+}
+
+static void
+create_pid_file(void)
+{
+ FILE *pid_file = NULL;
+
+ if (!pid_file_path) {
+ return;
+ }
+
+ pid_file = fopen(pid_file_path, "w");
+ if (!pid_file) {
+ fprintf(stderr,
+ "Failed to open PID file: <%s>: <%s>\n",
+ pid_file_path, grn_strerror(errno));
+ return;
+ }
+
+ {
+#ifdef WIN32
+ DWORD pid;
+ pid = GetCurrentProcessId();
+ fprintf(pid_file, "%" GRN_FMT_DWORD "\n", pid);
+#else /* WIN32 */
+ pid_t pid;
+ pid = grn_getpid();
+ fprintf(pid_file, "%d\n", pid);
+#endif /* WIN32 */
+ }
+ fclose(pid_file);
+}
+
+static void
+clean_pid_file(void)
+{
+ if (pid_file_path) {
+ grn_unlink(pid_file_path);
+ }
+}
+
+static int
+daemonize(void)
+{
+ int exit_code = EXIT_SUCCESS;
+#ifndef WIN32
+
+ if (pipe(ready_notify_pipe) == -1) {
+ reset_ready_notify_pipe();
+ }
+
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ perror("fork");
+ return EXIT_FAILURE;
+ default:
+ wait(NULL);
+ if (ready_notify_pipe[PIPE_READ] > 0) {
+ int max_fd;
+ fd_set read_fds;
+ FD_ZERO(&read_fds);
+ FD_SET(ready_notify_pipe[PIPE_READ], &read_fds);
+ max_fd = ready_notify_pipe[PIPE_READ] + 1;
+ select(max_fd, &read_fds, NULL, NULL, NULL);
+ }
+ close_ready_notify_pipe();
+ _exit(EXIT_SUCCESS);
+ }
+ switch (fork()) {
+ case 0:
+ if (pid_file_path) {
+ create_pid_file();
+ } else {
+ pid_t pid;
+ pid = grn_getpid();
+ fprintf(stderr, "%d\n", pid);
+ }
+ break;
+ case -1:
+ perror("fork");
+ return EXIT_FAILURE;
+ default:
+ close_ready_notify_pipe();
+ _exit(EXIT_SUCCESS);
+ }
+ {
+ int null_fd;
+ grn_open(null_fd, "/dev/null", O_RDWR);
+ if (null_fd != -1) {
+ dup2(null_fd, STDIN_FILENO);
+ dup2(null_fd, STDOUT_FILENO);
+ dup2(null_fd, STDERR_FILENO);
+ if (null_fd > STDERR_FILENO) { grn_close(null_fd); }
+ }
+ }
+#endif /* WIN32 */
+ return exit_code;
+}
+
+static void
+run_server_loop(grn_ctx *ctx, grn_com_event *ev)
+{
+ request_timer_init();
+ while (!grn_com_event_poll(ctx, ev, request_timer_get_poll_timeout()) &&
+ grn_gctx.stat != GRN_CTX_QUIT) {
+ grn_edge *edge;
+ while ((edge = (grn_edge *)grn_com_queue_deque(ctx, &ctx_old))) {
+ grn_obj *msg;
+ while ((msg = (grn_obj *)grn_com_queue_deque(ctx, &edge->send_old))) {
+ grn_msg_close(&edge->ctx, msg);
+ }
+ while ((msg = (grn_obj *)grn_com_queue_deque(ctx, &edge->recv_new))) {
+ grn_msg_close(ctx, msg);
+ }
+ grn_ctx_fin(&edge->ctx);
+ if (edge->com->has_sid && edge->com->opaque == edge) {
+ grn_com_close(ctx, edge->com);
+ }
+ grn_edges_delete(ctx, edge);
+ }
+ request_timer_process_timeout();
+ /* todo : log stat */
+ }
+ for (;;) {
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ if (n_running_threads == n_floating_threads) { break; }
+ MUTEX_UNLOCK(q_mutex);
+ grn_nanosleep(1000000);
+ }
+ {
+ grn_edge *edge;
+ GRN_HASH_EACH(ctx, grn_edges, id, NULL, NULL, &edge, {
+ grn_obj *obj;
+ while ((obj = (grn_obj *)grn_com_queue_deque(ctx, &edge->send_old))) {
+ grn_msg_close(&edge->ctx, obj);
+ }
+ while ((obj = (grn_obj *)grn_com_queue_deque(ctx, &edge->recv_new))) {
+ grn_msg_close(ctx, obj);
+ }
+ grn_ctx_fin(&edge->ctx);
+ if (edge->com->has_sid) {
+ grn_com_close(ctx, edge->com);
+ }
+ grn_edges_delete(ctx, edge);
+ });
+ }
+ {
+ grn_com *com;
+ GRN_HASH_EACH(ctx, ev->hash, id, NULL, NULL, &com, { grn_com_close(ctx, com); });
+ }
+}
+
+static int
+run_server(grn_ctx *ctx, grn_obj *db, grn_com_event *ev,
+ grn_edge_dispatcher_func dispatcher, grn_handler_func handler)
+{
+ int exit_code = EXIT_SUCCESS;
+ struct hostent *he;
+ if (!(he = gethostbyname(hostname))) {
+ send_ready_notify();
+ SOERR("gethostbyname");
+ } else {
+ ev->opaque = db;
+ grn_edges_init(ctx, dispatcher);
+ if (!grn_com_sopen(ctx, ev, bind_address, port, handler, he)) {
+ send_ready_notify();
+ run_server_loop(ctx, ev);
+ exit_code = EXIT_SUCCESS;
+ } else {
+ send_ready_notify();
+ fprintf(stderr, "grn_com_sopen failed (%s:%d): %s\n",
+ bind_address, port, ctx->errbuf);
+ }
+ grn_edges_fin(ctx);
+ }
+ return exit_code;
+}
+
+static grn_bool memcached_init(grn_ctx *ctx);
+
+static int
+start_service(grn_ctx *ctx, const char *db_path,
+ grn_edge_dispatcher_func dispatcher, grn_handler_func handler)
+{
+ int exit_code = EXIT_SUCCESS;
+ grn_com_event ev;
+
+ if (is_daemon_mode) {
+ exit_code = daemonize();
+ if (exit_code != EXIT_SUCCESS) {
+ return exit_code;
+ }
+ } else {
+ create_pid_file();
+ }
+
+ if (!grn_com_event_init(ctx, &ev, MAX_CON, sizeof(grn_com))) {
+ grn_obj *db;
+ db = (newdb || !db_path) ? grn_db_create(ctx, db_path, NULL) : grn_db_open(ctx, db_path);
+ if (db) {
+ if (is_memcached_mode) {
+ if (!memcached_init(ctx)) {
+ fprintf(stderr, "failed to initialize memcached mode: %s\n",
+ ctx->errbuf);
+ exit_code = EXIT_FAILURE;
+ send_ready_notify();
+ }
+ }
+ if (exit_code == EXIT_SUCCESS) {
+ exit_code = run_server(ctx, db, &ev, dispatcher, handler);
+ }
+ grn_obj_close(ctx, db);
+ } else {
+ fprintf(stderr, "db open failed (%s): %s\n", db_path, ctx->errbuf);
+ exit_code = EXIT_FAILURE;
+ send_ready_notify();
+ }
+ grn_com_event_fin(ctx, &ev);
+ } else {
+ fprintf(stderr, "grn_com_event_init failed\n");
+ exit_code = EXIT_FAILURE;
+ send_ready_notify();
+ }
+
+ clean_pid_file();
+
+ return exit_code;
+}
+
+typedef struct {
+ grn_msg *msg;
+ grn_bool in_body;
+ grn_bool is_chunked;
+} ht_context;
+
+static void
+h_output_set_header(grn_ctx *ctx,
+ grn_obj *header,
+ grn_rc rc,
+ long long int content_length,
+ grn_obj *foot)
+{
+ switch (rc) {
+ case GRN_SUCCESS :
+ GRN_TEXT_SETS(ctx, header, "HTTP/1.1 200 OK\r\n");
+ break;
+ case GRN_INVALID_ARGUMENT :
+ case GRN_FUNCTION_NOT_IMPLEMENTED :
+ case GRN_SYNTAX_ERROR :
+ GRN_TEXT_SETS(ctx, header, "HTTP/1.1 400 Bad Request\r\n");
+ break;
+ case GRN_NO_SUCH_FILE_OR_DIRECTORY :
+ GRN_TEXT_SETS(ctx, header, "HTTP/1.1 404 Not Found\r\n");
+ break;
+ case GRN_CANCEL :
+ GRN_TEXT_SETS(ctx, header, "HTTP/1.1 408 Request Timeout\r\n");
+ break;
+ default :
+ GRN_TEXT_SETS(ctx, header, "HTTP/1.1 500 Internal Server Error\r\n");
+ break;
+ }
+ GRN_TEXT_PUT(ctx, header,
+ GRN_TEXT_VALUE(&http_response_server_line),
+ GRN_TEXT_LEN(&http_response_server_line));
+ GRN_TEXT_PUTS(ctx, header, "Content-Type: ");
+ if (grn_ctx_get_output_type(ctx) == GRN_CONTENT_JSON &&
+ foot &&
+ GRN_TEXT_LEN(foot) > 0 &&
+ GRN_TEXT_VALUE(foot)[GRN_TEXT_LEN(foot) - 1] == ';') {
+ GRN_TEXT_PUTS(ctx, header, "application/javascript");
+ } else {
+ GRN_TEXT_PUTS(ctx, header, grn_ctx_get_mime_type(ctx));
+ }
+ GRN_TEXT_PUTS(ctx, header, "\r\n");
+ if (content_length >= 0) {
+ GRN_TEXT_PUTS(ctx, header, "Connection: close\r\n");
+ GRN_TEXT_PUTS(ctx, header, "Content-Length: ");
+ grn_text_lltoa(ctx, header, content_length);
+ GRN_TEXT_PUTS(ctx, header, "\r\n");
+ } else {
+ GRN_TEXT_PUTS(ctx, header, "Transfer-Encoding: chunked\r\n");
+ }
+ GRN_TEXT_PUTS(ctx, header, "\r\n");
+}
+
+static void
+h_output_send(grn_ctx *ctx, grn_sock fd,
+ grn_obj *header, grn_obj *head, grn_obj *body, grn_obj *foot)
+{
+ ssize_t ret;
+ ssize_t len = 0;
+#ifdef WIN32
+ int n_buffers = 0;
+ WSABUF wsabufs[4];
+ if (header) {
+ wsabufs[n_buffers].buf = GRN_TEXT_VALUE(header);
+ wsabufs[n_buffers].len = GRN_TEXT_LEN(header);
+ len += GRN_TEXT_LEN(header);
+ n_buffers++;
+ }
+ if (head) {
+ wsabufs[n_buffers].buf = GRN_TEXT_VALUE(head);
+ wsabufs[n_buffers].len = GRN_TEXT_LEN(head);
+ len += GRN_TEXT_LEN(head);
+ n_buffers++;
+ }
+ if (body) {
+ wsabufs[n_buffers].buf = GRN_TEXT_VALUE(body);
+ wsabufs[n_buffers].len = GRN_TEXT_LEN(body);
+ len += GRN_TEXT_LEN(body);
+ n_buffers++;
+ }
+ if (foot) {
+ wsabufs[n_buffers].buf = GRN_TEXT_VALUE(foot);
+ wsabufs[n_buffers].len = GRN_TEXT_LEN(foot);
+ len += GRN_TEXT_LEN(foot);
+ n_buffers++;
+ }
+ {
+ DWORD sent;
+ if (WSASend(fd, wsabufs, n_buffers, &sent, 0, NULL, NULL) == SOCKET_ERROR) {
+ SOERR("WSASend");
+ }
+ ret = sent;
+ }
+#else /* WIN32 */
+ struct iovec msg_iov[4];
+ struct msghdr msg;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = msg_iov;
+ msg.msg_iovlen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_flags = 0;
+
+ if (header) {
+ msg_iov[msg.msg_iovlen].iov_base = GRN_TEXT_VALUE(header);
+ msg_iov[msg.msg_iovlen].iov_len = GRN_TEXT_LEN(header);
+ len += GRN_TEXT_LEN(header);
+ msg.msg_iovlen++;
+ }
+ if (head) {
+ msg_iov[msg.msg_iovlen].iov_base = GRN_TEXT_VALUE(head);
+ msg_iov[msg.msg_iovlen].iov_len = GRN_TEXT_LEN(head);
+ len += GRN_TEXT_LEN(head);
+ msg.msg_iovlen++;
+ }
+ if (body) {
+ msg_iov[msg.msg_iovlen].iov_base = GRN_TEXT_VALUE(body);
+ msg_iov[msg.msg_iovlen].iov_len = GRN_TEXT_LEN(body);
+ len += GRN_TEXT_LEN(body);
+ msg.msg_iovlen++;
+ }
+ if (foot) {
+ msg_iov[msg.msg_iovlen].iov_base = GRN_TEXT_VALUE(foot);
+ msg_iov[msg.msg_iovlen].iov_len = GRN_TEXT_LEN(foot);
+ len += GRN_TEXT_LEN(foot);
+ msg.msg_iovlen++;
+ }
+ if ((ret = sendmsg(fd, &msg, MSG_NOSIGNAL)) == -1) {
+ SOERR("sendmsg");
+ }
+#endif /* WIN32 */
+ if (ret != len) {
+ GRN_LOG(&grn_gctx, GRN_LOG_NOTICE,
+ "couldn't send all data (%" GRN_FMT_LLD "/%" GRN_FMT_LLD ")",
+ (long long int)ret, (long long int)len);
+ }
+}
+
+static void
+h_output_raw(grn_ctx *ctx, int flags, ht_context *hc)
+{
+ grn_rc expr_rc = ctx->rc;
+ grn_sock fd = hc->msg->u.fd;
+ grn_obj header_;
+ grn_obj head_;
+ grn_obj body_;
+ grn_obj foot_;
+ grn_obj *header = NULL;
+ grn_obj *head = NULL;
+ grn_obj *body = NULL;
+ grn_obj *foot = NULL;
+ char *chunk = NULL;
+ unsigned int chunk_size = 0;
+ int recv_flags;
+ grn_bool is_last_message = (flags & GRN_CTX_TAIL);
+
+ GRN_TEXT_INIT(&header_, 0);
+ GRN_TEXT_INIT(&head_, 0);
+ GRN_TEXT_INIT(&body_, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_INIT(&foot_, 0);
+
+ grn_ctx_recv(ctx, &chunk, &chunk_size, &recv_flags);
+ GRN_TEXT_SET(ctx, &body_, chunk, chunk_size);
+
+ if (!hc->in_body) {
+ if (is_last_message) {
+ h_output_set_header(ctx, &header_, expr_rc, GRN_TEXT_LEN(&body_), NULL);
+ hc->is_chunked = GRN_FALSE;
+ } else {
+ h_output_set_header(ctx, &header_, expr_rc, -1, NULL);
+ hc->is_chunked = GRN_TRUE;
+ }
+ header = &header_;
+ hc->in_body = GRN_TRUE;
+ }
+
+ if (GRN_TEXT_LEN(&body_) > 0) {
+ if (hc->is_chunked) {
+ grn_text_printf(ctx, &head_,
+ "%x\r\n", (unsigned int)GRN_TEXT_LEN(&body_));
+ head = &head_;
+ GRN_TEXT_PUTS(ctx, &foot_, "\r\n");
+ foot = &foot_;
+ }
+ body = &body_;
+ }
+
+ if (is_last_message) {
+ if (hc->is_chunked) {
+ GRN_TEXT_PUTS(ctx, &foot_, "0\r\n");
+ GRN_TEXT_PUTS(ctx, &foot_, "Connection: close\r\n");
+ GRN_TEXT_PUTS(ctx, &foot_, "\r\n");
+ foot = &foot_;
+ }
+ }
+
+ h_output_send(ctx, fd, header, head, body, foot);
+
+ GRN_OBJ_FIN(ctx, &foot_);
+ GRN_OBJ_FIN(ctx, &body_);
+ GRN_OBJ_FIN(ctx, &head_);
+ GRN_OBJ_FIN(ctx, &header_);
+}
+
+static void
+h_output_typed(grn_ctx *ctx, int flags, ht_context *hc)
+{
+ grn_rc expr_rc = ctx->rc;
+ grn_sock fd = hc->msg->u.fd;
+ grn_obj header, head, body, foot;
+ char *chunk = NULL;
+ unsigned int chunk_size = 0;
+ int recv_flags;
+ grn_bool should_return_body;
+
+ if (!(flags & GRN_CTX_TAIL)) { return; }
+
+ switch (hc->msg->header.qtype) {
+ case 'G' :
+ case 'P' :
+ should_return_body = GRN_TRUE;
+ break;
+ default :
+ should_return_body = GRN_FALSE;
+ break;
+ }
+
+ GRN_TEXT_INIT(&header, 0);
+ GRN_TEXT_INIT(&head, 0);
+ GRN_TEXT_INIT(&body, 0);
+ GRN_TEXT_INIT(&foot, 0);
+
+ grn_ctx_recv(ctx, &chunk, &chunk_size, &recv_flags);
+ GRN_TEXT_SET(ctx, &body, chunk, chunk_size);
+
+ output_envelope(ctx, expr_rc, &head, &body, &foot);
+ h_output_set_header(ctx, &header, expr_rc,
+ GRN_TEXT_LEN(&head) +
+ GRN_TEXT_LEN(&body) +
+ GRN_TEXT_LEN(&foot),
+ &foot);
+ if (should_return_body) {
+ h_output_send(ctx, fd, &header, &head, &body, &foot);
+ } else {
+ h_output_send(ctx, fd, &header, NULL, NULL, NULL);
+ }
+ GRN_OBJ_FIN(ctx, &foot);
+ GRN_OBJ_FIN(ctx, &body);
+ GRN_OBJ_FIN(ctx, &head);
+ GRN_OBJ_FIN(ctx, &header);
+}
+
+static void
+h_output(grn_ctx *ctx, int flags, void *arg)
+{
+ ht_context *hc = (ht_context *)arg;
+
+ switch (grn_ctx_get_output_type(ctx)) {
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ case GRN_CONTENT_NONE :
+ h_output_raw(ctx, flags, hc);
+ break;
+ default :
+ h_output_typed(ctx, flags, hc);
+ break;
+ }
+}
+
+static void
+do_htreq_get(grn_ctx *ctx, ht_context *hc)
+{
+ grn_msg *msg = hc->msg;
+ char *path = NULL;
+ char *pathe = GRN_BULK_HEAD((grn_obj *)msg);
+ char *e = GRN_BULK_CURR((grn_obj *)msg);
+ for (;; pathe++) {
+ if (e <= pathe + 6) {
+ /* invalid request */
+ return;
+ }
+ if (*pathe == ' ') {
+ if (!path) {
+ path = pathe + 1;
+ } else {
+ if (!memcmp(pathe + 1, "HTTP/1", 6)) {
+ break;
+ }
+ }
+ }
+ }
+ grn_ctx_send(ctx, path, pathe - path, GRN_CTX_TAIL);
+}
+
+typedef struct {
+ const char *path_start;
+ int path_length;
+ long long int content_length;
+ grn_bool have_100_continue;
+ const char *body_start;
+} h_post_header;
+
+#define STRING_EQUAL(string, string_length, constant_string)\
+ (string_length == strlen(constant_string) &&\
+ strncmp(string, constant_string, string_length) == 0)
+
+#define STRING_EQUAL_CI(string, string_length, constant_string)\
+ (string_length == strlen(constant_string) &&\
+ grn_strncasecmp(string, constant_string, string_length) == 0)
+
+static const char *
+do_htreq_post_parse_header_request_line(grn_ctx *ctx,
+ const char *start,
+ const char *end,
+ h_post_header *header)
+{
+ const char *current;
+
+ {
+ const char *method = start;
+ int method_length = -1;
+
+ for (current = method; current < end; current++) {
+ if (current[0] == '\n') {
+ return NULL;
+ }
+ if (current[0] == ' ') {
+ method_length = current - method;
+ current++;
+ break;
+ }
+ }
+ if (method_length == -1) {
+ return NULL;
+ }
+ if (!STRING_EQUAL_CI(method, method_length, "POST")) {
+ return NULL;
+ }
+ }
+
+ {
+ header->path_start = current;
+ header->path_length = -1;
+ for (; current < end; current++) {
+ if (current[0] == '\n') {
+ return NULL;
+ }
+ if (current[0] == ' ') {
+ header->path_length = current - header->path_start;
+ current++;
+ break;
+ }
+ }
+ if (header->path_length == -1) {
+ return NULL;
+ }
+ }
+
+ {
+ const char *http_version_start = current;
+ int http_version_length = -1;
+ for (; current < end; current++) {
+ if (current[0] == '\n') {
+ http_version_length = current - http_version_start;
+ if (http_version_length > 0 &&
+ http_version_start[http_version_length - 1] == '\r') {
+ http_version_length--;
+ }
+ current++;
+ break;
+ }
+ }
+ if (http_version_length == -1) {
+ return NULL;
+ }
+ if (!(STRING_EQUAL_CI(http_version_start, http_version_length, "HTTP/1.0") ||
+ STRING_EQUAL_CI(http_version_start, http_version_length, "HTTP/1.1"))) {
+ return NULL;
+ }
+ }
+
+ return current;
+}
+
+static const char *
+do_htreq_post_parse_header_values(grn_ctx *ctx,
+ const char *start,
+ const char *end,
+ h_post_header *header)
+{
+ const char *current;
+ const char *name = start;
+ int name_length = -1;
+ const char *value = NULL;
+ int value_length = -1;
+
+ for (current = start; current < end; current++) {
+ switch (current[0]) {
+ case '\n' :
+ if (name_length == -1) {
+ if (current - name == 1 && current[-1] == '\r') {
+ return current + 1;
+ } else {
+ /* No ":" header line. TODO: report error. */
+ return NULL;
+ }
+ } else {
+ while (value < current && value[0] == ' ') {
+ value++;
+ }
+ value_length = current - value;
+ if (value_length > 0 && value[value_length - 1] == '\r') {
+ value_length--;
+ }
+ if (STRING_EQUAL_CI(name, name_length, "Content-Length")) {
+ const char *rest;
+ header->content_length = grn_atoll(value, value + value_length, &rest);
+ if (rest != value + value_length) {
+ /* Invalid Content-Length value. TODO: report error. */
+ header->content_length = -1;
+ }
+ } else if (STRING_EQUAL_CI(name, name_length, "Expect")) {
+ if (STRING_EQUAL(value, value_length, "100-continue")) {
+ header->have_100_continue = GRN_TRUE;
+ }
+ }
+ }
+ name = current + 1;
+ name_length = -1;
+ value = NULL;
+ value_length = -1;
+ break;
+ case ':' :
+ if (name_length == -1) {
+ name_length = current - name;
+ value = current + 1;
+ }
+ break;
+ default :
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static grn_bool
+do_htreq_post_parse_header(grn_ctx *ctx,
+ const char *start,
+ const char *end,
+ h_post_header *header)
+{
+ const char *current;
+
+ current = do_htreq_post_parse_header_request_line(ctx, start, end, header);
+ if (!current) {
+ return GRN_FALSE;
+ }
+ current = do_htreq_post_parse_header_values(ctx, current, end, header);
+ if (!current) {
+ return GRN_FALSE;
+ }
+
+ if (current == end) {
+ header->body_start = NULL;
+ } else {
+ header->body_start = current;
+ }
+
+ return GRN_TRUE;
+}
+
+static void
+do_htreq_post(grn_ctx *ctx, ht_context *hc)
+{
+ grn_msg *msg = hc->msg;
+ grn_sock fd = msg->u.fd;
+ const char *end;
+ h_post_header header;
+
+ header.path_start = NULL;
+ header.path_length = -1;
+ header.content_length = -1;
+ header.body_start = NULL;
+ header.have_100_continue = GRN_FALSE;
+
+ end = GRN_BULK_CURR((grn_obj *)msg);
+ if (!do_htreq_post_parse_header(ctx,
+ GRN_BULK_HEAD((grn_obj *)msg),
+ end,
+ &header)) {
+ return;
+ }
+
+ grn_ctx_send(ctx, header.path_start, header.path_length, GRN_CTX_MORE);
+ if (ctx->rc != GRN_SUCCESS) {
+ ht_context context;
+ context.msg = msg;
+ context.in_body = GRN_FALSE;
+ context.is_chunked = GRN_FALSE;
+ h_output(ctx, GRN_CTX_TAIL, &context);
+ return;
+ }
+
+ if (header.have_100_continue) {
+ const char *continue_message = "HTTP/1.1 100 Continue\r\n";
+ ssize_t send_size;
+ int send_flags = MSG_NOSIGNAL;
+ send_size = send(fd, continue_message, strlen(continue_message), send_flags);
+ if (send_size == -1) {
+ SOERR("send");
+ return;
+ }
+ }
+
+ {
+ grn_obj chunk_buffer;
+ long long int read_content_length = 0;
+
+ GRN_TEXT_INIT(&chunk_buffer, 0);
+ while (read_content_length < header.content_length) {
+#define POST_BUFFER_SIZE 8192
+ char buffer[POST_BUFFER_SIZE];
+ const char *buffer_start, *buffer_current, *buffer_end;
+
+ if (header.body_start) {
+ buffer_start = header.body_start;
+ buffer_end = end;
+ header.body_start = NULL;
+ } else {
+ ssize_t recv_length;
+ int recv_flags = 0;
+ recv_length = recv(fd, buffer, POST_BUFFER_SIZE, recv_flags);
+ if (recv_length == 0) {
+ break;
+ }
+ if (recv_length == -1) {
+ SOERR("recv");
+ break;
+ }
+ buffer_start = buffer;
+ buffer_end = buffer_start + recv_length;
+ }
+ read_content_length += buffer_end - buffer_start;
+
+ buffer_current = buffer_end - 1;
+ for (; buffer_current > buffer_start; buffer_current--) {
+ grn_bool is_separator;
+ switch (buffer_current[0]) {
+ case '\n' :
+ case ',' :
+ is_separator = GRN_TRUE;
+ break;
+ default :
+ is_separator = GRN_FALSE;
+ break;
+ }
+ if (!is_separator) {
+ continue;
+ }
+
+ GRN_TEXT_PUT(ctx,
+ &chunk_buffer,
+ buffer_start,
+ buffer_current + 1 - buffer_start);
+ {
+ int flags = 0;
+ if (!(read_content_length == header.content_length &&
+ buffer_current + 1 == buffer_end)) {
+ flags |= GRN_CTX_MORE;
+ } else {
+ flags |= GRN_CTX_TAIL;
+ }
+ grn_ctx_send(ctx,
+ GRN_TEXT_VALUE(&chunk_buffer),
+ GRN_TEXT_LEN(&chunk_buffer),
+ flags);
+ }
+ buffer_start = buffer_current + 1;
+ GRN_BULK_REWIND(&chunk_buffer);
+ break;
+ }
+ if (buffer_end > buffer_start) {
+ GRN_TEXT_PUT(ctx, &chunk_buffer,
+ buffer_start, buffer_end - buffer_start);
+ }
+#undef POST_BUFFER_SIZE
+
+ if (ctx->rc != GRN_SUCCESS) {
+ break;
+ }
+ }
+
+ if (ctx->rc == GRN_CANCEL) {
+ h_output(ctx, GRN_CTX_TAIL, hc);
+ } else if (ctx->rc == GRN_SUCCESS && GRN_TEXT_LEN(&chunk_buffer) > 0) {
+ grn_ctx_send(ctx,
+ GRN_TEXT_VALUE(&chunk_buffer),
+ GRN_TEXT_LEN(&chunk_buffer),
+ GRN_CTX_TAIL);
+ }
+
+ GRN_OBJ_FIN(ctx, &chunk_buffer);
+ }
+}
+
+static void
+do_htreq(grn_ctx *ctx, ht_context *hc)
+{
+ grn_msg *msg = hc->msg;
+ grn_com_header *header = &msg->header;
+ switch (header->qtype) {
+ case 'G' : /* GET */
+ case 'H' : /* HEAD */
+ do_htreq_get(ctx, hc);
+ break;
+ case 'P' : /* POST */
+ do_htreq_post(ctx, hc);
+ break;
+ }
+ /* if (ctx->rc != GRN_OPERATION_WOULD_BLOCK) {...} */
+ grn_msg_close(ctx, (grn_obj *)msg);
+ /* if not keep alive connection */
+ grn_sock_close(msg->u.fd);
+ grn_com_event_start_accept(ctx, msg->acceptor->ev);
+}
+
+enum {
+ MBRES_SUCCESS = 0x00,
+ MBRES_KEY_ENOENT = 0x01,
+ MBRES_KEY_EEXISTS = 0x02,
+ MBRES_E2BIG = 0x03,
+ MBRES_EINVAL = 0x04,
+ MBRES_NOT_STORED = 0x05,
+ MBRES_UNKNOWN_COMMAND = 0x81,
+ MBRES_ENOMEM = 0x82,
+};
+
+enum {
+ MBCMD_GET = 0x00,
+ MBCMD_SET = 0x01,
+ MBCMD_ADD = 0x02,
+ MBCMD_REPLACE = 0x03,
+ MBCMD_DELETE = 0x04,
+ MBCMD_INCREMENT = 0x05,
+ MBCMD_DECREMENT = 0x06,
+ MBCMD_QUIT = 0x07,
+ MBCMD_FLUSH = 0x08,
+ MBCMD_GETQ = 0x09,
+ MBCMD_NOOP = 0x0a,
+ MBCMD_VERSION = 0x0b,
+ MBCMD_GETK = 0x0c,
+ MBCMD_GETKQ = 0x0d,
+ MBCMD_APPEND = 0x0e,
+ MBCMD_PREPEND = 0x0f,
+ MBCMD_STAT = 0x10,
+ MBCMD_SETQ = 0x11,
+ MBCMD_ADDQ = 0x12,
+ MBCMD_REPLACEQ = 0x13,
+ MBCMD_DELETEQ = 0x14,
+ MBCMD_INCREMENTQ = 0x15,
+ MBCMD_DECREMENTQ = 0x16,
+ MBCMD_QUITQ = 0x17,
+ MBCMD_FLUSHQ = 0x18,
+ MBCMD_APPENDQ = 0x19,
+ MBCMD_PREPENDQ = 0x1a
+};
+
+static grn_obj *cache_table = NULL;
+static grn_obj *cache_value = NULL;
+static grn_obj *cache_flags = NULL;
+static grn_obj *cache_expire = NULL;
+static grn_obj *cache_cas = NULL;
+
+#define CTX_GET(name) (grn_ctx_get(ctx, (name), strlen(name)))
+
+static grn_bool
+memcached_setup_flags_column(grn_ctx *ctx, const char *name)
+{
+ cache_flags = grn_obj_column(ctx, cache_table, name, strlen(name));
+ if (cache_flags) {
+ return GRN_TRUE;
+ }
+
+ cache_flags = grn_column_create(ctx, cache_table, name, strlen(name), NULL,
+ GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx, GRN_DB_UINT32));
+ if (!cache_flags) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+memcached_setup_expire_column(grn_ctx *ctx, const char *name)
+{
+ cache_expire = grn_obj_column(ctx, cache_table, name, strlen(name));
+ if (cache_expire) {
+ return GRN_TRUE;
+ }
+
+ cache_expire = grn_column_create(ctx, cache_table, name, strlen(name), NULL,
+ GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx, GRN_DB_UINT32));
+ if (!cache_expire) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+memcached_setup_cas_column(grn_ctx *ctx, const char *name)
+{
+ cache_cas = grn_obj_column(ctx, cache_table, name, strlen(name));
+ if (cache_cas) {
+ return GRN_TRUE;
+ }
+
+ cache_cas = grn_column_create(ctx, cache_table, name, strlen(name), NULL,
+ GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx, GRN_DB_UINT64));
+ if (!cache_cas) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static grn_bool
+memcached_init(grn_ctx *ctx)
+{
+ if (memcached_column_name) {
+ cache_value = CTX_GET(memcached_column_name);
+ if (!cache_value) {
+ ERR(GRN_INVALID_ARGUMENT,
+ "memcached column doesn't exist: <%s>",
+ memcached_column_name);
+ return GRN_FALSE;
+ }
+ if (!(grn_obj_is_column(ctx, cache_value) &&
+ ((cache_value->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) ==
+ GRN_OBJ_COLUMN_SCALAR))) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, cache_value);
+ ERR(GRN_INVALID_ARGUMENT,
+ "memcached column must be scalar column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return GRN_FALSE;
+ }
+ if (!(GRN_DB_SHORT_TEXT <= grn_obj_get_range(ctx, cache_value) &&
+ grn_obj_get_range(ctx, cache_value) <= GRN_DB_LONG_TEXT)) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, cache_value);
+ ERR(GRN_INVALID_ARGUMENT,
+ "memcached column must be text column: <%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return GRN_FALSE;
+ }
+
+ cache_table = grn_ctx_at(ctx, cache_value->header.domain);
+ if (cache_table->header.type == GRN_TABLE_NO_KEY) {
+ grn_obj inspected;
+ GRN_TEXT_INIT(&inspected, 0);
+ grn_inspect(ctx, &inspected, cache_table);
+ ERR(GRN_INVALID_ARGUMENT,
+ "memcached column's table must be HASH_KEY, PAT_KEY or DAT_KEY table: "
+ "<%.*s>",
+ (int)GRN_TEXT_LEN(&inspected),
+ GRN_TEXT_VALUE(&inspected));
+ GRN_OBJ_FIN(ctx, &inspected);
+ return GRN_FALSE;
+ }
+
+ {
+ char column_name[GRN_TABLE_MAX_KEY_SIZE];
+ char value_column_name[GRN_TABLE_MAX_KEY_SIZE];
+ int value_column_name_size;
+
+ value_column_name_size = grn_column_name(ctx, cache_value,
+ value_column_name,
+ GRN_TABLE_MAX_KEY_SIZE);
+ grn_snprintf(column_name,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "%.*s_memcached_flags",
+ value_column_name_size,
+ value_column_name);
+ if (!memcached_setup_flags_column(ctx, column_name)) {
+ return GRN_FALSE;
+ }
+ grn_snprintf(column_name,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "%.*s_memcached_expire",
+ value_column_name_size,
+ value_column_name);
+ if (!memcached_setup_expire_column(ctx, column_name)) {
+ return GRN_FALSE;
+ }
+ grn_snprintf(column_name,
+ GRN_TABLE_MAX_KEY_SIZE,
+ GRN_TABLE_MAX_KEY_SIZE,
+ "%.*s_memcached_cas",
+ value_column_name_size,
+ value_column_name);
+ if (!memcached_setup_cas_column(ctx, column_name)) {
+ return GRN_FALSE;
+ }
+ }
+ } else {
+ const char *table_name = "Memcache";
+ const char *value_column_name = "value";
+
+ cache_table = CTX_GET(table_name);
+ if (!cache_table) {
+ cache_table = grn_table_create(ctx, table_name, strlen(table_name), NULL,
+ GRN_OBJ_TABLE_PAT_KEY|GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx, GRN_DB_SHORT_TEXT),
+ NULL);
+ if (!cache_table) {
+ return GRN_FALSE;
+ }
+ }
+
+ cache_value = grn_obj_column(ctx, cache_table,
+ value_column_name,
+ strlen(value_column_name));
+ if (!cache_value) {
+ cache_value = grn_column_create(ctx, cache_table,
+ value_column_name,
+ strlen(value_column_name),
+ NULL,
+ GRN_OBJ_COLUMN_SCALAR|GRN_OBJ_PERSISTENT,
+ grn_ctx_at(ctx, GRN_DB_SHORT_TEXT));
+ if (!cache_value) {
+ return GRN_FALSE;
+ }
+ }
+
+ if (!memcached_setup_flags_column(ctx, "flags")) {
+ return GRN_FALSE;
+ }
+ if (!memcached_setup_expire_column(ctx, "expire")) {
+ return GRN_FALSE;
+ }
+ if (!memcached_setup_cas_column(ctx, "cas")) {
+ return GRN_FALSE;
+ }
+ }
+
+ return GRN_TRUE;
+}
+
+#define RELATIVE_TIME_THRESH 1000000000
+
+#define MBRES(ctx,re,status,key_len,extra_len,flags) do {\
+ grn_msg_set_property((ctx), (re), (status), (key_len), (extra_len));\
+ grn_msg_send((ctx), (re), (flags));\
+} while (0)
+
+#define GRN_MSG_MBRES(block) do {\
+ if (!quiet) {\
+ grn_obj *re = grn_msg_open_for_reply(ctx, (grn_obj *)msg, &edge->send_old);\
+ ((grn_msg *)re)->header.qtype = header->qtype;\
+ block\
+ }\
+} while (0)
+
+static uint64_t
+get_mbreq_cas_id()
+{
+ static uint64_t cas_id = 0;
+ /* FIXME: use GRN_ATOMIC_ADD_EX_64, but it is not implemented */
+ return ++cas_id;
+}
+
+static void
+do_mbreq(grn_ctx *ctx, grn_edge *edge)
+{
+ int quiet = 0;
+ int flags = 0;
+ grn_msg *msg = edge->msg;
+ grn_com_header *header = &msg->header;
+
+ switch (header->qtype) {
+ case MBCMD_GETQ :
+ flags = GRN_CTX_MORE;
+ /* fallthru */
+ case MBCMD_GET :
+ {
+ grn_id rid;
+ uint16_t keylen = ntohs(header->keylen);
+ char *key = GRN_BULK_HEAD((grn_obj *)msg);
+ rid = grn_table_get(ctx, cache_table, key, keylen);
+ if (!rid) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ } else {
+ grn_timeval tv;
+ uint32_t expire;
+ {
+ grn_obj expire_buf;
+ GRN_UINT32_INIT(&expire_buf, 0);
+ grn_obj_get_value(ctx, cache_expire, rid, &expire_buf);
+ expire = GRN_UINT32_VALUE(&expire_buf);
+ grn_obj_close(ctx, &expire_buf);
+ }
+ grn_timeval_now(ctx, &tv);
+ if (expire && expire < tv.tv_sec) {
+ grn_table_delete_by_id(ctx, cache_table, rid);
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ } else {
+ grn_obj cas_buf;
+ GRN_UINT64_INIT(&cas_buf, 0);
+ grn_obj_get_value(ctx, cache_cas, rid, &cas_buf);
+ GRN_MSG_MBRES({
+ grn_obj_get_value(ctx, cache_flags, rid, re);
+ grn_obj_get_value(ctx, cache_value, rid, re);
+ ((grn_msg *)re)->header.cas = GRN_UINT64_VALUE(&cas_buf);
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 4, flags);
+ });
+ grn_obj_close(ctx, &cas_buf);
+ }
+ }
+ }
+ break;
+ case MBCMD_SETQ :
+ case MBCMD_ADDQ :
+ case MBCMD_REPLACEQ :
+ quiet = 1;
+ /* fallthru */
+ case MBCMD_SET :
+ case MBCMD_ADD :
+ case MBCMD_REPLACE :
+ {
+ grn_id rid;
+ uint32_t size = ntohl(header->size);
+ uint16_t keylen = ntohs(header->keylen);
+ uint8_t extralen = header->level;
+ char *body = GRN_BULK_HEAD((grn_obj *)msg);
+ uint32_t flags = *((uint32_t *)body);
+ uint32_t expire = ntohl(*((uint32_t *)(body + 4)));
+ uint32_t valuelen = size - keylen - extralen;
+ char *key = body + 8;
+ char *value = key + keylen;
+ int added = 0;
+ int f = (header->qtype == MBCMD_REPLACE ||
+ header->qtype == MBCMD_REPLACEQ) ? 0 : GRN_TABLE_ADD;
+ GRN_ASSERT(extralen == 8);
+ if (header->qtype == MBCMD_REPLACE || header->qtype == MBCMD_REPLACEQ) {
+ rid = grn_table_get(ctx, cache_table, key, keylen);
+ } else {
+ rid = grn_table_add(ctx, cache_table, key, keylen, &added);
+ }
+ if (!rid) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, (f & GRN_TABLE_ADD) ? MBRES_ENOMEM : MBRES_NOT_STORED, 0, 0, 0);
+ });
+ } else {
+ if (added) {
+ if (header->cas) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_EINVAL, 0, 0, 0);
+ });
+ } else {
+ grn_obj text_buf, uint32_buf;
+ GRN_TEXT_INIT(&text_buf, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&text_buf, value, valuelen);
+ grn_obj_set_value(ctx, cache_value, rid, &text_buf, GRN_OBJ_SET);
+ GRN_UINT32_INIT(&uint32_buf, 0);
+ GRN_UINT32_SET(ctx, &uint32_buf, flags);
+ grn_obj_set_value(ctx, cache_flags, rid, &uint32_buf, GRN_OBJ_SET);
+ if (expire && expire < RELATIVE_TIME_THRESH) {
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ expire += tv.tv_sec;
+ }
+ GRN_UINT32_SET(ctx, &uint32_buf, expire);
+ grn_obj_set_value(ctx, cache_expire, rid, &uint32_buf, GRN_OBJ_SET);
+ grn_obj_close(ctx, &uint32_buf);
+ {
+ grn_obj cas_buf;
+ uint64_t cas_id = get_mbreq_cas_id();
+ GRN_UINT64_INIT(&cas_buf, 0);
+ GRN_UINT64_SET(ctx, &cas_buf, cas_id);
+ grn_obj_set_value(ctx, cache_cas, rid, &cas_buf, GRN_OBJ_SET);
+ grn_obj_close(ctx, &cas_buf);
+ GRN_MSG_MBRES({
+ ((grn_msg *)re)->header.cas = cas_id;
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 0, 0);
+ });
+ }
+ }
+ } else {
+ if (header->qtype != MBCMD_SET && header->qtype != MBCMD_SETQ) {
+ grn_obj uint32_buf;
+ grn_timeval tv;
+ uint32_t oexpire;
+
+ GRN_UINT32_INIT(&uint32_buf, 0);
+ grn_obj_get_value(ctx, cache_expire, rid, &uint32_buf);
+ oexpire = GRN_UINT32_VALUE(&uint32_buf);
+ grn_timeval_now(ctx, &tv);
+
+ if (oexpire && oexpire < tv.tv_sec) {
+ if (header->qtype == MBCMD_REPLACE ||
+ header->qtype == MBCMD_REPLACEQ) {
+ grn_table_delete_by_id(ctx, cache_table, rid);
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_NOT_STORED, 0, 0, 0);
+ });
+ break;
+ }
+ } else if (header->qtype == MBCMD_ADD ||
+ header->qtype == MBCMD_ADDQ) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_NOT_STORED, 0, 0, 0);
+ });
+ break;
+ }
+ }
+ {
+ if (header->cas) {
+ grn_obj cas_buf;
+ GRN_UINT64_INIT(&cas_buf, 0);
+ grn_obj_get_value(ctx, cache_cas, rid, &cas_buf);
+ if (header->cas != GRN_UINT64_VALUE(&cas_buf)) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_NOT_STORED, 0, 0, 0);
+ });
+ }
+ }
+ {
+ grn_obj text_buf, uint32_buf;
+ GRN_TEXT_INIT(&text_buf, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&text_buf, value, valuelen);
+ grn_obj_set_value(ctx, cache_value, rid, &text_buf, GRN_OBJ_SET);
+ GRN_UINT32_INIT(&uint32_buf, 0);
+ GRN_UINT32_SET(ctx, &uint32_buf, flags);
+ grn_obj_set_value(ctx, cache_flags, rid, &uint32_buf, GRN_OBJ_SET);
+ if (expire && expire < RELATIVE_TIME_THRESH) {
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ expire += tv.tv_sec;
+ }
+ GRN_UINT32_SET(ctx, &uint32_buf, expire);
+ grn_obj_set_value(ctx, cache_expire, rid, &uint32_buf, GRN_OBJ_SET);
+ {
+ grn_obj cas_buf;
+ uint64_t cas_id = get_mbreq_cas_id();
+ GRN_UINT64_INIT(&cas_buf, 0);
+ GRN_UINT64_SET(ctx, &cas_buf, cas_id);
+ grn_obj_set_value(ctx, cache_cas, rid, &cas_buf, GRN_OBJ_SET);
+ GRN_MSG_MBRES({
+ ((grn_msg *)re)->header.cas = cas_id;
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 0, 0);
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case MBCMD_DELETEQ :
+ quiet = 1;
+ /* fallthru */
+ case MBCMD_DELETE :
+ {
+ grn_id rid;
+ uint16_t keylen = ntohs(header->keylen);
+ char *key = GRN_BULK_HEAD((grn_obj *)msg);
+ rid = grn_table_get(ctx, cache_table, key, keylen);
+ if (!rid) {
+ /* GRN_LOG(ctx, GRN_LOG_NOTICE, "GET k=%d not found", keylen); */
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ } else {
+ grn_table_delete_by_id(ctx, cache_table, rid);
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 4, 0);
+ });
+ }
+ }
+ break;
+ case MBCMD_INCREMENTQ :
+ case MBCMD_DECREMENTQ :
+ quiet = 1;
+ /* fallthru */
+ case MBCMD_INCREMENT :
+ case MBCMD_DECREMENT :
+ {
+ grn_id rid;
+ int added = 0;
+ uint64_t delta, init;
+ uint16_t keylen = ntohs(header->keylen);
+ char *body = GRN_BULK_HEAD((grn_obj *)msg);
+ char *key = body + 20;
+ uint32_t expire = ntohl(*((uint32_t *)(body + 16)));
+ grn_ntoh(&delta, body, 8);
+ grn_ntoh(&init, body + 8, 8);
+ GRN_ASSERT(header->level == 20); /* extralen */
+ if (expire == 0xffffffff) {
+ rid = grn_table_get(ctx, cache_table, key, keylen);
+ } else {
+ rid = grn_table_add(ctx, cache_table, key, keylen, &added);
+ }
+ if (!rid) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ } else {
+ grn_obj uint32_buf, text_buf;
+ GRN_UINT32_INIT(&uint32_buf, 0);
+ GRN_TEXT_INIT(&text_buf, GRN_OBJ_DO_SHALLOW_COPY);
+ if (added) {
+ GRN_TEXT_SET_REF(&text_buf, &init, 8);
+ grn_obj_set_value(ctx, cache_value, rid, &text_buf, GRN_OBJ_SET);
+ GRN_UINT32_SET(ctx, &uint32_buf, 0);
+ grn_obj_set_value(ctx, cache_flags, rid, &uint32_buf, GRN_OBJ_SET);
+ } else {
+ grn_timeval tv;
+ uint32_t oexpire;
+
+ grn_obj_get_value(ctx, cache_expire, rid, &uint32_buf);
+ oexpire = GRN_UINT32_VALUE(&uint32_buf);
+ grn_timeval_now(ctx, &tv);
+
+ if (oexpire && oexpire < tv.tv_sec) {
+ if (expire == 0xffffffffU) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ break;
+ } else {
+ GRN_TEXT_SET_REF(&text_buf, &init, 8);
+ grn_obj_set_value(ctx, cache_value, rid, &text_buf, GRN_OBJ_SET);
+ GRN_UINT32_SET(ctx, &uint32_buf, 0);
+ grn_obj_set_value(ctx, cache_flags, rid, &uint32_buf, GRN_OBJ_SET);
+ }
+ } else {
+ grn_obj uint64_buf;
+ GRN_UINT64_INIT(&uint64_buf, 0);
+ GRN_UINT64_SET(ctx, &uint64_buf, delta);
+ grn_obj_set_value(ctx, cache_value, rid, &uint64_buf,
+ header->qtype == MBCMD_INCREMENT ||
+ header->qtype == MBCMD_INCREMENTQ
+ ? GRN_OBJ_INCR
+ : GRN_OBJ_DECR);
+ }
+ }
+ if (expire && expire < RELATIVE_TIME_THRESH) {
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ expire += tv.tv_sec;
+ }
+ GRN_UINT32_SET(ctx, &uint32_buf, expire);
+ grn_obj_set_value(ctx, cache_expire, rid, &uint32_buf, GRN_OBJ_SET);
+ GRN_MSG_MBRES({
+ /* TODO: get_mbreq_cas_id() */
+ grn_obj_get_value(ctx, cache_value, rid, re);
+ grn_hton(&delta, (uint64_t *)GRN_BULK_HEAD(re), 8);
+ GRN_TEXT_SET(ctx, re, &delta, sizeof(uint64_t));
+ MBRES(ctx, re, MBRES_SUCCESS, 0, sizeof(uint64_t), 0);
+ });
+ }
+ }
+ break;
+ case MBCMD_FLUSHQ :
+ quiet = 1;
+ /* fallthru */
+ case MBCMD_FLUSH :
+ {
+ uint32_t expire;
+ uint8_t extralen = header->level;
+ if (extralen) {
+ char *body = GRN_BULK_HEAD((grn_obj *)msg);
+ GRN_ASSERT(extralen == 4);
+ expire = ntohl(*((uint32_t *)(body)));
+ if (expire < RELATIVE_TIME_THRESH) {
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ if (expire) {
+ expire += tv.tv_sec;
+ } else {
+ expire = tv.tv_sec - 1;
+ }
+ }
+ } else {
+ grn_timeval tv;
+ grn_timeval_now(ctx, &tv);
+ expire = tv.tv_sec - 1;
+ }
+ {
+ grn_obj exp_buf;
+ GRN_UINT32_INIT(&exp_buf, 0);
+ GRN_UINT32_SET(ctx, &exp_buf, expire);
+ GRN_TABLE_EACH(ctx, cache_table, 0, 0, rid, NULL, NULL, NULL, {
+ grn_obj_set_value(ctx, cache_expire, rid, &exp_buf, GRN_OBJ_SET);
+ });
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 4, 0);
+ });
+ grn_obj_close(ctx, &exp_buf);
+ }
+ }
+ break;
+ case MBCMD_NOOP :
+ break;
+ case MBCMD_VERSION :
+ GRN_MSG_MBRES({
+ grn_bulk_write(ctx, re, PACKAGE_VERSION, strlen(PACKAGE_VERSION));
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 0, 0);
+ });
+ break;
+ case MBCMD_GETKQ :
+ flags = GRN_CTX_MORE;
+ /* fallthru */
+ case MBCMD_GETK :
+ {
+ grn_id rid;
+ uint16_t keylen = ntohs(header->keylen);
+ char *key = GRN_BULK_HEAD((grn_obj *)msg);
+ rid = grn_table_get(ctx, cache_table, key, keylen);
+ if (!rid) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ } else {
+ grn_obj uint32_buf;
+ grn_timeval tv;
+ uint32_t expire;
+ GRN_UINT32_INIT(&uint32_buf, 0);
+ grn_obj_get_value(ctx, cache_expire, rid, &uint32_buf);
+ expire = GRN_UINT32_VALUE(&uint32_buf);
+ grn_timeval_now(ctx, &tv);
+ if (expire && expire < tv.tv_sec) {
+ grn_table_delete_by_id(ctx, cache_table, rid);
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_KEY_ENOENT, 0, 0, 0);
+ });
+ } else {
+ grn_obj uint64_buf;
+ GRN_UINT64_INIT(&uint64_buf, 0);
+ grn_obj_get_value(ctx, cache_cas, rid, &uint64_buf);
+ GRN_MSG_MBRES({
+ grn_obj_get_value(ctx, cache_flags, rid, re);
+ grn_bulk_write(ctx, re, key, keylen);
+ grn_obj_get_value(ctx, cache_value, rid, re);
+ ((grn_msg *)re)->header.cas = GRN_UINT64_VALUE(&uint64_buf);
+ MBRES(ctx, re, MBRES_SUCCESS, keylen, 4, flags);
+ });
+ }
+ }
+ }
+ break;
+ case MBCMD_APPENDQ :
+ case MBCMD_PREPENDQ :
+ quiet = 1;
+ /* fallthru */
+ case MBCMD_APPEND :
+ case MBCMD_PREPEND :
+ {
+ grn_id rid;
+ uint32_t size = ntohl(header->size);
+ uint16_t keylen = ntohs(header->keylen);
+ char *key = GRN_BULK_HEAD((grn_obj *)msg);
+ char *value = key + keylen;
+ uint32_t valuelen = size - keylen;
+ rid = grn_table_add(ctx, cache_table, key, keylen, NULL);
+ if (!rid) {
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_ENOMEM, 0, 0, 0);
+ });
+ } else {
+ /* FIXME: check expire */
+ grn_obj buf;
+ int flags = header->qtype == MBCMD_APPEND ? GRN_OBJ_APPEND : GRN_OBJ_PREPEND;
+ GRN_TEXT_INIT(&buf, GRN_OBJ_DO_SHALLOW_COPY);
+ GRN_TEXT_SET_REF(&buf, value, valuelen);
+ grn_obj_set_value(ctx, cache_value, rid, &buf, flags);
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 0, 0);
+ });
+ }
+ }
+ break;
+ case MBCMD_STAT :
+ {
+ pid_t pid = grn_getpid();
+ GRN_MSG_MBRES({
+ grn_bulk_write(ctx, re, "pid", 3);
+ grn_text_itoa(ctx, re, pid);
+ MBRES(ctx, re, MBRES_SUCCESS, 3, 0, 0);
+ });
+ }
+ break;
+ case MBCMD_QUITQ :
+ quiet = 1;
+ /* fallthru */
+ case MBCMD_QUIT :
+ GRN_MSG_MBRES({
+ MBRES(ctx, re, MBRES_SUCCESS, 0, 0, 0);
+ });
+ /* fallthru */
+ default :
+ ctx->stat = GRN_CTX_QUIT;
+ break;
+ }
+}
+
+/* worker thread */
+
+enum {
+ EDGE_IDLE = 0x00,
+ EDGE_WAIT = 0x01,
+ EDGE_DOING = 0x02,
+ EDGE_ABORT = 0x03,
+};
+
+static void
+check_rlimit_nofile(grn_ctx *ctx)
+{
+#ifndef WIN32
+ struct rlimit limit;
+ limit.rlim_cur = 0;
+ limit.rlim_max = 0;
+ getrlimit(RLIMIT_NOFILE, &limit);
+ if (limit.rlim_cur < RLIMIT_NOFILE_MINIMUM) {
+ limit.rlim_cur = RLIMIT_NOFILE_MINIMUM;
+ limit.rlim_max = RLIMIT_NOFILE_MINIMUM;
+ setrlimit(RLIMIT_NOFILE, &limit);
+ limit.rlim_cur = 0;
+ limit.rlim_max = 0;
+ getrlimit(RLIMIT_NOFILE, &limit);
+ }
+ GRN_LOG(ctx, GRN_LOG_NOTICE,
+ "RLIMIT_NOFILE(%" GRN_FMT_LLD ",%" GRN_FMT_LLD ")",
+ (long long int)limit.rlim_cur, (long long int)limit.rlim_max);
+#endif /* WIN32 */
+}
+
+static grn_thread_func_result CALLBACK
+h_worker(void *arg)
+{
+ ht_context hc;
+ grn_ctx ctx_, *ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ grn_ctx_use(ctx, (grn_obj *)arg);
+ grn_ctx_recv_handler_set(ctx, h_output, &hc);
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ GRN_LOG(&grn_gctx, GRN_LOG_NOTICE, "thread start (%d/%d)",
+ n_floating_threads, n_running_threads);
+ while (n_running_threads <= max_n_floating_threads &&
+ grn_gctx.stat != GRN_CTX_QUIT) {
+ grn_obj *msg;
+ if (ctx->rc == GRN_CANCEL) {
+ ctx->rc = GRN_SUCCESS;
+ }
+ n_floating_threads++;
+ while (!(msg = (grn_obj *)grn_com_queue_deque(&grn_gctx, &ctx_new))) {
+ COND_WAIT(q_cond, q_mutex);
+ if (grn_gctx.stat == GRN_CTX_QUIT) {
+ n_floating_threads--;
+ goto exit;
+ }
+ if (n_running_threads > max_n_floating_threads) {
+ n_floating_threads--;
+ goto exit;
+ }
+ }
+ n_floating_threads--;
+ MUTEX_UNLOCK(q_mutex);
+ hc.msg = (grn_msg *)msg;
+ hc.in_body = GRN_FALSE;
+ hc.is_chunked = GRN_FALSE;
+ do_htreq(ctx, &hc);
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ }
+exit :
+ n_running_threads--;
+ GRN_LOG(&grn_gctx, GRN_LOG_NOTICE, "thread end (%d/%d)",
+ n_floating_threads, n_running_threads);
+ if (grn_gctx.stat == GRN_CTX_QUIT) {
+ break_accept_event_loop(ctx);
+ }
+ grn_ctx_fin(ctx);
+ MUTEX_UNLOCK(q_mutex);
+ return GRN_THREAD_FUNC_RETURN_VALUE;
+}
+
+static void
+h_handler(grn_ctx *ctx, grn_obj *msg)
+{
+ grn_com *com = ((grn_msg *)msg)->u.peer;
+ if (ctx->rc) {
+ grn_com_close(ctx, com);
+ grn_msg_close(ctx, msg);
+ } else {
+ grn_sock fd = com->fd;
+ void *arg = com->ev->opaque;
+ /* if not keep alive connection */
+ grn_com_event_del(ctx, com->ev, fd);
+ ((grn_msg *)msg)->u.fd = fd;
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ grn_com_queue_enque(ctx, &ctx_new, (grn_com_queue_entry *)msg);
+ if (n_floating_threads == 0 && n_running_threads < max_n_floating_threads) {
+ grn_thread thread;
+ n_running_threads++;
+ if (THREAD_CREATE(thread, h_worker, arg)) {
+ n_running_threads--;
+ SERR("pthread_create");
+ }
+ }
+ COND_SIGNAL(q_cond);
+ MUTEX_UNLOCK(q_mutex);
+ }
+}
+
+static int
+h_server(char *path)
+{
+ int exit_code = EXIT_FAILURE;
+ grn_ctx ctx_, *ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ GRN_COM_QUEUE_INIT(&ctx_new);
+ GRN_COM_QUEUE_INIT(&ctx_old);
+ check_rlimit_nofile(ctx);
+ GRN_TEXT_INIT(&http_response_server_line, 0);
+ grn_text_printf(ctx,
+ &http_response_server_line,
+ "Server: %s/%s\r\n",
+ grn_get_package_label(),
+ grn_get_version());
+ exit_code = start_service(ctx, path, NULL, h_handler);
+ GRN_OBJ_FIN(ctx, &http_response_server_line);
+ grn_ctx_fin(ctx);
+ return exit_code;
+}
+
+static grn_thread_func_result CALLBACK
+g_worker(void *arg)
+{
+ MUTEX_LOCK_ENSURE(NULL, q_mutex);
+ GRN_LOG(&grn_gctx, GRN_LOG_NOTICE, "thread start (%d/%d)",
+ n_floating_threads, n_running_threads);
+ while (n_running_threads <= max_n_floating_threads &&
+ grn_gctx.stat != GRN_CTX_QUIT) {
+ grn_ctx *ctx;
+ grn_edge *edge;
+ n_floating_threads++;
+ while (!(edge = (grn_edge *)grn_com_queue_deque(&grn_gctx, &ctx_new))) {
+ COND_WAIT(q_cond, q_mutex);
+ if (grn_gctx.stat == GRN_CTX_QUIT) {
+ n_floating_threads--;
+ goto exit;
+ }
+ if (n_running_threads > max_n_floating_threads) {
+ n_floating_threads--;
+ goto exit;
+ }
+ }
+ ctx = &edge->ctx;
+ n_floating_threads--;
+ if (edge->stat == EDGE_DOING) { continue; }
+ if (edge->stat == EDGE_WAIT) {
+ edge->stat = EDGE_DOING;
+ while (!GRN_COM_QUEUE_EMPTYP(&edge->recv_new)) {
+ grn_obj *msg;
+ MUTEX_UNLOCK(q_mutex);
+ /* if (edge->flags == GRN_EDGE_WORKER) */
+ while (ctx->stat != GRN_CTX_QUIT &&
+ (edge->msg = (grn_msg *)grn_com_queue_deque(ctx, &edge->recv_new))) {
+ grn_com_header *header = &edge->msg->header;
+ msg = (grn_obj *)edge->msg;
+ switch (header->proto) {
+ case GRN_COM_PROTO_MBREQ :
+ do_mbreq(ctx, edge);
+ break;
+ case GRN_COM_PROTO_GQTP :
+ grn_ctx_send(ctx, GRN_BULK_HEAD(msg), GRN_BULK_VSIZE(msg), header->flags);
+ ERRCLR(ctx);
+ if (ctx->rc == GRN_CANCEL) {
+ ctx->rc = GRN_SUCCESS;
+ }
+ break;
+ default :
+ ctx->stat = GRN_CTX_QUIT;
+ break;
+ }
+ grn_msg_close(ctx, msg);
+ }
+ while ((msg = (grn_obj *)grn_com_queue_deque(ctx, &edge->send_old))) {
+ grn_msg_close(ctx, msg);
+ }
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ if (ctx->stat == GRN_CTX_QUIT || edge->stat == EDGE_ABORT) { break; }
+ }
+ }
+ if (ctx->stat == GRN_CTX_QUIT || edge->stat == EDGE_ABORT) {
+ grn_com_queue_enque(&grn_gctx, &ctx_old, (grn_com_queue_entry *)edge);
+ edge->stat = EDGE_ABORT;
+ } else {
+ edge->stat = EDGE_IDLE;
+ }
+ };
+exit :
+ n_running_threads--;
+ GRN_LOG(&grn_gctx, GRN_LOG_NOTICE, "thread end (%d/%d)",
+ n_floating_threads, n_running_threads);
+ MUTEX_UNLOCK(q_mutex);
+ return GRN_THREAD_FUNC_RETURN_VALUE;
+}
+
+static void
+g_dispatcher(grn_ctx *ctx, grn_edge *edge)
+{
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ if (edge->stat == EDGE_IDLE) {
+ grn_com_queue_enque(ctx, &ctx_new, (grn_com_queue_entry *)edge);
+ edge->stat = EDGE_WAIT;
+ if (n_floating_threads == 0 && n_running_threads < max_n_floating_threads) {
+ grn_thread thread;
+ n_running_threads++;
+ if (THREAD_CREATE(thread, g_worker, NULL)) {
+ n_running_threads--;
+ SERR("pthread_create");
+ }
+ }
+ COND_SIGNAL(q_cond);
+ }
+ MUTEX_UNLOCK(q_mutex);
+}
+
+static void
+g_output(grn_ctx *ctx, int flags, void *arg)
+{
+ grn_edge *edge = arg;
+ grn_com *com = edge->com;
+ grn_msg *req = edge->msg, *msg = (grn_msg *)ctx->impl->output.buf;
+ msg->edge_id = req->edge_id;
+ msg->header.proto = req->header.proto == GRN_COM_PROTO_MBREQ
+ ? GRN_COM_PROTO_MBRES : req->header.proto;
+ if (ctx->rc != GRN_SUCCESS && GRN_BULK_VSIZE(ctx->impl->output.buf) == 0) {
+ GRN_TEXT_PUTS(ctx, ctx->impl->output.buf, ctx->errbuf);
+ }
+ if (grn_msg_send(ctx, (grn_obj *)msg,
+ (flags & GRN_CTX_MORE) ? GRN_CTX_MORE : GRN_CTX_TAIL)) {
+ edge->stat = EDGE_ABORT;
+ }
+ ctx->impl->output.buf = grn_msg_open(ctx, com, &edge->send_old);
+}
+
+static void
+g_handler(grn_ctx *ctx, grn_obj *msg)
+{
+ grn_edge *edge;
+ grn_com *com = ((grn_msg *)msg)->u.peer;
+ if (ctx->rc) {
+ if (com->has_sid) {
+ if ((edge = com->opaque)) {
+ MUTEX_LOCK_ENSURE(ctx, q_mutex);
+ if (edge->stat == EDGE_IDLE) {
+ grn_com_queue_enque(ctx, &ctx_old, (grn_com_queue_entry *)edge);
+ }
+ edge->stat = EDGE_ABORT;
+ MUTEX_UNLOCK(q_mutex);
+ } else {
+ grn_com_close(ctx, com);
+ }
+ }
+ grn_msg_close(ctx, msg);
+ } else {
+ int added;
+ edge = grn_edges_add(ctx, &((grn_msg *)msg)->edge_id, &added);
+ if (added) {
+ grn_ctx_init(&edge->ctx, 0);
+ GRN_COM_QUEUE_INIT(&edge->recv_new);
+ GRN_COM_QUEUE_INIT(&edge->send_old);
+ grn_ctx_use(&edge->ctx, (grn_obj *)com->ev->opaque);
+ grn_ctx_recv_handler_set(&edge->ctx, g_output, edge);
+ com->opaque = edge;
+ grn_obj_close(&edge->ctx, edge->ctx.impl->output.buf);
+ edge->ctx.impl->output.buf =
+ grn_msg_open(&edge->ctx, com, &edge->send_old);
+ edge->com = com;
+ edge->stat = EDGE_IDLE;
+ edge->flags = GRN_EDGE_WORKER;
+ }
+ if (edge->ctx.stat == GRN_CTX_QUIT || edge->stat == EDGE_ABORT) {
+ grn_msg_close(ctx, msg);
+ } else {
+ grn_com_queue_enque(ctx, &edge->recv_new, (grn_com_queue_entry *)msg);
+ g_dispatcher(ctx, edge);
+ }
+ }
+}
+
+static int
+g_server(char *path)
+{
+ int exit_code = EXIT_FAILURE;
+ grn_ctx ctx_, *ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ GRN_COM_QUEUE_INIT(&ctx_new);
+ GRN_COM_QUEUE_INIT(&ctx_old);
+ check_rlimit_nofile(ctx);
+ exit_code = start_service(ctx, path, g_dispatcher, g_handler);
+ grn_ctx_fin(ctx);
+ return exit_code;
+}
+
+enum {
+ ACTION_USAGE = 1,
+ ACTION_VERSION,
+ ACTION_SHOW_CONFIG,
+ ACTION_ERROR
+};
+
+#define ACTION_MASK (0x0f)
+#define MODE_MASK (0xf0)
+#define FLAG_MODE_ALONE (1 << 4)
+#define FLAG_MODE_CLIENT (1 << 5)
+#define FLAG_MODE_DAEMON (1 << 6)
+#define FLAG_MODE_SERVER (1 << 7)
+#define FLAG_NEW_DB (1 << 8)
+#define FLAG_USE_WINDOWS_EVENT_LOG (1 << 9)
+
+static uint32_t
+get_core_number(void)
+{
+#ifdef WIN32
+ SYSTEM_INFO sinfo;
+ GetSystemInfo(&sinfo);
+ return sinfo.dwNumberOfProcessors;
+#else /* WIN32 */
+# ifdef _SC_NPROCESSORS_CONF
+ return sysconf(_SC_NPROCESSORS_CONF);
+# else
+ int n_processors;
+ size_t length = sizeof(n_processors);
+ int mib[] = {CTL_HW, HW_NCPU};
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
+ &n_processors, &length, NULL, 0) == 0 &&
+ length == sizeof(n_processors) &&
+ 0 < n_processors) {
+ return n_processors;
+ } else {
+ return 1;
+ }
+# endif /* _SC_NPROCESSORS_CONF */
+#endif /* WIN32 */
+}
+
+/*
+ * The length of each line, including an end-of-line, in config file should be
+ * shorter than (CONFIG_FILE_BUF_SIZE - 1) bytes. Too long lines are ignored.
+ * Note that both '\r' and '\n' are handled as end-of-lines.
+ *
+ * '#' and ';' are special symbols to start comments. A comment ends with an
+ * end-of-line.
+ *
+ * Format: name[=value]
+ * - Preceding/trailing white-spaces of each line are removed.
+ * - White-spaces aroung '=' are removed.
+ * - name does not allow white-spaces.
+ */
+#define CONFIG_FILE_BUF_SIZE 4096
+#define CONFIG_FILE_MAX_NAME_LENGTH 128
+#define CONFIG_FILE_MAX_VALUE_LENGTH 2048
+
+typedef enum {
+ CONFIG_FILE_SUCCESS,
+ CONFIG_FILE_FORMAT_ERROR,
+ CONFIG_FILE_FOPEN_ERROR,
+ CONFIG_FILE_MALLOC_ERROR,
+ CONFIG_FILE_ATEXIT_ERROR
+} config_file_status;
+
+/*
+ * The node type of a linked list for storing values. Note that a value is
+ * stored in the extra space of an object.
+ */
+typedef struct _config_file_entry {
+ struct _config_file_entry *next;
+} config_file_entry;
+
+static config_file_entry *config_file_entry_head = NULL;
+
+static void
+config_file_clear(void) {
+ while (config_file_entry_head) {
+ config_file_entry *next = config_file_entry_head->next;
+ free(config_file_entry_head);
+ config_file_entry_head = next;
+ }
+}
+
+static config_file_status
+config_file_register(const char *path, const grn_str_getopt_opt *opts,
+ int *flags, const char *name, size_t name_length,
+ const char *value, size_t value_length)
+{
+ char name_buf[CONFIG_FILE_MAX_NAME_LENGTH + 3];
+ config_file_entry *entry = NULL;
+ char *args[4];
+
+ name_buf[0] = name_buf[1] = '-';
+ grn_strcpy(name_buf + 2, CONFIG_FILE_MAX_NAME_LENGTH + 1, name);
+
+ if (value) {
+ const size_t entry_size = sizeof(config_file_entry) + value_length + 1;
+ entry = (config_file_entry *)malloc(entry_size);
+ if (!entry) {
+ fprintf(stderr, "memory allocation failed: %u bytes\n",
+ (unsigned int)entry_size);
+ return CONFIG_FILE_MALLOC_ERROR;
+ }
+ grn_strcpy((char *)(entry + 1), value_length + 1, value);
+ entry->next = config_file_entry_head;
+ if (!config_file_entry_head) {
+ if (atexit(config_file_clear)) {
+ free(entry);
+ return CONFIG_FILE_ATEXIT_ERROR;
+ }
+ }
+ config_file_entry_head = entry;
+ }
+
+ args[0] = (char *)path;
+ args[1] = name_buf;
+ args[2] = entry ? (char *)(entry + 1) : NULL;
+ args[3] = NULL;
+ grn_str_getopt(entry ? 3 : 2, args, opts, flags);
+ return CONFIG_FILE_SUCCESS;
+}
+
+static config_file_status
+config_file_parse(const char *path, const grn_str_getopt_opt *opts,
+ int *flags, char *buf) {
+ char *ptr, *name, *value;
+ size_t name_length, value_length;
+
+ while (isspace((unsigned char)*buf)) {
+ buf++;
+ }
+
+ ptr = buf;
+ while (*ptr && *ptr != '#' && *ptr != ';') {
+ ptr++;
+ }
+
+ do {
+ *ptr-- = '\0';
+ } while (ptr >= buf && isspace((unsigned char)*ptr));
+
+ if (!*buf) {
+ return CONFIG_FILE_SUCCESS;
+ }
+
+ name = ptr = buf;
+ while (*ptr && !isspace((unsigned char)*ptr) && *ptr != '=') {
+ ptr++;
+ }
+ while (isspace((unsigned char)*ptr)) {
+ *ptr++ = '\0';
+ }
+
+ name_length = strlen(name);
+ if (name_length == 0) {
+ return CONFIG_FILE_SUCCESS;
+ } else if (name_length > CONFIG_FILE_MAX_NAME_LENGTH) {
+ fprintf(stderr, "too long name in config file: %u bytes\n",
+ (unsigned int)name_length);
+ return CONFIG_FILE_FORMAT_ERROR;
+ }
+
+ if (*ptr == '=') {
+ *ptr++ = '\0';
+ while (isspace((unsigned char)*ptr)) {
+ ptr++;
+ }
+ value = ptr;
+ } else if (*ptr) {
+ fprintf(stderr, "invalid name in config file\n");
+ return CONFIG_FILE_FORMAT_ERROR;
+ } else {
+ value = NULL;
+ }
+
+ value_length = value ? strlen(value) : 0;
+ if (value_length > CONFIG_FILE_MAX_VALUE_LENGTH) {
+ fprintf(stderr, "too long value in config file: %u bytes\n",
+ (unsigned int)value_length);
+ return CONFIG_FILE_FORMAT_ERROR;
+ }
+
+ return config_file_register(path, opts, flags,
+ name, name_length, value, value_length);
+}
+
+static config_file_status
+config_file_load(const char *path, const grn_str_getopt_opt *opts, int *flags)
+{
+ config_file_status status = CONFIG_FILE_SUCCESS;
+ char buf[CONFIG_FILE_BUF_SIZE];
+ size_t length = 0;
+ FILE * const file = fopen(path, "rb");
+ if (!file) {
+ return CONFIG_FILE_FOPEN_ERROR;
+ }
+
+ for ( ; ; ) {
+ int c = fgetc(file);
+ if (c == '\r' || c == '\n' || c == EOF) {
+ if (length < sizeof(buf) - 1) {
+ buf[length] = '\0';
+ status = config_file_parse(path, opts, flags, buf);
+ if (status != CONFIG_FILE_SUCCESS) {
+ break;
+ }
+ }
+ length = 0;
+ } else if (c == '\0') {
+ fprintf(stderr, "prohibited '\\0' in config file: %s\n", path);
+ status = CONFIG_FILE_FORMAT_ERROR;
+ break;
+ } else {
+ if (length < sizeof(buf) - 1) {
+ buf[length] = (char)c;
+ }
+ length++;
+ }
+
+ if (c == EOF) {
+ break;
+ }
+ }
+
+ fclose(file);
+ return status;
+}
+
+static const int default_http_port = DEFAULT_HTTP_PORT;
+static const int default_gqtp_port = DEFAULT_GQTP_PORT;
+static grn_encoding default_encoding = GRN_ENC_DEFAULT;
+static uint32_t default_max_n_threads = DEFAULT_MAX_N_FLOATING_THREADS;
+static const grn_log_level default_log_level = GRN_LOG_DEFAULT_LEVEL;
+static const char * const default_protocol = "gqtp";
+static const char *default_hostname = "localhost";
+static const char * const default_dest = "localhost";
+static const char *default_log_path = "";
+static const char *default_query_log_path = "";
+static const char *default_config_path = "";
+static const char *default_document_root = "";
+static grn_command_version default_default_command_version =
+ GRN_COMMAND_VERSION_DEFAULT;
+static int64_t default_default_match_escalation_threshold = 0;
+static const char * const default_bind_address = "0.0.0.0";
+static double default_default_request_timeout = 0.0;
+
+static void
+init_default_hostname(void)
+{
+ static char hostname[HOST_NAME_MAX + 1];
+ struct addrinfo hints, *result;
+
+ hostname[HOST_NAME_MAX] = '\0';
+ if (gethostname(hostname, HOST_NAME_MAX) == -1)
+ return;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_addr = NULL;
+ hints.ai_canonname = NULL;
+ hints.ai_next = NULL;
+ if (getaddrinfo(hostname, NULL, &hints, &result) != 0)
+ return;
+ freeaddrinfo(result);
+
+ default_hostname = hostname;
+}
+
+static void
+init_default_settings(void)
+{
+ output = stdout;
+
+ default_encoding = grn_encoding_parse(GRN_DEFAULT_ENCODING);
+
+ {
+ const uint32_t n_cores = get_core_number();
+ if (n_cores != 0) {
+ default_max_n_threads = n_cores;
+ }
+ }
+
+ init_default_hostname();
+
+ default_log_path = grn_default_logger_get_path();
+ default_query_log_path = grn_default_query_logger_get_path();
+
+ default_config_path = getenv("GRN_CONFIG_PATH");
+ if (!default_config_path) {
+ default_config_path = GRN_CONFIG_PATH;
+ if (!default_config_path) {
+ default_config_path = "";
+ }
+ }
+
+#ifdef WIN32
+ {
+ static char windows_default_document_root[PATH_MAX];
+ size_t document_root_length = strlen(grn_windows_base_dir()) + 1 +
+ strlen(GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT) + 1;
+ if (document_root_length >= PATH_MAX) {
+ fprintf(stderr, "can't use default root: too long path\n");
+ } else {
+ grn_strcpy(windows_default_document_root, PATH_MAX,
+ grn_windows_base_dir());
+ grn_strcat(windows_default_document_root, PATH_MAX,
+ "/");
+ grn_strcat(windows_default_document_root, PATH_MAX,
+ GRN_DEFAULT_RELATIVE_DOCUMENT_ROOT);
+ default_document_root = windows_default_document_root;
+ }
+ }
+#else
+ default_document_root = GRN_DEFAULT_DOCUMENT_ROOT;
+#endif
+
+ default_default_command_version = grn_get_default_command_version();
+ default_default_match_escalation_threshold =
+ grn_get_default_match_escalation_threshold();
+ default_default_request_timeout = grn_get_default_request_timeout();
+}
+
+static void
+show_config(FILE *out, const grn_str_getopt_opt *opts, int flags)
+{
+ const grn_str_getopt_opt *o;
+
+ for (o = opts; o->opt || o->longopt; o++) {
+ switch (o->op) {
+ case GETOPT_OP_NONE:
+ if (o->arg && *o->arg) {
+ if (o->longopt && strcmp(o->longopt, "config-path")) {
+ fprintf(out, "%s=%s\n", o->longopt, *o->arg);
+ }
+ }
+ break;
+ case GETOPT_OP_ON:
+ if (flags & o->flag) {
+ goto no_arg;
+ }
+ break;
+ case GETOPT_OP_OFF:
+ if (!(flags & o->flag)) {
+ goto no_arg;
+ }
+ break;
+ case GETOPT_OP_UPDATE:
+ if (flags == o->flag) {
+ no_arg:
+ if (o->longopt) {
+ fprintf(out, "%s\n", o->longopt);
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void
+show_version(void)
+{
+ printf("%s %s [",
+ grn_get_package_label(),
+ grn_get_version());
+
+ /* FIXME: Should we detect host information dynamically on Windows? */
+#ifdef HOST_OS
+ printf("%s,", HOST_OS);
+#endif
+#ifdef HOST_CPU
+ printf("%s,", HOST_CPU);
+#endif
+ printf("%s", GRN_DEFAULT_ENCODING);
+
+ printf(",match-escalation-threshold=%" GRN_FMT_LLD,
+ grn_get_default_match_escalation_threshold());
+
+#ifndef NO_NFKC
+ printf(",nfkc");
+#endif
+#ifdef GRN_WITH_MECAB
+ printf(",mecab");
+#endif
+#ifdef GRN_WITH_MESSAGE_PACK
+ printf(",msgpack");
+#endif
+#ifdef GRN_WITH_MRUBY
+ printf(",mruby");
+#endif
+#ifdef GRN_WITH_ONIGMO
+ printf(",onigmo");
+#endif
+#ifdef GRN_WITH_ZLIB
+ printf(",zlib");
+#endif
+#ifdef GRN_WITH_LZ4
+ printf(",lz4");
+#endif
+#ifdef GRN_WITH_ZSTD
+ printf(",zstd");
+#endif
+#ifdef USE_KQUEUE
+ printf(",kqueue");
+#endif
+#ifdef USE_EPOLL
+ printf(",epoll");
+#endif
+#ifdef USE_POLL
+ printf(",poll");
+#endif
+ printf("]\n");
+
+#ifdef CONFIGURE_OPTIONS
+ printf("\n");
+ printf("configure options: <%s>\n", CONFIGURE_OPTIONS);
+#endif
+}
+
+static void
+show_usage(FILE *output)
+{
+ uint32_t default_cache_limit = GRN_CACHE_DEFAULT_MAX_N_ENTRIES;
+
+ fprintf(output,
+ "Usage: groonga [options...] [dest]\n"
+ "\n"
+ "Mode options: (default: standalone)\n"
+ " By default, groonga runs in standalone mode.\n"
+ " -c: run in client mode\n"
+ " -s: run in server mode\n"
+ " -d: run in daemon mode\n"
+ "\n"
+ "Database creation options:\n"
+ " -n: create new database (except client mode)\n"
+ " -e, --encoding <encoding>:\n"
+ " specify encoding for new database\n"
+ " [none|euc|utf8|sjis|latin1|koi8r] (default: %s)\n"
+ "\n"
+ "Standalone/client options:\n"
+ " --file <path>: read commands from specified file\n"
+ " --input-fd <FD>: read commands from specified file descriptor\n"
+ " --file has a prioriry over --input-fd\n"
+ " --output-fd <FD>: output response to specified file descriptor\n"
+ " -p, --port <port number>: specify server port number (client mode only)\n"
+ " (default: %d)\n"
+ "\n"
+ "Server/daemon options:\n"
+ " --bind-address <ip/hostname>:\n"
+ " specify server address to bind\n"
+ " (default: %s)\n"
+ " -p, --port <port number>: specify server port number\n"
+ " (HTTP default: %d, GQTP default: %d)\n"
+ " -i, --server-id <ip/hostname>:\n"
+ " specify server ID address (default: %s)\n"
+ " --protocol <protocol>: specify server protocol to listen\n"
+ " [gqtp|http|memcached] (default: %s)\n"
+ " --document-root <path>: specify document root path (http only)\n"
+ " (default: %s)\n"
+ " --cache-limit <limit>: specify max number of cache data (default: %u)\n"
+ " -t, --max-threads <max threads>:\n"
+ " specify max number of threads (default: %u)\n"
+ " --pid-path <path>: specify file to write process ID to\n"
+ " (daemon mode only)\n"
+ " --default-request-timeout <timeout>:\n"
+ " specify the default request timeout in seconds\n"
+ " (default: %f)\n"
+ " --cache-base-path <path>: specify the cache base path\n"
+ " You can make cache persistent by this option\n"
+ " You must specify path on memory file system\n"
+ " (default: none; disabled)\n"
+ "\n"
+ "Memcached options:\n"
+ " --memcached-column <column>:\n"
+ " specify column to access by memcached protocol\n"
+ " The column must be text type column and\n"
+ " its table must be not NO_KEY table\n"
+ "\n"
+ "Logging options:\n"
+ " -l, --log-level <log level>:\n"
+ " specify log level\n"
+ " [none|emergency|alert|critical|\n"
+ " error|warning|notice|info|debug|dump]\n"
+ " (default: %s)\n"
+ " --log-path <path>: specify log path\n"
+ " (default: %s)\n"
+ " --log-rotate-threshold-size <threshold>:\n"
+ " specify threshold for log rotate\n"
+ " Log file is rotated when\n"
+ " log file size is larger than or\n"
+ " equals to the threshold\n"
+ " (default: 0; disabled)\n"
+#ifdef WIN32
+ " --use-windows-event-log:\n"
+ " report logs as Windows events\n"
+#endif /* WIN32 */
+ " --query-log-path <path>:\n"
+ " specify query log path\n"
+ " (default: %s)\n"
+ " --query-log-rotate-threshold-size <threshold>:\n"
+ " specify threshold for query log rotate\n"
+ " Query log file is rotated when\n"
+ " query log file size is larger than or\n"
+ " equals to the threshold\n"
+ " (default: 0; disabled)\n"
+ "\n"
+ "Common options:\n"
+ " --working-directory <path>:\n"
+ " specify working directory path\n"
+ " (none)\n"
+ " --config-path <path>:\n"
+ " specify config file path\n"
+ " (default: %s)\n"
+ " --default-command-version <version>:\n"
+ " specify default command version (default: %d)\n"
+ " --default-match-escalation-threshold <threshold>:\n"
+ " specify default match escalation threshold"
+ " (default: %" GRN_FMT_LLD ")\n"
+ "\n"
+ " --show-config: show config\n"
+ " -h, --help: show usage\n"
+ " --version: show groonga version\n"
+ "\n"
+ "dest:\n"
+ " <db pathname> [<commands>]: in standalone mode\n"
+ " <db pathname>: in server/daemon mode\n"
+ " <dest hostname> [<commands>]: in client mode (default: %s)\n",
+ grn_encoding_to_string(default_encoding),
+ default_gqtp_port, default_bind_address,
+ default_http_port, default_gqtp_port, default_hostname, default_protocol,
+ default_document_root, default_cache_limit, default_max_n_threads,
+ default_default_request_timeout,
+ grn_log_level_to_string(default_log_level),
+ default_log_path, default_query_log_path,
+ default_config_path, default_default_command_version,
+ (long long int)default_default_match_escalation_threshold,
+ default_dest);
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *port_arg = NULL;
+ const char *encoding_arg = NULL;
+ const char *max_n_threads_arg = NULL;
+ const char *log_level_arg = NULL;
+ const char *bind_address_arg = NULL;
+ const char *hostname_arg = NULL;
+ const char *protocol_arg = NULL;
+ const char *log_path_arg = GRN_LOG_PATH;
+ const char *log_rotate_threshold_size_arg = NULL;
+ const char *query_log_path_arg = NULL;
+ const char *query_log_rotate_threshold_size_arg = NULL;
+ const char *cache_limit_arg = NULL;
+ const char *document_root_arg = NULL;
+ const char *default_command_version_arg = NULL;
+ const char *default_match_escalation_threshold_arg = NULL;
+ const char *input_fd_arg = NULL;
+ const char *output_fd_arg = NULL;
+ const char *working_directory_arg = NULL;
+ const char *config_path = NULL;
+ const char *default_request_timeout_arg = NULL;
+ const char *cache_base_path = NULL;
+ int exit_code = EXIT_SUCCESS;
+ int i;
+ int flags = 0;
+ uint32_t cache_limit = 0;
+ grn_command_version default_command_version;
+ int64_t default_match_escalation_threshold = 0;
+ double default_request_timeout = 0.0;
+ grn_bool need_line_editor = GRN_FALSE;
+ static grn_str_getopt_opt opts[] = {
+ {'p', "port", NULL, 0, GETOPT_OP_NONE},
+ {'e', "encoding", NULL, 0, GETOPT_OP_NONE},
+ {'t', "max-threads", NULL, 0, GETOPT_OP_NONE},
+ {'h', "help", NULL, ACTION_USAGE, GETOPT_OP_UPDATE},
+ {'c', NULL, NULL, FLAG_MODE_CLIENT, GETOPT_OP_ON},
+ {'d', NULL, NULL, FLAG_MODE_DAEMON, GETOPT_OP_ON},
+ {'s', NULL, NULL, FLAG_MODE_SERVER, GETOPT_OP_ON},
+ {'l', "log-level", NULL, 0, GETOPT_OP_NONE},
+ {'i', "server-id", NULL, 0, GETOPT_OP_NONE},
+ {'n', NULL, NULL, FLAG_NEW_DB, GETOPT_OP_ON},
+ {'\0', "protocol", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "version", NULL, ACTION_VERSION, GETOPT_OP_UPDATE},
+ {'\0', "log-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "log-rotate-threshold-size", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "query-log-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "query-log-rotate-threshold-size", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "pid-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "config-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "show-config", NULL, ACTION_SHOW_CONFIG, GETOPT_OP_UPDATE},
+ {'\0', "cache-limit", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "file", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "document-root", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "default-command-version", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "default-match-escalation-threshold", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "bind-address", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "input-fd", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "output-fd", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "working-directory", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "use-windows-event-log", NULL,
+ FLAG_USE_WINDOWS_EVENT_LOG, GETOPT_OP_ON},
+ {'\0', "memcached-column", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "default-request-timeout", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "cache-base-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', NULL, NULL, 0, 0}
+ };
+ opts[0].arg = &port_arg;
+ opts[1].arg = &encoding_arg;
+ opts[2].arg = &max_n_threads_arg;
+ opts[7].arg = &log_level_arg;
+ opts[8].arg = &hostname_arg;
+ opts[10].arg = &protocol_arg;
+ opts[12].arg = &log_path_arg;
+ opts[13].arg = &log_rotate_threshold_size_arg;
+ opts[14].arg = &query_log_path_arg;
+ opts[15].arg = &query_log_rotate_threshold_size_arg;
+ opts[16].arg = &pid_file_path;
+ opts[17].arg = &config_path;
+ opts[19].arg = &cache_limit_arg;
+ opts[20].arg = &input_path;
+ opts[21].arg = &document_root_arg;
+ opts[22].arg = &default_command_version_arg;
+ opts[23].arg = &default_match_escalation_threshold_arg;
+ opts[24].arg = &bind_address_arg;
+ opts[25].arg = &input_fd_arg;
+ opts[26].arg = &output_fd_arg;
+ opts[27].arg = &working_directory_arg;
+ opts[29].arg = &memcached_column_name;
+ opts[30].arg = &default_request_timeout_arg;
+ opts[31].arg = &cache_base_path;
+
+ reset_ready_notify_pipe();
+
+ init_default_settings();
+
+ /* only for parsing --config-path. */
+ i = grn_str_getopt(argc, argv, opts, &flags);
+ if (i < 0) {
+ show_usage(stderr);
+ return EXIT_FAILURE;
+ }
+
+ if (config_path) {
+ const config_file_status status = config_file_load(config_path, opts, &flags);
+ if (status == CONFIG_FILE_FOPEN_ERROR) {
+ fprintf(stderr, "%s: can't open config file: %s (%s)\n",
+ argv[0], config_path, strerror(errno));
+ return EXIT_FAILURE;
+ } else if (status != CONFIG_FILE_SUCCESS) {
+ fprintf(stderr, "%s: failed to parse config file: %s (%s)\n",
+ argv[0], config_path,
+ (status == CONFIG_FILE_FORMAT_ERROR) ? "Invalid format" : strerror(errno));
+ return EXIT_FAILURE;
+ }
+ } else if (*default_config_path) {
+ const config_file_status status =
+ config_file_load(default_config_path, opts, &flags);
+ if (status != CONFIG_FILE_SUCCESS && status != CONFIG_FILE_FOPEN_ERROR) {
+ fprintf(stderr, "%s: failed to parse config file: %s (%s)\n",
+ argv[0], default_config_path,
+ (status == CONFIG_FILE_FORMAT_ERROR) ? "Invalid format" : strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (working_directory_arg) {
+ if (chdir(working_directory_arg) == -1) {
+ fprintf(stderr, "%s: failed to change directory: %s: %s\n",
+ argv[0], working_directory_arg, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (cache_base_path) {
+ grn_set_default_cache_base_path(cache_base_path);
+ }
+
+ /* ignore mode option in config file */
+ flags = (flags == ACTION_ERROR) ? 0 : (flags & ~ACTION_MASK);
+
+ i = grn_str_getopt(argc, argv, opts, &flags);
+ if (i < 0) { flags = ACTION_ERROR; }
+ switch (flags & ACTION_MASK) {
+ case ACTION_VERSION :
+ show_version();
+ return EXIT_SUCCESS;
+ case ACTION_USAGE :
+ show_usage(output);
+ return EXIT_SUCCESS;
+ case ACTION_SHOW_CONFIG :
+ show_config(output, opts, flags & ~ACTION_MASK);
+ return EXIT_SUCCESS;
+ case ACTION_ERROR :
+ show_usage(stderr);
+ return EXIT_FAILURE;
+ }
+
+ if ((flags & MODE_MASK) == 0) {
+ flags |= FLAG_MODE_ALONE;
+ }
+
+ if (port_arg) {
+ const char * const end = port_arg + strlen(port_arg);
+ const char *rest = NULL;
+ const int value = grn_atoi(port_arg, end, &rest);
+ if (rest != end || value <= 0 || value > 65535) {
+ fprintf(stderr, "invalid port number: <%s>\n", port_arg);
+ return EXIT_FAILURE;
+ }
+ port = value;
+ } else {
+ if (protocol_arg) {
+ if (*protocol_arg == 'h' || *protocol_arg == 'H') {
+ port = default_http_port;
+ }
+ }
+ }
+
+ if (encoding_arg) {
+ switch (*encoding_arg) {
+ case 'n' :
+ case 'N' :
+ encoding = GRN_ENC_NONE;
+ break;
+ case 'e' :
+ case 'E' :
+ encoding = GRN_ENC_EUC_JP;
+ break;
+ case 'u' :
+ case 'U' :
+ encoding = GRN_ENC_UTF8;
+ break;
+ case 's' :
+ case 'S' :
+ encoding = GRN_ENC_SJIS;
+ break;
+ case 'l' :
+ case 'L' :
+ encoding = GRN_ENC_LATIN1;
+ break;
+ case 'k' :
+ case 'K' :
+ encoding = GRN_ENC_KOI8R;
+ break;
+ default:
+ encoding = GRN_ENC_DEFAULT;
+ break;
+ }
+ } else {
+ encoding = GRN_ENC_DEFAULT;
+ }
+
+ if (!grn_document_root) {
+ grn_document_root = default_document_root;
+ }
+
+ if (protocol_arg) {
+ switch (*protocol_arg) {
+ case 'g' :
+ case 'G' :
+ do_client = g_client;
+ do_server = g_server;
+ break;
+ case 'h' :
+ case 'H' :
+ do_client = g_client;
+ do_server = h_server;
+ break;
+ case 'm' :
+ case 'M' :
+ is_memcached_mode = GRN_TRUE;
+ do_client = g_client;
+ do_server = g_server;
+ break;
+ default :
+ do_client = g_client;
+ do_server = g_server;
+ break;
+ }
+ } else {
+ do_client = g_client;
+ do_server = g_server;
+ }
+
+#ifdef WIN32
+ if (flags & FLAG_USE_WINDOWS_EVENT_LOG) {
+ use_windows_event_log = GRN_TRUE;
+ }
+#endif /* WIN32 */
+
+ if (use_windows_event_log) {
+ grn_windows_event_logger_set(NULL, windows_event_source_name);
+ }
+
+ if (log_path_arg) {
+ grn_default_logger_set_path(log_path_arg);
+ }
+
+ if (log_rotate_threshold_size_arg) {
+ const char * const end =
+ log_rotate_threshold_size_arg +
+ strlen(log_rotate_threshold_size_arg);
+ const char *rest = NULL;
+ const uint64_t value = grn_atoull(log_rotate_threshold_size_arg, end, &rest);
+ if (end != rest) {
+ fprintf(stderr, "invalid log rotate threshold size: <%s>\n",
+ log_rotate_threshold_size_arg);
+ return EXIT_FAILURE;
+ }
+ grn_default_logger_set_rotate_threshold_size(value);
+ }
+
+ if (query_log_path_arg) {
+ grn_default_query_logger_set_path(query_log_path_arg);
+ }
+
+ if (query_log_rotate_threshold_size_arg) {
+ const char * const end =
+ query_log_rotate_threshold_size_arg +
+ strlen(query_log_rotate_threshold_size_arg);
+ const char *rest = NULL;
+ const uint64_t value =
+ grn_atoull(query_log_rotate_threshold_size_arg, end, &rest);
+ if (end != rest) {
+ fprintf(stderr, "invalid query log rotate threshold size: <%s>\n",
+ query_log_rotate_threshold_size_arg);
+ return EXIT_FAILURE;
+ }
+ grn_default_query_logger_set_rotate_threshold_size(value);
+ }
+
+ {
+ grn_log_level log_level;
+
+ if (log_level_arg) {
+ grn_bool parsed;
+
+ parsed = grn_log_level_parse(log_level_arg, &log_level);
+ if (!parsed) {
+ const char * const end = log_level_arg + strlen(log_level_arg);
+ const char *rest = NULL;
+ const int value = grn_atoi(log_level_arg, end, &rest);
+ if (end != rest || value < GRN_LOG_NONE || value > GRN_LOG_DUMP) {
+ fprintf(stderr, "invalid log level: <%s>\n", log_level_arg);
+ return EXIT_FAILURE;
+ }
+ log_level = value;
+ }
+ } else {
+ log_level = default_log_level;
+ }
+
+ grn_default_logger_set_max_level(log_level);
+ }
+
+ if (max_n_threads_arg) {
+ const char * const end = max_n_threads_arg + strlen(max_n_threads_arg);
+ const char *rest = NULL;
+ const uint32_t value = grn_atoui(max_n_threads_arg, end, &rest);
+ if (end != rest || value < 1 || value > 100) {
+ fprintf(stderr, "invalid max number of threads: <%s>\n",
+ max_n_threads_arg);
+ return EXIT_FAILURE;
+ }
+ max_n_floating_threads = value;
+ } else {
+ if (flags & FLAG_MODE_ALONE) {
+ max_n_floating_threads = 1;
+ } else {
+ max_n_floating_threads = default_max_n_threads;
+ }
+ }
+
+ grn_thread_set_get_limit_func(groonga_get_thread_limit, NULL);
+ grn_thread_set_set_limit_func(groonga_set_thread_limit, NULL);
+
+ if (output_fd_arg) {
+ const char * const end = output_fd_arg + strlen(output_fd_arg);
+ const char *rest = NULL;
+ const int output_fd = grn_atoi(output_fd_arg, end, &rest);
+ if (rest != end || output_fd == 0) {
+ fprintf(stderr, "invalid output FD: <%s>\n", output_fd_arg);
+ return EXIT_FAILURE;
+ }
+ output = fdopen(output_fd, "w");
+ if (!output) {
+ fprintf(stderr, "can't open output FD: %d (%s)\n",
+ output_fd, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ }
+
+
+ if (bind_address_arg) {
+ const size_t bind_address_length = strlen(bind_address_arg);
+ if (bind_address_length > HOST_NAME_MAX) {
+ fprintf(stderr, "too long bind address: %s (%u bytes):"
+ " must not be longer than %u bytes\n",
+ bind_address_arg, (unsigned int)bind_address_length, HOST_NAME_MAX);
+ return EXIT_FAILURE;
+ }
+ grn_strcpy(bind_address, HOST_NAME_MAX + 1, bind_address_arg);
+ } else {
+ grn_strcpy(bind_address, HOST_NAME_MAX + 1, default_bind_address);
+ }
+
+ if (hostname_arg) {
+ const size_t hostname_length = strlen(hostname_arg);
+ if (hostname_length > HOST_NAME_MAX) {
+ fprintf(stderr, "too long hostname: %s (%u bytes):"
+ " must not be longer than %u bytes\n",
+ hostname_arg, (unsigned int)hostname_length, HOST_NAME_MAX);
+ return EXIT_FAILURE;
+ }
+ grn_strcpy(hostname, HOST_NAME_MAX + 1, hostname_arg);
+ } else {
+ grn_strcpy(hostname, HOST_NAME_MAX + 1, default_hostname);
+ }
+
+ if (document_root_arg) {
+ grn_document_root = document_root_arg;
+ }
+
+ if (default_command_version_arg) {
+ const char * const end = default_command_version_arg
+ + strlen(default_command_version_arg);
+ const char *rest = NULL;
+ const int value = grn_atoi(default_command_version_arg, end, &rest);
+ if (end != rest || value < GRN_COMMAND_VERSION_MIN ||
+ value > GRN_COMMAND_VERSION_MAX) {
+ fprintf(stderr, "invalid command version: <%s>\n",
+ default_command_version_arg);
+ return EXIT_FAILURE;
+ }
+ default_command_version = value;
+ } else {
+ default_command_version = default_default_command_version;
+ }
+
+ if (default_match_escalation_threshold_arg) {
+ const char * const end = default_match_escalation_threshold_arg
+ + strlen(default_match_escalation_threshold_arg);
+ const char *rest = NULL;
+ const int64_t value = grn_atoll(default_match_escalation_threshold_arg, end, &rest);
+ if (end != rest) {
+ fprintf(stderr, "invalid match escalation threshold: <%s>\n",
+ default_match_escalation_threshold_arg);
+ return EXIT_FAILURE;
+ }
+ default_match_escalation_threshold = value;
+ } else {
+ default_match_escalation_threshold = default_default_match_escalation_threshold;
+ }
+
+ if (cache_limit_arg) {
+ const char * const end = cache_limit_arg + strlen(cache_limit_arg);
+ const char *rest = NULL;
+ const uint32_t value = grn_atoui(cache_limit_arg, end, &rest);
+ if (end != rest) {
+ fprintf(stderr, "invalid --cache-limit value: <%s>\n", cache_limit_arg);
+ return EXIT_FAILURE;
+ }
+ cache_limit = value;
+ }
+
+ if (default_request_timeout_arg) {
+ const char * const end =
+ default_request_timeout_arg + strlen(default_request_timeout_arg);
+ char *rest = NULL;
+ double value;
+ value = strtod(default_request_timeout_arg, &rest);
+ if (end != rest) {
+ fprintf(stderr, "invalid default request timeout: <%s>\n",
+ default_request_timeout_arg);
+ return EXIT_FAILURE;
+ }
+ default_request_timeout = value;
+ } else {
+ default_request_timeout = default_default_request_timeout;
+ }
+
+ grn_gctx.errbuf[0] = '\0';
+ if (grn_init()) {
+ fprintf(stderr, "failed to initialize Groonga: %s\n", grn_gctx.errbuf);
+ return EXIT_FAILURE;
+ }
+
+ grn_set_default_encoding(encoding);
+
+ if (default_command_version_arg) {
+ grn_set_default_command_version(default_command_version);
+ }
+
+ if (default_match_escalation_threshold_arg) {
+ grn_set_default_match_escalation_threshold(default_match_escalation_threshold);
+ }
+
+ if (default_request_timeout_arg) {
+ grn_set_default_request_timeout(default_request_timeout);
+ }
+
+ grn_set_segv_handler();
+ grn_set_int_handler();
+ grn_set_term_handler();
+
+ if (cache_limit_arg) {
+ grn_cache *cache;
+ cache = grn_cache_current_get(&grn_gctx);
+ grn_cache_set_max_n_entries(&grn_gctx, cache, cache_limit);
+ }
+
+ MUTEX_INIT(q_mutex);
+ COND_INIT(q_cond);
+
+ if (input_path) {
+ input_reader = grn_file_reader_open(&grn_gctx, input_path);
+ if (!input_reader) {
+ fprintf(stderr, "can't open input file: %s (%s)\n",
+ input_path, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ batchmode = GRN_TRUE;
+ } else {
+ if (input_fd_arg) {
+ const char * const end = input_fd_arg + strlen(input_fd_arg);
+ const char *rest = NULL;
+ const int input_fd = grn_atoi(input_fd_arg, end, &rest);
+ if (rest != end || input_fd == 0) {
+ fprintf(stderr, "invalid input FD: <%s>\n", input_fd_arg);
+ return EXIT_FAILURE;
+ }
+ if (dup2(input_fd, STDIN_FILENO) == -1) {
+ fprintf(stderr, "can't open input FD: %d (%s)\n",
+ input_fd, strerror(errno));
+ return EXIT_FAILURE;
+ }
+ input_reader = grn_file_reader_open(&grn_gctx, "-");
+ if (!input_reader) {
+ fprintf(stderr, "%s", grn_gctx.errbuf);
+ return EXIT_FAILURE;
+ }
+ batchmode = GRN_TRUE;
+ } else {
+ input_reader = grn_file_reader_open(&grn_gctx, "-");
+ if (!input_reader) {
+ fprintf(stderr, "%s", grn_gctx.errbuf);
+ return EXIT_FAILURE;
+ }
+ if (argc - i > 1) {
+ batchmode = GRN_TRUE;
+ } else {
+ batchmode = !grn_isatty(0);
+ }
+ }
+ }
+
+ if ((flags & (FLAG_MODE_ALONE | FLAG_MODE_CLIENT)) &&
+ !batchmode) {
+ need_line_editor = GRN_TRUE;
+ }
+
+#ifdef GRN_WITH_LIBEDIT
+ if (need_line_editor) {
+ line_editor_init(argc, argv);
+ }
+#endif
+
+ newdb = (flags & FLAG_NEW_DB);
+ is_daemon_mode = (flags & FLAG_MODE_DAEMON);
+ if (flags & FLAG_MODE_CLIENT) {
+ exit_code = do_client(argc - i, argv + i);
+ } else if (is_daemon_mode || (flags & FLAG_MODE_SERVER)) {
+ exit_code = do_server(argc > i ? argv[i] : NULL);
+ } else {
+ exit_code = do_alone(argc - i, argv + i);
+ }
+
+ COND_FIN(q_cond);
+ MUTEX_FIN(q_mutex);
+
+ if (input_reader) {
+ grn_file_reader_close(&grn_gctx, input_reader);
+ }
+#ifdef GRN_WITH_LIBEDIT
+ if (need_line_editor) {
+ line_editor_fin();
+ }
+#endif
+ if (output != stdout) {
+ fclose(output);
+ }
+ grn_fin();
+ return exit_code;
+}
diff --git a/storage/mroonga/vendor/groonga/src/groonga_benchmark.c b/storage/mroonga/vendor/groonga/src/groonga_benchmark.c
new file mode 100644
index 00000000..267bb278
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/groonga_benchmark.c
@@ -0,0 +1,3176 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2010-2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif /* HAVE_SYS_WAIT_H */
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif /* HAVE_SYS_SOCKET_H */
+#ifndef WIN32
+# include <netinet/in.h>
+#endif /* WIN32 */
+
+#include <grn_str.h>
+#include <grn_com.h>
+#include <grn_db.h>
+
+#ifdef WIN32
+#include <windows.h>
+#include <stddef.h>
+#else
+#include <sys/param.h>
+#include <sys/utsname.h>
+#include <sys/statvfs.h>
+#include <libgen.h>
+#endif /* WIN32 */
+
+/*
+#define DEBUG_FTP
+#define DEBUG_HTTP
+*/
+
+#define FTPUSER "anonymous"
+#define FTPPASSWD "grntest"
+#define FTPSERVER "ftp.groonga.org"
+#define FTPBUF 20000
+#define DEFAULT_PORT 10041
+#define DEFAULT_DEST "localhost"
+
+#define OUT_JSON 0
+#define OUT_TSV 1
+
+static int grntest_outtype = OUT_JSON;
+
+static grn_critical_section grntest_cs;
+
+static int grntest_stop_flag = 0;
+static int grntest_detail_on = 0;
+static int grntest_remote_mode = 0;
+static int grntest_localonly_mode = 0;
+static int grntest_owndb_mode = 0;
+static int grntest_onmemory_mode = 0;
+static grn_bool grntest_ftp_mode = GRN_FALSE;
+#define TMPFILE "_grntest.tmp"
+
+static grn_ctx grntest_server_context;
+static FILE *grntest_log_file;
+
+#define OS_LINUX64 "LINUX64"
+#define OS_LINUX32 "LINUX32"
+#define OS_WINDOWS64 "WINDOWS64"
+#define OS_WINDOWS32 "WINDOWS32"
+
+#ifdef WIN32
+typedef SOCKET socket_t;
+#define SOCKETERROR INVALID_SOCKET
+#define socketclose closesocket
+static const char *groonga_path = "groonga.exe";
+static PROCESS_INFORMATION grntest_pi;
+#else
+static pid_t grntest_server_id = 0;
+typedef int socket_t;
+#define socketclose close
+#define SOCKETERROR -1
+static const char *groonga_path = "groonga";
+#endif /* WIN32 */
+
+static const char *groonga_protocol = "gqtp";
+static const char *grntest_osinfo;
+static int grntest_sigint = 0;
+
+
+
+static grn_obj *grntest_db = NULL;
+
+#define MAX_CON_JOB 10
+#define MAX_CON 64
+
+#define BUF_LEN 1024
+#define MAX_PATH_LEN 256
+
+#define J_DO_LOCAL 1 /* do_local */
+#define J_DO_GQTP 2 /* do_gqtp */
+#define J_DO_HTTP 3 /* do_http */
+#define J_REP_LOCAL 4 /* rep_local */
+#define J_REP_GQTP 5 /* rep_gqtp */
+#define J_REP_HTTP 6 /* rep_http */
+#define J_OUT_LOCAL 7 /* out_local */
+#define J_OUT_GQTP 8 /* out_gqtp */
+#define J_OUT_HTTP 9 /* out_http */
+#define J_TEST_LOCAL 10 /* test_local */
+#define J_TEST_GQTP 11 /* test_gqtp */
+#define J_TEST_HTTP 12 /* test_http */
+
+static char grntest_username[BUF_LEN];
+static char grntest_scriptname[BUF_LEN];
+static char grntest_date[BUF_LEN];
+static char grntest_serverhost[BUF_LEN];
+static int grntest_serverport;
+static const char *grntest_dbpath;
+
+struct job {
+ char jobname[BUF_LEN];
+ char commandfile[BUF_LEN];
+ int qnum;
+ int jobtype;
+ int concurrency;
+ int ntimes;
+ int done;
+ long long int max;
+ long long int min;
+ FILE *outputlog;
+ grn_file_reader *inputlog;
+ char logfile[BUF_LEN];
+};
+
+struct task {
+ char *file;
+ grn_obj *commands;
+ int jobtype;
+ int ntimes;
+ int qnum;
+ int job_id;
+ long long int max;
+ long long int min;
+ socket_t http_socket;
+ grn_obj http_response;
+};
+
+static struct task grntest_task[MAX_CON];
+static struct job grntest_job[MAX_CON];
+static int grntest_jobdone;
+static int grntest_jobnum;
+static grn_ctx grntest_ctx[MAX_CON];
+static grn_obj *grntest_owndb[MAX_CON];
+
+static grn_obj grntest_starttime, grntest_jobs_start;
+
+static int
+grntest_atoi(const char *str, const char *end, const char **rest)
+{
+ while (grn_isspace(str, GRN_ENC_UTF8) == 1) {
+ str++;
+ }
+ return grn_atoi(str, end, rest);
+}
+
+static int
+out_p(int jobtype)
+{
+ if (jobtype == J_OUT_LOCAL) {
+ return 1;
+ }
+ if (jobtype == J_OUT_GQTP) {
+ return 1;
+ }
+ if (jobtype == J_OUT_HTTP) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+test_p(int jobtype)
+{
+ if (jobtype == J_TEST_LOCAL) {
+ return 1;
+ }
+ if (jobtype == J_TEST_GQTP) {
+ return 1;
+ }
+ if (jobtype == J_TEST_HTTP) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+report_p(int jobtype)
+{
+ if (jobtype == J_REP_LOCAL) {
+ return 1;
+ }
+ if (jobtype == J_REP_GQTP) {
+ return 1;
+ }
+ if (jobtype == J_REP_HTTP) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+gqtp_p(int jobtype)
+{
+ if (jobtype == J_DO_GQTP) {
+ return 1;
+ }
+ if (jobtype == J_REP_GQTP) {
+ return 1;
+ }
+ if (jobtype == J_OUT_GQTP) {
+ return 1;
+ }
+ if (jobtype == J_TEST_GQTP) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+http_p(int jobtype)
+{
+ if (jobtype == J_DO_HTTP) {
+ return 1;
+ }
+ if (jobtype == J_REP_HTTP) {
+ return 1;
+ }
+ if (jobtype == J_OUT_HTTP) {
+ return 1;
+ }
+ if (jobtype == J_TEST_HTTP) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+error_exit_in_thread(intptr_t code)
+{
+ fprintf(stderr,
+ "Fatal error! Check script file or database!: %ld\n", (long)code);
+ fflush(stderr);
+ CRITICAL_SECTION_ENTER(grntest_cs);
+ grntest_stop_flag = 1;
+ CRITICAL_SECTION_LEAVE(grntest_cs);
+#ifdef WIN32
+ _endthreadex(code);
+#else
+ pthread_exit((void *)code);
+#endif /* WIN32 */
+ return 0;
+}
+
+
+static void
+escape_command(grn_ctx *ctx, const char *in, int ilen, grn_obj *escaped_command)
+{
+ int i = 0;
+
+ while (i < ilen) {
+ if ((in[i] == '\\') || (in[i] == '\"') || (in[i] == '/')) {
+ GRN_TEXT_PUTC(ctx, escaped_command, '\\');
+ GRN_TEXT_PUTC(ctx, escaped_command, in[i]);
+ i++;
+ } else {
+ switch (in[i]) {
+ case '\b':
+ GRN_TEXT_PUTS(ctx, escaped_command, "\\b");
+ i++;
+ break;
+ case '\f':
+ GRN_TEXT_PUTS(ctx, escaped_command, "\\f");
+ i++;
+ break;
+ case '\n':
+ GRN_TEXT_PUTS(ctx, escaped_command, "\\n");
+ i++;
+ break;
+ case '\r':
+ GRN_TEXT_PUTS(ctx, escaped_command, "\\r");
+ i++;
+ break;
+ case '\t':
+ GRN_TEXT_PUTS(ctx, escaped_command, "\\t");
+ i++;
+ break;
+ default:
+ GRN_TEXT_PUTC(ctx, escaped_command, in[i]);
+ i++;
+ break;
+ }
+ }
+ }
+ GRN_TEXT_PUTC(ctx, escaped_command, '\0');
+}
+
+static int
+report_command(grn_ctx *ctx, const char *command, const char *ret, int task_id,
+ grn_obj *start_time, grn_obj *end_time)
+{
+ int i, len, clen;
+ long long int start, end;
+ grn_obj result, escaped_command;
+
+ GRN_TEXT_INIT(&result, 0);
+ if (strncmp(ret, "[[", 2) == 0) {
+ i = 2;
+ len = 1;
+ while (ret[i] != ']') {
+ i++;
+ len++;
+ if (ret[i] == '\0') {
+ fprintf(stderr, "Error results:command=[%s]\n", command);
+ error_exit_in_thread(3);
+ }
+ }
+ len++;
+ grn_text_esc(ctx, &result, ret + 1, len);
+ } else {
+ grn_text_esc(ctx, &result, ret, strlen(ret));
+ }
+
+ start = GRN_TIME_VALUE(start_time) - GRN_TIME_VALUE(&grntest_starttime);
+ end = GRN_TIME_VALUE(end_time) - GRN_TIME_VALUE(&grntest_starttime);
+ clen = strlen(command);
+ GRN_TEXT_INIT(&escaped_command, 0);
+ escape_command(ctx, command, clen, &escaped_command);
+ if (grntest_outtype == OUT_TSV) {
+ fprintf(grntest_log_file, "report\t%d\t%s\t%" GRN_FMT_LLD "\t%" GRN_FMT_LLD "\t%.*s\n",
+ task_id, GRN_TEXT_VALUE(&escaped_command), start, end,
+ (int)GRN_TEXT_LEN(&result), GRN_TEXT_VALUE(&result));
+ } else {
+ fprintf(grntest_log_file, "[%d, \"%s\", %" GRN_FMT_LLD ", %" GRN_FMT_LLD ", %.*s],\n",
+ task_id, GRN_TEXT_VALUE(&escaped_command), start, end,
+ (int)GRN_TEXT_LEN(&result), GRN_TEXT_VALUE(&result));
+ }
+ fflush(grntest_log_file);
+ GRN_OBJ_FIN(ctx, &escaped_command);
+ GRN_OBJ_FIN(ctx, &result);
+ return 0;
+}
+
+static int
+output_result_final(grn_ctx *ctx, int qnum)
+{
+ grn_obj end_time;
+ long long int latency, self;
+ double sec, qps;
+
+ GRN_TIME_INIT(&end_time, 0);
+ GRN_TIME_NOW(ctx, &end_time);
+
+ latency = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&grntest_starttime);
+ self = latency;
+ sec = self / (double)1000000;
+ qps = (double)qnum / sec;
+ if (grntest_outtype == OUT_TSV) {
+ fprintf(grntest_log_file, "total\t%" GRN_FMT_LLD "\t%f\t%d\n", latency, qps, qnum);
+ } else {
+ fprintf(grntest_log_file,
+ "{\"total\": %" GRN_FMT_LLD ", \"qps\": %f, \"queries\": %d}]\n", latency, qps, qnum);
+ }
+ grn_obj_close(ctx, &end_time);
+ return 0;
+}
+
+static int
+output_sysinfo(char *sysinfo)
+{
+ if (grntest_outtype == OUT_TSV) {
+ fprintf(grntest_log_file, "%s", sysinfo);
+ } else {
+ fprintf(grntest_log_file, "[%s\n", sysinfo);
+ }
+ return 0;
+}
+
+/* #define ENABLE_ERROR_REPORT 1 */
+#ifdef ENABLE_ERROR_REPORT
+static int
+error_command(grn_ctx *ctx, char *command, int task_id)
+{
+ fprintf(stderr, "error!:command=[%s] task_id = %d\n", command, task_id);
+ fflush(stderr);
+ error_exit_in_thread(1);
+ return 0;
+}
+#endif
+
+static void
+normalize_output(char *output, int length,
+ char **normalized_output, int *normalized_length)
+{
+ int i;
+
+ *normalized_output = NULL;
+ *normalized_length = length;
+ for (i = 0; i < length; i++) {
+ if (!strncmp(output + i, "],", 2)) {
+ *normalized_output = output + i + 2;
+ *normalized_length -= i + 2;
+ break;
+ }
+ }
+
+ if (!*normalized_output) {
+ if (length > 2 && strncmp(output + length - 2, "]]", 2)) {
+ *normalized_output = output + length;
+ *normalized_length = 0;
+ } else {
+ *normalized_output = output;
+ }
+ }
+}
+
+static grn_bool
+same_result_p(char *expect, int expected_length, char *result, int result_length)
+{
+ char *normalized_expected, *normalized_result;
+ int normalized_expected_length, normalized_result_length;
+
+ normalize_output(expect, expected_length,
+ &normalized_expected, &normalized_expected_length);
+ normalize_output(result, result_length,
+ &normalized_result, &normalized_result_length);
+
+ return((normalized_expected_length == normalized_result_length) &&
+ strncmp(normalized_expected, normalized_result,
+ normalized_expected_length) == 0);
+}
+
+static socket_t
+open_socket(const char *host, int port)
+{
+ socket_t sock;
+ struct hostent *servhost;
+ struct sockaddr_in server;
+ u_long inaddr;
+ int ret;
+
+ servhost = gethostbyname(host);
+ if (servhost == NULL){
+ fprintf(stderr, "Bad hostname [%s]\n", host);
+ return -1;
+ }
+ inaddr = *(u_long*)(servhost->h_addr_list[0]);
+
+ memset(&server, 0, sizeof(struct sockaddr_in));
+ server.sin_family = AF_INET;
+ server.sin_port = htons(port);
+ server.sin_addr = *(struct in_addr*)&inaddr;
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == -1) {
+ fprintf(stderr, "socket error\n");
+ return -1;
+ }
+ ret = connect(sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
+ if (ret == -1) {
+ fprintf(stderr, "connect error\n");
+ return -1;
+ }
+ return sock;
+}
+
+static int
+write_to_server(socket_t socket, const char *buf)
+{
+#ifdef DEBUG_FTP
+ fprintf(stderr, "send:%s", buf);
+#endif
+ send(socket, buf, strlen(buf), 0);
+ return 0;
+}
+
+#define OUTPUT_TYPE "output_type"
+#define OUTPUT_TYPE_LEN (sizeof(OUTPUT_TYPE) - 1)
+
+static void
+command_line_to_uri_path(grn_ctx *ctx, grn_obj *uri, const char *command)
+{
+ char tok_type;
+ int offset = 0, have_key = 0;
+ const char *p, *e, *v;
+ grn_obj buf, *expr = NULL;
+ grn_expr_var *vars;
+ unsigned int nvars;
+
+ GRN_TEXT_INIT(&buf, 0);
+ p = command;
+ e = command + strlen(command);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ if ((expr = grn_ctx_get(ctx, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf)))) {
+ grn_obj params, output_type;
+
+ GRN_TEXT_INIT(&params, 0);
+ GRN_TEXT_INIT(&output_type, 0);
+ vars = ((grn_proc *)expr)->vars;
+ nvars = ((grn_proc *)expr)->nvars;
+ GRN_TEXT_PUTS(ctx, uri, "/d/");
+ GRN_TEXT_PUT(ctx, uri, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ while (p < e) {
+ GRN_BULK_REWIND(&buf);
+ p = grn_text_unesc_tok(ctx, &buf, p, e, &tok_type);
+ v = GRN_TEXT_VALUE(&buf);
+ switch (tok_type) {
+ case GRN_TOK_VOID :
+ p = e;
+ break;
+ case GRN_TOK_SYMBOL :
+ if (GRN_TEXT_LEN(&buf) > 2 && v[0] == '-' && v[1] == '-') {
+ int l = GRN_TEXT_LEN(&buf) - 2;
+ v += 2;
+ if (l == OUTPUT_TYPE_LEN && !memcmp(v, OUTPUT_TYPE, OUTPUT_TYPE_LEN)) {
+ GRN_BULK_REWIND(&output_type);
+ p = grn_text_unesc_tok(ctx, &output_type, p, e, &tok_type);
+ break;
+ }
+ if (GRN_TEXT_LEN(&params)) {
+ GRN_TEXT_PUTS(ctx, &params, "&");
+ }
+ grn_text_urlenc(ctx, &params, v, l);
+ have_key = 1;
+ break;
+ }
+ /* fallthru */
+ case GRN_TOK_STRING :
+ case GRN_TOK_QUOTE :
+ if (!have_key) {
+ if (offset < nvars) {
+ if (GRN_TEXT_LEN(&params)) {
+ GRN_TEXT_PUTS(ctx, &params, "&");
+ }
+ grn_text_urlenc(ctx, &params,
+ vars[offset].name, vars[offset].name_size);
+ offset++;
+ }
+ }
+ GRN_TEXT_PUTS(ctx, &params, "=");
+ grn_text_urlenc(ctx, &params, GRN_TEXT_VALUE(&buf), GRN_TEXT_LEN(&buf));
+ have_key = 0;
+ break;
+ }
+ }
+ GRN_TEXT_PUTS(ctx, uri, ".");
+ if (GRN_TEXT_LEN(&output_type)) {
+ GRN_TEXT_PUT(ctx, uri,
+ GRN_TEXT_VALUE(&output_type), GRN_TEXT_LEN(&output_type));
+ } else {
+ GRN_TEXT_PUTS(ctx, uri, "json");
+ }
+ if (GRN_TEXT_LEN(&params) > 0) {
+ GRN_TEXT_PUTS(ctx, uri, "?");
+ GRN_TEXT_PUT(ctx, uri, GRN_TEXT_VALUE(&params), GRN_TEXT_LEN(&params));
+ }
+ GRN_OBJ_FIN(ctx, &params);
+ GRN_OBJ_FIN(ctx, &output_type);
+ }
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static void
+command_send_http(grn_ctx *ctx, const char *command, int type, int task_id)
+{
+ socket_t http_socket;
+ grn_obj buf;
+
+ http_socket = open_socket(grntest_serverhost, grntest_serverport);
+ if (http_socket == SOCKETERROR) {
+ fprintf(stderr, "failed to connect to groonga at %s:%d via HTTP: ",
+ grntest_serverhost, grntest_serverport);
+#ifdef WIN32
+ fprintf(stderr, "%lu\n", GetLastError());
+#else
+ fprintf(stderr, "%s\n", strerror(errno));
+#endif
+ error_exit_in_thread(100);
+ }
+ grntest_task[task_id].http_socket = http_socket;
+ GRN_BULK_REWIND(&grntest_task[task_id].http_response);
+
+ GRN_TEXT_INIT(&buf, 0);
+ GRN_TEXT_PUTS(ctx, &buf, "GET ");
+ if (strncmp(command, "/d/", 3) == 0) {
+ GRN_TEXT_PUTS(ctx, &buf, command);
+ } else {
+ command_line_to_uri_path(ctx, &buf, command);
+ }
+#ifdef DEBUG_HTTP
+ fprintf(stderr, "command: <%s>\n", command);
+ fprintf(stderr, "path: <%.*s>\n",
+ (int)GRN_TEXT_LEN(&buf), GRN_TEXT_VALUE(&buf));
+#endif
+ GRN_TEXT_PUTS(ctx, &buf, " HTTP/1.1\r\n");
+ GRN_TEXT_PUTS(ctx, &buf, "Host: ");
+ GRN_TEXT_PUTS(ctx, &buf, grntest_serverhost);
+ GRN_TEXT_PUTS(ctx, &buf, "\r\n");
+ GRN_TEXT_PUTS(ctx, &buf, "User-Agent: grntest/");
+ GRN_TEXT_PUTS(ctx, &buf, grn_get_version());
+ GRN_TEXT_PUTS(ctx, &buf, "\r\n");
+ GRN_TEXT_PUTS(ctx, &buf, "Connection: close\r\n");
+ GRN_TEXT_PUTS(ctx, &buf, "\r\n");
+ GRN_TEXT_PUTC(ctx, &buf, '\0');
+ write_to_server(http_socket, GRN_TEXT_VALUE(&buf));
+ GRN_OBJ_FIN(ctx, &buf);
+}
+
+static void
+command_send_ctx(grn_ctx *ctx, const char *command, int type, int task_id)
+{
+ grn_ctx_send(ctx, command, strlen(command), 0);
+/* fix me.
+ when command fails, ctx->rc is not 0 in local mode!
+ if (ctx->rc) {
+ fprintf(stderr, "ctx_send:rc=%d:command:%s\n", ctx->rc, command);
+ error_exit_in_thread(1);
+ }
+*/
+}
+
+static void
+command_send(grn_ctx *ctx, const char *command, int type, int task_id)
+{
+ if (http_p(type)) {
+ command_send_http(ctx, command, type, task_id);
+ } else {
+ command_send_ctx(ctx, command, type, task_id);
+ }
+}
+
+static void
+command_recv_http(grn_ctx *ctx, int type, int task_id,
+ char **res, unsigned int *res_len, int *flags)
+{
+ int len;
+ char buf[BUF_LEN];
+ char *p, *e;
+ socket_t http_socket;
+ grn_obj *http_response;
+
+ http_socket = grntest_task[task_id].http_socket;
+ http_response = &grntest_task[task_id].http_response;
+ while ((len = recv(http_socket, buf, BUF_LEN - 1, 0))) {
+#ifdef DEBUG_HTTP
+ fprintf(stderr, "receive: <%.*s>\n", len, buf);
+#endif
+ GRN_TEXT_PUT(ctx, http_response, buf, len);
+ }
+
+ p = GRN_TEXT_VALUE(http_response);
+ e = p + GRN_TEXT_LEN(http_response);
+ while (p < e) {
+ if (p[0] != '\r') {
+ p++;
+ continue;
+ }
+ if (e - p >= 4) {
+ if (!memcmp(p, "\r\n\r\n", 4)) {
+ *res = p + 4;
+ *res_len = e - *res;
+#ifdef DEBUG_HTTP
+ fprintf(stderr, "body: <%.*s>\n", *res_len, *res);
+#endif
+ break;
+ }
+ p += 4;
+ } else {
+ *res = NULL;
+ *res_len = 0;
+ break;
+ }
+ }
+
+ socketclose(http_socket);
+ grntest_task[task_id].http_socket = 0;
+}
+
+static void
+command_recv_ctx(grn_ctx *ctx, int type, int task_id,
+ char **res, unsigned int *res_len, int *flags)
+{
+ grn_ctx_recv(ctx, res, res_len, flags);
+ if (ctx->rc) {
+ fprintf(stderr, "ctx_recv:rc=%d\n", ctx->rc);
+ error_exit_in_thread(1);
+ }
+}
+
+static void
+command_recv(grn_ctx *ctx, int type, int task_id,
+ char **res, unsigned int *res_len, int *flags)
+{
+ if (http_p(type)) {
+ command_recv_http(ctx, type, task_id, res, res_len, flags);
+ } else {
+ command_recv_ctx(ctx, type, task_id, res, res_len, flags);
+ }
+}
+
+static int
+shutdown_server(void)
+{
+ char *res;
+ int flags;
+ unsigned int res_len;
+ int job_type;
+ int task_id = 0;
+
+ if (grntest_remote_mode) {
+ return 0;
+ }
+ job_type = grntest_task[task_id].jobtype;
+ command_send(&grntest_server_context, "shutdown", job_type, task_id);
+ if (grntest_server_context.rc) {
+ fprintf(stderr, "ctx_send:rc=%d\n", grntest_server_context.rc);
+ exit(1);
+ }
+ command_recv(&grntest_server_context, job_type, task_id,
+ &res, &res_len, &flags);
+
+ return 0;
+}
+
+static int
+do_load_command(grn_ctx *ctx, char *command, int type, int task_id,
+ long long int *load_start)
+{
+ char *res;
+ unsigned int res_len;
+ int flags, ret;
+ grn_obj start_time, end_time;
+
+ GRN_TIME_INIT(&start_time, 0);
+ if (*load_start == 0) {
+ GRN_TIME_NOW(ctx, &start_time);
+ *load_start = GRN_TIME_VALUE(&start_time);
+ } else {
+ GRN_TIME_SET(ctx, &start_time, *load_start);
+ }
+
+ command_send(ctx, command, type, task_id);
+ do {
+ command_recv(ctx, type, task_id, &res, &res_len, &flags);
+ if (res_len) {
+ long long int self;
+ GRN_TIME_INIT(&end_time, 0);
+ GRN_TIME_NOW(ctx, &end_time);
+
+ self = GRN_TIME_VALUE(&end_time) - *load_start;
+
+ if (grntest_task[task_id].max < self) {
+ grntest_task[task_id].max = self;
+ }
+ if (grntest_task[task_id].min > self) {
+ grntest_task[task_id].min = self;
+ }
+
+ if (report_p(grntest_task[task_id].jobtype)) {
+ char tmpbuf[BUF_LEN];
+
+ if (res_len < BUF_LEN) {
+ strncpy(tmpbuf, res, res_len);
+ tmpbuf[res_len] = '\0';
+ } else {
+ strncpy(tmpbuf, res, BUF_LEN - 2);
+ tmpbuf[BUF_LEN -2] = '\0';
+ }
+ report_command(ctx, "load", tmpbuf, task_id, &start_time, &end_time);
+ }
+ if (out_p(grntest_task[task_id].jobtype)) {
+ fwrite(res, 1, res_len, grntest_job[grntest_task[task_id].job_id].outputlog);
+ fputc('\n', grntest_job[grntest_task[task_id].job_id].outputlog);
+ fflush(grntest_job[grntest_task[task_id].job_id].outputlog);
+ }
+ if (test_p(grntest_task[task_id].jobtype)) {
+ grn_obj log;
+ grn_file_reader *input;
+ FILE *output;
+ GRN_TEXT_INIT(&log, 0);
+ input = grntest_job[grntest_task[task_id].job_id].inputlog;
+ output = grntest_job[grntest_task[task_id].job_id].outputlog;
+ if (grn_file_reader_read_line(ctx, input, &log) != GRN_SUCCESS) {
+ GRN_LOG(ctx, GRN_ERROR, "Cannot get input-log");
+ error_exit_in_thread(55);
+ }
+ if (GRN_TEXT_VALUE(&log)[GRN_TEXT_LEN(&log) - 1] == '\n') {
+ grn_bulk_truncate(ctx, &log, GRN_TEXT_LEN(&log) - 1);
+ }
+
+ if (!same_result_p(GRN_TEXT_VALUE(&log), GRN_TEXT_LEN(&log),
+ res, res_len)) {
+ fprintf(output, "DIFF:command:%s\n", command);
+ fprintf(output, "DIFF:result:");
+ fwrite(res, 1, res_len, output);
+ fputc('\n', output);
+ fprintf(output, "DIFF:expect:%.*s\n",
+ (int)GRN_TEXT_LEN(&log), GRN_TEXT_VALUE(&log));
+ fflush(output);
+ }
+ GRN_OBJ_FIN(ctx, &log);
+ }
+ grn_obj_close(ctx, &end_time);
+ ret = 1;
+ break;
+ } else {
+ ret = 0;
+ break;
+ }
+ } while ((flags & GRN_CTX_MORE));
+ grn_obj_close(ctx, &start_time);
+
+ return ret;
+}
+
+
+static int
+do_command(grn_ctx *ctx, char *command, int type, int task_id)
+{
+ char *res;
+ unsigned int res_len;
+ int flags;
+ grn_obj start_time, end_time;
+
+ GRN_TIME_INIT(&start_time, 0);
+ GRN_TIME_NOW(ctx, &start_time);
+
+ command_send(ctx, command, type, task_id);
+ do {
+ command_recv(ctx, type, task_id, &res, &res_len, &flags);
+ if (res_len) {
+ long long int self;
+ GRN_TIME_INIT(&end_time, 0);
+ GRN_TIME_NOW(ctx, &end_time);
+
+ self = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&start_time);
+
+ if (grntest_task[task_id].max < self) {
+ grntest_task[task_id].max = self;
+ }
+ if (grntest_task[task_id].min > self) {
+ grntest_task[task_id].min = self;
+ }
+
+ if (report_p(grntest_task[task_id].jobtype)) {
+ char tmpbuf[BUF_LEN];
+
+ if (res_len < BUF_LEN) {
+ strncpy(tmpbuf, res, res_len);
+ tmpbuf[res_len] = '\0';
+ } else {
+ strncpy(tmpbuf, res, BUF_LEN - 2);
+ tmpbuf[BUF_LEN -2] = '\0';
+ }
+ report_command(ctx, command, tmpbuf, task_id, &start_time, &end_time);
+ }
+ if (out_p(grntest_task[task_id].jobtype)) {
+ fwrite(res, 1, res_len, grntest_job[grntest_task[task_id].job_id].outputlog);
+ fputc('\n', grntest_job[grntest_task[task_id].job_id].outputlog);
+ fflush(grntest_job[grntest_task[task_id].job_id].outputlog);
+ }
+ if (test_p(grntest_task[task_id].jobtype)) {
+ grn_obj log;
+ grn_file_reader *input;
+ FILE *output;
+ GRN_TEXT_INIT(&log, 0);
+ input = grntest_job[grntest_task[task_id].job_id].inputlog;
+ output = grntest_job[grntest_task[task_id].job_id].outputlog;
+ if (grn_file_reader_read_line(ctx, input, &log) != GRN_SUCCESS) {
+ GRN_LOG(ctx, GRN_ERROR, "Cannot get input-log");
+ error_exit_in_thread(55);
+ }
+ if (GRN_TEXT_VALUE(&log)[GRN_TEXT_LEN(&log) - 1] == '\n') {
+ grn_bulk_truncate(ctx, &log, GRN_TEXT_LEN(&log) - 1);
+ }
+
+ if (!same_result_p(GRN_TEXT_VALUE(&log), GRN_TEXT_LEN(&log),
+ res, res_len)) {
+ fprintf(output, "DIFF:command:%s\n", command);
+ fprintf(output, "DIFF:result:");
+ fwrite(res, 1, res_len, output);
+ fputc('\n', output);
+ fprintf(output, "DIFF:expect:%.*s\n",
+ (int)GRN_TEXT_LEN(&log), GRN_TEXT_VALUE(&log));
+ fflush(output);
+ }
+ GRN_OBJ_FIN(ctx, &log);
+ }
+ grn_obj_close(ctx, &end_time);
+ break;
+ } else {
+#ifdef ENABLE_ERROR_REPORT
+ error_command(ctx, command, task_id);
+#endif
+ }
+ } while ((flags & GRN_CTX_MORE));
+
+ grn_obj_close(ctx, &start_time);
+
+ return 0;
+}
+
+static int
+comment_p(char *command)
+{
+ if (command[0] == '#') {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+load_command_p(char *command)
+{
+ int i = 0;
+
+ while (grn_isspace(&command[i], GRN_ENC_UTF8) == 1) {
+ i++;
+ }
+ if (command[i] == '\0') {
+ return 0;
+ }
+ if (!strncmp(&command[i], "load", 4)) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+worker_sub(grn_ctx *ctx, grn_obj *log, int task_id)
+{
+ int i, load_mode, load_count;
+ grn_obj end_time;
+ long long int total_elapsed_time, job_elapsed_time;
+ double sec, qps;
+ long long int load_start;
+ struct task *task;
+ struct job *job;
+
+ task = &(grntest_task[task_id]);
+ task->max = 0LL;
+ task->min = 9223372036854775807LL;
+ task->qnum = 0;
+
+ for (i = 0; i < task->ntimes; i++) {
+ if (task->file != NULL) {
+ grn_file_reader *reader;
+ grn_obj line;
+ reader = grn_file_reader_open(ctx, task->file);
+ if (!reader) {
+ fprintf(stderr, "Cannot open %s\n",grntest_task[task_id].file);
+ error_exit_in_thread(1);
+ }
+ load_mode = 0;
+ load_count = 0;
+ load_start = 0LL;
+ GRN_TEXT_INIT(&line, 0);
+ while (grn_file_reader_read_line(ctx, reader, &line) == GRN_SUCCESS) {
+ if (GRN_TEXT_VALUE(&line)[GRN_TEXT_LEN(&line) - 1] == '\n') {
+ grn_bulk_truncate(ctx, &line, GRN_TEXT_LEN(&line) - 1);
+ }
+ if (GRN_TEXT_LEN(&line) == 0) {
+ GRN_BULK_REWIND(&line);
+ continue;
+ }
+ GRN_TEXT_PUTC(ctx, &line, '\0');
+ if (comment_p(GRN_TEXT_VALUE(&line))) {
+ GRN_BULK_REWIND(&line);
+ continue;
+ }
+ if (load_command_p(GRN_TEXT_VALUE(&line))) {
+ load_mode = 1;
+ load_count = 1;
+ }
+ if (load_mode == 1) {
+ if (do_load_command(&grntest_ctx[task_id], GRN_TEXT_VALUE(&line),
+ task->jobtype,
+ task_id, &load_start)) {
+ task->qnum += load_count;
+ load_mode = 0;
+ load_count = 0;
+ load_start = 0LL;
+ }
+ load_count++;
+ GRN_BULK_REWIND(&line);
+ continue;
+ }
+ do_command(&grntest_ctx[task_id], GRN_TEXT_VALUE(&line),
+ task->jobtype,
+ task_id);
+ task->qnum++;
+ GRN_BULK_REWIND(&line);
+ if (grntest_sigint) {
+ goto exit;
+ }
+ }
+ GRN_OBJ_FIN(ctx, &line);
+ grn_file_reader_close(ctx, reader);
+ } else {
+ int i, n_commands;
+ grn_obj *commands;
+ commands = task->commands;
+ if (!commands) {
+ error_exit_in_thread(1);
+ }
+ load_mode = 0;
+ n_commands = GRN_BULK_VSIZE(commands) / sizeof(grn_obj *);
+ for (i = 0; i < n_commands; i++) {
+ grn_obj *command;
+ command = GRN_PTR_VALUE_AT(commands, i);
+ if (load_command_p(GRN_TEXT_VALUE(command))) {
+ load_mode = 1;
+ }
+ if (load_mode == 1) {
+ if (do_load_command(&grntest_ctx[task_id],
+ GRN_TEXT_VALUE(command),
+ task->jobtype, task_id, &load_start)) {
+ load_mode = 0;
+ load_start = 0LL;
+ task->qnum++;
+ }
+ continue;
+ }
+ do_command(&grntest_ctx[task_id],
+ GRN_TEXT_VALUE(command),
+ task->jobtype, task_id);
+ task->qnum++;
+ if (grntest_sigint) {
+ goto exit;
+ }
+ }
+ }
+ }
+
+exit:
+ GRN_TIME_INIT(&end_time, 0);
+ GRN_TIME_NOW(&grntest_ctx[task_id], &end_time);
+ total_elapsed_time = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&grntest_starttime);
+ job_elapsed_time = GRN_TIME_VALUE(&end_time) - GRN_TIME_VALUE(&grntest_jobs_start);
+
+ CRITICAL_SECTION_ENTER(grntest_cs);
+ job = &(grntest_job[task->job_id]);
+ if (job->max < task->max) {
+ job->max = task->max;
+ }
+ if (job->min > task->min) {
+ job->min = task->min;
+ }
+
+ job->qnum += task->qnum;
+ job->done++;
+ if (job->done == job->concurrency) {
+ char tmpbuf[BUF_LEN];
+ sec = job_elapsed_time / (double)1000000;
+ qps = (double)job->qnum/ sec;
+ grntest_jobdone++;
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf,
+ "job\t"
+ "%s\t"
+ "%" GRN_FMT_LLD "\t"
+ "%" GRN_FMT_LLD "\t"
+ "%f\t"
+ "%" GRN_FMT_LLD "\t"
+ "%" GRN_FMT_LLD "\t"
+ "%d\n",
+ job->jobname,
+ total_elapsed_time,
+ job_elapsed_time,
+ qps,
+ job->min,
+ job->max,
+ job->qnum);
+ } else {
+ sprintf(tmpbuf,
+ "{\"job\": \"%s\", "
+ "\"total_elapsed_time\": %" GRN_FMT_LLD ", "
+ "\"job_elapsed_time\": %" GRN_FMT_LLD ", "
+ "\"qps\": %f, "
+ "\"min\": %" GRN_FMT_LLD ", "
+ "\"max\": %" GRN_FMT_LLD ", "
+ "\"queries\": %d}",
+ job->jobname,
+ total_elapsed_time,
+ job_elapsed_time,
+ qps,
+ job->min,
+ job->max,
+ job->qnum);
+ if (grntest_jobdone < grntest_jobnum) {
+ grn_strcat(tmpbuf, BUF_LEN, ",");
+ }
+ }
+ GRN_TEXT_PUTS(ctx, log, tmpbuf);
+ if (grntest_jobdone == grntest_jobnum) {
+ if (grntest_outtype == OUT_TSV) {
+ fprintf(grntest_log_file, "%.*s",
+ (int)GRN_TEXT_LEN(log), GRN_TEXT_VALUE(log));
+ } else {
+ if (grntest_detail_on) {
+ fseek(grntest_log_file, -2, SEEK_CUR);
+ fprintf(grntest_log_file, "],\n");
+ }
+ fprintf(grntest_log_file, "\"summary\": [");
+ fprintf(grntest_log_file, "%.*s",
+ (int)GRN_TEXT_LEN(log), GRN_TEXT_VALUE(log));
+ fprintf(grntest_log_file, "]");
+ }
+ fflush(grntest_log_file);
+ }
+ }
+ grn_obj_close(&grntest_ctx[task_id], &end_time);
+ CRITICAL_SECTION_LEAVE(grntest_cs);
+
+ return 0;
+}
+
+typedef struct _grntest_worker {
+ grn_ctx *ctx;
+ grn_obj log;
+ int task_id;
+} grntest_worker;
+
+#ifdef WIN32
+static unsigned int
+__stdcall
+worker(void *val)
+{
+ grntest_worker *worker = val;
+ worker_sub(worker->ctx, &worker->log, worker->task_id);
+ return 0;
+}
+#else
+static void *
+worker(void *val)
+{
+ grntest_worker *worker = val;
+ worker_sub(worker->ctx, &worker->log, worker->task_id);
+ return NULL;
+}
+#endif /* WIN32 */
+
+#ifdef WIN32
+static int
+thread_main(grn_ctx *ctx, int num)
+{
+ int i;
+ int ret;
+ HANDLE pthread[MAX_CON];
+ grntest_worker *workers[MAX_CON];
+
+ for (i = 0; i < num; i++) {
+ workers[i] = GRN_MALLOC(sizeof(grntest_worker));
+ workers[i]->ctx = &grntest_ctx[i];
+ GRN_TEXT_INIT(&workers[i]->log, 0);
+ workers[i]->task_id = i;
+ pthread[i] = (HANDLE)_beginthreadex(NULL, 0, worker, (void *)workers[i],
+ 0, NULL);
+ if (pthread[i]== (HANDLE)0) {
+ fprintf(stderr, "thread failed:%d\n", i);
+ error_exit_in_thread(1);
+ }
+ }
+
+ ret = WaitForMultipleObjects(num, pthread, TRUE, INFINITE);
+ if (ret == WAIT_TIMEOUT) {
+ fprintf(stderr, "timeout\n");
+ error_exit_in_thread(1);
+ }
+
+ for (i = 0; i < num; i++) {
+ CloseHandle(pthread[i]);
+ GRN_OBJ_FIN(workers[i]->ctx, &workers[i]->log);
+ GRN_FREE(workers[i]);
+ }
+ return 0;
+}
+#else
+static int
+thread_main(grn_ctx *ctx, int num)
+{
+ intptr_t i;
+ int ret;
+ pthread_t pthread[MAX_CON];
+ grntest_worker *workers[MAX_CON];
+
+ for (i = 0; i < num; i++) {
+ workers[i] = GRN_MALLOC(sizeof(grntest_worker));
+ workers[i]->ctx = &grntest_ctx[i];
+ GRN_TEXT_INIT(&workers[i]->log, 0);
+ workers[i]->task_id = i;
+ ret = pthread_create(&pthread[i], NULL, worker, (void *)workers[i]);
+ if (ret) {
+ fprintf(stderr, "Cannot create thread:ret=%d\n", ret);
+ error_exit_in_thread(1);
+ }
+ }
+
+ for (i = 0; i < num; i++) {
+ ret = pthread_join(pthread[i], NULL);
+ GRN_OBJ_FIN(workers[i]->ctx, &workers[i]->log);
+ GRN_FREE(workers[i]);
+ if (ret) {
+ fprintf(stderr, "Cannot join thread:ret=%d\n", ret);
+ error_exit_in_thread(1);
+ }
+ }
+ return 0;
+}
+#endif
+
+static int
+error_exit(grn_ctx *ctx, int ret)
+{
+ fflush(stderr);
+ shutdown_server();
+ grn_ctx_fin(ctx);
+ grn_fin();
+ exit(ret);
+}
+
+static int
+get_sysinfo(const char *path, char *result, int olen)
+{
+ char tmpbuf[256];
+
+#ifdef WIN32
+ ULARGE_INTEGER dinfo;
+ char cpustring[64];
+ SYSTEM_INFO sinfo;
+ MEMORYSTATUSEX minfo;
+ OSVERSIONINFO osinfo;
+
+ if (grntest_outtype == OUT_TSV) {
+ result[0] = '\0';
+ sprintf(tmpbuf, "script\t%s\n", grntest_scriptname);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, "user\t%s\n", grntest_username);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, "date\t%s\n", grntest_date);
+ grn_strcat(result, olen, tmpbuf);
+ } else {
+ grn_strcpy(result, olen, "{");
+ sprintf(tmpbuf, "\"script\": \"%s.scr\",\n", grntest_scriptname);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, " \"user\": \"%s\",\n", grntest_username);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, " \"date\": \"%s\",\n", grntest_date);
+ grn_strcat(result, olen, tmpbuf);
+ }
+
+ memset(cpustring, 0, 64);
+#ifndef __GNUC__
+ {
+ int cinfo[4];
+ __cpuid(cinfo, 0x80000002);
+ memcpy(cpustring, cinfo, 16);
+ __cpuid(cinfo, 0x80000003);
+ memcpy(cpustring+16, cinfo, 16);
+ __cpuid(cinfo, 0x80000004);
+ memcpy(cpustring+32, cinfo, 16);
+ }
+#endif
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s\n", cpustring);
+ } else {
+ sprintf(tmpbuf, " \"CPU\": \"%s\",\n", cpustring);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (sizeof(int *) == 8) {
+ grntest_osinfo = OS_WINDOWS64;
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "64BIT\n");
+ } else {
+ sprintf(tmpbuf, " \"BIT\": 64,\n");
+ }
+ } else {
+ grntest_osinfo = OS_WINDOWS32;
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "32BIT\n");
+ } else {
+ sprintf(tmpbuf, " \"BIT\": 32,\n");
+ }
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ GetSystemInfo(&sinfo);
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "CORE\t%lu\n", sinfo.dwNumberOfProcessors);
+ } else {
+ sprintf(tmpbuf, " \"CORE\": %lu,\n", sinfo.dwNumberOfProcessors);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ minfo.dwLength = sizeof(MEMORYSTATUSEX);
+ GlobalMemoryStatusEx(&minfo);
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "RAM\t%I64dMByte\n", minfo.ullTotalPhys/(1024*1024));
+ } else {
+ sprintf(tmpbuf, " \"RAM\": \"%I64dMByte\",\n", minfo.ullTotalPhys/(1024*1024));
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ GetDiskFreeSpaceEx(NULL, NULL, &dinfo, NULL);
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "HDD\t%I64dKBytes\n", dinfo.QuadPart/1024 );
+ } else {
+ sprintf(tmpbuf, " \"HDD\": \"%I64dKBytes\",\n", dinfo.QuadPart/1024 );
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osinfo);
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "Windows %ld.%ld\n",
+ osinfo.dwMajorVersion, osinfo.dwMinorVersion);
+ } else {
+ sprintf(tmpbuf, " \"OS\": \"Windows %lu.%lu\",\n", osinfo.dwMajorVersion,
+ osinfo.dwMinorVersion);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s\n", grntest_serverhost);
+ } else {
+ sprintf(tmpbuf, " \"HOST\": \"%s\",\n", grntest_serverhost);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%d\n", grntest_serverport);
+ } else {
+ sprintf(tmpbuf, " \"PORT\": \"%d\",\n", grntest_serverport);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s\"\n", grn_get_version());
+ } else {
+ sprintf(tmpbuf, " \"VERSION\": \"%s\"\n", grn_get_version());
+ }
+
+ grn_strcat(result, olen, tmpbuf);
+ if (grntest_outtype != OUT_TSV) {
+ grn_strcat(result, olen, "}");
+ }
+
+#else /* linux only */
+ FILE *fp;
+ int ret;
+ int cpunum = 0;
+ int minfo = 0;
+ int unevictable = 0;
+ int mlocked = 0;
+#define CPU_STRING_SIZE 256
+ char cpu_string[CPU_STRING_SIZE];
+ struct utsname ubuf;
+ struct statvfs vfsbuf;
+
+ if (grntest_outtype == OUT_TSV) {
+ result[0] = '\0';
+ sprintf(tmpbuf, "sctipt\t%s\n", grntest_scriptname);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, "user\t%s\n", grntest_username);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, "date\t%s\n", grntest_date);
+ grn_strcat(result, olen, tmpbuf);
+ } else {
+ grn_strcpy(result, olen, "{");
+ sprintf(tmpbuf, "\"script\": \"%s.scr\",\n", grntest_scriptname);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, " \"user\": \"%s\",\n", grntest_username);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, " \"date\": \"%s\",\n", grntest_date);
+ grn_strcat(result, olen, tmpbuf);
+ }
+
+ fp = fopen("/proc/cpuinfo", "r");
+ if (!fp) {
+ fprintf(stderr, "Cannot open cpuinfo\n");
+ exit(1);
+ }
+ while (fgets(tmpbuf, 256, fp) != NULL) {
+ tmpbuf[strlen(tmpbuf)-1] = '\0';
+ if (!strncmp(tmpbuf, "model name\t: ", 13)) {
+ grn_strcpy(cpu_string, CPU_STRING_SIZE, &tmpbuf[13]);
+ }
+ }
+ fclose(fp);
+#undef CPU_STRING_SIZE
+
+ cpunum = sysconf(_SC_NPROCESSORS_CONF);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s\n", cpu_string);
+ } else {
+ sprintf(tmpbuf, " \"CPU\": \"%s\",\n", cpu_string);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (sizeof(int *) == 8) {
+ grntest_osinfo = OS_LINUX64;
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "64BIT\n");
+ } else {
+ sprintf(tmpbuf, " \"BIT\": 64,\n");
+ }
+ } else {
+ grntest_osinfo = OS_LINUX32;
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "32BIT\n");
+ } else {
+ sprintf(tmpbuf, " \"BIT\": 32,\n");
+ }
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "CORE\t%d\n", cpunum);
+ } else {
+ sprintf(tmpbuf, " \"CORE\": %d,\n", cpunum);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ fp = fopen("/proc/meminfo", "r");
+ if (!fp) {
+ fprintf(stderr, "Cannot open meminfo\n");
+ exit(1);
+ }
+ while (fgets(tmpbuf, 256, fp) != NULL) {
+ tmpbuf[strlen(tmpbuf)-1] = '\0';
+ if (!strncmp(tmpbuf, "MemTotal:", 9)) {
+ minfo = grntest_atoi(&tmpbuf[10], &tmpbuf[10] + 40, NULL);
+ }
+ if (!strncmp(tmpbuf, "Unevictable:", 12)) {
+ unevictable = grntest_atoi(&tmpbuf[13], &tmpbuf[13] + 40, NULL);
+ }
+ if (!strncmp(tmpbuf, "Mlocked:", 8)) {
+ mlocked = grntest_atoi(&tmpbuf[9], &tmpbuf[9] + 40, NULL);
+ }
+ }
+ fclose(fp);
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%dMBytes\n", minfo/1024);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, "%dMBytes_Unevictable\n", unevictable/1024);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, "%dMBytes_Mlocked\n", mlocked/1024);
+ grn_strcat(result, olen, tmpbuf);
+ } else {
+ sprintf(tmpbuf, " \"RAM\": \"%dMBytes\",\n", minfo/1024);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, " \"Unevictable\": \"%dMBytes\",\n", unevictable/1024);
+ grn_strcat(result, olen, tmpbuf);
+ sprintf(tmpbuf, " \"Mlocked\": \"%dMBytes\",\n", mlocked/1024);
+ grn_strcat(result, olen, tmpbuf);
+ }
+
+ ret = statvfs(path, &vfsbuf);
+ if (ret) {
+ fprintf(stderr, "Cannot access %s\n", path);
+ exit(1);
+ }
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%" GRN_FMT_INT64U "KBytes\n", vfsbuf.f_blocks * 4);
+ } else {
+ sprintf(tmpbuf,
+ " \"HDD\": \"%" GRN_FMT_INT64U "KBytes\",\n",
+ vfsbuf.f_blocks * 4);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ uname(&ubuf);
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s %s\n", ubuf.sysname, ubuf.release);
+ } else {
+ sprintf(tmpbuf, " \"OS\": \"%s %s\",\n", ubuf.sysname, ubuf.release);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s\n", grntest_serverhost);
+ } else {
+ sprintf(tmpbuf, " \"HOST\": \"%s\",\n", grntest_serverhost);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%d\n", grntest_serverport);
+ } else {
+ sprintf(tmpbuf, " \"PORT\": \"%d\",\n", grntest_serverport);
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype == OUT_TSV) {
+ sprintf(tmpbuf, "%s\n", grn_get_version());
+ } else {
+ sprintf(tmpbuf, " \"VERSION\": \"%s\"\n", grn_get_version());
+ }
+ grn_strcat(result, olen, tmpbuf);
+
+ if (grntest_outtype != OUT_TSV) {
+ grn_strcat(result, olen, "},");
+ }
+#endif /* WIN32 */
+ if (strlen(result) >= olen) {
+ fprintf(stderr, "buffer overrun in get_sysinfo!\n");
+ exit(1);
+ }
+ return 0;
+}
+
+static int
+start_server(const char *dbpath, int r)
+{
+ int ret;
+ char optbuf[BUF_LEN];
+#ifdef WIN32
+ char tmpbuf[BUF_LEN];
+
+ STARTUPINFO si;
+
+ if (strlen(dbpath) > BUF_LEN - 100) {
+ fprintf(stderr, "too long dbpath!\n");
+ exit(1);
+ }
+
+ grn_strcpy(tmpbuf, BUF_LEN, groonga_path);
+ grn_strcat(tmpbuf, BUF_LEN, " -s --protocol ");
+ grn_strcat(tmpbuf, BUF_LEN, groonga_protocol);
+ grn_strcat(tmpbuf, BUF_LEN, " -p ");
+ sprintf(optbuf, "%d ", grntest_serverport);
+ grn_strcat(tmpbuf, BUF_LEN, optbuf);
+ grn_strcat(tmpbuf, BUF_LEN, dbpath);
+ memset(&si, 0, sizeof(STARTUPINFO));
+ si.cb=sizeof(STARTUPINFO);
+ ret = CreateProcess(NULL, tmpbuf, NULL, NULL, FALSE,
+ 0, NULL, NULL, &si, &grntest_pi);
+
+ if (ret == 0) {
+ fprintf(stderr, "Cannot start groonga server: <%s>: error=%lu\n",
+ groonga_path, GetLastError());
+ exit(1);
+ }
+
+#else
+ pid_t pid;
+ pid = fork();
+ if (pid < 0) {
+ fprintf(stderr, "Cannot start groonga server:Cannot fork\n");
+ exit(1);
+ }
+ sprintf(optbuf, "%d", grntest_serverport);
+ if (pid == 0) {
+ ret = execlp(groonga_path, groonga_path,
+ "-s",
+ "--protocol", groonga_protocol,
+ "-p", optbuf,
+ dbpath, (char*)NULL);
+ if (ret == -1) {
+ fprintf(stderr, "Cannot start groonga server: <%s>: errno=%d\n",
+ groonga_path, errno);
+ exit(1);
+ }
+ }
+ else {
+ grntest_server_id = pid;
+ }
+
+#endif /* WIN32 */
+
+ return 0;
+}
+
+static int
+parse_line(grn_ctx *ctx, char *buf, int start, int end, int num)
+{
+ int i, j, error_flag = 0, out_or_test = 0;
+ char tmpbuf[BUF_LEN];
+
+ grntest_job[num].concurrency = 1;
+ grntest_job[num].ntimes = 1;
+ grntest_job[num].done = 0;
+ grntest_job[num].qnum = 0;
+ grntest_job[num].max = 0LL;
+ grntest_job[num].min = 9223372036854775807LL;
+ grntest_job[num].outputlog = NULL;
+ grntest_job[num].inputlog = NULL;
+
+ strncpy(grntest_job[num].jobname, &buf[start], end - start);
+ grntest_job[num].jobname[end - start] = '\0';
+ i = start;
+ while (i < end) {
+ if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ i++;
+ continue;
+ }
+ if (!strncmp(&buf[i], "do_local", 8)) {
+ grntest_job[num].jobtype = J_DO_LOCAL;
+ i = i + 8;
+ break;
+ }
+ if (!strncmp(&buf[i], "do_gqtp", 7)) {
+ grntest_job[num].jobtype = J_DO_GQTP;
+ i = i + 7;
+ break;
+ }
+ if (!strncmp(&buf[i], "do_http", 7)) {
+ grntest_job[num].jobtype = J_DO_HTTP;
+ i = i + 7;
+ break;
+ }
+ if (!strncmp(&buf[i], "rep_local", 9)) {
+ grntest_job[num].jobtype = J_REP_LOCAL;
+ i = i + 9;
+ break;
+ }
+ if (!strncmp(&buf[i], "rep_gqtp", 8)) {
+ grntest_job[num].jobtype = J_REP_GQTP;
+ i = i + 8;
+ break;
+ }
+ if (!strncmp(&buf[i], "rep_http", 8)) {
+ grntest_job[num].jobtype = J_REP_HTTP;
+ i = i + 8;
+ break;
+ }
+ if (!strncmp(&buf[i], "out_local", 9)) {
+ grntest_job[num].jobtype = J_OUT_LOCAL;
+ i = i + 9;
+ out_or_test = 1;
+ break;
+ }
+ if (!strncmp(&buf[i], "out_gqtp", 8)) {
+ grntest_job[num].jobtype = J_OUT_GQTP;
+ i = i + 8;
+ out_or_test = 1;
+ break;
+ }
+ if (!strncmp(&buf[i], "out_http", 8)) {
+ grntest_job[num].jobtype = J_OUT_HTTP;
+ i = i + 8;
+ out_or_test = 1;
+ break;
+ }
+ if (!strncmp(&buf[i], "test_local", 10)) {
+ grntest_job[num].jobtype = J_TEST_LOCAL;
+ i = i + 10;
+ out_or_test = 1;
+ break;
+ }
+ if (!strncmp(&buf[i], "test_gqtp", 9)) {
+ grntest_job[num].jobtype = J_TEST_GQTP;
+ i = i + 9;
+ out_or_test = 1;
+ break;
+ }
+ if (!strncmp(&buf[i], "test_http", 9)) {
+ grntest_job[num].jobtype = J_TEST_HTTP;
+ i = i + 9;
+ out_or_test = 1;
+ break;
+ }
+ error_flag = 1;
+ i++;
+ }
+
+ if (error_flag) {
+ return 3;
+ }
+ if (i == end) {
+ return 1;
+ }
+
+ if (grn_isspace(&buf[i], GRN_ENC_UTF8) != 1) {
+ return 4;
+ }
+ i++;
+
+ while (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ i++;
+ continue;
+ }
+ j = 0;
+ while (i < end) {
+ if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ break;
+ }
+ grntest_job[num].commandfile[j] = buf[i];
+ i++;
+ j++;
+ if (j > 255) {
+ return 5;
+ }
+ }
+ grntest_job[num].commandfile[j] = '\0';
+
+ while (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ i++;
+ }
+
+ if (i == end) {
+ if (out_or_test) {
+ fprintf(stderr, "log(test)_local(gqtp|http) needs log(test)_filename\n");
+ return 11;
+ }
+ return 0;
+ }
+
+ j = 0;
+ while (i < end) {
+ if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ break;
+ }
+ tmpbuf[j] = buf[i];
+ i++;
+ j++;
+ if (j >= BUF_LEN) {
+ return 6;
+ }
+ }
+ tmpbuf[j] ='\0';
+ if (out_or_test) {
+ if (out_p(grntest_job[num].jobtype)) {
+ grntest_job[num].outputlog = fopen(tmpbuf, "wb");
+ if (grntest_job[num].outputlog == NULL) {
+ fprintf(stderr, "Cannot open %s\n", tmpbuf);
+ return 13;
+ }
+ } else {
+ char outlog[BUF_LEN];
+ grntest_job[num].inputlog = grn_file_reader_open(ctx, tmpbuf);
+ if (grntest_job[num].inputlog == NULL) {
+ fprintf(stderr, "Cannot open %s\n", tmpbuf);
+ return 14;
+ }
+ sprintf(outlog, "%s.diff", tmpbuf);
+ grntest_job[num].outputlog = fopen(outlog, "wb");
+ if (grntest_job[num].outputlog == NULL) {
+ fprintf(stderr, "Cannot open %s\n", outlog);
+ return 15;
+ }
+ }
+ grn_strcpy(grntest_job[num].logfile, BUF_LEN, tmpbuf);
+ return 0;
+ } else {
+ grntest_job[num].concurrency = grntest_atoi(tmpbuf, tmpbuf + j, NULL);
+ if (grntest_job[num].concurrency == 0) {
+ return 7;
+ }
+ }
+
+ while (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ i++;
+ }
+
+ if (i == end) {
+ return 0;
+ }
+
+ j = 0;
+ while (i < end) {
+ if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ break;
+ }
+ tmpbuf[j] = buf[i];
+ i++;
+ j++;
+ if (j > 16) {
+ return 8;
+ }
+ }
+ tmpbuf[j] ='\0';
+ grntest_job[num].ntimes = grntest_atoi(tmpbuf, tmpbuf + j, NULL);
+ if (grntest_job[num].ntimes == 0) {
+ return 9;
+ }
+ if (i == end) {
+ return 0;
+ }
+
+ while (i < end) {
+ if (grn_isspace(&buf[i], GRN_ENC_UTF8) == 1) {
+ i++;
+ continue;
+ }
+ return 10;
+ }
+ return 0;
+}
+
+static int
+get_jobs(grn_ctx *ctx, char *buf, int line)
+{
+ int i, len, start, end, ret;
+ int jnum = 0;
+
+ len = strlen(buf);
+ i = 0;
+ while (i < len) {
+ if ((buf[i] == '#') || (buf[i] == '\r') || (buf[i] == '\n')) {
+ buf[i] = '\0';
+ len = i;
+ break;
+ }
+ i++;
+ }
+
+ i = 0;
+ start = 0;
+ while (i < len) {
+ if (buf[i] == ';') {
+ end = i;
+ ret = parse_line(ctx, buf, start, end, jnum);
+ if (ret) {
+ if (ret > 1) {
+ fprintf(stderr, "Syntax error:line=%d:ret=%d:%s\n", line, ret, buf);
+ error_exit(ctx, 1);
+ }
+ } else {
+ jnum++;
+ }
+ start = end + 1;
+ }
+ i++;
+ }
+ end = len;
+ ret = parse_line(ctx, buf, start, end, jnum);
+ if (ret) {
+ if (ret > 1) {
+ fprintf(stderr, "Syntax error:line=%d:ret=%d:%s\n", line, ret, buf);
+ error_exit(ctx, 1);
+ }
+ } else {
+ jnum++;
+ }
+ return jnum;
+}
+
+static int
+make_task_table(grn_ctx *ctx, int jobnum)
+{
+ int i, j;
+ int tid = 0;
+ grn_obj *commands = NULL;
+
+ for (i = 0; i < jobnum; i++) {
+ if ((grntest_job[i].concurrency == 1) && (!grntest_onmemory_mode)) {
+ grntest_task[tid].file = grntest_job[i].commandfile;
+ grntest_task[tid].commands = NULL;
+ grntest_task[tid].ntimes = grntest_job[i].ntimes;
+ grntest_task[tid].jobtype = grntest_job[i].jobtype;
+ grntest_task[tid].job_id = i;
+ tid++;
+ continue;
+ }
+ for (j = 0; j < grntest_job[i].concurrency; j++) {
+ if (j == 0) {
+ grn_file_reader *reader;
+ grn_obj line;
+ GRN_TEXT_INIT(&line, 0);
+ commands = grn_obj_open(ctx, GRN_PVECTOR, 0, GRN_VOID);
+ if (!commands) {
+ fprintf(stderr, "Cannot alloc commands\n");
+ error_exit(ctx, 1);
+ }
+ reader = grn_file_reader_open(ctx, grntest_job[i].commandfile);
+ if (!reader) {
+ fprintf(stderr, "Cannot alloc commandfile:%s\n",
+ grntest_job[i].commandfile);
+ error_exit(ctx, 1);
+ }
+ while (grn_file_reader_read_line(ctx, reader, &line) == GRN_SUCCESS) {
+ grn_obj *command;
+ if (GRN_TEXT_VALUE(&line)[GRN_TEXT_LEN(&line) - 1] == '\n') {
+ grn_bulk_truncate(ctx, &line, GRN_TEXT_LEN(&line) - 1);
+ }
+ if (GRN_TEXT_LEN(&line) == 0) {
+ GRN_BULK_REWIND(&line);
+ continue;
+ }
+ GRN_TEXT_PUTC(ctx, &line, '\0');
+ if (comment_p(GRN_TEXT_VALUE(&line))) {
+ GRN_BULK_REWIND(&line);
+ continue;
+ }
+ command = grn_obj_open(ctx, GRN_BULK, 0, GRN_VOID);
+ if (!command) {
+ fprintf(stderr, "Cannot alloc command: %s: %s\n",
+ grntest_job[i].commandfile, GRN_TEXT_VALUE(&line));
+ GRN_OBJ_FIN(ctx, &line);
+ error_exit(ctx, 1);
+ }
+ GRN_TEXT_SET(ctx, command, GRN_TEXT_VALUE(&line), GRN_TEXT_LEN(&line));
+ GRN_PTR_PUT(ctx, commands, command);
+ GRN_BULK_REWIND(&line);
+ }
+ grn_file_reader_close(ctx, reader);
+ GRN_OBJ_FIN(ctx, &line);
+ }
+ grntest_task[tid].file = NULL;
+ grntest_task[tid].commands = commands;
+ grntest_task[tid].ntimes = grntest_job[i].ntimes;
+ grntest_task[tid].jobtype = grntest_job[i].jobtype;
+ grntest_task[tid].job_id = i;
+ tid++;
+ }
+ }
+ return tid;
+}
+
+/*
+static int
+print_commandlist(int task_id)
+{
+ int i;
+
+ for (i = 0; i < GRN_TEXT_LEN(grntest_task[task_id].commands); i++) {
+ grn_obj *command;
+ command = GRN_PTR_VALUE_AT(grntest_task[task_id].commands, i);
+ printf("%s\n", GRN_TEXT_VALUE(command));
+ }
+ return 0;
+}
+*/
+
+/* return num of query */
+static int
+do_jobs(grn_ctx *ctx, int jobnum, int line)
+{
+ int i, task_num, ret, qnum = 0, thread_num = 0;
+
+ for (i = 0; i < jobnum; i++) {
+/*
+printf("%d:type =%d:file=%s:con=%d:ntimes=%d\n", i, grntest_job[i].jobtype,
+ grntest_job[i].commandfile, JobTable[i].concurrency, JobTable[i].ntimes);
+
+*/
+ thread_num = thread_num + grntest_job[i].concurrency;
+ }
+
+ if (thread_num >= MAX_CON) {
+ fprintf(stderr, "Too many threads requested(MAX=64):line=%d\n", line);
+ error_exit(ctx, 1);
+ }
+
+ task_num = make_task_table(ctx, jobnum);
+ if (task_num != thread_num) {
+ fprintf(stderr, "Logical error\n");
+ error_exit(ctx, 9);
+ }
+
+ grntest_detail_on = 0;
+ for (i = 0; i < task_num; i++) {
+ grn_ctx_init(&grntest_ctx[i], 0);
+ grntest_owndb[i] = NULL;
+ if (gqtp_p(grntest_task[i].jobtype)) {
+ ret = grn_ctx_connect(&grntest_ctx[i], grntest_serverhost, grntest_serverport, 0);
+ if (ret) {
+ fprintf(stderr, "Cannot connect groonga server:host=%s:port=%d:ret=%d\n",
+ grntest_serverhost, grntest_serverport, ret);
+ error_exit(ctx, 1);
+ }
+ } else if (http_p(grntest_task[i].jobtype)) {
+ grntest_task[i].http_socket = 0;
+ GRN_TEXT_INIT(&grntest_task[i].http_response, 0);
+ if (grntest_owndb_mode) {
+ grntest_owndb[i] = grn_db_open(&grntest_ctx[i], grntest_dbpath);
+ if (grntest_owndb[i] == NULL) {
+ fprintf(stderr, "Cannot open db:%s\n", grntest_dbpath);
+ exit(1);
+ }
+ } else {
+ grntest_owndb[i] = grn_db_create(&grntest_ctx[i], NULL, NULL);
+ }
+ } else {
+ if (grntest_owndb_mode) {
+ grntest_owndb[i] = grn_db_open(&grntest_ctx[i], grntest_dbpath);
+ if (grntest_owndb[i] == NULL) {
+ fprintf(stderr, "Cannot open db:%s\n", grntest_dbpath);
+ exit(1);
+ }
+ }
+ else {
+ grn_ctx_use(&grntest_ctx[i], grntest_db);
+ }
+ }
+ if (report_p(grntest_task[i].jobtype)) {
+ grntest_detail_on++;
+ }
+ }
+ if (grntest_detail_on) {
+ if (grntest_outtype == OUT_TSV) {
+ ;
+ }
+ else {
+ fprintf(grntest_log_file, "\"detail\": [\n");
+ }
+ fflush(grntest_log_file);
+ }
+
+ thread_main(ctx, task_num);
+
+ for (i = 0; i < task_num; i++) {
+ if (grntest_owndb[i]) {
+ grn_obj_close(&grntest_ctx[i], grntest_owndb[i]);
+ }
+ if (http_p(grntest_task[i].jobtype)) {
+ GRN_OBJ_FIN(&grntest_ctx[i], &grntest_task[i].http_response);
+ }
+ grn_ctx_fin(&grntest_ctx[i]);
+ qnum = qnum + grntest_task[i].qnum;
+ }
+
+ i = 0;
+ while (i < task_num) {
+ int job_id;
+ if (grntest_task[i].commands) {
+ job_id = grntest_task[i].job_id;
+ GRN_OBJ_FIN(ctx, grntest_task[i].commands);
+ while (job_id == grntest_task[i].job_id) {
+ i++;
+ }
+ } else {
+ i++;
+ }
+ }
+ for (i = 0; i < jobnum; i++) {
+ if (grntest_job[i].outputlog) {
+ int ret;
+ ret = fclose(grntest_job[i].outputlog);
+ if (ret) {
+ fprintf(stderr, "Cannot close %s\n", grntest_job[i].logfile);
+ exit(1);
+ }
+ }
+ if (grntest_job[i].inputlog) {
+ grn_file_reader_close(ctx, grntest_job[i].inputlog);
+ }
+ }
+ return qnum;
+}
+
+/* return num of query */
+static int
+do_script(grn_ctx *ctx, const char *script_file_path)
+{
+ int n_lines = 0;
+ int n_jobs;
+ int n_queries, total_n_queries = 0;
+ grn_file_reader *script_file;
+ grn_obj line;
+
+ script_file = grn_file_reader_open(ctx, script_file_path);
+ if (script_file == NULL) {
+ fprintf(stderr, "Cannot open script file: <%s>\n", script_file_path);
+ error_exit(ctx, 1);
+ }
+
+ GRN_TEXT_INIT(&line, 0);
+ while (grn_file_reader_read_line(ctx, script_file, &line) == GRN_SUCCESS) {
+ if (grntest_sigint) {
+ break;
+ }
+ n_lines++;
+ grntest_jobdone = 0;
+ n_jobs = get_jobs(ctx, GRN_TEXT_VALUE(&line), n_lines);
+ grntest_jobnum = n_jobs;
+
+ if (n_jobs > 0) {
+ GRN_TIME_INIT(&grntest_jobs_start, 0);
+ GRN_TIME_NOW(ctx, &grntest_jobs_start);
+ if (grntest_outtype == OUT_TSV) {
+ fprintf(grntest_log_file, "jobs-start\t%s\n", GRN_TEXT_VALUE(&line));
+ } else {
+ fprintf(grntest_log_file, "{\"jobs\": \"%s\",\n", GRN_TEXT_VALUE(&line));
+ }
+ n_queries = do_jobs(ctx, n_jobs, n_lines);
+ if (grntest_outtype == OUT_TSV) {
+ fprintf(grntest_log_file, "jobs-end\t%s\n", GRN_TEXT_VALUE(&line));
+ } else {
+ fprintf(grntest_log_file, "},\n");
+ }
+ total_n_queries += n_queries;
+
+ grn_obj_close(ctx, &grntest_jobs_start);
+ }
+ if (grntest_stop_flag) {
+ fprintf(stderr, "Error:Quit\n");
+ break;
+ }
+ GRN_BULK_REWIND(&line);
+ }
+ grn_obj_unlink(ctx, &line);
+
+ grn_file_reader_close(ctx, script_file);
+
+ return total_n_queries;
+}
+
+static int
+start_local(grn_ctx *ctx, const char *dbpath)
+{
+ grntest_db = grn_db_open(ctx, dbpath);
+ if (!grntest_db) {
+ grntest_db = grn_db_create(ctx, dbpath, NULL);
+ }
+ if (!grntest_db) {
+ fprintf(stderr, "Cannot open db:%s\n", dbpath);
+ exit(1);
+ }
+ return 0;
+}
+
+static int
+check_server(grn_ctx *ctx)
+{
+ int ret, retry = 0;
+ while (1) {
+ ret = grn_ctx_connect(ctx, grntest_serverhost, grntest_serverport, 0);
+ if (ret == GRN_CONNECTION_REFUSED) {
+ grn_sleep(1);
+ retry++;
+ if (retry > 5) {
+ fprintf(stderr, "Cannot connect groonga server:host=%s:port=%d:ret=%d\n",
+ grntest_serverhost, grntest_serverport, ret);
+ return 1;
+ }
+ continue;
+ }
+ if (ret) {
+ fprintf(stderr, "Cannot connect groonga server:host=%s:port=%d:ret=%d\n",
+ grntest_serverhost, grntest_serverport, ret);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+#define MODE_LIST 1
+#define MODE_GET 2
+#define MODE_PUT 3
+#define MODE_TIME 4
+
+static int
+check_response(char *buf)
+{
+ if (buf[0] == '1') {
+ return 1;
+ }
+ if (buf[0] == '2') {
+ return 1;
+ }
+ if (buf[0] == '3') {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+read_response(socket_t socket, char *buf)
+{
+ int ret;
+ ret = recv(socket, buf, BUF_LEN - 1, 0);
+ if (ret == -1) {
+ fprintf(stderr, "recv error:3\n");
+ exit(1);
+ }
+ buf[ret] ='\0';
+#ifdef DEBUG_FTP
+ fprintf(stderr, "recv:%s", buf);
+#endif
+ return ret;
+}
+
+static int
+put_file(socket_t socket, const char *filename)
+{
+ FILE *fp;
+ int c, ret, size = 0;
+ char buf[1];
+
+ fp = fopen(filename, "rb");
+ if (!fp) {
+ fprintf(stderr, "LOCAL:no such file:%s\n", filename);
+ return 0;
+ }
+
+ while ((c = fgetc(fp)) != EOF) {
+ buf[0] = c;
+ ret = send(socket, buf, 1, 0);
+ if (ret == -1) {
+ fprintf(stderr, "send error\n");
+ exit(1);
+ }
+ size++;
+ }
+ fclose(fp);
+ return size;
+}
+
+static int
+ftp_list(socket_t data_socket)
+{
+ int ret;
+ char buf[BUF_LEN];
+
+ while (1) {
+ ret = recv(data_socket, buf, BUF_LEN - 2, 0);
+ if (ret == 0) {
+ fflush(stdout);
+ return 0;
+ }
+ buf[ret] = '\0';
+ fprintf(stdout, "%s", buf);
+ }
+
+ return 0;
+}
+
+static int
+get_file(socket_t socket, const char *filename, int size)
+{
+ FILE *fp;
+ int ret, total;
+ char buf[FTPBUF];
+
+ fp = fopen(filename, "wb");
+ if (!fp) {
+ fprintf(stderr, "Cannot open %s\n", filename);
+ return -1;
+ }
+
+ total = 0;
+ while (total != size) {
+ ret = recv(socket, buf, FTPBUF, 0);
+ if (ret == -1) {
+ fprintf(stderr, "recv error:2:ret=%d:size=%d:total\n", ret, size);
+ return -1;
+ }
+ if (ret == 0) {
+ break;
+ }
+ fwrite(buf, ret, 1, fp);
+ total = total + ret;
+ }
+
+ fclose(fp);
+ return size;
+}
+
+static int
+get_port(char *buf, char *host, int *port)
+{
+ int ret,d1,d2,d3,d4,d5,d6;
+ ret = sscanf(buf, "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)",
+ &d1, &d2, &d3, &d4, &d5, &d6);
+ if (ret != 6) {
+ fprintf(stderr, "Cannot enter passsive mode\n");
+ return 0;
+ }
+
+ *port = d5 * 256 + d6;
+ sprintf(host, "%d.%d.%d.%d", d1, d2, d3, d4);
+ return 1;
+}
+
+static char *
+get_ftp_date(char *buf)
+{
+ while (*buf !=' ') {
+ buf++;
+ if (*buf == '\0') {
+ return NULL;
+ }
+ }
+ buf++;
+
+ return buf;
+}
+
+static int
+get_size(char *buf)
+{
+ int size;
+
+ while (*buf !='(') {
+ buf++;
+ if (*buf == '\0') {
+ return 0;
+ }
+ }
+ buf++;
+ size = grntest_atoi(buf, buf + strlen(buf), NULL);
+
+ return size;
+}
+
+int
+ftp_sub(const char *user, const char *passwd, const char *host,
+ const char *filename, int mode,
+ const char *cd_dirname, char *retval)
+{
+ int size = 0;
+ int status = 0;
+ socket_t command_socket, data_socket;
+ int data_port;
+ char data_host[BUF_LEN];
+ char send_mesg[BUF_LEN];
+ char buf[BUF_LEN];
+#ifdef WIN32
+ char base[BUF_LEN];
+ char fname[BUF_LEN];
+ char ext[BUF_LEN];
+#else
+ char *base;
+#endif /* WIN32 */
+
+#ifdef WIN32
+ WSADATA ws;
+
+ WSAStartup(MAKEWORD(2,0), &ws);
+#endif /* WIN32 */
+
+ if ((filename != NULL) && (strlen(filename) >= MAX_PATH_LEN)) {
+ fprintf(stderr, "too long filename\n");
+ exit(1);
+ }
+
+ if ((cd_dirname != NULL) && (strlen(cd_dirname) >= MAX_PATH_LEN)) {
+ fprintf(stderr, "too long dirname\n");
+ exit(1);
+ }
+
+ command_socket = open_socket(host, 21);
+ if (command_socket == SOCKETERROR) {
+ return 0;
+ }
+
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ goto exit;
+ }
+
+ /* send username */
+ sprintf(send_mesg, "USER %s\r\n", user);
+ write_to_server(command_socket, send_mesg);
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ goto exit;
+ }
+
+ /* send passwd */
+ sprintf(send_mesg, "PASS %s\r\n", passwd);
+ write_to_server(command_socket, send_mesg);
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ goto exit;
+ }
+
+ /* send TYPE I */
+ sprintf(send_mesg, "TYPE I\r\n");
+ write_to_server(command_socket, send_mesg);
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ goto exit;
+ }
+
+ /* send PASV */
+ sprintf(send_mesg, "PASV\r\n");
+ write_to_server(command_socket, send_mesg);
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ goto exit;
+ }
+
+ if (!get_port(buf, data_host, &data_port)) {
+ goto exit;
+ }
+
+ data_socket = open_socket(data_host, data_port);
+ if (data_socket == SOCKETERROR) {
+ goto exit;
+ }
+
+ if (cd_dirname) {
+ sprintf(send_mesg, "CWD %s\r\n", cd_dirname);
+ write_to_server(command_socket, send_mesg);
+ }
+
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ socketclose(data_socket);
+ goto exit;
+ }
+
+#ifdef WIN32
+ _splitpath(filename, NULL, NULL, fname, ext);
+ grn_strcpy(base, BUF_LEN, fname);
+ strcat(base, ext);
+#else
+ grn_strcpy(buf, BUF_LEN, filename);
+ base = basename(buf);
+#endif /* WIN32 */
+
+ switch (mode) {
+ case MODE_LIST:
+ if (filename) {
+ sprintf(send_mesg, "LIST %s\r\n", filename);
+ } else {
+ sprintf(send_mesg, "LIST \r\n");
+ }
+ write_to_server(command_socket, send_mesg);
+ break;
+ case MODE_PUT:
+ sprintf(send_mesg, "STOR %s\r\n", base);
+ write_to_server(command_socket, send_mesg);
+ break;
+ case MODE_GET:
+ sprintf(send_mesg, "RETR %s\r\n", base);
+ write_to_server(command_socket, send_mesg);
+ break;
+ case MODE_TIME:
+ sprintf(send_mesg, "MDTM %s\r\n", base);
+ write_to_server(command_socket, send_mesg);
+ break;
+ default:
+ fprintf(stderr, "invalid mode\n");
+ socketclose(data_socket);
+ goto exit;
+ }
+
+ read_response(command_socket, buf);
+ if (!check_response(buf)) {
+ socketclose(data_socket);
+ goto exit;
+ }
+ if (!strncmp(buf, "150", 3)) {
+ size = get_size(buf);
+ }
+ if (!strncmp(buf, "213", 3)) {
+ retval[BUF_LEN-2] = '\0';
+ grn_strcpy(retval, BUF_LEN - 2, get_ftp_date(buf));
+ if (retval[BUF_LEN-2] != '\0' ) {
+ fprintf(stderr, "buffer over run in ftp\n");
+ exit(1);
+ }
+ }
+
+ switch (mode) {
+ case MODE_LIST:
+ ftp_list(data_socket);
+ break;
+ case MODE_GET:
+ if (get_file(data_socket, filename, size) == -1) {
+ socketclose(data_socket);
+ goto exit;
+ }
+ fprintf(stderr, "get:%s\n", filename);
+ break;
+ case MODE_PUT:
+ if (put_file(data_socket, filename) == -1) {
+ socketclose(data_socket);
+ goto exit;
+ }
+ fprintf(stderr, "put:%s\n", filename);
+ break;
+ default:
+ break;
+ }
+
+ socketclose(data_socket);
+ if ((mode == MODE_GET) || (mode == MODE_PUT)) {
+ read_response(command_socket, buf);
+ }
+ write_to_server(command_socket, "QUIT\n");
+ status = 1;
+exit:
+ socketclose(command_socket);
+
+#ifdef WIN32
+ WSACleanup();
+#endif
+ return status;
+}
+
+/*
+static int
+ftp_main(int argc, char **argv)
+{
+ char val[BUF_LEN];
+ val[0] = '\0';
+ ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, argv[2],
+ grntest_atoi(argv[3], argv[3] + strlen(argv[3]), NULL), argv[4], val);
+ if (val[0] != '\0') {
+ printf("val=%s\n", val);
+ }
+ return 0;
+}
+*/
+
+static int
+get_username(char *name, int maxlen)
+{
+ char *env=NULL;
+ grn_strcpy(name, maxlen, "nobody");
+#ifdef WIN32
+ env = getenv("USERNAME");
+#else
+ env = getenv("USER");
+#endif /* WIN32 */
+ if (strlen(env) > maxlen) {
+ fprintf(stderr, "too long username:%s\n", env);
+ exit(1);
+ }
+ if (env) {
+ grn_strcpy(name, maxlen, env);
+ }
+ return 0;
+}
+
+static int
+get_date(char *date, time_t *sec)
+{
+#if defined(WIN32) && !defined(__GNUC__)
+ struct tm tmbuf;
+ struct tm *tm = &tmbuf;
+ localtime_s(tm, sec);
+#else /* defined(WIN32) && !defined(__GNUC__) */
+# ifdef HAVE_LOCALTIME_R
+ struct tm result;
+ struct tm *tm = &result;
+ localtime_r(sec, tm);
+# else /* HAVE_LOCALTIME_R */
+ struct tm *tm = localtime(sec);
+# endif /* HAVE_LOCALTIME_R */
+#endif /* defined(WIN32) && !defined(__GNUC__) */
+
+#ifdef WIN32
+ strftime(date, 128, "%Y-%m-%d %H:%M:%S", tm);
+#else
+ strftime(date, 128, "%F %T", tm);
+#endif /* WIN32 */
+
+ return 1;
+}
+
+static int
+get_scriptname(const char *path, char *name, size_t name_len, const char *suffix)
+{
+ int slen = strlen(suffix);
+ int len = strlen(path);
+
+ if (len >= BUF_LEN) {
+ fprintf(stderr, "too long script name\n");
+ exit(1);
+ }
+ if (slen > len) {
+ fprintf(stderr, "too long suffux\n");
+ exit(1);
+ }
+
+ grn_strcpy(name, name_len, path);
+ if (strncmp(&name[len-slen], suffix, slen)) {
+ name[0] = '\0';
+ return 0;
+ }
+ name[len-slen] = '\0';
+ return 1;
+}
+
+#ifdef WIN32
+static int
+get_tm_from_serverdate(char *serverdate, struct tm *tm)
+{
+ int res;
+ int year, month, day, hour, minute, second;
+
+ res = sscanf(serverdate, "%4d%2d%2d%2d%2d%2d",
+ &year, &month, &day, &hour, &minute, &second);
+
+/*
+ printf("%d %d %d %d %d %d\n", year, month, day, hour, minute, second);
+*/
+
+ tm->tm_sec = second;
+ tm->tm_min = minute;
+ tm->tm_hour = hour;
+ tm->tm_mday = day;
+ tm->tm_mon = month - 1;
+ tm->tm_year = year - 1900;
+ tm->tm_isdst = -1;
+
+ return 0;
+}
+#endif /* WIN32 */
+
+
+
+static int
+sync_sub(grn_ctx *ctx, const char *filename)
+{
+ int ret;
+ char serverdate[BUF_LEN];
+#ifdef WIN32
+ struct _stat statbuf;
+#else
+ struct stat statbuf;
+#endif /* WIN32 */
+ time_t st, lt;
+ struct tm stm;
+
+ ret = ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, filename, MODE_TIME, "data",
+ serverdate);
+ if (ret == 0) {
+ fprintf(stderr, "[%s] does not exist in server\n", filename);
+ return 0;
+ }
+#ifdef WIN32
+ get_tm_from_serverdate(serverdate, &stm);
+#else
+ strptime(serverdate, "%Y%m%d %H%M%S", &stm);
+#endif /* WIN32 */
+
+ /* fixme! needs timezone info */
+ st = mktime(&stm) + 3600 * 9;
+ lt = st;
+
+#ifdef WIN32
+ ret = _stat(filename, &statbuf);
+#else
+ ret = stat(filename, &statbuf);
+#endif /* WIN32 */
+
+ if (!ret) {
+ lt = statbuf.st_mtime;
+ if (lt < st) {
+ fprintf(stderr, "newer [%s] exists in server\n", filename);
+ fflush(stderr);
+ ret = ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, filename, MODE_GET, "data",
+ NULL);
+ return ret;
+ }
+ } else {
+ fprintf(stderr, "[%s] does not exist in local\n", filename);
+ fflush(stderr);
+ ret = ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, filename, MODE_GET, "data",
+ NULL);
+ return ret;
+ }
+ return 0;
+}
+
+static int
+cache_file(grn_ctx *ctx, char **flist, char *file, int fnum)
+{
+ int i;
+
+ for (i = 0; i < fnum; i++) {
+ if (!strcmp(flist[i], file) ) {
+ return fnum;
+ }
+ }
+ flist[fnum] = GRN_STRDUP(file);
+ fnum++;
+ if (fnum >= BUF_LEN) {
+ fprintf(stderr, "too many uniq commands file!\n");
+ exit(1);
+ }
+ return fnum;
+}
+
+static int
+sync_datafile(grn_ctx *ctx, const char *script_file_path)
+{
+ int line = 0;
+ int fnum = 0;
+ int i, job_num;
+ FILE *fp;
+ char buf[BUF_LEN];
+ char *filelist[BUF_LEN];
+
+ fp = fopen(script_file_path, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "Cannot open script file: <%s>\n", script_file_path);
+ error_exit(ctx, 1);
+ }
+ buf[BUF_LEN-2] = '\0';
+ while (fgets(buf, BUF_LEN, fp) != NULL) {
+ line++;
+ if (buf[BUF_LEN-2] != '\0') {
+ fprintf(stderr, "Too long line in script file:%d\n", line);
+ error_exit(ctx, 1);
+ }
+ job_num = get_jobs(ctx, buf, line);
+
+ if (job_num > 0) {
+ for (i = 0; i < job_num; i++) {
+/*
+printf("commandfile=[%s]:buf=%s\n", grntest_job[i].commandfile, buf);
+*/
+ fnum = cache_file(ctx, filelist, grntest_job[i].commandfile, fnum);
+ }
+ }
+ }
+ for (i = 0; i < fnum; i++) {
+ if (sync_sub(ctx, filelist[i])) {
+ fprintf(stderr, "updated!:%s\n", filelist[i]);
+ fflush(stderr);
+ }
+ GRN_FREE(filelist[i]);
+ }
+ fclose(fp);
+ return fnum;
+}
+
+static int
+sync_script(grn_ctx *ctx, const char *filename)
+{
+ int ret, filenum;
+
+ ret = sync_sub(ctx, filename);
+ if (!ret) {
+ return 0;
+ }
+
+ fprintf(stderr, "updated!:%s\n", filename);
+ fflush(stderr);
+ filenum = sync_datafile(ctx, filename);
+ return 1;
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "Usage: grntest [options...] [script] [db]\n"
+ "options:\n"
+ " --dir: show script files on ftp server\n"
+ " -i, --host <ip/hostname>: server address to listen (default: %s)\n"
+ " --localonly: omit server connection\n"
+ " --log-output-dir: specify output dir (default: current)\n"
+ " --ftp: connect to ftp server\n"
+ " --onmemory: load all commands into memory\n"
+ " --output-type <tsv/json>: specify output-type (default: json)\n"
+ " --owndb: open dbs for each ctx\n"
+ " -p, --port <port number>: server port number (default: %d)\n"
+ " --groonga <groonga_path>: groonga command path (default: %s)\n"
+ " --protocol <gqtp|http>: groonga server protocol (default: %s)\n"
+ " --log-path <path>: specify log file path\n"
+ " --pid-path <path>: specify file path to store PID file\n",
+ DEFAULT_DEST, DEFAULT_PORT,
+ groonga_path, groonga_protocol);
+ exit(1);
+}
+
+enum {
+ mode_default = 0,
+ mode_list,
+ mode_usage,
+};
+
+#define MODE_MASK 0x007f
+#define MODE_FTP 0x0080
+#define MODE_LOCALONLY 0x0100
+#define MODE_OWNDB 0x0800
+#define MODE_ONMEMORY 0x1000
+
+
+static int
+get_token(char *line, char *token, int maxlen, char **next)
+{
+ int i = 0;
+
+ *next = NULL;
+ token[i] = '\0';
+
+ while (*line) {
+ if (grn_isspace(line, GRN_ENC_UTF8) == 1) {
+ line++;
+ continue;
+ }
+ if (*line == ';') {
+ token[0] = ';';
+ token[1] = '\0';
+ *next = line + 1;
+ return 1;
+ }
+ if (*line == '#') {
+ token[0] = ';';
+ token[1] = '\0';
+ *next = line + 1;
+ return 1;
+ }
+ break;
+ }
+
+ while (*line) {
+ token[i] = *line;
+ i++;
+ if (grn_isspace(line + 1, GRN_ENC_UTF8) == 1) {
+ token[i] = '\0';
+ *next = line + 1;
+ return 1;
+ }
+ if (*(line + 1) == ';') {
+ token[i] = '\0';
+ *next = line + 1;
+ return 1;
+ }
+ if (*(line + 1) == '#') {
+ token[i] = '\0';
+ *next = line + 1;
+ return 1;
+ }
+ if (*(line + 1) == '\0') {
+ token[i] = '\0';
+ return 1;
+ }
+
+ line++;
+ }
+ return 0;
+}
+
+/* SET_PORT and SET_HOST */
+static grn_bool
+check_script(grn_ctx *ctx, const char *script_file_path)
+{
+ grn_file_reader *script_file;
+ grn_obj line;
+ char token[BUF_LEN];
+ char prev[BUF_LEN];
+ char *next = NULL;
+
+ script_file = grn_file_reader_open(ctx, script_file_path);
+ if (!script_file) {
+ fprintf(stderr, "Cannot open script file: <%s>\n", script_file_path);
+ return GRN_FALSE;
+ }
+
+ GRN_TEXT_INIT(&line, 0);
+ while (grn_file_reader_read_line(ctx, script_file, &line) == GRN_SUCCESS) {
+ GRN_TEXT_VALUE(&line)[GRN_TEXT_LEN(&line) - 1] = '\0';
+ get_token(GRN_TEXT_VALUE(&line), token, BUF_LEN, &next);
+ grn_strcpy(prev, BUF_LEN, token);
+
+ while (next) {
+ get_token(next, token, BUF_LEN, &next);
+ if (!strncmp(prev, "SET_PORT", 8)) {
+ grntest_serverport = grn_atoi(token, token + strlen(token), NULL);
+ }
+ if (!strncmp(prev, "SET_HOST", 8)) {
+ grn_strcpy(grntest_serverhost, BUF_LEN, token);
+ grntest_remote_mode = 1;
+ }
+ grn_strcpy(prev, BUF_LEN, token);
+ }
+ }
+ grn_obj_unlink(ctx, &line);
+
+ grn_file_reader_close(ctx, script_file);
+ return GRN_TRUE;
+}
+
+#ifndef WIN32
+static void
+timeout(int sig)
+{
+ fprintf(stderr, "timeout:groonga server cannot shutdown!!\n");
+ fprintf(stderr, "Use \"kill -9 %d\"\n", grntest_server_id);
+ alarm(0);
+}
+
+static void
+setexit(int sig)
+{
+ grntest_sigint = 1;
+}
+
+static int
+setsigalarm(int sec)
+{
+ int ret;
+ struct sigaction sig;
+
+ alarm(sec);
+ sig.sa_handler = timeout;
+ sig.sa_flags = 0;
+ sigemptyset(&sig.sa_mask);
+ ret = sigaction(SIGALRM, &sig, NULL);
+ if (ret == -1) {
+ fprintf(stderr, "setsigalarm:errno= %d\n", errno);
+ }
+ return ret;
+}
+
+static int
+setsigint(void)
+{
+ int ret;
+ struct sigaction sig;
+
+ sig.sa_handler = setexit;
+ sig.sa_flags = 0;
+ sigemptyset(&sig.sa_mask);
+ ret = sigaction(SIGINT, &sig, NULL);
+ if (ret == -1) {
+ fprintf(stderr, "setsigint:errno= %d\n", errno);
+ }
+ return ret;
+}
+#endif /* WIN32 */
+
+int
+main(int argc, char **argv)
+{
+ int qnum, i, mode = 0;
+ int exit_code = EXIT_SUCCESS;
+ grn_ctx context;
+ char sysinfo[BUF_LEN];
+ char log_path_buffer[BUF_LEN];
+ const char *log_path = NULL;
+ const char *pid_path = NULL;
+ const char *portstr = NULL, *hoststr = NULL, *dbname = NULL, *scrname = NULL, *outdir = NULL, *outtype = NULL;
+ time_t sec;
+
+ static grn_str_getopt_opt opts[] = {
+ {'i', "host", NULL, 0, GETOPT_OP_NONE},
+ {'p', "port", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "log-output-dir", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "output-type", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "dir", NULL, mode_list, GETOPT_OP_UPDATE},
+ {'\0', "ftp", NULL, MODE_FTP, GETOPT_OP_ON},
+ {'h', "help", NULL, mode_usage, GETOPT_OP_UPDATE},
+ {'\0', "localonly", NULL, MODE_LOCALONLY, GETOPT_OP_ON},
+ {'\0', "onmemory", NULL, MODE_ONMEMORY, GETOPT_OP_ON},
+ {'\0', "owndb", NULL, MODE_OWNDB, GETOPT_OP_ON},
+ {'\0', "groonga", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "protocol", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "log-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "pid-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', NULL, NULL, 0, 0}
+ };
+
+ opts[0].arg = &hoststr;
+ opts[1].arg = &portstr;
+ opts[2].arg = &outdir;
+ opts[3].arg = &outtype;
+ opts[10].arg = &groonga_path;
+ opts[11].arg = &groonga_protocol;
+ opts[12].arg = &log_path;
+ opts[13].arg = &pid_path;
+
+ i = grn_str_getopt(argc, argv, opts, &mode);
+ if (i < 0) {
+ usage();
+ }
+
+ switch (mode & MODE_MASK) {
+ case mode_list :
+ ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, "*.scr", 1, "data",
+ NULL);
+ return 0;
+ break;
+ case mode_usage :
+ usage();
+ break;
+ default :
+ break;
+ }
+
+ if (pid_path) {
+ FILE *pid_file;
+ pid_file = fopen(pid_path, "w");
+ if (pid_file) {
+ fprintf(pid_file, "%d", grn_getpid());
+ fclose(pid_file);
+ } else {
+ fprintf(stderr,
+ "failed to open PID file: <%s>: %s\n",
+ pid_path, strerror(errno));
+ }
+ }
+
+ if (i < argc) {
+ scrname = argv[i];
+ }
+ if (i < argc - 1) {
+ dbname = argv[i+1];
+ }
+ grntest_dbpath = dbname;
+
+ if (mode & MODE_LOCALONLY) {
+ grntest_localonly_mode = 1;
+ grntest_remote_mode = 1;
+ }
+
+ if (mode & MODE_OWNDB) {
+ grntest_localonly_mode = 1;
+ grntest_remote_mode = 1;
+ grntest_owndb_mode = 1;
+ }
+
+ if (mode & MODE_ONMEMORY) {
+ grntest_onmemory_mode= 1;
+ }
+
+ if (mode & MODE_FTP) {
+ grntest_ftp_mode = GRN_TRUE;
+ }
+
+ if ((scrname == NULL) || (dbname == NULL)) {
+ usage();
+ }
+
+ grn_strcpy(grntest_serverhost, BUF_LEN, DEFAULT_DEST);
+ if (hoststr) {
+ grntest_remote_mode = 1;
+ grn_strcpy(grntest_serverhost, BUF_LEN, hoststr);
+ }
+ grntest_serverport = DEFAULT_PORT;
+ if (portstr) {
+ grntest_serverport = grn_atoi(portstr, portstr + strlen(portstr), NULL);
+ }
+
+ if (outtype && !strcmp(outtype, "tsv")) {
+ grntest_outtype = OUT_TSV;
+ }
+
+ grn_default_logger_set_path(GRN_LOG_PATH);
+
+ grn_init();
+ CRITICAL_SECTION_INIT(grntest_cs);
+
+ grn_ctx_init(&context, 0);
+ grn_ctx_init(&grntest_server_context, 0);
+ grn_db_create(&grntest_server_context, NULL, NULL);
+ grn_set_default_encoding(GRN_ENC_UTF8);
+
+ if (grntest_ftp_mode) {
+ sync_script(&context, scrname);
+ }
+ if (!check_script(&context, scrname)) {
+ exit_code = EXIT_FAILURE;
+ goto exit;
+ }
+
+ start_local(&context, dbname);
+ if (!grntest_remote_mode) {
+ start_server(dbname, 0);
+ }
+
+ if (!grntest_localonly_mode) {
+ if (check_server(&grntest_server_context)) {
+ goto exit;
+ }
+ }
+
+ get_scriptname(scrname, grntest_scriptname, BUF_LEN, ".scr");
+ get_username(grntest_username, 256);
+
+ GRN_TIME_INIT(&grntest_starttime, 0);
+ GRN_TIME_NOW(&context, &grntest_starttime);
+ sec = (time_t)(GRN_TIME_VALUE(&grntest_starttime)/1000000);
+ get_date(grntest_date, &sec);
+
+ if (!log_path) {
+ if (outdir) {
+ sprintf(log_path_buffer,
+ "%s/%s-%s-%" GRN_FMT_LLD "-%s.log", outdir, grntest_scriptname,
+ grntest_username,
+ GRN_TIME_VALUE(&grntest_starttime), grn_get_version());
+ } else {
+ sprintf(log_path_buffer,
+ "%s-%s-%" GRN_FMT_LLD "-%s.log", grntest_scriptname,
+ grntest_username,
+ GRN_TIME_VALUE(&grntest_starttime), grn_get_version());
+ }
+ log_path = log_path_buffer;
+ }
+
+ grntest_log_file = fopen(log_path, "w+b");
+ if (!grntest_log_file) {
+ fprintf(stderr, "Cannot open log file: <%s>\n", log_path);
+ goto exit;
+ }
+
+ get_sysinfo(dbname, sysinfo, BUF_LEN);
+ output_sysinfo(sysinfo);
+
+#ifndef WIN32
+ setsigint();
+#endif /* WIN32 */
+ qnum = do_script(&context, scrname);
+ output_result_final(&context, qnum);
+ fclose(grntest_log_file);
+
+ if (grntest_ftp_mode) {
+ ftp_sub(FTPUSER, FTPPASSWD, FTPSERVER, log_path, 3,
+ "report", NULL);
+ }
+ fprintf(stderr, "grntest done. logfile=%s\n", log_path);
+
+exit:
+ if (pid_path) {
+ remove(pid_path);
+ }
+
+ shutdown_server();
+#ifdef WIN32
+ if (!grntest_remote_mode) {
+ int ret;
+ ret = WaitForSingleObject(grntest_pi.hProcess, 20000);
+ if (ret == WAIT_TIMEOUT) {
+ fprintf(stderr, "timeout:groonga server cannot shutdown!!\n");
+ fprintf(stderr, "Cannot wait\n");
+ exit(1);
+ }
+ }
+#else
+ if (grntest_server_id) {
+ int ret, pstatus;
+ setsigalarm(20);
+ ret = waitpid(grntest_server_id, &pstatus, 0);
+ if (ret < 0) {
+ fprintf(stderr, "Cannot wait\n");
+ exit(1);
+ }
+/*
+ else {
+ fprintf(stderr, "pstatus = %d\n", pstatus);
+ }
+*/
+ alarm(0);
+ }
+#endif /* WIN32 */
+ CRITICAL_SECTION_FIN(grntest_cs);
+ grn_obj_close(&context, &grntest_starttime);
+ grn_obj_close(&context, grntest_db);
+ grn_ctx_fin(&context);
+ grn_obj_close(&grntest_server_context, grn_ctx_db(&grntest_server_context));
+ grn_ctx_fin(&grntest_server_context);
+ grn_fin();
+ return exit_code;
+}
diff --git a/storage/mroonga/vendor/groonga/src/groonga_benchmark_sources.am b/storage/mroonga/vendor/groonga/src/groonga_benchmark_sources.am
new file mode 100644
index 00000000..bf05fbff
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/groonga_benchmark_sources.am
@@ -0,0 +1,2 @@
+groonga_benchmark_SOURCES = \
+ groonga_benchmark.c
diff --git a/storage/mroonga/vendor/groonga/src/groonga_mruby.c b/storage/mroonga/vendor/groonga/src/groonga_mruby.c
new file mode 100644
index 00000000..3aa73aaf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/groonga_mruby.c
@@ -0,0 +1,86 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2014 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#include <grn_mrb.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+run(grn_ctx *ctx, const char *db_path, const char *ruby_script_path)
+{
+ grn_obj *db;
+
+ db = grn_db_open(ctx, db_path);
+ if (!db) {
+ if (ctx->rc == GRN_NO_SUCH_FILE_OR_DIRECTORY) {
+ db = grn_db_create(ctx, db_path, NULL);
+ if (!db) {
+ fprintf(stderr, "Failed to create database: <%s>: %s",
+ db_path, ctx->errbuf);
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "Failed to open database: <%s>: %s",
+ db_path, ctx->errbuf);
+ return EXIT_FAILURE;
+ }
+ }
+
+ grn_mrb_load(ctx, ruby_script_path);
+ if (ctx->rc != GRN_SUCCESS) {
+ fprintf(stderr, "Failed to load Ruby script: <%s>: %s",
+ ruby_script_path, ctx->errbuf);
+ }
+
+ grn_obj_close(ctx, db);
+
+ if (ctx->rc == GRN_SUCCESS) {
+ return EXIT_SUCCESS;
+ } else {
+ return EXIT_FAILURE;
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ int exit_code = EXIT_SUCCESS;
+
+ if (argc != 3) {
+ fprintf(stderr, "Usage: %s DB_PATH RUBY_SCRIPT_PATH\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ grn_default_logger_set_path(GRN_LOG_PATH);
+
+ if (grn_init() != GRN_SUCCESS) {
+ return EXIT_FAILURE;
+ }
+
+ {
+ grn_ctx ctx;
+ grn_ctx_init(&ctx, 0);
+ exit_code = run(&ctx, argv[1], argv[2]);
+ grn_ctx_fin(&ctx);
+ }
+
+ grn_fin();
+
+ return exit_code;
+}
diff --git a/storage/mroonga/vendor/groonga/src/groonga_mruby_sources.am b/storage/mroonga/vendor/groonga/src/groonga_mruby_sources.am
new file mode 100644
index 00000000..c9006755
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/groonga_mruby_sources.am
@@ -0,0 +1,2 @@
+groonga_mruby_SOURCES = \
+ groonga_mruby.c
diff --git a/storage/mroonga/vendor/groonga/src/groonga_sources.am b/storage/mroonga/vendor/groonga/src/groonga_sources.am
new file mode 100644
index 00000000..308fdc3d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/groonga_sources.am
@@ -0,0 +1,2 @@
+groonga_SOURCES = \
+ groonga.c
diff --git a/storage/mroonga/vendor/groonga/src/httpd/Makefile.am b/storage/mroonga/vendor/groonga/src/httpd/Makefile.am
new file mode 100644
index 00000000..736dd1cf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/httpd/Makefile.am
@@ -0,0 +1,32 @@
+NGINX_DIR = $(top_builddir)/vendor/nginx-$(NGINX_VERSION)
+
+EXTRA_DIST = \
+ nginx-module \
+ configure
+
+if WITH_GROONGA_HTTPD
+NGINX_MAKEILE = $(NGINX_DIR)/Makefile
+NGINX_MAKEFILE_DEPEND_FILES = \
+ configure \
+ Makefile.am \
+ $(top_builddir)/config.status \
+ $(srcdir)/nginx-module/config
+
+$(NGINX_MAKEILE): $(NGINX_MAKEFILE_DEPEND_FILES)
+ $(srcdir)/configure --srcdir="$(srcdir)" `../../config.status --config`
+
+# nginx's Makefile specify 'build' as the default rule.
+# This isn't compatible with the 'all' default rule generated by Automake
+# So, override the all rule.
+all-nginx: $(NGINX_MAKEILE)
+ (cd $(NGINX_DIR) && $(MAKE) build)
+all-local: all-nginx
+
+clean-nginx: $(NGINX_MAKEILE)
+ (cd $(NGINX_DIR) && $(MAKE) clean)
+clean-local: clean-nginx
+
+install-exec-nginx: $(NGINX_MAKEILE)
+ (cd $(NGINX_DIR) && $(MAKE) install)
+install-exec-local: install-exec-nginx
+endif
diff --git a/storage/mroonga/vendor/groonga/src/httpd/nginx-module/config b/storage/mroonga/vendor/groonga/src/httpd/nginx-module/config
new file mode 100644
index 00000000..b79eef6b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/httpd/nginx-module/config
@@ -0,0 +1,56 @@
+# -*- sh -*-
+
+groonga_strip_switch()
+{
+ # skip "-I" from "-I/usr/..."
+ tail -c +3
+}
+
+if [ "$GROONGA_HTTPD_IN_TREE" = yes ]; then
+ groonga_cflags="-I${GROONGA_HTTPD_IN_TREE_INCLUDE_PATH}"
+ groonga_cflags="${groonga_cflags} -DNGX_HTTP_GROONGA_LOG_PATH=\\\"\"${GROONGA_HTTPD_GROONGA_LOG_PATH}\"\\\""
+ groonga_cflags="${groonga_cflags} -DNGX_HTTP_GROONGA_QUERY_LOG_PATH=\\\"\"${GROONGA_HTTPD_GROONGA_QUERY_LOG_PATH}\"\\\""
+ groonga_libs="-L${GROONGA_HTTPD_IN_TREE_LINK_PATH}"
+ if [ "${GROONGA_HTTPD_WITH_ONIGMO}" = "yes" ]; then
+ groonga_libs="$groonga_libs -L${GROONGA_HTTPD_ONIGMO_IN_TREE_LINK_PATH}"
+ fi
+ groonga_libs="$groonga_libs -lgroonga"
+ if [ -n "${GROONGA_HTTPD_RPATH}" ]; then
+ groonga_libs="$groonga_libs -Wl,-rpath -Wl,${GROONGA_HTTPD_RPATH}"
+ fi
+
+ ngx_addon_name=ngx_http_groonga_module
+ HTTP_MODULES="$HTTP_MODULES ngx_http_groonga_module"
+ NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_groonga_module.c"
+ CFLAGS="$CFLAGS $groonga_cflags"
+ CORE_LIBS="$CORE_LIBS $groonga_libs"
+
+ return 0
+fi
+
+groonga_cflags="$(pkg-config --cflags groonga)"
+groonga_feature_path="$(pkg-config --cflags-only-I groonga |
+ groonga_strip_switch)"
+groonga_libs="$(pkg-config --libs groonga)"
+
+ngx_feature="groonga"
+ngx_feature_name=
+ngx_feature_run=no
+ngx_feature_incs="#include <groonga.h>"
+ngx_feature_path="$groonga_feature_path"
+ngx_feature_libs="$groonga_libs"
+ngx_feature_test="grn_get_version()"
+. auto/feature
+
+if [ $ngx_found = yes ]; then
+ ngx_addon_name=ngx_http_groonga_module
+ HTTP_MODULES="$HTTP_MODULES ngx_http_groonga_module"
+ NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_groonga_module.c"
+ CFLAGS="$CFLAGS $groonga_cflags"
+ CORE_LIBS="$CORE_LIBS $groonga_libs"
+else
+ cat << END
+$0: error: the groonga module requires the Groonga library.
+END
+ exit 1
+fi
diff --git a/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c b/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c
new file mode 100644
index 00000000..07853906
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/httpd/nginx-module/ngx_http_groonga_module.c
@@ -0,0 +1,1678 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2012-2017 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+#ifndef WIN32
+# define NGX_GRN_SUPPORT_STOP_BY_COMMAND
+#endif
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include <groonga.h>
+#include <groonga/plugin.h>
+
+#include <sys/stat.h>
+
+#ifdef NGX_GRN_SUPPORT_STOP_BY_COMMAND
+# include <sys/types.h>
+# include <unistd.h>
+#endif
+
+#define GRN_NO_FLAGS 0
+
+typedef struct {
+ ngx_flag_t enabled;
+ ngx_str_t database_path;
+ char *database_path_cstr;
+ ngx_flag_t database_auto_create;
+ ngx_str_t base_path;
+ ngx_str_t log_path;
+ ngx_open_file_t *log_file;
+ grn_log_level log_level;
+ ngx_str_t query_log_path;
+ ngx_open_file_t *query_log_file;
+ size_t cache_limit;
+ ngx_msec_t default_request_timeout_msec;
+ char *config_file;
+ int config_line;
+ char *name;
+ grn_obj *database;
+ grn_cache *cache;
+ ngx_str_t cache_base_path;
+} ngx_http_groonga_loc_conf_t;
+
+typedef struct {
+ ngx_log_t *log;
+ ngx_pool_t *pool;
+ ngx_int_t rc;
+} ngx_http_groonga_database_callback_data_t;
+
+typedef struct {
+ grn_bool initialized;
+ grn_rc rc;
+ struct {
+ grn_bool processed;
+ grn_bool header_sent;
+ ngx_http_request_t *r;
+ ngx_int_t rc;
+ ngx_chain_t *free_chain;
+ ngx_chain_t *busy_chain;
+ } raw;
+ struct {
+ grn_obj head;
+ grn_obj body;
+ grn_obj foot;
+ } typed;
+} ngx_http_groonga_handler_data_t;
+
+typedef void (*ngx_http_groonga_loc_conf_callback_pt)(ngx_http_groonga_loc_conf_t *conf, void *user_data);
+
+ngx_module_t ngx_http_groonga_module;
+
+static grn_ctx ngx_http_groonga_context;
+static grn_ctx *context = &ngx_http_groonga_context;
+static ngx_http_groonga_loc_conf_t *ngx_http_groonga_current_location_conf = NULL;
+
+static char *
+ngx_str_null_terminate(ngx_pool_t *pool, const ngx_str_t *string)
+{
+ char *null_terminated_c_string;
+
+ null_terminated_c_string = ngx_pnalloc(pool, string->len + 1);
+ if (!null_terminated_c_string) {
+ return NULL;
+ }
+
+ memcpy(null_terminated_c_string, string->data, string->len);
+ null_terminated_c_string[string->len] = '\0';
+
+ return null_terminated_c_string;
+}
+
+static grn_bool
+ngx_str_equal_c_string(ngx_str_t *string, const char *c_string)
+{
+ if (string->len != strlen(c_string)) {
+ return GRN_FALSE;
+ }
+
+ return memcmp(c_string, string->data, string->len) == 0;
+}
+
+static grn_bool
+ngx_str_is_custom_path(ngx_str_t *string)
+{
+ if (string->len == 0) {
+ return GRN_FALSE;
+ }
+
+ if (strncmp((const char *)(string->data), "off", string->len) == 0) {
+ return GRN_FALSE;
+ }
+
+ return GRN_TRUE;
+}
+
+static uint32_t
+ngx_http_groonga_get_thread_limit(void *data)
+{
+ return 1;
+}
+
+static ngx_int_t
+ngx_http_groonga_grn_rc_to_http_status(grn_rc rc)
+{
+ switch (rc) {
+ case GRN_SUCCESS :
+ return NGX_HTTP_OK;
+ case GRN_INVALID_ARGUMENT :
+ case GRN_FUNCTION_NOT_IMPLEMENTED :
+ case GRN_SYNTAX_ERROR :
+ return NGX_HTTP_BAD_REQUEST;
+ case GRN_CANCEL :
+ return NGX_HTTP_REQUEST_TIME_OUT;
+ default :
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+}
+
+static void
+ngx_http_groonga_write_fd(ngx_fd_t fd,
+ u_char *buffer, size_t buffer_size,
+ const char *message, size_t message_size)
+{
+ size_t rest_message_size = message_size;
+ const char *current_message = message;
+
+ while (rest_message_size > 0) {
+ size_t current_message_size;
+
+ if (rest_message_size > NGX_MAX_ERROR_STR) {
+ current_message_size = NGX_MAX_ERROR_STR;
+ } else {
+ current_message_size = rest_message_size;
+ }
+
+ grn_memcpy(buffer, current_message, current_message_size);
+ ngx_write_fd(fd, buffer, current_message_size);
+ rest_message_size -= current_message_size;
+ current_message += current_message_size;
+ }
+}
+
+static void
+ngx_http_groonga_logger_log(grn_ctx *ctx, grn_log_level level,
+ const char *timestamp, const char *title,
+ const char *message, const char *location,
+ void *user_data)
+{
+ ngx_open_file_t *file = user_data;
+ char level_marks[] = " EACewnid-";
+ u_char buffer[NGX_MAX_ERROR_STR];
+
+ if (!file) {
+ return;
+ }
+
+ ngx_http_groonga_write_fd(file->fd,
+ buffer, NGX_MAX_ERROR_STR,
+ timestamp, strlen(timestamp));
+ ngx_write_fd(file->fd, "|", 1);
+ ngx_write_fd(file->fd, level_marks + level, 1);
+ ngx_write_fd(file->fd, "|", 1);
+ if (location && *location) {
+ ngx_http_groonga_write_fd(file->fd,
+ buffer, NGX_MAX_ERROR_STR,
+ location, strlen(location));
+ ngx_write_fd(file->fd, ": ", 2);
+ if (title && *title) {
+ ngx_http_groonga_write_fd(file->fd,
+ buffer, NGX_MAX_ERROR_STR,
+ title, strlen(title));
+ ngx_write_fd(file->fd, " ", 1);
+ }
+ } else {
+ ngx_http_groonga_write_fd(file->fd,
+ buffer, NGX_MAX_ERROR_STR,
+ title, strlen(title));
+ ngx_write_fd(file->fd, " ", 1);
+ }
+ ngx_http_groonga_write_fd(file->fd,
+ buffer, NGX_MAX_ERROR_STR,
+ message, strlen(message));
+ ngx_write_fd(file->fd, "\n", 1);
+}
+
+static void
+ngx_http_groonga_logger_reopen(grn_ctx *ctx, void *user_data)
+{
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "log will be closed.");
+ ngx_reopen_files((ngx_cycle_t *)ngx_cycle, -1);
+ GRN_LOG(ctx, GRN_LOG_NOTICE, "log opened.");
+}
+
+static void
+ngx_http_groonga_logger_fin(grn_ctx *ctx, void *user_data)
+{
+}
+
+static grn_logger ngx_http_groonga_logger = {
+ GRN_LOG_DEFAULT_LEVEL,
+ GRN_LOG_TIME | GRN_LOG_MESSAGE | GRN_LOG_PID,
+ NULL,
+ ngx_http_groonga_logger_log,
+ ngx_http_groonga_logger_reopen,
+ ngx_http_groonga_logger_fin
+};
+
+static ngx_int_t
+ngx_http_groonga_context_init_logger(ngx_http_groonga_loc_conf_t *location_conf,
+ ngx_pool_t *pool,
+ ngx_log_t *log)
+{
+ if (ngx_http_groonga_current_location_conf) {
+ ngx_http_groonga_current_location_conf->log_level =
+ grn_logger_get_max_level(context);
+ }
+
+ ngx_http_groonga_logger.max_level = location_conf->log_level;
+ ngx_http_groonga_logger.user_data = location_conf->log_file;
+ grn_logger_set(context, &ngx_http_groonga_logger);
+
+ return NGX_OK;
+}
+
+static void
+ngx_http_groonga_query_logger_log(grn_ctx *ctx, unsigned int flag,
+ const char *timestamp, const char *info,
+ const char *message, void *user_data)
+{
+ ngx_open_file_t *file = user_data;
+ u_char buffer[NGX_MAX_ERROR_STR];
+ u_char *last;
+
+ if (!file) {
+ return;
+ }
+
+ last = ngx_slprintf(buffer, buffer + NGX_MAX_ERROR_STR,
+ "%s|%s%s\n",
+ timestamp, info, message);
+ ngx_write_fd(file->fd, buffer, last - buffer);
+}
+
+static void
+ngx_http_groonga_query_logger_reopen(grn_ctx *ctx, void *user_data)
+{
+ ngx_reopen_files((ngx_cycle_t *)ngx_cycle, -1);
+}
+
+static void
+ngx_http_groonga_query_logger_fin(grn_ctx *ctx, void *user_data)
+{
+}
+
+static grn_query_logger ngx_http_groonga_query_logger = {
+ GRN_QUERY_LOG_DEFAULT,
+ NULL,
+ ngx_http_groonga_query_logger_log,
+ ngx_http_groonga_query_logger_reopen,
+ ngx_http_groonga_query_logger_fin
+};
+
+static ngx_int_t
+ngx_http_groonga_context_init_query_logger(ngx_http_groonga_loc_conf_t *location_conf,
+ ngx_pool_t *pool,
+ ngx_log_t *log)
+{
+ ngx_http_groonga_query_logger.user_data = location_conf->query_log_file;
+ grn_query_logger_set(context, &ngx_http_groonga_query_logger);
+
+ return NGX_OK;
+}
+
+static ngx_int_t
+ngx_http_groonga_context_init(ngx_http_groonga_loc_conf_t *location_conf,
+ ngx_pool_t *pool,
+ ngx_log_t *log)
+{
+ ngx_int_t status;
+
+ if (location_conf == ngx_http_groonga_current_location_conf) {
+ return NGX_OK;
+ }
+
+ status = ngx_http_groonga_context_init_logger(location_conf,
+ pool,
+ log);
+ if (status == NGX_ERROR) {
+ return status;
+ }
+
+ status = ngx_http_groonga_context_init_query_logger(location_conf,
+ pool,
+ log);
+ if (status == NGX_ERROR) {
+ return status;
+ }
+
+ grn_ctx_use(context, location_conf->database);
+ grn_cache_current_set(context, location_conf->cache);
+
+ /* TODO: It doesn't work yet. We need to implement request timeout
+ * handler. */
+ if (location_conf->default_request_timeout_msec == NGX_CONF_UNSET_MSEC) {
+ grn_set_default_request_timeout(0.0);
+ } else {
+ double timeout;
+ timeout = location_conf->default_request_timeout_msec / 1000.0;
+ grn_set_default_request_timeout(timeout);
+ }
+
+ ngx_http_groonga_current_location_conf = location_conf;
+
+ return status;
+}
+
+static void
+ngx_http_groonga_context_log_error(ngx_log_t *log)
+{
+ if (context->rc == GRN_SUCCESS) {
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_ERR, log, 0, "%s", context->errbuf);
+}
+
+static ngx_int_t
+ngx_http_groonga_context_check_error(ngx_log_t *log)
+{
+ if (context->rc == GRN_SUCCESS) {
+ return NGX_OK;
+ } else {
+ ngx_http_groonga_context_log_error(log);
+ return NGX_HTTP_BAD_REQUEST;
+ }
+}
+
+static ngx_buf_t *
+ngx_http_groonga_grn_obj_to_ngx_buf(ngx_pool_t *pool, grn_obj *object)
+{
+ ngx_buf_t *buffer;
+ buffer = ngx_pcalloc(pool, sizeof(ngx_buf_t));
+ if (buffer == NULL) {
+ return NULL;
+ }
+
+ /* adjust the pointers of the buffer */
+ buffer->pos = (u_char *)GRN_TEXT_VALUE(object);
+ buffer->last = (u_char *)GRN_TEXT_VALUE(object) + GRN_TEXT_LEN(object);
+ buffer->memory = 1; /* this buffer is in memory */
+ buffer->in_file = 0;
+
+ return buffer;
+}
+
+static void
+ngx_http_groonga_handler_cleanup(void *user_data)
+{
+ ngx_http_groonga_handler_data_t *data = user_data;
+
+ if (!data->initialized) {
+ return;
+ }
+
+ GRN_OBJ_FIN(context, &(data->typed.head));
+ GRN_OBJ_FIN(context, &(data->typed.body));
+ GRN_OBJ_FIN(context, &(data->typed.foot));
+}
+
+static void
+ngx_http_groonga_handler_set_content_type(ngx_http_request_t *r,
+ const char *content_type)
+{
+ r->headers_out.content_type.len = strlen(content_type);
+ r->headers_out.content_type.data = (u_char *)content_type;
+ r->headers_out.content_type_len = r->headers_out.content_type.len;
+}
+
+static void
+ngx_http_groonga_context_receive_handler_raw(grn_ctx *context,
+ int flags,
+ ngx_http_groonga_handler_data_t *data)
+{
+ char *chunk = NULL;
+ unsigned int chunk_size = 0;
+ int recv_flags;
+ ngx_http_request_t *r;
+ ngx_log_t *log;
+ grn_bool is_last_chunk;
+
+ grn_ctx_recv(context, &chunk, &chunk_size, &recv_flags);
+ data->raw.processed = GRN_TRUE;
+
+ if (data->raw.rc != NGX_OK) {
+ return;
+ }
+
+ r = data->raw.r;
+ log = r->connection->log;
+ is_last_chunk = (flags & GRN_CTX_TAIL);
+
+ if (!data->raw.header_sent) {
+ ngx_http_groonga_handler_set_content_type(r, grn_ctx_get_mime_type(context));
+ r->headers_out.status = NGX_HTTP_OK;
+ if (is_last_chunk) {
+ r->headers_out.content_length_n = chunk_size;
+ if (chunk_size == 0) {
+ r->header_only = 1;
+ }
+ } else {
+ r->headers_out.content_length_n = -1;
+ }
+ data->raw.rc = ngx_http_send_header(r);
+ data->raw.header_sent = GRN_TRUE;
+
+ if (data->raw.rc != NGX_OK) {
+ return;
+ }
+ }
+
+ if (chunk_size > 0 || is_last_chunk) {
+ ngx_chain_t *chain;
+
+ chain = ngx_chain_get_free_buf(r->pool, &(data->raw.free_chain));
+ if (!chain) {
+ ngx_log_error(NGX_LOG_ERR, log, 0,
+ "http_groonga: failed to allocate memory for chunked body");
+ data->raw.rc = NGX_ERROR;
+ return;
+ }
+ if (chunk_size == 0) {
+ chain->buf->pos = NULL;
+ chain->buf->last = NULL;
+ chain->buf->memory = 0;
+ } else {
+ chain->buf->pos = (u_char *)chunk;
+ chain->buf->last = (u_char *)chunk + chunk_size;
+ chain->buf->memory = 1;
+ }
+ chain->buf->tag = (ngx_buf_tag_t)&ngx_http_groonga_module;
+ chain->buf->flush = 1;
+ chain->buf->temporary = 0;
+ chain->buf->in_file = 0;
+ if (is_last_chunk) {
+ chain->buf->last_buf = 1;
+ } else {
+ chain->buf->last_buf = 0;
+ }
+ chain->next = NULL;
+
+ data->raw.rc = ngx_http_output_filter(r, chain);
+ ngx_chain_update_chains(r->pool,
+ &(data->raw.free_chain),
+ &(data->raw.busy_chain),
+ &chain,
+ (ngx_buf_tag_t)&ngx_http_groonga_module);
+ }
+}
+
+static void
+ngx_http_groonga_context_receive_handler_typed(grn_ctx *context,
+ int flags,
+ ngx_http_groonga_handler_data_t *data)
+{
+ char *result = NULL;
+ unsigned int result_size = 0;
+ int recv_flags;
+
+ if (!(flags & GRN_CTX_TAIL)) {
+ return;
+ }
+
+ grn_ctx_recv(context, &result, &result_size, &recv_flags);
+
+#ifdef NGX_GRN_SUPPORT_STOP_BY_COMMAND
+ if (recv_flags == GRN_CTX_QUIT) {
+ ngx_int_t ngx_rc;
+ ngx_int_t ngx_pid;
+
+ if (ngx_process == NGX_PROCESS_SINGLE) {
+ ngx_pid = getpid();
+ } else {
+ ngx_pid = getppid();
+ }
+
+ ngx_rc = ngx_os_signal_process((ngx_cycle_t *)ngx_cycle,
+ "quit",
+ ngx_pid);
+ if (ngx_rc == NGX_OK) {
+ context->stat &= ~GRN_CTX_QUIT;
+ grn_ctx_recv(context, &result, &result_size, &recv_flags);
+ context->stat |= GRN_CTX_QUIT;
+ } else {
+ context->rc = GRN_OPERATION_NOT_PERMITTED;
+ result = "false";
+ result_size = strlen(result);
+ context->stat &= ~GRN_CTX_QUIT;
+ }
+ }
+#endif
+
+ if (result_size > 0 ||
+ GRN_TEXT_LEN(&(data->typed.body)) > 0 ||
+ context->rc != GRN_SUCCESS) {
+ if (result_size > 0) {
+ GRN_TEXT_PUT(context, &(data->typed.body), result, result_size);
+ }
+
+ grn_output_envelope(context,
+ context->rc,
+ &(data->typed.head),
+ &(data->typed.body),
+ &(data->typed.foot),
+ NULL,
+ 0);
+ }
+}
+
+static void
+ngx_http_groonga_context_receive_handler(grn_ctx *context,
+ int flags,
+ void *callback_data)
+{
+ ngx_http_groonga_handler_data_t *data = callback_data;
+
+ switch (grn_ctx_get_output_type(context)) {
+ case GRN_CONTENT_GROONGA_COMMAND_LIST :
+ case GRN_CONTENT_NONE :
+ ngx_http_groonga_context_receive_handler_raw(context, flags, data);
+ break;
+ default :
+ ngx_http_groonga_context_receive_handler_typed(context, flags, data);
+ break;
+ }
+}
+
+static ngx_int_t
+ngx_http_groonga_extract_command_path(ngx_http_request_t *r,
+ ngx_str_t *command_path)
+{
+ size_t base_path_length;
+
+ ngx_http_core_loc_conf_t *http_location_conf;
+ ngx_http_groonga_loc_conf_t *location_conf;
+
+ http_location_conf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+ location_conf = ngx_http_get_module_loc_conf(r, ngx_http_groonga_module);
+
+ command_path->data = r->unparsed_uri.data;
+ command_path->len = r->unparsed_uri.len;
+ base_path_length = http_location_conf->name.len;
+ if (location_conf->base_path.len > 0) {
+ if (command_path->len < location_conf->base_path.len) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "requested URI is shorter than groonga_base_path: "
+ "URI: <%V>, groonga_base_path: <%V>",
+ &(r->unparsed_uri), &(location_conf->base_path));
+ } else if (strncmp((const char *)command_path->data,
+ (const char *)(location_conf->base_path.data),
+ location_conf->base_path.len) < 0) {
+ ngx_log_error(NGX_LOG_WARN, r->connection->log, 0,
+ "groonga_base_path doesn't match requested URI: "
+ "URI: <%V>, groonga_base_path: <%V>",
+ &(r->unparsed_uri), &(location_conf->base_path));
+ } else {
+ base_path_length = location_conf->base_path.len;
+ }
+ }
+ command_path->data += base_path_length;
+ command_path->len -= base_path_length;
+ if (command_path->len > 0 && command_path->data[0] == '/') {
+ command_path->data += 1;
+ command_path->len -= 1;
+ }
+ if (command_path->len == 0) {
+ return NGX_HTTP_BAD_REQUEST;
+ }
+
+ return NGX_OK;
+}
+
+static ngx_int_t
+ngx_http_groonga_handler_create_data(ngx_http_request_t *r,
+ ngx_http_groonga_handler_data_t **data_return)
+{
+ ngx_int_t rc;
+
+ ngx_http_groonga_loc_conf_t *location_conf;
+
+ ngx_http_cleanup_t *cleanup;
+ ngx_http_groonga_handler_data_t *data;
+
+ location_conf = ngx_http_get_module_loc_conf(r, ngx_http_groonga_module);
+
+ rc = ngx_http_groonga_context_init(location_conf, r->pool, r->connection->log);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ cleanup = ngx_http_cleanup_add(r, sizeof(ngx_http_groonga_handler_data_t));
+ cleanup->handler = ngx_http_groonga_handler_cleanup;
+ data = cleanup->data;
+ *data_return = data;
+
+ data->initialized = GRN_TRUE;
+ data->rc = GRN_SUCCESS;
+
+ data->raw.processed = GRN_FALSE;
+ data->raw.header_sent = GRN_FALSE;
+ data->raw.r = r;
+ data->raw.rc = NGX_OK;
+ data->raw.free_chain = NULL;
+ data->raw.busy_chain = NULL;
+
+ GRN_TEXT_INIT(&(data->typed.head), GRN_NO_FLAGS);
+ GRN_TEXT_INIT(&(data->typed.body), GRN_NO_FLAGS);
+ GRN_TEXT_INIT(&(data->typed.foot), GRN_NO_FLAGS);
+
+ grn_ctx_use(context, location_conf->database);
+ rc = ngx_http_groonga_context_check_error(r->connection->log);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ grn_ctx_recv_handler_set(context,
+ ngx_http_groonga_context_receive_handler,
+ data);
+
+ return NGX_OK;
+}
+
+static void
+ngx_http_groonga_handler_process_command_path(ngx_http_request_t *r,
+ ngx_str_t *command_path,
+ ngx_http_groonga_handler_data_t *data,
+ int flags)
+{
+ grn_obj uri;
+
+ GRN_TEXT_INIT(&uri, 0);
+ GRN_TEXT_PUTS(context, &uri, "/d/");
+ GRN_TEXT_PUT(context, &uri, command_path->data, command_path->len);
+ grn_ctx_send(context, GRN_TEXT_VALUE(&uri), GRN_TEXT_LEN(&uri), flags);
+ data->rc = context->rc;
+ ngx_http_groonga_context_log_error(r->connection->log);
+ GRN_OBJ_FIN(context, &uri);
+}
+
+static grn_bool
+ngx_http_groonga_handler_validate_post_command(ngx_http_request_t *r,
+ ngx_str_t *command_path,
+ ngx_http_groonga_handler_data_t *data)
+{
+ ngx_str_t command;
+
+ command.data = command_path->data;
+ if (r->args.len == 0) {
+ command.len = command_path->len;
+ } else {
+ command.len = command_path->len - r->args.len - strlen("?");
+ }
+ if (ngx_str_equal_c_string(&command, "load")) {
+ return GRN_TRUE;
+ }
+
+ data->rc = GRN_INVALID_ARGUMENT;
+ ngx_http_groonga_handler_set_content_type(r, "text/plain");
+ GRN_TEXT_PUTS(context, &(data->typed.body),
+ "command for POST must be <load>: <");
+ GRN_TEXT_PUT(context, &(data->typed.body), command.data, command.len);
+ GRN_TEXT_PUTS(context, &(data->typed.body), ">");
+
+ return GRN_FALSE;
+}
+
+static void
+ngx_http_groonga_send_body(ngx_http_request_t *r,
+ ngx_http_groonga_handler_data_t *data)
+{
+ ngx_log_t *log;
+ grn_obj line_buffer;
+ size_t line_start_offset;
+ size_t line_check_start_offset;
+ ngx_chain_t *chain;
+ size_t line_buffer_chunk_size = 4096;
+
+ log = r->connection->log;
+
+ GRN_TEXT_INIT(&line_buffer, 0);
+ line_start_offset = 0;
+ line_check_start_offset = 0;
+ for (chain = r->request_body->bufs; chain; chain = chain->next) {
+ ngx_buf_t *buffer;
+ size_t rest_buffer_size;
+ off_t offset;
+
+ buffer = chain->buf;
+ rest_buffer_size = ngx_buf_size(buffer);
+ offset = 0;
+ while (rest_buffer_size > 0) {
+ size_t current_buffer_size;
+
+ if (rest_buffer_size > line_buffer_chunk_size) {
+ current_buffer_size = line_buffer_chunk_size;
+ } else {
+ current_buffer_size = rest_buffer_size;
+ }
+
+ if (ngx_buf_in_memory(buffer)) {
+ GRN_TEXT_PUT(context,
+ &line_buffer,
+ buffer->pos + offset,
+ current_buffer_size);
+ } else {
+ ngx_int_t rc;
+ grn_bulk_reserve(context, &line_buffer, current_buffer_size);
+ rc = ngx_read_file(buffer->file,
+ (u_char *)GRN_BULK_CURR(&line_buffer),
+ current_buffer_size,
+ offset);
+ if (rc < 0) {
+ GRN_PLUGIN_ERROR(context,
+ GRN_INPUT_OUTPUT_ERROR,
+ "[nginx][post][body][read] "
+ "failed to read a request body from file");
+ goto exit;
+ }
+ GRN_BULK_INCR_LEN(&line_buffer, current_buffer_size);
+ }
+ offset += current_buffer_size;
+ rest_buffer_size -= current_buffer_size;
+
+ {
+ const char *line_start;
+ const char *line_current;
+ const char *line_end;
+
+ line_start = GRN_TEXT_VALUE(&line_buffer) + line_start_offset;
+ line_end = GRN_TEXT_VALUE(&line_buffer) + GRN_TEXT_LEN(&line_buffer);
+ for (line_current = line_start + line_check_start_offset;
+ line_current < line_end;
+ line_current++) {
+ size_t line_length;
+ int flags = GRN_NO_FLAGS;
+
+ if (*line_current != '\n') {
+ continue;
+ }
+
+ line_length = line_current - line_start + 1;
+ if (line_current + 1 == line_end &&
+ !chain->next &&
+ rest_buffer_size == 0) {
+ flags |= GRN_CTX_TAIL;
+ }
+ grn_ctx_send(context, line_start, line_length, flags);
+ line_start_offset += line_length;
+ line_start += line_length;
+ ngx_http_groonga_context_log_error(log);
+ if (context->rc != GRN_SUCCESS && data->rc == GRN_SUCCESS) {
+ data->rc = context->rc;
+ }
+ }
+
+ if (line_start_offset == 0) {
+ line_buffer_chunk_size *= 2;
+ line_check_start_offset = GRN_TEXT_LEN(&line_buffer);
+ } else if ((size_t)GRN_TEXT_LEN(&line_buffer) == line_start_offset) {
+ GRN_BULK_REWIND(&line_buffer);
+ line_start_offset = 0;
+ line_check_start_offset = 0;
+ } else {
+ size_t rest_line_size;
+ rest_line_size = GRN_TEXT_LEN(&line_buffer) - line_start_offset;
+ grn_memmove(GRN_TEXT_VALUE(&line_buffer),
+ GRN_TEXT_VALUE(&line_buffer) + line_start_offset,
+ rest_line_size);
+ grn_bulk_truncate(context, &line_buffer, rest_line_size);
+ line_start_offset = 0;
+ line_check_start_offset = GRN_TEXT_LEN(&line_buffer);
+ }
+ }
+ }
+ }
+
+ if (GRN_TEXT_LEN(&line_buffer) > 0) {
+ grn_ctx_send(context,
+ GRN_TEXT_VALUE(&line_buffer),
+ GRN_TEXT_LEN(&line_buffer),
+ GRN_CTX_TAIL);
+ ngx_http_groonga_context_log_error(log);
+ if (context->rc != GRN_SUCCESS && data->rc == GRN_SUCCESS) {
+ data->rc = context->rc;
+ }
+ }
+
+exit :
+ GRN_OBJ_FIN(context, &line_buffer);
+}
+
+static void
+ngx_http_groonga_handler_process_body(ngx_http_request_t *r,
+ ngx_http_groonga_handler_data_t *data)
+{
+ ngx_buf_t *body;
+
+ body = r->request_body->bufs->buf;
+ if (!body) {
+ data->rc = GRN_INVALID_ARGUMENT;
+ ngx_http_groonga_handler_set_content_type(r, "text/plain");
+ GRN_TEXT_PUTS(context, &(data->typed.body), "must send load data as body");
+ return;
+ }
+
+ ngx_http_groonga_send_body(r, data);
+}
+
+
+static void
+ngx_http_groonga_handler_process_load(ngx_http_request_t *r,
+ ngx_str_t *command_path,
+ ngx_http_groonga_handler_data_t *data)
+{
+ if (!ngx_http_groonga_handler_validate_post_command(r, command_path, data)) {
+ return;
+ }
+
+ ngx_http_groonga_handler_process_command_path(r,
+ command_path,
+ data,
+ GRN_NO_FLAGS);
+ if (data->rc != GRN_SUCCESS) {
+ return;
+ }
+
+ ngx_http_groonga_handler_process_body(r, data);
+}
+
+static ngx_chain_t *
+ngx_http_groonga_attach_chain(ngx_chain_t *chain, ngx_chain_t *new_chain)
+{
+ ngx_chain_t *last_chain;
+
+ if (new_chain->buf->last == new_chain->buf->pos) {
+ return chain;
+ }
+
+ new_chain->buf->last_buf = 1;
+ new_chain->next = NULL;
+ if (!chain) {
+ return new_chain;
+ }
+
+ chain->buf->last_buf = 0;
+ last_chain = chain;
+ while (last_chain->next) {
+ last_chain = last_chain->next;
+ }
+ last_chain->next = new_chain;
+ return chain;
+}
+
+static ngx_int_t
+ngx_http_groonga_handler_send_response(ngx_http_request_t *r,
+ ngx_http_groonga_handler_data_t *data)
+{
+ ngx_int_t rc;
+ const char *content_type;
+ ngx_buf_t *head_buf, *body_buf, *foot_buf;
+ ngx_chain_t head_chain, body_chain, foot_chain;
+ ngx_chain_t *output_chain = NULL;
+
+ if (data->raw.processed) {
+ return data->raw.rc;
+ }
+
+ /* set the 'Content-type' header */
+ if (r->headers_out.content_type.len == 0) {
+ grn_obj *foot = &(data->typed.foot);
+ if (grn_ctx_get_output_type(context) == GRN_CONTENT_JSON &&
+ GRN_TEXT_LEN(foot) > 0 &&
+ GRN_TEXT_VALUE(foot)[GRN_TEXT_LEN(foot) - 1] == ';') {
+ content_type = "application/javascript";
+ } else {
+ content_type = grn_ctx_get_mime_type(context);
+ }
+ ngx_http_groonga_handler_set_content_type(r, content_type);
+ }
+
+ /* allocate buffers for a response body */
+ head_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.head));
+ if (!head_buf) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ body_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.body));
+ if (!body_buf) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ foot_buf = ngx_http_groonga_grn_obj_to_ngx_buf(r->pool, &(data->typed.foot));
+ if (!foot_buf) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* attach buffers to the buffer chain */
+ head_chain.buf = head_buf;
+ output_chain = ngx_http_groonga_attach_chain(output_chain, &head_chain);
+ body_chain.buf = body_buf;
+ output_chain = ngx_http_groonga_attach_chain(output_chain, &body_chain);
+ foot_chain.buf = foot_buf;
+ output_chain = ngx_http_groonga_attach_chain(output_chain, &foot_chain);
+
+ /* set the status line */
+ r->headers_out.status = ngx_http_groonga_grn_rc_to_http_status(data->rc);
+ r->headers_out.content_length_n = GRN_TEXT_LEN(&(data->typed.head)) +
+ GRN_TEXT_LEN(&(data->typed.body)) +
+ GRN_TEXT_LEN(&(data->typed.foot));
+ if (r->headers_out.content_length_n == 0) {
+ r->header_only = 1;
+ }
+
+ /* send the headers of your response */
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+
+ /* send the buffer chain of your response */
+ rc = ngx_http_output_filter(r, output_chain);
+
+ return rc;
+}
+
+static ngx_int_t
+ngx_http_groonga_handler_get(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_str_t command_path;
+ ngx_http_groonga_handler_data_t *data;
+
+ rc = ngx_http_groonga_extract_command_path(r, &command_path);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ rc = ngx_http_groonga_handler_create_data(r, &data);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ ngx_http_groonga_handler_process_command_path(r,
+ &command_path,
+ data,
+ GRN_CTX_TAIL);
+
+ /* discard request body, since we don't need it here */
+ rc = ngx_http_discard_request_body(r);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ rc = ngx_http_groonga_handler_send_response(r, data);
+
+ return rc;
+}
+
+static void
+ngx_http_groonga_handler_post_send_error_response(ngx_http_request_t *r,
+ ngx_int_t rc)
+{
+ r->headers_out.status = rc;
+ r->headers_out.content_length_n = 0;
+ r->header_only = 1;
+ rc = ngx_http_send_header(r);
+ ngx_http_finalize_request(r, rc);
+}
+
+static void
+ngx_http_groonga_handler_post(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_str_t command_path;
+ ngx_http_groonga_handler_data_t *data = NULL;
+
+ rc = ngx_http_groonga_extract_command_path(r, &command_path);
+ if (rc != NGX_OK) {
+ ngx_http_groonga_handler_post_send_error_response(r, rc);
+ return;
+ }
+
+ rc = ngx_http_groonga_handler_create_data(r, &data);
+ if (rc != NGX_OK) {
+ ngx_http_groonga_handler_post_send_error_response(r, rc);
+ return;
+ }
+
+ ngx_http_groonga_handler_process_load(r, &command_path, data);
+ rc = ngx_http_groonga_handler_send_response(r, data);
+ ngx_http_finalize_request(r, rc);
+}
+
+static ngx_int_t
+ngx_http_groonga_handler(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+
+ switch (r->method) {
+ case NGX_HTTP_GET:
+ case NGX_HTTP_HEAD:
+ rc = ngx_http_groonga_handler_get(r);
+ break;
+ case NGX_HTTP_POST:
+ rc = ngx_http_read_client_request_body(r, ngx_http_groonga_handler_post);
+ if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
+ rc = NGX_DONE;
+ }
+ break;
+ default:
+ rc = NGX_HTTP_NOT_ALLOWED;
+ break;
+ }
+
+ return rc;
+}
+
+static char *
+ngx_http_groonga_conf_set_groonga_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ char *status;
+ ngx_http_core_loc_conf_t *location_conf;
+ ngx_http_groonga_loc_conf_t *groonga_location_conf = conf;
+
+ status = ngx_conf_set_flag_slot(cf, cmd, conf);
+ if (status != NGX_CONF_OK) {
+ return status;
+ }
+
+ location_conf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
+ if (groonga_location_conf->enabled) {
+ location_conf->handler = ngx_http_groonga_handler;
+ groonga_location_conf->name =
+ ngx_str_null_terminate(cf->pool, &(location_conf->name));
+ groonga_location_conf->config_file =
+ ngx_str_null_terminate(cf->pool, &(cf->conf_file->file.name));
+ groonga_location_conf->config_line = cf->conf_file->line;
+ } else {
+ location_conf->handler = NULL;
+ }
+
+ return NGX_CONF_OK;
+}
+
+static char *
+ngx_http_groonga_conf_set_log_path_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ char *status;
+ ngx_http_groonga_loc_conf_t *groonga_location_conf = conf;
+
+ status = ngx_conf_set_str_slot(cf, cmd, conf);
+ if (status != NGX_CONF_OK) {
+ return status;
+ }
+
+ if (!groonga_location_conf->log_path.data) {
+ return NGX_CONF_OK;
+ }
+
+ if (!ngx_str_is_custom_path(&(groonga_location_conf->log_path))) {
+ return NGX_CONF_OK;
+ }
+
+ groonga_location_conf->log_file =
+ ngx_conf_open_file(cf->cycle, &(groonga_location_conf->log_path));
+ if (!groonga_location_conf->log_file) {
+ ngx_log_error(NGX_LOG_ERR, cf->cycle->log, 0,
+ "http_groonga: failed to open groonga log file: <%V>",
+ &(groonga_location_conf->log_path));
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+static char *
+ngx_http_groonga_conf_set_log_level_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ char *status = NGX_CONF_OK;
+ ngx_http_groonga_loc_conf_t *groonga_location_conf = conf;
+ char *value;
+
+ value = ngx_str_null_terminate(cf->cycle->pool,
+ ((ngx_str_t *)cf->args->elts) + 1);
+ if (!grn_log_level_parse(value, &(groonga_location_conf->log_level))) {
+ status = "must be one of 'none', 'emergency', 'alert', "
+ "'critical', 'error', 'warning', 'notice', 'info', 'debug' and 'dump'";
+ }
+ ngx_pfree(cf->cycle->pool, value);
+
+ return status;
+}
+
+static char *
+ngx_http_groonga_conf_set_query_log_path_slot(ngx_conf_t *cf,
+ ngx_command_t *cmd,
+ void *conf)
+{
+ char *status;
+ ngx_http_groonga_loc_conf_t *groonga_location_conf = conf;
+
+ status = ngx_conf_set_str_slot(cf, cmd, conf);
+ if (status != NGX_CONF_OK) {
+ return status;
+ }
+
+ if (!groonga_location_conf->query_log_path.data) {
+ return NGX_CONF_OK;
+ }
+
+ if (!ngx_str_is_custom_path(&(groonga_location_conf->query_log_path))) {
+ return NGX_CONF_OK;
+ }
+
+ groonga_location_conf->query_log_file =
+ ngx_conf_open_file(cf->cycle, &(groonga_location_conf->query_log_path));
+ if (!groonga_location_conf->query_log_file) {
+ ngx_log_error(NGX_LOG_ERR, cf->cycle->log, 0,
+ "http_groonga: failed to open Groonga query log file: <%V>",
+ &(groonga_location_conf->query_log_path));
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+static void *
+ngx_http_groonga_create_loc_conf(ngx_conf_t *cf)
+{
+ ngx_http_groonga_loc_conf_t *conf;
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_groonga_loc_conf_t));
+ if (conf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ conf->enabled = NGX_CONF_UNSET;
+ conf->database_path.data = NULL;
+ conf->database_path.len = 0;
+ conf->database_path_cstr = NULL;
+ conf->database_auto_create = NGX_CONF_UNSET;
+ conf->base_path.data = NULL;
+ conf->base_path.len = 0;
+ conf->log_path.data = NULL;
+ conf->log_path.len = 0;
+ conf->log_file = NULL;
+ conf->log_level = GRN_LOG_DEFAULT_LEVEL;
+ conf->query_log_path.data = NULL;
+ conf->query_log_path.len = 0;
+ conf->query_log_file = NULL;
+ conf->cache_limit = NGX_CONF_UNSET_SIZE;
+ conf->config_file = NULL;
+ conf->config_line = 0;
+ conf->cache = NULL;
+ conf->cache_base_path.data = NULL;
+ conf->cache_base_path.len = 0;
+
+ return conf;
+}
+
+static char *
+ngx_http_groonga_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_groonga_loc_conf_t *prev = parent;
+ ngx_http_groonga_loc_conf_t *conf = child;
+ ngx_flag_t enabled = 0;
+
+ if (conf->enabled != NGX_CONF_UNSET) {
+ enabled = conf->enabled;
+ }
+
+ ngx_conf_merge_str_value(conf->database_path, prev->database_path, NULL);
+ ngx_conf_merge_value(conf->database_auto_create,
+ prev->database_auto_create,
+ GRN_TRUE);
+ ngx_conf_merge_size_value(conf->cache_limit, prev->cache_limit,
+ GRN_CACHE_DEFAULT_MAX_N_ENTRIES);
+
+#ifdef NGX_HTTP_GROONGA_LOG_PATH
+ ngx_conf_merge_str_value(conf->log_path, prev->log_path,
+ NGX_HTTP_GROONGA_LOG_PATH);
+ if (!conf->log_file &&
+ ngx_str_is_custom_path(&(conf->log_path)) &&
+ enabled) {
+ conf->log_file = ngx_conf_open_file(cf->cycle, &(conf->log_path));
+ if (!conf->log_file) {
+ ngx_log_error(NGX_LOG_ERR, cf->cycle->log, 0,
+ "http_groonga: "
+ "failed to open the default Groonga log file: <%V>",
+ &(conf->log_path));
+ return NGX_CONF_ERROR;
+ }
+ }
+#endif
+
+ ngx_conf_merge_str_value(conf->query_log_path, prev->query_log_path,
+ NGX_HTTP_GROONGA_QUERY_LOG_PATH);
+ if (!conf->query_log_file &&
+ ngx_str_is_custom_path(&(conf->query_log_path)) &&
+ enabled) {
+ conf->query_log_file = ngx_conf_open_file(cf->cycle,
+ &(conf->query_log_path));
+ if (!conf->query_log_file) {
+ ngx_log_error(NGX_LOG_ERR, cf->cycle->log, 0,
+ "http_groonga: "
+ "failed to open the default Groonga query log file: <%V>",
+ &(conf->query_log_path));
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ ngx_conf_merge_str_value(conf->cache_base_path,
+ prev->cache_base_path,
+ NULL);
+
+ return NGX_CONF_OK;
+}
+
+static void
+ngx_http_groonga_each_loc_conf_in_tree(ngx_http_location_tree_node_t *node,
+ ngx_http_groonga_loc_conf_callback_pt callback,
+ void *user_data)
+{
+ if (!node) {
+ return;
+ }
+
+ if (node->exact && node->exact->handler == ngx_http_groonga_handler) {
+ callback(node->exact->loc_conf[ngx_http_groonga_module.ctx_index],
+ user_data);
+ }
+
+ if (node->inclusive && node->inclusive->handler == ngx_http_groonga_handler) {
+ callback(node->inclusive->loc_conf[ngx_http_groonga_module.ctx_index],
+ user_data);
+ }
+
+ ngx_http_groonga_each_loc_conf_in_tree(node->left, callback, user_data);
+ ngx_http_groonga_each_loc_conf_in_tree(node->right, callback, user_data);
+ ngx_http_groonga_each_loc_conf_in_tree(node->tree, callback, user_data);
+}
+
+static void
+ngx_http_groonga_each_loc_conf(ngx_http_conf_ctx_t *http_conf,
+ ngx_http_groonga_loc_conf_callback_pt callback,
+ void *user_data)
+{
+ ngx_http_core_main_conf_t *main_conf;
+ ngx_http_core_srv_conf_t **server_confs;
+ ngx_uint_t i;
+
+ if (!http_conf) {
+ return;
+ }
+
+ main_conf = http_conf->main_conf[ngx_http_core_module.ctx_index];
+ server_confs = main_conf->servers.elts;
+ for (i = 0; i < main_conf->servers.nelts; i++) {
+ ngx_http_core_srv_conf_t *server_conf;
+ ngx_http_core_loc_conf_t *location_conf;
+
+ server_conf = server_confs[i];
+ location_conf = server_conf->ctx->loc_conf[ngx_http_core_module.ctx_index];
+ ngx_http_groonga_each_loc_conf_in_tree(location_conf->static_locations,
+ callback,
+ user_data);
+
+#if NGX_PCRE
+ if (location_conf->regex_locations) {
+ ngx_uint_t j;
+ for (j = 0; location_conf->regex_locations[j]; j++) {
+ ngx_http_core_loc_conf_t *regex_location_conf;
+
+ regex_location_conf = location_conf->regex_locations[j];
+ if (regex_location_conf->handler == ngx_http_groonga_handler) {
+ callback(regex_location_conf->loc_conf[ngx_http_groonga_module.ctx_index],
+ user_data);
+ }
+ }
+ }
+#endif
+ }
+}
+
+static void
+ngx_http_groonga_set_logger_callback(ngx_http_groonga_loc_conf_t *location_conf,
+ void *user_data)
+{
+ ngx_http_groonga_database_callback_data_t *data = user_data;
+
+ data->rc = ngx_http_groonga_context_init_logger(location_conf,
+ data->pool,
+ data->log);
+ if (data->rc != NGX_OK) {
+ return;
+ }
+ data->rc = ngx_http_groonga_context_init_query_logger(location_conf,
+ data->pool,
+ data->log);
+ if (data->rc != NGX_OK) {
+ return;
+ }
+}
+
+static ngx_int_t
+ngx_http_groonga_mkdir_p(ngx_log_t *log, const char *dir_name)
+{
+ char sub_path[PATH_MAX];
+ size_t i, dir_name_length;
+
+ dir_name_length = strlen(dir_name);
+ sub_path[0] = dir_name[0];
+ for (i = 1; i < dir_name_length + 1; i++) {
+ if (dir_name[i] == '/' || dir_name[i] == '\0') {
+ struct stat stat_buffer;
+ sub_path[i] = '\0';
+ if (stat(sub_path, &stat_buffer) == -1) {
+ if (ngx_create_dir(sub_path, 0700) == -1) {
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "failed to create directory: %s (%s): %s",
+ sub_path, dir_name,
+ strerror(errno));
+ return NGX_ERROR;
+ }
+ }
+ }
+ sub_path[i] = dir_name[i];
+ }
+
+ return NGX_OK;
+}
+
+static void
+ngx_http_groonga_create_database(ngx_http_groonga_loc_conf_t *location_conf,
+ ngx_http_groonga_database_callback_data_t *data)
+{
+ const char *database_base_name;
+
+ database_base_name = strrchr(location_conf->database_path_cstr, '/');
+ if (database_base_name) {
+ char database_dir[PATH_MAX];
+ database_dir[0] = '\0';
+ strncat(database_dir,
+ location_conf->database_path_cstr,
+ database_base_name - location_conf->database_path_cstr);
+ data->rc = ngx_http_groonga_mkdir_p(data->log, database_dir);
+ if (data->rc != NGX_OK) {
+ return;
+ }
+ }
+
+ location_conf->database =
+ grn_db_create(context, location_conf->database_path_cstr, NULL);
+ if (context->rc == GRN_SUCCESS) {
+ return;
+ }
+
+ ngx_log_error(NGX_LOG_EMERG, data->log, 0,
+ "failed to create Groonga database: %s",
+ context->errbuf);
+ data->rc = NGX_ERROR;
+}
+
+static void
+ngx_http_groonga_open_database_callback(ngx_http_groonga_loc_conf_t *location_conf,
+ void *user_data)
+{
+ ngx_http_groonga_database_callback_data_t *data = user_data;
+
+ data->rc = ngx_http_groonga_context_init_logger(location_conf,
+ data->pool,
+ data->log);
+ if (data->rc != NGX_OK) {
+ return;
+ }
+ data->rc = ngx_http_groonga_context_init_query_logger(location_conf,
+ data->pool,
+ data->log);
+ if (data->rc != NGX_OK) {
+ return;
+ }
+
+ if (!location_conf->database_path.data) {
+ ngx_log_error(NGX_LOG_EMERG, data->log, 0,
+ "%s: \"groonga_database\" must be specified in block at %s:%d",
+ location_conf->name,
+ location_conf->config_file,
+ location_conf->config_line);
+ data->rc = NGX_ERROR;
+ return;
+ }
+
+ if (!location_conf->database_path_cstr) {
+ location_conf->database_path_cstr =
+ ngx_str_null_terminate(data->pool, &(location_conf->database_path));
+ }
+
+ location_conf->database =
+ grn_db_open(context, location_conf->database_path_cstr);
+ if (context->rc != GRN_SUCCESS) {
+ if (location_conf->database_auto_create) {
+ ngx_http_groonga_create_database(location_conf, data);
+ } else {
+ ngx_log_error(NGX_LOG_EMERG, data->log, 0,
+ "failed to open Groonga database: %s",
+ context->errbuf);
+ data->rc = NGX_ERROR;
+ }
+ if (data->rc != NGX_OK) {
+ return;
+ }
+ }
+
+ if (location_conf->cache_base_path.data &&
+ ngx_str_is_custom_path(&(location_conf->cache_base_path))) {
+ char cache_base_path[PATH_MAX];
+ grn_memcpy(cache_base_path,
+ location_conf->cache_base_path.data,
+ location_conf->cache_base_path.len);
+ cache_base_path[location_conf->cache_base_path.len] = '\0';
+ location_conf->cache = grn_persistent_cache_open(context, cache_base_path);
+ } else {
+ location_conf->cache = grn_cache_open(context);
+ }
+ if (!location_conf->cache) {
+ ngx_log_error(NGX_LOG_EMERG, data->log, 0,
+ "failed to open Groonga cache: %s",
+ context->errbuf);
+ data->rc = NGX_ERROR;
+ return;
+ }
+
+ if (location_conf->cache_limit != NGX_CONF_UNSET_SIZE) {
+ grn_cache_set_max_n_entries(context,
+ location_conf->cache,
+ location_conf->cache_limit);
+ }
+}
+
+static void
+ngx_http_groonga_close_database_callback(ngx_http_groonga_loc_conf_t *location_conf,
+ void *user_data)
+{
+ ngx_http_groonga_database_callback_data_t *data = user_data;
+
+ ngx_http_groonga_context_init_logger(location_conf,
+ data->pool,
+ data->log);
+ ngx_http_groonga_context_init_query_logger(location_conf,
+ data->pool,
+ data->log);
+ grn_cache_current_set(context, location_conf->cache);
+
+ grn_obj_close(context, location_conf->database);
+ ngx_http_groonga_context_log_error(data->log);
+
+ grn_cache_current_set(context, NULL);
+ grn_cache_close(context, location_conf->cache);
+}
+
+static ngx_int_t
+ngx_http_groonga_init_process(ngx_cycle_t *cycle)
+{
+ grn_rc rc;
+ ngx_http_conf_ctx_t *http_conf;
+ ngx_http_groonga_database_callback_data_t data;
+
+ grn_thread_set_get_limit_func(ngx_http_groonga_get_thread_limit, NULL);
+
+#ifdef NGX_HTTP_GROONGA_LOG_PATH
+ grn_default_logger_set_path(NGX_HTTP_GROONGA_LOG_PATH);
+#endif
+
+ http_conf =
+ (ngx_http_conf_ctx_t *)ngx_get_conf(cycle->conf_ctx, ngx_http_module);
+
+ data.log = cycle->log;
+ data.pool = cycle->pool;
+ data.rc = NGX_OK;
+ ngx_http_groonga_each_loc_conf(http_conf,
+ ngx_http_groonga_set_logger_callback,
+ &data);
+
+ if (data.rc != NGX_OK) {
+ return data.rc;
+ }
+
+ rc = grn_init();
+ if (rc != GRN_SUCCESS) {
+ return NGX_ERROR;
+ }
+
+ grn_set_segv_handler();
+
+ rc = grn_ctx_init(context, GRN_NO_FLAGS);
+ if (rc != GRN_SUCCESS) {
+ return NGX_ERROR;
+ }
+
+ ngx_http_groonga_each_loc_conf(http_conf,
+ ngx_http_groonga_open_database_callback,
+ &data);
+
+ return data.rc;
+}
+
+static void
+ngx_http_groonga_exit_process(ngx_cycle_t *cycle)
+{
+ ngx_http_conf_ctx_t *http_conf;
+ ngx_http_groonga_database_callback_data_t data;
+
+ http_conf =
+ (ngx_http_conf_ctx_t *)ngx_get_conf(cycle->conf_ctx, ngx_http_module);
+ data.log = cycle->log;
+ data.pool = cycle->pool;
+ ngx_http_groonga_each_loc_conf(http_conf,
+ ngx_http_groonga_close_database_callback,
+ &data);
+
+ grn_ctx_fin(context);
+
+ grn_fin();
+
+ return;
+}
+
+/* entry point */
+static ngx_command_t ngx_http_groonga_commands[] = {
+ { ngx_string("groonga"),
+ NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_groonga_conf_set_groonga_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, enabled),
+ NULL },
+
+ { ngx_string("groonga_database"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, database_path),
+ NULL },
+
+ { ngx_string("groonga_database_auto_create"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, database_auto_create),
+ NULL },
+
+ { ngx_string("groonga_base_path"),
+ NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, base_path),
+ NULL },
+
+ { ngx_string("groonga_log_path"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_groonga_conf_set_log_path_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, log_path),
+ NULL },
+
+ { ngx_string("groonga_log_level"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_groonga_conf_set_log_level_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("groonga_query_log_path"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_groonga_conf_set_query_log_path_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, query_log_path),
+ NULL },
+
+ { ngx_string("groonga_cache_limit"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_size_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, cache_limit),
+ NULL },
+
+ { ngx_string("groonga_default_request_timeout"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, default_request_timeout_msec),
+ NULL },
+
+ { ngx_string("groonga_cache_base_path"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_str_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_groonga_loc_conf_t, cache_base_path),
+ NULL },
+
+ ngx_null_command
+};
+
+static ngx_http_module_t ngx_http_groonga_module_ctx = {
+ NULL, /* preconfiguration */
+ NULL, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_groonga_create_loc_conf, /* create location configuration */
+ ngx_http_groonga_merge_loc_conf, /* merge location configuration */
+};
+
+ngx_module_t ngx_http_groonga_module = {
+ NGX_MODULE_V1,
+ &ngx_http_groonga_module_ctx, /* module context */
+ ngx_http_groonga_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ ngx_http_groonga_init_process, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ ngx_http_groonga_exit_process, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
diff --git a/storage/mroonga/vendor/groonga/src/suggest/CMakeLists.txt b/storage/mroonga/vendor/groonga/src/suggest/CMakeLists.txt
new file mode 100644
index 00000000..ec85c1fb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/CMakeLists.txt
@@ -0,0 +1,87 @@
+# Copyright(C) 2012-2013 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+include_directories(
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../lib
+ ${MRUBY_INCLUDE_DIRS}
+ ${MESSAGE_PACK_INCLUDE_DIRS})
+
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/create_dataset_sources.am
+ GROONGA_SUGGEST_CREATE_DATASET_SOURCES)
+add_executable(groonga-suggest-create-dataset
+ ${GROONGA_SUGGEST_CREATE_DATASET_SOURCES})
+set_source_files_properties(${GROONGA_SUGGEST_CREATE_DATASET_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+target_link_libraries(groonga-suggest-create-dataset libgroonga)
+install(
+ TARGETS groonga-suggest-create-dataset
+ DESTINATION ${BIN_DIR})
+
+if(GRN_WITH_LIBEVENT AND GRN_WITH_ZEROMQ AND GRN_WITH_MESSAGE_PACK)
+ set(GRN_WITH_SUGGEST_LEARNER TRUE)
+else()
+ set(GRN_WITH_SUGGEST_LEARNER FALSE)
+endif()
+
+if(GRN_WITH_SUGGEST_LEARNER)
+ include_directories(
+ ${LIBEVENT_INCLUDE_DIRS}
+ ${ZEROMQ_INCLUDE_DIRS}
+ ${MESSAGE_PACK_INCLUDE_DIRS}
+ )
+ link_directories(
+ ${LIBEVENT_LIBRARY_DIRS}
+ ${ZEROMQ_LIBRARY_DIRS}
+ ${MESSAGE_PACK_LIBRARY_DIRS}
+ )
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/util_sources.am
+ GROONGA_SUGGEST_UTIL_SOURCES)
+ add_library(groonga-suggest-util STATIC ${GROONGA_SUGGEST_UTIL_SOURCES})
+ set_source_files_properties(${GROONGA_SUGGEST_UTIL_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/learner_sources.am
+ GROONGA_SUGGEST_LEARNER_SOURCES)
+ add_executable(groonga-suggest-learner ${GROONGA_SUGGEST_LEARNER_SOURCES})
+ set_source_files_properties(${GROONGA_SUGGEST_LEARNER_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ target_link_libraries(groonga-suggest-learner
+ groonga-suggest-util
+ libgroonga
+ ${LIBEVENT_LIBRARIES}
+ ${ZEROMQ_LIBRARIES}
+ ${MESSAGE_PACK_LIBRARIES})
+
+ read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/httpd_sources.am
+ GROONGA_SUGGEST_HTTPD_SOURCES)
+ add_executable(groonga-suggest-httpd ${GROONGA_SUGGEST_HTTPD_SOURCES})
+ set_source_files_properties(${GROONGA_SUGGEST_HTTPD_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ target_link_libraries(groonga-suggest-httpd
+ groonga-suggest-util
+ libgroonga
+ ${LIBEVENT_LIBRARIES}
+ ${ZEROMQ_LIBRARIES}
+ ${MESSAGE_PACK_LIBRARIES})
+
+ install(
+ TARGETS groonga-suggest-learner groonga-suggest-httpd
+ DESTINATION ${BIN_DIR})
+endif()
diff --git a/storage/mroonga/vendor/groonga/src/suggest/Makefile.am b/storage/mroonga/vendor/groonga/src/suggest/Makefile.am
new file mode 100644
index 00000000..91260016
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/Makefile.am
@@ -0,0 +1,74 @@
+bin_PROGRAMS =
+
+NONEXISTENT_CXX_SOURCE = nonexistent.cpp
+
+bin_PROGRAMS += \
+ groonga-suggest-create-dataset
+
+if ENABLE_SUGGEST_LEARNER
+bin_PROGRAMS += \
+ groonga-suggest-learner \
+ groonga-suggest-httpd
+noinst_LTLIBRARIES = libutil.la
+endif
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CFLAGS = \
+ $(NO_STRICT_ALIASING_CFLAGS) \
+ $(COVERAGE_CFLAGS) \
+ $(GRN_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS) \
+ $(MRUBY_CFLAGS)
+
+DEFS += $(GRN_DEFS)
+
+AM_LDFLAGS = -no-undefined
+
+DEFAULT_INCLUDES = \
+ -I$(top_builddir) \
+ -I$(srcdir) \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib \
+ $(GROONGA_INCLUDEDIR)
+
+include learner_sources.am
+nodist_EXTRA_groonga_suggest_learner_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+groonga_suggest_learner_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(LIBEVENT_CFLAGS) \
+ $(LIBZMQ_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS)
+groonga_suggest_learner_LDADD = \
+ libutil.la \
+ $(top_builddir)/lib/libgroonga.la \
+ $(LIBEVENT_LIBS) \
+ $(LIBZMQ_LIBS) \
+ $(MESSAGE_PACK_LIBS)
+
+include httpd_sources.am
+nodist_EXTRA_groonga_suggest_httpd_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+groonga_suggest_httpd_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(LIBEVENT_CFLAGS) \
+ $(LIBZMQ_CFLAGS) \
+ $(MESSAGE_PACK_CFLAGS)
+groonga_suggest_httpd_LDADD = \
+ libutil.la \
+ $(top_builddir)/lib/libgroonga.la \
+ $(LIBEVENT_LIBS) \
+ $(LIBZMQ_LIBS) \
+ $(MESSAGE_PACK_LIBS)
+
+include create_dataset_sources.am
+nodist_EXTRA_groonga_suggest_create_dataset_SOURCES = $(NONEXISTENT_CXX_SOURCE)
+groonga_suggest_create_dataset_CFLAGS = \
+ $(AM_CFLAGS)
+groonga_suggest_create_dataset_LDADD = \
+ $(top_builddir)/lib/libgroonga.la
+
+include util_sources.am
+libutil_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(LIBEVENT_CFLAGS)
diff --git a/storage/mroonga/vendor/groonga/src/suggest/create_dataset_sources.am b/storage/mroonga/vendor/groonga/src/suggest/create_dataset_sources.am
new file mode 100644
index 00000000..cfecd650
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/create_dataset_sources.am
@@ -0,0 +1,2 @@
+groonga_suggest_create_dataset_SOURCES = \
+ groonga_suggest_create_dataset.c
diff --git a/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_create_dataset.c b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_create_dataset.c
new file mode 100644
index 00000000..7cec2922
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_create_dataset.c
@@ -0,0 +1,223 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2010-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/* For grn_str_getopt() */
+#include <grn_str.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <groonga.h>
+
+typedef enum {
+ MODE_NONE,
+ MODE_USAGE
+} ModeFlags;
+
+static const char *DEFAULT_DEFAULT_TOKENIZER = "TokenBigram";
+
+static void
+usage(FILE *output, int argc, char **argv)
+{
+#define OUTPUT(...) fprintf(output, __VA_ARGS__)
+
+ OUTPUT("Usage: %s [OPTIONS] DB_PATH DATASET_NAME\n", argv[0]);
+ OUTPUT(" e.g.: %s /tmp/db shops\n", argv[0]);
+ OUTPUT("\n");
+ OUTPUT("Options:\n");
+ OUTPUT(" --default-tokenizer=TOKENIZER Use TOKENIZER as the default\n");
+ OUTPUT(" tokenizer for item name\n");
+ OUTPUT(" (default: %s)\n",
+ DEFAULT_DEFAULT_TOKENIZER);
+ OUTPUT(" -h, --help Show this message and exit\n");
+
+#undef OUTPUT
+}
+
+static void
+output(grn_ctx *ctx)
+{
+ int flags = 0;
+ char *str;
+ unsigned int str_len;
+
+ do {
+ grn_ctx_recv(ctx, &str, &str_len, &flags);
+ if (str_len > 0 || ctx->rc) {
+ if (ctx->rc) {
+ printf("ERROR (%d): %s\n", ctx->rc, ctx->errbuf);
+ }
+ if (str_len > 0) {
+ printf("%.*s\n", str_len, str);
+ }
+ }
+ } while (flags & GRN_CTX_MORE);
+}
+
+static void
+send_command(grn_ctx *ctx, grn_obj *buffer, const char *command,
+ const char *dataset_name)
+{
+ const char *p = command;
+ const char *dataset_place_holder = "${DATASET}";
+ char *dataset_place_holder_position;
+
+ if (ctx->rc != GRN_SUCCESS) {
+ return;
+ }
+
+ GRN_BULK_REWIND(buffer);
+ while ((dataset_place_holder_position = strstr(p, dataset_place_holder))) {
+ GRN_TEXT_PUT(ctx, buffer, p, dataset_place_holder_position - p);
+ GRN_TEXT_PUTS(ctx, buffer, dataset_name);
+ p = dataset_place_holder_position + strlen(dataset_place_holder);
+ }
+ GRN_TEXT_PUTS(ctx, buffer, p);
+ printf("> %.*s\n", (int)GRN_TEXT_LEN(buffer), GRN_TEXT_VALUE(buffer));
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(buffer), GRN_TEXT_LEN(buffer), 0);
+ output(ctx);
+}
+
+
+int
+main(int argc, char **argv)
+{
+ const char *db_path;
+ const char *dataset_name;
+ grn_ctx ctx_, *ctx;
+ grn_obj *db;
+ grn_bool success = GRN_TRUE;
+ int parsed_argc, rest_argc;
+ int flags = MODE_NONE;
+ const char *default_tokenizer = NULL;
+ static grn_str_getopt_opt opts[] = {
+ {'\0', "default-tokenizer", NULL, 0, GETOPT_OP_NONE},
+ {'h', "help", NULL, MODE_USAGE, GETOPT_OP_UPDATE}
+ };
+
+ opts[0].arg = &default_tokenizer;
+
+ parsed_argc = grn_str_getopt(argc, argv, opts, &flags);
+ if (parsed_argc < 0) {
+ usage(stderr, argc, argv);
+ return EXIT_FAILURE;
+ }
+
+ if (flags & MODE_USAGE) {
+ usage(stdout, argc, argv);
+ return EXIT_SUCCESS;
+ }
+
+ rest_argc = argc - parsed_argc;
+ if (rest_argc != 2) {
+ usage(stderr, argc, argv);
+ return EXIT_FAILURE;
+ }
+
+ db_path = argv[parsed_argc];
+ dataset_name = argv[parsed_argc + 1];
+
+ grn_init();
+
+ ctx = &ctx_;
+ grn_ctx_init(ctx, 0);
+ db = grn_db_open(ctx, db_path);
+ if (!db) {
+ if (ctx->rc == GRN_NO_SUCH_FILE_OR_DIRECTORY) {
+ db = grn_db_create(ctx, db_path, NULL);
+ if (!db) {
+ fprintf(stderr, "DB create failed (%s): %s\n", db_path, ctx->errbuf);
+ }
+ } else {
+ fprintf(stderr, "DB open failed (%s): %s\n", db_path, ctx->errbuf);
+ }
+ }
+
+ if (db) {
+ grn_obj text;
+ GRN_TEXT_INIT(&text, 0);
+#define SEND(string) send_command(ctx, &text, string, dataset_name)
+ SEND("plugin_register suggest/suggest");
+ SEND("table_create event_type TABLE_HASH_KEY ShortText");
+ {
+ grn_obj query;
+ GRN_TEXT_INIT(&query, 0);
+ GRN_TEXT_PUTS(ctx, &query,
+ "table_create bigram TABLE_PAT_KEY ShortText "
+ "--default_tokenizer ");
+ if (default_tokenizer) {
+ GRN_TEXT_PUTS(ctx, &query, default_tokenizer);
+ } else {
+ GRN_TEXT_PUTS(ctx, &query, DEFAULT_DEFAULT_TOKENIZER);
+ }
+ GRN_TEXT_PUTS(ctx, &query, " --normalizer NormalizerAuto");
+ GRN_TEXT_PUTC(ctx, &query, '\0');
+ SEND(GRN_TEXT_VALUE(&query));
+ GRN_OBJ_FIN(ctx, &query);
+ }
+ SEND("table_create kana TABLE_PAT_KEY ShortText "
+ "--normalizer NormalizerAuto");
+ SEND("table_create item_${DATASET} TABLE_PAT_KEY "
+ "ShortText --default_tokenizer TokenDelimit "
+ "--normalizer NormalizerAuto");
+ SEND("column_create bigram item_${DATASET}_key "
+ "COLUMN_INDEX|WITH_POSITION item_${DATASET} _key");
+ SEND("column_create item_${DATASET} kana COLUMN_VECTOR kana");
+ SEND("column_create kana item_${DATASET}_kana COLUMN_INDEX "
+ "item_${DATASET} kana");
+ SEND("column_create item_${DATASET} freq COLUMN_SCALAR Int32");
+ SEND("column_create item_${DATASET} last COLUMN_SCALAR Time");
+ SEND("column_create item_${DATASET} boost COLUMN_SCALAR Int32");
+ SEND("column_create item_${DATASET} freq2 COLUMN_SCALAR Int32");
+ SEND("column_create item_${DATASET} buzz COLUMN_SCALAR Int32");
+
+ SEND("table_create pair_${DATASET} TABLE_HASH_KEY UInt64");
+ SEND("column_create pair_${DATASET} pre COLUMN_SCALAR item_${DATASET}");
+ SEND("column_create pair_${DATASET} post COLUMN_SCALAR item_${DATASET}");
+ SEND("column_create pair_${DATASET} freq0 COLUMN_SCALAR Int32");
+ SEND("column_create pair_${DATASET} freq1 COLUMN_SCALAR Int32");
+ SEND("column_create pair_${DATASET} freq2 COLUMN_SCALAR Int32");
+ SEND("column_create item_${DATASET} co COLUMN_INDEX pair_${DATASET} pre");
+
+ SEND("table_create sequence_${DATASET} TABLE_HASH_KEY ShortText");
+ SEND("table_create event_${DATASET} TABLE_NO_KEY");
+ SEND("column_create sequence_${DATASET} events "
+ "COLUMN_VECTOR|RING_BUFFER event_${DATASET}");
+ SEND("column_create event_${DATASET} type COLUMN_SCALAR event_type");
+ SEND("column_create event_${DATASET} time COLUMN_SCALAR Time");
+ SEND("column_create event_${DATASET} item COLUMN_SCALAR item_${DATASET}");
+ SEND("column_create event_${DATASET} sequence COLUMN_SCALAR "
+ "sequence_${DATASET}");
+
+ SEND("table_create configuration TABLE_HASH_KEY ShortText");
+ SEND("column_create configuration weight COLUMN_SCALAR UInt32");
+ SEND("load --table configuration");
+ SEND("[");
+ SEND("{\"_key\": \"${DATASET}\", \"weight\": 1}");
+ SEND("]");
+#undef SEND
+ success = ctx->rc == GRN_SUCCESS;
+ GRN_OBJ_FIN(ctx, &text);
+ GRN_OBJ_FIN(ctx, db);
+ } else {
+ success = GRN_FALSE;
+ }
+ grn_ctx_fin(ctx);
+ grn_fin();
+
+ return success ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_ddl.txt b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_ddl.txt
new file mode 100644
index 00000000..f82763f8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_ddl.txt
@@ -0,0 +1,62 @@
+suggest向けDDL解説
+==================
+
+suggest機能で必要となるスキーマを説明する。なお、このドキュメントはsuggest機能完成とともにdocsディレクトリ内に移動される。
+
+1. 概要
+
+ suggestデータベースには、学習過程でのみ必要になるテーブルと、
+ 学習時およびサジェスト時に必要になるテーブルがあります。
+ 前者を作業用テーブルと呼び、後者を学習結果テーブルと呼びます。
+
+2. 学習結果テーブル
+
+ 学習結果テーブルは二つのファクトテーブルと二つの語彙テーブルから構成されます。
+
+2.1. 学習結果ファクトテーブル
+
+item: suggest候補として提示する個々の文字列を格納するテーブルです。
+
+ 以下のカラムを用意しています。
+
+ _key: itemテーブルの主キーは、サジェスト対象文字列そのものとなります。
+ kana: 対象文字列の読み仮名を格納します。必須ではありませんが、セットされていればローマ字入力途中の文字列に対しても補完候補を提示可能となります。
+ freq: ユーザクエリにおいて入力された回数を記録します。
+ last: ユーザクエリに最後に入力された時刻を記録します。
+ freq2: ユーザクエリにおいてサブミットされた回数を記録します。
+ boost: 当該文字列の露出を制御します。正値を指定すれば露出が頻繁になり、-1を指定すれば、露出されません。
+ buzz: 入力回数の差分を記録します。
+ co: 共起する他の文字列を参照するための索引です。
+
+pair: item間の共起関係を管理するテーブルです。
+
+ 以下のカラムを用意しています。
+
+ _kay: preおよびpostのIDを結合した数値が主キーとなります。
+ pre: 事前に出現するアイティムです。
+ post: 事後に出現するアイティムです。
+ freq0: completeイベントにおける共起頻度を記録します。
+ freq1: correctイベントにおける共起頻度を記録します。
+ freq2: suggestイベントにおける共起頻度を記録します。
+
+2.2. 学習結果語彙テーブル
+
+ bigram: itemの主キーによって全文検索を行うための語彙表です。
+ kana: itemのkanaカラムの入力補完を行うための語彙表です。
+
+3. 作業用テーブル
+
+ 作業用テーブルにはeventとsequenceの2テーブルがあります。
+
+event: ユーザの個々のクエリイベントに対応します。レコードの追加のみが行われます。
+ 適宜dropして再作成することが望ましいです。
+
+ type: submitの有無を記録します。
+ time: イベントが発生した時刻を記録します。
+ item: ユーザが入力した文字列を記録します。
+ sequence: ユーザの識別子(cookie, ipアドレス等)を記録します。
+
+sequence: 同一ユーザの一連の操作を記録します。レコードの追加のみが行われます。
+ 適宜dropして再作成することが望ましいです。
+
+ events: 当該ユーザの操作履歴を記録します。
diff --git a/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_httpd.c b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_httpd.c
new file mode 100644
index 00000000..4f542f21
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_httpd.c
@@ -0,0 +1,860 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2010-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/* groonga origin headers */
+#include <grn_str.h>
+#include <grn_msgpack.h>
+
+#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+
+#include <fcntl.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/resource.h>
+
+#include "zmq_compatible.h"
+#include <event.h>
+#include <evhttp.h>
+#include <groonga.h>
+#include <pthread.h>
+
+#include "util.h"
+
+#define DEFAULT_PORT 8080
+#define DEFAULT_MAX_THREADS 8
+
+#define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
+
+#define LISTEN_BACKLOG 756
+#define MIN_MAX_FDS 2048
+#define MAX_THREADS 128 /* max 256 */
+
+typedef enum {
+ run_mode_none = 0,
+ run_mode_usage,
+ run_mode_daemon,
+ run_mode_error
+} run_mode;
+
+#define RUN_MODE_MASK 0x007f
+#define RUN_MODE_ENABLE_MAX_FD_CHECK 0x0080
+
+
+typedef struct {
+ grn_ctx *ctx;
+ grn_obj *db;
+ void *zmq_sock;
+ grn_obj cmd_buf;
+ grn_obj pass_through_parameters;
+ pthread_t thd;
+ uint32_t thread_id;
+ struct event_base *base;
+ struct evhttp *httpd;
+ struct event pulse;
+ const char *log_base_path;
+ FILE *log_file;
+ uint32_t log_count;
+ grn_bool request_reopen_log_file;
+} thd_data;
+
+typedef struct {
+ const char *db_path;
+ const char *recv_endpoint;
+ pthread_t thd;
+ void *zmq_ctx;
+} recv_thd_data;
+
+#define CMD_BUF_SIZE 1024
+
+static thd_data threads[MAX_THREADS];
+static uint32_t default_max_threads = DEFAULT_MAX_THREADS;
+static uint32_t max_threads;
+static volatile sig_atomic_t loop = 1;
+static grn_obj *db;
+static uint32_t n_lines_per_log_file = 1000000;
+
+static int
+suggest_result(grn_ctx *ctx,
+ struct evbuffer *res_buf, const char *types, const char *query,
+ const char *target_name, int frequency_threshold,
+ double conditional_probability_threshold, int limit,
+ grn_obj *cmd_buf, grn_obj *pass_through_parameters)
+{
+ if (target_name && types && query) {
+ GRN_BULK_REWIND(cmd_buf);
+ GRN_TEXT_PUTS(ctx, cmd_buf, "/d/suggest?table=item_");
+ grn_text_urlenc(ctx, cmd_buf, target_name, strlen(target_name));
+ GRN_TEXT_PUTS(ctx, cmd_buf, "&column=kana&types=");
+ grn_text_urlenc(ctx, cmd_buf, types, strlen(types));
+ GRN_TEXT_PUTS(ctx, cmd_buf, "&query=");
+ grn_text_urlenc(ctx, cmd_buf, query, strlen(query));
+ GRN_TEXT_PUTS(ctx, cmd_buf, "&frequency_threshold=");
+ grn_text_itoa(ctx, cmd_buf, frequency_threshold);
+ GRN_TEXT_PUTS(ctx, cmd_buf, "&conditional_probability_threshold=");
+ grn_text_ftoa(ctx, cmd_buf, conditional_probability_threshold);
+ GRN_TEXT_PUTS(ctx, cmd_buf, "&limit=");
+ grn_text_itoa(ctx, cmd_buf, limit);
+ if (GRN_TEXT_LEN(pass_through_parameters) > 0) {
+ GRN_TEXT_PUTS(ctx, cmd_buf, "&");
+ GRN_TEXT_PUT(ctx, cmd_buf,
+ GRN_TEXT_VALUE(pass_through_parameters),
+ GRN_TEXT_LEN(pass_through_parameters));
+ }
+ {
+ char *res;
+ int flags;
+ unsigned int res_len;
+
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(cmd_buf), GRN_TEXT_LEN(cmd_buf), 0);
+ grn_ctx_recv(ctx, &res, &res_len, &flags);
+
+ evbuffer_add(res_buf, res, res_len);
+ return res_len;
+ }
+ } else {
+ evbuffer_add(res_buf, "{}", 2);
+ return 2;
+ }
+}
+
+static void
+log_send(struct evkeyvalq *output_headers, struct evbuffer *res_buf,
+ thd_data *thd, struct evkeyvalq *get_args)
+{
+ uint64_t millisec;
+ int frequency_threshold, limit;
+ double conditional_probability_threshold;
+ const char *callback, *types, *query, *client_id, *target_name,
+ *learn_target_name;
+
+ GRN_BULK_REWIND(&(thd->pass_through_parameters));
+ parse_keyval(thd->ctx, get_args, &query, &types, &client_id, &target_name,
+ &learn_target_name, &callback, &millisec, &frequency_threshold,
+ &conditional_probability_threshold, &limit,
+ &(thd->pass_through_parameters));
+
+ /* send data to learn client */
+ if (thd->zmq_sock && millisec && client_id && query && learn_target_name) {
+ char c;
+ size_t l;
+ msgpack_packer pk;
+ msgpack_sbuffer sbuf;
+ int cnt, submit_flag = 0;
+
+ msgpack_sbuffer_init(&sbuf);
+ msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
+
+ cnt = 4;
+ if (types && !strcmp(types, "submit")) {
+ cnt++;
+ types = NULL;
+ submit_flag = 1;
+ }
+ msgpack_pack_map(&pk, cnt);
+
+ c = 'i';
+ msgpack_pack_str(&pk, 1);
+ msgpack_pack_str_body(&pk, &c, 1);
+ l = strlen(client_id);
+ msgpack_pack_str(&pk, l);
+ msgpack_pack_str_body(&pk, client_id, l);
+
+ c = 'q';
+ msgpack_pack_str(&pk, 1);
+ msgpack_pack_str_body(&pk, &c, 1);
+ l = strlen(query);
+ msgpack_pack_str(&pk, l);
+ msgpack_pack_str_body(&pk, query, l);
+
+ c = 's';
+ msgpack_pack_str(&pk, 1);
+ msgpack_pack_str_body(&pk, &c, 1);
+ msgpack_pack_uint64(&pk, millisec);
+
+ c = 'l';
+ msgpack_pack_str(&pk, 1);
+ msgpack_pack_str_body(&pk, &c, 1);
+ l = strlen(learn_target_name);
+ msgpack_pack_str(&pk, l);
+ msgpack_pack_str_body(&pk, learn_target_name, l);
+
+ if (submit_flag) {
+ c = 't';
+ msgpack_pack_str(&pk, 1);
+ msgpack_pack_str_body(&pk, &c, 1);
+ msgpack_pack_true(&pk);
+ }
+ {
+ zmq_msg_t msg;
+ if (!zmq_msg_init_size(&msg, sbuf.size)) {
+ memcpy((void *)zmq_msg_data(&msg), sbuf.data, sbuf.size);
+ if (zmq_msg_send(&msg, thd->zmq_sock, 0) == -1) {
+ print_error("zmq_msg_send() error");
+ }
+ zmq_msg_close(&msg);
+ }
+ }
+ msgpack_sbuffer_destroy(&sbuf);
+ }
+ /* make result */
+ {
+ int content_length;
+ if (callback) {
+ evhttp_add_header(output_headers,
+ "Content-Type", "text/javascript; charset=UTF-8");
+ content_length = strlen(callback);
+ evbuffer_add(res_buf, callback, content_length);
+ evbuffer_add(res_buf, "(", 1);
+ content_length += suggest_result(thd->ctx,
+ res_buf, types, query, target_name,
+ frequency_threshold,
+ conditional_probability_threshold,
+ limit,
+ &(thd->cmd_buf),
+ &(thd->pass_through_parameters)) + 3;
+ evbuffer_add(res_buf, ");", 2);
+ } else {
+ evhttp_add_header(output_headers,
+ "Content-Type", "application/json; charset=UTF-8");
+ content_length = suggest_result(thd->ctx,
+ res_buf, types, query, target_name,
+ frequency_threshold,
+ conditional_probability_threshold,
+ limit,
+ &(thd->cmd_buf),
+ &(thd->pass_through_parameters));
+ }
+ if (content_length >= 0) {
+#define NUM_BUF_SIZE 16
+ char num_buf[NUM_BUF_SIZE];
+ grn_snprintf(num_buf, NUM_BUF_SIZE, NUM_BUF_SIZE, "%d", content_length);
+ evhttp_add_header(output_headers, "Content-Length", num_buf);
+#undef NUM_BUF_SIZE
+ }
+ }
+}
+
+static void
+cleanup_httpd_thread(thd_data *thd) {
+ if (thd->log_file) {
+ fclose(thd->log_file);
+ }
+ if (thd->httpd) {
+ evhttp_free(thd->httpd);
+ }
+ if (thd->zmq_sock) {
+ zmq_close(thd->zmq_sock);
+ }
+ grn_obj_unlink(thd->ctx, &(thd->cmd_buf));
+ grn_obj_unlink(thd->ctx, &(thd->pass_through_parameters));
+ if (thd->ctx) {
+ grn_ctx_close(thd->ctx);
+ }
+ event_base_free(thd->base);
+}
+
+static void
+close_log_file(thd_data *thread)
+{
+ fclose(thread->log_file);
+ thread->log_file = NULL;
+ thread->request_reopen_log_file = GRN_FALSE;
+}
+
+static void
+generic_handler(struct evhttp_request *req, void *arg)
+{
+ struct evkeyvalq args;
+ thd_data *thd = arg;
+
+ if (!loop) {
+ event_base_loopexit(thd->base, NULL);
+ return;
+ }
+ if (!req->uri) { return; }
+
+ evhttp_parse_query(req->uri, &args);
+ {
+ struct evbuffer *res_buf;
+ if (!(res_buf = evbuffer_new())) {
+ err(1, "failed to create response buffer");
+ }
+
+ evhttp_add_header(req->output_headers, "Connection", "close");
+
+ log_send(req->output_headers, res_buf, thd, &args);
+ evhttp_send_reply(req, HTTP_OK, "OK", res_buf);
+ evbuffer_free(res_buf);
+ /* logging */
+ {
+ if (thd->log_base_path) {
+ if (thd->log_file && thd->request_reopen_log_file) {
+ close_log_file(thd);
+ }
+ if (!thd->log_file) {
+ time_t n;
+ struct tm *t_st;
+ char p[PATH_MAX + 1];
+
+ time(&n);
+ t_st = localtime(&n);
+
+ grn_snprintf(p,
+ PATH_MAX,
+ PATH_MAX,
+ "%s%04d%02d%02d%02d%02d%02d-%02d",
+ thd->log_base_path,
+ t_st->tm_year + 1900,
+ t_st->tm_mon + 1,
+ t_st->tm_mday,
+ t_st->tm_hour,
+ t_st->tm_min,
+ t_st->tm_sec,
+ thd->thread_id);
+
+ if (!(thd->log_file = fopen(p, "a"))) {
+ print_error("cannot open log_file %s.", p);
+ } else {
+ thd->log_count = 0;
+ }
+ }
+ if (thd->log_file) {
+ fprintf(thd->log_file, "%s\n", req->uri);
+ thd->log_count++;
+ if (n_lines_per_log_file > 0 &&
+ thd->log_count >= n_lines_per_log_file) {
+ close_log_file(thd);
+ }
+ }
+ }
+ }
+ }
+ evhttp_clear_headers(&args);
+}
+
+static int
+bind_socket(int port)
+{
+ int nfd;
+ if ((nfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ print_error("cannot open socket for http.");
+ return -1;
+ } else {
+ int r, one = 1;
+ struct sockaddr_in addr;
+
+ r = setsockopt(nfd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(int));
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_port = htons(port);
+
+ if ((r = bind(nfd, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
+ print_error("cannot bind socket for http.");
+ return r;
+ }
+ if ((r = listen(nfd, LISTEN_BACKLOG)) < 0) {
+ print_error("cannot listen socket for http.");
+ return r;
+ }
+ if ((r = fcntl(nfd, F_GETFL, 0)) < 0 || fcntl(nfd, F_SETFL, r | O_NONBLOCK) < 0 ) {
+ print_error("cannot fcntl socket for http.");
+ return -1;
+ }
+ return nfd;
+ }
+}
+
+static void
+signal_handler(int sig)
+{
+ loop = 0;
+}
+
+static void
+signal_reopen_log_file(int sig)
+{
+ uint32_t i;
+
+ for (i = 0; i < max_threads; i++) {
+ threads[i].request_reopen_log_file = GRN_TRUE;
+ }
+}
+
+void
+timeout_handler(int fd, short events, void *arg) {
+ thd_data *thd = arg;
+ if (!loop) {
+ event_base_loopexit(thd->base, NULL);
+ } else {
+ struct timeval tv = {1, 0};
+ evtimer_add(&(thd->pulse), &tv);
+ }
+}
+
+static void *
+dispatch(void *arg)
+{
+ event_base_dispatch((struct event_base *)arg);
+ return NULL;
+}
+
+static void
+msgpack2json(msgpack_object *o, grn_ctx *ctx, grn_obj *buf)
+{
+ switch (o->type) {
+ case MSGPACK_OBJECT_POSITIVE_INTEGER:
+ grn_text_ulltoa(ctx, buf, o->via.u64);
+ break;
+ case MSGPACK_OBJECT_STR:
+ grn_text_esc(ctx, buf,
+ MSGPACK_OBJECT_STR_PTR(o),
+ MSGPACK_OBJECT_STR_SIZE(o));
+ break;
+ case MSGPACK_OBJECT_ARRAY:
+ GRN_TEXT_PUTC(ctx, buf, '[');
+ {
+ int i;
+ for (i = 0; i < o->via.array.size; i++) {
+ msgpack2json(o->via.array.ptr, ctx, buf);
+ }
+ }
+ GRN_TEXT_PUTC(ctx, buf, ']');
+ break;
+ case MSGPACK_OBJECT_FLOAT:
+ grn_text_ftoa(ctx, buf, MSGPACK_OBJECT_FLOAT_VALUE(o));
+ break;
+ default:
+ print_error("cannot handle this msgpack type.");
+ }
+}
+
+static void
+load_from_learner(msgpack_object *o, grn_ctx *ctx, grn_obj *cmd_buf)
+{
+ if (o->type == MSGPACK_OBJECT_MAP && o->via.map.size) {
+ msgpack_object_kv *kv;
+ msgpack_object *key;
+ msgpack_object *value;
+ kv = &(o->via.map.ptr[0]);
+ key = &(kv->key);
+ value = &(kv->val);
+ if (key->type == MSGPACK_OBJECT_STR && MSGPACK_OBJECT_STR_SIZE(key) == 6 &&
+ !memcmp(MSGPACK_OBJECT_STR_PTR(key), CONST_STR_LEN("target"))) {
+ if (value->type == MSGPACK_OBJECT_STR) {
+ int i;
+ GRN_BULK_REWIND(cmd_buf);
+ GRN_TEXT_PUTS(ctx, cmd_buf, "load --table ");
+ GRN_TEXT_PUT(ctx, cmd_buf,
+ MSGPACK_OBJECT_STR_PTR(value),
+ MSGPACK_OBJECT_STR_SIZE(value));
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(cmd_buf), GRN_TEXT_LEN(cmd_buf), GRN_CTX_MORE);
+ grn_ctx_send(ctx, CONST_STR_LEN("["), GRN_CTX_MORE);
+ if (MSGPACK_OBJECT_STR_SIZE(value) > 5) {
+ if (!memcmp(MSGPACK_OBJECT_STR_PTR(value), CONST_STR_LEN("item_")) ||
+ !memcmp(MSGPACK_OBJECT_STR_PTR(value), CONST_STR_LEN("pair_"))) {
+ char delim = '{';
+ GRN_BULK_REWIND(cmd_buf);
+ for (i = 1; i < o->via.map.size; i++) {
+ GRN_TEXT_PUTC(ctx, cmd_buf, delim);
+ kv = &(o->via.map.ptr[i]);
+ msgpack2json(&(kv->key), ctx, cmd_buf);
+ GRN_TEXT_PUTC(ctx, cmd_buf, ':');
+ msgpack2json(&(kv->val), ctx, cmd_buf);
+ delim = ',';
+ }
+ GRN_TEXT_PUTC(ctx, cmd_buf, '}');
+ /* printf("msg: %.*s\n", GRN_TEXT_LEN(cmd_buf), GRN_TEXT_VALUE(cmd_buf)); */
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(cmd_buf), GRN_TEXT_LEN(cmd_buf), GRN_CTX_MORE);
+ }
+ }
+ grn_ctx_send(ctx, CONST_STR_LEN("]"), 0);
+ {
+ char *res;
+ int flags;
+ unsigned int res_len;
+ grn_ctx_recv(ctx, &res, &res_len, &flags);
+ }
+ }
+ }
+ }
+}
+
+static void
+recv_handler(grn_ctx *ctx, void *zmq_recv_sock, msgpack_zone *mempool, grn_obj *cmd_buf)
+{
+ zmq_msg_t msg;
+
+ if (zmq_msg_init(&msg)) {
+ print_error("cannot init zmq message.");
+ } else {
+ if (zmq_msg_recv(&msg, zmq_recv_sock, 0) == -1) {
+ print_error("cannot recv zmq message.");
+ } else {
+ msgpack_object obj;
+ msgpack_unpack_return ret;
+
+ ret = msgpack_unpack(zmq_msg_data(&msg), zmq_msg_size(&msg), NULL, mempool, &obj);
+ if (MSGPACK_UNPACK_SUCCESS == ret) {
+ load_from_learner(&obj, ctx, cmd_buf);
+ } else {
+ print_error("invalid recv data.");
+ }
+ msgpack_zone_clear(mempool);
+ }
+ zmq_msg_close(&msg);
+ }
+}
+
+static void *
+recv_from_learner(void *arg)
+{
+ void *zmq_recv_sock;
+ recv_thd_data *thd = arg;
+
+ if ((zmq_recv_sock = zmq_socket(thd->zmq_ctx, ZMQ_SUB))) {
+ if (!zmq_connect(zmq_recv_sock, thd->recv_endpoint)) {
+ grn_ctx ctx;
+ if (!grn_ctx_init(&ctx, 0)) {
+ if ((!grn_ctx_use(&ctx, db))) {
+ msgpack_zone *mempool;
+ if ((mempool = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE))) {
+ grn_obj cmd_buf;
+ zmq_pollitem_t items[] = {
+ { zmq_recv_sock, 0, ZMQ_POLLIN, 0}
+ };
+ GRN_TEXT_INIT(&cmd_buf, 0);
+ zmq_setsockopt(zmq_recv_sock, ZMQ_SUBSCRIBE, "", 0);
+ while (loop) {
+ zmq_poll(items, 1, 10000);
+ if (items[0].revents & ZMQ_POLLIN) {
+ recv_handler(&ctx, zmq_recv_sock, mempool, &cmd_buf);
+ }
+ }
+ grn_obj_unlink(&ctx, &cmd_buf);
+ msgpack_zone_free(mempool);
+ } else {
+ print_error("cannot create msgpack zone.");
+ }
+ /* db_close */
+ } else {
+ print_error("error in grn_db_open() on recv thread.");
+ }
+ grn_ctx_fin(&ctx);
+ } else {
+ print_error("error in grn_ctx_init() on recv thread.");
+ }
+ } else {
+ print_error("cannot create recv zmq_socket.");
+ }
+ } else {
+ print_error("cannot connect zmq_socket.");
+ }
+ return NULL;
+}
+
+static int
+serve_threads(int nthreads, int port, const char *db_path, void *zmq_ctx,
+ const char *send_endpoint, const char *recv_endpoint,
+ const char *log_base_path)
+{
+ int nfd;
+ uint32_t i;
+ if ((nfd = bind_socket(port)) < 0) {
+ print_error("cannot bind socket. please check port number with netstat.");
+ return -1;
+ }
+
+ for (i = 0; i < nthreads; i++) {
+ memset(&threads[i], 0, sizeof(threads[i]));
+ threads[i].request_reopen_log_file = GRN_FALSE;
+ if (!(threads[i].base = event_init())) {
+ print_error("error in event_init() on thread %d.", i);
+ } else {
+ if (!(threads[i].httpd = evhttp_new(threads[i].base))) {
+ print_error("error in evhttp_new() on thread %d.", i);
+ } else {
+ int r;
+ if ((r = evhttp_accept_socket(threads[i].httpd, nfd))) {
+ print_error("error in evhttp_accept_socket() on thread %d.", i);
+ } else {
+ if (send_endpoint) {
+ if (!(threads[i].zmq_sock = zmq_socket(zmq_ctx, ZMQ_PUB))) {
+ print_error("cannot create zmq_socket.");
+ } else if (zmq_connect(threads[i].zmq_sock, send_endpoint)) {
+ print_error("cannot connect zmq_socket.");
+ zmq_close(threads[i].zmq_sock);
+ threads[i].zmq_sock = NULL;
+ } else {
+ uint64_t hwm = 1;
+ zmq_setsockopt(threads[i].zmq_sock, ZMQ_SNDHWM, &hwm, sizeof(uint64_t));
+ }
+ } else {
+ threads[i].zmq_sock = NULL;
+ }
+ if (!(threads[i].ctx = grn_ctx_open(0))) {
+ print_error("error in grn_ctx_open() on thread %d.", i);
+ } else if (grn_ctx_use(threads[i].ctx, db)) {
+ print_error("error in grn_db_open() on thread %d.", i);
+ } else {
+ GRN_TEXT_INIT(&(threads[i].cmd_buf), 0);
+ GRN_TEXT_INIT(&(threads[i].pass_through_parameters), 0);
+ threads[i].log_base_path = log_base_path;
+ threads[i].thread_id = i;
+ evhttp_set_gencb(threads[i].httpd, generic_handler, &threads[i]);
+ evhttp_set_timeout(threads[i].httpd, 10);
+ {
+ struct timeval tv = {1, 0};
+ evtimer_set(&(threads[i].pulse), timeout_handler, &threads[i]);
+ evtimer_add(&(threads[i].pulse), &tv);
+ }
+ if ((r = pthread_create(&(threads[i].thd), NULL, dispatch, threads[i].base))) {
+ print_error("error in pthread_create() on thread %d.", i);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* recv thread from learner */
+ if (recv_endpoint) {
+ recv_thd_data rthd;
+ rthd.db_path = db_path;
+ rthd.recv_endpoint = recv_endpoint;
+ rthd.zmq_ctx = zmq_ctx;
+
+ if (pthread_create(&(rthd.thd), NULL, recv_from_learner, &rthd)) {
+ print_error("error in pthread_create() on thread %d.", i);
+ }
+ if (pthread_join(rthd.thd, NULL)) {
+ print_error("error in pthread_join() on thread %d.", i);
+ }
+ } else {
+ while (loop) { sleep(1); }
+ }
+
+ /* join all httpd thread */
+ for (i = 0; i < nthreads; i++) {
+ if (threads[i].thd) {
+ if (pthread_join(threads[i].thd, NULL)) {
+ print_error("error in pthread_join() on thread %d.", i);
+ }
+ }
+ cleanup_httpd_thread(&(threads[i]));
+ }
+ return 0;
+}
+
+static uint32_t
+get_core_number(void)
+{
+#ifdef ACTUALLY_GET_CORE_NUMBER
+#ifdef _SC_NPROCESSORS_CONF
+ return sysconf(_SC_NPROCESSORS_CONF);
+#else /* _SC_NPROCESSORS_CONF */
+ int n_processors;
+ size_t length = sizeof(n_processors);
+ int mib[] = {CTL_HW, HW_NCPU};
+ if (sysctl(mib, sizeof(mib) / sizeof(mib[0]),
+ &n_processors, &length, NULL, 0) == 0 &&
+ length == sizeof(n_processors) &&
+ 0 < n_processors) {
+ return n_processors;
+ } else {
+ return 1;
+ }
+#endif /* _SC_NPROCESSORS_CONF */
+#endif /* ACTUALLY_GET_CORE_NUMBER */
+ return 0;
+}
+
+static void
+usage(FILE *output)
+{
+ fprintf(
+ output,
+ "Usage: groonga-suggest-httpd [options...] db_path\n"
+ "db_path:\n"
+ " specify groonga database path which is used for suggestion.\n"
+ "\n"
+ "options:\n"
+ " -p, --port <port number> : http server port number\n"
+ " (default: %d)\n"
+ /*
+ " --address <ip/hostname> : server address to listen\n"
+ " (default: %s)\n"
+ */
+ " -c <thread number> : number of server threads\n"
+ " (deprecated. use --n-threads)\n"
+ " -t, --n-threads <thread number> : number of server threads\n"
+ " (default: %d)\n"
+ " -s, --send-endpoint <send endpoint> : send endpoint\n"
+ " (ex. tcp://example.com:1234)\n"
+ " -r, --receive-endpoint <receive endpoint> : receive endpoint\n"
+ " (ex. tcp://example.com:1235)\n"
+ " -l, --log-base-path <path prefix> : log path prefix\n"
+ " --n-lines-per-log-file <lines number> : number of lines in a log file\n"
+ " use 0 for disabling this\n"
+ " (default: %d)\n"
+ " -d, --daemon : daemonize\n"
+ " --disable-max-fd-check : disable max FD check on start\n"
+ " -h, --help : show this message\n",
+ DEFAULT_PORT, default_max_threads, n_lines_per_log_file);
+}
+
+int
+main(int argc, char **argv)
+{
+ int port_no = DEFAULT_PORT;
+ const char *max_threads_string = NULL, *port_string = NULL;
+ const char *address;
+ const char *send_endpoint = NULL, *recv_endpoint = NULL, *log_base_path = NULL;
+ const char *n_lines_per_log_file_string = NULL;
+ int n_processed_args, flags = RUN_MODE_ENABLE_MAX_FD_CHECK;
+ run_mode mode = run_mode_none;
+
+ if (!(default_max_threads = get_core_number())) {
+ default_max_threads = DEFAULT_MAX_THREADS;
+ }
+
+ /* parse options */
+ {
+ static grn_str_getopt_opt opts[] = {
+ {'c', NULL, NULL, 0, GETOPT_OP_NONE}, /* deprecated */
+ {'t', "n-threads", NULL, 0, GETOPT_OP_NONE},
+ {'h', "help", NULL, run_mode_usage, GETOPT_OP_UPDATE},
+ {'p', "port", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "bind-address", NULL, 0, GETOPT_OP_NONE}, /* not supported yet */
+ {'s', "send-endpoint", NULL, 0, GETOPT_OP_NONE},
+ {'r', "receive-endpoint", NULL, 0, GETOPT_OP_NONE},
+ {'l', "log-base-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "n-lines-per-log-file", NULL, 0, GETOPT_OP_NONE},
+ {'d', "daemon", NULL, run_mode_daemon, GETOPT_OP_UPDATE},
+ {'\0', "disable-max-fd-check", NULL, RUN_MODE_ENABLE_MAX_FD_CHECK,
+ GETOPT_OP_OFF},
+ {'\0', NULL, NULL, 0, 0}
+ };
+ opts[0].arg = &max_threads_string;
+ opts[1].arg = &max_threads_string;
+ opts[3].arg = &port_string;
+ opts[4].arg = &address;
+ opts[5].arg = &send_endpoint;
+ opts[6].arg = &recv_endpoint;
+ opts[7].arg = &log_base_path;
+ opts[8].arg = &n_lines_per_log_file_string;
+
+ n_processed_args = grn_str_getopt(argc, argv, opts, &flags);
+ }
+
+ /* main */
+ mode = (flags & RUN_MODE_MASK);
+ if (n_processed_args < 0 ||
+ (argc - n_processed_args) != 1 ||
+ mode == run_mode_error) {
+ usage(stderr);
+ return EXIT_FAILURE;
+ } else if (mode == run_mode_usage) {
+ usage(stdout);
+ return EXIT_SUCCESS;
+ } else {
+ grn_ctx ctx;
+ void *zmq_ctx;
+
+ if (max_threads_string) {
+ max_threads = atoi(max_threads_string);
+ if (max_threads > MAX_THREADS) {
+ print_error("too many threads. limit to %d.", MAX_THREADS);
+ max_threads = MAX_THREADS;
+ }
+ } else {
+ max_threads = default_max_threads;
+ }
+
+ if (port_string) {
+ port_no = atoi(port_string);
+ }
+
+ if (flags & RUN_MODE_ENABLE_MAX_FD_CHECK) {
+ /* check environment */
+ struct rlimit rlim;
+ if (!getrlimit(RLIMIT_NOFILE, &rlim)) {
+ if (rlim.rlim_max < MIN_MAX_FDS) {
+ print_error("too small max fds. %d required.", MIN_MAX_FDS);
+ return -1;
+ }
+ rlim.rlim_cur = rlim.rlim_cur;
+ setrlimit(RLIMIT_NOFILE, &rlim);
+ }
+ }
+
+ if (n_lines_per_log_file_string) {
+ int64_t n_lines;
+ n_lines = grn_atoll(n_lines_per_log_file_string,
+ n_lines_per_log_file_string + strlen(n_lines_per_log_file_string),
+ NULL);
+ if (n_lines < 0) {
+ print_error("--n-lines-per-log-file must be >= 0: <%s>",
+ n_lines_per_log_file_string);
+ return(EXIT_FAILURE);
+ }
+ if (n_lines > UINT32_MAX) {
+ print_error("--n-lines-per-log-file must be <= %ld: <%s>",
+ UINT32_MAX, n_lines_per_log_file_string);
+ return(EXIT_FAILURE);
+ }
+ n_lines_per_log_file = (uint32_t)n_lines;
+ }
+
+ if (mode == run_mode_daemon) {
+ daemonize();
+ }
+
+ grn_init();
+ grn_ctx_init(&ctx, 0);
+ if ((db = grn_db_open(&ctx, argv[n_processed_args]))) {
+ if ((zmq_ctx = zmq_init(1))) {
+ signal(SIGTERM, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGQUIT, signal_handler);
+ signal(SIGUSR1, signal_reopen_log_file);
+
+ serve_threads(max_threads, port_no, argv[n_processed_args], zmq_ctx,
+ send_endpoint, recv_endpoint, log_base_path);
+ zmq_term(zmq_ctx);
+ } else {
+ print_error("cannot create zmq context.");
+ }
+ grn_obj_close(&ctx, db);
+ } else {
+ print_error("cannot open db.");
+ }
+ grn_ctx_fin(&ctx);
+ grn_fin();
+ }
+ return 0;
+}
diff --git a/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_learner.c b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_learner.c
new file mode 100644
index 00000000..8109ae7f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/groonga_suggest_learner.c
@@ -0,0 +1,843 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2010-2015 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+
+/* for grn_str_getopt() */
+#include <grn_str.h>
+#include <grn_msgpack.h>
+
+#include "zmq_compatible.h"
+#include <stdio.h>
+#include <signal.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <groonga.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "util.h"
+
+#include <evhttp.h>
+
+#define DEFAULT_RECV_ENDPOINT "tcp://*:1234"
+#define DEFAULT_SEND_ENDPOINT "tcp://*:1235"
+#define SEND_WAIT 1000 /* 0.001sec */
+
+#define CONST_STR_LEN(x) x, x ? sizeof(x) - 1 : 0
+
+typedef enum {
+ RUN_MODE_NONE = 0x00,
+ RUN_MODE_USAGE = 0x01,
+ RUN_MODE_DAEMON = 0x02,
+ RUN_MODE_ERROR = 0x04
+} run_mode;
+
+#define RUN_MODE_MASK 0x007f
+
+typedef struct {
+ const char *db_path;
+ const char *send_endpoint;
+ pthread_t thd;
+ void *zmq_ctx;
+} send_thd_data;
+
+static volatile sig_atomic_t loop = 1;
+
+static void
+load_to_groonga(grn_ctx *ctx,
+ grn_obj *buf,
+ const char *query, uint32_t query_len,
+ const char *client_id, uint32_t client_id_len,
+ const char *learn_target_name, uint32_t learn_target_name_len,
+ uint64_t millisec,
+ int submit)
+{
+ GRN_BULK_REWIND(buf);
+ GRN_TEXT_PUTS(ctx, buf, "load --table event_");
+ GRN_TEXT_PUT(ctx, buf, learn_target_name, learn_target_name_len);
+ GRN_TEXT_PUTS(ctx, buf, " --each 'suggest_preparer(_id,type,item,sequence,time,pair_");
+ GRN_TEXT_PUT(ctx, buf, learn_target_name, learn_target_name_len);
+ GRN_TEXT_PUTS(ctx, buf, ")'");
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(buf), GRN_TEXT_LEN(buf), GRN_CTX_MORE);
+ grn_ctx_send(ctx, CONST_STR_LEN("["), GRN_CTX_MORE);
+
+ GRN_BULK_REWIND(buf);
+ GRN_TEXT_PUTS(ctx, buf, "{\"item\":");
+ grn_text_esc(ctx, buf, query, query_len);
+ GRN_TEXT_PUTS(ctx, buf, ",\"sequence\":");
+ grn_text_esc(ctx, buf, client_id, client_id_len);
+ GRN_TEXT_PUTS(ctx, buf, ",\"time\":");
+ grn_text_ftoa(ctx, buf, (double)millisec / 1000);
+ if (submit) {
+ GRN_TEXT_PUTS(ctx, buf, ",\"type\":\"submit\"}");
+ } else {
+ GRN_TEXT_PUTS(ctx, buf, "}");
+ }
+ /* printf("%.*s\n", GRN_TEXT_LEN(buf), GRN_TEXT_VALUE(buf)); */
+ grn_ctx_send(ctx, GRN_TEXT_VALUE(buf), GRN_TEXT_LEN(buf), GRN_CTX_MORE);
+
+ grn_ctx_send(ctx, CONST_STR_LEN("]"), 0);
+
+ {
+ char *res;
+ int flags;
+ unsigned int res_len;
+ grn_ctx_recv(ctx, &res, &res_len, &flags);
+ }
+}
+
+void
+load_to_multi_targets(grn_ctx *ctx,
+ grn_obj *buf,
+ const char *query, uint32_t query_len,
+ const char *client_id, uint32_t client_id_len,
+ const char *learn_target_names,
+ uint32_t learn_target_names_len,
+ uint64_t millisec,
+ int submit)
+{
+ if (millisec && query && client_id && learn_target_names) {
+ unsigned int tn_len;
+ const char *tn, *tnp, *tne;
+ tn = tnp = learn_target_names;
+ tne = learn_target_names + learn_target_names_len;
+ while (tnp <= tne) {
+ if (tnp == tne || *tnp == '|') {
+ tn_len = tnp - tn;
+
+ /*
+ printf("sec: %" PRIu64 " query %.*s client_id: %.*s target: %.*s\n",
+ millisec,
+ query_len, query,
+ client_id_len, client_id,
+ tn_len, tn);
+ */
+ load_to_groonga(ctx, buf, query, query_len, client_id, client_id_len,
+ tn, tn_len, millisec, submit);
+
+ tn = ++tnp;
+ } else {
+ tnp++;
+ }
+ }
+ }
+}
+
+#define PACK_KEY_FROM_ID(id) do { \
+ int _k_len; \
+ char _k_buf[GRN_TABLE_MAX_KEY_SIZE]; \
+ _k_len = grn_table_get_key(ctx, ref_table, (id), _k_buf, GRN_TABLE_MAX_KEY_SIZE); \
+ msgpack_pack_str(&pk, _k_len); \
+ msgpack_pack_str_body(&pk, _k_buf, _k_len); \
+} while (0)
+
+#define PACK_MAP_ITEM(col_name) do { \
+ grn_obj _v; \
+ msgpack_pack_str(&pk, sizeof(#col_name) - 1); \
+ msgpack_pack_str_body(&pk, #col_name, sizeof(#col_name) - 1); \
+ switch (col_##col_name->header.type) { \
+ case GRN_COLUMN_FIX_SIZE: \
+ GRN_VALUE_FIX_SIZE_INIT(&_v, 0, grn_obj_get_range(ctx, col_##col_name)); \
+ break; \
+ case GRN_COLUMN_VAR_SIZE: \
+ if ((col_##col_name->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) == GRN_OBJ_COLUMN_VECTOR) { \
+ GRN_VALUE_FIX_SIZE_INIT(&_v, GRN_OBJ_VECTOR, grn_obj_get_range(ctx, col_##col_name)); \
+ } else { \
+ GRN_VALUE_VAR_SIZE_INIT(&_v, 0, grn_obj_get_range(ctx, col_##col_name)); \
+ } \
+ break; \
+ } \
+ grn_obj_get_value(ctx, col_##col_name, rec_id, &_v); \
+ \
+ switch (_v.header.type) { \
+ case GRN_BULK: \
+ switch (_v.header.domain) { \
+ case GRN_DB_SHORT_TEXT: \
+ msgpack_pack_str(&pk, GRN_TEXT_LEN(&_v)); \
+ msgpack_pack_str_body(&pk, GRN_TEXT_VALUE(&_v), GRN_TEXT_LEN(&_v)); \
+ break; \
+ case GRN_DB_INT32: \
+ msgpack_pack_int32(&pk, GRN_INT32_VALUE(&_v)); \
+ break; \
+ case GRN_DB_UINT32: \
+ msgpack_pack_uint32(&pk, GRN_UINT32_VALUE(&_v)); \
+ break; \
+ case GRN_DB_TIME: \
+ msgpack_pack_double(&pk, (double)GRN_TIME_VALUE(&_v) / GRN_TIME_USEC_PER_SEC); \
+ break; \
+ default: /* ref. to ShortText key */ \
+ PACK_KEY_FROM_ID(GRN_RECORD_VALUE(&_v)); \
+ } \
+ break; \
+ case GRN_UVECTOR: /* ref.s to ShortText key */ \
+ { \
+ grn_id *_idv = (grn_id *)GRN_BULK_HEAD(&_v), *_idve = (grn_id *)GRN_BULK_CURR(&_v); \
+ msgpack_pack_array(&pk, _idve - _idv); \
+ for (; _idv < _idve; _idv++) { \
+ PACK_KEY_FROM_ID(*_idv); \
+ } \
+ } \
+ break; \
+ default: \
+ print_error("invalid groonga object type(%d) for msgpack.", _v.header.type); \
+ msgpack_pack_nil(&pk); \
+ break; \
+ } \
+ grn_obj_close(ctx, &_v); \
+} while (0)
+
+static int
+zmq_send_to_httpd(void *zmq_send_sock, void *data, size_t size)
+{
+ zmq_msg_t msg;
+ if (!zmq_msg_init_size(&msg, size)) {
+ memcpy((void *)zmq_msg_data(&msg), data, size);
+ if (zmq_msg_send(&msg, zmq_send_sock, 0) == -1) {
+ print_error("zmq_send() error");
+ return -1;
+ }
+ zmq_msg_close(&msg);
+ } else {
+ print_error("zmq_msg_init_size() error");
+ }
+ return 0;
+}
+
+static void
+send_handler(void *zmq_send_sock, grn_ctx *ctx)
+{
+ grn_table_cursor *cur;
+ if ((cur = grn_table_cursor_open(ctx, grn_ctx_db(ctx), NULL, 0, NULL, 0,
+ 0, -1, 0))) {
+ grn_id table_id;
+ while (loop && (table_id = grn_table_cursor_next(ctx, cur)) != GRN_ID_NIL) {
+ grn_obj *table;
+ if ((table = grn_ctx_at(ctx, table_id))) {
+ int name_len;
+ char name_buf[GRN_TABLE_MAX_KEY_SIZE];
+
+ name_len = grn_obj_name(ctx, table, name_buf,
+ GRN_TABLE_MAX_KEY_SIZE);
+
+ if (name_len > 5) {
+ if (table->header.type == GRN_TABLE_PAT_KEY &&
+ !memcmp(name_buf, CONST_STR_LEN("item_"))) {
+ /* ["_key","ShortText"],["last","Time"],["kana","kana"],["freq2","Int32"],["freq","Int32"],["co","pair_all"],["buzz","Int32"],["boost","Int32"] */
+ grn_obj *ref_table;
+ grn_table_cursor *tc;
+ grn_obj *col_last, *col_kana, *col_freq, *col_freq2,
+ *col_buzz, *col_boost;
+
+ col_kana = grn_obj_column(ctx, table, CONST_STR_LEN("kana"));
+ col_freq = grn_obj_column(ctx, table, CONST_STR_LEN("freq"));
+ col_last = grn_obj_column(ctx, table, CONST_STR_LEN("last"));
+ col_boost = grn_obj_column(ctx, table, CONST_STR_LEN("boost"));
+ col_freq2 = grn_obj_column(ctx, table, CONST_STR_LEN("freq2"));
+ col_buzz = grn_obj_column(ctx, table, CONST_STR_LEN("buzz"));
+
+ ref_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, col_kana));
+
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL,
+ 0, 0, -1, 0))) {
+ grn_id rec_id;
+ while (loop && (rec_id = grn_table_cursor_next(ctx, tc))
+ != GRN_ID_NIL) {
+ char *key;
+ size_t key_len;
+ msgpack_packer pk;
+ msgpack_sbuffer sbuf;
+
+ msgpack_sbuffer_init(&sbuf);
+ msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
+
+ msgpack_pack_map(&pk, 8);
+
+ /* ["_key","ShortText"],["last","Time"],["kana","kana"],["freq2","Int32"],["freq","Int32"],["co","pair_all"],["buzz","Int32"],["boost","Int32"] */
+ msgpack_pack_str(&pk, 6);
+ msgpack_pack_str_body(&pk, "target", strlen("target"));
+ msgpack_pack_str(&pk, name_len);
+ msgpack_pack_str_body(&pk, name_buf, name_len);
+
+ msgpack_pack_str(&pk, 4);
+ msgpack_pack_str_body(&pk,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ key_len = grn_table_cursor_get_key(ctx, tc, (void **)&key);
+ msgpack_pack_str(&pk, key_len);
+ msgpack_pack_str_body(&pk, key, key_len);
+
+ PACK_MAP_ITEM(last);
+ PACK_MAP_ITEM(kana);
+ PACK_MAP_ITEM(freq);
+ PACK_MAP_ITEM(freq2);
+ PACK_MAP_ITEM(buzz);
+ PACK_MAP_ITEM(boost);
+
+ zmq_send_to_httpd(zmq_send_sock, sbuf.data, sbuf.size);
+
+ usleep(SEND_WAIT);
+
+ msgpack_sbuffer_destroy(&sbuf);
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ } else if (table->header.type == GRN_TABLE_HASH_KEY &&
+ !memcmp(name_buf, CONST_STR_LEN("pair_"))) {
+ grn_obj *ref_table;
+ grn_table_cursor *tc;
+ grn_obj *col_pre, *col_post, *col_freq0, *col_freq1, *col_freq2;
+
+ col_pre = grn_obj_column(ctx, table, CONST_STR_LEN("pre"));
+ col_post = grn_obj_column(ctx, table, CONST_STR_LEN("post"));
+ col_freq0 = grn_obj_column(ctx, table, CONST_STR_LEN("freq0"));
+ col_freq1 = grn_obj_column(ctx, table, CONST_STR_LEN("freq1"));
+ col_freq2 = grn_obj_column(ctx, table, CONST_STR_LEN("freq2"));
+
+ ref_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, col_pre));
+
+ if ((tc = grn_table_cursor_open(ctx, table, NULL, 0, NULL,
+ 0, 0, -1, 0))) {
+ grn_id rec_id;
+ while (loop && (rec_id = grn_table_cursor_next(ctx, tc))
+ != GRN_ID_NIL) {
+ uint64_t *key;
+ msgpack_packer pk;
+ msgpack_sbuffer sbuf;
+
+ /* skip freq0 == 0 && freq1 == 0 && freq2 == 0 */
+ {
+ grn_obj f;
+ grn_obj_get_value(ctx, col_freq0, rec_id, &f);
+ if (!GRN_INT32_VALUE(&f)) {
+ grn_obj_get_value(ctx, col_freq1, rec_id, &f);
+ if (!GRN_INT32_VALUE(&f)) {
+ grn_obj_get_value(ctx, col_freq2, rec_id, &f);
+ if (!GRN_INT32_VALUE(&f)) { continue; }
+ }
+ }
+ }
+
+ /* make pair_* message */
+ msgpack_sbuffer_init(&sbuf);
+ msgpack_packer_init(&pk, &sbuf, msgpack_sbuffer_write);
+
+ msgpack_pack_map(&pk, 7);
+ /* ["_key","UInt64"],["pre","item_all"],["post","item_all"],["freq2","Int32"],["freq1","Int32"],["freq0","Int32"] */
+
+ msgpack_pack_str(&pk, 6);
+ msgpack_pack_str_body(&pk, "target", strlen("target"));
+ msgpack_pack_str(&pk, name_len);
+ msgpack_pack_str_body(&pk, name_buf, name_len);
+
+ msgpack_pack_str(&pk, 4);
+ msgpack_pack_str_body(&pk,
+ GRN_COLUMN_NAME_KEY,
+ GRN_COLUMN_NAME_KEY_LEN);
+ grn_table_cursor_get_key(ctx, tc, (void **)&key);
+ msgpack_pack_uint64(&pk, *key);
+
+ PACK_MAP_ITEM(pre);
+ PACK_MAP_ITEM(post);
+ PACK_MAP_ITEM(freq0);
+ PACK_MAP_ITEM(freq1);
+ PACK_MAP_ITEM(freq2);
+
+ zmq_send_to_httpd(zmq_send_sock, sbuf.data, sbuf.size);
+
+ usleep(SEND_WAIT);
+
+ msgpack_sbuffer_destroy(&sbuf);
+ }
+ grn_table_cursor_close(ctx, tc);
+ }
+ }
+ }
+ grn_obj_unlink(ctx, table);
+ }
+ }
+ grn_table_cursor_close(ctx, cur);
+ }
+}
+
+static void *
+send_to_httpd(void *arg)
+{
+ send_thd_data *thd = arg;
+ void *zmq_send_sock;
+ if ((zmq_send_sock = zmq_socket(thd->zmq_ctx, ZMQ_PUB))) {
+ if (!zmq_bind(zmq_send_sock, thd->send_endpoint)) {
+ grn_ctx ctx;
+ if (!(grn_ctx_init(&ctx, 0))) {
+ grn_obj *db;
+ if ((db = grn_db_open(&ctx, thd->db_path))) {
+ uint64_t hwm = 1;
+ zmq_setsockopt(zmq_send_sock, ZMQ_SNDHWM, &hwm, sizeof(uint64_t));
+ while (loop) {
+ send_handler(zmq_send_sock, &ctx);
+ }
+ grn_obj_close(&ctx, db);
+ } else {
+ print_error("error in grn_db_open() on send thread.");
+ }
+ grn_ctx_fin(&ctx);
+ } else {
+ print_error("error in grn_ctx_init() on send thread.");
+ }
+ } else {
+ print_error("cannot bind zmq_socket.");
+ }
+ } else {
+ print_error("cannot create zmq_socket.");
+ }
+ return NULL;
+}
+
+static void
+handle_msg(msgpack_object *obj, grn_ctx *ctx, grn_obj *buf)
+{
+ int submit_flag = 0;
+ uint64_t millisec = 0;
+ const char *query = NULL,
+ *client_id = NULL, *learn_target_names = NULL;
+ uint32_t query_len = 0, client_id_len = 0, learn_target_names_len = 0;
+ if (obj->type == MSGPACK_OBJECT_MAP) {
+ int i;
+ for (i = 0; i < obj->via.map.size; i++) {
+ msgpack_object_kv *kv;
+ msgpack_object *key;
+ msgpack_object *value;
+ kv = &(obj->via.map.ptr[i]);
+ key = &(kv->key);
+ value = &(kv->val);
+ if (key->type == MSGPACK_OBJECT_STR && MSGPACK_OBJECT_STR_SIZE(key) > 0) {
+ switch (MSGPACK_OBJECT_STR_PTR(key)[0]) {
+ case 'i':
+ if (value->type == MSGPACK_OBJECT_STR) {
+ client_id_len = MSGPACK_OBJECT_STR_SIZE(value);
+ client_id = MSGPACK_OBJECT_STR_PTR(value);
+ }
+ break;
+ case 'q':
+ if (value->type == MSGPACK_OBJECT_STR) {
+ query_len = MSGPACK_OBJECT_STR_SIZE(value);
+ query = MSGPACK_OBJECT_STR_PTR(value);
+ }
+ break;
+ case 'l':
+ if (value->type == MSGPACK_OBJECT_STR) {
+ learn_target_names_len = MSGPACK_OBJECT_STR_SIZE(value);
+ learn_target_names = MSGPACK_OBJECT_STR_PTR(value);
+ }
+ break;
+ case 's':
+ if (kv->val.type == MSGPACK_OBJECT_POSITIVE_INTEGER) {
+ millisec = kv->val.via.u64;
+ }
+ break;
+ case 't':
+ if (kv->val.type == MSGPACK_OBJECT_BOOLEAN) {
+ submit_flag = (kv->val.via.boolean ? 1 : 0);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ load_to_multi_targets(ctx, buf, query, query_len,
+ client_id, client_id_len,
+ learn_target_names, learn_target_names_len,
+ millisec, submit_flag);
+ }
+}
+
+static void
+recv_event_loop(msgpack_zone *mempool, void *zmq_sock, grn_ctx *ctx)
+{
+ grn_obj buf;
+ zmq_pollitem_t items[] = {
+ { zmq_sock, 0, ZMQ_POLLIN, 0}
+ };
+ GRN_TEXT_INIT(&buf, 0);
+ while (loop) {
+ zmq_poll(items, 1, 10000);
+ if (items[0].revents & ZMQ_POLLIN) { /* always true */
+ zmq_msg_t msg;
+ if (zmq_msg_init(&msg)) {
+ print_error("cannot init zmq message.");
+ } else {
+ if (zmq_msg_recv(&msg, zmq_sock, 0) == -1) {
+ print_error("cannot recv zmq message.");
+ } else {
+ msgpack_object obj;
+ msgpack_unpack_return ret;
+ ret = msgpack_unpack(zmq_msg_data(&msg), zmq_msg_size(&msg), NULL, mempool, &obj);
+ if (MSGPACK_UNPACK_SUCCESS == ret) {
+ /* msgpack_object_print(stdout, obj); */
+ handle_msg(&obj, ctx, &buf);
+ }
+ msgpack_zone_clear(mempool);
+ }
+ zmq_msg_close(&msg);
+ }
+ }
+ }
+ grn_obj_unlink(ctx, &buf);
+}
+
+struct _suggest_log_file {
+ FILE *fp;
+ char *path;
+ uint64_t line;
+ /* datas from one line */
+ int submit;
+ char *query;
+ uint64_t millisec;
+ char *client_id;
+ char *learn_target_name;
+ /* link list */
+ struct _suggest_log_file *next;
+};
+typedef struct _suggest_log_file suggest_log_file;
+
+#if 0
+static void
+print_log_file_list(suggest_log_file *list)
+{
+ while (list) {
+ printf("fp:%p millisec:%" PRIu64 " next:%p\n",
+ list->fp, list->millisec, list->next);
+ list = list->next;
+ }
+}
+#endif
+
+static void
+free_log_line_data(suggest_log_file *l)
+{
+ if (l->query) {
+ free(l->query);
+ l->query = NULL;
+ }
+ if (l->client_id) {
+ free(l->client_id);
+ l->client_id = NULL;
+ }
+ if (l->learn_target_name) {
+ free(l->learn_target_name);
+ l->learn_target_name = NULL;
+ }
+}
+
+#define MAX_LOG_LENGTH 0x2000
+
+static void
+read_log_line(suggest_log_file **list)
+{
+ suggest_log_file *t = *list;
+ char line_buf[MAX_LOG_LENGTH];
+ while (1) {
+ free_log_line_data(t);
+ if (fgets(line_buf, MAX_LOG_LENGTH, t->fp)) {
+ char *eol;
+ t->line++;
+ if ((eol = strrchr(line_buf, '\n'))) {
+ const char *query, *types, *client_id, *learn_target_name;
+ struct evkeyvalq get_args;
+ *eol = '\0';
+ evhttp_parse_query(line_buf, &get_args);
+ parse_keyval(NULL,
+ &get_args, &query, &types, &client_id, NULL,
+ &learn_target_name, NULL, &(t->millisec), NULL, NULL, NULL,
+ NULL);
+ if (query && client_id && learn_target_name && t->millisec) {
+ t->query = evhttp_decode_uri(query);
+ t->submit = (types && !strcmp(types, "submit"));
+ t->client_id = evhttp_decode_uri(client_id);
+ t->learn_target_name = evhttp_decode_uri(learn_target_name);
+ evhttp_clear_headers(&get_args);
+ break;
+ }
+ print_error("invalid line path:%s line:%" PRIu64,
+ t->path, t->line);
+ evhttp_clear_headers(&get_args);
+ } else {
+ /* read until new line */
+ while (1) {
+ int c = fgetc(t->fp);
+ if (c == '\n' || c == EOF) { break; }
+ }
+ }
+ } else {
+ /* terminate reading log */
+ fclose(t->fp);
+ free(t->path);
+ *list = t->next;
+ free(t);
+ break;
+ }
+ }
+}
+
+/* re-sorting by list->millisec asc with moving a head item. */
+static void
+sort_log_file_list(suggest_log_file **list)
+{
+ suggest_log_file *p, *target;
+ target = *list;
+ if (!target || !target->next || target->millisec < target->next->millisec) {
+ return;
+ }
+ *list = target->next;
+ for (p = *list; p; p = p->next) {
+ if (!p->next || target->millisec > p->next->millisec) {
+ target->next = p->next;
+ p->next = target;
+ return;
+ }
+ }
+}
+
+#define PATH_SEPARATOR '/'
+
+static suggest_log_file *
+gather_log_file(const char *dir_path, unsigned int dir_path_len)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ char path[PATH_MAX + 1];
+ suggest_log_file *list = NULL;
+ if (!(dir = opendir(dir_path))) {
+ print_error("cannot open log directory.");
+ return NULL;
+ }
+ memcpy(path, dir_path, dir_path_len);
+ path[dir_path_len] = PATH_SEPARATOR;
+ while ((dirent = readdir(dir))) {
+ struct stat fstat;
+ unsigned int d_namlen, path_len;
+ if (*(dirent->d_name) == '.' && (
+ dirent->d_name[1] == '\0' ||
+ (dirent->d_name[1] == '.' && dirent->d_name[2] == '\0'))) {
+ continue;
+ }
+ d_namlen = strlen(dirent->d_name);
+ path_len = dir_path_len + 1 + d_namlen;
+ if (dir_path_len + d_namlen >= PATH_MAX) { continue; }
+ memcpy(path + dir_path_len + 1, dirent->d_name, d_namlen);
+ path[path_len] = '\0';
+ lstat(path, &fstat);
+ if (S_ISDIR(fstat.st_mode)) {
+ gather_log_file(path, path_len);
+ } else {
+ suggest_log_file *p = calloc(1, sizeof(suggest_log_file));
+ if (!(p->fp = fopen(path, "r"))) {
+ free(p);
+ } else {
+ if (list) {
+ p->next = list;
+ }
+ p->path = strdup(path);
+ list = p;
+ read_log_line(&list);
+ sort_log_file_list(&list);
+ }
+ }
+ /* print_log_file_list(list); */
+ }
+ return list;
+}
+
+static void
+load_log(grn_ctx *ctx, const char *log_dir_name)
+{
+ grn_obj buf;
+ suggest_log_file *list;
+ GRN_TEXT_INIT(&buf, 0);
+ list = gather_log_file(log_dir_name, strlen(log_dir_name));
+ while (list) {
+ /*
+ printf("file:%s line:%" PRIu64 " query:%s millisec:%" PRIu64 "\n",
+ list->path, list->line, list->query, list->millisec);
+ */
+ load_to_multi_targets(ctx, &buf,
+ list->query, strlen(list->query),
+ list->client_id, strlen(list->client_id),
+ list->learn_target_name, strlen(list->learn_target_name),
+ list->millisec,
+ list->submit);
+ read_log_line(&list);
+ sort_log_file_list(&list);
+ }
+ grn_obj_close(ctx, &buf);
+}
+
+static void
+usage(FILE *output)
+{
+ fprintf(output,
+ "Usage: groonga-suggest-learner [options...] db_path\n"
+ "options:\n"
+ " -r <recv endpoint>: recv endpoint (default: %s)\n"
+ " --receive-endpoint <recv endpoint>\n"
+ "\n"
+ " -s <send endpoint>: send endpoint (default: %s)\n"
+ " --send-endpoint <send endpoint>\n"
+ "\n"
+ " -l <log directory>: load from log files made on webserver.\n"
+ " --log-base-path <log directory>\n"
+ "\n"
+ " --log-path <path> : output logs to <path>\n"
+ " --log-level <level> : set log level to <level> (default: %d)\n"
+ " -d, --daemon : daemonize\n",
+ DEFAULT_RECV_ENDPOINT, DEFAULT_SEND_ENDPOINT,
+ GRN_LOG_DEFAULT_LEVEL);
+}
+
+static void
+signal_handler(int sig)
+{
+ loop = 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ run_mode mode = RUN_MODE_NONE;
+ int n_processed_args;
+ const char *recv_endpoint = DEFAULT_RECV_ENDPOINT;
+ const char *send_endpoint = DEFAULT_SEND_ENDPOINT;
+ const char *log_base_path = NULL;
+ const char *db_path = NULL;
+
+ /* parse options */
+ {
+ int flags = mode;
+ const char *log_path = NULL;
+ const char *log_level = NULL;
+ static grn_str_getopt_opt opts[] = {
+ {'r', "receive-endpoint", NULL, 0, GETOPT_OP_NONE},
+ {'s', "send-endpoint", NULL, 0, GETOPT_OP_NONE},
+ {'l', "log-base-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "log-path", NULL, 0, GETOPT_OP_NONE},
+ {'\0', "log-level", NULL, 0, GETOPT_OP_NONE},
+ {'d', "daemon", NULL, RUN_MODE_DAEMON, GETOPT_OP_UPDATE},
+ {'h', "help", NULL, RUN_MODE_USAGE, GETOPT_OP_UPDATE},
+ {'\0', NULL, NULL, 0, 0}
+ };
+ opts[0].arg = &recv_endpoint;
+ opts[1].arg = &send_endpoint;
+ opts[2].arg = &log_base_path;
+ opts[3].arg = &log_path;
+ opts[4].arg = &log_level;
+
+ n_processed_args = grn_str_getopt(argc, argv, opts, &flags);
+
+ if (log_path) {
+ grn_default_logger_set_path(log_path);
+ }
+
+ if (log_level) {
+ const char * const end = log_level + strlen(log_level);
+ const char *rest = NULL;
+ const int value = grn_atoi(log_level, end, &rest);
+ if (end != rest || value < 0 || value > 9) {
+ fprintf(stderr, "invalid log level: <%s>\n", log_level);
+ return EXIT_FAILURE;
+ }
+ grn_default_logger_set_max_level(value);
+ }
+
+ mode = (flags & RUN_MODE_MASK);
+
+ if (mode & RUN_MODE_USAGE) {
+ usage(stdout);
+ return EXIT_SUCCESS;
+ }
+
+ if ((n_processed_args < 0) ||
+ (argc - n_processed_args) != 1) {
+ usage(stderr);
+ }
+
+ db_path = argv[n_processed_args];
+ }
+
+ /* main */
+ {
+ grn_ctx *ctx;
+ msgpack_zone *mempool;
+
+ if (mode == RUN_MODE_DAEMON) {
+ daemonize();
+ }
+
+ grn_init();
+
+ ctx = grn_ctx_open(0);
+ if (!(grn_db_open(ctx, db_path))) {
+ print_error("cannot open database.");
+ } else {
+ if (log_base_path) {
+ /* loading log mode */
+ load_log(ctx, log_base_path);
+ } else {
+ /* zeromq/msgpack recv mode */
+ if (!(mempool = msgpack_zone_new(MSGPACK_ZONE_CHUNK_SIZE))) {
+ print_error("cannot create msgpack zone.");
+ } else {
+ void *zmq_ctx, *zmq_recv_sock;
+ if (!(zmq_ctx = zmq_init(1))) {
+ print_error("cannot create zmq context.");
+ } else {
+ if (!(zmq_recv_sock = zmq_socket(zmq_ctx, ZMQ_SUB))) {
+ print_error("cannot create zmq_socket.");
+ } else if (zmq_bind(zmq_recv_sock, recv_endpoint)) {
+ print_error("cannot bind zmq_socket.");
+ } else {
+ send_thd_data thd;
+
+ signal(SIGTERM, signal_handler);
+ signal(SIGINT, signal_handler);
+ signal(SIGQUIT, signal_handler);
+
+ zmq_setsockopt(zmq_recv_sock, ZMQ_SUBSCRIBE, "", 0);
+ thd.db_path = db_path;
+ thd.send_endpoint = send_endpoint;
+ thd.zmq_ctx = zmq_ctx;
+
+ if (pthread_create(&(thd.thd), NULL, send_to_httpd, &thd)) {
+ print_error("error in pthread_create() for sending datas.");
+ }
+ recv_event_loop(mempool, zmq_recv_sock, ctx);
+ if (pthread_join(thd.thd, NULL)) {
+ print_error("error in pthread_join() for waiting completion of sending data.");
+ }
+ }
+ zmq_term(zmq_ctx);
+ }
+ msgpack_zone_free(mempool);
+ }
+ }
+ }
+ grn_obj_close(ctx, grn_ctx_db(ctx));
+ grn_ctx_fin(ctx);
+ grn_fin();
+ }
+ return 0;
+}
diff --git a/storage/mroonga/vendor/groonga/src/suggest/httpd_sources.am b/storage/mroonga/vendor/groonga/src/suggest/httpd_sources.am
new file mode 100644
index 00000000..a09328d5
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/httpd_sources.am
@@ -0,0 +1,3 @@
+groonga_suggest_httpd_SOURCES = \
+ groonga_suggest_httpd.c \
+ zmq_compatible.h
diff --git a/storage/mroonga/vendor/groonga/src/suggest/learner_sources.am b/storage/mroonga/vendor/groonga/src/suggest/learner_sources.am
new file mode 100644
index 00000000..03b49087
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/learner_sources.am
@@ -0,0 +1,3 @@
+groonga_suggest_learner_SOURCES = \
+ groonga_suggest_learner.c \
+ zmq_compatible.h
diff --git a/storage/mroonga/vendor/groonga/src/suggest/util.c b/storage/mroonga/vendor/groonga/src/suggest/util.c
new file mode 100644
index 00000000..e455a257
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/util.c
@@ -0,0 +1,215 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2010- Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "util.h"
+
+#define DEFAULT_FREQUENCY_THRESHOLD 100
+#define DEFAULT_CONDITIONAL_PROBABILITY_THRESHOLD 0.2
+
+int
+print_error(const char *format, ...)
+{
+ int r;
+ va_list l;
+
+ va_start(l, format);
+ vfprintf(stderr, format, l);
+ r = fprintf(stderr, "\n");
+ fflush(stderr);
+ va_end(l);
+
+ return r;
+}
+
+int
+daemonize(void)
+{
+ pid_t pid;
+
+ switch (fork()) {
+ case 0:
+ break;
+ case -1:
+ print_error("fork failed.");
+ return -1;
+ default:
+ wait(NULL);
+ _exit(0);
+ }
+ switch ((pid = fork())) {
+ case 0:
+ break;
+ case -1:
+ perror("fork");
+ return -1;
+ default:
+ fprintf(stderr, "%d\n", pid);
+ _exit(0);
+ }
+ {
+ int null_fd = open("/dev/null", O_RDWR, 0);
+ if (null_fd != -1) {
+ dup2(null_fd, 0);
+ dup2(null_fd, 1);
+ dup2(null_fd, 2);
+ if (null_fd > 2) { close(null_fd); }
+ }
+ }
+ return 1;
+}
+
+static uint64_t
+atouint64_t(const char *s)
+{
+ uint64_t r;
+ for (r = 0; *s; s++) {
+ r *= 10;
+ r += (*s - '0');
+ }
+ return r;
+}
+
+void
+parse_keyval(grn_ctx *ctx,
+ struct evkeyvalq *get_args,
+ const char **query, const char **types,
+ const char **client_id, const char **target_name,
+ const char **learn_target_name,
+ const char **callback,
+ uint64_t *millisec,
+ int *frequency_threshold,
+ double *conditional_probability_threshold,
+ int *limit,
+ grn_obj *pass_through_parameters)
+{
+ struct evkeyval *get;
+
+ if (query) { *query = NULL; }
+ if (types) { *types = NULL; }
+ if (client_id) { *client_id = NULL; }
+ if (target_name) { *target_name = NULL; }
+ if (learn_target_name) { *learn_target_name = NULL; }
+ if (callback) { *callback = NULL; }
+ if (millisec) { *millisec = 0; }
+ if (frequency_threshold) {
+ *frequency_threshold = DEFAULT_FREQUENCY_THRESHOLD;
+ }
+ if (conditional_probability_threshold) {
+ *conditional_probability_threshold = DEFAULT_CONDITIONAL_PROBABILITY_THRESHOLD;
+ }
+ if (limit) { *limit = -1; }
+
+ TAILQ_FOREACH(get, get_args, next) {
+ grn_bool is_pass_through_parameter = GRN_FALSE;
+ size_t key_length;
+
+ key_length = strlen(get->key);
+ switch (key_length) {
+ case 0:
+ break;
+ case 1:
+ switch(get->key[0]) {
+ case 'q':
+ if (query) {
+ *query = get->value;
+ }
+ break;
+ case 't':
+ /* TODO: check types */
+ if (types) {
+ *types = get->value;
+ }
+ break;
+ case 'i':
+ if (client_id) {
+ *client_id = get->value;
+ }
+ break;
+ case 's':
+ if (millisec) {
+ *millisec = atouint64_t(get->value);
+ }
+ break;
+ case 'n':
+ /* TODO: check target_name */
+ if (target_name) {
+ *target_name = get->value;
+ }
+ break;
+ case 'l':
+ if (learn_target_name) {
+ *learn_target_name = get->value;
+ }
+ break;
+ case 'h':
+ if (frequency_threshold) {
+ *frequency_threshold = atoi(get->value);
+ }
+ break;
+ case 'p':
+ if (conditional_probability_threshold) {
+ *conditional_probability_threshold = strtod(get->value, NULL);
+ }
+ break;
+ case 'm':
+ if (limit) {
+ *limit = atoi(get->value);
+ }
+ break;
+ default:
+ is_pass_through_parameter = GRN_TRUE;
+ break;
+ }
+ break;
+ default:
+ switch (get->key[0]) {
+ case 'c':
+ if (!strcmp(get->key, "callback")) {
+ if (callback) {
+ *callback = get->value;
+ }
+ } else {
+ is_pass_through_parameter = GRN_TRUE;
+ }
+ break;
+ default:
+ is_pass_through_parameter = GRN_TRUE;
+ }
+ }
+
+ if (is_pass_through_parameter && pass_through_parameters) {
+ if (GRN_TEXT_LEN(pass_through_parameters) > 0) {
+ GRN_TEXT_PUTS(ctx, pass_through_parameters, "&");
+ }
+ grn_text_urlenc(ctx, pass_through_parameters, get->key, strlen(get->key));
+ GRN_TEXT_PUTS(ctx, pass_through_parameters, "=");
+ grn_text_urlenc(ctx, pass_through_parameters,
+ get->value, strlen(get->value));
+ }
+ }
+}
diff --git a/storage/mroonga/vendor/groonga/src/suggest/util.h b/storage/mroonga/vendor/groonga/src/suggest/util.h
new file mode 100644
index 00000000..eb36edfd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/util.h
@@ -0,0 +1,40 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2010- Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#ifndef GRN_SUGGEST_UTIL_H
+#define GRN_SUGGEST_UTIL_H
+
+#include <sys/queue.h>
+#include <event.h>
+#include <stdint.h>
+
+#include <groonga.h>
+
+int print_error(const char *format, ...);
+int daemonize(void);
+void parse_keyval(grn_ctx *ctx,
+ struct evkeyvalq *get_args,
+ const char **query, const char **types,
+ const char **client_id, const char **target_name,
+ const char **learn_target_name,
+ const char **callback,
+ uint64_t *millisec,
+ int *frequency_threshold,
+ double *conditional_probability_threshold,
+ int *limit,
+ grn_obj *pass_through_parameters);
+
+#endif /* GRN_SUGGEST_UTIL_H */
diff --git a/storage/mroonga/vendor/groonga/src/suggest/util_sources.am b/storage/mroonga/vendor/groonga/src/suggest/util_sources.am
new file mode 100644
index 00000000..d4b74860
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/util_sources.am
@@ -0,0 +1,3 @@
+libutil_la_SOURCES = \
+ util.c \
+ util.h
diff --git a/storage/mroonga/vendor/groonga/src/suggest/zmq_compatible.h b/storage/mroonga/vendor/groonga/src/suggest/zmq_compatible.h
new file mode 100644
index 00000000..e4897f68
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/src/suggest/zmq_compatible.h
@@ -0,0 +1,33 @@
+/* -*- c-basic-offset: 2 -*- */
+/* Copyright(C) 2013 Brazil
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License version 2.1 as published by the Free Software Foundation.
+
+ 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-1335 USA
+*/
+#ifndef GRN_SUGGEST_ZMQ_COMPATIBLE_H
+#define GRN_SUGGEST_ZMQ_COMPATIBLE_H
+
+#include <zmq.h>
+
+#ifndef ZMQ_SNDHWM
+# define ZMQ_SNDHWM ZMQ_HWM
+#endif
+
+#if ZMQ_VERSION_MAJOR == 2
+# define zmq_msg_send(message, socket, flags) \
+ zmq_send((socket), (message), (flags))
+# define zmq_msg_recv(message, socket, flags) \
+ zmq_recv((socket), (message), (flags))
+#endif
+
+#endif /* GRN_SUGGEST_ZMQ_COMPATIBLE_H */
diff --git a/storage/mroonga/vendor/groonga/tools/Makefile.am b/storage/mroonga/vendor/groonga/tools/Makefile.am
new file mode 100644
index 00000000..6027eee1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/Makefile.am
@@ -0,0 +1,7 @@
+noinstall_ruby_scripts = \
+ groonga-memory-leak-checker.rb \
+ groonga-object-list-checker.rb \
+ prepare-sphinx-html.rb
+
+EXTRA_DIST = \
+ $(noinstall_ruby_scripts)
diff --git a/storage/mroonga/vendor/groonga/tools/check-small-index-limit.rb b/storage/mroonga/vendor/groonga/tools/check-small-index-limit.rb
new file mode 100755
index 00000000..d943d89e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/check-small-index-limit.rb
@@ -0,0 +1,123 @@
+#!/usr/bin/env ruby
+
+# Groonga: 70dc95ef3b6fed1225981d099a65dcb7297248c5
+#
+# N segments N chunks N patterns N records
+# 1 1 2 50
+# 2 2 2 18898
+# 4 4 2 31181
+# 8 8 2 57853
+# 16 16 2 91349
+# 32 32 2 178502
+# 64 64 2 475020
+# 128 128 2 1066081
+# 256 256 2 2250389
+# 512 512 2 4648072
+# nil nil 1 16779239
+# nil nil 2 4648063
+# nil nil 4 7239005
+# nil nil 8 8308626
+# nil nil 16 11068608
+# nil nil 32 12670806
+# nil nil 64 18524231
+# nil nil 128 38095525
+# nil nil 256 51265415
+
+require "fileutils"
+require "json"
+
+def check_max_index(options)
+ max_n_segments = options[:max_n_segments]
+ max_n_chunks = options[:max_n_chunks]
+ n_patterns = options[:n_patterns] || 2
+
+ ENV["GRN_II_MAX_N_SEGMENTS_SMALL"] = max_n_segments&.to_s
+ ENV["GRN_II_MAX_N_CHUNKS_SMALL"] = max_n_chunks&.to_s
+
+ db_dir = "/dev/shm/db"
+ log_path = "#{db_dir}/log"
+ FileUtils.rm_rf(db_dir)
+ FileUtils.mkdir_p(db_dir)
+ command_line = [
+ "groonga",
+ "--log-path", log_path,
+ "-n", "#{db_dir}/db",
+ ]
+ IO.popen(command_line, "r+") do |groonga|
+ groonga.puts("table_create x TABLE_HASH_KEY UInt32")
+ groonga.gets
+ groonga.puts("column_create x y COLUMN_SCALAR UInt32")
+ groonga.gets
+ groonga.puts("table_create a TABLE_PAT_KEY UInt32")
+ groonga.gets
+ groonga.puts("column_create a b COLUMN_INDEX|INDEX_SMALL x y")
+ groonga.gets
+
+ groonga.puts("load --table x")
+ groonga.puts("[")
+ File.open(log_path) do |log|
+ log.seek(0, IO::SEEK_END)
+ log_size = log.size
+ i = 0
+ catch do |abort|
+ loop do
+ y = i + 1
+ n_patterns.times do
+ groonga.print(JSON.generate({"_key" => i, "y" => y}))
+ groonga.puts(",")
+ groonga.flush
+ i += 1
+ if log.size != log_size
+ data = log.read
+ if /\|[Ae]\|/ =~ data
+ parameters = [
+ max_n_segments.inspect,
+ max_n_chunks.inspect,
+ n_patterns.inspect,
+ i,
+ ]
+ puts(parameters.join("\t"))
+ # puts(data)
+ throw(abort)
+ end
+ log_size = log.size
+ end
+ end
+ end
+ end
+ end
+ groonga.puts("]")
+ load_response = groonga.gets
+ # puts(load_response)
+
+ groonga.puts("quit")
+ groonga.gets
+ end
+end
+
+puts("N segments\tN chunks\tN patterns\tN records")
+[
+ [1, 1, 2],
+ [2, 2, 2],
+ [4, 4, 2],
+ [8, 8, 2],
+ [16, 16, 2],
+ [32, 32, 2],
+ [64, 64, 2],
+ [128, 128, 2],
+ [256, 256, 2],
+ [512, 512, 2],
+ [nil, nil, 1],
+ [nil, nil, 2],
+ [nil, nil, 4],
+ [nil, nil, 8],
+ [nil, nil, 16],
+ [nil, nil, 32],
+ [nil, nil, 64],
+ [nil, nil, 128],
+ [nil, nil, 256],
+].each do |max_n_segments, max_n_chunks, n_parameters|
+ check_max_index(:max_n_segments => max_n_segments,
+ :max_n_chunks => max_n_chunks,
+ :n_patterns => n_parameters)
+end
diff --git a/storage/mroonga/vendor/groonga/tools/groonga-benchmark-indexing.rb b/storage/mroonga/vendor/groonga/tools/groonga-benchmark-indexing.rb
new file mode 100755
index 00000000..9c64e6d9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/groonga-benchmark-indexing.rb
@@ -0,0 +1,129 @@
+#!/usr/bin/env ruby
+
+require "fileutils"
+require "json"
+require "optparse"
+
+class IndexingBenchmarker
+ def initialize
+ @groonga = "groonga"
+ @database_path = nil
+ @benchmark_database_dir = detect_benchmark_database_dir
+ end
+
+ def run
+ catch(:run) do
+ parse_options!
+ end
+
+ dump_no_indexes = dump("dump-no-indexes.grn",
+ "--dump_indexes", "no")
+ dump_only_indexes = dump("dump-only-indexes.grn",
+ "--dump_plugins", "no",
+ "--dump_schema", "no",
+ "--dump_records", "no",
+ "--dump_configs", "no")
+ dump_no_records = dump("dump-no-records.grn",
+ "--dump_records", "no")
+ dump_only_records = dump("dump-only-records.grn",
+ "--dump_plugins", "no",
+ "--dump_schema", "no",
+ "--dump_indexes", "no",
+ "--dump_configs", "no")
+
+ create_benchmark_database do
+ p [:load_record, measure(dump_no_indexes)]
+ p [:static_index_creation, measure(dump_only_indexes)]
+ end
+
+ create_benchmark_database do
+ p [:create_schema, measure(dump_no_records)]
+ p [:load_record_and_create_index, measure(dump_only_records)]
+ end
+
+ true
+ end
+
+ private
+ def detect_benchmark_database_dir
+ candiates = [
+ "/dev/shm",
+ "tmp",
+ ]
+ candiates.find do |candidate|
+ File.exist?(candidate)
+ end
+ end
+
+ def benchmark_database_path
+ "#{@benchmark_database_dir}/bench-db/db"
+ end
+
+ def parse_options!
+ option_parser = OptionParser.new do |parser|
+ parser.banner += " SOURCE_DATABASE"
+
+ parser.on("--groonga=PATH",
+ "Use PATH as groonga command path") do |path|
+ @groonga = path
+ end
+
+ parser.on("--benchmark-database-dir=DIR",
+ "Use DIR to put benchmark database") do |dir|
+ @benchmark_database_dir = dir
+ end
+ end
+
+ @database_path, = option_parser.parse!(ARGV)
+ if @database_path.nil?
+ puts(option_parser)
+ throw(:run)
+ end
+ end
+
+ def dump(path, *dump_options)
+ return path if File.exist?(path)
+ unless system(@groonga,
+ @database_path,
+ "dump",
+ *dump_options,
+ :out => path)
+ raise "failed to dump: #{dump_options.inspect}"
+ end
+ path
+ end
+
+ def create_benchmark_database
+ dir = File.dirname(benchmark_database_path)
+ FileUtils.rm_rf(dir)
+ FileUtils.mkdir_p(dir)
+ system(@groonga,
+ "-n", benchmark_database_path,
+ "shutdown",
+ :out => IO::NULL)
+ begin
+ yield
+ ensure
+ FileUtils.rm_rf(dir)
+ end
+ end
+
+ def measure(dump_path)
+ result = "result"
+ begin
+ system(@groonga,
+ "--file", dump_path,
+ benchmark_database_path,
+ :out => result)
+ File.open(result) do |output|
+ output.each_line.inject(0) do |result, line|
+ result + JSON.parse(line)[0][2]
+ end
+ end
+ ensure
+ FileUtils.rm_f(result)
+ end
+ end
+end
+
+exit(IndexingBenchmarker.new.run)
diff --git a/storage/mroonga/vendor/groonga/tools/groonga-memory-leak-checker.rb b/storage/mroonga/vendor/groonga/tools/groonga-memory-leak-checker.rb
new file mode 100755
index 00000000..4e4e10a4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/groonga-memory-leak-checker.rb
@@ -0,0 +1,93 @@
+#!/usr/bin/env ruby
+
+unless respond_to?(:spawn, true)
+ puts("Ruby 1.9 is required.")
+ exit(false)
+end
+
+require 'ostruct'
+require 'optparse'
+require 'tempfile'
+require 'time'
+
+options = OpenStruct.new
+options.groonga = "groonga"
+options.show_result = false
+options.report_progress = true
+
+option_parser = OptionParser.new do |parser|
+ parser.banner += " DATABASE COMMAND_FILE1 ..."
+
+ parser.on("--groonga=PATH",
+ "Use PATH as groonga command path") do |path|
+ options.groonga = path
+ end
+
+ parser.on("--[no-]show-result",
+ "Show result of command") do |boolean|
+ options.show_result = boolean
+ end
+
+ parser.on("--[no-]report-progress",
+ "Report progress") do |boolean|
+ options.report_progress = boolean
+ end
+end
+
+database, *command_files = option_parser.parse!(ARGV)
+if database.nil?
+ puts(option_parser)
+ exit(false)
+end
+
+i = 0
+command_files.each do |path|
+ File.open(path) do |file|
+ file.each_line do |command|
+ if options.report_progress
+ i += 1
+ puts("#{Time.now.iso8601}: #{i} commands done.") if (i % 1000).zero?
+ end
+ command = command.chomp
+ base_name = File.basename($0, ".*")
+ log = Tempfile.new("#{base_name}-log")
+ command_file = Tempfile.new("#{base_name}-command")
+ command_file.puts(command)
+ command_file.close
+ command_line = [options.groonga,
+ "--log-path", log.path,
+ "--file", command_file.path]
+ command_file << "-n" unless File.exist?(database)
+ command_line << database
+ result = Tempfile.new("#{base_name}-result")
+ pid = spawn(*command_line, :out => result.fileno)
+ pid, status = Process.waitpid2(pid)
+ unless status.success?
+ puts("failed to run: (#{status.exitstatus}): " +
+ "[#{command_line.join(' ')}]")
+ puts("command:")
+ puts(command)
+ puts("result:")
+ result.open
+ puts(result.read)
+ next
+ # exit(false)
+ end
+ if options.show_result
+ result.open
+ puts(result.read)
+ end
+ log.open
+ log.each_line do |log_line|
+ case log_line
+ when /grn_fin \((\d+)\)/
+ n_unfreed_allocations = $1.to_i
+ unless n_unfreed_allocations.zero?
+ puts("maybe memory leak: #{n_unfreed_allocations}: <#{command}>")
+ exit(false)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/tools/groonga-memory-usage-analyzer.rb b/storage/mroonga/vendor/groonga/tools/groonga-memory-usage-analyzer.rb
new file mode 100755
index 00000000..5c4d5669
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/groonga-memory-usage-analyzer.rb
@@ -0,0 +1,127 @@
+#!/usr/bin/env ruby
+
+class Memory < Struct.new(:size, :file, :line, :function)
+ def location
+ "#{file}:#{line}"
+ end
+end
+
+class LocationGroup
+ attr_reader :location
+ attr_reader :memories
+ def initialize(location)
+ @location = location
+ @memories = []
+ end
+
+ def add(memory)
+ @memories << memory
+ end
+
+ def total_size
+ @memories.inject(0) do |sum, memory|
+ sum + memory.size
+ end
+ end
+
+ def average_size
+ total_size / @memories.size.to_f
+ end
+
+ def max_size
+ @memories.collect(&:size).max
+ end
+
+ def min_size
+ @memories.collect(&:size).min
+ end
+end
+
+class Statistics
+ def initialize
+ @location_groups = {}
+ end
+
+ def add(memory)
+ group = location_group(memory.location)
+ group.add(memory)
+ end
+
+ def sort_by_size
+ @location_groups.values.sort_by do |group|
+ group.total_size
+ end
+ end
+
+ private
+ def location_group(location)
+ @location_groups[location] ||= LocationGroup.new(location)
+ end
+end
+
+statistics = Statistics.new
+
+ARGF.each_line do |line|
+ case line
+ when /\Aaddress\[\d+\]\[not-freed\]:\s
+ (?:0x)?[\da-fA-F]+\((\d+)\):\s
+ (.+?):(\d+):\s(\S+)/x
+ size = $1.to_i
+ file = $2
+ line = $3.to_i
+ function = $4.strip
+ memory = Memory.new(size, file, line, function)
+ statistics.add(memory)
+ end
+end
+
+def format_size(size)
+ if size < 1024
+ "#{size}B"
+ elsif size < (1024 * 1024)
+ "%.3fKiB" % (size / 1024.0)
+ elsif size < (1024 * 1024 * 1024)
+ "%.3fMiB" % (size / 1024.0 / 1024.0)
+ elsif size < (1024 * 1024 * 1024 * 1024)
+ "%.3fGiB" % (size / 1024.0 / 1024.0 / 1024.0)
+ else
+ "#{size}B"
+ end
+end
+
+puts("%10s(%10s:%10s:%10s): %s(%s)" % [
+ "Total",
+ "Average",
+ "Max",
+ "Min",
+ "Location",
+ "N allocations",
+ ])
+top_allocated_groups = statistics.sort_by_size.reverse_each.take(10)
+top_allocated_groups.each do |group|
+ puts("%10s(%10s:%10s:%10s): %s(%d)" % [
+ format_size(group.total_size),
+ format_size(group.average_size),
+ format_size(group.max_size),
+ format_size(group.min_size),
+ group.location,
+ group.memories.size,
+ ])
+end
+
+puts
+puts("Top allocated location's details")
+top_allocated_group = top_allocated_groups.first
+target_memories = top_allocated_group.memories
+size_width = Math.log10(target_memories.size).floor + 1
+target_memories.group_by(&:size).sort_by do |size, memories|
+ size * memories.size
+end.reverse_each do |size, memories|
+ total_size = memories.inject(0) {|sum, memory| sum + memory.size}
+ puts("%10s(%10s * %#{size_width}d): %s" % [
+ format_size(total_size),
+ format_size(size),
+ memories.size,
+ memories.first.location,
+ ])
+end
diff --git a/storage/mroonga/vendor/groonga/tools/groonga-object-list-checker.rb b/storage/mroonga/vendor/groonga/tools/groonga-object-list-checker.rb
new file mode 100755
index 00000000..f92eec0e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/groonga-object-list-checker.rb
@@ -0,0 +1,104 @@
+#!/usr/bin/env ruby
+#
+# Copyright(C) 2016 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-1335 USA
+
+require "pp"
+require "json"
+require "groonga/command/parser"
+
+if ARGV.empty?
+ puts("Usage:")
+ puts(" #{$0} schema.grn object_list_result.json")
+ puts(" #{$0} schema.grn < object_list_result.json")
+ puts(" groonga DB_PATH object_list | #{$0} schema.grn")
+ exit(false)
+end
+
+schema_grn = ARGV.shift
+
+schema = {}
+Groonga::Command::Parser.parse(File.read(schema_grn)) do |type, *args|
+ case type
+ when :on_command
+ command, = args
+ case command.name
+ when "table_create"
+ if command.table_no_key?
+ type = "table:no_key"
+ elsif command.table_pat_key?
+ type = "table:pat_key"
+ elsif command.table_dat_key?
+ type = "table:dat_key"
+ else
+ type = "table:hash_key"
+ end
+ name = command[:name]
+ schema[name] ||= []
+ schema[name] << {
+ :type => type,
+ :flags => command.flags.join("|"),
+ }
+ when "column_create"
+ if command.column_index?
+ type = "column:index"
+ elsif command.column_vector? or command.type == "ShortText"
+ type = "column:var_size"
+ else
+ type = "column:fix_size"
+ end
+ name = "#{command[:table]}.#{command[:name]}"
+ schema[name] ||= []
+ schema[name] << {
+ :type => type,
+ :flags => command.flags.join("|"),
+ }
+ end
+ end
+end
+
+MAX_RESERVED_ID = 255
+response = JSON.parse(ARGF.read)
+body = response[1]
+body.each do |name, object|
+ id = object["id"]
+ next if id <= MAX_RESERVED_ID
+ normalized_name = name.gsub(/\d{4}\d{2}(?:\d{2})?/, "YYYYMMDD")
+
+ definitions = schema[normalized_name]
+ if definitions.nil?
+ next if object["type"]["name"] == "proc"
+ puts("Unknown table/column: #{name}(#{id})")
+ exit(false)
+ end
+
+ type = object["type"]
+ if type.nil?
+ puts("[invalid][no-type] #{id}:#{name}")
+ puts(PP.pp(object, "").gsub(/^/, " "))
+ next
+ end
+
+ type_name = type["name"]
+ valid_type_names = definitions.collect {|definition| definition[:type]}
+ unless valid_type_names.include?(type["name"])
+ expected = "expected:[#{valid_type_names.join(", ")}]"
+ puts("[invalid][wrong-type] #{id}:#{name} <#{type_name}> #{expected}")
+ puts(PP.pp(object, "").gsub(/^/, " "))
+ puts(PP.pp(definitions, "").gsub(/^/, " "))
+ next
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/tools/groonga-suggest-httpd-client.rb b/storage/mroonga/vendor/groonga/tools/groonga-suggest-httpd-client.rb
new file mode 100755
index 00000000..00b6abf6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/groonga-suggest-httpd-client.rb
@@ -0,0 +1,181 @@
+#!/usr/bin/env ruby
+#
+# Copyright(C) 2011 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 version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+require "optparse"
+require "cool.io"
+require "digest"
+
+class Terms
+ def initialize
+ @sources = []
+ end
+
+ def next
+ until @sources.empty?
+ source = @sources.first
+ term = source.next
+ @sources.shift if source.empty?
+ break if term
+ end
+ term
+ end
+
+ def empty?
+ @sources.all?(&:empty?)
+ end
+
+ def add_source_file(path)
+ @sources << InputSource.new(File.open(path))
+ end
+
+ def add_source_input(input)
+ @sources << InputSource.new(input)
+ end
+
+ class InputSource
+ def initialize(source)
+ @source = source
+ @lines = @source.each_line
+ @look_ahead_term = nil
+ end
+
+ def next
+ if @look_ahead_term
+ term = @look_ahead_term
+ @look_ahead_term = nil
+ else
+ loop do
+ term = @lines.next.strip
+ break unless term.empty?
+ end
+ end
+ term
+ rescue StopIteration
+ @lines = nil
+ @source.close
+ @source = nil
+ nil
+ end
+
+ def empty?
+ if @source.nil?
+ true
+ else
+ @look_ahead_term ||= self.next
+ @look_ahead_term.nil?
+ end
+ end
+ end
+end
+
+class GroongaSuggestHTTPDClient < Coolio::HttpClient
+ def initialize(socket, dataset, id, term)
+ super(socket)
+ @dataset = dataset
+ @id = id
+ @term = term
+ @callbacks = []
+ end
+
+ def request
+ query = {}
+ query["q"] = @term.dup.force_encoding("ASCII-8BIT")
+ query["s"] = (Time.now.to_f * 1_000).round.to_s
+ query["i"] = @id
+ query["t"] = "submit" if rand(10).zero?
+ query["l"] = @dataset
+ super("GET", "/", :query => query)
+ end
+
+ def on_body_data(data)
+ end
+
+ def on_request_complete(&block)
+ if block
+ @callbacks << block
+ else
+ @callbacks.each do |callback|
+ callback.call(self)
+ end
+ end
+ end
+
+ def on_error(reason)
+ close
+ $stderr.puts("Error: #{reason}")
+ end
+end
+
+n_connections = 100
+host = "localhost"
+port = 8080
+terms = Terms.new
+parser = OptionParser.new
+parser.banner += " DATASET"
+parser.on("--host=HOST",
+ "Use HOST as groonga suggest HTTPD host.",
+ "(#{host})") do |_host|
+ host = _host
+end
+parser.on("--port=PORT", Integer,
+ "Use PORT as groonga suggest HTTPD port.",
+ "(#{port})") do |_port|
+ port = _port
+end
+parser.on("--n-connections=N", Integer,
+ "Use N connections.",
+ "(#{n_connections})") do |n|
+ n_connections = n
+end
+parser.on("--terms=PATH",
+ "Use terns in PATH.",
+ "(none)") do |path|
+ terms.add_source_file(path)
+end
+
+parser.parse!
+if ARGV.size != 1
+ puts(parser)
+ exit(false)
+end
+dataset = ARGV.shift
+
+if terms.empty? and !$stdin.tty?
+ terms.add_source_input($stdin)
+end
+
+if terms.empty?
+ puts("no terms")
+ exit(false)
+end
+
+loop = Coolio::Loop.default
+run_client = lambda do |id|
+ term = terms.next
+ return if term.nil?
+ client = GroongaSuggestHTTPDClient.connect(host, port, dataset, id, term)
+ client.on_request_complete do
+ run_client.call(id)
+ end
+ client.attach(loop)
+ client.request
+end
+n_connections.times do |i|
+ id = Digest::SHA2.hexdigest(Time.now.to_f.to_s)
+ run_client.call(id)
+end
+loop.run
diff --git a/storage/mroonga/vendor/groonga/tools/install/install-for-debian-jessie.sh b/storage/mroonga/vendor/groonga/tools/install/install-for-debian-jessie.sh
new file mode 100755
index 00000000..d053d2d9
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/install/install-for-debian-jessie.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+set -e
+
+sources_list_path=/etc/apt/sources.list.d/groonga.list
+
+if [ ! -f $sources_list_path ]; then
+ sudo cat <<SOURCES_LIST | sudo tee $sources_list_path
+deb http://packages.groonga.org/debian/ jessie main
+deb-src http://packages.groonga.org/debian/ jessie main
+SOURCES_LIST
+fi
+
+sudo apt-get update
+sudo apt-get install -y --allow-unauthenticated groonga-keyring
+sudo apt-get update
+sudo apt-get install -y -V groonga
diff --git a/storage/mroonga/vendor/groonga/tools/prepare-sphinx-html.rb b/storage/mroonga/vendor/groonga/tools/prepare-sphinx-html.rb
new file mode 100755
index 00000000..5396d267
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/prepare-sphinx-html.rb
@@ -0,0 +1,183 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+
+if ARGV.size != 2
+ puts "Usage: #{$0} SOURCE_DIR DEST_DIR"
+ exit(false)
+end
+
+require 'pathname'
+
+def fix_link(text, extension, language)
+ send("fix_#{extension}_link", text, language)
+end
+
+def fix_link_path(text)
+ text.gsub(/\b_(sources|static|images)\b/, '\1')
+end
+
+def fix_language_link(url, language)
+ url.gsub(/\A((?:\.\.\/){2,})([a-z]{2})\/html\//) do
+ relative_base_path = $1
+ link_language = $2
+ close_quote = $3
+ if language == "en"
+ relative_base_path = relative_base_path.gsub(/\A\.\.\//, '')
+ end
+ if link_language != "en"
+ relative_base_path += "#{link_language}/"
+ end
+ "#{relative_base_path}docs/"
+ end
+end
+
+def fix_html_link(html, language)
+ html = html.gsub(/(href|src)="(.+?)"/) do
+ attribute = $1
+ link = $2
+ link = fix_link_path(link)
+ link = fix_language_link(link, language)
+ "#{attribute}=\"#{link}\""
+ end
+ html.gsub(/(id="top-link" href=)"(.+?)"/) do
+ prefix = $1
+ top_path = $2.gsub(/\/index\.html\z/, '/')
+ top_path = "./" if ["index.html", "#"].include?(top_path)
+ "#{prefix}\"#{top_path}../\""
+ end
+end
+
+def add_language_annotation_to_source_label(html, language)
+ return html unless language == "ja"
+ html.gsub(/>(ソースコードを表示)</) do
+ label = $1
+ ">#{label}(英語)<"
+ end
+end
+
+def fix_js_link(js, language)
+ fix_link_path(js)
+end
+
+LANGUAGE_TO_LOCALE = {
+ "ja" => "ja_JP",
+ "en" => "en_US",
+}
+
+def insert_facebook_html_header(html)
+ html.gsub(/<\/head>/) do
+ <<-HTML
+ <meta property="fb:page_id" content="201193596592346" /><!-- groonga -->
+ <meta property="fb:admins" content="664204556" /><!-- kouhei.sutou -->
+ <meta property="og:type" content="product" />
+ <meta property="og:image" content="http://groonga.org/images/logos/groonga-icon-full-size.png" />
+ <meta property="og:site_name" content="groonga" />
+
+ <link rel="stylesheet" href="/css/sphinx.css" type="text/css" />
+ </head>
+ HTML
+ end
+end
+
+def insert_facebook_html_fb_root(html)
+ html.gsub(/<body>/) do
+ <<-HTML
+ <body>
+ <div id="fb-root"></div>
+ HTML
+ end
+end
+
+def insert_facebook_html_buttons(html)
+ html.gsub(/(<div class="other-language-links">)/) do
+ <<-HTML
+ <div class="facebook-buttons">
+ <fb:like href="http://www.facebook.com/pages/groonga/201193596592346"
+ layout="standard"
+ width="290"></fb:like>
+ </div>
+ #{$1}
+ HTML
+ end
+end
+
+def insert_facebook_html_footer(html, language)
+ locale = LANGUAGE_TO_LOCALE[language]
+ raise "unknown locale for language #{language.inspect}" if locale.nil?
+ html.gsub(/<\/body>/) do
+ <<-HTML
+ <script src="http://connect.facebook.net/#{locale}/all.js"></script>
+
+ <script>
+ FB.init({
+ appId : null,
+ status : true, // check login status
+ cookie : true, // enable cookies to allow the server to access the session
+ xfbml : true // parse XFBML
+ });
+ </script>
+ </body>
+ HTML
+ end
+end
+
+def insert_facebook_html(html, language)
+ html = insert_facebook_html_header(html)
+ html = insert_facebook_html_fb_root(html)
+ html = insert_facebook_html_buttons(html)
+ html = insert_facebook_html_footer(html, language)
+ html
+end
+
+source_dir, dest_dir = ARGV
+
+source_dir = Pathname.new(source_dir)
+dest_dir = Pathname.new(dest_dir)
+
+language_dirs = []
+source_dir.each_entry do |top_level_path|
+ language_dirs << top_level_path if /\A[a-z]{2}\z/ =~ top_level_path.to_s
+end
+
+language_dirs.each do |language_dir|
+ language = language_dir.to_s
+ language_source_dir = source_dir + language_dir + "html"
+ language_dest_dir = dest_dir + language_dir
+ language_source_dir.find do |source_path|
+ relative_path = source_path.relative_path_from(language_source_dir)
+ dest_path = language_dest_dir + relative_path
+ if source_path.directory?
+ dest_path.mkpath
+ else
+ case source_path.extname
+ when ".html", ".js"
+ content = source_path.read
+ extension = source_path.extname.gsub(/\A\./, '')
+ content = fix_link(content, extension, language)
+ if extension == "html"
+ content = insert_facebook_html(content, language)
+ content = add_language_annotation_to_source_label(content, language)
+ end
+ dest_path.open("wb") do |dest|
+ dest.print(content.strip)
+ end
+ FileUtils.touch(dest_path, :mtime => source_path.mtime)
+ else
+ case source_path.basename.to_s
+ when ".buildinfo"
+ # ignore
+ else
+ FileUtils.cp(source_path, dest_path, :preserve => true)
+ end
+ end
+ end
+ end
+end
+
+dest_dir.find do |dest_path|
+ if dest_path.directory? and /\A_/ =~ dest_path.basename.to_s
+ normalized_dest_path = dest_path + ".."
+ normalized_dest_path += dest_path.basename.to_s.gsub(/\A_/, '')
+ FileUtils.mv(dest_path, normalized_dest_path)
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/tools/travis-before-script.sh b/storage/mroonga/vendor/groonga/tools/travis-before-script.sh
new file mode 100755
index 00000000..87ed5756
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/travis-before-script.sh
@@ -0,0 +1,53 @@
+#!/bin/sh
+
+set -e
+set -u
+
+: ${ENABLE_MRUBY:=no}
+
+git submodule update --init --depth 1
+
+prefix=/tmp/local
+
+case "${BUILD_TOOL}" in
+ autotools)
+ ./autogen.sh
+
+ configure_args=""
+ if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
+ pkg_config_path="$(brew --prefix openssl)/lib/pkgconfig"
+ configure_args="${configure_args} PKG_CONFIG_PATH=${pkg_config_path}"
+ fi
+ #if [ "$CC" = "clang" ]; then
+ configure_args="${configure_args} --enable-debug"
+ #fi
+ if [ "${ENABLE_MRUBY}" = "yes" ]; then
+ configure_args="${configure_args} --with-ruby --enable-mruby"
+ fi
+
+ ./configure --prefix=${prefix} --with-ruby ${configure_args}
+ ;;
+ cmake)
+ cmake_args=""
+ cmake_args="${cmake_args} -DGRN_WITH_DEBUG=yes"
+ if [ "${ENABLE_MRUBY}" = "yes" ]; then
+ cmake_args="${cmake_args} -DGRN_WITH_MRUBY=yes"
+ fi
+
+ cmake . ${cmake_args}
+ ;;
+esac
+
+case "$(uname)" in
+ Linux)
+ n_processors="$(grep '^processor' /proc/cpuinfo | wc -l)"
+ ;;
+ Darwin)
+ n_processors="$(/usr/sbin/sysctl -n hw.ncpu)"
+ ;;
+ *)
+ n_processors="1"
+ ;;
+esac
+
+make -j${n_processors} > /dev/null
diff --git a/storage/mroonga/vendor/groonga/tools/travis-install.sh b/storage/mroonga/vendor/groonga/tools/travis-install.sh
new file mode 100755
index 00000000..d7ac400c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/travis-install.sh
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+set -e
+set -u
+
+: ${ENABLE_MRUBY:=no}
+
+case "${TRAVIS_OS_NAME}" in
+ linux)
+ curl --silent --location https://raw.github.com/clear-code/cutter/master/data/travis/setup.sh | sh
+ sudo apt-get install -qq -y \
+ autotools-dev \
+ autoconf-archive \
+ zlib1g-dev \
+ libmsgpack-dev \
+ libevent-dev \
+ libmecab-dev \
+ mecab-naist-jdic \
+ cmake
+ ;;
+ osx)
+ brew update > /dev/null
+ brew outdated pkg-config || brew upgrade pkg-config
+ brew reinstall libtool
+ brew outdated libevent || brew upgrade libevent
+ brew install \
+ autoconf-archive \
+ msgpack \
+ mecab \
+ mecab-ipadic
+ brew install --force openssl
+ # brew install cutter
+ ;;
+esac
+
+if [ "${ENABLE_MRUBY}" = "yes" ]; then
+ gem install pkg-config groonga-client test-unit
+fi
diff --git a/storage/mroonga/vendor/groonga/tools/travis-script.sh b/storage/mroonga/vendor/groonga/tools/travis-script.sh
new file mode 100755
index 00000000..cc045725
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/tools/travis-script.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+
+set -e
+set -u
+
+: ${ENABLE_MRUBY:=no}
+: ${TEST_TARGET:=all}
+
+prefix=/tmp/local
+
+command_test_options="--reporter=mark --timeout=60"
+
+set -x
+
+export COLUMNS=79
+
+retry()
+{
+ local i=0
+ while ! "$@"; do
+ if [ $i -eq 3 ]; then
+ exit 1
+ fi
+ i=$((i + 1))
+ done
+}
+
+if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
+ memory_fs_size=$[768 * 1024 * 1024] # 768MiB
+ byte_per_sector=512
+ n_sectors=$[${memory_fs_size} / ${byte_per_sector}]
+ memory_fs_device_path=$(hdid -nomount ram://${n_sectors})
+ newfs_hfs ${memory_fs_device_path}
+ mkdir -p tmp
+ mount -t hfs ${memory_fs_device_path} tmp
+
+ command_test_options="${command_test_options} --n-workers=2"
+else
+ command_test_options="${command_test_options} --n-workers=4"
+fi
+
+case "${BUILD_TOOL}" in
+ autotools)
+ case "${TEST_TARGET}" in
+ command)
+ test/command/run-test.sh ${command_test_options}
+ ;;
+ command-http)
+ retry test/command/run-test.sh ${command_test_options} \
+ --interface http
+ ;;
+ command-httpd)
+ mkdir -p ${prefix}/var/log/groonga/httpd
+ retry test/command/run-test.sh ${command_test_options} \
+ --testee groonga-httpd
+ ;;
+ *)
+ test/unit/run-test.sh -v v
+ test/command/run-test.sh ${command_test_options}
+ if [ "${ENABLE_MRUBY}" = "yes" ]; then
+ test/mruby/run-test.rb
+ test/command_line/run-test.rb
+ fi
+ retry test/command/run-test.sh ${command_test_options} \
+ --interface http
+ mkdir -p ${prefix}/var/log/groonga/httpd
+ retry test/command/run-test.sh ${command_test_options} \
+ --testee groonga-httpd
+ ;;
+ esac
+ ;;
+ cmake)
+ test/command/run-test.sh ${command_test_options}
+ ;;
+esac
diff --git a/storage/mroonga/vendor/groonga/vendor/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/CMakeLists.txt
new file mode 100644
index 00000000..5a2ec9ab
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/CMakeLists.txt
@@ -0,0 +1,20 @@
+# Copyright(C) 2013-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+add_subdirectory(lz4)
+add_subdirectory(onigmo)
+add_subdirectory(mruby)
+add_subdirectory(mecab)
+add_subdirectory(message_pack)
diff --git a/storage/mroonga/vendor/groonga/vendor/Makefile.am b/storage/mroonga/vendor/groonga/vendor/Makefile.am
new file mode 100644
index 00000000..d66aac55
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/Makefile.am
@@ -0,0 +1,29 @@
+NGINX_DIR = nginx-$(NGINX_VERSION)
+
+SUBDIRS = \
+ lz4 \
+ onigmo \
+ mecab \
+ message_pack \
+ mruby
+
+EXTRA_DIST = \
+ $(NGINX_DIR) \
+ CMakeLists.txt \
+ plugins/CMakeLists.txt \
+ download_lz4.rb \
+ download_message_pack.rb \
+ download_mecab.rb
+
+dist-hook:
+ rm -rf $(distdir)/$(NGINX_DIR)/objs/
+ GIT_DIR=$(srcdir)/mruby-source/.git git archive --format=tar HEAD | \
+ tar xf - -C $(distdir)/mruby-source
+ $(MKDIR_P) $(distdir)/onigmo-source
+ GIT_DIR=$(srcdir)/onigmo-source/.git git archive --format=tar HEAD | \
+ tar xf - -C $(distdir)/onigmo-source
+ cd $(distdir)/onigmo-source && autoreconf --install --force
+ cd $(distdir)/onigmo-source && sleep 1 && touch config.h.in
+ $(MKDIR_P) $(distdir)/ngx_mruby-source
+ GIT_DIR=$(srcdir)/ngx_mruby-source/.git git archive --format=tar HEAD | \
+ tar xf - -C $(distdir)/ngx_mruby-source
diff --git a/storage/mroonga/vendor/groonga/vendor/download_lz4.rb b/storage/mroonga/vendor/groonga/vendor/download_lz4.rb
new file mode 100755
index 00000000..59b35081
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/download_lz4.rb
@@ -0,0 +1,54 @@
+#!/usr/bin/env ruby
+
+require "pathname"
+require "fileutils"
+require "open-uri"
+require "openssl"
+require "rubygems/package"
+require "zlib"
+
+@debug = (ENV["DEBUG"] == "true" or ARGV.include?("--debug"))
+
+base_dir = Pathname.new(__FILE__).expand_path.dirname.parent
+
+lz4_version = (base_dir + "bundled_lz4_version").read.strip
+
+lz4_base = "lz4-#{lz4_version}"
+
+def extract_tar_gz(tar_gz_path)
+ Zlib::GzipReader.open(tar_gz_path) do |tar_io|
+ Gem::Package::TarReader.new(tar_io) do |tar|
+ tar.each do |entry|
+ p [entry.header.typeflag, entry.full_name] if @debug
+ if entry.directory?
+ FileUtils.mkdir_p(entry.full_name)
+ elsif entry.file?
+ File.open(entry.full_name, "wb") do |file|
+ file.print(entry.read)
+ end
+ end
+ end
+ end
+ end
+end
+
+def download(url, base)
+ ssl_verify_mode = nil
+ if /mingw/ =~ RUBY_PLATFORM
+ ssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+
+ tar = "#{base}.tar"
+ tar_gz = "#{tar}.gz"
+ open(url, :ssl_verify_mode => ssl_verify_mode) do |remote_tar_gz|
+ File.open(tar_gz, "wb") do |local_tar_gz|
+ local_tar_gz.print(remote_tar_gz.read)
+ end
+ end
+ FileUtils.rm_rf(base)
+ extract_tar_gz(tar_gz)
+ FileUtils.rm_rf(tar_gz)
+end
+
+download("https://github.com/lz4/lz4/archive/v#{lz4_version}.tar.gz",
+ lz4_base)
diff --git a/storage/mroonga/vendor/groonga/vendor/download_mecab.rb b/storage/mroonga/vendor/groonga/vendor/download_mecab.rb
new file mode 100755
index 00000000..027f834f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/download_mecab.rb
@@ -0,0 +1,59 @@
+#!/usr/bin/env ruby
+
+require "pathname"
+require "fileutils"
+require "open-uri"
+require "openssl"
+require "rubygems/package"
+require "zlib"
+
+@debug = (ENV["DEBUG"] == "true" or ARGV.include?("--debug"))
+
+base_dir = Pathname.new(__FILE__).expand_path.dirname.parent
+
+mecab_version = (base_dir + "bundled_mecab_version").read.strip
+mecab_naist_jdic_version = (base_dir + "bundled_mecab_naist_jdic_version").read.strip
+
+mecab_base = "mecab-#{mecab_version}"
+mecab_naist_jdic_base = "mecab-naist-jdic-#{mecab_naist_jdic_version}"
+
+def extract_tar_gz(tar_gz_path)
+ Zlib::GzipReader.open(tar_gz_path) do |tar_io|
+ Gem::Package::TarReader.new(tar_io) do |tar|
+ tar.each do |entry|
+ p [entry.header.typeflag, entry.full_name] if @debug
+ if entry.directory?
+ FileUtils.mkdir_p(entry.full_name)
+ else
+ File.open(entry.full_name, "wb") do |file|
+ file.print(entry.read)
+ end
+ end
+ end
+ end
+ end
+end
+
+def download(url, base)
+ ssl_verify_mode = nil
+ if /mingw/ =~ RUBY_PLATFORM
+ ssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+
+ tar = "#{base}.tar"
+ tar_gz = "#{tar}.gz"
+ open(url, :ssl_verify_mode => ssl_verify_mode) do |remote_tar_gz|
+ File.open(tar_gz, "wb") do |local_tar_gz|
+ local_tar_gz.print(remote_tar_gz.read)
+ end
+ end
+ FileUtils.rm_rf(base)
+ extract_tar_gz(tar_gz)
+ FileUtils.rm_rf(tar_gz)
+end
+
+download("https://drive.google.com/uc?export=download&id=0B4y35FiV1wh7cENtOXlicTFaRUE",
+ mecab_base)
+
+download("http://osdn.dl.sourceforge.jp/naist-jdic/53500/#{mecab_naist_jdic_base}.tar.gz",
+ mecab_naist_jdic_base)
diff --git a/storage/mroonga/vendor/groonga/vendor/download_message_pack.rb b/storage/mroonga/vendor/groonga/vendor/download_message_pack.rb
new file mode 100755
index 00000000..b2f09af7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/download_message_pack.rb
@@ -0,0 +1,54 @@
+#!/usr/bin/env ruby
+
+require "pathname"
+require "fileutils"
+require "open-uri"
+require "openssl"
+require "rubygems/package"
+require "zlib"
+
+@debug = (ENV["DEBUG"] == "true" or ARGV.include?("--debug"))
+
+base_dir = Pathname.new(__FILE__).expand_path.dirname.parent
+
+message_pack_version = (base_dir + "bundled_message_pack_version").read.strip
+
+message_pack_base = "msgpack-#{message_pack_version}"
+
+def extract_tar_gz(tar_gz_path)
+ Zlib::GzipReader.open(tar_gz_path) do |tar_io|
+ Gem::Package::TarReader.new(tar_io) do |tar|
+ tar.each do |entry|
+ p [entry.header.typeflag, entry.full_name] if @debug
+ if entry.directory?
+ FileUtils.mkdir_p(entry.full_name)
+ else
+ File.open(entry.full_name, "wb") do |file|
+ file.print(entry.read)
+ end
+ end
+ end
+ end
+ end
+end
+
+def download(url, base)
+ ssl_verify_mode = nil
+ if /mingw/ =~ RUBY_PLATFORM
+ ssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
+ end
+
+ tar = "#{base}.tar"
+ tar_gz = "#{tar}.gz"
+ open(url, :ssl_verify_mode => ssl_verify_mode) do |remote_tar_gz|
+ File.open(tar_gz, "wb") do |local_tar_gz|
+ local_tar_gz.print(remote_tar_gz.read)
+ end
+ end
+ FileUtils.rm_rf(base)
+ extract_tar_gz(tar_gz)
+ FileUtils.rm_rf(tar_gz)
+end
+
+download("https://github.com/msgpack/msgpack-c/releases/download/cpp-#{message_pack_version}/msgpack-#{message_pack_version}.tar.gz",
+ message_pack_base)
diff --git a/storage/mroonga/vendor/groonga/vendor/lz4/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/lz4/CMakeLists.txt
new file mode 100644
index 00000000..87125a85
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/lz4/CMakeLists.txt
@@ -0,0 +1,98 @@
+# Copyright(C) 2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+set(LZ4_VERSION ${GRN_BUNDLED_LZ4_VERSION})
+
+set(LZ4_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../lz4-${LZ4_VERSION}")
+set(LZ4_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/../lz4-${LZ4_VERSION}")
+
+if(GRN_WITH_BUNDLED_LZ4)
+ include_directories(
+ BEFORE
+ ${LZ4_BINARY_DIR}
+ "${LZ4_SOURCE_DIR}/lib"
+ )
+
+ set(LIBLZ4_SOURCES
+ "${LZ4_SOURCE_DIR}/lib/lz4.c"
+ "${LZ4_SOURCE_DIR}/lib/lz4.h"
+ "${LZ4_SOURCE_DIR}/lib/lz4frame.c"
+ "${LZ4_SOURCE_DIR}/lib/lz4frame.h"
+ "${LZ4_SOURCE_DIR}/lib/lz4frame_static.h"
+ "${LZ4_SOURCE_DIR}/lib/lz4hc.c"
+ "${LZ4_SOURCE_DIR}/lib/lz4hc.h"
+ "${LZ4_SOURCE_DIR}/lib/xxhash.c"
+ "${LZ4_SOURCE_DIR}/lib/xxhash.h"
+ )
+ set(LZ4_SOURCES
+ "${LZ4_SOURCE_DIR}/programs/lz4cli.c"
+ "${LZ4_SOURCE_DIR}/programs/lz4io.c"
+ "${LZ4_SOURCE_DIR}/programs/lz4io.h"
+ "${LZ4_SOURCE_DIR}/programs/bench.c"
+ "${LZ4_SOURCE_DIR}/programs/bench.h"
+ "${LZ4_SOURCE_DIR}/programs/datagen.c"
+ "${LZ4_SOURCE_DIR}/programs/datagen.h"
+ "${LZ4_SOURCE_DIR}/programs/platform.h"
+ "${LZ4_SOURCE_DIR}/programs/util.h"
+ ${LIBLZ4_SOURCES})
+
+ set(LZ4_C_COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+
+ add_definitions("-DXXH_NAMESPACE=LZ4_")
+ if(MSVC)
+ add_definitions("-DLZ4_DLL_EXPORT=1")
+ endif()
+ set_source_files_properties(${LIBLZ4_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${LZ4_C_COMPILE_FLAGS}")
+ set_source_files_properties(${LZ4_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${LZ4_C_COMPILE_FLAGS}")
+
+ if(GRN_BUNDLED)
+ add_library(liblz4 STATIC ${LIBLZ4_SOURCES})
+ set_target_properties(
+ liblz4
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+ else()
+ add_library(liblz4 SHARED ${LIBLZ4_SOURCES})
+ endif()
+ if(NOT MSVC)
+ set_target_properties(liblz4 PROPERTIES OUTPUT_NAME "lz4")
+ endif()
+
+ if(NOT GRN_BUNDLED)
+ add_executable(lz4 ${LZ4_SOURCES})
+
+ install(TARGETS liblz4
+ ARCHIVE DESTINATION "${LIB_DIR}"
+ LIBRARY DESTINATION "${LIB_DIR}"
+ RUNTIME DESTINATION "${BIN_DIR}")
+ install(TARGETS lz4
+ DESTINATION "${BIN_DIR}")
+ install(FILES
+ "${LZ4_SOURCE_DIR}/lib/lz4.h"
+ "${LZ4_SOURCE_DIR}/lib/lz4frame.h"
+ "${LZ4_SOURCE_DIR}/lib/lz4hc.h"
+ DESTINATION "${INCLUDE_DIR}")
+ endif()
+
+ install(FILES
+ "${LZ4_SOURCE_DIR}/lib/LICENSE"
+ "${LZ4_SOURCE_DIR}/programs/COPYING"
+ "${LZ4_SOURCE_DIR}/README.md"
+ DESTINATION "${GRN_DATA_DIR}/lz4")
+endif()
diff --git a/storage/mroonga/vendor/groonga/vendor/lz4/Makefile.am b/storage/mroonga/vendor/groonga/vendor/lz4/Makefile.am
new file mode 100644
index 00000000..8a652320
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/lz4/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+ CMakeLists.txt
diff --git a/storage/mroonga/vendor/groonga/vendor/mecab/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/mecab/CMakeLists.txt
new file mode 100644
index 00000000..6376025c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mecab/CMakeLists.txt
@@ -0,0 +1,219 @@
+# Copyright(C) 2015 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+set(MECAB_VERSION ${GRN_BUNDLED_MECAB_VERSION})
+set(MECAB_DICT_VERSION "102")
+set(MECAB_NAIST_JDIC_VERSION ${GRN_BUNDLED_MECAB_NAIST_JDIC_VERSION})
+
+set(MECAB_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../mecab-${MECAB_VERSION}")
+set(MECAB_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/../mecab-${MECAB_VERSION}")
+set(MECAB_NAIST_JDIC_SOURCE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/../mecab-naist-jdic-${MECAB_NAIST_JDIC_VERSION}")
+
+if(GRN_WITH_BUNDLED_MECAB)
+ include_directories(
+ BEFORE
+ ${MECAB_BINARY_DIR}
+ ${MECAB_SOURCE_DIR}
+ )
+
+ set(MECAB_RELATIVE_DICT_DIR "${DATA_DIR}/mecab/dic")
+ set(MECAB_RELATIVE_NAIST_JDIC_DICT_DIR
+ "${MECAB_RELATIVE_DICT_DIR}/naist-jdic")
+ if(WIN32)
+ string(REGEX REPLACE "/" "\\\\"
+ MECAB_WINDOWS_RELATIVE_NAIST_JDIC_DICT_DIR
+ "${MECAB_RELATIVE_NAIST_JDIC_DICT_DIR}")
+ set(MECAB_NAIST_JDIC_DICT_DIR
+ "$(rcpath)\\..\\${MECAB_WINDOWS_RELATIVE_NAIST_JDIC_DICT_DIR}")
+ else()
+ set(MECAB_NAIST_JDIC_DICT_DIR
+ "$(rcpath)/../${MECAB_RELATIVE_NAIST_JDIC_DICT_DIR}")
+ endif()
+
+ set(LIBMECAB_SOURCES
+ "${MECAB_SOURCE_DIR}/src/char_property.cpp"
+ "${MECAB_SOURCE_DIR}/src/char_property.h"
+ "${MECAB_SOURCE_DIR}/src/common.h"
+ "${MECAB_SOURCE_DIR}/src/connector.cpp"
+ "${MECAB_SOURCE_DIR}/src/connector.h"
+ "${MECAB_SOURCE_DIR}/src/context_id.cpp"
+ "${MECAB_SOURCE_DIR}/src/context_id.h"
+ "${MECAB_SOURCE_DIR}/src/darts.h"
+ "${MECAB_SOURCE_DIR}/src/dictionary.cpp"
+ "${MECAB_SOURCE_DIR}/src/dictionary.h"
+ "${MECAB_SOURCE_DIR}/src/dictionary_compiler.cpp"
+ "${MECAB_SOURCE_DIR}/src/dictionary_generator.cpp"
+ "${MECAB_SOURCE_DIR}/src/dictionary_rewriter.cpp"
+ "${MECAB_SOURCE_DIR}/src/dictionary_rewriter.h"
+ "${MECAB_SOURCE_DIR}/src/eval.cpp"
+ "${MECAB_SOURCE_DIR}/src/feature_index.cpp"
+ "${MECAB_SOURCE_DIR}/src/feature_index.h"
+ "${MECAB_SOURCE_DIR}/src/freelist.h"
+ "${MECAB_SOURCE_DIR}/src/iconv_utils.cpp"
+ "${MECAB_SOURCE_DIR}/src/iconv_utils.h"
+ "${MECAB_SOURCE_DIR}/src/lbfgs.cpp"
+ "${MECAB_SOURCE_DIR}/src/lbfgs.h"
+ "${MECAB_SOURCE_DIR}/src/learner.cpp"
+ "${MECAB_SOURCE_DIR}/src/learner_node.h"
+ "${MECAB_SOURCE_DIR}/src/learner_tagger.cpp"
+ "${MECAB_SOURCE_DIR}/src/learner_tagger.h"
+ "${MECAB_SOURCE_DIR}/src/libmecab.cpp"
+ # "${MECAB_SOURCE_DIR}/src/mecab-cost-train.cpp"
+ # "${MECAB_SOURCE_DIR}/src/mecab-dict-gen.cpp"
+ # "${MECAB_SOURCE_DIR}/src/mecab-system-eval.cpp"
+ # "${MECAB_SOURCE_DIR}/src/mecab-test-gen.cpp"
+ "${MECAB_SOURCE_DIR}/src/mecab.h"
+ "${MECAB_SOURCE_DIR}/src/mmap.h"
+ "${MECAB_SOURCE_DIR}/src/nbest_generator.cpp"
+ "${MECAB_SOURCE_DIR}/src/nbest_generator.h"
+ "${MECAB_SOURCE_DIR}/src/param.cpp"
+ "${MECAB_SOURCE_DIR}/src/param.h"
+ "${MECAB_SOURCE_DIR}/src/scoped_ptr.h"
+ "${MECAB_SOURCE_DIR}/src/stream_wrapper.h"
+ "${MECAB_SOURCE_DIR}/src/string_buffer.cpp"
+ "${MECAB_SOURCE_DIR}/src/string_buffer.h"
+ "${MECAB_SOURCE_DIR}/src/tagger.cpp"
+ "${MECAB_SOURCE_DIR}/src/thread.h"
+ "${MECAB_SOURCE_DIR}/src/tokenizer.cpp"
+ "${MECAB_SOURCE_DIR}/src/tokenizer.h"
+ "${MECAB_SOURCE_DIR}/src/ucs.h"
+ "${MECAB_SOURCE_DIR}/src/ucstable.h"
+ "${MECAB_SOURCE_DIR}/src/utils.cpp"
+ "${MECAB_SOURCE_DIR}/src/utils.h"
+ "${MECAB_SOURCE_DIR}/src/viterbi.cpp"
+ "${MECAB_SOURCE_DIR}/src/viterbi.h"
+ "${MECAB_SOURCE_DIR}/src/winmain.h"
+ "${MECAB_SOURCE_DIR}/src/writer.cpp"
+ "${MECAB_SOURCE_DIR}/src/writer.h"
+ )
+ set(MECAB_SOURCES
+ "${MECAB_SOURCE_DIR}/src/mecab.cpp"
+ )
+ set(MECAB_DICT_INDEX_SOURCES
+ "${MECAB_SOURCE_DIR}/src/mecab-dict-index.cpp"
+ )
+
+ set(MECAB_CXX_COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS}")
+ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGCXX)
+ set(MECAB_CXX_COMPILE_FLAGS
+ "${MECAB_CXX_COMPILE_FLAGS} -Wno-type-limits")
+ set(MECAB_CXX_COMPILE_FLAGS
+ "${MECAB_CXX_COMPILE_FLAGS} -Wno-float-equal")
+ set(MECAB_CXX_COMPILE_FLAGS
+ "${MECAB_CXX_COMPILE_FLAGS} -Wno-ignored-qualifiers")
+ set(MECAB_CXX_COMPILE_FLAGS
+ "${MECAB_CXX_COMPILE_FLAGS} -Wno-unused-function")
+ endif()
+
+ add_definitions("-DPACKAGE=\"mecab\"")
+ add_definitions("-DVERSION=\"${MECAB_VERSION}\"")
+ add_definitions("-DDIC_VERSION=${MECAB_DICT_VERSION}")
+ if(MSVC)
+ add_definitions(
+ "-DMECAB_DEFAULT_RC=\"c:\\\\Program Files\\\\mecab\\\\etc\\\\mecabrc\"")
+ add_definitions(-DMECAB_USE_THREAD)
+ add_definitions(-DDLL_EXPORT)
+ add_definitions(-DHAVE_GETENV)
+ add_definitions(-DHAVE_STRING_H)
+ add_definitions(-DHAVE_UNSIGNED_LONG_LONG_INT)
+ add_definitions(-DHAVE_WINDOWS_H)
+ add_definitions(-DUNICODE)
+ add_definitions(-D_UNICODE)
+ else()
+ add_definitions(
+ "-DMECAB_DEFAULT_RC=\"${CMAKE_INSTALL_PREFIX}/${CONFIG_DIR}/mecabrc\"")
+ add_definitions(
+ "-DICONV_CONST=")
+ add_definitions(-DHAVE_DIRENT_H)
+ add_definitions(-DHAVE_FCNTL_H)
+ add_definitions(-DHAVE_ICONV)
+ add_definitions(-DHAVE_STDINT_H)
+ add_definitions(-DHAVE_STRING_H)
+ add_definitions(-DHAVE_SYS_MMAN_H)
+ add_definitions(-DHAVE_SYS_STAT_H)
+ add_definitions(-DHAVE_SYS_TYPES_H)
+ add_definitions(-DHAVE_UNISTD_H)
+ endif()
+ set_source_files_properties(${LIBMECAB_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${MECAB_CXX_COMPILE_FLAGS}")
+ set_source_files_properties(${MECAB_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS}")
+ set_source_files_properties(${MECAB_DICT_INDEX_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_CXX_COMPILE_FLAGS}")
+
+ add_library(libmecab SHARED ${LIBMECAB_SOURCES})
+ if(NOT MSVC)
+ set_target_properties(libmecab PROPERTIES OUTPUT_NAME "mecab")
+ endif()
+ add_executable(mecab ${MECAB_SOURCES})
+ target_link_libraries(mecab libmecab)
+ add_executable(mecab-dict-index ${MECAB_DICT_INDEX_SOURCES})
+ target_link_libraries(mecab-dict-index libmecab)
+ install(TARGETS libmecab
+ ARCHIVE DESTINATION "${LIB_DIR}"
+ LIBRARY DESTINATION "${LIB_DIR}"
+ RUNTIME DESTINATION "${BIN_DIR}")
+ install(TARGETS mecab
+ DESTINATION "${BIN_DIR}")
+ install(TARGETS mecab-dict-index
+ DESTINATION "${BIN_DIR}")
+ install(FILES "${MECAB_SOURCE_DIR}/src/mecab.h"
+ DESTINATION "${INCLUDE_DIR}")
+
+ set(MECAB_NAIST_JDIC_BUILD_DATA
+ "${CMAKE_CURRENT_BINARY_DIR}/matrix.bin"
+ "${CMAKE_CURRENT_BINARY_DIR}/char.bin"
+ "${CMAKE_CURRENT_BINARY_DIR}/sys.dic"
+ "${CMAKE_CURRENT_BINARY_DIR}/unk.dic")
+ add_custom_command(OUTPUT ${MECAB_NAIST_JDIC_BUILD_DATA}
+ COMMAND
+ mecab-dict-index
+ "--dicdir" "${MECAB_NAIST_JDIC_SOURCE_DIR}"
+ "--outdir" "${CMAKE_CURRENT_BINARY_DIR}"
+ "--dictionary-charset" "EUC-JP"
+ "--charset" "utf-8"
+ DEPENDS mecab-dict-index
+ COMMENT "Build NAIST Japanese Dictionary for MeCab")
+ add_custom_target(mecab-naist-jdic ALL
+ DEPENDS ${MECAB_NAIST_JDIC_BUILD_DATA})
+ install(FILES
+ ${MECAB_NAIST_JDIC_BUILD_DATA}
+ "${MECAB_NAIST_JDIC_SOURCE_DIR}/dicrc"
+ DESTINATION "${MECAB_RELATIVE_NAIST_JDIC_DICT_DIR}")
+
+ configure_file("mecabrc.cmake" "mecabrc")
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mecabrc"
+ DESTINATION "${CONFIG_DIR}")
+
+ install(FILES
+ "${MECAB_NAIST_JDIC_SOURCE_DIR}/AUTHORS"
+ "${MECAB_NAIST_JDIC_SOURCE_DIR}/COPYING"
+ "${MECAB_NAIST_JDIC_SOURCE_DIR}/README"
+ DESTINATION "${GRN_DATA_DIR}/mecab-naist-jdic")
+ install(FILES
+ "${MECAB_SOURCE_DIR}/AUTHORS"
+ "${MECAB_SOURCE_DIR}/BSD"
+ "${MECAB_SOURCE_DIR}/COPYING"
+ "${MECAB_SOURCE_DIR}/GPL"
+ "${MECAB_SOURCE_DIR}/LGPL"
+ "${MECAB_SOURCE_DIR}/README"
+ DESTINATION "${GRN_DATA_DIR}/mecab")
+
+ configure_file(config.h.cmake "${MECAB_BINARY_DIR}/config.h")
+endif()
diff --git a/storage/mroonga/vendor/groonga/vendor/mecab/Makefile.am b/storage/mroonga/vendor/groonga/vendor/mecab/Makefile.am
new file mode 100644
index 00000000..d284d6fc
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mecab/Makefile.am
@@ -0,0 +1,4 @@
+EXTRA_DIST = \
+ CMakeLists.txt \
+ config.h.cmake \
+ mecabrc.cmake
diff --git a/storage/mroonga/vendor/groonga/vendor/mecab/config.h.cmake b/storage/mroonga/vendor/groonga/vendor/mecab/config.h.cmake
new file mode 100644
index 00000000..2997587d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mecab/config.h.cmake
@@ -0,0 +1 @@
+/* dummy */
diff --git a/storage/mroonga/vendor/groonga/vendor/mecab/mecabrc.cmake b/storage/mroonga/vendor/groonga/vendor/mecab/mecabrc.cmake
new file mode 100644
index 00000000..8185cfae
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mecab/mecabrc.cmake
@@ -0,0 +1,3 @@
+; Configuration file of MeCab
+
+dicdir = ${MECAB_NAIST_JDIC_DICT_DIR}
diff --git a/storage/mroonga/vendor/groonga/vendor/message_pack/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/message_pack/CMakeLists.txt
new file mode 100644
index 00000000..bf75f95e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/message_pack/CMakeLists.txt
@@ -0,0 +1,53 @@
+# Copyright(C) 2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+set(MESSAGE_PACK_VERSION ${GRN_BUNDLED_MESSAGE_PACK_VERSION})
+
+set(MESSAGE_PACK_SOURCE_DIR
+ "${CMAKE_CURRENT_SOURCE_DIR}/../msgpack-${MESSAGE_PACK_VERSION}")
+
+if(GRN_WITH_BUNDLED_MESSAGE_PACK)
+ include_directories(
+ BEFORE
+ ${MESSAGE_PACK_SOURCE_DIR}/include
+ )
+
+ set(MESSAGE_PACK_SOURCES
+ "${MESSAGE_PACK_SOURCE_DIR}/src/objectc.c"
+ "${MESSAGE_PACK_SOURCE_DIR}/src/unpack.c"
+ "${MESSAGE_PACK_SOURCE_DIR}/src/version.c"
+ "${MESSAGE_PACK_SOURCE_DIR}/src/vrefbuffer.c"
+ "${MESSAGE_PACK_SOURCE_DIR}/src/zone.c"
+ )
+
+ set_source_files_properties(${MESSAGE_PACK_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+
+ add_library(msgpackc SHARED ${MESSAGE_PACK_SOURCES})
+ install(TARGETS msgpackc
+ ARCHIVE DESTINATION "${LIB_DIR}"
+ LIBRARY DESTINATION "${LIB_DIR}"
+ RUNTIME DESTINATION "${BIN_DIR}")
+ install(DIRECTORY
+ "${MESSAGE_PACK_SOURCE_DIR}/include/"
+ DESTINATION "${INCLUDE_DIR}"
+ FILES_MATCHING PATTERN "*.h")
+ install(FILES
+ "${MESSAGE_PACK_SOURCE_DIR}/COPYING"
+ "${MESSAGE_PACK_SOURCE_DIR}/LICENSE_1_0.txt"
+ "${MESSAGE_PACK_SOURCE_DIR}/README.md"
+ DESTINATION "${GRN_DATA_DIR}/msgpack")
+endif()
diff --git a/storage/mroonga/vendor/groonga/vendor/message_pack/Makefile.am b/storage/mroonga/vendor/groonga/vendor/message_pack/Makefile.am
new file mode 100644
index 00000000..8a652320
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/message_pack/Makefile.am
@@ -0,0 +1,2 @@
+EXTRA_DIST = \
+ CMakeLists.txt
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/mruby/CMakeLists.txt
new file mode 100644
index 00000000..54be31fb
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/CMakeLists.txt
@@ -0,0 +1,101 @@
+# Copyright(C) 2013-2016 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+if(GRN_WITH_MRUBY)
+ set(MRUBY_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../mruby-source")
+
+ include_directories(
+ "${MRUBY_SOURCE_DIR}/include"
+ "${MRUBY_SOURCE_DIR}/src"
+ "${MRUBY_SOURCE_DIR}/mrbgems/mruby-compiler/core"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../onigmo-source"
+ )
+
+ read_file_list("${CMAKE_CURRENT_SOURCE_DIR}/sources.am" MRUBY_SOURCES)
+ string(REGEX REPLACE "\\.\\./" "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ MRUBY_SOURCES "${MRUBY_SOURCES}")
+
+ read_file_list("${CMAKE_CURRENT_SOURCE_DIR}/built_sources.am"
+ MRUBY_BUILT_SOURCES)
+ set(mruby_pre_build_timestamp
+ "${CMAKE_CURRENT_SOURCE_DIR}/mruby_build.timestamp")
+ if(EXISTS "${mruby_pre_build_timestamp}")
+ set(MRUBY_LEGAL_FILE "${CMAKE_CURRENT_SOURCE_DIR}/LEGAL")
+ string(REGEX REPLACE "([^;]+)" "${CMAKE_CURRENT_SOURCE_DIR}/\\1"
+ MRUBY_BUILT_SOURCES "${MRUBY_BUILT_SOURCES}")
+ include_directories(
+ "${CMAKE_CURRENT_SOURCE_DIR}/mruby-io/include"
+ )
+ else()
+ set(mruby_build_timestamp
+ "${CMAKE_CURRENT_BINARY_DIR}/mruby_build.timestamp")
+ if(NOT EXISTS "${mruby_build_timestamp}")
+ execute_process(
+ COMMAND
+ "${RUBY}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/mruby_build.rb"
+ "${CMAKE_CURRENT_SOURCE_DIR}/build_config.rb"
+ "${MRUBY_SOURCE_DIR}"
+ "${CMAKE_CURRENT_BINARY_DIR}/../mruby-build"
+ "${CMAKE_CURRENT_SOURCE_DIR}/../onigmo-source"
+ "${mruby_build_timestamp}"
+ WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
+ RESULT_VARIABLE MRUBY_BUILD_RESULT
+ )
+ if(NOT MRUBY_BUILD_RESULT EQUAL "0")
+ message(FATAL_ERROR "Failed to build mruby files")
+ endif()
+ endif()
+ set(MRUBY_LEGAL_FILE "${CMAKE_CURRENT_BINARY_DIR}/LEGAL")
+ string(REGEX REPLACE "([^;]+)" "${CMAKE_CURRENT_BINARY_DIR}/\\1"
+ MRUBY_BUILT_SOURCES "${MRUBY_BUILT_SOURCES}")
+ include_directories(
+ "${CMAKE_CURRENT_BINARY_DIR}/mruby-io/include"
+ )
+ endif()
+ file(WRITE
+ "${CMAKE_CURRENT_BINARY_DIR}/mruby-file-stat/src/config.h"
+ "")
+
+ set(MRUBY_ALL_SOURCES
+ ${MRUBY_SOURCES}
+ ${MRUBY_BUILT_SOURCES}
+ )
+ add_library(mruby STATIC ${MRUBY_ALL_SOURCES})
+ set_target_properties(
+ mruby
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+
+ set(MRUBY_C_COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANGCC)
+ set(MRUBY_C_COMPILE_FLAGS
+ "${MRUBY_C_COMPILE_FLAGS} -Wno-float-equal")
+ set(MRUBY_C_COMPILE_FLAGS
+ "${MRUBY_C_COMPILE_FLAGS} -Wno-bad-function-cast")
+ endif()
+ if(WIN32)
+ set(MRUBY_DEFINITIONS ${MRUBY_DEFINITIONS} MRB_BUILD_AS_DLL MRB_CORE)
+ endif()
+ set_source_files_properties(${MRUBY_ALL_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${MRUBY_C_COMPILE_FLAGS}")
+ set_property(SOURCE ${MRUBY_ALL_SOURCES}
+ PROPERTY COMPILE_DEFINITIONS ${MRUBY_DEFINITIONS})
+
+ install(FILES
+ "${MRUBY_LEGAL_FILE}"
+ DESTINATION "${GRN_DATA_DIR}/mruby")
+endif()
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/Makefile.am b/storage/mroonga/vendor/groonga/vendor/mruby/Makefile.am
new file mode 100644
index 00000000..6d86565d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/Makefile.am
@@ -0,0 +1,79 @@
+EXTRA_DIST = \
+ LEGAL \
+ CMakeLists.txt \
+ build_config.rb \
+ mruby_build.rb \
+ mruby_build.timestamp \
+ version \
+ mruby-dir/src/Win/dirent.c
+
+DEFAULT_INCLUDES = \
+ -I$(srcdir)/../mruby-source/include \
+ -I$(srcdir)/../mruby-source/src \
+ -I$(srcdir)/../mruby-source/mrbgems/mruby-compiler/core \
+ -Imruby-io/include \
+ -I$(srcdir)/mruby-io/include
+
+CFLAGS += \
+ $(NO_FLOAT_EQUAL_CFLAGS) \
+ $(NO_BAD_FUNCTION_CAST_CFLAGS)
+
+if WITH_MRUBY
+mruby_datadir = $(pkgdatadir)/mruby
+mruby_data_DATA = \
+ LEGAL
+
+noinst_LTLIBRARIES = libmruby.la
+
+AM_CPPFLAGS = \
+ -I$(srcdir)/../onigmo-source \
+ -DHAVE_ONIGMO_H \
+ $(MRUBY_CPPFLAGS)
+
+if PLATFORM_WIN32
+AM_CPPFLAGS += \
+ -DMRB_BUILD_AS_DLL \
+ -DMRB_CORE
+endif
+
+include sources.am
+include built_sources.am
+libmruby_la_SOURCES += $(BUILT_SOURCES)
+
+LEGAL: mruby_build.timestamp
+mrblib.c: mruby_build.timestamp
+mrbgems_init.c: mruby_build.timestamp
+mruby-compiler/core/parse.c: mruby_build.timestamp
+mruby-onig-regexp/src/mruby_onig_regexp.c: mruby_build.timestamp
+mruby-env/src/env.c: mruby_build.timestamp
+mruby-io/include/mruby/ext/io.h: mruby_build.timestamp
+mruby-io/src/file.c: mruby_build.timestamp
+mruby-io/src/file_test.c: mruby_build.timestamp
+mruby-io/src/io.c: mruby_build.timestamp
+mruby-io/src/mruby_io_gem.c: mruby_build.timestamp
+mruby-file-stat/src/file-stat.c: mruby_build.timestamp
+mruby-file-stat/src/config.h: mruby_build.timestamp
+ touch "$(builddir)/$@"
+mruby-dir/src/dir.c: mruby_build.timestamp
+mruby-dir/src/Win/dirent.c: mruby_build.timestamp
+
+MRUBY_CONFIG = $(abs_srcdir)/build_config.rb
+MRUBY_BUILD_DIR = $(abs_top_builddir)/vendor/mruby-build
+mruby_build.timestamp: build_config.rb version
+ $(RUBY) "$(srcdir)/mruby_build.rb" \
+ "$(srcdir)/build_config.rb" \
+ "$(srcdir)/../mruby-source" \
+ "$(builddir)/../mruby-build" \
+ "$(srcdir)/../onigmo-source" \
+ "mruby_build.timestamp"
+
+CLEANFILES = *.gcno *gcda
+MAINTAINERCLEANFILES = mruby_build.timestamp
+endif
+
+update:
+ cd "$(srcdir)/../mruby-source" && \
+ (git checkout master && git pull --rebase)
+ (cd "$(srcdir)/../mruby-source" && git describe) > version
+ cd "$(srcdir)" && \
+ ./update.rb build_config.rb ../mruby-source > sources.am
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/build_config.rb b/storage/mroonga/vendor/groonga/vendor/mruby/build_config.rb
new file mode 100644
index 00000000..335a383d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/build_config.rb
@@ -0,0 +1,54 @@
+MRuby::Build.new do |conf|
+ if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR']
+ toolchain :visualcpp
+ else
+ toolchain :gcc
+ end
+
+ oniguruma_include_path = ENV["MRUBY_ONIGURUMA_INCLUDE_PATH"]
+ if oniguruma_include_path
+ conf.cc.include_paths << oniguruma_include_path
+ end
+
+ enable_debug
+
+ conf.gem :core => "mruby-compiler"
+ conf.gem :core => "mruby-sprintf"
+ conf.gem :core => "mruby-print"
+ conf.gem :core => "mruby-math"
+ conf.gem :core => "mruby-time"
+ conf.gem :core => "mruby-struct"
+ conf.gem :core => "mruby-enum-ext"
+ conf.gem :core => "mruby-string-ext"
+ conf.gem :core => "mruby-numeric-ext"
+ conf.gem :core => "mruby-array-ext"
+ conf.gem :core => "mruby-hash-ext"
+ conf.gem :core => "mruby-range-ext"
+ conf.gem :core => "mruby-proc-ext"
+ conf.gem :core => "mruby-symbol-ext"
+ conf.gem :core => "mruby-random"
+ conf.gem :core => "mruby-object-ext"
+ conf.gem :core => "mruby-objectspace"
+ conf.gem :core => "mruby-fiber"
+ conf.gem :core => "mruby-enumerator"
+ conf.gem :core => "mruby-enum-lazy"
+ conf.gem :core => "mruby-toplevel-ext"
+ conf.gem :core => "mruby-kernel-ext"
+
+ conf.gem :github => "mattn/mruby-onig-regexp",
+ :checksum_hash => "12f573cb327aa50834c3a549f62995f44edd3172"
+ conf.gem :github => "iij/mruby-env",
+ :checksum_hash => "57f0d737a4ece49dc5b6f1c7ee09b0bc8f8adf87"
+ conf.gem :github => "iij/mruby-io",
+ :checksum_hash => "69623078a86b45617a6fdbe0238c147e280ad9db"
+ conf.gem :github => "kou/mruby-pp",
+ :checksum_hash => "ddda20ca273ba532f2025d4ff7ddc8bb223ad8c2"
+ conf.gem :github => "kou/mruby-slop",
+ :checksum_hash => "752d1a3e2bc4fdc40ee92d668812a99c8fc5e1cc"
+ conf.gem :github => "ksss/mruby-file-stat",
+ :checksum_hash => "2d3ea9b5d59d2b41133228a71c110b75cb30a31e"
+ conf.gem :github => "kou/mruby-tsort",
+ :checksum_hash => "6d7f5a56ac7a90847f84186ce1dbc780e41928dc"
+ conf.gem :github => "iij/mruby-dir",
+ :checksum_hash => "14bc5c3e51eac16ebc9075b7b62132a0cf5ae724"
+end
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/built_sources.am b/storage/mroonga/vendor/groonga/vendor/mruby/built_sources.am
new file mode 100644
index 00000000..26151266
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/built_sources.am
@@ -0,0 +1,14 @@
+BUILT_SOURCES = \
+ mrblib.c \
+ mrbgems_init.c \
+ mruby-compiler/core/parse.c \
+ mruby-onig-regexp/src/mruby_onig_regexp.c \
+ mruby-env/src/env.c \
+ mruby-io/include/mruby/ext/io.h \
+ mruby-io/src/file.c \
+ mruby-io/src/file_test.c \
+ mruby-io/src/io.c \
+ mruby-io/src/mruby_io_gem.c \
+ mruby-file-stat/src/config.h \
+ mruby-file-stat/src/file-stat.c \
+ mruby-dir/src/dir.c
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/mruby_build.rb b/storage/mroonga/vendor/groonga/vendor/mruby/mruby_build.rb
new file mode 100755
index 00000000..c0a86448
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/mruby_build.rb
@@ -0,0 +1,65 @@
+#!/usr/bin/env ruby
+
+if ARGV.size != 5
+ puts("Usage: #{$0} BUILD_COFNIG.RB MRUBY_SOURCE_DIR MRUBY_BUILD_DIR ONIGURUMA_INCLUDE_PATH TIMESTAMP_FILE")
+ exit(false)
+end
+
+require "rbconfig"
+require "fileutils"
+
+build_config_rb = File.expand_path(ARGV.shift)
+mruby_source_dir = ARGV.shift
+mruby_build_dir = File.expand_path(ARGV.shift)
+oniguruma_include_path = File.expand_path(ARGV.shift)
+timestamp_file = File.expand_path(ARGV.shift)
+
+FileUtils.rm_rf(mruby_build_dir)
+
+Dir.chdir(mruby_source_dir) do
+ unless system(RbConfig.ruby,
+ "minirake",
+ "MRUBY_CONFIG=#{build_config_rb}",
+ "MRUBY_BUILD_DIR=#{mruby_build_dir}",
+ "MRUBY_ONIGURUMA_INCLUDE_PATH=#{oniguruma_include_path}")
+ exit(false)
+ end
+end
+
+FileUtils.touch(timestamp_file)
+
+FileUtils.cp("#{mruby_build_dir}/host/LEGAL", "./")
+
+FileUtils.cp("#{mruby_build_dir}/host/mrblib/mrblib.c", "./")
+
+File.open("mrbgems_init.c", "w") do |mrbgems_init|
+ Dir.glob("#{mruby_build_dir}/host/mrbgems/**/gem_init.c") do |gem_init|
+ mrbgems_init.puts(File.read(gem_init))
+ end
+end
+
+mruby_compiler_dir = "#{mruby_build_dir}/host/mrbgems/mruby-compiler"
+FileUtils.mkdir_p("mruby-compiler/core/")
+FileUtils.cp("#{mruby_compiler_dir}/core/y.tab.c",
+ "mruby-compiler/core/parse.c")
+
+mruby_onig_regexp_dir = "#{mruby_build_dir}/mrbgems/mruby-onig-regexp"
+FileUtils.mkdir_p("mruby-onig-regexp/")
+FileUtils.cp_r("#{mruby_onig_regexp_dir}/src/", "mruby-onig-regexp/")
+
+mruby_env_dir = "#{mruby_build_dir}/mrbgems/mruby-env"
+FileUtils.mkdir_p("mruby-env/")
+FileUtils.cp_r("#{mruby_env_dir}/src/", "mruby-env/")
+
+mruby_io_dir = "#{mruby_build_dir}/mrbgems/mruby-io"
+FileUtils.mkdir_p("mruby-io/")
+FileUtils.cp_r("#{mruby_io_dir}/include/", "mruby-io/")
+FileUtils.cp_r("#{mruby_io_dir}/src/", "mruby-io/")
+
+mruby_file_stat_dir = "#{mruby_build_dir}/mrbgems/mruby-file-stat"
+FileUtils.mkdir_p("mruby-file-stat/")
+FileUtils.cp_r("#{mruby_file_stat_dir}/src/", "mruby-file-stat/")
+
+mruby_dir_dir = "#{mruby_build_dir}/mrbgems/mruby-dir"
+FileUtils.mkdir_p("mruby-dir/")
+FileUtils.cp_r("#{mruby_dir_dir}/src/", "mruby-dir/")
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/sources.am b/storage/mroonga/vendor/groonga/vendor/mruby/sources.am
new file mode 100644
index 00000000..78ecc9b8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/sources.am
@@ -0,0 +1,57 @@
+libmruby_la_SOURCES = \
+ ../mruby-source/src/array.c \
+ ../mruby-source/src/backtrace.c \
+ ../mruby-source/src/class.c \
+ ../mruby-source/src/codedump.c \
+ ../mruby-source/src/compar.c \
+ ../mruby-source/src/crc.c \
+ ../mruby-source/src/debug.c \
+ ../mruby-source/src/dump.c \
+ ../mruby-source/src/enum.c \
+ ../mruby-source/src/error.c \
+ ../mruby-source/src/error.h \
+ ../mruby-source/src/etc.c \
+ ../mruby-source/src/fmt_fp.c \
+ ../mruby-source/src/gc.c \
+ ../mruby-source/src/hash.c \
+ ../mruby-source/src/init.c \
+ ../mruby-source/src/kernel.c \
+ ../mruby-source/src/load.c \
+ ../mruby-source/src/numeric.c \
+ ../mruby-source/src/object.c \
+ ../mruby-source/src/opcode.h \
+ ../mruby-source/src/pool.c \
+ ../mruby-source/src/print.c \
+ ../mruby-source/src/proc.c \
+ ../mruby-source/src/range.c \
+ ../mruby-source/src/state.c \
+ ../mruby-source/src/string.c \
+ ../mruby-source/src/symbol.c \
+ ../mruby-source/src/value_array.h \
+ ../mruby-source/src/variable.c \
+ ../mruby-source/src/version.c \
+ ../mruby-source/src/vm.c \
+ ../mruby-source/mrbgems/mruby-compiler/core/codegen.c \
+ ../mruby-source/mrbgems/mruby-compiler/core/node.h \
+ ../mruby-source/mrbgems/mruby-sprintf/src/kernel.c \
+ ../mruby-source/mrbgems/mruby-sprintf/src/sprintf.c \
+ ../mruby-source/mrbgems/mruby-print/src/print.c \
+ ../mruby-source/mrbgems/mruby-math/src/math.c \
+ ../mruby-source/mrbgems/mruby-time/src/time.c \
+ ../mruby-source/mrbgems/mruby-struct/src/struct.c \
+ ../mruby-source/mrbgems/mruby-string-ext/src/string.c \
+ ../mruby-source/mrbgems/mruby-numeric-ext/src/numeric_ext.c \
+ ../mruby-source/mrbgems/mruby-array-ext/src/array.c \
+ ../mruby-source/mrbgems/mruby-hash-ext/src/hash-ext.c \
+ ../mruby-source/mrbgems/mruby-range-ext/src/range.c \
+ ../mruby-source/mrbgems/mruby-proc-ext/src/proc.c \
+ ../mruby-source/mrbgems/mruby-proc-ext/test/proc.c \
+ ../mruby-source/mrbgems/mruby-symbol-ext/src/symbol.c \
+ ../mruby-source/mrbgems/mruby-random/src/mt19937ar.c \
+ ../mruby-source/mrbgems/mruby-random/src/mt19937ar.h \
+ ../mruby-source/mrbgems/mruby-random/src/random.c \
+ ../mruby-source/mrbgems/mruby-random/src/random.h \
+ ../mruby-source/mrbgems/mruby-object-ext/src/object.c \
+ ../mruby-source/mrbgems/mruby-objectspace/src/mruby_objectspace.c \
+ ../mruby-source/mrbgems/mruby-fiber/src/fiber.c \
+ ../mruby-source/mrbgems/mruby-kernel-ext/src/kernel.c
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/update.rb b/storage/mroonga/vendor/groonga/vendor/mruby/update.rb
new file mode 100755
index 00000000..888c3d30
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/update.rb
@@ -0,0 +1,88 @@
+#!/usr/bin/env ruby
+
+if ARGV.size != 2
+ puts("Usage: #{$0} BUILD_COFNIG.RB MRUBY_SOURCE_DIR")
+ exit(false)
+end
+
+require "find"
+
+build_config_rb = ARGV.shift
+mruby_source_dir = ARGV.shift
+
+module MRuby
+ class Build
+ class << self
+ def source_dir=(dir)
+ @@source_dir = dir
+ end
+
+ def latest
+ @@latest
+ end
+ end
+
+ attr_reader :config
+ def initialize(&block)
+ @@latest = self
+ @config = Config.new(@@source_dir)
+ @config.instance_eval(&block)
+ end
+ end
+
+ class Config
+ attr_reader :gem_dirs
+ def initialize(source_dir)
+ @source_dir = source_dir
+ @gem_dirs = []
+ end
+
+ def toolchain(*args)
+ # ignore
+ end
+
+ def enable_debug
+ # ignore
+ end
+
+ def gem(gem_dir)
+ if gem_dir.is_a?(Hash)
+ gem_dir = load_special_path_gem(gem_dir)
+ return if gem_dir.nil?
+ end
+ @gem_dirs << gem_dir
+ end
+
+ private
+ def load_special_path_gem(params)
+ if params[:core]
+ "#{@source_dir}/mrbgems/#{params[:core]}"
+ elsif params[:github]
+ nil
+ else
+ raise "Unsupported gem options: #{params.inspect}"
+ end
+ end
+ end
+end
+
+MRuby::Build.source_dir = mruby_source_dir
+load build_config_rb
+build = MRuby::Build.latest
+
+sources = []
+source_dirs = ["#{mruby_source_dir}/src"] + build.config.gem_dirs
+source_dirs.each do |source_dir|
+ Find.find(source_dir) do |path|
+ case path
+ when /\.[ch]\z/
+ sources << path
+ end
+ end
+end
+
+indented_sources = sources.collect do |source|
+ "\t#{source}"
+end
+puts("libmruby_la_SOURCES = \\")
+puts(indented_sources.join(" \\\n"))
diff --git a/storage/mroonga/vendor/groonga/vendor/mruby/version b/storage/mroonga/vendor/groonga/vendor/mruby/version
new file mode 100644
index 00000000..232c2993
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/mruby/version
@@ -0,0 +1 @@
+1.0.0-3861-ge5b61d34
diff --git a/storage/mroonga/vendor/groonga/vendor/onigmo/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/onigmo/CMakeLists.txt
new file mode 100644
index 00000000..664df222
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/onigmo/CMakeLists.txt
@@ -0,0 +1,147 @@
+# Copyright(C) 2015 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+if(GRN_WITH_ONIGMO)
+ set(ONIGMO_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../onigmo-source")
+ set(ONIGMO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/../onigmo-source")
+
+ include(CheckTypeSize)
+
+ macro(ac_check_sizeof type)
+ string(TOUPPER "${type}" output_variable_base_name)
+ string(REPLACE "*" "P"
+ output_variable_base_name
+ "${output_variable_base_name}")
+ string(REPLACE " " "_"
+ output_variable_base_name
+ "${output_variable_base_name}")
+ set(output_variable_name "ONIG_SIZEOF_${output_variable_base_name}")
+ check_type_size(${type} ${output_variable_name})
+ if(HAVE_${output_variable_name})
+ add_definitions(
+ -DSIZEOF_${output_variable_base_name}=${${output_variable_name}}
+ )
+ endif()
+ endmacro()
+
+ ac_check_sizeof(short)
+ ac_check_sizeof(int)
+ ac_check_sizeof(long)
+ ac_check_sizeof("void*")
+ ac_check_sizeof("long long")
+
+ add_definitions(-DHAVE_STDARG_H)
+ add_definitions(-DHAVE_STDINT_H)
+ add_definitions(-DHAVE_STDLIB_H)
+ add_definitions(-DHAVE_STRING_H)
+ add_definitions(-DHAVE_SYS_TYPES_H)
+
+ add_definitions(-DSTDC_HEADERS)
+
+ if(MSVC)
+ add_definitions(-Dinline=__inline)
+ add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+ else()
+ add_definitions(-DHAVE_INTTYPES_H)
+ endif()
+
+ include_directories(
+ BEFORE
+ ${ONIGMO_BINARY_DIR}
+ ${ONIGMO_SOURCE_DIR}
+ ${ONIGMO_SOURCE_DIR}/enc/unicode
+ )
+
+ set(ONIGMO_SOURCES
+ "${ONIGMO_SOURCE_DIR}/regint.h"
+ "${ONIGMO_SOURCE_DIR}/regparse.h"
+ "${ONIGMO_SOURCE_DIR}/regenc.h"
+ "${ONIGMO_SOURCE_DIR}/st.h"
+ "${ONIGMO_SOURCE_DIR}/regerror.c"
+ "${ONIGMO_SOURCE_DIR}/regparse.c"
+ "${ONIGMO_SOURCE_DIR}/regext.c"
+ "${ONIGMO_SOURCE_DIR}/regcomp.c"
+ "${ONIGMO_SOURCE_DIR}/regexec.c"
+ "${ONIGMO_SOURCE_DIR}/reggnu.c"
+ "${ONIGMO_SOURCE_DIR}/regenc.c"
+ "${ONIGMO_SOURCE_DIR}/regsyntax.c"
+ "${ONIGMO_SOURCE_DIR}/regtrav.c"
+ "${ONIGMO_SOURCE_DIR}/regversion.c"
+ "${ONIGMO_SOURCE_DIR}/st.c"
+ "${ONIGMO_SOURCE_DIR}/regposix.c"
+ "${ONIGMO_SOURCE_DIR}/regposerr.c"
+ "${ONIGMO_SOURCE_DIR}/enc/unicode.c"
+ "${ONIGMO_SOURCE_DIR}/enc/ascii.c"
+ "${ONIGMO_SOURCE_DIR}/enc/utf_8.c"
+ "${ONIGMO_SOURCE_DIR}/enc/utf_16be.c"
+ "${ONIGMO_SOURCE_DIR}/enc/utf_16le.c"
+ "${ONIGMO_SOURCE_DIR}/enc/utf_32be.c"
+ "${ONIGMO_SOURCE_DIR}/enc/utf_32le.c"
+ "${ONIGMO_SOURCE_DIR}/enc/unicode/casefold.h"
+ "${ONIGMO_SOURCE_DIR}/enc/unicode/name2ctype.h"
+ "${ONIGMO_SOURCE_DIR}/enc/euc_jp.c"
+ "${ONIGMO_SOURCE_DIR}/enc/shift_jis.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_31j.c"
+ "${ONIGMO_SOURCE_DIR}/enc/jis/props.h"
+# "${ONIGMO_SOURCE_DIR}/enc/jis/props.kwd"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859.h"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_1.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_2.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_3.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_4.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_5.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_6.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_7.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_8.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_9.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_10.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_11.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_13.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_14.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_15.c"
+ "${ONIGMO_SOURCE_DIR}/enc/iso_8859_16.c"
+ "${ONIGMO_SOURCE_DIR}/enc/euc_tw.c"
+ "${ONIGMO_SOURCE_DIR}/enc/euc_kr.c"
+ "${ONIGMO_SOURCE_DIR}/enc/big5.c"
+ "${ONIGMO_SOURCE_DIR}/enc/gb18030.c"
+ "${ONIGMO_SOURCE_DIR}/enc/koi8_r.c"
+ "${ONIGMO_SOURCE_DIR}/enc/koi8_u.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_1250.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_1251.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_1252.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_1253.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_1254.c"
+ "${ONIGMO_SOURCE_DIR}/enc/windows_1257.c"
+ )
+
+ set(ONIGMO_C_COMPILE_FLAGS "${GRN_C_COMPILE_FLAGS}")
+
+ add_library(onigmo STATIC ${ONIGMO_SOURCES})
+ set_source_files_properties(${ONIGMO_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "${ONIGMO_C_COMPILE_FLAGS}")
+ set_target_properties(
+ onigmo
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+
+ configure_file(config.h.cmake "${ONIGMO_BINARY_DIR}/config.h")
+
+ install(FILES
+ "${ONIGMO_SOURCE_DIR}/AUTHORS"
+ "${ONIGMO_SOURCE_DIR}/COPYING"
+ "${ONIGMO_SOURCE_DIR}/README"
+ DESTINATION "${GRN_DATA_DIR}/onigmo")
+endif()
diff --git a/storage/mroonga/vendor/groonga/vendor/onigmo/Makefile.am b/storage/mroonga/vendor/groonga/vendor/onigmo/Makefile.am
new file mode 100644
index 00000000..2e77323f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/onigmo/Makefile.am
@@ -0,0 +1,32 @@
+EXTRA_DIST = \
+ configure \
+ config.h.cmake \
+ CMakeLists.txt
+
+CONFIGURE_DEPENDENCIES = \
+ configure
+
+if WITH_BUNDLED_ONIGMO
+ALL_DEPEND_TARGETS = onigmo-all
+CLEAN_DEPEND_TARGETS = onigmo-clean
+
+INSTALL_DEPEND_TARGETS = onigmo-all
+if WITH_SHARED_ONIGMO
+INSTALL_DEPEND_TARGETS += onigmo-install
+endif
+
+onigmo-all:
+ cd ../onigmo-source && $(MAKE) all
+
+all: $(ALL_DEPEND_TARGETS)
+
+onigmo-install:
+ cd ../onigmo-source && $(MAKE) install
+
+install: $(INSTALL_DEPEND_TARGETS)
+
+onigmo-clean:
+ cd ../onigmo-source && $(MAKE) clean
+
+clean: $(CLEAN_DEPEND_TARGETS)
+endif
diff --git a/storage/mroonga/vendor/groonga/vendor/onigmo/config.h.cmake b/storage/mroonga/vendor/groonga/vendor/onigmo/config.h.cmake
new file mode 100644
index 00000000..2997587d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/onigmo/config.h.cmake
@@ -0,0 +1 @@
+/* dummy */
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/plugins/CMakeLists.txt
new file mode 100644
index 00000000..199baee8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright(C) 2013 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+file(GLOB
+ PLUGIN_CMAKE_LISTS_LIST
+ RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/*/CMakeLists.txt")
+if(PLUGIN_CMAKE_LISTS_LIST)
+ foreach(PLUGIN_CMAKE_LISTS "${PLUGIN_CMAKE_LISTS_LIST}")
+ string(REGEX REPLACE
+ "(/+CMakeLists\\.txt$)" ""
+ PLUGIN_DIR
+ "${PLUGIN_CMAKE_LISTS}")
+ add_subdirectory("${PLUGIN_DIR}")
+ endforeach(PLUGIN_CMAKE_LISTS)
+endif()
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/CMakeLists.txt
new file mode 100644
index 00000000..4c2aa343
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/CMakeLists.txt
@@ -0,0 +1,81 @@
+# Copyright(C) 2013-2015 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 Library General Public
+# License as published by the Free Software Foundation; version 2
+# of the License.
+#
+# 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1335 USA
+
+cmake_minimum_required(VERSION 2.6)
+if(NOT DEFINED GROONGA_NORMALIZER_MYSQL_PROJECT_NAME)
+ set(GROONGA_NORMALIZER_MYSQL_PROJECT_NAME "groonga-normalizer-mysql")
+endif()
+project("${GROONGA_NORMALIZER_MYSQL_PROJECT_NAME}")
+
+if(DEFINED GROONGA_NORMALIZER_MYSQL_EMBED)
+ set(GROONGA_NORMALIZER_MYSQL_EMBED_DEFAULT
+ ${GROONGA_NORMALIZER_MYSQL_EMBED})
+else()
+ set(GROONGA_NORMALIZER_MYSQL_EMBED_DEFAULT OFF)
+endif()
+set(GROONGA_NORMALIZER_MYSQL_EMBED ${GROONGA_NORMALIZER_MYSQL_EMBED_DEFAULT}
+ CACHE BOOL "Build as a static library to embed into an application")
+
+file(READ "${CMAKE_CURRENT_SOURCE_DIR}/version_full" VERSION)
+
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ set(GROONGA_NORMALIZER_MYSQL_BUNDLED FALSE)
+else()
+ set(GROONGA_NORMALIZER_MYSQL_BUNDLED TRUE)
+endif()
+
+if(GROONGA_NORMALIZER_MYSQL_BUNDLED)
+ set(GROONGA_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include")
+ set(GROONGA_LIBRARY_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/lib")
+ set(GROONGA_LIBRARIES "libgroonga")
+ set(GROONGA_PLUGINS_DIR "${GRN_RELATIVE_PLUGINS_DIR}")
+else()
+ include(FindPkgConfig)
+ include(${CMAKE_CURRENT_SOURCE_DIR}/build/cmake_modules/ReadFileList.cmake)
+
+ file(READ
+ ${CMAKE_CURRENT_SOURCE_DIR}/required_groonga_version
+ GROONGA_REQUIRED_VERSION)
+ string(STRIP "${GROONGA_REQUIRED_VERSION}" GROONGA_REQUIRED_VERSION)
+
+ pkg_check_modules(GROONGA REQUIRED "groonga >= ${GROONGA_REQUIRED_VERSION}")
+ _pkgconfig_invoke(groonga GROONGA PLUGINS_DIR "" --variable=pluginsdir)
+endif()
+
+include_directories(
+ ${CMAKE_BINARY_DIR}
+ ${GROONGA_INCLUDE_DIRS})
+
+link_directories(
+ ${GROONGA_LIBRARY_DIRS})
+
+add_subdirectory(normalizers)
+
+if(NOT GROONGA_NORMALIZER_MYSQL_EMBED)
+ configure_file(
+ groonga-normalizer-mysql.pc.in
+ "${CMAKE_CURRENT_BINARY_DIR}/groonga-normalizer-mysql.pc"
+ @ONLY)
+ install(
+ FILES "${CMAKE_CURRENT_BINARY_DIR}/groonga-normalizer-mysql.pc"
+ DESTINATION "lib/pkgconfig/")
+endif()
+
+install(FILES
+ "README.md"
+ "doc/text/lgpl-2.0.txt"
+ DESTINATION "share/${GROONGA_NORMALIZER_MYSQL_PROJECT_NAME}")
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/Makefile.am
new file mode 100644
index 00000000..16d8d961
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/Makefile.am
@@ -0,0 +1,84 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = \
+ build \
+ normalizers \
+ packages \
+ test \
+ doc
+
+docdir = $(datadir)/doc/$(PACKAGE)
+dist_doc_DATA = \
+ README.md
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = groonga-normalizer-mysql.pc
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+update-tables:
+ cd normalizers && $(MAKE) update-tables
+
+echo-groonga:
+ @echo $(GROONGA)
+
+echo-groonga-httpd:
+ @echo $(GROONGA_HTTPD)
+
+echo-ruby:
+ @echo $(RUBY)
+
+tag:
+ cd $(top_srcdir) && git tag v$(VERSION) -a -m 'groonga-normalizer-mysql $(VERSION)!!!'
+
+update-version:
+ @if test -z "$(NEW_VERSION)"; then \
+ echo "\$$(NEW_VERSION) is missing"; \
+ exit 1; \
+ fi
+ @echo -n $(NEW_VERSION) > $(srcdir)/version
+
+update-latest-release: misc
+ @if test -z "$(OLD_RELEASE)"; then \
+ echo "\$$(OLD_RELEASE) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(OLD_RELEASE_DATE)"; then \
+ echo "\$$(OLD_RELEASE_DATE) is missing"; \
+ exit 1; \
+ fi
+ @if test -z "$(NEW_RELEASE_DATE)"; then \
+ echo "\$$(NEW_RELEASE_DATE) is missing"; \
+ exit 1; \
+ fi
+ cd $(top_srcdir) && \
+ misc/update-latest-release.rb \
+ $(PACKAGE) $(OLD_RELEASE) $(OLD_RELEASE_DATE) \
+ $(VERSION) $(NEW_RELEASE_DATE) \
+ packages/rpm/fedora/groonga-normalizer-mysql.spec.in \
+ packages/rpm/centos/groonga-normalizer-mysql.spec.in \
+ packages/debian/changelog
+
+misc:
+ @if test -z "$(CUTTER_SOURCE_PATH)"; then \
+ echo "\$$(CUTTER_SOURCE_PATH) is missing"; \
+ exit 1; \
+ fi
+ ln -s "$(CUTTER_SOURCE_PATH)/misc" misc
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/README.md b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/README.md
new file mode 100644
index 00000000..fae74b6c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/README.md
@@ -0,0 +1,211 @@
+# README
+
+## Name
+
+groonga-normalizer-mysql
+
+## Description
+
+Groonga-normalizer-mysql is a Groonga plugin. It provides MySQL
+compatible normalizers and a custom normalizers to Groonga.
+
+Here are MySQL compatible normalizers:
+
+* `NormalizerMySQLGeneralCI` for `utf8mb4_general_ci`
+* `NormalizerMySQLUnicodeCI` for `utf8mb4_unicode_ci`
+* `NormalizerMySQLUnicode520CI` for `utf8mb4_unicode_520_ci`
+
+Here are custom normalizers:
+
+* `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark`
+ * It's based on `NormalizerMySQLUnicodeCI`
+* `NormalizerMySQLUnicode520CIExceptKanaCIKanaWithVoicedSoundMark`
+ * It's based on `NormalizerMySQLUnicode520CI`
+
+They are self-descriptive name but long. They are variant normalizers
+of `NormalizerMySQLUnicodeCI` and `NormalizerMySQLUnicode520CI`. They
+have different behaviors. The followings are the different
+behaviors. They describes with
+`NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark` but they
+are true for
+`NormalizerMySQLUnicode520CIExceptKanaCIKanaWithVoicedSoundMark`.
+
+* `NormalizerMySQLUnicodeCI` normalizes all small Hiragana such as `ぁ`,
+ `っ` to Hiragana such as `あ`, `つ`.
+ `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark`
+ doesn't normalize `ぁ` to `あ` nor `っ` to `つ`. `ぁ` and `あ` are
+ different characters. `っ` and `つ` are also different characters.
+ This behavior is described by `ExceptKanaCI` in the long name. This
+ following behaviors ared described by
+ `ExceptKanaWithVoicedSoundMark` in the long name.
+* `NormalizerMySQLUnicode` normalizes all Hiragana with voiced sound
+ mark such as `が` to Hiragana without voiced sound mark such as `か`.
+ `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark` doesn't
+ normalize `が` to `か`. `が` and `か` are different characters.
+* `NormalizerMySQLUnicode` normalizes all Hiragana with semi-voiced sound
+ mark such as `ぱ` to Hiragana without semi-voiced sound mark such as `は`.
+ `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark` doesn't
+ normalize `ぱ` to `は`. `ぱ` and `は` are different characters.
+* `NormalizerMySQLUnicode` normalizes all Katakana with voiced sound
+ mark such as `ガ` to Katakana without voiced sound mark such as `カ`.
+ `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark` doesn't
+ normalize `ガ` to `カ`. `ガ` and `カ` are different characters.
+* `NormalizerMySQLUnicode` normalizes all Katakana with semi-voiced sound
+ mark such as `パ` to Hiragana without semi-voiced sound mark such as `ハ`.
+ `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark` doesn't
+ normalize `パ` to `ハ`. `パ` and `ハ` are different characters.
+* `NormalizerMySQLUnicode` normalizes all halfwidth Katakana with
+ voiced sound mark such as `ガ` to halfwidth Katakana without voiced
+ sound mark such as `カ`.
+ `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark`
+ normalizes all halfwidth Katakana with voided sound mark such as `ガ`
+ to fullwidth Katakana with voiced sound mark such as `ガ`.
+
+`NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark` and
+`NormalizerMySQLUnicode520CIExceptKanaCIKanaWithVoicedSoundMark` and
+are MySQL incompatible normalizers but they are useful for Japanese
+text. For example, `ふらつく` and `ブラック` has different
+means. `NormalizerMySQLUnicodeCI` identifies `ふらつく` with `ブラック`
+but `NormalizerMySQLUnicodeCIExceptKanaCIKanaWithVoicedSoundMark`
+doesn't identify them.
+
+## Install
+
+### Debian GNU/Linux
+
+[Add apt-line for the Groonga deb package repository](http://groonga.org/docs/install/debian.html)
+and install `groonga-normalizer-mysql` package:
+
+ % sudo apt-get -y install groonga-normalizer-mysql
+
+### Ubuntu
+
+[Add apt-line for the Groonga deb package repository](http://groonga.org/docs/install/ubuntu.html)
+and install `groonga-normalizer-mysql` package:
+
+ % sudo apt-get -y install groonga-normalizer-mysql
+
+### CentOS
+
+Install `groonga-repository` package:
+
+ % sudo rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
+ % sudo yum makecache
+
+Then install `groonga-normalizer-mysql` package:
+
+ % sudo yum install -y groonga-normalizer-mysql
+
+### Fedora
+
+Install `groonga-repository` package:
+
+ % sudo rpm -ivh http://packages.groonga.org/fedora/groonga-release-1.1.0-1.noarch.rpm
+ % sudo yum makecache
+
+Then install `groonga-normalizer-mysql` package:
+
+ % sudo yum install -y groonga-normalizer-mysql
+
+### OS X - Homebrew
+
+Install `groonga-normalizer-mysql` package:
+
+ % brew install groonga-normalizer-mysql
+
+### Windows
+
+You need to build from source. Here are build instructions.
+
+#### Build system
+
+Install the following build tools:
+
+* [Microsoft Visual Studio 2010 Express](http://www.microsoft.com/japan/msdn/vstudio/express/): 2012 isn't tested yet.
+* [CMake](http://www.cmake.org/)
+
+#### Build Groonga
+
+Download the latest Groonga source from [packages.groonga.org](http://packages.groonga.org/source/groonga/). Source file name is formatted as `groonga-X.Y.Z.zip`.
+
+Extract the source and move to the source folder:
+
+ > cd ...\groonga-X.Y.Z
+ groonga-X.Y.Z>
+
+Run CMake. Here is a command line to install Groonga to `C:\groonga` folder:
+
+ groonga-X.Y.Z> cmake . -G "Visual Studio 12 Win64" -DCMAKE_INSTALL_PREFIX=C:\groonga
+
+Build:
+
+ groonga-X.Y.Z> cmake --build . --config Release
+
+Install:
+
+ groonga-X.Y.Z> cmake --build . --config Release --target Install
+
+#### Build groonga-normalizer-mysql
+
+Download the latest groonga-normalizer-mysql source from [packages.groonga.org](http://packages.groonga.org/source/groonga-normalizer-mysql/). Source file name is formatted as `groonga-normalizer-X.Y.Z.zip`.
+
+Extract the source and move to the source folder:
+
+ > cd ...\groonga-normalizer-mysql-X.Y.Z
+ groonga-normalizer-mysql-X.Y.Z>
+
+IMPORTANT!!!: Set `PKG_CONFIG_PATH` environment variable:
+
+ groonga-normalizer-mysql-X.Y.Z> set PKG_CONFIG_PATH=C:\groongalocal\lib\pkgconfig
+
+Run CMake. Here is a command line to install Groonga to `C:\groonga` folder:
+
+ groonga-normalizer-mysql-X.Y.Z> cmake . -G "Visual Studio 12 Win64" -DCMAKE_INSTALL_PREFIX=C:\groonga
+
+Build:
+
+ groonga-normalizer-mysql-X.Y.Z> cmake --build . --config Release
+
+Install:
+
+ groonga-normalizer-mysql-X.Y.Z> cmake --build . --config Release --target Install
+
+## Usage
+
+First, you need to register `normalizers/mysql` plugin:
+
+ groonga> register normalizers/mysql
+
+Then, you can use `NormalizerMySQLGeneralCI` and
+`NormalizerMySQLUnicodeCI` as normalizers:
+
+ groonga> table_create Lexicon TABLE_PAT_KEY --default_tokenizer TokenBigram --normalizer NormalizerMySQLGeneralCI
+
+## Dependencies
+
+* Groonga >= 3.0.3
+
+## Mailing list
+
+* English: [groonga-talk@lists.sourceforge.net](https://lists.sourceforge.net/lists/listinfo/groonga-talk)
+* Japanese: [groonga-dev@lists.sourceforge.jp](http://lists.sourceforge.jp/mailman/listinfo/groonga-dev)
+
+## Thanks
+
+* Alexander Barkov \<bar@udm.net\>: The author of
+ `MYSQL_SOURCE/strings/ctype-utf8.c`.
+* ...
+
+## Authors
+
+* Kouhei Sutou \<kou@clear-code.com\>
+
+## License
+
+LGPLv2 only. See doc/text/lgpl-2.0.txt for details.
+
+This program uses normalization table defined in MySQL source code. So
+this program is derived work of
+`MYSQL_SOURCE/strings/ctype-utf8.c`. This program is the same license
+as `MYSQL_SOURCE/strings/ctype-utf8.c` and it is licensed under LGPLv2
+only.
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/autogen.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/autogen.sh
new file mode 100755
index 00000000..f6f5d5af
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/autogen.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+mkdir -p m4
+autoreconf -i
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/Makefile.am
new file mode 100644
index 00000000..06b75071
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/Makefile.am
@@ -0,0 +1,18 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+SUBDIRS = \
+ cmake_modules
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/Makefile.am
new file mode 100644
index 00000000..960411e1
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/Makefile.am
@@ -0,0 +1,18 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+EXTRA_DIST = \
+ ReadFileList.cmake
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/ReadFileList.cmake b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/ReadFileList.cmake
new file mode 100644
index 00000000..204f59f6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/build/cmake_modules/ReadFileList.cmake
@@ -0,0 +1,27 @@
+# Copyright(C) 2012 Brazil
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License version 2.1 as published by the Free Software Foundation.
+#
+# 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-1335 USA
+
+macro(read_file_list file_name output_variable)
+ file(READ ${file_name} ${output_variable})
+ # Remove variable declaration at the first line:
+ # "libgroonga_la_SOURCES = \" -> ""
+ string(REGEX REPLACE "^.*=[ \t]*\\\\" ""
+ ${output_variable} "${${output_variable}}")
+ # Remove white spaces: " com.c \\\n com.h \\\n" -> "com.c\\com.h"
+ string(REGEX REPLACE "[ \t\n]" "" ${output_variable} "${${output_variable}}")
+ # Convert string to list: "com.c\\com.h" -> "com.c;com.h"
+ # NOTE: List in CMake is ";" separated string.
+ string(REGEX REPLACE "\\\\" ";" ${output_variable} "${${output_variable}}")
+endmacro()
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/configure.ac b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/configure.ac
new file mode 100644
index 00000000..f2d1933e
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/configure.ac
@@ -0,0 +1,223 @@
+# Copyright (C) 2013-2016 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+AC_PREREQ(2.59)
+m4_define([groonga_normalizer_mysql_version], m4_include(version))
+AC_INIT([groonga-normalizer-mysql],
+ groonga_normalizer_mysql_version,
+ [groonga-talk@lists.sourceforge.net])
+
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_SRCDIR([normalizers/mysql.c])
+AM_CONFIG_HEADER([config.h])
+
+AM_INIT_AUTOMAKE([1.9 foreign tar-pax])
+
+AC_PROG_LIBTOOL
+
+AC_MSG_CHECKING([for clang])
+if test "$CC" = "clang"; then
+ CLANG=yes
+else
+ CLANG=no
+fi
+AC_MSG_RESULT([$CLANG])
+
+if test "$GCC" = "yes"; then
+ CFLAGS="$CFLAGS -Wall -Wextra"
+ CFLAGS="$CFLAGS -Wmissing-declarations -Wmissing-prototypes"
+fi
+
+# For debug
+AC_ARG_ENABLE(debug,
+ [AS_HELP_STRING([--enable-debug],
+ [use debug flags (default=no)])],
+ [groonga_normalizer_mysql_debug="$enableval"],
+ [groonga_normalizer_mysql_debug="no"])
+if test "x$groonga_normalizer_mysql_debug" != "xno"; then
+ if test "$CLANG" = "yes"; then
+ CFLAGS="$CFLAGS -O0 -g"
+ CXXFLAGS="$CXXFLAGS -O0 -g"
+ elif test "$GCC" = "yes"; then
+ CFLAGS="$CFLAGS -O0 -g3"
+ CXXFLAGS="$CXXFLAGS -O0 -g3"
+ fi
+fi
+
+m4_define([groonga_required_version], m4_include(required_groonga_version))
+GROONGA_REQUIRED_VERSION=groonga_required_version
+PKG_CHECK_MODULES([GROONGA], [groonga >= ${GROONGA_REQUIRED_VERSION}])
+
+_PKG_CONFIG(GROONGA_PLUGINS_DIR, [variable=pluginsdir], [groonga])
+_PKG_CONFIG(GROONGA, [variable=groonga], [groonga])
+
+GROONGA_PLUGINS_DIR="${pkg_cv_GROONGA_PLUGINS_DIR}"
+GROONGA="${pkg_cv_GROONGA}"
+
+AC_SUBST(GROONGA_PLUGINS_DIR)
+AC_SUBST(GROONGA)
+
+normalizers_pluginsdir="\${GROONGA_PLUGINS_DIR}/normalizers"
+AC_SUBST(normalizers_pluginsdir)
+
+AC_ARG_ENABLE([embed],
+ AS_HELP_STRING([--enable-embed],
+ [Build as a static library to embed into an application (default: no)]),
+ [GROONGA_NORMALIZER_MYSQL_EMBED="$enableval"],
+ [GROONGA_NORMALIZER_MYSQL_EMBED="no"])
+
+if test "x$GROONGA_NORMALIZER_MYSQL_EMBED" = "xyes"; then
+ AC_DEFINE_UNQUOTED(GROONGA_NORMALIZER_MYSQL_EMBED,
+ [1],
+ [Define to 1 if groonga-normalizer-mysql is built for embedding.])
+fi
+
+# check Ruby for test
+ac_cv_ruby_available="no"
+AC_ARG_WITH([ruby],
+ AS_HELP_STRING([--with-ruby=PATH],
+ [Ruby interpreter path (default: auto)]),
+ [RUBY="$withval"],
+ [RUBY="auto"])
+
+if test "x$RUBY" = "xno"; then
+ RUBY=
+else
+ if test "x$RUBY" = "xauto"; then
+ AC_PATH_PROGS(RUBY,
+ [ dnl
+ ruby2.3 ruby23 dnl
+ ruby2.2 ruby22 dnl
+ ruby2.1 ruby21 dnl
+ ruby dnl
+ ],
+ ruby-not-found)
+ if test "$RUBY" != "ruby-not-found"; then
+ ruby_version="`$RUBY --version`"
+ if echo "$ruby_version" | grep -q -- 'ruby \(1\.9\|2\.\)'; then
+ ac_cv_ruby_available="yes"
+ else
+ AC_MSG_WARN([$RUBY isn't Ruby 1.9 or later ($ruby_version)])
+ fi
+ fi
+ else
+ ruby_not_found_warning_message="$RUBY is not found. Disable test."
+ case "$RUBY" in
+ /*)
+ AC_CHECK_FILE([$RUBY],
+ [ac_cv_ruby_available="yes"],
+ [AC_MSG_WARN([$ruby_not_found_warning_message])
+ RUBY="$RUBY-not-found"])
+ ;;
+ *)
+ ruby_not_found="$RUBY-not-found"
+ AC_PATH_PROGS(RUBY, "$RUBY", "$ruby_not_found")
+ if test "$RUBY" = "$ruby_not_found"; then
+ AC_MSG_WARN([$ruby_not_found_warning_message])
+ else
+ ac_cv_ruby_available="yes"
+ fi
+ ;;
+ esac
+ fi
+fi
+AC_SUBST(RUBY)
+AM_CONDITIONAL([WITH_TEST], [test "$ac_cv_ruby_available" = "yes"])
+
+# For package
+AC_ARG_WITH(rsync-path,
+ [AS_HELP_STRING([--with-rsync-path=PATH],
+ [specify rsync path to upload Groonga packages.])],
+ [RSYNC_PATH="$withval"],
+ [RSYNC_PATH="packages@packages.groonga.org:public"])
+AC_SUBST(RSYNC_PATH)
+
+AC_ARG_WITH(launchpad-uploader-pgp-key,
+ [AS_HELP_STRING([--with-launchpad-uploader-pgp-key=KEY],
+ [specify PGP key UID to upload Groonga packages to Launchpad.])],
+ [LAUNCHPAD_UPLOADER_PGP_KEY="$withval"],
+ [LAUNCHPAD_UPLOADER_PGP_KEY=""])
+AC_SUBST(LAUNCHPAD_UPLOADER_PGP_KEY)
+
+AC_ARG_WITH([groonga-source-path],
+ AS_HELP_STRING([--with-groonga-source-path=PATH],
+ [Specify Groonga source path for
+ groonga-normalizer-mysql's release manager.]),
+ [GROONGA_SOURCE_PATH="$withval"])
+case "$GROONGA_SOURCE_PATH" in
+ ""|/*)
+ : # do nothing
+ ;;
+ *)
+ GROONGA_SOURCE_PATH="\$(top_builddir)/${GROONGA_SOURCE_PATH}"
+ ;;
+esac
+AC_SUBST(GROONGA_SOURCE_PATH)
+
+AC_ARG_WITH([cutter-source-path],
+ AS_HELP_STRING([--with-cutter-source-path=PATH],
+ [Specify Cutter source path for
+ groonga-normalizer-mysql's release manager.]),
+ [CUTTER_SOURCE_PATH="$withval"])
+case "$CUTTER_SOURCE_PATH" in
+ ""|/*)
+ : # do nothing
+ ;;
+ *)
+ CUTTER_SOURCE_PATH="\$(top_builddir)/${CUTTER_SOURCE_PATH}"
+ ;;
+esac
+AC_SUBST(CUTTER_SOURCE_PATH)
+
+GPG_UID=m4_include(gpg_uid)
+AC_SUBST(GPG_UID)
+
+AC_CONFIG_FILES([
+ Makefile
+ groonga-normalizer-mysql.pc
+ build/Makefile
+ build/cmake_modules/Makefile
+ normalizers/Makefile
+ packages/Makefile
+ packages/apt/Makefile
+ packages/apt/env.sh
+ packages/ubuntu/Makefile
+ packages/rpm/Makefile
+ packages/rpm/centos/Makefile
+ packages/rpm/centos/groonga-normalizer-mysql.spec
+ packages/rpm/fedora/Makefile
+ packages/rpm/fedora/groonga-normalizer-mysql.spec
+ packages/yum/Makefile
+ packages/yum/env.sh
+ packages/source/Makefile
+ test/Makefile
+ doc/Makefile
+ doc/text/Makefile
+])
+
+AC_OUTPUT
+
+echo "$PACKAGE_NAME $PACKAGE_VERSION configuration:"
+echo "-----------------------"
+echo " Compiler: ${CC}"
+echo " CFLAGS: ${CFLAGS}"
+echo " CXXFLAGS: ${CXXFLAGS}"
+echo " Libraries: ${LIBS}"
+echo
+echo "Groonga"
+echo " CFLAGS: ${GROONGA_CFLAGS}"
+echo " Libraries: ${GROONGA_LIBS}"
+echo " install directory: ${normalizers_pluginsdir}"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/data/travis/setup.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/data/travis/setup.sh
new file mode 100755
index 00000000..82f6f84a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/data/travis/setup.sh
@@ -0,0 +1,34 @@
+#!/bin/sh
+#
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+set -e
+
+if [ "$GROONGA_NORMALIZER_MYSQL_MASTER" = "yes" ]; then
+ if ! pkg-config --exists groonga; then
+ sudo apt-get install -qq -y -V libgroonga-dev
+ fi
+ git clone --depth 1 https://github.com/groonga/groonga-normalizer-mysql.git
+ cd groonga-normalizer-mysql
+ ./autogen.sh
+ ./configure CFLAGS="-O0 -g3" CXXFLAGS="-O0 -g3" --prefix=/usr
+ make -j$(grep '^processor' /proc/cpuinfo | wc -l) > /dev/null
+ sudo make install > /dev/null
+ cd ..
+else
+ sudo apt-get install -qq -y -V groonga-normalizer-mysql
+fi
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/Makefile.am
new file mode 100644
index 00000000..59b76977
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/Makefile.am
@@ -0,0 +1,18 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+SUBDIRS = \
+ text
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/Makefile.am
new file mode 100644
index 00000000..7caeaddf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/Makefile.am
@@ -0,0 +1,20 @@
+# Copyright (C) 2013-2015 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+docdir = $(datadir)/doc/$(PACKAGE)
+dist_doc_DATA = \
+ lgpl-2.0.txt \
+ news.md
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/lgpl-2.0.txt b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/lgpl-2.0.txt
new file mode 100644
index 00000000..c44d41a2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/lgpl-2.0.txt
@@ -0,0 +1,481 @@
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/news.md b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/news.md
new file mode 100644
index 00000000..17bc587b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/doc/text/news.md
@@ -0,0 +1,41 @@
+# News
+
+## 1.1.1: 2016-04-29
+
+### Improvements
+
+ * Supported Ubuntu 15.10 and Ubuntu 16.04
+ * Dropped Debian 7.0
+
+### Fixes
+
+ * Fixed to install license information when cmake is used.
+
+## 1.1.0: 2015-05-29
+
+### Fixes
+
+ * Fixed a bug that full-width space isn't treated as blank character.
+ [groonga-dev,03215] [Reported by Shota Mitsui]
+
+### Thanks
+
+ * Shota Mitsui
+
+## 1.0.9: 2015-03-29
+
+### Improvements
+
+ * Added `NormalizerMySQLUnicode520CI`
+ * Added `NormalizerMySQLUnicode520CIExceptKanaCIKanaWithVoicedSoundMark`
+
+## 1.0.8: 2015-02-10
+
+### Fixes
+
+ * Fix registering error when you build with configure.
+ [GitHub#3][Reported by Kazuhiko]
+
+### Thanks
+
+ * Kazuhiko
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/gpg_uid b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/gpg_uid
new file mode 100644
index 00000000..7c1a800b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/gpg_uid
@@ -0,0 +1 @@
+45499429
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/groonga-normalizer-mysql.pc.in b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/groonga-normalizer-mysql.pc.in
new file mode 100644
index 00000000..c1093445
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/groonga-normalizer-mysql.pc.in
@@ -0,0 +1,5 @@
+plugin_name=normalizers/mysql
+
+Name: groonga-normalizer-mysql
+Description: A MySQL compatible normalizer plugin for groonga
+Version: @VERSION@
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/CMakeLists.txt b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/CMakeLists.txt
new file mode 100644
index 00000000..f8b748a7
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/CMakeLists.txt
@@ -0,0 +1,43 @@
+# Copyright(C) 2013-2015 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 Library General Public
+# License as published by the Free Software Foundation; version 2
+# of the License.
+#
+# 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1335 USA
+
+set(NORMALIZERS_DIR "${GROONGA_PLUGINS_DIR}/normalizers")
+read_file_list(${CMAKE_CURRENT_SOURCE_DIR}/mysql_sources.am MYSQL_SOURCES)
+if(GROONGA_NORMALIZER_MYSQL_EMBED)
+ add_library(mysql_normalizer STATIC ${MYSQL_SOURCES})
+ set_property(TARGET mysql_normalizer APPEND PROPERTY
+ COMPILE_DEFINITIONS "GROONGA_NORMALIZER_MYSQL_EMBED")
+ set_target_properties(
+ mysql_normalizer
+ PROPERTIES
+ POSITION_INDEPENDENT_CODE ON)
+ if(NOT DEFINED CMAKE_C_COMPILE_OPTIONS_PIC)
+ # For old CMake
+ if(CMAKE_COMPILER_IS_GNUCXX)
+ set_source_files_properties(${MYSQL_SOURCES}
+ PROPERTIES
+ COMPILE_FLAGS "-fPIC")
+ endif()
+ endif()
+else()
+ add_library(mysql_normalizer MODULE ${MYSQL_SOURCES})
+ set_target_properties(mysql_normalizer PROPERTIES
+ PREFIX ""
+ OUTPUT_NAME "mysql")
+ install(TARGETS mysql_normalizer DESTINATION "${NORMALIZERS_DIR}")
+endif()
+target_link_libraries(mysql_normalizer ${GROONGA_LIBRARIES})
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/Makefile.am
new file mode 100644
index 00000000..769d43ed
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/Makefile.am
@@ -0,0 +1,90 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+EXTRA_DIST = \
+ CMakeLists.txt
+
+AM_CFLAGS = \
+ $(GROONGA_CFLAGS)
+
+AM_LDFLAGS = \
+ -avoid-version \
+ -module \
+ -no-undefined
+
+LIBS = \
+ $(GROONGA_LIBS)
+
+normalizers_plugins_LTLIBRARIES =
+normalizers_plugins_LTLIBRARIES += mysql.la
+
+include mysql_sources.am
+
+ensure-mysql-source-dir:
+ @if test -z "$(MYSQL_SOURCE_DIR)"; then \
+ echo "\$$(MYSQL_SOURCE_DIR) is missing"; \
+ exit 1; \
+ fi
+
+UPDATE_TABLES_TARGETS = \
+ update-general-ci-table \
+ update-unicode-ci-table \
+ update-unicode-ci-except-kana-ci-kana-with-voiced-sound-mark-table \
+ update-unicode-520-ci-table \
+ update-unicode-520-ci-except-kana-ci-kana-with-voiced-sound-mark-table
+
+update-tables: $(UPDATE_TABLES_TARGETS)
+
+update-general-ci-table: ensure-mysql-source-dir
+ $(RUBY) \
+ $(top_srcdir)/tool/generate_utf8_table.rb \
+ $(MYSQL_SOURCE_DIR)/strings/ctype-utf8.c > \
+ $(srcdir)/mysql_general_ci_table.h
+
+update-unicode-ci-table: ensure-mysql-source-dir
+ $(RUBY) \
+ $(top_srcdir)/tool/generate_uca_table.rb \
+ $(MYSQL_SOURCE_DIR)/strings/ctype-uca.c > \
+ $(srcdir)/mysql_unicode_ci_table.h
+
+update-unicode-ci-except-kana-ci-kana-with-voiced-sound-mark-table: ensure-mysql-source-dir
+ $(RUBY) \
+ $(top_srcdir)/tool/generate_uca_table.rb \
+ --split-small-kana \
+ --split-kana-with-voiced-sound-mark \
+ --split-kana-with-semi-voiced-sound-mark \
+ --suffix _except_kana_ci_kana_with_voiced_sound_mark \
+ $(MYSQL_SOURCE_DIR)/strings/ctype-uca.c > \
+ $(srcdir)/mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
+
+update-unicode-520-ci-table: ensure-mysql-source-dir
+ $(RUBY) \
+ $(top_srcdir)/tool/generate_uca_table.rb \
+ --version=520 \
+ $(MYSQL_SOURCE_DIR)/strings/ctype-uca.c > \
+ $(srcdir)/mysql_unicode_520_ci_table.h
+
+update-unicode-520-ci-except-kana-ci-kana-with-voiced-sound-mark-table: ensure-mysql-source-dir
+ $(RUBY) \
+ $(top_srcdir)/tool/generate_uca_table.rb \
+ --version=520 \
+ --split-small-kana \
+ --split-kana-with-voiced-sound-mark \
+ --split-kana-with-semi-voiced-sound-mark \
+ --suffix _except_kana_ci_kana_with_voiced_sound_mark \
+ $(MYSQL_SOURCE_DIR)/strings/ctype-uca.c > \
+ $(srcdir)/mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
+
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql.c b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql.c
new file mode 100644
index 00000000..6096fc22
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql.c
@@ -0,0 +1,778 @@
+/* -*- c-basic-offset: 2 -*- */
+/*
+ Copyright(C) 2013-2015 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef GROONGA_NORMALIZER_MYSQL_EMBED
+# define GRN_PLUGIN_FUNCTION_TAG normalizers_mysql
+#endif
+
+#include <groonga/normalizer.h>
+#include <groonga/nfkc.h>
+
+#include <string.h>
+#include <stdio.h>
+
+#include "mysql_general_ci_table.h"
+#include "mysql_unicode_ci_table.h"
+#include "mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h"
+#include "mysql_unicode_520_ci_table.h"
+#include "mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h"
+
+#ifdef __GNUC__
+# define GNUC_UNUSED __attribute__((__unused__))
+#else
+# define GNUC_UNUSED
+#endif
+
+#ifdef _MSC_VER
+# define inline _inline
+# define snprintf _snprintf
+#endif
+
+#define SNIPPET_BUFFER_SIZE 256
+
+typedef grn_bool (*normalizer_func)(grn_ctx *ctx,
+ const char *utf8,
+ int *character_length,
+ int rest_length,
+ uint32_t **normalize_table,
+ char *normalized,
+ unsigned int *normalized_characer_length,
+ unsigned int *normalized_length_in_bytes,
+ unsigned int *normalized_n_characters);
+
+static inline unsigned int
+unichar_to_utf8(uint32_t unichar, char *output)
+{
+ unsigned int n_bytes;
+
+ if (unichar < 0x80) {
+ output[0] = unichar;
+ n_bytes = 1;
+ } else if (unichar < 0x0800) {
+ output[0] = ((unichar >> 6) & 0x1f) | 0xc0;
+ output[1] = (unichar & 0x3f) | 0x80;
+ n_bytes = 2;
+ } else if (unichar < 0x10000) {
+ output[0] = (unichar >> 12) | 0xe0;
+ output[1] = ((unichar >> 6) & 0x3f) | 0x80;
+ output[2] = (unichar & 0x3f) | 0x80;
+ n_bytes = 3;
+ } else if (unichar < 0x200000) {
+ output[0] = (unichar >> 18) | 0xf0;
+ output[1] = ((unichar >> 12) & 0x3f) | 0x80;
+ output[2] = ((unichar >> 6) & 0x3f) | 0x80;
+ output[3] = (unichar & 0x3f) | 0x80;
+ n_bytes = 4;
+ } else if (unichar < 0x4000000) {
+ output[0] = (unichar >> 24) | 0xf8;
+ output[1] = ((unichar >> 18) & 0x3f) | 0x80;
+ output[2] = ((unichar >> 12) & 0x3f) | 0x80;
+ output[3] = ((unichar >> 6) & 0x3f) | 0x80;
+ output[4] = (unichar & 0x3f) | 0x80;
+ n_bytes = 5;
+ } else {
+ output[0] = (unichar >> 30) | 0xfc;
+ output[1] = ((unichar >> 24) & 0x3f) | 0x80;
+ output[2] = ((unichar >> 18) & 0x3f) | 0x80;
+ output[3] = ((unichar >> 12) & 0x3f) | 0x80;
+ output[4] = ((unichar >> 6) & 0x3f) | 0x80;
+ output[5] = (unichar & 0x3f) | 0x80;
+ n_bytes = 6;
+ }
+
+ return n_bytes;
+}
+
+static inline uint32_t
+utf8_to_unichar(const char *utf8, int byte_size)
+{
+ uint32_t unichar;
+ const unsigned char *bytes = (const unsigned char *)utf8;
+
+ switch (byte_size) {
+ case 1 :
+ unichar = bytes[0] & 0x7f;
+ break;
+ case 2 :
+ unichar = ((bytes[0] & 0x1f) << 6) + (bytes[1] & 0x3f);
+ break;
+ case 3 :
+ unichar =
+ ((bytes[0] & 0x0f) << 12) +
+ ((bytes[1] & 0x3f) << 6) +
+ ((bytes[2] & 0x3f));
+ break;
+ case 4 :
+ unichar =
+ ((bytes[0] & 0x07) << 18) +
+ ((bytes[1] & 0x3f) << 12) +
+ ((bytes[2] & 0x3f) << 6) +
+ ((bytes[3] & 0x3f));
+ break;
+ case 5 :
+ unichar =
+ ((bytes[0] & 0x03) << 24) +
+ ((bytes[1] & 0x3f) << 18) +
+ ((bytes[2] & 0x3f) << 12) +
+ ((bytes[3] & 0x3f) << 6) +
+ ((bytes[4] & 0x3f));
+ break;
+ case 6 :
+ unichar =
+ ((bytes[0] & 0x01) << 30) +
+ ((bytes[1] & 0x3f) << 24) +
+ ((bytes[2] & 0x3f) << 18) +
+ ((bytes[3] & 0x3f) << 12) +
+ ((bytes[4] & 0x3f) << 6) +
+ ((bytes[5] & 0x3f));
+ break;
+ default :
+ unichar = 0;
+ break;
+ }
+
+ return unichar;
+}
+
+static inline void
+decompose_character(const char *rest, int character_length,
+ size_t *page, uint32_t *low_code)
+{
+ switch (character_length) {
+ case 1 :
+ *page = 0x00;
+ *low_code = rest[0] & 0x7f;
+ break;
+ case 2 :
+ *page = (rest[0] & 0x1c) >> 2;
+ *low_code = ((rest[0] & 0x03) << 6) + (rest[1] & 0x3f);
+ break;
+ case 3 :
+ *page = ((rest[0] & 0x0f) << 4) + ((rest[1] & 0x3c) >> 2);
+ *low_code = ((rest[1] & 0x03) << 6) + (rest[2] & 0x3f);
+ break;
+ case 4 :
+ *page =
+ ((rest[0] & 0x07) << 10) +
+ ((rest[1] & 0x3f) << 4) +
+ ((rest[2] & 0x3c) >> 2);
+ *low_code = ((rest[2] & 0x03) << 6) + (rest[3] & 0x3f);
+ break;
+ case 5 :
+ *page =
+ ((rest[0] & 0x03) << 16) +
+ ((rest[1] & 0x3f) << 10) +
+ ((rest[2] & 0x3f) << 4) +
+ ((rest[3] & 0x3c) >> 2);
+ *low_code = ((rest[3] & 0x03) << 6) + (rest[4] & 0x3f);
+ break;
+ case 6 :
+ *page =
+ ((rest[0] & 0x01) << 22) +
+ ((rest[1] & 0x3f) << 16) +
+ ((rest[2] & 0x3f) << 10) +
+ ((rest[3] & 0x3f) << 4) +
+ ((rest[4] & 0x3c) >> 2);
+ *low_code = ((rest[4] & 0x03) << 6) + (rest[5] & 0x3f);
+ break;
+ default :
+ *page = (size_t)-1;
+ *low_code = 0x00;
+ break;
+ }
+}
+
+static inline void
+normalize_character(const char *utf8, int character_length,
+ uint32_t **normalize_table,
+ size_t normalize_table_size,
+ char *normalized,
+ unsigned int *normalized_character_length,
+ unsigned int *normalized_length_in_bytes,
+ unsigned int *normalized_n_characters)
+{
+ size_t page;
+ uint32_t low_code;
+ decompose_character(utf8, character_length, &page, &low_code);
+ if (page < normalize_table_size && normalize_table[page]) {
+ uint32_t normalized_code;
+ unsigned int n_bytes;
+ normalized_code = normalize_table[page][low_code];
+ if (normalized_code == 0x00000) {
+ *normalized_character_length = 0;
+ } else {
+ n_bytes = unichar_to_utf8(normalized_code,
+ normalized + *normalized_length_in_bytes);
+ *normalized_character_length = n_bytes;
+ *normalized_length_in_bytes += n_bytes;
+ (*normalized_n_characters)++;
+ }
+ } else {
+ int i;
+ for (i = 0; i < character_length; i++) {
+ normalized[*normalized_length_in_bytes + i] = utf8[i];
+ }
+ *normalized_character_length = character_length;
+ *normalized_length_in_bytes += character_length;
+ (*normalized_n_characters)++;
+ }
+}
+
+static void
+sized_buffer_append(char *buffer,
+ unsigned int buffer_length,
+ unsigned int *buffer_rest_length,
+ const char *string)
+{
+ size_t string_length;
+
+ string_length = strlen(string);
+ if (string_length >= *buffer_rest_length) {
+ return;
+ }
+
+ strncat(buffer, string, buffer_length);
+ *buffer_rest_length -= string_length;
+}
+
+static void
+sized_buffer_dump_string(char *buffer,
+ unsigned int buffer_length,
+ unsigned int *buffer_rest_length,
+ const char *string, unsigned int string_length)
+{
+ const unsigned char *bytes;
+ unsigned int i;
+
+ bytes = (const unsigned char *)string;
+ for (i = 0; i < string_length; i++) {
+ unsigned char byte = bytes[i];
+#define FORMATTED_BYTE_BUFFER_SIZE 5 /* "0xFF\0" */
+ char formatted_byte[FORMATTED_BYTE_BUFFER_SIZE];
+ if (i > 0) {
+ sized_buffer_append(buffer, buffer_length, buffer_rest_length,
+ " ");
+ }
+ if (byte == 0) {
+ strncpy(formatted_byte, "0x00", FORMATTED_BYTE_BUFFER_SIZE);
+ } else {
+ snprintf(formatted_byte, FORMATTED_BYTE_BUFFER_SIZE, "%#04x", byte);
+ }
+ sized_buffer_append(buffer, buffer_length, buffer_rest_length,
+ formatted_byte);
+#undef FORMATTED_BYTE_BUFFER_SIZE
+ }
+}
+
+static const char *
+snippet(const char *string, unsigned int length, unsigned int target_byte,
+ char *buffer, unsigned int buffer_length)
+{
+ const char *elision_mark = "...";
+ unsigned int max_window_length = 12;
+ unsigned int window_length;
+ unsigned int buffer_rest_length = buffer_length - 1;
+
+ buffer[0] = '\0';
+
+ if (target_byte > 0) {
+ sized_buffer_append(buffer, buffer_length, &buffer_rest_length,
+ elision_mark);
+ }
+
+ sized_buffer_append(buffer, buffer_length, &buffer_rest_length, "<");
+ if (target_byte + max_window_length > length) {
+ window_length = length - target_byte;
+ } else {
+ window_length = max_window_length;
+ }
+ sized_buffer_dump_string(buffer, buffer_length, &buffer_rest_length,
+ string + target_byte, window_length);
+ sized_buffer_append(buffer, buffer_length, &buffer_rest_length,
+ ">");
+
+ if (target_byte + window_length < length) {
+ sized_buffer_append(buffer, buffer_length, &buffer_rest_length,
+ elision_mark);
+ }
+
+ return buffer;
+}
+
+static void
+normalize(grn_ctx *ctx, grn_obj *string,
+ const char *normalizer_type_label,
+ uint32_t **normalize_table,
+ size_t normalize_table_size,
+ normalizer_func custom_normalizer)
+{
+ const char *original, *rest;
+ unsigned int original_length_in_bytes, rest_length;
+ char *normalized;
+ unsigned int normalized_length_in_bytes = 0;
+ unsigned int normalized_n_characters = 0;
+ unsigned char *types = NULL;
+ unsigned char *current_type = NULL;
+ short *checks = NULL;
+ short *current_check = NULL;
+ grn_encoding encoding;
+ int flags;
+ grn_bool remove_blank_p;
+
+ encoding = grn_string_get_encoding(ctx, string);
+ flags = grn_string_get_flags(ctx, string);
+ remove_blank_p = flags & GRN_STRING_REMOVE_BLANK;
+ grn_string_get_original(ctx, string, &original, &original_length_in_bytes);
+ {
+ unsigned int max_normalized_length_in_bytes =
+ original_length_in_bytes + 1;
+ normalized = GRN_PLUGIN_MALLOC(ctx, max_normalized_length_in_bytes);
+ }
+ if (flags & GRN_STRING_WITH_TYPES) {
+ unsigned int max_normalized_n_characters = original_length_in_bytes + 1;
+ types = GRN_PLUGIN_MALLOC(ctx, max_normalized_n_characters);
+ current_type = types;
+ }
+ if (flags & GRN_STRING_WITH_CHECKS) {
+ unsigned int max_checks_size = sizeof(short) * original_length_in_bytes + 1;
+ checks = GRN_PLUGIN_MALLOC(ctx, max_checks_size);
+ current_check = checks;
+ current_check[0] = 0;
+ }
+ rest = original;
+ rest_length = original_length_in_bytes;
+ while (rest_length > 0) {
+ int character_length;
+ grn_bool custom_normalized = GRN_FALSE;
+ unsigned int normalized_character_length;
+ unsigned int previous_normalized_length_in_bytes =
+ normalized_length_in_bytes;
+ unsigned int previous_normalized_n_characters =
+ normalized_n_characters;
+
+ character_length = grn_plugin_charlen(ctx, rest, rest_length, encoding);
+ if (character_length == 0) {
+ break;
+ }
+
+ if (custom_normalizer) {
+ custom_normalized = custom_normalizer(ctx,
+ rest,
+ &character_length,
+ rest_length - character_length,
+ normalize_table,
+ normalized,
+ &normalized_character_length,
+ &normalized_length_in_bytes,
+ &normalized_n_characters);
+ }
+ if (!custom_normalized) {
+ normalize_character(rest, character_length,
+ normalize_table, normalize_table_size,
+ normalized,
+ &normalized_character_length,
+ &normalized_length_in_bytes,
+ &normalized_n_characters);
+ }
+
+ if (remove_blank_p &&
+ normalized_character_length == 1 &&
+ normalized[previous_normalized_length_in_bytes] == ' ') {
+ if (current_type > types) {
+ current_type[-1] |= GRN_CHAR_BLANK;
+ }
+ if (current_check) {
+ current_check[0]++;
+ }
+ normalized_length_in_bytes = previous_normalized_length_in_bytes;
+ normalized_n_characters = previous_normalized_n_characters;
+ } else {
+ if (current_type && normalized_character_length > 0) {
+ char *current_normalized;
+ current_normalized =
+ normalized + normalized_length_in_bytes - normalized_character_length;
+ current_type[0] =
+ grn_nfkc_char_type((unsigned char *)current_normalized);
+ current_type++;
+ }
+ if (current_check) {
+ current_check[0] += character_length;
+ if (normalized_character_length > 0) {
+ unsigned int i;
+ current_check++;
+ for (i = 1; i < normalized_character_length; i++) {
+ current_check[0] = 0;
+ current_check++;
+ }
+ current_check[0] = 0;
+ }
+ }
+ }
+
+ rest += character_length;
+ rest_length -= character_length;
+ }
+ if (current_type) {
+ current_type[0] = GRN_CHAR_NULL;
+ }
+ normalized[normalized_length_in_bytes] = '\0';
+
+ if (rest_length > 0) {
+ char buffer[SNIPPET_BUFFER_SIZE+1];
+ GRN_PLUGIN_LOG(ctx, GRN_LOG_DEBUG,
+ "[normalizer][%s] failed to normalize at %u byte: %s",
+ normalizer_type_label,
+ original_length_in_bytes - rest_length,
+ snippet(original,
+ original_length_in_bytes,
+ original_length_in_bytes - rest_length,
+ buffer,
+ SNIPPET_BUFFER_SIZE));
+ }
+ grn_string_set_normalized(ctx,
+ string,
+ normalized,
+ normalized_length_in_bytes,
+ normalized_n_characters);
+ grn_string_set_types(ctx, string, types);
+ grn_string_set_checks(ctx, string, checks);
+}
+
+static grn_obj *
+mysql_general_ci_next(GNUC_UNUSED grn_ctx *ctx,
+ GNUC_UNUSED int nargs,
+ grn_obj **args,
+ GNUC_UNUSED grn_user_data *user_data)
+{
+ grn_obj *string = args[0];
+ grn_encoding encoding;
+ const char *normalizer_type_label = "mysql-general-ci";
+
+ encoding = grn_string_get_encoding(ctx, string);
+ if (encoding != GRN_ENC_UTF8) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[normalizer][%s] "
+ "UTF-8 encoding is only supported: %s",
+ normalizer_type_label,
+ grn_encoding_to_string(encoding));
+ return NULL;
+ }
+ normalize(ctx, string, normalizer_type_label,
+ general_ci_table, sizeof(general_ci_table) / sizeof(uint32_t *),
+ NULL);
+ return NULL;
+}
+
+static grn_obj *
+mysql_unicode_ci_next(GNUC_UNUSED grn_ctx *ctx,
+ GNUC_UNUSED int nargs,
+ grn_obj **args,
+ GNUC_UNUSED grn_user_data *user_data)
+{
+ grn_obj *string = args[0];
+ grn_encoding encoding;
+ const char *normalizer_type_label = "mysql-unicode-ci";
+
+ encoding = grn_string_get_encoding(ctx, string);
+ if (encoding != GRN_ENC_UTF8) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[normalizer][%s] "
+ "UTF-8 encoding is only supported: %s",
+ normalizer_type_label,
+ grn_encoding_to_string(encoding));
+ return NULL;
+ }
+ normalize(ctx, string, normalizer_type_label,
+ unicode_ci_table, sizeof(unicode_ci_table) / sizeof(uint32_t *),
+ NULL);
+ return NULL;
+}
+
+#define HALFWIDTH_KATAKANA_LETTER_KA 0xff76
+#define HALFWIDTH_KATAKANA_LETTER_KI 0xff77
+#define HALFWIDTH_KATAKANA_LETTER_KU 0xff78
+#define HALFWIDTH_KATAKANA_LETTER_KE 0xff79
+#define HALFWIDTH_KATAKANA_LETTER_KO 0xff7a
+
+#define HALFWIDTH_KATAKANA_LETTER_SA 0xff7b
+#define HALFWIDTH_KATAKANA_LETTER_SI 0xff7c
+#define HALFWIDTH_KATAKANA_LETTER_SU 0xff7d
+#define HALFWIDTH_KATAKANA_LETTER_SE 0xff7e
+#define HALFWIDTH_KATAKANA_LETTER_SO 0xff7f
+
+#define HALFWIDTH_KATAKANA_LETTER_TA 0xff80
+#define HALFWIDTH_KATAKANA_LETTER_TI 0xff81
+#define HALFWIDTH_KATAKANA_LETTER_TU 0xff82
+#define HALFWIDTH_KATAKANA_LETTER_TE 0xff83
+#define HALFWIDTH_KATAKANA_LETTER_TO 0xff84
+
+#define HALFWIDTH_KATAKANA_LETTER_HA 0xff8a
+#define HALFWIDTH_KATAKANA_LETTER_HI 0xff8b
+#define HALFWIDTH_KATAKANA_LETTER_HU 0xff8c
+#define HALFWIDTH_KATAKANA_LETTER_HE 0xff8d
+#define HALFWIDTH_KATAKANA_LETTER_HO 0xff8e
+
+#define HALFWIDTH_KATAKANA_VOICED_SOUND_MARK 0xff9e
+#define HALFWIDTH_KATAKANA_SEMI_VOICED_SOUND_MARK 0xff9f
+
+#define HIRAGANA_LETTER_KA 0x304b
+#define HIRAGANA_VOICED_SOUND_MARK_OFFSET 1
+#define HIRAGANA_VOICED_SOUND_MARK_GAP 2
+
+#define HIRAGANA_LETTER_HA 0x306f
+#define HIRAGANA_HA_LINE_BA_OFFSET 1
+#define HIRAGANA_HA_LINE_PA_OFFSET 2
+#define HIRAGANA_HA_LINE_GAP 3
+
+static grn_bool
+normalize_halfwidth_katakana_with_voiced_sound_mark(
+ grn_ctx *ctx,
+ const char *utf8,
+ int *character_length,
+ int rest_length,
+ GNUC_UNUSED uint32_t **normalize_table,
+ char *normalized,
+ unsigned int *normalized_character_length,
+ unsigned int *normalized_length_in_bytes,
+ unsigned int *normalized_n_characters)
+{
+ grn_bool custom_normalized = GRN_FALSE;
+ grn_bool is_voiced_sound_markable_halfwidth_katakana = GRN_FALSE;
+ grn_bool is_semi_voiced_sound_markable_halfwidth_katakana = GRN_FALSE;
+ grn_bool is_ha_line = GRN_FALSE;
+ uint32_t unichar;
+
+ if (*character_length != 3) {
+ return GRN_FALSE;
+ }
+ if (rest_length < 3) {
+ return GRN_FALSE;
+ }
+
+ unichar = utf8_to_unichar(utf8, *character_length);
+ if (HALFWIDTH_KATAKANA_LETTER_KA <= unichar &&
+ unichar <= HALFWIDTH_KATAKANA_LETTER_TO) {
+ is_voiced_sound_markable_halfwidth_katakana = GRN_TRUE;
+ } else if (HALFWIDTH_KATAKANA_LETTER_HA <= unichar &&
+ unichar <= HALFWIDTH_KATAKANA_LETTER_HO) {
+ is_voiced_sound_markable_halfwidth_katakana = GRN_TRUE;
+ is_semi_voiced_sound_markable_halfwidth_katakana = GRN_TRUE;
+ is_ha_line = GRN_TRUE;
+ }
+
+ if (!is_voiced_sound_markable_halfwidth_katakana &&
+ !is_semi_voiced_sound_markable_halfwidth_katakana) {
+ return GRN_FALSE;
+ }
+
+ {
+ int next_character_length;
+ uint32_t next_unichar;
+ next_character_length = grn_plugin_charlen(ctx,
+ utf8 + *character_length,
+ rest_length,
+ GRN_ENC_UTF8);
+ if (next_character_length != 3) {
+ return GRN_FALSE;
+ }
+ next_unichar = utf8_to_unichar(utf8 + *character_length,
+ next_character_length);
+ if (next_unichar == HALFWIDTH_KATAKANA_VOICED_SOUND_MARK) {
+ if (is_voiced_sound_markable_halfwidth_katakana) {
+ unsigned int n_bytes;
+ if (is_ha_line) {
+ n_bytes = unichar_to_utf8(HIRAGANA_LETTER_HA +
+ HIRAGANA_HA_LINE_BA_OFFSET +
+ ((unichar - HALFWIDTH_KATAKANA_LETTER_HA) *
+ HIRAGANA_HA_LINE_GAP),
+ normalized + *normalized_length_in_bytes);
+ } else {
+ int small_tu_offset = 0;
+ if (HALFWIDTH_KATAKANA_LETTER_TU <= unichar &&
+ unichar <= HALFWIDTH_KATAKANA_LETTER_TO) {
+ small_tu_offset = 1;
+ }
+ n_bytes = unichar_to_utf8(HIRAGANA_LETTER_KA +
+ HIRAGANA_VOICED_SOUND_MARK_OFFSET +
+ small_tu_offset +
+ ((unichar - HALFWIDTH_KATAKANA_LETTER_KA) *
+ HIRAGANA_VOICED_SOUND_MARK_GAP),
+ normalized + *normalized_length_in_bytes);
+ }
+ *character_length += next_character_length;
+ *normalized_character_length = n_bytes;
+ *normalized_length_in_bytes += n_bytes;
+ (*normalized_n_characters)++;
+ custom_normalized = GRN_TRUE;
+ }
+ } else if (next_unichar == HALFWIDTH_KATAKANA_SEMI_VOICED_SOUND_MARK) {
+ if (is_semi_voiced_sound_markable_halfwidth_katakana) {
+ unsigned int n_bytes;
+ n_bytes = unichar_to_utf8(HIRAGANA_LETTER_HA +
+ HIRAGANA_HA_LINE_PA_OFFSET +
+ ((unichar - HALFWIDTH_KATAKANA_LETTER_HA) *
+ HIRAGANA_HA_LINE_GAP),
+ normalized + *normalized_length_in_bytes);
+ *character_length += next_character_length;
+ *normalized_character_length = n_bytes;
+ *normalized_length_in_bytes += n_bytes;
+ (*normalized_n_characters)++;
+ custom_normalized = GRN_TRUE;
+ }
+ }
+ }
+
+ return custom_normalized;
+}
+
+static grn_obj *
+mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_next(
+ GNUC_UNUSED grn_ctx *ctx,
+ GNUC_UNUSED int nargs,
+ grn_obj **args,
+ GNUC_UNUSED grn_user_data *user_data)
+{
+ grn_obj *string = args[0];
+ grn_encoding encoding;
+ const char *normalizer_type_label =
+ "mysql-unicode-ci-except-kana-ci-kana-with-voiced-sound-mark";
+
+ encoding = grn_string_get_encoding(ctx, string);
+ if (encoding != GRN_ENC_UTF8) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[normalizer][%s] "
+ "UTF-8 encoding is only supported: %s",
+ normalizer_type_label,
+ grn_encoding_to_string(encoding));
+ return NULL;
+ }
+ normalize(ctx, string,
+ normalizer_type_label,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table,
+ sizeof(unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table) / sizeof(uint32_t *),
+ normalize_halfwidth_katakana_with_voiced_sound_mark);
+ return NULL;
+}
+
+static grn_obj *
+mysql_unicode_520_ci_next(GNUC_UNUSED grn_ctx *ctx,
+ GNUC_UNUSED int nargs,
+ grn_obj **args,
+ GNUC_UNUSED grn_user_data *user_data)
+{
+ grn_obj *string = args[0];
+ grn_encoding encoding;
+ const char *normalizer_type_label = "mysql-unicode-520-ci";
+
+ encoding = grn_string_get_encoding(ctx, string);
+ if (encoding != GRN_ENC_UTF8) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[normalizer][%s] "
+ "UTF-8 encoding is only supported: %s",
+ normalizer_type_label,
+ grn_encoding_to_string(encoding));
+ return NULL;
+ }
+ normalize(ctx, string, normalizer_type_label,
+ unicode_520_ci_table,
+ sizeof(unicode_520_ci_table) / sizeof(uint32_t *),
+ NULL);
+ return NULL;
+}
+
+static grn_obj *
+mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_next(
+ GNUC_UNUSED grn_ctx *ctx,
+ GNUC_UNUSED int nargs,
+ grn_obj **args,
+ GNUC_UNUSED grn_user_data *user_data)
+{
+ grn_obj *string = args[0];
+ grn_encoding encoding;
+ const char *normalizer_type_label =
+ "mysql-unicode-520-ci-except-kana-ci-kana-with-voiced-sound-mark";
+
+ encoding = grn_string_get_encoding(ctx, string);
+ if (encoding != GRN_ENC_UTF8) {
+ GRN_PLUGIN_ERROR(ctx,
+ GRN_FUNCTION_NOT_IMPLEMENTED,
+ "[normalizer][%s] "
+ "UTF-8 encoding is only supported: %s",
+ normalizer_type_label,
+ grn_encoding_to_string(encoding));
+ return NULL;
+ }
+ normalize(ctx, string,
+ normalizer_type_label,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table,
+ sizeof(unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table) / sizeof(uint32_t *),
+ normalize_halfwidth_katakana_with_voiced_sound_mark);
+ return NULL;
+}
+
+grn_rc
+GRN_PLUGIN_INIT(grn_ctx *ctx)
+{
+ return ctx->rc;
+}
+
+grn_rc
+GRN_PLUGIN_REGISTER(grn_ctx *ctx)
+{
+ grn_normalizer_register(ctx, "NormalizerMySQLGeneralCI", -1,
+ NULL, mysql_general_ci_next, NULL);
+ grn_normalizer_register(ctx, "NormalizerMySQLUnicodeCI", -1,
+ NULL, mysql_unicode_ci_next, NULL);
+ grn_normalizer_register(ctx,
+ "NormalizerMySQLUnicodeCI"
+ "Except"
+ "KanaCI"
+ "KanaWithVoicedSoundMark",
+ -1,
+ NULL,
+ mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_next,
+ NULL);
+ grn_normalizer_register(ctx, "NormalizerMySQLUnicode520CI", -1,
+ NULL, mysql_unicode_520_ci_next, NULL);
+ grn_normalizer_register(ctx,
+ "NormalizerMySQLUnicode520CI"
+ "Except"
+ "KanaCI"
+ "KanaWithVoicedSoundMark",
+ -1,
+ NULL,
+ mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_next,
+ NULL);
+ return GRN_SUCCESS;
+}
+
+grn_rc
+GRN_PLUGIN_FIN(GNUC_UNUSED grn_ctx *ctx)
+{
+ return GRN_SUCCESS;
+}
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_general_ci_table.h b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_general_ci_table.h
new file mode 100644
index 00000000..16b43dbf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_general_ci_table.h
@@ -0,0 +1,565 @@
+/*
+ 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ mysql-5.6.23/strings/ctype-utf8.c.
+ The following is the header of the file:
+
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UTF8 according RFC 2279
+ Written by Alexander Barkov <bar@udm.net>
+*/
+
+#ifndef MYSQL_UTF8_H
+#define MYSQL_UTF8_H
+
+#include <stdint.h>
+
+static uint32_t general_ci_page_00[] = {
+ 0x00000, 0x00001, 0x00002, 0x00003, 0x00004, 0x00005, 0x00006, 0x00007,
+ 0x00008, 0x00009, 0x0000a, 0x0000b, 0x0000c, 0x0000d, 0x0000e, 0x0000f,
+ 0x00010, 0x00011, 0x00012, 0x00013, 0x00014, 0x00015, 0x00016, 0x00017,
+ 0x00018, 0x00019, 0x0001a, 0x0001b, 0x0001c, 0x0001d, 0x0001e, 0x0001f,
+ 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x0007f,
+ 0x00080, 0x00081, 0x00082, 0x00083, 0x00084, 0x00085, 0x00086, 0x00087,
+ 0x00088, 0x00089, 0x0008a, 0x0008b, 0x0008c, 0x0008d, 0x0008e, 0x0008f,
+ 0x00090, 0x00091, 0x00092, 0x00093, 0x00094, 0x00095, 0x00096, 0x00097,
+ 0x00098, 0x00099, 0x0009a, 0x0009b, 0x0009c, 0x0009d, 0x0009e, 0x0009f,
+ 0x000a0, 0x000a1, 0x000a2, 0x000a3, 0x000a4, 0x000a5, 0x000a6, 0x000a7,
+ 0x000a8, 0x000a9, 0x000aa, 0x000ab, 0x000ac, 0x000ad, 0x000ae, 0x000af,
+ 0x000b0, 0x000b1, 0x000b2, 0x000b3, 0x000b4, 0x0039c, 0x000b6, 0x000b7,
+ 0x000b8, 0x000b9, 0x000ba, 0x000bb, 0x000bc, 0x000bd, 0x000be, 0x000bf,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x000d0, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000d7,
+ 0x000d8, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x00053,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x000d0, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000f7,
+ 0x000d8, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x00059
+};
+
+static uint32_t general_ci_page_01[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00043, 0x00043,
+ 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00044, 0x00044,
+ 0x00110, 0x00110, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00047, 0x00047, 0x00047, 0x00047,
+ 0x00047, 0x00047, 0x00047, 0x00047, 0x00048, 0x00048, 0x00126, 0x00126,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00049, 0x00049, 0x00132, 0x00132, 0x0004a, 0x0004a, 0x0004b, 0x0004b,
+ 0x00138, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0013f,
+ 0x0013f, 0x00141, 0x00141, 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x00149, 0x0014a, 0x0014a, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00152, 0x00152, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00052, 0x00052, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00166, 0x00166,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00057, 0x00057, 0x00059, 0x00059,
+ 0x00059, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00053,
+ 0x00180, 0x00181, 0x00182, 0x00182, 0x00184, 0x00184, 0x00186, 0x00187,
+ 0x00187, 0x00189, 0x0018a, 0x0018b, 0x0018b, 0x0018d, 0x0018e, 0x0018f,
+ 0x00190, 0x00191, 0x00191, 0x00193, 0x00194, 0x001f6, 0x00196, 0x00197,
+ 0x00198, 0x00198, 0x0019a, 0x0019b, 0x0019c, 0x0019d, 0x0019e, 0x0019f,
+ 0x0004f, 0x0004f, 0x001a2, 0x001a2, 0x001a4, 0x001a4, 0x001a6, 0x001a7,
+ 0x001a7, 0x001a9, 0x001aa, 0x001ab, 0x001ac, 0x001ac, 0x001ae, 0x00055,
+ 0x00055, 0x001b1, 0x001b2, 0x001b3, 0x001b3, 0x001b5, 0x001b5, 0x001b7,
+ 0x001b8, 0x001b8, 0x001ba, 0x001bb, 0x001bc, 0x001bc, 0x001be, 0x001f7,
+ 0x001c0, 0x001c1, 0x001c2, 0x001c3, 0x001c4, 0x001c4, 0x001c4, 0x001c7,
+ 0x001c7, 0x001c7, 0x001ca, 0x001ca, 0x001ca, 0x00041, 0x00041, 0x00049,
+ 0x00049, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x0018e, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x000c6, 0x000c6, 0x001e4, 0x001e4, 0x00047, 0x00047,
+ 0x0004b, 0x0004b, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x001b7, 0x001b7,
+ 0x0004a, 0x001f1, 0x001f1, 0x001f1, 0x00047, 0x00047, 0x001f6, 0x001f7,
+ 0x0004e, 0x0004e, 0x00041, 0x00041, 0x000c6, 0x000c6, 0x000d8, 0x000d8
+};
+
+static uint32_t general_ci_page_02[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x0021c, 0x0021c, 0x00048, 0x00048,
+ 0x00220, 0x00221, 0x00222, 0x00222, 0x00224, 0x00224, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00059, 0x00059, 0x00234, 0x00235, 0x00236, 0x00237,
+ 0x00238, 0x00239, 0x0023a, 0x0023b, 0x0023c, 0x0023d, 0x0023e, 0x0023f,
+ 0x00240, 0x00241, 0x00242, 0x00243, 0x00244, 0x00245, 0x00246, 0x00247,
+ 0x00248, 0x00249, 0x0024a, 0x0024b, 0x0024c, 0x0024d, 0x0024e, 0x0024f,
+ 0x00250, 0x00251, 0x00252, 0x00181, 0x00186, 0x00255, 0x00189, 0x0018a,
+ 0x00258, 0x0018f, 0x0025a, 0x00190, 0x0025c, 0x0025d, 0x0025e, 0x0025f,
+ 0x00193, 0x00261, 0x00262, 0x00194, 0x00264, 0x00265, 0x00266, 0x00267,
+ 0x00197, 0x00196, 0x0026a, 0x0026b, 0x0026c, 0x0026d, 0x0026e, 0x0019c,
+ 0x00270, 0x00271, 0x0019d, 0x00273, 0x00274, 0x0019f, 0x00276, 0x00277,
+ 0x00278, 0x00279, 0x0027a, 0x0027b, 0x0027c, 0x0027d, 0x0027e, 0x0027f,
+ 0x001a6, 0x00281, 0x00282, 0x001a9, 0x00284, 0x00285, 0x00286, 0x00287,
+ 0x001ae, 0x00289, 0x001b1, 0x001b2, 0x0028c, 0x0028d, 0x0028e, 0x0028f,
+ 0x00290, 0x00291, 0x001b7, 0x00293, 0x00294, 0x00295, 0x00296, 0x00297,
+ 0x00298, 0x00299, 0x0029a, 0x0029b, 0x0029c, 0x0029d, 0x0029e, 0x0029f,
+ 0x002a0, 0x002a1, 0x002a2, 0x002a3, 0x002a4, 0x002a5, 0x002a6, 0x002a7,
+ 0x002a8, 0x002a9, 0x002aa, 0x002ab, 0x002ac, 0x002ad, 0x002ae, 0x002af,
+ 0x002b0, 0x002b1, 0x002b2, 0x002b3, 0x002b4, 0x002b5, 0x002b6, 0x002b7,
+ 0x002b8, 0x002b9, 0x002ba, 0x002bb, 0x002bc, 0x002bd, 0x002be, 0x002bf,
+ 0x002c0, 0x002c1, 0x002c2, 0x002c3, 0x002c4, 0x002c5, 0x002c6, 0x002c7,
+ 0x002c8, 0x002c9, 0x002ca, 0x002cb, 0x002cc, 0x002cd, 0x002ce, 0x002cf,
+ 0x002d0, 0x002d1, 0x002d2, 0x002d3, 0x002d4, 0x002d5, 0x002d6, 0x002d7,
+ 0x002d8, 0x002d9, 0x002da, 0x002db, 0x002dc, 0x002dd, 0x002de, 0x002df,
+ 0x002e0, 0x002e1, 0x002e2, 0x002e3, 0x002e4, 0x002e5, 0x002e6, 0x002e7,
+ 0x002e8, 0x002e9, 0x002ea, 0x002eb, 0x002ec, 0x002ed, 0x002ee, 0x002ef,
+ 0x002f0, 0x002f1, 0x002f2, 0x002f3, 0x002f4, 0x002f5, 0x002f6, 0x002f7,
+ 0x002f8, 0x002f9, 0x002fa, 0x002fb, 0x002fc, 0x002fd, 0x002fe, 0x002ff
+};
+
+static uint32_t general_ci_page_03[] = {
+ 0x00300, 0x00301, 0x00302, 0x00303, 0x00304, 0x00305, 0x00306, 0x00307,
+ 0x00308, 0x00309, 0x0030a, 0x0030b, 0x0030c, 0x0030d, 0x0030e, 0x0030f,
+ 0x00310, 0x00311, 0x00312, 0x00313, 0x00314, 0x00315, 0x00316, 0x00317,
+ 0x00318, 0x00319, 0x0031a, 0x0031b, 0x0031c, 0x0031d, 0x0031e, 0x0031f,
+ 0x00320, 0x00321, 0x00322, 0x00323, 0x00324, 0x00325, 0x00326, 0x00327,
+ 0x00328, 0x00329, 0x0032a, 0x0032b, 0x0032c, 0x0032d, 0x0032e, 0x0032f,
+ 0x00330, 0x00331, 0x00332, 0x00333, 0x00334, 0x00335, 0x00336, 0x00337,
+ 0x00338, 0x00339, 0x0033a, 0x0033b, 0x0033c, 0x0033d, 0x0033e, 0x0033f,
+ 0x00340, 0x00341, 0x00342, 0x00343, 0x00344, 0x00399, 0x00346, 0x00347,
+ 0x00348, 0x00349, 0x0034a, 0x0034b, 0x0034c, 0x0034d, 0x0034e, 0x0034f,
+ 0x00350, 0x00351, 0x00352, 0x00353, 0x00354, 0x00355, 0x00356, 0x00357,
+ 0x00358, 0x00359, 0x0035a, 0x0035b, 0x0035c, 0x0035d, 0x0035e, 0x0035f,
+ 0x00360, 0x00361, 0x00362, 0x00363, 0x00364, 0x00365, 0x00366, 0x00367,
+ 0x00368, 0x00369, 0x0036a, 0x0036b, 0x0036c, 0x0036d, 0x0036e, 0x0036f,
+ 0x00370, 0x00371, 0x00372, 0x00373, 0x00374, 0x00375, 0x00376, 0x00377,
+ 0x00378, 0x00379, 0x0037a, 0x0037b, 0x0037c, 0x0037d, 0x0037e, 0x0037f,
+ 0x00380, 0x00381, 0x00382, 0x00383, 0x00384, 0x00385, 0x00391, 0x00387,
+ 0x00395, 0x00397, 0x00399, 0x0038b, 0x0039f, 0x0038d, 0x003a5, 0x003a9,
+ 0x00399, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a2, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x00391, 0x00395, 0x00397, 0x00399,
+ 0x003a5, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x0039f, 0x003a5, 0x003a9, 0x003cf,
+ 0x00392, 0x00398, 0x003d2, 0x003d2, 0x003d2, 0x003a6, 0x003a0, 0x003d7,
+ 0x003d8, 0x003d9, 0x003da, 0x003da, 0x003dc, 0x003dc, 0x003de, 0x003de,
+ 0x003e0, 0x003e0, 0x003e2, 0x003e2, 0x003e4, 0x003e4, 0x003e6, 0x003e6,
+ 0x003e8, 0x003e8, 0x003ea, 0x003ea, 0x003ec, 0x003ec, 0x003ee, 0x003ee,
+ 0x0039a, 0x003a1, 0x003a3, 0x003f3, 0x003f4, 0x003f5, 0x003f6, 0x003f7,
+ 0x003f8, 0x003f9, 0x003fa, 0x003fb, 0x003fc, 0x003fd, 0x003fe, 0x003ff
+};
+
+static uint32_t general_ci_page_04[] = {
+ 0x00415, 0x00415, 0x00402, 0x00413, 0x00404, 0x00405, 0x00406, 0x00406,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0041a, 0x00418, 0x00423, 0x0040f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00415, 0x00416, 0x00417,
+ 0x00418, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00415, 0x00416, 0x00417,
+ 0x00418, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00415, 0x00415, 0x00402, 0x00413, 0x00404, 0x00405, 0x00406, 0x00406,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0041a, 0x00418, 0x00423, 0x0040f,
+ 0x00460, 0x00460, 0x00462, 0x00462, 0x00464, 0x00464, 0x00466, 0x00466,
+ 0x00468, 0x00468, 0x0046a, 0x0046a, 0x0046c, 0x0046c, 0x0046e, 0x0046e,
+ 0x00470, 0x00470, 0x00472, 0x00472, 0x00474, 0x00474, 0x00474, 0x00474,
+ 0x00478, 0x00478, 0x0047a, 0x0047a, 0x0047c, 0x0047c, 0x0047e, 0x0047e,
+ 0x00480, 0x00480, 0x00482, 0x00483, 0x00484, 0x00485, 0x00486, 0x00487,
+ 0x00488, 0x00489, 0x0048a, 0x0048b, 0x0048c, 0x0048c, 0x0048e, 0x0048e,
+ 0x00490, 0x00490, 0x00492, 0x00492, 0x00494, 0x00494, 0x00496, 0x00496,
+ 0x00498, 0x00498, 0x0049a, 0x0049a, 0x0049c, 0x0049c, 0x0049e, 0x0049e,
+ 0x004a0, 0x004a0, 0x004a2, 0x004a2, 0x004a4, 0x004a4, 0x004a6, 0x004a6,
+ 0x004a8, 0x004a8, 0x004aa, 0x004aa, 0x004ac, 0x004ac, 0x004ae, 0x004ae,
+ 0x004b0, 0x004b0, 0x004b2, 0x004b2, 0x004b4, 0x004b4, 0x004b6, 0x004b6,
+ 0x004b8, 0x004b8, 0x004ba, 0x004ba, 0x004bc, 0x004bc, 0x004be, 0x004be,
+ 0x004c0, 0x00416, 0x00416, 0x004c3, 0x004c3, 0x004c5, 0x004c6, 0x004c7,
+ 0x004c7, 0x004c9, 0x004ca, 0x004cb, 0x004cb, 0x004cd, 0x004ce, 0x004cf,
+ 0x00410, 0x00410, 0x00410, 0x00410, 0x004d4, 0x004d4, 0x00415, 0x00415,
+ 0x004d8, 0x004d8, 0x004d8, 0x004d8, 0x00416, 0x00416, 0x00417, 0x00417,
+ 0x004e0, 0x004e0, 0x00418, 0x00418, 0x00418, 0x00418, 0x0041e, 0x0041e,
+ 0x004e8, 0x004e8, 0x004e8, 0x004e8, 0x0042d, 0x0042d, 0x00423, 0x00423,
+ 0x00423, 0x00423, 0x00423, 0x00423, 0x00427, 0x00427, 0x004f6, 0x004f7,
+ 0x0042b, 0x0042b, 0x004fa, 0x004fb, 0x004fc, 0x004fd, 0x004fe, 0x004ff
+};
+
+static uint32_t general_ci_page_05[] = {
+ 0x00500, 0x00501, 0x00502, 0x00503, 0x00504, 0x00505, 0x00506, 0x00507,
+ 0x00508, 0x00509, 0x0050a, 0x0050b, 0x0050c, 0x0050d, 0x0050e, 0x0050f,
+ 0x00510, 0x00511, 0x00512, 0x00513, 0x00514, 0x00515, 0x00516, 0x00517,
+ 0x00518, 0x00519, 0x0051a, 0x0051b, 0x0051c, 0x0051d, 0x0051e, 0x0051f,
+ 0x00520, 0x00521, 0x00522, 0x00523, 0x00524, 0x00525, 0x00526, 0x00527,
+ 0x00528, 0x00529, 0x0052a, 0x0052b, 0x0052c, 0x0052d, 0x0052e, 0x0052f,
+ 0x00530, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00557,
+ 0x00558, 0x00559, 0x0055a, 0x0055b, 0x0055c, 0x0055d, 0x0055e, 0x0055f,
+ 0x00560, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00587,
+ 0x00588, 0x00589, 0x0058a, 0x0058b, 0x0058c, 0x0058d, 0x0058e, 0x0058f,
+ 0x00590, 0x00591, 0x00592, 0x00593, 0x00594, 0x00595, 0x00596, 0x00597,
+ 0x00598, 0x00599, 0x0059a, 0x0059b, 0x0059c, 0x0059d, 0x0059e, 0x0059f,
+ 0x005a0, 0x005a1, 0x005a2, 0x005a3, 0x005a4, 0x005a5, 0x005a6, 0x005a7,
+ 0x005a8, 0x005a9, 0x005aa, 0x005ab, 0x005ac, 0x005ad, 0x005ae, 0x005af,
+ 0x005b0, 0x005b1, 0x005b2, 0x005b3, 0x005b4, 0x005b5, 0x005b6, 0x005b7,
+ 0x005b8, 0x005b9, 0x005ba, 0x005bb, 0x005bc, 0x005bd, 0x005be, 0x005bf,
+ 0x005c0, 0x005c1, 0x005c2, 0x005c3, 0x005c4, 0x005c5, 0x005c6, 0x005c7,
+ 0x005c8, 0x005c9, 0x005ca, 0x005cb, 0x005cc, 0x005cd, 0x005ce, 0x005cf,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x005d7,
+ 0x005d8, 0x005d9, 0x005da, 0x005db, 0x005dc, 0x005dd, 0x005de, 0x005df,
+ 0x005e0, 0x005e1, 0x005e2, 0x005e3, 0x005e4, 0x005e5, 0x005e6, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005eb, 0x005ec, 0x005ed, 0x005ee, 0x005ef,
+ 0x005f0, 0x005f1, 0x005f2, 0x005f3, 0x005f4, 0x005f5, 0x005f6, 0x005f7,
+ 0x005f8, 0x005f9, 0x005fa, 0x005fb, 0x005fc, 0x005fd, 0x005fe, 0x005ff
+};
+
+static uint32_t general_ci_page_1e[] = {
+ 0x00041, 0x00041, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042,
+ 0x00043, 0x00043, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00046, 0x00046,
+ 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00048, 0x00048, 0x00048, 0x00048, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004d, 0x0004d,
+ 0x0004d, 0x0004d, 0x0004d, 0x0004d, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00050, 0x00050, 0x00050, 0x00050,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054,
+ 0x00054, 0x00054, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00056, 0x00056, 0x00056, 0x00056,
+ 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057,
+ 0x00057, 0x00057, 0x00058, 0x00058, 0x00058, 0x00058, 0x00059, 0x00059,
+ 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00048, 0x00054,
+ 0x00057, 0x00059, 0x01e9a, 0x00053, 0x01e9c, 0x01e9d, 0x01e9e, 0x01e9f,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059,
+ 0x00059, 0x00059, 0x01efa, 0x01efb, 0x01efc, 0x01efd, 0x01efe, 0x01eff
+};
+
+static uint32_t general_ci_page_1f[] = {
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f16, 0x01f17,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f1e, 0x01f1f,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f46, 0x01f47,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f4e, 0x01f4f,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5,
+ 0x01f58, 0x003a5, 0x01f5a, 0x003a5, 0x01f5c, 0x003a5, 0x01f5e, 0x003a5,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x01fbb, 0x00395, 0x01fc9, 0x00397, 0x01fcb, 0x00399, 0x01fdb,
+ 0x0039f, 0x01ff9, 0x003a5, 0x01feb, 0x003a9, 0x01ffb, 0x01f7e, 0x01f7f,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fb5, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x01fbb, 0x00391, 0x01fbd, 0x00399, 0x01fbf,
+ 0x01fc0, 0x01fc1, 0x00397, 0x00397, 0x00397, 0x01fc5, 0x00397, 0x00397,
+ 0x00395, 0x01fc9, 0x00397, 0x01fcb, 0x00397, 0x01fcd, 0x01fce, 0x01fcf,
+ 0x00399, 0x00399, 0x00399, 0x01fd3, 0x01fd4, 0x01fd5, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x01fdb, 0x01fdc, 0x01fdd, 0x01fde, 0x01fdf,
+ 0x003a5, 0x003a5, 0x003a5, 0x01fe3, 0x003a1, 0x003a1, 0x003a5, 0x003a5,
+ 0x003a5, 0x003a5, 0x003a5, 0x01feb, 0x003a1, 0x01fed, 0x01fee, 0x01fef,
+ 0x01ff0, 0x01ff1, 0x003a9, 0x003a9, 0x003a9, 0x01ff5, 0x003a9, 0x003a9,
+ 0x0039f, 0x01ff9, 0x003a9, 0x01ffb, 0x003a9, 0x01ffd, 0x01ffe, 0x01fff
+};
+
+static uint32_t general_ci_page_21[] = {
+ 0x02100, 0x02101, 0x02102, 0x02103, 0x02104, 0x02105, 0x02106, 0x02107,
+ 0x02108, 0x02109, 0x0210a, 0x0210b, 0x0210c, 0x0210d, 0x0210e, 0x0210f,
+ 0x02110, 0x02111, 0x02112, 0x02113, 0x02114, 0x02115, 0x02116, 0x02117,
+ 0x02118, 0x02119, 0x0211a, 0x0211b, 0x0211c, 0x0211d, 0x0211e, 0x0211f,
+ 0x02120, 0x02121, 0x02122, 0x02123, 0x02124, 0x02125, 0x02126, 0x02127,
+ 0x02128, 0x02129, 0x0212a, 0x0212b, 0x0212c, 0x0212d, 0x0212e, 0x0212f,
+ 0x02130, 0x02131, 0x02132, 0x02133, 0x02134, 0x02135, 0x02136, 0x02137,
+ 0x02138, 0x02139, 0x0213a, 0x0213b, 0x0213c, 0x0213d, 0x0213e, 0x0213f,
+ 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x02145, 0x02146, 0x02147,
+ 0x02148, 0x02149, 0x0214a, 0x0214b, 0x0214c, 0x0214d, 0x0214e, 0x0214f,
+ 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157,
+ 0x02158, 0x02159, 0x0215a, 0x0215b, 0x0215c, 0x0215d, 0x0215e, 0x0215f,
+ 0x02160, 0x02161, 0x02162, 0x02163, 0x02164, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x02169, 0x0216a, 0x0216b, 0x0216c, 0x0216d, 0x0216e, 0x0216f,
+ 0x02160, 0x02161, 0x02162, 0x02163, 0x02164, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x02169, 0x0216a, 0x0216b, 0x0216c, 0x0216d, 0x0216e, 0x0216f,
+ 0x02180, 0x02181, 0x02182, 0x02183, 0x02184, 0x02185, 0x02186, 0x02187,
+ 0x02188, 0x02189, 0x0218a, 0x0218b, 0x0218c, 0x0218d, 0x0218e, 0x0218f,
+ 0x02190, 0x02191, 0x02192, 0x02193, 0x02194, 0x02195, 0x02196, 0x02197,
+ 0x02198, 0x02199, 0x0219a, 0x0219b, 0x0219c, 0x0219d, 0x0219e, 0x0219f,
+ 0x021a0, 0x021a1, 0x021a2, 0x021a3, 0x021a4, 0x021a5, 0x021a6, 0x021a7,
+ 0x021a8, 0x021a9, 0x021aa, 0x021ab, 0x021ac, 0x021ad, 0x021ae, 0x021af,
+ 0x021b0, 0x021b1, 0x021b2, 0x021b3, 0x021b4, 0x021b5, 0x021b6, 0x021b7,
+ 0x021b8, 0x021b9, 0x021ba, 0x021bb, 0x021bc, 0x021bd, 0x021be, 0x021bf,
+ 0x021c0, 0x021c1, 0x021c2, 0x021c3, 0x021c4, 0x021c5, 0x021c6, 0x021c7,
+ 0x021c8, 0x021c9, 0x021ca, 0x021cb, 0x021cc, 0x021cd, 0x021ce, 0x021cf,
+ 0x021d0, 0x021d1, 0x021d2, 0x021d3, 0x021d4, 0x021d5, 0x021d6, 0x021d7,
+ 0x021d8, 0x021d9, 0x021da, 0x021db, 0x021dc, 0x021dd, 0x021de, 0x021df,
+ 0x021e0, 0x021e1, 0x021e2, 0x021e3, 0x021e4, 0x021e5, 0x021e6, 0x021e7,
+ 0x021e8, 0x021e9, 0x021ea, 0x021eb, 0x021ec, 0x021ed, 0x021ee, 0x021ef,
+ 0x021f0, 0x021f1, 0x021f2, 0x021f3, 0x021f4, 0x021f5, 0x021f6, 0x021f7,
+ 0x021f8, 0x021f9, 0x021fa, 0x021fb, 0x021fc, 0x021fd, 0x021fe, 0x021ff
+};
+
+static uint32_t general_ci_page_24[] = {
+ 0x02400, 0x02401, 0x02402, 0x02403, 0x02404, 0x02405, 0x02406, 0x02407,
+ 0x02408, 0x02409, 0x0240a, 0x0240b, 0x0240c, 0x0240d, 0x0240e, 0x0240f,
+ 0x02410, 0x02411, 0x02412, 0x02413, 0x02414, 0x02415, 0x02416, 0x02417,
+ 0x02418, 0x02419, 0x0241a, 0x0241b, 0x0241c, 0x0241d, 0x0241e, 0x0241f,
+ 0x02420, 0x02421, 0x02422, 0x02423, 0x02424, 0x02425, 0x02426, 0x02427,
+ 0x02428, 0x02429, 0x0242a, 0x0242b, 0x0242c, 0x0242d, 0x0242e, 0x0242f,
+ 0x02430, 0x02431, 0x02432, 0x02433, 0x02434, 0x02435, 0x02436, 0x02437,
+ 0x02438, 0x02439, 0x0243a, 0x0243b, 0x0243c, 0x0243d, 0x0243e, 0x0243f,
+ 0x02440, 0x02441, 0x02442, 0x02443, 0x02444, 0x02445, 0x02446, 0x02447,
+ 0x02448, 0x02449, 0x0244a, 0x0244b, 0x0244c, 0x0244d, 0x0244e, 0x0244f,
+ 0x02450, 0x02451, 0x02452, 0x02453, 0x02454, 0x02455, 0x02456, 0x02457,
+ 0x02458, 0x02459, 0x0245a, 0x0245b, 0x0245c, 0x0245d, 0x0245e, 0x0245f,
+ 0x02460, 0x02461, 0x02462, 0x02463, 0x02464, 0x02465, 0x02466, 0x02467,
+ 0x02468, 0x02469, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e, 0x0246f,
+ 0x02470, 0x02471, 0x02472, 0x02473, 0x02474, 0x02475, 0x02476, 0x02477,
+ 0x02478, 0x02479, 0x0247a, 0x0247b, 0x0247c, 0x0247d, 0x0247e, 0x0247f,
+ 0x02480, 0x02481, 0x02482, 0x02483, 0x02484, 0x02485, 0x02486, 0x02487,
+ 0x02488, 0x02489, 0x0248a, 0x0248b, 0x0248c, 0x0248d, 0x0248e, 0x0248f,
+ 0x02490, 0x02491, 0x02492, 0x02493, 0x02494, 0x02495, 0x02496, 0x02497,
+ 0x02498, 0x02499, 0x0249a, 0x0249b, 0x0249c, 0x0249d, 0x0249e, 0x0249f,
+ 0x024a0, 0x024a1, 0x024a2, 0x024a3, 0x024a4, 0x024a5, 0x024a6, 0x024a7,
+ 0x024a8, 0x024a9, 0x024aa, 0x024ab, 0x024ac, 0x024ad, 0x024ae, 0x024af,
+ 0x024b0, 0x024b1, 0x024b2, 0x024b3, 0x024b4, 0x024b5, 0x024b6, 0x024b7,
+ 0x024b8, 0x024b9, 0x024ba, 0x024bb, 0x024bc, 0x024bd, 0x024be, 0x024bf,
+ 0x024c0, 0x024c1, 0x024c2, 0x024c3, 0x024c4, 0x024c5, 0x024c6, 0x024c7,
+ 0x024c8, 0x024c9, 0x024ca, 0x024cb, 0x024cc, 0x024cd, 0x024ce, 0x024cf,
+ 0x024b6, 0x024b7, 0x024b8, 0x024b9, 0x024ba, 0x024bb, 0x024bc, 0x024bd,
+ 0x024be, 0x024bf, 0x024c0, 0x024c1, 0x024c2, 0x024c3, 0x024c4, 0x024c5,
+ 0x024c6, 0x024c7, 0x024c8, 0x024c9, 0x024ca, 0x024cb, 0x024cc, 0x024cd,
+ 0x024ce, 0x024cf, 0x024ea, 0x024eb, 0x024ec, 0x024ed, 0x024ee, 0x024ef,
+ 0x024f0, 0x024f1, 0x024f2, 0x024f3, 0x024f4, 0x024f5, 0x024f6, 0x024f7,
+ 0x024f8, 0x024f9, 0x024fa, 0x024fb, 0x024fc, 0x024fd, 0x024fe, 0x024ff
+};
+
+static uint32_t general_ci_page_ff[] = {
+ 0x0ff00, 0x0ff01, 0x0ff02, 0x0ff03, 0x0ff04, 0x0ff05, 0x0ff06, 0x0ff07,
+ 0x0ff08, 0x0ff09, 0x0ff0a, 0x0ff0b, 0x0ff0c, 0x0ff0d, 0x0ff0e, 0x0ff0f,
+ 0x0ff10, 0x0ff11, 0x0ff12, 0x0ff13, 0x0ff14, 0x0ff15, 0x0ff16, 0x0ff17,
+ 0x0ff18, 0x0ff19, 0x0ff1a, 0x0ff1b, 0x0ff1c, 0x0ff1d, 0x0ff1e, 0x0ff1f,
+ 0x0ff20, 0x0ff21, 0x0ff22, 0x0ff23, 0x0ff24, 0x0ff25, 0x0ff26, 0x0ff27,
+ 0x0ff28, 0x0ff29, 0x0ff2a, 0x0ff2b, 0x0ff2c, 0x0ff2d, 0x0ff2e, 0x0ff2f,
+ 0x0ff30, 0x0ff31, 0x0ff32, 0x0ff33, 0x0ff34, 0x0ff35, 0x0ff36, 0x0ff37,
+ 0x0ff38, 0x0ff39, 0x0ff3a, 0x0ff3b, 0x0ff3c, 0x0ff3d, 0x0ff3e, 0x0ff3f,
+ 0x0ff40, 0x0ff21, 0x0ff22, 0x0ff23, 0x0ff24, 0x0ff25, 0x0ff26, 0x0ff27,
+ 0x0ff28, 0x0ff29, 0x0ff2a, 0x0ff2b, 0x0ff2c, 0x0ff2d, 0x0ff2e, 0x0ff2f,
+ 0x0ff30, 0x0ff31, 0x0ff32, 0x0ff33, 0x0ff34, 0x0ff35, 0x0ff36, 0x0ff37,
+ 0x0ff38, 0x0ff39, 0x0ff3a, 0x0ff5b, 0x0ff5c, 0x0ff5d, 0x0ff5e, 0x0ff5f,
+ 0x0ff60, 0x0ff61, 0x0ff62, 0x0ff63, 0x0ff64, 0x0ff65, 0x0ff66, 0x0ff67,
+ 0x0ff68, 0x0ff69, 0x0ff6a, 0x0ff6b, 0x0ff6c, 0x0ff6d, 0x0ff6e, 0x0ff6f,
+ 0x0ff70, 0x0ff71, 0x0ff72, 0x0ff73, 0x0ff74, 0x0ff75, 0x0ff76, 0x0ff77,
+ 0x0ff78, 0x0ff79, 0x0ff7a, 0x0ff7b, 0x0ff7c, 0x0ff7d, 0x0ff7e, 0x0ff7f,
+ 0x0ff80, 0x0ff81, 0x0ff82, 0x0ff83, 0x0ff84, 0x0ff85, 0x0ff86, 0x0ff87,
+ 0x0ff88, 0x0ff89, 0x0ff8a, 0x0ff8b, 0x0ff8c, 0x0ff8d, 0x0ff8e, 0x0ff8f,
+ 0x0ff90, 0x0ff91, 0x0ff92, 0x0ff93, 0x0ff94, 0x0ff95, 0x0ff96, 0x0ff97,
+ 0x0ff98, 0x0ff99, 0x0ff9a, 0x0ff9b, 0x0ff9c, 0x0ff9d, 0x0ff9e, 0x0ff9f,
+ 0x0ffa0, 0x0ffa1, 0x0ffa2, 0x0ffa3, 0x0ffa4, 0x0ffa5, 0x0ffa6, 0x0ffa7,
+ 0x0ffa8, 0x0ffa9, 0x0ffaa, 0x0ffab, 0x0ffac, 0x0ffad, 0x0ffae, 0x0ffaf,
+ 0x0ffb0, 0x0ffb1, 0x0ffb2, 0x0ffb3, 0x0ffb4, 0x0ffb5, 0x0ffb6, 0x0ffb7,
+ 0x0ffb8, 0x0ffb9, 0x0ffba, 0x0ffbb, 0x0ffbc, 0x0ffbd, 0x0ffbe, 0x0ffbf,
+ 0x0ffc0, 0x0ffc1, 0x0ffc2, 0x0ffc3, 0x0ffc4, 0x0ffc5, 0x0ffc6, 0x0ffc7,
+ 0x0ffc8, 0x0ffc9, 0x0ffca, 0x0ffcb, 0x0ffcc, 0x0ffcd, 0x0ffce, 0x0ffcf,
+ 0x0ffd0, 0x0ffd1, 0x0ffd2, 0x0ffd3, 0x0ffd4, 0x0ffd5, 0x0ffd6, 0x0ffd7,
+ 0x0ffd8, 0x0ffd9, 0x0ffda, 0x0ffdb, 0x0ffdc, 0x0ffdd, 0x0ffde, 0x0ffdf,
+ 0x0ffe0, 0x0ffe1, 0x0ffe2, 0x0ffe3, 0x0ffe4, 0x0ffe5, 0x0ffe6, 0x0ffe7,
+ 0x0ffe8, 0x0ffe9, 0x0ffea, 0x0ffeb, 0x0ffec, 0x0ffed, 0x0ffee, 0x0ffef,
+ 0x0fff0, 0x0fff1, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff5, 0x0fff6, 0x0fff7,
+ 0x0fff8, 0x0fff9, 0x0fffa, 0x0fffb, 0x0fffc, 0x0fffd, 0x0fffe, 0x0ffff
+};
+
+static uint32_t *general_ci_table[256] = {
+ general_ci_page_00, general_ci_page_01,
+ general_ci_page_02, general_ci_page_03,
+ general_ci_page_04, general_ci_page_05,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ general_ci_page_1e, general_ci_page_1f,
+ NULL, general_ci_page_21,
+ NULL, NULL,
+ general_ci_page_24, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, general_ci_page_ff
+};
+
+#endif
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_sources.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_sources.am
new file mode 100644
index 00000000..07f30b30
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_sources.am
@@ -0,0 +1,7 @@
+mysql_la_SOURCES = \
+ mysql.c \
+ mysql_general_ci_table.h \
+ mysql_unicode_ci_table.h \
+ mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h \
+ mysql_unicode_520_ci_table.h \
+ mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
new file mode 100644
index 00000000..1a963122
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
@@ -0,0 +1,5028 @@
+/*
+ Copyright(C) 2013-2015 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ mysql-5.6.23/strings/ctype-uca.c.
+ The following is the header of the file:
+
+ Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UCA (Unicode Collation Algorithm) support.
+ Written by Alexander Barkov <bar@mysql.com>
+*/
+
+#ifndef MYSQL_UCA_520_EXCEPT_KANA_CI_KANA_WITH_VOICED_SOUND_MARK_H
+#define MYSQL_UCA_520_EXCEPT_KANA_CI_KANA_WITH_VOICED_SOUND_MARK_H
+
+#include <stdint.h>
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_00[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00009, 0x0000a, 0x0000b, 0x0000c, 0x0000d, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00085, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x000a1, 0x000a2, 0x000a3, 0x000a4, 0x000a5, 0x000a6, 0x000a7,
+ 0x000a8, 0x000a9, 0x00041, 0x000ab, 0x000ac, 0x000ad, 0x000ae, 0x000af,
+ 0x000b0, 0x000b1, 0x00032, 0x00033, 0x000b4, 0x0039c, 0x000b6, 0x000b7,
+ 0x000b8, 0x00031, 0x0004f, 0x000bb, 0x000bc, 0x000bd, 0x000be, 0x000bf,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00044, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000d7,
+ 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x000df,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00044, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000f7,
+ 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000fe, 0x000ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_01[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00043, 0x00043,
+ 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00047, 0x00047, 0x00047, 0x00047,
+ 0x00047, 0x00047, 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00049, 0x00131, 0x00132, 0x00132, 0x0004a, 0x0004a, 0x0004b, 0x0004b,
+ 0x00138, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x00149, 0x0014a, 0x0014a, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00152, 0x00152, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00052, 0x00052, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00166, 0x00166,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00057, 0x00057, 0x00059, 0x00059,
+ 0x00059, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00053,
+ 0x00180, 0x00181, 0x00182, 0x00182, 0x00184, 0x00184, 0x00186, 0x00187,
+ 0x00187, 0x00189, 0x0018a, 0x0018b, 0x0018b, 0x0018d, 0x0018e, 0x0018f,
+ 0x00190, 0x00191, 0x00191, 0x00193, 0x00194, 0x00195, 0x00196, 0x00197,
+ 0x00198, 0x00198, 0x0019a, 0x0019b, 0x0019c, 0x0019d, 0x0019e, 0x0019f,
+ 0x0004f, 0x0004f, 0x001a2, 0x001a2, 0x001a4, 0x001a4, 0x001a6, 0x001a7,
+ 0x001a7, 0x001a9, 0x001aa, 0x001ab, 0x001ac, 0x001ac, 0x001ae, 0x00055,
+ 0x00055, 0x001b1, 0x001b2, 0x001b3, 0x001b3, 0x001b5, 0x001b5, 0x001b7,
+ 0x001b8, 0x001b8, 0x001ba, 0x001bb, 0x001bc, 0x001bc, 0x001be, 0x001bf,
+ 0x001c0, 0x001c1, 0x001c2, 0x001c3, 0x001c4, 0x001c4, 0x001c4, 0x001c7,
+ 0x001c7, 0x001c7, 0x001ca, 0x001ca, 0x001ca, 0x00041, 0x00041, 0x00049,
+ 0x00049, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x0018e, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x000c6, 0x000c6, 0x001e4, 0x001e4, 0x00047, 0x00047,
+ 0x0004b, 0x0004b, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x001b7, 0x001b7,
+ 0x0004a, 0x001c4, 0x001c4, 0x001c4, 0x00047, 0x00047, 0x00195, 0x001bf,
+ 0x0004e, 0x0004e, 0x00041, 0x00041, 0x000c6, 0x000c6, 0x0004f, 0x001ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_02[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x0021c, 0x0021c, 0x00048, 0x00048,
+ 0x0019e, 0x00221, 0x00222, 0x00222, 0x00224, 0x00224, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00059, 0x00059, 0x00234, 0x00235, 0x00236, 0x00237,
+ 0x00238, 0x00239, 0x0023a, 0x0023b, 0x0023b, 0x0019a, 0x0023e, 0x0023f,
+ 0x00240, 0x00241, 0x00241, 0x00180, 0x00244, 0x00245, 0x00246, 0x00246,
+ 0x00248, 0x00248, 0x0024a, 0x0024a, 0x0024c, 0x0024c, 0x0024e, 0x0024e,
+ 0x00250, 0x00251, 0x00252, 0x00181, 0x00186, 0x00255, 0x00189, 0x0018a,
+ 0x00258, 0x0018f, 0x0025a, 0x00190, 0x0025c, 0x0025d, 0x0025e, 0x0025f,
+ 0x00193, 0x00261, 0x00262, 0x00194, 0x00264, 0x00265, 0x00266, 0x00267,
+ 0x00197, 0x00196, 0x0026a, 0x0026b, 0x0026c, 0x0026d, 0x0026e, 0x0019c,
+ 0x00270, 0x00271, 0x0019d, 0x00273, 0x00274, 0x0019f, 0x00276, 0x00277,
+ 0x00278, 0x00279, 0x0027a, 0x0027b, 0x0027c, 0x0027d, 0x0027e, 0x0027f,
+ 0x001a6, 0x00281, 0x00282, 0x001a9, 0x00284, 0x00285, 0x00286, 0x00287,
+ 0x001ae, 0x00244, 0x001b1, 0x001b2, 0x00245, 0x0028d, 0x0028e, 0x0028f,
+ 0x00290, 0x00291, 0x001b7, 0x00293, 0x00294, 0x00295, 0x00296, 0x00297,
+ 0x00298, 0x00299, 0x0029a, 0x0029b, 0x0029c, 0x0029d, 0x0029e, 0x0029f,
+ 0x002a0, 0x002a1, 0x002a2, 0x001c4, 0x002a4, 0x002a5, 0x001be, 0x002a7,
+ 0x002a8, 0x002a9, 0x002aa, 0x002ab, 0x002ac, 0x002ad, 0x002ae, 0x002af,
+ 0x00048, 0x00266, 0x0004a, 0x00052, 0x00279, 0x0027b, 0x00281, 0x00057,
+ 0x00059, 0x002b9, 0x002ba, 0x002bb, 0x002bc, 0x002bd, 0x002be, 0x002bf,
+ 0x002c0, 0x002c1, 0x002c2, 0x002c3, 0x002c4, 0x002c5, 0x002c6, 0x002c7,
+ 0x002c8, 0x002c9, 0x002ca, 0x002cb, 0x002cc, 0x002cd, 0x002ce, 0x002cf,
+ 0x002d0, 0x002d1, 0x002d2, 0x002d3, 0x002d4, 0x002d5, 0x002d6, 0x002d7,
+ 0x002d8, 0x002d9, 0x002da, 0x002db, 0x002dc, 0x002dd, 0x002de, 0x002df,
+ 0x00194, 0x0004c, 0x00053, 0x00058, 0x00295, 0x002e5, 0x002e6, 0x002e7,
+ 0x002e8, 0x002e9, 0x002ea, 0x002eb, 0x002ec, 0x002ed, 0x002ee, 0x002ef,
+ 0x002f0, 0x002f1, 0x002f2, 0x002f3, 0x002f4, 0x002f5, 0x002f6, 0x002f7,
+ 0x002f8, 0x002f9, 0x002fa, 0x002fb, 0x002fc, 0x002fd, 0x002fe, 0x002ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_03[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00041, 0x00045, 0x00049, 0x0004f, 0x00055,
+ 0x00043, 0x00044, 0x00048, 0x0004d, 0x00052, 0x00054, 0x00056, 0x00058,
+ 0x00370, 0x00370, 0x00372, 0x00372, 0x002b9, 0x00375, 0x00376, 0x00376,
+ 0x00378, 0x00379, 0x00399, 0x0037b, 0x0037c, 0x0037d, 0x0003b, 0x0037f,
+ 0x00380, 0x00381, 0x00382, 0x00383, 0x000b4, 0x000a8, 0x00391, 0x000b7,
+ 0x00395, 0x00397, 0x00399, 0x0038b, 0x0039f, 0x0038d, 0x003a5, 0x003a9,
+ 0x00399, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a2, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x00391, 0x00395, 0x00397, 0x00399,
+ 0x003a5, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x0039f, 0x003a5, 0x003a9, 0x003cf,
+ 0x00392, 0x00398, 0x003a5, 0x003a5, 0x003a5, 0x003a6, 0x003a0, 0x003cf,
+ 0x003d8, 0x003d8, 0x003da, 0x003da, 0x003dc, 0x003dc, 0x003de, 0x003de,
+ 0x003e0, 0x003e0, 0x003e2, 0x003e2, 0x003e4, 0x003e4, 0x003e6, 0x003e6,
+ 0x003e8, 0x003e8, 0x003ea, 0x003ea, 0x003ec, 0x003ec, 0x003ee, 0x003ee,
+ 0x0039a, 0x003a1, 0x003a3, 0x003f3, 0x00398, 0x00395, 0x003f6, 0x003f7,
+ 0x003f7, 0x003a3, 0x003fa, 0x003fa, 0x003fc, 0x0037b, 0x003fe, 0x003ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_04[] = {
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00460, 0x00460, 0x00462, 0x00462, 0x00464, 0x00464, 0x00466, 0x00466,
+ 0x00468, 0x00468, 0x0046a, 0x0046a, 0x0046c, 0x0046c, 0x0046e, 0x0046e,
+ 0x00470, 0x00470, 0x00472, 0x00472, 0x00474, 0x00474, 0x00476, 0x00476,
+ 0x00478, 0x00478, 0x0047a, 0x0047a, 0x0047c, 0x0047c, 0x0047e, 0x0047e,
+ 0x00480, 0x00480, 0x00482, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x0048a, 0x0048a, 0x0048c, 0x0048c, 0x0048e, 0x0048e,
+ 0x00413, 0x00413, 0x00492, 0x00492, 0x00494, 0x00494, 0x00496, 0x00496,
+ 0x00498, 0x00498, 0x0049a, 0x0049a, 0x0049c, 0x0049c, 0x0049e, 0x0049e,
+ 0x004a0, 0x004a0, 0x004a2, 0x004a2, 0x004a4, 0x004a4, 0x004a6, 0x004a6,
+ 0x004a8, 0x004a8, 0x004aa, 0x004aa, 0x004ac, 0x004ac, 0x004ae, 0x004ae,
+ 0x004b0, 0x004b0, 0x004b2, 0x004b2, 0x004b4, 0x004b4, 0x004b6, 0x004b6,
+ 0x004b8, 0x004b8, 0x004ba, 0x004ba, 0x004bc, 0x004bc, 0x004be, 0x004be,
+ 0x004c0, 0x00416, 0x00416, 0x004c3, 0x004c3, 0x004c5, 0x004c5, 0x004c7,
+ 0x004c7, 0x004c9, 0x004c9, 0x004cb, 0x004cb, 0x004cd, 0x004cd, 0x004c0,
+ 0x004d0, 0x004d0, 0x004d2, 0x004d2, 0x004d4, 0x004d4, 0x004d6, 0x004d6,
+ 0x004d8, 0x004d8, 0x004da, 0x004da, 0x004dc, 0x004dc, 0x004de, 0x004de,
+ 0x004e0, 0x004e0, 0x0040d, 0x0040d, 0x004e4, 0x004e4, 0x004e6, 0x004e6,
+ 0x004e8, 0x004e8, 0x004ea, 0x004ea, 0x004ec, 0x004ec, 0x00423, 0x00423,
+ 0x004f0, 0x004f0, 0x004f2, 0x004f2, 0x004f4, 0x004f4, 0x004f6, 0x004f6,
+ 0x004f8, 0x004f8, 0x004fa, 0x004fa, 0x004fc, 0x004fd, 0x004fe, 0x004ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_05[] = {
+ 0x00500, 0x00500, 0x00502, 0x00502, 0x00504, 0x00504, 0x00506, 0x00506,
+ 0x00508, 0x00508, 0x0050a, 0x0050a, 0x0050c, 0x0050c, 0x0050e, 0x0050e,
+ 0x00510, 0x00510, 0x00512, 0x00512, 0x00514, 0x00514, 0x00516, 0x00516,
+ 0x00518, 0x00518, 0x0051a, 0x0051a, 0x0051c, 0x0051c, 0x0051e, 0x0051e,
+ 0x00520, 0x00520, 0x00522, 0x00522, 0x00524, 0x00524, 0x00526, 0x00527,
+ 0x00528, 0x00529, 0x0052a, 0x0052b, 0x0052c, 0x0052d, 0x0052e, 0x0052f,
+ 0x00530, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00557,
+ 0x00558, 0x00559, 0x0055a, 0x0055b, 0x0055c, 0x0055d, 0x0055e, 0x0055f,
+ 0x00560, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00587,
+ 0x00588, 0x00589, 0x0058a, 0x0058b, 0x0058c, 0x0058d, 0x0058e, 0x0058f,
+ 0x00590, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x005be, 0x00000,
+ 0x005c0, 0x00000, 0x00000, 0x005c3, 0x00000, 0x00000, 0x005c6, 0x00000,
+ 0x005c8, 0x005c9, 0x005ca, 0x005cb, 0x005cc, 0x005cd, 0x005ce, 0x005cf,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x005d7,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x005dd, 0x005dd, 0x005df,
+ 0x005df, 0x005e1, 0x005e2, 0x005e3, 0x005e3, 0x005e5, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005eb, 0x005ec, 0x005ed, 0x005ee, 0x005ef,
+ 0x005f0, 0x005f1, 0x005f2, 0x005f3, 0x005f4, 0x005f5, 0x005f6, 0x005f7,
+ 0x005f8, 0x005f9, 0x005fa, 0x005fb, 0x005fc, 0x005fd, 0x005fe, 0x005ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_06[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00604, 0x00605, 0x00606, 0x00607,
+ 0x00608, 0x00609, 0x0060a, 0x0060b, 0x0060c, 0x0060d, 0x0060e, 0x0060f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0061b, 0x0061c, 0x0061d, 0x0061e, 0x0061f,
+ 0x00620, 0x00621, 0x00622, 0x00623, 0x00624, 0x00625, 0x00626, 0x00627,
+ 0x00628, 0x00629, 0x0062a, 0x0062b, 0x0062c, 0x0062d, 0x0062e, 0x0062f,
+ 0x00630, 0x00631, 0x00632, 0x00633, 0x00634, 0x00635, 0x00636, 0x00637,
+ 0x00638, 0x00639, 0x0063a, 0x0063b, 0x0063c, 0x0063d, 0x0063e, 0x0063f,
+ 0x00640, 0x00641, 0x00642, 0x00643, 0x00644, 0x00645, 0x00646, 0x00647,
+ 0x00648, 0x00649, 0x0064a, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0065f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0066a, 0x0066b, 0x0066c, 0x0066d, 0x0066e, 0x0066f,
+ 0x00000, 0x00671, 0x00672, 0x00673, 0x00621, 0x00675, 0x00676, 0x00677,
+ 0x00678, 0x00679, 0x0067a, 0x0067b, 0x0067c, 0x0067d, 0x0067e, 0x0067f,
+ 0x00680, 0x00681, 0x00682, 0x00683, 0x00684, 0x00685, 0x00686, 0x00687,
+ 0x00688, 0x00689, 0x0068a, 0x0068b, 0x0068c, 0x0068d, 0x0068e, 0x0068f,
+ 0x00690, 0x00691, 0x00692, 0x00693, 0x00694, 0x00695, 0x00696, 0x00697,
+ 0x00698, 0x00699, 0x0069a, 0x0069b, 0x0069c, 0x0069d, 0x0069e, 0x0069f,
+ 0x006a0, 0x006a1, 0x006a2, 0x006a3, 0x006a4, 0x006a5, 0x006a6, 0x006a7,
+ 0x006a8, 0x006a9, 0x006aa, 0x006ab, 0x006ac, 0x006ad, 0x006ae, 0x006af,
+ 0x006b0, 0x006b1, 0x006b2, 0x006b3, 0x006b4, 0x006b5, 0x006b6, 0x006b7,
+ 0x006b8, 0x006b9, 0x006ba, 0x006bb, 0x006bc, 0x006bd, 0x006be, 0x006bf,
+ 0x006c0, 0x006c1, 0x006c1, 0x006c3, 0x006c4, 0x006c5, 0x006c6, 0x006c7,
+ 0x006c8, 0x006c9, 0x006ca, 0x006cb, 0x006cc, 0x006cd, 0x006ce, 0x006cf,
+ 0x006d0, 0x006d1, 0x006d2, 0x006d2, 0x006d4, 0x006c0, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00648, 0x0064a, 0x00000,
+ 0x00000, 0x006e9, 0x00000, 0x00000, 0x00000, 0x00000, 0x006ee, 0x006ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x006fa, 0x006fb, 0x006fc, 0x00621, 0x00645, 0x006ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_07[] = {
+ 0x00700, 0x00701, 0x00702, 0x00703, 0x00704, 0x00705, 0x00706, 0x00707,
+ 0x00708, 0x00709, 0x0070a, 0x0070b, 0x0070c, 0x0070d, 0x0070e, 0x00000,
+ 0x00710, 0x00000, 0x00712, 0x00713, 0x00713, 0x00715, 0x00716, 0x00717,
+ 0x00718, 0x00719, 0x0071a, 0x0071b, 0x0071b, 0x0071d, 0x0071e, 0x0071f,
+ 0x00720, 0x00721, 0x00722, 0x00723, 0x00723, 0x00725, 0x00726, 0x00726,
+ 0x00728, 0x00729, 0x0072a, 0x0072b, 0x0072c, 0x00712, 0x00713, 0x00715,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0074b, 0x0074c, 0x0074d, 0x0074e, 0x0074f,
+ 0x00750, 0x00751, 0x00752, 0x00753, 0x00754, 0x00755, 0x00756, 0x00757,
+ 0x00758, 0x00759, 0x0075a, 0x0075b, 0x0075c, 0x0075d, 0x0075e, 0x0075f,
+ 0x00760, 0x00761, 0x00762, 0x00763, 0x00764, 0x00765, 0x00766, 0x00767,
+ 0x00768, 0x00769, 0x0076a, 0x0076b, 0x0076c, 0x0076d, 0x0076e, 0x0076f,
+ 0x00770, 0x00771, 0x00772, 0x00773, 0x00774, 0x00775, 0x00776, 0x00777,
+ 0x00778, 0x00779, 0x0077a, 0x0077b, 0x0077c, 0x0077d, 0x0077e, 0x0077f,
+ 0x00780, 0x00781, 0x00782, 0x00783, 0x00784, 0x00785, 0x00786, 0x00787,
+ 0x00788, 0x00789, 0x0078a, 0x0078b, 0x0078c, 0x0078d, 0x0078e, 0x0078f,
+ 0x00790, 0x00791, 0x00792, 0x00793, 0x00794, 0x00795, 0x00796, 0x00797,
+ 0x00798, 0x00799, 0x0079a, 0x0079b, 0x0079c, 0x0079d, 0x0079e, 0x0079f,
+ 0x007a0, 0x007a1, 0x007a2, 0x007a3, 0x007a4, 0x007a5, 0x007a6, 0x007a7,
+ 0x007a8, 0x007a9, 0x007aa, 0x007ab, 0x007ac, 0x007ad, 0x007ae, 0x007af,
+ 0x007b0, 0x007b1, 0x007b2, 0x007b3, 0x007b4, 0x007b5, 0x007b6, 0x007b7,
+ 0x007b8, 0x007b9, 0x007ba, 0x007bb, 0x007bc, 0x007bd, 0x007be, 0x007bf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x007ca, 0x007cb, 0x007cc, 0x007cd, 0x007ce, 0x007cf,
+ 0x007d0, 0x007d1, 0x007d2, 0x007d3, 0x007d4, 0x007d5, 0x007d6, 0x007d7,
+ 0x007d8, 0x007d9, 0x007da, 0x007db, 0x007dc, 0x007dd, 0x007de, 0x007df,
+ 0x007e0, 0x007e1, 0x007e2, 0x007e3, 0x007e4, 0x007e5, 0x007e6, 0x007e7,
+ 0x007d6, 0x007d7, 0x007d9, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x007f4, 0x007f5, 0x007f6, 0x007f7,
+ 0x007f8, 0x007f9, 0x007fa, 0x007fb, 0x007fc, 0x007fd, 0x007fe, 0x007ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_08[] = {
+ 0x00800, 0x00801, 0x00802, 0x00803, 0x00804, 0x00805, 0x00806, 0x00807,
+ 0x00808, 0x00809, 0x0080a, 0x0080b, 0x0080c, 0x0080d, 0x0080e, 0x0080f,
+ 0x00810, 0x00811, 0x00812, 0x00813, 0x00814, 0x00815, 0x00816, 0x00817,
+ 0x00000, 0x00000, 0x0081a, 0x0081b, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0082e, 0x0082f,
+ 0x00830, 0x00831, 0x00832, 0x00833, 0x00834, 0x00835, 0x00836, 0x00837,
+ 0x00838, 0x00839, 0x0083a, 0x0083b, 0x0083c, 0x0083d, 0x0083e, 0x0083f,
+ 0x00840, 0x00841, 0x00842, 0x00843, 0x00844, 0x00845, 0x00846, 0x00847,
+ 0x00848, 0x00849, 0x0084a, 0x0084b, 0x0084c, 0x0084d, 0x0084e, 0x0084f,
+ 0x00850, 0x00851, 0x00852, 0x00853, 0x00854, 0x00855, 0x00856, 0x00857,
+ 0x00858, 0x00859, 0x0085a, 0x0085b, 0x0085c, 0x0085d, 0x0085e, 0x0085f,
+ 0x00860, 0x00861, 0x00862, 0x00863, 0x00864, 0x00865, 0x00866, 0x00867,
+ 0x00868, 0x00869, 0x0086a, 0x0086b, 0x0086c, 0x0086d, 0x0086e, 0x0086f,
+ 0x00870, 0x00871, 0x00872, 0x00873, 0x00874, 0x00875, 0x00876, 0x00877,
+ 0x00878, 0x00879, 0x0087a, 0x0087b, 0x0087c, 0x0087d, 0x0087e, 0x0087f,
+ 0x00880, 0x00881, 0x00882, 0x00883, 0x00884, 0x00885, 0x00886, 0x00887,
+ 0x00888, 0x00889, 0x0088a, 0x0088b, 0x0088c, 0x0088d, 0x0088e, 0x0088f,
+ 0x00890, 0x00891, 0x00892, 0x00893, 0x00894, 0x00895, 0x00896, 0x00897,
+ 0x00898, 0x00899, 0x0089a, 0x0089b, 0x0089c, 0x0089d, 0x0089e, 0x0089f,
+ 0x008a0, 0x008a1, 0x008a2, 0x008a3, 0x008a4, 0x008a5, 0x008a6, 0x008a7,
+ 0x008a8, 0x008a9, 0x008aa, 0x008ab, 0x008ac, 0x008ad, 0x008ae, 0x008af,
+ 0x008b0, 0x008b1, 0x008b2, 0x008b3, 0x008b4, 0x008b5, 0x008b6, 0x008b7,
+ 0x008b8, 0x008b9, 0x008ba, 0x008bb, 0x008bc, 0x008bd, 0x008be, 0x008bf,
+ 0x008c0, 0x008c1, 0x008c2, 0x008c3, 0x008c4, 0x008c5, 0x008c6, 0x008c7,
+ 0x008c8, 0x008c9, 0x008ca, 0x008cb, 0x008cc, 0x008cd, 0x008ce, 0x008cf,
+ 0x008d0, 0x008d1, 0x008d2, 0x008d3, 0x008d4, 0x008d5, 0x008d6, 0x008d7,
+ 0x008d8, 0x008d9, 0x008da, 0x008db, 0x008dc, 0x008dd, 0x008de, 0x008df,
+ 0x008e0, 0x008e1, 0x008e2, 0x008e3, 0x008e4, 0x008e5, 0x008e6, 0x008e7,
+ 0x008e8, 0x008e9, 0x008ea, 0x008eb, 0x008ec, 0x008ed, 0x008ee, 0x008ef,
+ 0x008f0, 0x008f1, 0x008f2, 0x008f3, 0x008f4, 0x008f5, 0x008f6, 0x008f7,
+ 0x008f8, 0x008f9, 0x008fa, 0x008fb, 0x008fc, 0x008fd, 0x008fe, 0x008ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_09[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00904, 0x00905, 0x00906, 0x00907,
+ 0x00908, 0x00909, 0x0090a, 0x0090b, 0x0090c, 0x0090d, 0x0090e, 0x0090f,
+ 0x00910, 0x00911, 0x00912, 0x00913, 0x00914, 0x00915, 0x00916, 0x00917,
+ 0x00918, 0x00919, 0x0091a, 0x0091b, 0x0091c, 0x0091d, 0x0091e, 0x0091f,
+ 0x00920, 0x00921, 0x00922, 0x00923, 0x00924, 0x00925, 0x00926, 0x00927,
+ 0x00928, 0x00928, 0x0092a, 0x0092b, 0x0092c, 0x0092d, 0x0092e, 0x0092f,
+ 0x00930, 0x00930, 0x00932, 0x00933, 0x00933, 0x00935, 0x00936, 0x00937,
+ 0x00938, 0x00939, 0x0093a, 0x0093b, 0x00000, 0x0093d, 0x0093e, 0x0093f,
+ 0x00940, 0x00941, 0x00942, 0x00943, 0x00944, 0x00945, 0x00946, 0x00947,
+ 0x00948, 0x00949, 0x0094a, 0x0094b, 0x0094c, 0x0094d, 0x0094e, 0x0094f,
+ 0x00950, 0x00000, 0x00000, 0x00000, 0x00000, 0x00955, 0x00956, 0x00957,
+ 0x00915, 0x00916, 0x00917, 0x0091c, 0x00921, 0x00922, 0x0092b, 0x0092f,
+ 0x00960, 0x00961, 0x00962, 0x00963, 0x00964, 0x00965, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00970, 0x00971, 0x00972, 0x00973, 0x00974, 0x00975, 0x00976, 0x00977,
+ 0x00978, 0x00979, 0x0097a, 0x0097b, 0x0097c, 0x0097d, 0x0097e, 0x0097f,
+ 0x00980, 0x00000, 0x00000, 0x00000, 0x00984, 0x00985, 0x00986, 0x00987,
+ 0x00988, 0x00989, 0x0098a, 0x0098b, 0x0098c, 0x0098d, 0x0098e, 0x0098f,
+ 0x00990, 0x00991, 0x00992, 0x00993, 0x00994, 0x00995, 0x00996, 0x00997,
+ 0x00998, 0x00999, 0x0099a, 0x0099b, 0x0099c, 0x0099d, 0x0099e, 0x0099f,
+ 0x009a0, 0x009a1, 0x009a2, 0x009a3, 0x009a4, 0x009a5, 0x009a6, 0x009a7,
+ 0x009a8, 0x009a9, 0x009aa, 0x009ab, 0x009ac, 0x009ad, 0x009ae, 0x009af,
+ 0x009b0, 0x009b1, 0x009b2, 0x009b3, 0x009b4, 0x009b5, 0x009b6, 0x009b7,
+ 0x009b8, 0x009b9, 0x009ba, 0x009bb, 0x00000, 0x009bd, 0x009be, 0x009bf,
+ 0x009c0, 0x009c1, 0x009c2, 0x009c3, 0x009c4, 0x009c5, 0x009c6, 0x009c7,
+ 0x009c8, 0x009c9, 0x009ca, 0x009cb, 0x009cc, 0x009cd, 0x009ce, 0x009cf,
+ 0x009d0, 0x009d1, 0x009d2, 0x009d3, 0x009d4, 0x009d5, 0x009d6, 0x009d7,
+ 0x009d8, 0x009d9, 0x009da, 0x009db, 0x009a1, 0x009a2, 0x009de, 0x009af,
+ 0x009e0, 0x009e1, 0x009e2, 0x009e3, 0x009e4, 0x009e5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x009f0, 0x009f1, 0x009f2, 0x009f3, 0x009f4, 0x009f5, 0x009f6, 0x009f7,
+ 0x009f8, 0x009f9, 0x009fa, 0x009fb, 0x009fc, 0x009fd, 0x009fe, 0x009ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0a[] = {
+ 0x00a00, 0x00000, 0x00000, 0x00000, 0x00a04, 0x00a05, 0x00a06, 0x00a07,
+ 0x00a08, 0x00a09, 0x00a0a, 0x00a0b, 0x00a0c, 0x00a0d, 0x00a0e, 0x00a0f,
+ 0x00a10, 0x00a11, 0x00a12, 0x00a13, 0x00a14, 0x00a15, 0x00a16, 0x00a17,
+ 0x00a18, 0x00a19, 0x00a1a, 0x00a1b, 0x00a1c, 0x00a1d, 0x00a1e, 0x00a1f,
+ 0x00a20, 0x00a21, 0x00a22, 0x00a23, 0x00a24, 0x00a25, 0x00a26, 0x00a27,
+ 0x00a28, 0x00a29, 0x00a2a, 0x00a2b, 0x00a2c, 0x00a2d, 0x00a2e, 0x00a2f,
+ 0x00a30, 0x00a31, 0x00a32, 0x00a32, 0x00a34, 0x00a35, 0x00a36, 0x00a37,
+ 0x00a36, 0x00a39, 0x00a3a, 0x00a3b, 0x00000, 0x00a3d, 0x00a3e, 0x00a3f,
+ 0x00a40, 0x00a41, 0x00a42, 0x00a43, 0x00a44, 0x00a45, 0x00a46, 0x00a47,
+ 0x00a48, 0x00a49, 0x00a4a, 0x00a4b, 0x00a4c, 0x00a4d, 0x00a4e, 0x00a4f,
+ 0x00a50, 0x00a51, 0x00a52, 0x00a53, 0x00a54, 0x00a55, 0x00a56, 0x00a57,
+ 0x00a58, 0x00a16, 0x00a17, 0x00a1c, 0x00a5c, 0x00a5d, 0x00a2b, 0x00a5f,
+ 0x00a60, 0x00a61, 0x00a62, 0x00a63, 0x00a64, 0x00a65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00000, 0x00000, 0x00a72, 0x00a73, 0x00a74, 0x00a75, 0x00a76, 0x00a77,
+ 0x00a78, 0x00a79, 0x00a7a, 0x00a7b, 0x00a7c, 0x00a7d, 0x00a7e, 0x00a7f,
+ 0x00a80, 0x00000, 0x00000, 0x00000, 0x00a84, 0x00a85, 0x00a86, 0x00a87,
+ 0x00a88, 0x00a89, 0x00a8a, 0x00a8b, 0x00a8c, 0x00a8d, 0x00a8e, 0x00a8f,
+ 0x00a90, 0x00a91, 0x00a92, 0x00a93, 0x00a94, 0x00a95, 0x00a96, 0x00a97,
+ 0x00a98, 0x00a99, 0x00a9a, 0x00a9b, 0x00a9c, 0x00a9d, 0x00a9e, 0x00a9f,
+ 0x00aa0, 0x00aa1, 0x00aa2, 0x00aa3, 0x00aa4, 0x00aa5, 0x00aa6, 0x00aa7,
+ 0x00aa8, 0x00aa9, 0x00aaa, 0x00aab, 0x00aac, 0x00aad, 0x00aae, 0x00aaf,
+ 0x00ab0, 0x00ab1, 0x00ab2, 0x00ab3, 0x00ab4, 0x00ab5, 0x00ab6, 0x00ab7,
+ 0x00ab8, 0x00ab9, 0x00aba, 0x00abb, 0x00000, 0x00abd, 0x00abe, 0x00abf,
+ 0x00ac0, 0x00ac1, 0x00ac2, 0x00ac3, 0x00ac4, 0x00ac5, 0x00ac6, 0x00ac7,
+ 0x00ac8, 0x00ac9, 0x00aca, 0x00acb, 0x00acc, 0x00acd, 0x00ace, 0x00acf,
+ 0x00ad0, 0x00ad1, 0x00ad2, 0x00ad3, 0x00ad4, 0x00ad5, 0x00ad6, 0x00ad7,
+ 0x00ad8, 0x00ad9, 0x00ada, 0x00adb, 0x00adc, 0x00add, 0x00ade, 0x00adf,
+ 0x00ae0, 0x00ae1, 0x00ae2, 0x00ae3, 0x00ae4, 0x00ae5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00af0, 0x00af1, 0x00af2, 0x00af3, 0x00af4, 0x00af5, 0x00af6, 0x00af7,
+ 0x00af8, 0x00af9, 0x00afa, 0x00afb, 0x00afc, 0x00afd, 0x00afe, 0x00aff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0b[] = {
+ 0x00b00, 0x00000, 0x00000, 0x00000, 0x00b04, 0x00b05, 0x00b06, 0x00b07,
+ 0x00b08, 0x00b09, 0x00b0a, 0x00b0b, 0x00b0c, 0x00b0d, 0x00b0e, 0x00b0f,
+ 0x00b10, 0x00b11, 0x00b12, 0x00b13, 0x00b14, 0x00b15, 0x00b16, 0x00b17,
+ 0x00b18, 0x00b19, 0x00b1a, 0x00b1b, 0x00b1c, 0x00b1d, 0x00b1e, 0x00b1f,
+ 0x00b20, 0x00b21, 0x00b22, 0x00b23, 0x00b24, 0x00b25, 0x00b26, 0x00b27,
+ 0x00b28, 0x00b29, 0x00b2a, 0x00b2b, 0x00b2c, 0x00b2d, 0x00b2e, 0x00b2f,
+ 0x00b30, 0x00b31, 0x00b32, 0x00b33, 0x00b34, 0x00b35, 0x00b36, 0x00b37,
+ 0x00b38, 0x00b39, 0x00b3a, 0x00b3b, 0x00000, 0x00b3d, 0x00b3e, 0x00b3f,
+ 0x00b40, 0x00b41, 0x00b42, 0x00b43, 0x00b44, 0x00b45, 0x00b46, 0x00b47,
+ 0x00b48, 0x00b49, 0x00b4a, 0x00b4b, 0x00b4c, 0x00b4d, 0x00b4e, 0x00b4f,
+ 0x00b50, 0x00b51, 0x00b52, 0x00b53, 0x00b54, 0x00b55, 0x00b56, 0x00b57,
+ 0x00b58, 0x00b59, 0x00b5a, 0x00b5b, 0x00b21, 0x00b22, 0x00b5e, 0x00b5f,
+ 0x00b60, 0x00b61, 0x00b62, 0x00b63, 0x00b64, 0x00b65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00b70, 0x00b71, 0x00b72, 0x00b73, 0x00b74, 0x00b75, 0x00b76, 0x00b77,
+ 0x00b78, 0x00b79, 0x00b7a, 0x00b7b, 0x00b7c, 0x00b7d, 0x00b7e, 0x00b7f,
+ 0x00b80, 0x00b81, 0x00000, 0x00b83, 0x00b84, 0x00b85, 0x00b86, 0x00b87,
+ 0x00b88, 0x00b89, 0x00b8a, 0x00b8b, 0x00b8c, 0x00b8d, 0x00b8e, 0x00b8f,
+ 0x00b90, 0x00b91, 0x00b92, 0x00b93, 0x00b94, 0x00b95, 0x00b96, 0x00b97,
+ 0x00b98, 0x00b99, 0x00b9a, 0x00b9b, 0x00b9c, 0x00b9d, 0x00b9e, 0x00b9f,
+ 0x00ba0, 0x00ba1, 0x00ba2, 0x00ba3, 0x00ba4, 0x00ba5, 0x00ba6, 0x00ba7,
+ 0x00ba8, 0x00ba9, 0x00baa, 0x00bab, 0x00bac, 0x00bad, 0x00bae, 0x00baf,
+ 0x00bb0, 0x00bb1, 0x00bb2, 0x00bb3, 0x00bb4, 0x00bb5, 0x00bb6, 0x00bb7,
+ 0x00bb8, 0x00bb9, 0x00bba, 0x00bbb, 0x00bbc, 0x00bbd, 0x00bbe, 0x00bbf,
+ 0x00bc0, 0x00bc1, 0x00bc2, 0x00bc3, 0x00bc4, 0x00bc5, 0x00bc6, 0x00bc7,
+ 0x00bc8, 0x00bc9, 0x00bca, 0x00bcb, 0x00bcc, 0x00bcd, 0x00bce, 0x00bcf,
+ 0x00bd0, 0x00bd1, 0x00bd2, 0x00bd3, 0x00bd4, 0x00bd5, 0x00bd6, 0x00bd7,
+ 0x00bd8, 0x00bd9, 0x00bda, 0x00bdb, 0x00bdc, 0x00bdd, 0x00bde, 0x00bdf,
+ 0x00be0, 0x00be1, 0x00be2, 0x00be3, 0x00be4, 0x00be5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00bf0, 0x00bf1, 0x00bf2, 0x00bf3, 0x00bf4, 0x00bf5, 0x00bf6, 0x00bf7,
+ 0x00bf8, 0x00bf9, 0x00bfa, 0x00bfb, 0x00bfc, 0x00bfd, 0x00bfe, 0x00bff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0c[] = {
+ 0x00c00, 0x00000, 0x00000, 0x00000, 0x00c04, 0x00c05, 0x00c06, 0x00c07,
+ 0x00c08, 0x00c09, 0x00c0a, 0x00c0b, 0x00c0c, 0x00c0d, 0x00c0e, 0x00c0f,
+ 0x00c10, 0x00c11, 0x00c12, 0x00c13, 0x00c14, 0x00c15, 0x00c16, 0x00c17,
+ 0x00c18, 0x00c19, 0x00c1a, 0x00c1b, 0x00c1c, 0x00c1d, 0x00c1e, 0x00c1f,
+ 0x00c20, 0x00c21, 0x00c22, 0x00c23, 0x00c24, 0x00c25, 0x00c26, 0x00c27,
+ 0x00c28, 0x00c29, 0x00c2a, 0x00c2b, 0x00c2c, 0x00c2d, 0x00c2e, 0x00c2f,
+ 0x00c30, 0x00c31, 0x00c32, 0x00c33, 0x00c34, 0x00c35, 0x00c36, 0x00c37,
+ 0x00c38, 0x00c39, 0x00c3a, 0x00c3b, 0x00c3c, 0x00c3d, 0x00c3e, 0x00c3f,
+ 0x00c40, 0x00c41, 0x00c42, 0x00c43, 0x00c44, 0x00c45, 0x00c46, 0x00c47,
+ 0x00c48, 0x00c49, 0x00c4a, 0x00c4b, 0x00c4c, 0x00c4d, 0x00c4e, 0x00c4f,
+ 0x00c50, 0x00c51, 0x00c52, 0x00c53, 0x00c54, 0x00c55, 0x00c56, 0x00c57,
+ 0x00c58, 0x00c59, 0x00c5a, 0x00c5b, 0x00c5c, 0x00c5d, 0x00c5e, 0x00c5f,
+ 0x00c60, 0x00c61, 0x00c62, 0x00c63, 0x00c64, 0x00c65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00c70, 0x00c71, 0x00c72, 0x00c73, 0x00c74, 0x00c75, 0x00c76, 0x00c77,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00031, 0x00032, 0x00033, 0x00c7f,
+ 0x00c80, 0x00c81, 0x00000, 0x00000, 0x00c84, 0x00c85, 0x00c86, 0x00c87,
+ 0x00c88, 0x00c89, 0x00c8a, 0x00c8b, 0x00c8c, 0x00c8d, 0x00c8e, 0x00c8f,
+ 0x00c90, 0x00c91, 0x00c92, 0x00c93, 0x00c94, 0x00c95, 0x00c96, 0x00c97,
+ 0x00c98, 0x00c99, 0x00c9a, 0x00c9b, 0x00c9c, 0x00c9d, 0x00c9e, 0x00c9f,
+ 0x00ca0, 0x00ca1, 0x00ca2, 0x00ca3, 0x00ca4, 0x00ca5, 0x00ca6, 0x00ca7,
+ 0x00ca8, 0x00ca9, 0x00caa, 0x00cab, 0x00cac, 0x00cad, 0x00cae, 0x00caf,
+ 0x00cb0, 0x00cb1, 0x00cb2, 0x00cb3, 0x00cb4, 0x00cb5, 0x00cb6, 0x00cb7,
+ 0x00cb8, 0x00cb9, 0x00cba, 0x00cbb, 0x00000, 0x00cbd, 0x00cbe, 0x00cbf,
+ 0x00cc0, 0x00cc1, 0x00cc2, 0x00cc3, 0x00cc4, 0x00cc5, 0x00cc6, 0x00cc7,
+ 0x00cc8, 0x00cc9, 0x00cca, 0x00ccb, 0x00ccc, 0x00ccd, 0x00cce, 0x00ccf,
+ 0x00cd0, 0x00cd1, 0x00cd2, 0x00cd3, 0x00cd4, 0x00cd5, 0x00cd6, 0x00cd7,
+ 0x00cd8, 0x00cd9, 0x00cda, 0x00cdb, 0x00cdc, 0x00cdd, 0x00cde, 0x00cdf,
+ 0x00ce0, 0x00ce1, 0x00ce2, 0x00ce3, 0x00ce4, 0x00ce5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00cf0, 0x00cf1, 0x00cf2, 0x00cf3, 0x00cf4, 0x00cf5, 0x00cf6, 0x00cf7,
+ 0x00cf8, 0x00cf9, 0x00cfa, 0x00cfb, 0x00cfc, 0x00cfd, 0x00cfe, 0x00cff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0d[] = {
+ 0x00d00, 0x00d01, 0x00000, 0x00000, 0x00d04, 0x00d05, 0x00d06, 0x00d07,
+ 0x00d08, 0x00d09, 0x00d0a, 0x00d0b, 0x00d0c, 0x00d0d, 0x00d0e, 0x00d0f,
+ 0x00d10, 0x00d11, 0x00d12, 0x00d13, 0x00d14, 0x00d15, 0x00d16, 0x00d17,
+ 0x00d18, 0x00d19, 0x00d1a, 0x00d1b, 0x00d1c, 0x00d1d, 0x00d1e, 0x00d1f,
+ 0x00d20, 0x00d21, 0x00d22, 0x00d23, 0x00d24, 0x00d25, 0x00d26, 0x00d27,
+ 0x00d28, 0x00d29, 0x00d2a, 0x00d2b, 0x00d2c, 0x00d2d, 0x00d2e, 0x00d2f,
+ 0x00d30, 0x00d31, 0x00d32, 0x00d33, 0x00d34, 0x00d35, 0x00d36, 0x00d37,
+ 0x00d38, 0x00d39, 0x00d3a, 0x00d3b, 0x00d3c, 0x00d3d, 0x00d3e, 0x00d3f,
+ 0x00d40, 0x00d41, 0x00d42, 0x00d43, 0x00d44, 0x00d45, 0x00d46, 0x00d47,
+ 0x00d48, 0x00d49, 0x00d4a, 0x00d4b, 0x00d4c, 0x00d4d, 0x00d4e, 0x00d4f,
+ 0x00d50, 0x00d51, 0x00d52, 0x00d53, 0x00d54, 0x00d55, 0x00d56, 0x00d57,
+ 0x00d58, 0x00d59, 0x00d5a, 0x00d5b, 0x00d5c, 0x00d5d, 0x00d5e, 0x00d5f,
+ 0x00d60, 0x00d61, 0x00d62, 0x00d63, 0x00d64, 0x00d65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00d70, 0x00d71, 0x00d72, 0x00d73, 0x00d74, 0x00d75, 0x00d76, 0x00d77,
+ 0x00d78, 0x00d79, 0x00d7a, 0x00d7b, 0x00d7c, 0x00d7d, 0x00d7e, 0x00d7f,
+ 0x00d80, 0x00d81, 0x00000, 0x00000, 0x00d84, 0x00d85, 0x00d86, 0x00d87,
+ 0x00d88, 0x00d89, 0x00d8a, 0x00d8b, 0x00d8c, 0x00d8d, 0x00d8e, 0x00d8f,
+ 0x00d90, 0x00d91, 0x00d92, 0x00d93, 0x00d94, 0x00d95, 0x00d96, 0x00d97,
+ 0x00d98, 0x00d99, 0x00d9a, 0x00d9b, 0x00d9c, 0x00d9d, 0x00d9e, 0x00d9f,
+ 0x00da0, 0x00da1, 0x00da2, 0x00da3, 0x00da4, 0x00da5, 0x00da6, 0x00da7,
+ 0x00da8, 0x00da9, 0x00daa, 0x00dab, 0x00dac, 0x00dad, 0x00dae, 0x00daf,
+ 0x00db0, 0x00db1, 0x00db2, 0x00db3, 0x00db4, 0x00db5, 0x00db6, 0x00db7,
+ 0x00db8, 0x00db9, 0x00dba, 0x00dbb, 0x00dbc, 0x00dbd, 0x00dbe, 0x00dbf,
+ 0x00dc0, 0x00dc1, 0x00dc2, 0x00dc3, 0x00dc4, 0x00dc5, 0x00dc6, 0x00dc7,
+ 0x00dc8, 0x00dc9, 0x00dca, 0x00dcb, 0x00dcc, 0x00dcd, 0x00dce, 0x00dcf,
+ 0x00dd0, 0x00dd1, 0x00dd2, 0x00dd3, 0x00dd4, 0x00dd5, 0x00dd6, 0x00dd7,
+ 0x00dd8, 0x00dd9, 0x00dda, 0x00ddb, 0x00ddc, 0x00ddd, 0x00dde, 0x00ddf,
+ 0x00de0, 0x00de1, 0x00de2, 0x00de3, 0x00de4, 0x00de5, 0x00de6, 0x00de7,
+ 0x00de8, 0x00de9, 0x00dea, 0x00deb, 0x00dec, 0x00ded, 0x00dee, 0x00def,
+ 0x00df0, 0x00df1, 0x00df2, 0x00df3, 0x00df4, 0x00df5, 0x00df6, 0x00df7,
+ 0x00df8, 0x00df9, 0x00dfa, 0x00dfb, 0x00dfc, 0x00dfd, 0x00dfe, 0x00dff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0e[] = {
+ 0x00e00, 0x00e01, 0x00e02, 0x00e03, 0x00e04, 0x00e05, 0x00e06, 0x00e07,
+ 0x00e08, 0x00e09, 0x00e0a, 0x00e0b, 0x00e0c, 0x00e0d, 0x00e0e, 0x00e0f,
+ 0x00e10, 0x00e11, 0x00e12, 0x00e13, 0x00e14, 0x00e15, 0x00e16, 0x00e17,
+ 0x00e18, 0x00e19, 0x00e1a, 0x00e1b, 0x00e1c, 0x00e1d, 0x00e1e, 0x00e1f,
+ 0x00e20, 0x00e21, 0x00e22, 0x00e23, 0x00e24, 0x00e25, 0x00e26, 0x00e27,
+ 0x00e28, 0x00e29, 0x00e2a, 0x00e2b, 0x00e2c, 0x00e2d, 0x00e2e, 0x00e2f,
+ 0x00e30, 0x00e31, 0x00e32, 0x00e33, 0x00e34, 0x00e35, 0x00e36, 0x00e37,
+ 0x00e38, 0x00e39, 0x00e3a, 0x00e3b, 0x00e3c, 0x00e3d, 0x00e3e, 0x00e3f,
+ 0x00e40, 0x00e41, 0x00e42, 0x00e43, 0x00e44, 0x00e45, 0x00e46, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00e4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00e5a, 0x00e5b, 0x00e5c, 0x00e5d, 0x00e5e, 0x00e5f,
+ 0x00e60, 0x00e61, 0x00e62, 0x00e63, 0x00e64, 0x00e65, 0x00e66, 0x00e67,
+ 0x00e68, 0x00e69, 0x00e6a, 0x00e6b, 0x00e6c, 0x00e6d, 0x00e6e, 0x00e6f,
+ 0x00e70, 0x00e71, 0x00e72, 0x00e73, 0x00e74, 0x00e75, 0x00e76, 0x00e77,
+ 0x00e78, 0x00e79, 0x00e7a, 0x00e7b, 0x00e7c, 0x00e7d, 0x00e7e, 0x00e7f,
+ 0x00e80, 0x00e81, 0x00e82, 0x00e83, 0x00e84, 0x00e85, 0x00e86, 0x00e87,
+ 0x00e88, 0x00e89, 0x00e8a, 0x00e8b, 0x00e8c, 0x00e8d, 0x00e8e, 0x00e8f,
+ 0x00e90, 0x00e91, 0x00e92, 0x00e93, 0x00e94, 0x00e95, 0x00e96, 0x00e97,
+ 0x00e98, 0x00e99, 0x00e9a, 0x00e9b, 0x00e9c, 0x00e9d, 0x00e9e, 0x00e9f,
+ 0x00ea0, 0x00ea1, 0x00ea2, 0x00ea3, 0x00ea4, 0x00ea5, 0x00ea6, 0x00ea7,
+ 0x00ea8, 0x00ea9, 0x00eaa, 0x00eab, 0x00eac, 0x00ead, 0x00eae, 0x00eaf,
+ 0x00eb0, 0x00eb1, 0x00eb2, 0x00eb3, 0x00eb4, 0x00eb5, 0x00eb6, 0x00eb7,
+ 0x00eb8, 0x00eb9, 0x00eba, 0x00ebb, 0x00ebc, 0x00ebd, 0x00ebe, 0x00ebf,
+ 0x00ec0, 0x00ec1, 0x00ec2, 0x00ec3, 0x00ec4, 0x00ec5, 0x00ec6, 0x00ec7,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00ece, 0x00ecf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00eda, 0x00edb, 0x00edc, 0x00edd, 0x00ede, 0x00edf,
+ 0x00ee0, 0x00ee1, 0x00ee2, 0x00ee3, 0x00ee4, 0x00ee5, 0x00ee6, 0x00ee7,
+ 0x00ee8, 0x00ee9, 0x00eea, 0x00eeb, 0x00eec, 0x00eed, 0x00eee, 0x00eef,
+ 0x00ef0, 0x00ef1, 0x00ef2, 0x00ef3, 0x00ef4, 0x00ef5, 0x00ef6, 0x00ef7,
+ 0x00ef8, 0x00ef9, 0x00efa, 0x00efb, 0x00efc, 0x00efd, 0x00efe, 0x00eff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0f[] = {
+ 0x00f00, 0x00f01, 0x00f02, 0x00f03, 0x00f04, 0x00f05, 0x00f06, 0x00f07,
+ 0x00f08, 0x00f09, 0x00f0a, 0x00f0b, 0x00f0b, 0x00f0d, 0x00f0e, 0x00f0f,
+ 0x00f10, 0x00f11, 0x00f12, 0x00f13, 0x00f14, 0x00f15, 0x00f16, 0x00f17,
+ 0x00000, 0x00000, 0x00f1a, 0x00f1b, 0x00f1c, 0x00f1d, 0x00f1e, 0x00f1f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x00030, 0x00f34, 0x00000, 0x00f36, 0x00000,
+ 0x00f38, 0x00000, 0x00f3a, 0x00f3b, 0x00f3c, 0x00f3d, 0x00f3e, 0x00f3f,
+ 0x00f40, 0x00f41, 0x00f42, 0x00f43, 0x00f44, 0x00f45, 0x00f46, 0x00f47,
+ 0x00f48, 0x00f49, 0x00f4a, 0x00f4b, 0x00f4c, 0x00f4d, 0x00f4e, 0x00f4f,
+ 0x00f50, 0x00f51, 0x00f52, 0x00f53, 0x00f54, 0x00f55, 0x00f56, 0x00f57,
+ 0x00f58, 0x00f59, 0x00f5a, 0x00f5b, 0x00f5c, 0x00f5d, 0x00f5e, 0x00f5f,
+ 0x00f60, 0x00f61, 0x00f62, 0x00f63, 0x00f64, 0x00f65, 0x00f66, 0x00f67,
+ 0x00f68, 0x00f69, 0x00f62, 0x00f6b, 0x00f6c, 0x00f6d, 0x00f6e, 0x00f6f,
+ 0x00f70, 0x00f71, 0x00f72, 0x00f73, 0x00f74, 0x00f75, 0x00f76, 0x00f77,
+ 0x00f78, 0x00f79, 0x00f7a, 0x00f7b, 0x00f7c, 0x00f7d, 0x00000, 0x00000,
+ 0x00f80, 0x00f81, 0x00000, 0x00000, 0x00f84, 0x00f85, 0x00000, 0x00000,
+ 0x00f88, 0x00f89, 0x00f8a, 0x00f8b, 0x00f8c, 0x00f8d, 0x00f8e, 0x00f8f,
+ 0x00f90, 0x00f91, 0x00f92, 0x00f93, 0x00f94, 0x00f95, 0x00f96, 0x00f97,
+ 0x00f98, 0x00f99, 0x00f9a, 0x00f9b, 0x00f9c, 0x00f9d, 0x00f9e, 0x00f9f,
+ 0x00fa0, 0x00fa1, 0x00fa2, 0x00fa3, 0x00fa4, 0x00fa5, 0x00fa6, 0x00fa7,
+ 0x00fa8, 0x00fa9, 0x00faa, 0x00fab, 0x00fac, 0x00fad, 0x00fae, 0x00faf,
+ 0x00fb0, 0x00fb1, 0x00fb2, 0x00fb3, 0x00fb4, 0x00fb5, 0x00fb6, 0x00fb7,
+ 0x00fb8, 0x00fb9, 0x00fad, 0x00fb1, 0x00fb2, 0x00fbd, 0x00fbe, 0x00fbf,
+ 0x00fc0, 0x00fc1, 0x00fc2, 0x00fc3, 0x00fc4, 0x00fc5, 0x00000, 0x00fc7,
+ 0x00fc8, 0x00fc9, 0x00fca, 0x00fcb, 0x00fcc, 0x00fcd, 0x00fce, 0x00fcf,
+ 0x00fd0, 0x00fd1, 0x00fd2, 0x00fd3, 0x00fd4, 0x00fd5, 0x00fd6, 0x00fd7,
+ 0x00fd8, 0x00fd9, 0x00fda, 0x00fdb, 0x00fdc, 0x00fdd, 0x00fde, 0x00fdf,
+ 0x00fe0, 0x00fe1, 0x00fe2, 0x00fe3, 0x00fe4, 0x00fe5, 0x00fe6, 0x00fe7,
+ 0x00fe8, 0x00fe9, 0x00fea, 0x00feb, 0x00fec, 0x00fed, 0x00fee, 0x00fef,
+ 0x00ff0, 0x00ff1, 0x00ff2, 0x00ff3, 0x00ff4, 0x00ff5, 0x00ff6, 0x00ff7,
+ 0x00ff8, 0x00ff9, 0x00ffa, 0x00ffb, 0x00ffc, 0x00ffd, 0x00ffe, 0x00fff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10[] = {
+ 0x01000, 0x01001, 0x01002, 0x01003, 0x01004, 0x01005, 0x01006, 0x01007,
+ 0x01008, 0x01009, 0x0100a, 0x0100b, 0x0100c, 0x0100d, 0x0100e, 0x0100f,
+ 0x01010, 0x01011, 0x01012, 0x01013, 0x01014, 0x01015, 0x01016, 0x01017,
+ 0x01018, 0x01019, 0x0101a, 0x0101b, 0x0101c, 0x0101d, 0x0101e, 0x0101f,
+ 0x01020, 0x01021, 0x01022, 0x01023, 0x01024, 0x01025, 0x01026, 0x01027,
+ 0x01028, 0x01029, 0x0102a, 0x0102b, 0x0102b, 0x0102d, 0x0102e, 0x0102f,
+ 0x01030, 0x01031, 0x01032, 0x01033, 0x01034, 0x01035, 0x00000, 0x00000,
+ 0x00000, 0x01039, 0x0103a, 0x0103b, 0x0103c, 0x0103d, 0x0103e, 0x0103f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0104a, 0x0104b, 0x0104c, 0x0104d, 0x0104e, 0x0104f,
+ 0x01050, 0x01051, 0x01052, 0x01053, 0x01054, 0x01055, 0x01056, 0x01057,
+ 0x01058, 0x01059, 0x0105a, 0x0105b, 0x0105c, 0x0105d, 0x0105e, 0x0105f,
+ 0x01060, 0x01061, 0x01062, 0x01063, 0x01064, 0x01065, 0x01066, 0x01067,
+ 0x01068, 0x01069, 0x0106a, 0x0106b, 0x0106c, 0x0106d, 0x0106e, 0x0106f,
+ 0x01070, 0x01071, 0x01072, 0x01073, 0x01074, 0x01075, 0x01076, 0x01077,
+ 0x01078, 0x01079, 0x0107a, 0x0107b, 0x0107c, 0x0107d, 0x0107e, 0x0107f,
+ 0x01080, 0x01081, 0x01082, 0x01083, 0x01084, 0x01085, 0x01086, 0x01087,
+ 0x01088, 0x01089, 0x0108a, 0x0108b, 0x0108c, 0x00000, 0x0108e, 0x0108f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0109a, 0x0109b, 0x0109c, 0x0109d, 0x0109e, 0x0109f,
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x010c6, 0x010c7,
+ 0x010c8, 0x010c9, 0x010ca, 0x010cb, 0x010cc, 0x010cd, 0x010ce, 0x010cf,
+ 0x010d0, 0x010d1, 0x010d2, 0x010d3, 0x010d4, 0x010d5, 0x010d6, 0x010d7,
+ 0x010d8, 0x010d9, 0x010da, 0x010db, 0x010dc, 0x010dd, 0x010de, 0x010df,
+ 0x010e0, 0x010e1, 0x010e2, 0x010e3, 0x010e4, 0x010e5, 0x010e6, 0x010e7,
+ 0x010e8, 0x010e9, 0x010ea, 0x010eb, 0x010ec, 0x010ed, 0x010ee, 0x010ef,
+ 0x010f0, 0x010f1, 0x010f2, 0x010f3, 0x010f4, 0x010f5, 0x010f6, 0x010f7,
+ 0x010f8, 0x010f9, 0x010fa, 0x010fb, 0x010dc, 0x010fd, 0x010fe, 0x010ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_13[] = {
+ 0x01300, 0x01301, 0x01302, 0x01303, 0x01304, 0x01305, 0x01306, 0x01307,
+ 0x01308, 0x01309, 0x0130a, 0x0130b, 0x0130c, 0x0130d, 0x0130e, 0x0130f,
+ 0x01310, 0x01311, 0x01312, 0x01313, 0x01314, 0x01315, 0x01316, 0x01317,
+ 0x01318, 0x01319, 0x0131a, 0x0131b, 0x0131c, 0x0131d, 0x0131e, 0x0131f,
+ 0x01320, 0x01321, 0x01322, 0x01323, 0x01324, 0x01325, 0x01326, 0x01327,
+ 0x01328, 0x01329, 0x0132a, 0x0132b, 0x0132c, 0x0132d, 0x0132e, 0x0132f,
+ 0x01330, 0x01331, 0x01332, 0x01333, 0x01334, 0x01335, 0x01336, 0x01337,
+ 0x01338, 0x01339, 0x0133a, 0x0133b, 0x0133c, 0x0133d, 0x0133e, 0x0133f,
+ 0x01340, 0x01341, 0x01342, 0x01343, 0x01344, 0x01345, 0x01346, 0x01347,
+ 0x01348, 0x01349, 0x0134a, 0x0134b, 0x0134c, 0x0134d, 0x0134e, 0x0134f,
+ 0x01350, 0x01351, 0x01352, 0x01353, 0x01354, 0x01355, 0x01356, 0x01357,
+ 0x01358, 0x01359, 0x0135a, 0x0135b, 0x0135c, 0x0135d, 0x0135e, 0x00000,
+ 0x01360, 0x01361, 0x01362, 0x01363, 0x01364, 0x01365, 0x01366, 0x01367,
+ 0x01368, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01372, 0x01373, 0x01374, 0x01375, 0x01376, 0x01377,
+ 0x01378, 0x01379, 0x0137a, 0x0137b, 0x0137c, 0x0137d, 0x0137e, 0x0137f,
+ 0x01380, 0x01381, 0x01382, 0x01383, 0x01384, 0x01385, 0x01386, 0x01387,
+ 0x01388, 0x01389, 0x0138a, 0x0138b, 0x0138c, 0x0138d, 0x0138e, 0x0138f,
+ 0x01390, 0x01391, 0x01392, 0x01393, 0x01394, 0x01395, 0x01396, 0x01397,
+ 0x01398, 0x01399, 0x0139a, 0x0139b, 0x0139c, 0x0139d, 0x0139e, 0x0139f,
+ 0x013a0, 0x013a1, 0x013a2, 0x013a3, 0x013a4, 0x013a5, 0x013a6, 0x013a7,
+ 0x013a8, 0x013a9, 0x013aa, 0x013ab, 0x013ac, 0x013ad, 0x013ae, 0x013af,
+ 0x013b0, 0x013b1, 0x013b2, 0x013b3, 0x013b4, 0x013b5, 0x013b6, 0x013b7,
+ 0x013b8, 0x013b9, 0x013ba, 0x013bb, 0x013bc, 0x013bd, 0x013be, 0x013bf,
+ 0x013c0, 0x013c1, 0x013c2, 0x013c3, 0x013c4, 0x013c5, 0x013c6, 0x013c7,
+ 0x013c8, 0x013c9, 0x013ca, 0x013cb, 0x013cc, 0x013cd, 0x013ce, 0x013cf,
+ 0x013d0, 0x013d1, 0x013d2, 0x013d3, 0x013d4, 0x013d5, 0x013d6, 0x013d7,
+ 0x013d8, 0x013d9, 0x013da, 0x013db, 0x013dc, 0x013dd, 0x013de, 0x013df,
+ 0x013e0, 0x013e1, 0x013e2, 0x013e3, 0x013e4, 0x013e5, 0x013e6, 0x013e7,
+ 0x013e8, 0x013e9, 0x013ea, 0x013eb, 0x013ec, 0x013ed, 0x013ee, 0x013ef,
+ 0x013f0, 0x013f1, 0x013f2, 0x013f3, 0x013f4, 0x013f5, 0x013f6, 0x013f7,
+ 0x013f8, 0x013f9, 0x013fa, 0x013fb, 0x013fc, 0x013fd, 0x013fe, 0x013ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_16[] = {
+ 0x01600, 0x01601, 0x01602, 0x01603, 0x01604, 0x01605, 0x01606, 0x01607,
+ 0x01608, 0x01609, 0x0160a, 0x0160b, 0x0160c, 0x0160d, 0x0160e, 0x0160f,
+ 0x01610, 0x01611, 0x01612, 0x01613, 0x01614, 0x01615, 0x01616, 0x01617,
+ 0x01618, 0x01619, 0x0161a, 0x0161b, 0x0161c, 0x0161d, 0x0161e, 0x0161f,
+ 0x01620, 0x01621, 0x01622, 0x01623, 0x01624, 0x01625, 0x01626, 0x01627,
+ 0x01628, 0x01629, 0x0162a, 0x0162b, 0x0162c, 0x0162d, 0x0162e, 0x0162f,
+ 0x01630, 0x01631, 0x01632, 0x01633, 0x01634, 0x01635, 0x01636, 0x01637,
+ 0x01638, 0x01639, 0x0163a, 0x0163b, 0x0163c, 0x0163d, 0x0163e, 0x0163f,
+ 0x01640, 0x01641, 0x01642, 0x01643, 0x01644, 0x01645, 0x01646, 0x01647,
+ 0x01648, 0x01649, 0x0164a, 0x0164b, 0x0164c, 0x0164d, 0x0164e, 0x0164f,
+ 0x01650, 0x01651, 0x01652, 0x01653, 0x01654, 0x01655, 0x01656, 0x01657,
+ 0x01658, 0x01659, 0x0165a, 0x0165b, 0x0165c, 0x0165d, 0x0165e, 0x0165f,
+ 0x01660, 0x01661, 0x01662, 0x01663, 0x01664, 0x01665, 0x01666, 0x01667,
+ 0x01668, 0x01669, 0x0166a, 0x0166b, 0x0166c, 0x0166d, 0x0166e, 0x0166f,
+ 0x01670, 0x01671, 0x01672, 0x01673, 0x01674, 0x01675, 0x01676, 0x01677,
+ 0x01678, 0x01679, 0x0167a, 0x0167b, 0x0167c, 0x0167d, 0x0167e, 0x0167f,
+ 0x01680, 0x01681, 0x01682, 0x01683, 0x01684, 0x01685, 0x01686, 0x01687,
+ 0x01688, 0x01689, 0x0168a, 0x0168b, 0x0168c, 0x0168d, 0x0168e, 0x0168f,
+ 0x01690, 0x01691, 0x01692, 0x01693, 0x01694, 0x01695, 0x01696, 0x01697,
+ 0x01698, 0x01699, 0x0169a, 0x0169b, 0x0169c, 0x0169d, 0x0169e, 0x0169f,
+ 0x016a0, 0x016a0, 0x016a2, 0x016a3, 0x016a2, 0x016a2, 0x016a6, 0x016a6,
+ 0x016a8, 0x016a8, 0x016aa, 0x016ab, 0x016a8, 0x016a8, 0x016a8, 0x016af,
+ 0x016b0, 0x016b1, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b7,
+ 0x016b8, 0x016b9, 0x016ba, 0x016ba, 0x016ba, 0x016ba, 0x016be, 0x016be,
+ 0x016be, 0x016c1, 0x016c1, 0x016c3, 0x016c3, 0x016c5, 0x016c5, 0x016c7,
+ 0x016c8, 0x016c9, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016cf,
+ 0x016cf, 0x016cf, 0x016d2, 0x016d2, 0x016d2, 0x016c8, 0x016d6, 0x016d7,
+ 0x016d7, 0x016d7, 0x016da, 0x016da, 0x016dc, 0x016dc, 0x016de, 0x016df,
+ 0x016e0, 0x016e1, 0x016e2, 0x016e3, 0x016e4, 0x016e5, 0x016e6, 0x016e6,
+ 0x016e6, 0x016b9, 0x016ca, 0x016eb, 0x016ec, 0x016ed, 0x016ee, 0x016ef,
+ 0x016f0, 0x016f1, 0x016f2, 0x016f3, 0x016f4, 0x016f5, 0x016f6, 0x016f7,
+ 0x016f8, 0x016f9, 0x016fa, 0x016fb, 0x016fc, 0x016fd, 0x016fe, 0x016ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_17[] = {
+ 0x01700, 0x01701, 0x01702, 0x01703, 0x01704, 0x01705, 0x01706, 0x01707,
+ 0x01708, 0x01709, 0x0170a, 0x0170b, 0x0170c, 0x0170d, 0x0170e, 0x0170f,
+ 0x01710, 0x01711, 0x01712, 0x01713, 0x01714, 0x01715, 0x01716, 0x01717,
+ 0x01718, 0x01719, 0x0171a, 0x0171b, 0x0171c, 0x0171d, 0x0171e, 0x0171f,
+ 0x01720, 0x01721, 0x01722, 0x01723, 0x01724, 0x01725, 0x01726, 0x01727,
+ 0x01728, 0x01729, 0x0172a, 0x0172b, 0x0172c, 0x0172d, 0x0172e, 0x0172f,
+ 0x01730, 0x01731, 0x01732, 0x01733, 0x01734, 0x01735, 0x01736, 0x01737,
+ 0x01738, 0x01739, 0x0173a, 0x0173b, 0x0173c, 0x0173d, 0x0173e, 0x0173f,
+ 0x01740, 0x01741, 0x01742, 0x01743, 0x01744, 0x01745, 0x01746, 0x01747,
+ 0x01748, 0x01749, 0x0174a, 0x0174b, 0x0174c, 0x0174d, 0x0174e, 0x0174f,
+ 0x01750, 0x01751, 0x01752, 0x01753, 0x01754, 0x01755, 0x01756, 0x01757,
+ 0x01758, 0x01759, 0x0175a, 0x0175b, 0x0175c, 0x0175d, 0x0175e, 0x0175f,
+ 0x01760, 0x01761, 0x01762, 0x01763, 0x01764, 0x01765, 0x01766, 0x01767,
+ 0x01768, 0x01769, 0x0176a, 0x0176b, 0x0176c, 0x0176d, 0x0176e, 0x0176f,
+ 0x01770, 0x01771, 0x01772, 0x01773, 0x01774, 0x01775, 0x01776, 0x01777,
+ 0x01778, 0x01779, 0x0177a, 0x0177b, 0x0177c, 0x0177d, 0x0177e, 0x0177f,
+ 0x01780, 0x01781, 0x01782, 0x01783, 0x01784, 0x01785, 0x01786, 0x01787,
+ 0x01788, 0x01789, 0x0178a, 0x0178b, 0x0178c, 0x0178d, 0x0178e, 0x0178f,
+ 0x01790, 0x01791, 0x01792, 0x01793, 0x01794, 0x01795, 0x01796, 0x01797,
+ 0x01798, 0x01799, 0x0179a, 0x0179b, 0x0179c, 0x0179d, 0x0179e, 0x0179f,
+ 0x017a0, 0x017a1, 0x017a2, 0x017a3, 0x017a4, 0x017a5, 0x017a6, 0x017a7,
+ 0x017a8, 0x017a9, 0x017aa, 0x017ab, 0x017ac, 0x017ad, 0x017ae, 0x017af,
+ 0x017b0, 0x017b1, 0x017b2, 0x017b3, 0x017b4, 0x017b5, 0x017b6, 0x017b7,
+ 0x017b8, 0x017b9, 0x017ba, 0x017bb, 0x017bc, 0x017bd, 0x017be, 0x017bf,
+ 0x017c0, 0x017c1, 0x017c2, 0x017c3, 0x017c4, 0x017c5, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x017d2, 0x00000, 0x017d4, 0x017d5, 0x017d6, 0x017d7,
+ 0x017d8, 0x017d9, 0x017da, 0x017db, 0x017dc, 0x00000, 0x017de, 0x017df,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017ea, 0x017eb, 0x017ec, 0x017ed, 0x017ee, 0x017ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017fa, 0x017fb, 0x017fc, 0x017fd, 0x017fe, 0x017ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_18[] = {
+ 0x01800, 0x01801, 0x01802, 0x01803, 0x01804, 0x01805, 0x01806, 0x01807,
+ 0x01808, 0x01809, 0x0180a, 0x00000, 0x00000, 0x00000, 0x0180e, 0x0180f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0181a, 0x0181b, 0x0181c, 0x0181d, 0x0181e, 0x0181f,
+ 0x01820, 0x01821, 0x01822, 0x01823, 0x01824, 0x01825, 0x01826, 0x01827,
+ 0x01828, 0x01829, 0x0182a, 0x0182b, 0x0182c, 0x0182d, 0x0182e, 0x0182f,
+ 0x01830, 0x01831, 0x01832, 0x01833, 0x01834, 0x01835, 0x01836, 0x01837,
+ 0x01838, 0x01839, 0x0183a, 0x0183b, 0x0183c, 0x0183d, 0x0183e, 0x0183f,
+ 0x01840, 0x01841, 0x01842, 0x01843, 0x01844, 0x01845, 0x01846, 0x01847,
+ 0x01848, 0x01849, 0x0184a, 0x0184b, 0x0184c, 0x0184d, 0x0184e, 0x0184f,
+ 0x01850, 0x01851, 0x01852, 0x01853, 0x01854, 0x01855, 0x01856, 0x01857,
+ 0x01858, 0x01859, 0x0185a, 0x0185b, 0x0185c, 0x0185d, 0x0185e, 0x0185f,
+ 0x01860, 0x01861, 0x01862, 0x01863, 0x01864, 0x01865, 0x01866, 0x01867,
+ 0x01868, 0x01869, 0x0186a, 0x0186b, 0x0186c, 0x0186d, 0x0186e, 0x0186f,
+ 0x01870, 0x01871, 0x01872, 0x01873, 0x01874, 0x01875, 0x01876, 0x01877,
+ 0x01878, 0x01879, 0x0187a, 0x0187b, 0x0187c, 0x0187d, 0x0187e, 0x0187f,
+ 0x01880, 0x01881, 0x01882, 0x01883, 0x01884, 0x01885, 0x01886, 0x01887,
+ 0x01888, 0x01889, 0x0188a, 0x0188b, 0x0188c, 0x0188d, 0x0188e, 0x0188f,
+ 0x01890, 0x01891, 0x01892, 0x01893, 0x01894, 0x01895, 0x01896, 0x01897,
+ 0x01898, 0x01899, 0x0189a, 0x0189b, 0x0189c, 0x0189d, 0x0189e, 0x0189f,
+ 0x018a0, 0x018a1, 0x018a2, 0x018a3, 0x018a4, 0x018a5, 0x018a6, 0x018a7,
+ 0x018a8, 0x018a9, 0x018aa, 0x018ab, 0x018ac, 0x018ad, 0x018ae, 0x018af,
+ 0x018b0, 0x018b1, 0x018b2, 0x018b3, 0x018b4, 0x018b5, 0x018b6, 0x018b7,
+ 0x018b8, 0x018b9, 0x018ba, 0x018bb, 0x018bc, 0x018bd, 0x018be, 0x018bf,
+ 0x018c0, 0x018c1, 0x018c2, 0x018c3, 0x018c4, 0x018c5, 0x018c6, 0x018c7,
+ 0x018c8, 0x018c9, 0x018ca, 0x018cb, 0x018cc, 0x018cd, 0x018ce, 0x018cf,
+ 0x018d0, 0x018d1, 0x018d2, 0x018d3, 0x018d4, 0x018d5, 0x018d6, 0x018d7,
+ 0x018d8, 0x018d9, 0x018da, 0x018db, 0x018dc, 0x018dd, 0x018de, 0x018df,
+ 0x018e0, 0x018e1, 0x018e2, 0x018e3, 0x018e4, 0x018e5, 0x018e6, 0x018e7,
+ 0x018e8, 0x018e9, 0x018ea, 0x018eb, 0x018ec, 0x018ed, 0x018ee, 0x018ef,
+ 0x018f0, 0x018f1, 0x018f2, 0x018f3, 0x018f4, 0x018f5, 0x018f6, 0x018f7,
+ 0x018f8, 0x018f9, 0x018fa, 0x018fb, 0x018fc, 0x018fd, 0x018fe, 0x018ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_19[] = {
+ 0x01900, 0x01901, 0x01902, 0x01903, 0x01904, 0x01905, 0x01906, 0x01907,
+ 0x01908, 0x01909, 0x0190a, 0x0190b, 0x0190c, 0x0190d, 0x0190e, 0x0190f,
+ 0x01910, 0x01911, 0x01912, 0x01913, 0x01914, 0x01915, 0x01916, 0x01917,
+ 0x01918, 0x01919, 0x0191a, 0x0191b, 0x0191c, 0x0191d, 0x0191e, 0x0191f,
+ 0x01920, 0x01921, 0x01922, 0x01923, 0x01924, 0x01925, 0x01926, 0x01927,
+ 0x01928, 0x01929, 0x0192a, 0x0192b, 0x0192c, 0x0192d, 0x0192e, 0x0192f,
+ 0x01930, 0x01931, 0x01932, 0x01933, 0x01934, 0x01935, 0x01936, 0x01937,
+ 0x01938, 0x00000, 0x00000, 0x00000, 0x0193c, 0x0193d, 0x0193e, 0x0193f,
+ 0x01940, 0x01941, 0x01942, 0x01943, 0x01944, 0x01945, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x01950, 0x01951, 0x01952, 0x01953, 0x01954, 0x01955, 0x01956, 0x01957,
+ 0x01958, 0x01959, 0x0195a, 0x0195b, 0x0195c, 0x0195d, 0x0195e, 0x0195f,
+ 0x01960, 0x01961, 0x01962, 0x01963, 0x01964, 0x01965, 0x01966, 0x01967,
+ 0x01968, 0x01969, 0x0196a, 0x0196b, 0x0196c, 0x0196d, 0x0196e, 0x0196f,
+ 0x01970, 0x01971, 0x01972, 0x01973, 0x01974, 0x01975, 0x01976, 0x01977,
+ 0x01978, 0x01979, 0x0197a, 0x0197b, 0x0197c, 0x0197d, 0x0197e, 0x0197f,
+ 0x01980, 0x01981, 0x01982, 0x01983, 0x01984, 0x01985, 0x01986, 0x01987,
+ 0x01988, 0x01989, 0x0198a, 0x0198b, 0x0198c, 0x0198d, 0x0198e, 0x0198f,
+ 0x01990, 0x01991, 0x01992, 0x01993, 0x01994, 0x01995, 0x01996, 0x01997,
+ 0x01998, 0x01999, 0x0199a, 0x0199b, 0x0199c, 0x0199d, 0x0199e, 0x0199f,
+ 0x019a0, 0x019a1, 0x019a2, 0x019a3, 0x019a4, 0x019a5, 0x019a6, 0x019a7,
+ 0x019a8, 0x019a9, 0x019aa, 0x019ab, 0x019ac, 0x019ad, 0x019ae, 0x019af,
+ 0x019b0, 0x019b1, 0x019b2, 0x019b3, 0x019b4, 0x019b5, 0x019b6, 0x019b7,
+ 0x019b8, 0x019b9, 0x019ba, 0x019bb, 0x019bc, 0x019bd, 0x019be, 0x019bf,
+ 0x019c0, 0x019c1, 0x019c2, 0x019c3, 0x019c4, 0x019c5, 0x019c6, 0x019c7,
+ 0x019c8, 0x019c9, 0x019ca, 0x019cb, 0x019cc, 0x019cd, 0x019ce, 0x019cf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00031, 0x019db, 0x019dc, 0x019dd, 0x019de, 0x019df,
+ 0x019e0, 0x019e1, 0x019e2, 0x019e3, 0x019e4, 0x019e5, 0x019e6, 0x019e7,
+ 0x019e8, 0x019e9, 0x019ea, 0x019eb, 0x019ec, 0x019ed, 0x019ee, 0x019ef,
+ 0x019f0, 0x019f1, 0x019f2, 0x019f3, 0x019f4, 0x019f5, 0x019f6, 0x019f7,
+ 0x019f8, 0x019f9, 0x019fa, 0x019fb, 0x019fc, 0x019fd, 0x019fe, 0x019ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1a[] = {
+ 0x01a00, 0x01a01, 0x01a02, 0x01a03, 0x01a04, 0x01a05, 0x01a06, 0x01a07,
+ 0x01a08, 0x01a09, 0x01a0a, 0x01a0b, 0x01a0c, 0x01a0d, 0x01a0e, 0x01a0f,
+ 0x01a10, 0x01a11, 0x01a12, 0x01a13, 0x01a14, 0x01a15, 0x01a16, 0x01a17,
+ 0x01a18, 0x01a19, 0x01a1a, 0x01a1b, 0x01a1c, 0x01a1d, 0x01a1e, 0x01a1f,
+ 0x01a20, 0x01a21, 0x01a22, 0x01a23, 0x01a24, 0x01a25, 0x01a26, 0x01a27,
+ 0x01a28, 0x01a29, 0x01a2a, 0x01a2b, 0x01a2c, 0x01a2d, 0x01a2e, 0x01a2f,
+ 0x01a30, 0x01a31, 0x01a32, 0x01a33, 0x01a34, 0x01a35, 0x01a36, 0x01a37,
+ 0x01a38, 0x01a39, 0x01a3a, 0x01a3b, 0x01a3c, 0x01a3d, 0x01a3e, 0x01a3f,
+ 0x01a40, 0x01a41, 0x01a42, 0x01a43, 0x01a44, 0x01a45, 0x01a46, 0x01a47,
+ 0x01a48, 0x01a49, 0x01a4a, 0x01a4b, 0x01a4c, 0x01a4d, 0x01a4e, 0x01a4f,
+ 0x01a50, 0x01a51, 0x01a52, 0x01a53, 0x01a54, 0x01a55, 0x01a56, 0x01a57,
+ 0x01a26, 0x01a26, 0x01a3b, 0x01a3b, 0x01a5c, 0x01a5d, 0x01a5e, 0x01a5f,
+ 0x01a60, 0x01a61, 0x01a62, 0x01a63, 0x01a63, 0x01a65, 0x01a66, 0x01a67,
+ 0x01a68, 0x01a69, 0x01a6a, 0x01a6b, 0x01a6c, 0x01a6d, 0x01a6e, 0x01a6f,
+ 0x01a70, 0x01a71, 0x01a72, 0x01a73, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x01a7d, 0x01a7e, 0x00000,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01a8a, 0x01a8b, 0x01a8c, 0x01a8d, 0x01a8e, 0x01a8f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01a9a, 0x01a9b, 0x01a9c, 0x01a9d, 0x01a9e, 0x01a9f,
+ 0x01aa0, 0x01aa1, 0x01aa2, 0x01aa3, 0x01aa4, 0x01aa5, 0x01aa6, 0x01aa7,
+ 0x01aa8, 0x01aa9, 0x01aaa, 0x01aab, 0x01aac, 0x01aad, 0x01aae, 0x01aaf,
+ 0x01ab0, 0x01ab1, 0x01ab2, 0x01ab3, 0x01ab4, 0x01ab5, 0x01ab6, 0x01ab7,
+ 0x01ab8, 0x01ab9, 0x01aba, 0x01abb, 0x01abc, 0x01abd, 0x01abe, 0x01abf,
+ 0x01ac0, 0x01ac1, 0x01ac2, 0x01ac3, 0x01ac4, 0x01ac5, 0x01ac6, 0x01ac7,
+ 0x01ac8, 0x01ac9, 0x01aca, 0x01acb, 0x01acc, 0x01acd, 0x01ace, 0x01acf,
+ 0x01ad0, 0x01ad1, 0x01ad2, 0x01ad3, 0x01ad4, 0x01ad5, 0x01ad6, 0x01ad7,
+ 0x01ad8, 0x01ad9, 0x01ada, 0x01adb, 0x01adc, 0x01add, 0x01ade, 0x01adf,
+ 0x01ae0, 0x01ae1, 0x01ae2, 0x01ae3, 0x01ae4, 0x01ae5, 0x01ae6, 0x01ae7,
+ 0x01ae8, 0x01ae9, 0x01aea, 0x01aeb, 0x01aec, 0x01aed, 0x01aee, 0x01aef,
+ 0x01af0, 0x01af1, 0x01af2, 0x01af3, 0x01af4, 0x01af5, 0x01af6, 0x01af7,
+ 0x01af8, 0x01af9, 0x01afa, 0x01afb, 0x01afc, 0x01afd, 0x01afe, 0x01aff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1b[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x01b05, 0x01b06, 0x01b07,
+ 0x01b08, 0x01b09, 0x01b0a, 0x01b0b, 0x01b0c, 0x01b0d, 0x01b0e, 0x01b0f,
+ 0x01b10, 0x01b11, 0x01b12, 0x01b13, 0x01b14, 0x01b15, 0x01b16, 0x01b17,
+ 0x01b18, 0x01b19, 0x01b1a, 0x01b1b, 0x01b1c, 0x01b1d, 0x01b1e, 0x01b1f,
+ 0x01b20, 0x01b21, 0x01b22, 0x01b23, 0x01b24, 0x01b25, 0x01b26, 0x01b27,
+ 0x01b28, 0x01b29, 0x01b2a, 0x01b2b, 0x01b2c, 0x01b2d, 0x01b2e, 0x01b2f,
+ 0x01b30, 0x01b31, 0x01b32, 0x01b33, 0x00000, 0x01b35, 0x01b36, 0x01b37,
+ 0x01b38, 0x01b39, 0x01b3a, 0x01b3b, 0x01b3c, 0x01b3d, 0x01b3e, 0x01b3f,
+ 0x01b40, 0x01b41, 0x01b42, 0x01b43, 0x01b44, 0x01b45, 0x01b46, 0x01b47,
+ 0x01b48, 0x01b49, 0x01b4a, 0x01b4b, 0x01b4c, 0x01b4d, 0x01b4e, 0x01b4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01b5a, 0x01b5b, 0x01b5c, 0x01b5d, 0x01b5e, 0x01b5f,
+ 0x01b60, 0x01b61, 0x01b62, 0x01b63, 0x01b64, 0x01b65, 0x01b66, 0x01b67,
+ 0x01b68, 0x01b69, 0x01b6a, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x01b74, 0x01b75, 0x01b76, 0x01b77,
+ 0x01b78, 0x01b79, 0x01b7a, 0x01b7b, 0x01b7c, 0x01b7d, 0x01b7e, 0x01b7f,
+ 0x00000, 0x00000, 0x00000, 0x01b83, 0x01b84, 0x01b85, 0x01b86, 0x01b87,
+ 0x01b88, 0x01b89, 0x01b8a, 0x01b8b, 0x01b8c, 0x01b8d, 0x01b8e, 0x01b8f,
+ 0x01b90, 0x01b91, 0x01b92, 0x01b93, 0x01b94, 0x01b95, 0x01b96, 0x01b97,
+ 0x01b98, 0x01b99, 0x01b9a, 0x01b9b, 0x01b9c, 0x01b9d, 0x01b9e, 0x01b9f,
+ 0x01ba0, 0x01ba1, 0x01ba2, 0x01ba3, 0x01ba4, 0x01ba5, 0x01ba6, 0x01ba7,
+ 0x01ba8, 0x01ba9, 0x01baa, 0x01bab, 0x01bac, 0x01bad, 0x01bae, 0x01baf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01bba, 0x01bbb, 0x01bbc, 0x01bbd, 0x01bbe, 0x01bbf,
+ 0x01bc0, 0x01bc1, 0x01bc2, 0x01bc3, 0x01bc4, 0x01bc5, 0x01bc6, 0x01bc7,
+ 0x01bc8, 0x01bc9, 0x01bca, 0x01bcb, 0x01bcc, 0x01bcd, 0x01bce, 0x01bcf,
+ 0x01bd0, 0x01bd1, 0x01bd2, 0x01bd3, 0x01bd4, 0x01bd5, 0x01bd6, 0x01bd7,
+ 0x01bd8, 0x01bd9, 0x01bda, 0x01bdb, 0x01bdc, 0x01bdd, 0x01bde, 0x01bdf,
+ 0x01be0, 0x01be1, 0x01be2, 0x01be3, 0x01be4, 0x01be5, 0x01be6, 0x01be7,
+ 0x01be8, 0x01be9, 0x01bea, 0x01beb, 0x01bec, 0x01bed, 0x01bee, 0x01bef,
+ 0x01bf0, 0x01bf1, 0x01bf2, 0x01bf3, 0x01bf4, 0x01bf5, 0x01bf6, 0x01bf7,
+ 0x01bf8, 0x01bf9, 0x01bfa, 0x01bfb, 0x01bfc, 0x01bfd, 0x01bfe, 0x01bff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1c[] = {
+ 0x01c00, 0x01c01, 0x01c02, 0x01c03, 0x01c04, 0x01c05, 0x01c06, 0x01c07,
+ 0x01c08, 0x01c09, 0x01c0a, 0x01c0b, 0x01c0c, 0x01c0d, 0x01c0e, 0x01c0f,
+ 0x01c10, 0x01c11, 0x01c12, 0x01c13, 0x01c14, 0x01c15, 0x01c16, 0x01c17,
+ 0x01c18, 0x01c19, 0x01c1a, 0x01c1b, 0x01c1c, 0x01c1d, 0x01c1e, 0x01c1f,
+ 0x01c20, 0x01c21, 0x01c22, 0x01c23, 0x01c24, 0x01c25, 0x01c26, 0x01c27,
+ 0x01c28, 0x01c29, 0x01c2a, 0x01c2b, 0x01c2c, 0x01c2d, 0x01c2e, 0x01c2f,
+ 0x01c30, 0x01c31, 0x01c32, 0x01c33, 0x01c34, 0x01c35, 0x01c36, 0x00000,
+ 0x01c38, 0x01c39, 0x01c3a, 0x01c3b, 0x01c3c, 0x01c3d, 0x01c3e, 0x01c3f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01c4a, 0x01c4b, 0x01c4c, 0x01c4d, 0x01c4e, 0x01c4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01c5a, 0x01c5b, 0x01c5c, 0x01c5d, 0x01c5e, 0x01c5f,
+ 0x01c60, 0x01c61, 0x01c62, 0x01c63, 0x01c64, 0x01c65, 0x01c66, 0x01c67,
+ 0x01c68, 0x01c69, 0x01c6a, 0x01c6b, 0x01c6c, 0x01c6d, 0x01c6e, 0x01c6f,
+ 0x01c70, 0x01c71, 0x01c72, 0x01c73, 0x01c74, 0x01c75, 0x01c76, 0x01c77,
+ 0x01c78, 0x01c79, 0x01c7a, 0x01c7b, 0x01c7c, 0x01c7d, 0x01c7e, 0x01c7f,
+ 0x01c80, 0x01c81, 0x01c82, 0x01c83, 0x01c84, 0x01c85, 0x01c86, 0x01c87,
+ 0x01c88, 0x01c89, 0x01c8a, 0x01c8b, 0x01c8c, 0x01c8d, 0x01c8e, 0x01c8f,
+ 0x01c90, 0x01c91, 0x01c92, 0x01c93, 0x01c94, 0x01c95, 0x01c96, 0x01c97,
+ 0x01c98, 0x01c99, 0x01c9a, 0x01c9b, 0x01c9c, 0x01c9d, 0x01c9e, 0x01c9f,
+ 0x01ca0, 0x01ca1, 0x01ca2, 0x01ca3, 0x01ca4, 0x01ca5, 0x01ca6, 0x01ca7,
+ 0x01ca8, 0x01ca9, 0x01caa, 0x01cab, 0x01cac, 0x01cad, 0x01cae, 0x01caf,
+ 0x01cb0, 0x01cb1, 0x01cb2, 0x01cb3, 0x01cb4, 0x01cb5, 0x01cb6, 0x01cb7,
+ 0x01cb8, 0x01cb9, 0x01cba, 0x01cbb, 0x01cbc, 0x01cbd, 0x01cbe, 0x01cbf,
+ 0x01cc0, 0x01cc1, 0x01cc2, 0x01cc3, 0x01cc4, 0x01cc5, 0x01cc6, 0x01cc7,
+ 0x01cc8, 0x01cc9, 0x01cca, 0x01ccb, 0x01ccc, 0x01ccd, 0x01cce, 0x01ccf,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x01ce9, 0x01ce9, 0x01ce9, 0x01ce9, 0x00000, 0x01ce9, 0x01ce9,
+ 0x01ce9, 0x01ce9, 0x00000, 0x01cf3, 0x01cf4, 0x01cf5, 0x01cf6, 0x01cf7,
+ 0x01cf8, 0x01cf9, 0x01cfa, 0x01cfb, 0x01cfc, 0x01cfd, 0x01cfe, 0x01cff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d[] = {
+ 0x01d00, 0x01d01, 0x01d02, 0x01d03, 0x01d04, 0x01d05, 0x01d06, 0x01d07,
+ 0x01d08, 0x01d09, 0x01d0a, 0x01d0b, 0x01d0c, 0x01d0d, 0x01d0e, 0x01d0f,
+ 0x01d10, 0x01d11, 0x01d12, 0x01d13, 0x01d14, 0x01d15, 0x01d16, 0x01d17,
+ 0x01d18, 0x01d19, 0x01d1a, 0x01d1b, 0x01d1c, 0x01d1d, 0x01d1e, 0x01d1f,
+ 0x01d20, 0x01d21, 0x01d22, 0x01d23, 0x01d24, 0x01d25, 0x01d26, 0x01d27,
+ 0x01d28, 0x01d29, 0x01d2a, 0x01d2b, 0x00041, 0x000c6, 0x00042, 0x01d2f,
+ 0x00044, 0x00045, 0x0018e, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b,
+ 0x0004c, 0x0004d, 0x0004e, 0x01d3b, 0x0004f, 0x00222, 0x00050, 0x00052,
+ 0x00054, 0x00055, 0x00057, 0x00041, 0x00250, 0x00251, 0x01d02, 0x00042,
+ 0x00044, 0x00045, 0x0018f, 0x00190, 0x01d08, 0x00047, 0x01d09, 0x0004b,
+ 0x0004d, 0x0014a, 0x0004f, 0x00186, 0x01d16, 0x01d17, 0x00050, 0x00054,
+ 0x00055, 0x01d1d, 0x0019c, 0x00056, 0x01d25, 0x00392, 0x00393, 0x00394,
+ 0x003a6, 0x003a7, 0x00049, 0x00052, 0x00055, 0x00056, 0x00392, 0x00393,
+ 0x003a1, 0x003a6, 0x003a7, 0x01d6b, 0x01d6c, 0x01d6d, 0x01d6e, 0x01d6f,
+ 0x01d70, 0x01d71, 0x01d72, 0x01d73, 0x01d74, 0x01d75, 0x01d76, 0x01d77,
+ 0x0041d, 0x00047, 0x01d7a, 0x01d7b, 0x01d7c, 0x01d7d, 0x01d7e, 0x01d7f,
+ 0x01d80, 0x01d81, 0x01d82, 0x01d83, 0x01d84, 0x01d85, 0x01d86, 0x01d87,
+ 0x01d88, 0x01d89, 0x01d8a, 0x01d8b, 0x01d8c, 0x01d8d, 0x01d8e, 0x01d8f,
+ 0x01d90, 0x01d91, 0x01d92, 0x01d93, 0x01d94, 0x01d95, 0x01d96, 0x01d97,
+ 0x01d98, 0x01d99, 0x01d9a, 0x00252, 0x00043, 0x00255, 0x00044, 0x0025c,
+ 0x00046, 0x0025f, 0x00261, 0x00265, 0x00197, 0x00196, 0x0026a, 0x01d7b,
+ 0x0029d, 0x0026d, 0x01d85, 0x0029f, 0x00271, 0x00270, 0x0019d, 0x00273,
+ 0x00274, 0x0019f, 0x00278, 0x00282, 0x001a9, 0x001ab, 0x00244, 0x001b1,
+ 0x01d1c, 0x001b2, 0x00245, 0x0005a, 0x00290, 0x00291, 0x001b7, 0x00398,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00052, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x01dd2, 0x00041, 0x000c6, 0x01dd5, 0x01dd6, 0x00043,
+ 0x00044, 0x00044, 0x00047, 0x00262, 0x0004b, 0x0004c, 0x0029f, 0x01d0d,
+ 0x0004e, 0x00274, 0x001a6, 0x01de3, 0x00053, 0x00053, 0x0005a, 0x01de7,
+ 0x01de8, 0x01de9, 0x01dea, 0x01deb, 0x01dec, 0x01ded, 0x01dee, 0x01def,
+ 0x01df0, 0x01df1, 0x01df2, 0x01df3, 0x01df4, 0x01df5, 0x01df6, 0x01df7,
+ 0x01df8, 0x01df9, 0x01dfa, 0x01dfb, 0x01dfc, 0x00000, 0x00000, 0x01dff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1e[] = {
+ 0x00041, 0x00041, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042,
+ 0x00043, 0x00043, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00046, 0x00046,
+ 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00048, 0x00048, 0x00048, 0x00048, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004d, 0x0004d,
+ 0x0004d, 0x0004d, 0x0004d, 0x0004d, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00050, 0x00050, 0x00050, 0x00050,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054,
+ 0x00054, 0x00054, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00056, 0x00056, 0x00056, 0x00056,
+ 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057,
+ 0x00057, 0x00057, 0x00058, 0x00058, 0x00058, 0x00058, 0x00059, 0x00059,
+ 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00048, 0x00054,
+ 0x00057, 0x00059, 0x01e9a, 0x00053, 0x01e9c, 0x01e9d, 0x000df, 0x01e9f,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059,
+ 0x00059, 0x00059, 0x01efa, 0x01efa, 0x01efc, 0x01efc, 0x01efe, 0x01eff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f[] = {
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f16, 0x01f17,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f1e, 0x01f1f,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f46, 0x01f47,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f4e, 0x01f4f,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5,
+ 0x01f58, 0x003a5, 0x01f5a, 0x003a5, 0x01f5c, 0x003a5, 0x01f5e, 0x003a5,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00395, 0x00395, 0x00397, 0x00397, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x003a5, 0x003a5, 0x003a9, 0x003a9, 0x01f7e, 0x01f7f,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fb5, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fbd, 0x00399, 0x01fbd,
+ 0x01fc0, 0x000a8, 0x00397, 0x00397, 0x00397, 0x01fc5, 0x00397, 0x00397,
+ 0x00395, 0x00395, 0x00397, 0x00397, 0x00397, 0x01fbd, 0x01fbd, 0x01fbd,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fd4, 0x01fd5, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fdc, 0x01fdd, 0x01fdd, 0x01fdd,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x003a1, 0x003a5, 0x003a5,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x000a8, 0x000a8, 0x00060,
+ 0x01ff0, 0x01ff1, 0x003a9, 0x003a9, 0x003a9, 0x01ff5, 0x003a9, 0x003a9,
+ 0x0039f, 0x0039f, 0x003a9, 0x003a9, 0x003a9, 0x000b4, 0x01fdd, 0x01fff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_20[] = {
+ 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020,
+ 0x00020, 0x00020, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x02010, 0x02010, 0x02012, 0x02013, 0x02014, 0x02015, 0x02016, 0x02017,
+ 0x02018, 0x02019, 0x0201a, 0x0201b, 0x0201c, 0x0201d, 0x0201e, 0x0201f,
+ 0x02020, 0x02021, 0x02022, 0x02023, 0x0002e, 0x02025, 0x02026, 0x02027,
+ 0x02028, 0x02029, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00020,
+ 0x02030, 0x02031, 0x02032, 0x02033, 0x02034, 0x02035, 0x02036, 0x02037,
+ 0x02038, 0x02039, 0x0203a, 0x0203b, 0x0203c, 0x0203d, 0x0203e, 0x0203f,
+ 0x02040, 0x02041, 0x02042, 0x02043, 0x02044, 0x02045, 0x02046, 0x02047,
+ 0x02048, 0x02049, 0x0204a, 0x0204b, 0x0204c, 0x0204d, 0x0204e, 0x0204f,
+ 0x02050, 0x02051, 0x02052, 0x02053, 0x02054, 0x02055, 0x02056, 0x02057,
+ 0x02058, 0x02059, 0x0205a, 0x0205b, 0x0205c, 0x0205d, 0x0205e, 0x00020,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x02065, 0x02066, 0x02067,
+ 0x02068, 0x02069, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00030, 0x00049, 0x02072, 0x02073, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0004e,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0208f,
+ 0x00041, 0x00045, 0x0004f, 0x00058, 0x0018f, 0x02095, 0x02096, 0x02097,
+ 0x02098, 0x02099, 0x0209a, 0x0209b, 0x0209c, 0x0209d, 0x0209e, 0x0209f,
+ 0x020a0, 0x020a1, 0x020a2, 0x020a3, 0x020a4, 0x020a5, 0x020a6, 0x020a7,
+ 0x020a8, 0x020a9, 0x020aa, 0x020ab, 0x020ac, 0x020ad, 0x020ae, 0x020af,
+ 0x020b0, 0x020b1, 0x020b2, 0x020b3, 0x020b4, 0x020b5, 0x020b6, 0x020b7,
+ 0x020b8, 0x020b9, 0x020ba, 0x020bb, 0x020bc, 0x020bd, 0x020be, 0x020bf,
+ 0x020c0, 0x020c1, 0x020c2, 0x020c3, 0x020c4, 0x020c5, 0x020c6, 0x020c7,
+ 0x020c8, 0x020c9, 0x020ca, 0x020cb, 0x020cc, 0x020cd, 0x020ce, 0x020cf,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x020f1, 0x020f2, 0x020f3, 0x020f4, 0x020f5, 0x020f6, 0x020f7,
+ 0x020f8, 0x020f9, 0x020fa, 0x020fb, 0x020fc, 0x020fd, 0x020fe, 0x020ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_21[] = {
+ 0x02100, 0x02101, 0x00043, 0x02103, 0x02104, 0x02105, 0x02106, 0x00190,
+ 0x02108, 0x02109, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00049, 0x00049, 0x0004c, 0x0004c, 0x02114, 0x0004e, 0x02116, 0x02117,
+ 0x02118, 0x00050, 0x00051, 0x00052, 0x00052, 0x00052, 0x0211e, 0x0211f,
+ 0x02120, 0x02121, 0x02122, 0x02123, 0x0005a, 0x02125, 0x003a9, 0x02127,
+ 0x0005a, 0x02129, 0x0004b, 0x00041, 0x00042, 0x00043, 0x0212e, 0x00045,
+ 0x00045, 0x00046, 0x02132, 0x0004d, 0x0004f, 0x005d0, 0x005d1, 0x005d2,
+ 0x005d3, 0x00049, 0x0213a, 0x0213b, 0x003a0, 0x00393, 0x00393, 0x003a0,
+ 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x00044, 0x00044, 0x00045,
+ 0x00049, 0x0004a, 0x0214a, 0x0214b, 0x0214c, 0x0214d, 0x02132, 0x0214f,
+ 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157,
+ 0x02158, 0x02159, 0x0215a, 0x0215b, 0x0215c, 0x0215d, 0x0215e, 0x0215f,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x02180, 0x02181, 0x02182, 0x02183, 0x02183, 0x00036, 0x02186, 0x02187,
+ 0x02188, 0x02189, 0x0218a, 0x0218b, 0x0218c, 0x0218d, 0x0218e, 0x0218f,
+ 0x02190, 0x02191, 0x02192, 0x02193, 0x02194, 0x02195, 0x02196, 0x02197,
+ 0x02198, 0x02199, 0x02190, 0x02192, 0x0219c, 0x0219d, 0x0219e, 0x0219f,
+ 0x021a0, 0x021a1, 0x021a2, 0x021a3, 0x021a4, 0x021a5, 0x021a6, 0x021a7,
+ 0x021a8, 0x021a9, 0x021aa, 0x021ab, 0x021ac, 0x021ad, 0x02194, 0x021af,
+ 0x021b0, 0x021b1, 0x021b2, 0x021b3, 0x021b4, 0x021b5, 0x021b6, 0x021b7,
+ 0x021b8, 0x021b9, 0x021ba, 0x021bb, 0x021bc, 0x021bd, 0x021be, 0x021bf,
+ 0x021c0, 0x021c1, 0x021c2, 0x021c3, 0x021c4, 0x021c5, 0x021c6, 0x021c7,
+ 0x021c8, 0x021c9, 0x021ca, 0x021cb, 0x021cc, 0x021cd, 0x021ce, 0x021cf,
+ 0x021cd, 0x021d1, 0x021cf, 0x021d3, 0x021ce, 0x021d5, 0x021d6, 0x021d7,
+ 0x021d8, 0x021d9, 0x021da, 0x021db, 0x021dc, 0x021dd, 0x021de, 0x021df,
+ 0x021e0, 0x021e1, 0x021e2, 0x021e3, 0x021e4, 0x021e5, 0x021e6, 0x021e7,
+ 0x021e8, 0x021e9, 0x021ea, 0x021eb, 0x021ec, 0x021ed, 0x021ee, 0x021ef,
+ 0x021f0, 0x021f1, 0x021f2, 0x021f3, 0x021f4, 0x021f5, 0x021f6, 0x021f7,
+ 0x021f8, 0x021f9, 0x021fa, 0x021fb, 0x021fc, 0x021fd, 0x021fe, 0x021ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_22[] = {
+ 0x02200, 0x02201, 0x02202, 0x02203, 0x02203, 0x02205, 0x02206, 0x02207,
+ 0x02208, 0x02208, 0x0220a, 0x0220b, 0x0220b, 0x0220d, 0x0220e, 0x0220f,
+ 0x02210, 0x02140, 0x0207b, 0x02213, 0x02214, 0x02215, 0x02216, 0x02217,
+ 0x02218, 0x02219, 0x0221a, 0x0221b, 0x0221c, 0x0221d, 0x0221e, 0x0221f,
+ 0x02220, 0x02221, 0x02222, 0x02223, 0x02223, 0x02225, 0x02225, 0x02227,
+ 0x02228, 0x02229, 0x0222a, 0x0222b, 0x0222c, 0x0222d, 0x0222e, 0x0222f,
+ 0x02230, 0x02231, 0x02232, 0x02233, 0x02234, 0x02235, 0x02236, 0x02237,
+ 0x02238, 0x02239, 0x0223a, 0x0223b, 0x0223c, 0x0223d, 0x0223e, 0x0223f,
+ 0x02240, 0x0223c, 0x02242, 0x02243, 0x02243, 0x02245, 0x02246, 0x02245,
+ 0x02248, 0x02248, 0x0224a, 0x0224b, 0x0224c, 0x0224d, 0x0224e, 0x0224f,
+ 0x02250, 0x02251, 0x02252, 0x02253, 0x02254, 0x02255, 0x02256, 0x02257,
+ 0x02258, 0x02259, 0x0225a, 0x0225b, 0x0225c, 0x0225d, 0x0225e, 0x0225f,
+ 0x0003d, 0x02261, 0x02261, 0x02263, 0x02264, 0x02265, 0x02266, 0x02267,
+ 0x02268, 0x02269, 0x0226a, 0x0226b, 0x0226c, 0x0224d, 0x0003c, 0x0003e,
+ 0x02264, 0x02265, 0x02272, 0x02273, 0x02272, 0x02273, 0x02276, 0x02277,
+ 0x02276, 0x02277, 0x0227a, 0x0227b, 0x0227c, 0x0227d, 0x0227e, 0x0227f,
+ 0x0227a, 0x0227b, 0x02282, 0x02283, 0x02282, 0x02283, 0x02286, 0x02287,
+ 0x02286, 0x02287, 0x0228a, 0x0228b, 0x0228c, 0x0228d, 0x0228e, 0x0228f,
+ 0x02290, 0x02291, 0x02292, 0x02293, 0x02294, 0x02295, 0x02296, 0x02297,
+ 0x02298, 0x02299, 0x0229a, 0x0229b, 0x0229c, 0x0229d, 0x0229e, 0x0229f,
+ 0x022a0, 0x022a1, 0x022a2, 0x022a3, 0x022a4, 0x022a5, 0x022a6, 0x022a7,
+ 0x022a8, 0x022a9, 0x022aa, 0x022ab, 0x022a2, 0x022a8, 0x022a9, 0x022ab,
+ 0x022b0, 0x022b1, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022b6, 0x022b7,
+ 0x022b8, 0x022b9, 0x022ba, 0x022bb, 0x022bc, 0x022bd, 0x022be, 0x022bf,
+ 0x022c0, 0x022c1, 0x022c2, 0x022c3, 0x022c4, 0x022c5, 0x022c6, 0x022c7,
+ 0x022c8, 0x022c9, 0x022ca, 0x022cb, 0x022cc, 0x022cd, 0x022ce, 0x022cf,
+ 0x022d0, 0x022d1, 0x022d2, 0x022d3, 0x022d4, 0x022d5, 0x022d6, 0x022d7,
+ 0x022d8, 0x022d9, 0x022da, 0x022db, 0x022dc, 0x022dd, 0x022de, 0x022df,
+ 0x0227c, 0x0227d, 0x02291, 0x02292, 0x022e4, 0x022e5, 0x022e6, 0x022e7,
+ 0x022e8, 0x022e9, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022ee, 0x022ef,
+ 0x022f0, 0x022f1, 0x022f2, 0x022f3, 0x022f4, 0x022f5, 0x022f6, 0x022f7,
+ 0x022f8, 0x022f9, 0x022fa, 0x022fb, 0x022fc, 0x022fd, 0x022fe, 0x022ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_24[] = {
+ 0x02400, 0x02401, 0x02402, 0x02403, 0x02404, 0x02405, 0x02406, 0x02407,
+ 0x02408, 0x02409, 0x0240a, 0x0240b, 0x0240c, 0x0240d, 0x0240e, 0x0240f,
+ 0x02410, 0x02411, 0x02412, 0x02413, 0x02414, 0x02415, 0x02416, 0x02417,
+ 0x02418, 0x02419, 0x0241a, 0x0241b, 0x0241c, 0x0241d, 0x0241e, 0x0241f,
+ 0x02420, 0x02421, 0x02422, 0x02423, 0x02424, 0x02425, 0x02426, 0x02427,
+ 0x02428, 0x02429, 0x0242a, 0x0242b, 0x0242c, 0x0242d, 0x0242e, 0x0242f,
+ 0x02430, 0x02431, 0x02432, 0x02433, 0x02434, 0x02435, 0x02436, 0x02437,
+ 0x02438, 0x02439, 0x0243a, 0x0243b, 0x0243c, 0x0243d, 0x0243e, 0x0243f,
+ 0x02440, 0x02441, 0x02442, 0x02443, 0x02444, 0x02445, 0x02446, 0x02447,
+ 0x02448, 0x02449, 0x0244a, 0x0244b, 0x0244c, 0x0244d, 0x0244e, 0x0244f,
+ 0x02450, 0x02451, 0x02452, 0x02453, 0x02454, 0x02455, 0x02456, 0x02457,
+ 0x02458, 0x02459, 0x0245a, 0x0245b, 0x0245c, 0x0245d, 0x0245e, 0x0245f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e, 0x0246f,
+ 0x02470, 0x02471, 0x02472, 0x02473, 0x02474, 0x02475, 0x02476, 0x02477,
+ 0x02478, 0x02479, 0x0247a, 0x0247b, 0x0247c, 0x0247d, 0x0247e, 0x0247f,
+ 0x02480, 0x02481, 0x02482, 0x02483, 0x02484, 0x02485, 0x02486, 0x02487,
+ 0x02488, 0x02489, 0x0248a, 0x0248b, 0x0248c, 0x0248d, 0x0248e, 0x0248f,
+ 0x02490, 0x02491, 0x02492, 0x02493, 0x02494, 0x02495, 0x02496, 0x02497,
+ 0x02498, 0x02499, 0x0249a, 0x0249b, 0x0249c, 0x0249d, 0x0249e, 0x0249f,
+ 0x024a0, 0x024a1, 0x024a2, 0x024a3, 0x024a4, 0x024a5, 0x024a6, 0x024a7,
+ 0x024a8, 0x024a9, 0x024aa, 0x024ab, 0x024ac, 0x024ad, 0x024ae, 0x024af,
+ 0x024b0, 0x024b1, 0x024b2, 0x024b3, 0x024b4, 0x024b5, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00030, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e,
+ 0x0246f, 0x02470, 0x02471, 0x02472, 0x02473, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469, 0x024ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_27[] = {
+ 0x02700, 0x02701, 0x02702, 0x02703, 0x02704, 0x02705, 0x02706, 0x02707,
+ 0x02708, 0x02709, 0x0270a, 0x0270b, 0x0270c, 0x0270d, 0x0270e, 0x0270f,
+ 0x02710, 0x02711, 0x02712, 0x02713, 0x02714, 0x02715, 0x02716, 0x02717,
+ 0x02718, 0x02719, 0x0271a, 0x0271b, 0x0271c, 0x0271d, 0x0271e, 0x0271f,
+ 0x02720, 0x02721, 0x02722, 0x02723, 0x02724, 0x02725, 0x02726, 0x02727,
+ 0x02728, 0x02729, 0x0272a, 0x0272b, 0x0272c, 0x0272d, 0x0272e, 0x0272f,
+ 0x02730, 0x02731, 0x02732, 0x02733, 0x02734, 0x02735, 0x02736, 0x02737,
+ 0x02738, 0x02739, 0x0273a, 0x0273b, 0x0273c, 0x0273d, 0x0273e, 0x0273f,
+ 0x02740, 0x02741, 0x02742, 0x02743, 0x02744, 0x02745, 0x02746, 0x02747,
+ 0x02748, 0x02749, 0x0274a, 0x0274b, 0x0274c, 0x0274d, 0x0274e, 0x0274f,
+ 0x02750, 0x02751, 0x02752, 0x02753, 0x02754, 0x02755, 0x02756, 0x02757,
+ 0x02758, 0x02759, 0x0275a, 0x0275b, 0x0275c, 0x0275d, 0x0275e, 0x0275f,
+ 0x02760, 0x02761, 0x02762, 0x02763, 0x02764, 0x02765, 0x02766, 0x02767,
+ 0x02768, 0x02769, 0x0276a, 0x0276b, 0x0276c, 0x0276d, 0x0276e, 0x0276f,
+ 0x02770, 0x02771, 0x02772, 0x02773, 0x02774, 0x02775, 0x00031, 0x00032,
+ 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x02469, 0x02794, 0x02795, 0x02796, 0x02797,
+ 0x02798, 0x02799, 0x0279a, 0x0279b, 0x0279c, 0x0279d, 0x0279e, 0x0279f,
+ 0x027a0, 0x027a1, 0x027a2, 0x027a3, 0x027a4, 0x027a5, 0x027a6, 0x027a7,
+ 0x027a8, 0x027a9, 0x027aa, 0x027ab, 0x027ac, 0x027ad, 0x027ae, 0x027af,
+ 0x027b0, 0x027b1, 0x027b2, 0x027b3, 0x027b4, 0x027b5, 0x027b6, 0x027b7,
+ 0x027b8, 0x027b9, 0x027ba, 0x027bb, 0x027bc, 0x027bd, 0x027be, 0x027bf,
+ 0x027c0, 0x027c1, 0x027c2, 0x027c3, 0x027c4, 0x027c5, 0x027c6, 0x027c7,
+ 0x027c8, 0x027c9, 0x027ca, 0x027cb, 0x027cc, 0x027cd, 0x027ce, 0x027cf,
+ 0x027d0, 0x027d1, 0x027d2, 0x027d3, 0x027d4, 0x027d5, 0x027d6, 0x027d7,
+ 0x027d8, 0x027d9, 0x027da, 0x027db, 0x027dc, 0x027dd, 0x027de, 0x027df,
+ 0x027e0, 0x027e1, 0x027e2, 0x027e3, 0x027e4, 0x027e5, 0x027e6, 0x027e7,
+ 0x027e8, 0x027e9, 0x027ea, 0x027eb, 0x027ec, 0x027ed, 0x027ee, 0x027ef,
+ 0x027f0, 0x027f1, 0x027f2, 0x027f3, 0x027f4, 0x027f5, 0x027f6, 0x027f7,
+ 0x027f8, 0x027f9, 0x027fa, 0x027fb, 0x027fc, 0x027fd, 0x027fe, 0x027ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2a[] = {
+ 0x02a00, 0x02a01, 0x02a02, 0x02a03, 0x02a04, 0x02a05, 0x02a06, 0x02a07,
+ 0x02a08, 0x02a09, 0x02a0a, 0x02a0b, 0x02a0c, 0x02a0d, 0x02a0e, 0x02a0f,
+ 0x02a10, 0x02a11, 0x02a12, 0x02a13, 0x02a14, 0x02a15, 0x02a16, 0x02a17,
+ 0x02a18, 0x02a19, 0x02a1a, 0x02a1b, 0x02a1c, 0x02a1d, 0x02a1e, 0x02a1f,
+ 0x02a20, 0x02a21, 0x02a22, 0x02a23, 0x02a24, 0x02a25, 0x02a26, 0x02a27,
+ 0x02a28, 0x02a29, 0x02a2a, 0x02a2b, 0x02a2c, 0x02a2d, 0x02a2e, 0x02a2f,
+ 0x02a30, 0x02a31, 0x02a32, 0x02a33, 0x02a34, 0x02a35, 0x02a36, 0x02a37,
+ 0x02a38, 0x02a39, 0x02a3a, 0x02a3b, 0x02a3c, 0x02a3d, 0x02a3e, 0x02a3f,
+ 0x02a40, 0x02a41, 0x02a42, 0x02a43, 0x02a44, 0x02a45, 0x02a46, 0x02a47,
+ 0x02a48, 0x02a49, 0x02a4a, 0x02a4b, 0x02a4c, 0x02a4d, 0x02a4e, 0x02a4f,
+ 0x02a50, 0x02a51, 0x02a52, 0x02a53, 0x02a54, 0x02a55, 0x02a56, 0x02a57,
+ 0x02a58, 0x02a59, 0x02a5a, 0x02a5b, 0x02a5c, 0x02a5d, 0x02a5e, 0x02a5f,
+ 0x02a60, 0x02a61, 0x02a62, 0x02a63, 0x02a64, 0x02a65, 0x02a66, 0x02a67,
+ 0x02a68, 0x02a69, 0x02a6a, 0x02a6b, 0x02a6c, 0x02a6d, 0x02a6e, 0x02a6f,
+ 0x02a70, 0x02a71, 0x02a72, 0x02a73, 0x02a74, 0x02a75, 0x02a76, 0x02a77,
+ 0x02a78, 0x02a79, 0x02a7a, 0x02a7b, 0x02a7c, 0x02a7d, 0x02a7e, 0x02a7f,
+ 0x02a80, 0x02a81, 0x02a82, 0x02a83, 0x02a84, 0x02a85, 0x02a86, 0x02a87,
+ 0x02a88, 0x02a89, 0x02a8a, 0x02a8b, 0x02a8c, 0x02a8d, 0x02a8e, 0x02a8f,
+ 0x02a90, 0x02a91, 0x02a92, 0x02a93, 0x02a94, 0x02a95, 0x02a96, 0x02a97,
+ 0x02a98, 0x02a99, 0x02a9a, 0x02a9b, 0x02a9c, 0x02a9d, 0x02a9e, 0x02a9f,
+ 0x02aa0, 0x02aa1, 0x02aa2, 0x02aa3, 0x02aa4, 0x02aa5, 0x02aa6, 0x02aa7,
+ 0x02aa8, 0x02aa9, 0x02aaa, 0x02aab, 0x02aac, 0x02aad, 0x02aae, 0x02aaf,
+ 0x02ab0, 0x02ab1, 0x02ab2, 0x02ab3, 0x02ab4, 0x02ab5, 0x02ab6, 0x02ab7,
+ 0x02ab8, 0x02ab9, 0x02aba, 0x02abb, 0x02abc, 0x02abd, 0x02abe, 0x02abf,
+ 0x02ac0, 0x02ac1, 0x02ac2, 0x02ac3, 0x02ac4, 0x02ac5, 0x02ac6, 0x02ac7,
+ 0x02ac8, 0x02ac9, 0x02aca, 0x02acb, 0x02acc, 0x02acd, 0x02ace, 0x02acf,
+ 0x02ad0, 0x02ad1, 0x02ad2, 0x02ad3, 0x02ad4, 0x02ad5, 0x02ad6, 0x02ad7,
+ 0x02ad8, 0x02ad9, 0x02ada, 0x02adb, 0x02adc, 0x02adc, 0x02ade, 0x02adf,
+ 0x02ae0, 0x02ae1, 0x02ae2, 0x02ae3, 0x02ae4, 0x02ae5, 0x02ae6, 0x02ae7,
+ 0x02ae8, 0x02ae9, 0x02aea, 0x02aeb, 0x02aec, 0x02aed, 0x02aee, 0x02aef,
+ 0x02af0, 0x02af1, 0x02af2, 0x02af3, 0x02af4, 0x02af5, 0x02af6, 0x02af7,
+ 0x02af8, 0x02af9, 0x02afa, 0x02afb, 0x02afc, 0x02afd, 0x02afe, 0x02aff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2c[] = {
+ 0x02c00, 0x02c01, 0x02c02, 0x02c03, 0x02c04, 0x02c05, 0x02c06, 0x02c07,
+ 0x02c08, 0x02c09, 0x02c0a, 0x02c0b, 0x02c0c, 0x02c0d, 0x02c0e, 0x02c0f,
+ 0x02c10, 0x02c11, 0x02c12, 0x02c13, 0x02c14, 0x02c15, 0x02c16, 0x02c17,
+ 0x02c18, 0x02c19, 0x02c1a, 0x02c1b, 0x02c1c, 0x02c1d, 0x02c1e, 0x02c1f,
+ 0x02c20, 0x02c21, 0x02c22, 0x02c23, 0x02c24, 0x02c25, 0x02c26, 0x02c27,
+ 0x02c28, 0x02c29, 0x02c2a, 0x02c2b, 0x02c2c, 0x02c2d, 0x02c2e, 0x02c2f,
+ 0x02c00, 0x02c01, 0x02c02, 0x02c03, 0x02c04, 0x02c05, 0x02c06, 0x02c07,
+ 0x02c08, 0x02c09, 0x02c0a, 0x02c0b, 0x02c0c, 0x02c0d, 0x02c0e, 0x02c0f,
+ 0x02c10, 0x02c11, 0x02c12, 0x02c13, 0x02c14, 0x02c15, 0x02c16, 0x02c17,
+ 0x02c18, 0x02c19, 0x02c1a, 0x02c1b, 0x02c1c, 0x02c1d, 0x02c1e, 0x02c1f,
+ 0x02c20, 0x02c21, 0x02c22, 0x02c23, 0x02c24, 0x02c25, 0x02c26, 0x02c27,
+ 0x02c28, 0x02c29, 0x02c2a, 0x02c2b, 0x02c2c, 0x02c2d, 0x02c2e, 0x02c5f,
+ 0x02c60, 0x02c60, 0x0026b, 0x01d7d, 0x0027d, 0x0023a, 0x0023e, 0x02c67,
+ 0x02c67, 0x02c69, 0x02c69, 0x02c6b, 0x02c6b, 0x00251, 0x00271, 0x00250,
+ 0x00252, 0x02c71, 0x02c72, 0x02c72, 0x02c74, 0x02c75, 0x02c75, 0x02c77,
+ 0x02c78, 0x02c79, 0x02c7a, 0x02c7b, 0x0004a, 0x00056, 0x0023f, 0x00240,
+ 0x02c80, 0x02c80, 0x02c82, 0x02c82, 0x02c84, 0x02c84, 0x02c86, 0x02c86,
+ 0x02c88, 0x02c88, 0x02c8a, 0x02c8a, 0x02c8c, 0x02c8c, 0x02c8e, 0x02c8e,
+ 0x02c90, 0x02c90, 0x02c92, 0x02c92, 0x02c94, 0x02c94, 0x02c96, 0x02c96,
+ 0x02c98, 0x02c98, 0x02c9a, 0x02c9a, 0x02c9c, 0x02c9c, 0x02c9e, 0x02c9e,
+ 0x02ca0, 0x02ca0, 0x02ca2, 0x02ca2, 0x02ca4, 0x02ca4, 0x02ca6, 0x02ca6,
+ 0x02ca8, 0x02ca8, 0x02caa, 0x02caa, 0x02cac, 0x02cac, 0x02cae, 0x02cae,
+ 0x02cb0, 0x02cb0, 0x02cb2, 0x02cb2, 0x02cb4, 0x02cb4, 0x02cb6, 0x02cb6,
+ 0x02cb8, 0x02cb8, 0x02cba, 0x02cba, 0x02cbc, 0x02cbc, 0x02cbe, 0x02cbe,
+ 0x02cc0, 0x02cc0, 0x02cc2, 0x02cc2, 0x02cc4, 0x02cc4, 0x02cc6, 0x02cc6,
+ 0x02cc8, 0x02cc8, 0x02cca, 0x02cca, 0x02ccc, 0x02ccc, 0x02cce, 0x02cce,
+ 0x02cd0, 0x02cd0, 0x02cd2, 0x02cd2, 0x02cd4, 0x02cd4, 0x02cd6, 0x02cd6,
+ 0x02cd8, 0x02cd8, 0x02cda, 0x02cda, 0x02cdc, 0x02cdc, 0x02cde, 0x02cde,
+ 0x02ce0, 0x02ce0, 0x02ce2, 0x02ce2, 0x02ce4, 0x02ce5, 0x02ce6, 0x02ce7,
+ 0x02ce8, 0x02ce9, 0x02cea, 0x02ceb, 0x02ceb, 0x02ced, 0x02ced, 0x00000,
+ 0x00000, 0x00000, 0x02cf2, 0x02cf3, 0x02cf4, 0x02cf5, 0x02cf6, 0x02cf7,
+ 0x02cf8, 0x02cf9, 0x02cfa, 0x02cfb, 0x02cfc, 0x02cfd, 0x02cfe, 0x02cff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2d[] = {
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x02d26, 0x02d27,
+ 0x02d28, 0x02d29, 0x02d2a, 0x02d2b, 0x02d2c, 0x02d2d, 0x02d2e, 0x02d2f,
+ 0x02d30, 0x02d31, 0x02d32, 0x02d33, 0x02d34, 0x02d35, 0x02d36, 0x02d37,
+ 0x02d38, 0x02d39, 0x02d3a, 0x02d3b, 0x02d3c, 0x02d3d, 0x02d3e, 0x02d3f,
+ 0x02d40, 0x02d41, 0x02d42, 0x02d43, 0x02d44, 0x02d45, 0x02d46, 0x02d47,
+ 0x02d48, 0x02d49, 0x02d4a, 0x02d4b, 0x02d4c, 0x02d4d, 0x02d4e, 0x02d4f,
+ 0x02d50, 0x02d51, 0x02d52, 0x02d53, 0x02d54, 0x02d55, 0x02d56, 0x02d57,
+ 0x02d58, 0x02d59, 0x02d5a, 0x02d5b, 0x02d5c, 0x02d5d, 0x02d5e, 0x02d5f,
+ 0x02d60, 0x02d61, 0x02d62, 0x02d63, 0x02d64, 0x02d65, 0x02d66, 0x02d67,
+ 0x02d68, 0x02d69, 0x02d6a, 0x02d6b, 0x02d6c, 0x02d6d, 0x02d6e, 0x02d6f,
+ 0x02d70, 0x02d71, 0x02d72, 0x02d73, 0x02d74, 0x02d75, 0x02d76, 0x02d77,
+ 0x02d78, 0x02d79, 0x02d7a, 0x02d7b, 0x02d7c, 0x02d7d, 0x02d7e, 0x02d7f,
+ 0x02d80, 0x02d81, 0x02d82, 0x02d83, 0x02d84, 0x02d85, 0x02d86, 0x02d87,
+ 0x02d88, 0x02d89, 0x02d8a, 0x02d8b, 0x02d8c, 0x02d8d, 0x02d8e, 0x02d8f,
+ 0x02d90, 0x02d91, 0x02d92, 0x02d93, 0x02d94, 0x02d95, 0x02d96, 0x02d97,
+ 0x02d98, 0x02d99, 0x02d9a, 0x02d9b, 0x02d9c, 0x02d9d, 0x02d9e, 0x02d9f,
+ 0x02da0, 0x02da1, 0x02da2, 0x02da3, 0x02da4, 0x02da5, 0x02da6, 0x02da7,
+ 0x02da8, 0x02da9, 0x02daa, 0x02dab, 0x02dac, 0x02dad, 0x02dae, 0x02daf,
+ 0x02db0, 0x02db1, 0x02db2, 0x02db3, 0x02db4, 0x02db5, 0x02db6, 0x02db7,
+ 0x02db8, 0x02db9, 0x02dba, 0x02dbb, 0x02dbc, 0x02dbd, 0x02dbe, 0x02dbf,
+ 0x02dc0, 0x02dc1, 0x02dc2, 0x02dc3, 0x02dc4, 0x02dc5, 0x02dc6, 0x02dc7,
+ 0x02dc8, 0x02dc9, 0x02dca, 0x02dcb, 0x02dcc, 0x02dcd, 0x02dce, 0x02dcf,
+ 0x02dd0, 0x02dd1, 0x02dd2, 0x02dd3, 0x02dd4, 0x02dd5, 0x02dd6, 0x02dd7,
+ 0x02dd8, 0x02dd9, 0x02dda, 0x02ddb, 0x02ddc, 0x02ddd, 0x02dde, 0x02ddf,
+ 0x00411, 0x00412, 0x00413, 0x00414, 0x00416, 0x00417, 0x0041a, 0x0041b,
+ 0x0041c, 0x0041d, 0x0041e, 0x0041f, 0x00420, 0x00421, 0x00422, 0x00425,
+ 0x00426, 0x00427, 0x00428, 0x00429, 0x00472, 0x02df5, 0x00410, 0x00400,
+ 0x02df8, 0x02df9, 0x00462, 0x0042e, 0x02dfc, 0x00466, 0x0046a, 0x02dff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2e[] = {
+ 0x02e00, 0x02e01, 0x02e02, 0x02e03, 0x02e04, 0x02e05, 0x02e06, 0x02e07,
+ 0x02e08, 0x02e09, 0x02e0a, 0x02e0b, 0x02e0c, 0x02e0d, 0x02e0e, 0x02e0f,
+ 0x02e10, 0x02e11, 0x02e12, 0x02e13, 0x02e14, 0x02e15, 0x02e16, 0x02e17,
+ 0x02e18, 0x02e19, 0x02e1a, 0x02e1b, 0x02e1c, 0x02e1d, 0x02e1e, 0x02e1f,
+ 0x02e20, 0x02e21, 0x02e22, 0x02e23, 0x02e24, 0x02e25, 0x02e26, 0x02e27,
+ 0x02e28, 0x02e29, 0x02e2a, 0x02e2b, 0x02e2c, 0x02e2d, 0x02e2e, 0x02e2f,
+ 0x02e30, 0x02e31, 0x02e32, 0x02e33, 0x02e34, 0x02e35, 0x02e36, 0x02e37,
+ 0x02e38, 0x02e39, 0x02e3a, 0x02e3b, 0x02e3c, 0x02e3d, 0x02e3e, 0x02e3f,
+ 0x02e40, 0x02e41, 0x02e42, 0x02e43, 0x02e44, 0x02e45, 0x02e46, 0x02e47,
+ 0x02e48, 0x02e49, 0x02e4a, 0x02e4b, 0x02e4c, 0x02e4d, 0x02e4e, 0x02e4f,
+ 0x02e50, 0x02e51, 0x02e52, 0x02e53, 0x02e54, 0x02e55, 0x02e56, 0x02e57,
+ 0x02e58, 0x02e59, 0x02e5a, 0x02e5b, 0x02e5c, 0x02e5d, 0x02e5e, 0x02e5f,
+ 0x02e60, 0x02e61, 0x02e62, 0x02e63, 0x02e64, 0x02e65, 0x02e66, 0x02e67,
+ 0x02e68, 0x02e69, 0x02e6a, 0x02e6b, 0x02e6c, 0x02e6d, 0x02e6e, 0x02e6f,
+ 0x02e70, 0x02e71, 0x02e72, 0x02e73, 0x02e74, 0x02e75, 0x02e76, 0x02e77,
+ 0x02e78, 0x02e79, 0x02e7a, 0x02e7b, 0x02e7c, 0x02e7d, 0x02e7e, 0x02e7f,
+ 0x02e80, 0x02e81, 0x02e82, 0x02e83, 0x0319a, 0x02e85, 0x02e86, 0x02f0f,
+ 0x02f11, 0x02e89, 0x02f18, 0x02e8b, 0x02f29, 0x02f29, 0x02e8e, 0x02e8f,
+ 0x02e8e, 0x02e8f, 0x02e92, 0x02e93, 0x02e94, 0x02e95, 0x02e96, 0x02f3c,
+ 0x02e98, 0x02e99, 0x02e9a, 0x02e9b, 0x02f47, 0x02f49, 0x02e9e, 0x02e9f,
+ 0x02ea0, 0x02ea1, 0x02ea2, 0x02ea3, 0x02ea4, 0x02ea4, 0x02ea6, 0x02f5c,
+ 0x02ea8, 0x02ea9, 0x02eaa, 0x02f6c, 0x02f70, 0x02ead, 0x02f75, 0x02eaf,
+ 0x02eb0, 0x02eb1, 0x02eb2, 0x02eb1, 0x02eb1, 0x02eb2, 0x02eb7, 0x02eb7,
+ 0x02eb8, 0x02eb9, 0x02eba, 0x02f80, 0x02f81, 0x02f85, 0x02ebe, 0x02ebe,
+ 0x02ebe, 0x02ec1, 0x02ec2, 0x02ec3, 0x02ec4, 0x02ec5, 0x02f93, 0x02f93,
+ 0x02ec8, 0x02ec9, 0x02f9c, 0x02ecb, 0x02ecc, 0x02ecc, 0x02ecc, 0x02fa2,
+ 0x02ed0, 0x02fa7, 0x02ed2, 0x02ed3, 0x02ed4, 0x02fa9, 0x02ed6, 0x02fac,
+ 0x02ed8, 0x02ed9, 0x02eda, 0x02edb, 0x02edc, 0x02fb7, 0x02ede, 0x02ede,
+ 0x02ee0, 0x02fb8, 0x02ee2, 0x02fbb, 0x02fc1, 0x02ee5, 0x02ee6, 0x02ee7,
+ 0x02ee8, 0x02ee9, 0x02eea, 0x02eeb, 0x02eec, 0x02eed, 0x02eee, 0x02eef,
+ 0x02ef0, 0x02ef2, 0x02ef2, 0x02ef3, 0x02ef4, 0x02ef5, 0x02ef6, 0x02ef7,
+ 0x02ef8, 0x02ef9, 0x02efa, 0x02efb, 0x02efc, 0x02efd, 0x02efe, 0x02eff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f[] = {
+ 0x03192, 0x02f01, 0x02e80, 0x02f03, 0x0319a, 0x02f05, 0x03193, 0x02f07,
+ 0x0319f, 0x02f09, 0x02f0a, 0x02f0b, 0x02e86, 0x02f0d, 0x02f0e, 0x02f0f,
+ 0x02f10, 0x02f11, 0x02f12, 0x02f13, 0x02f14, 0x02f15, 0x02f16, 0x02f17,
+ 0x02f18, 0x02e8b, 0x02e81, 0x02f1b, 0x02f1c, 0x02f1d, 0x02f1e, 0x02f1f,
+ 0x02f20, 0x02f21, 0x02f22, 0x02f23, 0x02f24, 0x02f25, 0x02f26, 0x02f27,
+ 0x02f28, 0x02f29, 0x02e8e, 0x02f2b, 0x02f2c, 0x02f2d, 0x02f2e, 0x02f2f,
+ 0x02f30, 0x02f31, 0x02f32, 0x02e93, 0x02f34, 0x02f35, 0x02f36, 0x02f37,
+ 0x02f38, 0x02e95, 0x02f3a, 0x02f3b, 0x02f3c, 0x02f3d, 0x02f3e, 0x02f3f,
+ 0x02f40, 0x02f41, 0x02f42, 0x02f43, 0x02f44, 0x02f45, 0x02f46, 0x02f47,
+ 0x02f48, 0x02f49, 0x02f4a, 0x02f4b, 0x02f4c, 0x02f4d, 0x02f4e, 0x02f4f,
+ 0x02f50, 0x02f51, 0x02f52, 0x02f53, 0x02f54, 0x02f55, 0x02f56, 0x02f57,
+ 0x02f58, 0x02f59, 0x02f5a, 0x02f5b, 0x02f5c, 0x02f5d, 0x02f5e, 0x02f5f,
+ 0x02f60, 0x02f61, 0x02f62, 0x02f63, 0x02f64, 0x02f65, 0x02eaa, 0x02f67,
+ 0x02f68, 0x02f69, 0x02f6a, 0x02f6b, 0x02f6c, 0x02f6d, 0x02f6e, 0x02f6f,
+ 0x02f70, 0x02f71, 0x02f72, 0x02f73, 0x02f74, 0x02f75, 0x02f76, 0x02f77,
+ 0x02f78, 0x02f79, 0x02eb7, 0x02f7b, 0x02f7c, 0x02f7d, 0x02f7e, 0x02f7f,
+ 0x02f80, 0x02f81, 0x02f82, 0x02f83, 0x02f84, 0x02f85, 0x02f86, 0x02f87,
+ 0x02f88, 0x02f89, 0x02f8a, 0x02f8b, 0x02f8c, 0x02f8d, 0x02f8e, 0x02f8f,
+ 0x02f90, 0x02f91, 0x02f92, 0x02f93, 0x02f94, 0x02f95, 0x02f96, 0x02f97,
+ 0x02f98, 0x02f99, 0x02f9a, 0x02f9b, 0x02f9c, 0x02f9d, 0x02f9e, 0x02f9f,
+ 0x02fa0, 0x02fa1, 0x02fa2, 0x02fa3, 0x02fa4, 0x02fa5, 0x02fa6, 0x02fa7,
+ 0x02fa8, 0x02fa9, 0x02faa, 0x02fab, 0x02fac, 0x02fad, 0x02fae, 0x02faf,
+ 0x02fb0, 0x02fb1, 0x02fb2, 0x02fb3, 0x02fb4, 0x02fb5, 0x02fb6, 0x02fb7,
+ 0x02fb8, 0x02fb9, 0x02fba, 0x02fbb, 0x02fbc, 0x02fbd, 0x02fbe, 0x02fbf,
+ 0x02fc0, 0x02fc1, 0x02fc2, 0x02fc3, 0x02ee7, 0x02fc5, 0x02fc6, 0x02fc7,
+ 0x02fc8, 0x02fc9, 0x02fca, 0x02fcb, 0x02fcc, 0x02fcd, 0x02fce, 0x02fcf,
+ 0x02fd0, 0x02eeb, 0x02eed, 0x02eef, 0x02ef2, 0x02fd5, 0x02fd6, 0x02fd7,
+ 0x02fd8, 0x02fd9, 0x02fda, 0x02fdb, 0x02fdc, 0x02fdd, 0x02fde, 0x02fdf,
+ 0x02fe0, 0x02fe1, 0x02fe2, 0x02fe3, 0x02fe4, 0x02fe5, 0x02fe6, 0x02fe7,
+ 0x02fe8, 0x02fe9, 0x02fea, 0x02feb, 0x02fec, 0x02fed, 0x02fee, 0x02fef,
+ 0x02ff0, 0x02ff1, 0x02ff2, 0x02ff3, 0x02ff4, 0x02ff5, 0x02ff6, 0x02ff7,
+ 0x02ff8, 0x02ff9, 0x02ffa, 0x02ffb, 0x02ffc, 0x02ffd, 0x02ffe, 0x02fff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_30[] = {
+ 0x00020, 0x03001, 0x03002, 0x03003, 0x03004, 0x03005, 0x03006, 0x00030,
+ 0x02329, 0x0232a, 0x0300a, 0x0300b, 0x0300c, 0x0300d, 0x0300e, 0x0300f,
+ 0x03010, 0x03011, 0x03012, 0x03013, 0x03014, 0x03015, 0x03016, 0x03017,
+ 0x03018, 0x03019, 0x0301a, 0x0301b, 0x0301c, 0x0301d, 0x0301e, 0x0301f,
+ 0x03020, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x03030, 0x03031, 0x03031, 0x03033, 0x03033, 0x03035, 0x03012, 0x03037,
+ 0x02f17, 0x03039, 0x0303a, 0x0303b, 0x0303c, 0x0303d, 0x0303e, 0x0303f,
+ 0x03040, 0x03041, 0x03042, 0x03043, 0x03044, 0x03045, 0x03046, 0x03047,
+ 0x03048, 0x03049, 0x0304a, 0x0304b, 0x0304c, 0x0304d, 0x0304e, 0x0304f,
+ 0x03050, 0x03051, 0x03052, 0x03053, 0x03054, 0x03055, 0x03056, 0x03057,
+ 0x03058, 0x03059, 0x0305a, 0x0305b, 0x0305c, 0x0305d, 0x0305e, 0x0305f,
+ 0x03060, 0x03061, 0x03062, 0x03063, 0x03064, 0x03065, 0x03066, 0x03067,
+ 0x03068, 0x03069, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x03070, 0x03071, 0x03072, 0x03073, 0x03074, 0x03075, 0x03076, 0x03077,
+ 0x03078, 0x03079, 0x0307a, 0x0307b, 0x0307c, 0x0307d, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03083, 0x03084, 0x03085, 0x03086, 0x03087,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308e, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x03097,
+ 0x03098, 0x00000, 0x00000, 0x0309b, 0x0309c, 0x0309d, 0x0309d, 0x0309f,
+ 0x030a0, 0x03041, 0x03042, 0x03043, 0x03044, 0x03045, 0x03046, 0x03047,
+ 0x03048, 0x03049, 0x0304a, 0x0304b, 0x0304c, 0x0304d, 0x0304e, 0x0304f,
+ 0x03050, 0x03051, 0x03052, 0x03053, 0x03054, 0x03055, 0x03056, 0x03057,
+ 0x03058, 0x03059, 0x0305a, 0x0305b, 0x0305c, 0x0305d, 0x0305e, 0x0305f,
+ 0x03060, 0x03061, 0x03062, 0x03063, 0x03064, 0x03065, 0x03066, 0x03067,
+ 0x03068, 0x03069, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x03070, 0x03071, 0x03072, 0x03073, 0x03074, 0x03075, 0x03076, 0x03077,
+ 0x03078, 0x03079, 0x0307a, 0x0307b, 0x0307c, 0x0307d, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03083, 0x03084, 0x03085, 0x03086, 0x03087,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308e, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x030fb, 0x030fc, 0x030fd, 0x030fd, 0x030ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_31[] = {
+ 0x03100, 0x03101, 0x03102, 0x03103, 0x03104, 0x03105, 0x03106, 0x03107,
+ 0x03108, 0x03109, 0x0310a, 0x0310b, 0x0310c, 0x0310d, 0x0310e, 0x0310f,
+ 0x03110, 0x03111, 0x03112, 0x03113, 0x03114, 0x03115, 0x03116, 0x03117,
+ 0x03118, 0x03119, 0x0311a, 0x0311b, 0x0311c, 0x0311d, 0x0311e, 0x0311f,
+ 0x03120, 0x03121, 0x03122, 0x03123, 0x03124, 0x03125, 0x03126, 0x03127,
+ 0x03128, 0x03129, 0x0312a, 0x0312b, 0x0312c, 0x0312d, 0x0312e, 0x0312f,
+ 0x03130, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x01161,
+ 0x01162, 0x01163, 0x01164, 0x01165, 0x01166, 0x01167, 0x01168, 0x01169,
+ 0x0116a, 0x0116b, 0x0116c, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171,
+ 0x01172, 0x01173, 0x01174, 0x01175, 0x01160, 0x01114, 0x01115, 0x011c7,
+ 0x011c8, 0x011cc, 0x011ce, 0x011d3, 0x011d7, 0x011d9, 0x0111c, 0x011dd,
+ 0x011df, 0x0111d, 0x0111e, 0x01120, 0x01122, 0x01123, 0x01127, 0x01129,
+ 0x0112b, 0x0112c, 0x0112d, 0x0112e, 0x0112f, 0x01132, 0x01136, 0x01140,
+ 0x01147, 0x0114c, 0x011f1, 0x011f2, 0x01157, 0x01158, 0x01159, 0x01184,
+ 0x01185, 0x01188, 0x01191, 0x01192, 0x01194, 0x0119e, 0x011a1, 0x0318f,
+ 0x03190, 0x03191, 0x03192, 0x03193, 0x03194, 0x03195, 0x03196, 0x03197,
+ 0x03198, 0x03199, 0x0319a, 0x0319b, 0x0319c, 0x0319d, 0x0319e, 0x0319f,
+ 0x03105, 0x03117, 0x03110, 0x0310d, 0x031a4, 0x031a4, 0x031a6, 0x0311b,
+ 0x03128, 0x0311a, 0x03127, 0x03128, 0x031ac, 0x031ad, 0x0311e, 0x03120,
+ 0x031b0, 0x031b1, 0x031b2, 0x03127, 0x03106, 0x0310a, 0x0310e, 0x0310f,
+ 0x031b8, 0x031b9, 0x031ba, 0x031bb, 0x031bc, 0x031bd, 0x031be, 0x031bf,
+ 0x031c0, 0x031c1, 0x031c2, 0x031c3, 0x031c4, 0x031c5, 0x031c6, 0x031c7,
+ 0x031c8, 0x031c9, 0x031ca, 0x031cb, 0x031cc, 0x031cd, 0x031ce, 0x031cf,
+ 0x031d0, 0x031d1, 0x031d2, 0x031d3, 0x031d4, 0x031d5, 0x031d6, 0x031d7,
+ 0x031d8, 0x031d9, 0x031da, 0x031db, 0x031dc, 0x031dd, 0x031de, 0x031df,
+ 0x031e0, 0x031e1, 0x031e2, 0x031e3, 0x031e4, 0x031e5, 0x031e6, 0x031e7,
+ 0x031e8, 0x031e9, 0x031ea, 0x031eb, 0x031ec, 0x031ed, 0x031ee, 0x031ef,
+ 0x0304f, 0x03057, 0x03059, 0x03068, 0x0306c, 0x0306f, 0x03072, 0x03075,
+ 0x03078, 0x0307b, 0x03080, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x031ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_32[] = {
+ 0x03200, 0x03201, 0x03202, 0x03203, 0x03204, 0x03205, 0x03206, 0x03207,
+ 0x03208, 0x03209, 0x0320a, 0x0320b, 0x0320c, 0x0320d, 0x0320e, 0x0320f,
+ 0x03210, 0x03211, 0x03212, 0x03213, 0x03214, 0x03215, 0x03216, 0x03217,
+ 0x03218, 0x03219, 0x0321a, 0x0321b, 0x0321c, 0x0321d, 0x0321e, 0x0321f,
+ 0x03220, 0x03221, 0x03222, 0x03223, 0x03224, 0x03225, 0x03226, 0x03227,
+ 0x03228, 0x03229, 0x0322a, 0x0322b, 0x0322c, 0x0322d, 0x0322e, 0x0322f,
+ 0x03230, 0x03231, 0x03232, 0x03233, 0x03234, 0x03235, 0x03236, 0x03237,
+ 0x03238, 0x03239, 0x0323a, 0x0323b, 0x0323c, 0x0323d, 0x0323e, 0x0323f,
+ 0x03240, 0x03241, 0x03242, 0x03243, 0x03244, 0x03245, 0x02f42, 0x03247,
+ 0x02469, 0x02473, 0x0324a, 0x0324b, 0x0324c, 0x0324d, 0x0324e, 0x0324f,
+ 0x03250, 0x03251, 0x03252, 0x03253, 0x03254, 0x03255, 0x03256, 0x03257,
+ 0x03258, 0x03259, 0x0324a, 0x0325b, 0x0325c, 0x0325d, 0x0325e, 0x0325f,
+ 0x01100, 0x01102, 0x01103, 0x01105, 0x01106, 0x01107, 0x01109, 0x0110b,
+ 0x0110c, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0326e, 0x0326f,
+ 0x03270, 0x03271, 0x03272, 0x03273, 0x03274, 0x03275, 0x03276, 0x03277,
+ 0x03278, 0x03279, 0x0327a, 0x0327b, 0x0327c, 0x0327d, 0x0327e, 0x0327f,
+ 0x03192, 0x03193, 0x03194, 0x03195, 0x03284, 0x03285, 0x03286, 0x02f0b,
+ 0x03288, 0x02f17, 0x02f49, 0x02f55, 0x02f54, 0x02f4a, 0x02fa6, 0x02f1f,
+ 0x02f47, 0x03291, 0x03292, 0x03293, 0x03294, 0x03295, 0x03296, 0x03297,
+ 0x03298, 0x03299, 0x0329a, 0x02f25, 0x0329c, 0x0329d, 0x0329e, 0x0329f,
+ 0x032a0, 0x032a1, 0x032a2, 0x032a3, 0x03196, 0x03197, 0x03198, 0x032a7,
+ 0x032a8, 0x032a9, 0x032aa, 0x032ab, 0x032ac, 0x032ad, 0x032ae, 0x032af,
+ 0x032b0, 0x032b1, 0x032b2, 0x032b3, 0x032b4, 0x0324b, 0x032b6, 0x032b7,
+ 0x032b8, 0x032b9, 0x032ba, 0x032bb, 0x032bc, 0x032bd, 0x032be, 0x0324c,
+ 0x032c0, 0x032c1, 0x032c2, 0x032c3, 0x032c4, 0x032c5, 0x032c6, 0x032c7,
+ 0x032c8, 0x032c9, 0x032ca, 0x032cb, 0x032cc, 0x032cd, 0x032ce, 0x032cf,
+ 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d, 0x0304f,
+ 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d, 0x0305f,
+ 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d,
+ 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089, 0x0308a,
+ 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03090, 0x03091, 0x03092, 0x032ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_33[] = {
+ 0x03300, 0x03301, 0x03302, 0x03303, 0x03304, 0x03305, 0x03306, 0x03307,
+ 0x03308, 0x03309, 0x0330a, 0x0330b, 0x0330c, 0x0330d, 0x0330e, 0x0330f,
+ 0x03310, 0x03311, 0x03312, 0x03313, 0x03314, 0x03315, 0x03316, 0x03317,
+ 0x03318, 0x03319, 0x0331a, 0x0331b, 0x0331c, 0x0331d, 0x0331e, 0x0331f,
+ 0x03320, 0x03321, 0x03322, 0x03323, 0x03324, 0x03325, 0x03326, 0x03327,
+ 0x03328, 0x03329, 0x0332a, 0x0332b, 0x0332c, 0x0332d, 0x0332e, 0x0332f,
+ 0x03330, 0x03331, 0x03332, 0x03333, 0x03334, 0x03335, 0x03336, 0x03337,
+ 0x03338, 0x03339, 0x0333a, 0x0333b, 0x0333c, 0x0333d, 0x0333e, 0x0333f,
+ 0x03340, 0x03341, 0x03342, 0x03343, 0x03344, 0x03345, 0x03346, 0x03347,
+ 0x03348, 0x03349, 0x0334a, 0x0334b, 0x0334c, 0x0334d, 0x0334e, 0x0334f,
+ 0x03350, 0x03351, 0x03352, 0x03353, 0x03354, 0x03355, 0x03356, 0x03357,
+ 0x03358, 0x03359, 0x0335a, 0x0335b, 0x0335c, 0x0335d, 0x0335e, 0x0335f,
+ 0x03360, 0x03361, 0x03362, 0x03363, 0x03364, 0x03365, 0x03366, 0x03367,
+ 0x03368, 0x03369, 0x0336a, 0x0336b, 0x0336c, 0x0336d, 0x0336e, 0x0336f,
+ 0x03370, 0x03371, 0x03372, 0x03373, 0x03374, 0x03375, 0x03376, 0x03377,
+ 0x03378, 0x03379, 0x0337a, 0x0337b, 0x0337c, 0x0337d, 0x0337e, 0x0337f,
+ 0x03380, 0x03381, 0x03382, 0x03383, 0x03384, 0x03385, 0x03386, 0x03387,
+ 0x03388, 0x03389, 0x0338a, 0x0338b, 0x0338c, 0x0338d, 0x0338e, 0x0338f,
+ 0x03390, 0x03391, 0x03392, 0x03393, 0x03394, 0x03395, 0x03396, 0x03397,
+ 0x03398, 0x03399, 0x0339a, 0x0339b, 0x0339c, 0x0339d, 0x0339e, 0x0339f,
+ 0x033a0, 0x033a1, 0x033a2, 0x033a3, 0x033a4, 0x033a5, 0x033a6, 0x033a7,
+ 0x033a8, 0x03380, 0x033aa, 0x033ab, 0x033ac, 0x033ad, 0x033ae, 0x033af,
+ 0x033b0, 0x033b1, 0x033b2, 0x033b3, 0x033b4, 0x033b5, 0x033b6, 0x033b7,
+ 0x033b8, 0x033b7, 0x033ba, 0x033bb, 0x033bc, 0x033bd, 0x033be, 0x033bd,
+ 0x033c0, 0x033c1, 0x033c2, 0x033c3, 0x033c4, 0x033c5, 0x033c6, 0x033c7,
+ 0x00238, 0x033c9, 0x033ca, 0x033cb, 0x033cc, 0x033cd, 0x0339e, 0x033cf,
+ 0x033d0, 0x033d1, 0x033d2, 0x033d3, 0x03386, 0x033d5, 0x033d6, 0x033d7,
+ 0x033d8, 0x033d9, 0x033da, 0x033db, 0x033dc, 0x033dd, 0x033de, 0x033df,
+ 0x033e0, 0x033e1, 0x033e2, 0x033e3, 0x033e4, 0x033e5, 0x033e6, 0x033e7,
+ 0x033e8, 0x033e9, 0x033ea, 0x033eb, 0x033ec, 0x033ed, 0x033ee, 0x033ef,
+ 0x033f0, 0x033f1, 0x033f2, 0x033f3, 0x033f4, 0x033f5, 0x033f6, 0x033f7,
+ 0x033f8, 0x033f9, 0x033fa, 0x033fb, 0x033fc, 0x033fd, 0x033fe, 0x033ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a6[] = {
+ 0x0a600, 0x0a601, 0x0a602, 0x0a603, 0x0a604, 0x0a605, 0x0a606, 0x0a607,
+ 0x0a608, 0x0a609, 0x0a60a, 0x0a60b, 0x0a60c, 0x0a60d, 0x0a60e, 0x0a60f,
+ 0x0a558, 0x0a56a, 0x0a587, 0x0a613, 0x0a614, 0x0a615, 0x0a616, 0x0a617,
+ 0x0a618, 0x0a619, 0x0a61a, 0x0a61b, 0x0a61c, 0x0a61d, 0x0a61e, 0x0a61f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a56e, 0x0a5d1, 0x0a62c, 0x0a62d, 0x0a62e, 0x0a62f,
+ 0x0a630, 0x0a631, 0x0a632, 0x0a633, 0x0a634, 0x0a635, 0x0a636, 0x0a637,
+ 0x0a638, 0x0a639, 0x0a63a, 0x0a63b, 0x0a63c, 0x0a63d, 0x0a63e, 0x0a63f,
+ 0x0a640, 0x0a640, 0x0a642, 0x0a642, 0x0a644, 0x0a644, 0x0a646, 0x0a646,
+ 0x02df8, 0x02df8, 0x02df9, 0x02df9, 0x0a64c, 0x0a64c, 0x0a64e, 0x0a64e,
+ 0x0a650, 0x0a650, 0x0a652, 0x0a652, 0x0a654, 0x0a654, 0x02dfc, 0x02dfc,
+ 0x0a658, 0x0a658, 0x0a65a, 0x0a65a, 0x0a65c, 0x0a65c, 0x0a65e, 0x0a65e,
+ 0x0a660, 0x0a661, 0x0a662, 0x0a662, 0x0a664, 0x0a664, 0x0a666, 0x0a666,
+ 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0a673, 0x0a674, 0x0a675, 0x0a676, 0x0a677,
+ 0x0a678, 0x0a679, 0x0a67a, 0x0a67b, 0x00000, 0x00000, 0x0a67e, 0x0a67f,
+ 0x0a680, 0x0a680, 0x0a682, 0x0a682, 0x0a684, 0x0a684, 0x0a686, 0x0a686,
+ 0x0a688, 0x0a688, 0x0a68a, 0x0a68a, 0x0a68c, 0x0a68c, 0x0a68e, 0x0a68e,
+ 0x0a690, 0x0a690, 0x0a692, 0x0a692, 0x0a694, 0x0a694, 0x0a696, 0x0a696,
+ 0x0a698, 0x0a699, 0x0a69a, 0x0a69b, 0x0a69c, 0x0a69d, 0x0a69e, 0x0a69f,
+ 0x0a6a0, 0x0a6a1, 0x0a6a2, 0x0a6a3, 0x0a6a4, 0x0a6a5, 0x0a6a6, 0x0a6a7,
+ 0x0a6a8, 0x0a6a9, 0x0a6aa, 0x0a6ab, 0x0a6ac, 0x0a6ad, 0x0a6ae, 0x0a6af,
+ 0x0a6b0, 0x0a6b1, 0x0a6b2, 0x0a6b3, 0x0a6b4, 0x0a6b5, 0x0a6b6, 0x0a6b7,
+ 0x0a6b8, 0x0a6b9, 0x0a6ba, 0x0a6bb, 0x0a6bc, 0x0a6bd, 0x0a6be, 0x0a6bf,
+ 0x0a6c0, 0x0a6c1, 0x0a6c2, 0x0a6c3, 0x0a6c4, 0x0a6c5, 0x0a6c6, 0x0a6c7,
+ 0x0a6c8, 0x0a6c9, 0x0a6ca, 0x0a6cb, 0x0a6cc, 0x0a6cd, 0x0a6ce, 0x0a6cf,
+ 0x0a6d0, 0x0a6d1, 0x0a6d2, 0x0a6d3, 0x0a6d4, 0x0a6d5, 0x0a6d6, 0x0a6d7,
+ 0x0a6d8, 0x0a6d9, 0x0a6da, 0x0a6db, 0x0a6dc, 0x0a6dd, 0x0a6de, 0x0a6df,
+ 0x0a6e0, 0x0a6e1, 0x0a6e2, 0x0a6e3, 0x0a6e4, 0x0a6e5, 0x0a6e6, 0x0a6e7,
+ 0x0a6e8, 0x0a6e9, 0x0a6ea, 0x0a6eb, 0x0a6ec, 0x0a6ed, 0x0a6ee, 0x0a6ef,
+ 0x00000, 0x00000, 0x0a6f2, 0x0a6f3, 0x0a6f4, 0x0a6f5, 0x0a6f6, 0x0a6f7,
+ 0x0a6f8, 0x0a6f9, 0x0a6fa, 0x0a6fb, 0x0a6fc, 0x0a6fd, 0x0a6fe, 0x0a6ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a7[] = {
+ 0x0a700, 0x0a701, 0x0a702, 0x0a703, 0x0a704, 0x0a705, 0x0a706, 0x0a707,
+ 0x0a708, 0x0a709, 0x0a70a, 0x0a70b, 0x0a70c, 0x0a70d, 0x0a70e, 0x0a70f,
+ 0x0a710, 0x0a711, 0x0a712, 0x0a713, 0x0a714, 0x0a715, 0x0a716, 0x0a717,
+ 0x0a718, 0x0a719, 0x0a71a, 0x0a71b, 0x0a71c, 0x0a71d, 0x0a71e, 0x0a71f,
+ 0x0a720, 0x0a721, 0x0a722, 0x0a722, 0x0a724, 0x0a724, 0x0a726, 0x0a726,
+ 0x0a728, 0x0a728, 0x0a72a, 0x0a72a, 0x0a72c, 0x0a72c, 0x0a72e, 0x0a72e,
+ 0x0a730, 0x0a731, 0x0a732, 0x0a732, 0x01dd5, 0x01dd5, 0x03373, 0x03373,
+ 0x01dd6, 0x01dd6, 0x01dd6, 0x01dd6, 0x0a73c, 0x0a73c, 0x0a73e, 0x0a73e,
+ 0x0a740, 0x0a740, 0x0a742, 0x0a742, 0x0a744, 0x0a744, 0x0a746, 0x0a746,
+ 0x0a748, 0x0a748, 0x0a74a, 0x0a74a, 0x0a74c, 0x0a74c, 0x0a74e, 0x0a74e,
+ 0x0a750, 0x0a750, 0x0a752, 0x0a752, 0x0a754, 0x0a754, 0x0a756, 0x0a756,
+ 0x0a758, 0x0a758, 0x01de3, 0x01de3, 0x0a75c, 0x0a75c, 0x0a75e, 0x0a75e,
+ 0x0a760, 0x0a760, 0x0a762, 0x0a762, 0x0a764, 0x0a764, 0x0a766, 0x0a766,
+ 0x0a768, 0x0a768, 0x0a76a, 0x0a76a, 0x0a76c, 0x0a76c, 0x01dd2, 0x01dd2,
+ 0x01dd2, 0x0a771, 0x0a772, 0x0a773, 0x0a774, 0x0a775, 0x0a776, 0x0a777,
+ 0x0a778, 0x00044, 0x00044, 0x00046, 0x00046, 0x00047, 0x0a77e, 0x0a77e,
+ 0x0a780, 0x0a780, 0x00052, 0x00052, 0x00053, 0x00053, 0x00054, 0x00054,
+ 0x0a788, 0x0a789, 0x0a78a, 0x0a78b, 0x0a78b, 0x0a78d, 0x0a78e, 0x0a78f,
+ 0x0a790, 0x0a791, 0x0a792, 0x0a793, 0x0a794, 0x0a795, 0x0a796, 0x0a797,
+ 0x0a798, 0x0a799, 0x0a79a, 0x0a79b, 0x0a79c, 0x0a79d, 0x0a79e, 0x0a79f,
+ 0x0a7a0, 0x0a7a1, 0x0a7a2, 0x0a7a3, 0x0a7a4, 0x0a7a5, 0x0a7a6, 0x0a7a7,
+ 0x0a7a8, 0x0a7a9, 0x0a7aa, 0x0a7ab, 0x0a7ac, 0x0a7ad, 0x0a7ae, 0x0a7af,
+ 0x0a7b0, 0x0a7b1, 0x0a7b2, 0x0a7b3, 0x0a7b4, 0x0a7b5, 0x0a7b6, 0x0a7b7,
+ 0x0a7b8, 0x0a7b9, 0x0a7ba, 0x0a7bb, 0x0a7bc, 0x0a7bd, 0x0a7be, 0x0a7bf,
+ 0x0a7c0, 0x0a7c1, 0x0a7c2, 0x0a7c3, 0x0a7c4, 0x0a7c5, 0x0a7c6, 0x0a7c7,
+ 0x0a7c8, 0x0a7c9, 0x0a7ca, 0x0a7cb, 0x0a7cc, 0x0a7cd, 0x0a7ce, 0x0a7cf,
+ 0x0a7d0, 0x0a7d1, 0x0a7d2, 0x0a7d3, 0x0a7d4, 0x0a7d5, 0x0a7d6, 0x0a7d7,
+ 0x0a7d8, 0x0a7d9, 0x0a7da, 0x0a7db, 0x0a7dc, 0x0a7dd, 0x0a7de, 0x0a7df,
+ 0x0a7e0, 0x0a7e1, 0x0a7e2, 0x0a7e3, 0x0a7e4, 0x0a7e5, 0x0a7e6, 0x0a7e7,
+ 0x0a7e8, 0x0a7e9, 0x0a7ea, 0x0a7eb, 0x0a7ec, 0x0a7ed, 0x0a7ee, 0x0a7ef,
+ 0x0a7f0, 0x0a7f1, 0x0a7f2, 0x0a7f3, 0x0a7f4, 0x0a7f5, 0x0a7f6, 0x0a7f7,
+ 0x0a7f8, 0x0a7f9, 0x0a7fa, 0x0a7fb, 0x0a7fc, 0x0a7fd, 0x0a7fe, 0x0a7ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a8[] = {
+ 0x0a800, 0x0a801, 0x0a802, 0x0a803, 0x0a804, 0x0a805, 0x0a806, 0x0a807,
+ 0x0a808, 0x0a809, 0x0a80a, 0x00000, 0x0a80c, 0x0a80d, 0x0a80e, 0x0a80f,
+ 0x0a810, 0x0a811, 0x0a812, 0x0a813, 0x0a814, 0x0a815, 0x0a816, 0x0a817,
+ 0x0a818, 0x0a819, 0x0a81a, 0x0a81b, 0x0a81c, 0x0a81d, 0x0a81e, 0x0a81f,
+ 0x0a820, 0x0a821, 0x0a822, 0x0a823, 0x0a824, 0x0a825, 0x0a826, 0x0a827,
+ 0x0a828, 0x0a829, 0x0a82a, 0x0a82b, 0x0a82c, 0x0a82d, 0x0a82e, 0x0a82f,
+ 0x0a830, 0x0a831, 0x0a832, 0x0a833, 0x0a834, 0x0a835, 0x0a836, 0x0a837,
+ 0x0a838, 0x0a839, 0x0a83a, 0x0a83b, 0x0a83c, 0x0a83d, 0x0a83e, 0x0a83f,
+ 0x0a840, 0x0a841, 0x0a842, 0x0a843, 0x0a844, 0x0a845, 0x0a846, 0x0a847,
+ 0x0a848, 0x0a849, 0x0a84a, 0x0a84b, 0x0a84c, 0x0a84d, 0x0a84e, 0x0a84f,
+ 0x0a850, 0x0a851, 0x0a852, 0x0a853, 0x0a854, 0x0a855, 0x0a856, 0x0a857,
+ 0x0a858, 0x0a859, 0x0a85a, 0x0a85b, 0x0a85c, 0x0a85d, 0x0a85e, 0x0a85f,
+ 0x0a860, 0x0a861, 0x0a862, 0x0a863, 0x0a864, 0x0a865, 0x0a866, 0x0a867,
+ 0x0a868, 0x0a869, 0x0a86a, 0x0a86b, 0x0a86c, 0x0a86d, 0x0a86e, 0x0a86f,
+ 0x0a870, 0x0a871, 0x0a872, 0x0a873, 0x0a874, 0x0a875, 0x0a876, 0x0a877,
+ 0x0a878, 0x0a879, 0x0a87a, 0x0a87b, 0x0a87c, 0x0a87d, 0x0a87e, 0x0a87f,
+ 0x00000, 0x00000, 0x0a882, 0x0a883, 0x0a884, 0x0a885, 0x0a886, 0x0a887,
+ 0x0a888, 0x0a889, 0x0a88a, 0x0a88b, 0x0a88c, 0x0a88d, 0x0a88e, 0x0a88f,
+ 0x0a890, 0x0a891, 0x0a892, 0x0a893, 0x0a894, 0x0a895, 0x0a896, 0x0a897,
+ 0x0a898, 0x0a899, 0x0a89a, 0x0a89b, 0x0a89c, 0x0a89d, 0x0a89e, 0x0a89f,
+ 0x0a8a0, 0x0a8a1, 0x0a8a2, 0x0a8a3, 0x0a8a4, 0x0a8a5, 0x0a8a6, 0x0a8a7,
+ 0x0a8a8, 0x0a8a9, 0x0a8aa, 0x0a8ab, 0x0a8ac, 0x0a8ad, 0x0a8ae, 0x0a8af,
+ 0x0a8b0, 0x0a8b1, 0x0a8b2, 0x0a8b3, 0x0a8b4, 0x0a8b5, 0x0a8b6, 0x0a8b7,
+ 0x0a8b8, 0x0a8b9, 0x0a8ba, 0x0a8bb, 0x0a8bc, 0x0a8bd, 0x0a8be, 0x0a8bf,
+ 0x0a8c0, 0x0a8c1, 0x0a8c2, 0x0a8c3, 0x0a8c4, 0x0a8c5, 0x0a8c6, 0x0a8c7,
+ 0x0a8c8, 0x0a8c9, 0x0a8ca, 0x0a8cb, 0x0a8cc, 0x0a8cd, 0x0a8ce, 0x0a8cf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a8da, 0x0a8db, 0x0a8dc, 0x0a8dd, 0x0a8de, 0x0a8df,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x0a8f2, 0x0a8f2, 0x0a8f2, 0x0a8f2, 0x0a8f2, 0x0a8f2,
+ 0x0a8f8, 0x0a8f9, 0x0a8fa, 0x0a8fb, 0x0a8fc, 0x0a8fd, 0x0a8fe, 0x0a8ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a9[] = {
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a90a, 0x0a90b, 0x0a90c, 0x0a90d, 0x0a90e, 0x0a90f,
+ 0x0a910, 0x0a911, 0x0a912, 0x0a913, 0x0a914, 0x0a915, 0x0a916, 0x0a917,
+ 0x0a918, 0x0a919, 0x0a91a, 0x0a91b, 0x0a91c, 0x0a91d, 0x0a91e, 0x0a91f,
+ 0x0a920, 0x0a921, 0x0a922, 0x0a923, 0x0a924, 0x0a925, 0x0a926, 0x0a927,
+ 0x0a928, 0x0a929, 0x0a92a, 0x00000, 0x00000, 0x00000, 0x0a92e, 0x0a92f,
+ 0x0a930, 0x0a931, 0x0a932, 0x0a933, 0x0a934, 0x0a935, 0x0a936, 0x0a937,
+ 0x0a938, 0x0a939, 0x0a93a, 0x0a93b, 0x0a93c, 0x0a93d, 0x0a93e, 0x0a93f,
+ 0x0a940, 0x0a941, 0x0a942, 0x0a943, 0x0a944, 0x0a945, 0x0a946, 0x0a947,
+ 0x0a948, 0x0a949, 0x0a94a, 0x0a94b, 0x0a94c, 0x0a94d, 0x0a94e, 0x0a94f,
+ 0x0a950, 0x0a951, 0x0a952, 0x0a953, 0x0a954, 0x0a955, 0x0a956, 0x0a957,
+ 0x0a958, 0x0a959, 0x0a95a, 0x0a95b, 0x0a95c, 0x0a95d, 0x0a95e, 0x0a95f,
+ 0x0a960, 0x0a961, 0x0a962, 0x0a963, 0x0a964, 0x0a965, 0x0a966, 0x0a967,
+ 0x0a968, 0x0a969, 0x0a96a, 0x0a96b, 0x0a96c, 0x0a96d, 0x0a96e, 0x0a96f,
+ 0x0a970, 0x0a971, 0x0a972, 0x0a973, 0x0a974, 0x0a975, 0x0a976, 0x0a977,
+ 0x0a978, 0x0a979, 0x0a97a, 0x0a97b, 0x0a97c, 0x0a97d, 0x0a97e, 0x0a97f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0a984, 0x0a985, 0x0a986, 0x0a987,
+ 0x0a988, 0x0a989, 0x0a98a, 0x0a98b, 0x0a98c, 0x0a98d, 0x0a98e, 0x0a98f,
+ 0x0a990, 0x0a991, 0x0a992, 0x0a993, 0x0a994, 0x0a995, 0x0a996, 0x0a997,
+ 0x0a998, 0x0a999, 0x0a99a, 0x0a99b, 0x0a99c, 0x0a99d, 0x0a99e, 0x0a99f,
+ 0x0a9a0, 0x0a9a1, 0x0a9a2, 0x0a9a3, 0x0a9a4, 0x0a9a5, 0x0a9a6, 0x0a9a7,
+ 0x0a9a8, 0x0a9a9, 0x0a9aa, 0x0a9ab, 0x0a9ab, 0x0a9ad, 0x0a9ae, 0x0a9af,
+ 0x0a9b0, 0x0a9b1, 0x0a9b2, 0x00000, 0x0a9b4, 0x0a9b5, 0x0a9b6, 0x0a9b7,
+ 0x0a9b8, 0x0a9b9, 0x0a9ba, 0x0a9bb, 0x0a9bc, 0x0a9bd, 0x0a9be, 0x0a9bf,
+ 0x0a9c0, 0x0a9c1, 0x0a9c2, 0x0a9c3, 0x0a9c4, 0x0a9c5, 0x0a9c6, 0x0a9c7,
+ 0x0a9c8, 0x0a9c9, 0x0a9ca, 0x0a9cb, 0x0a9cc, 0x0a9cd, 0x0a9ce, 0x0a9cf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a9da, 0x0a9db, 0x0a9dc, 0x0a9dd, 0x0a9de, 0x0a9df,
+ 0x0a9e0, 0x0a9e1, 0x0a9e2, 0x0a9e3, 0x0a9e4, 0x0a9e5, 0x0a9e6, 0x0a9e7,
+ 0x0a9e8, 0x0a9e9, 0x0a9ea, 0x0a9eb, 0x0a9ec, 0x0a9ed, 0x0a9ee, 0x0a9ef,
+ 0x0a9f0, 0x0a9f1, 0x0a9f2, 0x0a9f3, 0x0a9f4, 0x0a9f5, 0x0a9f6, 0x0a9f7,
+ 0x0a9f8, 0x0a9f9, 0x0a9fa, 0x0a9fb, 0x0a9fc, 0x0a9fd, 0x0a9fe, 0x0a9ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_aa[] = {
+ 0x0aa00, 0x0aa01, 0x0aa02, 0x0aa03, 0x0aa04, 0x0aa05, 0x0aa06, 0x0aa07,
+ 0x0aa08, 0x0aa09, 0x0aa0a, 0x0aa0b, 0x0aa0c, 0x0aa0d, 0x0aa0e, 0x0aa0f,
+ 0x0aa10, 0x0aa11, 0x0aa12, 0x0aa13, 0x0aa14, 0x0aa15, 0x0aa16, 0x0aa17,
+ 0x0aa18, 0x0aa19, 0x0aa1a, 0x0aa1b, 0x0aa1c, 0x0aa1d, 0x0aa1e, 0x0aa1f,
+ 0x0aa20, 0x0aa21, 0x0aa22, 0x0aa23, 0x0aa24, 0x0aa25, 0x0aa26, 0x0aa27,
+ 0x0aa28, 0x0aa29, 0x0aa2a, 0x0aa2b, 0x0aa2c, 0x0aa2d, 0x0aa2e, 0x0aa2f,
+ 0x0aa30, 0x0aa31, 0x0aa32, 0x0aa33, 0x0aa34, 0x0aa35, 0x0aa36, 0x0aa37,
+ 0x0aa38, 0x0aa39, 0x0aa3a, 0x0aa3b, 0x0aa3c, 0x0aa3d, 0x0aa3e, 0x0aa3f,
+ 0x0aa40, 0x0aa41, 0x0aa42, 0x0aa43, 0x0aa44, 0x0aa45, 0x0aa46, 0x0aa47,
+ 0x0aa48, 0x0aa49, 0x0aa4a, 0x0aa4b, 0x0aa4c, 0x0aa4d, 0x0aa4e, 0x0aa4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0aa5a, 0x0aa5b, 0x0aa5c, 0x0aa5d, 0x0aa5e, 0x0aa5f,
+ 0x0aa60, 0x0aa61, 0x0aa62, 0x0aa63, 0x0aa64, 0x0aa65, 0x0aa66, 0x0aa67,
+ 0x0aa68, 0x0aa69, 0x0aa6a, 0x0aa6b, 0x0aa6c, 0x0aa6d, 0x0aa6e, 0x0aa6f,
+ 0x0aa70, 0x0aa71, 0x0aa72, 0x0aa73, 0x0aa74, 0x0aa75, 0x0aa76, 0x0aa77,
+ 0x0aa78, 0x0aa79, 0x0aa7a, 0x0aa7b, 0x0aa7c, 0x0aa7d, 0x0aa7e, 0x0aa7f,
+ 0x0aa80, 0x0aa81, 0x0aa82, 0x0aa83, 0x0aa84, 0x0aa85, 0x0aa86, 0x0aa87,
+ 0x0aa88, 0x0aa89, 0x0aa8a, 0x0aa8b, 0x0aa8c, 0x0aa8d, 0x0aa8e, 0x0aa8f,
+ 0x0aa90, 0x0aa91, 0x0aa92, 0x0aa93, 0x0aa94, 0x0aa95, 0x0aa96, 0x0aa97,
+ 0x0aa98, 0x0aa99, 0x0aa9a, 0x0aa9b, 0x0aa9c, 0x0aa9d, 0x0aa9e, 0x0aa9f,
+ 0x0aaa0, 0x0aaa1, 0x0aaa2, 0x0aaa3, 0x0aaa4, 0x0aaa5, 0x0aaa6, 0x0aaa7,
+ 0x0aaa8, 0x0aaa9, 0x0aaaa, 0x0aaab, 0x0aaac, 0x0aaad, 0x0aaae, 0x0aaaf,
+ 0x0aab0, 0x0aab1, 0x0aab2, 0x0aab3, 0x0aab4, 0x0aab5, 0x0aab6, 0x0aab7,
+ 0x0aab8, 0x0aab9, 0x0aaba, 0x0aabb, 0x0aabc, 0x0aabd, 0x0aabe, 0x00000,
+ 0x0aac0, 0x00000, 0x0aac2, 0x0aac3, 0x0aac4, 0x0aac5, 0x0aac6, 0x0aac7,
+ 0x0aac8, 0x0aac9, 0x0aaca, 0x0aacb, 0x0aacc, 0x0aacd, 0x0aace, 0x0aacf,
+ 0x0aad0, 0x0aad1, 0x0aad2, 0x0aad3, 0x0aad4, 0x0aad5, 0x0aad6, 0x0aad7,
+ 0x0aad8, 0x0aad9, 0x0aada, 0x0aadb, 0x0aadc, 0x0aadd, 0x0aade, 0x0aadf,
+ 0x0aae0, 0x0aae1, 0x0aae2, 0x0aae3, 0x0aae4, 0x0aae5, 0x0aae6, 0x0aae7,
+ 0x0aae8, 0x0aae9, 0x0aaea, 0x0aaeb, 0x0aaec, 0x0aaed, 0x0aaee, 0x0aaef,
+ 0x0aaf0, 0x0aaf1, 0x0aaf2, 0x0aaf3, 0x0aaf4, 0x0aaf5, 0x0aaf6, 0x0aaf7,
+ 0x0aaf8, 0x0aaf9, 0x0aafa, 0x0aafb, 0x0aafc, 0x0aafd, 0x0aafe, 0x0aaff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_ab[] = {
+ 0x0ab00, 0x0ab01, 0x0ab02, 0x0ab03, 0x0ab04, 0x0ab05, 0x0ab06, 0x0ab07,
+ 0x0ab08, 0x0ab09, 0x0ab0a, 0x0ab0b, 0x0ab0c, 0x0ab0d, 0x0ab0e, 0x0ab0f,
+ 0x0ab10, 0x0ab11, 0x0ab12, 0x0ab13, 0x0ab14, 0x0ab15, 0x0ab16, 0x0ab17,
+ 0x0ab18, 0x0ab19, 0x0ab1a, 0x0ab1b, 0x0ab1c, 0x0ab1d, 0x0ab1e, 0x0ab1f,
+ 0x0ab20, 0x0ab21, 0x0ab22, 0x0ab23, 0x0ab24, 0x0ab25, 0x0ab26, 0x0ab27,
+ 0x0ab28, 0x0ab29, 0x0ab2a, 0x0ab2b, 0x0ab2c, 0x0ab2d, 0x0ab2e, 0x0ab2f,
+ 0x0ab30, 0x0ab31, 0x0ab32, 0x0ab33, 0x0ab34, 0x0ab35, 0x0ab36, 0x0ab37,
+ 0x0ab38, 0x0ab39, 0x0ab3a, 0x0ab3b, 0x0ab3c, 0x0ab3d, 0x0ab3e, 0x0ab3f,
+ 0x0ab40, 0x0ab41, 0x0ab42, 0x0ab43, 0x0ab44, 0x0ab45, 0x0ab46, 0x0ab47,
+ 0x0ab48, 0x0ab49, 0x0ab4a, 0x0ab4b, 0x0ab4c, 0x0ab4d, 0x0ab4e, 0x0ab4f,
+ 0x0ab50, 0x0ab51, 0x0ab52, 0x0ab53, 0x0ab54, 0x0ab55, 0x0ab56, 0x0ab57,
+ 0x0ab58, 0x0ab59, 0x0ab5a, 0x0ab5b, 0x0ab5c, 0x0ab5d, 0x0ab5e, 0x0ab5f,
+ 0x0ab60, 0x0ab61, 0x0ab62, 0x0ab63, 0x0ab64, 0x0ab65, 0x0ab66, 0x0ab67,
+ 0x0ab68, 0x0ab69, 0x0ab6a, 0x0ab6b, 0x0ab6c, 0x0ab6d, 0x0ab6e, 0x0ab6f,
+ 0x0ab70, 0x0ab71, 0x0ab72, 0x0ab73, 0x0ab74, 0x0ab75, 0x0ab76, 0x0ab77,
+ 0x0ab78, 0x0ab79, 0x0ab7a, 0x0ab7b, 0x0ab7c, 0x0ab7d, 0x0ab7e, 0x0ab7f,
+ 0x0ab80, 0x0ab81, 0x0ab82, 0x0ab83, 0x0ab84, 0x0ab85, 0x0ab86, 0x0ab87,
+ 0x0ab88, 0x0ab89, 0x0ab8a, 0x0ab8b, 0x0ab8c, 0x0ab8d, 0x0ab8e, 0x0ab8f,
+ 0x0ab90, 0x0ab91, 0x0ab92, 0x0ab93, 0x0ab94, 0x0ab95, 0x0ab96, 0x0ab97,
+ 0x0ab98, 0x0ab99, 0x0ab9a, 0x0ab9b, 0x0ab9c, 0x0ab9d, 0x0ab9e, 0x0ab9f,
+ 0x0aba0, 0x0aba1, 0x0aba2, 0x0aba3, 0x0aba4, 0x0aba5, 0x0aba6, 0x0aba7,
+ 0x0aba8, 0x0aba9, 0x0abaa, 0x0abab, 0x0abac, 0x0abad, 0x0abae, 0x0abaf,
+ 0x0abb0, 0x0abb1, 0x0abb2, 0x0abb3, 0x0abb4, 0x0abb5, 0x0abb6, 0x0abb7,
+ 0x0abb8, 0x0abb9, 0x0abba, 0x0abbb, 0x0abbc, 0x0abbd, 0x0abbe, 0x0abbf,
+ 0x0abc0, 0x0abc1, 0x0abc2, 0x0abc3, 0x0abc4, 0x0abc5, 0x0abc6, 0x0abc7,
+ 0x0abc8, 0x0abc9, 0x0abca, 0x0abcb, 0x0abcc, 0x0abcd, 0x0abce, 0x0abcf,
+ 0x0abd0, 0x0abd1, 0x0abd2, 0x0abd3, 0x0abd4, 0x0abd5, 0x0abd6, 0x0abd7,
+ 0x0abd8, 0x0abd9, 0x0abda, 0x0abdb, 0x0abdc, 0x0abdd, 0x0abde, 0x0abdf,
+ 0x0abe0, 0x0abe1, 0x0abe2, 0x0abe3, 0x0abe4, 0x0abe5, 0x0abe6, 0x0abe7,
+ 0x0abe8, 0x0abe9, 0x0abea, 0x0abeb, 0x00000, 0x0abed, 0x0abee, 0x0abef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0abfa, 0x0abfb, 0x0abfc, 0x0abfd, 0x0abfe, 0x0abff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_f9[] = {
+ 0x0f900, 0x0f901, 0x02f9e, 0x0f903, 0x0f904, 0x0f905, 0x0f906, 0x02ef2,
+ 0x02ef2, 0x0f909, 0x02fa6, 0x0f90b, 0x0f90c, 0x0f90d, 0x0f90e, 0x0f90f,
+ 0x0f910, 0x0f911, 0x0f912, 0x0f913, 0x0f914, 0x0f915, 0x0f916, 0x0f917,
+ 0x0f918, 0x0f919, 0x0f91a, 0x0f91b, 0x0f91c, 0x0f91d, 0x0f91e, 0x0f91f,
+ 0x0f920, 0x0f921, 0x0f922, 0x0f923, 0x0f924, 0x0f925, 0x0f926, 0x0f927,
+ 0x0f928, 0x0f929, 0x0f92a, 0x0f92b, 0x0f92c, 0x0f92d, 0x0f92e, 0x0f92f,
+ 0x0f930, 0x0f931, 0x0f932, 0x0f933, 0x02f7c, 0x0f935, 0x0f936, 0x0f937,
+ 0x0f938, 0x0f939, 0x0f93a, 0x0f93b, 0x0f93c, 0x0f93d, 0x0f93e, 0x0f93f,
+ 0x02fc5, 0x0f941, 0x0f942, 0x0f943, 0x0f944, 0x0f945, 0x0f946, 0x0f947,
+ 0x0f948, 0x0f949, 0x0f94a, 0x0f94b, 0x0f94c, 0x0f94d, 0x0f94e, 0x0f94f,
+ 0x0f950, 0x0f951, 0x0f952, 0x0f953, 0x0f954, 0x0f955, 0x0f956, 0x0f957,
+ 0x0f958, 0x0f959, 0x0f95a, 0x0f95b, 0x0f914, 0x0f95d, 0x0f95e, 0x0f95f,
+ 0x0f960, 0x0f961, 0x0f962, 0x0f963, 0x0f964, 0x0f965, 0x0f966, 0x0f967,
+ 0x0f968, 0x0f969, 0x0f96a, 0x0f96b, 0x0f96c, 0x0f96d, 0x0f96e, 0x0f96f,
+ 0x0f970, 0x02fa0, 0x0f972, 0x0f973, 0x0f974, 0x0f975, 0x0f976, 0x0f977,
+ 0x0f978, 0x0f979, 0x0f97a, 0x0f97b, 0x0f97c, 0x0f97d, 0x0f97e, 0x0f97f,
+ 0x0f980, 0x02f25, 0x0f982, 0x0f983, 0x0f984, 0x0f985, 0x0f986, 0x0f987,
+ 0x0f988, 0x0f989, 0x02f12, 0x0f98b, 0x0f98c, 0x0f98d, 0x0f98e, 0x0f98f,
+ 0x0f990, 0x0f991, 0x0f992, 0x0f993, 0x0f994, 0x0f995, 0x0f996, 0x0f997,
+ 0x0f998, 0x0f999, 0x0f99a, 0x0f99b, 0x0f99c, 0x0f99d, 0x0f99e, 0x0f99f,
+ 0x0f9a0, 0x0f96f, 0x0f9a2, 0x0f9a3, 0x0f9a4, 0x0f9a5, 0x0f9a6, 0x0f9a7,
+ 0x0f9a8, 0x0f9a9, 0x0f95f, 0x0f9ab, 0x0f9ac, 0x0f9ad, 0x0f9ae, 0x0f9af,
+ 0x0f9b0, 0x0f9b1, 0x0f9b2, 0x0f9b3, 0x0f9b4, 0x0f9b5, 0x0f9b6, 0x0f9b7,
+ 0x0f9b8, 0x0f9b9, 0x0f9ba, 0x0f9bb, 0x0f9bc, 0x0f9bd, 0x0f9be, 0x0f914,
+ 0x0f9c0, 0x0f9c1, 0x0f9c2, 0x0f9c3, 0x02eef, 0x0f9c5, 0x0f9c6, 0x0f9c7,
+ 0x0f9c8, 0x0f9c9, 0x0f9ca, 0x0f9cb, 0x0f9cc, 0x0f9cd, 0x0f9ce, 0x0f9cf,
+ 0x0f9d0, 0x03285, 0x0f9d2, 0x0f9d3, 0x0f9d4, 0x0f9d5, 0x0f9d6, 0x0f9d7,
+ 0x0f9d8, 0x0f9d9, 0x0f9da, 0x0f961, 0x0f9dc, 0x0f9dd, 0x0f9de, 0x0f9df,
+ 0x0f9e0, 0x0f9e1, 0x0f9e2, 0x0f9e3, 0x0f9e4, 0x0f9e5, 0x0f9e6, 0x0f9e7,
+ 0x0f9e8, 0x02fa5, 0x0f9ea, 0x0f9eb, 0x0f9ec, 0x0f9ed, 0x0f9ee, 0x0f9ef,
+ 0x0f9f0, 0x0f9f1, 0x0f9f2, 0x0f9f3, 0x0f9f4, 0x0f9f5, 0x0f9f6, 0x02f74,
+ 0x0f9f8, 0x0f9f9, 0x0f9fa, 0x0f9fb, 0x0f9fc, 0x0f9fd, 0x0f9fe, 0x0f9ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fa[] = {
+ 0x0fa00, 0x0fa01, 0x0fa02, 0x0fa03, 0x0fa04, 0x0fa05, 0x0fa06, 0x0fa07,
+ 0x02f8f, 0x0fa09, 0x02f92, 0x0fa0b, 0x0fa0c, 0x0fa0d, 0x0fa0e, 0x0fa0f,
+ 0x0fa10, 0x0fa11, 0x0fa12, 0x0fa13, 0x0fa14, 0x0fa15, 0x0fa16, 0x0fa17,
+ 0x0fa18, 0x0fa19, 0x0fa1a, 0x0fa1b, 0x0fa1c, 0x0fa1d, 0x02f7b, 0x0fa1f,
+ 0x0fa20, 0x0fa21, 0x0fa22, 0x0fa23, 0x0fa24, 0x0fa25, 0x0fa26, 0x0fa27,
+ 0x0fa28, 0x0fa29, 0x0fa2a, 0x0fa2b, 0x0fa2c, 0x0fa2d, 0x0fa2e, 0x0fa2f,
+ 0x0fa30, 0x0fa31, 0x0fa32, 0x0fa33, 0x0fa34, 0x0fa35, 0x0fa36, 0x0fa37,
+ 0x0fa38, 0x0fa39, 0x0fa3a, 0x0fa3b, 0x02f2c, 0x0fa3d, 0x0fa3e, 0x0fa3f,
+ 0x0fa40, 0x0fa41, 0x0fa42, 0x0fa43, 0x0fa44, 0x0fa45, 0x0fa46, 0x0fa47,
+ 0x0fa48, 0x02ea4, 0x0fa4a, 0x0fa4b, 0x03293, 0x0fa4d, 0x0fa4e, 0x0fa4f,
+ 0x0fa50, 0x03297, 0x0fa52, 0x0fa53, 0x0fa54, 0x0fa55, 0x0fa56, 0x0f996,
+ 0x0fa58, 0x0fa59, 0x0fa5a, 0x0fa5b, 0x0fa5c, 0x02ebe, 0x02ebe, 0x0fa5f,
+ 0x0fa60, 0x0fa61, 0x0fa62, 0x0fa63, 0x0fa64, 0x0fa65, 0x02ecc, 0x0fa25,
+ 0x0fa68, 0x0fa69, 0x0fa6a, 0x0fa6b, 0x0fa6c, 0x0fa6d, 0x0fa6e, 0x0fa6f,
+ 0x0fa70, 0x0fa71, 0x0fa72, 0x0fa73, 0x0fa74, 0x0fa75, 0x0fa76, 0x0fa77,
+ 0x0fa36, 0x0fa79, 0x0fa7a, 0x0fa7b, 0x0fa10, 0x0fa7d, 0x0fa7e, 0x0fa7f,
+ 0x0fa80, 0x0fa81, 0x0fa82, 0x0fa83, 0x0fa84, 0x0fa85, 0x0fa86, 0x0fa87,
+ 0x0fa88, 0x0fa3f, 0x0fa8a, 0x0fa40, 0x0fa8c, 0x0fa8d, 0x0fa8e, 0x0fa8f,
+ 0x0fa90, 0x0fa12, 0x0f929, 0x0fa93, 0x0fa94, 0x02f4d, 0x0f970, 0x0f9ca,
+ 0x0fa98, 0x0fa99, 0x0fa47, 0x0fa9b, 0x0fa48, 0x0fa9d, 0x0fa9e, 0x0fa9f,
+ 0x0fa16, 0x0faa1, 0x0faa2, 0x0faa3, 0x0faa4, 0x0faa5, 0x0fa17, 0x0faa7,
+ 0x0faa8, 0x0faa9, 0x0faaa, 0x0faab, 0x0faac, 0x0fa56, 0x0faae, 0x0faaf,
+ 0x0f996, 0x0fab1, 0x0fa5b, 0x0fab3, 0x0fab4, 0x0fab5, 0x0fab6, 0x0fab7,
+ 0x0fa61, 0x0fab9, 0x0fa22, 0x0fabb, 0x0fa62, 0x0f95d, 0x0fabe, 0x0fa63,
+ 0x0fac0, 0x0fa65, 0x0fac2, 0x0fac3, 0x0fac4, 0x0fac5, 0x0fac6, 0x0fa68,
+ 0x0fa1c, 0x0fac9, 0x0fa69, 0x0facb, 0x0fa6a, 0x0facd, 0x02ef2, 0x0facf,
+ 0x0fad0, 0x0fad1, 0x0fad2, 0x0fad3, 0x0fad4, 0x0fad5, 0x0fad6, 0x0fad7,
+ 0x0fad8, 0x0fad9, 0x0fada, 0x0fadb, 0x0fadc, 0x0fadd, 0x0fade, 0x0fadf,
+ 0x0fae0, 0x0fae1, 0x0fae2, 0x0fae3, 0x0fae4, 0x0fae5, 0x0fae6, 0x0fae7,
+ 0x0fae8, 0x0fae9, 0x0faea, 0x0faeb, 0x0faec, 0x0faed, 0x0faee, 0x0faef,
+ 0x0faf0, 0x0faf1, 0x0faf2, 0x0faf3, 0x0faf4, 0x0faf5, 0x0faf6, 0x0faf7,
+ 0x0faf8, 0x0faf9, 0x0fafa, 0x0fafb, 0x0fafc, 0x0fafd, 0x0fafe, 0x0faff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fb[] = {
+ 0x0fb00, 0x0fb01, 0x0fb02, 0x0fb03, 0x0fb04, 0x0fb05, 0x0fb05, 0x0fb07,
+ 0x0fb08, 0x0fb09, 0x0fb0a, 0x0fb0b, 0x0fb0c, 0x0fb0d, 0x0fb0e, 0x0fb0f,
+ 0x0fb10, 0x0fb11, 0x0fb12, 0x0fb13, 0x0fb14, 0x0fb15, 0x0fb16, 0x0fb17,
+ 0x0fb18, 0x0fb19, 0x0fb1a, 0x0fb1b, 0x0fb1c, 0x005d9, 0x00000, 0x005f2,
+ 0x005e2, 0x005d0, 0x005d3, 0x005d4, 0x005da, 0x005dc, 0x005dd, 0x005e8,
+ 0x005ea, 0x0002b, 0x005e9, 0x005e9, 0x005e9, 0x005e9, 0x005d0, 0x005d0,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x0fb37,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x0fb3d, 0x005dd, 0x0fb3f,
+ 0x005df, 0x005e1, 0x0fb42, 0x005e3, 0x005e3, 0x0fb45, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005d5, 0x005d1, 0x005da, 0x005e3, 0x0fb4f,
+ 0x00671, 0x00671, 0x0067b, 0x0067b, 0x0067b, 0x0067b, 0x0067e, 0x0067e,
+ 0x0067e, 0x0067e, 0x00680, 0x00680, 0x00680, 0x00680, 0x0067a, 0x0067a,
+ 0x0067a, 0x0067a, 0x0067f, 0x0067f, 0x0067f, 0x0067f, 0x00679, 0x00679,
+ 0x00679, 0x00679, 0x006a4, 0x006a4, 0x006a4, 0x006a4, 0x006a6, 0x006a6,
+ 0x006a6, 0x006a6, 0x00684, 0x00684, 0x00684, 0x00684, 0x00683, 0x00683,
+ 0x00683, 0x00683, 0x00686, 0x00686, 0x00686, 0x00686, 0x00687, 0x00687,
+ 0x00687, 0x00687, 0x0068d, 0x0068d, 0x0068c, 0x0068c, 0x0068e, 0x0068e,
+ 0x00688, 0x00688, 0x00698, 0x00698, 0x00691, 0x00691, 0x006a9, 0x006a9,
+ 0x006a9, 0x006a9, 0x006af, 0x006af, 0x006af, 0x006af, 0x006b3, 0x006b3,
+ 0x006b3, 0x006b3, 0x006b1, 0x006b1, 0x006b1, 0x006b1, 0x006ba, 0x006ba,
+ 0x006bb, 0x006bb, 0x006bb, 0x006bb, 0x006c0, 0x006c0, 0x006c1, 0x006c1,
+ 0x006c1, 0x006c1, 0x006be, 0x006be, 0x006be, 0x006be, 0x006d2, 0x006d2,
+ 0x006d2, 0x006d2, 0x0fbb2, 0x0fbb3, 0x0fbb4, 0x0fbb5, 0x0fbb6, 0x0fbb7,
+ 0x0fbb8, 0x0fbb9, 0x0fbba, 0x0fbbb, 0x0fbbc, 0x0fbbd, 0x0fbbe, 0x0fbbf,
+ 0x0fbc0, 0x0fbc1, 0x0fbc2, 0x0fbc3, 0x0fbc4, 0x0fbc5, 0x0fbc6, 0x0fbc7,
+ 0x0fbc8, 0x0fbc9, 0x0fbca, 0x0fbcb, 0x0fbcc, 0x0fbcd, 0x0fbce, 0x0fbcf,
+ 0x0fbd0, 0x0fbd1, 0x0fbd2, 0x006ad, 0x006ad, 0x006ad, 0x006ad, 0x006c7,
+ 0x006c7, 0x006c6, 0x006c6, 0x006c8, 0x006c8, 0x00677, 0x006cb, 0x006cb,
+ 0x006c5, 0x006c5, 0x006c9, 0x006c9, 0x006d0, 0x006d0, 0x006d0, 0x006d0,
+ 0x00649, 0x00649, 0x0fbea, 0x0fbea, 0x0fbec, 0x0fbec, 0x0fbee, 0x0fbee,
+ 0x0fbf0, 0x0fbf0, 0x0fbf2, 0x0fbf2, 0x0fbf4, 0x0fbf4, 0x0fbf6, 0x0fbf6,
+ 0x0fbf6, 0x0fbf9, 0x0fbf9, 0x0fbf9, 0x006cc, 0x006cc, 0x0fbfe, 0x0fbff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fc[] = {
+ 0x0fc00, 0x0fc01, 0x0fc02, 0x0fbf9, 0x0fc04, 0x0fc05, 0x0fc06, 0x0fc07,
+ 0x0fc08, 0x0fc09, 0x0fc0a, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fc0f,
+ 0x0fc10, 0x0fc11, 0x0fc12, 0x0fc13, 0x0fc14, 0x0fc15, 0x0fc16, 0x0fc17,
+ 0x0fc18, 0x0fc19, 0x0fc1a, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fc1f,
+ 0x0fc20, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25, 0x0fc26, 0x0fc27,
+ 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e, 0x0fc2f,
+ 0x0fc30, 0x0fc31, 0x0fc32, 0x0fc33, 0x0fc34, 0x0fc35, 0x0fc36, 0x0fc37,
+ 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc3f,
+ 0x0fc40, 0x0fc41, 0x0fc42, 0x0fc43, 0x0fc44, 0x0fc45, 0x0fc46, 0x0fc47,
+ 0x0fc48, 0x0fc49, 0x0fc4a, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fc4f,
+ 0x0fc50, 0x0fc51, 0x0fc52, 0x0fc53, 0x0fc54, 0x0fc55, 0x0fc56, 0x0fc57,
+ 0x0fc58, 0x0fc59, 0x0fc5a, 0x00630, 0x00631, 0x00649, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0fc64, 0x0fc65, 0x0fc02, 0x0fc67,
+ 0x0fbf9, 0x0fc04, 0x0fc6a, 0x0fc6b, 0x0fc08, 0x0fc6d, 0x0fc09, 0x0fc0a,
+ 0x0fc70, 0x0fc71, 0x0fc0e, 0x0fc73, 0x0fc0f, 0x0fc10, 0x0fc76, 0x0fc77,
+ 0x0fc12, 0x0fc79, 0x0fc13, 0x0fc14, 0x0fc31, 0x0fc32, 0x0fc35, 0x0fc36,
+ 0x0fc37, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc42, 0x0fc43, 0x0fc44,
+ 0x0fc88, 0x0fc48, 0x0fc8a, 0x0fc8b, 0x0fc4e, 0x0fc8d, 0x0fc4f, 0x0fc50,
+ 0x00649, 0x0fc91, 0x0fc92, 0x0fc58, 0x0fc94, 0x0fc59, 0x0fc5a, 0x0fc00,
+ 0x0fc01, 0x0fc99, 0x0fc02, 0x0fc9b, 0x0fc05, 0x0fc06, 0x0fc07, 0x0fc08,
+ 0x0fca0, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fc15,
+ 0x0fc16, 0x0fc17, 0x0fc18, 0x0fc19, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e,
+ 0x0fc1f, 0x0fc20, 0x0fcb2, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25,
+ 0x0fc26, 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e,
+ 0x0fc2f, 0x0fc30, 0x0fc33, 0x0fc34, 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b,
+ 0x0fc3c, 0x0fc3f, 0x0fc40, 0x0fc41, 0x0fc42, 0x0fccd, 0x0fc45, 0x0fc46,
+ 0x0fc47, 0x0fc48, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fcd6, 0x0fc51,
+ 0x0fc52, 0x00647, 0x0fc55, 0x0fc56, 0x0fc57, 0x0fc58, 0x0fcde, 0x0fc02,
+ 0x0fc9b, 0x0fc08, 0x0fca0, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fce6, 0x0fc1f,
+ 0x0fce8, 0x0fce9, 0x0fcea, 0x0fc3b, 0x0fc3c, 0x0fc42, 0x0fc4e, 0x0fcd6,
+ 0x0fc58, 0x0fcde, 0x00000, 0x00000, 0x00000, 0x0fcf5, 0x0fcf6, 0x0fcf7,
+ 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb, 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fcff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fd[] = {
+ 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03, 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07,
+ 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b, 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f,
+ 0x0fd10, 0x0fcf5, 0x0fcf6, 0x0fcf7, 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb,
+ 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fd1b, 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03,
+ 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07, 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f, 0x0fd10, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fce8, 0x0fcea, 0x0fc27, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fd09,
+ 0x0fd0a, 0x0fd0b, 0x0fc27, 0x0fc28, 0x00627, 0x00627, 0x0fd3e, 0x0fd3f,
+ 0x0fd40, 0x0fd41, 0x0fd42, 0x0fd43, 0x0fd44, 0x0fd45, 0x0fd46, 0x0fd47,
+ 0x0fd48, 0x0fd49, 0x0fd4a, 0x0fd4b, 0x0fd4c, 0x0fd4d, 0x0fd4e, 0x0fd4f,
+ 0x0fd50, 0x0fd51, 0x0fd51, 0x0fd53, 0x0fd54, 0x0fd55, 0x0fd56, 0x0fd57,
+ 0x0fd58, 0x0fd58, 0x0fd5a, 0x0fd5b, 0x0fd5c, 0x0fd5d, 0x0fd5e, 0x0fd5f,
+ 0x0fd5f, 0x0fd61, 0x0fd62, 0x0fd62, 0x0fd64, 0x0fd64, 0x0fd66, 0x0fd67,
+ 0x0fd67, 0x0fd69, 0x0fd6a, 0x0fd6a, 0x0fd6c, 0x0fd6c, 0x0fd6e, 0x0fd6f,
+ 0x0fd6f, 0x0fd71, 0x0fd71, 0x0fd73, 0x0fd74, 0x0fd75, 0x0fd76, 0x0fd76,
+ 0x0fd78, 0x0fd79, 0x0fd7a, 0x0fd7b, 0x0fd7c, 0x0fd7c, 0x0fd7e, 0x0fd7f,
+ 0x0fd80, 0x0fd81, 0x0fd82, 0x0fd83, 0x0fd83, 0x0fd85, 0x0fd85, 0x0fd87,
+ 0x0fd87, 0x0fd89, 0x0fd8a, 0x0fd8b, 0x0fd8c, 0x0fd8d, 0x0fd8e, 0x0fd8f,
+ 0x0fd90, 0x0fd91, 0x0fd92, 0x0fd93, 0x0fd94, 0x0fd95, 0x0fd96, 0x0fd97,
+ 0x0fd97, 0x0fd99, 0x0fd9a, 0x0fd9b, 0x0fd9c, 0x0fd9c, 0x0fd9e, 0x0fd9f,
+ 0x0fda0, 0x0fda1, 0x0fda2, 0x0fda3, 0x0fda4, 0x0fda5, 0x0fda6, 0x0fda7,
+ 0x0fda8, 0x0fda9, 0x0fdaa, 0x0fdab, 0x0fdac, 0x0fdad, 0x0fdae, 0x0fdaf,
+ 0x0fdb0, 0x0fdb1, 0x0fdb2, 0x0fdb3, 0x0fd7e, 0x0fd80, 0x0fdb6, 0x0fdb7,
+ 0x0fdb8, 0x0fdb9, 0x0fdba, 0x0fdbb, 0x0fdba, 0x0fdb8, 0x0fdbe, 0x0fdbf,
+ 0x0fdc0, 0x0fdc1, 0x0fdc2, 0x0fdbb, 0x0fd75, 0x0fd66, 0x0fdc6, 0x0fdc7,
+ 0x0fdc8, 0x0fdc9, 0x0fdca, 0x0fdcb, 0x0fdcc, 0x0fdcd, 0x0fdce, 0x0fdcf,
+ 0x0fdd0, 0x0fdd1, 0x0fdd2, 0x0fdd3, 0x0fdd4, 0x0fdd5, 0x0fdd6, 0x0fdd7,
+ 0x0fdd8, 0x0fdd9, 0x0fdda, 0x0fddb, 0x0fddc, 0x0fddd, 0x0fdde, 0x0fddf,
+ 0x0fde0, 0x0fde1, 0x0fde2, 0x0fde3, 0x0fde4, 0x0fde5, 0x0fde6, 0x0fde7,
+ 0x0fde8, 0x0fde9, 0x0fdea, 0x0fdeb, 0x0fdec, 0x0fded, 0x0fdee, 0x0fdef,
+ 0x0fdf0, 0x0fdf1, 0x0fdf2, 0x0fdf3, 0x0fdf4, 0x0fdf5, 0x0fdf6, 0x0fdf7,
+ 0x0fdf8, 0x0fdf9, 0x0fdfa, 0x0fdfb, 0x0fdfc, 0x0fdfd, 0x0fdfe, 0x0fdff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fe[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x0002c, 0x03001, 0x03002, 0x0003a, 0x0003b, 0x00021, 0x0003f, 0x03016,
+ 0x03017, 0x02026, 0x0fe1a, 0x0fe1b, 0x0fe1c, 0x0fe1d, 0x0fe1e, 0x0fe1f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe27,
+ 0x0fe28, 0x0fe29, 0x0fe2a, 0x0fe2b, 0x0fe2c, 0x0fe2d, 0x0fe2e, 0x0fe2f,
+ 0x02025, 0x02014, 0x02013, 0x0005f, 0x0005f, 0x00028, 0x00029, 0x0007b,
+ 0x0007d, 0x03014, 0x03015, 0x03010, 0x03011, 0x0300a, 0x0300b, 0x02329,
+ 0x0232a, 0x0300c, 0x0300d, 0x0300e, 0x0300f, 0x0fe45, 0x0fe46, 0x0005b,
+ 0x0005d, 0x0203e, 0x0203e, 0x0203e, 0x0203e, 0x0005f, 0x0005f, 0x0005f,
+ 0x0002c, 0x03001, 0x0002e, 0x0fe53, 0x0003b, 0x0003a, 0x0003f, 0x00021,
+ 0x02014, 0x00028, 0x00029, 0x0007b, 0x0007d, 0x03014, 0x03015, 0x00023,
+ 0x00026, 0x0002a, 0x0002b, 0x0002d, 0x0003c, 0x0003e, 0x0003d, 0x0fe67,
+ 0x0005c, 0x00024, 0x00025, 0x00040, 0x0fe6c, 0x0fe6d, 0x0fe6e, 0x0fe6f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe75, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00621, 0x00622, 0x00622, 0x00623, 0x00623, 0x00624, 0x00624, 0x00625,
+ 0x00625, 0x00626, 0x00626, 0x00626, 0x00626, 0x00627, 0x00627, 0x00628,
+ 0x00628, 0x00628, 0x00628, 0x00629, 0x00629, 0x0062a, 0x0062a, 0x0062a,
+ 0x0062a, 0x0062b, 0x0062b, 0x0062b, 0x0062b, 0x0062c, 0x0062c, 0x0062c,
+ 0x0062c, 0x0062d, 0x0062d, 0x0062d, 0x0062d, 0x0062e, 0x0062e, 0x0062e,
+ 0x0062e, 0x0062f, 0x0062f, 0x00630, 0x00630, 0x00631, 0x00631, 0x00632,
+ 0x00632, 0x00633, 0x00633, 0x00633, 0x00633, 0x00634, 0x00634, 0x00634,
+ 0x00634, 0x00635, 0x00635, 0x00635, 0x00635, 0x00636, 0x00636, 0x00636,
+ 0x00636, 0x00637, 0x00637, 0x00637, 0x00637, 0x00638, 0x00638, 0x00638,
+ 0x00638, 0x00639, 0x00639, 0x00639, 0x00639, 0x0063a, 0x0063a, 0x0063a,
+ 0x0063a, 0x00641, 0x00641, 0x00641, 0x00641, 0x00642, 0x00642, 0x00642,
+ 0x00642, 0x00643, 0x00643, 0x00643, 0x00643, 0x00644, 0x00644, 0x00644,
+ 0x00644, 0x00645, 0x00645, 0x00645, 0x00645, 0x00646, 0x00646, 0x00646,
+ 0x00646, 0x00647, 0x00647, 0x00647, 0x00647, 0x00648, 0x00648, 0x00649,
+ 0x00649, 0x0064a, 0x0064a, 0x0064a, 0x0064a, 0x0fef5, 0x0fef5, 0x0fef7,
+ 0x0fef7, 0x0fef9, 0x0fef9, 0x0fefb, 0x0fefb, 0x0fefd, 0x0fefe, 0x0feff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_ff[] = {
+ 0x0ff00, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x02985,
+ 0x02986, 0x03002, 0x0300c, 0x0300d, 0x03001, 0x030fb, 0x03092, 0x03041,
+ 0x03043, 0x03045, 0x03047, 0x03049, 0x03083, 0x03085, 0x03087, 0x03063,
+ 0x030fc, 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d,
+ 0x0304f, 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d,
+ 0x0305f, 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c,
+ 0x0306d, 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e,
+ 0x0307f, 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089,
+ 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03093, 0x00000, 0x00000,
+ 0x01160, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0ffbf,
+ 0x0ffc0, 0x0ffc1, 0x01161, 0x01162, 0x01163, 0x01164, 0x01165, 0x01166,
+ 0x0ffc8, 0x0ffc9, 0x01167, 0x01168, 0x01169, 0x0116a, 0x0116b, 0x0116c,
+ 0x0ffd0, 0x0ffd1, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171, 0x01172,
+ 0x0ffd8, 0x0ffd9, 0x01173, 0x01174, 0x01175, 0x0ffdd, 0x0ffde, 0x0ffdf,
+ 0x000a2, 0x000a3, 0x000ac, 0x000af, 0x000a6, 0x000a5, 0x020a9, 0x0ffe7,
+ 0x02502, 0x02190, 0x02191, 0x02192, 0x02193, 0x025a0, 0x025cb, 0x0ffef,
+ 0x0fff0, 0x0fff1, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff5, 0x0fff6, 0x0fff7,
+ 0x0fff8, 0x00000, 0x00000, 0x00000, 0x0fffc, 0x0fffd, 0x0fffe, 0x0ffff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_101[] = {
+ 0x10100, 0x10101, 0x10102, 0x10103, 0x10104, 0x10105, 0x10106, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x10110, 0x10111, 0x10112, 0x10113, 0x10114, 0x10115, 0x10116, 0x10117,
+ 0x10118, 0x10119, 0x1011a, 0x1011b, 0x1011c, 0x1011d, 0x1011e, 0x1011f,
+ 0x10120, 0x10121, 0x10122, 0x10123, 0x10124, 0x10125, 0x10126, 0x10127,
+ 0x10128, 0x10129, 0x1012a, 0x1012b, 0x1012c, 0x1012d, 0x1012e, 0x1012f,
+ 0x10130, 0x10131, 0x10132, 0x10133, 0x10134, 0x10135, 0x10136, 0x10137,
+ 0x10138, 0x10139, 0x1013a, 0x1013b, 0x1013c, 0x1013d, 0x1013e, 0x1013f,
+ 0x10140, 0x10141, 0x00031, 0x00035, 0x10144, 0x10145, 0x10146, 0x10147,
+ 0x00035, 0x10149, 0x1014a, 0x1014b, 0x1014c, 0x1014d, 0x1014e, 0x00035,
+ 0x10150, 0x10151, 0x10152, 0x10153, 0x10154, 0x10155, 0x10156, 0x10157,
+ 0x00031, 0x00031, 0x00031, 0x00032, 0x00032, 0x00032, 0x00032, 0x00035,
+ 0x10160, 0x10161, 0x10162, 0x10163, 0x10164, 0x10165, 0x10166, 0x10167,
+ 0x10168, 0x10169, 0x1016a, 0x1016b, 0x1016c, 0x1016d, 0x1016e, 0x1016f,
+ 0x10170, 0x10171, 0x10172, 0x00035, 0x10174, 0x10175, 0x10176, 0x10177,
+ 0x10178, 0x10179, 0x1017a, 0x1017b, 0x1017c, 0x1017d, 0x1017e, 0x1017f,
+ 0x10180, 0x10181, 0x10182, 0x10183, 0x10184, 0x10185, 0x10186, 0x10187,
+ 0x10188, 0x10189, 0x00030, 0x1018b, 0x1018c, 0x1018d, 0x1018e, 0x1018f,
+ 0x10190, 0x10191, 0x10192, 0x10193, 0x10194, 0x10195, 0x10196, 0x10197,
+ 0x10198, 0x10199, 0x1019a, 0x1019b, 0x1019c, 0x1019d, 0x1019e, 0x1019f,
+ 0x101a0, 0x101a1, 0x101a2, 0x101a3, 0x101a4, 0x101a5, 0x101a6, 0x101a7,
+ 0x101a8, 0x101a9, 0x101aa, 0x101ab, 0x101ac, 0x101ad, 0x101ae, 0x101af,
+ 0x101b0, 0x101b1, 0x101b2, 0x101b3, 0x101b4, 0x101b5, 0x101b6, 0x101b7,
+ 0x101b8, 0x101b9, 0x101ba, 0x101bb, 0x101bc, 0x101bd, 0x101be, 0x101bf,
+ 0x101c0, 0x101c1, 0x101c2, 0x101c3, 0x101c4, 0x101c5, 0x101c6, 0x101c7,
+ 0x101c8, 0x101c9, 0x101ca, 0x101cb, 0x101cc, 0x101cd, 0x101ce, 0x101cf,
+ 0x101d0, 0x101d1, 0x101d2, 0x101d3, 0x101d4, 0x101d5, 0x101d6, 0x101d7,
+ 0x101d8, 0x101d9, 0x101da, 0x101db, 0x101dc, 0x101dd, 0x101de, 0x101df,
+ 0x101e0, 0x101e1, 0x101e2, 0x101e3, 0x101e4, 0x101e5, 0x101e6, 0x101e7,
+ 0x101e8, 0x101e9, 0x101ea, 0x101eb, 0x101ec, 0x101ed, 0x101ee, 0x101ef,
+ 0x101f0, 0x101f1, 0x101f2, 0x101f3, 0x101f4, 0x101f5, 0x101f6, 0x101f7,
+ 0x101f8, 0x101f9, 0x101fa, 0x101fb, 0x101fc, 0x00000, 0x101fe, 0x101ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_103[] = {
+ 0x10300, 0x10301, 0x10302, 0x10303, 0x10304, 0x10305, 0x10306, 0x10307,
+ 0x10308, 0x10309, 0x1030a, 0x1030b, 0x1030c, 0x1030d, 0x1030e, 0x1030f,
+ 0x10310, 0x10311, 0x10312, 0x10313, 0x10314, 0x10315, 0x10316, 0x10317,
+ 0x10318, 0x10319, 0x1031a, 0x1031b, 0x1031c, 0x1031d, 0x1031e, 0x1031f,
+ 0x00031, 0x00035, 0x10322, 0x10323, 0x10324, 0x10325, 0x10326, 0x10327,
+ 0x10328, 0x10329, 0x1032a, 0x1032b, 0x1032c, 0x1032d, 0x1032e, 0x1032f,
+ 0x10330, 0x10331, 0x10332, 0x10333, 0x10334, 0x10335, 0x10336, 0x10337,
+ 0x10338, 0x10339, 0x1033a, 0x1033b, 0x1033c, 0x1033d, 0x1033e, 0x1033f,
+ 0x10340, 0x10341, 0x10342, 0x10343, 0x10344, 0x10345, 0x10346, 0x10347,
+ 0x10348, 0x10349, 0x1034a, 0x1034b, 0x1034c, 0x1034d, 0x1034e, 0x1034f,
+ 0x10350, 0x10351, 0x10352, 0x10353, 0x10354, 0x10355, 0x10356, 0x10357,
+ 0x10358, 0x10359, 0x1035a, 0x1035b, 0x1035c, 0x1035d, 0x1035e, 0x1035f,
+ 0x10360, 0x10361, 0x10362, 0x10363, 0x10364, 0x10365, 0x10366, 0x10367,
+ 0x10368, 0x10369, 0x1036a, 0x1036b, 0x1036c, 0x1036d, 0x1036e, 0x1036f,
+ 0x10370, 0x10371, 0x10372, 0x10373, 0x10374, 0x10375, 0x10376, 0x10377,
+ 0x10378, 0x10379, 0x1037a, 0x1037b, 0x1037c, 0x1037d, 0x1037e, 0x1037f,
+ 0x10380, 0x10381, 0x10382, 0x10383, 0x10384, 0x10385, 0x10386, 0x10387,
+ 0x10388, 0x10389, 0x1038a, 0x1038b, 0x1038c, 0x1038d, 0x1038e, 0x1038f,
+ 0x10390, 0x10391, 0x10392, 0x10393, 0x10394, 0x10395, 0x10396, 0x10397,
+ 0x10398, 0x10399, 0x1039a, 0x1039b, 0x1039c, 0x1039d, 0x1039e, 0x1039f,
+ 0x103a0, 0x103a1, 0x103a2, 0x103a3, 0x103a4, 0x103a5, 0x103a6, 0x103a7,
+ 0x103a8, 0x103a9, 0x103aa, 0x103ab, 0x103ac, 0x103ad, 0x103ae, 0x103af,
+ 0x103b0, 0x103b1, 0x103b2, 0x103b3, 0x103b4, 0x103b5, 0x103b6, 0x103b7,
+ 0x103b8, 0x103b9, 0x103ba, 0x103bb, 0x103bc, 0x103bd, 0x103be, 0x103bf,
+ 0x103c0, 0x103c1, 0x103c2, 0x103c3, 0x103c4, 0x103c5, 0x103c6, 0x103c7,
+ 0x103c8, 0x103c9, 0x103ca, 0x103cb, 0x103cc, 0x103cd, 0x103ce, 0x103cf,
+ 0x103d0, 0x00031, 0x00032, 0x103d3, 0x103d4, 0x103d5, 0x103d6, 0x103d7,
+ 0x103d8, 0x103d9, 0x103da, 0x103db, 0x103dc, 0x103dd, 0x103de, 0x103df,
+ 0x103e0, 0x103e1, 0x103e2, 0x103e3, 0x103e4, 0x103e5, 0x103e6, 0x103e7,
+ 0x103e8, 0x103e9, 0x103ea, 0x103eb, 0x103ec, 0x103ed, 0x103ee, 0x103ef,
+ 0x103f0, 0x103f1, 0x103f2, 0x103f3, 0x103f4, 0x103f5, 0x103f6, 0x103f7,
+ 0x103f8, 0x103f9, 0x103fa, 0x103fb, 0x103fc, 0x103fd, 0x103fe, 0x103ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_104[] = {
+ 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407,
+ 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f,
+ 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417,
+ 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f,
+ 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427,
+ 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407,
+ 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f,
+ 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417,
+ 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f,
+ 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427,
+ 0x10450, 0x10451, 0x10452, 0x10453, 0x10454, 0x10455, 0x10456, 0x10457,
+ 0x10458, 0x10459, 0x1045a, 0x1045b, 0x1045c, 0x1045d, 0x1045e, 0x1045f,
+ 0x10460, 0x10461, 0x10462, 0x10463, 0x10464, 0x10465, 0x10466, 0x10467,
+ 0x10468, 0x10469, 0x1046a, 0x1046b, 0x1046c, 0x1046d, 0x1046e, 0x1046f,
+ 0x10470, 0x10471, 0x10472, 0x10473, 0x10474, 0x10475, 0x10476, 0x10477,
+ 0x10478, 0x10479, 0x1047a, 0x1047b, 0x1047c, 0x1047d, 0x1047e, 0x1047f,
+ 0x10480, 0x10481, 0x10482, 0x10483, 0x10484, 0x10485, 0x10486, 0x10487,
+ 0x10488, 0x10489, 0x1048a, 0x1048b, 0x1048c, 0x1048d, 0x1048e, 0x1048f,
+ 0x10490, 0x10491, 0x10492, 0x10493, 0x10494, 0x10495, 0x10496, 0x10497,
+ 0x10498, 0x10499, 0x1049a, 0x1049b, 0x1049c, 0x1049d, 0x1049e, 0x1049f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x104aa, 0x104ab, 0x104ac, 0x104ad, 0x104ae, 0x104af,
+ 0x104b0, 0x104b1, 0x104b2, 0x104b3, 0x104b4, 0x104b5, 0x104b6, 0x104b7,
+ 0x104b8, 0x104b9, 0x104ba, 0x104bb, 0x104bc, 0x104bd, 0x104be, 0x104bf,
+ 0x104c0, 0x104c1, 0x104c2, 0x104c3, 0x104c4, 0x104c5, 0x104c6, 0x104c7,
+ 0x104c8, 0x104c9, 0x104ca, 0x104cb, 0x104cc, 0x104cd, 0x104ce, 0x104cf,
+ 0x104d0, 0x104d1, 0x104d2, 0x104d3, 0x104d4, 0x104d5, 0x104d6, 0x104d7,
+ 0x104d8, 0x104d9, 0x104da, 0x104db, 0x104dc, 0x104dd, 0x104de, 0x104df,
+ 0x104e0, 0x104e1, 0x104e2, 0x104e3, 0x104e4, 0x104e5, 0x104e6, 0x104e7,
+ 0x104e8, 0x104e9, 0x104ea, 0x104eb, 0x104ec, 0x104ed, 0x104ee, 0x104ef,
+ 0x104f0, 0x104f1, 0x104f2, 0x104f3, 0x104f4, 0x104f5, 0x104f6, 0x104f7,
+ 0x104f8, 0x104f9, 0x104fa, 0x104fb, 0x104fc, 0x104fd, 0x104fe, 0x104ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_108[] = {
+ 0x10800, 0x10801, 0x10802, 0x10803, 0x10804, 0x10805, 0x10806, 0x10807,
+ 0x10808, 0x10809, 0x1080a, 0x1080b, 0x1080c, 0x1080d, 0x1080e, 0x1080f,
+ 0x10810, 0x10811, 0x10812, 0x10813, 0x10814, 0x10815, 0x10816, 0x10817,
+ 0x10818, 0x10819, 0x1081a, 0x1081b, 0x1081c, 0x1081d, 0x1081e, 0x1081f,
+ 0x10820, 0x10821, 0x10822, 0x10823, 0x10824, 0x10825, 0x10826, 0x10827,
+ 0x10828, 0x10829, 0x1082a, 0x1082b, 0x1082c, 0x1082d, 0x1082e, 0x1082f,
+ 0x10830, 0x10831, 0x10832, 0x10833, 0x10834, 0x10835, 0x10836, 0x10837,
+ 0x10838, 0x10839, 0x1083a, 0x1083b, 0x1083c, 0x1083d, 0x1083e, 0x1083f,
+ 0x10840, 0x10841, 0x10842, 0x10843, 0x10844, 0x10845, 0x10846, 0x10847,
+ 0x10848, 0x10849, 0x1084a, 0x1084b, 0x1084c, 0x1084d, 0x1084e, 0x1084f,
+ 0x10850, 0x10851, 0x10852, 0x10853, 0x10854, 0x10855, 0x10856, 0x10857,
+ 0x00031, 0x00032, 0x00033, 0x1085b, 0x1085c, 0x1085d, 0x1085e, 0x1085f,
+ 0x10860, 0x10861, 0x10862, 0x10863, 0x10864, 0x10865, 0x10866, 0x10867,
+ 0x10868, 0x10869, 0x1086a, 0x1086b, 0x1086c, 0x1086d, 0x1086e, 0x1086f,
+ 0x10870, 0x10871, 0x10872, 0x10873, 0x10874, 0x10875, 0x10876, 0x10877,
+ 0x10878, 0x10879, 0x1087a, 0x1087b, 0x1087c, 0x1087d, 0x1087e, 0x1087f,
+ 0x10880, 0x10881, 0x10882, 0x10883, 0x10884, 0x10885, 0x10886, 0x10887,
+ 0x10888, 0x10889, 0x1088a, 0x1088b, 0x1088c, 0x1088d, 0x1088e, 0x1088f,
+ 0x10890, 0x10891, 0x10892, 0x10893, 0x10894, 0x10895, 0x10896, 0x10897,
+ 0x10898, 0x10899, 0x1089a, 0x1089b, 0x1089c, 0x1089d, 0x1089e, 0x1089f,
+ 0x108a0, 0x108a1, 0x108a2, 0x108a3, 0x108a4, 0x108a5, 0x108a6, 0x108a7,
+ 0x108a8, 0x108a9, 0x108aa, 0x108ab, 0x108ac, 0x108ad, 0x108ae, 0x108af,
+ 0x108b0, 0x108b1, 0x108b2, 0x108b3, 0x108b4, 0x108b5, 0x108b6, 0x108b7,
+ 0x108b8, 0x108b9, 0x108ba, 0x108bb, 0x108bc, 0x108bd, 0x108be, 0x108bf,
+ 0x108c0, 0x108c1, 0x108c2, 0x108c3, 0x108c4, 0x108c5, 0x108c6, 0x108c7,
+ 0x108c8, 0x108c9, 0x108ca, 0x108cb, 0x108cc, 0x108cd, 0x108ce, 0x108cf,
+ 0x108d0, 0x108d1, 0x108d2, 0x108d3, 0x108d4, 0x108d5, 0x108d6, 0x108d7,
+ 0x108d8, 0x108d9, 0x108da, 0x108db, 0x108dc, 0x108dd, 0x108de, 0x108df,
+ 0x108e0, 0x108e1, 0x108e2, 0x108e3, 0x108e4, 0x108e5, 0x108e6, 0x108e7,
+ 0x108e8, 0x108e9, 0x108ea, 0x108eb, 0x108ec, 0x108ed, 0x108ee, 0x108ef,
+ 0x108f0, 0x108f1, 0x108f2, 0x108f3, 0x108f4, 0x108f5, 0x108f6, 0x108f7,
+ 0x108f8, 0x108f9, 0x108fa, 0x108fb, 0x108fc, 0x108fd, 0x108fe, 0x108ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_109[] = {
+ 0x10900, 0x10901, 0x10902, 0x10903, 0x10904, 0x10905, 0x10906, 0x10907,
+ 0x10908, 0x10909, 0x1090a, 0x1090b, 0x1090c, 0x1090d, 0x1090e, 0x1090f,
+ 0x10910, 0x10911, 0x10912, 0x10913, 0x10914, 0x10915, 0x00031, 0x10917,
+ 0x10918, 0x10919, 0x00032, 0x00033, 0x1091c, 0x1091d, 0x1091e, 0x1091f,
+ 0x10920, 0x10921, 0x10922, 0x10923, 0x10924, 0x10925, 0x10926, 0x10927,
+ 0x10928, 0x10929, 0x1092a, 0x1092b, 0x1092c, 0x1092d, 0x1092e, 0x1092f,
+ 0x10930, 0x10931, 0x10932, 0x10933, 0x10934, 0x10935, 0x10936, 0x10937,
+ 0x10938, 0x10939, 0x1093a, 0x1093b, 0x1093c, 0x1093d, 0x1093e, 0x1093f,
+ 0x10940, 0x10941, 0x10942, 0x10943, 0x10944, 0x10945, 0x10946, 0x10947,
+ 0x10948, 0x10949, 0x1094a, 0x1094b, 0x1094c, 0x1094d, 0x1094e, 0x1094f,
+ 0x10950, 0x10951, 0x10952, 0x10953, 0x10954, 0x10955, 0x10956, 0x10957,
+ 0x10958, 0x10959, 0x1095a, 0x1095b, 0x1095c, 0x1095d, 0x1095e, 0x1095f,
+ 0x10960, 0x10961, 0x10962, 0x10963, 0x10964, 0x10965, 0x10966, 0x10967,
+ 0x10968, 0x10969, 0x1096a, 0x1096b, 0x1096c, 0x1096d, 0x1096e, 0x1096f,
+ 0x10970, 0x10971, 0x10972, 0x10973, 0x10974, 0x10975, 0x10976, 0x10977,
+ 0x10978, 0x10979, 0x1097a, 0x1097b, 0x1097c, 0x1097d, 0x1097e, 0x1097f,
+ 0x10980, 0x10981, 0x10982, 0x10983, 0x10984, 0x10985, 0x10986, 0x10987,
+ 0x10988, 0x10989, 0x1098a, 0x1098b, 0x1098c, 0x1098d, 0x1098e, 0x1098f,
+ 0x10990, 0x10991, 0x10992, 0x10993, 0x10994, 0x10995, 0x10996, 0x10997,
+ 0x10998, 0x10999, 0x1099a, 0x1099b, 0x1099c, 0x1099d, 0x1099e, 0x1099f,
+ 0x109a0, 0x109a1, 0x109a2, 0x109a3, 0x109a4, 0x109a5, 0x109a6, 0x109a7,
+ 0x109a8, 0x109a9, 0x109aa, 0x109ab, 0x109ac, 0x109ad, 0x109ae, 0x109af,
+ 0x109b0, 0x109b1, 0x109b2, 0x109b3, 0x109b4, 0x109b5, 0x109b6, 0x109b7,
+ 0x109b8, 0x109b9, 0x109ba, 0x109bb, 0x109bc, 0x109bd, 0x109be, 0x109bf,
+ 0x109c0, 0x109c1, 0x109c2, 0x109c3, 0x109c4, 0x109c5, 0x109c6, 0x109c7,
+ 0x109c8, 0x109c9, 0x109ca, 0x109cb, 0x109cc, 0x109cd, 0x109ce, 0x109cf,
+ 0x109d0, 0x109d1, 0x109d2, 0x109d3, 0x109d4, 0x109d5, 0x109d6, 0x109d7,
+ 0x109d8, 0x109d9, 0x109da, 0x109db, 0x109dc, 0x109dd, 0x109de, 0x109df,
+ 0x109e0, 0x109e1, 0x109e2, 0x109e3, 0x109e4, 0x109e5, 0x109e6, 0x109e7,
+ 0x109e8, 0x109e9, 0x109ea, 0x109eb, 0x109ec, 0x109ed, 0x109ee, 0x109ef,
+ 0x109f0, 0x109f1, 0x109f2, 0x109f3, 0x109f4, 0x109f5, 0x109f6, 0x109f7,
+ 0x109f8, 0x109f9, 0x109fa, 0x109fb, 0x109fc, 0x109fd, 0x109fe, 0x109ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10a[] = {
+ 0x10a00, 0x10a01, 0x10a02, 0x10a03, 0x10a04, 0x10a05, 0x10a06, 0x10a07,
+ 0x10a08, 0x10a09, 0x10a0a, 0x10a0b, 0x10a0c, 0x00000, 0x00000, 0x00000,
+ 0x10a10, 0x10a11, 0x10a12, 0x10a13, 0x10a14, 0x10a15, 0x10a16, 0x10a17,
+ 0x10a18, 0x10a19, 0x10a1a, 0x10a1b, 0x10a1c, 0x10a1d, 0x10a1e, 0x10a1f,
+ 0x10a20, 0x10a21, 0x10a22, 0x10a23, 0x10a24, 0x10a25, 0x10a26, 0x10a27,
+ 0x10a28, 0x10a29, 0x10a2a, 0x10a2b, 0x10a2c, 0x10a2d, 0x10a2e, 0x10a2f,
+ 0x10a30, 0x10a31, 0x10a32, 0x10a33, 0x10a34, 0x10a35, 0x10a36, 0x10a37,
+ 0x00000, 0x00000, 0x00000, 0x10a3b, 0x10a3c, 0x10a3d, 0x10a3e, 0x10a3f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x10a44, 0x10a45, 0x10a46, 0x10a47,
+ 0x10a48, 0x10a49, 0x10a4a, 0x10a4b, 0x10a4c, 0x10a4d, 0x10a4e, 0x10a4f,
+ 0x10a50, 0x10a51, 0x10a52, 0x10a53, 0x10a54, 0x10a55, 0x10a56, 0x10a57,
+ 0x10a58, 0x10a59, 0x10a5a, 0x10a5b, 0x10a5c, 0x10a5d, 0x10a5e, 0x10a5f,
+ 0x10a60, 0x10a61, 0x10a62, 0x10a63, 0x10a64, 0x10a65, 0x10a66, 0x10a67,
+ 0x10a68, 0x10a69, 0x10a6a, 0x10a6b, 0x10a6c, 0x10a6d, 0x10a6e, 0x10a6f,
+ 0x10a70, 0x10a71, 0x10a72, 0x10a73, 0x10a74, 0x10a75, 0x10a76, 0x10a77,
+ 0x10a78, 0x10a79, 0x10a7a, 0x10a7b, 0x10a7c, 0x00031, 0x10a7e, 0x10a7f,
+ 0x10a80, 0x10a81, 0x10a82, 0x10a83, 0x10a84, 0x10a85, 0x10a86, 0x10a87,
+ 0x10a88, 0x10a89, 0x10a8a, 0x10a8b, 0x10a8c, 0x10a8d, 0x10a8e, 0x10a8f,
+ 0x10a90, 0x10a91, 0x10a92, 0x10a93, 0x10a94, 0x10a95, 0x10a96, 0x10a97,
+ 0x10a98, 0x10a99, 0x10a9a, 0x10a9b, 0x10a9c, 0x10a9d, 0x10a9e, 0x10a9f,
+ 0x10aa0, 0x10aa1, 0x10aa2, 0x10aa3, 0x10aa4, 0x10aa5, 0x10aa6, 0x10aa7,
+ 0x10aa8, 0x10aa9, 0x10aaa, 0x10aab, 0x10aac, 0x10aad, 0x10aae, 0x10aaf,
+ 0x10ab0, 0x10ab1, 0x10ab2, 0x10ab3, 0x10ab4, 0x10ab5, 0x10ab6, 0x10ab7,
+ 0x10ab8, 0x10ab9, 0x10aba, 0x10abb, 0x10abc, 0x10abd, 0x10abe, 0x10abf,
+ 0x10ac0, 0x10ac1, 0x10ac2, 0x10ac3, 0x10ac4, 0x10ac5, 0x10ac6, 0x10ac7,
+ 0x10ac8, 0x10ac9, 0x10aca, 0x10acb, 0x10acc, 0x10acd, 0x10ace, 0x10acf,
+ 0x10ad0, 0x10ad1, 0x10ad2, 0x10ad3, 0x10ad4, 0x10ad5, 0x10ad6, 0x10ad7,
+ 0x10ad8, 0x10ad9, 0x10ada, 0x10adb, 0x10adc, 0x10add, 0x10ade, 0x10adf,
+ 0x10ae0, 0x10ae1, 0x10ae2, 0x10ae3, 0x10ae4, 0x10ae5, 0x10ae6, 0x10ae7,
+ 0x10ae8, 0x10ae9, 0x10aea, 0x10aeb, 0x10aec, 0x10aed, 0x10aee, 0x10aef,
+ 0x10af0, 0x10af1, 0x10af2, 0x10af3, 0x10af4, 0x10af5, 0x10af6, 0x10af7,
+ 0x10af8, 0x10af9, 0x10afa, 0x10afb, 0x10afc, 0x10afd, 0x10afe, 0x10aff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10b[] = {
+ 0x10b00, 0x10b01, 0x10b02, 0x10b03, 0x10b04, 0x10b05, 0x10b06, 0x10b07,
+ 0x10b08, 0x10b09, 0x10b0a, 0x10b0b, 0x10b0c, 0x10b0d, 0x10b0e, 0x10b0f,
+ 0x10b10, 0x10b11, 0x10b12, 0x10b13, 0x10b14, 0x10b15, 0x10b16, 0x10b17,
+ 0x10b18, 0x10b19, 0x10b1a, 0x10b1b, 0x10b1c, 0x10b1d, 0x10b1e, 0x10b1f,
+ 0x10b20, 0x10b21, 0x10b22, 0x10b23, 0x10b24, 0x10b25, 0x10b26, 0x10b27,
+ 0x10b28, 0x10b29, 0x10b2a, 0x10b2b, 0x10b2c, 0x10b2d, 0x10b2d, 0x10b2f,
+ 0x10b30, 0x10b31, 0x10b32, 0x10b33, 0x10b34, 0x10b35, 0x10b36, 0x10b37,
+ 0x10b38, 0x10b39, 0x10b3a, 0x10b3b, 0x10b3c, 0x10b3d, 0x10b3e, 0x10b3f,
+ 0x10b40, 0x10b41, 0x10b42, 0x10b43, 0x10b44, 0x10b45, 0x10b46, 0x10b47,
+ 0x10b48, 0x10b49, 0x10b4a, 0x10b4b, 0x10b4c, 0x10b4d, 0x10b4e, 0x10b4f,
+ 0x10b50, 0x10b51, 0x10b52, 0x10b53, 0x10b54, 0x10b55, 0x10b56, 0x10b57,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x10b5c, 0x10b5d, 0x10b5e, 0x10b5f,
+ 0x10b60, 0x10b61, 0x10b62, 0x10b63, 0x10b64, 0x10b65, 0x10b66, 0x10b67,
+ 0x10b68, 0x10b69, 0x10b6a, 0x10b6b, 0x10b6c, 0x10b6d, 0x10b6e, 0x10b6f,
+ 0x10b70, 0x10b71, 0x10b72, 0x10b73, 0x10b74, 0x10b75, 0x10b76, 0x10b77,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x10b7c, 0x10b7d, 0x10b7e, 0x10b7f,
+ 0x10b80, 0x10b81, 0x10b82, 0x10b83, 0x10b84, 0x10b85, 0x10b86, 0x10b87,
+ 0x10b88, 0x10b89, 0x10b8a, 0x10b8b, 0x10b8c, 0x10b8d, 0x10b8e, 0x10b8f,
+ 0x10b90, 0x10b91, 0x10b92, 0x10b93, 0x10b94, 0x10b95, 0x10b96, 0x10b97,
+ 0x10b98, 0x10b99, 0x10b9a, 0x10b9b, 0x10b9c, 0x10b9d, 0x10b9e, 0x10b9f,
+ 0x10ba0, 0x10ba1, 0x10ba2, 0x10ba3, 0x10ba4, 0x10ba5, 0x10ba6, 0x10ba7,
+ 0x10ba8, 0x10ba9, 0x10baa, 0x10bab, 0x10bac, 0x10bad, 0x10bae, 0x10baf,
+ 0x10bb0, 0x10bb1, 0x10bb2, 0x10bb3, 0x10bb4, 0x10bb5, 0x10bb6, 0x10bb7,
+ 0x10bb8, 0x10bb9, 0x10bba, 0x10bbb, 0x10bbc, 0x10bbd, 0x10bbe, 0x10bbf,
+ 0x10bc0, 0x10bc1, 0x10bc2, 0x10bc3, 0x10bc4, 0x10bc5, 0x10bc6, 0x10bc7,
+ 0x10bc8, 0x10bc9, 0x10bca, 0x10bcb, 0x10bcc, 0x10bcd, 0x10bce, 0x10bcf,
+ 0x10bd0, 0x10bd1, 0x10bd2, 0x10bd3, 0x10bd4, 0x10bd5, 0x10bd6, 0x10bd7,
+ 0x10bd8, 0x10bd9, 0x10bda, 0x10bdb, 0x10bdc, 0x10bdd, 0x10bde, 0x10bdf,
+ 0x10be0, 0x10be1, 0x10be2, 0x10be3, 0x10be4, 0x10be5, 0x10be6, 0x10be7,
+ 0x10be8, 0x10be9, 0x10bea, 0x10beb, 0x10bec, 0x10bed, 0x10bee, 0x10bef,
+ 0x10bf0, 0x10bf1, 0x10bf2, 0x10bf3, 0x10bf4, 0x10bf5, 0x10bf6, 0x10bf7,
+ 0x10bf8, 0x10bf9, 0x10bfa, 0x10bfb, 0x10bfc, 0x10bfd, 0x10bfe, 0x10bff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10c[] = {
+ 0x10c00, 0x10c00, 0x10c02, 0x10c03, 0x10c03, 0x10c05, 0x10c06, 0x10c07,
+ 0x10c07, 0x10c09, 0x10c09, 0x10c0b, 0x10c0b, 0x10c0d, 0x10c0d, 0x10c0f,
+ 0x10c0f, 0x10c11, 0x10c11, 0x10c13, 0x10c14, 0x10c14, 0x10c16, 0x10c16,
+ 0x10c18, 0x10c18, 0x10c1a, 0x10c1a, 0x10c1c, 0x10c1c, 0x10c1e, 0x10c1e,
+ 0x10c20, 0x10c21, 0x10c22, 0x10c23, 0x10c24, 0x10c24, 0x10c26, 0x10c26,
+ 0x10c28, 0x10c28, 0x10c2a, 0x10c2a, 0x10c2c, 0x10c2d, 0x10c2d, 0x10c2f,
+ 0x10c30, 0x10c31, 0x10c32, 0x10c32, 0x10c34, 0x10c34, 0x10c36, 0x10c36,
+ 0x10c38, 0x10c38, 0x10c3a, 0x10c3a, 0x10c3c, 0x10c3d, 0x10c3e, 0x10c3f,
+ 0x10c3f, 0x10c41, 0x10c41, 0x10c43, 0x10c43, 0x10c45, 0x10c45, 0x10c47,
+ 0x10c48, 0x10c49, 0x10c4a, 0x10c4b, 0x10c4c, 0x10c4d, 0x10c4e, 0x10c4f,
+ 0x10c50, 0x10c51, 0x10c52, 0x10c53, 0x10c54, 0x10c55, 0x10c56, 0x10c57,
+ 0x10c58, 0x10c59, 0x10c5a, 0x10c5b, 0x10c5c, 0x10c5d, 0x10c5e, 0x10c5f,
+ 0x10c60, 0x10c61, 0x10c62, 0x10c63, 0x10c64, 0x10c65, 0x10c66, 0x10c67,
+ 0x10c68, 0x10c69, 0x10c6a, 0x10c6b, 0x10c6c, 0x10c6d, 0x10c6e, 0x10c6f,
+ 0x10c70, 0x10c71, 0x10c72, 0x10c73, 0x10c74, 0x10c75, 0x10c76, 0x10c77,
+ 0x10c78, 0x10c79, 0x10c7a, 0x10c7b, 0x10c7c, 0x10c7d, 0x10c7e, 0x10c7f,
+ 0x10c80, 0x10c81, 0x10c82, 0x10c83, 0x10c84, 0x10c85, 0x10c86, 0x10c87,
+ 0x10c88, 0x10c89, 0x10c8a, 0x10c8b, 0x10c8c, 0x10c8d, 0x10c8e, 0x10c8f,
+ 0x10c90, 0x10c91, 0x10c92, 0x10c93, 0x10c94, 0x10c95, 0x10c96, 0x10c97,
+ 0x10c98, 0x10c99, 0x10c9a, 0x10c9b, 0x10c9c, 0x10c9d, 0x10c9e, 0x10c9f,
+ 0x10ca0, 0x10ca1, 0x10ca2, 0x10ca3, 0x10ca4, 0x10ca5, 0x10ca6, 0x10ca7,
+ 0x10ca8, 0x10ca9, 0x10caa, 0x10cab, 0x10cac, 0x10cad, 0x10cae, 0x10caf,
+ 0x10cb0, 0x10cb1, 0x10cb2, 0x10cb3, 0x10cb4, 0x10cb5, 0x10cb6, 0x10cb7,
+ 0x10cb8, 0x10cb9, 0x10cba, 0x10cbb, 0x10cbc, 0x10cbd, 0x10cbe, 0x10cbf,
+ 0x10cc0, 0x10cc1, 0x10cc2, 0x10cc3, 0x10cc4, 0x10cc5, 0x10cc6, 0x10cc7,
+ 0x10cc8, 0x10cc9, 0x10cca, 0x10ccb, 0x10ccc, 0x10ccd, 0x10cce, 0x10ccf,
+ 0x10cd0, 0x10cd1, 0x10cd2, 0x10cd3, 0x10cd4, 0x10cd5, 0x10cd6, 0x10cd7,
+ 0x10cd8, 0x10cd9, 0x10cda, 0x10cdb, 0x10cdc, 0x10cdd, 0x10cde, 0x10cdf,
+ 0x10ce0, 0x10ce1, 0x10ce2, 0x10ce3, 0x10ce4, 0x10ce5, 0x10ce6, 0x10ce7,
+ 0x10ce8, 0x10ce9, 0x10cea, 0x10ceb, 0x10cec, 0x10ced, 0x10cee, 0x10cef,
+ 0x10cf0, 0x10cf1, 0x10cf2, 0x10cf3, 0x10cf4, 0x10cf5, 0x10cf6, 0x10cf7,
+ 0x10cf8, 0x10cf9, 0x10cfa, 0x10cfb, 0x10cfc, 0x10cfd, 0x10cfe, 0x10cff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10e[] = {
+ 0x10e00, 0x10e01, 0x10e02, 0x10e03, 0x10e04, 0x10e05, 0x10e06, 0x10e07,
+ 0x10e08, 0x10e09, 0x10e0a, 0x10e0b, 0x10e0c, 0x10e0d, 0x10e0e, 0x10e0f,
+ 0x10e10, 0x10e11, 0x10e12, 0x10e13, 0x10e14, 0x10e15, 0x10e16, 0x10e17,
+ 0x10e18, 0x10e19, 0x10e1a, 0x10e1b, 0x10e1c, 0x10e1d, 0x10e1e, 0x10e1f,
+ 0x10e20, 0x10e21, 0x10e22, 0x10e23, 0x10e24, 0x10e25, 0x10e26, 0x10e27,
+ 0x10e28, 0x10e29, 0x10e2a, 0x10e2b, 0x10e2c, 0x10e2d, 0x10e2e, 0x10e2f,
+ 0x10e30, 0x10e31, 0x10e32, 0x10e33, 0x10e34, 0x10e35, 0x10e36, 0x10e37,
+ 0x10e38, 0x10e39, 0x10e3a, 0x10e3b, 0x10e3c, 0x10e3d, 0x10e3e, 0x10e3f,
+ 0x10e40, 0x10e41, 0x10e42, 0x10e43, 0x10e44, 0x10e45, 0x10e46, 0x10e47,
+ 0x10e48, 0x10e49, 0x10e4a, 0x10e4b, 0x10e4c, 0x10e4d, 0x10e4e, 0x10e4f,
+ 0x10e50, 0x10e51, 0x10e52, 0x10e53, 0x10e54, 0x10e55, 0x10e56, 0x10e57,
+ 0x10e58, 0x10e59, 0x10e5a, 0x10e5b, 0x10e5c, 0x10e5d, 0x10e5e, 0x10e5f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x10e69, 0x10e6a, 0x10e6b, 0x10e6c, 0x10e6d, 0x10e6e, 0x10e6f,
+ 0x10e70, 0x10e71, 0x10e72, 0x10e73, 0x10e74, 0x10e75, 0x10e76, 0x10e77,
+ 0x10e78, 0x10e79, 0x10e7a, 0x10e7b, 0x10e7c, 0x10e7d, 0x10e7e, 0x10e7f,
+ 0x10e80, 0x10e81, 0x10e82, 0x10e83, 0x10e84, 0x10e85, 0x10e86, 0x10e87,
+ 0x10e88, 0x10e89, 0x10e8a, 0x10e8b, 0x10e8c, 0x10e8d, 0x10e8e, 0x10e8f,
+ 0x10e90, 0x10e91, 0x10e92, 0x10e93, 0x10e94, 0x10e95, 0x10e96, 0x10e97,
+ 0x10e98, 0x10e99, 0x10e9a, 0x10e9b, 0x10e9c, 0x10e9d, 0x10e9e, 0x10e9f,
+ 0x10ea0, 0x10ea1, 0x10ea2, 0x10ea3, 0x10ea4, 0x10ea5, 0x10ea6, 0x10ea7,
+ 0x10ea8, 0x10ea9, 0x10eaa, 0x10eab, 0x10eac, 0x10ead, 0x10eae, 0x10eaf,
+ 0x10eb0, 0x10eb1, 0x10eb2, 0x10eb3, 0x10eb4, 0x10eb5, 0x10eb6, 0x10eb7,
+ 0x10eb8, 0x10eb9, 0x10eba, 0x10ebb, 0x10ebc, 0x10ebd, 0x10ebe, 0x10ebf,
+ 0x10ec0, 0x10ec1, 0x10ec2, 0x10ec3, 0x10ec4, 0x10ec5, 0x10ec6, 0x10ec7,
+ 0x10ec8, 0x10ec9, 0x10eca, 0x10ecb, 0x10ecc, 0x10ecd, 0x10ece, 0x10ecf,
+ 0x10ed0, 0x10ed1, 0x10ed2, 0x10ed3, 0x10ed4, 0x10ed5, 0x10ed6, 0x10ed7,
+ 0x10ed8, 0x10ed9, 0x10eda, 0x10edb, 0x10edc, 0x10edd, 0x10ede, 0x10edf,
+ 0x10ee0, 0x10ee1, 0x10ee2, 0x10ee3, 0x10ee4, 0x10ee5, 0x10ee6, 0x10ee7,
+ 0x10ee8, 0x10ee9, 0x10eea, 0x10eeb, 0x10eec, 0x10eed, 0x10eee, 0x10eef,
+ 0x10ef0, 0x10ef1, 0x10ef2, 0x10ef3, 0x10ef4, 0x10ef5, 0x10ef6, 0x10ef7,
+ 0x10ef8, 0x10ef9, 0x10efa, 0x10efb, 0x10efc, 0x10efd, 0x10efe, 0x10eff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_110[] = {
+ 0x11000, 0x11001, 0x11002, 0x11003, 0x11004, 0x11005, 0x11006, 0x11007,
+ 0x11008, 0x11009, 0x1100a, 0x1100b, 0x1100c, 0x1100d, 0x1100e, 0x1100f,
+ 0x11010, 0x11011, 0x11012, 0x11013, 0x11014, 0x11015, 0x11016, 0x11017,
+ 0x11018, 0x11019, 0x1101a, 0x1101b, 0x1101c, 0x1101d, 0x1101e, 0x1101f,
+ 0x11020, 0x11021, 0x11022, 0x11023, 0x11024, 0x11025, 0x11026, 0x11027,
+ 0x11028, 0x11029, 0x1102a, 0x1102b, 0x1102c, 0x1102d, 0x1102e, 0x1102f,
+ 0x11030, 0x11031, 0x11032, 0x11033, 0x11034, 0x11035, 0x11036, 0x11037,
+ 0x11038, 0x11039, 0x1103a, 0x1103b, 0x1103c, 0x1103d, 0x1103e, 0x1103f,
+ 0x11040, 0x11041, 0x11042, 0x11043, 0x11044, 0x11045, 0x11046, 0x11047,
+ 0x11048, 0x11049, 0x1104a, 0x1104b, 0x1104c, 0x1104d, 0x1104e, 0x1104f,
+ 0x11050, 0x11051, 0x11052, 0x11053, 0x11054, 0x11055, 0x11056, 0x11057,
+ 0x11058, 0x11059, 0x1105a, 0x1105b, 0x1105c, 0x1105d, 0x1105e, 0x1105f,
+ 0x11060, 0x11061, 0x11062, 0x11063, 0x11064, 0x11065, 0x11066, 0x11067,
+ 0x11068, 0x11069, 0x1106a, 0x1106b, 0x1106c, 0x1106d, 0x1106e, 0x1106f,
+ 0x11070, 0x11071, 0x11072, 0x11073, 0x11074, 0x11075, 0x11076, 0x11077,
+ 0x11078, 0x11079, 0x1107a, 0x1107b, 0x1107c, 0x1107d, 0x1107e, 0x1107f,
+ 0x00000, 0x00000, 0x00000, 0x11083, 0x11084, 0x11085, 0x11086, 0x11087,
+ 0x11088, 0x11089, 0x1108a, 0x1108b, 0x1108c, 0x1108d, 0x1108e, 0x1108f,
+ 0x11090, 0x11091, 0x11092, 0x11093, 0x11094, 0x11095, 0x11096, 0x11097,
+ 0x11098, 0x11099, 0x11099, 0x1109b, 0x1109b, 0x1109d, 0x1109e, 0x1109f,
+ 0x110a0, 0x110a1, 0x110a2, 0x110a3, 0x110a4, 0x110a5, 0x110a6, 0x110a7,
+ 0x110a8, 0x110a9, 0x110aa, 0x110a5, 0x110ac, 0x110ad, 0x110ae, 0x110af,
+ 0x110b0, 0x110b1, 0x110b2, 0x110b3, 0x110b4, 0x110b5, 0x110b6, 0x110b7,
+ 0x110b8, 0x110b9, 0x00000, 0x110bb, 0x110bc, 0x00000, 0x110be, 0x110bf,
+ 0x110c0, 0x110c1, 0x110c2, 0x110c3, 0x110c4, 0x110c5, 0x110c6, 0x110c7,
+ 0x110c8, 0x110c9, 0x110ca, 0x110cb, 0x110cc, 0x110cd, 0x110ce, 0x110cf,
+ 0x110d0, 0x110d1, 0x110d2, 0x110d3, 0x110d4, 0x110d5, 0x110d6, 0x110d7,
+ 0x110d8, 0x110d9, 0x110da, 0x110db, 0x110dc, 0x110dd, 0x110de, 0x110df,
+ 0x110e0, 0x110e1, 0x110e2, 0x110e3, 0x110e4, 0x110e5, 0x110e6, 0x110e7,
+ 0x110e8, 0x110e9, 0x110ea, 0x110eb, 0x110ec, 0x110ed, 0x110ee, 0x110ef,
+ 0x110f0, 0x110f1, 0x110f2, 0x110f3, 0x110f4, 0x110f5, 0x110f6, 0x110f7,
+ 0x110f8, 0x110f9, 0x110fa, 0x110fb, 0x110fc, 0x110fd, 0x110fe, 0x110ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_124[] = {
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00034,
+ 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00031, 0x00032,
+ 0x00033, 0x00034, 0x00035, 0x00032, 0x00033, 0x00033, 0x00034, 0x00035,
+ 0x00036, 0x00037, 0x00038, 0x00039, 0x00031, 0x00032, 0x00033, 0x00033,
+ 0x00034, 0x00035, 0x12432, 0x12433, 0x00031, 0x00032, 0x00033, 0x00033,
+ 0x00034, 0x00035, 0x00033, 0x00033, 0x00034, 0x00034, 0x00034, 0x00034,
+ 0x00036, 0x00037, 0x00037, 0x00037, 0x00038, 0x00038, 0x00039, 0x00039,
+ 0x00039, 0x00039, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, 0x12456, 0x12457,
+ 0x00031, 0x00032, 0x1245a, 0x1245b, 0x1245c, 0x1245d, 0x1245e, 0x1245f,
+ 0x12460, 0x12461, 0x12462, 0x12463, 0x12464, 0x12465, 0x12466, 0x12467,
+ 0x12468, 0x12469, 0x1246a, 0x1246b, 0x1246c, 0x1246d, 0x1246e, 0x1246f,
+ 0x12470, 0x12471, 0x12472, 0x12473, 0x12474, 0x12475, 0x12476, 0x12477,
+ 0x12478, 0x12479, 0x1247a, 0x1247b, 0x1247c, 0x1247d, 0x1247e, 0x1247f,
+ 0x12480, 0x12481, 0x12482, 0x12483, 0x12484, 0x12485, 0x12486, 0x12487,
+ 0x12488, 0x12489, 0x1248a, 0x1248b, 0x1248c, 0x1248d, 0x1248e, 0x1248f,
+ 0x12490, 0x12491, 0x12492, 0x12493, 0x12494, 0x12495, 0x12496, 0x12497,
+ 0x12498, 0x12499, 0x1249a, 0x1249b, 0x1249c, 0x1249d, 0x1249e, 0x1249f,
+ 0x124a0, 0x124a1, 0x124a2, 0x124a3, 0x124a4, 0x124a5, 0x124a6, 0x124a7,
+ 0x124a8, 0x124a9, 0x124aa, 0x124ab, 0x124ac, 0x124ad, 0x124ae, 0x124af,
+ 0x124b0, 0x124b1, 0x124b2, 0x124b3, 0x124b4, 0x124b5, 0x124b6, 0x124b7,
+ 0x124b8, 0x124b9, 0x124ba, 0x124bb, 0x124bc, 0x124bd, 0x124be, 0x124bf,
+ 0x124c0, 0x124c1, 0x124c2, 0x124c3, 0x124c4, 0x124c5, 0x124c6, 0x124c7,
+ 0x124c8, 0x124c9, 0x124ca, 0x124cb, 0x124cc, 0x124cd, 0x124ce, 0x124cf,
+ 0x124d0, 0x124d1, 0x124d2, 0x124d3, 0x124d4, 0x124d5, 0x124d6, 0x124d7,
+ 0x124d8, 0x124d9, 0x124da, 0x124db, 0x124dc, 0x124dd, 0x124de, 0x124df,
+ 0x124e0, 0x124e1, 0x124e2, 0x124e3, 0x124e4, 0x124e5, 0x124e6, 0x124e7,
+ 0x124e8, 0x124e9, 0x124ea, 0x124eb, 0x124ec, 0x124ed, 0x124ee, 0x124ef,
+ 0x124f0, 0x124f1, 0x124f2, 0x124f3, 0x124f4, 0x124f5, 0x124f6, 0x124f7,
+ 0x124f8, 0x124f9, 0x124fa, 0x124fb, 0x124fc, 0x124fd, 0x124fe, 0x124ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d1[] = {
+ 0x1d100, 0x1d101, 0x1d102, 0x1d103, 0x1d104, 0x1d105, 0x1d106, 0x1d107,
+ 0x1d108, 0x1d109, 0x1d10a, 0x1d10b, 0x1d10c, 0x1d10d, 0x1d10e, 0x1d10f,
+ 0x1d110, 0x1d111, 0x1d112, 0x1d113, 0x1d114, 0x1d115, 0x1d116, 0x1d117,
+ 0x1d118, 0x1d119, 0x1d11a, 0x1d11b, 0x1d11c, 0x1d11d, 0x1d11e, 0x1d11f,
+ 0x1d120, 0x1d121, 0x1d122, 0x1d123, 0x1d124, 0x1d125, 0x1d126, 0x1d127,
+ 0x1d128, 0x1d129, 0x1d12a, 0x1d12b, 0x1d12c, 0x1d12d, 0x1d12e, 0x1d12f,
+ 0x1d130, 0x1d131, 0x1d132, 0x1d133, 0x1d134, 0x1d135, 0x1d136, 0x1d137,
+ 0x1d138, 0x1d139, 0x1d13a, 0x1d13b, 0x1d13c, 0x1d13d, 0x1d13e, 0x1d13f,
+ 0x1d140, 0x1d141, 0x1d142, 0x1d143, 0x1d144, 0x1d145, 0x1d146, 0x1d147,
+ 0x1d148, 0x1d149, 0x1d14a, 0x1d14b, 0x1d14c, 0x1d14d, 0x1d14e, 0x1d14f,
+ 0x1d150, 0x1d151, 0x1d152, 0x1d153, 0x1d154, 0x1d155, 0x1d156, 0x1d157,
+ 0x1d158, 0x1d159, 0x1d15a, 0x1d15b, 0x1d15c, 0x1d15d, 0x1d157, 0x1d158,
+ 0x1d158, 0x1d158, 0x1d158, 0x1d158, 0x1d158, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x1d16a, 0x1d16b, 0x1d16c, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x1d183, 0x1d184, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x1d18c, 0x1d18d, 0x1d18e, 0x1d18f,
+ 0x1d190, 0x1d191, 0x1d192, 0x1d193, 0x1d194, 0x1d195, 0x1d196, 0x1d197,
+ 0x1d198, 0x1d199, 0x1d19a, 0x1d19b, 0x1d19c, 0x1d19d, 0x1d19e, 0x1d19f,
+ 0x1d1a0, 0x1d1a1, 0x1d1a2, 0x1d1a3, 0x1d1a4, 0x1d1a5, 0x1d1a6, 0x1d1a7,
+ 0x1d1a8, 0x1d1a9, 0x00000, 0x00000, 0x00000, 0x00000, 0x1d1ae, 0x1d1af,
+ 0x1d1b0, 0x1d1b1, 0x1d1b2, 0x1d1b3, 0x1d1b4, 0x1d1b5, 0x1d1b6, 0x1d1b7,
+ 0x1d1b8, 0x1d1b9, 0x1d1ba, 0x1d1b9, 0x1d1ba, 0x1d1b9, 0x1d1ba, 0x1d1b9,
+ 0x1d1ba, 0x1d1c1, 0x1d1c2, 0x1d1c3, 0x1d1c4, 0x1d1c5, 0x1d1c6, 0x1d1c7,
+ 0x1d1c8, 0x1d1c9, 0x1d1ca, 0x1d1cb, 0x1d1cc, 0x1d1cd, 0x1d1ce, 0x1d1cf,
+ 0x1d1d0, 0x1d1d1, 0x1d1d2, 0x1d1d3, 0x1d1d4, 0x1d1d5, 0x1d1d6, 0x1d1d7,
+ 0x1d1d8, 0x1d1d9, 0x1d1da, 0x1d1db, 0x1d1dc, 0x1d1dd, 0x1d1de, 0x1d1df,
+ 0x1d1e0, 0x1d1e1, 0x1d1e2, 0x1d1e3, 0x1d1e4, 0x1d1e5, 0x1d1e6, 0x1d1e7,
+ 0x1d1e8, 0x1d1e9, 0x1d1ea, 0x1d1eb, 0x1d1ec, 0x1d1ed, 0x1d1ee, 0x1d1ef,
+ 0x1d1f0, 0x1d1f1, 0x1d1f2, 0x1d1f3, 0x1d1f4, 0x1d1f5, 0x1d1f6, 0x1d1f7,
+ 0x1d1f8, 0x1d1f9, 0x1d1fa, 0x1d1fb, 0x1d1fc, 0x1d1fd, 0x1d1fe, 0x1d1ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d2[] = {
+ 0x1d200, 0x1d201, 0x1d202, 0x1d203, 0x1d204, 0x1d205, 0x1d206, 0x1d207,
+ 0x1d208, 0x1d209, 0x1d20a, 0x1d20b, 0x1d20c, 0x1d20d, 0x1d20e, 0x1d20f,
+ 0x1d210, 0x1d211, 0x1d212, 0x1d213, 0x1d214, 0x1d215, 0x1d216, 0x1d217,
+ 0x1d218, 0x1d219, 0x1d21a, 0x1d21b, 0x1d21c, 0x1d21d, 0x1d21e, 0x1d21f,
+ 0x1d220, 0x1d221, 0x1d222, 0x1d223, 0x1d224, 0x1d225, 0x1d226, 0x1d227,
+ 0x1d228, 0x1d229, 0x1d22a, 0x1d22b, 0x1d22c, 0x1d22d, 0x1d22e, 0x1d22f,
+ 0x1d230, 0x1d231, 0x1d232, 0x1d233, 0x1d234, 0x1d235, 0x1d236, 0x1d237,
+ 0x1d238, 0x1d239, 0x1d23a, 0x1d23b, 0x1d23c, 0x1d23d, 0x1d23e, 0x1d23f,
+ 0x1d240, 0x1d241, 0x00000, 0x00000, 0x00000, 0x1d245, 0x1d246, 0x1d247,
+ 0x1d248, 0x1d249, 0x1d24a, 0x1d24b, 0x1d24c, 0x1d24d, 0x1d24e, 0x1d24f,
+ 0x1d250, 0x1d251, 0x1d252, 0x1d253, 0x1d254, 0x1d255, 0x1d256, 0x1d257,
+ 0x1d258, 0x1d259, 0x1d25a, 0x1d25b, 0x1d25c, 0x1d25d, 0x1d25e, 0x1d25f,
+ 0x1d260, 0x1d261, 0x1d262, 0x1d263, 0x1d264, 0x1d265, 0x1d266, 0x1d267,
+ 0x1d268, 0x1d269, 0x1d26a, 0x1d26b, 0x1d26c, 0x1d26d, 0x1d26e, 0x1d26f,
+ 0x1d270, 0x1d271, 0x1d272, 0x1d273, 0x1d274, 0x1d275, 0x1d276, 0x1d277,
+ 0x1d278, 0x1d279, 0x1d27a, 0x1d27b, 0x1d27c, 0x1d27d, 0x1d27e, 0x1d27f,
+ 0x1d280, 0x1d281, 0x1d282, 0x1d283, 0x1d284, 0x1d285, 0x1d286, 0x1d287,
+ 0x1d288, 0x1d289, 0x1d28a, 0x1d28b, 0x1d28c, 0x1d28d, 0x1d28e, 0x1d28f,
+ 0x1d290, 0x1d291, 0x1d292, 0x1d293, 0x1d294, 0x1d295, 0x1d296, 0x1d297,
+ 0x1d298, 0x1d299, 0x1d29a, 0x1d29b, 0x1d29c, 0x1d29d, 0x1d29e, 0x1d29f,
+ 0x1d2a0, 0x1d2a1, 0x1d2a2, 0x1d2a3, 0x1d2a4, 0x1d2a5, 0x1d2a6, 0x1d2a7,
+ 0x1d2a8, 0x1d2a9, 0x1d2aa, 0x1d2ab, 0x1d2ac, 0x1d2ad, 0x1d2ae, 0x1d2af,
+ 0x1d2b0, 0x1d2b1, 0x1d2b2, 0x1d2b3, 0x1d2b4, 0x1d2b5, 0x1d2b6, 0x1d2b7,
+ 0x1d2b8, 0x1d2b9, 0x1d2ba, 0x1d2bb, 0x1d2bc, 0x1d2bd, 0x1d2be, 0x1d2bf,
+ 0x1d2c0, 0x1d2c1, 0x1d2c2, 0x1d2c3, 0x1d2c4, 0x1d2c5, 0x1d2c6, 0x1d2c7,
+ 0x1d2c8, 0x1d2c9, 0x1d2ca, 0x1d2cb, 0x1d2cc, 0x1d2cd, 0x1d2ce, 0x1d2cf,
+ 0x1d2d0, 0x1d2d1, 0x1d2d2, 0x1d2d3, 0x1d2d4, 0x1d2d5, 0x1d2d6, 0x1d2d7,
+ 0x1d2d8, 0x1d2d9, 0x1d2da, 0x1d2db, 0x1d2dc, 0x1d2dd, 0x1d2de, 0x1d2df,
+ 0x1d2e0, 0x1d2e1, 0x1d2e2, 0x1d2e3, 0x1d2e4, 0x1d2e5, 0x1d2e6, 0x1d2e7,
+ 0x1d2e8, 0x1d2e9, 0x1d2ea, 0x1d2eb, 0x1d2ec, 0x1d2ed, 0x1d2ee, 0x1d2ef,
+ 0x1d2f0, 0x1d2f1, 0x1d2f2, 0x1d2f3, 0x1d2f4, 0x1d2f5, 0x1d2f6, 0x1d2f7,
+ 0x1d2f8, 0x1d2f9, 0x1d2fa, 0x1d2fb, 0x1d2fc, 0x1d2fd, 0x1d2fe, 0x1d2ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d3[] = {
+ 0x1d300, 0x1d301, 0x1d302, 0x1d303, 0x1d304, 0x1d305, 0x1d306, 0x1d307,
+ 0x1d308, 0x1d309, 0x1d30a, 0x1d30b, 0x1d30c, 0x1d30d, 0x1d30e, 0x1d30f,
+ 0x1d310, 0x1d311, 0x1d312, 0x1d313, 0x1d314, 0x1d315, 0x1d316, 0x1d317,
+ 0x1d318, 0x1d319, 0x1d31a, 0x1d31b, 0x1d31c, 0x1d31d, 0x1d31e, 0x1d31f,
+ 0x1d320, 0x1d321, 0x1d322, 0x1d323, 0x1d324, 0x1d325, 0x1d326, 0x1d327,
+ 0x1d328, 0x1d329, 0x1d32a, 0x1d32b, 0x1d32c, 0x1d32d, 0x1d32e, 0x1d32f,
+ 0x1d330, 0x1d331, 0x1d332, 0x1d333, 0x1d334, 0x1d335, 0x1d336, 0x1d337,
+ 0x1d338, 0x1d339, 0x1d33a, 0x1d33b, 0x1d33c, 0x1d33d, 0x1d33e, 0x1d33f,
+ 0x1d340, 0x1d341, 0x1d342, 0x1d343, 0x1d344, 0x1d345, 0x1d346, 0x1d347,
+ 0x1d348, 0x1d349, 0x1d34a, 0x1d34b, 0x1d34c, 0x1d34d, 0x1d34e, 0x1d34f,
+ 0x1d350, 0x1d351, 0x1d352, 0x1d353, 0x1d354, 0x1d355, 0x1d356, 0x1d357,
+ 0x1d358, 0x1d359, 0x1d35a, 0x1d35b, 0x1d35c, 0x1d35d, 0x1d35e, 0x1d35f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x1d369, 0x1d36a, 0x1d36b, 0x1d36c, 0x1d36d, 0x1d36e, 0x1d36f,
+ 0x1d370, 0x1d371, 0x1d372, 0x1d373, 0x1d374, 0x1d375, 0x1d376, 0x1d377,
+ 0x1d378, 0x1d379, 0x1d37a, 0x1d37b, 0x1d37c, 0x1d37d, 0x1d37e, 0x1d37f,
+ 0x1d380, 0x1d381, 0x1d382, 0x1d383, 0x1d384, 0x1d385, 0x1d386, 0x1d387,
+ 0x1d388, 0x1d389, 0x1d38a, 0x1d38b, 0x1d38c, 0x1d38d, 0x1d38e, 0x1d38f,
+ 0x1d390, 0x1d391, 0x1d392, 0x1d393, 0x1d394, 0x1d395, 0x1d396, 0x1d397,
+ 0x1d398, 0x1d399, 0x1d39a, 0x1d39b, 0x1d39c, 0x1d39d, 0x1d39e, 0x1d39f,
+ 0x1d3a0, 0x1d3a1, 0x1d3a2, 0x1d3a3, 0x1d3a4, 0x1d3a5, 0x1d3a6, 0x1d3a7,
+ 0x1d3a8, 0x1d3a9, 0x1d3aa, 0x1d3ab, 0x1d3ac, 0x1d3ad, 0x1d3ae, 0x1d3af,
+ 0x1d3b0, 0x1d3b1, 0x1d3b2, 0x1d3b3, 0x1d3b4, 0x1d3b5, 0x1d3b6, 0x1d3b7,
+ 0x1d3b8, 0x1d3b9, 0x1d3ba, 0x1d3bb, 0x1d3bc, 0x1d3bd, 0x1d3be, 0x1d3bf,
+ 0x1d3c0, 0x1d3c1, 0x1d3c2, 0x1d3c3, 0x1d3c4, 0x1d3c5, 0x1d3c6, 0x1d3c7,
+ 0x1d3c8, 0x1d3c9, 0x1d3ca, 0x1d3cb, 0x1d3cc, 0x1d3cd, 0x1d3ce, 0x1d3cf,
+ 0x1d3d0, 0x1d3d1, 0x1d3d2, 0x1d3d3, 0x1d3d4, 0x1d3d5, 0x1d3d6, 0x1d3d7,
+ 0x1d3d8, 0x1d3d9, 0x1d3da, 0x1d3db, 0x1d3dc, 0x1d3dd, 0x1d3de, 0x1d3df,
+ 0x1d3e0, 0x1d3e1, 0x1d3e2, 0x1d3e3, 0x1d3e4, 0x1d3e5, 0x1d3e6, 0x1d3e7,
+ 0x1d3e8, 0x1d3e9, 0x1d3ea, 0x1d3eb, 0x1d3ec, 0x1d3ed, 0x1d3ee, 0x1d3ef,
+ 0x1d3f0, 0x1d3f1, 0x1d3f2, 0x1d3f3, 0x1d3f4, 0x1d3f5, 0x1d3f6, 0x1d3f7,
+ 0x1d3f8, 0x1d3f9, 0x1d3fa, 0x1d3fb, 0x1d3fc, 0x1d3fd, 0x1d3fe, 0x1d3ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d4[] = {
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x1d455, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x1d49d, 0x00043, 0x00044,
+ 0x1d4a0, 0x1d4a1, 0x00047, 0x1d4a3, 0x1d4a4, 0x0004a, 0x0004b, 0x1d4a7,
+ 0x1d4a8, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x1d4ad, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x1d4ba, 0x00046, 0x1d4bc, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x1d4c4, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x1d4ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d5[] = {
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x1d506, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x1d50b, 0x1d50c, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x1d515, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x1d51d, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x1d53a, 0x00044, 0x00045, 0x00046, 0x00047, 0x1d53f,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x1d545, 0x0004f, 0x1d547,
+ 0x1d548, 0x1d549, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x1d551, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x1d5ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d6[] = {
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00131, 0x00237, 0x1d6a6, 0x1d6a7,
+ 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398,
+ 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0,
+ 0x003a1, 0x00398, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8,
+ 0x003a9, 0x02207, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396,
+ 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e,
+ 0x0039f, 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6,
+ 0x003a7, 0x003a8, 0x003a9, 0x02202, 0x00395, 0x00398, 0x0039a, 0x003a6,
+ 0x003a1, 0x003a0, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396,
+ 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e,
+ 0x0039f, 0x003a0, 0x003a1, 0x00398, 0x003a3, 0x003a4, 0x003a5, 0x003a6,
+ 0x003a7, 0x003a8, 0x003a9, 0x02207, 0x00391, 0x00392, 0x00393, 0x1d6ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d7[] = {
+ 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c,
+ 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4,
+ 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02202, 0x00395, 0x00398,
+ 0x0039a, 0x003a6, 0x003a1, 0x003a0, 0x00391, 0x00392, 0x00393, 0x00394,
+ 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c,
+ 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x00398, 0x003a3, 0x003a4,
+ 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02207, 0x00391, 0x00392,
+ 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a,
+ 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x003a3,
+ 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02202,
+ 0x00395, 0x00398, 0x0039a, 0x003a6, 0x003a1, 0x003a0, 0x00391, 0x00392,
+ 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a,
+ 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x00398,
+ 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02207,
+ 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398,
+ 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0,
+ 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8,
+ 0x003a9, 0x02202, 0x00395, 0x00398, 0x0039a, 0x003a6, 0x003a1, 0x003a0,
+ 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398,
+ 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0,
+ 0x003a1, 0x00398, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8,
+ 0x003a9, 0x02207, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396,
+ 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e,
+ 0x0039f, 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6,
+ 0x003a7, 0x003a8, 0x003a9, 0x02202, 0x00395, 0x00398, 0x0039a, 0x003a6,
+ 0x003a1, 0x003a0, 0x003dc, 0x003dc, 0x1d7cc, 0x1d7cd, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035,
+ 0x00036, 0x00037, 0x00038, 0x00039, 0x00030, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x1d7ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f1[] = {
+ 0x1f100, 0x1f101, 0x1f102, 0x1f103, 0x1f104, 0x1f105, 0x1f106, 0x1f107,
+ 0x1f108, 0x1f109, 0x1f10a, 0x1f10b, 0x1f10c, 0x1f10d, 0x1f10e, 0x1f10f,
+ 0x0249c, 0x0249d, 0x0249e, 0x0249f, 0x024a0, 0x024a1, 0x024a2, 0x024a3,
+ 0x024a4, 0x024a5, 0x024a6, 0x024a7, 0x024a8, 0x024a9, 0x024aa, 0x024ab,
+ 0x024ac, 0x024ad, 0x024ae, 0x024af, 0x024b0, 0x024b1, 0x024b2, 0x024b3,
+ 0x024b4, 0x024b5, 0x1f12a, 0x00043, 0x00052, 0x033c5, 0x1f12e, 0x1f12f,
+ 0x1f130, 0x00042, 0x1f132, 0x1f133, 0x1f134, 0x1f135, 0x1f136, 0x1f137,
+ 0x1f138, 0x1f139, 0x1f13a, 0x1f13b, 0x1f13c, 0x0004e, 0x1f13e, 0x00050,
+ 0x1f140, 0x1f141, 0x00053, 0x1f143, 0x1f144, 0x1f145, 0x00057, 0x1f147,
+ 0x1f148, 0x1f149, 0x1f14a, 0x033b7, 0x1f14c, 0x000df, 0x1f14e, 0x1f14f,
+ 0x1f150, 0x1f151, 0x1f152, 0x1f153, 0x1f154, 0x1f155, 0x1f156, 0x00048,
+ 0x1f158, 0x1f159, 0x1f15a, 0x1f15b, 0x1f15c, 0x1f15d, 0x1f15e, 0x00050,
+ 0x1f160, 0x1f161, 0x1f162, 0x1f163, 0x1f164, 0x1f165, 0x1f166, 0x1f167,
+ 0x1f168, 0x1f169, 0x1f16a, 0x1f16b, 0x1f16c, 0x1f16d, 0x1f16e, 0x1f16f,
+ 0x1f170, 0x1f171, 0x1f172, 0x1f173, 0x1f174, 0x1f175, 0x1f176, 0x1f177,
+ 0x1f178, 0x0004a, 0x1f17a, 0x0004c, 0x0004d, 0x1f17d, 0x1f17e, 0x00050,
+ 0x1f180, 0x1f181, 0x1f182, 0x1f183, 0x1f184, 0x1f185, 0x1f186, 0x1f187,
+ 0x1f188, 0x1f189, 0x00050, 0x1f18b, 0x03380, 0x1f18d, 0x1f18e, 0x1f18f,
+ 0x1f190, 0x1f191, 0x1f192, 0x1f193, 0x1f194, 0x1f195, 0x1f196, 0x1f197,
+ 0x1f198, 0x1f199, 0x1f19a, 0x1f19b, 0x1f19c, 0x1f19d, 0x1f19e, 0x1f19f,
+ 0x1f1a0, 0x1f1a1, 0x1f1a2, 0x1f1a3, 0x1f1a4, 0x1f1a5, 0x1f1a6, 0x1f1a7,
+ 0x1f1a8, 0x1f1a9, 0x1f1aa, 0x1f1ab, 0x1f1ac, 0x1f1ad, 0x1f1ae, 0x1f1af,
+ 0x1f1b0, 0x1f1b1, 0x1f1b2, 0x1f1b3, 0x1f1b4, 0x1f1b5, 0x1f1b6, 0x1f1b7,
+ 0x1f1b8, 0x1f1b9, 0x1f1ba, 0x1f1bb, 0x1f1bc, 0x1f1bd, 0x1f1be, 0x1f1bf,
+ 0x1f1c0, 0x1f1c1, 0x1f1c2, 0x1f1c3, 0x1f1c4, 0x1f1c5, 0x1f1c6, 0x1f1c7,
+ 0x1f1c8, 0x1f1c9, 0x1f1ca, 0x1f1cb, 0x1f1cc, 0x1f1cd, 0x1f1ce, 0x1f1cf,
+ 0x1f1d0, 0x1f1d1, 0x1f1d2, 0x1f1d3, 0x1f1d4, 0x1f1d5, 0x1f1d6, 0x1f1d7,
+ 0x1f1d8, 0x1f1d9, 0x1f1da, 0x1f1db, 0x1f1dc, 0x1f1dd, 0x1f1de, 0x1f1df,
+ 0x1f1e0, 0x1f1e1, 0x1f1e2, 0x1f1e3, 0x1f1e4, 0x1f1e5, 0x1f1e6, 0x1f1e7,
+ 0x1f1e8, 0x1f1e9, 0x1f1ea, 0x1f1eb, 0x1f1ec, 0x1f1ed, 0x1f1ee, 0x1f1ef,
+ 0x1f1f0, 0x1f1f1, 0x1f1f2, 0x1f1f3, 0x1f1f4, 0x1f1f5, 0x1f1f6, 0x1f1f7,
+ 0x1f1f8, 0x1f1f9, 0x1f1fa, 0x1f1fb, 0x1f1fc, 0x1f1fd, 0x1f1fe, 0x1f1ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f2[] = {
+ 0x1f200, 0x1f201, 0x1f202, 0x1f203, 0x1f204, 0x1f205, 0x1f206, 0x1f207,
+ 0x1f208, 0x1f209, 0x1f20a, 0x1f20b, 0x1f20c, 0x1f20d, 0x1f20e, 0x1f20f,
+ 0x02f3f, 0x1f211, 0x1f212, 0x03066, 0x03193, 0x1f215, 0x1f216, 0x0319d,
+ 0x1f218, 0x1f219, 0x1f21a, 0x0f9be, 0x1f21c, 0x1f21d, 0x1f21e, 0x1f21f,
+ 0x1f220, 0x1f221, 0x02f63, 0x1f223, 0x1f224, 0x1f225, 0x1f226, 0x1f227,
+ 0x1f228, 0x03192, 0x03194, 0x1f22b, 0x032a7, 0x03197, 0x032a8, 0x1f22f,
+ 0x02f9b, 0x1f231, 0x1f232, 0x1f233, 0x1f234, 0x1f235, 0x1f236, 0x1f237,
+ 0x1f238, 0x1f239, 0x1f23a, 0x1f23b, 0x1f23c, 0x1f23d, 0x1f23e, 0x1f23f,
+ 0x1f240, 0x1f241, 0x1f242, 0x1f243, 0x1f244, 0x1f245, 0x1f246, 0x1f247,
+ 0x1f248, 0x1f249, 0x1f24a, 0x1f24b, 0x1f24c, 0x1f24d, 0x1f24e, 0x1f24f,
+ 0x1f250, 0x1f251, 0x1f252, 0x1f253, 0x1f254, 0x1f255, 0x1f256, 0x1f257,
+ 0x1f258, 0x1f259, 0x1f25a, 0x1f25b, 0x1f25c, 0x1f25d, 0x1f25e, 0x1f25f,
+ 0x1f260, 0x1f261, 0x1f262, 0x1f263, 0x1f264, 0x1f265, 0x1f266, 0x1f267,
+ 0x1f268, 0x1f269, 0x1f26a, 0x1f26b, 0x1f26c, 0x1f26d, 0x1f26e, 0x1f26f,
+ 0x1f270, 0x1f271, 0x1f272, 0x1f273, 0x1f274, 0x1f275, 0x1f276, 0x1f277,
+ 0x1f278, 0x1f279, 0x1f27a, 0x1f27b, 0x1f27c, 0x1f27d, 0x1f27e, 0x1f27f,
+ 0x1f280, 0x1f281, 0x1f282, 0x1f283, 0x1f284, 0x1f285, 0x1f286, 0x1f287,
+ 0x1f288, 0x1f289, 0x1f28a, 0x1f28b, 0x1f28c, 0x1f28d, 0x1f28e, 0x1f28f,
+ 0x1f290, 0x1f291, 0x1f292, 0x1f293, 0x1f294, 0x1f295, 0x1f296, 0x1f297,
+ 0x1f298, 0x1f299, 0x1f29a, 0x1f29b, 0x1f29c, 0x1f29d, 0x1f29e, 0x1f29f,
+ 0x1f2a0, 0x1f2a1, 0x1f2a2, 0x1f2a3, 0x1f2a4, 0x1f2a5, 0x1f2a6, 0x1f2a7,
+ 0x1f2a8, 0x1f2a9, 0x1f2aa, 0x1f2ab, 0x1f2ac, 0x1f2ad, 0x1f2ae, 0x1f2af,
+ 0x1f2b0, 0x1f2b1, 0x1f2b2, 0x1f2b3, 0x1f2b4, 0x1f2b5, 0x1f2b6, 0x1f2b7,
+ 0x1f2b8, 0x1f2b9, 0x1f2ba, 0x1f2bb, 0x1f2bc, 0x1f2bd, 0x1f2be, 0x1f2bf,
+ 0x1f2c0, 0x1f2c1, 0x1f2c2, 0x1f2c3, 0x1f2c4, 0x1f2c5, 0x1f2c6, 0x1f2c7,
+ 0x1f2c8, 0x1f2c9, 0x1f2ca, 0x1f2cb, 0x1f2cc, 0x1f2cd, 0x1f2ce, 0x1f2cf,
+ 0x1f2d0, 0x1f2d1, 0x1f2d2, 0x1f2d3, 0x1f2d4, 0x1f2d5, 0x1f2d6, 0x1f2d7,
+ 0x1f2d8, 0x1f2d9, 0x1f2da, 0x1f2db, 0x1f2dc, 0x1f2dd, 0x1f2de, 0x1f2df,
+ 0x1f2e0, 0x1f2e1, 0x1f2e2, 0x1f2e3, 0x1f2e4, 0x1f2e5, 0x1f2e6, 0x1f2e7,
+ 0x1f2e8, 0x1f2e9, 0x1f2ea, 0x1f2eb, 0x1f2ec, 0x1f2ed, 0x1f2ee, 0x1f2ef,
+ 0x1f2f0, 0x1f2f1, 0x1f2f2, 0x1f2f3, 0x1f2f4, 0x1f2f5, 0x1f2f6, 0x1f2f7,
+ 0x1f2f8, 0x1f2f9, 0x1f2fa, 0x1f2fb, 0x1f2fc, 0x1f2fd, 0x1f2fe, 0x1f2ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f8[] = {
+ 0x2f800, 0x2f801, 0x2f802, 0x2f803, 0x2f804, 0x0fa30, 0x2f806, 0x2f807,
+ 0x2f808, 0x2f809, 0x0fa31, 0x2f80b, 0x2f80c, 0x2f80d, 0x0fa32, 0x2f80f,
+ 0x2f810, 0x2f811, 0x2f812, 0x2f813, 0x2f814, 0x1f21e, 0x2f816, 0x2f817,
+ 0x2f818, 0x2f819, 0x2f81a, 0x0fa71, 0x2f81c, 0x02f10, 0x2f81e, 0x2f81f,
+ 0x2f820, 0x2f821, 0x2f822, 0x2f823, 0x2f824, 0x0fa76, 0x0fa33, 0x0fa34,
+ 0x0fa77, 0x2f829, 0x2f82a, 0x0f963, 0x2f82c, 0x0fa35, 0x2f82e, 0x2f82f,
+ 0x2f830, 0x2f831, 0x2f831, 0x2f831, 0x2f834, 0x2f835, 0x2f836, 0x2f837,
+ 0x2f838, 0x2f839, 0x2f83a, 0x2f83b, 0x2f83c, 0x2f83d, 0x2f83e, 0x2f83f,
+ 0x2f840, 0x2f841, 0x2f842, 0x2f843, 0x2f844, 0x2f845, 0x2f845, 0x0fa7a,
+ 0x2f848, 0x2f849, 0x2f84a, 0x2f84b, 0x0fa37, 0x2f84d, 0x2f84e, 0x2f84f,
+ 0x0fa00, 0x2f851, 0x2f852, 0x2f853, 0x2f854, 0x2f855, 0x2f856, 0x2f857,
+ 0x2f858, 0x2f859, 0x2f85a, 0x2f85b, 0x2f85c, 0x1f215, 0x2f85e, 0x2f85f,
+ 0x2f860, 0x2f861, 0x2f862, 0x2f863, 0x2f864, 0x2f865, 0x2f866, 0x2f867,
+ 0x2f868, 0x2f869, 0x2f86a, 0x2f86a, 0x2f86c, 0x2f86d, 0x2f86e, 0x0f95f,
+ 0x2f870, 0x2f871, 0x2f872, 0x2f873, 0x2f874, 0x02e8e, 0x2f876, 0x2f877,
+ 0x02f2c, 0x2f879, 0x2f87a, 0x2f87b, 0x2f87c, 0x2f87d, 0x2f87e, 0x2f87f,
+ 0x2f880, 0x2f881, 0x2f882, 0x2f883, 0x2f884, 0x2f885, 0x2f886, 0x2f887,
+ 0x2f888, 0x2f889, 0x2f88a, 0x2f88b, 0x2f88c, 0x2f88d, 0x0f928, 0x2f88f,
+ 0x02f36, 0x2f891, 0x2f891, 0x2f893, 0x2f894, 0x2f894, 0x2f896, 0x2f897,
+ 0x2f898, 0x2f899, 0x2f89a, 0x2f89b, 0x2f89c, 0x2f89d, 0x2f89e, 0x2f89f,
+ 0x2f8a0, 0x2f8a1, 0x2f8a2, 0x0fa3d, 0x2f8a4, 0x2f8a5, 0x2f8a6, 0x2f8a7,
+ 0x0fa87, 0x2f8a7, 0x2f8aa, 0x0fa3f, 0x2f8ac, 0x2f8ad, 0x2f8ae, 0x2f8af,
+ 0x0fa40, 0x0f90d, 0x2f8b2, 0x2f8b3, 0x2f8b4, 0x2f8b5, 0x2f8b6, 0x2f8b7,
+ 0x2f8b8, 0x2f8b9, 0x2f8ba, 0x2f8bb, 0x2f8bc, 0x2f8bd, 0x2f8be, 0x2f8bf,
+ 0x2f8c0, 0x2f8c1, 0x2f8c2, 0x2f8c3, 0x2f8c4, 0x2f8c5, 0x2f8c6, 0x2f8c7,
+ 0x0fa41, 0x2f8c9, 0x2f8ca, 0x2f8cb, 0x2f8cc, 0x2f8cd, 0x2f8ce, 0x0fa43,
+ 0x2f8d0, 0x2f8d1, 0x2f8d2, 0x2f8d3, 0x2f8d4, 0x2f8d5, 0x2f8d6, 0x2f8d7,
+ 0x0f929, 0x0fa93, 0x2f8da, 0x2f8db, 0x2f8dc, 0x2f8dd, 0x2f8de, 0x2f8df,
+ 0x2f8e0, 0x2f8e1, 0x0fa44, 0x2f8e3, 0x2f8e4, 0x2f8e5, 0x2f8e6, 0x0fad2,
+ 0x2f8e8, 0x2f8e9, 0x2f8ea, 0x2f8eb, 0x2f8ec, 0x2f8ed, 0x2f8ee, 0x2f8ef,
+ 0x2f8f0, 0x2f8f1, 0x2f8f2, 0x2f8f3, 0x2f8f4, 0x0f970, 0x2f8f6, 0x2f8f7,
+ 0x2f8f8, 0x2f8f9, 0x2f8fa, 0x2f8fb, 0x2f8fc, 0x2f8fd, 0x2f8fe, 0x2f8ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f9[] = {
+ 0x2f900, 0x0fa45, 0x0f9ca, 0x2f903, 0x2f904, 0x2f905, 0x2f906, 0x2f907,
+ 0x2f908, 0x2f909, 0x2f90a, 0x0fa99, 0x2f90c, 0x2f90d, 0x2f90e, 0x2f90f,
+ 0x2f910, 0x2f911, 0x2f912, 0x2f913, 0x0fa9b, 0x2f915, 0x2f916, 0x2f917,
+ 0x2f918, 0x2f919, 0x2f91a, 0x2f91b, 0x2f91c, 0x2f91d, 0x2f91e, 0x2f91f,
+ 0x2f920, 0x0fa9e, 0x2f922, 0x2f923, 0x2f924, 0x2f925, 0x2f926, 0x2f927,
+ 0x2f928, 0x02ea9, 0x2f92a, 0x2f92b, 0x2f92c, 0x2f92c, 0x2f92e, 0x2f92f,
+ 0x0faa1, 0x2f931, 0x2f932, 0x2f933, 0x2f934, 0x2f935, 0x2f936, 0x2f937,
+ 0x0f962, 0x2f939, 0x2f93a, 0x2f93b, 0x2f93c, 0x2f93d, 0x2f93e, 0x2f93f,
+ 0x0faa8, 0x2f941, 0x2f942, 0x2f943, 0x2f944, 0x2f945, 0x2f946, 0x2f946,
+ 0x0faa9, 0x0fad4, 0x2f94a, 0x2f94b, 0x2f94c, 0x2f94d, 0x2f94e, 0x0f93b,
+ 0x0faab, 0x2f951, 0x2f952, 0x0fa50, 0x2f954, 0x2f955, 0x0fa1b, 0x2f957,
+ 0x2f958, 0x0fa54, 0x2f95a, 0x2f95b, 0x2f95c, 0x2f95d, 0x2f95d, 0x2f95f,
+ 0x2f960, 0x2f961, 0x2f962, 0x2f963, 0x2f964, 0x2f965, 0x2f966, 0x2f967,
+ 0x2f968, 0x2f969, 0x2f96a, 0x2f96b, 0x2f96c, 0x2f96d, 0x2f96e, 0x2f96f,
+ 0x2f970, 0x2f971, 0x2f972, 0x2f973, 0x2f974, 0x2f975, 0x2f976, 0x2f977,
+ 0x2f978, 0x2f979, 0x0fa5b, 0x2f97b, 0x2f97c, 0x2f97d, 0x2f97e, 0x2f97f,
+ 0x2f980, 0x2f981, 0x2f982, 0x2f983, 0x2f984, 0x2f985, 0x2f986, 0x2f987,
+ 0x2f988, 0x2f989, 0x2f98a, 0x2f893, 0x2f98c, 0x2f98d, 0x2f98e, 0x2f98f,
+ 0x2f990, 0x2f991, 0x2f992, 0x2f993, 0x2f994, 0x2f995, 0x2f996, 0x2f997,
+ 0x0f974, 0x2f999, 0x2f99a, 0x2f99b, 0x2f99c, 0x2f99d, 0x2f99e, 0x0fa5f,
+ 0x2f9a0, 0x2f9a1, 0x2f9a2, 0x2f9a3, 0x2f9a4, 0x2f9a5, 0x2f9a6, 0x2f9a7,
+ 0x2f9a8, 0x2f9a9, 0x2f9aa, 0x2f9ab, 0x2f9ac, 0x2f9ad, 0x2f9ae, 0x2f9af,
+ 0x2f9b0, 0x2f9b1, 0x2f9b2, 0x2f9b3, 0x0f936, 0x2f9b5, 0x2f9b6, 0x2f9b7,
+ 0x2f9b8, 0x2f9b9, 0x2f9ba, 0x0fab5, 0x2f9bc, 0x2f9bd, 0x2f9be, 0x2f9bf,
+ 0x2f9c0, 0x2f9c1, 0x2f9c2, 0x2f9c3, 0x02f90, 0x2f9c5, 0x2f9c6, 0x2f9c7,
+ 0x2f9c8, 0x2f9c9, 0x2f9ca, 0x2f9cb, 0x2f9cc, 0x2f9cd, 0x2f9ce, 0x2f9cf,
+ 0x0fabe, 0x0fac0, 0x02f97, 0x2f9d3, 0x2f9d4, 0x2f9d5, 0x2f9d6, 0x2f9d7,
+ 0x2f9d8, 0x2f9d9, 0x2f9da, 0x2f9db, 0x2f9dc, 0x2f9dd, 0x2f9de, 0x0fac2,
+ 0x2f9e0, 0x2f9e1, 0x2f9e2, 0x2f9e3, 0x2f9e4, 0x2f9e5, 0x2f9e6, 0x2f9e7,
+ 0x2f9e8, 0x2f9e9, 0x2f9ea, 0x2f9eb, 0x2f9ec, 0x2f9ed, 0x2f9ee, 0x2f9ef,
+ 0x2f9f0, 0x2f9f1, 0x2f9f2, 0x2f9f3, 0x2f9f4, 0x2f9f5, 0x2f9f6, 0x2f9f7,
+ 0x2f9f8, 0x2f9f9, 0x2f9fa, 0x2f9fb, 0x2f9fc, 0x2f9fd, 0x0facb, 0x2f9ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2fa[] = {
+ 0x2fa00, 0x2fa01, 0x2fa02, 0x2fa03, 0x2fa04, 0x2fa05, 0x2fa06, 0x2fa07,
+ 0x2fa08, 0x2fa09, 0x0facd, 0x2fa0b, 0x2fa0c, 0x2fa0d, 0x2fa0e, 0x2fa0f,
+ 0x2fa10, 0x2fa11, 0x2fa12, 0x2fa13, 0x2fa14, 0x02fc7, 0x04d56, 0x02fcb,
+ 0x02eea, 0x2fa19, 0x2fa1a, 0x2fa1b, 0x02fd0, 0x2fa1d, 0x2fa1e, 0x2fa1f,
+ 0x2fa20, 0x2fa21, 0x2fa22, 0x2fa23, 0x2fa24, 0x2fa25, 0x2fa26, 0x2fa27,
+ 0x2fa28, 0x2fa29, 0x2fa2a, 0x2fa2b, 0x2fa2c, 0x2fa2d, 0x2fa2e, 0x2fa2f,
+ 0x2fa30, 0x2fa31, 0x2fa32, 0x2fa33, 0x2fa34, 0x2fa35, 0x2fa36, 0x2fa37,
+ 0x2fa38, 0x2fa39, 0x2fa3a, 0x2fa3b, 0x2fa3c, 0x2fa3d, 0x2fa3e, 0x2fa3f,
+ 0x2fa40, 0x2fa41, 0x2fa42, 0x2fa43, 0x2fa44, 0x2fa45, 0x2fa46, 0x2fa47,
+ 0x2fa48, 0x2fa49, 0x2fa4a, 0x2fa4b, 0x2fa4c, 0x2fa4d, 0x2fa4e, 0x2fa4f,
+ 0x2fa50, 0x2fa51, 0x2fa52, 0x2fa53, 0x2fa54, 0x2fa55, 0x2fa56, 0x2fa57,
+ 0x2fa58, 0x2fa59, 0x2fa5a, 0x2fa5b, 0x2fa5c, 0x2fa5d, 0x2fa5e, 0x2fa5f,
+ 0x2fa60, 0x2fa61, 0x2fa62, 0x2fa63, 0x2fa64, 0x2fa65, 0x2fa66, 0x2fa67,
+ 0x2fa68, 0x2fa69, 0x2fa6a, 0x2fa6b, 0x2fa6c, 0x2fa6d, 0x2fa6e, 0x2fa6f,
+ 0x2fa70, 0x2fa71, 0x2fa72, 0x2fa73, 0x2fa74, 0x2fa75, 0x2fa76, 0x2fa77,
+ 0x2fa78, 0x2fa79, 0x2fa7a, 0x2fa7b, 0x2fa7c, 0x2fa7d, 0x2fa7e, 0x2fa7f,
+ 0x2fa80, 0x2fa81, 0x2fa82, 0x2fa83, 0x2fa84, 0x2fa85, 0x2fa86, 0x2fa87,
+ 0x2fa88, 0x2fa89, 0x2fa8a, 0x2fa8b, 0x2fa8c, 0x2fa8d, 0x2fa8e, 0x2fa8f,
+ 0x2fa90, 0x2fa91, 0x2fa92, 0x2fa93, 0x2fa94, 0x2fa95, 0x2fa96, 0x2fa97,
+ 0x2fa98, 0x2fa99, 0x2fa9a, 0x2fa9b, 0x2fa9c, 0x2fa9d, 0x2fa9e, 0x2fa9f,
+ 0x2faa0, 0x2faa1, 0x2faa2, 0x2faa3, 0x2faa4, 0x2faa5, 0x2faa6, 0x2faa7,
+ 0x2faa8, 0x2faa9, 0x2faaa, 0x2faab, 0x2faac, 0x2faad, 0x2faae, 0x2faaf,
+ 0x2fab0, 0x2fab1, 0x2fab2, 0x2fab3, 0x2fab4, 0x2fab5, 0x2fab6, 0x2fab7,
+ 0x2fab8, 0x2fab9, 0x2faba, 0x2fabb, 0x2fabc, 0x2fabd, 0x2fabe, 0x2fabf,
+ 0x2fac0, 0x2fac1, 0x2fac2, 0x2fac3, 0x2fac4, 0x2fac5, 0x2fac6, 0x2fac7,
+ 0x2fac8, 0x2fac9, 0x2faca, 0x2facb, 0x2facc, 0x2facd, 0x2face, 0x2facf,
+ 0x2fad0, 0x2fad1, 0x2fad2, 0x2fad3, 0x2fad4, 0x2fad5, 0x2fad6, 0x2fad7,
+ 0x2fad8, 0x2fad9, 0x2fada, 0x2fadb, 0x2fadc, 0x2fadd, 0x2fade, 0x2fadf,
+ 0x2fae0, 0x2fae1, 0x2fae2, 0x2fae3, 0x2fae4, 0x2fae5, 0x2fae6, 0x2fae7,
+ 0x2fae8, 0x2fae9, 0x2faea, 0x2faeb, 0x2faec, 0x2faed, 0x2faee, 0x2faef,
+ 0x2faf0, 0x2faf1, 0x2faf2, 0x2faf3, 0x2faf4, 0x2faf5, 0x2faf6, 0x2faf7,
+ 0x2faf8, 0x2faf9, 0x2fafa, 0x2fafb, 0x2fafc, 0x2fafd, 0x2fafe, 0x2faff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_e00[] = {
+ 0xe0000, 0x00000, 0xe0002, 0xe0003, 0xe0004, 0xe0005, 0xe0006, 0xe0007,
+ 0xe0008, 0xe0009, 0xe000a, 0xe000b, 0xe000c, 0xe000d, 0xe000e, 0xe000f,
+ 0xe0010, 0xe0011, 0xe0012, 0xe0013, 0xe0014, 0xe0015, 0xe0016, 0xe0017,
+ 0xe0018, 0xe0019, 0xe001a, 0xe001b, 0xe001c, 0xe001d, 0xe001e, 0xe001f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0xe0080, 0xe0081, 0xe0082, 0xe0083, 0xe0084, 0xe0085, 0xe0086, 0xe0087,
+ 0xe0088, 0xe0089, 0xe008a, 0xe008b, 0xe008c, 0xe008d, 0xe008e, 0xe008f,
+ 0xe0090, 0xe0091, 0xe0092, 0xe0093, 0xe0094, 0xe0095, 0xe0096, 0xe0097,
+ 0xe0098, 0xe0099, 0xe009a, 0xe009b, 0xe009c, 0xe009d, 0xe009e, 0xe009f,
+ 0xe00a0, 0xe00a1, 0xe00a2, 0xe00a3, 0xe00a4, 0xe00a5, 0xe00a6, 0xe00a7,
+ 0xe00a8, 0xe00a9, 0xe00aa, 0xe00ab, 0xe00ac, 0xe00ad, 0xe00ae, 0xe00af,
+ 0xe00b0, 0xe00b1, 0xe00b2, 0xe00b3, 0xe00b4, 0xe00b5, 0xe00b6, 0xe00b7,
+ 0xe00b8, 0xe00b9, 0xe00ba, 0xe00bb, 0xe00bc, 0xe00bd, 0xe00be, 0xe00bf,
+ 0xe00c0, 0xe00c1, 0xe00c2, 0xe00c3, 0xe00c4, 0xe00c5, 0xe00c6, 0xe00c7,
+ 0xe00c8, 0xe00c9, 0xe00ca, 0xe00cb, 0xe00cc, 0xe00cd, 0xe00ce, 0xe00cf,
+ 0xe00d0, 0xe00d1, 0xe00d2, 0xe00d3, 0xe00d4, 0xe00d5, 0xe00d6, 0xe00d7,
+ 0xe00d8, 0xe00d9, 0xe00da, 0xe00db, 0xe00dc, 0xe00dd, 0xe00de, 0xe00df,
+ 0xe00e0, 0xe00e1, 0xe00e2, 0xe00e3, 0xe00e4, 0xe00e5, 0xe00e6, 0xe00e7,
+ 0xe00e8, 0xe00e9, 0xe00ea, 0xe00eb, 0xe00ec, 0xe00ed, 0xe00ee, 0xe00ef,
+ 0xe00f0, 0xe00f1, 0xe00f2, 0xe00f3, 0xe00f4, 0xe00f5, 0xe00f6, 0xe00f7,
+ 0xe00f8, 0xe00f9, 0xe00fa, 0xe00fb, 0xe00fc, 0xe00fd, 0xe00fe, 0xe00ff
+};
+
+static uint32_t unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_e01[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0xe01f0, 0xe01f1, 0xe01f2, 0xe01f3, 0xe01f4, 0xe01f5, 0xe01f6, 0xe01f7,
+ 0xe01f8, 0xe01f9, 0xe01fa, 0xe01fb, 0xe01fc, 0xe01fd, 0xe01fe, 0xe01ff
+};
+
+static uint32_t *unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_table[4352] = {
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_00, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_01,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_02, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_03,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_04, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_05,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_06, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_07,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_08, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_09,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0a, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0b,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0c, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0d,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0e, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0f,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10, NULL,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_13,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_16, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_17,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_18, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_19,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1a, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1b,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1c, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1e, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_20, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_21,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_22, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_24, NULL,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_27,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2a, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2c, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2d,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2e, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_30, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_31,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_32, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_33,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a6, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a7,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a8, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_a9,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_aa, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_ab,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_f9,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fa, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fb,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fc, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fd,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fe, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_ff,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_101,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_103,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_104, NULL,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_108, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_109,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10a, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10b,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10c, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10e, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_110, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_124, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d1,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d2, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d3,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d4, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d5,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d6, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d7,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f1,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f2, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f8, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f9,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2fa, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_e00, unicode_520_ci_except_kana_ci_kana_with_voiced_sound_mark_page_e01,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL
+};
+
+#endif
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_table.h b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_table.h
new file mode 100644
index 00000000..6e24719b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_520_ci_table.h
@@ -0,0 +1,5028 @@
+/*
+ Copyright(C) 2013-2015 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ mysql-5.6.23/strings/ctype-uca.c.
+ The following is the header of the file:
+
+ Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UCA (Unicode Collation Algorithm) support.
+ Written by Alexander Barkov <bar@mysql.com>
+*/
+
+#ifndef MYSQL_UCA_520_H
+#define MYSQL_UCA_520_H
+
+#include <stdint.h>
+
+static uint32_t unicode_520_ci_page_00[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00009, 0x0000a, 0x0000b, 0x0000c, 0x0000d, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00085, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x000a1, 0x000a2, 0x000a3, 0x000a4, 0x000a5, 0x000a6, 0x000a7,
+ 0x000a8, 0x000a9, 0x00041, 0x000ab, 0x000ac, 0x000ad, 0x000ae, 0x000af,
+ 0x000b0, 0x000b1, 0x00032, 0x00033, 0x000b4, 0x0039c, 0x000b6, 0x000b7,
+ 0x000b8, 0x00031, 0x0004f, 0x000bb, 0x000bc, 0x000bd, 0x000be, 0x000bf,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00044, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000d7,
+ 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x000df,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00044, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000f7,
+ 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000fe, 0x000ff
+};
+
+static uint32_t unicode_520_ci_page_01[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00043, 0x00043,
+ 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00047, 0x00047, 0x00047, 0x00047,
+ 0x00047, 0x00047, 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00049, 0x00131, 0x00132, 0x00132, 0x0004a, 0x0004a, 0x0004b, 0x0004b,
+ 0x00138, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x00149, 0x0014a, 0x0014a, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00152, 0x00152, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00052, 0x00052, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00166, 0x00166,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00057, 0x00057, 0x00059, 0x00059,
+ 0x00059, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00053,
+ 0x00180, 0x00181, 0x00182, 0x00182, 0x00184, 0x00184, 0x00186, 0x00187,
+ 0x00187, 0x00189, 0x0018a, 0x0018b, 0x0018b, 0x0018d, 0x0018e, 0x0018f,
+ 0x00190, 0x00191, 0x00191, 0x00193, 0x00194, 0x00195, 0x00196, 0x00197,
+ 0x00198, 0x00198, 0x0019a, 0x0019b, 0x0019c, 0x0019d, 0x0019e, 0x0019f,
+ 0x0004f, 0x0004f, 0x001a2, 0x001a2, 0x001a4, 0x001a4, 0x001a6, 0x001a7,
+ 0x001a7, 0x001a9, 0x001aa, 0x001ab, 0x001ac, 0x001ac, 0x001ae, 0x00055,
+ 0x00055, 0x001b1, 0x001b2, 0x001b3, 0x001b3, 0x001b5, 0x001b5, 0x001b7,
+ 0x001b8, 0x001b8, 0x001ba, 0x001bb, 0x001bc, 0x001bc, 0x001be, 0x001bf,
+ 0x001c0, 0x001c1, 0x001c2, 0x001c3, 0x001c4, 0x001c4, 0x001c4, 0x001c7,
+ 0x001c7, 0x001c7, 0x001ca, 0x001ca, 0x001ca, 0x00041, 0x00041, 0x00049,
+ 0x00049, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x0018e, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x000c6, 0x000c6, 0x001e4, 0x001e4, 0x00047, 0x00047,
+ 0x0004b, 0x0004b, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x001b7, 0x001b7,
+ 0x0004a, 0x001c4, 0x001c4, 0x001c4, 0x00047, 0x00047, 0x00195, 0x001bf,
+ 0x0004e, 0x0004e, 0x00041, 0x00041, 0x000c6, 0x000c6, 0x0004f, 0x001ff
+};
+
+static uint32_t unicode_520_ci_page_02[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x0021c, 0x0021c, 0x00048, 0x00048,
+ 0x0019e, 0x00221, 0x00222, 0x00222, 0x00224, 0x00224, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00059, 0x00059, 0x00234, 0x00235, 0x00236, 0x00237,
+ 0x00238, 0x00239, 0x0023a, 0x0023b, 0x0023b, 0x0019a, 0x0023e, 0x0023f,
+ 0x00240, 0x00241, 0x00241, 0x00180, 0x00244, 0x00245, 0x00246, 0x00246,
+ 0x00248, 0x00248, 0x0024a, 0x0024a, 0x0024c, 0x0024c, 0x0024e, 0x0024e,
+ 0x00250, 0x00251, 0x00252, 0x00181, 0x00186, 0x00255, 0x00189, 0x0018a,
+ 0x00258, 0x0018f, 0x0025a, 0x00190, 0x0025c, 0x0025d, 0x0025e, 0x0025f,
+ 0x00193, 0x00261, 0x00262, 0x00194, 0x00264, 0x00265, 0x00266, 0x00267,
+ 0x00197, 0x00196, 0x0026a, 0x0026b, 0x0026c, 0x0026d, 0x0026e, 0x0019c,
+ 0x00270, 0x00271, 0x0019d, 0x00273, 0x00274, 0x0019f, 0x00276, 0x00277,
+ 0x00278, 0x00279, 0x0027a, 0x0027b, 0x0027c, 0x0027d, 0x0027e, 0x0027f,
+ 0x001a6, 0x00281, 0x00282, 0x001a9, 0x00284, 0x00285, 0x00286, 0x00287,
+ 0x001ae, 0x00244, 0x001b1, 0x001b2, 0x00245, 0x0028d, 0x0028e, 0x0028f,
+ 0x00290, 0x00291, 0x001b7, 0x00293, 0x00294, 0x00295, 0x00296, 0x00297,
+ 0x00298, 0x00299, 0x0029a, 0x0029b, 0x0029c, 0x0029d, 0x0029e, 0x0029f,
+ 0x002a0, 0x002a1, 0x002a2, 0x001c4, 0x002a4, 0x002a5, 0x001be, 0x002a7,
+ 0x002a8, 0x002a9, 0x002aa, 0x002ab, 0x002ac, 0x002ad, 0x002ae, 0x002af,
+ 0x00048, 0x00266, 0x0004a, 0x00052, 0x00279, 0x0027b, 0x00281, 0x00057,
+ 0x00059, 0x002b9, 0x002ba, 0x002bb, 0x002bc, 0x002bd, 0x002be, 0x002bf,
+ 0x002c0, 0x002c1, 0x002c2, 0x002c3, 0x002c4, 0x002c5, 0x002c6, 0x002c7,
+ 0x002c8, 0x002c9, 0x002ca, 0x002cb, 0x002cc, 0x002cd, 0x002ce, 0x002cf,
+ 0x002d0, 0x002d1, 0x002d2, 0x002d3, 0x002d4, 0x002d5, 0x002d6, 0x002d7,
+ 0x002d8, 0x002d9, 0x002da, 0x002db, 0x002dc, 0x002dd, 0x002de, 0x002df,
+ 0x00194, 0x0004c, 0x00053, 0x00058, 0x00295, 0x002e5, 0x002e6, 0x002e7,
+ 0x002e8, 0x002e9, 0x002ea, 0x002eb, 0x002ec, 0x002ed, 0x002ee, 0x002ef,
+ 0x002f0, 0x002f1, 0x002f2, 0x002f3, 0x002f4, 0x002f5, 0x002f6, 0x002f7,
+ 0x002f8, 0x002f9, 0x002fa, 0x002fb, 0x002fc, 0x002fd, 0x002fe, 0x002ff
+};
+
+static uint32_t unicode_520_ci_page_03[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00041, 0x00045, 0x00049, 0x0004f, 0x00055,
+ 0x00043, 0x00044, 0x00048, 0x0004d, 0x00052, 0x00054, 0x00056, 0x00058,
+ 0x00370, 0x00370, 0x00372, 0x00372, 0x002b9, 0x00375, 0x00376, 0x00376,
+ 0x00378, 0x00379, 0x00399, 0x0037b, 0x0037c, 0x0037d, 0x0003b, 0x0037f,
+ 0x00380, 0x00381, 0x00382, 0x00383, 0x000b4, 0x000a8, 0x00391, 0x000b7,
+ 0x00395, 0x00397, 0x00399, 0x0038b, 0x0039f, 0x0038d, 0x003a5, 0x003a9,
+ 0x00399, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a2, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x00391, 0x00395, 0x00397, 0x00399,
+ 0x003a5, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x0039f, 0x003a5, 0x003a9, 0x003cf,
+ 0x00392, 0x00398, 0x003a5, 0x003a5, 0x003a5, 0x003a6, 0x003a0, 0x003cf,
+ 0x003d8, 0x003d8, 0x003da, 0x003da, 0x003dc, 0x003dc, 0x003de, 0x003de,
+ 0x003e0, 0x003e0, 0x003e2, 0x003e2, 0x003e4, 0x003e4, 0x003e6, 0x003e6,
+ 0x003e8, 0x003e8, 0x003ea, 0x003ea, 0x003ec, 0x003ec, 0x003ee, 0x003ee,
+ 0x0039a, 0x003a1, 0x003a3, 0x003f3, 0x00398, 0x00395, 0x003f6, 0x003f7,
+ 0x003f7, 0x003a3, 0x003fa, 0x003fa, 0x003fc, 0x0037b, 0x003fe, 0x003ff
+};
+
+static uint32_t unicode_520_ci_page_04[] = {
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00460, 0x00460, 0x00462, 0x00462, 0x00464, 0x00464, 0x00466, 0x00466,
+ 0x00468, 0x00468, 0x0046a, 0x0046a, 0x0046c, 0x0046c, 0x0046e, 0x0046e,
+ 0x00470, 0x00470, 0x00472, 0x00472, 0x00474, 0x00474, 0x00476, 0x00476,
+ 0x00478, 0x00478, 0x0047a, 0x0047a, 0x0047c, 0x0047c, 0x0047e, 0x0047e,
+ 0x00480, 0x00480, 0x00482, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x0048a, 0x0048a, 0x0048c, 0x0048c, 0x0048e, 0x0048e,
+ 0x00413, 0x00413, 0x00492, 0x00492, 0x00494, 0x00494, 0x00496, 0x00496,
+ 0x00498, 0x00498, 0x0049a, 0x0049a, 0x0049c, 0x0049c, 0x0049e, 0x0049e,
+ 0x004a0, 0x004a0, 0x004a2, 0x004a2, 0x004a4, 0x004a4, 0x004a6, 0x004a6,
+ 0x004a8, 0x004a8, 0x004aa, 0x004aa, 0x004ac, 0x004ac, 0x004ae, 0x004ae,
+ 0x004b0, 0x004b0, 0x004b2, 0x004b2, 0x004b4, 0x004b4, 0x004b6, 0x004b6,
+ 0x004b8, 0x004b8, 0x004ba, 0x004ba, 0x004bc, 0x004bc, 0x004be, 0x004be,
+ 0x004c0, 0x00416, 0x00416, 0x004c3, 0x004c3, 0x004c5, 0x004c5, 0x004c7,
+ 0x004c7, 0x004c9, 0x004c9, 0x004cb, 0x004cb, 0x004cd, 0x004cd, 0x004c0,
+ 0x004d0, 0x004d0, 0x004d2, 0x004d2, 0x004d4, 0x004d4, 0x004d6, 0x004d6,
+ 0x004d8, 0x004d8, 0x004da, 0x004da, 0x004dc, 0x004dc, 0x004de, 0x004de,
+ 0x004e0, 0x004e0, 0x0040d, 0x0040d, 0x004e4, 0x004e4, 0x004e6, 0x004e6,
+ 0x004e8, 0x004e8, 0x004ea, 0x004ea, 0x004ec, 0x004ec, 0x00423, 0x00423,
+ 0x004f0, 0x004f0, 0x004f2, 0x004f2, 0x004f4, 0x004f4, 0x004f6, 0x004f6,
+ 0x004f8, 0x004f8, 0x004fa, 0x004fa, 0x004fc, 0x004fd, 0x004fe, 0x004ff
+};
+
+static uint32_t unicode_520_ci_page_05[] = {
+ 0x00500, 0x00500, 0x00502, 0x00502, 0x00504, 0x00504, 0x00506, 0x00506,
+ 0x00508, 0x00508, 0x0050a, 0x0050a, 0x0050c, 0x0050c, 0x0050e, 0x0050e,
+ 0x00510, 0x00510, 0x00512, 0x00512, 0x00514, 0x00514, 0x00516, 0x00516,
+ 0x00518, 0x00518, 0x0051a, 0x0051a, 0x0051c, 0x0051c, 0x0051e, 0x0051e,
+ 0x00520, 0x00520, 0x00522, 0x00522, 0x00524, 0x00524, 0x00526, 0x00527,
+ 0x00528, 0x00529, 0x0052a, 0x0052b, 0x0052c, 0x0052d, 0x0052e, 0x0052f,
+ 0x00530, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00557,
+ 0x00558, 0x00559, 0x0055a, 0x0055b, 0x0055c, 0x0055d, 0x0055e, 0x0055f,
+ 0x00560, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00587,
+ 0x00588, 0x00589, 0x0058a, 0x0058b, 0x0058c, 0x0058d, 0x0058e, 0x0058f,
+ 0x00590, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x005be, 0x00000,
+ 0x005c0, 0x00000, 0x00000, 0x005c3, 0x00000, 0x00000, 0x005c6, 0x00000,
+ 0x005c8, 0x005c9, 0x005ca, 0x005cb, 0x005cc, 0x005cd, 0x005ce, 0x005cf,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x005d7,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x005dd, 0x005dd, 0x005df,
+ 0x005df, 0x005e1, 0x005e2, 0x005e3, 0x005e3, 0x005e5, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005eb, 0x005ec, 0x005ed, 0x005ee, 0x005ef,
+ 0x005f0, 0x005f1, 0x005f2, 0x005f3, 0x005f4, 0x005f5, 0x005f6, 0x005f7,
+ 0x005f8, 0x005f9, 0x005fa, 0x005fb, 0x005fc, 0x005fd, 0x005fe, 0x005ff
+};
+
+static uint32_t unicode_520_ci_page_06[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00604, 0x00605, 0x00606, 0x00607,
+ 0x00608, 0x00609, 0x0060a, 0x0060b, 0x0060c, 0x0060d, 0x0060e, 0x0060f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0061b, 0x0061c, 0x0061d, 0x0061e, 0x0061f,
+ 0x00620, 0x00621, 0x00622, 0x00623, 0x00624, 0x00625, 0x00626, 0x00627,
+ 0x00628, 0x00629, 0x0062a, 0x0062b, 0x0062c, 0x0062d, 0x0062e, 0x0062f,
+ 0x00630, 0x00631, 0x00632, 0x00633, 0x00634, 0x00635, 0x00636, 0x00637,
+ 0x00638, 0x00639, 0x0063a, 0x0063b, 0x0063c, 0x0063d, 0x0063e, 0x0063f,
+ 0x00640, 0x00641, 0x00642, 0x00643, 0x00644, 0x00645, 0x00646, 0x00647,
+ 0x00648, 0x00649, 0x0064a, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0065f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0066a, 0x0066b, 0x0066c, 0x0066d, 0x0066e, 0x0066f,
+ 0x00000, 0x00671, 0x00672, 0x00673, 0x00621, 0x00675, 0x00676, 0x00677,
+ 0x00678, 0x00679, 0x0067a, 0x0067b, 0x0067c, 0x0067d, 0x0067e, 0x0067f,
+ 0x00680, 0x00681, 0x00682, 0x00683, 0x00684, 0x00685, 0x00686, 0x00687,
+ 0x00688, 0x00689, 0x0068a, 0x0068b, 0x0068c, 0x0068d, 0x0068e, 0x0068f,
+ 0x00690, 0x00691, 0x00692, 0x00693, 0x00694, 0x00695, 0x00696, 0x00697,
+ 0x00698, 0x00699, 0x0069a, 0x0069b, 0x0069c, 0x0069d, 0x0069e, 0x0069f,
+ 0x006a0, 0x006a1, 0x006a2, 0x006a3, 0x006a4, 0x006a5, 0x006a6, 0x006a7,
+ 0x006a8, 0x006a9, 0x006aa, 0x006ab, 0x006ac, 0x006ad, 0x006ae, 0x006af,
+ 0x006b0, 0x006b1, 0x006b2, 0x006b3, 0x006b4, 0x006b5, 0x006b6, 0x006b7,
+ 0x006b8, 0x006b9, 0x006ba, 0x006bb, 0x006bc, 0x006bd, 0x006be, 0x006bf,
+ 0x006c0, 0x006c1, 0x006c1, 0x006c3, 0x006c4, 0x006c5, 0x006c6, 0x006c7,
+ 0x006c8, 0x006c9, 0x006ca, 0x006cb, 0x006cc, 0x006cd, 0x006ce, 0x006cf,
+ 0x006d0, 0x006d1, 0x006d2, 0x006d2, 0x006d4, 0x006c0, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00648, 0x0064a, 0x00000,
+ 0x00000, 0x006e9, 0x00000, 0x00000, 0x00000, 0x00000, 0x006ee, 0x006ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x006fa, 0x006fb, 0x006fc, 0x00621, 0x00645, 0x006ff
+};
+
+static uint32_t unicode_520_ci_page_07[] = {
+ 0x00700, 0x00701, 0x00702, 0x00703, 0x00704, 0x00705, 0x00706, 0x00707,
+ 0x00708, 0x00709, 0x0070a, 0x0070b, 0x0070c, 0x0070d, 0x0070e, 0x00000,
+ 0x00710, 0x00000, 0x00712, 0x00713, 0x00713, 0x00715, 0x00716, 0x00717,
+ 0x00718, 0x00719, 0x0071a, 0x0071b, 0x0071b, 0x0071d, 0x0071e, 0x0071f,
+ 0x00720, 0x00721, 0x00722, 0x00723, 0x00723, 0x00725, 0x00726, 0x00726,
+ 0x00728, 0x00729, 0x0072a, 0x0072b, 0x0072c, 0x00712, 0x00713, 0x00715,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0074b, 0x0074c, 0x0074d, 0x0074e, 0x0074f,
+ 0x00750, 0x00751, 0x00752, 0x00753, 0x00754, 0x00755, 0x00756, 0x00757,
+ 0x00758, 0x00759, 0x0075a, 0x0075b, 0x0075c, 0x0075d, 0x0075e, 0x0075f,
+ 0x00760, 0x00761, 0x00762, 0x00763, 0x00764, 0x00765, 0x00766, 0x00767,
+ 0x00768, 0x00769, 0x0076a, 0x0076b, 0x0076c, 0x0076d, 0x0076e, 0x0076f,
+ 0x00770, 0x00771, 0x00772, 0x00773, 0x00774, 0x00775, 0x00776, 0x00777,
+ 0x00778, 0x00779, 0x0077a, 0x0077b, 0x0077c, 0x0077d, 0x0077e, 0x0077f,
+ 0x00780, 0x00781, 0x00782, 0x00783, 0x00784, 0x00785, 0x00786, 0x00787,
+ 0x00788, 0x00789, 0x0078a, 0x0078b, 0x0078c, 0x0078d, 0x0078e, 0x0078f,
+ 0x00790, 0x00791, 0x00792, 0x00793, 0x00794, 0x00795, 0x00796, 0x00797,
+ 0x00798, 0x00799, 0x0079a, 0x0079b, 0x0079c, 0x0079d, 0x0079e, 0x0079f,
+ 0x007a0, 0x007a1, 0x007a2, 0x007a3, 0x007a4, 0x007a5, 0x007a6, 0x007a7,
+ 0x007a8, 0x007a9, 0x007aa, 0x007ab, 0x007ac, 0x007ad, 0x007ae, 0x007af,
+ 0x007b0, 0x007b1, 0x007b2, 0x007b3, 0x007b4, 0x007b5, 0x007b6, 0x007b7,
+ 0x007b8, 0x007b9, 0x007ba, 0x007bb, 0x007bc, 0x007bd, 0x007be, 0x007bf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x007ca, 0x007cb, 0x007cc, 0x007cd, 0x007ce, 0x007cf,
+ 0x007d0, 0x007d1, 0x007d2, 0x007d3, 0x007d4, 0x007d5, 0x007d6, 0x007d7,
+ 0x007d8, 0x007d9, 0x007da, 0x007db, 0x007dc, 0x007dd, 0x007de, 0x007df,
+ 0x007e0, 0x007e1, 0x007e2, 0x007e3, 0x007e4, 0x007e5, 0x007e6, 0x007e7,
+ 0x007d6, 0x007d7, 0x007d9, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x007f4, 0x007f5, 0x007f6, 0x007f7,
+ 0x007f8, 0x007f9, 0x007fa, 0x007fb, 0x007fc, 0x007fd, 0x007fe, 0x007ff
+};
+
+static uint32_t unicode_520_ci_page_08[] = {
+ 0x00800, 0x00801, 0x00802, 0x00803, 0x00804, 0x00805, 0x00806, 0x00807,
+ 0x00808, 0x00809, 0x0080a, 0x0080b, 0x0080c, 0x0080d, 0x0080e, 0x0080f,
+ 0x00810, 0x00811, 0x00812, 0x00813, 0x00814, 0x00815, 0x00816, 0x00817,
+ 0x00000, 0x00000, 0x0081a, 0x0081b, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0082e, 0x0082f,
+ 0x00830, 0x00831, 0x00832, 0x00833, 0x00834, 0x00835, 0x00836, 0x00837,
+ 0x00838, 0x00839, 0x0083a, 0x0083b, 0x0083c, 0x0083d, 0x0083e, 0x0083f,
+ 0x00840, 0x00841, 0x00842, 0x00843, 0x00844, 0x00845, 0x00846, 0x00847,
+ 0x00848, 0x00849, 0x0084a, 0x0084b, 0x0084c, 0x0084d, 0x0084e, 0x0084f,
+ 0x00850, 0x00851, 0x00852, 0x00853, 0x00854, 0x00855, 0x00856, 0x00857,
+ 0x00858, 0x00859, 0x0085a, 0x0085b, 0x0085c, 0x0085d, 0x0085e, 0x0085f,
+ 0x00860, 0x00861, 0x00862, 0x00863, 0x00864, 0x00865, 0x00866, 0x00867,
+ 0x00868, 0x00869, 0x0086a, 0x0086b, 0x0086c, 0x0086d, 0x0086e, 0x0086f,
+ 0x00870, 0x00871, 0x00872, 0x00873, 0x00874, 0x00875, 0x00876, 0x00877,
+ 0x00878, 0x00879, 0x0087a, 0x0087b, 0x0087c, 0x0087d, 0x0087e, 0x0087f,
+ 0x00880, 0x00881, 0x00882, 0x00883, 0x00884, 0x00885, 0x00886, 0x00887,
+ 0x00888, 0x00889, 0x0088a, 0x0088b, 0x0088c, 0x0088d, 0x0088e, 0x0088f,
+ 0x00890, 0x00891, 0x00892, 0x00893, 0x00894, 0x00895, 0x00896, 0x00897,
+ 0x00898, 0x00899, 0x0089a, 0x0089b, 0x0089c, 0x0089d, 0x0089e, 0x0089f,
+ 0x008a0, 0x008a1, 0x008a2, 0x008a3, 0x008a4, 0x008a5, 0x008a6, 0x008a7,
+ 0x008a8, 0x008a9, 0x008aa, 0x008ab, 0x008ac, 0x008ad, 0x008ae, 0x008af,
+ 0x008b0, 0x008b1, 0x008b2, 0x008b3, 0x008b4, 0x008b5, 0x008b6, 0x008b7,
+ 0x008b8, 0x008b9, 0x008ba, 0x008bb, 0x008bc, 0x008bd, 0x008be, 0x008bf,
+ 0x008c0, 0x008c1, 0x008c2, 0x008c3, 0x008c4, 0x008c5, 0x008c6, 0x008c7,
+ 0x008c8, 0x008c9, 0x008ca, 0x008cb, 0x008cc, 0x008cd, 0x008ce, 0x008cf,
+ 0x008d0, 0x008d1, 0x008d2, 0x008d3, 0x008d4, 0x008d5, 0x008d6, 0x008d7,
+ 0x008d8, 0x008d9, 0x008da, 0x008db, 0x008dc, 0x008dd, 0x008de, 0x008df,
+ 0x008e0, 0x008e1, 0x008e2, 0x008e3, 0x008e4, 0x008e5, 0x008e6, 0x008e7,
+ 0x008e8, 0x008e9, 0x008ea, 0x008eb, 0x008ec, 0x008ed, 0x008ee, 0x008ef,
+ 0x008f0, 0x008f1, 0x008f2, 0x008f3, 0x008f4, 0x008f5, 0x008f6, 0x008f7,
+ 0x008f8, 0x008f9, 0x008fa, 0x008fb, 0x008fc, 0x008fd, 0x008fe, 0x008ff
+};
+
+static uint32_t unicode_520_ci_page_09[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00904, 0x00905, 0x00906, 0x00907,
+ 0x00908, 0x00909, 0x0090a, 0x0090b, 0x0090c, 0x0090d, 0x0090e, 0x0090f,
+ 0x00910, 0x00911, 0x00912, 0x00913, 0x00914, 0x00915, 0x00916, 0x00917,
+ 0x00918, 0x00919, 0x0091a, 0x0091b, 0x0091c, 0x0091d, 0x0091e, 0x0091f,
+ 0x00920, 0x00921, 0x00922, 0x00923, 0x00924, 0x00925, 0x00926, 0x00927,
+ 0x00928, 0x00928, 0x0092a, 0x0092b, 0x0092c, 0x0092d, 0x0092e, 0x0092f,
+ 0x00930, 0x00930, 0x00932, 0x00933, 0x00933, 0x00935, 0x00936, 0x00937,
+ 0x00938, 0x00939, 0x0093a, 0x0093b, 0x00000, 0x0093d, 0x0093e, 0x0093f,
+ 0x00940, 0x00941, 0x00942, 0x00943, 0x00944, 0x00945, 0x00946, 0x00947,
+ 0x00948, 0x00949, 0x0094a, 0x0094b, 0x0094c, 0x0094d, 0x0094e, 0x0094f,
+ 0x00950, 0x00000, 0x00000, 0x00000, 0x00000, 0x00955, 0x00956, 0x00957,
+ 0x00915, 0x00916, 0x00917, 0x0091c, 0x00921, 0x00922, 0x0092b, 0x0092f,
+ 0x00960, 0x00961, 0x00962, 0x00963, 0x00964, 0x00965, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00970, 0x00971, 0x00972, 0x00973, 0x00974, 0x00975, 0x00976, 0x00977,
+ 0x00978, 0x00979, 0x0097a, 0x0097b, 0x0097c, 0x0097d, 0x0097e, 0x0097f,
+ 0x00980, 0x00000, 0x00000, 0x00000, 0x00984, 0x00985, 0x00986, 0x00987,
+ 0x00988, 0x00989, 0x0098a, 0x0098b, 0x0098c, 0x0098d, 0x0098e, 0x0098f,
+ 0x00990, 0x00991, 0x00992, 0x00993, 0x00994, 0x00995, 0x00996, 0x00997,
+ 0x00998, 0x00999, 0x0099a, 0x0099b, 0x0099c, 0x0099d, 0x0099e, 0x0099f,
+ 0x009a0, 0x009a1, 0x009a2, 0x009a3, 0x009a4, 0x009a5, 0x009a6, 0x009a7,
+ 0x009a8, 0x009a9, 0x009aa, 0x009ab, 0x009ac, 0x009ad, 0x009ae, 0x009af,
+ 0x009b0, 0x009b1, 0x009b2, 0x009b3, 0x009b4, 0x009b5, 0x009b6, 0x009b7,
+ 0x009b8, 0x009b9, 0x009ba, 0x009bb, 0x00000, 0x009bd, 0x009be, 0x009bf,
+ 0x009c0, 0x009c1, 0x009c2, 0x009c3, 0x009c4, 0x009c5, 0x009c6, 0x009c7,
+ 0x009c8, 0x009c9, 0x009ca, 0x009cb, 0x009cc, 0x009cd, 0x009ce, 0x009cf,
+ 0x009d0, 0x009d1, 0x009d2, 0x009d3, 0x009d4, 0x009d5, 0x009d6, 0x009d7,
+ 0x009d8, 0x009d9, 0x009da, 0x009db, 0x009a1, 0x009a2, 0x009de, 0x009af,
+ 0x009e0, 0x009e1, 0x009e2, 0x009e3, 0x009e4, 0x009e5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x009f0, 0x009f1, 0x009f2, 0x009f3, 0x009f4, 0x009f5, 0x009f6, 0x009f7,
+ 0x009f8, 0x009f9, 0x009fa, 0x009fb, 0x009fc, 0x009fd, 0x009fe, 0x009ff
+};
+
+static uint32_t unicode_520_ci_page_0a[] = {
+ 0x00a00, 0x00000, 0x00000, 0x00000, 0x00a04, 0x00a05, 0x00a06, 0x00a07,
+ 0x00a08, 0x00a09, 0x00a0a, 0x00a0b, 0x00a0c, 0x00a0d, 0x00a0e, 0x00a0f,
+ 0x00a10, 0x00a11, 0x00a12, 0x00a13, 0x00a14, 0x00a15, 0x00a16, 0x00a17,
+ 0x00a18, 0x00a19, 0x00a1a, 0x00a1b, 0x00a1c, 0x00a1d, 0x00a1e, 0x00a1f,
+ 0x00a20, 0x00a21, 0x00a22, 0x00a23, 0x00a24, 0x00a25, 0x00a26, 0x00a27,
+ 0x00a28, 0x00a29, 0x00a2a, 0x00a2b, 0x00a2c, 0x00a2d, 0x00a2e, 0x00a2f,
+ 0x00a30, 0x00a31, 0x00a32, 0x00a32, 0x00a34, 0x00a35, 0x00a36, 0x00a37,
+ 0x00a36, 0x00a39, 0x00a3a, 0x00a3b, 0x00000, 0x00a3d, 0x00a3e, 0x00a3f,
+ 0x00a40, 0x00a41, 0x00a42, 0x00a43, 0x00a44, 0x00a45, 0x00a46, 0x00a47,
+ 0x00a48, 0x00a49, 0x00a4a, 0x00a4b, 0x00a4c, 0x00a4d, 0x00a4e, 0x00a4f,
+ 0x00a50, 0x00a51, 0x00a52, 0x00a53, 0x00a54, 0x00a55, 0x00a56, 0x00a57,
+ 0x00a58, 0x00a16, 0x00a17, 0x00a1c, 0x00a5c, 0x00a5d, 0x00a2b, 0x00a5f,
+ 0x00a60, 0x00a61, 0x00a62, 0x00a63, 0x00a64, 0x00a65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00000, 0x00000, 0x00a72, 0x00a73, 0x00a74, 0x00a75, 0x00a76, 0x00a77,
+ 0x00a78, 0x00a79, 0x00a7a, 0x00a7b, 0x00a7c, 0x00a7d, 0x00a7e, 0x00a7f,
+ 0x00a80, 0x00000, 0x00000, 0x00000, 0x00a84, 0x00a85, 0x00a86, 0x00a87,
+ 0x00a88, 0x00a89, 0x00a8a, 0x00a8b, 0x00a8c, 0x00a8d, 0x00a8e, 0x00a8f,
+ 0x00a90, 0x00a91, 0x00a92, 0x00a93, 0x00a94, 0x00a95, 0x00a96, 0x00a97,
+ 0x00a98, 0x00a99, 0x00a9a, 0x00a9b, 0x00a9c, 0x00a9d, 0x00a9e, 0x00a9f,
+ 0x00aa0, 0x00aa1, 0x00aa2, 0x00aa3, 0x00aa4, 0x00aa5, 0x00aa6, 0x00aa7,
+ 0x00aa8, 0x00aa9, 0x00aaa, 0x00aab, 0x00aac, 0x00aad, 0x00aae, 0x00aaf,
+ 0x00ab0, 0x00ab1, 0x00ab2, 0x00ab3, 0x00ab4, 0x00ab5, 0x00ab6, 0x00ab7,
+ 0x00ab8, 0x00ab9, 0x00aba, 0x00abb, 0x00000, 0x00abd, 0x00abe, 0x00abf,
+ 0x00ac0, 0x00ac1, 0x00ac2, 0x00ac3, 0x00ac4, 0x00ac5, 0x00ac6, 0x00ac7,
+ 0x00ac8, 0x00ac9, 0x00aca, 0x00acb, 0x00acc, 0x00acd, 0x00ace, 0x00acf,
+ 0x00ad0, 0x00ad1, 0x00ad2, 0x00ad3, 0x00ad4, 0x00ad5, 0x00ad6, 0x00ad7,
+ 0x00ad8, 0x00ad9, 0x00ada, 0x00adb, 0x00adc, 0x00add, 0x00ade, 0x00adf,
+ 0x00ae0, 0x00ae1, 0x00ae2, 0x00ae3, 0x00ae4, 0x00ae5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00af0, 0x00af1, 0x00af2, 0x00af3, 0x00af4, 0x00af5, 0x00af6, 0x00af7,
+ 0x00af8, 0x00af9, 0x00afa, 0x00afb, 0x00afc, 0x00afd, 0x00afe, 0x00aff
+};
+
+static uint32_t unicode_520_ci_page_0b[] = {
+ 0x00b00, 0x00000, 0x00000, 0x00000, 0x00b04, 0x00b05, 0x00b06, 0x00b07,
+ 0x00b08, 0x00b09, 0x00b0a, 0x00b0b, 0x00b0c, 0x00b0d, 0x00b0e, 0x00b0f,
+ 0x00b10, 0x00b11, 0x00b12, 0x00b13, 0x00b14, 0x00b15, 0x00b16, 0x00b17,
+ 0x00b18, 0x00b19, 0x00b1a, 0x00b1b, 0x00b1c, 0x00b1d, 0x00b1e, 0x00b1f,
+ 0x00b20, 0x00b21, 0x00b22, 0x00b23, 0x00b24, 0x00b25, 0x00b26, 0x00b27,
+ 0x00b28, 0x00b29, 0x00b2a, 0x00b2b, 0x00b2c, 0x00b2d, 0x00b2e, 0x00b2f,
+ 0x00b30, 0x00b31, 0x00b32, 0x00b33, 0x00b34, 0x00b35, 0x00b36, 0x00b37,
+ 0x00b38, 0x00b39, 0x00b3a, 0x00b3b, 0x00000, 0x00b3d, 0x00b3e, 0x00b3f,
+ 0x00b40, 0x00b41, 0x00b42, 0x00b43, 0x00b44, 0x00b45, 0x00b46, 0x00b47,
+ 0x00b48, 0x00b49, 0x00b4a, 0x00b4b, 0x00b4c, 0x00b4d, 0x00b4e, 0x00b4f,
+ 0x00b50, 0x00b51, 0x00b52, 0x00b53, 0x00b54, 0x00b55, 0x00b56, 0x00b57,
+ 0x00b58, 0x00b59, 0x00b5a, 0x00b5b, 0x00b21, 0x00b22, 0x00b5e, 0x00b5f,
+ 0x00b60, 0x00b61, 0x00b62, 0x00b63, 0x00b64, 0x00b65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00b70, 0x00b71, 0x00b72, 0x00b73, 0x00b74, 0x00b75, 0x00b76, 0x00b77,
+ 0x00b78, 0x00b79, 0x00b7a, 0x00b7b, 0x00b7c, 0x00b7d, 0x00b7e, 0x00b7f,
+ 0x00b80, 0x00b81, 0x00000, 0x00b83, 0x00b84, 0x00b85, 0x00b86, 0x00b87,
+ 0x00b88, 0x00b89, 0x00b8a, 0x00b8b, 0x00b8c, 0x00b8d, 0x00b8e, 0x00b8f,
+ 0x00b90, 0x00b91, 0x00b92, 0x00b93, 0x00b94, 0x00b95, 0x00b96, 0x00b97,
+ 0x00b98, 0x00b99, 0x00b9a, 0x00b9b, 0x00b9c, 0x00b9d, 0x00b9e, 0x00b9f,
+ 0x00ba0, 0x00ba1, 0x00ba2, 0x00ba3, 0x00ba4, 0x00ba5, 0x00ba6, 0x00ba7,
+ 0x00ba8, 0x00ba9, 0x00baa, 0x00bab, 0x00bac, 0x00bad, 0x00bae, 0x00baf,
+ 0x00bb0, 0x00bb1, 0x00bb2, 0x00bb3, 0x00bb4, 0x00bb5, 0x00bb6, 0x00bb7,
+ 0x00bb8, 0x00bb9, 0x00bba, 0x00bbb, 0x00bbc, 0x00bbd, 0x00bbe, 0x00bbf,
+ 0x00bc0, 0x00bc1, 0x00bc2, 0x00bc3, 0x00bc4, 0x00bc5, 0x00bc6, 0x00bc7,
+ 0x00bc8, 0x00bc9, 0x00bca, 0x00bcb, 0x00bcc, 0x00bcd, 0x00bce, 0x00bcf,
+ 0x00bd0, 0x00bd1, 0x00bd2, 0x00bd3, 0x00bd4, 0x00bd5, 0x00bd6, 0x00bd7,
+ 0x00bd8, 0x00bd9, 0x00bda, 0x00bdb, 0x00bdc, 0x00bdd, 0x00bde, 0x00bdf,
+ 0x00be0, 0x00be1, 0x00be2, 0x00be3, 0x00be4, 0x00be5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00bf0, 0x00bf1, 0x00bf2, 0x00bf3, 0x00bf4, 0x00bf5, 0x00bf6, 0x00bf7,
+ 0x00bf8, 0x00bf9, 0x00bfa, 0x00bfb, 0x00bfc, 0x00bfd, 0x00bfe, 0x00bff
+};
+
+static uint32_t unicode_520_ci_page_0c[] = {
+ 0x00c00, 0x00000, 0x00000, 0x00000, 0x00c04, 0x00c05, 0x00c06, 0x00c07,
+ 0x00c08, 0x00c09, 0x00c0a, 0x00c0b, 0x00c0c, 0x00c0d, 0x00c0e, 0x00c0f,
+ 0x00c10, 0x00c11, 0x00c12, 0x00c13, 0x00c14, 0x00c15, 0x00c16, 0x00c17,
+ 0x00c18, 0x00c19, 0x00c1a, 0x00c1b, 0x00c1c, 0x00c1d, 0x00c1e, 0x00c1f,
+ 0x00c20, 0x00c21, 0x00c22, 0x00c23, 0x00c24, 0x00c25, 0x00c26, 0x00c27,
+ 0x00c28, 0x00c29, 0x00c2a, 0x00c2b, 0x00c2c, 0x00c2d, 0x00c2e, 0x00c2f,
+ 0x00c30, 0x00c31, 0x00c32, 0x00c33, 0x00c34, 0x00c35, 0x00c36, 0x00c37,
+ 0x00c38, 0x00c39, 0x00c3a, 0x00c3b, 0x00c3c, 0x00c3d, 0x00c3e, 0x00c3f,
+ 0x00c40, 0x00c41, 0x00c42, 0x00c43, 0x00c44, 0x00c45, 0x00c46, 0x00c47,
+ 0x00c48, 0x00c49, 0x00c4a, 0x00c4b, 0x00c4c, 0x00c4d, 0x00c4e, 0x00c4f,
+ 0x00c50, 0x00c51, 0x00c52, 0x00c53, 0x00c54, 0x00c55, 0x00c56, 0x00c57,
+ 0x00c58, 0x00c59, 0x00c5a, 0x00c5b, 0x00c5c, 0x00c5d, 0x00c5e, 0x00c5f,
+ 0x00c60, 0x00c61, 0x00c62, 0x00c63, 0x00c64, 0x00c65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00c70, 0x00c71, 0x00c72, 0x00c73, 0x00c74, 0x00c75, 0x00c76, 0x00c77,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00031, 0x00032, 0x00033, 0x00c7f,
+ 0x00c80, 0x00c81, 0x00000, 0x00000, 0x00c84, 0x00c85, 0x00c86, 0x00c87,
+ 0x00c88, 0x00c89, 0x00c8a, 0x00c8b, 0x00c8c, 0x00c8d, 0x00c8e, 0x00c8f,
+ 0x00c90, 0x00c91, 0x00c92, 0x00c93, 0x00c94, 0x00c95, 0x00c96, 0x00c97,
+ 0x00c98, 0x00c99, 0x00c9a, 0x00c9b, 0x00c9c, 0x00c9d, 0x00c9e, 0x00c9f,
+ 0x00ca0, 0x00ca1, 0x00ca2, 0x00ca3, 0x00ca4, 0x00ca5, 0x00ca6, 0x00ca7,
+ 0x00ca8, 0x00ca9, 0x00caa, 0x00cab, 0x00cac, 0x00cad, 0x00cae, 0x00caf,
+ 0x00cb0, 0x00cb1, 0x00cb2, 0x00cb3, 0x00cb4, 0x00cb5, 0x00cb6, 0x00cb7,
+ 0x00cb8, 0x00cb9, 0x00cba, 0x00cbb, 0x00000, 0x00cbd, 0x00cbe, 0x00cbf,
+ 0x00cc0, 0x00cc1, 0x00cc2, 0x00cc3, 0x00cc4, 0x00cc5, 0x00cc6, 0x00cc7,
+ 0x00cc8, 0x00cc9, 0x00cca, 0x00ccb, 0x00ccc, 0x00ccd, 0x00cce, 0x00ccf,
+ 0x00cd0, 0x00cd1, 0x00cd2, 0x00cd3, 0x00cd4, 0x00cd5, 0x00cd6, 0x00cd7,
+ 0x00cd8, 0x00cd9, 0x00cda, 0x00cdb, 0x00cdc, 0x00cdd, 0x00cde, 0x00cdf,
+ 0x00ce0, 0x00ce1, 0x00ce2, 0x00ce3, 0x00ce4, 0x00ce5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00cf0, 0x00cf1, 0x00cf2, 0x00cf3, 0x00cf4, 0x00cf5, 0x00cf6, 0x00cf7,
+ 0x00cf8, 0x00cf9, 0x00cfa, 0x00cfb, 0x00cfc, 0x00cfd, 0x00cfe, 0x00cff
+};
+
+static uint32_t unicode_520_ci_page_0d[] = {
+ 0x00d00, 0x00d01, 0x00000, 0x00000, 0x00d04, 0x00d05, 0x00d06, 0x00d07,
+ 0x00d08, 0x00d09, 0x00d0a, 0x00d0b, 0x00d0c, 0x00d0d, 0x00d0e, 0x00d0f,
+ 0x00d10, 0x00d11, 0x00d12, 0x00d13, 0x00d14, 0x00d15, 0x00d16, 0x00d17,
+ 0x00d18, 0x00d19, 0x00d1a, 0x00d1b, 0x00d1c, 0x00d1d, 0x00d1e, 0x00d1f,
+ 0x00d20, 0x00d21, 0x00d22, 0x00d23, 0x00d24, 0x00d25, 0x00d26, 0x00d27,
+ 0x00d28, 0x00d29, 0x00d2a, 0x00d2b, 0x00d2c, 0x00d2d, 0x00d2e, 0x00d2f,
+ 0x00d30, 0x00d31, 0x00d32, 0x00d33, 0x00d34, 0x00d35, 0x00d36, 0x00d37,
+ 0x00d38, 0x00d39, 0x00d3a, 0x00d3b, 0x00d3c, 0x00d3d, 0x00d3e, 0x00d3f,
+ 0x00d40, 0x00d41, 0x00d42, 0x00d43, 0x00d44, 0x00d45, 0x00d46, 0x00d47,
+ 0x00d48, 0x00d49, 0x00d4a, 0x00d4b, 0x00d4c, 0x00d4d, 0x00d4e, 0x00d4f,
+ 0x00d50, 0x00d51, 0x00d52, 0x00d53, 0x00d54, 0x00d55, 0x00d56, 0x00d57,
+ 0x00d58, 0x00d59, 0x00d5a, 0x00d5b, 0x00d5c, 0x00d5d, 0x00d5e, 0x00d5f,
+ 0x00d60, 0x00d61, 0x00d62, 0x00d63, 0x00d64, 0x00d65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00d70, 0x00d71, 0x00d72, 0x00d73, 0x00d74, 0x00d75, 0x00d76, 0x00d77,
+ 0x00d78, 0x00d79, 0x00d7a, 0x00d7b, 0x00d7c, 0x00d7d, 0x00d7e, 0x00d7f,
+ 0x00d80, 0x00d81, 0x00000, 0x00000, 0x00d84, 0x00d85, 0x00d86, 0x00d87,
+ 0x00d88, 0x00d89, 0x00d8a, 0x00d8b, 0x00d8c, 0x00d8d, 0x00d8e, 0x00d8f,
+ 0x00d90, 0x00d91, 0x00d92, 0x00d93, 0x00d94, 0x00d95, 0x00d96, 0x00d97,
+ 0x00d98, 0x00d99, 0x00d9a, 0x00d9b, 0x00d9c, 0x00d9d, 0x00d9e, 0x00d9f,
+ 0x00da0, 0x00da1, 0x00da2, 0x00da3, 0x00da4, 0x00da5, 0x00da6, 0x00da7,
+ 0x00da8, 0x00da9, 0x00daa, 0x00dab, 0x00dac, 0x00dad, 0x00dae, 0x00daf,
+ 0x00db0, 0x00db1, 0x00db2, 0x00db3, 0x00db4, 0x00db5, 0x00db6, 0x00db7,
+ 0x00db8, 0x00db9, 0x00dba, 0x00dbb, 0x00dbc, 0x00dbd, 0x00dbe, 0x00dbf,
+ 0x00dc0, 0x00dc1, 0x00dc2, 0x00dc3, 0x00dc4, 0x00dc5, 0x00dc6, 0x00dc7,
+ 0x00dc8, 0x00dc9, 0x00dca, 0x00dcb, 0x00dcc, 0x00dcd, 0x00dce, 0x00dcf,
+ 0x00dd0, 0x00dd1, 0x00dd2, 0x00dd3, 0x00dd4, 0x00dd5, 0x00dd6, 0x00dd7,
+ 0x00dd8, 0x00dd9, 0x00dda, 0x00ddb, 0x00ddc, 0x00ddd, 0x00dde, 0x00ddf,
+ 0x00de0, 0x00de1, 0x00de2, 0x00de3, 0x00de4, 0x00de5, 0x00de6, 0x00de7,
+ 0x00de8, 0x00de9, 0x00dea, 0x00deb, 0x00dec, 0x00ded, 0x00dee, 0x00def,
+ 0x00df0, 0x00df1, 0x00df2, 0x00df3, 0x00df4, 0x00df5, 0x00df6, 0x00df7,
+ 0x00df8, 0x00df9, 0x00dfa, 0x00dfb, 0x00dfc, 0x00dfd, 0x00dfe, 0x00dff
+};
+
+static uint32_t unicode_520_ci_page_0e[] = {
+ 0x00e00, 0x00e01, 0x00e02, 0x00e03, 0x00e04, 0x00e05, 0x00e06, 0x00e07,
+ 0x00e08, 0x00e09, 0x00e0a, 0x00e0b, 0x00e0c, 0x00e0d, 0x00e0e, 0x00e0f,
+ 0x00e10, 0x00e11, 0x00e12, 0x00e13, 0x00e14, 0x00e15, 0x00e16, 0x00e17,
+ 0x00e18, 0x00e19, 0x00e1a, 0x00e1b, 0x00e1c, 0x00e1d, 0x00e1e, 0x00e1f,
+ 0x00e20, 0x00e21, 0x00e22, 0x00e23, 0x00e24, 0x00e25, 0x00e26, 0x00e27,
+ 0x00e28, 0x00e29, 0x00e2a, 0x00e2b, 0x00e2c, 0x00e2d, 0x00e2e, 0x00e2f,
+ 0x00e30, 0x00e31, 0x00e32, 0x00e33, 0x00e34, 0x00e35, 0x00e36, 0x00e37,
+ 0x00e38, 0x00e39, 0x00e3a, 0x00e3b, 0x00e3c, 0x00e3d, 0x00e3e, 0x00e3f,
+ 0x00e40, 0x00e41, 0x00e42, 0x00e43, 0x00e44, 0x00e45, 0x00e46, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00e4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00e5a, 0x00e5b, 0x00e5c, 0x00e5d, 0x00e5e, 0x00e5f,
+ 0x00e60, 0x00e61, 0x00e62, 0x00e63, 0x00e64, 0x00e65, 0x00e66, 0x00e67,
+ 0x00e68, 0x00e69, 0x00e6a, 0x00e6b, 0x00e6c, 0x00e6d, 0x00e6e, 0x00e6f,
+ 0x00e70, 0x00e71, 0x00e72, 0x00e73, 0x00e74, 0x00e75, 0x00e76, 0x00e77,
+ 0x00e78, 0x00e79, 0x00e7a, 0x00e7b, 0x00e7c, 0x00e7d, 0x00e7e, 0x00e7f,
+ 0x00e80, 0x00e81, 0x00e82, 0x00e83, 0x00e84, 0x00e85, 0x00e86, 0x00e87,
+ 0x00e88, 0x00e89, 0x00e8a, 0x00e8b, 0x00e8c, 0x00e8d, 0x00e8e, 0x00e8f,
+ 0x00e90, 0x00e91, 0x00e92, 0x00e93, 0x00e94, 0x00e95, 0x00e96, 0x00e97,
+ 0x00e98, 0x00e99, 0x00e9a, 0x00e9b, 0x00e9c, 0x00e9d, 0x00e9e, 0x00e9f,
+ 0x00ea0, 0x00ea1, 0x00ea2, 0x00ea3, 0x00ea4, 0x00ea5, 0x00ea6, 0x00ea7,
+ 0x00ea8, 0x00ea9, 0x00eaa, 0x00eab, 0x00eac, 0x00ead, 0x00eae, 0x00eaf,
+ 0x00eb0, 0x00eb1, 0x00eb2, 0x00eb3, 0x00eb4, 0x00eb5, 0x00eb6, 0x00eb7,
+ 0x00eb8, 0x00eb9, 0x00eba, 0x00ebb, 0x00ebc, 0x00ebd, 0x00ebe, 0x00ebf,
+ 0x00ec0, 0x00ec1, 0x00ec2, 0x00ec3, 0x00ec4, 0x00ec5, 0x00ec6, 0x00ec7,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00ece, 0x00ecf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00eda, 0x00edb, 0x00edc, 0x00edd, 0x00ede, 0x00edf,
+ 0x00ee0, 0x00ee1, 0x00ee2, 0x00ee3, 0x00ee4, 0x00ee5, 0x00ee6, 0x00ee7,
+ 0x00ee8, 0x00ee9, 0x00eea, 0x00eeb, 0x00eec, 0x00eed, 0x00eee, 0x00eef,
+ 0x00ef0, 0x00ef1, 0x00ef2, 0x00ef3, 0x00ef4, 0x00ef5, 0x00ef6, 0x00ef7,
+ 0x00ef8, 0x00ef9, 0x00efa, 0x00efb, 0x00efc, 0x00efd, 0x00efe, 0x00eff
+};
+
+static uint32_t unicode_520_ci_page_0f[] = {
+ 0x00f00, 0x00f01, 0x00f02, 0x00f03, 0x00f04, 0x00f05, 0x00f06, 0x00f07,
+ 0x00f08, 0x00f09, 0x00f0a, 0x00f0b, 0x00f0b, 0x00f0d, 0x00f0e, 0x00f0f,
+ 0x00f10, 0x00f11, 0x00f12, 0x00f13, 0x00f14, 0x00f15, 0x00f16, 0x00f17,
+ 0x00000, 0x00000, 0x00f1a, 0x00f1b, 0x00f1c, 0x00f1d, 0x00f1e, 0x00f1f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x00030, 0x00f34, 0x00000, 0x00f36, 0x00000,
+ 0x00f38, 0x00000, 0x00f3a, 0x00f3b, 0x00f3c, 0x00f3d, 0x00f3e, 0x00f3f,
+ 0x00f40, 0x00f41, 0x00f42, 0x00f43, 0x00f44, 0x00f45, 0x00f46, 0x00f47,
+ 0x00f48, 0x00f49, 0x00f4a, 0x00f4b, 0x00f4c, 0x00f4d, 0x00f4e, 0x00f4f,
+ 0x00f50, 0x00f51, 0x00f52, 0x00f53, 0x00f54, 0x00f55, 0x00f56, 0x00f57,
+ 0x00f58, 0x00f59, 0x00f5a, 0x00f5b, 0x00f5c, 0x00f5d, 0x00f5e, 0x00f5f,
+ 0x00f60, 0x00f61, 0x00f62, 0x00f63, 0x00f64, 0x00f65, 0x00f66, 0x00f67,
+ 0x00f68, 0x00f69, 0x00f62, 0x00f6b, 0x00f6c, 0x00f6d, 0x00f6e, 0x00f6f,
+ 0x00f70, 0x00f71, 0x00f72, 0x00f73, 0x00f74, 0x00f75, 0x00f76, 0x00f77,
+ 0x00f78, 0x00f79, 0x00f7a, 0x00f7b, 0x00f7c, 0x00f7d, 0x00000, 0x00000,
+ 0x00f80, 0x00f81, 0x00000, 0x00000, 0x00f84, 0x00f85, 0x00000, 0x00000,
+ 0x00f88, 0x00f89, 0x00f8a, 0x00f8b, 0x00f8c, 0x00f8d, 0x00f8e, 0x00f8f,
+ 0x00f90, 0x00f91, 0x00f92, 0x00f93, 0x00f94, 0x00f95, 0x00f96, 0x00f97,
+ 0x00f98, 0x00f99, 0x00f9a, 0x00f9b, 0x00f9c, 0x00f9d, 0x00f9e, 0x00f9f,
+ 0x00fa0, 0x00fa1, 0x00fa2, 0x00fa3, 0x00fa4, 0x00fa5, 0x00fa6, 0x00fa7,
+ 0x00fa8, 0x00fa9, 0x00faa, 0x00fab, 0x00fac, 0x00fad, 0x00fae, 0x00faf,
+ 0x00fb0, 0x00fb1, 0x00fb2, 0x00fb3, 0x00fb4, 0x00fb5, 0x00fb6, 0x00fb7,
+ 0x00fb8, 0x00fb9, 0x00fad, 0x00fb1, 0x00fb2, 0x00fbd, 0x00fbe, 0x00fbf,
+ 0x00fc0, 0x00fc1, 0x00fc2, 0x00fc3, 0x00fc4, 0x00fc5, 0x00000, 0x00fc7,
+ 0x00fc8, 0x00fc9, 0x00fca, 0x00fcb, 0x00fcc, 0x00fcd, 0x00fce, 0x00fcf,
+ 0x00fd0, 0x00fd1, 0x00fd2, 0x00fd3, 0x00fd4, 0x00fd5, 0x00fd6, 0x00fd7,
+ 0x00fd8, 0x00fd9, 0x00fda, 0x00fdb, 0x00fdc, 0x00fdd, 0x00fde, 0x00fdf,
+ 0x00fe0, 0x00fe1, 0x00fe2, 0x00fe3, 0x00fe4, 0x00fe5, 0x00fe6, 0x00fe7,
+ 0x00fe8, 0x00fe9, 0x00fea, 0x00feb, 0x00fec, 0x00fed, 0x00fee, 0x00fef,
+ 0x00ff0, 0x00ff1, 0x00ff2, 0x00ff3, 0x00ff4, 0x00ff5, 0x00ff6, 0x00ff7,
+ 0x00ff8, 0x00ff9, 0x00ffa, 0x00ffb, 0x00ffc, 0x00ffd, 0x00ffe, 0x00fff
+};
+
+static uint32_t unicode_520_ci_page_10[] = {
+ 0x01000, 0x01001, 0x01002, 0x01003, 0x01004, 0x01005, 0x01006, 0x01007,
+ 0x01008, 0x01009, 0x0100a, 0x0100b, 0x0100c, 0x0100d, 0x0100e, 0x0100f,
+ 0x01010, 0x01011, 0x01012, 0x01013, 0x01014, 0x01015, 0x01016, 0x01017,
+ 0x01018, 0x01019, 0x0101a, 0x0101b, 0x0101c, 0x0101d, 0x0101e, 0x0101f,
+ 0x01020, 0x01021, 0x01022, 0x01023, 0x01024, 0x01025, 0x01026, 0x01027,
+ 0x01028, 0x01029, 0x0102a, 0x0102b, 0x0102b, 0x0102d, 0x0102e, 0x0102f,
+ 0x01030, 0x01031, 0x01032, 0x01033, 0x01034, 0x01035, 0x00000, 0x00000,
+ 0x00000, 0x01039, 0x0103a, 0x0103b, 0x0103c, 0x0103d, 0x0103e, 0x0103f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0104a, 0x0104b, 0x0104c, 0x0104d, 0x0104e, 0x0104f,
+ 0x01050, 0x01051, 0x01052, 0x01053, 0x01054, 0x01055, 0x01056, 0x01057,
+ 0x01058, 0x01059, 0x0105a, 0x0105b, 0x0105c, 0x0105d, 0x0105e, 0x0105f,
+ 0x01060, 0x01061, 0x01062, 0x01063, 0x01064, 0x01065, 0x01066, 0x01067,
+ 0x01068, 0x01069, 0x0106a, 0x0106b, 0x0106c, 0x0106d, 0x0106e, 0x0106f,
+ 0x01070, 0x01071, 0x01072, 0x01073, 0x01074, 0x01075, 0x01076, 0x01077,
+ 0x01078, 0x01079, 0x0107a, 0x0107b, 0x0107c, 0x0107d, 0x0107e, 0x0107f,
+ 0x01080, 0x01081, 0x01082, 0x01083, 0x01084, 0x01085, 0x01086, 0x01087,
+ 0x01088, 0x01089, 0x0108a, 0x0108b, 0x0108c, 0x00000, 0x0108e, 0x0108f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0109a, 0x0109b, 0x0109c, 0x0109d, 0x0109e, 0x0109f,
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x010c6, 0x010c7,
+ 0x010c8, 0x010c9, 0x010ca, 0x010cb, 0x010cc, 0x010cd, 0x010ce, 0x010cf,
+ 0x010d0, 0x010d1, 0x010d2, 0x010d3, 0x010d4, 0x010d5, 0x010d6, 0x010d7,
+ 0x010d8, 0x010d9, 0x010da, 0x010db, 0x010dc, 0x010dd, 0x010de, 0x010df,
+ 0x010e0, 0x010e1, 0x010e2, 0x010e3, 0x010e4, 0x010e5, 0x010e6, 0x010e7,
+ 0x010e8, 0x010e9, 0x010ea, 0x010eb, 0x010ec, 0x010ed, 0x010ee, 0x010ef,
+ 0x010f0, 0x010f1, 0x010f2, 0x010f3, 0x010f4, 0x010f5, 0x010f6, 0x010f7,
+ 0x010f8, 0x010f9, 0x010fa, 0x010fb, 0x010dc, 0x010fd, 0x010fe, 0x010ff
+};
+
+static uint32_t unicode_520_ci_page_13[] = {
+ 0x01300, 0x01301, 0x01302, 0x01303, 0x01304, 0x01305, 0x01306, 0x01307,
+ 0x01308, 0x01309, 0x0130a, 0x0130b, 0x0130c, 0x0130d, 0x0130e, 0x0130f,
+ 0x01310, 0x01311, 0x01312, 0x01313, 0x01314, 0x01315, 0x01316, 0x01317,
+ 0x01318, 0x01319, 0x0131a, 0x0131b, 0x0131c, 0x0131d, 0x0131e, 0x0131f,
+ 0x01320, 0x01321, 0x01322, 0x01323, 0x01324, 0x01325, 0x01326, 0x01327,
+ 0x01328, 0x01329, 0x0132a, 0x0132b, 0x0132c, 0x0132d, 0x0132e, 0x0132f,
+ 0x01330, 0x01331, 0x01332, 0x01333, 0x01334, 0x01335, 0x01336, 0x01337,
+ 0x01338, 0x01339, 0x0133a, 0x0133b, 0x0133c, 0x0133d, 0x0133e, 0x0133f,
+ 0x01340, 0x01341, 0x01342, 0x01343, 0x01344, 0x01345, 0x01346, 0x01347,
+ 0x01348, 0x01349, 0x0134a, 0x0134b, 0x0134c, 0x0134d, 0x0134e, 0x0134f,
+ 0x01350, 0x01351, 0x01352, 0x01353, 0x01354, 0x01355, 0x01356, 0x01357,
+ 0x01358, 0x01359, 0x0135a, 0x0135b, 0x0135c, 0x0135d, 0x0135e, 0x00000,
+ 0x01360, 0x01361, 0x01362, 0x01363, 0x01364, 0x01365, 0x01366, 0x01367,
+ 0x01368, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01372, 0x01373, 0x01374, 0x01375, 0x01376, 0x01377,
+ 0x01378, 0x01379, 0x0137a, 0x0137b, 0x0137c, 0x0137d, 0x0137e, 0x0137f,
+ 0x01380, 0x01381, 0x01382, 0x01383, 0x01384, 0x01385, 0x01386, 0x01387,
+ 0x01388, 0x01389, 0x0138a, 0x0138b, 0x0138c, 0x0138d, 0x0138e, 0x0138f,
+ 0x01390, 0x01391, 0x01392, 0x01393, 0x01394, 0x01395, 0x01396, 0x01397,
+ 0x01398, 0x01399, 0x0139a, 0x0139b, 0x0139c, 0x0139d, 0x0139e, 0x0139f,
+ 0x013a0, 0x013a1, 0x013a2, 0x013a3, 0x013a4, 0x013a5, 0x013a6, 0x013a7,
+ 0x013a8, 0x013a9, 0x013aa, 0x013ab, 0x013ac, 0x013ad, 0x013ae, 0x013af,
+ 0x013b0, 0x013b1, 0x013b2, 0x013b3, 0x013b4, 0x013b5, 0x013b6, 0x013b7,
+ 0x013b8, 0x013b9, 0x013ba, 0x013bb, 0x013bc, 0x013bd, 0x013be, 0x013bf,
+ 0x013c0, 0x013c1, 0x013c2, 0x013c3, 0x013c4, 0x013c5, 0x013c6, 0x013c7,
+ 0x013c8, 0x013c9, 0x013ca, 0x013cb, 0x013cc, 0x013cd, 0x013ce, 0x013cf,
+ 0x013d0, 0x013d1, 0x013d2, 0x013d3, 0x013d4, 0x013d5, 0x013d6, 0x013d7,
+ 0x013d8, 0x013d9, 0x013da, 0x013db, 0x013dc, 0x013dd, 0x013de, 0x013df,
+ 0x013e0, 0x013e1, 0x013e2, 0x013e3, 0x013e4, 0x013e5, 0x013e6, 0x013e7,
+ 0x013e8, 0x013e9, 0x013ea, 0x013eb, 0x013ec, 0x013ed, 0x013ee, 0x013ef,
+ 0x013f0, 0x013f1, 0x013f2, 0x013f3, 0x013f4, 0x013f5, 0x013f6, 0x013f7,
+ 0x013f8, 0x013f9, 0x013fa, 0x013fb, 0x013fc, 0x013fd, 0x013fe, 0x013ff
+};
+
+static uint32_t unicode_520_ci_page_16[] = {
+ 0x01600, 0x01601, 0x01602, 0x01603, 0x01604, 0x01605, 0x01606, 0x01607,
+ 0x01608, 0x01609, 0x0160a, 0x0160b, 0x0160c, 0x0160d, 0x0160e, 0x0160f,
+ 0x01610, 0x01611, 0x01612, 0x01613, 0x01614, 0x01615, 0x01616, 0x01617,
+ 0x01618, 0x01619, 0x0161a, 0x0161b, 0x0161c, 0x0161d, 0x0161e, 0x0161f,
+ 0x01620, 0x01621, 0x01622, 0x01623, 0x01624, 0x01625, 0x01626, 0x01627,
+ 0x01628, 0x01629, 0x0162a, 0x0162b, 0x0162c, 0x0162d, 0x0162e, 0x0162f,
+ 0x01630, 0x01631, 0x01632, 0x01633, 0x01634, 0x01635, 0x01636, 0x01637,
+ 0x01638, 0x01639, 0x0163a, 0x0163b, 0x0163c, 0x0163d, 0x0163e, 0x0163f,
+ 0x01640, 0x01641, 0x01642, 0x01643, 0x01644, 0x01645, 0x01646, 0x01647,
+ 0x01648, 0x01649, 0x0164a, 0x0164b, 0x0164c, 0x0164d, 0x0164e, 0x0164f,
+ 0x01650, 0x01651, 0x01652, 0x01653, 0x01654, 0x01655, 0x01656, 0x01657,
+ 0x01658, 0x01659, 0x0165a, 0x0165b, 0x0165c, 0x0165d, 0x0165e, 0x0165f,
+ 0x01660, 0x01661, 0x01662, 0x01663, 0x01664, 0x01665, 0x01666, 0x01667,
+ 0x01668, 0x01669, 0x0166a, 0x0166b, 0x0166c, 0x0166d, 0x0166e, 0x0166f,
+ 0x01670, 0x01671, 0x01672, 0x01673, 0x01674, 0x01675, 0x01676, 0x01677,
+ 0x01678, 0x01679, 0x0167a, 0x0167b, 0x0167c, 0x0167d, 0x0167e, 0x0167f,
+ 0x01680, 0x01681, 0x01682, 0x01683, 0x01684, 0x01685, 0x01686, 0x01687,
+ 0x01688, 0x01689, 0x0168a, 0x0168b, 0x0168c, 0x0168d, 0x0168e, 0x0168f,
+ 0x01690, 0x01691, 0x01692, 0x01693, 0x01694, 0x01695, 0x01696, 0x01697,
+ 0x01698, 0x01699, 0x0169a, 0x0169b, 0x0169c, 0x0169d, 0x0169e, 0x0169f,
+ 0x016a0, 0x016a0, 0x016a2, 0x016a3, 0x016a2, 0x016a2, 0x016a6, 0x016a6,
+ 0x016a8, 0x016a8, 0x016aa, 0x016ab, 0x016a8, 0x016a8, 0x016a8, 0x016af,
+ 0x016b0, 0x016b1, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b7,
+ 0x016b8, 0x016b9, 0x016ba, 0x016ba, 0x016ba, 0x016ba, 0x016be, 0x016be,
+ 0x016be, 0x016c1, 0x016c1, 0x016c3, 0x016c3, 0x016c5, 0x016c5, 0x016c7,
+ 0x016c8, 0x016c9, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016cf,
+ 0x016cf, 0x016cf, 0x016d2, 0x016d2, 0x016d2, 0x016c8, 0x016d6, 0x016d7,
+ 0x016d7, 0x016d7, 0x016da, 0x016da, 0x016dc, 0x016dc, 0x016de, 0x016df,
+ 0x016e0, 0x016e1, 0x016e2, 0x016e3, 0x016e4, 0x016e5, 0x016e6, 0x016e6,
+ 0x016e6, 0x016b9, 0x016ca, 0x016eb, 0x016ec, 0x016ed, 0x016ee, 0x016ef,
+ 0x016f0, 0x016f1, 0x016f2, 0x016f3, 0x016f4, 0x016f5, 0x016f6, 0x016f7,
+ 0x016f8, 0x016f9, 0x016fa, 0x016fb, 0x016fc, 0x016fd, 0x016fe, 0x016ff
+};
+
+static uint32_t unicode_520_ci_page_17[] = {
+ 0x01700, 0x01701, 0x01702, 0x01703, 0x01704, 0x01705, 0x01706, 0x01707,
+ 0x01708, 0x01709, 0x0170a, 0x0170b, 0x0170c, 0x0170d, 0x0170e, 0x0170f,
+ 0x01710, 0x01711, 0x01712, 0x01713, 0x01714, 0x01715, 0x01716, 0x01717,
+ 0x01718, 0x01719, 0x0171a, 0x0171b, 0x0171c, 0x0171d, 0x0171e, 0x0171f,
+ 0x01720, 0x01721, 0x01722, 0x01723, 0x01724, 0x01725, 0x01726, 0x01727,
+ 0x01728, 0x01729, 0x0172a, 0x0172b, 0x0172c, 0x0172d, 0x0172e, 0x0172f,
+ 0x01730, 0x01731, 0x01732, 0x01733, 0x01734, 0x01735, 0x01736, 0x01737,
+ 0x01738, 0x01739, 0x0173a, 0x0173b, 0x0173c, 0x0173d, 0x0173e, 0x0173f,
+ 0x01740, 0x01741, 0x01742, 0x01743, 0x01744, 0x01745, 0x01746, 0x01747,
+ 0x01748, 0x01749, 0x0174a, 0x0174b, 0x0174c, 0x0174d, 0x0174e, 0x0174f,
+ 0x01750, 0x01751, 0x01752, 0x01753, 0x01754, 0x01755, 0x01756, 0x01757,
+ 0x01758, 0x01759, 0x0175a, 0x0175b, 0x0175c, 0x0175d, 0x0175e, 0x0175f,
+ 0x01760, 0x01761, 0x01762, 0x01763, 0x01764, 0x01765, 0x01766, 0x01767,
+ 0x01768, 0x01769, 0x0176a, 0x0176b, 0x0176c, 0x0176d, 0x0176e, 0x0176f,
+ 0x01770, 0x01771, 0x01772, 0x01773, 0x01774, 0x01775, 0x01776, 0x01777,
+ 0x01778, 0x01779, 0x0177a, 0x0177b, 0x0177c, 0x0177d, 0x0177e, 0x0177f,
+ 0x01780, 0x01781, 0x01782, 0x01783, 0x01784, 0x01785, 0x01786, 0x01787,
+ 0x01788, 0x01789, 0x0178a, 0x0178b, 0x0178c, 0x0178d, 0x0178e, 0x0178f,
+ 0x01790, 0x01791, 0x01792, 0x01793, 0x01794, 0x01795, 0x01796, 0x01797,
+ 0x01798, 0x01799, 0x0179a, 0x0179b, 0x0179c, 0x0179d, 0x0179e, 0x0179f,
+ 0x017a0, 0x017a1, 0x017a2, 0x017a3, 0x017a4, 0x017a5, 0x017a6, 0x017a7,
+ 0x017a8, 0x017a9, 0x017aa, 0x017ab, 0x017ac, 0x017ad, 0x017ae, 0x017af,
+ 0x017b0, 0x017b1, 0x017b2, 0x017b3, 0x017b4, 0x017b5, 0x017b6, 0x017b7,
+ 0x017b8, 0x017b9, 0x017ba, 0x017bb, 0x017bc, 0x017bd, 0x017be, 0x017bf,
+ 0x017c0, 0x017c1, 0x017c2, 0x017c3, 0x017c4, 0x017c5, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x017d2, 0x00000, 0x017d4, 0x017d5, 0x017d6, 0x017d7,
+ 0x017d8, 0x017d9, 0x017da, 0x017db, 0x017dc, 0x00000, 0x017de, 0x017df,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017ea, 0x017eb, 0x017ec, 0x017ed, 0x017ee, 0x017ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017fa, 0x017fb, 0x017fc, 0x017fd, 0x017fe, 0x017ff
+};
+
+static uint32_t unicode_520_ci_page_18[] = {
+ 0x01800, 0x01801, 0x01802, 0x01803, 0x01804, 0x01805, 0x01806, 0x01807,
+ 0x01808, 0x01809, 0x0180a, 0x00000, 0x00000, 0x00000, 0x0180e, 0x0180f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0181a, 0x0181b, 0x0181c, 0x0181d, 0x0181e, 0x0181f,
+ 0x01820, 0x01821, 0x01822, 0x01823, 0x01824, 0x01825, 0x01826, 0x01827,
+ 0x01828, 0x01829, 0x0182a, 0x0182b, 0x0182c, 0x0182d, 0x0182e, 0x0182f,
+ 0x01830, 0x01831, 0x01832, 0x01833, 0x01834, 0x01835, 0x01836, 0x01837,
+ 0x01838, 0x01839, 0x0183a, 0x0183b, 0x0183c, 0x0183d, 0x0183e, 0x0183f,
+ 0x01840, 0x01841, 0x01842, 0x01843, 0x01844, 0x01845, 0x01846, 0x01847,
+ 0x01848, 0x01849, 0x0184a, 0x0184b, 0x0184c, 0x0184d, 0x0184e, 0x0184f,
+ 0x01850, 0x01851, 0x01852, 0x01853, 0x01854, 0x01855, 0x01856, 0x01857,
+ 0x01858, 0x01859, 0x0185a, 0x0185b, 0x0185c, 0x0185d, 0x0185e, 0x0185f,
+ 0x01860, 0x01861, 0x01862, 0x01863, 0x01864, 0x01865, 0x01866, 0x01867,
+ 0x01868, 0x01869, 0x0186a, 0x0186b, 0x0186c, 0x0186d, 0x0186e, 0x0186f,
+ 0x01870, 0x01871, 0x01872, 0x01873, 0x01874, 0x01875, 0x01876, 0x01877,
+ 0x01878, 0x01879, 0x0187a, 0x0187b, 0x0187c, 0x0187d, 0x0187e, 0x0187f,
+ 0x01880, 0x01881, 0x01882, 0x01883, 0x01884, 0x01885, 0x01886, 0x01887,
+ 0x01888, 0x01889, 0x0188a, 0x0188b, 0x0188c, 0x0188d, 0x0188e, 0x0188f,
+ 0x01890, 0x01891, 0x01892, 0x01893, 0x01894, 0x01895, 0x01896, 0x01897,
+ 0x01898, 0x01899, 0x0189a, 0x0189b, 0x0189c, 0x0189d, 0x0189e, 0x0189f,
+ 0x018a0, 0x018a1, 0x018a2, 0x018a3, 0x018a4, 0x018a5, 0x018a6, 0x018a7,
+ 0x018a8, 0x018a9, 0x018aa, 0x018ab, 0x018ac, 0x018ad, 0x018ae, 0x018af,
+ 0x018b0, 0x018b1, 0x018b2, 0x018b3, 0x018b4, 0x018b5, 0x018b6, 0x018b7,
+ 0x018b8, 0x018b9, 0x018ba, 0x018bb, 0x018bc, 0x018bd, 0x018be, 0x018bf,
+ 0x018c0, 0x018c1, 0x018c2, 0x018c3, 0x018c4, 0x018c5, 0x018c6, 0x018c7,
+ 0x018c8, 0x018c9, 0x018ca, 0x018cb, 0x018cc, 0x018cd, 0x018ce, 0x018cf,
+ 0x018d0, 0x018d1, 0x018d2, 0x018d3, 0x018d4, 0x018d5, 0x018d6, 0x018d7,
+ 0x018d8, 0x018d9, 0x018da, 0x018db, 0x018dc, 0x018dd, 0x018de, 0x018df,
+ 0x018e0, 0x018e1, 0x018e2, 0x018e3, 0x018e4, 0x018e5, 0x018e6, 0x018e7,
+ 0x018e8, 0x018e9, 0x018ea, 0x018eb, 0x018ec, 0x018ed, 0x018ee, 0x018ef,
+ 0x018f0, 0x018f1, 0x018f2, 0x018f3, 0x018f4, 0x018f5, 0x018f6, 0x018f7,
+ 0x018f8, 0x018f9, 0x018fa, 0x018fb, 0x018fc, 0x018fd, 0x018fe, 0x018ff
+};
+
+static uint32_t unicode_520_ci_page_19[] = {
+ 0x01900, 0x01901, 0x01902, 0x01903, 0x01904, 0x01905, 0x01906, 0x01907,
+ 0x01908, 0x01909, 0x0190a, 0x0190b, 0x0190c, 0x0190d, 0x0190e, 0x0190f,
+ 0x01910, 0x01911, 0x01912, 0x01913, 0x01914, 0x01915, 0x01916, 0x01917,
+ 0x01918, 0x01919, 0x0191a, 0x0191b, 0x0191c, 0x0191d, 0x0191e, 0x0191f,
+ 0x01920, 0x01921, 0x01922, 0x01923, 0x01924, 0x01925, 0x01926, 0x01927,
+ 0x01928, 0x01929, 0x0192a, 0x0192b, 0x0192c, 0x0192d, 0x0192e, 0x0192f,
+ 0x01930, 0x01931, 0x01932, 0x01933, 0x01934, 0x01935, 0x01936, 0x01937,
+ 0x01938, 0x00000, 0x00000, 0x00000, 0x0193c, 0x0193d, 0x0193e, 0x0193f,
+ 0x01940, 0x01941, 0x01942, 0x01943, 0x01944, 0x01945, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x01950, 0x01951, 0x01952, 0x01953, 0x01954, 0x01955, 0x01956, 0x01957,
+ 0x01958, 0x01959, 0x0195a, 0x0195b, 0x0195c, 0x0195d, 0x0195e, 0x0195f,
+ 0x01960, 0x01961, 0x01962, 0x01963, 0x01964, 0x01965, 0x01966, 0x01967,
+ 0x01968, 0x01969, 0x0196a, 0x0196b, 0x0196c, 0x0196d, 0x0196e, 0x0196f,
+ 0x01970, 0x01971, 0x01972, 0x01973, 0x01974, 0x01975, 0x01976, 0x01977,
+ 0x01978, 0x01979, 0x0197a, 0x0197b, 0x0197c, 0x0197d, 0x0197e, 0x0197f,
+ 0x01980, 0x01981, 0x01982, 0x01983, 0x01984, 0x01985, 0x01986, 0x01987,
+ 0x01988, 0x01989, 0x0198a, 0x0198b, 0x0198c, 0x0198d, 0x0198e, 0x0198f,
+ 0x01990, 0x01991, 0x01992, 0x01993, 0x01994, 0x01995, 0x01996, 0x01997,
+ 0x01998, 0x01999, 0x0199a, 0x0199b, 0x0199c, 0x0199d, 0x0199e, 0x0199f,
+ 0x019a0, 0x019a1, 0x019a2, 0x019a3, 0x019a4, 0x019a5, 0x019a6, 0x019a7,
+ 0x019a8, 0x019a9, 0x019aa, 0x019ab, 0x019ac, 0x019ad, 0x019ae, 0x019af,
+ 0x019b0, 0x019b1, 0x019b2, 0x019b3, 0x019b4, 0x019b5, 0x019b6, 0x019b7,
+ 0x019b8, 0x019b9, 0x019ba, 0x019bb, 0x019bc, 0x019bd, 0x019be, 0x019bf,
+ 0x019c0, 0x019c1, 0x019c2, 0x019c3, 0x019c4, 0x019c5, 0x019c6, 0x019c7,
+ 0x019c8, 0x019c9, 0x019ca, 0x019cb, 0x019cc, 0x019cd, 0x019ce, 0x019cf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00031, 0x019db, 0x019dc, 0x019dd, 0x019de, 0x019df,
+ 0x019e0, 0x019e1, 0x019e2, 0x019e3, 0x019e4, 0x019e5, 0x019e6, 0x019e7,
+ 0x019e8, 0x019e9, 0x019ea, 0x019eb, 0x019ec, 0x019ed, 0x019ee, 0x019ef,
+ 0x019f0, 0x019f1, 0x019f2, 0x019f3, 0x019f4, 0x019f5, 0x019f6, 0x019f7,
+ 0x019f8, 0x019f9, 0x019fa, 0x019fb, 0x019fc, 0x019fd, 0x019fe, 0x019ff
+};
+
+static uint32_t unicode_520_ci_page_1a[] = {
+ 0x01a00, 0x01a01, 0x01a02, 0x01a03, 0x01a04, 0x01a05, 0x01a06, 0x01a07,
+ 0x01a08, 0x01a09, 0x01a0a, 0x01a0b, 0x01a0c, 0x01a0d, 0x01a0e, 0x01a0f,
+ 0x01a10, 0x01a11, 0x01a12, 0x01a13, 0x01a14, 0x01a15, 0x01a16, 0x01a17,
+ 0x01a18, 0x01a19, 0x01a1a, 0x01a1b, 0x01a1c, 0x01a1d, 0x01a1e, 0x01a1f,
+ 0x01a20, 0x01a21, 0x01a22, 0x01a23, 0x01a24, 0x01a25, 0x01a26, 0x01a27,
+ 0x01a28, 0x01a29, 0x01a2a, 0x01a2b, 0x01a2c, 0x01a2d, 0x01a2e, 0x01a2f,
+ 0x01a30, 0x01a31, 0x01a32, 0x01a33, 0x01a34, 0x01a35, 0x01a36, 0x01a37,
+ 0x01a38, 0x01a39, 0x01a3a, 0x01a3b, 0x01a3c, 0x01a3d, 0x01a3e, 0x01a3f,
+ 0x01a40, 0x01a41, 0x01a42, 0x01a43, 0x01a44, 0x01a45, 0x01a46, 0x01a47,
+ 0x01a48, 0x01a49, 0x01a4a, 0x01a4b, 0x01a4c, 0x01a4d, 0x01a4e, 0x01a4f,
+ 0x01a50, 0x01a51, 0x01a52, 0x01a53, 0x01a54, 0x01a55, 0x01a56, 0x01a57,
+ 0x01a26, 0x01a26, 0x01a3b, 0x01a3b, 0x01a5c, 0x01a5d, 0x01a5e, 0x01a5f,
+ 0x01a60, 0x01a61, 0x01a62, 0x01a63, 0x01a63, 0x01a65, 0x01a66, 0x01a67,
+ 0x01a68, 0x01a69, 0x01a6a, 0x01a6b, 0x01a6c, 0x01a6d, 0x01a6e, 0x01a6f,
+ 0x01a70, 0x01a71, 0x01a72, 0x01a73, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x01a7d, 0x01a7e, 0x00000,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01a8a, 0x01a8b, 0x01a8c, 0x01a8d, 0x01a8e, 0x01a8f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01a9a, 0x01a9b, 0x01a9c, 0x01a9d, 0x01a9e, 0x01a9f,
+ 0x01aa0, 0x01aa1, 0x01aa2, 0x01aa3, 0x01aa4, 0x01aa5, 0x01aa6, 0x01aa7,
+ 0x01aa8, 0x01aa9, 0x01aaa, 0x01aab, 0x01aac, 0x01aad, 0x01aae, 0x01aaf,
+ 0x01ab0, 0x01ab1, 0x01ab2, 0x01ab3, 0x01ab4, 0x01ab5, 0x01ab6, 0x01ab7,
+ 0x01ab8, 0x01ab9, 0x01aba, 0x01abb, 0x01abc, 0x01abd, 0x01abe, 0x01abf,
+ 0x01ac0, 0x01ac1, 0x01ac2, 0x01ac3, 0x01ac4, 0x01ac5, 0x01ac6, 0x01ac7,
+ 0x01ac8, 0x01ac9, 0x01aca, 0x01acb, 0x01acc, 0x01acd, 0x01ace, 0x01acf,
+ 0x01ad0, 0x01ad1, 0x01ad2, 0x01ad3, 0x01ad4, 0x01ad5, 0x01ad6, 0x01ad7,
+ 0x01ad8, 0x01ad9, 0x01ada, 0x01adb, 0x01adc, 0x01add, 0x01ade, 0x01adf,
+ 0x01ae0, 0x01ae1, 0x01ae2, 0x01ae3, 0x01ae4, 0x01ae5, 0x01ae6, 0x01ae7,
+ 0x01ae8, 0x01ae9, 0x01aea, 0x01aeb, 0x01aec, 0x01aed, 0x01aee, 0x01aef,
+ 0x01af0, 0x01af1, 0x01af2, 0x01af3, 0x01af4, 0x01af5, 0x01af6, 0x01af7,
+ 0x01af8, 0x01af9, 0x01afa, 0x01afb, 0x01afc, 0x01afd, 0x01afe, 0x01aff
+};
+
+static uint32_t unicode_520_ci_page_1b[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x01b05, 0x01b06, 0x01b07,
+ 0x01b08, 0x01b09, 0x01b0a, 0x01b0b, 0x01b0c, 0x01b0d, 0x01b0e, 0x01b0f,
+ 0x01b10, 0x01b11, 0x01b12, 0x01b13, 0x01b14, 0x01b15, 0x01b16, 0x01b17,
+ 0x01b18, 0x01b19, 0x01b1a, 0x01b1b, 0x01b1c, 0x01b1d, 0x01b1e, 0x01b1f,
+ 0x01b20, 0x01b21, 0x01b22, 0x01b23, 0x01b24, 0x01b25, 0x01b26, 0x01b27,
+ 0x01b28, 0x01b29, 0x01b2a, 0x01b2b, 0x01b2c, 0x01b2d, 0x01b2e, 0x01b2f,
+ 0x01b30, 0x01b31, 0x01b32, 0x01b33, 0x00000, 0x01b35, 0x01b36, 0x01b37,
+ 0x01b38, 0x01b39, 0x01b3a, 0x01b3b, 0x01b3c, 0x01b3d, 0x01b3e, 0x01b3f,
+ 0x01b40, 0x01b41, 0x01b42, 0x01b43, 0x01b44, 0x01b45, 0x01b46, 0x01b47,
+ 0x01b48, 0x01b49, 0x01b4a, 0x01b4b, 0x01b4c, 0x01b4d, 0x01b4e, 0x01b4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01b5a, 0x01b5b, 0x01b5c, 0x01b5d, 0x01b5e, 0x01b5f,
+ 0x01b60, 0x01b61, 0x01b62, 0x01b63, 0x01b64, 0x01b65, 0x01b66, 0x01b67,
+ 0x01b68, 0x01b69, 0x01b6a, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x01b74, 0x01b75, 0x01b76, 0x01b77,
+ 0x01b78, 0x01b79, 0x01b7a, 0x01b7b, 0x01b7c, 0x01b7d, 0x01b7e, 0x01b7f,
+ 0x00000, 0x00000, 0x00000, 0x01b83, 0x01b84, 0x01b85, 0x01b86, 0x01b87,
+ 0x01b88, 0x01b89, 0x01b8a, 0x01b8b, 0x01b8c, 0x01b8d, 0x01b8e, 0x01b8f,
+ 0x01b90, 0x01b91, 0x01b92, 0x01b93, 0x01b94, 0x01b95, 0x01b96, 0x01b97,
+ 0x01b98, 0x01b99, 0x01b9a, 0x01b9b, 0x01b9c, 0x01b9d, 0x01b9e, 0x01b9f,
+ 0x01ba0, 0x01ba1, 0x01ba2, 0x01ba3, 0x01ba4, 0x01ba5, 0x01ba6, 0x01ba7,
+ 0x01ba8, 0x01ba9, 0x01baa, 0x01bab, 0x01bac, 0x01bad, 0x01bae, 0x01baf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01bba, 0x01bbb, 0x01bbc, 0x01bbd, 0x01bbe, 0x01bbf,
+ 0x01bc0, 0x01bc1, 0x01bc2, 0x01bc3, 0x01bc4, 0x01bc5, 0x01bc6, 0x01bc7,
+ 0x01bc8, 0x01bc9, 0x01bca, 0x01bcb, 0x01bcc, 0x01bcd, 0x01bce, 0x01bcf,
+ 0x01bd0, 0x01bd1, 0x01bd2, 0x01bd3, 0x01bd4, 0x01bd5, 0x01bd6, 0x01bd7,
+ 0x01bd8, 0x01bd9, 0x01bda, 0x01bdb, 0x01bdc, 0x01bdd, 0x01bde, 0x01bdf,
+ 0x01be0, 0x01be1, 0x01be2, 0x01be3, 0x01be4, 0x01be5, 0x01be6, 0x01be7,
+ 0x01be8, 0x01be9, 0x01bea, 0x01beb, 0x01bec, 0x01bed, 0x01bee, 0x01bef,
+ 0x01bf0, 0x01bf1, 0x01bf2, 0x01bf3, 0x01bf4, 0x01bf5, 0x01bf6, 0x01bf7,
+ 0x01bf8, 0x01bf9, 0x01bfa, 0x01bfb, 0x01bfc, 0x01bfd, 0x01bfe, 0x01bff
+};
+
+static uint32_t unicode_520_ci_page_1c[] = {
+ 0x01c00, 0x01c01, 0x01c02, 0x01c03, 0x01c04, 0x01c05, 0x01c06, 0x01c07,
+ 0x01c08, 0x01c09, 0x01c0a, 0x01c0b, 0x01c0c, 0x01c0d, 0x01c0e, 0x01c0f,
+ 0x01c10, 0x01c11, 0x01c12, 0x01c13, 0x01c14, 0x01c15, 0x01c16, 0x01c17,
+ 0x01c18, 0x01c19, 0x01c1a, 0x01c1b, 0x01c1c, 0x01c1d, 0x01c1e, 0x01c1f,
+ 0x01c20, 0x01c21, 0x01c22, 0x01c23, 0x01c24, 0x01c25, 0x01c26, 0x01c27,
+ 0x01c28, 0x01c29, 0x01c2a, 0x01c2b, 0x01c2c, 0x01c2d, 0x01c2e, 0x01c2f,
+ 0x01c30, 0x01c31, 0x01c32, 0x01c33, 0x01c34, 0x01c35, 0x01c36, 0x00000,
+ 0x01c38, 0x01c39, 0x01c3a, 0x01c3b, 0x01c3c, 0x01c3d, 0x01c3e, 0x01c3f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01c4a, 0x01c4b, 0x01c4c, 0x01c4d, 0x01c4e, 0x01c4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01c5a, 0x01c5b, 0x01c5c, 0x01c5d, 0x01c5e, 0x01c5f,
+ 0x01c60, 0x01c61, 0x01c62, 0x01c63, 0x01c64, 0x01c65, 0x01c66, 0x01c67,
+ 0x01c68, 0x01c69, 0x01c6a, 0x01c6b, 0x01c6c, 0x01c6d, 0x01c6e, 0x01c6f,
+ 0x01c70, 0x01c71, 0x01c72, 0x01c73, 0x01c74, 0x01c75, 0x01c76, 0x01c77,
+ 0x01c78, 0x01c79, 0x01c7a, 0x01c7b, 0x01c7c, 0x01c7d, 0x01c7e, 0x01c7f,
+ 0x01c80, 0x01c81, 0x01c82, 0x01c83, 0x01c84, 0x01c85, 0x01c86, 0x01c87,
+ 0x01c88, 0x01c89, 0x01c8a, 0x01c8b, 0x01c8c, 0x01c8d, 0x01c8e, 0x01c8f,
+ 0x01c90, 0x01c91, 0x01c92, 0x01c93, 0x01c94, 0x01c95, 0x01c96, 0x01c97,
+ 0x01c98, 0x01c99, 0x01c9a, 0x01c9b, 0x01c9c, 0x01c9d, 0x01c9e, 0x01c9f,
+ 0x01ca0, 0x01ca1, 0x01ca2, 0x01ca3, 0x01ca4, 0x01ca5, 0x01ca6, 0x01ca7,
+ 0x01ca8, 0x01ca9, 0x01caa, 0x01cab, 0x01cac, 0x01cad, 0x01cae, 0x01caf,
+ 0x01cb0, 0x01cb1, 0x01cb2, 0x01cb3, 0x01cb4, 0x01cb5, 0x01cb6, 0x01cb7,
+ 0x01cb8, 0x01cb9, 0x01cba, 0x01cbb, 0x01cbc, 0x01cbd, 0x01cbe, 0x01cbf,
+ 0x01cc0, 0x01cc1, 0x01cc2, 0x01cc3, 0x01cc4, 0x01cc5, 0x01cc6, 0x01cc7,
+ 0x01cc8, 0x01cc9, 0x01cca, 0x01ccb, 0x01ccc, 0x01ccd, 0x01cce, 0x01ccf,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x01ce9, 0x01ce9, 0x01ce9, 0x01ce9, 0x00000, 0x01ce9, 0x01ce9,
+ 0x01ce9, 0x01ce9, 0x00000, 0x01cf3, 0x01cf4, 0x01cf5, 0x01cf6, 0x01cf7,
+ 0x01cf8, 0x01cf9, 0x01cfa, 0x01cfb, 0x01cfc, 0x01cfd, 0x01cfe, 0x01cff
+};
+
+static uint32_t unicode_520_ci_page_1d[] = {
+ 0x01d00, 0x01d01, 0x01d02, 0x01d03, 0x01d04, 0x01d05, 0x01d06, 0x01d07,
+ 0x01d08, 0x01d09, 0x01d0a, 0x01d0b, 0x01d0c, 0x01d0d, 0x01d0e, 0x01d0f,
+ 0x01d10, 0x01d11, 0x01d12, 0x01d13, 0x01d14, 0x01d15, 0x01d16, 0x01d17,
+ 0x01d18, 0x01d19, 0x01d1a, 0x01d1b, 0x01d1c, 0x01d1d, 0x01d1e, 0x01d1f,
+ 0x01d20, 0x01d21, 0x01d22, 0x01d23, 0x01d24, 0x01d25, 0x01d26, 0x01d27,
+ 0x01d28, 0x01d29, 0x01d2a, 0x01d2b, 0x00041, 0x000c6, 0x00042, 0x01d2f,
+ 0x00044, 0x00045, 0x0018e, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b,
+ 0x0004c, 0x0004d, 0x0004e, 0x01d3b, 0x0004f, 0x00222, 0x00050, 0x00052,
+ 0x00054, 0x00055, 0x00057, 0x00041, 0x00250, 0x00251, 0x01d02, 0x00042,
+ 0x00044, 0x00045, 0x0018f, 0x00190, 0x01d08, 0x00047, 0x01d09, 0x0004b,
+ 0x0004d, 0x0014a, 0x0004f, 0x00186, 0x01d16, 0x01d17, 0x00050, 0x00054,
+ 0x00055, 0x01d1d, 0x0019c, 0x00056, 0x01d25, 0x00392, 0x00393, 0x00394,
+ 0x003a6, 0x003a7, 0x00049, 0x00052, 0x00055, 0x00056, 0x00392, 0x00393,
+ 0x003a1, 0x003a6, 0x003a7, 0x01d6b, 0x01d6c, 0x01d6d, 0x01d6e, 0x01d6f,
+ 0x01d70, 0x01d71, 0x01d72, 0x01d73, 0x01d74, 0x01d75, 0x01d76, 0x01d77,
+ 0x0041d, 0x00047, 0x01d7a, 0x01d7b, 0x01d7c, 0x01d7d, 0x01d7e, 0x01d7f,
+ 0x01d80, 0x01d81, 0x01d82, 0x01d83, 0x01d84, 0x01d85, 0x01d86, 0x01d87,
+ 0x01d88, 0x01d89, 0x01d8a, 0x01d8b, 0x01d8c, 0x01d8d, 0x01d8e, 0x01d8f,
+ 0x01d90, 0x01d91, 0x01d92, 0x01d93, 0x01d94, 0x01d95, 0x01d96, 0x01d97,
+ 0x01d98, 0x01d99, 0x01d9a, 0x00252, 0x00043, 0x00255, 0x00044, 0x0025c,
+ 0x00046, 0x0025f, 0x00261, 0x00265, 0x00197, 0x00196, 0x0026a, 0x01d7b,
+ 0x0029d, 0x0026d, 0x01d85, 0x0029f, 0x00271, 0x00270, 0x0019d, 0x00273,
+ 0x00274, 0x0019f, 0x00278, 0x00282, 0x001a9, 0x001ab, 0x00244, 0x001b1,
+ 0x01d1c, 0x001b2, 0x00245, 0x0005a, 0x00290, 0x00291, 0x001b7, 0x00398,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00052, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x01dd2, 0x00041, 0x000c6, 0x01dd5, 0x01dd6, 0x00043,
+ 0x00044, 0x00044, 0x00047, 0x00262, 0x0004b, 0x0004c, 0x0029f, 0x01d0d,
+ 0x0004e, 0x00274, 0x001a6, 0x01de3, 0x00053, 0x00053, 0x0005a, 0x01de7,
+ 0x01de8, 0x01de9, 0x01dea, 0x01deb, 0x01dec, 0x01ded, 0x01dee, 0x01def,
+ 0x01df0, 0x01df1, 0x01df2, 0x01df3, 0x01df4, 0x01df5, 0x01df6, 0x01df7,
+ 0x01df8, 0x01df9, 0x01dfa, 0x01dfb, 0x01dfc, 0x00000, 0x00000, 0x01dff
+};
+
+static uint32_t unicode_520_ci_page_1e[] = {
+ 0x00041, 0x00041, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042,
+ 0x00043, 0x00043, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00046, 0x00046,
+ 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00048, 0x00048, 0x00048, 0x00048, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004d, 0x0004d,
+ 0x0004d, 0x0004d, 0x0004d, 0x0004d, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00050, 0x00050, 0x00050, 0x00050,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054,
+ 0x00054, 0x00054, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00056, 0x00056, 0x00056, 0x00056,
+ 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057,
+ 0x00057, 0x00057, 0x00058, 0x00058, 0x00058, 0x00058, 0x00059, 0x00059,
+ 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00048, 0x00054,
+ 0x00057, 0x00059, 0x01e9a, 0x00053, 0x01e9c, 0x01e9d, 0x000df, 0x01e9f,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059,
+ 0x00059, 0x00059, 0x01efa, 0x01efa, 0x01efc, 0x01efc, 0x01efe, 0x01eff
+};
+
+static uint32_t unicode_520_ci_page_1f[] = {
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f16, 0x01f17,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f1e, 0x01f1f,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f46, 0x01f47,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f4e, 0x01f4f,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5,
+ 0x01f58, 0x003a5, 0x01f5a, 0x003a5, 0x01f5c, 0x003a5, 0x01f5e, 0x003a5,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00395, 0x00395, 0x00397, 0x00397, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x003a5, 0x003a5, 0x003a9, 0x003a9, 0x01f7e, 0x01f7f,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fb5, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fbd, 0x00399, 0x01fbd,
+ 0x01fc0, 0x000a8, 0x00397, 0x00397, 0x00397, 0x01fc5, 0x00397, 0x00397,
+ 0x00395, 0x00395, 0x00397, 0x00397, 0x00397, 0x01fbd, 0x01fbd, 0x01fbd,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fd4, 0x01fd5, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fdc, 0x01fdd, 0x01fdd, 0x01fdd,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x003a1, 0x003a5, 0x003a5,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x000a8, 0x000a8, 0x00060,
+ 0x01ff0, 0x01ff1, 0x003a9, 0x003a9, 0x003a9, 0x01ff5, 0x003a9, 0x003a9,
+ 0x0039f, 0x0039f, 0x003a9, 0x003a9, 0x003a9, 0x000b4, 0x01fdd, 0x01fff
+};
+
+static uint32_t unicode_520_ci_page_20[] = {
+ 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020,
+ 0x00020, 0x00020, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x02010, 0x02010, 0x02012, 0x02013, 0x02014, 0x02015, 0x02016, 0x02017,
+ 0x02018, 0x02019, 0x0201a, 0x0201b, 0x0201c, 0x0201d, 0x0201e, 0x0201f,
+ 0x02020, 0x02021, 0x02022, 0x02023, 0x0002e, 0x02025, 0x02026, 0x02027,
+ 0x02028, 0x02029, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00020,
+ 0x02030, 0x02031, 0x02032, 0x02033, 0x02034, 0x02035, 0x02036, 0x02037,
+ 0x02038, 0x02039, 0x0203a, 0x0203b, 0x0203c, 0x0203d, 0x0203e, 0x0203f,
+ 0x02040, 0x02041, 0x02042, 0x02043, 0x02044, 0x02045, 0x02046, 0x02047,
+ 0x02048, 0x02049, 0x0204a, 0x0204b, 0x0204c, 0x0204d, 0x0204e, 0x0204f,
+ 0x02050, 0x02051, 0x02052, 0x02053, 0x02054, 0x02055, 0x02056, 0x02057,
+ 0x02058, 0x02059, 0x0205a, 0x0205b, 0x0205c, 0x0205d, 0x0205e, 0x00020,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x02065, 0x02066, 0x02067,
+ 0x02068, 0x02069, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00030, 0x00049, 0x02072, 0x02073, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0004e,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0208f,
+ 0x00041, 0x00045, 0x0004f, 0x00058, 0x0018f, 0x02095, 0x02096, 0x02097,
+ 0x02098, 0x02099, 0x0209a, 0x0209b, 0x0209c, 0x0209d, 0x0209e, 0x0209f,
+ 0x020a0, 0x020a1, 0x020a2, 0x020a3, 0x020a4, 0x020a5, 0x020a6, 0x020a7,
+ 0x020a8, 0x020a9, 0x020aa, 0x020ab, 0x020ac, 0x020ad, 0x020ae, 0x020af,
+ 0x020b0, 0x020b1, 0x020b2, 0x020b3, 0x020b4, 0x020b5, 0x020b6, 0x020b7,
+ 0x020b8, 0x020b9, 0x020ba, 0x020bb, 0x020bc, 0x020bd, 0x020be, 0x020bf,
+ 0x020c0, 0x020c1, 0x020c2, 0x020c3, 0x020c4, 0x020c5, 0x020c6, 0x020c7,
+ 0x020c8, 0x020c9, 0x020ca, 0x020cb, 0x020cc, 0x020cd, 0x020ce, 0x020cf,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x020f1, 0x020f2, 0x020f3, 0x020f4, 0x020f5, 0x020f6, 0x020f7,
+ 0x020f8, 0x020f9, 0x020fa, 0x020fb, 0x020fc, 0x020fd, 0x020fe, 0x020ff
+};
+
+static uint32_t unicode_520_ci_page_21[] = {
+ 0x02100, 0x02101, 0x00043, 0x02103, 0x02104, 0x02105, 0x02106, 0x00190,
+ 0x02108, 0x02109, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00049, 0x00049, 0x0004c, 0x0004c, 0x02114, 0x0004e, 0x02116, 0x02117,
+ 0x02118, 0x00050, 0x00051, 0x00052, 0x00052, 0x00052, 0x0211e, 0x0211f,
+ 0x02120, 0x02121, 0x02122, 0x02123, 0x0005a, 0x02125, 0x003a9, 0x02127,
+ 0x0005a, 0x02129, 0x0004b, 0x00041, 0x00042, 0x00043, 0x0212e, 0x00045,
+ 0x00045, 0x00046, 0x02132, 0x0004d, 0x0004f, 0x005d0, 0x005d1, 0x005d2,
+ 0x005d3, 0x00049, 0x0213a, 0x0213b, 0x003a0, 0x00393, 0x00393, 0x003a0,
+ 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x00044, 0x00044, 0x00045,
+ 0x00049, 0x0004a, 0x0214a, 0x0214b, 0x0214c, 0x0214d, 0x02132, 0x0214f,
+ 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157,
+ 0x02158, 0x02159, 0x0215a, 0x0215b, 0x0215c, 0x0215d, 0x0215e, 0x0215f,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x02180, 0x02181, 0x02182, 0x02183, 0x02183, 0x00036, 0x02186, 0x02187,
+ 0x02188, 0x02189, 0x0218a, 0x0218b, 0x0218c, 0x0218d, 0x0218e, 0x0218f,
+ 0x02190, 0x02191, 0x02192, 0x02193, 0x02194, 0x02195, 0x02196, 0x02197,
+ 0x02198, 0x02199, 0x02190, 0x02192, 0x0219c, 0x0219d, 0x0219e, 0x0219f,
+ 0x021a0, 0x021a1, 0x021a2, 0x021a3, 0x021a4, 0x021a5, 0x021a6, 0x021a7,
+ 0x021a8, 0x021a9, 0x021aa, 0x021ab, 0x021ac, 0x021ad, 0x02194, 0x021af,
+ 0x021b0, 0x021b1, 0x021b2, 0x021b3, 0x021b4, 0x021b5, 0x021b6, 0x021b7,
+ 0x021b8, 0x021b9, 0x021ba, 0x021bb, 0x021bc, 0x021bd, 0x021be, 0x021bf,
+ 0x021c0, 0x021c1, 0x021c2, 0x021c3, 0x021c4, 0x021c5, 0x021c6, 0x021c7,
+ 0x021c8, 0x021c9, 0x021ca, 0x021cb, 0x021cc, 0x021cd, 0x021ce, 0x021cf,
+ 0x021cd, 0x021d1, 0x021cf, 0x021d3, 0x021ce, 0x021d5, 0x021d6, 0x021d7,
+ 0x021d8, 0x021d9, 0x021da, 0x021db, 0x021dc, 0x021dd, 0x021de, 0x021df,
+ 0x021e0, 0x021e1, 0x021e2, 0x021e3, 0x021e4, 0x021e5, 0x021e6, 0x021e7,
+ 0x021e8, 0x021e9, 0x021ea, 0x021eb, 0x021ec, 0x021ed, 0x021ee, 0x021ef,
+ 0x021f0, 0x021f1, 0x021f2, 0x021f3, 0x021f4, 0x021f5, 0x021f6, 0x021f7,
+ 0x021f8, 0x021f9, 0x021fa, 0x021fb, 0x021fc, 0x021fd, 0x021fe, 0x021ff
+};
+
+static uint32_t unicode_520_ci_page_22[] = {
+ 0x02200, 0x02201, 0x02202, 0x02203, 0x02203, 0x02205, 0x02206, 0x02207,
+ 0x02208, 0x02208, 0x0220a, 0x0220b, 0x0220b, 0x0220d, 0x0220e, 0x0220f,
+ 0x02210, 0x02140, 0x0207b, 0x02213, 0x02214, 0x02215, 0x02216, 0x02217,
+ 0x02218, 0x02219, 0x0221a, 0x0221b, 0x0221c, 0x0221d, 0x0221e, 0x0221f,
+ 0x02220, 0x02221, 0x02222, 0x02223, 0x02223, 0x02225, 0x02225, 0x02227,
+ 0x02228, 0x02229, 0x0222a, 0x0222b, 0x0222c, 0x0222d, 0x0222e, 0x0222f,
+ 0x02230, 0x02231, 0x02232, 0x02233, 0x02234, 0x02235, 0x02236, 0x02237,
+ 0x02238, 0x02239, 0x0223a, 0x0223b, 0x0223c, 0x0223d, 0x0223e, 0x0223f,
+ 0x02240, 0x0223c, 0x02242, 0x02243, 0x02243, 0x02245, 0x02246, 0x02245,
+ 0x02248, 0x02248, 0x0224a, 0x0224b, 0x0224c, 0x0224d, 0x0224e, 0x0224f,
+ 0x02250, 0x02251, 0x02252, 0x02253, 0x02254, 0x02255, 0x02256, 0x02257,
+ 0x02258, 0x02259, 0x0225a, 0x0225b, 0x0225c, 0x0225d, 0x0225e, 0x0225f,
+ 0x0003d, 0x02261, 0x02261, 0x02263, 0x02264, 0x02265, 0x02266, 0x02267,
+ 0x02268, 0x02269, 0x0226a, 0x0226b, 0x0226c, 0x0224d, 0x0003c, 0x0003e,
+ 0x02264, 0x02265, 0x02272, 0x02273, 0x02272, 0x02273, 0x02276, 0x02277,
+ 0x02276, 0x02277, 0x0227a, 0x0227b, 0x0227c, 0x0227d, 0x0227e, 0x0227f,
+ 0x0227a, 0x0227b, 0x02282, 0x02283, 0x02282, 0x02283, 0x02286, 0x02287,
+ 0x02286, 0x02287, 0x0228a, 0x0228b, 0x0228c, 0x0228d, 0x0228e, 0x0228f,
+ 0x02290, 0x02291, 0x02292, 0x02293, 0x02294, 0x02295, 0x02296, 0x02297,
+ 0x02298, 0x02299, 0x0229a, 0x0229b, 0x0229c, 0x0229d, 0x0229e, 0x0229f,
+ 0x022a0, 0x022a1, 0x022a2, 0x022a3, 0x022a4, 0x022a5, 0x022a6, 0x022a7,
+ 0x022a8, 0x022a9, 0x022aa, 0x022ab, 0x022a2, 0x022a8, 0x022a9, 0x022ab,
+ 0x022b0, 0x022b1, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022b6, 0x022b7,
+ 0x022b8, 0x022b9, 0x022ba, 0x022bb, 0x022bc, 0x022bd, 0x022be, 0x022bf,
+ 0x022c0, 0x022c1, 0x022c2, 0x022c3, 0x022c4, 0x022c5, 0x022c6, 0x022c7,
+ 0x022c8, 0x022c9, 0x022ca, 0x022cb, 0x022cc, 0x022cd, 0x022ce, 0x022cf,
+ 0x022d0, 0x022d1, 0x022d2, 0x022d3, 0x022d4, 0x022d5, 0x022d6, 0x022d7,
+ 0x022d8, 0x022d9, 0x022da, 0x022db, 0x022dc, 0x022dd, 0x022de, 0x022df,
+ 0x0227c, 0x0227d, 0x02291, 0x02292, 0x022e4, 0x022e5, 0x022e6, 0x022e7,
+ 0x022e8, 0x022e9, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022ee, 0x022ef,
+ 0x022f0, 0x022f1, 0x022f2, 0x022f3, 0x022f4, 0x022f5, 0x022f6, 0x022f7,
+ 0x022f8, 0x022f9, 0x022fa, 0x022fb, 0x022fc, 0x022fd, 0x022fe, 0x022ff
+};
+
+static uint32_t unicode_520_ci_page_24[] = {
+ 0x02400, 0x02401, 0x02402, 0x02403, 0x02404, 0x02405, 0x02406, 0x02407,
+ 0x02408, 0x02409, 0x0240a, 0x0240b, 0x0240c, 0x0240d, 0x0240e, 0x0240f,
+ 0x02410, 0x02411, 0x02412, 0x02413, 0x02414, 0x02415, 0x02416, 0x02417,
+ 0x02418, 0x02419, 0x0241a, 0x0241b, 0x0241c, 0x0241d, 0x0241e, 0x0241f,
+ 0x02420, 0x02421, 0x02422, 0x02423, 0x02424, 0x02425, 0x02426, 0x02427,
+ 0x02428, 0x02429, 0x0242a, 0x0242b, 0x0242c, 0x0242d, 0x0242e, 0x0242f,
+ 0x02430, 0x02431, 0x02432, 0x02433, 0x02434, 0x02435, 0x02436, 0x02437,
+ 0x02438, 0x02439, 0x0243a, 0x0243b, 0x0243c, 0x0243d, 0x0243e, 0x0243f,
+ 0x02440, 0x02441, 0x02442, 0x02443, 0x02444, 0x02445, 0x02446, 0x02447,
+ 0x02448, 0x02449, 0x0244a, 0x0244b, 0x0244c, 0x0244d, 0x0244e, 0x0244f,
+ 0x02450, 0x02451, 0x02452, 0x02453, 0x02454, 0x02455, 0x02456, 0x02457,
+ 0x02458, 0x02459, 0x0245a, 0x0245b, 0x0245c, 0x0245d, 0x0245e, 0x0245f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e, 0x0246f,
+ 0x02470, 0x02471, 0x02472, 0x02473, 0x02474, 0x02475, 0x02476, 0x02477,
+ 0x02478, 0x02479, 0x0247a, 0x0247b, 0x0247c, 0x0247d, 0x0247e, 0x0247f,
+ 0x02480, 0x02481, 0x02482, 0x02483, 0x02484, 0x02485, 0x02486, 0x02487,
+ 0x02488, 0x02489, 0x0248a, 0x0248b, 0x0248c, 0x0248d, 0x0248e, 0x0248f,
+ 0x02490, 0x02491, 0x02492, 0x02493, 0x02494, 0x02495, 0x02496, 0x02497,
+ 0x02498, 0x02499, 0x0249a, 0x0249b, 0x0249c, 0x0249d, 0x0249e, 0x0249f,
+ 0x024a0, 0x024a1, 0x024a2, 0x024a3, 0x024a4, 0x024a5, 0x024a6, 0x024a7,
+ 0x024a8, 0x024a9, 0x024aa, 0x024ab, 0x024ac, 0x024ad, 0x024ae, 0x024af,
+ 0x024b0, 0x024b1, 0x024b2, 0x024b3, 0x024b4, 0x024b5, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00030, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e,
+ 0x0246f, 0x02470, 0x02471, 0x02472, 0x02473, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469, 0x024ff
+};
+
+static uint32_t unicode_520_ci_page_27[] = {
+ 0x02700, 0x02701, 0x02702, 0x02703, 0x02704, 0x02705, 0x02706, 0x02707,
+ 0x02708, 0x02709, 0x0270a, 0x0270b, 0x0270c, 0x0270d, 0x0270e, 0x0270f,
+ 0x02710, 0x02711, 0x02712, 0x02713, 0x02714, 0x02715, 0x02716, 0x02717,
+ 0x02718, 0x02719, 0x0271a, 0x0271b, 0x0271c, 0x0271d, 0x0271e, 0x0271f,
+ 0x02720, 0x02721, 0x02722, 0x02723, 0x02724, 0x02725, 0x02726, 0x02727,
+ 0x02728, 0x02729, 0x0272a, 0x0272b, 0x0272c, 0x0272d, 0x0272e, 0x0272f,
+ 0x02730, 0x02731, 0x02732, 0x02733, 0x02734, 0x02735, 0x02736, 0x02737,
+ 0x02738, 0x02739, 0x0273a, 0x0273b, 0x0273c, 0x0273d, 0x0273e, 0x0273f,
+ 0x02740, 0x02741, 0x02742, 0x02743, 0x02744, 0x02745, 0x02746, 0x02747,
+ 0x02748, 0x02749, 0x0274a, 0x0274b, 0x0274c, 0x0274d, 0x0274e, 0x0274f,
+ 0x02750, 0x02751, 0x02752, 0x02753, 0x02754, 0x02755, 0x02756, 0x02757,
+ 0x02758, 0x02759, 0x0275a, 0x0275b, 0x0275c, 0x0275d, 0x0275e, 0x0275f,
+ 0x02760, 0x02761, 0x02762, 0x02763, 0x02764, 0x02765, 0x02766, 0x02767,
+ 0x02768, 0x02769, 0x0276a, 0x0276b, 0x0276c, 0x0276d, 0x0276e, 0x0276f,
+ 0x02770, 0x02771, 0x02772, 0x02773, 0x02774, 0x02775, 0x00031, 0x00032,
+ 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x02469, 0x02794, 0x02795, 0x02796, 0x02797,
+ 0x02798, 0x02799, 0x0279a, 0x0279b, 0x0279c, 0x0279d, 0x0279e, 0x0279f,
+ 0x027a0, 0x027a1, 0x027a2, 0x027a3, 0x027a4, 0x027a5, 0x027a6, 0x027a7,
+ 0x027a8, 0x027a9, 0x027aa, 0x027ab, 0x027ac, 0x027ad, 0x027ae, 0x027af,
+ 0x027b0, 0x027b1, 0x027b2, 0x027b3, 0x027b4, 0x027b5, 0x027b6, 0x027b7,
+ 0x027b8, 0x027b9, 0x027ba, 0x027bb, 0x027bc, 0x027bd, 0x027be, 0x027bf,
+ 0x027c0, 0x027c1, 0x027c2, 0x027c3, 0x027c4, 0x027c5, 0x027c6, 0x027c7,
+ 0x027c8, 0x027c9, 0x027ca, 0x027cb, 0x027cc, 0x027cd, 0x027ce, 0x027cf,
+ 0x027d0, 0x027d1, 0x027d2, 0x027d3, 0x027d4, 0x027d5, 0x027d6, 0x027d7,
+ 0x027d8, 0x027d9, 0x027da, 0x027db, 0x027dc, 0x027dd, 0x027de, 0x027df,
+ 0x027e0, 0x027e1, 0x027e2, 0x027e3, 0x027e4, 0x027e5, 0x027e6, 0x027e7,
+ 0x027e8, 0x027e9, 0x027ea, 0x027eb, 0x027ec, 0x027ed, 0x027ee, 0x027ef,
+ 0x027f0, 0x027f1, 0x027f2, 0x027f3, 0x027f4, 0x027f5, 0x027f6, 0x027f7,
+ 0x027f8, 0x027f9, 0x027fa, 0x027fb, 0x027fc, 0x027fd, 0x027fe, 0x027ff
+};
+
+static uint32_t unicode_520_ci_page_2a[] = {
+ 0x02a00, 0x02a01, 0x02a02, 0x02a03, 0x02a04, 0x02a05, 0x02a06, 0x02a07,
+ 0x02a08, 0x02a09, 0x02a0a, 0x02a0b, 0x02a0c, 0x02a0d, 0x02a0e, 0x02a0f,
+ 0x02a10, 0x02a11, 0x02a12, 0x02a13, 0x02a14, 0x02a15, 0x02a16, 0x02a17,
+ 0x02a18, 0x02a19, 0x02a1a, 0x02a1b, 0x02a1c, 0x02a1d, 0x02a1e, 0x02a1f,
+ 0x02a20, 0x02a21, 0x02a22, 0x02a23, 0x02a24, 0x02a25, 0x02a26, 0x02a27,
+ 0x02a28, 0x02a29, 0x02a2a, 0x02a2b, 0x02a2c, 0x02a2d, 0x02a2e, 0x02a2f,
+ 0x02a30, 0x02a31, 0x02a32, 0x02a33, 0x02a34, 0x02a35, 0x02a36, 0x02a37,
+ 0x02a38, 0x02a39, 0x02a3a, 0x02a3b, 0x02a3c, 0x02a3d, 0x02a3e, 0x02a3f,
+ 0x02a40, 0x02a41, 0x02a42, 0x02a43, 0x02a44, 0x02a45, 0x02a46, 0x02a47,
+ 0x02a48, 0x02a49, 0x02a4a, 0x02a4b, 0x02a4c, 0x02a4d, 0x02a4e, 0x02a4f,
+ 0x02a50, 0x02a51, 0x02a52, 0x02a53, 0x02a54, 0x02a55, 0x02a56, 0x02a57,
+ 0x02a58, 0x02a59, 0x02a5a, 0x02a5b, 0x02a5c, 0x02a5d, 0x02a5e, 0x02a5f,
+ 0x02a60, 0x02a61, 0x02a62, 0x02a63, 0x02a64, 0x02a65, 0x02a66, 0x02a67,
+ 0x02a68, 0x02a69, 0x02a6a, 0x02a6b, 0x02a6c, 0x02a6d, 0x02a6e, 0x02a6f,
+ 0x02a70, 0x02a71, 0x02a72, 0x02a73, 0x02a74, 0x02a75, 0x02a76, 0x02a77,
+ 0x02a78, 0x02a79, 0x02a7a, 0x02a7b, 0x02a7c, 0x02a7d, 0x02a7e, 0x02a7f,
+ 0x02a80, 0x02a81, 0x02a82, 0x02a83, 0x02a84, 0x02a85, 0x02a86, 0x02a87,
+ 0x02a88, 0x02a89, 0x02a8a, 0x02a8b, 0x02a8c, 0x02a8d, 0x02a8e, 0x02a8f,
+ 0x02a90, 0x02a91, 0x02a92, 0x02a93, 0x02a94, 0x02a95, 0x02a96, 0x02a97,
+ 0x02a98, 0x02a99, 0x02a9a, 0x02a9b, 0x02a9c, 0x02a9d, 0x02a9e, 0x02a9f,
+ 0x02aa0, 0x02aa1, 0x02aa2, 0x02aa3, 0x02aa4, 0x02aa5, 0x02aa6, 0x02aa7,
+ 0x02aa8, 0x02aa9, 0x02aaa, 0x02aab, 0x02aac, 0x02aad, 0x02aae, 0x02aaf,
+ 0x02ab0, 0x02ab1, 0x02ab2, 0x02ab3, 0x02ab4, 0x02ab5, 0x02ab6, 0x02ab7,
+ 0x02ab8, 0x02ab9, 0x02aba, 0x02abb, 0x02abc, 0x02abd, 0x02abe, 0x02abf,
+ 0x02ac0, 0x02ac1, 0x02ac2, 0x02ac3, 0x02ac4, 0x02ac5, 0x02ac6, 0x02ac7,
+ 0x02ac8, 0x02ac9, 0x02aca, 0x02acb, 0x02acc, 0x02acd, 0x02ace, 0x02acf,
+ 0x02ad0, 0x02ad1, 0x02ad2, 0x02ad3, 0x02ad4, 0x02ad5, 0x02ad6, 0x02ad7,
+ 0x02ad8, 0x02ad9, 0x02ada, 0x02adb, 0x02adc, 0x02adc, 0x02ade, 0x02adf,
+ 0x02ae0, 0x02ae1, 0x02ae2, 0x02ae3, 0x02ae4, 0x02ae5, 0x02ae6, 0x02ae7,
+ 0x02ae8, 0x02ae9, 0x02aea, 0x02aeb, 0x02aec, 0x02aed, 0x02aee, 0x02aef,
+ 0x02af0, 0x02af1, 0x02af2, 0x02af3, 0x02af4, 0x02af5, 0x02af6, 0x02af7,
+ 0x02af8, 0x02af9, 0x02afa, 0x02afb, 0x02afc, 0x02afd, 0x02afe, 0x02aff
+};
+
+static uint32_t unicode_520_ci_page_2c[] = {
+ 0x02c00, 0x02c01, 0x02c02, 0x02c03, 0x02c04, 0x02c05, 0x02c06, 0x02c07,
+ 0x02c08, 0x02c09, 0x02c0a, 0x02c0b, 0x02c0c, 0x02c0d, 0x02c0e, 0x02c0f,
+ 0x02c10, 0x02c11, 0x02c12, 0x02c13, 0x02c14, 0x02c15, 0x02c16, 0x02c17,
+ 0x02c18, 0x02c19, 0x02c1a, 0x02c1b, 0x02c1c, 0x02c1d, 0x02c1e, 0x02c1f,
+ 0x02c20, 0x02c21, 0x02c22, 0x02c23, 0x02c24, 0x02c25, 0x02c26, 0x02c27,
+ 0x02c28, 0x02c29, 0x02c2a, 0x02c2b, 0x02c2c, 0x02c2d, 0x02c2e, 0x02c2f,
+ 0x02c00, 0x02c01, 0x02c02, 0x02c03, 0x02c04, 0x02c05, 0x02c06, 0x02c07,
+ 0x02c08, 0x02c09, 0x02c0a, 0x02c0b, 0x02c0c, 0x02c0d, 0x02c0e, 0x02c0f,
+ 0x02c10, 0x02c11, 0x02c12, 0x02c13, 0x02c14, 0x02c15, 0x02c16, 0x02c17,
+ 0x02c18, 0x02c19, 0x02c1a, 0x02c1b, 0x02c1c, 0x02c1d, 0x02c1e, 0x02c1f,
+ 0x02c20, 0x02c21, 0x02c22, 0x02c23, 0x02c24, 0x02c25, 0x02c26, 0x02c27,
+ 0x02c28, 0x02c29, 0x02c2a, 0x02c2b, 0x02c2c, 0x02c2d, 0x02c2e, 0x02c5f,
+ 0x02c60, 0x02c60, 0x0026b, 0x01d7d, 0x0027d, 0x0023a, 0x0023e, 0x02c67,
+ 0x02c67, 0x02c69, 0x02c69, 0x02c6b, 0x02c6b, 0x00251, 0x00271, 0x00250,
+ 0x00252, 0x02c71, 0x02c72, 0x02c72, 0x02c74, 0x02c75, 0x02c75, 0x02c77,
+ 0x02c78, 0x02c79, 0x02c7a, 0x02c7b, 0x0004a, 0x00056, 0x0023f, 0x00240,
+ 0x02c80, 0x02c80, 0x02c82, 0x02c82, 0x02c84, 0x02c84, 0x02c86, 0x02c86,
+ 0x02c88, 0x02c88, 0x02c8a, 0x02c8a, 0x02c8c, 0x02c8c, 0x02c8e, 0x02c8e,
+ 0x02c90, 0x02c90, 0x02c92, 0x02c92, 0x02c94, 0x02c94, 0x02c96, 0x02c96,
+ 0x02c98, 0x02c98, 0x02c9a, 0x02c9a, 0x02c9c, 0x02c9c, 0x02c9e, 0x02c9e,
+ 0x02ca0, 0x02ca0, 0x02ca2, 0x02ca2, 0x02ca4, 0x02ca4, 0x02ca6, 0x02ca6,
+ 0x02ca8, 0x02ca8, 0x02caa, 0x02caa, 0x02cac, 0x02cac, 0x02cae, 0x02cae,
+ 0x02cb0, 0x02cb0, 0x02cb2, 0x02cb2, 0x02cb4, 0x02cb4, 0x02cb6, 0x02cb6,
+ 0x02cb8, 0x02cb8, 0x02cba, 0x02cba, 0x02cbc, 0x02cbc, 0x02cbe, 0x02cbe,
+ 0x02cc0, 0x02cc0, 0x02cc2, 0x02cc2, 0x02cc4, 0x02cc4, 0x02cc6, 0x02cc6,
+ 0x02cc8, 0x02cc8, 0x02cca, 0x02cca, 0x02ccc, 0x02ccc, 0x02cce, 0x02cce,
+ 0x02cd0, 0x02cd0, 0x02cd2, 0x02cd2, 0x02cd4, 0x02cd4, 0x02cd6, 0x02cd6,
+ 0x02cd8, 0x02cd8, 0x02cda, 0x02cda, 0x02cdc, 0x02cdc, 0x02cde, 0x02cde,
+ 0x02ce0, 0x02ce0, 0x02ce2, 0x02ce2, 0x02ce4, 0x02ce5, 0x02ce6, 0x02ce7,
+ 0x02ce8, 0x02ce9, 0x02cea, 0x02ceb, 0x02ceb, 0x02ced, 0x02ced, 0x00000,
+ 0x00000, 0x00000, 0x02cf2, 0x02cf3, 0x02cf4, 0x02cf5, 0x02cf6, 0x02cf7,
+ 0x02cf8, 0x02cf9, 0x02cfa, 0x02cfb, 0x02cfc, 0x02cfd, 0x02cfe, 0x02cff
+};
+
+static uint32_t unicode_520_ci_page_2d[] = {
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x02d26, 0x02d27,
+ 0x02d28, 0x02d29, 0x02d2a, 0x02d2b, 0x02d2c, 0x02d2d, 0x02d2e, 0x02d2f,
+ 0x02d30, 0x02d31, 0x02d32, 0x02d33, 0x02d34, 0x02d35, 0x02d36, 0x02d37,
+ 0x02d38, 0x02d39, 0x02d3a, 0x02d3b, 0x02d3c, 0x02d3d, 0x02d3e, 0x02d3f,
+ 0x02d40, 0x02d41, 0x02d42, 0x02d43, 0x02d44, 0x02d45, 0x02d46, 0x02d47,
+ 0x02d48, 0x02d49, 0x02d4a, 0x02d4b, 0x02d4c, 0x02d4d, 0x02d4e, 0x02d4f,
+ 0x02d50, 0x02d51, 0x02d52, 0x02d53, 0x02d54, 0x02d55, 0x02d56, 0x02d57,
+ 0x02d58, 0x02d59, 0x02d5a, 0x02d5b, 0x02d5c, 0x02d5d, 0x02d5e, 0x02d5f,
+ 0x02d60, 0x02d61, 0x02d62, 0x02d63, 0x02d64, 0x02d65, 0x02d66, 0x02d67,
+ 0x02d68, 0x02d69, 0x02d6a, 0x02d6b, 0x02d6c, 0x02d6d, 0x02d6e, 0x02d6f,
+ 0x02d70, 0x02d71, 0x02d72, 0x02d73, 0x02d74, 0x02d75, 0x02d76, 0x02d77,
+ 0x02d78, 0x02d79, 0x02d7a, 0x02d7b, 0x02d7c, 0x02d7d, 0x02d7e, 0x02d7f,
+ 0x02d80, 0x02d81, 0x02d82, 0x02d83, 0x02d84, 0x02d85, 0x02d86, 0x02d87,
+ 0x02d88, 0x02d89, 0x02d8a, 0x02d8b, 0x02d8c, 0x02d8d, 0x02d8e, 0x02d8f,
+ 0x02d90, 0x02d91, 0x02d92, 0x02d93, 0x02d94, 0x02d95, 0x02d96, 0x02d97,
+ 0x02d98, 0x02d99, 0x02d9a, 0x02d9b, 0x02d9c, 0x02d9d, 0x02d9e, 0x02d9f,
+ 0x02da0, 0x02da1, 0x02da2, 0x02da3, 0x02da4, 0x02da5, 0x02da6, 0x02da7,
+ 0x02da8, 0x02da9, 0x02daa, 0x02dab, 0x02dac, 0x02dad, 0x02dae, 0x02daf,
+ 0x02db0, 0x02db1, 0x02db2, 0x02db3, 0x02db4, 0x02db5, 0x02db6, 0x02db7,
+ 0x02db8, 0x02db9, 0x02dba, 0x02dbb, 0x02dbc, 0x02dbd, 0x02dbe, 0x02dbf,
+ 0x02dc0, 0x02dc1, 0x02dc2, 0x02dc3, 0x02dc4, 0x02dc5, 0x02dc6, 0x02dc7,
+ 0x02dc8, 0x02dc9, 0x02dca, 0x02dcb, 0x02dcc, 0x02dcd, 0x02dce, 0x02dcf,
+ 0x02dd0, 0x02dd1, 0x02dd2, 0x02dd3, 0x02dd4, 0x02dd5, 0x02dd6, 0x02dd7,
+ 0x02dd8, 0x02dd9, 0x02dda, 0x02ddb, 0x02ddc, 0x02ddd, 0x02dde, 0x02ddf,
+ 0x00411, 0x00412, 0x00413, 0x00414, 0x00416, 0x00417, 0x0041a, 0x0041b,
+ 0x0041c, 0x0041d, 0x0041e, 0x0041f, 0x00420, 0x00421, 0x00422, 0x00425,
+ 0x00426, 0x00427, 0x00428, 0x00429, 0x00472, 0x02df5, 0x00410, 0x00400,
+ 0x02df8, 0x02df9, 0x00462, 0x0042e, 0x02dfc, 0x00466, 0x0046a, 0x02dff
+};
+
+static uint32_t unicode_520_ci_page_2e[] = {
+ 0x02e00, 0x02e01, 0x02e02, 0x02e03, 0x02e04, 0x02e05, 0x02e06, 0x02e07,
+ 0x02e08, 0x02e09, 0x02e0a, 0x02e0b, 0x02e0c, 0x02e0d, 0x02e0e, 0x02e0f,
+ 0x02e10, 0x02e11, 0x02e12, 0x02e13, 0x02e14, 0x02e15, 0x02e16, 0x02e17,
+ 0x02e18, 0x02e19, 0x02e1a, 0x02e1b, 0x02e1c, 0x02e1d, 0x02e1e, 0x02e1f,
+ 0x02e20, 0x02e21, 0x02e22, 0x02e23, 0x02e24, 0x02e25, 0x02e26, 0x02e27,
+ 0x02e28, 0x02e29, 0x02e2a, 0x02e2b, 0x02e2c, 0x02e2d, 0x02e2e, 0x02e2f,
+ 0x02e30, 0x02e31, 0x02e32, 0x02e33, 0x02e34, 0x02e35, 0x02e36, 0x02e37,
+ 0x02e38, 0x02e39, 0x02e3a, 0x02e3b, 0x02e3c, 0x02e3d, 0x02e3e, 0x02e3f,
+ 0x02e40, 0x02e41, 0x02e42, 0x02e43, 0x02e44, 0x02e45, 0x02e46, 0x02e47,
+ 0x02e48, 0x02e49, 0x02e4a, 0x02e4b, 0x02e4c, 0x02e4d, 0x02e4e, 0x02e4f,
+ 0x02e50, 0x02e51, 0x02e52, 0x02e53, 0x02e54, 0x02e55, 0x02e56, 0x02e57,
+ 0x02e58, 0x02e59, 0x02e5a, 0x02e5b, 0x02e5c, 0x02e5d, 0x02e5e, 0x02e5f,
+ 0x02e60, 0x02e61, 0x02e62, 0x02e63, 0x02e64, 0x02e65, 0x02e66, 0x02e67,
+ 0x02e68, 0x02e69, 0x02e6a, 0x02e6b, 0x02e6c, 0x02e6d, 0x02e6e, 0x02e6f,
+ 0x02e70, 0x02e71, 0x02e72, 0x02e73, 0x02e74, 0x02e75, 0x02e76, 0x02e77,
+ 0x02e78, 0x02e79, 0x02e7a, 0x02e7b, 0x02e7c, 0x02e7d, 0x02e7e, 0x02e7f,
+ 0x02e80, 0x02e81, 0x02e82, 0x02e83, 0x0319a, 0x02e85, 0x02e86, 0x02f0f,
+ 0x02f11, 0x02e89, 0x02f18, 0x02e8b, 0x02f29, 0x02f29, 0x02e8e, 0x02e8f,
+ 0x02e8e, 0x02e8f, 0x02e92, 0x02e93, 0x02e94, 0x02e95, 0x02e96, 0x02f3c,
+ 0x02e98, 0x02e99, 0x02e9a, 0x02e9b, 0x02f47, 0x02f49, 0x02e9e, 0x02e9f,
+ 0x02ea0, 0x02ea1, 0x02ea2, 0x02ea3, 0x02ea4, 0x02ea4, 0x02ea6, 0x02f5c,
+ 0x02ea8, 0x02ea9, 0x02eaa, 0x02f6c, 0x02f70, 0x02ead, 0x02f75, 0x02eaf,
+ 0x02eb0, 0x02eb1, 0x02eb2, 0x02eb1, 0x02eb1, 0x02eb2, 0x02eb7, 0x02eb7,
+ 0x02eb8, 0x02eb9, 0x02eba, 0x02f80, 0x02f81, 0x02f85, 0x02ebe, 0x02ebe,
+ 0x02ebe, 0x02ec1, 0x02ec2, 0x02ec3, 0x02ec4, 0x02ec5, 0x02f93, 0x02f93,
+ 0x02ec8, 0x02ec9, 0x02f9c, 0x02ecb, 0x02ecc, 0x02ecc, 0x02ecc, 0x02fa2,
+ 0x02ed0, 0x02fa7, 0x02ed2, 0x02ed3, 0x02ed4, 0x02fa9, 0x02ed6, 0x02fac,
+ 0x02ed8, 0x02ed9, 0x02eda, 0x02edb, 0x02edc, 0x02fb7, 0x02ede, 0x02ede,
+ 0x02ee0, 0x02fb8, 0x02ee2, 0x02fbb, 0x02fc1, 0x02ee5, 0x02ee6, 0x02ee7,
+ 0x02ee8, 0x02ee9, 0x02eea, 0x02eeb, 0x02eec, 0x02eed, 0x02eee, 0x02eef,
+ 0x02ef0, 0x02ef2, 0x02ef2, 0x02ef3, 0x02ef4, 0x02ef5, 0x02ef6, 0x02ef7,
+ 0x02ef8, 0x02ef9, 0x02efa, 0x02efb, 0x02efc, 0x02efd, 0x02efe, 0x02eff
+};
+
+static uint32_t unicode_520_ci_page_2f[] = {
+ 0x03192, 0x02f01, 0x02e80, 0x02f03, 0x0319a, 0x02f05, 0x03193, 0x02f07,
+ 0x0319f, 0x02f09, 0x02f0a, 0x02f0b, 0x02e86, 0x02f0d, 0x02f0e, 0x02f0f,
+ 0x02f10, 0x02f11, 0x02f12, 0x02f13, 0x02f14, 0x02f15, 0x02f16, 0x02f17,
+ 0x02f18, 0x02e8b, 0x02e81, 0x02f1b, 0x02f1c, 0x02f1d, 0x02f1e, 0x02f1f,
+ 0x02f20, 0x02f21, 0x02f22, 0x02f23, 0x02f24, 0x02f25, 0x02f26, 0x02f27,
+ 0x02f28, 0x02f29, 0x02e8e, 0x02f2b, 0x02f2c, 0x02f2d, 0x02f2e, 0x02f2f,
+ 0x02f30, 0x02f31, 0x02f32, 0x02e93, 0x02f34, 0x02f35, 0x02f36, 0x02f37,
+ 0x02f38, 0x02e95, 0x02f3a, 0x02f3b, 0x02f3c, 0x02f3d, 0x02f3e, 0x02f3f,
+ 0x02f40, 0x02f41, 0x02f42, 0x02f43, 0x02f44, 0x02f45, 0x02f46, 0x02f47,
+ 0x02f48, 0x02f49, 0x02f4a, 0x02f4b, 0x02f4c, 0x02f4d, 0x02f4e, 0x02f4f,
+ 0x02f50, 0x02f51, 0x02f52, 0x02f53, 0x02f54, 0x02f55, 0x02f56, 0x02f57,
+ 0x02f58, 0x02f59, 0x02f5a, 0x02f5b, 0x02f5c, 0x02f5d, 0x02f5e, 0x02f5f,
+ 0x02f60, 0x02f61, 0x02f62, 0x02f63, 0x02f64, 0x02f65, 0x02eaa, 0x02f67,
+ 0x02f68, 0x02f69, 0x02f6a, 0x02f6b, 0x02f6c, 0x02f6d, 0x02f6e, 0x02f6f,
+ 0x02f70, 0x02f71, 0x02f72, 0x02f73, 0x02f74, 0x02f75, 0x02f76, 0x02f77,
+ 0x02f78, 0x02f79, 0x02eb7, 0x02f7b, 0x02f7c, 0x02f7d, 0x02f7e, 0x02f7f,
+ 0x02f80, 0x02f81, 0x02f82, 0x02f83, 0x02f84, 0x02f85, 0x02f86, 0x02f87,
+ 0x02f88, 0x02f89, 0x02f8a, 0x02f8b, 0x02f8c, 0x02f8d, 0x02f8e, 0x02f8f,
+ 0x02f90, 0x02f91, 0x02f92, 0x02f93, 0x02f94, 0x02f95, 0x02f96, 0x02f97,
+ 0x02f98, 0x02f99, 0x02f9a, 0x02f9b, 0x02f9c, 0x02f9d, 0x02f9e, 0x02f9f,
+ 0x02fa0, 0x02fa1, 0x02fa2, 0x02fa3, 0x02fa4, 0x02fa5, 0x02fa6, 0x02fa7,
+ 0x02fa8, 0x02fa9, 0x02faa, 0x02fab, 0x02fac, 0x02fad, 0x02fae, 0x02faf,
+ 0x02fb0, 0x02fb1, 0x02fb2, 0x02fb3, 0x02fb4, 0x02fb5, 0x02fb6, 0x02fb7,
+ 0x02fb8, 0x02fb9, 0x02fba, 0x02fbb, 0x02fbc, 0x02fbd, 0x02fbe, 0x02fbf,
+ 0x02fc0, 0x02fc1, 0x02fc2, 0x02fc3, 0x02ee7, 0x02fc5, 0x02fc6, 0x02fc7,
+ 0x02fc8, 0x02fc9, 0x02fca, 0x02fcb, 0x02fcc, 0x02fcd, 0x02fce, 0x02fcf,
+ 0x02fd0, 0x02eeb, 0x02eed, 0x02eef, 0x02ef2, 0x02fd5, 0x02fd6, 0x02fd7,
+ 0x02fd8, 0x02fd9, 0x02fda, 0x02fdb, 0x02fdc, 0x02fdd, 0x02fde, 0x02fdf,
+ 0x02fe0, 0x02fe1, 0x02fe2, 0x02fe3, 0x02fe4, 0x02fe5, 0x02fe6, 0x02fe7,
+ 0x02fe8, 0x02fe9, 0x02fea, 0x02feb, 0x02fec, 0x02fed, 0x02fee, 0x02fef,
+ 0x02ff0, 0x02ff1, 0x02ff2, 0x02ff3, 0x02ff4, 0x02ff5, 0x02ff6, 0x02ff7,
+ 0x02ff8, 0x02ff9, 0x02ffa, 0x02ffb, 0x02ffc, 0x02ffd, 0x02ffe, 0x02fff
+};
+
+static uint32_t unicode_520_ci_page_30[] = {
+ 0x00020, 0x03001, 0x03002, 0x03003, 0x03004, 0x03005, 0x03006, 0x00030,
+ 0x02329, 0x0232a, 0x0300a, 0x0300b, 0x0300c, 0x0300d, 0x0300e, 0x0300f,
+ 0x03010, 0x03011, 0x03012, 0x03013, 0x03014, 0x03015, 0x03016, 0x03017,
+ 0x03018, 0x03019, 0x0301a, 0x0301b, 0x0301c, 0x0301d, 0x0301e, 0x0301f,
+ 0x03020, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x03030, 0x03031, 0x03031, 0x03033, 0x03033, 0x03035, 0x03012, 0x03037,
+ 0x02f17, 0x03039, 0x0303a, 0x0303b, 0x0303c, 0x0303d, 0x0303e, 0x0303f,
+ 0x03040, 0x03042, 0x03042, 0x03044, 0x03044, 0x03046, 0x03046, 0x03048,
+ 0x03048, 0x0304a, 0x0304a, 0x0304b, 0x0304b, 0x0304d, 0x0304d, 0x0304f,
+ 0x0304f, 0x03051, 0x03051, 0x03053, 0x03053, 0x03055, 0x03055, 0x03057,
+ 0x03057, 0x03059, 0x03059, 0x0305b, 0x0305b, 0x0305d, 0x0305d, 0x0305f,
+ 0x0305f, 0x03061, 0x03061, 0x03064, 0x03064, 0x03064, 0x03066, 0x03066,
+ 0x03068, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x0306f, 0x0306f, 0x03072, 0x03072, 0x03072, 0x03075, 0x03075, 0x03075,
+ 0x03078, 0x03078, 0x03078, 0x0307b, 0x0307b, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03084, 0x03086, 0x03086, 0x03088,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x03097,
+ 0x03098, 0x00000, 0x00000, 0x0309b, 0x0309c, 0x0309d, 0x0309d, 0x0309f,
+ 0x030a0, 0x03042, 0x03042, 0x03044, 0x03044, 0x03046, 0x03046, 0x03048,
+ 0x03048, 0x0304a, 0x0304a, 0x0304b, 0x0304b, 0x0304d, 0x0304d, 0x0304f,
+ 0x0304f, 0x03051, 0x03051, 0x03053, 0x03053, 0x03055, 0x03055, 0x03057,
+ 0x03057, 0x03059, 0x03059, 0x0305b, 0x0305b, 0x0305d, 0x0305d, 0x0305f,
+ 0x0305f, 0x03061, 0x03061, 0x03064, 0x03064, 0x03064, 0x03066, 0x03066,
+ 0x03068, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x0306f, 0x0306f, 0x03072, 0x03072, 0x03072, 0x03075, 0x03075, 0x03075,
+ 0x03078, 0x03078, 0x03078, 0x0307b, 0x0307b, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03084, 0x03086, 0x03086, 0x03088,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x030fb, 0x030fc, 0x030fd, 0x030fd, 0x030ff
+};
+
+static uint32_t unicode_520_ci_page_31[] = {
+ 0x03100, 0x03101, 0x03102, 0x03103, 0x03104, 0x03105, 0x03106, 0x03107,
+ 0x03108, 0x03109, 0x0310a, 0x0310b, 0x0310c, 0x0310d, 0x0310e, 0x0310f,
+ 0x03110, 0x03111, 0x03112, 0x03113, 0x03114, 0x03115, 0x03116, 0x03117,
+ 0x03118, 0x03119, 0x0311a, 0x0311b, 0x0311c, 0x0311d, 0x0311e, 0x0311f,
+ 0x03120, 0x03121, 0x03122, 0x03123, 0x03124, 0x03125, 0x03126, 0x03127,
+ 0x03128, 0x03129, 0x0312a, 0x0312b, 0x0312c, 0x0312d, 0x0312e, 0x0312f,
+ 0x03130, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x01161,
+ 0x01162, 0x01163, 0x01164, 0x01165, 0x01166, 0x01167, 0x01168, 0x01169,
+ 0x0116a, 0x0116b, 0x0116c, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171,
+ 0x01172, 0x01173, 0x01174, 0x01175, 0x01160, 0x01114, 0x01115, 0x011c7,
+ 0x011c8, 0x011cc, 0x011ce, 0x011d3, 0x011d7, 0x011d9, 0x0111c, 0x011dd,
+ 0x011df, 0x0111d, 0x0111e, 0x01120, 0x01122, 0x01123, 0x01127, 0x01129,
+ 0x0112b, 0x0112c, 0x0112d, 0x0112e, 0x0112f, 0x01132, 0x01136, 0x01140,
+ 0x01147, 0x0114c, 0x011f1, 0x011f2, 0x01157, 0x01158, 0x01159, 0x01184,
+ 0x01185, 0x01188, 0x01191, 0x01192, 0x01194, 0x0119e, 0x011a1, 0x0318f,
+ 0x03190, 0x03191, 0x03192, 0x03193, 0x03194, 0x03195, 0x03196, 0x03197,
+ 0x03198, 0x03199, 0x0319a, 0x0319b, 0x0319c, 0x0319d, 0x0319e, 0x0319f,
+ 0x03105, 0x03117, 0x03110, 0x0310d, 0x031a4, 0x031a4, 0x031a6, 0x0311b,
+ 0x03128, 0x0311a, 0x03127, 0x03128, 0x031ac, 0x031ad, 0x0311e, 0x03120,
+ 0x031b0, 0x031b1, 0x031b2, 0x03127, 0x03106, 0x0310a, 0x0310e, 0x0310f,
+ 0x031b8, 0x031b9, 0x031ba, 0x031bb, 0x031bc, 0x031bd, 0x031be, 0x031bf,
+ 0x031c0, 0x031c1, 0x031c2, 0x031c3, 0x031c4, 0x031c5, 0x031c6, 0x031c7,
+ 0x031c8, 0x031c9, 0x031ca, 0x031cb, 0x031cc, 0x031cd, 0x031ce, 0x031cf,
+ 0x031d0, 0x031d1, 0x031d2, 0x031d3, 0x031d4, 0x031d5, 0x031d6, 0x031d7,
+ 0x031d8, 0x031d9, 0x031da, 0x031db, 0x031dc, 0x031dd, 0x031de, 0x031df,
+ 0x031e0, 0x031e1, 0x031e2, 0x031e3, 0x031e4, 0x031e5, 0x031e6, 0x031e7,
+ 0x031e8, 0x031e9, 0x031ea, 0x031eb, 0x031ec, 0x031ed, 0x031ee, 0x031ef,
+ 0x0304f, 0x03057, 0x03059, 0x03068, 0x0306c, 0x0306f, 0x03072, 0x03075,
+ 0x03078, 0x0307b, 0x03080, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x031ff
+};
+
+static uint32_t unicode_520_ci_page_32[] = {
+ 0x03200, 0x03201, 0x03202, 0x03203, 0x03204, 0x03205, 0x03206, 0x03207,
+ 0x03208, 0x03209, 0x0320a, 0x0320b, 0x0320c, 0x0320d, 0x0320e, 0x0320f,
+ 0x03210, 0x03211, 0x03212, 0x03213, 0x03214, 0x03215, 0x03216, 0x03217,
+ 0x03218, 0x03219, 0x0321a, 0x0321b, 0x0321c, 0x0321d, 0x0321e, 0x0321f,
+ 0x03220, 0x03221, 0x03222, 0x03223, 0x03224, 0x03225, 0x03226, 0x03227,
+ 0x03228, 0x03229, 0x0322a, 0x0322b, 0x0322c, 0x0322d, 0x0322e, 0x0322f,
+ 0x03230, 0x03231, 0x03232, 0x03233, 0x03234, 0x03235, 0x03236, 0x03237,
+ 0x03238, 0x03239, 0x0323a, 0x0323b, 0x0323c, 0x0323d, 0x0323e, 0x0323f,
+ 0x03240, 0x03241, 0x03242, 0x03243, 0x03244, 0x03245, 0x02f42, 0x03247,
+ 0x02469, 0x02473, 0x0324a, 0x0324b, 0x0324c, 0x0324d, 0x0324e, 0x0324f,
+ 0x03250, 0x03251, 0x03252, 0x03253, 0x03254, 0x03255, 0x03256, 0x03257,
+ 0x03258, 0x03259, 0x0324a, 0x0325b, 0x0325c, 0x0325d, 0x0325e, 0x0325f,
+ 0x01100, 0x01102, 0x01103, 0x01105, 0x01106, 0x01107, 0x01109, 0x0110b,
+ 0x0110c, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0326e, 0x0326f,
+ 0x03270, 0x03271, 0x03272, 0x03273, 0x03274, 0x03275, 0x03276, 0x03277,
+ 0x03278, 0x03279, 0x0327a, 0x0327b, 0x0327c, 0x0327d, 0x0327e, 0x0327f,
+ 0x03192, 0x03193, 0x03194, 0x03195, 0x03284, 0x03285, 0x03286, 0x02f0b,
+ 0x03288, 0x02f17, 0x02f49, 0x02f55, 0x02f54, 0x02f4a, 0x02fa6, 0x02f1f,
+ 0x02f47, 0x03291, 0x03292, 0x03293, 0x03294, 0x03295, 0x03296, 0x03297,
+ 0x03298, 0x03299, 0x0329a, 0x02f25, 0x0329c, 0x0329d, 0x0329e, 0x0329f,
+ 0x032a0, 0x032a1, 0x032a2, 0x032a3, 0x03196, 0x03197, 0x03198, 0x032a7,
+ 0x032a8, 0x032a9, 0x032aa, 0x032ab, 0x032ac, 0x032ad, 0x032ae, 0x032af,
+ 0x032b0, 0x032b1, 0x032b2, 0x032b3, 0x032b4, 0x0324b, 0x032b6, 0x032b7,
+ 0x032b8, 0x032b9, 0x032ba, 0x032bb, 0x032bc, 0x032bd, 0x032be, 0x0324c,
+ 0x032c0, 0x032c1, 0x032c2, 0x032c3, 0x032c4, 0x032c5, 0x032c6, 0x032c7,
+ 0x032c8, 0x032c9, 0x032ca, 0x032cb, 0x032cc, 0x032cd, 0x032ce, 0x032cf,
+ 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d, 0x0304f,
+ 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d, 0x0305f,
+ 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d,
+ 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089, 0x0308a,
+ 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03090, 0x03091, 0x03092, 0x032ff
+};
+
+static uint32_t unicode_520_ci_page_33[] = {
+ 0x03300, 0x03301, 0x03302, 0x03303, 0x03304, 0x03305, 0x03306, 0x03307,
+ 0x03308, 0x03309, 0x0330a, 0x0330b, 0x0330c, 0x0330d, 0x0330e, 0x0330f,
+ 0x03310, 0x03311, 0x03312, 0x03313, 0x03314, 0x03315, 0x03316, 0x03317,
+ 0x03318, 0x03319, 0x0331a, 0x0331b, 0x0331c, 0x0331d, 0x0331e, 0x0331f,
+ 0x03320, 0x03321, 0x03322, 0x03323, 0x03324, 0x03325, 0x03326, 0x03327,
+ 0x03328, 0x03329, 0x0332a, 0x0332b, 0x0332c, 0x0332d, 0x0332e, 0x0332f,
+ 0x03330, 0x03331, 0x03332, 0x03333, 0x03334, 0x03335, 0x03336, 0x03337,
+ 0x03338, 0x03339, 0x0333a, 0x0333b, 0x0333c, 0x0333d, 0x0333e, 0x0333f,
+ 0x03340, 0x03341, 0x03342, 0x03343, 0x03344, 0x03345, 0x03346, 0x03347,
+ 0x03348, 0x03349, 0x0334a, 0x0334b, 0x0334c, 0x0334d, 0x0334e, 0x0334f,
+ 0x03350, 0x03351, 0x03352, 0x03353, 0x03354, 0x03355, 0x03356, 0x03357,
+ 0x03358, 0x03359, 0x0335a, 0x0335b, 0x0335c, 0x0335d, 0x0335e, 0x0335f,
+ 0x03360, 0x03361, 0x03362, 0x03363, 0x03364, 0x03365, 0x03366, 0x03367,
+ 0x03368, 0x03369, 0x0336a, 0x0336b, 0x0336c, 0x0336d, 0x0336e, 0x0336f,
+ 0x03370, 0x03371, 0x03372, 0x03373, 0x03374, 0x03375, 0x03376, 0x03377,
+ 0x03378, 0x03379, 0x0337a, 0x0337b, 0x0337c, 0x0337d, 0x0337e, 0x0337f,
+ 0x03380, 0x03381, 0x03382, 0x03383, 0x03384, 0x03385, 0x03386, 0x03387,
+ 0x03388, 0x03389, 0x0338a, 0x0338b, 0x0338c, 0x0338d, 0x0338e, 0x0338f,
+ 0x03390, 0x03391, 0x03392, 0x03393, 0x03394, 0x03395, 0x03396, 0x03397,
+ 0x03398, 0x03399, 0x0339a, 0x0339b, 0x0339c, 0x0339d, 0x0339e, 0x0339f,
+ 0x033a0, 0x033a1, 0x033a2, 0x033a3, 0x033a4, 0x033a5, 0x033a6, 0x033a7,
+ 0x033a8, 0x03380, 0x033aa, 0x033ab, 0x033ac, 0x033ad, 0x033ae, 0x033af,
+ 0x033b0, 0x033b1, 0x033b2, 0x033b3, 0x033b4, 0x033b5, 0x033b6, 0x033b7,
+ 0x033b8, 0x033b7, 0x033ba, 0x033bb, 0x033bc, 0x033bd, 0x033be, 0x033bd,
+ 0x033c0, 0x033c1, 0x033c2, 0x033c3, 0x033c4, 0x033c5, 0x033c6, 0x033c7,
+ 0x00238, 0x033c9, 0x033ca, 0x033cb, 0x033cc, 0x033cd, 0x0339e, 0x033cf,
+ 0x033d0, 0x033d1, 0x033d2, 0x033d3, 0x03386, 0x033d5, 0x033d6, 0x033d7,
+ 0x033d8, 0x033d9, 0x033da, 0x033db, 0x033dc, 0x033dd, 0x033de, 0x033df,
+ 0x033e0, 0x033e1, 0x033e2, 0x033e3, 0x033e4, 0x033e5, 0x033e6, 0x033e7,
+ 0x033e8, 0x033e9, 0x033ea, 0x033eb, 0x033ec, 0x033ed, 0x033ee, 0x033ef,
+ 0x033f0, 0x033f1, 0x033f2, 0x033f3, 0x033f4, 0x033f5, 0x033f6, 0x033f7,
+ 0x033f8, 0x033f9, 0x033fa, 0x033fb, 0x033fc, 0x033fd, 0x033fe, 0x033ff
+};
+
+static uint32_t unicode_520_ci_page_a6[] = {
+ 0x0a600, 0x0a601, 0x0a602, 0x0a603, 0x0a604, 0x0a605, 0x0a606, 0x0a607,
+ 0x0a608, 0x0a609, 0x0a60a, 0x0a60b, 0x0a60c, 0x0a60d, 0x0a60e, 0x0a60f,
+ 0x0a558, 0x0a56a, 0x0a587, 0x0a613, 0x0a614, 0x0a615, 0x0a616, 0x0a617,
+ 0x0a618, 0x0a619, 0x0a61a, 0x0a61b, 0x0a61c, 0x0a61d, 0x0a61e, 0x0a61f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a56e, 0x0a5d1, 0x0a62c, 0x0a62d, 0x0a62e, 0x0a62f,
+ 0x0a630, 0x0a631, 0x0a632, 0x0a633, 0x0a634, 0x0a635, 0x0a636, 0x0a637,
+ 0x0a638, 0x0a639, 0x0a63a, 0x0a63b, 0x0a63c, 0x0a63d, 0x0a63e, 0x0a63f,
+ 0x0a640, 0x0a640, 0x0a642, 0x0a642, 0x0a644, 0x0a644, 0x0a646, 0x0a646,
+ 0x02df8, 0x02df8, 0x02df9, 0x02df9, 0x0a64c, 0x0a64c, 0x0a64e, 0x0a64e,
+ 0x0a650, 0x0a650, 0x0a652, 0x0a652, 0x0a654, 0x0a654, 0x02dfc, 0x02dfc,
+ 0x0a658, 0x0a658, 0x0a65a, 0x0a65a, 0x0a65c, 0x0a65c, 0x0a65e, 0x0a65e,
+ 0x0a660, 0x0a661, 0x0a662, 0x0a662, 0x0a664, 0x0a664, 0x0a666, 0x0a666,
+ 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x0041e, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0a673, 0x0a674, 0x0a675, 0x0a676, 0x0a677,
+ 0x0a678, 0x0a679, 0x0a67a, 0x0a67b, 0x00000, 0x00000, 0x0a67e, 0x0a67f,
+ 0x0a680, 0x0a680, 0x0a682, 0x0a682, 0x0a684, 0x0a684, 0x0a686, 0x0a686,
+ 0x0a688, 0x0a688, 0x0a68a, 0x0a68a, 0x0a68c, 0x0a68c, 0x0a68e, 0x0a68e,
+ 0x0a690, 0x0a690, 0x0a692, 0x0a692, 0x0a694, 0x0a694, 0x0a696, 0x0a696,
+ 0x0a698, 0x0a699, 0x0a69a, 0x0a69b, 0x0a69c, 0x0a69d, 0x0a69e, 0x0a69f,
+ 0x0a6a0, 0x0a6a1, 0x0a6a2, 0x0a6a3, 0x0a6a4, 0x0a6a5, 0x0a6a6, 0x0a6a7,
+ 0x0a6a8, 0x0a6a9, 0x0a6aa, 0x0a6ab, 0x0a6ac, 0x0a6ad, 0x0a6ae, 0x0a6af,
+ 0x0a6b0, 0x0a6b1, 0x0a6b2, 0x0a6b3, 0x0a6b4, 0x0a6b5, 0x0a6b6, 0x0a6b7,
+ 0x0a6b8, 0x0a6b9, 0x0a6ba, 0x0a6bb, 0x0a6bc, 0x0a6bd, 0x0a6be, 0x0a6bf,
+ 0x0a6c0, 0x0a6c1, 0x0a6c2, 0x0a6c3, 0x0a6c4, 0x0a6c5, 0x0a6c6, 0x0a6c7,
+ 0x0a6c8, 0x0a6c9, 0x0a6ca, 0x0a6cb, 0x0a6cc, 0x0a6cd, 0x0a6ce, 0x0a6cf,
+ 0x0a6d0, 0x0a6d1, 0x0a6d2, 0x0a6d3, 0x0a6d4, 0x0a6d5, 0x0a6d6, 0x0a6d7,
+ 0x0a6d8, 0x0a6d9, 0x0a6da, 0x0a6db, 0x0a6dc, 0x0a6dd, 0x0a6de, 0x0a6df,
+ 0x0a6e0, 0x0a6e1, 0x0a6e2, 0x0a6e3, 0x0a6e4, 0x0a6e5, 0x0a6e6, 0x0a6e7,
+ 0x0a6e8, 0x0a6e9, 0x0a6ea, 0x0a6eb, 0x0a6ec, 0x0a6ed, 0x0a6ee, 0x0a6ef,
+ 0x00000, 0x00000, 0x0a6f2, 0x0a6f3, 0x0a6f4, 0x0a6f5, 0x0a6f6, 0x0a6f7,
+ 0x0a6f8, 0x0a6f9, 0x0a6fa, 0x0a6fb, 0x0a6fc, 0x0a6fd, 0x0a6fe, 0x0a6ff
+};
+
+static uint32_t unicode_520_ci_page_a7[] = {
+ 0x0a700, 0x0a701, 0x0a702, 0x0a703, 0x0a704, 0x0a705, 0x0a706, 0x0a707,
+ 0x0a708, 0x0a709, 0x0a70a, 0x0a70b, 0x0a70c, 0x0a70d, 0x0a70e, 0x0a70f,
+ 0x0a710, 0x0a711, 0x0a712, 0x0a713, 0x0a714, 0x0a715, 0x0a716, 0x0a717,
+ 0x0a718, 0x0a719, 0x0a71a, 0x0a71b, 0x0a71c, 0x0a71d, 0x0a71e, 0x0a71f,
+ 0x0a720, 0x0a721, 0x0a722, 0x0a722, 0x0a724, 0x0a724, 0x0a726, 0x0a726,
+ 0x0a728, 0x0a728, 0x0a72a, 0x0a72a, 0x0a72c, 0x0a72c, 0x0a72e, 0x0a72e,
+ 0x0a730, 0x0a731, 0x0a732, 0x0a732, 0x01dd5, 0x01dd5, 0x03373, 0x03373,
+ 0x01dd6, 0x01dd6, 0x01dd6, 0x01dd6, 0x0a73c, 0x0a73c, 0x0a73e, 0x0a73e,
+ 0x0a740, 0x0a740, 0x0a742, 0x0a742, 0x0a744, 0x0a744, 0x0a746, 0x0a746,
+ 0x0a748, 0x0a748, 0x0a74a, 0x0a74a, 0x0a74c, 0x0a74c, 0x0a74e, 0x0a74e,
+ 0x0a750, 0x0a750, 0x0a752, 0x0a752, 0x0a754, 0x0a754, 0x0a756, 0x0a756,
+ 0x0a758, 0x0a758, 0x01de3, 0x01de3, 0x0a75c, 0x0a75c, 0x0a75e, 0x0a75e,
+ 0x0a760, 0x0a760, 0x0a762, 0x0a762, 0x0a764, 0x0a764, 0x0a766, 0x0a766,
+ 0x0a768, 0x0a768, 0x0a76a, 0x0a76a, 0x0a76c, 0x0a76c, 0x01dd2, 0x01dd2,
+ 0x01dd2, 0x0a771, 0x0a772, 0x0a773, 0x0a774, 0x0a775, 0x0a776, 0x0a777,
+ 0x0a778, 0x00044, 0x00044, 0x00046, 0x00046, 0x00047, 0x0a77e, 0x0a77e,
+ 0x0a780, 0x0a780, 0x00052, 0x00052, 0x00053, 0x00053, 0x00054, 0x00054,
+ 0x0a788, 0x0a789, 0x0a78a, 0x0a78b, 0x0a78b, 0x0a78d, 0x0a78e, 0x0a78f,
+ 0x0a790, 0x0a791, 0x0a792, 0x0a793, 0x0a794, 0x0a795, 0x0a796, 0x0a797,
+ 0x0a798, 0x0a799, 0x0a79a, 0x0a79b, 0x0a79c, 0x0a79d, 0x0a79e, 0x0a79f,
+ 0x0a7a0, 0x0a7a1, 0x0a7a2, 0x0a7a3, 0x0a7a4, 0x0a7a5, 0x0a7a6, 0x0a7a7,
+ 0x0a7a8, 0x0a7a9, 0x0a7aa, 0x0a7ab, 0x0a7ac, 0x0a7ad, 0x0a7ae, 0x0a7af,
+ 0x0a7b0, 0x0a7b1, 0x0a7b2, 0x0a7b3, 0x0a7b4, 0x0a7b5, 0x0a7b6, 0x0a7b7,
+ 0x0a7b8, 0x0a7b9, 0x0a7ba, 0x0a7bb, 0x0a7bc, 0x0a7bd, 0x0a7be, 0x0a7bf,
+ 0x0a7c0, 0x0a7c1, 0x0a7c2, 0x0a7c3, 0x0a7c4, 0x0a7c5, 0x0a7c6, 0x0a7c7,
+ 0x0a7c8, 0x0a7c9, 0x0a7ca, 0x0a7cb, 0x0a7cc, 0x0a7cd, 0x0a7ce, 0x0a7cf,
+ 0x0a7d0, 0x0a7d1, 0x0a7d2, 0x0a7d3, 0x0a7d4, 0x0a7d5, 0x0a7d6, 0x0a7d7,
+ 0x0a7d8, 0x0a7d9, 0x0a7da, 0x0a7db, 0x0a7dc, 0x0a7dd, 0x0a7de, 0x0a7df,
+ 0x0a7e0, 0x0a7e1, 0x0a7e2, 0x0a7e3, 0x0a7e4, 0x0a7e5, 0x0a7e6, 0x0a7e7,
+ 0x0a7e8, 0x0a7e9, 0x0a7ea, 0x0a7eb, 0x0a7ec, 0x0a7ed, 0x0a7ee, 0x0a7ef,
+ 0x0a7f0, 0x0a7f1, 0x0a7f2, 0x0a7f3, 0x0a7f4, 0x0a7f5, 0x0a7f6, 0x0a7f7,
+ 0x0a7f8, 0x0a7f9, 0x0a7fa, 0x0a7fb, 0x0a7fc, 0x0a7fd, 0x0a7fe, 0x0a7ff
+};
+
+static uint32_t unicode_520_ci_page_a8[] = {
+ 0x0a800, 0x0a801, 0x0a802, 0x0a803, 0x0a804, 0x0a805, 0x0a806, 0x0a807,
+ 0x0a808, 0x0a809, 0x0a80a, 0x00000, 0x0a80c, 0x0a80d, 0x0a80e, 0x0a80f,
+ 0x0a810, 0x0a811, 0x0a812, 0x0a813, 0x0a814, 0x0a815, 0x0a816, 0x0a817,
+ 0x0a818, 0x0a819, 0x0a81a, 0x0a81b, 0x0a81c, 0x0a81d, 0x0a81e, 0x0a81f,
+ 0x0a820, 0x0a821, 0x0a822, 0x0a823, 0x0a824, 0x0a825, 0x0a826, 0x0a827,
+ 0x0a828, 0x0a829, 0x0a82a, 0x0a82b, 0x0a82c, 0x0a82d, 0x0a82e, 0x0a82f,
+ 0x0a830, 0x0a831, 0x0a832, 0x0a833, 0x0a834, 0x0a835, 0x0a836, 0x0a837,
+ 0x0a838, 0x0a839, 0x0a83a, 0x0a83b, 0x0a83c, 0x0a83d, 0x0a83e, 0x0a83f,
+ 0x0a840, 0x0a841, 0x0a842, 0x0a843, 0x0a844, 0x0a845, 0x0a846, 0x0a847,
+ 0x0a848, 0x0a849, 0x0a84a, 0x0a84b, 0x0a84c, 0x0a84d, 0x0a84e, 0x0a84f,
+ 0x0a850, 0x0a851, 0x0a852, 0x0a853, 0x0a854, 0x0a855, 0x0a856, 0x0a857,
+ 0x0a858, 0x0a859, 0x0a85a, 0x0a85b, 0x0a85c, 0x0a85d, 0x0a85e, 0x0a85f,
+ 0x0a860, 0x0a861, 0x0a862, 0x0a863, 0x0a864, 0x0a865, 0x0a866, 0x0a867,
+ 0x0a868, 0x0a869, 0x0a86a, 0x0a86b, 0x0a86c, 0x0a86d, 0x0a86e, 0x0a86f,
+ 0x0a870, 0x0a871, 0x0a872, 0x0a873, 0x0a874, 0x0a875, 0x0a876, 0x0a877,
+ 0x0a878, 0x0a879, 0x0a87a, 0x0a87b, 0x0a87c, 0x0a87d, 0x0a87e, 0x0a87f,
+ 0x00000, 0x00000, 0x0a882, 0x0a883, 0x0a884, 0x0a885, 0x0a886, 0x0a887,
+ 0x0a888, 0x0a889, 0x0a88a, 0x0a88b, 0x0a88c, 0x0a88d, 0x0a88e, 0x0a88f,
+ 0x0a890, 0x0a891, 0x0a892, 0x0a893, 0x0a894, 0x0a895, 0x0a896, 0x0a897,
+ 0x0a898, 0x0a899, 0x0a89a, 0x0a89b, 0x0a89c, 0x0a89d, 0x0a89e, 0x0a89f,
+ 0x0a8a0, 0x0a8a1, 0x0a8a2, 0x0a8a3, 0x0a8a4, 0x0a8a5, 0x0a8a6, 0x0a8a7,
+ 0x0a8a8, 0x0a8a9, 0x0a8aa, 0x0a8ab, 0x0a8ac, 0x0a8ad, 0x0a8ae, 0x0a8af,
+ 0x0a8b0, 0x0a8b1, 0x0a8b2, 0x0a8b3, 0x0a8b4, 0x0a8b5, 0x0a8b6, 0x0a8b7,
+ 0x0a8b8, 0x0a8b9, 0x0a8ba, 0x0a8bb, 0x0a8bc, 0x0a8bd, 0x0a8be, 0x0a8bf,
+ 0x0a8c0, 0x0a8c1, 0x0a8c2, 0x0a8c3, 0x0a8c4, 0x0a8c5, 0x0a8c6, 0x0a8c7,
+ 0x0a8c8, 0x0a8c9, 0x0a8ca, 0x0a8cb, 0x0a8cc, 0x0a8cd, 0x0a8ce, 0x0a8cf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a8da, 0x0a8db, 0x0a8dc, 0x0a8dd, 0x0a8de, 0x0a8df,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x0a8f2, 0x0a8f2, 0x0a8f2, 0x0a8f2, 0x0a8f2, 0x0a8f2,
+ 0x0a8f8, 0x0a8f9, 0x0a8fa, 0x0a8fb, 0x0a8fc, 0x0a8fd, 0x0a8fe, 0x0a8ff
+};
+
+static uint32_t unicode_520_ci_page_a9[] = {
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a90a, 0x0a90b, 0x0a90c, 0x0a90d, 0x0a90e, 0x0a90f,
+ 0x0a910, 0x0a911, 0x0a912, 0x0a913, 0x0a914, 0x0a915, 0x0a916, 0x0a917,
+ 0x0a918, 0x0a919, 0x0a91a, 0x0a91b, 0x0a91c, 0x0a91d, 0x0a91e, 0x0a91f,
+ 0x0a920, 0x0a921, 0x0a922, 0x0a923, 0x0a924, 0x0a925, 0x0a926, 0x0a927,
+ 0x0a928, 0x0a929, 0x0a92a, 0x00000, 0x00000, 0x00000, 0x0a92e, 0x0a92f,
+ 0x0a930, 0x0a931, 0x0a932, 0x0a933, 0x0a934, 0x0a935, 0x0a936, 0x0a937,
+ 0x0a938, 0x0a939, 0x0a93a, 0x0a93b, 0x0a93c, 0x0a93d, 0x0a93e, 0x0a93f,
+ 0x0a940, 0x0a941, 0x0a942, 0x0a943, 0x0a944, 0x0a945, 0x0a946, 0x0a947,
+ 0x0a948, 0x0a949, 0x0a94a, 0x0a94b, 0x0a94c, 0x0a94d, 0x0a94e, 0x0a94f,
+ 0x0a950, 0x0a951, 0x0a952, 0x0a953, 0x0a954, 0x0a955, 0x0a956, 0x0a957,
+ 0x0a958, 0x0a959, 0x0a95a, 0x0a95b, 0x0a95c, 0x0a95d, 0x0a95e, 0x0a95f,
+ 0x0a960, 0x0a961, 0x0a962, 0x0a963, 0x0a964, 0x0a965, 0x0a966, 0x0a967,
+ 0x0a968, 0x0a969, 0x0a96a, 0x0a96b, 0x0a96c, 0x0a96d, 0x0a96e, 0x0a96f,
+ 0x0a970, 0x0a971, 0x0a972, 0x0a973, 0x0a974, 0x0a975, 0x0a976, 0x0a977,
+ 0x0a978, 0x0a979, 0x0a97a, 0x0a97b, 0x0a97c, 0x0a97d, 0x0a97e, 0x0a97f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0a984, 0x0a985, 0x0a986, 0x0a987,
+ 0x0a988, 0x0a989, 0x0a98a, 0x0a98b, 0x0a98c, 0x0a98d, 0x0a98e, 0x0a98f,
+ 0x0a990, 0x0a991, 0x0a992, 0x0a993, 0x0a994, 0x0a995, 0x0a996, 0x0a997,
+ 0x0a998, 0x0a999, 0x0a99a, 0x0a99b, 0x0a99c, 0x0a99d, 0x0a99e, 0x0a99f,
+ 0x0a9a0, 0x0a9a1, 0x0a9a2, 0x0a9a3, 0x0a9a4, 0x0a9a5, 0x0a9a6, 0x0a9a7,
+ 0x0a9a8, 0x0a9a9, 0x0a9aa, 0x0a9ab, 0x0a9ab, 0x0a9ad, 0x0a9ae, 0x0a9af,
+ 0x0a9b0, 0x0a9b1, 0x0a9b2, 0x00000, 0x0a9b4, 0x0a9b5, 0x0a9b6, 0x0a9b7,
+ 0x0a9b8, 0x0a9b9, 0x0a9ba, 0x0a9bb, 0x0a9bc, 0x0a9bd, 0x0a9be, 0x0a9bf,
+ 0x0a9c0, 0x0a9c1, 0x0a9c2, 0x0a9c3, 0x0a9c4, 0x0a9c5, 0x0a9c6, 0x0a9c7,
+ 0x0a9c8, 0x0a9c9, 0x0a9ca, 0x0a9cb, 0x0a9cc, 0x0a9cd, 0x0a9ce, 0x0a9cf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0a9da, 0x0a9db, 0x0a9dc, 0x0a9dd, 0x0a9de, 0x0a9df,
+ 0x0a9e0, 0x0a9e1, 0x0a9e2, 0x0a9e3, 0x0a9e4, 0x0a9e5, 0x0a9e6, 0x0a9e7,
+ 0x0a9e8, 0x0a9e9, 0x0a9ea, 0x0a9eb, 0x0a9ec, 0x0a9ed, 0x0a9ee, 0x0a9ef,
+ 0x0a9f0, 0x0a9f1, 0x0a9f2, 0x0a9f3, 0x0a9f4, 0x0a9f5, 0x0a9f6, 0x0a9f7,
+ 0x0a9f8, 0x0a9f9, 0x0a9fa, 0x0a9fb, 0x0a9fc, 0x0a9fd, 0x0a9fe, 0x0a9ff
+};
+
+static uint32_t unicode_520_ci_page_aa[] = {
+ 0x0aa00, 0x0aa01, 0x0aa02, 0x0aa03, 0x0aa04, 0x0aa05, 0x0aa06, 0x0aa07,
+ 0x0aa08, 0x0aa09, 0x0aa0a, 0x0aa0b, 0x0aa0c, 0x0aa0d, 0x0aa0e, 0x0aa0f,
+ 0x0aa10, 0x0aa11, 0x0aa12, 0x0aa13, 0x0aa14, 0x0aa15, 0x0aa16, 0x0aa17,
+ 0x0aa18, 0x0aa19, 0x0aa1a, 0x0aa1b, 0x0aa1c, 0x0aa1d, 0x0aa1e, 0x0aa1f,
+ 0x0aa20, 0x0aa21, 0x0aa22, 0x0aa23, 0x0aa24, 0x0aa25, 0x0aa26, 0x0aa27,
+ 0x0aa28, 0x0aa29, 0x0aa2a, 0x0aa2b, 0x0aa2c, 0x0aa2d, 0x0aa2e, 0x0aa2f,
+ 0x0aa30, 0x0aa31, 0x0aa32, 0x0aa33, 0x0aa34, 0x0aa35, 0x0aa36, 0x0aa37,
+ 0x0aa38, 0x0aa39, 0x0aa3a, 0x0aa3b, 0x0aa3c, 0x0aa3d, 0x0aa3e, 0x0aa3f,
+ 0x0aa40, 0x0aa41, 0x0aa42, 0x0aa43, 0x0aa44, 0x0aa45, 0x0aa46, 0x0aa47,
+ 0x0aa48, 0x0aa49, 0x0aa4a, 0x0aa4b, 0x0aa4c, 0x0aa4d, 0x0aa4e, 0x0aa4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0aa5a, 0x0aa5b, 0x0aa5c, 0x0aa5d, 0x0aa5e, 0x0aa5f,
+ 0x0aa60, 0x0aa61, 0x0aa62, 0x0aa63, 0x0aa64, 0x0aa65, 0x0aa66, 0x0aa67,
+ 0x0aa68, 0x0aa69, 0x0aa6a, 0x0aa6b, 0x0aa6c, 0x0aa6d, 0x0aa6e, 0x0aa6f,
+ 0x0aa70, 0x0aa71, 0x0aa72, 0x0aa73, 0x0aa74, 0x0aa75, 0x0aa76, 0x0aa77,
+ 0x0aa78, 0x0aa79, 0x0aa7a, 0x0aa7b, 0x0aa7c, 0x0aa7d, 0x0aa7e, 0x0aa7f,
+ 0x0aa80, 0x0aa81, 0x0aa82, 0x0aa83, 0x0aa84, 0x0aa85, 0x0aa86, 0x0aa87,
+ 0x0aa88, 0x0aa89, 0x0aa8a, 0x0aa8b, 0x0aa8c, 0x0aa8d, 0x0aa8e, 0x0aa8f,
+ 0x0aa90, 0x0aa91, 0x0aa92, 0x0aa93, 0x0aa94, 0x0aa95, 0x0aa96, 0x0aa97,
+ 0x0aa98, 0x0aa99, 0x0aa9a, 0x0aa9b, 0x0aa9c, 0x0aa9d, 0x0aa9e, 0x0aa9f,
+ 0x0aaa0, 0x0aaa1, 0x0aaa2, 0x0aaa3, 0x0aaa4, 0x0aaa5, 0x0aaa6, 0x0aaa7,
+ 0x0aaa8, 0x0aaa9, 0x0aaaa, 0x0aaab, 0x0aaac, 0x0aaad, 0x0aaae, 0x0aaaf,
+ 0x0aab0, 0x0aab1, 0x0aab2, 0x0aab3, 0x0aab4, 0x0aab5, 0x0aab6, 0x0aab7,
+ 0x0aab8, 0x0aab9, 0x0aaba, 0x0aabb, 0x0aabc, 0x0aabd, 0x0aabe, 0x00000,
+ 0x0aac0, 0x00000, 0x0aac2, 0x0aac3, 0x0aac4, 0x0aac5, 0x0aac6, 0x0aac7,
+ 0x0aac8, 0x0aac9, 0x0aaca, 0x0aacb, 0x0aacc, 0x0aacd, 0x0aace, 0x0aacf,
+ 0x0aad0, 0x0aad1, 0x0aad2, 0x0aad3, 0x0aad4, 0x0aad5, 0x0aad6, 0x0aad7,
+ 0x0aad8, 0x0aad9, 0x0aada, 0x0aadb, 0x0aadc, 0x0aadd, 0x0aade, 0x0aadf,
+ 0x0aae0, 0x0aae1, 0x0aae2, 0x0aae3, 0x0aae4, 0x0aae5, 0x0aae6, 0x0aae7,
+ 0x0aae8, 0x0aae9, 0x0aaea, 0x0aaeb, 0x0aaec, 0x0aaed, 0x0aaee, 0x0aaef,
+ 0x0aaf0, 0x0aaf1, 0x0aaf2, 0x0aaf3, 0x0aaf4, 0x0aaf5, 0x0aaf6, 0x0aaf7,
+ 0x0aaf8, 0x0aaf9, 0x0aafa, 0x0aafb, 0x0aafc, 0x0aafd, 0x0aafe, 0x0aaff
+};
+
+static uint32_t unicode_520_ci_page_ab[] = {
+ 0x0ab00, 0x0ab01, 0x0ab02, 0x0ab03, 0x0ab04, 0x0ab05, 0x0ab06, 0x0ab07,
+ 0x0ab08, 0x0ab09, 0x0ab0a, 0x0ab0b, 0x0ab0c, 0x0ab0d, 0x0ab0e, 0x0ab0f,
+ 0x0ab10, 0x0ab11, 0x0ab12, 0x0ab13, 0x0ab14, 0x0ab15, 0x0ab16, 0x0ab17,
+ 0x0ab18, 0x0ab19, 0x0ab1a, 0x0ab1b, 0x0ab1c, 0x0ab1d, 0x0ab1e, 0x0ab1f,
+ 0x0ab20, 0x0ab21, 0x0ab22, 0x0ab23, 0x0ab24, 0x0ab25, 0x0ab26, 0x0ab27,
+ 0x0ab28, 0x0ab29, 0x0ab2a, 0x0ab2b, 0x0ab2c, 0x0ab2d, 0x0ab2e, 0x0ab2f,
+ 0x0ab30, 0x0ab31, 0x0ab32, 0x0ab33, 0x0ab34, 0x0ab35, 0x0ab36, 0x0ab37,
+ 0x0ab38, 0x0ab39, 0x0ab3a, 0x0ab3b, 0x0ab3c, 0x0ab3d, 0x0ab3e, 0x0ab3f,
+ 0x0ab40, 0x0ab41, 0x0ab42, 0x0ab43, 0x0ab44, 0x0ab45, 0x0ab46, 0x0ab47,
+ 0x0ab48, 0x0ab49, 0x0ab4a, 0x0ab4b, 0x0ab4c, 0x0ab4d, 0x0ab4e, 0x0ab4f,
+ 0x0ab50, 0x0ab51, 0x0ab52, 0x0ab53, 0x0ab54, 0x0ab55, 0x0ab56, 0x0ab57,
+ 0x0ab58, 0x0ab59, 0x0ab5a, 0x0ab5b, 0x0ab5c, 0x0ab5d, 0x0ab5e, 0x0ab5f,
+ 0x0ab60, 0x0ab61, 0x0ab62, 0x0ab63, 0x0ab64, 0x0ab65, 0x0ab66, 0x0ab67,
+ 0x0ab68, 0x0ab69, 0x0ab6a, 0x0ab6b, 0x0ab6c, 0x0ab6d, 0x0ab6e, 0x0ab6f,
+ 0x0ab70, 0x0ab71, 0x0ab72, 0x0ab73, 0x0ab74, 0x0ab75, 0x0ab76, 0x0ab77,
+ 0x0ab78, 0x0ab79, 0x0ab7a, 0x0ab7b, 0x0ab7c, 0x0ab7d, 0x0ab7e, 0x0ab7f,
+ 0x0ab80, 0x0ab81, 0x0ab82, 0x0ab83, 0x0ab84, 0x0ab85, 0x0ab86, 0x0ab87,
+ 0x0ab88, 0x0ab89, 0x0ab8a, 0x0ab8b, 0x0ab8c, 0x0ab8d, 0x0ab8e, 0x0ab8f,
+ 0x0ab90, 0x0ab91, 0x0ab92, 0x0ab93, 0x0ab94, 0x0ab95, 0x0ab96, 0x0ab97,
+ 0x0ab98, 0x0ab99, 0x0ab9a, 0x0ab9b, 0x0ab9c, 0x0ab9d, 0x0ab9e, 0x0ab9f,
+ 0x0aba0, 0x0aba1, 0x0aba2, 0x0aba3, 0x0aba4, 0x0aba5, 0x0aba6, 0x0aba7,
+ 0x0aba8, 0x0aba9, 0x0abaa, 0x0abab, 0x0abac, 0x0abad, 0x0abae, 0x0abaf,
+ 0x0abb0, 0x0abb1, 0x0abb2, 0x0abb3, 0x0abb4, 0x0abb5, 0x0abb6, 0x0abb7,
+ 0x0abb8, 0x0abb9, 0x0abba, 0x0abbb, 0x0abbc, 0x0abbd, 0x0abbe, 0x0abbf,
+ 0x0abc0, 0x0abc1, 0x0abc2, 0x0abc3, 0x0abc4, 0x0abc5, 0x0abc6, 0x0abc7,
+ 0x0abc8, 0x0abc9, 0x0abca, 0x0abcb, 0x0abcc, 0x0abcd, 0x0abce, 0x0abcf,
+ 0x0abd0, 0x0abd1, 0x0abd2, 0x0abd3, 0x0abd4, 0x0abd5, 0x0abd6, 0x0abd7,
+ 0x0abd8, 0x0abd9, 0x0abda, 0x0abdb, 0x0abdc, 0x0abdd, 0x0abde, 0x0abdf,
+ 0x0abe0, 0x0abe1, 0x0abe2, 0x0abe3, 0x0abe4, 0x0abe5, 0x0abe6, 0x0abe7,
+ 0x0abe8, 0x0abe9, 0x0abea, 0x0abeb, 0x00000, 0x0abed, 0x0abee, 0x0abef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0abfa, 0x0abfb, 0x0abfc, 0x0abfd, 0x0abfe, 0x0abff
+};
+
+static uint32_t unicode_520_ci_page_f9[] = {
+ 0x0f900, 0x0f901, 0x02f9e, 0x0f903, 0x0f904, 0x0f905, 0x0f906, 0x02ef2,
+ 0x02ef2, 0x0f909, 0x02fa6, 0x0f90b, 0x0f90c, 0x0f90d, 0x0f90e, 0x0f90f,
+ 0x0f910, 0x0f911, 0x0f912, 0x0f913, 0x0f914, 0x0f915, 0x0f916, 0x0f917,
+ 0x0f918, 0x0f919, 0x0f91a, 0x0f91b, 0x0f91c, 0x0f91d, 0x0f91e, 0x0f91f,
+ 0x0f920, 0x0f921, 0x0f922, 0x0f923, 0x0f924, 0x0f925, 0x0f926, 0x0f927,
+ 0x0f928, 0x0f929, 0x0f92a, 0x0f92b, 0x0f92c, 0x0f92d, 0x0f92e, 0x0f92f,
+ 0x0f930, 0x0f931, 0x0f932, 0x0f933, 0x02f7c, 0x0f935, 0x0f936, 0x0f937,
+ 0x0f938, 0x0f939, 0x0f93a, 0x0f93b, 0x0f93c, 0x0f93d, 0x0f93e, 0x0f93f,
+ 0x02fc5, 0x0f941, 0x0f942, 0x0f943, 0x0f944, 0x0f945, 0x0f946, 0x0f947,
+ 0x0f948, 0x0f949, 0x0f94a, 0x0f94b, 0x0f94c, 0x0f94d, 0x0f94e, 0x0f94f,
+ 0x0f950, 0x0f951, 0x0f952, 0x0f953, 0x0f954, 0x0f955, 0x0f956, 0x0f957,
+ 0x0f958, 0x0f959, 0x0f95a, 0x0f95b, 0x0f914, 0x0f95d, 0x0f95e, 0x0f95f,
+ 0x0f960, 0x0f961, 0x0f962, 0x0f963, 0x0f964, 0x0f965, 0x0f966, 0x0f967,
+ 0x0f968, 0x0f969, 0x0f96a, 0x0f96b, 0x0f96c, 0x0f96d, 0x0f96e, 0x0f96f,
+ 0x0f970, 0x02fa0, 0x0f972, 0x0f973, 0x0f974, 0x0f975, 0x0f976, 0x0f977,
+ 0x0f978, 0x0f979, 0x0f97a, 0x0f97b, 0x0f97c, 0x0f97d, 0x0f97e, 0x0f97f,
+ 0x0f980, 0x02f25, 0x0f982, 0x0f983, 0x0f984, 0x0f985, 0x0f986, 0x0f987,
+ 0x0f988, 0x0f989, 0x02f12, 0x0f98b, 0x0f98c, 0x0f98d, 0x0f98e, 0x0f98f,
+ 0x0f990, 0x0f991, 0x0f992, 0x0f993, 0x0f994, 0x0f995, 0x0f996, 0x0f997,
+ 0x0f998, 0x0f999, 0x0f99a, 0x0f99b, 0x0f99c, 0x0f99d, 0x0f99e, 0x0f99f,
+ 0x0f9a0, 0x0f96f, 0x0f9a2, 0x0f9a3, 0x0f9a4, 0x0f9a5, 0x0f9a6, 0x0f9a7,
+ 0x0f9a8, 0x0f9a9, 0x0f95f, 0x0f9ab, 0x0f9ac, 0x0f9ad, 0x0f9ae, 0x0f9af,
+ 0x0f9b0, 0x0f9b1, 0x0f9b2, 0x0f9b3, 0x0f9b4, 0x0f9b5, 0x0f9b6, 0x0f9b7,
+ 0x0f9b8, 0x0f9b9, 0x0f9ba, 0x0f9bb, 0x0f9bc, 0x0f9bd, 0x0f9be, 0x0f914,
+ 0x0f9c0, 0x0f9c1, 0x0f9c2, 0x0f9c3, 0x02eef, 0x0f9c5, 0x0f9c6, 0x0f9c7,
+ 0x0f9c8, 0x0f9c9, 0x0f9ca, 0x0f9cb, 0x0f9cc, 0x0f9cd, 0x0f9ce, 0x0f9cf,
+ 0x0f9d0, 0x03285, 0x0f9d2, 0x0f9d3, 0x0f9d4, 0x0f9d5, 0x0f9d6, 0x0f9d7,
+ 0x0f9d8, 0x0f9d9, 0x0f9da, 0x0f961, 0x0f9dc, 0x0f9dd, 0x0f9de, 0x0f9df,
+ 0x0f9e0, 0x0f9e1, 0x0f9e2, 0x0f9e3, 0x0f9e4, 0x0f9e5, 0x0f9e6, 0x0f9e7,
+ 0x0f9e8, 0x02fa5, 0x0f9ea, 0x0f9eb, 0x0f9ec, 0x0f9ed, 0x0f9ee, 0x0f9ef,
+ 0x0f9f0, 0x0f9f1, 0x0f9f2, 0x0f9f3, 0x0f9f4, 0x0f9f5, 0x0f9f6, 0x02f74,
+ 0x0f9f8, 0x0f9f9, 0x0f9fa, 0x0f9fb, 0x0f9fc, 0x0f9fd, 0x0f9fe, 0x0f9ff
+};
+
+static uint32_t unicode_520_ci_page_fa[] = {
+ 0x0fa00, 0x0fa01, 0x0fa02, 0x0fa03, 0x0fa04, 0x0fa05, 0x0fa06, 0x0fa07,
+ 0x02f8f, 0x0fa09, 0x02f92, 0x0fa0b, 0x0fa0c, 0x0fa0d, 0x0fa0e, 0x0fa0f,
+ 0x0fa10, 0x0fa11, 0x0fa12, 0x0fa13, 0x0fa14, 0x0fa15, 0x0fa16, 0x0fa17,
+ 0x0fa18, 0x0fa19, 0x0fa1a, 0x0fa1b, 0x0fa1c, 0x0fa1d, 0x02f7b, 0x0fa1f,
+ 0x0fa20, 0x0fa21, 0x0fa22, 0x0fa23, 0x0fa24, 0x0fa25, 0x0fa26, 0x0fa27,
+ 0x0fa28, 0x0fa29, 0x0fa2a, 0x0fa2b, 0x0fa2c, 0x0fa2d, 0x0fa2e, 0x0fa2f,
+ 0x0fa30, 0x0fa31, 0x0fa32, 0x0fa33, 0x0fa34, 0x0fa35, 0x0fa36, 0x0fa37,
+ 0x0fa38, 0x0fa39, 0x0fa3a, 0x0fa3b, 0x02f2c, 0x0fa3d, 0x0fa3e, 0x0fa3f,
+ 0x0fa40, 0x0fa41, 0x0fa42, 0x0fa43, 0x0fa44, 0x0fa45, 0x0fa46, 0x0fa47,
+ 0x0fa48, 0x02ea4, 0x0fa4a, 0x0fa4b, 0x03293, 0x0fa4d, 0x0fa4e, 0x0fa4f,
+ 0x0fa50, 0x03297, 0x0fa52, 0x0fa53, 0x0fa54, 0x0fa55, 0x0fa56, 0x0f996,
+ 0x0fa58, 0x0fa59, 0x0fa5a, 0x0fa5b, 0x0fa5c, 0x02ebe, 0x02ebe, 0x0fa5f,
+ 0x0fa60, 0x0fa61, 0x0fa62, 0x0fa63, 0x0fa64, 0x0fa65, 0x02ecc, 0x0fa25,
+ 0x0fa68, 0x0fa69, 0x0fa6a, 0x0fa6b, 0x0fa6c, 0x0fa6d, 0x0fa6e, 0x0fa6f,
+ 0x0fa70, 0x0fa71, 0x0fa72, 0x0fa73, 0x0fa74, 0x0fa75, 0x0fa76, 0x0fa77,
+ 0x0fa36, 0x0fa79, 0x0fa7a, 0x0fa7b, 0x0fa10, 0x0fa7d, 0x0fa7e, 0x0fa7f,
+ 0x0fa80, 0x0fa81, 0x0fa82, 0x0fa83, 0x0fa84, 0x0fa85, 0x0fa86, 0x0fa87,
+ 0x0fa88, 0x0fa3f, 0x0fa8a, 0x0fa40, 0x0fa8c, 0x0fa8d, 0x0fa8e, 0x0fa8f,
+ 0x0fa90, 0x0fa12, 0x0f929, 0x0fa93, 0x0fa94, 0x02f4d, 0x0f970, 0x0f9ca,
+ 0x0fa98, 0x0fa99, 0x0fa47, 0x0fa9b, 0x0fa48, 0x0fa9d, 0x0fa9e, 0x0fa9f,
+ 0x0fa16, 0x0faa1, 0x0faa2, 0x0faa3, 0x0faa4, 0x0faa5, 0x0fa17, 0x0faa7,
+ 0x0faa8, 0x0faa9, 0x0faaa, 0x0faab, 0x0faac, 0x0fa56, 0x0faae, 0x0faaf,
+ 0x0f996, 0x0fab1, 0x0fa5b, 0x0fab3, 0x0fab4, 0x0fab5, 0x0fab6, 0x0fab7,
+ 0x0fa61, 0x0fab9, 0x0fa22, 0x0fabb, 0x0fa62, 0x0f95d, 0x0fabe, 0x0fa63,
+ 0x0fac0, 0x0fa65, 0x0fac2, 0x0fac3, 0x0fac4, 0x0fac5, 0x0fac6, 0x0fa68,
+ 0x0fa1c, 0x0fac9, 0x0fa69, 0x0facb, 0x0fa6a, 0x0facd, 0x02ef2, 0x0facf,
+ 0x0fad0, 0x0fad1, 0x0fad2, 0x0fad3, 0x0fad4, 0x0fad5, 0x0fad6, 0x0fad7,
+ 0x0fad8, 0x0fad9, 0x0fada, 0x0fadb, 0x0fadc, 0x0fadd, 0x0fade, 0x0fadf,
+ 0x0fae0, 0x0fae1, 0x0fae2, 0x0fae3, 0x0fae4, 0x0fae5, 0x0fae6, 0x0fae7,
+ 0x0fae8, 0x0fae9, 0x0faea, 0x0faeb, 0x0faec, 0x0faed, 0x0faee, 0x0faef,
+ 0x0faf0, 0x0faf1, 0x0faf2, 0x0faf3, 0x0faf4, 0x0faf5, 0x0faf6, 0x0faf7,
+ 0x0faf8, 0x0faf9, 0x0fafa, 0x0fafb, 0x0fafc, 0x0fafd, 0x0fafe, 0x0faff
+};
+
+static uint32_t unicode_520_ci_page_fb[] = {
+ 0x0fb00, 0x0fb01, 0x0fb02, 0x0fb03, 0x0fb04, 0x0fb05, 0x0fb05, 0x0fb07,
+ 0x0fb08, 0x0fb09, 0x0fb0a, 0x0fb0b, 0x0fb0c, 0x0fb0d, 0x0fb0e, 0x0fb0f,
+ 0x0fb10, 0x0fb11, 0x0fb12, 0x0fb13, 0x0fb14, 0x0fb15, 0x0fb16, 0x0fb17,
+ 0x0fb18, 0x0fb19, 0x0fb1a, 0x0fb1b, 0x0fb1c, 0x005d9, 0x00000, 0x005f2,
+ 0x005e2, 0x005d0, 0x005d3, 0x005d4, 0x005da, 0x005dc, 0x005dd, 0x005e8,
+ 0x005ea, 0x0002b, 0x005e9, 0x005e9, 0x005e9, 0x005e9, 0x005d0, 0x005d0,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x0fb37,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x0fb3d, 0x005dd, 0x0fb3f,
+ 0x005df, 0x005e1, 0x0fb42, 0x005e3, 0x005e3, 0x0fb45, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005d5, 0x005d1, 0x005da, 0x005e3, 0x0fb4f,
+ 0x00671, 0x00671, 0x0067b, 0x0067b, 0x0067b, 0x0067b, 0x0067e, 0x0067e,
+ 0x0067e, 0x0067e, 0x00680, 0x00680, 0x00680, 0x00680, 0x0067a, 0x0067a,
+ 0x0067a, 0x0067a, 0x0067f, 0x0067f, 0x0067f, 0x0067f, 0x00679, 0x00679,
+ 0x00679, 0x00679, 0x006a4, 0x006a4, 0x006a4, 0x006a4, 0x006a6, 0x006a6,
+ 0x006a6, 0x006a6, 0x00684, 0x00684, 0x00684, 0x00684, 0x00683, 0x00683,
+ 0x00683, 0x00683, 0x00686, 0x00686, 0x00686, 0x00686, 0x00687, 0x00687,
+ 0x00687, 0x00687, 0x0068d, 0x0068d, 0x0068c, 0x0068c, 0x0068e, 0x0068e,
+ 0x00688, 0x00688, 0x00698, 0x00698, 0x00691, 0x00691, 0x006a9, 0x006a9,
+ 0x006a9, 0x006a9, 0x006af, 0x006af, 0x006af, 0x006af, 0x006b3, 0x006b3,
+ 0x006b3, 0x006b3, 0x006b1, 0x006b1, 0x006b1, 0x006b1, 0x006ba, 0x006ba,
+ 0x006bb, 0x006bb, 0x006bb, 0x006bb, 0x006c0, 0x006c0, 0x006c1, 0x006c1,
+ 0x006c1, 0x006c1, 0x006be, 0x006be, 0x006be, 0x006be, 0x006d2, 0x006d2,
+ 0x006d2, 0x006d2, 0x0fbb2, 0x0fbb3, 0x0fbb4, 0x0fbb5, 0x0fbb6, 0x0fbb7,
+ 0x0fbb8, 0x0fbb9, 0x0fbba, 0x0fbbb, 0x0fbbc, 0x0fbbd, 0x0fbbe, 0x0fbbf,
+ 0x0fbc0, 0x0fbc1, 0x0fbc2, 0x0fbc3, 0x0fbc4, 0x0fbc5, 0x0fbc6, 0x0fbc7,
+ 0x0fbc8, 0x0fbc9, 0x0fbca, 0x0fbcb, 0x0fbcc, 0x0fbcd, 0x0fbce, 0x0fbcf,
+ 0x0fbd0, 0x0fbd1, 0x0fbd2, 0x006ad, 0x006ad, 0x006ad, 0x006ad, 0x006c7,
+ 0x006c7, 0x006c6, 0x006c6, 0x006c8, 0x006c8, 0x00677, 0x006cb, 0x006cb,
+ 0x006c5, 0x006c5, 0x006c9, 0x006c9, 0x006d0, 0x006d0, 0x006d0, 0x006d0,
+ 0x00649, 0x00649, 0x0fbea, 0x0fbea, 0x0fbec, 0x0fbec, 0x0fbee, 0x0fbee,
+ 0x0fbf0, 0x0fbf0, 0x0fbf2, 0x0fbf2, 0x0fbf4, 0x0fbf4, 0x0fbf6, 0x0fbf6,
+ 0x0fbf6, 0x0fbf9, 0x0fbf9, 0x0fbf9, 0x006cc, 0x006cc, 0x0fbfe, 0x0fbff
+};
+
+static uint32_t unicode_520_ci_page_fc[] = {
+ 0x0fc00, 0x0fc01, 0x0fc02, 0x0fbf9, 0x0fc04, 0x0fc05, 0x0fc06, 0x0fc07,
+ 0x0fc08, 0x0fc09, 0x0fc0a, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fc0f,
+ 0x0fc10, 0x0fc11, 0x0fc12, 0x0fc13, 0x0fc14, 0x0fc15, 0x0fc16, 0x0fc17,
+ 0x0fc18, 0x0fc19, 0x0fc1a, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fc1f,
+ 0x0fc20, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25, 0x0fc26, 0x0fc27,
+ 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e, 0x0fc2f,
+ 0x0fc30, 0x0fc31, 0x0fc32, 0x0fc33, 0x0fc34, 0x0fc35, 0x0fc36, 0x0fc37,
+ 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc3f,
+ 0x0fc40, 0x0fc41, 0x0fc42, 0x0fc43, 0x0fc44, 0x0fc45, 0x0fc46, 0x0fc47,
+ 0x0fc48, 0x0fc49, 0x0fc4a, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fc4f,
+ 0x0fc50, 0x0fc51, 0x0fc52, 0x0fc53, 0x0fc54, 0x0fc55, 0x0fc56, 0x0fc57,
+ 0x0fc58, 0x0fc59, 0x0fc5a, 0x00630, 0x00631, 0x00649, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0fc64, 0x0fc65, 0x0fc02, 0x0fc67,
+ 0x0fbf9, 0x0fc04, 0x0fc6a, 0x0fc6b, 0x0fc08, 0x0fc6d, 0x0fc09, 0x0fc0a,
+ 0x0fc70, 0x0fc71, 0x0fc0e, 0x0fc73, 0x0fc0f, 0x0fc10, 0x0fc76, 0x0fc77,
+ 0x0fc12, 0x0fc79, 0x0fc13, 0x0fc14, 0x0fc31, 0x0fc32, 0x0fc35, 0x0fc36,
+ 0x0fc37, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc42, 0x0fc43, 0x0fc44,
+ 0x0fc88, 0x0fc48, 0x0fc8a, 0x0fc8b, 0x0fc4e, 0x0fc8d, 0x0fc4f, 0x0fc50,
+ 0x00649, 0x0fc91, 0x0fc92, 0x0fc58, 0x0fc94, 0x0fc59, 0x0fc5a, 0x0fc00,
+ 0x0fc01, 0x0fc99, 0x0fc02, 0x0fc9b, 0x0fc05, 0x0fc06, 0x0fc07, 0x0fc08,
+ 0x0fca0, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fc15,
+ 0x0fc16, 0x0fc17, 0x0fc18, 0x0fc19, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e,
+ 0x0fc1f, 0x0fc20, 0x0fcb2, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25,
+ 0x0fc26, 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e,
+ 0x0fc2f, 0x0fc30, 0x0fc33, 0x0fc34, 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b,
+ 0x0fc3c, 0x0fc3f, 0x0fc40, 0x0fc41, 0x0fc42, 0x0fccd, 0x0fc45, 0x0fc46,
+ 0x0fc47, 0x0fc48, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fcd6, 0x0fc51,
+ 0x0fc52, 0x00647, 0x0fc55, 0x0fc56, 0x0fc57, 0x0fc58, 0x0fcde, 0x0fc02,
+ 0x0fc9b, 0x0fc08, 0x0fca0, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fce6, 0x0fc1f,
+ 0x0fce8, 0x0fce9, 0x0fcea, 0x0fc3b, 0x0fc3c, 0x0fc42, 0x0fc4e, 0x0fcd6,
+ 0x0fc58, 0x0fcde, 0x00000, 0x00000, 0x00000, 0x0fcf5, 0x0fcf6, 0x0fcf7,
+ 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb, 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fcff
+};
+
+static uint32_t unicode_520_ci_page_fd[] = {
+ 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03, 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07,
+ 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b, 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f,
+ 0x0fd10, 0x0fcf5, 0x0fcf6, 0x0fcf7, 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb,
+ 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fd1b, 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03,
+ 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07, 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f, 0x0fd10, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fce8, 0x0fcea, 0x0fc27, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fd09,
+ 0x0fd0a, 0x0fd0b, 0x0fc27, 0x0fc28, 0x00627, 0x00627, 0x0fd3e, 0x0fd3f,
+ 0x0fd40, 0x0fd41, 0x0fd42, 0x0fd43, 0x0fd44, 0x0fd45, 0x0fd46, 0x0fd47,
+ 0x0fd48, 0x0fd49, 0x0fd4a, 0x0fd4b, 0x0fd4c, 0x0fd4d, 0x0fd4e, 0x0fd4f,
+ 0x0fd50, 0x0fd51, 0x0fd51, 0x0fd53, 0x0fd54, 0x0fd55, 0x0fd56, 0x0fd57,
+ 0x0fd58, 0x0fd58, 0x0fd5a, 0x0fd5b, 0x0fd5c, 0x0fd5d, 0x0fd5e, 0x0fd5f,
+ 0x0fd5f, 0x0fd61, 0x0fd62, 0x0fd62, 0x0fd64, 0x0fd64, 0x0fd66, 0x0fd67,
+ 0x0fd67, 0x0fd69, 0x0fd6a, 0x0fd6a, 0x0fd6c, 0x0fd6c, 0x0fd6e, 0x0fd6f,
+ 0x0fd6f, 0x0fd71, 0x0fd71, 0x0fd73, 0x0fd74, 0x0fd75, 0x0fd76, 0x0fd76,
+ 0x0fd78, 0x0fd79, 0x0fd7a, 0x0fd7b, 0x0fd7c, 0x0fd7c, 0x0fd7e, 0x0fd7f,
+ 0x0fd80, 0x0fd81, 0x0fd82, 0x0fd83, 0x0fd83, 0x0fd85, 0x0fd85, 0x0fd87,
+ 0x0fd87, 0x0fd89, 0x0fd8a, 0x0fd8b, 0x0fd8c, 0x0fd8d, 0x0fd8e, 0x0fd8f,
+ 0x0fd90, 0x0fd91, 0x0fd92, 0x0fd93, 0x0fd94, 0x0fd95, 0x0fd96, 0x0fd97,
+ 0x0fd97, 0x0fd99, 0x0fd9a, 0x0fd9b, 0x0fd9c, 0x0fd9c, 0x0fd9e, 0x0fd9f,
+ 0x0fda0, 0x0fda1, 0x0fda2, 0x0fda3, 0x0fda4, 0x0fda5, 0x0fda6, 0x0fda7,
+ 0x0fda8, 0x0fda9, 0x0fdaa, 0x0fdab, 0x0fdac, 0x0fdad, 0x0fdae, 0x0fdaf,
+ 0x0fdb0, 0x0fdb1, 0x0fdb2, 0x0fdb3, 0x0fd7e, 0x0fd80, 0x0fdb6, 0x0fdb7,
+ 0x0fdb8, 0x0fdb9, 0x0fdba, 0x0fdbb, 0x0fdba, 0x0fdb8, 0x0fdbe, 0x0fdbf,
+ 0x0fdc0, 0x0fdc1, 0x0fdc2, 0x0fdbb, 0x0fd75, 0x0fd66, 0x0fdc6, 0x0fdc7,
+ 0x0fdc8, 0x0fdc9, 0x0fdca, 0x0fdcb, 0x0fdcc, 0x0fdcd, 0x0fdce, 0x0fdcf,
+ 0x0fdd0, 0x0fdd1, 0x0fdd2, 0x0fdd3, 0x0fdd4, 0x0fdd5, 0x0fdd6, 0x0fdd7,
+ 0x0fdd8, 0x0fdd9, 0x0fdda, 0x0fddb, 0x0fddc, 0x0fddd, 0x0fdde, 0x0fddf,
+ 0x0fde0, 0x0fde1, 0x0fde2, 0x0fde3, 0x0fde4, 0x0fde5, 0x0fde6, 0x0fde7,
+ 0x0fde8, 0x0fde9, 0x0fdea, 0x0fdeb, 0x0fdec, 0x0fded, 0x0fdee, 0x0fdef,
+ 0x0fdf0, 0x0fdf1, 0x0fdf2, 0x0fdf3, 0x0fdf4, 0x0fdf5, 0x0fdf6, 0x0fdf7,
+ 0x0fdf8, 0x0fdf9, 0x0fdfa, 0x0fdfb, 0x0fdfc, 0x0fdfd, 0x0fdfe, 0x0fdff
+};
+
+static uint32_t unicode_520_ci_page_fe[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x0002c, 0x03001, 0x03002, 0x0003a, 0x0003b, 0x00021, 0x0003f, 0x03016,
+ 0x03017, 0x02026, 0x0fe1a, 0x0fe1b, 0x0fe1c, 0x0fe1d, 0x0fe1e, 0x0fe1f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe27,
+ 0x0fe28, 0x0fe29, 0x0fe2a, 0x0fe2b, 0x0fe2c, 0x0fe2d, 0x0fe2e, 0x0fe2f,
+ 0x02025, 0x02014, 0x02013, 0x0005f, 0x0005f, 0x00028, 0x00029, 0x0007b,
+ 0x0007d, 0x03014, 0x03015, 0x03010, 0x03011, 0x0300a, 0x0300b, 0x02329,
+ 0x0232a, 0x0300c, 0x0300d, 0x0300e, 0x0300f, 0x0fe45, 0x0fe46, 0x0005b,
+ 0x0005d, 0x0203e, 0x0203e, 0x0203e, 0x0203e, 0x0005f, 0x0005f, 0x0005f,
+ 0x0002c, 0x03001, 0x0002e, 0x0fe53, 0x0003b, 0x0003a, 0x0003f, 0x00021,
+ 0x02014, 0x00028, 0x00029, 0x0007b, 0x0007d, 0x03014, 0x03015, 0x00023,
+ 0x00026, 0x0002a, 0x0002b, 0x0002d, 0x0003c, 0x0003e, 0x0003d, 0x0fe67,
+ 0x0005c, 0x00024, 0x00025, 0x00040, 0x0fe6c, 0x0fe6d, 0x0fe6e, 0x0fe6f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe75, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00621, 0x00622, 0x00622, 0x00623, 0x00623, 0x00624, 0x00624, 0x00625,
+ 0x00625, 0x00626, 0x00626, 0x00626, 0x00626, 0x00627, 0x00627, 0x00628,
+ 0x00628, 0x00628, 0x00628, 0x00629, 0x00629, 0x0062a, 0x0062a, 0x0062a,
+ 0x0062a, 0x0062b, 0x0062b, 0x0062b, 0x0062b, 0x0062c, 0x0062c, 0x0062c,
+ 0x0062c, 0x0062d, 0x0062d, 0x0062d, 0x0062d, 0x0062e, 0x0062e, 0x0062e,
+ 0x0062e, 0x0062f, 0x0062f, 0x00630, 0x00630, 0x00631, 0x00631, 0x00632,
+ 0x00632, 0x00633, 0x00633, 0x00633, 0x00633, 0x00634, 0x00634, 0x00634,
+ 0x00634, 0x00635, 0x00635, 0x00635, 0x00635, 0x00636, 0x00636, 0x00636,
+ 0x00636, 0x00637, 0x00637, 0x00637, 0x00637, 0x00638, 0x00638, 0x00638,
+ 0x00638, 0x00639, 0x00639, 0x00639, 0x00639, 0x0063a, 0x0063a, 0x0063a,
+ 0x0063a, 0x00641, 0x00641, 0x00641, 0x00641, 0x00642, 0x00642, 0x00642,
+ 0x00642, 0x00643, 0x00643, 0x00643, 0x00643, 0x00644, 0x00644, 0x00644,
+ 0x00644, 0x00645, 0x00645, 0x00645, 0x00645, 0x00646, 0x00646, 0x00646,
+ 0x00646, 0x00647, 0x00647, 0x00647, 0x00647, 0x00648, 0x00648, 0x00649,
+ 0x00649, 0x0064a, 0x0064a, 0x0064a, 0x0064a, 0x0fef5, 0x0fef5, 0x0fef7,
+ 0x0fef7, 0x0fef9, 0x0fef9, 0x0fefb, 0x0fefb, 0x0fefd, 0x0fefe, 0x0feff
+};
+
+static uint32_t unicode_520_ci_page_ff[] = {
+ 0x0ff00, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x02985,
+ 0x02986, 0x03002, 0x0300c, 0x0300d, 0x03001, 0x030fb, 0x03092, 0x03042,
+ 0x03044, 0x03046, 0x03048, 0x0304a, 0x03084, 0x03086, 0x03088, 0x03064,
+ 0x030fc, 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d,
+ 0x0304f, 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d,
+ 0x0305f, 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c,
+ 0x0306d, 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e,
+ 0x0307f, 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089,
+ 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03093, 0x00000, 0x00000,
+ 0x01160, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0ffbf,
+ 0x0ffc0, 0x0ffc1, 0x01161, 0x01162, 0x01163, 0x01164, 0x01165, 0x01166,
+ 0x0ffc8, 0x0ffc9, 0x01167, 0x01168, 0x01169, 0x0116a, 0x0116b, 0x0116c,
+ 0x0ffd0, 0x0ffd1, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171, 0x01172,
+ 0x0ffd8, 0x0ffd9, 0x01173, 0x01174, 0x01175, 0x0ffdd, 0x0ffde, 0x0ffdf,
+ 0x000a2, 0x000a3, 0x000ac, 0x000af, 0x000a6, 0x000a5, 0x020a9, 0x0ffe7,
+ 0x02502, 0x02190, 0x02191, 0x02192, 0x02193, 0x025a0, 0x025cb, 0x0ffef,
+ 0x0fff0, 0x0fff1, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff5, 0x0fff6, 0x0fff7,
+ 0x0fff8, 0x00000, 0x00000, 0x00000, 0x0fffc, 0x0fffd, 0x0fffe, 0x0ffff
+};
+
+static uint32_t unicode_520_ci_page_101[] = {
+ 0x10100, 0x10101, 0x10102, 0x10103, 0x10104, 0x10105, 0x10106, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x10110, 0x10111, 0x10112, 0x10113, 0x10114, 0x10115, 0x10116, 0x10117,
+ 0x10118, 0x10119, 0x1011a, 0x1011b, 0x1011c, 0x1011d, 0x1011e, 0x1011f,
+ 0x10120, 0x10121, 0x10122, 0x10123, 0x10124, 0x10125, 0x10126, 0x10127,
+ 0x10128, 0x10129, 0x1012a, 0x1012b, 0x1012c, 0x1012d, 0x1012e, 0x1012f,
+ 0x10130, 0x10131, 0x10132, 0x10133, 0x10134, 0x10135, 0x10136, 0x10137,
+ 0x10138, 0x10139, 0x1013a, 0x1013b, 0x1013c, 0x1013d, 0x1013e, 0x1013f,
+ 0x10140, 0x10141, 0x00031, 0x00035, 0x10144, 0x10145, 0x10146, 0x10147,
+ 0x00035, 0x10149, 0x1014a, 0x1014b, 0x1014c, 0x1014d, 0x1014e, 0x00035,
+ 0x10150, 0x10151, 0x10152, 0x10153, 0x10154, 0x10155, 0x10156, 0x10157,
+ 0x00031, 0x00031, 0x00031, 0x00032, 0x00032, 0x00032, 0x00032, 0x00035,
+ 0x10160, 0x10161, 0x10162, 0x10163, 0x10164, 0x10165, 0x10166, 0x10167,
+ 0x10168, 0x10169, 0x1016a, 0x1016b, 0x1016c, 0x1016d, 0x1016e, 0x1016f,
+ 0x10170, 0x10171, 0x10172, 0x00035, 0x10174, 0x10175, 0x10176, 0x10177,
+ 0x10178, 0x10179, 0x1017a, 0x1017b, 0x1017c, 0x1017d, 0x1017e, 0x1017f,
+ 0x10180, 0x10181, 0x10182, 0x10183, 0x10184, 0x10185, 0x10186, 0x10187,
+ 0x10188, 0x10189, 0x00030, 0x1018b, 0x1018c, 0x1018d, 0x1018e, 0x1018f,
+ 0x10190, 0x10191, 0x10192, 0x10193, 0x10194, 0x10195, 0x10196, 0x10197,
+ 0x10198, 0x10199, 0x1019a, 0x1019b, 0x1019c, 0x1019d, 0x1019e, 0x1019f,
+ 0x101a0, 0x101a1, 0x101a2, 0x101a3, 0x101a4, 0x101a5, 0x101a6, 0x101a7,
+ 0x101a8, 0x101a9, 0x101aa, 0x101ab, 0x101ac, 0x101ad, 0x101ae, 0x101af,
+ 0x101b0, 0x101b1, 0x101b2, 0x101b3, 0x101b4, 0x101b5, 0x101b6, 0x101b7,
+ 0x101b8, 0x101b9, 0x101ba, 0x101bb, 0x101bc, 0x101bd, 0x101be, 0x101bf,
+ 0x101c0, 0x101c1, 0x101c2, 0x101c3, 0x101c4, 0x101c5, 0x101c6, 0x101c7,
+ 0x101c8, 0x101c9, 0x101ca, 0x101cb, 0x101cc, 0x101cd, 0x101ce, 0x101cf,
+ 0x101d0, 0x101d1, 0x101d2, 0x101d3, 0x101d4, 0x101d5, 0x101d6, 0x101d7,
+ 0x101d8, 0x101d9, 0x101da, 0x101db, 0x101dc, 0x101dd, 0x101de, 0x101df,
+ 0x101e0, 0x101e1, 0x101e2, 0x101e3, 0x101e4, 0x101e5, 0x101e6, 0x101e7,
+ 0x101e8, 0x101e9, 0x101ea, 0x101eb, 0x101ec, 0x101ed, 0x101ee, 0x101ef,
+ 0x101f0, 0x101f1, 0x101f2, 0x101f3, 0x101f4, 0x101f5, 0x101f6, 0x101f7,
+ 0x101f8, 0x101f9, 0x101fa, 0x101fb, 0x101fc, 0x00000, 0x101fe, 0x101ff
+};
+
+static uint32_t unicode_520_ci_page_103[] = {
+ 0x10300, 0x10301, 0x10302, 0x10303, 0x10304, 0x10305, 0x10306, 0x10307,
+ 0x10308, 0x10309, 0x1030a, 0x1030b, 0x1030c, 0x1030d, 0x1030e, 0x1030f,
+ 0x10310, 0x10311, 0x10312, 0x10313, 0x10314, 0x10315, 0x10316, 0x10317,
+ 0x10318, 0x10319, 0x1031a, 0x1031b, 0x1031c, 0x1031d, 0x1031e, 0x1031f,
+ 0x00031, 0x00035, 0x10322, 0x10323, 0x10324, 0x10325, 0x10326, 0x10327,
+ 0x10328, 0x10329, 0x1032a, 0x1032b, 0x1032c, 0x1032d, 0x1032e, 0x1032f,
+ 0x10330, 0x10331, 0x10332, 0x10333, 0x10334, 0x10335, 0x10336, 0x10337,
+ 0x10338, 0x10339, 0x1033a, 0x1033b, 0x1033c, 0x1033d, 0x1033e, 0x1033f,
+ 0x10340, 0x10341, 0x10342, 0x10343, 0x10344, 0x10345, 0x10346, 0x10347,
+ 0x10348, 0x10349, 0x1034a, 0x1034b, 0x1034c, 0x1034d, 0x1034e, 0x1034f,
+ 0x10350, 0x10351, 0x10352, 0x10353, 0x10354, 0x10355, 0x10356, 0x10357,
+ 0x10358, 0x10359, 0x1035a, 0x1035b, 0x1035c, 0x1035d, 0x1035e, 0x1035f,
+ 0x10360, 0x10361, 0x10362, 0x10363, 0x10364, 0x10365, 0x10366, 0x10367,
+ 0x10368, 0x10369, 0x1036a, 0x1036b, 0x1036c, 0x1036d, 0x1036e, 0x1036f,
+ 0x10370, 0x10371, 0x10372, 0x10373, 0x10374, 0x10375, 0x10376, 0x10377,
+ 0x10378, 0x10379, 0x1037a, 0x1037b, 0x1037c, 0x1037d, 0x1037e, 0x1037f,
+ 0x10380, 0x10381, 0x10382, 0x10383, 0x10384, 0x10385, 0x10386, 0x10387,
+ 0x10388, 0x10389, 0x1038a, 0x1038b, 0x1038c, 0x1038d, 0x1038e, 0x1038f,
+ 0x10390, 0x10391, 0x10392, 0x10393, 0x10394, 0x10395, 0x10396, 0x10397,
+ 0x10398, 0x10399, 0x1039a, 0x1039b, 0x1039c, 0x1039d, 0x1039e, 0x1039f,
+ 0x103a0, 0x103a1, 0x103a2, 0x103a3, 0x103a4, 0x103a5, 0x103a6, 0x103a7,
+ 0x103a8, 0x103a9, 0x103aa, 0x103ab, 0x103ac, 0x103ad, 0x103ae, 0x103af,
+ 0x103b0, 0x103b1, 0x103b2, 0x103b3, 0x103b4, 0x103b5, 0x103b6, 0x103b7,
+ 0x103b8, 0x103b9, 0x103ba, 0x103bb, 0x103bc, 0x103bd, 0x103be, 0x103bf,
+ 0x103c0, 0x103c1, 0x103c2, 0x103c3, 0x103c4, 0x103c5, 0x103c6, 0x103c7,
+ 0x103c8, 0x103c9, 0x103ca, 0x103cb, 0x103cc, 0x103cd, 0x103ce, 0x103cf,
+ 0x103d0, 0x00031, 0x00032, 0x103d3, 0x103d4, 0x103d5, 0x103d6, 0x103d7,
+ 0x103d8, 0x103d9, 0x103da, 0x103db, 0x103dc, 0x103dd, 0x103de, 0x103df,
+ 0x103e0, 0x103e1, 0x103e2, 0x103e3, 0x103e4, 0x103e5, 0x103e6, 0x103e7,
+ 0x103e8, 0x103e9, 0x103ea, 0x103eb, 0x103ec, 0x103ed, 0x103ee, 0x103ef,
+ 0x103f0, 0x103f1, 0x103f2, 0x103f3, 0x103f4, 0x103f5, 0x103f6, 0x103f7,
+ 0x103f8, 0x103f9, 0x103fa, 0x103fb, 0x103fc, 0x103fd, 0x103fe, 0x103ff
+};
+
+static uint32_t unicode_520_ci_page_104[] = {
+ 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407,
+ 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f,
+ 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417,
+ 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f,
+ 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427,
+ 0x10400, 0x10401, 0x10402, 0x10403, 0x10404, 0x10405, 0x10406, 0x10407,
+ 0x10408, 0x10409, 0x1040a, 0x1040b, 0x1040c, 0x1040d, 0x1040e, 0x1040f,
+ 0x10410, 0x10411, 0x10412, 0x10413, 0x10414, 0x10415, 0x10416, 0x10417,
+ 0x10418, 0x10419, 0x1041a, 0x1041b, 0x1041c, 0x1041d, 0x1041e, 0x1041f,
+ 0x10420, 0x10421, 0x10422, 0x10423, 0x10424, 0x10425, 0x10426, 0x10427,
+ 0x10450, 0x10451, 0x10452, 0x10453, 0x10454, 0x10455, 0x10456, 0x10457,
+ 0x10458, 0x10459, 0x1045a, 0x1045b, 0x1045c, 0x1045d, 0x1045e, 0x1045f,
+ 0x10460, 0x10461, 0x10462, 0x10463, 0x10464, 0x10465, 0x10466, 0x10467,
+ 0x10468, 0x10469, 0x1046a, 0x1046b, 0x1046c, 0x1046d, 0x1046e, 0x1046f,
+ 0x10470, 0x10471, 0x10472, 0x10473, 0x10474, 0x10475, 0x10476, 0x10477,
+ 0x10478, 0x10479, 0x1047a, 0x1047b, 0x1047c, 0x1047d, 0x1047e, 0x1047f,
+ 0x10480, 0x10481, 0x10482, 0x10483, 0x10484, 0x10485, 0x10486, 0x10487,
+ 0x10488, 0x10489, 0x1048a, 0x1048b, 0x1048c, 0x1048d, 0x1048e, 0x1048f,
+ 0x10490, 0x10491, 0x10492, 0x10493, 0x10494, 0x10495, 0x10496, 0x10497,
+ 0x10498, 0x10499, 0x1049a, 0x1049b, 0x1049c, 0x1049d, 0x1049e, 0x1049f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x104aa, 0x104ab, 0x104ac, 0x104ad, 0x104ae, 0x104af,
+ 0x104b0, 0x104b1, 0x104b2, 0x104b3, 0x104b4, 0x104b5, 0x104b6, 0x104b7,
+ 0x104b8, 0x104b9, 0x104ba, 0x104bb, 0x104bc, 0x104bd, 0x104be, 0x104bf,
+ 0x104c0, 0x104c1, 0x104c2, 0x104c3, 0x104c4, 0x104c5, 0x104c6, 0x104c7,
+ 0x104c8, 0x104c9, 0x104ca, 0x104cb, 0x104cc, 0x104cd, 0x104ce, 0x104cf,
+ 0x104d0, 0x104d1, 0x104d2, 0x104d3, 0x104d4, 0x104d5, 0x104d6, 0x104d7,
+ 0x104d8, 0x104d9, 0x104da, 0x104db, 0x104dc, 0x104dd, 0x104de, 0x104df,
+ 0x104e0, 0x104e1, 0x104e2, 0x104e3, 0x104e4, 0x104e5, 0x104e6, 0x104e7,
+ 0x104e8, 0x104e9, 0x104ea, 0x104eb, 0x104ec, 0x104ed, 0x104ee, 0x104ef,
+ 0x104f0, 0x104f1, 0x104f2, 0x104f3, 0x104f4, 0x104f5, 0x104f6, 0x104f7,
+ 0x104f8, 0x104f9, 0x104fa, 0x104fb, 0x104fc, 0x104fd, 0x104fe, 0x104ff
+};
+
+static uint32_t unicode_520_ci_page_108[] = {
+ 0x10800, 0x10801, 0x10802, 0x10803, 0x10804, 0x10805, 0x10806, 0x10807,
+ 0x10808, 0x10809, 0x1080a, 0x1080b, 0x1080c, 0x1080d, 0x1080e, 0x1080f,
+ 0x10810, 0x10811, 0x10812, 0x10813, 0x10814, 0x10815, 0x10816, 0x10817,
+ 0x10818, 0x10819, 0x1081a, 0x1081b, 0x1081c, 0x1081d, 0x1081e, 0x1081f,
+ 0x10820, 0x10821, 0x10822, 0x10823, 0x10824, 0x10825, 0x10826, 0x10827,
+ 0x10828, 0x10829, 0x1082a, 0x1082b, 0x1082c, 0x1082d, 0x1082e, 0x1082f,
+ 0x10830, 0x10831, 0x10832, 0x10833, 0x10834, 0x10835, 0x10836, 0x10837,
+ 0x10838, 0x10839, 0x1083a, 0x1083b, 0x1083c, 0x1083d, 0x1083e, 0x1083f,
+ 0x10840, 0x10841, 0x10842, 0x10843, 0x10844, 0x10845, 0x10846, 0x10847,
+ 0x10848, 0x10849, 0x1084a, 0x1084b, 0x1084c, 0x1084d, 0x1084e, 0x1084f,
+ 0x10850, 0x10851, 0x10852, 0x10853, 0x10854, 0x10855, 0x10856, 0x10857,
+ 0x00031, 0x00032, 0x00033, 0x1085b, 0x1085c, 0x1085d, 0x1085e, 0x1085f,
+ 0x10860, 0x10861, 0x10862, 0x10863, 0x10864, 0x10865, 0x10866, 0x10867,
+ 0x10868, 0x10869, 0x1086a, 0x1086b, 0x1086c, 0x1086d, 0x1086e, 0x1086f,
+ 0x10870, 0x10871, 0x10872, 0x10873, 0x10874, 0x10875, 0x10876, 0x10877,
+ 0x10878, 0x10879, 0x1087a, 0x1087b, 0x1087c, 0x1087d, 0x1087e, 0x1087f,
+ 0x10880, 0x10881, 0x10882, 0x10883, 0x10884, 0x10885, 0x10886, 0x10887,
+ 0x10888, 0x10889, 0x1088a, 0x1088b, 0x1088c, 0x1088d, 0x1088e, 0x1088f,
+ 0x10890, 0x10891, 0x10892, 0x10893, 0x10894, 0x10895, 0x10896, 0x10897,
+ 0x10898, 0x10899, 0x1089a, 0x1089b, 0x1089c, 0x1089d, 0x1089e, 0x1089f,
+ 0x108a0, 0x108a1, 0x108a2, 0x108a3, 0x108a4, 0x108a5, 0x108a6, 0x108a7,
+ 0x108a8, 0x108a9, 0x108aa, 0x108ab, 0x108ac, 0x108ad, 0x108ae, 0x108af,
+ 0x108b0, 0x108b1, 0x108b2, 0x108b3, 0x108b4, 0x108b5, 0x108b6, 0x108b7,
+ 0x108b8, 0x108b9, 0x108ba, 0x108bb, 0x108bc, 0x108bd, 0x108be, 0x108bf,
+ 0x108c0, 0x108c1, 0x108c2, 0x108c3, 0x108c4, 0x108c5, 0x108c6, 0x108c7,
+ 0x108c8, 0x108c9, 0x108ca, 0x108cb, 0x108cc, 0x108cd, 0x108ce, 0x108cf,
+ 0x108d0, 0x108d1, 0x108d2, 0x108d3, 0x108d4, 0x108d5, 0x108d6, 0x108d7,
+ 0x108d8, 0x108d9, 0x108da, 0x108db, 0x108dc, 0x108dd, 0x108de, 0x108df,
+ 0x108e0, 0x108e1, 0x108e2, 0x108e3, 0x108e4, 0x108e5, 0x108e6, 0x108e7,
+ 0x108e8, 0x108e9, 0x108ea, 0x108eb, 0x108ec, 0x108ed, 0x108ee, 0x108ef,
+ 0x108f0, 0x108f1, 0x108f2, 0x108f3, 0x108f4, 0x108f5, 0x108f6, 0x108f7,
+ 0x108f8, 0x108f9, 0x108fa, 0x108fb, 0x108fc, 0x108fd, 0x108fe, 0x108ff
+};
+
+static uint32_t unicode_520_ci_page_109[] = {
+ 0x10900, 0x10901, 0x10902, 0x10903, 0x10904, 0x10905, 0x10906, 0x10907,
+ 0x10908, 0x10909, 0x1090a, 0x1090b, 0x1090c, 0x1090d, 0x1090e, 0x1090f,
+ 0x10910, 0x10911, 0x10912, 0x10913, 0x10914, 0x10915, 0x00031, 0x10917,
+ 0x10918, 0x10919, 0x00032, 0x00033, 0x1091c, 0x1091d, 0x1091e, 0x1091f,
+ 0x10920, 0x10921, 0x10922, 0x10923, 0x10924, 0x10925, 0x10926, 0x10927,
+ 0x10928, 0x10929, 0x1092a, 0x1092b, 0x1092c, 0x1092d, 0x1092e, 0x1092f,
+ 0x10930, 0x10931, 0x10932, 0x10933, 0x10934, 0x10935, 0x10936, 0x10937,
+ 0x10938, 0x10939, 0x1093a, 0x1093b, 0x1093c, 0x1093d, 0x1093e, 0x1093f,
+ 0x10940, 0x10941, 0x10942, 0x10943, 0x10944, 0x10945, 0x10946, 0x10947,
+ 0x10948, 0x10949, 0x1094a, 0x1094b, 0x1094c, 0x1094d, 0x1094e, 0x1094f,
+ 0x10950, 0x10951, 0x10952, 0x10953, 0x10954, 0x10955, 0x10956, 0x10957,
+ 0x10958, 0x10959, 0x1095a, 0x1095b, 0x1095c, 0x1095d, 0x1095e, 0x1095f,
+ 0x10960, 0x10961, 0x10962, 0x10963, 0x10964, 0x10965, 0x10966, 0x10967,
+ 0x10968, 0x10969, 0x1096a, 0x1096b, 0x1096c, 0x1096d, 0x1096e, 0x1096f,
+ 0x10970, 0x10971, 0x10972, 0x10973, 0x10974, 0x10975, 0x10976, 0x10977,
+ 0x10978, 0x10979, 0x1097a, 0x1097b, 0x1097c, 0x1097d, 0x1097e, 0x1097f,
+ 0x10980, 0x10981, 0x10982, 0x10983, 0x10984, 0x10985, 0x10986, 0x10987,
+ 0x10988, 0x10989, 0x1098a, 0x1098b, 0x1098c, 0x1098d, 0x1098e, 0x1098f,
+ 0x10990, 0x10991, 0x10992, 0x10993, 0x10994, 0x10995, 0x10996, 0x10997,
+ 0x10998, 0x10999, 0x1099a, 0x1099b, 0x1099c, 0x1099d, 0x1099e, 0x1099f,
+ 0x109a0, 0x109a1, 0x109a2, 0x109a3, 0x109a4, 0x109a5, 0x109a6, 0x109a7,
+ 0x109a8, 0x109a9, 0x109aa, 0x109ab, 0x109ac, 0x109ad, 0x109ae, 0x109af,
+ 0x109b0, 0x109b1, 0x109b2, 0x109b3, 0x109b4, 0x109b5, 0x109b6, 0x109b7,
+ 0x109b8, 0x109b9, 0x109ba, 0x109bb, 0x109bc, 0x109bd, 0x109be, 0x109bf,
+ 0x109c0, 0x109c1, 0x109c2, 0x109c3, 0x109c4, 0x109c5, 0x109c6, 0x109c7,
+ 0x109c8, 0x109c9, 0x109ca, 0x109cb, 0x109cc, 0x109cd, 0x109ce, 0x109cf,
+ 0x109d0, 0x109d1, 0x109d2, 0x109d3, 0x109d4, 0x109d5, 0x109d6, 0x109d7,
+ 0x109d8, 0x109d9, 0x109da, 0x109db, 0x109dc, 0x109dd, 0x109de, 0x109df,
+ 0x109e0, 0x109e1, 0x109e2, 0x109e3, 0x109e4, 0x109e5, 0x109e6, 0x109e7,
+ 0x109e8, 0x109e9, 0x109ea, 0x109eb, 0x109ec, 0x109ed, 0x109ee, 0x109ef,
+ 0x109f0, 0x109f1, 0x109f2, 0x109f3, 0x109f4, 0x109f5, 0x109f6, 0x109f7,
+ 0x109f8, 0x109f9, 0x109fa, 0x109fb, 0x109fc, 0x109fd, 0x109fe, 0x109ff
+};
+
+static uint32_t unicode_520_ci_page_10a[] = {
+ 0x10a00, 0x10a01, 0x10a02, 0x10a03, 0x10a04, 0x10a05, 0x10a06, 0x10a07,
+ 0x10a08, 0x10a09, 0x10a0a, 0x10a0b, 0x10a0c, 0x00000, 0x00000, 0x00000,
+ 0x10a10, 0x10a11, 0x10a12, 0x10a13, 0x10a14, 0x10a15, 0x10a16, 0x10a17,
+ 0x10a18, 0x10a19, 0x10a1a, 0x10a1b, 0x10a1c, 0x10a1d, 0x10a1e, 0x10a1f,
+ 0x10a20, 0x10a21, 0x10a22, 0x10a23, 0x10a24, 0x10a25, 0x10a26, 0x10a27,
+ 0x10a28, 0x10a29, 0x10a2a, 0x10a2b, 0x10a2c, 0x10a2d, 0x10a2e, 0x10a2f,
+ 0x10a30, 0x10a31, 0x10a32, 0x10a33, 0x10a34, 0x10a35, 0x10a36, 0x10a37,
+ 0x00000, 0x00000, 0x00000, 0x10a3b, 0x10a3c, 0x10a3d, 0x10a3e, 0x10a3f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x10a44, 0x10a45, 0x10a46, 0x10a47,
+ 0x10a48, 0x10a49, 0x10a4a, 0x10a4b, 0x10a4c, 0x10a4d, 0x10a4e, 0x10a4f,
+ 0x10a50, 0x10a51, 0x10a52, 0x10a53, 0x10a54, 0x10a55, 0x10a56, 0x10a57,
+ 0x10a58, 0x10a59, 0x10a5a, 0x10a5b, 0x10a5c, 0x10a5d, 0x10a5e, 0x10a5f,
+ 0x10a60, 0x10a61, 0x10a62, 0x10a63, 0x10a64, 0x10a65, 0x10a66, 0x10a67,
+ 0x10a68, 0x10a69, 0x10a6a, 0x10a6b, 0x10a6c, 0x10a6d, 0x10a6e, 0x10a6f,
+ 0x10a70, 0x10a71, 0x10a72, 0x10a73, 0x10a74, 0x10a75, 0x10a76, 0x10a77,
+ 0x10a78, 0x10a79, 0x10a7a, 0x10a7b, 0x10a7c, 0x00031, 0x10a7e, 0x10a7f,
+ 0x10a80, 0x10a81, 0x10a82, 0x10a83, 0x10a84, 0x10a85, 0x10a86, 0x10a87,
+ 0x10a88, 0x10a89, 0x10a8a, 0x10a8b, 0x10a8c, 0x10a8d, 0x10a8e, 0x10a8f,
+ 0x10a90, 0x10a91, 0x10a92, 0x10a93, 0x10a94, 0x10a95, 0x10a96, 0x10a97,
+ 0x10a98, 0x10a99, 0x10a9a, 0x10a9b, 0x10a9c, 0x10a9d, 0x10a9e, 0x10a9f,
+ 0x10aa0, 0x10aa1, 0x10aa2, 0x10aa3, 0x10aa4, 0x10aa5, 0x10aa6, 0x10aa7,
+ 0x10aa8, 0x10aa9, 0x10aaa, 0x10aab, 0x10aac, 0x10aad, 0x10aae, 0x10aaf,
+ 0x10ab0, 0x10ab1, 0x10ab2, 0x10ab3, 0x10ab4, 0x10ab5, 0x10ab6, 0x10ab7,
+ 0x10ab8, 0x10ab9, 0x10aba, 0x10abb, 0x10abc, 0x10abd, 0x10abe, 0x10abf,
+ 0x10ac0, 0x10ac1, 0x10ac2, 0x10ac3, 0x10ac4, 0x10ac5, 0x10ac6, 0x10ac7,
+ 0x10ac8, 0x10ac9, 0x10aca, 0x10acb, 0x10acc, 0x10acd, 0x10ace, 0x10acf,
+ 0x10ad0, 0x10ad1, 0x10ad2, 0x10ad3, 0x10ad4, 0x10ad5, 0x10ad6, 0x10ad7,
+ 0x10ad8, 0x10ad9, 0x10ada, 0x10adb, 0x10adc, 0x10add, 0x10ade, 0x10adf,
+ 0x10ae0, 0x10ae1, 0x10ae2, 0x10ae3, 0x10ae4, 0x10ae5, 0x10ae6, 0x10ae7,
+ 0x10ae8, 0x10ae9, 0x10aea, 0x10aeb, 0x10aec, 0x10aed, 0x10aee, 0x10aef,
+ 0x10af0, 0x10af1, 0x10af2, 0x10af3, 0x10af4, 0x10af5, 0x10af6, 0x10af7,
+ 0x10af8, 0x10af9, 0x10afa, 0x10afb, 0x10afc, 0x10afd, 0x10afe, 0x10aff
+};
+
+static uint32_t unicode_520_ci_page_10b[] = {
+ 0x10b00, 0x10b01, 0x10b02, 0x10b03, 0x10b04, 0x10b05, 0x10b06, 0x10b07,
+ 0x10b08, 0x10b09, 0x10b0a, 0x10b0b, 0x10b0c, 0x10b0d, 0x10b0e, 0x10b0f,
+ 0x10b10, 0x10b11, 0x10b12, 0x10b13, 0x10b14, 0x10b15, 0x10b16, 0x10b17,
+ 0x10b18, 0x10b19, 0x10b1a, 0x10b1b, 0x10b1c, 0x10b1d, 0x10b1e, 0x10b1f,
+ 0x10b20, 0x10b21, 0x10b22, 0x10b23, 0x10b24, 0x10b25, 0x10b26, 0x10b27,
+ 0x10b28, 0x10b29, 0x10b2a, 0x10b2b, 0x10b2c, 0x10b2d, 0x10b2d, 0x10b2f,
+ 0x10b30, 0x10b31, 0x10b32, 0x10b33, 0x10b34, 0x10b35, 0x10b36, 0x10b37,
+ 0x10b38, 0x10b39, 0x10b3a, 0x10b3b, 0x10b3c, 0x10b3d, 0x10b3e, 0x10b3f,
+ 0x10b40, 0x10b41, 0x10b42, 0x10b43, 0x10b44, 0x10b45, 0x10b46, 0x10b47,
+ 0x10b48, 0x10b49, 0x10b4a, 0x10b4b, 0x10b4c, 0x10b4d, 0x10b4e, 0x10b4f,
+ 0x10b50, 0x10b51, 0x10b52, 0x10b53, 0x10b54, 0x10b55, 0x10b56, 0x10b57,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x10b5c, 0x10b5d, 0x10b5e, 0x10b5f,
+ 0x10b60, 0x10b61, 0x10b62, 0x10b63, 0x10b64, 0x10b65, 0x10b66, 0x10b67,
+ 0x10b68, 0x10b69, 0x10b6a, 0x10b6b, 0x10b6c, 0x10b6d, 0x10b6e, 0x10b6f,
+ 0x10b70, 0x10b71, 0x10b72, 0x10b73, 0x10b74, 0x10b75, 0x10b76, 0x10b77,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x10b7c, 0x10b7d, 0x10b7e, 0x10b7f,
+ 0x10b80, 0x10b81, 0x10b82, 0x10b83, 0x10b84, 0x10b85, 0x10b86, 0x10b87,
+ 0x10b88, 0x10b89, 0x10b8a, 0x10b8b, 0x10b8c, 0x10b8d, 0x10b8e, 0x10b8f,
+ 0x10b90, 0x10b91, 0x10b92, 0x10b93, 0x10b94, 0x10b95, 0x10b96, 0x10b97,
+ 0x10b98, 0x10b99, 0x10b9a, 0x10b9b, 0x10b9c, 0x10b9d, 0x10b9e, 0x10b9f,
+ 0x10ba0, 0x10ba1, 0x10ba2, 0x10ba3, 0x10ba4, 0x10ba5, 0x10ba6, 0x10ba7,
+ 0x10ba8, 0x10ba9, 0x10baa, 0x10bab, 0x10bac, 0x10bad, 0x10bae, 0x10baf,
+ 0x10bb0, 0x10bb1, 0x10bb2, 0x10bb3, 0x10bb4, 0x10bb5, 0x10bb6, 0x10bb7,
+ 0x10bb8, 0x10bb9, 0x10bba, 0x10bbb, 0x10bbc, 0x10bbd, 0x10bbe, 0x10bbf,
+ 0x10bc0, 0x10bc1, 0x10bc2, 0x10bc3, 0x10bc4, 0x10bc5, 0x10bc6, 0x10bc7,
+ 0x10bc8, 0x10bc9, 0x10bca, 0x10bcb, 0x10bcc, 0x10bcd, 0x10bce, 0x10bcf,
+ 0x10bd0, 0x10bd1, 0x10bd2, 0x10bd3, 0x10bd4, 0x10bd5, 0x10bd6, 0x10bd7,
+ 0x10bd8, 0x10bd9, 0x10bda, 0x10bdb, 0x10bdc, 0x10bdd, 0x10bde, 0x10bdf,
+ 0x10be0, 0x10be1, 0x10be2, 0x10be3, 0x10be4, 0x10be5, 0x10be6, 0x10be7,
+ 0x10be8, 0x10be9, 0x10bea, 0x10beb, 0x10bec, 0x10bed, 0x10bee, 0x10bef,
+ 0x10bf0, 0x10bf1, 0x10bf2, 0x10bf3, 0x10bf4, 0x10bf5, 0x10bf6, 0x10bf7,
+ 0x10bf8, 0x10bf9, 0x10bfa, 0x10bfb, 0x10bfc, 0x10bfd, 0x10bfe, 0x10bff
+};
+
+static uint32_t unicode_520_ci_page_10c[] = {
+ 0x10c00, 0x10c00, 0x10c02, 0x10c03, 0x10c03, 0x10c05, 0x10c06, 0x10c07,
+ 0x10c07, 0x10c09, 0x10c09, 0x10c0b, 0x10c0b, 0x10c0d, 0x10c0d, 0x10c0f,
+ 0x10c0f, 0x10c11, 0x10c11, 0x10c13, 0x10c14, 0x10c14, 0x10c16, 0x10c16,
+ 0x10c18, 0x10c18, 0x10c1a, 0x10c1a, 0x10c1c, 0x10c1c, 0x10c1e, 0x10c1e,
+ 0x10c20, 0x10c21, 0x10c22, 0x10c23, 0x10c24, 0x10c24, 0x10c26, 0x10c26,
+ 0x10c28, 0x10c28, 0x10c2a, 0x10c2a, 0x10c2c, 0x10c2d, 0x10c2d, 0x10c2f,
+ 0x10c30, 0x10c31, 0x10c32, 0x10c32, 0x10c34, 0x10c34, 0x10c36, 0x10c36,
+ 0x10c38, 0x10c38, 0x10c3a, 0x10c3a, 0x10c3c, 0x10c3d, 0x10c3e, 0x10c3f,
+ 0x10c3f, 0x10c41, 0x10c41, 0x10c43, 0x10c43, 0x10c45, 0x10c45, 0x10c47,
+ 0x10c48, 0x10c49, 0x10c4a, 0x10c4b, 0x10c4c, 0x10c4d, 0x10c4e, 0x10c4f,
+ 0x10c50, 0x10c51, 0x10c52, 0x10c53, 0x10c54, 0x10c55, 0x10c56, 0x10c57,
+ 0x10c58, 0x10c59, 0x10c5a, 0x10c5b, 0x10c5c, 0x10c5d, 0x10c5e, 0x10c5f,
+ 0x10c60, 0x10c61, 0x10c62, 0x10c63, 0x10c64, 0x10c65, 0x10c66, 0x10c67,
+ 0x10c68, 0x10c69, 0x10c6a, 0x10c6b, 0x10c6c, 0x10c6d, 0x10c6e, 0x10c6f,
+ 0x10c70, 0x10c71, 0x10c72, 0x10c73, 0x10c74, 0x10c75, 0x10c76, 0x10c77,
+ 0x10c78, 0x10c79, 0x10c7a, 0x10c7b, 0x10c7c, 0x10c7d, 0x10c7e, 0x10c7f,
+ 0x10c80, 0x10c81, 0x10c82, 0x10c83, 0x10c84, 0x10c85, 0x10c86, 0x10c87,
+ 0x10c88, 0x10c89, 0x10c8a, 0x10c8b, 0x10c8c, 0x10c8d, 0x10c8e, 0x10c8f,
+ 0x10c90, 0x10c91, 0x10c92, 0x10c93, 0x10c94, 0x10c95, 0x10c96, 0x10c97,
+ 0x10c98, 0x10c99, 0x10c9a, 0x10c9b, 0x10c9c, 0x10c9d, 0x10c9e, 0x10c9f,
+ 0x10ca0, 0x10ca1, 0x10ca2, 0x10ca3, 0x10ca4, 0x10ca5, 0x10ca6, 0x10ca7,
+ 0x10ca8, 0x10ca9, 0x10caa, 0x10cab, 0x10cac, 0x10cad, 0x10cae, 0x10caf,
+ 0x10cb0, 0x10cb1, 0x10cb2, 0x10cb3, 0x10cb4, 0x10cb5, 0x10cb6, 0x10cb7,
+ 0x10cb8, 0x10cb9, 0x10cba, 0x10cbb, 0x10cbc, 0x10cbd, 0x10cbe, 0x10cbf,
+ 0x10cc0, 0x10cc1, 0x10cc2, 0x10cc3, 0x10cc4, 0x10cc5, 0x10cc6, 0x10cc7,
+ 0x10cc8, 0x10cc9, 0x10cca, 0x10ccb, 0x10ccc, 0x10ccd, 0x10cce, 0x10ccf,
+ 0x10cd0, 0x10cd1, 0x10cd2, 0x10cd3, 0x10cd4, 0x10cd5, 0x10cd6, 0x10cd7,
+ 0x10cd8, 0x10cd9, 0x10cda, 0x10cdb, 0x10cdc, 0x10cdd, 0x10cde, 0x10cdf,
+ 0x10ce0, 0x10ce1, 0x10ce2, 0x10ce3, 0x10ce4, 0x10ce5, 0x10ce6, 0x10ce7,
+ 0x10ce8, 0x10ce9, 0x10cea, 0x10ceb, 0x10cec, 0x10ced, 0x10cee, 0x10cef,
+ 0x10cf0, 0x10cf1, 0x10cf2, 0x10cf3, 0x10cf4, 0x10cf5, 0x10cf6, 0x10cf7,
+ 0x10cf8, 0x10cf9, 0x10cfa, 0x10cfb, 0x10cfc, 0x10cfd, 0x10cfe, 0x10cff
+};
+
+static uint32_t unicode_520_ci_page_10e[] = {
+ 0x10e00, 0x10e01, 0x10e02, 0x10e03, 0x10e04, 0x10e05, 0x10e06, 0x10e07,
+ 0x10e08, 0x10e09, 0x10e0a, 0x10e0b, 0x10e0c, 0x10e0d, 0x10e0e, 0x10e0f,
+ 0x10e10, 0x10e11, 0x10e12, 0x10e13, 0x10e14, 0x10e15, 0x10e16, 0x10e17,
+ 0x10e18, 0x10e19, 0x10e1a, 0x10e1b, 0x10e1c, 0x10e1d, 0x10e1e, 0x10e1f,
+ 0x10e20, 0x10e21, 0x10e22, 0x10e23, 0x10e24, 0x10e25, 0x10e26, 0x10e27,
+ 0x10e28, 0x10e29, 0x10e2a, 0x10e2b, 0x10e2c, 0x10e2d, 0x10e2e, 0x10e2f,
+ 0x10e30, 0x10e31, 0x10e32, 0x10e33, 0x10e34, 0x10e35, 0x10e36, 0x10e37,
+ 0x10e38, 0x10e39, 0x10e3a, 0x10e3b, 0x10e3c, 0x10e3d, 0x10e3e, 0x10e3f,
+ 0x10e40, 0x10e41, 0x10e42, 0x10e43, 0x10e44, 0x10e45, 0x10e46, 0x10e47,
+ 0x10e48, 0x10e49, 0x10e4a, 0x10e4b, 0x10e4c, 0x10e4d, 0x10e4e, 0x10e4f,
+ 0x10e50, 0x10e51, 0x10e52, 0x10e53, 0x10e54, 0x10e55, 0x10e56, 0x10e57,
+ 0x10e58, 0x10e59, 0x10e5a, 0x10e5b, 0x10e5c, 0x10e5d, 0x10e5e, 0x10e5f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x10e69, 0x10e6a, 0x10e6b, 0x10e6c, 0x10e6d, 0x10e6e, 0x10e6f,
+ 0x10e70, 0x10e71, 0x10e72, 0x10e73, 0x10e74, 0x10e75, 0x10e76, 0x10e77,
+ 0x10e78, 0x10e79, 0x10e7a, 0x10e7b, 0x10e7c, 0x10e7d, 0x10e7e, 0x10e7f,
+ 0x10e80, 0x10e81, 0x10e82, 0x10e83, 0x10e84, 0x10e85, 0x10e86, 0x10e87,
+ 0x10e88, 0x10e89, 0x10e8a, 0x10e8b, 0x10e8c, 0x10e8d, 0x10e8e, 0x10e8f,
+ 0x10e90, 0x10e91, 0x10e92, 0x10e93, 0x10e94, 0x10e95, 0x10e96, 0x10e97,
+ 0x10e98, 0x10e99, 0x10e9a, 0x10e9b, 0x10e9c, 0x10e9d, 0x10e9e, 0x10e9f,
+ 0x10ea0, 0x10ea1, 0x10ea2, 0x10ea3, 0x10ea4, 0x10ea5, 0x10ea6, 0x10ea7,
+ 0x10ea8, 0x10ea9, 0x10eaa, 0x10eab, 0x10eac, 0x10ead, 0x10eae, 0x10eaf,
+ 0x10eb0, 0x10eb1, 0x10eb2, 0x10eb3, 0x10eb4, 0x10eb5, 0x10eb6, 0x10eb7,
+ 0x10eb8, 0x10eb9, 0x10eba, 0x10ebb, 0x10ebc, 0x10ebd, 0x10ebe, 0x10ebf,
+ 0x10ec0, 0x10ec1, 0x10ec2, 0x10ec3, 0x10ec4, 0x10ec5, 0x10ec6, 0x10ec7,
+ 0x10ec8, 0x10ec9, 0x10eca, 0x10ecb, 0x10ecc, 0x10ecd, 0x10ece, 0x10ecf,
+ 0x10ed0, 0x10ed1, 0x10ed2, 0x10ed3, 0x10ed4, 0x10ed5, 0x10ed6, 0x10ed7,
+ 0x10ed8, 0x10ed9, 0x10eda, 0x10edb, 0x10edc, 0x10edd, 0x10ede, 0x10edf,
+ 0x10ee0, 0x10ee1, 0x10ee2, 0x10ee3, 0x10ee4, 0x10ee5, 0x10ee6, 0x10ee7,
+ 0x10ee8, 0x10ee9, 0x10eea, 0x10eeb, 0x10eec, 0x10eed, 0x10eee, 0x10eef,
+ 0x10ef0, 0x10ef1, 0x10ef2, 0x10ef3, 0x10ef4, 0x10ef5, 0x10ef6, 0x10ef7,
+ 0x10ef8, 0x10ef9, 0x10efa, 0x10efb, 0x10efc, 0x10efd, 0x10efe, 0x10eff
+};
+
+static uint32_t unicode_520_ci_page_110[] = {
+ 0x11000, 0x11001, 0x11002, 0x11003, 0x11004, 0x11005, 0x11006, 0x11007,
+ 0x11008, 0x11009, 0x1100a, 0x1100b, 0x1100c, 0x1100d, 0x1100e, 0x1100f,
+ 0x11010, 0x11011, 0x11012, 0x11013, 0x11014, 0x11015, 0x11016, 0x11017,
+ 0x11018, 0x11019, 0x1101a, 0x1101b, 0x1101c, 0x1101d, 0x1101e, 0x1101f,
+ 0x11020, 0x11021, 0x11022, 0x11023, 0x11024, 0x11025, 0x11026, 0x11027,
+ 0x11028, 0x11029, 0x1102a, 0x1102b, 0x1102c, 0x1102d, 0x1102e, 0x1102f,
+ 0x11030, 0x11031, 0x11032, 0x11033, 0x11034, 0x11035, 0x11036, 0x11037,
+ 0x11038, 0x11039, 0x1103a, 0x1103b, 0x1103c, 0x1103d, 0x1103e, 0x1103f,
+ 0x11040, 0x11041, 0x11042, 0x11043, 0x11044, 0x11045, 0x11046, 0x11047,
+ 0x11048, 0x11049, 0x1104a, 0x1104b, 0x1104c, 0x1104d, 0x1104e, 0x1104f,
+ 0x11050, 0x11051, 0x11052, 0x11053, 0x11054, 0x11055, 0x11056, 0x11057,
+ 0x11058, 0x11059, 0x1105a, 0x1105b, 0x1105c, 0x1105d, 0x1105e, 0x1105f,
+ 0x11060, 0x11061, 0x11062, 0x11063, 0x11064, 0x11065, 0x11066, 0x11067,
+ 0x11068, 0x11069, 0x1106a, 0x1106b, 0x1106c, 0x1106d, 0x1106e, 0x1106f,
+ 0x11070, 0x11071, 0x11072, 0x11073, 0x11074, 0x11075, 0x11076, 0x11077,
+ 0x11078, 0x11079, 0x1107a, 0x1107b, 0x1107c, 0x1107d, 0x1107e, 0x1107f,
+ 0x00000, 0x00000, 0x00000, 0x11083, 0x11084, 0x11085, 0x11086, 0x11087,
+ 0x11088, 0x11089, 0x1108a, 0x1108b, 0x1108c, 0x1108d, 0x1108e, 0x1108f,
+ 0x11090, 0x11091, 0x11092, 0x11093, 0x11094, 0x11095, 0x11096, 0x11097,
+ 0x11098, 0x11099, 0x11099, 0x1109b, 0x1109b, 0x1109d, 0x1109e, 0x1109f,
+ 0x110a0, 0x110a1, 0x110a2, 0x110a3, 0x110a4, 0x110a5, 0x110a6, 0x110a7,
+ 0x110a8, 0x110a9, 0x110aa, 0x110a5, 0x110ac, 0x110ad, 0x110ae, 0x110af,
+ 0x110b0, 0x110b1, 0x110b2, 0x110b3, 0x110b4, 0x110b5, 0x110b6, 0x110b7,
+ 0x110b8, 0x110b9, 0x00000, 0x110bb, 0x110bc, 0x00000, 0x110be, 0x110bf,
+ 0x110c0, 0x110c1, 0x110c2, 0x110c3, 0x110c4, 0x110c5, 0x110c6, 0x110c7,
+ 0x110c8, 0x110c9, 0x110ca, 0x110cb, 0x110cc, 0x110cd, 0x110ce, 0x110cf,
+ 0x110d0, 0x110d1, 0x110d2, 0x110d3, 0x110d4, 0x110d5, 0x110d6, 0x110d7,
+ 0x110d8, 0x110d9, 0x110da, 0x110db, 0x110dc, 0x110dd, 0x110de, 0x110df,
+ 0x110e0, 0x110e1, 0x110e2, 0x110e3, 0x110e4, 0x110e5, 0x110e6, 0x110e7,
+ 0x110e8, 0x110e9, 0x110ea, 0x110eb, 0x110ec, 0x110ed, 0x110ee, 0x110ef,
+ 0x110f0, 0x110f1, 0x110f2, 0x110f3, 0x110f4, 0x110f5, 0x110f6, 0x110f7,
+ 0x110f8, 0x110f9, 0x110fa, 0x110fb, 0x110fc, 0x110fd, 0x110fe, 0x110ff
+};
+
+static uint32_t unicode_520_ci_page_124[] = {
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00034,
+ 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00031, 0x00032,
+ 0x00033, 0x00034, 0x00035, 0x00032, 0x00033, 0x00033, 0x00034, 0x00035,
+ 0x00036, 0x00037, 0x00038, 0x00039, 0x00031, 0x00032, 0x00033, 0x00033,
+ 0x00034, 0x00035, 0x12432, 0x12433, 0x00031, 0x00032, 0x00033, 0x00033,
+ 0x00034, 0x00035, 0x00033, 0x00033, 0x00034, 0x00034, 0x00034, 0x00034,
+ 0x00036, 0x00037, 0x00037, 0x00037, 0x00038, 0x00038, 0x00039, 0x00039,
+ 0x00039, 0x00039, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, 0x12456, 0x12457,
+ 0x00031, 0x00032, 0x1245a, 0x1245b, 0x1245c, 0x1245d, 0x1245e, 0x1245f,
+ 0x12460, 0x12461, 0x12462, 0x12463, 0x12464, 0x12465, 0x12466, 0x12467,
+ 0x12468, 0x12469, 0x1246a, 0x1246b, 0x1246c, 0x1246d, 0x1246e, 0x1246f,
+ 0x12470, 0x12471, 0x12472, 0x12473, 0x12474, 0x12475, 0x12476, 0x12477,
+ 0x12478, 0x12479, 0x1247a, 0x1247b, 0x1247c, 0x1247d, 0x1247e, 0x1247f,
+ 0x12480, 0x12481, 0x12482, 0x12483, 0x12484, 0x12485, 0x12486, 0x12487,
+ 0x12488, 0x12489, 0x1248a, 0x1248b, 0x1248c, 0x1248d, 0x1248e, 0x1248f,
+ 0x12490, 0x12491, 0x12492, 0x12493, 0x12494, 0x12495, 0x12496, 0x12497,
+ 0x12498, 0x12499, 0x1249a, 0x1249b, 0x1249c, 0x1249d, 0x1249e, 0x1249f,
+ 0x124a0, 0x124a1, 0x124a2, 0x124a3, 0x124a4, 0x124a5, 0x124a6, 0x124a7,
+ 0x124a8, 0x124a9, 0x124aa, 0x124ab, 0x124ac, 0x124ad, 0x124ae, 0x124af,
+ 0x124b0, 0x124b1, 0x124b2, 0x124b3, 0x124b4, 0x124b5, 0x124b6, 0x124b7,
+ 0x124b8, 0x124b9, 0x124ba, 0x124bb, 0x124bc, 0x124bd, 0x124be, 0x124bf,
+ 0x124c0, 0x124c1, 0x124c2, 0x124c3, 0x124c4, 0x124c5, 0x124c6, 0x124c7,
+ 0x124c8, 0x124c9, 0x124ca, 0x124cb, 0x124cc, 0x124cd, 0x124ce, 0x124cf,
+ 0x124d0, 0x124d1, 0x124d2, 0x124d3, 0x124d4, 0x124d5, 0x124d6, 0x124d7,
+ 0x124d8, 0x124d9, 0x124da, 0x124db, 0x124dc, 0x124dd, 0x124de, 0x124df,
+ 0x124e0, 0x124e1, 0x124e2, 0x124e3, 0x124e4, 0x124e5, 0x124e6, 0x124e7,
+ 0x124e8, 0x124e9, 0x124ea, 0x124eb, 0x124ec, 0x124ed, 0x124ee, 0x124ef,
+ 0x124f0, 0x124f1, 0x124f2, 0x124f3, 0x124f4, 0x124f5, 0x124f6, 0x124f7,
+ 0x124f8, 0x124f9, 0x124fa, 0x124fb, 0x124fc, 0x124fd, 0x124fe, 0x124ff
+};
+
+static uint32_t unicode_520_ci_page_1d1[] = {
+ 0x1d100, 0x1d101, 0x1d102, 0x1d103, 0x1d104, 0x1d105, 0x1d106, 0x1d107,
+ 0x1d108, 0x1d109, 0x1d10a, 0x1d10b, 0x1d10c, 0x1d10d, 0x1d10e, 0x1d10f,
+ 0x1d110, 0x1d111, 0x1d112, 0x1d113, 0x1d114, 0x1d115, 0x1d116, 0x1d117,
+ 0x1d118, 0x1d119, 0x1d11a, 0x1d11b, 0x1d11c, 0x1d11d, 0x1d11e, 0x1d11f,
+ 0x1d120, 0x1d121, 0x1d122, 0x1d123, 0x1d124, 0x1d125, 0x1d126, 0x1d127,
+ 0x1d128, 0x1d129, 0x1d12a, 0x1d12b, 0x1d12c, 0x1d12d, 0x1d12e, 0x1d12f,
+ 0x1d130, 0x1d131, 0x1d132, 0x1d133, 0x1d134, 0x1d135, 0x1d136, 0x1d137,
+ 0x1d138, 0x1d139, 0x1d13a, 0x1d13b, 0x1d13c, 0x1d13d, 0x1d13e, 0x1d13f,
+ 0x1d140, 0x1d141, 0x1d142, 0x1d143, 0x1d144, 0x1d145, 0x1d146, 0x1d147,
+ 0x1d148, 0x1d149, 0x1d14a, 0x1d14b, 0x1d14c, 0x1d14d, 0x1d14e, 0x1d14f,
+ 0x1d150, 0x1d151, 0x1d152, 0x1d153, 0x1d154, 0x1d155, 0x1d156, 0x1d157,
+ 0x1d158, 0x1d159, 0x1d15a, 0x1d15b, 0x1d15c, 0x1d15d, 0x1d157, 0x1d158,
+ 0x1d158, 0x1d158, 0x1d158, 0x1d158, 0x1d158, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x1d16a, 0x1d16b, 0x1d16c, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x1d183, 0x1d184, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x1d18c, 0x1d18d, 0x1d18e, 0x1d18f,
+ 0x1d190, 0x1d191, 0x1d192, 0x1d193, 0x1d194, 0x1d195, 0x1d196, 0x1d197,
+ 0x1d198, 0x1d199, 0x1d19a, 0x1d19b, 0x1d19c, 0x1d19d, 0x1d19e, 0x1d19f,
+ 0x1d1a0, 0x1d1a1, 0x1d1a2, 0x1d1a3, 0x1d1a4, 0x1d1a5, 0x1d1a6, 0x1d1a7,
+ 0x1d1a8, 0x1d1a9, 0x00000, 0x00000, 0x00000, 0x00000, 0x1d1ae, 0x1d1af,
+ 0x1d1b0, 0x1d1b1, 0x1d1b2, 0x1d1b3, 0x1d1b4, 0x1d1b5, 0x1d1b6, 0x1d1b7,
+ 0x1d1b8, 0x1d1b9, 0x1d1ba, 0x1d1b9, 0x1d1ba, 0x1d1b9, 0x1d1ba, 0x1d1b9,
+ 0x1d1ba, 0x1d1c1, 0x1d1c2, 0x1d1c3, 0x1d1c4, 0x1d1c5, 0x1d1c6, 0x1d1c7,
+ 0x1d1c8, 0x1d1c9, 0x1d1ca, 0x1d1cb, 0x1d1cc, 0x1d1cd, 0x1d1ce, 0x1d1cf,
+ 0x1d1d0, 0x1d1d1, 0x1d1d2, 0x1d1d3, 0x1d1d4, 0x1d1d5, 0x1d1d6, 0x1d1d7,
+ 0x1d1d8, 0x1d1d9, 0x1d1da, 0x1d1db, 0x1d1dc, 0x1d1dd, 0x1d1de, 0x1d1df,
+ 0x1d1e0, 0x1d1e1, 0x1d1e2, 0x1d1e3, 0x1d1e4, 0x1d1e5, 0x1d1e6, 0x1d1e7,
+ 0x1d1e8, 0x1d1e9, 0x1d1ea, 0x1d1eb, 0x1d1ec, 0x1d1ed, 0x1d1ee, 0x1d1ef,
+ 0x1d1f0, 0x1d1f1, 0x1d1f2, 0x1d1f3, 0x1d1f4, 0x1d1f5, 0x1d1f6, 0x1d1f7,
+ 0x1d1f8, 0x1d1f9, 0x1d1fa, 0x1d1fb, 0x1d1fc, 0x1d1fd, 0x1d1fe, 0x1d1ff
+};
+
+static uint32_t unicode_520_ci_page_1d2[] = {
+ 0x1d200, 0x1d201, 0x1d202, 0x1d203, 0x1d204, 0x1d205, 0x1d206, 0x1d207,
+ 0x1d208, 0x1d209, 0x1d20a, 0x1d20b, 0x1d20c, 0x1d20d, 0x1d20e, 0x1d20f,
+ 0x1d210, 0x1d211, 0x1d212, 0x1d213, 0x1d214, 0x1d215, 0x1d216, 0x1d217,
+ 0x1d218, 0x1d219, 0x1d21a, 0x1d21b, 0x1d21c, 0x1d21d, 0x1d21e, 0x1d21f,
+ 0x1d220, 0x1d221, 0x1d222, 0x1d223, 0x1d224, 0x1d225, 0x1d226, 0x1d227,
+ 0x1d228, 0x1d229, 0x1d22a, 0x1d22b, 0x1d22c, 0x1d22d, 0x1d22e, 0x1d22f,
+ 0x1d230, 0x1d231, 0x1d232, 0x1d233, 0x1d234, 0x1d235, 0x1d236, 0x1d237,
+ 0x1d238, 0x1d239, 0x1d23a, 0x1d23b, 0x1d23c, 0x1d23d, 0x1d23e, 0x1d23f,
+ 0x1d240, 0x1d241, 0x00000, 0x00000, 0x00000, 0x1d245, 0x1d246, 0x1d247,
+ 0x1d248, 0x1d249, 0x1d24a, 0x1d24b, 0x1d24c, 0x1d24d, 0x1d24e, 0x1d24f,
+ 0x1d250, 0x1d251, 0x1d252, 0x1d253, 0x1d254, 0x1d255, 0x1d256, 0x1d257,
+ 0x1d258, 0x1d259, 0x1d25a, 0x1d25b, 0x1d25c, 0x1d25d, 0x1d25e, 0x1d25f,
+ 0x1d260, 0x1d261, 0x1d262, 0x1d263, 0x1d264, 0x1d265, 0x1d266, 0x1d267,
+ 0x1d268, 0x1d269, 0x1d26a, 0x1d26b, 0x1d26c, 0x1d26d, 0x1d26e, 0x1d26f,
+ 0x1d270, 0x1d271, 0x1d272, 0x1d273, 0x1d274, 0x1d275, 0x1d276, 0x1d277,
+ 0x1d278, 0x1d279, 0x1d27a, 0x1d27b, 0x1d27c, 0x1d27d, 0x1d27e, 0x1d27f,
+ 0x1d280, 0x1d281, 0x1d282, 0x1d283, 0x1d284, 0x1d285, 0x1d286, 0x1d287,
+ 0x1d288, 0x1d289, 0x1d28a, 0x1d28b, 0x1d28c, 0x1d28d, 0x1d28e, 0x1d28f,
+ 0x1d290, 0x1d291, 0x1d292, 0x1d293, 0x1d294, 0x1d295, 0x1d296, 0x1d297,
+ 0x1d298, 0x1d299, 0x1d29a, 0x1d29b, 0x1d29c, 0x1d29d, 0x1d29e, 0x1d29f,
+ 0x1d2a0, 0x1d2a1, 0x1d2a2, 0x1d2a3, 0x1d2a4, 0x1d2a5, 0x1d2a6, 0x1d2a7,
+ 0x1d2a8, 0x1d2a9, 0x1d2aa, 0x1d2ab, 0x1d2ac, 0x1d2ad, 0x1d2ae, 0x1d2af,
+ 0x1d2b0, 0x1d2b1, 0x1d2b2, 0x1d2b3, 0x1d2b4, 0x1d2b5, 0x1d2b6, 0x1d2b7,
+ 0x1d2b8, 0x1d2b9, 0x1d2ba, 0x1d2bb, 0x1d2bc, 0x1d2bd, 0x1d2be, 0x1d2bf,
+ 0x1d2c0, 0x1d2c1, 0x1d2c2, 0x1d2c3, 0x1d2c4, 0x1d2c5, 0x1d2c6, 0x1d2c7,
+ 0x1d2c8, 0x1d2c9, 0x1d2ca, 0x1d2cb, 0x1d2cc, 0x1d2cd, 0x1d2ce, 0x1d2cf,
+ 0x1d2d0, 0x1d2d1, 0x1d2d2, 0x1d2d3, 0x1d2d4, 0x1d2d5, 0x1d2d6, 0x1d2d7,
+ 0x1d2d8, 0x1d2d9, 0x1d2da, 0x1d2db, 0x1d2dc, 0x1d2dd, 0x1d2de, 0x1d2df,
+ 0x1d2e0, 0x1d2e1, 0x1d2e2, 0x1d2e3, 0x1d2e4, 0x1d2e5, 0x1d2e6, 0x1d2e7,
+ 0x1d2e8, 0x1d2e9, 0x1d2ea, 0x1d2eb, 0x1d2ec, 0x1d2ed, 0x1d2ee, 0x1d2ef,
+ 0x1d2f0, 0x1d2f1, 0x1d2f2, 0x1d2f3, 0x1d2f4, 0x1d2f5, 0x1d2f6, 0x1d2f7,
+ 0x1d2f8, 0x1d2f9, 0x1d2fa, 0x1d2fb, 0x1d2fc, 0x1d2fd, 0x1d2fe, 0x1d2ff
+};
+
+static uint32_t unicode_520_ci_page_1d3[] = {
+ 0x1d300, 0x1d301, 0x1d302, 0x1d303, 0x1d304, 0x1d305, 0x1d306, 0x1d307,
+ 0x1d308, 0x1d309, 0x1d30a, 0x1d30b, 0x1d30c, 0x1d30d, 0x1d30e, 0x1d30f,
+ 0x1d310, 0x1d311, 0x1d312, 0x1d313, 0x1d314, 0x1d315, 0x1d316, 0x1d317,
+ 0x1d318, 0x1d319, 0x1d31a, 0x1d31b, 0x1d31c, 0x1d31d, 0x1d31e, 0x1d31f,
+ 0x1d320, 0x1d321, 0x1d322, 0x1d323, 0x1d324, 0x1d325, 0x1d326, 0x1d327,
+ 0x1d328, 0x1d329, 0x1d32a, 0x1d32b, 0x1d32c, 0x1d32d, 0x1d32e, 0x1d32f,
+ 0x1d330, 0x1d331, 0x1d332, 0x1d333, 0x1d334, 0x1d335, 0x1d336, 0x1d337,
+ 0x1d338, 0x1d339, 0x1d33a, 0x1d33b, 0x1d33c, 0x1d33d, 0x1d33e, 0x1d33f,
+ 0x1d340, 0x1d341, 0x1d342, 0x1d343, 0x1d344, 0x1d345, 0x1d346, 0x1d347,
+ 0x1d348, 0x1d349, 0x1d34a, 0x1d34b, 0x1d34c, 0x1d34d, 0x1d34e, 0x1d34f,
+ 0x1d350, 0x1d351, 0x1d352, 0x1d353, 0x1d354, 0x1d355, 0x1d356, 0x1d357,
+ 0x1d358, 0x1d359, 0x1d35a, 0x1d35b, 0x1d35c, 0x1d35d, 0x1d35e, 0x1d35f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x1d369, 0x1d36a, 0x1d36b, 0x1d36c, 0x1d36d, 0x1d36e, 0x1d36f,
+ 0x1d370, 0x1d371, 0x1d372, 0x1d373, 0x1d374, 0x1d375, 0x1d376, 0x1d377,
+ 0x1d378, 0x1d379, 0x1d37a, 0x1d37b, 0x1d37c, 0x1d37d, 0x1d37e, 0x1d37f,
+ 0x1d380, 0x1d381, 0x1d382, 0x1d383, 0x1d384, 0x1d385, 0x1d386, 0x1d387,
+ 0x1d388, 0x1d389, 0x1d38a, 0x1d38b, 0x1d38c, 0x1d38d, 0x1d38e, 0x1d38f,
+ 0x1d390, 0x1d391, 0x1d392, 0x1d393, 0x1d394, 0x1d395, 0x1d396, 0x1d397,
+ 0x1d398, 0x1d399, 0x1d39a, 0x1d39b, 0x1d39c, 0x1d39d, 0x1d39e, 0x1d39f,
+ 0x1d3a0, 0x1d3a1, 0x1d3a2, 0x1d3a3, 0x1d3a4, 0x1d3a5, 0x1d3a6, 0x1d3a7,
+ 0x1d3a8, 0x1d3a9, 0x1d3aa, 0x1d3ab, 0x1d3ac, 0x1d3ad, 0x1d3ae, 0x1d3af,
+ 0x1d3b0, 0x1d3b1, 0x1d3b2, 0x1d3b3, 0x1d3b4, 0x1d3b5, 0x1d3b6, 0x1d3b7,
+ 0x1d3b8, 0x1d3b9, 0x1d3ba, 0x1d3bb, 0x1d3bc, 0x1d3bd, 0x1d3be, 0x1d3bf,
+ 0x1d3c0, 0x1d3c1, 0x1d3c2, 0x1d3c3, 0x1d3c4, 0x1d3c5, 0x1d3c6, 0x1d3c7,
+ 0x1d3c8, 0x1d3c9, 0x1d3ca, 0x1d3cb, 0x1d3cc, 0x1d3cd, 0x1d3ce, 0x1d3cf,
+ 0x1d3d0, 0x1d3d1, 0x1d3d2, 0x1d3d3, 0x1d3d4, 0x1d3d5, 0x1d3d6, 0x1d3d7,
+ 0x1d3d8, 0x1d3d9, 0x1d3da, 0x1d3db, 0x1d3dc, 0x1d3dd, 0x1d3de, 0x1d3df,
+ 0x1d3e0, 0x1d3e1, 0x1d3e2, 0x1d3e3, 0x1d3e4, 0x1d3e5, 0x1d3e6, 0x1d3e7,
+ 0x1d3e8, 0x1d3e9, 0x1d3ea, 0x1d3eb, 0x1d3ec, 0x1d3ed, 0x1d3ee, 0x1d3ef,
+ 0x1d3f0, 0x1d3f1, 0x1d3f2, 0x1d3f3, 0x1d3f4, 0x1d3f5, 0x1d3f6, 0x1d3f7,
+ 0x1d3f8, 0x1d3f9, 0x1d3fa, 0x1d3fb, 0x1d3fc, 0x1d3fd, 0x1d3fe, 0x1d3ff
+};
+
+static uint32_t unicode_520_ci_page_1d4[] = {
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x1d455, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x1d49d, 0x00043, 0x00044,
+ 0x1d4a0, 0x1d4a1, 0x00047, 0x1d4a3, 0x1d4a4, 0x0004a, 0x0004b, 0x1d4a7,
+ 0x1d4a8, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x1d4ad, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x1d4ba, 0x00046, 0x1d4bc, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x1d4c4, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x1d4ff
+};
+
+static uint32_t unicode_520_ci_page_1d5[] = {
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x1d506, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x1d50b, 0x1d50c, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x1d515, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x1d51d, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x1d53a, 0x00044, 0x00045, 0x00046, 0x00047, 0x1d53f,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x1d545, 0x0004f, 0x1d547,
+ 0x1d548, 0x1d549, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x1d551, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x1d5ff
+};
+
+static uint32_t unicode_520_ci_page_1d6[] = {
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044,
+ 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c,
+ 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054,
+ 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046,
+ 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e,
+ 0x0004f, 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056,
+ 0x00057, 0x00058, 0x00059, 0x0005a, 0x00131, 0x00237, 0x1d6a6, 0x1d6a7,
+ 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398,
+ 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0,
+ 0x003a1, 0x00398, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8,
+ 0x003a9, 0x02207, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396,
+ 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e,
+ 0x0039f, 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6,
+ 0x003a7, 0x003a8, 0x003a9, 0x02202, 0x00395, 0x00398, 0x0039a, 0x003a6,
+ 0x003a1, 0x003a0, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396,
+ 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e,
+ 0x0039f, 0x003a0, 0x003a1, 0x00398, 0x003a3, 0x003a4, 0x003a5, 0x003a6,
+ 0x003a7, 0x003a8, 0x003a9, 0x02207, 0x00391, 0x00392, 0x00393, 0x1d6ff
+};
+
+static uint32_t unicode_520_ci_page_1d7[] = {
+ 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c,
+ 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4,
+ 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02202, 0x00395, 0x00398,
+ 0x0039a, 0x003a6, 0x003a1, 0x003a0, 0x00391, 0x00392, 0x00393, 0x00394,
+ 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c,
+ 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x00398, 0x003a3, 0x003a4,
+ 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02207, 0x00391, 0x00392,
+ 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a,
+ 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x003a3,
+ 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02202,
+ 0x00395, 0x00398, 0x0039a, 0x003a6, 0x003a1, 0x003a0, 0x00391, 0x00392,
+ 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398, 0x00399, 0x0039a,
+ 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0, 0x003a1, 0x00398,
+ 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8, 0x003a9, 0x02207,
+ 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398,
+ 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0,
+ 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8,
+ 0x003a9, 0x02202, 0x00395, 0x00398, 0x0039a, 0x003a6, 0x003a1, 0x003a0,
+ 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397, 0x00398,
+ 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f, 0x003a0,
+ 0x003a1, 0x00398, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7, 0x003a8,
+ 0x003a9, 0x02207, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396,
+ 0x00397, 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e,
+ 0x0039f, 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6,
+ 0x003a7, 0x003a8, 0x003a9, 0x02202, 0x00395, 0x00398, 0x0039a, 0x003a6,
+ 0x003a1, 0x003a0, 0x003dc, 0x003dc, 0x1d7cc, 0x1d7cd, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035,
+ 0x00036, 0x00037, 0x00038, 0x00039, 0x00030, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x1d7ff
+};
+
+static uint32_t unicode_520_ci_page_1f1[] = {
+ 0x1f100, 0x1f101, 0x1f102, 0x1f103, 0x1f104, 0x1f105, 0x1f106, 0x1f107,
+ 0x1f108, 0x1f109, 0x1f10a, 0x1f10b, 0x1f10c, 0x1f10d, 0x1f10e, 0x1f10f,
+ 0x0249c, 0x0249d, 0x0249e, 0x0249f, 0x024a0, 0x024a1, 0x024a2, 0x024a3,
+ 0x024a4, 0x024a5, 0x024a6, 0x024a7, 0x024a8, 0x024a9, 0x024aa, 0x024ab,
+ 0x024ac, 0x024ad, 0x024ae, 0x024af, 0x024b0, 0x024b1, 0x024b2, 0x024b3,
+ 0x024b4, 0x024b5, 0x1f12a, 0x00043, 0x00052, 0x033c5, 0x1f12e, 0x1f12f,
+ 0x1f130, 0x00042, 0x1f132, 0x1f133, 0x1f134, 0x1f135, 0x1f136, 0x1f137,
+ 0x1f138, 0x1f139, 0x1f13a, 0x1f13b, 0x1f13c, 0x0004e, 0x1f13e, 0x00050,
+ 0x1f140, 0x1f141, 0x00053, 0x1f143, 0x1f144, 0x1f145, 0x00057, 0x1f147,
+ 0x1f148, 0x1f149, 0x1f14a, 0x033b7, 0x1f14c, 0x000df, 0x1f14e, 0x1f14f,
+ 0x1f150, 0x1f151, 0x1f152, 0x1f153, 0x1f154, 0x1f155, 0x1f156, 0x00048,
+ 0x1f158, 0x1f159, 0x1f15a, 0x1f15b, 0x1f15c, 0x1f15d, 0x1f15e, 0x00050,
+ 0x1f160, 0x1f161, 0x1f162, 0x1f163, 0x1f164, 0x1f165, 0x1f166, 0x1f167,
+ 0x1f168, 0x1f169, 0x1f16a, 0x1f16b, 0x1f16c, 0x1f16d, 0x1f16e, 0x1f16f,
+ 0x1f170, 0x1f171, 0x1f172, 0x1f173, 0x1f174, 0x1f175, 0x1f176, 0x1f177,
+ 0x1f178, 0x0004a, 0x1f17a, 0x0004c, 0x0004d, 0x1f17d, 0x1f17e, 0x00050,
+ 0x1f180, 0x1f181, 0x1f182, 0x1f183, 0x1f184, 0x1f185, 0x1f186, 0x1f187,
+ 0x1f188, 0x1f189, 0x00050, 0x1f18b, 0x03380, 0x1f18d, 0x1f18e, 0x1f18f,
+ 0x1f190, 0x1f191, 0x1f192, 0x1f193, 0x1f194, 0x1f195, 0x1f196, 0x1f197,
+ 0x1f198, 0x1f199, 0x1f19a, 0x1f19b, 0x1f19c, 0x1f19d, 0x1f19e, 0x1f19f,
+ 0x1f1a0, 0x1f1a1, 0x1f1a2, 0x1f1a3, 0x1f1a4, 0x1f1a5, 0x1f1a6, 0x1f1a7,
+ 0x1f1a8, 0x1f1a9, 0x1f1aa, 0x1f1ab, 0x1f1ac, 0x1f1ad, 0x1f1ae, 0x1f1af,
+ 0x1f1b0, 0x1f1b1, 0x1f1b2, 0x1f1b3, 0x1f1b4, 0x1f1b5, 0x1f1b6, 0x1f1b7,
+ 0x1f1b8, 0x1f1b9, 0x1f1ba, 0x1f1bb, 0x1f1bc, 0x1f1bd, 0x1f1be, 0x1f1bf,
+ 0x1f1c0, 0x1f1c1, 0x1f1c2, 0x1f1c3, 0x1f1c4, 0x1f1c5, 0x1f1c6, 0x1f1c7,
+ 0x1f1c8, 0x1f1c9, 0x1f1ca, 0x1f1cb, 0x1f1cc, 0x1f1cd, 0x1f1ce, 0x1f1cf,
+ 0x1f1d0, 0x1f1d1, 0x1f1d2, 0x1f1d3, 0x1f1d4, 0x1f1d5, 0x1f1d6, 0x1f1d7,
+ 0x1f1d8, 0x1f1d9, 0x1f1da, 0x1f1db, 0x1f1dc, 0x1f1dd, 0x1f1de, 0x1f1df,
+ 0x1f1e0, 0x1f1e1, 0x1f1e2, 0x1f1e3, 0x1f1e4, 0x1f1e5, 0x1f1e6, 0x1f1e7,
+ 0x1f1e8, 0x1f1e9, 0x1f1ea, 0x1f1eb, 0x1f1ec, 0x1f1ed, 0x1f1ee, 0x1f1ef,
+ 0x1f1f0, 0x1f1f1, 0x1f1f2, 0x1f1f3, 0x1f1f4, 0x1f1f5, 0x1f1f6, 0x1f1f7,
+ 0x1f1f8, 0x1f1f9, 0x1f1fa, 0x1f1fb, 0x1f1fc, 0x1f1fd, 0x1f1fe, 0x1f1ff
+};
+
+static uint32_t unicode_520_ci_page_1f2[] = {
+ 0x1f200, 0x1f201, 0x1f202, 0x1f203, 0x1f204, 0x1f205, 0x1f206, 0x1f207,
+ 0x1f208, 0x1f209, 0x1f20a, 0x1f20b, 0x1f20c, 0x1f20d, 0x1f20e, 0x1f20f,
+ 0x02f3f, 0x1f211, 0x1f212, 0x03066, 0x03193, 0x1f215, 0x1f216, 0x0319d,
+ 0x1f218, 0x1f219, 0x1f21a, 0x0f9be, 0x1f21c, 0x1f21d, 0x1f21e, 0x1f21f,
+ 0x1f220, 0x1f221, 0x02f63, 0x1f223, 0x1f224, 0x1f225, 0x1f226, 0x1f227,
+ 0x1f228, 0x03192, 0x03194, 0x1f22b, 0x032a7, 0x03197, 0x032a8, 0x1f22f,
+ 0x02f9b, 0x1f231, 0x1f232, 0x1f233, 0x1f234, 0x1f235, 0x1f236, 0x1f237,
+ 0x1f238, 0x1f239, 0x1f23a, 0x1f23b, 0x1f23c, 0x1f23d, 0x1f23e, 0x1f23f,
+ 0x1f240, 0x1f241, 0x1f242, 0x1f243, 0x1f244, 0x1f245, 0x1f246, 0x1f247,
+ 0x1f248, 0x1f249, 0x1f24a, 0x1f24b, 0x1f24c, 0x1f24d, 0x1f24e, 0x1f24f,
+ 0x1f250, 0x1f251, 0x1f252, 0x1f253, 0x1f254, 0x1f255, 0x1f256, 0x1f257,
+ 0x1f258, 0x1f259, 0x1f25a, 0x1f25b, 0x1f25c, 0x1f25d, 0x1f25e, 0x1f25f,
+ 0x1f260, 0x1f261, 0x1f262, 0x1f263, 0x1f264, 0x1f265, 0x1f266, 0x1f267,
+ 0x1f268, 0x1f269, 0x1f26a, 0x1f26b, 0x1f26c, 0x1f26d, 0x1f26e, 0x1f26f,
+ 0x1f270, 0x1f271, 0x1f272, 0x1f273, 0x1f274, 0x1f275, 0x1f276, 0x1f277,
+ 0x1f278, 0x1f279, 0x1f27a, 0x1f27b, 0x1f27c, 0x1f27d, 0x1f27e, 0x1f27f,
+ 0x1f280, 0x1f281, 0x1f282, 0x1f283, 0x1f284, 0x1f285, 0x1f286, 0x1f287,
+ 0x1f288, 0x1f289, 0x1f28a, 0x1f28b, 0x1f28c, 0x1f28d, 0x1f28e, 0x1f28f,
+ 0x1f290, 0x1f291, 0x1f292, 0x1f293, 0x1f294, 0x1f295, 0x1f296, 0x1f297,
+ 0x1f298, 0x1f299, 0x1f29a, 0x1f29b, 0x1f29c, 0x1f29d, 0x1f29e, 0x1f29f,
+ 0x1f2a0, 0x1f2a1, 0x1f2a2, 0x1f2a3, 0x1f2a4, 0x1f2a5, 0x1f2a6, 0x1f2a7,
+ 0x1f2a8, 0x1f2a9, 0x1f2aa, 0x1f2ab, 0x1f2ac, 0x1f2ad, 0x1f2ae, 0x1f2af,
+ 0x1f2b0, 0x1f2b1, 0x1f2b2, 0x1f2b3, 0x1f2b4, 0x1f2b5, 0x1f2b6, 0x1f2b7,
+ 0x1f2b8, 0x1f2b9, 0x1f2ba, 0x1f2bb, 0x1f2bc, 0x1f2bd, 0x1f2be, 0x1f2bf,
+ 0x1f2c0, 0x1f2c1, 0x1f2c2, 0x1f2c3, 0x1f2c4, 0x1f2c5, 0x1f2c6, 0x1f2c7,
+ 0x1f2c8, 0x1f2c9, 0x1f2ca, 0x1f2cb, 0x1f2cc, 0x1f2cd, 0x1f2ce, 0x1f2cf,
+ 0x1f2d0, 0x1f2d1, 0x1f2d2, 0x1f2d3, 0x1f2d4, 0x1f2d5, 0x1f2d6, 0x1f2d7,
+ 0x1f2d8, 0x1f2d9, 0x1f2da, 0x1f2db, 0x1f2dc, 0x1f2dd, 0x1f2de, 0x1f2df,
+ 0x1f2e0, 0x1f2e1, 0x1f2e2, 0x1f2e3, 0x1f2e4, 0x1f2e5, 0x1f2e6, 0x1f2e7,
+ 0x1f2e8, 0x1f2e9, 0x1f2ea, 0x1f2eb, 0x1f2ec, 0x1f2ed, 0x1f2ee, 0x1f2ef,
+ 0x1f2f0, 0x1f2f1, 0x1f2f2, 0x1f2f3, 0x1f2f4, 0x1f2f5, 0x1f2f6, 0x1f2f7,
+ 0x1f2f8, 0x1f2f9, 0x1f2fa, 0x1f2fb, 0x1f2fc, 0x1f2fd, 0x1f2fe, 0x1f2ff
+};
+
+static uint32_t unicode_520_ci_page_2f8[] = {
+ 0x2f800, 0x2f801, 0x2f802, 0x2f803, 0x2f804, 0x0fa30, 0x2f806, 0x2f807,
+ 0x2f808, 0x2f809, 0x0fa31, 0x2f80b, 0x2f80c, 0x2f80d, 0x0fa32, 0x2f80f,
+ 0x2f810, 0x2f811, 0x2f812, 0x2f813, 0x2f814, 0x1f21e, 0x2f816, 0x2f817,
+ 0x2f818, 0x2f819, 0x2f81a, 0x0fa71, 0x2f81c, 0x02f10, 0x2f81e, 0x2f81f,
+ 0x2f820, 0x2f821, 0x2f822, 0x2f823, 0x2f824, 0x0fa76, 0x0fa33, 0x0fa34,
+ 0x0fa77, 0x2f829, 0x2f82a, 0x0f963, 0x2f82c, 0x0fa35, 0x2f82e, 0x2f82f,
+ 0x2f830, 0x2f831, 0x2f831, 0x2f831, 0x2f834, 0x2f835, 0x2f836, 0x2f837,
+ 0x2f838, 0x2f839, 0x2f83a, 0x2f83b, 0x2f83c, 0x2f83d, 0x2f83e, 0x2f83f,
+ 0x2f840, 0x2f841, 0x2f842, 0x2f843, 0x2f844, 0x2f845, 0x2f845, 0x0fa7a,
+ 0x2f848, 0x2f849, 0x2f84a, 0x2f84b, 0x0fa37, 0x2f84d, 0x2f84e, 0x2f84f,
+ 0x0fa00, 0x2f851, 0x2f852, 0x2f853, 0x2f854, 0x2f855, 0x2f856, 0x2f857,
+ 0x2f858, 0x2f859, 0x2f85a, 0x2f85b, 0x2f85c, 0x1f215, 0x2f85e, 0x2f85f,
+ 0x2f860, 0x2f861, 0x2f862, 0x2f863, 0x2f864, 0x2f865, 0x2f866, 0x2f867,
+ 0x2f868, 0x2f869, 0x2f86a, 0x2f86a, 0x2f86c, 0x2f86d, 0x2f86e, 0x0f95f,
+ 0x2f870, 0x2f871, 0x2f872, 0x2f873, 0x2f874, 0x02e8e, 0x2f876, 0x2f877,
+ 0x02f2c, 0x2f879, 0x2f87a, 0x2f87b, 0x2f87c, 0x2f87d, 0x2f87e, 0x2f87f,
+ 0x2f880, 0x2f881, 0x2f882, 0x2f883, 0x2f884, 0x2f885, 0x2f886, 0x2f887,
+ 0x2f888, 0x2f889, 0x2f88a, 0x2f88b, 0x2f88c, 0x2f88d, 0x0f928, 0x2f88f,
+ 0x02f36, 0x2f891, 0x2f891, 0x2f893, 0x2f894, 0x2f894, 0x2f896, 0x2f897,
+ 0x2f898, 0x2f899, 0x2f89a, 0x2f89b, 0x2f89c, 0x2f89d, 0x2f89e, 0x2f89f,
+ 0x2f8a0, 0x2f8a1, 0x2f8a2, 0x0fa3d, 0x2f8a4, 0x2f8a5, 0x2f8a6, 0x2f8a7,
+ 0x0fa87, 0x2f8a7, 0x2f8aa, 0x0fa3f, 0x2f8ac, 0x2f8ad, 0x2f8ae, 0x2f8af,
+ 0x0fa40, 0x0f90d, 0x2f8b2, 0x2f8b3, 0x2f8b4, 0x2f8b5, 0x2f8b6, 0x2f8b7,
+ 0x2f8b8, 0x2f8b9, 0x2f8ba, 0x2f8bb, 0x2f8bc, 0x2f8bd, 0x2f8be, 0x2f8bf,
+ 0x2f8c0, 0x2f8c1, 0x2f8c2, 0x2f8c3, 0x2f8c4, 0x2f8c5, 0x2f8c6, 0x2f8c7,
+ 0x0fa41, 0x2f8c9, 0x2f8ca, 0x2f8cb, 0x2f8cc, 0x2f8cd, 0x2f8ce, 0x0fa43,
+ 0x2f8d0, 0x2f8d1, 0x2f8d2, 0x2f8d3, 0x2f8d4, 0x2f8d5, 0x2f8d6, 0x2f8d7,
+ 0x0f929, 0x0fa93, 0x2f8da, 0x2f8db, 0x2f8dc, 0x2f8dd, 0x2f8de, 0x2f8df,
+ 0x2f8e0, 0x2f8e1, 0x0fa44, 0x2f8e3, 0x2f8e4, 0x2f8e5, 0x2f8e6, 0x0fad2,
+ 0x2f8e8, 0x2f8e9, 0x2f8ea, 0x2f8eb, 0x2f8ec, 0x2f8ed, 0x2f8ee, 0x2f8ef,
+ 0x2f8f0, 0x2f8f1, 0x2f8f2, 0x2f8f3, 0x2f8f4, 0x0f970, 0x2f8f6, 0x2f8f7,
+ 0x2f8f8, 0x2f8f9, 0x2f8fa, 0x2f8fb, 0x2f8fc, 0x2f8fd, 0x2f8fe, 0x2f8ff
+};
+
+static uint32_t unicode_520_ci_page_2f9[] = {
+ 0x2f900, 0x0fa45, 0x0f9ca, 0x2f903, 0x2f904, 0x2f905, 0x2f906, 0x2f907,
+ 0x2f908, 0x2f909, 0x2f90a, 0x0fa99, 0x2f90c, 0x2f90d, 0x2f90e, 0x2f90f,
+ 0x2f910, 0x2f911, 0x2f912, 0x2f913, 0x0fa9b, 0x2f915, 0x2f916, 0x2f917,
+ 0x2f918, 0x2f919, 0x2f91a, 0x2f91b, 0x2f91c, 0x2f91d, 0x2f91e, 0x2f91f,
+ 0x2f920, 0x0fa9e, 0x2f922, 0x2f923, 0x2f924, 0x2f925, 0x2f926, 0x2f927,
+ 0x2f928, 0x02ea9, 0x2f92a, 0x2f92b, 0x2f92c, 0x2f92c, 0x2f92e, 0x2f92f,
+ 0x0faa1, 0x2f931, 0x2f932, 0x2f933, 0x2f934, 0x2f935, 0x2f936, 0x2f937,
+ 0x0f962, 0x2f939, 0x2f93a, 0x2f93b, 0x2f93c, 0x2f93d, 0x2f93e, 0x2f93f,
+ 0x0faa8, 0x2f941, 0x2f942, 0x2f943, 0x2f944, 0x2f945, 0x2f946, 0x2f946,
+ 0x0faa9, 0x0fad4, 0x2f94a, 0x2f94b, 0x2f94c, 0x2f94d, 0x2f94e, 0x0f93b,
+ 0x0faab, 0x2f951, 0x2f952, 0x0fa50, 0x2f954, 0x2f955, 0x0fa1b, 0x2f957,
+ 0x2f958, 0x0fa54, 0x2f95a, 0x2f95b, 0x2f95c, 0x2f95d, 0x2f95d, 0x2f95f,
+ 0x2f960, 0x2f961, 0x2f962, 0x2f963, 0x2f964, 0x2f965, 0x2f966, 0x2f967,
+ 0x2f968, 0x2f969, 0x2f96a, 0x2f96b, 0x2f96c, 0x2f96d, 0x2f96e, 0x2f96f,
+ 0x2f970, 0x2f971, 0x2f972, 0x2f973, 0x2f974, 0x2f975, 0x2f976, 0x2f977,
+ 0x2f978, 0x2f979, 0x0fa5b, 0x2f97b, 0x2f97c, 0x2f97d, 0x2f97e, 0x2f97f,
+ 0x2f980, 0x2f981, 0x2f982, 0x2f983, 0x2f984, 0x2f985, 0x2f986, 0x2f987,
+ 0x2f988, 0x2f989, 0x2f98a, 0x2f893, 0x2f98c, 0x2f98d, 0x2f98e, 0x2f98f,
+ 0x2f990, 0x2f991, 0x2f992, 0x2f993, 0x2f994, 0x2f995, 0x2f996, 0x2f997,
+ 0x0f974, 0x2f999, 0x2f99a, 0x2f99b, 0x2f99c, 0x2f99d, 0x2f99e, 0x0fa5f,
+ 0x2f9a0, 0x2f9a1, 0x2f9a2, 0x2f9a3, 0x2f9a4, 0x2f9a5, 0x2f9a6, 0x2f9a7,
+ 0x2f9a8, 0x2f9a9, 0x2f9aa, 0x2f9ab, 0x2f9ac, 0x2f9ad, 0x2f9ae, 0x2f9af,
+ 0x2f9b0, 0x2f9b1, 0x2f9b2, 0x2f9b3, 0x0f936, 0x2f9b5, 0x2f9b6, 0x2f9b7,
+ 0x2f9b8, 0x2f9b9, 0x2f9ba, 0x0fab5, 0x2f9bc, 0x2f9bd, 0x2f9be, 0x2f9bf,
+ 0x2f9c0, 0x2f9c1, 0x2f9c2, 0x2f9c3, 0x02f90, 0x2f9c5, 0x2f9c6, 0x2f9c7,
+ 0x2f9c8, 0x2f9c9, 0x2f9ca, 0x2f9cb, 0x2f9cc, 0x2f9cd, 0x2f9ce, 0x2f9cf,
+ 0x0fabe, 0x0fac0, 0x02f97, 0x2f9d3, 0x2f9d4, 0x2f9d5, 0x2f9d6, 0x2f9d7,
+ 0x2f9d8, 0x2f9d9, 0x2f9da, 0x2f9db, 0x2f9dc, 0x2f9dd, 0x2f9de, 0x0fac2,
+ 0x2f9e0, 0x2f9e1, 0x2f9e2, 0x2f9e3, 0x2f9e4, 0x2f9e5, 0x2f9e6, 0x2f9e7,
+ 0x2f9e8, 0x2f9e9, 0x2f9ea, 0x2f9eb, 0x2f9ec, 0x2f9ed, 0x2f9ee, 0x2f9ef,
+ 0x2f9f0, 0x2f9f1, 0x2f9f2, 0x2f9f3, 0x2f9f4, 0x2f9f5, 0x2f9f6, 0x2f9f7,
+ 0x2f9f8, 0x2f9f9, 0x2f9fa, 0x2f9fb, 0x2f9fc, 0x2f9fd, 0x0facb, 0x2f9ff
+};
+
+static uint32_t unicode_520_ci_page_2fa[] = {
+ 0x2fa00, 0x2fa01, 0x2fa02, 0x2fa03, 0x2fa04, 0x2fa05, 0x2fa06, 0x2fa07,
+ 0x2fa08, 0x2fa09, 0x0facd, 0x2fa0b, 0x2fa0c, 0x2fa0d, 0x2fa0e, 0x2fa0f,
+ 0x2fa10, 0x2fa11, 0x2fa12, 0x2fa13, 0x2fa14, 0x02fc7, 0x04d56, 0x02fcb,
+ 0x02eea, 0x2fa19, 0x2fa1a, 0x2fa1b, 0x02fd0, 0x2fa1d, 0x2fa1e, 0x2fa1f,
+ 0x2fa20, 0x2fa21, 0x2fa22, 0x2fa23, 0x2fa24, 0x2fa25, 0x2fa26, 0x2fa27,
+ 0x2fa28, 0x2fa29, 0x2fa2a, 0x2fa2b, 0x2fa2c, 0x2fa2d, 0x2fa2e, 0x2fa2f,
+ 0x2fa30, 0x2fa31, 0x2fa32, 0x2fa33, 0x2fa34, 0x2fa35, 0x2fa36, 0x2fa37,
+ 0x2fa38, 0x2fa39, 0x2fa3a, 0x2fa3b, 0x2fa3c, 0x2fa3d, 0x2fa3e, 0x2fa3f,
+ 0x2fa40, 0x2fa41, 0x2fa42, 0x2fa43, 0x2fa44, 0x2fa45, 0x2fa46, 0x2fa47,
+ 0x2fa48, 0x2fa49, 0x2fa4a, 0x2fa4b, 0x2fa4c, 0x2fa4d, 0x2fa4e, 0x2fa4f,
+ 0x2fa50, 0x2fa51, 0x2fa52, 0x2fa53, 0x2fa54, 0x2fa55, 0x2fa56, 0x2fa57,
+ 0x2fa58, 0x2fa59, 0x2fa5a, 0x2fa5b, 0x2fa5c, 0x2fa5d, 0x2fa5e, 0x2fa5f,
+ 0x2fa60, 0x2fa61, 0x2fa62, 0x2fa63, 0x2fa64, 0x2fa65, 0x2fa66, 0x2fa67,
+ 0x2fa68, 0x2fa69, 0x2fa6a, 0x2fa6b, 0x2fa6c, 0x2fa6d, 0x2fa6e, 0x2fa6f,
+ 0x2fa70, 0x2fa71, 0x2fa72, 0x2fa73, 0x2fa74, 0x2fa75, 0x2fa76, 0x2fa77,
+ 0x2fa78, 0x2fa79, 0x2fa7a, 0x2fa7b, 0x2fa7c, 0x2fa7d, 0x2fa7e, 0x2fa7f,
+ 0x2fa80, 0x2fa81, 0x2fa82, 0x2fa83, 0x2fa84, 0x2fa85, 0x2fa86, 0x2fa87,
+ 0x2fa88, 0x2fa89, 0x2fa8a, 0x2fa8b, 0x2fa8c, 0x2fa8d, 0x2fa8e, 0x2fa8f,
+ 0x2fa90, 0x2fa91, 0x2fa92, 0x2fa93, 0x2fa94, 0x2fa95, 0x2fa96, 0x2fa97,
+ 0x2fa98, 0x2fa99, 0x2fa9a, 0x2fa9b, 0x2fa9c, 0x2fa9d, 0x2fa9e, 0x2fa9f,
+ 0x2faa0, 0x2faa1, 0x2faa2, 0x2faa3, 0x2faa4, 0x2faa5, 0x2faa6, 0x2faa7,
+ 0x2faa8, 0x2faa9, 0x2faaa, 0x2faab, 0x2faac, 0x2faad, 0x2faae, 0x2faaf,
+ 0x2fab0, 0x2fab1, 0x2fab2, 0x2fab3, 0x2fab4, 0x2fab5, 0x2fab6, 0x2fab7,
+ 0x2fab8, 0x2fab9, 0x2faba, 0x2fabb, 0x2fabc, 0x2fabd, 0x2fabe, 0x2fabf,
+ 0x2fac0, 0x2fac1, 0x2fac2, 0x2fac3, 0x2fac4, 0x2fac5, 0x2fac6, 0x2fac7,
+ 0x2fac8, 0x2fac9, 0x2faca, 0x2facb, 0x2facc, 0x2facd, 0x2face, 0x2facf,
+ 0x2fad0, 0x2fad1, 0x2fad2, 0x2fad3, 0x2fad4, 0x2fad5, 0x2fad6, 0x2fad7,
+ 0x2fad8, 0x2fad9, 0x2fada, 0x2fadb, 0x2fadc, 0x2fadd, 0x2fade, 0x2fadf,
+ 0x2fae0, 0x2fae1, 0x2fae2, 0x2fae3, 0x2fae4, 0x2fae5, 0x2fae6, 0x2fae7,
+ 0x2fae8, 0x2fae9, 0x2faea, 0x2faeb, 0x2faec, 0x2faed, 0x2faee, 0x2faef,
+ 0x2faf0, 0x2faf1, 0x2faf2, 0x2faf3, 0x2faf4, 0x2faf5, 0x2faf6, 0x2faf7,
+ 0x2faf8, 0x2faf9, 0x2fafa, 0x2fafb, 0x2fafc, 0x2fafd, 0x2fafe, 0x2faff
+};
+
+static uint32_t unicode_520_ci_page_e00[] = {
+ 0xe0000, 0x00000, 0xe0002, 0xe0003, 0xe0004, 0xe0005, 0xe0006, 0xe0007,
+ 0xe0008, 0xe0009, 0xe000a, 0xe000b, 0xe000c, 0xe000d, 0xe000e, 0xe000f,
+ 0xe0010, 0xe0011, 0xe0012, 0xe0013, 0xe0014, 0xe0015, 0xe0016, 0xe0017,
+ 0xe0018, 0xe0019, 0xe001a, 0xe001b, 0xe001c, 0xe001d, 0xe001e, 0xe001f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0xe0080, 0xe0081, 0xe0082, 0xe0083, 0xe0084, 0xe0085, 0xe0086, 0xe0087,
+ 0xe0088, 0xe0089, 0xe008a, 0xe008b, 0xe008c, 0xe008d, 0xe008e, 0xe008f,
+ 0xe0090, 0xe0091, 0xe0092, 0xe0093, 0xe0094, 0xe0095, 0xe0096, 0xe0097,
+ 0xe0098, 0xe0099, 0xe009a, 0xe009b, 0xe009c, 0xe009d, 0xe009e, 0xe009f,
+ 0xe00a0, 0xe00a1, 0xe00a2, 0xe00a3, 0xe00a4, 0xe00a5, 0xe00a6, 0xe00a7,
+ 0xe00a8, 0xe00a9, 0xe00aa, 0xe00ab, 0xe00ac, 0xe00ad, 0xe00ae, 0xe00af,
+ 0xe00b0, 0xe00b1, 0xe00b2, 0xe00b3, 0xe00b4, 0xe00b5, 0xe00b6, 0xe00b7,
+ 0xe00b8, 0xe00b9, 0xe00ba, 0xe00bb, 0xe00bc, 0xe00bd, 0xe00be, 0xe00bf,
+ 0xe00c0, 0xe00c1, 0xe00c2, 0xe00c3, 0xe00c4, 0xe00c5, 0xe00c6, 0xe00c7,
+ 0xe00c8, 0xe00c9, 0xe00ca, 0xe00cb, 0xe00cc, 0xe00cd, 0xe00ce, 0xe00cf,
+ 0xe00d0, 0xe00d1, 0xe00d2, 0xe00d3, 0xe00d4, 0xe00d5, 0xe00d6, 0xe00d7,
+ 0xe00d8, 0xe00d9, 0xe00da, 0xe00db, 0xe00dc, 0xe00dd, 0xe00de, 0xe00df,
+ 0xe00e0, 0xe00e1, 0xe00e2, 0xe00e3, 0xe00e4, 0xe00e5, 0xe00e6, 0xe00e7,
+ 0xe00e8, 0xe00e9, 0xe00ea, 0xe00eb, 0xe00ec, 0xe00ed, 0xe00ee, 0xe00ef,
+ 0xe00f0, 0xe00f1, 0xe00f2, 0xe00f3, 0xe00f4, 0xe00f5, 0xe00f6, 0xe00f7,
+ 0xe00f8, 0xe00f9, 0xe00fa, 0xe00fb, 0xe00fc, 0xe00fd, 0xe00fe, 0xe00ff
+};
+
+static uint32_t unicode_520_ci_page_e01[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0xe01f0, 0xe01f1, 0xe01f2, 0xe01f3, 0xe01f4, 0xe01f5, 0xe01f6, 0xe01f7,
+ 0xe01f8, 0xe01f9, 0xe01fa, 0xe01fb, 0xe01fc, 0xe01fd, 0xe01fe, 0xe01ff
+};
+
+static uint32_t *unicode_520_ci_table[4352] = {
+ unicode_520_ci_page_00, unicode_520_ci_page_01,
+ unicode_520_ci_page_02, unicode_520_ci_page_03,
+ unicode_520_ci_page_04, unicode_520_ci_page_05,
+ unicode_520_ci_page_06, unicode_520_ci_page_07,
+ unicode_520_ci_page_08, unicode_520_ci_page_09,
+ unicode_520_ci_page_0a, unicode_520_ci_page_0b,
+ unicode_520_ci_page_0c, unicode_520_ci_page_0d,
+ unicode_520_ci_page_0e, unicode_520_ci_page_0f,
+ unicode_520_ci_page_10, NULL,
+ NULL, unicode_520_ci_page_13,
+ NULL, NULL,
+ unicode_520_ci_page_16, unicode_520_ci_page_17,
+ unicode_520_ci_page_18, unicode_520_ci_page_19,
+ unicode_520_ci_page_1a, unicode_520_ci_page_1b,
+ unicode_520_ci_page_1c, unicode_520_ci_page_1d,
+ unicode_520_ci_page_1e, unicode_520_ci_page_1f,
+ unicode_520_ci_page_20, unicode_520_ci_page_21,
+ unicode_520_ci_page_22, NULL,
+ unicode_520_ci_page_24, NULL,
+ NULL, unicode_520_ci_page_27,
+ NULL, NULL,
+ unicode_520_ci_page_2a, NULL,
+ unicode_520_ci_page_2c, unicode_520_ci_page_2d,
+ unicode_520_ci_page_2e, unicode_520_ci_page_2f,
+ unicode_520_ci_page_30, unicode_520_ci_page_31,
+ unicode_520_ci_page_32, unicode_520_ci_page_33,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_page_a6, unicode_520_ci_page_a7,
+ unicode_520_ci_page_a8, unicode_520_ci_page_a9,
+ unicode_520_ci_page_aa, unicode_520_ci_page_ab,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_520_ci_page_f9,
+ unicode_520_ci_page_fa, unicode_520_ci_page_fb,
+ unicode_520_ci_page_fc, unicode_520_ci_page_fd,
+ unicode_520_ci_page_fe, unicode_520_ci_page_ff,
+ NULL, unicode_520_ci_page_101,
+ NULL, unicode_520_ci_page_103,
+ unicode_520_ci_page_104, NULL,
+ NULL, NULL,
+ unicode_520_ci_page_108, unicode_520_ci_page_109,
+ unicode_520_ci_page_10a, unicode_520_ci_page_10b,
+ unicode_520_ci_page_10c, NULL,
+ unicode_520_ci_page_10e, NULL,
+ unicode_520_ci_page_110, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_page_124, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_520_ci_page_1d1,
+ unicode_520_ci_page_1d2, unicode_520_ci_page_1d3,
+ unicode_520_ci_page_1d4, unicode_520_ci_page_1d5,
+ unicode_520_ci_page_1d6, unicode_520_ci_page_1d7,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_520_ci_page_1f1,
+ unicode_520_ci_page_1f2, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_page_2f8, unicode_520_ci_page_2f9,
+ unicode_520_ci_page_2fa, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ unicode_520_ci_page_e00, unicode_520_ci_page_e01,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL
+};
+
+#endif
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
new file mode 100644
index 00000000..98eabe87
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table.h
@@ -0,0 +1,1685 @@
+/*
+ Copyright(C) 2013-2015 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ mysql-5.6.23/strings/ctype-uca.c.
+ The following is the header of the file:
+
+ Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UCA (Unicode Collation Algorithm) support.
+ Written by Alexander Barkov <bar@mysql.com>
+*/
+
+#ifndef MYSQL_UCA_EXCEPT_KANA_CI_KANA_WITH_VOICED_SOUND_MARK_H
+#define MYSQL_UCA_EXCEPT_KANA_CI_KANA_WITH_VOICED_SOUND_MARK_H
+
+#include <stdint.h>
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_00[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00009, 0x0000a, 0x0000b, 0x0000c, 0x0000d, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00085, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x000a1, 0x000a2, 0x000a3, 0x000a4, 0x000a5, 0x000a6, 0x000a7,
+ 0x000a8, 0x000a9, 0x00041, 0x000ab, 0x000ac, 0x000ad, 0x000ae, 0x000af,
+ 0x000b0, 0x000b1, 0x00032, 0x00033, 0x000b4, 0x0039c, 0x000b6, 0x000b7,
+ 0x000b8, 0x00031, 0x0004f, 0x000bb, 0x000bc, 0x000bd, 0x000be, 0x000bf,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x000d0, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000d7,
+ 0x000d8, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x000df,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x000d0, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000f7,
+ 0x000d8, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x00059
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_01[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00043, 0x00043,
+ 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00044, 0x00044,
+ 0x00110, 0x00110, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00047, 0x00047, 0x00047, 0x00047,
+ 0x00047, 0x00047, 0x00047, 0x00047, 0x00048, 0x00048, 0x00126, 0x00126,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00049, 0x00131, 0x00132, 0x00132, 0x0004a, 0x0004a, 0x0004b, 0x0004b,
+ 0x00138, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0013f,
+ 0x0013f, 0x00141, 0x00141, 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x00149, 0x0014a, 0x0014a, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00152, 0x00152, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00052, 0x00052, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00166, 0x00166,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00057, 0x00057, 0x00059, 0x00059,
+ 0x00059, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00053,
+ 0x00180, 0x00181, 0x00182, 0x00182, 0x00184, 0x00184, 0x00186, 0x00187,
+ 0x00187, 0x00189, 0x0018a, 0x0018b, 0x0018b, 0x0018d, 0x0018e, 0x0018f,
+ 0x00190, 0x00191, 0x00191, 0x00193, 0x00194, 0x00195, 0x00196, 0x00197,
+ 0x00198, 0x00198, 0x0019a, 0x0019b, 0x0019c, 0x0019d, 0x0019e, 0x0019f,
+ 0x0004f, 0x0004f, 0x001a2, 0x001a2, 0x001a4, 0x001a4, 0x001a6, 0x001a7,
+ 0x001a7, 0x001a9, 0x001aa, 0x001ab, 0x001ac, 0x001ac, 0x001ae, 0x00055,
+ 0x00055, 0x001b1, 0x001b2, 0x001b3, 0x001b3, 0x001b5, 0x001b5, 0x001b7,
+ 0x001b8, 0x001b8, 0x001ba, 0x001bb, 0x001bc, 0x001bc, 0x001be, 0x001bf,
+ 0x001c0, 0x001c1, 0x001c2, 0x001c3, 0x001c4, 0x001c4, 0x001c4, 0x001c7,
+ 0x001c7, 0x001c7, 0x001ca, 0x001ca, 0x001ca, 0x00041, 0x00041, 0x00049,
+ 0x00049, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x0018e, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x000c6, 0x000c6, 0x001e4, 0x001e4, 0x00047, 0x00047,
+ 0x0004b, 0x0004b, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x001b7, 0x001b7,
+ 0x0004a, 0x001c4, 0x001c4, 0x001c4, 0x00047, 0x00047, 0x00195, 0x001bf,
+ 0x0004e, 0x0004e, 0x00041, 0x00041, 0x000c6, 0x000c6, 0x000d8, 0x001ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_02[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x0021c, 0x0021c, 0x00048, 0x00048,
+ 0x0019e, 0x00221, 0x00222, 0x00222, 0x00224, 0x00224, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00059, 0x00059, 0x00234, 0x00235, 0x00236, 0x00237,
+ 0x00238, 0x00239, 0x0023a, 0x0023b, 0x0023c, 0x0023d, 0x0023e, 0x0023f,
+ 0x00240, 0x00241, 0x00242, 0x00243, 0x00244, 0x00245, 0x00246, 0x00247,
+ 0x00248, 0x00249, 0x0024a, 0x0024b, 0x0024c, 0x0024d, 0x0024e, 0x0024f,
+ 0x00250, 0x00251, 0x00252, 0x00181, 0x00186, 0x00255, 0x00189, 0x0018a,
+ 0x00258, 0x0018f, 0x0025a, 0x00190, 0x0025c, 0x0025d, 0x0025e, 0x0025f,
+ 0x00193, 0x00261, 0x00262, 0x00194, 0x00264, 0x00265, 0x00266, 0x00267,
+ 0x00197, 0x00196, 0x0026a, 0x0026b, 0x0026c, 0x0026d, 0x0026e, 0x0019c,
+ 0x00270, 0x00271, 0x0019d, 0x00273, 0x00274, 0x0019f, 0x00276, 0x00277,
+ 0x00278, 0x00279, 0x0027a, 0x0027b, 0x0027c, 0x0027d, 0x0027e, 0x0027f,
+ 0x001a6, 0x00281, 0x00282, 0x001a9, 0x00284, 0x00285, 0x00286, 0x00287,
+ 0x001ae, 0x00289, 0x001b1, 0x001b2, 0x0028c, 0x0028d, 0x0028e, 0x0028f,
+ 0x00290, 0x00291, 0x001b7, 0x00293, 0x00294, 0x00295, 0x00296, 0x00297,
+ 0x00298, 0x00299, 0x0029a, 0x0029b, 0x0029c, 0x0029d, 0x0029e, 0x0029f,
+ 0x002a0, 0x002a1, 0x002a2, 0x001c4, 0x002a4, 0x002a5, 0x001be, 0x002a7,
+ 0x002a8, 0x002a9, 0x002aa, 0x002ab, 0x002ac, 0x002ad, 0x002ae, 0x002af,
+ 0x00048, 0x00266, 0x0004a, 0x00052, 0x00279, 0x0027b, 0x00281, 0x00057,
+ 0x00059, 0x002b9, 0x002ba, 0x002bb, 0x002bc, 0x002bd, 0x002be, 0x002bf,
+ 0x002c0, 0x002c1, 0x002c2, 0x002c3, 0x002c4, 0x002c5, 0x002c6, 0x002c7,
+ 0x002c8, 0x002c9, 0x002ca, 0x002cb, 0x002cc, 0x002cd, 0x002ce, 0x002cf,
+ 0x002d0, 0x002d1, 0x002d2, 0x002d3, 0x002d4, 0x002d5, 0x002d6, 0x002d7,
+ 0x002d8, 0x002d9, 0x002da, 0x002db, 0x002dc, 0x002dd, 0x002de, 0x002df,
+ 0x00194, 0x0004c, 0x00053, 0x00058, 0x00295, 0x002e5, 0x002e6, 0x002e7,
+ 0x002e8, 0x002e9, 0x002ea, 0x002eb, 0x002ec, 0x002ed, 0x002ee, 0x002ef,
+ 0x002f0, 0x002f1, 0x002f2, 0x002f3, 0x002f4, 0x002f5, 0x002f6, 0x002f7,
+ 0x002f8, 0x002f9, 0x002fa, 0x002fb, 0x002fc, 0x002fd, 0x002fe, 0x002ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_03[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00358, 0x00359, 0x0035a, 0x0035b, 0x0035c, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00041, 0x00045, 0x00049, 0x0004f, 0x00055,
+ 0x00043, 0x00044, 0x00048, 0x0004d, 0x00052, 0x00054, 0x00056, 0x00058,
+ 0x00370, 0x00371, 0x00372, 0x00373, 0x002b9, 0x00375, 0x00376, 0x00377,
+ 0x00378, 0x00379, 0x00399, 0x0037b, 0x0037c, 0x0037d, 0x0003b, 0x0037f,
+ 0x00380, 0x00381, 0x00382, 0x00383, 0x000b4, 0x000a8, 0x00391, 0x000b7,
+ 0x00395, 0x00397, 0x00399, 0x0038b, 0x0039f, 0x0038d, 0x003a5, 0x003a9,
+ 0x00399, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a2, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x00391, 0x00395, 0x00397, 0x00399,
+ 0x003a5, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x0039f, 0x003a5, 0x003a9, 0x003cf,
+ 0x00392, 0x00398, 0x003a5, 0x003a5, 0x003a5, 0x003a6, 0x003a0, 0x003d7,
+ 0x003d8, 0x003d8, 0x003da, 0x003da, 0x003dc, 0x003dc, 0x003de, 0x003de,
+ 0x003e0, 0x003e0, 0x003e2, 0x003e2, 0x003e4, 0x003e4, 0x003e6, 0x003e6,
+ 0x003e8, 0x003e8, 0x003ea, 0x003ea, 0x003ec, 0x003ec, 0x003ee, 0x003ee,
+ 0x0039a, 0x003a1, 0x003a3, 0x003f3, 0x00398, 0x00395, 0x003f6, 0x003f7,
+ 0x003f7, 0x003a3, 0x003fa, 0x003fa, 0x003fc, 0x003fd, 0x003fe, 0x003ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_04[] = {
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00460, 0x00460, 0x00462, 0x00462, 0x00464, 0x00464, 0x00466, 0x00466,
+ 0x00468, 0x00468, 0x0046a, 0x0046a, 0x0046c, 0x0046c, 0x0046e, 0x0046e,
+ 0x00470, 0x00470, 0x00472, 0x00472, 0x00474, 0x00474, 0x00476, 0x00476,
+ 0x00478, 0x00478, 0x0047a, 0x0047a, 0x0047c, 0x0047c, 0x0047e, 0x0047e,
+ 0x00480, 0x00480, 0x00482, 0x00000, 0x00000, 0x00000, 0x00000, 0x00487,
+ 0x00000, 0x00000, 0x0048a, 0x0048a, 0x0048c, 0x0048c, 0x0048e, 0x0048e,
+ 0x00413, 0x00413, 0x00492, 0x00492, 0x00494, 0x00494, 0x00496, 0x00496,
+ 0x00498, 0x00498, 0x0049a, 0x0049a, 0x0049c, 0x0049c, 0x0049e, 0x0049e,
+ 0x004a0, 0x004a0, 0x004a2, 0x004a2, 0x004a4, 0x004a4, 0x004a6, 0x004a6,
+ 0x004a8, 0x004a8, 0x004aa, 0x004aa, 0x004ac, 0x004ac, 0x004ae, 0x004ae,
+ 0x004b0, 0x004b0, 0x004b2, 0x004b2, 0x004b4, 0x004b4, 0x004b6, 0x004b6,
+ 0x004b8, 0x004b8, 0x004ba, 0x004ba, 0x004bc, 0x004bc, 0x004be, 0x004be,
+ 0x004c0, 0x00416, 0x00416, 0x004c3, 0x004c3, 0x004c5, 0x004c5, 0x004c7,
+ 0x004c7, 0x004c9, 0x004c9, 0x004cb, 0x004cb, 0x004cd, 0x004cd, 0x004cf,
+ 0x004d0, 0x004d0, 0x004d2, 0x004d2, 0x004d4, 0x004d4, 0x004d6, 0x004d6,
+ 0x004d8, 0x004d8, 0x004da, 0x004da, 0x004dc, 0x004dc, 0x004de, 0x004de,
+ 0x004e0, 0x004e0, 0x0040d, 0x0040d, 0x004e4, 0x004e4, 0x004e6, 0x004e6,
+ 0x004e8, 0x004e8, 0x004ea, 0x004ea, 0x004ec, 0x004ec, 0x00423, 0x00423,
+ 0x004f0, 0x004f0, 0x004f2, 0x004f2, 0x004f4, 0x004f4, 0x004f6, 0x004f7,
+ 0x004f8, 0x004f8, 0x004fa, 0x004fb, 0x004fc, 0x004fd, 0x004fe, 0x004ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_05[] = {
+ 0x00500, 0x00500, 0x00502, 0x00502, 0x00504, 0x00504, 0x00506, 0x00506,
+ 0x00508, 0x00508, 0x0050a, 0x0050a, 0x0050c, 0x0050c, 0x0050e, 0x0050e,
+ 0x00510, 0x00511, 0x00512, 0x00513, 0x00514, 0x00515, 0x00516, 0x00517,
+ 0x00518, 0x00519, 0x0051a, 0x0051b, 0x0051c, 0x0051d, 0x0051e, 0x0051f,
+ 0x00520, 0x00521, 0x00522, 0x00523, 0x00524, 0x00525, 0x00526, 0x00527,
+ 0x00528, 0x00529, 0x0052a, 0x0052b, 0x0052c, 0x0052d, 0x0052e, 0x0052f,
+ 0x00530, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00557,
+ 0x00558, 0x00559, 0x0055a, 0x0055b, 0x0055c, 0x0055d, 0x0055e, 0x0055f,
+ 0x00560, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00587,
+ 0x00588, 0x00589, 0x0058a, 0x0058b, 0x0058c, 0x0058d, 0x0058e, 0x0058f,
+ 0x00590, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x005a2, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x005ba, 0x00000, 0x00000, 0x00000, 0x005be, 0x00000,
+ 0x005c0, 0x00000, 0x00000, 0x005c3, 0x00000, 0x005c5, 0x005c6, 0x005c7,
+ 0x005c8, 0x005c9, 0x005ca, 0x005cb, 0x005cc, 0x005cd, 0x005ce, 0x005cf,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x005d7,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x005dd, 0x005dd, 0x005df,
+ 0x005df, 0x005e1, 0x005e2, 0x005e3, 0x005e3, 0x005e5, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005eb, 0x005ec, 0x005ed, 0x005ee, 0x005ef,
+ 0x005f0, 0x005f1, 0x005f2, 0x005f3, 0x005f4, 0x005f5, 0x005f6, 0x005f7,
+ 0x005f8, 0x005f9, 0x005fa, 0x005fb, 0x005fc, 0x005fd, 0x005fe, 0x005ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_06[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00604, 0x00605, 0x00606, 0x00607,
+ 0x00608, 0x00609, 0x0060a, 0x0060b, 0x0060c, 0x0060d, 0x0060e, 0x0060f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00616, 0x00617,
+ 0x00618, 0x00619, 0x0061a, 0x0061b, 0x0061c, 0x0061d, 0x0061e, 0x0061f,
+ 0x00620, 0x00621, 0x00622, 0x00623, 0x00624, 0x00625, 0x00626, 0x00627,
+ 0x00628, 0x00629, 0x0062a, 0x0062b, 0x0062c, 0x0062d, 0x0062e, 0x0062f,
+ 0x00630, 0x00631, 0x00632, 0x00633, 0x00634, 0x00635, 0x00636, 0x00637,
+ 0x00638, 0x00639, 0x0063a, 0x0063b, 0x0063c, 0x0063d, 0x0063e, 0x0063f,
+ 0x00640, 0x00641, 0x00642, 0x00643, 0x00644, 0x00645, 0x00646, 0x00647,
+ 0x00648, 0x00649, 0x0064a, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00659, 0x0065a, 0x0065b, 0x0065c, 0x0065d, 0x0065e, 0x0065f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0066a, 0x0066b, 0x0066c, 0x0066d, 0x0066e, 0x0066f,
+ 0x00000, 0x00671, 0x00672, 0x00673, 0x00621, 0x00675, 0x00676, 0x00677,
+ 0x00678, 0x00679, 0x0067a, 0x0067b, 0x0067c, 0x0067d, 0x0067e, 0x0067f,
+ 0x00680, 0x00681, 0x00682, 0x00683, 0x00684, 0x00685, 0x00686, 0x00687,
+ 0x00688, 0x00689, 0x0068a, 0x0068b, 0x0068c, 0x0068d, 0x0068e, 0x0068f,
+ 0x00690, 0x00691, 0x00692, 0x00693, 0x00694, 0x00695, 0x00696, 0x00697,
+ 0x00698, 0x00699, 0x0069a, 0x0069b, 0x0069c, 0x0069d, 0x0069e, 0x0069f,
+ 0x006a0, 0x006a1, 0x006a2, 0x006a3, 0x006a4, 0x006a5, 0x006a6, 0x006a7,
+ 0x006a8, 0x006a9, 0x006aa, 0x006ab, 0x006ac, 0x006ad, 0x006ae, 0x006af,
+ 0x006b0, 0x006b1, 0x006b2, 0x006b3, 0x006b4, 0x006b5, 0x006b6, 0x006b7,
+ 0x006b8, 0x006b9, 0x006ba, 0x006bb, 0x006bc, 0x006bd, 0x006be, 0x006bf,
+ 0x006c0, 0x006c1, 0x006c1, 0x006c3, 0x006c4, 0x006c5, 0x006c6, 0x006c7,
+ 0x006c8, 0x006c9, 0x006ca, 0x006cb, 0x006cc, 0x006cd, 0x006ce, 0x006cf,
+ 0x006d0, 0x006d1, 0x006d2, 0x006d2, 0x006d4, 0x006c0, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00648, 0x0064a, 0x00000,
+ 0x00000, 0x006e9, 0x00000, 0x00000, 0x00000, 0x00000, 0x006ee, 0x006ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x006fa, 0x006fb, 0x006fc, 0x00621, 0x00645, 0x006ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_07[] = {
+ 0x00700, 0x00701, 0x00702, 0x00703, 0x00704, 0x00705, 0x00706, 0x00707,
+ 0x00708, 0x00709, 0x0070a, 0x0070b, 0x0070c, 0x0070d, 0x0070e, 0x00000,
+ 0x00710, 0x00000, 0x00712, 0x00713, 0x00713, 0x00715, 0x00716, 0x00717,
+ 0x00718, 0x00719, 0x0071a, 0x0071b, 0x0071b, 0x0071d, 0x0071e, 0x0071f,
+ 0x00720, 0x00721, 0x00722, 0x00723, 0x00723, 0x00725, 0x00726, 0x00726,
+ 0x00728, 0x00729, 0x0072a, 0x0072b, 0x0072c, 0x00712, 0x00713, 0x00715,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0074b, 0x0074c, 0x0074d, 0x0074e, 0x0074f,
+ 0x00750, 0x00751, 0x00752, 0x00753, 0x00754, 0x00755, 0x00756, 0x00757,
+ 0x00758, 0x00759, 0x0075a, 0x0075b, 0x0075c, 0x0075d, 0x0075e, 0x0075f,
+ 0x00760, 0x00761, 0x00762, 0x00763, 0x00764, 0x00765, 0x00766, 0x00767,
+ 0x00768, 0x00769, 0x0076a, 0x0076b, 0x0076c, 0x0076d, 0x0076e, 0x0076f,
+ 0x00770, 0x00771, 0x00772, 0x00773, 0x00774, 0x00775, 0x00776, 0x00777,
+ 0x00778, 0x00779, 0x0077a, 0x0077b, 0x0077c, 0x0077d, 0x0077e, 0x0077f,
+ 0x00780, 0x00781, 0x00782, 0x00783, 0x00784, 0x00785, 0x00786, 0x00787,
+ 0x00788, 0x00789, 0x0078a, 0x0078b, 0x0078c, 0x0078d, 0x0078e, 0x0078f,
+ 0x00790, 0x00791, 0x00792, 0x00793, 0x00794, 0x00795, 0x00796, 0x00797,
+ 0x00798, 0x00799, 0x0079a, 0x0079b, 0x0079c, 0x0079d, 0x0079e, 0x0079f,
+ 0x007a0, 0x007a1, 0x007a2, 0x007a3, 0x007a4, 0x007a5, 0x007a6, 0x007a7,
+ 0x007a8, 0x007a9, 0x007aa, 0x007ab, 0x007ac, 0x007ad, 0x007ae, 0x007af,
+ 0x007b0, 0x007b1, 0x007b2, 0x007b3, 0x007b4, 0x007b5, 0x007b6, 0x007b7,
+ 0x007b8, 0x007b9, 0x007ba, 0x007bb, 0x007bc, 0x007bd, 0x007be, 0x007bf,
+ 0x007c0, 0x007c1, 0x007c2, 0x007c3, 0x007c4, 0x007c5, 0x007c6, 0x007c7,
+ 0x007c8, 0x007c9, 0x007ca, 0x007cb, 0x007cc, 0x007cd, 0x007ce, 0x007cf,
+ 0x007d0, 0x007d1, 0x007d2, 0x007d3, 0x007d4, 0x007d5, 0x007d6, 0x007d7,
+ 0x007d8, 0x007d9, 0x007da, 0x007db, 0x007dc, 0x007dd, 0x007de, 0x007df,
+ 0x007e0, 0x007e1, 0x007e2, 0x007e3, 0x007e4, 0x007e5, 0x007e6, 0x007e7,
+ 0x007e8, 0x007e9, 0x007ea, 0x007eb, 0x007ec, 0x007ed, 0x007ee, 0x007ef,
+ 0x007f0, 0x007f1, 0x007f2, 0x007f3, 0x007f4, 0x007f5, 0x007f6, 0x007f7,
+ 0x007f8, 0x007f9, 0x007fa, 0x007fb, 0x007fc, 0x007fd, 0x007fe, 0x007ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_09[] = {
+ 0x00900, 0x00000, 0x00000, 0x00000, 0x00904, 0x00905, 0x00906, 0x00907,
+ 0x00908, 0x00909, 0x0090a, 0x0090b, 0x0090c, 0x0090d, 0x0090e, 0x0090f,
+ 0x00910, 0x00911, 0x00912, 0x00913, 0x00914, 0x00915, 0x00916, 0x00917,
+ 0x00918, 0x00919, 0x0091a, 0x0091b, 0x0091c, 0x0091d, 0x0091e, 0x0091f,
+ 0x00920, 0x00921, 0x00922, 0x00923, 0x00924, 0x00925, 0x00926, 0x00927,
+ 0x00928, 0x00928, 0x0092a, 0x0092b, 0x0092c, 0x0092d, 0x0092e, 0x0092f,
+ 0x00930, 0x00930, 0x00932, 0x00933, 0x00933, 0x00935, 0x00936, 0x00937,
+ 0x00938, 0x00939, 0x0093a, 0x0093b, 0x00000, 0x0093d, 0x0093e, 0x0093f,
+ 0x00940, 0x00941, 0x00942, 0x00943, 0x00944, 0x00945, 0x00946, 0x00947,
+ 0x00948, 0x00949, 0x0094a, 0x0094b, 0x0094c, 0x0094d, 0x0094e, 0x0094f,
+ 0x00950, 0x00000, 0x00000, 0x00000, 0x00000, 0x00955, 0x00956, 0x00957,
+ 0x00915, 0x00916, 0x00917, 0x0091c, 0x00921, 0x00922, 0x0092b, 0x0092f,
+ 0x00960, 0x00961, 0x00962, 0x00963, 0x00964, 0x00965, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00970, 0x00971, 0x00972, 0x00973, 0x00974, 0x00975, 0x00976, 0x00977,
+ 0x00978, 0x00979, 0x0097a, 0x0097b, 0x0097c, 0x0097d, 0x0097e, 0x0097f,
+ 0x00980, 0x00000, 0x00000, 0x00000, 0x00984, 0x00985, 0x00986, 0x00987,
+ 0x00988, 0x00989, 0x0098a, 0x0098b, 0x0098c, 0x0098d, 0x0098e, 0x0098f,
+ 0x00990, 0x00991, 0x00992, 0x00993, 0x00994, 0x00995, 0x00996, 0x00997,
+ 0x00998, 0x00999, 0x0099a, 0x0099b, 0x0099c, 0x0099d, 0x0099e, 0x0099f,
+ 0x009a0, 0x009a1, 0x009a2, 0x009a3, 0x009a4, 0x009a5, 0x009a6, 0x009a7,
+ 0x009a8, 0x009a9, 0x009aa, 0x009ab, 0x009ac, 0x009ad, 0x009ae, 0x009af,
+ 0x009b0, 0x009b1, 0x009b2, 0x009b3, 0x009b4, 0x009b5, 0x009b6, 0x009b7,
+ 0x009b8, 0x009b9, 0x009ba, 0x009bb, 0x00000, 0x009bd, 0x009be, 0x009bf,
+ 0x009c0, 0x009c1, 0x009c2, 0x009c3, 0x009c4, 0x009c5, 0x009c6, 0x009c7,
+ 0x009c8, 0x009c9, 0x009ca, 0x009cb, 0x009cc, 0x009cd, 0x009ce, 0x009cf,
+ 0x009d0, 0x009d1, 0x009d2, 0x009d3, 0x009d4, 0x009d5, 0x009d6, 0x009d7,
+ 0x009d8, 0x009d9, 0x009da, 0x009db, 0x009a1, 0x009a2, 0x009de, 0x009af,
+ 0x009e0, 0x009e1, 0x009e2, 0x009e3, 0x009e4, 0x009e5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x009f0, 0x009f1, 0x009f2, 0x009f3, 0x00031, 0x00032, 0x00033, 0x00034,
+ 0x009f8, 0x009f9, 0x009fa, 0x009fb, 0x009fc, 0x009fd, 0x009fe, 0x009ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0a[] = {
+ 0x00a00, 0x00000, 0x00000, 0x00000, 0x00a04, 0x00a05, 0x00a06, 0x00a07,
+ 0x00a08, 0x00a09, 0x00a0a, 0x00a0b, 0x00a0c, 0x00a0d, 0x00a0e, 0x00a0f,
+ 0x00a10, 0x00a11, 0x00a12, 0x00a13, 0x00a14, 0x00a15, 0x00a16, 0x00a17,
+ 0x00a18, 0x00a19, 0x00a1a, 0x00a1b, 0x00a1c, 0x00a1d, 0x00a1e, 0x00a1f,
+ 0x00a20, 0x00a21, 0x00a22, 0x00a23, 0x00a24, 0x00a25, 0x00a26, 0x00a27,
+ 0x00a28, 0x00a29, 0x00a2a, 0x00a2b, 0x00a2c, 0x00a2d, 0x00a2e, 0x00a2f,
+ 0x00a30, 0x00a31, 0x00a32, 0x00a32, 0x00a34, 0x00a35, 0x00a36, 0x00a37,
+ 0x00a36, 0x00a39, 0x00a3a, 0x00a3b, 0x00000, 0x00a3d, 0x00a3e, 0x00a3f,
+ 0x00a40, 0x00a41, 0x00a42, 0x00a43, 0x00a44, 0x00a45, 0x00a46, 0x00a47,
+ 0x00a48, 0x00a49, 0x00a4a, 0x00a4b, 0x00a4c, 0x00a4d, 0x00a4e, 0x00a4f,
+ 0x00a50, 0x00a51, 0x00a52, 0x00a53, 0x00a54, 0x00a55, 0x00a56, 0x00a57,
+ 0x00a58, 0x00a16, 0x00a17, 0x00a1c, 0x00a5c, 0x00a5d, 0x00a2b, 0x00a5f,
+ 0x00a60, 0x00a61, 0x00a62, 0x00a63, 0x00a64, 0x00a65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00000, 0x00000, 0x00a72, 0x00a73, 0x00a74, 0x00a75, 0x00a76, 0x00a77,
+ 0x00a78, 0x00a79, 0x00a7a, 0x00a7b, 0x00a7c, 0x00a7d, 0x00a7e, 0x00a7f,
+ 0x00a80, 0x00000, 0x00000, 0x00000, 0x00a84, 0x00a85, 0x00a86, 0x00a87,
+ 0x00a88, 0x00a89, 0x00a8a, 0x00a8b, 0x00a8c, 0x00a8d, 0x00a8e, 0x00a8f,
+ 0x00a90, 0x00a91, 0x00a92, 0x00a93, 0x00a94, 0x00a95, 0x00a96, 0x00a97,
+ 0x00a98, 0x00a99, 0x00a9a, 0x00a9b, 0x00a9c, 0x00a9d, 0x00a9e, 0x00a9f,
+ 0x00aa0, 0x00aa1, 0x00aa2, 0x00aa3, 0x00aa4, 0x00aa5, 0x00aa6, 0x00aa7,
+ 0x00aa8, 0x00aa9, 0x00aaa, 0x00aab, 0x00aac, 0x00aad, 0x00aae, 0x00aaf,
+ 0x00ab0, 0x00ab1, 0x00ab2, 0x00ab3, 0x00ab4, 0x00ab5, 0x00ab6, 0x00ab7,
+ 0x00ab8, 0x00ab9, 0x00aba, 0x00abb, 0x00000, 0x00abd, 0x00abe, 0x00abf,
+ 0x00ac0, 0x00ac1, 0x00ac2, 0x00ac3, 0x00ac4, 0x00ac5, 0x00ac6, 0x00ac7,
+ 0x00ac8, 0x00ac9, 0x00aca, 0x00acb, 0x00acc, 0x00acd, 0x00ace, 0x00acf,
+ 0x00ad0, 0x00ad1, 0x00ad2, 0x00ad3, 0x00ad4, 0x00ad5, 0x00ad6, 0x00ad7,
+ 0x00ad8, 0x00ad9, 0x00ada, 0x00adb, 0x00adc, 0x00add, 0x00ade, 0x00adf,
+ 0x00ae0, 0x00ae1, 0x00ae2, 0x00ae3, 0x00ae4, 0x00ae5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00af0, 0x00af1, 0x00af2, 0x00af3, 0x00af4, 0x00af5, 0x00af6, 0x00af7,
+ 0x00af8, 0x00af9, 0x00afa, 0x00afb, 0x00afc, 0x00afd, 0x00afe, 0x00aff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0b[] = {
+ 0x00b00, 0x00000, 0x00000, 0x00000, 0x00b04, 0x00b05, 0x00b06, 0x00b07,
+ 0x00b08, 0x00b09, 0x00b0a, 0x00b0b, 0x00b0c, 0x00b0d, 0x00b0e, 0x00b0f,
+ 0x00b10, 0x00b11, 0x00b12, 0x00b13, 0x00b14, 0x00b15, 0x00b16, 0x00b17,
+ 0x00b18, 0x00b19, 0x00b1a, 0x00b1b, 0x00b1c, 0x00b1d, 0x00b1e, 0x00b1f,
+ 0x00b20, 0x00b21, 0x00b22, 0x00b23, 0x00b24, 0x00b25, 0x00b26, 0x00b27,
+ 0x00b28, 0x00b29, 0x00b2a, 0x00b2b, 0x00b2c, 0x00b2d, 0x00b2e, 0x00b2f,
+ 0x00b30, 0x00b31, 0x00b32, 0x00b33, 0x00b34, 0x00b35, 0x00b36, 0x00b37,
+ 0x00b38, 0x00b39, 0x00b3a, 0x00b3b, 0x00000, 0x00b3d, 0x00b3e, 0x00b3f,
+ 0x00b40, 0x00b41, 0x00b42, 0x00b43, 0x00b44, 0x00b45, 0x00b46, 0x00b47,
+ 0x00b48, 0x00b49, 0x00b4a, 0x00b4b, 0x00b4c, 0x00b4d, 0x00b4e, 0x00b4f,
+ 0x00b50, 0x00b51, 0x00b52, 0x00b53, 0x00b54, 0x00b55, 0x00b56, 0x00b57,
+ 0x00b58, 0x00b59, 0x00b5a, 0x00b5b, 0x00b21, 0x00b22, 0x00b5e, 0x00b5f,
+ 0x00b60, 0x00b61, 0x00b62, 0x00b63, 0x00b64, 0x00b65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00b70, 0x00b71, 0x00b72, 0x00b73, 0x00b74, 0x00b75, 0x00b76, 0x00b77,
+ 0x00b78, 0x00b79, 0x00b7a, 0x00b7b, 0x00b7c, 0x00b7d, 0x00b7e, 0x00b7f,
+ 0x00b80, 0x00b81, 0x00000, 0x00b83, 0x00b84, 0x00b85, 0x00b86, 0x00b87,
+ 0x00b88, 0x00b89, 0x00b8a, 0x00b8b, 0x00b8c, 0x00b8d, 0x00b8e, 0x00b8f,
+ 0x00b90, 0x00b91, 0x00b92, 0x00b93, 0x00b94, 0x00b95, 0x00b96, 0x00b97,
+ 0x00b98, 0x00b99, 0x00b9a, 0x00b9b, 0x00b9c, 0x00b9d, 0x00b9e, 0x00b9f,
+ 0x00ba0, 0x00ba1, 0x00ba2, 0x00ba3, 0x00ba4, 0x00ba5, 0x00ba6, 0x00ba7,
+ 0x00ba8, 0x00ba9, 0x00baa, 0x00bab, 0x00bac, 0x00bad, 0x00bae, 0x00baf,
+ 0x00bb0, 0x00bb1, 0x00bb2, 0x00bb3, 0x00bb4, 0x00bb5, 0x00bb6, 0x00bb7,
+ 0x00bb8, 0x00bb9, 0x00bba, 0x00bbb, 0x00bbc, 0x00bbd, 0x00bbe, 0x00bbf,
+ 0x00bc0, 0x00bc1, 0x00bc2, 0x00bc3, 0x00bc4, 0x00bc5, 0x00bc6, 0x00bc7,
+ 0x00bc8, 0x00bc9, 0x00bca, 0x00bcb, 0x00bcc, 0x00bcd, 0x00bce, 0x00bcf,
+ 0x00bd0, 0x00bd1, 0x00bd2, 0x00bd3, 0x00bd4, 0x00bd5, 0x00bd6, 0x00bd7,
+ 0x00bd8, 0x00bd9, 0x00bda, 0x00bdb, 0x00bdc, 0x00bdd, 0x00bde, 0x00bdf,
+ 0x00be0, 0x00be1, 0x00be2, 0x00be3, 0x00be4, 0x00be5, 0x00be6, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00bf0, 0x00bf1, 0x00bf2, 0x00bf3, 0x00bf4, 0x00bf5, 0x00bf6, 0x00bf7,
+ 0x00bf8, 0x00bf9, 0x00bfa, 0x00bfb, 0x00bfc, 0x00bfd, 0x00bfe, 0x00bff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0c[] = {
+ 0x00c00, 0x00000, 0x00000, 0x00000, 0x00c04, 0x00c05, 0x00c06, 0x00c07,
+ 0x00c08, 0x00c09, 0x00c0a, 0x00c0b, 0x00c0c, 0x00c0d, 0x00c0e, 0x00c0f,
+ 0x00c10, 0x00c11, 0x00c12, 0x00c13, 0x00c14, 0x00c15, 0x00c16, 0x00c17,
+ 0x00c18, 0x00c19, 0x00c1a, 0x00c1b, 0x00c1c, 0x00c1d, 0x00c1e, 0x00c1f,
+ 0x00c20, 0x00c21, 0x00c22, 0x00c23, 0x00c24, 0x00c25, 0x00c26, 0x00c27,
+ 0x00c28, 0x00c29, 0x00c2a, 0x00c2b, 0x00c2c, 0x00c2d, 0x00c2e, 0x00c2f,
+ 0x00c30, 0x00c31, 0x00c32, 0x00c33, 0x00c34, 0x00c35, 0x00c36, 0x00c37,
+ 0x00c38, 0x00c39, 0x00c3a, 0x00c3b, 0x00c3c, 0x00c3d, 0x00c3e, 0x00c3f,
+ 0x00c40, 0x00c41, 0x00c42, 0x00c43, 0x00c44, 0x00c45, 0x00c46, 0x00c47,
+ 0x00c48, 0x00c49, 0x00c4a, 0x00c4b, 0x00c4c, 0x00c4d, 0x00c4e, 0x00c4f,
+ 0x00c50, 0x00c51, 0x00c52, 0x00c53, 0x00c54, 0x00c55, 0x00c56, 0x00c57,
+ 0x00c58, 0x00c59, 0x00c5a, 0x00c5b, 0x00c5c, 0x00c5d, 0x00c5e, 0x00c5f,
+ 0x00c60, 0x00c61, 0x00c62, 0x00c63, 0x00c64, 0x00c65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00c70, 0x00c71, 0x00c72, 0x00c73, 0x00c74, 0x00c75, 0x00c76, 0x00c77,
+ 0x00c78, 0x00c79, 0x00c7a, 0x00c7b, 0x00c7c, 0x00c7d, 0x00c7e, 0x00c7f,
+ 0x00c80, 0x00c81, 0x00000, 0x00000, 0x00c84, 0x00c85, 0x00c86, 0x00c87,
+ 0x00c88, 0x00c89, 0x00c8a, 0x00c8b, 0x00c8c, 0x00c8d, 0x00c8e, 0x00c8f,
+ 0x00c90, 0x00c91, 0x00c92, 0x00c93, 0x00c94, 0x00c95, 0x00c96, 0x00c97,
+ 0x00c98, 0x00c99, 0x00c9a, 0x00c9b, 0x00c9c, 0x00c9d, 0x00c9e, 0x00c9f,
+ 0x00ca0, 0x00ca1, 0x00ca2, 0x00ca3, 0x00ca4, 0x00ca5, 0x00ca6, 0x00ca7,
+ 0x00ca8, 0x00ca9, 0x00caa, 0x00cab, 0x00cac, 0x00cad, 0x00cae, 0x00caf,
+ 0x00cb0, 0x00cb1, 0x00cb2, 0x00cb3, 0x00cb4, 0x00cb5, 0x00cb6, 0x00cb7,
+ 0x00cb8, 0x00cb9, 0x00cba, 0x00cbb, 0x00000, 0x00cbd, 0x00cbe, 0x00cbf,
+ 0x00cc0, 0x00cc1, 0x00cc2, 0x00cc3, 0x00cc4, 0x00cc5, 0x00cc6, 0x00cc7,
+ 0x00cc8, 0x00cc9, 0x00cca, 0x00ccb, 0x00ccc, 0x00ccd, 0x00cce, 0x00ccf,
+ 0x00cd0, 0x00cd1, 0x00cd2, 0x00cd3, 0x00cd4, 0x00cd5, 0x00cd6, 0x00cd7,
+ 0x00cd8, 0x00cd9, 0x00cda, 0x00cdb, 0x00cdc, 0x00cdd, 0x00cde, 0x00cdf,
+ 0x00ce0, 0x00ce1, 0x00ce2, 0x00ce3, 0x00ce4, 0x00ce5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00cf0, 0x00cf1, 0x00cf2, 0x00cf3, 0x00cf4, 0x00cf5, 0x00cf6, 0x00cf7,
+ 0x00cf8, 0x00cf9, 0x00cfa, 0x00cfb, 0x00cfc, 0x00cfd, 0x00cfe, 0x00cff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0d[] = {
+ 0x00d00, 0x00d01, 0x00000, 0x00000, 0x00d04, 0x00d05, 0x00d06, 0x00d07,
+ 0x00d08, 0x00d09, 0x00d0a, 0x00d0b, 0x00d0c, 0x00d0d, 0x00d0e, 0x00d0f,
+ 0x00d10, 0x00d11, 0x00d12, 0x00d13, 0x00d14, 0x00d15, 0x00d16, 0x00d17,
+ 0x00d18, 0x00d19, 0x00d1a, 0x00d1b, 0x00d1c, 0x00d1d, 0x00d1e, 0x00d1f,
+ 0x00d20, 0x00d21, 0x00d22, 0x00d23, 0x00d24, 0x00d25, 0x00d26, 0x00d27,
+ 0x00d28, 0x00d29, 0x00d2a, 0x00d2b, 0x00d2c, 0x00d2d, 0x00d2e, 0x00d2f,
+ 0x00d30, 0x00d31, 0x00d32, 0x00d33, 0x00d34, 0x00d35, 0x00d36, 0x00d37,
+ 0x00d38, 0x00d39, 0x00d3a, 0x00d3b, 0x00d3c, 0x00d3d, 0x00d3e, 0x00d3f,
+ 0x00d40, 0x00d41, 0x00d42, 0x00d43, 0x00d44, 0x00d45, 0x00d46, 0x00d47,
+ 0x00d48, 0x00d49, 0x00d4a, 0x00d4b, 0x00d4c, 0x00d4d, 0x00d4e, 0x00d4f,
+ 0x00d50, 0x00d51, 0x00d52, 0x00d53, 0x00d54, 0x00d55, 0x00d56, 0x00d57,
+ 0x00d58, 0x00d59, 0x00d5a, 0x00d5b, 0x00d5c, 0x00d5d, 0x00d5e, 0x00d5f,
+ 0x00d60, 0x00d61, 0x00d62, 0x00d63, 0x00d64, 0x00d65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00d70, 0x00d71, 0x00d72, 0x00d73, 0x00d74, 0x00d75, 0x00d76, 0x00d77,
+ 0x00d78, 0x00d79, 0x00d7a, 0x00d7b, 0x00d7c, 0x00d7d, 0x00d7e, 0x00d7f,
+ 0x00d80, 0x00d81, 0x00000, 0x00000, 0x00d84, 0x00d85, 0x00d86, 0x00d87,
+ 0x00d88, 0x00d89, 0x00d8a, 0x00d8b, 0x00d8c, 0x00d8d, 0x00d8e, 0x00d8f,
+ 0x00d90, 0x00d91, 0x00d92, 0x00d93, 0x00d94, 0x00d95, 0x00d96, 0x00d97,
+ 0x00d98, 0x00d99, 0x00d9a, 0x00d9b, 0x00d9c, 0x00d9d, 0x00d9e, 0x00d9f,
+ 0x00da0, 0x00da1, 0x00da2, 0x00da3, 0x00da4, 0x00da5, 0x00da6, 0x00da7,
+ 0x00da8, 0x00da9, 0x00daa, 0x00dab, 0x00dac, 0x00dad, 0x00dae, 0x00daf,
+ 0x00db0, 0x00db1, 0x00db2, 0x00db3, 0x00db4, 0x00db5, 0x00db6, 0x00db7,
+ 0x00db8, 0x00db9, 0x00dba, 0x00dbb, 0x00dbc, 0x00dbd, 0x00dbe, 0x00dbf,
+ 0x00dc0, 0x00dc1, 0x00dc2, 0x00dc3, 0x00dc4, 0x00dc5, 0x00dc6, 0x00dc7,
+ 0x00dc8, 0x00dc9, 0x00dca, 0x00dcb, 0x00dcc, 0x00dcd, 0x00dce, 0x00dcf,
+ 0x00dd0, 0x00dd1, 0x00dd2, 0x00dd3, 0x00dd4, 0x00dd5, 0x00dd6, 0x00dd7,
+ 0x00dd8, 0x00dd9, 0x00dda, 0x00ddb, 0x00ddc, 0x00ddd, 0x00dde, 0x00ddf,
+ 0x00de0, 0x00de1, 0x00de2, 0x00de3, 0x00de4, 0x00de5, 0x00de6, 0x00de7,
+ 0x00de8, 0x00de9, 0x00dea, 0x00deb, 0x00dec, 0x00ded, 0x00dee, 0x00def,
+ 0x00df0, 0x00df1, 0x00df2, 0x00df3, 0x00df4, 0x00df5, 0x00df6, 0x00df7,
+ 0x00df8, 0x00df9, 0x00dfa, 0x00dfb, 0x00dfc, 0x00dfd, 0x00dfe, 0x00dff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0e[] = {
+ 0x00e00, 0x00e01, 0x00e02, 0x00e03, 0x00e04, 0x00e05, 0x00e06, 0x00e07,
+ 0x00e08, 0x00e09, 0x00e0a, 0x00e0b, 0x00e0c, 0x00e0d, 0x00e0e, 0x00e0f,
+ 0x00e10, 0x00e11, 0x00e12, 0x00e13, 0x00e14, 0x00e15, 0x00e16, 0x00e17,
+ 0x00e18, 0x00e19, 0x00e1a, 0x00e1b, 0x00e1c, 0x00e1d, 0x00e1e, 0x00e1f,
+ 0x00e20, 0x00e21, 0x00e22, 0x00e23, 0x00e24, 0x00e25, 0x00e26, 0x00e27,
+ 0x00e28, 0x00e29, 0x00e2a, 0x00e2b, 0x00e2c, 0x00e2d, 0x00e2e, 0x00e2f,
+ 0x00e30, 0x00e31, 0x00e32, 0x00e33, 0x00e34, 0x00e35, 0x00e36, 0x00e37,
+ 0x00e38, 0x00e39, 0x00e3a, 0x00e3b, 0x00e3c, 0x00e3d, 0x00e3e, 0x00e3f,
+ 0x00e40, 0x00e41, 0x00e42, 0x00e43, 0x00e44, 0x00e45, 0x00e46, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00e4c, 0x00e4d, 0x00000, 0x00e4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00e5a, 0x00e5b, 0x00e5c, 0x00e5d, 0x00e5e, 0x00e5f,
+ 0x00e60, 0x00e61, 0x00e62, 0x00e63, 0x00e64, 0x00e65, 0x00e66, 0x00e67,
+ 0x00e68, 0x00e69, 0x00e6a, 0x00e6b, 0x00e6c, 0x00e6d, 0x00e6e, 0x00e6f,
+ 0x00e70, 0x00e71, 0x00e72, 0x00e73, 0x00e74, 0x00e75, 0x00e76, 0x00e77,
+ 0x00e78, 0x00e79, 0x00e7a, 0x00e7b, 0x00e7c, 0x00e7d, 0x00e7e, 0x00e7f,
+ 0x00e80, 0x00e81, 0x00e82, 0x00e83, 0x00e84, 0x00e85, 0x00e86, 0x00e87,
+ 0x00e88, 0x00e89, 0x00e8a, 0x00e8b, 0x00e8c, 0x00e8d, 0x00e8e, 0x00e8f,
+ 0x00e90, 0x00e91, 0x00e92, 0x00e93, 0x00e94, 0x00e95, 0x00e96, 0x00e97,
+ 0x00e98, 0x00e99, 0x00e9a, 0x00e9b, 0x00e9c, 0x00e9d, 0x00e9e, 0x00e9f,
+ 0x00ea0, 0x00ea1, 0x00ea2, 0x00ea3, 0x00ea4, 0x00ea5, 0x00ea6, 0x00ea7,
+ 0x00ea8, 0x00ea9, 0x00eaa, 0x00eab, 0x00eac, 0x00ead, 0x00eae, 0x00eaf,
+ 0x00eb0, 0x00eb1, 0x00eb2, 0x00eb3, 0x00eb4, 0x00eb5, 0x00eb6, 0x00eb7,
+ 0x00eb8, 0x00eb9, 0x00eba, 0x00ebb, 0x00ebc, 0x00ebd, 0x00ebe, 0x00ebf,
+ 0x00ec0, 0x00ec1, 0x00ec2, 0x00ec3, 0x00ec4, 0x00ec5, 0x00ec6, 0x00ec7,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00ecc, 0x00ecd, 0x00ece, 0x00ecf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00eda, 0x00edb, 0x00edc, 0x00edd, 0x00ede, 0x00edf,
+ 0x00ee0, 0x00ee1, 0x00ee2, 0x00ee3, 0x00ee4, 0x00ee5, 0x00ee6, 0x00ee7,
+ 0x00ee8, 0x00ee9, 0x00eea, 0x00eeb, 0x00eec, 0x00eed, 0x00eee, 0x00eef,
+ 0x00ef0, 0x00ef1, 0x00ef2, 0x00ef3, 0x00ef4, 0x00ef5, 0x00ef6, 0x00ef7,
+ 0x00ef8, 0x00ef9, 0x00efa, 0x00efb, 0x00efc, 0x00efd, 0x00efe, 0x00eff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0f[] = {
+ 0x00f00, 0x00f01, 0x00f02, 0x00f03, 0x00f04, 0x00f05, 0x00f06, 0x00f07,
+ 0x00f08, 0x00f09, 0x00f0a, 0x00f0b, 0x00f0b, 0x00f0d, 0x00f0e, 0x00f0f,
+ 0x00f10, 0x00f11, 0x00f12, 0x00f13, 0x00f14, 0x00f15, 0x00f16, 0x00f17,
+ 0x00000, 0x00000, 0x00f1a, 0x00f1b, 0x00f1c, 0x00f1d, 0x00f1e, 0x00f1f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x00030, 0x00f34, 0x00000, 0x00f36, 0x00000,
+ 0x00f38, 0x00000, 0x00f3a, 0x00f3b, 0x00f3c, 0x00f3d, 0x00f3e, 0x00f3f,
+ 0x00f40, 0x00f41, 0x00f42, 0x00f43, 0x00f44, 0x00f45, 0x00f46, 0x00f47,
+ 0x00f48, 0x00f49, 0x00f4a, 0x00f4b, 0x00f4c, 0x00f4d, 0x00f4e, 0x00f4f,
+ 0x00f50, 0x00f51, 0x00f52, 0x00f53, 0x00f54, 0x00f55, 0x00f56, 0x00f57,
+ 0x00f58, 0x00f59, 0x00f5a, 0x00f5b, 0x00f5c, 0x00f5d, 0x00f5e, 0x00f5f,
+ 0x00f60, 0x00f61, 0x00f62, 0x00f63, 0x00f64, 0x00f65, 0x00f66, 0x00f67,
+ 0x00f68, 0x00f69, 0x00f62, 0x00f6b, 0x00f6c, 0x00f6d, 0x00f6e, 0x00f6f,
+ 0x00f70, 0x00f71, 0x00f72, 0x00f73, 0x00f74, 0x00f75, 0x00f76, 0x00f77,
+ 0x00f78, 0x00f79, 0x00f7a, 0x00f7b, 0x00f7c, 0x00f7d, 0x00000, 0x00000,
+ 0x00f80, 0x00f81, 0x00000, 0x00000, 0x00f84, 0x00f85, 0x00000, 0x00000,
+ 0x00f88, 0x00f89, 0x00f8a, 0x00f8b, 0x00f8c, 0x00f8d, 0x00f8e, 0x00f8f,
+ 0x00f90, 0x00f91, 0x00f92, 0x00f93, 0x00f94, 0x00f95, 0x00f96, 0x00f97,
+ 0x00f98, 0x00f99, 0x00f9a, 0x00f9b, 0x00f9c, 0x00f9d, 0x00f9e, 0x00f9f,
+ 0x00fa0, 0x00fa1, 0x00fa2, 0x00fa3, 0x00fa4, 0x00fa5, 0x00fa6, 0x00fa7,
+ 0x00fa8, 0x00fa9, 0x00faa, 0x00fab, 0x00fac, 0x00fad, 0x00fae, 0x00faf,
+ 0x00fb0, 0x00fb1, 0x00fb2, 0x00fb3, 0x00fb4, 0x00fb5, 0x00fb6, 0x00fb7,
+ 0x00fb8, 0x00fb9, 0x00fad, 0x00fb1, 0x00fb2, 0x00fbd, 0x00fbe, 0x00fbf,
+ 0x00fc0, 0x00fc1, 0x00fc2, 0x00fc3, 0x00fc4, 0x00fc5, 0x00000, 0x00fc7,
+ 0x00fc8, 0x00fc9, 0x00fca, 0x00fcb, 0x00fcc, 0x00fcd, 0x00fce, 0x00fcf,
+ 0x00fd0, 0x00fd1, 0x00fd2, 0x00fd3, 0x00fd4, 0x00fd5, 0x00fd6, 0x00fd7,
+ 0x00fd8, 0x00fd9, 0x00fda, 0x00fdb, 0x00fdc, 0x00fdd, 0x00fde, 0x00fdf,
+ 0x00fe0, 0x00fe1, 0x00fe2, 0x00fe3, 0x00fe4, 0x00fe5, 0x00fe6, 0x00fe7,
+ 0x00fe8, 0x00fe9, 0x00fea, 0x00feb, 0x00fec, 0x00fed, 0x00fee, 0x00fef,
+ 0x00ff0, 0x00ff1, 0x00ff2, 0x00ff3, 0x00ff4, 0x00ff5, 0x00ff6, 0x00ff7,
+ 0x00ff8, 0x00ff9, 0x00ffa, 0x00ffb, 0x00ffc, 0x00ffd, 0x00ffe, 0x00fff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10[] = {
+ 0x01000, 0x01001, 0x01002, 0x01003, 0x01004, 0x01005, 0x01006, 0x01007,
+ 0x01008, 0x01009, 0x0100a, 0x0100b, 0x0100c, 0x0100d, 0x0100e, 0x0100f,
+ 0x01010, 0x01011, 0x01012, 0x01013, 0x01014, 0x01015, 0x01016, 0x01017,
+ 0x01018, 0x01019, 0x0101a, 0x0101b, 0x0101c, 0x0101d, 0x0101e, 0x0101f,
+ 0x01020, 0x01021, 0x01022, 0x01023, 0x01024, 0x01025, 0x01026, 0x01027,
+ 0x01028, 0x01029, 0x0102a, 0x0102b, 0x0102c, 0x0102d, 0x0102e, 0x0102f,
+ 0x01030, 0x01031, 0x01032, 0x01033, 0x01034, 0x01035, 0x00000, 0x00000,
+ 0x00000, 0x01039, 0x0103a, 0x0103b, 0x0103c, 0x0103d, 0x0103e, 0x0103f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0104a, 0x0104b, 0x0104c, 0x0104d, 0x0104e, 0x0104f,
+ 0x01050, 0x01051, 0x01052, 0x01053, 0x01054, 0x01055, 0x01056, 0x01057,
+ 0x01058, 0x01059, 0x0105a, 0x0105b, 0x0105c, 0x0105d, 0x0105e, 0x0105f,
+ 0x01060, 0x01061, 0x01062, 0x01063, 0x01064, 0x01065, 0x01066, 0x01067,
+ 0x01068, 0x01069, 0x0106a, 0x0106b, 0x0106c, 0x0106d, 0x0106e, 0x0106f,
+ 0x01070, 0x01071, 0x01072, 0x01073, 0x01074, 0x01075, 0x01076, 0x01077,
+ 0x01078, 0x01079, 0x0107a, 0x0107b, 0x0107c, 0x0107d, 0x0107e, 0x0107f,
+ 0x01080, 0x01081, 0x01082, 0x01083, 0x01084, 0x01085, 0x01086, 0x01087,
+ 0x01088, 0x01089, 0x0108a, 0x0108b, 0x0108c, 0x0108d, 0x0108e, 0x0108f,
+ 0x01090, 0x01091, 0x01092, 0x01093, 0x01094, 0x01095, 0x01096, 0x01097,
+ 0x01098, 0x01099, 0x0109a, 0x0109b, 0x0109c, 0x0109d, 0x0109e, 0x0109f,
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x010c6, 0x010c7,
+ 0x010c8, 0x010c9, 0x010ca, 0x010cb, 0x010cc, 0x010cd, 0x010ce, 0x010cf,
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x010f6, 0x010f7,
+ 0x010f8, 0x010f9, 0x010fa, 0x010fb, 0x010fc, 0x010fd, 0x010fe, 0x010ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_13[] = {
+ 0x01300, 0x01301, 0x01302, 0x01303, 0x01304, 0x01305, 0x01306, 0x01307,
+ 0x01308, 0x01309, 0x0130a, 0x0130b, 0x0130c, 0x0130d, 0x0130e, 0x0130f,
+ 0x01310, 0x01311, 0x01312, 0x01313, 0x01314, 0x01315, 0x01316, 0x01317,
+ 0x01318, 0x01319, 0x0131a, 0x0131b, 0x0131c, 0x0131d, 0x0131e, 0x0131f,
+ 0x01320, 0x01321, 0x01322, 0x01323, 0x01324, 0x01325, 0x01326, 0x01327,
+ 0x01328, 0x01329, 0x0132a, 0x0132b, 0x0132c, 0x0132d, 0x0132e, 0x0132f,
+ 0x01330, 0x01331, 0x01332, 0x01333, 0x01334, 0x01335, 0x01336, 0x01337,
+ 0x01338, 0x01339, 0x0133a, 0x0133b, 0x0133c, 0x0133d, 0x0133e, 0x0133f,
+ 0x01340, 0x01341, 0x01342, 0x01343, 0x01344, 0x01345, 0x01346, 0x01347,
+ 0x01348, 0x01349, 0x0134a, 0x0134b, 0x0134c, 0x0134d, 0x0134e, 0x0134f,
+ 0x01350, 0x01351, 0x01352, 0x01353, 0x01354, 0x01355, 0x01356, 0x01357,
+ 0x01358, 0x01359, 0x0135a, 0x0135b, 0x0135c, 0x0135d, 0x0135e, 0x0135f,
+ 0x01360, 0x01361, 0x01362, 0x01363, 0x01364, 0x01365, 0x01366, 0x01367,
+ 0x01368, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01372, 0x01373, 0x01374, 0x01375, 0x01376, 0x01377,
+ 0x01378, 0x01379, 0x0137a, 0x0137b, 0x0137c, 0x0137d, 0x0137e, 0x0137f,
+ 0x01380, 0x01381, 0x01382, 0x01383, 0x01384, 0x01385, 0x01386, 0x01387,
+ 0x01388, 0x01389, 0x0138a, 0x0138b, 0x0138c, 0x0138d, 0x0138e, 0x0138f,
+ 0x01390, 0x01391, 0x01392, 0x01393, 0x01394, 0x01395, 0x01396, 0x01397,
+ 0x01398, 0x01399, 0x0139a, 0x0139b, 0x0139c, 0x0139d, 0x0139e, 0x0139f,
+ 0x013a0, 0x013a1, 0x013a2, 0x013a3, 0x013a4, 0x013a5, 0x013a6, 0x013a7,
+ 0x013a8, 0x013a9, 0x013aa, 0x013ab, 0x013ac, 0x013ad, 0x013ae, 0x013af,
+ 0x013b0, 0x013b1, 0x013b2, 0x013b3, 0x013b4, 0x013b5, 0x013b6, 0x013b7,
+ 0x013b8, 0x013b9, 0x013ba, 0x013bb, 0x013bc, 0x013bd, 0x013be, 0x013bf,
+ 0x013c0, 0x013c1, 0x013c2, 0x013c3, 0x013c4, 0x013c5, 0x013c6, 0x013c7,
+ 0x013c8, 0x013c9, 0x013ca, 0x013cb, 0x013cc, 0x013cd, 0x013ce, 0x013cf,
+ 0x013d0, 0x013d1, 0x013d2, 0x013d3, 0x013d4, 0x013d5, 0x013d6, 0x013d7,
+ 0x013d8, 0x013d9, 0x013da, 0x013db, 0x013dc, 0x013dd, 0x013de, 0x013df,
+ 0x013e0, 0x013e1, 0x013e2, 0x013e3, 0x013e4, 0x013e5, 0x013e6, 0x013e7,
+ 0x013e8, 0x013e9, 0x013ea, 0x013eb, 0x013ec, 0x013ed, 0x013ee, 0x013ef,
+ 0x013f0, 0x013f1, 0x013f2, 0x013f3, 0x013f4, 0x013f5, 0x013f6, 0x013f7,
+ 0x013f8, 0x013f9, 0x013fa, 0x013fb, 0x013fc, 0x013fd, 0x013fe, 0x013ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_16[] = {
+ 0x01600, 0x01601, 0x01602, 0x01603, 0x01604, 0x01605, 0x01606, 0x01607,
+ 0x01608, 0x01609, 0x0160a, 0x0160b, 0x0160c, 0x0160d, 0x0160e, 0x0160f,
+ 0x01610, 0x01611, 0x01612, 0x01613, 0x01614, 0x01615, 0x01616, 0x01617,
+ 0x01618, 0x01619, 0x0161a, 0x0161b, 0x0161c, 0x0161d, 0x0161e, 0x0161f,
+ 0x01620, 0x01621, 0x01622, 0x01623, 0x01624, 0x01625, 0x01626, 0x01627,
+ 0x01628, 0x01629, 0x0162a, 0x0162b, 0x0162c, 0x0162d, 0x0162e, 0x0162f,
+ 0x01630, 0x01631, 0x01632, 0x01633, 0x01634, 0x01635, 0x01636, 0x01637,
+ 0x01638, 0x01639, 0x0163a, 0x0163b, 0x0163c, 0x0163d, 0x0163e, 0x0163f,
+ 0x01640, 0x01641, 0x01642, 0x01643, 0x01644, 0x01645, 0x01646, 0x01647,
+ 0x01648, 0x01649, 0x0164a, 0x0164b, 0x0164c, 0x0164d, 0x0164e, 0x0164f,
+ 0x01650, 0x01651, 0x01652, 0x01653, 0x01654, 0x01655, 0x01656, 0x01657,
+ 0x01658, 0x01659, 0x0165a, 0x0165b, 0x0165c, 0x0165d, 0x0165e, 0x0165f,
+ 0x01660, 0x01661, 0x01662, 0x01663, 0x01664, 0x01665, 0x01666, 0x01667,
+ 0x01668, 0x01669, 0x0166a, 0x0166b, 0x0166c, 0x0166d, 0x0166e, 0x0166f,
+ 0x01670, 0x01671, 0x01672, 0x01673, 0x01674, 0x01675, 0x01676, 0x01677,
+ 0x01678, 0x01679, 0x0167a, 0x0167b, 0x0167c, 0x0167d, 0x0167e, 0x0167f,
+ 0x01680, 0x01681, 0x01682, 0x01683, 0x01684, 0x01685, 0x01686, 0x01687,
+ 0x01688, 0x01689, 0x0168a, 0x0168b, 0x0168c, 0x0168d, 0x0168e, 0x0168f,
+ 0x01690, 0x01691, 0x01692, 0x01693, 0x01694, 0x01695, 0x01696, 0x01697,
+ 0x01698, 0x01699, 0x0169a, 0x0169b, 0x0169c, 0x0169d, 0x0169e, 0x0169f,
+ 0x016a0, 0x016a0, 0x016a2, 0x016a3, 0x016a2, 0x016a2, 0x016a6, 0x016a6,
+ 0x016a8, 0x016a8, 0x016aa, 0x016ab, 0x016a8, 0x016a8, 0x016a8, 0x016af,
+ 0x016b0, 0x016b1, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b7,
+ 0x016b8, 0x016b9, 0x016ba, 0x016ba, 0x016ba, 0x016ba, 0x016be, 0x016be,
+ 0x016be, 0x016c1, 0x016c1, 0x016c3, 0x016c3, 0x016c5, 0x016c5, 0x016c7,
+ 0x016c8, 0x016c9, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016cf,
+ 0x016cf, 0x016cf, 0x016d2, 0x016d2, 0x016d2, 0x016c8, 0x016d6, 0x016d7,
+ 0x016d7, 0x016d7, 0x016da, 0x016da, 0x016dc, 0x016dc, 0x016de, 0x016df,
+ 0x016e0, 0x016e1, 0x016e2, 0x016e3, 0x016e4, 0x016e5, 0x016e6, 0x016e6,
+ 0x016e6, 0x016b9, 0x016ca, 0x016eb, 0x016ec, 0x016ed, 0x016ee, 0x016ef,
+ 0x016f0, 0x016f1, 0x016f2, 0x016f3, 0x016f4, 0x016f5, 0x016f6, 0x016f7,
+ 0x016f8, 0x016f9, 0x016fa, 0x016fb, 0x016fc, 0x016fd, 0x016fe, 0x016ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_17[] = {
+ 0x01700, 0x01701, 0x01702, 0x01703, 0x01704, 0x01705, 0x01706, 0x01707,
+ 0x01708, 0x01709, 0x0170a, 0x0170b, 0x0170c, 0x0170d, 0x0170e, 0x0170f,
+ 0x01710, 0x01711, 0x01712, 0x01713, 0x01714, 0x01715, 0x01716, 0x01717,
+ 0x01718, 0x01719, 0x0171a, 0x0171b, 0x0171c, 0x0171d, 0x0171e, 0x0171f,
+ 0x01720, 0x01721, 0x01722, 0x01723, 0x01724, 0x01725, 0x01726, 0x01727,
+ 0x01728, 0x01729, 0x0172a, 0x0172b, 0x0172c, 0x0172d, 0x0172e, 0x0172f,
+ 0x01730, 0x01731, 0x01732, 0x01733, 0x01734, 0x01735, 0x01736, 0x01737,
+ 0x01738, 0x01739, 0x0173a, 0x0173b, 0x0173c, 0x0173d, 0x0173e, 0x0173f,
+ 0x01740, 0x01741, 0x01742, 0x01743, 0x01744, 0x01745, 0x01746, 0x01747,
+ 0x01748, 0x01749, 0x0174a, 0x0174b, 0x0174c, 0x0174d, 0x0174e, 0x0174f,
+ 0x01750, 0x01751, 0x01752, 0x01753, 0x01754, 0x01755, 0x01756, 0x01757,
+ 0x01758, 0x01759, 0x0175a, 0x0175b, 0x0175c, 0x0175d, 0x0175e, 0x0175f,
+ 0x01760, 0x01761, 0x01762, 0x01763, 0x01764, 0x01765, 0x01766, 0x01767,
+ 0x01768, 0x01769, 0x0176a, 0x0176b, 0x0176c, 0x0176d, 0x0176e, 0x0176f,
+ 0x01770, 0x01771, 0x01772, 0x01773, 0x01774, 0x01775, 0x01776, 0x01777,
+ 0x01778, 0x01779, 0x0177a, 0x0177b, 0x0177c, 0x0177d, 0x0177e, 0x0177f,
+ 0x01780, 0x01781, 0x01782, 0x01783, 0x01784, 0x01785, 0x01786, 0x01787,
+ 0x01788, 0x01789, 0x0178a, 0x0178b, 0x0178c, 0x0178d, 0x0178e, 0x0178f,
+ 0x01790, 0x01791, 0x01792, 0x01793, 0x01794, 0x01795, 0x01796, 0x01797,
+ 0x01798, 0x01799, 0x0179a, 0x0179b, 0x0179c, 0x0179d, 0x0179e, 0x0179f,
+ 0x017a0, 0x017a1, 0x017a2, 0x017a3, 0x017a4, 0x017a5, 0x017a6, 0x017a7,
+ 0x017a8, 0x017a9, 0x017aa, 0x017ab, 0x017ac, 0x017ad, 0x017ae, 0x017af,
+ 0x017b0, 0x017b1, 0x017b2, 0x017b3, 0x017b4, 0x017b5, 0x017b6, 0x017b7,
+ 0x017b8, 0x017b9, 0x017ba, 0x017bb, 0x017bc, 0x017bd, 0x017be, 0x017bf,
+ 0x017c0, 0x017c1, 0x017c2, 0x017c3, 0x017c4, 0x017c5, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x017d2, 0x00000, 0x017d4, 0x017d5, 0x017d6, 0x017d7,
+ 0x017d8, 0x017d9, 0x017da, 0x017db, 0x017dc, 0x00000, 0x017de, 0x017df,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017ea, 0x017eb, 0x017ec, 0x017ed, 0x017ee, 0x017ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017fa, 0x017fb, 0x017fc, 0x017fd, 0x017fe, 0x017ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_18[] = {
+ 0x01800, 0x01801, 0x01802, 0x01803, 0x01804, 0x01805, 0x01806, 0x01807,
+ 0x01808, 0x01809, 0x0180a, 0x00000, 0x00000, 0x00000, 0x00000, 0x0180f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0181a, 0x0181b, 0x0181c, 0x0181d, 0x0181e, 0x0181f,
+ 0x01820, 0x01821, 0x01822, 0x01823, 0x01824, 0x01825, 0x01826, 0x01827,
+ 0x01828, 0x01829, 0x0182a, 0x0182b, 0x0182c, 0x0182d, 0x0182e, 0x0182f,
+ 0x01830, 0x01831, 0x01832, 0x01833, 0x01834, 0x01835, 0x01836, 0x01837,
+ 0x01838, 0x01839, 0x0183a, 0x0183b, 0x0183c, 0x0183d, 0x0183e, 0x0183f,
+ 0x01840, 0x01841, 0x01842, 0x01843, 0x01844, 0x01845, 0x01846, 0x01847,
+ 0x01848, 0x01849, 0x0184a, 0x0184b, 0x0184c, 0x0184d, 0x0184e, 0x0184f,
+ 0x01850, 0x01851, 0x01852, 0x01853, 0x01854, 0x01855, 0x01856, 0x01857,
+ 0x01858, 0x01859, 0x0185a, 0x0185b, 0x0185c, 0x0185d, 0x0185e, 0x0185f,
+ 0x01860, 0x01861, 0x01862, 0x01863, 0x01864, 0x01865, 0x01866, 0x01867,
+ 0x01868, 0x01869, 0x0186a, 0x0186b, 0x0186c, 0x0186d, 0x0186e, 0x0186f,
+ 0x01870, 0x01871, 0x01872, 0x01873, 0x01874, 0x01875, 0x01876, 0x01877,
+ 0x01878, 0x01879, 0x0187a, 0x0187b, 0x0187c, 0x0187d, 0x0187e, 0x0187f,
+ 0x01880, 0x01881, 0x01882, 0x01883, 0x01884, 0x01885, 0x01886, 0x01887,
+ 0x01888, 0x01889, 0x0188a, 0x0188b, 0x0188c, 0x0188d, 0x0188e, 0x0188f,
+ 0x01890, 0x01891, 0x01892, 0x01893, 0x01894, 0x01895, 0x01896, 0x01897,
+ 0x01898, 0x01899, 0x0189a, 0x0189b, 0x0189c, 0x0189d, 0x0189e, 0x0189f,
+ 0x018a0, 0x018a1, 0x018a2, 0x018a3, 0x018a4, 0x018a5, 0x018a6, 0x018a7,
+ 0x018a8, 0x018a9, 0x018aa, 0x018ab, 0x018ac, 0x018ad, 0x018ae, 0x018af,
+ 0x018b0, 0x018b1, 0x018b2, 0x018b3, 0x018b4, 0x018b5, 0x018b6, 0x018b7,
+ 0x018b8, 0x018b9, 0x018ba, 0x018bb, 0x018bc, 0x018bd, 0x018be, 0x018bf,
+ 0x018c0, 0x018c1, 0x018c2, 0x018c3, 0x018c4, 0x018c5, 0x018c6, 0x018c7,
+ 0x018c8, 0x018c9, 0x018ca, 0x018cb, 0x018cc, 0x018cd, 0x018ce, 0x018cf,
+ 0x018d0, 0x018d1, 0x018d2, 0x018d3, 0x018d4, 0x018d5, 0x018d6, 0x018d7,
+ 0x018d8, 0x018d9, 0x018da, 0x018db, 0x018dc, 0x018dd, 0x018de, 0x018df,
+ 0x018e0, 0x018e1, 0x018e2, 0x018e3, 0x018e4, 0x018e5, 0x018e6, 0x018e7,
+ 0x018e8, 0x018e9, 0x018ea, 0x018eb, 0x018ec, 0x018ed, 0x018ee, 0x018ef,
+ 0x018f0, 0x018f1, 0x018f2, 0x018f3, 0x018f4, 0x018f5, 0x018f6, 0x018f7,
+ 0x018f8, 0x018f9, 0x018fa, 0x018fb, 0x018fc, 0x018fd, 0x018fe, 0x018ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_19[] = {
+ 0x01900, 0x01901, 0x01902, 0x01903, 0x01904, 0x01905, 0x01906, 0x01907,
+ 0x01908, 0x01909, 0x0190a, 0x0190b, 0x0190c, 0x0190d, 0x0190e, 0x0190f,
+ 0x01910, 0x01911, 0x01912, 0x01913, 0x01914, 0x01915, 0x01916, 0x01917,
+ 0x01918, 0x01919, 0x0191a, 0x0191b, 0x0191c, 0x0191d, 0x0191e, 0x0191f,
+ 0x01920, 0x01921, 0x01922, 0x01923, 0x01924, 0x01925, 0x01926, 0x01927,
+ 0x01928, 0x01929, 0x0192a, 0x0192b, 0x0192c, 0x0192d, 0x0192e, 0x0192f,
+ 0x01930, 0x01931, 0x01932, 0x01933, 0x01934, 0x01935, 0x01936, 0x01937,
+ 0x01938, 0x00000, 0x00000, 0x00000, 0x0193c, 0x0193d, 0x0193e, 0x0193f,
+ 0x01940, 0x01941, 0x01942, 0x01943, 0x01944, 0x01945, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x01950, 0x01951, 0x01952, 0x01953, 0x01954, 0x01955, 0x01956, 0x01957,
+ 0x01958, 0x01959, 0x0195a, 0x0195b, 0x0195c, 0x0195d, 0x0195e, 0x0195f,
+ 0x01960, 0x01961, 0x01962, 0x01963, 0x01964, 0x01965, 0x01966, 0x01967,
+ 0x01968, 0x01969, 0x0196a, 0x0196b, 0x0196c, 0x0196d, 0x0196e, 0x0196f,
+ 0x01970, 0x01971, 0x01972, 0x01973, 0x01974, 0x01975, 0x01976, 0x01977,
+ 0x01978, 0x01979, 0x0197a, 0x0197b, 0x0197c, 0x0197d, 0x0197e, 0x0197f,
+ 0x01980, 0x01981, 0x01982, 0x01983, 0x01984, 0x01985, 0x01986, 0x01987,
+ 0x01988, 0x01989, 0x0198a, 0x0198b, 0x0198c, 0x0198d, 0x0198e, 0x0198f,
+ 0x01990, 0x01991, 0x01992, 0x01993, 0x01994, 0x01995, 0x01996, 0x01997,
+ 0x01998, 0x01999, 0x0199a, 0x0199b, 0x0199c, 0x0199d, 0x0199e, 0x0199f,
+ 0x019a0, 0x019a1, 0x019a2, 0x019a3, 0x019a4, 0x019a5, 0x019a6, 0x019a7,
+ 0x019a8, 0x019a9, 0x019aa, 0x019ab, 0x019ac, 0x019ad, 0x019ae, 0x019af,
+ 0x019b0, 0x019b1, 0x019b2, 0x019b3, 0x019b4, 0x019b5, 0x019b6, 0x019b7,
+ 0x019b8, 0x019b9, 0x019ba, 0x019bb, 0x019bc, 0x019bd, 0x019be, 0x019bf,
+ 0x019c0, 0x019c1, 0x019c2, 0x019c3, 0x019c4, 0x019c5, 0x019c6, 0x019c7,
+ 0x019c8, 0x019c9, 0x019ca, 0x019cb, 0x019cc, 0x019cd, 0x019ce, 0x019cf,
+ 0x019d0, 0x019d1, 0x019d2, 0x019d3, 0x019d4, 0x019d5, 0x019d6, 0x019d7,
+ 0x019d8, 0x019d9, 0x019da, 0x019db, 0x019dc, 0x019dd, 0x019de, 0x019df,
+ 0x019e0, 0x019e1, 0x019e2, 0x019e3, 0x019e4, 0x019e5, 0x019e6, 0x019e7,
+ 0x019e8, 0x019e9, 0x019ea, 0x019eb, 0x019ec, 0x019ed, 0x019ee, 0x019ef,
+ 0x019f0, 0x019f1, 0x019f2, 0x019f3, 0x019f4, 0x019f5, 0x019f6, 0x019f7,
+ 0x019f8, 0x019f9, 0x019fa, 0x019fb, 0x019fc, 0x019fd, 0x019fe, 0x019ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d[] = {
+ 0x01d00, 0x01d01, 0x01d02, 0x01d03, 0x01d04, 0x01d05, 0x01d06, 0x01d07,
+ 0x01d08, 0x01d09, 0x01d0a, 0x01d0b, 0x01d0c, 0x01d0d, 0x01d0e, 0x01d0f,
+ 0x01d10, 0x01d11, 0x01d12, 0x01d13, 0x01d14, 0x01d15, 0x01d16, 0x01d17,
+ 0x01d18, 0x01d19, 0x01d1a, 0x01d1b, 0x01d1c, 0x01d1d, 0x01d1e, 0x01d1f,
+ 0x01d20, 0x01d21, 0x01d22, 0x01d23, 0x01d24, 0x01d25, 0x01d26, 0x01d27,
+ 0x01d28, 0x01d29, 0x01d2a, 0x01d2b, 0x00041, 0x000c6, 0x00042, 0x01d2f,
+ 0x00044, 0x00045, 0x0018e, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b,
+ 0x0004c, 0x0004d, 0x0004e, 0x01d3b, 0x0004f, 0x00222, 0x00050, 0x00052,
+ 0x00054, 0x00055, 0x00057, 0x00041, 0x00250, 0x00251, 0x01d02, 0x00042,
+ 0x00044, 0x00045, 0x0018f, 0x00190, 0x01d08, 0x00047, 0x01d09, 0x0004b,
+ 0x0004d, 0x0014a, 0x0004f, 0x00186, 0x01d16, 0x01d17, 0x00050, 0x00054,
+ 0x00055, 0x01d1d, 0x0019c, 0x00056, 0x01d25, 0x00392, 0x00393, 0x00394,
+ 0x003a6, 0x003a7, 0x00049, 0x00052, 0x00055, 0x00056, 0x00392, 0x00393,
+ 0x003a1, 0x003a6, 0x003a7, 0x01d6b, 0x01d6c, 0x01d6d, 0x01d6e, 0x01d6f,
+ 0x01d70, 0x01d71, 0x01d72, 0x01d73, 0x01d74, 0x01d75, 0x01d76, 0x01d77,
+ 0x01d78, 0x01d79, 0x01d7a, 0x01d7b, 0x01d7c, 0x01d7d, 0x01d7e, 0x01d7f,
+ 0x01d80, 0x01d81, 0x01d82, 0x01d83, 0x01d84, 0x01d85, 0x01d86, 0x01d87,
+ 0x01d88, 0x01d89, 0x01d8a, 0x01d8b, 0x01d8c, 0x01d8d, 0x01d8e, 0x01d8f,
+ 0x01d90, 0x01d91, 0x01d92, 0x01d93, 0x01d94, 0x01d95, 0x01d96, 0x01d97,
+ 0x01d98, 0x01d99, 0x01d9a, 0x01d9b, 0x01d9c, 0x01d9d, 0x01d9e, 0x01d9f,
+ 0x01da0, 0x01da1, 0x01da2, 0x01da3, 0x01da4, 0x01da5, 0x01da6, 0x01da7,
+ 0x01da8, 0x01da9, 0x01daa, 0x01dab, 0x01dac, 0x01dad, 0x01dae, 0x01daf,
+ 0x01db0, 0x01db1, 0x01db2, 0x01db3, 0x01db4, 0x01db5, 0x01db6, 0x01db7,
+ 0x01db8, 0x01db9, 0x01dba, 0x01dbb, 0x01dbc, 0x01dbd, 0x01dbe, 0x01dbf,
+ 0x01dc0, 0x01dc1, 0x01dc2, 0x01dc3, 0x01dc4, 0x01dc5, 0x01dc6, 0x01dc7,
+ 0x01dc8, 0x01dc9, 0x01dca, 0x01dcb, 0x01dcc, 0x01dcd, 0x01dce, 0x01dcf,
+ 0x01dd0, 0x01dd1, 0x01dd2, 0x01dd3, 0x01dd4, 0x01dd5, 0x01dd6, 0x01dd7,
+ 0x01dd8, 0x01dd9, 0x01dda, 0x01ddb, 0x01ddc, 0x01ddd, 0x01dde, 0x01ddf,
+ 0x01de0, 0x01de1, 0x01de2, 0x01de3, 0x01de4, 0x01de5, 0x01de6, 0x01de7,
+ 0x01de8, 0x01de9, 0x01dea, 0x01deb, 0x01dec, 0x01ded, 0x01dee, 0x01def,
+ 0x01df0, 0x01df1, 0x01df2, 0x01df3, 0x01df4, 0x01df5, 0x01df6, 0x01df7,
+ 0x01df8, 0x01df9, 0x01dfa, 0x01dfb, 0x01dfc, 0x01dfd, 0x01dfe, 0x01dff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1e[] = {
+ 0x00041, 0x00041, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042,
+ 0x00043, 0x00043, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00046, 0x00046,
+ 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00048, 0x00048, 0x00048, 0x00048, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004d, 0x0004d,
+ 0x0004d, 0x0004d, 0x0004d, 0x0004d, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00050, 0x00050, 0x00050, 0x00050,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054,
+ 0x00054, 0x00054, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00056, 0x00056, 0x00056, 0x00056,
+ 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057,
+ 0x00057, 0x00057, 0x00058, 0x00058, 0x00058, 0x00058, 0x00059, 0x00059,
+ 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00048, 0x00054,
+ 0x00057, 0x00059, 0x01e9a, 0x00053, 0x01e9c, 0x01e9d, 0x01e9e, 0x01e9f,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059,
+ 0x00059, 0x00059, 0x01efa, 0x01efb, 0x01efc, 0x01efd, 0x01efe, 0x01eff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f[] = {
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f16, 0x01f17,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f1e, 0x01f1f,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f46, 0x01f47,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f4e, 0x01f4f,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5,
+ 0x01f58, 0x003a5, 0x01f5a, 0x003a5, 0x01f5c, 0x003a5, 0x01f5e, 0x003a5,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00395, 0x00395, 0x00397, 0x00397, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x003a5, 0x003a5, 0x003a9, 0x003a9, 0x01f7e, 0x01f7f,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fb5, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fbd, 0x00399, 0x01fbd,
+ 0x01fc0, 0x000a8, 0x00397, 0x00397, 0x00397, 0x01fc5, 0x00397, 0x00397,
+ 0x00395, 0x00395, 0x00397, 0x00397, 0x00397, 0x01fbd, 0x01fbd, 0x01fbd,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fd4, 0x01fd5, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fdc, 0x01fdd, 0x01fdd, 0x01fdd,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x003a1, 0x003a5, 0x003a5,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x000a8, 0x000a8, 0x00060,
+ 0x01ff0, 0x01ff1, 0x003a9, 0x003a9, 0x003a9, 0x01ff5, 0x003a9, 0x003a9,
+ 0x0039f, 0x0039f, 0x003a9, 0x003a9, 0x003a9, 0x000b4, 0x01fdd, 0x01fff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_20[] = {
+ 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020,
+ 0x00020, 0x00020, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x02010, 0x02010, 0x02012, 0x02013, 0x02014, 0x02015, 0x02016, 0x02017,
+ 0x02018, 0x02019, 0x0201a, 0x0201b, 0x0201c, 0x0201d, 0x0201e, 0x0201f,
+ 0x02020, 0x02021, 0x02022, 0x02023, 0x0002e, 0x02025, 0x02026, 0x02027,
+ 0x02028, 0x02029, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00020,
+ 0x02030, 0x02031, 0x02032, 0x02033, 0x02034, 0x02035, 0x02036, 0x02037,
+ 0x02038, 0x02039, 0x0203a, 0x0203b, 0x0203c, 0x0203d, 0x0203e, 0x0203f,
+ 0x02040, 0x02041, 0x02042, 0x02043, 0x02044, 0x02045, 0x02046, 0x02047,
+ 0x02048, 0x02049, 0x0204a, 0x0204b, 0x0204c, 0x0204d, 0x0204e, 0x0204f,
+ 0x02050, 0x02051, 0x02052, 0x02053, 0x02054, 0x02055, 0x02056, 0x02057,
+ 0x02058, 0x02059, 0x0205a, 0x0205b, 0x0205c, 0x0205d, 0x0205e, 0x00020,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x02064, 0x02065, 0x02066, 0x02067,
+ 0x02068, 0x02069, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00030, 0x00049, 0x02072, 0x02073, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0004e,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0208f,
+ 0x02090, 0x02091, 0x02092, 0x02093, 0x02094, 0x02095, 0x02096, 0x02097,
+ 0x02098, 0x02099, 0x0209a, 0x0209b, 0x0209c, 0x0209d, 0x0209e, 0x0209f,
+ 0x020a0, 0x020a1, 0x020a2, 0x020a3, 0x020a4, 0x020a5, 0x020a6, 0x020a7,
+ 0x020a8, 0x020a9, 0x020aa, 0x020ab, 0x020ac, 0x020ad, 0x020ae, 0x020af,
+ 0x020b0, 0x020b1, 0x020b2, 0x020b3, 0x020b4, 0x020b5, 0x020b6, 0x020b7,
+ 0x020b8, 0x020b9, 0x020ba, 0x020bb, 0x020bc, 0x020bd, 0x020be, 0x020bf,
+ 0x020c0, 0x020c1, 0x020c2, 0x020c3, 0x020c4, 0x020c5, 0x020c6, 0x020c7,
+ 0x020c8, 0x020c9, 0x020ca, 0x020cb, 0x020cc, 0x020cd, 0x020ce, 0x020cf,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x020eb, 0x020ec, 0x020ed, 0x020ee, 0x020ef,
+ 0x020f0, 0x020f1, 0x020f2, 0x020f3, 0x020f4, 0x020f5, 0x020f6, 0x020f7,
+ 0x020f8, 0x020f9, 0x020fa, 0x020fb, 0x020fc, 0x020fd, 0x020fe, 0x020ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_21[] = {
+ 0x02100, 0x02101, 0x00043, 0x02103, 0x02104, 0x02105, 0x02106, 0x00190,
+ 0x02108, 0x02109, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00126,
+ 0x00049, 0x00049, 0x0004c, 0x0004c, 0x02114, 0x0004e, 0x02116, 0x02117,
+ 0x02118, 0x00050, 0x00051, 0x00052, 0x00052, 0x00052, 0x0211e, 0x0211f,
+ 0x02120, 0x02121, 0x02122, 0x02123, 0x0005a, 0x02125, 0x003a9, 0x02127,
+ 0x0005a, 0x02129, 0x0004b, 0x00041, 0x00042, 0x00043, 0x0212e, 0x00045,
+ 0x00045, 0x00046, 0x02132, 0x0004d, 0x0004f, 0x005d0, 0x005d1, 0x005d2,
+ 0x005d3, 0x00049, 0x0213a, 0x0213b, 0x0213c, 0x00393, 0x00393, 0x003a0,
+ 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x00044, 0x00044, 0x00045,
+ 0x00049, 0x0004a, 0x0214a, 0x0214b, 0x0214c, 0x0214d, 0x0214e, 0x0214f,
+ 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157,
+ 0x02158, 0x02159, 0x0215a, 0x0215b, 0x0215c, 0x0215d, 0x0215e, 0x0215f,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x02180, 0x02181, 0x02182, 0x02183, 0x02184, 0x02185, 0x02186, 0x02187,
+ 0x02188, 0x02189, 0x0218a, 0x0218b, 0x0218c, 0x0218d, 0x0218e, 0x0218f,
+ 0x02190, 0x02191, 0x02192, 0x02193, 0x02194, 0x02195, 0x02196, 0x02197,
+ 0x02198, 0x02199, 0x02190, 0x02192, 0x0219c, 0x0219d, 0x0219e, 0x0219f,
+ 0x021a0, 0x021a1, 0x021a2, 0x021a3, 0x021a4, 0x021a5, 0x021a6, 0x021a7,
+ 0x021a8, 0x021a9, 0x021aa, 0x021ab, 0x021ac, 0x021ad, 0x02194, 0x021af,
+ 0x021b0, 0x021b1, 0x021b2, 0x021b3, 0x021b4, 0x021b5, 0x021b6, 0x021b7,
+ 0x021b8, 0x021b9, 0x021ba, 0x021bb, 0x021bc, 0x021bd, 0x021be, 0x021bf,
+ 0x021c0, 0x021c1, 0x021c2, 0x021c3, 0x021c4, 0x021c5, 0x021c6, 0x021c7,
+ 0x021c8, 0x021c9, 0x021ca, 0x021cb, 0x021cc, 0x021cd, 0x021ce, 0x021cf,
+ 0x021cd, 0x021d1, 0x021cf, 0x021d3, 0x021ce, 0x021d5, 0x021d6, 0x021d7,
+ 0x021d8, 0x021d9, 0x021da, 0x021db, 0x021dc, 0x021dd, 0x021de, 0x021df,
+ 0x021e0, 0x021e1, 0x021e2, 0x021e3, 0x021e4, 0x021e5, 0x021e6, 0x021e7,
+ 0x021e8, 0x021e9, 0x021ea, 0x021eb, 0x021ec, 0x021ed, 0x021ee, 0x021ef,
+ 0x021f0, 0x021f1, 0x021f2, 0x021f3, 0x021f4, 0x021f5, 0x021f6, 0x021f7,
+ 0x021f8, 0x021f9, 0x021fa, 0x021fb, 0x021fc, 0x021fd, 0x021fe, 0x021ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_22[] = {
+ 0x02200, 0x02201, 0x02202, 0x02203, 0x02203, 0x02205, 0x02206, 0x02207,
+ 0x02208, 0x02208, 0x0220a, 0x0220b, 0x0220b, 0x0220d, 0x0220e, 0x0220f,
+ 0x02210, 0x02140, 0x0207b, 0x02213, 0x02214, 0x02215, 0x02216, 0x02217,
+ 0x02218, 0x02219, 0x0221a, 0x0221b, 0x0221c, 0x0221d, 0x0221e, 0x0221f,
+ 0x02220, 0x02221, 0x02222, 0x02223, 0x02223, 0x02225, 0x02225, 0x02227,
+ 0x02228, 0x02229, 0x0222a, 0x0222b, 0x0222c, 0x0222d, 0x0222e, 0x0222f,
+ 0x02230, 0x02231, 0x02232, 0x02233, 0x02234, 0x02235, 0x02236, 0x02237,
+ 0x02238, 0x02239, 0x0223a, 0x0223b, 0x0223c, 0x0223d, 0x0223e, 0x0223f,
+ 0x02240, 0x0223c, 0x02242, 0x02243, 0x02243, 0x02245, 0x02246, 0x02245,
+ 0x02248, 0x02248, 0x0224a, 0x0224b, 0x0224c, 0x0224d, 0x0224e, 0x0224f,
+ 0x02250, 0x02251, 0x02252, 0x02253, 0x02254, 0x02255, 0x02256, 0x02257,
+ 0x02258, 0x02259, 0x0225a, 0x0225b, 0x0225c, 0x0225d, 0x0225e, 0x0225f,
+ 0x0003d, 0x02261, 0x02261, 0x02263, 0x02264, 0x02265, 0x02266, 0x02267,
+ 0x02268, 0x02269, 0x0226a, 0x0226b, 0x0226c, 0x0224d, 0x0003c, 0x0003e,
+ 0x02264, 0x02265, 0x02272, 0x02273, 0x02272, 0x02273, 0x02276, 0x02277,
+ 0x02276, 0x02277, 0x0227a, 0x0227b, 0x0227c, 0x0227d, 0x0227e, 0x0227f,
+ 0x0227a, 0x0227b, 0x02282, 0x02283, 0x02282, 0x02283, 0x02286, 0x02287,
+ 0x02286, 0x02287, 0x0228a, 0x0228b, 0x0228c, 0x0228d, 0x0228e, 0x0228f,
+ 0x02290, 0x02291, 0x02292, 0x02293, 0x02294, 0x02295, 0x02296, 0x02297,
+ 0x02298, 0x02299, 0x0229a, 0x0229b, 0x0229c, 0x0229d, 0x0229e, 0x0229f,
+ 0x022a0, 0x022a1, 0x022a2, 0x022a3, 0x022a4, 0x022a5, 0x022a6, 0x022a7,
+ 0x022a8, 0x022a9, 0x022aa, 0x022ab, 0x022a2, 0x022a8, 0x022a9, 0x022ab,
+ 0x022b0, 0x022b1, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022b6, 0x022b7,
+ 0x022b8, 0x022b9, 0x022ba, 0x022bb, 0x022bc, 0x022bd, 0x022be, 0x022bf,
+ 0x022c0, 0x022c1, 0x022c2, 0x022c3, 0x022c4, 0x022c5, 0x022c6, 0x022c7,
+ 0x022c8, 0x022c9, 0x022ca, 0x022cb, 0x022cc, 0x022cd, 0x022ce, 0x022cf,
+ 0x022d0, 0x022d1, 0x022d2, 0x022d3, 0x022d4, 0x022d5, 0x022d6, 0x022d7,
+ 0x022d8, 0x022d9, 0x022da, 0x022db, 0x022dc, 0x022dd, 0x022de, 0x022df,
+ 0x0227c, 0x0227d, 0x02291, 0x02292, 0x022e4, 0x022e5, 0x022e6, 0x022e7,
+ 0x022e8, 0x022e9, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022ee, 0x022ef,
+ 0x022f0, 0x022f1, 0x022f2, 0x022f3, 0x022f4, 0x022f5, 0x022f6, 0x022f7,
+ 0x022f8, 0x022f9, 0x022fa, 0x022fb, 0x022fc, 0x022fd, 0x022fe, 0x022ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_24[] = {
+ 0x02400, 0x02401, 0x02402, 0x02403, 0x02404, 0x02405, 0x02406, 0x02407,
+ 0x02408, 0x02409, 0x0240a, 0x0240b, 0x0240c, 0x0240d, 0x0240e, 0x0240f,
+ 0x02410, 0x02411, 0x02412, 0x02413, 0x02414, 0x02415, 0x02416, 0x02417,
+ 0x02418, 0x02419, 0x0241a, 0x0241b, 0x0241c, 0x0241d, 0x0241e, 0x0241f,
+ 0x02420, 0x02421, 0x02422, 0x02423, 0x02424, 0x02425, 0x02426, 0x02427,
+ 0x02428, 0x02429, 0x0242a, 0x0242b, 0x0242c, 0x0242d, 0x0242e, 0x0242f,
+ 0x02430, 0x02431, 0x02432, 0x02433, 0x02434, 0x02435, 0x02436, 0x02437,
+ 0x02438, 0x02439, 0x0243a, 0x0243b, 0x0243c, 0x0243d, 0x0243e, 0x0243f,
+ 0x02440, 0x02441, 0x02442, 0x02443, 0x02444, 0x02445, 0x02446, 0x02447,
+ 0x02448, 0x02449, 0x0244a, 0x0244b, 0x0244c, 0x0244d, 0x0244e, 0x0244f,
+ 0x02450, 0x02451, 0x02452, 0x02453, 0x02454, 0x02455, 0x02456, 0x02457,
+ 0x02458, 0x02459, 0x0245a, 0x0245b, 0x0245c, 0x0245d, 0x0245e, 0x0245f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e, 0x0246f,
+ 0x02470, 0x02471, 0x02472, 0x02473, 0x02474, 0x02475, 0x02476, 0x02477,
+ 0x02478, 0x02479, 0x0247a, 0x0247b, 0x0247c, 0x0247d, 0x0247e, 0x0247f,
+ 0x02480, 0x02481, 0x02482, 0x02483, 0x02484, 0x02485, 0x02486, 0x02487,
+ 0x02488, 0x02489, 0x0248a, 0x0248b, 0x0248c, 0x0248d, 0x0248e, 0x0248f,
+ 0x02490, 0x02491, 0x02492, 0x02493, 0x02494, 0x02495, 0x02496, 0x02497,
+ 0x02498, 0x02499, 0x0249a, 0x0249b, 0x0249c, 0x0249d, 0x0249e, 0x0249f,
+ 0x024a0, 0x024a1, 0x024a2, 0x024a3, 0x024a4, 0x024a5, 0x024a6, 0x024a7,
+ 0x024a8, 0x024a9, 0x024aa, 0x024ab, 0x024ac, 0x024ad, 0x024ae, 0x024af,
+ 0x024b0, 0x024b1, 0x024b2, 0x024b3, 0x024b4, 0x024b5, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00030, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e,
+ 0x0246f, 0x02470, 0x02471, 0x02472, 0x02473, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469, 0x00030
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_27[] = {
+ 0x02700, 0x02701, 0x02702, 0x02703, 0x02704, 0x02705, 0x02706, 0x02707,
+ 0x02708, 0x02709, 0x0270a, 0x0270b, 0x0270c, 0x0270d, 0x0270e, 0x0270f,
+ 0x02710, 0x02711, 0x02712, 0x02713, 0x02714, 0x02715, 0x02716, 0x02717,
+ 0x02718, 0x02719, 0x0271a, 0x0271b, 0x0271c, 0x0271d, 0x0271e, 0x0271f,
+ 0x02720, 0x02721, 0x02722, 0x02723, 0x02724, 0x02725, 0x02726, 0x02727,
+ 0x02728, 0x02729, 0x0272a, 0x0272b, 0x0272c, 0x0272d, 0x0272e, 0x0272f,
+ 0x02730, 0x02731, 0x02732, 0x02733, 0x02734, 0x02735, 0x02736, 0x02737,
+ 0x02738, 0x02739, 0x0273a, 0x0273b, 0x0273c, 0x0273d, 0x0273e, 0x0273f,
+ 0x02740, 0x02741, 0x02742, 0x02743, 0x02744, 0x02745, 0x02746, 0x02747,
+ 0x02748, 0x02749, 0x0274a, 0x0274b, 0x0274c, 0x0274d, 0x0274e, 0x0274f,
+ 0x02750, 0x02751, 0x02752, 0x02753, 0x02754, 0x02755, 0x02756, 0x02757,
+ 0x02758, 0x02759, 0x0275a, 0x0275b, 0x0275c, 0x0275d, 0x0275e, 0x0275f,
+ 0x02760, 0x02761, 0x02762, 0x02763, 0x02764, 0x02765, 0x02766, 0x02767,
+ 0x02768, 0x02769, 0x0276a, 0x0276b, 0x0276c, 0x0276d, 0x0276e, 0x0276f,
+ 0x02770, 0x02771, 0x02772, 0x02773, 0x02774, 0x02775, 0x00031, 0x00032,
+ 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x02469, 0x02794, 0x02795, 0x02796, 0x02797,
+ 0x02798, 0x02799, 0x0279a, 0x0279b, 0x0279c, 0x0279d, 0x0279e, 0x0279f,
+ 0x027a0, 0x027a1, 0x027a2, 0x027a3, 0x027a4, 0x027a5, 0x027a6, 0x027a7,
+ 0x027a8, 0x027a9, 0x027aa, 0x027ab, 0x027ac, 0x027ad, 0x027ae, 0x027af,
+ 0x027b0, 0x027b1, 0x027b2, 0x027b3, 0x027b4, 0x027b5, 0x027b6, 0x027b7,
+ 0x027b8, 0x027b9, 0x027ba, 0x027bb, 0x027bc, 0x027bd, 0x027be, 0x027bf,
+ 0x027c0, 0x027c1, 0x027c2, 0x027c3, 0x027c4, 0x027c5, 0x027c6, 0x027c7,
+ 0x027c8, 0x027c9, 0x027ca, 0x027cb, 0x027cc, 0x027cd, 0x027ce, 0x027cf,
+ 0x027d0, 0x027d1, 0x027d2, 0x027d3, 0x027d4, 0x027d5, 0x027d6, 0x027d7,
+ 0x027d8, 0x027d9, 0x027da, 0x027db, 0x027dc, 0x027dd, 0x027de, 0x027df,
+ 0x027e0, 0x027e1, 0x027e2, 0x027e3, 0x027e4, 0x027e5, 0x027e6, 0x027e7,
+ 0x027e8, 0x027e9, 0x027ea, 0x027eb, 0x027ec, 0x027ed, 0x027ee, 0x027ef,
+ 0x027f0, 0x027f1, 0x027f2, 0x027f3, 0x027f4, 0x027f5, 0x027f6, 0x027f7,
+ 0x027f8, 0x027f9, 0x027fa, 0x027fb, 0x027fc, 0x027fd, 0x027fe, 0x027ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2a[] = {
+ 0x02a00, 0x02a01, 0x02a02, 0x02a03, 0x02a04, 0x02a05, 0x02a06, 0x02a07,
+ 0x02a08, 0x02a09, 0x02a0a, 0x02a0b, 0x02a0c, 0x02a0d, 0x02a0e, 0x02a0f,
+ 0x02a10, 0x02a11, 0x02a12, 0x02a13, 0x02a14, 0x02a15, 0x02a16, 0x02a17,
+ 0x02a18, 0x02a19, 0x02a1a, 0x02a1b, 0x02a1c, 0x02a1d, 0x02a1e, 0x02a1f,
+ 0x02a20, 0x02a21, 0x02a22, 0x02a23, 0x02a24, 0x02a25, 0x02a26, 0x02a27,
+ 0x02a28, 0x02a29, 0x02a2a, 0x02a2b, 0x02a2c, 0x02a2d, 0x02a2e, 0x02a2f,
+ 0x02a30, 0x02a31, 0x02a32, 0x02a33, 0x02a34, 0x02a35, 0x02a36, 0x02a37,
+ 0x02a38, 0x02a39, 0x02a3a, 0x02a3b, 0x02a3c, 0x02a3d, 0x02a3e, 0x02a3f,
+ 0x02a40, 0x02a41, 0x02a42, 0x02a43, 0x02a44, 0x02a45, 0x02a46, 0x02a47,
+ 0x02a48, 0x02a49, 0x02a4a, 0x02a4b, 0x02a4c, 0x02a4d, 0x02a4e, 0x02a4f,
+ 0x02a50, 0x02a51, 0x02a52, 0x02a53, 0x02a54, 0x02a55, 0x02a56, 0x02a57,
+ 0x02a58, 0x02a59, 0x02a5a, 0x02a5b, 0x02a5c, 0x02a5d, 0x02a5e, 0x02a5f,
+ 0x02a60, 0x02a61, 0x02a62, 0x02a63, 0x02a64, 0x02a65, 0x02a66, 0x02a67,
+ 0x02a68, 0x02a69, 0x02a6a, 0x02a6b, 0x02a6c, 0x02a6d, 0x02a6e, 0x02a6f,
+ 0x02a70, 0x02a71, 0x02a72, 0x02a73, 0x02a74, 0x02a75, 0x02a76, 0x02a77,
+ 0x02a78, 0x02a79, 0x02a7a, 0x02a7b, 0x02a7c, 0x02a7d, 0x02a7e, 0x02a7f,
+ 0x02a80, 0x02a81, 0x02a82, 0x02a83, 0x02a84, 0x02a85, 0x02a86, 0x02a87,
+ 0x02a88, 0x02a89, 0x02a8a, 0x02a8b, 0x02a8c, 0x02a8d, 0x02a8e, 0x02a8f,
+ 0x02a90, 0x02a91, 0x02a92, 0x02a93, 0x02a94, 0x02a95, 0x02a96, 0x02a97,
+ 0x02a98, 0x02a99, 0x02a9a, 0x02a9b, 0x02a9c, 0x02a9d, 0x02a9e, 0x02a9f,
+ 0x02aa0, 0x02aa1, 0x02aa2, 0x02aa3, 0x02aa4, 0x02aa5, 0x02aa6, 0x02aa7,
+ 0x02aa8, 0x02aa9, 0x02aaa, 0x02aab, 0x02aac, 0x02aad, 0x02aae, 0x02aaf,
+ 0x02ab0, 0x02ab1, 0x02ab2, 0x02ab3, 0x02ab4, 0x02ab5, 0x02ab6, 0x02ab7,
+ 0x02ab8, 0x02ab9, 0x02aba, 0x02abb, 0x02abc, 0x02abd, 0x02abe, 0x02abf,
+ 0x02ac0, 0x02ac1, 0x02ac2, 0x02ac3, 0x02ac4, 0x02ac5, 0x02ac6, 0x02ac7,
+ 0x02ac8, 0x02ac9, 0x02aca, 0x02acb, 0x02acc, 0x02acd, 0x02ace, 0x02acf,
+ 0x02ad0, 0x02ad1, 0x02ad2, 0x02ad3, 0x02ad4, 0x02ad5, 0x02ad6, 0x02ad7,
+ 0x02ad8, 0x02ad9, 0x02ada, 0x02adb, 0x02adc, 0x02adc, 0x02ade, 0x02adf,
+ 0x02ae0, 0x02ae1, 0x02ae2, 0x02ae3, 0x02ae4, 0x02ae5, 0x02ae6, 0x02ae7,
+ 0x02ae8, 0x02ae9, 0x02aea, 0x02aeb, 0x02aec, 0x02aed, 0x02aee, 0x02aef,
+ 0x02af0, 0x02af1, 0x02af2, 0x02af3, 0x02af4, 0x02af5, 0x02af6, 0x02af7,
+ 0x02af8, 0x02af9, 0x02afa, 0x02afb, 0x02afc, 0x02afd, 0x02afe, 0x02aff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2e[] = {
+ 0x02e00, 0x02e01, 0x02e02, 0x02e03, 0x02e04, 0x02e05, 0x02e06, 0x02e07,
+ 0x02e08, 0x02e09, 0x02e0a, 0x02e0b, 0x02e0c, 0x02e0d, 0x02e0e, 0x02e0f,
+ 0x02e10, 0x02e11, 0x02e12, 0x02e13, 0x02e14, 0x02e15, 0x02e16, 0x02e17,
+ 0x02e18, 0x02e19, 0x02e1a, 0x02e1b, 0x02e1c, 0x02e1d, 0x02e1e, 0x02e1f,
+ 0x02e20, 0x02e21, 0x02e22, 0x02e23, 0x02e24, 0x02e25, 0x02e26, 0x02e27,
+ 0x02e28, 0x02e29, 0x02e2a, 0x02e2b, 0x02e2c, 0x02e2d, 0x02e2e, 0x02e2f,
+ 0x02e30, 0x02e31, 0x02e32, 0x02e33, 0x02e34, 0x02e35, 0x02e36, 0x02e37,
+ 0x02e38, 0x02e39, 0x02e3a, 0x02e3b, 0x02e3c, 0x02e3d, 0x02e3e, 0x02e3f,
+ 0x02e40, 0x02e41, 0x02e42, 0x02e43, 0x02e44, 0x02e45, 0x02e46, 0x02e47,
+ 0x02e48, 0x02e49, 0x02e4a, 0x02e4b, 0x02e4c, 0x02e4d, 0x02e4e, 0x02e4f,
+ 0x02e50, 0x02e51, 0x02e52, 0x02e53, 0x02e54, 0x02e55, 0x02e56, 0x02e57,
+ 0x02e58, 0x02e59, 0x02e5a, 0x02e5b, 0x02e5c, 0x02e5d, 0x02e5e, 0x02e5f,
+ 0x02e60, 0x02e61, 0x02e62, 0x02e63, 0x02e64, 0x02e65, 0x02e66, 0x02e67,
+ 0x02e68, 0x02e69, 0x02e6a, 0x02e6b, 0x02e6c, 0x02e6d, 0x02e6e, 0x02e6f,
+ 0x02e70, 0x02e71, 0x02e72, 0x02e73, 0x02e74, 0x02e75, 0x02e76, 0x02e77,
+ 0x02e78, 0x02e79, 0x02e7a, 0x02e7b, 0x02e7c, 0x02e7d, 0x02e7e, 0x02e7f,
+ 0x02e80, 0x02e81, 0x02e82, 0x02e83, 0x0319a, 0x02e85, 0x02e86, 0x02f0f,
+ 0x02f11, 0x02e89, 0x02f18, 0x02e8b, 0x02f29, 0x02f29, 0x02e8e, 0x02e8f,
+ 0x02e8e, 0x02e8f, 0x02e92, 0x02e93, 0x02e94, 0x02e95, 0x02e96, 0x02f3c,
+ 0x02e98, 0x02e99, 0x02e9a, 0x02e9b, 0x02f47, 0x02f49, 0x02e9e, 0x02e9f,
+ 0x02ea0, 0x02ea1, 0x02ea2, 0x02ea3, 0x02ea4, 0x02ea4, 0x02ea6, 0x02f5c,
+ 0x02ea8, 0x02ea9, 0x02eaa, 0x02f6c, 0x02f70, 0x02ead, 0x02f75, 0x02eaf,
+ 0x02eb0, 0x02eb1, 0x02eb2, 0x02eb1, 0x02eb1, 0x02eb2, 0x02eb7, 0x02eb7,
+ 0x02eb8, 0x02eb9, 0x02eba, 0x02f80, 0x02f81, 0x02f85, 0x02ebe, 0x02ebe,
+ 0x02ebe, 0x02ec1, 0x02ec2, 0x02ec3, 0x02ec4, 0x02ec5, 0x02f93, 0x02f93,
+ 0x02ec8, 0x02ec9, 0x02f9c, 0x02ecb, 0x02ecc, 0x02ecc, 0x02ecc, 0x02fa2,
+ 0x02ed0, 0x02fa7, 0x02ed2, 0x02ed3, 0x02ed4, 0x02fa9, 0x02ed6, 0x02fac,
+ 0x02ed8, 0x02ed9, 0x02eda, 0x02edb, 0x02edc, 0x02fb7, 0x02ede, 0x02ede,
+ 0x02ee0, 0x02fb8, 0x02ee2, 0x02fbb, 0x02fc1, 0x02ee5, 0x02ee6, 0x02ee7,
+ 0x02ee8, 0x02ee9, 0x02eea, 0x02eeb, 0x02eec, 0x02eed, 0x02eee, 0x02eef,
+ 0x02ef0, 0x02ef2, 0x02ef2, 0x02ef3, 0x02ef4, 0x02ef5, 0x02ef6, 0x02ef7,
+ 0x02ef8, 0x02ef9, 0x02efa, 0x02efb, 0x02efc, 0x02efd, 0x02efe, 0x02eff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f[] = {
+ 0x03192, 0x02f01, 0x02e80, 0x02f03, 0x0319a, 0x02f05, 0x03193, 0x02f07,
+ 0x0319f, 0x02f09, 0x02f0a, 0x02f0b, 0x02e86, 0x02f0d, 0x02f0e, 0x02f0f,
+ 0x02f10, 0x02f11, 0x02f12, 0x02f13, 0x02f14, 0x02f15, 0x02f16, 0x02f17,
+ 0x02f18, 0x02e8b, 0x02e81, 0x02f1b, 0x02f1c, 0x02f1d, 0x02f1e, 0x02f1f,
+ 0x02f20, 0x02f21, 0x02f22, 0x02f23, 0x02f24, 0x02f25, 0x02f26, 0x02f27,
+ 0x02f28, 0x02f29, 0x02e8e, 0x02f2b, 0x02f2c, 0x02f2d, 0x02f2e, 0x02f2f,
+ 0x02f30, 0x02f31, 0x02f32, 0x02e93, 0x02f34, 0x02f35, 0x02f36, 0x02f37,
+ 0x02f38, 0x02e95, 0x02f3a, 0x02f3b, 0x02f3c, 0x02f3d, 0x02f3e, 0x02f3f,
+ 0x02f40, 0x02f41, 0x02f42, 0x02f43, 0x02f44, 0x02f45, 0x02f46, 0x02f47,
+ 0x02f48, 0x02f49, 0x02f4a, 0x02f4b, 0x02f4c, 0x02f4d, 0x02f4e, 0x02f4f,
+ 0x02f50, 0x02f51, 0x02f52, 0x02f53, 0x02f54, 0x02f55, 0x02f56, 0x02f57,
+ 0x02f58, 0x02f59, 0x02f5a, 0x02f5b, 0x02f5c, 0x02f5d, 0x02f5e, 0x02f5f,
+ 0x02f60, 0x02f61, 0x02f62, 0x02f63, 0x02f64, 0x02f65, 0x02eaa, 0x02f67,
+ 0x02f68, 0x02f69, 0x02f6a, 0x02f6b, 0x02f6c, 0x02f6d, 0x02f6e, 0x02f6f,
+ 0x02f70, 0x02f71, 0x02f72, 0x02f73, 0x02f74, 0x02f75, 0x02f76, 0x02f77,
+ 0x02f78, 0x02f79, 0x02eb7, 0x02f7b, 0x02f7c, 0x02f7d, 0x02f7e, 0x02f7f,
+ 0x02f80, 0x02f81, 0x02f82, 0x02f83, 0x02f84, 0x02f85, 0x02f86, 0x02f87,
+ 0x02f88, 0x02f89, 0x02f8a, 0x02f8b, 0x02f8c, 0x02f8d, 0x02f8e, 0x02f8f,
+ 0x02f90, 0x02f91, 0x02f92, 0x02f93, 0x02f94, 0x02f95, 0x02f96, 0x02f97,
+ 0x02f98, 0x02f99, 0x02f9a, 0x02f9b, 0x02f9c, 0x02f9d, 0x02f9e, 0x02f9f,
+ 0x02fa0, 0x02fa1, 0x02fa2, 0x02fa3, 0x02fa4, 0x02fa5, 0x02fa6, 0x02fa7,
+ 0x02fa8, 0x02fa9, 0x02faa, 0x02fab, 0x02fac, 0x02fad, 0x02fae, 0x02faf,
+ 0x02fb0, 0x02fb1, 0x02fb2, 0x02fb3, 0x02fb4, 0x02fb5, 0x02fb6, 0x02fb7,
+ 0x02fb8, 0x02fb9, 0x02fba, 0x02fbb, 0x02fbc, 0x02fbd, 0x02fbe, 0x02fbf,
+ 0x02fc0, 0x02fc1, 0x02fc2, 0x02fc3, 0x02ee7, 0x02fc5, 0x02fc6, 0x02fc7,
+ 0x02fc8, 0x02fc9, 0x02fca, 0x02fcb, 0x02fcc, 0x02fcd, 0x02fce, 0x02fcf,
+ 0x02fd0, 0x02eeb, 0x02eed, 0x02eef, 0x02ef2, 0x02fd5, 0x02fd6, 0x02fd7,
+ 0x02fd8, 0x02fd9, 0x02fda, 0x02fdb, 0x02fdc, 0x02fdd, 0x02fde, 0x02fdf,
+ 0x02fe0, 0x02fe1, 0x02fe2, 0x02fe3, 0x02fe4, 0x02fe5, 0x02fe6, 0x02fe7,
+ 0x02fe8, 0x02fe9, 0x02fea, 0x02feb, 0x02fec, 0x02fed, 0x02fee, 0x02fef,
+ 0x02ff0, 0x02ff1, 0x02ff2, 0x02ff3, 0x02ff4, 0x02ff5, 0x02ff6, 0x02ff7,
+ 0x02ff8, 0x02ff9, 0x02ffa, 0x02ffb, 0x02ffc, 0x02ffd, 0x02ffe, 0x02fff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_30[] = {
+ 0x00020, 0x03001, 0x03002, 0x03003, 0x03004, 0x03005, 0x03006, 0x00030,
+ 0x02329, 0x0232a, 0x0300a, 0x0300b, 0x0300c, 0x0300d, 0x0300e, 0x0300f,
+ 0x03010, 0x03011, 0x03012, 0x03013, 0x03014, 0x03015, 0x03016, 0x03017,
+ 0x03018, 0x03019, 0x0301a, 0x0301b, 0x0301c, 0x0301d, 0x0301e, 0x0301f,
+ 0x03020, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x03030, 0x03031, 0x03031, 0x03033, 0x03033, 0x03035, 0x03012, 0x03037,
+ 0x02f17, 0x03039, 0x0303a, 0x0303b, 0x0303c, 0x0303d, 0x0303e, 0x0303f,
+ 0x03040, 0x03041, 0x03042, 0x03043, 0x03044, 0x03045, 0x03046, 0x03047,
+ 0x03048, 0x03049, 0x0304a, 0x0304b, 0x0304c, 0x0304d, 0x0304e, 0x0304f,
+ 0x03050, 0x03051, 0x03052, 0x03053, 0x03054, 0x03055, 0x03056, 0x03057,
+ 0x03058, 0x03059, 0x0305a, 0x0305b, 0x0305c, 0x0305d, 0x0305e, 0x0305f,
+ 0x03060, 0x03061, 0x03062, 0x03063, 0x03064, 0x03065, 0x03066, 0x03067,
+ 0x03068, 0x03069, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x03070, 0x03071, 0x03072, 0x03073, 0x03074, 0x03075, 0x03076, 0x03077,
+ 0x03078, 0x03079, 0x0307a, 0x0307b, 0x0307c, 0x0307d, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03083, 0x03084, 0x03085, 0x03086, 0x03087,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308e, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x03097,
+ 0x03098, 0x00000, 0x00000, 0x0309b, 0x0309c, 0x0309d, 0x0309d, 0x0309f,
+ 0x030a0, 0x03041, 0x03042, 0x03043, 0x03044, 0x03045, 0x03046, 0x03047,
+ 0x03048, 0x03049, 0x0304a, 0x0304b, 0x0304c, 0x0304d, 0x0304e, 0x0304f,
+ 0x03050, 0x03051, 0x03052, 0x03053, 0x03054, 0x03055, 0x03056, 0x03057,
+ 0x03058, 0x03059, 0x0305a, 0x0305b, 0x0305c, 0x0305d, 0x0305e, 0x0305f,
+ 0x03060, 0x03061, 0x03062, 0x03063, 0x03064, 0x03065, 0x03066, 0x03067,
+ 0x03068, 0x03069, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x03070, 0x03071, 0x03072, 0x03073, 0x03074, 0x03075, 0x03076, 0x03077,
+ 0x03078, 0x03079, 0x0307a, 0x0307b, 0x0307c, 0x0307d, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03083, 0x03084, 0x03085, 0x03086, 0x03087,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308e, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x030fb, 0x030fc, 0x030fd, 0x030fd, 0x030ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_31[] = {
+ 0x03100, 0x03101, 0x03102, 0x03103, 0x03104, 0x03105, 0x03106, 0x03107,
+ 0x03108, 0x03109, 0x0310a, 0x0310b, 0x0310c, 0x0310d, 0x0310e, 0x0310f,
+ 0x03110, 0x03111, 0x03112, 0x03113, 0x03114, 0x03115, 0x03116, 0x03117,
+ 0x03118, 0x03119, 0x0311a, 0x0311b, 0x0311c, 0x0311d, 0x0311e, 0x0311f,
+ 0x03120, 0x03121, 0x03122, 0x03123, 0x03124, 0x03125, 0x03126, 0x03127,
+ 0x03128, 0x03129, 0x0312a, 0x0312b, 0x0312c, 0x0312d, 0x0312e, 0x0312f,
+ 0x03130, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x01161,
+ 0x01162, 0x01163, 0x01164, 0x01165, 0x01166, 0x01167, 0x01168, 0x01169,
+ 0x0116a, 0x0116b, 0x0116c, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171,
+ 0x01172, 0x01173, 0x01174, 0x01175, 0x01160, 0x01114, 0x01115, 0x011c7,
+ 0x011c8, 0x011cc, 0x011ce, 0x011d3, 0x011d7, 0x011d9, 0x0111c, 0x011dd,
+ 0x011df, 0x0111d, 0x0111e, 0x01120, 0x01122, 0x01123, 0x01127, 0x01129,
+ 0x0112b, 0x0112c, 0x0112d, 0x0112e, 0x0112f, 0x01132, 0x01136, 0x01140,
+ 0x01147, 0x0114c, 0x011f1, 0x011f2, 0x01157, 0x01158, 0x01159, 0x01184,
+ 0x01185, 0x01188, 0x01191, 0x01192, 0x01194, 0x0119e, 0x011a1, 0x0318f,
+ 0x03190, 0x03191, 0x03192, 0x03193, 0x03194, 0x03195, 0x03196, 0x03197,
+ 0x03198, 0x03199, 0x0319a, 0x0319b, 0x0319c, 0x0319d, 0x0319e, 0x0319f,
+ 0x03105, 0x03117, 0x03110, 0x0310d, 0x031a4, 0x031a4, 0x031a6, 0x0311b,
+ 0x03128, 0x0311a, 0x03127, 0x03128, 0x031ac, 0x031ad, 0x0311e, 0x03120,
+ 0x031b0, 0x031b1, 0x031b2, 0x03127, 0x03106, 0x0310a, 0x0310e, 0x0310f,
+ 0x031b8, 0x031b9, 0x031ba, 0x031bb, 0x031bc, 0x031bd, 0x031be, 0x031bf,
+ 0x031c0, 0x031c1, 0x031c2, 0x031c3, 0x031c4, 0x031c5, 0x031c6, 0x031c7,
+ 0x031c8, 0x031c9, 0x031ca, 0x031cb, 0x031cc, 0x031cd, 0x031ce, 0x031cf,
+ 0x031d0, 0x031d1, 0x031d2, 0x031d3, 0x031d4, 0x031d5, 0x031d6, 0x031d7,
+ 0x031d8, 0x031d9, 0x031da, 0x031db, 0x031dc, 0x031dd, 0x031de, 0x031df,
+ 0x031e0, 0x031e1, 0x031e2, 0x031e3, 0x031e4, 0x031e5, 0x031e6, 0x031e7,
+ 0x031e8, 0x031e9, 0x031ea, 0x031eb, 0x031ec, 0x031ed, 0x031ee, 0x031ef,
+ 0x0304f, 0x03057, 0x03059, 0x03068, 0x0306c, 0x0306f, 0x03072, 0x03075,
+ 0x03078, 0x0307b, 0x03080, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x031ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_32[] = {
+ 0x03200, 0x03201, 0x03202, 0x03203, 0x03204, 0x03205, 0x03206, 0x03207,
+ 0x03208, 0x03209, 0x0320a, 0x0320b, 0x0320c, 0x0320d, 0x0320e, 0x0320f,
+ 0x03210, 0x03211, 0x03212, 0x03213, 0x03214, 0x03215, 0x03216, 0x03217,
+ 0x03218, 0x03219, 0x0321a, 0x0321b, 0x0321c, 0x0321d, 0x0321e, 0x0321f,
+ 0x03220, 0x03221, 0x03222, 0x03223, 0x03224, 0x03225, 0x03226, 0x03227,
+ 0x03228, 0x03229, 0x0322a, 0x0322b, 0x0322c, 0x0322d, 0x0322e, 0x0322f,
+ 0x03230, 0x03231, 0x03232, 0x03233, 0x03234, 0x03235, 0x03236, 0x03237,
+ 0x03238, 0x03239, 0x0323a, 0x0323b, 0x0323c, 0x0323d, 0x0323e, 0x0323f,
+ 0x03240, 0x03241, 0x03242, 0x03243, 0x03244, 0x03245, 0x03246, 0x03247,
+ 0x03248, 0x03249, 0x0324a, 0x0324b, 0x0324c, 0x0324d, 0x0324e, 0x0324f,
+ 0x03250, 0x03251, 0x03252, 0x03253, 0x03254, 0x03255, 0x03256, 0x03257,
+ 0x03258, 0x03259, 0x0325a, 0x0325b, 0x0325c, 0x0325d, 0x0325e, 0x0325f,
+ 0x01100, 0x01102, 0x01103, 0x01105, 0x01106, 0x01107, 0x01109, 0x0110b,
+ 0x0110c, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0326e, 0x0326f,
+ 0x03270, 0x03271, 0x03272, 0x03273, 0x03274, 0x03275, 0x03276, 0x03277,
+ 0x03278, 0x03279, 0x0327a, 0x0327b, 0x0327c, 0x0327d, 0x0327e, 0x0327f,
+ 0x03192, 0x03193, 0x03194, 0x03195, 0x03284, 0x03285, 0x03286, 0x02f0b,
+ 0x03288, 0x02f17, 0x02f49, 0x02f55, 0x02f54, 0x02f4a, 0x02fa6, 0x02f1f,
+ 0x02f47, 0x03291, 0x03292, 0x03293, 0x03294, 0x03295, 0x03296, 0x03297,
+ 0x03298, 0x03299, 0x0329a, 0x02f25, 0x0329c, 0x0329d, 0x0329e, 0x0329f,
+ 0x032a0, 0x032a1, 0x032a2, 0x032a3, 0x03196, 0x03197, 0x03198, 0x032a7,
+ 0x032a8, 0x032a9, 0x032aa, 0x032ab, 0x032ac, 0x032ad, 0x032ae, 0x032af,
+ 0x032b0, 0x032b1, 0x032b2, 0x032b3, 0x032b4, 0x032b5, 0x032b6, 0x032b7,
+ 0x032b8, 0x032b9, 0x032ba, 0x032bb, 0x032bc, 0x032bd, 0x032be, 0x032bf,
+ 0x032c0, 0x032c1, 0x032c2, 0x032c3, 0x032c4, 0x032c5, 0x032c6, 0x032c7,
+ 0x032c8, 0x032c9, 0x032ca, 0x032cb, 0x032cc, 0x032cd, 0x032ce, 0x032cf,
+ 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d, 0x0304f,
+ 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d, 0x0305f,
+ 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d,
+ 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089, 0x0308a,
+ 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03090, 0x03091, 0x03092, 0x032ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_33[] = {
+ 0x03300, 0x03301, 0x03302, 0x03303, 0x03304, 0x03305, 0x03306, 0x03307,
+ 0x03308, 0x03309, 0x0330a, 0x0330b, 0x0330c, 0x0330d, 0x0330e, 0x0330f,
+ 0x03310, 0x03311, 0x03312, 0x03313, 0x03314, 0x03315, 0x03316, 0x03317,
+ 0x03318, 0x03319, 0x0331a, 0x0331b, 0x0331c, 0x0331d, 0x0331e, 0x0331f,
+ 0x03320, 0x03321, 0x03322, 0x03323, 0x03324, 0x03325, 0x03326, 0x03327,
+ 0x03328, 0x03329, 0x0332a, 0x0332b, 0x0332c, 0x0332d, 0x0332e, 0x0332f,
+ 0x03330, 0x03331, 0x03332, 0x03333, 0x03334, 0x03335, 0x03336, 0x03337,
+ 0x03338, 0x03339, 0x0333a, 0x0333b, 0x0333c, 0x0333d, 0x0333e, 0x0333f,
+ 0x03340, 0x03341, 0x03342, 0x03343, 0x03344, 0x03345, 0x03346, 0x03347,
+ 0x03348, 0x03349, 0x0334a, 0x0334b, 0x0334c, 0x0334d, 0x0334e, 0x0334f,
+ 0x03350, 0x03351, 0x03352, 0x03353, 0x03354, 0x03355, 0x03356, 0x03357,
+ 0x03358, 0x03359, 0x0335a, 0x0335b, 0x0335c, 0x0335d, 0x0335e, 0x0335f,
+ 0x03360, 0x03361, 0x03362, 0x03363, 0x03364, 0x03365, 0x03366, 0x03367,
+ 0x03368, 0x03369, 0x0336a, 0x0336b, 0x0336c, 0x0336d, 0x0336e, 0x0336f,
+ 0x03370, 0x03371, 0x03372, 0x03373, 0x03374, 0x03375, 0x03376, 0x03377,
+ 0x03378, 0x03379, 0x0337a, 0x0337b, 0x0337c, 0x0337d, 0x0337e, 0x0337f,
+ 0x03380, 0x03381, 0x03382, 0x03383, 0x03384, 0x03385, 0x03386, 0x03387,
+ 0x03388, 0x03389, 0x0338a, 0x0338b, 0x0338c, 0x0338d, 0x0338e, 0x0338f,
+ 0x03390, 0x03391, 0x03392, 0x03393, 0x03394, 0x03395, 0x03396, 0x03397,
+ 0x03398, 0x03399, 0x0339a, 0x0339b, 0x0339c, 0x0339d, 0x0339e, 0x0339f,
+ 0x033a0, 0x033a1, 0x033a2, 0x033a3, 0x033a4, 0x033a5, 0x033a6, 0x033a7,
+ 0x033a8, 0x03380, 0x033aa, 0x033ab, 0x033ac, 0x033ad, 0x033ae, 0x033af,
+ 0x033b0, 0x033b1, 0x033b2, 0x033b3, 0x033b4, 0x033b5, 0x033b6, 0x033b7,
+ 0x033b8, 0x033b7, 0x033ba, 0x033bb, 0x033bc, 0x033bd, 0x033be, 0x033bd,
+ 0x033c0, 0x033c1, 0x033c2, 0x033c3, 0x033c4, 0x033c5, 0x033c6, 0x033c7,
+ 0x033c8, 0x033c9, 0x033ca, 0x033cb, 0x033cc, 0x033cd, 0x0339e, 0x033cf,
+ 0x033d0, 0x033d1, 0x033d2, 0x033d3, 0x03386, 0x033d5, 0x033d6, 0x033d7,
+ 0x033d8, 0x033d9, 0x033da, 0x033db, 0x033dc, 0x033dd, 0x033de, 0x033df,
+ 0x033e0, 0x033e1, 0x033e2, 0x033e3, 0x033e4, 0x033e5, 0x033e6, 0x033e7,
+ 0x033e8, 0x033e9, 0x033ea, 0x033eb, 0x033ec, 0x033ed, 0x033ee, 0x033ef,
+ 0x033f0, 0x033f1, 0x033f2, 0x033f3, 0x033f4, 0x033f5, 0x033f6, 0x033f7,
+ 0x033f8, 0x033f9, 0x033fa, 0x033fb, 0x033fc, 0x033fd, 0x033fe, 0x033ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_f9[] = {
+ 0x0f900, 0x0f901, 0x02f9e, 0x0f903, 0x0f904, 0x0f905, 0x0f906, 0x02ef2,
+ 0x02ef2, 0x0f909, 0x02fa6, 0x0f90b, 0x0f90c, 0x0f90d, 0x0f90e, 0x0f90f,
+ 0x0f910, 0x0f911, 0x0f912, 0x0f913, 0x0f914, 0x0f915, 0x0f916, 0x0f917,
+ 0x0f918, 0x0f919, 0x0f91a, 0x0f91b, 0x0f91c, 0x0f91d, 0x0f91e, 0x0f91f,
+ 0x0f920, 0x0f921, 0x0f922, 0x0f923, 0x0f924, 0x0f925, 0x0f926, 0x0f927,
+ 0x0f928, 0x0f929, 0x0f92a, 0x0f92b, 0x0f92c, 0x0f92d, 0x0f92e, 0x0f92f,
+ 0x0f930, 0x0f931, 0x0f932, 0x0f933, 0x02f7c, 0x0f935, 0x0f936, 0x0f937,
+ 0x0f938, 0x0f939, 0x0f93a, 0x0f93b, 0x0f93c, 0x0f93d, 0x0f93e, 0x0f93f,
+ 0x02fc5, 0x0f941, 0x0f942, 0x0f943, 0x0f944, 0x0f945, 0x0f946, 0x0f947,
+ 0x0f948, 0x0f949, 0x0f94a, 0x0f94b, 0x0f94c, 0x0f94d, 0x0f94e, 0x0f94f,
+ 0x0f950, 0x0f951, 0x0f952, 0x0f953, 0x0f954, 0x0f955, 0x0f956, 0x0f957,
+ 0x0f958, 0x0f959, 0x0f95a, 0x0f95b, 0x0f914, 0x0f95d, 0x0f95e, 0x0f95f,
+ 0x0f960, 0x0f961, 0x0f962, 0x0f963, 0x0f964, 0x0f965, 0x0f966, 0x0f967,
+ 0x0f968, 0x0f969, 0x0f96a, 0x0f96b, 0x0f96c, 0x0f96d, 0x0f96e, 0x0f96f,
+ 0x0f970, 0x02fa0, 0x0f972, 0x0f973, 0x0f974, 0x0f975, 0x0f976, 0x0f977,
+ 0x0f978, 0x0f979, 0x0f97a, 0x0f97b, 0x0f97c, 0x0f97d, 0x0f97e, 0x0f97f,
+ 0x0f980, 0x02f25, 0x0f982, 0x0f983, 0x0f984, 0x0f985, 0x0f986, 0x0f987,
+ 0x0f988, 0x0f989, 0x02f12, 0x0f98b, 0x0f98c, 0x0f98d, 0x0f98e, 0x0f98f,
+ 0x0f990, 0x0f991, 0x0f992, 0x0f993, 0x0f994, 0x0f995, 0x0f996, 0x0f997,
+ 0x0f998, 0x0f999, 0x0f99a, 0x0f99b, 0x0f99c, 0x0f99d, 0x0f99e, 0x0f99f,
+ 0x0f9a0, 0x0f96f, 0x0f9a2, 0x0f9a3, 0x0f9a4, 0x0f9a5, 0x0f9a6, 0x0f9a7,
+ 0x0f9a8, 0x0f9a9, 0x0f95f, 0x0f9ab, 0x0f9ac, 0x0f9ad, 0x0f9ae, 0x0f9af,
+ 0x0f9b0, 0x0f9b1, 0x0f9b2, 0x0f9b3, 0x0f9b4, 0x0f9b5, 0x0f9b6, 0x0f9b7,
+ 0x0f9b8, 0x0f9b9, 0x0f9ba, 0x0f9bb, 0x0f9bc, 0x0f9bd, 0x0f9be, 0x0f914,
+ 0x0f9c0, 0x0f9c1, 0x0f9c2, 0x0f9c3, 0x02eef, 0x0f9c5, 0x0f9c6, 0x0f9c7,
+ 0x0f9c8, 0x0f9c9, 0x0f9ca, 0x0f9cb, 0x0f9cc, 0x0f9cd, 0x0f9ce, 0x0f9cf,
+ 0x0f9d0, 0x03285, 0x0f9d2, 0x0f9d3, 0x0f9d4, 0x0f9d5, 0x0f9d6, 0x0f9d7,
+ 0x0f9d8, 0x0f9d9, 0x0f9da, 0x0f961, 0x0f9dc, 0x0f9dd, 0x0f9de, 0x0f9df,
+ 0x0f9e0, 0x0f9e1, 0x0f9e2, 0x0f9e3, 0x0f9e4, 0x0f9e5, 0x0f9e6, 0x0f9e7,
+ 0x0f9e8, 0x02fa5, 0x0f9ea, 0x0f9eb, 0x0f9ec, 0x0f9ed, 0x0f9ee, 0x0f9ef,
+ 0x0f9f0, 0x0f9f1, 0x0f9f2, 0x0f9f3, 0x0f9f4, 0x0f9f5, 0x0f9f6, 0x02f74,
+ 0x0f9f8, 0x0f9f9, 0x0f9fa, 0x0f9fb, 0x0f9fc, 0x0f9fd, 0x0f9fe, 0x0f9ff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fa[] = {
+ 0x0fa00, 0x0fa01, 0x0fa02, 0x0fa03, 0x0fa04, 0x0fa05, 0x0fa06, 0x0fa07,
+ 0x02f8f, 0x0fa09, 0x02f92, 0x0fa0b, 0x0fa0c, 0x0fa0d, 0x0fa0e, 0x0fa0f,
+ 0x0fa10, 0x0fa11, 0x0fa12, 0x0fa13, 0x0fa14, 0x0fa15, 0x0fa16, 0x0fa17,
+ 0x0fa18, 0x0fa19, 0x0fa1a, 0x0fa1b, 0x0fa1c, 0x0fa1d, 0x02f7b, 0x0fa1f,
+ 0x0fa20, 0x0fa21, 0x0fa22, 0x0fa23, 0x0fa24, 0x0fa25, 0x0fa26, 0x0fa27,
+ 0x0fa28, 0x0fa29, 0x0fa2a, 0x0fa2b, 0x0fa2c, 0x0fa2d, 0x0fa2e, 0x0fa2f,
+ 0x0fa30, 0x0fa31, 0x0fa32, 0x0fa33, 0x0fa34, 0x0fa35, 0x0fa36, 0x0fa37,
+ 0x0fa38, 0x0fa39, 0x0fa3a, 0x0fa3b, 0x02f2c, 0x0fa3d, 0x0fa3e, 0x0fa3f,
+ 0x0fa40, 0x0fa41, 0x0fa42, 0x0fa43, 0x0fa44, 0x0fa45, 0x0fa46, 0x0fa47,
+ 0x0fa48, 0x02ea4, 0x0fa4a, 0x0fa4b, 0x03293, 0x0fa4d, 0x0fa4e, 0x0fa4f,
+ 0x0fa50, 0x03297, 0x0fa52, 0x0fa53, 0x0fa54, 0x0fa55, 0x0fa56, 0x0f996,
+ 0x0fa58, 0x0fa59, 0x0fa5a, 0x0fa5b, 0x0fa5c, 0x02ebe, 0x02ebe, 0x0fa5f,
+ 0x0fa60, 0x0fa61, 0x0fa62, 0x0fa63, 0x0fa64, 0x0fa65, 0x02ecc, 0x0fa25,
+ 0x0fa68, 0x0fa69, 0x0fa6a, 0x0fa6b, 0x0fa6c, 0x0fa6d, 0x0fa6e, 0x0fa6f,
+ 0x0fa70, 0x0fa71, 0x0fa72, 0x0fa73, 0x0fa74, 0x0fa75, 0x0fa76, 0x0fa77,
+ 0x0fa78, 0x0fa79, 0x0fa7a, 0x0fa7b, 0x0fa7c, 0x0fa7d, 0x0fa7e, 0x0fa7f,
+ 0x0fa80, 0x0fa81, 0x0fa82, 0x0fa83, 0x0fa84, 0x0fa85, 0x0fa86, 0x0fa87,
+ 0x0fa88, 0x0fa89, 0x0fa8a, 0x0fa8b, 0x0fa8c, 0x0fa8d, 0x0fa8e, 0x0fa8f,
+ 0x0fa90, 0x0fa91, 0x0fa92, 0x0fa93, 0x0fa94, 0x0fa95, 0x0fa96, 0x0fa97,
+ 0x0fa98, 0x0fa99, 0x0fa9a, 0x0fa9b, 0x0fa9c, 0x0fa9d, 0x0fa9e, 0x0fa9f,
+ 0x0faa0, 0x0faa1, 0x0faa2, 0x0faa3, 0x0faa4, 0x0faa5, 0x0faa6, 0x0faa7,
+ 0x0faa8, 0x0faa9, 0x0faaa, 0x0faab, 0x0faac, 0x0faad, 0x0faae, 0x0faaf,
+ 0x0fab0, 0x0fab1, 0x0fab2, 0x0fab3, 0x0fab4, 0x0fab5, 0x0fab6, 0x0fab7,
+ 0x0fab8, 0x0fab9, 0x0faba, 0x0fabb, 0x0fabc, 0x0fabd, 0x0fabe, 0x0fabf,
+ 0x0fac0, 0x0fac1, 0x0fac2, 0x0fac3, 0x0fac4, 0x0fac5, 0x0fac6, 0x0fac7,
+ 0x0fac8, 0x0fac9, 0x0faca, 0x0facb, 0x0facc, 0x0facd, 0x0face, 0x0facf,
+ 0x0fad0, 0x0fad1, 0x0fad2, 0x0fad3, 0x0fad4, 0x0fad5, 0x0fad6, 0x0fad7,
+ 0x0fad8, 0x0fad9, 0x0fada, 0x0fadb, 0x0fadc, 0x0fadd, 0x0fade, 0x0fadf,
+ 0x0fae0, 0x0fae1, 0x0fae2, 0x0fae3, 0x0fae4, 0x0fae5, 0x0fae6, 0x0fae7,
+ 0x0fae8, 0x0fae9, 0x0faea, 0x0faeb, 0x0faec, 0x0faed, 0x0faee, 0x0faef,
+ 0x0faf0, 0x0faf1, 0x0faf2, 0x0faf3, 0x0faf4, 0x0faf5, 0x0faf6, 0x0faf7,
+ 0x0faf8, 0x0faf9, 0x0fafa, 0x0fafb, 0x0fafc, 0x0fafd, 0x0fafe, 0x0faff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fb[] = {
+ 0x0fb00, 0x0fb01, 0x0fb02, 0x0fb03, 0x0fb04, 0x0fb05, 0x0fb05, 0x0fb07,
+ 0x0fb08, 0x0fb09, 0x0fb0a, 0x0fb0b, 0x0fb0c, 0x0fb0d, 0x0fb0e, 0x0fb0f,
+ 0x0fb10, 0x0fb11, 0x0fb12, 0x0fb13, 0x0fb14, 0x0fb15, 0x0fb16, 0x0fb17,
+ 0x0fb18, 0x0fb19, 0x0fb1a, 0x0fb1b, 0x0fb1c, 0x005d9, 0x00000, 0x005f2,
+ 0x005e2, 0x005d0, 0x005d3, 0x005d4, 0x005da, 0x005dc, 0x005dd, 0x005e8,
+ 0x005ea, 0x0002b, 0x005e9, 0x005e9, 0x005e9, 0x005e9, 0x005d0, 0x005d0,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x0fb37,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x0fb3d, 0x005dd, 0x0fb3f,
+ 0x005df, 0x005e1, 0x0fb42, 0x005e3, 0x005e3, 0x0fb45, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005d5, 0x005d1, 0x005da, 0x005e3, 0x0fb4f,
+ 0x00671, 0x00671, 0x0067b, 0x0067b, 0x0067b, 0x0067b, 0x0067e, 0x0067e,
+ 0x0067e, 0x0067e, 0x00680, 0x00680, 0x00680, 0x00680, 0x0067a, 0x0067a,
+ 0x0067a, 0x0067a, 0x0067f, 0x0067f, 0x0067f, 0x0067f, 0x00679, 0x00679,
+ 0x00679, 0x00679, 0x006a4, 0x006a4, 0x006a4, 0x006a4, 0x006a6, 0x006a6,
+ 0x006a6, 0x006a6, 0x00684, 0x00684, 0x00684, 0x00684, 0x00683, 0x00683,
+ 0x00683, 0x00683, 0x00686, 0x00686, 0x00686, 0x00686, 0x00687, 0x00687,
+ 0x00687, 0x00687, 0x0068d, 0x0068d, 0x0068c, 0x0068c, 0x0068e, 0x0068e,
+ 0x00688, 0x00688, 0x00698, 0x00698, 0x00691, 0x00691, 0x006a9, 0x006a9,
+ 0x006a9, 0x006a9, 0x006af, 0x006af, 0x006af, 0x006af, 0x006b3, 0x006b3,
+ 0x006b3, 0x006b3, 0x006b1, 0x006b1, 0x006b1, 0x006b1, 0x006ba, 0x006ba,
+ 0x006bb, 0x006bb, 0x006bb, 0x006bb, 0x006c0, 0x006c0, 0x006c1, 0x006c1,
+ 0x006c1, 0x006c1, 0x006be, 0x006be, 0x006be, 0x006be, 0x006d2, 0x006d2,
+ 0x006d2, 0x006d2, 0x0fbb2, 0x0fbb3, 0x0fbb4, 0x0fbb5, 0x0fbb6, 0x0fbb7,
+ 0x0fbb8, 0x0fbb9, 0x0fbba, 0x0fbbb, 0x0fbbc, 0x0fbbd, 0x0fbbe, 0x0fbbf,
+ 0x0fbc0, 0x0fbc1, 0x0fbc2, 0x0fbc3, 0x0fbc4, 0x0fbc5, 0x0fbc6, 0x0fbc7,
+ 0x0fbc8, 0x0fbc9, 0x0fbca, 0x0fbcb, 0x0fbcc, 0x0fbcd, 0x0fbce, 0x0fbcf,
+ 0x0fbd0, 0x0fbd1, 0x0fbd2, 0x006ad, 0x006ad, 0x006ad, 0x006ad, 0x006c7,
+ 0x006c7, 0x006c6, 0x006c6, 0x006c8, 0x006c8, 0x00677, 0x006cb, 0x006cb,
+ 0x006c5, 0x006c5, 0x006c9, 0x006c9, 0x006d0, 0x006d0, 0x006d0, 0x006d0,
+ 0x00649, 0x00649, 0x0fbea, 0x0fbea, 0x0fbec, 0x0fbec, 0x0fbee, 0x0fbee,
+ 0x0fbf0, 0x0fbf0, 0x0fbf2, 0x0fbf2, 0x0fbf4, 0x0fbf4, 0x0fbf6, 0x0fbf6,
+ 0x0fbf6, 0x0fbf9, 0x0fbf9, 0x0fbf9, 0x006cc, 0x006cc, 0x006cc, 0x006cc
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fc[] = {
+ 0x0fc00, 0x0fc01, 0x0fc02, 0x0fbf9, 0x0fc04, 0x0fc05, 0x0fc06, 0x0fc07,
+ 0x0fc08, 0x0fc09, 0x0fc0a, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fc0f,
+ 0x0fc10, 0x0fc11, 0x0fc12, 0x0fc13, 0x0fc14, 0x0fc15, 0x0fc16, 0x0fc17,
+ 0x0fc18, 0x0fc19, 0x0fc1a, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fc1f,
+ 0x0fc20, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25, 0x0fc26, 0x0fc27,
+ 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e, 0x0fc2f,
+ 0x0fc30, 0x0fc31, 0x0fc32, 0x0fc33, 0x0fc34, 0x0fc35, 0x0fc36, 0x0fc37,
+ 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc3f,
+ 0x0fc40, 0x0fc41, 0x0fc42, 0x0fc43, 0x0fc44, 0x0fc45, 0x0fc46, 0x0fc47,
+ 0x0fc48, 0x0fc49, 0x0fc4a, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fc4f,
+ 0x0fc50, 0x0fc51, 0x0fc52, 0x0fc53, 0x0fc54, 0x0fc55, 0x0fc56, 0x0fc57,
+ 0x0fc58, 0x0fc59, 0x0fc5a, 0x00630, 0x00631, 0x00649, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0fc64, 0x0fc65, 0x0fc02, 0x0fc67,
+ 0x0fbf9, 0x0fc04, 0x0fc6a, 0x0fc6b, 0x0fc08, 0x0fc6d, 0x0fc09, 0x0fc0a,
+ 0x0fc70, 0x0fc71, 0x0fc0e, 0x0fc73, 0x0fc0f, 0x0fc10, 0x0fc76, 0x0fc77,
+ 0x0fc12, 0x0fc79, 0x0fc13, 0x0fc14, 0x0fc31, 0x0fc32, 0x0fc35, 0x0fc36,
+ 0x0fc37, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc42, 0x0fc43, 0x0fc44,
+ 0x0fc88, 0x0fc48, 0x0fc8a, 0x0fc8b, 0x0fc4e, 0x0fc8d, 0x0fc4f, 0x0fc50,
+ 0x00649, 0x0fc91, 0x0fc92, 0x0fc58, 0x0fc94, 0x0fc59, 0x0fc5a, 0x0fc00,
+ 0x0fc01, 0x0fc99, 0x0fc02, 0x0fc9b, 0x0fc05, 0x0fc06, 0x0fc07, 0x0fc08,
+ 0x0fca0, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fc15,
+ 0x0fc16, 0x0fc17, 0x0fc18, 0x0fc19, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e,
+ 0x0fc1f, 0x0fc20, 0x0fcb2, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25,
+ 0x0fc26, 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e,
+ 0x0fc2f, 0x0fc30, 0x0fc33, 0x0fc34, 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b,
+ 0x0fc3c, 0x0fc3f, 0x0fc40, 0x0fc41, 0x0fc42, 0x0fccd, 0x0fc45, 0x0fc46,
+ 0x0fc47, 0x0fc48, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fcd6, 0x0fc51,
+ 0x0fc52, 0x00647, 0x0fc55, 0x0fc56, 0x0fc57, 0x0fc58, 0x0fcde, 0x0fc02,
+ 0x0fc9b, 0x0fc08, 0x0fca0, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fce6, 0x0fc1f,
+ 0x0fce8, 0x0fce9, 0x0fcea, 0x0fc3b, 0x0fc3c, 0x0fc42, 0x0fc4e, 0x0fcd6,
+ 0x0fc58, 0x0fcde, 0x00000, 0x00000, 0x00000, 0x0fcf5, 0x0fcf6, 0x0fcf7,
+ 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb, 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fcff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fd[] = {
+ 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03, 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07,
+ 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b, 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f,
+ 0x0fd10, 0x0fcf5, 0x0fcf6, 0x0fcf7, 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb,
+ 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fd1b, 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03,
+ 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07, 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f, 0x0fd10, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fce8, 0x0fcea, 0x0fc27, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fd09,
+ 0x0fd0a, 0x0fd0b, 0x0fc27, 0x0fc28, 0x00627, 0x00627, 0x0fd3e, 0x0fd3f,
+ 0x0fd40, 0x0fd41, 0x0fd42, 0x0fd43, 0x0fd44, 0x0fd45, 0x0fd46, 0x0fd47,
+ 0x0fd48, 0x0fd49, 0x0fd4a, 0x0fd4b, 0x0fd4c, 0x0fd4d, 0x0fd4e, 0x0fd4f,
+ 0x0fd50, 0x0fd51, 0x0fd51, 0x0fd53, 0x0fd54, 0x0fd55, 0x0fd56, 0x0fd57,
+ 0x0fd58, 0x0fd58, 0x0fd5a, 0x0fd5b, 0x0fd5c, 0x0fd5d, 0x0fd5e, 0x0fd5f,
+ 0x0fd5f, 0x0fd61, 0x0fd62, 0x0fd62, 0x0fd64, 0x0fd64, 0x0fd66, 0x0fd67,
+ 0x0fd67, 0x0fd69, 0x0fd6a, 0x0fd6a, 0x0fd6c, 0x0fd6c, 0x0fd6e, 0x0fd6f,
+ 0x0fd6f, 0x0fd71, 0x0fd71, 0x0fd73, 0x0fd74, 0x0fd75, 0x0fd76, 0x0fd76,
+ 0x0fd78, 0x0fd79, 0x0fd7a, 0x0fd7b, 0x0fd7c, 0x0fd7c, 0x0fd7e, 0x0fd7f,
+ 0x0fd80, 0x0fd81, 0x0fd82, 0x0fd83, 0x0fd83, 0x0fd85, 0x0fd85, 0x0fd87,
+ 0x0fd87, 0x0fd89, 0x0fd8a, 0x0fd8b, 0x0fd8c, 0x0fd8d, 0x0fd8e, 0x0fd8f,
+ 0x0fd90, 0x0fd91, 0x0fd92, 0x0fd93, 0x0fd94, 0x0fd95, 0x0fd96, 0x0fd97,
+ 0x0fd97, 0x0fd99, 0x0fd9a, 0x0fd9b, 0x0fd9c, 0x0fd9c, 0x0fd9e, 0x0fd9f,
+ 0x0fda0, 0x0fda1, 0x0fda2, 0x0fda3, 0x0fda4, 0x0fda5, 0x0fda6, 0x0fda7,
+ 0x0fda8, 0x0fda9, 0x0fdaa, 0x0fdab, 0x0fdac, 0x0fdad, 0x0fdae, 0x0fdaf,
+ 0x0fdb0, 0x0fdb1, 0x0fdb2, 0x0fdb3, 0x0fd7e, 0x0fd80, 0x0fdb6, 0x0fdb7,
+ 0x0fdb8, 0x0fdb9, 0x0fdba, 0x0fdbb, 0x0fdba, 0x0fdb8, 0x0fdbe, 0x0fdbf,
+ 0x0fdc0, 0x0fdc1, 0x0fdc2, 0x0fdbb, 0x0fd75, 0x0fd66, 0x0fdc6, 0x0fdc7,
+ 0x0fdc8, 0x0fdc9, 0x0fdca, 0x0fdcb, 0x0fdcc, 0x0fdcd, 0x0fdce, 0x0fdcf,
+ 0x0fdd0, 0x0fdd1, 0x0fdd2, 0x0fdd3, 0x0fdd4, 0x0fdd5, 0x0fdd6, 0x0fdd7,
+ 0x0fdd8, 0x0fdd9, 0x0fdda, 0x0fddb, 0x0fddc, 0x0fddd, 0x0fdde, 0x0fddf,
+ 0x0fde0, 0x0fde1, 0x0fde2, 0x0fde3, 0x0fde4, 0x0fde5, 0x0fde6, 0x0fde7,
+ 0x0fde8, 0x0fde9, 0x0fdea, 0x0fdeb, 0x0fdec, 0x0fded, 0x0fdee, 0x0fdef,
+ 0x0fdf0, 0x0fdf1, 0x0fdf2, 0x0fdf3, 0x0fdf4, 0x0fdf5, 0x0fdf6, 0x0fdf7,
+ 0x0fdf8, 0x0fdf9, 0x0fdfa, 0x0fdfb, 0x0fdfc, 0x0fdfd, 0x0fdfe, 0x0fdff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fe[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x0fe10, 0x0fe11, 0x0fe12, 0x0fe13, 0x0fe14, 0x0fe15, 0x0fe16, 0x0fe17,
+ 0x0fe18, 0x0fe19, 0x0fe1a, 0x0fe1b, 0x0fe1c, 0x0fe1d, 0x0fe1e, 0x0fe1f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe24, 0x0fe25, 0x0fe26, 0x0fe27,
+ 0x0fe28, 0x0fe29, 0x0fe2a, 0x0fe2b, 0x0fe2c, 0x0fe2d, 0x0fe2e, 0x0fe2f,
+ 0x02025, 0x02014, 0x02013, 0x0005f, 0x0005f, 0x00028, 0x00029, 0x0007b,
+ 0x0007d, 0x03014, 0x03015, 0x03010, 0x03011, 0x0300a, 0x0300b, 0x02329,
+ 0x0232a, 0x0300c, 0x0300d, 0x0300e, 0x0300f, 0x0fe45, 0x0fe46, 0x0005b,
+ 0x0005d, 0x0203e, 0x0203e, 0x0203e, 0x0203e, 0x0005f, 0x0005f, 0x0005f,
+ 0x0002c, 0x03001, 0x0002e, 0x0fe53, 0x0003b, 0x0003a, 0x0003f, 0x00021,
+ 0x02014, 0x00028, 0x00029, 0x0007b, 0x0007d, 0x03014, 0x03015, 0x00023,
+ 0x00026, 0x0002a, 0x0002b, 0x0002d, 0x0003c, 0x0003e, 0x0003d, 0x0fe67,
+ 0x0005c, 0x00024, 0x00025, 0x00040, 0x0fe6c, 0x0fe6d, 0x0fe6e, 0x0fe6f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe75, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00621, 0x00622, 0x00622, 0x00623, 0x00623, 0x00624, 0x00624, 0x00625,
+ 0x00625, 0x00626, 0x00626, 0x00626, 0x00626, 0x00627, 0x00627, 0x00628,
+ 0x00628, 0x00628, 0x00628, 0x00629, 0x00629, 0x0062a, 0x0062a, 0x0062a,
+ 0x0062a, 0x0062b, 0x0062b, 0x0062b, 0x0062b, 0x0062c, 0x0062c, 0x0062c,
+ 0x0062c, 0x0062d, 0x0062d, 0x0062d, 0x0062d, 0x0062e, 0x0062e, 0x0062e,
+ 0x0062e, 0x0062f, 0x0062f, 0x00630, 0x00630, 0x00631, 0x00631, 0x00632,
+ 0x00632, 0x00633, 0x00633, 0x00633, 0x00633, 0x00634, 0x00634, 0x00634,
+ 0x00634, 0x00635, 0x00635, 0x00635, 0x00635, 0x00636, 0x00636, 0x00636,
+ 0x00636, 0x00637, 0x00637, 0x00637, 0x00637, 0x00638, 0x00638, 0x00638,
+ 0x00638, 0x00639, 0x00639, 0x00639, 0x00639, 0x0063a, 0x0063a, 0x0063a,
+ 0x0063a, 0x00641, 0x00641, 0x00641, 0x00641, 0x00642, 0x00642, 0x00642,
+ 0x00642, 0x00643, 0x00643, 0x00643, 0x00643, 0x00644, 0x00644, 0x00644,
+ 0x00644, 0x00645, 0x00645, 0x00645, 0x00645, 0x00646, 0x00646, 0x00646,
+ 0x00646, 0x00647, 0x00647, 0x00647, 0x00647, 0x00648, 0x00648, 0x00649,
+ 0x00649, 0x0064a, 0x0064a, 0x0064a, 0x0064a, 0x0fef5, 0x0fef5, 0x0fef7,
+ 0x0fef7, 0x0fef9, 0x0fef9, 0x0fefb, 0x0fefb, 0x0fefd, 0x0fefe, 0x0feff
+};
+
+static uint32_t unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_ff[] = {
+ 0x0ff00, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x02985,
+ 0x02986, 0x03002, 0x0300c, 0x0300d, 0x03001, 0x030fb, 0x03092, 0x03041,
+ 0x03043, 0x03045, 0x03047, 0x03049, 0x03083, 0x03085, 0x03087, 0x03063,
+ 0x030fc, 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d,
+ 0x0304f, 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d,
+ 0x0305f, 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c,
+ 0x0306d, 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e,
+ 0x0307f, 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089,
+ 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03093, 0x00000, 0x00000,
+ 0x01160, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0ffbf,
+ 0x0ffc0, 0x0ffc1, 0x01161, 0x01162, 0x01163, 0x01164, 0x01165, 0x01166,
+ 0x0ffc8, 0x0ffc9, 0x01167, 0x01168, 0x01169, 0x0116a, 0x0116b, 0x0116c,
+ 0x0ffd0, 0x0ffd1, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171, 0x01172,
+ 0x0ffd8, 0x0ffd9, 0x01173, 0x01174, 0x01175, 0x0ffdd, 0x0ffde, 0x0ffdf,
+ 0x000a2, 0x000a3, 0x000ac, 0x000af, 0x000a6, 0x000a5, 0x020a9, 0x0ffe7,
+ 0x02502, 0x02190, 0x02191, 0x02192, 0x02193, 0x025a0, 0x025cb, 0x0ffef,
+ 0x0fff0, 0x0fff1, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff5, 0x0fff6, 0x0fff7,
+ 0x0fff8, 0x00000, 0x00000, 0x00000, 0x0fffc, 0x0fffd, 0x0fffe, 0x0ffff
+};
+
+static uint32_t *unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_table[256] = {
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_00, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_01,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_02, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_03,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_04, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_05,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_06, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_07,
+ NULL, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_09,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0a, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0b,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0c, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0d,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0e, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_0f,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_10, NULL,
+ NULL, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_13,
+ NULL, NULL,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_16, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_17,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_18, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_19,
+ NULL, NULL,
+ NULL, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1d,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1e, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_1f,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_20, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_21,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_22, NULL,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_24, NULL,
+ NULL, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_27,
+ NULL, NULL,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2a, NULL,
+ NULL, NULL,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2e, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_2f,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_30, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_31,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_32, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_33,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_f9,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fa, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fb,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fc, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fd,
+ unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_fe, unicode_ci_except_kana_ci_kana_with_voiced_sound_mark_page_ff
+};
+
+#endif
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_table.h b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_table.h
new file mode 100644
index 00000000..77b96d77
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/normalizers/mysql_unicode_ci_table.h
@@ -0,0 +1,1685 @@
+/*
+ Copyright(C) 2013-2015 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ mysql-5.6.23/strings/ctype-uca.c.
+ The following is the header of the file:
+
+ Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UCA (Unicode Collation Algorithm) support.
+ Written by Alexander Barkov <bar@mysql.com>
+*/
+
+#ifndef MYSQL_UCA_H
+#define MYSQL_UCA_H
+
+#include <stdint.h>
+
+static uint32_t unicode_ci_page_00[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00009, 0x0000a, 0x0000b, 0x0000c, 0x0000d, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00085, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00020, 0x000a1, 0x000a2, 0x000a3, 0x000a4, 0x000a5, 0x000a6, 0x000a7,
+ 0x000a8, 0x000a9, 0x00041, 0x000ab, 0x000ac, 0x000ad, 0x000ae, 0x000af,
+ 0x000b0, 0x000b1, 0x00032, 0x00033, 0x000b4, 0x0039c, 0x000b6, 0x000b7,
+ 0x000b8, 0x00031, 0x0004f, 0x000bb, 0x000bc, 0x000bd, 0x000be, 0x000bf,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x000d0, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000d7,
+ 0x000d8, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x000df,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x000c6, 0x00043,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x000d0, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x000f7,
+ 0x000d8, 0x00055, 0x00055, 0x00055, 0x00055, 0x00059, 0x000de, 0x00059
+};
+
+static uint32_t unicode_ci_page_01[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00043, 0x00043,
+ 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00043, 0x00044, 0x00044,
+ 0x00110, 0x00110, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00047, 0x00047, 0x00047, 0x00047,
+ 0x00047, 0x00047, 0x00047, 0x00047, 0x00048, 0x00048, 0x00126, 0x00126,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x00049, 0x00131, 0x00132, 0x00132, 0x0004a, 0x0004a, 0x0004b, 0x0004b,
+ 0x00138, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0013f,
+ 0x0013f, 0x00141, 0x00141, 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x00149, 0x0014a, 0x0014a, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00152, 0x00152, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00052, 0x00052, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00166, 0x00166,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00057, 0x00057, 0x00059, 0x00059,
+ 0x00059, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00053,
+ 0x00180, 0x00181, 0x00182, 0x00182, 0x00184, 0x00184, 0x00186, 0x00187,
+ 0x00187, 0x00189, 0x0018a, 0x0018b, 0x0018b, 0x0018d, 0x0018e, 0x0018f,
+ 0x00190, 0x00191, 0x00191, 0x00193, 0x00194, 0x00195, 0x00196, 0x00197,
+ 0x00198, 0x00198, 0x0019a, 0x0019b, 0x0019c, 0x0019d, 0x0019e, 0x0019f,
+ 0x0004f, 0x0004f, 0x001a2, 0x001a2, 0x001a4, 0x001a4, 0x001a6, 0x001a7,
+ 0x001a7, 0x001a9, 0x001aa, 0x001ab, 0x001ac, 0x001ac, 0x001ae, 0x00055,
+ 0x00055, 0x001b1, 0x001b2, 0x001b3, 0x001b3, 0x001b5, 0x001b5, 0x001b7,
+ 0x001b8, 0x001b8, 0x001ba, 0x001bb, 0x001bc, 0x001bc, 0x001be, 0x001bf,
+ 0x001c0, 0x001c1, 0x001c2, 0x001c3, 0x001c4, 0x001c4, 0x001c4, 0x001c7,
+ 0x001c7, 0x001c7, 0x001ca, 0x001ca, 0x001ca, 0x00041, 0x00041, 0x00049,
+ 0x00049, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x0018e, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x000c6, 0x000c6, 0x001e4, 0x001e4, 0x00047, 0x00047,
+ 0x0004b, 0x0004b, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x001b7, 0x001b7,
+ 0x0004a, 0x001c4, 0x001c4, 0x001c4, 0x00047, 0x00047, 0x00195, 0x001bf,
+ 0x0004e, 0x0004e, 0x00041, 0x00041, 0x000c6, 0x000c6, 0x000d8, 0x001ff
+};
+
+static uint32_t unicode_ci_page_02[] = {
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x0021c, 0x0021c, 0x00048, 0x00048,
+ 0x0019e, 0x00221, 0x00222, 0x00222, 0x00224, 0x00224, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x00059, 0x00059, 0x00234, 0x00235, 0x00236, 0x00237,
+ 0x00238, 0x00239, 0x0023a, 0x0023b, 0x0023c, 0x0023d, 0x0023e, 0x0023f,
+ 0x00240, 0x00241, 0x00242, 0x00243, 0x00244, 0x00245, 0x00246, 0x00247,
+ 0x00248, 0x00249, 0x0024a, 0x0024b, 0x0024c, 0x0024d, 0x0024e, 0x0024f,
+ 0x00250, 0x00251, 0x00252, 0x00181, 0x00186, 0x00255, 0x00189, 0x0018a,
+ 0x00258, 0x0018f, 0x0025a, 0x00190, 0x0025c, 0x0025d, 0x0025e, 0x0025f,
+ 0x00193, 0x00261, 0x00262, 0x00194, 0x00264, 0x00265, 0x00266, 0x00267,
+ 0x00197, 0x00196, 0x0026a, 0x0026b, 0x0026c, 0x0026d, 0x0026e, 0x0019c,
+ 0x00270, 0x00271, 0x0019d, 0x00273, 0x00274, 0x0019f, 0x00276, 0x00277,
+ 0x00278, 0x00279, 0x0027a, 0x0027b, 0x0027c, 0x0027d, 0x0027e, 0x0027f,
+ 0x001a6, 0x00281, 0x00282, 0x001a9, 0x00284, 0x00285, 0x00286, 0x00287,
+ 0x001ae, 0x00289, 0x001b1, 0x001b2, 0x0028c, 0x0028d, 0x0028e, 0x0028f,
+ 0x00290, 0x00291, 0x001b7, 0x00293, 0x00294, 0x00295, 0x00296, 0x00297,
+ 0x00298, 0x00299, 0x0029a, 0x0029b, 0x0029c, 0x0029d, 0x0029e, 0x0029f,
+ 0x002a0, 0x002a1, 0x002a2, 0x001c4, 0x002a4, 0x002a5, 0x001be, 0x002a7,
+ 0x002a8, 0x002a9, 0x002aa, 0x002ab, 0x002ac, 0x002ad, 0x002ae, 0x002af,
+ 0x00048, 0x00266, 0x0004a, 0x00052, 0x00279, 0x0027b, 0x00281, 0x00057,
+ 0x00059, 0x002b9, 0x002ba, 0x002bb, 0x002bc, 0x002bd, 0x002be, 0x002bf,
+ 0x002c0, 0x002c1, 0x002c2, 0x002c3, 0x002c4, 0x002c5, 0x002c6, 0x002c7,
+ 0x002c8, 0x002c9, 0x002ca, 0x002cb, 0x002cc, 0x002cd, 0x002ce, 0x002cf,
+ 0x002d0, 0x002d1, 0x002d2, 0x002d3, 0x002d4, 0x002d5, 0x002d6, 0x002d7,
+ 0x002d8, 0x002d9, 0x002da, 0x002db, 0x002dc, 0x002dd, 0x002de, 0x002df,
+ 0x00194, 0x0004c, 0x00053, 0x00058, 0x00295, 0x002e5, 0x002e6, 0x002e7,
+ 0x002e8, 0x002e9, 0x002ea, 0x002eb, 0x002ec, 0x002ed, 0x002ee, 0x002ef,
+ 0x002f0, 0x002f1, 0x002f2, 0x002f3, 0x002f4, 0x002f5, 0x002f6, 0x002f7,
+ 0x002f8, 0x002f9, 0x002fa, 0x002fb, 0x002fc, 0x002fd, 0x002fe, 0x002ff
+};
+
+static uint32_t unicode_ci_page_03[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00358, 0x00359, 0x0035a, 0x0035b, 0x0035c, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00041, 0x00045, 0x00049, 0x0004f, 0x00055,
+ 0x00043, 0x00044, 0x00048, 0x0004d, 0x00052, 0x00054, 0x00056, 0x00058,
+ 0x00370, 0x00371, 0x00372, 0x00373, 0x002b9, 0x00375, 0x00376, 0x00377,
+ 0x00378, 0x00379, 0x00399, 0x0037b, 0x0037c, 0x0037d, 0x0003b, 0x0037f,
+ 0x00380, 0x00381, 0x00382, 0x00383, 0x000b4, 0x000a8, 0x00391, 0x000b7,
+ 0x00395, 0x00397, 0x00399, 0x0038b, 0x0039f, 0x0038d, 0x003a5, 0x003a9,
+ 0x00399, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a2, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x00391, 0x00395, 0x00397, 0x00399,
+ 0x003a5, 0x00391, 0x00392, 0x00393, 0x00394, 0x00395, 0x00396, 0x00397,
+ 0x00398, 0x00399, 0x0039a, 0x0039b, 0x0039c, 0x0039d, 0x0039e, 0x0039f,
+ 0x003a0, 0x003a1, 0x003a3, 0x003a3, 0x003a4, 0x003a5, 0x003a6, 0x003a7,
+ 0x003a8, 0x003a9, 0x00399, 0x003a5, 0x0039f, 0x003a5, 0x003a9, 0x003cf,
+ 0x00392, 0x00398, 0x003a5, 0x003a5, 0x003a5, 0x003a6, 0x003a0, 0x003d7,
+ 0x003d8, 0x003d8, 0x003da, 0x003da, 0x003dc, 0x003dc, 0x003de, 0x003de,
+ 0x003e0, 0x003e0, 0x003e2, 0x003e2, 0x003e4, 0x003e4, 0x003e6, 0x003e6,
+ 0x003e8, 0x003e8, 0x003ea, 0x003ea, 0x003ec, 0x003ec, 0x003ee, 0x003ee,
+ 0x0039a, 0x003a1, 0x003a3, 0x003f3, 0x00398, 0x00395, 0x003f6, 0x003f7,
+ 0x003f7, 0x003a3, 0x003fa, 0x003fa, 0x003fc, 0x003fd, 0x003fe, 0x003ff
+};
+
+static uint32_t unicode_ci_page_04[] = {
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00410, 0x00411, 0x00412, 0x00413, 0x00414, 0x00400, 0x00416, 0x00417,
+ 0x0040d, 0x00419, 0x0041a, 0x0041b, 0x0041c, 0x0041d, 0x0041e, 0x0041f,
+ 0x00420, 0x00421, 0x00422, 0x00423, 0x00424, 0x00425, 0x00426, 0x00427,
+ 0x00428, 0x00429, 0x0042a, 0x0042b, 0x0042c, 0x0042d, 0x0042e, 0x0042f,
+ 0x00400, 0x00400, 0x00402, 0x00403, 0x00404, 0x00405, 0x00406, 0x00407,
+ 0x00408, 0x00409, 0x0040a, 0x0040b, 0x0040c, 0x0040d, 0x0040e, 0x0040f,
+ 0x00460, 0x00460, 0x00462, 0x00462, 0x00464, 0x00464, 0x00466, 0x00466,
+ 0x00468, 0x00468, 0x0046a, 0x0046a, 0x0046c, 0x0046c, 0x0046e, 0x0046e,
+ 0x00470, 0x00470, 0x00472, 0x00472, 0x00474, 0x00474, 0x00476, 0x00476,
+ 0x00478, 0x00478, 0x0047a, 0x0047a, 0x0047c, 0x0047c, 0x0047e, 0x0047e,
+ 0x00480, 0x00480, 0x00482, 0x00000, 0x00000, 0x00000, 0x00000, 0x00487,
+ 0x00000, 0x00000, 0x0048a, 0x0048a, 0x0048c, 0x0048c, 0x0048e, 0x0048e,
+ 0x00413, 0x00413, 0x00492, 0x00492, 0x00494, 0x00494, 0x00496, 0x00496,
+ 0x00498, 0x00498, 0x0049a, 0x0049a, 0x0049c, 0x0049c, 0x0049e, 0x0049e,
+ 0x004a0, 0x004a0, 0x004a2, 0x004a2, 0x004a4, 0x004a4, 0x004a6, 0x004a6,
+ 0x004a8, 0x004a8, 0x004aa, 0x004aa, 0x004ac, 0x004ac, 0x004ae, 0x004ae,
+ 0x004b0, 0x004b0, 0x004b2, 0x004b2, 0x004b4, 0x004b4, 0x004b6, 0x004b6,
+ 0x004b8, 0x004b8, 0x004ba, 0x004ba, 0x004bc, 0x004bc, 0x004be, 0x004be,
+ 0x004c0, 0x00416, 0x00416, 0x004c3, 0x004c3, 0x004c5, 0x004c5, 0x004c7,
+ 0x004c7, 0x004c9, 0x004c9, 0x004cb, 0x004cb, 0x004cd, 0x004cd, 0x004cf,
+ 0x004d0, 0x004d0, 0x004d2, 0x004d2, 0x004d4, 0x004d4, 0x004d6, 0x004d6,
+ 0x004d8, 0x004d8, 0x004da, 0x004da, 0x004dc, 0x004dc, 0x004de, 0x004de,
+ 0x004e0, 0x004e0, 0x0040d, 0x0040d, 0x004e4, 0x004e4, 0x004e6, 0x004e6,
+ 0x004e8, 0x004e8, 0x004ea, 0x004ea, 0x004ec, 0x004ec, 0x00423, 0x00423,
+ 0x004f0, 0x004f0, 0x004f2, 0x004f2, 0x004f4, 0x004f4, 0x004f6, 0x004f7,
+ 0x004f8, 0x004f8, 0x004fa, 0x004fb, 0x004fc, 0x004fd, 0x004fe, 0x004ff
+};
+
+static uint32_t unicode_ci_page_05[] = {
+ 0x00500, 0x00500, 0x00502, 0x00502, 0x00504, 0x00504, 0x00506, 0x00506,
+ 0x00508, 0x00508, 0x0050a, 0x0050a, 0x0050c, 0x0050c, 0x0050e, 0x0050e,
+ 0x00510, 0x00511, 0x00512, 0x00513, 0x00514, 0x00515, 0x00516, 0x00517,
+ 0x00518, 0x00519, 0x0051a, 0x0051b, 0x0051c, 0x0051d, 0x0051e, 0x0051f,
+ 0x00520, 0x00521, 0x00522, 0x00523, 0x00524, 0x00525, 0x00526, 0x00527,
+ 0x00528, 0x00529, 0x0052a, 0x0052b, 0x0052c, 0x0052d, 0x0052e, 0x0052f,
+ 0x00530, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00557,
+ 0x00558, 0x00559, 0x0055a, 0x0055b, 0x0055c, 0x0055d, 0x0055e, 0x0055f,
+ 0x00560, 0x00531, 0x00532, 0x00533, 0x00534, 0x00535, 0x00536, 0x00537,
+ 0x00538, 0x00539, 0x0053a, 0x0053b, 0x0053c, 0x0053d, 0x0053e, 0x0053f,
+ 0x00540, 0x00541, 0x00542, 0x00543, 0x00544, 0x00545, 0x00546, 0x00547,
+ 0x00548, 0x00549, 0x0054a, 0x0054b, 0x0054c, 0x0054d, 0x0054e, 0x0054f,
+ 0x00550, 0x00551, 0x00552, 0x00553, 0x00554, 0x00555, 0x00556, 0x00587,
+ 0x00588, 0x00589, 0x0058a, 0x0058b, 0x0058c, 0x0058d, 0x0058e, 0x0058f,
+ 0x00590, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x005a2, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x005ba, 0x00000, 0x00000, 0x00000, 0x005be, 0x00000,
+ 0x005c0, 0x00000, 0x00000, 0x005c3, 0x00000, 0x005c5, 0x005c6, 0x005c7,
+ 0x005c8, 0x005c9, 0x005ca, 0x005cb, 0x005cc, 0x005cd, 0x005ce, 0x005cf,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x005d7,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x005dd, 0x005dd, 0x005df,
+ 0x005df, 0x005e1, 0x005e2, 0x005e3, 0x005e3, 0x005e5, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005eb, 0x005ec, 0x005ed, 0x005ee, 0x005ef,
+ 0x005f0, 0x005f1, 0x005f2, 0x005f3, 0x005f4, 0x005f5, 0x005f6, 0x005f7,
+ 0x005f8, 0x005f9, 0x005fa, 0x005fb, 0x005fc, 0x005fd, 0x005fe, 0x005ff
+};
+
+static uint32_t unicode_ci_page_06[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00604, 0x00605, 0x00606, 0x00607,
+ 0x00608, 0x00609, 0x0060a, 0x0060b, 0x0060c, 0x0060d, 0x0060e, 0x0060f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00616, 0x00617,
+ 0x00618, 0x00619, 0x0061a, 0x0061b, 0x0061c, 0x0061d, 0x0061e, 0x0061f,
+ 0x00620, 0x00621, 0x00622, 0x00623, 0x00624, 0x00625, 0x00626, 0x00627,
+ 0x00628, 0x00629, 0x0062a, 0x0062b, 0x0062c, 0x0062d, 0x0062e, 0x0062f,
+ 0x00630, 0x00631, 0x00632, 0x00633, 0x00634, 0x00635, 0x00636, 0x00637,
+ 0x00638, 0x00639, 0x0063a, 0x0063b, 0x0063c, 0x0063d, 0x0063e, 0x0063f,
+ 0x00640, 0x00641, 0x00642, 0x00643, 0x00644, 0x00645, 0x00646, 0x00647,
+ 0x00648, 0x00649, 0x0064a, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00659, 0x0065a, 0x0065b, 0x0065c, 0x0065d, 0x0065e, 0x0065f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0066a, 0x0066b, 0x0066c, 0x0066d, 0x0066e, 0x0066f,
+ 0x00000, 0x00671, 0x00672, 0x00673, 0x00621, 0x00675, 0x00676, 0x00677,
+ 0x00678, 0x00679, 0x0067a, 0x0067b, 0x0067c, 0x0067d, 0x0067e, 0x0067f,
+ 0x00680, 0x00681, 0x00682, 0x00683, 0x00684, 0x00685, 0x00686, 0x00687,
+ 0x00688, 0x00689, 0x0068a, 0x0068b, 0x0068c, 0x0068d, 0x0068e, 0x0068f,
+ 0x00690, 0x00691, 0x00692, 0x00693, 0x00694, 0x00695, 0x00696, 0x00697,
+ 0x00698, 0x00699, 0x0069a, 0x0069b, 0x0069c, 0x0069d, 0x0069e, 0x0069f,
+ 0x006a0, 0x006a1, 0x006a2, 0x006a3, 0x006a4, 0x006a5, 0x006a6, 0x006a7,
+ 0x006a8, 0x006a9, 0x006aa, 0x006ab, 0x006ac, 0x006ad, 0x006ae, 0x006af,
+ 0x006b0, 0x006b1, 0x006b2, 0x006b3, 0x006b4, 0x006b5, 0x006b6, 0x006b7,
+ 0x006b8, 0x006b9, 0x006ba, 0x006bb, 0x006bc, 0x006bd, 0x006be, 0x006bf,
+ 0x006c0, 0x006c1, 0x006c1, 0x006c3, 0x006c4, 0x006c5, 0x006c6, 0x006c7,
+ 0x006c8, 0x006c9, 0x006ca, 0x006cb, 0x006cc, 0x006cd, 0x006ce, 0x006cf,
+ 0x006d0, 0x006d1, 0x006d2, 0x006d2, 0x006d4, 0x006c0, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00648, 0x0064a, 0x00000,
+ 0x00000, 0x006e9, 0x00000, 0x00000, 0x00000, 0x00000, 0x006ee, 0x006ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x006fa, 0x006fb, 0x006fc, 0x00621, 0x00645, 0x006ff
+};
+
+static uint32_t unicode_ci_page_07[] = {
+ 0x00700, 0x00701, 0x00702, 0x00703, 0x00704, 0x00705, 0x00706, 0x00707,
+ 0x00708, 0x00709, 0x0070a, 0x0070b, 0x0070c, 0x0070d, 0x0070e, 0x00000,
+ 0x00710, 0x00000, 0x00712, 0x00713, 0x00713, 0x00715, 0x00716, 0x00717,
+ 0x00718, 0x00719, 0x0071a, 0x0071b, 0x0071b, 0x0071d, 0x0071e, 0x0071f,
+ 0x00720, 0x00721, 0x00722, 0x00723, 0x00723, 0x00725, 0x00726, 0x00726,
+ 0x00728, 0x00729, 0x0072a, 0x0072b, 0x0072c, 0x00712, 0x00713, 0x00715,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x0074b, 0x0074c, 0x0074d, 0x0074e, 0x0074f,
+ 0x00750, 0x00751, 0x00752, 0x00753, 0x00754, 0x00755, 0x00756, 0x00757,
+ 0x00758, 0x00759, 0x0075a, 0x0075b, 0x0075c, 0x0075d, 0x0075e, 0x0075f,
+ 0x00760, 0x00761, 0x00762, 0x00763, 0x00764, 0x00765, 0x00766, 0x00767,
+ 0x00768, 0x00769, 0x0076a, 0x0076b, 0x0076c, 0x0076d, 0x0076e, 0x0076f,
+ 0x00770, 0x00771, 0x00772, 0x00773, 0x00774, 0x00775, 0x00776, 0x00777,
+ 0x00778, 0x00779, 0x0077a, 0x0077b, 0x0077c, 0x0077d, 0x0077e, 0x0077f,
+ 0x00780, 0x00781, 0x00782, 0x00783, 0x00784, 0x00785, 0x00786, 0x00787,
+ 0x00788, 0x00789, 0x0078a, 0x0078b, 0x0078c, 0x0078d, 0x0078e, 0x0078f,
+ 0x00790, 0x00791, 0x00792, 0x00793, 0x00794, 0x00795, 0x00796, 0x00797,
+ 0x00798, 0x00799, 0x0079a, 0x0079b, 0x0079c, 0x0079d, 0x0079e, 0x0079f,
+ 0x007a0, 0x007a1, 0x007a2, 0x007a3, 0x007a4, 0x007a5, 0x007a6, 0x007a7,
+ 0x007a8, 0x007a9, 0x007aa, 0x007ab, 0x007ac, 0x007ad, 0x007ae, 0x007af,
+ 0x007b0, 0x007b1, 0x007b2, 0x007b3, 0x007b4, 0x007b5, 0x007b6, 0x007b7,
+ 0x007b8, 0x007b9, 0x007ba, 0x007bb, 0x007bc, 0x007bd, 0x007be, 0x007bf,
+ 0x007c0, 0x007c1, 0x007c2, 0x007c3, 0x007c4, 0x007c5, 0x007c6, 0x007c7,
+ 0x007c8, 0x007c9, 0x007ca, 0x007cb, 0x007cc, 0x007cd, 0x007ce, 0x007cf,
+ 0x007d0, 0x007d1, 0x007d2, 0x007d3, 0x007d4, 0x007d5, 0x007d6, 0x007d7,
+ 0x007d8, 0x007d9, 0x007da, 0x007db, 0x007dc, 0x007dd, 0x007de, 0x007df,
+ 0x007e0, 0x007e1, 0x007e2, 0x007e3, 0x007e4, 0x007e5, 0x007e6, 0x007e7,
+ 0x007e8, 0x007e9, 0x007ea, 0x007eb, 0x007ec, 0x007ed, 0x007ee, 0x007ef,
+ 0x007f0, 0x007f1, 0x007f2, 0x007f3, 0x007f4, 0x007f5, 0x007f6, 0x007f7,
+ 0x007f8, 0x007f9, 0x007fa, 0x007fb, 0x007fc, 0x007fd, 0x007fe, 0x007ff
+};
+
+static uint32_t unicode_ci_page_09[] = {
+ 0x00900, 0x00000, 0x00000, 0x00000, 0x00904, 0x00905, 0x00906, 0x00907,
+ 0x00908, 0x00909, 0x0090a, 0x0090b, 0x0090c, 0x0090d, 0x0090e, 0x0090f,
+ 0x00910, 0x00911, 0x00912, 0x00913, 0x00914, 0x00915, 0x00916, 0x00917,
+ 0x00918, 0x00919, 0x0091a, 0x0091b, 0x0091c, 0x0091d, 0x0091e, 0x0091f,
+ 0x00920, 0x00921, 0x00922, 0x00923, 0x00924, 0x00925, 0x00926, 0x00927,
+ 0x00928, 0x00928, 0x0092a, 0x0092b, 0x0092c, 0x0092d, 0x0092e, 0x0092f,
+ 0x00930, 0x00930, 0x00932, 0x00933, 0x00933, 0x00935, 0x00936, 0x00937,
+ 0x00938, 0x00939, 0x0093a, 0x0093b, 0x00000, 0x0093d, 0x0093e, 0x0093f,
+ 0x00940, 0x00941, 0x00942, 0x00943, 0x00944, 0x00945, 0x00946, 0x00947,
+ 0x00948, 0x00949, 0x0094a, 0x0094b, 0x0094c, 0x0094d, 0x0094e, 0x0094f,
+ 0x00950, 0x00000, 0x00000, 0x00000, 0x00000, 0x00955, 0x00956, 0x00957,
+ 0x00915, 0x00916, 0x00917, 0x0091c, 0x00921, 0x00922, 0x0092b, 0x0092f,
+ 0x00960, 0x00961, 0x00962, 0x00963, 0x00964, 0x00965, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00970, 0x00971, 0x00972, 0x00973, 0x00974, 0x00975, 0x00976, 0x00977,
+ 0x00978, 0x00979, 0x0097a, 0x0097b, 0x0097c, 0x0097d, 0x0097e, 0x0097f,
+ 0x00980, 0x00000, 0x00000, 0x00000, 0x00984, 0x00985, 0x00986, 0x00987,
+ 0x00988, 0x00989, 0x0098a, 0x0098b, 0x0098c, 0x0098d, 0x0098e, 0x0098f,
+ 0x00990, 0x00991, 0x00992, 0x00993, 0x00994, 0x00995, 0x00996, 0x00997,
+ 0x00998, 0x00999, 0x0099a, 0x0099b, 0x0099c, 0x0099d, 0x0099e, 0x0099f,
+ 0x009a0, 0x009a1, 0x009a2, 0x009a3, 0x009a4, 0x009a5, 0x009a6, 0x009a7,
+ 0x009a8, 0x009a9, 0x009aa, 0x009ab, 0x009ac, 0x009ad, 0x009ae, 0x009af,
+ 0x009b0, 0x009b1, 0x009b2, 0x009b3, 0x009b4, 0x009b5, 0x009b6, 0x009b7,
+ 0x009b8, 0x009b9, 0x009ba, 0x009bb, 0x00000, 0x009bd, 0x009be, 0x009bf,
+ 0x009c0, 0x009c1, 0x009c2, 0x009c3, 0x009c4, 0x009c5, 0x009c6, 0x009c7,
+ 0x009c8, 0x009c9, 0x009ca, 0x009cb, 0x009cc, 0x009cd, 0x009ce, 0x009cf,
+ 0x009d0, 0x009d1, 0x009d2, 0x009d3, 0x009d4, 0x009d5, 0x009d6, 0x009d7,
+ 0x009d8, 0x009d9, 0x009da, 0x009db, 0x009a1, 0x009a2, 0x009de, 0x009af,
+ 0x009e0, 0x009e1, 0x009e2, 0x009e3, 0x009e4, 0x009e5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x009f0, 0x009f1, 0x009f2, 0x009f3, 0x00031, 0x00032, 0x00033, 0x00034,
+ 0x009f8, 0x009f9, 0x009fa, 0x009fb, 0x009fc, 0x009fd, 0x009fe, 0x009ff
+};
+
+static uint32_t unicode_ci_page_0a[] = {
+ 0x00a00, 0x00000, 0x00000, 0x00000, 0x00a04, 0x00a05, 0x00a06, 0x00a07,
+ 0x00a08, 0x00a09, 0x00a0a, 0x00a0b, 0x00a0c, 0x00a0d, 0x00a0e, 0x00a0f,
+ 0x00a10, 0x00a11, 0x00a12, 0x00a13, 0x00a14, 0x00a15, 0x00a16, 0x00a17,
+ 0x00a18, 0x00a19, 0x00a1a, 0x00a1b, 0x00a1c, 0x00a1d, 0x00a1e, 0x00a1f,
+ 0x00a20, 0x00a21, 0x00a22, 0x00a23, 0x00a24, 0x00a25, 0x00a26, 0x00a27,
+ 0x00a28, 0x00a29, 0x00a2a, 0x00a2b, 0x00a2c, 0x00a2d, 0x00a2e, 0x00a2f,
+ 0x00a30, 0x00a31, 0x00a32, 0x00a32, 0x00a34, 0x00a35, 0x00a36, 0x00a37,
+ 0x00a36, 0x00a39, 0x00a3a, 0x00a3b, 0x00000, 0x00a3d, 0x00a3e, 0x00a3f,
+ 0x00a40, 0x00a41, 0x00a42, 0x00a43, 0x00a44, 0x00a45, 0x00a46, 0x00a47,
+ 0x00a48, 0x00a49, 0x00a4a, 0x00a4b, 0x00a4c, 0x00a4d, 0x00a4e, 0x00a4f,
+ 0x00a50, 0x00a51, 0x00a52, 0x00a53, 0x00a54, 0x00a55, 0x00a56, 0x00a57,
+ 0x00a58, 0x00a16, 0x00a17, 0x00a1c, 0x00a5c, 0x00a5d, 0x00a2b, 0x00a5f,
+ 0x00a60, 0x00a61, 0x00a62, 0x00a63, 0x00a64, 0x00a65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00000, 0x00000, 0x00a72, 0x00a73, 0x00a74, 0x00a75, 0x00a76, 0x00a77,
+ 0x00a78, 0x00a79, 0x00a7a, 0x00a7b, 0x00a7c, 0x00a7d, 0x00a7e, 0x00a7f,
+ 0x00a80, 0x00000, 0x00000, 0x00000, 0x00a84, 0x00a85, 0x00a86, 0x00a87,
+ 0x00a88, 0x00a89, 0x00a8a, 0x00a8b, 0x00a8c, 0x00a8d, 0x00a8e, 0x00a8f,
+ 0x00a90, 0x00a91, 0x00a92, 0x00a93, 0x00a94, 0x00a95, 0x00a96, 0x00a97,
+ 0x00a98, 0x00a99, 0x00a9a, 0x00a9b, 0x00a9c, 0x00a9d, 0x00a9e, 0x00a9f,
+ 0x00aa0, 0x00aa1, 0x00aa2, 0x00aa3, 0x00aa4, 0x00aa5, 0x00aa6, 0x00aa7,
+ 0x00aa8, 0x00aa9, 0x00aaa, 0x00aab, 0x00aac, 0x00aad, 0x00aae, 0x00aaf,
+ 0x00ab0, 0x00ab1, 0x00ab2, 0x00ab3, 0x00ab4, 0x00ab5, 0x00ab6, 0x00ab7,
+ 0x00ab8, 0x00ab9, 0x00aba, 0x00abb, 0x00000, 0x00abd, 0x00abe, 0x00abf,
+ 0x00ac0, 0x00ac1, 0x00ac2, 0x00ac3, 0x00ac4, 0x00ac5, 0x00ac6, 0x00ac7,
+ 0x00ac8, 0x00ac9, 0x00aca, 0x00acb, 0x00acc, 0x00acd, 0x00ace, 0x00acf,
+ 0x00ad0, 0x00ad1, 0x00ad2, 0x00ad3, 0x00ad4, 0x00ad5, 0x00ad6, 0x00ad7,
+ 0x00ad8, 0x00ad9, 0x00ada, 0x00adb, 0x00adc, 0x00add, 0x00ade, 0x00adf,
+ 0x00ae0, 0x00ae1, 0x00ae2, 0x00ae3, 0x00ae4, 0x00ae5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00af0, 0x00af1, 0x00af2, 0x00af3, 0x00af4, 0x00af5, 0x00af6, 0x00af7,
+ 0x00af8, 0x00af9, 0x00afa, 0x00afb, 0x00afc, 0x00afd, 0x00afe, 0x00aff
+};
+
+static uint32_t unicode_ci_page_0b[] = {
+ 0x00b00, 0x00000, 0x00000, 0x00000, 0x00b04, 0x00b05, 0x00b06, 0x00b07,
+ 0x00b08, 0x00b09, 0x00b0a, 0x00b0b, 0x00b0c, 0x00b0d, 0x00b0e, 0x00b0f,
+ 0x00b10, 0x00b11, 0x00b12, 0x00b13, 0x00b14, 0x00b15, 0x00b16, 0x00b17,
+ 0x00b18, 0x00b19, 0x00b1a, 0x00b1b, 0x00b1c, 0x00b1d, 0x00b1e, 0x00b1f,
+ 0x00b20, 0x00b21, 0x00b22, 0x00b23, 0x00b24, 0x00b25, 0x00b26, 0x00b27,
+ 0x00b28, 0x00b29, 0x00b2a, 0x00b2b, 0x00b2c, 0x00b2d, 0x00b2e, 0x00b2f,
+ 0x00b30, 0x00b31, 0x00b32, 0x00b33, 0x00b34, 0x00b35, 0x00b36, 0x00b37,
+ 0x00b38, 0x00b39, 0x00b3a, 0x00b3b, 0x00000, 0x00b3d, 0x00b3e, 0x00b3f,
+ 0x00b40, 0x00b41, 0x00b42, 0x00b43, 0x00b44, 0x00b45, 0x00b46, 0x00b47,
+ 0x00b48, 0x00b49, 0x00b4a, 0x00b4b, 0x00b4c, 0x00b4d, 0x00b4e, 0x00b4f,
+ 0x00b50, 0x00b51, 0x00b52, 0x00b53, 0x00b54, 0x00b55, 0x00b56, 0x00b57,
+ 0x00b58, 0x00b59, 0x00b5a, 0x00b5b, 0x00b21, 0x00b22, 0x00b5e, 0x00b5f,
+ 0x00b60, 0x00b61, 0x00b62, 0x00b63, 0x00b64, 0x00b65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00b70, 0x00b71, 0x00b72, 0x00b73, 0x00b74, 0x00b75, 0x00b76, 0x00b77,
+ 0x00b78, 0x00b79, 0x00b7a, 0x00b7b, 0x00b7c, 0x00b7d, 0x00b7e, 0x00b7f,
+ 0x00b80, 0x00b81, 0x00000, 0x00b83, 0x00b84, 0x00b85, 0x00b86, 0x00b87,
+ 0x00b88, 0x00b89, 0x00b8a, 0x00b8b, 0x00b8c, 0x00b8d, 0x00b8e, 0x00b8f,
+ 0x00b90, 0x00b91, 0x00b92, 0x00b93, 0x00b94, 0x00b95, 0x00b96, 0x00b97,
+ 0x00b98, 0x00b99, 0x00b9a, 0x00b9b, 0x00b9c, 0x00b9d, 0x00b9e, 0x00b9f,
+ 0x00ba0, 0x00ba1, 0x00ba2, 0x00ba3, 0x00ba4, 0x00ba5, 0x00ba6, 0x00ba7,
+ 0x00ba8, 0x00ba9, 0x00baa, 0x00bab, 0x00bac, 0x00bad, 0x00bae, 0x00baf,
+ 0x00bb0, 0x00bb1, 0x00bb2, 0x00bb3, 0x00bb4, 0x00bb5, 0x00bb6, 0x00bb7,
+ 0x00bb8, 0x00bb9, 0x00bba, 0x00bbb, 0x00bbc, 0x00bbd, 0x00bbe, 0x00bbf,
+ 0x00bc0, 0x00bc1, 0x00bc2, 0x00bc3, 0x00bc4, 0x00bc5, 0x00bc6, 0x00bc7,
+ 0x00bc8, 0x00bc9, 0x00bca, 0x00bcb, 0x00bcc, 0x00bcd, 0x00bce, 0x00bcf,
+ 0x00bd0, 0x00bd1, 0x00bd2, 0x00bd3, 0x00bd4, 0x00bd5, 0x00bd6, 0x00bd7,
+ 0x00bd8, 0x00bd9, 0x00bda, 0x00bdb, 0x00bdc, 0x00bdd, 0x00bde, 0x00bdf,
+ 0x00be0, 0x00be1, 0x00be2, 0x00be3, 0x00be4, 0x00be5, 0x00be6, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00bf0, 0x00bf1, 0x00bf2, 0x00bf3, 0x00bf4, 0x00bf5, 0x00bf6, 0x00bf7,
+ 0x00bf8, 0x00bf9, 0x00bfa, 0x00bfb, 0x00bfc, 0x00bfd, 0x00bfe, 0x00bff
+};
+
+static uint32_t unicode_ci_page_0c[] = {
+ 0x00c00, 0x00000, 0x00000, 0x00000, 0x00c04, 0x00c05, 0x00c06, 0x00c07,
+ 0x00c08, 0x00c09, 0x00c0a, 0x00c0b, 0x00c0c, 0x00c0d, 0x00c0e, 0x00c0f,
+ 0x00c10, 0x00c11, 0x00c12, 0x00c13, 0x00c14, 0x00c15, 0x00c16, 0x00c17,
+ 0x00c18, 0x00c19, 0x00c1a, 0x00c1b, 0x00c1c, 0x00c1d, 0x00c1e, 0x00c1f,
+ 0x00c20, 0x00c21, 0x00c22, 0x00c23, 0x00c24, 0x00c25, 0x00c26, 0x00c27,
+ 0x00c28, 0x00c29, 0x00c2a, 0x00c2b, 0x00c2c, 0x00c2d, 0x00c2e, 0x00c2f,
+ 0x00c30, 0x00c31, 0x00c32, 0x00c33, 0x00c34, 0x00c35, 0x00c36, 0x00c37,
+ 0x00c38, 0x00c39, 0x00c3a, 0x00c3b, 0x00c3c, 0x00c3d, 0x00c3e, 0x00c3f,
+ 0x00c40, 0x00c41, 0x00c42, 0x00c43, 0x00c44, 0x00c45, 0x00c46, 0x00c47,
+ 0x00c48, 0x00c49, 0x00c4a, 0x00c4b, 0x00c4c, 0x00c4d, 0x00c4e, 0x00c4f,
+ 0x00c50, 0x00c51, 0x00c52, 0x00c53, 0x00c54, 0x00c55, 0x00c56, 0x00c57,
+ 0x00c58, 0x00c59, 0x00c5a, 0x00c5b, 0x00c5c, 0x00c5d, 0x00c5e, 0x00c5f,
+ 0x00c60, 0x00c61, 0x00c62, 0x00c63, 0x00c64, 0x00c65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00c70, 0x00c71, 0x00c72, 0x00c73, 0x00c74, 0x00c75, 0x00c76, 0x00c77,
+ 0x00c78, 0x00c79, 0x00c7a, 0x00c7b, 0x00c7c, 0x00c7d, 0x00c7e, 0x00c7f,
+ 0x00c80, 0x00c81, 0x00000, 0x00000, 0x00c84, 0x00c85, 0x00c86, 0x00c87,
+ 0x00c88, 0x00c89, 0x00c8a, 0x00c8b, 0x00c8c, 0x00c8d, 0x00c8e, 0x00c8f,
+ 0x00c90, 0x00c91, 0x00c92, 0x00c93, 0x00c94, 0x00c95, 0x00c96, 0x00c97,
+ 0x00c98, 0x00c99, 0x00c9a, 0x00c9b, 0x00c9c, 0x00c9d, 0x00c9e, 0x00c9f,
+ 0x00ca0, 0x00ca1, 0x00ca2, 0x00ca3, 0x00ca4, 0x00ca5, 0x00ca6, 0x00ca7,
+ 0x00ca8, 0x00ca9, 0x00caa, 0x00cab, 0x00cac, 0x00cad, 0x00cae, 0x00caf,
+ 0x00cb0, 0x00cb1, 0x00cb2, 0x00cb3, 0x00cb4, 0x00cb5, 0x00cb6, 0x00cb7,
+ 0x00cb8, 0x00cb9, 0x00cba, 0x00cbb, 0x00000, 0x00cbd, 0x00cbe, 0x00cbf,
+ 0x00cc0, 0x00cc1, 0x00cc2, 0x00cc3, 0x00cc4, 0x00cc5, 0x00cc6, 0x00cc7,
+ 0x00cc8, 0x00cc9, 0x00cca, 0x00ccb, 0x00ccc, 0x00ccd, 0x00cce, 0x00ccf,
+ 0x00cd0, 0x00cd1, 0x00cd2, 0x00cd3, 0x00cd4, 0x00cd5, 0x00cd6, 0x00cd7,
+ 0x00cd8, 0x00cd9, 0x00cda, 0x00cdb, 0x00cdc, 0x00cdd, 0x00cde, 0x00cdf,
+ 0x00ce0, 0x00ce1, 0x00ce2, 0x00ce3, 0x00ce4, 0x00ce5, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00cf0, 0x00cf1, 0x00cf2, 0x00cf3, 0x00cf4, 0x00cf5, 0x00cf6, 0x00cf7,
+ 0x00cf8, 0x00cf9, 0x00cfa, 0x00cfb, 0x00cfc, 0x00cfd, 0x00cfe, 0x00cff
+};
+
+static uint32_t unicode_ci_page_0d[] = {
+ 0x00d00, 0x00d01, 0x00000, 0x00000, 0x00d04, 0x00d05, 0x00d06, 0x00d07,
+ 0x00d08, 0x00d09, 0x00d0a, 0x00d0b, 0x00d0c, 0x00d0d, 0x00d0e, 0x00d0f,
+ 0x00d10, 0x00d11, 0x00d12, 0x00d13, 0x00d14, 0x00d15, 0x00d16, 0x00d17,
+ 0x00d18, 0x00d19, 0x00d1a, 0x00d1b, 0x00d1c, 0x00d1d, 0x00d1e, 0x00d1f,
+ 0x00d20, 0x00d21, 0x00d22, 0x00d23, 0x00d24, 0x00d25, 0x00d26, 0x00d27,
+ 0x00d28, 0x00d29, 0x00d2a, 0x00d2b, 0x00d2c, 0x00d2d, 0x00d2e, 0x00d2f,
+ 0x00d30, 0x00d31, 0x00d32, 0x00d33, 0x00d34, 0x00d35, 0x00d36, 0x00d37,
+ 0x00d38, 0x00d39, 0x00d3a, 0x00d3b, 0x00d3c, 0x00d3d, 0x00d3e, 0x00d3f,
+ 0x00d40, 0x00d41, 0x00d42, 0x00d43, 0x00d44, 0x00d45, 0x00d46, 0x00d47,
+ 0x00d48, 0x00d49, 0x00d4a, 0x00d4b, 0x00d4c, 0x00d4d, 0x00d4e, 0x00d4f,
+ 0x00d50, 0x00d51, 0x00d52, 0x00d53, 0x00d54, 0x00d55, 0x00d56, 0x00d57,
+ 0x00d58, 0x00d59, 0x00d5a, 0x00d5b, 0x00d5c, 0x00d5d, 0x00d5e, 0x00d5f,
+ 0x00d60, 0x00d61, 0x00d62, 0x00d63, 0x00d64, 0x00d65, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x00d70, 0x00d71, 0x00d72, 0x00d73, 0x00d74, 0x00d75, 0x00d76, 0x00d77,
+ 0x00d78, 0x00d79, 0x00d7a, 0x00d7b, 0x00d7c, 0x00d7d, 0x00d7e, 0x00d7f,
+ 0x00d80, 0x00d81, 0x00000, 0x00000, 0x00d84, 0x00d85, 0x00d86, 0x00d87,
+ 0x00d88, 0x00d89, 0x00d8a, 0x00d8b, 0x00d8c, 0x00d8d, 0x00d8e, 0x00d8f,
+ 0x00d90, 0x00d91, 0x00d92, 0x00d93, 0x00d94, 0x00d95, 0x00d96, 0x00d97,
+ 0x00d98, 0x00d99, 0x00d9a, 0x00d9b, 0x00d9c, 0x00d9d, 0x00d9e, 0x00d9f,
+ 0x00da0, 0x00da1, 0x00da2, 0x00da3, 0x00da4, 0x00da5, 0x00da6, 0x00da7,
+ 0x00da8, 0x00da9, 0x00daa, 0x00dab, 0x00dac, 0x00dad, 0x00dae, 0x00daf,
+ 0x00db0, 0x00db1, 0x00db2, 0x00db3, 0x00db4, 0x00db5, 0x00db6, 0x00db7,
+ 0x00db8, 0x00db9, 0x00dba, 0x00dbb, 0x00dbc, 0x00dbd, 0x00dbe, 0x00dbf,
+ 0x00dc0, 0x00dc1, 0x00dc2, 0x00dc3, 0x00dc4, 0x00dc5, 0x00dc6, 0x00dc7,
+ 0x00dc8, 0x00dc9, 0x00dca, 0x00dcb, 0x00dcc, 0x00dcd, 0x00dce, 0x00dcf,
+ 0x00dd0, 0x00dd1, 0x00dd2, 0x00dd3, 0x00dd4, 0x00dd5, 0x00dd6, 0x00dd7,
+ 0x00dd8, 0x00dd9, 0x00dda, 0x00ddb, 0x00ddc, 0x00ddd, 0x00dde, 0x00ddf,
+ 0x00de0, 0x00de1, 0x00de2, 0x00de3, 0x00de4, 0x00de5, 0x00de6, 0x00de7,
+ 0x00de8, 0x00de9, 0x00dea, 0x00deb, 0x00dec, 0x00ded, 0x00dee, 0x00def,
+ 0x00df0, 0x00df1, 0x00df2, 0x00df3, 0x00df4, 0x00df5, 0x00df6, 0x00df7,
+ 0x00df8, 0x00df9, 0x00dfa, 0x00dfb, 0x00dfc, 0x00dfd, 0x00dfe, 0x00dff
+};
+
+static uint32_t unicode_ci_page_0e[] = {
+ 0x00e00, 0x00e01, 0x00e02, 0x00e03, 0x00e04, 0x00e05, 0x00e06, 0x00e07,
+ 0x00e08, 0x00e09, 0x00e0a, 0x00e0b, 0x00e0c, 0x00e0d, 0x00e0e, 0x00e0f,
+ 0x00e10, 0x00e11, 0x00e12, 0x00e13, 0x00e14, 0x00e15, 0x00e16, 0x00e17,
+ 0x00e18, 0x00e19, 0x00e1a, 0x00e1b, 0x00e1c, 0x00e1d, 0x00e1e, 0x00e1f,
+ 0x00e20, 0x00e21, 0x00e22, 0x00e23, 0x00e24, 0x00e25, 0x00e26, 0x00e27,
+ 0x00e28, 0x00e29, 0x00e2a, 0x00e2b, 0x00e2c, 0x00e2d, 0x00e2e, 0x00e2f,
+ 0x00e30, 0x00e31, 0x00e32, 0x00e33, 0x00e34, 0x00e35, 0x00e36, 0x00e37,
+ 0x00e38, 0x00e39, 0x00e3a, 0x00e3b, 0x00e3c, 0x00e3d, 0x00e3e, 0x00e3f,
+ 0x00e40, 0x00e41, 0x00e42, 0x00e43, 0x00e44, 0x00e45, 0x00e46, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00e4c, 0x00e4d, 0x00000, 0x00e4f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00e5a, 0x00e5b, 0x00e5c, 0x00e5d, 0x00e5e, 0x00e5f,
+ 0x00e60, 0x00e61, 0x00e62, 0x00e63, 0x00e64, 0x00e65, 0x00e66, 0x00e67,
+ 0x00e68, 0x00e69, 0x00e6a, 0x00e6b, 0x00e6c, 0x00e6d, 0x00e6e, 0x00e6f,
+ 0x00e70, 0x00e71, 0x00e72, 0x00e73, 0x00e74, 0x00e75, 0x00e76, 0x00e77,
+ 0x00e78, 0x00e79, 0x00e7a, 0x00e7b, 0x00e7c, 0x00e7d, 0x00e7e, 0x00e7f,
+ 0x00e80, 0x00e81, 0x00e82, 0x00e83, 0x00e84, 0x00e85, 0x00e86, 0x00e87,
+ 0x00e88, 0x00e89, 0x00e8a, 0x00e8b, 0x00e8c, 0x00e8d, 0x00e8e, 0x00e8f,
+ 0x00e90, 0x00e91, 0x00e92, 0x00e93, 0x00e94, 0x00e95, 0x00e96, 0x00e97,
+ 0x00e98, 0x00e99, 0x00e9a, 0x00e9b, 0x00e9c, 0x00e9d, 0x00e9e, 0x00e9f,
+ 0x00ea0, 0x00ea1, 0x00ea2, 0x00ea3, 0x00ea4, 0x00ea5, 0x00ea6, 0x00ea7,
+ 0x00ea8, 0x00ea9, 0x00eaa, 0x00eab, 0x00eac, 0x00ead, 0x00eae, 0x00eaf,
+ 0x00eb0, 0x00eb1, 0x00eb2, 0x00eb3, 0x00eb4, 0x00eb5, 0x00eb6, 0x00eb7,
+ 0x00eb8, 0x00eb9, 0x00eba, 0x00ebb, 0x00ebc, 0x00ebd, 0x00ebe, 0x00ebf,
+ 0x00ec0, 0x00ec1, 0x00ec2, 0x00ec3, 0x00ec4, 0x00ec5, 0x00ec6, 0x00ec7,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00ecc, 0x00ecd, 0x00ece, 0x00ecf,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00eda, 0x00edb, 0x00edc, 0x00edd, 0x00ede, 0x00edf,
+ 0x00ee0, 0x00ee1, 0x00ee2, 0x00ee3, 0x00ee4, 0x00ee5, 0x00ee6, 0x00ee7,
+ 0x00ee8, 0x00ee9, 0x00eea, 0x00eeb, 0x00eec, 0x00eed, 0x00eee, 0x00eef,
+ 0x00ef0, 0x00ef1, 0x00ef2, 0x00ef3, 0x00ef4, 0x00ef5, 0x00ef6, 0x00ef7,
+ 0x00ef8, 0x00ef9, 0x00efa, 0x00efb, 0x00efc, 0x00efd, 0x00efe, 0x00eff
+};
+
+static uint32_t unicode_ci_page_0f[] = {
+ 0x00f00, 0x00f01, 0x00f02, 0x00f03, 0x00f04, 0x00f05, 0x00f06, 0x00f07,
+ 0x00f08, 0x00f09, 0x00f0a, 0x00f0b, 0x00f0b, 0x00f0d, 0x00f0e, 0x00f0f,
+ 0x00f10, 0x00f11, 0x00f12, 0x00f13, 0x00f14, 0x00f15, 0x00f16, 0x00f17,
+ 0x00000, 0x00000, 0x00f1a, 0x00f1b, 0x00f1c, 0x00f1d, 0x00f1e, 0x00f1f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x00030, 0x00f34, 0x00000, 0x00f36, 0x00000,
+ 0x00f38, 0x00000, 0x00f3a, 0x00f3b, 0x00f3c, 0x00f3d, 0x00f3e, 0x00f3f,
+ 0x00f40, 0x00f41, 0x00f42, 0x00f43, 0x00f44, 0x00f45, 0x00f46, 0x00f47,
+ 0x00f48, 0x00f49, 0x00f4a, 0x00f4b, 0x00f4c, 0x00f4d, 0x00f4e, 0x00f4f,
+ 0x00f50, 0x00f51, 0x00f52, 0x00f53, 0x00f54, 0x00f55, 0x00f56, 0x00f57,
+ 0x00f58, 0x00f59, 0x00f5a, 0x00f5b, 0x00f5c, 0x00f5d, 0x00f5e, 0x00f5f,
+ 0x00f60, 0x00f61, 0x00f62, 0x00f63, 0x00f64, 0x00f65, 0x00f66, 0x00f67,
+ 0x00f68, 0x00f69, 0x00f62, 0x00f6b, 0x00f6c, 0x00f6d, 0x00f6e, 0x00f6f,
+ 0x00f70, 0x00f71, 0x00f72, 0x00f73, 0x00f74, 0x00f75, 0x00f76, 0x00f77,
+ 0x00f78, 0x00f79, 0x00f7a, 0x00f7b, 0x00f7c, 0x00f7d, 0x00000, 0x00000,
+ 0x00f80, 0x00f81, 0x00000, 0x00000, 0x00f84, 0x00f85, 0x00000, 0x00000,
+ 0x00f88, 0x00f89, 0x00f8a, 0x00f8b, 0x00f8c, 0x00f8d, 0x00f8e, 0x00f8f,
+ 0x00f90, 0x00f91, 0x00f92, 0x00f93, 0x00f94, 0x00f95, 0x00f96, 0x00f97,
+ 0x00f98, 0x00f99, 0x00f9a, 0x00f9b, 0x00f9c, 0x00f9d, 0x00f9e, 0x00f9f,
+ 0x00fa0, 0x00fa1, 0x00fa2, 0x00fa3, 0x00fa4, 0x00fa5, 0x00fa6, 0x00fa7,
+ 0x00fa8, 0x00fa9, 0x00faa, 0x00fab, 0x00fac, 0x00fad, 0x00fae, 0x00faf,
+ 0x00fb0, 0x00fb1, 0x00fb2, 0x00fb3, 0x00fb4, 0x00fb5, 0x00fb6, 0x00fb7,
+ 0x00fb8, 0x00fb9, 0x00fad, 0x00fb1, 0x00fb2, 0x00fbd, 0x00fbe, 0x00fbf,
+ 0x00fc0, 0x00fc1, 0x00fc2, 0x00fc3, 0x00fc4, 0x00fc5, 0x00000, 0x00fc7,
+ 0x00fc8, 0x00fc9, 0x00fca, 0x00fcb, 0x00fcc, 0x00fcd, 0x00fce, 0x00fcf,
+ 0x00fd0, 0x00fd1, 0x00fd2, 0x00fd3, 0x00fd4, 0x00fd5, 0x00fd6, 0x00fd7,
+ 0x00fd8, 0x00fd9, 0x00fda, 0x00fdb, 0x00fdc, 0x00fdd, 0x00fde, 0x00fdf,
+ 0x00fe0, 0x00fe1, 0x00fe2, 0x00fe3, 0x00fe4, 0x00fe5, 0x00fe6, 0x00fe7,
+ 0x00fe8, 0x00fe9, 0x00fea, 0x00feb, 0x00fec, 0x00fed, 0x00fee, 0x00fef,
+ 0x00ff0, 0x00ff1, 0x00ff2, 0x00ff3, 0x00ff4, 0x00ff5, 0x00ff6, 0x00ff7,
+ 0x00ff8, 0x00ff9, 0x00ffa, 0x00ffb, 0x00ffc, 0x00ffd, 0x00ffe, 0x00fff
+};
+
+static uint32_t unicode_ci_page_10[] = {
+ 0x01000, 0x01001, 0x01002, 0x01003, 0x01004, 0x01005, 0x01006, 0x01007,
+ 0x01008, 0x01009, 0x0100a, 0x0100b, 0x0100c, 0x0100d, 0x0100e, 0x0100f,
+ 0x01010, 0x01011, 0x01012, 0x01013, 0x01014, 0x01015, 0x01016, 0x01017,
+ 0x01018, 0x01019, 0x0101a, 0x0101b, 0x0101c, 0x0101d, 0x0101e, 0x0101f,
+ 0x01020, 0x01021, 0x01022, 0x01023, 0x01024, 0x01025, 0x01026, 0x01027,
+ 0x01028, 0x01029, 0x0102a, 0x0102b, 0x0102c, 0x0102d, 0x0102e, 0x0102f,
+ 0x01030, 0x01031, 0x01032, 0x01033, 0x01034, 0x01035, 0x00000, 0x00000,
+ 0x00000, 0x01039, 0x0103a, 0x0103b, 0x0103c, 0x0103d, 0x0103e, 0x0103f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0104a, 0x0104b, 0x0104c, 0x0104d, 0x0104e, 0x0104f,
+ 0x01050, 0x01051, 0x01052, 0x01053, 0x01054, 0x01055, 0x01056, 0x01057,
+ 0x01058, 0x01059, 0x0105a, 0x0105b, 0x0105c, 0x0105d, 0x0105e, 0x0105f,
+ 0x01060, 0x01061, 0x01062, 0x01063, 0x01064, 0x01065, 0x01066, 0x01067,
+ 0x01068, 0x01069, 0x0106a, 0x0106b, 0x0106c, 0x0106d, 0x0106e, 0x0106f,
+ 0x01070, 0x01071, 0x01072, 0x01073, 0x01074, 0x01075, 0x01076, 0x01077,
+ 0x01078, 0x01079, 0x0107a, 0x0107b, 0x0107c, 0x0107d, 0x0107e, 0x0107f,
+ 0x01080, 0x01081, 0x01082, 0x01083, 0x01084, 0x01085, 0x01086, 0x01087,
+ 0x01088, 0x01089, 0x0108a, 0x0108b, 0x0108c, 0x0108d, 0x0108e, 0x0108f,
+ 0x01090, 0x01091, 0x01092, 0x01093, 0x01094, 0x01095, 0x01096, 0x01097,
+ 0x01098, 0x01099, 0x0109a, 0x0109b, 0x0109c, 0x0109d, 0x0109e, 0x0109f,
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x010c6, 0x010c7,
+ 0x010c8, 0x010c9, 0x010ca, 0x010cb, 0x010cc, 0x010cd, 0x010ce, 0x010cf,
+ 0x010a0, 0x010a1, 0x010a2, 0x010a3, 0x010a4, 0x010a5, 0x010a6, 0x010a7,
+ 0x010a8, 0x010a9, 0x010aa, 0x010ab, 0x010ac, 0x010ad, 0x010ae, 0x010af,
+ 0x010b0, 0x010b1, 0x010b2, 0x010b3, 0x010b4, 0x010b5, 0x010b6, 0x010b7,
+ 0x010b8, 0x010b9, 0x010ba, 0x010bb, 0x010bc, 0x010bd, 0x010be, 0x010bf,
+ 0x010c0, 0x010c1, 0x010c2, 0x010c3, 0x010c4, 0x010c5, 0x010f6, 0x010f7,
+ 0x010f8, 0x010f9, 0x010fa, 0x010fb, 0x010fc, 0x010fd, 0x010fe, 0x010ff
+};
+
+static uint32_t unicode_ci_page_13[] = {
+ 0x01300, 0x01301, 0x01302, 0x01303, 0x01304, 0x01305, 0x01306, 0x01307,
+ 0x01308, 0x01309, 0x0130a, 0x0130b, 0x0130c, 0x0130d, 0x0130e, 0x0130f,
+ 0x01310, 0x01311, 0x01312, 0x01313, 0x01314, 0x01315, 0x01316, 0x01317,
+ 0x01318, 0x01319, 0x0131a, 0x0131b, 0x0131c, 0x0131d, 0x0131e, 0x0131f,
+ 0x01320, 0x01321, 0x01322, 0x01323, 0x01324, 0x01325, 0x01326, 0x01327,
+ 0x01328, 0x01329, 0x0132a, 0x0132b, 0x0132c, 0x0132d, 0x0132e, 0x0132f,
+ 0x01330, 0x01331, 0x01332, 0x01333, 0x01334, 0x01335, 0x01336, 0x01337,
+ 0x01338, 0x01339, 0x0133a, 0x0133b, 0x0133c, 0x0133d, 0x0133e, 0x0133f,
+ 0x01340, 0x01341, 0x01342, 0x01343, 0x01344, 0x01345, 0x01346, 0x01347,
+ 0x01348, 0x01349, 0x0134a, 0x0134b, 0x0134c, 0x0134d, 0x0134e, 0x0134f,
+ 0x01350, 0x01351, 0x01352, 0x01353, 0x01354, 0x01355, 0x01356, 0x01357,
+ 0x01358, 0x01359, 0x0135a, 0x0135b, 0x0135c, 0x0135d, 0x0135e, 0x0135f,
+ 0x01360, 0x01361, 0x01362, 0x01363, 0x01364, 0x01365, 0x01366, 0x01367,
+ 0x01368, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x01372, 0x01373, 0x01374, 0x01375, 0x01376, 0x01377,
+ 0x01378, 0x01379, 0x0137a, 0x0137b, 0x0137c, 0x0137d, 0x0137e, 0x0137f,
+ 0x01380, 0x01381, 0x01382, 0x01383, 0x01384, 0x01385, 0x01386, 0x01387,
+ 0x01388, 0x01389, 0x0138a, 0x0138b, 0x0138c, 0x0138d, 0x0138e, 0x0138f,
+ 0x01390, 0x01391, 0x01392, 0x01393, 0x01394, 0x01395, 0x01396, 0x01397,
+ 0x01398, 0x01399, 0x0139a, 0x0139b, 0x0139c, 0x0139d, 0x0139e, 0x0139f,
+ 0x013a0, 0x013a1, 0x013a2, 0x013a3, 0x013a4, 0x013a5, 0x013a6, 0x013a7,
+ 0x013a8, 0x013a9, 0x013aa, 0x013ab, 0x013ac, 0x013ad, 0x013ae, 0x013af,
+ 0x013b0, 0x013b1, 0x013b2, 0x013b3, 0x013b4, 0x013b5, 0x013b6, 0x013b7,
+ 0x013b8, 0x013b9, 0x013ba, 0x013bb, 0x013bc, 0x013bd, 0x013be, 0x013bf,
+ 0x013c0, 0x013c1, 0x013c2, 0x013c3, 0x013c4, 0x013c5, 0x013c6, 0x013c7,
+ 0x013c8, 0x013c9, 0x013ca, 0x013cb, 0x013cc, 0x013cd, 0x013ce, 0x013cf,
+ 0x013d0, 0x013d1, 0x013d2, 0x013d3, 0x013d4, 0x013d5, 0x013d6, 0x013d7,
+ 0x013d8, 0x013d9, 0x013da, 0x013db, 0x013dc, 0x013dd, 0x013de, 0x013df,
+ 0x013e0, 0x013e1, 0x013e2, 0x013e3, 0x013e4, 0x013e5, 0x013e6, 0x013e7,
+ 0x013e8, 0x013e9, 0x013ea, 0x013eb, 0x013ec, 0x013ed, 0x013ee, 0x013ef,
+ 0x013f0, 0x013f1, 0x013f2, 0x013f3, 0x013f4, 0x013f5, 0x013f6, 0x013f7,
+ 0x013f8, 0x013f9, 0x013fa, 0x013fb, 0x013fc, 0x013fd, 0x013fe, 0x013ff
+};
+
+static uint32_t unicode_ci_page_16[] = {
+ 0x01600, 0x01601, 0x01602, 0x01603, 0x01604, 0x01605, 0x01606, 0x01607,
+ 0x01608, 0x01609, 0x0160a, 0x0160b, 0x0160c, 0x0160d, 0x0160e, 0x0160f,
+ 0x01610, 0x01611, 0x01612, 0x01613, 0x01614, 0x01615, 0x01616, 0x01617,
+ 0x01618, 0x01619, 0x0161a, 0x0161b, 0x0161c, 0x0161d, 0x0161e, 0x0161f,
+ 0x01620, 0x01621, 0x01622, 0x01623, 0x01624, 0x01625, 0x01626, 0x01627,
+ 0x01628, 0x01629, 0x0162a, 0x0162b, 0x0162c, 0x0162d, 0x0162e, 0x0162f,
+ 0x01630, 0x01631, 0x01632, 0x01633, 0x01634, 0x01635, 0x01636, 0x01637,
+ 0x01638, 0x01639, 0x0163a, 0x0163b, 0x0163c, 0x0163d, 0x0163e, 0x0163f,
+ 0x01640, 0x01641, 0x01642, 0x01643, 0x01644, 0x01645, 0x01646, 0x01647,
+ 0x01648, 0x01649, 0x0164a, 0x0164b, 0x0164c, 0x0164d, 0x0164e, 0x0164f,
+ 0x01650, 0x01651, 0x01652, 0x01653, 0x01654, 0x01655, 0x01656, 0x01657,
+ 0x01658, 0x01659, 0x0165a, 0x0165b, 0x0165c, 0x0165d, 0x0165e, 0x0165f,
+ 0x01660, 0x01661, 0x01662, 0x01663, 0x01664, 0x01665, 0x01666, 0x01667,
+ 0x01668, 0x01669, 0x0166a, 0x0166b, 0x0166c, 0x0166d, 0x0166e, 0x0166f,
+ 0x01670, 0x01671, 0x01672, 0x01673, 0x01674, 0x01675, 0x01676, 0x01677,
+ 0x01678, 0x01679, 0x0167a, 0x0167b, 0x0167c, 0x0167d, 0x0167e, 0x0167f,
+ 0x01680, 0x01681, 0x01682, 0x01683, 0x01684, 0x01685, 0x01686, 0x01687,
+ 0x01688, 0x01689, 0x0168a, 0x0168b, 0x0168c, 0x0168d, 0x0168e, 0x0168f,
+ 0x01690, 0x01691, 0x01692, 0x01693, 0x01694, 0x01695, 0x01696, 0x01697,
+ 0x01698, 0x01699, 0x0169a, 0x0169b, 0x0169c, 0x0169d, 0x0169e, 0x0169f,
+ 0x016a0, 0x016a0, 0x016a2, 0x016a3, 0x016a2, 0x016a2, 0x016a6, 0x016a6,
+ 0x016a8, 0x016a8, 0x016aa, 0x016ab, 0x016a8, 0x016a8, 0x016a8, 0x016af,
+ 0x016b0, 0x016b1, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b2, 0x016b7,
+ 0x016b8, 0x016b9, 0x016ba, 0x016ba, 0x016ba, 0x016ba, 0x016be, 0x016be,
+ 0x016be, 0x016c1, 0x016c1, 0x016c3, 0x016c3, 0x016c5, 0x016c5, 0x016c7,
+ 0x016c8, 0x016c9, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016ca, 0x016cf,
+ 0x016cf, 0x016cf, 0x016d2, 0x016d2, 0x016d2, 0x016c8, 0x016d6, 0x016d7,
+ 0x016d7, 0x016d7, 0x016da, 0x016da, 0x016dc, 0x016dc, 0x016de, 0x016df,
+ 0x016e0, 0x016e1, 0x016e2, 0x016e3, 0x016e4, 0x016e5, 0x016e6, 0x016e6,
+ 0x016e6, 0x016b9, 0x016ca, 0x016eb, 0x016ec, 0x016ed, 0x016ee, 0x016ef,
+ 0x016f0, 0x016f1, 0x016f2, 0x016f3, 0x016f4, 0x016f5, 0x016f6, 0x016f7,
+ 0x016f8, 0x016f9, 0x016fa, 0x016fb, 0x016fc, 0x016fd, 0x016fe, 0x016ff
+};
+
+static uint32_t unicode_ci_page_17[] = {
+ 0x01700, 0x01701, 0x01702, 0x01703, 0x01704, 0x01705, 0x01706, 0x01707,
+ 0x01708, 0x01709, 0x0170a, 0x0170b, 0x0170c, 0x0170d, 0x0170e, 0x0170f,
+ 0x01710, 0x01711, 0x01712, 0x01713, 0x01714, 0x01715, 0x01716, 0x01717,
+ 0x01718, 0x01719, 0x0171a, 0x0171b, 0x0171c, 0x0171d, 0x0171e, 0x0171f,
+ 0x01720, 0x01721, 0x01722, 0x01723, 0x01724, 0x01725, 0x01726, 0x01727,
+ 0x01728, 0x01729, 0x0172a, 0x0172b, 0x0172c, 0x0172d, 0x0172e, 0x0172f,
+ 0x01730, 0x01731, 0x01732, 0x01733, 0x01734, 0x01735, 0x01736, 0x01737,
+ 0x01738, 0x01739, 0x0173a, 0x0173b, 0x0173c, 0x0173d, 0x0173e, 0x0173f,
+ 0x01740, 0x01741, 0x01742, 0x01743, 0x01744, 0x01745, 0x01746, 0x01747,
+ 0x01748, 0x01749, 0x0174a, 0x0174b, 0x0174c, 0x0174d, 0x0174e, 0x0174f,
+ 0x01750, 0x01751, 0x01752, 0x01753, 0x01754, 0x01755, 0x01756, 0x01757,
+ 0x01758, 0x01759, 0x0175a, 0x0175b, 0x0175c, 0x0175d, 0x0175e, 0x0175f,
+ 0x01760, 0x01761, 0x01762, 0x01763, 0x01764, 0x01765, 0x01766, 0x01767,
+ 0x01768, 0x01769, 0x0176a, 0x0176b, 0x0176c, 0x0176d, 0x0176e, 0x0176f,
+ 0x01770, 0x01771, 0x01772, 0x01773, 0x01774, 0x01775, 0x01776, 0x01777,
+ 0x01778, 0x01779, 0x0177a, 0x0177b, 0x0177c, 0x0177d, 0x0177e, 0x0177f,
+ 0x01780, 0x01781, 0x01782, 0x01783, 0x01784, 0x01785, 0x01786, 0x01787,
+ 0x01788, 0x01789, 0x0178a, 0x0178b, 0x0178c, 0x0178d, 0x0178e, 0x0178f,
+ 0x01790, 0x01791, 0x01792, 0x01793, 0x01794, 0x01795, 0x01796, 0x01797,
+ 0x01798, 0x01799, 0x0179a, 0x0179b, 0x0179c, 0x0179d, 0x0179e, 0x0179f,
+ 0x017a0, 0x017a1, 0x017a2, 0x017a3, 0x017a4, 0x017a5, 0x017a6, 0x017a7,
+ 0x017a8, 0x017a9, 0x017aa, 0x017ab, 0x017ac, 0x017ad, 0x017ae, 0x017af,
+ 0x017b0, 0x017b1, 0x017b2, 0x017b3, 0x017b4, 0x017b5, 0x017b6, 0x017b7,
+ 0x017b8, 0x017b9, 0x017ba, 0x017bb, 0x017bc, 0x017bd, 0x017be, 0x017bf,
+ 0x017c0, 0x017c1, 0x017c2, 0x017c3, 0x017c4, 0x017c5, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x017d2, 0x00000, 0x017d4, 0x017d5, 0x017d6, 0x017d7,
+ 0x017d8, 0x017d9, 0x017da, 0x017db, 0x017dc, 0x00000, 0x017de, 0x017df,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017ea, 0x017eb, 0x017ec, 0x017ed, 0x017ee, 0x017ef,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x017fa, 0x017fb, 0x017fc, 0x017fd, 0x017fe, 0x017ff
+};
+
+static uint32_t unicode_ci_page_18[] = {
+ 0x01800, 0x01801, 0x01802, 0x01803, 0x01804, 0x01805, 0x01806, 0x01807,
+ 0x01808, 0x01809, 0x0180a, 0x00000, 0x00000, 0x00000, 0x00000, 0x0180f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0181a, 0x0181b, 0x0181c, 0x0181d, 0x0181e, 0x0181f,
+ 0x01820, 0x01821, 0x01822, 0x01823, 0x01824, 0x01825, 0x01826, 0x01827,
+ 0x01828, 0x01829, 0x0182a, 0x0182b, 0x0182c, 0x0182d, 0x0182e, 0x0182f,
+ 0x01830, 0x01831, 0x01832, 0x01833, 0x01834, 0x01835, 0x01836, 0x01837,
+ 0x01838, 0x01839, 0x0183a, 0x0183b, 0x0183c, 0x0183d, 0x0183e, 0x0183f,
+ 0x01840, 0x01841, 0x01842, 0x01843, 0x01844, 0x01845, 0x01846, 0x01847,
+ 0x01848, 0x01849, 0x0184a, 0x0184b, 0x0184c, 0x0184d, 0x0184e, 0x0184f,
+ 0x01850, 0x01851, 0x01852, 0x01853, 0x01854, 0x01855, 0x01856, 0x01857,
+ 0x01858, 0x01859, 0x0185a, 0x0185b, 0x0185c, 0x0185d, 0x0185e, 0x0185f,
+ 0x01860, 0x01861, 0x01862, 0x01863, 0x01864, 0x01865, 0x01866, 0x01867,
+ 0x01868, 0x01869, 0x0186a, 0x0186b, 0x0186c, 0x0186d, 0x0186e, 0x0186f,
+ 0x01870, 0x01871, 0x01872, 0x01873, 0x01874, 0x01875, 0x01876, 0x01877,
+ 0x01878, 0x01879, 0x0187a, 0x0187b, 0x0187c, 0x0187d, 0x0187e, 0x0187f,
+ 0x01880, 0x01881, 0x01882, 0x01883, 0x01884, 0x01885, 0x01886, 0x01887,
+ 0x01888, 0x01889, 0x0188a, 0x0188b, 0x0188c, 0x0188d, 0x0188e, 0x0188f,
+ 0x01890, 0x01891, 0x01892, 0x01893, 0x01894, 0x01895, 0x01896, 0x01897,
+ 0x01898, 0x01899, 0x0189a, 0x0189b, 0x0189c, 0x0189d, 0x0189e, 0x0189f,
+ 0x018a0, 0x018a1, 0x018a2, 0x018a3, 0x018a4, 0x018a5, 0x018a6, 0x018a7,
+ 0x018a8, 0x018a9, 0x018aa, 0x018ab, 0x018ac, 0x018ad, 0x018ae, 0x018af,
+ 0x018b0, 0x018b1, 0x018b2, 0x018b3, 0x018b4, 0x018b5, 0x018b6, 0x018b7,
+ 0x018b8, 0x018b9, 0x018ba, 0x018bb, 0x018bc, 0x018bd, 0x018be, 0x018bf,
+ 0x018c0, 0x018c1, 0x018c2, 0x018c3, 0x018c4, 0x018c5, 0x018c6, 0x018c7,
+ 0x018c8, 0x018c9, 0x018ca, 0x018cb, 0x018cc, 0x018cd, 0x018ce, 0x018cf,
+ 0x018d0, 0x018d1, 0x018d2, 0x018d3, 0x018d4, 0x018d5, 0x018d6, 0x018d7,
+ 0x018d8, 0x018d9, 0x018da, 0x018db, 0x018dc, 0x018dd, 0x018de, 0x018df,
+ 0x018e0, 0x018e1, 0x018e2, 0x018e3, 0x018e4, 0x018e5, 0x018e6, 0x018e7,
+ 0x018e8, 0x018e9, 0x018ea, 0x018eb, 0x018ec, 0x018ed, 0x018ee, 0x018ef,
+ 0x018f0, 0x018f1, 0x018f2, 0x018f3, 0x018f4, 0x018f5, 0x018f6, 0x018f7,
+ 0x018f8, 0x018f9, 0x018fa, 0x018fb, 0x018fc, 0x018fd, 0x018fe, 0x018ff
+};
+
+static uint32_t unicode_ci_page_19[] = {
+ 0x01900, 0x01901, 0x01902, 0x01903, 0x01904, 0x01905, 0x01906, 0x01907,
+ 0x01908, 0x01909, 0x0190a, 0x0190b, 0x0190c, 0x0190d, 0x0190e, 0x0190f,
+ 0x01910, 0x01911, 0x01912, 0x01913, 0x01914, 0x01915, 0x01916, 0x01917,
+ 0x01918, 0x01919, 0x0191a, 0x0191b, 0x0191c, 0x0191d, 0x0191e, 0x0191f,
+ 0x01920, 0x01921, 0x01922, 0x01923, 0x01924, 0x01925, 0x01926, 0x01927,
+ 0x01928, 0x01929, 0x0192a, 0x0192b, 0x0192c, 0x0192d, 0x0192e, 0x0192f,
+ 0x01930, 0x01931, 0x01932, 0x01933, 0x01934, 0x01935, 0x01936, 0x01937,
+ 0x01938, 0x00000, 0x00000, 0x00000, 0x0193c, 0x0193d, 0x0193e, 0x0193f,
+ 0x01940, 0x01941, 0x01942, 0x01943, 0x01944, 0x01945, 0x00030, 0x00031,
+ 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039,
+ 0x01950, 0x01951, 0x01952, 0x01953, 0x01954, 0x01955, 0x01956, 0x01957,
+ 0x01958, 0x01959, 0x0195a, 0x0195b, 0x0195c, 0x0195d, 0x0195e, 0x0195f,
+ 0x01960, 0x01961, 0x01962, 0x01963, 0x01964, 0x01965, 0x01966, 0x01967,
+ 0x01968, 0x01969, 0x0196a, 0x0196b, 0x0196c, 0x0196d, 0x0196e, 0x0196f,
+ 0x01970, 0x01971, 0x01972, 0x01973, 0x01974, 0x01975, 0x01976, 0x01977,
+ 0x01978, 0x01979, 0x0197a, 0x0197b, 0x0197c, 0x0197d, 0x0197e, 0x0197f,
+ 0x01980, 0x01981, 0x01982, 0x01983, 0x01984, 0x01985, 0x01986, 0x01987,
+ 0x01988, 0x01989, 0x0198a, 0x0198b, 0x0198c, 0x0198d, 0x0198e, 0x0198f,
+ 0x01990, 0x01991, 0x01992, 0x01993, 0x01994, 0x01995, 0x01996, 0x01997,
+ 0x01998, 0x01999, 0x0199a, 0x0199b, 0x0199c, 0x0199d, 0x0199e, 0x0199f,
+ 0x019a0, 0x019a1, 0x019a2, 0x019a3, 0x019a4, 0x019a5, 0x019a6, 0x019a7,
+ 0x019a8, 0x019a9, 0x019aa, 0x019ab, 0x019ac, 0x019ad, 0x019ae, 0x019af,
+ 0x019b0, 0x019b1, 0x019b2, 0x019b3, 0x019b4, 0x019b5, 0x019b6, 0x019b7,
+ 0x019b8, 0x019b9, 0x019ba, 0x019bb, 0x019bc, 0x019bd, 0x019be, 0x019bf,
+ 0x019c0, 0x019c1, 0x019c2, 0x019c3, 0x019c4, 0x019c5, 0x019c6, 0x019c7,
+ 0x019c8, 0x019c9, 0x019ca, 0x019cb, 0x019cc, 0x019cd, 0x019ce, 0x019cf,
+ 0x019d0, 0x019d1, 0x019d2, 0x019d3, 0x019d4, 0x019d5, 0x019d6, 0x019d7,
+ 0x019d8, 0x019d9, 0x019da, 0x019db, 0x019dc, 0x019dd, 0x019de, 0x019df,
+ 0x019e0, 0x019e1, 0x019e2, 0x019e3, 0x019e4, 0x019e5, 0x019e6, 0x019e7,
+ 0x019e8, 0x019e9, 0x019ea, 0x019eb, 0x019ec, 0x019ed, 0x019ee, 0x019ef,
+ 0x019f0, 0x019f1, 0x019f2, 0x019f3, 0x019f4, 0x019f5, 0x019f6, 0x019f7,
+ 0x019f8, 0x019f9, 0x019fa, 0x019fb, 0x019fc, 0x019fd, 0x019fe, 0x019ff
+};
+
+static uint32_t unicode_ci_page_1d[] = {
+ 0x01d00, 0x01d01, 0x01d02, 0x01d03, 0x01d04, 0x01d05, 0x01d06, 0x01d07,
+ 0x01d08, 0x01d09, 0x01d0a, 0x01d0b, 0x01d0c, 0x01d0d, 0x01d0e, 0x01d0f,
+ 0x01d10, 0x01d11, 0x01d12, 0x01d13, 0x01d14, 0x01d15, 0x01d16, 0x01d17,
+ 0x01d18, 0x01d19, 0x01d1a, 0x01d1b, 0x01d1c, 0x01d1d, 0x01d1e, 0x01d1f,
+ 0x01d20, 0x01d21, 0x01d22, 0x01d23, 0x01d24, 0x01d25, 0x01d26, 0x01d27,
+ 0x01d28, 0x01d29, 0x01d2a, 0x01d2b, 0x00041, 0x000c6, 0x00042, 0x01d2f,
+ 0x00044, 0x00045, 0x0018e, 0x00047, 0x00048, 0x00049, 0x0004a, 0x0004b,
+ 0x0004c, 0x0004d, 0x0004e, 0x01d3b, 0x0004f, 0x00222, 0x00050, 0x00052,
+ 0x00054, 0x00055, 0x00057, 0x00041, 0x00250, 0x00251, 0x01d02, 0x00042,
+ 0x00044, 0x00045, 0x0018f, 0x00190, 0x01d08, 0x00047, 0x01d09, 0x0004b,
+ 0x0004d, 0x0014a, 0x0004f, 0x00186, 0x01d16, 0x01d17, 0x00050, 0x00054,
+ 0x00055, 0x01d1d, 0x0019c, 0x00056, 0x01d25, 0x00392, 0x00393, 0x00394,
+ 0x003a6, 0x003a7, 0x00049, 0x00052, 0x00055, 0x00056, 0x00392, 0x00393,
+ 0x003a1, 0x003a6, 0x003a7, 0x01d6b, 0x01d6c, 0x01d6d, 0x01d6e, 0x01d6f,
+ 0x01d70, 0x01d71, 0x01d72, 0x01d73, 0x01d74, 0x01d75, 0x01d76, 0x01d77,
+ 0x01d78, 0x01d79, 0x01d7a, 0x01d7b, 0x01d7c, 0x01d7d, 0x01d7e, 0x01d7f,
+ 0x01d80, 0x01d81, 0x01d82, 0x01d83, 0x01d84, 0x01d85, 0x01d86, 0x01d87,
+ 0x01d88, 0x01d89, 0x01d8a, 0x01d8b, 0x01d8c, 0x01d8d, 0x01d8e, 0x01d8f,
+ 0x01d90, 0x01d91, 0x01d92, 0x01d93, 0x01d94, 0x01d95, 0x01d96, 0x01d97,
+ 0x01d98, 0x01d99, 0x01d9a, 0x01d9b, 0x01d9c, 0x01d9d, 0x01d9e, 0x01d9f,
+ 0x01da0, 0x01da1, 0x01da2, 0x01da3, 0x01da4, 0x01da5, 0x01da6, 0x01da7,
+ 0x01da8, 0x01da9, 0x01daa, 0x01dab, 0x01dac, 0x01dad, 0x01dae, 0x01daf,
+ 0x01db0, 0x01db1, 0x01db2, 0x01db3, 0x01db4, 0x01db5, 0x01db6, 0x01db7,
+ 0x01db8, 0x01db9, 0x01dba, 0x01dbb, 0x01dbc, 0x01dbd, 0x01dbe, 0x01dbf,
+ 0x01dc0, 0x01dc1, 0x01dc2, 0x01dc3, 0x01dc4, 0x01dc5, 0x01dc6, 0x01dc7,
+ 0x01dc8, 0x01dc9, 0x01dca, 0x01dcb, 0x01dcc, 0x01dcd, 0x01dce, 0x01dcf,
+ 0x01dd0, 0x01dd1, 0x01dd2, 0x01dd3, 0x01dd4, 0x01dd5, 0x01dd6, 0x01dd7,
+ 0x01dd8, 0x01dd9, 0x01dda, 0x01ddb, 0x01ddc, 0x01ddd, 0x01dde, 0x01ddf,
+ 0x01de0, 0x01de1, 0x01de2, 0x01de3, 0x01de4, 0x01de5, 0x01de6, 0x01de7,
+ 0x01de8, 0x01de9, 0x01dea, 0x01deb, 0x01dec, 0x01ded, 0x01dee, 0x01def,
+ 0x01df0, 0x01df1, 0x01df2, 0x01df3, 0x01df4, 0x01df5, 0x01df6, 0x01df7,
+ 0x01df8, 0x01df9, 0x01dfa, 0x01dfb, 0x01dfc, 0x01dfd, 0x01dfe, 0x01dff
+};
+
+static uint32_t unicode_ci_page_1e[] = {
+ 0x00041, 0x00041, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042, 0x00042,
+ 0x00043, 0x00043, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044, 0x00044,
+ 0x00044, 0x00044, 0x00044, 0x00044, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00046, 0x00046,
+ 0x00047, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048, 0x00048,
+ 0x00048, 0x00048, 0x00048, 0x00048, 0x00049, 0x00049, 0x00049, 0x00049,
+ 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004b, 0x0004c, 0x0004c,
+ 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004c, 0x0004d, 0x0004d,
+ 0x0004d, 0x0004d, 0x0004d, 0x0004d, 0x0004e, 0x0004e, 0x0004e, 0x0004e,
+ 0x0004e, 0x0004e, 0x0004e, 0x0004e, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00050, 0x00050, 0x00050, 0x00050,
+ 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052, 0x00052,
+ 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053, 0x00053,
+ 0x00053, 0x00053, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054, 0x00054,
+ 0x00054, 0x00054, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00056, 0x00056, 0x00056, 0x00056,
+ 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057, 0x00057,
+ 0x00057, 0x00057, 0x00058, 0x00058, 0x00058, 0x00058, 0x00059, 0x00059,
+ 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x0005a, 0x00048, 0x00054,
+ 0x00057, 0x00059, 0x01e9a, 0x00053, 0x01e9c, 0x01e9d, 0x01e9e, 0x01e9f,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041, 0x00041,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045, 0x00045,
+ 0x00049, 0x00049, 0x00049, 0x00049, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x0004f,
+ 0x0004f, 0x0004f, 0x0004f, 0x0004f, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055, 0x00055,
+ 0x00055, 0x00055, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059, 0x00059,
+ 0x00059, 0x00059, 0x01efa, 0x01efb, 0x01efc, 0x01efd, 0x01efe, 0x01eff
+};
+
+static uint32_t unicode_ci_page_1f[] = {
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f16, 0x01f17,
+ 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x00395, 0x01f1e, 0x01f1f,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f46, 0x01f47,
+ 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x0039f, 0x01f4e, 0x01f4f,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a5,
+ 0x01f58, 0x003a5, 0x01f5a, 0x003a5, 0x01f5c, 0x003a5, 0x01f5e, 0x003a5,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00395, 0x00395, 0x00397, 0x00397, 0x00399, 0x00399,
+ 0x0039f, 0x0039f, 0x003a5, 0x003a5, 0x003a9, 0x003a9, 0x01f7e, 0x01f7f,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x00391,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397, 0x00397,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9, 0x003a9,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fb5, 0x00391, 0x00391,
+ 0x00391, 0x00391, 0x00391, 0x00391, 0x00391, 0x01fbd, 0x00399, 0x01fbd,
+ 0x01fc0, 0x000a8, 0x00397, 0x00397, 0x00397, 0x01fc5, 0x00397, 0x00397,
+ 0x00395, 0x00395, 0x00397, 0x00397, 0x00397, 0x01fbd, 0x01fbd, 0x01fbd,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fd4, 0x01fd5, 0x00399, 0x00399,
+ 0x00399, 0x00399, 0x00399, 0x00399, 0x01fdc, 0x01fdd, 0x01fdd, 0x01fdd,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x003a1, 0x003a5, 0x003a5,
+ 0x003a5, 0x003a5, 0x003a5, 0x003a5, 0x003a1, 0x000a8, 0x000a8, 0x00060,
+ 0x01ff0, 0x01ff1, 0x003a9, 0x003a9, 0x003a9, 0x01ff5, 0x003a9, 0x003a9,
+ 0x0039f, 0x0039f, 0x003a9, 0x003a9, 0x003a9, 0x000b4, 0x01fdd, 0x01fff
+};
+
+static uint32_t unicode_ci_page_20[] = {
+ 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020, 0x00020,
+ 0x00020, 0x00020, 0x00020, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x02010, 0x02010, 0x02012, 0x02013, 0x02014, 0x02015, 0x02016, 0x02017,
+ 0x02018, 0x02019, 0x0201a, 0x0201b, 0x0201c, 0x0201d, 0x0201e, 0x0201f,
+ 0x02020, 0x02021, 0x02022, 0x02023, 0x0002e, 0x02025, 0x02026, 0x02027,
+ 0x02028, 0x02029, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00020,
+ 0x02030, 0x02031, 0x02032, 0x02033, 0x02034, 0x02035, 0x02036, 0x02037,
+ 0x02038, 0x02039, 0x0203a, 0x0203b, 0x0203c, 0x0203d, 0x0203e, 0x0203f,
+ 0x02040, 0x02041, 0x02042, 0x02043, 0x02044, 0x02045, 0x02046, 0x02047,
+ 0x02048, 0x02049, 0x0204a, 0x0204b, 0x0204c, 0x0204d, 0x0204e, 0x0204f,
+ 0x02050, 0x02051, 0x02052, 0x02053, 0x02054, 0x02055, 0x02056, 0x02057,
+ 0x02058, 0x02059, 0x0205a, 0x0205b, 0x0205c, 0x0205d, 0x0205e, 0x00020,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x02064, 0x02065, 0x02066, 0x02067,
+ 0x02068, 0x02069, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00030, 0x00049, 0x02072, 0x02073, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0004e,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0002b, 0x0207b, 0x0003d, 0x00028, 0x00029, 0x0208f,
+ 0x02090, 0x02091, 0x02092, 0x02093, 0x02094, 0x02095, 0x02096, 0x02097,
+ 0x02098, 0x02099, 0x0209a, 0x0209b, 0x0209c, 0x0209d, 0x0209e, 0x0209f,
+ 0x020a0, 0x020a1, 0x020a2, 0x020a3, 0x020a4, 0x020a5, 0x020a6, 0x020a7,
+ 0x020a8, 0x020a9, 0x020aa, 0x020ab, 0x020ac, 0x020ad, 0x020ae, 0x020af,
+ 0x020b0, 0x020b1, 0x020b2, 0x020b3, 0x020b4, 0x020b5, 0x020b6, 0x020b7,
+ 0x020b8, 0x020b9, 0x020ba, 0x020bb, 0x020bc, 0x020bd, 0x020be, 0x020bf,
+ 0x020c0, 0x020c1, 0x020c2, 0x020c3, 0x020c4, 0x020c5, 0x020c6, 0x020c7,
+ 0x020c8, 0x020c9, 0x020ca, 0x020cb, 0x020cc, 0x020cd, 0x020ce, 0x020cf,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x020eb, 0x020ec, 0x020ed, 0x020ee, 0x020ef,
+ 0x020f0, 0x020f1, 0x020f2, 0x020f3, 0x020f4, 0x020f5, 0x020f6, 0x020f7,
+ 0x020f8, 0x020f9, 0x020fa, 0x020fb, 0x020fc, 0x020fd, 0x020fe, 0x020ff
+};
+
+static uint32_t unicode_ci_page_21[] = {
+ 0x02100, 0x02101, 0x00043, 0x02103, 0x02104, 0x02105, 0x02106, 0x00190,
+ 0x02108, 0x02109, 0x00047, 0x00048, 0x00048, 0x00048, 0x00048, 0x00126,
+ 0x00049, 0x00049, 0x0004c, 0x0004c, 0x02114, 0x0004e, 0x02116, 0x02117,
+ 0x02118, 0x00050, 0x00051, 0x00052, 0x00052, 0x00052, 0x0211e, 0x0211f,
+ 0x02120, 0x02121, 0x02122, 0x02123, 0x0005a, 0x02125, 0x003a9, 0x02127,
+ 0x0005a, 0x02129, 0x0004b, 0x00041, 0x00042, 0x00043, 0x0212e, 0x00045,
+ 0x00045, 0x00046, 0x02132, 0x0004d, 0x0004f, 0x005d0, 0x005d1, 0x005d2,
+ 0x005d3, 0x00049, 0x0213a, 0x0213b, 0x0213c, 0x00393, 0x00393, 0x003a0,
+ 0x02140, 0x02141, 0x02142, 0x02143, 0x02144, 0x00044, 0x00044, 0x00045,
+ 0x00049, 0x0004a, 0x0214a, 0x0214b, 0x0214c, 0x0214d, 0x0214e, 0x0214f,
+ 0x02150, 0x02151, 0x02152, 0x02153, 0x02154, 0x02155, 0x02156, 0x02157,
+ 0x02158, 0x02159, 0x0215a, 0x0215b, 0x0215c, 0x0215d, 0x0215e, 0x0215f,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x00049, 0x02161, 0x02162, 0x02163, 0x00056, 0x02165, 0x02166, 0x02167,
+ 0x02168, 0x00058, 0x0216a, 0x0216b, 0x0004c, 0x00043, 0x00044, 0x0004d,
+ 0x02180, 0x02181, 0x02182, 0x02183, 0x02184, 0x02185, 0x02186, 0x02187,
+ 0x02188, 0x02189, 0x0218a, 0x0218b, 0x0218c, 0x0218d, 0x0218e, 0x0218f,
+ 0x02190, 0x02191, 0x02192, 0x02193, 0x02194, 0x02195, 0x02196, 0x02197,
+ 0x02198, 0x02199, 0x02190, 0x02192, 0x0219c, 0x0219d, 0x0219e, 0x0219f,
+ 0x021a0, 0x021a1, 0x021a2, 0x021a3, 0x021a4, 0x021a5, 0x021a6, 0x021a7,
+ 0x021a8, 0x021a9, 0x021aa, 0x021ab, 0x021ac, 0x021ad, 0x02194, 0x021af,
+ 0x021b0, 0x021b1, 0x021b2, 0x021b3, 0x021b4, 0x021b5, 0x021b6, 0x021b7,
+ 0x021b8, 0x021b9, 0x021ba, 0x021bb, 0x021bc, 0x021bd, 0x021be, 0x021bf,
+ 0x021c0, 0x021c1, 0x021c2, 0x021c3, 0x021c4, 0x021c5, 0x021c6, 0x021c7,
+ 0x021c8, 0x021c9, 0x021ca, 0x021cb, 0x021cc, 0x021cd, 0x021ce, 0x021cf,
+ 0x021cd, 0x021d1, 0x021cf, 0x021d3, 0x021ce, 0x021d5, 0x021d6, 0x021d7,
+ 0x021d8, 0x021d9, 0x021da, 0x021db, 0x021dc, 0x021dd, 0x021de, 0x021df,
+ 0x021e0, 0x021e1, 0x021e2, 0x021e3, 0x021e4, 0x021e5, 0x021e6, 0x021e7,
+ 0x021e8, 0x021e9, 0x021ea, 0x021eb, 0x021ec, 0x021ed, 0x021ee, 0x021ef,
+ 0x021f0, 0x021f1, 0x021f2, 0x021f3, 0x021f4, 0x021f5, 0x021f6, 0x021f7,
+ 0x021f8, 0x021f9, 0x021fa, 0x021fb, 0x021fc, 0x021fd, 0x021fe, 0x021ff
+};
+
+static uint32_t unicode_ci_page_22[] = {
+ 0x02200, 0x02201, 0x02202, 0x02203, 0x02203, 0x02205, 0x02206, 0x02207,
+ 0x02208, 0x02208, 0x0220a, 0x0220b, 0x0220b, 0x0220d, 0x0220e, 0x0220f,
+ 0x02210, 0x02140, 0x0207b, 0x02213, 0x02214, 0x02215, 0x02216, 0x02217,
+ 0x02218, 0x02219, 0x0221a, 0x0221b, 0x0221c, 0x0221d, 0x0221e, 0x0221f,
+ 0x02220, 0x02221, 0x02222, 0x02223, 0x02223, 0x02225, 0x02225, 0x02227,
+ 0x02228, 0x02229, 0x0222a, 0x0222b, 0x0222c, 0x0222d, 0x0222e, 0x0222f,
+ 0x02230, 0x02231, 0x02232, 0x02233, 0x02234, 0x02235, 0x02236, 0x02237,
+ 0x02238, 0x02239, 0x0223a, 0x0223b, 0x0223c, 0x0223d, 0x0223e, 0x0223f,
+ 0x02240, 0x0223c, 0x02242, 0x02243, 0x02243, 0x02245, 0x02246, 0x02245,
+ 0x02248, 0x02248, 0x0224a, 0x0224b, 0x0224c, 0x0224d, 0x0224e, 0x0224f,
+ 0x02250, 0x02251, 0x02252, 0x02253, 0x02254, 0x02255, 0x02256, 0x02257,
+ 0x02258, 0x02259, 0x0225a, 0x0225b, 0x0225c, 0x0225d, 0x0225e, 0x0225f,
+ 0x0003d, 0x02261, 0x02261, 0x02263, 0x02264, 0x02265, 0x02266, 0x02267,
+ 0x02268, 0x02269, 0x0226a, 0x0226b, 0x0226c, 0x0224d, 0x0003c, 0x0003e,
+ 0x02264, 0x02265, 0x02272, 0x02273, 0x02272, 0x02273, 0x02276, 0x02277,
+ 0x02276, 0x02277, 0x0227a, 0x0227b, 0x0227c, 0x0227d, 0x0227e, 0x0227f,
+ 0x0227a, 0x0227b, 0x02282, 0x02283, 0x02282, 0x02283, 0x02286, 0x02287,
+ 0x02286, 0x02287, 0x0228a, 0x0228b, 0x0228c, 0x0228d, 0x0228e, 0x0228f,
+ 0x02290, 0x02291, 0x02292, 0x02293, 0x02294, 0x02295, 0x02296, 0x02297,
+ 0x02298, 0x02299, 0x0229a, 0x0229b, 0x0229c, 0x0229d, 0x0229e, 0x0229f,
+ 0x022a0, 0x022a1, 0x022a2, 0x022a3, 0x022a4, 0x022a5, 0x022a6, 0x022a7,
+ 0x022a8, 0x022a9, 0x022aa, 0x022ab, 0x022a2, 0x022a8, 0x022a9, 0x022ab,
+ 0x022b0, 0x022b1, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022b6, 0x022b7,
+ 0x022b8, 0x022b9, 0x022ba, 0x022bb, 0x022bc, 0x022bd, 0x022be, 0x022bf,
+ 0x022c0, 0x022c1, 0x022c2, 0x022c3, 0x022c4, 0x022c5, 0x022c6, 0x022c7,
+ 0x022c8, 0x022c9, 0x022ca, 0x022cb, 0x022cc, 0x022cd, 0x022ce, 0x022cf,
+ 0x022d0, 0x022d1, 0x022d2, 0x022d3, 0x022d4, 0x022d5, 0x022d6, 0x022d7,
+ 0x022d8, 0x022d9, 0x022da, 0x022db, 0x022dc, 0x022dd, 0x022de, 0x022df,
+ 0x0227c, 0x0227d, 0x02291, 0x02292, 0x022e4, 0x022e5, 0x022e6, 0x022e7,
+ 0x022e8, 0x022e9, 0x022b2, 0x022b3, 0x022b4, 0x022b5, 0x022ee, 0x022ef,
+ 0x022f0, 0x022f1, 0x022f2, 0x022f3, 0x022f4, 0x022f5, 0x022f6, 0x022f7,
+ 0x022f8, 0x022f9, 0x022fa, 0x022fb, 0x022fc, 0x022fd, 0x022fe, 0x022ff
+};
+
+static uint32_t unicode_ci_page_24[] = {
+ 0x02400, 0x02401, 0x02402, 0x02403, 0x02404, 0x02405, 0x02406, 0x02407,
+ 0x02408, 0x02409, 0x0240a, 0x0240b, 0x0240c, 0x0240d, 0x0240e, 0x0240f,
+ 0x02410, 0x02411, 0x02412, 0x02413, 0x02414, 0x02415, 0x02416, 0x02417,
+ 0x02418, 0x02419, 0x0241a, 0x0241b, 0x0241c, 0x0241d, 0x0241e, 0x0241f,
+ 0x02420, 0x02421, 0x02422, 0x02423, 0x02424, 0x02425, 0x02426, 0x02427,
+ 0x02428, 0x02429, 0x0242a, 0x0242b, 0x0242c, 0x0242d, 0x0242e, 0x0242f,
+ 0x02430, 0x02431, 0x02432, 0x02433, 0x02434, 0x02435, 0x02436, 0x02437,
+ 0x02438, 0x02439, 0x0243a, 0x0243b, 0x0243c, 0x0243d, 0x0243e, 0x0243f,
+ 0x02440, 0x02441, 0x02442, 0x02443, 0x02444, 0x02445, 0x02446, 0x02447,
+ 0x02448, 0x02449, 0x0244a, 0x0244b, 0x0244c, 0x0244d, 0x0244e, 0x0244f,
+ 0x02450, 0x02451, 0x02452, 0x02453, 0x02454, 0x02455, 0x02456, 0x02457,
+ 0x02458, 0x02459, 0x0245a, 0x0245b, 0x0245c, 0x0245d, 0x0245e, 0x0245f,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e, 0x0246f,
+ 0x02470, 0x02471, 0x02472, 0x02473, 0x02474, 0x02475, 0x02476, 0x02477,
+ 0x02478, 0x02479, 0x0247a, 0x0247b, 0x0247c, 0x0247d, 0x0247e, 0x0247f,
+ 0x02480, 0x02481, 0x02482, 0x02483, 0x02484, 0x02485, 0x02486, 0x02487,
+ 0x02488, 0x02489, 0x0248a, 0x0248b, 0x0248c, 0x0248d, 0x0248e, 0x0248f,
+ 0x02490, 0x02491, 0x02492, 0x02493, 0x02494, 0x02495, 0x02496, 0x02497,
+ 0x02498, 0x02499, 0x0249a, 0x0249b, 0x0249c, 0x0249d, 0x0249e, 0x0249f,
+ 0x024a0, 0x024a1, 0x024a2, 0x024a3, 0x024a4, 0x024a5, 0x024a6, 0x024a7,
+ 0x024a8, 0x024a9, 0x024aa, 0x024ab, 0x024ac, 0x024ad, 0x024ae, 0x024af,
+ 0x024b0, 0x024b1, 0x024b2, 0x024b3, 0x024b4, 0x024b5, 0x00041, 0x00042,
+ 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048, 0x00049, 0x0004a,
+ 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050, 0x00051, 0x00052,
+ 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058, 0x00059, 0x0005a,
+ 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047, 0x00048,
+ 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f, 0x00050,
+ 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057, 0x00058,
+ 0x00059, 0x0005a, 0x00030, 0x0246a, 0x0246b, 0x0246c, 0x0246d, 0x0246e,
+ 0x0246f, 0x02470, 0x02471, 0x02472, 0x02473, 0x00031, 0x00032, 0x00033,
+ 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469, 0x00030
+};
+
+static uint32_t unicode_ci_page_27[] = {
+ 0x02700, 0x02701, 0x02702, 0x02703, 0x02704, 0x02705, 0x02706, 0x02707,
+ 0x02708, 0x02709, 0x0270a, 0x0270b, 0x0270c, 0x0270d, 0x0270e, 0x0270f,
+ 0x02710, 0x02711, 0x02712, 0x02713, 0x02714, 0x02715, 0x02716, 0x02717,
+ 0x02718, 0x02719, 0x0271a, 0x0271b, 0x0271c, 0x0271d, 0x0271e, 0x0271f,
+ 0x02720, 0x02721, 0x02722, 0x02723, 0x02724, 0x02725, 0x02726, 0x02727,
+ 0x02728, 0x02729, 0x0272a, 0x0272b, 0x0272c, 0x0272d, 0x0272e, 0x0272f,
+ 0x02730, 0x02731, 0x02732, 0x02733, 0x02734, 0x02735, 0x02736, 0x02737,
+ 0x02738, 0x02739, 0x0273a, 0x0273b, 0x0273c, 0x0273d, 0x0273e, 0x0273f,
+ 0x02740, 0x02741, 0x02742, 0x02743, 0x02744, 0x02745, 0x02746, 0x02747,
+ 0x02748, 0x02749, 0x0274a, 0x0274b, 0x0274c, 0x0274d, 0x0274e, 0x0274f,
+ 0x02750, 0x02751, 0x02752, 0x02753, 0x02754, 0x02755, 0x02756, 0x02757,
+ 0x02758, 0x02759, 0x0275a, 0x0275b, 0x0275c, 0x0275d, 0x0275e, 0x0275f,
+ 0x02760, 0x02761, 0x02762, 0x02763, 0x02764, 0x02765, 0x02766, 0x02767,
+ 0x02768, 0x02769, 0x0276a, 0x0276b, 0x0276c, 0x0276d, 0x0276e, 0x0276f,
+ 0x02770, 0x02771, 0x02772, 0x02773, 0x02774, 0x02775, 0x00031, 0x00032,
+ 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038, 0x00039, 0x02469,
+ 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037, 0x00038,
+ 0x00039, 0x02469, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036,
+ 0x00037, 0x00038, 0x00039, 0x02469, 0x02794, 0x02795, 0x02796, 0x02797,
+ 0x02798, 0x02799, 0x0279a, 0x0279b, 0x0279c, 0x0279d, 0x0279e, 0x0279f,
+ 0x027a0, 0x027a1, 0x027a2, 0x027a3, 0x027a4, 0x027a5, 0x027a6, 0x027a7,
+ 0x027a8, 0x027a9, 0x027aa, 0x027ab, 0x027ac, 0x027ad, 0x027ae, 0x027af,
+ 0x027b0, 0x027b1, 0x027b2, 0x027b3, 0x027b4, 0x027b5, 0x027b6, 0x027b7,
+ 0x027b8, 0x027b9, 0x027ba, 0x027bb, 0x027bc, 0x027bd, 0x027be, 0x027bf,
+ 0x027c0, 0x027c1, 0x027c2, 0x027c3, 0x027c4, 0x027c5, 0x027c6, 0x027c7,
+ 0x027c8, 0x027c9, 0x027ca, 0x027cb, 0x027cc, 0x027cd, 0x027ce, 0x027cf,
+ 0x027d0, 0x027d1, 0x027d2, 0x027d3, 0x027d4, 0x027d5, 0x027d6, 0x027d7,
+ 0x027d8, 0x027d9, 0x027da, 0x027db, 0x027dc, 0x027dd, 0x027de, 0x027df,
+ 0x027e0, 0x027e1, 0x027e2, 0x027e3, 0x027e4, 0x027e5, 0x027e6, 0x027e7,
+ 0x027e8, 0x027e9, 0x027ea, 0x027eb, 0x027ec, 0x027ed, 0x027ee, 0x027ef,
+ 0x027f0, 0x027f1, 0x027f2, 0x027f3, 0x027f4, 0x027f5, 0x027f6, 0x027f7,
+ 0x027f8, 0x027f9, 0x027fa, 0x027fb, 0x027fc, 0x027fd, 0x027fe, 0x027ff
+};
+
+static uint32_t unicode_ci_page_2a[] = {
+ 0x02a00, 0x02a01, 0x02a02, 0x02a03, 0x02a04, 0x02a05, 0x02a06, 0x02a07,
+ 0x02a08, 0x02a09, 0x02a0a, 0x02a0b, 0x02a0c, 0x02a0d, 0x02a0e, 0x02a0f,
+ 0x02a10, 0x02a11, 0x02a12, 0x02a13, 0x02a14, 0x02a15, 0x02a16, 0x02a17,
+ 0x02a18, 0x02a19, 0x02a1a, 0x02a1b, 0x02a1c, 0x02a1d, 0x02a1e, 0x02a1f,
+ 0x02a20, 0x02a21, 0x02a22, 0x02a23, 0x02a24, 0x02a25, 0x02a26, 0x02a27,
+ 0x02a28, 0x02a29, 0x02a2a, 0x02a2b, 0x02a2c, 0x02a2d, 0x02a2e, 0x02a2f,
+ 0x02a30, 0x02a31, 0x02a32, 0x02a33, 0x02a34, 0x02a35, 0x02a36, 0x02a37,
+ 0x02a38, 0x02a39, 0x02a3a, 0x02a3b, 0x02a3c, 0x02a3d, 0x02a3e, 0x02a3f,
+ 0x02a40, 0x02a41, 0x02a42, 0x02a43, 0x02a44, 0x02a45, 0x02a46, 0x02a47,
+ 0x02a48, 0x02a49, 0x02a4a, 0x02a4b, 0x02a4c, 0x02a4d, 0x02a4e, 0x02a4f,
+ 0x02a50, 0x02a51, 0x02a52, 0x02a53, 0x02a54, 0x02a55, 0x02a56, 0x02a57,
+ 0x02a58, 0x02a59, 0x02a5a, 0x02a5b, 0x02a5c, 0x02a5d, 0x02a5e, 0x02a5f,
+ 0x02a60, 0x02a61, 0x02a62, 0x02a63, 0x02a64, 0x02a65, 0x02a66, 0x02a67,
+ 0x02a68, 0x02a69, 0x02a6a, 0x02a6b, 0x02a6c, 0x02a6d, 0x02a6e, 0x02a6f,
+ 0x02a70, 0x02a71, 0x02a72, 0x02a73, 0x02a74, 0x02a75, 0x02a76, 0x02a77,
+ 0x02a78, 0x02a79, 0x02a7a, 0x02a7b, 0x02a7c, 0x02a7d, 0x02a7e, 0x02a7f,
+ 0x02a80, 0x02a81, 0x02a82, 0x02a83, 0x02a84, 0x02a85, 0x02a86, 0x02a87,
+ 0x02a88, 0x02a89, 0x02a8a, 0x02a8b, 0x02a8c, 0x02a8d, 0x02a8e, 0x02a8f,
+ 0x02a90, 0x02a91, 0x02a92, 0x02a93, 0x02a94, 0x02a95, 0x02a96, 0x02a97,
+ 0x02a98, 0x02a99, 0x02a9a, 0x02a9b, 0x02a9c, 0x02a9d, 0x02a9e, 0x02a9f,
+ 0x02aa0, 0x02aa1, 0x02aa2, 0x02aa3, 0x02aa4, 0x02aa5, 0x02aa6, 0x02aa7,
+ 0x02aa8, 0x02aa9, 0x02aaa, 0x02aab, 0x02aac, 0x02aad, 0x02aae, 0x02aaf,
+ 0x02ab0, 0x02ab1, 0x02ab2, 0x02ab3, 0x02ab4, 0x02ab5, 0x02ab6, 0x02ab7,
+ 0x02ab8, 0x02ab9, 0x02aba, 0x02abb, 0x02abc, 0x02abd, 0x02abe, 0x02abf,
+ 0x02ac0, 0x02ac1, 0x02ac2, 0x02ac3, 0x02ac4, 0x02ac5, 0x02ac6, 0x02ac7,
+ 0x02ac8, 0x02ac9, 0x02aca, 0x02acb, 0x02acc, 0x02acd, 0x02ace, 0x02acf,
+ 0x02ad0, 0x02ad1, 0x02ad2, 0x02ad3, 0x02ad4, 0x02ad5, 0x02ad6, 0x02ad7,
+ 0x02ad8, 0x02ad9, 0x02ada, 0x02adb, 0x02adc, 0x02adc, 0x02ade, 0x02adf,
+ 0x02ae0, 0x02ae1, 0x02ae2, 0x02ae3, 0x02ae4, 0x02ae5, 0x02ae6, 0x02ae7,
+ 0x02ae8, 0x02ae9, 0x02aea, 0x02aeb, 0x02aec, 0x02aed, 0x02aee, 0x02aef,
+ 0x02af0, 0x02af1, 0x02af2, 0x02af3, 0x02af4, 0x02af5, 0x02af6, 0x02af7,
+ 0x02af8, 0x02af9, 0x02afa, 0x02afb, 0x02afc, 0x02afd, 0x02afe, 0x02aff
+};
+
+static uint32_t unicode_ci_page_2e[] = {
+ 0x02e00, 0x02e01, 0x02e02, 0x02e03, 0x02e04, 0x02e05, 0x02e06, 0x02e07,
+ 0x02e08, 0x02e09, 0x02e0a, 0x02e0b, 0x02e0c, 0x02e0d, 0x02e0e, 0x02e0f,
+ 0x02e10, 0x02e11, 0x02e12, 0x02e13, 0x02e14, 0x02e15, 0x02e16, 0x02e17,
+ 0x02e18, 0x02e19, 0x02e1a, 0x02e1b, 0x02e1c, 0x02e1d, 0x02e1e, 0x02e1f,
+ 0x02e20, 0x02e21, 0x02e22, 0x02e23, 0x02e24, 0x02e25, 0x02e26, 0x02e27,
+ 0x02e28, 0x02e29, 0x02e2a, 0x02e2b, 0x02e2c, 0x02e2d, 0x02e2e, 0x02e2f,
+ 0x02e30, 0x02e31, 0x02e32, 0x02e33, 0x02e34, 0x02e35, 0x02e36, 0x02e37,
+ 0x02e38, 0x02e39, 0x02e3a, 0x02e3b, 0x02e3c, 0x02e3d, 0x02e3e, 0x02e3f,
+ 0x02e40, 0x02e41, 0x02e42, 0x02e43, 0x02e44, 0x02e45, 0x02e46, 0x02e47,
+ 0x02e48, 0x02e49, 0x02e4a, 0x02e4b, 0x02e4c, 0x02e4d, 0x02e4e, 0x02e4f,
+ 0x02e50, 0x02e51, 0x02e52, 0x02e53, 0x02e54, 0x02e55, 0x02e56, 0x02e57,
+ 0x02e58, 0x02e59, 0x02e5a, 0x02e5b, 0x02e5c, 0x02e5d, 0x02e5e, 0x02e5f,
+ 0x02e60, 0x02e61, 0x02e62, 0x02e63, 0x02e64, 0x02e65, 0x02e66, 0x02e67,
+ 0x02e68, 0x02e69, 0x02e6a, 0x02e6b, 0x02e6c, 0x02e6d, 0x02e6e, 0x02e6f,
+ 0x02e70, 0x02e71, 0x02e72, 0x02e73, 0x02e74, 0x02e75, 0x02e76, 0x02e77,
+ 0x02e78, 0x02e79, 0x02e7a, 0x02e7b, 0x02e7c, 0x02e7d, 0x02e7e, 0x02e7f,
+ 0x02e80, 0x02e81, 0x02e82, 0x02e83, 0x0319a, 0x02e85, 0x02e86, 0x02f0f,
+ 0x02f11, 0x02e89, 0x02f18, 0x02e8b, 0x02f29, 0x02f29, 0x02e8e, 0x02e8f,
+ 0x02e8e, 0x02e8f, 0x02e92, 0x02e93, 0x02e94, 0x02e95, 0x02e96, 0x02f3c,
+ 0x02e98, 0x02e99, 0x02e9a, 0x02e9b, 0x02f47, 0x02f49, 0x02e9e, 0x02e9f,
+ 0x02ea0, 0x02ea1, 0x02ea2, 0x02ea3, 0x02ea4, 0x02ea4, 0x02ea6, 0x02f5c,
+ 0x02ea8, 0x02ea9, 0x02eaa, 0x02f6c, 0x02f70, 0x02ead, 0x02f75, 0x02eaf,
+ 0x02eb0, 0x02eb1, 0x02eb2, 0x02eb1, 0x02eb1, 0x02eb2, 0x02eb7, 0x02eb7,
+ 0x02eb8, 0x02eb9, 0x02eba, 0x02f80, 0x02f81, 0x02f85, 0x02ebe, 0x02ebe,
+ 0x02ebe, 0x02ec1, 0x02ec2, 0x02ec3, 0x02ec4, 0x02ec5, 0x02f93, 0x02f93,
+ 0x02ec8, 0x02ec9, 0x02f9c, 0x02ecb, 0x02ecc, 0x02ecc, 0x02ecc, 0x02fa2,
+ 0x02ed0, 0x02fa7, 0x02ed2, 0x02ed3, 0x02ed4, 0x02fa9, 0x02ed6, 0x02fac,
+ 0x02ed8, 0x02ed9, 0x02eda, 0x02edb, 0x02edc, 0x02fb7, 0x02ede, 0x02ede,
+ 0x02ee0, 0x02fb8, 0x02ee2, 0x02fbb, 0x02fc1, 0x02ee5, 0x02ee6, 0x02ee7,
+ 0x02ee8, 0x02ee9, 0x02eea, 0x02eeb, 0x02eec, 0x02eed, 0x02eee, 0x02eef,
+ 0x02ef0, 0x02ef2, 0x02ef2, 0x02ef3, 0x02ef4, 0x02ef5, 0x02ef6, 0x02ef7,
+ 0x02ef8, 0x02ef9, 0x02efa, 0x02efb, 0x02efc, 0x02efd, 0x02efe, 0x02eff
+};
+
+static uint32_t unicode_ci_page_2f[] = {
+ 0x03192, 0x02f01, 0x02e80, 0x02f03, 0x0319a, 0x02f05, 0x03193, 0x02f07,
+ 0x0319f, 0x02f09, 0x02f0a, 0x02f0b, 0x02e86, 0x02f0d, 0x02f0e, 0x02f0f,
+ 0x02f10, 0x02f11, 0x02f12, 0x02f13, 0x02f14, 0x02f15, 0x02f16, 0x02f17,
+ 0x02f18, 0x02e8b, 0x02e81, 0x02f1b, 0x02f1c, 0x02f1d, 0x02f1e, 0x02f1f,
+ 0x02f20, 0x02f21, 0x02f22, 0x02f23, 0x02f24, 0x02f25, 0x02f26, 0x02f27,
+ 0x02f28, 0x02f29, 0x02e8e, 0x02f2b, 0x02f2c, 0x02f2d, 0x02f2e, 0x02f2f,
+ 0x02f30, 0x02f31, 0x02f32, 0x02e93, 0x02f34, 0x02f35, 0x02f36, 0x02f37,
+ 0x02f38, 0x02e95, 0x02f3a, 0x02f3b, 0x02f3c, 0x02f3d, 0x02f3e, 0x02f3f,
+ 0x02f40, 0x02f41, 0x02f42, 0x02f43, 0x02f44, 0x02f45, 0x02f46, 0x02f47,
+ 0x02f48, 0x02f49, 0x02f4a, 0x02f4b, 0x02f4c, 0x02f4d, 0x02f4e, 0x02f4f,
+ 0x02f50, 0x02f51, 0x02f52, 0x02f53, 0x02f54, 0x02f55, 0x02f56, 0x02f57,
+ 0x02f58, 0x02f59, 0x02f5a, 0x02f5b, 0x02f5c, 0x02f5d, 0x02f5e, 0x02f5f,
+ 0x02f60, 0x02f61, 0x02f62, 0x02f63, 0x02f64, 0x02f65, 0x02eaa, 0x02f67,
+ 0x02f68, 0x02f69, 0x02f6a, 0x02f6b, 0x02f6c, 0x02f6d, 0x02f6e, 0x02f6f,
+ 0x02f70, 0x02f71, 0x02f72, 0x02f73, 0x02f74, 0x02f75, 0x02f76, 0x02f77,
+ 0x02f78, 0x02f79, 0x02eb7, 0x02f7b, 0x02f7c, 0x02f7d, 0x02f7e, 0x02f7f,
+ 0x02f80, 0x02f81, 0x02f82, 0x02f83, 0x02f84, 0x02f85, 0x02f86, 0x02f87,
+ 0x02f88, 0x02f89, 0x02f8a, 0x02f8b, 0x02f8c, 0x02f8d, 0x02f8e, 0x02f8f,
+ 0x02f90, 0x02f91, 0x02f92, 0x02f93, 0x02f94, 0x02f95, 0x02f96, 0x02f97,
+ 0x02f98, 0x02f99, 0x02f9a, 0x02f9b, 0x02f9c, 0x02f9d, 0x02f9e, 0x02f9f,
+ 0x02fa0, 0x02fa1, 0x02fa2, 0x02fa3, 0x02fa4, 0x02fa5, 0x02fa6, 0x02fa7,
+ 0x02fa8, 0x02fa9, 0x02faa, 0x02fab, 0x02fac, 0x02fad, 0x02fae, 0x02faf,
+ 0x02fb0, 0x02fb1, 0x02fb2, 0x02fb3, 0x02fb4, 0x02fb5, 0x02fb6, 0x02fb7,
+ 0x02fb8, 0x02fb9, 0x02fba, 0x02fbb, 0x02fbc, 0x02fbd, 0x02fbe, 0x02fbf,
+ 0x02fc0, 0x02fc1, 0x02fc2, 0x02fc3, 0x02ee7, 0x02fc5, 0x02fc6, 0x02fc7,
+ 0x02fc8, 0x02fc9, 0x02fca, 0x02fcb, 0x02fcc, 0x02fcd, 0x02fce, 0x02fcf,
+ 0x02fd0, 0x02eeb, 0x02eed, 0x02eef, 0x02ef2, 0x02fd5, 0x02fd6, 0x02fd7,
+ 0x02fd8, 0x02fd9, 0x02fda, 0x02fdb, 0x02fdc, 0x02fdd, 0x02fde, 0x02fdf,
+ 0x02fe0, 0x02fe1, 0x02fe2, 0x02fe3, 0x02fe4, 0x02fe5, 0x02fe6, 0x02fe7,
+ 0x02fe8, 0x02fe9, 0x02fea, 0x02feb, 0x02fec, 0x02fed, 0x02fee, 0x02fef,
+ 0x02ff0, 0x02ff1, 0x02ff2, 0x02ff3, 0x02ff4, 0x02ff5, 0x02ff6, 0x02ff7,
+ 0x02ff8, 0x02ff9, 0x02ffa, 0x02ffb, 0x02ffc, 0x02ffd, 0x02ffe, 0x02fff
+};
+
+static uint32_t unicode_ci_page_30[] = {
+ 0x00020, 0x03001, 0x03002, 0x03003, 0x03004, 0x03005, 0x03006, 0x00030,
+ 0x02329, 0x0232a, 0x0300a, 0x0300b, 0x0300c, 0x0300d, 0x0300e, 0x0300f,
+ 0x03010, 0x03011, 0x03012, 0x03013, 0x03014, 0x03015, 0x03016, 0x03017,
+ 0x03018, 0x03019, 0x0301a, 0x0301b, 0x0301c, 0x0301d, 0x0301e, 0x0301f,
+ 0x03020, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x03030, 0x03031, 0x03031, 0x03033, 0x03033, 0x03035, 0x03012, 0x03037,
+ 0x02f17, 0x03039, 0x0303a, 0x0303b, 0x0303c, 0x0303d, 0x0303e, 0x0303f,
+ 0x03040, 0x03042, 0x03042, 0x03044, 0x03044, 0x03046, 0x03046, 0x03048,
+ 0x03048, 0x0304a, 0x0304a, 0x0304b, 0x0304b, 0x0304d, 0x0304d, 0x0304f,
+ 0x0304f, 0x03051, 0x03051, 0x03053, 0x03053, 0x03055, 0x03055, 0x03057,
+ 0x03057, 0x03059, 0x03059, 0x0305b, 0x0305b, 0x0305d, 0x0305d, 0x0305f,
+ 0x0305f, 0x03061, 0x03061, 0x03064, 0x03064, 0x03064, 0x03066, 0x03066,
+ 0x03068, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x0306f, 0x0306f, 0x03072, 0x03072, 0x03072, 0x03075, 0x03075, 0x03075,
+ 0x03078, 0x03078, 0x03078, 0x0307b, 0x0307b, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03084, 0x03086, 0x03086, 0x03088,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x03097,
+ 0x03098, 0x00000, 0x00000, 0x0309b, 0x0309c, 0x0309d, 0x0309d, 0x0309f,
+ 0x030a0, 0x03042, 0x03042, 0x03044, 0x03044, 0x03046, 0x03046, 0x03048,
+ 0x03048, 0x0304a, 0x0304a, 0x0304b, 0x0304b, 0x0304d, 0x0304d, 0x0304f,
+ 0x0304f, 0x03051, 0x03051, 0x03053, 0x03053, 0x03055, 0x03055, 0x03057,
+ 0x03057, 0x03059, 0x03059, 0x0305b, 0x0305b, 0x0305d, 0x0305d, 0x0305f,
+ 0x0305f, 0x03061, 0x03061, 0x03064, 0x03064, 0x03064, 0x03066, 0x03066,
+ 0x03068, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d, 0x0306e, 0x0306f,
+ 0x0306f, 0x0306f, 0x03072, 0x03072, 0x03072, 0x03075, 0x03075, 0x03075,
+ 0x03078, 0x03078, 0x03078, 0x0307b, 0x0307b, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03084, 0x03086, 0x03086, 0x03088,
+ 0x03088, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x03093, 0x03046, 0x0304b, 0x03051, 0x0308f,
+ 0x03090, 0x03091, 0x03092, 0x030fb, 0x030fc, 0x030fd, 0x030fd, 0x030ff
+};
+
+static uint32_t unicode_ci_page_31[] = {
+ 0x03100, 0x03101, 0x03102, 0x03103, 0x03104, 0x03105, 0x03106, 0x03107,
+ 0x03108, 0x03109, 0x0310a, 0x0310b, 0x0310c, 0x0310d, 0x0310e, 0x0310f,
+ 0x03110, 0x03111, 0x03112, 0x03113, 0x03114, 0x03115, 0x03116, 0x03117,
+ 0x03118, 0x03119, 0x0311a, 0x0311b, 0x0311c, 0x0311d, 0x0311e, 0x0311f,
+ 0x03120, 0x03121, 0x03122, 0x03123, 0x03124, 0x03125, 0x03126, 0x03127,
+ 0x03128, 0x03129, 0x0312a, 0x0312b, 0x0312c, 0x0312d, 0x0312e, 0x0312f,
+ 0x03130, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x01161,
+ 0x01162, 0x01163, 0x01164, 0x01165, 0x01166, 0x01167, 0x01168, 0x01169,
+ 0x0116a, 0x0116b, 0x0116c, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171,
+ 0x01172, 0x01173, 0x01174, 0x01175, 0x01160, 0x01114, 0x01115, 0x011c7,
+ 0x011c8, 0x011cc, 0x011ce, 0x011d3, 0x011d7, 0x011d9, 0x0111c, 0x011dd,
+ 0x011df, 0x0111d, 0x0111e, 0x01120, 0x01122, 0x01123, 0x01127, 0x01129,
+ 0x0112b, 0x0112c, 0x0112d, 0x0112e, 0x0112f, 0x01132, 0x01136, 0x01140,
+ 0x01147, 0x0114c, 0x011f1, 0x011f2, 0x01157, 0x01158, 0x01159, 0x01184,
+ 0x01185, 0x01188, 0x01191, 0x01192, 0x01194, 0x0119e, 0x011a1, 0x0318f,
+ 0x03190, 0x03191, 0x03192, 0x03193, 0x03194, 0x03195, 0x03196, 0x03197,
+ 0x03198, 0x03199, 0x0319a, 0x0319b, 0x0319c, 0x0319d, 0x0319e, 0x0319f,
+ 0x03105, 0x03117, 0x03110, 0x0310d, 0x031a4, 0x031a4, 0x031a6, 0x0311b,
+ 0x03128, 0x0311a, 0x03127, 0x03128, 0x031ac, 0x031ad, 0x0311e, 0x03120,
+ 0x031b0, 0x031b1, 0x031b2, 0x03127, 0x03106, 0x0310a, 0x0310e, 0x0310f,
+ 0x031b8, 0x031b9, 0x031ba, 0x031bb, 0x031bc, 0x031bd, 0x031be, 0x031bf,
+ 0x031c0, 0x031c1, 0x031c2, 0x031c3, 0x031c4, 0x031c5, 0x031c6, 0x031c7,
+ 0x031c8, 0x031c9, 0x031ca, 0x031cb, 0x031cc, 0x031cd, 0x031ce, 0x031cf,
+ 0x031d0, 0x031d1, 0x031d2, 0x031d3, 0x031d4, 0x031d5, 0x031d6, 0x031d7,
+ 0x031d8, 0x031d9, 0x031da, 0x031db, 0x031dc, 0x031dd, 0x031de, 0x031df,
+ 0x031e0, 0x031e1, 0x031e2, 0x031e3, 0x031e4, 0x031e5, 0x031e6, 0x031e7,
+ 0x031e8, 0x031e9, 0x031ea, 0x031eb, 0x031ec, 0x031ed, 0x031ee, 0x031ef,
+ 0x0304f, 0x03057, 0x03059, 0x03068, 0x0306c, 0x0306f, 0x03072, 0x03075,
+ 0x03078, 0x0307b, 0x03080, 0x03089, 0x0308a, 0x0308b, 0x0308c, 0x031ff
+};
+
+static uint32_t unicode_ci_page_32[] = {
+ 0x03200, 0x03201, 0x03202, 0x03203, 0x03204, 0x03205, 0x03206, 0x03207,
+ 0x03208, 0x03209, 0x0320a, 0x0320b, 0x0320c, 0x0320d, 0x0320e, 0x0320f,
+ 0x03210, 0x03211, 0x03212, 0x03213, 0x03214, 0x03215, 0x03216, 0x03217,
+ 0x03218, 0x03219, 0x0321a, 0x0321b, 0x0321c, 0x0321d, 0x0321e, 0x0321f,
+ 0x03220, 0x03221, 0x03222, 0x03223, 0x03224, 0x03225, 0x03226, 0x03227,
+ 0x03228, 0x03229, 0x0322a, 0x0322b, 0x0322c, 0x0322d, 0x0322e, 0x0322f,
+ 0x03230, 0x03231, 0x03232, 0x03233, 0x03234, 0x03235, 0x03236, 0x03237,
+ 0x03238, 0x03239, 0x0323a, 0x0323b, 0x0323c, 0x0323d, 0x0323e, 0x0323f,
+ 0x03240, 0x03241, 0x03242, 0x03243, 0x03244, 0x03245, 0x03246, 0x03247,
+ 0x03248, 0x03249, 0x0324a, 0x0324b, 0x0324c, 0x0324d, 0x0324e, 0x0324f,
+ 0x03250, 0x03251, 0x03252, 0x03253, 0x03254, 0x03255, 0x03256, 0x03257,
+ 0x03258, 0x03259, 0x0325a, 0x0325b, 0x0325c, 0x0325d, 0x0325e, 0x0325f,
+ 0x01100, 0x01102, 0x01103, 0x01105, 0x01106, 0x01107, 0x01109, 0x0110b,
+ 0x0110c, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0326e, 0x0326f,
+ 0x03270, 0x03271, 0x03272, 0x03273, 0x03274, 0x03275, 0x03276, 0x03277,
+ 0x03278, 0x03279, 0x0327a, 0x0327b, 0x0327c, 0x0327d, 0x0327e, 0x0327f,
+ 0x03192, 0x03193, 0x03194, 0x03195, 0x03284, 0x03285, 0x03286, 0x02f0b,
+ 0x03288, 0x02f17, 0x02f49, 0x02f55, 0x02f54, 0x02f4a, 0x02fa6, 0x02f1f,
+ 0x02f47, 0x03291, 0x03292, 0x03293, 0x03294, 0x03295, 0x03296, 0x03297,
+ 0x03298, 0x03299, 0x0329a, 0x02f25, 0x0329c, 0x0329d, 0x0329e, 0x0329f,
+ 0x032a0, 0x032a1, 0x032a2, 0x032a3, 0x03196, 0x03197, 0x03198, 0x032a7,
+ 0x032a8, 0x032a9, 0x032aa, 0x032ab, 0x032ac, 0x032ad, 0x032ae, 0x032af,
+ 0x032b0, 0x032b1, 0x032b2, 0x032b3, 0x032b4, 0x032b5, 0x032b6, 0x032b7,
+ 0x032b8, 0x032b9, 0x032ba, 0x032bb, 0x032bc, 0x032bd, 0x032be, 0x032bf,
+ 0x032c0, 0x032c1, 0x032c2, 0x032c3, 0x032c4, 0x032c5, 0x032c6, 0x032c7,
+ 0x032c8, 0x032c9, 0x032ca, 0x032cb, 0x032cc, 0x032cd, 0x032ce, 0x032cf,
+ 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d, 0x0304f,
+ 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d, 0x0305f,
+ 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c, 0x0306d,
+ 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e, 0x0307f,
+ 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089, 0x0308a,
+ 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03090, 0x03091, 0x03092, 0x032ff
+};
+
+static uint32_t unicode_ci_page_33[] = {
+ 0x03300, 0x03301, 0x03302, 0x03303, 0x03304, 0x03305, 0x03306, 0x03307,
+ 0x03308, 0x03309, 0x0330a, 0x0330b, 0x0330c, 0x0330d, 0x0330e, 0x0330f,
+ 0x03310, 0x03311, 0x03312, 0x03313, 0x03314, 0x03315, 0x03316, 0x03317,
+ 0x03318, 0x03319, 0x0331a, 0x0331b, 0x0331c, 0x0331d, 0x0331e, 0x0331f,
+ 0x03320, 0x03321, 0x03322, 0x03323, 0x03324, 0x03325, 0x03326, 0x03327,
+ 0x03328, 0x03329, 0x0332a, 0x0332b, 0x0332c, 0x0332d, 0x0332e, 0x0332f,
+ 0x03330, 0x03331, 0x03332, 0x03333, 0x03334, 0x03335, 0x03336, 0x03337,
+ 0x03338, 0x03339, 0x0333a, 0x0333b, 0x0333c, 0x0333d, 0x0333e, 0x0333f,
+ 0x03340, 0x03341, 0x03342, 0x03343, 0x03344, 0x03345, 0x03346, 0x03347,
+ 0x03348, 0x03349, 0x0334a, 0x0334b, 0x0334c, 0x0334d, 0x0334e, 0x0334f,
+ 0x03350, 0x03351, 0x03352, 0x03353, 0x03354, 0x03355, 0x03356, 0x03357,
+ 0x03358, 0x03359, 0x0335a, 0x0335b, 0x0335c, 0x0335d, 0x0335e, 0x0335f,
+ 0x03360, 0x03361, 0x03362, 0x03363, 0x03364, 0x03365, 0x03366, 0x03367,
+ 0x03368, 0x03369, 0x0336a, 0x0336b, 0x0336c, 0x0336d, 0x0336e, 0x0336f,
+ 0x03370, 0x03371, 0x03372, 0x03373, 0x03374, 0x03375, 0x03376, 0x03377,
+ 0x03378, 0x03379, 0x0337a, 0x0337b, 0x0337c, 0x0337d, 0x0337e, 0x0337f,
+ 0x03380, 0x03381, 0x03382, 0x03383, 0x03384, 0x03385, 0x03386, 0x03387,
+ 0x03388, 0x03389, 0x0338a, 0x0338b, 0x0338c, 0x0338d, 0x0338e, 0x0338f,
+ 0x03390, 0x03391, 0x03392, 0x03393, 0x03394, 0x03395, 0x03396, 0x03397,
+ 0x03398, 0x03399, 0x0339a, 0x0339b, 0x0339c, 0x0339d, 0x0339e, 0x0339f,
+ 0x033a0, 0x033a1, 0x033a2, 0x033a3, 0x033a4, 0x033a5, 0x033a6, 0x033a7,
+ 0x033a8, 0x03380, 0x033aa, 0x033ab, 0x033ac, 0x033ad, 0x033ae, 0x033af,
+ 0x033b0, 0x033b1, 0x033b2, 0x033b3, 0x033b4, 0x033b5, 0x033b6, 0x033b7,
+ 0x033b8, 0x033b7, 0x033ba, 0x033bb, 0x033bc, 0x033bd, 0x033be, 0x033bd,
+ 0x033c0, 0x033c1, 0x033c2, 0x033c3, 0x033c4, 0x033c5, 0x033c6, 0x033c7,
+ 0x033c8, 0x033c9, 0x033ca, 0x033cb, 0x033cc, 0x033cd, 0x0339e, 0x033cf,
+ 0x033d0, 0x033d1, 0x033d2, 0x033d3, 0x03386, 0x033d5, 0x033d6, 0x033d7,
+ 0x033d8, 0x033d9, 0x033da, 0x033db, 0x033dc, 0x033dd, 0x033de, 0x033df,
+ 0x033e0, 0x033e1, 0x033e2, 0x033e3, 0x033e4, 0x033e5, 0x033e6, 0x033e7,
+ 0x033e8, 0x033e9, 0x033ea, 0x033eb, 0x033ec, 0x033ed, 0x033ee, 0x033ef,
+ 0x033f0, 0x033f1, 0x033f2, 0x033f3, 0x033f4, 0x033f5, 0x033f6, 0x033f7,
+ 0x033f8, 0x033f9, 0x033fa, 0x033fb, 0x033fc, 0x033fd, 0x033fe, 0x033ff
+};
+
+static uint32_t unicode_ci_page_f9[] = {
+ 0x0f900, 0x0f901, 0x02f9e, 0x0f903, 0x0f904, 0x0f905, 0x0f906, 0x02ef2,
+ 0x02ef2, 0x0f909, 0x02fa6, 0x0f90b, 0x0f90c, 0x0f90d, 0x0f90e, 0x0f90f,
+ 0x0f910, 0x0f911, 0x0f912, 0x0f913, 0x0f914, 0x0f915, 0x0f916, 0x0f917,
+ 0x0f918, 0x0f919, 0x0f91a, 0x0f91b, 0x0f91c, 0x0f91d, 0x0f91e, 0x0f91f,
+ 0x0f920, 0x0f921, 0x0f922, 0x0f923, 0x0f924, 0x0f925, 0x0f926, 0x0f927,
+ 0x0f928, 0x0f929, 0x0f92a, 0x0f92b, 0x0f92c, 0x0f92d, 0x0f92e, 0x0f92f,
+ 0x0f930, 0x0f931, 0x0f932, 0x0f933, 0x02f7c, 0x0f935, 0x0f936, 0x0f937,
+ 0x0f938, 0x0f939, 0x0f93a, 0x0f93b, 0x0f93c, 0x0f93d, 0x0f93e, 0x0f93f,
+ 0x02fc5, 0x0f941, 0x0f942, 0x0f943, 0x0f944, 0x0f945, 0x0f946, 0x0f947,
+ 0x0f948, 0x0f949, 0x0f94a, 0x0f94b, 0x0f94c, 0x0f94d, 0x0f94e, 0x0f94f,
+ 0x0f950, 0x0f951, 0x0f952, 0x0f953, 0x0f954, 0x0f955, 0x0f956, 0x0f957,
+ 0x0f958, 0x0f959, 0x0f95a, 0x0f95b, 0x0f914, 0x0f95d, 0x0f95e, 0x0f95f,
+ 0x0f960, 0x0f961, 0x0f962, 0x0f963, 0x0f964, 0x0f965, 0x0f966, 0x0f967,
+ 0x0f968, 0x0f969, 0x0f96a, 0x0f96b, 0x0f96c, 0x0f96d, 0x0f96e, 0x0f96f,
+ 0x0f970, 0x02fa0, 0x0f972, 0x0f973, 0x0f974, 0x0f975, 0x0f976, 0x0f977,
+ 0x0f978, 0x0f979, 0x0f97a, 0x0f97b, 0x0f97c, 0x0f97d, 0x0f97e, 0x0f97f,
+ 0x0f980, 0x02f25, 0x0f982, 0x0f983, 0x0f984, 0x0f985, 0x0f986, 0x0f987,
+ 0x0f988, 0x0f989, 0x02f12, 0x0f98b, 0x0f98c, 0x0f98d, 0x0f98e, 0x0f98f,
+ 0x0f990, 0x0f991, 0x0f992, 0x0f993, 0x0f994, 0x0f995, 0x0f996, 0x0f997,
+ 0x0f998, 0x0f999, 0x0f99a, 0x0f99b, 0x0f99c, 0x0f99d, 0x0f99e, 0x0f99f,
+ 0x0f9a0, 0x0f96f, 0x0f9a2, 0x0f9a3, 0x0f9a4, 0x0f9a5, 0x0f9a6, 0x0f9a7,
+ 0x0f9a8, 0x0f9a9, 0x0f95f, 0x0f9ab, 0x0f9ac, 0x0f9ad, 0x0f9ae, 0x0f9af,
+ 0x0f9b0, 0x0f9b1, 0x0f9b2, 0x0f9b3, 0x0f9b4, 0x0f9b5, 0x0f9b6, 0x0f9b7,
+ 0x0f9b8, 0x0f9b9, 0x0f9ba, 0x0f9bb, 0x0f9bc, 0x0f9bd, 0x0f9be, 0x0f914,
+ 0x0f9c0, 0x0f9c1, 0x0f9c2, 0x0f9c3, 0x02eef, 0x0f9c5, 0x0f9c6, 0x0f9c7,
+ 0x0f9c8, 0x0f9c9, 0x0f9ca, 0x0f9cb, 0x0f9cc, 0x0f9cd, 0x0f9ce, 0x0f9cf,
+ 0x0f9d0, 0x03285, 0x0f9d2, 0x0f9d3, 0x0f9d4, 0x0f9d5, 0x0f9d6, 0x0f9d7,
+ 0x0f9d8, 0x0f9d9, 0x0f9da, 0x0f961, 0x0f9dc, 0x0f9dd, 0x0f9de, 0x0f9df,
+ 0x0f9e0, 0x0f9e1, 0x0f9e2, 0x0f9e3, 0x0f9e4, 0x0f9e5, 0x0f9e6, 0x0f9e7,
+ 0x0f9e8, 0x02fa5, 0x0f9ea, 0x0f9eb, 0x0f9ec, 0x0f9ed, 0x0f9ee, 0x0f9ef,
+ 0x0f9f0, 0x0f9f1, 0x0f9f2, 0x0f9f3, 0x0f9f4, 0x0f9f5, 0x0f9f6, 0x02f74,
+ 0x0f9f8, 0x0f9f9, 0x0f9fa, 0x0f9fb, 0x0f9fc, 0x0f9fd, 0x0f9fe, 0x0f9ff
+};
+
+static uint32_t unicode_ci_page_fa[] = {
+ 0x0fa00, 0x0fa01, 0x0fa02, 0x0fa03, 0x0fa04, 0x0fa05, 0x0fa06, 0x0fa07,
+ 0x02f8f, 0x0fa09, 0x02f92, 0x0fa0b, 0x0fa0c, 0x0fa0d, 0x0fa0e, 0x0fa0f,
+ 0x0fa10, 0x0fa11, 0x0fa12, 0x0fa13, 0x0fa14, 0x0fa15, 0x0fa16, 0x0fa17,
+ 0x0fa18, 0x0fa19, 0x0fa1a, 0x0fa1b, 0x0fa1c, 0x0fa1d, 0x02f7b, 0x0fa1f,
+ 0x0fa20, 0x0fa21, 0x0fa22, 0x0fa23, 0x0fa24, 0x0fa25, 0x0fa26, 0x0fa27,
+ 0x0fa28, 0x0fa29, 0x0fa2a, 0x0fa2b, 0x0fa2c, 0x0fa2d, 0x0fa2e, 0x0fa2f,
+ 0x0fa30, 0x0fa31, 0x0fa32, 0x0fa33, 0x0fa34, 0x0fa35, 0x0fa36, 0x0fa37,
+ 0x0fa38, 0x0fa39, 0x0fa3a, 0x0fa3b, 0x02f2c, 0x0fa3d, 0x0fa3e, 0x0fa3f,
+ 0x0fa40, 0x0fa41, 0x0fa42, 0x0fa43, 0x0fa44, 0x0fa45, 0x0fa46, 0x0fa47,
+ 0x0fa48, 0x02ea4, 0x0fa4a, 0x0fa4b, 0x03293, 0x0fa4d, 0x0fa4e, 0x0fa4f,
+ 0x0fa50, 0x03297, 0x0fa52, 0x0fa53, 0x0fa54, 0x0fa55, 0x0fa56, 0x0f996,
+ 0x0fa58, 0x0fa59, 0x0fa5a, 0x0fa5b, 0x0fa5c, 0x02ebe, 0x02ebe, 0x0fa5f,
+ 0x0fa60, 0x0fa61, 0x0fa62, 0x0fa63, 0x0fa64, 0x0fa65, 0x02ecc, 0x0fa25,
+ 0x0fa68, 0x0fa69, 0x0fa6a, 0x0fa6b, 0x0fa6c, 0x0fa6d, 0x0fa6e, 0x0fa6f,
+ 0x0fa70, 0x0fa71, 0x0fa72, 0x0fa73, 0x0fa74, 0x0fa75, 0x0fa76, 0x0fa77,
+ 0x0fa78, 0x0fa79, 0x0fa7a, 0x0fa7b, 0x0fa7c, 0x0fa7d, 0x0fa7e, 0x0fa7f,
+ 0x0fa80, 0x0fa81, 0x0fa82, 0x0fa83, 0x0fa84, 0x0fa85, 0x0fa86, 0x0fa87,
+ 0x0fa88, 0x0fa89, 0x0fa8a, 0x0fa8b, 0x0fa8c, 0x0fa8d, 0x0fa8e, 0x0fa8f,
+ 0x0fa90, 0x0fa91, 0x0fa92, 0x0fa93, 0x0fa94, 0x0fa95, 0x0fa96, 0x0fa97,
+ 0x0fa98, 0x0fa99, 0x0fa9a, 0x0fa9b, 0x0fa9c, 0x0fa9d, 0x0fa9e, 0x0fa9f,
+ 0x0faa0, 0x0faa1, 0x0faa2, 0x0faa3, 0x0faa4, 0x0faa5, 0x0faa6, 0x0faa7,
+ 0x0faa8, 0x0faa9, 0x0faaa, 0x0faab, 0x0faac, 0x0faad, 0x0faae, 0x0faaf,
+ 0x0fab0, 0x0fab1, 0x0fab2, 0x0fab3, 0x0fab4, 0x0fab5, 0x0fab6, 0x0fab7,
+ 0x0fab8, 0x0fab9, 0x0faba, 0x0fabb, 0x0fabc, 0x0fabd, 0x0fabe, 0x0fabf,
+ 0x0fac0, 0x0fac1, 0x0fac2, 0x0fac3, 0x0fac4, 0x0fac5, 0x0fac6, 0x0fac7,
+ 0x0fac8, 0x0fac9, 0x0faca, 0x0facb, 0x0facc, 0x0facd, 0x0face, 0x0facf,
+ 0x0fad0, 0x0fad1, 0x0fad2, 0x0fad3, 0x0fad4, 0x0fad5, 0x0fad6, 0x0fad7,
+ 0x0fad8, 0x0fad9, 0x0fada, 0x0fadb, 0x0fadc, 0x0fadd, 0x0fade, 0x0fadf,
+ 0x0fae0, 0x0fae1, 0x0fae2, 0x0fae3, 0x0fae4, 0x0fae5, 0x0fae6, 0x0fae7,
+ 0x0fae8, 0x0fae9, 0x0faea, 0x0faeb, 0x0faec, 0x0faed, 0x0faee, 0x0faef,
+ 0x0faf0, 0x0faf1, 0x0faf2, 0x0faf3, 0x0faf4, 0x0faf5, 0x0faf6, 0x0faf7,
+ 0x0faf8, 0x0faf9, 0x0fafa, 0x0fafb, 0x0fafc, 0x0fafd, 0x0fafe, 0x0faff
+};
+
+static uint32_t unicode_ci_page_fb[] = {
+ 0x0fb00, 0x0fb01, 0x0fb02, 0x0fb03, 0x0fb04, 0x0fb05, 0x0fb05, 0x0fb07,
+ 0x0fb08, 0x0fb09, 0x0fb0a, 0x0fb0b, 0x0fb0c, 0x0fb0d, 0x0fb0e, 0x0fb0f,
+ 0x0fb10, 0x0fb11, 0x0fb12, 0x0fb13, 0x0fb14, 0x0fb15, 0x0fb16, 0x0fb17,
+ 0x0fb18, 0x0fb19, 0x0fb1a, 0x0fb1b, 0x0fb1c, 0x005d9, 0x00000, 0x005f2,
+ 0x005e2, 0x005d0, 0x005d3, 0x005d4, 0x005da, 0x005dc, 0x005dd, 0x005e8,
+ 0x005ea, 0x0002b, 0x005e9, 0x005e9, 0x005e9, 0x005e9, 0x005d0, 0x005d0,
+ 0x005d0, 0x005d1, 0x005d2, 0x005d3, 0x005d4, 0x005d5, 0x005d6, 0x0fb37,
+ 0x005d8, 0x005d9, 0x005da, 0x005da, 0x005dc, 0x0fb3d, 0x005dd, 0x0fb3f,
+ 0x005df, 0x005e1, 0x0fb42, 0x005e3, 0x005e3, 0x0fb45, 0x005e5, 0x005e7,
+ 0x005e8, 0x005e9, 0x005ea, 0x005d5, 0x005d1, 0x005da, 0x005e3, 0x0fb4f,
+ 0x00671, 0x00671, 0x0067b, 0x0067b, 0x0067b, 0x0067b, 0x0067e, 0x0067e,
+ 0x0067e, 0x0067e, 0x00680, 0x00680, 0x00680, 0x00680, 0x0067a, 0x0067a,
+ 0x0067a, 0x0067a, 0x0067f, 0x0067f, 0x0067f, 0x0067f, 0x00679, 0x00679,
+ 0x00679, 0x00679, 0x006a4, 0x006a4, 0x006a4, 0x006a4, 0x006a6, 0x006a6,
+ 0x006a6, 0x006a6, 0x00684, 0x00684, 0x00684, 0x00684, 0x00683, 0x00683,
+ 0x00683, 0x00683, 0x00686, 0x00686, 0x00686, 0x00686, 0x00687, 0x00687,
+ 0x00687, 0x00687, 0x0068d, 0x0068d, 0x0068c, 0x0068c, 0x0068e, 0x0068e,
+ 0x00688, 0x00688, 0x00698, 0x00698, 0x00691, 0x00691, 0x006a9, 0x006a9,
+ 0x006a9, 0x006a9, 0x006af, 0x006af, 0x006af, 0x006af, 0x006b3, 0x006b3,
+ 0x006b3, 0x006b3, 0x006b1, 0x006b1, 0x006b1, 0x006b1, 0x006ba, 0x006ba,
+ 0x006bb, 0x006bb, 0x006bb, 0x006bb, 0x006c0, 0x006c0, 0x006c1, 0x006c1,
+ 0x006c1, 0x006c1, 0x006be, 0x006be, 0x006be, 0x006be, 0x006d2, 0x006d2,
+ 0x006d2, 0x006d2, 0x0fbb2, 0x0fbb3, 0x0fbb4, 0x0fbb5, 0x0fbb6, 0x0fbb7,
+ 0x0fbb8, 0x0fbb9, 0x0fbba, 0x0fbbb, 0x0fbbc, 0x0fbbd, 0x0fbbe, 0x0fbbf,
+ 0x0fbc0, 0x0fbc1, 0x0fbc2, 0x0fbc3, 0x0fbc4, 0x0fbc5, 0x0fbc6, 0x0fbc7,
+ 0x0fbc8, 0x0fbc9, 0x0fbca, 0x0fbcb, 0x0fbcc, 0x0fbcd, 0x0fbce, 0x0fbcf,
+ 0x0fbd0, 0x0fbd1, 0x0fbd2, 0x006ad, 0x006ad, 0x006ad, 0x006ad, 0x006c7,
+ 0x006c7, 0x006c6, 0x006c6, 0x006c8, 0x006c8, 0x00677, 0x006cb, 0x006cb,
+ 0x006c5, 0x006c5, 0x006c9, 0x006c9, 0x006d0, 0x006d0, 0x006d0, 0x006d0,
+ 0x00649, 0x00649, 0x0fbea, 0x0fbea, 0x0fbec, 0x0fbec, 0x0fbee, 0x0fbee,
+ 0x0fbf0, 0x0fbf0, 0x0fbf2, 0x0fbf2, 0x0fbf4, 0x0fbf4, 0x0fbf6, 0x0fbf6,
+ 0x0fbf6, 0x0fbf9, 0x0fbf9, 0x0fbf9, 0x006cc, 0x006cc, 0x006cc, 0x006cc
+};
+
+static uint32_t unicode_ci_page_fc[] = {
+ 0x0fc00, 0x0fc01, 0x0fc02, 0x0fbf9, 0x0fc04, 0x0fc05, 0x0fc06, 0x0fc07,
+ 0x0fc08, 0x0fc09, 0x0fc0a, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fc0f,
+ 0x0fc10, 0x0fc11, 0x0fc12, 0x0fc13, 0x0fc14, 0x0fc15, 0x0fc16, 0x0fc17,
+ 0x0fc18, 0x0fc19, 0x0fc1a, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fc1f,
+ 0x0fc20, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25, 0x0fc26, 0x0fc27,
+ 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e, 0x0fc2f,
+ 0x0fc30, 0x0fc31, 0x0fc32, 0x0fc33, 0x0fc34, 0x0fc35, 0x0fc36, 0x0fc37,
+ 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc3f,
+ 0x0fc40, 0x0fc41, 0x0fc42, 0x0fc43, 0x0fc44, 0x0fc45, 0x0fc46, 0x0fc47,
+ 0x0fc48, 0x0fc49, 0x0fc4a, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fc4f,
+ 0x0fc50, 0x0fc51, 0x0fc52, 0x0fc53, 0x0fc54, 0x0fc55, 0x0fc56, 0x0fc57,
+ 0x0fc58, 0x0fc59, 0x0fc5a, 0x00630, 0x00631, 0x00649, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0fc64, 0x0fc65, 0x0fc02, 0x0fc67,
+ 0x0fbf9, 0x0fc04, 0x0fc6a, 0x0fc6b, 0x0fc08, 0x0fc6d, 0x0fc09, 0x0fc0a,
+ 0x0fc70, 0x0fc71, 0x0fc0e, 0x0fc73, 0x0fc0f, 0x0fc10, 0x0fc76, 0x0fc77,
+ 0x0fc12, 0x0fc79, 0x0fc13, 0x0fc14, 0x0fc31, 0x0fc32, 0x0fc35, 0x0fc36,
+ 0x0fc37, 0x0fc3b, 0x0fc3c, 0x0fc3d, 0x0fc3e, 0x0fc42, 0x0fc43, 0x0fc44,
+ 0x0fc88, 0x0fc48, 0x0fc8a, 0x0fc8b, 0x0fc4e, 0x0fc8d, 0x0fc4f, 0x0fc50,
+ 0x00649, 0x0fc91, 0x0fc92, 0x0fc58, 0x0fc94, 0x0fc59, 0x0fc5a, 0x0fc00,
+ 0x0fc01, 0x0fc99, 0x0fc02, 0x0fc9b, 0x0fc05, 0x0fc06, 0x0fc07, 0x0fc08,
+ 0x0fca0, 0x0fc0b, 0x0fc0c, 0x0fc0d, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fc15,
+ 0x0fc16, 0x0fc17, 0x0fc18, 0x0fc19, 0x0fc1b, 0x0fc1c, 0x0fc1d, 0x0fc1e,
+ 0x0fc1f, 0x0fc20, 0x0fcb2, 0x0fc21, 0x0fc22, 0x0fc23, 0x0fc24, 0x0fc25,
+ 0x0fc26, 0x0fc28, 0x0fc29, 0x0fc2a, 0x0fc2b, 0x0fc2c, 0x0fc2d, 0x0fc2e,
+ 0x0fc2f, 0x0fc30, 0x0fc33, 0x0fc34, 0x0fc38, 0x0fc39, 0x0fc3a, 0x0fc3b,
+ 0x0fc3c, 0x0fc3f, 0x0fc40, 0x0fc41, 0x0fc42, 0x0fccd, 0x0fc45, 0x0fc46,
+ 0x0fc47, 0x0fc48, 0x0fc4b, 0x0fc4c, 0x0fc4d, 0x0fc4e, 0x0fcd6, 0x0fc51,
+ 0x0fc52, 0x00647, 0x0fc55, 0x0fc56, 0x0fc57, 0x0fc58, 0x0fcde, 0x0fc02,
+ 0x0fc9b, 0x0fc08, 0x0fca0, 0x0fc0e, 0x0fca5, 0x0fc12, 0x0fce6, 0x0fc1f,
+ 0x0fce8, 0x0fce9, 0x0fcea, 0x0fc3b, 0x0fc3c, 0x0fc42, 0x0fc4e, 0x0fcd6,
+ 0x0fc58, 0x0fcde, 0x00000, 0x00000, 0x00000, 0x0fcf5, 0x0fcf6, 0x0fcf7,
+ 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb, 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fcff
+};
+
+static uint32_t unicode_ci_page_fd[] = {
+ 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03, 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07,
+ 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b, 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f,
+ 0x0fd10, 0x0fcf5, 0x0fcf6, 0x0fcf7, 0x0fcf8, 0x0fcf9, 0x0fcfa, 0x0fcfb,
+ 0x0fcfc, 0x0fcfd, 0x0fcfe, 0x0fd1b, 0x0fd00, 0x0fd01, 0x0fd02, 0x0fd03,
+ 0x0fd04, 0x0fd05, 0x0fd06, 0x0fd07, 0x0fd08, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fd0d, 0x0fd0e, 0x0fd0f, 0x0fd10, 0x0fd09, 0x0fd0a, 0x0fd0b,
+ 0x0fce9, 0x0fce8, 0x0fcea, 0x0fc27, 0x0fc1c, 0x0fc1d, 0x0fc1e, 0x0fd09,
+ 0x0fd0a, 0x0fd0b, 0x0fc27, 0x0fc28, 0x00627, 0x00627, 0x0fd3e, 0x0fd3f,
+ 0x0fd40, 0x0fd41, 0x0fd42, 0x0fd43, 0x0fd44, 0x0fd45, 0x0fd46, 0x0fd47,
+ 0x0fd48, 0x0fd49, 0x0fd4a, 0x0fd4b, 0x0fd4c, 0x0fd4d, 0x0fd4e, 0x0fd4f,
+ 0x0fd50, 0x0fd51, 0x0fd51, 0x0fd53, 0x0fd54, 0x0fd55, 0x0fd56, 0x0fd57,
+ 0x0fd58, 0x0fd58, 0x0fd5a, 0x0fd5b, 0x0fd5c, 0x0fd5d, 0x0fd5e, 0x0fd5f,
+ 0x0fd5f, 0x0fd61, 0x0fd62, 0x0fd62, 0x0fd64, 0x0fd64, 0x0fd66, 0x0fd67,
+ 0x0fd67, 0x0fd69, 0x0fd6a, 0x0fd6a, 0x0fd6c, 0x0fd6c, 0x0fd6e, 0x0fd6f,
+ 0x0fd6f, 0x0fd71, 0x0fd71, 0x0fd73, 0x0fd74, 0x0fd75, 0x0fd76, 0x0fd76,
+ 0x0fd78, 0x0fd79, 0x0fd7a, 0x0fd7b, 0x0fd7c, 0x0fd7c, 0x0fd7e, 0x0fd7f,
+ 0x0fd80, 0x0fd81, 0x0fd82, 0x0fd83, 0x0fd83, 0x0fd85, 0x0fd85, 0x0fd87,
+ 0x0fd87, 0x0fd89, 0x0fd8a, 0x0fd8b, 0x0fd8c, 0x0fd8d, 0x0fd8e, 0x0fd8f,
+ 0x0fd90, 0x0fd91, 0x0fd92, 0x0fd93, 0x0fd94, 0x0fd95, 0x0fd96, 0x0fd97,
+ 0x0fd97, 0x0fd99, 0x0fd9a, 0x0fd9b, 0x0fd9c, 0x0fd9c, 0x0fd9e, 0x0fd9f,
+ 0x0fda0, 0x0fda1, 0x0fda2, 0x0fda3, 0x0fda4, 0x0fda5, 0x0fda6, 0x0fda7,
+ 0x0fda8, 0x0fda9, 0x0fdaa, 0x0fdab, 0x0fdac, 0x0fdad, 0x0fdae, 0x0fdaf,
+ 0x0fdb0, 0x0fdb1, 0x0fdb2, 0x0fdb3, 0x0fd7e, 0x0fd80, 0x0fdb6, 0x0fdb7,
+ 0x0fdb8, 0x0fdb9, 0x0fdba, 0x0fdbb, 0x0fdba, 0x0fdb8, 0x0fdbe, 0x0fdbf,
+ 0x0fdc0, 0x0fdc1, 0x0fdc2, 0x0fdbb, 0x0fd75, 0x0fd66, 0x0fdc6, 0x0fdc7,
+ 0x0fdc8, 0x0fdc9, 0x0fdca, 0x0fdcb, 0x0fdcc, 0x0fdcd, 0x0fdce, 0x0fdcf,
+ 0x0fdd0, 0x0fdd1, 0x0fdd2, 0x0fdd3, 0x0fdd4, 0x0fdd5, 0x0fdd6, 0x0fdd7,
+ 0x0fdd8, 0x0fdd9, 0x0fdda, 0x0fddb, 0x0fddc, 0x0fddd, 0x0fdde, 0x0fddf,
+ 0x0fde0, 0x0fde1, 0x0fde2, 0x0fde3, 0x0fde4, 0x0fde5, 0x0fde6, 0x0fde7,
+ 0x0fde8, 0x0fde9, 0x0fdea, 0x0fdeb, 0x0fdec, 0x0fded, 0x0fdee, 0x0fdef,
+ 0x0fdf0, 0x0fdf1, 0x0fdf2, 0x0fdf3, 0x0fdf4, 0x0fdf5, 0x0fdf6, 0x0fdf7,
+ 0x0fdf8, 0x0fdf9, 0x0fdfa, 0x0fdfb, 0x0fdfc, 0x0fdfd, 0x0fdfe, 0x0fdff
+};
+
+static uint32_t unicode_ci_page_fe[] = {
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x0fe10, 0x0fe11, 0x0fe12, 0x0fe13, 0x0fe14, 0x0fe15, 0x0fe16, 0x0fe17,
+ 0x0fe18, 0x0fe19, 0x0fe1a, 0x0fe1b, 0x0fe1c, 0x0fe1d, 0x0fe1e, 0x0fe1f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe24, 0x0fe25, 0x0fe26, 0x0fe27,
+ 0x0fe28, 0x0fe29, 0x0fe2a, 0x0fe2b, 0x0fe2c, 0x0fe2d, 0x0fe2e, 0x0fe2f,
+ 0x02025, 0x02014, 0x02013, 0x0005f, 0x0005f, 0x00028, 0x00029, 0x0007b,
+ 0x0007d, 0x03014, 0x03015, 0x03010, 0x03011, 0x0300a, 0x0300b, 0x02329,
+ 0x0232a, 0x0300c, 0x0300d, 0x0300e, 0x0300f, 0x0fe45, 0x0fe46, 0x0005b,
+ 0x0005d, 0x0203e, 0x0203e, 0x0203e, 0x0203e, 0x0005f, 0x0005f, 0x0005f,
+ 0x0002c, 0x03001, 0x0002e, 0x0fe53, 0x0003b, 0x0003a, 0x0003f, 0x00021,
+ 0x02014, 0x00028, 0x00029, 0x0007b, 0x0007d, 0x03014, 0x03015, 0x00023,
+ 0x00026, 0x0002a, 0x0002b, 0x0002d, 0x0003c, 0x0003e, 0x0003d, 0x0fe67,
+ 0x0005c, 0x00024, 0x00025, 0x00040, 0x0fe6c, 0x0fe6d, 0x0fe6e, 0x0fe6f,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x0fe75, 0x00000, 0x00000,
+ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000,
+ 0x00621, 0x00622, 0x00622, 0x00623, 0x00623, 0x00624, 0x00624, 0x00625,
+ 0x00625, 0x00626, 0x00626, 0x00626, 0x00626, 0x00627, 0x00627, 0x00628,
+ 0x00628, 0x00628, 0x00628, 0x00629, 0x00629, 0x0062a, 0x0062a, 0x0062a,
+ 0x0062a, 0x0062b, 0x0062b, 0x0062b, 0x0062b, 0x0062c, 0x0062c, 0x0062c,
+ 0x0062c, 0x0062d, 0x0062d, 0x0062d, 0x0062d, 0x0062e, 0x0062e, 0x0062e,
+ 0x0062e, 0x0062f, 0x0062f, 0x00630, 0x00630, 0x00631, 0x00631, 0x00632,
+ 0x00632, 0x00633, 0x00633, 0x00633, 0x00633, 0x00634, 0x00634, 0x00634,
+ 0x00634, 0x00635, 0x00635, 0x00635, 0x00635, 0x00636, 0x00636, 0x00636,
+ 0x00636, 0x00637, 0x00637, 0x00637, 0x00637, 0x00638, 0x00638, 0x00638,
+ 0x00638, 0x00639, 0x00639, 0x00639, 0x00639, 0x0063a, 0x0063a, 0x0063a,
+ 0x0063a, 0x00641, 0x00641, 0x00641, 0x00641, 0x00642, 0x00642, 0x00642,
+ 0x00642, 0x00643, 0x00643, 0x00643, 0x00643, 0x00644, 0x00644, 0x00644,
+ 0x00644, 0x00645, 0x00645, 0x00645, 0x00645, 0x00646, 0x00646, 0x00646,
+ 0x00646, 0x00647, 0x00647, 0x00647, 0x00647, 0x00648, 0x00648, 0x00649,
+ 0x00649, 0x0064a, 0x0064a, 0x0064a, 0x0064a, 0x0fef5, 0x0fef5, 0x0fef7,
+ 0x0fef7, 0x0fef9, 0x0fef9, 0x0fefb, 0x0fefb, 0x0fefd, 0x0fefe, 0x0feff
+};
+
+static uint32_t unicode_ci_page_ff[] = {
+ 0x0ff00, 0x00021, 0x00022, 0x00023, 0x00024, 0x00025, 0x00026, 0x00027,
+ 0x00028, 0x00029, 0x0002a, 0x0002b, 0x0002c, 0x0002d, 0x0002e, 0x0002f,
+ 0x00030, 0x00031, 0x00032, 0x00033, 0x00034, 0x00035, 0x00036, 0x00037,
+ 0x00038, 0x00039, 0x0003a, 0x0003b, 0x0003c, 0x0003d, 0x0003e, 0x0003f,
+ 0x00040, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0005b, 0x0005c, 0x0005d, 0x0005e, 0x0005f,
+ 0x00060, 0x00041, 0x00042, 0x00043, 0x00044, 0x00045, 0x00046, 0x00047,
+ 0x00048, 0x00049, 0x0004a, 0x0004b, 0x0004c, 0x0004d, 0x0004e, 0x0004f,
+ 0x00050, 0x00051, 0x00052, 0x00053, 0x00054, 0x00055, 0x00056, 0x00057,
+ 0x00058, 0x00059, 0x0005a, 0x0007b, 0x0007c, 0x0007d, 0x0007e, 0x02985,
+ 0x02986, 0x03002, 0x0300c, 0x0300d, 0x03001, 0x030fb, 0x03092, 0x03042,
+ 0x03044, 0x03046, 0x03048, 0x0304a, 0x03084, 0x03086, 0x03088, 0x03064,
+ 0x030fc, 0x03042, 0x03044, 0x03046, 0x03048, 0x0304a, 0x0304b, 0x0304d,
+ 0x0304f, 0x03051, 0x03053, 0x03055, 0x03057, 0x03059, 0x0305b, 0x0305d,
+ 0x0305f, 0x03061, 0x03064, 0x03066, 0x03068, 0x0306a, 0x0306b, 0x0306c,
+ 0x0306d, 0x0306e, 0x0306f, 0x03072, 0x03075, 0x03078, 0x0307b, 0x0307e,
+ 0x0307f, 0x03080, 0x03081, 0x03082, 0x03084, 0x03086, 0x03088, 0x03089,
+ 0x0308a, 0x0308b, 0x0308c, 0x0308d, 0x0308f, 0x03093, 0x00000, 0x00000,
+ 0x01160, 0x01100, 0x01101, 0x011aa, 0x01102, 0x011ac, 0x011ad, 0x01103,
+ 0x01104, 0x01105, 0x011b0, 0x011b1, 0x011b2, 0x011b3, 0x011b4, 0x011b5,
+ 0x0111a, 0x01106, 0x01107, 0x01108, 0x01121, 0x01109, 0x0110a, 0x0110b,
+ 0x0110c, 0x0110d, 0x0110e, 0x0110f, 0x01110, 0x01111, 0x01112, 0x0ffbf,
+ 0x0ffc0, 0x0ffc1, 0x01161, 0x01162, 0x01163, 0x01164, 0x01165, 0x01166,
+ 0x0ffc8, 0x0ffc9, 0x01167, 0x01168, 0x01169, 0x0116a, 0x0116b, 0x0116c,
+ 0x0ffd0, 0x0ffd1, 0x0116d, 0x0116e, 0x0116f, 0x01170, 0x01171, 0x01172,
+ 0x0ffd8, 0x0ffd9, 0x01173, 0x01174, 0x01175, 0x0ffdd, 0x0ffde, 0x0ffdf,
+ 0x000a2, 0x000a3, 0x000ac, 0x000af, 0x000a6, 0x000a5, 0x020a9, 0x0ffe7,
+ 0x02502, 0x02190, 0x02191, 0x02192, 0x02193, 0x025a0, 0x025cb, 0x0ffef,
+ 0x0fff0, 0x0fff1, 0x0fff2, 0x0fff3, 0x0fff4, 0x0fff5, 0x0fff6, 0x0fff7,
+ 0x0fff8, 0x00000, 0x00000, 0x00000, 0x0fffc, 0x0fffd, 0x0fffe, 0x0ffff
+};
+
+static uint32_t *unicode_ci_table[256] = {
+ unicode_ci_page_00, unicode_ci_page_01,
+ unicode_ci_page_02, unicode_ci_page_03,
+ unicode_ci_page_04, unicode_ci_page_05,
+ unicode_ci_page_06, unicode_ci_page_07,
+ NULL, unicode_ci_page_09,
+ unicode_ci_page_0a, unicode_ci_page_0b,
+ unicode_ci_page_0c, unicode_ci_page_0d,
+ unicode_ci_page_0e, unicode_ci_page_0f,
+ unicode_ci_page_10, NULL,
+ NULL, unicode_ci_page_13,
+ NULL, NULL,
+ unicode_ci_page_16, unicode_ci_page_17,
+ unicode_ci_page_18, unicode_ci_page_19,
+ NULL, NULL,
+ NULL, unicode_ci_page_1d,
+ unicode_ci_page_1e, unicode_ci_page_1f,
+ unicode_ci_page_20, unicode_ci_page_21,
+ unicode_ci_page_22, NULL,
+ unicode_ci_page_24, NULL,
+ NULL, unicode_ci_page_27,
+ NULL, NULL,
+ unicode_ci_page_2a, NULL,
+ NULL, NULL,
+ unicode_ci_page_2e, unicode_ci_page_2f,
+ unicode_ci_page_30, unicode_ci_page_31,
+ unicode_ci_page_32, unicode_ci_page_33,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, NULL,
+ NULL, unicode_ci_page_f9,
+ unicode_ci_page_fa, unicode_ci_page_fb,
+ unicode_ci_page_fc, unicode_ci_page_fd,
+ unicode_ci_page_fe, unicode_ci_page_ff
+};
+
+#endif
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/Makefile.am
new file mode 100644
index 00000000..f6ab8e5a
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/Makefile.am
@@ -0,0 +1,6 @@
+SUBDIRS = \
+ apt \
+ ubuntu \
+ rpm \
+ yum \
+ source
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Makefile.am
new file mode 100644
index 00000000..60969bcd
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Makefile.am
@@ -0,0 +1,67 @@
+REPOSITORIES_PATH = repositories
+DISTRIBUTIONS = debian
+ARCHITECTURES = i386 amd64
+CODE_NAMES = jessie
+
+all:
+
+release: build sign-packages update-repository sign-repository upload
+
+remove-existing-packages:
+ for distribution in $(DISTRIBUTIONS); do \
+ find $(REPOSITORIES_PATH)/$${distribution}/pool \
+ -type f -delete; \
+ done
+
+ensure-rsync-path:
+ @if test -z "$(RSYNC_PATH)"; then \
+ echo "--with-rsync-path configure option must be specified."; \
+ false; \
+ fi
+
+download: ensure-rsync-path
+ for distribution in $(DISTRIBUTIONS); do \
+ rsync -avz --progress --delete \
+ $(RSYNC_PATH)/$${distribution} \
+ ${REPOSITORIES_PATH}/; \
+ done
+
+sign-packages:
+ ./sign-packages.sh '$(GPG_UID)' '$(REPOSITORIES_PATH)/' '$(CODE_NAMES)'
+
+update-repository:
+ ./update-repository.sh '$(PACKAGE_NAME)' '$(REPOSITORIES_PATH)/' \
+ '$(ARCHITECTURES)' '$(CODE_NAMES)'
+
+sign-repository:
+ ./sign-repository.sh '$(GPG_UID)' '$(REPOSITORIES_PATH)/' '$(CODE_NAMES)'
+
+upload: ensure-rsync-path
+ for distribution in $(DISTRIBUTIONS); do \
+ (cd $(REPOSITORIES_PATH)/$${distribution}; \
+ rsync -avz --progress --delete \
+ dists pool $(RSYNC_PATH)/$${distribution}); \
+ done
+
+build: build-package-deb
+
+build-package-deb: prepare-build-package-deb
+ vagrant destroy --force
+ for architecture in $(ARCHITECTURES); do \
+ for code_name in $(CODE_NAMES); do \
+ id=debian-$$code_name-$$architecture; \
+ vagrant up $$id || exit 1; \
+ vagrant destroy --force $$id; \
+ done; \
+ done
+
+prepare-build-package-deb: source env.sh
+ cp env.sh tmp/
+ rm -rf tmp/debian
+ cp -rp $(srcdir)/../debian tmp/
+
+source: tmp/$(PACKAGE)-$(VERSION).tar.gz
+
+tmp/$(PACKAGE)-$(VERSION).tar.gz: $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz
+ mkdir -p tmp
+ cp $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz $@
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Vagrantfile b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Vagrantfile
new file mode 100644
index 00000000..c57c5a65
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/Vagrantfile
@@ -0,0 +1,26 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ vms = [
+ {
+ :id => "debian-jessie-i386",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_debian-8.2-i386_chef-provisionerless.box",
+ },
+ {
+ :id => "debian-jessie-amd64",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_debian-8.2_chef-provisionerless.box",
+ },
+ ]
+
+ vms.each do |vm|
+ config.vm.define(vm[:id]) do |node|
+ node.vm.box = vm[:id]
+ node.vm.box_url = vm[:box_url]
+ node.vm.provision(:shell, :path => "build-deb.sh")
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/build-deb.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/build-deb.sh
new file mode 100755
index 00000000..a0a28b0d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/build-deb.sh
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+LANG=C
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+. /vagrant/tmp/env.sh
+
+run apt-get update
+run apt-get install -y lsb-release
+
+distribution=$(lsb_release --id --short | tr 'A-Z' 'a-z')
+code_name=$(lsb_release --codename --short)
+case "${distribution}" in
+ debian)
+ component=main
+ run cat <<EOF > /etc/apt/sources.list.d/groonga.list
+deb http://packages.groonga.org/debian/ ${code_name} main
+deb-src http://packages.groonga.org/debian/ ${code_name} main
+EOF
+ run apt-get update
+ run apt-get install -y --allow-unauthenticated groonga-keyring
+ run apt-get update
+ ;;
+ ubuntu)
+ component=universe
+ run apt-get -y install software-properties-common
+ run add-apt-repository -y universe
+ run add-apt-repository -y ppa:groonga/ppa
+ run apt-get update
+ ;;
+esac
+
+run apt-get install -V -y build-essential devscripts ${DEPENDED_PACKAGES}
+
+run mkdir -p build
+run cp /vagrant/tmp/${PACKAGE}-${VERSION}.tar.gz \
+ build/${PACKAGE}_${VERSION}.orig.tar.gz
+run cd build
+run tar xfz ${PACKAGE}_${VERSION}.orig.tar.gz
+run cd ${PACKAGE}-${VERSION}/
+run cp -rp /vagrant/tmp/debian debian
+# export DEB_BUILD_OPTIONS=noopt
+run debuild -us -uc
+run cd -
+
+package_initial=$(echo "${PACKAGE}" | sed -e 's/\(.\).*/\1/')
+pool_dir="/vagrant/repositories/${distribution}/pool/${code_name}/${component}/${package_initial}/${PACKAGE}"
+run mkdir -p "${pool_dir}/"
+run cp *.tar.* *.dsc *.deb "${pool_dir}/"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/env.sh.in b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/env.sh.in
new file mode 100644
index 00000000..6fb3e840
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/env.sh.in
@@ -0,0 +1,8 @@
+PACKAGE=@PACKAGE@
+VERSION=@VERSION@
+DEPENDED_PACKAGES="
+debhelper
+autotools-dev
+pkg-config
+libgroonga-dev
+"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-packages.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-packages.sh
new file mode 100755
index 00000000..55678b98
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-packages.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_UID DESITINATION CODES"
+ echo " e.g.: $0 'F10399C0' repositories/ 'lenny unstable hardy karmic'"
+ exit 1
+fi
+
+GPG_UID=$1
+DESTINATION=$2
+CODES=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+for code_name in ${CODES}; do
+ case ${code_name} in
+ jessie|unstable)
+ distribution=debian
+ ;;
+ *)
+ distribution=ubuntu
+ ;;
+ esac
+
+ base_directory=${DESTINATION}${distribution}
+ debsign -pgpg2 --re-sign -k${GPG_UID} \
+ $(find ${base_directory} -name '*.dsc' -or -name '*.changes') &
+ if [ "${PARALLEL}" != "yes" ]; then
+ wait
+ fi
+done
+
+wait
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-repository.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-repository.sh
new file mode 100755
index 00000000..b2a1475f
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/sign-repository.sh
@@ -0,0 +1,46 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_UID DESTINATION CODES"
+ echo " e.g.: $0 'F10399C0' repositories/ 'lenny unstable hardy karmic'"
+ exit 1
+fi
+
+GPG_UID=$1
+DESTINATION=$2
+CODES=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+for code_name in ${CODES}; do
+ case ${code_name} in
+ jessie|unstable)
+ distribution=debian
+ ;;
+ *)
+ distribution=ubuntu
+ ;;
+ esac
+
+ release=${DESTINATION}${distribution}/dists/${code_name}/Release
+ rm -f ${release}.gpg
+ gpg2 --sign --detach-sign --armor \
+ --local-user ${GPG_UID} \
+ --output ${release}.gpg \
+ ${release} &
+
+ if [ "${PARALLEL}" != "yes" ]; then
+ wait
+ fi
+done
+
+wait
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/update-repository.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/update-repository.sh
new file mode 100755
index 00000000..0ad8f4a2
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/apt/update-repository.sh
@@ -0,0 +1,130 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 4 ]; then
+ echo "Usage: $0 PROJECT_NAME DESTINATION ARCHITECTURES CODES"
+ echo " e.g.: $0 mroonga repositories/ 'i386 amd64' 'lenny unstable hardy karmic'"
+ exit 1
+fi
+
+PROJECT_NAME=$1
+DESTINATION=$2
+ARCHITECTURES=$3
+CODES=$4
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+update_repository()
+{
+ distribution=$1
+ code_name=$2
+ component=$3
+
+ rm -rf dists/${code_name}
+ mkdir -p dists/${code_name}/${component}/binary-i386/
+ mkdir -p dists/${code_name}/${component}/binary-amd64/
+ mkdir -p dists/${code_name}/${component}/source/
+
+ cat <<EOF > dists/.htaccess
+Options +Indexes
+EOF
+
+ cat <<EOF > dists/${code_name}/${component}/binary-i386/Release
+Archive: ${code_name}
+Component: ${component}
+Origin: The ${PROJECT_NAME} project
+Label: The ${PROJECT_NAME} project
+Architecture: i386
+EOF
+
+ cat <<EOF > dists/${code_name}/${component}/binary-amd64/Release
+Archive: ${code_name}
+Component: ${component}
+Origin: The ${PROJECT_NAME} project
+Label: The ${PROJECT_NAME} project
+Architecture: amd64
+EOF
+
+ cat <<EOF > dists/${code_name}/${component}/source/Release
+Archive: ${code_name}
+Component: ${component}
+Origin: The ${PROJECT_NAME} project
+Label: The ${PROJECT_NAME} project
+Architecture: source
+EOF
+
+ cat <<EOF > generate-${code_name}.conf
+Dir::ArchiveDir ".";
+Dir::CacheDir ".";
+TreeDefault::Directory "pool/${code_name}/${component}";
+TreeDefault::SrcDirectory "pool/${code_name}/${component}";
+Default::Packages::Extensions ".deb";
+Default::Packages::Compress ". gzip bzip2";
+Default::Sources::Compress ". gzip bzip2";
+Default::Contents::Compress "gzip bzip2";
+
+BinDirectory "dists/${code_name}/${component}/binary-i386" {
+ Packages "dists/${code_name}/${component}/binary-i386/Packages";
+ Contents "dists/${code_name}/Contents-i386";
+ SrcPackages "dists/${code_name}/${component}/source/Sources";
+};
+
+BinDirectory "dists/${code_name}/${component}/binary-amd64" {
+ Packages "dists/${code_name}/${component}/binary-amd64/Packages";
+ Contents "dists/${code_name}/Contents-amd64";
+ SrcPackages "dists/${code_name}/${component}/source/Sources";
+};
+
+Tree "dists/${code_name}" {
+ Sections "${component}";
+ Architectures "i386 amd64 source";
+};
+EOF
+ apt-ftparchive generate generate-${code_name}.conf
+ chmod 644 dists/${code_name}/Contents-*
+
+ rm -f dists/${code_name}/Release*
+ rm -f *.db
+ cat <<EOF > release-${code_name}.conf
+APT::FTPArchive::Release::Origin "The ${PROJECT_NAME} project";
+APT::FTPArchive::Release::Label "The ${PROJECT_NAME} project";
+APT::FTPArchive::Release::Architectures "i386 amd64";
+APT::FTPArchive::Release::Codename "${code_name}";
+APT::FTPArchive::Release::Suite "${code_name}";
+APT::FTPArchive::Release::Components "${component}";
+APT::FTPArchive::Release::Description "${PACKAGE_NAME} packages";
+EOF
+ apt-ftparchive -c release-${code_name}.conf \
+ release dists/${code_name} > /tmp/Release
+ mv /tmp/Release dists/${code_name}
+}
+
+for code_name in ${CODES}; do
+ case ${code_name} in
+ jessie|unstable)
+ distribution=debian
+ component=main
+ ;;
+ *)
+ distribution=ubuntu
+ component=universe
+ ;;
+ esac
+
+ mkdir -p ${DESTINATION}${distribution}
+ (cd ${DESTINATION}${distribution}
+ update_repository $distribution $code_name $component) &
+ if [ "${PARALLEL}" != "yes" ]; then
+ wait
+ fi
+done
+
+wait
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/changelog b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/changelog
new file mode 100644
index 00000000..89763794
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/changelog
@@ -0,0 +1,71 @@
+groonga-normalizer-mysql (1.1.1-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Fri, 29 Apr 2016 00:00:00 +0900
+
+groonga-normalizer-mysql (1.1.0-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Kouhei Sutou <kou@clear-code.com> Fri, 29 May 2015 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.9-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Sun, 29 Mar 2015 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.8-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Kouhei Sutou <kou@clear-code.com> Tue, 10 Feb 2015 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.7-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- <hayashi@clear-code.com> Mon, 09 Feb 2015 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.6-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Sun, 09 Feb 2014 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.5-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Sat, 29 Jun 2013 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.4-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Wed, 29 May 2013 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.3-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Mon, 29 Apr 2013 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.2-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- HAYASHI Kentaro <hayashi@clear-code.com> Fri, 29 Mar 2013 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.1) unstable; urgency=low
+
+ * New upstream release
+
+ -- khayashi <hayashi@clear-code.com> Thu, 28 Feb 2013 00:00:00 +0900
+
+groonga-normalizer-mysql (1.0.0-1) unstable; urgency=low
+
+ * Initial release
+
+ -- Kouhei Sutou <kou@clear-code.com> Sat, 9 Feb 2013 00:00:00 +0900
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/compat b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/compat
new file mode 100644
index 00000000..ec635144
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/control b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/control
new file mode 100644
index 00000000..37a3805d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/control
@@ -0,0 +1,31 @@
+Source: groonga-normalizer-mysql
+Section: libs
+Priority: optional
+Maintainer: Groonga Project <packages@groonga.org>
+Build-Depends:
+ debhelper (>= 9),
+ autotools-dev,
+ pkg-config,
+ libgroonga-dev (>= 3.0.0)
+Standards-Version: 3.9.3
+Homepage: https://github.com/groonga/groonga-normalizer-mysql
+
+Package: groonga-normalizer-mysql
+Architecture: any
+Depends:
+ ${misc:Depends},
+ ${shlibs:Depends},
+ libgroonga0
+Description: MySQL derived normalizer for Groonga
+ Groonga is an open-source fulltext search engine and column store.
+ It lets you write high-performance applications that requires fulltext
+ search.
+ .
+ This package provides a normalizer which normalizes text as same as
+ MySQL does.
+ .
+ Groonga has its own normalizers by default, but that behavior is a bit
+ defferent from MySQL does, so as a result, it affects search results.
+ These normalizers are useful if you regards it important for keeping
+ normalizer compatibility with MySQL in Mroonga which uses Groonga as
+ storage engine.
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/copyright b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/copyright
new file mode 100644
index 00000000..aa491eef
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/copyright
@@ -0,0 +1,85 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Contact: Kouhei Sutou <kou at clear-code.com>
+Source: http://packages.groonga.org/source/groonga-normalizer-mysql/
+
+Files: *
+Copyright: 2013 Kouhei Sutou <kou@clear-code.com>
+License: LGPL-2
+
+Files: debian/*
+Copyright: 2013 Kouhei Sutou <kou@clear-code.com>
+ 2013 HAYASHI Kentaro <hayashi@clear-code.com>
+License: LGPL-2
+
+Files: test/run-test.sh
+Copyright: 2013 Kouhei Sutou <kou@clear-code.com>
+License: LGPL-2+
+
+Files: normalizers/mysql_general_ci_table.h
+Copyright: 2013 Kouhei Sutou <kou@clear-code.com>
+ 2000, 2012, Oracle and/or its affiliates
+License: LGPL-2
+
+Files: normalizers/mysql_unicode_ci_*.h
+Copyright: 2013 Kouhei Sutou <kou@clear-code.com>
+ 2004, 2011, Oracle and/or its affiliates
+License: LGPL-2
+
+Files: ltmain.sh
+Copyright: 1996, Gordon Matzigkeit <gord@gnu.ai.mit.edu>
+ 1996-2011, Free Software Foundation, Inc.
+License: GPL-2+ with Libtool exception
+ GNU Libtool is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+ .
+ As a special exception to the GNU General Public License,
+ if you distribute this file as part of a program or library that
+ is built using GNU Libtool, you may include this file under the
+ same distribution terms that you use for the rest of that program.
+ .
+ GNU Libtool is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with GNU Libtool; see the file COPYING. If not, a copy
+ can be downloaded from http://www.gnu.org/licenses/gpl.html,
+ or obtained by writing to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
+
+License: LGPL-2
+ 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, version 2 of the License.
+ .
+ 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 program. If not, see <http://www.gnu.org/licenses/>.
+ .
+ The Debian packaging is (C) 2013, Kouhei Sutou <kou@clear-code.com> and
+ is licensed under the LGPL-2, see `/usr/share/common-licenses/LGPL-2'.
+
+License: LGPL-2+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 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
+ Library General Public License for more details.
+ .
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+ .
+ On Debian systems, the full text of the GNU Library General Public
+ License version 2 can be found in the file `/usr/share/common-licenses/LGPL-2'.
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/groonga-normalizer-mysql.install b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/groonga-normalizer-mysql.install
new file mode 100644
index 00000000..1f58446d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/groonga-normalizer-mysql.install
@@ -0,0 +1 @@
+usr/lib/groonga/plugins/normalizers/mysql*
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/patches/series b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/patches/series
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/patches/series
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/rules b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/rules
new file mode 100755
index 00000000..753d4484
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/rules
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+# -*- makefile-gmake -*-
+#
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+# This has to be exported to make some magic below work.
+export DH_OPTIONS
+
+%:
+ dh $@
+
+# disable 'make check'.
+override_dh_auto_test:
+
+override_dh_install:
+ find $(CURDIR) -name '*.la' -delete
+ find $(CURDIR) -name 'lgpl-2.0.txt' -delete
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/source/format b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/source/format
new file mode 100644
index 00000000..163aaf8d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/watch b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/watch
new file mode 100644
index 00000000..ab451e4c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/debian/watch
@@ -0,0 +1,2 @@
+version=3
+http://packages.groonga.org/source/groonga-normalizer-mysql/groonga-normalizer-mysql-(.+).tar.gz
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/Makefile.am
new file mode 100644
index 00000000..06031c93
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = centos fedora
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/Makefile.am
new file mode 100644
index 00000000..eb5a6b42
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/Makefile.am
@@ -0,0 +1 @@
+noinst_DATA = groonga-normalizer-mysql.spec
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/groonga-normalizer-mysql.spec.in b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/groonga-normalizer-mysql.spec.in
new file mode 100644
index 00000000..a0f3b355
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/centos/groonga-normalizer-mysql.spec.in
@@ -0,0 +1,92 @@
+%global _initddir %{_sysconfdir}/init.d/
+
+Name: groonga-normalizer-mysql
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: MySQL compatible normalizer plugin for groonga
+
+Group: Applications/Text
+License: LGPLv2
+URL: http://groonga.org/
+Source0: http://packages.groonga.org/source/%{name}/%{name}-%{version}.tar.gz
+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-%(%{__id_u} -n)
+BuildRequires: groonga-devel >= 3.0.3
+Requires: groonga-libs >= 3.0.3
+
+%description
+This package provides MySQL compatible normalizer plugin.
+You can use NormalizerMySQLGeneralCI and NormalizerMySQLUnicodeCI as normalizer.
+
+%package devel
+Summary: Development files for groonga-normalizer-mysql
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+This package provides development files for groonga-normalizer-mysql.
+
+%prep
+%setup -q
+
+
+%build
+%configure \
+ --disable-static
+sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
+sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
+make %{?_smp_mflags}
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT INSTALL="install -p"
+rm $RPM_BUILD_ROOT%{_libdir}/groonga/plugins/*/*.la
+
+%files
+%dir %{_libdir}/groonga
+%dir %{_libdir}/groonga/plugins
+%dir %{_libdir}/groonga/plugins/normalizers
+%{_libdir}/groonga/plugins/normalizers/mysql.so
+%{_datadir}/doc/groonga-normalizer-mysql/
+
+%files devel
+%{_libdir}/pkgconfig/groonga-normalizer-mysql.pc
+
+%changelog
+* Fri Apr 29 2016 HAYASHI Kentaro <hayashi@clear-code.com> - 1.1.1-1
+- new upstream release.
+
+* Fri May 29 2015 Kouhei Sutou <kou@clear-code.com> - 1.1.0-1
+- new upstream release.
+
+* Sun Mar 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.9-1
+- new upstream release.
+
+* Tue Feb 10 2015 Kouhei Sutou <kou@clear-code.com> - 1.0.8-1
+- new upstream release.
+
+* Mon Feb 09 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.7-1
+- new upstream release.
+
+* Sun Feb 09 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.6-1
+- new upstream release.
+
+* Sat Jun 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.5-1
+- new upstream release.
+
+* Wed May 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.4-1
+- new upstream release.
+
+* Mon Apr 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.3-0
+- new upstream release.
+- Reduce required packages. groonga-libs is only required.
+- Require groonga 3.0.3 or later.
+- Split development files into -devel package.
+
+* Fri Mar 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.2-0
+- new upstream release.
+
+* Thu Feb 28 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.1-0
+- new upstream release
+
+* Tue Jan 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.0-0
+- initial packaging for CentOS
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/Makefile.am
new file mode 100644
index 00000000..1273c1d4
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/Makefile.am
@@ -0,0 +1,2 @@
+noinst_DATA = groonga-normalizer-mysql.spec
+
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/groonga-normalizer-mysql.spec.in b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/groonga-normalizer-mysql.spec.in
new file mode 100644
index 00000000..d6e3c7cf
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/rpm/fedora/groonga-normalizer-mysql.spec.in
@@ -0,0 +1,91 @@
+%global __provides_exclude_from ^%{_libdir}/groonga/plugins/normalizers/mysql\\.so$
+
+Name: groonga-normalizer-mysql
+Version: @VERSION@
+Release: 1%{?dist}
+Summary: MySQL compatible normalizer plugin for groonga
+
+Group: Applications/Text
+License: LGPLv2
+URL: http://groonga.org/
+Source0: http://packages.groonga.org/source/%{name}/%{name}-%{version}.tar.gz
+
+BuildRequires: groonga-devel >= 3.0.3
+Requires: groonga-libs >= 3.0.3
+ExclusiveArch: %{ix86} x86_64
+
+%description
+This package provides MySQL compatible normalizer plugin.
+You can use NormalizerMySQLGeneralCI and NormalizerMySQLUnicodeCI as normalizer.
+
+%package devel
+Summary: Development files for groonga-normalizer-mysql
+Group: Development/Libraries
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+This package provides development files for groonga-normalizer-mysql.
+
+%prep
+%setup -q
+
+%build
+%configure \
+ --disable-static
+sed -i 's|^hardcode_libdir_flag_spec=.*|hardcode_libdir_flag_spec=""|g' libtool
+sed -i 's|^runpath_var=LD_RUN_PATH|runpath_var=DIE_RPATH_DIE|g' libtool
+make %{?_smp_mflags}
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT INSTALL="install -p"
+rm $RPM_BUILD_ROOT%{_libdir}/groonga/plugins/*/*.la
+
+%files
+%dir %{_libdir}/groonga
+%dir %{_libdir}/groonga/plugins
+%dir %{_libdir}/groonga/plugins/normalizers
+%{_libdir}/groonga/plugins/normalizers/mysql.so
+%{_datadir}/doc/groonga-normalizer-mysql/
+
+%files devel
+%{_libdir}/pkgconfig/groonga-normalizer-mysql.pc
+
+%changelog
+* Fri Apr 29 2016 HAYASHI Kentaro <hayashi@clear-code.com> - 1.1.1-1
+- new upstream release.
+
+* Fri May 29 2015 Kouhei Sutou <kou@clear-code.com> - 1.1.0-1
+- new upstream release.
+
+* Sun Mar 29 2015 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.9-1
+- new upstream release.
+
+* Tue Feb 10 2015 Kouhei Sutou <kou@clear-code.com> - 1.0.8-1
+- new upstream release.
+
+* Mon Feb 09 2015 <hayashi@clear-code.com> - 1.0.7-1
+- new upstream release.
+
+* Sun Feb 09 2014 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.6-1
+- new upstream release.
+
+* Sat Jun 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.5-1
+- new upstream release.
+
+* Wed May 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.4-1
+- new upstream release.
+
+* Mon Apr 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.3-1
+- new upstream release.
+- Reduce required packages. groonga-libs is only required.
+- Require groonga 3.0.3 or later.
+- Split development files into -devel package.
+
+* Fri Mar 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.2-0
+- new upstream release.
+
+* Thu Feb 28 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.1-1
+- new upstream release
+
+* Tue Jan 29 2013 HAYASHI Kentaro <hayashi@clear-code.com> - 1.0.0-1
+- initial packaging for Fedora
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/source/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/source/Makefile.am
new file mode 100644
index 00000000..29051e80
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/source/Makefile.am
@@ -0,0 +1,25 @@
+all:
+
+release: upload
+
+ensure-rsync-path:
+ @if test -z "$(RSYNC_PATH)"; then \
+ echo "--with-rsync-path configure option must be specified."; \
+ false; \
+ fi
+
+download: ensure-rsync-path
+ rsync -avz --progress $(RSYNC_PATH)/source/groonga-normalizer-mysql/ files
+
+upload: ensure-rsync-path files/$(PACKAGE)-$(VERSION).tar.gz files/$(PACKAGE)-$(VERSION).zip
+ rsync -avz --progress --delete files/ $(RSYNC_PATH)/source/groonga-normalizer-mysql
+
+files/$(PACKAGE)-$(VERSION).tar.gz: $(top_builddir)/$(PACKAGE)-$(VERSION).tar.gz
+ mkdir -p files
+ cp -p $< $@
+
+files/$(PACKAGE)-$(VERSION).zip: files/$(PACKAGE)-$(VERSION).tar.gz
+ rm -rf $(PACKAGE)-$(VERSION)
+ tar xvzf files/$(PACKAGE)-$(VERSION).tar.gz
+ zip -r $@ $(PACKAGE)-$(VERSION)
+ rm -rf $(PACKAGE)-$(VERSION)
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/ubuntu/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/ubuntu/Makefile.am
new file mode 100644
index 00000000..cb0be12d
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/ubuntu/Makefile.am
@@ -0,0 +1,28 @@
+CODE_NAMES = precise,trusty,wily,xenial
+SOURCE = ../$(PACKAGE)-$(VERSION).tar.gz
+
+all:
+
+ensure-configuration:
+ @if test -z "$(LAUNCHPAD_UPLOADER_PGP_KEY)"; then \
+ echo "--with-launchpad-uploader-pgp-key configure option must be specified."; \
+ false; \
+ fi
+ @if test -z "$(GROONGA_SOURCE_PATH)"; then \
+ echo "--with-groonga-source-path configure option must be specified."; \
+ false; \
+ fi
+
+upload: source ensure-configuration
+ $(GROONGA_SOURCE_PATH)/packages/ubuntu/upload.rb \
+ --package '$(PACKAGE)' \
+ --version '$(VERSION)' \
+ --source-archive '$(SOURCE)' \
+ --code-names '$(CODE_NAMES)' \
+ --debian-directory '$(srcdir)/../debian/' \
+ --pgp-sign-key '$(LAUNCHPAD_UPLOADER_PGP_KEY)'
+
+source: $(SOURCE)
+
+$(SOURCE):
+ ln -s $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz $(SOURCE)
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Makefile.am b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Makefile.am
new file mode 100644
index 00000000..3f48f6f3
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Makefile.am
@@ -0,0 +1,72 @@
+REPOSITORIES_PATH = repositories
+DISTRIBUTIONS = centos
+ARCHITECTURES = i386 x86_64
+CENTOS_VERSIONS = 5 6 7
+
+release: download build sign-packages update-repository upload
+
+ensure-rsync-path:
+ @if test -z "$(RSYNC_PATH)"; then \
+ echo "--with-rsync-path configure option must be specified."; \
+ false; \
+ fi
+
+sign-packages:
+ ./sign-rpm.sh '$(GPG_UID)' '$(REPOSITORIES_PATH)/' \
+ '$(DISTRIBUTIONS)'
+
+update-repository: RPM-GPG-KEY-$(PACKAGE)
+ ./update-repository.sh '$(PACKAGE)' '$(REPOSITORIES_PATH)/' \
+ '$(DISTRIBUTIONS)'
+
+upload: ensure-rsync-path
+ for distribution in $(DISTRIBUTIONS); do \
+ rsync -avz --progress --delete --exclude .gitignore \
+ $(REPOSITORIES_PATH)/$${distribution}/ \
+ $(RSYNC_PATH)/$${distribution}; \
+ done
+
+download: ensure-rsync-path
+ mkdir -p $(REPOSITORIES_PATH)
+ for distribution in $(DISTRIBUTIONS); do \
+ rsync -avz --progress --delete \
+ $(RSYNC_PATH)/$${distribution}/ \
+ $(REPOSITORIES_PATH)/$${distribution}; \
+ done
+
+build: build-in-vm
+
+build-in-vm: source specs env.sh
+ vagrant destroy --force
+ for architecture in $(ARCHITECTURES); do \
+ for version in $(CENTOS_VERSIONS); do \
+ if [ $$version = 7 -a $$architecture = i386 ]; then \
+ continue; \
+ fi; \
+ id=centos-$$version-$$architecture; \
+ vagrant up $$id; \
+ vagrant destroy --force $$id; \
+ done; \
+ done
+
+ensure-public-key:
+ gpg --list-keys '$(GPG_UID)' > /dev/null || \
+ gpg --keyserver keyserver.ubuntu.com --recv-key '$(GPG_UID)'
+
+RPM-GPG-KEY-$(PACKAGE): ensure-public-key
+ gpg --armor --export '$(GPG_UID)' > $@
+
+source: tmp/$(PACKAGE)-$(VERSION).tar.gz
+
+tmp/$(PACKAGE)-$(VERSION).tar.gz: $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz
+ mkdir -p tmp/
+ cp $(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz tmp/
+
+$(abs_top_builddir)/$(PACKAGE)-$(VERSION).tar.gz:
+ cd $(abs_top_builddir) && $(MAKE) dist
+
+specs: tmp/centos/$(PACKAGE).spec
+
+tmp/centos/$(PACKAGE).spec: $(builddir)/../rpm/centos/$(PACKAGE).spec
+ mkdir -p tmp/centos
+ cp $(builddir)/../rpm/centos/$(PACKAGE).spec tmp/centos/
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Vagrantfile b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Vagrantfile
new file mode 100644
index 00000000..048d9e00
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/Vagrantfile
@@ -0,0 +1,38 @@
+# -*- mode: ruby -*-
+# vi: set ft=ruby :
+
+# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
+VAGRANTFILE_API_VERSION = "2"
+
+Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
+ vms = [
+ {
+ :id => "centos-5-i386",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-5.11-i386_chef-provisionerless.box",
+ },
+ {
+ :id => "centos-5-x86_64",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-5.11_chef-provisionerless.box",
+ },
+ {
+ :id => "centos-6-i386",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.7-i386_chef-provisionerless.box",
+ },
+ {
+ :id => "centos-6-x86_64",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-6.7_chef-provisionerless.box",
+ },
+ {
+ :id => "centos-7-x86_64",
+ :box_url => "http://opscode-vm-bento.s3.amazonaws.com/vagrant/virtualbox/opscode_centos-7.2_chef-provisionerless.box",
+ },
+ ]
+
+ vms.each do |vm|
+ config.vm.define(vm[:id]) do |node|
+ node.vm.box = vm[:id]
+ node.vm.box_url = vm[:box_url]
+ node.vm.provision(:shell, :path => "build-rpm.sh")
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/build-rpm.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/build-rpm.sh
new file mode 100755
index 00000000..14a13ad0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/build-rpm.sh
@@ -0,0 +1,67 @@
+#!/bin/sh
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+rpmbuild_options=
+
+. /vagrant/env.sh
+
+distribution=$(cut -d " " -f 1 /etc/redhat-release | tr "A-Z" "a-z")
+if grep -q Linux /etc/redhat-release; then
+ distribution_version=$(cut -d " " -f 4 /etc/redhat-release)
+else
+ distribution_version=$(cut -d " " -f 3 /etc/redhat-release)
+fi
+distribution_version=$(echo ${distribution_version} | sed -e 's/\..*$//g')
+
+architecture="$(arch)"
+case "${architecture}" in
+ i*86)
+ architecture=i386
+ ;;
+esac
+
+run rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
+run yum makecache
+
+run yum groupinstall -y "Development Tools"
+run yum install -y rpm-build rpmdevtools tar ${DEPENDED_PACKAGES}
+
+if [ -x /usr/bin/rpmdev-setuptree ]; then
+ rm -rf .rpmmacros
+ run rpmdev-setuptree
+else
+ run cat <<EOM > ~/.rpmmacros
+%_topdir ${HOME}/rpmbuild
+EOM
+ run mkdir -p ~/rpmbuild/SOURCES
+ run mkdir -p ~/rpmbuild/SPECS
+ run mkdir -p ~/rpmbuild/BUILD
+ run mkdir -p ~/rpmbuild/RPMS
+ run mkdir -p ~/rpmbuild/SRPMS
+fi
+
+repository="/vagrant/repositories/${distribution}/${distribution_version}"
+rpm_dir="${repository}/${architecture}/Packages"
+srpm_dir="${repository}/source/SRPMS"
+run mkdir -p "${rpm_dir}" "${srpm_dir}"
+
+# for debug
+# rpmbuild_options="$rpmbuild_options --define 'optflags -O0 -g3'"
+
+cd
+
+run cp /vagrant/tmp/${PACKAGE}-${VERSION}.* rpmbuild/SOURCES/
+run cp /vagrant/tmp/${distribution}/${PACKAGE}.spec rpmbuild/SPECS/
+
+run rpmbuild -ba ${rpmbuild_options} rpmbuild/SPECS/${PACKAGE}.spec
+
+run mv rpmbuild/RPMS/*/* "${rpm_dir}/"
+run mv rpmbuild/SRPMS/* "${srpm_dir}/"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/env.sh.in b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/env.sh.in
new file mode 100644
index 00000000..ea55d0d8
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/env.sh.in
@@ -0,0 +1,11 @@
+PACKAGE=@PACKAGE@
+VERSION=@VERSION@
+DEPENDED_PACKAGES="
+intltool
+libtool
+gcc
+gcc-c++
+make
+tar
+groonga-devel
+"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/sign-rpm.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/sign-rpm.sh
new file mode 100755
index 00000000..2022ca66
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/sign-rpm.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_UID DESTINATION DISTRIBUTIONS"
+ echo " e.g.: $0 'F10399C0' repositories/ 'fedora centos'"
+ exit 1
+fi
+
+GPG_UID=$1
+DESTINATION=$2
+DISTRIBUTIONS=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+rpms=""
+for distribution in ${DISTRIBUTIONS}; do
+ rpms="${rpms} $(echo ${DESTINATION}${distribution}/*/*/*/*.rpm)"
+done
+
+echo "NOTE: YOU JUST ENTER! YOU DON'T NEED TO INPUT PASSWORD!"
+echo " IT'S JUST FOR rpm COMMAND RESTRICTION!"
+run echo $rpms | xargs rpm \
+ -D "_gpg_name ${GPG_UID}" \
+ -D "_gpg_digest_algo sha1" \
+ -D "__gpg /usr/bin/gpg2" \
+ -D "__gpg_check_password_cmd /bin/true true" \
+ -D "__gpg_sign_cmd %{__gpg} gpg --batch --no-verbose --no-armor %{?_gpg_digest_algo:--digest-algo %{_gpg_digest_algo}} --no-secmem-warning -u \"%{_gpg_name}\" -sbo %{__signature_filename} %{__plaintext_filename}" \
+ --resign
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/update-repository.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/update-repository.sh
new file mode 100755
index 00000000..04058598
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/packages/yum/update-repository.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+
+script_base_dir=`dirname $0`
+
+if [ $# != 3 ]; then
+ echo "Usage: $0 GPG_KEY_NAME DESTINATION DISTRIBUTIONS"
+ echo " e.g.: $0 mitler-manager repositories/ 'fedora centos'"
+ exit 1
+fi
+
+GPG_KEY_NAME=$1
+DESTINATION=$2
+DISTRIBUTIONS=$3
+
+run()
+{
+ "$@"
+ if test $? -ne 0; then
+ echo "Failed $@"
+ exit 1
+ fi
+}
+
+for distribution in ${DISTRIBUTIONS}; do
+ for dir in ${DESTINATION}${distribution}/*/*; do
+ # "--checksum sha" is for CentOS 5. If we drop CentOS 5 support,
+ # we can remove the option.
+ test -d $dir && run createrepo --checksum sha $dir
+ done;
+
+ run cp $script_base_dir/RPM-GPG-KEY-${GPG_KEY_NAME} \
+ ${DESTINATION}${distribution}/RPM-GPG-KEY-${GPG_KEY_NAME};
+done
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/required_groonga_version b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/required_groonga_version
new file mode 100644
index 00000000..75a22a26
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/required_groonga_version
@@ -0,0 +1 @@
+3.0.3
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_uca.rb b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_uca.rb
new file mode 100644
index 00000000..b9d10584
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_uca.rb
@@ -0,0 +1,50 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require "parser"
+
+if ARGV.size != 1
+ puts("Usage: #{$0} MYSQL_SOURCE/strings/ctype-uca.c")
+ exit(false)
+end
+
+parser = CTypeUCAParser.new
+parser.parse(ARGF)
+
+n_idencials = 0
+n_expanded_characters = 0
+parser.weight_based_characters.each do |weight, characters|
+ next if characters.size == 1
+ n_idencials += 1
+ representative_character = characters.first
+ rest_characters = characters[1..-1]
+ rest_characters.each do |character|
+ if representative_character[:utf8].bytesize > character[:utf8].bytesize
+ n_expanded_characters += 1
+ end
+ end
+ formatted_weight = weight.collect {|component| '%#07x' % component}.join(', ')
+ puts "weight: #{formatted_weight}"
+ characters.each do |character|
+ utf8 = character[:utf8]
+ code_point = character[:code_point]
+ p ["U+%04x" % code_point, utf8]
+ end
+end
+
+puts "Number of idencial weights #{n_idencials}"
+puts "Number of expanded characters: #{n_expanded_characters}"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_utf8.rb b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_utf8.rb
new file mode 100644
index 00000000..4b6fde8c
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/dump_difference_utf8.rb
@@ -0,0 +1,50 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require "parser"
+
+if ARGV.size != 1
+ puts("Usage: #{$0} MYSQL_SOURCE/strings/ctype-utf8.c")
+ exit(false)
+end
+
+parser = CTypeUTF8Parser.new
+parser.parse(ARGF)
+
+n_differences = 0
+n_expanded_sort_characters = 0
+parser.sorted_pages.each do |page, characters|
+ characters.each do |character|
+ base = character[:base]
+ upper = character[:upper]
+ lower = character[:lower]
+ sort = character[:sort]
+ next if base == sort
+ n_differences += 1
+ utf8s = [base, upper, lower, sort]
+ formatted_code_points = utf8s.collect do |utf8|
+ "%#07x" % Unicode.from_utf8(utf8)
+ end
+ if sort.bytesize > base.bytesize
+ n_expanded_sort_characters += 1
+ end
+ p [utf8s, formatted_code_points]
+ end
+end
+
+puts "Number of differences: #{n_differences}"
+puts "Number of expanded sort characters: #{n_expanded_sort_characters}"
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_uca_table.rb b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_uca_table.rb
new file mode 100755
index 00000000..d70734e6
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_uca_table.rb
@@ -0,0 +1,304 @@
+#!/usr/bin/env ruby
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2013-2015 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+require "optparse"
+
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require "parser"
+
+@version = nil
+@suffix = ""
+@split_small_kana_p = false
+@split_kana_with_voiced_sound_mark_p = false
+@split_kana_with_semi_voiced_sound_mark_p = false
+
+option_parser = OptionParser.new
+option_parser.banner += " MYSQL_SOURCE/strings/ctype-uca.c"
+
+option_parser.on("--version=VERSION", "Use VERSION as UCA version") do |version|
+ @version = version
+end
+
+option_parser.on("--suffix=SUFFIX", "Add SUFFIX to names") do |suffix|
+ @suffix = suffix
+end
+
+option_parser.on("--[no-]split-small-kana",
+ "Split small hiragana (katakana) and " +
+ "large hiragana (katakana)",
+ "(#{@split_small_kana_p})") do |boolean|
+ @split_small_kana_p = boolean
+end
+
+option_parser.on("--[no-]split-kana-with-voiced-sound-mark",
+ "Split hiragana (katakana) with voiced sound mark",
+ "(#{@split_kana_with_voiced_sound_mark})") do |boolean|
+ @split_kana_with_voiced_sound_mark_p = boolean
+end
+
+option_parser.on("--[no-]split-kana-with-semi-voiced-sound-mark",
+ "Split hiragana (katakana) with semi-voiced sound mark",
+ "(#{@split_kana_with_semi_voiced_sound_mark})") do |boolean|
+ @split_kana_with_semi_voiced_sound_mark_p = boolean
+end
+
+begin
+ option_parser.parse!(ARGV)
+rescue OptionParser::Error
+ puts($!)
+ exit(false)
+end
+
+if ARGV.size != 1
+ puts(option_parser)
+ exit(false)
+end
+
+ctype_uca_c_path = ARGV[0]
+
+parser = CTypeUCAParser.new(@version)
+File.open(ctype_uca_c_path) do |ctype_uca_c|
+ parser.parse(ctype_uca_c)
+end
+
+SMALL_KANAS = [
+ "ぁ", "ぃ", "ぅ", "ぇ", "ぉ",
+ "っ",
+ "ゃ", "ゅ", "ょ",
+ "ゎ",
+ "ァ", "ィ", "ゥ", "ェ", "ォ",
+ "ッ",
+ "ャ", "ュ", "ョ",
+ "ヮ",
+ "ァ", "ィ", "ゥ", "ェ", "ォ",
+ "ッ",
+ "ャ", "ュ", "ョ",
+]
+def small_kana?(character)
+ SMALL_KANAS.include?(character[:utf8])
+end
+
+KANA_WITH_VOICED_SOUND_MARKS = [
+ "が", "ぎ", "ぐ", "げ", "ご",
+ "ざ", "じ", "ず", "ぜ", "ぞ",
+ "だ", "ぢ", "づ", "で", "ど",
+ "ば", "び", "ぶ", "べ", "ぼ",
+ "ガ", "ギ", "グ", "ゲ", "ゴ",
+ "ザ", "ジ", "ズ", "ゼ", "ゾ",
+ "ダ", "ヂ", "ヅ", "デ", "ド",
+ "バ", "ビ", "ブ", "ベ", "ボ",
+]
+def kana_with_voiced_sound_mark?(character)
+ KANA_WITH_VOICED_SOUND_MARKS.include?(character[:utf8])
+end
+
+KANA_WITH_SEMI_VOICED_SOUND_MARKS = [
+ "ぱ", "ぴ", "ぷ", "ぺ", "ぽ",
+ "パ", "ピ", "プ", "ペ", "ポ",
+]
+def kana_with_semi_voiced_sound_mark?(character)
+ KANA_WITH_SEMI_VOICED_SOUND_MARKS.include?(character[:utf8])
+end
+
+def split_characters(characters)
+ grouped_characters = characters.group_by do |character|
+ if @split_small_kana_p and small_kana?(character)
+ :small_kana
+ elsif @split_kana_with_voiced_sound_mark_p and
+ kana_with_voiced_sound_mark?(character)
+ :kana_with_voiced_sound_mark
+ elsif @split_kana_with_semi_voiced_sound_mark_p and
+ kana_with_semi_voiced_sound_mark?(character)
+ :kana_with_semi_voiced_sound_mark
+ else
+ :other
+ end
+ end
+ grouped_characters.values
+end
+
+grouped_characters = []
+parser.weight_based_characters.each do |weight, characters|
+ grouped_characters.concat(split_characters(characters))
+end
+
+GREEK_CAPITAL_UNICODE_RANGE = Unicode.from_utf8("Α")..Unicode.from_utf8("Ω")
+def find_greek_capital_character(characters)
+ characters.find do |character|
+ GREEK_CAPITAL_UNICODE_RANGE.cover?(character[:code_point])
+ end
+end
+
+def find_representative_character(characters)
+ representative_character = nil
+ case characters.first[:utf8]
+ when "⺄", "⺇", "⺈", "⺊", "⺌", "⺗"
+ representative_character = characters.last
+ when "⺜", "⺝", "⺧", "⺫", "⺬", "⺮", "⺶", "⺻", "⺼", "⺽"
+ representative_character = characters[1]
+ when "⻆", "⻊", "⻏", "⻑", "⻕", "⻗", "⻝", "⻡", "⻣", "⻤"
+ representative_character = characters.last
+ when "⻱", "⼀", "⼆", "⼈"
+ representative_character = characters[1]
+ when "ぁ", "ぃ", "ぅ", "ぇ", "ぉ", "っ", "ゃ", "ゅ", "ょ", "ゎ"
+ representative_character = characters[1] unless @split_small_kana_p
+ else
+ representative_character ||= find_greek_capital_character(characters)
+ end
+ representative_character ||= characters.first
+ representative_character
+end
+
+target_pages = {}
+grouped_characters.each do |characters|
+ next if characters.size == 1
+ representative_character = find_representative_character(characters)
+ representative_code_point = representative_character[:code_point]
+ rest_characters = characters.reject do |character|
+ character == representative_character
+ end
+ rest_characters.each do |character|
+ code_point = character[:code_point]
+ page = code_point >> 8
+ low_code = code_point & 0xff
+ target_pages[page] ||= [nil] * 256
+ target_pages[page][low_code] = representative_code_point
+ end
+end
+
+sorted_target_pages = target_pages.sort_by do |page, code_points|
+ page
+end
+
+
+normalized_ctype_uca_c_path =
+ ctype_uca_c_path.sub(/\A.*\/([^\/]+\/strings\/ctype-uca\.c)\z/, "\\1")
+
+header_guard_id = "MYSQL_UCA"
+if @version
+ header_guard_id << "_#{@version}"
+end
+header_guard_id << "#{@suffix.upcase}_H"
+
+puts(<<-HEADER)
+/*
+ Copyright(C) 2013-2015 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ #{normalized_ctype_uca_c_path}.
+ The following is the header of the file:
+
+ Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UCA (Unicode Collation Algorithm) support.
+ Written by Alexander Barkov <bar@mysql.com>
+*/
+
+#ifndef #{header_guard_id}
+#define #{header_guard_id}
+
+#include <stdint.h>
+HEADER
+
+def variable_name_prefix
+ prefix = "unicode"
+ if @version
+ prefix << "_#{@version}"
+ end
+ prefix << "_ci#{@suffix}"
+ prefix
+end
+
+def page_name(page)
+ "#{variable_name_prefix}_page_%02x" % page
+end
+
+sorted_target_pages.each do |page, characters|
+ puts(<<-PAGE_HEADER)
+
+static uint32_t #{page_name(page)}[] = {
+PAGE_HEADER
+ lines = characters.each_with_index.each_slice(8).collect do |characters_group|
+ formatted_code_points = characters_group.collect do |normalized, low_code|
+ normalized ||= (page << 8) + low_code
+ "0x%05x" % normalized
+ end
+ " " + formatted_code_points.join(", ")
+ end
+ puts(lines.join(",\n"))
+ puts(<<-PAGE_FOOTER)
+};
+PAGE_FOOTER
+end
+
+puts(<<-PAGES_HEADER)
+
+static uint32_t *#{variable_name_prefix}_table[#{parser.n_pages}] = {
+PAGES_HEADER
+
+pages = ["NULL"] * parser.n_pages
+sorted_target_pages.each do |page, characters|
+ pages[page] = page_name(page)
+end
+lines = pages.each_slice(2).collect do |pages_group|
+ formatted_pages = pages_group.collect do |page|
+ "%19s" % page
+ end
+ " " + formatted_pages.join(", ")
+end
+puts(lines.join(",\n"))
+
+puts(<<-PAGES_FOOTER)
+};
+PAGES_FOOTER
+
+puts(<<-FOOTER)
+
+#endif
+FOOTER
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_utf8_table.rb b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_utf8_table.rb
new file mode 100755
index 00000000..b8fc1143
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/generate_utf8_table.rb
@@ -0,0 +1,146 @@
+#!/usr/bin/env ruby
+#
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+require "parser"
+
+if ARGV.size != 1
+ puts("Usage: #{$0} MYSQL_SOURCE/strings/ctype-utf8.c")
+ exit(false)
+end
+
+ctype_utf8_c_path = ARGV[0]
+
+parser = CTypeUTF8Parser.new
+File.open(ctype_utf8_c_path) do |ctype_utf8_c|
+ parser.parse(ctype_utf8_c)
+end
+
+target_pages = {}
+parser.sorted_pages.each do |page, characters|
+ characters.each do |character|
+ base = character[:base]
+ upper = character[:upper]
+ lower = character[:lower]
+ sort = character[:sort]
+ next if base == sort
+ target_pages[page] ||= [nil] * 256
+ low_code = Unicode.from_utf8(base) & 0xff
+ target_pages[page][low_code] = Unicode.from_utf8(sort)
+ end
+end
+
+normalized_ctype_utf8_c_path =
+ ctype_utf8_c_path.sub(/\A.*\/([^\/]+\/strings\/ctype-utf8\.c)\z/, "\\1")
+puts(<<-HEADER)
+/*
+ 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 Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ This file uses normalization table defined in
+ #{normalized_ctype_utf8_c_path}.
+ The following is the header of the file:
+
+ Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1335 USA
+
+ UTF8 according RFC 2279
+ Written by Alexander Barkov <bar@udm.net>
+*/
+
+#ifndef MYSQL_UTF8_H
+#define MYSQL_UTF8_H
+
+#include <stdint.h>
+HEADER
+
+def page_name(page)
+ "general_ci_page_%02x" % page
+end
+
+target_pages.each do |page, characters|
+ puts(<<-PAGE_HEADER)
+
+static uint32_t #{page_name(page)}[] = {
+PAGE_HEADER
+ lines = characters.each_with_index.each_slice(8).collect do |characters_group|
+ formatted_code_points = characters_group.collect do |normalized, low_code|
+ normalized ||= (page << 8) + low_code
+ "0x%05x" % normalized
+ end
+ " " + formatted_code_points.join(", ")
+ end
+ puts(lines.join(",\n"))
+ puts(<<-PAGE_FOOTER)
+};
+PAGE_FOOTER
+end
+
+puts(<<-PAGES_HEADER)
+
+static uint32_t *general_ci_table[256] = {
+PAGES_HEADER
+
+pages = ["NULL"] * 256
+target_pages.each do |page, characters|
+ pages[page] = page_name(page)
+end
+lines = pages.each_slice(2).collect do |pages_group|
+ formatted_pages = pages_group.collect do |page|
+ "%18s" % page
+ end
+ " " + formatted_pages.join(", ")
+end
+puts(lines.join(",\n"))
+
+puts(<<-PAGES_FOOTER)
+};
+PAGES_FOOTER
+
+puts(<<-FOOTER)
+
+#endif
+FOOTER
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/parser.rb b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/parser.rb
new file mode 100644
index 00000000..29268a43
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/parser.rb
@@ -0,0 +1,183 @@
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+require "English"
+
+module Unicode
+ module_function
+ def to_utf8(code_point)
+ [code_point].pack("U")
+ end
+
+ def from_utf8(utf8)
+ utf8.unpack("U")[0]
+ end
+end
+
+class CTypeUTF8Parser
+ def initialize
+ @pages = {}
+ end
+
+ def parse(input)
+ parse_ctype_utf8(input)
+ normalize_pages
+ end
+
+ def sorted_pages
+ @pages.sort_by do |page, characters|
+ page
+ end
+ end
+
+ private
+ def parse_ctype_utf8(input)
+ current_page = nil
+ input.each_line do |line|
+ case line
+ when / plane([\da-fA-F]{2})\[\]=/
+ current_page = $1.to_i(16)
+ @pages[current_page] = []
+ when /^\s*
+ \{0x([\da-z]+),0x([\da-z]+),0x([\da-z]+)\},
+ \s*
+ \{0x([\da-z]+),0x([\da-z]+),0x([\da-z]+)\},?$/ix
+ next if current_page.nil?
+ parsed_characters = $LAST_MATCH_INFO.captures.collect do |value|
+ Unicode.to_utf8(value.to_i(16))
+ end
+ upper1, lower1, sort1, upper2, lower2, sort2 = parsed_characters
+ characters = @pages[current_page]
+ characters << {:upper => upper1, :lower => lower1, :sort => sort1}
+ characters << {:upper => upper2, :lower => lower2, :sort => sort2}
+ when /^\};$/
+ current_page = nil
+ end
+ end
+ end
+
+ def normalize_pages
+ @pages.each do |page, characters|
+ characters.each_with_index do |character, i|
+ character[:base] = Unicode.to_utf8((page << 8) + i)
+ end
+ end
+ end
+end
+
+class CTypeUCAParser
+ attr_reader :pages
+ def initialize(version=nil)
+ @version = version
+ @pages = {}
+ @lengths = []
+ end
+
+ def parse(input)
+ parse_ctype_uca(input)
+ normalize_pages
+ end
+
+ def weight_based_characters
+ weight_based_characters = {}
+ sorted_pages.each do |page, characters|
+ characters.each do |character|
+ weight = character[:weight]
+ weight_based_characters[weight] ||= []
+ weight_based_characters[weight] << character
+ end
+ end
+ weight_based_characters
+ end
+
+ def sorted_pages
+ @pages.sort_by do |page, characters|
+ page
+ end
+ end
+
+ def n_pages
+ @lengths.size
+ end
+
+ private
+ def page_data_pattern
+ if @version == "520"
+ / uca520_p([\da-fA-F]{3})\[\]=/
+ else
+ / page([\da-fA-F]{3})data\[\]=/
+ end
+ end
+
+ def length_pattern
+ if @version == "520"
+ / uca520_length\[4352\]=/
+ else
+ / uca_length\[256\]=/
+ end
+ end
+
+ def parse_ctype_uca(input)
+ current_page = nil
+ in_length = false
+ input.each_line do |line|
+ case line
+ when page_data_pattern
+ current_page = $1.to_i(16)
+ @pages[current_page] = []
+ when /^\s*(0x(?:[\da-z]+)(?:,\s*0x(?:[\da-z]+))*),?(?: \/\*.+\*\/)?$/i
+ weight_values = $1
+ next if current_page.nil?
+ weights = weight_values.split(/,\s*/).collect do |component|
+ Integer(component)
+ end
+ @pages[current_page].concat(weights)
+ when length_pattern
+ in_length = true
+ when /^\d+(?:,\d+)*,?$/
+ next unless in_length
+ current_lengths = line.chomp.split(/,/).collect do |length|
+ Integer(length)
+ end
+ @lengths.concat(current_lengths)
+ when /^\};$/
+ current_page = nil
+ in_length = false
+ end
+ end
+ end
+
+ def normalize_pages
+ @pages.each do |page, flatten_weights|
+ weights = flatten_weights.each_slice(@lengths[page])
+ @pages[page] = weights.with_index.collect do |weight, i|
+ if weight.all?(&:zero?)
+ weight = [0]
+ else
+ while weight.last.zero?
+ weight.pop
+ end
+ end
+ code_point = (page << 8) + i
+ {
+ :weight => weight,
+ :code_point => code_point,
+ :utf8 => Unicode.to_utf8(code_point),
+ }
+ end
+ end
+ end
+end
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/before_script.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/before_script.sh
new file mode 100755
index 00000000..24e97430
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/before_script.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+set -e
+
+./autogen.sh
+
+./configure
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/install.sh b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/install.sh
new file mode 100755
index 00000000..2fc22888
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/tool/travis/install.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# 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 Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 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
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+set -e
+
+# export GROONGA_MASTER=yes
+curl --silent --location \
+ https://raw.github.com/groonga/groonga/master/data/travis/setup.sh | sh
+
+if ! pkg-config --exists groonga; then
+ sudo apt-get install -qq -y libgroonga-dev
+fi
diff --git a/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/version_full b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/version_full
new file mode 100644
index 00000000..8cfbc905
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/version_full
@@ -0,0 +1 @@
+1.1.1 \ No newline at end of file
diff --git a/storage/mroonga/vendor/groonga/version-gen.sh b/storage/mroonga/vendor/groonga/version-gen.sh
new file mode 100755
index 00000000..c56cb9e0
--- /dev/null
+++ b/storage/mroonga/vendor/groonga/version-gen.sh
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+case "$0" in
+ */*)
+ cd `dirname $0`
+ ;;
+esac
+
+GRN_VERSION_SH=version.sh
+
+if test -f version
+then
+ GRN_VN=`cat version`
+elif test -d .git -o -f .git
+then
+ GRN_VN=`git describe --abbrev=7 HEAD 2>/dev/null`
+ if [ $? -ne 0 ]
+ then
+ GRN_VN=`cat base_version`
+ fi
+fi
+
+GRN_VN=`expr "$GRN_VN" : v*'\(.*\)'`
+
+if test -r $GRN_VERSION_SH
+then
+ GRN_VN_OLD=`sed -e 's/^GRN_VERSION=//' <$GRN_VERSION_SH`
+else
+ GRN_VN_OLD=unset
+fi
+
+if test "$GRN_VN_OLD" != "$GRN_VN"
+then
+ echo "GRN_VERSION=$GRN_VN" >$GRN_VERSION_SH
+fi
diff --git a/storage/mroonga/version_full b/storage/mroonga/version_full
new file mode 100644
index 00000000..5b1f5684
--- /dev/null
+++ b/storage/mroonga/version_full
@@ -0,0 +1 @@
+7.07 \ No newline at end of file
diff --git a/storage/mroonga/version_in_hex b/storage/mroonga/version_in_hex
new file mode 100644
index 00000000..33e98aa1
--- /dev/null
+++ b/storage/mroonga/version_in_hex
@@ -0,0 +1 @@
+0x0707 \ No newline at end of file
diff --git a/storage/mroonga/version_major b/storage/mroonga/version_major
new file mode 100644
index 00000000..c7930257
--- /dev/null
+++ b/storage/mroonga/version_major
@@ -0,0 +1 @@
+7 \ No newline at end of file
diff --git a/storage/mroonga/version_micro b/storage/mroonga/version_micro
new file mode 100644
index 00000000..c7930257
--- /dev/null
+++ b/storage/mroonga/version_micro
@@ -0,0 +1 @@
+7 \ No newline at end of file
diff --git a/storage/mroonga/version_minor b/storage/mroonga/version_minor
new file mode 100644
index 00000000..c2270834
--- /dev/null
+++ b/storage/mroonga/version_minor
@@ -0,0 +1 @@
+0 \ No newline at end of file